4. Execution

Once compiled, a ruleset is essentially a sequence of functions to call on the execution context. The simplest execution context is an empty table. If Lace is going to store anything it will use a _lace prefix as with compilation contexts. As with compilation, the caller is not permitted to put anything inside _lace nor to rely on its layout.

A few important functions make up the execution engine. The top level function is simply:

result, msg = lace.engine.run(ruleset, exec_context)

This will run ruleset with the given execution context and return a simple result.

If result is nil, then msg is a long-form string error explaining what went wrong. It represents a Lua error being caught and as such you may not want to report it to your users.

If result is false, then msg is a long-form string error explaining that something returned an error during execution which it would be reasonable to report to users under most circumstances.

If result is "allow", then msg is an optional string saying why the ruleset resulted in an allow. Ditto for "deny". Essentially any string might be a reason. This is covered below in Commands.

Commands

When a command is being run, it is called as:

result, msg = command_fn(exec_context, unpack(args))

where args are the arguments returned during the compilation of the command.

If the function throws an error, that will be caught and processed by the execution engine.

If result is falsehood (nil, false) then the command is considered to have failed for some reason and msg contains an "internal" error message to report to the user. This aborts the execution of the ruleset.

If result is true, then the command successfully ran, and execution continues at the next rule.

If result is a string, then the command returned a result. This ceases execution of the ruleset and the result and message (which must be a string explanation) are returned to the caller. Typically such results would be "allow" or "deny" although there's nothing forcing that to be the case.

Control Types

When a control type function is being run, it is called as:

result, msg = ct_fn(exec_context, unpack(args))

where args are the arguments returned when the definition was compiled.

If the function throws an error, it will be caught and processed by the execution engine.

If result is nil then msg is an "internal" error, execution will be stopped and the issue reported to the caller.

If result is false, the control call failed and returned falsehood. Anything else and the control call succeeded and returns truth.

Control type functions are called at the point of test, not at the point of definition. Control type results are NOT cached. It is up to the called functions to perform any caching/memoising of results as needed to ensure suitably performant behaviour.

Helper functions

Since sometimes when writing command functions, you need to know if a given define rule passes, Lace provides a function to do this. It is bound up in the behaviour of Lace's internal define command and as such, you should treat it as a black box.

result, msg = lace.engine.test(exec_context, name)

This, via the magic of the execution context calls through to the appropriate control type functions, returning their results directly.

This means that it can throw an error in the case of a Lua error, otherwise it returns the two values as detailed above.

generated by LDoc 1.4.6 Last updated 2022-07-22 12:53:02