#include "cvm_core.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <math.h>
#include <stdint.h>
int val_truthy(Value v) {
switch (v.type) {
case VAL_NUM: return v.as.num != 0.0;
case VAL_BOOL: return v.as.boolean;
case VAL_STR: return v.as.str && v.as.str[0] != '\0';
case VAL_NIL: return 0;
case VAL_MODULE: return v.as.mod != NULL;
case VAL_FUNC: return 1;
case VAL_ARRAY: return arr_len((const Arr *)v.as.arr) > 0;
case VAL_CLOSURE: return 1;
case VAL_PTR: return v.as.ptr != NULL;
case VAL_INT: return v.as.i != 0;
}
return 0;
}
const char *val_type_name(Value v) {
switch (v.type) {
case VAL_NUM: return "number";
case VAL_STR: return "string";
case VAL_BOOL: return "bool";
case VAL_NIL: return "nil";
case VAL_MODULE: return "module";
case VAL_FUNC: return "func";
case VAL_ARRAY: return "array";
case VAL_CLOSURE: return "closure";
case VAL_PTR: return "ptr";
case VAL_INT: return "int";
}
return "?";
}
static char *arr_to_str(Arena *a, const Arr *arr, int depth) {
if (depth > 32) return arena_strdup(a, "[...]");
char *out = arena_strdup(a, "[");
size_t len = 1;
for (int i = 0; i < arr_len(arr); ++i) {
ArrEntry *e = arr_at(arr, i);
if (i) {
char *sep = arena_strdup(a, ", ");
char *buf = (char *)arena_alloc(a, len + strlen(sep) + 1);
memcpy(buf, out, len); strcpy(buf + len, sep);
out = buf; len += strlen(sep);
}
char *kb = NULL;
if (e->is_str) {
size_t n = strlen(e->skey);
kb = (char *)arena_alloc(a, n + 3);
kb[0] = '"'; memcpy(kb + 1, e->skey, n); kb[n + 1] = '"'; kb[n + 2] = '\0';
} else {
char tmp[32]; snprintf(tmp, sizeof(tmp), "%lld", (long long)e->ikey);
kb = arena_strdup(a, tmp);
}
char *vs = val_to_str(a, e->value);
size_t kl = strlen(kb), vl = strlen(vs);
char *buf = (char *)arena_alloc(a, len + kl + vl + 3);
memcpy(buf, out, len);
memcpy(buf + len, kb, kl); buf[len + kl] = ':';
memcpy(buf + len + kl + 1, vs, vl); buf[len + kl + 1 + vl] = '\0';
out = buf; len += kl + 1 + vl;
}
char *tail = arena_strdup(a, "]");
char *buf = (char *)arena_alloc(a, len + 2);
memcpy(buf, out, len); strcpy(buf + len, tail);
return buf;
}
char *val_to_str(Arena *a, Value v) {
switch (v.type) {
case VAL_NUM: {
char buf[64];
snprintf(buf, sizeof(buf), "%.12g", v.as.num);
return arena_strdup(a, buf);
}
case VAL_INT: {
char buf[32];
snprintf(buf, sizeof(buf), "%lld", (long long)v.as.i);
return arena_strdup(a, buf);
}
case VAL_STR: return v.as.str ? v.as.str : "";
case VAL_BOOL: return arena_strdup(a, v.as.boolean ? "true" : "false");
case VAL_NIL: return arena_strdup(a, "nil");
case VAL_MODULE: return arena_strdup(a, "<module>");
case VAL_FUNC: {
char buf[128];
snprintf(buf, sizeof(buf), "<func %s>", v.as.funcname ? v.as.funcname : "?");
return arena_strdup(a, buf);
}
case VAL_ARRAY: return arr_to_str(a, (const Arr *)v.as.arr, 0);
case VAL_CLOSURE: {
Closure *cl = (Closure *)v.as.closure;
if (cl && cl->fn && cl->fn->u.func.name) {
char buf[128];
snprintf(buf, sizeof(buf), "<closure %s>", cl->fn->u.func.name);
return arena_strdup(a, buf);
}
return arena_strdup(a, "<closure>");
}
case VAL_PTR: {
char buf[64];
snprintf(buf, sizeof(buf), "<ptr %p>", v.as.ptr);
return arena_strdup(a, buf);
}
}
return arena_strdup(a, "?");
}
int value_equal(Value a, Value b, int depth) {
if (depth > 64) return 1;
if (a.type == b.type) {
switch (a.type) {
case VAL_NUM: return a.as.num == b.as.num;
case VAL_INT: return a.as.i == b.as.i;
case VAL_BOOL: return a.as.boolean == b.as.boolean;
case VAL_NIL: return 1;
case VAL_STR: return strcmp(a.as.str, b.as.str) == 0;
case VAL_ARRAY: {
Arr *x = (Arr *)a.as.arr, *y = (Arr *)b.as.arr;
if (arr_len(x) != arr_len(y)) return 0;
for (int i = 0; i < arr_len(x); ++i) {
ArrEntry *xe = arr_at(x, i);
ArrEntry *ye = arr_find(xe->is_str, xe->skey, xe->ikey, y);
if (!ye) return 0;
if (!value_equal(xe->value, ye->value, depth + 1)) return 0;
}
return 1;
}
default:
if (a.type == VAL_CLOSURE) return a.as.closure == b.as.closure;
if (a.type == VAL_PTR) return a.as.ptr == b.as.ptr;
return 0;
}
}
if ((a.type == VAL_INT && b.type == VAL_NUM) ||
(a.type == VAL_NUM && b.type == VAL_INT)) {
int64_t iv = (a.type == VAL_INT) ? a.as.i : b.as.i;
double fv = (a.type == VAL_NUM) ? a.as.num : b.as.num;
return (double)iv == fv;
}
return 0;
}
static int val_equal(Value a, Value b) { return value_equal(a, b, 0); }
typedef struct {
char **names;
int count;
int cap;
} FVSet;
static void fvset_init(FVSet *s) {
s->names = NULL; s->count = 0; s->cap = 0;
}
static void fvset_add(FVSet *s, const char *name) {
for (int i = 0; i < s->count; ++i)
if (strcmp(s->names[i], name) == 0) return;
if (s->count >= s->cap) {
int ncap = s->cap ? s->cap * 2 : 32;
s->names = (char **)realloc(s->names, (size_t)ncap * sizeof(char *));
if (!s->names) abort();
s->cap = ncap;
}
s->names[s->count++] = (char *)name;
}
static int fvset_has(FVSet *s, const char *name) {
for (int i = 0; i < s->count; ++i)
if (strcmp(s->names[i], name) == 0) return 1;
return 0;
}
static void fvset_free(FVSet *s) { free(s->names); s->names = NULL; s->count = s->cap = 0; }
static void fv_collect_expr(FVSet *used, Expr *e);
static void fv_collect_stmt(FVSet *used, FVSet *locals, Stmt *s);
static void fv_collect_expr(FVSet *used, Expr *e) {
if (!e) return;
switch (e->kind) {
case EXPR_VAR: fvset_add(used, e->u.name); break;
case EXPR_ASSIGN: fvset_add(used, e->u.assign.name); break;
case EXPR_UNARY: fv_collect_expr(used, e->u.unary.inner); break;
case EXPR_BINARY:
fv_collect_expr(used, e->u.binary.left);
fv_collect_expr(used, e->u.binary.right);
break;
case EXPR_CALL:
fv_collect_expr(used, e->u.call.callee);
for (int i = 0; i < e->u.call.argc; ++i)
fv_collect_expr(used, e->u.call.args[i]);
break;
case EXPR_MEMBER:
fv_collect_expr(used, e->u.member.obj);
break;
case EXPR_INDEX:
fv_collect_expr(used, e->u.idx.obj);
fv_collect_expr(used, e->u.idx.index);
break;
case EXPR_INDEX_ASSIGN:
fv_collect_expr(used, e->u.index_assign.target);
fv_collect_expr(used, e->u.index_assign.value);
break;
case EXPR_ARRAY:
for (int i = 0; i < e->u.array.count; ++i) {
fv_collect_expr(used, e->u.array.keys[i]);
fv_collect_expr(used, e->u.array.vals[i]);
}
break;
case EXPR_LAMBDA:
break;
default: break;
}
}
static void fv_collect_stmt(FVSet *used, FVSet *locals, Stmt *s) {
if (!s) return;
switch (s->kind) {
case STMT_LET:
fvset_add(locals, s->u.let.name);
if (s->u.let.init) fv_collect_expr(used, s->u.let.init);
break;
case STMT_ASSIGN:
fvset_add(used, s->u.assign.name);
fv_collect_expr(used, s->u.assign.value);
break;
case STMT_IF:
fv_collect_expr(used, s->u.ifs.cond);
fv_collect_stmt(used, locals, s->u.ifs.then_b);
if (s->u.ifs.else_b) fv_collect_stmt(used, locals, s->u.ifs.else_b);
break;
case STMT_WHILE:
fv_collect_expr(used, s->u.whiles.cond);
fv_collect_stmt(used, locals, s->u.whiles.body);
break;
case STMT_FOR:
if (s->u.fors.init) fv_collect_stmt(used, locals, s->u.fors.init);
if (s->u.fors.cond) fv_collect_expr(used, s->u.fors.cond);
if (s->u.fors.step) fv_collect_expr(used, s->u.fors.step);
fv_collect_stmt(used, locals, s->u.fors.body);
break;
case STMT_RETURN:
if (s->u.returns.value) fv_collect_expr(used, s->u.returns.value);
break;
case STMT_BLOCK:
for (int i = 0; i < s->u.block.count; ++i)
fv_collect_stmt(used, locals, s->u.block.stmts[i]);
break;
case STMT_FUNC:
if (s->u.func.name) fvset_add(locals, s->u.func.name);
break;
case STMT_EXPR:
if (s->u.expr) fv_collect_expr(used, s->u.expr);
break;
case STMT_TRY:
fv_collect_stmt(used, locals, s->u.trys.body);
if (s->u.trys.catchvar) fvset_add(locals, s->u.trys.catchvar);
if (s->u.trys.catchbody) fv_collect_stmt(used, locals, s->u.trys.catchbody);
if (s->u.trys.finallybody) fv_collect_stmt(used, locals, s->u.trys.finallybody);
break;
case STMT_THROW:
if (s->u.throws.value) fv_collect_expr(used, s->u.throws.value);
break;
}
}
static void collect_freevars_one(Arena *a, Stmt *func) {
if (!func || func->kind != STMT_FUNC) return;
FVSet used, locals, params;
fvset_init(&used); fvset_init(&locals); fvset_init(¶ms);
for (int i = 0; i < func->u.func.pcount; ++i)
fvset_add(¶ms, func->u.func.params[i]);
fv_collect_stmt(&used, &locals, func->u.func.body);
int freecount = 0;
for (int i = 0; i < used.count; ++i)
if (!fvset_has(&locals, used.names[i]) && !fvset_has(¶ms, used.names[i]))
freecount++;
if (freecount == 0) {
func->u.func.freevars = NULL;
func->u.func.freecount = 0;
} else {
char **fv = (char **)arena_alloc(a, (size_t)freecount * sizeof(char *));
int idx = 0;
for (int i = 0; i < used.count; ++i)
if (!fvset_has(&locals, used.names[i]) && !fvset_has(¶ms, used.names[i]))
fv[idx++] = used.names[i];
func->u.func.freevars = fv;
func->u.func.freecount = freecount;
}
fvset_free(&used); fvset_free(&locals); fvset_free(¶ms);
}
static void collect_freevars_deep_expr(Arena *a, Expr *e);
static void collect_freevars_deep(Arena *a, Stmt *s) {
if (!s) return;
if (s->kind == STMT_FUNC) {
if (s->u.func.body) collect_freevars_deep(a, s->u.func.body);
collect_freevars_one(a, s);
return;
}
switch (s->kind) {
case STMT_BLOCK:
for (int i = 0; i < s->u.block.count; ++i)
collect_freevars_deep(a, s->u.block.stmts[i]);
break;
case STMT_IF:
collect_freevars_deep(a, s->u.ifs.then_b);
collect_freevars_deep(a, s->u.ifs.else_b);
break;
case STMT_WHILE:
collect_freevars_deep(a, s->u.whiles.body);
break;
case STMT_FOR:
collect_freevars_deep(a, s->u.fors.init);
collect_freevars_deep(a, s->u.fors.body);
break;
case STMT_LET:
collect_freevars_deep_expr(a, s->u.let.init);
break;
case STMT_ASSIGN:
collect_freevars_deep_expr(a, s->u.assign.value);
break;
case STMT_EXPR:
collect_freevars_deep_expr(a, s->u.expr);
break;
case STMT_RETURN:
collect_freevars_deep_expr(a, s->u.returns.value);
break;
case STMT_TRY:
collect_freevars_deep(a, s->u.trys.body);
collect_freevars_deep(a, s->u.trys.catchbody);
collect_freevars_deep(a, s->u.trys.finallybody);
break;
default: break;
}
}
static void collect_freevars_deep_expr(Arena *a, Expr *e) {
if (!e) return;
switch (e->kind) {
case EXPR_LAMBDA: {
Stmt *func = e->u.lambda;
if (func->u.func.body)
collect_freevars_deep(a, func->u.func.body);
collect_freevars_one(a, func);
return;
}
case EXPR_UNARY:
collect_freevars_deep_expr(a, e->u.unary.inner);
break;
case EXPR_BINARY:
collect_freevars_deep_expr(a, e->u.binary.left);
collect_freevars_deep_expr(a, e->u.binary.right);
break;
case EXPR_CALL:
collect_freevars_deep_expr(a, e->u.call.callee);
for (int i = 0; i < e->u.call.argc; ++i)
collect_freevars_deep_expr(a, e->u.call.args[i]);
break;
case EXPR_ASSIGN:
collect_freevars_deep_expr(a, e->u.assign.value);
break;
case EXPR_MEMBER:
collect_freevars_deep_expr(a, e->u.member.obj);
break;
case EXPR_INDEX:
collect_freevars_deep_expr(a, e->u.idx.obj);
collect_freevars_deep_expr(a, e->u.idx.index);
break;
case EXPR_INDEX_ASSIGN:
collect_freevars_deep_expr(a, e->u.index_assign.target);
collect_freevars_deep_expr(a, e->u.index_assign.value);
break;
case EXPR_ARRAY:
for (int i = 0; i < e->u.array.count; ++i) {
collect_freevars_deep_expr(a, e->u.array.keys[i]);
collect_freevars_deep_expr(a, e->u.array.vals[i]);
}
break;
default: break;
}
}
void cvm_collect_freevars(Arena *a, Program *p) {
for (int i = 0; i < p->count; ++i)
collect_freevars_deep(a, p->stmts[i]);
}
Runtime *rt_new(void) {
Runtime *rt = (Runtime *)malloc(sizeof(Runtime));
if (!rt) abort();
arena_init(&rt->arena);
rt->global = env_new(NULL, &rt->arena);
map_init(&rt->funcs);
map_init(&rt->builtins);
map_init(&rt->modules);
map_init(&rt->ffi_syms);
map_init(&rt->ffi_sigs);
map_init(&rt->ffi_allow);
map_init(&rt->ffi_allow_sym);
rt->ffi_count = 0;
rt->ffi_enabled = 0;
rt->timer_count = 0;
rt->timer_epoch = 0;
rt->return_flag = 0;
rt->return_value = val_nil();
rt->break_flag = 0;
rt->continue_flag = 0;
rt->call_depth = 0;
rt->has_error = 0;
rt->has_throw = 0;
rt->thrown = val_nil();
rt->errbuf[0] = '\0';
rt->current_file[0] = '\0';
rt->loading_n = 0;
host_register_all(rt);
return rt;
}
void rt_free(Runtime *rt) {
if (!rt) return;
map_destroy(&rt->builtins);
map_destroy(&rt->funcs);
map_destroy(&rt->modules);
map_destroy(&rt->ffi_syms);
env_free(rt->global);
for (int i = 0; i < rt->ffi_count; ++i) ffi_close(rt->ffi_libs[i].lib);
arena_destroy(&rt->arena);
free(rt);
}
void rt_register_builtin(Runtime *rt, const char *name, BuiltinFunc f) {
map_set(&rt->builtins, name, (void *)f);
}
static void interp_err(Runtime *rt, int line, const char *fmt, ...) {
va_list ap; va_start(ap, fmt);
int n = snprintf(rt->errbuf, sizeof(rt->errbuf), "运行错误 行 %d: ", line);
vsnprintf(rt->errbuf + n, sizeof(rt->errbuf) - (size_t)n, fmt, ap);
va_end(ap);
rt->has_error = 1;
}
static Value call_function(Runtime *rt, Env *env, const char *name,
Expr **args, int argc, int line);
static void exec_stmt(Runtime *rt, Env *env, Stmt *s);
static Closure *make_closure(Runtime *rt, Env *env, Stmt *fn);
static Value eval_expr(Runtime *rt, Env *env, Expr *e) {
if (rt->has_error || rt->has_throw) return val_nil();
switch (e->kind) {
case EXPR_NUM:
if (e->u.numlit.is_int) return val_int(e->u.numlit.ival);
return val_num(e->u.numlit.fval);
case EXPR_STR: return val_str(e->u.str);
case EXPR_BOOL: return val_bool(e->u.boolean);
case EXPR_NIL: return val_nil();
case EXPR_ARRAY: {
Arr *arr = (Arr *)arena_alloc(&rt->arena, sizeof(Arr));
arr_init(&rt->arena, arr);
for (int i = 0; i < e->u.array.count; ++i) {
Expr *ve = e->u.array.vals[i];
Value v = ve ? eval_expr(rt, env, ve) : val_nil();
if (rt->has_error || rt->has_throw) return val_nil();
if (e->u.array.haskey[i]) {
Value k = eval_expr(rt, env, e->u.array.keys[i]);
if (rt->has_error || rt->has_throw) return val_nil();
arr_set_from_key(rt, arr, k, v);
} else {
arr_append(&rt->arena, arr, v);
}
}
return val_array(arr);
}
case EXPR_LAMBDA: {
Closure *cl = make_closure(rt, env, e->u.lambda);
return val_closure(cl);
}
case EXPR_VAR: {
Value *v = env_get(env, e->u.name);
if (!v) { interp_err(rt, e->line, "未定义的变量 '%s'", e->u.name); return val_nil(); }
return *v;
}
case EXPR_UNARY: {
Value inner = eval_expr(rt, env, e->u.unary.inner);
if (rt->has_error || rt->has_throw) return val_nil();
if (e->u.unary.op == TK_MINUS) {
if (inner.type == VAL_INT) return val_int(-inner.as.i);
if (inner.type == VAL_NUM) return val_num(-inner.as.num);
interp_err(rt, e->line, "一元'-'需要数字或整数"); return val_nil();
} else {
return val_bool(!val_truthy(inner));
}
}
case EXPR_BINARY: {
int op = e->u.binary.op;
if (op == TK_AND || op == TK_OR) {
Value l = eval_expr(rt, env, e->u.binary.left);
if (rt->has_error || rt->has_throw) return val_nil();
if (op == TK_AND) {
if (!val_truthy(l)) return l;
return eval_expr(rt, env, e->u.binary.right);
} else {
if (val_truthy(l)) return l;
return eval_expr(rt, env, e->u.binary.right);
}
}
Value l = eval_expr(rt, env, e->u.binary.left);
if (rt->has_error || rt->has_throw) return val_nil();
Value r = eval_expr(rt, env, e->u.binary.right);
if (rt->has_error || rt->has_throw) return val_nil();
switch (op) {
case TK_PLUS: {
if (l.type == VAL_STR && r.type == VAL_STR) {
size_t nl = strlen(l.as.str), nr = strlen(r.as.str);
char *buf = (char *)arena_alloc(&rt->arena, nl + nr + 1);
memcpy(buf, l.as.str, nl); memcpy(buf + nl, r.as.str, nr); buf[nl + nr] = '\0';
return val_str(buf);
}
if (l.type == VAL_INT && r.type == VAL_INT) return val_int(l.as.i + r.as.i);
if (l.type == VAL_NUM && r.type == VAL_NUM) return val_num(l.as.num + r.as.num);
if ((l.type == VAL_INT || l.type == VAL_NUM) &&
(r.type == VAL_INT || r.type == VAL_NUM)) {
double a = (l.type == VAL_INT) ? (double)l.as.i : l.as.num;
double b = (r.type == VAL_INT) ? (double)r.as.i : r.as.num;
return val_num(a + b);
}
interp_err(rt, e->line, "'+' 需要两个数字/整数或两个字符串"); return val_nil();
}
case TK_MINUS:
case TK_STAR:
case TK_SLASH:
case TK_PERCENT: {
if (l.type == VAL_INT && r.type == VAL_INT) {
if (op == TK_MINUS) return val_int(l.as.i - r.as.i);
if (op == TK_STAR) return val_int(l.as.i * r.as.i);
if (op == TK_SLASH) {
if (r.as.i == 0) { interp_err(rt, e->line, "除以零"); return val_nil(); }
return val_int(l.as.i / r.as.i);
}
if (op == TK_PERCENT) {
if (r.as.i == 0) { interp_err(rt, e->line, "取模零"); return val_nil(); }
return val_int(l.as.i % r.as.i);
}
break;
}
if (l.type == VAL_NUM && r.type == VAL_NUM) {
if (op == TK_MINUS) return val_num(l.as.num - r.as.num);
if (op == TK_STAR) return val_num(l.as.num * r.as.num);
if (op == TK_SLASH) {
if (r.as.num == 0.0) { interp_err(rt, e->line, "除以零"); return val_nil(); }
return val_num(l.as.num / r.as.num);
}
if (op == TK_PERCENT) {
if (r.as.num == 0.0) { interp_err(rt, e->line, "取模零"); return val_nil(); }
return val_num(fmod(l.as.num, r.as.num));
}
break;
}
if ((l.type == VAL_INT || l.type == VAL_NUM) &&
(r.type == VAL_INT || r.type == VAL_NUM)) {
double a = (l.type == VAL_INT) ? (double)l.as.i : l.as.num;
double b = (r.type == VAL_INT) ? (double)r.as.i : r.as.num;
if (op == TK_MINUS) return val_num(a - b);
if (op == TK_STAR) return val_num(a * b);
if (op == TK_SLASH) {
if (b == 0.0) { interp_err(rt, e->line, "除以零"); return val_nil(); }
return val_num(a / b);
}
if (op == TK_PERCENT) {
if (b == 0.0) { interp_err(rt, e->line, "取模零"); return val_nil(); }
return val_num(fmod(a, b));
}
break;
}
interp_err(rt, e->line, "算术运算需要数字或整数"); return val_nil();
}
case TK_EQEQ: return val_bool(val_equal(l, r));
case TK_NOTEQ: return val_bool(!val_equal(l, r));
case TK_LT: case TK_GT: case TK_LE: case TK_GE: {
if (l.type == VAL_INT && r.type == VAL_INT) {
int64_t a = l.as.i, b = r.as.i;
if (op == TK_LT) return val_bool(a < b);
if (op == TK_GT) return val_bool(a > b);
if (op == TK_LE) return val_bool(a <= b);
return val_bool(a >= b);
}
if (l.type == VAL_NUM && r.type == VAL_NUM) {
double a = l.as.num, b = r.as.num;
if (op == TK_LT) return val_bool(a < b);
if (op == TK_GT) return val_bool(a > b);
if (op == TK_LE) return val_bool(a <= b);
return val_bool(a >= b);
}
if (l.type == VAL_STR && r.type == VAL_STR) {
int c = strcmp(l.as.str, r.as.str);
if (op == TK_LT) return val_bool(c < 0);
if (op == TK_GT) return val_bool(c > 0);
if (op == TK_LE) return val_bool(c <= 0);
return val_bool(c >= 0);
}
if ((l.type == VAL_INT || l.type == VAL_NUM) &&
(r.type == VAL_INT || r.type == VAL_NUM)) {
double a = (l.type == VAL_INT) ? (double)l.as.i : l.as.num;
double b = (r.type == VAL_INT) ? (double)r.as.i : r.as.num;
if (op == TK_LT) return val_bool(a < b);
if (op == TK_GT) return val_bool(a > b);
if (op == TK_LE) return val_bool(a <= b);
return val_bool(a >= b);
}
interp_err(rt, e->line, "比较需要同类型数字或字符串"); return val_nil();
}
default: break;
}
interp_err(rt, e->line, "未知运算符"); return val_nil();
}
case EXPR_CALL: {
Expr *callee = e->u.call.callee;
if (callee->kind == EXPR_VAR) {
Value *cv = env_get(env, callee->u.name);
if (cv && cv->type == VAL_CLOSURE) {
Closure *cl = (Closure *)cv->as.closure;
Stmt *fn = cl->fn;
if (rt->call_depth >= CVM_MAX_CALL_DEPTH) {
interp_err(rt, e->line, "递归深度超过上限 (%d)", CVM_MAX_CALL_DEPTH);
return val_nil();
}
rt->call_depth++;
if (e->u.call.argc != fn->u.func.pcount) {
interp_err(rt, e->line, "函数期望 %d 个参数, 收到 %d",
fn->u.func.pcount, e->u.call.argc);
rt->call_depth--;
return val_nil();
}
Env *fen = env_new(cl->capenv, &rt->arena);
for (int i = 0; i < e->u.call.argc; ++i)
env_define(fen, fn->u.func.params[i],
eval_expr(rt, env, e->u.call.args[i]), &rt->arena);
if (rt->has_error || rt->has_throw) { env_free(fen); rt->call_depth--; return val_nil(); }
rt->return_flag = 0;
exec_stmt(rt, fen, fn->u.func.body);
Value r = rt->return_flag ? rt->return_value : val_nil();
rt->return_flag = 0;
env_free(fen);
rt->call_depth--;
return r;
}
}
const char *fname = NULL;
if (callee->kind == EXPR_VAR) {
fname = callee->u.name;
} else if (callee->kind == EXPR_MEMBER) {
Value obj = eval_expr(rt, env, callee->u.member.obj);
if (rt->has_error || rt->has_throw) return val_nil();
if (obj.type != VAL_MODULE) {
interp_err(rt, e->line, "只有模块才能用 '.' 访问成员");
return val_nil();
}
Value *mem = (Value *)map_get((Map *)obj.as.mod, callee->u.member.name);
if (!mem) {
interp_err(rt, e->line, "模块未导出成员 '%s'", callee->u.member.name);
return val_nil();
}
if (mem->type != VAL_FUNC) {
interp_err(rt, e->line, "成员 '%s' 不是可调用函数", callee->u.member.name);
return val_nil();
}
fname = mem->as.funcname;
} else {
interp_err(rt, e->line, "不支持的调用目标");
return val_nil();
}
return call_function(rt, env, fname, e->u.call.args, e->u.call.argc, e->line);
}
case EXPR_MEMBER: {
Value obj = eval_expr(rt, env, e->u.member.obj);
if (rt->has_error || rt->has_throw) return val_nil();
if (obj.type != VAL_MODULE) {
interp_err(rt, e->line, "只有模块才能用 '.' 访问成员");
return val_nil();
}
Value *mem = (Value *)map_get((Map *)obj.as.mod, e->u.member.name);
if (!mem) {
interp_err(rt, e->line, "模块未导出成员 '%s'", e->u.member.name);
return val_nil();
}
return *mem;
}
case EXPR_INDEX: {
Value obj = eval_expr(rt, env, e->u.idx.obj);
if (rt->has_error || rt->has_throw) return val_nil();
if (obj.type == VAL_STR) {
Value key = eval_expr(rt, env, e->u.idx.index);
if (rt->has_error || rt->has_throw) return val_nil();
long idx;
if (key.type == VAL_INT) idx = (long)key.as.i;
else if (key.type == VAL_NUM) idx = (long)key.as.num;
else { interp_err(rt, e->line, "字符串索引需要整数"); return val_nil(); }
int clen;
const char *p = utf8_char_at_ptr(obj.as.str, idx, &clen);
if (!p) { interp_err(rt, e->line, "字符串索引越界"); 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);
}
if (obj.type != VAL_ARRAY) { interp_err(rt, e->line, "下标操作需要数组或字符串"); return val_nil(); }
Value key = eval_expr(rt, env, e->u.idx.index);
if (rt->has_error || rt->has_throw) return val_nil();
ArrEntry *ent = arr_lookup(rt, (Arr *)obj.as.arr, key);
if (!ent) return val_nil();
return ent->value;
}
case EXPR_INDEX_ASSIGN: {
Expr *t = e->u.index_assign.target;
Value obj = eval_expr(rt, env, t->u.idx.obj);
if (rt->has_error || rt->has_throw) return val_nil();
if (obj.type == VAL_STR) {
Value key = eval_expr(rt, env, t->u.idx.index);
if (rt->has_error || rt->has_throw) return val_nil();
Value v = eval_expr(rt, env, e->u.index_assign.value);
if (rt->has_error || rt->has_throw) return val_nil();
long idx;
if (key.type == VAL_INT) idx = (long)key.as.i;
else if (key.type == VAL_NUM) idx = (long)key.as.num;
else { interp_err(rt, e->line, "字符串下标需要整数"); return val_nil(); }
if (idx < 0) { interp_err(rt, e->line, "字符串下标不能为负"); return val_nil(); }
int64_t new_cp;
if (v.type == VAL_STR) {
new_cp = utf8_codepoint_at(v.as.str, 0);
if (new_cp < 0 || v.as.str[0] == '\0')
{ interp_err(rt, e->line, "字符串下标赋值需要非空字符"); return val_nil(); }
} else if (v.type == VAL_INT) {
new_cp = v.as.i;
} else if (v.type == VAL_NUM) {
new_cp = (int64_t)v.as.num;
} else {
interp_err(rt, e->line, "字符串下标赋值需要字符、整数或码点值");
return val_nil();
}
int old_clen;
const char *old_p = utf8_char_at_ptr(obj.as.str, idx, &old_clen);
if (!old_p) { interp_err(rt, e->line, "字符串索引越界"); return val_nil(); }
size_t prefix_len = (size_t)(old_p - obj.as.str);
size_t suffix_start = prefix_len + (size_t)old_clen;
size_t suffix_len = strlen(obj.as.str + suffix_start);
char enc[4];
int enclen = utf8_encode(new_cp, enc);
size_t new_len = prefix_len + (size_t)enclen + suffix_len;
char *new_s = (char *)arena_alloc(&rt->arena, new_len + 1);
if (prefix_len) memcpy(new_s, obj.as.str, prefix_len);
memcpy(new_s + prefix_len, enc, (size_t)enclen);
if (suffix_len) memcpy(new_s + prefix_len + enclen, obj.as.str + suffix_start, suffix_len);
new_s[new_len] = '\0';
Value result = val_str(new_s);
if (t->u.idx.obj->kind == EXPR_VAR)
env_assign(env, t->u.idx.obj->u.name, result, &rt->arena);
return result;
}
if (obj.type != VAL_ARRAY) { interp_err(rt, e->line, "下标赋值需要数组"); return val_nil(); }
Value key = eval_expr(rt, env, t->u.idx.index);
if (rt->has_error || rt->has_throw) return val_nil();
Value v = eval_expr(rt, env, e->u.index_assign.value);
if (rt->has_error || rt->has_throw) return val_nil();
arr_set_from_key(rt, (Arr *)obj.as.arr, key, v);
return v;
}
case EXPR_ASSIGN: {
Value v = eval_expr(rt, env, e->u.assign.value);
if (rt->has_error || rt->has_throw) return val_nil();
env_assign(env, e->u.assign.name, v, &rt->arena);
return v;
}
}
interp_err(rt, e->line, "未知表达式节点"); return val_nil();
}
static Closure *make_closure(Runtime *rt, Env *env, Stmt *fn) {
Env *def_env = env;
Env *root_env = env_root(def_env);
Env *capenv = env_new(root_env, &rt->arena);
for (int i = 0; i < fn->u.func.freecount; ++i) {
const char *fv = fn->u.func.freevars[i];
Value *slot = NULL;
Env *owner = env_get_owner(def_env, fv, &slot);
if (owner && owner != root_env && slot)
env_link(capenv, fv, slot);
}
Closure *cl = (Closure *)arena_alloc(&rt->arena, sizeof(Closure));
cl->fn = fn;
cl->capenv = capenv;
return cl;
}
static void exec_block(Runtime *rt, Env *env, Stmt *s) {
Env *be = env_new(env, &rt->arena);
for (int i = 0; i < s->u.block.count; ++i) {
exec_stmt(rt, be, s->u.block.stmts[i]);
if (rt->has_error || rt->has_throw || rt->return_flag || rt->break_flag || rt->continue_flag) break;
}
env_free(be);
}
static void exec_stmt(Runtime *rt, Env *env, Stmt *s) {
if (rt->has_error || rt->has_throw) return;
switch (s->kind) {
case STMT_LET: {
Value v = s->u.let.init ? eval_expr(rt, env, s->u.let.init) : val_nil();
if (rt->has_error || rt->has_throw) return;
env_define(env, s->u.let.name, v, &rt->arena);
return;
}
case STMT_ASSIGN: {
Value v = eval_expr(rt, env, s->u.assign.value);
if (rt->has_error || rt->has_throw) return;
env_assign(env, s->u.assign.name, v, &rt->arena);
return;
}
case STMT_IF: {
Value c = eval_expr(rt, env, s->u.ifs.cond);
if (rt->has_error || rt->has_throw) return;
if (val_truthy(c)) exec_stmt(rt, env, s->u.ifs.then_b);
else if (s->u.ifs.else_b) exec_stmt(rt, env, s->u.ifs.else_b);
return;
}
case STMT_WHILE: {
int fast = 0; const char *cv=NULL; int64_t cc=0; int co=0;
if (s->u.whiles.cond && s->u.whiles.cond->kind == EXPR_BINARY) {
Expr *ce = s->u.whiles.cond; int op = ce->u.binary.op;
if ((op==TK_LT||op==TK_GT||op==TK_LE||op==TK_GE) &&
ce->u.binary.left && ce->u.binary.left->kind==EXPR_VAR &&
ce->u.binary.right && ce->u.binary.right->kind==EXPR_NUM &&
ce->u.binary.right->u.numlit.is_int) {
fast=1; cv=ce->u.binary.left->u.name;
cc=ce->u.binary.right->u.numlit.ival; co=op;
}
}
while (1) {
if (rt->break_flag) break;
rt->continue_flag = 0;
if (fast) {
Value *vp = env_get(env_root(env), cv);
int64_t v = (vp && vp->type == VAL_INT) ? vp->as.i : (vp ? (int64_t)vp->as.num : 0);
int ok; switch(co){case TK_LT:ok=v<cc;break;case TK_GT:ok=v>cc;break;case TK_LE:ok=v<=cc;break;case TK_GE:ok=v>=cc;break;default:ok=0;break;}
if (!ok) break;
} else {
Value c = eval_expr(rt, env, s->u.whiles.cond);
if (rt->has_error || rt->has_throw) return;
if (!val_truthy(c)) break;
}
exec_stmt(rt, env, s->u.whiles.body);
if (rt->has_error || rt->has_throw || rt->return_flag || rt->break_flag) break;
}
rt->break_flag = 0; rt->continue_flag = 0;
return;
}
case STMT_FOR: {
if (s->u.fors.init) { exec_stmt(rt, env, s->u.fors.init); if (rt->has_error || rt->has_throw || rt->return_flag || rt->break_flag) return; }
while (1) {
if (rt->break_flag) break;
rt->continue_flag = 0;
if (s->u.fors.cond) {
Value c = eval_expr(rt, env, s->u.fors.cond);
if (rt->has_error || rt->has_throw) return;
if (!val_truthy(c)) break;
}
exec_stmt(rt, env, s->u.fors.body);
if (rt->has_error || rt->has_throw || rt->return_flag || rt->break_flag) break;
if (s->u.fors.step) { eval_expr(rt, env, s->u.fors.step); if (rt->has_error || rt->has_throw) return; }
}
rt->break_flag = 0; rt->continue_flag = 0;
return;
}
case STMT_FOR_IN: {
Value it = eval_expr(rt, env, s->u.for_in.iterable);
if (rt->has_error || rt->has_throw) { rt->break_flag = 0; rt->continue_flag = 0; return; }
if (it.type == VAL_ARRAY) {
Arr *arr = (Arr *)it.as.arr;
int n = arr_len(arr);
for (int i = 0; i < n; ++i) {
if (rt->break_flag) break;
rt->continue_flag = 0;
ArrEntry *e = arr_at(arr, i);
Value elem = e ? e->value : val_nil();
env_define(env, s->u.for_in.iter_var, elem, &rt->arena);
exec_stmt(rt, env, s->u.for_in.body);
if (rt->has_error || rt->has_throw || rt->return_flag || rt->break_flag) break;
}
} else if (it.type == VAL_STR) {
const char *str = it.as.str ? it.as.str : "";
int n = (int)strlen(str);
for (int i = 0; i < n; ++i) {
if (rt->break_flag) break;
rt->continue_flag = 0;
char buf[2] = { str[i], '\0' };
Value elem = val_str(arena_strdup(&rt->arena, buf));
env_define(env, s->u.for_in.iter_var, elem, &rt->arena);
exec_stmt(rt, env, s->u.for_in.body);
if (rt->has_error || rt->has_throw || rt->return_flag || rt->break_flag) break;
}
} else {
interp_err(rt, s->line, "for-in 暂不支持该类型");
rt->break_flag = 0; rt->continue_flag = 0;
return;
}
rt->break_flag = 0; rt->continue_flag = 0;
return;
}
case STMT_RETURN: {
if (s->u.returns.value) {
rt->return_value = eval_expr(rt, env, s->u.returns.value);
if (rt->has_error || rt->has_throw) return;
} else {
rt->return_value = val_nil();
}
rt->return_flag = 1;
return;
}
case STMT_BREAK:
rt->break_flag = 1;
return;
case STMT_CONTINUE:
rt->continue_flag = 1;
return;
case STMT_BLOCK:
exec_block(rt, env, s);
return;
case STMT_FUNC: {
Stmt *fn = s;
Closure *cl = make_closure(rt, env, fn);
if (fn->u.func.name) {
map_set(&rt->funcs, fn->u.func.name, cl);
env_define(env, fn->u.func.name, val_closure(cl), &rt->arena);
}
return;
}
case STMT_EXPR: {
if (s->u.expr) { eval_expr(rt, env, s->u.expr); }
return;
}
case STMT_THROW: {
if (rt->has_error || rt->has_throw) return;
Value v = s->u.throws.value ? eval_expr(rt, env, s->u.throws.value) : val_nil();
if (rt->has_error || rt->has_throw) return;
rt->thrown = v;
rt->has_throw = 1;
return;
}
case STMT_TRY: {
exec_stmt(rt, env, s->u.trys.body);
if (rt->has_throw) {
if (s->u.trys.catchvar && s->u.trys.catchbody) {
Env *ce = env_new(env, &rt->arena);
env_define(ce, s->u.trys.catchvar, rt->thrown, &rt->arena);
rt->has_throw = 0;
exec_stmt(rt, ce, s->u.trys.catchbody);
env_free(ce);
}
}
if (s->u.trys.finallybody) {
int pend_throw = rt->has_throw;
int pend_err = rt->has_error;
rt->has_throw = 0; rt->has_error = 0;
exec_stmt(rt, env, s->u.trys.finallybody);
if (!rt->has_error && !rt->has_throw) {
if (pend_err) rt->has_error = 1;
if (pend_throw) rt->has_throw = 1;
}
}
return;
}
}
}
typedef union { double d; int64_t i; void *p; } CArg;
static CArg ffi_val_to_c(Runtime *rt, int line, Value v, char code) {
CArg out; out.i = 0;
switch (code) {
case 'd':
if (v.type == VAL_INT) { out.d = (double)v.as.i; break; }
if (v.type == VAL_NUM) { out.d = v.as.num; break; }
interp_err(rt, line, "FFI 参数需要数字 (类型 'd')"); return out;
case 'i':
if (v.type == VAL_INT) { out.i = v.as.i; break; }
if (v.type == VAL_NUM) { out.i = (int64_t)(int)v.as.num; break; }
interp_err(rt, line, "FFI 参数需要数字 (类型 'i')"); return out;
case 's':
if (v.type != VAL_STR) { interp_err(rt, line, "FFI 参数需要字符串 (类型 's')"); return out; }
out.p = v.as.str; break;
case 'p':
if (v.type != VAL_PTR) { interp_err(rt, line, "FFI 参数需要指针 (类型 'p')"); return out; }
out.p = v.as.ptr; break;
case 'q':
if (v.type == VAL_INT) { out.i = v.as.i; break; }
if (v.type == VAL_NUM) { out.i = (int64_t)v.as.num; break; }
interp_err(rt, line, "FFI 参数需要 int64 (类型 'q')"); return out;
default:
interp_err(rt, line, "FFI 不支持的参数类型码: '%c'", code); break;
}
return out;
}
static Value ffi_c_to_val(Runtime *rt, int line, char rc, intptr_t r) {
switch (rc) {
case 'd': return val_num((double)r);
case 'i': return val_num((double)(int)r);
case 'q': return val_int((int64_t)r);
case 'p': return val_ptr((void *)r);
case 's': {
const char *cs = (const char *)(intptr_t)r;
if (!cs) return val_str(arena_strdup(&rt->arena, ""));
return val_str(arena_strdup(&rt->arena, cs));
}
case 'v': return val_nil();
default: interp_err(rt, line, "FFI 不支持的返回类型码: '%c'", rc); return val_nil();
}
}
* 返回 d/i/p/v. 混合整型/浮点参数在 v1 中拒绝 (ABI 不确定, 避免 UB).
* 每个分支把 fp 内联转换成"精确元数"的函数指针类型再调用, 避免类型不匹配告警。 */
static Value ffi_invoke(Runtime *rt, int line, void *fp, const char *sig, int nparams, CArg *a) {
const char *rp = strchr(sig, ')');
char rc = rp ? rp[1] : sig[0];
int pbase = rp ? 0 : 1;
int all_sse = 1, all_int = 1;
for (int i = 0; i < nparams; ++i) {
char c = sig[pbase + i];
if (c == 'd') all_int = 0;
else if (c == 'i' || c == 's' || c == 'p' || c == 'q') all_sse = 0;
else { interp_err(rt, line, "FFI 不支持的参数类型码: '%c'", c); return val_nil(); }
}
if (!all_sse && !all_int) {
interp_err(rt, line, "FFI 暂不支持整型/浮点混合参数 (v1)");
return val_nil();
}
int n = nparams < 6 ? nparams : 6;
if (all_sse) {
double d[6]; for (int i = 0; i < nparams; ++i) d[i] = a[i].d;
if (rc == 'd') {
double r;
switch (n) {
case 0: r = ((double(*)(void))fp)(); break;
case 1: r = ((double(*)(double))fp)(d[0]); break;
case 2: r = ((double(*)(double,double))fp)(d[0], d[1]); break;
case 3: r = ((double(*)(double,double,double))fp)(d[0], d[1], d[2]); break;
case 4: r = ((double(*)(double,double,double,double))fp)(d[0], d[1], d[2], d[3]); break;
case 5: r = ((double(*)(double,double,double,double,double))fp)(d[0], d[1], d[2], d[3], d[4]); break;
default: r = ((double(*)(double,double,double,double,double,double))fp)(d[0], d[1], d[2], d[3], d[4], d[5]); break;
}
return val_num(r);
} else {
intptr_t r;
switch (n) {
case 0: r = ((intptr_t(*)(void))fp)(); break;
case 1: r = ((intptr_t(*)(double))fp)(d[0]); break;
case 2: r = ((intptr_t(*)(double,double))fp)(d[0], d[1]); break;
case 3: r = ((intptr_t(*)(double,double,double))fp)(d[0], d[1], d[2]); break;
case 4: r = ((intptr_t(*)(double,double,double,double))fp)(d[0], d[1], d[2], d[3]); break;
case 5: r = ((intptr_t(*)(double,double,double,double,double))fp)(d[0], d[1], d[2], d[3], d[4]); break;
default: r = ((intptr_t(*)(double,double,double,double,double,double))fp)(d[0], d[1], d[2], d[3], d[4], d[5]); break;
}
return ffi_c_to_val(rt, line, rc, r);
}
} else {
intptr_t d[6]; for (int i = 0; i < nparams; ++i) d[i] = a[i].i;
if (rc == 'd') {
double r;
switch (n) {
case 0: r = ((double(*)(void))fp)(); break;
case 1: r = ((double(*)(intptr_t))fp)(d[0]); break;
case 2: r = ((double(*)(intptr_t,intptr_t))fp)(d[0], d[1]); break;
case 3: r = ((double(*)(intptr_t,intptr_t,intptr_t))fp)(d[0], d[1], d[2]); break;
case 4: r = ((double(*)(intptr_t,intptr_t,intptr_t,intptr_t))fp)(d[0], d[1], d[2], d[3]); break;
case 5: r = ((double(*)(intptr_t,intptr_t,intptr_t,intptr_t,intptr_t))fp)(d[0], d[1], d[2], d[3], d[4]); break;
default: r = ((double(*)(intptr_t,intptr_t,intptr_t,intptr_t,intptr_t,intptr_t))fp)(d[0], d[1], d[2], d[3], d[4], d[5]); break;
}
return val_num(r);
} else {
intptr_t r;
switch (n) {
case 0: r = ((intptr_t(*)(void))fp)(); break;
case 1: r = ((intptr_t(*)(intptr_t))fp)(d[0]); break;
case 2: r = ((intptr_t(*)(intptr_t,intptr_t))fp)(d[0], d[1]); break;
case 3: r = ((intptr_t(*)(intptr_t,intptr_t,intptr_t))fp)(d[0], d[1], d[2]); break;
case 4: r = ((intptr_t(*)(intptr_t,intptr_t,intptr_t,intptr_t))fp)(d[0], d[1], d[2], d[3]); break;
case 5: r = ((intptr_t(*)(intptr_t,intptr_t,intptr_t,intptr_t,intptr_t))fp)(d[0], d[1], d[2], d[3], d[4]); break;
default: r = ((intptr_t(*)(intptr_t,intptr_t,intptr_t,intptr_t,intptr_t,intptr_t))fp)(d[0], d[1], d[2], d[3], d[4], d[5]); break;
}
return ffi_c_to_val(rt, line, rc, r);
}
}
}
static Value call_function(Runtime *rt, Env *env, const char *name,
Expr **args, int argc, int line) {
BuiltinFunc bf = (BuiltinFunc)map_get(&rt->builtins, name);
if (bf) {
Value *av = (Value *)malloc((size_t)(argc > 0 ? argc : 1) * sizeof(Value));
for (int i = 0; i < argc; ++i) av[i] = eval_expr(rt, env, args[i]);
if (rt->has_error || rt->has_throw) { free(av); return val_nil(); }
Value r = bf(rt, argc, av);
free(av);
return r;
}
Closure *cl = (Closure *)map_get(&rt->funcs, name);
if (cl) {
if (rt->call_depth >= CVM_MAX_CALL_DEPTH) {
interp_err(rt, line, "递归深度超过上限 (%d)", CVM_MAX_CALL_DEPTH);
return val_nil();
}
rt->call_depth++;
Stmt *fn = cl->fn;
if (argc != fn->u.func.pcount) {
interp_err(rt, line, "函数 '%s' 期望 %d 个参数, 收到 %d",
name, fn->u.func.pcount, argc);
rt->call_depth--;
return val_nil();
}
Env *fen = env_new(cl->capenv, &rt->arena);
for (int i = 0; i < argc; ++i)
env_define(fen, fn->u.func.params[i], eval_expr(rt, env, args[i]), &rt->arena);
if (rt->has_error || rt->has_throw) { env_free(fen); rt->call_depth--; return val_nil(); }
rt->return_flag = 0;
exec_stmt(rt, fen, fn->u.func.body);
Value r = rt->return_flag ? rt->return_value : val_nil();
rt->return_flag = 0;
env_free(fen);
rt->call_depth--;
return r;
}
const char *sig = (const char *)map_get(&rt->ffi_sigs, name);
void *fp = ffi_resolve_allowed(rt, name);
if (rt->has_error) return val_nil();
if (fp) {
if (!rt->ffi_enabled) {
interp_err(rt, line, "FFI 已禁用 (ffi_enabled=0)");
return val_nil();
}
if (!sig || sig[0] == '\0') {
interp_err(rt, line, "FFI 符号未声明签名: %s", name);
return val_nil();
}
* "s)i" -> 参数 s, 返回 i (params)return 形式, 例见 strlen)
* "is" -> 返回 i, 参数 s (首字符=返回, 其后=参数; spec 正文描述)
* 二者等价, 引擎自动按是否含 ')' 判定。 */
const char *rp = strchr(sig, ')');
int nparams, pbase;
if (rp) {
nparams = (int)(rp - sig);
if (rp[1] == '\0') {
interp_err(rt, line, "FFI 签名无效 (')' 后缺返回类型): %s", name);
return val_nil();
}
pbase = 0;
} else {
if (sig[0] == '\0') {
interp_err(rt, line, "FFI 签名无效 (空签名): %s", name);
return val_nil();
}
pbase = 1;
nparams = (int)strlen(sig) - 1;
}
if (nparams < 0) nparams = 0;
if (nparams > 6) {
interp_err(rt, line, "FFI 暂不支持超过 6 个参数: %s", name);
return val_nil();
}
if (argc != nparams) {
interp_err(rt, line, "FFI 函数 '%s' 签名期望 %d 个参数, 收到 %d",
name, nparams, argc);
return val_nil();
}
CArg a[6];
for (int i = 0; i < argc; ++i) {
Value v = eval_expr(rt, env, args[i]);
if (rt->has_error || rt->has_throw) return val_nil();
a[i] = ffi_val_to_c(rt, line, v, sig[pbase + i]);
if (rt->has_error || rt->has_throw) return val_nil();
}
return ffi_invoke(rt, line, fp, sig, nparams, a);
}
interp_err(rt, line, "未定义的函数 '%s'", name);
return val_nil();
}
Program cvm_compile(Runtime *rt, const char *source, const char *name) {
Program p; p.stmts = NULL; p.count = 0; p.cap = 0; p.has_error = 0;
char lerr[256]; lerr[0] = '\0';
TokenList tl = lex(&rt->arena, source, lerr, sizeof(lerr));
if (lerr[0]) {
snprintf(rt->errbuf, sizeof(rt->errbuf), "词法错误(%s): %s", name ? name : "?", lerr);
rt->has_error = 1; p.has_error = 1; return p;
}
p = parse(&rt->arena, &tl);
if (p.has_error) {
snprintf(rt->errbuf, sizeof(rt->errbuf), "语法错误(%s): %s", name ? name : "?", p.err);
rt->has_error = 1;
}
if (!p.has_error) cvm_collect_freevars(&rt->arena, &p);
return p;
}
void cvm_exec_program(Runtime *rt, Program *p, Env *env) {
for (int i = 0; i < p->count; ++i) {
exec_stmt(rt, env, p->stmts[i]);
if (rt->has_error) return;
if (rt->has_throw) {
snprintf(rt->errbuf, sizeof(rt->errbuf), "未捕获异常: %s", val_to_str(&rt->arena, rt->thrown));
rt->has_error = 1;
return;
}
if (rt->return_flag) rt->return_flag = 0;
}
}
int rt_run(Runtime *rt, const char *source, const char *name) {
rt->has_error = 0;
rt->has_throw = 0;
rt->thrown = val_nil();
rt->errbuf[0] = '\0';
rt->return_flag = 0;
char lerr[256]; lerr[0] = '\0';
TokenList tl = lex(&rt->arena, source, lerr, sizeof(lerr));
if (lerr[0]) {
snprintf(rt->errbuf, sizeof(rt->errbuf), "词法错误: %s", lerr);
rt->has_error = 1;
return -1;
}
Program prog = parse(&rt->arena, &tl);
if (prog.has_error) {
snprintf(rt->errbuf, sizeof(rt->errbuf), "语法错误: %s", prog.err);
rt->has_error = 1;
return -1;
}
const char *force_bc = getenv("CVM_USE_BC");
int use_bc = cvm_bc_supported(&prog);
if (force_bc && (force_bc[0] == '1' || force_bc[0] == 'y' || force_bc[0] == 'Y')) use_bc = 1;
if (force_bc && (force_bc[0] == '0' || force_bc[0] == 'n' || force_bc[0] == 'N')) use_bc = 0;
if (use_bc) {
int nbfs = 0;
ByteFunc *bfs = cvm_bc_compile_all(rt, &prog, &nbfs);
if (bfs && !bfs[0].unsupported) {
cvm_bc_run(rt, &bfs[0], bfs, nbfs);
cvm_bc_free(bfs, nbfs);
if (rt->has_error) return -1;
return 0;
}
if (bfs) cvm_bc_free(bfs, nbfs);
rt->has_error = 0;
rt->has_throw = 0;
rt->thrown = val_nil();
rt->errbuf[0] = '\0';
}
cvm_collect_freevars(&rt->arena, &prog);
for (int i = 0; i < prog.count; ++i)
if (prog.stmts[i]->kind == STMT_FUNC) {
Stmt *fn = prog.stmts[i];
Closure *cl = (Closure *)arena_alloc(&rt->arena, sizeof(Closure));
cl->fn = fn;
cl->capenv = env_new(rt->global, &rt->arena);
map_set(&rt->funcs, fn->u.func.name, cl);
}
Env *env = rt->global;
for (int i = 0; i < prog.count; ++i) {
exec_stmt(rt, env, prog.stmts[i]);
if (rt->has_error) return -1;
if (rt->has_throw) {
snprintf(rt->errbuf, sizeof(rt->errbuf), "未捕获异常: %s", val_to_str(&rt->arena, rt->thrown));
rt->has_error = 1;
return -1;
}
if (rt->return_flag) rt->return_flag = 0;
}
return 0;
}
int rt_run_file(Runtime *rt, const char *path) {
FILE *f = fopen(path, "rb");
if (!f) { snprintf(rt->errbuf, sizeof(rt->errbuf), "无法打开文件: %s", path); rt->has_error = 1; return -1; }
fseek(f, 0, SEEK_END); long sz = ftell(f); fseek(f, 0, SEEK_SET);
char *buf = (char *)malloc((size_t)sz + 1);
if (!buf) { fclose(f); abort(); }
size_t rd = fread(buf, 1, (size_t)sz, f);
buf[rd] = '\0';
fclose(f);
char saved[512];
snprintf(saved, sizeof(saved), "%s", rt->current_file);
snprintf(rt->current_file, sizeof(rt->current_file), "%s", path);
int r = rt_run(rt, buf, path);
snprintf(rt->current_file, sizeof(rt->current_file), "%s", saved);
free(buf);
return r;
}
#ifdef _WIN32
# include <windows.h>
int64_t rt_now_ms(Runtime *rt) {
(void)rt;
return (int64_t)GetTickCount64();
}
#else
# include <sys/time.h>
int64_t rt_now_ms(Runtime *rt) {
(void)rt;
struct timeval tv;
gettimeofday(&tv, NULL);
return (int64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
#endif
int rt_timer_add(Runtime *rt, const char *func_name, int delay_ms, int repeat_ms) {
if (rt->timer_count >= 64) return -1;
if (!rt->timer_epoch) rt->timer_epoch = rt_now_ms(rt);
int i = rt->timer_count++;
snprintf(rt->timers[i].name, sizeof(rt->timers[i].name), "%s", func_name);
rt->timers[i].deadline_ms = rt_now_ms(rt) - rt->timer_epoch + delay_ms;
rt->timers[i].repeat_ms = repeat_ms;
rt->timers[i].active = 1;
return 0;
}
int rt_process_timers(Runtime *rt) {
if (rt->timer_count == 0) return 0;
if (!rt->timer_epoch) return 0;
int64_t now = rt_now_ms(rt) - rt->timer_epoch;
int fired = 0;
for (int i = 0; i < rt->timer_count; ++i) {
if (!rt->timers[i].active) continue;
if (rt->timers[i].deadline_ms > now) continue;
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;
fired++;
if (rt->timers[i].repeat_ms > 0) {
rt->timers[i].deadline_ms = now + rt->timers[i].repeat_ms;
} else {
rt->timers[i].active = 0;
}
}
return fired;
}