stage2 提供c后端 提交stage1的测试

This commit is contained in:
zzy committed 2026-09-20 17:56:11 +08:00
1 parent 846f441e3a
commit 51d408d524
82 files changed
+6872 -65

No files matched your search

+179 -7
View File
@@ -25,6 +25,7 @@ failed: bool,
stop_agg: i32,
error_count: usize,
file: usize, // 当前源文件在 Sources 中的下标
comptime_depth: usize, // >0 表示处于 comptime 上下文(类型可作为表达式)
fn new(ast: *Ast, toks: Vec, diag: *Diag): Parser {
ret Parser {
@@ -36,6 +37,7 @@ fn new(ast: *Ast, toks: Vec, diag: *Diag): Parser {
.stop_agg = 0,
.error_count = 0,
.file = 0,
.comptime_depth = 0,
};
}
@@ -71,6 +73,21 @@ fn peek(self: *Parser): *Token {
ret base + i;
}
// 跳过 trivia,返回当前 token 之后的下一个非 trivia token(不移动 pos)。
fn peek_next(self: *Parser): *Token {
var n = self.toks.len;
var base = self.toks.data as *Token;
var i = self.pos + 1;
while i < n {
if base == null { break; }
var t = base + i;
if !is_trivia(t.kind) { break; }
i = i + 1;
}
if i >= n || base == null { ret null; }
ret base + i;
}
fn advance(self: *Parser): *Token {
var t = peek(self);
if t == null { ret null; }
@@ -264,6 +281,7 @@ fn can_start_expr(kind: TokenKind): bool {
.Loop => { ret true; },
.For => { ret true; },
.Match => { ret true; },
.Comptime => { ret true; },
_ => { ret false; },
}
},
@@ -655,7 +673,33 @@ fn parse_param_list(self: *Parser): Vec {
ret out;
}
fn parse_fn_decl(self: *Parser, tags: Vec): usize {
// 该 token 是否可能开始一个类型表达式(用于省略冒号的返回类型)。
fn token_starts_type(t: *Token): bool {
if t == null { ret false; }
match t.kind {
.Ident => { ret true; },
.Keyword(k) => {
if @enum2int(k) == @enum2int(Keyword.Type) { ret true; }
if @enum2int(k) == @enum2int(Keyword.Bool) { ret true; }
if @enum2int(k) == @enum2int(Keyword.Any) { ret true; }
if @enum2int(k) == @enum2int(Keyword.Fn) { ret true; }
if @enum2int(k) == @enum2int(Keyword.Struct) { ret true; }
if @enum2int(k) == @enum2int(Keyword.Union) { ret true; }
if @enum2int(k) == @enum2int(Keyword.Enum) { ret true; }
if @enum2int(k) == @enum2int(Keyword.Shape) { ret true; }
},
.Punct(p) => {
if @enum2int(p) == @enum2int(Punct.Mul) { ret true; }
if @enum2int(p) == @enum2int(Punct.LBracket) { ret true; }
if @enum2int(p) == @enum2int(Punct.At) { ret true; }
if @enum2int(p) == @enum2int(Punct.Sharp) { ret true; }
},
_ => {},
}
ret false;
}
fn parse_fn_decl(self: *Parser, tags: Vec, is_comptime: bool): usize {
var kw = peek(self);
if kw == null || !kind_is_keyword(kw.kind, .Fn) { ret 0; }
advance(self);
@@ -672,19 +716,26 @@ fn parse_fn_decl(self: *Parser, tags: Vec): usize {
advance(self);
ret_type = parse_type_expr(self);
t = peek(self);
} else if token_starts_type(t) {
// 省略冒号:`fn f() T { ... }`
ret_type = parse_type_expr(self);
t = peek(self);
}
var body: usize = 0;
if is_comptime { self.comptime_depth = self.comptime_depth + 1; }
if t != null && kind_is_punct(t.kind, .LBrace) {
body = parse_block(self);
} else if t != null && kind_is_punct(t.kind, .Semicolon) {
advance(self);
} else {
if is_comptime { self.comptime_depth = self.comptime_depth - 1; }
parse_error(self, t, "function declaration must end with ';' or block");
ret 0;
}
if is_comptime { self.comptime_depth = self.comptime_depth - 1; }
ret new_node(self, .FnDecl(.{
.tag_list = tags,
.is_comptime = false,
.is_comptime = is_comptime,
.name = name.text,
.params = params,
.ret_type = ret_type,
@@ -802,8 +853,10 @@ fn parse_comptime_decl(self: *Parser): usize {
advance(self);
var body: usize = 0;
var t = peek(self);
self.comptime_depth = self.comptime_depth + 1;
if t != null && kind_is_punct(t.kind, .LBrace) { body = parse_block(self); }
else { body = parse_expr(self); }
self.comptime_depth = self.comptime_depth - 1;
ret new_node(self, .ComptimeDecl(.{ .body = body }), kw);
}
@@ -815,7 +868,7 @@ fn parse_container_declaration(self: *Parser): usize {
match t.kind {
.Eof => { ret 0; },
.Keyword(k) => {
if @enum2int(k) == @enum2int(Keyword.Fn) { ret parse_fn_decl(self, tags); }
if @enum2int(k) == @enum2int(Keyword.Fn) { ret parse_fn_decl(self, tags, false); }
if @enum2int(k) == @enum2int(Keyword.Type) { ret parse_type_decl(self, tags); }
if @enum2int(k) == @enum2int(Keyword.Var) {
ret parse_var_const_decl(self, tags, false);
@@ -823,7 +876,15 @@ fn parse_container_declaration(self: *Parser): usize {
if @enum2int(k) == @enum2int(Keyword.Const) {
ret parse_var_const_decl(self, tags, true);
}
if @enum2int(k) == @enum2int(Keyword.Comptime) { ret parse_comptime_decl(self); }
if @enum2int(k) == @enum2int(Keyword.Comptime) {
// `comptime fn ...` -> 标记为编译期函数;否则 `comptime { }` 声明。
var nxt = peek_next(self);
if nxt != null && kind_is_keyword(nxt.kind, .Fn) {
advance(self);
ret parse_fn_decl(self, tags, true);
}
ret parse_comptime_decl(self);
}
},
.Ident => { ret parse_member_decl(self, tags); },
.Punct(p) => {
@@ -951,15 +1012,41 @@ fn parse_type_base(self: *Parser): usize {
match bt.kind {
.Ident => {
advance(self);
// 类型调用 `Name(T, ...)`(comptime 类型构造,如 `vec(i32)`)。
if at_punct(self, .LParen) {
advance(self);
var ref = new_node(self, .TypePath(.{
.name = bt.text,
.generic_args = ref_vec(),
}), bt);
var args = ref_vec();
while !self.failed && !at_punct(self, .RParen) {
var a = parse_type_expr(self);
match Vec.push(&args, &a as *u8) { .Ok => {}, .Err(e) => { ret 0; } }
if at_punct(self, .Comma) { advance(self); continue; }
break;
}
expect_punct(self, .RParen, "')' in type call");
var tn = Ast.node(self.ast, ref);
match tn.body {
.TypePath(tp) => {
tp.generic_args = args;
tn.body = .TypePath(tp);
},
_ => {},
}
ret ref;
}
ret new_node(self, .TypePath(.{
.name = bt.text,
.generic_args = ref_vec(),
}), bt);
},
.Keyword(k) => {
// stage1 is_builtin_type_kw:bool / any 作为类型路径。
// stage1 is_builtin_type_kw:bool / any 作为类型路径;stage3 增加 `type`。
if @enum2int(k) == @enum2int(Keyword.Bool) ||
@enum2int(k) == @enum2int(Keyword.Any) {
@enum2int(k) == @enum2int(Keyword.Any) ||
@enum2int(k) == @enum2int(Keyword.Type) {
advance(self);
ret new_node(self, .TypePath(.{
.name = bt.text,
@@ -1357,6 +1444,21 @@ fn parse_primary(self: *Parser): usize {
if @enum2int(k) == @enum2int(Keyword.Loop) { ret parse_loop_expr(self); }
if @enum2int(k) == @enum2int(Keyword.For) { ret parse_for_expr(self); }
if @enum2int(k) == @enum2int(Keyword.Match) { ret parse_match_expr(self); }
// `comptime <expr>`:编译期表达式(可调用普通函数、返回类型等)。
if @enum2int(k) == @enum2int(Keyword.Comptime) {
advance(self);
var cbody = parse_expr(self);
ret new_node(self, .ExprComptime(.{ .body = cbody }), t);
}
// 类型即表达式:仅在 comptime 上下文内允许 `struct { ... }` 等聚合类型。
if self.comptime_depth > 0 {
if @enum2int(k) == @enum2int(Keyword.Struct) ||
@enum2int(k) == @enum2int(Keyword.Union) ||
@enum2int(k) == @enum2int(Keyword.Enum) ||
@enum2int(k) == @enum2int(Keyword.Shape) {
ret parse_type_base(self);
}
}
parse_error(self, t, "unrecognized expression");
ret 0;
},
@@ -1553,6 +1655,15 @@ fn parse_comptime_call(self: *Parser): usize {
args = parse_expr_list(self);
if !expect_punct(self, .RParen, "')' in comptime call") { ret 0; }
}
// `@name(args){ ... }`:构造该编译期类型的值(聚合初始化)。
if at_punct(self, .LBrace) && self.stop_agg == 0 {
var fields = parse_aggregate_fields(self);
ret new_node(self, .ExprComptimeInit(.{
.name = name.text,
.args = args,
.fields = fields,
}), start);
}
ret new_node(self, .ExprComptimeCall(.{ .name = name.text, .args = args }), start);
}
@@ -1791,7 +1902,18 @@ fn parse_ret_stmt(self: *Parser): usize {
advance(self);
var expr: usize = 0;
var t = peek(self);
if t != null && can_start_expr(t.kind) { expr = parse_expr(self); }
var can = false;
if t != null {
can = can_start_expr(t.kind);
// comptime 上下文:允许返回类型表达式(如 `ret struct { ... };`)。
if !can && self.comptime_depth > 0 {
if kind_is_keyword(t.kind, .Struct) || kind_is_keyword(t.kind, .Union) ||
kind_is_keyword(t.kind, .Enum) || kind_is_keyword(t.kind, .Shape) {
can = true;
}
}
}
if can { expr = parse_expr(self); }
t = peek(self);
if t != null && kind_is_punct(t.kind, .Semicolon) { advance(self); }
ret new_node(self, .StatementRet(.{ .expr = expr }), kw);
@@ -2223,10 +2345,60 @@ fn test_big_int_literal() {
check_int("0o_17", "15");
}
fn expect_contains(buf: *ByteBuffer, needle: []u8) {
var actual = ByteBuffer.as_slice(buf.*);
if needle.len > actual.len { @assert(false, "contains length"); }
var i: usize = 0;
while i + needle.len <= actual.len {
var j: usize = 0;
var ok = true;
while j < needle.len {
if actual.ptr[i + j] != needle.ptr[j] { ok = false; break; }
j = j + 1;
}
if ok { ret; }
i = i + 1;
}
@assert(false, "expected substring not found");
}
// stage3 语法:`comptime fn ... (t: type) type { ... }` 与省略冒号的返回类型。
fn test_parse_comptime_fn() {
var src: []u8 = "comptime fn vec(t: type) type { ret t; }\n";
var toks = lex_tokens(src);
defer { Vec.drop(&toks); }
var sources = set_new();
defer { set_drop(&sources); }
match set_add(&sources, ByteView.from_slice("test.spl"), ByteView.from_slice(src)) {
.Ok(index) => {},
.Err(error) => { @assert(false, "set_add"); },
}
var ast: Ast = undefined;
match Ast.new(&sources) {
.Ok(v) => { ast = v; },
.Err(error) => { @assert(false, "ast new"); },
}
defer { Ast.drop(&ast); }
var p = new(&ast, toks, null);
parse(&p);
@assert(!p.failed, "comptime fn parse ok");
@assert(p.error_count == 0, "comptime fn no errors");
var buf = ByteBuffer.new();
defer { ByteBuffer.drop(&buf); }
@assert(Ast.dump(&ast, &buf), "dump");
expect_contains(&buf, "fn_decl");
expect_contains(&buf, "type_path");
}
fn main() {
test_peek_advance();
test_new_node_span();
test_parse_decls();
test_parse_main();
test_big_int_literal();
test_parse_comptime_fn();
}