//! C code generation backend for Lux
//!
//! Compiles Lux programs to C code that can be compiled with GCC/Clang.
//!
//! ## Compilation Strategy
//!
//! Lux source → Parse → Type check → Generate C → Invoke cc/gcc/clang → Binary
//!
//! This approach is similar to Koka, Nim, and Chicken Scheme. It leverages
//! decades of C compiler optimizations (GCC/Clang) without reimplementing them.
//!
//! ## Runtime Type Representations
//!
//! | Lux Type | C Type |
//! |----------|--------|
//! | Int | `int64_t` (LuxInt) |
//! | Float | `double` (LuxFloat) |
//! | Bool | `bool` (LuxBool) |
//! | String | `char*` (LuxString) |
//! | Closure | `struct {void* env, void* fn_ptr}` (LuxClosure) |
//! | ADT | Tagged union (enum tag + union of variant structs) |
//! | List | `struct {void** elements, int64_t length, capacity}` (LuxList) |
//!
//! ## Supported Features
//!
//! - **Functions**: Direct function calls with name mangling (`foo` → `foo_lux`)
//! - **Closures**: Heap-allocated environment struct + function pointer
//! - **ADTs**: Tagged unions with exhaustive pattern matching
//! - **Pattern Matching**: Compiles to if/else chains checking tags
//! - **Lists**: Dynamic arrays with void* boxing for generic elements
//!
//! ## Current Limitations
//!
//! - **Memory**: No deallocation - everything leaks (GC/RC not yet implemented)
//! - **Effects**: Only `Console.print` supported (hardcoded to printf)
//! - **If/else side effects**: Uses ternary `?:`, so both branches execute
//!   during codegen if they contain effects like Console.print
//!
//! ## Future Work (see docs/C_BACKEND.md)
//!
//! - Evidence passing for zero-cost effects (like Koka)
//! - Perceus-style reference counting for memory management
//! - More effects (File, Http, etc.)

use crate::ast::*;
use std::collections::{HashSet, HashMap};
use std::fmt::Write;

/// C code generation errors
#[derive(Debug, Clone)]
pub struct CGenError {
    pub message: String,
    #[allow(dead_code)]
    pub span: Option<Span>,
}

/// Information about a closure to be emitted
#[derive(Debug, Clone)]
struct ClosureInfo {
    id: usize,
    env_fields: Vec<(String, String)>,  // (var_name, c_type)
    params: Vec<(String, String)>,       // (param_name, c_type)
    return_type: String,
    body: Expr,
}

/// Information about an RC-managed variable in scope
#[derive(Debug, Clone)]
struct RcVariable {
    name: String,      // Variable name in generated C code
    c_type: String,    // C type (for documentation/debugging)
    adt_type_name: Option<String>,  // If Some, this is an ADT that needs field cleanup
}

impl std::fmt::Display for CGenError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "C codegen error: {}", self.message)
    }
}

impl std::error::Error for CGenError {}

/// Behavioral properties for a function
#[derive(Debug, Clone, Default)]
struct FunctionBehavior {
    is_pure: bool,
    is_total: bool,
    is_idempotent: bool,
    is_deterministic: bool,
    is_commutative: bool,
}

/// The C backend code generator
pub struct CBackend {
    /// Generated C code
    output: String,
    /// Current indentation level
    indent: usize,
    /// Known function names for forward declarations
    functions: HashSet<String>,
    /// Type definitions we've emitted
    types_emitted: HashSet<String>,
    /// Counter for generating unique names
    name_counter: usize,
    /// Effects used in the program (for evidence struct)
    effects_used: HashSet<String>,
    /// Closures to emit (collected during expression generation)
    closures: Vec<ClosureInfo>,
    /// Variables in scope (for free variable analysis)
    #[allow(dead_code)]
    local_vars: HashSet<String>,
    /// Functions that return closures
    closure_returning_functions: HashSet<String>,
    /// Mapping from variant names to their parent type name
    variant_to_type: HashMap<String, String>,
    /// Mapping from (type_name, variant_name) to field types
    variant_field_types: HashMap<(String, String), Vec<String>>,
    /// Functions that use effects (have evidence parameter)
    effectful_functions: HashSet<String>,
    /// Whether we're currently inside an effectful function (has evidence available)
    has_evidence: bool,
    /// Stack of scopes for RC management - each scope contains variables that need decref
    rc_scopes: Vec<Vec<RcVariable>>,
    /// Whether to emit memory tracking code for debugging
    debug_rc: bool,
    /// Mapping from function names to their C return types
    function_return_types: HashMap<String, String>,
    /// Mapping from function names to their parameter types
    function_param_types: HashMap<String, Vec<String>>,
    /// Type tags for ADT types (starting at 100)
    adt_type_tags: HashMap<String, i32>,
    /// Next available ADT type tag
    next_adt_tag: i32,
    /// ADT types that have pointer fields (need drop functions)
    adt_with_pointers: HashSet<String>,
    /// Variable types for type inference (variable name -> C type)
    var_types: HashMap<String, String>,
    /// Behavioral properties for functions (for optimization)
    function_behaviors: HashMap<String, FunctionBehavior>,
    /// Whether to enable behavioral type optimizations
    enable_behavioral_optimizations: bool,
}

impl CBackend {
    pub fn new() -> Self {
        Self {
            output: String::new(),
            indent: 0,
            functions: HashSet::new(),
            types_emitted: HashSet::new(),
            name_counter: 0,
            effects_used: HashSet::new(),
            closures: Vec::new(),
            local_vars: HashSet::new(),
            closure_returning_functions: HashSet::new(),
            variant_to_type: HashMap::new(),
            variant_field_types: HashMap::new(),
            effectful_functions: HashSet::new(),
            has_evidence: false,
            rc_scopes: Vec::new(),
            debug_rc: false,  // Set to true to enable RC leak tracking
            function_return_types: HashMap::new(),
            function_param_types: HashMap::new(),
            adt_type_tags: HashMap::new(),
            next_adt_tag: 100,  // ADT tags start at 100
            adt_with_pointers: HashSet::new(),
            var_types: HashMap::new(),
            function_behaviors: HashMap::new(),
            enable_behavioral_optimizations: true,
        }
    }

    /// Collect behavioral properties from function declaration
    fn collect_behavioral_properties(&mut self, f: &FunctionDecl) {
        let mut behavior = FunctionBehavior::default();

        for prop in &f.properties {
            match prop {
                BehavioralProperty::Pure => behavior.is_pure = true,
                BehavioralProperty::Total => behavior.is_total = true,
                BehavioralProperty::Idempotent => behavior.is_idempotent = true,
                BehavioralProperty::Deterministic => behavior.is_deterministic = true,
                BehavioralProperty::Commutative => behavior.is_commutative = true,
            }
        }

        if behavior.is_pure || behavior.is_total || behavior.is_idempotent
            || behavior.is_deterministic || behavior.is_commutative {
            self.function_behaviors.insert(f.name.name.clone(), behavior);
        }
    }

    /// Generate C code from a Lux program
    pub fn generate(&mut self, program: &Program) -> Result<String, CGenError> {
        self.output.clear();
        self.closures.clear();
        self.emit_prelude();

        // First pass: collect all function names, types, and effects
        for decl in &program.declarations {
            match decl {
                Declaration::Function(f) => {
                    self.functions.insert(f.name.name.clone());
                    // Store function return type for call inference
                    if let Ok(ret_type) = self.type_expr_to_c(&f.return_type) {
                        self.function_return_types.insert(f.name.name.clone(), ret_type);
                    }
                    // Store function parameter types for usage inference
                    let param_types: Vec<String> = f.params.iter()
                        .filter_map(|p| self.type_expr_to_c(&p.typ).ok())
                        .collect();
                    self.function_param_types.insert(f.name.name.clone(), param_types);
                    // Check if this function returns a closure
                    if matches!(&f.return_type, TypeExpr::Function { .. }) {
                        self.closure_returning_functions.insert(f.name.name.clone());
                    }
                    // Check if this function uses effects (evidence passing)
                    if !f.effects.is_empty() {
                        self.effectful_functions.insert(f.name.name.clone());
                    }
                    // Collect behavioral properties for optimization
                    self.collect_behavioral_properties(f);
                }
                Declaration::Type(t) => {
                    self.collect_type(t)?;
                }
                _ => {}
            }
        }

        // Emit type definitions
        self.emit_type_definitions(program)?;

        // Emit ADT drop function (after type definitions so we know the ADT structure)
        self.emit_adt_drop_function();

        // Emit forward declarations for regular functions
        self.emit_forward_declarations(program)?;

        // Generate function bodies to a temporary buffer
        // This collects closures that need to be emitted
        let saved_output = std::mem::take(&mut self.output);

        for decl in &program.declarations {
            match decl {
                Declaration::Function(f) => {
                    self.emit_function(f)?;
                }
                Declaration::Let(let_decl) => {
                    // Skip run expressions - they're handled in the main wrapper
                    if !matches!(&let_decl.value, Expr::Run { .. }) {
                        self.emit_global_let(&let_decl.name, &let_decl.value)?;
                    }
                }
                _ => {}
            }
        }

        let function_output = std::mem::replace(&mut self.output, saved_output);

        // Now emit closure definitions (collected during function generation)
        self.emit_closures()?;

        // Append the function definitions
        self.output.push_str(&function_output);

        // Emit main wrapper if there's a main function or top-level expressions
        self.emit_main_wrapper(program)?;

        Ok(self.output.clone())
    }

    /// Emit all collected closure definitions
    fn emit_closures(&mut self) -> Result<(), CGenError> {
        if self.closures.is_empty() {
            return Ok(());
        }

        self.writeln("// === Closure Definitions ===");
        self.writeln("");

        // Take closures to avoid borrow issues
        let closures = std::mem::take(&mut self.closures);

        for closure in &closures {
            // Emit environment struct
            if closure.env_fields.is_empty() {
                // No captured variables - no env struct needed
            } else {
                self.writeln(&format!("typedef struct {{"));
                self.indent += 1;
                for (name, typ) in &closure.env_fields {
                    self.writeln(&format!("{} {};", typ, name));
                }
                self.indent -= 1;
                self.writeln(&format!("}} LuxEnv_{};", closure.id));
                self.writeln("");
            }

            // Emit lambda implementation
            let params_str = if closure.params.is_empty() {
                "void* _env".to_string()
            } else {
                let ps: Vec<String> = closure.params.iter()
                    .map(|(name, typ)| format!("{} {}", typ, name))
                    .collect();
                format!("void* _env, {}", ps.join(", "))
            };

            self.writeln(&format!("static {} lambda_{}({}) {{",
                closure.return_type, closure.id, params_str));
            self.indent += 1;

            // Cast env pointer if we have captured variables
            if !closure.env_fields.is_empty() {
                self.writeln(&format!("LuxEnv_{}* env = (LuxEnv_{}*)_env;",
                    closure.id, closure.id));
            }

            // Emit body with env-> substitution for captured variables
            let body_result = self.emit_closure_body(&closure.body, &closure.env_fields)?;
            self.writeln(&format!("return {};", body_result));

            self.indent -= 1;
            self.writeln("}");
            self.writeln("");
        }

        // Restore closures (in case more are collected)
        self.closures = closures;

        Ok(())
    }

    /// Emit closure body with environment variable substitution
    fn emit_closure_body(&mut self, expr: &Expr, env_fields: &[(String, String)]) -> Result<String, CGenError> {
        // Create a set of captured variable names for quick lookup
        let captured: HashSet<&str> = env_fields.iter().map(|(n, _)| n.as_str()).collect();
        self.emit_expr_with_env(expr, &captured)
    }

    /// Emit expression, substituting captured variables with env->name
    fn emit_expr_with_env(&mut self, expr: &Expr, captured: &HashSet<&str>) -> Result<String, CGenError> {
        match expr {
            Expr::Var(ident) => {
                let escaped = self.escape_c_keyword(&ident.name);
                if captured.contains(ident.name.as_str()) {
                    Ok(format!("env->{}", escaped))
                } else if self.functions.contains(&ident.name) {
                    Ok(self.mangle_name(&ident.name))
                } else {
                    Ok(escaped)
                }
            }
            Expr::Literal(lit) => self.emit_literal(lit),
            Expr::BinaryOp { op, left, right, .. } => {
                let l = self.emit_expr_with_env(left, captured)?;
                let r = self.emit_expr_with_env(right, captured)?;

                // Check for string comparison - use strcmp instead of pointer comparison
                if matches!(op, BinaryOp::Eq | BinaryOp::Ne) {
                    let left_is_string = self.is_string_expr(left);
                    let right_is_string = self.is_string_expr(right);
                    if left_is_string || right_is_string {
                        if matches!(op, BinaryOp::Eq) {
                            return Ok(format!("(strcmp({}, {}) == 0)", l, r));
                        } else {
                            return Ok(format!("(strcmp({}, {}) != 0)", l, r));
                        }
                    }
                }

                let op_str = match op {
                    BinaryOp::Add => "+",
                    BinaryOp::Sub => "-",
                    BinaryOp::Mul => "*",
                    BinaryOp::Div => "/",
                    BinaryOp::Mod => "%",
                    BinaryOp::Eq => "==",
                    BinaryOp::Ne => "!=",
                    BinaryOp::Lt => "<",
                    BinaryOp::Le => "<=",
                    BinaryOp::Gt => ">",
                    BinaryOp::Ge => ">=",
                    BinaryOp::And => "&&",
                    BinaryOp::Or => "||",
                    _ => return Err(CGenError {
                        message: format!("Unsupported binary operator in closure"),
                        span: None,
                    }),
                };
                Ok(format!("({} {} {})", l, op_str, r))
            }
            Expr::UnaryOp { op, operand, .. } => {
                let o = self.emit_expr_with_env(operand, captured)?;
                let op_str = match op {
                    UnaryOp::Neg => "-",
                    UnaryOp::Not => "!",
                };
                Ok(format!("({}{})", op_str, o))
            }
            Expr::If { condition, then_branch, else_branch, .. } => {
                let c = self.emit_expr_with_env(condition, captured)?;
                let t = self.emit_expr_with_env(then_branch, captured)?;
                let e = self.emit_expr_with_env(else_branch, captured)?;
                Ok(format!("({} ? {} : {})", c, t, e))
            }
            Expr::Call { func, args, .. } => {
                let arg_strs: Result<Vec<_>, _> = args.iter()
                    .map(|a| self.emit_expr_with_env(a, captured))
                    .collect();
                let args_str = arg_strs?.join(", ");

                match func.as_ref() {
                    Expr::Var(ident) if self.functions.contains(&ident.name) => {
                        let c_func_name = self.mangle_name(&ident.name);
                        // Pass evidence if this function uses effects
                        let is_effectful = self.effectful_functions.contains(&ident.name);
                        if is_effectful {
                            // Inside closures, use default evidence
                            if args_str.is_empty() {
                                Ok(format!("{}(&default_evidence)", c_func_name))
                            } else {
                                Ok(format!("{}(&default_evidence, {})", c_func_name, args_str))
                            }
                        } else {
                            Ok(format!("{}({})", c_func_name, args_str))
                        }
                    }
                    _ => {
                        let closure_expr = self.emit_expr_with_env(func, captured)?;
                        let param_types: Vec<&str> = args.iter().map(|_| "LuxInt").collect();
                        let params_str = if param_types.is_empty() {
                            String::new()
                        } else {
                            format!(", {}", param_types.join(", "))
                        };
                        let args_with_env = if args_str.is_empty() {
                            format!("({})->env", closure_expr)
                        } else {
                            format!("({})->env, {}", closure_expr, args_str)
                        };
                        Ok(format!("((LuxInt(*)(void*{}))({})->fn_ptr)({})",
                            params_str, closure_expr, args_with_env))
                    }
                }
            }
            _ => {
                // For other expressions, fall back to regular emit_expr
                // This may not handle captured variables correctly for complex expressions
                self.emit_expr(expr)
            }
        }
    }

