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 layout/examples/layout_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ use std::fs;

use kvlang_layout::{compile, init_dirs, Kv};

/// 复刻 Go runtime 的 findEntry:DFS /lib/ 找首个 `.init`,否则 "init"。
/// 复刻 Go runtime 的 findEntry:DFS /lib/ 找首个 `·init`,否则 "init"。
fn find_entry(kv: &mut Kv, prefix: &str) -> String {
let children = kv.list(prefix, false, true);
for c in &children {
let c = c.trim_end_matches('/');
if c.ends_with(".init") {
if c.ends_with("·init") {
return c.to_string();
}
let sub = format!("{prefix}{c}/");
Expand Down
4 changes: 2 additions & 2 deletions layout/src/capi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ use std::panic::catch_unwind;

use crate::{compile, format, init_dirs, kvkind, vet, Kv};

/// 复刻 Go runtime / layout_file 的 findEntry:DFS /lib/ 找首个 `.init`,否则 "init"。
/// 复刻 Go runtime / layout_file 的 findEntry:DFS /lib/ 找首个 `·init`,否则 "init"。
fn find_entry(kv: &mut Kv, prefix: &str) -> String {
for c in kv.list(prefix, false, true) {
let c = c.trim_end_matches('/');
if c.ends_with(".init") {
if c.ends_with("·init") {
return c.to_string();
}
let sub = format!("{prefix}{c}/");
Expand Down
20 changes: 10 additions & 10 deletions layout/src/code.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
//! layoutcode(对齐 layout/layout.go 的编译期部分):把 AST 写到 /lib/ 下的结构化 KV。
//!
//! 存储约定:
//! /lib/<pkg>.<name>/[0,0] 编译后签名(kind=rwfunc)
//! /lib/<pkg>.<name>/<param> 命名参数→slot 指针(kind=char, isptr=1)
//! /lib/<pkg>.<name>/[i,j] 编译后指令(kind=rwir),i 从 1 开始
//! /lib/<pkg>.<name>/<label>/ 基本块子路径(scope 指令)
//! /lib/<pkg>.<name>.src 源码副本
//! /lib/<pkg>·<name>/[0,0] 编译后签名(kind=rwfunc)
//! /lib/<pkg>·<name>/<param> 命名参数→slot 指针(kind=char, isptr=1)
//! /lib/<pkg>·<name>/[i,j] 编译后指令(kind=rwir),i 从 1 开始
//! /lib/<pkg>·<name>/<label>/ 基本块子路径(scope 指令)
//! /lib/<pkg>·<name>.src 源码副本

use std::collections::HashMap;

Expand Down Expand Up @@ -320,7 +320,7 @@ mod tests {

#[test]
fn format_preserves_lib() {
roundtrip("lib http {\n\trwfunc get(url:[]char/utf32) -> (resp:[]char/utf32) {\n\t\thttp.call(\"GET\", \"\", url, \"\") -> resp\n\t}\n}\n");
roundtrip("lib http {\n\trwfunc get(url:[]char/utf32) -> (resp:[]char/utf32) {\n\t\thttp·call(\"GET\", \"\", url, \"\") -> resp\n\t}\n}\n");
roundtrip("lib byteseek {\nlib session {\nlib s1 {\nrwfunc main() -> () {\n3 + 4 -> s\nprintln(s)\n}\n}\n}\n}\nmain()\n");
}

Expand All @@ -330,11 +330,11 @@ mod tests {
init_dirs(&mut kv).unwrap();

compile(&mut kv, "lib a {\nlib b {\nrwfunc f() -> (r:int64) {\n1 -> r\n}\n}\n}\n").unwrap();
assert_eq!(kvkind::kind(&kv.get_one("/lib/a/b.f/[0,0]")), "defrwfunc");
assert_eq!(kvkind::kind(&kv.get_one("/lib/a/b·f/[0,0]")), "defrwfunc");

// 同 lib a 下再 layout 另一嵌套 lib c,验证 b.f 未被整库删除(增量合并)
// 同 lib a 下再 layout 另一嵌套 lib c,验证 b·f 未被整库删除(增量合并)
compile(&mut kv, "lib a {\nlib c {\nrwfunc g() -> (r:int64) {\n2 -> r\n}\n}\n}\n").unwrap();
assert_eq!(kvkind::kind(&kv.get_one("/lib/a/b.f/[0,0]")), "defrwfunc", "b.f 应保留");
assert_eq!(kvkind::kind(&kv.get_one("/lib/a/c.g/[0,0]")), "defrwfunc");
assert_eq!(kvkind::kind(&kv.get_one("/lib/a/b·f/[0,0]")), "defrwfunc", "b·f 应保留");
assert_eq!(kvkind::kind(&kv.get_one("/lib/a/c·g/[0,0]")), "defrwfunc");
}
}
6 changes: 3 additions & 3 deletions layout/src/keytree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

// ── 常量 ─────────────────────────────────────────────────────────────

pub const MEMBER_SEP: &str = "."; // 成员访问分隔符
pub const MEMBER_SEP: &str = "·"; // 成员访问分隔符(U+00B7 中点号):释放 '.' 供小数 key 使用
pub const RUNTIME_MEMBER_SEP: &str = "\u{2025}"; // U+2025,运行时保留字段前缀
pub const PATH_SEG_SEP: &str = "/"; // 路径分隔符
pub const PATH_SEG_LIB: &str = "lib"; // /lib
Expand Down Expand Up @@ -33,15 +33,15 @@ pub fn lib_func(pkg: &str, name: &str) -> String {
if pkg.is_empty() {
format!("{LIB_ROOT}/{name}")
} else {
format!("{LIB_ROOT}/{pkg}.{name}")
format!("{LIB_ROOT}/{pkg}{MEMBER_SEP}{name}")
}
}

pub fn lib_src(pkg: &str, name: &str) -> String {
if pkg.is_empty() {
format!("{LIB_ROOT}/{name}{SRC_EXT}")
} else {
format!("{LIB_ROOT}/{pkg}.{name}{SRC_EXT}")
format!("{LIB_ROOT}/{pkg}{MEMBER_SEP}{name}{SRC_EXT}")
}
}

Expand Down
42 changes: 21 additions & 21 deletions layout/src/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use std::collections::HashMap;

use super::ast::{self, Expr, Func, Instruction, LitKind, Stmt};
use super::{builtin, symbol};
use super::{builtin, keytree, symbol};

// ── 控制流 lowering(续体传递风格) ──────────────────────────────────

Expand Down Expand Up @@ -218,7 +218,7 @@ fn lower_for_with_cont(
if is_obj {
init_body.push(Stmt::Instruction(Instruction {
comments: Vec::new(),
expr: Some(ast::call("kv.listlen", vec![ast::leaf(&iter_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 @@ -227,7 +227,7 @@ fn lower_for_with_cont(
} else {
init_body.push(Stmt::Instruction(Instruction {
comments: Vec::new(),
expr: Some(ast::call("ndarray.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 @@ -264,15 +264,15 @@ fn lower_for_with_cont(
if is_obj {
body_insts.push(Stmt::Instruction(Instruction {
comments: Vec::new(),
expr: Some(ast::call("kv.listn", vec![ast::leaf(&iter_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,
eq: false,
}));
body_insts.push(Stmt::Instruction(Instruction {
comments: Vec::new(),
expr: Some(ast::call("kv.get", vec![ast::leaf(&iter_slot), ast::leaf(&key_slot)])),
expr: Some(ast::call("kv·get", vec![ast::leaf(&iter_slot), ast::leaf(&key_slot)])),
writes: vec![s.var.clone()],
write_types: Vec::new(),
arrow_left: false,
Expand All @@ -281,7 +281,7 @@ fn lower_for_with_cont(
} else {
body_insts.push(Stmt::Instruction(Instruction {
comments: Vec::new(),
expr: Some(ast::call("xv.at", vec![ast::leaf(&iter_slot), ast::leaf(&idx_slot)])),
expr: Some(ast::call("xv·at", vec![ast::leaf(&iter_slot), ast::leaf(&idx_slot)])),
writes: vec![s.var.clone()],
write_types: Vec::new(),
arrow_left: false,
Expand Down Expand Up @@ -530,7 +530,7 @@ fn infer_inst(inst: &Instruction, tm: &mut HashMap<String, String>) {
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('/') {
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());
}
if inst.writes.is_empty() {
Expand All @@ -545,7 +545,7 @@ fn infer_inst(inst: &Instruction, tm: &mut HashMap<String, String>) {
let inferred = lit_to_type(e.lit);
if !inferred.is_empty() {
for w in &inst.writes {
if w.is_empty() || w.starts_with('.') {
if w.is_empty() || w.starts_with(keytree::MEMBER_SEP) {
continue;
}
tm.entry(w.clone()).or_insert_with(|| inferred.to_string());
Expand All @@ -562,7 +562,7 @@ fn infer_inst(inst: &Instruction, tm: &mut HashMap<String, String>) {
return;
}
for w in &inst.writes {
if w.is_empty() || w.starts_with('.') {
if w.is_empty() || w.starts_with(keytree::MEMBER_SEP) {
continue;
}
tm.entry(w.clone()).or_insert_with(|| inferred.clone());
Expand Down Expand Up @@ -603,28 +603,28 @@ fn infer_op_type(opcode: &str, reads: &[String], tm: &mut HashMap<String, String
if opcode == "map" {
return "[]strkeymapindex".to_string();
}
if opcode == "kv.set" {
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());
}
return String::new();
}
match opcode {
"kvlen" | "ndarray.numel" | "ndarray.dim" | "kv.listlen" | "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();
}
"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(),
"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(),
"random.intn" | "random.uint64" => return "uint64".to_string(),
"random·intn" | "random.uint64" => return "uint64".to_string(),
"pow" | "sqrt" | "exp" | "log" => return "float64".to_string(),
"sign" => return "int64".to_string(),
"abs" | "neg" | "max" | "min" => {
return if !reads.is_empty() { slot_type(&reads[0], tm) } else { String::new() };
}
"xv.at" => {
"xv·at" => {
if !reads.is_empty() {
if let Some(t) = tm.get(&format!("{}.0", reads[0])) {
return t.clone();
Expand All @@ -637,7 +637,7 @@ fn infer_op_type(opcode: &str, reads: &[String], tm: &mut HashMap<String, String
}
return String::new();
}
"xv.set" => {
"xv·set" => {
if let Some(last) = reads.last() {
let t = slot_type(last, tm);
if !t.is_empty() {
Expand All @@ -647,7 +647,7 @@ fn infer_op_type(opcode: &str, reads: &[String], tm: &mut HashMap<String, String
}
return if !reads.is_empty() { slot_type(&reads[0], tm) } else { String::new() };
}
"xv.reshape" => {
"xv·reshape" => {
return if !reads.is_empty() { slot_type(&reads[0], tm) } else { String::new() };
}
_ => {}
Expand Down Expand Up @@ -730,10 +730,10 @@ fn specialize_inst(inst: &mut Instruction, tm: &HashMap<String, String>) {
}
// xv.at/xv.set 基座是 obj → 降为 kv.get/kv.set(命名成员目录访问)。
// map 是散 key 数组(base[i]),保持 xv.at/xv.set 走散 key 下标路径。
if (e.op == "xv.at" || e.op == "xv.set") && !e.args.is_empty() {
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" {
e.op = if e.op == "xv.at" { "kv.get".to_string() } else { "kv.set".to_string() };
e.op = if e.op == "xv·at" { "kv·get".to_string() } else { "kv·set".to_string() };
}
}
}
Expand Down Expand Up @@ -764,5 +764,5 @@ fn specialize_inst(inst: &mut Instruction, tm: &HashMap<String, String>) {
if k.is_empty() {
return;
}
e.op = format!("{k}.{word}");
e.op = format!("{k}{}{word}", keytree::MEMBER_SEP);
}
39 changes: 23 additions & 16 deletions layout/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,8 @@ impl Parser {
if self.peek().kind == Kind::Ident {
decl.sig.name = self.advance().value;
if self.peek().kind == Kind::Dot {
decl.sig.name.push_str(&self.advance().value); // .
self.advance(); // .
decl.sig.name.push_str(keytree::MEMBER_SEP);
if self.peek().kind == Kind::Ident {
decl.sig.name.push_str(&self.advance().value);
}
Expand Down Expand Up @@ -550,7 +551,7 @@ impl Parser {
}
// kv.set 成员形(3 读:base, key, val)改写 base 的成员目录,命中读参即拒绝
if let Some(e) = &inst.expr {
if e.op == "kv.set" && e.args.len() >= 3 {
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);
Expand Down Expand Up @@ -757,10 +758,10 @@ impl Parser {
let arr = s[..br].to_string();
let idxs = s[br + 1..s.len().saturating_sub(1)].to_string();
let e = inst.expr.take();
// 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" };
// strkeymap 坐标写 m·[i,j] <- v:坐标段是成员名(kv.set 字符串键)。
let dot_coord = arr.ends_with(keytree::MEMBER_SEP);
let arr = arr.trim_end_matches(keytree::MEMBER_SEP).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,
Expand Down Expand Up @@ -857,13 +858,13 @@ impl Parser {
self.advance(); // consume *
if self.peek().kind == Kind::Ident {
let key = self.advance().value;
left = ast::call("kv.get", vec![left, ast::leaf(&key)]);
left = ast::call("kv·get", vec![left, ast::leaf(&key)]);
continue;
}
}
if self.peek().kind == Kind::Ident || self.peek().kind == Kind::Literal {
let field = self.advance().value;
left = ast::call("kv.get", vec![left, ast::str_lit(&field)]);
left = ast::call("kv·get", vec![left, ast::str_lit(&field)]);
continue;
}
// strkeymap 坐标访问 m.[i,j]:坐标段是单个成员名(kv.get 字符串键)。
Expand All @@ -883,7 +884,7 @@ impl Parser {
"[{}]",
idxs.iter().map(|e| e.to_string()).collect::<Vec<_>>().join(",")
);
left = ast::call("kv.get", vec![left, ast::str_lit(&coord)]);
left = ast::call("kv·get", vec![left, ast::str_lit(&coord)]);
continue;
}
}
Expand All @@ -904,7 +905,7 @@ impl Parser {
let mut args = vec![left];
args.extend(indices);
// 路径字面量 + [idx] → kv.get(KV 路径成员访问);否则 xv.at(compact 数组元素)。
left = ast::call(if is_path { "kv.get" } else { "xv.at" }, args);
left = ast::call(if is_path { "kv·get" } else { "xv·at" }, args);
continue;
}
let t = self.peek();
Expand Down Expand Up @@ -1275,7 +1276,8 @@ impl Parser {
}
if (t.kind == Kind::Ident || is_path_literal) && self.peek_at(1).kind == Kind::Dot {
let mut w = self.advance().value;
w.push_str(&self.advance().value); // .
self.advance(); // .
w.push_str(keytree::MEMBER_SEP);
if self.peek().kind == Kind::Ident && self.peek().value == "*" && self.peek_at(1).kind == Kind::Ident {
w.push_str(&self.advance().value); // *
}
Expand Down Expand Up @@ -1338,9 +1340,13 @@ impl Parser {
continue;
}
let is_path_lit = t.kind == Kind::Literal && !t.value.is_empty() && t.value.as_bytes()[0] == b'/';
if (t.kind == Kind::Ident || is_path_lit) && self.peek_at(1).kind == Kind::Dot {
if (t.kind == Kind::Ident || is_path_lit)
&& self.peek_at(1).kind == Kind::Dot
&& self.peek_at(2).kind != Kind::LBrack
{
let mut w = self.advance().value;
w.push_str(&self.advance().value); // .
self.advance(); // .
w.push_str(keytree::MEMBER_SEP);
if self.peek().kind == Kind::Ident && self.peek().value == "*" && self.peek_at(1).kind == Kind::Ident {
w.push_str(&self.advance().value); // *
}
Expand Down Expand Up @@ -1368,7 +1374,8 @@ impl Parser {
}
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); // .
self.advance(); // .
w.push_str(keytree::MEMBER_SEP);
w.push_str(&self.advance().value); // [
let mut depth = 1i32;
while depth > 0 && self.peek().kind != Kind::EOF && self.peek().kind != Kind::Arrow {
Expand Down Expand Up @@ -1398,7 +1405,7 @@ impl Parser {
let s = inst.writes[0].clone();
let dt = s.find(keytree::MEMBER_SEP).unwrap_or(s.len());
let base = s[..dt].to_string();
let field = s[dt + 1..].to_string();
let field = s[dt + keytree::MEMBER_SEP.len()..].to_string();
let key = if field.starts_with('*') {
if field.len() == 1 {
let t = self.peek();
Expand All @@ -1419,7 +1426,7 @@ impl Parser {
};
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.expr = Some(ast::call("kv·set", vec![ast::leaf(&base), key, e.unwrap_or(ast::leaf(""))]));
inst.writes = Vec::new();
inst.write_types = Vec::new();
}
Expand Down
Loading
Loading