diff --git a/src/run.rs b/src/run.rs index 99556c6..d271b7c 100644 --- a/src/run.rs +++ b/src/run.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, fmt::Debug, rc::Rc}; use crate::{ - ast::{Constant, Expression, Location}, + ast::{Constant, Expression, Location, Statement}, types::{Value, ValueInner}, }; @@ -104,6 +104,43 @@ impl Eval for Expression { } } +pub trait Exec { + fn exec(&self, scope: &mut Scope); +} + +impl Exec for Statement { + fn exec(&self, scope: &mut Scope) { + match self { + Statement::Assign { target, source } => { + let value = source.eval(scope); + match target { + Location::Variable { name } => { + scope.set(name.into(), value); + } + Location::Field { table, index } => { + let table = table.eval(scope); + let Some(ValueInner::Table(table)) = table else { + panic!("attempt to index non-table value {table:?}") + }; + let index = index.eval(scope); + let Some(index) = index else { + panic!("attempt to index with a nil value") + }; + table.set(index, value); + } + }; + } + Statement::Call { callee, args } => { + Expression::Call { + callee: callee.clone(), + args: args.clone(), + } + .eval(scope); + } + } + } +} + #[cfg(test)] mod tests { use super::*; @@ -178,4 +215,18 @@ mod tests { Some(49.into()) ); } + + #[test] + fn test_var_assign() { + let mut scope = Scope::default(); + assert_eq!(scope.get("foo"), None); + assert_eq!(scope.get("bar"), None); + ast::Statement::Assign { + target: ast::Location::Variable { name: "foo".into() }, + source: Box::new(ast::Expression::Constant(ast::Constant::Number(42))), + } + .exec(&mut scope); + assert_eq!(scope.get("foo"), Some(42.into())); + assert_eq!(scope.get("bar"), None); + } }