mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-01 15:51:12 +00:00
Try moving to &Expr
This commit is contained in:
parent
064665c3b5
commit
f832827a66
2 changed files with 56 additions and 35 deletions
90
src/eval.rs
90
src/eval.rs
|
@ -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(())
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue