Writing Lua Scripts¶
All scripts in states, namely the entry, exit and action scripts, are written in the Lua language. Lua is a widely used and well documented extension language. Thus, this chapter is not intended to be an thorough documentation of the Lua language itself but assumes that the reader has already familiarized herself with the language itself. Instead, this document provides information on core model data types and functions that are provided for Lua scripts to interact with the core model state machine logic, access parameters and results and call operations.
Accessing core model properties¶
This section documents the core model related data exposed by the core in Lua scripts.
Parameter, result and variable values¶
States are parameterized with their parameter value and can provide
computation results through their result value. In particular, they
can pass state to themselves using their result value, for instance to
implement a counter. The state's parameter value in Lua scripts is
bound to the symbol parameter
while the state's current result
value is bound to the symbol result
. Additionally, every state can
utilize a variable to store private data which is persistent even
if a (child) state is deactivated and later activated again. The
state's variable is bound to the variable
symbol.
Its parameter value corresponds to the declared parameter type of the
state, the result value corresponds to the declared result type and
the variable to the declared variable type respectively. Values are
translated into (and from) Lua data types according to the following rules:
int
andfloat
types correspond to numbers.
string
types correspond to strings.
bool
types correspond to booleans.Array types (e.g.
[2]int
) correspond to Lua arrays, i.e. tables with ascending numeric keys starting with 1.Struct types correspond to Lua tables with keys according to the struct field names.
A
nil
value corresponds to Luanil
.
In addition, the functions setResult
and setVariable
are provided
by the core to allow to set the current result or variable to a new value.
setResult
and setVariable
allows to set the result value only partially
or to set it to nil
. A partial result/variable value is only defined for
struct result/variable types and is a Lua table that contains a subset of the
keys of the declared result type. Fields which cannot be found in the
result/variable type struct lead to a runtime error.
Let us assume a state with the following result type:
{
int foo;
float bar;
[]int baz;
}
The following code snippets show different examples on how to set the
result value (the same is true for setVariable
and the variable value):
setResult({ foo = 1, bar = 2.4, baz = {1, 2, 3} }) -- 1. Result value: { foo: 1; bar: 2.4; baz: [1, 2, 3]; }
setResult({ foo = 1.3 }) -- 2. Result value: { foo: 1; bar: nil; baz: nil }
setResult(nil) -- 3. Result value: nil
setResult({ foo = true }) -- 4. Runtime error: invalid type for 'foo'.
As can be seen, example 1 sets a complete result value. Example 2 sets
only one field in the result. It must be noted that the destination
data type (i.e. the type of the field foo
) is int
and
setResult
must convert the number to an integer. Example 3 shows
resetting of the complete result value while example 4 leads to a
runtime error because the value true
is not a number.
Accessing Ports¶
To query the truth value of ports, the core exposes the function
port(name)
in the Lua script context. The function returns a
boolean value corresponding to the truth value of the corresponding
port's expression.
Accessing Children¶
An array of the names of all children of the current core model state is
bound to the symbol childNames
. In addition, Lua scripts can
access the activation state and result and parameter values of their
direct children with the child
function. However, grand children
cannot be accessed.
The child
function takes one parameter, the
name of the child, and returns a Lua table containing the following
properties:
active
: A boolean indicating if the child is currently active.
parameter
: The child's parameter value.
result
: The child's result value.
port(name)
: The truth value of the corresponding port of the child.
The following example shows how to find all currently active children:
local active = {}
for i, childName in ipairs(childNames) do
if child(childName).active then
active[#active + 1] = childName
end
end
Note: Variable values can only be accessed by a state itself and not
using the child()
function.
Services, Operations and Events¶
To interact with services, the core exposes the function
service(name)
. It takes exactly one parameter, the name of the
service to access. The return value of the service
function is a
table that contains two functions, operation(name)
and
event(name)
. The name parameter is either the name of the
operation or the name of the event to access.
The event
function returns the latest event value sent by the
corresponding service or nil
if none has been received yet. The
value corresponds to the declared event type and is translated to a
Lua value according to the same rules that are used for translating
parameter and result values.
The operation
function returns a table with the following fields:
call(request)
: A function to call the operation. The parameter must be a Lua value that corresponds to the declared operation request type. The function does not have a meaningful return value. However, the call fails if a call to the same operation is already pending, i.e. if the operation has been called in this state in this macro step.
status
: A string indicating the status of a previous operation call. One of the following values;
"unknown"
: The operation has not been called.
"pending"
: The operation has been called but no result has been received yet.
"success"
: The operation call succeeded and theresult
field contains the result value.
"error"
: The operation call failed and theerror
field contains the corresponding error value returned by the service.
"internalError"
: An internal error occurred. Neither a result nor an error value could be received.
result
: The result value of a successful operation call ornil
.
error
: The error value returned by a failed operation call ornil
.
The core manages operation calls on a per-state basis. In other words, operation calls are tracked separately for each state. This allows to call the same operation in the same macro step from multiple states. The individual correct result values are exposed to the corresponding calling states. Result values stay valid for a complete macro step. In particular that means that if a state called an operation in a previous macro step and received a result in this macro step, the result will be available even if the state makes another call. The result will however be invalidated in the next macro step if for the new operation call, no result has been received so far.
Results stay valid for a complete macro step. Between macro steps, results are kept as long as a state is active and until the state calls the operation again.
Third-Party Lua Modules¶
The core provides support for third-party Lua modules that provide additional functionality. Currently, only a matrix module is provided (also refer to the github page of the matrix module for more details).
Modules are placed in a sub directory called lua
in the core and
can be loaded with Lua's require
function. The following example
shows how to load and use the matrix
module:
matrix = require("matrix")
foo = matrix {1, 2, 3, 4}
foo_inverted = matrix.invert(foo)
Logging Data¶
For simple debugging, the core provides the two functions print
and printf
that allow to log data on a specific logger of the
core. It must be noted that both functions always print a newline as
the last character. The reason is that the print functions actually
use a logger which is always line oriented. However, multiline
printing is possible by using \n
in strings.
The print
function takes an arbitrary number of parameters and
prints them.
The printf
function prints according to a format string. The
format string is a string with arbitrary characters and sequences of
format sequences. Format sequences are strings that begin with a
percent character (%
). The following format sequences are
supported:
%1
,%2
, ...,%9
: Print the first, second, ..., ninth parameter after the format string.
%{n}
: Print the nth parameter after the format string.
%p
: Print the parameter value of this state.
%r
: Print the current result value of this state.
%%
: Print the % character.