JavaScript code generation
JavaScript code generation is currently an experimental feature. |
The CIF code generator can generate JavaScript code from a CIF specification. It is assumed the reader of this page is familiar with the general information of the CIF code generator tool. This page describes specific information applicable only to JavaScript code generation.
Supported specifications
The CIF code generator supports a subset of CIF specifications. Generation of JavaScript code does not impose additional restrictions. See the Supported specifications section of the CIF code generator page for more information.
Options
The JavaScript code generator only uses the common options that apply to all target languages/platforms of the CIF code generator. It has no specific options of its own.
The code prefix that can be configured using a common option, is used in the generated JavaScript code as prefix for class names.
Compilation
The generated JavaScript code does not require compilation. The generated code is complete, and can be used as is, without any CIF related library or runtime. No additional dependencies or libraries are required. Only standard JavaScript functions, part of for instance any browser, are needed.
Generated files
JavaScript code generation leads to two files being generated:
<prefix>_class.js
<prefix>_utils.js
where <prefix>
is replaced by the code prefix configured using the Code prefix option.
The first file contains the code for all the features of the specific CIF model, primarily in a class named <prefix>_class
. The second file contains the code for utility methods, primarily in a class named <prefix>Utils
. The functionality from the second file is used the first file.
Executing the code
The code can be executed in multiple ways:
execOnce
methodexecOnce(newTime)
Invoke this method to execute the code once. Inputs are read, transitions are executed until none are possible, output is written, etc.
The
newTime
is the time in seconds, since the start of the first execution of this method. For each invocation, the time that has elapsed so far should be provided. This becomes the new value of variabletime
.Using this method, you decide when you invoke this method, and with what values to use for variable
time
. This approach allows full control.exec
methodexec()
Invoke this method to execute the code repeatedly, without ever stopping. This repeatedly invokes the
execOnce
method.The
frequency
field (in the same class) can be used to configure how often, in number of times per second, the code should be executed. By given a frequency of100
, the method attempts to execute the code every 10 milliseconds. If a single execution takes less than 10 milliseconds, the method will wait for the remainder of what is left of the 10 milliseconds. However, if a single execution takes more than 10 milliseconds, the next execution is immediately started.It is also possible to execute the code repeatedly, as fast as possible, without any delays. As soon as a single execution has finished, another execution is started. This kind of behavior can be obtained by providing a negative or zero value for
frequency
.
execOnce
provides flexibility, but lacks automation for repeated execution. exec
provides automatic repeated execution, but lacks flexibility. To support automatic repeated execution, with pausing/resuming support, and the ability to reset and restart the execution, use the following methods intead of execOnce
and exec
:
start
methodstart()
Start or continue execution. If execution is already in progress, invoking this method has no effect.
stop
methodstop()
Stop or pause execution. If execution is not in progress, invoking this method has no effect.
reset
methodreset()
Invokes the
stop
method and resets the state. If execution is subsequently started via thestart
method, it starts from the initial state.
Environment interface
The code generated for the CIF model does not do anything useful by itself. Only once it is coupled to the environment, can the CIF model become useful. The following methods are provided in the interface of the generated class as methods that may be modified or provided a (different) implementation in a derived class:
updateInputs
methodupdateInputs()
In this method, you should update the values of the input variables of the CIF model. Note that you should obtain these from the environment. You should not access the state of the CIF model from this method, as it may not be initialized or up-to-date yet.
If you want to update the variable, you should always assign completely new fresh values. Don’t modify arrays and tuples in-place, as that may lead to other variables being changed as well.
preExec
methodpreExec()
This method is invoked each time, just before the code for the CIF model is executed. This method is invoked before the
updateInputs
method is invoked.You should not access the state of the CIF model from this method, as it may not be initialized or up-to-date yet.
postExec
methodpostExec()
This method is invoked each time, just after the code for the CIF model is executed. In this method, you should write the output variables of the CIF model to the environment. Since the code for the CIF model was just executed, these variables may have new values.
All discrete and continuous variables of the CIF model are available, as are variable
time
and the current locations of all of the automata with at least two location.The code to write the output values to the environment is the dual to reading the inputs from the environment, as is done in the
updateInputs
method.infoExec
methodinfoExec(duration, cycleTime)
This method informs about the duration of a single execution of the code generated for the CIF model. The
duration
is the total number of milliseconds spent executing the code. ThecycleTime
is the desired maximum duration of the execution, in milliseconds, or-1
if not available.You can use this method to detect when the code runs longer than the desired maximum duration, and thus the desired execution frequency can not be achieved. You can also use this method to figure out the variability of the duration of execution.
The
doInfoExec
field of the class can be used to configure whether this method is invoked during execution by theexec
method. This is enabled (true
) by default.By default, this method does not do anything.
infoEvent
methodinfoEvent(idx, pre)
This method informs about events that are about to be executed or have just been executed. The
idx
is the 0-based index of the event. You can feed this index to thegetEventName
method to obtain the absolute name of the event. Thepre
istrue
if the event is about to be executed, andfalse
if the event has just been executed.You can use this method to be informed about what the code does during execution. You could for instance log that for debugging.
The
doInfoEvent
field of the class can be used to configure whether this method is invoked during execution. This is enabled (true
) by default.This method can print information about event transitions that are executed. The
doTransitionPrint
field of the class can be configured to enable or disable printing of transition output. By default, transition printing is enabled (true
).This method can print information about states that are reached. The
doStatePrint
field of the class can be configured to enable or disable printing of state output. By default, state printing is disabled (false
).infoPrintOutput
methodinfoPrintOutput(text, target)
This method informs that new print output has been generated during execution. The
text
is the text that is to be printed. Thetarget
indicates the file or special target to which text is to be printed. If printed to a file, an absolute or relative local file system path is given. Paths may contain both/
and\
as file separators. Supply the path to the<prefix>Utils.normalizePrintTarget
method to normalize the path to use/
file separators.There are two special targets:
:stdout
to print to the standard output stream, and:stderr
to print to the standard error stream.The
doInfoPrintOutput
field of the class can be used to configure whether this method is invoked during execution. This is enabled (true
) by default.By default, print output is printed to the JavaScript
console
. Output to files is also printed to the console, and is prefixed with the path.
Data access and manipulation
For each CIF constant, a field is generated in the JavaScript class. Similar fields are generated for the state variables (discrete and continuous variables), and the input variables. A time
field is always present and contains the current model time.
For each internal user-defined function of the CIF model, a method is generated in the JavaScript class. Similarly, a method is generated for each algebraic variable of the CIF model, as well as for the derivative of each continuous variable (except variable time
).
The standard library functions and operators that are supported by the code generation, are also available, in the <prefix>Utils
class. Not all operators and standard library functions are available. Only those that have no corresponding JavaScript operator or method, or behave differently with respect to runtime errors, are available in this class.
For more information on the names of the generated field and methods, see the section on naming below.
Data types
The following table lists CIF types supported by the code generator, and their equivalent in the generated JavaScript code:
CIF type | JavaScript type | Tuple postfix |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Notes:
For each unique tuple type (ignoring integer and array ranges of the types of the fields, as well as field names) a JavaScript class is generated. Their names all start with
CifTuple_
, and end in a postfix that describes the type. The Tuple postfix column in the table lists the texts used for each type in the postfix. For instance, for atuple(tuple(int x; real y; string z) a, list[3] int b)
type, the tuple class would be namedCifTuple_T2T3IRSLI
.Due to preprocessing all enumerations are merged together into a single enumeration. As such, always exactly one JavaScript
enum
is generated for a CIF model.
Runtime errors
Some CIF models that are syntactically valid, may lead to runtime errors when simulated or executed. For instance, there may be a division by zero, an out of bounds projection, or an assignment may lead to the range of the assigned variable being violated. The generated JavaScript code detects all such problems and throws a <prefix>Exception
in such cases. The exception indicates what caused the runtime error, using an informative end-user readable message.
Naming
The generated code will contain names for variables, functions, etc. The names in the generated code are based on the absolute names of the objects in the original CIF model. The names are further influenced by the linearization algorithm. Essentially, the absolute names are used, where each .
is replaced by a _
. Furthermore, a _
is added at the end, to avoid conflicts with other non-generated names, JavaScript keywords, etc. For instance, for an automaton a
with a discrete variable b
in it, the absolute name is a.b
. In the JavaScript code, the variable will be named a_b_
.
The code generator ensures unique names in the generated JavaScript code. If the same JavaScript name results from two different CIF objects, one of them is renamed, by adding a 2
, or 3
, or 4
, etc to make it unique. For instance, if the CIF model has a constant named a_b
in the top level scope, and a constant named b
in the a
automaton, both would be named a_b_
. One of them is renamed to a_b_2
. If such renaming takes place, a warning is printed to the console.
CIF model | JavaScript code | Example CIF name | Example JavaScript name |
---|---|---|---|
Constant |
Field |
|
|
Discrete variable |
Field |
|
|
Continuous variable |
Field |
|
|
Derivative of a continuous variable |
Method |
|
|
Algebraic variable |
Method |
|
|
Input variable |
Field |
|
|
User-defined function |
Method |
|
|
Parameter of a user-defined function |
Method parameter |
|
|
Local variable of an internal user-defined function |
Local variable of a method |
|
|
Enumeration |
Enumeration class |
|
|
Enumeration literal |
Object key |
|
|
Tuple type |
Tuple class |
n/a |
|
Notes:
As linearization is applied on the CIF model prior to generating JavaScript code, all enumerations are merged together to a single enumeration. As such, always exactly one JavaScript
enum
is generated for a CIF model.For details on tuple types and the classes that are generated for them, see the data types section above.