Skip to content

Commit 8c8ffbe

Browse files
authored
Merge pull request #282 from array2d/wip/struct-and-layout
struct 语法高亮关键字 + layout/runtime/tutorial 进行中改动
2 parents d0471e3 + 3448ea4 commit 8c8ffbe

37 files changed

Lines changed: 696 additions & 211 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.14",
3-
"kvspace-c": "v0.2.14",
4-
"kvspace-durable": "v0.2.14",
2+
"kvspace": "v0.2.15",
3+
"kvspace-c": "v0.2.15",
4+
"kvspace-durable": "v0.2.15",
55
"blockmalloc": "v0.1.4",
66
"slotsboxmalloc": "v0.1.5"
77
}

extensions/kvlang/syntaxes/kvlang.tmLanguage.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
},
4747
"keyword": {
4848
"name": "keyword.control.kvlang",
49-
"match": "\\b(rwfunc|rwir|lib|if|else|for|while|break|continue|return)\\b"
49+
"match": "\\b(rwfunc|rwir|lib|struct|if|else|for|while|break|continue|return)\\b"
5050
},
5151
"block_label": {
5252
"name": "entity.name.label.kvlang",

layout/src/code.rs

Lines changed: 261 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
//! layoutcode(对齐 layout/layout.go):检查 AST 并把结果布局写到 /lib/ 下的结构化 KV。
22
//!
33
//! 存储约定:
4-
//! /lib/<pkg>·<name>/[0,0] 布局后签名(kind=rwfunc)
5-
//! /lib/<pkg>·<name>/<param> 命名参数→slot 指针(langtype=char, ref=1)
4+
//! /lib/<pkg>·<name>/[0,0] 布局后签名锚点(kind=rwfunc,body=计数头 [nr,nw,dyn]
5+
//! /lib/<pkg>·<name>/<param> 命名参数→slot 指针(langtype=该参类型, ref=1, body=坐标
66
//! /lib/<pkg>·<name>/[i,j] 编译后指令(kind=rwir),i 从 1 开始
77
//! /lib/<pkg>·<name>/‥labels/<l> label → irseq
8-
//! /lib/<pkg>·<name>.src 源码副本
8+
//! /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),
12+
//! 不读 .src、不依赖签名行 [0,x] 静态槽。
1113
1214
use std::collections::HashMap;
1315

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

@@ -173,15 +175,16 @@ pub fn dump(kv: &mut Kv, lib: &str) -> String {
173175
// prefix 本身就是函数目录:直接重建该函数(pkg/name 从路径反推)。
174176
let base = prefix.trim_start_matches("/lib/");
175177
let (fpkg, name) = func_identity("", base);
176-
let src = kvkind::value_string(&kv.get_one(&format!("{prefix}.src")));
178+
let dir = format!("{prefix}/");
179+
let text = reconstruct(kv, &dir, &name);
177180
let mut slots = Vec::new();
178-
collect_slots(kv, &format!("{prefix}/"), &mut slots);
181+
collect_slots(kv, &dir, &mut slots);
179182
funcs.push(DumpFunc {
180183
pkg: fpkg,
181184
name,
182-
src,
185+
text,
183186
slots,
184-
dir: format!("{prefix}/"),
187+
dir,
185188
});
186189
} else {
187190
// 虚拟 pkg:func dir 以 prefix 为前缀(`/lib/foo` 匹配 `/lib/foo·*` 与 `/lib/foo/*`)。
@@ -210,11 +213,11 @@ pub fn dump(kv: &mut Kv, lib: &str) -> String {
210213
out
211214
}
212215

213-
/// 一个可运行函数:源码(.src)+ 原始槽位注释。
216+
/// 一个可运行函数:从 /lib 子树重建的源码 + 原始槽位注释。
214217
struct DumpFunc {
215218
pkg: String,
216219
name: String,
217-
src: String,
220+
text: String,
218221
slots: Vec<String>,
219222
dir: String,
220223
}
@@ -262,13 +265,13 @@ fn collect_funcs(
262265
let mem_sub = format!("{prefix}{base}·");
263266
if is_func_dir(kv, &dir_sub) {
264267
let (fpkg, name) = func_identity(pkg, &base);
265-
let src = kvkind::value_string(&kv.get_one(&format!("{prefix}{base}.src")));
268+
let text = reconstruct(kv, &dir_sub, &name);
266269
let mut slots = Vec::new();
267270
collect_slots(kv, &dir_sub, &mut slots);
268271
funcs.push(DumpFunc {
269272
pkg: fpkg,
270273
name,
271-
src,
274+
text,
272275
slots,
273276
dir: dir_sub,
274277
});
@@ -342,7 +345,7 @@ fn emit_node(out: &mut String, node: &DumpNode, indent: &str) {
342345
}
343346

344347
fn emit_func(out: &mut String, f: &DumpFunc, indent: &str) {
345-
for line in f.src.lines() {
348+
for line in f.text.lines() {
346349
out.push_str(indent);
347350
out.push_str(line);
348351
out.push('\n');
@@ -360,6 +363,251 @@ fn emit_func(out: &mut String, f: &DumpFunc, indent: &str) {
360363
out.push('\n');
361364
}
362365

366+
// ── dump 重建:严格从 /lib 子树反出可运行 kvlang(不读 .src)─────────────
367+
//
368+
// 数据来源(对齐 write_func / spec「指令布局格式」):
369+
// 签名 ← [0,0] 计数头(nr,nw,dyn) + 命名参数 Ptr 键(langtype=类型、body=[0,±k] 定位读/写与序)
370+
// 函数体 ← 线性指令槽 [n,0]=opcode、[n,-j]=读参、[n,j]=写参(n 连续、scope 已拍平)
371+
// 控制流 ← ‥labels/<label>=irseq;goto/br 的整数读参即 irseq,映射回 label 名并按 irseq 切块
372+
// 重建成 AST(Func) 后复用其 Display/full_text,箭头一律规范化为 `->`(源箭头风格不落盘)。
373+
374+
/// 单个函数目录 → 可运行 kvlang 文本(签名 + 体)。
375+
fn reconstruct(kv: &mut Kv, dir: &str, name: &str) -> String {
376+
let (nr, nw, dynamic) = kvkind::counts(&kv.get_one(&format!("{dir}[0,0]")));
377+
let sig = reconstruct_sig(kv, dir, name, nr, nw, dynamic);
378+
let labels = read_labels(kv, dir);
379+
let insts = read_insts(kv, dir);
380+
let body = build_body(&insts, &labels);
381+
Func {
382+
comments: Vec::new(),
383+
sig,
384+
body,
385+
pkg: String::new(),
386+
}
387+
.full_text()
388+
}
389+
390+
/// 从命名参数 Ptr 键重建签名:类型取 Ptr langtype,读/写与序取 body 坐标 [0,±k]。
391+
fn reconstruct_sig(kv: &mut Kv, dir: &str, name: &str, nr: i32, nw: i32, dynamic: bool) -> FuncSig {
392+
let blank = || Param {
393+
name: String::new(),
394+
ty: String::new(),
395+
};
396+
let mut params: Vec<Param> = (0..nr).map(|_| blank()).collect();
397+
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;
405+
}
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;
418+
}
419+
}
420+
if dynamic {
421+
if let Some(p) = params.last_mut() {
422+
if !p.ty.is_empty() {
423+
p.ty.push_str("...");
424+
}
425+
}
426+
}
427+
FuncSig {
428+
name: name.to_string(),
429+
params,
430+
returns,
431+
}
432+
}
433+
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+
442+
/// ‥labels/ 子树 → (irseq, label),按 irseq 升序(体切块用)。
443+
fn read_labels(kv: &mut Kv, dir: &str) -> Vec<(i32, String)> {
444+
let ldir = format!("{dir}{}{}/", keytree::RUNTIME_MEMBER_SEP, keytree::SEG_LABELS);
445+
let mut out: Vec<(i32, String)> = kv
446+
.list(&ldir, false, true)
447+
.into_iter()
448+
.filter(|c| !c.ends_with('/'))
449+
.filter_map(|c| {
450+
let irseq: i32 = kvkind::plain(&kv.get_one(&format!("{ldir}{c}"))).parse().ok()?;
451+
Some((irseq, c))
452+
})
453+
.collect();
454+
out.sort_by_key(|(irseq, _)| *irseq);
455+
out
456+
}
457+
458+
/// 一条重建指令:opcode + 读操作数 + 写目标名。
459+
struct RawInst {
460+
opcode: String,
461+
reads: Vec<Operand>,
462+
writes: Vec<String>,
463+
}
464+
465+
/// 操作数:引用(变量/opcode/路径)、字符串字面量、其它字面量(数值/bool)。
466+
enum Operand {
467+
Ref(String),
468+
Str(String),
469+
Lit(String),
470+
}
471+
472+
/// 线性读回 [n,*](n 从 1 连续到首个空 opcode 前)。
473+
fn read_insts(kv: &mut Kv, dir: &str) -> Vec<RawInst> {
474+
let mut out = Vec::new();
475+
let mut n = 1;
476+
loop {
477+
let op = kv.get_one(&format!("{dir}[{n},0]"));
478+
if op.is_empty() {
479+
break;
480+
}
481+
let opcode = kvkind::rwir_sig(&op);
482+
let mut reads = Vec::new();
483+
let mut j = 1;
484+
loop {
485+
let d = kv.get_one(&format!("{dir}[{n},-{j}]"));
486+
if d.is_empty() {
487+
break;
488+
}
489+
reads.push(decode_operand(&d));
490+
j += 1;
491+
}
492+
let mut writes = Vec::new();
493+
let mut j = 1;
494+
loop {
495+
let d = kv.get_one(&format!("{dir}[{n},{j}]"));
496+
if d.is_empty() {
497+
break;
498+
}
499+
writes.push(kvkind::rwir_sig(&d));
500+
j += 1;
501+
}
502+
out.push(RawInst {
503+
opcode,
504+
reads,
505+
writes,
506+
});
507+
n += 1;
508+
}
509+
out
510+
}
511+
512+
/// 槽值 → Operand:rwir 族为引用/opcode 名,char 为字符串字面量,其余为明文字面量。
513+
fn decode_operand(data: &[u8]) -> Operand {
514+
let k = kvkind::kind(data);
515+
if matches!(k.as_str(), "rwir" | "rwir|rwfunc" | "rwfunc" | "def rwir") {
516+
Operand::Ref(kvkind::rwir_sig(data))
517+
} else if kvkind::is_char_kind(&k) {
518+
Operand::Str(kvkind::plain(data))
519+
} else {
520+
Operand::Lit(kvkind::plain(data))
521+
}
522+
}
523+
524+
fn operand_expr(o: &Operand) -> Expr {
525+
match o {
526+
Operand::Ref(s) | Operand::Lit(s) => ast::leaf(s),
527+
Operand::Str(s) => ast::str_lit(s),
528+
}
529+
}
530+
531+
/// goto/br 的整数读参 → label 名(查不到则原样保留数字)。
532+
fn label_leaf(o: &Operand, by_irseq: &HashMap<i32, String>) -> Expr {
533+
if let Operand::Lit(s) = o {
534+
if let Ok(n) = s.parse::<i32>() {
535+
if let Some(l) = by_irseq.get(&n) {
536+
return ast::leaf(l);
537+
}
538+
}
539+
}
540+
operand_expr(o)
541+
}
542+
543+
/// 线性指令 + labels → 语句序列:首 label 前为前导语句,各 label 段成 ScopeStmt。
544+
fn build_body(insts: &[RawInst], labels: &[(i32, String)]) -> Vec<Stmt> {
545+
let by_irseq: HashMap<i32, String> = labels.iter().map(|(i, l)| (*i, l.clone())).collect();
546+
let total = insts.len() as i32;
547+
let first = labels.first().map(|(i, _)| *i).unwrap_or(total + 1);
548+
let inst_stmt = |i: i32| Stmt::Instruction(build_inst(&insts[i as usize - 1], &by_irseq));
549+
let mut body: Vec<Stmt> = (1..first).map(inst_stmt).collect();
550+
for (bi, (start, label)) in labels.iter().enumerate() {
551+
let end = labels.get(bi + 1).map(|(i, _)| *i).unwrap_or(total + 1);
552+
body.push(Stmt::Scope(ScopeStmt {
553+
comments: Vec::new(),
554+
label: label.clone(),
555+
body: (*start..end).map(inst_stmt).collect(),
556+
}));
557+
}
558+
body
559+
}
560+
561+
/// (opcode, reads, writes) → Instruction(箭头规范化为 `->`;复用 Display 还原算子/糖)。
562+
fn build_inst(inst: &RawInst, by_irseq: &HashMap<i32, String>) -> Instruction {
563+
let expr = match inst.opcode.as_str() {
564+
"" => None,
565+
"return" => Some(ast::leaf("return")),
566+
"=" => inst.reads.first().map(operand_expr),
567+
"goto" => Some(ast::call(
568+
"goto",
569+
inst.reads
570+
.iter()
571+
.map(|o| label_leaf(o, by_irseq))
572+
.collect(),
573+
)),
574+
"br" => {
575+
let mut args = Vec::with_capacity(inst.reads.len());
576+
for (i, o) in inst.reads.iter().enumerate() {
577+
args.push(if i == 0 {
578+
operand_expr(o)
579+
} else {
580+
label_leaf(o, by_irseq)
581+
});
582+
}
583+
Some(ast::call("br", args))
584+
}
585+
op => Some(ast::call(op, inst.reads.iter().map(operand_expr).collect())),
586+
};
587+
// array·fill 首参即写目标 langtype(Display 隐去不回显),回填 write_types 恢复类型标注。
588+
// 且须用前置 `=` 式(arrow_left=true):parser 仅在前置标注式把写类型喂给 array·fill 首参,
589+
// 后置箭头式 `[5...] -> b:TYPE` 会丢弃该类型(parser 不对称),故这里强制前置式以保幂等。
590+
let is_fill = inst.opcode == "array·fill" && !inst.writes.is_empty();
591+
let write_types = if is_fill {
592+
let ty = match inst.reads.first() {
593+
Some(Operand::Str(s)) | Some(Operand::Ref(s)) | Some(Operand::Lit(s)) => s.clone(),
594+
None => String::new(),
595+
};
596+
let mut v = vec![String::new(); inst.writes.len()];
597+
v[0] = ty;
598+
v
599+
} else {
600+
Vec::new()
601+
};
602+
Instruction {
603+
comments: Vec::new(),
604+
expr,
605+
writes: inst.writes.clone(),
606+
write_types,
607+
arrow_left: is_fill,
608+
}
609+
}
610+
363611
/// 写函数到 /lib/:签名(rwfunc)、源码、参数 Ptr、指令体。
364612
pub fn write_func(kv: &mut Kv, pkg: &str, fn_: &mut Func) {
365613
let mut type_map = lower::infer_types(fn_);

0 commit comments

Comments
 (0)