stage1 修复设计问题 实现ast2ir
This commit is contained in:
66
SPL.md
66
SPL.md
@@ -432,7 +432,7 @@ fn name(x: i32 = 0) { ... }
|
|||||||
声明 静态约束 动态语义
|
声明 静态约束 动态语义
|
||||||
FnDecl 名称唯一,签名完整。 仅定义。
|
FnDecl 名称唯一,签名完整。 仅定义。
|
||||||
TypeDecl 同作用域名称唯一。 定义类型别名或聚合体,编译时解析。
|
TypeDecl 同作用域名称唯一。 定义类型别名或聚合体,编译时解析。
|
||||||
VarDecl (容器级) var: 必须初始化,类型完整。const: 初始化必须编译期可求值。 const 编译时计算;var 启动初始化一次。
|
VarDecl var: 必须初始化,类型完整。 const: 初始化必须编译期可求值。 const 编译时计算;var 启动初始化一次。
|
||||||
ConstDecl 必须编译期可求值。 编译期常量。
|
ConstDecl 必须编译期可求值。 编译期常量。
|
||||||
ComptimeStmt 内部代码全部在编译时执行。 编译时执行,可生成声明。
|
ComptimeStmt 内部代码全部在编译时执行。 编译时执行,可生成声明。
|
||||||
DirectiveBlock @id { } / #id { } 为扩展占位,无预定义行为。未识别指令触发警告/错误。 同左。
|
DirectiveBlock @id { } / #id { } 为扩展占位,无预定义行为。未识别指令触发警告/错误。 同左。
|
||||||
@@ -478,12 +478,21 @@ type T = TypeExpr — 完全同义。
|
|||||||
|
|
||||||
匹配: match 必须穷举 (或含 _),否则编译错误。
|
匹配: 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)。
|
1. 函数内部 (参数 + 块局部,每个 {} 建立子 scope)。
|
||||||
2. $root:文件聚合的 scope,所有顶层声明 (fn/type/var/const) 都是其成员。
|
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: 可变量。
|
var x: T 或 var x := init: 可变量。
|
||||||
@@ -585,7 +594,9 @@ defer { ... }: 退出作用域时以后进先出执行。
|
|||||||
|
|
||||||
浮点 f64,布尔 bool。
|
浮点 f64,布尔 bool。
|
||||||
|
|
||||||
null -> ?T 隐式转换。
|
字符 'c'(含转义)默认 u8,视为整数字面量可参与拓宽。
|
||||||
|
|
||||||
|
null:空指针字面量。当前语言无 ?T,null 仅用于指针或切片的比较、赋值、初始化及聚合字段;其他用法为错误。
|
||||||
|
|
||||||
### 运算符
|
### 运算符
|
||||||
算术/位运算: 操作数类型必须完全一致或由字面量推导,无隐式提升。
|
算术/位运算: 操作数类型必须完全一致或由字面量推导,无隐式提升。
|
||||||
@@ -615,6 +626,8 @@ expr(args) 可调用 函数调用
|
|||||||
|
|
||||||
结构体字面量: Type { .f1 = v1, ... }。
|
结构体字面量: Type { .f1 = v1, ... }。
|
||||||
|
|
||||||
|
匿名聚合字面量: .{ .f1 = v1, ... }。省去显式类型名,必须出现在能由上下文推导目标聚合类型的语境 (变量初始化带类型、赋值、字段值等);无法推导目标类型则编译错误。切片可用 .{ .ptr = p, .len = n } 构造。
|
||||||
|
|
||||||
块表达式: { ... }。
|
块表达式: { ... }。
|
||||||
|
|
||||||
comptime { ... } / comptime expr;: 编译时求值,不可引用运行时变量。
|
comptime { ... } / comptime expr;: 编译时求值,不可引用运行时变量。
|
||||||
@@ -628,6 +641,8 @@ comptime { ... } / comptime expr;: 编译时求值,不可引用运行时变量
|
|||||||
|
|
||||||
函数类型: fn(T1, T2) RetType。
|
函数类型: fn(T1, T2) RetType。
|
||||||
|
|
||||||
|
裸 `_` 与 `ptr` 关键字不能作为独立类型 (单独出现为编译错误),`_` 只能以 `*_` 形式作指针目标,语义为"任意指针";`ptr` 关键字当前保留未启用。
|
||||||
|
|
||||||
*_ 的特殊规则:
|
*_ 的特殊规则:
|
||||||
|
|
||||||
*T -> *_: 允许,必须警告。
|
*T -> *_: 允许,必须警告。
|
||||||
@@ -638,9 +653,7 @@ comptime { ... } / comptime expr;: 编译时求值,不可引用运行时变量
|
|||||||
|
|
||||||
其他隐式转换:
|
其他隐式转换:
|
||||||
|
|
||||||
整数字面量适配更大类型。
|
null -> 指针/切片空值。
|
||||||
|
|
||||||
null -> ?T。
|
|
||||||
|
|
||||||
其余必须显式 as。
|
其余必须显式 as。
|
||||||
|
|
||||||
@@ -648,13 +661,15 @@ null -> ?T。
|
|||||||
区间类型 Range
|
区间类型 Range
|
||||||
语法 a..b 或 a..。
|
语法 a..b 或 a..。
|
||||||
|
|
||||||
内部结构: { begin: i64, end: ?i64 } (具体整数类型可能由上下文决定,默认为 i64)。
|
内部结构: { begin: <int>, end: <int> },其中 <int> 为边界整数类型 (左右边界类型一致,默认/通常为 isize 或 usize;无界端 end 存为空值表示无穷)。
|
||||||
|
|
||||||
a..b: begin = a, end = b。
|
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
|
切片类型 []T
|
||||||
内部结构: { ptr: *T, len: usize }。
|
内部结构: { ptr: *T, len: usize }。
|
||||||
@@ -732,13 +747,13 @@ void: 大小为 0,表示无值,仅用于函数返回或指针。
|
|||||||
从数组构造: array[a..b] 产生切片。
|
从数组构造: array[a..b] 产生切片。
|
||||||
|
|
||||||
### 区间类型
|
### 区间类型
|
||||||
a..b 或 a..: 类型为 Range,内部结构 { begin: isize, end: ?isize }。
|
a..b 或 a..: 类型为 Range,内部结构 { begin: <int>, end: <int> },<int> 为边界整数类型 (左右边界一致,默认 isize 或 usize;无界端 end 存空值)。
|
||||||
|
|
||||||
a..b: end 为 b。
|
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 的形式 (具体实现定义)。
|
?T: 可为 null 的类型。内部表示同 T 但附加一个判别 (可能通过 null 指针表示,视 T 而定)。?T 的大小和对齐与 T 相同或扩展为可容纳 null 的形式 (具体实现定义)。
|
||||||
|
|
||||||
null 字面量只能出现在需要 ?T 的上下文中。
|
当前阶段未实现 ?T,null 以"指针/切片的空值"语义生效 (见"特殊类型"与"类型兼容性")。
|
||||||
|
|
||||||
### 聚合类型
|
### 聚合类型
|
||||||
struct: 字段连续排列 (可能有对齐填充),每个字段有自己的类型。赋值是逐字段拷贝。
|
struct: 字段连续排列 (可能有对齐填充),每个字段有自己的类型。赋值是逐字段拷贝。
|
||||||
@@ -772,7 +787,7 @@ enum: 带标签的联合体,每个变体可有载荷。大小实现定义,
|
|||||||
### 特殊类型
|
### 特殊类型
|
||||||
void: 无法实例化,仅用于返回或指针目标。
|
void: 无法实例化,仅用于返回或指针目标。
|
||||||
|
|
||||||
null: 不是独立类型,仅用于初始化或赋值给 ?T。
|
null: 不是独立类型,是"指针/切片空值"字面量,仅用于指针或切片的初始化、赋值、比较及聚合字段。
|
||||||
|
|
||||||
## 类型兼容性与隐式转换
|
## 类型兼容性与隐式转换
|
||||||
下表中,“允许”表示可自动转换,否则需要显式 as 转换。警告列表明编译器必须输出诊断信息,不可静默。
|
下表中,“允许”表示可自动转换,否则需要显式 as 转换。警告列表明编译器必须输出诊断信息,不可静默。
|
||||||
@@ -782,12 +797,10 @@ T (任意) T 是 无 相同类型
|
|||||||
*T *_ 是 警告: “丢失类型信息”
|
*T *_ 是 警告: “丢失类型信息”
|
||||||
*_ *T 是 警告: “不安全的指针重解释”
|
*_ *T 是 警告: “不安全的指针重解释”
|
||||||
[N]T []T 是 无 数组到切片强制转换
|
[N]T []T 是 无 数组到切片强制转换
|
||||||
整数字面量 整数类型 U 是 (若值在 U 范围内) 无 字面量自动拓宽
|
整数字面量 整数类型 U 是 (若值在 U 范围内) 无 字面量自动拓宽 (含字符 'c' 视为 u8)
|
||||||
i32 i64 否 — 需显式 as i64,防止意外
|
i32 i64 否 — 需显式 as i64,防止意外
|
||||||
i64 i32 否 — 窄化必须显式
|
i64 i32 否 — 窄化必须显式
|
||||||
null ?T 是 无 空值初始化
|
null *T / []T 是 无 空指针/空切片初始化、比较、赋值、聚合字段
|
||||||
?T T 否 — 需显式解包 (如 orelse,但语言暂未定义,将来扩展)
|
|
||||||
T ?T 是 无 提升为可选
|
|
||||||
浮点字面量 f32 是 (值可表示则) 无
|
浮点字面量 f32 是 (值可表示则) 无
|
||||||
f64 f32 否 — 窄化需显式
|
f64 f32 否 — 窄化需显式
|
||||||
bool 整数 否 —
|
bool 整数 否 —
|
||||||
@@ -795,9 +808,11 @@ bool 整数 否 —
|
|||||||
|
|
||||||
注:
|
注:
|
||||||
|
|
||||||
|
?T (可选类型) 为预留特性,当前阶段未实现;null 语义以"指针/切片的空值"生效,见本表 null 行。
|
||||||
|
|
||||||
隐式转换不会嵌套传递。例如 *T 到 *_ 是警告转换,但不因此进一步允许 *_ 到 **T 的隐式转换。
|
隐式转换不会嵌套传递。例如 *T 到 *_ 是警告转换,但不因此进一步允许 *_ 到 **T 的隐式转换。
|
||||||
|
|
||||||
字面量拓宽仅适用于整数字面量直接出现在需要更宽整数类型的上下文 (如赋值给 i64 变量,或作为 Range 的边界,Range 内部为 isize,所以 0..5 中的 0 和 5 会拓宽为 isize)。
|
字面量拓宽仅适用于整数字面量直接出现在需要更宽整数类型的上下文 (如赋值给 i64 变量,或作为 Range 的边界,Range 内部为 isize,所以 0..5 中的 0 和 5 会拓宽为 isize;字符 'c' 同视为整数字面量)。
|
||||||
|
|
||||||
所有其他未列出的类型转换均需显式 as。
|
所有其他未列出的类型转换均需显式 as。
|
||||||
|
|
||||||
@@ -811,7 +826,7 @@ FLOAT -> f64
|
|||||||
|
|
||||||
true / false -> bool
|
true / false -> bool
|
||||||
|
|
||||||
null -> 必须从上下文推导出 ?T,无法推导则报错。
|
null -> 必须从上下文推导出 *T 或 []T 的空值 (当前无 ?T),用于比较/赋值/字段;无法推导或用于非指针上下文则报错。
|
||||||
|
|
||||||
字符串字面量 -> []u8 (具体待定)
|
字符串字面量 -> []u8 (具体待定)
|
||||||
|
|
||||||
@@ -936,7 +951,7 @@ ForRange 提供表达式列表 [E1, E2, ...]。as 后标识符列表 [v1, v2, ..
|
|||||||
|
|
||||||
对于 Ei:
|
对于 Ei:
|
||||||
|
|
||||||
若为 Range: 每次迭代产出的值类型为 isize (Range 的边界类型,这里默认为 isize)。
|
若为 Range: 每次迭代产出的值类型为 Range 的边界整数类型 (即 begin/end 的类型,默认 isize 或 usize)。
|
||||||
|
|
||||||
若为 []T 或 [N]T: 产出元素类型为 T。
|
若为 []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 决定。
|
若存在无界 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 决定
|
// 0..: Range 无界 -> idx: i64,长度由 my_slice 决定
|
||||||
```
|
```
|
||||||
## 类型系统限制
|
## 类型系统限制
|
||||||
无隐式类型提升 (除字面量整数拓宽和数组到切片外)。
|
|
||||||
|
|
||||||
无默认初始化: var x: T; 不初始化,警告/错误。
|
无默认初始化: var x: T; 不初始化,警告/错误。
|
||||||
|
|
||||||
无隐式 deref 多级: . 仅自动解引用一层。
|
无隐式 deref 多级: . 仅自动解引用一层。
|
||||||
@@ -1008,7 +1021,7 @@ Function ← AttributeList? 'func' GLOBAL_IDENT '(' ParamDefs? ')' '->' Type
|
|||||||
AttributeList ← Attribute (',' Attribute)*
|
AttributeList ← Attribute (',' Attribute)*
|
||||||
Attribute ← '!' IDENTIFIER ( '(' Args? ')' )? // 标记,如 !export("C")
|
Attribute ← '!' IDENTIFIER ( '(' Args? ')' )? // 标记,如 !export("C")
|
||||||
|
|
||||||
GLOBAL_IDENT ← '@' IDENTIFIER
|
GLOBAL_IDENT ← IDENTIFIER
|
||||||
|
|
||||||
ParamDefs ← LOCAL_IDENT ':' Type (',' LOCAL_IDENT ':' Type)*
|
ParamDefs ← LOCAL_IDENT ':' Type (',' LOCAL_IDENT ':' Type)*
|
||||||
Block ← '{' Stmt* '}'
|
Block ← '{' Stmt* '}'
|
||||||
@@ -1153,6 +1166,7 @@ CONSTANT ← INTEGER | FLOAT | STRING | 'true' | 'false' | 'null' | 'undefine
|
|||||||
@control.br(bool, label, label) -> ! 条件分支:根据第一个参数跳转到第二或第三个(标签或者地址)。终止函数 (调用后控制流不返回)。
|
@control.br(bool, label, label) -> ! 条件分支:根据第一个参数跳转到第二或第三个(标签或者地址)。终止函数 (调用后控制流不返回)。
|
||||||
@control.jmp(label) -> ! 无条件跳转(跳转到标签或者地址)。终止函数。
|
@control.jmp(label) -> ! 无条件跳转(跳转到标签或者地址)。终止函数。
|
||||||
@control.call(FT)(%fn:FT, %args...) -> %ret 按目标平台调用约定调用函数指针 %fn,FT 为 fn<param_types...->ret_type>
|
@control.call(FT)(%fn:FT, %args...) -> %ret 按目标平台调用约定调用函数指针 %fn,FT 为 fn<param_types...->ret_type>
|
||||||
|
@control.param(T)(%idx: usize) -> T 返回idx的函数参数(编译期检查是否越界)
|
||||||
@control.ret(T)(%val?) 按目标平台调用约定从当前函数返回,T 为返回值类型,void 时不带参数
|
@control.ret(T)(%val?) 按目标平台调用约定从当前函数返回,T 为返回值类型,void 时不带参数
|
||||||
@control.unreachable() -> ! 标记不可达代码
|
@control.unreachable() -> ! 标记不可达代码
|
||||||
@control.trap() -> ! 触发运行时陷阱
|
@control.trap() -> ! 触发运行时陷阱
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
vm = [
|
vm = [
|
||||||
"stage0/spl_ir.c",
|
"stage0/spl_mcode.c",
|
||||||
"stage0/spl_syscall.c",
|
"stage0/spl_syscall.c",
|
||||||
"stage0/spl_vm.c",
|
"stage0/spl_vm.c",
|
||||||
]
|
]
|
||||||
|
|
||||||
splc0_part = [
|
splc0_part = [
|
||||||
"stage1/spl_comp.c",
|
"stage1/spl_ir.c",
|
||||||
|
"stage1/spl_ast.c",
|
||||||
"stage1/spl_lexer.c",
|
"stage1/spl_lexer.c",
|
||||||
|
"stage1/spl_dumptree.c",
|
||||||
"stage1/spl_type.c",
|
"stage1/spl_type.c",
|
||||||
"stage1/spl_parser.c",
|
"stage1/spl_sema.c",
|
||||||
"stage1/spl_lex_util.c",
|
"stage1/spl_ast2ir.c",
|
||||||
"stage1/spl_expr.c",
|
|
||||||
"stage1/spl_stmt.c",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
exe = {
|
exe = {
|
||||||
"spl_cli": ["stage0/spl_cli.c"] + vm,
|
"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,
|
"splc0": ["stage1/splc0.c"] + vm + splc0_part,
|
||||||
"test": ["stage0/test_spl_vm.c"] + vm,
|
"test": ["stage0/test_spl_vm.c"] + vm,
|
||||||
"spl_disasm": ["stage0/spl_disasm.c"] + vm,
|
"spl_disasm": ["stage0/spl_disasm.c"] + vm,
|
||||||
|
|||||||
@@ -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 : "<unknown>";
|
const char *fn = (t && t->fname) ? t->fname : "<unknown>";
|
||||||
usize line = t ? t->line : 0;
|
usize line = t ? t->line : 0;
|
||||||
usize col = t ? t->col : 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) {
|
static int expect(parser_t *p, spl_tok_type_t type, const char *what) {
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ typedef VEC(spl_ast_node_ref_t) spl_ast_node_ref_vec_t;
|
|||||||
struct spl_ast_node {
|
struct spl_ast_node {
|
||||||
spl_ast_node_kind_t kind;
|
spl_ast_node_kind_t kind;
|
||||||
spl_ast_loc_t loc;
|
spl_ast_loc_t loc;
|
||||||
|
|
||||||
|
usize resolved_def_id;
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
spl_ast_node_ref_vec_t attr_list; /* attr_item */
|
spl_ast_node_ref_vec_t attr_list; /* attr_item */
|
||||||
|
|||||||
2879
stage1/spl_ast2ir.c
2879
stage1/spl_ast2ir.c
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,19 @@
|
|||||||
#ifndef __SPL_AST2IR_H__
|
#ifndef __SPL_AST2IR_H__
|
||||||
#define __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__ */
|
#endif /* __SPL_AST2IR_H__ */
|
||||||
|
|||||||
483
stage1/spl_ir.c
483
stage1/spl_ir.c
@@ -1 +1,484 @@
|
|||||||
|
/* spl_ir.c — function-based SIR IR (arena 容器 + 文本 dump) */
|
||||||
|
|
||||||
#include "spl_ir.h"
|
#include "spl_ir.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* ---- 内置函数名字表(与 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]);
|
||||||
|
}
|
||||||
|
|||||||
140
stage1/spl_ir.h
140
stage1/spl_ir.h
@@ -2,6 +2,7 @@
|
|||||||
#define __SPL_IR_H__
|
#define __SPL_IR_H__
|
||||||
|
|
||||||
#include "../stage0/include/utils.h"
|
#include "../stage0/include/utils.h"
|
||||||
|
#include "spl_type.h"
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
#define SPL_IR_FN_TABLE \
|
#define SPL_IR_FN_TABLE \
|
||||||
@@ -64,6 +65,7 @@
|
|||||||
X(control.br, V0, SPL_IR_CONTROL_BR) \
|
X(control.br, V0, SPL_IR_CONTROL_BR) \
|
||||||
X(control.jmp, V0, SPL_IR_CONTROL_JMP) \
|
X(control.jmp, V0, SPL_IR_CONTROL_JMP) \
|
||||||
X(control.call, V0, SPL_IR_CONTROL_CALL) \
|
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.ret, V0, SPL_IR_CONTROL_RET) \
|
||||||
X(control.unreachable, V0, SPL_IR_CONTROL_UNREACHABLE) \
|
X(control.unreachable, V0, SPL_IR_CONTROL_UNREACHABLE) \
|
||||||
X(control.trap, V0, SPL_IR_CONTROL_TRAP) \
|
X(control.trap, V0, SPL_IR_CONTROL_TRAP) \
|
||||||
@@ -80,14 +82,136 @@ typedef enum {
|
|||||||
} spl_ir_kind_t;
|
} spl_ir_kind_t;
|
||||||
/* clang-format on */
|
/* 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 usize spl_ir_node_ref_t; /* 0 is error */
|
||||||
typedef VEC(spl_ir_node_ref_t) spl_ir_node_ref_vec_t;
|
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 {
|
typedef struct {
|
||||||
enum {
|
enum {
|
||||||
SPL_IR_ATTR_NONE,
|
SPL_IR_ATTR_NONE,
|
||||||
@@ -103,12 +227,12 @@ typedef VEC(spl_ir_attr_t) spl_ir_attr_vec_t;
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
spl_ir_attr_t attr;
|
spl_ir_attr_t attr;
|
||||||
|
spl_type_id_t fn_tid;
|
||||||
spl_ir_node_vec_t nodes;
|
spl_ir_node_vec_t nodes;
|
||||||
spl_ir_node_ref_vec_t labels;
|
spl_ir_node_ref_vec_t labels;
|
||||||
} spl_ir_func_t;
|
} 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 {
|
typedef struct {
|
||||||
spl_ir_func_vec_t funcs;
|
spl_ir_func_vec_t funcs;
|
||||||
} spl_ir_t;
|
} 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_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);
|
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__ */
|
#endif /* __SPL_IR_H__ */
|
||||||
|
|||||||
@@ -112,11 +112,11 @@ static spl_type_id_t find_type(spl_sema_t *sema, const char *name) {
|
|||||||
/* ---- 聚合成员登记(def 层 agg_def) ---- */
|
/* ---- 聚合成员登记(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,
|
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);
|
spl_def_node_t *d = def_at(sema, def);
|
||||||
if (!d || d->kind != SPL_DEF_AGG)
|
if (!d || d->kind != SPL_DEF_AGG)
|
||||||
return;
|
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);
|
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))
|
(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 `*_`");
|
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;
|
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);
|
spl_def_id_t def = def_alloc(sema, SPL_DEF_AGG);
|
||||||
def_at(sema, def)->type_id = tid;
|
def_at(sema, def)->type_id = tid;
|
||||||
vec_init(def_at(sema, def)->agg_def);
|
vec_init(def_at(sema, def)->agg_def);
|
||||||
|
te->resolved_def_id = def; /* 注解:该 type_expr 解析到的 def */
|
||||||
h.tid = tid;
|
h.tid = tid;
|
||||||
h.def = def;
|
h.def = def;
|
||||||
return h;
|
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;
|
m->member_decl.type_expr ? resolve_type_expr(sema, m->member_decl.type_expr) : 0;
|
||||||
/* resolve_type_expr 可能 alloc 新类型 → 两表 realloc,须重新取节点 */
|
/* resolve_type_expr 可能 alloc 新类型 → 两表 realloc,须重新取节点 */
|
||||||
spl_type_node_t *tn = spl_type_node(&sema->type, tid);
|
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) {
|
if (tn->kind == SPL_TYPE_ENUM) {
|
||||||
vec_push(tn->enum_type.variants, ft ? ft : tid);
|
mtype = ft ? ft : tid; /* 哨兵:无载荷变体 = 枚举自身 tid */
|
||||||
agg_add_member(sema, def, m->member_decl.name, ft ? ft : tid, agg_scope);
|
vec_push(tn->enum_type.variants, mtype);
|
||||||
} else {
|
} else {
|
||||||
|
mtype = ft;
|
||||||
vec_push(tn->agg_field_types, 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;
|
break;
|
||||||
}
|
}
|
||||||
case SPL_AST_FN_DECL:
|
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) */
|
/* 变量/常量/绑定节点:建 VAR def(不包 SPL_TYPE_ID) */
|
||||||
static void register_binding(spl_sema_t *sema, const char *name, spl_ast_node_ref_t type_expr,
|
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_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);
|
spl_def_id_t def = new_var_def(sema, name, t, scope);
|
||||||
if (!spl_sema_scope_insert(sema, scope, name, def))
|
if (!spl_sema_scope_insert(sema, scope, name, def))
|
||||||
sema_error(sema, 0, "duplicate symbol");
|
sema_error(sema, 0, "duplicate symbol");
|
||||||
if (agg_def)
|
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,
|
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);
|
spl_ast_node_t *n = node_at(sema->ast, ref);
|
||||||
if (!n)
|
if (!n)
|
||||||
return;
|
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,
|
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);
|
spl_ast_node_t *n = node_at(sema->ast, ref);
|
||||||
if (!n)
|
if (!n)
|
||||||
return;
|
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 新建)。
|
/* 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))
|
if (!spl_sema_scope_insert(sema, scope, n->fn_decl.name, fdef))
|
||||||
sema_error(sema, ref, "duplicate function name");
|
sema_error(sema, ref, "duplicate function name");
|
||||||
if (agg_def)
|
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,
|
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))
|
if (!spl_sema_scope_insert(sema, scope, n->type_decl.name, def))
|
||||||
sema_error(sema, ref, "duplicate type name");
|
sema_error(sema, ref, "duplicate type name");
|
||||||
if (agg_def)
|
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) */
|
/* 嵌套类型提升到文件作用域:兄弟聚合可裸名引用(如 Lexer 方法内 Tag.eof) */
|
||||||
if (agg_def)
|
if (agg_def)
|
||||||
spl_sema_scope_insert(sema, sema->root_scope, n->type_decl.name, 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 → 类型) */
|
/* 标识符:scope 查找(def → 类型) */
|
||||||
static spl_type_id_t infer_ident(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *n) {
|
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_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) {
|
if (!t) {
|
||||||
sema_error(sema, ref, "undefined identifier");
|
sema_error(sema, ref, "undefined identifier");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
/* 注解:IDENT 引用 → 其符号 def(var 用 VAR、fn 用 FN_PARAMS 等) */
|
||||||
|
pn->resolved_def_id = def;
|
||||||
return t;
|
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_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 spl_type_id_t infer_prefix(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *n);
|
||||||
static void check_stmt(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_sema_ctx_t ctx);
|
static 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)
|
if (t && t->kind == SPL_TYPE_PTR)
|
||||||
base = underlying(sema, t->ptr_pointee);
|
base = underlying(sema, t->ptr_pointee);
|
||||||
|
/* 注解:FIELD 节点 → 被访问聚合(自动解引用后)的 AGG def;非聚合为 0 */
|
||||||
|
pf->resolved_def_id = def_for_type(sema, base);
|
||||||
t = type_node(sema, base);
|
t = type_node(sema, base);
|
||||||
if (!t) {
|
if (!t) {
|
||||||
sema_error(sema, ref, "field access on non-aggregate");
|
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");
|
sema_error(sema, ref, "call requires function type");
|
||||||
return 0;
|
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;
|
spl_ast_node_ref_vec_t *args = &pf->postfix_expr.call_expr;
|
||||||
/* 变参 fn(如 vm_printf)最后一个形参 name=NULL 且类型可为 0 */
|
/* 变参 fn(如 vm_printf)最后一个形参 name=NULL 且类型可为 0 */
|
||||||
/* 注意:infer_expr 可能新分配类型使 type_table realloc,t 会失效,须每次刷新 */
|
/* 注意: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) {
|
if (b->block_item.kind == SPL_AST_VARDECL) {
|
||||||
spl_ast_node_t *vd = node_at(sema->ast, b->block_item.var_decl);
|
spl_ast_node_t *vd = node_at(sema->ast, b->block_item.var_decl);
|
||||||
if (vd)
|
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) {
|
} else if (b->block_item.kind == SPL_AST_CONSTDECL) {
|
||||||
spl_ast_node_t *cd = node_at(sema->ast, b->block_item.const_decl);
|
spl_ast_node_t *cd = node_at(sema->ast, b->block_item.const_decl);
|
||||||
if (cd)
|
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) {
|
} else if (b->block_item.kind == SPL_AST_TYPEDECL) {
|
||||||
spl_ast_node_t *td = node_at(sema->ast, b->block_item.type_decl);
|
spl_ast_node_t *td = node_at(sema->ast, b->block_item.type_decl);
|
||||||
if (td)
|
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) {
|
if (pv->name) {
|
||||||
spl_def_id_t pdef = new_var_def(sema, pv->name, pv->type_id, fn_scope);
|
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);
|
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);
|
check_block(sema, &n->fn_decl.block, fn_scope, ctx);
|
||||||
@@ -1745,7 +1792,7 @@ void spl_sema_run(spl_sema_t *sema) {
|
|||||||
continue;
|
continue;
|
||||||
if (!spl_sema_scope_insert(sema, sema->root_scope, m->type_decl.name, h.def))
|
if (!spl_sema_scope_insert(sema, sema->root_scope, m->type_decl.name, h.def))
|
||||||
sema_error(sema, mref, "duplicate type name");
|
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) {
|
} else if (te) {
|
||||||
spl_type_id_t tid = resolve_type_expr(sema, m->type_decl.type_expr);
|
spl_type_id_t tid = resolve_type_expr(sema, m->type_decl.type_expr);
|
||||||
spl_def_id_t def = def_alloc(sema, SPL_DEF_ALIAS);
|
spl_def_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;
|
d->type_def.scope_id = sema->root_scope;
|
||||||
if (!spl_sema_scope_insert(sema, sema->root_scope, m->type_decl.name, def))
|
if (!spl_sema_scope_insert(sema, sema->root_scope, m->type_decl.name, def))
|
||||||
sema_error(sema, mref, "duplicate type name");
|
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) */
|
/* 1b. fn 名(建 fn type + def) */
|
||||||
|
|||||||
@@ -211,6 +211,8 @@ static const char *def_kind_name(spl_def_node_t *d) {
|
|||||||
return "builtin";
|
return "builtin";
|
||||||
case SPL_DEF_VAR:
|
case SPL_DEF_VAR:
|
||||||
return "var";
|
return "var";
|
||||||
|
case SPL_DEF_MEMBER:
|
||||||
|
return "member";
|
||||||
case SPL_DEF_FN_PARAMS:
|
case SPL_DEF_FN_PARAMS:
|
||||||
return "fn_params";
|
return "fn_params";
|
||||||
case SPL_DEF_AGG:
|
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:
|
case SPL_DEF_VAR:
|
||||||
printf(" var=%s", d->var_def.name ? d->var_def.name : "?");
|
printf(" var=%s", d->var_def.name ? d->var_def.name : "?");
|
||||||
break;
|
break;
|
||||||
|
case SPL_DEF_MEMBER:
|
||||||
|
printf(" member=%s", d->var_def.name ? d->var_def.name : "?");
|
||||||
|
break;
|
||||||
case SPL_DEF_ALIAS:
|
case SPL_DEF_ALIAS:
|
||||||
case SPL_DEF_DISTINCT:
|
case SPL_DEF_DISTINCT:
|
||||||
printf(" type=%s", d->type_def.name ? d->type_def.name : "?");
|
printf(" type=%s", d->type_def.name ? d->type_def.name : "?");
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ typedef struct {
|
|||||||
enum {
|
enum {
|
||||||
SPL_DEF_NONE,
|
SPL_DEF_NONE,
|
||||||
SPL_DEF_BUILTIN,
|
SPL_DEF_BUILTIN,
|
||||||
|
SPL_DEF_MEMBER,
|
||||||
SPL_DEF_VAR,
|
SPL_DEF_VAR,
|
||||||
SPL_DEF_FN_PARAMS,
|
SPL_DEF_FN_PARAMS,
|
||||||
SPL_DEF_AGG, // include enum variants
|
SPL_DEF_AGG, // include enum variants
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "spl_ast.h"
|
#include "spl_ast.h"
|
||||||
|
#include "spl_ast2ir.h"
|
||||||
#include "spl_lexer.h"
|
#include "spl_lexer.h"
|
||||||
#include "spl_sema.h"
|
#include "spl_sema.h"
|
||||||
#include "spl_tok.h"
|
#include "spl_tok.h"
|
||||||
@@ -102,6 +103,34 @@ static void dump_sema(const char *src, const char *fname) {
|
|||||||
spl_ast_drop(&ast);
|
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) {
|
static int cmd_dump(const char *flags, const char *path) {
|
||||||
long len;
|
long len;
|
||||||
char *src = read_file(path, &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_tokens = strstr(flags, "tokens") != NULL || strcmp(flags, "all") == 0;
|
||||||
int do_ast = strstr(flags, "ast") != 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_sema = strstr(flags, "sema") != NULL || strcmp(flags, "all") == 0;
|
||||||
|
int do_ir = strstr(flags, "ir") != NULL || strcmp(flags, "all") == 0;
|
||||||
if (do_tokens)
|
if (do_tokens)
|
||||||
dump_tokens(src, path);
|
dump_tokens(src, path);
|
||||||
if (do_ast)
|
if (do_ast)
|
||||||
dump_ast(src, path);
|
dump_ast(src, path);
|
||||||
if (do_sema)
|
if (do_sema)
|
||||||
dump_sema(src, path);
|
dump_sema(src, path);
|
||||||
|
if (do_ir)
|
||||||
|
dump_ir(src, path);
|
||||||
free(src);
|
free(src);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -127,7 +159,7 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) {
|
if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) {
|
||||||
LOG_INFO("splc0 <in> <out> compile (.spl -> .sir, 阶段 B)\n");
|
LOG_INFO("splc0 <in> <out> compile (.spl -> .sir, 阶段 B)\n");
|
||||||
LOG_INFO("splc0 --dump <flags> <file> dump: tokens,ast,sema,all\n");
|
LOG_INFO("splc0 --dump <flags> <file> dump: tokens,ast,sema,ir,all\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int argi = 1;
|
int argi = 1;
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ type Optional = enum {
|
|||||||
|
|
||||||
/* ---- 带结构体数据的枚举 ---- */
|
/* ---- 带结构体数据的枚举 ---- */
|
||||||
type Point = struct {
|
type Point = struct {
|
||||||
var x: i32;
|
x: i32;
|
||||||
var y: i32;
|
y: i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Shape = enum {
|
type Shape = enum {
|
||||||
|
|||||||
@@ -1,54 +1,54 @@
|
|||||||
/* ===== å¤<C3A5>æ<EFBFBD>‚类型嵌套综å<C2BC>ˆæµ‹è¯• =====
|
/* ===== å¤<C3A5>æ<EFBFBD>‚类型嵌套综å<C2BC>ˆæµ‹è¯• =====
|
||||||
* test20_complex — 结构体嵌套、切片、数组、方法、类型别名、枚举等
|
* test20_complex â€?结构体嵌套ã€<C3A3>切片ã€<C3A3>数组ã€<C3A3>方法ã€<C3A3>类型别å<C2AB><C3A5>ã€<C3A3>枚举ç‰
|
||||||
* 难度:5/5
|
* 难度�/5
|
||||||
*/
|
*/
|
||||||
/* ---- 基础结构体 ---- */
|
/* ---- 基础结构�---- */
|
||||||
type Point = struct {
|
type Point = struct {
|
||||||
var x: i32;
|
x: i32,
|
||||||
var y: i32;
|
y: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- 嵌套结构体 ---- */
|
/* ---- 嵌套结构�---- */
|
||||||
type Rect = struct {
|
type Rect = struct {
|
||||||
var min: Point;
|
min: Point,
|
||||||
var max: Point;
|
max: Point,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- 含切片字段的结构体 (核心 bug 测试) ---- */
|
/* ---- å<EFBFBD>«åˆ‡ç‰‡å—段的结构ä½?(æ ¸å¿ƒ bug 测试) ---- */
|
||||||
type Buffer = struct {
|
type Buffer = struct {
|
||||||
var data: []u8;
|
data: []u8,
|
||||||
var len: usize;
|
len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- 含数组字段的结构体 ---- */
|
/* ---- å<EFBFBD>«æ•°ç»„å—æ®µçš„结构ä½?---- */
|
||||||
type MatrixRow = struct {
|
type MatrixRow = struct {
|
||||||
var items: [4]i32;
|
items: [4]i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- 含指针字段的结构体 ---- */
|
/* ---- å<EFBFBD>«æŒ‡é’ˆå—段的结构ä½?---- */
|
||||||
type Node = struct {
|
type Node = struct {
|
||||||
var ptr: *i32;
|
ptr: *i32,
|
||||||
var val: i32;
|
val: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- 多层级嵌套:结构体里的结构体里的切片 ---- */
|
/* ---- 多层级嵌套:结构体里的结构体里的切片 ---- */
|
||||||
type Bundle = struct {
|
type Bundle = struct {
|
||||||
var name: *u8;
|
name: *u8,
|
||||||
var buf: Buffer;
|
buf: Buffer,
|
||||||
var row: MatrixRow;
|
row: MatrixRow,
|
||||||
var pt: Point;
|
pt: Point,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- 枚举含数据 ---- */
|
/* ---- 枚举å<EFBFBD>«æ•°æ<EFBFBD>?---- */
|
||||||
type Status = enum {
|
type Status = enum {
|
||||||
Active: i32;
|
Active: i32;
|
||||||
Inactive;
|
Inactive;
|
||||||
Pending: Point;
|
Pending: Point;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- 含方法的结构体 (方法定义在结构体内部) ---- */
|
/* ---- å<EFBFBD>«æ–¹æ³•的结构ä½?(方法定义在结构体内部) ---- */
|
||||||
type Counter = struct {
|
type Counter = struct {
|
||||||
var val: i32;
|
val: i32,
|
||||||
|
|
||||||
fn inc(self: *Counter) i32 {
|
fn inc(self: *Counter) i32 {
|
||||||
self.val = self.val + 1;
|
self.val = self.val + 1;
|
||||||
@@ -70,7 +70,7 @@ type Counter = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* 测试 1: 切片在结构体内部初始化 (修复的核心 bug)
|
* 测试 1: 切片在结构体内部åˆ<C3A5>å§‹åŒ?(ä¿®å¤<C3A5>çš„æ ¸å¿?bug)
|
||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
|
|
||||||
fn test_slice_in_struct() i32 {
|
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[1] != 66 { ret 3; }
|
||||||
if b.data[3] != 68 { ret 4; }
|
if b.data[3] != 68 { ret 4; }
|
||||||
|
|
||||||
/* Modify through slice — verify reflection */
|
/* Modify through slice �verify reflection */
|
||||||
b.data[0] = 90;
|
b.data[0] = 90;
|
||||||
if raw[0] != 90 { ret 5; }
|
if raw[0] != 90 { ret 5; }
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ fn test_nested_struct() i32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* 测试 4: 结构体成员方法 (实例方法调用)
|
* 测试 4: 结构体æˆ<C3A6>员方æ³?(实例方法调用)
|
||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
|
|
||||||
fn test_struct_method() i32 {
|
fn test_struct_method() i32 {
|
||||||
@@ -161,7 +161,7 @@ fn test_struct_method() i32 {
|
|||||||
if r1 != 1 { ret 1; }
|
if r1 != 1 { ret 1; }
|
||||||
if c.val != 1 { ret 2; }
|
if c.val != 1 { ret 2; }
|
||||||
|
|
||||||
/* 带参数方法调用 c.add(&c, n) */
|
/* 带å<EFBFBD>‚数方法调ç”?c.add(&c, n) */
|
||||||
var r2: i32 = c.add(&c, 5);
|
var r2: i32 = c.add(&c, 5);
|
||||||
if r2 != 6 { ret 3; }
|
if r2 != 6 { ret 3; }
|
||||||
if c.val != 6 { ret 4; }
|
if c.val != 6 { ret 4; }
|
||||||
@@ -193,7 +193,7 @@ fn test_ptr_in_struct() i32 {
|
|||||||
v = 100;
|
v = 100;
|
||||||
if n.ptr[0] != 100 { ret 3; }
|
if n.ptr[0] != 100 { ret 3; }
|
||||||
|
|
||||||
/* 通过指针在结构体内修改 */
|
/* 通过指针在结构体内修�*/
|
||||||
n.ptr[0] = 200;
|
n.ptr[0] = 200;
|
||||||
if v != 200 { ret 4; }
|
if v != 200 { ret 4; }
|
||||||
|
|
||||||
@@ -201,7 +201,7 @@ fn test_ptr_in_struct() i32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* 测试 6: 多层级复杂嵌套
|
* 测试 6: 多层级å¤<C3A5>æ<EFBFBD>‚嵌å¥?
|
||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
|
|
||||||
fn test_complex_nesting() i32 {
|
fn test_complex_nesting() i32 {
|
||||||
@@ -289,7 +289,7 @@ fn test_enum_complex() i32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* 主函数
|
* 主函�
|
||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
|
|
||||||
fn main() i32 {
|
fn main() i32 {
|
||||||
|
|||||||
Reference in New Issue
Block a user