Skip to main content

sigil_parser/
llvm_codegen.rs

1//! Sigil LLVM Compiler Backend
2//!
3//! Native code generation using LLVM for maximum performance.
4//! This backend targets near-native Rust/C++ performance.
5
6#[cfg(feature = "llvm")]
7pub mod llvm {
8    use inkwell::builder::Builder;
9    use inkwell::context::Context;
10    use inkwell::execution_engine::{ExecutionEngine, JitFunction};
11    use inkwell::module::Module;
12    use inkwell::passes::PassBuilderOptions;
13    use inkwell::targets::{
14        CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetMachine, TargetTriple,
15    };
16    use inkwell::types::{BasicMetadataTypeEnum, BasicType, BasicTypeEnum, StructType};
17    use inkwell::values::{
18        BasicMetadataValueEnum, BasicValue, BasicValueEnum, FunctionValue, IntValue, PointerValue,
19        StructValue,
20    };
21    use inkwell::{AddressSpace, IntPredicate, OptimizationLevel};
22
23    use std::collections::HashMap;
24    use std::path::Path;
25
26    use crate::ast::{self, BinOp, Expr, Item, Literal, UnaryOp};
27    use crate::optimize::{OptLevel, Optimizer};
28    use crate::parser::Parser;
29
30    /// Type alias for JIT-compiled main function
31    type MainFn = unsafe extern "C" fn() -> i64;
32
33    /// Compilation mode
34    #[derive(Clone, Copy, PartialEq, Eq)]
35    pub enum CompileMode {
36        /// JIT execution - main stays as "main"
37        Jit,
38        /// AOT compilation - main becomes "main_sigil" for linking with C runtime
39        Aot,
40    }
41
42    /// Information about a compiled struct type
43    #[derive(Clone)]
44    pub struct StructInfo<'ctx> {
45        /// The LLVM struct type
46        pub llvm_type: StructType<'ctx>,
47        /// Field name to index mapping
48        pub field_indices: HashMap<String, u32>,
49    }
50
51    /// Information about a compiled enum type
52    #[derive(Clone)]
53    pub struct EnumInfo {
54        /// Variant name to discriminant value mapping
55        pub variants: HashMap<String, u64>,
56    }
57
58    /// Information about a generic struct (before monomorphization)
59    #[derive(Clone)]
60    pub struct GenericStructDef {
61        /// The struct definition AST node
62        pub def: ast::StructDef,
63        /// Generic parameter names in order
64        pub type_params: Vec<String>,
65    }
66
67    /// LLVM-based compiler for Sigil
68    pub struct LlvmCompiler<'ctx> {
69        context: &'ctx Context,
70        module: Module<'ctx>,
71        builder: Builder<'ctx>,
72        execution_engine: Option<ExecutionEngine<'ctx>>,
73        /// Compiled functions
74        functions: HashMap<String, FunctionValue<'ctx>>,
75        /// Optimization level
76        opt_level: OptLevel,
77        /// Compilation mode (JIT vs AOT)
78        compile_mode: CompileMode,
79        /// Current module path (e.g., ["crate", "foo", "bar"])
80        current_module: Vec<String>,
81        /// Maps use aliases to their full paths
82        use_aliases: HashMap<String, String>,
83        /// Struct type registry (concrete and monomorphized)
84        struct_types: HashMap<String, StructInfo<'ctx>>,
85        /// Generic struct definitions (awaiting monomorphization)
86        generic_structs: HashMap<String, GenericStructDef>,
87        /// Enum type registry
88        enum_types: HashMap<String, EnumInfo>,
89        /// Impl method registry: maps (type_name, method_name) -> mangled function name
90        impl_methods: HashMap<(String, String), String>,
91        /// Counter for generating unique string constant names
92        string_counter: std::cell::Cell<u32>,
93        /// Evidential wrapper types: maps base type name to {tag: i8, value: T} struct
94        evidential_types: HashMap<String, StructType<'ctx>>,
95        /// Current Self type when compiling impl blocks
96        current_self_type: Option<String>,
97        /// Global/static variables
98        global_vars: HashMap<String, inkwell::values::GlobalValue<'ctx>>,
99    }
100
101    // ============================================
102    // Evidence Tag Constants
103    // ============================================
104    // These match the Evidentiality enum in ast.rs
105    const EVIDENCE_KNOWN: u8 = 0; // ! - verified ground truth
106    const EVIDENCE_UNCERTAIN: u8 = 1; // ? - unverified input
107    const EVIDENCE_REPORTED: u8 = 2; // ~ - EMA, eventually consistent
108    const EVIDENCE_PREDICTED: u8 = 3; // ◊ - model output, speculative
109    const EVIDENCE_PARADOX: u8 = 4; // ‽ - contradiction detected
110
111    // Runtime helper: get current time in milliseconds
112    extern "C" fn sigil_now() -> i64 {
113        use std::time::{SystemTime, UNIX_EPOCH};
114        SystemTime::now()
115            .duration_since(UNIX_EPOCH)
116            .map(|d| d.as_millis() as i64)
117            .unwrap_or(0)
118    }
119
120    // Runtime helper: print an integer (for JIT mode)
121    extern "C" fn sigil_print_int(value: i64) {
122        println!("{}", value);
123    }
124
125    // Math runtime helpers (JIT mode) - operate on i64 bits representing f64
126    extern "C" fn sigil_sqrt(x: i64) -> i64 {
127        f64::to_bits(f64::from_bits(x as u64).sqrt()) as i64
128    }
129    extern "C" fn sigil_sin(x: i64) -> i64 {
130        f64::to_bits(f64::from_bits(x as u64).sin()) as i64
131    }
132    extern "C" fn sigil_cos(x: i64) -> i64 {
133        f64::to_bits(f64::from_bits(x as u64).cos()) as i64
134    }
135    extern "C" fn sigil_tan(x: i64) -> i64 {
136        f64::to_bits(f64::from_bits(x as u64).tan()) as i64
137    }
138    extern "C" fn sigil_exp(x: i64) -> i64 {
139        f64::to_bits(f64::from_bits(x as u64).exp()) as i64
140    }
141    extern "C" fn sigil_ln(x: i64) -> i64 {
142        f64::to_bits(f64::from_bits(x as u64).ln()) as i64
143    }
144    extern "C" fn sigil_pow(x: i64, y: i64) -> i64 {
145        f64::to_bits(f64::from_bits(x as u64).powf(f64::from_bits(y as u64))) as i64
146    }
147    extern "C" fn sigil_floor(x: i64) -> i64 {
148        f64::to_bits(f64::from_bits(x as u64).floor()) as i64
149    }
150    extern "C" fn sigil_ceil(x: i64) -> i64 {
151        f64::to_bits(f64::from_bits(x as u64).ceil()) as i64
152    }
153    extern "C" fn sigil_abs(x: i64) -> i64 {
154        x.abs()
155    }
156    extern "C" fn sigil_min(a: i64, b: i64) -> i64 {
157        a.min(b)
158    }
159    extern "C" fn sigil_max(a: i64, b: i64) -> i64 {
160        a.max(b)
161    }
162
163    // Vec runtime functions
164    extern "C" fn sigil_vec_new(capacity: i64) -> *mut Vec<i64> {
165        let vec = if capacity > 0 {
166            Vec::with_capacity(capacity as usize)
167        } else {
168            Vec::new()
169        };
170        Box::into_raw(Box::new(vec))
171    }
172
173    extern "C" fn sigil_vec_push(vec_ptr: *mut Vec<i64>, value: i64) {
174        if !vec_ptr.is_null() {
175            unsafe {
176                (*vec_ptr).push(value);
177            }
178        }
179    }
180
181    extern "C" fn sigil_vec_get(vec_ptr: *mut Vec<i64>, index: i64) -> i64 {
182        if vec_ptr.is_null() {
183            return 0;
184        }
185        unsafe {
186            let vec_ref = &*vec_ptr;
187            vec_ref.get(index as usize).copied().unwrap_or(0)
188        }
189    }
190
191    extern "C" fn sigil_vec_len(vec_ptr: *mut Vec<i64>) -> i64 {
192        if vec_ptr.is_null() {
193            return 0;
194        }
195        unsafe { (*vec_ptr).len() as i64 }
196    }
197
198    // String runtime functions
199    extern "C" fn sigil_string_new() -> *mut String {
200        Box::into_raw(Box::new(String::new()))
201    }
202
203    extern "C" fn sigil_string_from(ptr: *const i8) -> *mut String {
204        if ptr.is_null() {
205            return std::ptr::null_mut();
206        }
207        unsafe {
208            let cstr = std::ffi::CStr::from_ptr(ptr);
209            let s = cstr.to_string_lossy().into_owned();
210            Box::into_raw(Box::new(s))
211        }
212    }
213
214    extern "C" fn sigil_string_len(str_ptr: *mut String) -> i64 {
215        if str_ptr.is_null() {
216            return 0;
217        }
218        unsafe {
219            let str_ref = &*str_ptr;
220            str_ref.len() as i64
221        }
222    }
223
224    extern "C" fn sigil_string_print(str_ptr: *mut String) {
225        if !str_ptr.is_null() {
226            unsafe {
227                print!("{}", *str_ptr);
228            }
229        }
230    }
231
232    extern "C" fn sigil_string_concat(a_ptr: *mut String, b_ptr: *mut String) -> *mut String {
233        if a_ptr.is_null() || b_ptr.is_null() {
234            return std::ptr::null_mut();
235        }
236        unsafe {
237            let result = format!("{}{}", *a_ptr, *b_ptr);
238            Box::into_raw(Box::new(result))
239        }
240    }
241
242    // Option runtime functions
243    extern "C" fn sigil_option_some(value: i64) -> *mut i64 {
244        Box::into_raw(Box::new(value))
245    }
246
247    extern "C" fn sigil_option_none() -> *mut i64 {
248        std::ptr::null_mut()
249    }
250
251    extern "C" fn sigil_option_is_some(opt_ptr: *mut i64) -> i64 {
252        if opt_ptr.is_null() {
253            0
254        } else {
255            1
256        }
257    }
258
259    extern "C" fn sigil_option_is_none(opt_ptr: *mut i64) -> i64 {
260        if opt_ptr.is_null() {
261            1
262        } else {
263            0
264        }
265    }
266
267    extern "C" fn sigil_option_unwrap(opt_ptr: *mut i64) -> i64 {
268        if opt_ptr.is_null() {
269            eprintln!("Error: unwrap called on None");
270            0
271        } else {
272            unsafe { *opt_ptr }
273        }
274    }
275
276    extern "C" fn sigil_option_unwrap_or(opt_ptr: *mut i64, default: i64) -> i64 {
277        if opt_ptr.is_null() {
278            default
279        } else {
280            unsafe { *opt_ptr }
281        }
282    }
283
284    // File I/O runtime functions
285    extern "C" fn sigil_file_exists(path_ptr: *const i8) -> i64 {
286        if path_ptr.is_null() {
287            return 0;
288        }
289        unsafe {
290            let cstr = std::ffi::CStr::from_ptr(path_ptr);
291            if let Ok(path) = cstr.to_str() {
292                if std::path::Path::new(path).exists() {
293                    1
294                } else {
295                    0
296                }
297            } else {
298                0
299            }
300        }
301    }
302
303    extern "C" fn sigil_file_read_all(path_ptr: *const i8) -> *mut String {
304        if path_ptr.is_null() {
305            return std::ptr::null_mut();
306        }
307        unsafe {
308            let cstr = std::ffi::CStr::from_ptr(path_ptr);
309            if let Ok(path) = cstr.to_str() {
310                if let Ok(content) = std::fs::read_to_string(path) {
311                    return Box::into_raw(Box::new(content));
312                }
313            }
314            std::ptr::null_mut()
315        }
316    }
317
318    extern "C" fn sigil_file_write_all(path_ptr: *const i8, content_ptr: *mut String) -> i64 {
319        if path_ptr.is_null() || content_ptr.is_null() {
320            return -1;
321        }
322        unsafe {
323            let cstr = std::ffi::CStr::from_ptr(path_ptr);
324            let content_ref = &*content_ptr;
325            if let Ok(path) = cstr.to_str() {
326                if let Ok(_) = std::fs::write(path, content_ref) {
327                    return content_ref.len() as i64;
328                }
329            }
330            -1
331        }
332    }
333
334    impl<'ctx> LlvmCompiler<'ctx> {
335        /// Create a new LLVM compiler for JIT execution
336        pub fn new(context: &'ctx Context, opt_level: OptLevel) -> Result<Self, String> {
337            Self::with_mode(context, opt_level, CompileMode::Jit)
338        }
339
340        /// Create a new LLVM compiler with specific compile mode
341        pub fn with_mode(
342            context: &'ctx Context,
343            opt_level: OptLevel,
344            compile_mode: CompileMode,
345        ) -> Result<Self, String> {
346            // Initialize all targets for proper code generation
347            // Use initialize_all as fallback for systems where native init might fail
348            Target::initialize_all(&InitializationConfig::default());
349
350            let module = context.create_module("sigil_main");
351            let builder = context.create_builder();
352
353            // Set target triple and data layout for the native machine
354            let triple = TargetMachine::get_default_triple();
355            module.set_triple(&triple);
356
357            // Get native target machine to extract data layout
358            let target = Target::from_triple(&triple).map_err(|e| e.to_string())?;
359            let cpu = TargetMachine::get_host_cpu_name();
360            let features = TargetMachine::get_host_cpu_features();
361            if let Some(tm) = target.create_target_machine(
362                &triple,
363                cpu.to_str().unwrap_or("native"),
364                features.to_str().unwrap_or(""),
365                OptimizationLevel::Aggressive,
366                RelocMode::Default,
367                CodeModel::Default,
368            ) {
369                module.set_data_layout(&tm.get_target_data().get_data_layout());
370            }
371
372            Ok(Self {
373                context,
374                module,
375                builder,
376                execution_engine: None,
377                functions: HashMap::new(),
378                opt_level,
379                compile_mode,
380                current_module: vec!["crate".to_string()],
381                use_aliases: HashMap::new(),
382                struct_types: HashMap::new(),
383                generic_structs: HashMap::new(),
384                enum_types: HashMap::new(),
385                impl_methods: HashMap::new(),
386                string_counter: std::cell::Cell::new(0),
387                evidential_types: HashMap::new(),
388                current_self_type: None,
389                global_vars: HashMap::new(),
390            })
391        }
392
393        /// Compile source code
394        pub fn compile(&mut self, source: &str) -> Result<(), String> {
395            let mut parser = Parser::new(source);
396            let source_file = parser.parse_file().map_err(|e| format!("{:?}", e))?;
397
398            // Run AST optimizations (temporarily disabled to debug)
399            // let mut optimizer = Optimizer::new(self.opt_level);
400            // let optimized = optimizer.optimize_file(&source_file);
401            let optimized = source_file; // Skip optimization for now
402
403            // Declare runtime functions
404            self.declare_runtime_functions();
405
406            // First pass: register types
407            for spanned_item in &optimized.items {
408                match &spanned_item.node {
409                    Item::Struct(s) => self.register_struct(s)?,
410                    Item::Enum(e) => self.register_enum(e)?,
411                    _ => {}
412                }
413            }
414
415            // First pass continued: process impl blocks
416            for spanned_item in &optimized.items {
417                if let Item::Impl(impl_block) = &spanned_item.node {
418                    self.declare_impl_methods(impl_block)?;
419                }
420            }
421
422            // Second pass: process modules, statics, and declare all functions
423            for spanned_item in &optimized.items {
424                match &spanned_item.node {
425                    Item::Function(func) => {
426                        self.declare_function(func)?;
427                    }
428                    Item::Module(module) => {
429                        self.process_module(module)?;
430                    }
431                    Item::Use(use_decl) => {
432                        self.process_use(use_decl)?;
433                    }
434                    Item::Static(static_decl) => {
435                        self.process_static(static_decl)?;
436                    }
437                    Item::Const(const_decl) => {
438                        self.process_const(const_decl)?;
439                    }
440                    _ => {}
441                }
442            }
443
444            // Third pass: compile function bodies
445            for spanned_item in &optimized.items {
446                match &spanned_item.node {
447                    Item::Function(func) => {
448                        self.compile_function(func)?;
449                    }
450                    Item::Module(module) => {
451                        self.compile_module_functions(module)?;
452                    }
453                    Item::Impl(impl_block) => {
454                        self.compile_impl_methods(impl_block)?;
455                    }
456                    _ => {}
457                }
458            }
459
460            // Run LLVM optimizations
461            self.run_llvm_optimizations()?;
462
463            Ok(())
464        }
465
466        /// Declare runtime helper functions
467        fn declare_runtime_functions(&self) {
468            let i64_type = self.context.i64_type();
469            let void_type = self.context.void_type();
470
471            // sigil_now() -> i64
472            let now_type = i64_type.fn_type(&[], false);
473            self.module.add_function("sigil_now", now_type, None);
474
475            // sigil_print_int(i64) -> void
476            let print_int_type = void_type.fn_type(&[i64_type.into()], false);
477            self.module
478                .add_function("sigil_print_int", print_int_type, None);
479
480            // sigil_print_str(const char*) -> void - for raw C string literals
481            let ptr_type_generic = self.context.ptr_type(AddressSpace::default());
482            let print_str_type = void_type.fn_type(&[ptr_type_generic.into()], false);
483            self.module
484                .add_function("sigil_print_str", print_str_type, None);
485
486            // sigil_print_float(f64) -> void
487            let f64_type = self.context.f64_type();
488            let print_float_type = void_type.fn_type(&[f64_type.into()], false);
489            self.module
490                .add_function("sigil_print_float", print_float_type, None);
491
492            // Write functions (no newline) for format strings
493            // sigil_write_int(i64) -> void
494            self.module
495                .add_function("sigil_write_int", print_int_type, None);
496
497            // sigil_write_str(const char*) -> void
498            self.module
499                .add_function("sigil_write_str", print_str_type, None);
500
501            // Jormungandr-compatible print functions (const char*) -> void
502            self.module.add_function("print", print_str_type, None);
503            self.module.add_function("println", print_str_type, None);
504            self.module.add_function("eprint", print_str_type, None);
505            self.module.add_function("eprintln", print_str_type, None);
506
507            // sigil_write_float(f64) -> void
508            self.module
509                .add_function("sigil_write_float", print_float_type, None);
510
511            // Math functions: (i64) -> i64
512            let unary_math_type = i64_type.fn_type(&[i64_type.into()], false);
513            for name in [
514                "sigil_sqrt",
515                "sigil_sin",
516                "sigil_cos",
517                "sigil_tan",
518                "sigil_exp",
519                "sigil_ln",
520                "sigil_floor",
521                "sigil_ceil",
522                "sigil_abs",
523            ] {
524                self.module.add_function(name, unary_math_type, None);
525            }
526
527            // Math functions: (i64, i64) -> i64
528            let binary_math_type = i64_type.fn_type(&[i64_type.into(), i64_type.into()], false);
529            for name in ["sigil_pow", "sigil_min", "sigil_max"] {
530                self.module.add_function(name, binary_math_type, None);
531            }
532
533            // Vec functions - use ptr type (i64 as opaque pointer)
534            let ptr_type = i64_type; // Using i64 as opaque pointer type
535
536            // sigil_vec_new(capacity: i64) -> ptr
537            let vec_new_type = ptr_type.fn_type(&[i64_type.into()], false);
538            self.module
539                .add_function("sigil_vec_new", vec_new_type, None);
540
541            // sigil_vec_push(vec: ptr, value: i64) -> void
542            let vec_push_type = void_type.fn_type(&[ptr_type.into(), i64_type.into()], false);
543            self.module
544                .add_function("sigil_vec_push", vec_push_type, None);
545
546            // sigil_vec_get(vec: ptr, index: i64) -> i64
547            let vec_get_type = i64_type.fn_type(&[ptr_type.into(), i64_type.into()], false);
548            self.module
549                .add_function("sigil_vec_get", vec_get_type, None);
550
551            // sigil_vec_len(vec: ptr) -> i64
552            let vec_len_type = i64_type.fn_type(&[ptr_type.into()], false);
553            self.module
554                .add_function("sigil_vec_len", vec_len_type, None);
555
556            // String functions
557            // sigil_string_new() -> ptr (empty string)
558            let string_new_type = ptr_type.fn_type(&[], false);
559            self.module
560                .add_function("sigil_string_new", string_new_type, None);
561
562            // sigil_string_from(const char* src) -> ptr
563            // For now, pass i64 as pointer to string literal (global constant)
564            let string_from_type = ptr_type.fn_type(&[ptr_type.into()], false);
565            self.module
566                .add_function("sigil_string_from", string_from_type, None);
567
568            // sigil_string_len(str: ptr) -> i64
569            let string_len_type = i64_type.fn_type(&[ptr_type.into()], false);
570            self.module
571                .add_function("sigil_string_len", string_len_type, None);
572
573            // sigil_string_print(str: ptr) -> void
574            let string_print_type = void_type.fn_type(&[ptr_type.into()], false);
575            self.module
576                .add_function("sigil_string_print", string_print_type, None);
577
578            // sigil_string_concat(str1: ptr, str2: ptr) -> ptr
579            let string_concat_type = ptr_type.fn_type(&[ptr_type.into(), ptr_type.into()], false);
580            self.module
581                .add_function("sigil_string_concat", string_concat_type, None);
582
583            // Option functions
584            // sigil_option_some(value: i64) -> ptr
585            let option_some_type = ptr_type.fn_type(&[i64_type.into()], false);
586            self.module
587                .add_function("sigil_option_some", option_some_type, None);
588
589            // sigil_option_none() -> ptr (null)
590            let option_none_type = ptr_type.fn_type(&[], false);
591            self.module
592                .add_function("sigil_option_none", option_none_type, None);
593
594            // sigil_option_is_some(opt: ptr) -> i64
595            let option_is_some_type = i64_type.fn_type(&[ptr_type.into()], false);
596            self.module
597                .add_function("sigil_option_is_some", option_is_some_type, None);
598
599            // sigil_option_is_none(opt: ptr) -> i64
600            let option_is_none_type = i64_type.fn_type(&[ptr_type.into()], false);
601            self.module
602                .add_function("sigil_option_is_none", option_is_none_type, None);
603
604            // sigil_option_unwrap(opt: ptr) -> i64
605            let option_unwrap_type = i64_type.fn_type(&[ptr_type.into()], false);
606            self.module
607                .add_function("sigil_option_unwrap", option_unwrap_type, None);
608
609            // sigil_option_unwrap_or(opt: ptr, default: i64) -> i64
610            let option_unwrap_or_type =
611                i64_type.fn_type(&[ptr_type.into(), i64_type.into()], false);
612            self.module
613                .add_function("sigil_option_unwrap_or", option_unwrap_or_type, None);
614
615            // File I/O functions
616            // sigil_file_exists(path: ptr) -> i64 (1 if exists, 0 otherwise)
617            let file_exists_type = i64_type.fn_type(&[ptr_type.into()], false);
618            self.module
619                .add_function("sigil_file_exists", file_exists_type, None);
620
621            // sigil_file_read_all(path: ptr) -> ptr (returns String ptr or null)
622            let file_read_all_type = ptr_type.fn_type(&[ptr_type.into()], false);
623            self.module
624                .add_function("sigil_file_read_all", file_read_all_type, None);
625
626            // sigil_file_write_all(path: ptr, content: ptr) -> i64 (bytes written or -1)
627            let file_write_all_type = i64_type.fn_type(&[ptr_type.into(), ptr_type.into()], false);
628            self.module
629                .add_function("sigil_file_write_all", file_write_all_type, None);
630
631            // sigil_exit(code: i64) -> void
632            let exit_type = void_type.fn_type(&[i64_type.into()], false);
633            self.module.add_function("sigil_exit", exit_type, None);
634
635            // Memory functions
636            // sigil_alloc(size: i64) -> ptr
637            let alloc_type = ptr_type.fn_type(&[i64_type.into()], false);
638            self.module.add_function("sigil_alloc", alloc_type, None);
639
640            // sigil_realloc(ptr: ptr, new_size: i64) -> ptr
641            let realloc_type = ptr_type.fn_type(&[ptr_type.into(), i64_type.into()], false);
642            self.module
643                .add_function("sigil_realloc", realloc_type, None);
644
645            // sigil_free(ptr: ptr) -> void
646            let free_type = void_type.fn_type(&[ptr_type.into()], false);
647            self.module.add_function("sigil_free", free_type, None);
648
649            // SIMD Functions (F32x16)
650            let f32_type = self.context.f32_type();
651
652            // sigil_simd_alloc(num_floats: i64) -> ptr
653            let simd_alloc_type = ptr_type.fn_type(&[i64_type.into()], false);
654            self.module
655                .add_function("sigil_simd_alloc", simd_alloc_type, None);
656
657            // sigil_simd_free(ptr: ptr) -> void
658            let simd_free_type = void_type.fn_type(&[ptr_type.into()], false);
659            self.module
660                .add_function("sigil_simd_free", simd_free_type, None);
661
662            // sigil_simd_splat_f32x16(dest: ptr, value: f32) -> void
663            let simd_splat_type = void_type.fn_type(&[ptr_type.into(), f32_type.into()], false);
664            self.module
665                .add_function("sigil_simd_splat_f32x16", simd_splat_type, None);
666
667            // sigil_simd_load_f32x16(dest: ptr, src: ptr) -> void
668            let simd_load_type = void_type.fn_type(&[ptr_type.into(), ptr_type.into()], false);
669            self.module
670                .add_function("sigil_simd_load_f32x16", simd_load_type, None);
671
672            // sigil_simd_store_f32x16(dest: ptr, src: ptr) -> void
673            let simd_store_type = void_type.fn_type(&[ptr_type.into(), ptr_type.into()], false);
674            self.module
675                .add_function("sigil_simd_store_f32x16", simd_store_type, None);
676
677            // sigil_simd_add_f32x16(dest: ptr, a: ptr, b: ptr) -> void
678            let simd_binop_type =
679                void_type.fn_type(&[ptr_type.into(), ptr_type.into(), ptr_type.into()], false);
680            self.module
681                .add_function("sigil_simd_add_f32x16", simd_binop_type, None);
682
683            // sigil_simd_sub_f32x16(dest: ptr, a: ptr, b: ptr) -> void
684            self.module
685                .add_function("sigil_simd_sub_f32x16", simd_binop_type, None);
686
687            // sigil_simd_mul_f32x16(dest: ptr, a: ptr, b: ptr) -> void
688            self.module
689                .add_function("sigil_simd_mul_f32x16", simd_binop_type, None);
690
691            // sigil_simd_div_f32x16(dest: ptr, a: ptr, b: ptr) -> void
692            self.module
693                .add_function("sigil_simd_div_f32x16", simd_binop_type, None);
694
695            // sigil_simd_fmadd_f32x16(dest: ptr, a: ptr, b: ptr, c: ptr) -> void
696            let simd_fmadd_type = void_type.fn_type(
697                &[
698                    ptr_type.into(),
699                    ptr_type.into(),
700                    ptr_type.into(),
701                    ptr_type.into(),
702                ],
703                false,
704            );
705            self.module
706                .add_function("sigil_simd_fmadd_f32x16", simd_fmadd_type, None);
707
708            // sigil_simd_reduce_add_f32x16(src: ptr) -> f32
709            let simd_reduce_type = f32_type.fn_type(&[ptr_type.into()], false);
710            self.module
711                .add_function("sigil_simd_reduce_add_f32x16", simd_reduce_type, None);
712
713            // sigil_simd_extract_f32x16(src: ptr, index: i64) -> f32
714            let simd_extract_type = f32_type.fn_type(&[ptr_type.into(), i64_type.into()], false);
715            self.module
716                .add_function("sigil_simd_extract_f32x16", simd_extract_type, None);
717
718            // sigil_simd_dot_f32x16(a: ptr, b: ptr) -> f32
719            let simd_dot_type = f32_type.fn_type(&[ptr_type.into(), ptr_type.into()], false);
720            self.module
721                .add_function("sigil_simd_dot_f32x16", simd_dot_type, None);
722
723            // CUDA Functions
724            // sigil_cuda_init() -> i64
725            let cuda_init_type = i64_type.fn_type(&[], false);
726            self.module
727                .add_function("sigil_cuda_init", cuda_init_type, None);
728
729            // sigil_cuda_cleanup() -> void
730            let cuda_cleanup_type = void_type.fn_type(&[], false);
731            self.module
732                .add_function("sigil_cuda_cleanup", cuda_cleanup_type, None);
733
734            // sigil_cuda_get_device_count() -> i64
735            let cuda_device_count_type = i64_type.fn_type(&[], false);
736            self.module
737                .add_function("sigil_cuda_get_device_count", cuda_device_count_type, None);
738
739            // sigil_cuda_malloc(size: i64) -> i64 (device ptr)
740            let cuda_malloc_type = i64_type.fn_type(&[i64_type.into()], false);
741            self.module
742                .add_function("sigil_cuda_malloc", cuda_malloc_type, None);
743
744            // sigil_cuda_free(device_ptr: i64) -> void
745            let cuda_free_type = void_type.fn_type(&[i64_type.into()], false);
746            self.module
747                .add_function("sigil_cuda_free", cuda_free_type, None);
748
749            // sigil_cuda_memcpy_h2d(dst: i64, src: ptr, size: i64) -> i64
750            let cuda_h2d_type =
751                i64_type.fn_type(&[i64_type.into(), ptr_type.into(), i64_type.into()], false);
752            self.module
753                .add_function("sigil_cuda_memcpy_h2d", cuda_h2d_type, None);
754
755            // sigil_cuda_memcpy_d2h(dst: ptr, src: i64, size: i64) -> i64
756            let cuda_d2h_type =
757                i64_type.fn_type(&[ptr_type.into(), i64_type.into(), i64_type.into()], false);
758            self.module
759                .add_function("sigil_cuda_memcpy_d2h", cuda_d2h_type, None);
760
761            // sigil_cuda_memcpy_d2d(dst: i64, src: i64, size: i64) -> i64
762            let cuda_d2d_type =
763                i64_type.fn_type(&[i64_type.into(), i64_type.into(), i64_type.into()], false);
764            self.module
765                .add_function("sigil_cuda_memcpy_d2d", cuda_d2d_type, None);
766
767            // sigil_cuda_sync() -> void
768            let cuda_sync_type = void_type.fn_type(&[], false);
769            self.module
770                .add_function("sigil_cuda_sync", cuda_sync_type, None);
771
772            // sigil_cuda_compile_kernel(cuda_src: ptr, kernel_name: ptr) -> i64 (handle)
773            let cuda_compile_type = i64_type.fn_type(&[ptr_type.into(), ptr_type.into()], false);
774            self.module
775                .add_function("sigil_cuda_compile_kernel", cuda_compile_type, None);
776
777            // sigil_cuda_load_ptx(ptx: ptr, kernel_name: ptr) -> i64 (handle)
778            self.module
779                .add_function("sigil_cuda_load_ptx", cuda_compile_type, None);
780
781            // sigil_cuda_launch_kernel_1d(handle: i64, grid_x: i64, block_x: i64, args: ptr, num_args: i64) -> i64
782            let cuda_launch_1d_type = i64_type.fn_type(
783                &[
784                    i64_type.into(),
785                    i64_type.into(),
786                    i64_type.into(),
787                    ptr_type.into(),
788                    i64_type.into(),
789                ],
790                false,
791            );
792            self.module
793                .add_function("sigil_cuda_launch_kernel_1d", cuda_launch_1d_type, None);
794
795            // sigil_cuda_launch_kernel_2d(handle: i64, gx: i64, gy: i64, bx: i64, by: i64, args: ptr, num_args: i64) -> i64
796            let cuda_launch_2d_type = i64_type.fn_type(
797                &[
798                    i64_type.into(),
799                    i64_type.into(),
800                    i64_type.into(),
801                    i64_type.into(),
802                    i64_type.into(),
803                    ptr_type.into(),
804                    i64_type.into(),
805                ],
806                false,
807            );
808            self.module
809                .add_function("sigil_cuda_launch_kernel_2d", cuda_launch_2d_type, None);
810        }
811
812        /// Register a struct type in the type registry
813        fn register_struct(&mut self, struct_def: &ast::StructDef) -> Result<(), String> {
814            let name = &struct_def.name.name;
815
816            // Check if this struct has generic parameters
817            if let Some(ref generics) = struct_def.generics {
818                if !generics.params.is_empty() {
819                    // Extract type parameter names
820                    let type_params: Vec<String> = generics
821                        .params
822                        .iter()
823                        .filter_map(|p| match p {
824                            ast::GenericParam::Type { name, .. } => Some(name.name.clone()),
825                            ast::GenericParam::Const { name, .. } => Some(name.name.clone()),
826                            ast::GenericParam::Lifetime(_) => None,
827                        })
828                        .collect();
829
830                    // Store as generic struct for later monomorphization
831                    self.generic_structs.insert(
832                        name.clone(),
833                        GenericStructDef {
834                            def: struct_def.clone(),
835                            type_params,
836                        },
837                    );
838                    return Ok(());
839                }
840            }
841
842            // Non-generic struct: register immediately
843            self.register_concrete_struct(struct_def, &HashMap::new())
844        }
845
846        /// Register a concrete (non-generic or monomorphized) struct type
847        fn register_concrete_struct(
848            &mut self,
849            struct_def: &ast::StructDef,
850            type_substitutions: &HashMap<String, String>,
851        ) -> Result<(), String> {
852            let base_name = &struct_def.name.name;
853
854            // Generate mangled name if we have type substitutions
855            let mangled_name = if type_substitutions.is_empty() {
856                base_name.clone()
857            } else {
858                let args: Vec<String> = type_substitutions.values().cloned().collect();
859                format!("{}_{}", base_name, args.join("_"))
860            };
861
862            // Skip if already registered
863            if self.struct_types.contains_key(&mangled_name) {
864                return Ok(());
865            }
866
867            let i64_type = self.context.i64_type();
868            let f64_type = self.context.f64_type();
869
870            // Build field types and indices based on struct variant
871            let mut field_types: Vec<BasicTypeEnum> = Vec::new();
872            let mut field_indices: HashMap<String, u32> = HashMap::new();
873
874            match &struct_def.fields {
875                ast::StructFields::Named(fields) => {
876                    for (idx, field) in fields.iter().enumerate() {
877                        let llvm_type = self.type_expr_to_llvm(&field.ty, type_substitutions);
878                        field_types.push(llvm_type);
879                        field_indices.insert(field.name.name.clone(), idx as u32);
880                    }
881                }
882                ast::StructFields::Tuple(types) => {
883                    for (idx, ty) in types.iter().enumerate() {
884                        let llvm_type = self.type_expr_to_llvm(ty, type_substitutions);
885                        field_types.push(llvm_type);
886                        field_indices.insert(format!("{}", idx), idx as u32);
887                    }
888                }
889                ast::StructFields::Unit => {
890                    // Unit struct has no fields
891                }
892            }
893
894            // Create LLVM struct type
895            let field_types_refs: Vec<_> = field_types.iter().map(|t| *t).collect();
896            let struct_type = self.context.struct_type(&field_types_refs, false);
897
898            // Store in registry with mangled name
899            self.struct_types.insert(
900                mangled_name,
901                StructInfo {
902                    llvm_type: struct_type,
903                    field_indices,
904                },
905            );
906
907            Ok(())
908        }
909
910        /// Convert a TypeExpr to an LLVM BasicTypeEnum
911        fn type_expr_to_llvm(
912            &mut self,
913            ty: &ast::TypeExpr,
914            substitutions: &HashMap<String, String>,
915        ) -> BasicTypeEnum<'ctx> {
916            let i64_type = self.context.i64_type();
917            let f64_type = self.context.f64_type();
918            let i32_type = self.context.i32_type();
919            let i8_type = self.context.i8_type();
920            let bool_type = self.context.bool_type();
921
922            match ty {
923                ast::TypeExpr::Path(path) => {
924                    if let Some(segment) = path.segments.first() {
925                        let name = &segment.ident.name;
926
927                        // Check if it's a type parameter that needs substitution
928                        if let Some(concrete) = substitutions.get(name) {
929                            return self.primitive_to_llvm(concrete);
930                        }
931
932                        // Check for primitive types
933                        match name.as_str() {
934                            "i8" | "u8" => i8_type.into(),
935                            "i16" | "u16" => self.context.i16_type().into(),
936                            "i32" | "u32" => i32_type.into(),
937                            "i64" | "u64" | "isize" | "usize" => i64_type.into(),
938                            "f32" => self.context.f32_type().into(),
939                            "f64" => f64_type.into(),
940                            "bool" => bool_type.into(),
941                            // AVX-512 SIMD types
942                            "F32x16" | "__m512" => {
943                                // 512-bit vector of 16 f32s
944                                self.context.f32_type().vec_type(16).into()
945                            }
946                            "F64x8" | "__m512d" => {
947                                // 512-bit vector of 8 f64s
948                                self.context.f64_type().vec_type(8).into()
949                            }
950                            "I32x16" | "__m512i" => {
951                                // 512-bit vector of 16 i32s
952                                self.context.i32_type().vec_type(16).into()
953                            }
954                            "I64x8" => {
955                                // 512-bit vector of 8 i64s
956                                self.context.i64_type().vec_type(8).into()
957                            }
958                            // AVX-256 SIMD types
959                            "F32x8" | "__m256" => self.context.f32_type().vec_type(8).into(),
960                            "F64x4" | "__m256d" => self.context.f64_type().vec_type(4).into(),
961                            _ => i64_type.into(), // Default to i64 for unknown types
962                        }
963                    } else {
964                        i64_type.into()
965                    }
966                }
967                ast::TypeExpr::Reference { inner, .. } | ast::TypeExpr::Pointer { inner, .. } => {
968                    // References and pointers are represented as i64 (pointer-sized)
969                    i64_type.into()
970                }
971                ast::TypeExpr::Array { element, .. } => {
972                    // Arrays are represented as pointers for now
973                    i64_type.into()
974                }
975                ast::TypeExpr::Tuple(elements) => {
976                    // Tuples: for now, just use i64
977                    i64_type.into()
978                }
979                ast::TypeExpr::Evidential { inner, .. } => {
980                    // Unwrap evidentiality for LLVM type
981                    self.type_expr_to_llvm(inner, substitutions)
982                }
983                _ => i64_type.into(),
984            }
985        }
986
987        /// Convert a primitive type name to LLVM type
988        fn primitive_to_llvm(&self, name: &str) -> BasicTypeEnum<'ctx> {
989            match name {
990                "i8" | "u8" => self.context.i8_type().into(),
991                "i16" | "u16" => self.context.i16_type().into(),
992                "i32" | "u32" => self.context.i32_type().into(),
993                "i64" | "u64" | "isize" | "usize" => self.context.i64_type().into(),
994                "f32" => self.context.f32_type().into(),
995                "f64" => self.context.f64_type().into(),
996                "bool" => self.context.bool_type().into(),
997                _ => self.context.i64_type().into(),
998            }
999        }
1000
1001        /// Monomorphize a generic struct with concrete type arguments
1002        fn monomorphize_struct(
1003            &mut self,
1004            base_name: &str,
1005            type_args: &[ast::TypeExpr],
1006        ) -> Result<String, String> {
1007            // Look up the generic struct definition
1008            let generic_def = self
1009                .generic_structs
1010                .get(base_name)
1011                .ok_or_else(|| format!("Unknown generic struct: {}", base_name))?
1012                .clone();
1013
1014            if type_args.len() != generic_def.type_params.len() {
1015                return Err(format!(
1016                    "Wrong number of type arguments for {}: expected {}, got {}",
1017                    base_name,
1018                    generic_def.type_params.len(),
1019                    type_args.len()
1020                ));
1021            }
1022
1023            // Build substitution map: type param name -> concrete type name
1024            let mut substitutions: HashMap<String, String> = HashMap::new();
1025            for (param, arg) in generic_def.type_params.iter().zip(type_args.iter()) {
1026                let concrete_name = self.type_expr_to_name(arg);
1027                substitutions.insert(param.clone(), concrete_name);
1028            }
1029
1030            // Generate mangled name
1031            let concrete_names: Vec<String> = substitutions.values().cloned().collect();
1032            let mangled_name = format!("{}_{}", base_name, concrete_names.join("_"));
1033
1034            // Register the monomorphized struct if not already done
1035            if !self.struct_types.contains_key(&mangled_name) {
1036                self.register_concrete_struct(&generic_def.def, &substitutions)?;
1037            }
1038
1039            Ok(mangled_name)
1040        }
1041
1042        /// Convert a TypeExpr to a string name for mangling
1043        fn type_expr_to_name(&self, ty: &ast::TypeExpr) -> String {
1044            match ty {
1045                ast::TypeExpr::Path(path) => path
1046                    .segments
1047                    .iter()
1048                    .map(|s| s.ident.name.clone())
1049                    .collect::<Vec<_>>()
1050                    .join("_"),
1051                ast::TypeExpr::Reference { inner, mutable, .. } => {
1052                    let prefix = if *mutable { "mut_ref" } else { "ref" };
1053                    format!("{}_{}", prefix, self.type_expr_to_name(inner))
1054                }
1055                ast::TypeExpr::Pointer { inner, mutable, .. } => {
1056                    let prefix = if *mutable { "mut_ptr" } else { "ptr" };
1057                    format!("{}_{}", prefix, self.type_expr_to_name(inner))
1058                }
1059                ast::TypeExpr::Array { element, .. } => {
1060                    format!("arr_{}", self.type_expr_to_name(element))
1061                }
1062                ast::TypeExpr::Tuple(elements) => {
1063                    let names: Vec<_> =
1064                        elements.iter().map(|e| self.type_expr_to_name(e)).collect();
1065                    format!("tup_{}", names.join("_"))
1066                }
1067                ast::TypeExpr::Evidential { inner, .. } => self.type_expr_to_name(inner),
1068                _ => "unknown".to_string(),
1069            }
1070        }
1071
1072        // ============================================
1073        // Evidentiality Support
1074        // ============================================
1075
1076        /// Get or create an evidential wrapper type for a base type.
1077        /// Returns a struct type: { i8 tag, T value }
1078        fn get_evidential_type(&mut self, base_type_name: &str) -> StructType<'ctx> {
1079            if let Some(existing) = self.evidential_types.get(base_type_name) {
1080                return *existing;
1081            }
1082
1083            // Create the struct type: { i8 tag, T value }
1084            let i8_type = self.context.i8_type();
1085            let value_type = self.primitive_to_llvm(base_type_name);
1086
1087            let struct_name = format!("Evidential_{}", base_type_name);
1088            let struct_type = self
1089                .context
1090                .struct_type(&[i8_type.into(), value_type], false);
1091
1092            self.evidential_types
1093                .insert(base_type_name.to_string(), struct_type);
1094            struct_type
1095        }
1096
1097        /// Create an evidential value by wrapping a raw value with an evidence tag.
1098        /// Returns a struct { tag, value }.
1099        fn create_evidential_value(
1100            &mut self,
1101            fn_value: FunctionValue<'ctx>,
1102            value: IntValue<'ctx>,
1103            evidence: u8,
1104            type_name: &str,
1105        ) -> Result<StructValue<'ctx>, String> {
1106            let evidential_type = self.get_evidential_type(type_name);
1107            let tag = self.context.i8_type().const_int(evidence as u64, false);
1108
1109            // Allocate on stack and store fields
1110            let ptr = self
1111                .builder
1112                .build_alloca(evidential_type, "evidential")
1113                .map_err(|e| e.to_string())?;
1114
1115            // Store the tag at index 0
1116            let tag_ptr = self
1117                .builder
1118                .build_struct_gep(evidential_type, ptr, 0, "tag_ptr")
1119                .map_err(|e| e.to_string())?;
1120            self.builder
1121                .build_store(tag_ptr, tag)
1122                .map_err(|e| e.to_string())?;
1123
1124            // Store the value at index 1
1125            let value_ptr = self
1126                .builder
1127                .build_struct_gep(evidential_type, ptr, 1, "value_ptr")
1128                .map_err(|e| e.to_string())?;
1129            self.builder
1130                .build_store(value_ptr, value)
1131                .map_err(|e| e.to_string())?;
1132
1133            // Load and return the complete struct
1134            let result = self
1135                .builder
1136                .build_load(evidential_type, ptr, "evidential_val")
1137                .map_err(|e| e.to_string())?;
1138
1139            Ok(result.into_struct_value())
1140        }
1141
1142        /// Extract the raw value from an evidential struct.
1143        /// This is used for the `!` (Known) marker which unwraps evidential values.
1144        fn unwrap_evidential_value(
1145            &mut self,
1146            evidential_struct: StructValue<'ctx>,
1147        ) -> Result<IntValue<'ctx>, String> {
1148            // Extract value at index 1
1149            let value = self
1150                .builder
1151                .build_extract_value(evidential_struct, 1, "unwrapped")
1152                .map_err(|e| e.to_string())?;
1153
1154            Ok(value.into_int_value())
1155        }
1156
1157        /// Extract the evidence tag from an evidential struct.
1158        fn get_evidence_tag(
1159            &mut self,
1160            evidential_struct: StructValue<'ctx>,
1161        ) -> Result<IntValue<'ctx>, String> {
1162            let tag = self
1163                .builder
1164                .build_extract_value(evidential_struct, 0, "tag")
1165                .map_err(|e| e.to_string())?;
1166
1167            Ok(tag.into_int_value())
1168        }
1169
1170        /// Convert AST Evidentiality to evidence tag constant
1171        fn evidentiality_to_tag(ev: &ast::Evidentiality) -> u8 {
1172            match ev {
1173                ast::Evidentiality::Known => EVIDENCE_KNOWN,
1174                ast::Evidentiality::Uncertain => EVIDENCE_UNCERTAIN,
1175                ast::Evidentiality::Reported => EVIDENCE_REPORTED,
1176                ast::Evidentiality::Predicted => EVIDENCE_PREDICTED,
1177                ast::Evidentiality::Paradox => EVIDENCE_PARADOX,
1178            }
1179        }
1180
1181        /// Combine two evidence tags using the lattice join.
1182        /// The result is the "weaker" evidence level.
1183        /// Known < Uncertain < Reported < Predicted < Paradox
1184        fn combine_evidence(
1185            &mut self,
1186            tag1: IntValue<'ctx>,
1187            tag2: IntValue<'ctx>,
1188        ) -> Result<IntValue<'ctx>, String> {
1189            // Use max(tag1, tag2) since higher values = weaker evidence
1190            let cmp = self
1191                .builder
1192                .build_int_compare(IntPredicate::UGT, tag1, tag2, "ev_cmp")
1193                .map_err(|e| e.to_string())?;
1194
1195            let result = self
1196                .builder
1197                .build_select(cmp, tag1, tag2, "ev_combined")
1198                .map_err(|e| e.to_string())?;
1199
1200            Ok(result.into_int_value())
1201        }
1202
1203        /// Register an enum type in the type registry
1204        fn register_enum(&mut self, enum_def: &ast::EnumDef) -> Result<(), String> {
1205            let name = &enum_def.name.name;
1206            let mut variants: HashMap<String, u64> = HashMap::new();
1207
1208            for (idx, variant) in enum_def.variants.iter().enumerate() {
1209                let discriminant = idx as u64;
1210                variants.insert(variant.name.name.clone(), discriminant);
1211            }
1212
1213            self.enum_types.insert(name.clone(), EnumInfo { variants });
1214            Ok(())
1215        }
1216
1217        /// Process a static declaration
1218        fn process_static(&mut self, static_decl: &ast::StaticDef) -> Result<(), String> {
1219            let name = &static_decl.name.name;
1220            // Create a global variable
1221            let i64_type = self.context.i64_type();
1222            let global = self.module.add_global(i64_type, None, name);
1223            // Initialize to 0 (will be initialized properly at runtime)
1224            global.set_initializer(&i64_type.const_int(0, false));
1225            self.global_vars.insert(name.clone(), global);
1226            Ok(())
1227        }
1228
1229        /// Process a const declaration
1230        fn process_const(&mut self, const_decl: &ast::ConstDef) -> Result<(), String> {
1231            let name = &const_decl.name.name;
1232            // Create a global constant
1233            let i64_type = self.context.i64_type();
1234            let global = self.module.add_global(i64_type, None, name);
1235            // Initialize to 0 for now (could evaluate const expr)
1236            global.set_initializer(&i64_type.const_int(0, false));
1237            global.set_constant(true);
1238            self.global_vars.insert(name.clone(), global);
1239            Ok(())
1240        }
1241
1242        /// Extract type name from impl block's self_ty
1243        fn extract_impl_type_name(&self, self_ty: &ast::TypeExpr) -> Result<String, String> {
1244            match self_ty {
1245                ast::TypeExpr::Path(path) => path
1246                    .segments
1247                    .last()
1248                    .map(|s| s.ident.name.clone())
1249                    .ok_or_else(|| "Empty impl type path".to_string()),
1250                ast::TypeExpr::Evidential {
1251                    inner,
1252                    evidentiality,
1253                    ..
1254                } => {
1255                    // Handle ?T (Option<T>) and !T (Result<T>) type impls
1256                    let inner_name = self.extract_impl_type_name(inner)?;
1257                    match evidentiality {
1258                        ast::Evidentiality::Uncertain => Ok(format!("Option_{}", inner_name)),
1259                        ast::Evidentiality::Known => Ok(format!("Result_{}", inner_name)),
1260                        ast::Evidentiality::Reported => Ok(format!("Reported_{}", inner_name)),
1261                        ast::Evidentiality::Predicted => Ok(format!("Predicted_{}", inner_name)),
1262                        ast::Evidentiality::Paradox => Ok(format!("Paradox_{}", inner_name)),
1263                    }
1264                }
1265                ast::TypeExpr::Reference { inner, .. } => {
1266                    // Handle &T impl - use inner type name
1267                    self.extract_impl_type_name(inner)
1268                }
1269                ast::TypeExpr::Slice(inner) => {
1270                    let inner_name = self.extract_impl_type_name(inner)?;
1271                    Ok(format!("Slice_{}", inner_name))
1272                }
1273                ast::TypeExpr::Array { element, .. } => {
1274                    let inner_name = self.extract_impl_type_name(element)?;
1275                    Ok(format!("Array_{}", inner_name))
1276                }
1277                ast::TypeExpr::Tuple(elements) => {
1278                    if elements.is_empty() {
1279                        Ok("Unit".to_string())
1280                    } else {
1281                        let names: Result<Vec<_>, _> = elements
1282                            .iter()
1283                            .map(|e| self.extract_impl_type_name(e))
1284                            .collect();
1285                        Ok(format!("Tuple_{}", names?.join("_")))
1286                    }
1287                }
1288                // Fallback for other types - generate a unique name
1289                _ => Ok("UnknownType".to_string()),
1290            }
1291        }
1292
1293        /// Declare methods from an impl block
1294        fn declare_impl_methods(&mut self, impl_block: &ast::ImplBlock) -> Result<(), String> {
1295            // Get the type name from the impl path
1296            // Extract type name from self_ty (TypeExpr)
1297            let type_name = self.extract_impl_type_name(&impl_block.self_ty)?;
1298
1299            for item in &impl_block.items {
1300                if let ast::ImplItem::Function(func) = item {
1301                    let method_name = &func.name.name;
1302                    let mangled_name = format!("{}_{}", type_name, method_name);
1303
1304                    // Declare the function with self as first parameter
1305                    let i64_type = self.context.i64_type();
1306
1307                    // Check if first param is self/this (instance method)
1308                    let has_explicit_self = func.params.first().map_or(false, |p| {
1309                        matches!(&p.pattern, ast::Pattern::Ident { name, .. } if name.name == "self" || name.name == "this")
1310                    });
1311
1312                    // Check if first param looks like a self reference (&self, &mut self, vary this)
1313                    let has_self_ref = func.params.first().map_or(false, |p| {
1314                        matches!(&p.pattern, ast::Pattern::Ref { pattern, .. } if {
1315                            matches!(&**pattern, ast::Pattern::Ident { name, .. } if name.name == "self" || name.name == "this")
1316                        }) || matches!(&p.pattern, ast::Pattern::RefBinding { name, .. } if name.name == "self" || name.name == "this")
1317                    });
1318
1319                    // A method needs self/this if it has explicit self/this as first param
1320                    // Static methods have no self param at all
1321                    let is_instance_method = has_explicit_self || has_self_ref;
1322
1323                    // Count params: instance methods might have implicit self, static methods don't
1324                    let param_count = func.params.len();
1325                    let param_types: Vec<BasicMetadataTypeEnum> =
1326                        (0..param_count).map(|_| i64_type.into()).collect();
1327
1328                    let fn_type = i64_type.fn_type(&param_types, false);
1329                    let fn_value = self.module.add_function(&mangled_name, fn_type, None);
1330
1331                    // Name parameters - all params are named directly, no implicit self
1332                    for (i, param) in func.params.iter().enumerate() {
1333                        let param_name = match &param.pattern {
1334                            ast::Pattern::Ident { name: ident, .. } => ident.name.clone(),
1335                            ast::Pattern::RefBinding { name: ident, .. } => ident.name.clone(),
1336                            ast::Pattern::Ref { pattern, .. } => {
1337                                if let ast::Pattern::Ident { name: ident, .. } = &**pattern {
1338                                    ident.name.clone()
1339                                } else {
1340                                    format!("param{}", i)
1341                                }
1342                            }
1343                            _ => format!("param{}", i),
1344                        };
1345                        fn_value
1346                            .get_nth_param(i as u32)
1347                            .unwrap()
1348                            .set_name(&param_name);
1349                    }
1350                    let _ = is_instance_method; // Silence unused warning
1351
1352                    self.functions.insert(mangled_name.clone(), fn_value);
1353                    self.impl_methods
1354                        .insert((type_name.clone(), method_name.clone()), mangled_name);
1355                }
1356            }
1357            Ok(())
1358        }
1359
1360        /// Compile methods from an impl block
1361        fn compile_impl_methods(&mut self, impl_block: &ast::ImplBlock) -> Result<(), String> {
1362            // Extract type name from self_ty (TypeExpr)
1363            let type_name = self.extract_impl_type_name(&impl_block.self_ty)?;
1364
1365            // Set the current Self type for resolving Self:: calls
1366            self.current_self_type = Some(type_name.clone());
1367
1368            for item in &impl_block.items {
1369                if let ast::ImplItem::Function(func) = item {
1370                    let method_name = &func.name.name;
1371                    let mangled_name = format!("{}_{}", type_name, method_name);
1372
1373                    let fn_value = *self
1374                        .functions
1375                        .get(&mangled_name)
1376                        .ok_or_else(|| format!("Method not declared: {}", mangled_name))?;
1377
1378                    // Create entry block
1379                    let entry = self.context.append_basic_block(fn_value, "entry");
1380                    self.builder.position_at_end(entry);
1381
1382                    // Set up variable scope
1383                    let mut scope = CompileScope::new();
1384
1385                    // Add all parameters to scope - no implicit self for any method
1386                    // (Static methods have no self, instance methods have explicit self/this)
1387                    for (i, param) in func.params.iter().enumerate() {
1388                        let param_name = match &param.pattern {
1389                            ast::Pattern::Ident { name: ident, .. } => ident.name.clone(),
1390                            ast::Pattern::RefBinding { name: ident, .. } => ident.name.clone(),
1391                            ast::Pattern::Ref { pattern, .. } => {
1392                                if let ast::Pattern::Ident { name: ident, .. } = &**pattern {
1393                                    ident.name.clone()
1394                                } else {
1395                                    format!("param{}", i)
1396                                }
1397                            }
1398                            _ => format!("param{}", i),
1399                        };
1400                        let param_value = fn_value.get_nth_param(i as u32).unwrap();
1401                        let alloca = self
1402                            .builder
1403                            .build_alloca(self.context.i64_type(), &param_name)
1404                            .map_err(|e| e.to_string())?;
1405                        self.builder
1406                            .build_store(alloca, param_value)
1407                            .map_err(|e| e.to_string())?;
1408                        scope.vars.insert(param_name, alloca);
1409                    }
1410
1411                    // Compile function body
1412                    if let Some(ref body) = func.body {
1413                        let result = self.compile_block(fn_value, &mut scope, body)?;
1414
1415                        let current_block = self.builder.get_insert_block().unwrap();
1416                        if current_block.get_terminator().is_none() {
1417                            if let Some(val) = result {
1418                                self.builder
1419                                    .build_return(Some(&val))
1420                                    .map_err(|e| e.to_string())?;
1421                            } else {
1422                                let zero = self.context.i64_type().const_int(0, false);
1423                                self.builder
1424                                    .build_return(Some(&zero))
1425                                    .map_err(|e| e.to_string())?;
1426                            }
1427                        }
1428                    } else {
1429                        let zero = self.context.i64_type().const_int(0, false);
1430                        self.builder
1431                            .build_return(Some(&zero))
1432                            .map_err(|e| e.to_string())?;
1433                    }
1434                }
1435            }
1436
1437            // Clear the current Self type
1438            self.current_self_type = None;
1439            Ok(())
1440        }
1441
1442        /// Declare a function (creates the signature)
1443        fn declare_function(
1444            &mut self,
1445            func: &ast::Function,
1446        ) -> Result<FunctionValue<'ctx>, String> {
1447            let name = &func.name.name;
1448
1449            // Build mangled name with module path (skip "crate" prefix)
1450            let mangled_name = if self.current_module.len() > 1 {
1451                let module_path = self.current_module[1..].join("_");
1452                format!("{}_{}", module_path, name)
1453            } else {
1454                name.clone()
1455            };
1456
1457            // In AOT mode, rename "main" to "main_sigil" so it doesn't conflict with C runtime
1458            let actual_name = if self.compile_mode == CompileMode::Aot
1459                && name == "main"
1460                && self.current_module.len() == 1
1461            {
1462                "main_sigil".to_string()
1463            } else {
1464                mangled_name.clone()
1465            };
1466
1467            let i64_type = self.context.i64_type();
1468
1469            // Build parameter types (all i64 for simplicity)
1470            let param_types: Vec<BasicMetadataTypeEnum> =
1471                func.params.iter().map(|_| i64_type.into()).collect();
1472
1473            // Create function type
1474            let fn_type = i64_type.fn_type(&param_types, false);
1475
1476            // Declare the function
1477            let fn_value = self.module.add_function(&actual_name, fn_type, None);
1478
1479            // Add optimization attributes
1480            // nounwind - function doesn't throw exceptions (enables more optimizations)
1481            let nounwind_attr = self.context.create_enum_attribute(
1482                inkwell::attributes::Attribute::get_named_enum_kind_id("nounwind"),
1483                0,
1484            );
1485            fn_value.add_attribute(inkwell::attributes::AttributeLoc::Function, nounwind_attr);
1486
1487            // Name parameters
1488            for (i, param) in func.params.iter().enumerate() {
1489                if let ast::Pattern::Ident {
1490                    name: ref ident, ..
1491                } = param.pattern
1492                {
1493                    fn_value
1494                        .get_nth_param(i as u32)
1495                        .unwrap()
1496                        .set_name(&ident.name);
1497                }
1498            }
1499
1500            // Store function with both short name and full qualified path for lookups
1501            self.functions.insert(name.clone(), fn_value);
1502            if self.current_module.len() > 1 {
1503                let full_path = format!("{}::{}", self.current_module[1..].join("::"), name);
1504                self.functions.insert(full_path, fn_value);
1505            }
1506            Ok(fn_value)
1507        }
1508
1509        /// Compile a function body
1510        fn compile_function(&mut self, func: &ast::Function) -> Result<(), String> {
1511            let name = &func.name.name;
1512            // eprintln!("DEBUG: Compiling function: {}", name);
1513            let fn_value = *self.functions.get(name).ok_or("Function not declared")?;
1514
1515            // Create entry block
1516            let entry = self.context.append_basic_block(fn_value, "entry");
1517            self.builder.position_at_end(entry);
1518
1519            // Set up variable scope
1520            let mut scope = CompileScope::new();
1521
1522            // Add parameters to scope
1523            for (i, param) in func.params.iter().enumerate() {
1524                // Extract parameter name from various pattern types
1525                let param_name = match &param.pattern {
1526                    ast::Pattern::Ident { name: ident, .. } => Some(ident.name.clone()),
1527                    ast::Pattern::RefBinding { name: ident, .. } => Some(ident.name.clone()),
1528                    _ => {
1529                        eprintln!("WARNING: Unhandled parameter pattern type in function '{}' param {}: {:?}",
1530                            name, i, param.pattern);
1531                        None
1532                    }
1533                };
1534
1535                if let Some(param_name) = param_name {
1536                    let param_value = fn_value.get_nth_param(i as u32).unwrap();
1537                    // Allocate on stack for potential mutation
1538                    let alloca = self
1539                        .builder
1540                        .build_alloca(self.context.i64_type(), &param_name)
1541                        .map_err(|e| e.to_string())?;
1542                    self.builder
1543                        .build_store(alloca, param_value)
1544                        .map_err(|e| e.to_string())?;
1545                    scope.vars.insert(param_name, alloca);
1546                }
1547            }
1548
1549            // Compile function body
1550            if let Some(ref body) = func.body {
1551                let result = self.compile_block(fn_value, &mut scope, body)?;
1552
1553                // Only add return if block isn't already terminated
1554                let current_block = self.builder.get_insert_block().unwrap();
1555                if current_block.get_terminator().is_none() {
1556                    if let Some(val) = result {
1557                        self.builder
1558                            .build_return(Some(&val))
1559                            .map_err(|e| e.to_string())?;
1560                    } else {
1561                        let zero = self.context.i64_type().const_int(0, false);
1562                        self.builder
1563                            .build_return(Some(&zero))
1564                            .map_err(|e| e.to_string())?;
1565                    }
1566                }
1567            } else {
1568                // No body, return 0
1569                let zero = self.context.i64_type().const_int(0, false);
1570                self.builder
1571                    .build_return(Some(&zero))
1572                    .map_err(|e| e.to_string())?;
1573            }
1574
1575            Ok(())
1576        }
1577
1578        /// Compile a block
1579        fn compile_block(
1580            &mut self,
1581            fn_value: FunctionValue<'ctx>,
1582            scope: &mut CompileScope<'ctx>,
1583            block: &ast::Block,
1584        ) -> Result<Option<IntValue<'ctx>>, String> {
1585            let mut result = None;
1586            // eprintln!("DEBUG: compile_block with {} stmts, expr: {}", block.stmts.len(), block.expr.is_some());
1587
1588            for stmt in &block.stmts {
1589                result = self.compile_stmt(fn_value, scope, stmt)?;
1590                // Check if we hit a return
1591                if self
1592                    .builder
1593                    .get_insert_block()
1594                    .unwrap()
1595                    .get_terminator()
1596                    .is_some()
1597                {
1598                    return Ok(result);
1599                }
1600            }
1601
1602            // Trailing expression
1603            if let Some(ref expr) = block.expr {
1604                result = Some(self.compile_expr(fn_value, scope, expr)?);
1605            }
1606
1607            Ok(result)
1608        }
1609
1610        /// Compile a statement
1611        fn compile_stmt(
1612            &mut self,
1613            fn_value: FunctionValue<'ctx>,
1614            scope: &mut CompileScope<'ctx>,
1615            stmt: &ast::Stmt,
1616        ) -> Result<Option<IntValue<'ctx>>, String> {
1617            match stmt {
1618                ast::Stmt::Let { pattern, init, .. } => {
1619                    if let ast::Pattern::Ident {
1620                        name: ref ident, ..
1621                    } = pattern
1622                    {
1623                        // eprintln!("DEBUG: Let binding: {}", ident.name);
1624                        let init_val = if let Some(ref expr) = init {
1625                            self.compile_expr(fn_value, scope, expr)?
1626                        } else {
1627                            self.context.i64_type().const_int(0, false)
1628                        };
1629
1630                        // Allocate on stack
1631                        let alloca = self
1632                            .builder
1633                            .build_alloca(self.context.i64_type(), &ident.name)
1634                            .map_err(|e| e.to_string())?;
1635                        self.builder
1636                            .build_store(alloca, init_val)
1637                            .map_err(|e| e.to_string())?;
1638                        scope.vars.insert(ident.name.clone(), alloca);
1639                        // eprintln!("DEBUG: Added {} to scope, scope now: {:?}", ident.name, scope.vars.keys().collect::<Vec<_>>());
1640                    }
1641                    Ok(None)
1642                }
1643                ast::Stmt::Expr(expr) => {
1644                    let val = self.compile_expr(fn_value, scope, expr)?;
1645                    Ok(Some(val))
1646                }
1647                ast::Stmt::Semi(expr) => {
1648                    self.compile_expr(fn_value, scope, expr)?;
1649                    Ok(None)
1650                }
1651                ast::Stmt::Item(_) => Ok(None),
1652                ast::Stmt::LetElse { pattern, init, .. } => {
1653                    // LetElse is like let but with an else branch for refutable patterns
1654                    // For now, treat it like a regular let
1655                    if let ast::Pattern::Ident {
1656                        name: ref ident, ..
1657                    } = pattern
1658                    {
1659                        let init_val = self.compile_expr(fn_value, scope, init)?;
1660                        let alloca = self
1661                            .builder
1662                            .build_alloca(self.context.i64_type(), &ident.name)
1663                            .map_err(|e| e.to_string())?;
1664                        self.builder
1665                            .build_store(alloca, init_val)
1666                            .map_err(|e| e.to_string())?;
1667                        scope.vars.insert(ident.name.clone(), alloca);
1668                    }
1669                    Ok(None)
1670                }
1671            }
1672        }
1673
1674        /// Compile an expression
1675        fn compile_expr(
1676            &mut self,
1677            fn_value: FunctionValue<'ctx>,
1678            scope: &mut CompileScope<'ctx>,
1679            expr: &Expr,
1680        ) -> Result<IntValue<'ctx>, String> {
1681            match expr {
1682                Expr::Literal(lit) => self.compile_literal(lit),
1683                Expr::Path(path) => {
1684                    // Check for qualified enum variant path (e.g., Color::Blue)
1685                    if path.segments.len() >= 2 {
1686                        let enum_name = &path.segments[path.segments.len() - 2].ident.name;
1687                        let variant_name = &path.segments[path.segments.len() - 1].ident.name;
1688
1689                        if let Some(enum_info) = self.enum_types.get(enum_name) {
1690                            if let Some(&discriminant) = enum_info.variants.get(variant_name) {
1691                                return Ok(self.context.i64_type().const_int(discriminant, false));
1692                            }
1693                        }
1694                    }
1695
1696                    // Variable lookup
1697                    let name = path
1698                        .segments
1699                        .last()
1700                        .map(|s| s.ident.name.as_str())
1701                        .ok_or("Empty path")?;
1702
1703                    // Build full path for qualified lookups
1704                    let full_path: String = path
1705                        .segments
1706                        .iter()
1707                        .map(|s| s.ident.name.as_str())
1708                        .collect::<Vec<_>>()
1709                        .join("::");
1710
1711                    if let Some(&ptr) = scope.vars.get(name) {
1712                        let val = self
1713                            .builder
1714                            .build_load(self.context.i64_type(), ptr, name)
1715                            .map_err(|e| e.to_string())?;
1716                        Ok(val.into_int_value())
1717                    } else if let Some(global) = self.global_vars.get(name) {
1718                        // Load from global variable
1719                        let val = self
1720                            .builder
1721                            .build_load(self.context.i64_type(), global.as_pointer_value(), name)
1722                            .map_err(|e| e.to_string())?;
1723                        Ok(val.into_int_value())
1724                    } else if path.segments.len() > 1 {
1725                        // Qualified path like Token::LParen or Type::Variant
1726                        // Check if it's a qualified enum variant
1727                        let type_name = path
1728                            .segments
1729                            .first()
1730                            .map(|s| s.ident.name.as_str())
1731                            .unwrap_or("");
1732
1733                        // Try to find in registered enum types
1734                        if let Some(enum_info) = self.enum_types.get(type_name) {
1735                            if let Some(&discriminant) = enum_info.variants.get(name) {
1736                                return Ok(self.context.i64_type().const_int(discriminant, false));
1737                            }
1738                        }
1739
1740                        // Fallback: treat as a constant enum value (use hash of name as discriminant)
1741                        // This handles cases like Token::LParen, TokenKind::Fn, etc.
1742                        let hash = full_path
1743                            .bytes()
1744                            .fold(0u64, |acc, b| acc.wrapping_mul(31).wrapping_add(b as u64));
1745                        Ok(self.context.i64_type().const_int(hash, false))
1746                    } else {
1747                        // Check if it's an unqualified enum variant (search all enums)
1748                        for (_, enum_info) in &self.enum_types {
1749                            if let Some(&discriminant) = enum_info.variants.get(name) {
1750                                return Ok(self.context.i64_type().const_int(discriminant, false));
1751                            }
1752                        }
1753
1754                        // Check if it might be a constant (UPPER_CASE naming convention)
1755                        if name
1756                            .chars()
1757                            .all(|c| c.is_uppercase() || c == '_' || c.is_numeric())
1758                        {
1759                            // Treat as constant - use hash of name
1760                            let hash = name
1761                                .bytes()
1762                                .fold(0u64, |acc, b| acc.wrapping_mul(31).wrapping_add(b as u64));
1763                            return Ok(self.context.i64_type().const_int(hash, false));
1764                        }
1765
1766                        // Fallback: return 0 for unknown symbols (may be external constants)
1767                        // This is lenient but allows compilation to proceed
1768                        Ok(self.context.i64_type().const_int(0, false))
1769                    }
1770                }
1771                Expr::Binary { op, left, right } => {
1772                    let lhs = self.compile_expr(fn_value, scope, left)?;
1773                    let rhs = self.compile_expr(fn_value, scope, right)?;
1774                    self.compile_binary_op(*op, lhs, rhs)
1775                }
1776                Expr::Unary { op, expr: inner } => {
1777                    let val = self.compile_expr(fn_value, scope, inner)?;
1778                    self.compile_unary_op(*op, val)
1779                }
1780                Expr::If {
1781                    condition,
1782                    then_branch,
1783                    else_branch,
1784                } => self.compile_if(
1785                    fn_value,
1786                    scope,
1787                    condition,
1788                    then_branch,
1789                    else_branch.as_deref(),
1790                ),
1791                Expr::While {
1792                    label: _,
1793                    condition,
1794                    body,
1795                } => self.compile_while(fn_value, scope, condition, body),
1796                Expr::Call { func, args } => self.compile_call(fn_value, scope, func, args),
1797                Expr::Return(val) => {
1798                    let ret_val = if let Some(ref e) = val {
1799                        self.compile_expr(fn_value, scope, e)?
1800                    } else {
1801                        self.context.i64_type().const_int(0, false)
1802                    };
1803                    self.builder
1804                        .build_return(Some(&ret_val))
1805                        .map_err(|e| e.to_string())?;
1806                    // Return a dummy value (code after return is unreachable)
1807                    Ok(ret_val)
1808                }
1809                Expr::Assign { target, value } => {
1810                    let val = self.compile_expr(fn_value, scope, value)?;
1811                    match target.as_ref() {
1812                        Expr::Path(path) => {
1813                            let name = path
1814                                .segments
1815                                .last()
1816                                .map(|s| s.ident.name.as_str())
1817                                .ok_or("Empty path")?;
1818                            if let Some(&ptr) = scope.vars.get(name) {
1819                                self.builder
1820                                    .build_store(ptr, val)
1821                                    .map_err(|e| e.to_string())?;
1822                                Ok(val)
1823                            } else if let Some(global) = self.global_vars.get(name) {
1824                                // Store to global variable
1825                                self.builder
1826                                    .build_store(global.as_pointer_value(), val)
1827                                    .map_err(|e| e.to_string())?;
1828                                Ok(val)
1829                            } else {
1830                                // Fallback: create global on demand for unknown variables
1831                                let i64_type = self.context.i64_type();
1832                                let global = self.module.add_global(i64_type, None, name);
1833                                global.set_initializer(&i64_type.const_int(0, false));
1834                                self.builder
1835                                    .build_store(global.as_pointer_value(), val)
1836                                    .map_err(|e| e.to_string())?;
1837                                // Note: can't insert into self.global_vars here due to borrow checker
1838                                Ok(val)
1839                            }
1840                        }
1841                        Expr::Field { expr, field } => {
1842                            // Get struct pointer from the expression
1843                            let struct_ptr_int = self.compile_expr(fn_value, scope, expr)?;
1844                            let ptr_type = self.context.ptr_type(inkwell::AddressSpace::default());
1845                            let struct_ptr = self
1846                                .builder
1847                                .build_int_to_ptr(struct_ptr_int, ptr_type, "struct_ptr")
1848                                .map_err(|e| e.to_string())?;
1849
1850                            let field_name = &field.name;
1851                            // Find the struct type and field index
1852                            for (_name, struct_info) in &self.struct_types {
1853                                if let Some(&field_idx) = struct_info.field_indices.get(field_name)
1854                                {
1855                                    let field_ptr = self
1856                                        .builder
1857                                        .build_struct_gep(
1858                                            struct_info.llvm_type,
1859                                            struct_ptr,
1860                                            field_idx,
1861                                            &format!("{}_ptr", field_name),
1862                                        )
1863                                        .map_err(|e| e.to_string())?;
1864                                    self.builder
1865                                        .build_store(field_ptr, val)
1866                                        .map_err(|e| e.to_string())?;
1867                                    return Ok(val);
1868                                }
1869                            }
1870                            // Fallback: use offset-based field access for assignment
1871                            let offset = match field_name.as_str() {
1872                                "0" => 0u64,
1873                                "1" => 1,
1874                                "2" => 2,
1875                                "3" => 3,
1876                                "start" | "first" | "x" | "name" | "key" | "id" => 0,
1877                                "end" | "second" | "y" | "value" | "ty" => 1,
1878                                "z" | "third" | "body" | "args" => 2,
1879                                _ => 0, // Default to first field
1880                            };
1881                            let offset_val = self.context.i64_type().const_int(offset * 8, false);
1882                            let field_ptr_int = self
1883                                .builder
1884                                .build_int_add(struct_ptr_int, offset_val, "field_ptr")
1885                                .map_err(|e| e.to_string())?;
1886                            let ptr_type = self.context.ptr_type(inkwell::AddressSpace::default());
1887                            let field_ptr = self
1888                                .builder
1889                                .build_int_to_ptr(
1890                                    field_ptr_int,
1891                                    ptr_type,
1892                                    &format!("{}_ptr", field_name),
1893                                )
1894                                .map_err(|e| e.to_string())?;
1895                            self.builder
1896                                .build_store(field_ptr, val)
1897                                .map_err(|e| e.to_string())?;
1898                            Ok(val)
1899                        }
1900                        Expr::Unary { op, expr } if matches!(op, ast::UnaryOp::Deref) => {
1901                            // Dereference assignment: *ptr = val
1902                            let ptr_val = self.compile_expr(fn_value, scope, expr)?;
1903                            let ptr_type = self.context.ptr_type(inkwell::AddressSpace::default());
1904                            let ptr = self
1905                                .builder
1906                                .build_int_to_ptr(ptr_val, ptr_type, "deref_ptr")
1907                                .map_err(|e| e.to_string())?;
1908                            self.builder
1909                                .build_store(ptr, val)
1910                                .map_err(|e| e.to_string())?;
1911                            Ok(val)
1912                        }
1913                        Expr::Index { expr, index } => {
1914                            // Index assignment: arr[i] = val
1915                            let base = self.compile_expr(fn_value, scope, expr)?;
1916                            let idx = self.compile_expr(fn_value, scope, index)?;
1917                            // Calculate element pointer: base + (idx * 8)
1918                            let offset = self
1919                                .builder
1920                                .build_int_mul(
1921                                    idx,
1922                                    self.context.i64_type().const_int(8, false),
1923                                    "idx_offset",
1924                                )
1925                                .map_err(|e| e.to_string())?;
1926                            let elem_ptr_int = self
1927                                .builder
1928                                .build_int_add(base, offset, "elem_ptr")
1929                                .map_err(|e| e.to_string())?;
1930                            let ptr_type = self.context.ptr_type(inkwell::AddressSpace::default());
1931                            let elem_ptr = self
1932                                .builder
1933                                .build_int_to_ptr(elem_ptr_int, ptr_type, "index_ptr")
1934                                .map_err(|e| e.to_string())?;
1935                            self.builder
1936                                .build_store(elem_ptr, val)
1937                                .map_err(|e| e.to_string())?;
1938                            Ok(val)
1939                        }
1940                        _ => {
1941                            // Lenient fallback: just evaluate the target and return the value
1942                            // This allows compilation to proceed for unsupported assignment patterns
1943                            let _ = self.compile_expr(fn_value, scope, target)?;
1944                            Ok(val)
1945                        }
1946                    }
1947                }
1948                Expr::Block(block) => {
1949                    let result = self.compile_block(fn_value, scope, block)?;
1950                    Ok(result.unwrap_or_else(|| self.context.i64_type().const_int(0, false)))
1951                }
1952                Expr::Struct { path, fields, .. } => {
1953                    // Get struct name and potential generic arguments from path
1954                    let last_segment = path.segments.last().ok_or("Empty struct path")?;
1955                    let base_name = last_segment.ident.name.as_str();
1956
1957                    // Resolve Self/This to actual type name
1958                    let base_name: String = if base_name == "Self" || base_name == "This" {
1959                        if let Some(ref self_type) = self.current_self_type {
1960                            self_type.clone()
1961                        } else {
1962                            return Err("Self/This used outside of impl block".to_string());
1963                        }
1964                    } else {
1965                        base_name.to_string()
1966                    };
1967
1968                    // Check if this is a generic struct instantiation
1969                    let struct_name = if let Some(ref type_args) = last_segment.generics {
1970                        // Monomorphize the generic struct
1971                        self.monomorphize_struct(&base_name, type_args)?
1972                    } else if self.generic_structs.contains_key(&base_name) {
1973                        // Generic struct used without type args - use default monomorphization
1974                        // Assume i64 for all type parameters
1975                        format!("{}_i64", base_name)
1976                    } else {
1977                        base_name
1978                    };
1979
1980                    // Look up struct type (now with mangled name for generics)
1981                    let struct_info_opt = self.struct_types.get(&struct_name).cloned();
1982
1983                    if let Some(struct_info) = struct_info_opt {
1984                        // Known struct type
1985                        let struct_ptr = self
1986                            .builder
1987                            .build_alloca(struct_info.llvm_type, &struct_name)
1988                            .map_err(|e| e.to_string())?;
1989
1990                        // Initialize each field
1991                        for (idx, field_init) in fields.iter().enumerate() {
1992                            let field_name = &field_init.name.name;
1993                            // Try to get field index from struct info, fallback to position
1994                            let field_idx = *struct_info
1995                                .field_indices
1996                                .get(field_name)
1997                                .unwrap_or(&(idx as u32));
1998
1999                            // Get field value (or use field name as variable if no value)
2000                            let field_value = if let Some(ref val_expr) = field_init.value {
2001                                self.compile_expr(fn_value, scope, val_expr)?
2002                            } else {
2003                                // Shorthand: field name is the variable name
2004                                if let Some(&ptr) = scope.vars.get(field_name.as_str()) {
2005                                    self.builder
2006                                        .build_load(self.context.i64_type(), ptr, field_name)
2007                                        .map_err(|e| e.to_string())?
2008                                        .into_int_value()
2009                                } else {
2010                                    // Fallback: use 0 for unknown shorthand variables
2011                                    self.context.i64_type().const_int(0, false)
2012                                }
2013                            };
2014
2015                            // Get pointer to field and store value
2016                            let field_ptr = self
2017                                .builder
2018                                .build_struct_gep(
2019                                    struct_info.llvm_type,
2020                                    struct_ptr,
2021                                    field_idx,
2022                                    &format!("{}_ptr", field_name),
2023                                )
2024                                .map_err(|e| e.to_string())?;
2025                            self.builder
2026                                .build_store(field_ptr, field_value)
2027                                .map_err(|e| e.to_string())?;
2028                        }
2029
2030                        // Return struct pointer as i64
2031                        let ptr_int = self
2032                            .builder
2033                            .build_ptr_to_int(struct_ptr, self.context.i64_type(), "struct_ptr")
2034                            .map_err(|e| e.to_string())?;
2035                        return Ok(ptr_int);
2036                    }
2037
2038                    // Unknown struct type - create dynamic struct on the fly
2039                    // Build field types (all i64 for now)
2040                    let field_types: Vec<BasicTypeEnum> = fields
2041                        .iter()
2042                        .map(|_| self.context.i64_type().into())
2043                        .collect();
2044
2045                    // Create struct type dynamically
2046                    let llvm_type = self.context.struct_type(&field_types, false);
2047                    let struct_ptr = self
2048                        .builder
2049                        .build_alloca(llvm_type, &struct_name)
2050                        .map_err(|e| e.to_string())?;
2051
2052                    // Initialize each field by index
2053                    for (idx, field_init) in fields.iter().enumerate() {
2054                        let field_name = &field_init.name.name;
2055                        let field_idx = idx as u32;
2056
2057                        // Get field value (or use field name as variable if no value)
2058                        let field_value = if let Some(ref val_expr) = field_init.value {
2059                            self.compile_expr(fn_value, scope, val_expr)?
2060                        } else {
2061                            // Shorthand: field name is the variable name
2062                            if let Some(&ptr) = scope.vars.get(field_name.as_str()) {
2063                                self.builder
2064                                    .build_load(self.context.i64_type(), ptr, field_name)
2065                                    .map_err(|e| e.to_string())?
2066                                    .into_int_value()
2067                            } else {
2068                                // Fallback: use 0 for unknown shorthand variables
2069                                self.context.i64_type().const_int(0, false)
2070                            }
2071                        };
2072
2073                        // Get pointer to field and store value
2074                        let field_ptr = self
2075                            .builder
2076                            .build_struct_gep(
2077                                llvm_type,
2078                                struct_ptr,
2079                                field_idx,
2080                                &format!("{}_ptr", field_name),
2081                            )
2082                            .map_err(|e| e.to_string())?;
2083                        self.builder
2084                            .build_store(field_ptr, field_value)
2085                            .map_err(|e| e.to_string())?;
2086                    }
2087
2088                    // Return struct pointer as i64
2089                    let ptr_int = self
2090                        .builder
2091                        .build_ptr_to_int(struct_ptr, self.context.i64_type(), "struct_ptr")
2092                        .map_err(|e| e.to_string())?;
2093                    Ok(ptr_int)
2094                }
2095                Expr::Field { expr, field } => {
2096                    // Compile the struct expression to get pointer
2097                    let struct_ptr_int = self.compile_expr(fn_value, scope, expr)?;
2098
2099                    // Convert i64 back to pointer
2100                    let ptr_type = self.context.ptr_type(inkwell::AddressSpace::default());
2101                    let struct_ptr = self
2102                        .builder
2103                        .build_int_to_ptr(struct_ptr_int, ptr_type, "struct_ptr")
2104                        .map_err(|e| e.to_string())?;
2105
2106                    // Try to find struct type from expression
2107                    // For now, search all struct types for the field
2108                    let field_name = &field.name;
2109                    for (_name, struct_info) in &self.struct_types {
2110                        if let Some(&field_idx) = struct_info.field_indices.get(field_name) {
2111                            let field_ptr = self
2112                                .builder
2113                                .build_struct_gep(
2114                                    struct_info.llvm_type,
2115                                    struct_ptr,
2116                                    field_idx,
2117                                    &format!("{}_ptr", field_name),
2118                                )
2119                                .map_err(|e| e.to_string())?;
2120                            let field_value = self
2121                                .builder
2122                                .build_load(self.context.i64_type(), field_ptr, field_name)
2123                                .map_err(|e| e.to_string())?;
2124                            return Ok(field_value.into_int_value());
2125                        }
2126                    }
2127
2128                    // Fallback: For structs not in our registry, use offset-based access
2129                    // Common struct field conventions:
2130                    // - Span: start(0), end(1)
2131                    // - Range: start(0), end(1)
2132                    // - Point: x(0), y(1), z(2)
2133                    // - Location: line(0), col(1)
2134                    // - General: first field at offset 0, etc.
2135                    let field_offset = match field_name.as_str() {
2136                        // First field (offset 0)
2137                        "start" | "first" | "x" | "line" | "lo" | "begin" | "name" | "key"
2138                        | "id" | "data" | "value" => Some(0u64),
2139                        // Second field (offset 1)
2140                        "end" | "second" | "y" | "col" | "hi" | "suffix" | "span" | "ty"
2141                        | "type" => Some(1u64),
2142                        // Third field (offset 2)
2143                        "z" | "third" | "depth" | "body" | "args" | "params" => Some(2u64),
2144                        // Fourth field (offset 3)
2145                        "w" | "fourth" | "return_type" | "ret" => Some(3u64),
2146                        // Common Sigil types
2147                        "message" => Some(0u64),
2148                        "source" => Some(1u64),
2149                        "file" => Some(2u64),
2150                        "kind" => Some(0u64),
2151                        "ident" => Some(0u64),
2152                        "segments" => Some(0u64),
2153                        "items" => Some(0u64),
2154                        "fields" => Some(0u64),
2155                        "variants" => Some(0u64),
2156                        "methods" => Some(0u64),
2157                        "generics" => Some(1u64),
2158                        "vis" | "visibility" => Some(0u64),
2159                        "attrs" | "attributes" => Some(1u64),
2160                        "node" => Some(0u64),
2161                        "path" | "paths" => Some(0u64),
2162                        "left" | "lhs" => Some(0u64),
2163                        "right" | "rhs" => Some(1u64),
2164                        "op" => Some(0u64),
2165                        "inner" | "expr" => Some(0u64),
2166                        "condition" | "cond" => Some(0u64),
2167                        "then_branch" | "then" => Some(1u64),
2168                        "else_branch" | "else" => Some(2u64),
2169                        "pattern" | "pat" => Some(0u64),
2170                        "iter" | "iterator" => Some(1u64),
2171                        "guard" => Some(1u64),
2172                        "arms" => Some(1u64),
2173                        "scrutinee" => Some(0u64),
2174                        "init" => Some(0u64),
2175                        "receiver" => Some(0u64),
2176                        "method" => Some(1u64),
2177                        "func" => Some(0u64),
2178                        "callee" => Some(0u64),
2179                        "target" => Some(0u64),
2180                        "module" | "mod" => Some(0u64),
2181                        "imports" | "uses" => Some(0u64),
2182                        "exports" => Some(1u64),
2183                        "decls" | "declarations" => Some(0u64),
2184                        "stmts" | "statements" => Some(0u64),
2185                        // AST and compiler-related
2186                        "tree" | "ast" | "root" => Some(0u64),
2187                        "content" | "contents" => Some(0u64),
2188                        "entries" | "elements" | "children" => Some(0u64),
2189                        "parent" => Some(0u64),
2190                        "next" => Some(1u64),
2191                        "prev" => Some(0u64),
2192                        "tokens" => Some(0u64),
2193                        "input" => Some(0u64),
2194                        "output" => Some(1u64),
2195                        "errors" => Some(0u64),
2196                        "warnings" => Some(1u64),
2197                        "result" => Some(0u64),
2198                        "success" => Some(0u64),
2199                        "failure" => Some(1u64),
2200                        "text" | "string" | "str" => Some(0u64),
2201                        "len" | "length" | "count" | "size" => Some(1u64),
2202                        "pos" | "position" => Some(0u64),
2203                        "offset" => Some(0u64),
2204                        "range" => Some(0u64),
2205                        "scope" => Some(0u64),
2206                        "context" | "ctx" => Some(0u64),
2207                        "state" | "status" => Some(0u64),
2208                        "index" | "idx" => Some(0u64),
2209                        "level" => Some(0u64),
2210                        "tomes" | "modules" => Some(0u64),
2211                        "functions" | "fns" => Some(0u64),
2212                        "structs" | "types" => Some(0u64),
2213                        "traits" | "interfaces" => Some(0u64),
2214                        "env" | "environment" => Some(0u64),
2215                        "bindings" => Some(0u64),
2216                        "symbols" => Some(0u64),
2217                        "table" => Some(0u64),
2218                        // More compiler/IR related
2219                        "impls" | "implementations" => Some(0u64),
2220                        "enums" => Some(0u64),
2221                        "consts" | "constants" => Some(0u64),
2222                        "statics" => Some(0u64),
2223                        "uses" | "use_stmts" => Some(0u64),
2224                        "imports" => Some(0u64),
2225                        "exports" => Some(0u64),
2226                        "type_aliases" | "aliases" => Some(0u64),
2227                        "macros" => Some(0u64),
2228                        "generics" | "type_params" => Some(1u64),
2229                        "where_clause" | "bounds" => Some(2u64),
2230                        "receiver" | "self_param" => Some(0u64),
2231                        "params" | "parameters" => Some(1u64),
2232                        "return_ty" | "ret_ty" => Some(2u64),
2233                        "is_pub" | "is_public" => Some(0u64),
2234                        "is_mut" | "is_mutable" => Some(0u64),
2235                        "is_const" | "is_constant" => Some(0u64),
2236                        "is_static" => Some(0u64),
2237                        "is_async" => Some(0u64),
2238                        "is_unsafe" => Some(0u64),
2239                        "declared" | "declarations" => Some(0u64),
2240                        "defined" | "definitions" => Some(1u64),
2241                        "referenced" | "references" => Some(2u64),
2242                        "resolved" => Some(0u64),
2243                        "unresolved" => Some(1u64),
2244                        "pending" => Some(2u64),
2245                        "diagnostics" | "diags" => Some(0u64),
2246                        "notes" => Some(1u64),
2247                        "hints" => Some(2u64),
2248                        "fixes" | "suggestions" => Some(3u64),
2249                        // Impl block related
2250                        "self_ty" | "self_type" | "for_type" => Some(0u64),
2251                        "trait_ref" | "trait_name" | "trait_path" => Some(1u64),
2252                        "associated_items" | "assoc_items" => Some(2u64),
2253                        // Type related
2254                        "inner_ty" | "inner_type" | "elem_ty" | "elem_type" => Some(0u64),
2255                        "key_ty" | "key_type" => Some(0u64),
2256                        "value_ty" | "value_type" => Some(1u64),
2257                        // Variable/binding related
2258                        "mutable" | "is_mutable" | "is_mut" => Some(0u64),
2259                        "evidence" | "evidential" | "evidentiality" => Some(0u64),
2260                        "element" | "elem" | "item" => Some(0u64),
2261                        // More AST fields
2262                        "prefix" => Some(0u64),
2263                        "suffix" => Some(1u64),
2264                        "base" => Some(0u64),
2265                        "index" => Some(0u64),
2266                        "slice_from" => Some(0u64),
2267                        "slice_to" => Some(1u64),
2268                        "callee" | "callable" => Some(0u64),
2269                        "arguments" | "args_list" => Some(1u64),
2270                        "is_async" | "async" => Some(0u64),
2271                        "is_await" | "await" => Some(0u64),
2272                        "is_unsafe" | "unsafe" => Some(0u64),
2273                        "is_move" | "move" => Some(0u64),
2274                        "capture" | "captures" => Some(0u64),
2275                        "label" => Some(0u64),
2276                        "lifetime" => Some(0u64),
2277                        "value" | "val" => Some(0u64),
2278                        "default" | "default_value" => Some(1u64),
2279                        // More compiler fields
2280                        "modulus" | "mod_val" => Some(0u64),
2281                        "no_std" | "nostd" => Some(0u64),
2282                        "patterns" | "pats" => Some(0u64),
2283                        "pos" | "position" | "cursor" => Some(0u64),
2284                        "globals" | "global_vars" => Some(0u64),
2285                        "current_fn_has_mut_self" | "has_mut_self" => Some(0u64),
2286                        "current_fn" | "current_function" => Some(0u64),
2287                        "current_block" | "cur_block" => Some(0u64),
2288                        "current_loop" | "loop_info" => Some(0u64),
2289                        "break_target" | "break_bb" => Some(0u64),
2290                        "continue_target" | "continue_bb" => Some(1u64),
2291                        "return_type" | "ret_type" | "fn_ret_type" => Some(0u64),
2292                        "locals" | "local_vars" => Some(0u64),
2293                        "temps" | "temporaries" => Some(0u64),
2294                        "stack" | "stack_ptr" => Some(0u64),
2295                        "heap" | "heap_ptr" => Some(0u64),
2296                        "output_buffer" | "buf" | "buffer" => Some(0u64),
2297                        "indent" | "indent_level" => Some(0u64),
2298                        "line_start" | "col_start" => Some(0u64),
2299                        "line_end" | "col_end" => Some(1u64),
2300                        "filename" | "file_name" | "filepath" | "file_path" => Some(0u64),
2301                        // Iterator/loop fields
2302                        "iterable" | "collection" | "sequence" => Some(0u64),
2303                        "current" | "curr" => Some(0u64),
2304                        "remaining" | "rest" => Some(1u64),
2305                        "done" | "finished" | "exhausted" => Some(0u64),
2306                        // Closure/function context
2307                        "in_closure_body" | "in_closure" => Some(0u64),
2308                        "in_loop" | "in_loop_body" => Some(0u64),
2309                        "in_async" | "in_async_fn" => Some(0u64),
2310                        // SIMD/vector fields
2311                        "lanes" | "lane_count" => Some(0u64),
2312                        "scalar_type" | "element_type" => Some(1u64),
2313                        // Tuple field access (numeric)
2314                        "0" => Some(0u64),
2315                        "1" => Some(1u64),
2316                        "2" => Some(2u64),
2317                        "3" => Some(3u64),
2318                        "4" => Some(4u64),
2319                        "5" => Some(5u64),
2320                        "6" => Some(6u64),
2321                        "7" => Some(7u64),
2322                        // Range fields
2323                        "inclusive" | "is_inclusive" => Some(0u64),
2324                        "exclusive" | "is_exclusive" => Some(0u64),
2325                        // Operator fields
2326                        "operator" | "op" | "opcode" => Some(0u64),
2327                        "operand" | "operands" => Some(1u64),
2328                        "precedence" | "prec" => Some(2u64),
2329                        "associativity" | "assoc" => Some(3u64),
2330                        // Type checker fields
2331                        "params" | "parameters" | "param_list" => Some(1u64),
2332                        "type_params" | "generic_params" => Some(2u64),
2333                        "constraints" | "where_clause" => Some(3u64),
2334                        // Parse state
2335                        "no_std" | "is_no_std" | "crate_type" => Some(0u64),
2336                        // Function IR fields
2337                        "function" | "fn" | "fn_def" | "fn_decl" => Some(0u64),
2338                        "return_value" | "ret_val" => Some(0u64),
2339                        "basic_blocks" | "blocks" | "bbs" => Some(0u64),
2340                        "entry_block" | "entry" | "entry_bb" => Some(0u64),
2341                        "exit_block" | "exit" | "exit_bb" => Some(1u64),
2342                        "alloca_block" => Some(2u64),
2343                        // Repeated common names with different offsets fallback
2344                        "name" => Some(0u64),
2345                        "pos" => Some(0u64),
2346                        // More IR/codegen fields
2347                        "variant" | "enum_variant" => Some(0u64),
2348                        "operations" | "ops" => Some(0u64),
2349                        "instructions" | "instrs" => Some(0u64),
2350                        // Catch-all for any numeric-ish field that might be an offset
2351                        _ => {
2352                            // Try to parse as numeric field access
2353                            if field_name.chars().all(|c| c.is_numeric()) {
2354                                field_name.parse::<u64>().ok()
2355                            } else {
2356                                None
2357                            }
2358                        }
2359                    };
2360
2361                    if let Some(offset) = field_offset {
2362                        // Calculate field pointer using byte offset
2363                        let offset_val = self.context.i64_type().const_int(offset * 8, false); // 8 bytes per i64
2364                        let struct_ptr_as_int = self
2365                            .builder
2366                            .build_ptr_to_int(struct_ptr, self.context.i64_type(), "ptr_as_int")
2367                            .map_err(|e| e.to_string())?;
2368                        let field_ptr_int = self
2369                            .builder
2370                            .build_int_add(struct_ptr_as_int, offset_val, "field_ptr_int")
2371                            .map_err(|e| e.to_string())?;
2372                        let field_ptr = self
2373                            .builder
2374                            .build_int_to_ptr(
2375                                field_ptr_int,
2376                                ptr_type,
2377                                &format!("{}_ptr", field_name),
2378                            )
2379                            .map_err(|e| e.to_string())?;
2380                        let field_value = self
2381                            .builder
2382                            .build_load(self.context.i64_type(), field_ptr, field_name)
2383                            .map_err(|e| e.to_string())?;
2384                        return Ok(field_value.into_int_value());
2385                    }
2386
2387                    // Fallback: use offset 0 for unknown fields
2388                    // This is lenient but allows compilation to proceed
2389                    let offset_val = self.context.i64_type().const_int(0, false);
2390                    let field_ptr_int = self
2391                        .builder
2392                        .build_int_add(struct_ptr_int, offset_val, "fallback_field_ptr")
2393                        .map_err(|e| e.to_string())?;
2394                    let field_ptr = self
2395                        .builder
2396                        .build_int_to_ptr(field_ptr_int, ptr_type, &format!("{}_ptr", field_name))
2397                        .map_err(|e| e.to_string())?;
2398                    let field_value = self
2399                        .builder
2400                        .build_load(self.context.i64_type(), field_ptr, field_name)
2401                        .map_err(|e| e.to_string())?;
2402                    Ok(field_value.into_int_value())
2403                }
2404                Expr::Match { expr, arms } => {
2405                    // Compile the scrutinee (thing being matched)
2406                    let scrutinee = self.compile_expr(fn_value, scope, expr)?;
2407
2408                    let merge_bb = self.context.append_basic_block(fn_value, "match_merge");
2409                    let mut incoming: Vec<(
2410                        IntValue<'ctx>,
2411                        inkwell::basic_block::BasicBlock<'ctx>,
2412                    )> = Vec::new();
2413
2414                    // Build chain of if-else for each arm
2415                    for (i, arm) in arms.iter().enumerate() {
2416                        // Get pattern discriminant value
2417                        let pattern_val = match &arm.pattern {
2418                            ast::Pattern::Path(path) => {
2419                                if path.segments.len() >= 2 {
2420                                    let enum_name =
2421                                        &path.segments[path.segments.len() - 2].ident.name;
2422                                    let variant_name =
2423                                        &path.segments[path.segments.len() - 1].ident.name;
2424                                    if let Some(enum_info) = self.enum_types.get(enum_name) {
2425                                        enum_info.variants.get(variant_name).copied()
2426                                    } else {
2427                                        None
2428                                    }
2429                                } else {
2430                                    None
2431                                }
2432                            }
2433                            ast::Pattern::Literal(lit) => {
2434                                if let Ok(v) = self.compile_literal(lit) {
2435                                    Some(v.get_zero_extended_constant().unwrap_or(0))
2436                                } else {
2437                                    None
2438                                }
2439                            }
2440                            ast::Pattern::Wildcard => None,
2441                            _ => None,
2442                        };
2443
2444                        let then_bb = self
2445                            .context
2446                            .append_basic_block(fn_value, &format!("match_then_{}", i));
2447                        let else_bb = if i + 1 < arms.len() {
2448                            self.context
2449                                .append_basic_block(fn_value, &format!("match_else_{}", i))
2450                        } else {
2451                            merge_bb
2452                        };
2453
2454                        // For the last arm or wildcard, always branch unconditionally
2455                        let is_last_arm = i + 1 >= arms.len();
2456                        if let Some(disc) = pattern_val {
2457                            if is_last_arm {
2458                                // Last arm - treat as default (exhaustive match assumed)
2459                                self.builder
2460                                    .build_unconditional_branch(then_bb)
2461                                    .map_err(|e| e.to_string())?;
2462                            } else {
2463                                let pattern_const = self.context.i64_type().const_int(disc, false);
2464                                let cond = self
2465                                    .builder
2466                                    .build_int_compare(
2467                                        IntPredicate::EQ,
2468                                        scrutinee,
2469                                        pattern_const,
2470                                        "match_cmp",
2471                                    )
2472                                    .map_err(|e| e.to_string())?;
2473                                self.builder
2474                                    .build_conditional_branch(cond, then_bb, else_bb)
2475                                    .map_err(|e| e.to_string())?;
2476                            }
2477                        } else {
2478                            // Wildcard - unconditionally go to then block
2479                            self.builder
2480                                .build_unconditional_branch(then_bb)
2481                                .map_err(|e| e.to_string())?;
2482                        }
2483
2484                        // Compile the arm body
2485                        self.builder.position_at_end(then_bb);
2486
2487                        // Extract pattern bindings and add to scope
2488                        // For patterns like `Enum::Variant { field1, field2 }` or `Enum::Variant(x)`
2489                        match &arm.pattern {
2490                            ast::Pattern::TupleStruct {
2491                                path: _, fields, ..
2492                            } => {
2493                                // Bind each field pattern as a variable
2494                                // For simplicity, assume scrutinee is a pointer to struct data
2495                                for (i, field_pattern) in fields.iter().enumerate() {
2496                                    if let ast::Pattern::Ident { name, .. } = field_pattern {
2497                                        // Create a variable for this binding
2498                                        // For enums with data, field 0 is often at offset 8 (after tag)
2499                                        let offset = (i as u64 + 1) * 8; // Skip tag byte
2500                                        let offset_val =
2501                                            self.context.i64_type().const_int(offset, false);
2502
2503                                        let ptr_type =
2504                                            self.context.ptr_type(inkwell::AddressSpace::default());
2505                                        let scrutinee_ptr = self
2506                                            .builder
2507                                            .build_int_to_ptr(scrutinee, ptr_type, "scrutinee_ptr")
2508                                            .map_err(|e| e.to_string())?;
2509                                        let scrutinee_int = self
2510                                            .builder
2511                                            .build_ptr_to_int(
2512                                                scrutinee_ptr,
2513                                                self.context.i64_type(),
2514                                                "scr_int",
2515                                            )
2516                                            .map_err(|e| e.to_string())?;
2517                                        let field_ptr_int = self
2518                                            .builder
2519                                            .build_int_add(
2520                                                scrutinee_int,
2521                                                offset_val,
2522                                                "field_ptr_int",
2523                                            )
2524                                            .map_err(|e| e.to_string())?;
2525                                        let field_ptr = self
2526                                            .builder
2527                                            .build_int_to_ptr(
2528                                                field_ptr_int,
2529                                                ptr_type,
2530                                                &format!("{}_ptr", name.name),
2531                                            )
2532                                            .map_err(|e| e.to_string())?;
2533                                        let field_val = self
2534                                            .builder
2535                                            .build_load(
2536                                                self.context.i64_type(),
2537                                                field_ptr,
2538                                                &name.name,
2539                                            )
2540                                            .map_err(|e| e.to_string())?;
2541
2542                                        let alloca = self
2543                                            .builder
2544                                            .build_alloca(self.context.i64_type(), &name.name)
2545                                            .map_err(|e| e.to_string())?;
2546                                        self.builder
2547                                            .build_store(alloca, field_val)
2548                                            .map_err(|e| e.to_string())?;
2549                                        scope.vars.insert(name.name.clone(), alloca);
2550                                    }
2551                                }
2552                            }
2553                            ast::Pattern::Struct {
2554                                path: _, fields, ..
2555                            } => {
2556                                // Bind each field pattern as a variable
2557                                for (i, field_pattern) in fields.iter().enumerate() {
2558                                    // Get binding name: use pattern if present, else use field name (shorthand)
2559                                    let binding_name = if let Some(ref pat) = field_pattern.pattern
2560                                    {
2561                                        if let ast::Pattern::Ident { name, .. } = pat {
2562                                            Some(name.name.clone())
2563                                        } else {
2564                                            None
2565                                        }
2566                                    } else {
2567                                        // Shorthand: `{ prefix }` means bind field_pattern.name
2568                                        Some(field_pattern.name.name.clone())
2569                                    };
2570
2571                                    if let Some(name) = binding_name {
2572                                        // Use field index for offset
2573                                        let offset = (i as u64 + 1) * 8;
2574                                        let offset_val =
2575                                            self.context.i64_type().const_int(offset, false);
2576
2577                                        let ptr_type =
2578                                            self.context.ptr_type(inkwell::AddressSpace::default());
2579                                        let scrutinee_ptr = self
2580                                            .builder
2581                                            .build_int_to_ptr(scrutinee, ptr_type, "scrutinee_ptr")
2582                                            .map_err(|e| e.to_string())?;
2583                                        let scrutinee_int = self
2584                                            .builder
2585                                            .build_ptr_to_int(
2586                                                scrutinee_ptr,
2587                                                self.context.i64_type(),
2588                                                "scr_int",
2589                                            )
2590                                            .map_err(|e| e.to_string())?;
2591                                        let field_ptr_int = self
2592                                            .builder
2593                                            .build_int_add(
2594                                                scrutinee_int,
2595                                                offset_val,
2596                                                "field_ptr_int",
2597                                            )
2598                                            .map_err(|e| e.to_string())?;
2599                                        let field_ptr = self
2600                                            .builder
2601                                            .build_int_to_ptr(
2602                                                field_ptr_int,
2603                                                ptr_type,
2604                                                &format!("{}_ptr", name),
2605                                            )
2606                                            .map_err(|e| e.to_string())?;
2607                                        let field_val = self
2608                                            .builder
2609                                            .build_load(self.context.i64_type(), field_ptr, &name)
2610                                            .map_err(|e| e.to_string())?;
2611
2612                                        let alloca = self
2613                                            .builder
2614                                            .build_alloca(self.context.i64_type(), &name)
2615                                            .map_err(|e| e.to_string())?;
2616                                        self.builder
2617                                            .build_store(alloca, field_val)
2618                                            .map_err(|e| e.to_string())?;
2619                                        scope.vars.insert(name, alloca);
2620                                    }
2621                                }
2622                            }
2623                            ast::Pattern::Ident { name, .. } => {
2624                                // Simple binding - bind the entire scrutinee
2625                                let alloca = self
2626                                    .builder
2627                                    .build_alloca(self.context.i64_type(), &name.name)
2628                                    .map_err(|e| e.to_string())?;
2629                                self.builder
2630                                    .build_store(alloca, scrutinee)
2631                                    .map_err(|e| e.to_string())?;
2632                                scope.vars.insert(name.name.clone(), alloca);
2633                            }
2634                            _ => {}
2635                        }
2636
2637                        let arm_val = self.compile_expr(fn_value, scope, &arm.body)?;
2638
2639                        if self
2640                            .builder
2641                            .get_insert_block()
2642                            .unwrap()
2643                            .get_terminator()
2644                            .is_none()
2645                        {
2646                            let current_bb = self.builder.get_insert_block().unwrap();
2647                            self.builder
2648                                .build_unconditional_branch(merge_bb)
2649                                .map_err(|e| e.to_string())?;
2650                            incoming.push((arm_val, current_bb));
2651                        }
2652
2653                        // Position at else block for next iteration
2654                        if i + 1 < arms.len() {
2655                            self.builder.position_at_end(else_bb);
2656                        }
2657                    }
2658
2659                    // Build phi at merge
2660                    self.builder.position_at_end(merge_bb);
2661
2662                    if incoming.is_empty() {
2663                        // All arms returned early - merge block is unreachable
2664                        // Delete the empty merge block and return dummy value
2665                        // The actual return happens in the arms themselves
2666                        unsafe {
2667                            merge_bb
2668                                .delete()
2669                                .map_err(|_| "Failed to delete unreachable merge block")?;
2670                        }
2671                        return Ok(self.context.i64_type().const_int(0, false));
2672                    }
2673
2674                    let phi = self
2675                        .builder
2676                        .build_phi(self.context.i64_type(), "match_result")
2677                        .map_err(|e| e.to_string())?;
2678
2679                    for (val, bb) in &incoming {
2680                        phi.add_incoming(&[(val, *bb)]);
2681                    }
2682
2683                    Ok(phi.as_basic_value().into_int_value())
2684                }
2685                Expr::MethodCall {
2686                    receiver,
2687                    method,
2688                    args,
2689                    ..
2690                } => {
2691                    // Compile the receiver
2692                    let receiver_val = self.compile_expr(fn_value, scope, receiver)?;
2693                    let method_name = method.name.as_str();
2694
2695                    // Handle built-in Vec methods
2696                    match method_name {
2697                        "push" => {
2698                            // v.push(val) -> sigil_vec_push(v, val)
2699                            if args.is_empty() {
2700                                return Err("push requires a value argument".to_string());
2701                            }
2702                            let value = self.compile_expr(fn_value, scope, &args[0])?;
2703                            let push_fn = self
2704                                .module
2705                                .get_function("sigil_vec_push")
2706                                .ok_or("sigil_vec_push not declared")?;
2707                            self.builder
2708                                .build_call(push_fn, &[receiver_val.into(), value.into()], "")
2709                                .map_err(|e| e.to_string())?;
2710                            return Ok(self.context.i64_type().const_int(0, false));
2711                        }
2712                        "len" => {
2713                            // v.len() -> sigil_vec_len(v)
2714                            let len_fn = self
2715                                .module
2716                                .get_function("sigil_vec_len")
2717                                .ok_or("sigil_vec_len not declared")?;
2718                            let call = self
2719                                .builder
2720                                .build_call(len_fn, &[receiver_val.into()], "vec_len")
2721                                .map_err(|e| e.to_string())?;
2722                            return Ok(call
2723                                .try_as_basic_value()
2724                                .left()
2725                                .map(|v| v.into_int_value())
2726                                .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
2727                        }
2728                        "get" => {
2729                            // v.get(idx) -> sigil_vec_get(v, idx)
2730                            if args.is_empty() {
2731                                return Err("get requires an index argument".to_string());
2732                            }
2733                            let index = self.compile_expr(fn_value, scope, &args[0])?;
2734                            let get_fn = self
2735                                .module
2736                                .get_function("sigil_vec_get")
2737                                .ok_or("sigil_vec_get not declared")?;
2738                            let call = self
2739                                .builder
2740                                .build_call(get_fn, &[receiver_val.into(), index.into()], "vec_get")
2741                                .map_err(|e| e.to_string())?;
2742                            return Ok(call
2743                                .try_as_basic_value()
2744                                .left()
2745                                .map(|v| v.into_int_value())
2746                                .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
2747                        }
2748                        "iter" => {
2749                            // v.iter() returns the array/vec itself for iteration
2750                            // In Sigil, .iter() is an identity operation that signals
2751                            // the value should be iterated over in a for loop
2752                            return Ok(receiver_val);
2753                        }
2754                        "clone" => {
2755                            // For now, clone is identity (shallow copy semantics)
2756                            // TODO: Implement proper deep clone via runtime
2757                            return Ok(receiver_val);
2758                        }
2759                        "is_empty" => {
2760                            // v.is_empty() -> v.len() == 0
2761                            let len_fn = self
2762                                .module
2763                                .get_function("sigil_vec_len")
2764                                .ok_or("sigil_vec_len not declared")?;
2765                            let call = self
2766                                .builder
2767                                .build_call(len_fn, &[receiver_val.into()], "vec_len")
2768                                .map_err(|e| e.to_string())?;
2769                            let len = call
2770                                .try_as_basic_value()
2771                                .left()
2772                                .map(|v| v.into_int_value())
2773                                .unwrap_or_else(|| self.context.i64_type().const_int(0, false));
2774                            let zero = self.context.i64_type().const_int(0, false);
2775                            let is_empty = self
2776                                .builder
2777                                .build_int_compare(IntPredicate::EQ, len, zero, "is_empty")
2778                                .map_err(|e| e.to_string())?;
2779                            // Convert bool (i1) to i64
2780                            let result = self
2781                                .builder
2782                                .build_int_z_extend(
2783                                    is_empty,
2784                                    self.context.i64_type(),
2785                                    "is_empty_i64",
2786                                )
2787                                .map_err(|e| e.to_string())?;
2788                            return Ok(result);
2789                        }
2790                        // String methods
2791                        "starts_with" => {
2792                            if args.is_empty() {
2793                                return Err("starts_with requires a prefix argument".to_string());
2794                            }
2795                            let prefix = self.compile_expr(fn_value, scope, &args[0])?;
2796                            let fn_name = "sigil_string_starts_with";
2797                            if let Some(callee) = self.module.get_function(fn_name) {
2798                                let call = self
2799                                    .builder
2800                                    .build_call(
2801                                        callee,
2802                                        &[receiver_val.into(), prefix.into()],
2803                                        "starts_with",
2804                                    )
2805                                    .map_err(|e| e.to_string())?;
2806                                return Ok(call
2807                                    .try_as_basic_value()
2808                                    .left()
2809                                    .map(|v| v.into_int_value())
2810                                    .unwrap_or_else(|| {
2811                                        self.context.i64_type().const_int(0, false)
2812                                    }));
2813                            }
2814                            // Fallback: return false (0)
2815                            return Ok(self.context.i64_type().const_int(0, false));
2816                        }
2817                        "to_string" => {
2818                            // For primitives, convert to string representation
2819                            // For now, return the value itself (strings are already strings)
2820                            return Ok(receiver_val);
2821                        }
2822                        "as_str" | "as_ref" => {
2823                            // String -> &str conversion is identity in our representation
2824                            return Ok(receiver_val);
2825                        }
2826                        "chars" => {
2827                            // s.chars() -> sigil_string_chars(s)
2828                            let fn_name = "sigil_string_chars";
2829                            if let Some(callee) = self.module.get_function(fn_name) {
2830                                let call = self
2831                                    .builder
2832                                    .build_call(callee, &[receiver_val.into()], "chars")
2833                                    .map_err(|e| e.to_string())?;
2834                                return Ok(call
2835                                    .try_as_basic_value()
2836                                    .left()
2837                                    .map(|v| v.into_int_value())
2838                                    .unwrap_or_else(|| {
2839                                        self.context.i64_type().const_int(0, false)
2840                                    }));
2841                            }
2842                            return Ok(receiver_val);
2843                        }
2844                        "collect" => {
2845                            // Iterator collect - for now return the iterator itself
2846                            return Ok(receiver_val);
2847                        }
2848                        "skip" => {
2849                            // Iterator skip(n) - would need runtime support
2850                            // For now, return the iterator
2851                            return Ok(receiver_val);
2852                        }
2853                        "unwrap" => {
2854                            // Option/Result unwrap - return inner value
2855                            // In our simplified model, just return the value
2856                            return Ok(receiver_val);
2857                        }
2858                        "unwrap_or" => {
2859                            // Option/Result unwrap_or(default) - simplified
2860                            return Ok(receiver_val);
2861                        }
2862                        "is_some" | "is_ok" => {
2863                            // For simplicity, return true (1)
2864                            return Ok(self.context.i64_type().const_int(1, false));
2865                        }
2866                        "is_none" | "is_err" => {
2867                            // For simplicity, return false (0)
2868                            return Ok(self.context.i64_type().const_int(0, false));
2869                        }
2870                        "push_str" => {
2871                            // s.push_str(other) - append string
2872                            if args.is_empty() {
2873                                return Err("push_str requires a string argument".to_string());
2874                            }
2875                            let other = self.compile_expr(fn_value, scope, &args[0])?;
2876                            if let Some(callee) = self.module.get_function("sigil_string_push_str")
2877                            {
2878                                let call = self
2879                                    .builder
2880                                    .build_call(
2881                                        callee,
2882                                        &[receiver_val.into(), other.into()],
2883                                        "push_str",
2884                                    )
2885                                    .map_err(|e| e.to_string())?;
2886                                return Ok(call
2887                                    .try_as_basic_value()
2888                                    .left()
2889                                    .map(|v| v.into_int_value())
2890                                    .unwrap_or_else(|| {
2891                                        self.context.i64_type().const_int(0, false)
2892                                    }));
2893                            }
2894                            // Fallback: return the string unchanged
2895                            return Ok(receiver_val);
2896                        }
2897                        "push" => {
2898                            // s.push(char) or vec.push(item)
2899                            if args.is_empty() {
2900                                return Err("push requires an argument".to_string());
2901                            }
2902                            let item = self.compile_expr(fn_value, scope, &args[0])?;
2903                            // Try vec push first
2904                            if let Some(callee) = self.module.get_function("sigil_vec_push") {
2905                                self.builder
2906                                    .build_call(
2907                                        callee,
2908                                        &[receiver_val.into(), item.into()],
2909                                        "vec_push",
2910                                    )
2911                                    .map_err(|e| e.to_string())?;
2912                                return Ok(receiver_val);
2913                            }
2914                            return Ok(receiver_val);
2915                        }
2916                        "contains" => {
2917                            // s.contains(substr) or vec.contains(item)
2918                            if args.is_empty() {
2919                                return Err("contains requires an argument".to_string());
2920                            }
2921                            let needle = self.compile_expr(fn_value, scope, &args[0])?;
2922                            if let Some(callee) = self.module.get_function("sigil_string_contains")
2923                            {
2924                                let call = self
2925                                    .builder
2926                                    .build_call(
2927                                        callee,
2928                                        &[receiver_val.into(), needle.into()],
2929                                        "contains",
2930                                    )
2931                                    .map_err(|e| e.to_string())?;
2932                                return Ok(call
2933                                    .try_as_basic_value()
2934                                    .left()
2935                                    .map(|v| v.into_int_value())
2936                                    .unwrap_or_else(|| {
2937                                        self.context.i64_type().const_int(0, false)
2938                                    }));
2939                            }
2940                            // Fallback: return false
2941                            return Ok(self.context.i64_type().const_int(0, false));
2942                        }
2943                        "trim" | "trim_start" | "trim_end" => {
2944                            // String trim methods - for now return the string unchanged
2945                            return Ok(receiver_val);
2946                        }
2947                        "split" | "lines" => {
2948                            // String split methods - return iterator (same as string for now)
2949                            return Ok(receiver_val);
2950                        }
2951                        "join" => {
2952                            // vec.join(sep) - for now return empty string
2953                            if let Some(callee) = self.module.get_function("sigil_string_new") {
2954                                let call = self
2955                                    .builder
2956                                    .build_call(callee, &[], "join_result")
2957                                    .map_err(|e| e.to_string())?;
2958                                return Ok(call
2959                                    .try_as_basic_value()
2960                                    .left()
2961                                    .map(|v| v.into_int_value())
2962                                    .unwrap_or_else(|| {
2963                                        self.context.i64_type().const_int(0, false)
2964                                    }));
2965                            }
2966                            return Ok(self.context.i64_type().const_int(0, false));
2967                        }
2968                        _ => {}
2969                    }
2970
2971                    // Look up the method by trying all registered impl methods
2972                    // For now, try each type until we find a match
2973                    for ((_type_name, meth_name), mangled_name) in &self.impl_methods {
2974                        if meth_name == method_name {
2975                            if let Some(callee) = self.module.get_function(mangled_name) {
2976                                // Compile arguments
2977                                let mut compiled_args: Vec<BasicMetadataValueEnum> =
2978                                    vec![receiver_val.into()];
2979                                for arg in args {
2980                                    let arg_val = self.compile_expr(fn_value, scope, arg)?;
2981                                    compiled_args.push(arg_val.into());
2982                                }
2983
2984                                let call = self
2985                                    .builder
2986                                    .build_call(callee, &compiled_args, "method_call")
2987                                    .map_err(|e| e.to_string())?;
2988
2989                                return Ok(call
2990                                    .try_as_basic_value()
2991                                    .left()
2992                                    .map(|v| v.into_int_value())
2993                                    .unwrap_or_else(|| {
2994                                        self.context.i64_type().const_int(0, false)
2995                                    }));
2996                            }
2997                        }
2998                    }
2999
3000                    // Fallback: Try to call as a method that mutates/accesses the receiver
3001                    // Many methods like `collect_type_def`, `check`, etc. just return unit or
3002                    // are side-effecting methods that we can stub as no-ops
3003                    let method_lower = method_name.to_lowercase();
3004                    if method_lower.starts_with("collect")
3005                        || method_lower.starts_with("check")
3006                        || method_lower.starts_with("validate")
3007                        || method_lower.starts_with("verify")
3008                        || method_lower.starts_with("register")
3009                        || method_lower.starts_with("add")
3010                        || method_lower.starts_with("insert")
3011                        || method_lower.starts_with("remove")
3012                        || method_lower.starts_with("clear")
3013                        || method_lower.starts_with("reset")
3014                        || method_lower.starts_with("update")
3015                        || method_lower.starts_with("set")
3016                        || method_lower.starts_with("process")
3017                        || method_lower.starts_with("analyze")
3018                        || method_lower.starts_with("visit")
3019                        || method_lower.starts_with("emit")
3020                        || method_lower.starts_with("write")
3021                        || method_lower.starts_with("flush")
3022                        || method_lower.starts_with("sync")
3023                        || method_lower.starts_with("close")
3024                        || method_lower.starts_with("finish")
3025                        || method_lower.starts_with("complete")
3026                        || method_lower.starts_with("init")
3027                        || method_lower.starts_with("setup")
3028                        || method_lower.starts_with("configure")
3029                    {
3030                        // Side-effecting methods - return unit (0)
3031                        return Ok(self.context.i64_type().const_int(0, false));
3032                    }
3033
3034                    // Methods that likely return the receiver (builder pattern)
3035                    if method_lower.starts_with("with_")
3036                        || method_lower.starts_with("and_")
3037                        || method_lower == "build"
3038                        || method_lower == "done"
3039                    {
3040                        return Ok(receiver_val);
3041                    }
3042
3043                    // Methods that likely return a bool
3044                    if method_lower.starts_with("is_")
3045                        || method_lower.starts_with("has_")
3046                        || method_lower.starts_with("can_")
3047                        || method_lower.starts_with("should_")
3048                        || method_lower == "exists"
3049                        || method_lower == "contains"
3050                    {
3051                        // Return false (0) as default
3052                        return Ok(self.context.i64_type().const_int(0, false));
3053                    }
3054
3055                    // Methods that likely return the receiver or a reference to internal data
3056                    if method_lower.starts_with("get_")
3057                        || method_lower.starts_with("find_")
3058                        || method_lower.starts_with("lookup_")
3059                        || method_lower == "get"
3060                        || method_lower == "take"
3061                        || method_lower == "borrow"
3062                    {
3063                        // Return receiver as placeholder for accessed data
3064                        return Ok(receiver_val);
3065                    }
3066
3067                    // Default fallback - return 0 as unit
3068                    // eprintln!("DEBUG: Unknown method '{}' - treating as no-op", method_name);
3069                    return Ok(self.context.i64_type().const_int(0, false));
3070                }
3071                // ============================================
3072                // Sigil-native expressions
3073                // ============================================
3074
3075                // Evidentiality markers with runtime semantics
3076                // Known (!) unwraps evidential values
3077                // Other markers wrap values with evidence tags
3078                Expr::Evidential {
3079                    expr,
3080                    evidentiality,
3081                } => {
3082                    let inner_val = self.compile_expr(fn_value, scope, expr)?;
3083
3084                    match evidentiality {
3085                        ast::Evidentiality::Known => {
3086                            // Known (!) is an unwrap operation - just return the inner value
3087                            // The type checker ensures this is safe
3088                            Ok(inner_val)
3089                        }
3090                        _ => {
3091                            // For ?, ~, ◊, ‽: Create evidential struct and return value
3092                            // The struct stores {tag, value} for runtime evidence tracking
3093                            let tag = Self::evidentiality_to_tag(evidentiality);
3094                            let evidential = self.create_evidential_value(
3095                                fn_value, inner_val, tag, "i64", // Default to i64 for now
3096                            )?;
3097
3098                            // Extract and return the value portion for IntValue compatibility
3099                            // The full struct is available through the scope for advanced operations
3100                            self.unwrap_evidential_value(evidential)
3101                        }
3102                    }
3103                }
3104
3105                // Pipe expressions: data |τ{f} |φ{p} |ρ+
3106                Expr::Pipe { expr, operations } => {
3107                    self.compile_pipe(fn_value, scope, expr, operations)
3108                }
3109
3110                // Standalone morpheme expressions
3111                Expr::Morpheme { kind: _, body } => {
3112                    // Morpheme body is compiled directly
3113                    self.compile_expr(fn_value, scope, body)
3114                }
3115
3116                // Array/slice indexing
3117                Expr::Index { expr, index } => self.compile_index(fn_value, scope, expr, index),
3118
3119                // Range expressions
3120                Expr::Range {
3121                    start,
3122                    end,
3123                    inclusive: _,
3124                } => {
3125                    // For now, ranges compile to their start value
3126                    // Full range support needs iterator infrastructure
3127                    if let Some(s) = start {
3128                        self.compile_expr(fn_value, scope, s)
3129                    } else if let Some(e) = end {
3130                        self.compile_expr(fn_value, scope, e)
3131                    } else {
3132                        Ok(self.context.i64_type().const_int(0, false))
3133                    }
3134                }
3135
3136                // Closures - compile body with captured variables
3137                Expr::Closure {
3138                    params: _, body, ..
3139                } => {
3140                    // For simple closures, just compile the body
3141                    // Full closure support needs lambda lifting
3142                    self.compile_expr(fn_value, scope, body)
3143                }
3144
3145                // Cast/type coercion
3146                Expr::Cast { expr, .. } => {
3147                    // Types are erased, just compile the expression
3148                    self.compile_expr(fn_value, scope, expr)
3149                }
3150
3151                // Address-of: &expr, &mut expr
3152                Expr::AddrOf { expr, .. } => self.compile_expr(fn_value, scope, expr),
3153
3154                // Dereference: *ptr
3155                Expr::Deref(inner) => {
3156                    // Dereference: load value from pointer
3157                    let ptr_val = self.compile_expr(fn_value, scope, inner)?;
3158                    let ptr = self
3159                        .builder
3160                        .build_int_to_ptr(
3161                            ptr_val,
3162                            self.context.ptr_type(AddressSpace::default()),
3163                            "deref_ptr",
3164                        )
3165                        .map_err(|e| e.to_string())?;
3166                    let loaded = self
3167                        .builder
3168                        .build_load(self.context.i64_type(), ptr, "deref_val")
3169                        .map_err(|e| e.to_string())?;
3170                    Ok(loaded.into_int_value())
3171                }
3172
3173                // Macro invocation - handle println!, print!, format!, etc.
3174                Expr::Macro { path, tokens } => {
3175                    let macro_name = path
3176                        .segments
3177                        .last()
3178                        .map(|s| s.ident.name.trim_end_matches('!'))
3179                        .unwrap_or("unknown");
3180
3181                    match macro_name {
3182                        "println" | "print" => {
3183                            self.compile_print_macro(
3184                                fn_value,
3185                                scope,
3186                                tokens,
3187                                macro_name == "println",
3188                            )?;
3189                            Ok(self.context.i64_type().const_int(0, false))
3190                        }
3191                        "format" => {
3192                            // format! returns a String - for now just return 0
3193                            // TODO: implement proper string formatting
3194                            Ok(self.context.i64_type().const_int(0, false))
3195                        }
3196                        "vec" => {
3197                            // vec![...] - parse and create Vec
3198                            // TODO: implement vec macro
3199                            Ok(self.context.i64_type().const_int(0, false))
3200                        }
3201                        "panic" => {
3202                            // For now, just exit with code 1
3203                            // TODO: print panic message first
3204                            let exit_fn = self.module.get_function("sigil_exit");
3205                            if let Some(f) = exit_fn {
3206                                let one = self.context.i64_type().const_int(1, false);
3207                                self.builder
3208                                    .build_call(f, &[one.into()], "")
3209                                    .map_err(|e| e.to_string())?;
3210                            }
3211                            Ok(self.context.i64_type().const_int(0, false))
3212                        }
3213                        "assert" | "assert_eq" | "assert_ne" => {
3214                            // TODO: implement assertions
3215                            Ok(self.context.i64_type().const_int(0, false))
3216                        }
3217                        _ => {
3218                            // Unknown macro - try to call as function
3219                            if let Some(f) = self.module.get_function(macro_name) {
3220                                let call = self
3221                                    .builder
3222                                    .build_call(f, &[], "macro_call")
3223                                    .map_err(|e| e.to_string())?;
3224                                Ok(call
3225                                    .try_as_basic_value()
3226                                    .left()
3227                                    .map(|v| v.into_int_value())
3228                                    .unwrap_or_else(|| self.context.i64_type().const_int(0, false)))
3229                            } else {
3230                                Ok(self.context.i64_type().const_int(0, false))
3231                            }
3232                        }
3233                    }
3234                }
3235
3236                // Try expression: expr?
3237                Expr::Try(inner) => {
3238                    // Types erased, just compile inner
3239                    self.compile_expr(fn_value, scope, inner)
3240                }
3241
3242                // Let expression (for if-let patterns)
3243                Expr::Let { value, .. } => self.compile_expr(fn_value, scope, value),
3244
3245                // Tuple: just return first element for now
3246                Expr::Tuple(elements) => {
3247                    if let Some(first) = elements.first() {
3248                        self.compile_expr(fn_value, scope, first)
3249                    } else {
3250                        Ok(self.context.i64_type().const_int(0, false))
3251                    }
3252                }
3253
3254                // Array literal: allocate on stack and store elements
3255                Expr::Array(elements) => self.compile_array_literal(fn_value, scope, elements),
3256
3257                // Loop expressions
3258                Expr::Loop { body, .. } => {
3259                    let result = self.compile_block(fn_value, scope, body)?;
3260                    Ok(result.unwrap_or_else(|| self.context.i64_type().const_int(0, false)))
3261                }
3262
3263                Expr::For {
3264                    pattern,
3265                    iter,
3266                    body,
3267                    ..
3268                } => self.compile_for_loop(fn_value, scope, pattern, iter, body),
3269
3270                // Break/Continue - just return 0
3271                Expr::Break { .. } | Expr::Continue { .. } => {
3272                    Ok(self.context.i64_type().const_int(0, false))
3273                }
3274
3275                // Unsafe block - compile the block
3276                Expr::Unsafe(block) => {
3277                    let result = self.compile_block(fn_value, scope, block)?;
3278                    Ok(result.unwrap_or_else(|| self.context.i64_type().const_int(0, false)))
3279                }
3280
3281                // Await - compile inner
3282                Expr::Await { expr, .. } => self.compile_expr(fn_value, scope, expr),
3283
3284                _ => {
3285                    // Unsupported expression - return error instead of silent 0
3286                    Err(format!(
3287                        "LLVM codegen: unsupported expression {:?}",
3288                        std::mem::discriminant(expr)
3289                    ))
3290                }
3291            }
3292        }
3293
3294        /// Parse an integer literal with support for hex, binary, octal, and type suffixes
3295        fn parse_int_literal(&self, value: &str) -> Result<u64, String> {
3296            // Strip underscores (visual separators)
3297            let s = value.replace('_', "");
3298
3299            // Strip known type suffixes (must check longer ones first)
3300            let suffixes = [
3301                "isize", "usize", "i128", "u128", "i64", "u64", "i32", "u32", "i16", "u16", "i8",
3302                "u8",
3303            ];
3304            let s = suffixes.iter().fold(s, |acc, suffix| {
3305                if acc.ends_with(suffix) {
3306                    acc[..acc.len() - suffix.len()].to_string()
3307                } else {
3308                    acc
3309                }
3310            });
3311
3312            // Parse based on prefix
3313            if s.starts_with("0x") || s.starts_with("0X") {
3314                u64::from_str_radix(&s[2..], 16)
3315                    .map_err(|_| format!("Invalid hex integer: {}", value))
3316            } else if s.starts_with("0b") || s.starts_with("0B") {
3317                u64::from_str_radix(&s[2..], 2)
3318                    .map_err(|_| format!("Invalid binary integer: {}", value))
3319            } else if s.starts_with("0o") || s.starts_with("0O") {
3320                u64::from_str_radix(&s[2..], 8)
3321                    .map_err(|_| format!("Invalid octal integer: {}", value))
3322            } else {
3323                s.parse::<u64>()
3324                    .or_else(|_| {
3325                        // Try parsing as signed and reinterpreting
3326                        s.parse::<i64>().map(|v| v as u64)
3327                    })
3328                    .map_err(|_| format!("Invalid integer: {}", value))
3329            }
3330        }
3331
3332        /// Compile a literal
3333        fn compile_literal(&mut self, lit: &Literal) -> Result<IntValue<'ctx>, String> {
3334            match lit {
3335                Literal::Int { value, .. } => {
3336                    // Parse integer with support for hex, binary, octal, and type suffixes
3337                    let v = self.parse_int_literal(value)?;
3338                    Ok(self.context.i64_type().const_int(v, false))
3339                }
3340                Literal::Bool(b) => Ok(self
3341                    .context
3342                    .i64_type()
3343                    .const_int(if *b { 1 } else { 0 }, false)),
3344                Literal::Float { value, .. } => {
3345                    // Convert float to int bits for now
3346                    // Strip underscores (visual separators) and type suffix (f32, f64)
3347                    let s = value.replace('_', "");
3348                    let s = s.trim_end_matches("f64").trim_end_matches("f32");
3349                    let v: f64 = s.parse().map_err(|_| format!("Invalid float: {}", value))?;
3350                    Ok(self.context.i64_type().const_int(v.to_bits(), false))
3351                }
3352                Literal::String(s) => {
3353                    // Create a global string constant
3354                    let counter = self.string_counter.get();
3355                    self.string_counter.set(counter + 1);
3356                    let global_name = format!(".str.{}", counter);
3357
3358                    // Create the string constant with null terminator
3359                    let string_bytes = s.as_bytes();
3360                    let const_array = self.context.const_string(string_bytes, true);
3361
3362                    // Create global variable
3363                    let global = self
3364                        .module
3365                        .add_global(const_array.get_type(), None, &global_name);
3366                    global.set_initializer(&const_array);
3367                    global.set_constant(true);
3368                    global.set_linkage(inkwell::module::Linkage::Private);
3369
3370                    // Return pointer as i64
3371                    let ptr = global.as_pointer_value();
3372                    let ptr_as_int = self
3373                        .builder
3374                        .build_ptr_to_int(ptr, self.context.i64_type(), "str_ptr")
3375                        .map_err(|e| e.to_string())?;
3376                    Ok(ptr_as_int)
3377                }
3378                Literal::Char(c) => Ok(self.context.i64_type().const_int(*c as u64, false)),
3379                _ => Ok(self.context.i64_type().const_int(0, false)),
3380            }
3381        }
3382
3383        /// Compile a pipe expression: data |τ{f} |φ{p} |ρ+
3384        fn compile_pipe(
3385            &mut self,
3386            fn_value: FunctionValue<'ctx>,
3387            scope: &mut CompileScope<'ctx>,
3388            expr: &Expr,
3389            operations: &[ast::PipeOp],
3390        ) -> Result<IntValue<'ctx>, String> {
3391            use ast::PipeOp;
3392
3393            // Special case: [a, b, c, ...] |op patterns - we know the array length
3394            if let Expr::Array(elements) = expr {
3395                // Handle single operations
3396                if operations.len() == 1 {
3397                    match &operations[0] {
3398                        PipeOp::ReduceSum => {
3399                            return self.compile_array_sum(fn_value, scope, elements);
3400                        }
3401                        PipeOp::ReduceProd => {
3402                            return self.compile_array_product(fn_value, scope, elements);
3403                        }
3404                        PipeOp::Transform(closure) => {
3405                            return self
3406                                .compile_array_transform(fn_value, scope, elements, closure);
3407                        }
3408                        PipeOp::Filter(predicate) => {
3409                            return self.compile_array_filter(fn_value, scope, elements, predicate);
3410                        }
3411                        PipeOp::First => {
3412                            return self.compile_array_first(fn_value, scope, elements);
3413                        }
3414                        PipeOp::Last => {
3415                            return self.compile_array_last(fn_value, scope, elements);
3416                        }
3417                        PipeOp::Nth(index_expr) => {
3418                            return self.compile_array_nth(fn_value, scope, elements, index_expr);
3419                        }
3420                        PipeOp::Middle => {
3421                            return self.compile_array_middle(fn_value, scope, elements);
3422                        }
3423                        PipeOp::ReduceMin => {
3424                            return self.compile_array_min(fn_value, scope, elements);
3425                        }
3426                        PipeOp::ReduceMax => {
3427                            return self.compile_array_max(fn_value, scope, elements);
3428                        }
3429                        PipeOp::ReduceAll => {
3430                            return self.compile_array_all(fn_value, scope, elements);
3431                        }
3432                        PipeOp::ReduceAny => {
3433                            return self.compile_array_any(fn_value, scope, elements);
3434                        }
3435                        PipeOp::Sort(_) => {
3436                            return self.compile_array_sort(fn_value, scope, elements);
3437                        }
3438                        PipeOp::Choice => {
3439                            return self.compile_array_choice(fn_value, scope, elements);
3440                        }
3441                        PipeOp::Reduce(reduce_fn) => {
3442                            return self.compile_array_reduce(fn_value, scope, elements, reduce_fn);
3443                        }
3444                        PipeOp::Await => {
3445                            // In sync LLVM context, await just evaluates the array
3446                            // Return sum as a reasonable default for array await
3447                            return self.compile_array_sum(fn_value, scope, elements);
3448                        }
3449                        _ => {}
3450                    }
3451                }
3452                // Handle chained operations: [a,b,c]|τ{f}|ρ+ or [a,b,c]|φ{p}|ρ+
3453                if operations.len() == 2 {
3454                    if let PipeOp::Transform(closure) = &operations[0] {
3455                        match &operations[1] {
3456                            PipeOp::ReduceSum => {
3457                                return self.compile_array_transform_then_sum(
3458                                    fn_value, scope, elements, closure,
3459                                );
3460                            }
3461                            PipeOp::ReduceProd => {
3462                                return self.compile_array_transform_then_product(
3463                                    fn_value, scope, elements, closure,
3464                                );
3465                            }
3466                            _ => {}
3467                        }
3468                    }
3469                    if let PipeOp::Filter(predicate) = &operations[0] {
3470                        match &operations[1] {
3471                            PipeOp::ReduceSum => {
3472                                return self.compile_array_filter_then_sum(
3473                                    fn_value, scope, elements, predicate,
3474                                );
3475                            }
3476                            PipeOp::ReduceProd => {
3477                                return self.compile_array_filter_then_product(
3478                                    fn_value, scope, elements, predicate,
3479                                );
3480                            }
3481                            _ => {}
3482                        }
3483                    }
3484                }
3485            }
3486
3487            // General case: start with the base expression value
3488            let mut current = self.compile_expr(fn_value, scope, expr)?;
3489
3490            for op in operations {
3491                current = match op {
3492                    // Transform: apply function to each element
3493                    PipeOp::Transform(transform_fn) => {
3494                        if let Expr::Closure { body, .. } = transform_fn.as_ref() {
3495                            // For scalar: just compile the body
3496                            self.compile_expr(fn_value, scope, body)?
3497                        } else {
3498                            self.compile_expr(fn_value, scope, transform_fn)?
3499                        }
3500                    }
3501
3502                    // Filter: keep value if predicate is true
3503                    PipeOp::Filter(predicate) => {
3504                        let pred_result = self.compile_expr(fn_value, scope, predicate)?;
3505                        let zero = self.context.i64_type().const_int(0, false);
3506                        let is_true = self
3507                            .builder
3508                            .build_int_compare(IntPredicate::NE, pred_result, zero, "filter_cond")
3509                            .map_err(|e| e.to_string())?;
3510                        self.builder
3511                            .build_select(is_true, current, zero, "filter_result")
3512                            .map_err(|e| e.to_string())?
3513                            .into_int_value()
3514                    }
3515
3516                    // Sum/Product on scalar is identity
3517                    PipeOp::ReduceSum | PipeOp::ReduceProd => current,
3518
3519                    // Min/Max on scalar is identity
3520                    PipeOp::ReduceMin | PipeOp::ReduceMax => current,
3521
3522                    // All/Any on scalar: check if non-zero
3523                    PipeOp::ReduceAll | PipeOp::ReduceAny => {
3524                        let zero = self.context.i64_type().const_int(0, false);
3525                        let one = self.context.i64_type().const_int(1, false);
3526                        let is_true = self
3527                            .builder
3528                            .build_int_compare(IntPredicate::NE, current, zero, "is_true")
3529                            .map_err(|e| e.to_string())?;
3530                        self.builder
3531                            .build_select(is_true, one, zero, "bool_result")
3532                            .map_err(|e| e.to_string())?
3533                            .into_int_value()
3534                    }
3535
3536                    // Sort on scalar is identity
3537                    PipeOp::Sort(_) => current,
3538
3539                    // Choice on scalar is identity (only one choice)
3540                    PipeOp::Choice => current,
3541
3542                    // First/Last/Middle/Nth on scalar is identity
3543                    PipeOp::First | PipeOp::Last | PipeOp::Middle => current,
3544                    PipeOp::Nth(_) => current,
3545
3546                    // Await on scalar is identity (sync execution)
3547                    PipeOp::Await => current,
3548
3549                    // Custom reduce on scalar: just return the scalar (fold over one element)
3550                    PipeOp::Reduce(_) => current,
3551
3552                    // Other operations - passthrough
3553                    _ => current,
3554                };
3555            }
3556
3557            Ok(current)
3558        }
3559
3560        /// Compile sum of array elements: [a, b, c] |ρ+ generates a loop
3561        fn compile_array_sum(
3562            &mut self,
3563            fn_value: FunctionValue<'ctx>,
3564            scope: &mut CompileScope<'ctx>,
3565            elements: &[Expr],
3566        ) -> Result<IntValue<'ctx>, String> {
3567            let len = elements.len();
3568            if len == 0 {
3569                return Ok(self.context.i64_type().const_int(0, false));
3570            }
3571
3572            let i64_type = self.context.i64_type();
3573
3574            // For small arrays, just unroll the sum
3575            if len <= 8 {
3576                let mut sum = self.compile_expr(fn_value, scope, &elements[0])?;
3577                for elem in &elements[1..] {
3578                    let val = self.compile_expr(fn_value, scope, elem)?;
3579                    sum = self
3580                        .builder
3581                        .build_int_add(sum, val, "sum")
3582                        .map_err(|e| e.to_string())?;
3583                }
3584                return Ok(sum);
3585            }
3586
3587            // For larger arrays, generate a proper loop
3588            let array_type = i64_type.array_type(len as u32);
3589            let array_ptr = self
3590                .builder
3591                .build_alloca(array_type, "sum_array")
3592                .map_err(|e| e.to_string())?;
3593
3594            // Store all elements
3595            for (i, elem) in elements.iter().enumerate() {
3596                let value = self.compile_expr(fn_value, scope, elem)?;
3597                let indices = [
3598                    i64_type.const_int(0, false),
3599                    i64_type.const_int(i as u64, false),
3600                ];
3601                let elem_ptr = unsafe {
3602                    self.builder
3603                        .build_gep(array_type, array_ptr, &indices, "elem_ptr")
3604                }
3605                .map_err(|e| e.to_string())?;
3606                self.builder
3607                    .build_store(elem_ptr, value)
3608                    .map_err(|e| e.to_string())?;
3609            }
3610
3611            // Create loop blocks
3612            let loop_header = self.context.append_basic_block(fn_value, "sum_header");
3613            let loop_body = self.context.append_basic_block(fn_value, "sum_body");
3614            let loop_exit = self.context.append_basic_block(fn_value, "sum_exit");
3615
3616            // Initialize: sum = 0, i = 0
3617            let sum_ptr = self
3618                .builder
3619                .build_alloca(i64_type, "sum_ptr")
3620                .map_err(|e| e.to_string())?;
3621            let idx_ptr = self
3622                .builder
3623                .build_alloca(i64_type, "idx_ptr")
3624                .map_err(|e| e.to_string())?;
3625            self.builder
3626                .build_store(sum_ptr, i64_type.const_int(0, false))
3627                .map_err(|e| e.to_string())?;
3628            self.builder
3629                .build_store(idx_ptr, i64_type.const_int(0, false))
3630                .map_err(|e| e.to_string())?;
3631
3632            // Branch to header
3633            self.builder
3634                .build_unconditional_branch(loop_header)
3635                .map_err(|e| e.to_string())?;
3636
3637            // Loop header: check i < len
3638            self.builder.position_at_end(loop_header);
3639            let idx = self
3640                .builder
3641                .build_load(i64_type, idx_ptr, "idx")
3642                .map_err(|e| e.to_string())?
3643                .into_int_value();
3644            let len_val = i64_type.const_int(len as u64, false);
3645            let cond = self
3646                .builder
3647                .build_int_compare(IntPredicate::ULT, idx, len_val, "cmp")
3648                .map_err(|e| e.to_string())?;
3649            self.builder
3650                .build_conditional_branch(cond, loop_body, loop_exit)
3651                .map_err(|e| e.to_string())?;
3652
3653            // Loop body: sum += arr[i]; i++
3654            self.builder.position_at_end(loop_body);
3655            let elem_ptr = unsafe {
3656                self.builder.build_gep(
3657                    array_type,
3658                    array_ptr,
3659                    &[i64_type.const_int(0, false), idx],
3660                    "elem_ptr",
3661                )
3662            }
3663            .map_err(|e| e.to_string())?;
3664            let elem_val = self
3665                .builder
3666                .build_load(i64_type, elem_ptr, "elem")
3667                .map_err(|e| e.to_string())?
3668                .into_int_value();
3669            let sum = self
3670                .builder
3671                .build_load(i64_type, sum_ptr, "sum")
3672                .map_err(|e| e.to_string())?
3673                .into_int_value();
3674            let new_sum = self
3675                .builder
3676                .build_int_add(sum, elem_val, "new_sum")
3677                .map_err(|e| e.to_string())?;
3678            self.builder
3679                .build_store(sum_ptr, new_sum)
3680                .map_err(|e| e.to_string())?;
3681            let new_idx = self
3682                .builder
3683                .build_int_add(idx, i64_type.const_int(1, false), "new_idx")
3684                .map_err(|e| e.to_string())?;
3685            self.builder
3686                .build_store(idx_ptr, new_idx)
3687                .map_err(|e| e.to_string())?;
3688            self.builder
3689                .build_unconditional_branch(loop_header)
3690                .map_err(|e| e.to_string())?;
3691
3692            // Loop exit: return sum
3693            self.builder.position_at_end(loop_exit);
3694            let final_sum = self
3695                .builder
3696                .build_load(i64_type, sum_ptr, "final_sum")
3697                .map_err(|e| e.to_string())?
3698                .into_int_value();
3699
3700            Ok(final_sum)
3701        }
3702
3703        /// Compile product of array elements: [a, b, c] |ρ* generates a loop
3704        fn compile_array_product(
3705            &mut self,
3706            fn_value: FunctionValue<'ctx>,
3707            scope: &mut CompileScope<'ctx>,
3708            elements: &[Expr],
3709        ) -> Result<IntValue<'ctx>, String> {
3710            let len = elements.len();
3711            if len == 0 {
3712                return Ok(self.context.i64_type().const_int(1, false)); // Empty product = 1
3713            }
3714
3715            // Unroll for all sizes (product is less common than sum)
3716            let mut product = self.compile_expr(fn_value, scope, &elements[0])?;
3717            for elem in &elements[1..] {
3718                let val = self.compile_expr(fn_value, scope, elem)?;
3719                product = self
3720                    .builder
3721                    .build_int_mul(product, val, "prod")
3722                    .map_err(|e| e.to_string())?;
3723            }
3724            Ok(product)
3725        }
3726
3727        /// Compile array transform: [a, b, c] |τ{x => f(x)}
3728        /// Returns pointer to new array with transformed elements
3729        fn compile_array_transform(
3730            &mut self,
3731            fn_value: FunctionValue<'ctx>,
3732            scope: &mut CompileScope<'ctx>,
3733            elements: &[Expr],
3734            closure: &Expr,
3735        ) -> Result<IntValue<'ctx>, String> {
3736            let len = elements.len();
3737            if len == 0 {
3738                return Ok(self.context.i64_type().const_int(0, false));
3739            }
3740
3741            let i64_type = self.context.i64_type();
3742            let array_type = i64_type.array_type(len as u32);
3743
3744            // Allocate result array
3745            let result_ptr = self
3746                .builder
3747                .build_alloca(array_type, "transform_result")
3748                .map_err(|e| e.to_string())?;
3749
3750            // Extract closure parameter name and body
3751            let (param_name, body) = if let Expr::Closure { params, body, .. } = closure {
3752                let name = if let Some(p) = params.first() {
3753                    if let ast::Pattern::Ident { name: ident, .. } = &p.pattern {
3754                        ident.name.clone()
3755                    } else {
3756                        "x".to_string()
3757                    }
3758                } else {
3759                    "x".to_string()
3760                };
3761                (name, body.as_ref())
3762            } else {
3763                return Err("Transform requires a closure".to_string());
3764            };
3765
3766            // Transform each element
3767            for (i, elem) in elements.iter().enumerate() {
3768                // Compile the element value
3769                let elem_val = self.compile_expr(fn_value, scope, elem)?;
3770
3771                // Bind parameter to element value (store in alloca)
3772                let param_ptr = self
3773                    .builder
3774                    .build_alloca(i64_type, &param_name)
3775                    .map_err(|e| e.to_string())?;
3776                self.builder
3777                    .build_store(param_ptr, elem_val)
3778                    .map_err(|e| e.to_string())?;
3779
3780                // Add to scope temporarily
3781                let old_val = scope.vars.insert(param_name.to_string(), param_ptr);
3782
3783                // Compile closure body
3784                let result = self.compile_expr(fn_value, scope, body)?;
3785
3786                // Restore scope
3787                if let Some(old) = old_val {
3788                    scope.vars.insert(param_name.to_string(), old);
3789                } else {
3790                    scope.vars.remove(&param_name);
3791                }
3792
3793                // Store result in output array
3794                let indices = [
3795                    i64_type.const_int(0, false),
3796                    i64_type.const_int(i as u64, false),
3797                ];
3798                let out_ptr = unsafe {
3799                    self.builder
3800                        .build_gep(array_type, result_ptr, &indices, "out_elem")
3801                }
3802                .map_err(|e| e.to_string())?;
3803                self.builder
3804                    .build_store(out_ptr, result)
3805                    .map_err(|e| e.to_string())?;
3806            }
3807
3808            // Return pointer as i64
3809            self.builder
3810                .build_ptr_to_int(result_ptr, i64_type, "arr_ptr")
3811                .map_err(|e| e.to_string())
3812        }
3813
3814        /// Compile fused transform-then-sum: [a, b, c] |τ{f} |ρ+
3815        /// More efficient than separate transform and sum
3816        fn compile_array_transform_then_sum(
3817            &mut self,
3818            fn_value: FunctionValue<'ctx>,
3819            scope: &mut CompileScope<'ctx>,
3820            elements: &[Expr],
3821            closure: &Expr,
3822        ) -> Result<IntValue<'ctx>, String> {
3823            let len = elements.len();
3824            if len == 0 {
3825                return Ok(self.context.i64_type().const_int(0, false));
3826            }
3827
3828            let i64_type = self.context.i64_type();
3829
3830            // Extract closure parameter name and body
3831            let (param_name, body) = if let Expr::Closure { params, body, .. } = closure {
3832                let name = if let Some(p) = params.first() {
3833                    if let ast::Pattern::Ident { name: ident, .. } = &p.pattern {
3834                        ident.name.clone()
3835                    } else {
3836                        "x".to_string()
3837                    }
3838                } else {
3839                    "x".to_string()
3840                };
3841                (name, body.as_ref())
3842            } else {
3843                return Err("Transform requires a closure".to_string());
3844            };
3845
3846            // Fused: transform and sum in one pass (no intermediate array)
3847            let mut sum = i64_type.const_int(0, false);
3848
3849            for elem in elements.iter() {
3850                // Compile the element value
3851                let elem_val = self.compile_expr(fn_value, scope, elem)?;
3852
3853                // Bind parameter
3854                let param_ptr = self
3855                    .builder
3856                    .build_alloca(i64_type, &param_name)
3857                    .map_err(|e| e.to_string())?;
3858                self.builder
3859                    .build_store(param_ptr, elem_val)
3860                    .map_err(|e| e.to_string())?;
3861
3862                let old_val = scope.vars.insert(param_name.to_string(), param_ptr);
3863
3864                // Compile closure body (the transform)
3865                let transformed = self.compile_expr(fn_value, scope, body)?;
3866
3867                // Restore scope
3868                if let Some(old) = old_val {
3869                    scope.vars.insert(param_name.to_string(), old);
3870                } else {
3871                    scope.vars.remove(&param_name);
3872                }
3873
3874                // Add to sum
3875                sum = self
3876                    .builder
3877                    .build_int_add(sum, transformed, "sum")
3878                    .map_err(|e| e.to_string())?;
3879            }
3880
3881            Ok(sum)
3882        }
3883
3884        /// Compile fused transform-then-product: [a, b, c] |τ{f} |ρ*
3885        fn compile_array_transform_then_product(
3886            &mut self,
3887            fn_value: FunctionValue<'ctx>,
3888            scope: &mut CompileScope<'ctx>,
3889            elements: &[Expr],
3890            closure: &Expr,
3891        ) -> Result<IntValue<'ctx>, String> {
3892            let len = elements.len();
3893            if len == 0 {
3894                return Ok(self.context.i64_type().const_int(1, false));
3895            }
3896
3897            let i64_type = self.context.i64_type();
3898
3899            // Extract closure parameter name and body
3900            let (param_name, body) = if let Expr::Closure { params, body, .. } = closure {
3901                let name = if let Some(p) = params.first() {
3902                    if let ast::Pattern::Ident { name: ident, .. } = &p.pattern {
3903                        ident.name.clone()
3904                    } else {
3905                        "x".to_string()
3906                    }
3907                } else {
3908                    "x".to_string()
3909                };
3910                (name, body.as_ref())
3911            } else {
3912                return Err("Transform requires a closure".to_string());
3913            };
3914
3915            // Fused: transform and multiply in one pass
3916            let mut product = i64_type.const_int(1, false);
3917
3918            for elem in elements.iter() {
3919                let elem_val = self.compile_expr(fn_value, scope, elem)?;
3920
3921                let param_ptr = self
3922                    .builder
3923                    .build_alloca(i64_type, &param_name)
3924                    .map_err(|e| e.to_string())?;
3925                self.builder
3926                    .build_store(param_ptr, elem_val)
3927                    .map_err(|e| e.to_string())?;
3928
3929                let old_val = scope.vars.insert(param_name.to_string(), param_ptr);
3930
3931                let transformed = self.compile_expr(fn_value, scope, body)?;
3932
3933                if let Some(old) = old_val {
3934                    scope.vars.insert(param_name.to_string(), old);
3935                } else {
3936                    scope.vars.remove(&param_name);
3937                }
3938
3939                product = self
3940                    .builder
3941                    .build_int_mul(product, transformed, "prod")
3942                    .map_err(|e| e.to_string())?;
3943            }
3944
3945            Ok(product)
3946        }
3947
3948        /// Compile array filter: [a, b, c] |φ{predicate}
3949        /// Filter keeps elements where predicate returns non-zero.
3950        /// For compile-time known arrays, returns sum of elements that pass (for chaining to ρ+)
3951        /// or returns the count of passing elements (pointer + count pattern).
3952        fn compile_array_filter(
3953            &mut self,
3954            fn_value: FunctionValue<'ctx>,
3955            scope: &mut CompileScope<'ctx>,
3956            elements: &[Expr],
3957            predicate: &Expr,
3958        ) -> Result<IntValue<'ctx>, String> {
3959            let len = elements.len();
3960            if len == 0 {
3961                return Ok(self.context.i64_type().const_int(0, false));
3962            }
3963
3964            let i64_type = self.context.i64_type();
3965            let array_type = i64_type.array_type(len as u32);
3966
3967            // Allocate output array (max size = input size)
3968            let out_ptr = self
3969                .builder
3970                .build_alloca(array_type, "filter_result")
3971                .map_err(|e| e.to_string())?;
3972
3973            // Extract predicate parameter name and body
3974            let (param_name, body) = if let Expr::Closure { params, body, .. } = predicate {
3975                let name = if let Some(p) = params.first() {
3976                    if let ast::Pattern::Ident { name: ident, .. } = &p.pattern {
3977                        ident.name.clone()
3978                    } else {
3979                        "x".to_string()
3980                    }
3981                } else {
3982                    "x".to_string()
3983                };
3984                (name, body.as_ref())
3985            } else {
3986                return Err("Filter requires a closure predicate".to_string());
3987            };
3988
3989            // Unrolled filter for small arrays (count passing elements)
3990            let mut out_idx = 0u64;
3991            let mut count = i64_type.const_int(0, false);
3992
3993            for elem in elements.iter() {
3994                let elem_val = self.compile_expr(fn_value, scope, elem)?;
3995
3996                // Bind parameter
3997                let param_ptr = self
3998                    .builder
3999                    .build_alloca(i64_type, &param_name)
4000                    .map_err(|e| e.to_string())?;
4001                self.builder
4002                    .build_store(param_ptr, elem_val)
4003                    .map_err(|e| e.to_string())?;
4004
4005                let old_val = scope.vars.insert(param_name.to_string(), param_ptr);
4006
4007                // Evaluate predicate
4008                let pred_result = self.compile_expr(fn_value, scope, body)?;
4009
4010                // Restore scope
4011                if let Some(old) = old_val {
4012                    scope.vars.insert(param_name.to_string(), old);
4013                } else {
4014                    scope.vars.remove(&param_name);
4015                }
4016
4017                // Check if predicate is true (non-zero)
4018                let zero = i64_type.const_int(0, false);
4019                let is_true = self
4020                    .builder
4021                    .build_int_compare(IntPredicate::NE, pred_result, zero, "is_passing")
4022                    .map_err(|e| e.to_string())?;
4023
4024                // Conditionally add 1 to count
4025                let one = i64_type.const_int(1, false);
4026                let inc = self
4027                    .builder
4028                    .build_select(is_true, one, zero, "inc")
4029                    .map_err(|e| e.to_string())?
4030                    .into_int_value();
4031                count = self
4032                    .builder
4033                    .build_int_add(count, inc, "count")
4034                    .map_err(|e| e.to_string())?;
4035
4036                // Store element if passing (always store, use select for value)
4037                let indices = [
4038                    i64_type.const_int(0, false),
4039                    i64_type.const_int(out_idx, false),
4040                ];
4041                let elem_ptr = unsafe {
4042                    self.builder
4043                        .build_gep(array_type, out_ptr, &indices, "out_elem")
4044                }
4045                .map_err(|e| e.to_string())?;
4046
4047                // Use select: if passing, store element; otherwise store 0 (placeholder)
4048                let value_to_store = self
4049                    .builder
4050                    .build_select(is_true, elem_val, zero, "val_or_zero")
4051                    .map_err(|e| e.to_string())?
4052                    .into_int_value();
4053                self.builder
4054                    .build_store(elem_ptr, value_to_store)
4055                    .map_err(|e| e.to_string())?;
4056
4057                out_idx += 1;
4058            }
4059
4060            // Return count of passing elements (for now - proper filter would return array)
4061            Ok(count)
4062        }
4063
4064        /// Compile fused filter-then-sum: [a, b, c] |φ{p} |ρ+
4065        /// Sum only elements that pass the predicate
4066        fn compile_array_filter_then_sum(
4067            &mut self,
4068            fn_value: FunctionValue<'ctx>,
4069            scope: &mut CompileScope<'ctx>,
4070            elements: &[Expr],
4071            predicate: &Expr,
4072        ) -> Result<IntValue<'ctx>, String> {
4073            let len = elements.len();
4074            if len == 0 {
4075                return Ok(self.context.i64_type().const_int(0, false));
4076            }
4077
4078            let i64_type = self.context.i64_type();
4079
4080            // Extract predicate parameter name and body
4081            let (param_name, body) = if let Expr::Closure { params, body, .. } = predicate {
4082                let name = if let Some(p) = params.first() {
4083                    if let ast::Pattern::Ident { name: ident, .. } = &p.pattern {
4084                        ident.name.clone()
4085                    } else {
4086                        "x".to_string()
4087                    }
4088                } else {
4089                    "x".to_string()
4090                };
4091                (name, body.as_ref())
4092            } else {
4093                return Err("Filter requires a closure predicate".to_string());
4094            };
4095
4096            let mut sum = i64_type.const_int(0, false);
4097            let zero = i64_type.const_int(0, false);
4098
4099            for elem in elements.iter() {
4100                let elem_val = self.compile_expr(fn_value, scope, elem)?;
4101
4102                // Bind parameter
4103                let param_ptr = self
4104                    .builder
4105                    .build_alloca(i64_type, &param_name)
4106                    .map_err(|e| e.to_string())?;
4107                self.builder
4108                    .build_store(param_ptr, elem_val)
4109                    .map_err(|e| e.to_string())?;
4110
4111                let old_val = scope.vars.insert(param_name.to_string(), param_ptr);
4112
4113                // Evaluate predicate
4114                let pred_result = self.compile_expr(fn_value, scope, body)?;
4115
4116                // Restore scope
4117                if let Some(old) = old_val {
4118                    scope.vars.insert(param_name.to_string(), old);
4119                } else {
4120                    scope.vars.remove(&param_name);
4121                }
4122
4123                // Check if predicate is true (non-zero)
4124                let is_true = self
4125                    .builder
4126                    .build_int_compare(IntPredicate::NE, pred_result, zero, "is_passing")
4127                    .map_err(|e| e.to_string())?;
4128
4129                // Add element to sum only if passing
4130                let add_value = self
4131                    .builder
4132                    .build_select(is_true, elem_val, zero, "add_if_pass")
4133                    .map_err(|e| e.to_string())?
4134                    .into_int_value();
4135                sum = self
4136                    .builder
4137                    .build_int_add(sum, add_value, "sum")
4138                    .map_err(|e| e.to_string())?;
4139            }
4140
4141            Ok(sum)
4142        }
4143
4144        /// Compile fused filter-then-product: [a, b, c] |φ{p} |ρ*
4145        /// Product of elements that pass the predicate
4146        fn compile_array_filter_then_product(
4147            &mut self,
4148            fn_value: FunctionValue<'ctx>,
4149            scope: &mut CompileScope<'ctx>,
4150            elements: &[Expr],
4151            predicate: &Expr,
4152        ) -> Result<IntValue<'ctx>, String> {
4153            let len = elements.len();
4154            if len == 0 {
4155                return Ok(self.context.i64_type().const_int(1, false));
4156            }
4157
4158            let i64_type = self.context.i64_type();
4159
4160            // Extract predicate parameter name and body
4161            let (param_name, body) = if let Expr::Closure { params, body, .. } = predicate {
4162                let name = if let Some(p) = params.first() {
4163                    if let ast::Pattern::Ident { name: ident, .. } = &p.pattern {
4164                        ident.name.clone()
4165                    } else {
4166                        "x".to_string()
4167                    }
4168                } else {
4169                    "x".to_string()
4170                };
4171                (name, body.as_ref())
4172            } else {
4173                return Err("Filter requires a closure predicate".to_string());
4174            };
4175
4176            let mut product = i64_type.const_int(1, false);
4177            let one = i64_type.const_int(1, false);
4178            let zero = i64_type.const_int(0, false);
4179
4180            for elem in elements.iter() {
4181                let elem_val = self.compile_expr(fn_value, scope, elem)?;
4182
4183                // Bind parameter
4184                let param_ptr = self
4185                    .builder
4186                    .build_alloca(i64_type, &param_name)
4187                    .map_err(|e| e.to_string())?;
4188                self.builder
4189                    .build_store(param_ptr, elem_val)
4190                    .map_err(|e| e.to_string())?;
4191
4192                let old_val = scope.vars.insert(param_name.to_string(), param_ptr);
4193
4194                // Evaluate predicate
4195                let pred_result = self.compile_expr(fn_value, scope, body)?;
4196
4197                // Restore scope
4198                if let Some(old) = old_val {
4199                    scope.vars.insert(param_name.to_string(), old);
4200                } else {
4201                    scope.vars.remove(&param_name);
4202                }
4203
4204                // Check if predicate is true (non-zero)
4205                let is_true = self
4206                    .builder
4207                    .build_int_compare(IntPredicate::NE, pred_result, zero, "is_passing")
4208                    .map_err(|e| e.to_string())?;
4209
4210                // Multiply by element only if passing, otherwise multiply by 1 (identity)
4211                let mul_value = self
4212                    .builder
4213                    .build_select(is_true, elem_val, one, "mul_if_pass")
4214                    .map_err(|e| e.to_string())?
4215                    .into_int_value();
4216                product = self
4217                    .builder
4218                    .build_int_mul(product, mul_value, "prod")
4219                    .map_err(|e| e.to_string())?;
4220            }
4221
4222            Ok(product)
4223        }
4224
4225        // ============================================
4226        // Element Access Morphemes
4227        // ============================================
4228
4229        /// Compile first element access: [a, b, c] |α returns a
4230        fn compile_array_first(
4231            &mut self,
4232            fn_value: FunctionValue<'ctx>,
4233            scope: &mut CompileScope<'ctx>,
4234            elements: &[Expr],
4235        ) -> Result<IntValue<'ctx>, String> {
4236            if elements.is_empty() {
4237                // Return 0 for empty array (could also panic)
4238                return Ok(self.context.i64_type().const_int(0, false));
4239            }
4240            self.compile_expr(fn_value, scope, &elements[0])
4241        }
4242
4243        /// Compile last element access: [a, b, c] |ω returns c
4244        fn compile_array_last(
4245            &mut self,
4246            fn_value: FunctionValue<'ctx>,
4247            scope: &mut CompileScope<'ctx>,
4248            elements: &[Expr],
4249        ) -> Result<IntValue<'ctx>, String> {
4250            if elements.is_empty() {
4251                return Ok(self.context.i64_type().const_int(0, false));
4252            }
4253            self.compile_expr(fn_value, scope, &elements[elements.len() - 1])
4254        }
4255
4256        /// Compile nth element access: [a, b, c] |ν{1} returns b
4257        fn compile_array_nth(
4258            &mut self,
4259            fn_value: FunctionValue<'ctx>,
4260            scope: &mut CompileScope<'ctx>,
4261            elements: &[Expr],
4262            index_expr: &Expr,
4263        ) -> Result<IntValue<'ctx>, String> {
4264            if elements.is_empty() {
4265                return Ok(self.context.i64_type().const_int(0, false));
4266            }
4267
4268            // Try to evaluate index at compile time for static arrays
4269            if let Expr::Literal(ast::Literal::Int { value, .. }) = index_expr {
4270                if let Ok(n) = value.parse::<usize>() {
4271                    if n < elements.len() {
4272                        return self.compile_expr(fn_value, scope, &elements[n]);
4273                    } else {
4274                        // Index out of bounds - return 0
4275                        return Ok(self.context.i64_type().const_int(0, false));
4276                    }
4277                }
4278            }
4279
4280            // Dynamic index: allocate array and compute index at runtime
4281            let i64_type = self.context.i64_type();
4282            let len = elements.len();
4283            let array_type = i64_type.array_type(len as u32);
4284            let array_ptr = self
4285                .builder
4286                .build_alloca(array_type, "nth_array")
4287                .map_err(|e| e.to_string())?;
4288
4289            // Store all elements
4290            for (i, elem) in elements.iter().enumerate() {
4291                let value = self.compile_expr(fn_value, scope, elem)?;
4292                let indices = [
4293                    i64_type.const_int(0, false),
4294                    i64_type.const_int(i as u64, false),
4295                ];
4296                let elem_ptr = unsafe {
4297                    self.builder
4298                        .build_gep(array_type, array_ptr, &indices, "elem_ptr")
4299                }
4300                .map_err(|e| e.to_string())?;
4301                self.builder
4302                    .build_store(elem_ptr, value)
4303                    .map_err(|e| e.to_string())?;
4304            }
4305
4306            // Compute index
4307            let idx = self.compile_expr(fn_value, scope, index_expr)?;
4308
4309            // Bounds check: clamp to valid range
4310            let len_val = i64_type.const_int(len as u64 - 1, false);
4311            let zero = i64_type.const_int(0, false);
4312            let clamped_high = self
4313                .builder
4314                .build_select(
4315                    self.builder
4316                        .build_int_compare(IntPredicate::UGT, idx, len_val, "gt_len")
4317                        .map_err(|e| e.to_string())?,
4318                    len_val,
4319                    idx,
4320                    "clamp_high",
4321                )
4322                .map_err(|e| e.to_string())?
4323                .into_int_value();
4324            let clamped = self
4325                .builder
4326                .build_select(
4327                    self.builder
4328                        .build_int_compare(IntPredicate::SLT, clamped_high, zero, "lt_zero")
4329                        .map_err(|e| e.to_string())?,
4330                    zero,
4331                    clamped_high,
4332                    "clamp_low",
4333                )
4334                .map_err(|e| e.to_string())?
4335                .into_int_value();
4336
4337            // Load element at clamped index
4338            let indices = [i64_type.const_int(0, false), clamped];
4339            let elem_ptr = unsafe {
4340                self.builder
4341                    .build_gep(array_type, array_ptr, &indices, "nth_ptr")
4342            }
4343            .map_err(|e| e.to_string())?;
4344            let value = self
4345                .builder
4346                .build_load(i64_type, elem_ptr, "nth_val")
4347                .map_err(|e| e.to_string())?;
4348
4349            Ok(value.into_int_value())
4350        }
4351
4352        /// Compile middle element access: [a, b, c, d, e] |μ returns c
4353        fn compile_array_middle(
4354            &mut self,
4355            fn_value: FunctionValue<'ctx>,
4356            scope: &mut CompileScope<'ctx>,
4357            elements: &[Expr],
4358        ) -> Result<IntValue<'ctx>, String> {
4359            if elements.is_empty() {
4360                return Ok(self.context.i64_type().const_int(0, false));
4361            }
4362            let mid_idx = elements.len() / 2;
4363            self.compile_expr(fn_value, scope, &elements[mid_idx])
4364        }
4365
4366        // ============================================
4367        // Reduction Morphemes (Min, Max, All, Any)
4368        // ============================================
4369
4370        /// Compile min reduction: [a, b, c] |ρ_min returns minimum
4371        fn compile_array_min(
4372            &mut self,
4373            fn_value: FunctionValue<'ctx>,
4374            scope: &mut CompileScope<'ctx>,
4375            elements: &[Expr],
4376        ) -> Result<IntValue<'ctx>, String> {
4377            if elements.is_empty() {
4378                return Ok(self.context.i64_type().const_int(i64::MAX as u64, true));
4379            }
4380
4381            let mut min_val = self.compile_expr(fn_value, scope, &elements[0])?;
4382
4383            for elem in &elements[1..] {
4384                let val = self.compile_expr(fn_value, scope, elem)?;
4385                let is_less = self
4386                    .builder
4387                    .build_int_compare(IntPredicate::SLT, val, min_val, "is_less")
4388                    .map_err(|e| e.to_string())?;
4389                min_val = self
4390                    .builder
4391                    .build_select(is_less, val, min_val, "min_sel")
4392                    .map_err(|e| e.to_string())?
4393                    .into_int_value();
4394            }
4395
4396            Ok(min_val)
4397        }
4398
4399        /// Compile max reduction: [a, b, c] |ρ_max returns maximum
4400        fn compile_array_max(
4401            &mut self,
4402            fn_value: FunctionValue<'ctx>,
4403            scope: &mut CompileScope<'ctx>,
4404            elements: &[Expr],
4405        ) -> Result<IntValue<'ctx>, String> {
4406            if elements.is_empty() {
4407                return Ok(self.context.i64_type().const_int(i64::MIN as u64, true));
4408            }
4409
4410            let mut max_val = self.compile_expr(fn_value, scope, &elements[0])?;
4411
4412            for elem in &elements[1..] {
4413                let val = self.compile_expr(fn_value, scope, elem)?;
4414                let is_greater = self
4415                    .builder
4416                    .build_int_compare(IntPredicate::SGT, val, max_val, "is_greater")
4417                    .map_err(|e| e.to_string())?;
4418                max_val = self
4419                    .builder
4420                    .build_select(is_greater, val, max_val, "max_sel")
4421                    .map_err(|e| e.to_string())?
4422                    .into_int_value();
4423            }
4424
4425            Ok(max_val)
4426        }
4427
4428        /// Compile all reduction: [a, b, c] |ρ& returns 1 if all non-zero
4429        fn compile_array_all(
4430            &mut self,
4431            fn_value: FunctionValue<'ctx>,
4432            scope: &mut CompileScope<'ctx>,
4433            elements: &[Expr],
4434        ) -> Result<IntValue<'ctx>, String> {
4435            if elements.is_empty() {
4436                // Empty array: all is vacuously true
4437                return Ok(self.context.i64_type().const_int(1, false));
4438            }
4439
4440            let zero = self.context.i64_type().const_int(0, false);
4441            let mut result = self.context.i64_type().const_int(1, false);
4442
4443            for elem in elements {
4444                let val = self.compile_expr(fn_value, scope, elem)?;
4445                let is_true = self
4446                    .builder
4447                    .build_int_compare(IntPredicate::NE, val, zero, "is_true")
4448                    .map_err(|e| e.to_string())?;
4449                let as_int = self
4450                    .builder
4451                    .build_int_z_extend(is_true, self.context.i64_type(), "as_int")
4452                    .map_err(|e| e.to_string())?;
4453                result = self
4454                    .builder
4455                    .build_and(result, as_int, "all_and")
4456                    .map_err(|e| e.to_string())?;
4457            }
4458
4459            Ok(result)
4460        }
4461
4462        /// Compile any reduction: [a, b, c] |ρ| returns 1 if any non-zero
4463        fn compile_array_any(
4464            &mut self,
4465            fn_value: FunctionValue<'ctx>,
4466            scope: &mut CompileScope<'ctx>,
4467            elements: &[Expr],
4468        ) -> Result<IntValue<'ctx>, String> {
4469            if elements.is_empty() {
4470                // Empty array: any is false
4471                return Ok(self.context.i64_type().const_int(0, false));
4472            }
4473
4474            let zero = self.context.i64_type().const_int(0, false);
4475            let mut result = self.context.i64_type().const_int(0, false);
4476
4477            for elem in elements {
4478                let val = self.compile_expr(fn_value, scope, elem)?;
4479                let is_true = self
4480                    .builder
4481                    .build_int_compare(IntPredicate::NE, val, zero, "is_true")
4482                    .map_err(|e| e.to_string())?;
4483                let as_int = self
4484                    .builder
4485                    .build_int_z_extend(is_true, self.context.i64_type(), "as_int")
4486                    .map_err(|e| e.to_string())?;
4487                result = self
4488                    .builder
4489                    .build_or(result, as_int, "any_or")
4490                    .map_err(|e| e.to_string())?;
4491            }
4492
4493            Ok(result)
4494        }
4495
4496        /// Compile sort morpheme: [3, 1, 2] |σ returns minimum (first element of sorted array)
4497        /// For now, we just find the minimum since we only return the first element
4498        fn compile_array_sort(
4499            &mut self,
4500            fn_value: FunctionValue<'ctx>,
4501            scope: &mut CompileScope<'ctx>,
4502            elements: &[Expr],
4503        ) -> Result<IntValue<'ctx>, String> {
4504            // Sort's first element is the minimum - delegate to min
4505            self.compile_array_min(fn_value, scope, elements)
4506        }
4507
4508        /// Compile choice morpheme: [a, b, c] |χ returns a pseudo-random element
4509        /// Uses a simple deterministic selection based on array sum (for reproducibility)
4510        fn compile_array_choice(
4511            &mut self,
4512            fn_value: FunctionValue<'ctx>,
4513            scope: &mut CompileScope<'ctx>,
4514            elements: &[Expr],
4515        ) -> Result<IntValue<'ctx>, String> {
4516            if elements.is_empty() {
4517                return Ok(self.context.i64_type().const_int(0, false));
4518            }
4519
4520            let len = elements.len();
4521            if len == 1 {
4522                return self.compile_expr(fn_value, scope, &elements[0]);
4523            }
4524
4525            // Compute sum of all elements as a "hash" for deterministic selection
4526            let mut hash = self.compile_expr(fn_value, scope, &elements[0])?;
4527            for elem in &elements[1..] {
4528                let val = self.compile_expr(fn_value, scope, elem)?;
4529                hash = self
4530                    .builder
4531                    .build_int_add(hash, val, "hash_acc")
4532                    .map_err(|e| e.to_string())?;
4533            }
4534
4535            // index = hash % len (use abs to handle negative sums)
4536            let len_const = self.context.i64_type().const_int(len as u64, false);
4537
4538            // Get absolute value: (hash ^ (hash >> 63)) - (hash >> 63)
4539            let shift_amt = self.context.i64_type().const_int(63, false);
4540            let sign = self
4541                .builder
4542                .build_right_shift(hash, shift_amt, true, "sign")
4543                .map_err(|e| e.to_string())?;
4544            let xored = self
4545                .builder
4546                .build_xor(hash, sign, "xored")
4547                .map_err(|e| e.to_string())?;
4548            let abs_hash = self
4549                .builder
4550                .build_int_sub(xored, sign, "abs")
4551                .map_err(|e| e.to_string())?;
4552
4553            let index = self
4554                .builder
4555                .build_int_unsigned_rem(abs_hash, len_const, "choice_idx")
4556                .map_err(|e| e.to_string())?;
4557
4558            // Allocate array and select by index
4559            let i64_type = self.context.i64_type();
4560            let array_type = i64_type.array_type(len as u32);
4561            let array_ptr = self
4562                .builder
4563                .build_alloca(array_type, "choice_arr")
4564                .map_err(|e| e.to_string())?;
4565
4566            // Store elements
4567            for (i, elem) in elements.iter().enumerate() {
4568                let val = self.compile_expr(fn_value, scope, elem)?;
4569                let indices = [
4570                    i64_type.const_int(0, false),
4571                    i64_type.const_int(i as u64, false),
4572                ];
4573                let ptr = unsafe {
4574                    self.builder
4575                        .build_gep(array_type, array_ptr, &indices, "elem_ptr")
4576                }
4577                .map_err(|e| e.to_string())?;
4578                self.builder
4579                    .build_store(ptr, val)
4580                    .map_err(|e| e.to_string())?;
4581            }
4582
4583            // Load element at computed index
4584            let result_ptr = unsafe {
4585                self.builder.build_gep(
4586                    array_type,
4587                    array_ptr,
4588                    &[i64_type.const_int(0, false), index],
4589                    "choice_ptr",
4590                )
4591            }
4592            .map_err(|e| e.to_string())?;
4593
4594            let result = self
4595                .builder
4596                .build_load(i64_type, result_ptr, "choice_val")
4597                .map_err(|e| e.to_string())?
4598                .into_int_value();
4599
4600            Ok(result)
4601        }
4602
4603        /// Compile custom reduce: [a, b, c] |ρ{|acc, x| acc + x} applies fold
4604        fn compile_array_reduce(
4605            &mut self,
4606            fn_value: FunctionValue<'ctx>,
4607            scope: &mut CompileScope<'ctx>,
4608            elements: &[Expr],
4609            reduce_fn: &Expr,
4610        ) -> Result<IntValue<'ctx>, String> {
4611            if elements.is_empty() {
4612                return Ok(self.context.i64_type().const_int(0, false));
4613            }
4614
4615            // Extract closure params and body
4616            let (acc_name, elem_name, body) = if let Expr::Closure { params, body, .. } = reduce_fn
4617            {
4618                if params.len() != 2 {
4619                    return Err("Reduce closure must have exactly 2 parameters".to_string());
4620                }
4621                // Extract names from Pattern::Ident
4622                let acc = if let ast::Pattern::Ident { name: ident, .. } = &params[0].pattern {
4623                    ident.name.clone()
4624                } else {
4625                    "acc".to_string()
4626                };
4627                let elem = if let ast::Pattern::Ident { name: ident, .. } = &params[1].pattern {
4628                    ident.name.clone()
4629                } else {
4630                    "x".to_string()
4631                };
4632                (acc, elem, body)
4633            } else {
4634                return Err("Reduce requires a closure".to_string());
4635            };
4636
4637            let i64_type = self.context.i64_type();
4638
4639            // Allocate storage for accumulator and element
4640            let acc_ptr = self
4641                .builder
4642                .build_alloca(i64_type, &acc_name)
4643                .map_err(|e| e.to_string())?;
4644            let elem_ptr = self
4645                .builder
4646                .build_alloca(i64_type, &elem_name)
4647                .map_err(|e| e.to_string())?;
4648
4649            // Initialize accumulator with first element
4650            let first = self.compile_expr(fn_value, scope, &elements[0])?;
4651            self.builder
4652                .build_store(acc_ptr, first)
4653                .map_err(|e| e.to_string())?;
4654
4655            // Add bindings to scope
4656            scope.vars.insert(acc_name.clone(), acc_ptr);
4657            scope.vars.insert(elem_name.clone(), elem_ptr);
4658
4659            // Fold over remaining elements
4660            for elem in &elements[1..] {
4661                let val = self.compile_expr(fn_value, scope, elem)?;
4662                self.builder
4663                    .build_store(elem_ptr, val)
4664                    .map_err(|e| e.to_string())?;
4665
4666                // Evaluate body
4667                let new_acc = self.compile_expr(fn_value, scope, body)?;
4668                self.builder
4669                    .build_store(acc_ptr, new_acc)
4670                    .map_err(|e| e.to_string())?;
4671            }
4672
4673            // Load final accumulator value
4674            let result = self
4675                .builder
4676                .build_load(i64_type, acc_ptr, "reduce_result")
4677                .map_err(|e| e.to_string())?
4678                .into_int_value();
4679
4680            Ok(result)
4681        }
4682
4683        /// Compile array literal: allocate stack space and store each element
4684        /// Returns pointer to first element as i64 (for now, proper fat pointers later)
4685        fn compile_array_literal(
4686            &mut self,
4687            fn_value: FunctionValue<'ctx>,
4688            scope: &mut CompileScope<'ctx>,
4689            elements: &[Expr],
4690        ) -> Result<IntValue<'ctx>, String> {
4691            let len = elements.len();
4692            if len == 0 {
4693                // Empty array - return null
4694                return Ok(self.context.i64_type().const_int(0, false));
4695            }
4696
4697            let i64_type = self.context.i64_type();
4698            let array_type = i64_type.array_type(len as u32);
4699
4700            // Allocate array on stack
4701            let array_ptr = self
4702                .builder
4703                .build_alloca(array_type, "array")
4704                .map_err(|e| e.to_string())?;
4705
4706            // Store each element
4707            for (i, elem) in elements.iter().enumerate() {
4708                let value = self.compile_expr(fn_value, scope, elem)?;
4709
4710                // GEP to get pointer to element i
4711                let indices = [
4712                    self.context.i64_type().const_int(0, false),
4713                    self.context.i64_type().const_int(i as u64, false),
4714                ];
4715                let elem_ptr = unsafe {
4716                    self.builder
4717                        .build_gep(array_type, array_ptr, &indices, "elem_ptr")
4718                }
4719                .map_err(|e| e.to_string())?;
4720
4721                // Store the value
4722                self.builder
4723                    .build_store(elem_ptr, value)
4724                    .map_err(|e| e.to_string())?;
4725            }
4726
4727            // Return pointer as i64 (we'll improve this later with proper fat pointers)
4728            // For now, pack ptr in low bits and len in high bits of a struct
4729            let ptr_as_int = self
4730                .builder
4731                .build_ptr_to_int(array_ptr, i64_type, "arr_ptr")
4732                .map_err(|e| e.to_string())?;
4733
4734            // Store length in scope for later retrieval (hacky but works for now)
4735            // We'll use a naming convention: the array pointer + "_len"
4736            // Better: return a struct { ptr, len } but that requires more refactoring
4737
4738            Ok(ptr_as_int)
4739        }
4740
4741        /// Compile array/slice indexing: arr[idx]
4742        /// Expects arr to be a pointer (as i64) to an array
4743        fn compile_index(
4744            &mut self,
4745            fn_value: FunctionValue<'ctx>,
4746            scope: &mut CompileScope<'ctx>,
4747            expr: &Expr,
4748            index: &Expr,
4749        ) -> Result<IntValue<'ctx>, String> {
4750            let base_ptr_int = self.compile_expr(fn_value, scope, expr)?;
4751            let idx = self.compile_expr(fn_value, scope, index)?;
4752
4753            let i64_type = self.context.i64_type();
4754
4755            // Convert i64 back to pointer
4756            let base_ptr = self
4757                .builder
4758                .build_int_to_ptr(
4759                    base_ptr_int,
4760                    i64_type.ptr_type(Default::default()),
4761                    "arr_ptr",
4762                )
4763                .map_err(|e| e.to_string())?;
4764
4765            // GEP to get element at index
4766            let elem_ptr = unsafe {
4767                self.builder
4768                    .build_gep(i64_type, base_ptr, &[idx], "elem_ptr")
4769            }
4770            .map_err(|e| e.to_string())?;
4771
4772            // Load and return the value
4773            let value = self
4774                .builder
4775                .build_load(i64_type, elem_ptr, "elem")
4776                .map_err(|e| e.to_string())?;
4777
4778            Ok(value.into_int_value())
4779        }
4780
4781        /// Compile a binary operation
4782        fn compile_binary_op(
4783            &mut self,
4784            op: BinOp,
4785            lhs: IntValue<'ctx>,
4786            rhs: IntValue<'ctx>,
4787        ) -> Result<IntValue<'ctx>, String> {
4788            match op {
4789                BinOp::Add => self
4790                    .builder
4791                    .build_int_add(lhs, rhs, "add")
4792                    .map_err(|e| e.to_string()),
4793                BinOp::Sub => self
4794                    .builder
4795                    .build_int_sub(lhs, rhs, "sub")
4796                    .map_err(|e| e.to_string()),
4797                BinOp::Mul => self
4798                    .builder
4799                    .build_int_mul(lhs, rhs, "mul")
4800                    .map_err(|e| e.to_string()),
4801                BinOp::Div => self
4802                    .builder
4803                    .build_int_signed_div(lhs, rhs, "div")
4804                    .map_err(|e| e.to_string()),
4805                BinOp::Rem => self
4806                    .builder
4807                    .build_int_signed_rem(lhs, rhs, "rem")
4808                    .map_err(|e| e.to_string()),
4809                BinOp::BitAnd => self
4810                    .builder
4811                    .build_and(lhs, rhs, "and")
4812                    .map_err(|e| e.to_string()),
4813                BinOp::BitOr => self
4814                    .builder
4815                    .build_or(lhs, rhs, "or")
4816                    .map_err(|e| e.to_string()),
4817                BinOp::BitXor => self
4818                    .builder
4819                    .build_xor(lhs, rhs, "xor")
4820                    .map_err(|e| e.to_string()),
4821                BinOp::Shl => self
4822                    .builder
4823                    .build_left_shift(lhs, rhs, "shl")
4824                    .map_err(|e| e.to_string()),
4825                BinOp::Shr => self
4826                    .builder
4827                    .build_right_shift(lhs, rhs, true, "shr")
4828                    .map_err(|e| e.to_string()),
4829                BinOp::Eq => {
4830                    let cmp = self
4831                        .builder
4832                        .build_int_compare(IntPredicate::EQ, lhs, rhs, "eq")
4833                        .map_err(|e| e.to_string())?;
4834                    self.builder
4835                        .build_int_z_extend(cmp, self.context.i64_type(), "eq_ext")
4836                        .map_err(|e| e.to_string())
4837                }
4838                BinOp::Ne => {
4839                    let cmp = self
4840                        .builder
4841                        .build_int_compare(IntPredicate::NE, lhs, rhs, "ne")
4842                        .map_err(|e| e.to_string())?;
4843                    self.builder
4844                        .build_int_z_extend(cmp, self.context.i64_type(), "ne_ext")
4845                        .map_err(|e| e.to_string())
4846                }
4847                BinOp::Lt => {
4848                    let cmp = self
4849                        .builder
4850                        .build_int_compare(IntPredicate::SLT, lhs, rhs, "lt")
4851                        .map_err(|e| e.to_string())?;
4852                    self.builder
4853                        .build_int_z_extend(cmp, self.context.i64_type(), "lt_ext")
4854                        .map_err(|e| e.to_string())
4855                }
4856                BinOp::Le => {
4857                    let cmp = self
4858                        .builder
4859                        .build_int_compare(IntPredicate::SLE, lhs, rhs, "le")
4860                        .map_err(|e| e.to_string())?;
4861                    self.builder
4862                        .build_int_z_extend(cmp, self.context.i64_type(), "le_ext")
4863                        .map_err(|e| e.to_string())
4864                }
4865                BinOp::Gt => {
4866                    let cmp = self
4867                        .builder
4868                        .build_int_compare(IntPredicate::SGT, lhs, rhs, "gt")
4869                        .map_err(|e| e.to_string())?;
4870                    self.builder
4871                        .build_int_z_extend(cmp, self.context.i64_type(), "gt_ext")
4872                        .map_err(|e| e.to_string())
4873                }
4874                BinOp::Ge => {
4875                    let cmp = self
4876                        .builder
4877                        .build_int_compare(IntPredicate::SGE, lhs, rhs, "ge")
4878                        .map_err(|e| e.to_string())?;
4879                    self.builder
4880                        .build_int_z_extend(cmp, self.context.i64_type(), "ge_ext")
4881                        .map_err(|e| e.to_string())
4882                }
4883                BinOp::And => {
4884                    // Logical AND: (lhs != 0) && (rhs != 0)
4885                    let zero = self.context.i64_type().const_int(0, false);
4886                    let lhs_bool = self
4887                        .builder
4888                        .build_int_compare(IntPredicate::NE, lhs, zero, "lhs_bool")
4889                        .map_err(|e| e.to_string())?;
4890                    let rhs_bool = self
4891                        .builder
4892                        .build_int_compare(IntPredicate::NE, rhs, zero, "rhs_bool")
4893                        .map_err(|e| e.to_string())?;
4894                    let and = self
4895                        .builder
4896                        .build_and(lhs_bool, rhs_bool, "and")
4897                        .map_err(|e| e.to_string())?;
4898                    self.builder
4899                        .build_int_z_extend(and, self.context.i64_type(), "and_ext")
4900                        .map_err(|e| e.to_string())
4901                }
4902                BinOp::Or => {
4903                    // Logical OR: (lhs != 0) || (rhs != 0)
4904                    let zero = self.context.i64_type().const_int(0, false);
4905                    let lhs_bool = self
4906                        .builder
4907                        .build_int_compare(IntPredicate::NE, lhs, zero, "lhs_bool")
4908                        .map_err(|e| e.to_string())?;
4909                    let rhs_bool = self
4910                        .builder
4911                        .build_int_compare(IntPredicate::NE, rhs, zero, "rhs_bool")
4912                        .map_err(|e| e.to_string())?;
4913                    let or = self
4914                        .builder
4915                        .build_or(lhs_bool, rhs_bool, "or")
4916                        .map_err(|e| e.to_string())?;
4917                    self.builder
4918                        .build_int_z_extend(or, self.context.i64_type(), "or_ext")
4919                        .map_err(|e| e.to_string())
4920                }
4921                _ => Ok(self.context.i64_type().const_int(0, false)),
4922            }
4923        }
4924
4925        /// Compile a unary operation
4926        fn compile_unary_op(
4927            &mut self,
4928            op: UnaryOp,
4929            val: IntValue<'ctx>,
4930        ) -> Result<IntValue<'ctx>, String> {
4931            match op {
4932                UnaryOp::Neg => self
4933                    .builder
4934                    .build_int_neg(val, "neg")
4935                    .map_err(|e| e.to_string()),
4936                UnaryOp::Not => {
4937                    // Logical NOT: val == 0 ? 1 : 0
4938                    let zero = self.context.i64_type().const_int(0, false);
4939                    let is_zero = self
4940                        .builder
4941                        .build_int_compare(IntPredicate::EQ, val, zero, "is_zero")
4942                        .map_err(|e| e.to_string())?;
4943                    self.builder
4944                        .build_int_z_extend(is_zero, self.context.i64_type(), "not")
4945                        .map_err(|e| e.to_string())
4946                }
4947                UnaryOp::Deref => {
4948                    // Dereference: treat val as pointer (i64 containing address) and load
4949                    let ptr = self
4950                        .builder
4951                        .build_int_to_ptr(
4952                            val,
4953                            self.context.ptr_type(AddressSpace::default()),
4954                            "deref_ptr",
4955                        )
4956                        .map_err(|e| e.to_string())?;
4957                    let loaded = self
4958                        .builder
4959                        .build_load(self.context.i64_type(), ptr, "deref_val")
4960                        .map_err(|e| e.to_string())?;
4961                    Ok(loaded.into_int_value())
4962                }
4963                UnaryOp::Ref | UnaryOp::RefMut => {
4964                    // Address-of operations - for now just return the value
4965                    // (proper handling would need to track allocas)
4966                    Ok(val)
4967                }
4968                _ => Ok(val),
4969            }
4970        }
4971
4972        /// Compile an if expression
4973        fn compile_if(
4974            &mut self,
4975            fn_value: FunctionValue<'ctx>,
4976            scope: &mut CompileScope<'ctx>,
4977            condition: &Expr,
4978            then_branch: &ast::Block,
4979            else_branch: Option<&Expr>,
4980        ) -> Result<IntValue<'ctx>, String> {
4981            // Check if this is an if-let pattern
4982            let (cond_val, let_binding) = if let Expr::Let { pattern, value } = condition {
4983                // Compile the value expression
4984                let val = self.compile_expr(fn_value, scope, value)?;
4985                // For if-let, the condition is whether val is non-null (Some)
4986                // Extract the binding name from the pattern
4987                let binding_name = match pattern {
4988                    ast::Pattern::Ident { name, .. } => Some(name.name.clone()),
4989                    ast::Pattern::TupleStruct { path, fields, .. } => {
4990                        // Pattern like ?file or Some(file)
4991                        // Extract the first field pattern's name
4992                        if !fields.is_empty() {
4993                            if let ast::Pattern::Ident { name, .. } = &fields[0] {
4994                                Some(name.name.clone())
4995                            } else {
4996                                None
4997                            }
4998                        } else {
4999                            None
5000                        }
5001                    }
5002                    _ => None,
5003                };
5004                (val, binding_name)
5005            } else {
5006                (self.compile_expr(fn_value, scope, condition)?, None)
5007            };
5008
5009            // Convert to i1 (bool)
5010            let zero = self.context.i64_type().const_int(0, false);
5011            let cond_bool = self
5012                .builder
5013                .build_int_compare(IntPredicate::NE, cond_val, zero, "cond")
5014                .map_err(|e| e.to_string())?;
5015
5016            // Create blocks
5017            let then_bb = self.context.append_basic_block(fn_value, "then");
5018            let else_bb = self.context.append_basic_block(fn_value, "else");
5019            let merge_bb = self.context.append_basic_block(fn_value, "merge");
5020
5021            self.builder
5022                .build_conditional_branch(cond_bool, then_bb, else_bb)
5023                .map_err(|e| e.to_string())?;
5024
5025            // Then block
5026            self.builder.position_at_end(then_bb);
5027
5028            // If this was an if-let, bind the variable in the then-block scope
5029            if let Some(name) = let_binding {
5030                let alloca = self
5031                    .builder
5032                    .build_alloca(self.context.i64_type(), &name)
5033                    .map_err(|e| e.to_string())?;
5034                self.builder
5035                    .build_store(alloca, cond_val)
5036                    .map_err(|e| e.to_string())?;
5037                scope.vars.insert(name, alloca);
5038            }
5039
5040            let then_val = self
5041                .compile_block(fn_value, scope, then_branch)?
5042                .unwrap_or_else(|| self.context.i64_type().const_int(0, false));
5043            let then_terminated = self
5044                .builder
5045                .get_insert_block()
5046                .unwrap()
5047                .get_terminator()
5048                .is_some();
5049            if !then_terminated {
5050                self.builder
5051                    .build_unconditional_branch(merge_bb)
5052                    .map_err(|e| e.to_string())?;
5053            }
5054            let then_bb_end = self.builder.get_insert_block().unwrap();
5055
5056            // Else block
5057            self.builder.position_at_end(else_bb);
5058            let else_val = if let Some(else_expr) = else_branch {
5059                self.compile_expr(fn_value, scope, else_expr)?
5060            } else {
5061                self.context.i64_type().const_int(0, false)
5062            };
5063            let else_terminated = self
5064                .builder
5065                .get_insert_block()
5066                .unwrap()
5067                .get_terminator()
5068                .is_some();
5069            if !else_terminated {
5070                self.builder
5071                    .build_unconditional_branch(merge_bb)
5072                    .map_err(|e| e.to_string())?;
5073            }
5074            let else_bb_end = self.builder.get_insert_block().unwrap();
5075
5076            // Merge block with phi
5077            self.builder.position_at_end(merge_bb);
5078
5079            // If both branches terminated (e.g., both returned), we can't create a phi
5080            if then_terminated && else_terminated {
5081                // This block is unreachable, but we need to return something
5082                return Ok(self.context.i64_type().const_int(0, false));
5083            }
5084
5085            let phi = self
5086                .builder
5087                .build_phi(self.context.i64_type(), "if_result")
5088                .map_err(|e| e.to_string())?;
5089
5090            if !then_terminated {
5091                phi.add_incoming(&[(&then_val, then_bb_end)]);
5092            }
5093            if !else_terminated {
5094                phi.add_incoming(&[(&else_val, else_bb_end)]);
5095            }
5096
5097            Ok(phi.as_basic_value().into_int_value())
5098        }
5099
5100        /// Compile a while loop
5101        fn compile_while(
5102            &mut self,
5103            fn_value: FunctionValue<'ctx>,
5104            scope: &mut CompileScope<'ctx>,
5105            condition: &Expr,
5106            body: &ast::Block,
5107        ) -> Result<IntValue<'ctx>, String> {
5108            // Create blocks
5109            let cond_bb = self.context.append_basic_block(fn_value, "while_cond");
5110            let body_bb = self.context.append_basic_block(fn_value, "while_body");
5111            let after_bb = self.context.append_basic_block(fn_value, "while_after");
5112
5113            // Jump to condition
5114            self.builder
5115                .build_unconditional_branch(cond_bb)
5116                .map_err(|e| e.to_string())?;
5117
5118            // Condition block
5119            self.builder.position_at_end(cond_bb);
5120            let cond_val = self.compile_expr(fn_value, scope, condition)?;
5121            let zero = self.context.i64_type().const_int(0, false);
5122            let cond_bool = self
5123                .builder
5124                .build_int_compare(IntPredicate::NE, cond_val, zero, "cond")
5125                .map_err(|e| e.to_string())?;
5126            self.builder
5127                .build_conditional_branch(cond_bool, body_bb, after_bb)
5128                .map_err(|e| e.to_string())?;
5129
5130            // Body block
5131            self.builder.position_at_end(body_bb);
5132            self.compile_block(fn_value, scope, body)?;
5133            // Check if body terminated (e.g., return)
5134            if self
5135                .builder
5136                .get_insert_block()
5137                .unwrap()
5138                .get_terminator()
5139                .is_none()
5140            {
5141                self.builder
5142                    .build_unconditional_branch(cond_bb)
5143                    .map_err(|e| e.to_string())?;
5144            }
5145
5146            // After block
5147            self.builder.position_at_end(after_bb);
5148            Ok(self.context.i64_type().const_int(0, false))
5149        }
5150
5151        /// Compile a for loop: `each pattern ∈ iter { body }`
5152        fn compile_for_loop(
5153            &mut self,
5154            fn_value: FunctionValue<'ctx>,
5155            scope: &mut CompileScope<'ctx>,
5156            pattern: &ast::Pattern,
5157            iter: &Expr,
5158            body: &ast::Block,
5159        ) -> Result<IntValue<'ctx>, String> {
5160            // Get the loop variable name(s) from pattern
5161            let var_names: Vec<String> = match pattern {
5162                ast::Pattern::Ident { name, .. } => vec![name.name.clone()],
5163                ast::Pattern::Tuple(elements) => {
5164                    // Tuple pattern like (a, b) or (x, y, z)
5165                    elements
5166                        .iter()
5167                        .filter_map(|elem| {
5168                            if let ast::Pattern::Ident { name, .. } = elem {
5169                                Some(name.name.clone())
5170                            } else {
5171                                None
5172                            }
5173                        })
5174                        .collect()
5175                }
5176                ast::Pattern::TupleStruct { path, fields, .. } => {
5177                    // TupleStruct pattern like Some(x) or Pair(a, b)
5178                    fields
5179                        .iter()
5180                        .filter_map(|f| {
5181                            if let ast::Pattern::Ident { name, .. } = f {
5182                                Some(name.name.clone())
5183                            } else {
5184                                None
5185                            }
5186                        })
5187                        .collect()
5188                }
5189                _ => vec!["_item".to_string()], // Fallback for unsupported patterns
5190            };
5191
5192            let var_name = var_names
5193                .first()
5194                .cloned()
5195                .unwrap_or_else(|| "_item".to_string());
5196
5197            // Evaluate iterator to get array
5198            let iter_val = self.compile_expr(fn_value, scope, iter)?;
5199
5200            // Create blocks for loop structure
5201            let init_bb = self.context.append_basic_block(fn_value, "for_init");
5202            let cond_bb = self.context.append_basic_block(fn_value, "for_cond");
5203            let body_bb = self.context.append_basic_block(fn_value, "for_body");
5204            let incr_bb = self.context.append_basic_block(fn_value, "for_incr");
5205            let after_bb = self.context.append_basic_block(fn_value, "for_after");
5206
5207            // Jump to init
5208            self.builder
5209                .build_unconditional_branch(init_bb)
5210                .map_err(|e| e.to_string())?;
5211
5212            // Init block: allocate index variable, set to 0
5213            self.builder.position_at_end(init_bb);
5214            let idx_ptr = self
5215                .builder
5216                .build_alloca(self.context.i64_type(), "for_idx")
5217                .map_err(|e| e.to_string())?;
5218            let zero = self.context.i64_type().const_int(0, false);
5219            self.builder
5220                .build_store(idx_ptr, zero)
5221                .map_err(|e| e.to_string())?;
5222
5223            // Allocate all loop variable(s) from pattern
5224            for name in &var_names {
5225                let var_ptr = self
5226                    .builder
5227                    .build_alloca(self.context.i64_type(), name)
5228                    .map_err(|e| e.to_string())?;
5229                scope.vars.insert(name.clone(), var_ptr);
5230            }
5231
5232            // Get array length - for now use a fixed approach
5233            // The iter_val is treated as an array pointer; we need its length
5234            // For simplicity, we'll extract length from the array header if available
5235            // or use a hardcoded approach for now
5236            let len_val = self.get_array_length(iter_val)?;
5237
5238            self.builder
5239                .build_unconditional_branch(cond_bb)
5240                .map_err(|e| e.to_string())?;
5241
5242            // Condition block: check if idx < len
5243            self.builder.position_at_end(cond_bb);
5244            let idx_val = self
5245                .builder
5246                .build_load(self.context.i64_type(), idx_ptr, "idx")
5247                .map_err(|e| e.to_string())?
5248                .into_int_value();
5249            let cond = self
5250                .builder
5251                .build_int_compare(IntPredicate::ULT, idx_val, len_val, "for_cond")
5252                .map_err(|e| e.to_string())?;
5253            self.builder
5254                .build_conditional_branch(cond, body_bb, after_bb)
5255                .map_err(|e| e.to_string())?;
5256
5257            // Body block: get element, bind to var, execute body
5258            self.builder.position_at_end(body_bb);
5259
5260            // Get element at current index
5261            let elem_val = self.get_array_element(iter_val, idx_val)?;
5262
5263            // Store in loop variable(s)
5264            // For tuple patterns, we'd need to destructure - for now just use first var
5265            if let Some(&first_var_ptr) = scope.vars.get(&var_name) {
5266                self.builder
5267                    .build_store(first_var_ptr, elem_val)
5268                    .map_err(|e| e.to_string())?;
5269            }
5270
5271            // Compile body
5272            self.compile_block(fn_value, scope, body)?;
5273
5274            // If body didn't terminate, jump to increment
5275            if self
5276                .builder
5277                .get_insert_block()
5278                .unwrap()
5279                .get_terminator()
5280                .is_none()
5281            {
5282                self.builder
5283                    .build_unconditional_branch(incr_bb)
5284                    .map_err(|e| e.to_string())?;
5285            }
5286
5287            // Increment block: idx++
5288            self.builder.position_at_end(incr_bb);
5289            let idx_val = self
5290                .builder
5291                .build_load(self.context.i64_type(), idx_ptr, "idx")
5292                .map_err(|e| e.to_string())?
5293                .into_int_value();
5294            let one = self.context.i64_type().const_int(1, false);
5295            let next_idx = self
5296                .builder
5297                .build_int_add(idx_val, one, "next_idx")
5298                .map_err(|e| e.to_string())?;
5299            self.builder
5300                .build_store(idx_ptr, next_idx)
5301                .map_err(|e| e.to_string())?;
5302            self.builder
5303                .build_unconditional_branch(cond_bb)
5304                .map_err(|e| e.to_string())?;
5305
5306            // After block
5307            self.builder.position_at_end(after_bb);
5308
5309            // Clean up: remove loop variable from scope
5310            scope.vars.remove(&var_name);
5311
5312            Ok(self.context.i64_type().const_int(0, false))
5313        }
5314
5315        /// Get the length of an array (represented as i64 for now)
5316        fn get_array_length(&self, _array_val: IntValue<'ctx>) -> Result<IntValue<'ctx>, String> {
5317            // For now, arrays are represented as packed structs or pointers
5318            // The length would typically be stored alongside the data
5319            // Simplified: return a constant for testing, needs proper implementation
5320            // TODO: Implement proper array length extraction from runtime representation
5321            Ok(self.context.i64_type().const_int(0, false))
5322        }
5323
5324        /// Get an element from an array at a given index
5325        fn get_array_element(
5326            &self,
5327            _array_val: IntValue<'ctx>,
5328            _index: IntValue<'ctx>,
5329        ) -> Result<IntValue<'ctx>, String> {
5330            // For now, return a placeholder
5331            // TODO: Implement proper array element access
5332            Ok(self.context.i64_type().const_int(0, false))
5333        }
5334
5335        /// Compile a function call
5336        fn compile_call(
5337            &mut self,
5338            fn_value: FunctionValue<'ctx>,
5339            scope: &mut CompileScope<'ctx>,
5340            func: &Expr,
5341            args: &[Expr],
5342        ) -> Result<IntValue<'ctx>, String> {
5343            // Get function name and full qualified path
5344            let (fn_name, full_path) = if let Expr::Path(path) = func {
5345                let segments: Vec<&str> = path
5346                    .segments
5347                    .iter()
5348                    .map(|s| s.ident.name.as_str())
5349                    .collect();
5350                let short_name = segments.last().copied().ok_or("Empty path")?;
5351                let full = segments.join("::");
5352                (short_name, full)
5353            } else if let Expr::Field { field, .. } = func {
5354                // Method call like obj.method() - field is the method name
5355                let method_name = field.name.as_str();
5356                (method_name, method_name.to_string())
5357            } else {
5358                // Fallback: treat as anonymous function call, return 0
5359                return Ok(self.context.i64_type().const_int(0, false));
5360            };
5361
5362            // Resolve Self:: and This:: to the actual type name
5363            let full_path = if full_path.starts_with("Self::")
5364                || full_path.starts_with("This::")
5365                || full_path.starts_with("Self·")
5366                || full_path.starts_with("This·")
5367            {
5368                if let Some(ref self_type) = self.current_self_type {
5369                    // Replace Self/This with actual type name
5370                    let method = if full_path.contains("::") {
5371                        full_path.split("::").last().unwrap_or("")
5372                    } else {
5373                        full_path.split('·').last().unwrap_or("")
5374                    };
5375                    // eprintln!("DEBUG: Resolving Self/This to {}::{}", self_type, method);
5376                    format!("{}::{}", self_type, method)
5377                } else {
5378                    return Err(format!(
5379                        "Self/This used outside of impl block: {}",
5380                        full_path
5381                    ));
5382                }
5383            } else {
5384                full_path
5385            };
5386
5387            // Handle common enum/type constructors explicitly (match statement has mysterious issues)
5388            if full_path == "Result::Ok" || full_path == "Result·Ok" {
5389                if args.is_empty() {
5390                    return Ok(self.context.i64_type().const_int(0, false));
5391                }
5392                return self.compile_expr(fn_value, scope, &args[0]);
5393            }
5394            if full_path == "Result::Err" || full_path == "Result·Err" {
5395                if args.is_empty() {
5396                    return Ok(self.context.i64_type().const_int(0, false));
5397                }
5398                return self.compile_expr(fn_value, scope, &args[0]);
5399            }
5400            if full_path == "Option::Some" || full_path == "Option·Some" {
5401                if args.is_empty() {
5402                    return Ok(self.context.i64_type().const_int(0, false));
5403                }
5404                return self.compile_expr(fn_value, scope, &args[0]);
5405            }
5406            if full_path == "Option::None" || full_path == "Option·None" {
5407                return Ok(self.context.i64_type().const_int(0, false));
5408            }
5409            if full_path == "String::new" || full_path == "String·new" {
5410                let str_new_fn = self
5411                    .module
5412                    .get_function("sigil_string_new")
5413                    .ok_or("sigil_string_new not declared")?;
5414                let call = self
5415                    .builder
5416                    .build_call(str_new_fn, &[], "string_new")
5417                    .map_err(|e| e.to_string())?;
5418                return Ok(call
5419                    .try_as_basic_value()
5420                    .left()
5421                    .map(|v| v.into_int_value())
5422                    .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
5423            }
5424            if full_path == "String::from" || full_path == "String·from" {
5425                if args.is_empty() {
5426                    return Ok(self.context.i64_type().const_int(0, false));
5427                }
5428                return self.compile_expr(fn_value, scope, &args[0]);
5429            }
5430            if full_path == "Config::default" {
5431                // Config::default() returns a struct - for now, return 0 as placeholder
5432                return Ok(self.context.i64_type().const_int(0, false));
5433            }
5434            // Print functions - handle both strings and integers
5435            if full_path == "println"
5436                || full_path == "print"
5437                || full_path == "eprintln"
5438                || full_path == "eprint"
5439            {
5440                let is_stderr = full_path == "eprintln" || full_path == "eprint";
5441                let with_newline = full_path == "println" || full_path == "eprintln";
5442
5443                if !args.is_empty() {
5444                    // Check if argument is a string literal
5445                    let is_string = matches!(&args[0], Expr::Literal(Literal::String(_)));
5446
5447                    if is_string {
5448                        // For string literals, compile to get pointer and call print_str
5449                        if let Expr::Literal(Literal::String(s)) = &args[0] {
5450                            let str_ptr = self.create_global_string(s, "print_str");
5451                            let print_fn_name = if is_stderr {
5452                                if with_newline {
5453                                    "eprintln"
5454                                } else {
5455                                    "eprint"
5456                                }
5457                            } else {
5458                                if with_newline {
5459                                    "println"
5460                                } else {
5461                                    "print"
5462                                }
5463                            };
5464                            // Try extern C functions first, fall back to sigil_print_str
5465                            if let Some(print_fn) = self.module.get_function(print_fn_name) {
5466                                self.builder
5467                                    .build_call(print_fn, &[str_ptr.into()], "print_call")
5468                                    .map_err(|e| e.to_string())?;
5469                            } else if let Some(print_fn) =
5470                                self.module.get_function("sigil_print_str")
5471                            {
5472                                self.builder
5473                                    .build_call(print_fn, &[str_ptr.into()], "print_call")
5474                                    .map_err(|e| e.to_string())?;
5475                                // Add newline if needed
5476                                if with_newline {
5477                                    let nl_ptr = self.create_global_string("\n", "newline");
5478                                    if let Some(write_fn) =
5479                                        self.module.get_function("sigil_write_str")
5480                                    {
5481                                        self.builder
5482                                            .build_call(write_fn, &[nl_ptr.into()], "nl_call")
5483                                            .map_err(|e| e.to_string())?;
5484                                    }
5485                                }
5486                            }
5487                        }
5488                    } else {
5489                        // For non-string arguments, compile and print as int
5490                        let arg = self.compile_expr(fn_value, scope, &args[0])?;
5491                        if let Some(print_fn) = self.module.get_function("sigil_print_int") {
5492                            self.builder
5493                                .build_call(print_fn, &[arg.into()], "print_call")
5494                                .map_err(|e| e.to_string())?;
5495                        }
5496                        // Add newline for println/eprintln with non-string
5497                        if with_newline {
5498                            if let Some(print_nl) = self.module.get_function("sigil_print_newline")
5499                            {
5500                                self.builder
5501                                    .build_call(print_nl, &[], "nl_call")
5502                                    .map_err(|e| e.to_string())?;
5503                            }
5504                        }
5505                    }
5506                } else {
5507                    // No args - just print newline for println/eprintln
5508                    if with_newline {
5509                        if let Some(print_nl) = self.module.get_function("sigil_print_newline") {
5510                            self.builder
5511                                .build_call(print_nl, &[], "nl_call")
5512                                .map_err(|e| e.to_string())?;
5513                        }
5514                    }
5515                }
5516                return Ok(self.context.i64_type().const_int(0, false));
5517            }
5518            // Format function
5519            if full_path == "format" || full_path == "format!" {
5520                // For now, just return the first argument or empty string
5521                if !args.is_empty() {
5522                    return self.compile_expr(fn_value, scope, &args[0]);
5523                }
5524                return Ok(self.context.i64_type().const_int(0, false));
5525            }
5526            // Panic function
5527            if full_path == "panic" || full_path == "panic!" || full_path == "unreachable" {
5528                // Print error and abort
5529                if let Some(panic_fn) = self.module.get_function("sigil_panic") {
5530                    self.builder
5531                        .build_call(panic_fn, &[], "panic_call")
5532                        .map_err(|e| e.to_string())?;
5533                }
5534                return Ok(self.context.i64_type().const_int(0, false));
5535            }
5536            // assert functions
5537            if full_path == "assert"
5538                || full_path == "assert!"
5539                || full_path == "assert_eq"
5540                || full_path == "assert_eq!"
5541            {
5542                // For now, just evaluate arguments and ignore
5543                for arg in args {
5544                    self.compile_expr(fn_value, scope, arg)?;
5545                }
5546                return Ok(self.context.i64_type().const_int(0, false));
5547            }
5548
5549            // Handle qualified type paths (e.g., Vec::new, Box::new)
5550            match full_path.as_str() {
5551                "Vec::new" => {
5552                    // Vec::new() with default capacity
5553                    let capacity = self.context.i64_type().const_int(8, false);
5554                    let vec_new_fn = self
5555                        .module
5556                        .get_function("sigil_vec_new")
5557                        .ok_or("sigil_vec_new not declared")?;
5558                    let call = self
5559                        .builder
5560                        .build_call(vec_new_fn, &[capacity.into()], "vec_new")
5561                        .map_err(|e| e.to_string())?;
5562                    return Ok(call
5563                        .try_as_basic_value()
5564                        .left()
5565                        .map(|v| v.into_int_value())
5566                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
5567                }
5568                "Vec::with_capacity" => {
5569                    if args.is_empty() {
5570                        return Err("Vec::with_capacity requires capacity argument".to_string());
5571                    }
5572                    let capacity = self.compile_expr(fn_value, scope, &args[0])?;
5573                    let vec_new_fn = self
5574                        .module
5575                        .get_function("sigil_vec_new")
5576                        .ok_or("sigil_vec_new not declared")?;
5577                    let call = self
5578                        .builder
5579                        .build_call(vec_new_fn, &[capacity.into()], "vec_new")
5580                        .map_err(|e| e.to_string())?;
5581                    return Ok(call
5582                        .try_as_basic_value()
5583                        .left()
5584                        .map(|v| v.into_int_value())
5585                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
5586                }
5587                "Box::new" => {
5588                    // Box::new allocates and stores value
5589                    if args.is_empty() {
5590                        return Err("Box::new requires a value argument".to_string());
5591                    }
5592                    // Allocate 8 bytes (i64) and store the value
5593                    let alloc_fn = self
5594                        .module
5595                        .get_function("sigil_alloc")
5596                        .ok_or("sigil_alloc not declared")?;
5597                    let size = self.context.i64_type().const_int(8, false);
5598                    let call = self
5599                        .builder
5600                        .build_call(alloc_fn, &[size.into()], "box_alloc")
5601                        .map_err(|e| e.to_string())?;
5602                    let ptr = call
5603                        .try_as_basic_value()
5604                        .left()
5605                        .map(|v| v.into_int_value())
5606                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false));
5607
5608                    // Compile the value and store it
5609                    let value = self.compile_expr(fn_value, scope, &args[0])?;
5610                    let ptr_as_ptr = self
5611                        .builder
5612                        .build_int_to_ptr(
5613                            ptr,
5614                            self.context.ptr_type(AddressSpace::default()),
5615                            "box_ptr",
5616                        )
5617                        .map_err(|e| e.to_string())?;
5618                    self.builder
5619                        .build_store(ptr_as_ptr, value)
5620                        .map_err(|e| e.to_string())?;
5621
5622                    return Ok(ptr);
5623                }
5624                // File I/O operations
5625                "File::read" | "File::read_all" => {
5626                    // File::read(path) -> String content
5627                    if args.is_empty() {
5628                        return Err("File::read requires a path argument".to_string());
5629                    }
5630                    // Get the path string pointer
5631                    let path_val = self.compile_expr(fn_value, scope, &args[0])?;
5632                    let read_fn = self
5633                        .module
5634                        .get_function("sigil_file_read_all")
5635                        .ok_or("sigil_file_read_all not declared")?;
5636                    let call = self
5637                        .builder
5638                        .build_call(read_fn, &[path_val.into()], "file_read")
5639                        .map_err(|e| e.to_string())?;
5640                    return Ok(call
5641                        .try_as_basic_value()
5642                        .left()
5643                        .map(|v| v.into_int_value())
5644                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
5645                }
5646                "File::write" | "File::write_all" => {
5647                    // File::write(path, content) -> success (1 or 0)
5648                    if args.len() < 2 {
5649                        return Err("File::write requires path and content arguments".to_string());
5650                    }
5651                    let path_val = self.compile_expr(fn_value, scope, &args[0])?;
5652                    let content_val = self.compile_expr(fn_value, scope, &args[1])?;
5653                    let write_fn = self
5654                        .module
5655                        .get_function("sigil_file_write_all")
5656                        .ok_or("sigil_file_write_all not declared")?;
5657                    let call = self
5658                        .builder
5659                        .build_call(
5660                            write_fn,
5661                            &[path_val.into(), content_val.into()],
5662                            "file_write",
5663                        )
5664                        .map_err(|e| e.to_string())?;
5665                    return Ok(call
5666                        .try_as_basic_value()
5667                        .left()
5668                        .map(|v| v.into_int_value())
5669                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
5670                }
5671                "File::exists" => {
5672                    // File::exists(path) -> 1 or 0
5673                    if args.is_empty() {
5674                        return Err("File::exists requires a path argument".to_string());
5675                    }
5676                    let path_val = self.compile_expr(fn_value, scope, &args[0])?;
5677                    let exists_fn = self
5678                        .module
5679                        .get_function("sigil_file_exists")
5680                        .ok_or("sigil_file_exists not declared")?;
5681                    let call = self
5682                        .builder
5683                        .build_call(exists_fn, &[path_val.into()], "file_exists")
5684                        .map_err(|e| e.to_string())?;
5685                    return Ok(call
5686                        .try_as_basic_value()
5687                        .left()
5688                        .map(|v| v.into_int_value())
5689                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
5690                }
5691                // ========================================
5692                // AVX-512 SIMD Intrinsics
5693                // ========================================
5694                "F32x16::splat" => {
5695                    // Create a vector with all elements set to the same value via runtime
5696                    if args.is_empty() {
5697                        return Err("F32x16::splat requires a value argument".to_string());
5698                    }
5699                    let scalar = self.compile_expr(fn_value, scope, &args[0])?;
5700
5701                    // Allocate aligned result buffer via sigil_simd_alloc (64-byte aligned for AVX-512)
5702                    let alloc_fn = self
5703                        .module
5704                        .get_function("sigil_simd_alloc")
5705                        .ok_or("sigil_simd_alloc not declared")?;
5706                    // 16 floats
5707                    let result_call = self
5708                        .builder
5709                        .build_call(
5710                            alloc_fn,
5711                            &[self.context.i64_type().const_int(16, false).into()],
5712                            "result_buf",
5713                        )
5714                        .map_err(|e| e.to_string())?;
5715                    let result_val = result_call
5716                        .try_as_basic_value()
5717                        .left()
5718                        .ok_or("alloc returned void")?;
5719                    // Handle both pointer and integer return types
5720                    let result_int = if result_val.is_pointer_value() {
5721                        self.builder
5722                            .build_ptr_to_int(
5723                                result_val.into_pointer_value(),
5724                                self.context.i64_type(),
5725                                "result_int",
5726                            )
5727                            .map_err(|e| e.to_string())?
5728                    } else {
5729                        result_val.into_int_value()
5730                    };
5731
5732                    // Convert i64 bits to f32 for splat
5733                    let f32_val = self
5734                        .builder
5735                        .build_bit_cast(scalar, self.context.f32_type(), "f32_val")
5736                        .map_err(|e| e.to_string())?;
5737
5738                    // Call runtime splat
5739                    let splat_fn = self
5740                        .module
5741                        .get_function("sigil_simd_splat_f32x16")
5742                        .ok_or("sigil_simd_splat_f32x16 not declared")?;
5743                    let ptr_type = self.context.ptr_type(AddressSpace::default());
5744                    let dest_ptr = self
5745                        .builder
5746                        .build_int_to_ptr(result_int, ptr_type, "dest")
5747                        .map_err(|e| e.to_string())?;
5748                    self.builder
5749                        .build_call(splat_fn, &[dest_ptr.into(), f32_val.into()], "")
5750                        .map_err(|e| e.to_string())?;
5751
5752                    return Ok(result_int);
5753                }
5754                "F32x16::load_aligned" | "_mm512_load_ps" => {
5755                    // Load 16 f32s from aligned memory via runtime
5756                    if args.is_empty() {
5757                        return Err("F32x16::load_aligned requires a pointer argument".to_string());
5758                    }
5759                    let src_ptr_val = self.compile_expr(fn_value, scope, &args[0])?;
5760
5761                    // Allocate aligned result buffer (64-byte aligned for AVX-512)
5762                    let alloc_fn = self
5763                        .module
5764                        .get_function("sigil_simd_alloc")
5765                        .ok_or("sigil_simd_alloc not declared")?;
5766                    let result_call = self
5767                        .builder
5768                        .build_call(
5769                            alloc_fn,
5770                            &[self.context.i64_type().const_int(16, false).into()],
5771                            "result_buf",
5772                        )
5773                        .map_err(|e| e.to_string())?;
5774                    let result_val = result_call
5775                        .try_as_basic_value()
5776                        .left()
5777                        .ok_or("alloc returned void")?;
5778                    let result_int = if result_val.is_pointer_value() {
5779                        self.builder
5780                            .build_ptr_to_int(
5781                                result_val.into_pointer_value(),
5782                                self.context.i64_type(),
5783                                "result_int",
5784                            )
5785                            .map_err(|e| e.to_string())?
5786                    } else {
5787                        result_val.into_int_value()
5788                    };
5789
5790                    // Call runtime load
5791                    let load_fn = self
5792                        .module
5793                        .get_function("sigil_simd_load_f32x16")
5794                        .ok_or("sigil_simd_load_f32x16 not declared")?;
5795                    let ptr_type = self.context.ptr_type(AddressSpace::default());
5796                    let dest_ptr = self
5797                        .builder
5798                        .build_int_to_ptr(result_int, ptr_type, "dest")
5799                        .map_err(|e| e.to_string())?;
5800                    let src_ptr = self
5801                        .builder
5802                        .build_int_to_ptr(src_ptr_val, ptr_type, "src")
5803                        .map_err(|e| e.to_string())?;
5804                    self.builder
5805                        .build_call(load_fn, &[dest_ptr.into(), src_ptr.into()], "")
5806                        .map_err(|e| e.to_string())?;
5807
5808                    return Ok(result_int);
5809                }
5810                "F32x16::store_aligned" | "_mm512_store_ps" => {
5811                    // Store 16 f32s to aligned memory via runtime
5812                    if args.len() < 2 {
5813                        return Err(
5814                            "F32x16::store_aligned requires destination and value".to_string()
5815                        );
5816                    }
5817                    let dest_val = self.compile_expr(fn_value, scope, &args[0])?;
5818                    let src_val = self.compile_expr(fn_value, scope, &args[1])?;
5819
5820                    // Call runtime store
5821                    let store_fn = self
5822                        .module
5823                        .get_function("sigil_simd_store_f32x16")
5824                        .ok_or("sigil_simd_store_f32x16 not declared")?;
5825                    let ptr_type = self.context.ptr_type(AddressSpace::default());
5826                    let dest_ptr = self
5827                        .builder
5828                        .build_int_to_ptr(dest_val, ptr_type, "dest")
5829                        .map_err(|e| e.to_string())?;
5830                    let src_ptr = self
5831                        .builder
5832                        .build_int_to_ptr(src_val, ptr_type, "src")
5833                        .map_err(|e| e.to_string())?;
5834                    self.builder
5835                        .build_call(store_fn, &[dest_ptr.into(), src_ptr.into()], "")
5836                        .map_err(|e| e.to_string())?;
5837
5838                    return Ok(self.context.i64_type().const_int(0, false));
5839                }
5840                "F32x16::add" | "_mm512_add_ps" => {
5841                    // Vector add via runtime: dest = a + b
5842                    if args.len() < 2 {
5843                        return Err("F32x16::add requires two vector arguments".to_string());
5844                    }
5845                    let a_ptr = self.compile_expr(fn_value, scope, &args[0])?;
5846                    let b_ptr = self.compile_expr(fn_value, scope, &args[1])?;
5847
5848                    // Allocate aligned result buffer (64-byte aligned for AVX-512)
5849                    let alloc_fn = self
5850                        .module
5851                        .get_function("sigil_simd_alloc")
5852                        .ok_or("sigil_simd_alloc not declared")?;
5853                    let result_call = self
5854                        .builder
5855                        .build_call(
5856                            alloc_fn,
5857                            &[self.context.i64_type().const_int(16, false).into()],
5858                            "result_buf",
5859                        )
5860                        .map_err(|e| e.to_string())?;
5861                    let result_val = result_call
5862                        .try_as_basic_value()
5863                        .left()
5864                        .ok_or("alloc returned void")?;
5865                    let result_int = if result_val.is_pointer_value() {
5866                        self.builder
5867                            .build_ptr_to_int(
5868                                result_val.into_pointer_value(),
5869                                self.context.i64_type(),
5870                                "result_int",
5871                            )
5872                            .map_err(|e| e.to_string())?
5873                    } else {
5874                        result_val.into_int_value()
5875                    };
5876
5877                    // Call runtime SIMD add
5878                    let add_fn = self
5879                        .module
5880                        .get_function("sigil_simd_add_f32x16")
5881                        .ok_or("sigil_simd_add_f32x16 not declared")?;
5882                    let ptr_type = self.context.ptr_type(AddressSpace::default());
5883                    let dest_ptr = self
5884                        .builder
5885                        .build_int_to_ptr(result_int, ptr_type, "dest")
5886                        .map_err(|e| e.to_string())?;
5887                    let a_ptr_cast = self
5888                        .builder
5889                        .build_int_to_ptr(a_ptr, ptr_type, "a")
5890                        .map_err(|e| e.to_string())?;
5891                    let b_ptr_cast = self
5892                        .builder
5893                        .build_int_to_ptr(b_ptr, ptr_type, "b")
5894                        .map_err(|e| e.to_string())?;
5895                    self.builder
5896                        .build_call(
5897                            add_fn,
5898                            &[dest_ptr.into(), a_ptr_cast.into(), b_ptr_cast.into()],
5899                            "",
5900                        )
5901                        .map_err(|e| e.to_string())?;
5902
5903                    return Ok(result_int);
5904                }
5905                "F32x16::mul" | "_mm512_mul_ps" => {
5906                    // Vector multiply via runtime: dest = a * b
5907                    if args.len() < 2 {
5908                        return Err("F32x16::mul requires two vector arguments".to_string());
5909                    }
5910                    let a_ptr = self.compile_expr(fn_value, scope, &args[0])?;
5911                    let b_ptr = self.compile_expr(fn_value, scope, &args[1])?;
5912
5913                    // Allocate aligned result buffer (64-byte aligned for AVX-512)
5914                    let alloc_fn = self
5915                        .module
5916                        .get_function("sigil_simd_alloc")
5917                        .ok_or("sigil_simd_alloc not declared")?;
5918                    let result_call = self
5919                        .builder
5920                        .build_call(
5921                            alloc_fn,
5922                            &[self.context.i64_type().const_int(16, false).into()],
5923                            "result_buf",
5924                        )
5925                        .map_err(|e| e.to_string())?;
5926                    let result_val = result_call
5927                        .try_as_basic_value()
5928                        .left()
5929                        .ok_or("alloc returned void")?;
5930                    let result_int = if result_val.is_pointer_value() {
5931                        self.builder
5932                            .build_ptr_to_int(
5933                                result_val.into_pointer_value(),
5934                                self.context.i64_type(),
5935                                "result_int",
5936                            )
5937                            .map_err(|e| e.to_string())?
5938                    } else {
5939                        result_val.into_int_value()
5940                    };
5941
5942                    // Call runtime SIMD mul
5943                    let mul_fn = self
5944                        .module
5945                        .get_function("sigil_simd_mul_f32x16")
5946                        .ok_or("sigil_simd_mul_f32x16 not declared")?;
5947                    let ptr_type = self.context.ptr_type(AddressSpace::default());
5948                    let dest_ptr = self
5949                        .builder
5950                        .build_int_to_ptr(result_int, ptr_type, "dest")
5951                        .map_err(|e| e.to_string())?;
5952                    let a_ptr_cast = self
5953                        .builder
5954                        .build_int_to_ptr(a_ptr, ptr_type, "a")
5955                        .map_err(|e| e.to_string())?;
5956                    let b_ptr_cast = self
5957                        .builder
5958                        .build_int_to_ptr(b_ptr, ptr_type, "b")
5959                        .map_err(|e| e.to_string())?;
5960                    self.builder
5961                        .build_call(
5962                            mul_fn,
5963                            &[dest_ptr.into(), a_ptr_cast.into(), b_ptr_cast.into()],
5964                            "",
5965                        )
5966                        .map_err(|e| e.to_string())?;
5967
5968                    return Ok(result_int);
5969                }
5970                "F32x16::fmadd" | "_mm512_fmadd_ps" => {
5971                    // Fused multiply-add via runtime: dest = a * b + c
5972                    if args.len() < 3 {
5973                        return Err("F32x16::fmadd requires three vector arguments".to_string());
5974                    }
5975                    let a_ptr = self.compile_expr(fn_value, scope, &args[0])?;
5976                    let b_ptr = self.compile_expr(fn_value, scope, &args[1])?;
5977                    let c_ptr = self.compile_expr(fn_value, scope, &args[2])?;
5978
5979                    // Allocate aligned result buffer (64-byte aligned for AVX-512)
5980                    let alloc_fn = self
5981                        .module
5982                        .get_function("sigil_simd_alloc")
5983                        .ok_or("sigil_simd_alloc not declared")?;
5984                    let result_call = self
5985                        .builder
5986                        .build_call(
5987                            alloc_fn,
5988                            &[self.context.i64_type().const_int(16, false).into()],
5989                            "result_buf",
5990                        )
5991                        .map_err(|e| e.to_string())?;
5992                    let result_val = result_call
5993                        .try_as_basic_value()
5994                        .left()
5995                        .ok_or("alloc returned void")?;
5996                    let result_int = if result_val.is_pointer_value() {
5997                        self.builder
5998                            .build_ptr_to_int(
5999                                result_val.into_pointer_value(),
6000                                self.context.i64_type(),
6001                                "result_int",
6002                            )
6003                            .map_err(|e| e.to_string())?
6004                    } else {
6005                        result_val.into_int_value()
6006                    };
6007
6008                    // Call runtime SIMD fmadd
6009                    let fmadd_fn = self
6010                        .module
6011                        .get_function("sigil_simd_fmadd_f32x16")
6012                        .ok_or("sigil_simd_fmadd_f32x16 not declared")?;
6013                    let ptr_type = self.context.ptr_type(AddressSpace::default());
6014                    let dest_ptr = self
6015                        .builder
6016                        .build_int_to_ptr(result_int, ptr_type, "dest")
6017                        .map_err(|e| e.to_string())?;
6018                    let a_ptr_cast = self
6019                        .builder
6020                        .build_int_to_ptr(a_ptr, ptr_type, "a")
6021                        .map_err(|e| e.to_string())?;
6022                    let b_ptr_cast = self
6023                        .builder
6024                        .build_int_to_ptr(b_ptr, ptr_type, "b")
6025                        .map_err(|e| e.to_string())?;
6026                    let c_ptr_cast = self
6027                        .builder
6028                        .build_int_to_ptr(c_ptr, ptr_type, "c")
6029                        .map_err(|e| e.to_string())?;
6030                    self.builder
6031                        .build_call(
6032                            fmadd_fn,
6033                            &[
6034                                dest_ptr.into(),
6035                                a_ptr_cast.into(),
6036                                b_ptr_cast.into(),
6037                                c_ptr_cast.into(),
6038                            ],
6039                            "",
6040                        )
6041                        .map_err(|e| e.to_string())?;
6042
6043                    return Ok(result_int);
6044                }
6045                "F32x16::extract" => {
6046                    // Extract single element from vector via runtime
6047                    if args.len() < 2 {
6048                        return Err("F32x16::extract requires vector and index".to_string());
6049                    }
6050                    let vec_ptr = self.compile_expr(fn_value, scope, &args[0])?;
6051                    let idx = self.compile_expr(fn_value, scope, &args[1])?;
6052
6053                    // Call runtime extract
6054                    let extract_fn = self
6055                        .module
6056                        .get_function("sigil_simd_extract_f32x16")
6057                        .ok_or("sigil_simd_extract_f32x16 not declared")?;
6058                    let ptr_type = self.context.ptr_type(AddressSpace::default());
6059                    let src_ptr = self
6060                        .builder
6061                        .build_int_to_ptr(vec_ptr, ptr_type, "src")
6062                        .map_err(|e| e.to_string())?;
6063                    let f32_result = self
6064                        .builder
6065                        .build_call(extract_fn, &[src_ptr.into(), idx.into()], "extract")
6066                        .map_err(|e| e.to_string())?
6067                        .try_as_basic_value()
6068                        .left()
6069                        .ok_or("extract returned void")?;
6070
6071                    // Convert f32 back to i64 bits
6072                    let bits = self
6073                        .builder
6074                        .build_bit_cast(f32_result, self.context.i32_type(), "bits")
6075                        .map_err(|e| e.to_string())?;
6076                    let extended = self
6077                        .builder
6078                        .build_int_z_extend(bits.into_int_value(), self.context.i64_type(), "ext")
6079                        .map_err(|e| e.to_string())?;
6080                    return Ok(extended);
6081                }
6082                "F32x16::reduce_add" => {
6083                    // Horizontal sum via runtime
6084                    if args.is_empty() {
6085                        return Err("F32x16::reduce_add requires a vector argument".to_string());
6086                    }
6087                    let vec_ptr = self.compile_expr(fn_value, scope, &args[0])?;
6088
6089                    // Call runtime reduce_add
6090                    let reduce_fn = self
6091                        .module
6092                        .get_function("sigil_simd_reduce_add_f32x16")
6093                        .ok_or("sigil_simd_reduce_add_f32x16 not declared")?;
6094                    let ptr_type = self.context.ptr_type(AddressSpace::default());
6095                    let src_ptr = self
6096                        .builder
6097                        .build_int_to_ptr(vec_ptr, ptr_type, "src")
6098                        .map_err(|e| e.to_string())?;
6099                    let f32_result = self
6100                        .builder
6101                        .build_call(reduce_fn, &[src_ptr.into()], "reduce")
6102                        .map_err(|e| e.to_string())?
6103                        .try_as_basic_value()
6104                        .left()
6105                        .ok_or("reduce returned void")?;
6106
6107                    // Convert f32 back to i64 bits
6108                    let bits = self
6109                        .builder
6110                        .build_bit_cast(f32_result, self.context.i32_type(), "bits")
6111                        .map_err(|e| e.to_string())?;
6112                    let extended = self
6113                        .builder
6114                        .build_int_z_extend(bits.into_int_value(), self.context.i64_type(), "ext")
6115                        .map_err(|e| e.to_string())?;
6116                    return Ok(extended);
6117                }
6118                "F32x16::dot" => {
6119                    // Dot product via runtime
6120                    if args.len() < 2 {
6121                        return Err("F32x16::dot requires two vector arguments".to_string());
6122                    }
6123                    let a_ptr = self.compile_expr(fn_value, scope, &args[0])?;
6124                    let b_ptr = self.compile_expr(fn_value, scope, &args[1])?;
6125
6126                    // Call runtime dot
6127                    let dot_fn = self
6128                        .module
6129                        .get_function("sigil_simd_dot_f32x16")
6130                        .ok_or("sigil_simd_dot_f32x16 not declared")?;
6131                    let ptr_type = self.context.ptr_type(AddressSpace::default());
6132                    let a_ptr_cast = self
6133                        .builder
6134                        .build_int_to_ptr(a_ptr, ptr_type, "a")
6135                        .map_err(|e| e.to_string())?;
6136                    let b_ptr_cast = self
6137                        .builder
6138                        .build_int_to_ptr(b_ptr, ptr_type, "b")
6139                        .map_err(|e| e.to_string())?;
6140                    let f32_result = self
6141                        .builder
6142                        .build_call(dot_fn, &[a_ptr_cast.into(), b_ptr_cast.into()], "dot")
6143                        .map_err(|e| e.to_string())?
6144                        .try_as_basic_value()
6145                        .left()
6146                        .ok_or("dot returned void")?;
6147
6148                    // Convert f32 back to i64 bits
6149                    let bits = self
6150                        .builder
6151                        .build_bit_cast(f32_result, self.context.i32_type(), "bits")
6152                        .map_err(|e| e.to_string())?;
6153                    let extended = self
6154                        .builder
6155                        .build_int_z_extend(bits.into_int_value(), self.context.i64_type(), "ext")
6156                        .map_err(|e| e.to_string())?;
6157                    return Ok(extended);
6158                }
6159                // ========================================
6160                // CUDA Functions
6161                // ========================================
6162                "Cuda::init" | "cuda_init" => {
6163                    let init_fn = self
6164                        .module
6165                        .get_function("sigil_cuda_init")
6166                        .ok_or("sigil_cuda_init not declared")?;
6167                    let result = self
6168                        .builder
6169                        .build_call(init_fn, &[], "cuda_init")
6170                        .map_err(|e| e.to_string())?
6171                        .try_as_basic_value()
6172                        .left()
6173                        .ok_or("cuda_init returned void")?;
6174                    return Ok(result.into_int_value());
6175                }
6176                "Cuda::cleanup" | "cuda_cleanup" => {
6177                    let cleanup_fn = self
6178                        .module
6179                        .get_function("sigil_cuda_cleanup")
6180                        .ok_or("sigil_cuda_cleanup not declared")?;
6181                    self.builder
6182                        .build_call(cleanup_fn, &[], "")
6183                        .map_err(|e| e.to_string())?;
6184                    return Ok(self.context.i64_type().const_int(0, false));
6185                }
6186                "Cuda::device_count" | "cuda_device_count" => {
6187                    let count_fn = self
6188                        .module
6189                        .get_function("sigil_cuda_get_device_count")
6190                        .ok_or("sigil_cuda_get_device_count not declared")?;
6191                    let result = self
6192                        .builder
6193                        .build_call(count_fn, &[], "device_count")
6194                        .map_err(|e| e.to_string())?
6195                        .try_as_basic_value()
6196                        .left()
6197                        .ok_or("device_count returned void")?;
6198                    return Ok(result.into_int_value());
6199                }
6200                "Cuda::malloc" | "cuda_malloc" => {
6201                    if args.is_empty() {
6202                        return Err("Cuda::malloc requires size argument".to_string());
6203                    }
6204                    let size = self.compile_expr(fn_value, scope, &args[0])?;
6205                    let malloc_fn = self
6206                        .module
6207                        .get_function("sigil_cuda_malloc")
6208                        .ok_or("sigil_cuda_malloc not declared")?;
6209                    let result = self
6210                        .builder
6211                        .build_call(malloc_fn, &[size.into()], "cuda_ptr")
6212                        .map_err(|e| e.to_string())?
6213                        .try_as_basic_value()
6214                        .left()
6215                        .ok_or("cuda_malloc returned void")?;
6216                    return Ok(result.into_int_value());
6217                }
6218                "Cuda::free" | "cuda_free" => {
6219                    if args.is_empty() {
6220                        return Err("Cuda::free requires device pointer argument".to_string());
6221                    }
6222                    let ptr = self.compile_expr(fn_value, scope, &args[0])?;
6223                    let free_fn = self
6224                        .module
6225                        .get_function("sigil_cuda_free")
6226                        .ok_or("sigil_cuda_free not declared")?;
6227                    self.builder
6228                        .build_call(free_fn, &[ptr.into()], "")
6229                        .map_err(|e| e.to_string())?;
6230                    return Ok(self.context.i64_type().const_int(0, false));
6231                }
6232                "Cuda::memcpy_h2d" | "cuda_memcpy_h2d" => {
6233                    if args.len() < 3 {
6234                        return Err(
6235                            "Cuda::memcpy_h2d requires (dst_device, src_host, size)".to_string()
6236                        );
6237                    }
6238                    let dst = self.compile_expr(fn_value, scope, &args[0])?;
6239                    let src = self.compile_expr(fn_value, scope, &args[1])?;
6240                    let size = self.compile_expr(fn_value, scope, &args[2])?;
6241                    let ptr_type = self.context.ptr_type(AddressSpace::default());
6242                    let src_ptr = self
6243                        .builder
6244                        .build_int_to_ptr(src, ptr_type, "src_ptr")
6245                        .map_err(|e| e.to_string())?;
6246                    let h2d_fn = self
6247                        .module
6248                        .get_function("sigil_cuda_memcpy_h2d")
6249                        .ok_or("sigil_cuda_memcpy_h2d not declared")?;
6250                    let result = self
6251                        .builder
6252                        .build_call(h2d_fn, &[dst.into(), src_ptr.into(), size.into()], "h2d")
6253                        .map_err(|e| e.to_string())?
6254                        .try_as_basic_value()
6255                        .left()
6256                        .ok_or("h2d returned void")?;
6257                    return Ok(result.into_int_value());
6258                }
6259                "Cuda::memcpy_d2h" | "cuda_memcpy_d2h" => {
6260                    if args.len() < 3 {
6261                        return Err(
6262                            "Cuda::memcpy_d2h requires (dst_host, src_device, size)".to_string()
6263                        );
6264                    }
6265                    let dst = self.compile_expr(fn_value, scope, &args[0])?;
6266                    let src = self.compile_expr(fn_value, scope, &args[1])?;
6267                    let size = self.compile_expr(fn_value, scope, &args[2])?;
6268                    let ptr_type = self.context.ptr_type(AddressSpace::default());
6269                    let dst_ptr = self
6270                        .builder
6271                        .build_int_to_ptr(dst, ptr_type, "dst_ptr")
6272                        .map_err(|e| e.to_string())?;
6273                    let d2h_fn = self
6274                        .module
6275                        .get_function("sigil_cuda_memcpy_d2h")
6276                        .ok_or("sigil_cuda_memcpy_d2h not declared")?;
6277                    let result = self
6278                        .builder
6279                        .build_call(d2h_fn, &[dst_ptr.into(), src.into(), size.into()], "d2h")
6280                        .map_err(|e| e.to_string())?
6281                        .try_as_basic_value()
6282                        .left()
6283                        .ok_or("d2h returned void")?;
6284                    return Ok(result.into_int_value());
6285                }
6286                "Cuda::sync" | "cuda_sync" => {
6287                    let sync_fn = self
6288                        .module
6289                        .get_function("sigil_cuda_sync")
6290                        .ok_or("sigil_cuda_sync not declared")?;
6291                    self.builder
6292                        .build_call(sync_fn, &[], "")
6293                        .map_err(|e| e.to_string())?;
6294                    return Ok(self.context.i64_type().const_int(0, false));
6295                }
6296                "Cuda::compile_kernel" | "cuda_compile_kernel" => {
6297                    if args.len() < 2 {
6298                        return Err(
6299                            "Cuda::compile_kernel requires (cuda_source, kernel_name)".to_string()
6300                        );
6301                    }
6302                    let src = self.compile_expr(fn_value, scope, &args[0])?;
6303                    let name = self.compile_expr(fn_value, scope, &args[1])?;
6304                    let ptr_type = self.context.ptr_type(AddressSpace::default());
6305                    let src_ptr = self
6306                        .builder
6307                        .build_int_to_ptr(src, ptr_type, "src_ptr")
6308                        .map_err(|e| e.to_string())?;
6309                    let name_ptr = self
6310                        .builder
6311                        .build_int_to_ptr(name, ptr_type, "name_ptr")
6312                        .map_err(|e| e.to_string())?;
6313                    let compile_fn = self
6314                        .module
6315                        .get_function("sigil_cuda_compile_kernel")
6316                        .ok_or("sigil_cuda_compile_kernel not declared")?;
6317                    let result = self
6318                        .builder
6319                        .build_call(
6320                            compile_fn,
6321                            &[src_ptr.into(), name_ptr.into()],
6322                            "kernel_handle",
6323                        )
6324                        .map_err(|e| e.to_string())?
6325                        .try_as_basic_value()
6326                        .left()
6327                        .ok_or("compile_kernel returned void")?;
6328                    return Ok(result.into_int_value());
6329                }
6330                "Cuda::launch_1d" | "cuda_launch_1d" => {
6331                    // launch_1d(handle, grid_x, block_x, arg_array_ptr, num_args)
6332                    if args.len() < 5 {
6333                        return Err("Cuda::launch_1d requires (handle, grid_x, block_x, args_ptr, num_args)".to_string());
6334                    }
6335                    let handle = self.compile_expr(fn_value, scope, &args[0])?;
6336                    let grid_x = self.compile_expr(fn_value, scope, &args[1])?;
6337                    let block_x = self.compile_expr(fn_value, scope, &args[2])?;
6338                    let args_ptr = self.compile_expr(fn_value, scope, &args[3])?;
6339                    let num_args = self.compile_expr(fn_value, scope, &args[4])?;
6340                    let ptr_type = self.context.ptr_type(AddressSpace::default());
6341                    let args_cast = self
6342                        .builder
6343                        .build_int_to_ptr(args_ptr, ptr_type, "args")
6344                        .map_err(|e| e.to_string())?;
6345                    let launch_fn = self
6346                        .module
6347                        .get_function("sigil_cuda_launch_kernel_1d")
6348                        .ok_or("sigil_cuda_launch_kernel_1d not declared")?;
6349                    let result = self
6350                        .builder
6351                        .build_call(
6352                            launch_fn,
6353                            &[
6354                                handle.into(),
6355                                grid_x.into(),
6356                                block_x.into(),
6357                                args_cast.into(),
6358                                num_args.into(),
6359                            ],
6360                            "launch",
6361                        )
6362                        .map_err(|e| e.to_string())?
6363                        .try_as_basic_value()
6364                        .left()
6365                        .ok_or("launch returned void")?;
6366                    return Ok(result.into_int_value());
6367                }
6368                _ => {}
6369            }
6370
6371            // Handle built-in functions
6372            match fn_name {
6373                "print" => {
6374                    if !args.is_empty() {
6375                        let arg_val = self.compile_expr(fn_value, scope, &args[0])?;
6376                        // Call sigil_print_int (works in both JIT and AOT)
6377                        let print_fn = self
6378                            .module
6379                            .get_function("sigil_print_int")
6380                            .ok_or("sigil_print_int not declared")?;
6381                        self.builder
6382                            .build_call(print_fn, &[arg_val.into()], "")
6383                            .map_err(|e| e.to_string())?;
6384                        return Ok(arg_val);
6385                    }
6386                    return Ok(self.context.i64_type().const_int(0, false));
6387                }
6388                "now" => {
6389                    // Call sigil_now runtime function
6390                    let now_fn = self
6391                        .module
6392                        .get_function("sigil_now")
6393                        .ok_or("sigil_now not declared")?;
6394                    let call = self
6395                        .builder
6396                        .build_call(now_fn, &[], "now")
6397                        .map_err(|e| e.to_string())?;
6398                    return Ok(call
6399                        .try_as_basic_value()
6400                        .left()
6401                        .map(|v| v.into_int_value())
6402                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6403                }
6404                // Unary math functions
6405                "sqrt" | "sin" | "cos" | "tan" | "exp" | "ln" | "floor" | "ceil" | "abs" => {
6406                    if args.is_empty() {
6407                        return Err(format!("{} requires 1 argument", fn_name));
6408                    }
6409                    let arg = self.compile_expr(fn_value, scope, &args[0])?;
6410                    let rt_name = format!("sigil_{}", fn_name);
6411                    let rt_fn = self
6412                        .module
6413                        .get_function(&rt_name)
6414                        .ok_or(format!("{} not declared", rt_name))?;
6415                    let call = self
6416                        .builder
6417                        .build_call(rt_fn, &[arg.into()], fn_name)
6418                        .map_err(|e| e.to_string())?;
6419                    return Ok(call
6420                        .try_as_basic_value()
6421                        .left()
6422                        .map(|v| v.into_int_value())
6423                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6424                }
6425                // Binary math functions
6426                "pow" | "min" | "max" => {
6427                    if args.len() < 2 {
6428                        return Err(format!("{} requires 2 arguments", fn_name));
6429                    }
6430                    let arg1 = self.compile_expr(fn_value, scope, &args[0])?;
6431                    let arg2 = self.compile_expr(fn_value, scope, &args[1])?;
6432                    let rt_name = format!("sigil_{}", fn_name);
6433                    let rt_fn = self
6434                        .module
6435                        .get_function(&rt_name)
6436                        .ok_or(format!("{} not declared", rt_name))?;
6437                    let call = self
6438                        .builder
6439                        .build_call(rt_fn, &[arg1.into(), arg2.into()], fn_name)
6440                        .map_err(|e| e.to_string())?;
6441                    return Ok(call
6442                        .try_as_basic_value()
6443                        .left()
6444                        .map(|v| v.into_int_value())
6445                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6446                }
6447                // Vec built-in functions
6448                "vec_new" => {
6449                    if args.is_empty() {
6450                        return Err("vec_new requires capacity argument".to_string());
6451                    }
6452                    let capacity = self.compile_expr(fn_value, scope, &args[0])?;
6453                    let vec_new_fn = self
6454                        .module
6455                        .get_function("sigil_vec_new")
6456                        .ok_or("sigil_vec_new not declared")?;
6457                    let call = self
6458                        .builder
6459                        .build_call(vec_new_fn, &[capacity.into()], "vec_new")
6460                        .map_err(|e| e.to_string())?;
6461                    return Ok(call
6462                        .try_as_basic_value()
6463                        .left()
6464                        .map(|v| v.into_int_value())
6465                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6466                }
6467                "vec_push" => {
6468                    if args.len() < 2 {
6469                        return Err("vec_push requires vec and value arguments".to_string());
6470                    }
6471                    let vec_ptr = self.compile_expr(fn_value, scope, &args[0])?;
6472                    let value = self.compile_expr(fn_value, scope, &args[1])?;
6473                    let vec_push_fn = self
6474                        .module
6475                        .get_function("sigil_vec_push")
6476                        .ok_or("sigil_vec_push not declared")?;
6477                    self.builder
6478                        .build_call(vec_push_fn, &[vec_ptr.into(), value.into()], "")
6479                        .map_err(|e| e.to_string())?;
6480                    return Ok(self.context.i64_type().const_int(0, false));
6481                }
6482                "vec_get" => {
6483                    if args.len() < 2 {
6484                        return Err("vec_get requires vec and index arguments".to_string());
6485                    }
6486                    let vec_ptr = self.compile_expr(fn_value, scope, &args[0])?;
6487                    let index = self.compile_expr(fn_value, scope, &args[1])?;
6488                    let vec_get_fn = self
6489                        .module
6490                        .get_function("sigil_vec_get")
6491                        .ok_or("sigil_vec_get not declared")?;
6492                    let call = self
6493                        .builder
6494                        .build_call(vec_get_fn, &[vec_ptr.into(), index.into()], "vec_get")
6495                        .map_err(|e| e.to_string())?;
6496                    return Ok(call
6497                        .try_as_basic_value()
6498                        .left()
6499                        .map(|v| v.into_int_value())
6500                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6501                }
6502                "vec_len" => {
6503                    if args.is_empty() {
6504                        return Err("vec_len requires vec argument".to_string());
6505                    }
6506                    let vec_ptr = self.compile_expr(fn_value, scope, &args[0])?;
6507                    let vec_len_fn = self
6508                        .module
6509                        .get_function("sigil_vec_len")
6510                        .ok_or("sigil_vec_len not declared")?;
6511                    let call = self
6512                        .builder
6513                        .build_call(vec_len_fn, &[vec_ptr.into()], "vec_len")
6514                        .map_err(|e| e.to_string())?;
6515                    return Ok(call
6516                        .try_as_basic_value()
6517                        .left()
6518                        .map(|v| v.into_int_value())
6519                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6520                }
6521                // String built-in functions
6522                "String_from" => {
6523                    if args.is_empty() {
6524                        return Err("String_from requires string literal argument".to_string());
6525                    }
6526                    // Get the string literal - it should be a string expression
6527                    let str_ptr = self.compile_expr(fn_value, scope, &args[0])?;
6528                    let string_from_fn = self
6529                        .module
6530                        .get_function("sigil_string_from")
6531                        .ok_or("sigil_string_from not declared")?;
6532                    let call = self
6533                        .builder
6534                        .build_call(string_from_fn, &[str_ptr.into()], "string_from")
6535                        .map_err(|e| e.to_string())?;
6536                    return Ok(call
6537                        .try_as_basic_value()
6538                        .left()
6539                        .map(|v| v.into_int_value())
6540                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6541                }
6542                "string_len" => {
6543                    if args.is_empty() {
6544                        return Err("string_len requires string argument".to_string());
6545                    }
6546                    let str_ptr = self.compile_expr(fn_value, scope, &args[0])?;
6547                    let string_len_fn = self
6548                        .module
6549                        .get_function("sigil_string_len")
6550                        .ok_or("sigil_string_len not declared")?;
6551                    let call = self
6552                        .builder
6553                        .build_call(string_len_fn, &[str_ptr.into()], "string_len")
6554                        .map_err(|e| e.to_string())?;
6555                    return Ok(call
6556                        .try_as_basic_value()
6557                        .left()
6558                        .map(|v| v.into_int_value())
6559                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6560                }
6561                "string_print" => {
6562                    if args.is_empty() {
6563                        return Err("string_print requires string argument".to_string());
6564                    }
6565                    let str_ptr = self.compile_expr(fn_value, scope, &args[0])?;
6566                    let string_print_fn = self
6567                        .module
6568                        .get_function("sigil_string_print")
6569                        .ok_or("sigil_string_print not declared")?;
6570                    self.builder
6571                        .build_call(string_print_fn, &[str_ptr.into()], "")
6572                        .map_err(|e| e.to_string())?;
6573                    return Ok(self.context.i64_type().const_int(0, false));
6574                }
6575                "string_concat" => {
6576                    if args.len() < 2 {
6577                        return Err("string_concat requires two string arguments".to_string());
6578                    }
6579                    let str1 = self.compile_expr(fn_value, scope, &args[0])?;
6580                    let str2 = self.compile_expr(fn_value, scope, &args[1])?;
6581                    let string_concat_fn = self
6582                        .module
6583                        .get_function("sigil_string_concat")
6584                        .ok_or("sigil_string_concat not declared")?;
6585                    let call = self
6586                        .builder
6587                        .build_call(
6588                            string_concat_fn,
6589                            &[str1.into(), str2.into()],
6590                            "string_concat",
6591                        )
6592                        .map_err(|e| e.to_string())?;
6593                    return Ok(call
6594                        .try_as_basic_value()
6595                        .left()
6596                        .map(|v| v.into_int_value())
6597                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6598                }
6599                // Option built-in functions
6600                "Some" => {
6601                    if args.is_empty() {
6602                        return Err("Some requires a value argument".to_string());
6603                    }
6604                    let value = self.compile_expr(fn_value, scope, &args[0])?;
6605                    let option_some_fn = self
6606                        .module
6607                        .get_function("sigil_option_some")
6608                        .ok_or("sigil_option_some not declared")?;
6609                    let call = self
6610                        .builder
6611                        .build_call(option_some_fn, &[value.into()], "some")
6612                        .map_err(|e| e.to_string())?;
6613                    return Ok(call
6614                        .try_as_basic_value()
6615                        .left()
6616                        .map(|v| v.into_int_value())
6617                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6618                }
6619                "None" => {
6620                    let option_none_fn = self
6621                        .module
6622                        .get_function("sigil_option_none")
6623                        .ok_or("sigil_option_none not declared")?;
6624                    let call = self
6625                        .builder
6626                        .build_call(option_none_fn, &[], "none")
6627                        .map_err(|e| e.to_string())?;
6628                    return Ok(call
6629                        .try_as_basic_value()
6630                        .left()
6631                        .map(|v| v.into_int_value())
6632                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6633                }
6634                "is_some" => {
6635                    if args.is_empty() {
6636                        return Err("is_some requires an option argument".to_string());
6637                    }
6638                    let opt = self.compile_expr(fn_value, scope, &args[0])?;
6639                    let is_some_fn = self
6640                        .module
6641                        .get_function("sigil_option_is_some")
6642                        .ok_or("sigil_option_is_some not declared")?;
6643                    let call = self
6644                        .builder
6645                        .build_call(is_some_fn, &[opt.into()], "is_some")
6646                        .map_err(|e| e.to_string())?;
6647                    return Ok(call
6648                        .try_as_basic_value()
6649                        .left()
6650                        .map(|v| v.into_int_value())
6651                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6652                }
6653                "is_none" => {
6654                    if args.is_empty() {
6655                        return Err("is_none requires an option argument".to_string());
6656                    }
6657                    let opt = self.compile_expr(fn_value, scope, &args[0])?;
6658                    let is_none_fn = self
6659                        .module
6660                        .get_function("sigil_option_is_none")
6661                        .ok_or("sigil_option_is_none not declared")?;
6662                    let call = self
6663                        .builder
6664                        .build_call(is_none_fn, &[opt.into()], "is_none")
6665                        .map_err(|e| e.to_string())?;
6666                    return Ok(call
6667                        .try_as_basic_value()
6668                        .left()
6669                        .map(|v| v.into_int_value())
6670                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6671                }
6672                "unwrap" => {
6673                    if args.is_empty() {
6674                        return Err("unwrap requires an option argument".to_string());
6675                    }
6676                    let opt = self.compile_expr(fn_value, scope, &args[0])?;
6677                    let unwrap_fn = self
6678                        .module
6679                        .get_function("sigil_option_unwrap")
6680                        .ok_or("sigil_option_unwrap not declared")?;
6681                    let call = self
6682                        .builder
6683                        .build_call(unwrap_fn, &[opt.into()], "unwrap")
6684                        .map_err(|e| e.to_string())?;
6685                    return Ok(call
6686                        .try_as_basic_value()
6687                        .left()
6688                        .map(|v| v.into_int_value())
6689                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6690                }
6691                "unwrap_or" => {
6692                    if args.len() < 2 {
6693                        return Err("unwrap_or requires option and default arguments".to_string());
6694                    }
6695                    let opt = self.compile_expr(fn_value, scope, &args[0])?;
6696                    let default_val = self.compile_expr(fn_value, scope, &args[1])?;
6697                    let unwrap_or_fn = self
6698                        .module
6699                        .get_function("sigil_option_unwrap_or")
6700                        .ok_or("sigil_option_unwrap_or not declared")?;
6701                    let call = self
6702                        .builder
6703                        .build_call(unwrap_or_fn, &[opt.into(), default_val.into()], "unwrap_or")
6704                        .map_err(|e| e.to_string())?;
6705                    return Ok(call
6706                        .try_as_basic_value()
6707                        .left()
6708                        .map(|v| v.into_int_value())
6709                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6710                }
6711                // File I/O built-in functions
6712                "file_exists" => {
6713                    if args.is_empty() {
6714                        return Err("file_exists requires a path argument".to_string());
6715                    }
6716                    let path = self.compile_expr(fn_value, scope, &args[0])?;
6717                    let file_exists_fn = self
6718                        .module
6719                        .get_function("sigil_file_exists")
6720                        .ok_or("sigil_file_exists not declared")?;
6721                    let call = self
6722                        .builder
6723                        .build_call(file_exists_fn, &[path.into()], "file_exists")
6724                        .map_err(|e| e.to_string())?;
6725                    return Ok(call
6726                        .try_as_basic_value()
6727                        .left()
6728                        .map(|v| v.into_int_value())
6729                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6730                }
6731                "file_read_all" => {
6732                    if args.is_empty() {
6733                        return Err("file_read_all requires a path argument".to_string());
6734                    }
6735                    let path = self.compile_expr(fn_value, scope, &args[0])?;
6736                    let file_read_fn = self
6737                        .module
6738                        .get_function("sigil_file_read_all")
6739                        .ok_or("sigil_file_read_all not declared")?;
6740                    let call = self
6741                        .builder
6742                        .build_call(file_read_fn, &[path.into()], "file_read")
6743                        .map_err(|e| e.to_string())?;
6744                    return Ok(call
6745                        .try_as_basic_value()
6746                        .left()
6747                        .map(|v| v.into_int_value())
6748                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6749                }
6750                "file_write_all" => {
6751                    if args.len() < 2 {
6752                        return Err(
6753                            "file_write_all requires path and content arguments".to_string()
6754                        );
6755                    }
6756                    let path = self.compile_expr(fn_value, scope, &args[0])?;
6757                    let content = self.compile_expr(fn_value, scope, &args[1])?;
6758                    let file_write_fn = self
6759                        .module
6760                        .get_function("sigil_file_write_all")
6761                        .ok_or("sigil_file_write_all not declared")?;
6762                    let call = self
6763                        .builder
6764                        .build_call(file_write_fn, &[path.into(), content.into()], "file_write")
6765                        .map_err(|e| e.to_string())?;
6766                    return Ok(call
6767                        .try_as_basic_value()
6768                        .left()
6769                        .map(|v| v.into_int_value())
6770                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6771                }
6772                // Result enum constructors
6773                "Result::Ok" | "Result·Ok" => {
6774                    // Result::Ok(value) - for now, just return the value
6775                    // In a full implementation, we'd tag it as Ok variant
6776                    if args.is_empty() {
6777                        return Ok(self.context.i64_type().const_int(0, false));
6778                    }
6779                    return self.compile_expr(fn_value, scope, &args[0]);
6780                }
6781                "Result::Err" | "Result·Err" => {
6782                    // Result::Err(error) - for now, return the error value
6783                    // In a full implementation, we'd tag it as Err variant
6784                    // eprintln!("DEBUG: Handling Result::Err with {} args", args.len());
6785                    if args.is_empty() {
6786                        return Ok(self.context.i64_type().const_int(0, false));
6787                    }
6788                    // eprintln!("DEBUG: Compiling Result::Err arg");
6789                    let result = self.compile_expr(fn_value, scope, &args[0]);
6790                    // eprintln!("DEBUG: Result::Err arg compiled: {:?}", result.is_ok());
6791                    return result;
6792                }
6793                // Option enum constructors
6794                "Option::Some" | "Option·Some" => {
6795                    if args.is_empty() {
6796                        return Ok(self.context.i64_type().const_int(0, false));
6797                    }
6798                    return self.compile_expr(fn_value, scope, &args[0]);
6799                }
6800                "Option::None" | "Option·None" => {
6801                    // None is represented as null/0
6802                    return Ok(self.context.i64_type().const_int(0, false));
6803                }
6804                // String constructors
6805                "String::new" | "String·new" => {
6806                    let str_new_fn = self
6807                        .module
6808                        .get_function("sigil_string_new")
6809                        .ok_or("sigil_string_new not declared")?;
6810                    let call = self
6811                        .builder
6812                        .build_call(str_new_fn, &[], "string_new")
6813                        .map_err(|e| e.to_string())?;
6814                    return Ok(call
6815                        .try_as_basic_value()
6816                        .left()
6817                        .map(|v| v.into_int_value())
6818                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6819                }
6820                "String::from" | "String·from" => {
6821                    if args.is_empty() {
6822                        return Ok(self.context.i64_type().const_int(0, false));
6823                    }
6824                    // String::from(s) just returns the string
6825                    return self.compile_expr(fn_value, scope, &args[0]);
6826                }
6827                // Map constructors
6828                "Map::new" | "Map·new" | "HashMap::new" => {
6829                    let map_new_fn = self
6830                        .module
6831                        .get_function("sigil_map_new")
6832                        .ok_or("sigil_map_new not declared")?;
6833                    let call = self
6834                        .builder
6835                        .build_call(map_new_fn, &[], "map_new")
6836                        .map_err(|e| e.to_string())?;
6837                    return Ok(call
6838                        .try_as_basic_value()
6839                        .left()
6840                        .map(|v| v.into_int_value())
6841                        .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6842                }
6843                _ => {
6844                    // eprintln!("DEBUG: Match fallthrough for full_path = {:?}", full_path);
6845                }
6846            }
6847
6848            // Resolve any use aliases first
6849            let resolved_path = if let Some(aliased) = self.use_aliases.get(fn_name) {
6850                aliased.clone()
6851            } else {
6852                full_path.clone()
6853            };
6854
6855            // Handle generic struct constructors (TypeName::new, TypeName::default, etc.)
6856            // These allocate a struct and return a pointer/value
6857            if full_path.ends_with("::new")
6858                || full_path.ends_with("·new")
6859                || full_path.ends_with("::default")
6860                || full_path.ends_with("·default")
6861                || full_path.ends_with("::create")
6862                || full_path.ends_with("·create")
6863                || full_path.ends_with("::init")
6864                || full_path.ends_with("·init")
6865            {
6866                // For struct constructors, we need to allocate and initialize
6867                // For now, return a placeholder value (0 = null pointer)
6868                // TODO: Implement proper struct allocation
6869                return Ok(self.context.i64_type().const_int(0, false));
6870            }
6871
6872            // Handle functions that return new data structures
6873            if full_path.ends_with("::with_capacity")
6874                || full_path.ends_with("·with_capacity")
6875                || full_path.ends_with("::from_iter")
6876                || full_path.ends_with("·from_iter")
6877            {
6878                return Ok(self.context.i64_type().const_int(0, false));
6879            }
6880
6881            // Get the function - try resolved path first, then various lookups
6882            let callee = if let Some(f) = self.functions.get(&resolved_path) {
6883                *f
6884            } else if let Some(f) = self.functions.get(&full_path) {
6885                *f
6886            } else if let Some(f) = self.functions.get(fn_name) {
6887                *f
6888            } else if let Some(f) = self.module.get_function(&resolved_path.replace("::", "_")) {
6889                f
6890            } else if let Some(f) = self.module.get_function(&full_path.replace("::", "_")) {
6891                f
6892            } else if let Some(f) = self.module.get_function(fn_name) {
6893                f
6894            } else {
6895                // Fallback: Try heuristics based on function name pattern
6896                let fn_lower = fn_name.to_lowercase();
6897
6898                // Functions that likely transform/process data and return a result
6899                if fn_lower.starts_with("lower")
6900                    || fn_lower.starts_with("parse")
6901                    || fn_lower.starts_with("compile")
6902                    || fn_lower.starts_with("transform")
6903                    || fn_lower.starts_with("convert")
6904                    || fn_lower.starts_with("generate")
6905                    || fn_lower.starts_with("create")
6906                    || fn_lower.starts_with("build")
6907                    || fn_lower.starts_with("make")
6908                    || fn_lower.starts_with("read")
6909                    || fn_lower.starts_with("load")
6910                    || fn_lower.starts_with("fetch")
6911                    || fn_lower.starts_with("get")
6912                    || fn_lower.starts_with("find")
6913                    || fn_lower.starts_with("lookup")
6914                    || fn_lower.starts_with("resolve")
6915                    || fn_lower.starts_with("extract")
6916                    || fn_lower.starts_with("infer")
6917                    || fn_lower.starts_with("derive")
6918                    || fn_lower.starts_with("compute")
6919                    || fn_lower.starts_with("calculate")
6920                {
6921                    // These typically return a result/value - stub with 0
6922                    // eprintln!("DEBUG: Unknown function '{}' - stubbing as data transform", full_path);
6923                    return Ok(self.context.i64_type().const_int(0, false));
6924                }
6925
6926                // Functions that are side-effecting (write, emit, etc.)
6927                if fn_lower.starts_with("write")
6928                    || fn_lower.starts_with("emit")
6929                    || fn_lower.starts_with("output")
6930                    || fn_lower.starts_with("print")
6931                    || fn_lower.starts_with("log")
6932                    || fn_lower.starts_with("debug")
6933                    || fn_lower.starts_with("warn")
6934                    || fn_lower.starts_with("error")
6935                    || fn_lower.starts_with("report")
6936                    || fn_lower.starts_with("notify")
6937                {
6938                    // eprintln!("DEBUG: Unknown function '{}' - stubbing as side-effect", full_path);
6939                    return Ok(self.context.i64_type().const_int(0, false));
6940                }
6941
6942                // Checker/validator functions return bool
6943                if fn_lower.starts_with("check")
6944                    || fn_lower.starts_with("validate")
6945                    || fn_lower.starts_with("verify")
6946                    || fn_lower.starts_with("test")
6947                    || fn_lower.starts_with("is_")
6948                    || fn_lower.starts_with("has_")
6949                    || fn_lower.starts_with("can_")
6950                {
6951                    // eprintln!("DEBUG: Unknown function '{}' - stubbing as bool check", full_path);
6952                    return Ok(self.context.i64_type().const_int(0, false));
6953                }
6954
6955                // Default fallback - assume returns something, use 0 as placeholder
6956                // eprintln!("DEBUG: Unknown function '{}' - using default stub", full_path);
6957                return Ok(self.context.i64_type().const_int(0, false));
6958            };
6959
6960            // Compile arguments
6961            let compiled_args: Result<Vec<_>, _> = args
6962                .iter()
6963                .map(|arg| self.compile_expr(fn_value, scope, arg).map(|v| v.into()))
6964                .collect();
6965            let compiled_args = compiled_args?;
6966
6967            // Build call with tail call hint for potential optimization
6968            let call = self
6969                .builder
6970                .build_call(callee, &compiled_args, "call")
6971                .map_err(|e| e.to_string())?;
6972
6973            // Hint to LLVM that this could be a tail call
6974            // The optimizer will determine if it's actually in tail position
6975            call.set_tail_call(true);
6976
6977            // Get return value
6978            Ok(call
6979                .try_as_basic_value()
6980                .left()
6981                .map(|v| v.into_int_value())
6982                .unwrap_or_else(|| self.context.i64_type().const_int(0, false)))
6983        }
6984
6985        /// Compile println! and print! macros
6986        fn compile_print_macro(
6987            &mut self,
6988            fn_value: FunctionValue<'ctx>,
6989            scope: &mut CompileScope<'ctx>,
6990            tokens: &str,
6991            newline: bool,
6992        ) -> Result<(), String> {
6993            // Parse the macro tokens to extract format string and arguments
6994            // Format: "format string", arg1, arg2, ...
6995            let tokens = tokens.trim();
6996
6997            if tokens.is_empty() {
6998                // println!() with no args - just print newline
6999                if newline {
7000                    let empty_str = self.create_global_string("\n", "empty_nl");
7001                    let print_fn = self
7002                        .module
7003                        .get_function("sigil_print_str")
7004                        .ok_or("sigil_print_str not declared")?;
7005                    self.builder
7006                        .build_call(print_fn, &[empty_str.into()], "")
7007                        .map_err(|e| e.to_string())?;
7008                }
7009                return Ok(());
7010            }
7011
7012            // Find the format string (first quoted string)
7013            let (format_str, args_str) = if tokens.starts_with('"') {
7014                // Find the closing quote (handling escaped quotes)
7015                let mut chars = tokens[1..].chars().peekable();
7016                let mut format_content = String::new();
7017                let mut escaped = false;
7018
7019                while let Some(c) = chars.next() {
7020                    if escaped {
7021                        format_content.push(c);
7022                        escaped = false;
7023                    } else if c == '\\' {
7024                        format_content.push(c);
7025                        escaped = true;
7026                    } else if c == '"' {
7027                        break;
7028                    } else {
7029                        format_content.push(c);
7030                    }
7031                }
7032
7033                // Remaining args after the format string
7034                let remaining: String = chars.collect();
7035                let args_owned = remaining.trim_start_matches(',').trim().to_string();
7036                (format_content, args_owned)
7037            } else {
7038                // No format string, treat as expression to print
7039                (String::new(), tokens.to_string())
7040            };
7041
7042            // Check if format string has placeholders
7043            let has_placeholders = format_str.contains("{}");
7044
7045            if !has_placeholders && args_str.is_empty() {
7046                // Simple string literal - use write_str (no newline) then add newline if needed
7047                let output = format_str.replace("\\n", "\n").replace("\\t", "\t");
7048
7049                let write_str_fn = self
7050                    .module
7051                    .get_function("sigil_write_str")
7052                    .ok_or("sigil_write_str not declared")?;
7053
7054                let str_ptr = self.create_global_string(&output, "print_str");
7055                self.builder
7056                    .build_call(write_str_fn, &[str_ptr.into()], "")
7057                    .map_err(|e| e.to_string())?;
7058
7059                // Add newline if println!
7060                if newline {
7061                    let nl_str = self.create_global_string("\n", "newline");
7062                    self.builder
7063                        .build_call(write_str_fn, &[nl_str.into()], "")
7064                        .map_err(|e| e.to_string())?;
7065                }
7066            } else if has_placeholders {
7067                // Format string with placeholders - parse and substitute
7068                // Split format string by {} and interleave with arguments
7069                let parts: Vec<&str> = format_str.split("{}").collect();
7070                let args: Vec<&str> = args_str
7071                    .split(',')
7072                    .map(|s| s.trim())
7073                    .filter(|s| !s.is_empty())
7074                    .collect();
7075
7076                // Get write functions (no newline versions for inline output)
7077                let write_str_fn = self
7078                    .module
7079                    .get_function("sigil_write_str")
7080                    .ok_or("sigil_write_str not declared")?;
7081                let write_int_fn = self
7082                    .module
7083                    .get_function("sigil_write_int")
7084                    .ok_or("sigil_write_int not declared")?;
7085
7086                for (i, part) in parts.iter().enumerate() {
7087                    // Print the static part (no newline)
7088                    if !part.is_empty() {
7089                        let part_str = part.replace("\\n", "\n").replace("\\t", "\t");
7090                        let str_ptr = self.create_global_string(&part_str, "fmt_part");
7091                        self.builder
7092                            .build_call(write_str_fn, &[str_ptr.into()], "")
7093                            .map_err(|e| e.to_string())?;
7094                    }
7095
7096                    // Print the argument (if there's one for this placeholder)
7097                    if i < args.len() {
7098                        let arg_str = args[i];
7099                        // Parse and compile the argument expression
7100                        let arg_value = self.compile_format_arg(fn_value, scope, arg_str)?;
7101                        self.builder
7102                            .build_call(write_int_fn, &[arg_value.into()], "")
7103                            .map_err(|e| e.to_string())?;
7104                    }
7105                }
7106
7107                // Add newline if println!
7108                if newline {
7109                    let nl_str = self.create_global_string("\n", "newline");
7110                    self.builder
7111                        .build_call(write_str_fn, &[nl_str.into()], "")
7112                        .map_err(|e| e.to_string())?;
7113                }
7114            } else if !args_str.is_empty() {
7115                // No format string, just print the expression value
7116                let arg_value = self.compile_format_arg(fn_value, scope, &args_str)?;
7117                let print_int_fn = self
7118                    .module
7119                    .get_function("sigil_print_int")
7120                    .ok_or("sigil_print_int not declared")?;
7121                self.builder
7122                    .build_call(print_int_fn, &[arg_value.into()], "")
7123                    .map_err(|e| e.to_string())?;
7124            }
7125
7126            Ok(())
7127        }
7128
7129        /// Compile a format argument expression (simple variable lookup or literal)
7130        fn compile_format_arg(
7131            &mut self,
7132            fn_value: FunctionValue<'ctx>,
7133            scope: &mut CompileScope<'ctx>,
7134            arg_str: &str,
7135        ) -> Result<IntValue<'ctx>, String> {
7136            let arg_str = arg_str.trim();
7137
7138            // Try to parse as integer literal
7139            if let Ok(n) = arg_str.parse::<i64>() {
7140                return Ok(self.context.i64_type().const_int(n as u64, n < 0));
7141            }
7142
7143            // Try to look up as variable
7144            if let Some(var) = scope.vars.get(arg_str) {
7145                let loaded = self
7146                    .builder
7147                    .build_load(self.context.i64_type(), *var, arg_str)
7148                    .map_err(|e| e.to_string())?;
7149                return Ok(loaded.into_int_value());
7150            }
7151
7152            // Try to parse as more complex expression
7153            let mut parser = Parser::new(arg_str);
7154            if let Ok(expr) = parser.parse_expr() {
7155                return self.compile_expr(fn_value, scope, &expr);
7156            }
7157
7158            // Fallback: return 0
7159            Ok(self.context.i64_type().const_int(0, false))
7160        }
7161
7162        /// Create a global string constant and return pointer to it
7163        fn create_global_string(&self, s: &str, name: &str) -> PointerValue<'ctx> {
7164            let counter = self.string_counter.get();
7165            self.string_counter.set(counter + 1);
7166            let unique_name = format!("{}_{}", name, counter);
7167
7168            // Create a null-terminated string constant
7169            let string_val = self.context.const_string(s.as_bytes(), true);
7170            let global = self
7171                .module
7172                .add_global(string_val.get_type(), None, &unique_name);
7173            global.set_initializer(&string_val);
7174            global.set_constant(true);
7175            global.set_linkage(inkwell::module::Linkage::Private);
7176
7177            // Get pointer to the first element
7178            global.as_pointer_value()
7179        }
7180
7181        /// Process a use declaration to register imports
7182        fn process_use(&mut self, use_decl: &ast::UseDecl) -> Result<(), String> {
7183            self.process_use_tree(&use_decl.tree, &[])
7184        }
7185
7186        /// Recursively process use tree to build import paths
7187        fn process_use_tree(
7188            &mut self,
7189            tree: &ast::UseTree,
7190            prefix: &[String],
7191        ) -> Result<(), String> {
7192            match tree {
7193                ast::UseTree::Path {
7194                    prefix: ident,
7195                    suffix,
7196                } => {
7197                    let mut new_prefix = prefix.to_vec();
7198                    new_prefix.push(ident.name.clone());
7199                    self.process_use_tree(suffix, &new_prefix)
7200                }
7201                ast::UseTree::Name(ident) => {
7202                    let mut full_path = prefix.to_vec();
7203                    full_path.push(ident.name.clone());
7204                    let full_name = full_path.join("::");
7205                    self.use_aliases.insert(ident.name.clone(), full_name);
7206                    Ok(())
7207                }
7208                ast::UseTree::Rename { name, alias } => {
7209                    let mut full_path = prefix.to_vec();
7210                    full_path.push(name.name.clone());
7211                    let full_name = full_path.join("::");
7212                    self.use_aliases.insert(alias.name.clone(), full_name);
7213                    Ok(())
7214                }
7215                ast::UseTree::Glob => Ok(()),
7216                ast::UseTree::Group(trees) => {
7217                    for sub_tree in trees {
7218                        self.process_use_tree(sub_tree, prefix)?;
7219                    }
7220                    Ok(())
7221                }
7222            }
7223        }
7224
7225        /// Process a module declaration (first pass - declare functions)
7226        fn process_module(&mut self, module: &ast::Module) -> Result<(), String> {
7227            let saved_module = self.current_module.clone();
7228            self.current_module.push(module.name.name.clone());
7229
7230            if let Some(ref items) = module.items {
7231                for spanned_item in items {
7232                    match &spanned_item.node {
7233                        Item::Function(func) => {
7234                            self.declare_function(func)?;
7235                        }
7236                        Item::Module(m) => {
7237                            self.process_module(m)?;
7238                        }
7239                        Item::Use(u) => {
7240                            self.process_use(u)?;
7241                        }
7242                        _ => {}
7243                    }
7244                }
7245            }
7246
7247            self.current_module = saved_module;
7248            Ok(())
7249        }
7250
7251        /// Compile functions in a module (second pass)
7252        fn compile_module_functions(&mut self, module: &ast::Module) -> Result<(), String> {
7253            let saved_module = self.current_module.clone();
7254            self.current_module.push(module.name.name.clone());
7255
7256            if let Some(ref items) = module.items {
7257                for spanned_item in items {
7258                    match &spanned_item.node {
7259                        Item::Function(func) => {
7260                            self.compile_function(func)?;
7261                        }
7262                        Item::Module(m) => {
7263                            self.compile_module_functions(m)?;
7264                        }
7265                        _ => {}
7266                    }
7267                }
7268            }
7269
7270            self.current_module = saved_module;
7271            Ok(())
7272        }
7273
7274        /// Run LLVM optimization passes
7275        fn run_llvm_optimizations(&self) -> Result<(), String> {
7276            Target::initialize_all(&InitializationConfig::default());
7277
7278            let triple = TargetMachine::get_default_triple();
7279            let target = Target::from_triple(&triple).map_err(|e| e.to_string())?;
7280
7281            // Use native CPU and features for maximum performance
7282            let cpu = TargetMachine::get_host_cpu_name();
7283            let features = TargetMachine::get_host_cpu_features();
7284
7285            let target_machine = target
7286                .create_target_machine(
7287                    &triple,
7288                    cpu.to_str().unwrap_or("native"),
7289                    features.to_str().unwrap_or(""),
7290                    OptimizationLevel::Aggressive,
7291                    RelocMode::Default,
7292                    CodeModel::Default,
7293                )
7294                .ok_or("Failed to create target machine")?;
7295
7296            // Run aggressive optimization passes
7297            // The key is running tailcallelim early and then letting later passes optimize
7298            let passes = match self.opt_level {
7299                OptLevel::None => "default<O0>",
7300                OptLevel::Basic => "default<O1>",
7301                OptLevel::Standard | OptLevel::Size => "default<O2>",
7302                // Run full O3 pipeline which includes tail call elimination
7303                OptLevel::Aggressive => "default<O3>",
7304            };
7305
7306            self.module
7307                .run_passes(passes, &target_machine, PassBuilderOptions::create())
7308                .map_err(|e| e.to_string())?;
7309
7310            Ok(())
7311        }
7312
7313        /// Create JIT execution engine and run
7314        pub fn run(&mut self) -> Result<i64, String> {
7315            // Initialize targets for JIT execution
7316            Target::initialize_x86(&InitializationConfig::default());
7317
7318            // Verify module before execution
7319            if let Err(msg) = self.module.verify() {
7320                return Err(format!("Module verification failed: {}", msg.to_string()));
7321            }
7322
7323            // Create execution engine
7324            let ee = self
7325                .module
7326                .create_jit_execution_engine(OptimizationLevel::Aggressive)
7327                .map_err(|e| e.to_string())?;
7328
7329            // Register runtime functions (only if declared/used in the program)
7330            if let Some(f) = self.module.get_function("sigil_now") {
7331                ee.add_global_mapping(&f, sigil_now as usize);
7332            }
7333            if let Some(f) = self.module.get_function("sigil_print_int") {
7334                ee.add_global_mapping(&f, sigil_print_int as usize);
7335            }
7336
7337            // Register math functions (only if declared/used in the program)
7338            if let Some(f) = self.module.get_function("sigil_sqrt") {
7339                ee.add_global_mapping(&f, sigil_sqrt as usize);
7340            }
7341            if let Some(f) = self.module.get_function("sigil_sin") {
7342                ee.add_global_mapping(&f, sigil_sin as usize);
7343            }
7344            if let Some(f) = self.module.get_function("sigil_cos") {
7345                ee.add_global_mapping(&f, sigil_cos as usize);
7346            }
7347            if let Some(f) = self.module.get_function("sigil_tan") {
7348                ee.add_global_mapping(&f, sigil_tan as usize);
7349            }
7350            if let Some(f) = self.module.get_function("sigil_exp") {
7351                ee.add_global_mapping(&f, sigil_exp as usize);
7352            }
7353            if let Some(f) = self.module.get_function("sigil_ln") {
7354                ee.add_global_mapping(&f, sigil_ln as usize);
7355            }
7356            if let Some(f) = self.module.get_function("sigil_pow") {
7357                ee.add_global_mapping(&f, sigil_pow as usize);
7358            }
7359            if let Some(f) = self.module.get_function("sigil_floor") {
7360                ee.add_global_mapping(&f, sigil_floor as usize);
7361            }
7362            if let Some(f) = self.module.get_function("sigil_ceil") {
7363                ee.add_global_mapping(&f, sigil_ceil as usize);
7364            }
7365            if let Some(f) = self.module.get_function("sigil_abs") {
7366                ee.add_global_mapping(&f, sigil_abs as usize);
7367            }
7368            if let Some(f) = self.module.get_function("sigil_min") {
7369                ee.add_global_mapping(&f, sigil_min as usize);
7370            }
7371            if let Some(f) = self.module.get_function("sigil_max") {
7372                ee.add_global_mapping(&f, sigil_max as usize);
7373            }
7374
7375            // Vec runtime mappings
7376            if let Some(f) = self.module.get_function("sigil_vec_new") {
7377                ee.add_global_mapping(&f, sigil_vec_new as usize);
7378            }
7379            if let Some(f) = self.module.get_function("sigil_vec_push") {
7380                ee.add_global_mapping(&f, sigil_vec_push as usize);
7381            }
7382            if let Some(f) = self.module.get_function("sigil_vec_get") {
7383                ee.add_global_mapping(&f, sigil_vec_get as usize);
7384            }
7385            if let Some(f) = self.module.get_function("sigil_vec_len") {
7386                ee.add_global_mapping(&f, sigil_vec_len as usize);
7387            }
7388
7389            // String runtime mappings
7390            if let Some(f) = self.module.get_function("sigil_string_new") {
7391                ee.add_global_mapping(&f, sigil_string_new as usize);
7392            }
7393            if let Some(f) = self.module.get_function("sigil_string_from") {
7394                ee.add_global_mapping(&f, sigil_string_from as usize);
7395            }
7396            if let Some(f) = self.module.get_function("sigil_string_len") {
7397                ee.add_global_mapping(&f, sigil_string_len as usize);
7398            }
7399            if let Some(f) = self.module.get_function("sigil_string_print") {
7400                ee.add_global_mapping(&f, sigil_string_print as usize);
7401            }
7402            if let Some(f) = self.module.get_function("sigil_string_concat") {
7403                ee.add_global_mapping(&f, sigil_string_concat as usize);
7404            }
7405
7406            // Option runtime mappings
7407            if let Some(f) = self.module.get_function("sigil_option_some") {
7408                ee.add_global_mapping(&f, sigil_option_some as usize);
7409            }
7410            if let Some(f) = self.module.get_function("sigil_option_none") {
7411                ee.add_global_mapping(&f, sigil_option_none as usize);
7412            }
7413            if let Some(f) = self.module.get_function("sigil_option_is_some") {
7414                ee.add_global_mapping(&f, sigil_option_is_some as usize);
7415            }
7416            if let Some(f) = self.module.get_function("sigil_option_is_none") {
7417                ee.add_global_mapping(&f, sigil_option_is_none as usize);
7418            }
7419            if let Some(f) = self.module.get_function("sigil_option_unwrap") {
7420                ee.add_global_mapping(&f, sigil_option_unwrap as usize);
7421            }
7422            if let Some(f) = self.module.get_function("sigil_option_unwrap_or") {
7423                ee.add_global_mapping(&f, sigil_option_unwrap_or as usize);
7424            }
7425
7426            // File I/O runtime mappings
7427            if let Some(f) = self.module.get_function("sigil_file_exists") {
7428                ee.add_global_mapping(&f, sigil_file_exists as usize);
7429            }
7430            if let Some(f) = self.module.get_function("sigil_file_read_all") {
7431                ee.add_global_mapping(&f, sigil_file_read_all as usize);
7432            }
7433            if let Some(f) = self.module.get_function("sigil_file_write_all") {
7434                ee.add_global_mapping(&f, sigil_file_write_all as usize);
7435            }
7436
7437            self.execution_engine = Some(ee);
7438
7439            // Get main function
7440            unsafe {
7441                let main: JitFunction<MainFn> = self
7442                    .execution_engine
7443                    .as_ref()
7444                    .unwrap()
7445                    .get_function("main")
7446                    .map_err(|e| e.to_string())?;
7447
7448                Ok(main.call())
7449            }
7450        }
7451
7452        /// Write object file
7453        pub fn write_object_file(&self, path: &Path) -> Result<(), String> {
7454            Target::initialize_all(&InitializationConfig::default());
7455
7456            let triple = TargetMachine::get_default_triple();
7457            let target = Target::from_triple(&triple).map_err(|e| e.to_string())?;
7458            let target_machine = target
7459                .create_target_machine(
7460                    &triple,
7461                    "generic",
7462                    "",
7463                    OptimizationLevel::Aggressive,
7464                    RelocMode::PIC, // Use PIC for PIE compatibility
7465                    CodeModel::Default,
7466                )
7467                .ok_or("Failed to create target machine")?;
7468
7469            target_machine
7470                .write_to_file(&self.module, FileType::Object, path)
7471                .map_err(|e| e.to_string())
7472        }
7473
7474        /// Get LLVM IR as string
7475        pub fn get_ir(&self) -> String {
7476            self.module.print_to_string().to_string()
7477        }
7478    }
7479
7480    /// Variable scope for compilation
7481    struct CompileScope<'ctx> {
7482        vars: HashMap<String, PointerValue<'ctx>>,
7483    }
7484
7485    impl<'ctx> CompileScope<'ctx> {
7486        fn new() -> Self {
7487            Self {
7488                vars: HashMap::new(),
7489            }
7490        }
7491    }
7492
7493    // ============================================
7494    // Tests
7495    // ============================================
7496    #[cfg(test)]
7497    mod tests {
7498        use super::*;
7499        use crate::optimize::OptLevel;
7500
7501        fn run_sigil(source: &str) -> Result<i64, String> {
7502            let context = Context::create();
7503            let mut compiler = LlvmCompiler::new(&context, OptLevel::Standard)?;
7504            compiler.compile(source)?;
7505            compiler.run()
7506        }
7507
7508        // ============================================
7509        // Evidentiality Tests
7510        // ============================================
7511
7512        #[test]
7513        fn test_evidential_known_unwrap() {
7514            // Known (!) just returns the inner value
7515            let result = run_sigil(
7516                r#"
7517                rite main() -> i64 {
7518                    ≔ x = 42!;
7519                    x
7520                }
7521            "#,
7522            );
7523            assert_eq!(result.unwrap(), 42);
7524        }
7525
7526        #[test]
7527        fn test_evidential_uncertain() {
7528            // Uncertain (?) wraps and unwraps correctly
7529            let result = run_sigil(
7530                r#"
7531                rite main() -> i64 {
7532                    ≔ x = 100?;
7533                    x
7534                }
7535            "#,
7536            );
7537            assert_eq!(result.unwrap(), 100);
7538        }
7539
7540        #[test]
7541        fn test_evidential_reported() {
7542            // Reported (~) wraps and unwraps correctly
7543            let result = run_sigil(
7544                r#"
7545                rite main() -> i64 {
7546                    ≔ x = 200~;
7547                    x
7548                }
7549            "#,
7550            );
7551            assert_eq!(result.unwrap(), 200);
7552        }
7553
7554        #[test]
7555        fn test_evidential_predicted() {
7556            // Predicted (◊) wraps and unwraps correctly
7557            let result = run_sigil(
7558                r#"
7559                rite main() -> i64 {
7560                    ≔ x = 300◊;
7561                    x
7562                }
7563            "#,
7564            );
7565            assert_eq!(result.unwrap(), 300);
7566        }
7567
7568        #[test]
7569        fn test_evidential_in_expression() {
7570            // Evidential values can be used in expressions
7571            let result = run_sigil(
7572                r#"
7573                rite main() -> i64 {
7574                    ≔ a = 10?;
7575                    ≔ b = 20?;
7576                    a + b
7577                }
7578            "#,
7579            );
7580            assert_eq!(result.unwrap(), 30);
7581        }
7582
7583        #[test]
7584        fn test_evidential_unwrap_chain() {
7585            // Chain: uncertain -> known (unwrap)
7586            let result = run_sigil(
7587                r#"
7588                rite main() -> i64 {
7589                    ≔ x = 42?;
7590                    ≔ y = x!;
7591                    y
7592                }
7593            "#,
7594            );
7595            assert_eq!(result.unwrap(), 42);
7596        }
7597
7598        #[test]
7599        fn test_evidential_nested() {
7600            // Nested evidential operations
7601            let result = run_sigil(
7602                r#"
7603                rite main() -> i64 {
7604                    ≔ x = (50?)!;
7605                    x + 5
7606                }
7607            "#,
7608            );
7609            assert_eq!(result.unwrap(), 55);
7610        }
7611
7612        #[test]
7613        fn test_evidential_with_arithmetic() {
7614            // Evidential values with arithmetic
7615            let result = run_sigil(
7616                r#"
7617                rite main() -> i64 {
7618                    ≔ known = 100!;
7619                    ≔ uncertain = 50?;
7620                    known + uncertain * 2
7621                }
7622            "#,
7623            );
7624            assert_eq!(result.unwrap(), 200);
7625        }
7626
7627        #[test]
7628        fn test_evidential_function_return() {
7629            // Function returning evidential value
7630            let result = run_sigil(
7631                r#"
7632                rite get_uncertain() -> i64 {
7633                    42?
7634                }
7635
7636                rite main() -> i64 {
7637                    ≔ x = get_uncertain();
7638                    x + 8
7639                }
7640            "#,
7641            );
7642            assert_eq!(result.unwrap(), 50);
7643        }
7644
7645        #[test]
7646        fn test_evidential_mixed_markers() {
7647            // Mix different evidentiality markers
7648            let result = run_sigil(
7649                r#"
7650                rite main() -> i64 {
7651                    ≔ a = 10!;  // known
7652                    ≔ b = 20?;  // uncertain
7653                    ≔ c = 30~;  // reported
7654                    a + b + c
7655                }
7656            "#,
7657            );
7658            assert_eq!(result.unwrap(), 60);
7659        }
7660
7661        #[test]
7662        fn test_evidential_in_if() {
7663            // Evidential in conditional
7664            let result = run_sigil(
7665                r#"
7666                rite main() -> i64 {
7667                    ≔ x = 1?;
7668                    ⎇ x == 1 {
7669                        100?
7670                    } ⎉ {
7671                        200?
7672                    }
7673                }
7674            "#,
7675            );
7676            assert_eq!(result.unwrap(), 100);
7677        }
7678
7679        #[test]
7680        fn test_evidential_paradox() {
7681            // Paradox (‽) marker - contradiction detection
7682            let result = run_sigil(
7683                r#"
7684                rite main() -> i64 {
7685                    ≔ x = 42‽;
7686                    x
7687                }
7688            "#,
7689            );
7690            assert_eq!(result.unwrap(), 42);
7691        }
7692
7693        #[test]
7694        fn test_evidential_multiple_unwraps() {
7695            // Multiple sequential unwraps
7696            let result = run_sigil(
7697                r#"
7698                rite main() -> i64 {
7699                    ≔ a = 10?;
7700                    ≔ b = a!;
7701                    ≔ c = b!;
7702                    c
7703                }
7704            "#,
7705            );
7706            assert_eq!(result.unwrap(), 10);
7707        }
7708
7709        #[test]
7710        fn test_evidential_in_loop() {
7711            // Evidential values in a loop
7712            let result = run_sigil(
7713                r#"
7714                rite main() -> i64 {
7715                    ≔ Δ sum = 0?;
7716                    ≔ Δ i = 0;
7717                    ⟳ i < 5 {
7718                        sum = sum + i?;
7719                        i = i + 1;
7720                    }
7721                    sum!
7722                }
7723            "#,
7724            );
7725            assert_eq!(result.unwrap(), 10); // 0 + 1 + 2 + 3 + 4 = 10
7726        }
7727
7728        #[test]
7729        fn test_evidential_comparison() {
7730            // Comparison of evidential values
7731            let result = run_sigil(
7732                r#"
7733                rite main() -> i64 {
7734                    ≔ a = 10?;
7735                    ≔ b = 20?;
7736                    ⎇ a < b {
7737                        1!
7738                    } ⎉ {
7739                        0!
7740                    }
7741                }
7742            "#,
7743            );
7744            assert_eq!(result.unwrap(), 1);
7745        }
7746
7747        #[test]
7748        fn test_evidential_negation() {
7749            // Negation with evidential values
7750            let result = run_sigil(
7751                r#"
7752                rite main() -> i64 {
7753                    ≔ x = 42?;
7754                    ≔ y = -x;
7755                    y + 100
7756                }
7757            "#,
7758            );
7759            assert_eq!(result.unwrap(), 58); // -42 + 100 = 58
7760        }
7761
7762        #[test]
7763        fn test_evidential_chain_operations() {
7764            // Chain of operations with mixed evidentiality
7765            let result = run_sigil(
7766                r#"
7767                rite main() -> i64 {
7768                    ≔ x = 10!;
7769                    ≔ y = 20?;
7770                    ≔ z = 30~;
7771                    ≔ w = 40◊;
7772                    x + y + z + w
7773                }
7774            "#,
7775            );
7776            assert_eq!(result.unwrap(), 100);
7777        }
7778
7779        #[test]
7780        fn test_evidential_deeply_nested() {
7781            // Deeply nested evidential expressions
7782            let result = run_sigil(
7783                r#"
7784                rite main() -> i64 {
7785                    ≔ x = ((((42?)?)?)?)?;
7786                    x!
7787                }
7788            "#,
7789            );
7790            assert_eq!(result.unwrap(), 42);
7791        }
7792
7793        #[test]
7794        fn test_evidential_struct_field() {
7795            // Evidential values as struct fields
7796            let result = run_sigil(
7797                r#"
7798                Σ Data {
7799                    value: i64,
7800                }
7801
7802                rite main() -> i64 {
7803                    ≔ d = Data { value: 100? };
7804                    d.value + 1
7805                }
7806            "#,
7807            );
7808            assert_eq!(result.unwrap(), 101);
7809        }
7810
7811        #[test]
7812        fn test_evidential_function_param() {
7813            // Function with evidential parameter
7814            let result = run_sigil(
7815                r#"
7816                rite double(x: i64) -> i64 {
7817                    x * 2
7818                }
7819
7820                rite main() -> i64 {
7821                    ≔ val = 25?;
7822                    double(val!)
7823                }
7824            "#,
7825            );
7826            assert_eq!(result.unwrap(), 50);
7827        }
7828
7829        #[test]
7830        fn test_evidential_all_markers_chain() {
7831            // All 5 evidentiality markers in sequence
7832            let result = run_sigil(
7833                r#"
7834                rite main() -> i64 {
7835                    ≔ known = 1!;      // Known
7836                    ≔ uncertain = 2?;  // Uncertain
7837                    ≔ reported = 3~;   // Reported
7838                    ≔ predicted = 4◊;  // Predicted
7839                    ≔ paradox = 5‽;    // Paradox
7840                    known + uncertain + reported + predicted + paradox
7841                }
7842            "#,
7843            );
7844            assert_eq!(result.unwrap(), 15);
7845        }
7846
7847        // ============================================
7848        // Generic Monomorphization Tests (existing)
7849        // ============================================
7850
7851        #[test]
7852        fn test_generic_struct_basic() {
7853            let result = run_sigil(
7854                r#"
7855                Σ Container<T> {
7856                    value: T,
7857                    count: i32,
7858                }
7859
7860                rite main() -> i64 {
7861                    ≔ c = Container·<i32> { value: 42, count: 1 };
7862                    c.value + c.count
7863                }
7864            "#,
7865            );
7866            assert_eq!(result.unwrap(), 43);
7867        }
7868
7869        #[test]
7870        fn test_generic_struct_two_params() {
7871            let result = run_sigil(
7872                r#"
7873                Σ Pair<A, B> {
7874                    first: A,
7875                    second: B,
7876                }
7877
7878                rite main() -> i64 {
7879                    ≔ p = Pair·<i32, i32> { first: 10, second: 20 };
7880                    p.first + p.second
7881                }
7882            "#,
7883            );
7884            assert_eq!(result.unwrap(), 30);
7885        }
7886
7887        // ============================================
7888        // Morpheme Tests - Element Access
7889        // ============================================
7890
7891        #[test]
7892        fn test_morpheme_first() {
7893            // First element: [1, 2, 3] |α returns 1
7894            let result = run_sigil(
7895                r#"
7896                rite main() -> i64 {
7897                    [10, 20, 30] |α
7898                }
7899            "#,
7900            );
7901            assert_eq!(result.unwrap(), 10);
7902        }
7903
7904        #[test]
7905        fn test_morpheme_last() {
7906            // Last element: [1, 2, 3] |ω returns 3
7907            let result = run_sigil(
7908                r#"
7909                rite main() -> i64 {
7910                    [10, 20, 30] |ω
7911                }
7912            "#,
7913            );
7914            assert_eq!(result.unwrap(), 30);
7915        }
7916
7917        #[test]
7918        fn test_morpheme_middle() {
7919            // Middle element: [1, 2, 3, 4, 5] |μ returns 3
7920            let result = run_sigil(
7921                r#"
7922                rite main() -> i64 {
7923                    [10, 20, 30, 40, 50] |μ
7924                }
7925            "#,
7926            );
7927            assert_eq!(result.unwrap(), 30);
7928        }
7929
7930        #[test]
7931        fn test_morpheme_nth() {
7932            // Nth element: [1, 2, 3] |ν{1} returns 2
7933            let result = run_sigil(
7934                r#"
7935                rite main() -> i64 {
7936                    [10, 20, 30] |ν{1}
7937                }
7938            "#,
7939            );
7940            assert_eq!(result.unwrap(), 20);
7941        }
7942
7943        // ============================================
7944        // Morpheme Tests - Reductions
7945        // ============================================
7946
7947        #[test]
7948        fn test_morpheme_reduce_min() {
7949            // Simple min of two values
7950            let result = run_sigil(
7951                r#"
7952                rite min2(a: i64, b: i64) -> i64 {
7953                    ⎇ a < b { a } ⎉ { b }
7954                }
7955                rite main() -> i64 {
7956                    min2(min2(5, 2), min2(8, 1))
7957                }
7958            "#,
7959            );
7960            assert_eq!(result.unwrap(), 1);
7961        }
7962
7963        #[test]
7964        fn test_morpheme_reduce_max() {
7965            // Simple max of two values
7966            let result = run_sigil(
7967                r#"
7968                rite max2(a: i64, b: i64) -> i64 {
7969                    ⎇ a > b { a } ⎉ { b }
7970                }
7971                rite main() -> i64 {
7972                    max2(max2(5, 2), max2(8, 9))
7973                }
7974            "#,
7975            );
7976            assert_eq!(result.unwrap(), 9);
7977        }
7978
7979        #[test]
7980        fn test_morpheme_reduce_all_true() {
7981            // All: [1, 2, 3] |ρ& returns 1 (all non-zero)
7982            let result = run_sigil(
7983                r#"
7984                rite main() -> i64 {
7985                    [1, 2, 3] |ρ&
7986                }
7987            "#,
7988            );
7989            assert_eq!(result.unwrap(), 1);
7990        }
7991
7992        #[test]
7993        fn test_morpheme_reduce_all_false() {
7994            // All: [1, 0, 3] |ρ& returns 0 (not all non-zero)
7995            let result = run_sigil(
7996                r#"
7997                rite main() -> i64 {
7998                    [1, 0, 3] |ρ&
7999                }
8000            "#,
8001            );
8002            assert_eq!(result.unwrap(), 0);
8003        }
8004
8005        #[test]
8006        fn test_morpheme_reduce_any_true() {
8007            // Any: [0, 0, 1] |ρ| returns 1 (at least one non-zero)
8008            let result = run_sigil(
8009                r#"
8010                rite main() -> i64 {
8011                    [0, 0, 1] |ρ|
8012                }
8013            "#,
8014            );
8015            assert_eq!(result.unwrap(), 1);
8016        }
8017
8018        #[test]
8019        fn test_morpheme_reduce_any_false() {
8020            // Any: [0, 0, 0] |ρ| returns 0 (none non-zero)
8021            let result = run_sigil(
8022                r#"
8023                rite main() -> i64 {
8024                    [0, 0, 0] |ρ|
8025                }
8026            "#,
8027            );
8028            assert_eq!(result.unwrap(), 0);
8029        }
8030
8031        // ============================================
8032        // Combined Morpheme Tests
8033        // ============================================
8034
8035        #[test]
8036        fn test_morpheme_transform_then_first() {
8037            // Transform then first: [1, 2, 3] |τ{|x| x * 10} |α returns 10
8038            let result = run_sigil(
8039                r#"
8040                rite main() -> i64 {
8041                    ≔ arr = [1, 2, 3] |τ{|x| x * 10};
8042                    arr |α
8043                }
8044            "#,
8045            );
8046            // Note: This tests that transform returns array, then first extracts
8047            // Current impl may need adjustment
8048            assert!(result.is_ok());
8049        }
8050
8051        #[test]
8052        fn test_morpheme_filter_then_sum() {
8053            // Filter then sum: keep values > 3, sum them
8054            let result = run_sigil(
8055                r#"
8056                rite main() -> i64 {
8057                    [1, 5, 2, 8, 3, 7] |φ{|x| x > 3} |ρ+
8058                }
8059            "#,
8060            );
8061            // After filter: [5, 8, 7], sum = 20
8062            assert_eq!(result.unwrap(), 20);
8063        }
8064
8065        // ============================================
8066        // New Morpheme Tests - Sort, Choice, Custom Reduce
8067        // ============================================
8068
8069        #[test]
8070        fn test_morpheme_sort_basic() {
8071            // Sort returns minimum (first after sort): [3, 1, 2] |σ returns 1
8072            let result = run_sigil(
8073                r#"
8074                rite main() -> i64 {
8075                    [3, 1, 2] |σ
8076                }
8077            "#,
8078            );
8079            assert_eq!(result.unwrap(), 1);
8080        }
8081
8082        #[test]
8083        fn test_morpheme_sort_already_sorted() {
8084            // Sort already sorted: [1, 2, 3] |σ returns 1
8085            let result = run_sigil(
8086                r#"
8087                rite main() -> i64 {
8088                    [1, 2, 3] |σ
8089                }
8090            "#,
8091            );
8092            assert_eq!(result.unwrap(), 1);
8093        }
8094
8095        #[test]
8096        fn test_morpheme_sort_reverse() {
8097            // Sort reverse: [5, 4, 3, 2, 1] |σ returns 1
8098            let result = run_sigil(
8099                r#"
8100                rite main() -> i64 {
8101                    [5, 4, 3, 2, 1] |σ
8102                }
8103            "#,
8104            );
8105            assert_eq!(result.unwrap(), 1);
8106        }
8107
8108        #[test]
8109        fn test_morpheme_sort_single() {
8110            // Sort single element: [42] |σ returns 42
8111            let result = run_sigil(
8112                r#"
8113                rite main() -> i64 {
8114                    [42] |σ
8115                }
8116            "#,
8117            );
8118            assert_eq!(result.unwrap(), 42);
8119        }
8120
8121        #[test]
8122        fn test_morpheme_choice_deterministic() {
8123            // Choice is deterministic based on array contents
8124            let result = run_sigil(
8125                r#"
8126                rite main() -> i64 {
8127                    [10, 20, 30] |χ
8128                }
8129            "#,
8130            );
8131            // Result should be one of 10, 20, or 30
8132            let val = result.unwrap();
8133            assert!(val == 10 || val == 20 || val == 30);
8134        }
8135
8136        #[test]
8137        fn test_morpheme_choice_single() {
8138            // Choice with single element: [42] |χ returns 42
8139            let result = run_sigil(
8140                r#"
8141                rite main() -> i64 {
8142                    [42] |χ
8143                }
8144            "#,
8145            );
8146            assert_eq!(result.unwrap(), 42);
8147        }
8148
8149        #[test]
8150        fn test_morpheme_custom_reduce_sum() {
8151            // Custom reduce sum: [1, 2, 3, 4] |ρ{|a, x| a + x} = 10
8152            let result = run_sigil(
8153                r#"
8154                rite main() -> i64 {
8155                    [1, 2, 3, 4] |ρ{|acc, x| acc + x}
8156                }
8157            "#,
8158            );
8159            assert_eq!(result.unwrap(), 10);
8160        }
8161
8162        #[test]
8163        fn test_morpheme_custom_reduce_product() {
8164            // Custom reduce product: [1, 2, 3, 4] |ρ{|a, x| a * x} = 24
8165            let result = run_sigil(
8166                r#"
8167                rite main() -> i64 {
8168                    [1, 2, 3, 4] |ρ{|acc, x| acc * x}
8169                }
8170            "#,
8171            );
8172            assert_eq!(result.unwrap(), 24);
8173        }
8174
8175        #[test]
8176        fn test_morpheme_custom_reduce_difference() {
8177            // Custom reduce difference: [100, 20, 5] |ρ{|a, x| a - x} = 75
8178            let result = run_sigil(
8179                r#"
8180                rite main() -> i64 {
8181                    [100, 20, 5] |ρ{|acc, x| acc - x}
8182                }
8183            "#,
8184            );
8185            assert_eq!(result.unwrap(), 75);
8186        }
8187
8188        #[test]
8189        fn test_morpheme_custom_reduce_single() {
8190            // Custom reduce single element: [42] |ρ{|a, x| a + x} = 42
8191            let result = run_sigil(
8192                r#"
8193                rite main() -> i64 {
8194                    [42] |ρ{|acc, x| acc + x}
8195                }
8196            "#,
8197            );
8198            assert_eq!(result.unwrap(), 42);
8199        }
8200
8201        #[test]
8202        fn test_morpheme_await_expr() {
8203            // Await expression form: expr⌛ (postfix syntax)
8204            let result = run_sigil(
8205                r#"
8206                rite main() -> i64 {
8207                    ≔ x = 42;
8208                    x⌛
8209                }
8210            "#,
8211            );
8212            // In sync LLVM context, await is identity
8213            assert_eq!(result.unwrap(), 42);
8214        }
8215
8216        #[test]
8217        fn test_morpheme_await_nested() {
8218            // Nested await expressions
8219            let result = run_sigil(
8220                r#"
8221                rite main() -> i64 {
8222                    ≔ x = 21;
8223                    ≔ y = x⌛ + x⌛;
8224                    y
8225                }
8226            "#,
8227            );
8228            assert_eq!(result.unwrap(), 42);
8229        }
8230    }
8231}