Skip to content

Commit b72a689

Browse files
authored
Merge pull request #288 from array2d/link-no-deref
2-runtime: link 不隐式穿透 + 指针身份比较(v0.2.16)
2 parents c0078f3 + 766e157 commit b72a689

37 files changed

Lines changed: 594 additions & 372 deletions

‎deps.json‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
2-
"kvspace": "v0.2.15",
3-
"kvspace-c": "v0.2.15",
4-
"kvspace-durable": "v0.2.15",
2+
"kvspace": "v0.2.16",
3+
"kvspace-c": "v0.2.16",
4+
"kvspace-durable": "v0.2.16",
55
"blockmalloc": "v0.1.4",
66
"slotsboxmalloc": "v0.1.5"
77
}

‎layout/src/code.rs‎

Lines changed: 76 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,20 @@
22
//!
33
//! 存储约定:
44
//! /lib/<pkg>·<name>/[0,0] 布局后签名锚点(kind=rwfunc,body=计数头 [nr,nw,dyn])
5-
//! /lib/<pkg>·<name>/<param> 命名参数→slot 指针(langtype=该参类型, ref=1, body=坐标)
5+
//! /lib/<pkg>·<name>.[0,±k] 参数定义键(langtype=def langtype, body=名字\x00类型)
66
//! /lib/<pkg>·<name>/[i,j] 编译后指令(kind=rwir),i 从 1 开始
77
//! /lib/<pkg>·<name>/‥labels/<l> label → irseq
88
//! /lib/<pkg>·<name>.src 源码副本(仅 write_func 保留写入,dump 不再依赖)
99
//!
1010
//! WriteBody: DFS-number insts (incl. ScopeStmt), emit [i,j], rewrite goto/br labels to irseq.
11-
//! dump: 反向——严格读 /lib/<pkg> 子树重建 AST(签名读命名参数 Ptr、体读线性槽+‥labels),
11+
//! dump: 反向——严格读 /lib/<pkg> 子树重建 AST(签名读参数定义键 .[0,±k]、体读线性槽+‥labels),
1212
//! 不读 .src、不依赖签名行 [0,x] 静态槽。
1313
1414
use std::collections::HashMap;
1515

16-
use super::ast::{self, Expr, Func, FuncSig, Instruction, Param, RwirDecl, ScopeStmt, Stmt, StructDecl};
16+
use super::ast::{
17+
self, Expr, Func, FuncSig, Instruction, Param, RwirDecl, ScopeStmt, Stmt, StructDecl,
18+
};
1719
use super::ffi::Kv;
1820
use super::{builtin, ffi, keytree, kvkind, lower, parser};
1921

@@ -387,34 +389,32 @@ fn reconstruct(kv: &mut Kv, dir: &str, name: &str) -> String {
387389
.full_text()
388390
}
389391