    fn emit_prelude(&mut self) {
        self.writeln("// Generated by Lux compiler");
        self.writeln("// Do not edit - regenerate from .lux source");
        self.writeln("");
        self.writeln("#include <stdint.h>");
        self.writeln("#include <stdbool.h>");
        self.writeln("#include <stdio.h>");
        self.writeln("#include <stdlib.h>");
        self.writeln("#include <string.h>");
        self.writeln("");
        self.writeln("// === Lux Runtime Types ===");
        self.writeln("");
        self.writeln("typedef int64_t LuxInt;");
        self.writeln("typedef double LuxFloat;");
        self.writeln("typedef bool LuxBool;");
        self.writeln("typedef char* LuxString;");
        self.writeln("typedef void* LuxUnit;");
        self.writeln("");
        self.writeln("// Forward struct declarations for drop specialization");
        self.writeln("typedef struct LuxList_s LuxList;");
        self.writeln("typedef struct LuxClosure_s LuxClosure;");
        self.writeln("");
        self.writeln("// Closure representation: env pointer + function pointer");
        self.writeln("struct LuxClosure_s { void* env; void* fn_ptr; };");
        self.writeln("");
        self.writeln("// List struct body (typedef declared above)");
        self.writeln("struct LuxList_s {");
        self.writeln("    void** elements;");
        self.writeln("    int64_t length;");
        self.writeln("    int64_t capacity;");
        self.writeln("};");
        self.writeln("");
        self.writeln("// === Reference Counting Infrastructure ===");
        self.writeln("// Perceus-inspired RC system for automatic memory management.");
        self.writeln("// See docs/REFERENCE_COUNTING.md for details.");
        self.writeln("");
        self.writeln("// Type tags for polymorphic drop - identifies the type of RC object");
        self.writeln("typedef enum {");
        self.writeln("    LUX_TAG_STRING = 1,");
        self.writeln("    LUX_TAG_LIST = 2,");
        self.writeln("    LUX_TAG_CLOSURE = 3,");
        self.writeln("    LUX_TAG_BOXED_INT = 4,");
        self.writeln("    LUX_TAG_BOXED_BOOL = 5,");
        self.writeln("    LUX_TAG_BOXED_FLOAT = 6,");
        self.writeln("    LUX_TAG_ENV = 7,         // Closure environment");
        self.writeln("    LUX_TAG_ADT = 100        // ADT types start at 100");
        self.writeln("} LuxTypeTag;");
        self.writeln("");
        self.writeln("// Magic number to identify RC-managed memory (allows safe decref of static strings)");
        self.writeln("#define LUX_RC_MAGIC 0x4C555852  // 'LUXR' in ASCII");
        self.writeln("");
        self.writeln("// RC header placed before every heap-allocated object");
        self.writeln("typedef struct {");
        self.writeln("    int32_t magic;   // Magic number to identify RC-managed memory");
        self.writeln("    int32_t rc;      // Reference count");
        self.writeln("    int32_t tag;     // Type tag for polymorphic drop");
        self.writeln("    int32_t _pad;    // Padding for alignment");
        self.writeln("} LuxRcHeader;");
        self.writeln("");
        self.writeln("// Get the RC header from an object pointer");
        self.writeln("#define LUX_RC_HEADER(ptr) (((LuxRcHeader*)(ptr)) - 1)");
        self.writeln("");
        self.writeln("// Check if a pointer is RC-managed (has valid magic number)");
        self.writeln("#define LUX_IS_RC_MANAGED(ptr) (ptr && LUX_RC_HEADER(ptr)->magic == LUX_RC_MAGIC)");
        self.writeln("");
        self.writeln("// Forward declarations of drop functions");
        self.writeln("static void lux_drop(void* ptr, int32_t tag);");
        self.writeln("static void lux_drop_adt(void* ptr, int32_t tag);");
        self.writeln("");

        // Memory tracking counters (must be before lux_rc_alloc which uses them)
        if self.debug_rc {
            self.writeln("// Memory tracking counters");
            self.writeln("static int64_t lux_rc_alloc_count = 0;");
            self.writeln("static int64_t lux_rc_free_count = 0;");
            self.writeln("");
            self.writeln("// FBIP (Functional But In-Place) optimization counters");
            self.writeln("static int64_t lux_fbip_reuse_count = 0;");
            self.writeln("static int64_t lux_fbip_copy_count = 0;");
            self.writeln("");
        }

        self.writeln("// Allocate RC-managed memory with initial refcount of 1");
        self.writeln("static void* lux_rc_alloc(size_t size, int32_t tag) {");
        self.writeln("    LuxRcHeader* hdr = (LuxRcHeader*)malloc(sizeof(LuxRcHeader) + size);");
        self.writeln("    if (!hdr) return NULL;");
        self.writeln("    hdr->magic = LUX_RC_MAGIC;");
        self.writeln("    hdr->rc = 1;");
        self.writeln("    hdr->tag = tag;");
        if self.debug_rc {
            self.writeln("    lux_rc_alloc_count++;");
        }
        self.writeln("    return hdr + 1;  // Return pointer after header");
        self.writeln("}");
        self.writeln("");
        self.writeln("// Increment reference count (only for RC-managed memory)");
        self.writeln("static inline void lux_incref(void* ptr) {");
        self.writeln("    if (LUX_IS_RC_MANAGED(ptr)) LUX_RC_HEADER(ptr)->rc++;");
        self.writeln("}");
        self.writeln("");
        self.writeln("// Decrement reference count, call drop if zero (generic)");
        self.writeln("static inline void lux_decref(void* ptr) {");
        self.writeln("    if (LUX_IS_RC_MANAGED(ptr)) {");
        self.writeln("        LuxRcHeader* hdr = LUX_RC_HEADER(ptr);");
        self.writeln("        if (--hdr->rc == 0) {");
        self.writeln("            lux_drop(ptr, hdr->tag);");
        self.writeln("        }");
        self.writeln("    }");
        self.writeln("}");
        self.writeln("");

        // Forward declarations for specialized decref functions (defined after struct bodies)
        self.writeln("// Forward declarations for drop specialization (defined after struct bodies)");
        self.writeln("static inline void lux_decref_list(LuxList* list);");
        self.writeln("static inline void lux_decref_closure(LuxClosure* closure);");
        self.writeln("static inline void lux_decref_string(LuxString str);");
        self.writeln("static inline void lux_decref_boxed(void* ptr);");
        self.writeln("");

        self.writeln("// Get current reference count (for debugging)");
        self.writeln("static inline int32_t lux_refcount(void* ptr) {");
        self.writeln("    return ptr ? LUX_RC_HEADER(ptr)->rc : 0;");
        self.writeln("}");
        self.writeln("");

        // Memory leak check function (only if debug_rc is enabled)
        if self.debug_rc {
            self.writeln("// === Memory Tracking (Debug) ===");
            self.writeln("static void lux_rc_check_leaks(void) {");
            self.writeln("    if (lux_rc_alloc_count != lux_rc_free_count) {");
            self.writeln("        fprintf(stderr, \"[RC] LEAK DETECTED: %lld allocs, %lld frees, %lld leaked\\n\",");
            self.writeln("                (long long)lux_rc_alloc_count, (long long)lux_rc_free_count,");
            self.writeln("                (long long)(lux_rc_alloc_count - lux_rc_free_count));");
            self.writeln("    } else {");
            self.writeln("        fprintf(stderr, \"[RC] No leaks: %lld allocs, %lld frees\\n\",");
            self.writeln("                (long long)lux_rc_alloc_count, (long long)lux_rc_free_count);");
            self.writeln("    }");
            self.writeln("    // Print FBIP optimization stats");
            self.writeln("    if (lux_fbip_reuse_count > 0 || lux_fbip_copy_count > 0) {");
            self.writeln("        fprintf(stderr, \"[FBIP] %lld reuses, %lld copies\\n\",");
            self.writeln("                (long long)lux_fbip_reuse_count, (long long)lux_fbip_copy_count);");
            self.writeln("    }");
            self.writeln("}");
            self.writeln("");
        }

        self.writeln("// === String Operations ===");
        self.writeln("// Dynamically created strings are RC-managed.");
        self.writeln("// Static string literals from source code are NOT RC-managed.");
        self.writeln("");
        self.writeln("static LuxString lux_string_concat(LuxString a, LuxString b) {");
        self.writeln("    size_t len_a = strlen(a);");
        self.writeln("    size_t len_b = strlen(b);");
        self.writeln("    LuxString result = (LuxString)lux_rc_alloc(len_a + len_b + 1, LUX_TAG_STRING);");
        self.writeln("    memcpy(result, a, len_a);");
        self.writeln("    memcpy(result + len_a, b, len_b + 1);");
        self.writeln("    return result;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString lux_int_to_string(LuxInt n) {");
        self.writeln("    char buffer[32];");
        self.writeln("    snprintf(buffer, sizeof(buffer), \"%lld\", (long long)n);");
        self.writeln("    size_t len = strlen(buffer);");
        self.writeln("    LuxString result = (LuxString)lux_rc_alloc(len + 1, LUX_TAG_STRING);");
        self.writeln("    memcpy(result, buffer, len + 1);");
        self.writeln("    return result;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxBool lux_string_eq(LuxString a, LuxString b) {");
        self.writeln("    return strcmp(a, b) == 0;");
        self.writeln("}");
        self.writeln("");
        self.writeln("// Alias for memoization key comparison");
        self.writeln("static inline LuxBool lux_string_equals(LuxString a, LuxString b) {");
        self.writeln("    return strcmp(a, b) == 0;");
        self.writeln("}");
        self.writeln("");
        self.writeln("// String hash for memoization (djb2 algorithm)");
        self.writeln("static inline size_t lux_string_hash(LuxString s) {");
        self.writeln("    size_t hash = 5381;");
        self.writeln("    unsigned char c;");
        self.writeln("    while ((c = (unsigned char)*s++)) {");
        self.writeln("        hash = ((hash << 5) + hash) + c;");
        self.writeln("    }");
        self.writeln("    return hash;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxBool lux_string_contains(LuxString haystack, LuxString needle) {");
        self.writeln("    return strstr(haystack, needle) != NULL;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString lux_string_dup(LuxString s) {");
        self.writeln("    if (!s) return \"\";");
        self.writeln("    size_t len = strlen(s);");
        self.writeln("    LuxString result = (LuxString)lux_rc_alloc(len + 1, LUX_TAG_STRING);");
        self.writeln("    memcpy(result, s, len + 1);");
        self.writeln("    return result;");
        self.writeln("}");
        self.writeln("");
        self.writeln("// === Built-in Effect Implementations ===");
        self.writeln("");
        self.writeln("static void lux_console_print(LuxString msg) {");
        self.writeln("    printf(\"%s\\n\", msg);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString lux_console_readLine(void) {");
        self.writeln("    char buffer[4096];");
        self.writeln("    if (fgets(buffer, sizeof(buffer), stdin)) {");
        self.writeln("        size_t len = strlen(buffer);");
        self.writeln("        if (len > 0 && buffer[len-1] == '\\n') buffer[len-1] = '\\0';");
        self.writeln("        len = strlen(buffer);");
        self.writeln("        LuxString result = (LuxString)lux_rc_alloc(len + 1, LUX_TAG_STRING);");
        self.writeln("        memcpy(result, buffer, len + 1);");
        self.writeln("        return result;");
        self.writeln("    }");
        self.writeln("    LuxString result = (LuxString)lux_rc_alloc(1, LUX_TAG_STRING);");
        self.writeln("    result[0] = '\\0';");
        self.writeln("    return result;");
        self.writeln("}");
        self.writeln("");
        // Forward declare Option type (needed by LuxProcessHandler)
        self.writeln("// Built-in Option type (forward declaration for use in handlers)");
        self.writeln("typedef enum { Option_TAG_NONE, Option_TAG_SOME } Option_Tag;");
        self.writeln("typedef struct { void* field0; } Option_Some_Data;");
        self.writeln("typedef struct { Option_Tag tag; union { Option_Some_Data some; } data; } Option;");
        self.writeln("");

        self.writeln("// === Evidence Passing Types ===");
        self.writeln("// These enable O(1) effect handler lookup instead of O(n) stack search.");
        self.writeln("// See docs/EVIDENCE_PASSING.md for details.");
        self.writeln("");
        self.writeln("// Handler struct for Console effect");
        self.writeln("typedef struct {");
        self.writeln("    void (*print)(void* env, LuxString msg);");
        self.writeln("    LuxString (*readLine)(void* env);");
        self.writeln("    void* env;");
        self.writeln("} LuxConsoleHandler;");
        self.writeln("");
        self.writeln("// Handler struct for State effect");
        self.writeln("typedef struct {");
        self.writeln("    void* (*get)(void* env);");
        self.writeln("    void (*put)(void* env, void* value);");
        self.writeln("    void* env;");
        self.writeln("} LuxStateHandler;");
        self.writeln("");
        self.writeln("// Handler struct for Reader effect");
        self.writeln("typedef struct {");
        self.writeln("    void* (*ask)(void* env);");
        self.writeln("    void* env;");
        self.writeln("} LuxReaderHandler;");
        self.writeln("");
        self.writeln("// Handler struct for Random effect");
        self.writeln("typedef struct {");
        self.writeln("    LuxInt (*randInt)(void* env, LuxInt min, LuxInt max);");
        self.writeln("    LuxFloat (*randFloat)(void* env);");
        self.writeln("    LuxBool (*randBool)(void* env);");
        self.writeln("    void* env;");
        self.writeln("} LuxRandomHandler;");
        self.writeln("");
        self.writeln("// Handler struct for Time effect");
        self.writeln("typedef struct {");
        self.writeln("    LuxInt (*now)(void* env);");
        self.writeln("    void (*sleep)(void* env, LuxInt ms);");
        self.writeln("    void* env;");
        self.writeln("} LuxTimeHandler;");
        self.writeln("");
        self.writeln("// Handler struct for File effect");
        self.writeln("typedef struct {");
        self.writeln("    LuxString (*read)(void* env, LuxString path);");
        self.writeln("    void (*write)(void* env, LuxString path, LuxString content);");
        self.writeln("    void (*append)(void* env, LuxString path, LuxString content);");
        self.writeln("    LuxBool (*exists)(void* env, LuxString path);");
        self.writeln("    void (*delete_file)(void* env, LuxString path);");
        self.writeln("    LuxBool (*isDir)(void* env, LuxString path);");
        self.writeln("    void (*mkdir)(void* env, LuxString path);");
        self.writeln("    void* env;");
        self.writeln("} LuxFileHandler;");
        self.writeln("");
        self.writeln("// Handler struct for Http effect");
        self.writeln("typedef struct {");
        self.writeln("    LuxString (*get)(void* env, LuxString url);");
        self.writeln("    LuxString (*post)(void* env, LuxString url, LuxString body);");
        self.writeln("    LuxString (*put)(void* env, LuxString url, LuxString body);");
        self.writeln("    LuxString (*delete_req)(void* env, LuxString url);");
        self.writeln("    void* env;");
        self.writeln("} LuxHttpHandler;");
        self.writeln("");
        self.writeln("// Handler struct for Process effect");
        self.writeln("typedef struct {");
        self.writeln("    LuxString (*exec)(void* env, LuxString cmd);");
        self.writeln("    Option (*getenv_fn)(void* env, LuxString name);");
        self.writeln("    LuxList* (*args)(void* env);");
        self.writeln("    LuxString (*cwd)(void* env);");
        self.writeln("    void* env;");
        self.writeln("} LuxProcessHandler;");
        self.writeln("");
        self.writeln("// Evidence struct - passed to effectful functions");
        self.writeln("// Contains pointers to current handlers for each effect type");
        self.writeln("typedef struct {");
        self.writeln("    LuxConsoleHandler* console;");
        self.writeln("    LuxStateHandler* state;");
        self.writeln("    LuxReaderHandler* reader;");
        self.writeln("    LuxRandomHandler* random;");
        self.writeln("    LuxTimeHandler* time;");
        self.writeln("    LuxFileHandler* file;");
        self.writeln("    LuxHttpHandler* http;");
        self.writeln("    LuxProcessHandler* process;");
        self.writeln("} LuxEvidence;");
        self.writeln("");
        self.writeln("// Default Console handler using built-in implementations");
        self.writeln("static void default_console_print(void* env, LuxString msg) {");
        self.writeln("    (void)env;");
        self.writeln("    lux_console_print(msg);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString default_console_readLine(void* env) {");
        self.writeln("    (void)env;");
        self.writeln("    return lux_console_readLine();");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxConsoleHandler default_console_handler = {");
        self.writeln("    .print = default_console_print,");
        self.writeln("    .readLine = default_console_readLine,");
        self.writeln("    .env = NULL");
        self.writeln("};");
        self.writeln("");
        self.writeln("// === Random Effect Built-in Implementations ===");
        self.writeln("");
        self.writeln("static unsigned int lux_rand_state = 12345;");
        self.writeln("");
        self.writeln("static LuxInt lux_random_int(LuxInt min, LuxInt max) {");
        self.writeln("    // Simple LCG random number generator");
        self.writeln("    lux_rand_state = lux_rand_state * 1103515245 + 12345;");
        self.writeln("    LuxInt range = max - min + 1;");
        self.writeln("    if (range <= 0) return min;");
        self.writeln("    return min + (LuxInt)((lux_rand_state >> 16) % range);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxFloat lux_random_float(void) {");
        self.writeln("    lux_rand_state = lux_rand_state * 1103515245 + 12345;");
        self.writeln("    return (double)(lux_rand_state >> 16) / 32767.0;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxBool lux_random_bool(void) {");
        self.writeln("    return lux_random_int(0, 1) == 1;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxInt default_random_int(void* env, LuxInt min, LuxInt max) {");
        self.writeln("    (void)env;");
        self.writeln("    return lux_random_int(min, max);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxFloat default_random_float(void* env) {");
        self.writeln("    (void)env;");
        self.writeln("    return lux_random_float();");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxBool default_random_bool(void* env) {");
        self.writeln("    (void)env;");
        self.writeln("    return lux_random_bool();");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxRandomHandler default_random_handler = {");
        self.writeln("    .randInt = default_random_int,");
        self.writeln("    .randFloat = default_random_float,");
        self.writeln("    .randBool = default_random_bool,");
        self.writeln("    .env = NULL");
        self.writeln("};");
        self.writeln("");
        self.writeln("// === Time Effect Built-in Implementations ===");
        self.writeln("");
        self.writeln("#include <time.h>");
        self.writeln("");
        self.writeln("static LuxInt lux_time_now(void) {");
        self.writeln("    struct timespec ts;");
        self.writeln("    clock_gettime(CLOCK_REALTIME, &ts);");
        self.writeln("    return (LuxInt)(ts.tv_sec * 1000 + ts.tv_nsec / 1000000);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static void lux_time_sleep(LuxInt ms) {");
        self.writeln("    struct timespec ts;");
        self.writeln("    ts.tv_sec = ms / 1000;");
        self.writeln("    ts.tv_nsec = (ms % 1000) * 1000000;");
        self.writeln("    nanosleep(&ts, NULL);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxInt default_time_now(void* env) {");
        self.writeln("    (void)env;");
        self.writeln("    return lux_time_now();");
        self.writeln("}");
        self.writeln("");
        self.writeln("static void default_time_sleep(void* env, LuxInt ms) {");
        self.writeln("    (void)env;");
        self.writeln("    lux_time_sleep(ms);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxTimeHandler default_time_handler = {");
        self.writeln("    .now = default_time_now,");
        self.writeln("    .sleep = default_time_sleep,");
        self.writeln("    .env = NULL");
        self.writeln("};");
        self.writeln("");
        self.writeln("// === File Effect Built-in Implementations ===");
        self.writeln("");
        self.writeln("#include <sys/stat.h>");
        self.writeln("#include <unistd.h>");
        self.writeln("#include <errno.h>");
        self.writeln("");
        self.writeln("static LuxString lux_file_read(LuxString path) {");
        self.writeln("    FILE* f = fopen(path, \"r\");");
        self.writeln("    if (!f) {");
        self.writeln("        LuxString empty = (LuxString)lux_rc_alloc(1, LUX_TAG_STRING);");
        self.writeln("        empty[0] = '\\0';");
        self.writeln("        return empty;");
        self.writeln("    }");
        self.writeln("    fseek(f, 0, SEEK_END);");
        self.writeln("    long size = ftell(f);");
        self.writeln("    fseek(f, 0, SEEK_SET);");
        self.writeln("    LuxString content = (LuxString)lux_rc_alloc(size + 1, LUX_TAG_STRING);");
        self.writeln("    size_t read_size = fread(content, 1, size, f);");
        self.writeln("    content[read_size] = '\\0';");
        self.writeln("    fclose(f);");
        self.writeln("    return content;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static void lux_file_write(LuxString path, LuxString content) {");
        self.writeln("    FILE* f = fopen(path, \"w\");");
        self.writeln("    if (f) {");
        self.writeln("        fputs(content, f);");
        self.writeln("        fclose(f);");
        self.writeln("    }");
        self.writeln("}");
        self.writeln("");
        self.writeln("static void lux_file_append(LuxString path, LuxString content) {");
        self.writeln("    FILE* f = fopen(path, \"a\");");
        self.writeln("    if (f) {");
        self.writeln("        fputs(content, f);");
        self.writeln("        fclose(f);");
        self.writeln("    }");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxBool lux_file_exists(LuxString path) {");
        self.writeln("    return access(path, F_OK) == 0;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static void lux_file_delete(LuxString path) {");
        self.writeln("    remove(path);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxBool lux_file_isDir(LuxString path) {");
        self.writeln("    struct stat st;");
        self.writeln("    if (stat(path, &st) == 0) {");
        self.writeln("        return S_ISDIR(st.st_mode);");
        self.writeln("    }");
        self.writeln("    return false;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static void lux_file_mkdir(LuxString path) {");
        self.writeln("    mkdir(path, 0755);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString default_file_read(void* env, LuxString path) {");
        self.writeln("    (void)env;");
        self.writeln("    return lux_file_read(path);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static void default_file_write(void* env, LuxString path, LuxString content) {");
        self.writeln("    (void)env;");
        self.writeln("    lux_file_write(path, content);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static void default_file_append(void* env, LuxString path, LuxString content) {");
        self.writeln("    (void)env;");
        self.writeln("    lux_file_append(path, content);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxBool default_file_exists(void* env, LuxString path) {");
        self.writeln("    (void)env;");
        self.writeln("    return lux_file_exists(path);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static void default_file_delete(void* env, LuxString path) {");
        self.writeln("    (void)env;");
        self.writeln("    lux_file_delete(path);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxBool default_file_isDir(void* env, LuxString path) {");
        self.writeln("    (void)env;");
        self.writeln("    return lux_file_isDir(path);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static void default_file_mkdir(void* env, LuxString path) {");
        self.writeln("    (void)env;");
        self.writeln("    lux_file_mkdir(path);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxFileHandler default_file_handler = {");
        self.writeln("    .read = default_file_read,");
        self.writeln("    .write = default_file_write,");
        self.writeln("    .append = default_file_append,");
        self.writeln("    .exists = default_file_exists,");
        self.writeln("    .delete_file = default_file_delete,");
        self.writeln("    .isDir = default_file_isDir,");
        self.writeln("    .mkdir = default_file_mkdir,");
        self.writeln("    .env = NULL");
        self.writeln("};");
        self.writeln("");
        self.writeln("// === Http Effect Built-in Implementations ===");
        self.writeln("");
        self.writeln("#include <sys/socket.h>");
        self.writeln("#include <netinet/in.h>");
        self.writeln("#include <netdb.h>");
        self.writeln("#include <arpa/inet.h>");
        self.writeln("");
        self.writeln("// Parse URL into host, port, and path");
        self.writeln("static int lux_http_parse_url(const char* url, char* host, int* port, char* path) {");
        self.writeln("    *port = 80;");
        self.writeln("    path[0] = '/'; path[1] = '\\0';");
        self.writeln("    const char* start = url;");
        self.writeln("    if (strncmp(url, \"http://\", 7) == 0) start = url + 7;");
        self.writeln("    else if (strncmp(url, \"https://\", 8) == 0) { start = url + 8; *port = 443; }");
        self.writeln("    const char* slash = strchr(start, '/');");
        self.writeln("    const char* colon = strchr(start, ':');");
        self.writeln("    if (colon && (!slash || colon < slash)) {");
        self.writeln("        strncpy(host, start, colon - start);");
        self.writeln("        host[colon - start] = '\\0';");
        self.writeln("        *port = atoi(colon + 1);");
        self.writeln("    } else if (slash) {");
        self.writeln("        strncpy(host, start, slash - start);");
        self.writeln("        host[slash - start] = '\\0';");
        self.writeln("    } else {");
        self.writeln("        strcpy(host, start);");
        self.writeln("    }");
        self.writeln("    if (slash) strcpy(path, slash);");
        self.writeln("    return 0;");
        self.writeln("}");
        self.writeln("");
        self.writeln("// Helper to create RC-managed error string");
        self.writeln("static LuxString lux_rc_string(const char* s) {");
        self.writeln("    size_t len = strlen(s);");
        self.writeln("    LuxString result = (LuxString)lux_rc_alloc(len + 1, LUX_TAG_STRING);");
        self.writeln("    memcpy(result, s, len + 1);");
        self.writeln("    return result;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString lux_http_request(const char* method, LuxString url, LuxString body) {");
        self.writeln("    char host[256], path[1024];");
        self.writeln("    int port;");
        self.writeln("    lux_http_parse_url(url, host, &port, path);");
        self.writeln("");
        self.writeln("    struct hostent* server = gethostbyname(host);");
        self.writeln("    if (!server) return lux_rc_string(\"Error: Could not resolve host\");");
        self.writeln("");
        self.writeln("    int sockfd = socket(AF_INET, SOCK_STREAM, 0);");
        self.writeln("    if (sockfd < 0) return lux_rc_string(\"Error: Could not create socket\");");
        self.writeln("");
        self.writeln("    struct sockaddr_in serv_addr;");
        self.writeln("    memset(&serv_addr, 0, sizeof(serv_addr));");
        self.writeln("    serv_addr.sin_family = AF_INET;");
        self.writeln("    memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length);");
        self.writeln("    serv_addr.sin_port = htons(port);");
        self.writeln("");
        self.writeln("    if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {");
        self.writeln("        close(sockfd);");
        self.writeln("        return lux_rc_string(\"Error: Connection failed\");");
        self.writeln("    }");
        self.writeln("");
        self.writeln("    char request[4096];");
        self.writeln("    if (body && strlen(body) > 0) {");
        self.writeln("        snprintf(request, sizeof(request),");
        self.writeln("            \"%s %s HTTP/1.1\\r\\n\"");
        self.writeln("            \"Host: %s\\r\\n\"");
        self.writeln("            \"Content-Type: application/x-www-form-urlencoded\\r\\n\"");
        self.writeln("            \"Content-Length: %zu\\r\\n\"");
        self.writeln("            \"Connection: close\\r\\n\\r\\n%s\",");
        self.writeln("            method, path, host, strlen(body), body);");
        self.writeln("    } else {");
        self.writeln("        snprintf(request, sizeof(request),");
        self.writeln("            \"%s %s HTTP/1.1\\r\\n\"");
        self.writeln("            \"Host: %s\\r\\n\"");
        self.writeln("            \"Connection: close\\r\\n\\r\\n\",");
        self.writeln("            method, path, host);");
        self.writeln("    }");
        self.writeln("");
        self.writeln("    send(sockfd, request, strlen(request), 0);");
        self.writeln("");
        self.writeln("    char* response = (char*)malloc(65536);");
        self.writeln("    size_t total = 0;");
        self.writeln("    ssize_t n;");
        self.writeln("    while ((n = recv(sockfd, response + total, 65536 - total - 1, 0)) > 0) {");
        self.writeln("        total += n;");
        self.writeln("        if (total >= 65535) break;");
        self.writeln("    }");
        self.writeln("    response[total] = '\\0';");
        self.writeln("    close(sockfd);");
        self.writeln("");
        self.writeln("    // Find body (after \\r\\n\\r\\n)");
        self.writeln("    char* body_start = strstr(response, \"\\r\\n\\r\\n\");");
        self.writeln("    if (body_start) {");
        self.writeln("        body_start += 4;");
        self.writeln("        LuxString result = lux_rc_string(body_start);");
        self.writeln("        free(response);");
        self.writeln("        return result;");
        self.writeln("    }");
        self.writeln("    // If no body separator, wrap the whole response");
        self.writeln("    LuxString result = lux_rc_string(response);");
        self.writeln("    free(response);");
        self.writeln("    return result;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString lux_http_get(LuxString url) {");
        self.writeln("    return lux_http_request(\"GET\", url, NULL);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString lux_http_post(LuxString url, LuxString body) {");
        self.writeln("    return lux_http_request(\"POST\", url, body);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString lux_http_put(LuxString url, LuxString body) {");
        self.writeln("    return lux_http_request(\"PUT\", url, body);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString lux_http_delete(LuxString url) {");
        self.writeln("    return lux_http_request(\"DELETE\", url, NULL);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString default_http_get(void* env, LuxString url) {");
        self.writeln("    (void)env;");
        self.writeln("    return lux_http_get(url);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString default_http_post(void* env, LuxString url, LuxString body) {");
        self.writeln("    (void)env;");
        self.writeln("    return lux_http_post(url, body);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString default_http_put(void* env, LuxString url, LuxString body) {");
        self.writeln("    (void)env;");
        self.writeln("    return lux_http_put(url, body);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString default_http_delete(void* env, LuxString url) {");
        self.writeln("    (void)env;");
        self.writeln("    return lux_http_delete(url);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxHttpHandler default_http_handler = {");
        self.writeln("    .get = default_http_get,");
        self.writeln("    .post = default_http_post,");
        self.writeln("    .put = default_http_put,");
        self.writeln("    .delete_req = default_http_delete,");
        self.writeln("    .env = NULL");
        self.writeln("};");
        self.writeln("");
        self.writeln("// === Process Effect Built-in Implementations ===");
        self.writeln("");
        self.writeln("// Forward declarations for list functions used by Process/String");
        self.writeln("static LuxList* lux_list_new(int64_t capacity);");
        self.writeln("static void lux_list_push(LuxList* list, void* element);");
        self.writeln("");
        self.writeln("static LuxString lux_process_exec(LuxString cmd) {");
        self.writeln("    FILE* fp = popen(cmd, \"r\");");
        self.writeln("    if (!fp) return \"\";");
        self.writeln("    char buffer[4096];");
        self.writeln("    size_t total_len = 0;");
        self.writeln("    size_t capacity = 4096;");
        self.writeln("    char* temp = (char*)malloc(capacity);");
        self.writeln("    if (!temp) { pclose(fp); return \"\"; }");
        self.writeln("    temp[0] = '\\0';");
        self.writeln("    while (fgets(buffer, sizeof(buffer), fp) != NULL) {");
        self.writeln("        size_t chunk_len = strlen(buffer);");
        self.writeln("        if (total_len + chunk_len + 1 > capacity) {");
        self.writeln("            capacity *= 2;");
        self.writeln("            char* new_temp = (char*)realloc(temp, capacity);");
        self.writeln("            if (!new_temp) { free(temp); pclose(fp); return \"\"; }");
        self.writeln("            temp = new_temp;");
        self.writeln("        }");
        self.writeln("        strcpy(temp + total_len, buffer);");
        self.writeln("        total_len += chunk_len;");
        self.writeln("    }");
        self.writeln("    pclose(fp);");
        self.writeln("    // Copy to RC-managed string");
        self.writeln("    LuxString result = (LuxString)lux_rc_alloc(total_len + 1, LUX_TAG_STRING);");
        self.writeln("    if (!result) { free(temp); return \"\"; }");
        self.writeln("    memcpy(result, temp, total_len + 1);");
        self.writeln("    free(temp);");
        self.writeln("    return result;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static Option lux_process_env(LuxString name) {");
        self.writeln("    char* value = getenv(name);");
        self.writeln("    if (value) {");
        self.writeln("        Option result;");
        self.writeln("        result.tag = Option_TAG_SOME;");
        self.writeln("        result.data.some.field0 = (void*)lux_string_dup(value);");
        self.writeln("        return result;");
        self.writeln("    } else {");
        self.writeln("        Option result;");
        self.writeln("        result.tag = Option_TAG_NONE;");
        self.writeln("        return result;");
        self.writeln("    }");
        self.writeln("}");
        self.writeln("");
        self.writeln("// Global argc/argv for Process.args()");
        self.writeln("static int lux_argc = 0;");
        self.writeln("static char** lux_argv = NULL;");
        self.writeln("");
        self.writeln("static LuxList* lux_process_args(void) {");
        self.writeln("    LuxList* list = lux_list_new(lux_argc > 0 ? lux_argc : 1);");
        self.writeln("    for (int i = 0; i < lux_argc; i++) {");
        self.writeln("        lux_list_push(list, (void*)lux_string_dup(lux_argv[i]));");
        self.writeln("    }");
        self.writeln("    return list;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString lux_process_cwd(void) {");
        self.writeln("    char* cwd = getcwd(NULL, 0);");
        self.writeln("    if (!cwd) return \"\";");
        self.writeln("    return cwd;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString default_process_exec(void* env, LuxString cmd) {");
        self.writeln("    (void)env;");
        self.writeln("    return lux_process_exec(cmd);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static Option default_process_env(void* env, LuxString name) {");
        self.writeln("    (void)env;");
        self.writeln("    return lux_process_env(name);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxList* default_process_args(void* env) {");
        self.writeln("    (void)env;");
        self.writeln("    return lux_process_args();");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString default_process_cwd(void* env) {");
        self.writeln("    (void)env;");
        self.writeln("    return lux_process_cwd();");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxProcessHandler default_process_handler = {");
        self.writeln("    .exec = default_process_exec,");
        self.writeln("    .getenv_fn = default_process_env,");
        self.writeln("    .args = default_process_args,");
        self.writeln("    .cwd = default_process_cwd,");
        self.writeln("    .env = NULL");
        self.writeln("};");
        self.writeln("");
        self.writeln("// === String Built-in Functions ===");
        self.writeln("");
        self.writeln("static LuxString lux_string_trim(LuxString s) {");
        self.writeln("    if (!s) return \"\";");
        self.writeln("    const char* start = s;");
        self.writeln("    const char* end = s + strlen(s) - 1;");
        self.writeln("    while (*start && (*start == ' ' || *start == '\\t' || *start == '\\n' || *start == '\\r')) start++;");
        self.writeln("    while (end > start && (*end == ' ' || *end == '\\t' || *end == '\\n' || *end == '\\r')) end--;");
        self.writeln("    size_t len = end - start + 1;");
        self.writeln("    LuxString result = (LuxString)lux_rc_alloc(len + 1, LUX_TAG_STRING);");
        self.writeln("    if (!result) return \"\";");
        self.writeln("    strncpy(result, start, len);");
        self.writeln("    result[len] = '\\0';");
        self.writeln("    return result;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxInt lux_string_length(LuxString s) {");
        self.writeln("    if (!s) return 0;");
        self.writeln("    return (LuxInt)strlen(s);");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxList* lux_string_lines(LuxString s) {");
        self.writeln("    LuxList* list = lux_list_new(8);");
        self.writeln("    if (!s || !*s) return list;");
        self.writeln("    const char* start = s;");
        self.writeln("    const char* p = s;");
        self.writeln("    while (*p) {");
        self.writeln("        if (*p == '\\n') {");
        self.writeln("            size_t len = p - start;");
        self.writeln("            LuxString line = (LuxString)lux_rc_alloc(len + 1, LUX_TAG_STRING);");
        self.writeln("            if (line) {");
        self.writeln("                strncpy(line, start, len);");
        self.writeln("                line[len] = '\\0';");
        self.writeln("                lux_list_push(list, (void*)line);");
        self.writeln("            }");
        self.writeln("            start = p + 1;");
        self.writeln("        }");
        self.writeln("        p++;");
        self.writeln("    }");
        self.writeln("    if (start != p) {");
        self.writeln("        size_t len = p - start;");
        self.writeln("        LuxString line = (LuxString)lux_rc_alloc(len + 1, LUX_TAG_STRING);");
        self.writeln("        if (line) {");
        self.writeln("            strncpy(line, start, len);");
        self.writeln("            line[len] = '\\0';");
        self.writeln("            lux_list_push(list, (void*)line);");
        self.writeln("        }");
        self.writeln("    }");
        self.writeln("    return list;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxList* lux_string_split(LuxString s, LuxString sep) {");
        self.writeln("    LuxList* list = lux_list_new(8);");
        self.writeln("    if (!s || !*s) return list;");
        self.writeln("    if (!sep || !*sep) {");
        self.writeln("        lux_list_push(list, (void*)lux_string_dup(s));");
        self.writeln("        return list;");
        self.writeln("    }");
        self.writeln("    size_t sep_len = strlen(sep);");
        self.writeln("    const char* start = s;");
        self.writeln("    const char* found;");
        self.writeln("    while ((found = strstr(start, sep)) != NULL) {");
        self.writeln("        size_t len = found - start;");
        self.writeln("        LuxString part = (LuxString)lux_rc_alloc(len + 1, LUX_TAG_STRING);");
        self.writeln("        if (part) {");
        self.writeln("            strncpy(part, start, len);");
        self.writeln("            part[len] = '\\0';");
        self.writeln("            lux_list_push(list, (void*)part);");
        self.writeln("        }");
        self.writeln("        start = found + sep_len;");
        self.writeln("    }");
        self.writeln("    if (*start) {");
        self.writeln("        lux_list_push(list, (void*)lux_string_dup(start));");
        self.writeln("    }");
        self.writeln("    return list;");
        self.writeln("}");
        self.writeln("");
        // Note: lux_string_contains is already defined in the String Operations section
        self.writeln("");
        self.writeln("static Option lux_string_parseInt(LuxString s) {");
        self.writeln("    Option result;");
        self.writeln("    if (!s || !*s) {");
        self.writeln("        result.tag = Option_TAG_NONE;");
        self.writeln("        return result;");
        self.writeln("    }");
        self.writeln("    char* endptr;");
        self.writeln("    errno = 0;");
        self.writeln("    long long val = strtoll(s, &endptr, 10);");
        self.writeln("    if (errno != 0 || endptr == s || *endptr != '\\0') {");
        self.writeln("        result.tag = Option_TAG_NONE;");
        self.writeln("        return result;");
        self.writeln("    }");
        self.writeln("    result.tag = Option_TAG_SOME;");
        self.writeln("    LuxInt* boxed = (LuxInt*)lux_rc_alloc(sizeof(LuxInt), LUX_TAG_BOXED_INT);");
        self.writeln("    *boxed = (LuxInt)val;");
        self.writeln("    result.data.some.field0 = (void*)boxed;");
        self.writeln("    return result;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static Option lux_string_parseFloat(LuxString s) {");
        self.writeln("    Option result;");
        self.writeln("    if (!s || !*s) {");
        self.writeln("        result.tag = Option_TAG_NONE;");
        self.writeln("        return result;");
        self.writeln("    }");
        self.writeln("    char* endptr;");
        self.writeln("    errno = 0;");
        self.writeln("    double val = strtod(s, &endptr);");
        self.writeln("    if (errno != 0 || endptr == s || *endptr != '\\0') {");
        self.writeln("        result.tag = Option_TAG_NONE;");
        self.writeln("        return result;");
        self.writeln("    }");
        self.writeln("    result.tag = Option_TAG_SOME;");
        self.writeln("    LuxFloat* boxed = (LuxFloat*)malloc(sizeof(LuxFloat));");
        self.writeln("    *boxed = val;");
        self.writeln("    result.data.some.field0 = (void*)boxed;");
        self.writeln("    return result;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString lux_string_from_char(char c) {");
        self.writeln("    LuxString result = (LuxString)lux_rc_alloc(2, LUX_TAG_STRING);");
        self.writeln("    if (!result) return \"\";");
        self.writeln("    result[0] = c;");
        self.writeln("    result[1] = '\\0';");
        self.writeln("    return result;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxList* lux_string_chars(LuxString s) {");
        self.writeln("    size_t len = s ? strlen(s) : 0;");
        self.writeln("    LuxList* list = lux_list_new(len);");
        self.writeln("    for (size_t i = 0; i < len; i++) {");
        self.writeln("        LuxString ch = lux_string_from_char(s[i]);");
        self.writeln("        lux_list_push(list, (void*)ch);");
        self.writeln("    }");
        self.writeln("    return list;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString lux_string_substring(LuxString s, LuxInt start, LuxInt len) {");
        self.writeln("    if (!s) return \"\";");
        self.writeln("    size_t slen = strlen(s);");
        self.writeln("    if (start < 0) start = 0;");
        self.writeln("    if ((size_t)start >= slen) return \"\";");
        self.writeln("    if (len < 0) len = 0;");
        self.writeln("    if ((size_t)(start + len) > slen) len = slen - start;");
        self.writeln("    LuxString result = (LuxString)lux_rc_alloc(len + 1, LUX_TAG_STRING);");
        self.writeln("    if (!result) return \"\";");
        self.writeln("    strncpy(result, s + start, len);");
        self.writeln("    result[len] = '\\0';");
        self.writeln("    return result;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString lux_string_to_upper(LuxString s) {");
        self.writeln("    if (!s) return \"\";");
        self.writeln("    size_t len = strlen(s);");
        self.writeln("    LuxString result = (LuxString)lux_rc_alloc(len + 1, LUX_TAG_STRING);");
        self.writeln("    if (!result) return \"\";");
        self.writeln("    for (size_t i = 0; i < len; i++) {");
        self.writeln("        result[i] = (s[i] >= 'a' && s[i] <= 'z') ? s[i] - 32 : s[i];");
        self.writeln("    }");
        self.writeln("    result[len] = '\\0';");
        self.writeln("    return result;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString lux_string_to_lower(LuxString s) {");
        self.writeln("    if (!s) return \"\";");
        self.writeln("    size_t len = strlen(s);");
        self.writeln("    LuxString result = (LuxString)lux_rc_alloc(len + 1, LUX_TAG_STRING);");
        self.writeln("    if (!result) return \"\";");
        self.writeln("    for (size_t i = 0; i < len; i++) {");
        self.writeln("        result[i] = (s[i] >= 'A' && s[i] <= 'Z') ? s[i] + 32 : s[i];");
        self.writeln("    }");
        self.writeln("    result[len] = '\\0';");
        self.writeln("    return result;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString lux_string_replace(LuxString s, LuxString from, LuxString to) {");
        self.writeln("    if (!s || !from || !*from) return s ? lux_string_dup(s) : \"\";");
        self.writeln("    if (!to) to = \"\";");
        self.writeln("    size_t from_len = strlen(from);");
        self.writeln("    size_t to_len = strlen(to);");
        self.writeln("    size_t count = 0;");
        self.writeln("    const char* p = s;");
        self.writeln("    while ((p = strstr(p, from)) != NULL) { count++; p += from_len; }");
        self.writeln("    size_t new_len = strlen(s) + count * (to_len - from_len);");
        self.writeln("    LuxString result = (LuxString)lux_rc_alloc(new_len + 1, LUX_TAG_STRING);");
        self.writeln("    if (!result) return \"\";");
        self.writeln("    char* out = result;");
        self.writeln("    p = s;");
        self.writeln("    const char* found;");
        self.writeln("    while ((found = strstr(p, from)) != NULL) {");
        self.writeln("        size_t prefix_len = found - p;");
        self.writeln("        memcpy(out, p, prefix_len);");
        self.writeln("        out += prefix_len;");
        self.writeln("        memcpy(out, to, to_len);");
        self.writeln("        out += to_len;");
        self.writeln("        p = found + from_len;");
        self.writeln("    }");
        self.writeln("    strcpy(out, p);");
        self.writeln("    return result;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxBool lux_string_starts_with(LuxString s, LuxString prefix) {");
        self.writeln("    if (!s || !prefix) return 0;");
        self.writeln("    size_t prefix_len = strlen(prefix);");
        self.writeln("    if (strlen(s) < prefix_len) return 0;");
        self.writeln("    return strncmp(s, prefix, prefix_len) == 0;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxBool lux_string_ends_with(LuxString s, LuxString suffix) {");
        self.writeln("    if (!s || !suffix) return 0;");
        self.writeln("    size_t s_len = strlen(s);");
        self.writeln("    size_t suffix_len = strlen(suffix);");
        self.writeln("    if (s_len < suffix_len) return 0;");
        self.writeln("    return strcmp(s + s_len - suffix_len, suffix) == 0;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxString lux_string_join(LuxList* list, LuxString sep) {");
        self.writeln("    if (!list || list->length == 0) return \"\";");
        self.writeln("    if (!sep) sep = \"\";");
        self.writeln("    size_t sep_len = strlen(sep);");
        self.writeln("    size_t total_len = 0;");
        self.writeln("    for (int64_t i = 0; i < list->length; i++) {");
        self.writeln("        LuxString elem = (LuxString)list->elements[i];");
        self.writeln("        if (elem) total_len += strlen(elem);");
        self.writeln("        if (i > 0) total_len += sep_len;");
        self.writeln("    }");
        self.writeln("    LuxString result = (LuxString)lux_rc_alloc(total_len + 1, LUX_TAG_STRING);");
        self.writeln("    if (!result) return \"\";");
        self.writeln("    char* out = result;");
        self.writeln("    for (int64_t i = 0; i < list->length; i++) {");
        self.writeln("        if (i > 0) { strcpy(out, sep); out += sep_len; }");
        self.writeln("        LuxString elem = (LuxString)list->elements[i];");
        self.writeln("        if (elem) { strcpy(out, elem); out += strlen(elem); }");
        self.writeln("    }");
        self.writeln("    *out = '\\0';");
        self.writeln("    return result;");
        self.writeln("}");
        self.writeln("");
        self.writeln("// Default evidence with built-in handlers");
        self.writeln("static LuxEvidence default_evidence = {");
        self.writeln("    .console = &default_console_handler,");
        self.writeln("    .state = NULL,");
        self.writeln("    .reader = NULL,");
        self.writeln("    .random = &default_random_handler,");
        self.writeln("    .time = &default_time_handler,");
        self.writeln("    .file = &default_file_handler,");
        self.writeln("    .http = &default_http_handler,");
        self.writeln("    .process = &default_process_handler");
        self.writeln("};");
        self.writeln("");
        self.writeln("// === List Operations ===");
        self.writeln("// (LuxList struct defined earlier, before string functions)");

        // Emit specialized decref implementations (now that types are defined)
        self.emit_specialized_decref_implementations();

        self.writeln("// === List Operations ===");
        self.writeln("// All lists are RC-managed. Elements are also RC-managed.");
        self.writeln("");
        self.writeln("static LuxList* lux_list_new(int64_t capacity) {");
        self.writeln("    LuxList* list = (LuxList*)lux_rc_alloc(sizeof(LuxList), LUX_TAG_LIST);");
        self.writeln("    if (!list) return NULL;");
        self.writeln("    list->capacity = capacity > 0 ? capacity : 4;");
        self.writeln("    list->elements = (void**)malloc(sizeof(void*) * list->capacity);");
        self.writeln("    list->length = 0;");
        self.writeln("    return list;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static void lux_list_push(LuxList* list, void* element) {");
        self.writeln("    if (list->length >= list->capacity) {");
        self.writeln("        list->capacity *= 2;");
        self.writeln("        list->elements = (void**)realloc(list->elements, sizeof(void*) * list->capacity);");
        self.writeln("    }");
        self.writeln("    list->elements[list->length++] = element;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static int64_t lux_list_length(LuxList* list) { return list->length; }");
        self.writeln("static LuxBool lux_list_isEmpty(LuxList* list) { return list->length == 0; }");
        self.writeln("");
        self.writeln("static LuxList* lux_list_concat(LuxList* a, LuxList* b) {");
        self.writeln("    LuxList* result = lux_list_new(a->length + b->length);");
        self.writeln("    for (int64_t i = 0; i < a->length; i++) {");
        self.writeln("        lux_incref(a->elements[i]);");
        self.writeln("        result->elements[i] = a->elements[i];");
        self.writeln("    }");
        self.writeln("    for (int64_t i = 0; i < b->length; i++) {");
        self.writeln("        lux_incref(b->elements[i]);");
        self.writeln("        result->elements[a->length + i] = b->elements[i];");
        self.writeln("    }");
        self.writeln("    result->length = a->length + b->length;");
        self.writeln("    return result;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxList* lux_list_reverse(LuxList* list) {");
        self.writeln("    // FBIP: If rc=1, reverse in-place instead of copying");
        self.writeln("    if (LUX_RC_HEADER(list)->rc == 1) {");
        if self.debug_rc {
            self.writeln("        lux_fbip_reuse_count++;");
        }
        self.writeln("        // In-place reversal - just swap element pointers");
        self.writeln("        int64_t n = list->length;");
        self.writeln("        for (int64_t i = 0; i < n / 2; i++) {");
        self.writeln("            void* tmp = list->elements[i];");
        self.writeln("            list->elements[i] = list->elements[n - 1 - i];");
        self.writeln("            list->elements[n - 1 - i] = tmp;");
        self.writeln("        }");
        self.writeln("        return list;  // Reuse same list");
        self.writeln("    }");
        if self.debug_rc {
            self.writeln("    lux_fbip_copy_count++;");
        }
        self.writeln("    // rc > 1: Allocate new list (standard path)");
        self.writeln("    LuxList* result = lux_list_new(list->length);");
        self.writeln("    for (int64_t i = 0; i < list->length; i++) {");
        self.writeln("        lux_incref(list->elements[list->length - 1 - i]);");
        self.writeln("        result->elements[i] = list->elements[list->length - 1 - i];");
        self.writeln("    }");
        self.writeln("    result->length = list->length;");
        self.writeln("    return result;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxList* lux_list_take(LuxList* list, int64_t n) {");
        self.writeln("    if (n <= 0) return lux_list_new(0);");
        self.writeln("    if (n >= list->length) {");
        self.writeln("        lux_incref(list);  // Return same list");
        self.writeln("        return list;");
        self.writeln("    }");
        self.writeln("    // FBIP: If rc=1, truncate in-place");
        self.writeln("    if (LUX_RC_HEADER(list)->rc == 1) {");
        if self.debug_rc {
            self.writeln("        lux_fbip_reuse_count++;");
        }
        self.writeln("        // Decref elements we're dropping");
        self.writeln("        for (int64_t i = n; i < list->length; i++) {");
        self.writeln("            lux_decref(list->elements[i]);");
        self.writeln("        }");
        self.writeln("        list->length = n;");
        self.writeln("        return list;  // Reuse same list");
        self.writeln("    }");
        if self.debug_rc {
            self.writeln("    lux_fbip_copy_count++;");
        }
        self.writeln("    // rc > 1: Allocate new list");
        self.writeln("    LuxList* result = lux_list_new(n);");
        self.writeln("    for (int64_t i = 0; i < n; i++) {");
        self.writeln("        lux_incref(list->elements[i]);");
        self.writeln("        result->elements[i] = list->elements[i];");
        self.writeln("    }");
        self.writeln("    result->length = n;");
        self.writeln("    return result;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxList* lux_list_drop(LuxList* list, int64_t n) {");
        self.writeln("    if (n >= list->length) return lux_list_new(0);");
        self.writeln("    if (n <= 0) {");
        self.writeln("        lux_incref(list);  // Return same list with bumped refcount");
        self.writeln("        return list;");
        self.writeln("    }");
        self.writeln("    int64_t new_len = list->length - n;");
        self.writeln("    // FBIP: If rc=1, shift elements in-place");
        self.writeln("    if (LUX_RC_HEADER(list)->rc == 1) {");
        if self.debug_rc {
            self.writeln("        lux_fbip_reuse_count++;");
        }
        self.writeln("        // Decref elements we're dropping");
        self.writeln("        for (int64_t i = 0; i < n; i++) {");
        self.writeln("            lux_decref(list->elements[i]);");
        self.writeln("        }");
        self.writeln("        // Shift remaining elements to front");
        self.writeln("        for (int64_t i = 0; i < new_len; i++) {");
        self.writeln("            list->elements[i] = list->elements[n + i];");
        self.writeln("        }");
        self.writeln("        list->length = new_len;");
        self.writeln("        return list;  // Reuse same list");
        self.writeln("    }");
        if self.debug_rc {
            self.writeln("    lux_fbip_copy_count++;");
        }
        self.writeln("    // rc > 1: Allocate new list");
        self.writeln("    LuxList* result = lux_list_new(new_len);");
        self.writeln("    for (int64_t i = 0; i < new_len; i++) {");
        self.writeln("        lux_incref(list->elements[n + i]);");
        self.writeln("        result->elements[i] = list->elements[n + i];");
        self.writeln("    }");
        self.writeln("    result->length = new_len;");
        self.writeln("    return result;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static LuxList* lux_list_range(int64_t start, int64_t end) {");
        self.writeln("    if (end <= start) return lux_list_new(0);");
        self.writeln("    int64_t len = end - start;");
        self.writeln("    LuxList* result = lux_list_new(len);");
        self.writeln("    for (int64_t i = 0; i < len; i++) {");
        self.writeln("        LuxInt* p = (LuxInt*)lux_rc_alloc(sizeof(LuxInt), LUX_TAG_BOXED_INT);");
        self.writeln("        *p = start + i;");
        self.writeln("        result->elements[i] = p;");
        self.writeln("    }");
        self.writeln("    result->length = len;");
        self.writeln("    return result;");
        self.writeln("}");
        self.writeln("");
        self.writeln("static Option lux_option_none(void) { return (Option){Option_TAG_NONE}; }");
        self.writeln("static Option lux_option_some(void* value) { return (Option){Option_TAG_SOME, .data.some = {value}}; }");
        self.writeln("");
        self.writeln("// === Boxing/Unboxing ===");
        self.writeln("// All boxed values are RC-managed.");
        self.writeln("");
        self.writeln("static void* lux_box_int(LuxInt n) {");
        self.writeln("    LuxInt* p = (LuxInt*)lux_rc_alloc(sizeof(LuxInt), LUX_TAG_BOXED_INT);");
        self.writeln("    *p = n;");
        self.writeln("    return p;");
        self.writeln("}");
        self.writeln("static LuxInt lux_unbox_int(void* p) { return *(LuxInt*)p; }");
        self.writeln("");
        self.writeln("static void* lux_box_bool(LuxBool b) {");
        self.writeln("    LuxBool* p = (LuxBool*)lux_rc_alloc(sizeof(LuxBool), LUX_TAG_BOXED_BOOL);");
        self.writeln("    *p = b;");
        self.writeln("    return p;");
        self.writeln("}");
        self.writeln("static LuxBool lux_unbox_bool(void* p) { return *(LuxBool*)p; }");
        self.writeln("");
        self.writeln("static void* lux_box_float(LuxFloat f) {");
        self.writeln("    LuxFloat* p = (LuxFloat*)lux_rc_alloc(sizeof(LuxFloat), LUX_TAG_BOXED_FLOAT);");
        self.writeln("    *p = f;");
        self.writeln("    return p;");
        self.writeln("}");
        self.writeln("static LuxFloat lux_unbox_float(void* p) { return *(LuxFloat*)p; }");
        self.writeln("");
        self.writeln("static void* lux_box_string(LuxString s) {");
        self.writeln("    // Strings are already char*, so we allocate a new RC-managed string");
        self.writeln("    size_t len = strlen(s);");
        self.writeln("    LuxString p = (LuxString)lux_rc_alloc(len + 1, LUX_TAG_STRING);");
        self.writeln("    memcpy(p, s, len + 1);");
        self.writeln("    return p;");
        self.writeln("}");
        self.writeln("static LuxString lux_unbox_string(void* p) { return (LuxString)p; }");
        self.writeln("");
        self.writeln("// === Polymorphic Drop Function ===");
        self.writeln("// Called when an object's refcount reaches zero.");
        self.writeln("// Recursively decrefs any owned references before freeing.");
        self.writeln("");
        self.writeln("static void lux_drop(void* ptr, int32_t tag) {");
        self.writeln("    if (!ptr) return;");
        self.writeln("    switch (tag) {");
        self.writeln("        case LUX_TAG_STRING:");
        self.writeln("            // Strings are just char arrays, no sub-references");
        self.writeln("            break;");
        self.writeln("        case LUX_TAG_LIST: {");
        self.writeln("            LuxList* list = (LuxList*)ptr;");
        self.writeln("            // Decref each element (they're all boxed/RC-managed)");
        self.writeln("            for (int64_t i = 0; i < list->length; i++) {");
        self.writeln("                lux_decref(list->elements[i]);");
        self.writeln("            }");
        self.writeln("            free(list->elements);");
        self.writeln("            break;");
        self.writeln("        }");
        self.writeln("        case LUX_TAG_CLOSURE: {");
        self.writeln("            LuxClosure* closure = (LuxClosure*)ptr;");
        self.writeln("            // Decref the environment if it's RC-managed");
        self.writeln("            lux_decref(closure->env);");
        self.writeln("            break;");
        self.writeln("        }");
        self.writeln("        case LUX_TAG_BOXED_INT:");
        self.writeln("        case LUX_TAG_BOXED_BOOL:");
        self.writeln("        case LUX_TAG_BOXED_FLOAT:");
        self.writeln("            // Primitive boxes have no sub-references");
        self.writeln("            break;");
        self.writeln("        case LUX_TAG_ENV:");
        self.writeln("            // Environment structs may contain RC pointers");
        self.writeln("            // For now, just free - proper drop needs type info");
        self.writeln("            break;");
        self.writeln("        default:");
        self.writeln("            // ADT types (tag >= 100) - call generated drop function");
        self.writeln("            lux_drop_adt(ptr, tag);");
        self.writeln("            break;");
        self.writeln("    }");
        self.writeln("    // Free the object and its RC header");
        if self.debug_rc {
            self.writeln("    lux_rc_free_count++;");
        }
        self.writeln("    free(LUX_RC_HEADER(ptr));");
        self.writeln("}");
        self.writeln("");
        self.writeln("// === Forward Declarations ===");
        self.writeln("");
    }

    /// Emit specialized decref implementations (must be called after type definitions)
    fn emit_specialized_decref_implementations(&mut self) {
        self.writeln("// === Specialized Decref Implementations (Drop Specialization) ===");
        self.writeln("// These avoid the polymorphic lux_drop dispatch when type is known");
        self.writeln("");

        self.writeln("// Specialized decref for lists - inline drop logic");
        self.writeln("static inline void lux_decref_list(LuxList* list) {");
        self.writeln("    if (list) {");
        self.writeln("        LuxRcHeader* hdr = LUX_RC_HEADER(list);");
        self.writeln("        if (--hdr->rc == 0) {");
        self.writeln("            // Inline list drop - decref each element");
        self.writeln("            for (int64_t i = 0; i < list->length; i++) {");
        self.writeln("                lux_decref(list->elements[i]);");
        self.writeln("            }");
        self.writeln("            free(list->elements);");
        if self.debug_rc {
            self.writeln("            lux_rc_free_count++;");
        }
        self.writeln("            free(hdr);");
        self.writeln("        }");
        self.writeln("    }");
        self.writeln("}");
        self.writeln("");

        self.writeln("// Specialized decref for closures - inline drop logic");
        self.writeln("static inline void lux_decref_closure(LuxClosure* closure) {");
        self.writeln("    if (closure) {");
        self.writeln("        LuxRcHeader* hdr = LUX_RC_HEADER(closure);");
        self.writeln("        if (--hdr->rc == 0) {");
        self.writeln("            // Inline closure drop - decref environment");
        self.writeln("            lux_decref(closure->env);");
        if self.debug_rc {
            self.writeln("            lux_rc_free_count++;");
        }
        self.writeln("            free(hdr);");
        self.writeln("        }");
        self.writeln("    }");
        self.writeln("}");
        self.writeln("");

        self.writeln("// Specialized decref for strings - safe for both RC and static strings");
        self.writeln("static inline void lux_decref_string(LuxString str) {");
        self.writeln("    // Check magic number to distinguish RC-managed from static strings");
        self.writeln("    // Static string literals don't have our header, so we skip them");
        self.writeln("    if (LUX_IS_RC_MANAGED(str)) {");
        self.writeln("        LuxRcHeader* hdr = LUX_RC_HEADER(str);");
        self.writeln("        if (--hdr->rc == 0) {");
        if self.debug_rc {
            self.writeln("            lux_rc_free_count++;");
        }
        self.writeln("            free(hdr);");
        self.writeln("        }");
        self.writeln("    }");
        self.writeln("}");
        self.writeln("");

        self.writeln("// Specialized decref for boxed primitives - no sub-references");
        self.writeln("static inline void lux_decref_boxed(void* ptr) {");
        self.writeln("    if (ptr) {");
        self.writeln("        LuxRcHeader* hdr = LUX_RC_HEADER(ptr);");
        self.writeln("        if (--hdr->rc == 0) {");
        if self.debug_rc {
            self.writeln("            lux_rc_free_count++;");
        }
        self.writeln("            free(hdr);");
        self.writeln("        }");
        self.writeln("    }");
        self.writeln("}");
        self.writeln("");
    }

    fn collect_type(&mut self, _type_decl: &TypeDecl) -> Result<(), CGenError> {
        // Collect type info for later emission
        Ok(())
    }

    fn emit_type_definitions(&mut self, program: &Program) -> Result<(), CGenError> {
        for decl in &program.declarations {
            if let Declaration::Type(t) = decl {
                self.emit_type_def(t)?;
            }
        }
        Ok(())
    }

    /// Emit the lux_drop_adt function that handles dropping ADT types
    fn emit_adt_drop_function(&mut self) {
        self.writeln("// === ADT Drop Function ===");
        self.writeln("// Generated based on ADT type definitions.");
        self.writeln("static void lux_drop_adt(void* ptr, int32_t tag) {");
        self.indent += 1;

        if self.adt_with_pointers.is_empty() {
            // No ADTs with pointer fields - nothing to do
            self.writeln("// No ADTs with pointer fields");
            self.writeln("(void)ptr; (void)tag;  // Unused");
        } else {
            self.writeln("switch (tag) {");
            self.indent += 1;

            // Generate cases for each ADT type with pointer fields
            // Clone to avoid borrow issues
            let adt_tags = self.adt_type_tags.clone();
            let variant_field_types = self.variant_field_types.clone();

            for (adt_name, tag) in &adt_tags {
                if !self.adt_with_pointers.contains(adt_name) {
                    continue;
                }

                self.writeln(&format!("case {}: {{", tag));
                self.indent += 1;
                self.writeln(&format!("{}* adt = ({}*)ptr;", adt_name, adt_name));

                // Find all variants of this ADT and their pointer fields
                let mut variant_cases: Vec<(String, Vec<(usize, String)>)> = Vec::new();
                for ((type_name, variant_name), field_types) in &variant_field_types {
                    if type_name != adt_name {
                        continue;
                    }
                    let pointer_fields: Vec<(usize, String)> = field_types.iter()
                        .enumerate()
                        .filter(|(_, t)| t.ends_with('*'))
                        .map(|(i, t)| (i, t.clone()))
                        .collect();
                    if !pointer_fields.is_empty() {
                        variant_cases.push((variant_name.clone(), pointer_fields));
                    }
                }

                if !variant_cases.is_empty() {
                    self.writeln("switch (adt->tag) {");
                    self.indent += 1;

                    for (variant_name, pointer_fields) in &variant_cases {
                        let variant_upper = variant_name.to_uppercase();
                        let variant_lower = variant_name.to_lowercase();
                        self.writeln(&format!("case {}_TAG_{}: {{", adt_name, variant_upper));
                        self.indent += 1;
                        for (field_idx, _field_type) in pointer_fields {
                            self.writeln(&format!("lux_decref(adt->data.{}.field{});", variant_lower, field_idx));
                        }
                        self.writeln("break;");
                        self.indent -= 1;
                        self.writeln("}");
                    }

                    self.writeln("default: break;");
                    self.indent -= 1;
                    self.writeln("}");
                }

                self.writeln("break;");
                self.indent -= 1;
                self.writeln("}");
            }

            self.writeln("default: break;");
            self.indent -= 1;
            self.writeln("}");
        }

        self.indent -= 1;
        self.writeln("}");
        self.writeln("");
    }

    fn emit_type_def(&mut self, type_decl: &TypeDecl) -> Result<(), CGenError> {
        let name = &type_decl.name.name;

        if self.types_emitted.contains(name) {
            return Ok(());
        }
        self.types_emitted.insert(name.clone());

        match &type_decl.definition {
            TypeDef::Record(fields) => {
                self.writeln(&format!("typedef struct {} {{", name));
                self.indent += 1;
                for field in fields {
                    let c_type = self.type_to_c(&field.typ)?;
                    self.writeln(&format!("{} {};", c_type, field.name.name));
                }
                self.indent -= 1;
                self.writeln(&format!("}} {};", name));
                self.writeln("");
            }
            TypeDef::Enum(variants) => {
                // Record variant -> type mapping for pattern matching
                for variant in variants {
                    self.variant_to_type.insert(variant.name.name.clone(), name.clone());

                    // Also record field types for pattern binding type inference
                    // Use self-check for recursive types (which become pointers)
                    let field_types: Vec<String> = match &variant.fields {
                        VariantFields::Tuple(fields) => {
                            fields.iter().map(|f| {
                                self.type_to_c_with_self_check(f, name).unwrap_or_else(|_| "LuxInt".to_string())
                            }).collect()
                        }
                        VariantFields::Record(fields) => {
                            fields.iter().map(|f| {
                                self.type_to_c_with_self_check(&f.typ, name).unwrap_or_else(|_| "LuxInt".to_string())
                            }).collect()
                        }
                        VariantFields::Unit => vec![],
                    };
                    // Track if this variant has pointer fields
                    let has_pointers = field_types.iter().any(|t| t.ends_with('*'));
                    if has_pointers {
                        self.adt_with_pointers.insert(name.clone());
                    }

                    self.variant_field_types.insert(
                        (name.clone(), variant.name.name.clone()),
                        field_types
                    );
                }

                // Assign a type tag to this ADT
                if !self.adt_type_tags.contains_key(name) {
                    let tag = self.next_adt_tag;
                    self.adt_type_tags.insert(name.clone(), tag);
                    self.next_adt_tag += 1;
                }

                // Forward declare the main struct for recursive types
                self.writeln(&format!("struct {};", name));
                self.writeln(&format!("typedef struct {} {};", name, name));
                self.writeln("");

                // Emit tag enum
                self.writeln(&format!("typedef enum {}_Tag {{", name));
                self.indent += 1;
                for (i, variant) in variants.iter().enumerate() {
                    let comma = if i < variants.len() - 1 { "," } else { "" };
                    self.writeln(&format!("{}_TAG_{}{}", name, variant.name.name.to_uppercase(), comma));
                }
                self.indent -= 1;
                self.writeln(&format!("}} {}_Tag;", name));
                self.writeln("");

                // Emit variant structs
                for variant in variants {
                    let has_fields = !matches!(&variant.fields, VariantFields::Unit);
                    if has_fields {
                        self.writeln(&format!("typedef struct {}_{}_Data {{", name, variant.name.name));
                        self.indent += 1;
                        match &variant.fields {
                            VariantFields::Tuple(fields) => {
                                for (i, field) in fields.iter().enumerate() {
                                    let c_type = self.type_to_c_with_self_check(field, name)?;
                                    self.writeln(&format!("{} field{};", c_type, i));
                                }
                            }
                            VariantFields::Record(fields) => {
                                for field in fields {
                                    let c_type = self.type_to_c_with_self_check(&field.typ, name)?;
                                    self.writeln(&format!("{} {};", c_type, field.name.name));
                                }
                            }
                            VariantFields::Unit => {}
                        }
                        self.indent -= 1;
                        self.writeln(&format!("}} {}_{}_Data;", name, variant.name.name));
                        self.writeln("");
                    }
                }

                // Emit main union struct (typedef already created above)
                self.writeln(&format!("struct {} {{", name));
                self.indent += 1;
                self.writeln(&format!("{}_Tag tag;", name));
                self.writeln("union {");
                self.indent += 1;
                for variant in variants {
                    let has_fields = !matches!(&variant.fields, VariantFields::Unit);
                    if has_fields {
                        self.writeln(&format!("{}_{}_Data {};", name, variant.name.name, variant.name.name.to_lowercase()));
                    }
                }
                self.indent -= 1;
                self.writeln("} data;");
                self.indent -= 1;
                self.writeln("};");
                self.writeln("");
            }
            TypeDef::Alias(_) => {
                // Type aliases are handled during type resolution
            }
        }
        Ok(())
    }

    fn mangle_name(&self, name: &str) -> String {
        // Add suffix to avoid conflicts with C keywords and standard library
        format!("{}_lux", name)
    }

    /// Escape C reserved keywords by adding underscore prefix
    fn escape_c_keyword(&self, name: &str) -> String {
        // C reserved keywords that might conflict with Lux variable names
        const C_KEYWORDS: &[&str] = &[
            // C89/C90 keywords
            "auto", "break", "case", "char", "const", "continue", "default",
            "do", "double", "else", "enum", "extern", "float", "for", "goto",
            "if", "int", "long", "register", "return", "short", "signed",
            "sizeof", "static", "struct", "switch", "typedef", "union",
            "unsigned", "void", "volatile", "while",
            // C99 keywords
            "inline", "restrict", "_Bool", "_Complex", "_Imaginary",
            // C11 keywords
            "_Alignas", "_Alignof", "_Atomic", "_Generic", "_Noreturn",
            "_Static_assert", "_Thread_local",
            // Common type aliases and macros that might conflict
            "bool", "true", "false", "NULL",
            // Standard library identifiers that might conflict
            "stdin", "stdout", "stderr", "errno", "main",
        ];

        if C_KEYWORDS.contains(&name) {
            format!("_{}", name)
        } else {
            name.to_string()
        }
    }

    /// Check if an expression is a string expression (for concatenation detection)
    fn is_string_expr(&self, expr: &Expr) -> bool {
        match expr {
            // String literals
            Expr::Literal(lit) => matches!(lit.kind, LiteralKind::String(_)),

            // Variables - check if we know their type
            Expr::Var(ident) => {
                let escaped = self.escape_c_keyword(&ident.name);
                self.var_types.get(&escaped).map(|t| t == "LuxString").unwrap_or(false)
            }

            // toString function call or other string-returning functions
            Expr::Call { func, .. } => {
                if let Expr::Var(ident) = func.as_ref() {
                    if ident.name == "toString" {
                        return true;
                    }
                    // Check function return type
                    if let Some(ret_type) = self.function_return_types.get(&ident.name) {
                        return ret_type == "LuxString";
                    }
                }
                false
            }

            // String concatenation with +
            Expr::BinaryOp { op, left, right, .. } => {
                matches!(op, BinaryOp::Add)
                    && (self.is_string_expr(left) || self.is_string_expr(right))
            }

            // Effect operations that return strings
            Expr::EffectOp { effect, operation, .. } => {
                match (effect.name.as_str(), operation.name.as_str()) {
                    ("Process", "exec") | ("Process", "cwd") => true,
                    ("Console", "readLine") => true,
                    ("File", "read") => true,
                    ("Http", "get") | ("Http", "post") | ("Http", "put") | ("Http", "delete") => true,
                    ("String", "trim") => true,
                    _ => false,
                }
            }

            // Field access on String module
            Expr::Field { object, field, .. } => {
                if let Expr::Var(module) = object.as_ref() {
                    module.name == "String" && matches!(field.name.as_str(), "trim")
                } else {
                    false
                }
            }

            _ => false,
        }
    }

    fn emit_forward_declarations(&mut self, program: &Program) -> Result<(), CGenError> {
        for decl in &program.declarations {
            if let Declaration::Function(f) = decl {
                let ret_type = self.type_expr_to_c(&f.return_type)?;
                let params = self.emit_params(&f.params)?;
                let mangled = self.mangle_name(&f.name.name);

                // Add evidence parameter for effectful functions
                let full_params = if !f.effects.is_empty() {
                    if params == "void" {
                        "LuxEvidence* ev".to_string()
                    } else {
                        format!("LuxEvidence* ev, {}", params)
                    }
                } else {
                    params
                };

                self.writeln(&format!("{} {}({});", ret_type, mangled, full_params));
            }
        }
        self.writeln("");
        Ok(())
    }

    fn emit_function(&mut self, func: &FunctionDecl) -> Result<(), CGenError> {
        let ret_type = self.type_expr_to_c(&func.return_type)?;
        let params = self.emit_params(&func.params)?;
        let mangled = self.mangle_name(&func.name.name);

        // Check if this function uses effects (needs evidence parameter)
        let is_effectful = !func.effects.is_empty();

        // Build parameter list with evidence if needed
        let full_params = if is_effectful {
            if params == "void" {
                "LuxEvidence* ev".to_string()
            } else {
                format!("LuxEvidence* ev, {}", params)
            }
        } else {
            params.clone()
        };

        // Check for behavioral optimizations
        let behavior = self.function_behaviors.get(&func.name.name).cloned();
        let use_memoization = self.enable_behavioral_optimizations
            && behavior.as_ref().map_or(false, |b| b.is_pure)
            && !func.params.is_empty()
            && ret_type != "void"
            && ret_type != "LuxUnit";

        let use_idempotent = self.enable_behavioral_optimizations
            && behavior.as_ref().map_or(false, |b| b.is_idempotent && !b.is_pure)
            && ret_type != "void"
            && ret_type != "LuxUnit";

        let use_commutative = self.enable_behavioral_optimizations
            && behavior.as_ref().map_or(false, |b| b.is_commutative)
            && func.params.len() == 2;

        let is_deterministic = behavior.as_ref().map_or(false, |b| b.is_deterministic);

        self.writeln(&format!("{} {}({}) {{", ret_type, mangled, full_params));
        self.indent += 1;

        // Emit deterministic attribute hint
        if is_deterministic {
            self.emit_deterministic_attribute(&func.name.name);
        }

        // Emit commutative optimization (normalize argument order for better CSE)
        if use_commutative {
            self.emit_commutative_optimization(&func.name.name, &func.params)?;
        }

        // Emit memoization check for pure functions
        if use_memoization {
            self.emit_memoization_lookup(&func.name.name, &func.params, &ret_type)?;
        }

        // Emit idempotent check (for non-pure idempotent functions)
        if use_idempotent {
            self.emit_idempotent_check(&func.name.name, &func.params, &ret_type)?;
        }

        // Set evidence availability for expression generation
        let prev_has_evidence = self.has_evidence;
        if is_effectful {
            self.has_evidence = true;
        }

        // Push function scope for RC tracking
        self.push_rc_scope();

        // Emit function body
        let result = self.emit_expr(&func.body)?;

        // Restore previous evidence state
        self.has_evidence = prev_has_evidence;

        // For non-void functions, we need to save result, decref locals, then return
        if ret_type != "void" && ret_type != "LuxUnit" {
            // Check if result is a local RC variable we should skip decref'ing
            let skip_var = if let Expr::Var(ident) = &func.body {
                if self.is_var_in_current_rc_scope(&ident.name) {
                    Some(ident.name.clone())
                } else {
                    None
                }
            } else if let Expr::Block { result: block_result, .. } = &func.body {
                // For blocks, check if the result expression is a var in scope
                if let Expr::Var(ident) = block_result.as_ref() {
                    if self.is_var_in_current_rc_scope(&ident.name) {
                        Some(ident.name.clone())
                    } else {
                        None
                    }
                } else {
                    None
                }
            } else {
                None
            };

            // Also check if result is an RC temp (like _str_concat_N) that we should skip
            let skip_var = skip_var.or_else(|| {
                if self.is_rc_temp(&result) {
                    Some(result.clone())
                } else {
                    None
                }
            });

            // Check if result is an RC type that we need to keep alive
            let is_rc_result = self.is_rc_type(&ret_type);
            let has_rc_locals = !self.rc_scopes.last().map_or(true, |s| s.is_empty());

            if let Some(ref var_name) = skip_var {
                // Result is a local variable or RC temp - skip decref'ing it and just return
                self.pop_rc_scope_except(Some(var_name));
                if use_memoization {
                    self.emit_memoization_store(&func.name.name, &func.params, &result)?;
                }
                if use_idempotent {
                    self.emit_idempotent_store(&func.name.name, &func.params, &result)?;
                }
                self.writeln(&format!("return {};", result));
            } else if is_rc_result && has_rc_locals {
                // Result is from a call or complex expression - use incref/decref pattern
                self.writeln(&format!("{} _result = {};", ret_type, result));
                self.writeln("lux_incref(_result);");
                self.pop_rc_scope();  // Emit decrefs for all local RC vars
                self.writeln("lux_decref(_result);  // Balance the incref");
                if use_memoization {
                    self.emit_memoization_store(&func.name.name, &func.params, "_result")?;
                }
                if use_idempotent {
                    self.emit_idempotent_store(&func.name.name, &func.params, "_result")?;
                }
                self.writeln("return _result;");
            } else {
                // No RC locals or non-RC result - simple cleanup
                self.pop_rc_scope();
                if use_memoization {
                    self.emit_memoization_store(&func.name.name, &func.params, &result)?;
                }
                if use_idempotent {
                    self.emit_idempotent_store(&func.name.name, &func.params, &result)?;
                }
                self.writeln(&format!("return {};", result));
            }
        } else {
            // Void function - just cleanup
            self.pop_rc_scope();
        }

        self.indent -= 1;
        self.writeln("}");
        self.writeln("");
        Ok(())
    }

    fn emit_params(&self, params: &[Parameter]) -> Result<String, CGenError> {
        if params.is_empty() {
            return Ok("void".to_string());
        }

        let param_strs: Result<Vec<_>, _> = params.iter().map(|p| {
            let c_type = self.type_expr_to_c(&p.typ)?;
            let escaped_name = self.escape_c_keyword(&p.name.name);
            Ok(format!("{} {}", c_type, escaped_name))
        }).collect();

        Ok(param_strs?.join(", "))
    }

    fn emit_expr(&mut self, expr: &Expr) -> Result<String, CGenError> {
        match expr {
            Expr::Literal(lit) => self.emit_literal(lit),

            Expr::Var(ident) => {
                // Check if this is a unit constructor (no-argument variant)
                if let Some(type_name) = self.variant_to_type.get(&ident.name) {
                    // This is a constructor - emit struct literal
                    let variant_name = &ident.name;
                    Ok(format!("({}){{{}_TAG_{}}}", type_name, type_name, variant_name.to_uppercase()))
                } else {
                    // Escape C reserved keywords
                    Ok(self.escape_c_keyword(&ident.name))
                }
            }

            Expr::BinaryOp { op, left, right, .. } => {
                // Check if args are function calls returning String - need to track for cleanup
                let left_is_string_call = if let Expr::Call { func, .. } = left.as_ref() {
                    if let Expr::Var(ident) = func.as_ref() {
                        self.function_return_types.get(&ident.name)
                            .map(|t| t == "LuxString")
                            .unwrap_or(false)
                    } else { false }
                } else { false };

                let right_is_string_call = if let Expr::Call { func, .. } = right.as_ref() {
                    if let Expr::Var(ident) = func.as_ref() {
                        self.function_return_types.get(&ident.name)
                            .map(|t| t == "LuxString")
                            .unwrap_or(false)
                    } else { false }
                } else { false };

                let l = self.emit_expr(left)?;
                let r = self.emit_expr(right)?;

                // Check for string concatenation
                if matches!(op, BinaryOp::Add) {
                    let left_is_string = self.is_string_expr(left);
                    let right_is_string = self.is_string_expr(right);
                    if left_is_string || right_is_string {
                        // If args are function calls returning String, store in temp for cleanup
                        let (actual_l, l_temp) = if left_is_string_call && !self.is_rc_temp(&l) {
                            let temp = format!("_concat_arg_{}", self.fresh_name());
                            self.writeln(&format!("LuxString {} = {};", temp, l));
                            (temp.clone(), Some(temp))
                        } else {
                            (l.clone(), None)
                        };

                        let (actual_r, r_temp) = if right_is_string_call && !self.is_rc_temp(&r) {
                            let temp = format!("_concat_arg_{}", self.fresh_name());
                            self.writeln(&format!("LuxString {} = {};", temp, r));
                            (temp.clone(), Some(temp))
                        } else {
                            (r.clone(), None)
                        };

                        // String concat returns RC-managed string - track it
                        let temp = format!("_str_concat_{}", self.fresh_name());
                        self.writeln(&format!("LuxString {} = lux_string_concat({}, {});", temp, actual_l, actual_r));
                        self.register_rc_var(&temp, "LuxString");

                        // Decref any temporary strings used as inputs
                        // Now safe for both RC-managed and static strings due to magic check
                        if self.is_rc_temp(&l) {
                            self.writeln(&format!("lux_decref_string({});", l));
                            self.unregister_rc_var(&l);
                        } else if let Some(ref temp_l) = l_temp {
                            self.writeln(&format!("lux_decref_string({});", temp_l));
                        }
                        if self.is_rc_temp(&r) {
                            self.writeln(&format!("lux_decref_string({});", r));
                            self.unregister_rc_var(&r);
                        } else if let Some(ref temp_r) = r_temp {
                            self.writeln(&format!("lux_decref_string({});", temp_r));
                        }
                        return Ok(temp);
                    }
                }

                // Check for string comparison - use strcmp instead of pointer comparison
                if matches!(op, BinaryOp::Eq | BinaryOp::Ne) {
                    let left_is_string = self.is_string_expr(left);
                    let right_is_string = self.is_string_expr(right);
                    if left_is_string || right_is_string {
                        if matches!(op, BinaryOp::Eq) {
                            return Ok(format!("(strcmp({}, {}) == 0)", l, r));
                        } else {
                            return Ok(format!("(strcmp({}, {}) != 0)", l, r));
                        }
                    }
                }

                let op_str = match op {
                    BinaryOp::Add => "+",
                    BinaryOp::Sub => "-",
                    BinaryOp::Mul => "*",
                    BinaryOp::Div => "/",
                    BinaryOp::Mod => "%",
                    BinaryOp::Eq => "==",
                    BinaryOp::Ne => "!=",
                    BinaryOp::Lt => "<",
                    BinaryOp::Le => "<=",
                    BinaryOp::Gt => ">",
                    BinaryOp::Ge => ">=",
                    BinaryOp::And => "&&",
                    BinaryOp::Or => "||",
                    BinaryOp::Pipe => {
                        // Pipe operator - for now, just call the right side with left as argument
                        return Ok(format!("{}({})", r, l));
                    }
                };

                Ok(format!("({} {} {})", l, op_str, r))
            }

            Expr::UnaryOp { op, operand, .. } => {
                let val = self.emit_expr(operand)?;
                let op_str = match op {
                    UnaryOp::Neg => "-",
                    UnaryOp::Not => "!",
                };
                Ok(format!("({}{})", op_str, val))
            }

            Expr::If { condition, then_branch, else_branch, .. } => {
                // Check if this is a void/Unit-returning if (for side effects only)
                let then_type = self.infer_expr_type(then_branch);
                let else_type = self.infer_expr_type(else_branch);
                let is_void = then_type.as_ref().map(|t| t == "void").unwrap_or(false)
                    || else_type.as_ref().map(|t| t == "void").unwrap_or(false)
                    || matches!(else_branch.as_ref(), Expr::Literal(lit) if matches!(lit.kind, LiteralKind::Unit));

                if is_void {
                    // Void/Unit-returning if - emit as simple if statement
                    let cond = self.emit_expr(condition)?;
                    self.writeln(&format!("if ({}) {{", cond));
                    self.indent += 1;
                    let then_val = self.emit_expr(then_branch)?;
                    // Only emit if it's not just a Unit literal
                    if then_val != "0" && !then_val.is_empty() {
                        self.writeln(&format!("{};", then_val));
                    }
                    self.indent -= 1;

                    // Check if else branch is a Unit literal (meaning no else was provided)
                    let is_missing_else = matches!(else_branch.as_ref(), Expr::Literal(lit) if matches!(lit.kind, LiteralKind::Unit));
                    if !is_missing_else {
                        self.writeln("} else {");
                        self.indent += 1;
                        let else_val = self.emit_expr(else_branch)?;
                        if else_val != "0" && !else_val.is_empty() {
                            self.writeln(&format!("{};", else_val));
                        }
                        self.indent -= 1;
                    }
                    self.writeln("}");
                    Ok("0".to_string()) // Return dummy value for void expression
                } else {
                    // Check if branches create RC values - if so, use if-statement to avoid
                    // allocating both when only one is needed
                    let then_creates_rc = self.expr_creates_rc_value(then_branch);
                    let else_creates_rc = self.expr_creates_rc_value(else_branch);

                    if then_creates_rc || else_creates_rc {
                        // Use if-statement pattern to avoid allocating unused branch
                        let result_type = self.infer_expr_type(then_branch)
                            .or_else(|| self.infer_expr_type(else_branch))
                            .unwrap_or_else(|| "LuxInt".to_string());
                        let result_var = format!("_if_result_{}", self.fresh_name());

                        // Declare result variable
                        self.writeln(&format!("{} {};", result_type, result_var));

                        // Emit condition
                        let cond = self.emit_expr(condition)?;
                        self.writeln(&format!("if ({}) {{", cond));
                        self.indent += 1;

                        // Emit then branch
                        let then_val = self.emit_expr(then_branch)?;
                        self.writeln(&format!("{} = {};", result_var, then_val));
                        self.indent -= 1;
                        self.writeln("} else {");
                        self.indent += 1;

                        // Emit else branch
                        let else_val = self.emit_expr(else_branch)?;
                        self.writeln(&format!("{} = {};", result_var, else_val));
                        self.indent -= 1;
                        self.writeln("}");

                        Ok(result_var)
                    } else {
                        // Simple ternary for non-RC values
                        let cond = self.emit_expr(condition)?;
                        let then_val = self.emit_expr(then_branch)?;
                        let else_val = self.emit_expr(else_branch)?;
                        Ok(format!("({} ? {} : {})", cond, then_val, else_val))
                    }
                }
            }

            Expr::Let { name, value, body, .. } => {
                let val = self.emit_expr(value)?;

                // Handle underscore pattern - just evaluate the expression, discard result
                if name.name == "_" {
                    // Just emit the expression for its side effects
                    self.writeln(&format!("(void){};", val));
                    // Continue with body
                    let body_result = self.emit_expr(body)?;
                    return Ok(body_result);
                }

                let var_name = format!("{}_{}", name.name, self.fresh_name());

                // Infer the type from the value expression
                let var_type = self.infer_expr_type(value).unwrap_or_else(|| "LuxInt".to_string());

                self.writeln(&format!("{} {} = {};", var_type, var_name, val));

                // Substitute the name in the body
                // For now, assume the variable is directly usable
                let body_result = self.emit_expr_with_substitution(body, &name.name, &var_name)?;
                Ok(body_result)
            }

            Expr::Call { func, args, .. } => {
                // Check for List module calls first (List.map, List.filter, etc.)
                if let Expr::Field { object, field, .. } = func.as_ref() {
                    if let Expr::Var(module_name) = object.as_ref() {
                        if module_name.name == "List" {
                            return self.emit_list_operation(&field.name, args);
                        }
                    }
                }

                // Check for built-in functions like toString
                if let Expr::Var(ident) = func.as_ref() {
                    if ident.name == "toString" {
                        // toString converts Int to String - returns RC-managed string
                        let arg = self.emit_expr(&args[0])?;
                        let temp = format!("_to_string_{}", self.fresh_name());
                        self.writeln(&format!("LuxString {} = lux_int_to_string({});", temp, arg));
                        self.register_rc_var(&temp, "LuxString");
                        return Ok(temp);
                    }
                }

                let arg_strs: Result<Vec<_>, _> = args.iter().map(|a| self.emit_expr(a)).collect();
                let args_str = arg_strs?.join(", ");

                match func.as_ref() {
                    Expr::Var(ident) if self.functions.contains(&ident.name) => {
                        // Direct call to a known function
                        let c_func_name = self.mangle_name(&ident.name);
                        // Pass evidence if this function uses effects and we have evidence
                        let is_effectful = self.effectful_functions.contains(&ident.name);
                        let call_expr = if is_effectful && self.has_evidence {
                            if args_str.is_empty() {
                                format!("{}(ev)", c_func_name)
                            } else {
                                format!("{}(ev, {})", c_func_name, args_str)
                            }
                        } else if is_effectful {
                            // Calling effectful function but don't have evidence - use default
                            if args_str.is_empty() {
                                format!("{}(&default_evidence)", c_func_name)
                            } else {
                                format!("{}(&default_evidence, {})", c_func_name, args_str)
                            }
                        } else {
                            format!("{}({})", c_func_name, args_str)
                        };

                        Ok(call_expr)
                    }
                    Expr::Var(ident) if self.variant_to_type.contains_key(&ident.name) => {
                        // ADT constructor call - create struct with tag and data
                        let type_name = self.variant_to_type.get(&ident.name).unwrap().clone();
                        let variant_name = ident.name.clone();
                        let variant_lower = variant_name.to_lowercase();
                        let variant_upper = variant_name.to_uppercase();

                        // Look up field types to handle pointer fields
                        let field_types = self.variant_field_types
                            .get(&(type_name.clone(), variant_name.clone()))
                            .cloned()
                            .unwrap_or_default();

                        // Generate struct initialization
                        let arg_values: Result<Vec<_>, _> = args.iter().map(|a| self.emit_expr(a)).collect();
                        let arg_values = arg_values?;

                        // Build field initializers, handling pointer fields
                        // Clone adt_type_tags to avoid borrow issues
                        let adt_tags = self.adt_type_tags.clone();
                        let field_inits: Vec<String> = arg_values.iter()
                            .enumerate()
                            .map(|(i, v)| {
                                let field_type = field_types.get(i).map(|s| s.as_str()).unwrap_or("LuxInt");
                                if field_type.ends_with('*') {
                                    // Pointer field - allocate with RC and copy
                                    let base_type = &field_type[..field_type.len()-1];
                                    // Look up type tag for this ADT (default to 100 if not found)
                                    let type_tag = adt_tags.get(base_type).copied().unwrap_or(100);
                                    format!(".field{} = ({}*)memcpy(lux_rc_alloc(sizeof({}), {}), &({}), sizeof({}))",
                                        i, base_type, base_type, type_tag, v, base_type)
                                } else {
                                    format!(".field{} = {}", i, v)
                                }
                            })
                            .collect();

                        if field_inits.is_empty() {
                            // Unit variant
                            Ok(format!("({}){{{}_TAG_{}}}", type_name, type_name, variant_upper))
                        } else {
                            // Variant with data
                            Ok(format!("({}){{{}_TAG_{}, .data.{} = {{{}}}}}",
                                type_name, type_name, variant_upper,
                                variant_lower, field_inits.join(", ")))
                        }
                    }
                    _ => {
                        // Indirect call - treat as closure
                        let closure_expr = self.emit_expr(func)?;
                        // Build the cast for the function pointer
                        // For now, assume all args are LuxInt and return LuxInt
                        let param_types: Vec<&str> = args.iter().map(|_| "LuxInt").collect();
                        let params_str = if param_types.is_empty() {
                            String::new()
                        } else {
                            format!(", {}", param_types.join(", "))
                        };
                        let args_with_env = if args_str.is_empty() {
                            format!("({})->env", closure_expr)
                        } else {
                            format!("({})->env, {}", closure_expr, args_str)
                        };
                        Ok(format!("((LuxInt(*)(void*{}))({})->fn_ptr)({})",
                            params_str, closure_expr, args_with_env))
                    }
                }
            }

            Expr::Lambda { params, body, return_type, .. } => {
                // Find free variables in the lambda body
                let param_names: HashSet<String> = params.iter()
                    .map(|p| p.name.name.clone())
                    .collect();
                let free_vars = self.find_free_vars(body, &param_names);

                // Generate unique closure ID
                let id = self.fresh_name();

                // Determine parameter types (escape C keywords)
                let param_pairs: Vec<(String, String)> = params.iter()
                    .map(|p| {
                        let typ = self.type_expr_to_c(&p.typ)
                            .unwrap_or_else(|_| "LuxInt".to_string());
                        (self.escape_c_keyword(&p.name.name), typ)
                    })
                    .collect();

                // Determine return type (default to LuxInt)
                let ret_type = return_type.as_ref()
                    .map(|t| self.type_expr_to_c(t).unwrap_or_else(|_| "LuxInt".to_string()))
                    .unwrap_or_else(|| "LuxInt".to_string());

                // Determine captured variable types (default to LuxInt for now, escape C keywords)
                let env_fields: Vec<(String, String)> = free_vars.iter()
                    .map(|v| (self.escape_c_keyword(v), "LuxInt".to_string()))
                    .collect();

                // Store closure info for later emission
                self.closures.push(ClosureInfo {
                    id,
                    env_fields: env_fields.clone(),
                    params: param_pairs,
                    return_type: ret_type,
                    body: (**body).clone(),
                });

                // Generate code to create the closure at runtime
                let temp_env = format!("_env_{}", id);
                let temp_closure = format!("_closure_{}", id);

                // Allocate and initialize environment struct (RC-managed)
                if env_fields.is_empty() {
                    self.writeln(&format!("LuxClosure* {} = lux_rc_alloc(sizeof(LuxClosure), LUX_TAG_CLOSURE);", temp_closure));
                    self.writeln(&format!("{}->env = NULL;", temp_closure));
                } else {
                    // Allocate RC-managed environment
                    self.writeln(&format!("LuxEnv_{}* {} = lux_rc_alloc(sizeof(LuxEnv_{}), LUX_TAG_ENV);", id, temp_env, id));
                    for (name, _) in &env_fields {
                        self.writeln(&format!("{}->{} = {};", temp_env, name, name));
                    }
                    // Allocate RC-managed closure
                    self.writeln(&format!("LuxClosure* {} = lux_rc_alloc(sizeof(LuxClosure), LUX_TAG_CLOSURE);", temp_closure));
                    self.writeln(&format!("{}->env = {};", temp_closure, temp_env));
                }
                self.writeln(&format!("{}->fn_ptr = (void*)lambda_{};", temp_closure, id));

                Ok(temp_closure)
            }

            Expr::Block { statements, result, .. } => {
                // Push a scope for this block's local variables
                self.push_rc_scope();

                for stmt in statements {
                    match stmt {
                        Statement::Let { name, value, .. } => {
                            // Handle underscore pattern - just evaluate the expression, discard result
                            if name.name == "_" {
                                let val = self.emit_expr(value)?;
                                // Just evaluate for side effects, don't store
                                if !val.is_empty() && !val.starts_with("(void)") {
                                    self.writeln(&format!("(void){};", val));
                                }
                                continue;
                            }

                            // First, infer type from value expression (before emitting)
                            let inferred_type = self.infer_expr_type(value);

                            // Check for ownership transfer: assigning from another variable
                            let source_var = if let Expr::Var(ident) = value {
                                let escaped_source = self.escape_c_keyword(&ident.name);
                                // Check if source is an RC-tracked variable
                                if self.is_rc_tracked(&escaped_source) {
                                    Some(escaped_source)
                                } else {
                                    None
                                }
                            } else {
                                None
                            };

                            let val = self.emit_expr(value)?;

                            // Determine final type
                            let typ = if let Some(t) = inferred_type {
                                t
                            } else if val.starts_with("_closure_") || self.is_closure_returning_call(value) {
                                "LuxClosure*".to_string()
                            } else {
                                "LuxInt".to_string()
                            };
                            let escaped_name = self.escape_c_keyword(&name.name);
                            self.writeln(&format!("{} {} = {};", typ, escaped_name, val));

                            // Record variable type for future inference
                            self.var_types.insert(escaped_name.clone(), typ.clone());

                            // Handle ownership transfer or RC registration
                            if let Some(source_name) = source_var {
                                // Ownership transfer: unregister source, register dest
                                self.unregister_rc_var(&source_name);
                                self.register_rc_var(&escaped_name, &typ);
                            } else if self.is_rc_temp(&val) {
                                // Value is already an RC temp - transfer ownership to bound variable
                                self.unregister_rc_var(&val);
                                self.register_rc_var(&escaped_name, &typ);
                            } else if self.expr_creates_rc_value(value) {
                                // Register RC variable if it creates a new RC value
                                self.register_rc_var(&escaped_name, &typ);
                            } else if let Some(adt_name) = self.expr_creates_adt_with_pointers(value) {
                                // ADT with pointer fields - needs field cleanup at scope exit
                                self.register_rc_var_with_adt(&escaped_name, &typ, Some(adt_name));
                            }
                        }
                        Statement::Expr(e) => {
                            // Emit expression - if it's a function call that returns void/unit,
                            // we need to emit it as a statement
                            let expr_str = self.emit_expr(e)?;
                            // If emit_expr didn't write the call itself (for non-void returns),
                            // and it's a function call, emit it as a statement
                            if !expr_str.is_empty() && expr_str != "NULL" {
                                // Check if this is a function call expression
                                if let Expr::Call { func, .. } = e {
                                    if let Expr::Var(ident) = func.as_ref() {
                                        if self.functions.contains(&ident.name) {
                                            // It's a function call - emit as statement
                                            self.writeln(&format!("{};", expr_str));
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                // Emit the result expression
                let result_val = self.emit_expr(result)?;

                // Check if result references RC-tracked variables from this scope
                // If so, we need to save the result before cleanup to avoid use-after-free
                let result_uses_rc_vars = self.expr_uses_rc_vars_from_scope(result);

                // Infer result type to check if it's void
                let result_type = self.infer_expr_type(result);
                let is_void = result_type.as_ref().map_or(false, |t| t == "void" || t == "LuxUnit");

                // Check if the result is a variable from this scope - if so, skip decref'ing it
                let skip_var = if let Expr::Var(ident) = result.as_ref() {
                    if self.is_var_in_current_rc_scope(&ident.name) {
                        Some(ident.name.as_str())
                    } else {
                        None
                    }
                } else {
                    None
                };

                // If result uses RC vars that would be freed, save it first (but not for void results)
                let final_result = if result_uses_rc_vars && skip_var.is_none() && !self.is_rc_temp(&result_val) && !is_void {
                    let typ = result_type.unwrap_or_else(|| "LuxInt".to_string());
                    let temp = format!("_block_result_{}", self.fresh_name());
                    self.writeln(&format!("{} {} = {};", typ, temp, result_val));
                    self.pop_rc_scope_except(None);
                    temp
                } else {
                    self.pop_rc_scope_except(skip_var);
                    result_val
                };

                Ok(final_result)
            }

            Expr::EffectOp { effect, operation, args, .. } => {
                self.effects_used.insert(effect.name.clone());

                // List module operations (treated as effect by parser but handled specially)
                if effect.name == "List" {
                    return self.emit_list_operation(&operation.name, args);
                }

                // Built-in Console effect
                if effect.name == "Console" {
                    if operation.name == "print" {
                        // Check if arg is a function call that returns an RC type (like String)
                        // If so, we need to store the result and decref it after printing
                        let needs_rc_cleanup = if let Expr::Call { func, .. } = &args[0] {
                            if let Expr::Var(ident) = func.as_ref() {
                                // Check if function returns LuxString
                                self.function_return_types.get(&ident.name)
                                    .map(|t| t == "LuxString" || self.is_rc_type(t))
                                    .unwrap_or(false)
                            } else {
                                false
                            }
                        } else {
                            false
                        };

                        let arg = self.emit_expr(&args[0])?;

                        // If it's a function call returning RC type, store in temp for cleanup
                        let actual_arg = if needs_rc_cleanup && !self.is_rc_temp(&arg) {
                            let temp = format!("_print_arg_{}", self.fresh_name());
                            self.writeln(&format!("LuxString {} = {};", temp, arg));
                            temp
                        } else {
                            arg.clone()
                        };

                        if self.has_evidence {
                            self.writeln(&format!("ev->console->print(ev->console->env, {});", actual_arg));
                        } else {
                            self.writeln(&format!("lux_console_print({});", actual_arg));
                        }
                        // Immediately decref string concat temps or function return temps after use
                        if self.is_rc_temp(&arg) {
                            self.writeln(&format!("lux_decref_string({});", arg));
                            self.unregister_rc_var(&arg);
                        } else if needs_rc_cleanup {
                            self.writeln(&format!("lux_decref_string({});", actual_arg));
                        }
                        return Ok("NULL".to_string());
                    } else if operation.name == "readLine" {
                        let temp = format!("_readLine_{}", self.fresh_name());
                        if self.has_evidence {
                            self.writeln(&format!("LuxString {} = ev->console->readLine(ev->console->env);", temp));
                        } else {
                            self.writeln(&format!("LuxString {} = lux_console_readLine();", temp));
                        }
                        self.register_rc_var(&temp, "LuxString");
                        return Ok(temp);
                    }
                }

                // Built-in Random effect
                if effect.name == "Random" {
                    match operation.name.as_str() {
                        "int" => {
                            let min = self.emit_expr(&args[0])?;
                            let max = self.emit_expr(&args[1])?;
                            if self.has_evidence {
                                return Ok(format!("ev->random->randInt(ev->random->env, {}, {})", min, max));
                            } else {
                                return Ok(format!("lux_random_int({}, {})", min, max));
                            }
                        }
                        "float" => {
                            if self.has_evidence {
                                return Ok("ev->random->randFloat(ev->random->env)".to_string());
                            } else {
                                return Ok("lux_random_float()".to_string());
                            }
                        }
                        "bool" => {
                            if self.has_evidence {
                                return Ok("ev->random->randBool(ev->random->env)".to_string());
                            } else {
                                return Ok("lux_random_bool()".to_string());
                            }
                        }
                        _ => {}
                    }
                }

                // Built-in Time effect
                if effect.name == "Time" {
                    match operation.name.as_str() {
                        "now" => {
                            if self.has_evidence {
                                return Ok("ev->time->now(ev->time->env)".to_string());
                            } else {
                                return Ok("lux_time_now()".to_string());
                            }
                        }
                        "sleep" => {
                            let ms = self.emit_expr(&args[0])?;
                            if self.has_evidence {
                                self.writeln(&format!("ev->time->sleep(ev->time->env, {});", ms));
                            } else {
                                self.writeln(&format!("lux_time_sleep({});", ms));
                            }
                            return Ok("NULL".to_string());
                        }
                        _ => {}
                    }
                }

                // Built-in File effect
                if effect.name == "File" {
                    match operation.name.as_str() {
                        "read" => {
                            let path = self.emit_expr(&args[0])?;
                            let temp = format!("_file_read_{}", self.fresh_name());
                            if self.has_evidence {
                                self.writeln(&format!("LuxString {} = ev->file->read(ev->file->env, {});", temp, path));
                            } else {
                                self.writeln(&format!("LuxString {} = lux_file_read({});", temp, path));
                            }
                            self.register_rc_var(&temp, "LuxString");
                            return Ok(temp);
                        }
                        "write" => {
                            let path = self.emit_expr(&args[0])?;
                            let content = self.emit_expr(&args[1])?;
                            if self.has_evidence {
                                self.writeln(&format!("ev->file->write(ev->file->env, {}, {});", path, content));
                            } else {
                                self.writeln(&format!("lux_file_write({}, {});", path, content));
                            }
                            return Ok("NULL".to_string());
                        }
                        "append" => {
                            let path = self.emit_expr(&args[0])?;
                            let content = self.emit_expr(&args[1])?;
                            if self.has_evidence {
                                self.writeln(&format!("ev->file->append(ev->file->env, {}, {});", path, content));
                            } else {
                                self.writeln(&format!("lux_file_append({}, {});", path, content));
                            }
                            return Ok("NULL".to_string());
                        }
                        "exists" => {
                            let path = self.emit_expr(&args[0])?;
                            if self.has_evidence {
                                return Ok(format!("ev->file->exists(ev->file->env, {})", path));
                            } else {
                                return Ok(format!("lux_file_exists({})", path));
                            }
                        }
                        "delete" => {
                            let path = self.emit_expr(&args[0])?;
                            if self.has_evidence {
                                self.writeln(&format!("ev->file->delete_file(ev->file->env, {});", path));
                            } else {
                                self.writeln(&format!("lux_file_delete({});", path));
                            }
                            return Ok("NULL".to_string());
                        }
                        "isDir" => {
                            let path = self.emit_expr(&args[0])?;
                            if self.has_evidence {
                                return Ok(format!("ev->file->isDir(ev->file->env, {})", path));
                            } else {
                                return Ok(format!("lux_file_isDir({})", path));
                            }
                        }
                        "mkdir" => {
                            let path = self.emit_expr(&args[0])?;
                            if self.has_evidence {
                                self.writeln(&format!("ev->file->mkdir(ev->file->env, {});", path));
                            } else {
                                self.writeln(&format!("lux_file_mkdir({});", path));
                            }
                            return Ok("NULL".to_string());
                        }
                        _ => {}
                    }
                }

                // Built-in Http effect
                if effect.name == "Http" {
                    match operation.name.as_str() {
                        "get" => {
                            let url = self.emit_expr(&args[0])?;
                            let temp = format!("_http_get_{}", self.fresh_name());
                            if self.has_evidence {
                                self.writeln(&format!("LuxString {} = ev->http->get(ev->http->env, {});", temp, url));
                            } else {
                                self.writeln(&format!("LuxString {} = lux_http_get({});", temp, url));
                            }
                            self.register_rc_var(&temp, "LuxString");
                            return Ok(temp);
                        }
                        "post" => {
                            let url = self.emit_expr(&args[0])?;
                            let body = self.emit_expr(&args[1])?;
                            let temp = format!("_http_post_{}", self.fresh_name());
                            if self.has_evidence {
                                self.writeln(&format!("LuxString {} = ev->http->post(ev->http->env, {}, {});", temp, url, body));
                            } else {
                                self.writeln(&format!("LuxString {} = lux_http_post({}, {});", temp, url, body));
                            }
                            self.register_rc_var(&temp, "LuxString");
                            return Ok(temp);
                        }
                        "put" => {
                            let url = self.emit_expr(&args[0])?;
                            let body = self.emit_expr(&args[1])?;
                            let temp = format!("_http_put_{}", self.fresh_name());
                            if self.has_evidence {
                                self.writeln(&format!("LuxString {} = ev->http->put(ev->http->env, {}, {});", temp, url, body));
                            } else {
                                self.writeln(&format!("LuxString {} = lux_http_put({}, {});", temp, url, body));
                            }
                            self.register_rc_var(&temp, "LuxString");
                            return Ok(temp);
                        }
                        "delete" => {
                            let url = self.emit_expr(&args[0])?;
                            let temp = format!("_http_delete_{}", self.fresh_name());
                            if self.has_evidence {
                                self.writeln(&format!("LuxString {} = ev->http->delete_req(ev->http->env, {});", temp, url));
                            } else {
                                self.writeln(&format!("LuxString {} = lux_http_delete({});", temp, url));
                            }
                            self.register_rc_var(&temp, "LuxString");
                            return Ok(temp);
                        }
                        _ => {}
                    }
                }

                // Built-in Process effect
                if effect.name == "Process" {
                    match operation.name.as_str() {
                        "exec" => {
                            let cmd = self.emit_expr(&args[0])?;
                            let temp = format!("_exec_{}", self.fresh_name());
                            if self.has_evidence {
                                self.writeln(&format!("LuxString {} = ev->process->exec(ev->process->env, {});", temp, cmd));
                            } else {
                                self.writeln(&format!("LuxString {} = lux_process_exec({});", temp, cmd));
                            }
                            self.register_rc_var(&temp, "LuxString");
                            return Ok(temp);
                        }
                        "env" => {
                            let name = self.emit_expr(&args[0])?;
                            // Process.env returns static string or NULL, not RC-managed
                            if self.has_evidence {
                                return Ok(format!("ev->process->getenv_fn(ev->process->env, {})", name));
                            } else {
                                return Ok(format!("lux_process_env({})", name));
                            }
                        }
                        "args" => {
                            let temp = format!("_args_{}", self.fresh_name());
                            if self.has_evidence {
                                self.writeln(&format!("LuxList* {} = ev->process->args(ev->process->env);", temp));
                            } else {
                                self.writeln(&format!("LuxList* {} = lux_process_args();", temp));
                            }
                            self.register_rc_var(&temp, "LuxList*");
                            return Ok(temp);
                        }
                        "cwd" => {
                            let temp = format!("_cwd_{}", self.fresh_name());
                            if self.has_evidence {
                                self.writeln(&format!("LuxString {} = ev->process->cwd(ev->process->env);", temp));
                            } else {
                                self.writeln(&format!("LuxString {} = lux_process_cwd();", temp));
                            }
                            self.register_rc_var(&temp, "LuxString");
                            return Ok(temp);
                        }
                        _ => {}
                    }
                }

                // Built-in String module (not an effect, but handled similarly)
                if effect.name == "String" {
                    match operation.name.as_str() {
                        "trim" => {
                            let s = self.emit_expr(&args[0])?;
                            // Create temp variable and track for cleanup (returns RC-managed string)
                            let temp = format!("_trim_{}", self.fresh_name());
                            self.writeln(&format!("LuxString {} = lux_string_trim({});", temp, s));
                            self.register_rc_var(&temp, "LuxString");
                            return Ok(temp);
                        }
                        "length" => {
                            let s = self.emit_expr(&args[0])?;
                            return Ok(format!("lux_string_length({})", s));
                        }
                        "lines" => {
                            let s = self.emit_expr(&args[0])?;
                            // Create temp variable and track for cleanup (returns RC-managed list)
                            let temp = format!("_lines_{}", self.fresh_name());
                            self.writeln(&format!("LuxList* {} = lux_string_lines({});", temp, s));
                            self.register_rc_var(&temp, "LuxList*");
                            return Ok(temp);
                        }
                        "split" => {
                            let s = self.emit_expr(&args[0])?;
                            let sep = self.emit_expr(&args[1])?;
                            // Create temp variable and track for cleanup (returns RC-managed list)
                            let temp = format!("_split_{}", self.fresh_name());
                            self.writeln(&format!("LuxList* {} = lux_string_split({}, {});", temp, s, sep));
                            self.register_rc_var(&temp, "LuxList*");
                            return Ok(temp);
                        }
                        "contains" => {
                            let s = self.emit_expr(&args[0])?;
                            let sub = self.emit_expr(&args[1])?;
                            return Ok(format!("lux_string_contains({}, {})", s, sub));
                        }
                        "parseInt" => {
                            let s = self.emit_expr(&args[0])?;
                            return Ok(format!("lux_string_parseInt({})", s));
                        }
                        "parseFloat" => {
                            let s = self.emit_expr(&args[0])?;
                            return Ok(format!("lux_string_parseFloat({})", s));
                        }
                        "fromChar" => {
                            let c = self.emit_expr(&args[0])?;
                            // Create temp variable and track for cleanup (returns RC-managed string)
                            let temp = format!("_fromchar_{}", self.fresh_name());
                            self.writeln(&format!("LuxString {} = lux_string_from_char({});", temp, c));
                            self.register_rc_var(&temp, "LuxString");
                            return Ok(temp);
                        }
                        "chars" => {
                            let s = self.emit_expr(&args[0])?;
                            // Create temp variable and track for cleanup (returns RC-managed list)
                            let temp = format!("_chars_{}", self.fresh_name());
                            self.writeln(&format!("LuxList* {} = lux_string_chars({});", temp, s));
                            self.register_rc_var(&temp, "LuxList*");
                            return Ok(temp);
                        }
                        "substring" => {
                            let s = self.emit_expr(&args[0])?;
                            let start = self.emit_expr(&args[1])?;
                            let len = self.emit_expr(&args[2])?;
                            let temp = format!("_substr_{}", self.fresh_name());
                            self.writeln(&format!("LuxString {} = lux_string_substring({}, {}, {});", temp, s, start, len));
                            self.register_rc_var(&temp, "LuxString");
                            return Ok(temp);
                        }
                        "toUpper" => {
                            let s = self.emit_expr(&args[0])?;
                            let temp = format!("_upper_{}", self.fresh_name());
                            self.writeln(&format!("LuxString {} = lux_string_to_upper({});", temp, s));
                            self.register_rc_var(&temp, "LuxString");
                            return Ok(temp);
                        }
                        "toLower" => {
                            let s = self.emit_expr(&args[0])?;
                            let temp = format!("_lower_{}", self.fresh_name());
                            self.writeln(&format!("LuxString {} = lux_string_to_lower({});", temp, s));
                            self.register_rc_var(&temp, "LuxString");
                            return Ok(temp);
                        }
                        "replace" => {
                            let s = self.emit_expr(&args[0])?;
                            let from = self.emit_expr(&args[1])?;
                            let to = self.emit_expr(&args[2])?;
                            let temp = format!("_replace_{}", self.fresh_name());
                            self.writeln(&format!("LuxString {} = lux_string_replace({}, {}, {});", temp, s, from, to));
                            self.register_rc_var(&temp, "LuxString");
                            return Ok(temp);
                        }
                        "startsWith" => {
                            let s = self.emit_expr(&args[0])?;
                            let prefix = self.emit_expr(&args[1])?;
                            return Ok(format!("lux_string_starts_with({}, {})", s, prefix));
                        }
                        "endsWith" => {
                            let s = self.emit_expr(&args[0])?;
                            let suffix = self.emit_expr(&args[1])?;
                            return Ok(format!("lux_string_ends_with({}, {})", s, suffix));
                        }
                        "join" => {
                            let list = self.emit_expr(&args[0])?;
                            let sep = self.emit_expr(&args[1])?;
                            let temp = format!("_join_{}", self.fresh_name());
                            self.writeln(&format!("LuxString {} = lux_string_join({}, {});", temp, list, sep));
                            self.register_rc_var(&temp, "LuxString");
                            return Ok(temp);
                        }
                        _ => {}
                    }
                }

                // For other effects, emit generic evidence-passing call
                let arg_strs: Result<Vec<_>, _> = args.iter().map(|a| self.emit_expr(a)).collect();
                if self.has_evidence {
                    Ok(format!("ev->{}->{}(ev->{}->env{}{})",
                        effect.name.to_lowercase(),
                        operation.name,
                        effect.name.to_lowercase(),
                        if arg_strs.as_ref().map_or(true, |v| v.is_empty()) { "" } else { ", " },
                        arg_strs?.join(", ")))
                } else {
                    Ok(format!("lux_{}__{}({})",
                        effect.name.to_lowercase(),
                        operation.name,
                        arg_strs?.join(", ")))
                }
            }

            Expr::Record { fields, .. } => {
                let field_strs: Result<Vec<_>, _> = fields.iter().map(|(name, val)| {
                    let v = self.emit_expr(val)?;
                    Ok(format!(".{} = {}", name.name, v))
                }).collect();
                Ok(format!("{{ {} }}", field_strs?.join(", ")))
            }

            Expr::Field { object, field, .. } => {
                let obj = self.emit_expr(object)?;
                Ok(format!("{}.{}", obj, field.name))
            }

            Expr::Match { scrutinee, arms, .. } => {
                self.emit_match(scrutinee, arms)
            }

            Expr::List { elements, .. } => {
                self.emit_list_literal(elements)
            }

            _ => Err(CGenError {
                message: format!("Unsupported expression type in C backend"),
                span: None,
            }),
        }
    }

    fn emit_list_literal(&mut self, elements: &[Expr]) -> Result<String, CGenError> {
        let list_var = format!("_list_{}", self.fresh_name());
        let len = elements.len();

        self.writeln(&format!("LuxList* {} = lux_list_new({});", list_var, len));

        for (i, elem) in elements.iter().enumerate() {
            let elem_val = self.emit_expr(elem)?;
            let boxed = self.box_value(&elem_val, self.infer_expr_type(elem).as_deref());
            self.writeln(&format!("{}->elements[{}] = {};", list_var, i, boxed));
        }

        self.writeln(&format!("{}->length = {};", list_var, len));
        Ok(list_var)
    }

    fn box_value(&self, val: &str, type_hint: Option<&str>) -> String {
        match type_hint {
            Some("LuxInt") => format!("lux_box_int({})", val),
            Some("LuxBool") => format!("lux_box_bool({})", val),
            Some("LuxString") => format!("lux_box_string({})", val),
            Some(t) if t.ends_with('*') => val.to_string(), // Already a pointer
            _ => format!("lux_box_int({})", val), // Default to int boxing
        }
    }

    #[allow(dead_code)]
    fn unbox_value(&self, val: &str, type_hint: Option<&str>) -> String {
        match type_hint {
            Some("LuxInt") => format!("lux_unbox_int({})", val),
            Some("LuxBool") => format!("lux_unbox_bool({})", val),
            Some("LuxString") => format!("lux_unbox_string({})", val),
            _ => format!("lux_unbox_int({})", val), // Default to int unboxing
        }
    }

    /// Emit code for List module operations (List.map, List.filter, etc.)
    fn emit_list_operation(&mut self, op: &str, args: &[Expr]) -> Result<String, CGenError> {
        match op {
            // Simple operations - direct C function calls
            "length" => {
                if args.len() != 1 {
                    return Err(CGenError { message: "List.length takes 1 argument".to_string(), span: None });
                }
                let list = self.emit_expr(&args[0])?;
                Ok(format!("lux_list_length({})", list))
            }
            "isEmpty" => {
                if args.len() != 1 {
                    return Err(CGenError { message: "List.isEmpty takes 1 argument".to_string(), span: None });
                }
                let list = self.emit_expr(&args[0])?;
                Ok(format!("lux_list_isEmpty({})", list))
            }
            "concat" => {
                if args.len() != 2 {
                    return Err(CGenError { message: "List.concat takes 2 arguments".to_string(), span: None });
                }
                let list1 = self.emit_expr(&args[0])?;
                let list2 = self.emit_expr(&args[1])?;
                Ok(format!("lux_list_concat({}, {})", list1, list2))
            }
            "reverse" => {
                if args.len() != 1 {
                    return Err(CGenError { message: "List.reverse takes 1 argument".to_string(), span: None });
                }
                let list = self.emit_expr(&args[0])?;
                Ok(format!("lux_list_reverse({})", list))
            }
            "range" => {
                if args.len() != 2 {
                    return Err(CGenError { message: "List.range takes 2 arguments".to_string(), span: None });
                }
                let start = self.emit_expr(&args[0])?;
                let end = self.emit_expr(&args[1])?;
                Ok(format!("lux_list_range({}, {})", start, end))
            }
            "take" => {
                if args.len() != 2 {
                    return Err(CGenError { message: "List.take takes 2 arguments".to_string(), span: None });
                }
                let list = self.emit_expr(&args[0])?;
                let n = self.emit_expr(&args[1])?;
                Ok(format!("lux_list_take({}, {})", list, n))
            }
            "drop" => {
                if args.len() != 2 {
                    return Err(CGenError { message: "List.drop takes 2 arguments".to_string(), span: None });
                }
                let list = self.emit_expr(&args[0])?;
                let n = self.emit_expr(&args[1])?;
                Ok(format!("lux_list_drop({}, {})", list, n))
            }

            // Access operations - return Option
            "head" => {
                if args.len() != 1 {
                    return Err(CGenError { message: "List.head takes 1 argument".to_string(), span: None });
                }
                let list = self.emit_expr(&args[0])?;
                let result_var = format!("_head_{}", self.fresh_name());
                // Need to incref the element since it's being extracted from the list
                self.writeln(&format!("Option {};", result_var));
                self.writeln(&format!("if ({0}->length > 0) {{", list));
                self.indent += 1;
                self.writeln(&format!("lux_incref({0}->elements[0]);", list));
                self.writeln(&format!("{0} = lux_option_some({1}->elements[0]);", result_var, list));
                self.indent -= 1;
                self.writeln("} else {");
                self.indent += 1;
                self.writeln(&format!("{} = lux_option_none();", result_var));
                self.indent -= 1;
                self.writeln("}");
                Ok(result_var)
            }
            "tail" => {
                if args.len() != 1 {
                    return Err(CGenError { message: "List.tail takes 1 argument".to_string(), span: None });
                }
                let list = self.emit_expr(&args[0])?;
                let result_var = format!("_tail_{}", self.fresh_name());
                self.writeln(&format!("Option {};", result_var));
                self.writeln(&format!("if ({0}->length > 0) {{", list));
                self.indent += 1;
                self.writeln(&format!("LuxList* _tail_list = lux_list_new({0}->length - 1);", list));
                self.writeln(&format!("for (int64_t i = 1; i < {0}->length; i++) {{", list));
                self.indent += 1;
                // Incref each element being copied to the new list
                self.writeln(&format!("lux_incref({0}->elements[i]);", list));
                self.writeln(&format!("_tail_list->elements[i-1] = {0}->elements[i];", list));
                self.indent -= 1;
                self.writeln("}");
                self.writeln(&format!("_tail_list->length = {0}->length - 1;", list));
                self.writeln(&format!("{} = lux_option_some(_tail_list);", result_var));
                self.indent -= 1;
                self.writeln("} else {");
                self.indent += 1;
                self.writeln(&format!("{} = lux_option_none();", result_var));
                self.indent -= 1;
                self.writeln("}");
                Ok(result_var)
            }
            "get" => {
                if args.len() != 2 {
                    return Err(CGenError { message: "List.get takes 2 arguments".to_string(), span: None });
                }
                let list = self.emit_expr(&args[0])?;
                let idx = self.emit_expr(&args[1])?;
                let result_var = format!("_get_{}", self.fresh_name());
                // Need to incref the element since it's being extracted from the list
                self.writeln(&format!("Option {};", result_var));
                self.writeln(&format!("if ({0} >= 0 && {0} < {1}->length) {{", idx, list));
                self.indent += 1;
                self.writeln(&format!("lux_incref({0}->elements[{1}]);", list, idx));
                self.writeln(&format!("{0} = lux_option_some({1}->elements[{2}]);", result_var, list, idx));
                self.indent -= 1;
                self.writeln("} else {");
                self.indent += 1;
                self.writeln(&format!("{} = lux_option_none();", result_var));
                self.indent -= 1;
                self.writeln("}");
                Ok(result_var)
            }

            // Higher-order operations - inline loops
            "map" => {
                if args.len() != 2 {
                    return Err(CGenError { message: "List.map takes 2 arguments".to_string(), span: None });
                }
                let list = self.emit_expr(&args[0])?;
                let closure = self.emit_expr(&args[1])?;
                let id = self.fresh_name();
                let result_var = format!("_map_{}", id);
                let i_var = format!("_i_{}", id);
                let elem_var = format!("_elem_{}", id);
                let fn_var = format!("_fn_{}", id);
                let mapped_var = format!("_mapped_{}", id);

                // FBIP: Check if we can reuse the list in-place
                self.writeln(&format!("LuxList* {};", result_var));
                self.writeln(&format!("if (LUX_RC_HEADER({})->rc == 1) {{", list));
                self.indent += 1;
                if self.debug_rc {
                    self.writeln("lux_fbip_reuse_count++;");
                }
                self.writeln(&format!("// FBIP: Reuse list in-place"));
                self.writeln(&format!("{} = {};", result_var, list));
                self.writeln(&format!("for (int64_t {} = 0; {} < {}->length; {}++) {{", i_var, i_var, list, i_var));
                self.indent += 1;
                self.writeln(&format!("void* {} = {}->elements[{}];", elem_var, list, i_var));
                self.writeln(&format!("LuxClosure* {} = (LuxClosure*){};", fn_var, closure));
                self.writeln(&format!("LuxInt {} = ((LuxInt(*)(void*, LuxInt)){}->fn_ptr)({}->env, lux_unbox_int({}));", mapped_var, fn_var, fn_var, elem_var));
                self.writeln(&format!("lux_decref({});  // Decref old element", elem_var));
                self.writeln(&format!("{}->elements[{}] = lux_box_int({});", result_var, i_var, mapped_var));
                self.indent -= 1;
                self.writeln("}");
                self.indent -= 1;
                self.writeln("} else {");
                self.indent += 1;
                if self.debug_rc {
                    self.writeln("lux_fbip_copy_count++;");
                }
                self.writeln(&format!("// Allocate new list"));
                self.writeln(&format!("{} = lux_list_new({}->length);", result_var, list));
                self.writeln(&format!("for (int64_t {} = 0; {} < {}->length; {}++) {{", i_var, i_var, list, i_var));
                self.indent += 1;
                self.writeln(&format!("void* {} = {}->elements[{}];", elem_var, list, i_var));
                self.writeln(&format!("LuxClosure* {} = (LuxClosure*){};", fn_var, closure));
                self.writeln(&format!("LuxInt {} = ((LuxInt(*)(void*, LuxInt)){}->fn_ptr)({}->env, lux_unbox_int({}));", mapped_var, fn_var, fn_var, elem_var));
                self.writeln(&format!("{}->elements[{}] = lux_box_int({});", result_var, i_var, mapped_var));
                self.indent -= 1;
                self.writeln("}");
                self.writeln(&format!("{}->length = {}->length;", result_var, list));
                self.indent -= 1;
                self.writeln("}");
                // Decref the closure if it was a temporary (inline lambda)
                if closure.starts_with("_closure_") {
                    self.writeln(&format!("lux_decref_closure({});", closure));
                }

                Ok(result_var)
            }
            "filter" => {
                if args.len() != 2 {
                    return Err(CGenError { message: "List.filter takes 2 arguments".to_string(), span: None });
                }
                let list = self.emit_expr(&args[0])?;
                let closure = self.emit_expr(&args[1])?;
                let id = self.fresh_name();
                let result_var = format!("_filter_{}", id);
                let count_var = format!("_count_{}", id);
                let i_var = format!("_i_{}", id);
                let elem_var = format!("_elem_{}", id);
                let fn_var = format!("_fn_{}", id);
                let keep_var = format!("_keep_{}", id);

                // FBIP: Check if we can filter in-place
                self.writeln(&format!("LuxList* {};", result_var));
                self.writeln(&format!("int64_t {} = 0;", count_var));
                self.writeln(&format!("if (LUX_RC_HEADER({})->rc == 1) {{", list));
                self.indent += 1;
                if self.debug_rc {
                    self.writeln("lux_fbip_reuse_count++;");
                }
                self.writeln(&format!("// FBIP: Filter in-place"));
                self.writeln(&format!("{} = {};", result_var, list));
                self.writeln(&format!("for (int64_t {} = 0; {} < {}->length; {}++) {{", i_var, i_var, list, i_var));
                self.indent += 1;
                self.writeln(&format!("void* {} = {}->elements[{}];", elem_var, list, i_var));
                self.writeln(&format!("LuxClosure* {} = (LuxClosure*){};", fn_var, closure));
                self.writeln(&format!("LuxBool {} = ((LuxBool(*)(void*, LuxInt)){}->fn_ptr)({}->env, lux_unbox_int({}));", keep_var, fn_var, fn_var, elem_var));
                self.writeln(&format!("if ({}) {{", keep_var));
                self.indent += 1;
                self.writeln(&format!("{}->elements[{}++] = {};", result_var, count_var, elem_var));
                self.indent -= 1;
                self.writeln("} else {");
                self.indent += 1;
                self.writeln(&format!("lux_decref({});  // Decref filtered-out element", elem_var));
                self.indent -= 1;
                self.writeln("}");
                self.indent -= 1;
                self.writeln("}");
                self.writeln(&format!("{}->length = {};", result_var, count_var));
                self.indent -= 1;
                self.writeln("} else {");
                self.indent += 1;
                if self.debug_rc {
                    self.writeln("lux_fbip_copy_count++;");
                }
                self.writeln(&format!("// Allocate new list"));
                self.writeln(&format!("{} = lux_list_new({}->length);", result_var, list));
                self.writeln(&format!("for (int64_t {} = 0; {} < {}->length; {}++) {{", i_var, i_var, list, i_var));
                self.indent += 1;
                self.writeln(&format!("void* {} = {}->elements[{}];", elem_var, list, i_var));
                self.writeln(&format!("LuxClosure* {} = (LuxClosure*){};", fn_var, closure));
                self.writeln(&format!("LuxBool {} = ((LuxBool(*)(void*, LuxInt)){}->fn_ptr)({}->env, lux_unbox_int({}));", keep_var, fn_var, fn_var, elem_var));
                self.writeln(&format!("if ({}) {{", keep_var));
                self.indent += 1;
                // Incref the element since it's now shared between lists
                self.writeln(&format!("lux_incref({});", elem_var));
                self.writeln(&format!("{}->elements[{}++] = {};", result_var, count_var, elem_var));
                self.indent -= 1;
                self.writeln("}");
                self.indent -= 1;
                self.writeln("}");
                self.writeln(&format!("{}->length = {};", result_var, count_var));
                self.indent -= 1;
                self.writeln("}");
                // Decref the closure if it was a temporary (inline lambda)
                if closure.starts_with("_closure_") {
                    self.writeln(&format!("lux_decref_closure({});", closure));
                }

                Ok(result_var)
            }
            "fold" => {
                if args.len() != 3 {
                    return Err(CGenError { message: "List.fold takes 3 arguments".to_string(), span: None });
                }
                let list = self.emit_expr(&args[0])?;
                let init = self.emit_expr(&args[1])?;
                let closure = self.emit_expr(&args[2])?;
                let id = self.fresh_name();
                let result_var = format!("_fold_{}", id);
                let i_var = format!("_i_{}", id);
                let elem_var = format!("_elem_{}", id);
                let fn_var = format!("_fn_{}", id);

                self.writeln(&format!("LuxInt {} = {};", result_var, init));
                self.writeln(&format!("for (int64_t {} = 0; {} < {}->length; {}++) {{", i_var, i_var, list, i_var));
                self.indent += 1;
                self.writeln(&format!("void* {} = {}->elements[{}];", elem_var, list, i_var));
                self.writeln(&format!("LuxClosure* {} = (LuxClosure*){};", fn_var, closure));
                self.writeln(&format!("{} = ((LuxInt(*)(void*, LuxInt, LuxInt)){}->fn_ptr)({}->env, {}, lux_unbox_int({}));", result_var, fn_var, fn_var, result_var, elem_var));
                self.indent -= 1;
                self.writeln("}");
                // Decref the closure if it was a temporary (inline lambda)
                if closure.starts_with("_closure_") {
                    self.writeln(&format!("lux_decref_closure({});", closure));
                }

                Ok(result_var)
            }
            "find" => {
                if args.len() != 2 {
                    return Err(CGenError { message: "List.find takes 2 arguments".to_string(), span: None });
                }
                let list = self.emit_expr(&args[0])?;
                let closure = self.emit_expr(&args[1])?;
                let id = self.fresh_name();
                let result_var = format!("_find_{}", id);
                let i_var = format!("_i_{}", id);
                let elem_var = format!("_elem_{}", id);
                let fn_var = format!("_fn_{}", id);
                let matches_var = format!("_matches_{}", id);

                self.writeln(&format!("Option {} = lux_option_none();", result_var));
                self.writeln(&format!("for (int64_t {} = 0; {} < {}->length; {}++) {{", i_var, i_var, list, i_var));
                self.indent += 1;
                self.writeln(&format!("void* {} = {}->elements[{}];", elem_var, list, i_var));
                self.writeln(&format!("LuxClosure* {} = (LuxClosure*){};", fn_var, closure));
                self.writeln(&format!("LuxBool {} = ((LuxBool(*)(void*, LuxInt)){}->fn_ptr)({}->env, lux_unbox_int({}));", matches_var, fn_var, fn_var, elem_var));
                self.writeln(&format!("if ({}) {{", matches_var));
                self.indent += 1;
                self.writeln(&format!("{} = lux_option_some({});", result_var, elem_var));
                self.writeln("break;");
                self.indent -= 1;
                self.writeln("}");
                self.indent -= 1;
                self.writeln("}");
                // Decref the closure if it was a temporary (inline lambda)
                if closure.starts_with("_closure_") {
                    self.writeln(&format!("lux_decref_closure({});", closure));
                }

                Ok(result_var)
            }
            "any" => {
                if args.len() != 2 {
                    return Err(CGenError { message: "List.any takes 2 arguments".to_string(), span: None });
                }
                let list = self.emit_expr(&args[0])?;
                let closure = self.emit_expr(&args[1])?;
                let id = self.fresh_name();
                let result_var = format!("_any_{}", id);
                let i_var = format!("_i_{}", id);
                let elem_var = format!("_elem_{}", id);
                let fn_var = format!("_fn_{}", id);

                self.writeln(&format!("LuxBool {} = 0;", result_var));
                self.writeln(&format!("for (int64_t {} = 0; {} < {}->length; {}++) {{", i_var, i_var, list, i_var));
                self.indent += 1;
                self.writeln(&format!("void* {} = {}->elements[{}];", elem_var, list, i_var));
                self.writeln(&format!("LuxClosure* {} = (LuxClosure*){};", fn_var, closure));
                self.writeln(&format!("if (((LuxBool(*)(void*, LuxInt)){}->fn_ptr)({}->env, lux_unbox_int({}))) {{", fn_var, fn_var, elem_var));
                self.indent += 1;
                self.writeln(&format!("{} = 1;", result_var));
                self.writeln("break;");
                self.indent -= 1;
                self.writeln("}");
                self.indent -= 1;
                self.writeln("}");
                // Decref the closure if it was a temporary (inline lambda)
                if closure.starts_with("_closure_") {
                    self.writeln(&format!("lux_decref_closure({});", closure));
                }

                Ok(result_var)
            }
            "all" => {
                if args.len() != 2 {
                    return Err(CGenError { message: "List.all takes 2 arguments".to_string(), span: None });
                }
                let list = self.emit_expr(&args[0])?;
                let closure = self.emit_expr(&args[1])?;
                let id = self.fresh_name();
                let result_var = format!("_all_{}", id);
                let i_var = format!("_i_{}", id);
                let elem_var = format!("_elem_{}", id);
                let fn_var = format!("_fn_{}", id);

                self.writeln(&format!("LuxBool {} = 1;", result_var));
                self.writeln(&format!("for (int64_t {} = 0; {} < {}->length; {}++) {{", i_var, i_var, list, i_var));
                self.indent += 1;
                self.writeln(&format!("void* {} = {}->elements[{}];", elem_var, list, i_var));
                self.writeln(&format!("LuxClosure* {} = (LuxClosure*){};", fn_var, closure));
                self.writeln(&format!("if (!((LuxBool(*)(void*, LuxInt)){}->fn_ptr)({}->env, lux_unbox_int({}))) {{", fn_var, fn_var, elem_var));
                self.indent += 1;
                self.writeln(&format!("{} = 0;", result_var));
                self.writeln("break;");
                self.indent -= 1;
                self.writeln("}");
                self.indent -= 1;
                self.writeln("}");
                // Decref the closure if it was a temporary (inline lambda)
                if closure.starts_with("_closure_") {
                    self.writeln(&format!("lux_decref_closure({});", closure));
                }

                Ok(result_var)
            }

            _ => Err(CGenError {
                message: format!("Unsupported List operation: {}", op),
                span: None,
            }),
        }
    }

    fn emit_expr_with_substitution(&mut self, expr: &Expr, from: &str, to: &str) -> Result<String, CGenError> {
        // Simple substitution - in a real implementation, this would be more sophisticated
        match expr {
            Expr::Var(ident) if ident.name == from => Ok(to.to_string()),
            _ => self.emit_expr(expr),
        }
    }

    fn emit_match(&mut self, expr: &Expr, arms: &[MatchArm]) -> Result<String, CGenError> {
        let scrutinee = self.emit_expr(expr)?;
        let scrutinee_var = format!("scrutinee_{}", self.fresh_name());
        let result_var = format!("match_result_{}", self.fresh_name());

        // Infer the type name from the first constructor pattern we find
        let type_name = self.infer_type_name_from_arms(arms);

        // Infer the result type from match arm bodies
        // Try all arms since variables bound in patterns may not have known types yet
        let result_type = self.infer_match_result_type(arms);
        let is_void = result_type == "void";

        // Infer scrutinee type: first from constructor patterns, then from scrutinee expr, then from literal patterns
        let scrutinee_type = if let Some(ref tn) = type_name {
            tn.clone()
        } else if let Some(expr_type) = self.infer_expr_type(expr) {
            expr_type
        } else if self.has_string_literal_patterns(arms) {
            "LuxString".to_string()
        } else {
            "LuxInt".to_string()
        };
        self.writeln(&format!("{} {} = {};", scrutinee_type, scrutinee_var, scrutinee));

        // Don't declare a result variable for void-returning matches
        if !is_void {
            self.writeln(&format!("{} {};", result_type, result_var));
        }

        for (i, arm) in arms.iter().enumerate() {
            let condition = self.pattern_to_condition(&arm.pattern, &scrutinee_var, type_name.as_deref())?;

            if i == 0 {
                self.writeln(&format!("if ({}) {{", condition));
            } else {
                self.writeln(&format!("}} else if ({}) {{", condition));
            }

            self.indent += 1;

            // Extract and emit variable bindings from the pattern
            let bindings = self.extract_pattern_bindings(&arm.pattern, &scrutinee_var, type_name.as_deref());
            for (var_name, c_expr, c_type) in &bindings {
                // For void* from generic types like Option, try to infer the actual type
                let actual_type = if c_type == "void*" {
                    // First try to infer from the scrutinee expression - this gives us the Option<T> type
                    let scrutinee_inner_type = self.infer_option_inner_type(expr);
                    if let Some(inner_type) = scrutinee_inner_type {
                        inner_type
                    } else if let Some(body_type) = self.infer_expr_type(&arm.body) {
                        // Try to infer from body type
                        if matches!(body_type.as_str(), "LuxString" | "LuxInt" | "LuxFloat" | "LuxBool" | "LuxList*") {
                            body_type
                        } else {
                            // Try to find the var's usage in the body and infer from that
                            self.infer_var_type_from_usage(&arm.body, &var_name)
                                .unwrap_or_else(|| "LuxString".to_string())
                        }
                    } else {
                        // Try to find the var's usage in the body
                        self.infer_var_type_from_usage(&arm.body, &var_name)
                            .unwrap_or_else(|| "LuxString".to_string())
                    }
                } else {
                    c_type.clone()
                };

                // Emit the binding with proper casting
                if c_type == "void*" {
                    // Cast from void* to actual type
                    self.writeln(&format!("{} {} = ({})({});", actual_type, var_name, actual_type, c_expr));
                    self.var_types.insert(var_name.clone(), actual_type);
                } else if actual_type.ends_with('*') && actual_type != "void*" {
                    // Dereference pointer types (but not void*)
                    let base_type = &actual_type[..actual_type.len()-1];
                    self.writeln(&format!("{} {} = *({});", base_type, var_name, c_expr));
                    self.var_types.insert(var_name.clone(), base_type.to_string());
                } else {
                    self.writeln(&format!("{} {} = {};", actual_type, var_name, c_expr));
                    self.var_types.insert(var_name.clone(), actual_type);
                }
            }

            let body = self.emit_expr(&arm.body)?;
            if is_void {
                // For void expressions, just emit the body without assignment
                self.writeln(&format!("{};", body));
            } else {
                self.writeln(&format!("{} = {};", result_var, body));
            }
            self.indent -= 1;
        }

        self.writeln("}");

        // For void matches, return a dummy NULL
        if is_void {
            Ok("NULL".to_string())
        } else {
            Ok(result_var)
        }
    }

    /// Infer the result type of a match expression by checking all arm bodies
    /// Returns the first concrete type found, or "LuxInt" as default
    fn infer_match_result_type(&self, arms: &[MatchArm]) -> String {
        // Priority: check all arms for concrete types since bound variables
        // from patterns may not have known types in var_types yet
        let mut found_void = false;
        for arm in arms {
            if let Some(t) = self.infer_expr_type(&arm.body) {
                if t == "void" {
                    found_void = true;
                } else {
                    // Found a non-void type, use it
                    return t;
                }
            }
        }
        // If all arms were void, return void
        if found_void {
            return "void".to_string();
        }
        // Default fallback
        "LuxInt".to_string()
    }

    /// Check if any arm has a string literal pattern
    fn has_string_literal_patterns(&self, arms: &[MatchArm]) -> bool {
        for arm in arms {
            if let Pattern::Literal(lit) = &arm.pattern {
                if matches!(&lit.kind, LiteralKind::String(_)) {
                    return true;
                }
            }
        }
        false
    }

    /// Try to infer the type name from match arms by looking at constructor patterns
    fn infer_type_name_from_arms(&self, arms: &[MatchArm]) -> Option<String> {
        for arm in arms {
            if let Pattern::Constructor { name, .. } = &arm.pattern {
                // Look up the variant in our mapping
                if let Some(type_name) = self.variant_to_type.get(&name.name) {
                    return Some(type_name.clone());
                }
                // Fallback for built-in types that might not be in the map
                match name.name.as_str() {
                    "Some" | "None" => return Some("Option".to_string()),
                    "Ok" | "Err" => return Some("Result".to_string()),
                    _ => {}
                }
            }
        }
        None
    }

    /// Try to infer the C type of an expression
    fn infer_expr_type(&self, expr: &Expr) -> Option<String> {
        match expr {
            Expr::Literal(lit) => {
                match &lit.kind {
                    LiteralKind::Int(_) => Some("LuxInt".to_string()),
                    LiteralKind::Float(_) => Some("LuxFloat".to_string()),
                    LiteralKind::Bool(_) => Some("LuxBool".to_string()),
                    LiteralKind::String(_) => Some("LuxString".to_string()),
                    LiteralKind::Char(_) => Some("char".to_string()),
                    LiteralKind::Unit => Some("void".to_string()),
                }
            }
            Expr::Var(ident) => {
                // Check if it's a unit constructor
                if let Some(type_name) = self.variant_to_type.get(&ident.name) {
                    Some(type_name.clone())
                } else {
                    // Check if we know the variable's type
                    let escaped = self.escape_c_keyword(&ident.name);
                    self.var_types.get(&escaped).cloned()
                }
            }
            Expr::Call { func, .. } => {
                // Check if calling a constructor
                if let Expr::Var(ident) = func.as_ref() {
                    // toString returns LuxString
                    if ident.name == "toString" {
                        return Some("LuxString".to_string());
                    }
                    if let Some(type_name) = self.variant_to_type.get(&ident.name) {
                        return Some(type_name.clone());
                    }
                    // Check if calling a known function - use its return type
                    if let Some(ret_type) = self.function_return_types.get(&ident.name) {
                        return Some(ret_type.clone());
                    }
                }
                None
            }
            Expr::BinaryOp { op, left, right, .. } => {
                // String concatenation with + returns LuxString
                if matches!(op, BinaryOp::Add) {
                    if self.is_string_expr(left) || self.is_string_expr(right) {
                        return Some("LuxString".to_string());
                    }
                }
                // For other binary ops, infer from operands
                self.infer_expr_type(left).or_else(|| self.infer_expr_type(right))
            }
            Expr::Block { result, .. } => {
                // Type of block is the type of the result expression
                self.infer_expr_type(result)
            }
            Expr::If { then_branch, else_branch, .. } => {
                // Type of if is the type of either branch (they should match)
                self.infer_expr_type(then_branch)
                    .or_else(|| self.infer_expr_type(else_branch))
            }
            Expr::List { .. } => Some("LuxList*".to_string()),
            Expr::EffectOp { effect, operation, .. } => {
                // List operations have known return types
                if effect.name == "List" {
                    match operation.name.as_str() {
                        // Operations returning lists
                        "map" | "filter" | "concat" | "reverse" | "take" | "drop" | "range" => Some("LuxList*".to_string()),
                        // Operations returning Option
                        "head" | "tail" | "get" | "find" => Some("Option".to_string()),
                        // Operations returning Int
                        "length" | "fold" => Some("LuxInt".to_string()),
                        // Operations returning Bool
                        "isEmpty" | "any" | "all" => Some("LuxBool".to_string()),
                        _ => None,
                    }
                } else if effect.name == "Random" {
                    match operation.name.as_str() {
                        "int" => Some("LuxInt".to_string()),
                        "float" => Some("LuxFloat".to_string()),
                        "bool" => Some("LuxBool".to_string()),
                        _ => None,
                    }
                } else if effect.name == "Time" {
                    match operation.name.as_str() {
                        "now" => Some("LuxInt".to_string()),
                        "sleep" => Some("void".to_string()),
                        _ => None,
                    }
                } else if effect.name == "File" {
                    match operation.name.as_str() {
                        "read" => Some("LuxString".to_string()),
                        "write" | "append" | "delete" | "mkdir" => Some("void".to_string()),
                        "exists" | "isDir" => Some("LuxBool".to_string()),
                        _ => None,
                    }
                } else if effect.name == "Http" {
                    match operation.name.as_str() {
                        "get" | "post" | "put" | "delete" => Some("LuxString".to_string()),
                        _ => None,
                    }
                } else if effect.name == "Console" {
                    match operation.name.as_str() {
                        "print" => Some("void".to_string()),
                        "readLine" => Some("LuxString".to_string()),
                        "readInt" => Some("LuxInt".to_string()),
                        _ => None,
                    }
                } else if effect.name == "Process" {
                    match operation.name.as_str() {
                        "exec" | "cwd" => Some("LuxString".to_string()),
                        "env" => Some("Option".to_string()),
                        "args" => Some("LuxList*".to_string()),
                        _ => None,
                    }
                } else if effect.name == "String" {
                    match operation.name.as_str() {
                        "trim" => Some("LuxString".to_string()),
                        "length" => Some("LuxInt".to_string()),
                        "lines" | "split" => Some("LuxList*".to_string()),
                        "contains" => Some("LuxBool".to_string()),
                        "parseInt" | "parseFloat" => Some("Option".to_string()),
                        _ => None,
                    }
                } else {
                    None
                }
            }
            Expr::Match { arms, .. } => {
                // Type of match is the type of its arms
                Some(self.infer_match_result_type(arms))
            }
            _ => None,
        }
    }

    fn pattern_to_condition(&self, pattern: &Pattern, scrutinee: &str, type_name: Option<&str>) -> Result<String, CGenError> {
        match pattern {
            Pattern::Wildcard(_) => Ok("1".to_string()),
            Pattern::Var(_) => Ok("1".to_string()), // Var always matches, binding handled separately
            Pattern::Literal(lit) => {
                let lit_val = self.emit_literal_value(&lit.kind)?;
                // For strings, use strcmp instead of pointer comparison
                if matches!(&lit.kind, LiteralKind::String(_)) {
                    Ok(format!("strcmp({}, {}) == 0", scrutinee, lit_val))
                } else {
                    Ok(format!("{} == {}", scrutinee, lit_val))
                }
            }
            Pattern::Constructor { name, fields, .. } => {
                // Get the type name for proper tag generation
                let tn = type_name.unwrap_or("Option"); // Default fallback
                let tag_check = format!("{}.tag == {}_TAG_{}", scrutinee, tn, name.name.to_uppercase());

                // If there are nested patterns, we need to check those too
                if fields.is_empty() {
                    Ok(tag_check)
                } else {
                    let mut conditions = vec![tag_check];
                    let variant_lower = name.name.to_lowercase();

                    for (i, field_pattern) in fields.iter().enumerate() {
                        // Access the field data
                        let field_access = format!("{}.data.{}.field{}", scrutinee, variant_lower, i);
                        let field_condition = self.pattern_to_condition(field_pattern, &field_access, None)?;
                        if field_condition != "1" {
                            conditions.push(field_condition);
                        }
                    }

                    Ok(conditions.join(" && "))
                }
            }
            Pattern::Tuple { elements, .. } => {
                // For tuples, check each element pattern
                let mut conditions = Vec::new();
                for (i, elem_pattern) in elements.iter().enumerate() {
                    let elem_access = format!("{}.field{}", scrutinee, i);
                    let elem_condition = self.pattern_to_condition(elem_pattern, &elem_access, None)?;
                    if elem_condition != "1" {
                        conditions.push(elem_condition);
                    }
                }
                if conditions.is_empty() {
                    Ok("1".to_string())
                } else {
                    Ok(conditions.join(" && "))
                }
            }
            Pattern::Record { .. } => Ok("1".to_string()), // TODO: record pattern matching
        }
    }

    /// Try to infer the inner type of an Option expression
    /// For List.tail, List.head, etc., returns the element/list type
    fn infer_option_inner_type(&self, expr: &Expr) -> Option<String> {
        match expr {
            Expr::EffectOp { effect, operation, .. } => {
                if effect.name == "List" {
                    match operation.name.as_str() {
                        "head" | "get" | "find" => {
                            // These return Option<T> where T is the element type
                            // Default to LuxString for strings, but could be improved
                            Some("LuxString".to_string())
                        }
                        "tail" => {
                            // tail returns Option<List<T>> - so inner type is LuxList*
                            Some("LuxList*".to_string())
                        }
                        _ => None,
                    }
                } else if effect.name == "Process" && operation.name == "env" {
                    Some("LuxString".to_string())
                } else if effect.name == "String" && (operation.name == "parseInt" || operation.name == "parseFloat") {
                    if operation.name == "parseInt" {
                        Some("LuxInt".to_string())
                    } else {
                        Some("LuxFloat".to_string())
                    }
                } else {
                    None
                }
            }
            Expr::Call { func, .. } => {
                if let Expr::Field { object, field, .. } = func.as_ref() {
                    if let Expr::Var(module) = object.as_ref() {
                        if module.name == "List" {
                            match field.name.as_str() {
                                "head" | "get" | "find" => Some("LuxString".to_string()),
                                "tail" => Some("LuxList*".to_string()),
                                _ => None,
                            }
                        } else {
                            None
                        }
                    } else {
                        None
                    }
                } else {
                    None
                }
            }
            _ => None,
        }
    }

    /// Infer a variable's type by looking at how it's used in an expression
    fn infer_var_type_from_usage(&self, expr: &Expr, var_name: &str) -> Option<String> {
        match expr {
            Expr::Call { func, args, .. } => {
                // Check if the variable is used as an argument
                for (i, arg) in args.iter().enumerate() {
                    if let Expr::Var(ident) = arg {
                        if ident.name == var_name {
                            // Try to get the expected parameter type from function signature
                            if let Expr::Var(func_ident) = func.as_ref() {
                                if let Some(param_types) = self.function_param_types.get(&func_ident.name) {
                                    if let Some(param_type) = param_types.get(i) {
                                        return Some(param_type.clone());
                                    }
                                }
                            }
                        }
                    }
                    // Recursively check arguments
                    if let Some(t) = self.infer_var_type_from_usage(arg, var_name) {
                        return Some(t);
                    }
                }
                None
            }
            Expr::BinaryOp { left, right, .. } => {
                self.infer_var_type_from_usage(left, var_name)
                    .or_else(|| self.infer_var_type_from_usage(right, var_name))
            }
            Expr::Block { statements, result, .. } => {
                for stmt in statements {
                    if let crate::ast::Statement::Expr(e) = stmt {
                        if let Some(t) = self.infer_var_type_from_usage(e, var_name) {
                            return Some(t);
                        }
                    }
                }
                self.infer_var_type_from_usage(result, var_name)
            }
            Expr::If { then_branch, else_branch, .. } => {
                self.infer_var_type_from_usage(then_branch, var_name)
                    .or_else(|| self.infer_var_type_from_usage(else_branch, var_name))
            }
            _ => None,
        }
    }

    /// Extract variable bindings from a pattern.
    /// Returns a list of (var_name, c_expression, c_type) triples.
    fn extract_pattern_bindings(&self, pattern: &Pattern, scrutinee: &str, expected_type: Option<&str>) -> Vec<(String, String, String)> {
        match pattern {
            Pattern::Wildcard(_) => vec![],
            Pattern::Var(ident) => {
                let typ = expected_type.unwrap_or("LuxInt").to_string();
                let escaped_name = self.escape_c_keyword(&ident.name);
                vec![(escaped_name, scrutinee.to_string(), typ)]
            }
            Pattern::Literal(_) => vec![],
            Pattern::Constructor { name, fields, .. } => {
                let mut bindings = Vec::new();
                let variant_lower = name.name.to_lowercase();

                // Look up field types for this variant
                let type_name = self.variant_to_type.get(&name.name);
                let field_types = type_name.and_then(|tn| {
                    self.variant_field_types.get(&(tn.clone(), name.name.clone()))
                });

                for (i, field_pattern) in fields.iter().enumerate() {
                    let field_access = format!("{}.data.{}.field{}", scrutinee, variant_lower, i);
                    let mut field_type = field_types.and_then(|ft| ft.get(i)).map(|s| s.as_str());

                    // Special handling for built-in Option type
                    // Option fields are void* in C but we need to preserve type info
                    if name.name == "Some" && field_type.is_none() {
                        // For Option<T>, the inner value should be treated as void*
                        // but we can infer more specific types from context
                        // Default to void* for safety (requires cast at use site)
                        field_type = Some("void*");
                    }

                    bindings.extend(self.extract_pattern_bindings(field_pattern, &field_access, field_type));
                }

                bindings
            }
            Pattern::Tuple { elements, .. } => {
                let mut bindings = Vec::new();
                for (i, elem_pattern) in elements.iter().enumerate() {
                    let elem_access = format!("{}.field{}", scrutinee, i);
                    bindings.extend(self.extract_pattern_bindings(elem_pattern, &elem_access, None));
                }
                bindings
            }
            Pattern::Record { fields, .. } => {
                let mut bindings = Vec::new();
                for (field_name, field_pattern) in fields {
                    let field_access = format!("{}.{}", scrutinee, field_name.name);
                    bindings.extend(self.extract_pattern_bindings(field_pattern, &field_access, None));
                }
                bindings
            }
        }
    }

    fn emit_literal(&self, lit: &Literal) -> Result<String, CGenError> {
        self.emit_literal_value(&lit.kind)
    }

    fn emit_literal_value(&self, kind: &LiteralKind) -> Result<String, CGenError> {
        match kind {
            LiteralKind::Int(n) => Ok(format!("{}", n)),
            LiteralKind::Float(f) => Ok(format!("{}", f)),
            LiteralKind::Bool(b) => Ok(if *b { "true" } else { "false" }.to_string()),
            LiteralKind::String(s) => Ok(format!("\"{}\"", escape_c_string(s))),
            LiteralKind::Char(c) => Ok(format!("'{}'", c)),
            LiteralKind::Unit => Ok("NULL".to_string()),
        }
    }

    fn emit_global_let(&mut self, name: &Ident, value: &Expr) -> Result<(), CGenError> {
        let val = self.emit_expr(value)?;
        self.writeln(&format!("static LuxInt {} = {};", name.name, val));
        self.writeln("");
        Ok(())
    }

    fn emit_main_wrapper(&mut self, program: &Program) -> Result<(), CGenError> {
        // Check if there's a main function
        let has_main = program.declarations.iter().any(|d| {
            matches!(d, Declaration::Function(f) if f.name.name == "main")
        });

        // Check for top-level run expressions
        let has_run = program.declarations.iter().any(|d| {
            matches!(d, Declaration::Let(let_decl) if matches!(&let_decl.value, Expr::Run { .. }))
        });

        if has_main || has_run {
            self.writeln("int main(int argc, char** argv) {");
            self.indent += 1;

            // Store argc/argv for Process.args()
            self.writeln("lux_argc = argc;");
            self.writeln("lux_argv = argv;");
            self.writeln("");

            // Execute top-level let bindings with run expressions
            // Track if main was already called via a run expression
            let mut main_called_via_run = false;
            for decl in &program.declarations {
                if let Declaration::Let(let_decl) = decl {
                    if matches!(&let_decl.value, Expr::Run { .. }) {
                        if let Expr::Run { expr, .. } = &let_decl.value {
                            if let Expr::Call { func, .. } = expr.as_ref() {
                                if let Expr::Var(fn_name) = func.as_ref() {
                                    let mangled = self.mangle_name(&fn_name.name);
                                    // Track if this is a call to main
                                    if fn_name.name == "main" {
                                        main_called_via_run = true;
                                    }
                                    // Pass default evidence if function uses effects
                                    if self.effectful_functions.contains(&fn_name.name) {
                                        self.writeln(&format!("{}(&default_evidence);", mangled));
                                    } else {
                                        self.writeln(&format!("{}();", mangled));
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // If there's a main function and it wasn't already called via run, call it
            if has_main && !main_called_via_run {
                // Check if main uses effects (Console typically)
                if self.effectful_functions.contains("main") {
                    self.writeln("main_lux(&default_evidence);");
                } else {
                    self.writeln("main_lux();");
                }
            }

            // Check for memory leaks in debug mode
            if self.debug_rc {
                self.writeln("lux_rc_check_leaks();");
            }

            self.writeln("return 0;");
            self.indent -= 1;
            self.writeln("}");
        }
        Ok(())
    }

    fn type_to_c(&self, type_expr: &TypeExpr) -> Result<String, CGenError> {
        self.type_expr_to_c(type_expr)
    }

    /// Convert type to C, using pointers for self-referential types
    fn type_to_c_with_self_check(&self, type_expr: &TypeExpr, parent_type: &str) -> Result<String, CGenError> {
        if let TypeExpr::Named(ident) = type_expr {
            if ident.name == parent_type {
                // Self-referential type - use pointer
                return Ok(format!("{}*", parent_type));
            }
        }
        self.type_expr_to_c(type_expr)
    }

    fn type_expr_to_c(&self, type_expr: &TypeExpr) -> Result<String, CGenError> {
        match type_expr {
            TypeExpr::Named(ident) => {
                match ident.name.as_str() {
                    "Int" => Ok("LuxInt".to_string()),
                    "Float" => Ok("LuxFloat".to_string()),
                    "Bool" => Ok("LuxBool".to_string()),
                    "String" => Ok("LuxString".to_string()),
                    "Unit" => Ok("void".to_string()),
                    other => Ok(other.to_string()),
                }
            }
            TypeExpr::App(base, _) => {
                // Handle generic types
                if let TypeExpr::Named(name) = base.as_ref() {
                    match name.name.as_str() {
                        "List" => Ok("LuxList*".to_string()),
                        "Option" => Ok("Option".to_string()),
                        _ => Ok("void*".to_string()),
                    }
                } else {
                    Ok("void*".to_string())
                }
            }
            TypeExpr::Unit => Ok("void".to_string()),
            TypeExpr::Versioned { base, .. } => self.type_expr_to_c(base),
            TypeExpr::Function { .. } => Ok("LuxClosure*".to_string()),
            TypeExpr::Tuple(_) => Ok("void*".to_string()),
            TypeExpr::Record(_) => Ok("void*".to_string()),
        }
    }

    fn fresh_name(&mut self) -> usize {
        self.name_counter += 1;
        self.name_counter
    }

    // === RC Scope Management ===

    /// Push a new scope onto the RC scope stack
    fn push_rc_scope(&mut self) {
        self.rc_scopes.push(Vec::new());
    }

    /// Pop the current scope and emit decref calls for all variables
    fn pop_rc_scope(&mut self) {
        self.pop_rc_scope_except(None);
    }

    /// Pop the current scope and emit decref calls, skipping the named variable
    /// This is used when returning a variable from a block - we don't want to decref it
    fn pop_rc_scope_except(&mut self, skip_var: Option<&str>) {
        if let Some(scope) = self.rc_scopes.pop() {
            // Clone data we need to avoid borrow issues
            let variant_field_types = self.variant_field_types.clone();

            // Decref in reverse order (LIFO - last allocated, first freed)
            for var in scope.iter().rev() {
                // Skip the variable we're returning (if any)
                if let Some(skip) = skip_var {
                    if var.name == skip {
                        continue;
                    }
                }

                if let Some(adt_name) = &var.adt_type_name {
                    // ADT with pointer fields - need to decref the fields
                    self.emit_adt_field_cleanup(&var.name, adt_name, &variant_field_types);
                } else {
                    // Use specialized decref based on type (drop specialization)
                    self.emit_specialized_decref(&var.name, &var.c_type);
                }
            }
        }
    }

    /// Emit a specialized decref call based on the known type (drop specialization)
    /// This avoids the polymorphic lux_drop dispatch when we know the type at compile time
    fn emit_specialized_decref(&mut self, var_name: &str, c_type: &str) {
        match c_type {
            "LuxList*" => {
                self.writeln(&format!("lux_decref_list({});", var_name));
            }
            "LuxClosure*" => {
                self.writeln(&format!("lux_decref_closure({});", var_name));
            }
            "LuxString" => {
                self.writeln(&format!("lux_decref_string({});", var_name));
            }
            // Boxed primitives
            "void*" => {
                self.writeln(&format!("lux_decref_boxed({});", var_name));
            }
            // Fall back to generic decref for unknown types
            _ => {
                self.writeln(&format!("lux_decref({});", var_name));
            }
        }
    }

    /// Emit cleanup code for an ADT variable's pointer fields
    fn emit_adt_field_cleanup(&mut self, var_name: &str, adt_name: &str, variant_field_types: &HashMap<(String, String), Vec<String>>) {
        // Find all variants of this ADT with pointer fields
        let mut has_cleanup = false;

        for ((type_name, variant_name), field_types) in variant_field_types {
            if type_name != adt_name {
                continue;
            }
            let pointer_fields: Vec<(usize, &String)> = field_types.iter()
                .enumerate()
                .filter(|(_, t)| t.ends_with('*'))
                .collect();
            if !pointer_fields.is_empty() {
                if !has_cleanup {
                    self.writeln(&format!("switch ({}.tag) {{", var_name));
                    self.indent += 1;
                    has_cleanup = true;
                }
                let variant_upper = variant_name.to_uppercase();
                let variant_lower = variant_name.to_lowercase();
                self.writeln(&format!("case {}_TAG_{}: {{", adt_name, variant_upper));
                self.indent += 1;
                for (field_idx, _) in &pointer_fields {
                    self.writeln(&format!("lux_decref({}.data.{}.field{});", var_name, variant_lower, field_idx));
                }
                self.writeln("break;");
                self.indent -= 1;
                self.writeln("}");
            }
        }

        if has_cleanup {
            self.writeln("default: break;");
            self.indent -= 1;
            self.writeln("}");
        }
    }

    /// Register an RC-managed variable in the current scope
    fn register_rc_var(&mut self, name: &str, c_type: &str) {
        self.register_rc_var_with_adt(name, c_type, None);
    }

    fn register_rc_var_with_adt(&mut self, name: &str, c_type: &str, adt_type_name: Option<String>) {
        if let Some(scope) = self.rc_scopes.last_mut() {
            scope.push(RcVariable {
                name: name.to_string(),
                c_type: c_type.to_string(),
                adt_type_name,
            });
        }
    }

    /// Check if a variable is tracked for RC cleanup in any scope
    fn is_rc_tracked(&self, name: &str) -> bool {
        self.rc_scopes.iter().any(|scope| scope.iter().any(|var| var.name == name))
    }

    /// Check if a value is a temporary RC variable (starts with _ and is tracked)
    fn is_rc_temp(&self, name: &str) -> bool {
        name.starts_with("_") && self.is_rc_tracked(name)
    }

    /// Remove a variable from RC tracking (for ownership transfer)
    fn unregister_rc_var(&mut self, name: &str) {
        for scope in self.rc_scopes.iter_mut() {
            scope.retain(|var| var.name != name);
        }
    }

    /// Emit decrefs for all variables in all scopes (for early return)
    #[allow(dead_code)]
    fn emit_all_scope_cleanup(&mut self) {
        // Collect all decrefs first to avoid borrow issues
        let decrefs: Vec<String> = self.rc_scopes.iter().rev()
            .flat_map(|scope| scope.iter().rev())
            .map(|var| format!("lux_decref({});", var.name))
            .collect();

        for decref in decrefs {
            self.writeln(&decref);
        }
    }

    /// Check if a C type needs RC management
    fn is_rc_type(&self, c_type: &str) -> bool {
        // Pointer types that are RC-managed
        matches!(c_type, "LuxList*" | "LuxClosure*" | "void*")
            || c_type.ends_with("*") && c_type != "LuxString"
        // Note: LuxString (char*) needs special handling - only dynamic strings are RC
    }

    /// Check if a variable name is in the current RC scope
    fn is_var_in_current_rc_scope(&self, name: &str) -> bool {
        if let Some(scope) = self.rc_scopes.last() {
            scope.iter().any(|var| var.name == name)
        } else {
            false
        }
    }

    /// Check if an expression references RC-tracked variables from the current scope
    fn expr_uses_rc_vars_from_scope(&self, expr: &Expr) -> bool {
        match expr {
            Expr::Var(ident) => self.is_var_in_current_rc_scope(&ident.name),
            Expr::Call { func, args, .. } => {
                self.expr_uses_rc_vars_from_scope(func)
                    || args.iter().any(|a| self.expr_uses_rc_vars_from_scope(a))
            }
            Expr::BinaryOp { left, right, .. } => {
                self.expr_uses_rc_vars_from_scope(left)
                    || self.expr_uses_rc_vars_from_scope(right)
            }
            Expr::UnaryOp { operand, .. } => self.expr_uses_rc_vars_from_scope(operand),
            Expr::Field { object, .. } => self.expr_uses_rc_vars_from_scope(object),
            Expr::EffectOp { args, .. } => {
                args.iter().any(|a| self.expr_uses_rc_vars_from_scope(a))
            }
            Expr::If { condition, then_branch, else_branch, .. } => {
                self.expr_uses_rc_vars_from_scope(condition)
                    || self.expr_uses_rc_vars_from_scope(then_branch)
                    || self.expr_uses_rc_vars_from_scope(else_branch)
            }
            _ => false,
        }
    }

    /// Check if an expression creates a new RC-managed value that needs tracking
    fn expr_creates_rc_value(&self, expr: &Expr) -> bool {
        match expr {
            // List literals create new RC lists
            Expr::List { .. } => true,

            // Lambdas create RC-managed closures
            Expr::Lambda { .. } => true,

            // Calls to List.* / String.* that return RC values, or user functions
            Expr::Call { func, .. } => {
                if let Expr::Field { object, field, .. } = func.as_ref() {
                    if let Expr::Var(module) = object.as_ref() {
                        if module.name == "List" {
                            // These List operations return new lists
                            return matches!(field.name.as_str(),
                                "map" | "filter" | "concat" | "reverse" |
                                "take" | "drop" | "range"
                            );
                        }
                        if module.name == "String" {
                            // These String operations return new RC strings
                            return matches!(field.name.as_str(),
                                "trim" | "lines" | "split"
                            );
                        }
                    }
                }
                // Check if calling a user-defined function that returns an RC type
                if let Expr::Var(fn_name) = func.as_ref() {
                    if let Some(ret_type) = self.function_return_types.get(&fn_name.name) {
                        // Include LuxString since our string functions now return RC strings
                        return ret_type.ends_with('*') || ret_type == "LuxString";
                    }
                }
                false
            }

            // Effect operations that return RC values
            Expr::EffectOp { effect, operation, .. } => {
                if effect.name == "List" {
                    matches!(operation.name.as_str(),
                        "map" | "filter" | "concat" | "reverse" |
                        "take" | "drop" | "range"
                    )
                } else if effect.name == "Process" {
                    // Process.exec returns RC-managed string
                    matches!(operation.name.as_str(), "exec")
                } else if effect.name == "Console" {
                    // Console.readLine returns RC-managed string
                    matches!(operation.name.as_str(), "readLine")
                } else if effect.name == "File" {
                    // File.read returns RC-managed string
                    matches!(operation.name.as_str(), "read")
                } else if effect.name == "Http" {
                    // Http operations return RC-managed strings
                    matches!(operation.name.as_str(), "get" | "post" | "put" | "delete")
                } else if effect.name == "String" {
                    // String.trim, lines, split return RC values
                    matches!(operation.name.as_str(), "trim" | "lines" | "split")
                } else {
                    false
                }
            }

            // Variable references don't create new values - they borrow
            Expr::Var(_) => false,

            // Literals don't need RC (primitives or static strings)
            Expr::Literal(_) => false,

            _ => false,
        }
    }

    /// Check if an expression creates an ADT with pointer fields that need cleanup
    /// Returns Some(adt_type_name) if so, None otherwise
    fn expr_creates_adt_with_pointers(&self, expr: &Expr) -> Option<String> {
        match expr {
            // ADT constructor call
            Expr::Call { func, .. } => {
                if let Expr::Var(ident) = func.as_ref() {
                    // Check if this is an ADT constructor
                    if let Some(adt_name) = self.variant_to_type.get(&ident.name) {
                        // Check if this ADT has pointer fields
                        if self.adt_with_pointers.contains(adt_name) {
                            return Some(adt_name.clone());
                        }
                    }
                }
                None
            }
            _ => None,
        }
    }

    /// Check if an expression is a call to a function that returns a closure
    fn is_closure_returning_call(&self, expr: &Expr) -> bool {
        match expr {
            Expr::Lambda { .. } => true,
            Expr::Call { func, .. } => {
                // Check if we're calling a function known to return a closure
                if let Expr::Var(ident) = func.as_ref() {
                    self.closure_returning_functions.contains(&ident.name)
                } else {
                    false
                }
            }
            _ => false,
        }
    }

    /// Find free variables in an expression (variables not in bound set)
    fn find_free_vars(&self, expr: &Expr, bound: &HashSet<String>) -> Vec<String> {
        let mut free = Vec::new();
        self.collect_free_vars(expr, bound, &mut free);
        // Remove duplicates while preserving order
        let mut seen = HashSet::new();
        free.retain(|v| seen.insert(v.clone()));
        free
    }

    fn collect_free_vars(&self, expr: &Expr, bound: &HashSet<String>, free: &mut Vec<String>) {
        match expr {
            Expr::Var(ident) => {
                // If not bound locally and not a known function, it's a free variable
                if !bound.contains(&ident.name) && !self.functions.contains(&ident.name) {
                    free.push(ident.name.clone());
                }
            }
            Expr::Literal(_) => {}
            Expr::BinaryOp { left, right, .. } => {
                self.collect_free_vars(left, bound, free);
                self.collect_free_vars(right, bound, free);
            }
            Expr::UnaryOp { operand, .. } => {
                self.collect_free_vars(operand, bound, free);
            }
            Expr::If { condition, then_branch, else_branch, .. } => {
                self.collect_free_vars(condition, bound, free);
                self.collect_free_vars(then_branch, bound, free);
                self.collect_free_vars(else_branch, bound, free);
            }
            Expr::Call { func, args, .. } => {
                self.collect_free_vars(func, bound, free);
                for arg in args {
                    self.collect_free_vars(arg, bound, free);
                }
            }
            Expr::Block { statements, result, .. } => {
                let mut inner_bound = bound.clone();
                for stmt in statements {
                    match stmt {
                        Statement::Let { name, value, .. } => {
                            self.collect_free_vars(value, &inner_bound, free);
                            inner_bound.insert(name.name.clone());
                        }
                        Statement::Expr(e) => {
                            self.collect_free_vars(e, &inner_bound, free);
                        }
                    }
                }
                self.collect_free_vars(result, &inner_bound, free);
            }
            Expr::Lambda { params, body, .. } => {
                let mut inner_bound = bound.clone();
                for p in params {
                    inner_bound.insert(p.name.name.clone());
                }
                self.collect_free_vars(body, &inner_bound, free);
            }
            Expr::Record { fields, .. } => {
                for (_, val) in fields {
                    self.collect_free_vars(val, bound, free);
                }
            }
            Expr::Field { object, .. } => {
                self.collect_free_vars(object, bound, free);
            }
            Expr::Match { scrutinee, arms, .. } => {
                self.collect_free_vars(scrutinee, bound, free);
                for arm in arms {
                    // TODO: Handle pattern bindings
                    self.collect_free_vars(&arm.body, bound, free);
                }
            }
            Expr::EffectOp { args, .. } => {
                for arg in args {
                    self.collect_free_vars(arg, bound, free);
                }
            }
            Expr::Run { expr, .. } => {
                self.collect_free_vars(expr, bound, free);
            }
            Expr::Tuple { elements, .. } => {
                for e in elements {
                    self.collect_free_vars(e, bound, free);
                }
            }
            Expr::List { elements, .. } => {
                for e in elements {
                    self.collect_free_vars(e, bound, free);
                }
            }
            Expr::Resume { value, .. } => {
                self.collect_free_vars(value, bound, free);
            }
            Expr::Let { value, body, name, .. } => {
                self.collect_free_vars(value, bound, free);
                let mut inner_bound = bound.clone();
                inner_bound.insert(name.name.clone());
                self.collect_free_vars(body, &inner_bound, free);
            }
        }
    }

    /// Emit memoization lookup code for pure functions
    ///
    /// For pure functions, we generate a static memo table that caches results.
    /// This is a simple linear cache for now - a hash table would be more efficient
    /// for functions called with many different arguments.
    fn emit_memoization_lookup(&mut self, func_name: &str, params: &[Parameter], ret_type: &str) -> Result<(), CGenError> {
        let mangled = self.mangle_name(func_name);
        let memo_size = 64; // Fixed size memo table

        // Generate a hash expression from parameters
        let hash_expr = if params.len() == 1 {
            let p = &params[0];
            let c_type = self.type_expr_to_c(&p.typ)?;
            match c_type.as_str() {
                "LuxInt" => format!("((size_t){} & {})", self.escape_c_keyword(&p.name.name), memo_size - 1),
                "LuxString" => format!("(lux_string_hash({}) & {})", self.escape_c_keyword(&p.name.name), memo_size - 1),
                "LuxBool" => format!("((size_t){} & {})", self.escape_c_keyword(&p.name.name), memo_size - 1),
                _ => format!("((size_t)(uintptr_t){} & {})", self.escape_c_keyword(&p.name.name), memo_size - 1),
            }
        } else {
            // For multiple params, combine hashes
            let mut parts = Vec::new();
            for (i, p) in params.iter().enumerate() {
                let c_type = self.type_expr_to_c(&p.typ)?;
                let hash = match c_type.as_str() {
                    "LuxInt" => format!("(size_t){}", self.escape_c_keyword(&p.name.name)),
                    "LuxString" => format!("lux_string_hash({})", self.escape_c_keyword(&p.name.name)),
                    "LuxBool" => format!("(size_t){}", self.escape_c_keyword(&p.name.name)),
                    _ => format!("(size_t)(uintptr_t){}", self.escape_c_keyword(&p.name.name)),
                };
                // Mix with prime numbers for better distribution
                let prime = [31, 37, 41, 43, 47, 53, 59, 61][i % 8];
                parts.push(format!("({} * {})", hash, prime));
            }
            format!("(({}) & {})", parts.join(" ^ "), memo_size - 1)
        };

        // Emit static memo table
        self.writeln(&format!("// Memoization for pure function {}", func_name));
        self.writeln(&format!("static struct {{ bool valid; {} result; {} key; }} _memo_{}[{}];",
                              ret_type, self.generate_key_type(params)?, mangled, memo_size));
        self.writeln(&format!("size_t _memo_idx = {};", hash_expr));

        // Check if cached
        self.writeln(&format!("if (_memo_{}[_memo_idx].valid && {}) {{",
                              mangled, self.generate_key_compare(params, &format!("_memo_{}[_memo_idx]", mangled))?));
        self.indent += 1;
        self.writeln(&format!("return _memo_{}[_memo_idx].result;", mangled));
        self.indent -= 1;
        self.writeln("}");

        Ok(())
    }

    /// Emit memoization store code for pure functions
    fn emit_memoization_store(&mut self, func_name: &str, params: &[Parameter], result_expr: &str) -> Result<(), CGenError> {
        let mangled = self.mangle_name(func_name);

        // Store result in memo table
        self.writeln(&format!("_memo_{}[_memo_idx].valid = true;", mangled));
        self.writeln(&format!("_memo_{}[_memo_idx].result = {};", mangled, result_expr));
        for p in params {
            let name = self.escape_c_keyword(&p.name.name);
            self.writeln(&format!("_memo_{}[_memo_idx].key_{} = {};", mangled, name, name));
        }

        Ok(())
    }

    /// Generate the key type for memoization (stores all parameter values)
    fn generate_key_type(&self, params: &[Parameter]) -> Result<String, CGenError> {
        let mut fields = Vec::new();
        for p in params {
            let c_type = self.type_expr_to_c(&p.typ)?;
            let name = self.escape_c_keyword(&p.name.name);
            fields.push(format!("{} key_{}", c_type, name));
        }
        Ok(fields.join("; "))
    }

    /// Generate key comparison expression for memoization lookup
    fn generate_key_compare(&self, params: &[Parameter], memo_entry: &str) -> Result<String, CGenError> {
        let mut comparisons = Vec::new();
        for p in params {
            let c_type = self.type_expr_to_c(&p.typ)?;
            let name = self.escape_c_keyword(&p.name.name);
            let cmp = match c_type.as_str() {
                "LuxString" => format!("lux_string_equals({}.key_{}, {})", memo_entry, name, name),
                _ => format!("{}.key_{} == {}", memo_entry, name, name),
            };
            comparisons.push(cmp);
        }
        Ok(comparisons.join(" && "))
    }

    /// Emit idempotent function optimization
    ///
    /// For idempotent functions (f(f(x)) = f(x)), we track if the function
    /// has already been called with the same arguments to avoid redundant computation.
    /// This is useful for initialization functions, setters with same value, etc.
    fn emit_idempotent_check(&mut self, func_name: &str, params: &[Parameter], ret_type: &str) -> Result<(), CGenError> {
        let mangled = self.mangle_name(func_name);

        self.writeln(&format!("// Idempotent optimization for {}", func_name));
        self.writeln(&format!("static bool _idem_{}_called = false;", mangled));
        self.writeln(&format!("static {} _idem_{}_result;", ret_type, mangled));

        // For idempotent functions with no params, just return the cached result
        if params.is_empty() {
            self.writeln(&format!("if (_idem_{}_called) {{ return _idem_{}_result; }}", mangled, mangled));
        } else {
            // For params, we still use memoization-like caching
            self.writeln(&format!("static {} _idem_{}_key;", self.generate_key_type(params)?, mangled));
            let key_compare = self.generate_key_compare_inline(params, &format!("_idem_{}_key", mangled))?;
            self.writeln(&format!("if (_idem_{}_called && {}) {{ return _idem_{}_result; }}", mangled, key_compare, mangled));
        }

        Ok(())
    }

    /// Emit idempotent function store
    fn emit_idempotent_store(&mut self, func_name: &str, params: &[Parameter], result_expr: &str) -> Result<(), CGenError> {
        let mangled = self.mangle_name(func_name);

        self.writeln(&format!("_idem_{}_called = true;", mangled));
        self.writeln(&format!("_idem_{}_result = {};", mangled, result_expr));
        for p in params {
            let name = self.escape_c_keyword(&p.name.name);
            self.writeln(&format!("_idem_{}_key_{} = {};", mangled, name, name));
        }

        Ok(())
    }

    /// Generate key comparison expression inline (for idempotent check)
    fn generate_key_compare_inline(&self, params: &[Parameter], prefix: &str) -> Result<String, CGenError> {
        let mut comparisons = Vec::new();
        for p in params {
            let c_type = self.type_expr_to_c(&p.typ)?;
            let name = self.escape_c_keyword(&p.name.name);
            let cmp = match c_type.as_str() {
                "LuxString" => format!("lux_string_equals({}.{}, {})", prefix, name, name),
                _ => format!("{}_{} == {}", prefix, name, name),
            };
            comparisons.push(cmp);
        }
        Ok(comparisons.join(" && "))
    }

    /// Emit deterministic function hint as a comment
    ///
    /// Deterministic functions always produce the same output for the same inputs.
    /// This hint helps C compilers (GCC/Clang) with optimization.
    fn emit_deterministic_attribute(&mut self, func_name: &str) {
        // GCC and Clang support __attribute__((const)) for pure functions without side effects
        // that only depend on their arguments (not even global state)
        self.writeln(&format!("// OPTIMIZATION: {} is deterministic - output depends only on inputs", func_name));
    }

    /// Emit commutative function hint
    ///
    /// For commutative functions (f(a, b) = f(b, a)), we can normalize argument order
    /// to improve common subexpression elimination (CSE).
    fn emit_commutative_optimization(&mut self, func_name: &str, params: &[Parameter]) -> Result<(), CGenError> {
        if params.len() != 2 {
            return Ok(());  // Commutativity only makes sense for binary functions
        }

        let p1 = &params[0];
        let p2 = &params[1];
        let c_type1 = self.type_expr_to_c(&p1.typ)?;
        let c_type2 = self.type_expr_to_c(&p2.typ)?;

        // Only do swapping for comparable types
        if c_type1 == c_type2 && matches!(c_type1.as_str(), "LuxInt" | "LuxFloat") {
            let name1 = self.escape_c_keyword(&p1.name.name);
            let name2 = self.escape_c_keyword(&p2.name.name);

            self.writeln(&format!("// Commutative optimization for {}: normalize argument order", func_name));
            self.writeln(&format!("if ({} > {}) {{", name1, name2));
            self.indent += 1;
            self.writeln(&format!("{} _swap_tmp = {}; {} = {}; {} = _swap_tmp;",
                                  c_type1, name1, name1, name2, name2));
            self.indent -= 1;
            self.writeln("}");
        }

        Ok(())
    }

    fn writeln(&mut self, line: &str) {
        let indent = "    ".repeat(self.indent);
        writeln!(self.output, "{}{}", indent, line).unwrap();
    }
}

impl Default for CBackend {
    fn default() -> Self {
        Self::new()
    }
}

/// Escape a string for use as a C string literal
fn escape_c_string(s: &str) -> String {
    let mut result = String::with_capacity(s.len() * 2);
    for c in s.chars() {
        match c {
            '\\' => result.push_str("\\\\"),
            '"' => result.push_str("\\\""),
            '\n' => result.push_str("\\n"),
            '\r' => result.push_str("\\r"),
            '\t' => result.push_str("\\t"),
            '\0' => result.push_str("\\0"),
            c if c.is_ascii_control() => {
                // Escape other control characters as hex
                result.push_str(&format!("\\x{:02x}", c as u8));
            }
            c => result.push(c),
        }
    }
    result
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::parser::Parser;

    fn generate(source: &str) -> Result<String, CGenError> {
        let program = Parser::parse_source(source).expect("Parse error");
        let mut backend = CBackend::new();
        backend.generate(&program)
    }

    #[test]
    fn test_simple_function() {
        let source = r#"
            fn add(a: Int, b: Int): Int = a + b
        "#;
        let c_code = generate(source).unwrap();
        assert!(c_code.contains("LuxInt add_lux(LuxInt a, LuxInt b)"));
        assert!(c_code.contains("return (a + b)"));
    }

    #[test]
    fn test_factorial() {
        let source = r#"
            fn factorial(n: Int): Int =
                if n <= 1 then 1 else n * factorial(n - 1)
        "#;
        let c_code = generate(source).unwrap();
        assert!(c_code.contains("LuxInt factorial_lux(LuxInt n)"));
        assert!(c_code.contains("factorial_lux((n - 1))"));
    }

    #[test]
    fn test_console_effect() {
        let source = r#"
            fn greet(): Unit with {Console} = Console.print("Hello")
        "#;
        let c_code = generate(source).unwrap();
        assert!(c_code.contains("lux_console_print"));
    }

    #[test]
    fn test_closure_basic() {
        let source = r#"
            fn makeAdder(n: Int): fn(Int): Int =
                fn(x: Int): Int => x + n
        "#;
        let c_code = generate(source).unwrap();
        // Should have closure type
        assert!(c_code.contains("LuxClosure"));
        // Should have environment struct
        assert!(c_code.contains("LuxEnv_"));
        // Should have lambda function
        assert!(c_code.contains("lambda_"));
        // Function should return LuxClosure*
        assert!(c_code.contains("LuxClosure* makeAdder_lux"));
    }

    #[test]
    fn test_closure_call() {
        let source = r#"
            fn makeAdder(n: Int): fn(Int): Int =
                fn(x: Int): Int => x + n

            fn test(): Int = {
                let add5 = makeAdder(5)
                add5(10)
            }
        "#;
        let c_code = generate(source).unwrap();
        // Local should be typed as LuxClosure*
        assert!(c_code.contains("LuxClosure* add5"));
        // Should have indirect call syntax
        assert!(c_code.contains("->fn_ptr"));
        assert!(c_code.contains("->env"));
    }

    #[test]
    fn test_pure_function_memoization() {
        let source = r#"
            fn fib(n: Int): Int is pure =
                if n <= 1 then n else fib(n - 1) + fib(n - 2)
        "#;
        let c_code = generate(source).unwrap();
        // Pure function should have memoization infrastructure
        assert!(c_code.contains("// Memoization for pure function fib"));
        assert!(c_code.contains("_memo_fib_lux"));
        assert!(c_code.contains("_memo_idx"));
        // Should check cache before computation
        assert!(c_code.contains(".valid &&"));
        // Should store result in cache
        assert!(c_code.contains(".valid = true"));
        assert!(c_code.contains(".result ="));
    }

    #[test]
    fn test_non_pure_function_no_memoization() {
        let source = r#"
            fn add(a: Int, b: Int): Int = a + b
        "#;
        let c_code = generate(source).unwrap();
        // Non-pure function should NOT have memoization
        assert!(!c_code.contains("// Memoization for pure function add"));
        assert!(!c_code.contains("_memo_add_lux"));
    }
}
