use crate::ast::types::{Purity, StaticType, Value}; /// 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::make_function(Purity::Pure, |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::make_function(Purity::Pure, |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::make_function(Purity::Pure, |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::make_function(Purity::Pure, |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::make_function(Purity::Pure, |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::make_function(Purity::Pure, |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::make_function(Purity::Pure, |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::make_function(Purity::Pure, |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::make_function(Purity::Pure, |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) --- // --- Series & Streams --- ("push", [StaticType::Any, StaticType::Any]) => Some(( Value::make_function(Purity::Impure, |args| { if args.len() < 2 { return Value::Void; } let series_val = &args[0]; let item = &args[1]; if let Value::Object(obj) = series_val { if let Some(rs) = obj.as_any().downcast_ref::() { // SoA Fast-Path: Push record values directly if they match the layout. if let Value::Record(layout, values) = item && std::sync::Arc::ptr_eq(rs.layout(), layout) { rs.push_record_values(values); return Value::Void; } } // Fallback to dynamic push (works for ScalarSeries and RecordSeries) if let Some(series) = obj.as_series() { series.push_value(item.clone()); } } Value::Void }), StaticType::Void, )), ("len", [StaticType::Any]) => Some(( Value::make_function(Purity::Pure, |args| { if let Some(Value::Object(obj)) = args.first() && let Some(series) = obj.as_series() { return Value::Int(series.len() as i64); } Value::Int(0) }), StaticType::Int, )), // Special case: tak uses (- x 1). The specializer sees Call("-", [Int, Int]). _ => None, } }