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