MiniLua
Contents
MiniLua is a lua interpreter with source value tracking.
Usage Example
minilua::Interpreter interpreter; // parse the program if (!interpreter.parse("x_coord = 10; force(x_coord, 25)")) { // parser failed } // run the program minilua::EvalResult result = interpreter.evaluate(); // (optionally) apply a source change if (result.source_change) { interpreter.apply_source_changes( result.source_change.value().collect_first_alternative()); } // source code is now: // // xcoord = 25; force(x_coord, 25) // re-run
Origin Tracking and Source Changes
This Lua interpreter tracks the Origin of all (or most) Values. The following Lua code
-- Lua Code x = 10 y = 20 return x^2 + y^2
returns the value 500 and that value has the following origin:
This origin hierarchy allows the interpreter to generate SourceChanges if you want to force a value to a have a different value. I.e. here we force the value of the expression x^2 + y^2
(which is 500) to 400
.
-- Lua Code x = 10 y = 20 z_squared = x^2 + y^2 force(z_squared, 400)
This code would generate the following source changes:
Here a SourceChangeAlternative means that exactly one of the children should be applied. In this case (because multiple SourceChangeAlternative
s are nested) we could flatten the hierarchy. If we apply any of the source changes we will have forced the old value of z_squared
(which was 500) to the new value 400.
Note that the second source change (replace the first "2" on line 3 with "-9223372036854775808") was generated due to floating point underflow and while it is correct and would yield the wanted result is probably not what you want to apply.
See also: Generating Custom SourceChanges when writing native functions.
Guide for Writing Native Functions
You can write your own C++ functions that are callable from Lua. These functions need to be compatible with one of the following signatures:
auto (minilua::CallContext) -> minilua::CallResult; auto (minilua::CallContext) -> minilua::Value; void (minilua::CallContext);
That means the return type has to be convertible to minilua::
or minilua::
or void
(which equivalent to nil
in lua) and the function needs exactly one arguments of type minilua::
or const minilua::
(the latter is preferred because it avoids a copy/move and offer the same functionality).
You can use the minilua::
to get access to the actual arguments and the global environment and to call other (Lua) functions.
Using Arguments
Examples for implementing a function that adds two values:
auto add_using_call_result(const minilua::CallContext& ctx) -> minilua::CallResult { auto arg1 = ctx.arguments().get(0); auto arg2 = ctx.arguments().get(1); return minilua::CallResult(minilua::Vallist(arg1 + arg2)); }
CallContext::minilua::
. Note that you can't actually differentiate between the case where the user did not provide an argument and the user explicitly providing nil
.
A more convenient way to write the same function is to directly return a Value
:
auto add_using_value(const minilua::CallContext& ctx) -> minilua::Value { auto arg1 = ctx.arguments().get(0); auto arg2 = ctx.arguments().get(1); return arg1 + arg2; }
Using the Global Environment
You can also access and modify the global environment. (Native functions do not have access to a local environment because they were not created in one.)
void add_to_global_env(const minilua::CallContext& ctx) { auto arg = ctx.arguments().get(0); auto value = ctx.environment().get("global_var"); ctx.environment().add("global_var", value + arg); }
Creating Values in Native Functions
You can create most Values (except Tables) directly through the corresponding constructor. If you want to create tables you have to call CallContext::make_table()
. This will ensure that the table uses the same allocator as all other values in the interpreter. See Allocator.
auto create_a_table(const minilua::CallContext& ctx) -> minilua::Value { auto key = ctx.arguments().get(0); auto value = ctx.arguments().get(1); auto table = ctx.make_table(); table[key] = value; return table; }