#include "cvm_core.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <ctype.h>
#ifdef _WIN32
#  include <windows.h>
#else
#  include <unistd.h>
#endif

static int arg_num(Runtime *rt, Value v, double *out, const char *fn) {
    if (v.type == VAL_INT) { *out = (double)v.as.i; return 1; }
    if (v.type == VAL_NUM) { *out = v.as.num; return 1; }
    snprintf(rt->errbuf, sizeof(rt->errbuf), "函数 '%s' 需要数字参数", fn);
    rt->has_error = 1;
    return 0;
}

static Value b_print(Runtime *rt, int argc, Value *a) {
    for (int i = 0; i < argc; ++i) {
        char *s = val_to_str(&rt->arena, a[i]);
        if (i) fputc(' ', stdout);
        fputs(s, stdout);
    }
    fflush(stdout);
    return val_nil();
}
static Value b_println(Runtime *rt, int argc, Value *a) {
    b_print(rt, argc, a);
    fputc('\n', stdout);
    return val_nil();
}
static Value b_sqrt(Runtime *rt, int argc, Value *a) {
    double x; if (argc != 1 || !arg_num(rt, a[0], &x, "sqrt")) return val_nil();
    return val_num(sqrt(x));
}
static Value b_pow(Runtime *rt, int argc, Value *a) {
    double x, y; if (argc != 2 || !arg_num(rt, a[0], &x, "pow") || !arg_num(rt, a[1], &y, "pow")) return val_nil();
    return val_num(pow(x, y));
}
static Value b_abs(Runtime *rt, int argc, Value *a) {
    double x; if (argc != 1 || !arg_num(rt, a[0], &x, "abs")) return val_nil();
    return val_num(fabs(x));
}
static Value b_floor(Runtime *rt, int argc, Value *a) {
    double x; if (argc != 1 || !arg_num(rt, a[0], &x, "floor")) return val_nil();
    return val_num(floor(x));
}
static Value b_ceil(Runtime *rt, int argc, Value *a) {
    double x; if (argc != 1 || !arg_num(rt, a[0], &x, "ceil")) return val_nil();
    return val_num(ceil(x));
}
static Value b_round(Runtime *rt, int argc, Value *a) {
    double x; if (argc != 1 || !arg_num(rt, a[0], &x, "round")) return val_nil();
    return val_num((double)((long long)(x + (x >= 0 ? 0.5 : -0.5))));
}
static Value b_rand(Runtime *rt, int argc, Value *a) {
    (void)argc; (void)a;
    return val_num((double)rand() / (double)RAND_MAX);
}
static Value b_time(Runtime *rt, int argc, Value *a) {
    (void)argc; (void)a;
    return val_num((double)time(NULL));
}
static Value b_clock_ms(Runtime *rt, int argc, Value *a) {
    (void)argc; (void)a;
    return val_num((double)clock() * 1000.0 / (double)CLOCKS_PER_SEC);
}
static Value b_len(Runtime *rt, int argc, Value *a) {
    if (argc != 1) { snprintf(rt->errbuf, sizeof(rt->errbuf), "len 需要 1 个参数"); rt->has_error = 1; return val_nil(); }
    if (a[0].type == VAL_STR)  return val_num((double)strlen(a[0].as.str));
    if (a[0].type == VAL_ARRAY) return val_num((double)arr_len((const Arr *)a[0].as.arr));
    snprintf(rt->errbuf, sizeof(rt->errbuf), "len 需要字符串或数组"); rt->has_error = 1; return val_nil();
}

