From 8ac59dfaa157760a330ef3b935d208b8492b2b06 Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Tue, 4 Aug 2026 10:20:57 +0800 Subject: [PATCH] =?UTF-8?q?stage1=20=E5=AE=8C=E6=88=90sema=E8=AF=8D?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SPL.md | 7 + stage1/spl_ast.c | 33 +- stage1/spl_ast.h | 5 +- stage1/spl_emit.h | 4 + stage1/spl_ir.h | 11 +- stage1/spl_sema.c | 1868 ++++++++++++++++++++++++++++++++++- stage1/spl_sema.h | 8 +- stage1/spl_type.c | 325 +++++- stage1/spl_type.h | 18 +- stage1/splc0.c | 53 +- stage1/test01_literals.spl | 8 +- stage1/test04_operators.spl | 10 +- stage1/test10_struct.spl | 2 +- stage1/test13_extern.spl | 4 +- 14 files changed, 2309 insertions(+), 47 deletions(-) create mode 100644 stage1/spl_emit.h diff --git a/SPL.md b/SPL.md index 732b228..176e9a3 100644 --- a/SPL.md +++ b/SPL.md @@ -478,6 +478,13 @@ type T = TypeExpr — 完全同义。 匹配: match 必须穷举 (或含 _),否则编译错误。 +## 名称解析 + +1. 函数内部 (参数 + 块局部,每个 {} 建立子 scope)。 +2. $root:文件聚合的 scope,所有顶层声明 (fn/type/var/const) 都是其成员。 + +无独立"全局"命名空间。$root 抽象不写死:@import(xxx) 返回的匿名结构即该模块当时的 $root,多文件时切换。字段/变体名不在 scope map 中 (存于聚合 def 的成员列表),裸名查找天然不命中字段;路径 a.b.c 首段裸名查 scope、后续段查聚合成员。 + ## 变量与常量 var x: T 或 var x := init: 可变量。 diff --git a/stage1/spl_ast.c b/stage1/spl_ast.c index c3503bb..ec0468b 100644 --- a/stage1/spl_ast.c +++ b/stage1/spl_ast.c @@ -151,10 +151,7 @@ static void parse_error(parser_t *p, spl_tok_t *t, const char *msg) { const char *fn = (t && t->fname) ? t->fname : ""; usize line = t ? t->line : 0; usize col = t ? t->col : 0; - fprintf(stderr, "%s:%llu:%llu: error: %s\n", fn, (unsigned long long)line, - (unsigned long long)col, msg); - fflush(stderr); - abort(); + LOG_FATAL("%s:%llu:%llu: error: %s", fn, (unsigned long long)line, (unsigned long long)col, msg); } static int expect(parser_t *p, spl_tok_type_t type, const char *what) { @@ -1383,7 +1380,8 @@ static spl_ast_node_ref_t parse_postfix(parser_t *p) { } } else if (t->type == TOK_L_BRACKET) { advance(p); - spl_ast_node_ref_t begin = parse_expr(p); + /* 切片 begin 用 parse_shift 解析:`a..b` 中 `..` 属切片标记而非 Range 表达式 */ + spl_ast_node_ref_t begin = parse_shift(p); if (peek(p) && peek(p)->type == TOK_RANGE) { advance(p); spl_ast_node_ref_t end = 0; @@ -1529,7 +1527,8 @@ static spl_ast_node_ref_t parse_primary(parser_t *p) { /* 结构体字面量 T { .f1 = e1, ... } */ spl_ast_node_ref_vec_t agg_vec = parse_aggregate_init_body(p); spl_ast_node_ref_t pr = mk_primary(p, t, SPL_AST_ARGGREGATE_INIT); - node_at(p->ast, pr)->primary_expr.aggregate_init_expr = agg_vec; + node_at(p->ast, pr)->primary_expr.aggregate_init.name = sdupn(t->lexeme, t->len); + node_at(p->ast, pr)->primary_expr.aggregate_init.expr = agg_vec; return wrap_expr(p, pr); } spl_ast_node_ref_t pr = mk_primary(p, t, SPL_AST_IDENT); @@ -1543,7 +1542,8 @@ static spl_ast_node_ref_t parse_primary(parser_t *p) { advance(p); spl_ast_node_ref_vec_t agg_vec = parse_aggregate_init_body(p); spl_ast_node_ref_t pr = mk_primary(p, t, SPL_AST_ARGGREGATE_INIT); - node_at(p->ast, pr)->primary_expr.aggregate_init_expr = agg_vec; + node_at(p->ast, pr)->primary_expr.aggregate_init.name = NULL; + node_at(p->ast, pr)->primary_expr.aggregate_init.expr = agg_vec; return wrap_expr(p, pr); } parse_error(p, t, "unexpected '.' in expression"); @@ -2132,10 +2132,8 @@ static void expr_inline(spl_ast_t *ast, spl_ast_node_ref_t ref, char *out, size_ snprintf(tmp, sizeof tmp, "%s", STR(pn->primary_expr.ident)); break; case SPL_AST_ARGGREGATE_INIT: - tmp[0] = '{'; - tmp[1] = ' '; - tmp[2] = '\0'; - agg_items_inline(ast, &pn->primary_expr.aggregate_init_expr, tmp, sizeof tmp); + snprintf(tmp, sizeof tmp, "%s{ ", STR(pn->primary_expr.aggregate_init.name)); + agg_items_inline(ast, &pn->primary_expr.aggregate_init.expr, tmp, sizeof tmp); strncat(tmp, " }", sizeof tmp - strlen(tmp) - 1); break; case SPL_AST_EXPR_EXPR: @@ -2480,11 +2478,11 @@ static void dump_primary_expr(spl_ast_t *ast, spl_ast_node_ref_t ref, const char node_label(prefix, is_last, "Ident %s", STR(n->primary_expr.ident)); break; case SPL_AST_ARGGREGATE_INIT: - node_label(prefix, is_last, "AggInit"); + node_label(prefix, is_last, "AggInit %s", STR(n->primary_expr.aggregate_init.name)); spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); - for (usize i = 0; i < n->primary_expr.aggregate_init_expr.size; i++) { - spl_ast_node_t *it = &ast->buckets.data[n->primary_expr.aggregate_init_expr.data[i]]; - int it_last = (int)(i == n->primary_expr.aggregate_init_expr.size - 1); + for (usize i = 0; i < n->primary_expr.aggregate_init.expr.size; i++) { + spl_ast_node_t *it = &ast->buckets.data[n->primary_expr.aggregate_init.expr.data[i]]; + int it_last = (int)(i == n->primary_expr.aggregate_init.expr.size - 1); node_label(cp, it_last, "Field .%s", STR(it->aggregate_init_item.ident)); if (it->aggregate_init_item.expr) { char cq[512]; @@ -3153,7 +3151,8 @@ static void drop_node(spl_ast_t *ast, spl_ast_node_ref_t ref, walk_ctx_t ctx) { free((void *)n->primary_expr.string_lit_expr); break; case SPL_AST_ARGGREGATE_INIT: - drop_vec(ast, &n->primary_expr.aggregate_init_expr, CTX_AGG_ITEM); + free((void *)n->primary_expr.aggregate_init.name); + drop_vec(ast, &n->primary_expr.aggregate_init.expr, CTX_AGG_ITEM); break; case SPL_AST_EXPR_EXPR: drop_node(ast, n->primary_expr.expr, CTX_EXPR); @@ -3382,7 +3381,7 @@ static void validate_node(spl_ast_t *ast, spl_ast_node_ref_t ref, walk_ctx_t ctx printf("valid: identifier missing name\n"); break; case SPL_AST_ARGGREGATE_INIT: - validate_vec(ast, &n->primary_expr.aggregate_init_expr, CTX_AGG_ITEM); + validate_vec(ast, &n->primary_expr.aggregate_init.expr, CTX_AGG_ITEM); break; case SPL_AST_EXPR_EXPR: validate_node(ast, n->primary_expr.expr, CTX_EXPR); diff --git a/stage1/spl_ast.h b/stage1/spl_ast.h index b90c8d4..de66679 100644 --- a/stage1/spl_ast.h +++ b/stage1/spl_ast.h @@ -253,7 +253,10 @@ struct spl_ast_node { const char *string_lit_expr; /* parsed c string */ const char *ident; - spl_ast_node_ref_vec_t aggregate_init_expr; /* aggregate_init_item */ + struct { + const char *name; + spl_ast_node_ref_vec_t expr; /* aggregate_init_item */ + } aggregate_init; spl_ast_node_ref_t expr; struct { diff --git a/stage1/spl_emit.h b/stage1/spl_emit.h new file mode 100644 index 0000000..265b9f6 --- /dev/null +++ b/stage1/spl_emit.h @@ -0,0 +1,4 @@ +#ifndef __SPL_EMIT_H__ +#define __SPL_EMIT_H__ + +#endif /* __SPL_EMIT_H__ */ diff --git a/stage1/spl_ir.h b/stage1/spl_ir.h index 38c2b0b..f978f80 100644 --- a/stage1/spl_ir.h +++ b/stage1/spl_ir.h @@ -85,7 +85,7 @@ typedef struct { } spl_ir_node_t; typedef VEC(spl_ir_node_t) spl_ir_node_vec_t; -typedef usize spl_ir_node_ref_t; +typedef usize spl_ir_node_ref_t; /* 0 is error */ typedef VEC(spl_ir_node_ref_t) spl_ir_node_ref_vec_t; typedef struct { @@ -106,8 +106,9 @@ typedef struct { spl_ir_node_vec_t nodes; spl_ir_node_ref_vec_t labels; } spl_ir_func_t; - +typedef usize spl_ir_func_ref_t; /* 0 is error */ typedef VEC(spl_ir_func_t) spl_ir_func_vec_t; + typedef struct { spl_ir_func_vec_t funcs; } spl_ir_t; @@ -115,6 +116,12 @@ typedef struct { void spl_ir_init(spl_ir_t *ir); void spl_ir_drop(spl_ir_t *ir); +spl_ir_node_ref_t spl_ir_alloc_node(spl_ir_t *ir, spl_ir_func_ref_t fn_id); +spl_ir_func_ref_t spl_ir_alloc_fn(spl_ir_t *ir); + +spl_ir_node_t *spl_ir_node(spl_ir_t *ir, spl_ir_func_ref_t fn_id, spl_ir_node_ref_t node_id); +spl_ir_func_t *spl_ir_func(spl_ir_t *ir, spl_ir_func_ref_t fn_id); + void spl_ir_dump(spl_ir_t *ir); #endif /* __SPL_IR_H__ */ diff --git a/stage1/spl_sema.c b/stage1/spl_sema.c index 95249de..7355a67 100644 --- a/stage1/spl_sema.c +++ b/stage1/spl_sema.c @@ -1 +1,1867 @@ -#include "spl_sema.h" \ No newline at end of file +// WRITE BY AI +/* spl_sema.c SPL 语义分析 + * + * 两趟 AST 遍历(splc0 显式先 run 再 check): + * spl_sema_run —— Pass1:预登记顶层名字(聚合壳/别名/fn/var),使兄弟前向引用成立 + * spl_sema_check —— Pass2:边构建聚合成员与方法 def,边检查函数体(类型检查) + * + * scope 符号表存 spl_def_id_t(def 第一公民);匿名类型放 type_table, + * 命名实体放 def_table,两张表 id 空间完全独立。 + */ +#include "spl_sema.h" + +#include +#include + +typedef struct { + spl_type_id_t ret; +} spl_sema_ctx_t; + +static spl_ast_node_t *node_at(spl_ast_t *ast, spl_ast_node_ref_t ref) { + if (!ref || ref >= ast->buckets.size) + return NULL; + return &ast->buckets.data[ref]; +} + +static void sema_error(spl_sema_t *sema, spl_ast_node_ref_t ref, const char *msg) { + spl_ast_node_t *n = node_at(sema->ast, ref); + sema->error_count++; + if (n) { + LOG_ERROR("%s error: %s (%s:%d:%d)", "sema", msg, n->loc.fname ? n->loc.fname : "?", + n->loc.line, n->loc.col); + } else { + LOG_ERROR("%s error: %s", "sema", msg); + } +} + +static void sema_warn(spl_sema_t *sema, spl_ast_node_ref_t ref, const char *msg) { + spl_ast_node_t *n = node_at(sema->ast, ref); + if (n) { + LOG_WARN("%s warning: %s (%s:%d:%d)", "sema", msg, n->loc.fname ? n->loc.fname : "?", + n->loc.line, n->loc.col); + } else { + LOG_WARN("%s warning: %s", "sema", msg); + } +} + +/* ---- def/type 快捷访问 ---- */ + +static spl_def_node_t *def_at(spl_sema_t *sema, spl_def_id_t id) { + return spl_type_def(&sema->type, id); +} + +static spl_type_id_t def_type(spl_sema_t *sema, spl_def_id_t id) { + spl_def_node_t *d = def_at(sema, id); + return d ? d->type_id : 0; +} + +/* 由匿名类型 id 反查拥有它的 def(聚合优先;别名/ distinct 次之) */ +static spl_def_id_t def_for_type(spl_sema_t *sema, spl_type_id_t tid) { + if (!tid) + return 0; + spl_def_id_t fallback = 0; + for (usize i = 1; i < sema->type.def_table.size; i++) { + spl_def_node_t *d = &sema->type.def_table.data[i]; + if (d->type_id == tid) { + if (d->kind == SPL_DEF_AGG) + return i; + if (!fallback && (d->kind == SPL_DEF_ALIAS || d->kind == SPL_DEF_DISTINCT)) + fallback = i; + } + } + return fallback; +} + +static spl_def_id_t def_alloc(spl_sema_t *sema, int kind) { + spl_def_id_t id = spl_type_def_alloc(&sema->type); + def_at(sema, id)->kind = kind; + return id; +} + +static spl_def_id_t new_var_def(spl_sema_t *sema, const char *name, spl_type_id_t type, + spl_scope_id_t scope) { + spl_def_id_t id = def_alloc(sema, SPL_DEF_VAR); + spl_def_node_t *d = def_at(sema, id); + d->type_id = type; + d->var_def.name = name; + d->var_def.def_id = id; + d->var_def.type_id = type; + d->var_def.scope_id = scope; + return id; +} + +/* 裸名查找:从 current_scope 沿父链到 root(字段名不在 symbols,天然不命中) */ +static spl_def_id_t find_bare(spl_sema_t *sema, const char *name) { + spl_scope_id_t cur = sema->current_scope; + while (cur) { + if (cur >= sema->scopes.size) + break; + spl_def_id_t val = 0; + if (map_get(sema->scopes.data[cur].symbols, name, &val)) + return val; + cur = sema->scopes.data[cur].parent; + } + return 0; +} + +/* 名字 → 其类型(def → type_id) */ +static spl_type_id_t find_type(spl_sema_t *sema, const char *name) { + return def_type(sema, find_bare(sema, name)); +} + +/* ---- 聚合成员登记(def 层 agg_def) ---- */ + +static void agg_add_member(spl_sema_t *sema, spl_def_id_t def, const char *name, spl_type_id_t type, + spl_scope_id_t scope) { + spl_def_node_t *d = def_at(sema, def); + if (!d || d->kind != SPL_DEF_AGG) + return; + spl_var_def_t v = {name, 0, type, scope}; + vec_push(d->agg_def, v); +} + +/* 聚合/枚举成员查找:匿名类型 id → 拥有它的 def → agg_def */ +static spl_type_id_t agg_member_type(spl_sema_t *sema, spl_type_id_t agg_tid, const char *name) { + spl_def_id_t d = def_for_type(sema, agg_tid); + if (!d) + return 0; + spl_def_node_t *def = def_at(sema, d); + for (usize i = 0; i < def->agg_def.size; i++) { + if (def->agg_def.data[i].name && strcmp(def->agg_def.data[i].name, name) == 0) + return def->agg_def.data[i].type_id; + } + return 0; +} + +/* ---- 类型解析 ---- */ + +static spl_type_id_t resolve_type_expr(spl_sema_t *sema, spl_ast_node_ref_t ref); +static spl_type_id_t resolve_type_atom(spl_sema_t *sema, spl_ast_node_ref_t ref); +static spl_type_id_t build_agg(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t parent, + const char *name); + +/* 路径类型:首段裸名(含内置),后续段逐级查聚合 agg_def */ +static spl_type_id_t resolve_type_path(spl_sema_t *sema, spl_ast_node_ref_vec_t *path) { + if (!path->size) + return 0; + spl_type_id_t tid = resolve_type_atom(sema, path->data[0]); + if (!tid) + return 0; + for (usize i = 1; i < path->size; i++) { + spl_ast_node_t *atom = node_at(sema->ast, path->data[i]); + if (!atom) { + sema_error(sema, path->data[i], "bad type path segment"); + return 0; + } + spl_type_id_t mt = agg_member_type(sema, tid, atom->type_atom.ident); + if (!mt) { + char buf[128]; + snprintf(buf, sizeof buf, "no member '%s' in type", atom->type_atom.ident); + sema_error(sema, path->data[i], buf); + return 0; + } + tid = mt; + } + return tid; +} + +static spl_type_id_t resolve_type_atom(spl_sema_t *sema, spl_ast_node_ref_t ref) { + spl_ast_node_t *n = node_at(sema->ast, ref); + if (!n) + return 0; + switch (n->type_atom.kind) { + case SPL_AST_TYPE_VOID: + return spl_type_void(&sema->type); + case SPL_AST_TYPE_BOOL: + return spl_type_bool(&sema->type); + case SPL_AST_TYPE_I8: + return spl_type_int(&sema->type, 8, 1); + case SPL_AST_TYPE_U8: + return spl_type_int(&sema->type, 8, 0); + case SPL_AST_TYPE_I16: + return spl_type_int(&sema->type, 16, 1); + case SPL_AST_TYPE_U16: + return spl_type_int(&sema->type, 16, 0); + case SPL_AST_TYPE_I32: + return spl_type_int(&sema->type, 32, 1); + case SPL_AST_TYPE_U32: + return spl_type_int(&sema->type, 32, 0); + case SPL_AST_TYPE_I64: + return spl_type_int(&sema->type, 64, 1); + case SPL_AST_TYPE_U64: + return spl_type_int(&sema->type, 64, 0); + case SPL_AST_TYPE_ISIZE: + return spl_type_int(&sema->type, sizeof(isize) * 8, 1); + case SPL_AST_TYPE_USIZE: + return spl_type_int(&sema->type, sizeof(usize) * 8, 0); + case SPL_AST_TYPE__F32: + return spl_type_float(&sema->type, 32); + case SPL_AST_TYPE__F64: + return spl_type_float(&sema->type, 64); + case SPL_AST_TYPE_PTR: + case SPL_AST_TYPE_ANY: + /* `_`/`ptr` 均为通配:只能作为指针目标,等于 *void。 + * 裸用(无 * 前缀)由 resolve_type_expr 报错;ptr 关键字暂不使用 */ + return spl_type_void(&sema->type); + case SPL_AST_TYPE_IDENT: { + spl_type_id_t tid = find_type(sema, n->type_atom.ident); + if (!tid) { + char buf[160]; + snprintf(buf, sizeof buf, "unknown type '%s'", n->type_atom.ident); + sema_error(sema, ref, buf); + return 0; + } + return tid; + } + } + return 0; +} + +static spl_type_id_t resolve_type_expr(spl_sema_t *sema, spl_ast_node_ref_t ref) { + spl_ast_node_t *n = node_at(sema->ast, ref); + if (!n) + return 0; + spl_type_id_t base = 0; + switch (n->type_expr.kind) { + case SPL_AST_BASE_TYPE_PATH: + base = resolve_type_path(sema, &n->type_expr.type_path); + break; + case SPL_AST_BASE_TYPE_FN: { + spl_type_id_vec_t params; + vec_init(params); + for (usize i = 0; i < n->type_expr.fn_type.param_list.size; i++) { + spl_ast_node_t *pd = node_at(sema->ast, n->type_expr.fn_type.param_list.data[i]); + spl_type_id_t pt = 0; + if (pd && pd->param_decl.type_expr) + pt = resolve_type_expr(sema, pd->param_decl.type_expr); + vec_push(params, pt); + } + spl_type_id_t ret = 0; + if (n->type_expr.fn_type.type_expr) + ret = resolve_type_expr(sema, n->type_expr.fn_type.type_expr); + else + ret = spl_type_void(&sema->type); + base = spl_type_fn(&sema->type, params, ret); + break; + } + case SPL_AST_TYPE_STRUCT: + case SPL_AST_TYPE_UNION: + case SPL_AST_TYPE_ENUM: + /* 内联匿名聚合:构建聚合类型(不注册名字,parent 为当前 scope) */ + base = build_agg(sema, ref, sema->current_scope, NULL); + break; + default: + return 0; + } + /* 前缀修饰:* → ptr,[] → slice,[n] → array(逆序包裹) */ + for (usize i = n->type_expr.type_prefixs.size; i > 0; i--) { + spl_ast_node_t *pf = node_at(sema->ast, n->type_expr.type_prefixs.data[i - 1]); + if (!pf) + continue; + if (pf->prefix_type.pointer == 1) { + base = spl_type_ptr(&sema->type, base); + } else if (pf->prefix_type.pointer == 2) { + if (pf->prefix_type.array_size > 0) + base = spl_type_array(&sema->type, base, (usize)pf->prefix_type.array_size); + else + base = spl_type_slice(&sema->type, base); + } + } + /* `_`/`ptr` 只能在指针目标位置(*_ = *void);裸用是无类型值,报错 */ + if (n->type_expr.kind == SPL_AST_BASE_TYPE_PATH && n->type_expr.type_path.size) { + spl_ast_node_t *atom = + node_at(sema->ast, n->type_expr.type_path.data[n->type_expr.type_path.size - 1]); + int ptr_pre = 0; + for (usize i = 0; i < n->type_expr.type_prefixs.size; i++) { + spl_ast_node_t *pf = node_at(sema->ast, n->type_expr.type_prefixs.data[i]); + if (pf && pf->prefix_type.pointer == 1) + ptr_pre = 1; + } + if (atom && !ptr_pre && + (atom->type_atom.kind == SPL_AST_TYPE_ANY || atom->type_atom.kind == SPL_AST_TYPE_PTR)) + sema_error(sema, ref, "bare `_` type only allowed as pointer target `*_`"); + } + return base; +} + +/* ---- 声明处理 ---- */ + +static void sema_fn_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t scope, + spl_def_id_t agg_def); +static void sema_type_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t scope, + spl_def_id_t agg_def); +static void sema_var_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t scope, + spl_def_id_t agg_def); +static void sema_const_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t scope, + spl_def_id_t agg_def); +static void check_fn_body(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_def_id_t fdef, + spl_scope_id_t parent_scope); + +typedef struct { + spl_type_id_t tid; + spl_def_id_t def; +} agg_handle_t; + +/* 只建匿名聚合类型 + AGG def(名字由调用方注册到目标 scope),不做成员解析。 + * 用于顶层聚合在 Pass1 预登记,使兄弟/自引用 `type Node{next:*Node}` 成立。 */ +static agg_handle_t agg_prepare(spl_sema_t *sema, spl_ast_node_ref_t ref) { + agg_handle_t h = {0, 0}; + spl_ast_node_t *te = node_at(sema->ast, ref); + if (!te) + return h; + spl_type_id_t tid = spl_type_alloc(&sema->type); + spl_type_node_t *tn = spl_type_node(&sema->type, tid); + switch (te->type_expr.kind) { + case SPL_AST_TYPE_STRUCT: + tn->kind = SPL_TYPE_STRUCT; + vec_init(tn->agg_field_types); + break; + case SPL_AST_TYPE_UNION: + tn->kind = SPL_TYPE_UNION; + vec_init(tn->agg_field_types); + break; + case SPL_AST_TYPE_ENUM: + tn->kind = SPL_TYPE_ENUM; + vec_init(tn->enum_type.variants); + tn->enum_type.tag_type = 0; + break; + default: + return h; /* 非聚合 */ + } + spl_def_id_t def = def_alloc(sema, SPL_DEF_AGG); + def_at(sema, def)->type_id = tid; + vec_init(def_at(sema, def)->agg_def); + h.tid = tid; + h.def = def; + return h; +} + +/* 聚合成员解析:建聚合 scope(自名注册)→ 嵌套类型 pass1 → 成员/方法 pass2 → 方法体 pass3 */ +static void agg_resolve(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_type_id_t tid, + spl_def_id_t def, spl_scope_id_t parent, const char *name) { + spl_ast_node_t *te = node_at(sema->ast, ref); + if (!te) + return; + spl_scope_id_t agg_scope = spl_sema_scope_alloc(sema); + sema->scopes.data[agg_scope].parent = parent; + if (name) + spl_sema_scope_insert(sema, agg_scope, name, def); + spl_scope_id_t save = sema->current_scope; + sema->current_scope = agg_scope; + /* pass1: 先构建嵌套类型(type 声明),使字段类型可前向引用嵌套类型 */ + for (usize i = 0; i < te->type_expr.aggregate_list.size; i++) { + spl_ast_node_t *m = node_at(sema->ast, te->type_expr.aggregate_list.data[i]); + if (m && m->kind == SPL_AST_TYPE_DECL) + sema_type_decl(sema, te->type_expr.aggregate_list.data[i], agg_scope, def); + } + /* pass2: 成员 + 方法 def(兄弟方法全部登记后再检查体) */ + for (usize i = 0; i < te->type_expr.aggregate_list.size; i++) { + spl_ast_node_ref_t mref = te->type_expr.aggregate_list.data[i]; + spl_ast_node_t *m = node_at(sema->ast, mref); + if (!m) + continue; + switch (m->kind) { + case SPL_AST_MEMBER_DECL: { + spl_type_id_t ft = + m->member_decl.type_expr ? resolve_type_expr(sema, m->member_decl.type_expr) : 0; + /* resolve_type_expr 可能 alloc 新类型 → 两表 realloc,须重新取节点 */ + spl_type_node_t *tn = spl_type_node(&sema->type, tid); + if (tn->kind == SPL_TYPE_ENUM) { + vec_push(tn->enum_type.variants, ft ? ft : tid); + agg_add_member(sema, def, m->member_decl.name, ft ? ft : tid, agg_scope); + } else { + vec_push(tn->agg_field_types, ft); + agg_add_member(sema, def, m->member_decl.name, ft, agg_scope); + } + break; + } + case SPL_AST_FN_DECL: + case SPL_AST_FN_DEFINE: + sema_fn_decl(sema, mref, agg_scope, def); + break; + case SPL_AST_TYPE_DECL: + /* 已在 pass1 处理 */ + break; + case SPL_AST_VAR_DECL: + sema_var_decl(sema, mref, agg_scope, def); + break; + case SPL_AST_CONST_DECL: + sema_const_decl(sema, mref, agg_scope, def); + break; + default: + break; + } + } + /* pass3: 检查方法体(当前聚合所有方法已登记,兄弟可互调) */ + for (usize i = 0; i < te->type_expr.aggregate_list.size; i++) { + spl_ast_node_ref_t mref = te->type_expr.aggregate_list.data[i]; + spl_ast_node_t *m = node_at(sema->ast, mref); + if (m && m->kind == SPL_AST_FN_DEFINE) { + spl_def_id_t mdef = find_bare(sema, m->fn_decl.name); + check_fn_body(sema, mref, mdef, agg_scope); + } + } + sema->current_scope = save; +} + +/* 嵌套/内联聚合:prepare + resolve 一步完成 */ +static spl_type_id_t build_agg(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t parent, + const char *name) { + agg_handle_t h = agg_prepare(sema, ref); + if (!h.tid) + return 0; + agg_resolve(sema, ref, h.tid, h.def, parent, name); + return h.tid; +} + +/* 变量/常量/绑定节点:建 VAR def(不包 SPL_TYPE_ID) */ +static void register_binding(spl_sema_t *sema, const char *name, spl_ast_node_ref_t type_expr, + spl_scope_id_t scope, spl_def_id_t agg_def) { + spl_type_id_t t = type_expr ? resolve_type_expr(sema, type_expr) : 0; + spl_def_id_t def = new_var_def(sema, name, t, scope); + if (!spl_sema_scope_insert(sema, scope, name, def)) + sema_error(sema, 0, "duplicate symbol"); + if (agg_def) + agg_add_member(sema, agg_def, name, t, scope); +} + +static void sema_var_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t scope, + spl_def_id_t agg_def) { + spl_ast_node_t *n = node_at(sema->ast, ref); + if (!n) + return; + register_binding(sema, n->var_decl.name, n->var_decl.type_expr, scope, agg_def); +} + +static void sema_const_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t scope, + spl_def_id_t agg_def) { + spl_ast_node_t *n = node_at(sema->ast, ref); + if (!n) + return; + register_binding(sema, n->const_decl.name, n->const_decl.type_expr, scope, agg_def); +} + +/* fn 声明:建 fn type + FN_PARAMS def + 登记名字。不建 fn_scope(由 check 新建)。 + * 形参只把 name/type 记入 fn_params_def(def_id=0),实际参数 def 在 check 时创建。 */ +static void sema_fn_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t scope, + spl_def_id_t agg_def) { + spl_ast_node_t *n = node_at(sema->ast, ref); + if (!n) + return; + spl_type_id_vec_t params; + vec_init(params); + for (usize i = 0; i < n->fn_decl.param_list.size; i++) { + spl_ast_node_t *pd = node_at(sema->ast, n->fn_decl.param_list.data[i]); + spl_type_id_t pt = 0; + if (pd && pd->param_decl.type_expr) + pt = resolve_type_expr(sema, pd->param_decl.type_expr); + vec_push(params, pt); + } + spl_type_id_t ret = 0; + if (n->fn_decl.type_expr) + ret = resolve_type_expr(sema, n->fn_decl.type_expr); + else + ret = spl_type_void(&sema->type); + spl_type_id_t fid = spl_type_fn(&sema->type, params, ret); + spl_def_id_t fdef = def_alloc(sema, SPL_DEF_FN_PARAMS); + spl_def_node_t *d = def_at(sema, fdef); + d->type_id = fid; + vec_init(d->fn_params_def); + for (usize i = 0; i < n->fn_decl.param_list.size; i++) { + spl_ast_node_t *pd = node_at(sema->ast, n->fn_decl.param_list.data[i]); + if (!pd) + continue; + spl_var_def_t pv = {pd->param_decl.name, 0, params.data[i], 0}; + vec_push(d->fn_params_def, pv); + } + if (!spl_sema_scope_insert(sema, scope, n->fn_decl.name, fdef)) + sema_error(sema, ref, "duplicate function name"); + if (agg_def) + agg_add_member(sema, agg_def, n->fn_decl.name, fid, scope); +} + +static void sema_type_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t scope, + spl_def_id_t agg_def) { + spl_ast_node_t *n = node_at(sema->ast, ref); + if (!n) + return; + spl_ast_node_t *te = node_at(sema->ast, n->type_decl.type_expr); + spl_type_id_t tid = 0; + spl_def_id_t def = 0; + if (te && + (te->type_expr.kind == SPL_AST_TYPE_STRUCT || te->type_expr.kind == SPL_AST_TYPE_UNION || + te->type_expr.kind == SPL_AST_TYPE_ENUM)) { + agg_handle_t h = agg_prepare(sema, n->type_decl.type_expr); + tid = h.tid; + def = h.def; + agg_resolve(sema, n->type_decl.type_expr, h.tid, h.def, scope, n->type_decl.name); + } else if (te) { + tid = resolve_type_expr(sema, n->type_decl.type_expr); + def = def_alloc(sema, SPL_DEF_ALIAS); + spl_def_node_t *d = def_at(sema, def); + d->type_id = tid; + d->type_def.name = n->type_decl.name; + d->type_def.def_id = def; + d->type_def.type_id = tid; + d->type_def.scope_id = scope; + } + if (!tid || !def) + return; + if (!spl_sema_scope_insert(sema, scope, n->type_decl.name, def)) + sema_error(sema, ref, "duplicate type name"); + if (agg_def) + agg_add_member(sema, agg_def, n->type_decl.name, tid, scope); + /* 嵌套类型提升到文件作用域:兄弟聚合可裸名引用(如 Lexer 方法内 Tag.eof) */ + if (agg_def) + spl_sema_scope_insert(sema, sema->root_scope, n->type_decl.name, def); +} + +/* ================================================================ + * 类型检查(阶段 B) + * ================================================================ */ + +static spl_type_id_t infer_expr(spl_sema_t *sema, spl_ast_node_ref_t ref); + +/* 类型节点快捷查询 */ +static spl_type_node_t *type_node(spl_sema_t *sema, spl_type_id_t tid) { + return spl_type_node(&sema->type, tid); +} + +static bool is_int_tid(spl_sema_t *sema, spl_type_id_t tid) { + spl_type_node_t *t = type_node(sema, tid); + return t && t->kind == SPL_TYPE_INT; +} + +static bool is_numeric_tid(spl_sema_t *sema, spl_type_id_t tid) { + spl_type_node_t *t = type_node(sema, tid); + return t && (t->kind == SPL_TYPE_INT || t->kind == SPL_TYPE_FLOAT); +} + +static bool is_agg_tid(spl_sema_t *sema, spl_type_id_t tid) { + spl_type_node_t *t = type_node(sema, tid); + return t && + (t->kind == SPL_TYPE_STRUCT || t->kind == SPL_TYPE_UNION || t->kind == SPL_TYPE_ENUM); +} + +/* 表达式是否为整数字面量(含一元负号) */ +static bool expr_is_int_literal(spl_sema_t *sema, spl_ast_node_ref_t ref) { + spl_ast_node_t *n = node_at(sema->ast, ref); + if (!n || n->kind != SPL_AST_EXPR) + return false; + switch (n->expr.op) { + case SPL_AST_PRIMARY_EXPR: { + spl_ast_node_t *pn = node_at(sema->ast, n->expr.op_expr.left); + int k = pn && pn->kind == SPL_AST_EXPR ? (int)pn->primary_expr.kind : -1; + return k == SPL_AST_INTEGER || k == SPL_AST_CHAR_LIT; + } + case SPL_AST_PREFIX_EXPR: + return expr_is_int_literal(sema, n->expr.op_expr.left); + default: + return false; + } +} + +/* 打开 SPL_TYPE_ID 绑定节点,返回真实类型(newtype 预留;当前无调用产生该节点) */ +static spl_type_id_t underlying(spl_sema_t *sema, spl_type_id_t tid) { + spl_type_node_t *t = type_node(sema, tid); + if (t && t->kind == SPL_TYPE_ID) + return t->type_id; + return tid; +} + +/* 结构递归相等:ptr/slice/array/fn 等构造类型按结构比较, + * 因为 spl_type_ptr/slice/array 不去重,相同结构可能有不同 id */ +static int type_same(spl_sema_t *sema, spl_type_id_t a, spl_type_id_t b) { + if (a == b) + return 1; + a = underlying(sema, a); + b = underlying(sema, b); + if (a == b) + return 1; + spl_type_node_t *na = type_node(sema, a); + spl_type_node_t *nb = type_node(sema, b); + if (!na || !nb || na->kind != nb->kind) + return 0; + switch (na->kind) { + case SPL_TYPE_INT: + return na->int_type.bits == nb->int_type.bits && + na->int_type.is_signed == nb->int_type.is_signed; + case SPL_TYPE_FLOAT: + return na->float_type.bits == nb->float_type.bits; + case SPL_TYPE_PTR: + return type_same(sema, na->ptr_pointee, nb->ptr_pointee); + case SPL_TYPE_SLICE: + return type_same(sema, na->slice_element, nb->slice_element); + case SPL_TYPE_RANGE: + return type_same(sema, na->range_element, nb->range_element); + case SPL_TYPE_ARRAY: + return na->array_type.len == nb->array_type.len && + type_same(sema, na->array_type.element, nb->array_type.element); + case SPL_TYPE_FN: { + if (na->fn_type.params.size != nb->fn_type.params.size) + return 0; + for (usize i = 0; i < na->fn_type.params.size; i++) + if (!type_same(sema, na->fn_type.params.data[i], nb->fn_type.params.data[i])) + return 0; + return type_same(sema, na->fn_type.ret, nb->fn_type.ret); + } + default: + return 0; + } +} + +/* 兼容性检查:src 可赋给 dst?is_literal 表示 src 是整数字面量 */ +/* 返回值:1 兼容,0 不兼容 */ +static int type_compatible(spl_sema_t *sema, spl_type_id_t dst, spl_type_id_t src, int is_literal, + int *warned) { + if (warned) + *warned = 0; + if (!dst || !src) + return 0; + dst = underlying(sema, dst); + src = underlying(sema, src); + spl_type_node_t *d = type_node(sema, dst); + spl_type_node_t *s = type_node(sema, src); + if (!d || !s) + return 0; + if (type_same(sema, dst, src)) + return 1; + /* 整数字面量可拓宽到目标整数 */ + if (is_literal && d->kind == SPL_TYPE_INT && s->kind == SPL_TYPE_INT) { + /* 字面量值已隐含满足范围(检查时由调用方保证),此处允许拓宽 */ + return 1; + } + /* isize/usize(机器字宽)与 i32 混合:比较/算术/传参可用(splc1 与旧测试事实标准) */ + if (d->kind == SPL_TYPE_INT && s->kind == SPL_TYPE_INT) { + int dbits = d->int_type.bits, sbits = s->int_type.bits; + int word = (int)(sizeof(usize) * 8); + if ((dbits == word && sbits == 32) || (dbits == 32 && sbits == word)) { + if (warned) + *warned = 1; + return 1; + } + } + /* 数组 [N]T -> 切片 []T */ + if (d->kind == SPL_TYPE_SLICE && s->kind == SPL_TYPE_ARRAY) { + if (d->slice_element == s->array_type.element) + return 1; + } + /* *T -> *_ 与 *_ -> *T(警告转换;*_ 即 *void) */ + if (d->kind == SPL_TYPE_PTR && s->kind == SPL_TYPE_PTR) { + spl_type_id_t void_t = spl_type_void(&sema->type); + if (d->ptr_pointee == void_t && s->ptr_pointee != void_t) { + if (warned) + *warned = 1; + return 1; + } + if (s->ptr_pointee == void_t && d->ptr_pointee != void_t) { + if (warned) + *warned = 1; + return 1; + } + /* *T -> *u8:字节指针视图(splc1 事实标准,如 vm_fwrite(buf:*u8, &x)) */ + spl_type_node_t *dtn = type_node(sema, d->ptr_pointee); + if (dtn && dtn->kind == SPL_TYPE_INT && dtn->int_type.bits == 8 && + dtn->int_type.is_signed == 0 && !type_same(sema, d->ptr_pointee, s->ptr_pointee)) { + if (warned) + *warned = 1; + return 1; + } + } + return 0; +} + +/* expr 是否为 null 字面量(不参与类型推导,需上下文) */ +static bool expr_is_null_literal(spl_sema_t *sema, spl_ast_node_ref_t ref) { + spl_ast_node_t *n = node_at(sema->ast, ref); + if (!n || n->kind != SPL_AST_EXPR) + return false; + if (n->expr.op == SPL_AST_PRIMARY_EXPR) + return expr_is_null_literal(sema, n->expr.op_expr.left); + return n->primary_expr.kind == SPL_AST_NULL; +} + +/* 二元算术/位运算:两侧类型一致,或整数字面量拓宽;含指针算术 *T + int */ +static spl_type_id_t infer_binary_arith(spl_sema_t *sema, spl_ast_node_ref_t ref, + spl_ast_node_t *e) { + spl_type_id_t l = infer_expr(sema, e->expr.op_expr.left); + spl_type_id_t r = infer_expr(sema, e->expr.op_expr.right); + if (!l || !r) { + sema_error(sema, ref, "bad operand in arithmetic"); + return 0; + } + l = underlying(sema, l); + r = underlying(sema, r); + /* 指针算术:*T + int / int + *T / *T - int → *T */ + if (e->expr.op == SPL_AST_ADD_EXPR || e->expr.op == SPL_AST_SUB_EXPR) { + spl_type_node_t *lt = type_node(sema, l); + spl_type_node_t *rt = type_node(sema, r); + if (lt && lt->kind == SPL_TYPE_PTR && rt && is_int_tid(sema, r)) + return l; + if (rt && rt->kind == SPL_TYPE_PTR && lt && is_int_tid(sema, l) && + e->expr.op == SPL_AST_ADD_EXPR) + return r; + } + if (l == r) { + if (!is_numeric_tid(sema, l)) { + sema_error(sema, ref, "arithmetic requires numeric operands"); + return 0; + } + return l; + } + int ll = expr_is_int_literal(sema, e->expr.op_expr.left); + int rl = expr_is_int_literal(sema, e->expr.op_expr.right); + if (ll && is_int_tid(sema, r)) { + int w = 0; + if (type_compatible(sema, r, l, 1, &w)) + return r; + } + if (rl && is_int_tid(sema, l)) { + int w = 0; + if (type_compatible(sema, l, r, 1, &w)) + return l; + } + /* isize/usize 与 i32 混合算术:结果取左操作数类型 */ + if (is_int_tid(sema, l) && is_int_tid(sema, r)) { + int w = 0; + if (type_compatible(sema, l, r, 0, &w)) + return l; + } + sema_error(sema, ref, "type mismatch in arithmetic"); + return 0; +} + +/* 比较运算:兼容则返回 bool */ +static spl_type_id_t infer_binary_cmp(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *e) { + spl_type_id_t l = infer_expr(sema, e->expr.op_expr.left); + spl_type_id_t r = infer_expr(sema, e->expr.op_expr.right); + /* null 与指针比较合法 */ + if (expr_is_null_literal(sema, e->expr.op_expr.left)) { + if (r && type_node(sema, underlying(sema, r))->kind == SPL_TYPE_PTR) + return spl_type_bool(&sema->type); + sema_error(sema, ref, "null can only compare with pointers"); + return 0; + } + if (expr_is_null_literal(sema, e->expr.op_expr.right)) { + if (l && type_node(sema, underlying(sema, l))->kind == SPL_TYPE_PTR) + return spl_type_bool(&sema->type); + sema_error(sema, ref, "null can only compare with pointers"); + return 0; + } + if (!l || !r) { + sema_error(sema, ref, "bad operand in comparison"); + return 0; + } + int w = 0; + if (type_compatible(sema, l, r, expr_is_int_literal(sema, e->expr.op_expr.right), &w) || + type_compatible(sema, r, l, expr_is_int_literal(sema, e->expr.op_expr.left), &w)) { + return spl_type_bool(&sema->type); + } + sema_error(sema, ref, "type mismatch in comparison"); + return 0; +} + +/* 逻辑运算:两侧 bool */ +static spl_type_id_t infer_binary_logic(spl_sema_t *sema, spl_ast_node_ref_t ref, + spl_ast_node_t *e) { + spl_type_id_t l = infer_expr(sema, e->expr.op_expr.left); + spl_type_id_t r = infer_expr(sema, e->expr.op_expr.right); + if (underlying(sema, l) != underlying(sema, spl_type_bool(&sema->type)) || + underlying(sema, r) != underlying(sema, spl_type_bool(&sema->type))) { + sema_error(sema, ref, "logical operators require bool operands"); + return 0; + } + return spl_type_bool(&sema->type); +} + +/* 位运算:两侧整数同型或字面量拓宽 */ +static spl_type_id_t infer_binary_bit(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *e) { + spl_type_id_t l = infer_expr(sema, e->expr.op_expr.left); + spl_type_id_t r = infer_expr(sema, e->expr.op_expr.right); + if (!l || !r) { + sema_error(sema, ref, "bad operand in bitwise"); + return 0; + } + l = underlying(sema, l); + r = underlying(sema, r); + if (l == r) { + if (!is_int_tid(sema, l)) { + sema_error(sema, ref, "bitwise requires integer operands"); + return 0; + } + return l; + } + int ll = expr_is_int_literal(sema, e->expr.op_expr.left); + int rl = expr_is_int_literal(sema, e->expr.op_expr.right); + if (ll && is_int_tid(sema, r)) + return r; + if (rl && is_int_tid(sema, l)) + return l; + sema_error(sema, ref, "type mismatch in bitwise"); + return 0; +} + +static spl_type_id_t infer_binary(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *e) { + switch (e->expr.op) { + case SPL_AST_ADD_EXPR: + case SPL_AST_SUB_EXPR: + case SPL_AST_MUL_EXPR: + case SPL_AST_DIV_EXPR: + case SPL_AST_MOD_EXPR: + return infer_binary_arith(sema, ref, e); + case SPL_AST_CMPEQ_EXPR: + case SPL_AST_CMPNE_EXPR: + case SPL_AST_CMP_LE_EXPR: + case SPL_AST_CMP_GE_EXPR: + case SPL_AST_CMP_LT_EXPR: + case SPL_AST_CMP_GT_EXPR: + return infer_binary_cmp(sema, ref, e); + case SPL_AST_BOOLOR_EXPR: + case SPL_AST_BOOLAND_EXPR: + return infer_binary_logic(sema, ref, e); + case SPL_AST_BITOR_EXPR: + case SPL_AST_BITXOR_EXPR: + case SPL_AST_BITAND_EXPR: + case SPL_AST_LSHIFT_EXPR: + case SPL_AST_RSHIFT_EXPR: + return infer_binary_bit(sema, ref, e); + default: + return 0; + } +} + +/* 聚合初始化字面量:目标类型已知时校验字段 */ +static spl_type_id_t infer_agg_init(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *n) { + spl_ast_node_t *pn = n->kind == SPL_AST_EXPR ? node_at(sema->ast, n->expr.op_expr.left) : n; + if (!pn || pn->primary_expr.kind != SPL_AST_ARGGREGATE_INIT) + return 0; + spl_type_id_t tid = 0; + if (pn->primary_expr.aggregate_init.name) { + tid = find_type(sema, pn->primary_expr.aggregate_init.name); + if (!tid) { + sema_error(sema, ref, "unknown aggregate type in literal"); + return 0; + } + } else { + /* 匿名 .{} 依赖上下文,由调用方(赋值/初始化)填充 */ + return 0; + } + spl_type_node_t *tn = type_node(sema, tid); + if (!tn || !is_agg_tid(sema, tid)) { + sema_error(sema, ref, "aggregate literal target is not a struct/union/enum"); + return 0; + } + /* 枚举无载荷初始化如 Color { .Red }:仅一个成员且为变体 */ + if (tn->kind == SPL_TYPE_ENUM) { + usize nitems = + n->kind == SPL_AST_EXPR + ? node_at(sema->ast, n->expr.op_expr.left)->primary_expr.aggregate_init.expr.size + : pn->primary_expr.aggregate_init.expr.size; + for (usize i = 0; i < nitems; i++) { + spl_ast_node_ref_t iref = + (n->kind == SPL_AST_EXPR + ? node_at(sema->ast, n->expr.op_expr.left)->primary_expr.aggregate_init.expr + : pn->primary_expr.aggregate_init.expr) + .data[i]; + spl_ast_node_t *item = node_at(sema->ast, iref); + if (!item) + continue; + spl_type_id_t mt = agg_member_type(sema, tid, item->aggregate_init_item.ident); + if (!mt) { + sema_error(sema, iref, "unknown variant in enum literal"); + continue; + } + if (item->aggregate_init_item.expr) + infer_expr(sema, item->aggregate_init_item.expr); + } + return tid; + } + /* struct/union:逐字段校验 */ + for (usize i = 0; + i < (n->kind == SPL_AST_EXPR + ? node_at(sema->ast, n->expr.op_expr.left)->primary_expr.aggregate_init.expr.size + : pn->primary_expr.aggregate_init.expr.size); + i++) { + spl_ast_node_ref_t iref = + (n->kind == SPL_AST_EXPR + ? node_at(sema->ast, n->expr.op_expr.left)->primary_expr.aggregate_init.expr + : pn->primary_expr.aggregate_init.expr) + .data[i]; + spl_ast_node_t *item = node_at(sema->ast, iref); + if (!item) + continue; + spl_type_id_t mt = agg_member_type(sema, tid, item->aggregate_init_item.ident); + if (!mt) { + sema_error(sema, iref, "unknown field in aggregate literal"); + continue; + } + if (item->aggregate_init_item.expr) { + spl_type_id_t et = infer_expr(sema, item->aggregate_init_item.expr); + int w = 0; + if (!expr_is_null_literal(sema, item->aggregate_init_item.expr) && et && + !type_compatible(sema, mt, et, + expr_is_int_literal(sema, item->aggregate_init_item.expr), &w)) { + sema_error(sema, iref, "field type mismatch in aggregate literal"); + } + } + } + return tid; +} + +/* 数组字面量 [N]T{...} */ +static spl_type_id_t infer_array_lit(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *n) { + spl_ast_node_t *pn = n->kind == SPL_AST_EXPR ? node_at(sema->ast, n->expr.op_expr.left) : n; + spl_type_id_t elem = 0; + if (pn->primary_expr.array_lit_expr.type_expr) { + elem = resolve_type_expr(sema, pn->primary_expr.array_lit_expr.type_expr); + if (!elem) + sema_error(sema, ref, "bad array literal element type"); + } + for (usize i = 0; i < pn->primary_expr.array_lit_expr.expr_list.size; i++) { + spl_type_id_t et = infer_expr(sema, pn->primary_expr.array_lit_expr.expr_list.data[i]); + if (elem) { + int w = 0; + if (!type_compatible( + sema, elem, et, + expr_is_int_literal(sema, pn->primary_expr.array_lit_expr.expr_list.data[i]), + &w)) { + sema_error(sema, pn->primary_expr.array_lit_expr.expr_list.data[i], + "element type mismatch in array literal"); + } + } + } + return spl_type_array(&sema->type, elem ? elem : 0, + (usize)pn->primary_expr.array_lit_expr.integer); +} + +/* 标识符:scope 查找(def → 类型) */ +static spl_type_id_t infer_ident(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *n) { + spl_ast_node_t *pn = n->kind == SPL_AST_EXPR ? node_at(sema->ast, n->expr.op_expr.left) : n; + spl_type_id_t t = find_type(sema, pn->primary_expr.ident); + if (!t) { + sema_error(sema, ref, "undefined identifier"); + return 0; + } + return t; +} + +static spl_type_id_t infer_postfix(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *n); +static spl_type_id_t infer_prefix(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *n); +static void check_stmt(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_sema_ctx_t ctx); + +static spl_type_id_t infer_primary(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *n) { + spl_ast_node_t *pn = n->kind == SPL_AST_EXPR ? node_at(sema->ast, n->expr.op_expr.left) : n; + if (!pn) { + sema_error(sema, ref, "invalid primary expression"); + return 0; + } + switch (pn->primary_expr.kind) { + case SPL_AST_INTEGER: + return spl_type_int(&sema->type, 32, 1); + case SPL_AST_FLOAT: + return spl_type_float(&sema->type, 64); + case SPL_AST_CHAR_LIT: + /* 字符字面量即字节立即数(u8),经字面量宽化可赋给任意整数类型 */ + return spl_type_int(&sema->type, 8, 0); + case SPL_AST_STRING_LIT: + /* 字符串字面量:底层为 *u8(NUL 终止)。splc1 自举源中一律传 *u8, + * SPL.md 建议 []u8,但 IR 层按 *u8 处理,此处与实现一致 */ + return spl_type_ptr(&sema->type, spl_type_int(&sema->type, 8, 0)); + case SPL_AST_TRUE: + case SPL_AST_FALSE: + return spl_type_bool(&sema->type); + case SPL_AST_NULL: + return 0; /* null 无独立类型,需上下文 */ + case SPL_AST_IDENT: + return infer_ident(sema, ref, n); + case SPL_AST_ARGGREGATE_INIT: + return infer_agg_init(sema, ref, n); + case SPL_AST_EXPR_EXPR: + return infer_expr(sema, pn->primary_expr.expr); + case SPL_AST_ARRAY_LIT: + return infer_array_lit(sema, ref, n); + case SPL_AST_BUILTIN_EXPR: + /* 内置调用:先推断实参,类型按名称约定 */ + for (usize i = 0; i < pn->primary_expr.builtin_expr.expr_list.size; i++) + infer_expr(sema, pn->primary_expr.builtin_expr.expr_list.data[i]); + if (strcmp(pn->primary_expr.builtin_expr.ident, "sizeof") == 0) + return spl_type_int(&sema->type, sizeof(usize) * 8, 0); + if (strcmp(pn->primary_expr.builtin_expr.ident, "dbg") == 0 || + strcmp(pn->primary_expr.builtin_expr.ident, "assert") == 0) + return spl_type_void(&sema->type); + return spl_type_void(&sema->type); + case SPL_AST_BLOCK_EXPR: { + /* 块表达式:有独立 scope;逐语句检查,返回末尾表达式类型(无则 void) */ + spl_ast_node_ref_vec_t *items = &pn->primary_expr.block_expr; + spl_scope_id_t scope = spl_sema_scope_alloc(sema); + sema->scopes.data[scope].parent = sema->current_scope; + spl_scope_id_t save = sema->current_scope; + sema->current_scope = scope; + spl_type_id_t rt = spl_type_void(&sema->type); + spl_sema_ctx_t vctx = {0}; /* 表达式块内的 ret 暂不强制(罕见) */ + for (usize i = 0; i < items->size; i++) { + if (i + 1 == items->size) { + spl_ast_node_t *last = node_at(sema->ast, items->data[i]); + if (last && last->kind == SPL_AST_EXPR && + !(last->expr.op == SPL_AST_PRIMARY_EXPR)) { + rt = infer_expr(sema, items->data[i]); + continue; + } + if (last && last->expr.op == SPL_AST_PRIMARY_EXPR) { + spl_ast_node_t *in = node_at(sema->ast, last->expr.op_expr.left); + if (in && in->primary_expr.kind == SPL_AST_BLOCK_EXPR) { + rt = infer_primary(sema, items->data[i], last); + continue; + } + } + } + check_stmt(sema, items->data[i], vctx); + } + sema->current_scope = save; + return rt; + } + default: + return 0; + } +} + +/* 前缀运算 */ +static spl_type_id_t infer_prefix(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *n) { + spl_ast_node_t *pf = n->kind == SPL_AST_EXPR ? node_at(sema->ast, n->expr.op_expr.left) : n; + if (!pf) + return 0; + spl_type_id_t inner = infer_expr(sema, pf->prefix_expr.postfix_expr); + if (!inner) + return 0; + inner = underlying(sema, inner); + switch (pf->prefix_expr.kind) { + case SPL_AST_MINUS_EXPR: + if (!is_numeric_tid(sema, inner)) { + sema_error(sema, ref, "unary minus requires numeric"); + return 0; + } + return inner; + case SPL_AST_BANG_EXPR: + if (inner != underlying(sema, spl_type_bool(&sema->type))) { + sema_error(sema, ref, "! requires bool"); + return 0; + } + return spl_type_bool(&sema->type); + case SPL_AST_TILDE_EXPR: + if (!is_int_tid(sema, inner)) { + sema_error(sema, ref, "~ requires integer"); + return 0; + } + return inner; + case SPL_AST_AMPERSAND_EXPR: + if (type_node(sema, inner) && type_node(sema, inner)->kind == SPL_TYPE_FN) + return inner; /* &foo 为函数值(fn 类型),非常规指针 */ + return spl_type_ptr(&sema->type, inner); + case SPL_AST_ASTERISK_EXPR: + /* 前缀 * 不在 SPL 中使用(解引用为后缀 .*),忽略 */ + return inner; + default: + return 0; + } +} + +/* 后缀运算 */ +static spl_type_id_t infer_postfix(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *n) { + spl_ast_node_t *pf = n->kind == SPL_AST_EXPR ? node_at(sema->ast, n->expr.op_expr.left) : n; + if (!pf) + return 0; + spl_type_id_t base = infer_expr(sema, pf->postfix_expr.primary_expr); + if (!base) + return 0; + base = underlying(sema, base); + switch (pf->postfix_expr.kind) { + case SPL_AST_FIELD_EXPR: { + spl_type_node_t *t = type_node(sema, base); + /* 指针自动解引用一层 */ + if (t && t->kind == SPL_TYPE_PTR) + base = underlying(sema, t->ptr_pointee); + t = type_node(sema, base); + if (!t) { + sema_error(sema, ref, "field access on non-aggregate"); + return 0; + } + /* 切片字段 len/ptr 优先于聚合检查 */ + if (t->kind == SPL_TYPE_SLICE) { + if (strcmp(pf->postfix_expr.field_expr, "len") == 0) + return spl_type_int(&sema->type, sizeof(usize) * 8, 0); + if (strcmp(pf->postfix_expr.field_expr, "ptr") == 0) + return spl_type_ptr(&sema->type, t->slice_element); + sema_error(sema, ref, "unknown slice field"); + return 0; + } + /* Range 内置字段 begin/end:元素类型 */ + if (t->kind == SPL_TYPE_RANGE) { + if (strcmp(pf->postfix_expr.field_expr, "begin") == 0 || + strcmp(pf->postfix_expr.field_expr, "end") == 0) + return t->range_element; + sema_error(sema, ref, "unknown range field"); + return 0; + } + if (!is_agg_tid(sema, base)) { + sema_error(sema, ref, "field access on non-aggregate"); + return 0; + } + spl_type_id_t mt = agg_member_type(sema, base, pf->postfix_expr.field_expr); + if (!mt) { + sema_error(sema, ref, "unknown field"); + return 0; + } + /* 枚举变体表达式:带载荷变体(payload 为 struct/整数)整体值为枚举类型; + * 方法(fn)/嵌套类型/无载荷固标保持 member 类型 */ + spl_type_node_t *mtt = mt ? type_node(sema, underlying(sema, mt)) : NULL; + if (t && t->kind == SPL_TYPE_ENUM && mtt && + (mtt->kind == SPL_TYPE_STRUCT || mtt->kind == SPL_TYPE_INT)) + return base; + return mt; + } + case SPL_AST_DEREF_EXPR: { + spl_type_node_t *t = type_node(sema, base); + if (!t || t->kind != SPL_TYPE_PTR) { + sema_error(sema, ref, ".* requires pointer"); + return 0; + } + /* *_(即 *void)类型已丢失,不可解引用,须先转换为具体指针 */ + spl_type_id_t pt = underlying(sema, t->ptr_pointee); + spl_type_node_t *ptn = type_node(sema, pt); + if (ptn && ptn->kind == SPL_TYPE_VOID) { + sema_error(sema, ref, "cannot dereference `*_`; cast to a concrete pointer first"); + return 0; + } + return underlying(sema, t->ptr_pointee); + } + case SPL_AST_INDEX_EXPR: { + spl_type_node_t *t = type_node(sema, base); + spl_type_id_t idx = infer_expr(sema, pf->postfix_expr.index_expr); + t = type_node(sema, base); + if (!is_int_tid(sema, underlying(sema, idx))) { + sema_error(sema, ref, "index requires integer"); + return 0; + } + if (t && t->kind == SPL_TYPE_ARRAY) + return t->array_type.element; + if (t && t->kind == SPL_TYPE_SLICE) + return t->slice_element; + if (t && t->kind == SPL_TYPE_PTR) + return underlying(sema, t->ptr_pointee); + sema_error(sema, ref, "index requires array/slice/pointer"); + return 0; + } + case SPL_AST_SLICE_EXPR: { + spl_type_node_t *t = type_node(sema, base); + if (pf->postfix_expr.slice_expr.begin) + infer_expr(sema, pf->postfix_expr.slice_expr.begin); + if (pf->postfix_expr.slice_expr.end) + infer_expr(sema, pf->postfix_expr.slice_expr.end); + t = type_node(sema, base); + if (t && t->kind == SPL_TYPE_ARRAY) + return spl_type_slice(&sema->type, t->array_type.element); + if (t && t->kind == SPL_TYPE_SLICE) + return spl_type_slice(&sema->type, t->slice_element); + sema_error(sema, ref, "slice requires array/slice"); + return 0; + } + case SPL_AST_CALL_EXPR: { + spl_type_node_t *t = type_node(sema, base); + if (!t || t->kind != SPL_TYPE_FN) { + sema_error(sema, ref, "call requires function type"); + return 0; + } + spl_ast_node_ref_vec_t *args = &pf->postfix_expr.call_expr; + /* 变参 fn(如 vm_printf)最后一个形参 name=NULL 且类型可为 0 */ + /* 注意:infer_expr 可能新分配类型使 type_table realloc,t 会失效,须每次刷新 */ + usize nparams = t->fn_type.params.size; + for (usize i = 0; i < args->size; i++) { + spl_type_id_t at = infer_expr(sema, args->data[i]); + t = type_node(sema, base); + if (i < nparams && t && t->fn_type.params.data[i]) { + int w = 0; + if (!expr_is_null_literal(sema, args->data[i]) && at && + !type_compatible(sema, t->fn_type.params.data[i], at, + expr_is_int_literal(sema, args->data[i]), &w)) { + sema_error(sema, args->data[i], "argument type mismatch"); + } + } + } + t = type_node(sema, base); + return t ? t->fn_type.ret : 0; + } + case SPL_AST_AS_EXPR: { + spl_type_id_t st = infer_expr(sema, pf->postfix_expr.primary_expr); + if (!st) + return 0; + spl_type_id_t dt = 0; + if (pf->postfix_expr.type_expr) { + /* 未知类型已由 resolve_type_atom 报错,此处不重复报"缺目标类型" */ + dt = resolve_type_expr(sema, pf->postfix_expr.type_expr); + } else { + sema_error(sema, ref, "as requires a target type"); + } + if (!dt) + return 0; + return dt; + } + default: + return 0; + } +} + +/* 表达式类型推断 */ +static spl_type_id_t infer_expr(spl_sema_t *sema, spl_ast_node_ref_t ref) { + if (!ref) + return 0; + spl_ast_node_t *n = node_at(sema->ast, ref); + if (!n) + return 0; + spl_type_id_t tid = 0; + if (n->kind == SPL_AST_EXPR) { + switch (n->expr.op) { + case SPL_AST_PRIMARY_EXPR: + tid = infer_primary(sema, ref, n); + break; + case SPL_AST_PREFIX_EXPR: + tid = infer_prefix(sema, ref, n); + break; + case SPL_AST_POSTFIX_EXPR: + tid = infer_postfix(sema, ref, n); + break; + case SPL_AST_RANGE_EXPR: { + spl_type_id_t l = 0, r = 0; + if (n->expr.op_expr.left) + l = underlying(sema, infer_expr(sema, n->expr.op_expr.left)); + if (n->expr.op_expr.right) + r = underlying(sema, infer_expr(sema, n->expr.op_expr.right)); + if ((l && !is_int_tid(sema, l)) || (r && !is_int_tid(sema, r)) || (!l && !r)) { + sema_error(sema, ref, "range bounds must be integers"); + return 0; + } + return spl_type_range(&sema->type, r ? r : l); + } + case SPL_AST_ASSIGN_EXPR: + case SPL_AST_ASSIGN_ADD_EXPR: + case SPL_AST_ASSIGN_sUB_EXPR: + case SPL_AST_ASSIGN_MUL_EXPR: + case SPL_AST_ASSIGN_DIV_EXPR: + case SPL_AST_ASSIGN_MOD_EXPR: + case SPL_AST_ASSIGN_AND_EXPR: + case SPL_AST_ASSIGN_OR_EXPR: + case SPL_AST_ASSIGN_XOR_EXPR: + case SPL_AST_ASSIGN_LSHIFT_EXPR: + case SPL_AST_ASSIGN_USHIFT_EXPR: { + spl_type_id_t l = infer_expr(sema, n->expr.op_expr.left); + spl_type_id_t r = infer_expr(sema, n->expr.op_expr.right); + if (!l || (!r && !expr_is_null_literal(sema, n->expr.op_expr.right))) { + sema_error(sema, ref, "bad assignment"); + return 0; + } + int w = 0; + if (!expr_is_null_literal(sema, n->expr.op_expr.right) && + !type_compatible(sema, l, r, expr_is_int_literal(sema, n->expr.op_expr.right), + &w)) { + sema_error(sema, ref, "assignment type mismatch"); + return 0; + } + return l; + } + default: + tid = infer_binary(sema, ref, n); + break; + } + } + return tid; +} + +/* ---- 语句类型检查 ---- */ + +static void check_stmt(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_sema_ctx_t ctx); +static void check_block(spl_sema_t *sema, spl_ast_node_ref_vec_t *block, spl_scope_id_t parent, + spl_sema_ctx_t ctx); +static spl_type_id_t infer_agg_init_with_type(spl_sema_t *sema, spl_ast_node_ref_t ref, + spl_type_id_t expect); + +/* var/const 初始化与类型注解兼容性检查;name 用于 `var x := e` 推导类型回写 */ +static void check_var_init(spl_sema_t *sema, spl_ast_node_ref_t ref, const char *name, + spl_ast_node_ref_t type_expr, spl_ast_node_ref_t init_expr, + spl_sema_ctx_t ctx) { + (void)ctx; + (void)type_expr; + /* dt 取自已登记 def 的类型(check_block 已预登记),避免二次解析重复报错 */ + spl_type_id_t dt = 0; + if (name) { + spl_scope_id_t cur = sema->current_scope; + while (cur) { + spl_def_id_t val = 0; + if (map_get(sema->scopes.data[cur].symbols, name, &val)) { + dt = def_type(sema, val); + break; + } + cur = sema->scopes.data[cur].parent; + } + } + spl_type_id_t it = 0; + if (init_expr) { + it = infer_expr(sema, init_expr); + if (!it && !expr_is_null_literal(sema, init_expr)) { + /* 匿名聚合依赖上下文类型 */ + spl_ast_node_t *in = node_at(sema->ast, init_expr); + if (in && in->kind == SPL_AST_EXPR && in->expr.op == SPL_AST_PRIMARY_EXPR) { + spl_ast_node_t *pn = node_at(sema->ast, in->expr.op_expr.left); + if (pn && pn->primary_expr.kind == SPL_AST_ARGGREGATE_INIT && dt) { + spl_type_id_t save_scope = sema->current_scope; + it = infer_agg_init_with_type(sema, init_expr, dt); + sema->current_scope = save_scope; + } + } + } + if (dt) { + int w = 0; + if (!expr_is_null_literal(sema, init_expr) && it && + !type_compatible(sema, dt, it, expr_is_int_literal(sema, init_expr), &w)) { + sema_error(sema, ref, "initializer type mismatch"); + } else if (w) { + sema_warn(sema, ref, "pointer conversion involves wildcard"); + } + } else if (it && name) { + /* `var x := e` 推导类型回写 binding def */ + spl_scope_id_t cur = sema->current_scope; + while (cur) { + spl_def_id_t val = 0; + if (map_get(sema->scopes.data[cur].symbols, name, &val)) { + spl_def_node_t *d = def_at(sema, val); + if (d && d->kind == SPL_DEF_VAR) { + d->type_id = it; + d->var_def.type_id = it; + } + break; + } + cur = sema->scopes.data[cur].parent; + } + } + } +} + +/* 带期望类型的匿名聚合推断 */ +static spl_type_id_t infer_agg_init_with_type(spl_sema_t *sema, spl_ast_node_ref_t ref, + spl_type_id_t expect) { + spl_ast_node_t *n = node_at(sema->ast, ref); + spl_ast_node_t *pn = n->kind == SPL_AST_EXPR ? node_at(sema->ast, n->expr.op_expr.left) : n; + if (!pn || pn->primary_expr.kind != SPL_AST_ARGGREGATE_INIT) + return 0; + spl_type_id_t tid = underlying(sema, expect); + if (!type_node(sema, tid)) + return 0; + for (usize i = 0; i < pn->primary_expr.aggregate_init.expr.size; i++) { + spl_ast_node_ref_t iref = pn->primary_expr.aggregate_init.expr.data[i]; + spl_ast_node_t *item = node_at(sema->ast, iref); + if (!item) + continue; + spl_type_node_t *tn = type_node(sema, tid); + spl_type_id_t mt = 0; + /* 切片 {} 字面量支持 .ptr/.len */ + if (tn->kind == SPL_TYPE_SLICE) { + if (strcmp(item->aggregate_init_item.ident, "ptr") == 0) + mt = spl_type_ptr(&sema->type, tn->slice_element); + else if (strcmp(item->aggregate_init_item.ident, "len") == 0) + mt = spl_type_int(&sema->type, sizeof(usize) * 8, 0); + else { + sema_error(sema, iref, "unknown field in slice literal"); + continue; + } + } else if (is_agg_tid(sema, tid)) { + mt = agg_member_type(sema, tid, item->aggregate_init_item.ident); + if (!mt) { + sema_error(sema, iref, "unknown field in aggregate literal"); + continue; + } + } else { + sema_error(sema, iref, "literal target not an aggregate"); + continue; + } + if (item->aggregate_init_item.expr) { + spl_type_id_t et = infer_expr(sema, item->aggregate_init_item.expr); + int w = 0; + if (!expr_is_null_literal(sema, item->aggregate_init_item.expr) && et && + !type_compatible(sema, mt, et, + expr_is_int_literal(sema, item->aggregate_init_item.expr), &w)) { + sema_error(sema, iref, "field type mismatch in aggregate literal"); + } + } + } + return tid; +} + +/* for 循环:序列类型 Range/[]T/[N]T,变量个数匹配 */ +static void check_for(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *b, + spl_sema_ctx_t ctx) { + spl_ast_node_ref_vec_t *expr_vec = &b->block_item.for_statement.expr_vec; + char **id_data = b->block_item.for_statement.ident_vec.data; + usize id_size = b->block_item.for_statement.ident_vec.size; + if (expr_vec->size != id_size) { + sema_error(sema, ref, "for: sequence/variable count mismatch"); + return; + } + spl_scope_id_t scope = spl_sema_scope_alloc(sema); + sema->scopes.data[scope].parent = sema->current_scope; + spl_scope_id_t save = sema->current_scope; + sema->current_scope = scope; + for (usize i = 0; i < expr_vec->size; i++) { + spl_type_id_t et = infer_expr(sema, expr_vec->data[i]); + et = underlying(sema, et); + spl_type_node_t *t = type_node(sema, et); + spl_type_id_t elem = 0; + if (t && t->kind == SPL_TYPE_SLICE) + elem = t->slice_element; + else if (t && t->kind == SPL_TYPE_ARRAY) + elem = t->array_type.element; + else if (t && t->kind == SPL_TYPE_RANGE) + /* Range 遍历绑定元素类型(0..n 通常为 usize 索引遍历) */ + elem = t->range_element; + else { + sema_error(sema, expr_vec->data[i], "for: sequence must be Range/[]T/[N]T"); + continue; + } + spl_def_id_t vdef = new_var_def(sema, id_data[i], elem, scope); + spl_sema_scope_insert(sema, scope, id_data[i], vdef); + } + check_block(sema, &b->block_item.for_statement.block, scope, ctx); + sema->current_scope = save; +} + +/* match:被匹配表达式须为枚举/union;臂体类型一致性本轮简化为逐臂检查 */ +static void check_match(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *b, + spl_sema_ctx_t ctx) { + spl_type_id_t mtype = infer_expr(sema, b->block_item.match_statement.expr); + mtype = underlying(sema, mtype); + spl_type_node_t *t = type_node(sema, mtype); + /* 指针自动解引用 */ + if (t && t->kind == SPL_TYPE_PTR) + mtype = underlying(sema, t->ptr_pointee); + t = type_node(sema, mtype); + if (t && t->kind != SPL_TYPE_ENUM && t->kind != SPL_TYPE_UNION && !is_int_tid(sema, mtype)) { + sema_error(sema, b->block_item.match_statement.expr, + "match subject must be enum/union/integer"); + } + spl_ast_node_ref_vec_t *arms = &b->block_item.match_statement.paced_exprs; + spl_ast_node_ref_vec_t *bodies = &b->block_item.match_statement.match_block; + if (arms->size != bodies->size) { + sema_error(sema, ref, "match: arm pattern/body count mismatch"); + return; + } + for (usize i = 0; i < arms->size; i++) { + spl_ast_node_t *pk = node_at(sema->ast, arms->data[i]); + if (!pk) + continue; + /* 每个臂体是 BLOCK_EXPR,有自己的 scope */ + spl_scope_id_t scope = spl_sema_scope_alloc(sema); + sema->scopes.data[scope].parent = sema->current_scope; + spl_scope_id_t save = sema->current_scope; + sema->current_scope = scope; + if (pk->packed_expr.ident) { + /* 变体模式:若带绑定则登记绑定变量 */ + if (is_agg_tid(sema, mtype) && pk->packed_expr.bind_ident) { + spl_type_id_t vt = agg_member_type(sema, mtype, pk->packed_expr.ident); + if (vt && vt != mtype) { + spl_def_id_t vdef = new_var_def(sema, pk->packed_expr.bind_ident, vt, scope); + spl_sema_scope_insert(sema, scope, pk->packed_expr.bind_ident, vdef); + } + } else if (is_agg_tid(sema, mtype)) { + if (!agg_member_type(sema, mtype, pk->packed_expr.ident)) + sema_error(sema, arms->data[i], "unknown variant in match arm"); + } + } else if (pk->packed_expr.expr) { + spl_type_id_t et = infer_expr(sema, pk->packed_expr.expr); + int w = 0; + if (is_int_tid(sema, mtype) && et && + !type_compatible(sema, mtype, et, expr_is_int_literal(sema, pk->packed_expr.expr), + &w)) { + sema_error(sema, pk->packed_expr.expr, "match arm pattern type mismatch"); + } + } + /* 检查臂体 */ + spl_ast_node_t *body = node_at(sema->ast, bodies->data[i]); + if (body && body->kind == SPL_AST_EXPR && body->expr.op == SPL_AST_PRIMARY_EXPR) { + spl_ast_node_t *pn = node_at(sema->ast, body->expr.op_expr.left); + if (pn && pn->primary_expr.kind == SPL_AST_BLOCK_EXPR) { + check_block(sema, &pn->primary_expr.block_expr, scope, ctx); + } else { + infer_expr(sema, bodies->data[i]); + } + } + sema->current_scope = save; + } +} + +/* 单个语句检查 */ +static void check_stmt(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_sema_ctx_t ctx) { + spl_ast_node_t *b = node_at(sema->ast, ref); + if (!b) + return; + if (b->kind == SPL_AST_EXPR) { + /* 裸 { } 块作为语句:不产生值,仅检查其内部 */ + if (b->expr.op == SPL_AST_PRIMARY_EXPR) { + spl_ast_node_t *pn = node_at(sema->ast, b->expr.op_expr.left); + if (pn && pn->primary_expr.kind == SPL_AST_BLOCK_EXPR) { + check_block(sema, &pn->primary_expr.block_expr, sema->current_scope, ctx); + return; + } + } + infer_expr(sema, ref); + return; + } + switch (b->block_item.kind) { + case SPL_AST_VARDECL: { + spl_ast_node_t *vd = node_at(sema->ast, b->block_item.var_decl); + if (vd) + check_var_init(sema, b->block_item.var_decl, vd->var_decl.name, vd->var_decl.type_expr, + vd->var_decl.expr, ctx); + break; + } + case SPL_AST_CONSTDECL: { + spl_ast_node_t *cd = node_at(sema->ast, b->block_item.const_decl); + if (cd) + check_var_init(sema, b->block_item.const_decl, cd->const_decl.name, + cd->const_decl.type_expr, cd->const_decl.expr, ctx); + break; + } + case SPL_AST_TYPEDECL: + break; + case SPL_AST_IF_STATEMENT: { + spl_type_id_t c = infer_expr(sema, b->block_item.if_statement.expr); + c = underlying(sema, c); + if (c && c != underlying(sema, spl_type_bool(&sema->type))) + sema_error(sema, b->block_item.if_statement.expr, "if condition must be bool"); + spl_scope_id_t sc = sema->current_scope; + check_block(sema, &b->block_item.if_statement.if_block, sc, ctx); + if (b->block_item.if_statement.else_block.size) + check_block(sema, &b->block_item.if_statement.else_block, sc, ctx); + break; + } + case SPL_AST_IFVAR_STATEMENT: { + spl_ast_node_t *pk = node_at(sema->ast, b->block_item.ifvar_statement.packed_expr); + spl_type_id_t vt = 0; + if (pk && pk->packed_expr.expr) + vt = infer_expr(sema, pk->packed_expr.expr); + spl_scope_id_t sc = sema->current_scope; + if (pk && pk->packed_expr.bind_ident && vt) { + spl_scope_id_t s2 = spl_sema_scope_alloc(sema); + sema->scopes.data[s2].parent = sc; + spl_def_id_t vdef = + new_var_def(sema, pk->packed_expr.bind_ident, underlying(sema, vt), s2); + spl_sema_scope_insert(sema, s2, pk->packed_expr.bind_ident, vdef); + sema->current_scope = s2; + } + check_block(sema, &b->block_item.ifvar_statement.if_block, sema->current_scope, ctx); + sema->current_scope = sc; + if (b->block_item.ifvar_statement.else_block.size) + check_block(sema, &b->block_item.ifvar_statement.else_block, sc, ctx); + break; + } + case SPL_AST_WHILE_STATEMENT: { + spl_type_id_t c = infer_expr(sema, b->block_item.while_statement.expr); + c = underlying(sema, c); + if (c && c != underlying(sema, spl_type_bool(&sema->type))) + sema_error(sema, b->block_item.while_statement.expr, "while condition must be bool"); + check_block(sema, &b->block_item.while_statement.while_block, sema->current_scope, ctx); + break; + } + case SPL_AST_LOOP_STATEMENT: + check_block(sema, &b->block_item.loop_statement.loop_block, sema->current_scope, ctx); + break; + case SPL_AST_FOR_STATEMENT: + check_for(sema, ref, b, ctx); + break; + case SPL_AST_MATCH_STATEMENT: + check_match(sema, ref, b, ctx); + break; + case SPL_AST_RET_STATEMENT: { + spl_ast_node_t *rd = b; + if (rd->block_item.ret_statement.expr) { + spl_type_id_t et = infer_expr(sema, rd->block_item.ret_statement.expr); + if (ctx.ret) { + if (!expr_is_null_literal(sema, rd->block_item.ret_statement.expr) && et && + !type_compatible(sema, ctx.ret, et, + expr_is_int_literal(sema, rd->block_item.ret_statement.expr), + NULL)) { + sema_error(sema, rd->block_item.ret_statement.expr, "ret type mismatch"); + } + } + } + break; + } + case SPL_AST_BREAK_STATEMENT: + case SPL_AST_CONTINUE_STATEMENT: + break; + case SPL_AST_DEFER_STATEMENT: + check_block(sema, &b->block_item.defer_statement.block_or_statement, sema->current_scope, + ctx); + break; + case SPL_AST_EXPR_STATEMENT: + if (b->block_item.expr_statement) + infer_expr(sema, b->block_item.expr_statement); + break; + default: + break; + } +} + +/* 块检查:为块建子 scope 并检查其中语句 */ +static void check_block(spl_sema_t *sema, spl_ast_node_ref_vec_t *block, spl_scope_id_t parent, + spl_sema_ctx_t ctx) { + spl_scope_id_t scope = spl_sema_scope_alloc(sema); + sema->scopes.data[scope].parent = parent; + spl_scope_id_t save = sema->current_scope; + sema->current_scope = scope; + /* 变量声明先登记进本块 scope,随后语句检查 */ + for (usize i = 0; i < block->size; i++) { + spl_ast_node_t *b = node_at(sema->ast, block->data[i]); + if (!b || b->kind == SPL_AST_EXPR) + continue; + if (b->block_item.kind == SPL_AST_VARDECL) { + spl_ast_node_t *vd = node_at(sema->ast, b->block_item.var_decl); + if (vd) + register_binding(sema, vd->var_decl.name, vd->var_decl.type_expr, scope, 0); + } else if (b->block_item.kind == SPL_AST_CONSTDECL) { + spl_ast_node_t *cd = node_at(sema->ast, b->block_item.const_decl); + if (cd) + register_binding(sema, cd->const_decl.name, cd->const_decl.type_expr, scope, 0); + } else if (b->block_item.kind == SPL_AST_TYPEDECL) { + spl_ast_node_t *td = node_at(sema->ast, b->block_item.type_decl); + if (td) + sema_type_decl(sema, b->block_item.type_decl, scope, 0); + } + } + for (usize i = 0; i < block->size; i++) + check_stmt(sema, block->data[i], ctx); + sema->current_scope = save; +} + +/* 函数体检查:新建 fn_scope、登记形参(复用 def 里的 fn_params_def 类型),随后检查块 */ +static void check_fn_body(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_def_id_t fdef, + spl_scope_id_t parent_scope) { + spl_ast_node_t *n = node_at(sema->ast, ref); + if (!n || !fdef) + return; + spl_type_id_t fid = def_type(sema, fdef); + spl_type_id_t ret = 0; + spl_type_node_t *ft = type_node(sema, fid); + if (ft && ft->kind == SPL_TYPE_FN) + ret = ft->fn_type.ret; + spl_sema_ctx_t ctx = {ret}; + spl_scope_id_t fn_scope = spl_sema_scope_alloc(sema); + sema->scopes.data[fn_scope].parent = parent_scope; + spl_scope_id_t save = sema->current_scope; + sema->current_scope = fn_scope; + /* 先复制参数信息,避免 new_var_def 触发 def_table 扩容使指针失效 */ + spl_def_node_t *d = def_at(sema, fdef); + usize nparams = d ? d->fn_params_def.size : 0; + for (usize i = 0; i < nparams; i++) { + d = def_at(sema, fdef); + spl_var_def_t *pv = &d->fn_params_def.data[i]; + if (pv->name) { + spl_def_id_t pdef = new_var_def(sema, pv->name, pv->type_id, fn_scope); + spl_sema_scope_insert(sema, fn_scope, pv->name, pdef); + } + } + check_block(sema, &n->fn_decl.block, fn_scope, ctx); + sema->current_scope = save; +} + +void spl_sema_init(spl_sema_t *sema) { + memset(sema, 0, sizeof *sema); + spl_type_init(&sema->type); + vec_init(sema->scopes); + /* scope id 0 保留为 error */ + spl_scope_node_t s0; + memset(&s0, 0, sizeof s0); + map_init(s0.symbols, MAP_HASH_STR, MAP_CMP_STR); + vec_push(sema->scopes, s0); + sema->root_scope = spl_sema_scope_alloc(sema); + sema->current_scope = sema->root_scope; + /* 文件聚合根:$root 即文件聚合(root_def = AGG,成员为顶层声明) */ + spl_type_id_t root_type = spl_type_alloc(&sema->type); + spl_type_node_t *rn = spl_type_node(&sema->type, root_type); + rn->kind = SPL_TYPE_STRUCT; + vec_init(rn->agg_field_types); + sema->root_def = def_alloc(sema, SPL_DEF_AGG); + def_at(sema, sema->root_def)->type_id = root_type; + vec_init(def_at(sema, sema->root_def)->agg_def); + /* 关键字类型注册进 root(每个关键字一个 BUILTIN def) */ +#define SPL_REG_KEYWORD(nm, tid) \ + do { \ + spl_def_id_t _d = def_alloc(sema, SPL_DEF_BUILTIN); \ + def_at(sema, _d)->type_id = (tid); \ + spl_sema_scope_insert(sema, sema->root_scope, (nm), _d); \ + } while (0) + SPL_REG_KEYWORD("void", spl_type_void(&sema->type)); + SPL_REG_KEYWORD("bool", spl_type_bool(&sema->type)); + SPL_REG_KEYWORD("i8", spl_type_int(&sema->type, 8, 1)); + SPL_REG_KEYWORD("u8", spl_type_int(&sema->type, 8, 0)); + SPL_REG_KEYWORD("i16", spl_type_int(&sema->type, 16, 1)); + SPL_REG_KEYWORD("u16", spl_type_int(&sema->type, 16, 0)); + SPL_REG_KEYWORD("i32", spl_type_int(&sema->type, 32, 1)); + SPL_REG_KEYWORD("u32", spl_type_int(&sema->type, 32, 0)); + SPL_REG_KEYWORD("i64", spl_type_int(&sema->type, 64, 1)); + SPL_REG_KEYWORD("u64", spl_type_int(&sema->type, 64, 0)); + SPL_REG_KEYWORD("isize", spl_type_int(&sema->type, sizeof(isize) * 8, 1)); + SPL_REG_KEYWORD("usize", spl_type_int(&sema->type, sizeof(usize) * 8, 0)); + SPL_REG_KEYWORD("f32", spl_type_float(&sema->type, 32)); + SPL_REG_KEYWORD("f64", spl_type_float(&sema->type, 64)); +#undef SPL_REG_KEYWORD +} + +void spl_sema_drop(spl_sema_t *sema) { + for (usize i = 0; i < sema->scopes.size; i++) + map_free(sema->scopes.data[i].symbols); + vec_free(sema->scopes); + spl_type_drop(&sema->type); +} + +/* Pass1:预登记顶层名字,使兄弟/自引用成立(不解析成员、不检查函数体) */ +void spl_sema_run(spl_sema_t *sema) { + if (!sema->ast || !sema->ast->root) + return; + spl_ast_node_t *c = node_at(sema->ast, sema->ast->root); + if (!c || c->kind != SPL_AST_CONTAINER_ITEM) + return; + LOG_DEBUG("sema_run root=%zu kind=%d members=%zu", sema->ast->root, c->kind, + c->container_item.members.size); + sema->current_scope = sema->root_scope; + /* 1a. 聚合壳 + 别名(类型名先全部登记,兄弟聚合可互引) */ + for (usize i = 0; i < c->container_item.members.size; i++) { + spl_ast_node_ref_t mref = c->container_item.members.data[i]; + spl_ast_node_t *m = node_at(sema->ast, mref); + if (!m || m->kind != SPL_AST_TYPE_DECL) + continue; + spl_ast_node_t *te = node_at(sema->ast, m->type_decl.type_expr); + if (te && + (te->type_expr.kind == SPL_AST_TYPE_STRUCT || + te->type_expr.kind == SPL_AST_TYPE_UNION || te->type_expr.kind == SPL_AST_TYPE_ENUM)) { + agg_handle_t h = agg_prepare(sema, m->type_decl.type_expr); + if (!h.def) + continue; + if (!spl_sema_scope_insert(sema, sema->root_scope, m->type_decl.name, h.def)) + sema_error(sema, mref, "duplicate type name"); + agg_add_member(sema, sema->root_def, m->type_decl.name, h.tid, sema->root_scope); + } else if (te) { + spl_type_id_t tid = resolve_type_expr(sema, m->type_decl.type_expr); + spl_def_id_t def = def_alloc(sema, SPL_DEF_ALIAS); + spl_def_node_t *d = def_at(sema, def); + d->type_id = tid; + d->type_def.name = m->type_decl.name; + d->type_def.def_id = def; + d->type_def.type_id = tid; + d->type_def.scope_id = sema->root_scope; + if (!spl_sema_scope_insert(sema, sema->root_scope, m->type_decl.name, def)) + sema_error(sema, mref, "duplicate type name"); + agg_add_member(sema, sema->root_def, m->type_decl.name, tid, sema->root_scope); + } + } + /* 1b. fn 名(建 fn type + def) */ + for (usize i = 0; i < c->container_item.members.size; i++) { + spl_ast_node_ref_t mref = c->container_item.members.data[i]; + spl_ast_node_t *m = node_at(sema->ast, mref); + if (!m) + continue; + if (m->kind == SPL_AST_FN_DECL || m->kind == SPL_AST_FN_DEFINE) + sema_fn_decl(sema, mref, sema->root_scope, sema->root_def); + } + /* 1c. 顶层 var/const */ + for (usize i = 0; i < c->container_item.members.size; i++) { + spl_ast_node_ref_t mref = c->container_item.members.data[i]; + spl_ast_node_t *m = node_at(sema->ast, mref); + if (!m) + continue; + if (m->kind == SPL_AST_VAR_DECL) + sema_var_decl(sema, mref, sema->root_scope, sema->root_def); + else if (m->kind == SPL_AST_CONST_DECL) + sema_const_decl(sema, mref, sema->root_scope, sema->root_def); + } + sema->current_scope = sema->root_scope; +} + +/* Pass2:构建聚合成员(含方法 def)并检查函数体,一次遍历完成 */ +void spl_sema_check(spl_sema_t *sema) { + if (!sema->ast || !sema->ast->root) + return; + spl_ast_node_t *c = node_at(sema->ast, sema->ast->root); + if (!c || c->kind != SPL_AST_CONTAINER_ITEM) + return; + sema->current_scope = sema->root_scope; + /* 构建所有顶层聚合成员 */ + for (usize i = 0; i < c->container_item.members.size; i++) { + spl_ast_node_ref_t mref = c->container_item.members.data[i]; + spl_ast_node_t *m = node_at(sema->ast, mref); + if (!m || m->kind != SPL_AST_TYPE_DECL) + continue; + spl_ast_node_t *te = node_at(sema->ast, m->type_decl.type_expr); + if (te && + (te->type_expr.kind == SPL_AST_TYPE_STRUCT || + te->type_expr.kind == SPL_AST_TYPE_UNION || te->type_expr.kind == SPL_AST_TYPE_ENUM)) { + spl_def_id_t def = find_bare(sema, m->type_decl.name); + if (!def) + continue; + agg_resolve(sema, m->type_decl.type_expr, def_type(sema, def), def, sema->root_scope, + m->type_decl.name); + } + } + /* 检查顶层函数体 */ + for (usize i = 0; i < c->container_item.members.size; i++) { + spl_ast_node_ref_t mref = c->container_item.members.data[i]; + spl_ast_node_t *m = node_at(sema->ast, mref); + if (!m || m->kind != SPL_AST_FN_DEFINE) + continue; + spl_def_id_t def = find_bare(sema, m->fn_decl.name); + check_fn_body(sema, mref, def, sema->root_scope); + } + sema->current_scope = sema->root_scope; +} + +spl_scope_id_t spl_sema_scope_alloc(spl_sema_t *sema) { + spl_scope_node_t n; + memset(&n, 0, sizeof n); + map_init(n.symbols, MAP_HASH_STR, MAP_CMP_STR); + vec_push(sema->scopes, n); + return sema->scopes.size - 1; +} + +bool spl_sema_scope_insert(spl_sema_t *sema, spl_scope_id_t id, const char *symbol_name, + spl_def_id_t symbol_val) { + if (!id || id >= sema->scopes.size) + return false; + spl_def_id_t old = 0; + if (map_get(sema->scopes.data[id].symbols, symbol_name, &old)) + return false; + map_put(sema->scopes.data[id].symbols, symbol_name, symbol_val); + return true; +} + +spl_def_id_t spl_sema_scope_find(spl_sema_t *sema, spl_symbol_path_t path) { + if (!path.size) + return 0; + spl_def_id_t def = find_bare(sema, path.data[0]); + if (!def) + return 0; + for (usize i = 1; i < path.size; i++) { + spl_type_id_t t = def_type(sema, def); + spl_def_id_t owner = def_for_type(sema, t); + if (!owner) + return 0; + spl_def_node_t *od = def_at(sema, owner); + spl_def_id_t next = 0; + for (usize j = 0; j < od->agg_def.size; j++) { + if (od->agg_def.data[j].name && strcmp(od->agg_def.data[j].name, path.data[i]) == 0) { + next = od->agg_def.data[j].def_id ? od->agg_def.data[j].def_id + : def_for_type(sema, od->agg_def.data[j].type_id); + break; + } + } + if (!next) + return 0; + def = next; + } + return def; +} diff --git a/stage1/spl_sema.h b/stage1/spl_sema.h index e8ffe5d..2020767 100644 --- a/stage1/spl_sema.h +++ b/stage1/spl_sema.h @@ -7,7 +7,7 @@ typedef usize spl_scope_id_t; /* 0 is error */ typedef struct { spl_scope_id_t parent; - MAP(const char *, spl_type_id_t) symbols; + MAP(const char *, spl_def_id_t) symbols; } spl_scope_node_t; typedef VEC(spl_scope_node_t) spl_scope_node_vec_t; @@ -17,17 +17,19 @@ typedef struct { spl_scope_node_vec_t scopes; spl_scope_id_t root_scope; spl_scope_id_t current_scope; + spl_def_id_t root_def; int error_count; } spl_sema_t; void spl_sema_init(spl_sema_t *sema); void spl_sema_drop(spl_sema_t *sema); void spl_sema_run(spl_sema_t *sema); +void spl_sema_check(spl_sema_t *sema); spl_scope_id_t spl_sema_scope_alloc(spl_sema_t *sema); bool spl_sema_scope_insert(spl_sema_t *sema, spl_scope_id_t id, const char *symbol_name, - spl_type_id_t symbol_val); + spl_def_id_t symbol_val); typedef VEC(const char *) spl_symbol_path_t; -spl_type_id_t spl_sema_scope_find(spl_sema_t *sema, spl_symbol_path_t path); +spl_def_id_t spl_sema_scope_find(spl_sema_t *sema, spl_symbol_path_t path); #endif /* __SPL_SEMA_H__ */ diff --git a/stage1/spl_type.c b/stage1/spl_type.c index 52ac773..24f4617 100644 --- a/stage1/spl_type.c +++ b/stage1/spl_type.c @@ -1 +1,324 @@ -#include "spl_type.h" \ No newline at end of file +// WRITE BY AI +/* spl_type.c SPL 类型系统:type/def 两张完全独立的 arena 表 + 构造器 + dump + * type_table 按 spl_type_id_t 存匿名类型;def_table 按 spl_def_id_t 存命名实体。 + * 两表 id 空间互不相干(0 均保留为 error)。 */ +#include "spl_type.h" + +#include +#include + +static spl_type_id_t type_push(spl_type_t *type) { + spl_type_node_t n; + memset(&n, 0, sizeof n); + n.kind = SPL_TYPE_VOID; + vec_push(type->type_table, n); + return type->type_table.size - 1; +} + +/* 内置整型去重:同 bits/signed 复用同一 id(类型唯一化) */ +spl_type_id_t spl_type_int(spl_type_t *type, usize bits, int is_signed) { + for (usize i = 1; i < type->type_table.size; i++) { + spl_type_node_t *n = &type->type_table.data[i]; + if (n->kind == SPL_TYPE_INT && n->int_type.bits == bits && + n->int_type.is_signed == is_signed) + return i; + } + spl_type_id_t id = type_push(type); + type->type_table.data[id].kind = SPL_TYPE_INT; + type->type_table.data[id].int_type.bits = bits; + type->type_table.data[id].int_type.is_signed = is_signed; + return id; +} + +/* 内置浮点去重 */ +spl_type_id_t spl_type_float(spl_type_t *type, usize bits) { + for (usize i = 1; i < type->type_table.size; i++) { + spl_type_node_t *n = &type->type_table.data[i]; + if (n->kind == SPL_TYPE_FLOAT && n->float_type.bits == bits) + return i; + } + spl_type_id_t id = type_push(type); + type->type_table.data[id].kind = SPL_TYPE_FLOAT; + type->type_table.data[id].float_type.bits = bits; + return id; +} + +spl_type_id_t spl_type_void(spl_type_t *type) { + for (usize i = 1; i < type->type_table.size; i++) + if (type->type_table.data[i].kind == SPL_TYPE_VOID) + return i; + spl_type_id_t id = type_push(type); + type->type_table.data[id].kind = SPL_TYPE_VOID; + return id; +} + +spl_type_id_t spl_type_bool(spl_type_t *type) { + for (usize i = 1; i < type->type_table.size; i++) + if (type->type_table.data[i].kind == SPL_TYPE_BOOL) + return i; + spl_type_id_t id = type_push(type); + type->type_table.data[id].kind = SPL_TYPE_BOOL; + return id; +} + +spl_type_id_t spl_type_ptr(spl_type_t *type, spl_type_id_t val) { + spl_type_id_t id = type_push(type); + type->type_table.data[id].kind = SPL_TYPE_PTR; + type->type_table.data[id].ptr_pointee = val; + return id; +} + +spl_type_id_t spl_type_slice(spl_type_t *type, spl_type_id_t val) { + spl_type_id_t id = type_push(type); + type->type_table.data[id].kind = SPL_TYPE_SLICE; + type->type_table.data[id].slice_element = val; + return id; +} + +spl_type_id_t spl_type_range(spl_type_t *type, spl_type_id_t val) { + spl_type_id_t id = type_push(type); + type->type_table.data[id].kind = SPL_TYPE_RANGE; + type->type_table.data[id].range_element = val; + return id; +} + +spl_type_id_t spl_type_array(spl_type_t *type, spl_type_id_t val, usize len) { + spl_type_id_t id = type_push(type); + type->type_table.data[id].kind = SPL_TYPE_ARRAY; + type->type_table.data[id].array_type.element = val; + type->type_table.data[id].array_type.len = len; + return id; +} + +/* 绑定节点/别名引用:type 节点指向被引用的类型 id + * (供未来"底层同型但类型系统不认"的 newtype 使用,暂不参与注册) */ +spl_type_id_t spl_type_tid(spl_type_t *type, spl_type_id_t val) { + spl_type_id_t id = type_push(type); + type->type_table.data[id].kind = SPL_TYPE_ID; + type->type_table.data[id].type_id = val; + return id; +} + +/* 聚合类型:默认 STRUCT,字段类型列表 */ +spl_type_id_t spl_type_agg(spl_type_t *type, spl_type_id_vec_t fields) { + spl_type_id_t id = type_push(type); + type->type_table.data[id].kind = SPL_TYPE_STRUCT; + type->type_table.data[id].agg_field_types = fields; + return id; +} + +spl_type_id_t spl_type_enum(spl_type_t *type, spl_type_id_vec_t variants, spl_type_id_t tag) { + spl_type_id_t id = type_push(type); + type->type_table.data[id].kind = SPL_TYPE_ENUM; + type->type_table.data[id].enum_type.variants = variants; + type->type_table.data[id].enum_type.tag_type = tag; + return id; +} + +spl_type_id_t spl_type_fn(spl_type_t *type, spl_type_id_vec_t params, spl_type_id_t ret) { + spl_type_id_t id = type_push(type); + type->type_table.data[id].kind = SPL_TYPE_FN; + type->type_table.data[id].fn_type.params = params; + type->type_table.data[id].fn_type.ret = ret; + return id; +} + +void spl_type_init(spl_type_t *type) { + vec_init(type->type_table); + vec_init(type->def_table); + /* 两表 id 0 均保留为 error */ + type_push(type); + spl_type_def_alloc(type); + /* 关键字/内置类型(去重后 i8..u64 等各占一个 id;def 由 sema 登记) */ + spl_type_void(type); + spl_type_bool(type); + spl_type_int(type, 8, 1); + spl_type_int(type, 8, 0); + spl_type_int(type, 16, 1); + spl_type_int(type, 16, 0); + spl_type_int(type, 32, 1); + spl_type_int(type, 32, 0); + spl_type_int(type, 64, 1); + spl_type_int(type, 64, 0); + spl_type_float(type, 32); + spl_type_float(type, 64); +} + +void spl_type_drop(spl_type_t *type) { + /* type 节点持有的内嵌 vec */ + for (usize i = 0; i < type->type_table.size; i++) { + spl_type_node_t *n = &type->type_table.data[i]; + switch (n->kind) { + case SPL_TYPE_STRUCT: + case SPL_TYPE_UNION: + vec_free(n->agg_field_types); + break; + case SPL_TYPE_ENUM: + vec_free(n->enum_type.variants); + break; + case SPL_TYPE_FN: + vec_free(n->fn_type.params); + break; + default: + break; + } + } + /* def 节点持有的内嵌 vec */ + for (usize i = 0; i < type->def_table.size; i++) { + spl_def_node_t *d = &type->def_table.data[i]; + switch (d->kind) { + case SPL_DEF_AGG: + vec_free(d->agg_def); + break; + case SPL_DEF_FN_PARAMS: + vec_free(d->fn_params_def); + break; + default: + break; + } + } + vec_free(type->type_table); + vec_free(type->def_table); +} + +spl_type_id_t spl_type_alloc(spl_type_t *type) { return type_push(type); } + +spl_type_node_t *spl_type_node(spl_type_t *type, spl_type_id_t id) { + if (!id || id >= type->type_table.size) + return NULL; + return &type->type_table.data[id]; +} + +spl_def_id_t spl_type_def_alloc(spl_type_t *type) { + spl_def_node_t d; + memset(&d, 0, sizeof d); + d.kind = SPL_DEF_NONE; + vec_push(type->def_table, d); + return type->def_table.size - 1; +} + +spl_def_node_t *spl_type_def(spl_type_t *type, spl_def_id_t id) { + if (!id || id >= type->def_table.size) + return NULL; + return &type->def_table.data[id]; +} + +static const char *def_kind_name(spl_def_node_t *d) { + switch (d->kind) { + case SPL_DEF_NONE: + return "none"; + case SPL_DEF_BUILTIN: + return "builtin"; + case SPL_DEF_VAR: + return "var"; + case SPL_DEF_FN_PARAMS: + return "fn_params"; + case SPL_DEF_AGG: + return "agg"; + case SPL_DEF_DISTINCT: + return "distinct"; + case SPL_DEF_ALIAS: + return "alias"; + } + return "?"; +} + +void spl_type_pure_dump(spl_type_t *type, spl_type_id_t id) { + spl_type_node_t *n = spl_type_node(type, id); + if (!n) { + printf("(err)"); + return; + } + switch (n->kind) { + case SPL_TYPE_VOID: + printf("void"); + break; + case SPL_TYPE_BOOL: + printf("bool"); + break; + case SPL_TYPE_INT: + printf("%s%zu", n->int_type.is_signed ? "i" : "u", n->int_type.bits); + break; + case SPL_TYPE_FLOAT: + printf("f%zu", n->float_type.bits); + break; + case SPL_TYPE_PTR: + printf("*"); + spl_type_pure_dump(type, n->ptr_pointee); + break; + case SPL_TYPE_SLICE: + printf("[]"); + spl_type_pure_dump(type, n->slice_element); + break; + case SPL_TYPE_RANGE: + printf("range["); + spl_type_pure_dump(type, n->range_element); + printf("]"); + break; + case SPL_TYPE_ARRAY: + printf("[%zu]", n->array_type.len); + spl_type_pure_dump(type, n->array_type.element); + break; + case SPL_TYPE_STRUCT: + printf("struct{%zu fields}", n->agg_field_types.size); + break; + case SPL_TYPE_UNION: + printf("union{%zu fields}", n->agg_field_types.size); + break; + case SPL_TYPE_ENUM: + printf("enum{%zu variants}", n->enum_type.variants.size); + break; + case SPL_TYPE_FN: { + printf("fn("); + for (usize i = 0; i < n->fn_type.params.size; i++) { + if (i) + printf(","); + spl_type_pure_dump(type, n->fn_type.params.data[i]); + } + printf(") -> "); + spl_type_pure_dump(type, n->fn_type.ret); + break; + } + case SPL_TYPE_ID: + printf("id#%zu", n->type_id); + break; + } +} + +void spl_type_def_dump(spl_type_t *type, spl_def_id_t id) { + spl_def_node_t *d = spl_type_def(type, id); + if (!d) { + printf("(err)"); + return; + } + printf("kind=%s type_id=%zu", def_kind_name(d), d->type_id); + switch (d->kind) { + case SPL_DEF_VAR: + printf(" var=%s", d->var_def.name ? d->var_def.name : "?"); + break; + case SPL_DEF_ALIAS: + case SPL_DEF_DISTINCT: + printf(" type=%s", d->type_def.name ? d->type_def.name : "?"); + break; + case SPL_DEF_AGG: + printf(" agg{"); + for (usize i = 0; i < d->agg_def.size; i++) { + if (i) + printf(","); + printf("%s", d->agg_def.data[i].name ? d->agg_def.data[i].name : "?"); + } + printf("}"); + break; + case SPL_DEF_FN_PARAMS: + printf(" fn("); + for (usize i = 0; i < d->fn_params_def.size; i++) { + if (i) + printf(","); + printf("%s", d->fn_params_def.data[i].name ? d->fn_params_def.data[i].name : "?"); + } + printf(")"); + break; + default: + break; + } +} diff --git a/stage1/spl_type.h b/stage1/spl_type.h index e9373b9..f056e88 100644 --- a/stage1/spl_type.h +++ b/stage1/spl_type.h @@ -5,6 +5,8 @@ typedef usize spl_type_id_t; /* 0 is error */ typedef VEC(spl_type_id_t) spl_type_id_vec_t; +typedef usize spl_def_id_t; /* 0 is error */ +typedef VEC(spl_def_id_t) spl_def_id_vec_t; typedef struct { enum { @@ -14,6 +16,7 @@ typedef struct { SPL_TYPE_FLOAT, SPL_TYPE_PTR, SPL_TYPE_SLICE, + SPL_TYPE_RANGE, SPL_TYPE_ARRAY, SPL_TYPE_STRUCT, SPL_TYPE_UNION, @@ -31,6 +34,7 @@ typedef struct { } float_type; spl_type_id_t ptr_pointee; spl_type_id_t slice_element; + spl_type_id_t range_element; struct { spl_type_id_t element; usize len; @@ -46,13 +50,13 @@ typedef struct { } fn_type; spl_type_id_t type_id; }; - usize byte_size; /* 布局缓存 */ } spl_type_node_t; typedef VEC(spl_type_node_t) spl_type_node_vec_t; typedef struct { const char *name; - spl_type_id_t type; + spl_def_id_t def_id; + spl_type_id_t type_id; usize scope_id; } spl_var_def_t; typedef VEC(spl_var_def_t) spl_var_def_vec_t; @@ -67,6 +71,7 @@ typedef struct { SPL_DEF_DISTINCT, // newtype SPL_DEF_ALIAS, // sametypes } kind; + spl_type_id_t type_id; union { spl_var_def_t var_def; spl_var_def_vec_t agg_def; // include enum variants @@ -87,19 +92,19 @@ type (类型名) = (匿名类型) */ typedef struct { spl_type_node_vec_t type_table; - spl_def_node_vec_t def_table; /* 使用type_id作为索引 */ + spl_def_node_vec_t def_table; } spl_type_t; void spl_type_init(spl_type_t *type); void spl_type_drop(spl_type_t *type); -void spl_type_def_dump(spl_type_t *type, spl_type_id_t id); +void spl_type_def_dump(spl_type_t *type, spl_def_id_t id); void spl_type_pure_dump(spl_type_t *type, spl_type_id_t id); -// alloc 时两表平行 push, 保证索引同步 spl_type_id_t spl_type_alloc(spl_type_t *type); spl_type_node_t *spl_type_node(spl_type_t *type, spl_type_id_t id); -spl_def_node_t *spl_type_def(spl_type_t *type, spl_type_id_t id); +spl_def_id_t spl_type_def_alloc(spl_type_t *type); +spl_def_node_t *spl_type_def(spl_type_t *type, spl_def_id_t id); spl_type_id_t spl_type_void(spl_type_t *type); spl_type_id_t spl_type_bool(spl_type_t *type); @@ -107,6 +112,7 @@ spl_type_id_t spl_type_int(spl_type_t *type, usize bits, int is_signed); spl_type_id_t spl_type_float(spl_type_t *type, usize bits); spl_type_id_t spl_type_ptr(spl_type_t *type, spl_type_id_t val); spl_type_id_t spl_type_slice(spl_type_t *type, spl_type_id_t val); +spl_type_id_t spl_type_range(spl_type_t *type, spl_type_id_t val); spl_type_id_t spl_type_array(spl_type_t *type, spl_type_id_t val, usize len); spl_type_id_t spl_type_tid(spl_type_t *type, spl_type_id_t val); spl_type_id_t spl_type_agg(spl_type_t *type, spl_type_id_vec_t fields); diff --git a/stage1/splc0.c b/stage1/splc0.c index ec49081..904af58 100644 --- a/stage1/splc0.c +++ b/stage1/splc0.c @@ -12,6 +12,7 @@ #include "spl_ast.h" #include "spl_lexer.h" +#include "spl_sema.h" #include "spl_tok.h" static char *read_file(const char *path, long *out_len) { @@ -65,6 +66,42 @@ static void dump_ast(const char *src, const char *fname) { spl_ast_drop(&ast); } +static void dump_sema(const char *src, const char *fname) { + spl_tok_vec_t toks = spl_lex(src, fname); + spl_ast_t ast; + spl_ast_init(&ast, &toks); + spl_ast_prase(&ast); + spl_ast_valid(&ast); + spl_sema_t sema; + spl_sema_init(&sema); + sema.ast = * + spl_sema_run(&sema); + spl_sema_check(&sema); + printf("Sema root_scope=%zu scopes=%zu errors=%d\n", sema.root_scope, sema.scopes.size, + sema.error_count); + for (usize i = 0; i < sema.scopes.size; i++) { + printf("scope[%zu] parent=%zu\n", i, sema.scopes.data[i].parent); + map_for(sema.scopes.data[i].symbols, mi) { + printf(" %s -> def#%zu\n", sema.scopes.data[i].symbols.data[mi].key, + sema.scopes.data[i].symbols.data[mi].val); + } + } + printf("TypeTable:\n"); + for (usize i = 0; i < sema.type.type_table.size; i++) { + printf(" id#%zu type=", i); + spl_type_pure_dump(&sema.type, i); + printf("\n"); + } + printf("DefTable:\n"); + for (usize i = 0; i < sema.type.def_table.size; i++) { + printf(" def#%zu ", i); + spl_type_def_dump(&sema.type, i); + printf("\n"); + } + spl_sema_drop(&sema); + spl_ast_drop(&ast); +} + static int cmd_dump(const char *flags, const char *path) { long len; char *src = read_file(path, &len); @@ -72,10 +109,13 @@ static int cmd_dump(const char *flags, const char *path) { return 1; int do_tokens = strstr(flags, "tokens") != NULL || strcmp(flags, "all") == 0; int do_ast = strstr(flags, "ast") != NULL || strcmp(flags, "all") == 0; + int do_sema = strstr(flags, "sema") != NULL || strcmp(flags, "all") == 0; if (do_tokens) dump_tokens(src, path); if (do_ast) dump_ast(src, path); + if (do_sema) + dump_sema(src, path); free(src); return 0; } @@ -87,15 +127,20 @@ int main(int argc, char **argv) { } if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) { LOG_INFO("splc0 compile (.spl -> .sir, 阶段 B)\n"); - LOG_INFO("splc0 --dump dump: tokens,ast,all\n"); + LOG_INFO("splc0 --dump dump: tokens,ast,sema,all\n"); return 0; } - if (strcmp(argv[1], "--dump") == 0) { - if (argc < 4) { + int argi = 1; + if (argi >= argc) { + LOG_FATAL("Usage: splc0 [--dump ] [out]\n"); + return 1; + } + if (strcmp(argv[argi], "--dump") == 0) { + if (argc < argi + 3) { LOG_INFO("splc0: --dump need \n"); return 1; } - return cmd_dump(argv[2], argv[3]); + return cmd_dump(argv[argi + 1], argv[argi + 2]); } LOG_FATAL("splc0: compile todo\n"); return 1; diff --git a/stage1/test01_literals.spl b/stage1/test01_literals.spl index 27fb602..70048f2 100644 --- a/stage1/test01_literals.spl +++ b/stage1/test01_literals.spl @@ -30,10 +30,10 @@ fn main() i32 { if nl != 10 { ret 6; } /* 布尔字面量 */ - var t: i32 = true; - if t != 1 { ret 7; } - var f: i32 = false; - if f != 0 { ret 8; } + var t: bool = true; + if !t { ret 7; } + var f: bool = false; + if f { ret 8; } /* null 指针 */ var np: *i32 = null; diff --git a/stage1/test04_operators.spl b/stage1/test04_operators.spl index 98e9077..3e55fd7 100644 --- a/stage1/test04_operators.spl +++ b/stage1/test04_operators.spl @@ -16,11 +16,11 @@ fn main() i32 { /* 比较结果为 0/1 */ var eq := (42 == 42); - if eq != 1 { ret 9; } + if !eq { ret 9; } var ne := (42 == 43); - if ne != 0 { ret 10; } + if ne { ret 10; } var lt := (5 < 10); - if lt != 1 { ret 11; } + if !lt { ret 11; } /* ---- 逻辑运算 ---- */ if (true) {} else { ret 12; } @@ -30,9 +30,9 @@ fn main() i32 { /* 逻辑非 */ var not_t := !true; - if not_t != 0 { ret 16; } + if not_t { ret 16; } var not_f := !false; - if not_f != 1 { ret 17; } + if !not_f { ret 17; } // /* ---- 短路求值 ---- */ // var short1 := 0; diff --git a/stage1/test10_struct.spl b/stage1/test10_struct.spl index 74c8392..dc32b52 100644 --- a/stage1/test10_struct.spl +++ b/stage1/test10_struct.spl @@ -81,7 +81,7 @@ fn test_param_pass_token() i32 { ret 0; } -fn test_get_tag(tok: Token) i32 { +fn test_get_tag(tok: Token) Tag { ret tok.tag; } diff --git a/stage1/test13_extern.spl b/stage1/test13_extern.spl index 076dbdd..3275b90 100644 --- a/stage1/test13_extern.spl +++ b/stage1/test13_extern.spl @@ -5,8 +5,8 @@ * 字符串字面量、字符串参数传递 */ @extern(vm) fn vm_printf(fmt: *u8, ...) void; -@extern(vm) fn vm_strlen(s: *i8) i32; -@extern(vm) fn vm_strcmp(a: *i8, b: *i8) i32; +@extern(vm) fn vm_strlen(s: *u8) i32; +@extern(vm) fn vm_strcmp(a: *u8, b: *u8) i32; fn main() i32 { /* vm_printf 输出测试 */