Operators
Arithmetic Operations
Operator | Name | Use Type | Result Type |
---|---|---|---|
+ | Unary plus | + any_numeric_type | any_numeric_type |
- | Unary minus | - any_numeric_type | any_numeric_type |
+ | Plus | any_numeric_type + numeric_type numeric_type + any_numeric_type | any_numeric_type |
- | Minus | any_numeric_type - numeric_type numeric_type - any_numeric_type | any_numeric_type |
* | Multiply | numeric_type * numeric_type | numeric_type |
/ | Divide | numeric_type / numeric_type | float_type |
div | Integer divide | integer_type div integer_type | integer_type |
mod | Integer modulo | integer_type mod integer_type | integer_type |
For numeric_types, the arithmetic operators '+' (addition), '-' (subtraction, negation) and '*' (multiplication) retain their normal mathematical meanings. There are two forms division, normal division '/' which always gives a floating point result. Division 'div' and 'mod' provides integer division and modulus (remainder). Note that the modulo operator always returns a positive value and that if q = a div b and r = a mod b then a = b * q + r.
Unary Plus and Minus
Unitary plus is included for completeness. It currently does nothing. It is often used with inf and infinity to clarify when compared to -inf and -infinity
Unary minus has normal meaning of negation.
Negation of a range negates both limits, so -(a..b) = (-b..-a).
Negation of an rlist negates all the ranges, but retains the well orderliness,
so -(a..b | c..d) = (-d..-c | -b..-a).
Addition and Subtraction
Normal addition is applied when both sides of an expression are numeric values. A numeric value can be added or subtracted from range or rlist. But ranges and rlists cannot be added or subtracted from each other and will result in an error.
Subtraction is carried out by adding the negated right hand side. So a - b = a + -b and a - (c..d) = a + (-d..-c).
Expression | Example | Result |
---|---|---|
field_type + field_type | 5 + 10 -infinity + 123 -infinity + infinity | 15 -infinity Error |
range_type + field_type field_type + range_type |
(8..16) + 20 250 + (500..+infinity) -infinity + (500..+infinity) |
28..36 750..+infinity Error |
range_type + range_type | (8..16) + (10..20) | Error |
rlist_type + field_type field_type + rlist_type |
(8..16 | 20..50) + 20 250 + (-infinity..90 | 500..+infinity) |
28..36 | 40..70 -infinity..340 | 750..+infinity |
String Concatenation
The '+' operator is also used to combine string values. If both sides of the operator are string values, the right hand side will be appended to the left hand. If just one side is a string value then the other is stringified first (see write Statement).
Multiplication, Division and Modulo
Glich has two distinct division operators, floating point division '/' and integer division 'div'. The 'mod' operator is only used for integer modulo.
Currently, these operators can only be used with numerical types. The integer division and modulus operators are based on Euclidean integer division.
Multiplication of any number with the ? value is an error.
Multiplication of any number with +infinity (except ? and -infinity) results in +infinity.
Multiplication of any number with -infinity (except ? and +infinity) results in -infinity.
Multiplication of -infinity and +infinity values is an error.
For the normal division operator, the following conditions apply.
The divisor must be a non-zero integer value.
Using the values 0, ?, -infinity or +infinity results in an error.
If the dividend is -infinity and the divisor valid, the result is also -infinity.
If the dividend is +infinity and the divisor valid, the result is also +infinity.
Division of the ? value results in an error.
For the modulo operator, the following conditions apply.
Using ? on the left hand side of the operation results in an error.
Using -infinity or +infinity on the left hand side of the operation always equals 0.
Use of 0, ?, -infinity or +infinity on right side the operation results in an error.
Note, these rules have been set to ensure the following is always true:
If q = a div b and r = a mod b then a = b * q + r
and r is always positive.
Expression | Example | Result |
---|---|---|
field_type * field_type | 5 * 10 -infinity * 123 -infinity * +infinity |
50 -infinity Error |
field_type div field_type | 10 div 5 -infinity div 123 123 div +infinity |
2 -infinity Error |
field_type mod field_type | 21 mod 5 -100 mod -6 -infinity mod 2 |
1 2 0 |
Range Operator
The binary range operator creates a range value which is just large enough to include
both its operands.
The order of the operands is not significant.
The operands can be either field or range types. Numbers will be converted to a field if possible.
The values -infinity and +infinity may be used.
Use of the ? value is an error.
Note, the size of a range is always greater than 0.
Example | Result |
---|---|
5..10 | 5..10 |
123..-infinity | -infinity..123 |
?..40 | Error |
(5..10)..6 | 5..10 |
(5..10)..(15..8) | 5..15 |
48..25..5..10 | 5..48 |
Set Operators
The set operators operate on set_types, any numerical_type will be promoted as necessary. The output is always a demoted set_type.
Operator | Name | Example | Result |
---|---|---|---|
! | Complement | !0 !(-infinity..-1 | 1..+infinity) | -infinity..-1 | 1..+infinity 0 |
| | Union | 1..100 | 50..150 | 1..150 |
&& | Intersection | 1..100 && 50..150 | 50..100 |
^^ | Symmetric difference | 1..100 ^^ 50..150 | 1..49 | 101..150 |
\\ | Relative complement | 1..100 \\ 50..150 | 1..49 |
Comparison Operators
The comparison operators must have operands of the same type, after allowing for type promotion. The output is always a boolean type.
Any types, other than error types, can be compared for equality or non-equality.
Comparison operators that compare magnitude can only be used with numeric or string types. Use with any other type results in an error.
Boolean Operators
The unary prefix operator 'not' and the binary operators 'and' and 'or' can be used with boolean types only. Use with any other type will produce an error.
Subscript operators
The subscript operators allow access to to the various parts of the more complex value types.
Index operator
Used in the form Value[ Index ], the square brackets are used to enclose an index into left hand value.
If the value is a rlist type and the index a number type, then the result is the range pointed to by the (zero based) index.
If the value is an object type and the index a number type, then the result is the member value. If the index is a name or string value then this is matched with an objects member variable name and the result is the corresponding value.
Example | Result |
---|---|
(8..16|20..50|75..99)[1] | 20..50 |
{complex 10, 25}[1] | 25 |
{complex 10, 25}[real] | 10 |
Function Operator
Operator | Name | Use Type | Result Type |
---|---|---|---|
@ | Unary function.qualifier( arguments ) | @ function_name | value |
@ | Object function.qualifier( arguments ) | object_type @ object_function_name | value |
The unitary function operator introduces either a built-in or a user defined function.
User defined functions first have to be defined using the function statement. They can then be called in an expression using the at '@' operator.
When defining a function, it has an additional local variable: result. When the function is used in an expression, its value is that of the 'result' variable.
Example | Result |
---|---|
function power(number, power) { result = 1; do while power > 0 result *= number; power -= 1; loop } | |
4 * @power(2,4) + 10 | 74 |
The object function operator is a function that uses the object on the left hand as input. The function may be a general object function that acts on all object types or a function defined as part of a named object.
Example | Result |
---|---|
object pair { values first second; function sum { result = first + second; } } | |
{pair 3, 4} @ sum | 7 |
Operator Precedence
Expressions are evaluated according to the operators detailed in the table. Operators with higher precedence are listed first. When precedence is equal, operations are carried out from left to right.
Operator List | |||
---|---|---|---|
Operator | Name | Use | Result |
() | Parenthesized expression | ( expr ) | value |
{} | Object | {sig value, ...} | object_value |
@ | Unary Function | @name @name(expr, ...) @name.qualifier @name.qualifier(expr, ...) | value |
@ | Object Function | object_value@name object_value@name(expr, ...) object_value@name.qualifier object_value@name.qualifier(expr, ...) | value |
[name] | Member | object_value[name] | value |
! | Complement | !rlist_value | rlist_value |
not | Logical not | not bool_value | bool_value |
+ | Unary plus | +number_value | number_value |
- | Unary minus | -number_value | number_value |
* | Multiply | numeric_value * numeric_value | numeric_value |
/ | Divide | numeric_value / numeric_value | float_value |
div | Integer divide | integer_value div integer_value | integer_value |
mod | Integer modulo | integer_value mod integer_value | integer_value |
+ | Plus | number_value + number_value string_value + value value + string_value |
number_value string_value string_value |
- | Minus | number_value - number_value | number_value |
.. | Range | field_value .. field_value range_value .. range_value |
range_value range_value |
| | Union | rlist_value | range_value | rlist_value |
&& | Intersection | rlist_value && range_value | rlist_value |
^^ | Symmetric difference | rlist_value ^^ range_value | rlist_value |
\\ | Relative complement | rlist_value \\ range_value | rlist_value |
< | Less than | value < value | bool_value |
<= | Less than or equal | value <= value | bool_value |
> | Greater than | value > value | bool_value |
>= | Greater than or equal | value >= value | bool_value |
= | Equal | value = value | bool_value |
<> | Not equal | value <> value | bool_value |
and | Logical and | bool_value and bool_value | bool_value |
or | Logical inclusive or | bool_value or bool_value | bool_value |
Keywords
The following is a complete list of keywords, including the Hics extensions. These words cannot be used as variable names and, if used as codes or signatures, they must be enclosed in double quotes.
and, div, do, endif, else, elseif, false, future, if, inf, infinite, loop, mod, nan, not, null, or, past, this, today, true
The other statement words call, command, end, file, format, function, grammar, let, lexicon, mark, object, scheme, set, until, while, write, writeln are not strictly keyword, but are best avoided. If they are used as variable names then all assignments must start with 'let'.
Names
Any text in the script which is not an operator, literal or keyword is termed a 'name'. How a name is treated depends upon the context.
Names are constructed from alphanumeric, '_' underline and ':' colon characters. They cannot start with a numeric character.
In some cases the script may accept either a name, a literal string or a string expression in '( )' parentheses. It is often called a code or a signature when used like this.
Constants
Constants are created using the 'constant' statement. It allows a name to a be use in place of value. Once created it cannot be changed. A constant cannot use the same name as a variable.
The lifetime of a constant is controlled with the 'mark' statement.
Variables
Variables are created using the 'let' or 'global' statements. They both link a name to a value and can be changed using additional statements. They cannot use the same name as a constant.
The 'let' statement creates a local variable which has limited visibility, it cannot be seen inside a function or command unless declared there.
The 'global' statement creates a variable which has global visibility. It can be used or modified inside a function or command even if it was declared outside of them.
Once created, the 'let' or 'global' statement names are optional. When a variable name is used to start a statement, it is first checked for a local variable name and if found then the 'let' is assumed. If not found, it is checked against the global variables. If found there, then the 'global' statement is assumed.
When a variable is used in an expression and the name has been used to define both a local and global variable, the local value will take precedent. Use of the global value may be forced using the @global.name function.
The life of a variable is controlled by the 'mark' statement. It should be noted that variable names and values are remembered after a script has finished running. So subsequent scripts can use values calculated by previous ones. The 'mark' statement can be used to control this behavior.