From f21e4ce82fff3273c2370e359ec1b948d406a150 Mon Sep 17 00:00:00 2001 From: Francois Brodeur Date: Sun, 14 Jul 2024 15:24:48 -0400 Subject: [PATCH] make eval consume --- ordo/Cargo.toml | 4 ++ ordo/benches/eval_benchmark.rs | 67 ++++++++++++++++++++++++++++++++++ ordo/src/env.rs | 2 +- ordo/src/eval.rs | 62 +++++++++++++++---------------- ordo/src/tests/ifs.rs | 4 +- ordo/src/tests/unwraps.rs | 8 ++-- 6 files changed, 109 insertions(+), 38 deletions(-) create mode 100644 ordo/benches/eval_benchmark.rs diff --git a/ordo/Cargo.toml b/ordo/Cargo.toml index 54d90df..88c12c9 100644 --- a/ordo/Cargo.toml +++ b/ordo/Cargo.toml @@ -17,3 +17,7 @@ criterion = "0.5.1" [[bench]] name = "infer_benchmark" harness = false + +[[bench]] +name = "eval_benchmark" +harness = false diff --git a/ordo/benches/eval_benchmark.rs b/ordo/benches/eval_benchmark.rs new file mode 100644 index 0000000..425b9a8 --- /dev/null +++ b/ordo/benches/eval_benchmark.rs @@ -0,0 +1,67 @@ +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use ordo::{eval, infer, parser::Parser}; + +pub fn eval_benchmark(c: &mut Criterion) { + let mut group = c.benchmark_group("eval"); + + let expr = "let a = 1 in a"; + group.bench_function(expr, |b| { + b.iter(|| { + let source = black_box(expr); + let parsed = Parser::expr(source).unwrap(); + let mut env = black_box(infer::Env::default()); + let typed = env.infer(parsed).unwrap(); + let mut env = black_box(eval::Env::default()); + let result = env.eval(typed).unwrap(); + black_box(result) + }) + }); + + let expr = "2 + 3 * 4"; + group.bench_function(expr, |b| { + b.iter(|| { + let source = black_box(expr); + let parsed = Parser::expr(source).unwrap(); + let mut env = black_box(infer::Env::default()); + let typed = env.infer(parsed).unwrap(); + black_box(typed) + }) + }); + + let expr = "let add(a, b) = a + b in add(2, 3)"; + group.bench_function(expr, |b| { + b.iter(|| { + let source = black_box(expr); + let parsed = Parser::expr(source).unwrap(); + let mut env = black_box(infer::Env::default()); + let typed = env.infer(parsed).unwrap(); + black_box(typed) + }) + }); + + let expr = "let add({a, b}) = a + b in let a = 2 in let b = 3 in add({a, b})"; + group.bench_function(expr, |b| { + b.iter(|| { + let source = black_box(expr); + let parsed = Parser::expr(source).unwrap(); + let mut env = black_box(infer::Env::default()); + let typed = env.infer(parsed).unwrap(); + black_box(typed) + }) + }); + + let expr = + "let safe_div(n, d) = if d == 0 then :div_by_zero {} else :ok (n / d) in safe_div(4, 2)"; + group.bench_function(expr, |b| { + b.iter(|| { + let source = black_box(expr); + let parsed = Parser::expr(source).unwrap(); + let mut env = black_box(infer::Env::default()); + let typed = env.infer(parsed).unwrap(); + black_box(typed) + }) + }); +} + +criterion_group!(benches, eval_benchmark); +criterion_main!(benches); diff --git a/ordo/src/env.rs b/ordo/src/env.rs index ff5860c..5b7f885 100644 --- a/ordo/src/env.rs +++ b/ordo/src/env.rs @@ -65,8 +65,8 @@ impl Env { pub fn process(&mut self, source: &str) -> Result { let expr = Parser::repl(source)?; let typed_expr = self.infer.infer(expr.clone())?; - let value = self.eval.eval(&expr)?; let ty = self.infer.ty_to_string(typed_expr.ty()).unwrap(); + let value = self.eval.eval(typed_expr)?; let val = value.to_string(); Ok(Output { ty, val }) } diff --git a/ordo/src/eval.rs b/ordo/src/eval.rs index d33f2d1..6c6aac3 100644 --- a/ordo/src/eval.rs +++ b/ordo/src/eval.rs @@ -3,7 +3,7 @@ use std::collections::BTreeMap; use itertools::Itertools; -use crate::expr::{Expr, ExprAt, IntBinOp, Pattern, PatternAt, OK_LABEL}; +use crate::expr::{Expr, ExprTypedAt, IntBinOp, Pattern, PatternTypedAt, OK_LABEL}; #[derive(Debug)] pub enum Error { @@ -17,8 +17,8 @@ pub enum Error { LabelNotFound(String), NoCase, UnwrapNotVariant(Value), - PatternRecordRestNotEmpty(ExprAt), - InvalidPattern(ExprAt), + PatternRecordRestNotEmpty(ExprTypedAt), + InvalidPattern(ExprTypedAt), } impl fmt::Display for Error { @@ -46,8 +46,8 @@ type Result = std::result::Result; #[derive(Clone, Debug, PartialEq)] pub struct Function { env: Env, - params: Vec, - body: ExprAt, + params: Vec, + body: ExprTypedAt, } impl fmt::Display for Function { @@ -62,11 +62,10 @@ impl Function { if self.params.len() != args.len() { return Err(Error::UnexpectedNumberOfArguments); } - for (i, arg) in args.into_iter().enumerate() { - let param = &self.params[i]; + for (arg, param) in args.into_iter().zip(self.params.clone().into_iter()) { self.env.eval_pattern(param, arg)?; } - self.env.eval_inner(&self.body) + self.env.eval_inner(self.body.clone()) } } @@ -108,37 +107,37 @@ impl Value { Value::Record(labels) } - fn as_bool(&self) -> Result { + fn as_bool(self) -> Result { match self { - Value::Bool(b) => Ok(*b), + Value::Bool(b) => Ok(b), _ => Err(Error::NotBool(self.clone())), } } - fn as_int(&self) -> Result { + fn as_int(self) -> Result { match self { - Value::Int(i) => Ok(*i), + Value::Int(i) => Ok(i), _ => Err(Error::NotInt(self.clone())), } } - fn as_function(&self) -> Result { + fn as_function(self) -> Result { match self { - Value::Function(fun) => Ok(fun.clone()), + Value::Function(fun) => Ok(fun), _ => Err(Error::NotFunction(self.clone())), } } - fn as_record(&self) -> Result<&BTreeMap> { + fn as_record(self) -> Result> { match self { Value::Record(record) => Ok(record), _ => Err(Error::NotRecord(self.clone())), } } - fn as_variant(&self) -> Result<(&String, &Value)> { + fn as_variant(self) -> Result<(String, Value)> { match self { - Value::Variant(label, value) => Ok((label, value)), + Value::Variant(label, value) => Ok((label, *value)), _ => Err(Error::NotVariant(self.clone())), } } @@ -164,13 +163,13 @@ pub struct Env { } impl Env { - pub fn eval(&mut self, expr: &ExprAt) -> Result { + pub fn eval(&mut self, expr: ExprTypedAt) -> Result { let wrap = self.eval_inner(expr)?; Ok(wrap.value()) } - fn eval_pattern(&mut self, pattern: &PatternAt, value: Value) -> Result<()> { - match pattern.expr.as_ref() { + fn eval_pattern(&mut self, pattern: PatternTypedAt, value: Value) -> Result<()> { + match *pattern.expr { Pattern::Var(var) => { self.vars.insert(var.clone(), value); } @@ -179,12 +178,12 @@ impl Env { Expr::RecordEmpty => (), _ => return Err(Error::PatternRecordRestNotEmpty(rest.clone())), } - let labels_value = match value { + let mut labels_value = match value { Value::Record(labels) => labels, _ => return Err(Error::NotRecord(value)), }; for (label, label_pattern) in labels { - match labels_value.get(label) { + match labels_value.remove(&label) { None => return Err(Error::LabelNotFound(label.clone())), Some(label_value) => { self.eval_pattern(label_pattern, label_value.clone())? @@ -197,10 +196,10 @@ impl Env { Ok(()) } - fn eval_inner(&mut self, expr: &ExprAt) -> Result { - match expr.expr.as_ref() { - Expr::Bool(b) => Ok(Wrap::Value(Value::Bool(*b))), - Expr::Int(i) => Ok(Wrap::Value(Value::Int(*i))), + fn eval_inner(&mut self, expr: ExprTypedAt) -> Result { + match *expr.expr { + Expr::Bool(b) => Ok(Wrap::Value(Value::Bool(b))), + Expr::Int(i) => Ok(Wrap::Value(Value::Int(i))), Expr::IntBinOp(op, lhs, rhs) => { let lhs = match self.eval_inner(lhs)? { Wrap::Value(value) => value.as_int()?, @@ -243,7 +242,7 @@ impl Env { Expr::Var(s) => { let value = self .vars - .get(s) + .get(&s) .ok_or_else(|| Error::VarNotFound(s.clone()))?; Ok(Wrap::Value(value.clone())) } @@ -284,7 +283,7 @@ impl Env { }; let record = record.as_record()?; let val = record - .get(label) + .get(&label) .ok_or_else(|| Error::LabelNotFound(label.clone()))?; Ok(Wrap::Value(val.clone())) } @@ -311,7 +310,7 @@ impl Env { }; let record = record.as_record()?; let mut record = record.clone(); - record.remove(label); + record.remove(&label); Ok(Wrap::Value(Value::Record(record))) } Expr::RecordEmpty => Ok(Wrap::Value(Value::Record(BTreeMap::new()))), @@ -381,7 +380,7 @@ impl Env { #[cfg(test)] mod tests { - use crate::parser::Parser; + use crate::{infer, parser::Parser}; use super::{Env, Value}; @@ -403,7 +402,8 @@ mod tests { ]; for (expr_str, expected) in cases { let expr = Parser::expr(expr_str).unwrap(); - let actual = Env::default().eval(&expr).unwrap(); + let expr = infer::Env::default().infer(expr).unwrap(); + let actual = Env::default().eval(expr).unwrap(); assert_eq!(expected, actual); } } diff --git a/ordo/src/tests/ifs.rs b/ordo/src/tests/ifs.rs index a1eed61..9964c0f 100644 --- a/ordo/src/tests/ifs.rs +++ b/ordo/src/tests/ifs.rs @@ -13,12 +13,12 @@ fn pass(source_expr: &str, source_ty: &str, expected_val: Value) { let expected = env.replace_ty_constants_with_vars(forall, ty); let expr = Parser::expr(source_expr).unwrap(); let typed_expr = env.infer(expr.clone()).unwrap(); - let actual = typed_expr.context.ty.ty; + let actual = typed_expr.context.ty.ty.clone(); let expected_ty = env.ty_to_string(&expected).unwrap(); let actual_ty = env.ty_to_string(&actual).unwrap(); assert_eq!(expected_ty, actual_ty); let mut env = eval::Env::default(); - let actual_val = env.eval(&expr).unwrap(); + let actual_val = env.eval(typed_expr).unwrap(); assert_eq!(expected_val, actual_val); } diff --git a/ordo/src/tests/unwraps.rs b/ordo/src/tests/unwraps.rs index 0eb23b9..13cbe8a 100644 --- a/ordo/src/tests/unwraps.rs +++ b/ordo/src/tests/unwraps.rs @@ -32,11 +32,11 @@ impl Env { let expected_ty = self.infer.replace_ty_constants_with_vars(forall, ty); let expr = Parser::repl(source).unwrap(); let typed_expr = self.infer.infer(expr.clone()).unwrap(); - let actual_ty = typed_expr.context.ty.ty; + let actual_ty = typed_expr.context.ty.ty.clone(); let expected_ty = self.infer.ty_to_string(&expected_ty).unwrap(); let actual_ty = self.infer.ty_to_string(&actual_ty).unwrap(); assert_eq!(expected_ty, actual_ty); - let _ = self.eval.eval(&expr).unwrap(); + let _ = self.eval.eval(typed_expr).unwrap(); } } @@ -47,11 +47,11 @@ fn pass(source: &str, source_ty: &str, expected_val: Value) { let expected_ty = env.infer.replace_ty_constants_with_vars(forall, ty); let expr = Parser::expr(source).unwrap(); let typed_expr = env.infer.infer(expr.clone()).unwrap(); - let actual_ty = typed_expr.context.ty.ty; + let actual_ty = typed_expr.context.ty.ty.clone(); let expected_ty = env.infer.ty_to_string(&expected_ty).unwrap(); let actual_ty = env.infer.ty_to_string(&actual_ty).unwrap(); assert_eq!(expected_ty, actual_ty); - let actual_val = env.eval.eval(&expr).unwrap(); + let actual_val = env.eval.eval(typed_expr).unwrap(); assert_eq!(expected_val, actual_val); }