390-
/// 从命名参数 Ptr 键重建签名:类型取 Ptr langtype,读/写与序取 body 坐标 [0,±k]。
392+
/// 从参数定义键 base.[0,±k](点后缀)重建签名:body=名字\x00类型串。
391393
fn reconstruct_sig(kv: &mut Kv, dir: &str, name: &str, nr: i32, nw: i32, dynamic: bool) -> FuncSig {
392394
let blank = || Param {
393395
name: String::new(),
394396
ty: String::new(),
395397
};
396398
let mut params: Vec<Param> = (0..nr).map(|_| blank()).collect();
397399
let mut returns: Vec<Param> = (0..nw).map(|_| blank()).collect();
398-
for c in kv.list(dir, false, true) {
399-
if c.starts_with('[') || c.ends_with('/') || c.starts_with(keytree::RUNTIME_MEMBER_SEP) {
400-
continue; // 指令槽 / labels 目录 / 运行时保留字段
401-
}
402-
let data = kv.get_one(&format!("{dir}{c}"));
403-
if !kvkind::is_ptr(&data) {
404-
continue;
400+
let base = dir.trim_end_matches('/');
401+
for k in 1..=nr {
402+
if let Some((pname, pty)) =
403+
kvkind::def_param_parts(&kv.get_one(&format!("{base}.[0,-{k}]")))
404+
{
405+
params[(k - 1) as usize] = Param {
406+
name: pname,
407+
ty: pty,
408+
};
405409
}
406-
let ty = kvkind::langtype(&data);
407-
let (is_read, k) = match parse_slot_coord(&kvkind::ptr_target(&data)) {
408-
Some(v) => v,
409-
None => continue,
410-
};
411-
let slot = Param {
412-
name: c.clone(),
413-
ty,
414-
};
415-
let dst = if is_read { &mut params } else { &mut returns };
416-
if k >= 1 && (k as usize) <= dst.len() {
417-
dst[k as usize - 1] = slot;
410+
}
411+
for k in 1..=nw {
412+
if let Some((rname, rty)) = kvkind::def_param_parts(&kv.get_one(&format!("{base}.[0,{k}]")))
413+
{
414+
returns[(k - 1) as usize] = Param {
415+
name: rname,
416+
ty: rty,
417+
};
418418
}
419419
}
420420
if dynamic {
@@ -431,23 +431,21 @@ fn reconstruct_sig(kv: &mut Kv, dir: &str, name: &str, nr: i32, nw: i32, dynamic
431431
}
432432
}
433433

434-
/// 解析槽坐标 `[0,-1]`/`[0,1]` → (是否读参, |k|)。
435-
fn parse_slot_coord(s: &str) -> Option<(bool, i32)> {
436-
let inner = s.strip_prefix('[')?.strip_suffix(']')?;
437-
let col = inner.split(',').nth(1)?.trim();
438-
let n: i32 = col.parse().ok()?;
439-
Some((n < 0, n.abs()))
440-
}
441-
442434
/// ‥labels/ 子树 → (irseq, label),按 irseq 升序(体切块用)。
443435
fn read_labels(kv: &mut Kv, dir: &str) -> Vec<(i32, String)> {
444-
let ldir = format!("{dir}{}{}/", keytree::RUNTIME_MEMBER_SEP, keytree::SEG_LABELS);
436+
let ldir = format!(
437+
"{dir}{}{}/",
438+
keytree::RUNTIME_MEMBER_SEP,
439+
keytree::SEG_LABELS
440+
);
445441
let mut out: Vec<(i32, String)> = kv
446442
.list(&ldir, false, true)
447443
.into_iter()
448444
.filter(|c| !c.ends_with('/'))
449445
.filter_map(|c| {
450-
let irseq: i32 = kvkind::plain(&kv.get_one(&format!("{ldir}{c}"))).parse().ok()?;
446+
let irseq: i32 = kvkind::plain(&kv.get_one(&format!("{ldir}{c}")))
447+
.parse()
448+
.ok()?;
451449
Some((irseq, c))
452450
})
453451
.collect();
@@ -566,10 +564,7 @@ fn build_inst(inst: &RawInst, by_irseq: &HashMap<i32, String>) -> Instruction {
566564
"=" => inst.reads.first().map(operand_expr),
567565
"goto" => Some(ast::call(
568566
"goto",
569-
inst.reads
570-
.iter()
571-
.map(|o| label_leaf(o, by_irseq))
572-
.collect(),
567+
inst.reads.iter().map(|o| label_leaf(o, by_irseq)).collect(),
573568
)),
574569
"br" => {
575570
let mut args = Vec::with_capacity(inst.reads.len());
@@ -631,6 +626,15 @@ pub fn write_func(kv: &mut Kv, pkg: &str, fn_: &mut Func) {
631626
let mut labels: HashMap<String, i32> = HashMap::new();
632627
collect_insts(&fn_.body, &mut seq, &mut labels);
633628

629+
// 参数名 → *[0,±k](显式解引用坐标):函数体形参引用编译期替换,删命名参数 Ptr 运行时角色。
630+
let mut param_coord: HashMap<String, String> = HashMap::new();
631+
for (i, p) in fn_.sig.params.iter().enumerate() {
632+
param_coord.insert(p.name.clone(), format!("*[0,-{}]", i + 1));
633+
}
634+
for (i, r) in fn_.sig.returns.iter().enumerate() {
635+
param_coord.insert(r.name.clone(), format!("*[0,{}]", i + 1));
636+
}
637+
634638
// 按函数覆盖(文件夹复制式合并):只 del_tree 本函数子树,不动 /lib 下其它函数。
635639
// 禁止整库删除——layoutcode 必须可增量:多次 layout 各自覆盖其函数,不误删先前的函数。
636640
let _ = kv.del_tree(&func_dir);
@@ -649,26 +653,33 @@ pub fn write_func(kv: &mut Kv, pkg: &str, fn_: &mut Func) {
649653
keytree::lib_src(pkg, &fn_.sig.name),
650654
ffi::new_char_byte(fn_.full_text().as_bytes()),
651655
));
652-
// 命名参数键 funcDir/<name>:Ptr,body=帧坐标 [0,±k](k<0 读参、k>0 写参),
653-
// target_langtype=该参类型——类型随参数名承载。func dir 根不落 [0,±k] 静态槽:
654-
// 那些坐标是 runtime call 期写入的帧本地实参地址,若 layout 提前落在 func dir 根,
655-
// 建帧 extindex 时会把它们当只读扩展节点,令 call 期同坐标绑定触发 ext-write 保护。
656+
// 参数定义键 funcDir.[0,±k](点后缀,与坐标斜杠键 /[0,±k] 区分):langtype=def langtype,
657+
// body=名字\x00类型串。坐标斜杠键 [0,±k] 留给 runtime call 期写实参地址 Ptr;点后缀键
658+
// 不同名、不触发 extindex 写保护。函数体形参引用已替换为 *[0,±k] 显式解引用。
656659
for (i, p) in fn_.sig.params.iter().enumerate() {
657660
pairs.push((
658-
format!("{func_dir}/{}", p.name),
659-
ffi::new_ptr(&param_types[i], &format!("[0,-{}]", i + 1)),
661+
format!("{func_dir}.[0,-{}]", i + 1),
662+
kvkind::new_def_param(&p.name, &param_types[i]),
660663
));
661664
}
662665
for (i, r) in fn_.sig.returns.iter().enumerate() {
663666
pairs.push((
664-
format!("{func_dir}/{}", r.name),
665-
ffi::new_ptr(&param_types[nr as usize + i], &format!("[0,{}]", i + 1)),
667+
format!("{func_dir}.[0,{}]", i + 1),
668+
kvkind::new_def_param(&r.name, &param_types[nr as usize + i]),
666669
));
667670
}
668671
let _ = kv.set(&pairs);
669672

670673
for (i, inst) in seq.iter().enumerate() {
671-
write_linear_inst(kv, &func_dir, (i as i32) + 1, inst, &labels, &mut type_map);
674+
write_linear_inst(
675+
kv,
676+
&func_dir,
677+
(i as i32) + 1,
678+
inst,
679+
&labels,
680+
&mut type_map,
681+
&param_coord,
682+
);
672683
}
673684
if !labels.is_empty() {
674685
let _ = kv.mkindex(&keytree::lib_labels_dir(pkg, &fn_.sig.name));
@@ -715,6 +726,10 @@ pub fn write_struct_decl(kv: &mut Kv, decl: &StructDecl) {
715726
/// 字段默认值 XValue:head kind = 字段类型,body = 默认字面量(未给则零值)。
716727
/// 标量+char 直接编码;带 dims / structref 仅记录类型(空 body),嵌套 struct 待定。
717728
fn field_default(ty: &str, default: Option<&Expr>) -> Vec<u8> {
729+
// *T 指针字段:默认空指针(ref=1、langtype=目标 kindexpr、body 空)。
730+
if let Some(target) = ty.strip_prefix('*') {
731+
return ffi::new_ptr(target, "");
732+
}
718733
let (dims, base) = kvkind::parse_langtype(ty);
719734
let s = default.map(|e| e.val.clone()).unwrap_or_default();
720735
if base.starts_with("char/") {
@@ -753,8 +768,10 @@ pub fn write_rwir_decl(kv: &mut Kv, decl: &RwirDecl) {
753768
let param_types = decl.sig.langtype_list();
754769
let base = keytree::rwir(&opcode);
755770
// 路由头:仅计数头(无参数载荷);各参数类型落 [0,x] 签名行槽(def langtype)。
756-
let mut pairs: Vec<(String, Vec<u8>)> =
757-
vec![(base.clone(), kvkind::new_defrwir(nr, nw, decl.sig.dynamic()))];
771+
let mut pairs: Vec<(String, Vec<u8>)> = vec![(
772+
base.clone(),
773+
kvkind::new_defrwir(nr, nw, decl.sig.dynamic()),
774+
)];
758775
for i in 0..nr as usize {
759776
pairs.push((
760777
format!("{base}/[0,-{}]", i + 1),
@@ -804,6 +821,7 @@ fn write_linear_inst(
804821
s: &Instruction,
805822
labels: &HashMap<String, i32>,
806823
type_map: &mut HashMap<String, String>,
824+
params: &HashMap<String, String>,
807825
) {
808826
for (j, w) in s.writes.iter().enumerate() {
809827
if j < s.write_types.len() && !s.write_types[j].is_empty() {
@@ -841,13 +859,21 @@ fn write_linear_inst(
841859
pairs.push((format!("{prefix}/[{n},0]"), opcode_value(&opcode)));
842860
}
843861
for (j, r) in reads.iter().enumerate() {
862+
let rv = params
863+
.get(r.as_str())
864+
.map(String::as_str)
865+
.unwrap_or(r.as_str());
844866
pairs.push((
845867
format!("{prefix}/[{n},-{}]", j + 1),
846-
slot_value(r, target_char),
868+
slot_value(rv, target_char),
847869
));
848870
}
849871
for (j, w) in s.writes.iter().enumerate() {
850-
pairs.push((format!("{prefix}/[{n},{}]", j + 1), slot_value(w, "")));
872+
let wv = params
873+
.get(w.as_str())
874+
.map(String::as_str)
875+
.unwrap_or(w.as_str());
876+
pairs.push((format!("{prefix}/[{n},{}]", j + 1), slot_value(wv, "")));
851877
}
852878
if !pairs.is_empty() {
853879
let _ = kv.set(&pairs);

‎layout/src/kvkind.rs‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,27 @@ pub fn new_def_langtype(langtype: &str) -> Vec<u8> {
260260
ffi::tlv_encode(KIND_DEF_LANGTYPE, langtype.as_bytes(), 1)
261261
}
262262

263+
/// rwfunc 参数定义键(点后缀 .[0,-k]):body=名字\x00类型串,langtype=def langtype。
264+
pub fn new_def_param(name: &str, langtype: &str) -> Vec<u8> {
265+
let mut body = name.as_bytes().to_vec();
266+
body.push(0);
267+
body.extend_from_slice(langtype.as_bytes());
268+
ffi::tlv_encode(KIND_DEF_LANGTYPE, &body, 1)
269+
}
270+
271+
/// 解析参数定义键 body(名字\x00类型串)→ (名字, 类型)。
272+
pub fn def_param_parts(data: &[u8]) -> Option<(String, String)> {
273+
if data.is_empty() {
274+
return None;
275+
}
276+
let h = ffi::decode_head(data);
277+
let b = body(data, &h);
278+
let nul = b.iter().position(|&x| x == 0)?;
279+
let name = String::from_utf8_lossy(&b[..nul]).into_owned();
280+
let ty = String::from_utf8_lossy(&b[nul + 1..]).into_owned();
281+
Some((name, ty))
282+
}
283+
263284
// ── struct 原型(对齐 runtime kvlangBuiltinMemindex)─────────────────
264285
//
265286
// /lib/Name kind=struct,body="name:langtype\n..."(字段声明类型,供实例化类型校验)

‎layout/src/langtype.rs‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,11 @@ fn valid_key(s: &str) -> bool {
159159
}
160160

161161
/// atom = shape | mapexpr | structref;mapexpr = key "·" type;structref = "/" path。
162+
/// 最前 `*` 是 ref 前缀(Ptr 存储位置),校验剥离后剩余部分(见 [[类型表达式文法]])。
162163
fn valid_atom(s: &str) -> bool {
164+
if let Some(rest) = s.strip_prefix('*') {
165+
return !rest.is_empty() && valid_atom(rest);
166+
}
163167
if s.starts_with('/') {
164168
return valid_structref(s);
165169
}
@@ -178,13 +182,13 @@ pub fn valid_langtype(expr: &str) -> bool {
178182
/// `/lib/<name>`,使 kv 源可写 `x:Node` / `[int64]·Node`,runtime 恒收到完整 `/lib/…` 路径。
179183
/// 已 `/` 开头或 known kind 原样返回。mapexpr 只对 value 递归展开(key 恒 `[…]` 非 struct)。
180184
pub fn expand_struct_refs(s: &str) -> String {
181-
s.split('|')
182-
.map(expand_atom)
183-
.collect::<Vec<_>>()
184-
.join("|")
185+
s.split('|').map(expand_atom).collect::<Vec<_>>().join("|")
185186
}
186187

187188
fn expand_atom(s: &str) -> String {
189+
if let Some(rest) = s.strip_prefix('*') {
190+
return format!("*{}", expand_atom(rest));
191+
}
188192
if s.starts_with('/') {
189193
return s.to_string();
190194
}

‎layout/src/parser.rs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,9 +1240,14 @@ impl Parser {
12401240
return self.parse_pratt(UNARY_PREC);
12411241
}
12421242
// 一元前缀 & = 取址:&x ≡ kv·abs(x)(中缀 & 仍为按位与,走 pratt 中缀路径)。
1243+
// & 对成员链 kv·get(base, segs...) → kv·abs(base, segs...):取成员路径地址,非读值取址。
12431244
if symbol::lookup(&t.value).word == "bitand" {
12441245
let arg = self.parse_pratt(UNARY_PREC)?;
12451246
let op = format!("kv{}abs", keytree::MEMBER_SEP);
1247+
let get = format!("kv{}get", keytree::MEMBER_SEP);
1248+
if arg.op == get && arg.args.len() >= 2 {
1249+
return Some(ast::call(&op, arg.args));
1250+
}
12461251
return Some(ast::call(&op, vec![arg]));
12471252
}
12481253
let arg = self.parse_pratt(UNARY_PREC)?;

0 commit comments

Comments
 (0)