parent
6a46c6ca52
commit
32f8f7c29a
@ -0,0 +1,352 @@
|
|||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
parse::Constant,
|
||||||
|
types::{PrimitiveType, TaggedType, Type, TypeTag},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
DeBrujinAst,
|
||||||
|
builtins::{Builtin, DeBrujinBuiltInAst},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct AddOp;
|
||||||
|
struct AddOpNat(usize);
|
||||||
|
struct AddOpFloat(f64);
|
||||||
|
|
||||||
|
impl Builtin for AddOp {
|
||||||
|
fn name(&self) -> String {
|
||||||
|
"add".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn r#type(&self) -> TaggedType {
|
||||||
|
TaggedType::Tagged(
|
||||||
|
TypeTag::Num,
|
||||||
|
"a".to_string(),
|
||||||
|
Box::new(TaggedType::Concrete(Type::arrow(
|
||||||
|
"a",
|
||||||
|
Type::arrow("a", "a"),
|
||||||
|
))),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(&self, rhs: DeBrujinBuiltInAst) -> Option<DeBrujinBuiltInAst> {
|
||||||
|
match rhs {
|
||||||
|
DeBrujinBuiltInAst::Constant(Constant::Nat(n)) => {
|
||||||
|
Some(DeBrujinBuiltInAst::Builtin(Rc::new(AddOpNat(n))))
|
||||||
|
}
|
||||||
|
DeBrujinBuiltInAst::Constant(Constant::Float(n)) => {
|
||||||
|
Some(DeBrujinBuiltInAst::Builtin(Rc::new(AddOpFloat(n))))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Builtin for AddOpNat {
|
||||||
|
fn name(&self) -> String {
|
||||||
|
format!("add{}", self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_ast(&self) -> DeBrujinAst {
|
||||||
|
DeBrujinAst::Application(
|
||||||
|
Box::new(DeBrujinAst::FreeVariable("add".to_string())),
|
||||||
|
Box::new(DeBrujinAst::Constant(Constant::Nat(self.0))),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn r#type(&self) -> TaggedType {
|
||||||
|
Type::arrow(PrimitiveType::Nat, PrimitiveType::Nat).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(&self, rhs: DeBrujinBuiltInAst) -> Option<DeBrujinBuiltInAst> {
|
||||||
|
match rhs {
|
||||||
|
DeBrujinBuiltInAst::Constant(Constant::Nat(n)) => {
|
||||||
|
Some(DeBrujinBuiltInAst::Constant(Constant::Nat(n + self.0)))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Builtin for AddOpFloat {
|
||||||
|
fn name(&self) -> String {
|
||||||
|
format!("add{}", self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_ast(&self) -> DeBrujinAst {
|
||||||
|
DeBrujinAst::Application(
|
||||||
|
Box::new(DeBrujinAst::FreeVariable("add".to_string())),
|
||||||
|
Box::new(DeBrujinAst::Constant(Constant::Float(self.0))),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn r#type(&self) -> TaggedType {
|
||||||
|
Type::arrow(PrimitiveType::Float, PrimitiveType::Float).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(&self, rhs: DeBrujinBuiltInAst) -> Option<DeBrujinBuiltInAst> {
|
||||||
|
match rhs {
|
||||||
|
DeBrujinBuiltInAst::Constant(Constant::Float(n)) => {
|
||||||
|
Some(DeBrujinBuiltInAst::Constant(Constant::Float(n + self.0)))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SubOp;
|
||||||
|
struct SubOpNat(usize);
|
||||||
|
struct SubOpFloat(f64);
|
||||||
|
|
||||||
|
impl Builtin for SubOp {
|
||||||
|
fn name(&self) -> String {
|
||||||
|
"sub".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn r#type(&self) -> TaggedType {
|
||||||
|
TaggedType::Tagged(
|
||||||
|
TypeTag::Num,
|
||||||
|
"a".to_string(),
|
||||||
|
Box::new(TaggedType::Concrete(Type::arrow(
|
||||||
|
"a",
|
||||||
|
Type::arrow("a", "a"),
|
||||||
|
))),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(&self, rhs: DeBrujinBuiltInAst) -> Option<DeBrujinBuiltInAst> {
|
||||||
|
match rhs {
|
||||||
|
DeBrujinBuiltInAst::Constant(Constant::Nat(n)) => {
|
||||||
|
Some(DeBrujinBuiltInAst::Builtin(Rc::new(SubOpNat(n))))
|
||||||
|
}
|
||||||
|
DeBrujinBuiltInAst::Constant(Constant::Float(n)) => {
|
||||||
|
Some(DeBrujinBuiltInAst::Builtin(Rc::new(SubOpFloat(n))))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Builtin for SubOpNat {
|
||||||
|
fn name(&self) -> String {
|
||||||
|
format!("sub{}", self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_ast(&self) -> DeBrujinAst {
|
||||||
|
DeBrujinAst::Application(
|
||||||
|
Box::new(DeBrujinAst::FreeVariable("sub".to_string())),
|
||||||
|
Box::new(DeBrujinAst::Constant(Constant::Nat(self.0))),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn r#type(&self) -> TaggedType {
|
||||||
|
Type::arrow(PrimitiveType::Nat, PrimitiveType::Nat).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(&self, rhs: DeBrujinBuiltInAst) -> Option<DeBrujinBuiltInAst> {
|
||||||
|
match rhs {
|
||||||
|
DeBrujinBuiltInAst::Constant(Constant::Nat(n)) => {
|
||||||
|
Some(DeBrujinBuiltInAst::Constant(Constant::Nat(self.0 - n)))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Builtin for SubOpFloat {
|
||||||
|
fn name(&self) -> String {
|
||||||
|
format!("sub{}", self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_ast(&self) -> DeBrujinAst {
|
||||||
|
DeBrujinAst::Application(
|
||||||
|
Box::new(DeBrujinAst::FreeVariable("sub".to_string())),
|
||||||
|
Box::new(DeBrujinAst::Constant(Constant::Float(self.0))),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn r#type(&self) -> TaggedType {
|
||||||
|
Type::arrow(PrimitiveType::Float, PrimitiveType::Float).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(&self, rhs: DeBrujinBuiltInAst) -> Option<DeBrujinBuiltInAst> {
|
||||||
|
match rhs {
|
||||||
|
DeBrujinBuiltInAst::Constant(Constant::Float(n)) => {
|
||||||
|
Some(DeBrujinBuiltInAst::Constant(Constant::Float(self.0 - n)))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MulOp;
|
||||||
|
struct MulOpNat(usize);
|
||||||
|
struct MulOpFloat(f64);
|
||||||
|
|
||||||
|
impl Builtin for MulOp {
|
||||||
|
fn name(&self) -> String {
|
||||||
|
"mul".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn r#type(&self) -> TaggedType {
|
||||||
|
TaggedType::Tagged(
|
||||||
|
TypeTag::Num,
|
||||||
|
"a".to_string(),
|
||||||
|
Box::new(TaggedType::Concrete(Type::arrow(
|
||||||
|
"a",
|
||||||
|
Type::arrow("a", "a"),
|
||||||
|
))),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(&self, rhs: DeBrujinBuiltInAst) -> Option<DeBrujinBuiltInAst> {
|
||||||
|
match rhs {
|
||||||
|
DeBrujinBuiltInAst::Constant(Constant::Nat(n)) => {
|
||||||
|
Some(DeBrujinBuiltInAst::Builtin(Rc::new(MulOpNat(n))))
|
||||||
|
}
|
||||||
|
DeBrujinBuiltInAst::Constant(Constant::Float(n)) => {
|
||||||
|
Some(DeBrujinBuiltInAst::Builtin(Rc::new(MulOpFloat(n))))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Builtin for MulOpNat {
|
||||||
|
fn name(&self) -> String {
|
||||||
|
format!("mul{}", self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_ast(&self) -> DeBrujinAst {
|
||||||
|
DeBrujinAst::Application(
|
||||||
|
Box::new(DeBrujinAst::FreeVariable("mul".to_string())),
|
||||||
|
Box::new(DeBrujinAst::Constant(Constant::Nat(self.0))),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn r#type(&self) -> TaggedType {
|
||||||
|
Type::arrow(PrimitiveType::Nat, PrimitiveType::Nat).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(&self, rhs: DeBrujinBuiltInAst) -> Option<DeBrujinBuiltInAst> {
|
||||||
|
match rhs {
|
||||||
|
DeBrujinBuiltInAst::Constant(Constant::Nat(n)) => {
|
||||||
|
Some(DeBrujinBuiltInAst::Constant(Constant::Nat(n * self.0)))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Builtin for MulOpFloat {
|
||||||
|
fn name(&self) -> String {
|
||||||
|
format!("mul{}", self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_ast(&self) -> DeBrujinAst {
|
||||||
|
DeBrujinAst::Application(
|
||||||
|
Box::new(DeBrujinAst::FreeVariable("mul".to_string())),
|
||||||
|
Box::new(DeBrujinAst::Constant(Constant::Float(self.0))),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn r#type(&self) -> TaggedType {
|
||||||
|
Type::arrow(PrimitiveType::Float, PrimitiveType::Float).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(&self, rhs: DeBrujinBuiltInAst) -> Option<DeBrujinBuiltInAst> {
|
||||||
|
match rhs {
|
||||||
|
DeBrujinBuiltInAst::Constant(Constant::Float(n)) => {
|
||||||
|
Some(DeBrujinBuiltInAst::Constant(Constant::Float(n * self.0)))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OpCond;
|
||||||
|
struct OpCond1(bool);
|
||||||
|
struct OpCond2(bool, DeBrujinBuiltInAst);
|
||||||
|
|
||||||
|
impl Builtin for OpCond {
|
||||||
|
fn name(&self) -> String {
|
||||||
|
"if".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn r#type(&self) -> TaggedType {
|
||||||
|
TaggedType::Tagged(
|
||||||
|
TypeTag::Any,
|
||||||
|
"a".to_string(),
|
||||||
|
Box::new(TaggedType::Concrete(Type::arrow(
|
||||||
|
PrimitiveType::Bool,
|
||||||
|
Type::arrow("a", Type::arrow("a", "a")),
|
||||||
|
))),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(&self, rhs: DeBrujinBuiltInAst) -> Option<DeBrujinBuiltInAst> {
|
||||||
|
match rhs {
|
||||||
|
DeBrujinBuiltInAst::Constant(Constant::Bool(b)) => {
|
||||||
|
Some(DeBrujinBuiltInAst::Builtin(Rc::new(OpCond1(b))))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Builtin for OpCond1 {
|
||||||
|
fn name(&self) -> String {
|
||||||
|
format!("if{}1", self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn r#type(&self) -> TaggedType {
|
||||||
|
TaggedType::Tagged(
|
||||||
|
TypeTag::Any,
|
||||||
|
"a".to_string(),
|
||||||
|
Box::new(TaggedType::Concrete(Type::arrow(
|
||||||
|
"a",
|
||||||
|
Type::arrow("a", "a"),
|
||||||
|
))),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_ast(&self) -> DeBrujinAst {
|
||||||
|
DeBrujinAst::Application(
|
||||||
|
Box::new(DeBrujinAst::FreeVariable("if".to_string())),
|
||||||
|
Box::new(DeBrujinAst::Constant(Constant::Bool(self.0))),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(&self, rhs: DeBrujinBuiltInAst) -> Option<DeBrujinBuiltInAst> {
|
||||||
|
Some(DeBrujinBuiltInAst::Builtin(Rc::new(OpCond2(self.0, rhs))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Builtin for OpCond2 {
|
||||||
|
fn name(&self) -> String {
|
||||||
|
format!("if{}2", self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn r#type(&self) -> TaggedType {
|
||||||
|
TaggedType::Tagged(
|
||||||
|
TypeTag::Any,
|
||||||
|
"a".to_string(),
|
||||||
|
Box::new(TaggedType::Concrete(Type::arrow("a", "a"))),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_ast(&self) -> DeBrujinAst {
|
||||||
|
DeBrujinAst::Application(
|
||||||
|
Box::new(DeBrujinAst::Application(
|
||||||
|
Box::new(DeBrujinAst::FreeVariable("if".to_string())),
|
||||||
|
Box::new(DeBrujinAst::Constant(Constant::Bool(self.0))),
|
||||||
|
)),
|
||||||
|
Box::new(self.1.clone().into()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(&self, rhs: DeBrujinBuiltInAst) -> Option<DeBrujinBuiltInAst> {
|
||||||
|
Some(if self.0 { self.1.clone() } else { rhs })
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,101 @@
|
|||||||
|
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()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue