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/parser.rs | 46 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) (limited to 'users/tazjin/rlox/src/parser.rs') 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