From 420c83d255ff7310718daf9a22c6931eb0c02595 Mon Sep 17 00:00:00 2001 From: "peng.li24" <734991033@qq.com> Date: Sat, 12 Sep 2026 14:48:55 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20runtime-c=20=E6=BA=90=E7=A0=81?= =?UTF-8?q?=E6=8C=89=20rwir=20=E7=B1=BB=E5=88=AB=E9=87=8D=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - builtin.c/builtin_collection.c 拆分为 rwir_*.c(int/bool/array/map/ struct/ndarray/string/time/random/vthread/kv/xvalue/func) - 新增 myrwircaps.c(opcode→处理器能力表)、kvlang_vthread.h - 改名 kv.c→kvspace.c、rwir.c→rwir_decode.c、builtin_internal.h→rwir_internal.h - kvlang_runtime.h/rwirext.c/runtime.c/ffi.rs/Makefile/README 同步 - spec(runtimec内建、cruntime与后端abi、内建函数)同步 Co-Authored-By: Claude Opus 4.8 --- Makefile | 2 +- README.md | 2 +- README_CN.md | 2 +- runtime-rs/src/ffi.rs | 6 +- runtime/include/kvlang_runtime.h | 61 +- runtime/include/kvlang_rwirext.h | 51 - runtime/include/kvlang_vthread.h | 28 + runtime/src/builtin.c | 810 ------------ runtime/src/builtin_collection.c | 1087 ----------------- runtime/src/kvcpu.c | 40 + runtime/src/{kv.c => kvspace.c} | 0 runtime/src/myrwircaps.c | 227 ++++ runtime/src/runtime.c | 2 +- runtime/src/runtime_internal.h | 2 +- runtime/src/rwir_array.c | 353 ++++++ runtime/src/rwir_bool.c | 96 ++ runtime/src/{rwir.c => rwir_decode.c} | 0 runtime/src/rwir_func.c | 223 ++++ runtime/src/rwir_int.c | 269 ++++ .../{builtin_internal.h => rwir_internal.h} | 29 +- runtime/src/{builtin_kv.c => rwir_kv.c} | 4 +- runtime/src/rwir_map.c | 183 +++ runtime/src/rwir_ndarray.c | 83 ++ .../src/{builtin_random.c => rwir_random.c} | 4 +- .../src/{builtin_string.c => rwir_string.c} | 4 +- runtime/src/rwir_struct.c | 123 ++ runtime/src/{builtin_time.c => rwir_time.c} | 4 +- .../src/{builtin_vthread.c => rwir_vthread.c} | 4 +- runtime/src/rwir_xvalue.c | 354 ++++++ runtime/src/rwirext.c | 130 +- runtime/src/xvalue.c | 2 +- ...13\350\241\250\350\276\276\345\274\217.kv" | 2 +- .../05-runtimec\345\206\205\345\273\272.kv" | 2 +- ...344\270\216\345\220\216\347\253\257abi.kv" | 14 +- ...05\345\273\272\345\207\275\346\225\260.kv" | 2 +- 35 files changed, 2078 insertions(+), 2127 deletions(-) delete mode 100644 runtime/include/kvlang_rwirext.h create mode 100644 runtime/include/kvlang_vthread.h delete mode 100644 runtime/src/builtin.c delete mode 100644 runtime/src/builtin_collection.c rename runtime/src/{kv.c => kvspace.c} (100%) create mode 100644 runtime/src/myrwircaps.c create mode 100644 runtime/src/rwir_array.c create mode 100644 runtime/src/rwir_bool.c rename runtime/src/{rwir.c => rwir_decode.c} (100%) create mode 100644 runtime/src/rwir_func.c create mode 100644 runtime/src/rwir_int.c rename runtime/src/{builtin_internal.h => rwir_internal.h} (65%) rename runtime/src/{builtin_kv.c => rwir_kv.c} (99%) create mode 100644 runtime/src/rwir_map.c create mode 100644 runtime/src/rwir_ndarray.c rename runtime/src/{builtin_random.c => rwir_random.c} (94%) rename runtime/src/{builtin_string.c => rwir_string.c} (99%) create mode 100644 runtime/src/rwir_struct.c rename runtime/src/{builtin_time.c => rwir_time.c} (97%) rename runtime/src/{builtin_vthread.c => rwir_vthread.c} (98%) create mode 100644 runtime/src/rwir_xvalue.c diff --git a/Makefile b/Makefile index 2fa2d1ad..4300df35 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ install: install -m 755 $(BIN)/libkvlang_runtime.so /usr/lib/ install -m 755 layout/target/release/libkvlanglayout.so /usr/lib/ install -m 755 $(BIN)/kvlang $(BIN)/kvlanglayout /usr/bin/ - install -m 644 runtime/include/kvlang_runtime.h runtime/include/kvlang_rwirext.h /usr/include/kvlang/ + install -m 644 runtime/include/kvlang_vthread.h runtime/include/kvlang_runtime.h /usr/include/kvlang/ json: cd runtime-rwirext_example/go/json && CGO_LDFLAGS="-lkvspace" go build -o ../../../bin/json-rwirext ./cmd/ diff --git a/README.md b/README.md index 1eb3a078..fec7a790 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ kvspace is the addressing and memory space at the core; the language is a small - **kvspace** — one C ABI (`kvspace_*`, 24 symbols), two implementations selected by DSN: `kvspace-c` (C, `shm://`, links `blockmalloc` + `slotsboxmalloc`) and `kvspace-durable` (Rust, `redis://` / `fs://`, s3/tikv planned). - **kvlang** — `layout` (Rust, compile) and `runtime` (C, execute), both depending only on the `kvspace_*` C ABI. -- **rwirext** — extensions on top of the runtime. Embedded (Rust `term`, links `libkvlang_runtime` via `kvlang_rwirext.h`) or process-separated by handoff (Go `json`, Python `numpy`). `term` / `json` are example base extensions, not headline features. +- **rwirext** — extensions on top of the runtime. Embedded (Rust `term`, links `libkvlang_runtime` via `kvlang_runtime.h`) or process-separated by handoff (Go `json`, Python `numpy`). `term` / `json` are example base extensions, not headline features. --- diff --git a/README_CN.md b/README_CN.md index 54a7ca50..c30157e9 100644 --- a/README_CN.md +++ b/README_CN.md @@ -56,7 +56,7 @@ kvspace 是核心的寻址空间与内存空间;语言本体是小核心 runti - **kvspace** — 一套 C ABI(`kvspace_*`,24 符号),由 DSN 选择两种实现:`kvspace-c`(C,`shm://`,链接 `blockmalloc` + `slotsboxmalloc`)与 `kvspace-durable`(Rust,`redis://` / `fs://`,s3/tikv 规划中)。 - **kvlang** — `layout`(Rust,语法检查+布局)与 `runtime`(C,执行),二者都只依赖 `kvspace_*` C ABI。 -- **rwirext** — 构建在 runtime 之上的扩展。嵌入式(Rust `term`,经 `kvlang_rwirext.h` 链接 `libkvlang_runtime`)或独立进程 handoff(Go `json`、Python `numpy`)。`term` / `json` 只是基础示例扩展,不是招牌能力。 +- **rwirext** — 构建在 runtime 之上的扩展。嵌入式(Rust `term`,经 `kvlang_runtime.h` 链接 `libkvlang_runtime`)或独立进程 handoff(Go `json`、Python `numpy`)。`term` / `json` 只是基础示例扩展,不是招牌能力。 --- diff --git a/runtime-rs/src/ffi.rs b/runtime-rs/src/ffi.rs index 1a32981e..d9b2a4db 100644 --- a/runtime-rs/src/ffi.rs +++ b/runtime-rs/src/ffi.rs @@ -145,7 +145,7 @@ unsafe extern "C" { out_len: *mut u32, ) -> c_int; - // ── kvlang runtime:模式2 执行 ─────────────────────────────────── + // ── kvlang runtime:模式2 执行(kvlang_vthread.h)─────────────── pub fn kvlangRuntimeConnect(dsn: *const c_char) -> *mut c_void; /// runtime 内部 kvspace 句柄——复用它而非另开连接(durable 惰性 flush 仅同句柄内相干)。 pub fn kvlangRuntimeKvspaceHandle(rt: *mut c_void) -> *mut c_void; @@ -161,8 +161,8 @@ unsafe extern "C" { out_pc: *mut *mut c_char, ) -> c_int; - // ── kvlang runtime:rwirext 宿主 ABI(均传 kvspace 句柄)───────── - // C 头 kvlang_rwirext.h 导出 9 符号;此处声明 7:故意省略 LangtypeValid/LangtypeMatch + // ── kvlang runtime:rwirext 宿主 ABI(均传 kvspace 句柄;kvlang_runtime.h)── + // C 头 kvlang_runtime.h 导出 9 符号;此处声明 7:故意省略 LangtypeValid/LangtypeMatch // ——langtype 校验属 layout 期、匹配属 C dispatch 内部,Rust term 侧不调用(非缺陷)。 pub fn kvlangDefRwir( kvspace: *mut c_void, diff --git a/runtime/include/kvlang_runtime.h b/runtime/include/kvlang_runtime.h index 8376c3c7..a5250514 100644 --- a/runtime/include/kvlang_runtime.h +++ b/runtime/include/kvlang_runtime.h @@ -1,28 +1,51 @@ #pragma once +#include #include -typedef struct kvlangRuntime_t kvlangRuntime_t; +/* kvlang 扩展 runtime ABI:供第三方语言(Rust/Python/Go)通过 C ABI 嵌入 C + * runtime, 实现自定义 rwirext(如 term 的 print)。 + * + * KV 存取(connect/get/set/del/list/mkindex/tlv)不在此——扩展宿主自己连 kvspace + * ABI (kvspaceConnect/Get/Set/...),把拿到的 kvspace 句柄(void + * *)传进下列带句柄的函数即可。 本 ABI 只暴露 kvspace 不提供的 runtime + * 语义:rwir 解码 + resolve + display + PC 推进 + 类型判定。 */ -kvlangRuntime_t *kvlangRuntimeConnect(const char *dsn); -void kvlangRuntimeDisconnect(kvlangRuntime_t *rt); +/* 注册一条 rwir(幂等):/lib/ 路由头(body 仅计数头 [nr][nw][dynamic])+ + * 各参数类型落签名行 [0,x] 槽(def langtype)。读参类型逐条 rp[0..nr]、写参 wp[0..nw], + * 不拼签名串——避免其它 runtime 把「拼接 sig」误当注册标准。末读参尾缀 "..." → 变参。 */ +int kvlangDefRwir(void *kvspace, const char *opcode, + const char *const *rp, int32_t nr, + const char *const *wp, int32_t nw); -int kvlangRuntimeExecutePc(kvlangRuntime_t *rt, const char *pc); +/* 外部扩展 handoff:写 /lib//.todo 并阻塞 watch .done(30s + * 超时)。RETURN 模式下 term 遇非己方 ext rwir(如 json.to/numpy)时调用,把 + * 该指令交给对应扩展进程,扩展处理后写回下一 PC 并 signal .done。返回 0 成功, + * -1 失败/超时。 */ +int kvlangRwirextHandoff(void *kvspace, const char *vtid, const char *pc); -/* runtime 内部 kvspace 句柄——runtime-rs 须复用它而非另开连接(durable 惰性 - * flush 只在同句柄内相干)。返回句柄生命周期同 rt,调用方不得 close。 */ -void *kvlangRuntimeKvspaceHandle(kvlangRuntime_t *rt); +/* 当前指令的下一条 PC(malloc) */ +char *kvlangRwirextNextPc(const char *pc); -/* 模式2(runtime 主导 + term 嵌入):分配 vthread 并 bootstrap,返回 - * vid(malloc)。 term 专注这一个 vid 的 ext rwir 处理。 */ -char *kvlangRuntimeBootstrap(kvlangRuntime_t *rt, const char *funcname, - const char *const *args, int nargs); +/* 解码指令,返回 opcode + 读参名 + 写参名(\n 分隔:首行 opcode,接 nr + * 行读参名,接 nw 行写参名,malloc)。 供 numpy/tensor 扩展按路径零拷贝读 raw + * 数据。 */ +char *kvlangRwirextParams(void *kvspace, const char *pc); -/* 模式2:从 vid 的当前 pc 执行 vthread,遇 ext rwir 不再 - * handoff/watch,直接返回。 返回值:1=遇 ext rwir(*out_pc=该 - * PC,malloc,调用方 free);0=vthread done;-1=错误。 */ -int kvlangRuntimeExecuteVthread(kvlangRuntime_t *rt, const char *vid, - char **out_pc); +/* 解析读参 idx 为字符串(变量 → 帧槽值;路径 → 该路径下的值)。 */ +char *kvlangRwirextResolveRead(void *kvspace, const char *pc, int idx); -int kvlangRuntimeExecute(kvlangRuntime_t *rt, const char *funcname, - const char *const *args, int nargs, char **ret, - char *err, uint32_t err_cap); +/* 解析读参 idx 为 KV 路径(变量 → 帧槽路径;路径 → 直接返回;字面量 → "")。 + * 供 numpy/tensor 扩展按路径零拷贝读整块 ndarray raw 数据。 */ +char *kvlangRwirextResolveReadPath(void *kvspace, const char *pc, int idx); + +/* 解析写参 idx 为 KV 路径(路径 → 直接返回;变量 → 帧槽路径)。 */ +char *kvlangRwirextResolveWrite(void *kvspace, const char *pc, int idx); + +/* 签名 langtype(runtime篇-07)——供扩展做实参类型判定。 */ +/* 语法校验:type = atom("|"atom)*, atom = [dims](family|kind), + * dims="[]"|"["dim(","dim)*"]", dim=int|"?"。 */ +bool kvlangLangtypeValid(const char *expr); +/* 值判定:kind 为实际落盘 kind 串,ndim 为秩(标量 0),dims 为各维长(标量传 + * NULL)。 */ +bool kvlangLangtypeMatch(const char *expr, const char *kind, int32_t ndim, + const int32_t *dims); diff --git a/runtime/include/kvlang_rwirext.h b/runtime/include/kvlang_rwirext.h deleted file mode 100644 index a5250514..00000000 --- a/runtime/include/kvlang_rwirext.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once -#include -#include - -/* kvlang 扩展 runtime ABI:供第三方语言(Rust/Python/Go)通过 C ABI 嵌入 C - * runtime, 实现自定义 rwirext(如 term 的 print)。 - * - * KV 存取(connect/get/set/del/list/mkindex/tlv)不在此——扩展宿主自己连 kvspace - * ABI (kvspaceConnect/Get/Set/...),把拿到的 kvspace 句柄(void - * *)传进下列带句柄的函数即可。 本 ABI 只暴露 kvspace 不提供的 runtime - * 语义:rwir 解码 + resolve + display + PC 推进 + 类型判定。 */ - -/* 注册一条 rwir(幂等):/lib/ 路由头(body 仅计数头 [nr][nw][dynamic])+ - * 各参数类型落签名行 [0,x] 槽(def langtype)。读参类型逐条 rp[0..nr]、写参 wp[0..nw], - * 不拼签名串——避免其它 runtime 把「拼接 sig」误当注册标准。末读参尾缀 "..." → 变参。 */ -int kvlangDefRwir(void *kvspace, const char *opcode, - const char *const *rp, int32_t nr, - const char *const *wp, int32_t nw); - -/* 外部扩展 handoff:写 /lib//.todo 并阻塞 watch .done(30s - * 超时)。RETURN 模式下 term 遇非己方 ext rwir(如 json.to/numpy)时调用,把 - * 该指令交给对应扩展进程,扩展处理后写回下一 PC 并 signal .done。返回 0 成功, - * -1 失败/超时。 */ -int kvlangRwirextHandoff(void *kvspace, const char *vtid, const char *pc); - -/* 当前指令的下一条 PC(malloc) */ -char *kvlangRwirextNextPc(const char *pc); - -/* 解码指令,返回 opcode + 读参名 + 写参名(\n 分隔:首行 opcode,接 nr - * 行读参名,接 nw 行写参名,malloc)。 供 numpy/tensor 扩展按路径零拷贝读 raw - * 数据。 */ -char *kvlangRwirextParams(void *kvspace, const char *pc); - -/* 解析读参 idx 为字符串(变量 → 帧槽值;路径 → 该路径下的值)。 */ -char *kvlangRwirextResolveRead(void *kvspace, const char *pc, int idx); - -/* 解析读参 idx 为 KV 路径(变量 → 帧槽路径;路径 → 直接返回;字面量 → "")。 - * 供 numpy/tensor 扩展按路径零拷贝读整块 ndarray raw 数据。 */ -char *kvlangRwirextResolveReadPath(void *kvspace, const char *pc, int idx); - -/* 解析写参 idx 为 KV 路径(路径 → 直接返回;变量 → 帧槽路径)。 */ -char *kvlangRwirextResolveWrite(void *kvspace, const char *pc, int idx); - -/* 签名 langtype(runtime篇-07)——供扩展做实参类型判定。 */ -/* 语法校验:type = atom("|"atom)*, atom = [dims](family|kind), - * dims="[]"|"["dim(","dim)*"]", dim=int|"?"。 */ -bool kvlangLangtypeValid(const char *expr); -/* 值判定:kind 为实际落盘 kind 串,ndim 为秩(标量 0),dims 为各维长(标量传 - * NULL)。 */ -bool kvlangLangtypeMatch(const char *expr, const char *kind, int32_t ndim, - const int32_t *dims); diff --git a/runtime/include/kvlang_vthread.h b/runtime/include/kvlang_vthread.h new file mode 100644 index 00000000..8376c3c7 --- /dev/null +++ b/runtime/include/kvlang_vthread.h @@ -0,0 +1,28 @@ +#pragma once +#include + +typedef struct kvlangRuntime_t kvlangRuntime_t; + +kvlangRuntime_t *kvlangRuntimeConnect(const char *dsn); +void kvlangRuntimeDisconnect(kvlangRuntime_t *rt); + +int kvlangRuntimeExecutePc(kvlangRuntime_t *rt, const char *pc); + +/* runtime 内部 kvspace 句柄——runtime-rs 须复用它而非另开连接(durable 惰性 + * flush 只在同句柄内相干)。返回句柄生命周期同 rt,调用方不得 close。 */ +void *kvlangRuntimeKvspaceHandle(kvlangRuntime_t *rt); + +/* 模式2(runtime 主导 + term 嵌入):分配 vthread 并 bootstrap,返回 + * vid(malloc)。 term 专注这一个 vid 的 ext rwir 处理。 */ +char *kvlangRuntimeBootstrap(kvlangRuntime_t *rt, const char *funcname, + const char *const *args, int nargs); + +/* 模式2:从 vid 的当前 pc 执行 vthread,遇 ext rwir 不再 + * handoff/watch,直接返回。 返回值:1=遇 ext rwir(*out_pc=该 + * PC,malloc,调用方 free);0=vthread done;-1=错误。 */ +int kvlangRuntimeExecuteVthread(kvlangRuntime_t *rt, const char *vid, + char **out_pc); + +int kvlangRuntimeExecute(kvlangRuntime_t *rt, const char *funcname, + const char *const *args, int nargs, char **ret, + char *err, uint32_t err_cap); diff --git a/runtime/src/builtin.c b/runtime/src/builtin.c deleted file mode 100644 index 929eea45..00000000 --- a/runtime/src/builtin.c +++ /dev/null @@ -1,810 +0,0 @@ -#include "runtime_internal.h" -#include "builtin_internal.h" -#include -#include - -typedef int (*kvlangBuiltinFn)(kvlangFrame_t *f); - - -/* ── 类型 helper:全经 langtype id + 标量 0copy 视图,热路径零 strcmp、每值只 decode 一次 ── */ - -static const kvlangScalar_t SCALAR_NONE = { KVLANG_LT_NONE, NULL, 0 }; - -/* 两操作数结果整型 id(对齐旧 wider_int_kind:同号取宽者,异号升一档有符号)。 */ -static int wider_int_id(int a, int b) { - int aw = kvlangLtIntWidth(a), bw = kvlangLtIntWidth(b); - bool au = kvlangLtIsUint(a), bu = kvlangLtIsUint(b); - if (au == bu) { - int w = aw >= bw ? aw : bw; - int off = w == 8 ? 0 : w == 16 ? 1 : w == 32 ? 2 : 3; - return (au ? KVLANG_LT_UINT8 : KVLANG_LT_INT8) + off; - } - int w = aw > bw ? aw : bw; - return w <= 8 ? KVLANG_LT_INT16 : w == 16 ? KVLANG_LT_INT32 : KVLANG_LT_INT64; -} - -static int wider_float_id(int a, int b) { - if (a == KVLANG_LT_FLOAT64 || b == KVLANG_LT_FLOAT64) return KVLANG_LT_FLOAT64; - if (a == KVLANG_LT_FLOAT32 || b == KVLANG_LT_FLOAT32) return KVLANG_LT_FLOAT32; - return KVLANG_LT_FLOAT64; -} - -static void narrow_int(int a, int b, int64_t v, kvlangXvalue_t *out) { - int k = wider_int_id(a, b); - const char *kind = kvlangLangTypeKind(k); - switch (k) { - case KVLANG_LT_INT8: { int8_t x = (int8_t)v; kvlangXvalueNewTlv(out, kind, (uint8_t *)&x, 1, 1); return; } - case KVLANG_LT_INT16: { int16_t x = (int16_t)v; uint8_t r[2] = { x & 0xFF, (x >> 8) & 0xFF }; kvlangXvalueNewTlv(out, kind, r, 2, 1); return; } - case KVLANG_LT_INT32: { int32_t x = (int32_t)v; uint8_t r[4]; memcpy(r, &x, 4); kvlangXvalueNewTlv(out, kind, r, 4, 1); return; } - case KVLANG_LT_UINT8: { uint8_t x = (uint8_t)v; kvlangXvalueNewTlv(out, kind, &x, 1, 1); return; } - case KVLANG_LT_UINT16: { uint16_t x = (uint16_t)v; uint8_t r[2] = { x & 0xFF, (x >> 8) & 0xFF }; kvlangXvalueNewTlv(out, kind, r, 2, 1); return; } - case KVLANG_LT_UINT32: { uint32_t x = (uint32_t)v; uint8_t r[4]; memcpy(r, &x, 4); kvlangXvalueNewTlv(out, kind, r, 4, 1); return; } - case KVLANG_LT_UINT64: { uint64_t x = (uint64_t)v; uint8_t r[8]; memcpy(r, &x, 8); kvlangXvalueNewTlv(out, kind, r, 8, 1); return; } - default: kvlangXvalueNewInt64(out, v); return; /* INT64 */ - } -} - -static void narrow_float(int a, int b, double v, kvlangXvalue_t *out) { - if (wider_float_id(a, b) == KVLANG_LT_FLOAT32) { - float f = (float)v; uint8_t r[4]; memcpy(r, &f, 4); - kvlangXvalueNewTlv(out, KVSPACE_KIND_FLOAT32, r, 4, 1); - } else kvlangXvalueNewFloat64(out, v); -} - -static int cmp_int(kvlangScalar_t a, kvlangScalar_t b) { - bool au = kvlangLtIsUint(a.id), bu = kvlangLtIsUint(b.id); - if (!au && !bu) { int64_t ai = kvlangScalarI64(a), bi = kvlangScalarI64(b); return ai < bi ? -1 : ai > bi ? 1 : 0; } - if (au && bu) { uint64_t x = kvlangScalarU64(a), y = kvlangScalarU64(b); return x < y ? -1 : x > y ? 1 : 0; } - if (au && !bu) { int64_t bi = kvlangScalarI64(b); if (bi < 0) return 1; uint64_t x = kvlangScalarU64(a); return x < (uint64_t)bi ? -1 : x > (uint64_t)bi ? 1 : 0; } - int64_t ai = kvlangScalarI64(a); if (ai < 0) return -1; uint64_t y = kvlangScalarU64(b); - return (uint64_t)ai < y ? -1 : (uint64_t)ai > y ? 1 : 0; -} - -/* ── resolve ───────────────────────────────────────────────────────── */ -/* #116 后 if/while 不再建 scope 帧,当前帧 [d] 即 rwfunc 帧,frame_root 直接可用。 */ - -void kvlangBuiltinResolveReadValue(kvlangKv_t *kv, const char *frame_root, const char *name, - const kvlangXvalue_t *val, kvlangXvalue_t *out) { - kvlangXvalueZero(out); - if (val && !kvlangXvalueNone(val) && !kvlangXvalueKindIs(val, KVSPACE_KIND_RWIR) && !kvlangXvalueKindIs(val, KVSPACE_KIND_RWFUNC)) { - out->data = val->data; /* 借指令内冻结字面量(生命周期同 decode 缓存,永不 flush/free) */ - out->len = val->len; - out->borrowed = 1; - return; - } - if (!name || !name[0]) return; - if (name[0] == '/') { kvlangKvGetOne(kv, name, out); return; } - if (name[0] == '*') { - /* 显式解引用:*[0,±k] → 读 frame_root/[0,±k](ref=1 Ptr)→ 解引用到实参值。 - * 同 ResolveWriteSlot:帧槽必有 Ptr,读不到即传参链路已坏 → panic, - * 绝不静默留 None(那会让形参读成空值,把真因藏到几层之外)。 */ - char *stk = kvlangKeytreeStack(frame_root); - kvlangXvalue_t pv; kvlangXvalueZero(&pv); - kvlangKvGetMember(kv, stk, name + 1, &pv); - if (!kvlangXvalueIsPtr(&pv)) { - fprintf(stderr, "panic: %s%s is not a Ptr — frame slot missing, param passing broken\n", stk, name + 1); - abort(); - } - char *target = kvlangXvaluePtrTarget(&pv); - kvlangKvGetOne(kv, target, out); - free(target); - kvlangXvalueFree(&pv); free(stk); - return; - } - char *stk = kvlangKeytreeStack(frame_root); - kvlangXvalue_t pv; kvlangXvalueZero(&pv); - kvlangKvGetMember(kv, stk, name, &pv); - if (kvlangXvalueIsPtr(&pv)) { - /* 数据 Ptr(&x):地址值本体,读值不解引用。成员访问另走 kvspace·get 的 member_path。 */ - *out = pv; pv.data = NULL; pv.len = 0; - } else if (!kvlangXvalueNone(&pv)) { - *out = pv; pv.data = NULL; pv.len = 0; - } - kvlangXvalueFree(&pv); free(stk); -} - -/* 读参 → 其最终存储键(malloc):字面量(指令内冻结的具体值,无后端槽)返 NULL; - * 变量则复用 ResolveWriteSlot——读侧最终槽键与写侧同一路径(普通成员=stk+name, - * ptr 追链到最终目标),供 xv 系列对 key 直发 GetHead/GetPart/SetPart 做分片读写。 */ -char *kvlangBuiltinResolveReadKey(kvlangKv_t *kv, const char *frame_root, const char *name, - const kvlangXvalue_t *val) { - if (val && !kvlangXvalueNone(val) && !kvlangXvalueKindIs(val, KVSPACE_KIND_RWIR) && !kvlangXvalueKindIs(val, KVSPACE_KIND_RWFUNC)) - return NULL; - if (!name || !name[0]) return NULL; - return kvlangBuiltinResolveWriteSlot(kv, frame_root, name); -} - -char *kvlangBuiltinResolveWriteSlot(kvlangKv_t *kv, const char *frame_root, const char *name) { - if (name[0] == '/') return strdup(name); - char *stk = kvlangKeytreeStack(frame_root); - if (name[0] == '*') { - /* 显式解引用:*[0,±k] → 读 frame_root/[0,±k](ref=1 Ptr)→ target=写槽路径。 - * `*[0,±k]` 是 layout 编译期生成的形参引用,帧槽必有调用点写入的 Ptr;读不到 - * 即传参链路已坏(不变量违反,非用户错误)→ panic,绝不回退成字面路径—— - * 回退会把「写形参」静默变成「写一个叫 *[0,±k] 的键」,掩盖真因。 */ - kvlangXvalue_t pv; kvlangXvalueZero(&pv); - kvlangKvGetMember(kv, stk, name + 1, &pv); - if (!kvlangXvalueIsPtr(&pv)) { - fprintf(stderr, "panic: %s%s is not a Ptr — frame slot missing, param passing broken\n", stk, name + 1); - abort(); - } - char *target = kvlangXvaluePtrTarget(&pv); - kvlangXvalueFree(&pv); free(stk); - return target; - } - kvlangStrbuf_t o; kvlangStrbufInit(&o); - kvlangStrbufPuts(&o, stk); kvlangStrbufPuts(&o, name); - free(stk); - return kvlangStrbufDetach(&o); -} - -/* ── coerce / kvlangDisplay ─────────────────────────────────────────────── */ - -static bool try_parse_int(const char *s, int64_t *out) { - if (!s || !s[0]) return false; - char *end; long long v = strtoll(s, &end, 10); - if (end == s || *end != 0) return false; - *out = v; return true; -} - -bool kvlangBuiltinTryParseNumber(const char *s, kvlangXvalue_t *out) { - kvlangXvalueZero(out); - if (!s || !s[0]) return false; - char c0 = s[0]; - bool num = (c0 >= '0' && c0 <= '9') || (c0 == '-' && s[1] >= '0' && s[1] <= '9'); - if (!num) return false; - int64_t iv; - if (try_parse_int(s, &iv)) { kvlangXvalueNewInt64(out, iv); return true; } - if (c0 != '-' && !strpbrk(s, ".eE")) { - char *end; unsigned long long uv = strtoull(s, &end, 10); - if (end != s && *end == 0) { - uint8_t r[8]; memcpy(r, &uv, 8); - kvlangXvalueNewTlv(out, KVSPACE_KIND_UINT64, r, 8, 1); return true; - } - } - char *end; double f = strtod(s, &end); - if (end != s && *end == 0) { kvlangXvalueNewFloat64(out, f); return true; } - return false; -} - -void kvlangBuiltinXvalueAt(const kvlangXvalue_t *v, int i, kvlangXvalue_t *out) { - kvlangXvalueZero(out); - int n = kvlangXvalueArrayLen(v); - if (i < 0 || i >= n) return; - const char *k = kvlangXvalueKind(v); - int sz = kvlangXvalueElemSize(k); - if (sz <= 0) return; - kvspaceHead_t h; kvspaceDecodeHead(v->data, v->len, &h); - const uint8_t *body = v->data + h.body_offset; - kvlangXvalueNewTlv(out, k, body + i * sz, (uint32_t)sz, 1); -} - -void kvlangDisplay(const kvlangXvalue_t *v, char **out); - -static void format_array(const kvlangXvalue_t *v, char **out) { - int n = kvlangXvalueArrayLen(v); - kvlangStrbuf_t b; kvlangStrbufInit(&b); - kvlangStrbufPutc(&b, '['); - for (int i = 0; i < n; i++) { - if (i) kvlangStrbufPuts(&b, ", "); - kvlangXvalue_t e; kvlangBuiltinXvalueAt(v, i, &e); - char *s; kvlangDisplay(&e, &s); - kvlangStrbufPuts(&b, s); free(s); kvlangXvalueFree(&e); - } - kvlangStrbufPutc(&b, ']'); - *out = kvlangStrbufDetach(&b); -} - -void kvlangDisplay(const kvlangXvalue_t *v, char **out) { - if (kvlangXvalueIsCharKind(kvlangXvalueKind(v))) { *out = kvlangXvalueValueString(v); return; } - if (kvlangXvalueArrayLen(v) > 1) { format_array(v, out); return; } - *out = kvlangXvalueValueString(v); -} - -/* ── frame helper ─────────────────────────────────────────────────── */ - -int kvlangBuiltinReadInputs(kvlangFrame_t *f, kvlangXvalue_t *out, int cap) { - char *fr = kvlangKeytreeFrameRoot(f->pc); - int n = 0; - for (int i = 0; i < f->inst->nr && n < cap; i++) { - kvlangBuiltinResolveReadValue(f->kv, fr, f->inst->reads[i].name, &f->inst->reads[i].val, &out[n]); - n++; - } - free(fr); - return n; -} - -void kvlangBuiltinFreeInputs(kvlangXvalue_t *in, int n) { for (int i = 0; i < n; i++) kvlangXvalueFree(&in[i]); } - -void kvlangBuiltinNextPc(kvlangFrame_t *f) { - kvlangStrbuf_t npc; kvlangStrbufInit(&npc); - kvlangRwirNextPc(f->pc, &npc); - kvlangVthreadSet(f->kv, f->vtid, npc.p, "running"); - kvlangStrbufFree(&npc); -} - -int kvlangBuiltinWriteResult(kvlangFrame_t *f, const kvlangXvalue_t *result) { - if (f->inst->nw > 0) { - char *fr = kvlangKeytreeFrameRoot(f->pc); - char *key = kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[0].name); - free(fr); - kvlangKvPair_t pair = { key, *result }; - char err[256]; - kvlangKvSet(f->kv, &pair, 1, err, sizeof err); - free(key); - } - kvlangBuiltinNextPc(f); - return 0; -} - -int kvlangBuiltinSetErr(kvlangFrame_t *f, const char *fmt, ...) { - char msg[512]; - va_list ap; va_start(ap, fmt); - vsnprintf(msg, sizeof msg, fmt, ap); - va_end(ap); - kvlangVthreadSetError(f->kv, f->vtid, f->pc, msg); - return -1; -} - -/* ── 数值算子 ─────────────────────────────────────────────────────── */ - -static int kvlangBuiltinAdd(kvlangFrame_t *f) { - kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); - kvlangScalar_t a = kvlangXvalueScalar(&in[0]), b = n >= 2 ? kvlangXvalueScalar(&in[1]) : SCALAR_NONE; - int rc; - if (n == 2 && kvlangLtIsChar(a.id) && kvlangLtIsChar(b.id)) { - kvlangXvalue_t r; - if (kvlangBuiltinCharConcat(&in[0], &in[1], &r)) { - rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); - } else rc = kvlangBuiltinSetErr(f, "TypeError: cannot concat %s with %s; convert encoding explicitly (char/utf8|char/utf32|char/ascii)", kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[1])); - } else if (n >= 2 && kvlangLtIsNum(a.id) && kvlangLtIsNum(b.id)) { - kvlangXvalue_t r; - if (kvlangLtIsInt(a.id) && kvlangLtIsInt(b.id)) narrow_int(a.id, b.id, kvlangScalarI64(a) + kvlangScalarI64(b), &r); - else narrow_float(a.id, b.id, kvlangScalarF64(a) + kvlangScalarF64(b), &r); - rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); - } else rc = kvlangBuiltinSetErr(f, "TypeError: expected numeric, got %s", n ? kvlangXvalueKind(&in[0]) : "none"); - kvlangBuiltinFreeInputs(in, n); - return rc; -} - -static int kvlangBuiltinSub(kvlangFrame_t *f) { - kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); - kvlangScalar_t a = kvlangXvalueScalar(&in[0]), b = n >= 2 ? kvlangXvalueScalar(&in[1]) : SCALAR_NONE; - int rc; - if (n == 1) { - kvlangXvalue_t r; kvlangXvalueNewInt64(&r, -kvlangScalarI64(a)); - rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); - } else if (n >= 2 && kvlangLtIsInt(a.id) && kvlangLtIsInt(b.id)) { - kvlangXvalue_t r; narrow_int(a.id, b.id, kvlangScalarI64(a) - kvlangScalarI64(b), &r); - rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); - } else if (n >= 2 && kvlangLtIsNum(a.id) && kvlangLtIsNum(b.id)) { - kvlangXvalue_t r; narrow_float(a.id, b.id, kvlangScalarF64(a) - kvlangScalarF64(b), &r); - rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); - } else rc = kvlangBuiltinSetErr(f, "TypeError: expected numeric, got %s", n ? kvlangXvalueKind(&in[0]) : "none"); - kvlangBuiltinFreeInputs(in, n); - return rc; -} - -static int kvlangBuiltinMul(kvlangFrame_t *f) { - kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); - kvlangScalar_t a = kvlangXvalueScalar(&in[0]), b = n >= 2 ? kvlangXvalueScalar(&in[1]) : SCALAR_NONE; - int rc; - if (n >= 2 && kvlangLtIsInt(a.id) && kvlangLtIsInt(b.id)) { - kvlangXvalue_t r; narrow_int(a.id, b.id, kvlangScalarI64(a) * kvlangScalarI64(b), &r); - rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); - } else if (n >= 2 && kvlangLtIsNum(a.id) && kvlangLtIsNum(b.id)) { - kvlangXvalue_t r; narrow_float(a.id, b.id, kvlangScalarF64(a) * kvlangScalarF64(b), &r); - rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); - } else rc = kvlangBuiltinSetErr(f, "TypeError: expected numeric, got %s", n ? kvlangXvalueKind(&in[0]) : "none"); - kvlangBuiltinFreeInputs(in, n); - return rc; -} - -static int kvlangBuiltinDiv(kvlangFrame_t *f) { - kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); - kvlangScalar_t a = kvlangXvalueScalar(&in[0]), b = n >= 2 ? kvlangXvalueScalar(&in[1]) : SCALAR_NONE; - int rc; - if (n < 2) { rc = kvlangBuiltinSetErr(f, "TypeError: binary op requires 2 inputs, got %d", n); kvlangBuiltinFreeInputs(in, n); return rc; } - if (kvlangScalarF64(b) == 0) { rc = kvlangBuiltinSetErr(f, "ZeroDivisionError: division by zero"); kvlangBuiltinFreeInputs(in, n); return rc; } - if (kvlangLtIsInt(a.id) && kvlangLtIsInt(b.id)) { - kvlangXvalue_t r; narrow_int(a.id, b.id, kvlangScalarI64(a) / kvlangScalarI64(b), &r); - rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); - } else { - kvlangXvalue_t r; narrow_float(a.id, b.id, kvlangScalarF64(a) / kvlangScalarF64(b), &r); - rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); - } - kvlangBuiltinFreeInputs(in, n); - return rc; -} - -static int kvlangBuiltinMod(kvlangFrame_t *f) { - kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); - kvlangScalar_t a = kvlangXvalueScalar(&in[0]), b = n >= 2 ? kvlangXvalueScalar(&in[1]) : SCALAR_NONE; - int rc; - if (n < 2 || !kvlangLtIsInt(a.id) || !kvlangLtIsInt(b.id)) { - rc = kvlangBuiltinSetErr(f, "TypeError: expected integer, got %s", n ? kvlangXvalueKind(&in[0]) : "none"); - kvlangBuiltinFreeInputs(in, n); return rc; - } - int64_t bv = kvlangScalarI64(b); - if (bv == 0) { rc = kvlangBuiltinSetErr(f, "ZeroDivisionError: modulo by zero"); kvlangBuiltinFreeInputs(in, n); return rc; } - kvlangXvalue_t r; narrow_int(a.id, b.id, kvlangScalarI64(a) % bv, &r); - rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); - kvlangBuiltinFreeInputs(in, n); - return rc; -} - -typedef enum { CMP_EQ, CMP_NEQ, CMP_LT, CMP_GT, CMP_LE, CMP_GE } cmp_op; - -static int kvlangBuiltinCmp(kvlangFrame_t *f, cmp_op op) { - kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); - if (n < 2) { kvlangBuiltinSetErr(f, "TypeError: binary op requires 2 inputs, got %d", n); kvlangBuiltinFreeInputs(in, n); return -1; } - bool allow_null = (op == CMP_EQ || op == CMP_NEQ); - if (kvlangXvalueNone(&in[0]) || kvlangXvalueNone(&in[1])) { - if (!allow_null) { kvlangBuiltinSetErr(f, "TypeError: None in comparison"); kvlangBuiltinFreeInputs(in, n); return -1; } - bool eq = kvlangXvalueNone(&in[0]) == kvlangXvalueNone(&in[1]); - bool r = (op == CMP_EQ) ? eq : (op == CMP_NEQ) ? !eq : false; - kvlangXvalue_t rv; kvlangXvalueNewBool(&rv, r); - int rc = kvlangBuiltinWriteResult(f, &rv); kvlangXvalueFree(&rv); kvlangBuiltinFreeInputs(in, n); return rc; - } - bool r; - kvlangScalar_t a = kvlangXvalueScalar(&in[0]), b = kvlangXvalueScalar(&in[1]); - if (kvlangLtIsInt(a.id) && kvlangLtIsInt(b.id)) { - int c = cmp_int(a, b); - r = op == CMP_EQ ? c == 0 : op == CMP_NEQ ? c != 0 : op == CMP_LT ? c < 0 : op == CMP_GT ? c > 0 : op == CMP_LE ? c <= 0 : c >= 0; - } else if (kvlangLtIsNum(a.id) && kvlangLtIsNum(b.id)) { - double av = kvlangScalarF64(a), bv = kvlangScalarF64(b); - r = op == CMP_EQ ? av == bv : op == CMP_NEQ ? av != bv : op == CMP_LT ? av < bv : op == CMP_GT ? av > bv : op == CMP_LE ? av <= bv : av >= bv; - } else if (kvlangLtIsChar(a.id) && kvlangLtIsChar(b.id)) { - char *as = kvlangXvalueValueString(&in[0]), *bs = kvlangXvalueValueString(&in[1]); - int c = strcmp(as, bs); - r = op == CMP_EQ ? c == 0 : op == CMP_NEQ ? c != 0 : op == CMP_LT ? c < 0 : op == CMP_GT ? c > 0 : op == CMP_LE ? c <= 0 : c >= 0; - free(as); free(bs); - } else if (a.id == KVLANG_LT_BOOL && b.id == KVLANG_LT_BOOL) { - bool av = kvlangScalarI64(a) != 0, bv = kvlangScalarI64(b) != 0; - r = op == CMP_EQ ? av == bv : op == CMP_NEQ ? av != bv : op == CMP_LT ? av < bv : op == CMP_GT ? av > bv : op == CMP_LE ? av <= bv : av >= bv; - } else if (kvlangXvalueIsPtr(&in[0]) || kvlangXvalueIsPtr(&in[1])) { - // 指针比较恒判身份(target 串),且只允许 Ptr 对 Ptr——空指针即 None,已在上方 - // None 分支处理;不设 char 哨兵(`p == ""` 是非法比较,正是被砍掉的歧义分支)。 - if (op != CMP_EQ && op != CMP_NEQ) { - kvlangBuiltinSetErr(f, "TypeError: cannot order ptr with %s", kvlangXvalueKind(&in[0])); kvlangBuiltinFreeInputs(in, n); return -1; - } - if (!kvlangXvalueIsPtr(&in[0]) || !kvlangXvalueIsPtr(&in[1])) { - kvlangBuiltinSetErr(f, "TypeError: cannot compare %s with ptr; use None for a null pointer", - kvlangXvalueIsPtr(&in[0]) ? kvlangXvalueKind(&in[1]) : kvlangXvalueKind(&in[0])); - kvlangBuiltinFreeInputs(in, n); return -1; - } - char *as = kvlangXvaluePtrTarget(&in[0]); - char *bs = kvlangXvaluePtrTarget(&in[1]); - int c = strcmp(as, bs); - r = op == CMP_EQ ? c == 0 : c != 0; - free(as); free(bs); - } else { - kvlangBuiltinSetErr(f, "TypeError: cannot compare %s with %s", kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[1])); kvlangBuiltinFreeInputs(in, n); return -1; - } - kvlangXvalue_t rv; kvlangXvalueNewBool(&rv, r); - int rc = kvlangBuiltinWriteResult(f, &rv); kvlangXvalueFree(&rv); kvlangBuiltinFreeInputs(in, n); - return rc; -} - -static int kvlangBuiltinEq(kvlangFrame_t *f) { return kvlangBuiltinCmp(f, CMP_EQ); } -static int kvlangBuiltinNeq(kvlangFrame_t *f) { return kvlangBuiltinCmp(f, CMP_NEQ); } -static int kvlangBuiltinLt(kvlangFrame_t *f) { return kvlangBuiltinCmp(f, CMP_LT); } -static int kvlangBuiltinGt(kvlangFrame_t *f) { return kvlangBuiltinCmp(f, CMP_GT); } -static int kvlangBuiltinLe(kvlangFrame_t *f) { return kvlangBuiltinCmp(f, CMP_LE); } -static int kvlangBuiltinGe(kvlangFrame_t *f) { return kvlangBuiltinCmp(f, CMP_GE); } - -static bool require_bool(kvlangFrame_t *f, const char *op, kvlangXvalue_t *in, int n, int want) { - if (n < want) return false; - for (int i = 0; i < want; i++) { - if (!kvlangXvalueKindIs(&in[i], KVSPACE_KIND_BOOL)) { - kvlangBuiltinSetErr(f, "TypeError: %s requires bool, got %s", op, kvlangXvalueKind(&in[i])); - return false; - } - } - return true; -} -static int kvlangBuiltinAnd(kvlangFrame_t *f) { - kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); - if (!require_bool(f, "&&", in, n, 2)) { kvlangBuiltinFreeInputs(in, n); return -1; } - kvlangXvalue_t r; kvlangXvalueNewBool(&r, kvlangScalarI64(kvlangXvalueScalar(&in[0])) != 0 && kvlangScalarI64(kvlangXvalueScalar(&in[1])) != 0); - int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); - return rc; -} -static int kvlangBuiltinOr(kvlangFrame_t *f) { - kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); - if (!require_bool(f, "||", in, n, 2)) { kvlangBuiltinFreeInputs(in, n); return -1; } - kvlangXvalue_t r; kvlangXvalueNewBool(&r, kvlangScalarI64(kvlangXvalueScalar(&in[0])) != 0 || kvlangScalarI64(kvlangXvalueScalar(&in[1])) != 0); - int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); - return rc; -} -static int kvlangBuiltinNot(kvlangFrame_t *f) { - kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); - if (!require_bool(f, "!", in, n, 1)) { kvlangBuiltinFreeInputs(in, n); return -1; } - kvlangXvalue_t r; kvlangXvalueNewBool(&r, kvlangScalarI64(kvlangXvalueScalar(&in[0])) == 0); - int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); - return rc; -} - -static int kvlangBuiltinBit(kvlangFrame_t *f, int op) { - kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); - kvlangScalar_t sa = kvlangXvalueScalar(&in[0]), sb = n >= 2 ? kvlangXvalueScalar(&in[1]) : SCALAR_NONE; - if (n < 2 || !kvlangLtIsInt(sa.id) || !kvlangLtIsInt(sb.id)) { - kvlangBuiltinSetErr(f, "TypeError: expected integer, got %s", n ? kvlangXvalueKind(&in[0]) : "none"); - kvlangBuiltinFreeInputs(in, n); return -1; - } - int64_t a = kvlangScalarI64(sa), b = kvlangScalarI64(sb); - int64_t v = op == 0 ? a & b : op == 1 ? a | b : op == 2 ? a ^ b : op == 3 ? (a << (uint64_t)b) : (a >> (uint64_t)b); - kvlangXvalue_t r; narrow_int(sa.id, sb.id, v, &r); - int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); - return rc; -} -static int kvlangBuiltinBitand(kvlangFrame_t *f) { return kvlangBuiltinBit(f, 0); } -static int kvlangBuiltinBitor(kvlangFrame_t *f) { return kvlangBuiltinBit(f, 1); } -static int kvlangBuiltinBitxor(kvlangFrame_t *f) { return kvlangBuiltinBit(f, 2); } -static int kvlangBuiltinShl(kvlangFrame_t *f) { return kvlangBuiltinBit(f, 3); } -static int kvlangBuiltinShr(kvlangFrame_t *f) { return kvlangBuiltinBit(f, 4); } - -/* math */ -static int kvlangBuiltinMathUnary(kvlangFrame_t *f, int op) { - kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); - kvlangScalar_t sa = kvlangXvalueScalar(&in[0]); - if (n < 1 || !kvlangLtIsNum(sa.id)) { kvlangBuiltinSetErr(f, "TypeError: expected numeric, got %s", n ? kvlangXvalueKind(&in[0]) : "none"); kvlangBuiltinFreeInputs(in, n); return -1; } - kvlangXvalue_t r; - double x = kvlangScalarF64(sa); - switch (op) { - case 0: kvlangXvalueNewFloat64(&r, sqrt(x)); break; - case 1: kvlangXvalueNewFloat64(&r, exp(x)); break; - case 2: kvlangXvalueNewFloat64(&r, log(x)); break; - case 3: /* neg */ if (kvlangLtIsFloat(sa.id)) { narrow_float(sa.id, sa.id, -x, &r); } else { narrow_int(sa.id, sa.id, -kvlangScalarI64(sa), &r); } break; - case 4: /* abs */ if (kvlangLtIsFloat(sa.id)) { narrow_float(sa.id, sa.id, fabs(x), &r); } else { int64_t iv = kvlangScalarI64(sa); narrow_int(sa.id, sa.id, iv < 0 ? -iv : iv, &r); } break; - case 5: kvlangXvalueNewInt64(&r, x < 0 ? -1 : x > 0 ? 1 : 0); break; - } - int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); - return rc; -} -static int kvlangBuiltinSqrt(kvlangFrame_t *f) { return kvlangBuiltinMathUnary(f, 0); } -static int kvlangBuiltinExp(kvlangFrame_t *f) { return kvlangBuiltinMathUnary(f, 1); } -static int kvlangBuiltinLog(kvlangFrame_t *f) { return kvlangBuiltinMathUnary(f, 2); } -static int kvlangBuiltinNeg(kvlangFrame_t *f) { return kvlangBuiltinMathUnary(f, 3); } -static int kvlangBuiltinAbs(kvlangFrame_t *f) { return kvlangBuiltinMathUnary(f, 4); } -static int kvlangBuiltinSign(kvlangFrame_t *f) { return kvlangBuiltinMathUnary(f, 5); } - -static int kvlangBuiltinPow(kvlangFrame_t *f) { - kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); - kvlangScalar_t sa = kvlangXvalueScalar(&in[0]), sb = n >= 2 ? kvlangXvalueScalar(&in[1]) : SCALAR_NONE; - if (n < 2 || !kvlangLtIsNum(sa.id) || !kvlangLtIsNum(sb.id)) { kvlangBuiltinSetErr(f, "TypeError: expected numeric"); kvlangBuiltinFreeInputs(in, n); return -1; } - kvlangXvalue_t r; kvlangXvalueNewFloat64(&r, pow(kvlangScalarF64(sa), kvlangScalarF64(sb))); - int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); - return rc; -} - -static int kvlangBuiltinMaxmin(kvlangFrame_t *f, bool is_max) { - kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); - if (n < 2) { kvlangBuiltinSetErr(f, "TypeError: binary op requires 2 inputs, got %d", n); kvlangBuiltinFreeInputs(in, n); return -1; } - kvlangXvalue_t r; - kvlangScalar_t sa = kvlangXvalueScalar(&in[0]), sb = kvlangXvalueScalar(&in[1]); - if (kvlangLtIsInt(sa.id) && kvlangLtIsInt(sb.id)) { - int c = cmp_int(sa, sb); - bool take_a = (is_max && c >= 0) || (!is_max && c <= 0); - narrow_int(sa.id, sb.id, take_a ? kvlangScalarI64(sa) : kvlangScalarI64(sb), &r); - } else if (kvlangLtIsNum(sa.id) && kvlangLtIsNum(sb.id)) { - double a = kvlangScalarF64(sa), b = kvlangScalarF64(sb); - bool take_a = (is_max && a >= b) || (!is_max && a <= b); - narrow_float(sa.id, sb.id, take_a ? a : b, &r); - } else { kvlangBuiltinSetErr(f, "TypeError: max/min requires numeric, got %s and %s", kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[1])); kvlangBuiltinFreeInputs(in, n); return -1; } - int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); - return rc; -} -static int kvlangBuiltinMax(kvlangFrame_t *f) { return kvlangBuiltinMaxmin(f, true); } -static int kvlangBuiltinMin(kvlangFrame_t *f) { return kvlangBuiltinMaxmin(f, false); } - -/* cast */ -static int kvlangBuiltinCastNum(kvlangFrame_t *f, const char *kind) { - kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); - if (n < 1 || kvlangXvalueNone(&in[0])) { kvlangBuiltinSetErr(f, "TypeError: cannot cast None"); kvlangBuiltinFreeInputs(in, n); return -1; } - kvlangXvalue_t r; - kvlangScalar_t sa = kvlangXvalueScalar(&in[0]); - int tid = kvlangLangTypeId(kind, strlen(kind)); - if (tid == KVLANG_LT_BOOL) { - if (!kvlangXvalueKindIs(&in[0], KVSPACE_KIND_BOOL)) { kvlangBuiltinSetErr(f, "TypeError: cannot cast %s to bool — use != 0", kvlangXvalueKind(&in[0])); kvlangBuiltinFreeInputs(in, n); return -1; } - kvlangXvalueNewBool(&r, kvlangScalarI64(sa) != 0); - } - else if (tid == KVLANG_LT_FLOAT32) { float fv = (float)kvlangScalarF64(sa); uint8_t b[4]; memcpy(b, &fv, 4); kvlangXvalueNewTlv(&r, KVSPACE_KIND_FLOAT32, b, 4, 1); } - else if (tid == KVLANG_LT_FLOAT64) kvlangXvalueNewFloat64(&r, kvlangScalarF64(sa)); - else { int64_t v = kvlangScalarI64(sa); narrow_int(tid, tid, v, &r); } - int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); - return rc; -} -static int kvlangBuiltinCastBool(kvlangFrame_t *f) { return kvlangBuiltinCastNum(f, KVSPACE_KIND_BOOL); } -static int kvlangBuiltinCastInt8(kvlangFrame_t *f) { return kvlangBuiltinCastNum(f, KVSPACE_KIND_INT8); } -static int kvlangBuiltinCastInt16(kvlangFrame_t *f) { return kvlangBuiltinCastNum(f, KVSPACE_KIND_INT16); } -static int kvlangBuiltinCastInt32(kvlangFrame_t *f) { return kvlangBuiltinCastNum(f, KVSPACE_KIND_INT32); } -static int kvlangBuiltinCastInt64(kvlangFrame_t *f) { return kvlangBuiltinCastNum(f, KVSPACE_KIND_INT64); } -static int kvlangBuiltinCastUint8(kvlangFrame_t *f) { return kvlangBuiltinCastNum(f, KVSPACE_KIND_UINT8); } -static int kvlangBuiltinCastUint16(kvlangFrame_t *f) { return kvlangBuiltinCastNum(f, KVSPACE_KIND_UINT16); } -static int kvlangBuiltinCastUint32(kvlangFrame_t *f) { return kvlangBuiltinCastNum(f, KVSPACE_KIND_UINT32); } -static int kvlangBuiltinCastUint64(kvlangFrame_t *f) { return kvlangBuiltinCastNum(f, KVSPACE_KIND_UINT64); } -static int kvlangBuiltinCastF32(kvlangFrame_t *f) { return kvlangBuiltinCastNum(f, KVSPACE_KIND_FLOAT32); } -static int kvlangBuiltinCastF64(kvlangFrame_t *f) { return kvlangBuiltinCastNum(f, KVSPACE_KIND_FLOAT64); } - -static int kvlangBuiltinCastChar(kvlangFrame_t *f, const char *kind) { - kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); - if (n < 1 || kvlangXvalueNone(&in[0])) { kvlangBuiltinSetErr(f, "TypeError: char conversion requires a value"); kvlangBuiltinFreeInputs(in, n); return -1; } - char *s = kvlangXvalueValueString(&in[0]); - kvlangXvalue_t r; - if (strcmp(kind, KVSPACE_KIND_CHAR) == 0) kvlangXvalueNewCharUtf32(&r, s); - else kvlangXvalueNewCharKind(&r, kind, s); - int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); free(s); kvlangBuiltinFreeInputs(in, n); - return rc; -} -static int kvlangBuiltinCastChar32(kvlangFrame_t *f) { return kvlangBuiltinCastChar(f, KVSPACE_KIND_CHAR); } -static int kvlangBuiltinCastChar8(kvlangFrame_t *f) { return kvlangBuiltinCastChar(f, KVSPACE_KIND_CHAR_UTF8); } -static int kvlangBuiltinCastCharAscii(kvlangFrame_t *f) { return kvlangBuiltinCastChar(f, KVSPACE_KIND_CHAR_ASCII); } - -/* ── 注册表 ───────────────────────────────────────────────────────── */ - -/* 精度前缀(int64·add / float32·add …)保留:CapIndex 两级查表——先按完整 opcode 命中特化, - * 未命中且前缀是 C native 数字 kind 时才剥前缀归到裸 op(如 add),kvlangBuiltin* 按操作数 kind 归约。 */ -static int kvlangCtlCopy(kvlangFrame_t *f) { return kvlangBuiltinExecuteCopy(f->kv, f->vtid, f->pc, f->inst); } - -static const struct { const char *op; kvlangBuiltinFn fn; } myrwircaps[] = { - /* control / copy:与 native 算子同表,op_id 单跳派发 */ - {OP_CALL, kvlangCtlCall}, {OP_RETURN, kvlangCtlReturn}, {OP_GOTO, kvlangCtlGoto}, - {OP_BR, kvlangCtlBr}, {OP_COPY, kvlangCtlCopy}, - {"add", kvlangBuiltinAdd}, {"+", kvlangBuiltinAdd}, - {"sub", kvlangBuiltinSub}, {"-", kvlangBuiltinSub}, - {"mul", kvlangBuiltinMul}, {"×", kvlangBuiltinMul}, - {"div", kvlangBuiltinDiv}, {"÷", kvlangBuiltinDiv}, - {"mod", kvlangBuiltinMod}, {"%", kvlangBuiltinMod}, - {"eq", kvlangBuiltinEq}, {"==", kvlangBuiltinEq}, - {"neq", kvlangBuiltinNeq}, {"!=", kvlangBuiltinNeq}, {"≠", kvlangBuiltinNeq}, - {"lt", kvlangBuiltinLt}, {"<", kvlangBuiltinLt}, - {"gt", kvlangBuiltinGt}, {">", kvlangBuiltinGt}, - {"le", kvlangBuiltinLe}, {"<=", kvlangBuiltinLe}, {"≤", kvlangBuiltinLe}, - {"ge", kvlangBuiltinGe}, {">=", kvlangBuiltinGe}, {"≥", kvlangBuiltinGe}, - {"and", kvlangBuiltinAnd}, {"&&", kvlangBuiltinAnd}, - {"or", kvlangBuiltinOr}, {"||", kvlangBuiltinOr}, - {"not", kvlangBuiltinNot}, {"!", kvlangBuiltinNot}, - {"bitand", kvlangBuiltinBitand}, {"&", kvlangBuiltinBitand}, - {"bitor", kvlangBuiltinBitor}, {"|", kvlangBuiltinBitor}, - {"bitxor", kvlangBuiltinBitxor}, {"^", kvlangBuiltinBitxor}, - {"shl", kvlangBuiltinShl}, {"<<", kvlangBuiltinShl}, - {"shr", kvlangBuiltinShr}, {">>", kvlangBuiltinShr}, - {"pow", kvlangBuiltinPow}, - {"sqrt", kvlangBuiltinSqrt}, {"√", kvlangBuiltinSqrt}, - {"exp", kvlangBuiltinExp}, - {"log", kvlangBuiltinLog}, - {"neg", kvlangBuiltinNeg}, - {"abs", kvlangBuiltinAbs}, - {"sign", kvlangBuiltinSign}, - {"max", kvlangBuiltinMax}, {"min", kvlangBuiltinMin}, - /* cast */ - {"bool", kvlangBuiltinCastBool}, {"int8", kvlangBuiltinCastInt8}, {"int16", kvlangBuiltinCastInt16}, - {"int32", kvlangBuiltinCastInt32}, {"int64", kvlangBuiltinCastInt64}, {"uint8", kvlangBuiltinCastUint8}, - {"uint16", kvlangBuiltinCastUint16}, {"uint32", kvlangBuiltinCastUint32}, {"uint64", kvlangBuiltinCastUint64}, - {"float32", kvlangBuiltinCastF32}, {"float64", kvlangBuiltinCastF64}, - {"char/utf32", kvlangBuiltinCastChar32}, {"char/utf8", kvlangBuiltinCastChar8}, {"char/ascii", kvlangBuiltinCastCharAscii}, - /* collection */ - {"array", kvlangBuiltinArray}, {"array·fill", kvlangBuiltinArrayFill}, - {"array·scatter", kvlangBuiltinScatter}, {"array·compact", kvlangBuiltinCompact}, - {"array·append", kvlangBuiltinAppend}, {"array·slice", kvlangBuiltinSlice}, - {"obj", kvlangBuiltinObj}, {"map", kvlangBuiltinMap}, {"struct·new", kvlangBuiltinStructNew}, - {"ndarray·numel", kvlangBuiltinNdarrayNumel}, {"ndarray·dim", kvlangBuiltinNdarrayDim}, {"ndarray·shape", kvlangBuiltinNdarrayShape}, - {"xv·at", kvlangBuiltinXvAt}, {"xv·set", kvlangBuiltinXvSet}, {"xv·reshape", kvlangBuiltinXvReshape}, - {"xv·reinterpret", kvlangBuiltinXvReinterpret}, - {"xv·langtype", kvlangBuiltinXvLangtype}, {"xv·bodylen", kvlangBuiltinXvBodylen}, - {"string·set", kvlangBuiltinStringSet}, {"string·char", kvlangBuiltinStringChar}, {"string·ord", kvlangBuiltinStringOrd}, - {"string·cmp", kvlangBuiltinStringCmp}, {"string·find", kvlangBuiltinStringFind}, {"string·len", kvlangBuiltinStringLen}, - {"string·slice", kvlangBuiltinStringSlice}, {"string·concat", kvlangBuiltinStringConcat}, - {"string·formatint", kvlangBuiltinStringFormatInt}, {"string·formatuint", kvlangBuiltinStringFormatUint}, - {"string·parseint", kvlangBuiltinStringParseInt}, {"string·parseuint", kvlangBuiltinStringParseUint}, - {"time·now", kvlangBuiltinTimeNow}, {"time·sub", kvlangBuiltinTimeSub}, {"time·add", kvlangBuiltinTimeAdd}, - {"time/duration·nanos", kvlangBuiltinDurFrom}, {"time/duration·millis", kvlangBuiltinDurFrom}, - {"time/duration·seconds", kvlangBuiltinDurFrom}, {"time/duration·minutes", kvlangBuiltinDurFrom}, - {"time/duration·hours", kvlangBuiltinDurFrom}, - {"time/duration·as_nanos", kvlangBuiltinDurTo}, {"time/duration·as_millis", kvlangBuiltinDurTo}, - {"time/duration·as_seconds", kvlangBuiltinDurTo}, {"time/duration·as_minutes", kvlangBuiltinDurTo}, - {"time/duration·as_hours", kvlangBuiltinDurTo}, - {"time/duration·add", kvlangBuiltinDurArith}, {"time/duration·sub", kvlangBuiltinDurArith}, - {"time/duration·before", kvlangBuiltinDurCmp}, {"time/duration·after", kvlangBuiltinDurCmp}, - {"time·before", kvlangBuiltinTimeCmp}, {"time·after", kvlangBuiltinTimeCmp}, - {"random·uint64", kvlangBuiltinRandUint64}, {"random·int63", kvlangBuiltinRandInt63}, {"random·intn", kvlangBuiltinRandIntn}, - {"kvspace·get", kvlangCGet}, {"kvspace·set", kvlangCSet}, {"kvspace·del", kvlangCDel}, - {"kvspace·deltree", kvlangCDelTree}, {"kvspace·cp", kvlangCCp}, {"kvspace·cpdir", kvlangCCpTree}, {"kvspace·cplist", kvlangCCpList}, {"kvspace·list", kvlangCList}, {"kvspace·listlen", kvlangCListLen}, {"kvspace·listn", kvlangCListN}, {"kvspace·mkindex", kvlangCMkindex}, - {"kvspace·extindex", kvlangCExtIndex}, {"kvspace·rmindexext", kvlangCRmIndexExt}, {"kvspace·watch", kvlangCWatch}, {"kvlang·abs", kvlangCAbs}, - {"vthread·create", kvlangBuiltinVthreadCreate}, - {"vthread·run", kvlangBuiltinVthreadRun}, - {"vthread·call", kvlangBuiltinVthreadCall}, - {"vthread·sleep", kvlangBuiltinVthreadSleep}, - {"vthread·setstatus", kvlangBuiltinVthreadSetstatus}, - {"debugger", kvlangBuiltinDebugger}, -}; - -static const size_t myrwircaps_n = sizeof(myrwircaps) / sizeof(myrwircaps[0]); - -/* C 原生数值 langtype 集:仅这些精度的算术走 kvlangBuiltinAdd 等通用实现。 - * int4/fp8/bf16 等 C 表达不了的量化精度不在此列,其 ·op 走专精 fn 或 handoff。 */ -static const char *NUM_KINDS[] = {"int8", "int16", "int32", "int64", "uint8", - "uint16", "uint32", "uint64", "float32", "float64"}; -static bool is_num_kind_prefix(const char *op, size_t n) { - for (size_t i = 0; i < sizeof(NUM_KINDS) / sizeof(NUM_KINDS[0]); i++) - if (strlen(NUM_KINDS[i]) == n && strncmp(op, NUM_KINDS[i], n) == 0) return true; - return false; -} - -/* rwirtable 两级查找:先查完整 opcode(命中=专精实现,如 fp8·add,或 time·add 等成员算子), - * 未命中且末段前缀是 C 原生数值 langtype 才拆前缀查裸算子(int64·add → add,通用实现)。 - * 非数值前缀(time/duration·max 等用户 rwfunc)不剥离,两级皆 miss → 非本 runtime native。 */ -int kvlangBuiltinCapIndex(const char *opcode) { - for (size_t i = 0; i < myrwircaps_n; i++) - if (strcmp(myrwircaps[i].op, opcode) == 0) return (int)i; - const char *dot = strstr(opcode, MEMBER_SEP); - if (dot && is_num_kind_prefix(opcode, (size_t)(dot - opcode))) { - const char *bare = dot + MEMBER_SEP_LEN; - for (size_t i = 0; i < myrwircaps_n; i++) - if (strcmp(myrwircaps[i].op, bare) == 0) return (int)i; - } - return -1; -} - -/* notinmycaps:查 myrwircaps table。opcode 不在本 runtime 能力表内 → true - * (即须经 /lib/ 的 def rwir 路由给能兑现它的其它 runtime,或为用户 rwfunc)。 */ -bool notinmycaps(const char *opcode) { - return kvlangBuiltinCapIndex(opcode) < 0; -} - -bool kvlangBuiltinNumOp(const char *opcode) { - switch (opcode[0]) { - case 'a': return strcmp(opcode, "add") == 0 || strcmp(opcode, "abs") == 0; - case 'b': return strcmp(opcode, "bitand") == 0 || strcmp(opcode, "bitor") == 0 || strcmp(opcode, "bitxor") == 0; - case 'd': return strcmp(opcode, "div") == 0; - case 'e': return strcmp(opcode, "eq") == 0 || strcmp(opcode, "exp") == 0; - case 'g': return strcmp(opcode, "gt") == 0 || strcmp(opcode, "ge") == 0; - case 'l': return strcmp(opcode, "lt") == 0 || strcmp(opcode, "le") == 0 || strcmp(opcode, "log") == 0; - case 'm': return strcmp(opcode, "mod") == 0 || strcmp(opcode, "mul") == 0 || strcmp(opcode, "max") == 0 || strcmp(opcode, "min") == 0; - case 'n': return strcmp(opcode, "neq") == 0 || strcmp(opcode, "neg") == 0; - case 'p': return strcmp(opcode, "pow") == 0; - case 's': return strcmp(opcode, "sub") == 0 || strcmp(opcode, "sqrt") == 0 || strcmp(opcode, "shl") == 0 || strcmp(opcode, "shr") == 0 || strcmp(opcode, "sign") == 0; - } - return false; -} - -int kvlangBuiltinNative(kvlangFrame_t *f) { - int i = f->inst->op_id >= 0 ? f->inst->op_id : kvlangBuiltinCapIndex(f->inst->opcode); - if (i >= 0) return myrwircaps[i].fn(f); - return kvlangBuiltinSetErr(f, "unknown builtin op: %s", f->inst->opcode); -} - -/* ── copy ─────────────────────────────────────────────────────────── */ - -int kvlangBuiltinExecuteCopy(kvlangKv_t *kv, const char *vtid, const char *pc, kvlangRwirInst_t *inst) { - char *fr = kvlangKeytreeFrameRoot(pc); - kvlangFrame_t f = { kv, vtid, pc, inst }; - if (inst->nr == 0) { free(fr); kvlangBuiltinNextPc(&f); return 0; } - kvlangXvalue_t v; kvlangXvalueZero(&v); - kvlangBuiltinResolveReadValue(kv, fr, inst->reads[0].name, &inst->reads[0].val, &v); - for (int i = 0; i < inst->nw; i++) { - const char *slot = inst->writes[i].name; - const char *dot = strstr(slot, MEMBER_SEP); - if (dot && dot != slot) { - /* 成员写前置条件:memhead 必须已存在(同 kvspace·set,见 builtin_kv.c)。 */ - char *b = strndup(slot, (size_t)(dot - slot)); - int ok = kvlangBuiltinCheckMemhead(kv, fr, b); - char msg[320]; - if (ok != 0) - snprintf(msg, sizeof msg, "TypeError: memhead %s does not exist — declare the container first (e.g. `%s:T = {}`)", b, b); - free(b); - if (ok != 0) { - kvlangXvalueFree(&v); free(fr); - kvlangVthreadSetError(kv, vtid, pc, msg); - return -1; - } - } - char *key = kvlangBuiltinResolveWriteSlot(kv, fr, slot); - kvlangKvPair_t pair = { key, v }; - char err[256]; - kvlangKvSet(kv, &pair, 1, err, sizeof err); - free(key); - } - kvlangXvalueFree(&v); - free(fr); - kvlangBuiltinNextPc(&f); - return 0; -} - -/* ── collection helper ────────────────────────────────────────────── */ - - - - - - - - - - - - -/* ── array 系列 ───────────────────────────────────────────────────── */ - - - - - - - - - - - - - - - - - -/* ── dict ─────────────────────────────────────────────────────────── */ - - - -/* ── string 系列 ──────────────────────────────────────────────────── */ - - - - - - - - - -/* ── strconv(对齐 Go strconv 的 Format/Parse,base 2..36)─────────── */ - - - - - - - -/* ── time / duration ──────────────────────────────────────────────── */ - - - - - - - - - - - - -/* ── random ───────────────────────────────────────────────────────── */ - - - - - -/* ── kvspace·* ─────────────────────────────────────────────── */ - - - - - - - - - - - - - - - - -/* ── vthread ─────────────────────────────────────────────────────── */ - - - - - -/* ── vthread 控制 / debugger ─────────────────────────────────────── */ diff --git a/runtime/src/builtin_collection.c b/runtime/src/builtin_collection.c deleted file mode 100644 index cadce3d1..00000000 --- a/runtime/src/builtin_collection.c +++ /dev/null @@ -1,1087 +0,0 @@ -// builtin_coll —— array/ndarray/xv/obj/map 集合与容器 rwir - -#include "builtin_internal.h" - -static void pack_typed_array(const char *kind, const kvlangXvalue_t *elems, - int n, kvlangXvalue_t *out) { - int sz = kvlangXvalueElemSize(kind); - uint8_t *raw = malloc((size_t)sz * (n > 0 ? n : 1)); - for (int i = 0; i < n; i++) { - const uint8_t *b; - int32_t blen; - kvspaceHead_t h; - kvspaceDecodeHead(elems[i].data, elems[i].len, &h); - b = elems[i].data + h.body_offset; - blen = h.body_len; - int c = blen < sz ? blen : sz; - memcpy(raw + i * sz, b, (size_t)c); - for (int j = c; j < sz; j++) - raw[i * sz + j] = 0; - } - kvlangXvalueNewTlv(out, kind, raw, (uint32_t)(sz * n), n); - free(raw); -} - -static int separated_len(kvlangKv_t *kv, const char *base) { - for (int i = 0;; i++) { - kvlangStrbuf_t k; - kvlangStrbufInit(&k); - kvlangStrbufPuts(&k, base); - kvlangStrbufPuts(&k, MEMBER_SEP); - kvlangStrbufPrintf(&k, "[%d]", i); - kvlangXvalue_t v; - kvlangXvalueZero(&v); - kvlangKvGetOne(kv, k.p, &v); - bool none = kvlangXvalueNone(&v); - kvlangXvalueFree(&v); - kvlangStrbufFree(&k); - if (none) - return i; - } -} - -/* 坐标段 key:base·[s0,s1,...]。1 维即 base·[s0]。 */ -char *kvlangBuiltinScatterKey(const char *base, const int64_t *coords, - int ncoord) { - kvlangStrbuf_t b; - kvlangStrbufInit(&b); - kvlangStrbufPuts(&b, base); - kvlangStrbufPuts(&b, MEMBER_SEP); - kvlangStrbufPutc(&b, '['); - for (int i = 0; i < ncoord; i++) { - if (i) - kvlangStrbufPutc(&b, ','); - kvlangStrbufPrintf(&b, "%lld", (long long)coords[i]); - } - kvlangStrbufPutc(&b, ']'); - return kvlangStrbufDetach(&b); -} - -/* kvlangBuiltinMemindex(p·):kind=index,body=[4B count LE][name\n...],成员列表唯一权威。 */ -void kvlangBuiltinMemindex(kvlangXvalue_t *out, const char *const *names, - int n) { - kvlangStrbuf_t body; - kvlangStrbufInit(&body); - char count[4] = {(char)(n & 0xFF), (char)((n >> 8) & 0xFF), - (char)((n >> 16) & 0xFF), (char)((n >> 24) & 0xFF)}; - kvlangStrbufPutn(&body, count, 4); - for (int i = 0; i < n; i++) { - if (i) - kvlangStrbufPutc(&body, '\n'); - kvlangStrbufPuts(&body, names[i]); - } - kvlangXvalueNewTlv(out, KVSPACE_KIND_INDEX, (const uint8_t *)body.p, - (uint32_t)body.len, 1); - kvlangStrbufFree(&body); -} - -/* map 容器值(p):body 空、storetype=index,langtype 为 map langtype(见 [[map容器]])。 - * langtype 恒非空——layout 强制容器字面量写目标带 map langtype(缺则 layout 报错)。 */ -void kvlangBuiltinMapMarker(kvlangXvalue_t *out, const char *langtype, - const int32_t *dims, int ndim) { - kvlangXvalueNewTlvDims(out, langtype, (const uint8_t *)"", 0, dims, ndim); -} - -/* 写槽 `w` 的声明容器类型:layout 的 write_slot_value 把 map langtype 落进写槽的 langtype - * (见 code.rs)。缺类型即 layout 漏检——直接 fatal,不退化兜底。调用方负责 free。 */ -static char *declared_map_langtype(kvlangFrame_t *f, int w) { - if (w >= f->inst->nw) { - fprintf(stderr, - "panic: container literal write slot %d missing (nw=%d)\n", w, - f->inst->nw); - abort(); - } - char buf[256]; - kvlangXvalueLangtype(&f->inst->writes[w].val, buf, sizeof buf); - if (!strstr(buf, MEMBER_SEP)) { - fprintf(stderr, - "panic: container literal target %s has no map langtype " - "(layout must reject)\n", - f->inst->writes[w].name); - abort(); - } - return strdup(buf); -} - -static void ensure_scattered(kvlangFrame_t *f, const char *base) { - kvlangXvalue_t arr; - kvlangXvalueZero(&arr); - kvlangKvGetOne(f->kv, base, &arr); - if (kvlangXvalueNone(&arr) || - kvlangXvalueElemSize(kvlangXvalueKind(&arr)) <= 0) { - kvlangXvalueFree(&arr); - return; - } - int n = kvlangXvalueArrayLen(&arr); - for (int i = 0; i < n; i++) { - int64_t c[1] = {i}; - char *k = kvlangBuiltinScatterKey(base, c, 1); - kvlangXvalue_t e; - kvlangBuiltinXvalueAt(&arr, i, &e); - kvlangKvPair_t p = {k, e}; - char err[256]; - kvlangKvSet(f->kv, &p, 1, err, sizeof err); - kvlangXvalueFree(&e); - free(k); - } - kvlangXvalueFree(&arr); - char err[256]; - kvlangKvDel(f->kv, base, err, sizeof err); -} - -int kvlangBuiltinArray(kvlangFrame_t *f) { - kvlangXvalue_t in[64]; - int n = kvlangBuiltinReadInputs(f, in, 64); - if (f->inst->nw == 0 || n == 0) { - kvlangBuiltinNextPc(f); - kvlangBuiltinFreeInputs(in, n); - return 0; - } - const char *kind = kvlangXvalueKind(&in[0]); - if (kvlangXvalueElemSize(kind) <= 0) { - kvlangBuiltinFreeInputs(in, n); - return kvlangBuiltinSetErr(f, "array: unsupported element kind %s", - kind); - } - for (int i = 1; i < n; i++) - if (strcmp(kvlangXvalueKind(&in[i]), kind) != 0) { - kvlangBuiltinFreeInputs(in, n); - return kvlangBuiltinSetErr(f, "array: mixed kinds %s and %s", kind, - kvlangXvalueKind(&in[i])); - } - kvlangXvalue_t arr; - pack_typed_array(kind, in, n, &arr); - char *fr = kvlangKeytreeFrameRoot(f->pc); - char *key = - kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[0].name); - free(fr); - kvlangKvPair_t p = {key, arr}; - char err[256]; - kvlangKvSet(f->kv, &p, 1, err, sizeof err); - free(key); - kvlangXvalueFree(&arr); - kvlangBuiltinNextPc(f); - kvlangBuiltinFreeInputs(in, n); - return 0; -} - -/* array·fill(langtype[, value]) -> a:按 langtype 的定长维度一次成型 compact 数组, - * 每元素填 value(缺省全零)。用于大数组初始化,无需逐元素赋值。 */ -int kvlangBuiltinArrayFill(kvlangFrame_t *f) { - if (f->inst->nw == 0) - return kvlangBuiltinSetErr( - f, "TypeError: array.fill requires a write param (-> a)"); - kvlangXvalue_t in[2]; - int n = kvlangBuiltinReadInputs(f, in, 2); - if (n < 1) { - kvlangBuiltinFreeInputs(in, n); - return kvlangBuiltinSetErr(f, - "TypeError: array.fill requires a langtype"); - } - char *ke = kvlangXvalueValueString(&in[0]); - kvlangLangtype kx; - kvlangLangtypeParse((const uint8_t *)ke, &kx); - int sz = kvlangXvalueElemSize(kx.kind); - if (sz <= 0 || sz > 8 || kx.ndim < 1 || kx.array_len < 0) { - int rc = kvlangBuiltinSetErr( - f, "TypeError: array.fill: not a fixed-length array type %s", ke); - free(ke); - kvlangBuiltinFreeInputs(in, n); - return rc; - } - uint8_t elem[8] = {0}; - if (n >= 2 && !kvlangXvalueNone(&in[1])) { - kvlangScalar_t s = kvlangXvalueScalar(&in[1]); - int tid = kvlangLangTypeId(kx.kind, kx.kind_len); - if (tid == KVLANG_LT_FLOAT32) { - float v = (float)kvlangScalarF64(s); - memcpy(elem, &v, 4); - } else if (tid == KVLANG_LT_FLOAT64) { - double v = kvlangScalarF64(s); - memcpy(elem, &v, 8); - } else { - int64_t v = kvlangScalarI64(s); - memcpy(elem, &v, (size_t)sz); - } - } - size_t total = (size_t)sz * (size_t)kx.array_len; - uint8_t *raw = malloc(total > 0 ? total : 1); - for (int i = 0; i < kx.array_len; i++) - memcpy(raw + (size_t)i * sz, elem, (size_t)sz); - kvlangXvalue_t arr; - kvlangXvalueNewTlvDims(&arr, kx.kind, raw, (uint32_t)total, kx.dims, - kx.ndim); - free(raw); - int rc = kvlangBuiltinWriteResult(f, &arr); - kvlangXvalueFree(&arr); - free(ke); - kvlangBuiltinFreeInputs(in, n); - return rc; -} - -static int xv_head1(kvlangFrame_t *f, - kvspaceHead_t *h); /* GetHead-only 单读参 head,定义见下 */ - -/* ndarray 形状算子只认带形状段的 langtype。map 容器(langtype=`{keylt}·{valt}`)无形状段—— - * 成员数在 memindex(`p·`)而非容器值,用 ndarray·numel 取是范畴错误,直接报错逼用 kvspace·listlen。 */ -static int ndarray_shape_guard(kvlangFrame_t *f, const char *op, - const kvspaceHead_t *h) { - kvlangLangtype kx; - kvlangLangtypeParse(h->langtype, &kx); - if (kx.ndim > 0) - return 0; - if (kvlangKindIsMap(kx.kind)) - return kvlangBuiltinSetErr(f, - "TypeError: %s: container %s has no shape; " - "use kvspace·listlen for member count", - op, kx.kind); - return 0; -} - -int kvlangBuiltinNdarrayNumel(kvlangFrame_t *f) { - kvspaceHead_t h; - int64_t n_el = 0; - if (xv_head1(f, &h) == 0) { - int g = ndarray_shape_guard(f, "ndarray·numel", &h); - if (g) - return g; - kvlangLangtype kx; - kvlangLangtypeParse(h.langtype, &kx); - n_el = kx.array_len; - } - kvlangXvalue_t r; - kvlangXvalueNewInt64(&r, n_el); - int rc = kvlangBuiltinWriteResult(f, &r); - kvlangXvalueFree(&r); - return rc; -} - -int kvlangBuiltinNdarrayDim(kvlangFrame_t *f) { - kvspaceHead_t h; - int64_t ndim = 0; - if (xv_head1(f, &h) == 0) { - int g = ndarray_shape_guard(f, "ndarray·dim", &h); - if (g) - return g; - kvlangLangtype kx; - kvlangLangtypeParse(h.langtype, &kx); - ndim = kx.ndim; - } - kvlangXvalue_t r; - kvlangXvalueNewInt64(&r, ndim); - int rc = kvlangBuiltinWriteResult(f, &r); - kvlangXvalueFree(&r); - return rc; -} - -int kvlangBuiltinNdarrayShape(kvlangFrame_t *f) { - int32_t dims[8]; - int32_t ndim = 0; - kvspaceHead_t h; - if (xv_head1(f, &h) == 0) { - int g = ndarray_shape_guard(f, "ndarray·shape", &h); - if (g) - return g; - kvlangLangtype kx; - kvlangLangtypeParse(h.langtype, &kx); - ndim = kx.ndim; - for (int i = 0; i < ndim && i < 8; i++) - dims[i] = kx.dims[i]; - } - uint8_t raw[64]; - uint32_t raw_len = 0; - for (int i = 0; i < ndim; i++) { - int64_t d = dims[i]; - for (int j = 0; j < 8; j++) - raw[i * 8 + j] = (d >> (j * 8)) & 0xFF; - raw_len += 8; - } - int32_t sd[1] = {ndim}; - kvlangXvalue_t r; - kvlangXvalueNewTlvDims(&r, KVSPACE_KIND_INT64, raw, raw_len, sd, 1); - int rc = kvlangBuiltinWriteResult(f, &r); - kvlangXvalueFree(&r); - return rc; -} - -/* 计算多维下标的 row-major 扁平索引,越界返回 -1。 */ -static int64_t flat_index(const kvlangLangtype *kx, const int64_t *idx, - int nidx) { - int64_t flat = 0; - for (int i = 0; i < nidx; i++) { - if (idx[i] < 0 || idx[i] >= kx->dims[i]) - return -1; - flat = flat * kx->dims[i] + idx[i]; - } - return flat; -} - -/* base kind(kx.kind 为非 NUL 终止子串)拷成 NUL 终止串,取元素字节大小;空 kind → 0。 */ -static int xv_elem_size(const kvlangLangtype *kx) { - if (!kx->kind || kx->kind_len <= 0) - return 0; - char kb[64]; - int kl = kx->kind_len < 63 ? kx->kind_len : 63; - memcpy(kb, kx->kind, (size_t)kl); - kb[kl] = 0; - return kvlangXvalueElemSize(kb); -} - -/* 读参 ri 的 head:变量走 GetHead 只读前缀(不借 body,*key=malloc'd 键),字面量数组借整块 - * 解 head(*key=NULL,*borrow 持整块,调用方 kvlangXvalueFree)。返回 0 成功、非 0 空/不存在。 */ -static int xv_read_head(kvlangFrame_t *f, const char *fr, int ri, - kvspaceHead_t *h, char **key, kvlangXvalue_t *borrow) { - kvlangXvalueZero(borrow); - *key = NULL; - char *k = kvlangBuiltinResolveReadKey(f->kv, fr, f->inst->reads[ri].name, - &f->inst->reads[ri].val); - if (k) { - if (kvlangKvGetHead(f->kv, k, h) != 0) { - free(k); - return -1; - } - *key = k; - return 0; - } - kvlangBuiltinResolveReadValue(f->kv, fr, f->inst->reads[ri].name, - &f->inst->reads[ri].val, borrow); - if (kvlangXvalueNone(borrow)) - return -1; - return kvspaceDecodeHead(borrow->data, borrow->len, h) == 0 ? 0 : -1; -} - -/* 单读参 head:GetHead-only(变量)或借块解码(字面量),完毕即释放借块与键。 - * 返回 0 并填 *h;空/不存在返回 -1(调用方给默认值)。 */ -static int xv_head1(kvlangFrame_t *f, kvspaceHead_t *h) { - char *fr = kvlangKeytreeFrameRoot(f->pc); - char *key; - kvlangXvalue_t borrow; - int rc = xv_read_head(f, fr, 0, h, &key, &borrow); - free(key); - kvlangXvalueFree(&borrow); - free(fr); - return rc; -} - -/* 读 first..first+nidx-1 的标量下标到 idx[]。 */ -static void xv_read_indices(kvlangFrame_t *f, const char *fr, int first, - int nidx, int64_t *idx) { - for (int i = 0; i < nidx && i < X_MAX_NDIM; i++) { - kvlangXvalue_t iv; - kvlangBuiltinResolveReadValue(f->kv, fr, f->inst->reads[first + i].name, - &f->inst->reads[first + i].val, &iv); - idx[i] = kvlangScalarI64(kvlangXvalueScalar(&iv)); - kvlangXvalueFree(&iv); - } -} - -/* 分片读单元素:GetHead 定位 + GetPart 只借该元素的 [off, off+sz) 字节,不借整块。 */ -int kvlangBuiltinXvAt(kvlangFrame_t *f) { - int nidx = f->inst->nr - 1; - if (nidx < 1) - return kvlangBuiltinSetErr( - f, "TypeError: xv.at requires array and indices"); - char *fr = kvlangKeytreeFrameRoot(f->pc); - kvspaceHead_t h; - char *key; - kvlangXvalue_t arr; - if (xv_read_head(f, fr, 0, &h, &key, &arr) != 0) { - free(fr); - return kvlangBuiltinSetErr(f, - "TypeError: xv.at requires a compact array"); - } - kvlangLangtype kx; - kvlangLangtypeParse(h.langtype, &kx); - int sz = xv_elem_size(&kx); - if (sz <= 0 || kx.ndim == 0) { - free(key); - kvlangXvalueFree(&arr); - free(fr); - return kvlangBuiltinSetErr( - f, "TypeError: xv.at requires a compact array, got %s", h.langtype); - } - if (nidx != kx.ndim) { - free(key); - kvlangXvalueFree(&arr); - free(fr); - return kvlangBuiltinSetErr( - f, "IndexError: xv.at: %d-dim array needs %d indices, got %d", - kx.ndim, kx.ndim, nidx); - } - int64_t idx[X_MAX_NDIM]; - xv_read_indices(f, fr, 1, nidx, idx); - free(fr); - int64_t flat = flat_index(&kx, idx, nidx); - if (flat < 0) { - free(key); - kvlangXvalueFree(&arr); - return kvlangBuiltinSetErr(f, "IndexError: xv.at: index out of bounds"); - } - char kb[64]; - int kl = kx.kind_len < 63 ? kx.kind_len : 63; - memcpy(kb, kx.kind, (size_t)kl); - kb[kl] = 0; - kvlangXvalue_t e; - if (key) { - kvlangXvalue_t part; - kvlangKvGetPart(f->kv, key, (uint32_t)(h.body_offset + flat * sz), - (uint32_t)sz, &part); - kvlangXvalueNewTlv(&e, kb, part.data, part.len, 1); - kvlangXvalueFree(&part); - free(key); - } else { - const uint8_t *body = arr.data + h.body_offset; - kvlangXvalueNewTlv(&e, kb, body + flat * sz, (uint32_t)sz, 1); - } - kvlangXvalueFree(&arr); - int rc = kvlangBuiltinWriteResult(f, &e); - kvlangXvalueFree(&e); - return rc; -} - -/* 分片写单元素:写目标==源变量且已存在 → GetHead 定位 + SetPart 就地写该元素字节(O(1), - * 不重建整块);源≠目标 / 字面量 / 缺失 → 回退借整块、拷贝、改元素、整体重建。 */ -int kvlangBuiltinXvSet(kvlangFrame_t *f) { - int nidx = f->inst->nr - 2; - if (nidx < 1) - return kvlangBuiltinSetErr( - f, "TypeError: xv.set requires array, indices, value"); - if (f->inst->nw == 0) - return kvlangBuiltinSetErr( - f, "TypeError: xv.set requires a write param (-> a)"); - char *fr = kvlangKeytreeFrameRoot(f->pc); - char *rk = kvlangBuiltinResolveReadKey(f->kv, fr, f->inst->reads[0].name, - &f->inst->reads[0].val); - char *wk = - kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[0].name); - int64_t idx[X_MAX_NDIM]; - xv_read_indices(f, fr, 1, nidx, idx); - kvlangXvalue_t vv; - kvlangBuiltinResolveReadValue(f->kv, fr, f->inst->reads[nidx + 1].name, - &f->inst->reads[nidx + 1].val, &vv); - kvspaceHead_t vh; - kvspaceDecodeHead(vv.data, vv.len, &vh); - const uint8_t *vb = vv.data + vh.body_offset; - - kvspaceHead_t h; - if (rk && wk && strcmp(rk, wk) == 0 && - kvlangKvGetHead(f->kv, wk, &h) == 0) { - kvlangLangtype kx; - kvlangLangtypeParse(h.langtype, &kx); - int sz = xv_elem_size(&kx); - int64_t flat = (sz > 0 && kx.ndim && nidx == kx.ndim) - ? flat_index(&kx, idx, nidx) - : -1; - const char *emsg = - sz <= 0 || kx.ndim == 0 - ? "TypeError: xv.set requires a compact array" - : nidx != kx.ndim ? "IndexError: xv.set: dim/index count mismatch" - : flat < 0 ? "IndexError: xv.set: index out of bounds" - : NULL; - int rc = 0; - if (emsg) - rc = kvlangBuiltinSetErr(f, "%s", emsg); - else { - int c = vh.body_len < sz ? vh.body_len : sz; - char err[256]; - kvlangKvSetPart(f->kv, wk, (uint32_t)(h.body_offset + flat * sz), - vb, (uint32_t)c, err, sizeof err); - kvlangBuiltinNextPc(f); - } - free(rk); - free(wk); - free(fr); - kvlangXvalueFree(&vv); - return rc; - } - free(rk); - free(wk); - - kvlangXvalue_t arr; - kvlangBuiltinResolveReadValue(f->kv, fr, f->inst->reads[0].name, - &f->inst->reads[0].val, &arr); - free(fr); - const char *k = kvlangXvalueKind(&arr); - int sz = kvlangXvalueElemSize(k); - kvspaceHead_t ah; - kvspaceDecodeHead(arr.data, arr.len, &ah); - kvlangLangtype kx; - kvlangLangtypeParse(ah.langtype, &kx); - const char *emsg = - sz <= 0 || kx.ndim == 0 ? "TypeError: xv.set requires a compact array" - : nidx != kx.ndim ? "IndexError: xv.set: dim/index count mismatch" - : NULL; - int64_t flat = emsg ? -1 : flat_index(&kx, idx, nidx); - if (!emsg && flat < 0) - emsg = "IndexError: xv.set: index out of bounds"; - if (emsg) { - kvlangXvalueFree(&arr); - kvlangXvalueFree(&vv); - return kvlangBuiltinSetErr(f, "%s", emsg); - } - uint8_t *nb = malloc((size_t)ah.body_len); - memcpy(nb, arr.data + ah.body_offset, (size_t)ah.body_len); - int c = vh.body_len < sz ? vh.body_len : sz; - memcpy(nb + flat * sz, vb, (size_t)c); - kvlangXvalue_t nv; - kvlangXvalueNewTlvDims(&nv, k, nb, (uint32_t)ah.body_len, kx.dims, kx.ndim); - int rc = kvlangBuiltinWriteResult(f, &nv); - kvlangXvalueFree(&nv); - free(nb); - kvlangXvalueFree(&arr); - kvlangXvalueFree(&vv); - return rc; -} - -int kvlangBuiltinXvReshape(kvlangFrame_t *f) { - int ndims = f->inst->nr - 1; - if (ndims < 1) - return kvlangBuiltinSetErr( - f, "TypeError: xv.reshape requires array and >=1 dims"); - if (f->inst->nw == 0) - return kvlangBuiltinSetErr( - f, "TypeError: xv.reshape requires a write param (-> a)"); - kvlangXvalue_t in[MAX_PARAMS]; - int n = kvlangBuiltinReadInputs(f, in, MAX_PARAMS); - const char *k = kvlangXvalueKind(&in[0]); - if (kvlangXvalueElemSize(k) <= 0) { - kvlangBuiltinFreeInputs(in, n); - return kvlangBuiltinSetErr( - f, "TypeError: xv.reshape requires a compact array, got %s", k); - } - kvspaceHead_t h; - kvspaceDecodeHead(in[0].data, in[0].len, &h); - kvlangLangtype kx; - kvlangLangtypeParse(h.langtype, &kx); - if (kx.ndim < 1) { - kvlangBuiltinFreeInputs(in, n); - return kvlangBuiltinSetErr( - f, "TypeError: xv.reshape requires a compact array, got scalar %s", - k); - } - if (ndims > X_MAX_NDIM) { - kvlangBuiltinFreeInputs(in, n); - return kvlangBuiltinSetErr( - f, "IndexError: xv.reshape: at most %d dims, got %d", X_MAX_NDIM, - ndims); - } - int32_t dims[X_MAX_NDIM]; - int64_t numel = 1; - for (int i = 0; i < ndims; i++) { - dims[i] = (int32_t)kvlangScalarI64(kvlangXvalueScalar(&in[i + 1])); - if (dims[i] < 0) { - kvlangBuiltinFreeInputs(in, n); - return kvlangBuiltinSetErr( - f, "IndexError: xv.reshape: negative dim %d", dims[i]); - } - numel *= dims[i]; - } - if (numel != kx.array_len) { - kvlangBuiltinFreeInputs(in, n); - return kvlangBuiltinSetErr( - f, "IndexError: xv.reshape: cannot reshape %d elements into %lld", - kx.array_len, (long long)numel); - } - const uint8_t *body = in[0].data + h.body_offset; - kvlangXvalue_t nv; - kvlangXvalueNewTlvDims(&nv, k, body, (uint32_t)h.body_len, dims, ndims); - int rc = kvlangBuiltinWriteResult(f, &nv); - kvlangXvalueFree(&nv); - kvlangBuiltinFreeInputs(in, n); - return rc; -} - -/* xv·reinterpret(arr, langtype) -> a:body 字节原样,整个 langtype 换成传入的(kind+dims 一起),不做校验。 */ -int kvlangBuiltinXvReinterpret(kvlangFrame_t *f) { - if (f->inst->nr < 2) - return kvlangBuiltinSetErr( - f, "TypeError: xv.reinterpret requires array and langtype"); - if (f->inst->nw == 0) - return kvlangBuiltinSetErr( - f, "TypeError: xv.reinterpret requires a write param (-> a)"); - kvlangXvalue_t in[2]; - int n = kvlangBuiltinReadInputs(f, in, 2); - char *ke = kvlangXvalueValueString(&in[1]); - kvlangLangtype nkx; - kvlangLangtypeParse((const uint8_t *)ke, &nkx); - kvspaceHead_t h; - kvspaceDecodeHead(in[0].data, in[0].len, &h); - const uint8_t *body = in[0].data + h.body_offset; - /* 动态 "[]kind"(parse 得 ndim0 但带方括号):按 body 字节数补出一维长度,与落盘数组表示一致。 */ - int32_t ndim = nkx.ndim; - if (nkx.ndim == 0 && strchr(ke, '[')) { - int32_t es = kvlangXvalueElemSize(nkx.kind); - nkx.dims[0] = es > 0 ? (int32_t)(h.body_len / es) : (int32_t)h.body_len; - ndim = 1; - } - kvlangXvalue_t nv; - kvlangXvalueNewTlvDims(&nv, nkx.kind, body, (uint32_t)h.body_len, nkx.dims, - ndim); - int rc = kvlangBuiltinWriteResult(f, &nv); - kvlangXvalueFree(&nv); - free(ke); - kvlangBuiltinFreeInputs(in, n); - return rc; -} - -/* xv·langtype(v) -> s:返回 v 的 head langtype 串(含 ref 前缀与 [dims]),作为字符串。 */ -int kvlangBuiltinXvLangtype(kvlangFrame_t *f) { - if (f->inst->nw == 0) - return kvlangBuiltinSetErr( - f, "TypeError: xv.langtype requires a write param (-> s)"); - kvspaceHead_t h; - const char *ke = ""; - if (xv_head1(f, &h) == 0) - ke = (const char *)h.langtype; - kvlangXvalue_t r; - kvlangXvalueNewCharUtf8(&r, ke); - int rc = kvlangBuiltinWriteResult(f, &r); - kvlangXvalueFree(&r); - return rc; -} - -/* xv·bodylen(v) -> n:返回 v 的 body 字节数(int64)。 */ -int kvlangBuiltinXvBodylen(kvlangFrame_t *f) { - if (f->inst->nw == 0) - return kvlangBuiltinSetErr( - f, "TypeError: xv.bodylen requires a write param (-> n)"); - kvspaceHead_t h; - int64_t bl = 0; - if (xv_head1(f, &h) == 0) - bl = h.body_len; - kvlangXvalue_t r; - kvlangXvalueNewInt64(&r, bl); - int rc = kvlangBuiltinWriteResult(f, &r); - kvlangXvalueFree(&r); - return rc; -} - -int kvlangBuiltinScatter(kvlangFrame_t *f) { - if (f->inst->nw == 0) - return kvlangBuiltinSetErr( - f, "TypeError: array.scatter requires a write param"); - kvlangXvalue_t in[2]; - int n = kvlangBuiltinReadInputs(f, in, 2); - if (n == 0 || kvlangXvalueNone(&in[0])) { - kvlangBuiltinNextPc(f); - kvlangBuiltinFreeInputs(in, n); - return 0; - } - if (kvlangXvalueElemSize(kvlangXvalueKind(&in[0])) <= 0) { - kvlangBuiltinFreeInputs(in, n); - return kvlangBuiltinSetErr( - f, - "TypeError: array.scatter requires a compact array ([]T), got %s", - kvlangXvalueKind(&in[0])); - } - char *fr = kvlangKeytreeFrameRoot(f->pc); - char *dst = - kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[0].name); - int al = kvlangXvalueArrayLen(&in[0]); - if (al > 0) { - char err[256]; - int32_t dims[1] = {al}; - /* 散 key 化的容器值类型:键是坐标段 `[i]`,值是原 compact 元素类型(逐元素原样搬)。 */ - char ty[256]; - snprintf(ty, sizeof ty, "[int64]%s%s", MEMBER_SEP, - kvlangXvalueKind(&in[0])); - kvlangXvalue_t mark; - kvlangBuiltinMapMarker(&mark, ty, dims, 1); - kvlangKvPair_t p0 = {dst, mark}; - kvlangKvSet(f->kv, &p0, 1, err, sizeof err); - kvlangXvalueFree(&mark); - } - for (int i = 0; i < al; i++) { - int64_t c[1] = {i}; - char *k = kvlangBuiltinScatterKey(dst, c, 1); - kvlangXvalue_t e; - kvlangBuiltinXvalueAt(&in[0], i, &e); - kvlangKvPair_t p = {k, e}; - char err[256]; - kvlangKvSet(f->kv, &p, 1, err, sizeof err); - kvlangXvalueFree(&e); - free(k); - } - free(dst); - free(fr); - kvlangBuiltinNextPc(f); - kvlangBuiltinFreeInputs(in, n); - return 0; -} - -int kvlangBuiltinCompact(kvlangFrame_t *f) { - if (f->inst->nr == 0 || f->inst->nw == 0) - return kvlangBuiltinSetErr( - f, "TypeError: array.compact requires read and write params"); - char *fr = kvlangKeytreeFrameRoot(f->pc); - char *src = - kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->reads[0].name); - kvlangXvalue_t elems[1024]; - int n = 0; - for (int i = 0;; i++) { - int64_t c[1] = {i}; - char *k = kvlangBuiltinScatterKey(src, c, 1); - kvlangXvalue_t v; - kvlangXvalueZero(&v); - kvlangKvGetOne(f->kv, k, &v); - bool none = kvlangXvalueNone(&v); - free(k); - if (none) - break; - elems[n++] = v; - } - if (n == 0) { - free(src); - free(fr); - kvlangBuiltinNextPc(f); - return 0; - } - kvlangXvalue_t arr; - pack_typed_array(kvlangXvalueKind(&elems[0]), elems, n, &arr); - char *dst = - kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[0].name); - kvlangKvPair_t p = {dst, arr}; - char err[256]; - kvlangKvSet(f->kv, &p, 1, err, sizeof err); - for (int i = 0; i < n; i++) - kvlangXvalueFree(&elems[i]); - kvlangXvalueFree(&arr); - free(dst); - free(src); - free(fr); - kvlangBuiltinNextPc(f); - return 0; -} - -int kvlangBuiltinAppend(kvlangFrame_t *f) { - if (f->inst->nr < 2) - return kvlangBuiltinSetErr( - f, "TypeError: array.append requires array and element"); - if (f->inst->nw == 0) - return kvlangBuiltinSetErr( - f, "TypeError: array.append requires a write param (-> arr)"); - kvlangXvalue_t in[2]; - int n = kvlangBuiltinReadInputs(f, in, 2); - char *fr = kvlangKeytreeFrameRoot(f->pc); - char *base = - kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[0].name); - ensure_scattered(f, base); - int len = separated_len(f->kv, base); - int64_t c[1] = {len}; - char *k = kvlangBuiltinScatterKey(base, c, 1); - kvlangKvPair_t p = {k, n >= 2 ? in[1] : in[0]}; - char err[256]; - kvlangKvSet(f->kv, &p, 1, err, sizeof err); - free(k); - free(base); - free(fr); - kvlangBuiltinNextPc(f); - kvlangBuiltinFreeInputs(in, n); - return 0; -} - -int kvlangBuiltinSlice(kvlangFrame_t *f) { - if (f->inst->nr < 3) - return kvlangBuiltinSetErr( - f, "TypeError: array.slice requires array, start, end"); - if (f->inst->nw == 0) - return kvlangBuiltinSetErr( - f, "TypeError: array.slice requires a write param (-> arr)"); - kvlangXvalue_t in[3]; - int n = kvlangBuiltinReadInputs(f, in, 3); - char *fr = kvlangKeytreeFrameRoot(f->pc); - char *base = - kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[0].name); - ensure_scattered(f, base); - int al = separated_len(f->kv, base); - int lo = (int)kvlangScalarI64(kvlangXvalueScalar(&in[1])), - hi = (int)kvlangScalarI64(kvlangXvalueScalar(&in[2])); - if (lo < 0 || hi < lo || hi > al) { - free(base); - free(fr); - kvlangBuiltinFreeInputs(in, n); - return kvlangBuiltinSetErr( - f, "IndexError: array.slice: bounds [%d:%d] out of range (len=%d)", - lo, hi, al); - } - for (int i = lo; i < hi; i++) { - int64_t sc[1] = {i}, dc[1] = {i - lo}; - char *sk = kvlangBuiltinScatterKey(base, sc, 1); - kvlangXvalue_t v; - kvlangXvalueZero(&v); - kvlangKvGetOne(f->kv, sk, &v); - char *dk = kvlangBuiltinScatterKey(base, dc, 1); - kvlangKvPair_t p = {dk, v}; - char err[256]; - kvlangKvSet(f->kv, &p, 1, err, sizeof err); - kvlangXvalueFree(&v); - free(sk); - free(dk); - } - for (int i = hi - lo; i < al; i++) { - int64_t dc[1] = {i}; - char *dk = kvlangBuiltinScatterKey(base, dc, 1); - char err[256]; - kvlangKvDel(f->kv, dk, err, sizeof err); - free(dk); - } - free(base); - free(fr); - kvlangBuiltinNextPc(f); - kvlangBuiltinFreeInputs(in, n); - return 0; -} - -int kvlangBuiltinObj(kvlangFrame_t *f) { - kvlangXvalue_t in[64]; - int n = kvlangBuiltinReadInputs(f, in, 64); - char *fr = kvlangKeytreeFrameRoot(f->pc); - for (int w = 0; w < f->inst->nw; w++) { - char *ok = - kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[w].name); - char err[256]; - /* 重建:清旧成员(p·name),容器值随后重写。 */ - char *dir = kvlangKeytreeMember(ok, ""); - char **old = NULL; - int oc = 0; - kvlangKvList(f->kv, dir, false, false, &old, &oc); - for (int i = 0; i < oc; i++) { - char *mk = kvlangKeytreeMember(ok, old[i]); - kvlangKvDel(f->kv, mk, err, sizeof err); - free(mk); - free(old[i]); - } - free(old); - free(dir); - /* 收集成员名(跳过 None)。 */ - int cnt = 0; - for (int i = 0; i + 1 < n; i += 2) - if (!kvlangXvalueNone(&in[i + 1])) - cnt++; - char **names = malloc(sizeof(char *) * (size_t)(cnt > 0 ? cnt : 1)); - for (int i = 0, j = 0; i + 1 < n; i += 2) { - if (kvlangXvalueNone(&in[i + 1])) - continue; - names[j++] = kvlangXvalueValueString(&in[i]); - } - /* 容器值 p:langtype=声明的 map langtype,dims=[0](命名字典无形状,成员在 memindex)。 */ - int32_t odims[1] = {0}; - char *wty = declared_map_langtype(f, w); - kvlangXvalue_t mark; - kvlangBuiltinMapMarker(&mark, wty, odims, 1); - free(wty); - kvlangKvPair_t p0 = {ok, mark}; - kvlangKvSet(f->kv, &p0, 1, err, sizeof err); - kvlangXvalueFree(&mark); - /* kvlangBuiltinMemindex p·:kind=index,body=[4B count][names]。 */ - char *mip = kvlangKeytreeMember(ok, ""); - kvlangXvalue_t mi; - kvlangBuiltinMemindex(&mi, (const char *const *)names, cnt); - kvlangKvPair_t p1 = {mip, mi}; - kvlangKvSet(f->kv, &p1, 1, err, sizeof err); - kvlangXvalueFree(&mi); - free(mip); - for (int i = 0, j = 0; i + 1 < n; i += 2) { - if (kvlangXvalueNone(&in[i + 1])) - continue; - char *mk = kvlangKeytreeMember(ok, names[j]); - kvlangKvPair_t p = {mk, in[i + 1]}; - kvlangKvSet(f->kv, &p, 1, err, sizeof err); - free(mk); - free(names[j]); - j++; - } - free(names); - free(ok); - } - free(fr); - kvlangBuiltinNextPc(f); - kvlangBuiltinFreeInputs(in, n); - return 0; -} - -static char *dupn(const char *s, size_t n) { - char *r = malloc(n + 1); - memcpy(r, s, n); - r[n] = 0; - return r; -} - -/* 在 "name:langtype\n..." 声明串里查字段名,返回其类型(malloc)或 NULL(无此字段)。 */ -static char *struct_field_type(const char *decl, const char *fname) { - size_t fl = strlen(fname); - const char *p = decl; - while (*p) { - const char *nl = strchr(p, '\n'); - size_t linelen = nl ? (size_t)(nl - p) : strlen(p); - const char *colon = memchr(p, ':', linelen); - if (colon) { - size_t nlen = (size_t)(colon - p); - if (nlen == fl && memcmp(p, fname, fl) == 0) - return dupn(colon + 1, linelen - nlen - 1); - } - if (!nl) - break; - p = nl + 1; - } - return NULL; -} - -/* struct·new:克隆 /lib/Name 原型子树到写槽,覆盖给定字段(校验字段存在性+类型)。 - * in[0]=structref("/lib/Name"),其后成对 (字段名, 值)。实例基值 kind=structref。 */ -int kvlangBuiltinStructNew(kvlangFrame_t *f) { - kvlangXvalue_t in[64]; - int n = kvlangBuiltinReadInputs(f, in, 64); - if (n < 1) { - kvlangBuiltinFreeInputs(in, n); - return kvlangBuiltinSetErr(f, "TypeError: struct.new requires a type"); - } - char *ref = kvlangXvalueValueString(&in[0]); - kvlangXvalue_t proto; - kvlangXvalueZero(&proto); - kvlangKvGetOne(f->kv, ref, &proto); - if (kvlangXvalueNone(&proto) || - strcmp(kvlangXvalueKind(&proto), KVSPACE_KIND_STRUCT) != 0) { - int e = - kvlangBuiltinSetErr(f, "TypeError: %s is not a struct type", ref); - kvlangXvalueFree(&proto); - free(ref); - kvlangBuiltinFreeInputs(in, n); - return e; - } - kvspaceHead_t ph; - kvlangXvalueHead(&proto, &ph); - int32_t dclen = 0; - const uint8_t *dcl = kvlangXvalueBody(&proto, &ph, &dclen); - char *decl = dupn((const char *)dcl, (size_t)(dclen > 0 ? dclen : 0)); - kvlangXvalueFree(&proto); - - char err[256]; - int rc = 0; - char *fr = kvlangKeytreeFrameRoot(f->pc); - for (int w = 0; w < f->inst->nw && rc == 0; w++) { - char *ok = - kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[w].name); - if (kvlangKvCpList(f->kv, ref, ok, err, sizeof err) != 0) { - rc = kvlangBuiltinSetErr(f, "%s", err); - free(ok); - break; - } - kvlangXvalue_t mark; - kvlangXvalueNewTlv(&mark, ref, (const uint8_t *)"", 0, 1); - kvlangKvPair_t p0 = {ok, mark}; - kvlangKvSet(f->kv, &p0, 1, err, sizeof err); - kvlangXvalueFree(&mark); - for (int i = 1; i + 1 < n && rc == 0; i += 2) { - char *fname = kvlangXvalueValueString(&in[i]); - char *ftype = struct_field_type(decl, fname); - if (!ftype) { - rc = kvlangBuiltinSetErr( - f, "TypeError: struct %s has no field %s", ref, fname); - free(fname); - break; - } - const char *vk = kvlangXvalueKind(&in[i + 1]); - kvspaceHead_t vh; - kvlangXvalueHead(&in[i + 1], &vh); - kvlangLangtype vkx; - kvlangLangtypeParse(vh.langtype, &vkx); - // *T 指针字段:字段类型剥离前导 * 后与值的 langtype 比对,并校验值 ref=1; - // None 是合法空指针(见 [[ptr]]),不算类型不符。 - const char *fx = (ftype[0] == '*') ? ftype + 1 : ftype; - bool type_ok = ftype[0] - ? kvlangLangtypeMatch(fx, vk, vkx.ndim, vkx.dims) - : true; - if (ftype[0] == '*' && !kvlangXvalueNone(&in[i + 1]) && - vh.ref != KVSPACE_REF_PTR) - type_ok = false; - if (ftype[0] && !type_ok) { - rc = kvlangBuiltinSetErr( - f, "TypeError: field %s: expected %s, got %s", fname, ftype, - vk[0] ? vk : "None"); - free(ftype); - free(fname); - break; - } - char *mk = kvlangKeytreeMember(ok, fname); - kvlangKvPair_t p = {mk, in[i + 1]}; - kvlangKvSet(f->kv, &p, 1, err, sizeof err); - free(mk); - free(ftype); - free(fname); - } - free(ok); - } - free(fr); - free(decl); - free(ref); - kvlangBuiltinFreeInputs(in, n); - if (rc != 0) - return rc; - kvlangBuiltinNextPc(f); - return 0; -} - -int kvlangBuiltinMap(kvlangFrame_t *f) { - kvlangXvalue_t in[64]; - int n = kvlangBuiltinReadInputs(f, in, 64); - char *fr = kvlangKeytreeFrameRoot(f->pc); - for (int w = 0; w < f->inst->nw; w++) { - char *ok = - kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[w].name); - char err[256]; - /* 重建:清旧成员(p·name)与旧容器值,随后重写。 */ - char *dir = kvlangKeytreeMember(ok, ""); - char **old = NULL; - int oc = 0; - kvlangKvList(f->kv, dir, false, false, &old, &oc); - for (int i = 0; i < oc; i++) { - char *mk = kvlangKeytreeMember(ok, old[i]); - kvlangKvDel(f->kv, mk, err, sizeof err); - free(mk); - free(old[i]); - } - free(old); - free(dir); - kvlangKvDel(f->kv, ok, err, sizeof err); - - char **names = malloc(sizeof(char *) * (size_t)(n > 0 ? n : 1)); - for (int i = 0; i < n; i++) { - kvlangStrbuf_t s; - kvlangStrbufInit(&s); - kvlangStrbufPrintf(&s, "[%d]", i); - names[i] = kvlangStrbufDetach(&s); - } - /* 容器值 p:langtype=声明的 map langtype,body 空,dims=[n] 落 head。 */ - int32_t dims[1] = {n}; - char *wty = declared_map_langtype(f, w); - kvlangXvalue_t mark; - kvlangBuiltinMapMarker(&mark, wty, dims, 1); - free(wty); - kvlangKvPair_t p0 = {ok, mark}; - kvlangKvSet(f->kv, &p0, 1, err, sizeof err); - kvlangXvalueFree(&mark); - /* kvlangBuiltinMemindex p·:kind=index,body=[4B count][[0]\n[1]...]。 */ - char *mip = kvlangKeytreeMember(ok, ""); - kvlangXvalue_t mi; - kvlangBuiltinMemindex(&mi, (const char *const *)names, n); - kvlangKvPair_t p1 = {mip, mi}; - kvlangKvSet(f->kv, &p1, 1, err, sizeof err); - kvlangXvalueFree(&mi); - free(mip); - for (int i = 0; i < n; i++) { - int64_t c[1] = {i}; - char *k = kvlangBuiltinScatterKey(ok, c, 1); - kvlangKvPair_t p = {k, in[i]}; - kvlangKvSet(f->kv, &p, 1, err, sizeof err); - free(k); - free(names[i]); - } - free(names); - free(ok); - } - free(fr); - kvlangBuiltinNextPc(f); - kvlangBuiltinFreeInputs(in, n); - return 0; -} diff --git a/runtime/src/kvcpu.c b/runtime/src/kvcpu.c index b25352d5..7efa1ca5 100644 --- a/runtime/src/kvcpu.c +++ b/runtime/src/kvcpu.c @@ -1221,3 +1221,43 @@ int kvlangKvcpuExecute(kvlangKv_t *kv, const char *pc) { int rc = kvlangKvcpuExecuteMode(kv, pc, KVMODE_WATCH, NULL); return rc == 1 ? 0 : rc; /* WATCH 模式不返回 1,防御性归一 */ } + +/* ── 路由判定 + 扩展 handoff(自 rwirext.c 迁入)────────────── */ + +/* notinmyrwircaps:opcode 是一条不在本 runtime myrwircaps 内、须经 def rwir 路由给 + * 能兑现它的其它 runtime 的 rwir。判据是 /lib/ 存在 def rwir 路由头 + * (langtype=def rwir,storetype=index)。kvspace 是能力唯一事实源;本判定在独立 + * kvlang 进程内发生,进程内 myrwircaps 恒不含它,故只有 /lib 路由头可信。 */ +bool notinmyrwircaps(kvlangKv_t *k, const char *opcode) { + if (opcode[0] == '/') + return false; + char *key = kvlangKeytreeRwir(opcode); + kvlangXvalue_t v; + kvlangXvalueZero(&v); + kvlangKvGetOne(k, key, &v); + bool yes = + !kvlangXvalueNone(&v) && kvlangXvalueKindIs(&v, KVSPACE_KIND_DEF_RWIR); + kvlangXvalueFree(&v); + free(key); + return yes; +} + +int kvlangRwirextHandoff(void *kvspace, const char *vtid, const char *pc) { + kvlangKv_t k = {kvspace}; + char *fr = kvlangKeytreeFrameRoot(pc); + if (!fr) + return -1; + char *lb = kvlangKeytreeStack(fr); + kvlangRwirInst_t inst; + char err[256]; + if (kvlangRwirDecode(&k, lb, pc, &inst, err, sizeof err) != 0) { + free(fr); + free(lb); + return -1; + } + free(lb); + int rc = handoff_external_rwir(&k, vtid, pc, &inst); + free(fr); + kvlangRwirInstFree(&inst); + return rc; +} diff --git a/runtime/src/kv.c b/runtime/src/kvspace.c similarity index 100% rename from runtime/src/kv.c rename to runtime/src/kvspace.c diff --git a/runtime/src/myrwircaps.c b/runtime/src/myrwircaps.c new file mode 100644 index 00000000..f17bb381 --- /dev/null +++ b/runtime/src/myrwircaps.c @@ -0,0 +1,227 @@ +#include "runtime_internal.h" +#include "rwir_internal.h" +#include "kvlang_runtime.h" + +typedef int (*kvlangBuiltinFn)(kvlangFrame_t *f); + +/* 共享队列根:第一个 rwir 的 /lib//vids 绝对路径。 */ +static char *g_first_vids = NULL; + +/* 建立 rwir 的 vids 队列:第一个 rwir 是真实 strkeymap,后续是 Ptr 指向第一个。 + * 幂等:vids 已存在则跳过——否则脏 kvspace 上重复注册时,Set 经路径穿透会把首队列 + * 改成自指 Ptr,令 resolve_path 死循环(父子 kvlang 共享同一 redis 的挂起根因)。 */ +static void register_vids(kvlangKv_t *k, const char *opcode) { + char *base = kvlangKeytreeRwir(opcode); + kvlangStrbuf_t tk; + kvlangStrbufInit(&tk); + kvlangStrbufPuts(&tk, base); + kvlangStrbufPuts(&tk, "/vids"); + bool first = (g_first_vids == NULL); + if (first) + g_first_vids = strdup(tk.p); + kvlangXvalue_t cur; + kvlangXvalueZero(&cur); + bool exists = + (kvlangKvGetOne(k, tk.p, &cur) == 0 && !kvlangXvalueNone(&cur)); + kvlangXvalueFree(&cur); + if (!exists) { + kvlangXvalue_t v; + kvlangXvalueZero(&v); + int32_t dims[1] = {0}; + if (first) + kvlangXvalueNewTlvDims(&v, KVSPACE_KIND_MAP, (const uint8_t *)"", 0, + dims, 1); + else + kvlangXvalueNewPtr(&v, KVSPACE_KIND_MAP, g_first_vids); + kvlangKvPair_t p = {tk.p, v}; + char err[256]; + kvlangKvSet(k, &p, 1, err, sizeof err); + kvlangXvalueFree(&v); + } + kvlangStrbufFree(&tk); + free(base); +} + +/* 写 [0,x] 签名行槽 = def langtype(body 为该参数 langtype 串)。 */ +static void write_sig_slot(kvlangKv_t *k, const char *base, int x, + const char *lt, size_t lt_len) { + kvlangStrbuf_t sk; + kvlangStrbufInit(&sk); + kvlangStrbufPrintf(&sk, "%s/[0,%d]", base, x); + char *clean = strndup(lt, lt_len); + kvlangXvalue_t sv; + kvlangXvalueNewDefLangtype(&sv, clean); + free(clean); + kvlangKvPair_t sp = {sk.p, sv}; + char err[256]; + kvlangKvSet(k, &sp, 1, err, sizeof err); + kvlangXvalueFree(&sv); + kvlangStrbufFree(&sk); +} + +/* 注册一条 rwir:/lib/ 路由头(仅计数头)+ 各参数落 [0,x] 签名行槽(def langtype)。 + * 参数类型逐条传入(读参 rp[0..nr]、写参 wp[0..nw]),不再拼签名串——避免其它 runtime + * 把「拼接 sig 串」误当注册标准。末读参尾缀 "..." → 变参 arity(落 dynamic 字节)。 */ +int kvlangDefRwir(void *kvspace, const char *opcode, const char *const *rp, + int32_t nr, const char *const *wp, int32_t nw) { + kvlangKv_t k = {kvspace}; + char *base = kvlangKeytreeRwir(opcode); + char err[256]; + + int dynamic = 0; + size_t last_len = (nr > 0 && rp[nr - 1]) ? strlen(rp[nr - 1]) : 0; + if (nr > 0 && last_len >= 3 && + memcmp(rp[nr - 1] + last_len - 3, "...", 3) == 0) { + dynamic = 1; + last_len -= 3; + } + + kvlangXvalue_t hv; + kvlangXvalueNewDefRwir(&hv, nr, nw, dynamic); + kvlangKvPair_t hp = {base, hv}; + int rc = kvlangKvSet(&k, &hp, 1, err, sizeof err); + kvlangXvalueFree(&hv); + + for (int32_t i = 0; i < nr; i++) + write_sig_slot(&k, base, -(i + 1), rp[i], + (i == nr - 1) ? last_len : strlen(rp[i])); + for (int32_t i = 0; i < nw; i++) + write_sig_slot(&k, base, i + 1, wp[i], strlen(wp[i])); + + free(base); + /* 建立共享 vids 队列(第一个真实 strkeymap,后续 Ptr 指向它;幂等查 kvspace)。 */ + register_vids(&k, opcode); + return rc; +} + +/* 精度前缀(int64·add / float32·add …)保留:CapIndex 两级查表——先按完整 opcode 命中特化, + * 未命中且前缀是 C native 数字 kind 时才剥前缀归到裸 op(如 add),kvlangBuiltin* 按操作数 kind 归约。 */ +static int kvlangCtlCopy(kvlangFrame_t *f) { return kvlangBuiltinExecuteCopy(f->kv, f->vtid, f->pc, f->inst); } + +static const struct { const char *op; kvlangBuiltinFn fn; } myrwircaps[] = { + /* control / copy:与 native 算子同表,op_id 单跳派发 */ + {OP_CALL, kvlangCtlCall}, {OP_RETURN, kvlangCtlReturn}, {OP_GOTO, kvlangCtlGoto}, + {OP_BR, kvlangCtlBr}, {OP_COPY, kvlangCtlCopy}, + {"add", kvlangBuiltinAdd}, {"+", kvlangBuiltinAdd}, + {"sub", kvlangBuiltinSub}, {"-", kvlangBuiltinSub}, + {"mul", kvlangBuiltinMul}, {"×", kvlangBuiltinMul}, + {"div", kvlangBuiltinDiv}, {"÷", kvlangBuiltinDiv}, + {"mod", kvlangBuiltinMod}, {"%", kvlangBuiltinMod}, + {"eq", kvlangBuiltinEq}, {"==", kvlangBuiltinEq}, + {"neq", kvlangBuiltinNeq}, {"!=", kvlangBuiltinNeq}, {"≠", kvlangBuiltinNeq}, + {"lt", kvlangBuiltinLt}, {"<", kvlangBuiltinLt}, + {"gt", kvlangBuiltinGt}, {">", kvlangBuiltinGt}, + {"le", kvlangBuiltinLe}, {"<=", kvlangBuiltinLe}, {"≤", kvlangBuiltinLe}, + {"ge", kvlangBuiltinGe}, {">=", kvlangBuiltinGe}, {"≥", kvlangBuiltinGe}, + {"and", kvlangBuiltinAnd}, {"&&", kvlangBuiltinAnd}, + {"or", kvlangBuiltinOr}, {"||", kvlangBuiltinOr}, + {"not", kvlangBuiltinNot}, {"!", kvlangBuiltinNot}, + {"bitand", kvlangBuiltinBitand}, {"&", kvlangBuiltinBitand}, + {"bitor", kvlangBuiltinBitor}, {"|", kvlangBuiltinBitor}, + {"bitxor", kvlangBuiltinBitxor}, {"^", kvlangBuiltinBitxor}, + {"shl", kvlangBuiltinShl}, {"<<", kvlangBuiltinShl}, + {"shr", kvlangBuiltinShr}, {">>", kvlangBuiltinShr}, + {"pow", kvlangBuiltinPow}, + {"sqrt", kvlangBuiltinSqrt}, {"√", kvlangBuiltinSqrt}, + {"exp", kvlangBuiltinExp}, + {"log", kvlangBuiltinLog}, + {"neg", kvlangBuiltinNeg}, + {"abs", kvlangBuiltinAbs}, + {"sign", kvlangBuiltinSign}, + {"max", kvlangBuiltinMax}, {"min", kvlangBuiltinMin}, + /* cast */ + {"bool", kvlangBuiltinCastBool}, {"int8", kvlangBuiltinCastInt8}, {"int16", kvlangBuiltinCastInt16}, + {"int32", kvlangBuiltinCastInt32}, {"int64", kvlangBuiltinCastInt64}, {"uint8", kvlangBuiltinCastUint8}, + {"uint16", kvlangBuiltinCastUint16}, {"uint32", kvlangBuiltinCastUint32}, {"uint64", kvlangBuiltinCastUint64}, + {"float32", kvlangBuiltinCastF32}, {"float64", kvlangBuiltinCastF64}, + {"char/utf32", kvlangBuiltinCastChar32}, {"char/utf8", kvlangBuiltinCastChar8}, {"char/ascii", kvlangBuiltinCastCharAscii}, + /* collection */ + {"array", kvlangBuiltinArray}, {"array·fill", kvlangBuiltinArrayFill}, + {"array·scatter", kvlangBuiltinScatter}, {"array·compact", kvlangBuiltinCompact}, + {"array·append", kvlangBuiltinAppend}, {"array·slice", kvlangBuiltinSlice}, + {"obj", kvlangBuiltinObj}, {"map", kvlangBuiltinMap}, {"struct·new", kvlangBuiltinStructNew}, + {"ndarray·numel", kvlangBuiltinNdarrayNumel}, {"ndarray·dim", kvlangBuiltinNdarrayDim}, {"ndarray·shape", kvlangBuiltinNdarrayShape}, + {"xv·at", kvlangBuiltinXvAt}, {"xv·set", kvlangBuiltinXvSet}, {"xv·reshape", kvlangBuiltinXvReshape}, + {"xv·reinterpret", kvlangBuiltinXvReinterpret}, + {"xv·langtype", kvlangBuiltinXvLangtype}, {"xv·bodylen", kvlangBuiltinXvBodylen}, + {"string·set", kvlangBuiltinStringSet}, {"string·char", kvlangBuiltinStringChar}, {"string·ord", kvlangBuiltinStringOrd}, + {"string·cmp", kvlangBuiltinStringCmp}, {"string·find", kvlangBuiltinStringFind}, {"string·len", kvlangBuiltinStringLen}, + {"string·slice", kvlangBuiltinStringSlice}, {"string·concat", kvlangBuiltinStringConcat}, + {"string·formatint", kvlangBuiltinStringFormatInt}, {"string·formatuint", kvlangBuiltinStringFormatUint}, + {"string·parseint", kvlangBuiltinStringParseInt}, {"string·parseuint", kvlangBuiltinStringParseUint}, + {"time·now", kvlangBuiltinTimeNow}, {"time·sub", kvlangBuiltinTimeSub}, {"time·add", kvlangBuiltinTimeAdd}, + {"time/duration·nanos", kvlangBuiltinDurFrom}, {"time/duration·millis", kvlangBuiltinDurFrom}, + {"time/duration·seconds", kvlangBuiltinDurFrom}, {"time/duration·minutes", kvlangBuiltinDurFrom}, + {"time/duration·hours", kvlangBuiltinDurFrom}, + {"time/duration·as_nanos", kvlangBuiltinDurTo}, {"time/duration·as_millis", kvlangBuiltinDurTo}, + {"time/duration·as_seconds", kvlangBuiltinDurTo}, {"time/duration·as_minutes", kvlangBuiltinDurTo}, + {"time/duration·as_hours", kvlangBuiltinDurTo}, + {"time/duration·add", kvlangBuiltinDurArith}, {"time/duration·sub", kvlangBuiltinDurArith}, + {"time/duration·before", kvlangBuiltinDurCmp}, {"time/duration·after", kvlangBuiltinDurCmp}, + {"time·before", kvlangBuiltinTimeCmp}, {"time·after", kvlangBuiltinTimeCmp}, + {"random·uint64", kvlangBuiltinRandUint64}, {"random·int63", kvlangBuiltinRandInt63}, {"random·intn", kvlangBuiltinRandIntn}, + {"kvspace·get", kvlangCGet}, {"kvspace·set", kvlangCSet}, {"kvspace·del", kvlangCDel}, + {"kvspace·deltree", kvlangCDelTree}, {"kvspace·cp", kvlangCCp}, {"kvspace·cpdir", kvlangCCpTree}, {"kvspace·cplist", kvlangCCpList}, {"kvspace·list", kvlangCList}, {"kvspace·listlen", kvlangCListLen}, {"kvspace·listn", kvlangCListN}, {"kvspace·mkindex", kvlangCMkindex}, + {"kvspace·extindex", kvlangCExtIndex}, {"kvspace·rmindexext", kvlangCRmIndexExt}, {"kvspace·watch", kvlangCWatch}, {"kvlang·abs", kvlangCAbs}, + {"vthread·create", kvlangBuiltinVthreadCreate}, + {"vthread·run", kvlangBuiltinVthreadRun}, + {"vthread·call", kvlangBuiltinVthreadCall}, + {"vthread·sleep", kvlangBuiltinVthreadSleep}, + {"vthread·setstatus", kvlangBuiltinVthreadSetstatus}, + {"debugger", kvlangBuiltinDebugger}, +}; + +static const size_t myrwircaps_n = sizeof(myrwircaps) / sizeof(myrwircaps[0]); + +/* C 原生数值 langtype 集:仅这些精度的算术走 kvlangBuiltinAdd 等通用实现。 + * int4/fp8/bf16 等 C 表达不了的量化精度不在此列,其 ·op 走专精 fn 或 handoff。 */ +static const char *NUM_KINDS[] = {"int8", "int16", "int32", "int64", "uint8", + "uint16", "uint32", "uint64", "float32", "float64"}; +static bool is_num_kind_prefix(const char *op, size_t n) { + for (size_t i = 0; i < sizeof(NUM_KINDS) / sizeof(NUM_KINDS[0]); i++) + if (strlen(NUM_KINDS[i]) == n && strncmp(op, NUM_KINDS[i], n) == 0) return true; + return false; +} + +/* rwirtable 两级查找:先查完整 opcode(命中=专精实现,如 fp8·add,或 time·add 等成员算子), + * 未命中且末段前缀是 C 原生数值 langtype 才拆前缀查裸算子(int64·add → add,通用实现)。 + * 非数值前缀(time/duration·max 等用户 rwfunc)不剥离,两级皆 miss → 非本 runtime native。 */ +int kvlangBuiltinCapIndex(const char *opcode) { + for (size_t i = 0; i < myrwircaps_n; i++) + if (strcmp(myrwircaps[i].op, opcode) == 0) return (int)i; + const char *dot = strstr(opcode, MEMBER_SEP); + if (dot && is_num_kind_prefix(opcode, (size_t)(dot - opcode))) { + const char *bare = dot + MEMBER_SEP_LEN; + for (size_t i = 0; i < myrwircaps_n; i++) + if (strcmp(myrwircaps[i].op, bare) == 0) return (int)i; + } + return -1; +} + +/* notinmycaps:查 myrwircaps table。opcode 不在本 runtime 能力表内 → true + * (即须经 /lib/ 的 def rwir 路由给能兑现它的其它 runtime,或为用户 rwfunc)。 */ +bool notinmycaps(const char *opcode) { + return kvlangBuiltinCapIndex(opcode) < 0; +} + +bool kvlangBuiltinNumOp(const char *opcode) { + switch (opcode[0]) { + case 'a': return strcmp(opcode, "add") == 0 || strcmp(opcode, "abs") == 0; + case 'b': return strcmp(opcode, "bitand") == 0 || strcmp(opcode, "bitor") == 0 || strcmp(opcode, "bitxor") == 0; + case 'd': return strcmp(opcode, "div") == 0; + case 'e': return strcmp(opcode, "eq") == 0 || strcmp(opcode, "exp") == 0; + case 'g': return strcmp(opcode, "gt") == 0 || strcmp(opcode, "ge") == 0; + case 'l': return strcmp(opcode, "lt") == 0 || strcmp(opcode, "le") == 0 || strcmp(opcode, "log") == 0; + case 'm': return strcmp(opcode, "mod") == 0 || strcmp(opcode, "mul") == 0 || strcmp(opcode, "max") == 0 || strcmp(opcode, "min") == 0; + case 'n': return strcmp(opcode, "neq") == 0 || strcmp(opcode, "neg") == 0; + case 'p': return strcmp(opcode, "pow") == 0; + case 's': return strcmp(opcode, "sub") == 0 || strcmp(opcode, "sqrt") == 0 || strcmp(opcode, "shl") == 0 || strcmp(opcode, "shr") == 0 || strcmp(opcode, "sign") == 0; + } + return false; +} + +int kvlangBuiltinNative(kvlangFrame_t *f) { + int i = f->inst->op_id >= 0 ? f->inst->op_id : kvlangBuiltinCapIndex(f->inst->opcode); + if (i >= 0) return myrwircaps[i].fn(f); + return kvlangBuiltinSetErr(f, "unknown builtin op: %s", f->inst->opcode); +} diff --git a/runtime/src/runtime.c b/runtime/src/runtime.c index 7c958b03..3341406a 100644 --- a/runtime/src/runtime.c +++ b/runtime/src/runtime.c @@ -1,4 +1,4 @@ -#include "kvlang_runtime.h" +#include "kvlang_vthread.h" #include "runtime_internal.h" struct kvlangRuntime_t { diff --git a/runtime/src/runtime_internal.h b/runtime/src/runtime_internal.h index 6b132a7a..aafe0cd8 100644 --- a/runtime/src/runtime_internal.h +++ b/runtime/src/runtime_internal.h @@ -489,7 +489,7 @@ void kvlangBuiltinResolveReadValue(kvlangKv_t *kv, const char *frame_root, kvlangXvalue_t *out); char *kvlangBuiltinResolveWriteSlot(kvlangKv_t *kv, const char *frame_root, const char *name); -/* 成员写的 base 尚无值 → 落空 stringkeymap 值(`/lib` 下跳过,见 builtin_kv.c)。 */ +/* 成员写的 base 尚无值 → 落空 stringkeymap 值(`/lib` 下跳过,见 rwir_kv.c)。 */ /* 成员写(memitem)前置条件:memhead(base 容器值)必须已存在;缺则返回 -1 拒绝写入。 */ int kvlangBuiltinCheckMemhead(kvlangKv_t *kv, const char *frame_root, const char *base); diff --git a/runtime/src/rwir_array.c b/runtime/src/rwir_array.c new file mode 100644 index 00000000..68053af9 --- /dev/null +++ b/runtime/src/rwir_array.c @@ -0,0 +1,353 @@ +#include "rwir_internal.h" + +/* ── 数组打包 / 散 key 辅助 ──────────────────────────────────────── */ + +static void pack_typed_array(const char *kind, const kvlangXvalue_t *elems, + int n, kvlangXvalue_t *out) { + int sz = kvlangXvalueElemSize(kind); + uint8_t *raw = malloc((size_t)sz * (n > 0 ? n : 1)); + for (int i = 0; i < n; i++) { + const uint8_t *b; + int32_t blen; + kvspaceHead_t h; + kvspaceDecodeHead(elems[i].data, elems[i].len, &h); + b = elems[i].data + h.body_offset; + blen = h.body_len; + int c = blen < sz ? blen : sz; + memcpy(raw + i * sz, b, (size_t)c); + for (int j = c; j < sz; j++) + raw[i * sz + j] = 0; + } + kvlangXvalueNewTlv(out, kind, raw, (uint32_t)(sz * n), n); + free(raw); +} + +static int separated_len(kvlangKv_t *kv, const char *base) { + for (int i = 0;; i++) { + kvlangStrbuf_t k; + kvlangStrbufInit(&k); + kvlangStrbufPuts(&k, base); + kvlangStrbufPuts(&k, MEMBER_SEP); + kvlangStrbufPrintf(&k, "[%d]", i); + kvlangXvalue_t v; + kvlangXvalueZero(&v); + kvlangKvGetOne(kv, k.p, &v); + bool none = kvlangXvalueNone(&v); + kvlangXvalueFree(&v); + kvlangStrbufFree(&k); + if (none) + return i; + } +} + +/* 坐标段 key:base·[s0,s1,...]。1 维即 base·[s0]。 */ +char *kvlangBuiltinScatterKey(const char *base, const int64_t *coords, + int ncoord) { + kvlangStrbuf_t b; + kvlangStrbufInit(&b); + kvlangStrbufPuts(&b, base); + kvlangStrbufPuts(&b, MEMBER_SEP); + kvlangStrbufPutc(&b, '['); + for (int i = 0; i < ncoord; i++) { + if (i) + kvlangStrbufPutc(&b, ','); + kvlangStrbufPrintf(&b, "%lld", (long long)coords[i]); + } + kvlangStrbufPutc(&b, ']'); + return kvlangStrbufDetach(&b); +} + +static void ensure_scattered(kvlangFrame_t *f, const char *base) { + kvlangXvalue_t arr; + kvlangXvalueZero(&arr); + kvlangKvGetOne(f->kv, base, &arr); + if (kvlangXvalueNone(&arr) || + kvlangXvalueElemSize(kvlangXvalueKind(&arr)) <= 0) { + kvlangXvalueFree(&arr); + return; + } + int n = kvlangXvalueArrayLen(&arr); + for (int i = 0; i < n; i++) { + int64_t c[1] = {i}; + char *k = kvlangBuiltinScatterKey(base, c, 1); + kvlangXvalue_t e; + kvlangBuiltinXvalueAt(&arr, i, &e); + kvlangKvPair_t p = {k, e}; + char err[256]; + kvlangKvSet(f->kv, &p, 1, err, sizeof err); + kvlangXvalueFree(&e); + free(k); + } + kvlangXvalueFree(&arr); + char err[256]; + kvlangKvDel(f->kv, base, err, sizeof err); +} + +int kvlangBuiltinArray(kvlangFrame_t *f) { + kvlangXvalue_t in[64]; + int n = kvlangBuiltinReadInputs(f, in, 64); + if (f->inst->nw == 0 || n == 0) { + kvlangBuiltinNextPc(f); + kvlangBuiltinFreeInputs(in, n); + return 0; + } + const char *kind = kvlangXvalueKind(&in[0]); + if (kvlangXvalueElemSize(kind) <= 0) { + kvlangBuiltinFreeInputs(in, n); + return kvlangBuiltinSetErr(f, "array: unsupported element kind %s", + kind); + } + for (int i = 1; i < n; i++) + if (strcmp(kvlangXvalueKind(&in[i]), kind) != 0) { + kvlangBuiltinFreeInputs(in, n); + return kvlangBuiltinSetErr(f, "array: mixed kinds %s and %s", kind, + kvlangXvalueKind(&in[i])); + } + kvlangXvalue_t arr; + pack_typed_array(kind, in, n, &arr); + char *fr = kvlangKeytreeFrameRoot(f->pc); + char *key = + kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[0].name); + free(fr); + kvlangKvPair_t p = {key, arr}; + char err[256]; + kvlangKvSet(f->kv, &p, 1, err, sizeof err); + free(key); + kvlangXvalueFree(&arr); + kvlangBuiltinNextPc(f); + kvlangBuiltinFreeInputs(in, n); + return 0; +} + +/* array·fill(langtype[, value]) -> a:按 langtype 的定长维度一次成型 compact 数组, + * 每元素填 value(缺省全零)。用于大数组初始化,无需逐元素赋值。 */ +int kvlangBuiltinArrayFill(kvlangFrame_t *f) { + if (f->inst->nw == 0) + return kvlangBuiltinSetErr( + f, "TypeError: array.fill requires a write param (-> a)"); + kvlangXvalue_t in[2]; + int n = kvlangBuiltinReadInputs(f, in, 2); + if (n < 1) { + kvlangBuiltinFreeInputs(in, n); + return kvlangBuiltinSetErr(f, + "TypeError: array.fill requires a langtype"); + } + char *ke = kvlangXvalueValueString(&in[0]); + kvlangLangtype kx; + kvlangLangtypeParse((const uint8_t *)ke, &kx); + int sz = kvlangXvalueElemSize(kx.kind); + if (sz <= 0 || sz > 8 || kx.ndim < 1 || kx.array_len < 0) { + int rc = kvlangBuiltinSetErr( + f, "TypeError: array.fill: not a fixed-length array type %s", ke); + free(ke); + kvlangBuiltinFreeInputs(in, n); + return rc; + } + uint8_t elem[8] = {0}; + if (n >= 2 && !kvlangXvalueNone(&in[1])) { + kvlangScalar_t s = kvlangXvalueScalar(&in[1]); + int tid = kvlangLangTypeId(kx.kind, kx.kind_len); + if (tid == KVLANG_LT_FLOAT32) { + float v = (float)kvlangScalarF64(s); + memcpy(elem, &v, 4); + } else if (tid == KVLANG_LT_FLOAT64) { + double v = kvlangScalarF64(s); + memcpy(elem, &v, 8); + } else { + int64_t v = kvlangScalarI64(s); + memcpy(elem, &v, (size_t)sz); + } + } + size_t total = (size_t)sz * (size_t)kx.array_len; + uint8_t *raw = malloc(total > 0 ? total : 1); + for (int i = 0; i < kx.array_len; i++) + memcpy(raw + (size_t)i * sz, elem, (size_t)sz); + kvlangXvalue_t arr; + kvlangXvalueNewTlvDims(&arr, kx.kind, raw, (uint32_t)total, kx.dims, + kx.ndim); + free(raw); + int rc = kvlangBuiltinWriteResult(f, &arr); + kvlangXvalueFree(&arr); + free(ke); + kvlangBuiltinFreeInputs(in, n); + return rc; +} + +/* ── array· 系列 ────────────────────────────────────────────────── */ + +int kvlangBuiltinScatter(kvlangFrame_t *f) { + if (f->inst->nw == 0) + return kvlangBuiltinSetErr( + f, "TypeError: array.scatter requires a write param"); + kvlangXvalue_t in[2]; + int n = kvlangBuiltinReadInputs(f, in, 2); + if (n == 0 || kvlangXvalueNone(&in[0])) { + kvlangBuiltinNextPc(f); + kvlangBuiltinFreeInputs(in, n); + return 0; + } + if (kvlangXvalueElemSize(kvlangXvalueKind(&in[0])) <= 0) { + kvlangBuiltinFreeInputs(in, n); + return kvlangBuiltinSetErr( + f, + "TypeError: array.scatter requires a compact array ([]T), got %s", + kvlangXvalueKind(&in[0])); + } + char *fr = kvlangKeytreeFrameRoot(f->pc); + char *dst = + kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[0].name); + int al = kvlangXvalueArrayLen(&in[0]); + if (al > 0) { + char err[256]; + int32_t dims[1] = {al}; + /* 散 key 化的容器值类型:键是坐标段 `[i]`,值是原 compact 元素类型(逐元素原样搬)。 */ + char ty[256]; + snprintf(ty, sizeof ty, "[int64]%s%s", MEMBER_SEP, + kvlangXvalueKind(&in[0])); + kvlangXvalue_t mark; + kvlangBuiltinMapMarker(&mark, ty, dims, 1); + kvlangKvPair_t p0 = {dst, mark}; + kvlangKvSet(f->kv, &p0, 1, err, sizeof err); + kvlangXvalueFree(&mark); + } + for (int i = 0; i < al; i++) { + int64_t c[1] = {i}; + char *k = kvlangBuiltinScatterKey(dst, c, 1); + kvlangXvalue_t e; + kvlangBuiltinXvalueAt(&in[0], i, &e); + kvlangKvPair_t p = {k, e}; + char err[256]; + kvlangKvSet(f->kv, &p, 1, err, sizeof err); + kvlangXvalueFree(&e); + free(k); + } + free(dst); + free(fr); + kvlangBuiltinNextPc(f); + kvlangBuiltinFreeInputs(in, n); + return 0; +} + +int kvlangBuiltinCompact(kvlangFrame_t *f) { + if (f->inst->nr == 0 || f->inst->nw == 0) + return kvlangBuiltinSetErr( + f, "TypeError: array.compact requires read and write params"); + char *fr = kvlangKeytreeFrameRoot(f->pc); + char *src = + kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->reads[0].name); + kvlangXvalue_t elems[1024]; + int n = 0; + for (int i = 0;; i++) { + int64_t c[1] = {i}; + char *k = kvlangBuiltinScatterKey(src, c, 1); + kvlangXvalue_t v; + kvlangXvalueZero(&v); + kvlangKvGetOne(f->kv, k, &v); + bool none = kvlangXvalueNone(&v); + free(k); + if (none) + break; + elems[n++] = v; + } + if (n == 0) { + free(src); + free(fr); + kvlangBuiltinNextPc(f); + return 0; + } + kvlangXvalue_t arr; + pack_typed_array(kvlangXvalueKind(&elems[0]), elems, n, &arr); + char *dst = + kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[0].name); + kvlangKvPair_t p = {dst, arr}; + char err[256]; + kvlangKvSet(f->kv, &p, 1, err, sizeof err); + for (int i = 0; i < n; i++) + kvlangXvalueFree(&elems[i]); + kvlangXvalueFree(&arr); + free(dst); + free(src); + free(fr); + kvlangBuiltinNextPc(f); + return 0; +} + +int kvlangBuiltinAppend(kvlangFrame_t *f) { + if (f->inst->nr < 2) + return kvlangBuiltinSetErr( + f, "TypeError: array.append requires array and element"); + if (f->inst->nw == 0) + return kvlangBuiltinSetErr( + f, "TypeError: array.append requires a write param (-> arr)"); + kvlangXvalue_t in[2]; + int n = kvlangBuiltinReadInputs(f, in, 2); + char *fr = kvlangKeytreeFrameRoot(f->pc); + char *base = + kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[0].name); + ensure_scattered(f, base); + int len = separated_len(f->kv, base); + int64_t c[1] = {len}; + char *k = kvlangBuiltinScatterKey(base, c, 1); + kvlangKvPair_t p = {k, n >= 2 ? in[1] : in[0]}; + char err[256]; + kvlangKvSet(f->kv, &p, 1, err, sizeof err); + free(k); + free(base); + free(fr); + kvlangBuiltinNextPc(f); + kvlangBuiltinFreeInputs(in, n); + return 0; +} + +int kvlangBuiltinSlice(kvlangFrame_t *f) { + if (f->inst->nr < 3) + return kvlangBuiltinSetErr( + f, "TypeError: array.slice requires array, start, end"); + if (f->inst->nw == 0) + return kvlangBuiltinSetErr( + f, "TypeError: array.slice requires a write param (-> arr)"); + kvlangXvalue_t in[3]; + int n = kvlangBuiltinReadInputs(f, in, 3); + char *fr = kvlangKeytreeFrameRoot(f->pc); + char *base = + kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[0].name); + ensure_scattered(f, base); + int al = separated_len(f->kv, base); + int lo = (int)kvlangScalarI64(kvlangXvalueScalar(&in[1])), + hi = (int)kvlangScalarI64(kvlangXvalueScalar(&in[2])); + if (lo < 0 || hi < lo || hi > al) { + free(base); + free(fr); + kvlangBuiltinFreeInputs(in, n); + return kvlangBuiltinSetErr( + f, "IndexError: array.slice: bounds [%d:%d] out of range (len=%d)", + lo, hi, al); + } + for (int i = lo; i < hi; i++) { + int64_t sc[1] = {i}, dc[1] = {i - lo}; + char *sk = kvlangBuiltinScatterKey(base, sc, 1); + kvlangXvalue_t v; + kvlangXvalueZero(&v); + kvlangKvGetOne(f->kv, sk, &v); + char *dk = kvlangBuiltinScatterKey(base, dc, 1); + kvlangKvPair_t p = {dk, v}; + char err[256]; + kvlangKvSet(f->kv, &p, 1, err, sizeof err); + kvlangXvalueFree(&v); + free(sk); + free(dk); + } + for (int i = hi - lo; i < al; i++) { + int64_t dc[1] = {i}; + char *dk = kvlangBuiltinScatterKey(base, dc, 1); + char err[256]; + kvlangKvDel(f->kv, dk, err, sizeof err); + free(dk); + } + free(base); + free(fr); + kvlangBuiltinNextPc(f); + kvlangBuiltinFreeInputs(in, n); + return 0; +} + diff --git a/runtime/src/rwir_bool.c b/runtime/src/rwir_bool.c new file mode 100644 index 00000000..b0d0e308 --- /dev/null +++ b/runtime/src/rwir_bool.c @@ -0,0 +1,96 @@ +#include "runtime_internal.h" +#include "rwir_internal.h" + +/* ── 比较 / 逻辑 ──────────────────────────────────────────── */ + +typedef enum { CMP_EQ, CMP_NEQ, CMP_LT, CMP_GT, CMP_LE, CMP_GE } cmp_op; + +static int kvlangBuiltinCmp(kvlangFrame_t *f, cmp_op op) { + kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); + if (n < 2) { kvlangBuiltinSetErr(f, "TypeError: binary op requires 2 inputs, got %d", n); kvlangBuiltinFreeInputs(in, n); return -1; } + bool allow_null = (op == CMP_EQ || op == CMP_NEQ); + if (kvlangXvalueNone(&in[0]) || kvlangXvalueNone(&in[1])) { + if (!allow_null) { kvlangBuiltinSetErr(f, "TypeError: None in comparison"); kvlangBuiltinFreeInputs(in, n); return -1; } + bool eq = kvlangXvalueNone(&in[0]) == kvlangXvalueNone(&in[1]); + bool r = (op == CMP_EQ) ? eq : (op == CMP_NEQ) ? !eq : false; + kvlangXvalue_t rv; kvlangXvalueNewBool(&rv, r); + int rc = kvlangBuiltinWriteResult(f, &rv); kvlangXvalueFree(&rv); kvlangBuiltinFreeInputs(in, n); return rc; + } + bool r; + kvlangScalar_t a = kvlangXvalueScalar(&in[0]), b = kvlangXvalueScalar(&in[1]); + if (kvlangLtIsInt(a.id) && kvlangLtIsInt(b.id)) { + int c = cmp_int(a, b); + r = op == CMP_EQ ? c == 0 : op == CMP_NEQ ? c != 0 : op == CMP_LT ? c < 0 : op == CMP_GT ? c > 0 : op == CMP_LE ? c <= 0 : c >= 0; + } else if (kvlangLtIsNum(a.id) && kvlangLtIsNum(b.id)) { + double av = kvlangScalarF64(a), bv = kvlangScalarF64(b); + r = op == CMP_EQ ? av == bv : op == CMP_NEQ ? av != bv : op == CMP_LT ? av < bv : op == CMP_GT ? av > bv : op == CMP_LE ? av <= bv : av >= bv; + } else if (kvlangLtIsChar(a.id) && kvlangLtIsChar(b.id)) { + char *as = kvlangXvalueValueString(&in[0]), *bs = kvlangXvalueValueString(&in[1]); + int c = strcmp(as, bs); + r = op == CMP_EQ ? c == 0 : op == CMP_NEQ ? c != 0 : op == CMP_LT ? c < 0 : op == CMP_GT ? c > 0 : op == CMP_LE ? c <= 0 : c >= 0; + free(as); free(bs); + } else if (a.id == KVLANG_LT_BOOL && b.id == KVLANG_LT_BOOL) { + bool av = kvlangScalarI64(a) != 0, bv = kvlangScalarI64(b) != 0; + r = op == CMP_EQ ? av == bv : op == CMP_NEQ ? av != bv : op == CMP_LT ? av < bv : op == CMP_GT ? av > bv : op == CMP_LE ? av <= bv : av >= bv; + } else if (kvlangXvalueIsPtr(&in[0]) || kvlangXvalueIsPtr(&in[1])) { + // 指针比较恒判身份(target 串),且只允许 Ptr 对 Ptr——空指针即 None,已在上方 + // None 分支处理;不设 char 哨兵(`p == ""` 是非法比较,正是被砍掉的歧义分支)。 + if (op != CMP_EQ && op != CMP_NEQ) { + kvlangBuiltinSetErr(f, "TypeError: cannot order ptr with %s", kvlangXvalueKind(&in[0])); kvlangBuiltinFreeInputs(in, n); return -1; + } + if (!kvlangXvalueIsPtr(&in[0]) || !kvlangXvalueIsPtr(&in[1])) { + kvlangBuiltinSetErr(f, "TypeError: cannot compare %s with ptr; use None for a null pointer", + kvlangXvalueIsPtr(&in[0]) ? kvlangXvalueKind(&in[1]) : kvlangXvalueKind(&in[0])); + kvlangBuiltinFreeInputs(in, n); return -1; + } + char *as = kvlangXvaluePtrTarget(&in[0]); + char *bs = kvlangXvaluePtrTarget(&in[1]); + int c = strcmp(as, bs); + r = op == CMP_EQ ? c == 0 : c != 0; + free(as); free(bs); + } else { + kvlangBuiltinSetErr(f, "TypeError: cannot compare %s with %s", kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[1])); kvlangBuiltinFreeInputs(in, n); return -1; + } + kvlangXvalue_t rv; kvlangXvalueNewBool(&rv, r); + int rc = kvlangBuiltinWriteResult(f, &rv); kvlangXvalueFree(&rv); kvlangBuiltinFreeInputs(in, n); + return rc; +} + +int kvlangBuiltinEq(kvlangFrame_t *f) { return kvlangBuiltinCmp(f, CMP_EQ); } +int kvlangBuiltinNeq(kvlangFrame_t *f) { return kvlangBuiltinCmp(f, CMP_NEQ); } +int kvlangBuiltinLt(kvlangFrame_t *f) { return kvlangBuiltinCmp(f, CMP_LT); } +int kvlangBuiltinGt(kvlangFrame_t *f) { return kvlangBuiltinCmp(f, CMP_GT); } +int kvlangBuiltinLe(kvlangFrame_t *f) { return kvlangBuiltinCmp(f, CMP_LE); } +int kvlangBuiltinGe(kvlangFrame_t *f) { return kvlangBuiltinCmp(f, CMP_GE); } + +static bool require_bool(kvlangFrame_t *f, const char *op, kvlangXvalue_t *in, int n, int want) { + if (n < want) return false; + for (int i = 0; i < want; i++) { + if (!kvlangXvalueKindIs(&in[i], KVSPACE_KIND_BOOL)) { + kvlangBuiltinSetErr(f, "TypeError: %s requires bool, got %s", op, kvlangXvalueKind(&in[i])); + return false; + } + } + return true; +} +int kvlangBuiltinAnd(kvlangFrame_t *f) { + kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); + if (!require_bool(f, "&&", in, n, 2)) { kvlangBuiltinFreeInputs(in, n); return -1; } + kvlangXvalue_t r; kvlangXvalueNewBool(&r, kvlangScalarI64(kvlangXvalueScalar(&in[0])) != 0 && kvlangScalarI64(kvlangXvalueScalar(&in[1])) != 0); + int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); + return rc; +} +int kvlangBuiltinOr(kvlangFrame_t *f) { + kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); + if (!require_bool(f, "||", in, n, 2)) { kvlangBuiltinFreeInputs(in, n); return -1; } + kvlangXvalue_t r; kvlangXvalueNewBool(&r, kvlangScalarI64(kvlangXvalueScalar(&in[0])) != 0 || kvlangScalarI64(kvlangXvalueScalar(&in[1])) != 0); + int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); + return rc; +} +int kvlangBuiltinNot(kvlangFrame_t *f) { + kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); + if (!require_bool(f, "!", in, n, 1)) { kvlangBuiltinFreeInputs(in, n); return -1; } + kvlangXvalue_t r; kvlangXvalueNewBool(&r, kvlangScalarI64(kvlangXvalueScalar(&in[0])) == 0); + int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); + return rc; +} diff --git a/runtime/src/rwir.c b/runtime/src/rwir_decode.c similarity index 100% rename from runtime/src/rwir.c rename to runtime/src/rwir_decode.c diff --git a/runtime/src/rwir_func.c b/runtime/src/rwir_func.c new file mode 100644 index 00000000..b4dfe25f --- /dev/null +++ b/runtime/src/rwir_func.c @@ -0,0 +1,223 @@ +#include "runtime_internal.h" +#include "rwir_internal.h" + +/* ── resolve ───────────────────────────────────────────────────────── */ +/* #116 后 if/while 不再建 scope 帧,当前帧 [d] 即 rwfunc 帧,frame_root 直接可用。 */ + +void kvlangBuiltinResolveReadValue(kvlangKv_t *kv, const char *frame_root, const char *name, + const kvlangXvalue_t *val, kvlangXvalue_t *out) { + kvlangXvalueZero(out); + if (val && !kvlangXvalueNone(val) && !kvlangXvalueKindIs(val, KVSPACE_KIND_RWIR) && !kvlangXvalueKindIs(val, KVSPACE_KIND_RWFUNC)) { + out->data = val->data; /* 借指令内冻结字面量(生命周期同 decode 缓存,永不 flush/free) */ + out->len = val->len; + out->borrowed = 1; + return; + } + if (!name || !name[0]) return; + if (name[0] == '/') { kvlangKvGetOne(kv, name, out); return; } + if (name[0] == '*') { + /* 显式解引用:*[0,±k] → 读 frame_root/[0,±k](ref=1 Ptr)→ 解引用到实参值。 + * 同 ResolveWriteSlot:帧槽必有 Ptr,读不到即传参链路已坏 → panic, + * 绝不静默留 None(那会让形参读成空值,把真因藏到几层之外)。 */ + char *stk = kvlangKeytreeStack(frame_root); + kvlangXvalue_t pv; kvlangXvalueZero(&pv); + kvlangKvGetMember(kv, stk, name + 1, &pv); + if (!kvlangXvalueIsPtr(&pv)) { + fprintf(stderr, "panic: %s%s is not a Ptr — frame slot missing, param passing broken\n", stk, name + 1); + abort(); + } + char *target = kvlangXvaluePtrTarget(&pv); + kvlangKvGetOne(kv, target, out); + free(target); + kvlangXvalueFree(&pv); free(stk); + return; + } + char *stk = kvlangKeytreeStack(frame_root); + kvlangXvalue_t pv; kvlangXvalueZero(&pv); + kvlangKvGetMember(kv, stk, name, &pv); + if (kvlangXvalueIsPtr(&pv)) { + /* 数据 Ptr(&x):地址值本体,读值不解引用。成员访问另走 kvspace·get 的 member_path。 */ + *out = pv; pv.data = NULL; pv.len = 0; + } else if (!kvlangXvalueNone(&pv)) { + *out = pv; pv.data = NULL; pv.len = 0; + } + kvlangXvalueFree(&pv); free(stk); +} + +/* 读参 → 其最终存储键(malloc):字面量(指令内冻结的具体值,无后端槽)返 NULL; + * 变量则复用 ResolveWriteSlot——读侧最终槽键与写侧同一路径(普通成员=stk+name, + * ptr 追链到最终目标),供 xv 系列对 key 直发 GetHead/GetPart/SetPart 做分片读写。 */ +char *kvlangBuiltinResolveReadKey(kvlangKv_t *kv, const char *frame_root, const char *name, + const kvlangXvalue_t *val) { + if (val && !kvlangXvalueNone(val) && !kvlangXvalueKindIs(val, KVSPACE_KIND_RWIR) && !kvlangXvalueKindIs(val, KVSPACE_KIND_RWFUNC)) + return NULL; + if (!name || !name[0]) return NULL; + return kvlangBuiltinResolveWriteSlot(kv, frame_root, name); +} + +char *kvlangBuiltinResolveWriteSlot(kvlangKv_t *kv, const char *frame_root, const char *name) { + if (name[0] == '/') return strdup(name); + char *stk = kvlangKeytreeStack(frame_root); + if (name[0] == '*') { + /* 显式解引用:*[0,±k] → 读 frame_root/[0,±k](ref=1 Ptr)→ target=写槽路径。 + * `*[0,±k]` 是 layout 编译期生成的形参引用,帧槽必有调用点写入的 Ptr;读不到 + * 即传参链路已坏(不变量违反,非用户错误)→ panic,绝不回退成字面路径—— + * 回退会把「写形参」静默变成「写一个叫 *[0,±k] 的键」,掩盖真因。 */ + kvlangXvalue_t pv; kvlangXvalueZero(&pv); + kvlangKvGetMember(kv, stk, name + 1, &pv); + if (!kvlangXvalueIsPtr(&pv)) { + fprintf(stderr, "panic: %s%s is not a Ptr — frame slot missing, param passing broken\n", stk, name + 1); + abort(); + } + char *target = kvlangXvaluePtrTarget(&pv); + kvlangXvalueFree(&pv); free(stk); + return target; + } + kvlangStrbuf_t o; kvlangStrbufInit(&o); + kvlangStrbufPuts(&o, stk); kvlangStrbufPuts(&o, name); + free(stk); + return kvlangStrbufDetach(&o); +} + +/* ── coerce / kvlangDisplay ─────────────────────────────────────────────── */ + +static bool try_parse_int(const char *s, int64_t *out) { + if (!s || !s[0]) return false; + char *end; long long v = strtoll(s, &end, 10); + if (end == s || *end != 0) return false; + *out = v; return true; +} + +bool kvlangBuiltinTryParseNumber(const char *s, kvlangXvalue_t *out) { + kvlangXvalueZero(out); + if (!s || !s[0]) return false; + char c0 = s[0]; + bool num = (c0 >= '0' && c0 <= '9') || (c0 == '-' && s[1] >= '0' && s[1] <= '9'); + if (!num) return false; + int64_t iv; + if (try_parse_int(s, &iv)) { kvlangXvalueNewInt64(out, iv); return true; } + if (c0 != '-' && !strpbrk(s, ".eE")) { + char *end; unsigned long long uv = strtoull(s, &end, 10); + if (end != s && *end == 0) { + uint8_t r[8]; memcpy(r, &uv, 8); + kvlangXvalueNewTlv(out, KVSPACE_KIND_UINT64, r, 8, 1); return true; + } + } + char *end; double f = strtod(s, &end); + if (end != s && *end == 0) { kvlangXvalueNewFloat64(out, f); return true; } + return false; +} + +void kvlangBuiltinXvalueAt(const kvlangXvalue_t *v, int i, kvlangXvalue_t *out) { + kvlangXvalueZero(out); + int n = kvlangXvalueArrayLen(v); + if (i < 0 || i >= n) return; + const char *k = kvlangXvalueKind(v); + int sz = kvlangXvalueElemSize(k); + if (sz <= 0) return; + kvspaceHead_t h; kvspaceDecodeHead(v->data, v->len, &h); + const uint8_t *body = v->data + h.body_offset; + kvlangXvalueNewTlv(out, k, body + i * sz, (uint32_t)sz, 1); +} + +void kvlangDisplay(const kvlangXvalue_t *v, char **out); + +static void format_array(const kvlangXvalue_t *v, char **out) { + int n = kvlangXvalueArrayLen(v); + kvlangStrbuf_t b; kvlangStrbufInit(&b); + kvlangStrbufPutc(&b, '['); + for (int i = 0; i < n; i++) { + if (i) kvlangStrbufPuts(&b, ", "); + kvlangXvalue_t e; kvlangBuiltinXvalueAt(v, i, &e); + char *s; kvlangDisplay(&e, &s); + kvlangStrbufPuts(&b, s); free(s); kvlangXvalueFree(&e); + } + kvlangStrbufPutc(&b, ']'); + *out = kvlangStrbufDetach(&b); +} + +void kvlangDisplay(const kvlangXvalue_t *v, char **out) { + if (kvlangXvalueIsCharKind(kvlangXvalueKind(v))) { *out = kvlangXvalueValueString(v); return; } + if (kvlangXvalueArrayLen(v) > 1) { format_array(v, out); return; } + *out = kvlangXvalueValueString(v); +} + +/* ── frame helper ─────────────────────────────────────────────────── */ + +int kvlangBuiltinReadInputs(kvlangFrame_t *f, kvlangXvalue_t *out, int cap) { + char *fr = kvlangKeytreeFrameRoot(f->pc); + int n = 0; + for (int i = 0; i < f->inst->nr && n < cap; i++) { + kvlangBuiltinResolveReadValue(f->kv, fr, f->inst->reads[i].name, &f->inst->reads[i].val, &out[n]); + n++; + } + free(fr); + return n; +} + +void kvlangBuiltinFreeInputs(kvlangXvalue_t *in, int n) { for (int i = 0; i < n; i++) kvlangXvalueFree(&in[i]); } + +void kvlangBuiltinNextPc(kvlangFrame_t *f) { + kvlangStrbuf_t npc; kvlangStrbufInit(&npc); + kvlangRwirNextPc(f->pc, &npc); + kvlangVthreadSet(f->kv, f->vtid, npc.p, "running"); + kvlangStrbufFree(&npc); +} + +int kvlangBuiltinWriteResult(kvlangFrame_t *f, const kvlangXvalue_t *result) { + if (f->inst->nw > 0) { + char *fr = kvlangKeytreeFrameRoot(f->pc); + char *key = kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[0].name); + free(fr); + kvlangKvPair_t pair = { key, *result }; + char err[256]; + kvlangKvSet(f->kv, &pair, 1, err, sizeof err); + free(key); + } + kvlangBuiltinNextPc(f); + return 0; +} + +int kvlangBuiltinSetErr(kvlangFrame_t *f, const char *fmt, ...) { + char msg[512]; + va_list ap; va_start(ap, fmt); + vsnprintf(msg, sizeof msg, fmt, ap); + va_end(ap); + kvlangVthreadSetError(f->kv, f->vtid, f->pc, msg); + return -1; +} + +int kvlangBuiltinExecuteCopy(kvlangKv_t *kv, const char *vtid, const char *pc, kvlangRwirInst_t *inst) { + char *fr = kvlangKeytreeFrameRoot(pc); + kvlangFrame_t f = { kv, vtid, pc, inst }; + if (inst->nr == 0) { free(fr); kvlangBuiltinNextPc(&f); return 0; } + kvlangXvalue_t v; kvlangXvalueZero(&v); + kvlangBuiltinResolveReadValue(kv, fr, inst->reads[0].name, &inst->reads[0].val, &v); + for (int i = 0; i < inst->nw; i++) { + const char *slot = inst->writes[i].name; + const char *dot = strstr(slot, MEMBER_SEP); + if (dot && dot != slot) { + /* 成员写前置条件:memhead 必须已存在(同 kvspace·set,见 rwir_kv.c)。 */ + char *b = strndup(slot, (size_t)(dot - slot)); + int ok = kvlangBuiltinCheckMemhead(kv, fr, b); + char msg[320]; + if (ok != 0) + snprintf(msg, sizeof msg, "TypeError: memhead %s does not exist — declare the container first (e.g. `%s:T = {}`)", b, b); + free(b); + if (ok != 0) { + kvlangXvalueFree(&v); free(fr); + kvlangVthreadSetError(kv, vtid, pc, msg); + return -1; + } + } + char *key = kvlangBuiltinResolveWriteSlot(kv, fr, slot); + kvlangKvPair_t pair = { key, v }; + char err[256]; + kvlangKvSet(kv, &pair, 1, err, sizeof err); + free(key); + } + kvlangXvalueFree(&v); + free(fr); + kvlangBuiltinNextPc(&f); + return 0; +} diff --git a/runtime/src/rwir_int.c b/runtime/src/rwir_int.c new file mode 100644 index 00000000..b51502bf --- /dev/null +++ b/runtime/src/rwir_int.c @@ -0,0 +1,269 @@ +#include "runtime_internal.h" +#include "rwir_internal.h" +#include + +/* ── 类型 helper ─────────────────────────────────────────────── */ + +/* ── 类型 helper:全经 langtype id + 标量 0copy 视图,热路径零 strcmp、每值只 decode 一次 ── */ + +static const kvlangScalar_t SCALAR_NONE = { KVLANG_LT_NONE, NULL, 0 }; + +/* 两操作数结果整型 id(对齐旧 wider_int_kind:同号取宽者,异号升一档有符号)。 */ +static int wider_int_id(int a, int b) { + int aw = kvlangLtIntWidth(a), bw = kvlangLtIntWidth(b); + bool au = kvlangLtIsUint(a), bu = kvlangLtIsUint(b); + if (au == bu) { + int w = aw >= bw ? aw : bw; + int off = w == 8 ? 0 : w == 16 ? 1 : w == 32 ? 2 : 3; + return (au ? KVLANG_LT_UINT8 : KVLANG_LT_INT8) + off; + } + int w = aw > bw ? aw : bw; + return w <= 8 ? KVLANG_LT_INT16 : w == 16 ? KVLANG_LT_INT32 : KVLANG_LT_INT64; +} + +static int wider_float_id(int a, int b) { + if (a == KVLANG_LT_FLOAT64 || b == KVLANG_LT_FLOAT64) return KVLANG_LT_FLOAT64; + if (a == KVLANG_LT_FLOAT32 || b == KVLANG_LT_FLOAT32) return KVLANG_LT_FLOAT32; + return KVLANG_LT_FLOAT64; +} + +static void narrow_int(int a, int b, int64_t v, kvlangXvalue_t *out) { + int k = wider_int_id(a, b); + const char *kind = kvlangLangTypeKind(k); + switch (k) { + case KVLANG_LT_INT8: { int8_t x = (int8_t)v; kvlangXvalueNewTlv(out, kind, (uint8_t *)&x, 1, 1); return; } + case KVLANG_LT_INT16: { int16_t x = (int16_t)v; uint8_t r[2] = { x & 0xFF, (x >> 8) & 0xFF }; kvlangXvalueNewTlv(out, kind, r, 2, 1); return; } + case KVLANG_LT_INT32: { int32_t x = (int32_t)v; uint8_t r[4]; memcpy(r, &x, 4); kvlangXvalueNewTlv(out, kind, r, 4, 1); return; } + case KVLANG_LT_UINT8: { uint8_t x = (uint8_t)v; kvlangXvalueNewTlv(out, kind, &x, 1, 1); return; } + case KVLANG_LT_UINT16: { uint16_t x = (uint16_t)v; uint8_t r[2] = { x & 0xFF, (x >> 8) & 0xFF }; kvlangXvalueNewTlv(out, kind, r, 2, 1); return; } + case KVLANG_LT_UINT32: { uint32_t x = (uint32_t)v; uint8_t r[4]; memcpy(r, &x, 4); kvlangXvalueNewTlv(out, kind, r, 4, 1); return; } + case KVLANG_LT_UINT64: { uint64_t x = (uint64_t)v; uint8_t r[8]; memcpy(r, &x, 8); kvlangXvalueNewTlv(out, kind, r, 8, 1); return; } + default: kvlangXvalueNewInt64(out, v); return; /* INT64 */ + } +} + +static void narrow_float(int a, int b, double v, kvlangXvalue_t *out) { + if (wider_float_id(a, b) == KVLANG_LT_FLOAT32) { + float f = (float)v; uint8_t r[4]; memcpy(r, &f, 4); + kvlangXvalueNewTlv(out, KVSPACE_KIND_FLOAT32, r, 4, 1); + } else kvlangXvalueNewFloat64(out, v); +} + +int cmp_int(kvlangScalar_t a, kvlangScalar_t b) { + bool au = kvlangLtIsUint(a.id), bu = kvlangLtIsUint(b.id); + if (!au && !bu) { int64_t ai = kvlangScalarI64(a), bi = kvlangScalarI64(b); return ai < bi ? -1 : ai > bi ? 1 : 0; } + if (au && bu) { uint64_t x = kvlangScalarU64(a), y = kvlangScalarU64(b); return x < y ? -1 : x > y ? 1 : 0; } + if (au && !bu) { int64_t bi = kvlangScalarI64(b); if (bi < 0) return 1; uint64_t x = kvlangScalarU64(a); return x < (uint64_t)bi ? -1 : x > (uint64_t)bi ? 1 : 0; } + int64_t ai = kvlangScalarI64(a); if (ai < 0) return -1; uint64_t y = kvlangScalarU64(b); + return (uint64_t)ai < y ? -1 : (uint64_t)ai > y ? 1 : 0; +} + +/* ── 算术算子 ─────────────────────────────────────────────── */ + +/* ── 数值算子 ─────────────────────────────────────────────────────── */ + +int kvlangBuiltinAdd(kvlangFrame_t *f) { + kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); + kvlangScalar_t a = kvlangXvalueScalar(&in[0]), b = n >= 2 ? kvlangXvalueScalar(&in[1]) : SCALAR_NONE; + int rc; + if (n == 2 && kvlangLtIsChar(a.id) && kvlangLtIsChar(b.id)) { + kvlangXvalue_t r; + if (kvlangBuiltinCharConcat(&in[0], &in[1], &r)) { + rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); + } else rc = kvlangBuiltinSetErr(f, "TypeError: cannot concat %s with %s; convert encoding explicitly (char/utf8|char/utf32|char/ascii)", kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[1])); + } else if (n >= 2 && kvlangLtIsNum(a.id) && kvlangLtIsNum(b.id)) { + kvlangXvalue_t r; + if (kvlangLtIsInt(a.id) && kvlangLtIsInt(b.id)) narrow_int(a.id, b.id, kvlangScalarI64(a) + kvlangScalarI64(b), &r); + else narrow_float(a.id, b.id, kvlangScalarF64(a) + kvlangScalarF64(b), &r); + rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); + } else rc = kvlangBuiltinSetErr(f, "TypeError: expected numeric, got %s", n ? kvlangXvalueKind(&in[0]) : "none"); + kvlangBuiltinFreeInputs(in, n); + return rc; +} + +int kvlangBuiltinSub(kvlangFrame_t *f) { + kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); + kvlangScalar_t a = kvlangXvalueScalar(&in[0]), b = n >= 2 ? kvlangXvalueScalar(&in[1]) : SCALAR_NONE; + int rc; + if (n == 1) { + kvlangXvalue_t r; kvlangXvalueNewInt64(&r, -kvlangScalarI64(a)); + rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); + } else if (n >= 2 && kvlangLtIsInt(a.id) && kvlangLtIsInt(b.id)) { + kvlangXvalue_t r; narrow_int(a.id, b.id, kvlangScalarI64(a) - kvlangScalarI64(b), &r); + rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); + } else if (n >= 2 && kvlangLtIsNum(a.id) && kvlangLtIsNum(b.id)) { + kvlangXvalue_t r; narrow_float(a.id, b.id, kvlangScalarF64(a) - kvlangScalarF64(b), &r); + rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); + } else rc = kvlangBuiltinSetErr(f, "TypeError: expected numeric, got %s", n ? kvlangXvalueKind(&in[0]) : "none"); + kvlangBuiltinFreeInputs(in, n); + return rc; +} + +int kvlangBuiltinMul(kvlangFrame_t *f) { + kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); + kvlangScalar_t a = kvlangXvalueScalar(&in[0]), b = n >= 2 ? kvlangXvalueScalar(&in[1]) : SCALAR_NONE; + int rc; + if (n >= 2 && kvlangLtIsInt(a.id) && kvlangLtIsInt(b.id)) { + kvlangXvalue_t r; narrow_int(a.id, b.id, kvlangScalarI64(a) * kvlangScalarI64(b), &r); + rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); + } else if (n >= 2 && kvlangLtIsNum(a.id) && kvlangLtIsNum(b.id)) { + kvlangXvalue_t r; narrow_float(a.id, b.id, kvlangScalarF64(a) * kvlangScalarF64(b), &r); + rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); + } else rc = kvlangBuiltinSetErr(f, "TypeError: expected numeric, got %s", n ? kvlangXvalueKind(&in[0]) : "none"); + kvlangBuiltinFreeInputs(in, n); + return rc; +} + +int kvlangBuiltinDiv(kvlangFrame_t *f) { + kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); + kvlangScalar_t a = kvlangXvalueScalar(&in[0]), b = n >= 2 ? kvlangXvalueScalar(&in[1]) : SCALAR_NONE; + int rc; + if (n < 2) { rc = kvlangBuiltinSetErr(f, "TypeError: binary op requires 2 inputs, got %d", n); kvlangBuiltinFreeInputs(in, n); return rc; } + if (kvlangScalarF64(b) == 0) { rc = kvlangBuiltinSetErr(f, "ZeroDivisionError: division by zero"); kvlangBuiltinFreeInputs(in, n); return rc; } + if (kvlangLtIsInt(a.id) && kvlangLtIsInt(b.id)) { + kvlangXvalue_t r; narrow_int(a.id, b.id, kvlangScalarI64(a) / kvlangScalarI64(b), &r); + rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); + } else { + kvlangXvalue_t r; narrow_float(a.id, b.id, kvlangScalarF64(a) / kvlangScalarF64(b), &r); + rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); + } + kvlangBuiltinFreeInputs(in, n); + return rc; +} + +int kvlangBuiltinMod(kvlangFrame_t *f) { + kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); + kvlangScalar_t a = kvlangXvalueScalar(&in[0]), b = n >= 2 ? kvlangXvalueScalar(&in[1]) : SCALAR_NONE; + int rc; + if (n < 2 || !kvlangLtIsInt(a.id) || !kvlangLtIsInt(b.id)) { + rc = kvlangBuiltinSetErr(f, "TypeError: expected integer, got %s", n ? kvlangXvalueKind(&in[0]) : "none"); + kvlangBuiltinFreeInputs(in, n); return rc; + } + int64_t bv = kvlangScalarI64(b); + if (bv == 0) { rc = kvlangBuiltinSetErr(f, "ZeroDivisionError: modulo by zero"); kvlangBuiltinFreeInputs(in, n); return rc; } + kvlangXvalue_t r; narrow_int(a.id, b.id, kvlangScalarI64(a) % bv, &r); + rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); + kvlangBuiltinFreeInputs(in, n); + return rc; +} + +/* ── 位运算 ───────────────────────────────────────────────── */ + +static int kvlangBuiltinBit(kvlangFrame_t *f, int op) { + kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); + kvlangScalar_t sa = kvlangXvalueScalar(&in[0]), sb = n >= 2 ? kvlangXvalueScalar(&in[1]) : SCALAR_NONE; + if (n < 2 || !kvlangLtIsInt(sa.id) || !kvlangLtIsInt(sb.id)) { + kvlangBuiltinSetErr(f, "TypeError: expected integer, got %s", n ? kvlangXvalueKind(&in[0]) : "none"); + kvlangBuiltinFreeInputs(in, n); return -1; + } + int64_t a = kvlangScalarI64(sa), b = kvlangScalarI64(sb); + int64_t v = op == 0 ? a & b : op == 1 ? a | b : op == 2 ? a ^ b : op == 3 ? (a << (uint64_t)b) : (a >> (uint64_t)b); + kvlangXvalue_t r; narrow_int(sa.id, sb.id, v, &r); + int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); + return rc; +} +int kvlangBuiltinBitand(kvlangFrame_t *f) { return kvlangBuiltinBit(f, 0); } +int kvlangBuiltinBitor(kvlangFrame_t *f) { return kvlangBuiltinBit(f, 1); } +int kvlangBuiltinBitxor(kvlangFrame_t *f) { return kvlangBuiltinBit(f, 2); } +int kvlangBuiltinShl(kvlangFrame_t *f) { return kvlangBuiltinBit(f, 3); } +int kvlangBuiltinShr(kvlangFrame_t *f) { return kvlangBuiltinBit(f, 4); } + +/* math */ +static int kvlangBuiltinMathUnary(kvlangFrame_t *f, int op) { + kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); + kvlangScalar_t sa = kvlangXvalueScalar(&in[0]); + if (n < 1 || !kvlangLtIsNum(sa.id)) { kvlangBuiltinSetErr(f, "TypeError: expected numeric, got %s", n ? kvlangXvalueKind(&in[0]) : "none"); kvlangBuiltinFreeInputs(in, n); return -1; } + kvlangXvalue_t r; + double x = kvlangScalarF64(sa); + switch (op) { + case 0: kvlangXvalueNewFloat64(&r, sqrt(x)); break; + case 1: kvlangXvalueNewFloat64(&r, exp(x)); break; + case 2: kvlangXvalueNewFloat64(&r, log(x)); break; + case 3: /* neg */ if (kvlangLtIsFloat(sa.id)) { narrow_float(sa.id, sa.id, -x, &r); } else { narrow_int(sa.id, sa.id, -kvlangScalarI64(sa), &r); } break; + case 4: /* abs */ if (kvlangLtIsFloat(sa.id)) { narrow_float(sa.id, sa.id, fabs(x), &r); } else { int64_t iv = kvlangScalarI64(sa); narrow_int(sa.id, sa.id, iv < 0 ? -iv : iv, &r); } break; + case 5: kvlangXvalueNewInt64(&r, x < 0 ? -1 : x > 0 ? 1 : 0); break; + } + int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); + return rc; +} +int kvlangBuiltinSqrt(kvlangFrame_t *f) { return kvlangBuiltinMathUnary(f, 0); } +int kvlangBuiltinExp(kvlangFrame_t *f) { return kvlangBuiltinMathUnary(f, 1); } +int kvlangBuiltinLog(kvlangFrame_t *f) { return kvlangBuiltinMathUnary(f, 2); } +int kvlangBuiltinNeg(kvlangFrame_t *f) { return kvlangBuiltinMathUnary(f, 3); } +int kvlangBuiltinAbs(kvlangFrame_t *f) { return kvlangBuiltinMathUnary(f, 4); } +int kvlangBuiltinSign(kvlangFrame_t *f) { return kvlangBuiltinMathUnary(f, 5); } + +int kvlangBuiltinPow(kvlangFrame_t *f) { + kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); + kvlangScalar_t sa = kvlangXvalueScalar(&in[0]), sb = n >= 2 ? kvlangXvalueScalar(&in[1]) : SCALAR_NONE; + if (n < 2 || !kvlangLtIsNum(sa.id) || !kvlangLtIsNum(sb.id)) { kvlangBuiltinSetErr(f, "TypeError: expected numeric"); kvlangBuiltinFreeInputs(in, n); return -1; } + kvlangXvalue_t r; kvlangXvalueNewFloat64(&r, pow(kvlangScalarF64(sa), kvlangScalarF64(sb))); + int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); + return rc; +} + +static int kvlangBuiltinMaxmin(kvlangFrame_t *f, bool is_max) { + kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); + if (n < 2) { kvlangBuiltinSetErr(f, "TypeError: binary op requires 2 inputs, got %d", n); kvlangBuiltinFreeInputs(in, n); return -1; } + kvlangXvalue_t r; + kvlangScalar_t sa = kvlangXvalueScalar(&in[0]), sb = kvlangXvalueScalar(&in[1]); + if (kvlangLtIsInt(sa.id) && kvlangLtIsInt(sb.id)) { + int c = cmp_int(sa, sb); + bool take_a = (is_max && c >= 0) || (!is_max && c <= 0); + narrow_int(sa.id, sb.id, take_a ? kvlangScalarI64(sa) : kvlangScalarI64(sb), &r); + } else if (kvlangLtIsNum(sa.id) && kvlangLtIsNum(sb.id)) { + double a = kvlangScalarF64(sa), b = kvlangScalarF64(sb); + bool take_a = (is_max && a >= b) || (!is_max && a <= b); + narrow_float(sa.id, sb.id, take_a ? a : b, &r); + } else { kvlangBuiltinSetErr(f, "TypeError: max/min requires numeric, got %s and %s", kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[1])); kvlangBuiltinFreeInputs(in, n); return -1; } + int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); + return rc; +} +int kvlangBuiltinMax(kvlangFrame_t *f) { return kvlangBuiltinMaxmin(f, true); } +int kvlangBuiltinMin(kvlangFrame_t *f) { return kvlangBuiltinMaxmin(f, false); } + +/* ── cast ─────────────────────────────────────────────────── */ + + +/* cast */ +static int kvlangBuiltinCastNum(kvlangFrame_t *f, const char *kind) { + kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); + if (n < 1 || kvlangXvalueNone(&in[0])) { kvlangBuiltinSetErr(f, "TypeError: cannot cast None"); kvlangBuiltinFreeInputs(in, n); return -1; } + kvlangXvalue_t r; + kvlangScalar_t sa = kvlangXvalueScalar(&in[0]); + int tid = kvlangLangTypeId(kind, strlen(kind)); + if (tid == KVLANG_LT_BOOL) { + if (!kvlangXvalueKindIs(&in[0], KVSPACE_KIND_BOOL)) { kvlangBuiltinSetErr(f, "TypeError: cannot cast %s to bool — use != 0", kvlangXvalueKind(&in[0])); kvlangBuiltinFreeInputs(in, n); return -1; } + kvlangXvalueNewBool(&r, kvlangScalarI64(sa) != 0); + } + else if (tid == KVLANG_LT_FLOAT32) { float fv = (float)kvlangScalarF64(sa); uint8_t b[4]; memcpy(b, &fv, 4); kvlangXvalueNewTlv(&r, KVSPACE_KIND_FLOAT32, b, 4, 1); } + else if (tid == KVLANG_LT_FLOAT64) kvlangXvalueNewFloat64(&r, kvlangScalarF64(sa)); + else { int64_t v = kvlangScalarI64(sa); narrow_int(tid, tid, v, &r); } + int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); + return rc; +} +int kvlangBuiltinCastBool(kvlangFrame_t *f) { return kvlangBuiltinCastNum(f, KVSPACE_KIND_BOOL); } +int kvlangBuiltinCastInt8(kvlangFrame_t *f) { return kvlangBuiltinCastNum(f, KVSPACE_KIND_INT8); } +int kvlangBuiltinCastInt16(kvlangFrame_t *f) { return kvlangBuiltinCastNum(f, KVSPACE_KIND_INT16); } +int kvlangBuiltinCastInt32(kvlangFrame_t *f) { return kvlangBuiltinCastNum(f, KVSPACE_KIND_INT32); } +int kvlangBuiltinCastInt64(kvlangFrame_t *f) { return kvlangBuiltinCastNum(f, KVSPACE_KIND_INT64); } +int kvlangBuiltinCastUint8(kvlangFrame_t *f) { return kvlangBuiltinCastNum(f, KVSPACE_KIND_UINT8); } +int kvlangBuiltinCastUint16(kvlangFrame_t *f) { return kvlangBuiltinCastNum(f, KVSPACE_KIND_UINT16); } +int kvlangBuiltinCastUint32(kvlangFrame_t *f) { return kvlangBuiltinCastNum(f, KVSPACE_KIND_UINT32); } +int kvlangBuiltinCastUint64(kvlangFrame_t *f) { return kvlangBuiltinCastNum(f, KVSPACE_KIND_UINT64); } +int kvlangBuiltinCastF32(kvlangFrame_t *f) { return kvlangBuiltinCastNum(f, KVSPACE_KIND_FLOAT32); } +int kvlangBuiltinCastF64(kvlangFrame_t *f) { return kvlangBuiltinCastNum(f, KVSPACE_KIND_FLOAT64); } + +static int kvlangBuiltinCastChar(kvlangFrame_t *f, const char *kind) { + kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); + if (n < 1 || kvlangXvalueNone(&in[0])) { kvlangBuiltinSetErr(f, "TypeError: char conversion requires a value"); kvlangBuiltinFreeInputs(in, n); return -1; } + char *s = kvlangXvalueValueString(&in[0]); + kvlangXvalue_t r; + if (strcmp(kind, KVSPACE_KIND_CHAR) == 0) kvlangXvalueNewCharUtf32(&r, s); + else kvlangXvalueNewCharKind(&r, kind, s); + int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); free(s); kvlangBuiltinFreeInputs(in, n); + return rc; +} +int kvlangBuiltinCastChar32(kvlangFrame_t *f) { return kvlangBuiltinCastChar(f, KVSPACE_KIND_CHAR); } +int kvlangBuiltinCastChar8(kvlangFrame_t *f) { return kvlangBuiltinCastChar(f, KVSPACE_KIND_CHAR_UTF8); } +int kvlangBuiltinCastCharAscii(kvlangFrame_t *f) { return kvlangBuiltinCastChar(f, KVSPACE_KIND_CHAR_ASCII); } diff --git a/runtime/src/builtin_internal.h b/runtime/src/rwir_internal.h similarity index 65% rename from runtime/src/builtin_internal.h rename to runtime/src/rwir_internal.h index 994676d8..6524576c 100644 --- a/runtime/src/builtin_internal.h +++ b/runtime/src/rwir_internal.h @@ -2,7 +2,7 @@ #include "runtime_internal.h" /* ── 跨模块共享 helper ───────────────────────────────────────────── - frame I/O 与 xvalue_at 定义在 builtin.c;容器 key/index helper 定义在 builtin_coll.c。*/ + frame I/O 与 xvalue_at 定义在 rwir_func.c;容器 key/index helper 定义在 rwir_array.c / rwir_map.c。*/ int kvlangBuiltinReadInputs(kvlangFrame_t *f, kvlangXvalue_t *out, int cap); void kvlangBuiltinFreeInputs(kvlangXvalue_t *in, int n); void kvlangBuiltinNextPc(kvlangFrame_t *f); @@ -19,7 +19,32 @@ void kvlangBuiltinMapMarker(kvlangXvalue_t *out, const char *langtype, bool kvlangBuiltinCharConcat(const kvlangXvalue_t *a, const kvlangXvalue_t *b, kvlangXvalue_t *out); -/* ── 各 lib 的 rwir handler 原型(表在 builtin.c 引用)────────────── */ +/* ── 各 lib 的 rwir handler 原型(表在 rwir_func.c 引用)────────────── */ +/* 算术 / 位 / cast(rwir_int.c) */ +int cmp_int(kvlangScalar_t a, kvlangScalar_t b); +int kvlangBuiltinAdd(kvlangFrame_t *f), kvlangBuiltinSub(kvlangFrame_t *f), + kvlangBuiltinMul(kvlangFrame_t *f), kvlangBuiltinDiv(kvlangFrame_t *f), + kvlangBuiltinMod(kvlangFrame_t *f), kvlangBuiltinBitand(kvlangFrame_t *f), + kvlangBuiltinBitor(kvlangFrame_t *f), kvlangBuiltinBitxor(kvlangFrame_t *f), + kvlangBuiltinShl(kvlangFrame_t *f), kvlangBuiltinShr(kvlangFrame_t *f), + kvlangBuiltinSqrt(kvlangFrame_t *f), kvlangBuiltinExp(kvlangFrame_t *f), + kvlangBuiltinLog(kvlangFrame_t *f), kvlangBuiltinNeg(kvlangFrame_t *f), + kvlangBuiltinAbs(kvlangFrame_t *f), kvlangBuiltinSign(kvlangFrame_t *f), + kvlangBuiltinPow(kvlangFrame_t *f), kvlangBuiltinMax(kvlangFrame_t *f), + kvlangBuiltinMin(kvlangFrame_t *f), + kvlangBuiltinCastBool(kvlangFrame_t *f), kvlangBuiltinCastInt8(kvlangFrame_t *f), + kvlangBuiltinCastInt16(kvlangFrame_t *f), kvlangBuiltinCastInt32(kvlangFrame_t *f), + kvlangBuiltinCastInt64(kvlangFrame_t *f), kvlangBuiltinCastUint8(kvlangFrame_t *f), + kvlangBuiltinCastUint16(kvlangFrame_t *f), kvlangBuiltinCastUint32(kvlangFrame_t *f), + kvlangBuiltinCastUint64(kvlangFrame_t *f), kvlangBuiltinCastF32(kvlangFrame_t *f), + kvlangBuiltinCastF64(kvlangFrame_t *f), kvlangBuiltinCastChar32(kvlangFrame_t *f), + kvlangBuiltinCastChar8(kvlangFrame_t *f), kvlangBuiltinCastCharAscii(kvlangFrame_t *f); +/* 比较 / 逻辑(rwir_bool.c) */ +int kvlangBuiltinEq(kvlangFrame_t *f), kvlangBuiltinNeq(kvlangFrame_t *f), + kvlangBuiltinLt(kvlangFrame_t *f), kvlangBuiltinGt(kvlangFrame_t *f), + kvlangBuiltinLe(kvlangFrame_t *f), kvlangBuiltinGe(kvlangFrame_t *f), + kvlangBuiltinAnd(kvlangFrame_t *f), kvlangBuiltinOr(kvlangFrame_t *f), + kvlangBuiltinNot(kvlangFrame_t *f); int kvlangBuiltinArray(kvlangFrame_t *f), kvlangBuiltinArrayFill(kvlangFrame_t *f), kvlangBuiltinNdarrayNumel(kvlangFrame_t *f), diff --git a/runtime/src/builtin_kv.c b/runtime/src/rwir_kv.c similarity index 99% rename from runtime/src/builtin_kv.c rename to runtime/src/rwir_kv.c index 2dbcc8b2..9057c5e2 100644 --- a/runtime/src/builtin_kv.c +++ b/runtime/src/rwir_kv.c @@ -1,6 +1,6 @@ -// builtin_kv —— kvspace·* KV 树 rwir +// rwir_kv —— kvspace·* KV 树 rwir -#include "builtin_internal.h" +#include "rwir_internal.h" static bool is_int_kind(const char *k) { return kvlangXvalueIsIntKind(k) || kvlangXvalueIsUintKind(k); diff --git a/runtime/src/rwir_map.c b/runtime/src/rwir_map.c new file mode 100644 index 00000000..8bf37ef9 --- /dev/null +++ b/runtime/src/rwir_map.c @@ -0,0 +1,183 @@ +#include "rwir_internal.h" + +/* ── 容器值 / 成员索引 ──────────────────────────────────────────── */ + +/* kvlangBuiltinMemindex(p·):kind=index,body=[4B count LE][name\n...],成员列表唯一权威。 */ +void kvlangBuiltinMemindex(kvlangXvalue_t *out, const char *const *names, + int n) { + kvlangStrbuf_t body; + kvlangStrbufInit(&body); + char count[4] = {(char)(n & 0xFF), (char)((n >> 8) & 0xFF), + (char)((n >> 16) & 0xFF), (char)((n >> 24) & 0xFF)}; + kvlangStrbufPutn(&body, count, 4); + for (int i = 0; i < n; i++) { + if (i) + kvlangStrbufPutc(&body, '\n'); + kvlangStrbufPuts(&body, names[i]); + } + kvlangXvalueNewTlv(out, KVSPACE_KIND_INDEX, (const uint8_t *)body.p, + (uint32_t)body.len, 1); + kvlangStrbufFree(&body); +} + +/* map 容器值(p):body 空、storetype=index,langtype 为 map langtype(见 [[map容器]])。 + * langtype 恒非空——layout 强制容器字面量写目标带 map langtype(缺则 layout 报错)。 */ +void kvlangBuiltinMapMarker(kvlangXvalue_t *out, const char *langtype, + const int32_t *dims, int ndim) { + kvlangXvalueNewTlvDims(out, langtype, (const uint8_t *)"", 0, dims, ndim); +} + +/* 写槽 `w` 的声明容器类型:layout 的 write_slot_value 把 map langtype 落进写槽的 langtype + * (见 code.rs)。缺类型即 layout 漏检——直接 fatal,不退化兜底。调用方负责 free。 */ +static char *declared_map_langtype(kvlangFrame_t *f, int w) { + if (w >= f->inst->nw) { + fprintf(stderr, + "panic: container literal write slot %d missing (nw=%d)\n", w, + f->inst->nw); + abort(); + } + char buf[256]; + kvlangXvalueLangtype(&f->inst->writes[w].val, buf, sizeof buf); + if (!strstr(buf, MEMBER_SEP)) { + fprintf(stderr, + "panic: container literal target %s has no map langtype " + "(layout must reject)\n", + f->inst->writes[w].name); + abort(); + } + return strdup(buf); +} + +/* ── obj / map ─────────────────────────────────────────────────── */ + +int kvlangBuiltinObj(kvlangFrame_t *f) { + kvlangXvalue_t in[64]; + int n = kvlangBuiltinReadInputs(f, in, 64); + char *fr = kvlangKeytreeFrameRoot(f->pc); + for (int w = 0; w < f->inst->nw; w++) { + char *ok = + kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[w].name); + char err[256]; + /* 重建:清旧成员(p·name),容器值随后重写。 */ + char *dir = kvlangKeytreeMember(ok, ""); + char **old = NULL; + int oc = 0; + kvlangKvList(f->kv, dir, false, false, &old, &oc); + for (int i = 0; i < oc; i++) { + char *mk = kvlangKeytreeMember(ok, old[i]); + kvlangKvDel(f->kv, mk, err, sizeof err); + free(mk); + free(old[i]); + } + free(old); + free(dir); + /* 收集成员名(跳过 None)。 */ + int cnt = 0; + for (int i = 0; i + 1 < n; i += 2) + if (!kvlangXvalueNone(&in[i + 1])) + cnt++; + char **names = malloc(sizeof(char *) * (size_t)(cnt > 0 ? cnt : 1)); + for (int i = 0, j = 0; i + 1 < n; i += 2) { + if (kvlangXvalueNone(&in[i + 1])) + continue; + names[j++] = kvlangXvalueValueString(&in[i]); + } + /* 容器值 p:langtype=声明的 map langtype,dims=[0](命名字典无形状,成员在 memindex)。 */ + int32_t odims[1] = {0}; + char *wty = declared_map_langtype(f, w); + kvlangXvalue_t mark; + kvlangBuiltinMapMarker(&mark, wty, odims, 1); + free(wty); + kvlangKvPair_t p0 = {ok, mark}; + kvlangKvSet(f->kv, &p0, 1, err, sizeof err); + kvlangXvalueFree(&mark); + /* kvlangBuiltinMemindex p·:kind=index,body=[4B count][names]。 */ + char *mip = kvlangKeytreeMember(ok, ""); + kvlangXvalue_t mi; + kvlangBuiltinMemindex(&mi, (const char *const *)names, cnt); + kvlangKvPair_t p1 = {mip, mi}; + kvlangKvSet(f->kv, &p1, 1, err, sizeof err); + kvlangXvalueFree(&mi); + free(mip); + for (int i = 0, j = 0; i + 1 < n; i += 2) { + if (kvlangXvalueNone(&in[i + 1])) + continue; + char *mk = kvlangKeytreeMember(ok, names[j]); + kvlangKvPair_t p = {mk, in[i + 1]}; + kvlangKvSet(f->kv, &p, 1, err, sizeof err); + free(mk); + free(names[j]); + j++; + } + free(names); + free(ok); + } + free(fr); + kvlangBuiltinNextPc(f); + kvlangBuiltinFreeInputs(in, n); + return 0; +} + +int kvlangBuiltinMap(kvlangFrame_t *f) { + kvlangXvalue_t in[64]; + int n = kvlangBuiltinReadInputs(f, in, 64); + char *fr = kvlangKeytreeFrameRoot(f->pc); + for (int w = 0; w < f->inst->nw; w++) { + char *ok = + kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[w].name); + char err[256]; + /* 重建:清旧成员(p·name)与旧容器值,随后重写。 */ + char *dir = kvlangKeytreeMember(ok, ""); + char **old = NULL; + int oc = 0; + kvlangKvList(f->kv, dir, false, false, &old, &oc); + for (int i = 0; i < oc; i++) { + char *mk = kvlangKeytreeMember(ok, old[i]); + kvlangKvDel(f->kv, mk, err, sizeof err); + free(mk); + free(old[i]); + } + free(old); + free(dir); + kvlangKvDel(f->kv, ok, err, sizeof err); + + char **names = malloc(sizeof(char *) * (size_t)(n > 0 ? n : 1)); + for (int i = 0; i < n; i++) { + kvlangStrbuf_t s; + kvlangStrbufInit(&s); + kvlangStrbufPrintf(&s, "[%d]", i); + names[i] = kvlangStrbufDetach(&s); + } + /* 容器值 p:langtype=声明的 map langtype,body 空,dims=[n] 落 head。 */ + int32_t dims[1] = {n}; + char *wty = declared_map_langtype(f, w); + kvlangXvalue_t mark; + kvlangBuiltinMapMarker(&mark, wty, dims, 1); + free(wty); + kvlangKvPair_t p0 = {ok, mark}; + kvlangKvSet(f->kv, &p0, 1, err, sizeof err); + kvlangXvalueFree(&mark); + /* kvlangBuiltinMemindex p·:kind=index,body=[4B count][[0]\n[1]...]。 */ + char *mip = kvlangKeytreeMember(ok, ""); + kvlangXvalue_t mi; + kvlangBuiltinMemindex(&mi, (const char *const *)names, n); + kvlangKvPair_t p1 = {mip, mi}; + kvlangKvSet(f->kv, &p1, 1, err, sizeof err); + kvlangXvalueFree(&mi); + free(mip); + for (int i = 0; i < n; i++) { + int64_t c[1] = {i}; + char *k = kvlangBuiltinScatterKey(ok, c, 1); + kvlangKvPair_t p = {k, in[i]}; + kvlangKvSet(f->kv, &p, 1, err, sizeof err); + free(k); + free(names[i]); + } + free(names); + free(ok); + } + free(fr); + kvlangBuiltinNextPc(f); + kvlangBuiltinFreeInputs(in, n); + return 0; +} diff --git a/runtime/src/rwir_ndarray.c b/runtime/src/rwir_ndarray.c new file mode 100644 index 00000000..c2136f11 --- /dev/null +++ b/runtime/src/rwir_ndarray.c @@ -0,0 +1,83 @@ +#include "rwir_internal.h" + +/* ndarray 形状算子只认带形状段的 langtype。map 容器(langtype=`{keylt}·{valt}`)无形状段—— + * 成员数在 memindex(`p·`)而非容器值,用 ndarray·numel 取是范畴错误,直接报错逼用 kvspace·listlen。 */ +static int ndarray_shape_guard(kvlangFrame_t *f, const char *op, + const kvspaceHead_t *h) { + kvlangLangtype kx; + kvlangLangtypeParse(h->langtype, &kx); + if (kx.ndim > 0) + return 0; + if (kvlangKindIsMap(kx.kind)) + return kvlangBuiltinSetErr(f, + "TypeError: %s: container %s has no shape; " + "use kvspace·listlen for member count", + op, kx.kind); + return 0; +} + +int kvlangBuiltinNdarrayNumel(kvlangFrame_t *f) { + kvspaceHead_t h; + int64_t n_el = 0; + if (xv_head1(f, &h) == 0) { + int g = ndarray_shape_guard(f, "ndarray·numel", &h); + if (g) + return g; + kvlangLangtype kx; + kvlangLangtypeParse(h.langtype, &kx); + n_el = kx.array_len; + } + kvlangXvalue_t r; + kvlangXvalueNewInt64(&r, n_el); + int rc = kvlangBuiltinWriteResult(f, &r); + kvlangXvalueFree(&r); + return rc; +} + +int kvlangBuiltinNdarrayDim(kvlangFrame_t *f) { + kvspaceHead_t h; + int64_t ndim = 0; + if (xv_head1(f, &h) == 0) { + int g = ndarray_shape_guard(f, "ndarray·dim", &h); + if (g) + return g; + kvlangLangtype kx; + kvlangLangtypeParse(h.langtype, &kx); + ndim = kx.ndim; + } + kvlangXvalue_t r; + kvlangXvalueNewInt64(&r, ndim); + int rc = kvlangBuiltinWriteResult(f, &r); + kvlangXvalueFree(&r); + return rc; +} + +int kvlangBuiltinNdarrayShape(kvlangFrame_t *f) { + int32_t dims[8]; + int32_t ndim = 0; + kvspaceHead_t h; + if (xv_head1(f, &h) == 0) { + int g = ndarray_shape_guard(f, "ndarray·shape", &h); + if (g) + return g; + kvlangLangtype kx; + kvlangLangtypeParse(h.langtype, &kx); + ndim = kx.ndim; + for (int i = 0; i < ndim && i < 8; i++) + dims[i] = kx.dims[i]; + } + uint8_t raw[64]; + uint32_t raw_len = 0; + for (int i = 0; i < ndim; i++) { + int64_t d = dims[i]; + for (int j = 0; j < 8; j++) + raw[i * 8 + j] = (d >> (j * 8)) & 0xFF; + raw_len += 8; + } + int32_t sd[1] = {ndim}; + kvlangXvalue_t r; + kvlangXvalueNewTlvDims(&r, KVSPACE_KIND_INT64, raw, raw_len, sd, 1); + int rc = kvlangBuiltinWriteResult(f, &r); + kvlangXvalueFree(&r); + return rc; +} diff --git a/runtime/src/builtin_random.c b/runtime/src/rwir_random.c similarity index 94% rename from runtime/src/builtin_random.c rename to runtime/src/rwir_random.c index 8d2853ab..4bf8a9d3 100644 --- a/runtime/src/builtin_random.c +++ b/runtime/src/rwir_random.c @@ -1,6 +1,6 @@ -// builtin_random —— random·* 随机数 rwir +// rwir_random —— random·* 随机数 rwir -#include "builtin_internal.h" +#include "rwir_internal.h" static uint64_t crypto_rand_u64(void) { uint64_t v = 0; diff --git a/runtime/src/builtin_string.c b/runtime/src/rwir_string.c similarity index 99% rename from runtime/src/builtin_string.c rename to runtime/src/rwir_string.c index 32aaeeac..614818ff 100644 --- a/runtime/src/builtin_string.c +++ b/runtime/src/rwir_string.c @@ -1,6 +1,6 @@ -// builtin_string —— string·* 字符串 rwir +// rwir_string —— string·* 字符串 rwir -#include "builtin_internal.h" +#include "rwir_internal.h" static uint32_t utf8_decode_next(const char *s, size_t *i, size_t len) { const unsigned char *p = (const unsigned char *)s; diff --git a/runtime/src/rwir_struct.c b/runtime/src/rwir_struct.c new file mode 100644 index 00000000..9efef51d --- /dev/null +++ b/runtime/src/rwir_struct.c @@ -0,0 +1,123 @@ +#include "rwir_internal.h" + +static char *dupn(const char *s, size_t n) { + char *r = malloc(n + 1); + memcpy(r, s, n); + r[n] = 0; + return r; +} + +/* 在 "name:langtype\n..." 声明串里查字段名,返回其类型(malloc)或 NULL(无此字段)。 */ +static char *struct_field_type(const char *decl, const char *fname) { + size_t fl = strlen(fname); + const char *p = decl; + while (*p) { + const char *nl = strchr(p, '\n'); + size_t linelen = nl ? (size_t)(nl - p) : strlen(p); + const char *colon = memchr(p, ':', linelen); + if (colon) { + size_t nlen = (size_t)(colon - p); + if (nlen == fl && memcmp(p, fname, fl) == 0) + return dupn(colon + 1, linelen - nlen - 1); + } + if (!nl) + break; + p = nl + 1; + } + return NULL; +} + +/* struct·new:克隆 /lib/Name 原型子树到写槽,覆盖给定字段(校验字段存在性+类型)。 + * in[0]=structref("/lib/Name"),其后成对 (字段名, 值)。实例基值 kind=structref。 */ +int kvlangBuiltinStructNew(kvlangFrame_t *f) { + kvlangXvalue_t in[64]; + int n = kvlangBuiltinReadInputs(f, in, 64); + if (n < 1) { + kvlangBuiltinFreeInputs(in, n); + return kvlangBuiltinSetErr(f, "TypeError: struct.new requires a type"); + } + char *ref = kvlangXvalueValueString(&in[0]); + kvlangXvalue_t proto; + kvlangXvalueZero(&proto); + kvlangKvGetOne(f->kv, ref, &proto); + if (kvlangXvalueNone(&proto) || + strcmp(kvlangXvalueKind(&proto), KVSPACE_KIND_STRUCT) != 0) { + int e = + kvlangBuiltinSetErr(f, "TypeError: %s is not a struct type", ref); + kvlangXvalueFree(&proto); + free(ref); + kvlangBuiltinFreeInputs(in, n); + return e; + } + kvspaceHead_t ph; + kvlangXvalueHead(&proto, &ph); + int32_t dclen = 0; + const uint8_t *dcl = kvlangXvalueBody(&proto, &ph, &dclen); + char *decl = dupn((const char *)dcl, (size_t)(dclen > 0 ? dclen : 0)); + kvlangXvalueFree(&proto); + + char err[256]; + int rc = 0; + char *fr = kvlangKeytreeFrameRoot(f->pc); + for (int w = 0; w < f->inst->nw && rc == 0; w++) { + char *ok = + kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[w].name); + if (kvlangKvCpList(f->kv, ref, ok, err, sizeof err) != 0) { + rc = kvlangBuiltinSetErr(f, "%s", err); + free(ok); + break; + } + kvlangXvalue_t mark; + kvlangXvalueNewTlv(&mark, ref, (const uint8_t *)"", 0, 1); + kvlangKvPair_t p0 = {ok, mark}; + kvlangKvSet(f->kv, &p0, 1, err, sizeof err); + kvlangXvalueFree(&mark); + for (int i = 1; i + 1 < n && rc == 0; i += 2) { + char *fname = kvlangXvalueValueString(&in[i]); + char *ftype = struct_field_type(decl, fname); + if (!ftype) { + rc = kvlangBuiltinSetErr( + f, "TypeError: struct %s has no field %s", ref, fname); + free(fname); + break; + } + const char *vk = kvlangXvalueKind(&in[i + 1]); + kvspaceHead_t vh; + kvlangXvalueHead(&in[i + 1], &vh); + kvlangLangtype vkx; + kvlangLangtypeParse(vh.langtype, &vkx); + // *T 指针字段:字段类型剥离前导 * 后与值的 langtype 比对,并校验值 ref=1; + // None 是合法空指针(见 [[ptr]]),不算类型不符。 + const char *fx = (ftype[0] == '*') ? ftype + 1 : ftype; + bool type_ok = ftype[0] + ? kvlangLangtypeMatch(fx, vk, vkx.ndim, vkx.dims) + : true; + if (ftype[0] == '*' && !kvlangXvalueNone(&in[i + 1]) && + vh.ref != KVSPACE_REF_PTR) + type_ok = false; + if (ftype[0] && !type_ok) { + rc = kvlangBuiltinSetErr( + f, "TypeError: field %s: expected %s, got %s", fname, ftype, + vk[0] ? vk : "None"); + free(ftype); + free(fname); + break; + } + char *mk = kvlangKeytreeMember(ok, fname); + kvlangKvPair_t p = {mk, in[i + 1]}; + kvlangKvSet(f->kv, &p, 1, err, sizeof err); + free(mk); + free(ftype); + free(fname); + } + free(ok); + } + free(fr); + free(decl); + free(ref); + kvlangBuiltinFreeInputs(in, n); + if (rc != 0) + return rc; + kvlangBuiltinNextPc(f); + return 0; +} diff --git a/runtime/src/builtin_time.c b/runtime/src/rwir_time.c similarity index 97% rename from runtime/src/builtin_time.c rename to runtime/src/rwir_time.c index 9d7ffbff..ae44a21d 100644 --- a/runtime/src/builtin_time.c +++ b/runtime/src/rwir_time.c @@ -1,6 +1,6 @@ -// builtin_time —— time·* / time/duration·* 时间与时长 rwir +// rwir_time —— time·* / time/duration·* 时间与时长 rwir -#include "builtin_internal.h" +#include "rwir_internal.h" #include static int64_t now_nanos(void) { diff --git a/runtime/src/builtin_vthread.c b/runtime/src/rwir_vthread.c similarity index 98% rename from runtime/src/builtin_vthread.c rename to runtime/src/rwir_vthread.c index 81ae418b..2a04f78e 100644 --- a/runtime/src/builtin_vthread.c +++ b/runtime/src/rwir_vthread.c @@ -1,6 +1,6 @@ -// builtin_vthread —— vthread·* 虚拟线程 rwir +// rwir_vthread —— vthread·* 虚拟线程 rwir -#include "builtin_internal.h" +#include "rwir_internal.h" #include /* vthread·create(funckey) -> vid:分配 vid、建栈索引、bootstrap 首指令、置 init,返回 vid 句柄。 diff --git a/runtime/src/rwir_xvalue.c b/runtime/src/rwir_xvalue.c new file mode 100644 index 00000000..7bda0ff0 --- /dev/null +++ b/runtime/src/rwir_xvalue.c @@ -0,0 +1,354 @@ +#include "rwir_internal.h" + +/* 计算多维下标的 row-major 扁平索引,越界返回 -1。 */ +static int64_t flat_index(const kvlangLangtype *kx, const int64_t *idx, + int nidx) { + int64_t flat = 0; + for (int i = 0; i < nidx; i++) { + if (idx[i] < 0 || idx[i] >= kx->dims[i]) + return -1; + flat = flat * kx->dims[i] + idx[i]; + } + return flat; +} + +/* base kind(kx.kind 为非 NUL 终止子串)拷成 NUL 终止串,取元素字节大小;空 kind → 0。 */ +static int xv_elem_size(const kvlangLangtype *kx) { + if (!kx->kind || kx->kind_len <= 0) + return 0; + char kb[64]; + int kl = kx->kind_len < 63 ? kx->kind_len : 63; + memcpy(kb, kx->kind, (size_t)kl); + kb[kl] = 0; + return kvlangXvalueElemSize(kb); +} + +/* 读参 ri 的 head:变量走 GetHead 只读前缀(不借 body,*key=malloc'd 键),字面量数组借整块 + * 解 head(*key=NULL,*borrow 持整块,调用方 kvlangXvalueFree)。返回 0 成功、非 0 空/不存在。 */ +static int xv_read_head(kvlangFrame_t *f, const char *fr, int ri, + kvspaceHead_t *h, char **key, kvlangXvalue_t *borrow) { + kvlangXvalueZero(borrow); + *key = NULL; + char *k = kvlangBuiltinResolveReadKey(f->kv, fr, f->inst->reads[ri].name, + &f->inst->reads[ri].val); + if (k) { + if (kvlangKvGetHead(f->kv, k, h) != 0) { + free(k); + return -1; + } + *key = k; + return 0; + } + kvlangBuiltinResolveReadValue(f->kv, fr, f->inst->reads[ri].name, + &f->inst->reads[ri].val, borrow); + if (kvlangXvalueNone(borrow)) + return -1; + return kvspaceDecodeHead(borrow->data, borrow->len, h) == 0 ? 0 : -1; +} + +/* 单读参 head:GetHead-only(变量)或借块解码(字面量),完毕即释放借块与键。 + * 返回 0 并填 *h;空/不存在返回 -1(调用方给默认值)。 */ +int xv_head1(kvlangFrame_t *f, kvspaceHead_t *h) { + char *fr = kvlangKeytreeFrameRoot(f->pc); + char *key; + kvlangXvalue_t borrow; + int rc = xv_read_head(f, fr, 0, h, &key, &borrow); + free(key); + kvlangXvalueFree(&borrow); + free(fr); + return rc; +} + +/* 读 first..first+nidx-1 的标量下标到 idx[]。 */ +static void xv_read_indices(kvlangFrame_t *f, const char *fr, int first, + int nidx, int64_t *idx) { + for (int i = 0; i < nidx && i < X_MAX_NDIM; i++) { + kvlangXvalue_t iv; + kvlangBuiltinResolveReadValue(f->kv, fr, f->inst->reads[first + i].name, + &f->inst->reads[first + i].val, &iv); + idx[i] = kvlangScalarI64(kvlangXvalueScalar(&iv)); + kvlangXvalueFree(&iv); + } +} + +/* 分片读单元素:GetHead 定位 + GetPart 只借该元素的 [off, off+sz) 字节,不借整块。 */ +int kvlangBuiltinXvAt(kvlangFrame_t *f) { + int nidx = f->inst->nr - 1; + if (nidx < 1) + return kvlangBuiltinSetErr( + f, "TypeError: xv.at requires array and indices"); + char *fr = kvlangKeytreeFrameRoot(f->pc); + kvspaceHead_t h; + char *key; + kvlangXvalue_t arr; + if (xv_read_head(f, fr, 0, &h, &key, &arr) != 0) { + free(fr); + return kvlangBuiltinSetErr(f, + "TypeError: xv.at requires a compact array"); + } + kvlangLangtype kx; + kvlangLangtypeParse(h.langtype, &kx); + int sz = xv_elem_size(&kx); + if (sz <= 0 || kx.ndim == 0) { + free(key); + kvlangXvalueFree(&arr); + free(fr); + return kvlangBuiltinSetErr( + f, "TypeError: xv.at requires a compact array, got %s", h.langtype); + } + if (nidx != kx.ndim) { + free(key); + kvlangXvalueFree(&arr); + free(fr); + return kvlangBuiltinSetErr( + f, "IndexError: xv.at: %d-dim array needs %d indices, got %d", + kx.ndim, kx.ndim, nidx); + } + int64_t idx[X_MAX_NDIM]; + xv_read_indices(f, fr, 1, nidx, idx); + free(fr); + int64_t flat = flat_index(&kx, idx, nidx); + if (flat < 0) { + free(key); + kvlangXvalueFree(&arr); + return kvlangBuiltinSetErr(f, "IndexError: xv.at: index out of bounds"); + } + char kb[64]; + int kl = kx.kind_len < 63 ? kx.kind_len : 63; + memcpy(kb, kx.kind, (size_t)kl); + kb[kl] = 0; + kvlangXvalue_t e; + if (key) { + kvlangXvalue_t part; + kvlangKvGetPart(f->kv, key, (uint32_t)(h.body_offset + flat * sz), + (uint32_t)sz, &part); + kvlangXvalueNewTlv(&e, kb, part.data, part.len, 1); + kvlangXvalueFree(&part); + free(key); + } else { + const uint8_t *body = arr.data + h.body_offset; + kvlangXvalueNewTlv(&e, kb, body + flat * sz, (uint32_t)sz, 1); + } + kvlangXvalueFree(&arr); + int rc = kvlangBuiltinWriteResult(f, &e); + kvlangXvalueFree(&e); + return rc; +} + +/* 分片写单元素:写目标==源变量且已存在 → GetHead 定位 + SetPart 就地写该元素字节(O(1), + * 不重建整块);源≠目标 / 字面量 / 缺失 → 回退借整块、拷贝、改元素、整体重建。 */ +int kvlangBuiltinXvSet(kvlangFrame_t *f) { + int nidx = f->inst->nr - 2; + if (nidx < 1) + return kvlangBuiltinSetErr( + f, "TypeError: xv.set requires array, indices, value"); + if (f->inst->nw == 0) + return kvlangBuiltinSetErr( + f, "TypeError: xv.set requires a write param (-> a)"); + char *fr = kvlangKeytreeFrameRoot(f->pc); + char *rk = kvlangBuiltinResolveReadKey(f->kv, fr, f->inst->reads[0].name, + &f->inst->reads[0].val); + char *wk = + kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[0].name); + int64_t idx[X_MAX_NDIM]; + xv_read_indices(f, fr, 1, nidx, idx); + kvlangXvalue_t vv; + kvlangBuiltinResolveReadValue(f->kv, fr, f->inst->reads[nidx + 1].name, + &f->inst->reads[nidx + 1].val, &vv); + kvspaceHead_t vh; + kvspaceDecodeHead(vv.data, vv.len, &vh); + const uint8_t *vb = vv.data + vh.body_offset; + + kvspaceHead_t h; + if (rk && wk && strcmp(rk, wk) == 0 && + kvlangKvGetHead(f->kv, wk, &h) == 0) { + kvlangLangtype kx; + kvlangLangtypeParse(h.langtype, &kx); + int sz = xv_elem_size(&kx); + int64_t flat = (sz > 0 && kx.ndim && nidx == kx.ndim) + ? flat_index(&kx, idx, nidx) + : -1; + const char *emsg = + sz <= 0 || kx.ndim == 0 + ? "TypeError: xv.set requires a compact array" + : nidx != kx.ndim ? "IndexError: xv.set: dim/index count mismatch" + : flat < 0 ? "IndexError: xv.set: index out of bounds" + : NULL; + int rc = 0; + if (emsg) + rc = kvlangBuiltinSetErr(f, "%s", emsg); + else { + int c = vh.body_len < sz ? vh.body_len : sz; + char err[256]; + kvlangKvSetPart(f->kv, wk, (uint32_t)(h.body_offset + flat * sz), + vb, (uint32_t)c, err, sizeof err); + kvlangBuiltinNextPc(f); + } + free(rk); + free(wk); + free(fr); + kvlangXvalueFree(&vv); + return rc; + } + free(rk); + free(wk); + + kvlangXvalue_t arr; + kvlangBuiltinResolveReadValue(f->kv, fr, f->inst->reads[0].name, + &f->inst->reads[0].val, &arr); + free(fr); + const char *k = kvlangXvalueKind(&arr); + int sz = kvlangXvalueElemSize(k); + kvspaceHead_t ah; + kvspaceDecodeHead(arr.data, arr.len, &ah); + kvlangLangtype kx; + kvlangLangtypeParse(ah.langtype, &kx); + const char *emsg = + sz <= 0 || kx.ndim == 0 ? "TypeError: xv.set requires a compact array" + : nidx != kx.ndim ? "IndexError: xv.set: dim/index count mismatch" + : NULL; + int64_t flat = emsg ? -1 : flat_index(&kx, idx, nidx); + if (!emsg && flat < 0) + emsg = "IndexError: xv.set: index out of bounds"; + if (emsg) { + kvlangXvalueFree(&arr); + kvlangXvalueFree(&vv); + return kvlangBuiltinSetErr(f, "%s", emsg); + } + uint8_t *nb = malloc((size_t)ah.body_len); + memcpy(nb, arr.data + ah.body_offset, (size_t)ah.body_len); + int c = vh.body_len < sz ? vh.body_len : sz; + memcpy(nb + flat * sz, vb, (size_t)c); + kvlangXvalue_t nv; + kvlangXvalueNewTlvDims(&nv, k, nb, (uint32_t)ah.body_len, kx.dims, kx.ndim); + int rc = kvlangBuiltinWriteResult(f, &nv); + kvlangXvalueFree(&nv); + free(nb); + kvlangXvalueFree(&arr); + kvlangXvalueFree(&vv); + return rc; +} + +int kvlangBuiltinXvReshape(kvlangFrame_t *f) { + int ndims = f->inst->nr - 1; + if (ndims < 1) + return kvlangBuiltinSetErr( + f, "TypeError: xv.reshape requires array and >=1 dims"); + if (f->inst->nw == 0) + return kvlangBuiltinSetErr( + f, "TypeError: xv.reshape requires a write param (-> a)"); + kvlangXvalue_t in[MAX_PARAMS]; + int n = kvlangBuiltinReadInputs(f, in, MAX_PARAMS); + const char *k = kvlangXvalueKind(&in[0]); + if (kvlangXvalueElemSize(k) <= 0) { + kvlangBuiltinFreeInputs(in, n); + return kvlangBuiltinSetErr( + f, "TypeError: xv.reshape requires a compact array, got %s", k); + } + kvspaceHead_t h; + kvspaceDecodeHead(in[0].data, in[0].len, &h); + kvlangLangtype kx; + kvlangLangtypeParse(h.langtype, &kx); + if (kx.ndim < 1) { + kvlangBuiltinFreeInputs(in, n); + return kvlangBuiltinSetErr( + f, "TypeError: xv.reshape requires a compact array, got scalar %s", + k); + } + if (ndims > X_MAX_NDIM) { + kvlangBuiltinFreeInputs(in, n); + return kvlangBuiltinSetErr( + f, "IndexError: xv.reshape: at most %d dims, got %d", X_MAX_NDIM, + ndims); + } + int32_t dims[X_MAX_NDIM]; + int64_t numel = 1; + for (int i = 0; i < ndims; i++) { + dims[i] = (int32_t)kvlangScalarI64(kvlangXvalueScalar(&in[i + 1])); + if (dims[i] < 0) { + kvlangBuiltinFreeInputs(in, n); + return kvlangBuiltinSetErr( + f, "IndexError: xv.reshape: negative dim %d", dims[i]); + } + numel *= dims[i]; + } + if (numel != kx.array_len) { + kvlangBuiltinFreeInputs(in, n); + return kvlangBuiltinSetErr( + f, "IndexError: xv.reshape: cannot reshape %d elements into %lld", + kx.array_len, (long long)numel); + } + const uint8_t *body = in[0].data + h.body_offset; + kvlangXvalue_t nv; + kvlangXvalueNewTlvDims(&nv, k, body, (uint32_t)h.body_len, dims, ndims); + int rc = kvlangBuiltinWriteResult(f, &nv); + kvlangXvalueFree(&nv); + kvlangBuiltinFreeInputs(in, n); + return rc; +} + +/* xv·reinterpret(arr, langtype) -> a:body 字节原样,整个 langtype 换成传入的(kind+dims 一起),不做校验。 */ +int kvlangBuiltinXvReinterpret(kvlangFrame_t *f) { + if (f->inst->nr < 2) + return kvlangBuiltinSetErr( + f, "TypeError: xv.reinterpret requires array and langtype"); + if (f->inst->nw == 0) + return kvlangBuiltinSetErr( + f, "TypeError: xv.reinterpret requires a write param (-> a)"); + kvlangXvalue_t in[2]; + int n = kvlangBuiltinReadInputs(f, in, 2); + char *ke = kvlangXvalueValueString(&in[1]); + kvlangLangtype nkx; + kvlangLangtypeParse((const uint8_t *)ke, &nkx); + kvspaceHead_t h; + kvspaceDecodeHead(in[0].data, in[0].len, &h); + const uint8_t *body = in[0].data + h.body_offset; + /* 动态 "[]kind"(parse 得 ndim0 但带方括号):按 body 字节数补出一维长度,与落盘数组表示一致。 */ + int32_t ndim = nkx.ndim; + if (nkx.ndim == 0 && strchr(ke, '[')) { + int32_t es = kvlangXvalueElemSize(nkx.kind); + nkx.dims[0] = es > 0 ? (int32_t)(h.body_len / es) : (int32_t)h.body_len; + ndim = 1; + } + kvlangXvalue_t nv; + kvlangXvalueNewTlvDims(&nv, nkx.kind, body, (uint32_t)h.body_len, nkx.dims, + ndim); + int rc = kvlangBuiltinWriteResult(f, &nv); + kvlangXvalueFree(&nv); + free(ke); + kvlangBuiltinFreeInputs(in, n); + return rc; +} + +/* xv·langtype(v) -> s:返回 v 的 head langtype 串(含 ref 前缀与 [dims]),作为字符串。 */ +int kvlangBuiltinXvLangtype(kvlangFrame_t *f) { + if (f->inst->nw == 0) + return kvlangBuiltinSetErr( + f, "TypeError: xv.langtype requires a write param (-> s)"); + kvspaceHead_t h; + const char *ke = ""; + if (xv_head1(f, &h) == 0) + ke = (const char *)h.langtype; + kvlangXvalue_t r; + kvlangXvalueNewCharUtf8(&r, ke); + int rc = kvlangBuiltinWriteResult(f, &r); + kvlangXvalueFree(&r); + return rc; +} + +/* xv·bodylen(v) -> n:返回 v 的 body 字节数(int64)。 */ +int kvlangBuiltinXvBodylen(kvlangFrame_t *f) { + if (f->inst->nw == 0) + return kvlangBuiltinSetErr( + f, "TypeError: xv.bodylen requires a write param (-> n)"); + kvspaceHead_t h; + int64_t bl = 0; + if (xv_head1(f, &h) == 0) + bl = h.body_len; + kvlangXvalue_t r; + kvlangXvalueNewInt64(&r, bl); + int rc = kvlangBuiltinWriteResult(f, &r); + kvlangXvalueFree(&r); + return rc; +} + diff --git a/runtime/src/rwirext.c b/runtime/src/rwirext.c index 86314cc9..1a61c7f0 100644 --- a/runtime/src/rwirext.c +++ b/runtime/src/rwirext.c @@ -1,134 +1,6 @@ -#include "kvlang_rwirext.h" +#include "kvlang_runtime.h" #include "runtime_internal.h" -/* 共享队列根:第一个 rwir 的 /lib//vids 绝对路径。 */ -static char *g_first_vids = NULL; - -/* notinmyrwircaps:opcode 是一条不在本 runtime myrwircaps 内、须经 def rwir 路由给 - * 能兑现它的其它 runtime 的 rwir。判据是 /lib/ 存在 def rwir 路由头 - * (langtype=def rwir,storetype=index)。kvspace 是能力唯一事实源;本判定在独立 - * kvlang 进程内发生,进程内 myrwircaps 恒不含它,故只有 /lib 路由头可信。 */ -bool notinmyrwircaps(kvlangKv_t *k, const char *opcode) { - if (opcode[0] == '/') - return false; - char *key = kvlangKeytreeRwir(opcode); - kvlangXvalue_t v; - kvlangXvalueZero(&v); - kvlangKvGetOne(k, key, &v); - bool yes = - !kvlangXvalueNone(&v) && kvlangXvalueKindIs(&v, KVSPACE_KIND_DEF_RWIR); - kvlangXvalueFree(&v); - free(key); - return yes; -} - -/* 建立 rwir 的 vids 队列:第一个 rwir 是真实 strkeymap,后续是 Ptr 指向第一个。 - * 幂等:vids 已存在则跳过——否则脏 kvspace 上重复注册时,Set 经路径穿透会把首队列 - * 改成自指 Ptr,令 resolve_path 死循环(父子 kvlang 共享同一 redis 的挂起根因)。 */ -static void register_vids(kvlangKv_t *k, const char *opcode) { - char *base = kvlangKeytreeRwir(opcode); - kvlangStrbuf_t tk; - kvlangStrbufInit(&tk); - kvlangStrbufPuts(&tk, base); - kvlangStrbufPuts(&tk, "/vids"); - bool first = (g_first_vids == NULL); - if (first) - g_first_vids = strdup(tk.p); - kvlangXvalue_t cur; - kvlangXvalueZero(&cur); - bool exists = - (kvlangKvGetOne(k, tk.p, &cur) == 0 && !kvlangXvalueNone(&cur)); - kvlangXvalueFree(&cur); - if (!exists) { - kvlangXvalue_t v; - kvlangXvalueZero(&v); - int32_t dims[1] = {0}; - if (first) - kvlangXvalueNewTlvDims(&v, KVSPACE_KIND_MAP, (const uint8_t *)"", 0, - dims, 1); - else - kvlangXvalueNewPtr(&v, KVSPACE_KIND_MAP, g_first_vids); - kvlangKvPair_t p = {tk.p, v}; - char err[256]; - kvlangKvSet(k, &p, 1, err, sizeof err); - kvlangXvalueFree(&v); - } - kvlangStrbufFree(&tk); - free(base); -} - -/* 写 [0,x] 签名行槽 = def langtype(body 为该参数 langtype 串)。 */ -static void write_sig_slot(kvlangKv_t *k, const char *base, int x, - const char *lt, size_t lt_len) { - kvlangStrbuf_t sk; - kvlangStrbufInit(&sk); - kvlangStrbufPrintf(&sk, "%s/[0,%d]", base, x); - char *clean = strndup(lt, lt_len); - kvlangXvalue_t sv; - kvlangXvalueNewDefLangtype(&sv, clean); - free(clean); - kvlangKvPair_t sp = {sk.p, sv}; - char err[256]; - kvlangKvSet(k, &sp, 1, err, sizeof err); - kvlangXvalueFree(&sv); - kvlangStrbufFree(&sk); -} - -/* 注册一条 rwir:/lib/ 路由头(仅计数头)+ 各参数落 [0,x] 签名行槽(def langtype)。 - * 参数类型逐条传入(读参 rp[0..nr]、写参 wp[0..nw]),不再拼签名串——避免其它 runtime - * 把「拼接 sig 串」误当注册标准。末读参尾缀 "..." → 变参 arity(落 dynamic 字节)。 */ -int kvlangDefRwir(void *kvspace, const char *opcode, const char *const *rp, - int32_t nr, const char *const *wp, int32_t nw) { - kvlangKv_t k = {kvspace}; - char *base = kvlangKeytreeRwir(opcode); - char err[256]; - - int dynamic = 0; - size_t last_len = (nr > 0 && rp[nr - 1]) ? strlen(rp[nr - 1]) : 0; - if (nr > 0 && last_len >= 3 && - memcmp(rp[nr - 1] + last_len - 3, "...", 3) == 0) { - dynamic = 1; - last_len -= 3; - } - - kvlangXvalue_t hv; - kvlangXvalueNewDefRwir(&hv, nr, nw, dynamic); - kvlangKvPair_t hp = {base, hv}; - int rc = kvlangKvSet(&k, &hp, 1, err, sizeof err); - kvlangXvalueFree(&hv); - - for (int32_t i = 0; i < nr; i++) - write_sig_slot(&k, base, -(i + 1), rp[i], - (i == nr - 1) ? last_len : strlen(rp[i])); - for (int32_t i = 0; i < nw; i++) - write_sig_slot(&k, base, i + 1, wp[i], strlen(wp[i])); - - free(base); - /* 建立共享 vids 队列(第一个真实 strkeymap,后续 Ptr 指向它;幂等查 kvspace)。 */ - register_vids(&k, opcode); - return rc; -} - -int kvlangRwirextHandoff(void *kvspace, const char *vtid, const char *pc) { - kvlangKv_t k = {kvspace}; - char *fr = kvlangKeytreeFrameRoot(pc); - if (!fr) - return -1; - char *lb = kvlangKeytreeStack(fr); - kvlangRwirInst_t inst; - char err[256]; - if (kvlangRwirDecode(&k, lb, pc, &inst, err, sizeof err) != 0) { - free(fr); - free(lb); - return -1; - } - free(lb); - int rc = handoff_external_rwir(&k, vtid, pc, &inst); - free(fr); - kvlangRwirInstFree(&inst); - return rc; -} - char *kvlangRwirextNextPc(const char *pc) { kvlangStrbuf_t b; kvlangStrbufInit(&b); diff --git a/runtime/src/xvalue.c b/runtime/src/xvalue.c index 4330175a..794aad7e 100644 --- a/runtime/src/xvalue.c +++ b/runtime/src/xvalue.c @@ -1,7 +1,7 @@ #include "runtime_internal.h" /* 后端无关的 XValue TLV 编解码(对齐 kvspace-durable/kvspace-c 的 kindexp TLV)。 - * xval.data 一律 malloc(free 释放),后端在 kv.c 层负责拷贝。 */ + * xval.data 一律 malloc(free 释放),后端在 kvspace.c 层负责拷贝。 */ static uint32_t rd32(const uint8_t *p) { return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | diff --git "a/stdlib/kvlang/spec/03-\347\261\273\345\236\213\347\263\273\347\273\237/05-langtype\347\255\276\345\220\215\347\261\273\345\236\213\350\241\250\350\276\276\345\274\217.kv" "b/stdlib/kvlang/spec/03-\347\261\273\345\236\213\347\263\273\347\273\237/05-langtype\347\255\276\345\220\215\347\261\273\345\236\213\350\241\250\350\276\276\345\274\217.kv" index c1af27fe..4ca21840 100644 --- "a/stdlib/kvlang/spec/03-\347\261\273\345\236\213\347\263\273\347\273\237/05-langtype\347\255\276\345\220\215\347\261\273\345\236\213\350\241\250\350\276\276\345\274\217.kv" +++ "b/stdlib/kvlang/spec/03-\347\261\273\345\236\213\347\263\273\347\273\237/05-langtype\347\255\276\345\220\215\347\261\273\345\236\213\350\241\250\350\276\276\345\274\217.kv" @@ -32,7 +32,7 @@ rwfunc,交 runtime 查 `/lib/` 定,见 [[指令槽编码]]),既 ## 两条 runtime-c ABI(供外部调用) -runtime-c 对外开放两组类型能力,一一对应这两者(`kvlang_rwirext.h` 与正典 codec,见 [[cruntime与后端 +runtime-c 对外开放两组类型能力,一一对应这两者(`kvlang_runtime.h` 与正典 codec,见 [[cruntime与后端 abi]]),供扩展运行时与嵌入方调用: - **def langtype 侧(匹配)**:`LangtypeValid` 校验一条 def langtype 串合法、`LangtypeMatch` 把一个值的 diff --git "a/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/05-runtimec\345\206\205\345\273\272.kv" "b/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/05-runtimec\345\206\205\345\273\272.kv" index 4176aee5..1c006126 100644 --- "a/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/05-runtimec\345\206\205\345\273\272.kv" +++ "b/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/05-runtimec\345\206\205\345\273\272.kv" @@ -7,7 +7,7 @@ lib kvlang/spec/runtime语义/runtimec内建 { ## native builtin 判定 -查表函数 `kvlangBuiltinCapIndex(opcode)`(`runtime/src/builtin.c`)**两级查找**:先按完整 opcode 查 +查表函数 `kvlangBuiltinCapIndex(opcode)`(`runtime/src/rwir_func.c`)**两级查找**:先按完整 opcode 查 (命中即专精实现,如 `float8/e4m3·add`、`time·add` 等成员算子),未命中且末段前缀是 **C 原生数值 langtype** (`int8..int64`/`uint8..uint64`/`float32`/`float64`)才剥前缀查裸算子(`int64·add → add`,通用实现, 按操作数 kind 归约)。命中返回索引即在 myrwircaps 内;否则 `notinmycaps`。**保留精度前缀专精**: diff --git "a/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/09-cruntime\344\270\216\345\220\216\347\253\257abi.kv" "b/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/09-cruntime\344\270\216\345\220\216\347\253\257abi.kv" index a1688c1c..abe1eddf 100644 --- "a/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/09-cruntime\344\270\216\345\220\216\347\253\257abi.kv" +++ "b/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/09-cruntime\344\270\216\345\220\216\347\253\257abi.kv" @@ -18,11 +18,11 @@ durable 单句柄相干、后端装载。 2. **值语义与编解码**:TLV / langtype 的**唯一编解码器**在 kvspace 正典 codec(`kvspaceTlvEncode` / `kvspaceDecodeHead` / `kvspaceNewPtr`/`NewChar`/`NewBool`/`NewInt64`/`NewFloat64`);runtime-c 的 `xvalue.c` 只是其薄封装。langtype 串是类型的唯一真相,怎么拼、怎么解,只此一处。 -3. **指令解码与签名校验**:`rwir.c:RwirDecode`(稠密探查、遇空即停)、`/lib/` 签名的读写码规范、 +3. **指令解码与签名校验**:`rwir_decode.c:RwirDecode`(稠密探查、遇空即停)、`/lib/` 签名的读写码规范、 `LangtypeValid`/`LangtypeMatch` 类型判定。 -**扩展运行时套用核心,不复刻**:runtime-c 把上述三件能力经嵌入式 C ABI(下节 `kvlang_runtime.h` + -`kvlang_rwirext.h`)对外开放。扩展运行时**嵌入**这套核心、复用其执行循环、native 派发与正典 codec,只 +**扩展运行时套用核心,不复刻**:runtime-c 把上述三件能力经嵌入式 C ABI(下节 `kvlang_vthread.h` + +`kvlang_runtime.h`)对外开放。扩展运行时**嵌入**这套核心、复用其执行循环、native 派发与正典 codec,只 **自行解释己方 opcode**——不得另起执行核心、不得另写编解码器、不得复刻 native 算子。据此: - **runtime-rs 是扩展运行时的参考实现**,不是第二套等价核心。它作为 myrwir 宿主,套用 runtime-c 核 @@ -37,9 +37,9 @@ durable 单句柄相干、后端装载。 `kvlang/runtime/` 是通用嵌入式执行器(纯 C + `extern "C"`),可嵌入 myrwir 项目(op-gpu、agent、 livebyte)。两组对外 C ABI: -- `kvlang_runtime.h`:核心执行器(`kvlangRuntimeConnect`/`Disconnect`/`Bootstrap`/`ExecuteVthread`/ +- `kvlang_vthread.h`:核心执行器(`kvlangRuntimeConnect`/`Disconnect`/`Bootstrap`/`ExecuteVthread`/ `KvspaceHandle` …)。 -- `kvlang_rwirext.h`:扩展 runtime 语义,**只暴露 kvspace 不提供的部分**。现有 9 个符号:`kvlangDefRwir`、 +- `kvlang_runtime.h`:扩展 runtime 语义,**只暴露 kvspace 不提供的部分**。现有 9 个符号:`kvlangDefRwir`、 `kvlangRwirextHandoff`、`kvlangRwirextNextPc`、`kvlangRwirextParams`、`kvlangRwirextResolveRead`、 `kvlangRwirextResolveReadPath`、`kvlangRwirextResolveWrite`、`kvlangLangtypeValid`、 `kvlangLangtypeMatch`。KV 存取(connect/get/write/del/list/tlv)**不在此**——扩展宿主自连 kvspace ABI,把 @@ -52,8 +52,8 @@ livebyte)。两组对外 C ABI: 类型表达式串、共用唯一文法与 codec,差别只在**匹配** vs **解析**。 内部模块:`xvalue.c`(TLV 编解码薄封装)、`langtype.c` + `langtypetable.c`(langtype 校验/匹配与我 -表格)、`kv.c`(kvspace ABI 封装)、`keytree.c`(路径构造)、`rwir.c`(PC 解析 + Decode)、 -`vthread.c`、`builtin*.c`(native 算子 + 静态注册表)、`kvcpu.c`(Execute 循环)、`runtime.c`(ABI +表格)、`kvspace.c`(kvspace ABI 封装)、`keytree.c`(路径构造)、`rwir_decode.c`(PC 解析 + Decode)、 +`vthread.c`、`rwir*.c`(native 算子 + 静态注册表)、`kvcpu.c`(Execute 循环)、`runtime.c`(ABI 层)、`rwirext.c`(扩展宿主 ABI,含 `notinmyrwircaps`)、`logx.c`、`strbuf.c`、`const.h`。 myrwircaps 为**静态数组 + 线性查找**。 diff --git "a/stdlib/kvlang/spec/\351\231\204\345\275\225/07-\345\206\205\345\273\272\345\207\275\346\225\260.kv" "b/stdlib/kvlang/spec/\351\231\204\345\275\225/07-\345\206\205\345\273\272\345\207\275\346\225\260.kv" index 0bdc29a7..86f9013e 100644 --- "a/stdlib/kvlang/spec/\351\231\204\345\275\225/07-\345\206\205\345\273\272\345\207\275\346\225\260.kv" +++ "b/stdlib/kvlang/spec/\351\231\204\345\275\225/07-\345\206\205\345\273\272\345\207\275\346\225\260.kv" @@ -2,7 +2,7 @@ lib kvlang/spec/附录/内建函数 { r##"# 内建函数 -裸名内建(native,权威全集见 `runtime/src/builtin.c` 注册表): +裸名内建(native,权威全集见 `runtime/src/rwir_func.c` 注册表): ``` builtin_call = ( "abs" | "neg" | "sign" | "pow" | "sqrt" | "exp" | "log"