/*
 * xs_jit_builder.c - C implementation for XS::JIT code builder
 *
 * This provides a fluent C API for generating C code strings dynamically.
 */

#define PERL_NO_GET_CONTEXT
#include "xs_jit_builder.h"
#include <stdarg.h>

/* ============================================
 * Internal helpers
 * ============================================ */

static void add_indent(pTHX_ XS_JIT_Builder* b) {
    int i;
    if (b->use_tabs) {
        for (i = 0; i < b->indent; i++) {
            sv_catpvs(b->code, "\t");
        }
    } else {
        int spaces = b->indent * b->indent_width;
        for (i = 0; i < spaces; i++) {
            sv_catpvs(b->code, " ");
        }
    }
}

/* ============================================
 * Lifecycle
 * ============================================ */

XS_JIT_Builder* xs_jit_builder_new(pTHX) {
    XS_JIT_Builder* b;
    Newxz(b, 1, XS_JIT_Builder);
    b->code = newSVpvs("");
    b->indent = 0;
    b->indent_width = 4;
    b->use_tabs = 0;
    b->in_function = 0;
    return b;
}

void xs_jit_builder_free(pTHX_ XS_JIT_Builder* b) {
    /* Note: does NOT free code SV - caller should get it first if needed */
    if (b) {
        SvREFCNT_dec(b->code);
        Safefree(b);
    }
}

SV* xs_jit_builder_code(pTHX_ XS_JIT_Builder* b) {
    SvREFCNT_inc(b->code);
    return b->code;
}

const char* xs_jit_builder_cstr(pTHX_ XS_JIT_Builder* b) {
    return SvPV_nolen(b->code);
}

void xs_jit_builder_reset(pTHX_ XS_JIT_Builder* b) {
    SvREFCNT_dec(b->code);
    b->code = newSVpvs("");
    b->indent = 0;
    b->in_function = 0;
}

/* ============================================
 * Low-level output
 * ============================================ */

void xs_jit_line(pTHX_ XS_JIT_Builder* b, const char* fmt, ...) {
    va_list args;
    
    add_indent(aTHX_ b);
    
    va_start(args, fmt);
    sv_vcatpvf(b->code, fmt, &args);
    va_end(args);
    
    sv_catpvs(b->code, "\n");
}

void xs_jit_raw(pTHX_ XS_JIT_Builder* b, const char* fmt, ...) {
    va_list args;
    
    va_start(args, fmt);
    sv_vcatpvf(b->code, fmt, &args);
    va_end(args);
}

void xs_jit_comment(pTHX_ XS_JIT_Builder* b, const char* text) {
    add_indent(aTHX_ b);
    sv_catpvf(b->code, "/* %s */\n", text);
}

void xs_jit_blank(pTHX_ XS_JIT_Builder* b) {
    sv_catpvs(b->code, "\n");
}

/* ============================================
 * Indentation control
 * ============================================ */

void xs_jit_indent(XS_JIT_Builder* b) {
    b->indent++;
}

void xs_jit_dedent(XS_JIT_Builder* b) {
    if (b->indent > 0) {
        b->indent--;
    }
}

void xs_jit_set_indent_width(XS_JIT_Builder* b, int width) {
    b->indent_width = width;
}

void xs_jit_set_use_tabs(XS_JIT_Builder* b, int use_tabs) {
    b->use_tabs = use_tabs;
}

/* ============================================
 * Blocks and structure
 * ============================================ */

void xs_jit_block_start(pTHX_ XS_JIT_Builder* b) {
    xs_jit_line(aTHX_ b, "{");
    b->indent++;
}

void xs_jit_block_end(pTHX_ XS_JIT_Builder* b) {
    b->indent--;
    xs_jit_line(aTHX_ b, "}");
}

/* ============================================
 * XS Function structure
 * ============================================ */

void xs_jit_xs_function(pTHX_ XS_JIT_Builder* b, const char* name) {
    xs_jit_line(aTHX_ b, "XS_EUPXS(%s) {", name);
    b->indent++;
    b->in_function = 1;
}

void xs_jit_xs_preamble(pTHX_ XS_JIT_Builder* b) {
    xs_jit_line(aTHX_ b, "dVAR; dXSARGS;");
    xs_jit_line(aTHX_ b, "PERL_UNUSED_VAR(cv);");
}

void xs_jit_xs_end(pTHX_ XS_JIT_Builder* b) {
    b->indent--;
    xs_jit_line(aTHX_ b, "}");
    b->in_function = 0;
}

void xs_jit_xs_return(pTHX_ XS_JIT_Builder* b, int count) {
    xs_jit_line(aTHX_ b, "XSRETURN(%d);", count);
}

void xs_jit_xs_return_undef(pTHX_ XS_JIT_Builder* b) {
    xs_jit_line(aTHX_ b, "ST(0) = &PL_sv_undef;");
    xs_jit_line(aTHX_ b, "XSRETURN(1);");
}

void xs_jit_croak_usage(pTHX_ XS_JIT_Builder* b, const char* usage) {
    xs_jit_line(aTHX_ b, "croak_xs_usage(cv, \"%s\");", usage);
}

/* ============================================
 * Control flow
 * ============================================ */

void xs_jit_if(pTHX_ XS_JIT_Builder* b, const char* cond) {
    xs_jit_line(aTHX_ b, "if (%s) {", cond);
    b->indent++;
}

void xs_jit_elsif(pTHX_ XS_JIT_Builder* b, const char* cond) {
    b->indent--;
    xs_jit_line(aTHX_ b, "} else if (%s) {", cond);
    b->indent++;
}

void xs_jit_else(pTHX_ XS_JIT_Builder* b) {
    b->indent--;
    xs_jit_line(aTHX_ b, "} else {");
    b->indent++;
}

void xs_jit_endif(pTHX_ XS_JIT_Builder* b) {
    b->indent--;
    xs_jit_line(aTHX_ b, "}");
}

void xs_jit_for(pTHX_ XS_JIT_Builder* b, const char* init, const char* cond, const char* incr) {
    xs_jit_line(aTHX_ b, "for (%s; %s; %s) {", init, cond, incr);
    b->indent++;
}

void xs_jit_while(pTHX_ XS_JIT_Builder* b, const char* cond) {
    xs_jit_line(aTHX_ b, "while (%s) {", cond);
    b->indent++;
}

void xs_jit_endloop(pTHX_ XS_JIT_Builder* b) {
    b->indent--;
    xs_jit_line(aTHX_ b, "}");
}

/* ============================================
 * Variable declarations
 * ============================================ */

void xs_jit_declare(pTHX_ XS_JIT_Builder* b, const char* type, const char* name, const char* value) {
    if (value && *value) {
        xs_jit_line(aTHX_ b, "%s %s = %s;", type, name, value);
    } else {
        xs_jit_line(aTHX_ b, "%s %s;", type, name);
    }
}

void xs_jit_declare_sv(pTHX_ XS_JIT_Builder* b, const char* name, const char* value) {
    xs_jit_declare(aTHX_ b, "SV*", name, value);
}

void xs_jit_declare_hv(pTHX_ XS_JIT_Builder* b, const char* name, const char* value) {
    xs_jit_declare(aTHX_ b, "HV*", name, value);
}

void xs_jit_declare_av(pTHX_ XS_JIT_Builder* b, const char* name, const char* value) {
    xs_jit_declare(aTHX_ b, "AV*", name, value);
}

void xs_jit_declare_int(pTHX_ XS_JIT_Builder* b, const char* name, const char* value) {
    xs_jit_declare(aTHX_ b, "int", name, value);
}

void xs_jit_declare_iv(pTHX_ XS_JIT_Builder* b, const char* name, const char* value) {
    xs_jit_declare(aTHX_ b, "IV", name, value);
}

void xs_jit_declare_nv(pTHX_ XS_JIT_Builder* b, const char* name, const char* value) {
    xs_jit_declare(aTHX_ b, "NV", name, value);
}

void xs_jit_declare_pv(pTHX_ XS_JIT_Builder* b, const char* name, const char* value) {
    xs_jit_declare(aTHX_ b, "const char*", name, value);
}

void xs_jit_assign(pTHX_ XS_JIT_Builder* b, const char* var, const char* value) {
    xs_jit_line(aTHX_ b, "%s = %s;", var, value);
}

/* ============================================
 * Common XS patterns
 * ============================================ */

void xs_jit_get_self(pTHX_ XS_JIT_Builder* b) {
    xs_jit_declare_sv(aTHX_ b, "self", "ST(0)");
}

void xs_jit_get_self_hv(pTHX_ XS_JIT_Builder* b) {
    xs_jit_declare_sv(aTHX_ b, "self", "ST(0)");
    xs_jit_declare_hv(aTHX_ b, "hv", "(HV*)SvRV(self)");
}

void xs_jit_get_self_av(pTHX_ XS_JIT_Builder* b) {
    xs_jit_declare_sv(aTHX_ b, "self", "ST(0)");
    xs_jit_declare_av(aTHX_ b, "av", "(AV*)SvRV(self)");
}

/* ============================================
 * Hash operations
 * ============================================ */

void xs_jit_hv_fetch(pTHX_ XS_JIT_Builder* b, const char* hv, const char* key, STRLEN len, const char* result_var) {
    xs_jit_line(aTHX_ b, "SV** %s = hv_fetch(%s, \"%s\", %lu, 0);", result_var, hv, key, (unsigned long)len);
}

void xs_jit_hv_fetch_sv(pTHX_ XS_JIT_Builder* b, const char* hv, const char* key_expr, const char* len_expr, const char* result_var) {
    xs_jit_line(aTHX_ b, "SV** %s = hv_fetch(%s, %s, %s, 0);", result_var, hv, key_expr, len_expr);
}

void xs_jit_hv_store(pTHX_ XS_JIT_Builder* b, const char* hv, const char* key, STRLEN len, const char* value) {
    xs_jit_line(aTHX_ b, "(void)hv_store(%s, \"%s\", %lu, %s, 0);", hv, key, (unsigned long)len, value);
}

void xs_jit_hv_store_sv(pTHX_ XS_JIT_Builder* b, const char* hv, const char* key_expr, const char* len_expr, const char* value) {
    xs_jit_line(aTHX_ b, "(void)hv_store(%s, %s, %s, %s, 0);", hv, key_expr, len_expr, value);
}

void xs_jit_hv_fetch_return(pTHX_ XS_JIT_Builder* b, const char* hv, const char* key, STRLEN len) {
    xs_jit_line(aTHX_ b, "SV** valp = hv_fetch(%s, \"%s\", %lu, 0);", hv, key, (unsigned long)len);
    xs_jit_line(aTHX_ b, "ST(0) = (valp && *valp) ? *valp : &PL_sv_undef;");
    xs_jit_line(aTHX_ b, "XSRETURN(1);");
}

/* ============================================
 * Array operations
 * ============================================ */

void xs_jit_av_fetch(pTHX_ XS_JIT_Builder* b, const char* av, const char* index, const char* result_var) {
    xs_jit_line(aTHX_ b, "SV** %s = av_fetch(%s, %s, 0);", result_var, av, index);
}

void xs_jit_av_store(pTHX_ XS_JIT_Builder* b, const char* av, const char* index, const char* value) {
    xs_jit_line(aTHX_ b, "av_store(%s, %s, %s);", av, index, value);
}

void xs_jit_av_push(pTHX_ XS_JIT_Builder* b, const char* av, const char* value) {
    xs_jit_line(aTHX_ b, "av_push(%s, %s);", av, value);
}

void xs_jit_av_len(pTHX_ XS_JIT_Builder* b, const char* av, const char* result_var) {
    xs_jit_line(aTHX_ b, "I32 %s = av_len(%s);", result_var, av);
}

