Compare commits

...

4 Commits

Author SHA1 Message Date
zzy
314100afbc stage1 初步实现 2026-08-06 19:26:30 +08:00
zzy
a56b4cbb70 stage0 支持类gdb的调试vm手段 2026-08-06 09:11:15 +08:00
zzy
ca7cf221c8 stage1 修复设计问题 实现ir2vm 2026-08-05 19:13:48 +08:00
zzy
2ccee5f1cf stage1 修复设计问题 实现ast2ir 2026-08-05 08:14:23 +08:00
45 changed files with 6771 additions and 2280 deletions

66
SPL.md
View File

@@ -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空指针字面量。当前语言无 ?Tnull 仅用于指针或切片的比较、赋值、初始化及聚合字段;其他用法为错误。
### 运算符 ### 运算符
算术/位运算: 操作数类型必须完全一致或由字面量推导,无隐式提升。 算术/位运算: 操作数类型必须完全一致或由字面量推导,无隐式提升。
@@ -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 的上下文中 当前阶段未实现 ?Tnull 以"指针/切片的空值"语义生效 (见"特殊类型"与"类型兼容性")
### 聚合类型 ### 聚合类型
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, idx0.. 的长度由 slice.len 决定。 若存在无界 Range (如 0..),则要求循环中至少有一个有界序列,且该有界序列的长度将作为无界序列的上限。例如 for slice, 0.. as elem, idx0.. 的长度由 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 按目标平台调用约定调用函数指针 %fnFT 为 fn<param_types...->ret_type> @control.call(FT)(%fn:FT, %args...) -> %ret 按目标平台调用约定调用函数指针 %fnFT 为 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() -> ! 触发运行时陷阱

View File

@@ -1,22 +1,23 @@
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_ir2vm.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,

View File

@@ -1,65 +1,686 @@
/* spl_cli.c — SIR VM launcher /* spl_cli.c — SIR VM launcher + gdb-style interactive debugger
* *
* Loads a compiled .sir binary and runs it via the SIR VM. * Usage: spl_cli [options] <file.sir> [args...]
* Built-in syscalls are auto-registered via spl_syscall_register(). * -d, --debug stack-canary checks
* -g, --debug-cli interactive debugger (REPL)
* --entry <name> entry function (default: main)
* --trace print every instruction
* -h, --help show help
* *
* Usage: * spl 程序 argvargv[0]=file.sirargv[1..]=args。
* spl_cli [-d] <file.sir> [entry_point] * REPL 配合 splc0 -g.sir 尾部内嵌 debug 段IR 行 + VAR 行)可显示
* 当前 IR 节点/源行/局部变量。
*/ */
#include "spl_mcode.h" #include "spl_mcode.h"
#include "spl_syscall.h" #include "spl_syscall.h"
#include "spl_vm.h" #include "spl_vm.h"
#include <ctype.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
int main(int argc, const char **argv) { /* ================================================================
int debug_mode = 0; * 命令行解析
int arg_idx = 1; * ================================================================ */
if (argc >= 2 && strcmp(argv[1], "-d") == 0) { typedef struct {
debug_mode = 1; int debug;
arg_idx = 2; int debug_cli;
int trace;
const char *entry;
const char *path; /* file.sir */
const char **args; /* spl 程序参数file.sir 之后) */
int nargs;
} cli_opts_t;
static void usage(void) {
fprintf(stderr, "Usage: spl_cli [options] <file.sir> [args...]\n"
" -d, --debug stack-canary checks\n"
" -g, --debug-cli interactive debugger (REPL)\n"
" --entry <name> entry function (default: main)\n"
" --trace print every instruction\n"
" -h, --help show help\n");
}
/* options 可穿插;`--` 终止 option 解析(本身不作为 file/args
* 第一个非 option 为 file.sir其后为 spl args。 */
static int parse_args(int argc, const char **argv, cli_opts_t *o) {
memset(o, 0, sizeof *o);
o->entry = "main";
int i = 1;
for (; i < argc; i++) {
const char *a = argv[i];
if (a[0] == '-' && a[1]) {
if (strcmp(a, "--") == 0) {
i++;
break;
} }
if (strcmp(a, "-d") == 0 || strcmp(a, "--debug") == 0) {
o->debug = 1;
} else if (strcmp(a, "-g") == 0 || strcmp(a, "--debug-cli") == 0) {
o->debug_cli = 1;
} else if (strcmp(a, "--trace") == 0) {
o->trace = 1;
} else if (strcmp(a, "--entry") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "spl_cli: --entry needs a name\n");
return -1;
}
o->entry = argv[++i];
} else if (strcmp(a, "-h") == 0 || strcmp(a, "--help") == 0) {
usage();
return -1;
} else {
fprintf(stderr, "spl_cli: unknown option '%s'\n", a);
usage();
return -1;
}
} else {
break;
}
}
/* 跳过前导 `--`pipeline 调用会带 `--` 分隔 file 与 args */
while (i < argc && strcmp(argv[i], "--") == 0)
i++;
if (i >= argc) {
fprintf(stderr, "spl_cli: missing <file.sir>\n");
usage();
return -1;
}
o->path = argv[i++];
while (i < argc && strcmp(argv[i], "--") == 0)
i++;
o->args = argv + i;
o->nargs = argc - i;
return 0;
}
if (arg_idx >= argc) { /* ================================================================
fprintf(stderr, "Usage: spl_cli [-d] <file.sir> [entry_point]\n"); * Debug mapsplc0 -g 追加在 .sir 尾部的文本段)
* IR <ip> <node_ref> <line> <kind>
* VAR <func> <name> <fp_offset> <tid> <is_param>
* ================================================================ */
typedef struct {
usize ip;
usize ref;
int line;
char kind[64];
} dbg_irline_t;
typedef VEC(dbg_irline_t) dbg_irline_vec_t;
typedef struct {
char func[128];
char name[128];
usize offset;
usize tid;
int is_param;
} dbg_var_t;
typedef VEC(dbg_var_t) dbg_var_vec_t;
typedef struct {
dbg_irline_vec_t irlines;
dbg_var_vec_t vars;
int loaded;
} dbg_map_t;
static void dbg_map_load(dbg_map_t *m, const char *text) {
memset(m, 0, sizeof *m);
vec_init(m->irlines);
vec_init(m->vars);
m->loaded = 0;
if (!text)
return;
const char *p = strstr(text, "SPLDBG");
if (!p)
return;
p += 6;
while (p && *p) {
const char *nl = strchr(p, '\n');
size_t len = nl ? (size_t)(nl - p) : strlen(p);
char line[512];
if (len >= sizeof line)
len = sizeof line - 1;
memcpy(line, p, len);
line[len] = 0;
if (strncmp(line, "IR ", 3) == 0) {
dbg_irline_t ir;
memset(&ir, 0, sizeof ir);
sscanf(line + 3, "%zu %zu %d %63s", &ir.ip, &ir.ref, &ir.line, ir.kind);
vec_push(m->irlines, ir);
} else if (strncmp(line, "VAR ", 4) == 0) {
dbg_var_t v;
memset(&v, 0, sizeof v);
sscanf(line + 4, "%127s %127s %zu %zu %d", v.func, v.name, &v.offset, &v.tid,
&v.is_param);
vec_push(m->vars, v);
}
if (!nl)
break;
p = nl + 1;
}
m->loaded = 1;
}
/* 当前 ip 所属 IR 节点行ip 恰好是某节点首指令) */
static const dbg_irline_t *irline_at_exact(dbg_map_t *m, usize ip) {
for (usize i = 0; i < m->irlines.size; i++)
if (m->irlines.data[i].ip == ip)
return &m->irlines.data[i];
return NULL;
}
/* ================================================================
* 调试器核心
* ================================================================ */
typedef struct {
spl_vm_t *vm;
spl_prog_t *prog;
const char *entry;
dbg_map_t map;
usize last_ptr; /* p 最近读到的值x 无参重读) */
int quit;
} dbg_t;
/* ---- 位置/指令显示辅助 ---- */
static const char *fn_name_at(spl_prog_t *prog, usize ip) {
for (usize i = 0; i < vec_size(prog->funcs); i++) {
spl_func_t *f = &vec_at(prog->funcs, i);
if (ip >= f->address && ip < f->address + f->ninsns)
return f->name ? f->name : "?";
}
return "?";
}
/* ip 所在函数的指令范围 [*start, *end) */
static void cur_func_bounds(spl_prog_t *prog, usize ip, usize *start, usize *end) {
*start = 0;
*end = vec_size(prog->insns);
for (usize i = 0; i < vec_size(prog->funcs); i++) {
spl_func_t *f = &vec_at(prog->funcs, i);
if (ip >= f->address && ip < f->address + f->ninsns) {
*start = f->address;
*end = f->address + f->ninsns;
return;
}
}
}
/* 格式化一条指令(不含行号前缀) */
static void fmt_insn(const spl_ins_t *ins, char *buf, size_t n) {
snprintf(buf, n, "%-11s %-5s %zu", spl_opcode_name(ins->opcode), spl_type_tag_name(ins->type),
ins->imm);
}
static void dbg_show_location(dbg_t *d) {
spl_vm_t *vm = d->vm;
if (vm->ip >= vec_size(vm->prog->insns)) {
printf(" (end of program)\n");
return;
}
char ib[80];
fmt_insn(&vec_at(vm->prog->insns, vm->ip), ib, sizeof ib);
printf(" %s @ ip=%zu %s [sp=%zu fp=%zu cp=%zu]\n", fn_name_at(vm->prog, vm->ip), vm->ip,
ib, vm->sp, vm->fp, vm->cp);
const dbg_irline_t *ir = irline_at_exact(&d->map, vm->ip);
if (ir)
printf(" -> ir node#%zu line %d %s\n", ir->ref, ir->line, ir->kind);
}
static void dbg_handle_status(dbg_t *d, int r) {
if (r == 1) {
printf(" program halted, exit_code=%d\n", d->vm->exit_code);
d->quit = 1;
} else if (r == 2) {
printf(" breakpoint hit\n");
} else if (r == -1) {
printf(" VM error: %s\n", d->vm->error_msg[0] ? d->vm->error_msg : "(no detail)");
d->quit = 1;
}
}
/* ---- 变量查找p / x 复用) ---- */
static dbg_var_t *dbg_find_var(dbg_t *d, const char *fn, const char *name) {
for (usize i = 0; i < d->map.vars.size; i++) {
dbg_var_t *v = &d->map.vars.data[i];
if (strcmp(v->func, fn) == 0 && strcmp(v->name, name) == 0)
return v;
}
return NULL;
}
/* ================================================================
* 命令
* ================================================================ */
static int cmd_help(dbg_t *d, const char *args);
static int cmd_run(dbg_t *d, const char *args);
static int cmd_step(dbg_t *d, const char *args);
static int cmd_next(dbg_t *d, const char *args);
static int cmd_finish(dbg_t *d, const char *args);
static int cmd_break(dbg_t *d, const char *args);
static int cmd_delete(dbg_t *d, const char *args);
static int cmd_info(dbg_t *d, const char *args);
static int cmd_list(dbg_t *d, const char *args);
static int cmd_backtrace(dbg_t *d, const char *args);
static int cmd_stack(dbg_t *d, const char *args);
static int cmd_x(dbg_t *d, const char *args);
static int cmd_p(dbg_t *d, const char *args);
static int cmd_quit(dbg_t *d, const char *args);
typedef struct {
const char *name;
const char *alias;
const char *usage;
const char *help;
int (*fn)(dbg_t *, const char *);
} dbg_cmd_t;
static const dbg_cmd_t cmds[] = {
/* 会话 */
{"help", "h", "[cmd]", "list commands / help", cmd_help},
{"quit", "q", "", "quit debugger", cmd_quit},
/* 执行 */
{"run", "r", "", "run to next breakpoint or exit", cmd_run},
{"continue", "c", "", "alias of run", cmd_run},
{"step", "s", "", "step one instruction (into calls)", cmd_step},
{"next", "n", "", "step over a call", cmd_next},
{"finish", "f", "", "run until current function returns", cmd_finish},
/* 断点 */
{"break", "b", "<fn|ip>", "set breakpoint (no arg: list)", cmd_break},
{"delete", "d", "", "clear all breakpoints", cmd_delete},
/* 信息 */
{"info", "i", "b|stack|locals|args|var", "breakpoints/stack/locals", cmd_info},
{"list", "l", "[N]", "disassemble ip±N of current function", cmd_list},
{"backtrace", "bt", "", "print call stack backtrace", cmd_backtrace},
{"stack", "st", "", "dump stack words", cmd_stack},
/* 内存/变量 */
{"x", "x", "<var|addr|fp+N>", "read memory (no arg: last pointer)", cmd_x},
{"print", "p", "<var>", "print local variable (needs splc0 -g)", cmd_p},
{NULL, NULL, NULL, NULL, NULL},
};
static const dbg_cmd_t *find_cmd(const char *name) {
for (const dbg_cmd_t *c = cmds; c->name; c++)
if (!strcmp(c->name, name) || (c->alias && !strcmp(c->alias, name)))
return c;
return NULL;
}
static int cmd_help(dbg_t *d, const char *args) {
(void)d;
if (*args) {
const dbg_cmd_t *c = find_cmd(args);
if (c) {
printf(" %-10s %-22s %s", c->name, c->usage, c->help);
if (c->alias)
printf(" (alias: %s)", c->alias);
printf("\n");
} else {
printf(" unknown command '%s'\n", args);
}
return 0;
}
printf("commands:\n");
for (const dbg_cmd_t *c = cmds; c->name; c++) {
printf(" %-10s %-22s %s", c->name, c->usage, c->help);
if (c->alias)
printf(" (alias: %s)", c->alias);
printf("\n");
}
return 0;
}
/* ---- 执行 ---- */
static int ip_is_breakpoint(dbg_t *d) {
for (usize i = 0; i < vec_size(d->vm->breakpoints); i++)
if (d->vm->breakpoints.data[i] == (usize)d->vm->ip)
return 1; return 1;
} return 0;
}
const char *path = argv[arg_idx]; static int cmd_run(dbg_t *d, const char *args) {
const char *entry = argc >= arg_idx + 2 ? argv[arg_idx + 1] : "main"; (void)args;
if (ip_is_breakpoint(d)) /* 越过当前断点指令,避免原地重停 */
spl_vm_skip_breakpoint(d->vm);
dbg_handle_status(d, spl_vm_run_until(d->vm, 0));
return 0;
}
static int cmd_step(dbg_t *d, const char *args) {
(void)args;
dbg_handle_status(d, spl_vm_run_once(d->vm));
return 0;
}
static int cmd_next(dbg_t *d, const char *args) {
(void)args;
/* 执行 1 条若进入被调cp 增),继续执行到返回原深度 */
usize base_cp = d->vm->cp;
int r = spl_vm_run_once(d->vm);
if (r)
return dbg_handle_status(d, r), 0;
while (d->vm->cp > base_cp) {
r = spl_vm_run_once(d->vm);
if (r)
return dbg_handle_status(d, r), 0;
}
return 0;
}
static int cmd_finish(dbg_t *d, const char *args) {
(void)args;
usize base_cp = d->vm->cp;
while (d->vm->cp >= base_cp) {
int r = spl_vm_run_once(d->vm);
if (r)
return dbg_handle_status(d, r), 0;
}
return 0;
}
/* ---- 断点 ---- */
static int is_all_digits(const char *s) {
if (!*s)
return 0;
for (; *s; s++)
if (!isdigit((unsigned char)*s))
return 0;
return 1;
}
static int cmd_break(dbg_t *d, const char *args) {
if (!*args) {
printf(" ip breakpoints:\n");
for (usize i = 0; i < vec_size(d->vm->breakpoints); i++)
printf(" %zu\n", d->vm->breakpoints.data[i]);
printf(" fn breakpoints:\n");
for (usize i = 0; i < vec_size(d->vm->fn_breakpoints); i++)
printf(" %s\n", d->vm->fn_breakpoints.data[i]);
return 0;
}
while (*args && isspace((unsigned char)*args))
args++;
if (is_all_digits(args)) {
usize ip = (usize)strtoul(args, NULL, 10);
spl_vm_add_breakpoint(d->vm, ip);
printf(" breakpoint at ip=%zu\n", ip);
} else {
spl_vm_add_breakpoint_fn(d->vm, args);
printf(" breakpoint at function '%s'\n", args);
}
return 0;
}
static int cmd_delete(dbg_t *d, const char *args) {
(void)args;
spl_vm_clear_breakpoints(d->vm);
printf(" breakpoints cleared\n");
return 0;
}
/* ---- 信息 ---- */
/* 列出当前函数变量args_flag=1 列参数local_flag=1 列局部 */
static void list_vars(dbg_t *d, int args_flag, int local_flag) {
if (!d->map.loaded) {
printf(" no debug info (compile with splc0 -g)\n");
return;
}
const char *fn = fn_name_at(d->prog, d->vm->ip);
int any = 0;
for (usize i = 0; i < d->map.vars.size; i++) {
dbg_var_t *v = &d->map.vars.data[i];
if (strcmp(v->func, fn) != 0)
continue;
if ((v->is_param && !args_flag) || (!v->is_param && !local_flag))
continue;
printf(" %-20s @ fp+%-5zu %s\n", v->name, v->offset, v->is_param ? "[param]" : "[local]");
any = 1;
}
if (!any)
printf(" (no matching variables in %s)\n", fn);
}
static int cmd_info(dbg_t *d, const char *args) {
while (*args && isspace((unsigned char)*args))
args++;
if (!strncmp(args, "b", 1) || !strncmp(args, "break", 5))
return cmd_break(d, "");
if (!strncmp(args, "st", 2) || !strncmp(args, "stack", 5))
spl_vm_stackdump(d->vm, d->vm->sp);
else if (!strncmp(args, "l", 1) || !strncmp(args, "local", 5))
list_vars(d, 0, 1);
else if (!strncmp(args, "a", 1) || !strncmp(args, "arg", 3))
list_vars(d, 1, 0);
else if (!strncmp(args, "v", 1) || !strncmp(args, "var", 3))
list_vars(d, 1, 1);
else
printf(" usage: info b|stack|locals|args|var\n");
return 0;
}
/* l [N]:当前函数内 ip±N 反汇编 */
static int cmd_list(dbg_t *d, const char *args) {
usize ip = d->vm->ip;
long half = 5;
if (*args)
half = strtol(args, NULL, 10);
if (half < 0)
half = 0;
usize fstart, fend;
cur_func_bounds(d->prog, ip, &fstart, &fend);
usize lo = (ip > (usize)half) ? ip - (usize)half : fstart;
usize hi = ip + (usize)half;
if (hi >= fend)
hi = fend - 1;
if (lo < fstart)
lo = fstart;
for (usize i = lo; i <= hi; i++) {
char ib[80];
fmt_insn(&vec_at(d->prog->insns, i), ib, sizeof ib);
printf("%s%6zu: %s", i == ip ? "=>" : " ", i, ib);
const dbg_irline_t *ir = irline_at_exact(&d->map, i);
if (ir)
printf(" || node#%zu line %d %s", ir->ref, ir->line, ir->kind);
printf("\n");
}
return 0;
}
static int cmd_backtrace(dbg_t *d, const char *args) {
(void)args;
spl_vm_backtrace(d->vm, d->vm->fp);
return 0;
}
static int cmd_stack(dbg_t *d, const char *args) {
(void)args;
spl_vm_stackdump(d->vm, d->vm->sp);
return 0;
}
/* ---- 内存 / 变量 ---- */
static int cmd_x(dbg_t *d, const char *args) {
while (*args && isspace((unsigned char)*args))
args++;
unsigned long long addr = 0;
if (*args) {
if (strncmp(args, "fp+", 3) == 0 || strncmp(args, "sp+", 3) == 0) {
int is_fp = args[0] == 'f';
unsigned long long off = strtoull(args + 3, NULL, 0);
addr = (uintptr_t)((char *)&d->vm->stacks.data[is_fp ? d->vm->fp : d->vm->sp] + off);
printf(" (%s+%llu)\n", is_fp ? "fp" : "sp", off);
} else if (d->map.loaded && !isdigit((unsigned char)*args)) {
const char *fn = fn_name_at(d->prog, d->vm->ip);
dbg_var_t *v = dbg_find_var(d, fn, args);
if (v) {
addr = (uintptr_t)((char *)&d->vm->stacks.data[d->vm->fp] + v->offset);
printf(" (%s @ fp+%zu)\n", v->name, v->offset);
} else {
printf(" no variable '%s' in %s\n", args, fn);
}
} else {
addr = strtoull(args, NULL, 0);
}
} else {
addr = (unsigned long long)d->last_ptr;
}
if (!addr) {
printf(" usage: x <var|addr|fp+N> (no arg: re-read last printed pointer)\n");
return 0;
}
unsigned char *sbase = (unsigned char *)d->vm->stacks.data;
usize slen = d->vm->config.max_stack_depth * sizeof(spl_val_t);
printf(" addr=%#llx stack=[%p,+%zu) in=%d\n", addr, sbase, slen,
addr >= (uintptr_t)sbase && addr < (uintptr_t)(sbase + slen));
unsigned char *p = (unsigned char *)(uintptr_t)addr;
printf(" ");
for (int i = 0; i < 32; i++)
printf("%02x ", p[i]);
printf("\n");
return 0;
}
static int cmd_p(dbg_t *d, const char *args) {
while (*args && isspace((unsigned char)*args))
args++;
if (!*args) {
printf(" usage: p <varname>\n");
return 0;
}
if (!d->map.loaded) {
printf(" no debug info (compile with splc0 -g)\n");
return 0;
}
const char *fn = fn_name_at(d->prog, d->vm->ip);
dbg_var_t *v = dbg_find_var(d, fn, args);
if (!v) {
printf(" no variable '%s' in %s\n", args, fn);
return 0;
}
spl_val_t *addr = (spl_val_t *)((char *)&d->vm->stacks.data[d->vm->fp] + v->offset);
printf(" %s = %zu (0x%zx) @ fp+%zu\n", v->name, *addr, *addr, v->offset);
d->last_ptr = (usize)*addr; /* 供 x 无参重读 */
return 0;
}
static int cmd_quit(dbg_t *d, const char *args) {
(void)args;
d->quit = 1;
return 0;
}
static void repl_loop(dbg_t *d) {
char line[1024];
while (!d->quit) {
dbg_show_location(d);
printf("spl-dbg> ");
fflush(stdout);
if (!fgets(line, sizeof line, stdin))
break;
char *nl = strchr(line, '\n');
if (nl)
*nl = 0;
char *p = line;
while (*p && isspace((unsigned char)*p))
p++;
if (!*p)
continue;
/* 拆命令名 + 参数 */
char *sp = p;
while (*sp && !isspace((unsigned char)*sp))
sp++;
char saved = *sp;
*sp = 0;
const dbg_cmd_t *c = find_cmd(p);
*sp = saved;
char *args = sp;
while (*args && isspace((unsigned char)*args))
args++;
if (c) {
c->fn(d, args);
} else {
printf(" unknown command '%s' (h for help)\n", p);
}
}
}
int main(int argc, const char **argv) {
cli_opts_t o;
if (parse_args(argc, argv, &o) != 0)
return 1;
spl_prog_t prog; spl_prog_t prog;
if (spl_prog_load_from_file(path, &prog) != 0) { if (spl_prog_load_from_file(o.path, &prog) != 0) {
fprintf(stderr, "spl_cli: cannot load '%s'\n", path); fprintf(stderr, "spl_cli: cannot load '%s'\n", o.path);
return 1; return 1;
} }
spl_syscall_register(&prog); spl_syscall_register(&prog);
spl_vm_t vm; spl_vm_t vm;
spl_vm_init(&vm); spl_vm_init(&vm);
if (debug_mode) spl_vm_set_debug(&vm, 1); if (o.debug)
spl_vm_set_debug(&vm, 1);
if (o.trace)
spl_vm_set_trace(&vm, 1);
if (spl_vm_load_prog(&vm, &prog) != 0) { if (spl_vm_load_prog(&vm, &prog) != 0) {
fprintf(stderr, "vm: prog '%s' not found\n", entry); fprintf(stderr, "spl_cli: failed to load prog\n");
spl_prog_drop(&prog); spl_vm_drop(&vm);
return 1;
}
if (spl_vm_prepare(&vm, entry, argc, argv, NULL) != 0) {
fprintf(stderr, "vm: entry point '%s' not found\n", entry);
spl_prog_drop(&prog); spl_prog_drop(&prog);
return 1; return 1;
} }
int ret = spl_vm_run_until(&vm, 0); /* spl 程序 argvargv[0]=file.sir程序名argv[1..]=args */
const char **spl_argv = (const char **)malloc(sizeof(char *) * (size_t)(o.nargs + 1));
if (!spl_argv) {
spl_vm_drop(&vm);
spl_prog_drop(&prog);
return 1;
}
spl_argv[0] = o.path;
for (int i = 0; i < o.nargs; i++)
spl_argv[i + 1] = o.args[i];
if (spl_vm_prepare(&vm, o.entry, o.nargs + 1, spl_argv, NULL) != 0) {
fprintf(stderr, "spl_cli: entry point '%s' not found\n", o.entry);
free(spl_argv);
spl_vm_drop(&vm);
spl_prog_drop(&prog);
return 1;
}
int ret = 0;
if (o.debug_cli) {
dbg_t d;
d.vm = &vm;
d.prog = &prog;
d.entry = o.entry;
d.quit = 0;
d.last_ptr = 0;
dbg_map_load(&d.map, prog.debug);
repl_loop(&d);
vec_free(d.map.irlines);
vec_free(d.map.vars);
} else {
ret = spl_vm_run_until(&vm, 0);
if (ret == 2)
fprintf(stderr, "spl_cli: hit breakpoint (run with -g to debug)\n");
}
free(spl_argv);
spl_vm_drop(&vm); spl_vm_drop(&vm);
spl_prog_drop(&prog); spl_prog_drop(&prog);
if (ret < 0) { if (ret < 0)
fprintf(stderr, "spl_cli: VM error (exit_code=%d)\n", vm.exit_code); return 1;
return (int)vm.exit_code;
}
return (int)vm.exit_code; return (int)vm.exit_code;
} }

