|  |  |  | @ -1,4 +1,4 @@ | 
			
		
	
		
			
				
					|  |  |  |  | use std::{collections::HashMap, rc::Rc}; | 
			
		
	
		
			
				
					|  |  |  |  | use std::{collections::HashMap, fmt::Debug, rc::Rc}; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | use crate::{ | 
			
		
	
		
			
				
					|  |  |  |  |     parse::Constant, | 
			
		
	
	
		
			
				
					|  |  |  | @ -55,32 +55,65 @@ pub trait Builtin { | 
			
		
	
		
			
				
					|  |  |  |  |     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 { | 
			
		
	
		
			
				
					|  |  |  |  |     pub(super) fn reduce(self) -> DeBrujinBuiltInAst { | 
			
		
	
		
			
				
					|  |  |  |  |         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 reduce_builtins(self) -> DeBrujinBuiltInAst { | 
			
		
	
		
			
				
					|  |  |  |  |     fn subst_bound(self, depth: usize, subst: DeBrujinBuiltInAst) -> DeBrujinBuiltInAst { | 
			
		
	
		
			
				
					|  |  |  |  |         match self { | 
			
		
	
		
			
				
					|  |  |  |  |             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::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(), | 
			
		
	
		
			
				
					|  |  |  |  |             }, | 
			
		
	
		
			
				
					|  |  |  |  |             DeBrujinBuiltInAst::Application(lhs, rhs) => DeBrujinBuiltInAst::Application( | 
			
		
	
		
			
				
					|  |  |  |  |                 Box::new(lhs.subst_bound(depth, subst.clone())), | 
			
		
	
		
			
				
					|  |  |  |  |                 Box::new(rhs.subst_bound(depth, subst)), | 
			
		
	
		
			
				
					|  |  |  |  |             ), | 
			
		
	
		
			
				
					|  |  |  |  |             DeBrujinBuiltInAst::BoundVariable(n) if n == depth => subst, | 
			
		
	
		
			
				
					|  |  |  |  |             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 { | 
			
		
	
	
		
			
				
					|  |  |  | @ -95,7 +128,7 @@ impl From<DeBrujinBuiltInAst> for DeBrujinAst { | 
			
		
	
		
			
				
					|  |  |  |  |             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()), | 
			
		
	
		
			
				
					|  |  |  |  |             DeBrujinBuiltInAst::Builtin(builtin) => builtin.to_ast(), | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
	
		
			
				
					|  |  |  | 
 |