/* ============================================
 * SV creation
 * ============================================ */

void xs_jit_new_sv_iv(pTHX_ XS_JIT_Builder* b, const char* result_var, const char* value) {
    xs_jit_line(aTHX_ b, "SV* %s = newSViv(%s);", result_var, value);
}

void xs_jit_new_sv_nv(pTHX_ XS_JIT_Builder* b, const char* result_var, const char* value) {
    xs_jit_line(aTHX_ b, "SV* %s = newSVnv(%s);", result_var, value);
}

void xs_jit_new_sv_pv(pTHX_ XS_JIT_Builder* b, const char* result_var, const char* str, STRLEN len) {
    xs_jit_line(aTHX_ b, "SV* %s = newSVpvn(\"%s\", %lu);", result_var, str, (unsigned long)len);
}

void xs_jit_mortal(pTHX_ XS_JIT_Builder* b, const char* sv) {
    xs_jit_line(aTHX_ b, "%s = sv_2mortal(%s);", sv, sv);
}

/* ============================================
 * Type checking
 * ============================================ */

void xs_jit_check_items(pTHX_ XS_JIT_Builder* b, int min, int max, const char* usage) {
    char cond[128];
    if (min == max) {
        snprintf(cond, sizeof(cond), "items != %d", min);
    } else if (max < 0) {
        snprintf(cond, sizeof(cond), "items < %d", min);
    } else {
        snprintf(cond, sizeof(cond), "items < %d || items > %d", min, max);
    }
    xs_jit_if(aTHX_ b, cond);
    xs_jit_croak_usage(aTHX_ b, usage);
    xs_jit_endif(aTHX_ b);
}

void xs_jit_check_defined(pTHX_ XS_JIT_Builder* b, const char* sv, const char* error_msg) {
    char cond[128];
    snprintf(cond, sizeof(cond), "!SvOK(%s)", sv);
    xs_jit_if(aTHX_ b, cond);
    xs_jit_croak(aTHX_ b, error_msg);
    xs_jit_endif(aTHX_ b);
}

void xs_jit_check_ref_type(pTHX_ XS_JIT_Builder* b, const char* sv, const char* type, const char* error_msg) {
    char cond[256];
    snprintf(cond, sizeof(cond), "!SvROK(%s) || SvTYPE(SvRV(%s)) != %s", sv, sv, type);
    xs_jit_if(aTHX_ b, cond);
    xs_jit_croak(aTHX_ b, error_msg);
    xs_jit_endif(aTHX_ b);
}

void xs_jit_check_hashref(pTHX_ XS_JIT_Builder* b, const char* sv, const char* error_msg) {
    xs_jit_check_ref_type(aTHX_ b, sv, "SVt_PVHV", error_msg);
}

void xs_jit_check_arrayref(pTHX_ XS_JIT_Builder* b, const char* sv, const char* error_msg) {
    xs_jit_check_ref_type(aTHX_ b, sv, "SVt_PVAV", error_msg);
}

/* ============================================
 * SV conversion (extract values from SV)
 * ============================================ */

void xs_jit_sv_to_iv(pTHX_ XS_JIT_Builder* b, const char* result_var, const char* sv) {
    xs_jit_line(aTHX_ b, "IV %s = SvIV(%s);", result_var, sv);
}

void xs_jit_sv_to_uv(pTHX_ XS_JIT_Builder* b, const char* result_var, const char* sv) {
    xs_jit_line(aTHX_ b, "UV %s = SvUV(%s);", result_var, sv);
}

void xs_jit_sv_to_nv(pTHX_ XS_JIT_Builder* b, const char* result_var, const char* sv) {
    xs_jit_line(aTHX_ b, "NV %s = SvNV(%s);", result_var, sv);
}

void xs_jit_sv_to_pv(pTHX_ XS_JIT_Builder* b, const char* result_var, const char* len_var, const char* sv) {
    if (len_var && *len_var) {
        xs_jit_line(aTHX_ b, "STRLEN %s;", len_var);
        xs_jit_line(aTHX_ b, "const char* %s = SvPV(%s, %s);", result_var, sv, len_var);
    } else {
        xs_jit_line(aTHX_ b, "const char* %s = SvPV_nolen(%s);", result_var, sv);
    }
}

void xs_jit_sv_to_bool(pTHX_ XS_JIT_Builder* b, const char* result_var, const char* sv) {
    xs_jit_line(aTHX_ b, "int %s = SvTRUE(%s);", result_var, sv);
}

/* ============================================
 * Return helpers
 * ============================================ */

void xs_jit_return_iv(pTHX_ XS_JIT_Builder* b, const char* value) {
    xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(newSViv(%s));", value);
    xs_jit_xs_return(aTHX_ b, 1);
}

void xs_jit_return_uv(pTHX_ XS_JIT_Builder* b, const char* value) {
    xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(newSVuv(%s));", value);
    xs_jit_xs_return(aTHX_ b, 1);
}

void xs_jit_return_nv(pTHX_ XS_JIT_Builder* b, const char* value) {
    xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(newSVnv(%s));", value);
    xs_jit_xs_return(aTHX_ b, 1);
}

void xs_jit_return_pv(pTHX_ XS_JIT_Builder* b, const char* str, const char* len) {
    /* str is used as-is - caller must quote literal strings with \" */
    if (len && *len) {
        xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(newSVpvn(%s, %s));", str, len);
    } else {
        xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(newSVpv(%s, 0));", str);
    }
    xs_jit_xs_return(aTHX_ b, 1);
}

void xs_jit_return_sv(pTHX_ XS_JIT_Builder* b, const char* sv) {
    xs_jit_line(aTHX_ b, "ST(0) = %s;", sv);
    xs_jit_xs_return(aTHX_ b, 1);
}

void xs_jit_return_yes(pTHX_ XS_JIT_Builder* b) {
    xs_jit_line(aTHX_ b, "ST(0) = &PL_sv_yes;");
    xs_jit_xs_return(aTHX_ b, 1);
}

