stage1 实现更多ast2ir 修复bug 提供内置操作

This commit is contained in:
zzy committed 2026-09-11 19:26:48 +08:00
1 parent ab6e99c958
commit 49ccdec3dd
10 files changed
+396 -76

No files matched your search

+19 -28
View File
@@ -18,7 +18,7 @@
static const char *CFLAGS_STAMP = BUILD_FOLDER ".cflags";
/* clang-format off */
#define VM_SRCS "stage0/spl_mcode.c", "stage0/spl_syscall.c", "stage0/spl_vm.c"
#define VM_SRCS "stage0/spl_mcode.c", "stage0/spl_syscall.c", "stage0/spl_vm.c",
static const char *spl_cli_srcs[] = {"stage0/spl_cli.c", VM_SRCS};
static const char *test_srcs[] = {"stage0/test_spl_vm.c", VM_SRCS};
static const char *splc0_srcs[] = {
@@ -28,12 +28,12 @@ static const char *splc0_srcs[] = {
"stage1/spl_dumptree.c",
"stage1/spl_type.c",
"stage1/spl_sema.c",
// "stage1/spl_ir.c",
// "stage1/spl_ast2ir.c",
"stage1/spl_intrin.c",
"stage1/spl_ir.c",
"stage1/spl_ast2ir.c",
// "stage1/spl_ir2vm.c",
// "stage0/spl_mcode.c",
};
/* clang-format on */
typedef struct {
@@ -204,7 +204,9 @@ static void parse_expect(const char *name, Nob_Cmd_Result *expect) {
}
}
static bool test_once(const char *fname) {
static bool test_once(const char *fname, void *user_data) {
(void)user_data;
const char *compiler_path = "splc0";
const char *cli_path = "spl_cli";
const char *target_sir = BUILD_FOLDER "test.sir";
@@ -250,7 +252,7 @@ static bool test_once(const char *fname) {
return true;
}
static bool test_once_ast(const char *fname) {
static bool test_once_with_dump(const char *fname, void *user_data) {
const char *target_name = "splc0";
if (!prepare_build())
return 1;
@@ -258,24 +260,12 @@ static bool test_once_ast(const char *fname) {
return 1;
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, nob_temp_sprintf(BUILD_FOLDER "%s", target_name));
nob_cmd_append(&cmd, "--dump", "ast", fname, BUILD_FOLDER "t.sir");
nob_cmd_append(&cmd, "--dump", (char *)user_data, fname, BUILD_FOLDER "t.sir");
return nob_cmd_run(&cmd);
}
static bool test_once_sema(const char *fname) {
const char *target_name = "splc0";
if (!prepare_build())
return 1;
if (!build_target(target_name))
return 1;
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, nob_temp_sprintf(BUILD_FOLDER "%s", target_name));
nob_cmd_append(&cmd, "--dump", "sema", fname, BUILD_FOLDER "t.sir");
return nob_cmd_run(&cmd);
}
typedef bool (*test_fn_t)(const char *fname);
static bool run_test(Nob_Files *files, test_fn_t test_once) {
typedef bool (*test_fn_t)(const char *fname, void *user_data);
static bool run_test(Nob_Files *files, test_fn_t test_once, void *user_data) {
const char *test_folder = "./tests/stage1/";
Nob_File_Paths paths = {0};
@@ -289,7 +279,7 @@ static bool run_test(Nob_Files *files, test_fn_t test_once) {
}
const char *tname = nob_temp_sprintf("%s%s", test_folder, paths.items[j]);
printf("--- test %s ---\n", tname);
if (test_once(tname) == false)
if (test_once(tname, user_data) == false)
return false;
}
}
@@ -376,12 +366,13 @@ int main(int argc, char **argv) {
if (strcmp(command_name, "test") == 0) {
Nob_Files files = {0};
test_fn_t tfn = test_once;
const char *mode_name = NULL;
if (argc > 0) {
const char *mode_name = nob_shift(argv, argc);
if (strcmp(mode_name, "ast") == 0) {
tfn = test_once_ast;
} else if (strcmp(mode_name, "sema") == 0) {
tfn = test_once_sema;
mode_name = nob_shift(argv, argc);
if (strcmp(mode_name, "lex") == 0 || strcmp(mode_name, "ast") == 0 ||
strcmp(mode_name, "sema") == 0 || strcmp(mode_name, "ir") == 0 ||
strcmp(mode_name, "vm") == 0) {
tfn = test_once_with_dump;
} else {
da_append(&files, mode_name);
}
@@ -391,7 +382,7 @@ int main(int argc, char **argv) {
da_append(&files, nob_shift(argv, argc));
}
return run_test(&files, tfn) ? 0 : 1;
return run_test(&files, tfn, (void *)mode_name) ? 0 : 1;
}
if (strcmp(command_name, "clean") == 0) {
+25 -14
View File
@@ -311,7 +311,8 @@ static void parse_tag_list(parser_t *p, spl_ast_node_ref_vec_t *out, int is_exte
t = peek(p);
if (t && t->type == TOK_L_PAREN) {
advance(p);
tag->tag_item.args = parse_expr_list(p);
spl_ast_node_ref_vec_t args = parse_expr_list(p);
node_at(p->ast, ref)->tag_item.args = args;
t = peek(p);
if (!t || t->type != TOK_R_PAREN) {
SPL_FATAL(t, "expected ')' in tag args");
@@ -474,7 +475,8 @@ static spl_ast_node_ref_t parse_type_decl(parser_t *p, spl_ast_node_ref_vec_t ta
spl_ast_node_t *td = node_at(p->ast, ref);
MOVE_VEC(td->type_decl.attr_list, tag_list);
SET_STR_FIELD(p->ast, td->type_decl.name, name);
td->type_decl.type_expr = parse_type_expr(p);
spl_ast_node_ref_t type_expr = parse_type_expr(p);
node_at(p->ast, ref)->type_decl.type_expr = type_expr;
t = peek(p);
if (t && (t->type == TOK_COMMA || t->type == TOK_SEMICOLON)) {
@@ -645,13 +647,15 @@ static spl_ast_node_ref_t parse_var_pattern_atom(parser_t *p) {
return 0;
}
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_PATTERN_DOT, t);
spl_ast_node_t *pat = node_at(p->ast, ref);
SET_STR_FIELD(p->ast, pat->pattern_dot.name, name);
if (peek(p) && peek(p)->type == TOK_L_BRACKET) {
advance(p);
pat->pattern_dot.sub_pattern = parse_var_pattern(p);
spl_ast_node_ref_t sub = parse_var_pattern(p);
node_at(p->ast, ref)->pattern_dot.sub_pattern = sub;
t = peek(p);
if (!t || t->type != TOK_R_BRACKET) {
SPL_FATAL(t, "expected ']' in pattern");
@@ -778,8 +782,8 @@ static spl_ast_node_ref_t parse_type_base(parser_t *p) {
if (peek(p) && peek(p)->type == TOK_COLON) {
advance(p);
fn_type = node_at(p->ast, ref);
fn_type->type_fn.ret_type = parse_type_expr(p);
spl_ast_node_ref_t ret = parse_type_expr(p);
node_at(p->ast, ref)->type_fn.ret_type = ret;
}
return ref;
}
@@ -948,7 +952,8 @@ static spl_ast_node_ref_t parse_type_expr(parser_t *p) {
if (t->type == TOK_MUL) {
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_POINTER, t);
node_at(p->ast, ref)->type_pointer.pointee = parse_type_expr(p);
spl_ast_node_ref_t pointee = parse_type_expr(p);
node_at(p->ast, ref)->type_pointer.pointee = pointee;
return ref;
}
@@ -1292,7 +1297,10 @@ static spl_ast_node_ref_t parse_postfix(parser_t *p) {
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_CALL, t);
node_at(p->ast, ref)->call.callee = expr;
node_at(p->ast, ref)->call.args = parse_expr_list(p);
spl_ast_node_ref_vec_t args = parse_expr_list(p);
node_at(p->ast, ref)->call.args = args;
t = peek(p);
if (!t || t->type != TOK_R_PAREN) {
SPL_FATAL(t, "expected ')' in call");
@@ -1415,14 +1423,15 @@ static spl_ast_node_ref_t parse_primary(parser_t *p) {
case TOK_IDENT: {
advance(p);
if (peek(p) && peek(p)->type == TOK_L_BRACE && !p->stop_agg) {
// 具名聚合字面量:Identifier { fields }
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_AGGREGATE_LIT, t);
spl_ast_node_t *agg = node_at(p->ast, ref);
agg->aggregate_literal.name = intern_string(p->ast, t->lexeme, t->len);
agg->aggregate_literal.fields = parse_aggregate_fields(p);
spl_ast_node_ref_vec_t fields = parse_aggregate_fields(p);
node_at(p->ast, ref)->aggregate_literal.fields = fields;
return ref;
}
// 普通标识符引用
/* 普通标识符 */
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_IDENT, t);
node_at(p->ast, ref)->ident.name = intern_string(p->ast, t->lexeme, t->len);
return ref;
@@ -1435,11 +1444,11 @@ static spl_ast_node_ref_t parse_primary(parser_t *p) {
return 0;
}
if (nx->type == TOK_L_BRACE && !p->stop_agg) {
// 匿名聚合字面量:. { fields }
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_AGGREGATE_LIT, t);
spl_ast_node_t *agg = node_at(p->ast, ref);
agg->aggregate_literal.name = NULL;
agg->aggregate_literal.fields = parse_aggregate_fields(p);
node_at(p->ast, ref)->aggregate_literal.name = NULL;
spl_ast_node_ref_vec_t fields = parse_aggregate_fields(p);
node_at(p->ast, ref)->aggregate_literal.fields = fields;
return ref;
} else if (nx->type == TOK_L_BRACKET) {
// 匿名数组字面量:. [ elems ]
@@ -1934,6 +1943,8 @@ static spl_ast_node_ref_t parse_match_expr(parser_t *p) {
spl_ast_node_t *arm_node = node_at(p->ast, arm);
arm_node->match_arm.pattern = patterns.data[i];
arm_node->match_arm.body = bodies.data[i];
me = node_at(p->ast, ref); /* 每次迭代重新获取 防止 new_node 扩容 */
vec_push(me->match_expr.arms, arm);
}
vec_free(patterns);
+154 -11
View File
@@ -1,5 +1,5 @@
#include "spl_ast2ir.h"
#include <string.h>
#include "spl_intrin.h"
static spl_type_id_t to_ir_type(spl_ast2ir_t *a, spl_lang_type_id_t lang) {
if (!lang)
@@ -32,6 +32,70 @@ static void emit_fn(spl_ast2ir_t *a, spl_ast_node_t *n);
static void emit_container(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
static spl_ir_node_ref_t emit_cast(spl_ast2ir_t *a, spl_ast_node_t *n);
static spl_ir_node_ref_t ast2ir_intrin_call(spl_ast2ir_t *a, spl_ast_node_t *n, spl_intrin_t in);
static spl_ir_node_ref_t ast2ir_intrin_field(spl_ast2ir_t *a, spl_ast_node_t *n, spl_intrin_t in);
static spl_ir_node_ref_t ast2ir_intrin_len(spl_ast2ir_t *a, spl_ast_node_t *n);
static spl_ir_node_ref_t ast2ir_intrin_call(spl_ast2ir_t *a, spl_ast_node_t *n, spl_intrin_t in) {
switch (in) {
case SPL_INTRIN_SIZEOF: {
spl_ast_node_t *arg = spl_ast_node(a->sema->ast, vec_at(n->call.args, 0));
return spl_ir_builder_type_sizeof(a->ir, node_ir(a, arg));
}
case SPL_INTRIN_ALIGNOF: {
spl_ast_node_t *arg = spl_ast_node(a->sema->ast, vec_at(n->call.args, 0));
return spl_ir_builder_type_alignof(a->ir, node_ir(a, arg));
}
case SPL_INTRIN_ASSERT: {
/* 目前 SEMA 只做类型检查,emit 阶段留空,
@assert 展开需待 control.trap 语义明确后再实现 */
return 0;
}
default:
UNREACHABLE();
}
return 0;
}
static spl_ir_node_ref_t ast2ir_intrin_field(spl_ast2ir_t *a, spl_ast_node_t *n, spl_intrin_t in) {
switch (in) {
case SPL_INTRIN_LEN:
return ast2ir_intrin_len(a, n);
default:
UNREACHABLE();
}
return 0;
}
static spl_ir_node_ref_t ast2ir_intrin_len(spl_ast2ir_t *a, spl_ast_node_t *n) {
spl_ast_node_t *obj = spl_ast_node(a->sema->ast, n->field.obj);
spl_lang_type_id_t recv_lang = node_lang(a, obj);
spl_lang_type_node_t *recv = spl_lang_type_node(a->sema->type, recv_lang);
if (!recv)
return 0;
spl_lang_type_id_t usize_lang = spl_lang_make_int(a->sema->type, sizeof(void *) * 8, 0);
spl_type_id_t usize_ir = to_ir_type(a, usize_lang);
switch (recv->kind) {
case SPL_LANG_TYPE_ARRAY: {
spl_type_node_t *arr = spl_type_node(a->sema->type, recv->ir_type_id);
if (!arr)
return 0;
return spl_ir_builder_type_const_int(a->ir, usize_ir, arr->array_type.len);
}
case SPL_LANG_TYPE_SLICE: {
spl_ir_node_ref_t slice_val = emit_expr(a, n->field.obj);
if (!slice_val)
return 0;
return spl_ir_builder_agg_extract(a->ir, usize_ir, usize_ir, SPL_SLICE_LEN_FIELD_IDX,
slice_val);
}
default:
return 0;
}
}
static spl_ir_node_ref_t emit_lvalue(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
spl_ast_node_t *n = spl_ast_node(a->sema->ast, ref);
if (!n)
@@ -55,6 +119,8 @@ static spl_ir_node_ref_t emit_lvalue(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
spl_lang_type_node_t *obj_ln = spl_lang_type_node(a->sema->type, obj_lang);
if (!obj_ln)
return 0;
if (spl_intrin_lookup_field(obj_ln->kind, n->field.field) != SPL_INTRIN_NONE)
return 0; /* 内建字段不是左值 */
spl_ir_node_ref_t base = 0;
spl_lang_type_id_t agg_lang = 0;
@@ -97,9 +163,20 @@ static spl_ir_node_ref_t emit_lvalue(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
if (obj_ln->kind == SPL_LANG_TYPE_PTR) {
base = emit_expr(a, n->index.obj);
elem_lang = obj_ln->extra.elem;
} else if (obj_ln->kind == SPL_LANG_TYPE_ARRAY || obj_ln->kind == SPL_LANG_TYPE_SLICE) {
} else if (obj_ln->kind == SPL_LANG_TYPE_ARRAY) {
base = emit_lvalue(a, n->index.obj);
elem_lang = obj_ln->extra.elem;
} else if (obj_ln->kind == SPL_LANG_TYPE_SLICE) {
/* 切片:取出切片值,再 agg_extract 出 ptr 字段 */
spl_ir_node_ref_t slice_val = emit_expr(a, n->index.obj);
if (!slice_val)
return 0;
spl_lang_type_id_t elem = obj_ln->extra.elem;
spl_type_id_t ptr_ir = spl_type_builder_ptr(a->sema->type, to_ir_type(a, elem));
spl_ir_node_ref_t ptr = spl_ir_builder_agg_extract(a->ir, ptr_ir, ptr_ir,
SPL_SLICE_PTR_FIELD_IDX, slice_val);
base = ptr;
elem_lang = elem;
} else {
return 0;
}
@@ -315,6 +392,13 @@ static spl_ir_node_ref_t emit_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
}
}
case SPL_AST_EXPR_CALL: {
spl_ast_node_t *callee = spl_ast_node(a->sema->ast, n->call.callee);
if (callee && callee->kind == SPL_AST_EXPR_IDENT) {
spl_intrin_t in = spl_intrin_lookup_call(callee->ident.name);
if (in != SPL_INTRIN_NONE)
return ast2ir_intrin_call(a, n, in);
}
spl_ir_node_ref_t fn = emit_expr(a, n->call.callee);
if (!fn)
return 0;
@@ -331,6 +415,14 @@ static spl_ir_node_ref_t emit_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
return call;
}
case SPL_AST_EXPR_FIELD: {
spl_ast_node_t *obj = spl_ast_node(a->sema->ast, n->field.obj);
spl_lang_type_id_t obj_lang = node_lang(a, obj);
spl_lang_type_node_t *obj_ln = spl_lang_type_node(a->sema->type, obj_lang);
if (obj_ln) {
spl_intrin_t in = spl_intrin_lookup_field(obj_ln->kind, n->field.field);
if (in != SPL_INTRIN_NONE)
return ast2ir_intrin_field(a, n, in);
}
spl_ir_node_ref_t ptr = emit_lvalue(a, ref);
if (!ptr)
return 0;
@@ -436,7 +528,56 @@ static spl_ir_node_ref_t emit_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
emit_stmt(a, ref);
return 0;
}
case SPL_AST_EXPR_SLICE: {
spl_ast_node_t *obj = spl_ast_node(a->sema->ast, n->slice.obj);
spl_lang_type_id_t obj_lang = node_lang(a, obj);
spl_lang_type_node_t *obj_ln = spl_lang_type_node(a->sema->type, obj_lang);
if (!obj_ln)
return 0;
/* 目前只处理数组->切片的完整形式 arr[..](无 begin / end)
或 arr[begin..end] 的通用形式。简化实现只做完整切片。 */
spl_type_id_t slice_ir = node_ir(a, n); /* struct{ptr, len} */
if (!slice_ir)
return 0;
spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, slice_ir);
if (!node)
return 0;
/* 取数组元素指针 */
spl_ir_node_ref_t base = emit_lvalue(a, n->slice.obj);
if (!base)
return 0;
spl_type_id_t ptr_ir =
spl_type_builder_ptr(a->sema->type, to_ir_type(a, obj_ln->extra.elem));
/* 字段 0:ptr */
spl_ir_builder_agg_construct_field(a->ir, node, base);
/* 字段 1:len —— 数组取 len,切片取原切片 len */
spl_ir_node_ref_t len = 0;
if (obj_ln->kind == SPL_LANG_TYPE_ARRAY) {
spl_type_node_t *arr = spl_type_node(a->sema->type, obj_ln->ir_type_id);
spl_lang_type_id_t usize = spl_lang_make_int(a->sema->type, sizeof(void *) * 8, 0);
len = spl_ir_builder_type_const_int(a->ir, to_ir_type(a, usize), arr->array_type.len);
} else if (obj_ln->kind == SPL_LANG_TYPE_SLICE) {
spl_ir_node_ref_t slice_val = emit_expr(a, n->slice.obj);
spl_lang_type_id_t usize = spl_lang_make_int(a->sema->type, sizeof(void *) * 8, 0);
len = spl_ir_builder_agg_extract(a->ir, to_ir_type(a, usize), to_ir_type(a, usize),
SPL_SLICE_LEN_FIELD_IDX, slice_val);
} else {
return 0;
}
spl_ir_builder_agg_construct_field(a->ir, node, len);
return node;
}
case SPL_AST_EXPR_COMPTIME_CALL:
// TODO
return 0;
default:
TODO();
return 0;
}
}
@@ -449,18 +590,15 @@ static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
switch (n->kind) {
case SPL_AST_STATEMENT_RET: {
while (vec_size(a->defer_stack) > 0) {
spl_ast_node_ref_t d = vec_at(a->defer_stack, vec_size(a->defer_stack) - 1);
vec_pop(a->defer_stack);
spl_ast_node_ref_t d = vec_pop(a->defer_stack);
emit_stmt(a, d);
}
spl_type_id_t ret_ir = to_ir_type(a, a->cur_ret_lang);
if (n->statement_ret.expr) {
spl_ast_node_t *en = spl_ast_node(a->sema->ast, n->statement_ret.expr);
spl_ir_node_ref_t v = emit_expr(a, n->statement_ret.expr);
spl_type_id_t t = node_ir(a, en);
spl_ir_builder_control_ret(a->ir, t, v);
spl_ir_builder_control_ret(a->ir, ret_ir, v);
} else {
spl_lang_type_id_t rt = a->sema->current_fn_ret_tid;
spl_ir_builder_control_ret(a->ir, to_ir_type(a, rt), 0);
spl_ir_builder_control_ret(a->ir, ret_ir, 0);
}
return;
}
@@ -722,6 +860,9 @@ static void emit_fn(spl_ast2ir_t *a, spl_ast_node_t *n) {
spl_ir_func_ref_t fn_ref = spl_ir_builder_fn_begin(a->ir, n->fn_decl.name, fn_ir, attr);
map_put(a->def2ir_map, n->resolved_def_id, (spl_ir_node_ref_t)fn_ref);
spl_lang_type_id_t saved_ret = a->cur_ret_lang;
a->cur_ret_lang = fn_ln->extra.fn.ret;
usize defer_base = vec_size(a->defer_stack);
usize loop_base = vec_size(a->loop_stack);
@@ -753,7 +894,6 @@ static void emit_fn(spl_ast2ir_t *a, spl_ast_node_t *n) {
emit_expr(a, n->fn_decl.body);
if (!a->ir->terminated) {
/* 隐式返回路径:先跑 defer(LIFO),再 ret/unreachable */
while (vec_size(a->defer_stack) > defer_base) {
spl_ast_node_ref_t d = vec_pop(a->defer_stack);
emit_stmt(a, d);
@@ -783,6 +923,8 @@ static void emit_fn(spl_ast2ir_t *a, spl_ast_node_t *n) {
vec_pop(a->loop_stack);
}
a->cur_ret_lang = saved_ret;
spl_ir_builder_block_end(a->ir);
spl_ir_builder_fn_end(a->ir);
}
@@ -827,6 +969,7 @@ void spl_ast2ir_init(spl_ast2ir_t *ast2ir, spl_ir_builder_t *ir, const spl_sema_
vec_init(ast2ir->loop_stack);
vec_init(ast2ir->defer_stack);
ast2ir->err_count = 0;
ast2ir->cur_ret_lang = 0;
}
void spl_ast2ir_drop(spl_ast2ir_t *ast2ir) {
@@ -845,4 +988,4 @@ void spl_ast2ir_run(spl_ast2ir_t *ast2ir) {
if (!root || root->kind != SPL_AST_ROOT)
return;
emit_container(ast2ir, root->root.members);
}
}
+2 -1
View File
@@ -21,6 +21,7 @@ typedef struct {
spl_def2ir_map_t def2ir_map;
spl_loop_ctx_vec_t loop_stack;
spl_defer_stack_t defer_stack;
spl_lang_type_id_t cur_ret_lang;
int err_count;
} spl_ast2ir_t;
@@ -29,4 +30,4 @@ void spl_ast2ir_drop(spl_ast2ir_t *ast2ir);
void spl_ast2ir_run(spl_ast2ir_t *ast2ir);
#endif /* __SPL_AST2IR_H__ */
#endif /* __SPL_AST2IR_H__ */
+46
View File
@@ -0,0 +1,46 @@
#include "spl_intrin.h"
static const spl_intrin_info_t g_intrin_table[] = {
[SPL_INTRIN_NONE] = {0},
[SPL_INTRIN_SIZEOF] = {"@sizeof", SPL_INTRIN_SIZEOF, SPL_INTRIN_FORM_CALL, 1, 1,
SPL_INTRIN_RESULT_USIZE},
[SPL_INTRIN_ALIGNOF] = {"@alignof", SPL_INTRIN_ALIGNOF, SPL_INTRIN_FORM_CALL, 1, 1,
SPL_INTRIN_RESULT_USIZE},
[SPL_INTRIN_ASSERT] = {"@assert", SPL_INTRIN_ASSERT, SPL_INTRIN_FORM_CALL, 1, 2,
SPL_INTRIN_RESULT_UNIT},
[SPL_INTRIN_LEN] = {"len", SPL_INTRIN_LEN, SPL_INTRIN_FORM_FIELD, 0, 0,
SPL_INTRIN_RESULT_USIZE},
};
static const usize g_intrin_count = sizeof(g_intrin_table) / sizeof(g_intrin_table[0]);
const spl_intrin_info_t *spl_intrin_info(spl_intrin_t kind) {
if ((usize)kind >= g_intrin_count)
return NULL;
return &g_intrin_table[kind];
}
spl_intrin_t spl_intrin_lookup_call(const char *name) {
if (!name)
return SPL_INTRIN_NONE;
const char *n = name[0] == '@' ? name + 1 : name;
for (usize i = 1; i < g_intrin_count; ++i) {
const spl_intrin_info_t *d = &g_intrin_table[i];
if (d->form != SPL_INTRIN_FORM_CALL)
continue;
const char *dn = d->name[0] == '@' ? d->name + 1 : d->name;
if (strcmp(dn, n) == 0)
return d->kind;
}
return SPL_INTRIN_NONE;
}
spl_intrin_t spl_intrin_lookup_field(spl_lang_type_kind_t recv_kind, const char *field) {
if (!field)
return SPL_INTRIN_NONE;
if (strcmp(field, "len") == 0) {
if (recv_kind == SPL_LANG_TYPE_ARRAY || recv_kind == SPL_LANG_TYPE_SLICE)
return SPL_INTRIN_LEN;
}
return SPL_INTRIN_NONE;
}
+48
View File
@@ -0,0 +1,48 @@
#ifndef __SPL_INTRIN_H__
#define __SPL_INTRIN_H__
#include "../stage0/include/utils.h"
#include "spl_type.h"
typedef enum {
SPL_INTRIN_NONE = 0,
SPL_INTRIN_SIZEOF,
SPL_INTRIN_ALIGNOF,
SPL_INTRIN_ASSERT,
SPL_INTRIN_LEN,
} spl_intrin_t;
typedef enum {
SPL_INTRIN_FORM_CALL = 1, /* @sizeof(...) @assert(...) */
SPL_INTRIN_FORM_FIELD = 2, /* recv.len */
} spl_intrin_form_t;
typedef enum {
SPL_INTRIN_RESULT_UNIT,
SPL_INTRIN_RESULT_BOOL,
SPL_INTRIN_RESULT_USIZE,
} spl_intrin_result_t;
typedef struct {
const char *name;
spl_intrin_t kind;
spl_intrin_form_t form;
int min_args; /* FIELD 形态忽略 */
int max_args; /* -1 = variadic */
spl_intrin_result_t result;
} spl_intrin_info_t;
/* 统一入口:名字 → 枚举。name 允许带或不带 '@'。 */
spl_intrin_t spl_intrin_lookup_call(const char *name);
/* 统一入口:字段形态,按接收者类型分派。 */
spl_intrin_t spl_intrin_lookup_field(spl_lang_type_kind_t recv_kind, const char *field);
/* 从枚举取得元数据,SEMA/AST2IR 都从这里读。 */
const spl_intrin_info_t *spl_intrin_info(spl_intrin_t kind);
/* ---- 与 IR 侧共享的类型布局约定 ---- */
#define SPL_SLICE_PTR_FIELD_IDX 0
#define SPL_SLICE_LEN_FIELD_IDX 1
#endif /* __SPL_INTRIN_H__ */
+4 -2
View File
@@ -773,9 +773,11 @@ spl_ir_node_ref_t spl_ir_builder_control_unreachable(spl_ir_builder_t *b) {
}
spl_ir_node_ref_t spl_ir_builder_control_trap(spl_ir_builder_t *b) {
return builder_alloc_node(b, SPL_IR_CONTROL_TRAP);
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_CONTROL_TRAP);
b->terminated = true;
return ref;
}
spl_ir_node_ref_t spl_ir_builder_dbg_breakpoint(spl_ir_builder_t *b) {
return builder_alloc_node(b, SPL_IR_DBG_BREAKPOINT);
}
}
+96 -19
View File
@@ -1,4 +1,5 @@
#include "spl_sema.h"
#include "spl_intrin.h"
#include "spl_type.h"
void spl_scope_init(spl_scope_t *scope) {
@@ -52,6 +53,10 @@ bool spl_scope_find(spl_scope_t *scope, const char *name, spl_symbol_t *out) {
return false;
}
static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref);
static spl_lang_type_id_t sema_intrin_call(spl_sema_t *sema, spl_ast_node_t *n, spl_intrin_t in);
static spl_lang_type_id_t sema_intrin_field(spl_sema_t *sema, spl_ast_node_t *n, spl_intrin_t in);
static inline void sema_push_scope(spl_sema_t *sema) {
spl_scope_id_t new_scope = spl_scope_alloc(sema->scope);
sema->store_scope = sema->scope->current_scope;
@@ -170,6 +175,67 @@ static void sema_collect(spl_sema_t *sema, spl_ast_node_ref_t ref) {
}
}
static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref);
static spl_lang_type_id_t sema_intrin_call(spl_sema_t *sema, spl_ast_node_t *n, spl_intrin_t in) {
const spl_intrin_info_t *info = spl_intrin_info(in);
usize nargs = vec_size(n->call.args);
if ((int)nargs < info->min_args || (info->max_args >= 0 && (int)nargs > info->max_args)) {
SPL_ERROR(&n->dbg, "`%s` expects %d..%d args, got %zu", info->name, info->min_args,
info->max_args, nargs);
sema->error_count++;
return 0;
}
switch (in) {
case SPL_INTRIN_SIZEOF:
case SPL_INTRIN_ALIGNOF: {
spl_ast_node_ref_t arg_ref = vec_at(n->call.args, 0);
spl_ast_node_t *arg = spl_ast_node(sema->ast, arg_ref);
if (!arg || !(arg->kind == SPL_AST_TYPE_PATH || arg->kind == SPL_AST_TYPE_POINTER ||
arg->kind == SPL_AST_TYPE_ARRAY || arg->kind == SPL_AST_TYPE_SLICE ||
arg->kind == SPL_AST_TYPE_FN || arg->kind == SPL_AST_TYPE_PAREN)) {
SPL_ERROR(&n->dbg, "`%s` expects a type argument", info->name);
sema->error_count++;
return 0;
}
sema_parse(sema, arg_ref);
return spl_lang_make_int(sema->type, sizeof(void *) * 8, 0);
}
case SPL_INTRIN_ASSERT: {
spl_lang_type_id_t cond = sema_parse(sema, vec_at(n->call.args, 0));
spl_lang_type_id_t b = spl_lang_make_bool(sema->type);
if (spl_lang_type_coerce_to(sema->type, b, cond) == 0) {
SPL_ERROR(&n->dbg, "`@assert` condition must be bool");
sema->error_count++;
}
if (nargs == 2)
sema_parse(sema, vec_at(n->call.args, 1));
return spl_lang_make_unit(sema->type);
}
default:
UNREACHABLE();
}
return 0;
}
static spl_lang_type_id_t sema_intrin_field(spl_sema_t *sema, spl_ast_node_t *n, spl_intrin_t in) {
const spl_intrin_info_t *info = spl_intrin_info(in);
switch (info->result) {
case SPL_INTRIN_RESULT_USIZE:
return spl_lang_make_int(sema->type, sizeof(void *) * 8, 0);
case SPL_INTRIN_RESULT_BOOL:
return spl_lang_make_bool(sema->type);
case SPL_INTRIN_RESULT_UNIT:
return spl_lang_make_unit(sema->type);
default:
UNREACHABLE();
}
(void)n;
return 0;
}
static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
if (ref == 0)
return 0;
@@ -268,31 +334,33 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
sema->type, tk, &members, spl_type_builder_int(sema->type, 32, 1), layout);
vec_free(members);
// 创建语言级节点
spl_lang_type_node_t lang_node = {0};
spl_lang_type_kind_t lk;
switch (tk) {
case SPL_TYPE_STRUCT:
lang_node.kind = SPL_LANG_TYPE_STRUCT;
lk = SPL_LANG_TYPE_STRUCT;
break;
case SPL_TYPE_UNION:
lang_node.kind = SPL_LANG_TYPE_UNION;
lk = SPL_LANG_TYPE_UNION;
break;
case SPL_TYPE_ENUM:
lang_node.kind = SPL_LANG_TYPE_ENUM;
lk = SPL_LANG_TYPE_ENUM;
break;
case SPL_TYPE_SHAPE:
lang_node.kind = SPL_LANG_TYPE_SHAPE;
lk = SPL_LANG_TYPE_SHAPE;
break;
default:
lk = SPL_LANG_TYPE_STRUCT;
break;
}
lang_node.ir_type_id = agg_ir;
vec_push(sema->type->lang_table, lang_node);
spl_lang_type_id_t agg_lang = vec_size(sema->type->lang_table) - 1;
spl_def_resolve(sema->type, n->resolved_def_id, agg_lang);
n->resolved_type_id = agg_lang; // 存储 lang_id
// 处理聚合内部的函数声明
spl_lang_type_node_t lang_node = {0};
lang_node.kind = lk;
lang_node.ir_type_id = agg_ir;
spl_lang_type_id_t agg_lang = spl_lang_node_push(sema->type, &lang_node);
spl_def_resolve(sema->type, n->resolved_def_id, agg_lang);
n->resolved_type_id = agg_lang;
/* 聚合内部函数:方法后续单独处理,这里暂只做函数体的语义解析 */
for (usize i = 0; i < vec_size(te->type_aggregate.members); ++i) {
spl_ast_node_t *mn = spl_ast_node(sema->ast, vec_at(te->type_aggregate.members, i));
if (mn && mn->kind == SPL_AST_FN_DECL) {
@@ -302,7 +370,7 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
} else {
spl_lang_type_id_t tid = sema_parse(sema, n->type_decl.type_expr);
spl_def_resolve(sema->type, n->resolved_def_id, tid);
n->resolved_type_id = tid; // 存储 lang_id
n->resolved_type_id = tid;
}
break;
}
@@ -630,6 +698,16 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
}
case SPL_AST_EXPR_CALL: {
spl_ast_node_t *callee = spl_ast_node(sema->ast, n->call.callee);
if (callee && callee->kind == SPL_AST_EXPR_IDENT) {
spl_intrin_t in = spl_intrin_lookup_call(callee->ident.name);
if (in != SPL_INTRIN_NONE) {
spl_lang_type_id_t t = sema_intrin_call(sema, n, in);
n->resolved_type_id = t;
return t;
}
}
spl_lang_type_id_t callee_tid = sema_parse(sema, n->call.callee);
spl_lang_type_node_t *fn = spl_lang_type_node(sema->type, callee_tid);
if (!fn || fn->kind != SPL_LANG_TYPE_FN) {
@@ -702,12 +780,11 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
if (!obj_node)
return 0;
// 内建字段:数组/切片的 len
if ((obj_node->kind == SPL_LANG_TYPE_ARRAY || obj_node->kind == SPL_LANG_TYPE_SLICE) &&
strcmp(n->field.field, "len") == 0) {
spl_lang_type_id_t usize_tid = spl_lang_make_int(sema->type, sizeof(void *) * 8, 0);
n->resolved_type_id = usize_tid;
return usize_tid;
spl_intrin_t in = spl_intrin_lookup_field(obj_node->kind, n->field.field);
if (in != SPL_INTRIN_NONE) {
spl_lang_type_id_t t = sema_intrin_field(sema, n, in);
n->resolved_type_id = t;
return t;
}
// 自动解引用
+1 -1
View File
@@ -218,7 +218,7 @@ static void spl_lang_node_free_extra(spl_lang_type_node_t *n) {
}
}
static spl_lang_type_id_t spl_lang_node_push(spl_type_t *type, spl_lang_type_node_t *node) {
spl_lang_type_id_t spl_lang_node_push(spl_type_t *type, spl_lang_type_node_t *node) {
usize hash = spl_lang_type_hash(*node);
usize idx = (usize)-1;
spl_lang_type_id_t cand = 0;
+1
View File
@@ -168,6 +168,7 @@ spl_def_node_t *spl_def_node(const spl_type_t *type, spl_def_id_t id);
bool spl_lang_type_is_subtype(const spl_type_t *type, spl_lang_type_id_t sub,
spl_lang_type_id_t super);
bool spl_type_is_subtype(const spl_type_t *type, spl_type_id_t sub, spl_type_id_t super);
spl_lang_type_id_t spl_lang_node_push(spl_type_t *type, spl_lang_type_node_t *node);
/* 计算 from 是否可以隐式转换到 to。
* - to 是 INFER 时视为"接受任意 from",返回 from。