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/parser.rs | |
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/parser.rs')
-rw-r--r-- | users/tazjin/rlox/src/parser.rs | 46 |
1 files changed, 43 insertions, 3 deletions
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 { |