diff --git a/layout/src/kindexpr.rs b/layout/src/kindexpr.rs index 1861b8a5..439fd3dc 100644 --- a/layout/src/kindexpr.rs +++ b/layout/src/kindexpr.rs @@ -15,8 +15,8 @@ fn known_kind(k: &str) -> bool { matches!( k, "bool" | "int8" | "int16" | "int32" | "int64" | "uint8" | "uint16" | "uint32" | "uint64" - | "float32" | "float64" | "char/utf32" | "char/utf8" | "char/ascii" | "objindex" - | "strkeymapindex" | "index" | "extindex" | "rwir" | "rwfunc" | "scope" | "time" + | "float32" | "float64" | "char/utf32" | "char/utf8" | "char/ascii" | "object" + | "stringkeymap" | "index" | "extindex" | "rwir" | "rwfunc" | "scope" | "time" | "duration" ) } @@ -132,11 +132,11 @@ mod tests { fn valid() { for e in [ "int64", "uint8", "float32", "bool", "any", - "char/utf8", "char/utf32", "char/ascii", "objindex", "strkeymapindex", "index", + "char/utf8", "char/utf32", "char/ascii", "object", "stringkeymap", "index", "[]float32", "[2]float32", "[2,3]float32", "[2,3,4]float64", "[?,768]float32", "[?,?]int8", "int64|float64", "[2,3]float32|float32", "[]float32|[]float64", - "bool|char/utf8", "index|objindex", + "bool|char/utf8", "index|object", "any...", "int64|float64...", "[]float32...", ] { assert!(valid_kindexpr(e), "{e} should be valid"); @@ -171,7 +171,7 @@ mod tests { let cases = [ ("int64", "int64", 0, &[][..], true), ("int64", "float64", 0, &[], false), - ("any", "objindex", 0, &[], true), + ("any", "object", 0, &[], true), ("any", "int4", 0, &[], true), ("char/utf8", "char/utf8", 0, &[], true), ("char/utf8", "char/utf32", 0, &[], false), @@ -186,7 +186,7 @@ mod tests { ("[2,3]float32|float32", "float64", 0, &[], false), ("[]float32|[]float64", "float64", 1, &[10], true), ("bool|char/utf8", "char/utf8", 0, &[], true), - ("index|objindex", "index", 0, &[], true), + ("index|object", "index", 0, &[], true), ]; for (expr, kind, ndim, dims, want) in cases { let got = match_kindexpr(expr, kind, ndim, dims); diff --git a/layout/src/kvkind.rs b/layout/src/kvkind.rs index 4a04906c..d528eb9c 100644 --- a/layout/src/kvkind.rs +++ b/layout/src/kvkind.rs @@ -14,8 +14,8 @@ pub const KIND_CHAR_ASCII: &str = "char/ascii"; pub const KIND_BOOL: &str = "bool"; pub const KIND_INT64: &str = "int64"; pub const KIND_FLOAT64: &str = "float64"; -pub const KIND_OBJ: &str = "objindex"; -pub const KIND_MAP: &str = "strkeymapindex"; +pub const KIND_OBJ: &str = "object"; +pub const KIND_MAP: &str = "stringkeymap"; pub const KIND_INDEX: &str = "index"; pub const KIND_EXT_INDEX: &str = "extindex"; diff --git a/layout/src/lower.rs b/layout/src/lower.rs index 7bf33fc7..568253dd 100644 --- a/layout/src/lower.rs +++ b/layout/src/lower.rs @@ -192,7 +192,7 @@ fn lower_for_with_cont( let is_obj = s.iter.op == "obj" || s.iter.op == "map" || (s.iter.is_leaf() - && matches!(tm.get(&s.iter.val), Some(t) if t == "objindex" || t == "[]strkeymapindex" || t == "strkeymapindex")); + && matches!(tm.get(&s.iter.val), Some(t) if t == "object" || t == "[]stringkeymap" || t == "stringkeymap")); // 迭代源:裸标识符直接原地遍历;表达式(如数组字面量)先物化到临时槽。 let mut init_body = Vec::new(); @@ -531,7 +531,7 @@ fn infer_inst(inst: &Instruction, tm: &mut HashMap) { }; // kv.set 成员形(3 读:base, key, val)是 void 无写槽,但 base 仍须推断为 obj/map(供 for-in / 成员访问) if e.op == "kv·set" && e.args.len() >= 3 && !e.args[0].val.contains('/') { - tm.entry(e.args[0].val.clone()).or_insert_with(|| "objindex".to_string()); + tm.entry(e.args[0].val.clone()).or_insert_with(|| "object".to_string()); } if inst.writes.is_empty() { return; @@ -598,15 +598,15 @@ fn infer_op_type(opcode: &str, reads: &[String], tm: &mut HashMap= 3 { - tm.entry(reads[0].clone()).or_insert_with(|| "objindex".to_string()); + tm.entry(reads[0].clone()).or_insert_with(|| "object".to_string()); } return String::new(); } @@ -732,7 +732,7 @@ fn specialize_inst(inst: &mut Instruction, tm: &HashMap) { // map 是散 key 数组(base[i]),保持 xv.at/xv.set 走散 key 下标路径。 if (e.op == "xv·at" || e.op == "xv·set") && !e.args.is_empty() { if let Some(t) = tm.get(&e.args[0].val) { - if t == "objindex" { + if t == "object" { e.op = if e.op == "xv·at" { "kv·get".to_string() } else { "kv·set".to_string() }; } } diff --git a/layout/src/scanner.rs b/layout/src/scanner.rs index eda83a3f..d58ef161 100644 --- a/layout/src/scanner.rs +++ b/layout/src/scanner.rs @@ -400,7 +400,15 @@ pub fn scan(src: &str) -> Vec { if i + 1 < src.len() && is_abs_path_start(src[i + 1]) { let start = i; i += 1; - while i < src.len() && !is_token_delim(src[i]) { + while i < src.len() { + // ·(U+00B7)在绝对路径里是路径字符,不是成员分隔符 + if src[i] == 0xC2 && i + 1 < src.len() && src[i + 1] == 0xB7 { + i += 2; + continue; + } + if is_token_delim(src[i]) { + break; + } i += 1; } tokens.push(Token { diff --git a/runtime-rwirext_example/go/json/json.go b/runtime-rwirext_example/go/json/json.go index 9756794f..c3f62694 100644 --- a/runtime-rwirext_example/go/json/json.go +++ b/runtime-rwirext_example/go/json/json.go @@ -230,7 +230,7 @@ func parseTLV(data []byte) (kind string, raw []byte, arrLen int) { } // constructTLV:char/utf8 走 kvspaceNewChar(显式长度,NUL 安全), -// 其余(数值/布尔/objindex 等)走 kvspaceTlvEncode(arrLen>1 → 一维 [arrLen])。 +// 其余(数值/布尔/object 等)走 kvspaceTlvEncode(arrLen>1 → 一维 [arrLen])。 func constructTLV(kind string, raw []byte, arrLen int) []byte { if kind == kindChar8 { buf := C.CBytes(raw) @@ -266,7 +266,7 @@ func constructTLV(kind string, raw []byte, arrLen int) []byte { return C.GoBytes(unsafe.Pointer(out), C.int(ol)) } -// encodeTLVDims:显式 dims/ndim 编码(供 strkeymapindex 目录标记落 dims)。 +// encodeTLVDims:显式 dims/ndim 编码(供 stringkeymap 容器值落 dims)。 func encodeTLVDims(kind string, raw []byte, dims []int32) []byte { ck := cstr(kind) defer C.free(unsafe.Pointer(ck)) @@ -427,8 +427,9 @@ func u64bits(f float64) []byte { } // ── KV 子树 ↔ map[string]any ─────────────────────────────────────── -// objindex(对象)/ strkeymapindex(数组)承载复杂结构:marker 在 path·, -// 成员在 path·(key 恒字符串,数组下标为坐标段 [i])。后端按 · 成员自动维护 index。 +// 值/索引分离:容器值(object/stringkeymap)存 p(无后缀,body 空,stringkeymap 的 dims 在 head); +// memindex 存 p·(kind=index,body=[4B count][names],成员列表唯一权威);成员在 p· +// (key 恒字符串,数组下标为坐标段 [i])。后端按 · 成员自动维护 index 与 stringkeymap 兜底。 // 从 kvspace ABI(kvspaceConst)取的常量,扩展不硬编码分隔符/kind 字面量(#111)。 var ( @@ -475,21 +476,19 @@ func cconst(name string) string { return C.GoString(s) } -func mkIndexMarker(kind string, names []string) []byte { +// memindex p·:kind=index,body=[4B count LE][names],成员列表唯一权威。 +func mkMemIndex(names []string) []byte { body := make([]byte, 4) binary.LittleEndian.PutUint32(body, uint32(len(names))) body = append(body, []byte(strings.Join(names, "\n"))...) - return constructTLV(kind, body, 1) + return constructTLV(kindIndex, body, 1) } -// strkeymapindex 目录标记:body 同上,dims=[len](恒一维坐标段 [i])。 -func mkMapMarker(names []string) []byte { - body := make([]byte, 4) - binary.LittleEndian.PutUint32(body, uint32(len(names))) - body = append(body, []byte(strings.Join(names, "\n"))...) - dims := []int32{int32(len(names))} - return encodeTLVDims(kindMap, body, dims) -} +// 容器值(无后缀 p):object body 空。 +func mkObjValue() []byte { return constructTLV(kindObj, nil, 1) } + +// 容器值(无后缀 p):stringkeymap body 空,dims=[n](恒一维坐标段 [i])。 +func mkMapValue(n int) []byte { return encodeTLVDims(kindMap, nil, []int32{int32(n)}) } // validateKey:JSON 对象 key 不能含影响 kvspace 存储分隔的字符(§5.4)。 // 空串、/ · [ ] \n \r \0 U+2025 及 ASCII 控制字符一律拒绝(不静默丢键、不转义)。 @@ -534,7 +533,8 @@ func writeObj(c unsafe.Pointer, path string, m map[string]any) error { keys = append(keys, k) } sort.Strings(keys) - setTLV(c, path+sep, mkIndexMarker(kindObj, keys)) + setTLV(c, path, mkObjValue()) + setTLV(c, path+sep, mkMemIndex(keys)) for _, k := range keys { if err := writeValue(c, path+sep+k, m[k]); err != nil { return err @@ -548,7 +548,8 @@ func writeArr(c unsafe.Pointer, path string, arr []interface{}) error { for i := range arr { keys[i] = fmt.Sprintf("[%d]", i) } - setTLV(c, path+sep, mkMapMarker(keys)) + setTLV(c, path, mkMapValue(len(arr))) + setTLV(c, path+sep, mkMemIndex(keys)) for i, v := range arr { if err := writeValue(c, path+sep+fmt.Sprintf("[%d]", i), v); err != nil { return err @@ -558,8 +559,8 @@ func writeArr(c unsafe.Pointer, path string, arr []interface{}) error { } func readValue(c unsafe.Pointer, path string) interface{} { - // · 成员容器(objindex/strkeymapindex) - kind, _, _ := parseTLV(getTLV(c, path+sep)) + // 容器值在 p(无后缀):object/stringkeymap(body 空,成员在 memindex p·) + kind, _, _ := parseTLV(getTLV(c, path)) if kind == kindObj { return readObj(c, path) } diff --git a/runtime-rwirext_example/go/json/tutorial/json.kv b/runtime-rwirext_example/go/json/tutorial/json.kv index ac2ace4d..c294ba64 100644 --- a/runtime-rwirext_example/go/json/tutorial/json.kv +++ b/runtime-rwirext_example/go/json/tutorial/json.kv @@ -26,12 +26,12 @@ rwfunc main() -> () { json·to(/data) -> j println("j =", j) json·from(j) -> /data2 - println("name =", /data2/name) - println("c =", /data2/grp/c) - println("cont =", /data2/cont) - println("scat =", /data2/scat) - ndarray·numel(/data2/cont) -> n1 - ndarray·numel(/data2/scat) -> n2 + println("name =", /data2·name) + println("c =", /data2·grp·c) + println("cont =", /data2·cont) + println("scat =", /data2·scat) + ndarray·numel(/data2·cont) -> n1 + ndarray·numel(/data2·scat) -> n2 println("len =", n1, n2) } diff --git a/runtime-rwirext_example/go/json/tutorial/json_roundtrip.kv b/runtime-rwirext_example/go/json/tutorial/json_roundtrip.kv index 6a032bf3..e41e1c96 100644 --- a/runtime-rwirext_example/go/json/tutorial/json_roundtrip.kv +++ b/runtime-rwirext_example/go/json/tutorial/json_roundtrip.kv @@ -1,9 +1,9 @@ -# json: json.to / json.from 往返(objindex / strkeymapindex 承载复杂结构) +# json: json.to / json.from 往返(object / stringkeymap 承载复杂结构) # extern: 需先启动 redis 与 json rwirext 两个外部进程 # 1) redis-server --port 6379 # 2) ./bin/json-rwirext & # 3) ./bin/kvlang <本文件> -# 语义: json·from(json) 把 JSON 反序列化进 KV 树(对象→objindex、数组→strkeymapindex、 +# 语义: json·from(json) 把 JSON 反序列化进 KV 树(对象→object、数组→stringkeymap、 # null→None 空字节);json·to(root) 把 KV 子树序列化回 JSON,二者无损等价。 # 期望输出: # roundtrip = {"a":[1,{"b":"x"}],"list":[{"x":1},{"y":2}],"mixed":[1,"a",true,null,3.14],"n":null,"s":["a","b"]} diff --git a/runtime/src/builtin.c b/runtime/src/builtin.c index c8e9d8b4..af023de7 100644 --- a/runtime/src/builtin.c +++ b/runtime/src/builtin.c @@ -774,22 +774,11 @@ static void pack_typed_array(const char *kind, const kvlangXvalue_t *elems, int free(raw); } -static char *separated_base(kvlangKv_t *kv, const char *fp, const char *name) { - char *base = kvlangBuiltinResolveWriteSlot(kv, fp, name); - kvlangStrbuf_t k; kvlangStrbufInit(&k); - kvlangStrbufPuts(&k, base); kvlangStrbufPuts(&k, ".[0]"); - kvlangXvalue_t v; kvlangXvalueZero(&v); - kvlangKvGetOne(kv, k.p, &v); - bool exists = !kvlangXvalueNone(&v); - kvlangXvalueFree(&v); kvlangStrbufFree(&k); - if (!exists) { free(base); return NULL; } - return base; -} - static int separated_len(kvlangKv_t *kv, const char *base) { for (int i = 0; ; i++) { kvlangStrbuf_t k; kvlangStrbufInit(&k); - kvlangStrbufPrintf(&k, "%s.[%d]", base, i); + 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); @@ -810,8 +799,8 @@ static char *scatter_key(const char *base, const int64_t *coords, int ncoord) { return kvlangStrbufDetach(&b); } -/* map 目录标记:kind=strkeymapindex,body=[4B count LE][name\n...],dims 落 head。 */ -static void map_marker(kvlangXvalue_t *out, const char *const *names, int n, const int32_t *dims, int ndim) { +/* memindex(p·):kind=index,body=[4B count LE][name\n...],成员列表唯一权威。 */ +static void memindex(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); @@ -819,10 +808,15 @@ static void map_marker(kvlangXvalue_t *out, const char *const *names, int n, con if (i) kvlangStrbufPutc(&body, '\n'); kvlangStrbufPuts(&body, names[i]); } - kvlangXvalueNewTlvDims(out, KVSPACE_KIND_MAP, (const uint8_t *)body.p, (uint32_t)body.len, dims, ndim); + kvlangXvalueNewTlv(out, KVSPACE_KIND_INDEX, (const uint8_t *)body.p, (uint32_t)body.len, 1); kvlangStrbufFree(&body); } +/* stringkeymap 容器值(p):body 空,dims 落 head。 */ +static void map_marker(kvlangXvalue_t *out, const int32_t *dims, int ndim) { + kvlangXvalueNewTlvDims(out, KVSPACE_KIND_MAP, (const uint8_t *)"", 0, dims, ndim); +} + /* ── array 系列 ───────────────────────────────────────────────────── */ static void ensure_scattered(kvlangFrame_t *f, const char *base) { @@ -998,10 +992,15 @@ int kvlangBuiltinScatter(kvlangFrame_t *f) { kvlangStrbuf_t s; kvlangStrbufInit(&s); kvlangStrbufPrintf(&s, "[%d]", i); names[i] = kvlangStrbufDetach(&s); } + char err[256]; int32_t dims[1] = { al }; - kvlangXvalue_t mark; map_marker(&mark, (const char *const *)names, al, dims, 1); - kvlangKvPair_t p0 = { dst, mark }; char err[256]; kvlangKvSet(f->kv, &p0, 1, err, sizeof err); + kvlangXvalue_t mark; map_marker(&mark, dims, 1); + kvlangKvPair_t p0 = { dst, mark }; kvlangKvSet(f->kv, &p0, 1, err, sizeof err); kvlangXvalueFree(&mark); + char *dir = kvlangKeytreeMember(dst, ""); + kvlangXvalue_t mi; memindex(&mi, (const char *const *)names, al); + kvlangKvPair_t p1 = { dir, mi }; kvlangKvSet(f->kv, &p1, 1, err, sizeof err); + kvlangXvalueFree(&mi); free(dir); for (int i = 0; i < al; i++) free(names[i]); free(names); } @@ -1089,18 +1088,44 @@ int kvlangBuiltinObj(kvlangFrame_t *f) { 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:kind=object,body 空。 */ kvlangXvalue_t mark; kvlangXvalueNewTlv(&mark, KVSPACE_KIND_OBJ, (const uint8_t *)"", 0, 1); kvlangKvPair_t p0 = { ok, mark }; - char err[256]; kvlangKvSet(f->kv, &p0, 1, err, sizeof err); + kvlangKvSet(f->kv, &p0, 1, err, sizeof err); kvlangXvalueFree(&mark); - for (int i = 0; i + 1 < n; i += 2) { + /* memindex p·:kind=index,body=[4B count][names]。 */ + char *mip = kvlangKeytreeMember(ok, ""); + kvlangXvalue_t mi; memindex(&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 *k = kvlangXvalueValueString(&in[i]); - char *mk = kvlangKeytreeMember(ok, k); + char *mk = kvlangKeytreeMember(ok, names[j]); kvlangKvPair_t p = { mk, in[i + 1] }; kvlangKvSet(f->kv, &p, 1, err, sizeof err); - free(k); free(mk); + free(mk); free(names[j]); j++; } + free(names); free(ok); } free(fr); @@ -1112,35 +1137,44 @@ int kvlangBuiltinMap(kvlangFrame_t *f) { 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); - /* 散 key 数组:元素在 ok.[i],目录标记(kind=strkeymapindex,dims=[n])在 ok。 */ - int old = separated_len(f->kv, ok); - for (int i = 0; i < old; i++) { - int64_t c[1] = { i }; - char *k = scatter_key(ok, c, 1); - char err[256]; kvlangKvDel(f->kv, k, err, sizeof err); free(k); + 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]); } - char err[256]; kvlangKvDel(f->kv, ok, err, sizeof err); + free(old); free(dir); + kvlangKvDel(f->kv, ok, err, sizeof err); char **names = malloc(sizeof(char *) * (size_t)(n > 0 ? n : 1)); - int64_t *cs = malloc(sizeof(int64_t) * (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); cs[i] = i; + names[i] = kvlangStrbufDetach(&s); } + /* 容器值 p:stringkeymap,body 空,dims=[n] 落 head。 */ int32_t dims[1] = { n }; - if (n > 0) { - kvlangXvalue_t mark; map_marker(&mark, (const char *const *)names, n, dims, 1); - kvlangKvPair_t p0 = { ok, mark }; - kvlangKvSet(f->kv, &p0, 1, err, sizeof err); - kvlangXvalueFree(&mark); - } + kvlangXvalue_t mark; map_marker(&mark, dims, 1); + kvlangKvPair_t p0 = { ok, mark }; + kvlangKvSet(f->kv, &p0, 1, err, sizeof err); + kvlangXvalueFree(&mark); + /* memindex p·:kind=index,body=[4B count][[0]\n[1]...]。 */ + char *mip = kvlangKeytreeMember(ok, ""); + kvlangXvalue_t mi; memindex(&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++) { - char *k = scatter_key(ok, &cs[i], 1); + int64_t c[1] = { i }; + char *k = scatter_key(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(cs); free(ok); + free(names); free(ok); } free(fr); next_pc(f); free_inputs(in, n); return 0; @@ -1466,26 +1500,29 @@ int kvlangBuiltinKvList(kvlangFrame_t *f) { char *fr = kvlangKeytreeFrameRoot(f->pc); char *dst = kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[0].name); free(fr); - /* 结果是一个 strkeymapindex:目录标记在 dst(dims=[count]),成员名是坐标段 [i], - * 值是对应的成员名字符串。 */ - if (count > 0) { - char **coords = malloc(sizeof(char *) * (size_t)count); - for (int i = 0; i < count; i++) { - kvlangStrbuf_t s; kvlangStrbufInit(&s); kvlangStrbufPrintf(&s, "[%d]", i); - coords[i] = kvlangStrbufDetach(&s); - } - int32_t dims[1] = { count }; - kvlangXvalue_t mark; map_marker(&mark, (const char *const *)coords, count, dims, 1); - kvlangKvPair_t p0 = { dst, mark }; char err[256]; kvlangKvSet(f->kv, &p0, 1, err, sizeof err); - kvlangXvalueFree(&mark); - for (int i = 0; i < count; i++) free(coords[i]); - free(coords); + /* 结果是一个 stringkeymap:容器值在 dst(body 空,dims=[count] 落 head), + * memindex 在 dst·,成员名是坐标段 [i],值是对应的成员名字符串。 */ + char **coords = malloc(sizeof(char *) * (size_t)(count > 0 ? count : 1)); + for (int i = 0; i < count; i++) { + kvlangStrbuf_t s; kvlangStrbufInit(&s); kvlangStrbufPrintf(&s, "[%d]", i); + coords[i] = kvlangStrbufDetach(&s); } + char err[256]; + int32_t dims[1] = { count }; + kvlangXvalue_t mark; map_marker(&mark, dims, 1); + kvlangKvPair_t p0 = { dst, mark }; kvlangKvSet(f->kv, &p0, 1, err, sizeof err); + kvlangXvalueFree(&mark); + char *dir = kvlangKeytreeMember(dst, ""); + kvlangXvalue_t mi; memindex(&mi, (const char *const *)coords, count); + kvlangKvPair_t p1 = { dir, mi }; kvlangKvSet(f->kv, &p1, 1, err, sizeof err); + kvlangXvalueFree(&mi); free(dir); + for (int i = 0; i < count; i++) free(coords[i]); + free(coords); for (int i = 0; i < count; i++) { int64_t c[1] = { i }; char *k = scatter_key(dst, c, 1); kvlangXvalue_t e; kvlangXvalueNewCharUtf8(&e, names[i]); - kvlangKvPair_t p = { k, e }; char err[256]; kvlangKvSet(f->kv, &p, 1, err, sizeof err); + kvlangKvPair_t p = { k, e }; kvlangKvSet(f->kv, &p, 1, err, sizeof err); kvlangXvalueFree(&e); free(k); free(names[i]); } for (int i = count; ; i++) { @@ -1494,7 +1531,7 @@ int kvlangBuiltinKvList(kvlangFrame_t *f) { kvlangXvalue_t v; kvlangXvalueZero(&v); kvlangKvGetOne(f->kv, k, &v); bool none = kvlangXvalueNone(&v); kvlangXvalueFree(&v); if (none) { free(k); break; } - char err[256]; kvlangKvDel(f->kv, k, err, sizeof err); free(k); + kvlangKvDel(f->kv, k, err, sizeof err); free(k); } free(names); free(dst); free(key); next_pc(f); free_inputs(in, n); return 0; diff --git a/runtime/src/const.h b/runtime/src/const.h index 2b5693bd..7ecbdc03 100644 --- a/runtime/src/const.h +++ b/runtime/src/const.h @@ -20,8 +20,8 @@ #define KVSPACE_KIND_CHAR "char/utf32" #define KVSPACE_KIND_CHAR_UTF8 "char/utf8" #define KVSPACE_KIND_CHAR_ASCII "char/ascii" -#define KVSPACE_KIND_OBJ "objindex" -#define KVSPACE_KIND_MAP "strkeymapindex" +#define KVSPACE_KIND_OBJ "object" +#define KVSPACE_KIND_MAP "stringkeymap" #define KVSPACE_KIND_INDEX "index" #define KVSPACE_KIND_EXT_INDEX "extindex" #define KVSPACE_KIND_RWIR "rwir" diff --git a/runtime/src/xvalue.c b/runtime/src/xvalue.c index bbc3ca98..ac211b15 100644 --- a/runtime/src/xvalue.c +++ b/runtime/src/xvalue.c @@ -303,11 +303,15 @@ char *kvlangXvalueValueString(const kvlangXvalue_t *v) { int n = blen >= 4 ? (int)rd32(body) : 0; kvlangStrbuf_t b; kvlangStrbufInit(&b); kvlangStrbufPrintf(&b, "(%d)", n); return kvlangStrbufDetach(&b); } - if (strcmp(k, KVSPACE_KIND_OBJ) == 0) { - int n = blen >= 4 ? (int)rd32(body) : 0; + if (strcmp(k, KVSPACE_KIND_OBJ) == 0) return strdup(KVSPACE_KIND_OBJ); + if (strcmp(k, KVSPACE_KIND_MAP) == 0) { kvlangStrbuf_t b; kvlangStrbufInit(&b); - if (n == 0) kvlangStrbufPuts(&b, KVSPACE_KIND_OBJ); - else kvlangStrbufPrintf(&b, "{%d}", n); + kvlangStrbufPuts(&b, "map["); + for (int d = 0; d < kx.ndim; d++) { + if (d) kvlangStrbufPutc(&b, ','); + kvlangStrbufPrintf(&b, "%d", kx.dims[d]); + } + kvlangStrbufPutc(&b, ']'); return kvlangStrbufDetach(&b); } return strndup2(body, blen); diff --git a/tutorial/04-ndarray/map_coord.kv b/tutorial/04-ndarray/map_coord.kv index c802b4a9..6dd9933c 100644 --- a/tutorial/04-ndarray/map_coord.kv +++ b/tutorial/04-ndarray/map_coord.kv @@ -1,4 +1,4 @@ -# strkeymap_coord: strkeymapindex 坐标段访问 a·[i] +# strkeymap_coord: stringkeymap 坐标段访问 a·[i] # 语义: {..} 创建 1 维散 key map,成员名是坐标段 "[i]",a·[i] 走 kv·get # 期望输出: # a[0] = 10