Expressions

Grouping, Postifix, and Unaries.

primary-expr % primary
: "(" expressions-list ")" % paren
| "[" expressions-list "]" % array
| identifier % ident
| constant % const
;
postfix-expr % postfix
: primary-expr % degenerate
| postfix-expr "=?" primary-expr % nullcoalesce
| postfix-expr "[" expressions-list "]" % indirect
| postfix-expr "(" expressions-list ")" % funccall
| postfix-expr "." identifier % member
| postfix-expr "++" % inc
| postfix-expr "--" % dec
| object-notation % objdef
;

Note: Previously, the close-binding null-coalescing operator was ->, this was changed as it had been desired to reserve it for a 'trait' static call syntax where the first argument of a subroutine (i.e. non-method function) receives the value of or a reference to the left-hand of the operator. This is tentative and no commitment over this had been made yet. All in all, the close-binding null-coalescing operator is now =?. (Note dated 2025-09-26.)

unary-expr % unary
: postfix-expr % degenerate
| "++" unary-expr % inc
| "--" unary-expr % dec
| "+" unary-expr % positive
| "-" unary-expr % negative
| "~" unary-expr % bitcompl
| "!" unary-expr % logicnot
;

For inc and dec in unary and postfix, and positive and negative, operation occur under arithmetic context. For bitcompl and logicnot, the operation occur under integer context.

Arithmetic Binary Operations

mul-expr % mulexpr
: unary-expr % degenerate
| mul-expr "*" unary-expr % multiply
| mul-expr "/" unary-expr % divide
| mul-expr "%" unary-expr % remainder
;

The result of division on integers SHALL round towards 0.

The remainder computed SHALL be such that (a/b)*b + a%b == a is true.

If the divisor is 0, then the quotient of division becomes positive/negative infinity of type double if the sign of both operands are same/different, while the remainder becomes NaN, with the "invalid" floating point exception signalled.

For the purpose of determining the sign of operands, the integer 0 in ulong and two's complement signed long are considered to be positive.

Editorial Note: The first 3 of the above 4 paragraphs were together 1 paragraph in a previous version of the draft before 2025-08-25. This had the potential of causing the confusion that remainder is only applicable to integers. Because now remainder is also applicable to floating points, this is first separated into its own paragraph. The rule regarding type conversion on division by 0 is of separate interest, so it's also an individual paragraph now. The 4th paragraph is added on 2025-08-25.

Note: The condition for determining remainder is equivalent to:

remainder x % y shall be such x-ny such that for some integer n, if y is non-zero, the result has the same sign as x and magnitude less than that of y.

These are separate descriptions for integer modulo operator and floating point fmod function in the C language, as such, an implementation may utilize these facilities in C. Any inconsistency between these 2 definitions in C are supposedly unintentional from the standard developer's perspective.

All of mulexpr occur under arithmetic context.

add-expr % addexpr
: mul-expr % degenerate
| add-expr "+" mul-expr % add
| add-expr "-" mul-expr % subtract
;

All of addexpr occur under arithmetic context.

Bit Shifting Operations

bit-shift-expr % shiftexpr
: add-expr % degenerate
| bit-shift-expr << add-expr % lshift
| bit-shift-expr >> add-expr % arshift
| bit-shift-expr >>> add-expr % rshift
;

All of shiftexpr occur under integer context.

Side Note: There was left and right rotate operators. Since there's only a single 64-bit width in native integer types, bit rotation become meaningless. Therefore those functionalities will be offered in the standard library method functions.

Arithmetic Relations

rel-expr % relops
: bit-shift-expr % degenerate
| rel-expr "<" bit-shift-expr % lt
| rel-expr ">" bit-shift-expr % gt
| rel-expr "<=" bit-shift-expr % le
| rel-expr ">=" bit-shift-expr % ge
;

All of relops occur under arithmetic context. If either operand is NaN, then the value of the expression is false.

eq-expr % eqops
: rel-expr % degenerate
| eq-expr "==" rel-expr % eq
| eq-expr "!=" rel-expr % ne
| eq-expr "===" rel-expr % ideq
| eq-expr "!==" rel-expr % idne
;

Bitwise Operations

bit-and % bitand
: eq-expr % degenerate
| bit-and "&" eq-expr % bitand
;

bit-xor % bitxor
: bit-and % degenerate
| bit-xor "^" bit-and % bitxor
;

bit-or % bitxor
: bit-xor % degenerate
| bit-or "|" bit-xor % bitor
;

All of the bitwise operations occur under integer context.

Boolean Logics

logic-and % logicand
: bit-or % degenerate
| logic-and "&&" bit-or % logicand
;

logic-or % logicand
: logic-and % degenerate
| logic-or "||" logic-and % logicor
| logic-or "??" logic-and % nullcoalesce
;

Compounds

cond-expr % tenary
: logic-or % degenerate
| logic-or "?" expressions-list ":" cond-expr % tenary
;
assign-expr % assignment
: cond-expr % degenerate
| unary-expr "=" assign-expr % directassign
| unary-expr "*=" assign-expr % mulassign
| unary-expr "/=" assign-expr % divassign
| unary-expr "%=" assign-expr % remassign
| unary-expr "+=" assign-expr % addassign
| unary-expr "-=" assign-expr % subassign
| unary-expr "<<=" assign-expr % lshiftassign
| unary-expr ">>=" assign-expr % arshiftassign
| unary-expr ">>>=" assign-expr % rshiftassign
| unary-expr "&=" assign-expr % andassign
| unary-expr "^=" assign-expr % xorassign
| unary-expr "|=" assign-expr % orassign
| unary-expr "&&=" assign-expr % conjassign
| unary-expr "||=" assign-expr % disjassign
;

See 8.2. Object/Value Key Access for further discussion.

expressions-list % exprlist
: assign-expr % degenerate
| expressions-list "," assign-expr % exprlist
;