diff --git a/schala-lang/src/eval.rs b/schala-lang/src/eval.rs index ff1f2f7..5b37054 100644 --- a/schala-lang/src/eval.rs +++ b/schala-lang/src/eval.rs @@ -16,7 +16,7 @@ pub struct State<'a> { macro_rules! builtin_binding { ($name:expr, $values:expr) => { - $values.insert(Rc::new(format!($name)), ValueEntry::Binding { constant: true, val: Expr::Func(Func::BuiltIn(Rc::new(format!($name)))) }); + $values.insert(Rc::new(format!($name)), ValueEntry::Binding { constant: true, val: Node::Expr(Expr::Func(Func::BuiltIn(Rc::new(format!($name))))) }); } } @@ -34,33 +34,57 @@ impl<'a> State<'a> { } } +#[derive(Debug, Clone)] +enum Node { + Expr(Expr), + PrimObject { + name: Rc, + tag: usize, + items: Vec, + } +} + +fn paren_wrapped_vec(terms: impl Iterator) -> String { + let mut buf = String::new(); + write!(buf, "(").unwrap(); + for term in terms.map(|e| Some(e)).intersperse(None) { + match term { + Some(e) => write!(buf, "{}", e).unwrap(), + None => write!(buf, ", ").unwrap(), + }; + } + write!(buf, ")").unwrap(); + buf +} + + +impl Node { + fn to_repl(&self) -> String { + match self { + Node::Expr(e) => e.to_repl(), + Node::PrimObject { name, items, tag } if items.len() == 0 => format!("{}", name), + Node::PrimObject { name, items, tag } => format!("{}{}", name, paren_wrapped_vec(items.iter().map(|x| x.to_repl()))), + } + } +} + #[derive(Debug)] enum ValueEntry { Binding { constant: bool, - val: /*FullyEvaluatedExpr*/ Expr, + val: /*FullyEvaluatedExpr*/ Node, //TODO make this use a subtype to represent fully evaluatedness } } type EvalResult = Result; - impl Expr { + fn to_node(self) -> Node { + Node::Expr(self) + } fn to_repl(&self) -> String { use self::Lit::*; use self::Func::*; - fn paren_wrapped_vec(exprs: &Vec) -> String { - let mut buf = String::new(); - write!(buf, "(").unwrap(); - for term in exprs.iter().map(|e| Some(e)).intersperse(None) { - match term { - Some(e) => write!(buf, "{}", e.to_repl()).unwrap(), - None => write!(buf, ", ").unwrap(), - }; - } - write!(buf, ")").unwrap(); - buf - } match self { Expr::Lit(ref l) => match l { @@ -69,8 +93,6 @@ impl Expr { Float(f) => format!("{}", f), Bool(b) => format!("{}", b), StringLit(s) => format!("\"{}\"", s), - PrimObject { name, items } if items.len() == 0 => format!("{}", name), - PrimObject { name, items } => format!("{}{}", name, paren_wrapped_vec(items)), }, Expr::Func(f) => match f { BuiltIn(name) => format!("", name), @@ -84,7 +106,7 @@ impl Expr { } else { format!("", name) }, - Expr::Tuple(exprs) => paren_wrapped_vec(exprs), + Expr::Tuple(exprs) => paren_wrapped_vec(exprs.iter().map(|x| x.to_repl())), _ => format!("{:?}", self), } } @@ -115,7 +137,7 @@ impl<'a> State<'a> { fn prebinding(&mut self, stmt: &Stmt) { match stmt { Stmt::PreBinding { name, func } => { - let v_entry = ValueEntry::Binding { constant: true, val: Expr::Func(func.clone()) }; + let v_entry = ValueEntry::Binding { constant: true, val: Node::Expr(Expr::Func(func.clone())) }; self.values.insert(name.clone(), v_entry); }, Stmt::Expr(_expr) => { @@ -126,79 +148,86 @@ impl<'a> State<'a> { } } - fn statement(&mut self, stmt: Stmt) -> EvalResult> { + fn statement(&mut self, stmt: Stmt) -> EvalResult> { match stmt { Stmt::Binding { name, constant, expr } => { - let val = self.expression(expr)?; + let val = self.expression(Node::Expr(expr))?; self.values.insert(name.clone(), ValueEntry::Binding { constant, val }); Ok(None) }, - Stmt::Expr(expr) => Ok(Some(self.expression(expr)?)), + Stmt::Expr(expr) => Ok(Some(self.expression(expr.to_node())?)), Stmt::PreBinding {..} | Stmt::Noop => Ok(None), } } - fn block(&mut self, stmts: Vec) -> EvalResult { + fn block(&mut self, stmts: Vec) -> EvalResult { let mut ret = None; for stmt in stmts { ret = self.statement(stmt)?; } - Ok(ret.unwrap_or(Expr::Unit)) + Ok(ret.unwrap_or(Node::Expr(Expr::Unit))) } - fn expression(&mut self, expr: Expr) -> EvalResult { + fn expression(&mut self, node: Node) -> EvalResult { use self::Expr::*; - match expr { - literal @ Lit(_) => Ok(literal), - Call { box f, args } => { - match self.expression(f)? { - Constructor { type_name, name, tag, arity} => self.apply_data_constructor(type_name, name, tag, arity, args), - Func(f) => self.apply_function(f, args), - other => return Err(format!("Tried to call {:?} which is not a function or data constructor", other)), - } - }, - Val(v) => self.value(v), - constructor @ Constructor { .. } => Ok(constructor), - func @ Func(_) => Ok(func), - Tuple(exprs) => Ok(Tuple(exprs.into_iter().map(|expr| self.expression(expr)).collect::,_>>()?)), - Conditional { box cond, then_clause, else_clause } => self.conditional(cond, then_clause, else_clause), - Assign { box val, box expr } => { - let name = match val { - Expr::Val(name) => name, - _ => return Err(format!("Trying to assign to a non-value")), - }; + match node { + obj @ Node::PrimObject { .. } => Ok(obj), + Node::Expr(expr) => match expr { + literal @ Lit(_) => Ok(Node::Expr(literal)), + Call { box f, args } => { + match self.expression(Node::Expr(f))? { + Node::Expr(Constructor { type_name, name, tag, arity }) => self.apply_data_constructor(type_name, name, tag, arity, args), + Node::Expr(Func(f)) => self.apply_function(f, args), + other => return Err(format!("Tried to call {:?} which is not a function or data constructor", other)), + } + }, + Val(v) => self.value(v), + constructor @ Constructor { .. } => Ok(Node::Expr(constructor)), + func @ Func(_) => Ok(Node::Expr(func)), + Tuple(exprs) => { + unimplemented!() + }, + //Tuple(exprs) => Ok(Tuple(exprs.into_iter().map(|expr| self.expression(expr)).collect::,_>>()?)), + Conditional { box cond, then_clause, else_clause } => self.conditional(cond, then_clause, else_clause), + 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!("{} is undefined", name)), - Some(ValueEntry::Binding { constant, .. }) => constant.clone(), - }; - if constant { - return Err(format!("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)) + let constant = match self.values.lookup(&name) { + None => return Err(format!("{} is undefined", name)), + Some(ValueEntry::Binding { constant, .. }) => constant.clone(), + }; + if constant { + return Err(format!("trying to update {}, a non-mutable binding", name)); + } + let val = self.expression(Node::Expr(expr))?; + self.values.insert(name.clone(), ValueEntry::Binding { constant: false, val }); + Ok(Node::Expr(Expr::Unit)) + }, + e => Err(format!("Expr {:?} eval not implemented", e)) + } } } - fn apply_data_constructor(&mut self, type_name: Rc, name: Rc, tag: usize, arity: usize, args: Vec) -> EvalResult { + fn apply_data_constructor(&mut self, type_name: Rc, name: Rc, tag: usize, arity: usize, args: Vec) -> EvalResult { if arity != args.len() { return Err(format!("Data constructor {} requires {} args", name, arity)); } - let evaled_args = args.into_iter().map(|expr| self.expression(expr)).collect::,_>>()?; + let evaled_args = args.into_iter().map(|expr| self.expression(Node::Expr(expr))).collect::,_>>()?; //let evaled_args = vec![]; - Ok(Expr::Lit(self::Lit::PrimObject { + Ok(Node::PrimObject { name: name.clone(), items: evaled_args, - })) + tag: 0, + }) } - fn apply_function(&mut self, f: Func, args: Vec) -> EvalResult { + fn apply_function(&mut self, f: Func, args: Vec) -> EvalResult { match f { - Func::BuiltIn(sigil) => self.apply_builtin(sigil, args), + Func::BuiltIn(sigil) => Ok(Node::Expr(self.apply_builtin(sigil, args)?)), Func::UserDefined { params, body, name } => { if params.len() != args.len() { @@ -209,7 +238,7 @@ impl<'a> State<'a> { symbol_table_handle: self.symbol_table_handle.clone(), }; for (param, val) in params.into_iter().zip(args.into_iter()) { - let val = func_state.expression(val)?; + let val = func_state.expression(Node::Expr(val))?; func_state.values.insert(param, ValueEntry::Binding { constant: true, val }); } // TODO figure out function return semantics @@ -221,7 +250,13 @@ impl<'a> State<'a> { fn apply_builtin(&mut self, name: Rc, args: Vec) -> EvalResult { use self::Expr::*; use self::Lit::*; - let evaled_args: Result, String> = args.into_iter().map(|arg| self.expression(arg)).collect(); + let evaled_args: Result, String> = args.into_iter().map(|arg| { + match self.expression(Node::Expr(arg)) { + Ok(Node::Expr(e)) => Ok(e), + Ok(Node::PrimObject { .. }) => Err(format!("Trying to apply a builtin to a primitive object")), + Err(e) => Err(e) + } + }).collect(); let evaled_args = evaled_args?; Ok(match (name.as_str(), evaled_args.as_slice()) { @@ -274,16 +309,16 @@ impl<'a> State<'a> { }) } - fn conditional(&mut self, cond: Expr, then_clause: Vec, else_clause: Vec) -> EvalResult { - let cond = self.expression(cond)?; + fn conditional(&mut self, cond: Expr, then_clause: Vec, else_clause: Vec) -> EvalResult { + let cond = self.expression(Node::Expr(cond))?; Ok(match cond { - Expr::Lit(Lit::Bool(true)) => self.block(then_clause)?, - Expr::Lit(Lit::Bool(false)) => self.block(else_clause)?, + Node::Expr(Expr::Lit(Lit::Bool(true))) => self.block(then_clause)?, + Node::Expr(Expr::Lit(Lit::Bool(false))) => self.block(else_clause)?, _ => return Err(format!("Conditional with non-boolean condition")) }) } - fn value(&mut self, name: Rc) -> EvalResult { + fn value(&mut self, name: Rc) -> EvalResult { use self::ValueEntry::*; use self::Func::*; //TODO add a layer of indirection here to talk to the symbol table first, and only then look up @@ -295,14 +330,14 @@ impl<'a> State<'a> { Some(Symbol { name, spec }) => match spec { SymbolSpec::DataConstructor { type_name, type_args, .. } => { if type_args.len() == 0 { - Expr::Lit(Lit::PrimObject { name: name.clone(), items: vec![] }) + Node::PrimObject { name: name.clone(), tag: 0, items: vec![] } } else { return Err(format!("This data constructor thing not done")) } }, SymbolSpec::Func(_) => match self.values.lookup(&name) { - Some(Binding { val: Expr::Func(UserDefined { name, params, body }), .. }) => { - Expr::Func(UserDefined { name: name.clone(), params: params.clone(), body: body.clone() }) + Some(Binding { val: Node::Expr(Expr::Func(UserDefined { name, params, body })), .. }) => { + Node::Expr(Expr::Func(UserDefined { name: name.clone(), params: params.clone(), body: body.clone() })) }, _ => unreachable!(), }, diff --git a/schala-lang/src/reduced_ast.rs b/schala-lang/src/reduced_ast.rs index d6dcf7b..6c322bd 100644 --- a/schala-lang/src/reduced_ast.rs +++ b/schala-lang/src/reduced_ast.rs @@ -69,10 +69,6 @@ pub enum Lit { Float(f64), Bool(bool), StringLit(Rc), - PrimObject { //TODO rethink placement in type heierarchy - name: Rc, - items: Vec, - } } #[derive(Debug, Clone)] @@ -156,7 +152,7 @@ fn reduce_if_expression(discriminator: &Discriminator, body: &IfExpressionBody, None => vec![], Some(stmts) => stmts.iter().map(|expr| expr.reduce(symbol_table)).collect(), }; - + let first_alt: Alternative = match pat { Pattern::TupleStruct(name, subpatterns) => { let symbol = symbol_table.values.get(name).unwrap();