You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
102 lines
3.5 KiB
102 lines
3.5 KiB
use std::{collections::HashMap, rc::Rc, usize};
|
|
|
|
use crate::{
|
|
parse::Constant,
|
|
types::{Ident, PrimitiveType, TaggedType, Type, TypeTag},
|
|
};
|
|
|
|
use super::DeBrujinAst;
|
|
|
|
#[derive(Clone)]
|
|
pub enum DeBrujinBuiltInAst {
|
|
Abstraction(Ident, Type, Box<DeBrujinBuiltInAst>), // \:1.2
|
|
Application(Box<DeBrujinBuiltInAst>, Box<DeBrujinBuiltInAst>), // 0 1
|
|
FreeVariable(String), // x
|
|
BoundVariable(usize), // 1
|
|
Constant(Constant), // true | false | n
|
|
Builtin(Rc<dyn Builtin>),
|
|
}
|
|
|
|
impl DeBrujinAst {
|
|
pub fn resolve_builtins(
|
|
self,
|
|
builtins: &HashMap<String, Rc<dyn Builtin>>,
|
|
) -> DeBrujinBuiltInAst {
|
|
match self {
|
|
DeBrujinAst::Abstraction(i, t, ast) => {
|
|
DeBrujinBuiltInAst::Abstraction(i, t, Box::new(ast.resolve_builtins(builtins)))
|
|
}
|
|
DeBrujinAst::Application(lhs, rhs) => DeBrujinBuiltInAst::Application(
|
|
Box::new(lhs.resolve_builtins(builtins)),
|
|
Box::new(rhs.resolve_builtins(builtins)),
|
|
),
|
|
DeBrujinAst::FreeVariable(x) => {
|
|
if let Some(b) = builtins.get(&x) {
|
|
DeBrujinBuiltInAst::Builtin(b.clone())
|
|
} else {
|
|
DeBrujinBuiltInAst::FreeVariable(x)
|
|
}
|
|
}
|
|
DeBrujinAst::BoundVariable(b) => DeBrujinBuiltInAst::BoundVariable(b),
|
|
DeBrujinAst::Constant(c) => DeBrujinBuiltInAst::Constant(c),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub trait Builtin {
|
|
fn name(&self) -> String;
|
|
|
|
fn to_ast(&self) -> DeBrujinAst {
|
|
DeBrujinAst::FreeVariable(self.name())
|
|
}
|
|
|
|
fn r#type(&self) -> TaggedType;
|
|
|
|
fn apply(&self, rhs: DeBrujinBuiltInAst) -> Option<DeBrujinBuiltInAst>;
|
|
}
|
|
|
|
impl DeBrujinAst {
|
|
pub fn reduce_builtins(self, builtins: &HashMap<String, Rc<dyn Builtin>>) -> DeBrujinAst {
|
|
self.resolve_builtins(builtins).reduce_builtins().into()
|
|
}
|
|
}
|
|
|
|
impl DeBrujinBuiltInAst {
|
|
fn reduce_builtins(self) -> DeBrujinBuiltInAst {
|
|
match self {
|
|
DeBrujinBuiltInAst::Abstraction(i, t, ast) => {
|
|
DeBrujinBuiltInAst::Abstraction(i, t, Box::new(ast.reduce_builtins()))
|
|
}
|
|
DeBrujinBuiltInAst::Application(lhs, rhs) => match *lhs {
|
|
DeBrujinBuiltInAst::Builtin(builtin) => builtin
|
|
.apply(*rhs)
|
|
.expect("the type checker should make sure we can apply")
|
|
.reduce_builtins(),
|
|
lhs => DeBrujinBuiltInAst::Application(
|
|
Box::new(lhs.reduce_builtins()),
|
|
Box::new(rhs.reduce_builtins()),
|
|
)
|
|
.reduce_builtins(),
|
|
},
|
|
a => a,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Into<DeBrujinAst> for DeBrujinBuiltInAst {
|
|
fn into(self) -> DeBrujinAst {
|
|
match self {
|
|
DeBrujinBuiltInAst::Abstraction(i, t, ast) => {
|
|
DeBrujinAst::Abstraction(i, t, Box::new((*ast).into()))
|
|
}
|
|
DeBrujinBuiltInAst::Application(lhs, rhs) => {
|
|
DeBrujinAst::Application(Box::new((*lhs).into()), Box::new((*rhs).into()))
|
|
}
|
|
DeBrujinBuiltInAst::FreeVariable(x) => DeBrujinAst::FreeVariable(x),
|
|
DeBrujinBuiltInAst::BoundVariable(i) => DeBrujinAst::BoundVariable(i),
|
|
DeBrujinBuiltInAst::Constant(constant) => DeBrujinAst::Constant(constant),
|
|
DeBrujinBuiltInAst::Builtin(builtin) => DeBrujinAst::FreeVariable(builtin.name()),
|
|
}
|
|
}
|
|
}
|