View File

@@ -39,6 +39,8 @@ void spl_prog_drop(spl_prog_t *prog) {
vec_for(prog->strtab, i) { free((void *)vec_at(prog->strtab, i)); } vec_for(prog->strtab, i) { free((void *)vec_at(prog->strtab, i)); }
vec_free(prog->strtab); vec_free(prog->strtab);
map_free(prog->symtab); map_free(prog->symtab);
free(prog->debug);
prog->debug = NULL;
} }
/* ---- LE read/write helpers ---- */ /* ---- LE read/write helpers ---- */
@@ -201,6 +203,23 @@ int spl_prog_load_from_file(const char *fname, spl_prog_t *prog) {
vec_push(prog->gdata, entry); vec_push(prog->gdata, entry);
} }
/* ---- debug 段splc0 -g 追加在文件尾部) ---- */
prog->debug = NULL;
prog->debug_size = 0;
{
ptrdiff_t used = p - data;
if (used >= 0 && (usize)used < (usize)len) {
size_t dlen = (size_t)len - (size_t)used;
char *dbg = (char *)malloc(dlen + 1);
if (dbg) {
memcpy(dbg, data + used, dlen);
dbg[dlen] = 0;
prog->debug = dbg;
prog->debug_size = dlen;
}
}
}
free(data); free(data);
return 0; return 0;
} }
@@ -343,6 +362,14 @@ int spl_prog_store_to_file(const char *fname, spl_prog_t *prog) {
return 0; return 0;
} }
int spl_prog_add_instr(spl_prog_t *prog, uint8_t opcode, uint8_t type, spl_val_t imm) {
if (!prog)
return 0;
spl_ins_t ins = (spl_ins_t){.opcode = opcode, .type = type, .imm = imm};
vec_push(prog->insns, ins);
return vec_size(prog->insns);
}
int spl_prog_add_func(spl_prog_t *prog, spl_func_t *func) { int spl_prog_add_func(spl_prog_t *prog, spl_func_t *func) {
if (!prog || !func) if (!prog || !func)
return 0; return 0;

View File

@@ -193,6 +193,8 @@ typedef struct spl_prog {
spl_data_t gdata; spl_data_t gdata;
spl_strtab_t strtab; spl_strtab_t strtab;
spl_symtab_t symtab; spl_symtab_t symtab;
char *debug; /* 文件尾部 debug 段splc0 -g 追加的文本),无则 NULL */
usize debug_size;
} spl_prog_t; } spl_prog_t;
void spl_prog_init(spl_prog_t *prog); void spl_prog_init(spl_prog_t *prog);
@@ -201,6 +203,7 @@ void spl_prog_drop(spl_prog_t *prog);
int spl_prog_load_from_file(const char *fname, spl_prog_t *prog); int spl_prog_load_from_file(const char *fname, spl_prog_t *prog);
int spl_prog_store_to_file(const char *fname, spl_prog_t *prog); int spl_prog_store_to_file(const char *fname, spl_prog_t *prog);
int spl_prog_add_instr(spl_prog_t *prog, uint8_t opcode, uint8_t type, spl_val_t imm);
int spl_prog_add_data(spl_prog_t *prog, void *ptr, usize size); int spl_prog_add_data(spl_prog_t *prog, void *ptr, usize size);
int spl_prog_add_func(spl_prog_t *prog, spl_func_t *func); int spl_prog_add_func(spl_prog_t *prog, spl_func_t *func);
int spl_prog_add_native(spl_prog_t *prog, spl_native_t *native); int spl_prog_add_native(spl_prog_t *prog, spl_native_t *native);

View File

@@ -200,6 +200,7 @@ static spl_val_t vm_printf(int nargs, spl_val_t *args) {
for (usize j = 0; j < args[arg_idx]; ++j) { for (usize j = 0; j < args[arg_idx]; ++j) {
vec_push(buffer, ((const char *)args[arg_idx + 1])[j]); vec_push(buffer, ((const char *)args[arg_idx + 1])[j]);
} }
arg_idx += 1; /* %.*s 消耗 2 个实参len, data遇 % 已 +1这里补 1 */
i += 2; i += 2;
} break; } break;
case 'd': case 'd':

View File

@@ -81,15 +81,17 @@ static int spl_type_size(spl_type_t t) {
return -1; \ return -1; \
} while (0) } while (0)
#define CHECK_ADDR(addr, label) do { \ #define CHECK_ADDR(addr, label) \
do { \
if (vm->debug_addr && (uintptr_t)(addr) < 0x1000) { \ if (vm->debug_addr && (uintptr_t)(addr) < 0x1000) { \
fprintf(stderr, "vm: %s at ip=%zd: LOW ADDR=%p sp=%zd fp=%zd\n", \ fprintf(stderr, "vm: %s at ip=%zd: LOW ADDR=%p sp=%zd fp=%zd\n", label, vm->ip - 1, \
label, vm->ip - 1, (void*)(uintptr_t)(addr), vm->sp, vm->fp); \ (void *)(uintptr_t)(addr), vm->sp, vm->fp); \
spl_vm_stackdump(vm, vm->sp); \ spl_vm_stackdump(vm, vm->sp); \
spl_vm_backtrace(vm, vm->fp); \ spl_vm_backtrace(vm, vm->fp); \
vm->exit_code = 1; return -1; \ vm->exit_code = 1; \
return -1; \
} \ } \
} while(0) } while (0)
/* ================================================================ /* ================================================================
* Stack push/pop (stacks.data is pre-allocated in init) * Stack push/pop (stacks.data is pre-allocated in init)
@@ -546,19 +548,22 @@ void spl_vm_init_ex(spl_vm_t *vm, int stack_size, int call_depth) {
#endif #endif
if (!vm) if (!vm)
return; return;
vm->config.max_stack_depth = stack_size > 0 ? stack_size : 1024 * 8; vm->config.max_stack_depth = stack_size > 0 ? stack_size : 1024 * 1024 * 8;
vm->config.max_call_depth = call_depth > 0 ? call_depth : 128; vm->config.max_call_depth = call_depth > 0 ? call_depth : 128;
vec_init(vm->stacks); vec_init(vm->stacks);
vec_realloc(vm->stacks, (usize)vm->config.max_stack_depth); vec_realloc(vm->stacks, (usize)vm->config.max_stack_depth);
vec_init(vm->frames); vec_init(vm->frames);
vec_realloc(vm->frames, (usize)vm->config.max_call_depth); vec_realloc(vm->frames, (usize)vm->config.max_call_depth);
vec_init(vm->breakpoints);
vec_init(vm->fn_breakpoints);
vm->sp = vm->fp = vm->ip = vm->cp = vm->gp = 0; vm->sp = vm->fp = vm->ip = vm->cp = vm->gp = 0;
vm->prog = NULL; vm->prog = NULL;
vm->trace = 0; vm->trace = 0;
vm->debug = 1; vm->debug = 1;
vm->debug_addr = 0; vm->debug_addr = 0;
vm->skip_bp = 0;
vm->exit_code = 0; vm->exit_code = 0;
} }
@@ -569,6 +574,68 @@ void spl_vm_drop(spl_vm_t *vm) {
return; return;
vec_free(vm->stacks); vec_free(vm->stacks);
vec_free(vm->frames); vec_free(vm->frames);
for (usize i = 0; i < vec_size(vm->fn_breakpoints); i++)
free(vm->fn_breakpoints.data[i]);
vec_free(vm->fn_breakpoints);
vec_free(vm->breakpoints);
}
void spl_vm_add_breakpoint(spl_vm_t *vm, usize ip) {
if (!vm)
return;
for (usize i = 0; i < vec_size(vm->breakpoints); i++)
if (vm->breakpoints.data[i] == ip)
return;
vec_push(vm->breakpoints, ip);
}
void spl_vm_add_breakpoint_fn(spl_vm_t *vm, const char *name) {
if (!vm || !name)
return;
for (usize i = 0; i < vec_size(vm->fn_breakpoints); i++)
if (strcmp(vm->fn_breakpoints.data[i], name) == 0)
return;
vec_push(vm->fn_breakpoints, strdup(name));
}
void spl_vm_clear_breakpoints(spl_vm_t *vm) {
if (!vm)
return;
vm->breakpoints.size = 0;
for (usize i = 0; i < vec_size(vm->fn_breakpoints); i++)
free(vm->fn_breakpoints.data[i]);
vm->fn_breakpoints.size = 0;
}
void spl_vm_skip_breakpoint(spl_vm_t *vm) {
if (vm)
vm->skip_bp = 1;
}
/* 前向声明(定义在文件尾部 dump 区域) */
static const char *func_name_by_ip(spl_prog_t *prog, spl_val_t ip);
/* 函数名断点命中addr 所在函数名是否在断点表 */
static int fn_breakpoint_hit(spl_vm_t *vm, spl_val_t addr) {
if (!vm || !vm->prog || !vec_size(vm->fn_breakpoints))
return 0;
const char *fn = func_name_by_ip(vm->prog, addr);
if (!fn)
return 0;
for (usize i = 0; i < vec_size(vm->fn_breakpoints); i++)
if (strcmp(vm->fn_breakpoints.data[i], fn) == 0)
return 1;
return 0;
}
/* ip 断点命中vm->ip即将执行的指令在断点表 */
static int ip_breakpoint_hit(spl_vm_t *vm) {
if (!vm || !vec_size(vm->breakpoints))
return 0;
for (usize i = 0; i < vec_size(vm->breakpoints); i++)
if (vm->breakpoints.data[i] == (usize)vm->ip)
return 1;
return 0;
} }
/* ================================================================ /* ================================================================
@@ -678,6 +745,16 @@ int spl_vm_run_once(spl_vm_t *vm) {
return -1; return -1;
} }
/* 断点:即将执行的指令命中 ip 断点 → 暂停(返回 2
* skip_bp 置位时执行当前指令continue 越过当前断点)。 */
if (ip_breakpoint_hit(vm)) {
if (vm->skip_bp) {
vm->skip_bp = 0;
} else {
return 2;
}
}
ins = &vec_at(prog->insns, vm->ip); ins = &vec_at(prog->insns, vm->ip);
vm->ip++; vm->ip++;
@@ -870,14 +947,20 @@ int spl_vm_run_once(spl_vm_t *vm) {
case SPL_CALL: { case SPL_CALL: {
spl_val_t _nargs = ins->imm; spl_val_t _nargs = ins->imm;
spl_val_t _addr = POP(); spl_val_t _addr = POP();
int _hit = fn_breakpoint_hit(vm, _addr);
spl_vm_call(vm, _addr, _nargs); spl_vm_call(vm, _addr, _nargs);
if (_hit)
return 2; /* 已进入函数,暂停在函数入口 */
break; break;
} }
case SPL_CALLI: { case SPL_CALLI: {
spl_val_t _addr = POP(); spl_val_t _addr = POP();
spl_val_t _nargs = POP(); spl_val_t _nargs = POP();
int _hit = fn_breakpoint_hit(vm, _addr);
spl_vm_call(vm, _addr, _nargs); spl_vm_call(vm, _addr, _nargs);
if (_hit)
return 2;
break; break;
} }
@@ -906,6 +989,8 @@ int spl_vm_run_once(spl_vm_t *vm) {
} }
case SPL_HALT: case SPL_HALT:
if (ins->imm)
vm->exit_code = (int)ins->imm;
return 1; return 1;
/* ========== Stack / Frame Local Memory ========== */ /* ========== Stack / Frame Local Memory ========== */
@@ -1053,7 +1138,7 @@ int spl_vm_run_once(spl_vm_t *vm) {
} }
case SPL_BK: { case SPL_BK: {
return 0; /* breakpoint: pause execution */ return 2; /* breakpoint: pause execution */
} }
default: default:

