diff --git a/src/ast/environment.rs b/src/ast/environment.rs index ef7d6c0..54e4b56 100644 --- a/src/ast/environment.rs +++ b/src/ast/environment.rs @@ -405,17 +405,27 @@ impl Environment { } } - pub fn compile_untyped(&self, untyped_ast: Node) -> Result { - let mut diagnostics = Diagnostics::new(); - - let expanded_ast = self.get_expander().expand(untyped_ast)?; + fn compile_pipeline(&self, untyped_ast: Node, diagnostics: &mut Diagnostics) -> Option { + let expanded_ast = match self.get_expander().expand(untyped_ast) { + Ok(ast) => ast, + Err(e) => { + diagnostics.push_error(e, None); + return None; + } + }; let (bound_ast, captures) = - Binder::bind_root(self.global_names.clone(), &expanded_ast, &mut diagnostics)?; + match Binder::bind_root(self.global_names.clone(), &expanded_ast, diagnostics) { + Ok(res) => res, + Err(e) => { + diagnostics.push_error(e, None); + return None; + } + }; let bound_ast = crate::ast::compiler::captures::CapturePass::apply(bound_ast, &captures); - // Pre-allocate global slots + // Pre-allocate global slots to prevent out-of-bounds during specialization/optimization { let mut values = self.global_values.borrow_mut(); let names = self.global_names.borrow(); @@ -446,9 +456,15 @@ impl Environment { ty: (), } }; - let typed_ast = checker.check(&wrapped_ast, &[], &mut diagnostics); + Some(checker.check(&wrapped_ast, &[], diagnostics)) + } - if diagnostics.has_errors() { + pub fn compile_untyped(&self, untyped_ast: Node) -> Result { + let mut diagnostics = Diagnostics::new(); + + let typed_ast_opt = self.compile_pipeline(untyped_ast, &mut diagnostics); + + if diagnostics.has_errors() || typed_ast_opt.is_none() { return Err(diagnostics .items .into_iter() @@ -457,7 +473,7 @@ impl Environment { .join("\n")); } - Ok(typed_ast) + Ok(typed_ast_opt.unwrap()) } pub fn register_native( @@ -536,66 +552,10 @@ impl Environment { } let mut diagnostics = parser.diagnostics; - let expanded_ast = match self.get_expander().expand(untyped_ast) { - Ok(ast) => ast, - Err(e) => { - diagnostics.push_error(e, None); - return CompilationResult { - ast: None, - diagnostics, - }; - } - }; - - let (bound_ast, captures) = - match Binder::bind_root(self.global_names.clone(), &expanded_ast, &mut diagnostics) { - Ok(res) => res, - Err(e) => { - diagnostics.push_error(e, None); - return CompilationResult { - ast: None, - diagnostics, - }; - } - }; - - let bound_ast = crate::ast::compiler::captures::CapturePass::apply(bound_ast, &captures); - - // Pre-allocate global slots to prevent out-of-bounds during specialization/optimization - { - let mut values = self.global_values.borrow_mut(); - let names = self.global_names.borrow(); - let max_idx = names.values().map(|(idx, _)| idx.0).max().unwrap_or(0); - if (max_idx as usize) >= values.len() { - values.resize((max_idx + 1) as usize, Value::Void); - } - } - - LambdaCollector::collect(&bound_ast, &mut self.function_registry.borrow_mut()); - - let checker = TypeChecker::new(self.global_types.clone()); - let wrapped_ast = if let crate::ast::compiler::bound_nodes::BoundKind::Lambda { .. } = bound_ast.kind { - bound_ast - } else { - crate::ast::compiler::bound_nodes::BoundNode { - identity: bound_ast.identity.clone(), - kind: crate::ast::compiler::bound_nodes::BoundKind::Lambda { - params: std::rc::Rc::new(crate::ast::nodes::Node { - identity: bound_ast.identity.clone(), - kind: crate::ast::compiler::bound_nodes::BoundKind::Tuple { elements: vec![] }, - ty: (), - }), - upvalues: vec![], - body: std::rc::Rc::new(bound_ast), - positional_count: Some(0), - }, - ty: (), - } - }; - let typed_ast = checker.check(&wrapped_ast, &[], &mut diagnostics); + let typed_ast = self.compile_pipeline(untyped_ast, &mut diagnostics); CompilationResult { - ast: Some(typed_ast), + ast: typed_ast, diagnostics, } }