Fix: add assignment as right-associative expression

`=` was missing from the Pratt table, causing `a = b;` to fail with
"expected `;`, found `=`". Assignment is now BinaryOp::Assign with
binding power (2, 2) — lowest precedence, right-associative — so
`a = b = c` parses as `a = (b = c)`.
This commit is contained in:
2026-03-10 18:10:35 +01:00
parent 546dc119d0
commit 1a4e464d5e
4 changed files with 100 additions and 24 deletions

View File

@@ -37,6 +37,7 @@ appear as UPPERCASE terminals in `GRAMMAR.ebnf`.
| `BANG` | `!` | Logical NOT |
| `TILDE` | `~` | Bitwise NOT |
| `DOT` | `.` | Member access |
| `EQ` | `=` | Assignment |
### Keyword Tokens
@@ -128,33 +129,35 @@ tightly).
| Level | Operators | Associativity | Description |
| ----- | --------------------------- | -------------- | -------------------------------- |
| 1 | `or` | left | Logical OR (lowest) |
| 2 | `and` | left | Logical AND |
| 3 | `\|` | left | Bitwise OR |
| 4 | `^` | left | Bitwise XOR |
| 5 | `&` | left | Bitwise AND |
| 6 | `+` `-` | left | Addition, subtraction |
| 7 | `*` `/` `%` | left | Multiplication, division, modulo |
| 8 | `!` `~` `-` `*` `&` | right (unary) | Prefix unary operators |
| 9 | `.` `[…]` `(…)` | left (postfix) | Member access, index, call |
| 10 | literals, identifiers, `()` | — | Primary expressions (highest) |
| 1 | `=` | right | Assignment (lowest) |
| 2 | `or` | left | Logical OR |
| 3 | `and` | left | Logical AND |
| 4 | `\|` | left | Bitwise OR |
| 5 | `^` | left | Bitwise XOR |
| 6 | `&` | left | Bitwise AND |
| 7 | `+` `-` | left | Addition, subtraction |
| 8 | `*` `/` `%` | left | Multiplication, division, modulo |
| 9 | `!` `~` `-` `*` `&` | right (unary) | Prefix unary operators |
| 10 | `.` `[…]` `()` | left (postfix) | Member access, index, call |
| 11 | literals, identifiers, `()` | — | Primary expressions (highest) |
### Operator Descriptions
#### Binary Operators
| Operator | Name | Example | Notes |
| -------- | -------------- | --------- | -------------------------------------------- |
| `or` | Logical OR | `a or b` | Short-circuits; both operands must be `bool` |
| `and` | Logical AND | `a and b` | Short-circuits; both operands must be `bool` |
| `\|` | Bitwise OR | `a \| b` | Integer types |
| `^` | Bitwise XOR | `a ^ b` | Integer types |
| `&` | Bitwise AND | `a & b` | Integer types (binary context) |
| `+` | Addition | `a + b` | |
| `-` | Subtraction | `a - b` | |
| `*` | Multiplication | `a * b` | Binary context (both operands are values) |
| `/` | Division | `a / b` | Integer division truncates toward zero |
| `%` | Modulo | `a % b` | Sign follows the dividend |
| Operator | Name | Example | Notes |
| -------- | -------------- | --------- | ---------------------------------------------- |
| `=` | Assignment | `a = b` | Right-associative; `a = b = c``a = (b = c)` |
| `or` | Logical OR | `a or b` | Short-circuits; both operands must be `bool` |
| `and` | Logical AND | `a and b` | Short-circuits; both operands must be `bool` |
| `\|` | Bitwise OR | `a \| b` | Integer types |
| `^` | Bitwise XOR | `a ^ b` | Integer types |
| `&` | Bitwise AND | `a & b` | Integer types (binary context) |
| `+` | Addition | `a + b` | |
| `-` | Subtraction | `a - b` | |
| `*` | Multiplication | `a * b` | Binary context (both operands are values) |
| `/` | Division | `a / b` | Integer division truncates toward zero |
| `%` | Modulo | `a % b` | Sign follows the dividend |
#### Unary Prefix Operators