123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- Action Language
- ===============
- The primary language of the Modelverse, is its action language.
- This language serves as a nicer representation of the underlying Modelverse Graph Language, which is stored as a graph.
- The action language gets parsed by the parser, resulting in a kind of abstract syntax graph.
- This abstract syntax graph highly resembles an executable graph in the Modelverse Graph Language.
- Users will mainly use this language to write actions and constraints, but maybe also to implement their own interfaces, or override core functionality of the Modelverse.
- .. warning::
- The current parser is unable to handle whitespaces in a general way.
- As such, all indentation needs to be done using tabs, and the difference needs to be exactly 1.
- This is different from Python, where tabs and whitespaces can be mixed, and the number can even vary.
- Files
- -----
- There are two kinds of files: code files, and headers.
- This distinction is similar to C and related languages.
- Code in header files will always be copied throughout all including files.
- As such, it is a good idea to have header files which declare the signatures of functions, but leave the actual implementation to the code files.
- Code files do not need to import the headers they are implementing: all variable names are automatically shared.
- Language description
- --------------------
- The language is inspired by Python syntax, and highly resembles it.
- Nonetheless, it is a lot simpler.
- In the remainder of this subsection, we go over the different language constructs.
- If
- ^^
- The IF construct is similar to that found in other languages.
- Its structure is as follows::
- if condition1:
- do_when_condition1
- elif condition2:
- do_when_condition2
- else:
- do_otherwise
- Each condition can be an expression.
- The code blocks can be any other kind of code.
- Just like Python, indentation is the only way to structure code.
- Unlike Python, only tabs are allowed (thus no space), and the number of tabs must be exactly one higher for a deeper block.
- The presence of an "elif" and "else" is optional.
- While
- ^^^^^
- The WHILE construct is similar to that found in other languages.
- Contrary to Python, there is no support for the "else" construct.
- Its structure is as follows::
- while condition:
- action
- Conditions and actions are similar to the If construct.
- Break
- ^^^^^
- Whereas this is supported in the Modelverse, the parser currently does not consider this keyword.
- Continue
- ^^^^^^^^
- Whereas this is supported in the Modelverse, the parser currently does not consider this keyword.
- Return
- ^^^^^^
- The RETURN construct is again similar to how it is expected.
- To prevent ambiguity in the grammar, an exclamation mark should follow after the expression to return.
- Its structure is as follows::
- return expression!
- The expression can be any expression, similar to the condition in an If and While.
- Function call
- ^^^^^^^^^^^^^
- Function calls happen like usual, by appending an opening and closing parenthesis at the end.
- Its structure is as follows::
- my_function(argument_a, argument_b)
- Arguments can again be any kind of expression.
- Named parameters are not supported in the grammar, though the Modelverse can internally handle them.
- Function definition
- ^^^^^^^^^^^^^^^^^^^
- Defining a function makes the function available as a variable in the remainder of the context.
- Forward declaration is unnecessary: all function names are retrieved before going over the body of the functions.
- This makes mutual recursion easy.
- A function needs to define its return type, as well as the type of all its parameters.
- In case the type is unknown, or can be anything, *Element* can be used as a kind of "void pointer".
- Its structure is as follows::
- Element function function_name(parameter_a : Integer):
- body_of_the_function
- First comes the returntype, followed by the keyword "function".
- Again, indentation needs to happen using tabs.
- Assignment
- ^^^^^^^^^^
- Assignment is like usual.
- Its structure is::
- a = expression
- This assumes that a is already defined.
- Declaration
- ^^^^^^^^^^^
- All variables used in the Modelverse need to be defined statically.
- Defining a variable reserves a part of the Modelverse State to hold the value for this value.
- As such, variables cannot be used if they are not defined.
- Additionally, a declared variable will have a type defined with it.
- Again, if the type can vary or is unknown, this can be *Element*.
- .. warning::
- Contrary to other languages, declaring a variable does not equal defining the variable.
- Therefore, after a variable is declared, it can be used, but its contents will be non-existing.
- It is wise to always assign a value to a declared value right after declaration!
- Its structure is as follows::
- String abc
- There are two kinds of declaration: local declaration, and global declaration.
- Local declarations happen in the current block of the code, and their references get removed when exiting the block.
- Global declarations have identically the same syntax, but are specified at the top level (*i.e.*, they have no tabs in front of them).
- Global declarations do not assign a value and are thus external references, to be defined in the future or by some other module.
- Sharing between modules is possible this way, as all global names are linked together when linking the application together.
- A global declaration that is never defined is flagged as invalid by the compiler and will prevent compilation.
- Definition
- ^^^^^^^^^^
- Defining a variable is similar to a global declaration, but now there is an immediate assignment.
- Immediate assignment is only possible at the top level.
- Note that the assignment must be of a constant which requires no execution of functions or such.
- Also, it is impossible to assign the value of another variable.
- Its structure is as follows::
- String abc = "abc"
- It is possible that a definition does not yet know the value to assign, or is an empty element.
- To notify the other files that this is the defining element, use the import syntax to assign *?* to it::
- Element abc = ?
- This results in the Modelverse creating an empty node as placeholder for a value.
- The value will now be defined and accessible.
- Imports
- ^^^^^^^
- Direct imports in the Modelverse are possible, but are not recommended for ordinary users.
- This syntax allows a variable to be bound to an absolute location in the Modelverse, which is resolved at compile time.
- The primary use case for this is the creation of bootstrap files, but it is also possible for other purposes.
- Use with care!
- Its structure is as follows::
- String abc = ?path/in/modelverse
- A special case is when the path is empty, which indicates that a new (anonymous) node should be created for it::
- Element abc = ?
- Include
- ^^^^^^^
- Other files can easily be included using the include syntax.
- This is a raw include: the contents of the file are just copied inside the file at that exact spot.
- Generally, you should only include *.alh* files, unless you know what you are doing.
- Constants
- ^^^^^^^^^
- The Modelverse supports a set of constants that can be used.
- All constants can be assigned in a definition of globals.
- ============= ========================================================================== =======
- Constant type Values Example
- ============= ========================================================================== =======
- Integer Any possible integer, either positive (no prefix) or negative (- prefix) 1
- Float Any possible floating point value; scientific notation is not supported 1.0
- Boolean Either True or False True
- String Any possible string, enclosed with either double or single quotes "abc"
- Action An action construct from the Modelverse, prefixed with an exclamation mark !If
- ============= ========================================================================== =======
- Operators
- ^^^^^^^^^
- While operators are seemingly supported by the compiler, these are actually expanded to function calls to relevant functions.
- For example, *1 + 2*, is expanded to *integer_addition(1, 2)*
- User I/O
- ^^^^^^^^
- User input and output is done through the keyworded operations *input()* and *output(msg)*.
- *input()* returns the first message in the input queue of the current user.
- *output(msg)* places the value of the expression in the output queue of the current user.
- All I/O is done using queues: the value is only read and written to a specific place in the Modelverse.
- To actually read or write it at the client side, these special places should be accessed through dedicated Modelverse operations.
- Examples
- --------
- We now show some simple code fragments written in valid Action Language code.
- As this code is directly executable in the Modelverse, the main function is always called "main" and all includes are also present.
- We do not currently handle how to execute this code: this is explained further on.
- Fibonacci
- ^^^^^^^^^
- The Fibonacci code is fairly simple.
- First, the primitives are imported to make sure that we know about all operations on primitives.
- Then, a function *fib* is defined, which will recursively compute the specified Fibonacci number.
- This is wrapped by a *main* function, which takes input from the user and outputs the result of the *fib* function.
- This code looks as follows::
- include "primitives.alh"
- Integer function fib(param : Integer):
- if (param <= 2):
- return 1!
- else:
- return fib(param - 1) + fib(param - 2)!
- Void function main():
- while(True):
- output(fib(input()))
- Factorial
- ^^^^^^^^^
- Similarly, the code for computing a factorial is given below::
- include "primitives.alh"
- Integer function factorial(n : Integer):
- if(n <= 1):
- return 1!
- else:
- return n * factorial(n - 1)!
- Void function main():
- while(True):
- output(factorial(input()))
- Binary to decimal converter
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- A simple binary to decimal converter is given below::
- include "primitives.alh"
- Integer function b2d(param : String):
- Integer value
- value = 0
- Integer length
- length = string_len(param)
- Integer counter
- counter = integer_subtraction(length, 1)
- Integer accumul
- accumul = 1
- while (counter >= 0):
- if (string_get(param, counter) == "1"):
- value = integer_addition(value, accumul)
- accumul = integer_multiplication(accumul, 2)
- counter = integer_subtraction(counter, 1)
- return value!
- Void function main():
- while(True):
- output(b2d(input()))
|