void xs_jit_return_no(pTHX_ XS_JIT_Builder* b) {
    xs_jit_line(aTHX_ b, "ST(0) = &PL_sv_no;");
    xs_jit_xs_return(aTHX_ b, 1);
}

void xs_jit_return_self(pTHX_ XS_JIT_Builder* b) {
    xs_jit_line(aTHX_ b, "ST(0) = self;");
    xs_jit_xs_return(aTHX_ b, 1);
}

/* ============================================
 * Common method patterns
 * ============================================ */

void xs_jit_method_start(pTHX_ XS_JIT_Builder* b, const char* func_name, int min_args, int max_args, const char* usage) {
    xs_jit_xs_function(aTHX_ b, func_name);
    xs_jit_xs_preamble(aTHX_ b);
    if (min_args > 0 || max_args >= 0) {
        xs_jit_check_items(aTHX_ b, min_args, max_args, usage);
    }
    xs_jit_get_self_hv(aTHX_ b);
}

/* Predicate (returns true/false based on attribute existence) */
void xs_jit_predicate(pTHX_ XS_JIT_Builder* b, const char* func_name, const char* attr_name, STRLEN attr_len) {
    xs_jit_xs_function(aTHX_ b, func_name);
    xs_jit_xs_preamble(aTHX_ b);
    xs_jit_get_self_hv(aTHX_ b);
    xs_jit_line(aTHX_ b, "SV** valp = hv_fetch(hv, \"%s\", %lu, 0);", attr_name, (unsigned long)attr_len);
    xs_jit_if(aTHX_ b, "valp != NULL");
    xs_jit_return_yes(aTHX_ b);
    xs_jit_else(aTHX_ b);
    xs_jit_return_no(aTHX_ b);
    xs_jit_endif(aTHX_ b);
    xs_jit_xs_end(aTHX_ b);
}

/* Clearer (deletes an attribute) */
void xs_jit_clearer(pTHX_ XS_JIT_Builder* b, const char* func_name, const char* attr_name, STRLEN attr_len) {
    xs_jit_xs_function(aTHX_ b, func_name);
    xs_jit_xs_preamble(aTHX_ b);
    xs_jit_get_self_hv(aTHX_ b);
    xs_jit_line(aTHX_ b, "(void)hv_delete(hv, \"%s\", %lu, G_DISCARD);", attr_name, (unsigned long)attr_len);
    xs_jit_return_self(aTHX_ b);
    xs_jit_xs_end(aTHX_ b);
}

/* ============================================
 * Error handling
 * ============================================ */

void xs_jit_croak(pTHX_ XS_JIT_Builder* b, const char* message) {
    xs_jit_line(aTHX_ b, "croak(\"%s\");", message);
}

void xs_jit_warn(pTHX_ XS_JIT_Builder* b, const char* message) {
    xs_jit_line(aTHX_ b, "warn(\"%s\");", message);
}

/* ============================================
 * Prebuilt patterns
 * ============================================ */

void xs_jit_ro_accessor(pTHX_ XS_JIT_Builder* b, const char* func_name, const char* attr_name, STRLEN attr_len) {
    xs_jit_xs_function(aTHX_ b, func_name);
    xs_jit_xs_preamble(aTHX_ b);
    
    xs_jit_if(aTHX_ b, "items > 1");
    xs_jit_croak(aTHX_ b, "Read only attribute cannot be set");
    xs_jit_endif(aTHX_ b);
    
    xs_jit_get_self_hv(aTHX_ b);
    xs_jit_hv_fetch_return(aTHX_ b, "hv", attr_name, attr_len);
    
    xs_jit_xs_end(aTHX_ b);
}

void xs_jit_rw_accessor(pTHX_ XS_JIT_Builder* b, const char* func_name, const char* attr_name, STRLEN attr_len) {
    xs_jit_xs_function(aTHX_ b, func_name);
    xs_jit_xs_preamble(aTHX_ b);
    
    xs_jit_get_self_hv(aTHX_ b);
    
    xs_jit_if(aTHX_ b, "items > 1");
    xs_jit_line(aTHX_ b, "SV* new_val = newSVsv(ST(1));");
    xs_jit_hv_store(aTHX_ b, "hv", attr_name, attr_len, "new_val");
    xs_jit_line(aTHX_ b, "ST(0) = new_val;");
    xs_jit_line(aTHX_ b, "XSRETURN(1);");
    xs_jit_endif(aTHX_ b);
    
    xs_jit_hv_fetch_return(aTHX_ b, "hv", attr_name, attr_len);
    
    xs_jit_xs_end(aTHX_ b);
}

