stage2 提供c后端 提交stage1的测试
This commit is contained in:
1 parent
846f441e3a
commit
51d408d524
82 files changed
+6872
-65
No files matched your search
+179
-7
@@ -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();
|
||||
}
|
||||
Reference in new issue
Block a user