diff --git a/SPL.md b/SPL.md index 176e9a3..dcb0c5d 100644 --- a/SPL.md +++ b/SPL.md @@ -432,7 +432,7 @@ fn name(x: i32 = 0) { ... } 声明 静态约束 动态语义 FnDecl 名称唯一,签名完整。 仅定义。 TypeDecl 同作用域名称唯一。 定义类型别名或聚合体,编译时解析。 -VarDecl (容器级) var: 必须初始化,类型完整。const: 初始化必须编译期可求值。 const 编译时计算;var 启动初始化一次。 +VarDecl var: 必须初始化,类型完整。 const: 初始化必须编译期可求值。 const 编译时计算;var 启动初始化一次。 ConstDecl 必须编译期可求值。 编译期常量。 ComptimeStmt 内部代码全部在编译时执行。 编译时执行,可生成声明。 DirectiveBlock @id { } / #id { } 为扩展占位,无预定义行为。未识别指令触发警告/错误。 同左。 @@ -478,12 +478,21 @@ type T = TypeExpr — 完全同义。 匹配: match 必须穷举 (或含 _),否则编译错误。 +### 聚合体内的成员函数(就是普通函数) +在 struct / union / enum 体内的 `fn` 声明就是普通函数,进入该聚合 def 的成员列表(与字段、变体并列)。**无"方法"概念、无隐式接收者、无 self 魔法**:需要实例时,实例以普通参数显式传入(首参命名 self 只是习惯,无特殊语义)。 + +- 聚合类型 (以及文件 $root) 同时是**命名空间**,其内 fn 即该命名空间下的具名函数。 +- 调用**只能命名空间限定**: `TypeName.fn(args)`(如 `Vec.at(&vec, i)`)。**禁止 `expr.fn(args)` 用表达式实例点调其成员函数**。 +- 命名空间内相互调用用裸名 `fn(...)`。 +- `.` 仅用于字段/变体/路径选择 (`vec.len`、`.Some[5]`、`Token.Tag.kw_null`),不是函数调用通道。 +- 函数名、字段名、变体名同存于聚合 def 的成员列表,名称互斥(同一聚合内同名冲突为编译错误)。 + ## 名称解析 1. 函数内部 (参数 + 块局部,每个 {} 建立子 scope)。 2. $root:文件聚合的 scope,所有顶层声明 (fn/type/var/const) 都是其成员。 -无独立"全局"命名空间。$root 抽象不写死:@import(xxx) 返回的匿名结构即该模块当时的 $root,多文件时切换。字段/变体名不在 scope map 中 (存于聚合 def 的成员列表),裸名查找天然不命中字段;路径 a.b.c 首段裸名查 scope、后续段查聚合成员。 +无独立"全局"命名空间。$root 抽象不写死:@import(xxx) 返回的匿名结构即该模块当时的 $root,多文件时切换。字段/变体/命名空间函数名不在 scope map 中 (存于聚合 def 的成员列表),裸名查找天然不命中字段/函数;命名空间函数只能经 `TypeName.fn` 限定调用,禁止 `expr.fn(...)` 实例点调;路径 a.b.c 首段裸名查 scope、后续段查聚合成员。 ## 变量与常量 var x: T 或 var x := init: 可变量。 @@ -585,7 +594,9 @@ defer { ... }: 退出作用域时以后进先出执行。 浮点 f64,布尔 bool。 -null -> ?T 隐式转换。 +字符 'c'(含转义)默认 u8,视为整数字面量可参与拓宽。 + +null:空指针字面量。当前语言无 ?T,null 仅用于指针或切片的比较、赋值、初始化及聚合字段;其他用法为错误。 ### 运算符 算术/位运算: 操作数类型必须完全一致或由字面量推导,无隐式提升。 @@ -615,6 +626,8 @@ expr(args) 可调用 函数调用 结构体字面量: Type { .f1 = v1, ... }。 +匿名聚合字面量: .{ .f1 = v1, ... }。省去显式类型名,必须出现在能由上下文推导目标聚合类型的语境 (变量初始化带类型、赋值、字段值等);无法推导目标类型则编译错误。切片可用 .{ .ptr = p, .len = n } 构造。 + 块表达式: { ... }。 comptime { ... } / comptime expr;: 编译时求值,不可引用运行时变量。 @@ -628,6 +641,8 @@ comptime { ... } / comptime expr;: 编译时求值,不可引用运行时变量 函数类型: fn(T1, T2) RetType。 +裸 `_` 与 `ptr` 关键字不能作为独立类型 (单独出现为编译错误),`_` 只能以 `*_` 形式作指针目标,语义为"任意指针";`ptr` 关键字当前保留未启用。 + *_ 的特殊规则: *T -> *_: 允许,必须警告。 @@ -638,9 +653,7 @@ comptime { ... } / comptime expr;: 编译时求值,不可引用运行时变量 其他隐式转换: -整数字面量适配更大类型。 - -null -> ?T。 +null -> 指针/切片空值。 其余必须显式 as。 @@ -648,13 +661,15 @@ null -> ?T。 区间类型 Range 语法 a..b 或 a..。 -内部结构: { begin: i64, end: ?i64 } (具体整数类型可能由上下文决定,默认为 i64)。 +内部结构: { begin: , end: },其中 为边界整数类型 (左右边界类型一致,默认/通常为 isize 或 usize;无界端 end 存为空值表示无穷)。 a..b: begin = a, end = b。 -a..: begin = a, end = null。 +a..: begin = a, end = 空值 (无界)。 -用作迭代器时: 产生从 begin 到 end-1 的整数 (若 end 为 null 则无穷)。在 for 中与其他序列配合时,无界的区间自动取其配对序列的长度作为上界 (等于 0..other.len),如果配对序列也是无界则无限循环。 +Range 是一等类型 (值类型,同聚合行为),其 begin / end 可作为字段直接访问 (expr.begin / expr.end),访问类型即边界整数类型。 + +用作迭代器时: 产生从 begin 到 end-1 的整数 (若 end 为空值则无穷),元素类型即边界整数类型 (与 begin/end 一致)。在 for 中与其他序列配合时,无界的区间自动取其配对序列的长度作为上界 (等于 0..other.len),如果配对序列也是无界则无限循环。 切片类型 []T 内部结构: { ptr: *T, len: usize }。 @@ -732,13 +747,13 @@ void: 大小为 0,表示无值,仅用于函数返回或指针。 从数组构造: array[a..b] 产生切片。 ### 区间类型 -a..b 或 a..: 类型为 Range,内部结构 { begin: isize, end: ?isize }。 +a..b 或 a..: 类型为 Range,内部结构 { begin: , end: }, 为边界整数类型 (左右边界一致,默认 isize 或 usize;无界端 end 存空值)。 a..b: end 为 b。 -a..: end 为 null (无界)。 +a..: end 为空值 (无界)。 -Range 是值类型同聚合类型行为。 +Range 是值类型同聚合类型行为,begin / end 可作为字段直接访问。 用于迭代和切片边界。 @@ -747,10 +762,10 @@ fn(参数类型列表) 返回类型 函数值本身的大小和表示未指定 (闭包待定),但函数名作为标识符使用时具有指针语义 (类似函数指针)。 -### 可选类型(暂时不需要实现) +### 可选类型(预留,当前不实现) ?T: 可为 null 的类型。内部表示同 T 但附加一个判别 (可能通过 null 指针表示,视 T 而定)。?T 的大小和对齐与 T 相同或扩展为可容纳 null 的形式 (具体实现定义)。 -null 字面量只能出现在需要 ?T 的上下文中。 +当前阶段未实现 ?T,null 以"指针/切片的空值"语义生效 (见"特殊类型"与"类型兼容性")。 ### 聚合类型 struct: 字段连续排列 (可能有对齐填充),每个字段有自己的类型。赋值是逐字段拷贝。 @@ -772,7 +787,7 @@ enum: 带标签的联合体,每个变体可有载荷。大小实现定义, ### 特殊类型 void: 无法实例化,仅用于返回或指针目标。 -null: 不是独立类型,仅用于初始化或赋值给 ?T。 +null: 不是独立类型,是"指针/切片空值"字面量,仅用于指针或切片的初始化、赋值、比较及聚合字段。 ## 类型兼容性与隐式转换 下表中,“允许”表示可自动转换,否则需要显式 as 转换。警告列表明编译器必须输出诊断信息,不可静默。 @@ -782,12 +797,10 @@ T (任意) T 是 无 相同类型 *T *_ 是 警告: “丢失类型信息” *_ *T 是 警告: “不安全的指针重解释” [N]T []T 是 无 数组到切片强制转换 -整数字面量 整数类型 U 是 (若值在 U 范围内) 无 字面量自动拓宽 +整数字面量 整数类型 U 是 (若值在 U 范围内) 无 字面量自动拓宽 (含字符 'c' 视为 u8) i32 i64 否 — 需显式 as i64,防止意外 i64 i32 否 — 窄化必须显式 -null ?T 是 无 空值初始化 -?T T 否 — 需显式解包 (如 orelse,但语言暂未定义,将来扩展) -T ?T 是 无 提升为可选 +null *T / []T 是 无 空指针/空切片初始化、比较、赋值、聚合字段 浮点字面量 f32 是 (值可表示则) 无 f64 f32 否 — 窄化需显式 bool 整数 否 — @@ -795,9 +808,11 @@ bool 整数 否 — 注: +?T (可选类型) 为预留特性,当前阶段未实现;null 语义以"指针/切片的空值"生效,见本表 null 行。 + 隐式转换不会嵌套传递。例如 *T 到 *_ 是警告转换,但不因此进一步允许 *_ 到 **T 的隐式转换。 -字面量拓宽仅适用于整数字面量直接出现在需要更宽整数类型的上下文 (如赋值给 i64 变量,或作为 Range 的边界,Range 内部为 isize,所以 0..5 中的 0 和 5 会拓宽为 isize)。 +字面量拓宽仅适用于整数字面量直接出现在需要更宽整数类型的上下文 (如赋值给 i64 变量,或作为 Range 的边界,Range 内部为 isize,所以 0..5 中的 0 和 5 会拓宽为 isize;字符 'c' 同视为整数字面量)。 所有其他未列出的类型转换均需显式 as。 @@ -811,7 +826,7 @@ FLOAT -> f64 true / false -> bool -null -> 必须从上下文推导出 ?T,无法推导则报错。 +null -> 必须从上下文推导出 *T 或 []T 的空值 (当前无 ?T),用于比较/赋值/字段;无法推导或用于非指针上下文则报错。 字符串字面量 -> []u8 (具体待定) @@ -936,7 +951,7 @@ ForRange 提供表达式列表 [E1, E2, ...]。as 后标识符列表 [v1, v2, .. 对于 Ei: -若为 Range: 每次迭代产出的值类型为 isize (Range 的边界类型,这里默认为 isize)。 +若为 Range: 每次迭代产出的值类型为 Range 的边界整数类型 (即 begin/end 的类型,默认 isize 或 usize)。 若为 []T 或 [N]T: 产出元素类型为 T。 @@ -946,7 +961,7 @@ ForRange 提供表达式列表 [E1, E2, ...]。as 后标识符列表 [v1, v2, .. 长度协调规则: -若所有序列均为有界 (Range 有 end 不为 null,或切片长度已知),则循环次数为最短长度。 +若所有序列均为有界 (Range 有 end 非空值,或切片长度已知),则循环次数为最短长度。 若存在无界 Range (如 0..),则要求循环中至少有一个有界序列,且该有界序列的长度将作为无界序列的上限。例如 for slice, 0.. as elem, idx,0.. 的长度由 slice.len 决定。 @@ -960,8 +975,6 @@ for my_slice, 0.. as elem, idx { ... } // 0..: Range 无界 -> idx: i64,长度由 my_slice 决定 ``` ## 类型系统限制 -无隐式类型提升 (除字面量整数拓宽和数组到切片外)。 - 无默认初始化: var x: T; 不初始化,警告/错误。 无隐式 deref 多级: . 仅自动解引用一层。 @@ -1008,7 +1021,7 @@ Function ← AttributeList? 'func' GLOBAL_IDENT '(' ParamDefs? ')' '->' Type AttributeList ← Attribute (',' Attribute)* Attribute ← '!' IDENTIFIER ( '(' Args? ')' )? // 标记,如 !export("C") -GLOBAL_IDENT ← '@' IDENTIFIER +GLOBAL_IDENT ← IDENTIFIER ParamDefs ← LOCAL_IDENT ':' Type (',' LOCAL_IDENT ':' Type)* Block ← '{' Stmt* '}' @@ -1153,6 +1166,7 @@ CONSTANT ← INTEGER | FLOAT | STRING | 'true' | 'false' | 'null' | 'undefine @control.br(bool, label, label) -> ! 条件分支:根据第一个参数跳转到第二或第三个(标签或者地址)。终止函数 (调用后控制流不返回)。 @control.jmp(label) -> ! 无条件跳转(跳转到标签或者地址)。终止函数。 @control.call(FT)(%fn:FT, %args...) -> %ret 按目标平台调用约定调用函数指针 %fn,FT 为 fnret_type> +@control.param(T)(%idx: usize) -> T 返回idx的函数参数(编译期检查是否越界) @control.ret(T)(%val?) 按目标平台调用约定从当前函数返回,T 为返回值类型,void 时不带参数 @control.unreachable() -> ! 标记不可达代码 @control.trap() -> ! 触发运行时陷阱 diff --git a/project_desc.py b/project_desc.py index d9ac56c..8302ad0 100644 --- a/project_desc.py +++ b/project_desc.py @@ -1,22 +1,22 @@ vm = [ - "stage0/spl_ir.c", + "stage0/spl_mcode.c", "stage0/spl_syscall.c", "stage0/spl_vm.c", ] splc0_part = [ - "stage1/spl_comp.c", + "stage1/spl_ir.c", + "stage1/spl_ast.c", "stage1/spl_lexer.c", + "stage1/spl_dumptree.c", "stage1/spl_type.c", - "stage1/spl_parser.c", - "stage1/spl_lex_util.c", - "stage1/spl_expr.c", - "stage1/spl_stmt.c", + "stage1/spl_sema.c", + "stage1/spl_ast2ir.c", ] exe = { "spl_cli": ["stage0/spl_cli.c"] + vm, - "splc_cli": ["stage1/splc_cli.c"] + vm + splc0_part, + "splc_cli": ["stage1/splc_cli.c"] + vm, "splc0": ["stage1/splc0.c"] + vm + splc0_part, "test": ["stage0/test_spl_vm.c"] + vm, "spl_disasm": ["stage0/spl_disasm.c"] + vm, diff --git a/stage1/spl_ast.c b/stage1/spl_ast.c index ec0468b..f524a0e 100644 --- a/stage1/spl_ast.c +++ b/stage1/spl_ast.c @@ -151,7 +151,8 @@ 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; - LOG_FATAL("%s:%llu:%llu: error: %s", fn, (unsigned long long)line, (unsigned long long)col, msg); + 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) { diff --git a/stage1/spl_ast.h b/stage1/spl_ast.h index de66679..39725b9 100644 --- a/stage1/spl_ast.h +++ b/stage1/spl_ast.h @@ -35,6 +35,8 @@ typedef VEC(spl_ast_node_ref_t) spl_ast_node_ref_vec_t; struct spl_ast_node { spl_ast_node_kind_t kind; spl_ast_loc_t loc; + + usize resolved_def_id; union { struct { spl_ast_node_ref_vec_t attr_list; /* attr_item */ diff --git a/stage1/spl_ast2ir.c b/stage1/spl_ast2ir.c index f34279c..60ae5ce 100644 --- a/stage1/spl_ast2ir.c +++ b/stage1/spl_ast2ir.c @@ -1 +1,2880 @@ +/* spl_ast2ir.c AST IR lowering + * + * 设计要点 * - 名称解析自包含:局部变类型用自身环境栈;顶层类函数sema root scope 与聚合成员表 * - + * 变量落在内存槽(@mem.alloca),写走 @mem.load/store;表达式临时值为 SSA * - 控制流用"块表 + + * fixup 补丁":分跳转目标在函数末尾回填为块首指令node ref * - + * 聚合字段访问:读@agg.extract,写字节地址直写"(@mem.offset + @mem.store) * - 枚举= + * agg.construct(enum)([tag, payload?]);match tag 分发 * - defer 按作用域逆序执行(正常退/ ret / + * break / continue 全覆盖) */ + #include "spl_ast2ir.h" + +#include +#include +#include + +/* ================================================================ + * 基础访问 + * ================================================================ */ + +static spl_ast_node_t *node_at(const spl_sema_t *sema, spl_ast_node_ref_t ref) { + if (!ref || ref >= sema->ast->buckets.size) + return NULL; + return &sema->ast->buckets.data[ref]; +} + +static spl_type_node_t *tn(const spl_sema_t *sema, spl_type_id_t tid) { + return spl_type_node((spl_type_t *)&sema->type, tid); +} + +static spl_def_node_t *def_at(const spl_sema_t *sema, spl_def_id_t id) { + return spl_type_def((spl_type_t *)&sema->type, id); +} + +static spl_type_id_t underlying(const spl_sema_t *sema, spl_type_id_t tid) { + spl_type_node_t *t = tn(sema, tid); + return (t && t->kind == SPL_TYPE_ID) ? t->type_id : tid; +} + +static int type_same(const 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 = tn(sema, a); + spl_type_node_t *nb = tn(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; + } +} + +static int is_int_type(const spl_sema_t *sema, spl_type_id_t tid) { + spl_type_node_t *t = tn(sema, underlying(sema, tid)); + return t && t->kind == SPL_TYPE_INT; +} +static int is_float_type(const spl_sema_t *sema, spl_type_id_t tid) { + spl_type_node_t *t = tn(sema, underlying(sema, tid)); + return t && t->kind == SPL_TYPE_FLOAT; +} +static int is_num_type(const spl_sema_t *sema, spl_type_id_t tid) { + spl_type_node_t *t = tn(sema, underlying(sema, tid)); + return t && (t->kind == SPL_TYPE_INT || t->kind == SPL_TYPE_FLOAT); +} +static int is_ptr_type(const spl_sema_t *sema, spl_type_id_t tid) { + spl_type_node_t *t = tn(sema, underlying(sema, tid)); + return t && t->kind == SPL_TYPE_PTR; +} + +/* ---- 符号解析 ---- */ + +static spl_type_id_t agg_field_tid_at(spl_ast2ir_t *a, spl_type_id_t agg_tid, isize idx); + +static spl_type_id_t kw_type(spl_ast2ir_t *a, const char *name) { + spl_def_id_t def = 0; + if (map_get(a->sema->scopes.data[a->sema->root_scope].symbols, name, &def)) { + spl_def_node_t *d = def_at(a->sema, def); + if (d) + return d->type_id; + } + return 0; +} + +static spl_def_id_t root_lookup(spl_ast2ir_t *a, const char *name) { + spl_def_id_t def = 0; + if (map_get(a->sema->scopes.data[a->sema->root_scope].symbols, name, &def)) + return def; + return 0; +} + +/* 匿名类型 id 拥有它的 def(聚合优先,别名/distinct 兜底*/ +static spl_def_id_t def_for_type(spl_ast2ir_t *a, spl_type_id_t tid) { + if (!tid) + return 0; + tid = underlying(a->sema, tid); + spl_def_id_t fallback = 0; + for (usize i = 1; i < a->sema->type.def_table.size; i++) { + spl_def_node_t *d = &a->sema->type.def_table.data[i]; + spl_type_id_t dt = underlying(a->sema, d->type_id); + if (dt == 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; +} + +/* 判断 agg_def 条目是否为结构字段(SPL_DEF_MEMBER) */ +static int agg_entry_is_field(spl_ast2ir_t *a, const spl_var_def_t *e) { + if (!e->def_id) + return 0; + spl_def_node_t *ed = def_at(a->sema, e->def_id); + return ed && ed->kind == SPL_DEF_MEMBER; +} + +/* 命名空间成员类型(方法/嵌套类型/static var):按名任意 kind */ +static spl_type_id_t agg_member_type(spl_ast2ir_t *a, spl_type_id_t agg_tid, const char *name) { + agg_tid = underlying(a->sema, agg_tid); + spl_def_id_t d = def_for_type(a, agg_tid); + if (!d) + return 0; + spl_def_node_t *def = def_at(a->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; +} + +/* 结构字段序号 = 相对 SPL_DEF_MEMBER 的位置(与 type.agg_field_types 按序对齐) */ +static isize agg_member_index(spl_ast2ir_t *a, spl_type_id_t agg_tid, const char *name) { + agg_tid = underlying(a->sema, agg_tid); + spl_def_id_t d = def_for_type(a, agg_tid); + if (!d) + return -1; + spl_def_node_t *def = def_at(a->sema, d); + isize fidx = 0; + for (usize i = 0; i < def->agg_def.size; i++) { + spl_var_def_t *e = &def->agg_def.data[i]; + int is_field = agg_entry_is_field(a, e); + if (is_field && e->name && strcmp(e->name, name) == 0) + return fidx; + if (is_field) + fidx++; + } + /* 字段访问只认结构字段(MEMBER_DECL);var/fn/type 成员是命名空间实体,不在此列 */ + return -1; +} + +static spl_type_id_t agg_field_tid_at(spl_ast2ir_t *a, spl_type_id_t agg_tid, isize idx) { + spl_type_node_t *t = tn(a->sema, underlying(a->sema, agg_tid)); + if (!t || (t->kind != SPL_TYPE_STRUCT && t->kind != SPL_TYPE_UNION && t->kind != SPL_TYPE_ENUM)) + return 0; + if (idx >= 0 && (usize)idx < t->agg_field_types.size) + return t->agg_field_types.data[idx]; + if (t->kind == SPL_TYPE_ENUM && idx >= 0 && (usize)idx < t->enum_type.variants.size) { + spl_type_id_t v = underlying(a->sema, t->enum_type.variants.data[idx]); + return (v == underlying(a->sema, agg_tid)) ? 0 : v; + } + return 0; +} + +/* 按字段序号查成员名(agg_def 中第 idx 个 SPL_DEF_MEMBER 条目) */ +static const char *agg_field_name_at(spl_ast2ir_t *a, spl_type_id_t agg_tid, isize idx) { + agg_tid = underlying(a->sema, agg_tid); + spl_def_id_t d = def_for_type(a, agg_tid); + if (!d) + return NULL; + spl_def_node_t *def = def_at(a->sema, d); + isize fidx = 0; + for (usize i = 0; i < def->agg_def.size; i++) { + spl_var_def_t *e = &def->agg_def.data[i]; + if (agg_entry_is_field(a, e)) { + if (fidx == idx) + return e->name; + fidx++; + } + } + return NULL; +} + +/* 切片/区间内置字段(ptr/len/begin/end)并入成员查*/ +static isize agg_index_or_builtin(spl_ast2ir_t *a, spl_type_id_t agg_tid, const char *name) { + spl_type_node_t *t = tn(a->sema, underlying(a->sema, agg_tid)); + if (t && t->kind == SPL_TYPE_SLICE) { + if (strcmp(name, "ptr") == 0) + return 0; + if (strcmp(name, "len") == 0) + return 1; + } + if (t && t->kind == SPL_TYPE_RANGE) { + if (strcmp(name, "begin") == 0) + return 0; + if (strcmp(name, "end") == 0) + return 1; + } + return agg_member_index(a, agg_tid, name); +} + +static spl_type_id_t agg_field_tid_or_builtin(spl_ast2ir_t *a, spl_type_id_t agg_tid, isize idx) { + spl_type_node_t *t = tn(a->sema, underlying(a->sema, agg_tid)); + if (t && t->kind == SPL_TYPE_SLICE) { + if (idx == 0) + return spl_type_ptr((spl_type_t *)&a->sema->type, t->slice_element); + if (idx == 1) + return kw_type(a, "usize"); + } + if (t && t->kind == SPL_TYPE_RANGE) + return t->range_element; + return agg_field_tid_at(a, agg_tid, idx); +} + +/* ================================================================ + * 类型布局(sizeof / alignof / offsetof * + * ================================================================ */ + +static usize align_up(usize v, usize a) { return (v + a - 1) & ~(a - 1); } + +static usize type_align(const spl_sema_t *sema, spl_type_id_t tid) { + spl_type_node_t *t = tn(sema, underlying(sema, tid)); + if (!t) + return 1; + switch (t->kind) { + case SPL_TYPE_VOID: + return 1; + case SPL_TYPE_BOOL: + return 1; + case SPL_TYPE_INT: + return t->int_type.bits / 8; + case SPL_TYPE_FLOAT: + return t->float_type.bits / 8; + case SPL_TYPE_PTR: + case SPL_TYPE_FN: + return sizeof(usize); + case SPL_TYPE_SLICE: + case SPL_TYPE_RANGE: + return sizeof(usize); + case SPL_TYPE_ARRAY: + return type_align(sema, t->array_type.element); + case SPL_TYPE_STRUCT: { + usize a = 1; + for (usize i = 0; i < t->agg_field_types.size; i++) { + usize fa = type_align(sema, t->agg_field_types.data[i]); + if (fa > a) + a = fa; + } + return a; + } + case SPL_TYPE_UNION: { + usize a = 1; + for (usize i = 0; i < t->agg_field_types.size; i++) { + usize fa = type_align(sema, t->agg_field_types.data[i]); + if (fa > a) + a = fa; + } + return a; + } + case SPL_TYPE_ENUM: + return sizeof(usize); + default: + return 1; + } +} + +static usize type_size(const spl_sema_t *sema, spl_type_id_t tid) { + spl_type_node_t *t = tn(sema, underlying(sema, tid)); + if (!t) + return 0; + switch (t->kind) { + case SPL_TYPE_VOID: + return 0; + case SPL_TYPE_BOOL: + return 1; + case SPL_TYPE_INT: + return t->int_type.bits / 8; + case SPL_TYPE_FLOAT: + return t->float_type.bits / 8; + case SPL_TYPE_PTR: + case SPL_TYPE_FN: + return sizeof(usize); + case SPL_TYPE_SLICE: + return sizeof(usize) * 2; + case SPL_TYPE_RANGE: + return sizeof(usize) * 2; + case SPL_TYPE_ARRAY: + return t->array_type.len * type_size(sema, t->array_type.element); + case SPL_TYPE_STRUCT: { + usize sz = 0; + for (usize i = 0; i < t->agg_field_types.size; i++) { + usize fa = type_align(sema, t->agg_field_types.data[i]); + sz = align_up(sz, fa); + sz += type_size(sema, t->agg_field_types.data[i]); + } + return sz; + } + case SPL_TYPE_UNION: { + usize sz = 0; + for (usize i = 0; i < t->agg_field_types.size; i++) { + usize fs = type_size(sema, t->agg_field_types.data[i]); + if (fs > sz) + sz = fs; + } + return sz; + } + case SPL_TYPE_ENUM: { + usize payload = 0; + for (usize i = 0; i < t->enum_type.variants.size; i++) { + spl_type_id_t v = underlying(sema, t->enum_type.variants.data[i]); + if (v == underlying(sema, tid)) + continue; + usize vs = type_size(sema, v); + if (vs > payload) + payload = vs; + } + return sizeof(usize) + payload; + } + default: + return 0; + } +} + +/* 聚合字段字节偏移(struct 顺序对齐;union/enum 偏移 0;slice/range 内置字段*/ +static usize type_field_offset(const spl_sema_t *sema, spl_type_id_t agg_tid, isize idx) { + spl_type_node_t *t = tn(sema, underlying(sema, agg_tid)); + if (!t) + return 0; + if (t->kind == SPL_TYPE_SLICE || t->kind == SPL_TYPE_RANGE) + return (usize)idx * sizeof(usize); + if ((usize)idx >= t->agg_field_types.size) + return 0; + switch (t->kind) { + case SPL_TYPE_STRUCT: { + usize off = 0; + for (isize i = 0; i < idx; i++) { + usize fa = type_align(sema, t->agg_field_types.data[i]); + off = align_up(off, fa); + off += type_size(sema, t->agg_field_types.data[i]); + } + return align_up(off, type_align(sema, t->agg_field_types.data[idx])); + } + case SPL_TYPE_UNION: + case SPL_TYPE_ENUM: + default: + return 0; + } +} + +/* ================================================================ + * IR 发射(per-function 上下文) + * ================================================================ */ + +typedef struct { + const char *name; + spl_def_id_t def_id; /* 0 = 未知(名字兜底) */ + spl_type_id_t tid; + spl_ir_node_ref_t slot; /* 0 = 非内存绑*/ + spl_ir_node_ref_t value; /* SSA 值绑*/ + int is_type; + int mut; +} ir_env_t; +typedef struct { + VEC(ir_env_t) syms; + VEC(spl_ast_node_ref_t) defers; /* 本作用域defer */ +} ir_env_scope_t; +typedef VEC(ir_env_scope_t) ir_env_stack_t; + +typedef struct { + spl_ir_node_ref_t first; +} ir_block_t; +typedef VEC(ir_block_t) ir_block_vec_t; + +typedef struct { + spl_ir_node_ref_t node; + int slot; /* 0=true_label 1=false_label 2=jmp.label */ + usize block; +} ir_fix_t; +typedef VEC(ir_fix_t) ir_fix_vec_t; + +typedef struct { + usize brk; + usize cont; + usize env_mark; /* 循环体作用域起始下标(defer 边界*/ +} ir_loop_t; +typedef VEC(ir_loop_t) ir_loop_vec_t; + +typedef struct { + spl_ir_func_ref_t fn; + spl_type_id_t ret_tid; + spl_type_id_t ns_tid; /* 所在聚合类型(方法命名空间);顶层0 */ + ir_env_stack_t env; + ir_block_vec_t blocks; + usize cur_block; + ir_fix_vec_t fixups; + ir_loop_vec_t loops; + VEC(spl_type_id_t) types; /* nodes 平行的结果类型表 */ + int terminated; + spl_type_id_t hint; + int err; +} fnctx_t; + +static void fc_init(fnctx_t *fc, spl_ir_func_ref_t fn, spl_type_id_t ret) { + memset(fc, 0, sizeof *fc); + fc->fn = fn; + fc->ret_tid = ret; + vec_init(fc->env); + vec_init(fc->blocks); + vec_init(fc->fixups); + vec_init(fc->loops); + vec_init(fc->types); +} + +static void fc_init_ns(fnctx_t *fc, spl_ir_func_ref_t fn, spl_type_id_t ret, spl_type_id_t ns) { + fc_init(fc, fn, ret); + fc->ns_tid = ns; +} + +static void fc_drop(fnctx_t *fc) { + for (usize i = 0; i < fc->env.size; i++) { + vec_free(fc->env.data[i].syms); + vec_free(fc->env.data[i].defers); + } + vec_free(fc->env); + vec_free(fc->blocks); + vec_free(fc->fixups); + vec_free(fc->loops); + vec_free(fc->types); +} + +static void diag(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref, const char *msg) { + spl_ast_node_t *n = node_at(a->sema, ref); + fc->err++; + if (n) + LOG_WARN("ast2ir: %s (%s:%d:%d)", msg, n->loc.fname ? n->loc.fname : "?", n->loc.line, + n->loc.col); + else + LOG_WARN("ast2ir: %s [fn=%s]", msg, + spl_ir_func(&a->ir, fc->fn)->name ? spl_ir_func(&a->ir, fc->fn)->name : "?"); +} + +static spl_ir_node_ref_t emit_node(spl_ast2ir_t *a, fnctx_t *fc) { + if (fc->terminated) { + ir_block_t b; + memset(&b, 0, sizeof b); + vec_push(fc->blocks, b); + fc->cur_block = fc->blocks.size - 1; + fc->terminated = 0; + } + spl_ir_node_ref_t r = spl_ir_alloc_node(&a->ir, fc->fn); + if (fc->cur_block < fc->blocks.size && !fc->blocks.data[fc->cur_block].first) + fc->blocks.data[fc->cur_block].first = r; + if (fc->types.size == 0) { + spl_type_id_t t0 = 0; + vec_push(fc->types, t0); + } + spl_type_id_t t1 = 0; + vec_push(fc->types, t1); + return r; +} + +static spl_ir_node_t *enode(spl_ast2ir_t *a, fnctx_t *fc, spl_ir_node_ref_t r) { + return spl_ir_node(&a->ir, fc->fn, r); +} + +static void set_ntype(fnctx_t *fc, spl_ir_node_ref_t r, spl_type_id_t tid) { + if (r && r < fc->types.size) + fc->types.data[r] = tid; +} + +static spl_type_id_t node_type(fnctx_t *fc, spl_ir_node_ref_t r) { + if (!r || r >= fc->types.size) + return 0; + return fc->types.data[r]; +} + +static usize new_block(fnctx_t *fc) { + ir_block_t b; + memset(&b, 0, sizeof b); + vec_push(fc->blocks, b); + return fc->blocks.size - 1; +} + +static void begin_block(fnctx_t *fc, usize id) { + fc->cur_block = id; + fc->terminated = 0; +} + +static void emit_jmp(spl_ast2ir_t *a, fnctx_t *fc, usize target) { + spl_ir_node_ref_t r = emit_node(a, fc); + spl_ir_node_t *n = enode(a, fc, r); + n->kind = SPL_IR_CONTROL_JMP; + n->control_jmp.label = 0; + ir_fix_t f = {r, 2, target}; + vec_push(fc->fixups, f); + fc->terminated = 1; +} + +static void emit_br(spl_ast2ir_t *a, fnctx_t *fc, spl_ir_node_ref_t cond, usize t, usize f) { + spl_ir_node_ref_t r = emit_node(a, fc); + spl_ir_node_t *n = enode(a, fc, r); + n->kind = SPL_IR_CONTROL_BR; + n->control_br.cond = cond; + n->control_br.true_label = 0; + n->control_br.false_label = 0; + ir_fix_t a1 = {r, 0, t}; + ir_fix_t a2 = {r, 1, f}; + vec_push(fc->fixups, a1); + vec_push(fc->fixups, a2); + fc->terminated = 1; +} + +static void emit_ret(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid, spl_ir_node_ref_t val) { + spl_ir_node_ref_t r = emit_node(a, fc); + spl_ir_node_t *n = enode(a, fc, r); + n->kind = SPL_IR_CONTROL_RET; + n->control_ret.tid = tid; + n->control_ret.val = val; + fc->terminated = 1; +} + +static spl_ir_node_ref_t emit_const(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid) { + spl_ir_node_ref_t r = emit_node(a, fc); + spl_ir_node_t *n = enode(a, fc, r); + n->kind = SPL_IR_TYPE_CONST; + n->type_const.tid = tid; + set_ntype(fc, r, tid); + return r; +} + +static spl_ir_node_ref_t const_int(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid, usize v) { + spl_ir_node_ref_t r = emit_const(a, fc, tid); + enode(a, fc, r)->type_const.int_lit = v; + return r; +} + +static spl_ir_node_ref_t const_bool(spl_ast2ir_t *a, fnctx_t *fc, int v) { + return const_int(a, fc, kw_type(a, "bool"), (usize)(v ? 1 : 0)); +} + +static spl_ir_node_ref_t const_float(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid, double v) { + spl_ir_node_ref_t r = emit_const(a, fc, tid); + enode(a, fc, r)->type_const.float_lit = v; + return r; +} + +static spl_ir_node_ref_t const_str(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid, const char *s) { + spl_ir_node_ref_t r = emit_const(a, fc, tid); + enode(a, fc, r)->type_const.cstr_lit = s; + return r; +} + +static spl_ir_node_ref_t const_fnref(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t fn_tid, + spl_ir_func_ref_t fid) { + spl_ir_node_ref_t r = emit_const(a, fc, fn_tid); + enode(a, fc, r)->type_const.fn = fid; + return r; +} + +static spl_ir_node_ref_t emit_arith(spl_ast2ir_t *a, fnctx_t *fc, spl_ir_kind_t k, + spl_type_id_t tid, spl_ir_node_ref_t l, spl_ir_node_ref_t r) { + spl_ir_node_ref_t n = emit_node(a, fc); + spl_ir_node_t *e = enode(a, fc, n); + e->kind = k; + e->arith.tid = tid; + e->arith.left = l; + e->arith.right = r; + set_ntype(fc, n, tid); + return n; +} + +static spl_ir_node_ref_t emit_cmp(spl_ast2ir_t *a, fnctx_t *fc, spl_ir_kind_t k, spl_type_id_t tid, + spl_ir_node_ref_t x, spl_ir_node_ref_t y) { + spl_ir_node_ref_t n = emit_node(a, fc); + spl_ir_node_t *e = enode(a, fc, n); + e->kind = k; + e->cmp.tid = tid; + e->cmp.a = x; + e->cmp.b = y; + set_ntype(fc, n, kw_type(a, "bool")); + return n; +} + +static spl_ir_node_ref_t emit_cast(spl_ast2ir_t *a, fnctx_t *fc, spl_ir_kind_t k, + spl_type_id_t from, spl_type_id_t to, spl_ir_node_ref_t v) { + spl_ir_node_ref_t n = emit_node(a, fc); + spl_ir_node_t *e = enode(a, fc, n); + e->kind = k; + e->cast.from_tid = from; + e->cast.to_tid = to; + e->cast.val = v; + set_ntype(fc, n, to); + return n; +} + +static spl_ir_node_ref_t emit_alloca(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid) { + spl_ir_node_ref_t cnt = const_int(a, fc, kw_type(a, "usize"), 1); + spl_ir_node_ref_t n = emit_node(a, fc); + spl_ir_node_t *e = enode(a, fc, n); + e->kind = SPL_IR_MEM_ALLOCA; + e->mem_alloc.tid = tid; + e->mem_alloc.count = cnt; + spl_type_id_t pt = spl_type_ptr((spl_type_t *)&a->sema->type, tid); + set_ntype(fc, n, pt); + return n; +} + +static void emit_store(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid, spl_ir_node_ref_t ptr, + spl_ir_node_ref_t val) { + spl_ir_node_ref_t n = emit_node(a, fc); + spl_ir_node_t *e = enode(a, fc, n); + e->kind = SPL_IR_MEM_STORE; + e->mem_store.tid = tid; + e->mem_store.ptr = ptr; + e->mem_store.val = val; +} + +static spl_ir_node_ref_t emit_load(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid, + spl_ir_node_ref_t ptr) { + spl_ir_node_ref_t n = emit_node(a, fc); + spl_ir_node_t *e = enode(a, fc, n); + e->kind = SPL_IR_MEM_LOAD; + e->mem_load.tid = tid; + e->mem_load.ptr = ptr; + set_ntype(fc, n, tid); + return n; +} + +static spl_ir_node_ref_t emit_offset(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid, + spl_ir_node_ref_t ptr, spl_ir_node_ref_t off) { + spl_ir_node_ref_t n = emit_node(a, fc); + spl_ir_node_t *e = enode(a, fc, n); + e->kind = SPL_IR_MEM_OFFSET; + e->mem_offset.tid = tid; + e->mem_offset.ptr = ptr; + e->mem_offset.offset = off; + spl_type_id_t pt = spl_type_ptr((spl_type_t *)&a->sema->type, tid); + set_ntype(fc, n, pt); + return n; +} + +static spl_ir_node_ref_t emit_agg_construct(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid) { + spl_ir_node_ref_t n = emit_node(a, fc); + spl_ir_node_t *e = enode(a, fc, n); + e->kind = SPL_IR_AGG_CONSTRUCT; + e->agg_construct.tid = tid; + vec_init(e->agg_construct.fields); + set_ntype(fc, n, tid); + return n; +} + +static void agg_construct_add(spl_ast2ir_t *a, fnctx_t *fc, spl_ir_node_ref_t agg, + spl_ir_node_ref_t field) { + spl_ir_node_t *e = enode(a, fc, agg); + vec_push(e->agg_construct.fields, field); +} + +static spl_ir_node_ref_t emit_agg_extract(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid, + spl_type_id_t field_tid, isize fidx, + spl_ir_node_ref_t val) { + spl_ir_node_ref_t n = emit_node(a, fc); + spl_ir_node_t *e = enode(a, fc, n); + e->kind = SPL_IR_AGG_EXTRACT; + e->agg_extract.tid = tid; + e->agg_extract.field_idx = fidx; + e->agg_extract.val = val; + set_ntype(fc, n, field_tid); + return n; +} + +static spl_ir_node_ref_t emit_agg_insert(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid, + isize fidx, spl_ir_node_ref_t agg, + spl_ir_node_ref_t field) { + spl_ir_node_ref_t n = emit_node(a, fc); + spl_ir_node_t *e = enode(a, fc, n); + e->kind = SPL_IR_AGG_INSERT; + e->agg_insert.tid = tid; + e->agg_insert.field_idx = fidx; + e->agg_insert.agg = agg; + e->agg_insert.field = field; + set_ntype(fc, n, tid); + return n; +} + +static spl_ir_node_ref_t emit_call(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t fn_tid, + spl_ir_node_ref_t callee, spl_ir_node_ref_t *args, usize nargs) { + spl_ir_node_ref_t n = emit_node(a, fc); + spl_ir_node_t *e = enode(a, fc, n); + e->kind = SPL_IR_CONTROL_CALL; + e->control_call.tid = fn_tid; + e->control_call.func = callee; + vec_init(e->control_call.params); + for (usize i = 0; i < nargs; i++) + vec_push(e->control_call.params, args[i]); + spl_type_node_t *ft = tn(a->sema, fn_tid); + spl_type_id_t ret = (ft && ft->kind == SPL_TYPE_FN) ? ft->fn_type.ret : 0; + set_ntype(fc, n, ret); + return n; +} + +static spl_ir_node_ref_t emit_select(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid, + spl_ir_node_ref_t c, spl_ir_node_ref_t t, + spl_ir_node_ref_t f) { + spl_ir_node_ref_t n = emit_node(a, fc); + spl_ir_node_t *e = enode(a, fc, n); + e->kind = SPL_IR_CONTROL_SELECT; + e->control_select.tid = tid; + e->control_select.cond = c; + e->control_select.true_val = t; + e->control_select.false_val = f; + set_ntype(fc, n, tid); + return n; +} + +/* ================================================================ + * 环境(变类型绑定 * ================================================================ */ + +static void env_push(fnctx_t *fc) { + ir_env_scope_t s; + memset(&s, 0, sizeof s); + vec_init(s.syms); + vec_init(s.defers); + vec_push(fc->env, s); +} + +static void env_pop(fnctx_t *fc) { + if (!fc->env.size) + return; + vec_free(fc->env.data[fc->env.size - 1].syms); + vec_free(fc->env.data[fc->env.size - 1].defers); + vec_pop(fc->env); +} + +static ir_env_t *env_find(fnctx_t *fc, const char *name) { + for (usize i = fc->env.size; i > 0; i--) { + ir_env_scope_t *s = &fc->env.data[i - 1]; + for (usize j = 0; j < s->syms.size; j++) { + if (s->syms.data[j].name && strcmp(s->syms.data[j].name, name) == 0) + return &s->syms.data[j]; + } + } + return NULL; +} + +/* def_id 优先定位(sema 已作用域解析,绕开同名遮蔽歧义);无 def_id 时兜底名字 */ +static ir_env_t *env_find_def(fnctx_t *fc, spl_def_id_t def_id, const char *name) { + if (def_id) { + for (usize i = fc->env.size; i > 0; i--) { + ir_env_scope_t *s = &fc->env.data[i - 1]; + for (usize j = 0; j < s->syms.size; j++) { + if (s->syms.data[j].def_id == def_id) + return &s->syms.data[j]; + } + } + } + return name ? env_find(fc, name) : NULL; +} + +static void env_add(fnctx_t *fc, const char *name, spl_def_id_t def_id, spl_type_id_t tid, + spl_ir_node_ref_t slot, spl_ir_node_ref_t value, int is_type, int mut) { + if (!fc->env.size) + env_push(fc); + ir_env_t it; + memset(&it, 0, sizeof it); + it.name = name; + it.def_id = def_id; + it.tid = tid; + it.slot = slot; + it.value = value; + it.is_type = is_type; + it.mut = mut; + vec_push(fc->env.data[fc->env.size - 1].syms, it); +} + +/* ================================================================ + * 枚举 + * ================================================================ */ + +static spl_type_id_t enum_tag_tid(spl_ast2ir_t *a) { return kw_type(a, "usize"); } + +static isize enum_variant_index(spl_ast2ir_t *a, spl_type_id_t enum_tid, const char *name) { + enum_tid = underlying(a->sema, enum_tid); + spl_def_id_t d = def_for_type(a, enum_tid); + if (!d) + return -1; + spl_def_node_t *def = def_at(a->sema, d); + isize vidx = 0; + for (usize i = 0; i < def->agg_def.size; i++) { + spl_var_def_t *e = &def->agg_def.data[i]; + if (agg_entry_is_field(a, e)) { + if (e->name && strcmp(e->name, name) == 0) + return vidx; + vidx++; + } + } + return -1; +} + +static spl_type_id_t enum_payload_tid(spl_ast2ir_t *a, spl_type_id_t enum_tid, isize idx) { + enum_tid = underlying(a->sema, enum_tid); + spl_type_node_t *t = tn(a->sema, enum_tid); + if (!t || t->kind != SPL_TYPE_ENUM || idx < 0 || (usize)idx >= t->enum_type.variants.size) + return 0; + spl_type_id_t v = underlying(a->sema, t->enum_type.variants.data[idx]); + return (v == enum_tid) ? 0 : v; +} + +static spl_ir_node_ref_t enum_variant_value(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t enum_tid, + isize idx) { + spl_ir_node_ref_t agg = emit_agg_construct(a, fc, enum_tid); + agg_construct_add(a, fc, agg, const_int(a, fc, enum_tag_tid(a), (usize)idx)); + return agg; +} + +static spl_ir_node_ref_t enum_tag_of(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t enum_tid, + spl_ir_node_ref_t val) { + return emit_agg_extract(a, fc, enum_tid, enum_tag_tid(a), 0, val); +} + +/* 表达式当作类型引用解析(a / a.b.c,用于枚举变嵌套类型路径*/ +static spl_type_id_t type_of_type_ref(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t bref) { + spl_ast_node_t *n = node_at(a->sema, bref); + if (!n || n->kind != SPL_AST_EXPR) + return 0; + if (n->expr.op == SPL_AST_PRIMARY_EXPR) { + spl_ast_node_t *pn = node_at(a->sema, n->expr.op_expr.left); + if (pn && pn->primary_expr.kind == SPL_AST_IDENT) { + ir_env_t *it = env_find_def(fc, pn->resolved_def_id, pn->primary_expr.ident); + if (it && it->is_type) + return underlying(a->sema, it->tid); + spl_def_id_t def = root_lookup(a, pn->primary_expr.ident); + if (def) { + spl_def_node_t *d = def_at(a->sema, def); + if (d && d->type_id) + return underlying(a->sema, d->type_id); + } + } + return 0; + } + if (n->expr.op == SPL_AST_POSTFIX_EXPR) { + spl_ast_node_t *pf = node_at(a->sema, n->expr.op_expr.left); + if (pf && pf->postfix_expr.kind == SPL_AST_FIELD_EXPR) { + spl_type_id_t bt = type_of_type_ref(a, fc, pf->postfix_expr.primary_expr); + if (bt) { + spl_type_id_t mt = agg_member_type(a, bt, pf->postfix_expr.field_expr); + return underlying(a->sema, mt); + } + } + return 0; + } + return 0; +} + +/* ================================================================ + * 类型解析(自包含 * ================================================================ */ + +static spl_type_id_t resolve_type_expr(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref); + +static spl_type_id_t resolve_type_atom(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref) { + spl_ast_node_t *n = node_at(a->sema, ref); + if (!n) + return 0; + switch (n->type_atom.kind) { + case SPL_AST_TYPE_VOID: + return kw_type(a, "void"); + case SPL_AST_TYPE_BOOL: + return kw_type(a, "bool"); + case SPL_AST_TYPE_I8: + return kw_type(a, "i8"); + case SPL_AST_TYPE_U8: + return kw_type(a, "u8"); + case SPL_AST_TYPE_I16: + return kw_type(a, "i16"); + case SPL_AST_TYPE_U16: + return kw_type(a, "u16"); + case SPL_AST_TYPE_I32: + return kw_type(a, "i32"); + case SPL_AST_TYPE_U32: + return kw_type(a, "u32"); + case SPL_AST_TYPE_I64: + return kw_type(a, "i64"); + case SPL_AST_TYPE_U64: + return kw_type(a, "u64"); + case SPL_AST_TYPE_ISIZE: + return kw_type(a, "isize"); + case SPL_AST_TYPE_USIZE: + return kw_type(a, "usize"); + case SPL_AST_TYPE__F32: + return kw_type(a, "f32"); + case SPL_AST_TYPE__F64: + return kw_type(a, "f64"); + case SPL_AST_TYPE_PTR: + case SPL_AST_TYPE_ANY: + return kw_type(a, "void"); + case SPL_AST_TYPE_IDENT: { + const char *name = n->type_atom.ident; + ir_env_t *it = env_find(fc, name); + if (it && it->is_type) + return it->tid; + spl_def_id_t def = root_lookup(a, name); + if (def) { + spl_def_node_t *d = def_at(a->sema, def); + if (d && d->type_id) + return d->type_id; + } + return 0; + } + } + return 0; +} + +static spl_type_id_t resolve_type_path(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_vec_t *path) { + if (!path->size) + return 0; + spl_type_id_t tid = resolve_type_atom(a, fc, path->data[0]); + if (!tid) + return 0; + for (usize i = 1; i < path->size; i++) { + spl_ast_node_t *atom = node_at(a->sema, path->data[i]); + if (!atom) + return 0; + spl_type_id_t mt = agg_member_type(a, tid, atom->type_atom.ident); + if (!mt) + return 0; + tid = mt; + } + return tid; +} + +static spl_type_id_t resolve_type_expr(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref) { + spl_ast_node_t *n = node_at(a->sema, ref); + if (!n) + return 0; + /* 首选 sema 注解:resolved_def_id → def → 类型(聚合/别名/命名类型) */ + if (n->resolved_def_id) { + spl_def_node_t *d = def_at(a->sema, n->resolved_def_id); + if (d && d->type_id) + return d->type_id; + } + /* 兜底:组合/内置类型(sema 不为其建 def 的 *T、[]T、fn(...)、关键字、别名到组合) */ + spl_type_id_t base = 0; + switch (n->type_expr.kind) { + case SPL_AST_BASE_TYPE_PATH: + base = resolve_type_path(a, fc, &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(a->sema, 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(a, fc, 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(a, fc, n->type_expr.fn_type.type_expr); + else + ret = kw_type(a, "void"); + base = spl_type_fn((spl_type_t *)&a->sema->type, params, ret); + break; + } + case SPL_AST_TYPE_STRUCT: + case SPL_AST_TYPE_UNION: + case SPL_AST_TYPE_ENUM: + /* 内联聚合不应走到这里(sema 已注解其 def);防御性报错 */ + diag(a, fc, ref, "inline aggregate not annotated by sema"); + return 0; + default: + return 0; + } + for (usize i = n->type_expr.type_prefixs.size; i > 0; i--) { + spl_ast_node_t *pf = node_at(a->sema, n->type_expr.type_prefixs.data[i - 1]); + if (!pf) + continue; + if (pf->prefix_type.pointer == 1) + base = spl_type_ptr((spl_type_t *)&a->sema->type, base); + else if (pf->prefix_type.pointer == 2) { + if (pf->prefix_type.array_size > 0) + base = spl_type_array((spl_type_t *)&a->sema->type, base, + (usize)pf->prefix_type.array_size); + else + base = spl_type_slice((spl_type_t *)&a->sema->type, base); + } + } + return base; +} + +/* ================================================================ + * 表达 * ================================================================ */ + +static spl_ir_node_ref_t lower_expr(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref); +static void lower_stmt(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref); +static void emit_scope_defers(spl_ast2ir_t *a, fnctx_t *fc, usize scope_idx); +static void emit_defers_from(spl_ast2ir_t *a, fnctx_t *fc, usize mark); +static spl_ir_func_ref_t a2ir_fn_of(spl_ast2ir_t *a, spl_type_id_t fn_tid); +static spl_ir_node_ref_t lower_compound_op(spl_ast2ir_t *a, fnctx_t *fc, int op, spl_type_id_t tid, + spl_ir_node_ref_t cur, spl_ir_node_ref_t rhs); + +static int expr_is_int_literal(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { + spl_ast_node_t *n = node_at(a->sema, ref); + if (!n || n->kind != SPL_AST_EXPR) + return 0; + switch (n->expr.op) { + case SPL_AST_PRIMARY_EXPR: { + spl_ast_node_t *pn = node_at(a->sema, n->expr.op_expr.left); + return pn && pn->primary_expr.kind == SPL_AST_INTEGER; + } + case SPL_AST_PREFIX_EXPR: { + spl_ast_node_t *pf = node_at(a->sema, n->expr.op_expr.left); + if (pf && pf->prefix_expr.kind == SPL_AST_MINUS_EXPR) + return expr_is_int_literal(a, pf->prefix_expr.postfix_expr); + return 0; + } + default: + return 0; + } +} + +static spl_ir_node_ref_t coerce_to(spl_ast2ir_t *a, fnctx_t *fc, spl_ir_node_ref_t v, + spl_type_id_t from, spl_type_id_t to) { + if (!v || !from || !to) + return v; + if (type_same(a->sema, from, to)) + return v; + spl_type_id_t f = underlying(a->sema, from); + spl_type_id_t t = underlying(a->sema, to); + spl_type_node_t *ft = tn(a->sema, f); + spl_type_node_t *tt = tn(a->sema, t); + if (!ft || !tt) + return v; + if (ft->kind == SPL_TYPE_INT && tt->kind == SPL_TYPE_INT) { + if (ft->int_type.bits == tt->int_type.bits) + return v; + if (tt->int_type.bits > ft->int_type.bits) + return emit_cast(a, fc, ft->int_type.is_signed ? SPL_IR_CAST_SEXT : SPL_IR_CAST_ZEXT, + from, to, v); + return emit_cast(a, fc, SPL_IR_CAST_TRUNC, from, to, v); + } + if (ft->kind == SPL_TYPE_INT && tt->kind == SPL_TYPE_FLOAT) + return emit_cast(a, fc, SPL_IR_CASE_INT2FLOAT, from, to, v); + if (ft->kind == SPL_TYPE_FLOAT && tt->kind == SPL_TYPE_INT) + return emit_cast(a, fc, SPL_IR_CASE_FLOAT2INT, from, to, v); + if (ft->kind == SPL_TYPE_FLOAT && tt->kind == SPL_TYPE_FLOAT) + return emit_cast(a, fc, + tt->float_type.bits > ft->float_type.bits ? SPL_IR_CAST_FEXT + : SPL_IR_CAST_FTRUNC, + from, to, v); + if (ft->kind == SPL_TYPE_PTR && tt->kind == SPL_TYPE_PTR) + return emit_cast(a, fc, SPL_IR_CAST_BITCAST, from, to, v); + if (ft->kind == SPL_TYPE_PTR && tt->kind == SPL_TYPE_INT) + return emit_cast(a, fc, SPL_IR_CAST_PTR2INT, from, to, v); + if (ft->kind == SPL_TYPE_INT && tt->kind == SPL_TYPE_PTR) + return emit_cast(a, fc, SPL_IR_CAST_INT2PTR, from, to, v); + if (ft->kind == SPL_TYPE_BOOL && tt->kind == SPL_TYPE_INT) + return emit_cast(a, fc, SPL_IR_CAST_BOOL2INT, from, to, v); + return v; +} + +/* ---- 左值地址 ---- */ + +#define MAX_FIELD_CHAIN 16 + +static spl_ir_node_ref_t lower_lvalue(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref, + spl_type_id_t *out_tid); + +/* 收集字段链(叶子在前):返回EXPR ref */ +static spl_ast_node_ref_t field_chain_base(spl_ast2ir_t *a, spl_ast_node_t *pf, const char **names, + int *n) { + *n = 0; + names[(*n)++] = pf->postfix_expr.field_expr; + spl_ast_node_ref_t bref = pf->postfix_expr.primary_expr; + spl_ast_node_t *base = node_at(a->sema, bref); + while (base && base->kind == SPL_AST_EXPR && base->expr.op == SPL_AST_POSTFIX_EXPR) { + spl_ast_node_t *bpf = node_at(a->sema, base->expr.op_expr.left); + if (!bpf || bpf->postfix_expr.kind != SPL_AST_FIELD_EXPR) + break; + if (*n >= MAX_FIELD_CHAIN) + break; + names[(*n)++] = bpf->postfix_expr.field_expr; + bref = bpf->postfix_expr.primary_expr; + base = node_at(a->sema, bref); + } + return bref; +} + +/* 指针按字节偏移(mem.offset u8 为单位即字节*/ +static spl_ir_node_ref_t ptr_add_bytes(spl_ast2ir_t *a, fnctx_t *fc, spl_ir_node_ref_t addr, + usize bytes) { + if (!bytes || !addr) + return addr; + spl_ir_node_ref_t c = const_int(a, fc, kw_type(a, "usize"), bytes); + return emit_offset(a, fc, kw_type(a, "u8"), addr, c); +} + +/* 字段链的存储地址(root.a.b 地址 + 字段类型*/ +static spl_ir_node_ref_t lower_field_address(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t bref, + spl_type_id_t *out_tid) { + spl_ast_node_t *n = node_at(a->sema, bref); + if (!n || n->kind != SPL_AST_EXPR || n->expr.op != SPL_AST_POSTFIX_EXPR) + return 0; + spl_ast_node_t *pf = node_at(a->sema, n->expr.op_expr.left); + if (!pf || pf->postfix_expr.kind != SPL_AST_FIELD_EXPR) + return 0; + const char *names[MAX_FIELD_CHAIN]; + int nf = 0; + spl_ast_node_ref_t root_ref = field_chain_base(a, pf, names, &nf); + spl_type_id_t cur_tid = 0; + spl_ir_node_ref_t addr = lower_lvalue(a, fc, root_ref, &cur_tid); + spl_type_node_t *curt = tn(a->sema, underlying(a->sema, cur_tid)); + if (curt && curt->kind == SPL_TYPE_PTR) { + cur_tid = underlying(a->sema, curt->ptr_pointee); + addr = emit_load(a, fc, cur_tid, addr); + } + if (!addr || !cur_tid) + return 0; + for (int i = nf - 1; i >= 0; i--) { + spl_type_node_t *ct = tn(a->sema, underlying(a->sema, cur_tid)); + if (!ct || (ct->kind != SPL_TYPE_STRUCT && ct->kind != SPL_TYPE_UNION && + ct->kind != SPL_TYPE_SLICE && ct->kind != SPL_TYPE_RANGE)) + return 0; + isize idx = agg_index_or_builtin(a, cur_tid, names[i]); + if (idx < 0) + return 0; + usize off = type_field_offset(a->sema, cur_tid, idx); + spl_type_id_t ft = agg_field_tid_or_builtin(a, cur_tid, idx); + if (off) + addr = ptr_add_bytes(a, fc, addr, off); + cur_tid = ft; + if (i > 0) { + spl_type_node_t *ftt = tn(a->sema, underlying(a->sema, cur_tid)); + if (ftt && ftt->kind == SPL_TYPE_PTR) { + cur_tid = underlying(a->sema, ftt->ptr_pointee); + addr = emit_load(a, fc, cur_tid, addr); + } + } + } + *out_tid = cur_tid; + return addr; +} + +/* a[i] 内联 postfix 节点 元素地址 */ +static spl_ir_node_ref_t index_addr(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *pf, + spl_type_id_t *elem) { + spl_ir_node_ref_t idx = lower_expr(a, fc, pf->postfix_expr.index_expr); + spl_ast_node_ref_t bref = pf->postfix_expr.primary_expr; + spl_type_id_t base_t = 0; + spl_ir_node_ref_t base_lv = lower_lvalue(a, fc, bref, &base_t); + spl_ir_node_ref_t base_addr = 0; + spl_type_id_t elem_t = 0; + spl_type_node_t *bt = NULL; + if (base_lv) { + bt = tn(a->sema, underlying(a->sema, base_t)); + } else { + spl_ir_node_ref_t v = lower_expr(a, fc, bref); + spl_type_id_t vt = underlying(a->sema, node_type(fc, v)); + spl_type_node_t *vtt = vt ? tn(a->sema, vt) : NULL; + if (vtt && vtt->kind == SPL_TYPE_PTR) { + base_addr = v; + base_t = vt; + bt = vtt; + } else if (vtt && vtt->kind == SPL_TYPE_SLICE) { + spl_type_id_t ep = spl_type_ptr((spl_type_t *)&a->sema->type, vtt->slice_element); + base_addr = emit_agg_extract(a, fc, vt, ep, 0, v); + base_t = vt; + bt = vtt; + } else if (vtt && vtt->kind == SPL_TYPE_ARRAY) { + spl_type_id_t fat = 0; + spl_ir_node_ref_t faddr = lower_field_address(a, fc, bref, &fat); + if (faddr) { + base_addr = faddr; + base_t = fat; + bt = tn(a->sema, underlying(a->sema, fat)); + } else { + diag(a, fc, 0, "index on non-addressable array value"); + return 0; + } + } else { + diag(a, fc, 0, "index requires array/slice/pointer"); + return 0; + } + } + if (bt && bt->kind == SPL_TYPE_ARRAY) { + base_addr = base_lv ? base_lv : base_addr; + elem_t = bt->array_type.element; + } else if (bt && bt->kind == SPL_TYPE_PTR) { + base_addr = base_lv ? emit_load(a, fc, base_t, base_lv) : base_addr; + elem_t = underlying(a->sema, bt->ptr_pointee); + } else if (bt && bt->kind == SPL_TYPE_SLICE) { + spl_ir_node_ref_t slv = base_lv ? emit_load(a, fc, base_t, base_lv) : base_addr; + elem_t = bt->slice_element; + spl_type_id_t ep = spl_type_ptr((spl_type_t *)&a->sema->type, elem_t); + base_addr = emit_agg_extract(a, fc, base_t, ep, 0, slv); + } else { + diag(a, fc, 0, "index requires array/slice/pointer"); + return 0; + } + if (!elem_t) { + diag(a, fc, 0, "index requires array/slice/pointer"); + return 0; + } + spl_ir_node_ref_t o = coerce_to(a, fc, idx, node_type(fc, idx), kw_type(a, "isize")); + spl_ir_node_ref_t addr = emit_offset(a, fc, elem_t, base_addr, o); + *elem = elem_t; + return addr; +} + +static spl_ir_node_ref_t lower_lvalue(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref, + spl_type_id_t *out_tid) { + spl_ast_node_t *n = node_at(a->sema, ref); + if (!n || n->kind != SPL_AST_EXPR) + return 0; + if (n->expr.op == SPL_AST_PRIMARY_EXPR) { + spl_ast_node_t *pn = node_at(a->sema, n->expr.op_expr.left); + if (pn && pn->primary_expr.kind == SPL_AST_IDENT) { + ir_env_t *it = env_find_def(fc, pn->resolved_def_id, pn->primary_expr.ident); + if (it && it->slot) { + *out_tid = it->tid; + return it->slot; + } + if (it) + diag(a, fc, ref, "not an addressable variable"); + return 0; + } + if (pn && pn->primary_expr.kind == SPL_AST_EXPR_EXPR) + return lower_lvalue(a, fc, pn->primary_expr.expr, out_tid); + return 0; + } + if (n->expr.op == SPL_AST_POSTFIX_EXPR) { + spl_ast_node_t *pf = node_at(a->sema, n->expr.op_expr.left); + if (!pf) + return 0; + if (pf->postfix_expr.kind == SPL_AST_DEREF_EXPR) { + spl_ir_node_ref_t p = lower_expr(a, fc, pf->postfix_expr.primary_expr); + spl_type_id_t pt = underlying(a->sema, node_type(fc, p)); + spl_type_node_t *tt = tn(a->sema, pt); + if (!tt || tt->kind != SPL_TYPE_PTR) { + diag(a, fc, ref, ".* requires pointer"); + return 0; + } + *out_tid = underlying(a->sema, tt->ptr_pointee); + return p; + } + if (pf->postfix_expr.kind == SPL_AST_INDEX_EXPR) + return index_addr(a, fc, pf, out_tid); + if (pf->postfix_expr.kind == SPL_AST_FIELD_EXPR) + return lower_field_address(a, fc, ref, out_tid); + return 0; + } + if (n->expr.op == SPL_AST_PREFIX_EXPR) { + spl_ast_node_t *pp = node_at(a->sema, n->expr.op_expr.left); + if (pp && pp->prefix_expr.kind == SPL_AST_ASTERISK_EXPR) { + spl_ir_node_ref_t p = lower_expr(a, fc, pp->prefix_expr.postfix_expr); + spl_type_id_t pt = underlying(a->sema, node_type(fc, p)); + spl_type_node_t *tt = tn(a->sema, pt); + if (!tt || tt->kind != SPL_TYPE_PTR) { + diag(a, fc, ref, "prefix * requires pointer"); + return 0; + } + *out_tid = underlying(a->sema, tt->ptr_pointee); + return p; + } + return 0; + } + return 0; +} + +static spl_ir_node_ref_t lower_ident(spl_ast2ir_t *a, fnctx_t *fc, const char *name, + spl_def_id_t def_id, spl_ast_node_ref_t ref) { + ir_env_t *it = env_find_def(fc, def_id, name); + if (it) { + if (it->is_type) { + diag(a, fc, ref, "type used as value"); + return 0; + } + if (it->slot) + return emit_load(a, fc, it->tid, it->slot); + return it->value; + } + spl_def_id_t def = root_lookup(a, name); + if (def) { + spl_def_node_t *d = def_at(a->sema, def); + if (d && + (d->kind == SPL_DEF_AGG || d->kind == SPL_DEF_ALIAS || d->kind == SPL_DEF_DISTINCT)) + diag(a, fc, ref, "type name used as value (aggregate member not supported)"); + else + diag(a, fc, ref, "undefined identifier"); + } else { + diag(a, fc, ref, "undefined identifier"); + } + return 0; +} + +static spl_type_id_t type_from_type_like(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref) { + spl_ast_node_t *n = node_at(a->sema, ref); + if (!n || n->kind != SPL_AST_EXPR) + return 0; + if (n->expr.op != SPL_AST_PRIMARY_EXPR) + return 0; + spl_ast_node_t *pn = node_at(a->sema, n->expr.op_expr.left); + if (!pn || pn->primary_expr.kind != SPL_AST_IDENT) + return 0; + ir_env_t *it = env_find_def(fc, pn->resolved_def_id, pn->primary_expr.ident); + if (it && it->is_type) + return it->tid; + spl_def_id_t def = root_lookup(a, pn->primary_expr.ident); + if (def) { + spl_def_node_t *d = def_at(a->sema, def); + if (d && d->type_id) + return d->type_id; + } + return 0; +} + +static spl_ir_node_ref_t lower_block_expr(spl_ast2ir_t *a, fnctx_t *fc, + spl_ast_node_ref_vec_t *items) { + env_push(fc); + spl_ir_node_ref_t result = 0; + for (usize i = 0; i < items->size; i++) { + spl_ast_node_t *b = node_at(a->sema, items->data[i]); + if (i + 1 == items->size && b && b->kind == SPL_AST_EXPR) { + spl_ir_node_ref_t v = lower_expr(a, fc, items->data[i]); + if (v && !fc->terminated) + result = v; + break; + } + lower_stmt(a, fc, items->data[i]); + } + if (!fc->terminated) + emit_scope_defers(a, fc, fc->env.size - 1); + env_pop(fc); + return result; +} + +static spl_ir_node_ref_t lower_primary(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *pn) { + switch (pn->primary_expr.kind) { + case SPL_AST_INTEGER: { + spl_type_id_t t = kw_type(a, "i32"); + if (fc->hint && is_int_type(a->sema, fc->hint)) + t = underlying(a->sema, fc->hint); + return const_int(a, fc, t, (usize)pn->primary_expr.integer_expr); + } + case SPL_AST_FLOAT: { + spl_type_id_t t = kw_type(a, "f64"); + if (fc->hint && is_float_type(a->sema, fc->hint)) + t = underlying(a->sema, fc->hint); + return const_float(a, fc, t, pn->primary_expr.float_expr); + } + case SPL_AST_CHAR_LIT: { + spl_type_id_t t = kw_type(a, "u8"); + if (fc->hint && is_int_type(a->sema, fc->hint)) + t = underlying(a->sema, fc->hint); + return const_int(a, fc, t, (usize)(unsigned char)pn->primary_expr.char_lit_expr); + } + case SPL_AST_STRING_LIT: { + spl_type_id_t u8 = kw_type(a, "u8"); + spl_type_id_t t = spl_type_ptr((spl_type_t *)&a->sema->type, u8); + return const_str(a, fc, t, pn->primary_expr.string_lit_expr); + } + case SPL_AST_TRUE: + case SPL_AST_FALSE: + return const_bool(a, fc, pn->primary_expr.kind == SPL_AST_TRUE); + case SPL_AST_NULL: { + spl_type_id_t ht = underlying(a->sema, fc->hint); + spl_type_node_t *htt = ht ? tn(a->sema, ht) : NULL; + if (htt && htt->kind == SPL_TYPE_SLICE) { + spl_ir_node_ref_t sl = emit_agg_construct(a, fc, ht); + spl_type_id_t ep = spl_type_ptr((spl_type_t *)&a->sema->type, htt->slice_element); + agg_construct_add(a, fc, sl, const_int(a, fc, ep, 0)); + agg_construct_add(a, fc, sl, const_int(a, fc, kw_type(a, "usize"), 0)); + return sl; + } + spl_type_id_t t = htt && htt->kind == SPL_TYPE_PTR + ? ht + : spl_type_ptr((spl_type_t *)&a->sema->type, kw_type(a, "void")); + return const_int(a, fc, t, 0); + } + case SPL_AST_IDENT: + return lower_ident(a, fc, pn->primary_expr.ident, pn->resolved_def_id, 0); + case SPL_AST_EXPR_EXPR: + return lower_expr(a, fc, pn->primary_expr.expr); + case SPL_AST_BLOCK_EXPR: + return lower_block_expr(a, fc, &pn->primary_expr.block_expr); + case SPL_AST_ARRAY_LIT: { + spl_type_id_t elem = resolve_type_expr(a, fc, pn->primary_expr.array_lit_expr.type_expr); + if (!elem) + elem = kw_type(a, "i32"); + spl_type_id_t arr = spl_type_array((spl_type_t *)&a->sema->type, elem, + (usize)pn->primary_expr.array_lit_expr.integer); + spl_ir_node_ref_t agg = emit_agg_construct(a, fc, arr); + for (usize i = 0; i < pn->primary_expr.array_lit_expr.expr_list.size; i++) { + fc->hint = elem; + spl_ir_node_ref_t v = + lower_expr(a, fc, pn->primary_expr.array_lit_expr.expr_list.data[i]); + fc->hint = 0; + v = coerce_to(a, fc, v, node_type(fc, v), elem); + agg_construct_add(a, fc, agg, v); + } + return agg; + } + case SPL_AST_ARGGREGATE_INIT: { + spl_type_id_t tid = 0; + if (pn->primary_expr.aggregate_init.name) { + spl_def_id_t def = root_lookup(a, pn->primary_expr.aggregate_init.name); + if (def) + tid = underlying(a->sema, def_at(a->sema, def)->type_id); + else { + ir_env_t *it = env_find(fc, pn->primary_expr.aggregate_init.name); + if (it && it->is_type) + tid = underlying(a->sema, it->tid); + } + } else { + spl_type_id_t hint_t = underlying(a->sema, fc->hint); + spl_type_node_t *htt = hint_t ? tn(a->sema, hint_t) : NULL; + if (!htt || (htt->kind != SPL_TYPE_STRUCT && htt->kind != SPL_TYPE_UNION && + htt->kind != SPL_TYPE_SLICE && htt->kind != SPL_TYPE_RANGE)) { + diag(a, fc, 0, "anonymous aggregate literal without context type"); + return 0; + } + spl_ir_node_ref_t agg = emit_agg_construct(a, fc, hint_t); + for (usize j = 0; j < pn->primary_expr.aggregate_init.expr.size; j++) { + spl_ast_node_t *item = + node_at(a->sema, pn->primary_expr.aggregate_init.expr.data[j]); + if (!item || !item->aggregate_init_item.ident) + continue; + isize fidx = agg_index_or_builtin(a, hint_t, item->aggregate_init_item.ident); + if (fidx < 0) { + diag(a, fc, 0, "unknown field in aggregate literal"); + continue; + } + spl_type_id_t ft = agg_field_tid_or_builtin(a, hint_t, fidx); + spl_ir_node_ref_t v = lower_expr(a, fc, item->aggregate_init_item.expr); + if (ft) + v = coerce_to(a, fc, v, node_type(fc, v), ft); + agg_construct_add(a, fc, agg, v); + } + return agg; + } + spl_type_node_t *tt = tn(a->sema, tid); + if (!tt) + return 0; + if (tt->kind == SPL_TYPE_ENUM) { + spl_ir_node_ref_t agg = emit_agg_construct(a, fc, tid); + for (usize j = 0; j < pn->primary_expr.aggregate_init.expr.size; j++) { + spl_ast_node_t *item = + node_at(a->sema, pn->primary_expr.aggregate_init.expr.data[j]); + if (!item || !item->aggregate_init_item.ident) + continue; + isize vidx = enum_variant_index(a, tid, item->aggregate_init_item.ident); + if (vidx < 0) { + diag(a, fc, 0, "unknown enum variant"); + continue; + } + agg_construct_add(a, fc, agg, const_int(a, fc, enum_tag_tid(a), (usize)vidx)); + if (item->aggregate_init_item.expr) { + spl_type_id_t pt = enum_payload_tid(a, tid, vidx); + fc->hint = pt; + spl_ir_node_ref_t pv = lower_expr(a, fc, item->aggregate_init_item.expr); + fc->hint = 0; + if (pt) + pv = coerce_to(a, fc, pv, node_type(fc, pv), pt); + agg_construct_add(a, fc, agg, pv); + } + } + return agg; + } + if (tt->kind != SPL_TYPE_STRUCT) { + diag(a, fc, 0, "aggregate literal target is not a struct"); + return 0; + } + spl_ir_node_ref_t agg = emit_agg_construct(a, fc, tid); + usize nfields = tt->agg_field_types.size; + for (usize i = 0; i < nfields; i++) { + const char *fname = agg_field_name_at(a, tid, (isize)i); + spl_ast_node_ref_t found = 0; + for (usize j = 0; j < pn->primary_expr.aggregate_init.expr.size; j++) { + spl_ast_node_t *item = + node_at(a->sema, pn->primary_expr.aggregate_init.expr.data[j]); + if (item && fname && item->aggregate_init_item.ident && + strcmp(item->aggregate_init_item.ident, fname) == 0) { + found = pn->primary_expr.aggregate_init.expr.data[j]; + break; + } + } + if (!found) { + agg_construct_add(a, fc, agg, const_int(a, fc, tt->agg_field_types.data[i], 0)); + continue; + } + spl_ast_node_t *item = node_at(a->sema, found); + fc->hint = tt->agg_field_types.data[i]; + spl_ir_node_ref_t v = lower_expr(a, fc, item->aggregate_init_item.expr); + fc->hint = 0; + v = coerce_to(a, fc, v, node_type(fc, v), tt->agg_field_types.data[i]); + agg_construct_add(a, fc, agg, v); + } + return agg; + } + case SPL_AST_BUILTIN_EXPR: { + const char *id = pn->primary_expr.builtin_expr.ident; + if (strcmp(id, "sizeof") == 0 && pn->primary_expr.builtin_expr.expr_list.size) { + spl_type_id_t t = + type_from_type_like(a, fc, pn->primary_expr.builtin_expr.expr_list.data[0]); + if (!t) { + diag(a, fc, 0, "sizeof: cannot resolve type"); + return 0; + } + spl_ir_node_ref_t n = emit_node(a, fc); + spl_ir_node_t *e = enode(a, fc, n); + e->kind = SPL_IR_TYPE_SIZEOF; + e->ir_sizeof.tid = t; + set_ntype(fc, n, kw_type(a, "usize")); + return n; + } + if (strcmp(id, "dbg") == 0) { + for (usize i = 0; i < pn->primary_expr.builtin_expr.expr_list.size; i++) + lower_expr(a, fc, pn->primary_expr.builtin_expr.expr_list.data[i]); + spl_ir_node_ref_t n = emit_node(a, fc); + spl_ir_node_t *e = enode(a, fc, n); + e->kind = SPL_IR_DBG_BREAKPOINT; + set_ntype(fc, n, kw_type(a, "void")); + return n; + } + diag(a, fc, 0, "unsupported builtin call"); + return 0; + } + default: + return 0; + } +} + +static spl_ir_node_ref_t lower_prefix(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *pf) { + switch (pf->prefix_expr.kind) { + case SPL_AST_MINUS_EXPR: { + spl_ir_node_ref_t v = lower_expr(a, fc, pf->prefix_expr.postfix_expr); + spl_type_id_t t = underlying(a->sema, node_type(fc, v)); + if (!is_num_type(a->sema, t)) { + diag(a, fc, 0, "unary minus requires numeric"); + return 0; + } + return emit_arith(a, fc, SPL_IR_ARITH_NEG, t, v, 0); + } + case SPL_AST_BANG_EXPR: { + spl_ir_node_ref_t v = lower_expr(a, fc, pf->prefix_expr.postfix_expr); + spl_ir_node_ref_t z = const_bool(a, fc, 0); + return emit_cmp(a, fc, SPL_IR_CMP_EQ, kw_type(a, "bool"), v, z); + } + case SPL_AST_TILDE_EXPR: { + spl_ir_node_ref_t v = lower_expr(a, fc, pf->prefix_expr.postfix_expr); + spl_type_id_t t = underlying(a->sema, node_type(fc, v)); + if (!is_int_type(a->sema, t)) { + diag(a, fc, 0, "~ requires integer"); + return 0; + } + return emit_arith(a, fc, SPL_IR_ARITH_NOT, t, v, 0); + } + case SPL_AST_AMPERSAND_EXPR: { + spl_type_id_t t = 0; + spl_ir_node_ref_t addr = lower_lvalue(a, fc, pf->prefix_expr.postfix_expr, &t); + if (addr) { + spl_type_id_t pt = spl_type_ptr((spl_type_t *)&a->sema->type, t); + set_ntype(fc, addr, pt); + return addr; + } + spl_ast_node_t *operand = node_at(a->sema, pf->prefix_expr.postfix_expr); + if (operand && operand->kind == SPL_AST_EXPR && operand->expr.op == SPL_AST_PRIMARY_EXPR) { + spl_ast_node_t *pn = node_at(a->sema, operand->expr.op_expr.left); + if (pn && pn->primary_expr.kind == SPL_AST_IDENT) { + spl_def_id_t def = root_lookup(a, pn->primary_expr.ident); + if (def) { + spl_def_node_t *d = def_at(a->sema, def); + if (d && d->kind == SPL_DEF_FN_PARAMS && d->type_id) { + spl_ir_func_ref_t fid = a2ir_fn_of(a, d->type_id); + if (fid) + return const_fnref(a, fc, d->type_id, fid); + } + } + } + } + diag(a, fc, 0, "& requires addressable operand"); + return 0; + } + case SPL_AST_ASTERISK_EXPR: { + spl_ir_node_ref_t v = lower_expr(a, fc, pf->prefix_expr.postfix_expr); + spl_type_id_t t = underlying(a->sema, node_type(fc, v)); + spl_type_node_t *tt = tn(a->sema, t); + if (tt && tt->kind == SPL_TYPE_PTR) { + spl_type_id_t pointee = underlying(a->sema, tt->ptr_pointee); + return emit_load(a, fc, pointee, v); + } + return v; + } + default: + return 0; + } +} + +/* ---- 调用目标 ---- */ + +typedef struct { + spl_type_id_t fn_tid; + spl_ir_node_ref_t callee; +} callee_t; + +static int resolve_callee(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t base, callee_t *out) { + memset(out, 0, sizeof *out); + spl_ast_node_t *n = node_at(a->sema, base); + if (!n || n->kind != SPL_AST_EXPR) + return 0; + if (n->expr.op == SPL_AST_PRIMARY_EXPR) { + spl_ast_node_t *pn = node_at(a->sema, n->expr.op_expr.left); + if (pn && pn->primary_expr.kind == SPL_AST_IDENT) { + const char *name = pn->primary_expr.ident; + ir_env_t *it = env_find_def(fc, pn->resolved_def_id, name); + if (it && it->is_type) { + diag(a, fc, base, "type is not callable"); + return 0; + } + spl_def_id_t def = root_lookup(a, name); + if (def) { + spl_def_node_t *d = def_at(a->sema, def); + if (d && d->kind == SPL_DEF_FN_PARAMS && d->type_id) { + out->fn_tid = d->type_id; + spl_ir_func_ref_t fid = a2ir_fn_of(a, d->type_id); + if (fid) { + out->callee = const_fnref(a, fc, d->type_id, fid); + return 1; + } + diag(a, fc, base, "function has no IR function"); + return 0; + } + } + /* 命名空间内裸名互调:Str.from_cstr 中调cstrlen(...) */ + if (fc->ns_tid) { + spl_type_id_t mt = agg_member_type(a, fc->ns_tid, name); + spl_type_node_t *mtn = mt ? tn(a->sema, mt) : NULL; + if (mt && mtn && mtn->kind == SPL_TYPE_FN) { + out->fn_tid = mt; + spl_ir_func_ref_t fid = a2ir_fn_of(a, mt); + if (fid) { + out->callee = const_fnref(a, fc, mt, fid); + return 1; + } + } + } + } + } + if (n->expr.op == SPL_AST_POSTFIX_EXPR) { + spl_ast_node_t *pf = node_at(a->sema, n->expr.op_expr.left); + if (pf && pf->postfix_expr.kind == SPL_AST_FIELD_EXPR) { + const char *fname = pf->postfix_expr.field_expr; + spl_ast_node_ref_t bref = pf->postfix_expr.primary_expr; + spl_type_id_t ttr = type_of_type_ref(a, fc, bref); + if (ttr) { + spl_type_id_t mt = agg_member_type(a, ttr, fname); + spl_type_node_t *mtn = tn(a->sema, mt); + if (mt && mtn && mtn->kind == SPL_TYPE_FN) { + out->fn_tid = mt; + spl_ir_func_ref_t fid = a2ir_fn_of(a, mt); + if (fid) { + out->callee = const_fnref(a, fc, mt, fid); + return 1; + } + } + } + spl_ir_node_ref_t bv = lower_expr(a, fc, bref); + spl_type_id_t vt = underlying(a->sema, node_type(fc, bv)); + spl_type_node_t *vtt = vt ? tn(a->sema, vt) : NULL; + if (vtt && vtt->kind == SPL_TYPE_PTR) { + vt = underlying(a->sema, vtt->ptr_pointee); + vtt = tn(a->sema, vt); + } + spl_type_id_t mt = vtt ? agg_member_type(a, vt, fname) : 0; + spl_type_node_t *mtn = mt ? tn(a->sema, mt) : NULL; + if (mt && mtn && mtn->kind == SPL_TYPE_FN) { + out->fn_tid = mt; + spl_ir_func_ref_t fid = a2ir_fn_of(a, mt); + if (fid) { + out->callee = const_fnref(a, fc, mt, fid); + return 1; + } + } + } + } + out->callee = lower_expr(a, fc, base); + out->fn_tid = node_type(fc, out->callee); + if (out->fn_tid) { + spl_type_node_t *ft = tn(a->sema, underlying(a->sema, out->fn_tid)); + if (ft && ft->kind != SPL_TYPE_FN) { + diag(a, fc, base, "call requires function type"); + return 0; + } + return 1; + } + return 0; +} + +static spl_ir_node_ref_t lower_field(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *pf) { + const char *fname = pf->postfix_expr.field_expr; + spl_type_id_t ttr = type_of_type_ref(a, fc, pf->postfix_expr.primary_expr); + if (ttr) { + spl_type_node_t *ttr_t = tn(a->sema, ttr); + if (ttr_t && ttr_t->kind == SPL_TYPE_ENUM) { + isize vidx = enum_variant_index(a, ttr, fname); + if (vidx >= 0) + return enum_variant_value(a, fc, ttr, vidx); + } + diag(a, fc, 0, "aggregate member is not a value"); + return 0; + } + spl_ir_node_ref_t base = lower_expr(a, fc, pf->postfix_expr.primary_expr); + if (!base) + return 0; + spl_type_id_t bt = underlying(a->sema, node_type(fc, base)); + spl_type_node_t *tt = tn(a->sema, bt); + if (!tt) + return 0; + spl_type_id_t agg_tid = bt; + spl_ir_node_ref_t agg_val = base; + if (tt->kind == SPL_TYPE_PTR) { + agg_tid = underlying(a->sema, tt->ptr_pointee); + tt = tn(a->sema, agg_tid); + agg_val = emit_load(a, fc, agg_tid, base); + } + if (!tt) + return 0; + if (tt->kind == SPL_TYPE_SLICE) { + if (strcmp(fname, "ptr") == 0) { + spl_type_id_t ft = spl_type_ptr((spl_type_t *)&a->sema->type, tt->slice_element); + return emit_agg_extract(a, fc, agg_tid, ft, 0, agg_val); + } + if (strcmp(fname, "len") == 0) + return emit_agg_extract(a, fc, agg_tid, kw_type(a, "usize"), 1, agg_val); + diag(a, fc, 0, "unknown slice field"); + return 0; + } + if (tt->kind == SPL_TYPE_RANGE) { + if (strcmp(fname, "begin") == 0) + return emit_agg_extract(a, fc, agg_tid, tt->range_element, 0, agg_val); + if (strcmp(fname, "end") == 0) + return emit_agg_extract(a, fc, agg_tid, tt->range_element, 1, agg_val); + diag(a, fc, 0, "unknown range field"); + return 0; + } + isize fidx = agg_member_index(a, agg_tid, fname); + if (fidx < 0) { + diag(a, fc, 0, "unknown field"); + return 0; + } + spl_type_id_t ft = agg_field_tid_at(a, agg_tid, fidx); + return emit_agg_extract(a, fc, agg_tid, ft, fidx, agg_val); +} + +static spl_ir_node_ref_t lower_postfix(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *pf) { + switch (pf->postfix_expr.kind) { + case SPL_AST_CALL_EXPR: { + callee_t cal; + if (!resolve_callee(a, fc, pf->postfix_expr.primary_expr, &cal)) + return 0; + spl_type_node_t *ft = tn(a->sema, underlying(a->sema, cal.fn_tid)); + usize nparams = (ft && ft->kind == SPL_TYPE_FN) ? ft->fn_type.params.size : 0; + spl_ast_node_ref_vec_t *args = &pf->postfix_expr.call_expr; + spl_ir_node_ref_t av[64]; + usize na = args->size < 64 ? args->size : 64; + for (usize i = 0; i < na; i++) { + spl_type_id_t pt = 0; + if (i < nparams && ft && ft->kind == SPL_TYPE_FN) + pt = ft->fn_type.params.data[i]; + fc->hint = pt; + spl_ir_node_ref_t v = lower_expr(a, fc, args->data[i]); + fc->hint = 0; + if (pt) + v = coerce_to(a, fc, v, node_type(fc, v), pt); + av[i] = v; + } + return emit_call(a, fc, cal.fn_tid, cal.callee, av, na); + } + case SPL_AST_FIELD_EXPR: + return lower_field(a, fc, pf); + case SPL_AST_DEREF_EXPR: { + spl_ir_node_ref_t p = lower_expr(a, fc, pf->postfix_expr.primary_expr); + spl_type_id_t pt = underlying(a->sema, node_type(fc, p)); + spl_type_node_t *tt = tn(a->sema, pt); + if (!tt || tt->kind != SPL_TYPE_PTR) { + diag(a, fc, 0, ".* requires pointer"); + return 0; + } + spl_type_id_t pointee = underlying(a->sema, tt->ptr_pointee); + return emit_load(a, fc, pointee, p); + } + case SPL_AST_INDEX_EXPR: { + spl_type_id_t elem = 0; + spl_ir_node_ref_t addr = index_addr(a, fc, pf, &elem); + if (!addr) + return 0; + return emit_load(a, fc, elem, addr); + } + case SPL_AST_SLICE_EXPR: { + spl_type_id_t bt = 0; + spl_ir_node_ref_t base_lv = lower_lvalue(a, fc, pf->postfix_expr.primary_expr, &bt); + spl_type_node_t *tt = tn(a->sema, underlying(a->sema, bt)); + if (!tt || (tt->kind != SPL_TYPE_ARRAY && tt->kind != SPL_TYPE_SLICE)) { + diag(a, fc, 0, "slice requires array/slice"); + return 0; + } + spl_type_id_t elem = + tt->kind == SPL_TYPE_ARRAY ? tt->array_type.element : tt->slice_element; + spl_type_id_t slice_t = spl_type_slice((spl_type_t *)&a->sema->type, elem); + spl_ir_node_ref_t base_ptr = 0; + spl_ir_node_ref_t total_len = 0; + if (tt->kind == SPL_TYPE_ARRAY) { + base_ptr = base_lv; + total_len = const_int(a, fc, kw_type(a, "usize"), tt->array_type.len); + } else { + spl_ir_node_ref_t slv = emit_load(a, fc, bt, base_lv); + spl_type_id_t ep = spl_type_ptr((spl_type_t *)&a->sema->type, elem); + base_ptr = emit_agg_extract(a, fc, bt, ep, 0, slv); + total_len = emit_agg_extract(a, fc, bt, kw_type(a, "usize"), 1, slv); + } + spl_ir_node_ref_t beg = 0, end = 0; + if (pf->postfix_expr.slice_expr.begin) + beg = lower_expr(a, fc, pf->postfix_expr.slice_expr.begin); + else + beg = const_int(a, fc, kw_type(a, "usize"), 0); + if (pf->postfix_expr.slice_expr.end) + end = lower_expr(a, fc, pf->postfix_expr.slice_expr.end); + spl_type_id_t iszt = kw_type(a, "isize"); + spl_ir_node_ref_t ptr = + emit_offset(a, fc, elem, base_ptr, coerce_to(a, fc, beg, node_type(fc, beg), iszt)); + spl_ir_node_ref_t len = 0; + spl_ir_node_ref_t begu = coerce_to(a, fc, beg, node_type(fc, beg), kw_type(a, "usize")); + if (end) { + len = emit_arith(a, fc, SPL_IR_ARITH_SUB, kw_type(a, "usize"), + coerce_to(a, fc, end, node_type(fc, end), kw_type(a, "usize")), begu); + } else { + len = emit_arith(a, fc, SPL_IR_ARITH_SUB, kw_type(a, "usize"), total_len, begu); + } + spl_ir_node_ref_t sl = emit_agg_construct(a, fc, slice_t); + agg_construct_add(a, fc, sl, ptr); + agg_construct_add(a, fc, sl, len); + return sl; + } + case SPL_AST_AS_EXPR: { + spl_ir_node_ref_t v = lower_expr(a, fc, pf->postfix_expr.primary_expr); + spl_type_id_t dt = resolve_type_expr(a, fc, pf->postfix_expr.type_expr); + if (!dt) + return v; + return coerce_to(a, fc, v, node_type(fc, v), dt); + } + default: + return 0; + } +} + +static spl_ir_node_ref_t lower_binary(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *n) { + spl_ast_node_ref_t lr = n->expr.op_expr.left; + spl_ast_node_ref_t rr = n->expr.op_expr.right; + switch (n->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: + 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: { + spl_ir_node_ref_t l = lower_expr(a, fc, lr); + spl_ir_node_ref_t r = lower_expr(a, fc, rr); + spl_type_id_t lt = underlying(a->sema, node_type(fc, l)); + spl_type_id_t rt = underlying(a->sema, node_type(fc, r)); + if ((n->expr.op == SPL_AST_ADD_EXPR || n->expr.op == SPL_AST_SUB_EXPR) && + is_ptr_type(a->sema, lt) && is_int_type(a->sema, rt)) { + spl_type_node_t *ltt = tn(a->sema, lt); + spl_type_id_t elem = underlying(a->sema, ltt->ptr_pointee); + spl_ir_node_ref_t off = coerce_to(a, fc, r, rt, kw_type(a, "isize")); + if (n->expr.op == SPL_AST_SUB_EXPR) { + spl_ir_node_ref_t zero = const_int(a, fc, kw_type(a, "isize"), 0); + off = emit_arith(a, fc, SPL_IR_ARITH_SUB, kw_type(a, "isize"), zero, off); + } + return emit_offset(a, fc, elem, l, off); + } + spl_type_id_t res = lt; + if (!type_same(a->sema, lt, rt)) { + if (expr_is_int_literal(a, lr) && is_int_type(a->sema, rt)) + res = rt; + else if (expr_is_int_literal(a, rr) && is_int_type(a->sema, lt)) + res = lt; + else + res = lt; + } + spl_ir_kind_t k; + switch (n->expr.op) { + case SPL_AST_ADD_EXPR: + k = SPL_IR_ARITH_ADD; + break; + case SPL_AST_SUB_EXPR: + k = SPL_IR_ARITH_SUB; + break; + case SPL_AST_MUL_EXPR: + k = SPL_IR_ARITH_MUL; + break; + case SPL_AST_DIV_EXPR: + k = SPL_IR_ARITH_DIV; + break; + case SPL_AST_MOD_EXPR: + k = SPL_IR_ARITH_REM; + break; + case SPL_AST_BITOR_EXPR: + k = SPL_IR_ARITH_OR; + break; + case SPL_AST_BITXOR_EXPR: + k = SPL_IR_ARITH_XOR; + break; + case SPL_AST_BITAND_EXPR: + k = SPL_IR_ARITH_AND; + break; + case SPL_AST_LSHIFT_EXPR: + k = SPL_IR_ARITH_SHL; + break; + default: + k = SPL_IR_ARITH_SHR; + break; + } + spl_ir_node_ref_t l2 = coerce_to(a, fc, l, lt, res); + spl_ir_node_ref_t r2 = coerce_to(a, fc, r, rt, res); + return emit_arith(a, fc, k, res, l2, r2); + } + 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: { + spl_ir_node_ref_t l = lower_expr(a, fc, lr); + spl_ir_node_ref_t r = lower_expr(a, fc, rr); + spl_type_id_t lt = underlying(a->sema, node_type(fc, l)); + spl_type_id_t rt = underlying(a->sema, node_type(fc, r)); + spl_type_node_t *ltt = tn(a->sema, lt); + spl_type_node_t *rtt = tn(a->sema, rt); + if (ltt && ltt->kind == SPL_TYPE_ENUM && rtt && rtt->kind == SPL_TYPE_ENUM) { + spl_type_id_t tag_t = enum_tag_tid(a); + l = enum_tag_of(a, fc, lt, l); + r = enum_tag_of(a, fc, rt, r); + lt = tag_t; + rt = tag_t; + } + spl_type_id_t res = lt; + if (!type_same(a->sema, lt, rt)) { + if (is_int_type(a->sema, lt) && is_int_type(a->sema, rt)) + res = expr_is_int_literal(a, lr) ? rt : lt; + else + res = lt; + } + l = coerce_to(a, fc, l, node_type(fc, l), res); + r = coerce_to(a, fc, r, node_type(fc, r), res); + spl_ir_kind_t k; + switch (n->expr.op) { + case SPL_AST_CMPEQ_EXPR: + k = SPL_IR_CMP_EQ; + break; + case SPL_AST_CMPNE_EXPR: + k = SPL_IR_CMP_NE; + break; + case SPL_AST_CMP_LE_EXPR: + k = SPL_IR_CMP_LE; + break; + case SPL_AST_CMP_GE_EXPR: + k = SPL_IR_CMP_GE; + break; + case SPL_AST_CMP_LT_EXPR: + k = SPL_IR_CMP_LT; + break; + default: + k = SPL_IR_CMP_GT; + break; + } + return emit_cmp(a, fc, k, res, l, r); + } + case SPL_AST_BOOLAND_EXPR: + case SPL_AST_BOOLOR_EXPR: { + spl_type_id_t bt = kw_type(a, "bool"); + spl_ir_node_ref_t l = lower_expr(a, fc, lr); + usize t = new_block(fc), f = new_block(fc), join = new_block(fc); + spl_ir_node_ref_t slot = emit_alloca(a, fc, bt); + emit_br(a, fc, l, t, f); + begin_block(fc, t); + if (n->expr.op == SPL_AST_BOOLAND_EXPR) { + spl_ir_node_ref_t r = lower_expr(a, fc, rr); + emit_store(a, fc, bt, slot, r); + } else { + emit_store(a, fc, bt, slot, const_bool(a, fc, 1)); + } + emit_jmp(a, fc, join); + begin_block(fc, f); + if (n->expr.op == SPL_AST_BOOLAND_EXPR) { + emit_store(a, fc, bt, slot, const_bool(a, fc, 0)); + } else { + spl_ir_node_ref_t r = lower_expr(a, fc, rr); + emit_store(a, fc, bt, slot, r); + } + emit_jmp(a, fc, join); + begin_block(fc, join); + return emit_load(a, fc, bt, slot); + } + default: + return 0; + } +} + +static spl_ir_node_ref_t lower_range_value(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *n) { + spl_ir_node_ref_t b = lower_expr(a, fc, n->expr.op_expr.left); + spl_type_id_t et = underlying(a->sema, node_type(fc, b)); + spl_type_id_t range_t = spl_type_range((spl_type_t *)&a->sema->type, et); + spl_ir_node_ref_t r = emit_agg_construct(a, fc, range_t); + agg_construct_add(a, fc, r, b); + if (n->expr.op_expr.right) + agg_construct_add(a, fc, r, lower_expr(a, fc, n->expr.op_expr.right)); + else + agg_construct_add(a, fc, r, const_int(a, fc, et, 0)); + return r; +} + +static spl_ir_node_ref_t lower_compound_op(spl_ast2ir_t *a, fnctx_t *fc, int op, spl_type_id_t tid, + spl_ir_node_ref_t cur, spl_ir_node_ref_t rhs) { + spl_ir_kind_t k; + switch (op) { + case SPL_AST_ASSIGN_ADD_EXPR: + k = SPL_IR_ARITH_ADD; + break; + case SPL_AST_ASSIGN_sUB_EXPR: + k = SPL_IR_ARITH_SUB; + break; + case SPL_AST_ASSIGN_MUL_EXPR: + k = SPL_IR_ARITH_MUL; + break; + case SPL_AST_ASSIGN_DIV_EXPR: + k = SPL_IR_ARITH_DIV; + break; + case SPL_AST_ASSIGN_MOD_EXPR: + k = SPL_IR_ARITH_REM; + break; + case SPL_AST_ASSIGN_AND_EXPR: + k = SPL_IR_ARITH_AND; + break; + case SPL_AST_ASSIGN_OR_EXPR: + k = SPL_IR_ARITH_OR; + break; + case SPL_AST_ASSIGN_XOR_EXPR: + k = SPL_IR_ARITH_XOR; + break; + case SPL_AST_ASSIGN_LSHIFT_EXPR: + k = SPL_IR_ARITH_SHL; + break; + case SPL_AST_ASSIGN_USHIFT_EXPR: + k = SPL_IR_ARITH_SHR; + break; + default: + return rhs; + } + spl_ir_node_ref_t r = coerce_to(a, fc, rhs, node_type(fc, rhs), tid); + return emit_arith(a, fc, k, tid, cur, r); +} + +/* 字段链赋o.a.b = rhs:直接按字节地址写回(含指针中间字段*/ +static void field_assign(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t target, + spl_ir_node_ref_t rhs) { + spl_type_id_t ft = 0; + spl_ir_node_ref_t addr = lower_field_address(a, fc, target, &ft); + if (!addr || !ft) { + diag(a, fc, target, "field assignment: unsupported base"); + return; + } + rhs = coerce_to(a, fc, rhs, node_type(fc, rhs), ft); + emit_store(a, fc, ft, addr, rhs); +} + +static spl_ir_node_ref_t lower_assign(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *n) { + spl_ast_node_ref_t lr = n->expr.op_expr.left; + spl_ast_node_ref_t rr = n->expr.op_expr.right; + spl_ast_node_t *ln = node_at(a->sema, lr); + if (!ln || ln->kind != SPL_AST_EXPR) + return 0; + int compound = n->expr.op != SPL_AST_ASSIGN_EXPR; + spl_ast_node_t *pf = NULL; + if (ln->expr.op == SPL_AST_POSTFIX_EXPR) + pf = node_at(a->sema, ln->expr.op_expr.left); + + if (ln->expr.op == SPL_AST_PRIMARY_EXPR) { + spl_ast_node_t *pn = node_at(a->sema, ln->expr.op_expr.left); + if (pn && pn->primary_expr.kind == SPL_AST_IDENT) { + ir_env_t *it = env_find_def(fc, pn->resolved_def_id, pn->primary_expr.ident); + if (!it || !it->slot) { + diag(a, fc, lr, "assignment target not writable"); + return 0; + } + spl_ir_node_ref_t cur = compound ? emit_load(a, fc, it->tid, it->slot) : 0; + spl_ir_node_ref_t v = lower_expr(a, fc, rr); + if (compound) + v = lower_compound_op(a, fc, n->expr.op, it->tid, cur, v); + v = coerce_to(a, fc, v, node_type(fc, v), it->tid); + emit_store(a, fc, it->tid, it->slot, v); + return v; + } + } + if (ln->expr.op == SPL_AST_PREFIX_EXPR) { + spl_ast_node_t *pp = node_at(a->sema, ln->expr.op_expr.left); + if (pp && pp->prefix_expr.kind == SPL_AST_ASTERISK_EXPR) { + spl_ir_node_ref_t p = lower_expr(a, fc, pp->prefix_expr.postfix_expr); + spl_type_id_t pt = underlying(a->sema, node_type(fc, p)); + spl_type_node_t *tt = tn(a->sema, pt); + if (tt && tt->kind == SPL_TYPE_PTR) { + spl_type_id_t pointee = underlying(a->sema, tt->ptr_pointee); + spl_ir_node_ref_t cur = compound ? emit_load(a, fc, pointee, p) : 0; + spl_ir_node_ref_t v = lower_expr(a, fc, rr); + if (compound) + v = lower_compound_op(a, fc, n->expr.op, pointee, cur, v); + v = coerce_to(a, fc, v, node_type(fc, v), pointee); + emit_store(a, fc, pointee, p, v); + return v; + } + } + } + if (pf && pf->postfix_expr.kind == SPL_AST_DEREF_EXPR) { + spl_ir_node_ref_t p = lower_expr(a, fc, pf->postfix_expr.primary_expr); + spl_type_id_t pt = underlying(a->sema, node_type(fc, p)); + spl_type_node_t *tt = tn(a->sema, pt); + if (!tt || tt->kind != SPL_TYPE_PTR) { + diag(a, fc, lr, ".* requires pointer"); + return 0; + } + spl_type_id_t pointee = underlying(a->sema, tt->ptr_pointee); + spl_ir_node_ref_t cur = compound ? emit_load(a, fc, pointee, p) : 0; + spl_ir_node_ref_t v = lower_expr(a, fc, rr); + if (compound) + v = lower_compound_op(a, fc, n->expr.op, pointee, cur, v); + v = coerce_to(a, fc, v, node_type(fc, v), pointee); + emit_store(a, fc, pointee, p, v); + return v; + } + if (pf && pf->postfix_expr.kind == SPL_AST_INDEX_EXPR) { + spl_type_id_t elem = 0; + spl_ir_node_ref_t addr = index_addr(a, fc, pf, &elem); + if (!addr) + return 0; + spl_ir_node_ref_t cur = compound ? emit_load(a, fc, elem, addr) : 0; + spl_ir_node_ref_t v = lower_expr(a, fc, rr); + if (compound) + v = lower_compound_op(a, fc, n->expr.op, elem, cur, v); + v = coerce_to(a, fc, v, node_type(fc, v), elem); + emit_store(a, fc, elem, addr, v); + return v; + } + if (pf && pf->postfix_expr.kind == SPL_AST_FIELD_EXPR) { + spl_ir_node_ref_t v = lower_expr(a, fc, rr); + if (compound) { + spl_ir_node_ref_t cur = lower_expr(a, fc, lr); + v = lower_compound_op(a, fc, n->expr.op, node_type(fc, cur), cur, v); + } + field_assign(a, fc, lr, v); + return v; + } + diag(a, fc, lr, "unsupported assignment target"); + return 0; +} + +static spl_ir_node_ref_t lower_expr(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref) { + spl_ast_node_t *n = node_at(a->sema, ref); + if (!n || n->kind != SPL_AST_EXPR) + return 0; + switch (n->expr.op) { + case SPL_AST_PRIMARY_EXPR: + return lower_primary(a, fc, node_at(a->sema, n->expr.op_expr.left)); + case SPL_AST_PREFIX_EXPR: + return lower_prefix(a, fc, node_at(a->sema, n->expr.op_expr.left)); + case SPL_AST_POSTFIX_EXPR: + return lower_postfix(a, fc, node_at(a->sema, n->expr.op_expr.left)); + case SPL_AST_RANGE_EXPR: + return lower_range_value(a, fc, n); + 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: + return lower_assign(a, fc, n); + default: + return lower_binary(a, fc, n); + } +} + +/* ================================================================ + * 语句 + * ================================================================ */ + +static void lower_block(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_vec_t *block) { + env_push(fc); + for (usize i = 0; i < block->size; i++) + lower_stmt(a, fc, block->data[i]); + if (!fc->terminated) + emit_scope_defers(a, fc, fc->env.size - 1); + env_pop(fc); +} + +/* 登记 defer 体到当前作用*/ +static void lower_defer(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref) { + if (!fc->env.size) + env_push(fc); + vec_push(fc->env.data[fc->env.size - 1].defers, ref); +} + +/* 逆序发射 scope_idx 作用域的 defer,并清空 */ +static void emit_scope_defers(spl_ast2ir_t *a, fnctx_t *fc, usize scope_idx) { + if (scope_idx >= fc->env.size) + return; + for (usize i = fc->env.data[scope_idx].defers.size; i > 0; i--) { + spl_ast_node_t *d = node_at(a->sema, fc->env.data[scope_idx].defers.data[i - 1]); + if (d) { + lower_block(a, fc, &d->block_item.defer_statement.block_or_statement); + } + } + vec_free(fc->env.data[scope_idx].defers); + vec_init(fc->env.data[scope_idx].defers); +} + +/* 从最内层作用域发射到 mark(含),用于 ret / break / continue */ +static void emit_defers_from(spl_ast2ir_t *a, fnctx_t *fc, usize mark) { + for (usize i = fc->env.size; i > mark; i--) + emit_scope_defers(a, fc, i - 1); +} + +static void lower_type_decl(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *td) { + spl_type_id_t tid = resolve_type_expr(a, fc, td->type_decl.type_expr); + env_add(fc, td->type_decl.name, td->resolved_def_id, tid, 0, 0, 1, 0); +} + +static void lower_var_decl(spl_ast2ir_t *a, fnctx_t *fc, const char *name, spl_def_id_t def_id, + spl_ast_node_ref_t texpr, spl_ast_node_ref_t initexpr) { + spl_type_id_t tid = texpr ? resolve_type_expr(a, fc, texpr) : 0; + spl_ir_node_ref_t v = 0; + spl_type_id_t vt = 0; + if (initexpr) { + fc->hint = tid; + v = lower_expr(a, fc, initexpr); + fc->hint = 0; + vt = node_type(fc, v); + if (!tid && vt) + tid = vt; + } + if (!tid) + tid = kw_type(a, "void"); + spl_ir_node_ref_t slot = emit_alloca(a, fc, tid); + if (v && vt && tid) { + if (!type_same(a->sema, vt, tid)) + v = coerce_to(a, fc, v, vt, tid); + emit_store(a, fc, tid, slot, v); + } + env_add(fc, name, def_id, tid, slot, 0, 0, 1); +} + +static void lower_if(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *b) { + spl_ir_node_ref_t c = lower_expr(a, fc, b->block_item.if_statement.expr); + int has_else = b->block_item.if_statement.else_block.size > 0; + usize then_b = new_block(fc); + usize else_b = has_else ? new_block(fc) : 0; + usize exit_b = new_block(fc); + emit_br(a, fc, c, then_b, has_else ? else_b : exit_b); + begin_block(fc, then_b); + lower_block(a, fc, &b->block_item.if_statement.if_block); + emit_jmp(a, fc, exit_b); + if (has_else) { + begin_block(fc, else_b); + lower_block(a, fc, &b->block_item.if_statement.else_block); + emit_jmp(a, fc, exit_b); + } + begin_block(fc, exit_b); +} + +static void lower_while(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *b) { + usize cond_b = new_block(fc); + usize body_b = new_block(fc); + usize exit_b = new_block(fc); + begin_block(fc, cond_b); + spl_ir_node_ref_t c = lower_expr(a, fc, b->block_item.while_statement.expr); + emit_br(a, fc, c, body_b, exit_b); + begin_block(fc, body_b); + ir_loop_t lp = {exit_b, cond_b, fc->env.size}; + vec_push(fc->loops, lp); + lower_block(a, fc, &b->block_item.while_statement.while_block); + emit_jmp(a, fc, cond_b); + vec_pop(fc->loops); + begin_block(fc, exit_b); +} + +static void lower_loop(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *b) { + usize body_b = new_block(fc); + usize exit_b = new_block(fc); + begin_block(fc, body_b); + ir_loop_t lp = {exit_b, body_b, fc->env.size}; + vec_push(fc->loops, lp); + lower_block(a, fc, &b->block_item.loop_statement.loop_block); + emit_jmp(a, fc, body_b); + vec_pop(fc->loops); + begin_block(fc, exit_b); +} + +enum { FOR_RANGE, FOR_ARRAY, FOR_SLICE }; +typedef struct { + int kind; + spl_type_id_t elem_tid; + spl_ir_node_ref_t len; /* 长度节点 = 无界 */ + spl_ir_node_ref_t begin_slot; /* range: begin */ + spl_ir_node_ref_t base_slot; /* array/slice: 元素基址*/ +} for_seq_t; + +static void for_seq_setup(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t eref, for_seq_t *s) { + memset(s, 0, sizeof *s); + spl_ast_node_t *n = node_at(a->sema, eref); + if (n && n->kind == SPL_AST_EXPR && n->expr.op == SPL_AST_RANGE_EXPR) { + s->kind = FOR_RANGE; + spl_ir_node_ref_t beg = lower_expr(a, fc, n->expr.op_expr.left); + s->elem_tid = underlying(a->sema, node_type(fc, beg)); + s->begin_slot = emit_alloca(a, fc, s->elem_tid); + emit_store(a, fc, s->elem_tid, s->begin_slot, beg); + if (n->expr.op_expr.right) { + spl_ir_node_ref_t end = lower_expr(a, fc, n->expr.op_expr.right); + spl_ir_node_ref_t b = emit_load(a, fc, s->elem_tid, s->begin_slot); + s->len = emit_arith(a, fc, SPL_IR_ARITH_SUB, s->elem_tid, + coerce_to(a, fc, end, node_type(fc, end), s->elem_tid), b); + } + return; + } + spl_type_id_t bt = 0; + spl_ir_node_ref_t base_lv = lower_lvalue(a, fc, eref, &bt); + spl_type_node_t *tt = bt ? tn(a->sema, underlying(a->sema, bt)) : NULL; + if (base_lv && tt && tt->kind == SPL_TYPE_ARRAY) { + s->kind = FOR_ARRAY; + s->elem_tid = tt->array_type.element; + s->base_slot = base_lv; + s->len = const_int(a, fc, kw_type(a, "usize"), tt->array_type.len); + return; + } + if (base_lv && tt && tt->kind == SPL_TYPE_SLICE) { + s->kind = FOR_SLICE; + s->elem_tid = tt->slice_element; + spl_ir_node_ref_t slv = emit_load(a, fc, bt, base_lv); + spl_type_id_t ep = spl_type_ptr((spl_type_t *)&a->sema->type, s->elem_tid); + s->base_slot = emit_alloca(a, fc, ep); + s->len = emit_alloca(a, fc, kw_type(a, "usize")); + emit_store(a, fc, ep, s->base_slot, emit_agg_extract(a, fc, bt, ep, 0, slv)); + emit_store(a, fc, kw_type(a, "usize"), s->len, + emit_agg_extract(a, fc, bt, kw_type(a, "usize"), 1, slv)); + return; + } + spl_ir_node_ref_t v = lower_expr(a, fc, eref); + spl_type_id_t vt = underlying(a->sema, node_type(fc, v)); + spl_type_node_t *vtt = vt ? tn(a->sema, vt) : NULL; + if (vtt && vtt->kind == SPL_TYPE_SLICE) { + s->kind = FOR_SLICE; + s->elem_tid = vtt->slice_element; + spl_type_id_t ep = spl_type_ptr((spl_type_t *)&a->sema->type, s->elem_tid); + s->base_slot = emit_alloca(a, fc, ep); + s->len = emit_alloca(a, fc, kw_type(a, "usize")); + emit_store(a, fc, ep, s->base_slot, emit_agg_extract(a, fc, vt, ep, 0, v)); + emit_store(a, fc, kw_type(a, "usize"), s->len, + emit_agg_extract(a, fc, vt, kw_type(a, "usize"), 1, v)); + return; + } + if (vtt && vtt->kind == SPL_TYPE_ARRAY) { + spl_type_id_t fat = 0; + spl_ir_node_ref_t faddr = lower_field_address(a, fc, eref, &fat); + if (faddr) { + s->kind = FOR_ARRAY; + s->elem_tid = vtt->array_type.element; + s->base_slot = faddr; + s->len = const_int(a, fc, kw_type(a, "usize"), vtt->array_type.len); + return; + } + } + diag(a, fc, eref, "for: sequence must be Range/[]T/[N]T"); +} + +static void lower_for(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *b) { + 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; + usize nseq = expr_vec->size; + if (nseq != id_size || nseq > 8) { + diag(a, fc, 0, "for: sequence/variable count mismatch"); + return; + } + for_seq_t seqs[8]; + for (usize i = 0; i < nseq; i++) + for_seq_setup(a, fc, expr_vec->data[i], &seqs[i]); + spl_type_id_t iszt = kw_type(a, "isize"); + spl_ir_node_ref_t min_slot = 0; + int has_finite = 0; + for (usize i = 0; i < nseq; i++) + if (seqs[i].len) + has_finite = 1; + if (has_finite) { + spl_ir_node_ref_t m = 0; + for (usize i = 0; i < nseq; i++) { + if (!seqs[i].len) + continue; + spl_ir_node_ref_t l = coerce_to(a, fc, seqs[i].len, node_type(fc, seqs[i].len), iszt); + if (!m) { + m = l; + } else { + spl_ir_node_ref_t c = emit_cmp(a, fc, SPL_IR_CMP_LT, iszt, l, m); + m = emit_select(a, fc, iszt, c, l, m); + } + } + min_slot = emit_alloca(a, fc, iszt); + emit_store(a, fc, iszt, min_slot, m); + } + spl_ir_node_ref_t ctr = emit_alloca(a, fc, iszt); + emit_store(a, fc, iszt, ctr, const_int(a, fc, iszt, 0)); + env_push(fc); + for (usize i = 0; i < nseq; i++) + env_add(fc, id_data[i], 0, seqs[i].elem_tid, 0, 0, 0, 0); + usize cond_b = new_block(fc); + usize body_b = new_block(fc); + usize exit_b = new_block(fc); + begin_block(fc, cond_b); + if (has_finite) { + spl_ir_node_ref_t cur = emit_load(a, fc, iszt, ctr); + spl_ir_node_ref_t ml = emit_load(a, fc, iszt, min_slot); + spl_ir_node_ref_t c = emit_cmp(a, fc, SPL_IR_CMP_LT, iszt, cur, ml); + emit_br(a, fc, c, body_b, exit_b); + } else { + emit_jmp(a, fc, body_b); + } + begin_block(fc, body_b); + for (usize i = 0; i < nseq; i++) { + for_seq_t *s = &seqs[i]; + spl_ir_node_ref_t cur = emit_load(a, fc, iszt, ctr); + spl_ir_node_ref_t v = 0; + if (s->kind == FOR_RANGE) { + spl_ir_node_ref_t bg = emit_load(a, fc, s->elem_tid, s->begin_slot); + v = emit_arith(a, fc, SPL_IR_ARITH_ADD, s->elem_tid, bg, + coerce_to(a, fc, cur, iszt, s->elem_tid)); + } else { + spl_ir_node_ref_t addr = emit_offset(a, fc, s->elem_tid, s->base_slot, cur); + v = emit_load(a, fc, s->elem_tid, addr); + } + ir_env_t *it = env_find(fc, id_data[i]); + if (it) { + it->tid = s->elem_tid; + it->value = v; + } + } + ir_loop_t lp = {exit_b, cond_b, fc->env.size}; + vec_push(fc->loops, lp); + lower_block(a, fc, &b->block_item.for_statement.block); + spl_ir_node_ref_t cur2 = emit_load(a, fc, iszt, ctr); + spl_ir_node_ref_t one = const_int(a, fc, iszt, 1); + spl_ir_node_ref_t nxt = emit_arith(a, fc, SPL_IR_ARITH_ADD, iszt, cur2, one); + emit_store(a, fc, iszt, ctr, nxt); + emit_jmp(a, fc, cond_b); + vec_pop(fc->loops); + env_pop(fc); + begin_block(fc, exit_b); +} + +static void lower_ret(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *b) { + emit_defers_from(a, fc, 0); + if (b->block_item.ret_statement.expr) { + fc->hint = fc->ret_tid; + spl_ir_node_ref_t v = lower_expr(a, fc, b->block_item.ret_statement.expr); + fc->hint = 0; + spl_type_id_t vt = node_type(fc, v); + if (fc->ret_tid && vt && !type_same(a->sema, vt, fc->ret_tid)) + v = coerce_to(a, fc, v, vt, fc->ret_tid); + emit_ret(a, fc, fc->ret_tid, v); + } else { + emit_ret(a, fc, fc->ret_tid, 0); + } +} + +static void lower_match(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *b) { + 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) { + diag(a, fc, 0, "match: arm pattern/body count mismatch"); + return; + } + spl_ir_node_ref_t subj = lower_expr(a, fc, b->block_item.match_statement.expr); + spl_type_id_t st = underlying(a->sema, node_type(fc, subj)); + spl_type_node_t *tt = tn(a->sema, st); + if (tt && tt->kind == SPL_TYPE_PTR) { + st = underlying(a->sema, tt->ptr_pointee); + tt = tn(a->sema, st); + subj = emit_load(a, fc, st, subj); + } + int is_enum = tt && tt->kind == SPL_TYPE_ENUM; + int is_int = tt && tt->kind == SPL_TYPE_INT; + if (!is_enum && !is_int) { + diag(a, fc, 0, "match subject must be enum/union/integer"); + return; + } + spl_ir_node_ref_t subj_slot = emit_alloca(a, fc, st); + emit_store(a, fc, st, subj_slot, subj); + spl_type_id_t tag_t = enum_tag_tid(a); + spl_ir_node_ref_t tag_slot = 0; + if (is_enum) { + spl_ir_node_ref_t tagv = + emit_agg_extract(a, fc, st, tag_t, 0, emit_load(a, fc, st, subj_slot)); + tag_slot = emit_alloca(a, fc, tag_t); + emit_store(a, fc, tag_t, tag_slot, tagv); + } + usize exit_b = new_block(fc); + for (usize i = 0; i < arms->size; i++) { + spl_ast_node_t *pk = node_at(a->sema, arms->data[i]); + usize body_b = new_block(fc); + usize next_b = (i + 1 < arms->size) ? new_block(fc) : 0; + int is_default = !pk || (!pk->packed_expr.ident && !pk->packed_expr.expr); + if (is_default) { + emit_jmp(a, fc, body_b); + } else { + spl_ir_node_ref_t cond = 0; + if (is_enum && pk->packed_expr.ident) { + isize vidx = enum_variant_index(a, st, pk->packed_expr.ident); + if (vidx < 0) + vidx = 0; + spl_ir_node_ref_t tv = emit_load(a, fc, tag_t, tag_slot); + spl_ir_node_ref_t idxc = const_int(a, fc, tag_t, (usize)vidx); + cond = emit_cmp(a, fc, SPL_IR_CMP_EQ, tag_t, tv, idxc); + } else if (is_int && pk->packed_expr.expr) { + spl_ir_node_ref_t sv = emit_load(a, fc, st, subj_slot); + spl_ir_node_ref_t pv = lower_expr(a, fc, pk->packed_expr.expr); + pv = coerce_to(a, fc, pv, node_type(fc, pv), st); + cond = emit_cmp(a, fc, SPL_IR_CMP_EQ, st, sv, pv); + } + if (cond) + emit_br(a, fc, cond, body_b, next_b ? next_b : exit_b); + else + emit_jmp(a, fc, body_b); + } + begin_block(fc, body_b); + env_push(fc); + if (is_enum && pk && pk->packed_expr.ident && pk->packed_expr.bind_ident) { + isize vidx = enum_variant_index(a, st, pk->packed_expr.ident); + spl_type_id_t pt = enum_payload_tid(a, st, vidx); + if (pt) { + spl_ir_node_ref_t sv = emit_load(a, fc, st, subj_slot); + spl_ir_node_ref_t pv = emit_agg_extract(a, fc, st, pt, 1, sv); + spl_ir_node_ref_t bslot = emit_alloca(a, fc, pt); + emit_store(a, fc, pt, bslot, pv); + env_add(fc, pk->packed_expr.bind_ident, 0, pt, bslot, 0, 0, 0); + } + } + spl_ast_node_t *body = node_at(a->sema, bodies->data[i]); + if (body && body->kind == SPL_AST_EXPR && body->expr.op == SPL_AST_PRIMARY_EXPR) { + spl_ast_node_t *pn = node_at(a->sema, body->expr.op_expr.left); + if (pn && pn->primary_expr.kind == SPL_AST_BLOCK_EXPR) + lower_block(a, fc, &pn->primary_expr.block_expr); + else + lower_expr(a, fc, bodies->data[i]); + } else { + lower_expr(a, fc, bodies->data[i]); + } + env_pop(fc); + emit_jmp(a, fc, exit_b); + if (next_b) + begin_block(fc, next_b); + } + begin_block(fc, exit_b); +} + +static void lower_stmt(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref) { + spl_ast_node_t *b = node_at(a->sema, 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(a->sema, b->expr.op_expr.left); + if (pn && pn->primary_expr.kind == SPL_AST_BLOCK_EXPR) { + lower_block_expr(a, fc, &pn->primary_expr.block_expr); + return; + } + } + lower_expr(a, fc, ref); + return; + } + switch (b->block_item.kind) { + case SPL_AST_VARDECL: { + spl_ast_node_t *vd = node_at(a->sema, b->block_item.var_decl); + if (vd) + lower_var_decl(a, fc, vd->var_decl.name, vd->resolved_def_id, vd->var_decl.type_expr, + vd->var_decl.expr); + break; + } + case SPL_AST_CONSTDECL: { + spl_ast_node_t *cd = node_at(a->sema, b->block_item.const_decl); + if (cd) + lower_var_decl(a, fc, cd->const_decl.name, cd->resolved_def_id, + cd->const_decl.type_expr, cd->const_decl.expr); + break; + } + case SPL_AST_TYPEDECL: { + spl_ast_node_t *td = node_at(a->sema, b->block_item.type_decl); + if (td) + lower_type_decl(a, fc, td); + break; + } + case SPL_AST_IF_STATEMENT: + lower_if(a, fc, b); + break; + case SPL_AST_IFVAR_STATEMENT: + diag(a, fc, ref, "if-var not supported"); + break; + case SPL_AST_WHILE_STATEMENT: + lower_while(a, fc, b); + break; + case SPL_AST_LOOP_STATEMENT: + lower_loop(a, fc, b); + break; + case SPL_AST_FOR_STATEMENT: + lower_for(a, fc, b); + break; + case SPL_AST_MATCH_STATEMENT: + lower_match(a, fc, b); + break; + case SPL_AST_RET_STATEMENT: + lower_ret(a, fc, b); + break; + case SPL_AST_BREAK_STATEMENT: { + if (!fc->loops.size) { + diag(a, fc, ref, "break outside loop"); + break; + } + ir_loop_t *lp = &fc->loops.data[fc->loops.size - 1]; + emit_defers_from(a, fc, lp->env_mark); + emit_jmp(a, fc, lp->brk); + break; + } + case SPL_AST_CONTINUE_STATEMENT: { + if (!fc->loops.size) { + diag(a, fc, ref, "continue outside loop"); + break; + } + ir_loop_t *lp = &fc->loops.data[fc->loops.size - 1]; + emit_defers_from(a, fc, lp->env_mark); + emit_jmp(a, fc, lp->cont); + break; + } + case SPL_AST_DEFER_STATEMENT: + lower_defer(a, fc, ref); + break; + case SPL_AST_EXPR_STATEMENT: + if (b->block_item.expr_statement) + lower_expr(a, fc, b->block_item.expr_statement); + break; + default: + break; + } +} + +/* ================================================================ + * 函数 + * ================================================================ */ + +static spl_ir_func_ref_t a2ir_fn_of(spl_ast2ir_t *a, spl_type_id_t fn_tid) { + /* 懒扫描:IR func 已记录 fn_tid(spl_type_fn 不去重,fn_tid 唯一) */ + for (usize i = 1; i < a->ir.funcs.size; i++) { + if (a->ir.funcs.data[i].fn_tid == fn_tid) + return i; + } + return 0; +} + +static void lower_func_body(spl_ast2ir_t *a, spl_ir_func_ref_t fid, spl_type_id_t fn_tid, + spl_ast_node_ref_t def_ref, spl_type_id_t ns_tid) { + spl_ast_node_t *fn = node_at(a->sema, def_ref); + if (!fn) + return; + spl_type_node_t *ft = tn(a->sema, fn_tid); + spl_type_id_t ret = (ft && ft->kind == SPL_TYPE_FN) ? ft->fn_type.ret : 0; + fnctx_t fc; + fc_init_ns(&fc, fid, ret, ns_tid); + spl_ast_node_ref_vec_t *pl = &fn->fn_decl.param_list; + usize nparams = (ft && ft->kind == SPL_TYPE_FN) ? ft->fn_type.params.size : 0; + env_push(&fc); + for (usize i = 0; i < pl->size && i < nparams; i++) { + spl_ast_node_t *pd = node_at(a->sema, pl->data[i]); + if (!pd || !pd->param_decl.name) + continue; + spl_type_id_t pt = ft->fn_type.params.data[i]; + spl_ir_node_ref_t pr = emit_node(a, &fc); + spl_ir_node_t *e = enode(a, &fc, pr); + e->kind = SPL_IR_CONTROL_PARAM; + e->control_param.tid = pt; + e->control_param.idx = (usize)i; + set_ntype(&fc, pr, pt); + spl_ir_node_ref_t slot = emit_alloca(a, &fc, pt); + emit_store(a, &fc, pt, slot, pr); + env_add(&fc, pd->param_decl.name, pd->resolved_def_id, pt, slot, 0, 0, 0); + } + begin_block(&fc, new_block(&fc)); + lower_block(a, &fc, &fn->fn_decl.block); + if (!fc.terminated) + emit_ret(a, &fc, ret, 0); + spl_ir_func_t *ff = spl_ir_func(&a->ir, fid); + for (usize i = 0; i < fc.fixups.size; i++) { + ir_fix_t *fx = &fc.fixups.data[i]; + spl_ir_node_t *nn = spl_ir_node(&a->ir, fid, fx->node); + spl_ir_node_ref_t target = fc.blocks.data[fx->block].first; + if (!target) + target = ff->nodes.size ? ff->nodes.size - 1 : 0; + if (fx->slot == 0) + nn->control_br.true_label = target; + else if (fx->slot == 1) + nn->control_br.false_label = target; + else + nn->control_jmp.label = target; + } + for (usize i = 0; i < fc.blocks.size; i++) + if (fc.blocks.data[i].first) + vec_push(ff->labels, fc.blocks.data[i].first); + for (usize i = 1; i < ff->labels.size; i++) { + spl_ir_node_ref_t k = ff->labels.data[i]; + usize j = i; + while (j > 0 && ff->labels.data[j - 1] > k) { + ff->labels.data[j] = ff->labels.data[j - 1]; + j--; + } + ff->labels.data[j] = k; + } + if (fc.err) + a->err_count += fc.err; + fc_drop(&fc); +} + +void spl_ast2ir_init(spl_ast2ir_t *ast2ir, const spl_sema_t *sema) { + memset(ast2ir, 0, sizeof *ast2ir); + ast2ir->sema = sema; + spl_ir_init(&ast2ir->ir); + vec_init(ast2ir->owned_names); +} + +void spl_ast2ir_drop(spl_ast2ir_t *ast2ir) { + for (usize i = 0; i < ast2ir->owned_names.size; i++) + free(ast2ir->owned_names.data[i]); + vec_free(ast2ir->owned_names); + spl_ir_drop(&ast2ir->ir); +} + +/* ================================================================ + * 预登记:为所有函数(顶层 + 聚合方法)建 IR func + * ================================================================ */ + +/* 预登记:为所有函数(顶层 + 聚合方法)建 IR func */ +static void register_funcs(spl_ast2ir_t *a) { + spl_ast_node_t *root = node_at(a->sema, a->sema->ast->root); + if (!root || root->kind != SPL_AST_CONTAINER_ITEM) + return; + for (usize i = 0; i < root->container_item.members.size; i++) { + spl_ast_node_ref_t mref = root->container_item.members.data[i]; + spl_ast_node_t *m = node_at(a->sema, mref); + if (!m || (m->kind != SPL_AST_FN_DECL && m->kind != SPL_AST_FN_DEFINE)) + continue; + spl_def_id_t def = root_lookup(a, m->fn_decl.name); + if (!def) + continue; + spl_type_id_t fn_tid = def_at(a->sema, def)->type_id; + spl_ir_func_ref_t fid = spl_ir_alloc_fn(&a->ir); + spl_ir_func_t *f = spl_ir_func(&a->ir, fid); + f->name = m->fn_decl.name; + f->fn_tid = fn_tid; + } + for (usize i = 0; i < root->container_item.members.size; i++) { + spl_ast_node_ref_t mref = root->container_item.members.data[i]; + spl_ast_node_t *m = node_at(a->sema, mref); + if (!m || m->kind != SPL_AST_TYPE_DECL) + continue; + spl_ast_node_t *te = node_at(a->sema, 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)) + continue; + spl_def_id_t adef = root_lookup(a, m->type_decl.name); + if (!adef) + continue; + spl_type_id_t agg_tid = underlying(a->sema, def_at(a->sema, adef)->type_id); + for (usize j = 0; j < te->type_expr.aggregate_list.size; j++) { + spl_ast_node_ref_t mm = te->type_expr.aggregate_list.data[j]; + spl_ast_node_t *mn = node_at(a->sema, mm); + if (!mn || (mn->kind != SPL_AST_FN_DECL && mn->kind != SPL_AST_FN_DEFINE)) + continue; + spl_type_id_t mt = agg_member_type(a, agg_tid, mn->fn_decl.name); + if (!mt) + continue; + size_t nlen = strlen(m->type_decl.name) + 1 + strlen(mn->fn_decl.name) + 1; + char *fname = malloc(nlen); + snprintf(fname, nlen, "%s.%s", m->type_decl.name, mn->fn_decl.name); + spl_ir_func_ref_t fid = spl_ir_alloc_fn(&a->ir); + spl_ir_func_t *f = spl_ir_func(&a->ir, fid); + f->name = fname; + f->fn_tid = mt; + vec_push(a->owned_names, fname); + } + } +} + +void spl_ast2ir_run(spl_ast2ir_t *a) { + spl_ast_node_t *root = node_at(a->sema, a->sema->ast->root); + if (!root || root->kind != SPL_AST_CONTAINER_ITEM) + return; + register_funcs(a); + for (usize i = 0; i < root->container_item.members.size; i++) { + spl_ast_node_ref_t mref = root->container_item.members.data[i]; + spl_ast_node_t *m = node_at(a->sema, mref); + if (!m || m->kind != SPL_AST_FN_DEFINE) + continue; + spl_def_id_t def = root_lookup(a, m->fn_decl.name); + if (!def) + continue; + spl_type_id_t fn_tid = def_at(a->sema, def)->type_id; + spl_ir_func_ref_t fid = a2ir_fn_of(a, fn_tid); + if (fid) + lower_func_body(a, fid, fn_tid, mref, 0); + } + for (usize i = 0; i < root->container_item.members.size; i++) { + spl_ast_node_ref_t mref = root->container_item.members.data[i]; + spl_ast_node_t *m = node_at(a->sema, mref); + if (!m || m->kind != SPL_AST_TYPE_DECL) + continue; + spl_ast_node_t *te = node_at(a->sema, 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)) + continue; + spl_def_id_t adef = root_lookup(a, m->type_decl.name); + if (!adef) + continue; + spl_type_id_t agg_tid = underlying(a->sema, def_at(a->sema, adef)->type_id); + for (usize j = 0; j < te->type_expr.aggregate_list.size; j++) { + spl_ast_node_ref_t mm = te->type_expr.aggregate_list.data[j]; + spl_ast_node_t *mn = node_at(a->sema, mm); + if (!mn || mn->kind != SPL_AST_FN_DEFINE) + continue; + spl_type_id_t mt = agg_member_type(a, agg_tid, mn->fn_decl.name); + spl_ir_func_ref_t fid = mt ? a2ir_fn_of(a, mt) : 0; + if (fid) + lower_func_body(a, fid, mt, mm, agg_tid); + } + } +} diff --git a/stage1/spl_ast2ir.h b/stage1/spl_ast2ir.h index ed8ef87..f7c5446 100644 --- a/stage1/spl_ast2ir.h +++ b/stage1/spl_ast2ir.h @@ -1,4 +1,19 @@ #ifndef __SPL_AST2IR_H__ #define __SPL_AST2IR_H__ +#include "spl_ir.h" +#include "spl_sema.h" + +typedef struct { + const spl_sema_t *sema; + spl_ir_t ir; + VEC(char *) owned_names; /* 本模块 malloc 的函数名,drop 时释放 */ + int err_count; +} spl_ast2ir_t; + +void spl_ast2ir_init(spl_ast2ir_t *ast2ir, const spl_sema_t *sema); +void spl_ast2ir_drop(spl_ast2ir_t *ast2ir); + +void spl_ast2ir_run(spl_ast2ir_t *ast2ir); + #endif /* __SPL_AST2IR_H__ */ diff --git a/stage1/spl_ir.c b/stage1/spl_ir.c index 9259c5a..978b658 100644 --- a/stage1/spl_ir.c +++ b/stage1/spl_ir.c @@ -1 +1,484 @@ +/* spl_ir.c — function-based SIR IR (arena 容器 + 文本 dump) */ + #include "spl_ir.h" + +#include +#include + +/* ---- 内置函数名字表(与 spl_ir_kind_t 枚举一一对应) ---- */ +static const char *const ir_kind_names[] = { +#define X(a, b, c) #a, + SPL_IR_FN_TABLE +#undef X +}; + +void spl_ir_init(spl_ir_t *ir) { + memset(ir, 0, sizeof *ir); + vec_init(ir->funcs); + /* func ref 0 保留为 error,占位 */ + spl_ir_func_t f0; + memset(&f0, 0, sizeof f0); + vec_push(ir->funcs, f0); +} + +static void node_drop_vecs(spl_ir_node_t *n) { + if (!n) + return; + switch (n->kind) { + case SPL_IR_AGG_CONSTRUCT: + vec_free(n->agg_construct.fields); + break; + case SPL_IR_CONTROL_CALL: + vec_free(n->control_call.params); + break; + default: + break; + } +} + +void spl_ir_drop(spl_ir_t *ir) { + for (usize i = 0; i < ir->funcs.size; i++) { + spl_ir_func_t *f = &ir->funcs.data[i]; + for (usize j = 0; j < f->nodes.size; j++) + node_drop_vecs(&f->nodes.data[j]); + vec_free(f->nodes); + vec_free(f->labels); + } + vec_free(ir->funcs); +} + +spl_ir_func_ref_t spl_ir_alloc_fn(spl_ir_t *ir) { + spl_ir_func_t f; + memset(&f, 0, sizeof f); + vec_init(f.nodes); + vec_init(f.labels); + vec_push(ir->funcs, f); + return ir->funcs.size - 1; +} + +spl_ir_node_ref_t spl_ir_alloc_node(spl_ir_t *ir, spl_ir_func_ref_t fn_id) { + if (!fn_id || fn_id >= ir->funcs.size) + return 0; + spl_ir_func_t *f = &ir->funcs.data[fn_id]; + spl_ir_node_t n; + memset(&n, 0, sizeof n); + if (f->nodes.size == 0) { + vec_push(f->nodes, n); /* 占位:node ref 0 保留为 error */ + } + vec_push(f->nodes, n); + return f->nodes.size - 1; +} + +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) { + if (!fn_id || fn_id >= ir->funcs.size) + return NULL; + spl_ir_func_t *f = &ir->funcs.data[fn_id]; + if (!node_id || node_id >= f->nodes.size) + return NULL; + return &f->nodes.data[node_id]; +} + +spl_ir_func_t *spl_ir_func(spl_ir_t *ir, spl_ir_func_ref_t fn_id) { + if (!fn_id || fn_id >= ir->funcs.size) + return NULL; + return &ir->funcs.data[fn_id]; +} + +/* ================================================================ + * dump + * ================================================================ */ + +static void ir_type_dump(const spl_type_t *ty, spl_type_id_t tid) { + spl_type_node_t *n = spl_type_node((spl_type_t *)ty, tid); + if (!n) { + printf("?"); + 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("*"); + ir_type_dump(ty, n->ptr_pointee); + break; + case SPL_TYPE_SLICE: + printf("[]"); + ir_type_dump(ty, n->slice_element); + break; + case SPL_TYPE_RANGE: + printf("range["); + ir_type_dump(ty, n->range_element); + printf("]"); + break; + case SPL_TYPE_ARRAY: + printf("[%zu]", n->array_type.len); + ir_type_dump(ty, n->array_type.element); + break; + case SPL_TYPE_STRUCT: + printf("struct#%zu", tid); + break; + case SPL_TYPE_UNION: + printf("union#%zu", tid); + break; + case SPL_TYPE_ENUM: + printf("enum#%zu", tid); + break; + case SPL_TYPE_FN: + printf("fn<"); + for (usize i = 0; i < n->fn_type.params.size; i++) { + if (i) + printf(","); + ir_type_dump(ty, n->fn_type.params.data[i]); + } + printf("->"); + ir_type_dump(ty, n->fn_type.ret); + printf(">"); + break; + case SPL_TYPE_ID: + ir_type_dump(ty, n->type_id); + break; + default: + printf("?%zu", tid); + break; + } +} + +static const char *node_name(spl_ir_kind_t k) { + if ((usize)k < sizeof(ir_kind_names) / sizeof(ir_kind_names[0])) + return ir_kind_names[k]; + return "?"; +} + +static int node_produces_value(spl_ir_kind_t k) { + switch (k) { + case SPL_IR_MEM_STORE: + case SPL_IR_MEM_COPY: + case SPL_IR_MEM_SET: + case SPL_IR_MEM_FENCE: + case SPL_IR_CONTROL_BR: + case SPL_IR_CONTROL_JMP: + case SPL_IR_CONTROL_RET: + case SPL_IR_CONTROL_UNREACHABLE: + case SPL_IR_CONTROL_TRAP: + case SPL_IR_DBG_BREAKPOINT: + case SPL_IR_DBG_DECLARE: + return 0; + default: + return 1; + } +} + +static void dump_ref(spl_ir_node_ref_t r) { printf("%%%zu", r); } + +static void dump_node(const spl_type_t *ty, const spl_ir_node_t *n) { + switch (n->kind) { + case SPL_IR_TYPE_CONST: + printf("@type.const("); + ir_type_dump(ty, n->type_const.tid); + printf(")("); + { + spl_type_node_t *t = spl_type_node((spl_type_t *)ty, n->type_const.tid); + if (t && t->kind == SPL_TYPE_INT) + printf("%lld", (long long)n->type_const.int_lit); + else if (t && t->kind == SPL_TYPE_FLOAT) + printf("%g", n->type_const.float_lit); + else if (t && t->kind == SPL_TYPE_FN) + printf("@fn#%zu", n->type_const.fn); + else if (t && (t->kind == SPL_TYPE_PTR || t->kind == SPL_TYPE_SLICE)) { + if (n->type_const.cstr_lit) + printf("\"%s\"", n->type_const.cstr_lit); + else + printf("0"); + } else if (t && t->kind == SPL_TYPE_BOOL) + printf("%lld", (long long)n->type_const.int_lit); + else + printf("?"); + } + printf(")"); + break; + case SPL_IR_ARITH_ADD: + case SPL_IR_ARITH_SUB: + case SPL_IR_ARITH_MUL: + case SPL_IR_ARITH_DIV: + case SPL_IR_ARITH_REM: + case SPL_IR_ARITH_AND: + case SPL_IR_ARITH_OR: + case SPL_IR_ARITH_XOR: + case SPL_IR_ARITH_SHL: + case SPL_IR_ARITH_SHR: + printf("@%s(", node_name(n->kind)); + ir_type_dump(ty, n->arith.tid); + printf(")("); + dump_ref(n->arith.left); + if (n->arith.right) { + printf(", "); + dump_ref(n->arith.right); + } + printf(")"); + break; + case SPL_IR_ARITH_NEG: + case SPL_IR_ARITH_ABS: + case SPL_IR_ARITH_NOT: + printf("@%s(", node_name(n->kind)); + ir_type_dump(ty, n->arith.tid); + printf(")("); + dump_ref(n->arith.left); + printf(")"); + break; + case SPL_IR_CMP_EQ: + case SPL_IR_CMP_NE: + case SPL_IR_CMP_LT: + case SPL_IR_CMP_LE: + case SPL_IR_CMP_GT: + case SPL_IR_CMP_GE: + printf("@%s(", node_name(n->kind)); + ir_type_dump(ty, n->cmp.tid); + printf(")("); + dump_ref(n->cmp.a); + printf(", "); + dump_ref(n->cmp.b); + printf(")"); + break; + case SPL_IR_CAST_TRUNC: + case SPL_IR_CAST_ZEXT: + case SPL_IR_CAST_SEXT: + case SPL_IR_CAST_FEXT: + case SPL_IR_CAST_FTRUNC: + case SPL_IR_CAST_BITCAST: + case SPL_IR_CAST_PTR2INT: + case SPL_IR_CAST_INT2PTR: + case SPL_IR_CAST_BOOL2INT: + case SPL_IR_CASE_INT2FLOAT: + case SPL_IR_CASE_FLOAT2INT: + printf("@%s(", node_name(n->kind)); + ir_type_dump(ty, n->cast.from_tid); + printf(", "); + ir_type_dump(ty, n->cast.to_tid); + printf(")("); + dump_ref(n->cast.val); + printf(")"); + break; + case SPL_IR_MEM_ALLOCA: + printf("@mem.alloca("); + ir_type_dump(ty, n->mem_alloc.tid); + printf(")("); + dump_ref(n->mem_alloc.count); + printf(")"); + break; + case SPL_IR_MEM_LOAD: + printf("@mem.load("); + ir_type_dump(ty, n->mem_load.tid); + printf(")("); + dump_ref(n->mem_load.ptr); + printf(")"); + break; + case SPL_IR_MEM_STORE: + printf("@mem.store("); + ir_type_dump(ty, n->mem_store.tid); + printf(")("); + dump_ref(n->mem_store.ptr); + printf(", "); + dump_ref(n->mem_store.val); + printf(")"); + break; + case SPL_IR_MEM_OFFSET: + printf("@mem.offset("); + ir_type_dump(ty, n->mem_offset.tid); + printf(")("); + dump_ref(n->mem_offset.ptr); + printf(", "); + dump_ref(n->mem_offset.offset); + printf(")"); + break; + case SPL_IR_MEM_COPY: + printf("@mem.copy()("); + dump_ref(n->mem_copy.dst); + printf(", "); + dump_ref(n->mem_copy.src); + printf(", "); + dump_ref(n->mem_copy.size); + printf(")"); + break; + case SPL_IR_MEM_SET: + printf("@mem.set()("); + dump_ref(n->mem_set.dst); + printf(", "); + dump_ref(n->mem_set.val); + printf(", "); + dump_ref(n->mem_set.size); + printf(")"); + break; + case SPL_IR_MEM_FENCE: + printf("@mem.fence()("); + dump_ref(n->mem_fence.ordering); + printf(")"); + break; + case SPL_IR_TYPE_BITSIZEOF: + printf("@type.bitsizeof("); + ir_type_dump(ty, n->bitsizeof.tid); + printf(")()"); + break; + case SPL_IR_TYPE_SIZEOF: + printf("@type.sizeof("); + ir_type_dump(ty, n->ir_sizeof.tid); + printf(")()"); + break; + case SPL_IR_TYPE_ALIGNOF: + printf("@type.alignof("); + ir_type_dump(ty, n->ir_alignof.tid); + printf(")()"); + break; + case SPL_IR_TYPE_OFFSETOF: + printf("@type.offsetof("); + ir_type_dump(ty, n->ir_offsetof.tid); + printf(")("); + dump_ref(n->ir_offsetof.field_idx); + printf(")"); + break; + case SPL_IR_TYPE_FIELD_COUNT: + printf("@type.field_count("); + ir_type_dump(ty, n->field_count.tid); + printf(")()"); + break; + case SPL_IR_AGG_CONSTRUCT: + printf("@agg.construct("); + ir_type_dump(ty, n->agg_construct.tid); + printf(")("); + for (usize i = 0; i < n->agg_construct.fields.size; i++) { + if (i) + printf(", "); + dump_ref(n->agg_construct.fields.data[i]); + } + printf(")"); + break; + case SPL_IR_AGG_EXTRACT: + printf("@agg.extract("); + ir_type_dump(ty, n->agg_extract.tid); + printf(", %lld)(", (long long)n->agg_extract.field_idx); + dump_ref(n->agg_extract.val); + printf(")"); + break; + case SPL_IR_AGG_INSERT: + printf("@agg.insert("); + ir_type_dump(ty, n->agg_insert.tid); + printf(", %lld)(", (long long)n->agg_insert.field_idx); + dump_ref(n->agg_insert.agg); + printf(", "); + dump_ref(n->agg_insert.field); + printf(")"); + break; + case SPL_IR_CONTROL_SELECT: + printf("@control.select("); + ir_type_dump(ty, n->control_select.tid); + printf(")("); + dump_ref(n->control_select.cond); + printf(", "); + dump_ref(n->control_select.true_val); + printf(", "); + dump_ref(n->control_select.false_val); + printf(")"); + break; + case SPL_IR_CONTROL_BR: + printf("@control.br()("); + dump_ref(n->control_br.cond); + printf(", "); + dump_ref(n->control_br.true_label); + printf(", "); + dump_ref(n->control_br.false_label); + printf(")"); + break; + case SPL_IR_CONTROL_JMP: + printf("@control.jmp()("); + dump_ref(n->control_jmp.label); + printf(")"); + break; + case SPL_IR_CONTROL_CALL: + printf("@control.call("); + ir_type_dump(ty, n->control_call.tid); + printf(")("); + dump_ref(n->control_call.func); + for (usize i = 0; i < n->control_call.params.size; i++) { + printf(", "); + dump_ref(n->control_call.params.data[i]); + } + printf(")"); + break; + case SPL_IR_CONTROL_PARAM: + printf("@control.param("); + ir_type_dump(ty, n->control_param.tid); + printf(")(%lld)", (long long)n->control_param.idx); + break; + case SPL_IR_CONTROL_RET: + printf("@control.ret("); + ir_type_dump(ty, n->control_ret.tid); + printf(")("); + if (n->control_ret.val) + dump_ref(n->control_ret.val); + printf(")"); + break; + case SPL_IR_CONTROL_UNREACHABLE: + printf("@control.unreachable()()"); + break; + case SPL_IR_CONTROL_TRAP: + printf("@control.trap()()"); + break; + case SPL_IR_DBG_BREAKPOINT: + printf("@dbg.breakpoint()()"); + break; + case SPL_IR_DBG_DECLARE: + printf("@dbg.declare()()"); + break; + default: + printf("@%s()()", node_name(n->kind)); + break; + } +} + +static void dump_func(const spl_type_t *ty, const spl_ir_func_t *f) { + printf("func @%s", f->name ? f->name : "?"); + if (f->fn_tid) { + spl_type_node_t *t = spl_type_node((spl_type_t *)ty, f->fn_tid); + if (t && t->kind == SPL_TYPE_FN) { + printf("("); + for (usize i = 0; i < t->fn_type.params.size; i++) { + if (i) + printf(", "); + ir_type_dump(ty, t->fn_type.params.data[i]); + } + printf(") -> "); + ir_type_dump(ty, t->fn_type.ret); + } + } + printf(" {\n"); + usize li = 0; + for (usize i = 1; i < f->nodes.size; i++) { + if (li < f->labels.size && f->labels.data[li] == i) { + printf("#bb%zu:\n", li); + li++; + } + printf(" "); + if (node_produces_value(f->nodes.data[i].kind)) + printf("%%%zu = ", i); + dump_node(ty, &f->nodes.data[i]); + printf("\n"); + } + if (li < f->labels.size && f->labels.data[li] == f->nodes.size) + printf("#bb%zu:\n", li); + printf("}\n"); +} + +void spl_ir_dump(spl_ir_t *ir, const spl_type_t *ty) { + printf("; SPL IR module (%zu funcs)\n", ir->funcs.size - 1); + for (usize i = 1; i < ir->funcs.size; i++) + dump_func(ty, &ir->funcs.data[i]); +} diff --git a/stage1/spl_ir.h b/stage1/spl_ir.h index f978f80..ce1ccc9 100644 --- a/stage1/spl_ir.h +++ b/stage1/spl_ir.h @@ -2,6 +2,7 @@ #define __SPL_IR_H__ #include "../stage0/include/utils.h" +#include "spl_type.h" /* clang-format off */ #define SPL_IR_FN_TABLE \ @@ -64,6 +65,7 @@ X(control.br, V0, SPL_IR_CONTROL_BR) \ X(control.jmp, V0, SPL_IR_CONTROL_JMP) \ X(control.call, V0, SPL_IR_CONTROL_CALL) \ + X(control.param, V0, SPL_IR_CONTROL_PARAM) \ X(control.ret, V0, SPL_IR_CONTROL_RET) \ X(control.unreachable, V0, SPL_IR_CONTROL_UNREACHABLE) \ X(control.trap, V0, SPL_IR_CONTROL_TRAP) \ @@ -80,14 +82,136 @@ typedef enum { } spl_ir_kind_t; /* clang-format on */ -typedef struct { - spl_ir_kind_t kind; -} spl_ir_node_t; -typedef VEC(spl_ir_node_t) spl_ir_node_vec_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 usize spl_ir_func_ref_t; /* 0 is error */ + +typedef struct { + spl_ir_kind_t kind; + union { + struct { + spl_type_id_t tid; + spl_ir_node_ref_t left; + spl_ir_node_ref_t right; + } arith; + struct { + spl_type_id_t tid; + spl_ir_node_ref_t a; + spl_ir_node_ref_t b; + } cmp; + struct { + spl_type_id_t from_tid; + spl_type_id_t to_tid; + spl_ir_node_ref_t val; + } cast; + struct { + spl_type_id_t tid; + spl_ir_node_ref_t count; + } mem_alloc; + struct { + spl_type_id_t tid; + spl_ir_node_ref_t ptr; + } mem_load; + struct { + spl_type_id_t tid; + spl_ir_node_ref_t ptr; + spl_ir_node_ref_t val; + } mem_store; + struct { + spl_type_id_t tid; + spl_ir_node_ref_t ptr; + spl_ir_node_ref_t offset; + } mem_offset; + struct { + spl_type_id_t tid; + spl_ir_node_ref_t dst; + spl_ir_node_ref_t src; + spl_ir_node_ref_t size; + } mem_copy; + struct { + spl_type_id_t tid; + spl_ir_node_ref_t dst; + spl_ir_node_ref_t val; + spl_ir_node_ref_t size; + } mem_set; + struct { + spl_ir_node_ref_t ordering; + } mem_fence; + struct { + spl_type_id_t tid; + union { + usize int_lit; + double float_lit; + const char *cstr_lit; + char ch_lit; + spl_ir_func_ref_t fn; + }; + } type_const; + struct { + spl_type_id_t tid; + } bitsizeof; + struct { + spl_type_id_t tid; + } ir_sizeof; + struct { + spl_type_id_t tid; + } ir_alignof; + struct { + spl_type_id_t tid; + spl_ir_node_ref_t field_idx; + } ir_offsetof; + struct { + spl_type_id_t tid; + } field_count; + + struct { + spl_type_id_t tid; + spl_ir_node_ref_vec_t fields; + } agg_construct; + struct { + spl_type_id_t tid; + isize field_idx; + spl_ir_node_ref_t val; + } agg_extract; + struct { + spl_type_id_t tid; + isize field_idx; + spl_ir_node_ref_t agg; + spl_ir_node_ref_t field; + } agg_insert; + + struct { + spl_type_id_t tid; + spl_ir_node_ref_t cond; + spl_ir_node_ref_t true_val; + spl_ir_node_ref_t false_val; + } control_select; + struct { + spl_ir_node_ref_t cond; + spl_ir_node_ref_t true_label; + spl_ir_node_ref_t false_label; + } control_br; + struct { + spl_ir_node_ref_t label; + } control_jmp; + struct { + spl_type_id_t tid; + spl_ir_node_ref_t func; + spl_ir_node_ref_vec_t params; + } control_call; + struct { + spl_type_id_t tid; + spl_ir_node_ref_t idx; + } control_param; + struct { + spl_type_id_t tid; + spl_ir_node_ref_t val; + } control_ret; + }; +} spl_ir_node_t; +typedef VEC(spl_ir_node_t) spl_ir_node_vec_t; + typedef struct { enum { SPL_IR_ATTR_NONE, @@ -103,12 +227,12 @@ typedef VEC(spl_ir_attr_t) spl_ir_attr_vec_t; typedef struct { const char *name; spl_ir_attr_t attr; + spl_type_id_t fn_tid; 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 VEC(spl_ir_func_t) spl_ir_func_vec_t; typedef struct { spl_ir_func_vec_t funcs; } spl_ir_t; @@ -122,6 +246,6 @@ 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); +void spl_ir_dump(spl_ir_t *ir, const spl_type_t *ty); #endif /* __SPL_IR_H__ */ diff --git a/stage1/spl_sema.c b/stage1/spl_sema.c index 7355a67..011d925 100644 --- a/stage1/spl_sema.c +++ b/stage1/spl_sema.c @@ -112,11 +112,11 @@ static spl_type_id_t find_type(spl_sema_t *sema, const char *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_scope_id_t scope, spl_def_id_t member_def) { 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}; + spl_var_def_t v = {name, member_def, type, scope}; vec_push(d->agg_def, v); } @@ -281,6 +281,9 @@ static spl_type_id_t resolve_type_expr(spl_sema_t *sema, spl_ast_node_ref_t ref) (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 `*_`"); } + /* AST 注解:该 type_expr 解析到的 def(聚合/别名/内置为 0;ast2ir 据此直接取类型) */ + if (base) + n->resolved_def_id = def_for_type(sema, base); return base; } @@ -331,6 +334,7 @@ static agg_handle_t agg_prepare(spl_sema_t *sema, spl_ast_node_ref_t ref) { 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); + te->resolved_def_id = def; /* 注解:该 type_expr 解析到的 def */ h.tid = tid; h.def = def; return h; @@ -366,13 +370,20 @@ static void agg_resolve(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_type_id_t 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); + /* 每个 MEMBER_DECL 建一个 SPL_DEF_MEMBER def(结构字段/枚举变体) */ + spl_type_id_t mtype = 0; 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); + mtype = ft ? ft : tid; /* 哨兵:无载荷变体 = 枚举自身 tid */ + vec_push(tn->enum_type.variants, mtype); } else { + mtype = ft; vec_push(tn->agg_field_types, ft); - agg_add_member(sema, def, m->member_decl.name, ft, agg_scope); } + spl_def_id_t mdef = def_alloc(sema, SPL_DEF_MEMBER); + def_at(sema, mdef)->type_id = mtype; + def_at(sema, mdef)->var_def.name = m->member_decl.name; + agg_add_member(sema, def, m->member_decl.name, mtype, agg_scope, mdef); + m->resolved_def_id = mdef; /* 注解:member_decl → 其 SPL_DEF_MEMBER def */ break; } case SPL_AST_FN_DECL: @@ -416,13 +427,19 @@ static spl_type_id_t build_agg(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_sco /* 变量/常量/绑定节点:建 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_scope_id_t scope, spl_def_id_t agg_def, + spl_ast_node_ref_t node_ref) { 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); + agg_add_member(sema, agg_def, name, t, scope, def); + if (node_ref) { + spl_ast_node_t *nn = node_at(sema->ast, node_ref); + if (nn) + nn->resolved_def_id = def; /* 注解:var/const 声明 → 其 VAR def */ + } } static void sema_var_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t scope, @@ -430,7 +447,7 @@ static void sema_var_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id 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); + register_binding(sema, n->var_decl.name, n->var_decl.type_expr, scope, agg_def, ref); } static void sema_const_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t scope, @@ -438,7 +455,7 @@ static void sema_const_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_ 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); + register_binding(sema, n->const_decl.name, n->const_decl.type_expr, scope, agg_def, ref); } /* fn 声明:建 fn type + FN_PARAMS def + 登记名字。不建 fn_scope(由 check 新建)。 @@ -477,7 +494,8 @@ static void sema_fn_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_ 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); + agg_add_member(sema, agg_def, n->fn_decl.name, fid, scope, fdef); + n->resolved_def_id = fdef; /* 注解:fn 声明 → 其 FN_PARAMS def */ } static void sema_type_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t scope, @@ -510,10 +528,11 @@ static void sema_type_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_i 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); + agg_add_member(sema, agg_def, n->type_decl.name, tid, scope, def); /* 嵌套类型提升到文件作用域:兄弟聚合可裸名引用(如 Lexer 方法内 Tag.eof) */ if (agg_def) spl_sema_scope_insert(sema, sema->root_scope, n->type_decl.name, def); + n->resolved_def_id = def; /* 注解:type_decl → 其 AGG/ALIAS def */ } /* ================================================================ @@ -937,14 +956,32 @@ static spl_type_id_t infer_array_lit(spl_sema_t *sema, spl_ast_node_ref_t ref, s /* 标识符: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); + spl_def_id_t def = find_bare(sema, pn->primary_expr.ident); + spl_type_id_t t = def_type(sema, def); if (!t) { sema_error(sema, ref, "undefined identifier"); return 0; } + /* 注解:IDENT 引用 → 其符号 def(var 用 VAR、fn 用 FN_PARAMS 等) */ + pn->resolved_def_id = def; return t; } +/* 表达式 ref 解析到的 def:取内层节点注解;裸 ident 兜底 find_bare */ +static spl_def_id_t expr_def_at(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 0; + spl_ast_node_t *inner = node_at(sema->ast, n->expr.op_expr.left); + if (!inner) + return 0; + if (inner->resolved_def_id) + return inner->resolved_def_id; + if (n->expr.op == SPL_AST_PRIMARY_EXPR && inner->primary_expr.kind == SPL_AST_IDENT) + return find_bare(sema, inner->primary_expr.ident); + return 0; +} + 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); @@ -1080,6 +1117,8 @@ static spl_type_id_t infer_postfix(spl_sema_t *sema, spl_ast_node_ref_t ref, spl /* 指针自动解引用一层 */ if (t && t->kind == SPL_TYPE_PTR) base = underlying(sema, t->ptr_pointee); + /* 注解:FIELD 节点 → 被访问聚合(自动解引用后)的 AGG def;非聚合为 0 */ + pf->resolved_def_id = def_for_type(sema, base); t = type_node(sema, base); if (!t) { sema_error(sema, ref, "field access on non-aggregate"); @@ -1171,6 +1210,8 @@ static spl_type_id_t infer_postfix(spl_sema_t *sema, spl_ast_node_ref_t ref, spl sema_error(sema, ref, "call requires function type"); return 0; } + /* 注解:CALL 节点 → 被调 fn 的 def(从 callee primary 节点/裸名解析) */ + pf->resolved_def_id = expr_def_at(sema, pf->postfix_expr.primary_expr); spl_ast_node_ref_vec_t *args = &pf->postfix_expr.call_expr; /* 变参 fn(如 vm_printf)最后一个形参 name=NULL 且类型可为 0 */ /* 注意:infer_expr 可能新分配类型使 type_table realloc,t 会失效,须每次刷新 */ @@ -1623,11 +1664,13 @@ static void check_block(spl_sema_t *sema, spl_ast_node_ref_vec_t *block, spl_sco 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); + register_binding(sema, vd->var_decl.name, vd->var_decl.type_expr, scope, 0, + b->block_item.var_decl); } 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); + register_binding(sema, cd->const_decl.name, cd->const_decl.type_expr, scope, 0, + b->block_item.const_decl); } 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) @@ -1664,6 +1707,10 @@ static void check_fn_body(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_def_id_t 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); + /* 注解:param_decl → 其在 fn_scope 的 VAR def */ + spl_ast_node_t *pd = node_at(sema->ast, n->fn_decl.param_list.data[i]); + if (pd) + pd->resolved_def_id = pdef; } } check_block(sema, &n->fn_decl.block, fn_scope, ctx); @@ -1745,7 +1792,7 @@ void spl_sema_run(spl_sema_t *sema) { 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); + agg_add_member(sema, sema->root_def, m->type_decl.name, h.tid, sema->root_scope, h.def); } 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); @@ -1757,7 +1804,7 @@ void spl_sema_run(spl_sema_t *sema) { 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); + agg_add_member(sema, sema->root_def, m->type_decl.name, tid, sema->root_scope, def); } } /* 1b. fn 名(建 fn type + def) */ diff --git a/stage1/spl_type.c b/stage1/spl_type.c index 24f4617..dc5f64e 100644 --- a/stage1/spl_type.c +++ b/stage1/spl_type.c @@ -211,6 +211,8 @@ static const char *def_kind_name(spl_def_node_t *d) { return "builtin"; case SPL_DEF_VAR: return "var"; + case SPL_DEF_MEMBER: + return "member"; case SPL_DEF_FN_PARAMS: return "fn_params"; case SPL_DEF_AGG: @@ -296,6 +298,9 @@ void spl_type_def_dump(spl_type_t *type, spl_def_id_t id) { case SPL_DEF_VAR: printf(" var=%s", d->var_def.name ? d->var_def.name : "?"); break; + case SPL_DEF_MEMBER: + printf(" member=%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 : "?"); diff --git a/stage1/spl_type.h b/stage1/spl_type.h index f056e88..237489c 100644 --- a/stage1/spl_type.h +++ b/stage1/spl_type.h @@ -65,6 +65,7 @@ typedef struct { enum { SPL_DEF_NONE, SPL_DEF_BUILTIN, + SPL_DEF_MEMBER, SPL_DEF_VAR, SPL_DEF_FN_PARAMS, SPL_DEF_AGG, // include enum variants diff --git a/stage1/splc0.c b/stage1/splc0.c index 904af58..21ceea2 100644 --- a/stage1/splc0.c +++ b/stage1/splc0.c @@ -11,6 +11,7 @@ #include #include "spl_ast.h" +#include "spl_ast2ir.h" #include "spl_lexer.h" #include "spl_sema.h" #include "spl_tok.h" @@ -102,6 +103,34 @@ static void dump_sema(const char *src, const char *fname) { spl_ast_drop(&ast); } +static void dump_ir(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); + if (sema.error_count) { + printf("sema errors=%d, skip IR\n", sema.error_count); + spl_sema_drop(&sema); + spl_ast_drop(&ast); + return; + } + spl_ast2ir_t a2ir; + spl_ast2ir_init(&a2ir, &sema); + spl_ast2ir_run(&a2ir); + if (a2ir.err_count) + printf("ast2ir errors=%d\n", a2ir.err_count); + spl_ir_dump(&a2ir.ir, &sema.type); + spl_ast2ir_drop(&a2ir); + 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); @@ -110,12 +139,15 @@ static int cmd_dump(const char *flags, const char *path) { 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; + int do_ir = strstr(flags, "ir") != 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); + if (do_ir) + dump_ir(src, path); free(src); return 0; } @@ -127,7 +159,7 @@ 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,sema,all\n"); + LOG_INFO("splc0 --dump dump: tokens,ast,sema,ir,all\n"); return 0; } int argi = 1; diff --git a/stage1/test18_match.spl b/stage1/test18_match.spl index a7e211d..f7b977d 100644 --- a/stage1/test18_match.spl +++ b/stage1/test18_match.spl @@ -20,8 +20,8 @@ type Optional = enum { /* ---- 带结构体数据的枚举 ---- */ type Point = struct { - var x: i32; - var y: i32; + x: i32; + y: i32; } type Shape = enum { diff --git a/stage1/test20_complex.spl b/stage1/test20_complex.spl index fa15889..8e60693 100644 --- a/stage1/test20_complex.spl +++ b/stage1/test20_complex.spl @@ -1,54 +1,54 @@ /* ===== 复杂类型嵌套综合测试 ===== - * test20_complex — 结构体嵌套、切片、数组、方法、类型别名、枚举等 - * 难度:5/5 + * test20_complex ?结构体嵌套、切片、数组、方法、类型别名、枚举等 + * 难度?/5 */ -/* ---- 基础结构体 ---- */ +/* ---- 基础结构?---- */ type Point = struct { - var x: i32; - var y: i32; + x: i32, + y: i32, } -/* ---- 嵌套结构体 ---- */ +/* ---- 嵌套结构?---- */ type Rect = struct { - var min: Point; - var max: Point; + min: Point, + max: Point, } -/* ---- 含切片字段的结构体 (核心 bug 测试) ---- */ +/* ---- 含切片字段的结构?(核心 bug 测试) ---- */ type Buffer = struct { - var data: []u8; - var len: usize; + data: []u8, + len: usize, } -/* ---- 含数组字段的结构体 ---- */ +/* ---- 含数组字段的结构?---- */ type MatrixRow = struct { - var items: [4]i32; + items: [4]i32, } -/* ---- 含指针字段的结构体 ---- */ +/* ---- 含指针字段的结构?---- */ type Node = struct { - var ptr: *i32; - var val: i32; + ptr: *i32, + val: i32, } /* ---- 多层级嵌套:结构体里的结构体里的切片 ---- */ type Bundle = struct { - var name: *u8; - var buf: Buffer; - var row: MatrixRow; - var pt: Point; + name: *u8, + buf: Buffer, + row: MatrixRow, + pt: Point, } -/* ---- 枚举含数据 ---- */ +/* ---- 枚举含数?---- */ type Status = enum { Active: i32; Inactive; Pending: Point; } -/* ---- 含方法的结构体 (方法定义在结构体内部) ---- */ +/* ---- 含方法的结构?(方法定义在结构体内部) ---- */ type Counter = struct { - var val: i32; + val: i32, fn inc(self: *Counter) i32 { self.val = self.val + 1; @@ -70,7 +70,7 @@ type Counter = struct { } /* ============================================================ - * 测试 1: 切片在结构体内部初始化 (修复的核心 bug) + * 测试 1: 切片在结构体内部初始?(修复的核?bug) * ============================================================ */ fn test_slice_in_struct() i32 { @@ -85,7 +85,7 @@ fn test_slice_in_struct() i32 { if b.data[1] != 66 { ret 3; } if b.data[3] != 68 { ret 4; } - /* Modify through slice — verify reflection */ + /* Modify through slice ?verify reflection */ b.data[0] = 90; if raw[0] != 90 { ret 5; } @@ -150,7 +150,7 @@ fn test_nested_struct() i32 { } /* ============================================================ - * 测试 4: 结构体成员方法 (实例方法调用) + * 测试 4: 结构体成员方?(实例方法调用) * ============================================================ */ fn test_struct_method() i32 { @@ -161,7 +161,7 @@ fn test_struct_method() i32 { if r1 != 1 { ret 1; } if c.val != 1 { ret 2; } - /* 带参数方法调用 c.add(&c, n) */ + /* 带参数方法调?c.add(&c, n) */ var r2: i32 = c.add(&c, 5); if r2 != 6 { ret 3; } if c.val != 6 { ret 4; } @@ -193,7 +193,7 @@ fn test_ptr_in_struct() i32 { v = 100; if n.ptr[0] != 100 { ret 3; } - /* 通过指针在结构体内修改 */ + /* 通过指针在结构体内修?*/ n.ptr[0] = 200; if v != 200 { ret 4; } @@ -201,7 +201,7 @@ fn test_ptr_in_struct() i32 { } /* ============================================================ - * 测试 6: 多层级复杂嵌套 + * 测试 6: 多层级复杂嵌? * ============================================================ */ fn test_complex_nesting() i32 { @@ -289,7 +289,7 @@ fn test_enum_complex() i32 { } /* ============================================================ - * 主函数 + * 主函? * ============================================================ */ fn main() i32 {