View File

@@ -31,6 +31,9 @@ typedef struct {
int trace; /* non-zero to print each instruction */ int trace; /* non-zero to print each instruction */
int debug; /* non-zero to enable canary checks */ int debug; /* non-zero to enable canary checks */
int debug_addr; /* non-zero to check for low-address memory access */ int debug_addr; /* non-zero to check for low-address memory access */
int skip_bp; /* non-zero: run_once 忽略下一次断点continue 越过当前断点指令) */
VEC(usize) breakpoints; /* ip 断点执行到该指令前暂停run_once 返回 2 */
VEC(char *) fn_breakpoints; /* 函数名断点CALL/CALLI 目标函数入口暂停) */
spl_prog_t *prog; spl_prog_t *prog;
char error_msg[1024]; char error_msg[1024];
struct { struct {
@@ -61,6 +64,13 @@ void spl_vm_set_debug(spl_vm_t *vm, int enabled);
int spl_vm_run_once(spl_vm_t *vm); int spl_vm_run_once(spl_vm_t *vm);
int spl_vm_run_until(spl_vm_t *vm, size_t step); int spl_vm_run_until(spl_vm_t *vm, size_t step);
/* 断点ip 断点 / 函数名断点CALL/CALLI 目标函数入口)。命中时 run_once 返回 2。 */
void spl_vm_add_breakpoint(spl_vm_t *vm, usize ip);
void spl_vm_add_breakpoint_fn(spl_vm_t *vm, const char *name);
void spl_vm_clear_breakpoints(spl_vm_t *vm);
/* 让 run_once 执行当前指令忽略一次断点命中continue 越过当前断点用 */
void spl_vm_skip_breakpoint(spl_vm_t *vm);
void spl_vm_dump_instr(spl_vm_t *vm, spl_val_t ip); void spl_vm_dump_instr(spl_vm_t *vm, spl_val_t ip);
void spl_vm_stackdump(spl_vm_t *vm, spl_val_t sp); void spl_vm_stackdump(spl_vm_t *vm, spl_val_t sp);
int spl_vm_backtrace(spl_vm_t *vm, spl_val_t fp); int spl_vm_backtrace(spl_vm_t *vm, spl_val_t fp);

View File

@@ -147,11 +147,12 @@ static spl_tok_t *peek_next(parser_t *p) {
} }
static void parse_error(parser_t *p, spl_tok_t *t, const char *msg) { static void parse_error(parser_t *p, spl_tok_t *t, const char *msg) {
(void)p; p->failed = 1; /* 出错即停(上层循环以 !p->failed 提前退出) */
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_ERROR("%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) {
@@ -222,7 +223,7 @@ static spl_ast_node_ref_t wrap_op_expr(parser_t *p, spl_ast_node_ref_t inner, in
/* ================================================================ /* ================================================================
* 字面量解 * ================================================================ */ * 字面量解 * ================================================================ */
/* 整数字面量去下划线后按0 解析x/0o/0b/十进制,忽略 0b 特判*/ /* 整数字面量:去下划线后按 0x/0o/0b/十进制解析 */
static isize parse_int_literal(const spl_tok_t *t) { static isize parse_int_literal(const spl_tok_t *t) {
char buf[128]; char buf[128];
usize j = 0; usize j = 0;
@@ -231,6 +232,11 @@ static isize parse_int_literal(const spl_tok_t *t) {
buf[j++] = t->lexeme[i]; buf[j++] = t->lexeme[i];
} }
buf[j] = 0; buf[j] = 0;
/* strtoll base 0 不认 0b/0o 前缀:单独处理 */
if (j >= 3 && buf[0] == '0' && (buf[1] == 'b' || buf[1] == 'B'))
return (isize)strtoll(buf + 2, NULL, 2);
if (j >= 3 && buf[0] == '0' && (buf[1] == 'o' || buf[1] == 'O'))
return (isize)strtoll(buf + 2, NULL, 8);
return (isize)strtoll(buf, NULL, 0); return (isize)strtoll(buf, NULL, 0);
} }
@@ -636,7 +642,7 @@ static spl_ast_node_ref_vec_t parse_block(parser_t *p) {
vec_init(vec); vec_init(vec);
if (!expect(p, TOK_L_BRACE, "expected '{'")) if (!expect(p, TOK_L_BRACE, "expected '{'"))
return vec; return vec;
while (1) { while (!p->failed) {
spl_tok_t *t = peek(p); spl_tok_t *t = peek(p);
if (!t || t->type == TOK_EOF) { if (!t || t->type == TOK_EOF) {
parse_error(p, t, "block missing '}'"); parse_error(p, t, "block missing '}'");
@@ -1780,10 +1786,11 @@ static spl_ast_node_ref_t parse_type_atom(parser_t *p) {
kind = SPL_AST_TYPE_USIZE; kind = SPL_AST_TYPE_USIZE;
else if (IS_TY("ptr")) else if (IS_TY("ptr"))
kind = SPL_AST_TYPE_PTR; kind = SPL_AST_TYPE_PTR;
else if (IS_TY("f32") || IS_TY("f64")) { else if (IS_TY("f32"))
parse_error(p, t, "not implemented: f32/f64 type"); kind = SPL_AST_TYPE__F32;
kind = SPL_AST_TYPE_IDENT; else if (IS_TY("f64"))
} else { kind = SPL_AST_TYPE__F64;
else {
kind = SPL_AST_TYPE_IDENT; kind = SPL_AST_TYPE_IDENT;
} }
#undef IS_TY #undef IS_TY
@@ -1826,7 +1833,7 @@ void spl_ast_prase(spl_ast_t *ast) {
spl_ast_node_ref_vec_t members; spl_ast_node_ref_vec_t members;
vec_init(members); vec_init(members);
while (1) { while (!p.failed) {
spl_tok_t *t = peek(&p); spl_tok_t *t = peek(&p);
if (!t || t->type == TOK_EOF) if (!t || t->type == TOK_EOF)
break; break;

View File

@@ -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 */

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,26 @@
#ifndef __SPL_AST2IR_H__ #ifndef __SPL_AST2IR_H__
#define __SPL_AST2IR_H__ #define __SPL_AST2IR_H__
#include "spl_ir.h"
#include "spl_sema.h"
/* 全局 var/const 的 def → gdata 向量中的 value 节点索引 */
typedef struct {
spl_def_id_t def_id;
usize gdata_idx;
} spl_ast2ir_gref_t;
typedef struct {
const spl_sema_t *sema;
spl_ir_t ir;
VEC(char *) owned_names; /* 本模块 malloc 的函数名drop 时释放 */
VEC(spl_ast2ir_gref_t) gdata_ref; /* def_id → gdata value 节点索引 */
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__ */

28
stage1/spl_builtin.c Normal file
View File

@@ -0,0 +1,28 @@
/* spl_builtin.c — 内置函数集中注册表实现 */
#include "spl_builtin.h"
#include "../stage0/include/utils.h"
#include <string.h>
static const spl_builtin_t k_builtins[] = {
{"sizeof", SPL_BUILTIN_SIZE_OF, 1, 1, 0},
{"bitsizeof", SPL_BUILTIN_BITSIZE_OF, 1, 1, 0},
{"alignof", SPL_BUILTIN_ALIGN_OF, 1, 1, 0},
{"offsetof", SPL_BUILTIN_OFFSET_OF, 2, 2, 0},
{"field_count", SPL_BUILTIN_FIELD_COUNT, 1, 1, 0},
{"dbg", SPL_BUILTIN_DBG, 0, -1, 1},
{"assert", SPL_BUILTIN_ASSERT, 1, 1, 1},
{"import", SPL_BUILTIN_IMPORT, 1, 1, 1},
};
const spl_builtin_t *spl_builtin_lookup(const char *name) {
if (!name)
return NULL;
for (usize i = 0; i < sizeof(k_builtins) / sizeof(k_builtins[0]); i++) {
if (strcmp(k_builtins[i].name, name) == 0)
return &k_builtins[i];
}
return NULL;
}
int spl_builtin_count(void) { return (int)(sizeof(k_builtins) / sizeof(k_builtins[0])); }

43
stage1/spl_builtin.h Normal file
View File

@@ -0,0 +1,43 @@
/* spl_builtin.h — 内置函数集中注册表
*
* @builtin 名称/类别/参数/返回类型的单一事实来源。
* sema类型推导与 ast2irIR 发射)各自按 kind 分发实现。
*/
#ifndef __SPL_BUILTIN_H__
#define __SPL_BUILTIN_H__
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
SPL_BUILTIN_SIZE_OF, /* @sizeof(T) -> usize */
SPL_BUILTIN_BITSIZE_OF, /* @bitsizeof(T) -> usize */
SPL_BUILTIN_ALIGN_OF, /* @alignof(T) -> usize */
SPL_BUILTIN_OFFSET_OF, /* @offsetof(T, field) -> usize */
SPL_BUILTIN_FIELD_COUNT, /* @field_count(T) -> usize */
SPL_BUILTIN_DBG, /* @dbg(args...) -> void */
SPL_BUILTIN_ASSERT, /* @assert(cond) -> void */
SPL_BUILTIN_IMPORT, /* @import(path) -> 模块 (预留) */
SPL_BUILTIN_COUNT
} spl_builtin_kind_t;
typedef struct {
const char *name;
spl_builtin_kind_t kind;
int min_args; /* 参数个数下限 */
int max_args; /* 参数个数上限,-1 = 不限 */
int ret_is_void; /* 1 = void 返回 */
} spl_builtin_t;
/* 按名称查找内置;未注册返回 NULL */
const spl_builtin_t *spl_builtin_lookup(const char *name);
/* 内置总数 */
int spl_builtin_count(void);
#ifdef __cplusplus
}
#endif
#endif /* __SPL_BUILTIN_H__ */

View File

@@ -1 +1,519 @@
/* 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);
vec_init(ir->gdata);
/* 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(f->dbg_vars);
}
vec_free(ir->funcs);
for (usize i = 0; i < ir->gdata.size; i++)
node_drop_vecs(&ir->gdata.data[i]);
vec_free(ir->gdata);
}
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_init(f.dbg_vars);
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_FIELD_PTR:
printf("@mem.field_ptr(");
ir_type_dump(ty, n->mem_field_ptr.tid);
printf(", %zu)(", (size_t)n->mem_field_ptr.field_idx);
dump_ref(n->mem_field_ptr.agg);
printf(")");
break;
case SPL_IR_MEM_GLOBAL_ALLOC:
printf("@mem.global_alloc(gdata[%zu])()", (size_t)n->mem_global_alloc.const_node);
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]);
if (ir->gdata.size) {
printf("; global data (%zu)\n", ir->gdata.size);
for (usize i = 0; i < ir->gdata.size; i++) {
printf("; gdata[%zu] = ", i);
dump_node(ty, &ir->gdata.data[i]);
printf("\n");
}
}
}
const char *spl_ir_kind_name(spl_ir_kind_t kind) {
static const char *const names[] = {
#define X(a, b, c) #a,
SPL_IR_FN_TABLE
#undef X
};
if ((usize)kind < sizeof(names) / sizeof(names[0]))
return names[kind];
return "?";
}

View File

@@ -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 \
@@ -36,9 +37,11 @@
X(case.int2float, V0, SPL_IR_CASE_INT2FLOAT) \ X(case.int2float, V0, SPL_IR_CASE_INT2FLOAT) \
X(case.float2int, V0, SPL_IR_CASE_FLOAT2INT) \ X(case.float2int, V0, SPL_IR_CASE_FLOAT2INT) \
X(mem.alloca, V0, SPL_IR_MEM_ALLOCA) \ X(mem.alloca, V0, SPL_IR_MEM_ALLOCA) \
X(mem.global_alloc, V0, SPL_IR_MEM_GLOBAL_ALLOC) \
X(mem.load, V0, SPL_IR_MEM_LOAD) \ X(mem.load, V0, SPL_IR_MEM_LOAD) \
X(mem.store, V0, SPL_IR_MEM_STORE) \ X(mem.store, V0, SPL_IR_MEM_STORE) \
X(mem.offset, V0, SPL_IR_MEM_OFFSET) \ X(mem.offset, V0, SPL_IR_MEM_OFFSET) \
X(mem.field, V0, SPL_IR_MEM_FIELD_PTR) \
X(mem.copy, V0, SPL_IR_MEM_COPY) \ X(mem.copy, V0, SPL_IR_MEM_COPY) \
X(mem.set, V0, SPL_IR_MEM_SET) \ X(mem.set, V0, SPL_IR_MEM_SET) \
X(mem.fence, V0, SPL_IR_MEM_FENCE) \ X(mem.fence, V0, SPL_IR_MEM_FENCE) \
@@ -64,6 +67,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 +84,147 @@ 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;
usize src_ref; /* AST 节点 ref调试行号用ast2ir 注解) */
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 const_node;
} mem_global_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 agg;
usize field_idx;
} mem_field_ptr;
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;
spl_type_id_t field_tid;
usize field_idx;
spl_ir_node_ref_t val;
} agg_extract;
struct {
spl_type_id_t tid;
usize 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,
@@ -100,17 +237,32 @@ typedef struct {
}; };
} spl_ir_attr_t; } spl_ir_attr_t;
typedef VEC(spl_ir_attr_t) spl_ir_attr_vec_t; typedef VEC(spl_ir_attr_t) spl_ir_attr_vec_t;
/* 调试:函数内变量(名 → 内存位置。alloca 节点或参数槽。 */
typedef struct {
const char *name; /* 指向 AST 字符串,不拥有 */
spl_ir_node_ref_t alloca; /* 非参数alloca 节点 ref */
spl_type_id_t tid;
int is_param; /* 参数则用 param_idx */
usize param_idx;
usize offset; /* fp 字节偏移LADDR imm 语义ir2vm 填) */
} spl_ir_dbg_var_t;
typedef VEC(spl_ir_dbg_var_t) spl_ir_dbg_var_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_dbg_var_vec_t dbg_vars; /* 调试变量表fp 偏移在 ir2vm 填) */
} 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_node_vec_t gdata;
} spl_ir_t; } spl_ir_t;
void spl_ir_init(spl_ir_t *ir); void spl_ir_init(spl_ir_t *ir);
@@ -122,6 +274,7 @@ 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);
const char *spl_ir_kind_name(spl_ir_kind_t kind);
#endif /* __SPL_IR_H__ */ #endif /* __SPL_IR_H__ */

1426
stage1/spl_ir2vm.c Normal file

File diff suppressed because it is too large Load Diff

101
stage1/spl_ir2vm.h Normal file
View File

@@ -0,0 +1,101 @@
#ifndef __SPL_IR2VM_H__
#define __SPL_IR2VM_H__
#include "spl_ir.h"
#include "spl_type.h"
/*
* ================================================================
* SPL VM ABI (ir2vm 的正式约定;布局知识唯一来源)
* ================================================================
*
* 栈值槽 spl_val_t = sizeof(usize) = 8 字节。
* SIR 指令 type 只表达标量 tagSPL_I8..SPL_PTR聚合无 tag——
* 聚合值在 vreg 中是字节块,整体搬运用 NCALL vm_memcpy。
*
* ── 函数栈帧(字节坐标系,基址 = (char*)&stacks[fp])─────────────
*
* [canary] fp-8 .. 0 VM CALL 自动插入ir2vm 不触碰)
* [params 区] fp+0 .. fp+Na Na = C ABI 参数区字节数)
* [locals / vreg] fp+Na .. fp+Na+L
*
* ALLOC ceil((Na+L)/8) 一条 prologueepilogue 走 RET。
* LADDR(imm) 的 imm 是字节偏移canary 在 fp-1 槽,编译码不可见。
*
* ── 参数区 = C ABI聚合值按值 ─────────────────────────────────
* 标量参数align_up(off,8) 后占 8 字节(一槽)。
* 聚合参数:按聚合 size 排布跨多槽align8 + size
* 调用方:标量 ld/PUSH 一槽;聚合逐 8 字节块压栈(聚合 vreg 强制 8 对齐)。
* 被调方:标量参数映射参数槽;聚合参数在 prologue memcpy 参数区 → param vreg
* emit_value(param) 取 vreg 地址。参数槽数 = ceil(param_bytes/8) = CALL nargs。
*
* ── locals = 虚拟寄存器区 ────────────────────────────────────────
* 每个产生值的 IR 节点 = 一个 vreglocals 区按类型对齐的字节块)。
* 纯值节点type.const / mem.global_alloc / mem.alloca / 折叠 sizeof 等)不落 vreg
* 引用处重算PUSH / GADDR / LADDR其余产生值节点落 vreg引用处 LOAD。
* 聚合 vreg 引用处返回其地址LADDR搬运经 vm_memcpy。
* mem.alloca(tid)(cnt) 的 vreg 槽即缓冲区本体,节点值 = LADDR(vreg_off)。
* 所有运算走 load/storeld A; ld B; op; st Dst立即数直接 PUSH。
*
* ── 调用 ──────────────────────────────────────────────────────────
* 调用方:逐参数压栈(标量一槽;聚合按 C ABI 逐 8 字节块)→ push fn_addr(或
* native_idx) → CALL n / NCALL n。返回值落 call 节点 vreg。
* 原生函数IR 中 nodes 为空的函数(@extern 声明)→ 注册进 prog.natives
* 加载时由 spl_syscall_register 填 impl调用改 PUSH nat_idx + NCALL。
* 变参 nargs = 实际参数槽数。
*
* ── enum不展开直接保留─────────────────────────────────────
* IR 层保留 enum 类型(不再展开为 struct。enum 布局 = tag(usize, offset 0)
* + payload(offset 8最大变体。构造agg.construct(enum)(tag, payload)
* match先取 tag 判定变体,再 extract(enum, 1) 一跳取 payload
* field_tid = 变体具体类型(由 ast2ir 传入)。
*
* ── 返回 ──────────────────────────────────────────────────────────
* 标量ld vreg(val); RET(tag)RET 的 type 决定 VM 是否弹出返回值)。
* 聚合返回 = sret自展开不改 VM
* 被调函数签名尾部追加隐藏 *T 参数(最后一个);返回时把聚合 vreg
* memcpy 到 sret 地址RET(void)。
* 调用方在 locals 预留聚合槽(= call 节点 vreg压其地址为最后实参
* call 完成后聚合值已在该槽。
* 返回 voidRET(SPL_VOID)。
*
* ── 全局数据 ──────────────────────────────────────────────────────
* 任何聚合类型下(含 $root 顶层)的 var/const 属全局数据区。gdata 是
* spl_ir_node_vec_t每条 = 一个 value 节点type.const标量折叠值
* 聚合/无 init 零。ir2vm 遍历求值 → SIR gdata 条目(字节 blob
* mem.global_alloc(tid, const_node) 的 const_node = gdata 向量索引,
* 降级为 GADDR(idx)。符号(def) → gdata 索引的解析在 ast2ir 收集期
* gdata_ref 表ir2vm 按索引直接用。
*
* ── 类型布局C ABI唯一实现处────────────────────────────────
* type_align / type_size / field_offset标量按 bits/8 对齐;
* struct 顺序对齐 + 尾填充union 取最大字段enum = tag(8) + 最大 payload
* slice/range = [ptr, len] 各 8 字节array = len * elem。
*
* ── 分支 ──────────────────────────────────────────────────────────
* control.br/jmp/select 的 label 是 IR node ref基本块首指令。两遍发射
* 第一遍逐节点发指令并记录 label 节点 → 指令地址;第二遍回填
* JMP/BZ/BNZ 相对偏移 imm = target_addr - (jmp_addr + 1)。
* ================================================================
*/
/* 调试映射:每函数 IR 节点 → 首条指令 ip调试器显示当前 IR 节点用) */
typedef struct {
spl_ir_func_ref_t fid;
VEC(usize) node_first_ip; /* 索引 = IR 节点 ref值 = 该节点首指令绝对 ip */
} spl_ir2vm_fdbg_t;
typedef VEC(spl_ir2vm_fdbg_t) spl_ir2vm_fdbg_vec_t;
typedef struct {
const spl_ir_t *ir;
const spl_type_t *type;
spl_ir2vm_fdbg_vec_t fdbg; /* ir2vm_run 后填充splc0 -g 读取生成 debug 段 */
} spl_ir2vm_t;
void spl_ir2vm_init(spl_ir2vm_t *ctx, const spl_ir_t *ir, const spl_type_t *type);
void spl_ir2vm_drop(spl_ir2vm_t *ctx);
int spl_ir2vm_run(spl_ir2vm_t *ctx, const char *outpath); /* 返回错误数 */
void spl_ir2vm_dump(spl_ir2vm_t *ctx);
#endif /* __SPL_IR2VM_H__ */

View File

@@ -270,7 +270,8 @@ spl_tok_vec_t spl_lex(const char *source, const char *fname) {
/* Hex literal */ /* Hex literal */
offset += 2; offset += 2;
col += 2; col += 2;
while (offset < len && isxdigit((unsigned char)source[offset])) { while (offset < len &&
(isxdigit((unsigned char)source[offset]) || source[offset] == '_')) {
offset++; offset++;
col++; col++;
} }
@@ -280,7 +281,8 @@ spl_tok_vec_t spl_lex(const char *source, const char *fname) {
/* Binary literal */ /* Binary literal */
offset += 2; offset += 2;
col += 2; col += 2;
while (offset < len && (source[offset] == '0' || source[offset] == '1')) { while (offset < len && (source[offset] == '0' || source[offset] == '1' ||
source[offset] == '_')) {
offset++; offset++;
col++; col++;
} }
@@ -290,7 +292,8 @@ spl_tok_vec_t spl_lex(const char *source, const char *fname) {
/* Octal literal */ /* Octal literal */
offset += 2; offset += 2;
col += 2; col += 2;
while (offset < len && source[offset] >= '0' && source[offset] <= '7') { while (offset < len && ((source[offset] >= '0' && source[offset] <= '7') ||
source[offset] == '_')) {
offset++; offset++;
col++; col++;
} }
@@ -299,7 +302,8 @@ spl_tok_vec_t spl_lex(const char *source, const char *fname) {
} }
/* Decimal integer or float */ /* Decimal integer or float */
while (offset < len && isdigit((unsigned char)source[offset])) { while (offset < len &&
(isdigit((unsigned char)source[offset]) || source[offset] == '_')) {
offset++; offset++;
col++; col++;
} }

View File

@@ -1,4 +1,4 @@
// WRITE BY AI // WRITE BY AI
/* spl_sema.c SPL 语义分析 /* spl_sema.c SPL 语义分析
* *
* 两趟 AST 遍历splc0 显式先 run 再 check * 两趟 AST 遍历splc0 显式先 run 再 check
@@ -9,6 +9,7 @@
* 命名实体放 def_table两张表 id 空间完全独立。 * 命名实体放 def_table两张表 id 空间完全独立。
*/ */
#include "spl_sema.h" #include "spl_sema.h"
#include "spl_builtin.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@@ -112,11 +113,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 +282,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聚合/别名/内置为 0ast2ir 据此直接取类型) */
if (base)
n->resolved_def_id = def_for_type(sema, base);
return base; return base;
} }
@@ -331,6 +335,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 +371,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 +428,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 +448,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 +456,14 @@ 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);
/* 标记 const赋值检查拒绝写入 */
spl_ast_node_t *nn = node_at(sema->ast, ref);
if (nn && nn->resolved_def_id) {
spl_def_node_t *d = def_at(sema, nn->resolved_def_id);
if (d)
d->var_def.is_const = 1;
}
} }
/* fn 声明:建 fn type + FN_PARAMS def + 登记名字。不建 fn_scope由 check 新建)。 /* fn 声明:建 fn type + FN_PARAMS def + 登记名字。不建 fn_scope由 check 新建)。
@@ -477,7 +502,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 +536,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 */
} }
/* ================================================================ /* ================================================================
@@ -561,6 +588,29 @@ static bool expr_is_int_literal(spl_sema_t *sema, spl_ast_node_ref_t ref) {
} }
} }
/* 浮点字面量(含负号前缀):允许拓宽/窄化到目标浮点类型 */
static bool expr_is_float_literal(spl_sema_t *sema, spl_ast_node_ref_t ref) {
spl_ast_node_t *n = node_at(sema->ast, ref);
if (!n || n->kind != SPL_AST_EXPR)
return false;
switch (n->expr.op) {
case SPL_AST_PRIMARY_EXPR: {
spl_ast_node_t *pn = node_at(sema->ast, n->expr.op_expr.left);
int k = pn && pn->kind == SPL_AST_EXPR ? (int)pn->primary_expr.kind : -1;
return k == SPL_AST_FLOAT;
}
case SPL_AST_PREFIX_EXPR:
return expr_is_float_literal(sema, n->expr.op_expr.left);
default:
return false;
}
}
/* 字面量(整型或浮点):检查时允许类型拓宽 */
static bool expr_is_literal(spl_sema_t *sema, spl_ast_node_ref_t ref) {
return expr_is_int_literal(sema, ref) || expr_is_float_literal(sema, ref);
}
/* 打开 SPL_TYPE_ID 绑定节点返回真实类型newtype 预留;当前无调用产生该节点) */ /* 打开 SPL_TYPE_ID 绑定节点返回真实类型newtype 预留;当前无调用产生该节点) */
static spl_type_id_t underlying(spl_sema_t *sema, spl_type_id_t tid) { static spl_type_id_t underlying(spl_sema_t *sema, spl_type_id_t tid) {
spl_type_node_t *t = type_node(sema, tid); spl_type_node_t *t = type_node(sema, tid);
@@ -631,6 +681,9 @@ static int type_compatible(spl_sema_t *sema, spl_type_id_t dst, spl_type_id_t sr
/* 字面量值已隐含满足范围(检查时由调用方保证),此处允许拓宽 */ /* 字面量值已隐含满足范围(检查时由调用方保证),此处允许拓宽 */
return 1; return 1;
} }
/* 浮点字面量可赋值到目标浮点f64 字面量 → f32 变量,值可表示则允许) */
if (is_literal && d->kind == SPL_TYPE_FLOAT && s->kind == SPL_TYPE_FLOAT)
return 1;
/* isize/usize机器字宽与 i32 混合:比较/算术/传参可用splc1 与旧测试事实标准) */ /* isize/usize机器字宽与 i32 混合:比较/算术/传参可用splc1 与旧测试事实标准) */
if (d->kind == SPL_TYPE_INT && s->kind == SPL_TYPE_INT) { if (d->kind == SPL_TYPE_INT && s->kind == SPL_TYPE_INT) {
int dbits = d->int_type.bits, sbits = s->int_type.bits; int dbits = d->int_type.bits, sbits = s->int_type.bits;
@@ -753,8 +806,8 @@ static spl_type_id_t infer_binary_cmp(spl_sema_t *sema, spl_ast_node_ref_t ref,
return 0; return 0;
} }
int w = 0; int w = 0;
if (type_compatible(sema, l, r, expr_is_int_literal(sema, e->expr.op_expr.right), &w) || if (type_compatible(sema, l, r, expr_is_literal(sema, e->expr.op_expr.right), &w) ||
type_compatible(sema, r, l, expr_is_int_literal(sema, e->expr.op_expr.left), &w)) { type_compatible(sema, r, l, expr_is_literal(sema, e->expr.op_expr.left), &w)) {
return spl_type_bool(&sema->type); return spl_type_bool(&sema->type);
} }
sema_error(sema, ref, "type mismatch in comparison"); sema_error(sema, ref, "type mismatch in comparison");
@@ -900,7 +953,7 @@ static spl_type_id_t infer_agg_init(spl_sema_t *sema, spl_ast_node_ref_t ref, sp
int w = 0; int w = 0;
if (!expr_is_null_literal(sema, item->aggregate_init_item.expr) && et && if (!expr_is_null_literal(sema, item->aggregate_init_item.expr) && et &&
!type_compatible(sema, mt, et, !type_compatible(sema, mt, et,
expr_is_int_literal(sema, item->aggregate_init_item.expr), &w)) { expr_is_literal(sema, item->aggregate_init_item.expr), &w)) {
sema_error(sema, iref, "field type mismatch in aggregate literal"); sema_error(sema, iref, "field type mismatch in aggregate literal");
} }
} }
@@ -923,8 +976,7 @@ static spl_type_id_t infer_array_lit(spl_sema_t *sema, spl_ast_node_ref_t ref, s
int w = 0; int w = 0;
if (!type_compatible( if (!type_compatible(
sema, elem, et, sema, elem, et,
expr_is_int_literal(sema, pn->primary_expr.array_lit_expr.expr_list.data[i]), expr_is_literal(sema, pn->primary_expr.array_lit_expr.expr_list.data[i]), &w)) {
&w)) {
sema_error(sema, pn->primary_expr.array_lit_expr.expr_list.data[i], sema_error(sema, pn->primary_expr.array_lit_expr.expr_list.data[i],
"element type mismatch in array literal"); "element type mismatch in array literal");
} }
@@ -937,14 +989,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 引用 → 其符号 defvar 用 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);
@@ -980,16 +1050,35 @@ static spl_type_id_t infer_primary(spl_sema_t *sema, spl_ast_node_ref_t ref, spl
return infer_expr(sema, pn->primary_expr.expr); return infer_expr(sema, pn->primary_expr.expr);
case SPL_AST_ARRAY_LIT: case SPL_AST_ARRAY_LIT:
return infer_array_lit(sema, ref, n); return infer_array_lit(sema, ref, n);
case SPL_AST_BUILTIN_EXPR: case SPL_AST_BUILTIN_EXPR: {
/* 内置调用:先推断实参,类型按名称约定 */ /* 内置调用:类型按注册表约定参数按需推断offsetof 字段名参数非表达式) */
for (usize i = 0; i < pn->primary_expr.builtin_expr.expr_list.size; i++) const spl_builtin_t *bi = spl_builtin_lookup(pn->primary_expr.builtin_expr.ident);
if (!bi) {
sema_error(sema, ref, "unknown builtin");
return 0;
}
usize nargs = pn->primary_expr.builtin_expr.expr_list.size;
if (nargs < (usize)bi->min_args || (bi->max_args >= 0 && nargs > (usize)bi->max_args)) {
char buf[96];
snprintf(buf, sizeof buf, "builtin @%s: arg count mismatch", bi->name);
sema_error(sema, ref, buf);
return 0;
}
for (usize i = 0; i < nargs; i++) {
/* offsetof 第二参数为字段标识符,不按表达式推断 */
if (bi->kind == SPL_BUILTIN_OFFSET_OF && i == 1)
continue;
infer_expr(sema, pn->primary_expr.builtin_expr.expr_list.data[i]); infer_expr(sema, pn->primary_expr.builtin_expr.expr_list.data[i]);
if (strcmp(pn->primary_expr.builtin_expr.ident, "sizeof") == 0) }
if (bi->ret_is_void)
return spl_type_void(&sema->type);
if (bi->kind == SPL_BUILTIN_SIZE_OF || bi->kind == SPL_BUILTIN_BITSIZE_OF ||
bi->kind == SPL_BUILTIN_ALIGN_OF || bi->kind == SPL_BUILTIN_OFFSET_OF ||
bi->kind == SPL_BUILTIN_FIELD_COUNT)
return spl_type_int(&sema->type, sizeof(usize) * 8, 0); return spl_type_int(&sema->type, sizeof(usize) * 8, 0);
if (strcmp(pn->primary_expr.builtin_expr.ident, "dbg") == 0 || sema_error(sema, ref, "unsupported builtin");
strcmp(pn->primary_expr.builtin_expr.ident, "assert") == 0) return 0;
return spl_type_void(&sema->type); }
return spl_type_void(&sema->type);
case SPL_AST_BLOCK_EXPR: { case SPL_AST_BLOCK_EXPR: {
/* 块表达式:有独立 scope逐语句检查返回末尾表达式类型无则 void */ /* 块表达式:有独立 scope逐语句检查返回末尾表达式类型无则 void */
spl_ast_node_ref_vec_t *items = &pn->primary_expr.block_expr; spl_ast_node_ref_vec_t *items = &pn->primary_expr.block_expr;
@@ -1080,6 +1169,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 +1262,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 realloct 会失效,须每次刷新 */ /* 注意infer_expr 可能新分配类型使 type_table realloct 会失效,须每次刷新 */
@@ -1182,7 +1275,7 @@ static spl_type_id_t infer_postfix(spl_sema_t *sema, spl_ast_node_ref_t ref, spl
int w = 0; int w = 0;
if (!expr_is_null_literal(sema, args->data[i]) && at && if (!expr_is_null_literal(sema, args->data[i]) && at &&
!type_compatible(sema, t->fn_type.params.data[i], at, !type_compatible(sema, t->fn_type.params.data[i], at,
expr_is_int_literal(sema, args->data[i]), &w)) { expr_is_literal(sema, args->data[i]), &w)) {
sema_error(sema, args->data[i], "argument type mismatch"); sema_error(sema, args->data[i], "argument type mismatch");
} }
} }
@@ -1258,10 +1351,24 @@ static spl_type_id_t infer_expr(spl_sema_t *sema, spl_ast_node_ref_t ref) {
sema_error(sema, ref, "bad assignment"); sema_error(sema, ref, "bad assignment");
return 0; return 0;
} }
/* 不可写检查:赋值目标为 const 变量时拒绝 */
{
spl_ast_node_t *lhs = node_at(sema->ast, n->expr.op_expr.left);
if (lhs && lhs->kind == SPL_AST_EXPR && lhs->expr.op == SPL_AST_PRIMARY_EXPR) {
spl_ast_node_t *lpn = node_at(sema->ast, lhs->expr.op_expr.left);
if (lpn && lpn->kind == SPL_AST_EXPR &&
lpn->primary_expr.kind == SPL_AST_IDENT && lpn->resolved_def_id) {
spl_def_node_t *ld = def_at(sema, lpn->resolved_def_id);
if (ld && ld->kind == SPL_DEF_VAR && ld->var_def.is_const) {
sema_error(sema, ref, "cannot assign to const");
return 0;
}
}
}
}
int w = 0; int w = 0;
if (!expr_is_null_literal(sema, n->expr.op_expr.right) && if (!expr_is_null_literal(sema, n->expr.op_expr.right) &&
!type_compatible(sema, l, r, expr_is_int_literal(sema, n->expr.op_expr.right), !type_compatible(sema, l, r, expr_is_literal(sema, n->expr.op_expr.right), &w)) {
&w)) {
sema_error(sema, ref, "assignment type mismatch"); sema_error(sema, ref, "assignment type mismatch");
return 0; return 0;
} }
@@ -1320,7 +1427,7 @@ static void check_var_init(spl_sema_t *sema, spl_ast_node_ref_t ref, const char
if (dt) { if (dt) {
int w = 0; int w = 0;
if (!expr_is_null_literal(sema, init_expr) && it && if (!expr_is_null_literal(sema, init_expr) && it &&
!type_compatible(sema, dt, it, expr_is_int_literal(sema, init_expr), &w)) { !type_compatible(sema, dt, it, expr_is_literal(sema, init_expr), &w)) {
sema_error(sema, ref, "initializer type mismatch"); sema_error(sema, ref, "initializer type mismatch");
} else if (w) { } else if (w) {
sema_warn(sema, ref, "pointer conversion involves wildcard"); sema_warn(sema, ref, "pointer conversion involves wildcard");
@@ -1386,7 +1493,7 @@ static spl_type_id_t infer_agg_init_with_type(spl_sema_t *sema, spl_ast_node_ref
int w = 0; int w = 0;
if (!expr_is_null_literal(sema, item->aggregate_init_item.expr) && et && if (!expr_is_null_literal(sema, item->aggregate_init_item.expr) && et &&
!type_compatible(sema, mt, et, !type_compatible(sema, mt, et,
expr_is_int_literal(sema, item->aggregate_init_item.expr), &w)) { expr_is_literal(sema, item->aggregate_init_item.expr), &w)) {
sema_error(sema, iref, "field type mismatch in aggregate literal"); sema_error(sema, iref, "field type mismatch in aggregate literal");
} }
} }
@@ -1451,6 +1558,33 @@ static void check_match(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t
sema_error(sema, ref, "match: arm pattern/body count mismatch"); sema_error(sema, ref, "match: arm pattern/body count mismatch");
return; return;
} }
/* 穷举检查enum 必须覆盖所有变体,或含通配 _含表达式的整数 match 免检) */
{
spl_def_id_t adef = def_for_type(sema, mtype);
spl_def_node_t *ad = adef ? &sema->type.def_table.data[adef] : NULL;
int is_enum_agg = ad && ad->kind == SPL_DEF_AGG;
if (is_enum_agg) {
int has_wild = 0;
usize covered = 0;
for (usize i = 0; i < arms->size; i++) {
spl_ast_node_t *pk = node_at(sema->ast, arms->data[i]);
if (!pk)
continue;
/* _ 通配ident 与 expr 均为空 */
if (!pk->packed_expr.ident && !pk->packed_expr.expr) {
has_wild = 1;
break;
}
if (pk->packed_expr.ident) {
/* 变体被覆盖:匹配臂中出现的合法变体计数 */
if (agg_member_type(sema, mtype, pk->packed_expr.ident))
covered++;
}
}
if (!has_wild && covered < ad->agg_def.size)
sema_error(sema, ref, "match must be exhaustive");
}
}
for (usize i = 0; i < arms->size; i++) { for (usize i = 0; i < arms->size; i++) {
spl_ast_node_t *pk = node_at(sema->ast, arms->data[i]); spl_ast_node_t *pk = node_at(sema->ast, arms->data[i]);
if (!pk) if (!pk)
@@ -1476,7 +1610,7 @@ static void check_match(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t
spl_type_id_t et = infer_expr(sema, pk->packed_expr.expr); spl_type_id_t et = infer_expr(sema, pk->packed_expr.expr);
int w = 0; int w = 0;
if (is_int_tid(sema, mtype) && et && if (is_int_tid(sema, mtype) && et &&
!type_compatible(sema, mtype, et, expr_is_int_literal(sema, pk->packed_expr.expr), !type_compatible(sema, mtype, et, expr_is_literal(sema, pk->packed_expr.expr),
&w)) { &w)) {
sema_error(sema, pk->packed_expr.expr, "match arm pattern type mismatch"); sema_error(sema, pk->packed_expr.expr, "match arm pattern type mismatch");
} }
@@ -1584,7 +1718,7 @@ static void check_stmt(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_sema_ctx_t
if (ctx.ret) { if (ctx.ret) {
if (!expr_is_null_literal(sema, rd->block_item.ret_statement.expr) && et && if (!expr_is_null_literal(sema, rd->block_item.ret_statement.expr) && et &&
!type_compatible(sema, ctx.ret, et, !type_compatible(sema, ctx.ret, et,
expr_is_int_literal(sema, rd->block_item.ret_statement.expr), expr_is_literal(sema, rd->block_item.ret_statement.expr),
NULL)) { NULL)) {
sema_error(sema, rd->block_item.ret_statement.expr, "ret type mismatch"); sema_error(sema, rd->block_item.ret_statement.expr, "ret type mismatch");
} }
@@ -1623,11 +1757,21 @@ 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);
/* 标记 const赋值检查拒绝写入 */
spl_ast_node_t *cn = node_at(sema->ast, b->block_item.const_decl);
if (cn && cn->resolved_def_id) {
spl_def_node_t *cdd = def_at(sema, cn->resolved_def_id);
if (cdd)
cdd->var_def.is_const = 1;
}
}
} 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 +1808,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 +1893,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 +1905,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 */
@@ -1779,6 +1927,9 @@ void spl_sema_run(spl_sema_t *sema) {
sema_var_decl(sema, mref, sema->root_scope, sema->root_def); sema_var_decl(sema, mref, sema->root_scope, sema->root_def);
else if (m->kind == SPL_AST_CONST_DECL) else if (m->kind == SPL_AST_CONST_DECL)
sema_const_decl(sema, mref, sema->root_scope, sema->root_def); sema_const_decl(sema, mref, sema->root_scope, sema->root_def);
else if (m->kind == SPL_AST_MEMBER_DECL && m->member_decl.name)
register_binding(sema, m->member_decl.name, m->member_decl.type_expr, sema->root_scope,
sema->root_def, mref);
} }
sema->current_scope = sema->root_scope; sema->current_scope = sema->root_scope;
} }

View File

@@ -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 : "?");

View File

@@ -58,6 +58,7 @@ typedef struct {
spl_def_id_t def_id; spl_def_id_t def_id;
spl_type_id_t type_id; spl_type_id_t type_id;
usize scope_id; usize scope_id;
int is_const; /* var_def 是否为 const 声明(只读) */
} spl_var_def_t; } spl_var_def_t;
typedef VEC(spl_var_def_t) spl_var_def_vec_t; typedef VEC(spl_var_def_t) spl_var_def_vec_t;
@@ -65,6 +66,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

View File

@@ -11,6 +11,8 @@
#include <string.h> #include <string.h>
#include "spl_ast.h" #include "spl_ast.h"
#include "spl_ast2ir.h"
#include "spl_ir2vm.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"
@@ -61,6 +63,11 @@ static void dump_ast(const char *src, const char *fname) {
spl_ast_t ast; spl_ast_t ast;
spl_ast_init(&ast, &toks); spl_ast_init(&ast, &toks);
spl_ast_prase(&ast); spl_ast_prase(&ast);
if (ast.parsed < 0) {
printf("parse failed, skip AST dump\n");
spl_ast_drop(&ast);
return;
}
spl_ast_valid(&ast); spl_ast_valid(&ast);
spl_ast_dump(&ast, ast.root); spl_ast_dump(&ast, ast.root);
spl_ast_drop(&ast); spl_ast_drop(&ast);
@@ -71,6 +78,11 @@ static void dump_sema(const char *src, const char *fname) {
spl_ast_t ast; spl_ast_t ast;
spl_ast_init(&ast, &toks); spl_ast_init(&ast, &toks);
spl_ast_prase(&ast); spl_ast_prase(&ast);
if (ast.parsed < 0) {
printf("parse failed, skip sema dump\n");
spl_ast_drop(&ast);
return;
}
spl_ast_valid(&ast); spl_ast_valid(&ast);
spl_sema_t sema; spl_sema_t sema;
spl_sema_init(&sema); spl_sema_init(&sema);
@@ -102,6 +114,39 @@ 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);
if (ast.parsed < 0) {
printf("parse failed, skip IR\n");
spl_ast_drop(&ast);
return;
}
spl_ast_valid(&ast);
spl_sema_t sema;
spl_sema_init(&sema);
sema.ast = &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,38 +155,147 @@ 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;
} }
static spl_ast_node_t *ast_node_at(spl_ast_t *ast, spl_ast_node_ref_t ref) {
if (ref == 0 || ref >= ast->buckets.size)
return NULL;
return &ast->buckets.data[ref];
}
static int ast_line(spl_ast_t *ast, spl_ast_node_ref_t ref) {
spl_ast_node_t *n = ast_node_at(ast, ref);
return n ? n->loc.line : 0;
}
/* -g在 .sir 尾部追加 debug 段文本IR 行 + VAR 行spl_cli -g 读取 */
static void gen_debug_map(const char *outpath, spl_ast_t *ast, const spl_ir_t *ir,
const spl_ir2vm_t *ir2vm) {
FILE *f = fopen(outpath, "ab");
if (!f)
return;
fprintf(f, "SPLDBG\n");
for (usize i = 0; i < ir2vm->fdbg.size; i++) {
const spl_ir2vm_fdbg_t *fd = &ir2vm->fdbg.data[i];
if (fd->fid >= ir->funcs.size)
continue;
const spl_ir_func_t *fn = &ir->funcs.data[fd->fid];
const char *fname = fn->name ? fn->name : "?";
for (usize ref = 1; ref < fd->node_first_ip.size; ref++) {
usize ip = fd->node_first_ip.data[ref];
if (ip == (usize)-1)
continue;
const spl_ir_node_t *n = &fn->nodes.data[ref];
fprintf(f, "IR %zu %zu %d %s\n", ip, ref, ast_line(ast, n->src_ref),
spl_ir_kind_name(n->kind));
}
for (usize j = 0; j < fn->dbg_vars.size; j++) {
const spl_ir_dbg_var_t *dv = &fn->dbg_vars.data[j];
if (!dv->name)
continue;
fprintf(f, "VAR %s %s %zu %zu %d\n", fname, dv->name, dv->offset, dv->tid,
dv->is_param);
}
}
fclose(f);
}
static int compile_spl(const char *src, const char *fname, const char *outpath, int gen_debug) {
spl_tok_vec_t toks = spl_lex(src, fname);
spl_ast_t ast;
spl_ast_init(&ast, &toks);
spl_ast_prase(&ast);
if (ast.parsed < 0) {
printf("parse failed, no output\n");
spl_ast_drop(&ast);
return 1;
}
spl_ast_valid(&ast);
spl_sema_t sema;
spl_sema_init(&sema);
sema.ast = &ast;
spl_sema_run(&sema);
spl_sema_check(&sema);
if (sema.error_count) {
printf("sema errors=%d, no output\n", sema.error_count);
spl_sema_drop(&sema);
spl_ast_drop(&ast);
return 1;
}
spl_ast2ir_t a2ir;
spl_ast2ir_init(&a2ir, &sema);
spl_ast2ir_run(&a2ir);
if (a2ir.err_count) {
printf("ast2ir errors=%d, no output\n", a2ir.err_count);
spl_ast2ir_drop(&a2ir);
spl_sema_drop(&sema);
spl_ast_drop(&ast);
return 1;
}
spl_ir2vm_t ir2vm;
spl_ir2vm_init(&ir2vm, &a2ir.ir, &sema.type);
int rc = spl_ir2vm_run(&ir2vm, outpath);
if (gen_debug && rc == 0)
gen_debug_map(outpath, &ast, &a2ir.ir, &ir2vm);
spl_ir2vm_drop(&ir2vm);
spl_ast2ir_drop(&a2ir);
spl_sema_drop(&sema);
spl_ast_drop(&ast);
return rc ? 1 : 0;
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
if (argc < 2) { if (argc < 2) {
LOG_FATAL("Usage: splc0 [--dump <flags>] <in> [out]\n"); LOG_FATAL("Usage: splc0 [--dump <flags>] <in> [out]");
return 1; return 1;
} }
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, stage B)");
LOG_INFO("splc0 --dump <flags> <file> dump: tokens,ast,sema,all\n"); LOG_INFO("splc0 --dump <flags> <file> dump: tokens,ast,sema,ir,all");
return 0; return 0;
} }
int argi = 1; int argi = 1;
if (argi >= argc) { if (argi >= argc) {
LOG_FATAL("Usage: splc0 [--dump <flags>] <in> [out]\n"); LOG_FATAL("Usage: splc0 [--dump <flags>] <in> [out]");
return 1; return 1;
} }
if (strcmp(argv[argi], "--dump") == 0) { if (strcmp(argv[argi], "--dump") == 0) {
if (argc < argi + 3) { if (argc < argi + 3) {
LOG_INFO("splc0: --dump need <flags> <file>\n"); LOG_INFO("splc0: --dump need <flags> <file>");
return 1; return 1;
} }
return cmd_dump(argv[argi + 1], argv[argi + 2]); return cmd_dump(argv[argi + 1], argv[argi + 2]);
} }
LOG_FATAL("splc0: compile todo\n"); /* splc0 [-g] <in> <out> */
if (argc < argi + 2) {
LOG_FATAL("Usage: splc0 <in> <out> [-g] or splc0 --dump <flags> <file>\n");
return 1; return 1;
}
int gen_debug = 0;
if (strcmp(argv[argi], "-g") == 0) {
gen_debug = 1;
argi++;
}
if (argc < argi + 2) {
LOG_FATAL("Usage: splc0 <in> <out> [-g] or splc0 --dump <flags> <file>\n");
return 1;
}
long len;
char *src = read_file(argv[argi], &len);
if (!src)
return 1;
int rc = compile_spl(src, argv[argi], argv[argi + 1], gen_debug);
free(src);
return rc;
} }