void xs_jit_constructor(pTHX_ XS_JIT_Builder* b, const char* func_name, const char* class_name, XS_JIT_Attr* attrs, int num_attrs) {
    int i;
    
    xs_jit_xs_function(aTHX_ b, func_name);
    xs_jit_xs_preamble(aTHX_ b);
    
    xs_jit_comment(aTHX_ b, "Get class name");
    xs_jit_declare_sv(aTHX_ b, "class_sv", "ST(0)");
    xs_jit_line(aTHX_ b, "const char* classname = SvPV_nolen(class_sv);");
    xs_jit_blank(aTHX_ b);
    
    xs_jit_comment(aTHX_ b, "Parse args hash if provided");
    xs_jit_declare_hv(aTHX_ b, "args", "NULL");
    xs_jit_if(aTHX_ b, "items > 1 && SvROK(ST(1)) && SvTYPE(SvRV(ST(1))) == SVt_PVHV");
    xs_jit_line(aTHX_ b, "args = (HV*)SvRV(ST(1));");
    xs_jit_endif(aTHX_ b);
    xs_jit_blank(aTHX_ b);
    
    xs_jit_comment(aTHX_ b, "Create new hash for object");
    xs_jit_declare_hv(aTHX_ b, "hv", "newHV()");
    xs_jit_blank(aTHX_ b);
    
    xs_jit_comment(aTHX_ b, "Process attributes");
    for (i = 0; i < num_attrs; i++) {
        const char* name = attrs[i].name;
        STRLEN len = attrs[i].len;
        
        xs_jit_line(aTHX_ b, "{");
        b->indent++;
        xs_jit_line(aTHX_ b, "SV** %s_valp = args ? hv_fetch(args, \"%s\", %lu, 0) : NULL;", name, name, (unsigned long)len);
        /* Build condition string for if */
        SV* cond_sv = newSVpvf("%s_valp && SvOK(*%s_valp)", name, name);
        xs_jit_if(aTHX_ b, SvPV_nolen(cond_sv));
        SvREFCNT_dec(cond_sv);
        xs_jit_line(aTHX_ b, "(void)hv_store(hv, \"%s\", %lu, newSVsv(*%s_valp), 0);", name, (unsigned long)len, name);
        xs_jit_endif(aTHX_ b);
        b->indent--;
        xs_jit_line(aTHX_ b, "}");
    }
    xs_jit_blank(aTHX_ b);
    
    xs_jit_comment(aTHX_ b, "Bless and return");
    xs_jit_declare_sv(aTHX_ b, "self", "newRV_noinc((SV*)hv)");
    xs_jit_line(aTHX_ b, "sv_bless(self, gv_stashpv(classname, GV_ADD));");
    xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(self);");
    xs_jit_line(aTHX_ b, "XSRETURN(1);");
    
    xs_jit_xs_end(aTHX_ b);
}

/* ============================================
 * Op-based accessors (array-based objects with inline ops)
 * ============================================ */

void xs_jit_op_ro_accessor(pTHX_ XS_JIT_Builder* b, const char* func_name, IV slot) {
    xs_jit_xs_function(aTHX_ b, func_name);
    xs_jit_xs_preamble(aTHX_ b);
    
    xs_jit_if(aTHX_ b, "items > 1");
    xs_jit_croak(aTHX_ b, "Read only attributes cannot be set");
    xs_jit_endif(aTHX_ b);
    
    xs_jit_line(aTHX_ b, "SV** ary = AvARRAY((AV*)SvRV(ST(0)));");
    xs_jit_line(aTHX_ b, "ST(0) = ary[%ld] ? ary[%ld] : &PL_sv_undef;", (long)slot, (long)slot);
    xs_jit_line(aTHX_ b, "XSRETURN(1);");
    
    xs_jit_xs_end(aTHX_ b);
}

void xs_jit_op_rw_accessor(pTHX_ XS_JIT_Builder* b, const char* func_name, IV slot) {
    xs_jit_xs_function(aTHX_ b, func_name);
    xs_jit_xs_preamble(aTHX_ b);
    
    xs_jit_line(aTHX_ b, "AV* av = (AV*)SvRV(ST(0));");
    
    xs_jit_if(aTHX_ b, "items > 1");
    xs_jit_line(aTHX_ b, "SV* new_val = newSVsv(ST(1));");
    xs_jit_line(aTHX_ b, "av_store(av, %ld, new_val);", (long)slot);
    xs_jit_line(aTHX_ b, "ST(0) = new_val;");
    xs_jit_line(aTHX_ b, "XSRETURN(1);");
    xs_jit_endif(aTHX_ b);
    
    xs_jit_line(aTHX_ b, "SV** ary = AvARRAY(av);");
    xs_jit_line(aTHX_ b, "ST(0) = ary[%ld] ? ary[%ld] : &PL_sv_undef;", (long)slot, (long)slot);
    xs_jit_line(aTHX_ b, "XSRETURN(1);");
    
    xs_jit_xs_end(aTHX_ b);
}

/* ============================================
 * Custom op builder (pp functions)
 * ============================================ */

void xs_jit_pp_start(pTHX_ XS_JIT_Builder* b, const char* name) {
    xs_jit_line(aTHX_ b, "static OP* S_pp_%s(pTHX) {", name);
    b->indent++;
}

void xs_jit_pp_end(pTHX_ XS_JIT_Builder* b) {
    b->indent--;
    xs_jit_line(aTHX_ b, "}");
    xs_jit_blank(aTHX_ b);
}

void xs_jit_pp_dsp(pTHX_ XS_JIT_Builder* b) {
    xs_jit_line(aTHX_ b, "dSP;");
}

void xs_jit_pp_get_self(pTHX_ XS_JIT_Builder* b) {
    xs_jit_line(aTHX_ b, "SV* self = TOPs;");
}

void xs_jit_pp_pop_self(pTHX_ XS_JIT_Builder* b) {
    xs_jit_line(aTHX_ b, "SV* self = POPs;");
}

void xs_jit_pp_pop_sv(pTHX_ XS_JIT_Builder* b, const char* name) {
    xs_jit_line(aTHX_ b, "SV* %s = POPs;", name);
}

void xs_jit_pp_pop_nv(pTHX_ XS_JIT_Builder* b, const char* name) {
    xs_jit_line(aTHX_ b, "NV %s = POPn;", name);
}

void xs_jit_pp_pop_iv(pTHX_ XS_JIT_Builder* b, const char* name) {
    xs_jit_line(aTHX_ b, "IV %s = POPi;", name);
}

void xs_jit_pp_get_slots(pTHX_ XS_JIT_Builder* b) {
    xs_jit_line(aTHX_ b, "SV** ary = AvARRAY((AV*)SvRV(self));");
}

void xs_jit_pp_slot(pTHX_ XS_JIT_Builder* b, const char* name, IV slot) {
    xs_jit_line(aTHX_ b, "SV* %s = ary[%ld] ? ary[%ld] : &PL_sv_undef;", name, (long)slot, (long)slot);
}

void xs_jit_pp_return_sv(pTHX_ XS_JIT_Builder* b, const char* sv_expr) {
    xs_jit_line(aTHX_ b, "SETs(%s);", sv_expr);
    xs_jit_line(aTHX_ b, "return NORMAL;");
}

