From 0f9a7b3f86f56162cf1a694d98d82e4937d44a52 Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Tue, 22 Dec 2020 15:44:25 +0100 Subject: feat(tazjin/rlox): Parse variable assignment & access Change-Id: I9894d76716d739e85a4757d9e658f884228e7f52 Reviewed-on: https://cl.tvl.fyi/c/depot/+/2290 Reviewed-by: tazjin Tested-by: BuildkiteCI --- users/tazjin/rlox/src/errors.rs | 1 + users/tazjin/rlox/src/interpreter.rs | 2 ++ users/tazjin/rlox/src/parser.rs | 46 +++++++++++++++++++++++++++++++++--- 3 files changed, 46 insertions(+), 3 deletions(-) (limited to 'users/tazjin/rlox/src') 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 { 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 @@ -34,12 +34,16 @@ pub struct Unary<'a> { pub right: Box>, } +#[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>, +} + #[derive(Debug)] pub enum Declaration<'a> { Stmt(Statement<'a>), + Var(Var<'a>), } pub type Program<'a> = Vec>; @@ -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 { if self.check_token(kind) { - self.advance(); - return Ok(()); + return Ok(self.advance()); } Err(Error { -- cgit 1.4.1