about summary refs log tree commit diff
path: root/src/interpret/walker.rs
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2021-10-22 22:44:21 +0200
committerMel <einebeere@gmail.com>2021-10-22 22:52:24 +0200
commitc35a7ba06a47a8b26bd784df552ad4c881383898 (patch)
tree1ae23ace7246a0a97d6d53d6b0d0b88528ca5ad1 /src/interpret/walker.rs
parentce9007bd5aefc37cf7e48eefc0fab4049c8a6b7d (diff)
downloadrabbithole-c35a7ba06a47a8b26bd784df552ad4c881383898.tar.zst
rabbithole-c35a7ba06a47a8b26bd784df552ad4c881383898.zip
Boolean logic and If expressions.
Diffstat (limited to 'src/interpret/walker.rs')
-rw-r--r--src/interpret/walker.rs113
1 files changed, 67 insertions, 46 deletions
diff --git a/src/interpret/walker.rs b/src/interpret/walker.rs
index 16f3f1c..79ef87f 100644
--- a/src/interpret/walker.rs
+++ b/src/interpret/walker.rs
@@ -2,7 +2,7 @@ use std::{cell::RefCell, rc::Rc};
 
 use crate::parse::ast::{
     expression::Expression,
-    nodes::{BinaryOperator as BinOp, Literal, UnaryOperator as UnOp},
+    nodes::{BinaryOperator as BinOp, BlockNode, Literal, UnaryOperator as UnOp},
     statement::Statement,
     Program,
 };
@@ -10,7 +10,6 @@ use anyhow::{anyhow, Result};
 
 use super::{scope::Scope, value::Value};
 
-// No state for now.
 pub struct Walker {
     scope: Scope,
 }
@@ -49,36 +48,37 @@ impl Walker {
     pub fn walk_expression(&mut self, node: &Expression) -> Result<Value> {
         match node {
             Expression::Binary { left, op, right } => {
+                // Assignment
+                // No difference between assignments for now.
+                if let BinOp::ConstAssign | BinOp::Assign = op {
+                    let identifier = match left.as_ref() {
+                        Expression::Identifier(i) => i,
+                        _ => todo!("Lvalues can only be identifiers."),
+                    };
+
+                    let value = self.walk_expression(right)?;
+                    self.scope.set_var(identifier, value.clone());
+                    return Ok(value);
+                }
+
+                let left = self.walk_expression(left)?;
+                let right = self.walk_expression(right)?;
+
+                // Other operators
                 let new_value = match op {
-                    BinOp::Plus => self
-                        .walk_expression(left)?
-                        .add(self.walk_expression(right)?),
-                    BinOp::Minus => self
-                        .walk_expression(left)?
-                        .sub(self.walk_expression(right)?),
-                    BinOp::Star => self
-                        .walk_expression(left)?
-                        .mul(self.walk_expression(right)?),
-                    BinOp::Slash => self
-                        .walk_expression(left)?
-                        .div(self.walk_expression(right)?),
-                    // No difference between assignments for now.
-                    BinOp::Assign | BinOp::ConstAssign => {
-                        let identifier = match left.as_ref() {
-                            Expression::Identifier(i) => i,
-                            _ => todo!("Lvalues can only be identifiers."),
-                        };
-
-                        let value = self.walk_expression(right)?;
-                        self.scope.set_var(identifier, value.clone());
-                        Ok(value)
-                    }
-                    // Boolean logic comes later.
-                    BinOp::Eq | BinOp::Neq | BinOp::Gt | BinOp::Gte | BinOp::Lt | BinOp::Lte => {
-                        todo!()
-                    }
+                    BinOp::Plus => left.add(right),
+                    BinOp::Minus => left.sub(right),
+                    BinOp::Star => left.mul(right),
+                    BinOp::Slash => left.div(right),
+                    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),
                     // No structure access yet.
                     BinOp::Dot => todo!(),
+                    _ => unreachable!(),
                 }?;
 
                 Ok(new_value)
@@ -100,32 +100,35 @@ impl Walker {
                     Literal::Int(int) => Value::Int(*int as i64),
                     Literal::Float(float) => Value::Float(*float as f64),
                     Literal::Str(string) => Value::Str(string.clone()),
+                    Literal::Bool(bool) => Value::Bool(*bool),
                 };
 
                 Ok(value)
             }
-            Expression::Block(block) => {
-                self.scope.nest();
-
-                for statement in block.statements.iter() {
-                    self.walk_statement(statement)?;
+            Expression::Block(block) => self.walk_block(block.as_ref()),
+            Expression::Fn(fn_node) => {
+                let node = fn_node.as_ref().clone();
+                Ok(Value::Fn(RefCell::new(Rc::new(node))))
+            }
+            Expression::If(if_node) => {
+                for conditional in &if_node.conditionals {
+                    if let Value::Bool(bool) = self.walk_expression(&conditional.condition)? {
+                        if bool {
+                            return self.walk_block(&conditional.block);
+                        }
+                    } else {
+                        return Err(anyhow!(
+                            "If and Elif expressions can only take boolean values as conditions."
+                        ));
+                    }
                 }
 
-                let result = if let Some(tail_expression) = &block.tail_expression {
-                    Ok(self.walk_expression(tail_expression)?)
+                if let Some(else_conditional) = &if_node.else_block {
+                    self.walk_block(else_conditional)
                 } else {
                     Ok(Value::Void)
-                };
-
-                self.scope.unnest();
-
-                result
-            }
-            Expression::Fn(fn_node) => {
-                let node = fn_node.as_ref().clone();
-                Ok(Value::Fn(RefCell::new(Rc::new(node))))
+                }
             }
-            Expression::If(_) => todo!(),
             Expression::Identifier(ident) => {
                 if let Some(value) = self.scope.get_var(ident) {
                     Ok(value)
@@ -135,4 +138,22 @@ impl Walker {
             }
         }
     }
+
+    fn walk_block(&mut self, block: &BlockNode) -> Result<Value> {
+        self.scope.nest();
+
+        for statement in block.statements.iter() {
+            self.walk_statement(statement)?;
+        }
+
+        let result = if let Some(tail_expression) = &block.tail_expression {
+            Ok(self.walk_expression(tail_expression)?)
+        } else {
+            Ok(Value::Void)
+        };
+
+        self.scope.unnest();
+
+        result
+    }
 }