void xs_jit_pp_return_nv(pTHX_ XS_JIT_Builder* b, const char* nv_expr) {
    xs_jit_line(aTHX_ b, "SETs(sv_2mortal(newSVnv(%s)));", nv_expr);
    xs_jit_line(aTHX_ b, "return NORMAL;");
}

void xs_jit_pp_return_iv(pTHX_ XS_JIT_Builder* b, const char* iv_expr) {
    xs_jit_line(aTHX_ b, "SETs(sv_2mortal(newSViv(%s)));", iv_expr);
    xs_jit_line(aTHX_ b, "return NORMAL;");
}

void xs_jit_pp_return_pv(pTHX_ XS_JIT_Builder* b, const char* pv_expr) {
    xs_jit_line(aTHX_ b, "SETs(sv_2mortal(newSVpv(%s, 0)));", pv_expr);
    xs_jit_line(aTHX_ b, "return NORMAL;");
}

void xs_jit_pp_return(pTHX_ XS_JIT_Builder* b) {
    xs_jit_line(aTHX_ b, "return NORMAL;");
}

/* ============================================
 * Call checker builder
 * ============================================ */

void xs_jit_ck_start(pTHX_ XS_JIT_Builder* b, const char* name) {
    xs_jit_line(aTHX_ b, "static OP* S_ck_%s(pTHX_ OP* entersubop, GV* namegv, SV* ckobj) {", name);
    b->indent++;
    xs_jit_line(aTHX_ b, "PERL_UNUSED_ARG(namegv);");
}

void xs_jit_ck_end(pTHX_ XS_JIT_Builder* b) {
    b->indent--;
    xs_jit_line(aTHX_ b, "}");
    xs_jit_blank(aTHX_ b);
}

void xs_jit_ck_preamble(pTHX_ XS_JIT_Builder* b) {
    xs_jit_line(aTHX_ b, "OP* parent = entersubop;");
    xs_jit_line(aTHX_ b, "OP* pushmark = cUNOPx(entersubop)->op_first;");
    xs_jit_blank(aTHX_ b);
    xs_jit_line(aTHX_ b, "if (!OpHAS_SIBLING(pushmark)) {");
    b->indent++;
    xs_jit_line(aTHX_ b, "parent = pushmark;");
    xs_jit_line(aTHX_ b, "pushmark = cUNOPx(pushmark)->op_first;");
    b->indent--;
    xs_jit_line(aTHX_ b, "}");
    xs_jit_blank(aTHX_ b);
    xs_jit_line(aTHX_ b, "OP* selfop = OpSIBLING(pushmark);");
    xs_jit_line(aTHX_ b, "if (!selfop || selfop->op_type == OP_RV2CV || selfop->op_type == OP_NULL) {");
    b->indent++;
    xs_jit_line(aTHX_ b, "return entersubop;");
    b->indent--;
    xs_jit_line(aTHX_ b, "}");
    xs_jit_blank(aTHX_ b);
}

void xs_jit_ck_build_unop(pTHX_ XS_JIT_Builder* b, const char* pp_func, const char* targ_expr) {
    xs_jit_line(aTHX_ b, "op_sibling_splice(parent, pushmark, 1, NULL);");
    xs_jit_line(aTHX_ b, "op_free(entersubop);");
    xs_jit_blank(aTHX_ b);
    xs_jit_line(aTHX_ b, "UNOP* newop;");
    xs_jit_line(aTHX_ b, "NewOp(1234, newop, 1, UNOP);");
    xs_jit_line(aTHX_ b, "newop->op_type = OP_CUSTOM;");
    xs_jit_line(aTHX_ b, "newop->op_ppaddr = %s;", pp_func);
    xs_jit_line(aTHX_ b, "newop->op_flags = OPf_KIDS | OPf_WANT_SCALAR;");
    xs_jit_line(aTHX_ b, "newop->op_private = 0;");
    xs_jit_line(aTHX_ b, "newop->op_targ = (PADOFFSET)(%s);", targ_expr);
    xs_jit_blank(aTHX_ b);
    xs_jit_line(aTHX_ b, "op_sibling_splice((OP*)newop, NULL, 0, selfop);");
    xs_jit_blank(aTHX_ b);
    xs_jit_line(aTHX_ b, "return (OP*)newop;");
}

void xs_jit_ck_build_binop(pTHX_ XS_JIT_Builder* b, const char* pp_func, const char* targ_expr) {
    xs_jit_line(aTHX_ b, "OP* valop = OpSIBLING(selfop);");
    xs_jit_line(aTHX_ b, "if (!valop || valop->op_type == OP_RV2CV || valop->op_type == OP_NULL) {");
    b->indent++;
    xs_jit_line(aTHX_ b, "return entersubop;");
    b->indent--;
    xs_jit_line(aTHX_ b, "}");
    xs_jit_blank(aTHX_ b);
    xs_jit_line(aTHX_ b, "op_sibling_splice(parent, pushmark, 2, NULL);");
    xs_jit_line(aTHX_ b, "op_free(entersubop);");
    xs_jit_blank(aTHX_ b);
    xs_jit_line(aTHX_ b, "BINOP* newop;");
    xs_jit_line(aTHX_ b, "NewOp(1234, newop, 1, BINOP);");
    xs_jit_line(aTHX_ b, "newop->op_type = OP_CUSTOM;");
    xs_jit_line(aTHX_ b, "newop->op_ppaddr = %s;", pp_func);
    xs_jit_line(aTHX_ b, "newop->op_flags = OPf_KIDS | OPf_STACKED | OPf_WANT_SCALAR;");
    xs_jit_line(aTHX_ b, "newop->op_private = 1;");
    xs_jit_line(aTHX_ b, "newop->op_targ = (PADOFFSET)(%s);", targ_expr);
    xs_jit_blank(aTHX_ b);
    xs_jit_line(aTHX_ b, "OpMORESIB_set(selfop, valop);");
    xs_jit_line(aTHX_ b, "OpLASTSIB_set(valop, (OP*)newop);");
    xs_jit_line(aTHX_ b, "newop->op_first = selfop;");
    xs_jit_line(aTHX_ b, "newop->op_last = valop;");
    xs_jit_blank(aTHX_ b);
    xs_jit_line(aTHX_ b, "return (OP*)newop;");
}

