Assignment

This commit is contained in:
greg 2018-05-12 03:51:42 -07:00
parent bd8bf1945c
commit 6c5e3dea5d
2 changed files with 38 additions and 8 deletions

View File

@ -26,6 +26,10 @@ pub enum Expr {
f: Box<Expr>, f: Box<Expr>,
args: Vec<Expr>, args: Vec<Expr>,
}, },
Assign {
val: Box<Expr>,
expr: Box<Expr>,
},
UnimplementedSigilValue UnimplementedSigilValue
} }
@ -110,8 +114,15 @@ impl Declaration {
impl BinOp { impl BinOp {
fn reduce(&self, lhs: &Box<Expression>, rhs: &Box<Expression>) -> Expr { fn reduce(&self, lhs: &Box<Expression>, rhs: &Box<Expression>) -> Expr {
let f = Box::new(Expr::Func(Func::BuiltIn(self.sigil().clone()))); if **self.sigil() == "=" {
Expr::Call { f, args: vec![lhs.reduce(), rhs.reduce()]} 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()]}
}
} }
} }

View File

@ -345,6 +345,23 @@ impl<'a> State<'a> {
}, },
Val(v) => self.value(v), Val(v) => self.value(v),
func @ Func(_) => Ok(func), 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)) e => Err(format!("Expr {:?} eval not implemented", e))
} }
} }
@ -402,8 +419,8 @@ impl<'a> State<'a> {
("+", &[Lit(Int(n))]) => Lit(Int(n)), ("+", &[Lit(Int(n))]) => Lit(Int(n)),
("+", &[Lit(Nat(n))]) => Lit(Nat(n)), ("+", &[Lit(Nat(n))]) => Lit(Nat(n)),
/* builtin functions */
/* builtin functions */
("print", &[ref anything]) => { ("print", &[ref anything]) => {
print!("{}", anything.to_repl()); print!("{}", anything.to_repl());
Expr::Unit Expr::Unit
@ -417,7 +434,7 @@ impl<'a> State<'a> {
io::stdin().read_line(&mut buf).expect("Error readling line in 'getline'"); io::stdin().read_line(&mut buf).expect("Error readling line in 'getline'");
Lit(StringLit(Rc::new(buf))) 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 Expr::Func(Func::UserDefined { name: Some(name.clone()), params: params.clone(), body: body.clone() }) //TODO here is unnecessary cloning
} else { } else {
val.clone() val.clone()
}), }
_ => Err(format!("Functions not done")), )
} }
} }
} }
@ -448,13 +465,15 @@ mod eval_tests {
($string:expr, $correct:expr) => { ($string:expr, $correct:expr) => {
let mut state = State::new(); let mut state = State::new();
let all_output = state.evaluate(parse(tokenize($string)).0.unwrap().reduce(), true); let all_output = state.evaluate(parse(tokenize($string)).0.unwrap().reduce(), true);
let ref output = all_output[0]; let ref output = all_output.last().unwrap();
assert_eq!(*output, Ok($correct.to_string())); assert_eq!(**output, Ok($correct.to_string()));
} }
} }
#[test] #[test]
fn test_basic_eval() { fn test_basic_eval() {
fresh_env!("1 + 2", "3"); fresh_env!("1 + 2", "3");
fresh_env!("var a = 1; a = 2", "Unit");
fresh_env!("var a = 1; a = 2; a", "2");
} }
} }