about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/interpret/walker.rs24
-rw-r--r--src/lex/lexer.rs14
-rw-r--r--src/lex/token.rs3
-rw-r--r--src/parse/ast/nodes.rs4
-rw-r--r--src/parse/parser.rs34
5 files changed, 77 insertions, 2 deletions
diff --git a/src/interpret/walker.rs b/src/interpret/walker.rs
index b8a2e68..471da89 100644
--- a/src/interpret/walker.rs
+++ b/src/interpret/walker.rs
@@ -69,6 +69,25 @@ impl Walker {
                     _ => {}
                 }
 
+                // Short-circuting operators
+                if let BinOp::And | BinOp::Or = op {
+                    let left_value = self.walk_expression(left)?;
+                    let is_left_true = match left_value {
+                        Value::Bool(bool) => bool,
+                        _ => return Err(WalkerError::WrongAndOrType),
+                    };
+
+                    if let BinOp::And = op {
+                        if !is_left_true {
+                            return Ok(Value::Bool(false));
+                        }
+                    } else if is_left_true {
+                        return Ok(Value::Bool(true));
+                    }
+
+                    return self.walk_expression(right);
+                }
+
                 let left = self.walk_expression(left)?;
                 let right = self.walk_expression(right)?;
 
@@ -78,13 +97,14 @@ impl Walker {
                     BinOp::Minus => left.sub(right),
                     BinOp::Star => left.mul(right),
                     BinOp::Slash => left.div(right),
+                    BinOp::Dot => todo!("Structures not implemented yet."),
                     BinOp::Eq => left.eq(right),
                     BinOp::Neq => left.neq(right),
                     BinOp::Gt => left.gt(right),
                     BinOp::Gte => left.gte(right),
                     BinOp::Lt => right.gt(left),
                     BinOp::Lte => right.gte(left),
-                    BinOp::Dot => todo!("Structures not implemented yet."),
+
                     _ => unreachable!(),
                 }
                 .map_err(WalkerError::OperationError)
@@ -245,6 +265,8 @@ pub enum WalkerError {
     WrongLoopConditionType,
     #[error("If and Elif expressions can only take boolean values as conditions.")]
     WrongIfConditionType,
+    #[error("&& and || expressions can only take boolean values as their operands.")]
+    WrongAndOrType,
     #[error("Can only assign to identifiers and member or array access results.")]
     NonLValueAssignment,
     #[error(transparent)]
diff --git a/src/lex/lexer.rs b/src/lex/lexer.rs
index edd1ff0..1d46ce7 100644
--- a/src/lex/lexer.rs
+++ b/src/lex/lexer.rs
@@ -79,6 +79,20 @@ impl Iterator for Lexer<'_> {
                         OpGt
                     }
                 }
+                '&' => {
+                    if self.advance_if('&') {
+                        OpAnd
+                    } else {
+                        Unknown('&')
+                    }
+                }
+                '|' => {
+                    if self.advance_if('|') {
+                        OpOr
+                    } else {
+                        Unknown('|')
+                    }
+                }
                 '(' => GroupOpen,
                 ')' => GroupClose,
                 '{' => BlockOpen,
diff --git a/src/lex/token.rs b/src/lex/token.rs
index 3c6d5c6..77b0df6 100644
--- a/src/lex/token.rs
+++ b/src/lex/token.rs
@@ -25,6 +25,9 @@ pub enum TokenVariant {
     OpGt,
     OpLte,
     OpGte,
+    // Short-circuting boolean operators
+    OpAnd,
+    OpOr,
 
     // Statement symbols
     Dot,
diff --git a/src/parse/ast/nodes.rs b/src/parse/ast/nodes.rs
index bffaea3..2bf3f17 100644
--- a/src/parse/ast/nodes.rs
+++ b/src/parse/ast/nodes.rs
@@ -14,6 +14,8 @@ pub enum BinaryOperator {
     Gte,
     Lt,
     Lte,
+    And,
+    Or,
     Assign,
     ConstAssign,
     Dot,
@@ -32,6 +34,8 @@ impl BinaryOperator {
             OpGt => Self::Gt,
             OpLte => Self::Lte,
             OpGte => Self::Gte,
+            OpAnd => Self::And,
+            OpOr => Self::Or,
             Assign => Self::Assign,
             ConstAssign => Self::ConstAssign,
             Dot => Self::Dot,
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index a882f35..6b0a785 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -87,7 +87,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
 
     fn assignment_expression(&mut self) -> Result<Expression> {
         // Parse any expressions as l-values for now.
-        let left = self.equality_expression()?;
+        let left = self.or_expression()?;
 
         if let Some(op) = consume_if!(self, Assign | ConstAssign) {
             let right = self.assignment_expression()?;
@@ -102,6 +102,38 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         }
     }
 
+    fn or_expression(&mut self) -> Result<Expression> {
+        let mut left = self.and_expression()?;
+
+        while let Some(op) = consume_if!(self, OpAnd) {
+            let right = self.and_expression()?;
+
+            left = Expression::Binary {
+                left: Box::new(left),
+                op: BinaryOperator::from_token(op),
+                right: Box::new(right),
+            };
+        }
+
+        Ok(left)
+    }
+
+    fn and_expression(&mut self) -> Result<Expression> {
+        let mut left = self.equality_expression()?;
+
+        while let Some(op) = consume_if!(self, OpOr) {
+            let right = self.equality_expression()?;
+
+            left = Expression::Binary {
+                left: Box::new(left),
+                op: BinaryOperator::from_token(op),
+                right: Box::new(right),
+            };
+        }
+
+        Ok(left)
+    }
+
     fn equality_expression(&mut self) -> Result<Expression> {
         let mut left = self.comparison_expression()?;