diff options
author | Vincent Ambo <mail@tazj.in> | 2020-12-22T14·44+0100 |
---|---|---|
committer | tazjin <mail@tazj.in> | 2020-12-22T20·18+0000 |
commit | 0f9a7b3f86f56162cf1a694d98d82e4937d44a52 (patch) | |
tree | e0e092c0fcf9e34b1eddf39bf08423e5fe6e3e91 /users/tazjin/rlox/src | |
parent | 5010b7971806d30de0987d8e7706ca24a96fbef5 (diff) |
feat(tazjin/rlox): Parse variable assignment & access r/2027
Change-Id: I9894d76716d739e85a4757d9e658f884228e7f52 Reviewed-on: https://cl.tvl.fyi/c/depot/+/2290 Reviewed-by: tazjin <mail@tazj.in> Tested-by: BuildkiteCI
Diffstat (limited to 'users/tazjin/rlox/src')
-rw-r--r-- | users/tazjin/rlox/src/errors.rs | 1 | ||||
-rw-r--r-- | users/tazjin/rlox/src/interpreter.rs | 2 | ||||
-rw-r--r-- | users/tazjin/rlox/src/parser.rs | 46 |
3 files changed, 46 insertions, 3 deletions
diff --git a/users/tazjin/rlox/src/errors.rs b/users/tazjin/rlox/src/errors.rs index 9598893aa352..03a24312411c 100644 --- a/users/tazjin/rlox/src/errors.rs +++ b/users/tazjin/rlox/src/errors.rs @@ -5,6 +5,7 @@ pub enum ErrorKind { UnmatchedParens, ExpectedExpression(String), ExpectedSemicolon, + ExpectedVariableName, TypeError(String), } diff --git a/users/tazjin/rlox/src/interpreter.rs b/users/tazjin/rlox/src/interpreter.rs index 5e43e075b03c..99df23d725dd 100644 --- a/users/tazjin/rlox/src/interpreter.rs +++ b/users/tazjin/rlox/src/interpreter.rs @@ -101,6 +101,7 @@ fn eval<'a>(expr: &Expr<'a>) -> Result<Literal, Error> { Expr::Grouping(grouping) => eval(&*grouping.0), Expr::Unary(unary) => eval_unary(unary), Expr::Binary(binary) => eval_binary(binary), + Expr::Variable(_) => unimplemented!(), } } @@ -122,6 +123,7 @@ fn run_program<'a>(program: &Program<'a>) -> Result<(), Error> { for decl in program { match decl { Declaration::Stmt(stmt) => run_stmt(stmt)?, + Declaration::Var(_var) => unimplemented!(), } } diff --git a/users/tazjin/rlox/src/parser.rs b/users/tazjin/rlox/src/parser.rs index 91000db9dd90..3f1dda6e39cf 100644 --- a/users/tazjin/rlox/src/parser.rs +++ b/users/tazjin/rlox/src/parser.rs @@ -35,11 +35,15 @@ pub struct Unary<'a> { } #[derive(Debug)] +pub struct Variable<'a>(pub Token<'a>); + +#[derive(Debug)] pub enum Expr<'a> { Binary(Binary<'a>), Grouping(Grouping<'a>), Literal(Literal), Unary(Unary<'a>), + Variable(Variable<'a>), } #[derive(Debug)] @@ -48,9 +52,17 @@ pub enum Statement<'a> { Print(Expr<'a>), } +// Not to be confused with `Variable`, which is for access. +#[derive(Debug)] +pub struct Var<'a> { + pub name: Token<'a>, + pub initialiser: Option<Expr<'a>>, +} + #[derive(Debug)] pub enum Declaration<'a> { Stmt(Statement<'a>), + Var(Var<'a>), } pub type Program<'a> = Vec<Declaration<'a>>; @@ -93,9 +105,36 @@ impl<'a> Parser<'a> { // recursive-descent parser functions fn declaration(&mut self) -> DeclResult<'a> { + if self.match_token(&[TokenKind::Var]) { + return self.var_declaration(); + } + Ok(Declaration::Stmt(self.statement()?)) } + fn var_declaration(&mut self) -> DeclResult<'a> { + // Since `TokenKind::Identifier` carries data, we can't use + // `consume`. + if let TokenKind::Identifier(_) = self.peek().kind { + let mut var = Var { + name: self.advance(), + initialiser: None, + }; + + if self.match_token(&[TokenKind::Equal]) { + var.initialiser = Some(self.expression()?); + } + + self.consume(&TokenKind::Semicolon, ErrorKind::ExpectedSemicolon)?; + return Ok(Declaration::Var(var)); + } + + return Err(Error { + line: self.peek().line, + kind: ErrorKind::ExpectedVariableName, + }); + } + fn statement(&mut self) -> StmtResult<'a> { if self.match_token(&[TokenKind::Print]) { self.print_statement() @@ -173,6 +212,8 @@ impl<'a> Parser<'a> { return Ok(Expr::Grouping(Grouping(Box::new(expr)))); } + TokenKind::Identifier(_) => return Ok(Expr::Variable(Variable(next))), + unexpected => { eprintln!("encountered {:?}", unexpected); return Err(Error { @@ -225,10 +266,9 @@ impl<'a> Parser<'a> { &self.tokens[self.current - 1] } - fn consume(&mut self, kind: &TokenKind, err: ErrorKind) -> Result<(), Error> { + fn consume(&mut self, kind: &TokenKind, err: ErrorKind) -> Result<Token, Error> { if self.check_token(kind) { - self.advance(); - return Ok(()); + return Ok(self.advance()); } Err(Error { |