Operators¶
Overview¶
Larol provides a set of unary and binary operators.
Syntax¶
someFunction()
someStructCapability.someField
someStructCapability.someFunction()
someSliceCapability[someIndexValue]
(1 + 1)
!someBool
~someInt
-someInt
#someSliceCapability
move someLocalVariable
read someHandle
write someHandle
alloc SomeStructType
alloc SomeType[SomeLength]
someFunctionPointer == anotherFunctionPointer
2 * 3
9 / 3
7 % 3
2 + 3
9 - 3
10 << 2
32 >> 1
2 < 3
2 <= 3
4 > 5
4 >= 5
1 == 1
2 != 3
3 | 2
3 & 2
true || false
true && true
Rules¶
Precedence and Associativity¶
| Precedence | Operator | Associativity |
|---|---|---|
| 1 | (), ., [], f() | Left-to-right |
| 2 | !, ~, - (unary), #, alloc, move, read, write | Right-to-left |
| 3 | *, /, % | Left-to-right |
| 4 | +, - | Left-to-right |
| 5 | <<, >> | Left-to-right |
| 6 | <, <=, >, >= | Left-to-right |
| 7 | ==, != | Left-to-right |
| 8 | & | Left-to-right |
| 9 | \| | Left-to-right |
| 10 | && | Left-to-right |
| 11 | \|\| | Left-to-right |
Grouping¶
Parenthesised expressions MUST override default precedence and evaluate the enclosed expression first.
Integer Overflow¶
Runtime integer overflow on arithmetic operators (+, -, *) MUST wrap according to two's complement arithmetic. Division by zero MUST cause a fatal error.
Function Call¶
The function call operator MUST invoke the target function with the supplied arguments. The function call operator MUST be usable on member functions via the capability.functionName() syntax. When calling a member function, the capability expression serves as the implicit this argument. A read capability for a struct type MAY call member functions whose implicit this resolves to read StructType. A read capability MUST NOT call member functions whose implicit this resolves to write StructType. A write capability MAY call member functions whose implicit this resolves to either read StructType or write StructType. The function call operator MUST be usable on function pointer values via the pointerName(args) syntax. Each argument expression MUST be implicitly convertible to the corresponding parameter type using the same conversion rules as assignment.
Calling a region-qualified function (^ function) MUST require an active region context at the call site.
When a handle-bearing lvalue is passed as a function argument, move MUST be used. A handle-bearing rvalue MAY be passed directly. After the call, the source lvalue MUST be invalidated. move MUST NOT be used on non-handle argument types.
Field Access¶
The field access operator MUST access the named field of the operand (a struct capability) and produce that field. The field access operator MUST NOT be used on struct handle types (&StructType).
Index¶
The index operator MUST index into a slice capability or slice handle using the supplied value and produce the element at that position.
Logical NOT¶
The logical NOT operator MUST accept an expression convertible to bool. The operand MUST be converted to bool first, then logically negated, producing false if the converted operand is true and true if the converted operand is false.
Bitwise NOT¶
The bitwise NOT operator MUST apply a bitwise NOT to any integer type, flipping every bit.
Arithmetic Negation¶
The arithmetic negation operator MUST negate a numeric value arithmetically. Arithmetic negation MUST be supported for all integer and floating-point types.
Length Of (#)¶
The length of operator MUST produce the number of elements in a slice capability or slice handle.
Move¶
The move operator MUST only be applied to an lvalue. The moved expression MUST have a type that transitively contains an owned handle. Lvalues include variables, struct member access results, and slice index results. The move operator MUST invalidate the source lvalue and produce its value as an rvalue.
Read¶
The read operator MUST only be applied to a handle type. The read operator MUST produce a read capability for the handle's owned object/memory. The read operator MUST be applicable to expressions that evaluate to a handle value, including handle-typed variable references and handle member field access results. Applying the read operator to a handle-valued expression MUST NOT constitute a handle copy; the compiler MUST access the underlying object directly to produce the capability.
Multithreading may be supported in future versions; additional rules may apply at that time.
Write¶
The write operator MUST only be applied to a handle type. The write operator MUST produce a write capability for the handle's owned object/memory. A write capability for a struct handle MUST provide read-write access to the struct's fields. A write capability for a slice handle MUST provide read-write access to the slice's elements. The write operator MUST be applicable to expressions that evaluate to a handle value, including handle-typed variable references and handle member field access results. Applying the write operator to a handle-valued expression MUST NOT constitute a handle copy; the compiler MUST access the underlying object directly to produce the capability.
Multithreading may be supported in future versions; additional rules may apply at that time.
Alloc¶
Use of alloc MUST only be permitted within an active region context.
alloc StructType MUST allocate a struct of the given type within the current region by calling larol_alloc; this MUST produce a struct handle for the given type. The allocated struct MUST be initialized using the struct member defaults defined by the struct declaration, evaluated in declaration order.
alloc ElementType[Length] MUST allocate a slice of the given element type and length within the current region by calling larol_alloc_slice; this MUST produce a slice handle for the given element type. The element type MUST be a permitted slice element type. The provided length MUST NOT be negative. A length of zero MUST be permitted, the larol_alloc_slice function SHOULD NOT be called for slice allocations with length of zero.
Allocated slice elements MUST be default-initialized recursively according to their element type: primitive values MUST become zero-equivalent values, function pointers MUST become null, struct handles MUST become null, and slice handles MUST become zero-length empty slices.
Multiply¶
The multiply operator MUST multiply two numeric values and produce their product.
Divide¶
The divide operator MUST divide the left operand by the right operand and produce the quotient. For integer division, the quotient MUST be truncated toward zero (i.e., the fractional part is discarded).
Remainder¶
The remainder operator MUST divide the left operand by the right operand and produce the remainder. For integer operands, the sign of the remainder MUST match the sign of the left operand (the dividend). Truncation toward zero MUST be used.
Add¶
The add operator MUST add two numeric values and produce their sum.
Subtract¶
The subtract operator MUST subtract the right operand from the left operand and produce the difference.
Left Shift¶
The left shift operator MUST shift the bits of the left operand to the left by the number of positions given by the right operand. Vacated bits MUST be filled with zero.
Right Shift¶
The right shift operator MUST shift the bits of the left operand to the right by the number of positions given by the right operand. If the left operand is a signed type, the shift MUST be arithmetic (sign-extending). If the left operand is an unsigned type, the shift MUST be logical (zero-filling).
Less Than¶
The less than operator MUST produce true if the left operand is strictly less than the right operand, otherwise false.
Less Than or Equal¶
The less than or equal operator MUST produce true if the left operand is less than or equal to the right operand, otherwise false.
Greater Than¶
The greater than operator MUST produce true if the left operand is strictly greater than the right operand, otherwise false.
Greater Than or Equal¶
The greater than or equal operator MUST produce true if the left operand is greater than or equal to the right operand, otherwise false.
Equal¶
The equal operator MUST produce true if both operands are equal, otherwise false. The equal operator MUST be permitted on primitive types, function pointer types, and struct handle types. Two struct handles are equal if and only if they reference the same allocation or are both null.
Not Equal¶
The not equal operator MUST produce true if the operands are not equal, otherwise false. The not equal operator MUST be permitted on primitive types, function pointer types, and struct handle types.
Bitwise AND¶
The bitwise AND operator MUST apply a bitwise AND to two integer values, producing a value where each bit is set only if the corresponding bit is set in both operands.
Bitwise OR¶
The bitwise OR operator MUST apply a bitwise OR to two integer values, producing a value where each bit is set if the corresponding bit is set in either operand.
Logical AND¶
The logical AND operator MUST accept operands convertible to bool. The left operand MUST be converted to bool first. The logical AND operator MUST produce true only if both converted operands are true. The logical AND operator MUST short-circuit and not evaluate the right operand if the left operand is false after conversion.
Logical OR¶
The logical OR operator MUST accept operands convertible to bool. The left operand MUST be converted to bool first. The logical OR operator MUST produce true if either converted operand is true. The logical OR operator MUST short-circuit and not evaluate the right operand if the left operand is true after conversion.
Primitive Operand Conversion¶
For binary arithmetic, bitwise, and comparison operators on primitive values, the right operand MUST be implicitly converted to the left operand's type before the operator is applied. The result type of arithmetic and bitwise operators MUST be the left operand's type. Comparison operators MUST produce bool.