/* ---- 数组内置 ---- */
static Value b_push(Runtime *rt, int argc, Value *a) {
    if (argc < 2 || a[0].type != VAL_ARRAY) { snprintf(rt->errbuf, sizeof(rt->errbuf), "push(arr, v, ...) 需要数组作为首个参数"); rt->has_error = 1; return val_nil(); }
    for (int i = 1; i < argc; ++i) arr_append(&rt->arena, (Arr *)a[0].as.arr, a[i]);
    return a[0];
}
static Value b_arr_get(Runtime *rt, int argc, Value *a) {
    if (argc != 2 || a[0].type != VAL_ARRAY) { snprintf(rt->errbuf, sizeof(rt->errbuf), "arr_get(arr, key) 用法错误"); rt->has_error = 1; return val_nil(); }
    ArrEntry *e = arr_lookup(rt, (Arr *)a[0].as.arr, a[1]);
    return e ? e->value : val_nil();
}
static Value b_arr_set(Runtime *rt, int argc, Value *a) {
    if (argc != 3 || a[0].type != VAL_ARRAY) { snprintf(rt->errbuf, sizeof(rt->errbuf), "arr_set(arr, key, val) 用法错误"); rt->has_error = 1; return val_nil(); }
    arr_set_from_key(rt, (Arr *)a[0].as.arr, a[1], a[2]);
    return a[0];
}
static Value b_arr_has(Runtime *rt, int argc, Value *a) {
    if (argc != 2 || a[0].type != VAL_ARRAY) { snprintf(rt->errbuf, sizeof(rt->errbuf), "arr_has(arr, key) 用法错误"); rt->has_error = 1; return val_nil(); }
    return val_bool(arr_lookup(rt, (Arr *)a[0].as.arr, a[1]) != NULL);
}
static Value b_arr_del(Runtime *rt, int argc, Value *a) {
    if (argc != 2 || a[0].type != VAL_ARRAY) { snprintf(rt->errbuf, sizeof(rt->errbuf), "arr_del(arr, key) 用法错误"); rt->has_error = 1; return val_nil(); }
    return val_bool(arr_del((Arr *)a[0].as.arr, a[1]));
}
static Value b_arr_keys(Runtime *rt, int argc, Value *a) {
    if (argc != 1 || a[0].type != VAL_ARRAY) { snprintf(rt->errbuf, sizeof(rt->errbuf), "arr_keys(arr) 需要数组"); rt->has_error = 1; return val_nil(); }
    return val_array(arr_keys(&rt->arena, (const Arr *)a[0].as.arr));
}
static Value b_arr_values(Runtime *rt, int argc, Value *a) {
    if (argc != 1 || a[0].type != VAL_ARRAY) { snprintf(rt->errbuf, sizeof(rt->errbuf), "arr_values(arr) 需要数组"); rt->has_error = 1; return val_nil(); }
    return val_array(arr_values(&rt->arena, (const Arr *)a[0].as.arr));
}
static Value b_arr_merge(Runtime *rt, int argc, Value *a) {
    if (argc != 2 || a[0].type != VAL_ARRAY || a[1].type != VAL_ARRAY) { snprintf(rt->errbuf, sizeof(rt->errbuf), "arr_merge(a, b) 需要两个数组"); rt->has_error = 1; return val_nil(); }
    Arr *dst = (Arr *)arena_alloc(&rt->arena, sizeof(Arr));
    arr_init(&rt->arena, dst);
    for (int i = 0; i < arr_len((const Arr *)a[0].as.arr); ++i) {
        ArrEntry *e = arr_at((const Arr *)a[0].as.arr, i);
        arr_set(&rt->arena, dst, e->is_str, e->skey, e->ikey, e->value);
    }
    for (int i = 0; i < arr_len((const Arr *)a[1].as.arr); ++i) {
        ArrEntry *e = arr_at((const Arr *)a[1].as.arr, i);
        arr_set(&rt->arena, dst, e->is_str, e->skey, e->ikey, e->value);
    }
    return val_array(dst);
}
static Value b_type(Runtime *rt, int argc, Value *a) {
    (void)argc;
    return val_str(arena_strdup(&rt->arena, val_type_name(a[0])));
}
static Value b_str(Runtime *rt, int argc, Value *a) {
    (void)argc;
    return val_str(val_to_str(&rt->arena, a[0]));
}
static Value b_num(Runtime *rt, int argc, Value *a) {
    if (argc != 1) { snprintf(rt->errbuf, sizeof(rt->errbuf), "num 需要 1 个参数"); rt->has_error = 1; return val_nil(); }
    if (a[0].type == VAL_NUM) return a[0];
    if (a[0].type == VAL_INT) return val_num((double)a[0].as.i);
    if (a[0].type == VAL_STR) return val_num(strtod(a[0].as.str, NULL));
    snprintf(rt->errbuf, sizeof(rt->errbuf), "num 无法转换该类型"); rt->has_error = 1; return val_nil();
}
static Value b_input(Runtime *rt, int argc, Value *a) {
    if (argc > 0) { char *p = val_to_str(&rt->arena, a[0]); fputs(p, stdout); fflush(stdout); }
    char buf[4096];
    if (!fgets(buf, sizeof(buf), stdin)) return val_str(arena_strdup(&rt->arena, ""));
    size_t n = strlen(buf);
    while (n > 0 && (buf[n - 1] == '\n' || buf[n - 1] == '\r')) buf[--n] = '\0';
    return val_str(arena_strdup(&rt->arena, buf));
}
static Value b_import(Runtime *rt, int argc, Value *a) {
    if (argc < 1 || a[0].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "import 需要库路径字符串"); rt->has_error = 1; return val_nil(); }
    if (!rt->ffi_enabled) {
        snprintf(rt->errbuf, sizeof(rt->errbuf), "FFI 已禁用 (运维未配置 cvmruntime.ffi)");
        rt->has_error = 1;
        return val_nil();
    }
    /* v1.1: 库必须在白名单内 */
    if (rt->ffi_allow.count > 0 && !map_get(&rt->ffi_allow, a[0].as.str)) {
        /* 尝试带 .dll/.so 后缀的规范化路径 */
        char norm[300];
#ifdef _WIN32
        snprintf(norm, sizeof(norm), "%s.dll", a[0].as.str);
#else
        snprintf(norm, sizeof(norm), "%s.so", a[0].as.str);
#endif
        if (!map_get(&rt->ffi_allow, norm)) {
            snprintf(rt->errbuf, sizeof(rt->errbuf),
                "FFI: 库不在白名单: %s (运维需在 cvmruntime.ffi 中授权)", a[0].as.str);
            rt->has_error = 1;
            return val_nil();
        }
    }
    if (ffi_load(rt, a[0].as.str) != 0) return val_nil();
    return val_nil();
}

/* ---- FFI 沙箱控制 (v1.1: 脚本不可自启, 由运维 cvmruntime.ffi 配置授权) ---- */
static Value b_ffi_enable(Runtime *rt, int argc, Value *a) {
    (void)argc; (void)a;
    snprintf(rt->errbuf, sizeof(rt->errbuf),
        "FFI 必须由运维通过 cvmruntime.ffi 配置授权,脚本不可自启");
    rt->has_error = 1;
    return val_nil();
}
static Value b_ffi_decl(Runtime *rt, int argc, Value *a) {
    if (argc != 2 || a[0].type != VAL_STR || a[1].type != VAL_STR) {
        snprintf(rt->errbuf, sizeof(rt->errbuf), "ffi_decl(name, sig) 需要两个字符串参数");
        rt->has_error = 1;
        return val_nil();
    }
    /* v1.1: 仅白名单内的符号可声明签名 */
    if (!rt->ffi_enabled) {
        snprintf(rt->errbuf, sizeof(rt->errbuf),
            "FFI 未启用 (运维未配置 cvmruntime.ffi)");
        rt->has_error = 1;
        return val_nil();
    }
    if (rt->ffi_allow_sym.count > 0 && !map_get(&rt->ffi_allow_sym, a[0].as.str)) {
        snprintf(rt->errbuf, sizeof(rt->errbuf),
            "FFI 符号未授权 (不在 cvmruntime.ffi 白名单): %s", a[0].as.str);
        rt->has_error = 1;
        return val_nil();
    }
    map_set(&rt->ffi_sigs, a[0].as.str, (void *)a[1].as.str);
    return val_nil();
}

