Expressions¶
Arithmetic expressions¶
The operators +, -, *, /, %
represent the addition, substraction, product,
division and modulo operations. They have the conventional precedence level.
arithm_expression
: expression '+' expression
| expression '-' expression
| expression '*' expression
| expression '/' expression
| expression '%' expression
| '+' expression
| '-' expression
;
Applied on numbers (integers or floats)¶
The operators +, -, *
convert their operands to floats and return a float
as soon as one of the two operands is a float. On the contrary they return an
integer when both operands are integers.
The operator /
converts its operands to floats and returns a float, even
if the two operands are integers.
The operator modulo %
can be applied on integers only.
Warning
In previous versions of LocalSolver the division followed the C convention : If the two operands were integers, the result was also an integer. The behavior has changed from the 4.0 release.
Applied on strings¶
Only the +
operator is defined for strings. It corresponds to the
concatenation operator. When one of the two operands is a string, then the
other is converted to a string and a new string concatenating the two operands
is returned. For instance "abc"+12
returns abc12
.
Applied on LSExpressions¶
When one of the two operands is an LSExpression, then the operators return an LSExpression representing the arithmetic operation of these two terms in the mathematical model. If the mathematical model cannot handle one of the operand (e.g if one of them is a string), an exception is thrown.
Other cases, other types¶
By default, throws an exception. See the different modules for additionnal information on the available arithmetic operators for each type.
Examples:
a = 10;
b = a + 5.0; // a is equals to 15
c <- a * 3.0; // a is converted to an LSExpression
// and a new LSExpression of type PRODUCT is added to the model.
d = "foo" + 42 // 42 is converted to a string, then the concatenation is performed.
// This arithmetic operation will throw an exception:
// the modulo operation is not overloaded for strings.
e = "foo" % 2;
Relational expressions¶
The relational operators are ==, !=, <, >, >= and <=
.
relational_expression
: expression '<' expression
| expression '>' expression
| expression '==' expression
| expression '!=' expression
| expression '>=' expression
| expression '<=' expression
;
Applied on numbers (integers or floats)¶
The operators return a boolean value equal to 1 when the comparison is true, 0 otherwise. If one of the operand is a float, the operators convert both operands to floats and then, compare them.
Applied on strings¶
When one of the two operands is a string then the other is converted to a string. Then, the comparison is done lexicographically.
Applied on LSExpressions¶
When one of the two operands is an LSExpression then the operators return an LSExpression representing the comparison of these two terms in the mathematical model. If the mathematical model cannot handle one of the operand (e.g if one of them is a string), an exception is thrown.
Applied on nil¶
The operators ==, !=
can be used to compare a value with nil
.
In that case, the operators return 1 (respectively 0) if the compared operand
is equals (respectively not equals) to nil.
The other relational operators (<, >, <=, >=
) cannot be used with nil.
Other cases, other types¶
By default, throws an exception. See the different modules for additionnal information on the available relational operators for each type.
Examples:
a = {1,8};
b = {1,8};
println(8 < 9.2); // print 1
println(a == b); // throw an exception since "==" is not defined on maps
println("abc" <= "abcde"); // print 1
println("abc" == "aBc"); // print 0 since comparison is case-sensitive
Logical expressions¶
The operators !, &&, and ||
represent the boolean negation, logical and, and
logical or.
logical_expression
: expression '&&' expression
| expression '||' expression
| '!' expression
;
Applied on booleans¶
When applied on booleans (0 or 1), the logical operators use short-circuit evaluation: the second argument is interpreted only if the value of the first argument is not sufficient to determine the whole value of the expression.
- The unary operator ! returns 1 if its argument is 0, 0 otherwise.
- The operation
x && y
first evaluates x; if x is 0 (false), its value is returned; otherwise, y is evaluated and the resulting value is returned. - The operation
x || y
first evaluates x; if x is 1 (true), its value is returned; otherwise, y is evaluated and the resulting value is returned.
Applied on LSExpressions¶
As soon as one of the operands is an LSExpression the logical operation returns an LSExpression representing the operation in the mathematical model. In that case, both operands are evaluated. If the mathematical model cannot handle one of the operand (e.g if one of them is a string), an exception is thrown.
Other cases, other types¶
By default, throws an exception. See the different modules for additionnal information on the available logical operators for each type.
Conditional (ternary) expressions¶
logical_expression
: expression '?' expression ':' expression
;
First argument is boolean¶
The ternary operation cond ? trueExpr : falseExpr
first evaluates cond
expression. If cond
is 1, then trueExpr
is evaluated and returned,
otherwise falseExpr
is evaluated and returned. Note that only two of the
three operands are evaluated. trueExpr
and falseExpr
can be of any type.
First argument is an LSExpression¶
The operation returns an LSExpression representing this conditional operation in the mathematical model (operator IF). In that case, the three operands are evaluated. If the mathematical model cannot handle one of the operand (e.g if one of them is a string), an exception is thrown.
Other cases, other types¶
By default, throws an exception. See the different modules for additionnal information on the availability of the ternary operator for each type.
Indexed expressions¶
The binary operator []
is the index selector. It is appliable to maps or
any other types that contain subvalues.
index_expression
: expression '[' expression ']'
;
Applied on maps¶
The main usage of the index selector is for maps. a[b]
returns the value
in a
for the key b
. The key can be of any type except nil that
has a special meaning. If the key does not exist in the map, no error is thrown
but nil is returned.
Applied on LSExpressions¶
As soon as one of the operands (value or index) is an LSExpression the index selector returns an LSExpression representing the index operation in the mathematical model (operator AT). If the mathematical model cannot handle one of the operand (e.g if one of them is a string), an exception is thrown.
Applied on modules¶
The key must be a string. In that case, the expression a[b]
returns the
global variable with the name represented in b
for the module a
.
If the global variable was not declared in the module, no error is thrown but
nil is returned.
Other cases, other types¶
By default, throws an exception. See the different modules for additionnal information on the availability of the index operator for each type.
Member expressions¶
The binary operator .
is the member selector. Most of the time, its semantic
is similar to the index selector, but it throws an error if the key is not
present in the underlying container. Furthermore, the type of the index is
restricted to string literals only (formely, an identifier).
In conjunction with maps, it is used for Object-oriented-programming.
member_expression
: expression '.' identifier
;
Applied on maps¶
The expression a.b
returns the value in a
for the key b
, where b
is a string literal. Contrary to the index operator, if the key does not exist
in the map, an exception is thrown.
Applied on modules¶
The expression a.b
returns the global variable with the name b
for the module a
. Contrary to the index operator, if the global variable
was not declared in the module, an exception is thrown.
Other cases, other types¶
As the member selector is the base of Object-oriented-programming, it is extensively used in all modules and types. Please refer to the documentation of each module for additionnal information.
Operator precedence & associativity¶
- Expressions inside parentheses are evaluated first
- Nested parentheses are evaluated from the innermost to the outermost parentheses.
- Operators in the following tables are ranked by decreasing precedences: operators with higher precedence are evaluated before operators with relatively lower precedence.
- Operators on the same line have equal precedence. Their associativity determines the execution order.
Description | Operators | Associativity |
---|---|---|
Parentheses, index and member selector operators | ( ) [ ] |
left to right |
Boolean negation, opposite and typeof operators | - + ! typeof |
left to right |
Multiplication, division, modulo | * / %` |
left to right |
Addition, substraction | + - |
left to right |
Relational and type compatibility operators | < > <= >= is |
left to right |
Equality operators | == != |
left to right |
Logical and | && |
left to right |
Logical or | || |
left to right |
Ternary conditional | ? : |
right to left |
Assignment | = <- |
right to left |
Map declaration¶
LSP language offers a shortcut to declare maps or arrays quickly with the
{ }
brace syntax.
map_expression
: '{' '}'
| '{' map_list '}'
;
map_list
: expression
| map_key '=' expression
| map_key ':' expression
| map_list ',' expression
| map_list ',' map_key '=' expression
| map_list ',' map_key ':' expression
;
map_key
: string
| identifier
| integer
| '-' integer
;
The declaration of a map starts with the {
character and ends with }
.
Between these two delimiters, you can define a list of values or a list of
<key, value> pairs. A map is both an associative table and an array. Thus, if
you only set a value, without a key, a default integer key is automatically
attributed to the value. This automatic key is equals to the biggest integer key
presents in the map plus one or zero if the map does not contains integer keys.
If the same key is attributed more than once in the declaration, only the last value is retained.
Examples:
// Affects values -5, 4 and "foo" to the keys 0, 1 and 2
a = {-5, 4, "foo"};
// Affects values -3, -5, 8, -78 and 22 to the keys 0, "key1", 10, 11 and 12
b = {
-3,
"key1" : -5,
10 : 8,
-78,
22
};
// Bigger example with nested maps
c = {
"key1": 42,
"key2": 31,
"foo",
-78.4e+6,
"key3": {
"nested map",
4,
-8
}
};
Note
Even if maps accept keys of any types, only string keys and int keys are accepted in the short map declaration.