View File

@@ -1,68 +0,0 @@
/* spc_vm.c launcher for stage 1 */
#include "../stage0/spl_mcode.h"
#include "../stage0/spl_syscall.h"
#include "../stage0/spl_vm.h"
#include <stdio.h>
#include <string.h>
int main(int argc, const char **argv) {
int argi = 1;
/* Parse flags: --entry <name>, --trace, -d */
const char *entry = "main";
int trace = 0;
int debug_addr = 0;
for (int i = argi; i < argc; i += 1) {
if (strcmp(argv[i], "--entry") == 0 && i + 1 < argc) {
entry = argv[++i];
} else if (strcmp(argv[i], "--trace") == 0) {
trace = 1;
} else if (strcmp(argv[i], "-d") == 0) {
debug_addr = 1;
} else if (argv[i][0] != '-') {
argi = i;
break;
}
}
if (argi >= argc) {
fprintf(stderr, "Usage: spc_vm [-d] [--trace] <file.sir> [args...]\n");
return 1;
}
const char *path = argv[argi++];
const char **spl_argv = argv + (argi - 1);
int spl_argc = (int)(argc - (argi - 1));
spl_prog_t prog;
if (spl_prog_load_from_file(path, &prog) != 0) {
fprintf(stderr, "spc_vm: cannot load '%s'\n", path);
return 1;
}
spl_syscall_register(&prog);
spl_vm_t vm;
spl_vm_init(&vm);
if (spl_vm_load_prog(&vm, &prog) != 0) {
fprintf(stderr, "vm: prog '%s' not found\n", entry);
spl_prog_drop(&prog);
return 1;
}
if (spl_vm_prepare(&vm, entry, spl_argc, spl_argv, NULL) != 0) {
fprintf(stderr, "vm: entry point '%s' not found\n", entry);
spl_prog_drop(&prog);
return 1;
}
spl_vm_set_trace(&vm, trace);
if (debug_addr)
spl_vm_set_debug(&vm, 1);
int ret = spl_vm_run_until(&vm, 0);
spl_vm_drop(&vm);
spl_prog_drop(&prog);
return (int)vm.exit_code;
}

