diff options
| author | Mel <einebeere@gmail.com> | 2021-10-22 22:44:21 +0200 |
|---|---|---|
| committer | Mel <einebeere@gmail.com> | 2021-10-22 22:52:24 +0200 |
| commit | c35a7ba06a47a8b26bd784df552ad4c881383898 (patch) | |
| tree | 1ae23ace7246a0a97d6d53d6b0d0b88528ca5ad1 /src/interpret | |
| parent | ce9007bd5aefc37cf7e48eefc0fab4049c8a6b7d (diff) | |
| download | rabbithole-c35a7ba06a47a8b26bd784df552ad4c881383898.tar.zst rabbithole-c35a7ba06a47a8b26bd784df552ad4c881383898.zip | |
Boolean logic and If expressions.
Diffstat (limited to 'src/interpret')
| -rw-r--r-- | src/interpret/value.rs | 150 | ||||
| -rw-r--r-- | src/interpret/walker.rs | 113 |
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 + } } |
