diff --git a/layout/src/builtin.rs b/layout/src/builtin.rs index 5bcf00ef..5220f802 100644 --- a/layout/src/builtin.rs +++ b/layout/src/builtin.rs @@ -170,7 +170,7 @@ fn native_rwir_set() -> &'static [&'static str] { "kv.get", "kv.set", "kv.del", "kv.deltree", "kv.list", "kv.mkindex", "kv.extindex", "kv.rmindexext", "kv.watch", // xv.* 形状内省与多维元素访问 - "xv.numel", "xv.dim", "xv.shape", "xv.at", "xv.set", + "xv.numel", "xv.dim", "xv.shape", "xv.at", "xv.set", "xv.reshape", ] } diff --git a/layout/src/lower.rs b/layout/src/lower.rs index 1eb81c9e..e2940642 100644 --- a/layout/src/lower.rs +++ b/layout/src/lower.rs @@ -536,6 +536,10 @@ fn infer_inst(inst: &Instruction, tm: &mut HashMap) { Some(e) => e, None => return, }; + // 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(|| "obj".to_string()); + } if inst.writes.is_empty() { return; } @@ -650,6 +654,9 @@ fn infer_op_type(opcode: &str, reads: &[String], tm: &mut HashMap { + return if !reads.is_empty() { slot_type(&reads[0], tm) } else { String::new() }; + } _ => {} } String::new() diff --git a/layout/src/parser.rs b/layout/src/parser.rs index 607c1ba8..5fed5543 100644 --- a/layout/src/parser.rs +++ b/layout/src/parser.rs @@ -539,19 +539,24 @@ impl Parser { }); }; let check = |p: &mut Self, inst: &Instruction, ro: &std::collections::HashSet, fname: &str| { - for (i, w) in inst.writes.iter().enumerate() { + // 写槽命中读参(非路径/索引/成员) + for w in inst.writes.iter() { if w.contains('/') || w.contains('[') || w.contains(keytree::MEMBER_SEP) { continue; } - if let Some(e) = &inst.expr { - if e.op == "set" && i == 0 && !e.args.is_empty() && w == &e.args[0].val { - continue; - } - } if ro.contains(w) { bad(p, w, fname); } } + // kv.set 成员形(3 读:base, key, val)改写 base 的成员目录,命中读参即拒绝 + if let Some(e) = &inst.expr { + if e.op == "kv.set" && e.args.len() >= 3 { + let base = &e.args[0].val; + if !base.contains('/') && ro.contains(base) { + bad(p, base, fname); + } + } + } }; let fname = func.sig.name.clone(); walk_read_only(self, &func.body, &ro, &fname, &check); @@ -1357,8 +1362,9 @@ impl Parser { ast::str_lit(&field) }; let e = inst.expr.take(); + // base.key = v 脱糖为 kv.set(base, key, val):kv.set 是 void(副作用写成员),无写槽 inst.expr = Some(ast::call("kv.set", vec![ast::leaf(&base), key, e.unwrap_or(ast::leaf(""))])); - inst.writes = vec![base]; + inst.writes = Vec::new(); inst.write_types = Vec::new(); } diff --git a/runtime/src/builtin.c b/runtime/src/builtin.c index b9d9d5ef..f5d0b93e 100644 --- a/runtime/src/builtin.c +++ b/runtime/src/builtin.c @@ -6,7 +6,7 @@ typedef int (*kvlangBuiltinFn)(kvlangFrame_t *f); /* collection 模块 handler(builtin_coll.c) */ int kvlangBuiltinArray(kvlangFrame_t *f), kvlangBuiltinXvNumel(kvlangFrame_t *f), kvlangBuiltinXvDim(kvlangFrame_t *f), kvlangBuiltinXvShape(kvlangFrame_t *f), - kvlangBuiltinXvAt(kvlangFrame_t *f), kvlangBuiltinXvSet(kvlangFrame_t *f), + kvlangBuiltinXvAt(kvlangFrame_t *f), kvlangBuiltinXvSet(kvlangFrame_t *f), kvlangBuiltinXvReshape(kvlangFrame_t *f), kvlangBuiltinScatter(kvlangFrame_t *f), kvlangBuiltinCompact(kvlangFrame_t *f), kvlangBuiltinAppend(kvlangFrame_t *f), kvlangBuiltinSlice(kvlangFrame_t *f), kvlangBuiltinObj(kvlangFrame_t *f), kvlangBuiltinMap(kvlangFrame_t *f), kvlangBuiltinStringSet(kvlangFrame_t *f), kvlangBuiltinStringChar(kvlangFrame_t *f), kvlangBuiltinStringOrd(kvlangFrame_t *f), kvlangBuiltinStringCmp(kvlangFrame_t *f), @@ -593,7 +593,7 @@ static const struct { const char *op; kvlangBuiltinFn fn; } builtins[] = { {"array.append", kvlangBuiltinAppend}, {"array.slice", kvlangBuiltinSlice}, {"obj", kvlangBuiltinObj}, {"map", kvlangBuiltinMap}, {"xv.numel", kvlangBuiltinXvNumel}, {"xv.dim", kvlangBuiltinXvDim}, {"xv.shape", kvlangBuiltinXvShape}, - {"xv.at", kvlangBuiltinXvAt}, {"xv.set", kvlangBuiltinXvSet}, + {"xv.at", kvlangBuiltinXvAt}, {"xv.set", kvlangBuiltinXvSet}, {"xv.reshape", kvlangBuiltinXvReshape}, {"string.set", kvlangBuiltinStringSet}, {"string.char", kvlangBuiltinStringChar}, {"string.ord", kvlangBuiltinStringOrd}, {"string.cmp", kvlangBuiltinStringCmp}, {"string.find", kvlangBuiltinStringFind}, {"string.len", kvlangBuiltinStringLen}, {"string.slice", kvlangBuiltinStringSlice}, {"string.concat", kvlangBuiltinStringConcat}, @@ -934,6 +934,7 @@ int kvlangBuiltinXvAt(kvlangFrame_t *f) { int kvlangBuiltinXvSet(kvlangFrame_t *f) { int nidx = f->inst->nr - 2; if (nidx < 1) return set_err(f, "TypeError: xv.set requires array, indices, value"); + if (f->inst->nw == 0) return set_err(f, "TypeError: xv.set requires a write param (-> a)"); kvlangXvalue_t in[MAX_PARAMS]; int n = read_inputs(f, in, MAX_PARAMS); const char *k = kvlangXvalueKind(&in[0]); int sz = kvlangXvalueElemSize(k); @@ -950,13 +951,43 @@ int kvlangBuiltinXvSet(kvlangFrame_t *f) { 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)h.body_len, h.dims, h.ndim); - char *fr = kvlangKeytreeFrameRoot(f->pc); - char *key = kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->reads[0].name); - free(fr); - kvlangKvPair_t p = { key, nv }; - char err[256]; kvlangKvSet(f->kv, &p, 1, err, sizeof err); - free(key); kvlangXvalueFree(&nv); free(nb); free_inputs(in, n); - next_pc(f); return 0; + int rc = write_result(f, &nv); + kvlangXvalueFree(&nv); free(nb); free_inputs(in, n); + return rc; +} + +int kvlangBuiltinXvReshape(kvlangFrame_t *f) { + int ndims = f->inst->nr - 1; + if (ndims < 1) return set_err(f, "TypeError: xv.reshape requires array and >=1 dims"); + if (f->inst->nw == 0) return set_err(f, "TypeError: xv.reshape requires a write param (-> a)"); + kvlangXvalue_t in[MAX_PARAMS]; int n = read_inputs(f, in, MAX_PARAMS); + const char *k = kvlangXvalueKind(&in[0]); + if (kvlangXvalueElemSize(k) <= 0) { free_inputs(in, n); return set_err(f, "TypeError: xv.reshape requires a compact array, got %s", k); } + kvspaceHead_t h; kvspaceDecodeHead(in[0].data, in[0].len, &h); + if (h.ndim < 1) { free_inputs(in, n); return set_err(f, "TypeError: xv.reshape requires a compact array, got scalar %s", k); } + if (ndims > X_MAX_NDIM) { free_inputs(in, n); return set_err(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)kvlangXvalueAsInt64(&in[i + 1]); + if (dims[i] < 0) { free_inputs(in, n); return set_err(f, "IndexError: xv.reshape: negative dim %d", dims[i]); } + numel *= dims[i]; + } + if (numel != h.array_len) { free_inputs(in, n); return set_err(f, "IndexError: xv.reshape: cannot reshape %d elements into %lld", h.array_len, (long long)numel); } + /* 原地改写:数组 head 形状段恒 X_MAX_NDIM×4=32B,改写 dims+ndim+padding,body 不搬 */ + uint8_t *data = in[0].data; + int32_t dims_off = 1 + (int32_t)data[0] + 2; + data[dims_off - 1] = (uint8_t)ndims; + memset(data + dims_off, 0, (size_t)(X_MAX_NDIM * 4)); + for (int i = 0; i < ndims; i++) { + uint32_t v = (uint32_t)dims[i]; + data[dims_off + i * 4] = (uint8_t)v; + data[dims_off + i * 4 + 1] = (uint8_t)(v >> 8); + data[dims_off + i * 4 + 2] = (uint8_t)(v >> 16); + data[dims_off + i * 4 + 3] = (uint8_t)(v >> 24); + } + int rc = write_result(f, &in[0]); + free_inputs(in, n); + return rc; } int kvlangBuiltinScatter(kvlangFrame_t *f) { @@ -1001,9 +1032,10 @@ int kvlangBuiltinCompact(kvlangFrame_t *f) { int kvlangBuiltinAppend(kvlangFrame_t *f) { if (f->inst->nr < 2) return set_err(f, "TypeError: array.append requires array and element"); + if (f->inst->nw == 0) return set_err(f, "TypeError: array.append requires a write param (-> arr)"); kvlangXvalue_t in[2]; int n = read_inputs(f, in, 2); char *fr = kvlangKeytreeFrameRoot(f->pc); - char *base = kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->reads[0].name); + char *base = kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[0].name); ensure_scattered(f, base); int len = separated_len(f->kv, base); kvlangStrbuf_t k; kvlangStrbufInit(&k); kvlangStrbufPrintf(&k, "%s[%d]", base, len); @@ -1015,9 +1047,10 @@ int kvlangBuiltinAppend(kvlangFrame_t *f) { int kvlangBuiltinSlice(kvlangFrame_t *f) { if (f->inst->nr < 3) return set_err(f, "TypeError: array.slice requires array, start, end"); + if (f->inst->nw == 0) return set_err(f, "TypeError: array.slice requires a write param (-> arr)"); kvlangXvalue_t in[3]; int n = read_inputs(f, in, 3); char *fr = kvlangKeytreeFrameRoot(f->pc); - char *base = kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->reads[0].name); + 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)kvlangXvalueAsInt64(&in[1]), hi = (int)kvlangXvalueAsInt64(&in[2]); diff --git a/runtime/src/runtime_internal.h b/runtime/src/runtime_internal.h index 5e8a9ad6..cae0892c 100644 --- a/runtime/src/runtime_internal.h +++ b/runtime/src/runtime_internal.h @@ -87,6 +87,7 @@ extern int kvspaceNewFloat64(double v, uint8_t **out, uint32_t *out_len); #define MAX_PARAMS 128 #define MAX_STACK_DEPTH 256 +#define X_MAX_NDIM 8 /* ── 基础类型 ──────────────────────────────────────────────────────── */ diff --git a/tutorial/04-ndarray/xv_shape.kv b/tutorial/04-ndarray/xv_shape.kv index 33b67813..c5dd188b 100644 --- a/tutorial/04-ndarray/xv_shape.kv +++ b/tutorial/04-ndarray/xv_shape.kv @@ -12,7 +12,7 @@ rwfunc main() -> () { println("shape0=", s[0]) xv.at(a, 1) -> e println("at1=", e) - xv.set(a, 1, 99) + xv.set(a, 1, 99) -> a println("set1=", a[1]) } main()