Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions layout/src/kindexpr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
}
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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),
Expand All @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions layout/src/kvkind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down
12 changes: 6 additions & 6 deletions layout/src/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -531,7 +531,7 @@ fn infer_inst(inst: &Instruction, tm: &mut HashMap<String, String>) {
};
// 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;
Expand Down Expand Up @@ -598,15 +598,15 @@ fn infer_op_type(opcode: &str, reads: &[String], tm: &mut HashMap<String, String
return opcode.to_string();
}
if opcode == "obj" {
return "objindex".to_string();
return "object".to_string();
}
if opcode == "map" {
return "[]strkeymapindex".to_string();
return "[]stringkeymap".to_string();
}
if opcode == "kv·set" {
// 成员写 base.key = v(3 reads:base, key, value)→ base 是 obj/map。
if reads.len() >= 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();
}
Expand Down Expand Up @@ -732,7 +732,7 @@ fn specialize_inst(inst: &mut Instruction, tm: &HashMap<String, String>) {
// 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() };
}
}
Expand Down
10 changes: 9 additions & 1 deletion layout/src/scanner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,15 @@ pub fn scan(src: &str) -> Vec<Token> {
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 {
Expand Down
37 changes: 19 additions & 18 deletions runtime-rwirext_example/go/json/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -427,8 +427,9 @@ func u64bits(f float64) []byte {
}

// ── KV 子树 ↔ map[string]any ───────────────────────────────────────
// objindex(对象)/ strkeymapindex(数组)承载复杂结构:marker 在 path·,
// 成员在 path·<key>(key 恒字符串,数组下标为坐标段 [i])。后端按 · 成员自动维护 index。
// 值/索引分离:容器值(object/stringkeymap)存 p(无后缀,body 空,stringkeymap 的 dims 在 head);
// memindex 存 p·(kind=index,body=[4B count][names],成员列表唯一权威);成员在 p·<key>
// (key 恒字符串,数组下标为坐标段 [i])。后端按 · 成员自动维护 index 与 stringkeymap 兜底。

// 从 kvspace ABI(kvspaceConst)取的常量,扩展不硬编码分隔符/kind 字面量(#111)。
var (
Expand Down Expand Up @@ -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 控制字符一律拒绝(不静默丢键、不转义)。
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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)
}
Expand Down
12 changes: 6 additions & 6 deletions runtime-rwirext_example/go/json/tutorial/json.kv
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down
4 changes: 2 additions & 2 deletions runtime-rwirext_example/go/json/tutorial/json_roundtrip.kv
Original file line number Diff line number Diff line change
@@ -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"]}
Expand Down
Loading
Loading