mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 15:21:12 +00:00
Fix some of eval
This commit is contained in:
parent
5868f64fb2
commit
d71b646f6a
1 changed files with 48 additions and 40 deletions
88
src/eval.rs
88
src/eval.rs
|
@ -1,17 +1,17 @@
|
||||||
use expr::{Expr, Pattern, Ident};
|
use expr::{Expr, Ident, Pattern, VariantName};
|
||||||
use expr::Pattern::*;
|
use expr::Pattern::*;
|
||||||
use expr;
|
use expr;
|
||||||
use operator::Operator::*;
|
use operator::Operator::*;
|
||||||
use operator::Operator;
|
use operator::Operator;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use im_rc::hashmap::HashMap;
|
use collections::ImMap;
|
||||||
use self::Problem::*;
|
use self::Problem::*;
|
||||||
use fraction::Fraction;
|
use fraction::Fraction;
|
||||||
use region::{Located, Region};
|
use region::{Located, Region};
|
||||||
|
|
||||||
pub fn eval(expr: Located<Expr>) -> Evaluated {
|
pub fn eval(expr: Located<Expr>) -> Evaluated {
|
||||||
scoped_eval(prepare_for_eval(expr), &HashMap::new())
|
scoped_eval(prepare_for_eval(expr), &ImMap::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_for_eval(expr: Located<Expr>) -> Located<Expr> {
|
fn prepare_for_eval(expr: Located<Expr>) -> Located<Expr> {
|
||||||
|
@ -31,7 +31,7 @@ pub enum Evaluated {
|
||||||
Closure(Vec<Pattern>, Box<Located<Expr>>, Scope),
|
Closure(Vec<Pattern>, Box<Located<Expr>>, Scope),
|
||||||
|
|
||||||
// Sum Types
|
// Sum Types
|
||||||
ApplyVariant(String, Option<Vec<Evaluated>>),
|
ApplyVariant(VariantName, Option<Vec<Evaluated>>),
|
||||||
|
|
||||||
// Product Types
|
// Product Types
|
||||||
EmptyRecord,
|
EmptyRecord,
|
||||||
|
@ -50,7 +50,7 @@ pub enum Problem {
|
||||||
NoBranchesMatched,
|
NoBranchesMatched,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Scope = HashMap<String, Rc<Evaluated>>;
|
type Scope = ImMap<String, Rc<Evaluated>>;
|
||||||
|
|
||||||
pub fn scoped_eval(expr: Located<Expr>, vars: &Scope) -> Evaluated {
|
pub fn scoped_eval(expr: Located<Expr>, vars: &Scope) -> Evaluated {
|
||||||
use self::Evaluated::*;
|
use self::Evaluated::*;
|
||||||
|
@ -68,16 +68,22 @@ pub fn scoped_eval(expr: Located<Expr>, vars: &Scope) -> Evaluated {
|
||||||
Expr::EmptyRecord => EmptyRecord,
|
Expr::EmptyRecord => EmptyRecord,
|
||||||
|
|
||||||
// Resolve variable names
|
// Resolve variable names
|
||||||
Expr::Var(name) => match vars.get(&name) {
|
Expr::Var(ident) => {
|
||||||
Some(resolved) => (**resolved).clone(),
|
let ident_name = ident.name();
|
||||||
None => EvalError(region, UnrecognizedVarName(name))
|
|
||||||
},
|
match vars.get(&ident_name) {
|
||||||
|
Some(resolved) => (**resolved).clone(),
|
||||||
|
None => EvalError(region, UnrecognizedVarName(ident_name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Expr::InterpolatedStr(pairs, trailing_str) => {
|
Expr::InterpolatedStr(pairs, trailing_str) => {
|
||||||
let mut output = String::new();
|
let mut output = String::new();
|
||||||
|
|
||||||
for (string, var_name) in pairs.into_iter() {
|
for (string, loc_ident) in pairs.into_iter() {
|
||||||
match vars.get(&var_name.value) {
|
let ident_name = loc_ident.value.name();
|
||||||
|
|
||||||
|
match vars.get(&ident_name) {
|
||||||
Some(resolved) => {
|
Some(resolved) => {
|
||||||
match **resolved {
|
match **resolved {
|
||||||
Str(ref var_string) => {
|
Str(ref var_string) => {
|
||||||
|
@ -85,11 +91,11 @@ pub fn scoped_eval(expr: Located<Expr>, vars: &Scope) -> Evaluated {
|
||||||
output.push_str(var_string.as_str());
|
output.push_str(var_string.as_str());
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
return EvalError(region, TypeMismatch(var_name.value));
|
return EvalError(region, TypeMismatch(ident_name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => { return EvalError(region, UnrecognizedVarName(var_name.value)); }
|
None => { return EvalError(region, UnrecognizedVarName(ident_name)); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,10 +108,12 @@ pub fn scoped_eval(expr: Located<Expr>, vars: &Scope) -> Evaluated {
|
||||||
eval_assign(located_pattern, *assigned_expr, *returned_expr, vars)
|
eval_assign(located_pattern, *assigned_expr, *returned_expr, vars)
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::CallByName(name, args) => {
|
Expr::CallByName(ident, args) => {
|
||||||
let func_expr = match vars.get(&name) {
|
let ident_name = ident.name();
|
||||||
|
|
||||||
|
let func_expr = match vars.get(&ident_name) {
|
||||||
Some(resolved) => (**resolved).clone(),
|
Some(resolved) => (**resolved).clone(),
|
||||||
None => EvalError(region, UnrecognizedVarName(name))
|
None => EvalError(region, UnrecognizedVarName(ident_name))
|
||||||
};
|
};
|
||||||
|
|
||||||
eval_apply(region, func_expr, args, vars)
|
eval_apply(region, func_expr, args, vars)
|
||||||
|
@ -140,7 +148,7 @@ pub fn scoped_eval(expr: Located<Expr>, vars: &Scope) -> Evaluated {
|
||||||
Expr::If(condition, if_true, if_false) => {
|
Expr::If(condition, if_true, if_false) => {
|
||||||
match scoped_eval(*condition, vars) {
|
match scoped_eval(*condition, vars) {
|
||||||
ApplyVariant(variant_name, None) => {
|
ApplyVariant(variant_name, None) => {
|
||||||
match variant_name.as_str() {
|
match variant_name.name().as_str() {
|
||||||
"True" => scoped_eval(*if_true, vars),
|
"True" => scoped_eval(*if_true, vars),
|
||||||
"False" => scoped_eval(*if_false, vars),
|
"False" => scoped_eval(*if_false, vars),
|
||||||
_ => EvalError(region, TypeMismatch("non-Bool used in `if` condition".to_string()))
|
_ => EvalError(region, TypeMismatch("non-Bool used in `if` condition".to_string()))
|
||||||
|
@ -158,15 +166,17 @@ fn eval_assign(pattern: Located<Pattern>, assigned_expr: Located<Expr>, returned
|
||||||
let pattern_region = pattern.region;
|
let pattern_region = pattern.region;
|
||||||
|
|
||||||
match pattern.value {
|
match pattern.value {
|
||||||
Identifier(name) => {
|
Identifier(ident) => {
|
||||||
if vars.contains_key(&name) {
|
let ident_name = ident.name();
|
||||||
EvalError(pattern_region, ReassignedVarName(name))
|
|
||||||
|
if vars.contains_key(&ident_name) {
|
||||||
|
EvalError(pattern_region, ReassignedVarName(ident_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();
|
||||||
let evaluated_defn = scoped_eval(assigned_expr, vars);
|
let evaluated_defn = scoped_eval(assigned_expr, vars);
|
||||||
|
|
||||||
new_vars.insert(name, Rc::new(evaluated_defn));
|
new_vars.insert(ident_name, Rc::new(evaluated_defn));
|
||||||
|
|
||||||
// Evaluate in_expr with that new scope's variables.
|
// Evaluate in_expr with that new scope's variables.
|
||||||
scoped_eval(returned_expr, &new_vars)
|
scoped_eval(returned_expr, &new_vars)
|
||||||
|
@ -243,9 +253,9 @@ fn eval_closure(args: Vec<Evaluated>, arg_patterns: Vec<Pattern>, vars: &Scope)
|
||||||
|
|
||||||
fn bool_variant(is_true: bool) -> Evaluated {
|
fn bool_variant(is_true: bool) -> Evaluated {
|
||||||
if is_true {
|
if is_true {
|
||||||
Evaluated::ApplyVariant("True".to_string(), None)
|
Evaluated::ApplyVariant(VariantName::Unqualified("True".to_string()), None)
|
||||||
} else {
|
} else {
|
||||||
Evaluated::ApplyVariant("False".to_string(), None)
|
Evaluated::ApplyVariant(VariantName::Unqualified("False".to_string()), None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,13 +291,11 @@ fn eq(region: Region, evaluated1: &Evaluated, evaluated2: &Evaluated) -> Evaluat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bool_from_variant_name(name: &str) -> Option<bool> {
|
fn bool_from_variant_name(name: &VariantName) -> Option<bool> {
|
||||||
if name == "True" {
|
match name.clone().name().as_str() {
|
||||||
Some(true)
|
"True" => Some(true),
|
||||||
} else if name == "False" {
|
"False" => Some(false),
|
||||||
Some(false)
|
_ => None
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,7 +397,7 @@ fn eval_operator(region: Region, left_expr: &Evaluated, op: Operator, right_expr
|
||||||
if answer.is_finite() {
|
if answer.is_finite() {
|
||||||
ok_variant(Frac(answer))
|
ok_variant(Frac(answer))
|
||||||
} else {
|
} else {
|
||||||
err_variant(ApplyVariant("DivisionByZero".to_string(), None))
|
err_variant(ApplyVariant(VariantName::Unqualified("DivisionByZero".to_string()), None))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -417,7 +425,7 @@ fn eval_operator(region: Region, left_expr: &Evaluated, op: Operator, right_expr
|
||||||
if answer.is_finite() {
|
if answer.is_finite() {
|
||||||
ok_variant(Approx(answer))
|
ok_variant(Approx(answer))
|
||||||
} else {
|
} else {
|
||||||
err_variant(ApplyVariant("DivisionByZero".to_string(), None))
|
err_variant(ApplyVariant(VariantName::Unqualified("DivisionByZero".to_string()), None))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -439,7 +447,7 @@ fn eval_operator(region: Region, left_expr: &Evaluated, op: Operator, right_expr
|
||||||
if answer.is_finite() {
|
if answer.is_finite() {
|
||||||
ok_variant(Frac(answer))
|
ok_variant(Frac(answer))
|
||||||
} else {
|
} else {
|
||||||
err_variant(ApplyVariant("DivisionByZero".to_string(), None))
|
err_variant(ApplyVariant(VariantName::Unqualified("DivisionByZero".to_string()), None))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -455,14 +463,14 @@ fn eval_operator(region: Region, left_expr: &Evaluated, op: Operator, right_expr
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn eval_case(region: Region, evaluated: Evaluated, branches: Vec<(Located<Pattern>, Box<Located<Expr>>)>, vars: &Scope) -> Evaluated {
|
fn eval_case(region: Region, evaluated: Evaluated, branches: Vec<(Located<Pattern>, Located<Expr>)>, vars: &Scope) -> Evaluated {
|
||||||
use self::Evaluated::*;
|
use self::Evaluated::*;
|
||||||
|
|
||||||
for (pattern, definition) in branches {
|
for (pattern, definition) in branches {
|
||||||
let mut branch_vars = vars.clone();
|
let mut branch_vars = vars.clone();
|
||||||
|
|
||||||
if pattern_match(&evaluated, &pattern.value, &mut branch_vars).is_ok() {
|
if pattern_match(&evaluated, &pattern.value, &mut branch_vars).is_ok() {
|
||||||
return scoped_eval(*definition, &branch_vars);
|
return scoped_eval(definition, &branch_vars);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,7 +482,7 @@ fn pattern_match(evaluated: &Evaluated, pattern: &Pattern, vars: &mut Scope) ->
|
||||||
|
|
||||||
match pattern {
|
match pattern {
|
||||||
Identifier(name) => {
|
Identifier(name) => {
|
||||||
vars.insert(name.clone(), Rc::new(evaluated.clone()));
|
vars.insert(name.clone().name(), Rc::new(evaluated.clone()));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
|
@ -611,7 +619,7 @@ impl fmt::Display for Evaluated {
|
||||||
Closure(args, _, _) => write!(f, "<{}-argument function>", args.len()),
|
Closure(args, _, _) => write!(f, "<{}-argument function>", args.len()),
|
||||||
ApplyVariant(name, opt_exprs) => {
|
ApplyVariant(name, opt_exprs) => {
|
||||||
match opt_exprs {
|
match opt_exprs {
|
||||||
None => write!(f, "{}", name),
|
None => write!(f, "{}", name.clone().name()),
|
||||||
Some(exprs) => {
|
Some(exprs) => {
|
||||||
let contents =
|
let contents =
|
||||||
exprs.into_iter()
|
exprs.into_iter()
|
||||||
|
@ -619,7 +627,7 @@ impl fmt::Display for Evaluated {
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(",");
|
.join(",");
|
||||||
|
|
||||||
write!(f, "{}{}", name, contents)
|
write!(f, "{}{}", name.clone().name(), contents)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -653,11 +661,11 @@ impl fmt::Display for Problem {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ok_variant(contents: Evaluated) -> Evaluated{
|
fn ok_variant(contents: Evaluated) -> Evaluated{
|
||||||
Evaluated::ApplyVariant("Ok".to_string(), Some(vec![contents]))
|
Evaluated::ApplyVariant(VariantName::Unqualified("Ok".to_string()), Some(vec![contents]))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn err_variant(contents: Evaluated) -> Evaluated {
|
fn err_variant(contents: Evaluated) -> Evaluated {
|
||||||
Evaluated::ApplyVariant("Err".to_string(), Some(vec![contents]))
|
Evaluated::ApplyVariant(VariantName::Unqualified("Err".to_string()), Some(vec![contents]))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fraction_from_i64s(numerator: i64, denominator: i64) -> Fraction {
|
fn fraction_from_i64s(numerator: i64, denominator: i64) -> Fraction {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue