Skip to content

Commit

Permalink
supports parsing assignment
Browse files Browse the repository at this point in the history
  • Loading branch information
xffxff committed Sep 25, 2023
1 parent fc3479b commit 73607af
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 7 deletions.
1 change: 1 addition & 0 deletions components/lox-compile/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,6 @@ fn compile_expr(db: &dyn crate::Db, expr: &syntax::Expr, chunk: &mut Chunk) {
let word_str = word.as_str(db);
chunk.emit_byte(Code::Variable(word_str.to_string()))
}
syntax::Expr::Assign { name, value } => todo!(),
}
}
8 changes: 8 additions & 0 deletions components/lox-ir/src/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ pub enum Expr {

// `foo`
Variable(Word),

// assignment expression, like `foo = 1 + 2`
Assign { name: Word, value: Box<Expr> },
}

impl<'db> salsa::DebugWithDb<dyn crate::Db + 'db> for Expr {
Expand Down Expand Up @@ -57,6 +60,11 @@ impl<'db> salsa::DebugWithDb<dyn crate::Db + 'db> for Expr {
Expr::BooleanLiteral(value) => write!(f, "BooleanLiteral({})", value),
Expr::StringLiteral(word) => write!(f, "StringLiteral({})", word.as_str(db)),
Expr::Variable(word) => write!(f, "Variable({})", word.as_str(db)),
Expr::Assign { name, value } => f
.debug_struct("Assign")
.field("name", &name.as_str(db))
.field("value", &value.debug(db))
.finish(),
_ => todo!(),
}
}
Expand Down
35 changes: 28 additions & 7 deletions components/lox-parse/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,38 @@ impl<'me> Parser<'me> {
Some(Stmt::Expr(expr))
}

// expression → equality ;
// equality → comparison ( ( "!=" | "==" ) comparison )* ;
// comparison → term ( ( ">" | ">=" | "<" | "<=" ) term )* ;
// term → factor ( ( "-" | "+" ) factor )* ;
// factor → unary ( ( "/" | "*" ) unary )* ;
// unary → ( "!" | "-" ) unary
// expression -> assignment ;
// assignment -> IDENTIFIER "=" assignment | equality ;
// equality -> comparison ( ( "!=" | "==" ) comparison )* ;
// comparison -> term ( ( ">" | ">=" | "<" | "<=" ) term )* ;
// term -> factor ( ( "-" | "+" ) factor )* ;
// factor -> unary ( ( "/" | "*" ) unary )* ;
// unary -> ( "!" | "-" ) unary
// | primary ;
// primary → NUMBER | STRING | "true" | "false" | "nil"
// | "(" expression ")" ;
fn parse_expr(&mut self) -> Option<Expr> {
self.equality()
self.assignment()
}

// assignment -> IDENTIFIER "=" assignment | equality ;
// assignment is not a statement, it is an expression
fn assignment(&mut self) -> Option<Expr> {
let expr = self.equality()?;
if self.eat_op(Op::Equal).is_some() {
let value = self.assignment()?;
if let Expr::Variable(name) = expr {
return Some(Expr::Assign {
name,
value: Box::new(value),
});
} else {
// FIXME: we should use the span of the `expr` here
let span = self.tokens.peek_span();
self.error(span, "invalid assignment target").emit(self.db);
}
}
Some(expr)
}

fn equality(&mut self) -> Option<Expr> {
Expand Down
2 changes: 2 additions & 0 deletions lox_tests/assignment.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
var a = 1;
a = 2;
15 changes: 15 additions & 0 deletions lox_tests/assignment/bytecode
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Chunk {
code: [
Constant(
F64(
1.0,
),
),
VarDeclaration(
"a",
),
Variable(
"a",
),
],
}
25 changes: 25 additions & 0 deletions lox_tests/assignment/execute
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
execute: Constant(
F64(
1.0,
),
)
stack: [
Number(
1.0,
),
]

execute: VarDeclaration(
"a",
)
stack: []

execute: Variable(
"a",
)
stack: [
Number(
1.0,
),
]

12 changes: 12 additions & 0 deletions lox_tests/assignment/syntax
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Var {
name: "a",
initializer: Some(
NumberLiteral(1),
),
}
Expr {
expr: Assign {
name: "a",
value: NumberLiteral(2),
},
}
20 changes: 20 additions & 0 deletions lox_tests/assignment/token
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
TokenTree {
source text: "var a = 1;\na = 2;",
tokens: [
Alphabetic(var),
Whitespace(' '),
Alphabetic(a),
Whitespace(' '),
Op(=),
Whitespace(' '),
Number(1),
Semicolon,
Whitespace('\n'),
Alphabetic(a),
Whitespace(' '),
Op(=),
Whitespace(' '),
Number(2),
Semicolon,
],
}

0 comments on commit 73607af

Please sign in to comment.