View File

@@ -1,8 +0,0 @@
/* ===== 模块1核心基础 =====
* test00_basic — 最小程序 / 返回码
* 难度1/5
* 验证点函数定义、整型返回、ret 语句
*/
fn main() i32 {
ret 0;
}

View File

@@ -1,43 +0,0 @@
/* ===== 模块1核心基础 =====
* test01_literals — 全部字面量形式
* 难度1/5
* 验证点:十进制/十六进制/二进制/八进制整数、
* 字符字面量、字符串字面量、布尔字面量、null
*/
fn main() i32 {
/* 整数:十进制 */
var a: i32 = 42;
if a != 42 { ret 1; }
/* 整数:十六进制 */
var b: i32 = 0xFF;
if b != 255 { ret 2; }
/* 整数:二进制 */
var c: i32 = 0b1010;
if c != 10 { ret 3; }
/* 整数:八进制 */
var d: i32 = 0o77;
if d != 63 { ret 4; }
/* 字符字面量 */
var ch: i32 = 'A';
if ch != 65 { ret 5; }
/* 字符转义 */
var nl: i32 = '\n';
if nl != 10 { ret 6; }
/* 布尔字面量 */
var t: bool = true;
if !t { ret 7; }
var f: bool = false;
if f { ret 8; }
/* null 指针 */
var np: *i32 = null;
if np != null { ret 9; }
ret 0;
}