/* ---- 字符串内置 (供 str 包包装) ---- */
/* v1.1+: Unicode-aware 大小写 (Latin-1/希腊/西里尔, 码点级) */
static Value b_str_upper(Runtime *rt, int argc, Value *a) {
    if (argc != 1 || a[0].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_upper 需要字符串"); rt->has_error = 1; return val_nil(); }
    const char *s = a[0].as.str; size_t slen = strlen(s);
    char *o = (char *)arena_alloc(&rt->arena, slen * 4 + 1); /* 最坏: 每码点扩到 4 字节 */
    size_t w = 0; const char *p = s;
    while (*p) {
        int clen = utf8_seq_len((unsigned char)*p);
        int actual = 1;
        for (int k = 1; k < clen; k++) {
            if (p[k] == '\0' || ((unsigned char)p[k] & 0xC0) != 0x80) break;
            actual = k + 1;
        }
        /* 解码码点 (与 utf8_codepoint_at 一致) */
        unsigned char *u = (unsigned char *)p;
        int64_t cp;
        switch (actual) {
            case 1: cp = u[0]; break;
            case 2: cp = ((u[0] & 0x1F) << 6) | (u[1] & 0x3F); break;
            case 3: cp = ((u[0] & 0x0F) << 12) | ((u[1] & 0x3F) << 6) | (u[2] & 0x3F); break;
            case 4: cp = ((u[0] & 0x07) << 18) | ((u[1] & 0x3F) << 12) | ((u[2] & 0x3F) << 6) | (u[3] & 0x3F); break;
            default: cp = u[0]; actual = 1; break;
        }
        int64_t folded = unicode_casefold(cp, 1);
        char enc[4]; int enclen = utf8_encode(folded, enc);
        memcpy(o + w, enc, (size_t)enclen); w += (size_t)enclen;
        p += actual;
    }
    o[w] = '\0';
    return val_str(o);
}
static Value b_str_lower(Runtime *rt, int argc, Value *a) {
    if (argc != 1 || a[0].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_lower 需要字符串"); rt->has_error = 1; return val_nil(); }
    const char *s = a[0].as.str; size_t slen = strlen(s);
    char *o = (char *)arena_alloc(&rt->arena, slen * 4 + 1);
    size_t w = 0; const char *p = s;
    while (*p) {
        int clen = utf8_seq_len((unsigned char)*p);
        int actual = 1;
        for (int k = 1; k < clen; k++) {
            if (p[k] == '\0' || ((unsigned char)p[k] & 0xC0) != 0x80) break;
            actual = k + 1;
        }
        unsigned char *u = (unsigned char *)p;
        int64_t cp;
        switch (actual) {
            case 1: cp = u[0]; break;
            case 2: cp = ((u[0] & 0x1F) << 6) | (u[1] & 0x3F); break;
            case 3: cp = ((u[0] & 0x0F) << 12) | ((u[1] & 0x3F) << 6) | (u[2] & 0x3F); break;
            case 4: cp = ((u[0] & 0x07) << 18) | ((u[1] & 0x3F) << 12) | ((u[2] & 0x3F) << 6) | (u[3] & 0x3F); break;
            default: cp = u[0]; actual = 1; break;
        }
        int64_t folded = unicode_casefold(cp, 0);
        char enc[4]; int enclen = utf8_encode(folded, enc);
        memcpy(o + w, enc, (size_t)enclen); w += (size_t)enclen;
        p += actual;
    }
    o[w] = '\0';
    return val_str(o);
}
static Value b_str_substr(Runtime *rt, int argc, Value *a) {
    if (argc != 3 || a[0].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_substr(s,start,len) 用法错误"); rt->has_error = 1; return val_nil(); }
    char *s = a[0].as.str; long n = (long)strlen(s);
    long start = (long)(a[1].type == VAL_INT ? (double)a[1].as.i : a[1].as.num);
    long len  = (long)(a[2].type == VAL_INT ? (double)a[2].as.i : a[2].as.num);
    if (start < 0) start = 0;
    if (start > n) start = n;
    if (start + len > n) len = n - start;
    if (len < 0) len = 0;
    char *o = (char *)arena_alloc(&rt->arena, (size_t)len + 1);
    memcpy(o, s + start, (size_t)len); o[len] = '\0';
    return val_str(o);
}
static Value b_str_contains(Runtime *rt, int argc, Value *a) {
    if (argc != 2 || a[0].type != VAL_STR || a[1].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_contains(s,sub) 用法错误"); rt->has_error = 1; return val_nil(); }
    return val_bool(strstr(a[0].as.str, a[1].as.str) != NULL);
}

/* 从 Value 取整数下标 (VAL_INT/VAL_NUM); 非法类型报错返回 -1 */
static long str_idx_arg(Runtime *rt, Value v, const char *fn) {
    if (v.type == VAL_INT) return (long)v.as.i;
    if (v.type == VAL_NUM) return (long)v.as.num;
    snprintf(rt->errbuf, sizeof(rt->errbuf), "函数 '%s' 需要整数下标", fn);
    rt->has_error = 1;
    return -1;
}

/* ---- 字符串家族新增 (v1) ---- */
static Value b_str_index(Runtime *rt, int argc, Value *a) {
    if (argc != 2 || a[0].type != VAL_STR || a[1].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_index(s,sub) 用法错误"); rt->has_error = 1; return val_nil(); }
    const char *m = strstr(a[0].as.str, a[1].as.str);
    if (!m) return val_num(-1);
    return val_num((double)(m - a[0].as.str));
}
static Value b_str_rindex(Runtime *rt, int argc, Value *a) {
    if (argc != 2 || a[0].type != VAL_STR || a[1].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_rindex(s,sub) 用法错误"); rt->has_error = 1; return val_nil(); }
    const char *s = a[0].as.str, *sub = a[1].as.str;
    if (sub[0] == '\0') return val_num((double)strlen(s));
    const char *last = NULL, *p = s;
    while (*p) {
        const char *m = strstr(p, sub);
        if (!m) break;
        last = m; p = m + 1; /* 推进 1 字节以覆盖重叠匹配 */
    }
    if (!last) return val_num(-1);
    return val_num((double)(last - s));
}
static Value b_str_replace(Runtime *rt, int argc, Value *a) {
    if (argc != 3 || a[0].type != VAL_STR || a[1].type != VAL_STR || a[2].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_replace(s,old,new) 用法错误"); rt->has_error = 1; return val_nil(); }
    const char *s = a[0].as.str, *old = a[1].as.str, *nw = a[2].as.str;
    size_t oldlen = strlen(old);
    if (oldlen == 0) return val_str(arena_strdup(&rt->arena, s)); /* old 空: 原样返回 */
    size_t nwlen = strlen(nw);
    long count = 0; const char *p = s;
    while (*p) { const char *m = strstr(p, old); if (!m) break; count++; p = m + oldlen; }
    size_t slen = strlen(s);
    size_t total = slen + (size_t)count * (nwlen > oldlen ? (nwlen - oldlen) : 0);
    char *o = (char *)arena_alloc(&rt->arena, total + 1);
    char *w = o; p = s;
    while (*p) {
        const char *m = strstr(p, old);
        if (!m) { size_t rest = strlen(p); memcpy(w, p, rest); w += rest; break; }
        size_t pre = (size_t)(m - p);
        memcpy(w, p, pre); w += pre;
        memcpy(w, nw, nwlen); w += nwlen;
        p = m + oldlen;
    }
    *w = '\0';
    return val_str(o);
}
static Value b_str_split(Runtime *rt, int argc, Value *a) {
    if (argc != 2 || a[0].type != VAL_STR || a[1].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_split(s,sep) 用法错误"); rt->has_error = 1; return val_nil(); }
    const char *s = a[0].as.str, *sep = a[1].as.str;
    size_t seplen = strlen(sep);
    if (seplen == 0) { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_split: 分隔符不能为空"); rt->has_error = 1; return val_nil(); }
    Arr *arr = (Arr *)arena_alloc(&rt->arena, sizeof(Arr));
    arr_init(&rt->arena, arr);
    if (s[0] == '\0') { arr_append(&rt->arena, arr, val_str(arena_strdup(&rt->arena, ""))); return val_array(arr); }
    while (1) {
        const char *next = strstr(s, sep);
        if (!next) { arr_append(&rt->arena, arr, val_str(arena_strdup(&rt->arena, s))); break; }
        size_t fieldlen = (size_t)(next - s);
        char *field = (char *)arena_alloc(&rt->arena, fieldlen + 1);
        memcpy(field, s, fieldlen); field[fieldlen] = '\0';
        arr_append(&rt->arena, arr, val_str(field));
        s = next + seplen;
    }
    return val_array(arr);
}
static Value b_str_join(Runtime *rt, int argc, Value *a) {
    if (argc != 2 || a[0].type != VAL_ARRAY || a[1].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_join(arr,sep) 用法错误"); rt->has_error = 1; return val_nil(); }
    Arr *arr = (Arr *)a[0].as.arr;
    const char *sep = a[1].as.str;
    size_t seplen = strlen(sep);
    size_t total = 0; int n = arr_len(arr);
    for (int i = 0; i < n; ++i) {
        ArrEntry *e = arr_at(arr, i);
        char *ss = e ? val_to_str(&rt->arena, e->value) : (char *)"";
        total += strlen(ss);
        if (i) total += seplen;
    }
    char *buf = (char *)arena_alloc(&rt->arena, total + 1);
    char *w = buf;
    for (int i = 0; i < n; ++i) {
        ArrEntry *e = arr_at(arr, i);
        char *ss = e ? val_to_str(&rt->arena, e->value) : (char *)"";
        if (i) { memcpy(w, sep, seplen); w += seplen; }
        size_t l = strlen(ss); memcpy(w, ss, l); w += l;
    }
    *w = '\0';
    return val_str(buf);
}
static Value b_str_trim(Runtime *rt, int argc, Value *a) {
    if (argc != 1 || a[0].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_trim(s) 需要字符串"); rt->has_error = 1; return val_nil(); }
    const char *s = a[0].as.str;
    while (*s && isspace((unsigned char)*s)) s++;
    const char *end = s + strlen(s);
    while (end > s && isspace((unsigned char)end[-1])) end--;
    size_t n = (size_t)(end - s);
    char *o = (char *)arena_alloc(&rt->arena, n + 1);
    memcpy(o, s, n); o[n] = '\0';
    return val_str(o);
}
static Value b_str_ltrim(Runtime *rt, int argc, Value *a) {
    if (argc != 1 || a[0].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_ltrim(s) 需要字符串"); rt->has_error = 1; return val_nil(); }
    const char *s = a[0].as.str;
    while (*s && isspace((unsigned char)*s)) s++;
    return val_str(arena_strdup(&rt->arena, s));
}
static Value b_str_rtrim(Runtime *rt, int argc, Value *a) {
    if (argc != 1 || a[0].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_rtrim(s) 需要字符串"); rt->has_error = 1; return val_nil(); }
    const char *s = a[0].as.str;
    const char *end = s + strlen(s);
    while (end > s && isspace((unsigned char)end[-1])) end--;
    size_t n = (size_t)(end - s);
    char *o = (char *)arena_alloc(&rt->arena, n + 1);
    memcpy(o, s, n); o[n] = '\0';
    return val_str(o);
}
static Value b_str_starts(Runtime *rt, int argc, Value *a) {
    if (argc != 2 || a[0].type != VAL_STR || a[1].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_starts(s,prefix) 用法错误"); rt->has_error = 1; return val_nil(); }
    const char *s = a[0].as.str, *pre = a[1].as.str;
    size_t plen = strlen(pre);
    if (plen == 0) return val_bool(1);
    return val_bool(strlen(s) >= plen && strncmp(s, pre, plen) == 0);
}
static Value b_str_ends(Runtime *rt, int argc, Value *a) {
    if (argc != 2 || a[0].type != VAL_STR || a[1].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_ends(s,suffix) 用法错误"); rt->has_error = 1; return val_nil(); }
    const char *s = a[0].as.str, *suf = a[1].as.str;
    size_t slen = strlen(s), suf_len = strlen(suf);
    if (suf_len == 0) return val_bool(1);
    if (suf_len > slen) return val_bool(0);
    return val_bool(strcmp(s + slen - suf_len, suf) == 0);
}
static Value b_str_reverse(Runtime *rt, int argc, Value *a) {
    if (argc != 1 || a[0].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_reverse(s) 需要字符串"); rt->has_error = 1; return val_nil(); }
    const char *s = a[0].as.str;
    size_t n = strlen(s);
    char *o = (char *)arena_alloc(&rt->arena, n + 1);
    for (size_t i = 0; i < n; ++i) o[i] = s[n - 1 - i];
    o[n] = '\0';
    return val_str(o);
}
static Value b_str_repeat(Runtime *rt, int argc, Value *a) {
    if (argc != 2 || a[0].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_repeat(s,n) 用法错误"); rt->has_error = 1; return val_nil(); }
    double dn;
    if (a[1].type == VAL_INT) dn = (double)a[1].as.i;
    else if (a[1].type == VAL_NUM) dn = a[1].as.num;
    else { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_repeat 需要整数次数"); rt->has_error = 1; return val_nil(); }
    if (dn < 0) { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_repeat 次数不能为负"); rt->has_error = 1; return val_nil(); }
    long n = (long)dn;
    const char *s = a[0].as.str;
    size_t slen = strlen(s);
    size_t total = slen * (size_t)n;
    char *o = (char *)arena_alloc(&rt->arena, total + 1);
    char *w = o;
    for (long i = 0; i < n; ++i) { memcpy(w, s, slen); w += slen; }
    *w = '\0';
    return val_str(o);
}
static Value b_str_count(Runtime *rt, int argc, Value *a) {
    if (argc != 2 || a[0].type != VAL_STR || a[1].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_count(s,sub) 用法错误"); rt->has_error = 1; return val_nil(); }
    const char *s = a[0].as.str, *sub = a[1].as.str;
    size_t sublen = strlen(sub);
    if (sublen == 0) return val_num(0);
    long count = 0; const char *p = s;
    while (*p) { const char *m = strstr(p, sub); if (!m) break; count++; p = m + sublen; }
    return val_num((double)count);
}
static Value b_str_len(Runtime *rt, int argc, Value *a) {
    if (argc != 1 || a[0].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_len(s) 需要字符串"); rt->has_error = 1; return val_nil(); }
    return val_num((double)utf8_count_codepoints(a[0].as.str)); /* UTF-8 码点计数 */
}
static Value b_str_char_at(Runtime *rt, int argc, Value *a) {
    if (argc != 2 || a[0].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_char_at(s,i) 用法错误"); rt->has_error = 1; return val_nil(); }
    long idx = str_idx_arg(rt, a[1], "str_char_at");
    if (rt->has_error) return val_nil();
    int clen;
    const char *p = utf8_char_at_ptr(a[0].as.str, idx, &clen);
    if (!p) { snprintf(rt->errbuf, sizeof(rt->errbuf), "字符串索引越界"); rt->has_error = 1; return val_nil(); }
    char *o = (char *)arena_alloc(&rt->arena, (size_t)clen + 1);
    memcpy(o, p, (size_t)clen); o[clen] = '\0';
    return val_str(o);
}
static Value b_str_ord(Runtime *rt, int argc, Value *a) {
    if (argc != 2 || a[0].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "str_ord(s,i) 用法错误"); rt->has_error = 1; return val_nil(); }
    long idx = str_idx_arg(rt, a[1], "str_ord");
    if (rt->has_error) return val_nil();
    int64_t cp = utf8_codepoint_at(a[0].as.str, idx);
    if (cp < 0) { snprintf(rt->errbuf, sizeof(rt->errbuf), "字符串索引越界"); rt->has_error = 1; return val_nil(); }
    return val_int(cp);
}

/* ---- 文件内置 (供 fs 包包装) ---- */
static Value b_file_read(Runtime *rt, int argc, Value *a) {
    if (argc != 1 || a[0].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "file_read 需要路径字符串"); rt->has_error = 1; return val_nil(); }
    FILE *f = fopen(a[0].as.str, "rb");
    if (!f) return val_nil();
    fseek(f, 0, SEEK_END); long sz = ftell(f); fseek(f, 0, SEEK_SET);
    char *buf = (char *)arena_alloc(&rt->arena, (size_t)sz + 1);
    size_t rd = fread(buf, 1, (size_t)sz, f); buf[rd] = '\0';
    fclose(f);
    return val_str(buf);
}
static Value b_file_write(Runtime *rt, int argc, Value *a) {
    if (argc != 2 || a[0].type != VAL_STR || a[1].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "file_write(path,content) 用法错误"); rt->has_error = 1; return val_nil(); }
    FILE *f = fopen(a[0].as.str, "wb");
    if (!f) { snprintf(rt->errbuf, sizeof(rt->errbuf), "file_write: 无法打开 '%s'", a[0].as.str); rt->has_error = 1; return val_nil(); }
    fwrite(a[1].as.str, 1, strlen(a[1].as.str), f);
    fclose(f);
    return val_nil();
}
static Value b_file_exists(Runtime *rt, int argc, Value *a) {
    if (argc != 1 || a[0].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "file_exists 需要路径字符串"); rt->has_error = 1; return val_nil(); }
    FILE *f = fopen(a[0].as.str, "rb");
    if (!f) return val_bool(0);
    fclose(f);
    return val_bool(1);
}

/* ---- v1.1+ 事件循环 / 定时器 ---- */
#ifdef _WIN32
#  include <windows.h>
static void host_sleep_ms(int ms) { Sleep((DWORD)ms); }
#else
#  include <unistd.h>
#  include <time.h>
static void host_sleep_ms(int ms) { struct timespec ts = {ms/1000, (ms%1000)*1000000L}; nanosleep(&ts, NULL); }
#endif

static Value b_delay(Runtime *rt, int argc, Value *a) {
    if (argc != 1) { snprintf(rt->errbuf, sizeof(rt->errbuf), "delay(ms) 需要一个参数"); rt->has_error = 1; return val_nil(); }
    int ms = (int)(a[0].type == VAL_INT ? (double)a[0].as.i : a[0].as.num);
    if (ms < 0) ms = 0;
    host_sleep_ms(ms);
    return val_nil();
}

static Value b_set_timeout(Runtime *rt, int argc, Value *a) {
    if (argc != 2 || a[0].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "set_timeout(name, ms) 用法错误"); rt->has_error = 1; return val_nil(); }
    int ms = (int)(a[1].type == VAL_INT ? (double)a[1].as.i : a[1].as.num);
    if (ms < 0) ms = 0;
    rt_timer_add(rt, a[0].as.str, ms, 0);
    return val_nil();
}

static Value b_set_interval(Runtime *rt, int argc, Value *a) {
    if (argc != 2 || a[0].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "set_interval(name, ms) 用法错误"); rt->has_error = 1; return val_nil(); }
    int ms = (int)(a[1].type == VAL_INT ? (double)a[1].as.i : a[1].as.num);
    if (ms <= 0) { snprintf(rt->errbuf, sizeof(rt->errbuf), "set_interval 间隔必须 > 0"); rt->has_error = 1; return val_nil(); }
    rt_timer_add(rt, a[0].as.str, ms, ms);
    return val_nil();
}

static Value b_event_loop(Runtime *rt, int argc, Value *a) {
    (void)argc; (void)a;
    while (1) {
        int active = 0, soonest = 999999;
        if (!rt->timer_epoch) { host_sleep_ms(100); continue; }
        int64_t now = rt_now_ms(rt) - rt->timer_epoch;
        for (int i = 0; i < rt->timer_count; ++i) {
            if (!rt->timers[i].active) continue;
            active = 1;
            int64_t wait = rt->timers[i].deadline_ms - now;
            if (wait < 0) wait = 0;
            if (wait < soonest) soonest = (wait > 2147483647LL) ? 2147483647 : (int)wait;
            if (rt->timers[i].deadline_ms <= now) {
                char call_str[320];
                snprintf(call_str, sizeof(call_str), "%s();", rt->timers[i].name);
                rt_run(rt, call_str, "timer");
                rt->has_error = 0;
                if (rt->timers[i].repeat_ms > 0)
                    rt->timers[i].deadline_ms = now + rt->timers[i].repeat_ms;
                else
                    rt->timers[i].active = 0;
                /* 重置循环: timer_run 可能已改 timer_count (通过 set_timeout 回调) */
                now = rt_now_ms(rt) - rt->timer_epoch;
                goto restart_loop;
            }
        }
        if (!active) break;
        if (soonest > 0) host_sleep_ms(soonest);
        restart_loop:;
    }
    return val_nil();
}

static Value b_gc_collect(Runtime *rt, int argc, Value *a) {
    (void)argc; (void)a;
    gc_collect(rt);
    return val_nil();
}

/* ====== v1.2 标准库扩充 (Node/Python/PHP 对标) ====== */

/* ---- 数学补充 ---- */
static Value b_math_sin(Runtime *rt, int argc, Value *a) {
    if(argc!=1){rt->has_error=1;return val_nil();}
    double v=a[0].type==VAL_INT?(double)a[0].as.i:a[0].as.num;
    return val_num(sin(v));
}
static Value b_math_cos(Runtime *rt, int argc, Value *a) {
    if(argc!=1){rt->has_error=1;return val_nil();}
    double v=a[0].type==VAL_INT?(double)a[0].as.i:a[0].as.num;
    return val_num(cos(v));
}
static Value b_math_tan(Runtime *rt, int argc, Value *a) {
    if(argc!=1){rt->has_error=1;return val_nil();}
    double v=a[0].type==VAL_INT?(double)a[0].as.i:a[0].as.num;
    return val_num(tan(v));
}
static Value b_math_log(Runtime *rt, int argc, Value *a) {
    if(argc!=1){rt->has_error=1;return val_nil();}
    double v=a[0].type==VAL_INT?(double)a[0].as.i:a[0].as.num;
    return val_num(log(v));
}
static Value b_math_exp(Runtime *rt, int argc, Value *a) {
    if(argc!=1){rt->has_error=1;return val_nil();}
    double v=a[0].type==VAL_INT?(double)a[0].as.i:a[0].as.num;
    return val_num(exp(v));
}
static Value b_math_pi(Runtime *rt, int argc, Value *a) {
    (void)argc;(void)a;
    return val_num(3.14159265358979323846);
}

/* ---- URL 编解码 ---- */
static int hex_val(char c){if(c>='0'&&c<='9')return c-'0';if(c>='A'&&c<='F')return c-'A'+10;if(c>='a'&&c<='f')return c-'a'+10;return 0;}

static Value b_url_encode(Runtime *rt, int argc, Value *a) {
    if(argc!=1||a[0].type!=VAL_STR){rt->has_error=1;return val_nil();}
    const char *s=a[0].as.str; size_t n=strlen(s);
    char *o=(char*)arena_alloc(&rt->arena,n*3+1); size_t w=0;
    for(size_t i=0;i<n;i++){
        unsigned char c=(unsigned char)s[i];
        if((c>='A'&&c<='Z')||(c>='a'&&c<='z')||(c>='0'&&c<='9')||c=='-'||c=='_'||c=='.'||c=='~'){o[w++]=c;}
        else{w+=sprintf(o+w,"%%%02X",c);}
    }
    o[w]='\0'; return val_str(o);
}
static Value b_url_decode(Runtime *rt, int argc, Value *a) {
    if(argc!=1||a[0].type!=VAL_STR){rt->has_error=1;return val_nil();}
    const char *s=a[0].as.str; size_t n=strlen(s);
    char *o=(char*)arena_alloc(&rt->arena,n+1); size_t w=0;
    for(size_t i=0;i<n;i++){
        if(s[i]=='%'&&i+2<n){o[w++]=(char)(hex_val(s[i+1])*16+hex_val(s[i+2]));i+=2;}
        else if(s[i]=='+'){o[w++]=' ';}
        else o[w++]=s[i];
    }
    o[w]='\0'; return val_str(o);
}

/* ---- HTML 转义 ---- */
static Value b_html_escape(Runtime *rt, int argc, Value *a) {
    if(argc!=1||a[0].type!=VAL_STR){rt->has_error=1;return val_nil();}
    const char *s=a[0].as.str; size_t n=strlen(s);
    char *o=(char*)arena_alloc(&rt->arena,n*6+1); size_t w=0;
    for(size_t i=0;i<n;i++){
        switch(s[i]){
            case '&': memcpy(o+w,"&amp;",5);w+=5;break;
            case '<': memcpy(o+w,"&lt;",4);w+=4;break;
            case '>': memcpy(o+w,"&gt;",4);w+=4;break;
            case '"': memcpy(o+w,"&quot;",6);w+=6;break;
            default: o[w++]=s[i];
        }
    }
    o[w]='\0'; return val_str(o);
}

/* ---- 格式化字符串 (sprintf) ---- */
static Value b_str_format(Runtime *rt, int argc, Value *a) {
    if(argc<1||a[0].type!=VAL_STR){rt->has_error=1;return val_nil();}
    /* 简单版: 替换 {0} {1} 占位符 */
    const char *tmpl=a[0].as.str; size_t tlen=strlen(tmpl);
    char *o=(char*)arena_alloc(&rt->arena,4096); size_t w=0;
    size_t i=0;
    while(i<tlen){
        if(tmpl[i]=='{'&&i+2<tlen&&tmpl[i+1]>='0'&&tmpl[i+1]<='9'){
            size_t j=i+1; while(j<tlen&&tmpl[j]!='}')j++;
            if(j<tlen){
                int idx=tmpl[i+1]-'0';
                if(idx<argc-1){
                    char *vs=val_to_str(&rt->arena,a[idx+1]);
                    size_t vl=strlen(vs); memcpy(o+w,vs,vl); w+=vl;
                }
                i=j+1; continue;
            }
        }
        o[w++]=tmpl[i++];
    }
    o[w]='\0'; return val_str(o);
}

/* ---- 环境变量 ---- */
static Value b_os_getenv(Runtime *rt, int argc, Value *a) {
    if(argc!=1||a[0].type!=VAL_STR){rt->has_error=1;return val_nil();}
    const char *v=getenv(a[0].as.str);
    return v?val_str(arena_strdup(&rt->arena,v)):val_nil();
}

/* ---- 目录列表 ---- */
static Value b_file_listdir(Runtime *rt, int argc, Value *a) {
    if(argc!=1||a[0].type!=VAL_STR){rt->has_error=1;return val_nil();}
    Arr *arr=(Arr*)arena_alloc(&rt->arena,sizeof(Arr)); arr_init(&rt->arena,arr);
#ifdef _WIN32
    char pat[512]; snprintf(pat,sizeof(pat),"%s\\*",a[0].as.str);
    WIN32_FIND_DATAA fd; HANDLE h=FindFirstFileA(pat,&fd);
    if(h!=INVALID_HANDLE_VALUE){
        do{arr_append(&rt->arena,arr,val_str(arena_strdup(&rt->arena,fd.cFileName)));}while(FindNextFileA(h,&fd));
        FindClose(h);
    }
#endif
    return val_array(arr);
}

/* ---- 协议状态机 (ProtoState) 内置 ---- */
static ProtoState *arg_proto(Runtime *rt, Value v) {
    if (v.type != VAL_PTR || !v.as.ptr) {
        snprintf(rt->errbuf, sizeof(rt->errbuf), "协议状态机操作需要状态机句柄");
        rt->has_error = 1;
        return NULL;
    }
    return (ProtoState *)v.as.ptr;
}
static Value b_proto_new(Runtime *rt, int argc, Value *a) {
    if (argc < 1 || a[0].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "proto_new(name) 需要字符串名称"); rt->has_error = 1; return val_nil(); }
    ProtoState *ps = proto_new(a[0].as.str);
    if (!ps) { snprintf(rt->errbuf, sizeof(rt->errbuf), "proto_new: 创建状态机失败"); rt->has_error = 1; return val_nil(); }
    return val_ptr_obj(ps);
}
static Value b_proto_state(Runtime *rt, int argc, Value *a) {
    if (argc < 2) { snprintf(rt->errbuf, sizeof(rt->errbuf), "proto_state(sm, id, label?, level?) 参数不足"); rt->has_error = 1; return val_nil(); }
    ProtoState *ps = arg_proto(rt, a[0]); if (!ps) return val_nil();
    int id = (int)(a[1].type == VAL_INT ? a[1].as.i : (int64_t)a[1].as.num);
    const char *label = (argc >= 3 && a[2].type == VAL_STR) ? a[2].as.str : "";
    int level = (argc >= 4) ? (int)(a[3].type == VAL_INT ? a[3].as.i : (int64_t)a[3].as.num) : 0;
    if (proto_state_add(ps, id, label, level) != 0) { snprintf(rt->errbuf, sizeof(rt->errbuf), "proto_state: 添加状态失败"); rt->has_error = 1; return val_nil(); }
    return val_ptr_obj(ps);
}
static Value b_proto_transition(Runtime *rt, int argc, Value *a) {
    if (argc < 4) { snprintf(rt->errbuf, sizeof(rt->errbuf), "proto_transition(sm, from, event, to, action?) 参数不足"); rt->has_error = 1; return val_nil(); }
    ProtoState *ps = arg_proto(rt, a[0]); if (!ps) return val_nil();
    int from = (int)(a[1].type == VAL_INT ? a[1].as.i : (int64_t)a[1].as.num);
    if (a[2].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "proto_transition: event 需要字符串"); rt->has_error = 1; return val_nil(); }
    int to = (int)(a[3].type == VAL_INT ? a[3].as.i : (int64_t)a[3].as.num);
    const char *action = (argc >= 5 && a[4].type == VAL_STR) ? a[4].as.str : "";
    if (proto_transition_add(ps, from, a[2].as.str, to, action) != 0) { snprintf(rt->errbuf, sizeof(rt->errbuf), "proto_transition: 添加转换失败"); rt->has_error = 1; return val_nil(); }
    return val_ptr_obj(ps);
}
static Value b_proto_event(Runtime *rt, int argc, Value *a) {
    if (argc != 2 || a[1].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "proto_event(sm, event) 需要事件字符串"); rt->has_error = 1; return val_nil(); }
    ProtoState *ps = arg_proto(rt, a[0]); if (!ps) return val_nil();
    int r = proto_event(ps, a[1].as.str);
    return val_int(r);
}
static Value b_proto_current(Runtime *rt, int argc, Value *a) {
    if (argc != 1) { snprintf(rt->errbuf, sizeof(rt->errbuf), "proto_current(sm) 需要一个参数"); rt->has_error = 1; return val_nil(); }
    ProtoState *ps = arg_proto(rt, a[0]); if (!ps) return val_nil();
    return val_str(arena_strdup(&rt->arena, proto_current_label(ps)));
}
static Value b_proto_current_id(Runtime *rt, int argc, Value *a) {
    if (argc != 1) { snprintf(rt->errbuf, sizeof(rt->errbuf), "proto_current_id(sm) 需要一个参数"); rt->has_error = 1; return val_nil(); }
    ProtoState *ps = arg_proto(rt, a[0]); if (!ps) return val_nil();
    return val_int(proto_current_id(ps));
}
static Value b_proto_level(Runtime *rt, int argc, Value *a) {
    if (argc != 1) { snprintf(rt->errbuf, sizeof(rt->errbuf), "proto_level(sm) 需要一个参数"); rt->has_error = 1; return val_nil(); }
    ProtoState *ps = arg_proto(rt, a[0]); if (!ps) return val_nil();
    return val_int(proto_current_level(ps));
}
static Value b_proto_level_name(Runtime *rt, int argc, Value *a) {
    int level = (argc >= 1) ? (int)(a[0].type == VAL_INT ? a[0].as.i : (int64_t)a[0].as.num) : 0;
    return val_str(arena_strdup(&rt->arena, proto_level_name(level)));
}

/* ---- JSON 序列化 (简单版) ---- */
static Value b_json_stringify(Runtime *rt, int argc, Value *a) {
    if(argc!=1){rt->has_error=1;return val_nil();}
    Value v=a[0];
    if(v.type==VAL_NIL) return val_str(arena_strdup(&rt->arena,"null"));
    if(v.type==VAL_BOOL) return val_str(arena_strdup(&rt->arena,v.as.i?"true":"false"));
    if(v.type==VAL_NUM) {char b[64];snprintf(b,sizeof(b),"%.12g",v.as.num);return val_str(arena_strdup(&rt->arena,b));}
    if(v.type==VAL_INT) {char b[64];snprintf(b,sizeof(b),"%lld",(long long)v.as.i);return val_str(arena_strdup(&rt->arena,b));}
    if(v.type==VAL_STR) {
        const char *s=v.as.str; size_t n=strlen(s);
        char *o=(char*)arena_alloc(&rt->arena,n*2+3); size_t w=0; o[w++]='"';
        for(size_t i=0;i<n;i++){
            char c=s[i];
            if(c=='"'||c=='\\'){o[w++]='\\';o[w++]=c;}
            else if(c=='\n'){o[w++]='\\';o[w++]='n';}
            else if(c=='\r'){o[w++]='\\';o[w++]='r';}
            else if(c=='\t'){o[w++]='\\';o[w++]='t';}
            else o[w++]=c;
        }
        o[w++]='"'; o[w]='\0'; return val_str(o);
    }
    if(v.type==VAL_ARRAY){
        Arr *arr=(Arr*)v.as.arr; int n=arr_len(arr);
        char *o=(char*)arena_alloc(&rt->arena,65536); size_t w=0; o[w++]='[';
        for(int i=0;i<n;i++){ArrEntry *e=arr_at(arr,i);if(i>0){o[w++]=',';}
            Value sv=b_json_stringify(rt,1,&e->value);
            size_t sl=strlen(sv.as.str); memcpy(o+w,sv.as.str,sl); w+=sl;
        }
        o[w++]=']'; o[w]='\0'; return val_str(o);
    }
    return val_str(arena_strdup(&rt->arena,"null"));
}

/* ---- 模块系统 ---- */
static Value b_require(Runtime *rt, int argc, Value *a) {
    if (argc != 1 || a[0].type != VAL_STR) { snprintf(rt->errbuf, sizeof(rt->errbuf), "require 需要字符串模块名"); rt->has_error = 1; return val_nil(); }
    Map *exp = load_module(rt, a[0].as.str);
    if (!exp) return val_nil();
    return val_module((void *)exp);
}

void host_register_all(Runtime *rt) {
    srand((unsigned)time(NULL));
    rt_register_builtin(rt, "print",    b_print);
    rt_register_builtin(rt, "println",  b_println);
    rt_register_builtin(rt, "sqrt",     b_sqrt);
    rt_register_builtin(rt, "pow",      b_pow);
    rt_register_builtin(rt, "abs",      b_abs);
    rt_register_builtin(rt, "floor",    b_floor);
    rt_register_builtin(rt, "ceil",     b_ceil);
    rt_register_builtin(rt, "round",    b_round);
    rt_register_builtin(rt, "rand",     b_rand);
    rt_register_builtin(rt, "time",     b_time);
    rt_register_builtin(rt, "clock_ms", b_clock_ms);
    rt_register_builtin(rt, "len",      b_len);
    rt_register_builtin(rt, "type",     b_type);
    rt_register_builtin(rt, "str",      b_str);
    rt_register_builtin(rt, "num",      b_num);
    rt_register_builtin(rt, "input",    b_input);
    rt_register_builtin(rt, "import",   b_import);
    rt_register_builtin(rt, "ffi_enable", b_ffi_enable);
    rt_register_builtin(rt, "ffi_decl",   b_ffi_decl);
    rt_register_builtin(rt, "require",  b_require);
    rt_register_builtin(rt, "push",       b_push);
    rt_register_builtin(rt, "arr_get",    b_arr_get);
    rt_register_builtin(rt, "arr_set",    b_arr_set);
    rt_register_builtin(rt, "arr_has",    b_arr_has);
    rt_register_builtin(rt, "arr_del",    b_arr_del);
    rt_register_builtin(rt, "arr_keys",   b_arr_keys);
    rt_register_builtin(rt, "arr_values", b_arr_values);
    rt_register_builtin(rt, "arr_merge",  b_arr_merge);
    rt_register_builtin(rt, "str_upper",   b_str_upper);
    rt_register_builtin(rt, "str_lower",   b_str_lower);
    rt_register_builtin(rt, "str_substr",  b_str_substr);
    rt_register_builtin(rt, "str_contains",b_str_contains);
    rt_register_builtin(rt, "str_index",   b_str_index);
    rt_register_builtin(rt, "str_rindex",  b_str_rindex);
    rt_register_builtin(rt, "str_replace", b_str_replace);
    rt_register_builtin(rt, "str_split",   b_str_split);
    rt_register_builtin(rt, "str_join",    b_str_join);
    rt_register_builtin(rt, "str_trim",    b_str_trim);
    rt_register_builtin(rt, "str_ltrim",   b_str_ltrim);
    rt_register_builtin(rt, "str_rtrim",   b_str_rtrim);
    rt_register_builtin(rt, "str_starts",  b_str_starts);
    rt_register_builtin(rt, "str_ends",    b_str_ends);
    rt_register_builtin(rt, "str_reverse", b_str_reverse);
    rt_register_builtin(rt, "str_repeat",  b_str_repeat);
    rt_register_builtin(rt, "str_count",   b_str_count);
    rt_register_builtin(rt, "str_len",     b_str_len);
    rt_register_builtin(rt, "str_char_at", b_str_char_at);
    rt_register_builtin(rt, "str_ord",     b_str_ord);
    rt_register_builtin(rt, "file_read",   b_file_read);
    rt_register_builtin(rt, "file_write",  b_file_write);
    rt_register_builtin(rt, "file_exists", b_file_exists);
    /* v1.1+ 事件循环 / 定时器 */
    rt_register_builtin(rt, "delay",        b_delay);
    rt_register_builtin(rt, "set_timeout",  b_set_timeout);
    rt_register_builtin(rt, "set_interval", b_set_interval);
    rt_register_builtin(rt, "event_loop",   b_event_loop);
    /* v1.1+ GC */
    rt_register_builtin(rt, "gc_collect",   b_gc_collect);
    /* v1.2 标准库扩充 (Node/Python/PHP 对标) */
    rt_register_builtin(rt, "math_sin",     b_math_sin);
    rt_register_builtin(rt, "math_cos",     b_math_cos);
    rt_register_builtin(rt, "math_tan",     b_math_tan);
    rt_register_builtin(rt, "math_log",     b_math_log);
    rt_register_builtin(rt, "math_exp",     b_math_exp);
    rt_register_builtin(rt, "math_pi",      b_math_pi);
    rt_register_builtin(rt, "url_encode",   b_url_encode);
    rt_register_builtin(rt, "url_decode",   b_url_decode);
    rt_register_builtin(rt, "html_escape",  b_html_escape);
    rt_register_builtin(rt, "str_format",   b_str_format);
    rt_register_builtin(rt, "os_getenv",    b_os_getenv);
    rt_register_builtin(rt, "file_listdir", b_file_listdir);
    rt_register_builtin(rt, "json_stringify", b_json_stringify);
    /* v1.3+ 协议状态机 (米特-木卫三协议) */
    rt_register_builtin(rt, "proto_new",         b_proto_new);
    rt_register_builtin(rt, "proto_state",       b_proto_state);
    rt_register_builtin(rt, "proto_transition",  b_proto_transition);
    rt_register_builtin(rt, "proto_event",       b_proto_event);
    rt_register_builtin(rt, "proto_current",     b_proto_current);
    rt_register_builtin(rt, "proto_current_id",  b_proto_current_id);
    rt_register_builtin(rt, "proto_level",       b_proto_level);
    rt_register_builtin(rt, "proto_level_name",  b_proto_level_name);
}