void xs_jit_ck_fallback(pTHX_ XS_JIT_Builder* b) {
    xs_jit_line(aTHX_ b, "return entersubop;");
}

/* ============================================
 * XOP registration helpers
 * ============================================ */

void xs_jit_xop_declare(pTHX_ XS_JIT_Builder* b, const char* name, const char* pp_func, const char* desc) {
    xs_jit_line(aTHX_ b, "static XOP xop_%s;", name);
    xs_jit_blank(aTHX_ b);
    xs_jit_line(aTHX_ b, "static void register_xop_%s(pTHX) {", name);
    b->indent++;
    xs_jit_line(aTHX_ b, "static int registered = 0;");
    xs_jit_line(aTHX_ b, "if (registered) return;");
    xs_jit_blank(aTHX_ b);
    xs_jit_line(aTHX_ b, "XopENTRY_set(&xop_%s, xop_name, \"%s\");", name, name);
    xs_jit_line(aTHX_ b, "XopENTRY_set(&xop_%s, xop_desc, \"%s\");", name, desc);
    xs_jit_line(aTHX_ b, "XopENTRY_set(&xop_%s, xop_class, OA_UNOP);", name);
    xs_jit_line(aTHX_ b, "Perl_custom_op_register(aTHX_ %s, &xop_%s);", pp_func, name);
    xs_jit_blank(aTHX_ b);
    xs_jit_line(aTHX_ b, "registered = 1;");
    b->indent--;
    xs_jit_line(aTHX_ b, "}");
    xs_jit_blank(aTHX_ b);
}

void xs_jit_register_checker(pTHX_ XS_JIT_Builder* b, const char* cv_expr, const char* ck_func, const char* ckobj_expr) {
    xs_jit_line(aTHX_ b, "cv_set_call_checker_flags(%s, %s, %s, 0);", cv_expr, ck_func, ckobj_expr);
}

/* ============================================
 * Inline op support
 * ============================================ */

/* For cv_set_call_checker - need Perl 5.14+ */
#ifndef cv_set_call_checker_flags
#define cv_set_call_checker_flags(cv, ckfun, ckobj, ckflags) \
    cv_set_call_checker(cv, ckfun, ckobj)
#endif

/* XOP descriptors for custom ops */
static XOP xs_jit_xop_getter;
static XOP xs_jit_xop_setter;
static int xs_jit_xops_registered = 0;

/* Forward declarations */
static OP* S_pp_xs_jit_get(pTHX);
static OP* S_pp_xs_jit_set(pTHX);
static OP* S_ck_xs_jit_get(pTHX_ OP* entersubop, GV* namegv, SV* ckobj);
static OP* S_ck_xs_jit_set(pTHX_ OP* entersubop, GV* namegv, SV* ckobj);

/* Initialize inline op subsystem */
void xs_jit_inline_init(pTHX) {
    if (xs_jit_xops_registered) return;
    
    /* Initialize getter XOP */
    XopENTRY_set(&xs_jit_xop_getter, xop_name, "xs_jit_get");
    XopENTRY_set(&xs_jit_xop_getter, xop_desc, "XS::JIT inline getter");
    XopENTRY_set(&xs_jit_xop_getter, xop_class, OA_UNOP);
    Perl_custom_op_register(aTHX_ S_pp_xs_jit_get, &xs_jit_xop_getter);
    
    /* Initialize setter XOP */
    XopENTRY_set(&xs_jit_xop_setter, xop_name, "xs_jit_set");
    XopENTRY_set(&xs_jit_xop_setter, xop_desc, "XS::JIT inline setter");
    XopENTRY_set(&xs_jit_xop_setter, xop_class, OA_BINOP);
    Perl_custom_op_register(aTHX_ S_pp_xs_jit_set, &xs_jit_xop_setter);
    
    xs_jit_xops_registered = 1;
}

/*
 * pp_xs_jit_get - Ultra-fast getter custom op
 * 
 * Stack: self -> [result]
 * Slot index stored in op_targ
 */
static OP* S_pp_xs_jit_get(pTHX) {
    dSP;
    SV* self = TOPs;
    PADOFFSET slot_index = PL_op->op_targ;
    
    SV** ary = AvARRAY((AV*)SvRV(self));
    SETs(ary[slot_index] ? ary[slot_index] : &PL_sv_undef);
    
    return NORMAL;
}

/*
 * pp_xs_jit_set - Ultra-fast setter custom op
 *
 * Stack: self, [value] -> [result]
 * Slot index stored in op_targ
 */
static OP* S_pp_xs_jit_set(pTHX) {
    dSP;
    PADOFFSET slot_index = PL_op->op_targ;
    
    /* Check if we have a value argument (setter mode) */
    if (PL_op->op_private & 1) {
        /* Setter: self, value on stack */
        SV* value = POPs;
        SV* self = TOPs;
        AV* av = (AV*)SvRV(self);
        
        SvREFCNT_inc(value);
        av_store(av, slot_index, value);
        SETs(value);
    } else {
        /* Getter: just self on stack */
        SV* self = TOPs;
        SV** ary = AvARRAY((AV*)SvRV(self));
        SETs(ary[slot_index] ? ary[slot_index] : &PL_sv_undef);
    }
    
    return NORMAL;
}

/*
 * S_ck_xs_jit_get - Call checker for read-only accessors
 */
