225 lines
5.9 KiB
Plaintext
225 lines
5.9 KiB
Plaintext
// Expect retcode = 0
|
||
|
||
// 作用域树(移植自 stage1/spl_scope.c)。每个作用域是一张名字 -> Symbol 表,
|
||
// 节点用 parent 指向父作用域;查找从 current_scope 沿父链上溯(支持遮蔽)。
|
||
// 名字是 ByteView(借用源/AST);Map 复制键值字节,但 ByteView 指向的字节由
|
||
// 调用方保证存活。node 字段是 def.spl 的 DefId。
|
||
|
||
type .{ .Error } = @import("utils/error.spl");
|
||
type .{ .Vec } = @import("utils/vec.spl");
|
||
type .{ .Map } = @import("utils/map.spl");
|
||
type .{ .ByteView } = @import("utils/byte_view.spl");
|
||
type .{ .hash_view, .eq_view } = @import("utils/hash.spl");
|
||
|
||
type SymbolKind = enum {
|
||
Error,
|
||
Var,
|
||
Member,
|
||
Fn,
|
||
Type,
|
||
}
|
||
|
||
type Symbol = struct {
|
||
name: ByteView,
|
||
kind: SymbolKind,
|
||
node: usize, // DefId
|
||
}
|
||
|
||
type ScopeNode = struct {
|
||
parent: usize,
|
||
symbols: Map,
|
||
}
|
||
|
||
type Scope = @self;
|
||
|
||
scopes: Vec, // ScopeNode
|
||
root_scope: usize,
|
||
current_scope: usize,
|
||
|
||
type ScopeResult = enum {
|
||
Ok: Scope,
|
||
Err: Error,
|
||
}
|
||
|
||
fn new_map(): Map {
|
||
ret Map.new(@sizeof(ByteView), @alignof(ByteView), @sizeof(Symbol), @alignof(Symbol),
|
||
hash_view, eq_view);
|
||
}
|
||
|
||
fn new(): ScopeResult {
|
||
var sc = Scope {
|
||
.scopes = Vec.blank(@sizeof(ScopeNode), @alignof(ScopeNode)),
|
||
.root_scope = 0,
|
||
.current_scope = 0,
|
||
};
|
||
var sentinel = ScopeNode { .parent = 0, .symbols = new_map() };
|
||
match Vec.push(&sc.scopes, &sentinel as *u8) {
|
||
.Ok => {},
|
||
.Err(error) => {
|
||
Vec.drop(&sc.scopes);
|
||
Map.drop(&sentinel.symbols);
|
||
ret .Err(error);
|
||
},
|
||
}
|
||
ret .Ok(sc);
|
||
}
|
||
|
||
fn drop(self: *Scope) {
|
||
var i: usize = 0;
|
||
while i < self.scopes.len {
|
||
var n = node(self, i);
|
||
if n != null {
|
||
Map.drop(&n.symbols);
|
||
}
|
||
i = i + 1;
|
||
}
|
||
Vec.drop(&self.scopes);
|
||
self.root_scope = 0;
|
||
self.current_scope = 0;
|
||
}
|
||
|
||
// id 0 与越界返回 null。
|
||
fn node(self: *Scope, id: usize): *ScopeNode {
|
||
if id == 0 || id >= self.scopes.len { ret null; }
|
||
match Vec.get(&self.scopes, id) {
|
||
.Ok(ptr) => { ret ptr as *ScopeNode; },
|
||
.Err(error) => { ret null; },
|
||
}
|
||
ret null;
|
||
}
|
||
|
||
// 新作用域 parent = 当前作用域;不自动切换 current(调用方负责,见 sema)。
|
||
fn alloc(self: *Scope): usize {
|
||
var n = ScopeNode { .parent = self.current_scope, .symbols = new_map() };
|
||
match Vec.push(&self.scopes, &n as *u8) {
|
||
.Ok => {},
|
||
.Err(error) => {
|
||
Map.drop(&n.symbols);
|
||
ret 0;
|
||
},
|
||
}
|
||
ret self.scopes.len - 1;
|
||
}
|
||
|
||
// 插入符号;同名已存在返回 false(不改动)。
|
||
fn insert(self: *Scope, id: usize, symbol: Symbol): bool {
|
||
if id == 0 || id >= self.scopes.len { ret false; }
|
||
var n = node(self, id);
|
||
if n == null { ret false; }
|
||
var old = Symbol {
|
||
.name = ByteView.empty(),
|
||
.kind = .Error,
|
||
.node = 0,
|
||
};
|
||
match Map.get(&n.symbols, &symbol.name as *u8, &old as *u8) {
|
||
.Found => { ret false; },
|
||
.NotFound => {},
|
||
}
|
||
match Map.put(&n.symbols, &symbol.name as *u8, &symbol as *u8) {
|
||
.Ok => { ret true; },
|
||
.Err(error) => { ret false; },
|
||
}
|
||
ret false;
|
||
}
|
||
|
||
// 从 current_scope 沿父链查找;找到填 out 返回 true。
|
||
fn find(self: *Scope, name: ByteView, out: *Symbol): bool {
|
||
if out == null { ret false; }
|
||
var id = self.current_scope;
|
||
while id != 0 {
|
||
var n = node(self, id);
|
||
if n == null { ret false; }
|
||
match Map.get(&n.symbols, &name as *u8, out as *u8) {
|
||
.Found => { ret true; },
|
||
.NotFound => {},
|
||
}
|
||
id = n.parent;
|
||
}
|
||
ret false;
|
||
}
|
||
|
||
// ---- 测试 ----
|
||
|
||
fn sym(name: []u8, kind: SymbolKind, node: usize): Symbol {
|
||
ret Symbol {
|
||
.name = ByteView.from_slice(name),
|
||
.kind = kind,
|
||
.node = node,
|
||
};
|
||
}
|
||
|
||
fn test_alloc_and_find() {
|
||
var sc: Scope = undefined;
|
||
match new() {
|
||
.Ok(v) => { sc = v; },
|
||
.Err(error) => { @assert(false, "scope new failed"); },
|
||
}
|
||
defer { drop(&sc); }
|
||
|
||
@assert(sc.root_scope == 0 && sc.current_scope == 0, "initial");
|
||
|
||
// root
|
||
var root = alloc(&sc);
|
||
sc.root_scope = root;
|
||
sc.current_scope = root;
|
||
|
||
// module scope(child of root)
|
||
var mod = alloc(&sc);
|
||
sc.current_scope = mod;
|
||
|
||
@assert(insert(&sc, mod, sym("x", .Var, 11)), "insert x");
|
||
@assert(!insert(&sc, mod, sym("x", .Var, 12)), "duplicate x");
|
||
|
||
// 函数作用域
|
||
var fn_scope = alloc(&sc);
|
||
sc.current_scope = fn_scope;
|
||
|
||
var out = sym("", .Error, 0);
|
||
@assert(find(&sc, ByteView.from_slice("x"), &out), "find x from child");
|
||
@assert(out.node == 11, "x def id");
|
||
|
||
// 遮蔽:函数内层再定义 x
|
||
@assert(insert(&sc, fn_scope, sym("x", .Fn, 99)), "shadow x");
|
||
@assert(find(&sc, ByteView.from_slice("x"), &out), "find shadow");
|
||
@assert(out.node == 99, "shadow def id");
|
||
|
||
// 未定义
|
||
@assert(!find(&sc, ByteView.from_slice("nope"), &out), "missing");
|
||
|
||
// 父链结构
|
||
var m = node(&sc, mod);
|
||
var f = node(&sc, fn_scope);
|
||
@assert(m != null && m.parent == root, "mod parent");
|
||
@assert(f != null && f.parent == mod, "fn parent");
|
||
}
|
||
|
||
fn test_kinds_isolated() {
|
||
var sc: Scope = undefined;
|
||
match new() {
|
||
.Ok(v) => { sc = v; },
|
||
.Err(error) => { @assert(false, "scope new failed"); },
|
||
}
|
||
defer { drop(&sc); }
|
||
|
||
var a = alloc(&sc);
|
||
sc.current_scope = a;
|
||
@assert(insert(&sc, a, sym("T", .Type, 1)), "type T");
|
||
@assert(insert(&sc, a, sym("f", .Fn, 2)), "fn f");
|
||
|
||
var out = sym("", .Error, 0);
|
||
@assert(find(&sc, ByteView.from_slice("T"), &out), "find T");
|
||
var kind_matches = false;
|
||
match out.kind {
|
||
.Type => { kind_matches = true; },
|
||
_ => {},
|
||
}
|
||
@assert(kind_matches, "T kind");
|
||
@assert(find(&sc, ByteView.from_slice("f"), &out), "find f");
|
||
@assert(out.node == 2, "f def id");
|
||
}
|
||
|
||
fn main() {
|
||
test_alloc_and_find();
|
||
test_kinds_isolated();
|
||
}
|