View File

@@ -1,51 +0,0 @@
/* ===== 模块1核心基础 =====
* test02_variables — 变量与常量声明
* 难度1/5
* 验证点var 声明 + 类型注解、var 声明 + 初始化、
* const 声明、var := 短声明、const := 短声明
*/
fn main() i32 {
/* var 带类型注解与初始化 */
var a: i32 = 10;
if a != 10 { ret 1; }
/* var 先声明后赋值 */
var b: i32;
b = 20;
if b != 20 { ret 2; }
/* const 声明 */
const c: i32 = 30;
if c != 30 { ret 3; }
/* var := 短声明(类型推断) */
var d := 40;
if d != 40 { ret 4; }
/* const := 短声明 */
const e := 50;
if e != 50 { ret 5; }
/* 多类型变量 */
var i8v: i8 = 127;
if i8v != 127 { ret 6; }
var u8v: u8 = 255;
if u8v != 255 { ret 7; }
var i16v: i16 = 32767;
if i16v != 32767 { ret 8; }
var u16v: u16 = 65535;
if u16v != 65535 { ret 9; }
var u32v: u32 = 4294967295;
if u32v != 4294967295 { ret 10; }
/* 指针类型变量 */
var x: i32 = 100;
var p: *i32 = &x;
if p == null { ret 11; }
ret 0;
}

View File

@@ -1,56 +0,0 @@
/* ===== 模块2表达式 =====
* test03_arithmetic — 算术运算
* 难度1/5
* 验证点:加、减、乘、除、取模、负数、混合运算优先级
*/
fn main() i32 {
/* 加法 */
var a := 12 + 34;
if a != 46 { ret 1; }
/* 减法 */
var b := 100 - 23;
if b != 77 { ret 2; }
/* 乘法 */
var c := 7 * 8;
if c != 56 { ret 3; }
/* 除法 */
var d := 100 / 3;
if d != 33 { ret 4; }
/* 取模 */
var e := 100 % 3;
if e != 1 { ret 5; }
/* 负数 */
var f := -5;
if f != -5 { ret 6; }
/* 负数运算 */
var g := -10 + 3;
if g != -7 { ret 7; }
/* 运算优先级:乘优先于加 */
var h := 2 + 3 * 4;
if h != 14 { ret 8; }
/* 括号改变优先级 */
var i := (2 + 3) * 4;
if i != 20 { ret 9; }
/* 连续运算 */
var j := 1 + 2 + 3 + 4 + 5;
if j != 15 { ret 10; }
/* 混合运算 */
var k := 10 * 2 - 8 / 4;
if k != 18 { ret 11; }
/* 负数取模 */
var l := -7 % 3;
if l != -1 { ret 12; }
ret 0;
}

View File

@@ -1,66 +0,0 @@
/* ===== 模块2表达式 =====
* test04_operators — 比较/逻辑/位运算 + 短路求值
* 难度2/5
* 验证点:== != < <= > >=、&& || !、& | ^ ~ << >>、&&/|| 短路
*/
fn main() i32 {
/* ---- 比较运算 ---- */
if (1 < 2) {} else { ret 1; }
if (3 > 1) {} else { ret 2; }
if (2 == 2) {} else { ret 3; }
if (2 != 3) {} else { ret 4; }
if (2 <= 2) {} else { ret 5; }
if (2 <= 3) {} else { ret 6; }
if (3 >= 3) {} else { ret 7; }
if (3 >= 2) {} else { ret 8; }
/* 比较结果为 0/1 */
var eq := (42 == 42);
if !eq { ret 9; }
var ne := (42 == 43);
if ne { ret 10; }
var lt := (5 < 10);
if !lt { ret 11; }
/* ---- 逻辑运算 ---- */
if (true) {} else { ret 12; }
if (!false) {} else { ret 13; }
if (true && true) {} else { ret 14; }
if (false || true) {} else { ret 15; }
/* 逻辑非 */
var not_t := !true;
if not_t { ret 16; }
var not_f := !false;
if !not_f { ret 17; }
// /* ---- 短路求值 ---- */
// var short1 := 0;
// var short2 := 0;
// if (false && { short1 = 1; true; }) {} else {}
// if short1 != 0 { ret 18; } /* 右侧未执行 */
/* ---- 位运算 ---- */
var band := 0xFF & 0x0F;
if band != 0x0F { ret 19; }
var bor := 0xF0 | 0x0F;
if bor != 0xFF { ret 20; }
var bxor := 0xFF ^ 0x0F;
if bxor != 0xF0 { ret 21; }
var bnot := ~0xFF;
/* ~0xFF 在 32 位下 = 0xFFFFFF00即 -256 */
if bnot != -256 { ret 22; }
/* 左移 */
var shl := 1 << 3;
if shl != 8 { ret 23; }
/* 右移 */
var shr := 16 >> 2;
if shr != 4 { ret 24; }
ret 0;
}

View File

@@ -1,79 +0,0 @@
/* ===== 模块3控制流 =====
* test05_control — 分支与循环
* 难度2/5
* 验证点if/else、while、loop、break、continue
*/
fn main() i32 {
/* ---- if/else ---- */
var x: i32 = 10;
if x > 5 {
x = 0;
} else {
x = 1;
}
if x != 0 { ret 1; }
/* else 分支 */
var y: i32 = 1;
if y > 5 {
y = 10;
} else {
y = 20;
}
if y != 20 { ret 2; }
/* if 不带 else */
var z: i32 = 0;
if z == 0 {
z = 99;
}
if z != 99 { ret 3; }
/* ---- while ---- */
var i: i32 = 0;
while i < 5 {
i = i + 1;
}
if i != 5 { ret 4; }
/* while 条件为 false */
var j: i32 = 0;
while j > 0 {
j = j + 1;
}
if j != 0 { ret 5; }
/* ---- loop / break ---- */
var k: i32 = 0;
loop {
k = k + 1;
if k >= 3 { break; }
}
if k != 3 { ret 6; }
/* ---- continue ---- */
var n: i32 = 0;
var m: i32 = 0;
while n < 5 {
n = n + 1;
if n == 3 { continue; }
m = m + 1;
}
if n != 5 { ret 7; }
if m != 4 { ret 8; }
/* ---- 嵌套控制流 ---- */
var total: i32 = 0;
var p: i32 = 0;
while p < 3 {
var q: i32 = 0;
while q < 4 {
total = total + 1;
q = q + 1;
}
p = p + 1;
}
if total != 12 { ret 9; }
ret 0;
}

View File

@@ -1,48 +0,0 @@
/* ===== 模块3控制流 =====
* test06_for — for 区间循环
* 难度2/5
* 验证点for begin..end as i、for slice as val、for slice,0.. as val,idx
*/
@extern(vm) fn vm_printf(fmt: *u8, ...) void;
fn main() i32 {
/* for 数值区间for 0..N as i */
var sum: i32 = 0;
for 0..5 as i {
sum = sum + i;
}
/* 0+1+2+3+4 = 10 */
if sum != 10 { ret 1; }
/* for 数值区间:非 0 起始 */
var sum2: i32 = 0;
for 3..7 as i {
sum2 = sum2 + i;
}
/* 3+4+5+6 = 18 */
if sum2 != 18 { ret 2; }
/* for 遍历切片 */
var arr: [4]i32 = [4]i32{10, 20, 30, 40};
var sl: []i32 = arr[0..];
var total: i32 = 0;
for sl as val {
total = total + val;
}
/* 10+20+30+40 = 100 */
if total != 100 { ret 3; }
/* for 遍历切片 + 索引 */
var arr2: [3]i32 = [3]i32{100, 200, 300};
var sl2: []i32 = arr2[0..];
var sum_val: i32 = 0;
var sum_idx: i32 = 0;
for sl2, 0.. as val, idx {
sum_val = sum_val + val;
sum_idx = sum_idx + idx;
}
if sum_val != 600 { ret 4; }
if sum_idx != 3 { ret 5; }
ret 0;
}

View File

@@ -1,64 +0,0 @@
/* ===== 模块4指针 =====
* test07_pointers — 指针操作
* 难度2/5
* 验证点:& 取地址、* 解引用、null 空指针、指针自动解引用(->)、.* 后缀解引用
*/
fn inc(ptr: *i32) void {
*ptr = *ptr + 1;
}
fn main() i32 {
/* ---- & 取地址和 * 解引用 ---- */
var x: i32 = 42;
var p: *i32 = &x;
var v := p.*;
if v != 42 { ret 1; }
/* 通过指针修改 */
p.* = 99;
if x != 99 { ret 2; }
/* 指针作为函数参数 */
var y: i32 = 5;
inc(&y);
if y != 6 { ret 3; }
/* ---- null 空指针 ---- */
var np: *i32 = null;
if np != null { ret 4; }
if np == null {} else { ret 5; }
/* ---- 指针自动解引用ptr.field 相当于 ptr->field ---- */
type Point = struct {
a: i32,
b: i32,
};
var pt: Point;
pt.a = 10;
pt.b = 20;
var pp: *Point = &pt;
if pp.a != 10 { ret 6; }
if pp.b != 20 { ret 7; }
/* 通过指针修改字段 */
pp.a = 30;
if pt.a != 30 { ret 8; }
/* ---- 指向数组元素的指针 ---- */
var buf: [4]i32 = [4]i32{1, 2, 3, 4};
// @dbg(); /* 数组初始化后的栈状态 */
var elem_ptr: *i32 = &buf[0];
// @dbg(); /* &buf[0] 之后:栈上应有指针值 */
var loaded := elem_ptr.*;
// @dbg(); /* 解引用后loaded 值 */
if loaded != 1 { ret 9; }
elem_ptr = &buf[1];
// @dbg(); /* &buf[1] 之后 */
var loaded2 := elem_ptr.*;
// @dbg(); /* 解引用后loaded2 值 */
if loaded2 != 2 { ret 10; }
ret 0;
}

View File

@@ -1,38 +0,0 @@
/* ===== 模块5复合类型 =====
* test08_arrays — 数组
* 难度2/5
* 验证点:数组字面量 [N]T{...}、数组索引、数组元素修改
*/
fn main() i32 {
/* 数组字面量 */
var arr: [3]i32 = [3]i32{1, 2, 3};
if arr[0] != 1 { ret 1; }
if arr[1] != 2 { ret 2; }
if arr[2] != 3 { ret 3; }
/* 数组元素修改 */
arr[1] = 99;
if arr[1] != 99 { ret 4; }
/* 数组求和 */
var nums: [5]i32 = [5]i32{10, 20, 30, 40, 50};
var sum: i32 = 0;
sum = sum + nums[0];
sum = sum + nums[1];
sum = sum + nums[2];
sum = sum + nums[3];
sum = sum + nums[4];
if sum != 150 { ret 5; }
/* 数组通过循环访问while */
var vals: [4]i32 = [4]i32{2, 4, 6, 8};
var i: i32 = 0;
var s: i32 = 0;
while i < 4 {
s = s + vals[i];
i = i + 1;
}
if s != 20 { ret 6; }
ret 0;
}

View File

@@ -1,43 +0,0 @@
/* ===== 模块5复合类型 =====
* test09_slices — 切片
* 难度2/5
* 验证点arr[begin..end] 创建切片、arr[begin..] 到末尾、
* 切片索引访问、slice.len、slice.ptr
*/
fn main() i32 {
/* 从数组创建切片 */
var arr: [5]i32 = [5]i32{10, 20, 30, 40, 50};
var slice: []i32 = arr[1..4];
/* 切片长度 */
if slice.len != 3 { ret 1; }
/* 切片元素访问 */
if slice[0] != 20 { ret 2; }
if slice[1] != 30 { ret 3; }
if slice[2] != 40 { ret 4; }
/* 省略结束值arr[begin..] */
var full: []i32 = arr[0..];
if full.len != 5 { ret 5; }
if full[0] != 10 { ret 6; }
if full[4] != 50 { ret 7; }
/* 从开头到中间 */
var head: []i32 = arr[0..3];
if head.len != 3 { ret 8; }
if head[0] != 10 { ret 9; }
/* 切片遍历(配合 for*/
var nums: [3]i32 = [3]i32{100, 200, 300};
var sl: []i32 = nums[0..];
var total: i32 = 0;
var i: i32 = 0;
while i < sl.len {
total = total + sl[i];
i = i + 1;
}
if total != 600 { ret 10; }
ret 0;
}

View File

@@ -1,215 +0,0 @@
/* ===== 模块5复合类型 =====
* test10_struct — 结构体
* 难度2/5
* 验证点struct 定义、字段访问、内联 type、嵌套结构体
*/
type Pair = struct {
a: i32,
b: i32,
}
type Three = struct {
a: i64,
b: i64,
c: i64,
}
type Tag = enum {
Unknown,
BlockComment,
LineComment,
Ident,
Number,
}
type Token = struct {
loc_start: i32,
loc_end: i32,
tag: Tag,
}
fn make_three(a: i64, b: i64, c: i64) Three {
ret Three { .a = a, .b = b, .c = c };
}
fn sum_three(t: Three) i64 {
ret t.a + t.b + t.c;
}
fn make_token(s: i32, e: i32, t: Tag) Token {
ret Token { .loc_start = s, .loc_end = e, .tag = t };
}
fn test_ret_enum_struct() i32 {
var tok := make_token(10, 20, Tag.BlockComment);
if tok.loc_start != 10 { ret 1; }
if tok.loc_end != 20 { ret 2; }
if tok.tag != Tag.BlockComment { ret 3; }
ret 0;
}
fn test_nested_ret_enum() i32 {
var tok := make_token(1, 5, Tag.Ident);
if tok.tag != Tag.Ident { ret 1; }
var tok2 := make_token(6, 9, Tag.Number);
if tok2.tag != Tag.Number { ret 2; }
if tok.tag != Tag.Ident { ret 3; }
ret 0;
}
fn test_copy_token() i32 {
var tok := make_token(0, 100, Tag.LineComment);
var c := tok;
if c.loc_start != 0 { ret 1; }
if c.tag != Tag.LineComment { ret 2; }
c.tag = Tag.Ident;
if tok.tag != Tag.LineComment { ret 3; }
if c.tag != Tag.Ident { ret 4; }
ret 0;
}
fn test_pass_token(t: Token) i32 {
if t.tag != Tag.Number { ret 1; }
if t.loc_start != 42 { ret 2; }
ret 0;
}
fn test_param_pass_token() i32 {
var tok := make_token(42, 99, Tag.Number);
var r := test_pass_token(tok);
if r != 0 { ret r; }
ret 0;
}
fn test_get_tag(tok: Token) Tag {
ret tok.tag;
}
fn test_chain_func_call() i32 {
var tok := make_token(1, 2, Tag.BlockComment);
var tg := test_get_tag(tok);
if tg != Tag.BlockComment { ret 1; }
var tok2 := make_token(3, 4, Tag.LineComment);
var tg2 := test_get_tag(tok2);
if tg2 != Tag.LineComment { ret 2; }
ret 0;
}
fn test_ret_multi_slot_struct() i32 {
var t := make_three(10, 20, 30);
if t.a != 10 { ret 1; }
if t.b != 20 { ret 2; }
if t.c != 30 { ret 3; }
ret 0;
}
fn test_pass_struct_by_value() i32 {
var t := make_three(10, 20, 30);
var sum := sum_three(t);
if sum != 60 { ret 1; }
ret 0;
}
fn test_copy_struct() i32 {
var t := make_three(10, 20, 30);
var t2: Three;
t2 = t;
if t2.a != 10 { ret 1; }
t2.a = 99;
if t.a != 10 { ret 2; }
if t2.a != 99 { ret 3; }
ret 0;
}
fn test_multi_calls() i32 {
var ta := make_three(5, 10, 15);
var tb := make_three(20, 25, 30);
if ta.a + ta.b + ta.c != 30 { ret 1; }
if tb.a + tb.b + tb.c != 75 { ret 2; }
ret 0;
}
fn test_literal_arg() i32 {
var sum := sum_three(Three { .a = 7, .b = 8, .c = 9 });
if sum != 24 { ret 1; }
ret 0;
}
fn main() i32 {
/* struct 字段访问 */
var p: Pair;
p.a = 1;
p.b = 2;
if p.a != 1 { ret 1; }
if p.b != 2 { ret 2; }
/* 同一类型复用 */
var p2: Pair;
p2.a = 10;
p2.b = 20;
if p2.a + p2.b != 30 { ret 3; }
/* 不影响其他实例 */
if p.a != 1 { ret 4; }
/* 内联 type 定义(在函数内) */
type Triple = struct {
x: i32,
y: i32,
z: i32,
}
var t: Triple;
t.x = 5;
t.y = 10;
t.z = 15;
if t.x + t.y + t.z != 30 { ret 5; }
/* 结构体字段运算 */
var calc: Pair;
calc.a = 7;
calc.b = 3;
var r := calc.a * calc.b + calc.a - calc.b;
if r != 25 { ret 6; }
/* 结构体嵌套 */
type Outer = struct {
inner: Inner,
extra: i32,
type Inner = struct {
val: i32,
}
}
var o: Outer;
o.inner.val = 42;
o.extra = 58;
if o.inner.val != 42 { ret 7; }
if o.extra != 58 { ret 8; }
/* 多 slot 结构体返回值测试 */
var r9 := test_ret_multi_slot_struct();
if r9 != 0 { ret 100; }
var r10 := test_pass_struct_by_value();
if r10 != 0 { ret 101; }
var r11 := test_copy_struct();
if r11 != 0 { ret 102; }
var r12 := test_multi_calls();
if r12 != 0 { ret 103; }
var r13 := test_literal_arg();
if r13 != 0 { ret 104; }
/* 含 enum 字段的结构体返回值测试 */
var r14 := test_ret_enum_struct();
if r14 != 0 { ret 110; }
var r15 := test_nested_ret_enum();
if r15 != 0 { ret 111; }
var r16 := test_copy_token();
if r16 != 0 { ret 112; }
var r17 := test_param_pass_token();
if r17 != 0 { ret 113; }
var r18 := test_chain_func_call();
if r18 != 0 { ret 114; }
ret 0;
}

