Was this page helpful?

Expressions

This page is showing examples in the target language CC++PythonTypeScriptRust. You can change the target language in the left sidebar.

A subset of LF syntax is used to write expressions, which represent values in the target language. Expressions are used to initialize state variable and to give values to parameters. Arbitrary expressions in the target language can always be given within delimiters {= ... =}, but simple forms do not require the delimiters. These simple forms are documented here.

Basic expressions

The most basic expression forms, which are supported by all target languages, are the following:

  • Literals:

    • Numeric literals, e.g. 1, -120, 1.5, 3.14e10. Note that the sign, if any, is part of the literal and must not be separated by whitespace.
    • String literals, e.g. "abcd". String literals always use double-quotes, even in languages which support other forms (like Python).
    • Character literals. e.g. 'a'. Single-quoted literals must be exactly one character long —even in Python.
    • Boolean literals: true, false, True, False. The latter two are there for Python.
  • Parameter references, which are simple identifiers (e.g. foo). Any identifier in expression position must refer to a parameter of the enclosing reactor.

  • Time values, e.g. 1 msec or 10 seconds. The syntax of time values is integer time_unit, where time_unit is one of the following:

    • nsec or ns: nanoseconds
    • usec or us: microseconds
    • msec or ms: milliseconds
    • sec, second, or s: seconds
    • minute or min: 60 seconds
    • hour: 60 minutes
    • day: 24 hours
    • week: 7 days

    Each of these units also support a plural version (e.g., nsecs, minutes, and days), which means the same thing.

    The time value 0 need not be given a unit, but for all other values, the unit is required.

    Time values are compatible with the time type.

  • Escaped target-language expression, e.g. {= foo() =}. This syntax is used to write any expression which does not fall into one of the other forms described here. The contents are not parsed and are used verbatim in the generated file.

For instance, to have a 2-dimensional array as a parameter in C:

reactor Foo(param:{= int[][] =}({= { {1}, {2} } =})) {
    ...
}

Both int[][] and { {1}, {2} } are C fragments here, not LF.

For instance, to assign a 2-dimensional list as an initial value to a parameter in the Python target:

reactor Foo(param({= ((1, 2, 3), (4, 5, 6)) =})) {
    ...
}

Collections

This page is showing examples in the target language CC++PythonTypeScriptRust. You can change the target language in the left sidebar.

To avoid the awkwardness of using the code delimiters {= ... =}, Lingua Franca supports initialization of simple arrays and similar structures. The interpretation is slightly different in each target language.

In C, a parameter or state may be given an array value as in the following example:

reactor Foo(param:double[](0.0, 1.0, 2.0)) {
    ...
}

This will become an array of length three. When instantiating this reactor, the default parameter value can be overridden using a similar syntax:

main reactor {
    f = new Foo(param = (3.3, 4.4, 5.5));
}

See the Target Language Details for details and alternative syntaxes.

In C++, initial values for a parameter or state can be used to pass arguments to a constructor, as in the following example:

    state x: int[](1,2);

Here, the type int[] is translated by the code generator into std::vector and the (1,2) to constructor arguments, as in new std::vector(1,2). See the Target Language Details for details and alternative syntaxes.

In Python, a parameter or state variable may be assigned an array expression as its initial value, as in the following example:

reactor Foo(param(1, 2, 3)) {
    state x(1, 2, 3)
    ...
}

The Python target interprets the (1, 2, 3) expression differently depending on whether the assignee is a parameter or a state variable. For parameters, the (1, 2, 3) expression will translate into an immutable Python tuple (i.e., param = (1, 2, 3)). For state variables, the (1, 2, 3) expression will translate into a mutable Python list (i.e., x = [1, 2, 3])). The reason behind this discrepancy is that parameters are assumed to be immutable after instantiation (in fact, they are also read-only in reaction bodies), but state variables usually need to be updated during execution.

Notice that even though the tuple assigned to the parameter is immutable (you cannot assign new values to its elements), the parameter itself can be overridden with another immutable tuple when instantiating the reactor:

main reactor {
    f = new Foo(param = (3, 4, 5))
}

See the Target Language Details for details and alternative syntaxes.

In TypeScript, a parameter or state variable may be assigned an array expression as its initial value, as in the following example:

reactor Foo(param:{=Array<number>=}({= [1, 2, 3] =})) {
    state x:{=Array<number>=}({= [0.1, 0.2, 0.3] =});
}

See the TypeScript reactor documentation for details and alternative syntaxes.

FIXME: Rust

Lingua Franca is an open source project. Help us improve these pages by sending a Pull Request

Contributors to this page:
Eeal  (6)
MLMarten Lohstroh  (1)
HKHokeun Kim  (1)
SBSoroush Bateni  (1)

Last updated: May 27, 2022