diff options
Diffstat (limited to 'src/interpret/walker.rs')
| -rw-r--r-- | src/interpret/walker.rs | 113 |
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 + } } |
