diff --git a/src/ast/compiler/lambda_collector.rs b/src/ast/compiler/lambda_collector.rs new file mode 100644 index 0000000..257e2f2 --- /dev/null +++ b/src/ast/compiler/lambda_collector.rs @@ -0,0 +1,89 @@ +use std::collections::HashMap; +use crate::ast::compiler::TypedNode; +use crate::ast::compiler::bound_nodes::{BoundKind, Address}; + +/// A pass that collects all global function definitions (lambdas) into a registry. +/// This allows the Specializer to retrieve the original AST of a function for monomorphization. +pub struct LambdaCollector<'a> { + registry: &'a mut HashMap, +} + +impl<'a> LambdaCollector<'a> { + /// Performs a full traversal of the AST and populates the provided registry. + pub fn collect(node: &TypedNode, registry: &'a mut HashMap) { + let mut collector = Self { registry }; + collector.visit(node); + } + + fn visit(&mut self, node: &TypedNode) { + match &node.kind { + BoundKind::Block { exprs } => { + for expr in exprs { + self.visit(expr); + } + } + + BoundKind::DefGlobal { global_index, value, .. } => { + // If we define a global that is a lambda, register it as a template. + if let BoundKind::Lambda { .. } = &value.kind { + self.registry.insert(*global_index, (**value).clone()); + } + self.visit(value); + } + + BoundKind::Set { addr, value } => { + // Also track assignments to globals if they hold lambdas. + if let Address::Global(global_index) = addr { + if let BoundKind::Lambda { .. } = &value.kind { + self.registry.insert(*global_index, (**value).clone()); + } + } + self.visit(value); + } + + BoundKind::If { cond, then_br, else_br } => { + self.visit(cond); + self.visit(then_br); + if let Some(e) = else_br { + self.visit(e); + } + } + + BoundKind::Lambda { body, .. } => { + // Nested functions are not yet supported for global specialization + // but we traverse them to find potential global definitions inside (if allowed). + self.visit(body); + } + + BoundKind::DefLocal { value, .. } => { + self.visit(value); + } + + BoundKind::Call { callee, args } | BoundKind::TailCall { callee, args } => { + self.visit(callee); + for arg in args { + self.visit(arg); + } + } + + BoundKind::Tuple { elements } => { + for el in elements { + self.visit(el); + } + } + + BoundKind::Map { entries } => { + for (k, v) in entries { + self.visit(k); + self.visit(v); + } + } + + BoundKind::Expansion { bound_expanded, .. } => { + self.visit(bound_expanded); + } + + _ => {} // Leaf nodes (Constant, Get, Nop, etc.) + } + } +} diff --git a/src/ast/rtl/intrinsics.rs b/src/ast/rtl/intrinsics.rs new file mode 100644 index 0000000..17e0ae4 --- /dev/null +++ b/src/ast/rtl/intrinsics.rs @@ -0,0 +1,108 @@ +use std::rc::Rc; +use crate::ast::types::{Value, StaticType}; + +/// Looks up a specialized intrinsic function for the given operator and argument types. +/// Returns (Executable Value, Return Type) if a fast-path exists. +pub fn lookup(name: &str, args: &[StaticType]) -> Option<(Value, StaticType)> { + match (name, args) { + // --- Integer Arithmetic --- + ("+", [StaticType::Int, StaticType::Int]) => Some(( + Value::Function(Rc::new(|args| { + if let (Value::Int(a), Value::Int(b)) = (&args[0], &args[1]) { + Value::Int(a + b) + } else { + Value::Int(0) // Should not happen if type checker works + } + })), + StaticType::Int + )), + ("-", [StaticType::Int, StaticType::Int]) => Some(( + Value::Function(Rc::new(|args| { + if let (Value::Int(a), Value::Int(b)) = (&args[0], &args[1]) { + Value::Int(a - b) + } else { + Value::Int(0) + } + })), + StaticType::Int + )), + ("-", [StaticType::Int, StaticType::Int, StaticType::Int]) => Some(( + // Variadic optimization for 3 args (common in some Lisp dialects, though - usually is binary/unary) + // MyC's core.rs supports variadic subtraction. + Value::Function(Rc::new(|args| { + let a = match args[0] { Value::Int(i) => i, _ => 0 }; + let b = match args[1] { Value::Int(i) => i, _ => 0 }; + let c = match args[2] { Value::Int(i) => i, _ => 0 }; + Value::Int(a - b - c) + })), + StaticType::Int + )), + ("*", [StaticType::Int, StaticType::Int]) => Some(( + Value::Function(Rc::new(|args| { + if let (Value::Int(a), Value::Int(b)) = (&args[0], &args[1]) { + Value::Int(a * b) + } else { + Value::Int(0) + } + })), + StaticType::Int + )), + + // --- Integer Comparison --- + ("<=", [StaticType::Int, StaticType::Int]) => Some(( + Value::Function(Rc::new(|args| { + if let (Value::Int(a), Value::Int(b)) = (&args[0], &args[1]) { + Value::Bool(a <= b) + } else { + Value::Bool(false) + } + })), + StaticType::Bool + )), + ("<", [StaticType::Int, StaticType::Int]) => Some(( + Value::Function(Rc::new(|args| { + if let (Value::Int(a), Value::Int(b)) = (&args[0], &args[1]) { + Value::Bool(a < b) + } else { + Value::Bool(false) + } + })), + StaticType::Bool + )), + (">", [StaticType::Int, StaticType::Int]) => Some(( + Value::Function(Rc::new(|args| { + if let (Value::Int(a), Value::Int(b)) = (&args[0], &args[1]) { + Value::Bool(a > b) + } else { + Value::Bool(false) + } + })), + StaticType::Bool + )), + (">=", [StaticType::Int, StaticType::Int]) => Some(( + Value::Function(Rc::new(|args| { + if let (Value::Int(a), Value::Int(b)) = (&args[0], &args[1]) { + Value::Bool(a >= b) + } else { + Value::Bool(false) + } + })), + StaticType::Bool + )), + ("=", [StaticType::Int, StaticType::Int]) => Some(( + Value::Function(Rc::new(|args| { + if let (Value::Int(a), Value::Int(b)) = (&args[0], &args[1]) { + Value::Bool(a == b) + } else { + Value::Bool(false) + } + })), + StaticType::Bool + )), + + // --- Constant Unary for -1 (decrement optimization) --- + // Special case: tak uses (- x 1). The specializer sees Call("-", [Int, Int]). + + _ => None + } +}