Feat: add compound assignment and shift operators

Compound assignment: +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=
Shift: <<, >>

Each compound assignment token parses at the same precedence as `=`
(right-associative, lowest) and produces ExprKind::CompoundAssign.
Shifts parse between additive and multiplicative precedence.
GRAMMAR.ebnf and SYNTAX.md updated accordingly.
This commit is contained in:
2026-03-10 18:29:52 +01:00
parent 1a4e464d5e
commit a82b7e4633
6 changed files with 269 additions and 56 deletions

View File

@@ -36,20 +36,27 @@ top_level_def = func_def
expr = assign_expr ;
(* --- Assignment (lowest-precedence binary operator) --- *)
(* --- Assignment and compound assignment (lowest precedence) --- *)
(* *)
(* Uses token `=`; right-associative via recursion. *)
(* The optional form encodes at-most-one assignment target: chains *)
(* like `a = b = c` parse as `a = (b = c)` thanks to right *)
(* recursion. *)
(* assign_op covers `=` and all compound-assignment operators. *)
(* All have the same precedence and are right-associative: *)
(* `a = b = c` `a = (b = c)` *)
(* `a += b += c` `a += (b += c)` (unusual but syntactically *)
(* valid; semantics checked later) *)
(* *)
(* Compound assignments expand semantically: *)
(* `x += y` `x = x + y` *)
(* `x -= y` `x = x - y` etc. *)
(* *)
(* LL(1): after or_expr, peek at next token. *)
(* "=" consume and recurse into assign_expr *)
(* assign_op token consume and recurse into assign_expr *)
(* other return the or_expr as-is *)
(* "=" is not in FIRST(stmt), so expr_stmt can still be *)
(* distinguished from other statement kinds. *)
(* None of the assign_op tokens are in FIRST(stmt), so expr_stmt *)
(* remains unambiguous. *)
assign_expr = or_expr , [ "=" , assign_expr ] ;
assign_expr = or_expr , [ assign_op , assign_expr ] ;
assign_op = "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "^=" | "<<=" | ">>=" ;
(* --- Logical OR (lowest-precedence binary operator) --- *)
@@ -83,8 +90,14 @@ bitand_expr = additive_expr , { "&" , additive_expr } ;
(* --- Additive: addition and subtraction --- *)
additive_expr = multiplicative_expr ,
{ ( "+" | "-" ) , multiplicative_expr } ;
additive_expr = shift_expr ,
{ ( "+" | "-" ) , shift_expr } ;
(* --- Shift: left shift and right shift --- *)
shift_expr = multiplicative_expr ,
{ ( "<<" | ">>" ) , multiplicative_expr } ;
(* --- Multiplicative: multiplication, division, modulo --- *)
@@ -183,7 +196,7 @@ arg_list = [ expr , { "," , expr } ] ;
expr_ns = assign_expr_ns ;
assign_expr_ns = or_expr_ns , [ "=" , assign_expr_ns ] ;
assign_expr_ns = or_expr_ns , [ assign_op , assign_expr_ns ] ;
or_expr_ns = and_expr_ns , { "or" , and_expr_ns } ;
and_expr_ns = bitor_expr_ns , { "and" , bitor_expr_ns } ;
@@ -192,8 +205,11 @@ bitor_expr_ns = bitxor_expr_ns , { "|" , bitxor_expr_ns } ;
bitxor_expr_ns = bitand_expr_ns , { "^" , bitand_expr_ns } ;
bitand_expr_ns = additive_expr_ns , { "&" , additive_expr_ns } ;
additive_expr_ns = multiplicative_expr_ns ,
{ ( "+" | "-" ) , multiplicative_expr_ns } ;
additive_expr_ns = shift_expr_ns ,
{ ( "+" | "-" ) , shift_expr_ns } ;
shift_expr_ns = multiplicative_expr_ns ,
{ ( "<<" | ">>" ) , multiplicative_expr_ns } ;
multiplicative_expr_ns = unary_expr_ns ,
{ ( "*" | "/" | "%" ) , unary_expr_ns } ;