Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make eval consume #43

Merged
merged 1 commit into from
Jul 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions ordo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ criterion = "0.5.1"
[[bench]]
name = "infer_benchmark"
harness = false

[[bench]]
name = "eval_benchmark"
harness = false
67 changes: 67 additions & 0 deletions ordo/benches/eval_benchmark.rs
Original file line number Diff line number Diff line change
@@ -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);
2 changes: 1 addition & 1 deletion ordo/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ impl Env {
pub fn process(&mut self, source: &str) -> Result<Output> {
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 })
}
Expand Down
62 changes: 31 additions & 31 deletions ordo/src/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down Expand Up @@ -46,8 +46,8 @@ type Result<T, E = Error> = std::result::Result<T, E>;
#[derive(Clone, Debug, PartialEq)]
pub struct Function {
env: Env,
params: Vec<PatternAt>,
body: ExprAt,
params: Vec<PatternTypedAt>,
body: ExprTypedAt,
}

impl fmt::Display for Function {
Expand All @@ -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())
}
}

Expand Down Expand Up @@ -108,37 +107,37 @@ impl Value {
Value::Record(labels)
}

fn as_bool(&self) -> Result<bool> {
fn as_bool(self) -> Result<bool> {
match self {
Value::Bool(b) => Ok(*b),
Value::Bool(b) => Ok(b),
_ => Err(Error::NotBool(self.clone())),
}
}

fn as_int(&self) -> Result<i64> {
fn as_int(self) -> Result<i64> {
match self {
Value::Int(i) => Ok(*i),
Value::Int(i) => Ok(i),
_ => Err(Error::NotInt(self.clone())),
}
}

fn as_function(&self) -> Result<Function> {
fn as_function(self) -> Result<Function> {
match self {
Value::Function(fun) => Ok(fun.clone()),
Value::Function(fun) => Ok(fun),
_ => Err(Error::NotFunction(self.clone())),
}
}

fn as_record(&self) -> Result<&BTreeMap<String, Value>> {
fn as_record(self) -> Result<BTreeMap<String, Value>> {
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())),
}
}
Expand All @@ -164,13 +163,13 @@ pub struct Env {
}

impl Env {
pub fn eval(&mut self, expr: &ExprAt) -> Result<Value> {
pub fn eval(&mut self, expr: ExprTypedAt) -> Result<Value> {
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);
}
Expand All @@ -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())?
Expand All @@ -197,10 +196,10 @@ impl Env {
Ok(())
}

fn eval_inner(&mut self, expr: &ExprAt) -> Result<Wrap> {
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<Wrap> {
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()?,
Expand Down Expand Up @@ -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()))
}
Expand Down Expand Up @@ -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()))
}
Expand All @@ -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()))),
Expand Down Expand Up @@ -381,7 +380,7 @@ impl Env {

#[cfg(test)]
mod tests {
use crate::parser::Parser;
use crate::{infer, parser::Parser};

use super::{Env, Value};

Expand All @@ -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);
}
}
Expand Down
4 changes: 2 additions & 2 deletions ordo/src/tests/ifs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
8 changes: 4 additions & 4 deletions ordo/src/tests/unwraps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}

Expand All @@ -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);
}

Expand Down
Loading