From 83f1bd585e5cc775b86ca62961b2eec61c459991 Mon Sep 17 00:00:00 2001 From: "peng.li24" <734991033@qq.com> Date: Mon, 24 Aug 2026 06:21:04 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=B0=83=E7=94=A8=E7=9B=AE=E6=A0=87?= =?UTF-8?q?=E7=BB=9F=E4=B8=80=20layout=20=E4=B8=BA=20rwir|rwfunc=20union?= =?UTF-8?q?=20kind?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - kvkind.rs 新增 KIND_RWIR_OR_RWFUNC;code.rs 调用目标 layout 为 rwir|rwfunc。 - runtime 按 /lib/ 的 XValue kind 分派扩展 rwir / 用户 rwfunc。 - const.h/xvalue.c/rwirext 示例同步;tutorial/07-lib 收敛到 single/。 Co-Authored-By: Claude --- layout/src/capi.rs | 45 +++++++++++- layout/src/code.rs | 72 +++++++------------ layout/src/kvkind.rs | 9 ++- layout/tests/pipeline_test.rs | 8 +-- layout/tests/redis_roundtrip_test.rs | 4 +- runtime-rwirext_example/go/json/json.go | 36 ++++++---- runtime-rwirext_example/py/numpy/numpy.py | 26 ++++--- runtime-rwirext_example/rust/term/src/main.rs | 18 ++--- runtime/src/const.h | 1 + runtime/src/xvalue.c | 2 +- tutorial/07-lib/lib.kv | 11 --- tutorial/07-lib/main.kv | 8 --- tutorial/07-lib/single/inline.kv | 2 +- tutorial/07-lib/single/lib.kv | 2 +- 14 files changed, 137 insertions(+), 107 deletions(-) delete mode 100644 tutorial/07-lib/lib.kv delete mode 100644 tutorial/07-lib/main.kv diff --git a/layout/src/capi.rs b/layout/src/capi.rs index d3e02b71..21d0e18e 100644 --- a/layout/src/capi.rs +++ b/layout/src/capi.rs @@ -16,7 +16,7 @@ use std::fs; use std::os::raw::c_char; use std::panic::catch_unwind; -use crate::{compile, format, init_dirs, vet, Kv}; +use crate::{compile, format, init_dirs, kvkind, vet, Kv}; /// 复刻 Go runtime / layout_file 的 findEntry:DFS /lib/ 找首个 `.init`,否则 "init"。 fn find_entry(kv: &mut Kv, prefix: &str) -> String { @@ -163,3 +163,46 @@ pub extern "C" fn kvlangLayoutFormat( } } } + +// ── kindexpr 解析 ABI ────────────────────────────────────────────────── +// kindexpr 语法唯一事实源在 layout(kindexpr.rs);解析能力导出为 C ABI, +// 供 runtime 之外的消费方(扩展宿主 term/numpy/json、byteseek…)读取 XValue head 时 +// 复用,杜绝各处手写 head 结构/解析造成的 ABI 漂移(#70 遗留的旧 kind[32] 结构即此类)。 + +/// kindexpr 解析结果(repr(C),内存布局 = i32,i32,[i32;8],i32,[u8;64])。 +#[repr(C)] +pub struct kvlangKindexpr { + pub ref_: i32, // 0=内联 1=软链接(*) 2=扩展句柄(@) + pub ndim: i32, // 维数(0=标量) + pub dims: [i32; 8], // 各维大小(前 ndim 项有效) + pub array_len: i32, // 元素总数(标量=1,多维=各维乘积) + pub kind: [u8; 64], // base kind,NUL 终止(如 "float64"、"char/utf8"、"rwir|rwfunc") +} + +/// 解析 XValue head 的 kindexpr 内容(NUL 终止串,含 */@ 前缀与 [dims])。 +/// 成功返回 0,失败(空指针/空串)返回 -1。 +#[no_mangle] +pub extern "C" fn kvlangKindexprParse(kindexpr: *const c_char, out: *mut kvlangKindexpr) -> i32 { + if kindexpr.is_null() || out.is_null() { + return -1; + } + let s = cstr(kindexpr); + if s.is_empty() { + return -1; + } + let (r, dims, kind) = kvkind::parse_kindexpr(s); + let out = unsafe { &mut *out }; + out.ref_ = r; + out.ndim = dims.len() as i32; + for (i, d) in dims.iter().enumerate() { + if i < 8 { + out.dims[i] = *d; + } + } + out.array_len = if dims.is_empty() { 1 } else { dims.iter().product() }; + let kb = kind.as_bytes(); + let n = kb.len().min(63); + out.kind[..n].copy_from_slice(&kb[..n]); + out.kind[n] = 0; + 0 +} diff --git a/layout/src/code.rs b/layout/src/code.rs index 11c30770..1de79aa2 100644 --- a/layout/src/code.rs +++ b/layout/src/code.rs @@ -11,7 +11,7 @@ use std::collections::HashMap; use super::ast::{Func, RwirDecl, Stmt}; use super::ffi::Kv; -use super::{builtin, ffi, keytree, kvkind, lower, parser, symbol}; +use super::{builtin, ffi, keytree, kvkind, lower, parser}; /// 创建基础目录 /lib/ 与 /vthread/(layout 前必须存在)。 pub fn init_dirs(kv: &mut Kv) -> Result<(), String> { @@ -30,23 +30,11 @@ pub fn compile(kv: &mut Kv, src: &str) -> Result<(), String> { return Err("parse: error-level diagnostics — refusing to load".to_string()); } - // 用户函数名 → 有效包名。layout 只对这些名字加包前缀(正向识别用户函数), - // 其余 opcode(native / 扩展 rwir)原样落盘,由 runtime 查 /lib/ 的 XValue kind 判定。 - let mut user_pkg: HashMap = HashMap::new(); - for func in &file.funcs { - let p = if func.pkg.is_empty() { file.package.clone() } else { func.pkg.clone() }; - user_pkg.insert(func.sig.name.clone(), p); - } - for decl in &file.rwir_decls { - let p = if decl.pkg.is_empty() { file.package.clone() } else { decl.pkg.clone() }; - user_pkg.insert(decl.sig.name.clone(), p); - } - let mut any_code = false; for func in &file.funcs { let pkg = if func.pkg.is_empty() { file.package.clone() } else { func.pkg.clone() }; let mut lowered = lower::lower_func(func); - write_func(kv, &pkg, &mut lowered, &user_pkg); + write_func(kv, &pkg, &mut lowered); any_code = true; } for decl in &file.rwir_decls { @@ -65,7 +53,7 @@ pub fn compile(kv: &mut Kv, src: &str) -> Result<(), String> { pkg: String::new(), }; let mut lowered = lower::lower_func(&init_fn); - write_func(kv, "", &mut lowered, &user_pkg); + write_func(kv, "", &mut lowered); any_code = true; } @@ -112,7 +100,7 @@ pub fn vet(src: &str) -> Result<(), String> { } /// 写函数到 /lib/:签名(rwfunc)、源码、参数 Ptr、指令体。 -pub fn write_func(kv: &mut Kv, pkg: &str, fn_: &mut Func, user_pkg: &HashMap) { +pub fn write_func(kv: &mut Kv, pkg: &str, fn_: &mut Func) { let mut type_map = lower::infer_types(fn_); lower::specialize(fn_, &type_map); let func_dir = keytree::lib_func(pkg, &fn_.sig.name); @@ -145,7 +133,7 @@ pub fn write_func(kv: &mut Kv, pkg: &str, fn_: &mut Func, user_pkg: &HashMap。 @@ -159,11 +147,11 @@ pub fn write_rwir_decl(kv: &mut Kv, decl: &RwirDecl) { } /// 将 body 写入 /lib/// 下。offset 起始 idx(顶层函数=1)。 -fn write_body(kv: &mut Kv, pkg: &str, name: &str, body: &[Stmt], type_map: &mut HashMap, offset: i32, user_pkg: &HashMap) { +fn write_body(kv: &mut Kv, pkg: &str, name: &str, body: &[Stmt], type_map: &mut HashMap, offset: i32) { let prefix = keytree::lib_func(pkg, name); let mut idx = offset; for st in body { - write_stmt(kv, st, &prefix, &mut idx, type_map, pkg, user_pkg); + write_stmt(kv, st, &prefix, &mut idx, type_map, pkg); } } @@ -174,7 +162,6 @@ fn write_stmt( idx: &mut i32, type_map: &mut HashMap, pkg: &str, - user_pkg: &HashMap, ) { match st { Stmt::Instruction(s) => { @@ -184,15 +171,7 @@ fn write_stmt( type_map.insert(w.clone(), s.write_types[j].clone()); } } - let (mut opcode, reads) = s.flat(); - if !pkg.is_empty() - && user_pkg.get(&opcode).map_or(false, |p| p == pkg) - && !opcode.contains(keytree::MEMBER_SEP) - && !opcode.starts_with("/lib/") - && symbol::lookup(&opcode).word != "assign" - { - opcode = format!("{pkg}{}{opcode}", keytree::MEMBER_SEP); - } + let (opcode, reads) = s.flat(); let target_char = if s.writes.len() == 1 && !s.write_types.is_empty() && kvkind::is_char_kind(&s.write_types[0]) { s.write_types[0].as_str() } else { @@ -201,7 +180,7 @@ fn write_stmt( let mut pairs: Vec<(String, Vec)> = Vec::with_capacity(1 + reads.len() + s.writes.len()); if !opcode.is_empty() { - pairs.push((format!("{prefix}/[{n},0]"), slot_value(&opcode, ""))); + pairs.push((format!("{prefix}/[{n},0]"), opcode_value(&opcode))); } for (j, r) in reads.iter().enumerate() { pairs.push((format!("{prefix}/[{n},-{}]", j + 1), slot_value(r, target_char))); @@ -218,7 +197,7 @@ fn write_stmt( let scope_prefix = format!("{prefix}/{}", s.label); let mut scope_idx = 0; for child in &s.body { - write_stmt_scope(kv, child, &scope_prefix, &mut scope_idx, type_map, pkg, prefix, user_pkg); + write_stmt_scope(kv, child, &scope_prefix, &mut scope_idx, type_map, pkg, prefix); } } _ => {} @@ -233,7 +212,6 @@ fn write_stmt_scope( type_map: &mut HashMap, pkg: &str, func_prefix: &str, - user_pkg: &HashMap, ) { match st { Stmt::Instruction(s) => { @@ -243,15 +221,7 @@ fn write_stmt_scope( type_map.insert(w.clone(), s.write_types[j].clone()); } } - let (mut opcode, reads) = s.flat(); - if !pkg.is_empty() - && user_pkg.get(&opcode).map_or(false, |p| p == pkg) - && !opcode.contains(keytree::MEMBER_SEP) - && !opcode.starts_with("/lib/") - && symbol::lookup(&opcode).word != "assign" - { - opcode = format!("{pkg}{}{opcode}", keytree::MEMBER_SEP); - } + let (opcode, reads) = s.flat(); let target_char = if s.writes.len() == 1 && !s.write_types.is_empty() && kvkind::is_char_kind(&s.write_types[0]) { s.write_types[0].as_str() } else { @@ -260,7 +230,7 @@ fn write_stmt_scope( let mut pairs: Vec<(String, Vec)> = Vec::with_capacity(1 + reads.len() + s.writes.len()); if !opcode.is_empty() { - pairs.push((format!("{scope_prefix}[{n},0]"), slot_value(&opcode, ""))); + pairs.push((format!("{scope_prefix}[{n},0]"), opcode_value(&opcode))); } for (j, r) in reads.iter().enumerate() { pairs.push((format!("{scope_prefix}[{n},-{}]", j + 1), slot_value(r, target_char))); @@ -277,13 +247,23 @@ fn write_stmt_scope( let child_prefix = format!("{func_prefix}/{}", s.label); let mut child_idx = 0; for child in &s.body { - write_stmt_scope(kv, child, &child_prefix, &mut child_idx, type_map, pkg, func_prefix, user_pkg); + write_stmt_scope(kv, child, &child_prefix, &mut child_idx, type_map, pkg, func_prefix); } } _ => {} } } +/// 调用目标 opcode 槽值:函数调用/运算符 → `rwir|rwfunc` 并列; +/// 控制/拷贝 opcode(return/goto/br/call/=)原样 `rwir`(非调用目标)。 +fn opcode_value(opcode: &str) -> Vec { + if matches!(opcode, "return" | "goto" | "br" | "call" | "=") { + kvkind::new_rwir(0, 0, opcode) + } else { + kvkind::new_rwir_union(opcode) + } +} + /// 将字面量/引用字符串编码为 XValue TLV(rwir 槽值)。 fn slot_value(val: &str, target_char: &str) -> Vec { if !is_literal(val) { @@ -350,11 +330,11 @@ mod tests { init_dirs(&mut kv).unwrap(); compile(&mut kv, "lib a {\nlib b {\nrwfunc f() -> (r:int64) {\n1 -> r\n}\n}\n}\n").unwrap(); - assert_eq!(kvkind::kind(&kv.get_one("/lib/a/b.f/[0,0]")), "rwfunc"); + assert_eq!(kvkind::kind(&kv.get_one("/lib/a/b.f/[0,0]")), "defrwfunc"); // 同 lib a 下再 layout 另一嵌套 lib c,验证 b.f 未被整库删除(增量合并) compile(&mut kv, "lib a {\nlib c {\nrwfunc g() -> (r:int64) {\n2 -> r\n}\n}\n}\n").unwrap(); - assert_eq!(kvkind::kind(&kv.get_one("/lib/a/b.f/[0,0]")), "rwfunc", "b.f 应保留"); - assert_eq!(kvkind::kind(&kv.get_one("/lib/a/c.g/[0,0]")), "rwfunc"); + assert_eq!(kvkind::kind(&kv.get_one("/lib/a/b.f/[0,0]")), "defrwfunc", "b.f 应保留"); + assert_eq!(kvkind::kind(&kv.get_one("/lib/a/c.g/[0,0]")), "defrwfunc"); } } diff --git a/layout/src/kvkind.rs b/layout/src/kvkind.rs index 43c4855f..4a04906c 100644 --- a/layout/src/kvkind.rs +++ b/layout/src/kvkind.rs @@ -24,6 +24,7 @@ pub const KIND_RWIR: &str = "rwir"; pub const KIND_RWFUNC: &str = "rwfunc"; pub const KIND_DEF_RWIR: &str = "defrwir"; pub const KIND_DEF_RWFUNC: &str = "defrwfunc"; +pub const KIND_RWIR_OR_RWFUNC: &str = "rwir|rwfunc"; pub const KIND_SCOPE: &str = "scope"; // ── 通用 XValue 字节访问器 ─────────────────────────────────────────── @@ -38,7 +39,7 @@ pub fn head(data: &[u8]) -> ffi::kvspaceHead_t { } /// 解析 head 的 kindexpr 内容 → (ref, dims, base kind)。 -fn parse_kindexpr(kx: &str) -> (i32, Vec, String) { +pub fn parse_kindexpr(kx: &str) -> (i32, Vec, String) { let (r, rest) = match kx.as_bytes().first() { Some(b'*') => (1, &kx[1..]), Some(b'@') => (2, &kx[1..]), @@ -138,6 +139,12 @@ pub fn new_rwir(nr: i32, nw: i32, sig: &str) -> Vec { ffi::tlv_encode(KIND_RWIR, &rwir_body(nr, nw, sig), 1) } +/// 调用目标(看起来像函数调用的 opcode)→ kindexpr `rwir|rwfunc` 并列。 +/// 静态无法判定是扩展 rwir 还是用户 rwfunc,交 runtime 查 /lib/ 的 XValue kind 分派。 +pub fn new_rwir_union(sig: &str) -> Vec { + ffi::tlv_encode(KIND_RWIR_OR_RWFUNC, &rwir_body(0, 0, sig), 1) +} + pub fn new_defrwir(nr: i32, nw: i32, sig: &str) -> Vec { ffi::tlv_encode(KIND_DEF_RWIR, &rwir_body(nr, nw, sig), 1) } diff --git a/layout/tests/pipeline_test.rs b/layout/tests/pipeline_test.rs index 96289a0b..6f20af4a 100644 --- a/layout/tests/pipeline_test.rs +++ b/layout/tests/pipeline_test.rs @@ -25,7 +25,7 @@ fn compile_simple_func() { // 函数签名 let sig_val = kv.get_one("/lib/sum/[0,0]"); - assert_eq!(kvkind::kind(&sig_val), "rwfunc"); + assert_eq!(kvkind::kind(&sig_val), "defrwfunc"); assert_eq!(kvkind::array_len(&sig_val), 1); let b = body(&sig_val); assert_eq!(kvkind::rwfunc_num_reads(b), 2); @@ -43,7 +43,7 @@ fn compile_simple_func() { // 指令(特化后 opcode = int64.add) let op = kv.get_one("/lib/sum/[1,0]"); - assert_eq!(kvkind::kind(&op), "rwir"); + assert_eq!(kvkind::kind(&op), "rwir|rwfunc"); assert_eq!(sig(&op), "int64.add"); assert_eq!(sig(&kv.get_one("/lib/sum/[1,-1]")), "A"); assert_eq!(sig(&kv.get_one("/lib/sum/[1,-2]")), "B"); @@ -62,7 +62,7 @@ fn compile_string_literal_and_lib() { // 函数在 /lib/p.hi/ 下(lib 块 pkg 前缀) let sig_val = kv.get_one("/lib/p.hi/[0,0]"); - assert_eq!(kvkind::kind(&sig_val), "rwfunc"); + assert_eq!(kvkind::kind(&sig_val), "defrwfunc"); // 字符串字面量读槽 → char/utf32(UTF-32 LE 码点) let r = kv.get_one("/lib/p.hi/[1,-1]"); @@ -98,7 +98,7 @@ fn compile_control_flow_lowers_to_blocks() { compile(&mut kv, src).unwrap(); let sig_val = kv.get_one("/lib/f/[0,0]"); - assert_eq!(kvkind::kind(&sig_val), "rwfunc"); + assert_eq!(kvkind::kind(&sig_val), "defrwfunc"); // 降级后存在 if/then 基本块(label 指令以 _label[coord] 扁平键存在;空 merge 块不落盘) let children = kv.list("/lib/f/", false, false); assert!(children.iter().any(|c| c.contains("_if_"))); diff --git a/layout/tests/redis_roundtrip_test.rs b/layout/tests/redis_roundtrip_test.rs index fb424f00..d6704ab0 100644 --- a/layout/tests/redis_roundtrip_test.rs +++ b/layout/tests/redis_roundtrip_test.rs @@ -35,12 +35,12 @@ fn redis_compile() { compile(&mut kv, src).unwrap(); let sig_val = kv.get_one("/lib/sum/[0,0]"); - assert_eq!(kvkind::kind(&sig_val), "rwfunc"); + assert_eq!(kvkind::kind(&sig_val), "defrwfunc"); let b = body(&sig_val); assert_eq!(kvkind::rwfunc_num_reads(b), 2); assert_eq!(kvkind::rwfunc_num_writes(b), 1); let op = kv.get_one("/lib/sum/[1,0]"); - assert_eq!(kvkind::kind(&op), "rwir"); + assert_eq!(kvkind::kind(&op), "rwir|rwfunc"); assert_eq!(String::from_utf8_lossy(&body(&op)[4..]), "int64.add"); } diff --git a/runtime-rwirext_example/go/json/json.go b/runtime-rwirext_example/go/json/json.go index 933e1d40..7e5767e6 100644 --- a/runtime-rwirext_example/go/json/json.go +++ b/runtime-rwirext_example/go/json/json.go @@ -6,7 +6,7 @@ package json // 后端(kvspace-c=shm / kvspace_durable=redis|fs)由 Makefile 经 CGO_LDFLAGS 注入, // 对齐 term 的 KVLANG_KVSPACE_LIB;扩展宿主自连 kvspace,不经 runtime。 #cgo CFLAGS: -I${SRCDIR}/../../../runtime/include -#cgo LDFLAGS: -L${SRCDIR}/../../../bin -lkvlang_runtime -Wl,-rpath,${SRCDIR}/../../../bin +#cgo LDFLAGS: -L${SRCDIR}/../../../bin -lkvlang_runtime -L${SRCDIR}/../../../layout/target/release -lkvlang_layout -Wl,-rpath,${SRCDIR}/../../../bin -Wl,-rpath,${SRCDIR}/../../../layout/target/release #include "kvlang_rwirext.h" #include #include @@ -24,19 +24,27 @@ extern int kvspaceDel(void *h, const char *const *keys, uint32_t nkeys, char * extern int kvspaceMkindex(void *h, const char *path, char *err, uint32_t err_cap); extern int kvspaceNewChar(const char *kind, const char *s, uint8_t **out, uint32_t *out_len); -// XValue 头(repr(C),对齐 kvspace ABI):kind+ndim+dims 即 kindexp,body 段靠 offset/len 定位。 +// XValue 头(repr(C),对齐 kvspace ABI):kindexpr 为唯一类型真相,body 段靠 offset/len 定位。 typedef struct { - uint8_t kind[32]; - uint8_t is_ptr; - int32_t array_len; - int32_t body_len; - int32_t body_offset; - int32_t ndim; - int32_t dims[8]; + uint8_t kindexpr[256]; + uint8_t ro; + uint32_t vid; + int32_t body_len; + int32_t body_offset; } kvspaceHead_t; extern int kvspaceDecodeHead(const uint8_t *data, uint32_t data_len, kvspaceHead_t *out); extern int kvspaceTlvEncode(const char *kind, const uint8_t *raw, uint32_t raw_len, const int32_t *dims, int32_t ndim, uint8_t **out, uint32_t *out_len); + +// kindexpr 解析(kvlang/layout 提供 ABI,唯一事实源):ref/ndim/dims/kind。 +typedef struct { + int32_t ref; + int32_t ndim; + int32_t dims[8]; + int32_t array_len; + uint8_t kind[64]; +} kvlangKindexpr; +extern int kvlangKindexprParse(const char *kindexpr, kvlangKindexpr *out); */ import "C" @@ -184,7 +192,11 @@ func parseTLV(data []byte) (kind string, raw []byte, arrLen int) { if C.kvspaceDecodeHead((*C.uint8_t)(unsafe.Pointer(&data[0])), C.uint32_t(len(data)), &h) != 0 { return "", nil, 0 } - kb := C.GoBytes(unsafe.Pointer(&h.kind[0]), 32) + var kx C.kvlangKindexpr + if C.kvlangKindexprParse((*C.char)(unsafe.Pointer(&h.kindexpr[0])), &kx) != 0 { + return "", nil, 0 + } + kb := C.GoBytes(unsafe.Pointer(&kx.kind[0]), 64) if i := bytes.IndexByte(kb, 0); i >= 0 { kb = kb[:i] } @@ -195,8 +207,8 @@ func parseTLV(data []byte) (kind string, raw []byte, arrLen int) { } raw = data[bo : bo+bl] arrLen = 1 - for i := 0; i < int(h.ndim); i++ { - arrLen *= int(h.dims[i]) + for i := 0; i < int(kx.ndim); i++ { + arrLen *= int(kx.dims[i]) } if arrLen < 1 { arrLen = 1 diff --git a/runtime-rwirext_example/py/numpy/numpy.py b/runtime-rwirext_example/py/numpy/numpy.py index f7d70390..324aad5f 100644 --- a/runtime-rwirext_example/py/numpy/numpy.py +++ b/runtime-rwirext_example/py/numpy/numpy.py @@ -51,10 +51,15 @@ def _find_lib(name, env, rel): class kvspace_head_t(ctypes.Structure): - _fields_ = [("kind", ctypes.c_uint8 * 32), ("is_ptr", ctypes.c_uint8), - ("array_len", ctypes.c_int32), ("body_len", ctypes.c_int32), - ("body_offset", ctypes.c_int32), ("ndim", ctypes.c_int32), - ("dims", ctypes.c_int32 * 8)] + _fields_ = [("kindexpr", ctypes.c_uint8 * 256), ("ro", ctypes.c_uint8), + ("vid", ctypes.c_uint32), ("body_len", ctypes.c_int32), + ("body_offset", ctypes.c_int32)] + + +class kvlang_kindexpr_t(ctypes.Structure): + _fields_ = [("ref", ctypes.c_int32), ("ndim", ctypes.c_int32), + ("dims", ctypes.c_int32 * 8), ("array_len", ctypes.c_int32), + ("kind", ctypes.c_uint8 * 64)] def _bind(): @@ -94,6 +99,8 @@ def _bind(): _lay.kvlangLayoutFile.restype = ctypes.c_int _lay.kvlangLayoutFile.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_uint32, ctypes.c_char_p, ctypes.c_uint32] + _lay.kvlangKindexprParse.restype = ctypes.c_int + _lay.kvlangKindexprParse.argtypes = [ctypes.c_char_p, ctypes.POINTER(kvlang_kindexpr_t)] _bind() @@ -234,17 +241,20 @@ def view(self, key): h = kvspace_head_t() if _ks.kvspaceDecodeHead(d, ol.value, ctypes.byref(h)) != 0: return None - kind = bytes(h.kind).split(b"\x00", 1)[0].decode() - if h.is_ptr or kind not in _KIND_CTYPE: + kx = kvlang_kindexpr_t() + if _lay.kvlangKindexprParse(ctypes.cast(h.kindexpr, ctypes.c_char_p), ctypes.byref(kx)) != 0: + return None + kind = bytes(kx.kind).split(b"\x00", 1)[0].decode() + if kx.ref != 0 or kind not in _KIND_CTYPE: return None elem = _KIND_CTYPE[kind] n = h.body_len // ctypes.sizeof(elem) base = ctypes.cast(d, ctypes.c_void_p).value ptr = ctypes.cast(base + h.body_offset, ctypes.POINTER(elem)) flat = np.ctypeslib.as_array(ptr, shape=(max(n, 1),)) - if h.ndim == 0: + if kx.ndim == 0: return flat[0] - return flat[:n].reshape(tuple(h.dims[i] for i in range(h.ndim))) + return flat[:n].reshape(tuple(kx.dims[i] for i in range(kx.ndim))) def alloc(self, key, arr): arr = np.asarray(arr) # 保形(ascontiguousarray 会把 0 维升 1 维) diff --git a/runtime-rwirext_example/rust/term/src/main.rs b/runtime-rwirext_example/rust/term/src/main.rs index 5fc06457..9612db75 100644 --- a/runtime-rwirext_example/rust/term/src/main.rs +++ b/runtime-rwirext_example/rust/term/src/main.rs @@ -17,16 +17,14 @@ struct kvlangRuntime_t { _p: [u8; 0], } -// 对齐 kvspace ABI 的 kvspaceHead_t(repr(C)):kind+ndim+dims 即完整 kindexp,body 段定位靠 offset/len。 +// 对齐 kvspace ABI 的 kvspaceHead_t(repr(C)):kindexpr 为唯一类型真相,body 段定位靠 offset/len。 #[repr(C)] struct kvspaceHead_t { - kind: [u8; 32], - is_ptr: u8, - array_len: i32, + kindexpr: [u8; 256], + ro: u8, + vid: u32, body_len: i32, body_offset: i32, - ndim: i32, - dims: [i32; 8], } unsafe impl Send for kvlangRuntime_t {} @@ -140,13 +138,11 @@ fn kv_get(kv: *mut c_void, key: &str) -> String { return String::new(); } let mut h = kvspaceHead_t { - kind: [0; 32], - is_ptr: 0, - array_len: 0, + kindexpr: [0; 256], + ro: 0, + vid: 0, body_len: 0, body_offset: 0, - ndim: 0, - dims: [0; 8], }; let s = if unsafe { kvspaceDecodeHead(out, out_len, &mut h) } == 0 && h.body_len > 0 diff --git a/runtime/src/const.h b/runtime/src/const.h index 5a3f0429..c6f7ae9c 100644 --- a/runtime/src/const.h +++ b/runtime/src/const.h @@ -28,6 +28,7 @@ #define KVSPACE_KIND_RWFUNC "rwfunc" #define KVSPACE_KIND_DEF_RWIR "defrwir" #define KVSPACE_KIND_DEF_RWFUNC "defrwfunc" +#define KVSPACE_KIND_RWIR_OR_RWFUNC "rwir|rwfunc" #define KVSPACE_KIND_SCOPE "scope" #define KVSPACE_KIND_TIME "time" #define KVSPACE_KIND_DURATION "duration" diff --git a/runtime/src/xvalue.c b/runtime/src/xvalue.c index a382d382..bbc3ca98 100644 --- a/runtime/src/xvalue.c +++ b/runtime/src/xvalue.c @@ -293,7 +293,7 @@ char *kvlangXvalueValueString(const kvlangXvalue_t *v) { } if (strcmp(k, KVSPACE_KIND_CHAR_UTF8) == 0 || strcmp(k, KVSPACE_KIND_CHAR_ASCII) == 0) return strndup2(body, blen); if (strcmp(k, KVSPACE_KIND_CHAR) == 0) return utf32_to_utf8(body, blen); - if (strcmp(k, KVSPACE_KIND_RWIR) == 0) return strndup2(body + (blen >= 4 ? 4 : 0), blen >= 4 ? blen - 4 : 0); + if (strcmp(k, KVSPACE_KIND_RWIR) == 0 || strcmp(k, KVSPACE_KIND_RWIR_OR_RWFUNC) == 0) return strndup2(body + (blen >= 4 ? 4 : 0), blen >= 4 ? blen - 4 : 0); if (strcmp(k, KVSPACE_KIND_RWFUNC) == 0) { kvlangStrbuf_t b; kvlangStrbufInit(&b); kvlangStrbufPrintf(&b, "r%d/w%d", (blen >= 2 ? rd16(body) : 0), (blen >= 4 ? rd16(body + 2) : 0)); diff --git a/tutorial/07-lib/lib.kv b/tutorial/07-lib/lib.kv deleted file mode 100644 index 6c315fb5..00000000 --- a/tutorial/07-lib/lib.kv +++ /dev/null @@ -1,11 +0,0 @@ -# lib.kv: 被导入的数学库(lib block 显式声明包名) -lib math { - rwfunc sum(A:int64, B:int64) -> (C:int64) { - A + B -> C - } - - rwfunc twice(A:int64) -> (R:int64) { - A × 2 -> R - A × 2 -> R_m - } -} diff --git a/tutorial/07-lib/main.kv b/tutorial/07-lib/main.kv deleted file mode 100644 index 6158e6e1..00000000 --- a/tutorial/07-lib/main.kv +++ /dev/null @@ -1,8 +0,0 @@ -# main.kv: import 示例——import 为文档级声明 -# 运行: kvlang run lib.kv main.kv -import math - -sum(3, 4) -> s -println(s) -twice(3) -> d -println(d) diff --git a/tutorial/07-lib/single/inline.kv b/tutorial/07-lib/single/inline.kv index 2fb5ed7e..b7100908 100644 --- a/tutorial/07-lib/single/inline.kv +++ b/tutorial/07-lib/single/inline.kv @@ -4,7 +4,7 @@ lib math { rwfunc sum(A:int64, B:int64) -> (C:int64) { A + B -> C } rwfunc init() -> () { - sum(3, 4) -> s + math.sum(3, 4) -> s println(s) } } diff --git a/tutorial/07-lib/single/lib.kv b/tutorial/07-lib/single/lib.kv index 40cd23a3..f0530893 100644 --- a/tutorial/07-lib/single/lib.kv +++ b/tutorial/07-lib/single/lib.kv @@ -2,7 +2,7 @@ lib math { rwfunc sum(A:int64, B:int64) -> (C:int64) { A + B -> C } rwfunc init() -> () { - sum(3, 4) -> s + math.sum(3, 4) -> s println(s) } }