|
|
@ -1,4 +1,4 @@
|
|
|
|
use std::{collections::HashMap, rc::Rc};
|
|
|
|
use std::{collections::HashMap, fmt::Debug, rc::Rc};
|
|
|
|
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
use crate::{
|
|
|
|
parse::Constant,
|
|
|
|
parse::Constant,
|
|
|
@ -55,32 +55,65 @@ pub trait Builtin {
|
|
|
|
fn apply(&self, rhs: DeBrujinBuiltInAst) -> Option<DeBrujinBuiltInAst>;
|
|
|
|
fn apply(&self, rhs: DeBrujinBuiltInAst) -> Option<DeBrujinBuiltInAst>;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl DeBrujinAst {
|
|
|
|
impl DeBrujinBuiltInAst {
|
|
|
|
pub fn reduce_builtins(self, builtins: &HashMap<String, Rc<dyn Builtin>>) -> DeBrujinAst {
|
|
|
|
pub(super) fn reduce(self) -> DeBrujinBuiltInAst {
|
|
|
|
self.resolve_builtins(builtins).reduce_builtins().into()
|
|
|
|
match self {
|
|
|
|
|
|
|
|
DeBrujinBuiltInAst::Application(lhs, rhs) => {
|
|
|
|
|
|
|
|
let lhs = if lhs.is_value() { *lhs } else { lhs.reduce() };
|
|
|
|
|
|
|
|
let rhs = if rhs.is_value() { *rhs } else { rhs.reduce() };
|
|
|
|
|
|
|
|
assert!(lhs.is_value() && rhs.is_value());
|
|
|
|
|
|
|
|
match lhs {
|
|
|
|
|
|
|
|
DeBrujinBuiltInAst::Abstraction(_, _, ast) => {
|
|
|
|
|
|
|
|
let ast = ast.subst_bound(1, rhs);
|
|
|
|
|
|
|
|
if ast.is_value() { ast } else { ast.reduce() }
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
DeBrujinBuiltInAst::Builtin(builtin) => match builtin.apply(rhs.clone()) {
|
|
|
|
|
|
|
|
Some(a) => {
|
|
|
|
|
|
|
|
if a.is_value() {
|
|
|
|
|
|
|
|
a
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
a.reduce()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
None => DeBrujinBuiltInAst::Application(
|
|
|
|
|
|
|
|
Box::new(DeBrujinBuiltInAst::Builtin(builtin)),
|
|
|
|
|
|
|
|
Box::new(rhs),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
a => unreachable!(
|
|
|
|
|
|
|
|
"We cannot get a variable or constant because of type checking and we cannot get a application because that is not a value, {:?}",
|
|
|
|
|
|
|
|
<DeBrujinBuiltInAst as Into<DeBrujinAst>>::into(a)
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
a => a,
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl DeBrujinBuiltInAst {
|
|
|
|
fn subst_bound(self, depth: usize, subst: DeBrujinBuiltInAst) -> DeBrujinBuiltInAst {
|
|
|
|
fn reduce_builtins(self) -> DeBrujinBuiltInAst {
|
|
|
|
|
|
|
|
match self {
|
|
|
|
match self {
|
|
|
|
DeBrujinBuiltInAst::Abstraction(i, t, ast) => {
|
|
|
|
DeBrujinBuiltInAst::Abstraction(i, t, ast) => {
|
|
|
|
DeBrujinBuiltInAst::Abstraction(i, t, Box::new(ast.reduce_builtins()))
|
|
|
|
DeBrujinBuiltInAst::Abstraction(i, t, Box::new(ast.subst_bound(depth + 1, subst)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DeBrujinBuiltInAst::Application(lhs, rhs) => match *lhs {
|
|
|
|
DeBrujinBuiltInAst::Application(lhs, rhs) => DeBrujinBuiltInAst::Application(
|
|
|
|
DeBrujinBuiltInAst::Builtin(builtin) => builtin
|
|
|
|
Box::new(lhs.subst_bound(depth, subst.clone())),
|
|
|
|
.apply(*rhs)
|
|
|
|
Box::new(rhs.subst_bound(depth, subst)),
|
|
|
|
.expect("the type checker should make sure we can apply")
|
|
|
|
),
|
|
|
|
.reduce_builtins(),
|
|
|
|
DeBrujinBuiltInAst::BoundVariable(n) if n == depth => subst,
|
|
|
|
lhs => DeBrujinBuiltInAst::Application(
|
|
|
|
|
|
|
|
Box::new(lhs.reduce_builtins()),
|
|
|
|
|
|
|
|
Box::new(rhs.reduce_builtins()),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.reduce_builtins(),
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
a => a,
|
|
|
|
a => a,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn is_value(&self) -> bool {
|
|
|
|
|
|
|
|
match self {
|
|
|
|
|
|
|
|
DeBrujinBuiltInAst::Abstraction(_, _, _) => true,
|
|
|
|
|
|
|
|
DeBrujinBuiltInAst::Application(_, _) => false,
|
|
|
|
|
|
|
|
DeBrujinBuiltInAst::FreeVariable(_) => true,
|
|
|
|
|
|
|
|
DeBrujinBuiltInAst::BoundVariable(_) => true,
|
|
|
|
|
|
|
|
DeBrujinBuiltInAst::Constant(constant) => true,
|
|
|
|
|
|
|
|
DeBrujinBuiltInAst::Builtin(builtin) => true,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl From<DeBrujinBuiltInAst> for DeBrujinAst {
|
|
|
|
impl From<DeBrujinBuiltInAst> for DeBrujinAst {
|
|
|
@ -95,7 +128,7 @@ impl From<DeBrujinBuiltInAst> for DeBrujinAst {
|
|
|
|
DeBrujinBuiltInAst::FreeVariable(x) => DeBrujinAst::FreeVariable(x),
|
|
|
|
DeBrujinBuiltInAst::FreeVariable(x) => DeBrujinAst::FreeVariable(x),
|
|
|
|
DeBrujinBuiltInAst::BoundVariable(i) => DeBrujinAst::BoundVariable(i),
|
|
|
|
DeBrujinBuiltInAst::BoundVariable(i) => DeBrujinAst::BoundVariable(i),
|
|
|
|
DeBrujinBuiltInAst::Constant(constant) => DeBrujinAst::Constant(constant),
|
|
|
|
DeBrujinBuiltInAst::Constant(constant) => DeBrujinAst::Constant(constant),
|
|
|
|
DeBrujinBuiltInAst::Builtin(builtin) => DeBrujinAst::FreeVariable(builtin.name()),
|
|
|
|
DeBrujinBuiltInAst::Builtin(builtin) => builtin.to_ast(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|