stage2 提供近乎完整的功能但出现严重性能问题 添加stage0的原生性能记录 stage1添加更多内置函数 nob重构代码使其更加健壮
This commit is contained in:
1 parent
b5a7a811b3
commit
e02b0c633a
35 files changed
+14018
-216
No files matched your search
+316
@@ -0,0 +1,316 @@
|
||||
// Expect retcode = 0
|
||||
|
||||
// 声明句柄表(移植自 stage1/spl_lang_type.h 的 spl_def_node_t 部分)。
|
||||
// DefId 是「声明」的稳定身份:作用域符号、AST 节点 resolved_def_id、以及将来
|
||||
// comptime 生成的声明都用它。前向引用/环形引用由 state 状态机表达。
|
||||
//
|
||||
// 与 stage1 的差异:owner_ast 改为不透明 `*any`(借用),使本表不依赖具体 AST
|
||||
// 表示,便于将来 comptime/序列化复用;sema 侧自行 cast 回 *Ast。
|
||||
// 名称是 ByteView(借用源/AST),本表不做拥有。
|
||||
|
||||
type .{ .Error } = @import("utils/error.spl");
|
||||
type .{ .Vec } = @import("utils/vec.spl");
|
||||
type .{ .ByteView } = @import("utils/byte_view.spl");
|
||||
type .{ .ByteBuffer } = @import("utils/byte_buffer.spl");
|
||||
type .{ .append_usize } = @import("utils/fmt.spl");
|
||||
type .{ .Span, .span_none } = @import("./diag.spl");
|
||||
|
||||
type DefKind = enum {
|
||||
Error,
|
||||
Scalar,
|
||||
Member,
|
||||
Var,
|
||||
Fn,
|
||||
Agg,
|
||||
Distinct,
|
||||
Alias,
|
||||
Builtin,
|
||||
}
|
||||
|
||||
type DeclState = enum {
|
||||
Unresolved,
|
||||
Resolving,
|
||||
Resolved,
|
||||
Error,
|
||||
}
|
||||
|
||||
type DefNode = struct {
|
||||
kind: DefKind,
|
||||
name: ByteView,
|
||||
span: Span,
|
||||
lang_id: usize,
|
||||
owner: *any, // 借用;不透明,sema 侧 cast 回 *Ast
|
||||
ast_node_ref: usize,
|
||||
state: DeclState,
|
||||
owner_def: usize,
|
||||
}
|
||||
|
||||
type DefTable = @self;
|
||||
|
||||
table: Vec, // DefNode
|
||||
|
||||
type DefTableResult = enum {
|
||||
Ok: DefTable,
|
||||
Err: Error,
|
||||
}
|
||||
|
||||
fn new_node(): DefNode {
|
||||
ret DefNode {
|
||||
.kind = .Error,
|
||||
.name = ByteView.empty(),
|
||||
.span = span_none(),
|
||||
.lang_id = 0,
|
||||
.owner = null,
|
||||
.ast_node_ref = 0,
|
||||
.state = .Unresolved,
|
||||
.owner_def = 0,
|
||||
};
|
||||
}
|
||||
|
||||
fn new(): DefTableResult {
|
||||
var dt = DefTable { .table = Vec.blank(@sizeof(DefNode), @alignof(DefNode)) };
|
||||
var sentinel = new_node();
|
||||
match Vec.push(&dt.table, &sentinel as *u8) {
|
||||
.Ok => {},
|
||||
.Err(error) => {
|
||||
Vec.drop(&dt.table);
|
||||
ret .Err(error);
|
||||
},
|
||||
}
|
||||
ret .Ok(dt);
|
||||
}
|
||||
|
||||
fn drop(self: *DefTable) {
|
||||
Vec.drop(&self.table);
|
||||
}
|
||||
|
||||
// id 0 与越界均返回 null(对应 stage1 spl_def_node)。
|
||||
fn node(self: *DefTable, id: usize): *DefNode {
|
||||
if id == 0 || id >= self.table.len { ret null; }
|
||||
match Vec.get(&self.table, id) {
|
||||
.Ok(ptr) => { ret ptr as *DefNode; },
|
||||
.Err(error) => { ret null; },
|
||||
}
|
||||
ret null;
|
||||
}
|
||||
|
||||
fn count(self: *DefTable): usize {
|
||||
ret self.table.len;
|
||||
}
|
||||
|
||||
// 追加一条声明,返回其 DefId(失败返回 0)。
|
||||
fn alloc(self: *DefTable, kind: DefKind, name: ByteView, span: Span, owner: *any,
|
||||
ast_node_ref: usize): usize {
|
||||
var n = new_node();
|
||||
n.kind = kind;
|
||||
n.name = name;
|
||||
n.span = span;
|
||||
n.owner = owner;
|
||||
n.ast_node_ref = ast_node_ref;
|
||||
match Vec.push(&self.table, &n as *u8) {
|
||||
.Ok => {},
|
||||
.Err(error) => { ret 0; },
|
||||
}
|
||||
ret self.table.len - 1;
|
||||
}
|
||||
|
||||
fn resolve(self: *DefTable, id: usize, lang_id: usize) {
|
||||
var d = node(self, id);
|
||||
if d == null { ret; }
|
||||
d.lang_id = lang_id;
|
||||
d.state = .Resolved;
|
||||
}
|
||||
|
||||
fn set_state(self: *DefTable, id: usize, state: DeclState) {
|
||||
var d = node(self, id);
|
||||
if d == null { ret; }
|
||||
d.state = state;
|
||||
}
|
||||
|
||||
fn get_lang_id(self: *DefTable, id: usize): usize {
|
||||
var d = node(self, id);
|
||||
if d == null { ret 0; }
|
||||
ret d.lang_id;
|
||||
}
|
||||
|
||||
// ---- 分类 ----
|
||||
|
||||
fn kind_name(kind: DefKind): []u8 {
|
||||
match kind {
|
||||
.Error => { ret "error"; },
|
||||
.Scalar => { ret "scalar"; },
|
||||
.Member => { ret "member"; },
|
||||
.Var => { ret "var"; },
|
||||
.Fn => { ret "fn"; },
|
||||
.Agg => { ret "agg"; },
|
||||
.Distinct => { ret "distinct"; },
|
||||
.Alias => { ret "alias"; },
|
||||
.Builtin => { ret "builtin"; },
|
||||
}
|
||||
ret "unknown";
|
||||
}
|
||||
|
||||
fn state_name(state: DeclState): []u8 {
|
||||
match state {
|
||||
.Unresolved => { ret "unresolved"; },
|
||||
.Resolving => { ret "resolving"; },
|
||||
.Resolved => { ret "resolved"; },
|
||||
.Error => { ret "error"; },
|
||||
}
|
||||
ret "unknown";
|
||||
}
|
||||
|
||||
// 能作为类型使用的 def(对应 stage1 sema_def_is_type)。
|
||||
fn is_type_kind(kind: DefKind): bool {
|
||||
match kind {
|
||||
.Scalar => { ret true; },
|
||||
.Agg => { ret true; },
|
||||
.Distinct => { ret true; },
|
||||
.Alias => { ret true; },
|
||||
.Builtin => { ret true; },
|
||||
_ => { ret false; },
|
||||
}
|
||||
ret false;
|
||||
}
|
||||
|
||||
// ---- dump(镜像 stage1 spl_type_def_dump 的文本)----
|
||||
|
||||
fn push_out(buf: *ByteBuffer, bytes: []u8): bool {
|
||||
match ByteBuffer.append(buf, bytes) {
|
||||
.Ok => { ret true; },
|
||||
.Err(error) => { ret false; },
|
||||
}
|
||||
ret false;
|
||||
}
|
||||
|
||||
fn push_usize(buf: *ByteBuffer, value: usize): bool {
|
||||
match append_usize(buf, value, 10, false) {
|
||||
.Ok => { ret true; },
|
||||
.Err(error) => { ret false; },
|
||||
}
|
||||
ret false;
|
||||
}
|
||||
|
||||
fn dump(self: *DefTable, id: usize, out: *ByteBuffer): bool {
|
||||
var d = node(self, id);
|
||||
if d == null {
|
||||
ret push_out(out, "none");
|
||||
}
|
||||
if !push_out(out, "kind=") { ret false; }
|
||||
if !push_out(out, kind_name(d.kind)) { ret false; }
|
||||
if !push_out(out, " lang_id=") { ret false; }
|
||||
if !push_usize(out, d.lang_id) { ret false; }
|
||||
if !push_out(out, " name=") { ret false; }
|
||||
if d.name.len == 0 {
|
||||
ret push_out(out, "?");
|
||||
}
|
||||
ret push_out(out, ByteView.as_slice(d.name));
|
||||
}
|
||||
|
||||
// ---- 测试 ----
|
||||
|
||||
fn test_alloc_and_state() {
|
||||
var dt: DefTable = undefined;
|
||||
match new() {
|
||||
.Ok(v) => { dt = v; },
|
||||
.Err(error) => { @assert(false, "def table new failed"); },
|
||||
}
|
||||
defer { drop(&dt); }
|
||||
|
||||
@assert(count(&dt) == 1, "sentinel only");
|
||||
@assert(node(&dt, 0) == null, "id 0 is null");
|
||||
|
||||
var span = span_none();
|
||||
var a = alloc(&dt, .Fn, ByteView.from_slice("foo"), span, null, 7);
|
||||
var b = alloc(&dt, .Agg, ByteView.from_slice("Bar"), span, null, 9);
|
||||
@assert(a == 1 && b == 2, "ids increase from 1");
|
||||
|
||||
var na = node(&dt, a);
|
||||
@assert(na != null, "node a");
|
||||
@assert(ByteView.eq(na.name, ByteView.from_slice("foo")), "name stored");
|
||||
@assert(na.ast_node_ref == 7, "ast_node_ref stored");
|
||||
@assert(na.owner == null, "owner stored");
|
||||
match na.state {
|
||||
.Unresolved => {},
|
||||
_ => { @assert(false, "initial state unresolved"); },
|
||||
}
|
||||
match na.kind {
|
||||
.Fn => {},
|
||||
_ => { @assert(false, "kind fn"); },
|
||||
}
|
||||
|
||||
resolve(&dt, a, 42);
|
||||
@assert(get_lang_id(&dt, a) == 42, "lang id resolved");
|
||||
var na2 = node(&dt, a);
|
||||
match na2.state {
|
||||
.Resolved => {},
|
||||
_ => { @assert(false, "state resolved"); },
|
||||
}
|
||||
|
||||
set_state(&dt, b, .Resolving);
|
||||
var nb = node(&dt, b);
|
||||
match nb.state {
|
||||
.Resolving => {},
|
||||
_ => { @assert(false, "state resolving"); },
|
||||
}
|
||||
|
||||
@assert(get_lang_id(&dt, 999) == 0, "missing id");
|
||||
}
|
||||
|
||||
fn test_kind_helpers() {
|
||||
@assert(is_type_kind(.Scalar), "scalar is type");
|
||||
@assert(is_type_kind(.Agg), "agg is type");
|
||||
@assert(is_type_kind(.Alias), "alias is type");
|
||||
@assert(!is_type_kind(.Fn), "fn not type");
|
||||
@assert(!is_type_kind(.Var), "var not type");
|
||||
@assert(!is_type_kind(.Member), "member not type");
|
||||
|
||||
@assert(ByteView.eq(ByteView.from_slice(kind_name(.Agg)), ByteView.from_slice("agg")), "agg name");
|
||||
@assert(ByteView.eq(ByteView.from_slice(state_name(.Resolving)),
|
||||
ByteView.from_slice("resolving")),
|
||||
"resolving name");
|
||||
}
|
||||
|
||||
fn test_dump() {
|
||||
var dt: DefTable = undefined;
|
||||
match new() {
|
||||
.Ok(v) => { dt = v; },
|
||||
.Err(error) => { @assert(false, "def table new failed"); },
|
||||
}
|
||||
defer { drop(&dt); }
|
||||
|
||||
var a = alloc(&dt, .Var, ByteView.from_slice("x"), span_none(), null, 0);
|
||||
resolve(&dt, a, 5);
|
||||
|
||||
var out = ByteBuffer.new();
|
||||
defer { ByteBuffer.drop(&out); }
|
||||
if !dump(&dt, a, &out) { @assert(false, "dump ok"); }
|
||||
expect_text(out, "kind=var lang_id=5 name=x");
|
||||
|
||||
var out2 = ByteBuffer.new();
|
||||
defer { ByteBuffer.drop(&out2); }
|
||||
if !dump(&dt, 0, &out2) { @assert(false, "dump none ok"); }
|
||||
expect_text(out2, "none");
|
||||
|
||||
var out3 = ByteBuffer.new();
|
||||
defer { ByteBuffer.drop(&out3); }
|
||||
var c = alloc(&dt, .Alias, ByteView.empty(), span_none(), null, 0);
|
||||
if !dump(&dt, c, &out3) { @assert(false, "dump empty name ok"); }
|
||||
expect_text(out3, "kind=alias lang_id=0 name=?");
|
||||
}
|
||||
|
||||
fn expect_text(buf: ByteBuffer, expected: []u8) {
|
||||
var got = ByteBuffer.as_slice(buf);
|
||||
@assert(got.len == expected.len, "dump length");
|
||||
var i: usize = 0;
|
||||
while i < expected.len {
|
||||
@assert(got.ptr[i] == expected.ptr[i], "dump byte");
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test_alloc_and_state();
|
||||
test_kind_helpers();
|
||||
test_dump();
|
||||
}
|
||||
Reference in new issue
Block a user