From 6c5e3dea5d099c36e14442a28304062b3d7a2415 Mon Sep 17 00:00:00 2001 From: greg Date: Sat, 12 May 2018 03:51:42 -0700 Subject: [PATCH] Assignment --- schala-lang/src/ast_reducing.rs | 15 +++++++++++++-- schala-lang/src/eval.rs | 31 +++++++++++++++++++++++++------ 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/schala-lang/src/ast_reducing.rs b/schala-lang/src/ast_reducing.rs index 24ae03a..f57d130 100644 --- a/schala-lang/src/ast_reducing.rs +++ b/schala-lang/src/ast_reducing.rs @@ -26,6 +26,10 @@ pub enum Expr { f: Box, args: Vec, }, + Assign { + val: Box, + expr: Box, + }, UnimplementedSigilValue } @@ -110,8 +114,15 @@ impl Declaration { impl BinOp { fn reduce(&self, lhs: &Box, rhs: &Box) -> Expr { - let f = Box::new(Expr::Func(Func::BuiltIn(self.sigil().clone()))); - Expr::Call { f, args: vec![lhs.reduce(), rhs.reduce()]} + if **self.sigil() == "=" { + Expr::Assign { + val: Box::new(lhs.reduce()), + expr: Box::new(rhs.reduce()), + } + } else { + let f = Box::new(Expr::Func(Func::BuiltIn(self.sigil().clone()))); + Expr::Call { f, args: vec![lhs.reduce(), rhs.reduce()]} + } } } diff --git a/schala-lang/src/eval.rs b/schala-lang/src/eval.rs index 812b5dc..2726fbc 100644 --- a/schala-lang/src/eval.rs +++ b/schala-lang/src/eval.rs @@ -345,6 +345,23 @@ impl<'a> State<'a> { }, Val(v) => self.value(v), func @ Func(_) => Ok(func), + Assign { box val, box expr } => { + let name = match val { + Expr::Val(name) => name, + _ => return Err(format!("Trying to assign to a non-value")), + }; + + let constant = match self.values.lookup(&name) { + None => return Err(format!("Runtime error: {} is undefined", name)), + Some(ValueEntry::Binding { constant, .. }) => constant.clone(), + }; + if constant { + return Err(format!("Runtime error: trying to update {}, a non-mutable binding", name)); + } + let val = self.expression(expr)?; + self.values.insert(name.clone(), ValueEntry::Binding { constant: false, val }); + Ok(Expr::Unit) + }, e => Err(format!("Expr {:?} eval not implemented", e)) } } @@ -402,8 +419,8 @@ impl<'a> State<'a> { ("+", &[Lit(Int(n))]) => Lit(Int(n)), ("+", &[Lit(Nat(n))]) => Lit(Nat(n)), - /* builtin functions */ + /* builtin functions */ ("print", &[ref anything]) => { print!("{}", anything.to_repl()); Expr::Unit @@ -417,7 +434,7 @@ impl<'a> State<'a> { io::stdin().read_line(&mut buf).expect("Error readling line in 'getline'"); Lit(StringLit(Rc::new(buf))) }, - _ => return Err(format!("Runtime error: bad or unimplemented builtin")), + (x, args) => return Err(format!("Runtime error: bad or unimplemented builtin {:?} | {:?}", x, args)), }) } @@ -431,8 +448,8 @@ impl<'a> State<'a> { Expr::Func(Func::UserDefined { name: Some(name.clone()), params: params.clone(), body: body.clone() }) //TODO here is unnecessary cloning } else { val.clone() - }), - _ => Err(format!("Functions not done")), + } + ) } } } @@ -448,13 +465,15 @@ mod eval_tests { ($string:expr, $correct:expr) => { let mut state = State::new(); let all_output = state.evaluate(parse(tokenize($string)).0.unwrap().reduce(), true); - let ref output = all_output[0]; - assert_eq!(*output, Ok($correct.to_string())); + let ref output = all_output.last().unwrap(); + assert_eq!(**output, Ok($correct.to_string())); } } #[test] fn test_basic_eval() { fresh_env!("1 + 2", "3"); + fresh_env!("var a = 1; a = 2", "Unit"); + fresh_env!("var a = 1; a = 2; a", "2"); } }