about summary refs log tree commit diff
path: root/users/tazjin/rlox/src/parser.rs
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2020-12-22T14·44+0100
committertazjin <mail@tazj.in>2020-12-22T20·18+0000
commit0f9a7b3f86f56162cf1a694d98d82e4937d44a52 (patch)
treee0e092c0fcf9e34b1eddf39bf08423e5fe6e3e91 /users/tazjin/rlox/src/parser.rs
parent5010b7971806d30de0987d8e7706ca24a96fbef5 (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.rs46
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 {