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:
@@ -35,6 +35,9 @@ impl fmt::Display for ParseError {
|
||||
|
||||
fn infix_bp(kind: TokenKind) -> Option<(u8, u8)> {
|
||||
let bp = match kind {
|
||||
// Assignment: lowest precedence, right-associative (left_bp == right_bp).
|
||||
// `a = b = c` → `a = (b = c)`.
|
||||
TokenKind::Eq => (2, 2),
|
||||
TokenKind::Or => (10, 11),
|
||||
TokenKind::And => (20, 21),
|
||||
TokenKind::Pipe => (30, 31),
|
||||
@@ -97,6 +100,7 @@ fn token_to_binary_op(kind: TokenKind) -> BinaryOp {
|
||||
TokenKind::Star => BinaryOp::Mul,
|
||||
TokenKind::Slash => BinaryOp::Div,
|
||||
TokenKind::Percent => BinaryOp::Rem,
|
||||
TokenKind::Eq => BinaryOp::Assign,
|
||||
_ => unreachable!("not a binary op: {:?}", kind),
|
||||
}
|
||||
}
|
||||
@@ -1048,6 +1052,55 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assignment_expr() {
|
||||
let expr = parse("a = b");
|
||||
assert!(matches!(
|
||||
expr.kind,
|
||||
ExprKind::Binary {
|
||||
op: BinaryOp::Assign,
|
||||
..
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assignment_right_associative() {
|
||||
// `a = b = c` → `a = (b = c)`
|
||||
let expr = parse("a = b = c");
|
||||
match &expr.kind {
|
||||
ExprKind::Binary {
|
||||
op: BinaryOp::Assign,
|
||||
rhs,
|
||||
..
|
||||
} => {
|
||||
assert!(matches!(
|
||||
rhs.kind,
|
||||
ExprKind::Binary {
|
||||
op: BinaryOp::Assign,
|
||||
..
|
||||
}
|
||||
));
|
||||
}
|
||||
_ => panic!("expected assignment"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assignment_stmt() {
|
||||
let s = stmt("a = b + 1;");
|
||||
match &s.kind {
|
||||
StmtKind::Expr(e) => assert!(matches!(
|
||||
e.kind,
|
||||
ExprKind::Binary {
|
||||
op: BinaryOp::Assign,
|
||||
..
|
||||
}
|
||||
)),
|
||||
_ => panic!("expected expr stmt with assignment"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deref_and_addrof() {
|
||||
assert!(matches!(
|
||||
|
||||
Reference in New Issue
Block a user