about summary refs log tree commit diff
path: root/src/interpret
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
parentce9007bd5aefc37cf7e48eefc0fab4049c8a6b7d (diff)
downloadrabbithole-c35a7ba06a47a8b26bd784df552ad4c881383898.tar.zst
rabbithole-c35a7ba06a47a8b26bd784df552ad4c881383898.zip
Boolean logic and If expressions.
Diffstat (limited to 'src/interpret')
-rw-r--r--src/interpret/value.rs150
-rw-r--r--src/interpret/walker.rs113
2 files changed, 127 insertions, 136 deletions
diff --git a/src/interpret/value.rs b/src/interpret/value.rs
index 0c7843c..1ca0f0e 100644
--- a/src/interpret/value.rs
+++ b/src/interpret/value.rs
@@ -9,6 +9,7 @@ pub enum Value {
     Str(String),
     Float(f64),
     Int(i64),
+    Bool(bool),
     Fn(Ref<FnNode>),
     Void,
 }
@@ -85,97 +86,66 @@ impl Value {
             _ => Err(anyhow!("Left operand can't be multiplied.")),
         }
     }
-}
-
-// pub enum Value {
-//     Float(f64),
-//     Int(i64),
-// }
-
-// impl Add for WalkValue {
-//     type Output = Self;
-
-//     fn add(self, rhs: Self) -> Self::Output {
-//         match self {
-//             Self::Float(float) => match rhs {
-//                 Self::Float(other_float) => Self::Float(float + other_float),
-//                 Self::Int(other_int) => Self::Float(float + other_int as f64),
-//             },
-//             Self::Int(int) => match rhs {
-//                 Self::Float(other_float) => Self::Float(int as f64 + other_float),
-//                 Self::Int(other_int) => Self::Int(int + other_int),
-//             },
-//         }
-//     }
-// }
-
-// impl Sub for WalkValue {
-//     type Output = Self;
-
-//     fn sub(self, rhs: Self) -> Self::Output {
-//         match self {
-//             Self::Float(float) => match rhs {
-//                 Self::Float(other_float) => Self::Float(float - other_float),
-//                 Self::Int(other_int) => Self::Float(float - other_int as f64),
-//             },
-//             Self::Int(int) => match rhs {
-//                 Self::Float(other_float) => Self::Float(int as f64 - other_float),
-//                 Self::Int(other_int) => Self::Int(int - other_int),
-//             },
-//         }
-//     }
-// }
-
-// impl Mul for WalkValue {
-//     type Output = Self;
-
-//     fn mul(self, rhs: Self) -> Self::Output {
-//         match self {
-//             Self::Float(float) => match rhs {
-//                 Self::Float(other_float) => Self::Float(float * other_float),
-//                 Self::Int(other_int) => Self::Float(float * other_int as f64),
-//             },
-//             Self::Int(int) => match rhs {
-//                 Self::Float(other_float) => Self::Float(int as f64 * other_float),
-//                 Self::Int(other_int) => Self::Int(int * other_int),
-//             },
-//         }
-//     }
-// }
 
-// impl Div for WalkValue {
-//     type Output = Self;
-
-//     fn div(self, rhs: Self) -> Self::Output {
-//         match self {
-//             Self::Float(float) => match rhs {
-//                 Self::Float(other_float) => Self::Float(float / other_float),
-//                 Self::Int(other_int) => Self::Float(float / other_int as f64),
-//             },
-//             Self::Int(int) => match rhs {
-//                 Self::Float(other_float) => Self::Float(int as f64 / other_float),
-//                 Self::Int(other_int) => Self::Float(int as f64 / other_int as f64),
-//             },
-//         }
-//     }
-// }
+    pub fn eq(self, rhs: Value) -> Result<Value> {
+        match self {
+            Value::Str(l) => match rhs {
+                Value::Str(r) => Ok(Value::Bool(l == r)),
+                _ => Ok(Value::Bool(false)),
+            },
+            Value::Float(l) => match rhs {
+                Value::Float(r) => Ok(Value::Bool(l == r)),
+                _ => Ok(Value::Bool(false)),
+            },
+            Value::Int(l) => match rhs {
+                Value::Int(r) => Ok(Value::Bool(l == r)),
+                _ => Ok(Value::Bool(false)),
+            },
+            Value::Bool(l) => match rhs {
+                Value::Bool(r) => Ok(Value::Bool(l == r)),
+                _ => Ok(Value::Bool(false)),
+            },
+            _ => Ok(Value::Bool(false)),
+        }
+    }
 
-// impl Neg for WalkValue {
-//     type Output = Self;
+    pub fn neq(self, rhs: Value) -> Result<Value> {
+        if let Ok(Value::Bool(value)) = self.eq(rhs) {
+            Ok(Value::Bool(!value))
+        } else {
+            unreachable!()
+        }
+    }
 
-//     fn neg(self) -> Self::Output {
-//         match self {
-//             Self::Float(float) => Self::Float(-float),
-//             Self::Int(int) => Self::Int(-int),
-//         }
-//     }
-// }
+    pub fn gt(self, rhs: Value) -> Result<Value> {
+        match self {
+            Value::Float(r) => match rhs {
+                Value::Float(l) => Ok(Value::Bool(r > l)),
+                Value::Int(l) => Ok(Value::Bool(r > l as f64)),
+                _ => Err(anyhow!("Right operand can't be compared.")),
+            },
+            Value::Int(r) => match rhs {
+                Value::Float(l) => Ok(Value::Bool(r as f64 > l)),
+                Value::Int(l) => Ok(Value::Bool(r > l)),
+                _ => Err(anyhow!("Right operand can't be compared.")),
+            },
+            _ => Err(anyhow!("Left operand can't be compared.")),
+        }
+    }
 
-// impl Display for WalkValue {
-//     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-//         match self {
-//             Self::Float(float) => write!(f, "{}", float),
-//             Self::Int(int) => write!(f, "{}", int),
-//         }
-//     }
-// }
+    pub fn gte(self, rhs: Value) -> Result<Value> {
+        match self {
+            Value::Float(r) => match rhs {
+                Value::Float(l) => Ok(Value::Bool(r >= l)),
+                Value::Int(l) => Ok(Value::Bool(r >= l as f64)),
+                _ => Err(anyhow!("Right operand can't be compared.")),
+            },
+            Value::Int(r) => match rhs {
+                Value::Float(l) => Ok(Value::Bool(r as f64 >= l)),
+                Value::Int(l) => Ok(Value::Bool(r >= l)),
+                _ => Err(anyhow!("Right operand can't be compared.")),
+            },
+            _ => Err(anyhow!("Left operand can't be compared.")),
+        }
+    }
+}
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
+    }
 }