From e4347cc3eaff7319797d9ae109a41bac675e0572 Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Wed, 16 Sep 2026 15:21:59 +0800 Subject: [PATCH] =?UTF-8?q?stage1=20=E9=87=8D=E5=86=99=E8=BF=9B=E8=A1=8C?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=AE=BE=E8=AE=A1=E5=B9=B6=E9=87=8D=E6=9E=84?= =?UTF-8?q?=20=E6=8F=90=E4=BE=9Bdiag=E6=9B=BF=E6=8D=A2=E8=80=81=E6=97=A7?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nob.c | 1 + stage0/spl_syscall.c | 13 ++ stage1/spl_ast.c | 203 ++++++++++----------- stage1/spl_ast.h | 5 +- stage1/spl_ast2ir.c | 111 +++--------- stage1/spl_ast2ir.h | 5 +- stage1/spl_diag.c | 368 ++++++++++++++++++++++++++++++++++++++ stage1/spl_diag.h | 165 ++++++++++++++++++ stage1/spl_ir2vm.c | 32 +++- stage1/spl_ir2vm.h | 5 +- stage1/spl_sema.c | 407 ++++++++++++++++++++----------------------- stage1/spl_sema.h | 15 +- stage1/spl_type.c | 148 ++++++---------- stage1/splc0.c | 31 +++- 14 files changed, 983 insertions(+), 526 deletions(-) create mode 100644 stage1/spl_diag.c create mode 100644 stage1/spl_diag.h diff --git a/nob.c b/nob.c index 2146a0b..3103f27 100644 --- a/nob.c +++ b/nob.c @@ -23,6 +23,7 @@ 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[] = { "stage1/splc0.c", + "stage1/spl_diag.c", "stage1/spl_lexer.c", "stage1/spl_ast.c", "stage1/spl_dumptree.c", diff --git a/stage0/spl_syscall.c b/stage0/spl_syscall.c index f2dc532..2b26fee 100644 --- a/stage0/spl_syscall.c +++ b/stage0/spl_syscall.c @@ -37,6 +37,7 @@ #define SYSCALL_0(name, ret_expr) \ static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ + (void)_vm; \ CHECK_NARGS(#name, 0); \ (void)args; \ return (spl_vm_val_t)(uintptr_t)(ret_expr); \ @@ -44,6 +45,7 @@ #define SYSCALL_1(name, t1, ret_expr) \ static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ + (void)_vm; \ CHECK_NARGS(#name, 1); \ t1 a1 = (t1)(uintptr_t)args[0]; \ return (spl_vm_val_t)(uintptr_t)(ret_expr); \ @@ -51,6 +53,7 @@ #define SYSCALL_2(name, t1, t2, ret_expr) \ static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ + (void)_vm; \ CHECK_NARGS(#name, 2); \ t1 a1 = (t1)(uintptr_t)args[0]; \ t2 a2 = (t2)(uintptr_t)args[1]; \ @@ -59,6 +62,7 @@ #define SYSCALL_3(name, t1, t2, t3, ret_expr) \ static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ + (void)_vm; \ CHECK_NARGS(#name, 3); \ t1 a1 = (t1)(uintptr_t)args[0]; \ t2 a2 = (t2)(uintptr_t)args[1]; \ @@ -68,6 +72,7 @@ #define SYSCALL_4(name, t1, t2, t3, t4, ret_expr) \ static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ + (void)_vm; \ CHECK_NARGS(#name, 4); \ t1 a1 = (t1)(uintptr_t)args[0]; \ t2 a2 = (t2)(uintptr_t)args[1]; \ @@ -145,6 +150,7 @@ SYSCALL_4(vm_fwrite, const void *, size_t, size_t, FILE *, fwrite(a1, a2, a3, a4 /* vm_fsize - get file size in bytes */ static spl_vm_val_t vm_fsize(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; CHECK_NARGS("vm_fsize", 1); FILE *f = (FILE *)(uintptr_t)args[0]; long cur = ftell(f); @@ -160,6 +166,7 @@ SYSCALL_0(vm_stderr, stderr) /* vm_read_file - read entire file into a malloc'd, null-terminated buffer */ static spl_vm_val_t vm_read_file(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; CHECK_NARGS("vm_read_file", 1); const char *path = (const char *)(uintptr_t)args[0]; if (path == nullptr) { @@ -248,6 +255,7 @@ static spl_vm_val_t vm_memcmp(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { } static spl_vm_val_t vm_printf(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; if (nargs <= 0) return 0; @@ -323,6 +331,7 @@ static spl_vm_val_t vm_printf(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { /* vm_new - create a new sub-VM instance, returns spl_vm_t* */ static spl_vm_val_t vm_new(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; CHECK_NARGS("vm_new", 0); (void)args; spl_vm_t *vm = (spl_vm_t *)malloc(sizeof(spl_vm_t)); @@ -334,6 +343,7 @@ static spl_vm_val_t vm_new(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { /* vm_drop - destroy a sub-VM and its loaded program */ static spl_vm_val_t vm_drop(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; CHECK_NARGS("vm_drop", 1); spl_vm_t *vm = (spl_vm_t *)(uintptr_t)args[0]; if (!vm) @@ -350,6 +360,7 @@ static spl_vm_val_t vm_drop(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { /* vm_load - load a .sir file, register syscalls, return spl_prog_t* */ static spl_vm_val_t vm_load(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; CHECK_NARGS("vm_load", 2); spl_vm_t *vm = (spl_vm_t *)(uintptr_t)args[0]; const char *path = (const char *)(uintptr_t)args[1]; @@ -374,6 +385,7 @@ static spl_vm_val_t vm_load(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { /* vm_push - push a value onto the sub-VM's stack (for passing arguments) */ static spl_vm_val_t vm_push(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; CHECK_NARGS("vm_push", 2); spl_vm_t *vm = (spl_vm_t *)(uintptr_t)args[0]; spl_vm_val_t val = args[1]; @@ -399,6 +411,7 @@ static spl_vm_val_t vm_push(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { * - Sets ip to the function address */ static spl_vm_val_t vm_call(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; CHECK_NARGS("vm_call", 3); spl_vm_t *vm = (spl_vm_t *)(uintptr_t)args[0]; const char *name = (const char *)(uintptr_t)args[1]; diff --git a/stage1/spl_ast.c b/stage1/spl_ast.c index b1c7a47..efe2577 100644 --- a/stage1/spl_ast.c +++ b/stage1/spl_ast.c @@ -59,12 +59,34 @@ const char *spl_unary_op_name(spl_unary_op_t op) { typedef struct { spl_ast_t *ast; + spl_diag_t *diag; usize pos; int failed; int stop_as; int stop_agg; } parser_t; +/* token -> dbg 位置;tok 可为 NULL */ +static spl_dbg_node_t tok_to_dbg(const spl_tok_t *t) { + spl_dbg_node_t d = {0}; + if (t) { + d.fname = t->fname; + d.line = (int)t->line; + d.col = (int)t->col; + } + return d; +} + +/* parser 层的 fatal 发射。diag 为 NULL 时静默。 + * 调用者必须紧跟 return / break,因为 diag_fatal 不终止流程。 */ +#define PARSE_FATAL(p, kind, tok, ...) \ + do { \ + if ((p)->diag) { \ + spl_dbg_node_t _pd = tok_to_dbg(tok); \ + spl_diag_fatal((p)->diag, (kind), &_pd, __VA_ARGS__); \ + } \ + } while (0) + static inline int is_trivia(spl_tok_type_t t) { return t == TOK_ENDLINE || t == TOK_LINE_COMMENT; } static inline const spl_tok_t *peek(parser_t *p) { @@ -301,7 +323,7 @@ static void parse_tag_list(parser_t *p, spl_ast_node_ref_vec_t *out, int is_exte if (is_external) { t = peek(p); if (!t || t->type != TOK_NOT) { - SPL_FATAL(t, "expected '!' in external tag"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '!' in external tag"); return; } advance(p); @@ -309,7 +331,7 @@ 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_IDENT) { - SPL_FATAL(t, "expected tag name"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected tag name"); return; } advance(p); @@ -328,7 +350,7 @@ static void parse_tag_list(parser_t *p, spl_ast_node_ref_vec_t *out, int is_exte 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"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ')' in tag args"); return; } advance(p); @@ -363,15 +385,9 @@ static void parse_param_list(parser_t *p, spl_ast_node_ref_vec_t *out) { if (peek(p) && peek(p)->type == TOK_COMMA) advance(p); break; - // } else if (t->type == KW_VOID) { - // advance(p); - // t = peek(p); - // if (!t || t->type != TOK_R_PAREN) { - // SPL_FATAL(t, "expected ')' after void"); - // } - // break; } else { - SPL_FATAL(t, "unexpected token in parameter list"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, + "unexpected token in parameter list"); break; } } @@ -384,14 +400,14 @@ static spl_ast_node_ref_t parse_param_decl_impl(parser_t *p) { const spl_tok_t *name = peek(p); if (!name || (name->type != TOK_IDENT && name->type != KW_UNDERSCORE)) { - SPL_FATAL(name, "expected parameter name or '_'"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, name, "expected parameter name or '_'"); return 0; } advance(p); const spl_tok_t *t = peek(p); if (!t || t->type != TOK_COLON) { - SPL_FATAL(t, "expected ':' in parameter declaration"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ':' in parameter declaration"); return 0; } advance(p); @@ -415,14 +431,14 @@ static spl_ast_node_ref_t parse_fn_decl(parser_t *p, spl_ast_node_ref_vec_t tag_ const spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { - SPL_FATAL(name ? name : kw, "expected function name"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, name ? name : kw, "expected function name"); return 0; } advance(p); const spl_tok_t *t = peek(p); if (!t || t->type != TOK_L_PAREN) { - SPL_FATAL(t, "expected '(' in function declaration"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '(' in function declaration"); return 0; } advance(p); @@ -432,7 +448,7 @@ static spl_ast_node_ref_t parse_fn_decl(parser_t *p, spl_ast_node_ref_vec_t tag_ parse_param_list(p, ¶ms); t = peek(p); if (!t || t->type != TOK_R_PAREN) { - SPL_FATAL(t, "expected ')' in function declaration"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ')' in function declaration"); return 0; } advance(p); @@ -451,7 +467,8 @@ static spl_ast_node_ref_t parse_fn_decl(parser_t *p, spl_ast_node_ref_vec_t tag_ } else if (t && t->type == TOK_SEMICOLON) { advance(p); } else { - SPL_FATAL(t, "function declaration must end with ';' or block"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, + "function declaration must end with ';' or block"); return 0; } @@ -474,14 +491,14 @@ static spl_ast_node_ref_t parse_type_decl(parser_t *p, spl_ast_node_ref_vec_t ta const spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { - SPL_FATAL(name ? name : kw, "expected type name"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, name ? name : kw, "expected type name"); return 0; } advance(p); const spl_tok_t *t = peek(p); if (!t || t->type != TOK_ASSIGN) { - SPL_FATAL(t, "expected '=' in type declaration"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '=' in type declaration"); return 0; } advance(p); @@ -636,7 +653,7 @@ static spl_ast_node_ref_t parse_container_declaration(parser_t *p) { return ref; } default: - SPL_FATAL(t, "unrecognized declaration"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, "unrecognized declaration"); vec_free(tag_list); return 0; } @@ -659,7 +676,8 @@ static spl_ast_node_ref_t parse_var_pattern_atom(parser_t *p) { advance(p); const spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { - SPL_FATAL(name, "expected identifier after '.' in pattern"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, name, + "expected identifier after '.' in pattern"); return 0; } advance(p); @@ -674,7 +692,7 @@ static spl_ast_node_ref_t parse_var_pattern_atom(parser_t *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"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ']' in pattern"); return 0; } advance(p); @@ -685,7 +703,7 @@ static spl_ast_node_ref_t parse_var_pattern_atom(parser_t *p) { spl_ast_node_ref_t inner = parse_var_pattern(p); t = peek(p); if (!t || t->type != TOK_R_PAREN) { - SPL_FATAL(t, "expected ')' in pattern"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ')' in pattern"); return 0; } advance(p); @@ -700,7 +718,7 @@ static spl_ast_node_ref_t parse_var_pattern_atom(parser_t *p) { } return ref; } else { - SPL_FATAL(t, "unexpected token in pattern"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, "unexpected token in pattern"); return 0; } } @@ -753,7 +771,7 @@ static spl_ast_node_ref_t parse_match_pattern(parser_t *p) { static spl_ast_node_ref_t parse_type_base(parser_t *p) { const spl_tok_t *bt = peek(p); if (!bt) { - SPL_FATAL(bt, "expected type"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, bt, "expected type"); return 0; } @@ -762,7 +780,7 @@ static spl_ast_node_ref_t parse_type_base(parser_t *p) { advance(p); const spl_tok_t *t = peek(p); if (!t || t->type != TOK_L_PAREN) { - SPL_FATAL(t, "expected '(' in function type"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '(' in function type"); return 0; } advance(p); @@ -785,7 +803,7 @@ static spl_ast_node_ref_t parse_type_base(parser_t *p) { t = peek(p); if (!t || t->type != TOK_R_PAREN) { - SPL_FATAL(t, "expected ')' in function type"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ')' in function type"); return 0; } advance(p); @@ -808,7 +826,7 @@ static spl_ast_node_ref_t parse_type_base(parser_t *p) { advance(p); const spl_tok_t *t = peek(p); if (!t || t->type != TOK_L_BRACE) { - SPL_FATAL(t, "expected '{' in aggregate type"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '{' in aggregate type"); return 0; } advance(p); @@ -822,7 +840,7 @@ static spl_ast_node_ref_t parse_type_base(parser_t *p) { while (!p->failed) { t = peek(p); if (!t || t->type == TOK_EOF) { - SPL_FATAL(t, "aggregate type missing '}'"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "aggregate type missing '}'"); return ref; } if (t->type == TOK_R_BRACE) { @@ -862,10 +880,7 @@ static spl_ast_node_ref_t parse_type_base(parser_t *p) { (len == 5 && strncmp(name, "usize", 5) == 0) || (len == 3 && strncmp(name, "f32", 3) == 0) || (len == 3 && strncmp(name, "f64", 3) == 0) || - (len == 4 && strncmp(name, "bool", 4) == 0) - // (len == 4 && strncmp(name, "void", 4) == 0) || - // (len == 3 && strncmp(name, "any", 3) == 0) - ) { + (len == 4 && strncmp(name, "bool", 4) == 0)) { advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_PATH, bt); spl_ast_node_t *tp = node_at(p->ast, ref); @@ -885,7 +900,8 @@ static spl_ast_node_ref_t parse_type_base(parser_t *p) { advance(p); const spl_tok_t *seg = peek(p); if (!seg || seg->type != TOK_IDENT) { - SPL_FATAL(seg, "expected identifier after '.' in type path"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, seg, + "expected identifier after '.' in type path"); break; } advance(p); @@ -906,7 +922,7 @@ static spl_ast_node_ref_t parse_type_base(parser_t *p) { return ref; } - SPL_FATAL(bt, "unrecognized type"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, bt, "unrecognized type"); return 0; } @@ -918,7 +934,7 @@ static spl_ast_node_ref_t parse_type_comptime_call(parser_t *p) { const spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { - SPL_FATAL(name, "expected comptime name"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, name, "expected comptime name"); return 0; } advance(p); @@ -932,7 +948,7 @@ static spl_ast_node_ref_t parse_type_comptime_call(parser_t *p) { args = parse_expr_list(p); t = peek(p); if (!t || t->type != TOK_R_PAREN) { - SPL_FATAL(t, "expected ')' in comptime type"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ')' in comptime type"); vec_free(args); return 0; } @@ -949,7 +965,7 @@ static spl_ast_node_ref_t parse_type_comptime_call(parser_t *p) { static spl_ast_node_ref_t parse_type_expr(parser_t *p) { const spl_tok_t *t = peek(p); if (!t) { - SPL_FATAL(t, "expected type"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected type"); return 0; } @@ -980,7 +996,7 @@ static spl_ast_node_ref_t parse_type_expr(parser_t *p) { t = peek(p); if (!t || t->type != TOK_R_BRACKET) { - SPL_FATAL(t, "expected ']' in array type"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ']' in array type"); return 0; } advance(p); @@ -1027,7 +1043,7 @@ static spl_ast_node_ref_t parse_type_expr(parser_t *p) { t = peek(p); if (!t || t->type != TOK_R_PAREN) { - SPL_FATAL(t, "expected ')' in parenthesized type"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ')' in parenthesized type"); return 0; } advance(p); @@ -1071,37 +1087,35 @@ static spl_ast_node_ref_vec_t parse_aggregate_fields(parser_t *p) { const spl_tok_t *t = peek(p); if (!t || t->type != TOK_L_BRACE) { - SPL_FATAL(t, "expected '{' in aggregate literal"); - return fields; // 空 vec,调用者处理 + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '{' in aggregate literal"); + return fields; } - advance(p); // 消费 '{' + advance(p); while (!p->failed) { t = peek(p); if (!t || t->type == TOK_R_BRACE || t->type == TOK_EOF) break; - // 字段必须由 '.' 开头 if (t->type != TOK_DOT) { - SPL_FATAL(t, "expected '.' in aggregate field initializer"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, + "expected '.' in aggregate field initializer"); break; } advance(p); t = peek(p); if (!t || t->type != TOK_IDENT) { - SPL_FATAL(t, "expected field name after '.'"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected field name after '.'"); break; } advance(p); - // 创建 struct_init_item 节点 spl_ast_node_ref_t item_ref = new_node(p, SPL_AST_STRUCT_INIT_ITEM, t); spl_ast_node_t *item = node_at(p->ast, item_ref); SET_STR_FIELD(p->ast, item->struct_init_item.name, t); item->struct_init_item.expr = 0; - // 可选:= 表达式 if (peek(p) && peek(p)->type == TOK_ASSIGN) { advance(p); spl_ast_node_ref_t expr_ref = parse_expr(p); @@ -1111,7 +1125,6 @@ static spl_ast_node_ref_vec_t parse_aggregate_fields(parser_t *p) { vec_push(fields, item_ref); - // 分隔符 t = peek(p); if (t && (t->type == TOK_COMMA || t->type == TOK_SEMICOLON)) { advance(p); @@ -1122,9 +1135,9 @@ static spl_ast_node_ref_vec_t parse_aggregate_fields(parser_t *p) { t = peek(p); if (!t || t->type != TOK_R_BRACE) { - SPL_FATAL(t, "expected '}' in aggregate literal"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '}' in aggregate literal"); } else { - advance(p); // 消费 '}' + advance(p); } return fields; @@ -1295,7 +1308,7 @@ static spl_ast_node_ref_t parse_prefix(parser_t *p) { else if (kw && kw->type == KW_FOR) ref = parse_for_expr(p); else { - SPL_FATAL(kw, "expected while/loop/for after label"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, kw, "expected while/loop/for after label"); return 0; } if (!ref) @@ -1357,7 +1370,7 @@ static spl_ast_node_ref_t parse_postfix(parser_t *p) { t = peek(p); if (!t || t->type != TOK_R_PAREN) { - SPL_FATAL(t, "expected ')' in call"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ')' in call"); return expr; } advance(p); @@ -1378,7 +1391,8 @@ static spl_ast_node_ref_t parse_postfix(parser_t *p) { spl_ast_node_ref_t ref = mk_unary(p, t, SPL_UNARY_OP_DEREF, expr); expr = ref; } else { - SPL_FATAL(next, "expected identifier or '*' after '.'"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, next, + "expected identifier or '*' after '.'"); break; } } else if (t->type == TOK_L_BRACKET) { @@ -1392,7 +1406,7 @@ static spl_ast_node_ref_t parse_postfix(parser_t *p) { end = parse_expr(p); t = peek(p); if (!t || t->type != TOK_R_BRACKET) { - SPL_FATAL(t, "expected ']' in slice"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ']' in slice"); return expr; } advance(p); @@ -1404,7 +1418,7 @@ static spl_ast_node_ref_t parse_postfix(parser_t *p) { } else { t = peek(p); if (!t || t->type != TOK_R_BRACKET) { - SPL_FATAL(t, "expected ']' in index"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ']' in index"); return expr; } advance(p); @@ -1423,7 +1437,7 @@ static spl_ast_node_ref_t parse_postfix(parser_t *p) { static spl_ast_node_ref_t parse_primary(parser_t *p) { const spl_tok_t *t = peek(p); if (!t) { - SPL_FATAL(t, "unexpected end of expression"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, "unexpected end of expression"); return 0; } @@ -1491,7 +1505,7 @@ static spl_ast_node_ref_t parse_primary(parser_t *p) { advance(p); const spl_tok_t *nx = peek(p); if (!nx) { - SPL_FATAL(t, "unexpected '.'"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, "unexpected '.'"); return 0; } if (nx->type == TOK_L_BRACE && !p->stop_agg) { @@ -1508,7 +1522,7 @@ static spl_ast_node_ref_t parse_primary(parser_t *p) { spl_ast_node_ref_vec_t elems = parse_expr_list(p); const spl_tok_t *close = peek(p); if (!close || close->type != TOK_R_BRACKET) { - SPL_FATAL(close, "expected ']'"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, close, "expected ']'"); return 0; } advance(p); // 消费 ']' @@ -1518,7 +1532,7 @@ static spl_ast_node_ref_t parse_primary(parser_t *p) { arr->array_literal.elem_type = 0; return ref; } else { - SPL_FATAL(nx, "expected '{' or '[' after '.'"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, nx, "expected '{' or '[' after '.'"); return 0; } } @@ -1552,7 +1566,7 @@ static spl_ast_node_ref_t parse_primary(parser_t *p) { } t = peek(p); if (!t || t->type != TOK_R_PAREN) { - SPL_FATAL(t, "expected ')'"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ')'"); return 0; } advance(p); @@ -1562,7 +1576,7 @@ static spl_ast_node_ref_t parse_primary(parser_t *p) { } else { t = peek(p); if (!t || t->type != TOK_R_PAREN) { - SPL_FATAL(t, "expected ')'"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ')'"); return 0; } advance(p); @@ -1581,7 +1595,7 @@ static spl_ast_node_ref_t parse_primary(parser_t *p) { case KW_MATCH: return parse_match_expr(p); default: - SPL_FATAL(t, "unrecognized expression"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, "unrecognized expression"); return 0; } } @@ -1609,7 +1623,7 @@ static spl_ast_node_ref_t parse_array_literal(parser_t *p) { t = peek(p); if (!t || t->type != TOK_R_BRACKET) { - SPL_FATAL(t, "expected ']' in array literal"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ']' in array literal"); return 0; } advance(p); @@ -1618,7 +1632,7 @@ static spl_ast_node_ref_t parse_array_literal(parser_t *p) { t = peek(p); if (!t || t->type != TOK_L_BRACKET) { - SPL_FATAL(t, "expected '[' in array literal"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '[' in array literal"); return 0; } advance(p); @@ -1627,7 +1641,7 @@ static spl_ast_node_ref_t parse_array_literal(parser_t *p) { t = peek(p); if (!t || t->type != TOK_R_BRACKET) { - SPL_FATAL(t, "expected ']' in array literal"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ']' in array literal"); return 0; } advance(p); @@ -1650,7 +1664,7 @@ static spl_ast_node_ref_t parse_comptime_call(parser_t *p) { const spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { - SPL_FATAL(name, "expected comptime name"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, name, "expected comptime name"); return 0; } advance(p); @@ -1666,7 +1680,7 @@ static spl_ast_node_ref_t parse_comptime_call(parser_t *p) { args = parse_expr_list(p); t = peek(p); if (!t || t->type != TOK_R_PAREN) { - SPL_FATAL(t, "expected ')' in comptime call"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ')' in comptime call"); vec_free(args); return 0; } @@ -1688,7 +1702,7 @@ static spl_ast_node_ref_t parse_label(parser_t *p) { advance(p); const spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { - SPL_FATAL(name, "expected identifier after '$'"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, name, "expected identifier after '$'"); return 0; } advance(p); @@ -1726,14 +1740,15 @@ static spl_ast_node_ref_t parse_if_expr(parser_t *p) { advance(p); init_expr = parse_expr(p); } else { - SPL_FATAL(t, "expected '=' in if var"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '=' in if var"); return 0; } } else if (t && t->type == TOK_ASSIGN) { advance(p); init_expr = parse_expr(p); } else { - SPL_FATAL(t, "expected type annotation or '=' in if var"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, + "expected type annotation or '=' in if var"); return 0; } @@ -1847,7 +1862,7 @@ static spl_ast_node_ref_t parse_for_expr(parser_t *p) { const spl_tok_t *t = peek(p); if (!t || t->type != KW_AS) { - SPL_FATAL(t, "expected 'as' in for loop"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected 'as' in for loop"); return 0; } advance(p); @@ -1856,7 +1871,7 @@ static spl_ast_node_ref_t parse_for_expr(parser_t *p) { vec_init(idents); t = peek(p); if (!t || (t->type != TOK_IDENT && t->type != KW_UNDERSCORE)) { - SPL_FATAL(t, "expected binding variable or '_' in for"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected binding variable or '_' in for"); return 0; } advance(p); @@ -1868,7 +1883,8 @@ static spl_ast_node_ref_t parse_for_expr(parser_t *p) { advance(p); t = peek(p); if (!t || (t->type != TOK_IDENT && t->type != KW_UNDERSCORE)) { - SPL_FATAL(t, "expected binding variable or '_' in for"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, + "expected binding variable or '_' in for"); return 0; } advance(p); @@ -1919,7 +1935,7 @@ static int parse_match_arm(parser_t *p, spl_ast_node_ref_vec_t *patterns_out, const spl_tok_t *t = peek(p); if (!t || t->type != TOK_RIGHT_FAT_ARROW) { - SPL_FATAL(t, "expected '=>' in match arm"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '=>' in match arm"); return 0; } advance(p); @@ -1927,7 +1943,7 @@ static int parse_match_arm(parser_t *p, spl_ast_node_ref_vec_t *patterns_out, spl_ast_node_ref_t body; t = peek(p); if (!t || t->type != TOK_L_BRACE) { - SPL_FATAL(t, "expected block after '=>' in match arm"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected block after '=>' in match arm"); return 0; } body = parse_block(p); @@ -1952,7 +1968,7 @@ static spl_ast_node_ref_t parse_match_expr(parser_t *p) { const spl_tok_t *t = peek(p); if (!t || t->type != TOK_L_BRACE) { - SPL_FATAL(t, "expected '{' in match"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '{' in match"); return 0; } advance(p); @@ -1973,7 +1989,7 @@ static spl_ast_node_ref_t parse_match_expr(parser_t *p) { t = peek(p); if (!t || t->type != TOK_R_BRACE) { - SPL_FATAL(t, "expected '}' in match"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '}' in match"); return 0; } advance(p); @@ -2145,7 +2161,7 @@ static spl_ast_node_ref_t parse_statement(parser_t *p) { node_at(p->ast, ref)->statement_expr.expr = expr; return ref; } else { - SPL_FATAL(t, "unrecognized statement"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, "unrecognized statement"); return 0; } } @@ -2155,7 +2171,7 @@ static spl_ast_node_ref_t parse_statement(parser_t *p) { static spl_ast_node_ref_t parse_block(parser_t *p) { const spl_tok_t *start = peek(p); if (!start || start->type != TOK_L_BRACE) { - SPL_FATAL(start, "expected '{'"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, start, "expected '{'"); return 0; } advance(p); @@ -2168,7 +2184,7 @@ static spl_ast_node_ref_t parse_block(parser_t *p) { while (!p->failed) { const spl_tok_t *t = peek(p); if (!t || t->type == TOK_EOF) { - SPL_FATAL(t, "block missing '}'"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "block missing '}'"); return ref; } if (t->type == TOK_R_BRACE) { @@ -2190,7 +2206,8 @@ static spl_ast_node_ref_t parse_block(parser_t *p) { vec_push(block->block.stmts, expr); } else if (t && t->type == TOK_R_BRACE) { if (block->block.tail_expr != 0) { - SPL_FATAL(t, "only one tail expression allowed"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, + "only one tail expression allowed"); } block->block.tail_expr = expr; } else { @@ -2202,12 +2219,13 @@ static spl_ast_node_ref_t parse_block(parser_t *p) { if (block_like) { vec_push(block->block.stmts, expr); } else { - SPL_FATAL(t, "expected ';' or '}' after expression"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, + "expected ';' or '}' after expression"); break; } } } else { - SPL_FATAL(t, "unrecognized token in block"); + PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, "unrecognized token in block"); break; } } @@ -2220,7 +2238,7 @@ void spl_ast_init(spl_ast_t *ast, const spl_tok_vec_t *tok_vec) { vec_init(ast->node_buckets); vec_init(ast->str_buckets); ast->root = 0; - ast->parsed = 0; + ast->diag = NULL; spl_ast_node_t n = {0}; vec_push(ast->node_buckets, n); @@ -2232,11 +2250,11 @@ void spl_ast_parse(spl_ast_t *ast) { parser_t p; p.ast = ast; + p.diag = ast->diag; p.pos = 0; p.failed = 0; p.stop_as = 0; p.stop_agg = 0; - ast->parsed = 0; spl_ast_node_ref_vec_t external_tags; vec_init(external_tags); @@ -2276,7 +2294,6 @@ void spl_ast_parse(spl_ast_t *ast) { node_at(ast, root)->root.members = container_members; ast->root = root; - ast->parsed = p.failed ? -1 : 1; } void spl_ast_drop(spl_ast_t *ast) { @@ -2287,7 +2304,6 @@ void spl_ast_drop(spl_ast_t *ast) { vec_for(ast->node_buckets, idx) { vec_free(vec_at(ast->node_buckets, idx).attrs); } vec_free(ast->node_buckets); vec_free(ast->input); - ast->parsed = 0; ast->root = 0; } @@ -2297,16 +2313,6 @@ spl_ast_node_t *spl_ast_node(spl_ast_t *ast, spl_ast_node_ref_t node) { return &ast->node_buckets.data[node]; } -void spl_ast_valid(spl_ast_t *ast) { - if (!ast) - return; - if (ast->parsed != 1) { - printf("valid: AST not parsed successfully (parsed=%d)\n", ast->parsed); - return; - } - /* TODO */ -} - typedef VEC(char) dump_stack_t; static void dump_node(spl_ast_t *ast, spl_ast_node_ref_t node_ref, dump_stack_t *stack, bool last); @@ -2527,7 +2533,6 @@ static void dump_node(spl_ast_t *ast, spl_ast_node_ref_t node_ref, dump_stack_t break; case SPL_AST_EXPR_AGGREGATE_LIT: - dump_vec(ast, node->aggregate_literal.fields, stack); break; diff --git a/stage1/spl_ast.h b/stage1/spl_ast.h index 67b8dfd..67be385 100644 --- a/stage1/spl_ast.h +++ b/stage1/spl_ast.h @@ -4,6 +4,7 @@ #include "../stage0/include/utils.h" #include "spl_attr.h" #include "spl_dbg.h" +#include "spl_diag.h" #include "spl_lexer.h" #include "spl_mpa.h" #include "spl_tok.h" @@ -483,11 +484,12 @@ struct spl_ast_node { typedef VEC(spl_ast_node_t) spl_ast_node_vec_t; typedef VEC(char *) spl_ast_cstr_ref_vec_t; typedef struct { - int parsed; spl_tok_vec_t input; spl_ast_node_vec_t node_buckets; spl_ast_cstr_ref_vec_t str_buckets; spl_ast_node_ref_t root; + + spl_diag_t *diag; } spl_ast_t; void spl_ast_init(spl_ast_t *ast, const spl_tok_vec_t *tok_vec /*move*/); @@ -497,7 +499,6 @@ spl_ast_node_t *spl_ast_node(spl_ast_t *ast, spl_ast_node_ref_t node); const char *spl_ast_node_name(spl_ast_node_t *node); void spl_ast_parse(spl_ast_t *ast); -void spl_ast_valid(spl_ast_t *ast); void spl_ast_dump(spl_ast_t *ast, spl_ast_node_ref_t node); #endif /* __SPL_AST_H__ */ diff --git a/stage1/spl_ast2ir.c b/stage1/spl_ast2ir.c index 7c5b2a9..ade2005 100644 --- a/stage1/spl_ast2ir.c +++ b/stage1/spl_ast2ir.c @@ -39,9 +39,8 @@ static spl_ir_node_ref_t ast2ir_emit_cast_builtin(spl_ast2ir_t *a, spl_ast_node_ spl_type_id_t tt, spl_ir_node_ref_t v); static spl_ir_node_ref_t emit_cast(spl_ast2ir_t *a, spl_ast_node_t *n); static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref); -static spl_ir_node_ref_t emit_if_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref); -static spl_ir_node_ref_t emit_implicit_cast(spl_ast2ir_t *a, spl_type_id_t ft, spl_type_id_t tt, - spl_ir_node_ref_t v); +static spl_ir_node_ref_t emit_implicit_cast(spl_ast2ir_t *a, spl_ast_node_t *n, spl_type_id_t ft, + spl_type_id_t tt, spl_ir_node_ref_t v); static spl_ir_node_ref_t ast2ir_intrin_call(spl_ast2ir_t *a, spl_ast_node_t *n, spl_intrin_t in, spl_ast_node_ref_vec_t *args); @@ -111,6 +110,7 @@ static spl_ir_node_ref_t emit_zero_value(spl_ast2ir_t *a, spl_type_id_t tid) { return 0; } } + static void copy_attrs_to_ir_node(spl_ast2ir_t *a, spl_ast_node_t *n, spl_ir_node_ref_t ir_ref) { if (!ir_ref || !n || vec_size(n->attrs) == 0) return; @@ -135,7 +135,8 @@ static spl_ir_node_ref_t ast2ir_intrin_cast(spl_ast2ir_t *a, spl_ast_node_t *n, spl_ast_node_ref_vec_t *args) { usize nargs = vec_size(*args); if (nargs < 1) { - SPL_ERROR(&n->dbg, "cast builtin requires at least 1 argument"); + spl_diag_error(a->diag, SPL_DIAG_KIND_INTRIN_ARG_COUNT, &n->dbg, + "cast builtin requires at least 1 argument"); return 0; } spl_ir_node_ref_t v = emit_expr(a, vec_at(*args, 0)); @@ -149,7 +150,6 @@ static spl_ir_node_ref_t ast2ir_intrin_cast(spl_ast2ir_t *a, spl_ast_node_t *n, spl_ast_node_t *targ = spl_ast_node(a->sema->ast, vec_at(*args, 1)); tt = node_ir(a, targ); } else { - /* 单参数形式:目标类型由 sema 在节点上标好的 resolved 类型给出 */ tt = node_ir(a, n); } if (!ft || !tt) @@ -287,7 +287,6 @@ static spl_ir_node_ref_t emit_lvalue(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { case SPL_AST_EXPR_UNARY: { if (n->unary.op != SPL_UNARY_OP_DEREF) return 0; - /* *p 作为左值,地址就是指针 p 的值 */ return emit_expr(a, n->unary.operand); } case SPL_AST_EXPR_FIELD: { @@ -302,7 +301,7 @@ static spl_ir_node_ref_t emit_lvalue(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { spl_lang_type_id_t obj_elem = (obj_kind == SPL_LANG_TYPE_PTR) ? obj_ln->extra.elem : 0; if (spl_intrin_lookup_field(obj_kind, n->field.field) != SPL_INTRIN_NONE) - return 0; /* 内建字段不是左值 */ + return 0; spl_ir_node_ref_t base = 0; spl_lang_type_id_t agg_lang = 0; @@ -430,7 +429,7 @@ static spl_ir_node_ref_t ast2ir_emit_cast_builtin(spl_ast2ir_t *a, spl_ast_node_ case SPL_INTRIN_PTR_CAST: return spl_ir_builder_cast_bitcast(a->ir, ft, tt, v); default: - SPL_ERROR(&n->dbg, "as: unknown cast builtin"); + spl_diag_error(a->diag, SPL_DIAG_KIND_INTERNAL, &n->dbg, "ast2ir: unknown cast builtin"); return 0; } } @@ -448,7 +447,8 @@ static spl_ir_node_ref_t emit_cast(spl_ast2ir_t *a, spl_ast_node_t *n) { spl_intrin_t in = spl_intrin_lookup_cast(a->sema->type, ft, tt); if (in == SPL_INTRIN_NONE) { - SPL_ERROR(&n->dbg, "as: no conversion between the given types"); + spl_diag_error(a->diag, SPL_DIAG_KIND_CAST_INVALID, &n->dbg, + "as: no conversion between the given types"); return 0; } return ast2ir_emit_cast_builtin(a, n, in, ft, tt, v); @@ -475,7 +475,7 @@ static spl_ir_node_ref_t emit_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { if (!from_ir || !to_ir || from_ir == to_ir) return val; - return emit_implicit_cast(a, from_ir, to_ir, val); + return emit_implicit_cast(a, n, from_ir, to_ir, val); } static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { @@ -485,8 +485,6 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref) switch (n->kind) { case SPL_AST_EXPR_INT_LIT: { - /* 节点经 coerce 后 resolved 可能是具体 int 或 float。 - * 值始终存在 int_lit.bits(补码);按 resolved 决定如何构造 IR 常量。 */ spl_type_id_t it = node_ir(a, n); spl_type_node_t *itn = spl_type_node(a->sema->type, it); if (itn && itn->kind == SPL_TYPE_FLOAT) { @@ -673,7 +671,6 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref) case SPL_OP_CMP_LE: case SPL_OP_CMP_GT: case SPL_OP_CMP_GE: { - /* 比较的操作数类型从左侧子节点读(sema 已 coerce 到共同类型) */ spl_ast_node_t *cmln = spl_ast_node(a->sema->ast, n->binary.left); spl_type_id_t op_tid = cmln ? node_ir(a, cmln) : 0; switch (op) { @@ -719,14 +716,12 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref) if (!fn) return 0; - /* 先求所有参数 */ usize nargs = vec_size(n->call.args); spl_ir_node_ref_vec_t arg_refs; vec_init(arg_refs); for (usize i = 0; i < nargs; ++i) vec_push(arg_refs, emit_expr(a, vec_at(n->call.args, i))); - /* 再创建 call 节点 */ spl_type_id_t ret_t = node_ir(a, n); spl_ir_node_ref_t call = spl_ir_builder_control_call(a->ir, ret_t, fn); if (!call) { @@ -960,13 +955,10 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref) 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); - /* base = 元素数据首地址 */ spl_ir_node_ref_t base = 0; if (obj_kind == SPL_LANG_TYPE_PTR) { - /* ptr 值本身就是首元素地址 */ base = emit_expr(a, n->slice.obj); } else if (obj_kind == SPL_LANG_TYPE_SLICE) { - /* 取 slice 的 ptr 字段 */ spl_ir_node_ref_t slice_val = emit_expr(a, n->slice.obj); if (!slice_val) return 0; @@ -974,7 +966,6 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref) base = spl_ir_builder_agg_extract(a->ir, obj_ir, ptr_ir, SPL_SLICE_PTR_FIELD_IDX, slice_val); } else { - /* ARRAY:&arr 即首元素地址 */ base = emit_lvalue(a, n->slice.obj); } if (!base) @@ -1032,60 +1023,6 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref) } } -static spl_ir_node_ref_t emit_if_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { - spl_ast_node_t *n = spl_ast_node(a->sema->ast, ref); - if (!n || n->kind != SPL_AST_EXPR_IF) - return 0; - - spl_type_id_t if_t = node_ir(a, n); - spl_type_node_t *if_tn = if_t ? spl_type_node(a->sema->type, if_t) : NULL; - /* 只有 when 有非 unit 值时(作为表达式使用),才分配 result_slot */ - bool need_result = if_tn && if_tn->kind != SPL_TYPE_UNIT; - - spl_ir_node_ref_t result_slot = 0; - if (need_result) - result_slot = spl_ir_builder_mem_alloca(a->ir, if_t, const_usize(a, 1)); - - spl_ir_node_ref_t cond = emit_expr(a, n->if_expr.cond); - if (!cond) - Panic("if cond emit failed"); - spl_ir_node_ref_t br = spl_ir_builder_control_br(a->ir, cond); - spl_ir_builder_block_end(a->ir); - - usize then_blk = spl_ir_builder_block_begin(a->ir); - spl_ir_node_ref_t then_v = 0; - if (n->if_expr.then_block) - then_v = emit_expr(a, n->if_expr.then_block); - if (result_slot && then_v) - spl_ir_builder_mem_store(a->ir, if_t, result_slot, then_v); - spl_ir_node_ref_t then_end = 0; - if (!a->ir->terminated) - then_end = spl_ir_builder_control_jmp(a->ir); - spl_ir_builder_block_end(a->ir); - - usize else_blk = spl_ir_builder_block_begin(a->ir); - spl_ir_node_ref_t else_v = 0; - if (n->if_expr.else_branch) - else_v = emit_expr(a, n->if_expr.else_branch); - if (result_slot && else_v) - spl_ir_builder_mem_store(a->ir, if_t, result_slot, else_v); - spl_ir_node_ref_t else_end = 0; - if (!a->ir->terminated) - else_end = spl_ir_builder_control_jmp(a->ir); - spl_ir_builder_block_end(a->ir); - - usize merge_blk = spl_ir_builder_block_begin(a->ir); - spl_ir_builder_control_br_fixup(a->ir, br, then_blk, else_blk); - if (then_end) - spl_ir_builder_control_jmp_fixup(a->ir, then_end, merge_blk); - if (else_end) - spl_ir_builder_control_jmp_fixup(a->ir, else_end, merge_blk); - - if (!result_slot) - return 0; - return spl_ir_builder_mem_load(a->ir, if_t, result_slot); -} - static spl_ir_node_ref_t emit_if_like(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { spl_ast_node_t *n = spl_ast_node(a->sema->ast, ref); if (!n) @@ -1179,8 +1116,6 @@ static spl_ir_node_ref_t emit_loop_like(spl_ast2ir_t *a, spl_ast_node_ref_t ref) pre_jmp = spl_ir_builder_control_jmp(a->ir); spl_ir_builder_block_end(a->ir); - /* while 需要独立 head 块(含 cond + br); - loop 没有头块,body_blk 同时是入口和回跳目标 */ usize head_blk = 0; spl_ir_node_ref_t br = 0; @@ -1198,7 +1133,6 @@ static spl_ir_node_ref_t emit_loop_like(spl_ast2ir_t *a, spl_ast_node_ref_t ref) spl_loop_ctx_t ctx = {0}; ctx.cont_blk = cont_blk; - ctx.brk_blk = 0; ctx.label = NULL; ctx.result_slot = result_slot; ctx.result_tid = result_t; @@ -1272,7 +1206,6 @@ static void emit_break_stmt(spl_ast2ir_t *a, spl_ast_node_t *n) { if (!target) return; - /* 有值 loop:先把 break 值写入 result_slot 再跳转 */ if (n->statement_break.expr && target->result_slot) { spl_ir_node_ref_t bv = emit_expr(a, n->statement_break.expr); if (bv) @@ -1292,12 +1225,10 @@ static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { case SPL_AST_STATEMENT_RET: { spl_type_id_t ret_ir = to_ir_type(a, a->cur_ret_lang); - /* 先求值 ret 表达式,结果保存在 v 中 */ spl_ir_node_ref_t v = 0; if (n->statement_ret.expr) v = emit_expr(a, n->statement_ret.expr); - /* 再执行 defer(LIFO),只清空当前函数注册的 defer */ while (vec_size(a->defer_stack) > a->cur_defer_base) { spl_ast_node_ref_t d = vec_pop(a->defer_stack); emit_stmt(a, d); @@ -1620,8 +1551,8 @@ static void emit_container_body(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { } } -static spl_ir_node_ref_t emit_implicit_cast(spl_ast2ir_t *a, spl_type_id_t ft, spl_type_id_t tt, - spl_ir_node_ref_t v) { +static spl_ir_node_ref_t emit_implicit_cast(spl_ast2ir_t *a, spl_ast_node_t *n, spl_type_id_t ft, + spl_type_id_t tt, spl_ir_node_ref_t v) { if (!ft || !tt || ft == tt) return v; spl_type_node_t *fs = spl_type_node(a->sema->type, ft); @@ -1638,10 +1569,6 @@ static spl_ir_node_ref_t emit_implicit_cast(spl_ast2ir_t *a, spl_type_id_t ft, s return spl_ir_builder_cast_sext(a->ir, ft, tt, v); return spl_ir_builder_cast_zext(a->ir, ft, tt, v); } - if (fs->kind == SPL_TYPE_INT && ts->kind == SPL_TYPE_FLOAT) - return spl_ir_builder_case_int2float(a->ir, ft, tt, v); - if (fs->kind == SPL_TYPE_FLOAT && ts->kind == SPL_TYPE_INT) - return spl_ir_builder_case_float2int(a->ir, ft, tt, v); if (fs->kind == SPL_TYPE_FLOAT && ts->kind == SPL_TYPE_FLOAT) { if (fs->float_type.bits > ts->float_type.bits) return spl_ir_builder_cast_ftrunc(a->ir, ft, tt, v); @@ -1649,11 +1576,20 @@ static spl_ir_node_ref_t emit_implicit_cast(spl_ast2ir_t *a, spl_type_id_t ft, s } if (fs->kind == SPL_TYPE_BOOL && ts->kind == SPL_TYPE_INT) return spl_ir_builder_cast_bool2int(a->ir, ft, tt, v); + + /* 指针之间:IR 层不区分 pointee,值语义相同,直接透传。 + 覆盖 *never -> *T(null 字面量)和 *T -> *any。 */ + if (fs->kind == SPL_TYPE_PTR && ts->kind == SPL_TYPE_PTR) + return v; + if (fs->kind == SPL_TYPE_PTR && ts->kind == SPL_TYPE_INT) return spl_ir_builder_cast_ptr2int(a->ir, ft, tt, v); if (fs->kind == SPL_TYPE_INT && ts->kind == SPL_TYPE_PTR) return spl_ir_builder_cast_int2ptr(a->ir, ft, tt, v); - return spl_ir_builder_cast_bitcast(a->ir, ft, tt, v); + + spl_diag_fatal(a->diag, SPL_DIAG_KIND_IMPLICIT_CAST_FAIL, &n->dbg, + "implicit cast: cannot convert type#%zu -> type#%zu", ft, tt); + return 0; } static usize spl_int_map_hash(usize k) { return MAP_HASH_INT(k); } @@ -1665,9 +1601,10 @@ void spl_ast2ir_init(spl_ast2ir_t *ast2ir, spl_ir_builder_t *ir, const spl_sema_ map_init(ast2ir->def2ir_map, spl_int_map_hash, spl_int_map_cmp); vec_init(ast2ir->loop_stack); vec_init(ast2ir->defer_stack); - ast2ir->err_count = 0; ast2ir->cur_ret_lang = 0; ast2ir->cur_defer_base = 0; + + ast2ir->diag = NULL; } void spl_ast2ir_drop(spl_ast2ir_t *ast2ir) { diff --git a/stage1/spl_ast2ir.h b/stage1/spl_ast2ir.h index a012641..a681cd9 100644 --- a/stage1/spl_ast2ir.h +++ b/stage1/spl_ast2ir.h @@ -1,6 +1,7 @@ #ifndef __SPL_AST2IR_H__ #define __SPL_AST2IR_H__ +#include "spl_diag.h" #include "spl_ir.h" #include "spl_sema.h" @@ -8,7 +9,6 @@ typedef MAP(spl_def_id_t, spl_ir_node_ref_t) spl_def2ir_map_t; typedef struct { usize cont_blk; - usize brk_blk; const char *label; spl_ir_node_ref_vec_t breaks; spl_ir_node_ref_t result_slot; @@ -26,7 +26,8 @@ typedef struct { spl_defer_stack_t defer_stack; spl_lang_type_id_t cur_ret_lang; usize cur_defer_base; - int err_count; + + spl_diag_t *diag; } spl_ast2ir_t; void spl_ast2ir_init(spl_ast2ir_t *ast2ir, spl_ir_builder_t *ir, const spl_sema_t *sema); diff --git a/stage1/spl_diag.c b/stage1/spl_diag.c new file mode 100644 index 0000000..d937792 --- /dev/null +++ b/stage1/spl_diag.c @@ -0,0 +1,368 @@ +#include "spl_diag.h" +#include "../stage0/include/color.h" + +#include + +static const char *const g_kind_names[] = { + [SPL_DIAG_KIND_NONE] = "none", + [SPL_DIAG_KIND_LEX_UNEXPECTED] = "lex_unexpected", + [SPL_DIAG_KIND_PARSE_EXPECTED] = "parse_expected", + [SPL_DIAG_KIND_PARSE_UNRECOGNIZED] = "parse_unrecognized", + [SPL_DIAG_KIND_UNDEFINED_SYMBOL] = "undefined_symbol", + [SPL_DIAG_KIND_DUPLICATE_SYMBOL] = "duplicate_symbol", + [SPL_DIAG_KIND_TYPE_MISMATCH] = "type_mismatch", + [SPL_DIAG_KIND_ARG_COUNT_MISMATCH] = "arg_count_mismatch", + [SPL_DIAG_KIND_NOT_A_FUNCTION] = "not_a_function", + [SPL_DIAG_KIND_NO_FIELD] = "no_field", + [SPL_DIAG_KIND_NO_METHOD] = "no_method", + [SPL_DIAG_KIND_INDEX_BASE_INVALID] = "index_base_invalid", + [SPL_DIAG_KIND_TUPLE_INDEX_OOB] = "tuple_index_oob", + [SPL_DIAG_KIND_FITS_OVERFLOW] = "fits_overflow", + [SPL_DIAG_KIND_CIRCULAR_DEP] = "circular_dep", + [SPL_DIAG_KIND_BREAK_OUTSIDE_LOOP] = "break_outside_loop", + [SPL_DIAG_KIND_CONTINUE_OUTSIDE_LOOP] = "continue_outside_loop", + [SPL_DIAG_KIND_UNDEFINED_LABEL] = "undefined_label", + [SPL_DIAG_KIND_CAST_INVALID] = "cast_invalid", + [SPL_DIAG_KIND_UNKNOWN_ATTR] = "unknown_attr", + [SPL_DIAG_KIND_UNKNOWN_INTRIN] = "unknown_intrin", + [SPL_DIAG_KIND_INTRIN_ARG_COUNT] = "intrin_arg_count", + [SPL_DIAG_KIND_VAR_UNINITIALIZED] = "var_uninitialized", + [SPL_DIAG_KIND_CANNOT_INFER] = "cannot_infer", + [SPL_DIAG_KIND_MUST_RETURN_VALUE] = "must_return_value", + [SPL_DIAG_KIND_UNHANDLED_NODE] = "unhandled_node", + [SPL_DIAG_KIND_IMPLICIT_CAST_FAIL] = "implicit_cast_fail", + [SPL_DIAG_KIND_NO_LVALUE] = "no_lvalue", + [SPL_DIAG_KIND_BAD_FIELD_INDEX] = "bad_field_index", + [SPL_DIAG_KIND_BAD_BLOCK] = "bad_block", + [SPL_DIAG_KIND_IR_UNKNOWN_KIND] = "ir_unknown_kind", + [SPL_DIAG_KIND_FRAME_OVERFLOW] = "frame_overflow", + [SPL_DIAG_KIND_INTERNAL] = "internal", +}; + +const char *spl_diag_kind_name(spl_diag_kind_t k) { + if ((usize)k < sizeof(g_kind_names) / sizeof(g_kind_names[0]) && g_kind_names[k]) + return g_kind_names[k]; + return "unknown"; +} + +static const char *const g_stage_names[] = { + [SPL_STAGE_NONE] = "none", [SPL_STAGE_LEX] = "lex", [SPL_STAGE_PARSE] = "parse", + [SPL_STAGE_SEMA] = "sema", [SPL_STAGE_AST2IR] = "ast2ir", [SPL_STAGE_IR2VM] = "ir2vm", + [SPL_STAGE_DRIVER] = "driver", +}; + +const char *spl_diag_stage_name(spl_diag_stage_t s) { + if ((usize)s < sizeof(g_stage_names) / sizeof(g_stage_names[0]) && g_stage_names[s]) + return g_stage_names[s]; + return "?"; +} + +const char *spl_diag_level_name(spl_diag_level_t l) { + switch (l) { + case SPL_DIAG_LEVEL_NOTE: + return "note"; + case SPL_DIAG_LEVEL_WARN: + return "warn"; + case SPL_DIAG_LEVEL_ERROR: + return "error"; + case SPL_DIAG_LEVEL_FATAL: + return "fatal"; + } + return "?"; +} + +static const char *level_color(spl_diag_level_t l) { + switch (l) { + case SPL_DIAG_LEVEL_NOTE: + return ANSI_FG_CYAN; + case SPL_DIAG_LEVEL_WARN: + return ANSI_FG_YELLOW; + case SPL_DIAG_LEVEL_ERROR: + return ANSI_FG_RED; + case SPL_DIAG_LEVEL_FATAL: + return ANSI_FG_RED ANSI_UNDERLINED; + } + return ANSI_NONE; +} + +static char *diag_strdup(const char *s) { + if (!s) + return NULL; + usize n = strlen(s); + char *r = malloc(n + 1); + if (!r) + return NULL; + memcpy(r, s, n); + r[n] = '\0'; + return r; +} + +void spl_diag_init(spl_diag_t *d, void *fout) { + memset(d, 0, sizeof *d); + vec_init(d->ctx); + vec_init(d->records); + d->collect = true; + d->fout = fout; + d->color = true; + d->stage = SPL_STAGE_NONE; +} + +static void frame_free(spl_diag_frame_t *f) { + free(f->fn_name); + free(f->label); + f->fn_name = NULL; + f->label = NULL; +} + +static void record_free(spl_diag_record_t *r) { + free(r->message); + r->message = NULL; + for (usize i = 0; i < vec_size(r->ctx); ++i) + frame_free(&vec_at(r->ctx, i)); + vec_free(r->ctx); + for (usize i = 0; i < vec_size(r->notes); ++i) + free(vec_at(r->notes, i).message); + vec_free(r->notes); +} + +void spl_diag_reset(spl_diag_t *d) { + for (usize i = 0; i < vec_size(d->ctx); ++i) + frame_free(&vec_at(d->ctx, i)); + d->ctx.size = 0; + + for (usize i = 0; i < vec_size(d->records); ++i) + record_free(&vec_at(d->records, i)); + d->records.size = 0; + + d->num_printed = 0; + d->n_errors = 0; + d->n_warns = 0; + d->n_fatals = 0; +} + +void spl_diag_drop(spl_diag_t *d) { + spl_diag_reset(d); + vec_free(d->ctx); + vec_free(d->records); +} + +void spl_diag_set_stage(spl_diag_t *d, spl_diag_stage_t stage) { d->stage = stage; } + +void spl_diag_set_output(spl_diag_t *d, FILE *out) { d->fout = out; } + +void spl_diag_set_color(spl_diag_t *d, bool enabled) { d->color = enabled; } + +void spl_diag_set_collect(spl_diag_t *d, bool enabled) { d->collect = enabled; } + +void spl_diag_push(spl_diag_t *d, const spl_dbg_node_t *loc, const char *fn_name, + const char *label) { + spl_diag_frame_t f = {0}; + if (loc) + f.loc = *loc; + f.fn_name = fn_name ? diag_strdup(fn_name) : NULL; + f.label = label ? diag_strdup(label) : NULL; + vec_push(d->ctx, f); +} + +void spl_diag_pop(spl_diag_t *d) { + if (vec_size(d->ctx) == 0) + return; + frame_free(&vec_at(d->ctx, vec_size(d->ctx) - 1)); + d->ctx.size--; +} + +usize spl_diag_depth(const spl_diag_t *d) { return vec_size(d->ctx); } + +static spl_diag_frame_vec_t ctx_snapshot(const spl_diag_t *d) { + spl_diag_frame_vec_t snap; + vec_init(snap); + for (usize i = 0; i < vec_size(d->ctx); ++i) { + spl_diag_frame_t *src = &vec_at(d->ctx, i); + spl_diag_frame_t f = {0}; + f.loc = src->loc; + f.fn_name = src->fn_name ? diag_strdup(src->fn_name) : NULL; + f.label = src->label ? diag_strdup(src->label) : NULL; + vec_push(snap, f); + } + return snap; +} + +static void frame_desc(const spl_diag_frame_t *f, char *buf, usize cap) { + if (f->fn_name && f->label) + snprintf(buf, cap, "%s %s", f->label, f->fn_name); + else if (f->fn_name) + snprintf(buf, cap, "%s", f->fn_name); + else if (f->label) + snprintf(buf, cap, "%s", f->label); + else + snprintf(buf, cap, "?"); +} + +static void print_loc(FILE *out, const spl_dbg_node_t *loc) { + if (loc && loc->fname) + fprintf(out, "%s:%d:%d", loc->fname, loc->line, loc->col); + else + fprintf(out, ""); +} + +static void print_record(const spl_diag_t *d, const spl_diag_record_t *r) { + FILE *out = (FILE *)d->fout; + if (!out) + return; + const char *col = d->color ? level_color(r->level) : ""; + const char *rst = d->color ? ANSI_NONE : ""; + + fprintf(out, "%s%s[%s:%s]%s: ", col, spl_diag_level_name(r->level), + spl_diag_stage_name(r->stage), spl_diag_kind_name(r->kind), rst); + print_loc(out, &r->loc); + fputc('\n', out); + + fprintf(out, " %s\n", r->message ? r->message : ""); + + for (usize i = vec_size(r->ctx); i > 0; --i) { + char buf[256]; + frame_desc(&vec_at(r->ctx, i - 1), buf, sizeof buf); + fprintf(out, " in %s at ", buf); + print_loc(out, &vec_at(r->ctx, i - 1).loc); + fputc('\n', out); + } + + for (usize i = 0; i < vec_size(r->notes); ++i) { + spl_diag_note_t *n = &vec_at(r->notes, i); + const char *ncol = d->color ? ANSI_FG_CYAN : ""; + fprintf(out, "%snote%s: ", ncol, rst); + print_loc(out, &n->loc); + fputc('\n', out); + fprintf(out, " %s\n", n->message ? n->message : ""); + } +} + +static void emit(spl_diag_t *d, spl_diag_level_t level, spl_diag_kind_t kind, + const spl_dbg_node_t *loc, const char *fmt, va_list ap) { + va_list ap2; + va_copy(ap2, ap); + int need = vsnprintf(NULL, 0, fmt, ap); + if (need < 0) + need = 0; + + char *msg = malloc((usize)need + 1); + if (msg) + vsnprintf(msg, (usize)need + 1, fmt, ap2); + va_end(ap2); + + spl_diag_record_t rec = {0}; + rec.level = level; + rec.stage = d->stage; + rec.kind = kind; + if (loc) + rec.loc = *loc; + rec.message = msg; + rec.ctx = ctx_snapshot(d); + vec_init(rec.notes); + + if (level == SPL_DIAG_LEVEL_ERROR) + d->n_errors++; + else if (level == SPL_DIAG_LEVEL_FATAL) { + d->n_errors++; + d->n_fatals++; + } else if (level == SPL_DIAG_LEVEL_WARN) + d->n_warns++; + + if (d->fout) { + print_record(d, &rec); + d->num_printed++; + } + + if (d->collect) + vec_push(d->records, rec); + else + record_free(&rec); +} + +void spl_diag_note(spl_diag_t *d, spl_diag_kind_t kind, const spl_dbg_node_t *loc, const char *fmt, + ...) { + va_list ap; + va_start(ap, fmt); + emit(d, SPL_DIAG_LEVEL_NOTE, kind, loc, fmt, ap); + va_end(ap); +} + +void spl_diag_warn(spl_diag_t *d, spl_diag_kind_t kind, const spl_dbg_node_t *loc, const char *fmt, + ...) { + va_list ap; + va_start(ap, fmt); + emit(d, SPL_DIAG_LEVEL_WARN, kind, loc, fmt, ap); + va_end(ap); +} + +void spl_diag_error(spl_diag_t *d, spl_diag_kind_t kind, const spl_dbg_node_t *loc, const char *fmt, + ...) { + va_list ap; + va_start(ap, fmt); + emit(d, SPL_DIAG_LEVEL_ERROR, kind, loc, fmt, ap); + va_end(ap); +} + +void spl_diag_fatal(spl_diag_t *d, spl_diag_kind_t kind, const spl_dbg_node_t *loc, const char *fmt, + ...) { + va_list ap; + va_start(ap, fmt); + emit(d, SPL_DIAG_LEVEL_FATAL, kind, loc, fmt, ap); + va_end(ap); +} + +void spl_diag_attach_note(spl_diag_t *d, const spl_dbg_node_t *loc, const char *fmt, ...) { + if (vec_size(d->records) == 0) + return; + spl_diag_record_t *last = &vec_at(d->records, vec_size(d->records) - 1); + + va_list ap; + va_start(ap, fmt); + int need = vsnprintf(NULL, 0, fmt, ap); + va_end(ap); + if (need < 0) + need = 0; + + char *msg = malloc((usize)need + 1); + if (msg) { + va_start(ap, fmt); + vsnprintf(msg, (usize)need + 1, fmt, ap); + va_end(ap); + } + + spl_diag_note_t n = {0}; + if (loc) + n.loc = *loc; + n.message = msg; + vec_push(last->notes, n); +} + +bool spl_diag_has_error(const spl_diag_t *d) { return d->n_errors > 0; } + +bool spl_diag_has_fatal(const spl_diag_t *d) { return d->n_fatals > 0; } + +usize spl_diag_error_count(const spl_diag_t *d) { return d->n_errors; } + +usize spl_diag_warn_count(const spl_diag_t *d) { return d->n_warns; } + +void spl_diag_summary(const spl_diag_t *d) { + FILE *out = (FILE *)d->fout; + if (!out) + return; + + /* 把还没实时打印过的记录补打一遍。 + collect == false 时 records 是空的,num_printed 可能非零, + 用 records.size 兜底避免越界。 */ + usize printed_limit = d->num_printed; + if (printed_limit > vec_size(d->records)) + printed_limit = vec_size(d->records); + + for (usize i = printed_limit; i < vec_size(d->records); ++i) + print_record(d, &vec_at(d->records, i)); + + /* 计数 */ + const char *ecol = d->color && d->n_errors > 0 ? ANSI_FG_RED : ""; + const char *rst = d->color ? ANSI_NONE : ""; + fprintf(out, "%s%zu error%s, %zu warning%s%s\n", ecol, d->n_errors, d->n_errors == 1 ? "" : "s", + d->n_warns, d->n_warns == 1 ? "" : "s", rst); +} \ No newline at end of file diff --git a/stage1/spl_diag.h b/stage1/spl_diag.h new file mode 100644 index 0000000..d3d7f01 --- /dev/null +++ b/stage1/spl_diag.h @@ -0,0 +1,165 @@ +#ifndef __SPL_DIAG_H__ +#define __SPL_DIAG_H__ + +#include "../stage0/include/utils.h" +#include "spl_dbg.h" + +typedef enum { + SPL_DIAG_LEVEL_NOTE = 0, + SPL_DIAG_LEVEL_WARN, + SPL_DIAG_LEVEL_ERROR, + SPL_DIAG_LEVEL_FATAL, +} spl_diag_level_t; + +typedef enum { + SPL_STAGE_NONE = 0, + SPL_STAGE_LEX, + SPL_STAGE_PARSE, + SPL_STAGE_SEMA, + SPL_STAGE_AST2IR, + SPL_STAGE_IR2VM, + SPL_STAGE_DRIVER, +} spl_diag_stage_t; + +/* kind 枚举:边写边补。新增时放对应分组末尾即可。 */ +typedef enum { + SPL_DIAG_KIND_NONE = 0, + + /* 词法 / 语法 */ + SPL_DIAG_KIND_LEX_UNEXPECTED, + SPL_DIAG_KIND_PARSE_EXPECTED, + SPL_DIAG_KIND_PARSE_UNRECOGNIZED, + + /* sema */ + SPL_DIAG_KIND_UNDEFINED_SYMBOL, + SPL_DIAG_KIND_DUPLICATE_SYMBOL, + SPL_DIAG_KIND_TYPE_MISMATCH, + SPL_DIAG_KIND_ARG_COUNT_MISMATCH, + SPL_DIAG_KIND_NOT_A_FUNCTION, + SPL_DIAG_KIND_NO_FIELD, + SPL_DIAG_KIND_NO_METHOD, + SPL_DIAG_KIND_INDEX_BASE_INVALID, + SPL_DIAG_KIND_TUPLE_INDEX_OOB, + SPL_DIAG_KIND_FITS_OVERFLOW, + SPL_DIAG_KIND_CIRCULAR_DEP, + SPL_DIAG_KIND_BREAK_OUTSIDE_LOOP, + SPL_DIAG_KIND_CONTINUE_OUTSIDE_LOOP, + SPL_DIAG_KIND_UNDEFINED_LABEL, + SPL_DIAG_KIND_CAST_INVALID, + SPL_DIAG_KIND_UNKNOWN_ATTR, + SPL_DIAG_KIND_UNKNOWN_INTRIN, + SPL_DIAG_KIND_INTRIN_ARG_COUNT, + SPL_DIAG_KIND_VAR_UNINITIALIZED, + SPL_DIAG_KIND_CANNOT_INFER, + SPL_DIAG_KIND_MUST_RETURN_VALUE, + + /* ast2ir */ + SPL_DIAG_KIND_UNHANDLED_NODE, + SPL_DIAG_KIND_IMPLICIT_CAST_FAIL, + SPL_DIAG_KIND_NO_LVALUE, + SPL_DIAG_KIND_BAD_FIELD_INDEX, + SPL_DIAG_KIND_BAD_BLOCK, + + /* ir2vm */ + SPL_DIAG_KIND_IR_UNKNOWN_KIND, + SPL_DIAG_KIND_FRAME_OVERFLOW, + + /* 通用 */ + SPL_DIAG_KIND_INTERNAL, +} spl_diag_kind_t; + +typedef struct { + spl_dbg_node_t loc; + char *fn_name; + char *label; +} spl_diag_frame_t; +typedef VEC(spl_diag_frame_t) spl_diag_frame_vec_t; + +typedef struct { + spl_dbg_node_t loc; + char *message; +} spl_diag_note_t; +typedef VEC(spl_diag_note_t) spl_diag_note_vec_t; + +typedef struct { + spl_diag_level_t level; + spl_diag_stage_t stage; + spl_diag_kind_t kind; + spl_dbg_node_t loc; + char *message; + spl_diag_frame_vec_t ctx; + spl_diag_note_vec_t notes; +} spl_diag_record_t; +typedef VEC(spl_diag_record_t) spl_diag_record_vec_t; + +typedef struct spl_diag { + spl_diag_frame_vec_t ctx; + spl_diag_record_vec_t records; + usize num_printed; + bool collect; + usize n_errors; + usize n_warns; + usize n_fatals; + spl_diag_stage_t stage; + void *fout; + bool color; +} spl_diag_t; + +void spl_diag_init(spl_diag_t *d, void *fout); +void spl_diag_drop(spl_diag_t *d); +void spl_diag_reset(spl_diag_t *d); +void spl_diag_set_stage(spl_diag_t *d, spl_diag_stage_t stage); +void spl_diag_set_output(spl_diag_t *d, FILE *out); +void spl_diag_set_color(spl_diag_t *d, bool enabled); +void spl_diag_set_collect(spl_diag_t *d, bool enabled); + +void spl_diag_push(spl_diag_t *d, const spl_dbg_node_t *loc, const char *fn_name, + const char *label); +void spl_diag_pop(spl_diag_t *d); +usize spl_diag_depth(const spl_diag_t *d); + +/* ============================================================ + * 发射 + * + * 每个级别都生成独立的 spl_diag_record_t: + * - 计入 records(collect=true 时) + * - error/fatal 计入 n_errors,warn 计入 n_warns + * - 立刻输出到 out(如果非 NULL) + * + * 四种级别的语义区别: + * note —— 一般信息;不阻塞;用在前序诊断之外的独立说明 + * warn —— 警告;不阻塞;driver 可忽略 + * error —— 用户代码错误;调用者应 return 0 + * fatal —— 用户代码错误到数据结构已损坏;调用者必须 return 0 + * ============================================================ */ +void spl_diag_note(spl_diag_t *d, spl_diag_kind_t kind, const spl_dbg_node_t *loc, const char *fmt, + ...); +void spl_diag_warn(spl_diag_t *d, spl_diag_kind_t kind, const spl_dbg_node_t *loc, const char *fmt, + ...); +void spl_diag_error(spl_diag_t *d, spl_diag_kind_t kind, const spl_dbg_node_t *loc, const char *fmt, + ...); +void spl_diag_fatal(spl_diag_t *d, spl_diag_kind_t kind, const spl_dbg_node_t *loc, const char *fmt, + ...); + +/* 挂到最近一条记录(records 末尾)的 notes 列表下。 + * 不生成独立记录、不计入计数,输出时显示为: + * note: + * + * 使用场景:辅助说明前一条诊断,例如 + * spl_diag_error(d, DUPLICATE_SYMBOL, &n->dbg, "duplicate symbol `foo`"); + * spl_diag_attach_note(d, &prev->dbg, "previously defined here"); + * 约束:只在 records 非空时生效;否则静默丢弃,不报错。 */ +void spl_diag_attach_note(spl_diag_t *d, const spl_dbg_node_t *loc, const char *fmt, ...); + +bool spl_diag_has_error(const spl_diag_t *d); +bool spl_diag_has_fatal(const spl_diag_t *d); +usize spl_diag_error_count(const spl_diag_t *d); +usize spl_diag_warn_count(const spl_diag_t *d); + +void spl_diag_summary(const spl_diag_t *d); + +const char *spl_diag_kind_name(spl_diag_kind_t k); +const char *spl_diag_stage_name(spl_diag_stage_t s); +const char *spl_diag_level_name(spl_diag_level_t l); + +#endif /* __SPL_DIAG_H__ */ \ No newline at end of file diff --git a/stage1/spl_ir2vm.c b/stage1/spl_ir2vm.c index f7b2c8b..bd383ea 100644 --- a/stage1/spl_ir2vm.c +++ b/stage1/spl_ir2vm.c @@ -52,6 +52,23 @@ static bool ir_is_aggregate(spl_ir2vm_t *ctx, spl_type_id_t tid) { tn->kind == SPL_TYPE_UNION || tn->kind == SPL_TYPE_ENUM || tn->kind == SPL_TYPE_SHAPE; } +/* 从 fn_tid 取返回类型;非 fn 类型返回 0。 + 集中处理 fn 类型查表,避免调用点各自 spl_type_node + kind 检查。 */ +static spl_type_id_t fn_ret_type(spl_ir2vm_t *ctx, spl_type_id_t fn_tid) { + spl_type_node_t *ftn = spl_type_node(ctx->type, fn_tid); + if (!ftn || ftn->kind != SPL_TYPE_FN) + return 0; + return ftn->fn_type.ret; +} + +/* 从 fn_tid 取参数个数;非 fn 类型返回 0 */ +static usize fn_nargs(spl_ir2vm_t *ctx, spl_type_id_t fn_tid) { + spl_type_node_t *ftn = spl_type_node(ctx->type, fn_tid); + if (!ftn || ftn->kind != SPL_TYPE_FN) + return 0; + return vec_size(ftn->fn_type.params); +} + static spl_type_id_t ir_agg_field_tid(spl_ir2vm_t *ctx, spl_type_id_t tid, usize idx) { spl_type_node_t *tn = spl_type_node(ctx->type, tid); if (!tn) @@ -304,11 +321,9 @@ static void frame_build(frame_layout_t *fl, spl_ir2vm_t *ctx, spl_ir_func_ref_t for (usize i = 0; i < n; ++i) vec_push(fl->slots, (slot_t){0}); - spl_type_node_t *ftn = spl_type_node(ctx->type, f->fn_tid); - usize nargs = (ftn && ftn->kind == SPL_TYPE_FN) ? vec_size(ftn->fn_type.params) : 0; - spl_type_id_t ret_t = (ftn && ftn->kind == SPL_TYPE_FN) ? ftn->fn_type.ret : 0; /* 聚合返回时 fp+0 是 caller 传入的 sret 指针,占用一个隐藏参数槽 */ - usize hidden_sret = ir_is_aggregate(ctx, ret_t) ? 1 : 0; + usize nargs = fn_nargs(ctx, f->fn_tid); + usize hidden_sret = ir_is_aggregate(ctx, fn_ret_type(ctx, f->fn_tid)) ? 1 : 0; fl->args_bytes = (nargs + hidden_sret) * sizeof(spl_vm_val_t); usize off = fl->args_bytes; @@ -747,9 +762,7 @@ static void cg_control(cgen_t *cg, usize ref, const spl_ir_node_t *n) { idx = (usize)idx_node->type_const.int_lit; } /* 聚合返回时 fp+0 是 sret 指针,实参从 fp+8 起 */ - spl_type_node_t *ftn = spl_type_node(ctx->type, cg->irf->fn_tid); - spl_type_id_t cur_ret = (ftn && ftn->kind == SPL_TYPE_FN) ? ftn->fn_type.ret : 0; - usize shift = ir_is_aggregate(ctx, cur_ret) ? 1 : 0; + usize shift = ir_is_aggregate(ctx, fn_ret_type(ctx, cg->irf->fn_tid)) ? 1 : 0; CG_LADDR(cg, (idx + shift) * sizeof(spl_vm_val_t)); CG_LOAD(cg, k); cg_store_slot(cg, ref, k); @@ -1074,8 +1087,7 @@ static usize translate_function(spl_ir2vm_t *ctx, spl_ir_func_ref_t fid, fix_vec spl_vm_func_t entry = {0}; entry.name = strdup(irf->name ? irf->name : ""); entry.idx_of_strtab = 0; - spl_type_node_t *ftn = spl_type_node(ctx->type, irf->fn_tid); - entry.nargs = (ftn && ftn->kind == SPL_TYPE_FN) ? vec_size(ftn->fn_type.params) : 0; + entry.nargs = fn_nargs(ctx, irf->fn_tid); entry.ninsns = 0; entry.address = func_ip; vec_push(ctx->prog.funcs, entry); @@ -1121,6 +1133,8 @@ void spl_ir2vm_init(spl_ir2vm_t *ctx, const spl_ir_t *ir, const spl_type_t *type ctx->attr = attr; map_init(ctx->extern_native, spl_map_hash, spl_map_cmp); spl_prog_init(&ctx->prog); + + ctx->diag = NULL; } void spl_ir2vm_drop(spl_ir2vm_t *ctx) { diff --git a/stage1/spl_ir2vm.h b/stage1/spl_ir2vm.h index a3b21dc..4f043e0 100644 --- a/stage1/spl_ir2vm.h +++ b/stage1/spl_ir2vm.h @@ -1,6 +1,7 @@ #ifndef __SPL_IR2VM_H__ #define __SPL_IR2VM_H__ +#include "spl_diag.h" #include "spl_ir.h" #include "spl_type.h" @@ -13,7 +14,7 @@ typedef struct { typedef VEC(spl_ir2vm_fdbg_t) spl_ir2vm_fdbg_vec_t; typedef MAP(spl_ir_func_ref_t, isize) spl_extern_idx_map_t; -// MAP() + typedef struct { const spl_ir_t *ir; const spl_type_t *type; @@ -21,7 +22,7 @@ typedef struct { spl_extern_idx_map_t extern_native; spl_prog_t prog; - // spl_ir2vm_fdbg_vec_t fdbg; /* ir2vm_run 后填充;splc0 -g 读取生成 debug 段 */ + spl_diag_t *diag; } spl_ir2vm_t; void spl_ir2vm_init(spl_ir2vm_t *ctx, const spl_ir_t *ir, const spl_type_t *type, diff --git a/stage1/spl_sema.c b/stage1/spl_sema.c index 19edd8c..c6a546a 100644 --- a/stage1/spl_sema.c +++ b/stage1/spl_sema.c @@ -27,16 +27,11 @@ spl_scope_id_t spl_scope_alloc(spl_scope_t *scope) { } bool spl_scope_insert(spl_scope_t *scope, spl_scope_id_t id, spl_symbol_t symbol) { - if (!id || id >= vec_size(scope->scopes)) { - LOG_FATAL("sema scope insert error"); - return false; - } + Assert(id != 0 && id < vec_size(scope->scopes)); spl_scope_node_t *node = &vec_at(scope->scopes, id); spl_symbol_t old = {0}; - if (map_get(node->symbols, symbol.name, &old)) { - SPL_ERROR(&(spl_dbg_node_t){0}, "duplicate symbol `%s`", symbol.name); + if (map_get(node->symbols, symbol.name, &old)) return false; - } map_put(node->symbols, symbol.name, symbol); return true; } @@ -46,9 +41,8 @@ bool spl_scope_find(spl_scope_t *scope, const char *name, spl_symbol_t *out) { return false; for (spl_scope_id_t id = scope->current_scope; id != 0; id = vec_at(scope->scopes, id).parent) { spl_scope_node_t *s = &vec_at(scope->scopes, id); - if (map_get(s->symbols, name, out)) { + if (map_get(s->symbols, name, out)) return true; - } } return false; } @@ -83,16 +77,16 @@ static void sema_resolve_attrs(spl_sema_t *sema, spl_ast_node_ref_vec_t *raw, spl_attr_info_t *info = spl_attr_lookup(sema->attr, NULL, a->tag_item.name); if (!info) { - SPL_ERROR(&a->dbg, "unknown attribute `%s`", a->tag_item.name); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_UNKNOWN_ATTR, &a->dbg, + "unknown attribute `%s`", a->tag_item.name); continue; } usize nargs = vec_size(a->tag_item.args); if ((int)nargs < info->min_args || (info->max_args >= 0 && (int)nargs > info->max_args)) { - SPL_ERROR(&a->dbg, "attribute `%s` expects %d..%d args, got %zu", info->name, - info->min_args, info->max_args, nargs); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_UNKNOWN_ATTR, &a->dbg, + "attribute `%s` expects %d..%d args, got %zu", info->name, + info->min_args, info->max_args, nargs); continue; } @@ -120,8 +114,8 @@ static void sema_resolve_attrs(spl_sema_t *sema, spl_ast_node_ref_vec_t *raw, oa.value.i = arg->int_lit.bits; break; default: - SPL_ERROR(&a->dbg, "attribute arg #%zu has unsupported form", j); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_UNKNOWN_ATTR, &a->dbg, + "attribute arg #%zu has unsupported form", j); bad = 1; break; } @@ -162,21 +156,6 @@ static spl_lang_type_id_t sema_lang_from_ir(spl_sema_t *sema, spl_type_id_t ir) return 0; } -static bool sema_is_literal(spl_ast_node_t *n) { - switch (n->kind) { - case SPL_AST_EXPR_INT_LIT: - case SPL_AST_EXPR_FLOAT_LIT: - case SPL_AST_EXPR_CHAR_LIT: - case SPL_AST_EXPR_STRING_LIT: - case SPL_AST_EXPR_BOOL_LIT: - case SPL_AST_EXPR_NULL_LIT: - case SPL_AST_EXPR_UNDEFINED_LIT: - return true; - default: - return false; - } -} - static void sema_type_to_str(spl_sema_t *sema, spl_lang_type_id_t tid, char *buf, usize cap) { if (!buf || cap == 0) return; @@ -255,17 +234,14 @@ static void sema_type_to_str(spl_sema_t *sema, spl_lang_type_id_t tid, char *buf 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; sema->scope->current_scope = new_scope; } static inline void sema_pop_scope(spl_sema_t *sema) { spl_scope_id_t cur = sema->scope->current_scope; - if (cur != 0 && cur < vec_size(sema->scope->scopes)) { - sema->scope->current_scope = vec_at(sema->scope->scopes, cur).parent; - } else { - sema->scope->current_scope = sema->store_scope; - } + if (cur == 0 || cur >= vec_size(sema->scope->scopes)) + Panic("sema_pop_scope: bad current_scope %zu", cur); + sema->scope->current_scope = vec_at(sema->scope->scopes, cur).parent; } static spl_lang_type_id_t sema_for_elem_type(spl_sema_t *sema, spl_lang_type_id_t lang_tid) { @@ -394,8 +370,8 @@ static spl_lang_type_id_t sema_eval_decl(spl_sema_t *sema, spl_def_id_t def_id) } if (def->state == SPL_DECL_RESOLVING) { - SPL_ERROR(&def->dbg_node, "circular dependency on `%s`", def->name ? def->name : "?"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_CIRCULAR_DEP, &def->dbg_node, + "circular dependency on `%s`", def->name ? def->name : "?"); def->state = SPL_DECL_ERROR; return 0; } @@ -457,13 +433,11 @@ static void sema_collect_names(spl_sema_t *sema, spl_ast_node_ref_t ref) { switch (n->kind) { case SPL_AST_CONTAINER_MEMBERS: { - /* root_scope 只在第一次创建,后续 module 复用 */ if (sema->scope->root_scope == 0) { spl_scope_id_t root = spl_scope_alloc(sema->scope); sema->scope->root_scope = root; } - /* 进入 root_scope,再为当前 module 开一个子 scope */ sema->scope->current_scope = sema->scope->root_scope; spl_scope_id_t mod_scope = spl_scope_alloc(sema->scope); sema->scope->current_scope = mod_scope; @@ -476,18 +450,14 @@ static void sema_collect_names(spl_sema_t *sema, spl_ast_node_ref_t ref) { for (usize i = 0; i < vec_size(n->container_members.declarations); ++i) { sema_collect_names(sema, vec_at(n->container_members.declarations, i)); } - - /* 故意不恢复 current_scope - 保持 mod_scope 交给随后的 sema_parse 使用。 - 恢复由 spl_sema_run_module 统一负责 */ break; } case SPL_AST_TYPE_DECL: { spl_symbol_t sym = {.name = n->type_decl.name, .kind = SPL_SYMBOL_KIND_TYPE}; spl_ast_node_t *te = spl_ast_node(sema->ast, n->type_decl.type_expr); if (!te) { - SPL_ERROR(&n->dbg, "type declaration `%s` missing type expression", n->type_decl.name); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, + "type declaration `%s` missing type expression", n->type_decl.name); return; } if (te->kind == SPL_AST_TYPE_AGGREGATE) @@ -495,14 +465,20 @@ static void sema_collect_names(spl_sema_t *sema, spl_ast_node_ref_t ref) { else sym.node = spl_def_alloc(sema->type, SPL_DEF_SCALAR, sym.name, te->dbg, ref); n->resolved_def_id = sym.node; - spl_scope_insert(sema->scope, sema->scope->current_scope, sym); + if (!spl_scope_insert(sema->scope, sema->scope->current_scope, sym)) { + spl_diag_error(sema->diag, SPL_DIAG_KIND_DUPLICATE_SYMBOL, &n->dbg, + "duplicate symbol `%s`", sym.name); + } break; } case SPL_AST_FN_DECL: { spl_symbol_t sym = {.name = n->fn_decl.name, .kind = SPL_SYMBOL_KIND_FN}; sym.node = spl_def_alloc(sema->type, SPL_DEF_FN, sym.name, n->dbg, ref); n->resolved_def_id = sym.node; - spl_scope_insert(sema->scope, sema->scope->current_scope, sym); + if (!spl_scope_insert(sema->scope, sema->scope->current_scope, sym)) { + spl_diag_error(sema->diag, SPL_DIAG_KIND_DUPLICATE_SYMBOL, &n->dbg, + "duplicate symbol `%s`", sym.name); + } break; } case SPL_AST_VAR_DECL: @@ -513,17 +489,19 @@ static void sema_collect_names(spl_sema_t *sema, spl_ast_node_ref_t ref) { spl_symbol_t sym = {.name = name, .kind = SPL_SYMBOL_KIND_VAR}; sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, name, n->dbg, ref); n->resolved_def_id = sym.node; - spl_scope_insert(sema->scope, sema->scope->current_scope, sym); + if (!spl_scope_insert(sema->scope, sema->scope->current_scope, sym)) { + spl_diag_error(sema->diag, SPL_DIAG_KIND_DUPLICATE_SYMBOL, &n->dbg, + "duplicate symbol `%s`", name); + } } else { - SPL_ERROR(&n->dbg, "unsupported variable pattern (only simple identifier)"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, + "unsupported variable pattern (only simple identifier)"); } break; } case SPL_AST_TOP_LEVEL_BLOCK: - if (n->top_level_block.block) { + if (n->top_level_block.block) sema_collect_names(sema, n->top_level_block.block); - } break; default: break; @@ -572,9 +550,9 @@ static spl_lang_type_id_t sema_intrin_call(spl_sema_t *sema, spl_ast_node_t *n, const spl_intrin_info_t *info = spl_intrin_info(in); usize nargs = vec_size(*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++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_INTRIN_ARG_COUNT, &n->dbg, + "`%s` expects %d..%d args, got %zu", info->name, info->min_args, + info->max_args, nargs); return 0; } @@ -599,7 +577,6 @@ static spl_lang_type_id_t sema_intrin_call(spl_sema_t *sema, spl_ast_node_t *n, case SPL_INTRIN_FLOAT_FROM_INT: case SPL_INTRIN_PTR_FROM_INT: case SPL_INTRIN_PTR_CAST: { - /* 双参数形式:源表达式 + 目标类型 */ spl_lang_type_id_t src_lang = sema_infer(sema, vec_at(*args, 0)); if (!src_lang) return 0; @@ -610,17 +587,15 @@ static spl_lang_type_id_t sema_intrin_call(spl_sema_t *sema, spl_ast_node_t *n, spl_type_id_t tt = spl_lang_type_get_ir_type(sema->type, dst_lang); spl_intrin_t expected = spl_intrin_lookup_cast(sema->type, ft, tt); if (expected == SPL_INTRIN_NONE) { - SPL_ERROR(&n->dbg, "`%s`: incompatible types", info->name); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_CAST_INVALID, &n->dbg, + "`%s`: incompatible types", info->name); return 0; } - /* 允许显式 builtin 覆盖 as 的默认选择(例如用 @int_cast 代替 @truncate) */ n->resolved_lang_tid = dst_lang; return dst_lang; } case SPL_INTRIN_INT_FROM_BOOL: case SPL_INTRIN_INT_FROM_PTR: { - /* 单参数:目标类型默认 usize;双参数时以第二参数为准 */ sema_infer(sema, vec_at(*args, 0)); if (nargs >= 2) { spl_lang_type_id_t dst = sema_infer(sema, vec_at(*args, 1)); @@ -655,6 +630,34 @@ static spl_lang_type_id_t sema_intrin_field(spl_sema_t *sema, spl_ast_node_t *n, return 0; } +static spl_lang_type_id_t sema_block_body(spl_sema_t *sema, spl_ast_node_t *n, + spl_lang_type_id_t expected) { + spl_ast_node_ref_t tail = n->block.tail_expr; + + sema_push_scope(sema); + for (usize i = 0; i < vec_size(n->block.stmts); ++i) + sema_infer(sema, vec_at(n->block.stmts, i)); + + spl_lang_type_id_t r = 0; + if (tail) { + if (expected) { + r = sema_coerce(sema, tail, expected); + if (!r) { + sema_pop_scope(sema); + return 0; + } + } else { + r = sema_infer(sema, tail); + } + } else { + r = spl_lang_make_unit(sema->type); + } + sema_pop_scope(sema); + + n->resolved_lang_tid = r; + return r; +} + static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_lang_type_id_t expected) { if (!ref || !expected) @@ -671,13 +674,11 @@ static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref, if (already != 0) { spl_lang_type_node_t *an = spl_lang_type_node(sema->type, already); spl_type_node_t *air = an ? spl_type_node(sema->type, an->ir_type_id) : NULL; - /* comptime 与 infer 都属于"可重定型":清空 resolved 后按 expected 重新推导 */ bool a_rebindable = (an && an->kind == SPL_LANG_TYPE_INFER) || (an && an->kind == SPL_LANG_TYPE_INT && air && air->int_type.bits == 0) || (an && an->kind == SPL_LANG_TYPE_FLOAT && air && air->float_type.bits == 0); if (!a_rebindable) { - /* 具体类型:只接受子类型方向 */ if (spl_lang_type_is_subtype(sema->type, already, expected)) { n->expected_lang_tid = expected; return expected; @@ -685,12 +686,11 @@ static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref, char ebuf[128], gbuf[128]; sema_type_to_str(sema, expected, ebuf, sizeof(ebuf)); sema_type_to_str(sema, already, gbuf, sizeof(gbuf)); - SPL_ERROR(&n->dbg, "type mismatch: node kind=%d already typed as %s, expected %s", - (int)n->kind, gbuf, ebuf); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, + "type mismatch: node kind=%d already typed as %s, expected %s", + (int)n->kind, gbuf, ebuf); return 0; } - /* 清空 resolved,走未定型路径,让递归按 expected 下推子节点 */ n->resolved_lang_tid = 0; } @@ -698,9 +698,6 @@ static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref, switch (n->kind) { case SPL_AST_EXPR_UNARY: { - /* ADDRESS / DEREF 的结果类型由操作数决定,不能用 expected 反向定型。 - * 但不能直接 return ——— 那会绕过 expected 兼容性检查。 - * 走 break 落到兜底:infer 后做 is_subtype / comptime 判定。 */ if (n->unary.op == SPL_UNARY_OP_ADDRESS || n->unary.op == SPL_UNARY_OP_DEREF) break; if (!sema_coerce(sema, n->unary.operand, expected)) @@ -743,8 +740,8 @@ static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref, char lbuf[128], rbuf[128]; sema_type_to_str(sema, lt, lbuf, sizeof(lbuf)); sema_type_to_str(sema, rt, rbuf, sizeof(rbuf)); - SPL_ERROR(&n->dbg, "comparison operands type mismatch: lhs=%s rhs=%s", lbuf, rbuf); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, + "comparison operands type mismatch: lhs=%s rhs=%s", lbuf, rbuf); return 0; } sema_coerce(sema, n->binary.left, common); @@ -754,8 +751,6 @@ static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref, return b; } - /* ptr +/- int:expected 是 ptr 且左侧推断为 ptr。 - * 右侧保留原整型;仅 comptime_int(bits==0)收紧到 isize。 */ if (op == SPL_OP_ADD || op == SPL_OP_SUB) { spl_lang_type_node_t *en = spl_lang_type_node(sema->type, expected); if (en && en->kind == SPL_LANG_TYPE_PTR) { @@ -765,8 +760,8 @@ static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_lang_type_id_t rt = sema_infer(sema, n->binary.right); spl_lang_type_node_t *rn = spl_lang_type_node(sema->type, rt); if (!rn || rn->kind != SPL_LANG_TYPE_INT) { - SPL_ERROR(&n->dbg, "pointer offset must be integer"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, + "pointer offset must be integer"); return 0; } spl_type_node_t *rn_ir = spl_type_node(sema->type, rn->ir_type_id); @@ -809,8 +804,8 @@ static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref, usize nelems = vec_size(n->tuple.elems); usize ntypes = vec_size(en->extra.elems); if (nelems != ntypes) { - SPL_ERROR(&n->dbg, "tuple arity mismatch (expected %zu, got %zu)", ntypes, nelems); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, + "tuple arity mismatch (expected %zu, got %zu)", ntypes, nelems); return 0; } for (usize i = 0; i < nelems; ++i) { @@ -830,19 +825,18 @@ static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref, en->kind != SPL_LANG_TYPE_ENUM)) break; - /* 有名字时,名字必须与 expected 指向同一类型 */ if (n->aggregate_literal.name) { spl_symbol_t sym; if (!spl_scope_find(sema->scope, n->aggregate_literal.name, &sym)) { - SPL_ERROR(&n->dbg, "unknown type `%s`", n->aggregate_literal.name); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_UNDEFINED_SYMBOL, &n->dbg, + "unknown type `%s`", n->aggregate_literal.name); return 0; } spl_def_node_t *def = spl_def_node(sema->type, sym.node); if (!def || def->lang_id != expected) { - SPL_ERROR(&n->dbg, "aggregate `%s` does not match expected type", - n->aggregate_literal.name); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, + "aggregate `%s` does not match expected type", + n->aggregate_literal.name); return 0; } } @@ -850,27 +844,27 @@ static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_type_id_t agg_ir = spl_lang_type_get_ir_type(sema->type, expected); spl_type_node_t *irn = spl_type_node(sema->type, agg_ir); if (!irn) { - SPL_ERROR(&n->dbg, "aggregate type unresolved"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, + "aggregate type unresolved"); return 0; } if (en->kind == SPL_LANG_TYPE_ENUM) { if (vec_size(n->aggregate_literal.fields) != 1) { - SPL_ERROR(&n->dbg, "enum literal must have exactly one variant"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, + "enum literal must have exactly one variant"); return 0; } spl_ast_node_t *item = spl_ast_node(sema->ast, vec_at(n->aggregate_literal.fields, 0)); if (!item || item->kind != SPL_AST_STRUCT_INIT_ITEM) { - SPL_ERROR(&n->dbg, "invalid enum literal"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, + "invalid enum literal"); return 0; } usize idx = 0; if (!spl_type_agg_member_idx(sema->type, agg_ir, item->struct_init_item.name, &idx)) { - SPL_ERROR(&item->dbg, "no variant `%s`", item->struct_init_item.name); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_NO_FIELD, &item->dbg, "no variant `%s`", + item->struct_init_item.name); return 0; } usize field_tid_ir = vec_at(irn->agg_type.variants, idx).type_id; @@ -889,8 +883,8 @@ static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref, continue; usize idx = 0; if (!spl_type_agg_member_idx(sema->type, agg_ir, item->struct_init_item.name, &idx)) { - SPL_ERROR(&item->dbg, "no field `%s`", item->struct_init_item.name); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_NO_FIELD, &item->dbg, "no field `%s`", + item->struct_init_item.name); continue; } usize field_tid_ir = vec_at(irn->agg_type.variants, idx).type_id; @@ -924,25 +918,8 @@ static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref, return expected; } - case SPL_AST_EXPR_BLOCK: { - sema_push_scope(sema); - for (usize i = 0; i < vec_size(n->block.stmts); ++i) - sema_infer(sema, vec_at(n->block.stmts, i)); - spl_lang_type_id_t r = 0; - if (n->block.tail_expr) { - spl_lang_type_id_t t = sema_coerce(sema, n->block.tail_expr, expected); - if (!t) { - sema_pop_scope(sema); - return 0; - } - r = t; - } else { - r = spl_lang_make_unit(sema->type); - } - sema_pop_scope(sema); - n->resolved_lang_tid = r; - return r; - } + case SPL_AST_EXPR_BLOCK: + return sema_block_body(sema, n, expected); default: break; @@ -968,8 +945,8 @@ static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref, uint32_t bits = to_ir ? (uint32_t)to_ir->int_type.bits : 0; if (n->kind == SPL_AST_EXPR_INT_LIT && bits != 0 && !spl_lang_mpa_int_fits(sema->type, expected, n->int_lit)) { - SPL_ERROR(&n->dbg, "comptime value does not fit target type"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_FITS_OVERFLOW, &n->dbg, + "comptime value does not fit target type"); return 0; } n->resolved_lang_tid = expected; @@ -988,8 +965,8 @@ static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref, char ebuf[128], gbuf[128]; sema_type_to_str(sema, expected, ebuf, sizeof(ebuf)); sema_type_to_str(sema, from, gbuf, sizeof(gbuf)); - SPL_ERROR(&n->dbg, "type mismatch: expect %s, got %s (node kind=%d)", ebuf, gbuf, (int)n->kind); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, + "type mismatch: expect %s, got %s (node kind=%d)", ebuf, gbuf, (int)n->kind); return 0; } @@ -1045,18 +1022,18 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { return t; } - /* ---------- IDENT:同时写 def_id 和 lang_tid 副本 ---------- */ + /* ---------- IDENT ---------- */ case SPL_AST_EXPR_IDENT: { const char *name = n->ident.name; spl_symbol_t sym; if (!spl_scope_find(sema->scope, name, &sym)) { - SPL_ERROR(&n->dbg, "undefined identifier `%s`", name); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_UNDEFINED_SYMBOL, &n->dbg, + "undefined identifier `%s`", name); return 0; } if (sym.node == 0) { - SPL_ERROR(&n->dbg, "identifier `%s` has no definition", name); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_UNDEFINED_SYMBOL, &n->dbg, + "identifier `%s` has no definition", name); return 0; } n->resolved_def_id = sym.node; @@ -1077,16 +1054,16 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { switch (n->unary.op) { case SPL_UNARY_OP_MINUS: if (tn->kind != SPL_LANG_TYPE_INT && tn->kind != SPL_LANG_TYPE_FLOAT) { - SPL_ERROR(&n->dbg, "unary minus requires numeric operand"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, + "unary minus requires numeric operand"); return 0; } n->resolved_lang_tid = op; return op; case SPL_UNARY_OP_BIT_NOT: if (tn->kind != SPL_LANG_TYPE_INT) { - SPL_ERROR(&n->dbg, "bitwise not requires integer operand"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, + "bitwise not requires integer operand"); return 0; } n->resolved_lang_tid = op; @@ -1104,8 +1081,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { } case SPL_UNARY_OP_DEREF: { if (tn->kind != SPL_LANG_TYPE_PTR) { - SPL_ERROR(&n->dbg, "deref requires pointer operand"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, + "deref requires pointer operand"); return 0; } spl_lang_type_id_t elem = tn->extra.elem; @@ -1121,7 +1098,6 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { case SPL_AST_EXPR_BINARY: { spl_binary_op_t op = n->binary.op; - /* 赋值 / 复合赋值 */ if (op == SPL_OP_ASSIGN || (op >= SPL_OP_ASSIGN_ADD && op <= SPL_OP_ASSIGN_RSHIFT)) { spl_lang_type_id_t lt = sema_infer(sema, n->binary.left); if (!lt) @@ -1131,7 +1107,6 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { return lt; } - /* 逻辑 */ if (op == SPL_OP_BOOL_OR || op == SPL_OP_BOOL_AND) { spl_lang_type_id_t bt = spl_lang_make_bool(sema->type); sema_coerce(sema, n->binary.left, bt); @@ -1152,8 +1127,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { char lbuf[128], rbuf[128]; sema_type_to_str(sema, lt, lbuf, sizeof(lbuf)); sema_type_to_str(sema, rt, rbuf, sizeof(rbuf)); - SPL_ERROR(&n->dbg, "comparison operands type mismatch: lhs=%s rhs=%s", lbuf, rbuf); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, + "comparison operands type mismatch: lhs=%s rhs=%s", lbuf, rbuf); return 0; } @@ -1165,7 +1140,6 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { return b; } - /* Range */ if (op == SPL_OP_RANGE) { sema_infer(sema, n->binary.left); sema_infer(sema, n->binary.right); @@ -1175,15 +1149,14 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { return r; } - /* 移位:结果 = 左类型 */ if (op == SPL_OP_LSHIFT || op == SPL_OP_RSHIFT) { spl_lang_type_id_t lt = sema_infer(sema, n->binary.left); if (!lt) return 0; spl_lang_type_node_t *ln = spl_lang_type_node(sema->type, lt); if (!ln || ln->kind != SPL_LANG_TYPE_INT) { - SPL_ERROR(&n->dbg, "shift requires integer operands"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, + "shift requires integer operands"); return 0; } sema_infer(sema, n->binary.right); @@ -1199,9 +1172,6 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { spl_lang_type_node_t *ln = spl_lang_type_node(sema->type, lt); spl_lang_type_node_t *rn = spl_lang_type_node(sema->type, rt); - /* ptr +/- int 特判:右侧保留自己的整型; - * 仅当右操作数是 comptime_int(bits==0)时收紧到 isize, - * 避免 comptime 类型泄漏到 IR。 */ if (ln && ln->kind == SPL_LANG_TYPE_PTR && rn && rn->kind == SPL_LANG_TYPE_INT && (op == SPL_OP_ADD || op == SPL_OP_SUB)) { spl_type_node_t *rn_ir = spl_type_node(sema->type, rn->ir_type_id); @@ -1218,8 +1188,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { char lbuf[128], rbuf[128]; sema_type_to_str(sema, lt, lbuf, sizeof(lbuf)); sema_type_to_str(sema, rt, rbuf, sizeof(rbuf)); - SPL_ERROR(&n->dbg, "operand types cannot be joined: lhs=%s rhs=%s", lbuf, rbuf); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, + "operand types cannot be joined: lhs=%s rhs=%s", lbuf, rbuf); return 0; } @@ -1245,8 +1215,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { spl_lang_type_id_t callee_tid = sema_infer(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) { - SPL_ERROR(&n->dbg, "callee is not a function"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_NOT_A_FUNCTION, &n->dbg, + "callee is not a function"); return 0; } @@ -1264,15 +1234,14 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { usize nargs = vec_size(n->call.args); if (has_varargs) { if (nargs < fixed) { - SPL_ERROR(&n->dbg, "too few arguments (expected at least %zu)", fixed); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_ARG_COUNT_MISMATCH, &n->dbg, + "too few arguments (expected at least %zu)", fixed); } } else if (nargs != fixed) { - SPL_ERROR(&n->dbg, "argument count mismatch (expected %zu, got %zu)", fixed, nargs); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_ARG_COUNT_MISMATCH, &n->dbg, + "argument count mismatch (expected %zu, got %zu)", fixed, nargs); } - /* 固定参数:check 到形参类型 */ for (usize i = 0; i < nargs && i < fixed; ++i) { spl_lang_type_id_t pt = vec_at(spl_lang_type_node(sema->type, callee_tid)->extra.fn.params, i); @@ -1311,8 +1280,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { agg_lang = obj->extra.elem; spl_lang_type_node_t *agg = spl_lang_type_node(sema->type, agg_lang); if (!agg) { - SPL_ERROR(&n->dbg, "field access on invalid type"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_NO_FIELD, &n->dbg, + "field access on invalid type"); return 0; } @@ -1322,8 +1291,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { if (m) { spl_lang_type_id_t ft = sema_lang_from_ir(sema, m->type_id); if (!ft) { - SPL_ERROR(&n->dbg, "cannot resolve field type"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_NO_FIELD, &n->dbg, + "cannot resolve field type"); return 0; } n->resolved_lang_tid = ft; @@ -1341,8 +1310,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { return t; } - SPL_ERROR(&n->dbg, "no field `%s`", n->field.field); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_NO_FIELD, &n->dbg, "no field `%s`", + n->field.field); return 0; } @@ -1364,22 +1333,22 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { case SPL_LANG_TYPE_TUPLE: { spl_ast_node_t *idx_node = spl_ast_node(sema->ast, n->index.index); if (!idx_node || idx_node->kind != SPL_AST_EXPR_INT_LIT) { - SPL_ERROR(&n->dbg, "tuple index must be an integer literal"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_TUPLE_INDEX_OOB, &n->dbg, + "tuple index must be an integer literal"); return 0; } isize i = (isize)idx_node->int_lit.bits; if (i < 0 || (usize)i >= vec_size(obj->extra.elems)) { - SPL_ERROR(&n->dbg, "tuple index out of range"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_TUPLE_INDEX_OOB, &n->dbg, + "tuple index out of range"); return 0; } elem = vec_at(obj->extra.elems, (usize)i); break; } default: - SPL_ERROR(&n->dbg, "index base must be array/slice/ptr/range/tuple"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_INDEX_BASE_INVALID, &n->dbg, + "index base must be array/slice/ptr/range/tuple"); return 0; } n->resolved_lang_tid = elem; @@ -1401,8 +1370,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { obj->kind == SPL_LANG_TYPE_SLICE) { elem = obj->extra.elem; } else { - SPL_ERROR(&n->dbg, "slice base must be array/ptr/slice"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_INDEX_BASE_INVALID, &n->dbg, + "slice base must be array/ptr/slice"); return 0; } spl_lang_type_id_t s = spl_lang_make_slice(sema->type, elem); @@ -1427,7 +1396,6 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { sn && sn->kind == SPL_LANG_TYPE_FLOAT && sir && sir->float_type.bits == 0; if (src_is_literal_int || src_is_literal_float) { - /* 字面量目标物化:允许任意宽度,as 会按其语义处理 */ spl_ast_node_t *src_node = spl_ast_node(sema->ast, n->cast.expr); if (src_node && (src_node->kind == SPL_AST_EXPR_INT_LIT || src_node->kind == SPL_AST_EXPR_FLOAT_LIT)) { @@ -1442,14 +1410,14 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { spl_type_id_t ft = spl_lang_type_get_ir_type(sema->type, src_lang); spl_type_id_t tt = spl_lang_type_get_ir_type(sema->type, dst_lang); if (!ft || !tt) { - SPL_ERROR(&n->dbg, "as: unresolved source or target type"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_CAST_INVALID, &n->dbg, + "as: unresolved source or target type"); return 0; } spl_intrin_t in = spl_intrin_lookup_cast(sema->type, ft, tt); if (in == SPL_INTRIN_NONE) { - SPL_ERROR(&n->dbg, "as: invalid conversion (not supported by as)"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_CAST_INVALID, &n->dbg, + "as: invalid conversion (not supported by as)"); return 0; } n->resolved_lang_tid = dst_lang; @@ -1509,27 +1477,27 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { } spl_symbol_t sym; if (!spl_scope_find(sema->scope, type_name, &sym)) { - SPL_ERROR(&n->dbg, "unknown type `%s`", type_name); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_UNDEFINED_SYMBOL, &n->dbg, "unknown type `%s`", + type_name); return 0; } spl_def_node_t *def = spl_def_node(sema->type, sym.node); if (!def || !def->lang_id) { - SPL_ERROR(&n->dbg, "type `%s` not resolved", type_name); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_UNDEFINED_SYMBOL, &n->dbg, + "type `%s` not resolved", type_name); return 0; } spl_lang_type_id_t agg = def->lang_id; spl_lang_type_node_t *an = spl_lang_type_node(sema->type, agg); if (!an || (an->kind != SPL_LANG_TYPE_STRUCT && an->kind != SPL_LANG_TYPE_UNION && an->kind != SPL_LANG_TYPE_ENUM)) { - SPL_ERROR(&n->dbg, "`%s` is not a struct/union/enum", type_name); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, + "`%s` is not a struct/union/enum", type_name); return 0; } if (an->kind == SPL_LANG_TYPE_ENUM && vec_size(n->aggregate_literal.fields) != 1) { - SPL_ERROR(&n->dbg, "enum literal must have exactly one variant"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, + "enum literal must have exactly one variant"); return 0; } spl_type_id_t agg_ir = spl_lang_type_get_ir_type(sema->type, agg); @@ -1543,8 +1511,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { usize idx = 0; if (!spl_type_agg_member_idx(sema->type, agg_ir, item->struct_init_item.name, &idx)) { - SPL_ERROR(&item->dbg, "no field `%s`", item->struct_init_item.name); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_NO_FIELD, &item->dbg, "no field `%s`", + item->struct_init_item.name); continue; } usize field_tid_ir = vec_at(irn->agg_type.variants, idx).type_id; @@ -1561,8 +1529,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { case SPL_AST_EXPR_COMPTIME_CALL: { spl_intrin_t in = spl_intrin_lookup_call(n->comptime_call.name); if (in == SPL_INTRIN_NONE) { - SPL_ERROR(&n->dbg, "unknown comptime call `@%s`", n->comptime_call.name); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_UNKNOWN_INTRIN, &n->dbg, + "unknown comptime call `@%s`", n->comptime_call.name); return 0; } spl_lang_type_id_t t = sema_intrin_call(sema, n, in, &n->comptime_call.args); @@ -1571,17 +1539,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { } /* ---------- BLOCK ---------- */ - case SPL_AST_EXPR_BLOCK: { - sema_push_scope(sema); - spl_lang_type_id_t last = 0; - for (usize i = 0; i < vec_size(n->block.stmts); ++i) - sema_infer(sema, vec_at(n->block.stmts, i)); - if (n->block.tail_expr) - last = sema_infer(sema, n->block.tail_expr); - sema_pop_scope(sema); - n->resolved_lang_tid = last; - return last; - } + case SPL_AST_EXPR_BLOCK: + return sema_block_body(sema, n, 0); /* ---------- IF ---------- */ case SPL_AST_EXPR_IF: { @@ -1666,7 +1625,10 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, var_name, id_node->dbg, vec_at(n->for_expr.idents, i)); spl_def_resolve(sema->type, sym.node, elem_tid); - spl_scope_insert(sema->scope, sema->scope->current_scope, sym); + if (!spl_scope_insert(sema->scope, sema->scope->current_scope, sym)) { + spl_diag_error(sema->diag, SPL_DIAG_KIND_DUPLICATE_SYMBOL, + &id_node->dbg, "duplicate symbol `%s`", var_name); + } id_node->resolved_def_id = sym.node; id_node->resolved_lang_tid = elem_tid; } @@ -1718,8 +1680,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { } spl_symbol_t sym; if (!spl_scope_find(sema->scope, name, &sym)) { - SPL_ERROR(&n->dbg, "type `%s` not found", name); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_UNDEFINED_SYMBOL, &n->dbg, + "type `%s` not found", name); return 0; } spl_lang_type_id_t t = sema_eval_decl(sema, sym.node); @@ -1785,8 +1747,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { const char *name = n->type_comptime_call.name; if (name && strcmp(name, "self") == 0) { if (sema->current_aggregate_lang == 0) { - SPL_ERROR(&n->dbg, "`@self` outside of aggregate"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_UNDEFINED_SYMBOL, &n->dbg, + "`@self` outside of aggregate"); return 0; } n->resolved_lang_tid = sema->current_aggregate_lang; @@ -1842,7 +1804,10 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { pdef->state = p_tid ? SPL_DECL_RESOLVED : SPL_DECL_ERROR; } pd->resolved_def_id = psym.node; - spl_scope_insert(sema->scope, sema->scope->current_scope, psym); + if (!spl_scope_insert(sema->scope, sema->scope->current_scope, psym)) { + spl_diag_error(sema->diag, SPL_DIAG_KIND_DUPLICATE_SYMBOL, &pd->dbg, + "duplicate symbol `%s`", psym.name); + } } } spl_lang_type_id_t old_ret = sema->current_fn_ret_tid; @@ -1885,8 +1850,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { case SPL_AST_CONST_DECL: { spl_ast_node_t *pat = spl_ast_node(sema->ast, n->var_const_decl.pattern); if (!pat || pat->kind != SPL_AST_PATTERN_IDENT) { - SPL_ERROR(&n->dbg, "unsupported variable pattern"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, + "unsupported variable pattern"); return 0; } const char *name = pat->pattern_ident.name; @@ -1895,7 +1860,10 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { spl_symbol_t sym = {.name = name, .kind = SPL_SYMBOL_KIND_VAR}; sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, name, n->dbg, ref); n->resolved_def_id = sym.node; - spl_scope_insert(sema->scope, sema->scope->current_scope, sym); + if (!spl_scope_insert(sema->scope, sema->scope->current_scope, sym)) { + spl_diag_error(sema->diag, SPL_DIAG_KIND_DUPLICATE_SYMBOL, &n->dbg, + "duplicate symbol `%s`", name); + } } spl_lang_type_id_t decl_tid = 0; @@ -1903,8 +1871,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { decl_tid = sema_infer(sema, n->var_const_decl.type); if (!n->var_const_decl.init_expr) { - SPL_ERROR(&n->dbg, "variable `%s` must be initialized", name); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_VAR_UNINITIALIZED, &n->dbg, + "variable `%s` must be initialized", name); return 0; } @@ -1913,8 +1881,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { } else { decl_tid = sema_infer(sema, n->var_const_decl.init_expr); if (!decl_tid || sema_is_infer(sema, decl_tid)) { - SPL_ERROR(&n->dbg, "cannot infer type of `%s`", name); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_CANNOT_INFER, &n->dbg, + "cannot infer type of `%s`", name); return 0; } } @@ -1925,16 +1893,14 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { } /* ---------- MEMBER / PARAM ---------- */ - case SPL_AST_MEMBER_DECL: { + case SPL_AST_MEMBER_DECL: if (n->member_decl.type_expr) return sema_infer(sema, n->member_decl.type_expr); return 0; - } - case SPL_AST_PARAM_DECL: { + case SPL_AST_PARAM_DECL: if (n->param_decl.type_expr) return sema_infer(sema, n->param_decl.type_expr); return 0; - } /* ---------- 语句 ---------- */ case SPL_AST_STATEMENT_RET: { @@ -1946,8 +1912,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { } else if (sema->current_fn_ret_tid) { spl_lang_type_id_t u = spl_lang_make_unit(sema->type); if (sema->current_fn_ret_tid != u) { - SPL_ERROR(&n->dbg, "function must return a value"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_MUST_RETURN_VALUE, &n->dbg, + "function must return a value"); } } return 0; @@ -1960,8 +1926,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { lbl = ln->label.name; } if (vec_size(sema->label_stack) == 0) { - SPL_ERROR(&n->dbg, "`break` outside of loop"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_BREAK_OUTSIDE_LOOP, &n->dbg, + "`break` outside of loop"); return 0; } if (lbl) { @@ -1974,12 +1940,11 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { } } if (!found) { - SPL_ERROR(&n->dbg, "undefined label `$%s`", lbl); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_UNDEFINED_LABEL, &n->dbg, + "undefined label `$%s`", lbl); } } if (n->statement_break.expr) { - /* 有值 loop:break 值 coerce 到 loop 的期望类型 */ if (sema->current_loop_break_tid != 0) { sema_coerce(sema, n->statement_break.expr, sema->current_loop_break_tid); } else { @@ -1996,8 +1961,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { lbl = ln->label.name; } if (vec_size(sema->label_stack) == 0) { - SPL_ERROR(&n->dbg, "`continue` outside of loop"); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_CONTINUE_OUTSIDE_LOOP, &n->dbg, + "`continue` outside of loop"); return 0; } if (lbl) { @@ -2010,8 +1975,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { } } if (!found) { - SPL_ERROR(&n->dbg, "undefined label `$%s`", lbl); - sema->error_count++; + spl_diag_error(sema->diag, SPL_DIAG_KIND_UNDEFINED_LABEL, &n->dbg, + "undefined label `$%s`", lbl); } } return 0; @@ -2050,14 +2015,14 @@ void spl_sema_init(spl_sema_t *sema, spl_ast_t *ast, spl_type_t *type, spl_scope sema->ast = ast; sema->type = type; sema->scope = scope; - sema->error_count = 0; sema->current_fn_ret_tid = 0; sema->current_aggregate_lang = 0; sema->current_loop_break_tid = 0; sema->attr = attr; sema->root = (spl_symbol_t){0}; - sema->store_scope = 0; vec_init(sema->label_stack); + + sema->diag = NULL; } void spl_sema_drop(spl_sema_t *sema) { vec_free(sema->label_stack); } diff --git a/stage1/spl_sema.h b/stage1/spl_sema.h index 08cd6b1..50c0ab0 100644 --- a/stage1/spl_sema.h +++ b/stage1/spl_sema.h @@ -2,11 +2,11 @@ #define __SPL_SEMA_H__ #include "spl_ast.h" +#include "spl_attr.h" +#include "spl_diag.h" #include "spl_mpa.h" #include "spl_type.h" -#include "spl_attr.h" - typedef enum { SPL_SYMBOL_KIND_ERROR, SPL_SYMBOL_KIND_VAR, @@ -14,6 +14,7 @@ typedef enum { SPL_SYMBOL_KIND_FN, SPL_SYMBOL_KIND_TYPE, } spl_symbol_kind_t; + typedef struct { const char *name; spl_symbol_kind_t kind; @@ -21,11 +22,13 @@ typedef struct { } spl_symbol_t; typedef usize spl_scope_id_t; /* 0 is error */ + typedef struct { spl_scope_id_t parent; MAP(const char *, spl_symbol_t) symbols; } spl_scope_node_t; typedef VEC(spl_scope_node_t) spl_scope_node_vec_t; + typedef struct { spl_scope_node_vec_t scopes; spl_scope_id_t root_scope; @@ -34,24 +37,24 @@ typedef struct { void spl_scope_init(spl_scope_t *scope); void spl_scope_drop(spl_scope_t *scope); - spl_scope_id_t spl_scope_alloc(spl_scope_t *scope); bool spl_scope_insert(spl_scope_t *scope, spl_scope_id_t id, spl_symbol_t symbol); -typedef VEC(const char *) spl_symbol_path_t; bool spl_scope_find(spl_scope_t *scop, const char *symbol_name, spl_symbol_t *out); +typedef VEC(const char *) spl_symbol_path_t; + typedef struct { spl_ast_t *ast; spl_type_t *type; spl_scope_t *scope; spl_symbol_t root; - int error_count; - spl_scope_id_t store_scope; spl_attr_t *attr; spl_lang_type_id_t current_aggregate_lang; spl_lang_type_id_t current_fn_ret_tid; spl_lang_type_id_t current_loop_break_tid; spl_symbol_path_t label_stack; + + spl_diag_t *diag; } spl_sema_t; void spl_sema_init(spl_sema_t *sema, spl_ast_t *ast, spl_type_t *type, spl_scope_t *scope, diff --git a/stage1/spl_type.c b/stage1/spl_type.c index 1388491..4f06c11 100644 --- a/stage1/spl_type.c +++ b/stage1/spl_type.c @@ -380,61 +380,43 @@ bool spl_lang_type_is_subtype(const spl_type_t *type, spl_lang_type_id_t sub, if (!nsub || !nsuper) return false; + /* never 是任何类型的子类型(undefined / null 字面量的 pointee) */ if (nsub->kind == SPL_LANG_TYPE_NEVER) return true; + + /* 任何类型是 any 的子类型 */ if (nsuper->kind == SPL_LANG_TYPE_ANY) return true; + /* 整数:只有 comptime_int (bits==0) 能物化到具体整数 */ if (nsub->kind == SPL_LANG_TYPE_INT && nsuper->kind == SPL_LANG_TYPE_INT) { spl_type_node_t *ir_sub = spl_type_node(type, nsub->ir_type_id); - spl_type_node_t *ir_super = spl_type_node(type, nsuper->ir_type_id); - if (!ir_sub || !ir_super) + if (!ir_sub) return false; - uint32_t sb = (uint32_t)ir_sub->int_type.bits; - uint32_t pb = (uint32_t)ir_super->int_type.bits; - /* comptime_int (bits==0) 是整数格的 top */ - if (pb == 0) - return true; /* 任何具体整数 <: comptime_int */ - if (sb == 0) - return false; /* comptime_int 不能隐式收窄到具体整数 */ - bool ss = ir_sub->int_type.is_signed != 0; - bool ps = ir_super->int_type.is_signed != 0; - if (ss == ps) - return sb <= pb; - if (!ss && ps) - return sb < pb; - return false; + return ir_sub->int_type.bits == 0; } + /* 浮点:只有 comptime_float (bits==0) 能物化到具体浮点 */ if (nsub->kind == SPL_LANG_TYPE_FLOAT && nsuper->kind == SPL_LANG_TYPE_FLOAT) { spl_type_node_t *ir_sub = spl_type_node(type, nsub->ir_type_id); - spl_type_node_t *ir_super = spl_type_node(type, nsuper->ir_type_id); - if (!ir_sub || !ir_super) + if (!ir_sub) return false; - uint32_t sb = (uint32_t)ir_sub->float_type.bits; - uint32_t pb = (uint32_t)ir_super->float_type.bits; - if (pb == 0) - return true; - if (sb == 0) - return false; - return sb <= pb; + return ir_sub->float_type.bits == 0; } + /* 指针:只保留 *never -> *T、*T -> *any、同 elem */ if (nsub->kind == SPL_LANG_TYPE_PTR && nsuper->kind == SPL_LANG_TYPE_PTR) { + if (nsub->extra.elem == nsuper->extra.elem) + return true; spl_lang_type_node_t *sub_elem = spl_lang_type_node(type, nsub->extra.elem); spl_lang_type_node_t *super_elem = spl_lang_type_node(type, nsuper->extra.elem); if (sub_elem && sub_elem->kind == SPL_LANG_TYPE_NEVER) return true; if (super_elem && super_elem->kind == SPL_LANG_TYPE_ANY) return true; - if (nsub->extra.elem == nsuper->extra.elem) - return true; return false; } - if (nsub->kind == nsuper->kind) - return spl_type_is_subtype(type, nsub->ir_type_id, nsuper->ir_type_id); - return false; } @@ -469,41 +451,46 @@ spl_lang_type_id_t spl_lang_type_join(const spl_type_t *type, spl_lang_type_id_t if (na->kind == SPL_LANG_TYPE_ANY || nb->kind == SPL_LANG_TYPE_ANY) return spl_lang_make_any((spl_type_t *)type); - /* comptime 参与:返回另一侧的具体类型(comptime 是宽度未定,优先取具体) */ bool a_int = na->kind == SPL_LANG_TYPE_INT; bool b_int = nb->kind == SPL_LANG_TYPE_INT; bool a_flt = na->kind == SPL_LANG_TYPE_FLOAT; bool b_flt = nb->kind == SPL_LANG_TYPE_FLOAT; + + /* int / int:仅 comptime 混具体。两侧都具体则失败 */ if (a_int && b_int) { spl_type_node_t *ira = spl_type_node(type, na->ir_type_id); spl_type_node_t *irb = spl_type_node(type, nb->ir_type_id); - if (ira && irb) { - bool a_ct = ira->int_type.bits == 0; - bool b_ct = irb->int_type.bits == 0; - if (a_ct && b_ct) - return a; /* 都是 comptime_int */ - if (a_ct) - return b; - if (b_ct) - return a; - } + if (!ira || !irb) + return 0; + bool a_ct = ira->int_type.bits == 0; + bool b_ct = irb->int_type.bits == 0; + if (a_ct && b_ct) + return a; + if (a_ct) + return b; + if (b_ct) + return a; + return 0; } + + /* float / float:同 int 策略 */ if (a_flt && b_flt) { spl_type_node_t *ira = spl_type_node(type, na->ir_type_id); spl_type_node_t *irb = spl_type_node(type, nb->ir_type_id); - if (ira && irb) { - bool a_ct = ira->float_type.bits == 0; - bool b_ct = irb->float_type.bits == 0; - if (a_ct && b_ct) - return a; - if (a_ct) - return b; - if (b_ct) - return a; - } + if (!ira || !irb) + return 0; + bool a_ct = ira->float_type.bits == 0; + bool b_ct = irb->float_type.bits == 0; + if (a_ct && b_ct) + return a; + if (a_ct) + return b; + if (b_ct) + return a; + return 0; } - /* int / float 混合:仅 comptime 混 comptime 视为 comptime_float */ + /* int / float:只有 comptime 混 comptime 才视为 comptime_float */ if (a_int && b_flt) { spl_type_node_t *ira = spl_type_node(type, na->ir_type_id); spl_type_node_t *irb = spl_type_node(type, nb->ir_type_id); @@ -519,46 +506,27 @@ spl_lang_type_id_t spl_lang_type_join(const spl_type_t *type, spl_lang_type_id_t return 0; } - /* 现在走子类型关系(两侧均为具体类型) */ - if (spl_lang_type_is_subtype(type, a, b)) - return b; - if (spl_lang_type_is_subtype(type, b, a)) - return a; + /* 指针:*never 与任意 *T 结合得 *T;*T 与 *any 结合得 *any */ + if (na->kind == SPL_LANG_TYPE_PTR && nb->kind == SPL_LANG_TYPE_PTR) { + if (na->extra.elem == nb->extra.elem) + return a; + + spl_lang_type_node_t *ea = spl_lang_type_node(type, na->extra.elem); + spl_lang_type_node_t *eb = spl_lang_type_node(type, nb->extra.elem); + + /* 一侧 elem 是 never:结果取另一侧 */ + if (ea && ea->kind == SPL_LANG_TYPE_NEVER) + return b; + if (eb && eb->kind == SPL_LANG_TYPE_NEVER) + return a; + + /* 一侧 elem 是 any:结果取 any 那侧 */ + if (ea && ea->kind == SPL_LANG_TYPE_ANY) + return a; + if (eb && eb->kind == SPL_LANG_TYPE_ANY) + return b; - if (na->kind != nb->kind) return 0; - - if (a_int) { - spl_type_node_t *ira = spl_type_node(type, na->ir_type_id); - spl_type_node_t *irb = spl_type_node(type, nb->ir_type_id); - if (!ira || !irb) - return 0; - uint32_t ba = (uint32_t)ira->int_type.bits; - uint32_t bb = (uint32_t)irb->int_type.bits; - bool sa = ira->int_type.is_signed != 0; - bool sb = irb->int_type.is_signed != 0; - if (sa == sb) { - uint32_t bits = ba > bb ? ba : bb; - return spl_lang_make_int((spl_type_t *)type, bits, sa); - } - uint32_t s_bits = sa ? ba : bb; - uint32_t u_bits = sa ? bb : ba; - uint32_t need = s_bits > (u_bits + 1) ? s_bits : (u_bits + 1); - uint32_t std_bits = spl_type_std_int_bits_up(need); - if (std_bits == 0) - return 0; - return spl_lang_make_int((spl_type_t *)type, std_bits, 1); - } - - if (a_flt) { - spl_type_node_t *ira = spl_type_node(type, na->ir_type_id); - spl_type_node_t *irb = spl_type_node(type, nb->ir_type_id); - if (!ira || !irb) - return 0; - uint32_t ba = (uint32_t)ira->float_type.bits; - uint32_t bb = (uint32_t)irb->float_type.bits; - uint32_t bits = ba > bb ? ba : bb; - return spl_lang_make_float((spl_type_t *)type, bits); } return 0; diff --git a/stage1/splc0.c b/stage1/splc0.c index 0ac29f8..54b4025 100644 --- a/stage1/splc0.c +++ b/stage1/splc0.c @@ -12,6 +12,7 @@ #include "spl_ast.h" #include "spl_ast2ir.h" +#include "spl_diag.h" #include "spl_ir2vm.h" #include "spl_lexer.h" #include "spl_sema.h" @@ -77,11 +78,17 @@ static int compile_spl(const char *src, const char *fname, const char *outpath, // memory leak return 0; } + + spl_diag_t diag; + spl_diag_init(&diag, stderr); + spl_ast_t ast; spl_ast_init(&ast, &toks); + spl_diag_set_stage(&diag, SPL_STAGE_PARSE); + ast.diag = &diag; spl_ast_parse(&ast); - if (ast.parsed < 0) { - printf("parse failed, no output\n"); + if (spl_diag_has_error(&diag) || spl_diag_has_fatal(&diag)) { + spl_diag_summary(&diag); // memory leak return 1; } @@ -101,10 +108,12 @@ static int compile_spl(const char *src, const char *fname, const char *outpath, spl_scope_init(&scope); spl_sema_init(&sema, &ast, &type, &scope, &attr); sema.ast = * + spl_diag_set_stage(&diag, SPL_STAGE_SEMA); + sema.diag = &diag; spl_sema_run(&sema); - if (sema.error_count) { - printf("sema errors=%d, no output\n", sema.error_count); + if (spl_diag_has_error(&diag) || spl_diag_has_fatal(&diag)) { // memory leak + spl_diag_summary(&diag); return 1; } if (dump == DUMP_SEMA) { @@ -118,9 +127,12 @@ static int compile_spl(const char *src, const char *fname, const char *outpath, spl_ir_builder_t ir_builder; spl_ir_builder_init(&ir_builder); spl_ast2ir_init(&a2ir, &ir_builder, &sema); + spl_diag_set_stage(&diag, SPL_STAGE_AST2IR); + a2ir.diag = &diag; spl_ast2ir_run(&a2ir); - if (a2ir.err_count) { - printf("ast2ir errors=%d, no output\n", a2ir.err_count); + if (spl_diag_has_error(&diag) || spl_diag_has_fatal(&diag)) { + spl_diag_summary(&diag); + // memory leak spl_ast2ir_drop(&a2ir); spl_sema_drop(&sema); spl_ast_drop(&ast); @@ -134,9 +146,12 @@ static int compile_spl(const char *src, const char *fname, const char *outpath, spl_ir2vm_t ir2vm; spl_ir2vm_init(&ir2vm, &a2ir.ir->ir, &type, &attr); + // ir2vm.diag = &diag; + spl_diag_set_stage(&diag, SPL_STAGE_IR2VM); + ir2vm.diag = &diag; int rc = spl_ir2vm_run(&ir2vm); - if (rc != 0) { - printf("ir2vm error %d", rc); + if (spl_diag_has_error(&diag) || spl_diag_has_fatal(&diag)) { + spl_diag_summary(&diag); return rc; } if (dump == DUMP_VM) {