View File

@@ -1,29 +0,0 @@
/* ===== 模块5复合类型 =====
* test11_enum — 枚举
* 难度3/5
* 验证点enum 定义、简单枚举值、带数据枚举变体
*/
@extern(vm) fn vm_printf(fmt: *u8, ...) void;
type Color = enum {
Red,
Green,
Blue,
}
type Expr = enum {
val: i32,
tag: Tag,
type Tag = enum {
TagA,
TagB,
TagC,
}
}
fn main() i32 {
vm_printf("enum values: %d %d %d\n", Color.Red, Color.Green, Color.Blue);
vm_printf("enum values: %d %d %d\n", Expr.Tag.TagA, Expr.Tag.TagB, Expr.Tag.TagC);
ret 0;
}

View File

@@ -1,55 +0,0 @@
/* ===== 模块6函数 =====
* test12_functions — 函数调用
* 难度2/5
* 验证点:函数定义与调用、参数传递、返回值、多个参数
*/
fn add(a: i32, b: i32) i32 {
ret a + b;
}
fn sub(a: i32, b: i32) i32 {
ret a - b;
}
fn mul(a: i32, b: i32) i32 {
ret a * b;
}
fn identity(x: i32) i32 {
ret x;
}
fn addr(x: *i32) *i32 {
ret x;
}
fn main() i32 {
/* 函数调用 */
var r1 := add(3, 4);
if r1 != 7 { ret 1; }
var r2 := sub(10, 3);
if r2 != 7 { ret 2; }
var r3 := mul(6, 7);
if r3 != 42 { ret 3; }
/* 函数嵌套调用 */
var r4 := add(mul(2, 3), sub(10, 4));
if r4 != 12 { ret 4; }
/* 函数返回值的传递 */
var r5 := identity(99);
if r5 != 99 { ret 5; }
/* 多个参数 */
var r6 := add(add(1, 2), add(3, 4));
if r6 != 10 { ret 6; }
/* 返回地址 */
var r7 := addr(&r6);
if r7 != &r6 { ret 7; }
if r7.* != 10 { ret 8; }
ret 0;
}

View File

@@ -1,35 +0,0 @@
/* ===== 模块6函数 =====
* test13_extern — 外部 VM 函数与字符串
* 难度2/5
* 验证点:@extern(vm) 声明、vm_printf 调用、
* 字符串字面量、字符串参数传递
*/
@extern(vm) fn vm_printf(fmt: *u8, ...) void;
@extern(vm) fn vm_strlen(s: *u8) i32;
@extern(vm) fn vm_strcmp(a: *u8, b: *u8) i32;
fn main() i32 {
/* vm_printf 输出测试 */
vm_printf("hello spl\n");
vm_printf("%d %d %d\n", 1, 2, 3);
vm_printf("chars: %c%c\n", 'A', 'B');
/* 字符串字面量用于 extern */
var len := vm_strlen("hello");
if len != 5 { ret 1; }
/* 字符串比较 */
var cmp := vm_strcmp("abc", "abc");
if cmp != 0 { ret 2; }
var cmp2 := vm_strcmp("abc", "def");
if cmp2 == 0 { ret 3; }
/* 字符串作为格式化参数 */
vm_printf("string test: %s %s\n", "foo", "bar");
/* vm_printf 返回 void不关心返回值*/
vm_printf("all extern tests done\n");
ret 0;
}

View File

@@ -1,56 +0,0 @@
/* ===== 模块7高级特性 =====
* test14_assignment — 复合赋值
* 难度2/5
* 验证点:+= -= *= /= %= &= |= ^= <<= >>=
*/
fn main() i32 {
var x: i32 = 10;
/* += */
x += 5;
if x != 15 { ret 1; }
/* -= */
x -= 3;
if x != 12 { ret 2; }
/* *= */
x *= 2;
if x != 24 { ret 3; }
/* /= */
x /= 4;
if x != 6 { ret 4; }
/* %= */
var y: i32 = 17;
y %= 5;
if y != 2 { ret 5; }
/* &= */
var a: i32 = 0xFF;
a &= 0x0F;
if a != 0x0F { ret 6; }
/* |= */
var b: i32 = 0xF0;
b |= 0x0F;
if b != 0xFF { ret 7; }
/* ^= */
var c: i32 = 0xFF;
c ^= 0xF0;
if c != 0x0F { ret 8; }
/* <<= */
var d: i32 = 1;
d <<= 4;
if d != 16 { ret 9; }
/* >>= */
var e: i32 = 64;
e >>= 3;
if e != 8 { ret 10; }
ret 0;
}

View File

@@ -1,45 +0,0 @@
/* ===== 模块7高级特性 =====
* test15_defer — 延迟执行
* 难度3/5
* 验证点defer 语句、defer 块、多个 defer逆序执行
* 函数中 defer、块作用域 defer
*/
@extern(vm) fn vm_printf(fmt: *u8, ...) void;
fn with_cleanup() void {
defer vm_printf(" inner defer\n");
vm_printf(" inside with_cleanup\n");
}
fn main() i32 {
vm_printf("--- defer test ---\n");
/* defer 语句 */
defer vm_printf("defer1\n");
vm_printf("after defer1\n");
/* defer 块 */
defer {
vm_printf("defer block\n");
}
vm_printf("after defer block\n");
/* 函数内 defer */
with_cleanup();
vm_printf("after with_cleanup\n");
/* 多个 defer 应逆序执行出作用域应该立刻执行,包括循环作用域 */
{
defer vm_printf("block defer last\n");
defer vm_printf("block defer middle\n");
defer vm_printf("block defer first (should print third)\n");
}
/* 多个 defer 应逆序执行 */
defer vm_printf("defer last\n");
defer vm_printf("defer middle\n");
defer vm_printf("defer first (should print third)\n");
vm_printf("--- defer test end ---\n");
ret 0;
}

View File

@@ -1,48 +0,0 @@
/* ===== 模块7高级特性 =====
* test16_methods — 类型关联方法
* 难度3/5
* 验证点struct 方法、enum 方法、self 参数自动填充、方法调用
*/
@extern(vm) fn vm_printf(fmt: *u8, ...) void;
type Point = struct {
x: i32,
y: i32,
fn init(x: i32, y: i32) Point {
ret Point { .x = x, .y = y };
}
fn dump(self: *Point) void {
vm_printf("Point(%d, %d)\n", self.x, self.y);
}
}
type Expr = enum {
Int: i32,
Add: struct { left: *Expr, right: *Expr },
fn eval(self: *Expr) i32 {
match self {
.Int[val] => { ret val; },
.Add[sub] => { ret eval(sub.left) + eval(sub.right); }
}
ret 0;
}
}
fn main() i32 {
/* struct 方法调用 */
var p: Point = Point.init(3, 4);
p.dump(&p);
/* enum 方法 + match */
var expr_l := Expr { .Int = 3 };
var expr_r := Expr { .Int = 4 };
var expr := Expr { .Add = .{ .left = expr_l, .right = expr_r } };
var result := expr.eval(&expr);
vm_printf("eval result: %d\n", result);
if result != 7 { ret 1; }
ret 0;
}

View File

@@ -1,95 +0,0 @@
/* ===== 模块8综合 =====
* test17_integration — 综合测试
* 难度3/5
* 验证点:多特性组合——指针 + 结构体 + 函数 + 循环 + 数组 + 切片
*/
@extern(vm) fn vm_printf(fmt: *u8, ...) void;
type Point = struct {
x: i32,
y: i32,
}
/* 计算点积 */
fn dot(a: *Point, b: *Point) i32 {
ret a.x * b.x + a.y * b.y;
}
/* 递归斐波那契 */
fn fib(n: i32) i32 {
if n <= 1 { ret n; }
ret fib(n - 1) + fib(n - 2);
}
fn main() i32 {
/* 综合:指针 + 结构体 + 函数 */
var p1: Point;
p1.x = 3;
p1.y = 4;
var p2: Point;
p2.x = 5;
p2.y = 6;
var d := dot(&p1, &p2);
/* 3*5 + 4*6 = 15 + 24 = 39 */
if d != 39 { ret 1; }
/* 综合:数组 + while 循环 */
var arr: [5]i32 = [5]i32{1, 2, 3, 4, 5};
var sum: i32 = 0;
var i: i32 = 0;
while i < 5 {
sum = sum + arr[i];
i = i + 1;
}
if sum != 15 { ret 2; }
/* 综合:切片 + for */
var sl: []i32 = arr[1..4];
var sl_sum: i32 = 0;
for sl as val {
sl_sum = sl_sum + val;
}
if sl_sum != 9 { ret 3; } /* 2+3+4 */
/* 综合:递归 */
var f := fib(10);
if f != 55 { ret 4; }
/* 综合loop/break/continue */
var n: i32 = 0;
var count: i32 = 0;
loop {
n = n + 1;
if n == 2 { continue; }
count = count + 1;
if n >= 5 { break; }
}
/* 执行 n=1,3,4,5 共 4 次 (n=2 被 continue) */
if count != 4 { ret 5; }
/* 综合:指针修改结构体 */
var pp: *Point = &p1;
pp.x = 10;
pp.y = 20;
if p1.x != 10 { ret 6; }
if p1.y != 20 { ret 7; }
/* 综合:嵌套控制流 */
var mat: [3]i32 = [3]i32{1, 2, 3};
var outer_sum: i32 = 0;
var j: i32 = 0;
while j < 3 {
var k: i32 = 0;
while k < 3 {
if mat[j] > mat[k] {
outer_sum = outer_sum + 1;
}
k = k + 1;
}
j = j + 1;
}
if outer_sum != 3 { ret 8; }
ret 0;
}

View File

@@ -1,488 +0,0 @@
/* ===== 模块4match 语句 =====
* test18_match — match 枚举匹配 + 整数匹配(类似 switch
* 难度3/5
* 验证点:枚举匹配、带数据绑定、结构体字段绑定、枚举指针、
* 整数自变量匹配、默认分支 _
*/
/* ---- 简单枚举(无数据) ---- */
type Color = enum {
Red;
Green;
Blue;
}
/* ---- 带 i32 数据的枚举 ---- */
type Optional = enum {
Some: i32;
None;
}
/* ---- 带结构体数据的枚举 ---- */
type Point = struct {
var x: i32;
var y: i32;
}
type Shape = enum {
Circle: i32;
Rect: Point;
}
/* ---- 多变体枚举 ---- */
type ActionResult = enum {
Success: i32;
NotFound;
Timeout: i32;
Error: *u8;
}
/* ============================================================
* 测试 1: 无数据枚举匹配
* ============================================================ */
fn test_color_match() i32 {
var c: Color = Color { .Red };
var val: i32 = 0;
match c {
.Red => { val = 1; },
.Green => { val = 2; },
.Blue => { val = 3; }
}
if val != 1 { ret 1; }
c = Color { .Green };
match c {
.Red => { val = 0; },
.Green => { val = 2; },
.Blue => { val = 0; }
}
if val != 2 { ret 2; }
c = Color { .Blue };
match c {
.Red => { val = 0; },
.Green => { val = 0; },
.Blue => { val = 3; }
}
if val != 3 { ret 3; }
ret 0;
}
/* ============================================================
* 测试 2: 带 i32 数据枚举匹配
* ============================================================ */
fn test_optional_match() i32 {
var o: Optional = Optional { .Some = 42 };
match o {
.Some[val] => {
if val != 42 { ret 1; }
},
.None => {
ret 2;
}
}
o = Optional { .None };
var is_none: i32 = 0;
match o {
.Some[val] => {},
.None => { is_none = 1; }
}
if is_none != 1 { ret 3; }
/* 多次提取不同值 */
o = Optional { .Some = 99 };
match o {
.Some[val] => {
if val != 99 { ret 4; }
},
.None => { ret 5; }
}
ret 0;
}
/* ============================================================
* 测试 3: 带结构体数据枚举匹配(多字段绑定)
* ============================================================ */
fn test_shape_match() i32 {
/* Circle: 单数据 */
var s: Shape = Shape { .Circle = 10 };
match s {
.Circle[r] => {
if r != 10 { ret 1; }
},
.Rect[p] => {
ret 2;
}
}
/* Rect: 结构体数据,绑定为 (x, y) 对应 Point 的字段 */
s = Shape { .Rect = Point { .x = 3, .y = 4 } };
match s {
.Circle[r] => { ret 3; },
.Rect[p] => {
if p.x != 3 { ret 4; }
if p.y != 4 { ret 5; }
}
}
ret 0;
}
/* ============================================================
* 测试 4: 多数据变体枚举匹配
* ============================================================ */
fn test_action_result_match() i32 {
var r: ActionResult = ActionResult { .Success = 200 };
match r {
.Success[code] => {
if code != 200 { ret 1; }
},
.NotFound => {
ret 2;
},
.Timeout[ms] => {
ret 3;
},
.Error[msg] => {
ret 4;
}
}
r = ActionResult { .NotFound };
var found: i32 = 1;
match r {
.Success[code] => { found = 0; },
.NotFound => { },
.Timeout[ms] => { found = 0; },
.Error[msg] => { found = 0; }
}
if found != 1 { ret 5; }
r = ActionResult { .Timeout = 5000 };
match r {
.Success[code] => { ret 6; },
.NotFound => { ret 7; },
.Timeout[ms] => {
if ms != 5000 { ret 8; }
},
.Error[msg] => { ret 9; }
}
ret 0;
}
/* ============================================================
* 测试 5: 枚举指针匹配
* ============================================================ */
fn test_ptr_match() i32 {
var c: Color = Color { .Green };
var p: *Color = &c;
match p {
.Red => { ret 1; },
.Green => { },
.Blue => { ret 2; }
}
/* 修改后通过指针匹配 */
c = Color { .Blue };
match p {
.Red => { ret 3; },
.Green => { ret 4; },
.Blue => { }
}
ret 0;
}
/* ============================================================
* 测试 6: match 作为函数返回值
* ============================================================ */
fn classify_color(c: Color) i32 {
match c {
.Red => { ret 1; },
.Green => { ret 2; },
.Blue => { ret 3; }
}
ret 0;
}
fn test_match_in_func() i32 {
var r: i32;
r = classify_color(Color { .Red });
if r != 1 { ret 1; }
r = classify_color(Color { .Green });
if r != 2 { ret 2; }
r = classify_color(Color { .Blue });
if r != 3 { ret 3; }
ret 0;
}
/* ============================================================
* 测试 7: match 嵌套在循环中
* ============================================================ */
fn test_match_in_loop() i32 {
var i: i32 = 0;
var sum: i32 = 0;
while i < 3 {
var o: Optional;
if i == 0 {
o = Optional { .Some = 10 };
} else if i == 1 {
o = Optional { .Some = 20 };
} else {
o = Optional { .Some = 30 };
}
match o {
.Some[val] => {
sum = sum + val;
},
.None => { }
}
i = i + 1;
}
if sum != 60 { ret 1; }
ret 0;
}
/* ============================================================
* 测试 8: 整数 match类似 switch
* ============================================================ */
fn test_int_match() i32 {
var x: i32 = 2;
var result: i32 = 0;
match x {
1 => { result = 10; },
2 => { result = 20; },
3 => { result = 30; }
}
if result != 20 { ret 1; }
/* 匹配第一个值 */
x = 1;
match x {
1 => { result = 100; },
2 => { result = 200; },
3 => { result = 300; }
}
if result != 100 { ret 2; }
/* 匹配最后一个值 */
x = 3;
match x {
1 => { result = 1000; },
2 => { result = 2000; },
3 => { result = 3000; }
}
if result != 3000 { ret 3; }
ret 0;
}
/* ============================================================
* 测试 9: 整数 match 带默认分支 _
* ============================================================ */
fn test_int_match_default() i32 {
var x: i32 = 99;
var result: i32 = 0;
match x {
1 => { result = 1; },
2 => { result = 2; },
_ => { result = 99; }
}
if result != 99 { ret 1; }
/* 默认分支未触发 */
x = 1;
match x {
1 => { result = 1; },
2 => { result = 2; },
_ => { result = 99; }
}
if result != 1 { ret 2; }
ret 0;
}
/* ============================================================
* 测试 10: 整数 match 多个值跳转到相同逻辑
* ============================================================ */
fn test_int_match_multi() i32 {
var x: i32 = 2;
var result: i32 = 0;
/* 每个分支独立 */
match x {
0 => { result = 0; },
1 => { result = 1; },
2 => { result = 2; },
3 => { result = 3; }
}
if result != 2 { ret 1; }
/* 负数和零 */
x = -1;
match x {
-1 => { result = -1; },
0 => { result = 0; },
1 => { result = 1; }
}
if result != -1 { ret 2; }
x = 0;
match x {
-1 => { result = -1; },
0 => { result = 0; },
1 => { result = 1; }
}
if result != 0 { ret 3; }
ret 0;
}
/* ============================================================
* 测试 11a: match 多值 fallthrough: 1, 2, 3 => body
* ============================================================ */
fn test_int_match_fallthrough() i32 {
var x: i32;
var r: i32;
/* 三个值映射到同一个 body */
x = 1; r = 0;
match x {
1, 2, 3 => { r = 10; },
4, 5 => { r = 20; }
}
if r != 10 { ret 1; }
x = 3;
match x {
1, 2, 3 => { r = 10; },
4, 5 => { r = 20; }
}
if r != 10 { ret 2; }
x = 5;
match x {
1, 2, 3 => { r = 10; },
4, 5 => { r = 20; }
}
if r != 20 { ret 3; }
/* 单一值(非fallthrough)仍然正常 */
x = 7; r = 0;
match x {
1 => { r = 1; },
7 => { r = 7; }
}
if r != 7 { ret 4; }
/* 多个负数值 */
x = -2; r = 0;
match x {
-3, -2, -1 => { r = 100; },
0, 1 => { r = 200; }
}
if r != 100 { ret 5; }
ret 0;
}
/* ============================================================
* 测试 11b: match with body 中修改变量
* ============================================================ */
fn test_match_with_side_effects() i32 {
var x: i32 = 3;
var acc: i32 = 0;
match x {
1 => { acc = acc + 1; },
2 => { acc = acc + 2; },
3 => { acc = acc + 3; },
4 => { acc = acc + 4; }
}
if acc != 3 { ret 1; }
/* 再次 match 同一个变量 */
match x {
1 => { acc = acc + 1; },
2 => { acc = acc + 2; },
3 => { acc = acc + 3; },
4 => { acc = acc + 4; }
}
if acc != 6 { ret 2; }
ret 0;
}
/* ============================================================
* 主函数
* ============================================================ */
fn main() i32 {
var r: i32;
r = test_color_match();
if r != 0 { ret r; }
r = test_optional_match();
if r != 0 { ret r + 10; }
r = test_shape_match();
if r != 0 { ret r + 20; }
r = test_action_result_match();
if r != 0 { ret r + 30; }
r = test_ptr_match();
if r != 0 { ret r + 40; }
r = test_match_in_func();
if r != 0 { ret r + 50; }
r = test_match_in_loop();
if r != 0 { ret r + 60; }
r = test_int_match();
if r != 0 { ret r + 70; }
r = test_int_match_default();
if r != 0 { ret r + 80; }
r = test_int_match_multi();
if r != 0 { ret r + 90; }
r = test_match_with_side_effects();
if r != 0 { ret r + 100; }
r = test_int_match_fallthrough();
if r != 0 { ret r + 110; }
ret 0;
}

