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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ Conditions may be compound expressions: `if (7 % 2 != 0)` and `while (i < string
**Scalar:** `abs` `neg` `sign` `pow` `sqrt` `exp` `log` `min` `max` (variadic, e.g. `max(a,b,c)`) `debugger`\
**Types:** `bool` `int8` `int16` `int32` `int64` `uint8` `uint16` `uint32` `uint64` `float32` `float64` `char/utf8` `char/utf32` `char/ascii`\
**Collections:** `array` `at` `set` `has` `array.sort` `array.slice` `array.append` `dict`\
**Shape:** `xv.numel` `xv.dim` `xv.shape` `xv.at` `xv.set`\
**Shape:** `ndarray.numel` `ndarray.dim` `ndarray.shape` `xv.at` `xv.set`\
**KV tree:** `kv.get` `kv.set` `kv.del` `kv.deltree` `kv.list` `kv.mkindex` `kv.extindex` `kv.rmindexext` `kv.watch` `kv.has` `kv.at`\
**Strings:** `string.char` `string.ord` `string.len` `string.cmp` `string.find` `string.slice` `string.concat` `string.set`\
**Time:** `time.now` `time.sub` `time.add` `time.before` `time.after` `time/duration.nanos` `time/duration.as_nanos` (and `millis`/`seconds`/`minutes`/`hours` variants)\
Expand All @@ -223,7 +223,7 @@ Conditions may be compound expressions: `if (7 % 2 != 0)` and `while (i < string

```kv
a:int64 = [7, 2, 9, 4] # typed 1D array, = ≡ <-
xv.numel(a) -> n # 4
ndarray.numel(a) -> n # 4
at(a, 2) -> e # 9 (0-indexed)
set(a, 1, 99) -> a # modify element: a becomes [7, 99, 9, 4]
sort(a) -> sorted # sorted copy: [2, 4, 7, 9]
Expand Down
4 changes: 2 additions & 2 deletions README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ for (x in [7, 2, 9, 4]) { println(x) }
**标量:** `abs` `neg` `sign` `pow` `sqrt` `exp` `log` `min` `max`(变参,如 `max(a,b,c)`)`debugger`\
**类型:** `bool` `int8` `int16` `int32` `int64` `uint8` `uint16` `uint32` `uint64` `float32` `float64` `char/utf8` `char/utf32` `char/ascii`\
**容器:** `array` `at` `set` `has` `array.sort` `array.slice` `array.append` `dict`\
**形状:** `xv.numel` `xv.dim` `xv.shape` `xv.at` `xv.set`\
**形状:** `ndarray.numel` `ndarray.dim` `ndarray.shape` `xv.at` `xv.set`\
**KV 树:** `kv.get` `kv.set` `kv.del` `kv.deltree` `kv.list` `kv.mkindex` `kv.extindex` `kv.rmindexext` `kv.watch` `kv.has` `kv.at`\
**字符串:** `string.char` `string.ord` `string.len` `string.cmp` `string.find` `string.slice` `string.concat` `string.set`\
**时间:** `time.now` `time.sub` `time.add` `time.before` `time.after` `time/duration.nanos` `time/duration.as_nanos`(及 `millis`/`seconds`/`minutes`/`hours` 变体)\
Expand All @@ -220,7 +220,7 @@ for (x in [7, 2, 9, 4]) { println(x) }

```kv
a:int64 = [7, 2, 9, 4] # 带类型 1D 数组,= ≡ <-
xv.numel(a) -> n # 4
ndarray.numel(a) -> n # 4
at(a, 2) -> e # 9
set(a, 1, 99) -> a # 修改元素:a 变为 [7, 99, 9, 4]
sort(a) -> sorted # 排序副本:[2, 4, 7, 9]
Expand Down
10 changes: 10 additions & 0 deletions layout/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@
// 依赖 .so 已由 ci/deps.sh 安装到 /usr/lib;默认 kvspace-durable,KVLANG_KVSPACE_LIB=kvspace-c 时用 SHM 版。
fn main() {
println!("cargo:rerun-if-env-changed=KVLANG_KVSPACE_LIB");
let manifest = env!("CARGO_MANIFEST_DIR");
let array2d = format!("{manifest}/../.."); // array2d 工作区
let lib = std::env::var("KVLANG_KVSPACE_LIB").unwrap_or_else(|_| "kvspace_durable".into());
let dir = if lib == "kvspace_durable" {
format!("{array2d}/kvspace-durable/target/release")
} else {
format!("{array2d}/kvspace-c/build")
};
println!("cargo:rustc-link-search=native={dir}");
println!("cargo:rustc-link-lib=dylib={lib}");
println!("cargo:rustc-link-arg=-Wl,--disable-new-dtags");
println!("cargo:rustc-link-arg=-Wl,-rpath,{dir}");
}
24 changes: 9 additions & 15 deletions layout/src/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,9 @@ fn lower_for_with_cont(
let keys_slot = lg.tmp();
let key_slot = lg.tmp();
let is_obj = s.iter.op == "obj"
|| (s.iter.is_leaf() && matches!(tm.get(&s.iter.val), Some(t) if t == "objindex"));
|| s.iter.op == "map"
|| (s.iter.is_leaf()
&& matches!(tm.get(&s.iter.val), Some(t) if t == "objindex" || t == "[]strkeymapindex" || t == "strkeymapindex"));

// 迭代源:裸标识符直接原地遍历;表达式(如数组字面量)先物化到临时槽。
let mut init_body = Vec::new();
Expand All @@ -217,15 +219,7 @@ fn lower_for_with_cont(
if is_obj {
init_body.push(Stmt::Instruction(Instruction {
comments: Vec::new(),
expr: Some(ast::call("kv.list", vec![ast::leaf(&iter_slot)])),
writes: vec![keys_slot.clone()],
write_types: Vec::new(),
arrow_left: false,
eq: false,
}));
init_body.push(Stmt::Instruction(Instruction {
comments: Vec::new(),
expr: Some(ast::call("xv.numel", vec![ast::leaf(&keys_slot)])),
expr: Some(ast::call("kv.listlen", vec![ast::leaf(&iter_slot)])),
writes: vec![len_slot.clone()],
write_types: Vec::new(),
arrow_left: false,
Expand All @@ -234,7 +228,7 @@ fn lower_for_with_cont(
} else {
init_body.push(Stmt::Instruction(Instruction {
comments: Vec::new(),
expr: Some(ast::call("xv.numel", vec![ast::leaf(&iter_slot)])),
expr: Some(ast::call("ndarray.numel", vec![ast::leaf(&iter_slot)])),
writes: vec![len_slot.clone()],
write_types: Vec::new(),
arrow_left: false,
Expand Down Expand Up @@ -271,7 +265,7 @@ fn lower_for_with_cont(
if is_obj {
body_insts.push(Stmt::Instruction(Instruction {
comments: Vec::new(),
expr: Some(ast::call("xv.at", vec![ast::leaf(&keys_slot), ast::leaf(&idx_slot)])),
expr: Some(ast::call("kv.listn", vec![ast::leaf(&iter_slot), ast::leaf(&idx_slot)])),
writes: vec![key_slot.clone()],
write_types: Vec::new(),
arrow_left: false,
Expand Down Expand Up @@ -608,7 +602,7 @@ fn infer_op_type(opcode: &str, reads: &[String], tm: &mut HashMap<String, String
return "objindex".to_string();
}
if opcode == "map" {
return "strkeymapindex".to_string();
return "[]strkeymapindex".to_string();
}
if opcode == "kv.set" {
// 成员写 base.key = v(3 reads:base, key, value)→ base 是 obj/map。
Expand All @@ -618,10 +612,10 @@ fn infer_op_type(opcode: &str, reads: &[String], tm: &mut HashMap<String, String
return String::new();
}
match opcode {
"kvlen" | "xv.numel" | "xv.dim" | "string.len" | "string.ord" | "string.cmp" | "string.find" => {
"kvlen" | "ndarray.numel" | "ndarray.dim" | "kv.listlen" | "string.len" | "string.ord" | "string.cmp" | "string.find" => {
return "int64".to_string();
}
"xv.shape" => return "[]int64".to_string(),
"ndarray.shape" => return "[]int64".to_string(),
"kv.list" => return "[]char/utf8".to_string(),
"string.char" | "string.set" | "string.slice" | "string.concat" => return "char/utf32".to_string(),
"random.int63" => return "int64".to_string(),
Expand Down
62 changes: 59 additions & 3 deletions layout/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -755,10 +755,28 @@ impl Parser {
let s = inst.writes[0].clone();
let br = s.find('[').unwrap_or(s.len());
let arr = s[..br].to_string();
let idx = s[br + 1..s.len().saturating_sub(1)].to_string();
let idxs = s[br + 1..s.len().saturating_sub(1)].to_string();
let e = inst.expr.take();
let op = if arr.starts_with('/') { "kv.set" } else { "xv.set" };
inst.expr = Some(ast::call(op, vec![ast::leaf(&arr), ast::leaf(&idx), e.unwrap_or(ast::leaf(""))]));
// strkeymap 坐标写 m.[i,j] <- v:坐标段是成员名(kv.set 字符串键)。
let dot_coord = arr.ends_with('.');
let arr = arr.trim_end_matches('.').to_string();
let op = if dot_coord { "kv.set" } else if arr.starts_with('/') { "kv.set" } else { "xv.set" };
if dot_coord {
inst.expr = Some(ast::call(
op,
vec![ast::leaf(&arr), ast::str_lit(&format!("[{}]", idxs)), e.unwrap_or(ast::leaf(""))],
));
} else {
// 多维 compact 下标:arr[i,j] <- v 展开为 xv.set(arr, i, j, v)。
let mut args = vec![ast::leaf(&arr)];
for idx in idxs.split(',').map(|x| x.trim()) {
if !idx.is_empty() {
args.push(ast::leaf(idx));
}
}
args.push(e.unwrap_or(ast::leaf("")));
inst.expr = Some(ast::call(op, args));
}
inst.writes = vec![arr];
inst.write_types = Vec::new();
}
Expand Down Expand Up @@ -848,6 +866,26 @@ impl Parser {
left = ast::call("kv.get", vec![left, ast::str_lit(&field)]);
continue;
}
// strkeymap 坐标访问 m.[i,j]:坐标段是单个成员名(kv.get 字符串键)。
if self.peek().kind == Kind::LBrack {
self.advance();
let mut idxs = Vec::new();
while self.peek().kind != Kind::RBrack && self.peek().kind != Kind::EOF {
if self.eat(Kind::Comma) {
continue;
}
if let Some(idx) = self.parse_pratt(0) {
idxs.push(idx);
}
}
self.expect(Kind::RBrack);
let coord = format!(
"[{}]",
idxs.iter().map(|e| e.to_string()).collect::<Vec<_>>().join(",")
);
left = ast::call("kv.get", vec![left, ast::str_lit(&coord)]);
continue;
}
}
// 后缀索引
if self.peek().kind == Kind::LBrack {
Expand Down Expand Up @@ -1328,6 +1366,24 @@ impl Parser {
wtypes.push(String::new());
continue;
}
if t.kind == Kind::Ident && self.peek_at(1).kind == Kind::Dot && self.peek_at(2).kind == Kind::LBrack {
let mut w = self.advance().value; // base
w.push_str(&self.advance().value); // .
w.push_str(&self.advance().value); // [
let mut depth = 1i32;
while depth > 0 && self.peek().kind != Kind::EOF && self.peek().kind != Kind::Arrow {
if self.peek().kind == Kind::RBrack {
depth -= 1;
}
if self.peek().kind == Kind::LBrack {
depth += 1;
}
w.push_str(&self.advance().value);
}
writes.push(w);
wtypes.push(String::new());
continue;
}
let (name, typ) = self.parse_write_slot();
writes.push(name);
wtypes.push(typ);
Expand Down
43 changes: 38 additions & 5 deletions runtime-rwirext_example/go/json/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,28 @@ func constructTLV(kind string, raw []byte, arrLen int) []byte {
return C.GoBytes(unsafe.Pointer(out), C.int(ol))
}

// encodeTLVDims:显式 dims/ndim 编码(供 strkeymapindex 目录标记落 dims)。
func encodeTLVDims(kind string, raw []byte, dims []int32) []byte {
ck := cstr(kind)
defer C.free(unsafe.Pointer(ck))
var buf unsafe.Pointer
if len(raw) > 0 {
buf = C.CBytes(raw)
defer C.free(buf)
}
carr := make([]C.int32_t, len(dims))
for i, d := range dims {
carr[i] = C.int32_t(d)
}
var out *C.uint8_t
var ol C.uint32_t
if C.kvspaceTlvEncode(ck, (*C.uint8_t)(buf), C.uint32_t(len(raw)), &carr[0], C.int32_t(len(carr)), &out, &ol) != 0 || out == nil {
return nil
}
defer C.kvspaceBytesFree(out, ol)
return C.GoBytes(unsafe.Pointer(out), C.int(ol))
}

// ── JSON 值 ↔ TLV ───────────────────────────────────────────────────

func readInt(raw []byte) int64 {
Expand Down Expand Up @@ -382,6 +404,15 @@ func mkIndexMarker(kind string, names []string) []byte {
return constructTLV(kind, 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("strkeymapindex", body, dims)
}

// validateKey:JSON 对象 key 不能含影响 kvspace 存储分隔的字符(§5.4)。
// 空串、/ . [ ] \n \r \0 U+2025 及 ASCII 控制字符一律拒绝(不静默丢键、不转义)。
func validateKey(k string) error {
Expand Down Expand Up @@ -432,11 +463,11 @@ func writeObj(c unsafe.Pointer, path string, m map[string]any) error {
func writeArr(c unsafe.Pointer, path string, arr []interface{}) error {
keys := make([]string, len(arr))
for i := range arr {
keys[i] = strconv.Itoa(i)
keys[i] = fmt.Sprintf("[%d]", i)
}
setTLV(c, path+".", mkIndexMarker("strkeymapindex", keys))
setTLV(c, path+".", mkMapMarker(keys))
for i, v := range arr {
if err := writeValue(c, path+"."+strconv.Itoa(i), v); err != nil {
if err := writeValue(c, path+"."+fmt.Sprintf("[%d]", i), v); err != nil {
return err
}
}
Expand Down Expand Up @@ -469,14 +500,16 @@ func readObj(c unsafe.Pointer, path string) map[string]any {
func readArr(c unsafe.Pointer, path string) []interface{} {
idxs := make([]int, 0, 8)
for _, n := range list(c, path+".") {
if i, err := strconv.Atoi(n); err == nil {
s := strings.TrimPrefix(n, "[")
s = strings.TrimSuffix(s, "]")
if i, err := strconv.Atoi(s); err == nil {
idxs = append(idxs, i)
}
}
sort.Ints(idxs)
arr := make([]interface{}, len(idxs))
for i, idx := range idxs {
arr[i] = readValue(c, path+"."+strconv.Itoa(idx))
arr[i] = readValue(c, path+"."+fmt.Sprintf("[%d]", idx))
}
return arr
}
Expand Down
4 changes: 2 additions & 2 deletions runtime-rwirext_example/go/json/tutorial/json.kv
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ rwfunc main() -> () {
println("c =", /data2/grp/c)
println("cont =", /data2/cont)
println("scat =", /data2/scat)
xv.numel(/data2/cont) -> n1
xv.numel(/data2/scat) -> n2
ndarray.numel(/data2/cont) -> n1
ndarray.numel(/data2/scat) -> n2
println("len =", n1, n2)
}

Expand Down
Loading
Loading