pub struct VirtualMachine { /* private fields */ }
Expand description

Bytecode evaluation engine

Attach compiled functions to a VirtualMachine with insert_function or initialize it with a list of functions using with_functions.

Begin execution with run.

Implementations

Construct a VirtualMachine with an iterator of functions.

Run the virtual machine to completion, starting with the function referred to by entry_name. If it does not exist in the virtual machine, a RuntimeError is returned. Otherwise, is used to lookup the entry function by name.

The entry function is called with the values in args and its return value is returned by this function as a Value.

Infinite loops:

Using run will continue to execute bytecode until entry_name finishes and returns. This could potentially cause an unrecoverable infinite loop. Use initialize_with_values and execution_loop for more fine-grained control over the number of instructions to allow the VM to execute.

Example:
let source_code = r"
function trisum(a, b, c)
  return a + b + c
end
";
let (_, declarations) = parser::parse_file(source_code).unwrap();
let functions = compiler::compile_declarations(declarations.iter());
let mut vm = VirtualMachine::with_functions(functions);

let result = vm.run("trisum", [1.into(), 2.into(), 3.into()]);
assert!(matches!(result, Ok(Value::Integer(6))));

Gets the return value of the entry function.

This will always be Value::Nil if the entry function has not finished.

Sets the entry procedure of the virtual machine and sets its argument registers to the Values in args.

Does not begin execution, unlike run.

Execute instructions until either limit is reached or the entry procedure finishes.

Example:
let source_code = r"
function forever(n)  # causes an infinite loop when n >= 0
  x = 0
  while x >= 0 do
    x = x + n
  end
end
";
let (_, fn_decl) = parser::declaration::function_decl(source_code).expect("parse failed");
let procedure = compiler::compile_function(&fn_decl);
 
let mut vm = VirtualMachine::new();
// Initialize a call to: forever(10)
vm.initialize_with_values(Rc::new(procedure), [Value::Integer(10)]);

// Run for 200 instructions
let status = vm.execution_loop(InstructionCount::Limited(200));
assert!(matches!(status, Ok(ExecutionStatus::Unfinished))); // Did not finish

// Continue to run for 5000 more instructions
let status = vm.execution_loop(InstructionCount::Limited(5000));
assert!(matches!(status, Ok(ExecutionStatus::Unfinished))); // Will always return Unfinished

Execute a single bytecode instruction

Trait Implementations

Formats the value using the given formatter. Read more

Returns the “default value” for a type. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.