diff options
| author | Mel <einebeere@gmail.com> | 2021-10-24 23:04:22 +0200 |
|---|---|---|
| committer | Mel <einebeere@gmail.com> | 2021-10-24 23:04:22 +0200 |
| commit | cede973c76e061e06c7bdaad3922be5d9305f950 (patch) | |
| tree | 19d67ed113cb73109f2197c2637d2162a2db9228 /src/interpret/walker.rs | |
| parent | af34b3030a46805f42f04341f1ffb20d92fbb7ce (diff) | |
| download | rabbithole-cede973c76e061e06c7bdaad3922be5d9305f950.tar.zst rabbithole-cede973c76e061e06c7bdaad3922be5d9305f950.zip | |
Array element assignment and constants
Diffstat (limited to 'src/interpret/walker.rs')
| -rw-r--r-- | src/interpret/walker.rs | 71 |
1 files changed, 47 insertions, 24 deletions
diff --git a/src/interpret/walker.rs b/src/interpret/walker.rs index 0177777..b8a2e68 100644 --- a/src/interpret/walker.rs +++ b/src/interpret/walker.rs @@ -2,14 +2,14 @@ use std::{cell::RefCell, rc::Rc}; use crate::parse::ast::{ expression::Expression, - nodes::{BinaryOperator as BinOp, BlockNode, Identifier, SimpleLiteral, UnaryOperator as UnOp}, + nodes::{BinaryOperator as BinOp, BlockNode, SimpleLiteral, UnaryOperator as UnOp}, statement::Statement, Program, }; use thiserror::Error; use super::{ - scope::Scope, + scope::{Scope, ScopeError}, value::{OperationError, Value}, }; @@ -63,16 +63,10 @@ impl Walker { 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); + match op { + BinOp::ConstAssign => return self.assing_to_lvalue(left, right, true), + BinOp::Assign => return self.assing_to_lvalue(left, right, false), + _ => {} } let left = self.walk_expression(left)?; @@ -90,8 +84,7 @@ impl Walker { BinOp::Gte => left.gte(right), BinOp::Lt => right.gt(left), BinOp::Lte => right.gte(left), - // No structure access yet. - BinOp::Dot => todo!(), + BinOp::Dot => todo!("Structures not implemented yet."), _ => unreachable!(), } .map_err(WalkerError::OperationError) @@ -109,7 +102,10 @@ impl Walker { Expression::ArrayAccess(node) => { let array = self.walk_expression(&node.array)?; let index = self.walk_expression(&node.index)?; - array.subscript(index).map_err(WalkerError::OperationError) + array + .subscript(index) + .map(|v| v.clone()) + .map_err(WalkerError::OperationError) } Expression::MemberAccess(_) => todo!("Structures not implemented yet."), Expression::Group(node) => self.walk_expression(node), @@ -118,7 +114,7 @@ impl Walker { for expression in &node.elements { elements.push(self.walk_expression(expression)?); } - Ok(Value::Array(elements)) + Ok(Value::Array(Rc::new(RefCell::new(elements)))) } Expression::SimpleLiteral(token) => { let value = match token { @@ -133,7 +129,7 @@ impl Walker { Expression::Block(block) => self.walk_block(block.as_ref()), Expression::FnLiteral(fn_node) => { let node = fn_node.as_ref().clone(); - Ok(Value::Fn(RefCell::new(Rc::new(node)))) + Ok(Value::Fn(Rc::new(RefCell::new(node)))) } Expression::If(if_node) => { for conditional in &if_node.conditionals { @@ -189,11 +185,7 @@ impl Walker { } } Expression::Identifier(ident) => { - if let Some(value) = self.scope.get_var(ident) { - Ok(value) - } else { - Err(WalkerError::UnknownIdentifier(ident.clone())) - } + self.scope.get_var(ident).map_err(WalkerError::ScopeError) } } } @@ -215,17 +207,48 @@ impl Walker { result } + + pub fn assing_to_lvalue( + &mut self, + lvalue: &Expression, + rvalue: &Expression, + is_constant: bool, + ) -> Result<Value, WalkerError> { + // Maybe other expressions could also be l-values, but these are fine for now. + match lvalue { + Expression::MemberAccess(_) => todo!("Structures not implemented yet."), + Expression::ArrayAccess(node) => { + let mut array = self.walk_expression(&node.array)?; + let index = self.walk_expression(&node.index)?; + let value = self.walk_expression(rvalue)?; + + array + .subscript_assign(index, value) + .map_err(WalkerError::OperationError) + } + Expression::Identifier(ident) => { + let value = self.walk_expression(rvalue)?; + self.scope + .set_var(ident, value.clone(), is_constant) + .map_err(WalkerError::ScopeError)?; + return Ok(value); + } + _ => Err(WalkerError::NonLValueAssignment), + } + } } // TODO: Add source maps to the errors. #[derive(Error, Debug)] pub enum WalkerError { - #[error("Unknown identifier '{0}'")] - UnknownIdentifier(Identifier), #[error("Loop expressions can only take boolean values as conditions.")] WrongLoopConditionType, #[error("If and Elif expressions can only take boolean values as conditions.")] WrongIfConditionType, + #[error("Can only assign to identifiers and member or array access results.")] + NonLValueAssignment, + #[error(transparent)] + ScopeError(ScopeError), #[error(transparent)] OperationError(OperationError), // These are used for loop control flow and are only errors |