View File

@@ -1,184 +0,0 @@
/* ===== 进阶数组与切片 =====
* test19_hardarray — 多维数组、多维切片、切片构造、字符串测试
* 难度4/5
* 验证点:多维数组索引与修改、多维切片、切片字段读写、扁平指针访问、字符串切片
*/
fn test_string() i32 {
/* ============================
* String test: str is []u8
* ============================ */
var data: *u8 = "hello";
var s: []u8 = .{ .ptr = data, .len = 5 };
if s.len != 5 { ret 100; }
if s[0] != 104 { ret 101; } /* 'h' */
if s[1] != 101 { ret 102; } /* 'e' */
if s[4] != 111 { ret 103; } /* 'o' */
/* Slice the string slice */
var sub: []u8 = s[1..4];
if sub.len != 3 { ret 104; }
if sub[0] != 101 { ret 105; } /* 'e' */
if sub[2] != 108 { ret 106; } /* 'l' */
/* Modify through slice → original changes */
s[0] = 72; /* 'H' */
if data[0] != 72 { ret 107; }
/* Full slice */
var full: []u8 = s[0..];
if full.len != 5 { ret 108; }
if full[0] != 72 { ret 109; }
/* Construct slice from pointer via field assignment */
var s2: []u8;
s2.ptr = data;
s2.len = 3;
if s2.len != 3 { ret 110; }
if s2[0] != 72 { ret 111; }
ret 0;
}
fn main() i32 {
/* ============================
* Part 1: 多维数组(逐元素初始化)
* ============================ */
var matrix: [2][3]i32;
matrix[0][0] = 1; matrix[0][1] = 2; matrix[0][2] = 3;
matrix[1][0] = 4; matrix[1][1] = 5; matrix[1][2] = 6;
if matrix[0][0] != 1 { ret 1; }
if matrix[0][1] != 2 { ret 2; }
if matrix[0][2] != 3 { ret 3; }
if matrix[1][0] != 4 { ret 4; }
if matrix[1][1] != 5 { ret 5; }
if matrix[1][2] != 6 { ret 6; }
/* 元素修改 */
matrix[0][0] = 10;
matrix[1][2] = 60;
if matrix[0][0] != 10 { ret 7; }
if matrix[1][2] != 60 { ret 8; }
/* ============================
* Part 2: 嵌套循环遍历多维数组
* ============================ */
var big: [3][4]i32;
big[0][0] = 1; big[0][1] = 2; big[0][2] = 3; big[0][3] = 4;
big[1][0] = 5; big[1][1] = 6; big[1][2] = 7; big[1][3] = 8;
big[2][0] = 9; big[2][1] = 10; big[2][2] = 11; big[2][3] = 12;
var total: i32 = 0;
var i: i32 = 0;
while i < 3 {
var j: i32 = 0;
while j < 4 {
total = total + big[i][j];
j = j + 1;
}
i = i + 1;
}
if total != 78 { ret 9; }
/* ============================
* Part 3: &取地址 + 扁平指针访问
* ============================ */
var flat: *i32 = &matrix[0][0];
if flat[0] != 10 { ret 10; }
if flat[1] != 2 { ret 11; }
if flat[2] != 3 { ret 12; }
if flat[3] != 4 { ret 13; }
if flat[4] != 5 { ret 14; }
if flat[5] != 60 { ret 15; }
/* ============================
* Part 4: 多维数组切片
* ============================ */
var row: []i32 = matrix[0][0..3];
if row.len != 3 { ret 16; }
if row[0] != 10 { ret 17; }
if row[1] != 2 { ret 18; }
if row[2] != 3 { ret 19; }
/* 切取第二行 */
var row2: []i32 = matrix[1][0..];
if row2.len != 3 { ret 20; }
if row2[0] != 4 { ret 21; }
if row2[2] != 60 { ret 22; }
/* ============================
* Part 5: 切片的切片
* ============================ */
var sub: []i32 = row[1..3];
if sub.len != 2 { ret 23; }
if sub[0] != 2 { ret 24; }
if sub[1] != 3 { ret 25; }
/* ============================
* Part 6: 切片字段读写
* ============================ */
var arr: [4]i32;
arr[0] = 100; arr[1] = 200; arr[2] = 300; arr[3] = 400;
var custom: []i32;
custom.ptr = &arr[1];
custom.len = 2;
if custom.len != 2 { ret 26; }
if custom[0] != 200 { ret 27; }
if custom[1] != 300 { ret 28; }
/* 修改切片长度 */
custom.len = 3;
if custom.len != 3 { ret 29; }
if custom[2] != 400 { ret 30; }
/* ============================
* Part 7: 空范围 / 全切片
* ============================ */
var full: []i32 = arr[0..];
if full.len != 4 { ret 31; }
if full[0] != 100 { ret 32; }
if full[3] != 400 { ret 33; }
/* ============================
* Part 8: 从指针构造切片
* ============================ */
var data: [5]i32;
data[0] = 10; data[1] = 20; data[2] = 30; data[3] = 40; data[4] = 50;
var p: *i32 = &data[2];
var from_ptr: []i32 = .{ .ptr = p, .len = 2 };
var from_ptr2: []i32;
from_ptr2.ptr = p;
from_ptr2.len = 2;
if from_ptr.len != 2 { ret 34; }
if from_ptr[0] != 30 { ret 35; }
if from_ptr[1] != 40 { ret 36; }
if from_ptr2.len != 2 { ret 37; }
if from_ptr2[0] != 30 { ret 38; }
if from_ptr2[1] != 40 { ret 39; }
/* ============================
* Part 9: 切片元素修改反映到原始数组
* ============================ */
row2[0] = 99;
if matrix[1][0] != 99 { ret 40; }
/* ============================
* Part 10: 1D 数组字面量仍然正常
* ============================ */
var literal: [3]i32 = [3]i32{10, 20, 30};
if literal[0] != 10 { ret 41; }
if literal[1] != 20 { ret 42; }
if literal[2] != 30 { ret 43; }
/* ============================
* Part 11: 字符串切片测试
* ============================ */
var r: i32 = test_string();
if r != 0 { ret r; }
ret 0;
}

View File

@@ -1,320 +0,0 @@
/* ===== 复杂类型嵌套综合测试 =====
* test20_complex — 结构体嵌套、切片、数组、方法、类型别名、枚举等
* 难度5/5
*/
/* ---- 基础结构体 ---- */
type Point = struct {
var x: i32;
var y: i32;
}
/* ---- 嵌套结构体 ---- */
type Rect = struct {
var min: Point;
var max: Point;
}
/* ---- 含切片字段的结构体 (核心 bug 测试) ---- */
type Buffer = struct {
var data: []u8;
var len: usize;
}
/* ---- 含数组字段的结构体 ---- */
type MatrixRow = struct {
var items: [4]i32;
}
/* ---- 含指针字段的结构体 ---- */
type Node = struct {
var ptr: *i32;
var val: i32;
}
/* ---- 多层级嵌套:结构体里的结构体里的切片 ---- */
type Bundle = struct {
var name: *u8;
var buf: Buffer;
var row: MatrixRow;
var pt: Point;
}
/* ---- 枚举含数据 ---- */
type Status = enum {
Active: i32;
Inactive;
Pending: Point;
}
/* ---- 含方法的结构体 (方法定义在结构体内部) ---- */
type Counter = struct {
var val: i32;
fn inc(self: *Counter) i32 {
self.val = self.val + 1;
ret self.val;
}
fn add(self: *Counter, n: i32) i32 {
self.val = self.val + n;
ret self.val;
}
fn reset(self: *Counter) {
self.val = 0;
}
fn get(self: *Counter) i32 {
ret self.val;
}
}
/* ============================================================
* 测试 1: 切片在结构体内部初始化 (修复的核心 bug)
* ============================================================ */
fn test_slice_in_struct() i32 {
var raw: [4]u8;
raw[0] = 65; raw[1] = 66; raw[2] = 67; raw[3] = 68;
/* Bug fix: { .ptr = ..., .len = ... } inside struct literal */
var b: Buffer = Buffer { .data = .{ .ptr = &raw[0], .len = 4 }, .len = 4 };
if b.len != 4 { ret 1; }
if b.data[0] != 65 { ret 2; }
if b.data[1] != 66 { ret 3; }
if b.data[3] != 68 { ret 4; }
/* Modify through slice — verify reflection */
b.data[0] = 90;
if raw[0] != 90 { ret 5; }
/* Initialize with shorter slice */
var b2: Buffer = Buffer { .data = .{ .ptr = &raw[2], .len = 2 }, .len = 2 };
if b2.len != 2 { ret 6; }
if b2.data[0] != 67 { ret 7; }
/* Slice field assignment via field access */
b2.data.ptr = &raw[0];
b2.data.len = 4;
if b2.data[0] != 90 { ret 8; }
if b2.data.len != 4 { ret 9; }
ret 0;
}
/* ============================================================
* 测试 2: 结构体含数组字段
* ============================================================ */
fn test_struct_with_array() i32 {
var mr: MatrixRow = MatrixRow { .items = [4]i32{10, 20, 30, 40} };
if mr.items[0] != 10 { ret 1; }
if mr.items[1] != 20 { ret 2; }
if mr.items[2] != 30 { ret 3; }
if mr.items[3] != 40 { ret 4; }
/* 修改数组元素 */
mr.items[2] = 99;
if mr.items[2] != 99 { ret 5; }
ret 0;
}
/* ============================================================
* 测试 3: 嵌套结构体初始化
* ============================================================ */
fn test_nested_struct() i32 {
var p: Point = Point { .x = 5, .y = 10 };
if p.x != 5 { ret 1; }
if p.y != 10 { ret 2; }
/* 嵌套结构体字面量 */
var r: Rect = Rect {
.min = Point { .x = 1, .y = 2 },
.max = Point { .x = 3, .y = 4 }
};
if r.min.x != 1 { ret 3; }
if r.min.y != 2 { ret 4; }
if r.max.x != 3 { ret 5; }
if r.max.y != 4 { ret 6; }
/* 修改嵌套字段 */
r.min.x = 100;
if r.min.x != 100 { ret 7; }
if r.min.y != 2 { ret 8; } /* unchanged */
ret 0;
}
/* ============================================================
* 测试 4: 结构体成员方法 (实例方法调用)
* ============================================================ */
fn test_struct_method() i32 {
var c: Counter = Counter { .val = 0 };
/* 实例方法调用 c.inc(&c) */
var r1: i32 = c.inc(&c);
if r1 != 1 { ret 1; }
if c.val != 1 { ret 2; }
/* 带参数方法调用 c.add(&c, n) */
var r2: i32 = c.add(&c, 5);
if r2 != 6 { ret 3; }
if c.val != 6 { ret 4; }
/* 连续调用 (显式 self) */
c.reset(&c);
if c.val != 0 { ret 5; }
c.add(&c, 10);
c.inc(&c);
var r3: i32 = c.get(&c);
if r3 != 11 { ret 6; }
ret 0;
}
/* ============================================================
* 测试 5: 结构体含指针字段
* ============================================================ */
fn test_ptr_in_struct() i32 {
var v: i32 = 42;
var n: Node = Node { .ptr = &v, .val = 99 };
if n.val != 99 { ret 1; }
if n.ptr[0] != 42 { ret 2; }
/* 通过指针修改 */
v = 100;
if n.ptr[0] != 100 { ret 3; }
/* 通过指针在结构体内修改 */
n.ptr[0] = 200;
if v != 200 { ret 4; }
ret 0;
}
/* ============================================================
* 测试 6: 多层级复杂嵌套
* ============================================================ */
fn test_complex_nesting() i32 {
var str_data: [5]u8;
str_data[0] = 72; str_data[1] = 101;
str_data[2] = 108; str_data[3] = 108; str_data[4] = 111;
var bundle: Bundle = Bundle {
.name = &str_data[0],
.buf = Buffer { .data = .{ .ptr = &str_data[1], .len = 3 }, .len = 3 },
.row = MatrixRow { .items = [4]i32{1, 2, 3, 4} },
.pt = Point { .x = -5, .y = 15 }
};
/* Verify name */
if bundle.name[0] != 72 { ret 1; }
if bundle.name[4] != 111 { ret 2; }
/* Verify nested slice */
if bundle.buf.len != 3 { ret 3; }
if bundle.buf.data[0] != 101 { ret 4; }
if bundle.buf.data[2] != 108 { ret 5; }
/* Verify array field */
if bundle.row.items[0] != 1 { ret 6; }
if bundle.row.items[3] != 4 { ret 7; }
/* Verify nested struct field */
if bundle.pt.x != -5 { ret 8; }
if bundle.pt.y != 15 { ret 9; }
/* Modify nested slice */
bundle.buf.data[1] = 87; /* 'W' */
if str_data[2] != 87 { ret 10; }
/* Modify nested array */
bundle.row.items[2] = 33;
if bundle.row.items[2] != 33 { ret 11; }
ret 0;
}
/* ============================================================
* 测试 7: 枚举含结构体数据
* ============================================================ */
fn test_enum_complex() i32 {
var s: Status = Status { .Active = 42 };
/* Verify active variant */
match s {
.Active[val] => {
if val != 42 { ret 1; }
},
.Inactive => {
ret 2;
},
.Pending[p] => {
ret 3;
}
}
/* Test Inactive variant */
var s2: Status = Status { .Inactive };
var is_inactive: i32 = 0;
match s2 {
.Active[val] => {},
.Inactive => { is_inactive = 1; },
.Pending[p] => {}
}
if is_inactive != 1 { ret 4; }
/* Test Pending variant with struct data */
var s3: Status = Status { .Pending = Point { .x = 7, .y = 8 } };
match s3 {
.Active[val] => { ret 5; },
.Inactive => { ret 6; },
.Pending[p] => {
if p.x != 7 { ret 7; }
if p.y != 8 { ret 8; }
}
}
ret 0;
}
/* ============================================================
* 主函数
* ============================================================ */
fn main() i32 {
var r: i32;
r = test_slice_in_struct();
if r != 0 { ret r; }
r = test_struct_with_array();
if r != 0 { ret r + 100; }
r = test_nested_struct();
if r != 0 { ret r + 200; }
r = test_struct_method();
if r != 0 { ret r + 300; }
r = test_ptr_in_struct();
if r != 0 { ret r + 400; }
r = test_complex_nesting();
if r != 0 { ret r + 500; }
r = test_enum_complex();
if r != 0 { ret r + 600; }
ret 0;
}