From 0a0335ae6cd957f48086a41832cef794998f7271 Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Wed, 6 Jan 2021 20:35:05 +0300 Subject: feat(tazjin/rlox): Parse & interpret logical operators Change-Id: I1a7d0eda61f7f077b820dc0d2c2516e204966962 Reviewed-on: https://cl.tvl.fyi/c/depot/+/2324 Reviewed-by: tazjin Tested-by: BuildkiteCI --- users/tazjin/rlox/src/interpreter.rs | 15 +++++++++++++ users/tazjin/rlox/src/parser.rs | 42 ++++++++++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 2 deletions(-) (limited to 'users/tazjin/rlox/src') diff --git a/users/tazjin/rlox/src/interpreter.rs b/users/tazjin/rlox/src/interpreter.rs index cfef5548ec..738542b6b8 100644 --- a/users/tazjin/rlox/src/interpreter.rs +++ b/users/tazjin/rlox/src/interpreter.rs @@ -180,6 +180,7 @@ impl Interpreter { Expr::Unary(unary) => self.eval_unary(unary), Expr::Binary(binary) => self.eval_binary(binary), Expr::Variable(var) => self.get_var(var), + Expr::Logical(log) => self.eval_logical(log), } } @@ -249,6 +250,20 @@ impl Interpreter { self.assign_var(&assign.name, value.clone())?; Ok(value) } + + fn eval_logical<'a>(&mut self, logical: &parser::Logical<'a>) -> Result { + let left = eval_truthy(&self.eval(&logical.left)?); + let right = eval_truthy(&self.eval(&logical.right)?); + + match &logical.operator.kind { + TokenKind::And => Ok(Literal::Boolean(left && right)), + TokenKind::Or => Ok(Literal::Boolean(left || right)), + kind => Err(Error { + line: logical.operator.line, + kind: ErrorKind::InternalError(format!("Invalid logical operator: {:?}", kind)), + }), + } + } } // Interpreter functions not dependent on interpreter-state. diff --git a/users/tazjin/rlox/src/parser.rs b/users/tazjin/rlox/src/parser.rs index 4be6a6afcc..ac99f19cb2 100644 --- a/users/tazjin/rlox/src/parser.rs +++ b/users/tazjin/rlox/src/parser.rs @@ -23,6 +23,13 @@ pub struct Binary<'a> { pub right: Box>, } +#[derive(Debug)] +pub struct Logical<'a> { + pub left: Box>, + pub operator: Token<'a>, + pub right: Box>, +} + #[derive(Debug)] pub struct Grouping<'a>(pub Box>); @@ -52,6 +59,7 @@ pub enum Expr<'a> { Literal(Literal), Unary(Unary<'a>), Variable(Variable<'a>), + Logical(Logical<'a>), } // Variable assignment. Not to be confused with `Variable`, which is @@ -102,7 +110,9 @@ printStmt → "print" expression ";" ; expression → assignment ; assignment → IDENTIFIER "=" assignment - | equality ; + | logic_or ; +logic_or → logic_and ( "or" logic_and )* ; +logic_and → equality ( "and" equality )* ; equality → comparison ( ( "!=" | "==" ) comparison )* ; comparison → term ( ( ">" | ">=" | "<" | "<=" ) term )* ; term → factor ( ( "-" | "+" ) factor )* ; @@ -222,7 +232,7 @@ impl<'a> Parser<'a> { } fn assignment(&mut self) -> ExprResult<'a> { - let expr = self.equality()?; + let expr = self.logic_or()?; if self.match_token(&[TokenKind::Equal]) { let equals = self.previous().clone(); @@ -244,6 +254,34 @@ impl<'a> Parser<'a> { Ok(expr) } + fn logic_or(&mut self) -> ExprResult<'a> { + let mut expr = self.logic_and()?; + + while self.match_token(&[TokenKind::Or]) { + expr = Expr::Logical(Logical { + left: Box::new(expr), + operator: self.previous().clone(), + right: Box::new(self.logic_and()?), + }) + } + + Ok(expr) + } + + fn logic_and(&mut self) -> ExprResult<'a> { + let mut expr = self.equality()?; + + while self.match_token(&[TokenKind::And]) { + expr = Expr::Logical(Logical { + left: Box::new(expr), + operator: self.previous().clone(), + right: Box::new(self.equality()?), + }) + } + + Ok(expr) + } + fn equality(&mut self) -> ExprResult<'a> { self.binary_operator( &[TokenKind::BangEqual, TokenKind::EqualEqual], -- cgit 1.4.1