static OP* S_ck_xs_jit_get(pTHX_ OP* entersubop, GV* namegv, SV* ckobj) {
    OP* parent;
    OP* pushmark;
    OP* selfop;
    UNOP* newop;
    
    PERL_UNUSED_ARG(namegv);
    
    IV slot_index = SvIV(ckobj);
    
    parent = entersubop;
    pushmark = cUNOPx(entersubop)->op_first;
    
    if (!OpHAS_SIBLING(pushmark)) {
        parent = pushmark;
        pushmark = cUNOPx(pushmark)->op_first;
    }
    
    selfop = OpSIBLING(pushmark);
    
    if (!selfop || selfop->op_type == OP_RV2CV || selfop->op_type == OP_NULL) {
        return entersubop;
    }
    
    /* Check for extra arguments (setter call on ro) */
    OP* nextop = OpSIBLING(selfop);
    if (nextop && nextop->op_type != OP_RV2CV && nextop->op_type != OP_NULL) {
        return entersubop;
    }
    
    /* Detach selfop */
    op_sibling_splice(parent, pushmark, 1, NULL);
    op_free(entersubop);
    
    /* Create custom UNOP */
    NewOp(1234, newop, 1, UNOP);
    newop->op_type = OP_CUSTOM;
    newop->op_ppaddr = S_pp_xs_jit_get;
    newop->op_flags = OPf_KIDS | OPf_WANT_SCALAR;
    newop->op_private = 0;
    newop->op_targ = (PADOFFSET)slot_index;
    
    op_sibling_splice((OP*)newop, NULL, 0, selfop);
    
    return (OP*)newop;
}

/*
 * S_ck_xs_jit_set - Call checker for read-write accessors
 */
static OP* S_ck_xs_jit_set(pTHX_ OP* entersubop, GV* namegv, SV* ckobj) {
    OP* parent;
    OP* pushmark;
    OP* selfop;
    OP* valop;
    
    PERL_UNUSED_ARG(namegv);
    
    IV slot_index = SvIV(ckobj);
    
    parent = entersubop;
    pushmark = cUNOPx(entersubop)->op_first;
    
    if (!OpHAS_SIBLING(pushmark)) {
        parent = pushmark;
        pushmark = cUNOPx(pushmark)->op_first;
    }
    
    selfop = OpSIBLING(pushmark);
    if (!selfop || selfop->op_type == OP_RV2CV || selfop->op_type == OP_NULL) {
        return entersubop;
    }
    
    valop = OpSIBLING(selfop);
    
    /* Determine getter vs setter */
    int is_setter = 0;
    if (valop && valop->op_type != OP_RV2CV && valop->op_type != OP_NULL) {
        OP* afterval = OpSIBLING(valop);
        if (!afterval || afterval->op_type == OP_RV2CV || afterval->op_type == OP_NULL) {
            is_setter = 1;
        } else {
            return entersubop;
        }
    }
    
    if (is_setter) {
        BINOP* newop;
        
        op_sibling_splice(parent, pushmark, 2, NULL);
        op_free(entersubop);
        
        NewOp(1234, newop, 1, BINOP);
        newop->op_type = OP_CUSTOM;
        newop->op_ppaddr = S_pp_xs_jit_set;
        newop->op_flags = OPf_KIDS | OPf_STACKED | OPf_WANT_SCALAR;
        newop->op_private = 1;  /* Flag: is setter */
        newop->op_targ = (PADOFFSET)slot_index;
        
        OpMORESIB_set(selfop, valop);
        OpLASTSIB_set(valop, (OP*)newop);
        newop->op_first = selfop;
        newop->op_last = valop;
        
        return (OP*)newop;
    } else {
        UNOP* newop;
        
        op_sibling_splice(parent, pushmark, 1, NULL);
        op_free(entersubop);
        
        NewOp(1234, newop, 1, UNOP);
        newop->op_type = OP_CUSTOM;
        newop->op_ppaddr = S_pp_xs_jit_set;
        newop->op_flags = OPf_KIDS | OPf_WANT_SCALAR;
        newop->op_private = 0;  /* Flag: is getter */
        newop->op_targ = (PADOFFSET)slot_index;
        
        op_sibling_splice((OP*)newop, NULL, 0, selfop);
        
        return (OP*)newop;
    }
}

/* Register inline op for a CV */
int xs_jit_inline_register(pTHX_ CV* cv, XS_JIT_InlineType type, 
                           IV slot, const char* key, STRLEN key_len) {
    PERL_UNUSED_ARG(key);
    PERL_UNUSED_ARG(key_len);
    
    if (!cv) return 0;
    
    xs_jit_inline_init(aTHX);
    
    SV* ckobj = newSViv(slot);
    
    switch (type) {
        case XS_JIT_INLINE_GETTER:
            cv_set_call_checker_flags(cv, S_ck_xs_jit_get, ckobj, 0);
            break;
        case XS_JIT_INLINE_SETTER:
            cv_set_call_checker_flags(cv, S_ck_xs_jit_set, ckobj, 0);
            break;
        case XS_JIT_INLINE_HV_GETTER:
        case XS_JIT_INLINE_HV_SETTER:
            /* TODO: Implement hash-based inline ops */
            SvREFCNT_dec(ckobj);
            return 0;
        default:
            SvREFCNT_dec(ckobj);
            return 0;
    }
    
    return 1;
}

/* Check if CV has inline op */
XS_JIT_InlineType xs_jit_inline_get_type(pTHX_ CV* cv) {
    MAGIC* mg;
    
    if (!cv) return XS_JIT_INLINE_NONE;
    
    mg = mg_find((SV*)cv, PERL_MAGIC_checkcall);
    if (!mg) return XS_JIT_INLINE_NONE;
    
    /* Check which checker function is registered */
    if (mg->mg_ptr == (char*)S_ck_xs_jit_get) {
        return XS_JIT_INLINE_GETTER;
    } else if (mg->mg_ptr == (char*)S_ck_xs_jit_set) {
        return XS_JIT_INLINE_SETTER;
    }
    
    return XS_JIT_INLINE_NONE;
}
