Was this page helpful?

A First Reactor

This page is showing examples in the target language CC++PythonTypeScriptRust. You can change the target language in the left sidebar. See the requirements for using this target.

Minimal Example

A minimal but complete Lingua Franca file with one reactor is this:

target C;
main reactor {
    reaction(startup) {=
        printf("Hello World.\n");
    =}
}
target Cpp;

main reactor {
    reaction(startup) {=
        std::cout << "Hello World." << std::endl;
    =}
}

target Python;
main reactor {
    reaction(startup) {=
        print("Hello World.")
    =}
}
target TypeScript
main reactor {
    reaction(startup) {=
        console.log("Hello World.")
    =}
}

target Rust;
main reactor {
    reaction(startup) {=
        println!("Hello World.");
    =}
}

Every Lingua Franca program begins with a target declaration that specifies the language in which reactions are written. This is also the language of the program(s) generated by the Lingua Franca code generator.

Every LF program also has a main or federated reactor, which is the top level of a hierarchy of contained and interconnected reactors. The above simple example has no contained reactors.

The main reactor above has a single reaction, which is triggered by the startup trigger. This trigger causes the reaction to execute at the start of the program. The body of the reaction, delimited by {= ... =}, is ordinary CCppPythonTypeScriptRust code which, as we will see, has access to a number of functions and variables specific to Lingua Franca.

Examples

Examples of Lingua Franca programs can be found in the examples-lingua-franca repository.

The regression tests have a rich set of examples that illustrate every feature of the language.

Structure of an LF Project

The Lingua Franca tools assume that LF programs are put into a file with a .lf extension that is stored somewhere within a directory called src. To compile and run the above example, choose a project root directory, create a src directory within that, and put the above code into a file called, say, src/HelloWorld.lf. You can compile the code on the command line, within Visual Studio Code, or within the Epoch IDE. On the command line this will look like this:

    > lfc src/HelloWorld.lf
    ... output from the code generator and compiler ...

After this completes, two additional directories will have been created within the project root, bin and src-gen. The bin directory has an executable file called HelloWorld. Executing that file will result, not surprisingly, in printing “Hello World”. The generated source files will be in a subdirectory called HelloWorld within src-gen.

After this completes, an additional src-gen directory will have been created within the project root. The generated code will be in subdirectory called HelloWorld within src-gen. The output from the code generator will include instructions for executing the generated code:

#####################################
To run the generated program, use:

    node ...path-to-project.../src-gen/Minimal/dist/Minimal.js

#####################################
#####################################
To run the generated program, use:

    python3 ...path-to-project.../src-gen/Minimal/Minimal.py

#####################################

Reactor Block

A reactor is a software component that reacts to input events, timer events, and internal events. It has private state variables that are not visible to any other reactor. Its reactions can consist of altering its own state, sending messages to other reactors, or affecting the environment through some kind of actuation or side effect (e.g., printing a message, as in the above HelloWorld example).

The general structure of a reactor definition is as follows:

[main or federated] reactor <class-name> [(<parameters>)] {
    input <name>:<type>
    output <name>:<type>
    state <name>:<type>(<value>)
    timer <name>([<offset>, [<period>]])
    logical action <name>[:<type>]
    physical action <name>[:<type>]
    reaction(<triggers>) [<uses>] [=> <effects>] {= ... body ...=}
    <instance-name> = new <class-name>([<parameter-assignments>])
    <instance-name> [, ...] => <instance-name> [, ...] [after <delay>]
}
[main] reactor <class-name> [(<parameters>)] {
    input <name>:<type>
    output <name>:<type>
    state <name>:<type>(<value>)
    timer <name>([<offset>, [<period>]])
    logical action <name>[:<type>]
    physical action <name>[:<type>]
    [const] method <name>(<parameters>):<type> {= ... body ...=}
    reaction(<triggers>) [<uses>] [=> <effects>] {= ... body ...=}
    <instance-name> = new <class-name>([<parameter-assignments>])
    <instance-name> [, ...] => <instance-name> [, ...] [after <delay>]
}
[main or federated] reactor <class-name> [(<parameters>)] {
    input <name>
    output <name>
    state <name>(<value>)
    timer <name>([<offset>, [<period>]])
    logical action <name>
    physical action <name>
    [const] method <name>(<parameters>) {= ... body ...=}
    reaction(<triggers>) [<uses>] [=> <effects>] {= ... body ...=}
    <instance-name> = new <class-name>([<parameter-assignments>])
    <instance-name> [, ...] => <instance-name> [, ...] [after <delay>]
}

Contents within square brackets are optional, contents within <...> are user-defined, and each line may appear zero or more times, as explained in the next pages. Parameters, inputs, outputs, timers, actions, and contained reactors all have names, and the names are required to be distinct from one another.

If the reactor keyword is preceded by main or federated, then this reactor will be instantiated and run by the generated code.

Any number of reactors may be defined in one file, and a main or federated reactor need not be given a name, but if it is given a name, then that name must match the file name.

Reactors may extend other reactors, inheriting their properties, and a file may import reactors from other files. If an imported LF file contains a main or federated reactor, that reactor is ignored (it will not be imported). This makes it easy to create a library of reusable reactors that each come with a test case or demonstration in the form of a main reactor.

Comments

Lingua Franca files can have C/C++/Java-style comments and/or Python-style comments. All of the following are valid comments:

    // Single-line C-style comment.
    /*
     * Multi-line C-style comment.
     */
    # Single-line Python-style comment.
    '''
       Multi-line Python-style comment.
    '''

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

Contributors to this page:
Eeal  (17)
SBSoroush Bateni  (4)
PDPeter Donovan  (1)

Last updated: Jun 28, 2022