diff options
Diffstat (limited to 'users/tazjin/rlox/src')
-rw-r--r-- | users/tazjin/rlox/src/interpreter.rs | 15 | ||||
-rw-r--r-- | users/tazjin/rlox/src/parser.rs | 42 |
2 files changed, 55 insertions, 2 deletions
diff --git a/users/tazjin/rlox/src/interpreter.rs b/users/tazjin/rlox/src/interpreter.rs index cfef5548ecdf..738542b6b85b 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<Literal, Error> { + 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 4be6a6afcc54..ac99f19cb2ee 100644 --- a/users/tazjin/rlox/src/parser.rs +++ b/users/tazjin/rlox/src/parser.rs @@ -24,6 +24,13 @@ pub struct Binary<'a> { } #[derive(Debug)] +pub struct Logical<'a> { + pub left: Box<Expr<'a>>, + pub operator: Token<'a>, + pub right: Box<Expr<'a>>, +} + +#[derive(Debug)] pub struct Grouping<'a>(pub Box<Expr<'a>>); #[derive(Debug, Clone, PartialEq)] @@ -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], |