Try moving to &Expr

This commit is contained in:
Richard Feldman 2019-05-29 14:20:26 -04:00
parent 064665c3b5
commit f832827a66
2 changed files with 56 additions and 35 deletions

View file

@ -7,31 +7,31 @@ use expr::Operator::*;
use std::rc::Rc; use std::rc::Rc;
use im_rc::hashmap::HashMap; use im_rc::hashmap::HashMap;
pub fn eval(expr: Expr) -> Expr { pub fn eval(expr: &Expr) -> Expr {
scoped_eval(expr, &HashMap::new()) scoped_eval(expr, &HashMap::new())
} }
pub fn scoped_eval(expr: Expr, vars: &HashMap<String, Rc<Expr>>) -> Expr { pub fn scoped_eval(expr: &Expr, vars: &HashMap<String, Rc<Expr>>) -> Expr {
match expr { match expr {
// Primitives need no further evaluation // Primitives need no further evaluation
Error(_) | Int(_) | Str(_) | Frac(_, _) | Char(_) | Bool(_) | Closure(_, _) => expr, Error(_) | Int(_) | Str(_) | Frac(_, _) | Char(_) | Bool(_) | Closure(_, _) => *expr,
// Resolve variable names // Resolve variable names
Var(name) => match vars.get(&name) { Var(name) => match vars.get(name) {
Some(resolved) => (*Rc::clone(resolved)).clone(), Some(resolved) => (*Rc::clone(resolved)).clone(),
None => Error(UnrecognizedVarName(name)) None => Error(UnrecognizedVarName(*name))
} }
Let(Identifier(name), definition, in_expr) => { Let(Identifier(name), definition, in_expr) => {
if vars.contains_key(&name) { if vars.contains_key(name) {
Error(ReassignedVarName(name)) Error(ReassignedVarName(*name))
} else { } else {
// Create a new scope containing the new declaration. // Create a new scope containing the new declaration.
let mut new_vars = (*vars).clone(); let mut new_vars = (*vars).clone();
new_vars.insert(name, Rc::new(scoped_eval(*definition, vars))); new_vars.insert(*name, Rc::new(scoped_eval(definition, vars)));
// Evaluate in_expr with that new scope's variables. // Evaluate in_expr with that new scope's variables.
scoped_eval(*in_expr, &new_vars) scoped_eval(in_expr, &new_vars)
} }
}, },
@ -41,22 +41,22 @@ pub fn scoped_eval(expr: Expr, vars: &HashMap<String, Rc<Expr>>) -> Expr {
Let(Underscore, definition, in_expr) => { Let(Underscore, definition, in_expr) => {
// Faithfully eval this, but discard its result. // Faithfully eval this, but discard its result.
scoped_eval(*definition, vars); scoped_eval(definition, vars);
// Actually use this part. // Actually use this part.
scoped_eval(*in_expr, vars) scoped_eval(in_expr, vars)
}, },
Func(name, args) => { Func(name, args) => {
let func_expr = match vars.get(&name) { let func_expr = match vars.get(name) {
Some(resolved) => (*Rc::clone(resolved)).clone(), Some(resolved) => (*Rc::clone(resolved)).clone(),
None => Error(UnrecognizedVarName(name)) None => Error(UnrecognizedVarName(*name))
}; };
scoped_eval(Apply(Box::new(func_expr), args), vars) eval_apply(func_expr, *args, vars)
}, },
ApplyVariant(_, None) => expr, // This is all we do - for now... ApplyVariant(_, None) => *expr, // This is all we do - for now...
ApplyVariant(name, Some(args)) => { ApplyVariant(name, Some(args)) => {
let mut evaluated_args = Vec::with_capacity(args.len()); let mut evaluated_args = Vec::with_capacity(args.len());
@ -65,45 +65,51 @@ pub fn scoped_eval(expr: Expr, vars: &HashMap<String, Rc<Expr>>) -> Expr {
evaluated_args.push(scoped_eval(arg, vars)) evaluated_args.push(scoped_eval(arg, vars))
} }
ApplyVariant(name, Some(evaluated_args)) ApplyVariant(*name, Some(evaluated_args))
} }
Apply(func_expr, args) => { Apply(func_expr, args) => {
match *func_expr.clone() { eval_apply(**func_expr, *args, vars)
Closure(arg_patterns, body) => {
match eval_closure(args, arg_patterns, vars) {
Ok(new_vars) => scoped_eval(*body, &new_vars),
Err(problem) => Error(problem)
}
},
_ => Error(TypeMismatch("Tried to call a non-function.".to_string()))
}
}, },
Operator(left_arg, op, right_arg) => { Operator(left_arg, op, right_arg) => {
eval_operator( eval_operator(
&scoped_eval(*left_arg, vars), &scoped_eval(left_arg, vars),
&op, &op,
&scoped_eval(*right_arg, vars) &scoped_eval(right_arg, vars)
) )
}, },
Match(condition, branches) => { Match(condition, branches) => {
match scoped_eval(*condition, vars) { match scoped_eval(condition, vars) {
_ => { panic!("TODO implement eval for match-expressions"); } _ => { panic!("TODO implement eval for match-expressions"); }
} }
}, },
If(condition, if_true, if_false) => { If(condition, if_true, if_false) => {
match scoped_eval(*condition, vars) { match scoped_eval(condition, vars) {
Bool(true) => scoped_eval(*if_true, vars), Bool(true) => scoped_eval(if_true, vars),
Bool(false) => scoped_eval(*if_false, vars), Bool(false) => scoped_eval(if_false, vars),
_ => Error(TypeMismatch("non-Bool used in `if` condition".to_string())) _ => Error(TypeMismatch("non-Bool used in `if` condition".to_string()))
} }
} }
} }
} }
#[inline(always)]
fn eval_apply(expr: Expr, args: Vec<Expr>, vars: &HashMap<String, Rc<Expr>>) -> Expr {
match expr {
Closure(arg_patterns, body) => {
match eval_closure(args, arg_patterns, vars) {
Ok(new_vars) => scoped_eval(&*body, &new_vars),
Err(problem) => Error(problem)
}
},
_ => Error(TypeMismatch("Tried to call a non-function.".to_string()))
}
}
#[inline(always)]
fn eval_closure(args: Vec<Expr>, arg_patterns: Vec<Pattern>, vars: &HashMap<String, Rc<Expr>>) fn eval_closure(args: Vec<Expr>, arg_patterns: Vec<Pattern>, vars: &HashMap<String, Rc<Expr>>)
-> Result<HashMap<String, Rc<Expr>>, expr::Problem> -> Result<HashMap<String, Rc<Expr>>, expr::Problem>
{ {
@ -112,7 +118,7 @@ fn eval_closure(args: Vec<Expr>, arg_patterns: Vec<Pattern>, vars: &HashMap<Stri
let mut new_vars = (*vars).clone(); let mut new_vars = (*vars).clone();
for ( arg, pattern ) in args.into_iter().zip(arg_patterns) { for ( arg, pattern ) in args.into_iter().zip(arg_patterns) {
pattern_match(arg, pattern, &mut new_vars)?; pattern_match(&arg, pattern, &mut new_vars)?;
} }
Ok(new_vars) Ok(new_vars)
@ -121,6 +127,7 @@ fn eval_closure(args: Vec<Expr>, arg_patterns: Vec<Pattern>, vars: &HashMap<Stri
} }
} }
#[inline(always)]
fn eval_operator(left_expr: &Expr, op: &Operator, right_expr: &Expr) -> Expr { fn eval_operator(left_expr: &Expr, op: &Operator, right_expr: &Expr) -> Expr {
match (left_expr, op, right_expr) { match (left_expr, op, right_expr) {
// Error // Error
@ -192,7 +199,20 @@ fn eval_operator(left_expr: &Expr, op: &Operator, right_expr: &Expr) -> Expr {
} }
} }
fn pattern_match(expr: Expr, pattern: Pattern, vars: &mut HashMap<String, Rc<Expr>>) -> Result<(), expr::Problem> { #[inline(always)]
fn eval_match(condition: &Expr, branches: Vec<(Pattern, Box<Expr>)>, vars: HashMap<String, Rc<Expr>>) -> Expr {
for (pattern, expr) in branches {
let mut branch_vars = vars.clone();
if pattern_match(&condition, pattern, &mut branch_vars).is_ok() {
return scoped_eval(&*expr, &branch_vars);
}
}
Error(NoBranchesMatched)
}
fn pattern_match(expr: &Expr, pattern: Pattern, vars: &mut HashMap<String, Rc<Expr>>) -> Result<(), expr::Problem> {
match pattern { match pattern {
Identifier(name) => { Identifier(name) => {
let new_val = scoped_eval(expr, vars); let new_val = scoped_eval(expr, vars);
@ -206,7 +226,7 @@ fn pattern_match(expr: Expr, pattern: Pattern, vars: &mut HashMap<String, Rc<Exp
Ok(()) Ok(())
}, },
Variant(expected_variant_name, opt_contents) => { Variant(expected_variant_name, opt_contents) => {
match expr { match *expr {
ApplyVariant(variant_name, opt_expected_patterns) => { ApplyVariant(variant_name, opt_expected_patterns) => {
if expected_variant_name != variant_name { if expected_variant_name != variant_name {
return Err(TypeMismatch(format!("Wanted a `{}` variant, but was given a `{}` variant.", expected_variant_name, variant_name))); return Err(TypeMismatch(format!("Wanted a `{}` variant, but was given a `{}` variant.", expected_variant_name, variant_name)));
@ -217,7 +237,7 @@ fn pattern_match(expr: Expr, pattern: Pattern, vars: &mut HashMap<String, Rc<Exp
if contents.len() == patterns.len() { if contents.len() == patterns.len() {
// Recursively pattern match // Recursively pattern match
for ( arg, pattern ) in contents.into_iter().zip(patterns) { for ( arg, pattern ) in contents.into_iter().zip(patterns) {
pattern_match(arg, pattern, vars)?; pattern_match(&arg, pattern, vars)?;
} }
Ok(()) Ok(())

View file

@ -82,6 +82,7 @@ pub enum Problem {
TypeMismatch(String), TypeMismatch(String),
ReassignedVarName(String), ReassignedVarName(String),
WrongArity(u32 /* Expected */, u32 /* Provided */), WrongArity(u32 /* Expected */, u32 /* Provided */),
NoBranchesMatched,
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]