From 49ccdec3dd2b199a8620a5a7f3efa6f673977f1a Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Fri, 11 Sep 2026 19:26:48 +0800 Subject: [PATCH] =?UTF-8?q?stage1=20=E5=AE=9E=E7=8E=B0=E6=9B=B4=E5=A4=9Aas?= =?UTF-8?q?t2ir=20=E4=BF=AE=E5=A4=8Dbug=20=E6=8F=90=E4=BE=9B=E5=86=85?= =?UTF-8?q?=E7=BD=AE=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nob.c | 47 +++++-------- stage1/spl_ast.c | 39 +++++++---- stage1/spl_ast2ir.c | 165 +++++++++++++++++++++++++++++++++++++++++--- stage1/spl_ast2ir.h | 3 +- stage1/spl_intrin.c | 46 ++++++++++++ stage1/spl_intrin.h | 48 +++++++++++++ stage1/spl_ir.c | 6 +- stage1/spl_sema.c | 115 +++++++++++++++++++++++++----- stage1/spl_type.c | 2 +- stage1/spl_type.h | 1 + 10 files changed, 396 insertions(+), 76 deletions(-) create mode 100644 stage1/spl_intrin.c create mode 100644 stage1/spl_intrin.h diff --git a/nob.c b/nob.c index 15140a1..2152b75 100644 --- a/nob.c +++ b/nob.c @@ -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) { diff --git a/stage1/spl_ast.c b/stage1/spl_ast.c index 82ae34c..b286ffb 100644 --- a/stage1/spl_ast.c +++ b/stage1/spl_ast.c @@ -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); diff --git a/stage1/spl_ast2ir.c b/stage1/spl_ast2ir.c index 6a6294f..bc7dab3 100644 --- a/stage1/spl_ast2ir.c +++ b/stage1/spl_ast2ir.c @@ -1,5 +1,5 @@ #include "spl_ast2ir.h" -#include +#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); -} \ No newline at end of file +} diff --git a/stage1/spl_ast2ir.h b/stage1/spl_ast2ir.h index 3b5e271..806b396 100644 --- a/stage1/spl_ast2ir.h +++ b/stage1/spl_ast2ir.h @@ -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__ */ \ No newline at end of file +#endif /* __SPL_AST2IR_H__ */ diff --git a/stage1/spl_intrin.c b/stage1/spl_intrin.c new file mode 100644 index 0000000..f5f637d --- /dev/null +++ b/stage1/spl_intrin.c @@ -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; +} diff --git a/stage1/spl_intrin.h b/stage1/spl_intrin.h new file mode 100644 index 0000000..009e5d3 --- /dev/null +++ b/stage1/spl_intrin.h @@ -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__ */ diff --git a/stage1/spl_ir.c b/stage1/spl_ir.c index ef41ad0..d86ac1d 100644 --- a/stage1/spl_ir.c +++ b/stage1/spl_ir.c @@ -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); -} \ No newline at end of file +} diff --git a/stage1/spl_sema.c b/stage1/spl_sema.c index a4a948a..0cc3ee6 100644 --- a/stage1/spl_sema.c +++ b/stage1/spl_sema.c @@ -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; } // 自动解引用 diff --git a/stage1/spl_type.c b/stage1/spl_type.c index 0b8b967..17f6e40 100644 --- a/stage1/spl_type.c +++ b/stage1/spl_type.c @@ -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; diff --git a/stage1/spl_type.h b/stage1/spl_type.h index 05550ed..54efa7e 100644 --- a/stage1/spl_type.h +++ b/stage1/spl_type.h @@ -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。