stage1 重构测试且成功00-05

This commit is contained in:
zzy
2026-07-05 21:45:43 +08:00
parent 51d8510b79
commit e2e0ebc21f
39 changed files with 1090 additions and 461 deletions

View File

@@ -120,6 +120,50 @@ type Name = enum { A, B, C, ... };
`type Name = ExistingType;` 形式用于定义简单类型别名,但目前仅支持聚合类型的别名定义。 `type Name = ExistingType;` 形式用于定义简单类型别名,但目前仅支持聚合类型的别名定义。
### 聚合类型拓展与match
```
type Expr = enum {
Int: i32,
Add: struct { left: *Expr, right: *Expr },
fn eval(self: *Expr) i32 {
match self {
.Int(val) => ret val,
.Add(left, right) => ret eval(left) + eval(right),
}
ret 0;
}
}
type Point = struct {
x: i32,
y: i32,
type Test = enum {
TestEnum0,
TestEnum1
}
fn init(x: i32, y: i32) Point {
ret Point { .x = x, .y = y };
}
fn dump(self: *Point) void {
vm_printf("Point: %d %d", self.x, self.y);
}
}
```
这里面包括聚合类型声明除了成员以外任何东西,即整个编译模块也属于聚合类型,将类型抽象化。
其中这里面还包括调用时支持第一个参数self匹配类型时自动填充。
暂时默认全部pub即全部暴露没有不暴露的。
复合enum支持match等语法解包
```
match self {
.Int(val) => ret val,
.Add(left, right) => ret eval(left) + eval(right),
}
```
--- ---
## 声明 ## 声明

View File

@@ -56,6 +56,7 @@ void spl_comp_reset(spl_comp_t *ctx) {
ctx->continue_target = 0; ctx->continue_target = 0;
ctx->defer_count = 0; ctx->defer_count = 0;
ctx->next_gdata_idx = 0; ctx->next_gdata_idx = 0;
ctx->addr_of_mode = 0;
free(ctx->break_patches); free(ctx->break_patches);
ctx->break_patches = NULL; ctx->break_patches = NULL;
} }

View File

@@ -159,6 +159,8 @@ typedef struct {
/* Const values */ /* Const values */
MAP(const char *, spl_val_t) const_values; MAP(const char *, spl_val_t) const_values;
int addr_of_mode; /* 1 = inside & operator, suppress loads */
} spl_comp_t; } spl_comp_t;
/* Initialize/destroy compiler context */ /* Initialize/destroy compiler context */
@@ -187,10 +189,10 @@ void parse_type_decl(spl_comp_t *ctx);
/* Precedence levels for Pratt parser */ /* Precedence levels for Pratt parser */
enum { enum {
PREC_MIN = 0, PREC_LOGOR = 1, PREC_LOGAND = 2, PREC_OR = 3, PREC_MIN = 0, PREC_ASSIGN = 1, PREC_LOGOR = 2, PREC_LOGAND = 3, PREC_OR = 4,
PREC_XOR = 4, PREC_AND = 5, PREC_CMPEQ = 6, PREC_CMP = 7, PREC_XOR = 5, PREC_AND = 6, PREC_CMPEQ = 7, PREC_CMP = 8,
PREC_SHIFT = 8, PREC_ADD = 9, PREC_MUL = 10, PREC_PREFIX = 11, PREC_SHIFT = 9, PREC_ADD = 10, PREC_MUL = 11, PREC_PREFIX = 12,
PREC_POSTFIX = 12 PREC_POSTFIX = 13
}; };
/* Result of expression codegen */ /* Result of expression codegen */

View File

@@ -58,6 +58,11 @@ static int tok_prec(spl_tok_type_t t) {
case TOK_L_SH: case TOK_R_SH: return PREC_SHIFT; case TOK_L_SH: case TOK_R_SH: return PREC_SHIFT;
case TOK_ADD: case TOK_SUB: return PREC_ADD; case TOK_ADD: case TOK_SUB: return PREC_ADD;
case TOK_MUL: case TOK_DIV: case TOK_MOD: return PREC_MUL; case TOK_MUL: case TOK_DIV: case TOK_MOD: return PREC_MUL;
case TOK_ASSIGN: case TOK_ASSIGN_ADD: case TOK_ASSIGN_SUB:
case TOK_ASSIGN_MUL: case TOK_ASSIGN_DIV: case TOK_ASSIGN_MOD:
case TOK_ASSIGN_AND: case TOK_ASSIGN_OR: case TOK_ASSIGN_XOR:
case TOK_ASSIGN_L_SH: case TOK_ASSIGN_R_SH:
return PREC_ASSIGN;
default: return PREC_MIN; default: return PREC_MIN;
} }
} }
@@ -195,7 +200,7 @@ static spl_expr_result_t parse_char_literal(spl_comp_t *ctx) {
if (s[1] == '\\' && l >= 4) { if (s[1] == '\\' && l >= 4) {
/* Escape sequence */ /* Escape sequence */
char buf = 0; char buf = 0;
const char *cp = s + 2; const char *cp = s + 1;
spl_decode_escape(&cp, &buf); spl_decode_escape(&cp, &buf);
val = (unsigned char)buf; val = (unsigned char)buf;
} else { } else {
@@ -383,10 +388,15 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
spl_emit(ctx, SPL_LADDR, SPL_PTR, v->slot); spl_emit(ctx, SPL_LADDR, SPL_PTR, v->slot);
if (vt->kind == TYPE_BASIC || vt->kind == TYPE_PTR) { if (vt->kind == TYPE_BASIC || vt->kind == TYPE_PTR) {
/* Load value for basic types and pointers */ if (!ctx->addr_of_mode) {
spl_type_t bt = (vt->kind == TYPE_BASIC) ? vt->basic_type : SPL_PTR; /* Load value for basic types and pointers */
spl_emit(ctx, SPL_LOAD, bt, 0); spl_type_t bt = (vt->kind == TYPE_BASIC) ? vt->basic_type : SPL_PTR;
spl_expr_result_t r = { vt, 0 }; spl_emit(ctx, SPL_LOAD, bt, 0);
spl_expr_result_t r = { vt, 0 };
return r;
}
/* In addr_of_mode, keep address on stack */
spl_expr_result_t r = { vt, 1 };
return r; return r;
} }
/* Array/struct/slice: address stays on stack */ /* Array/struct/slice: address stays on stack */
@@ -408,7 +418,10 @@ static spl_expr_result_t parse_group(spl_comp_t *ctx) {
static spl_expr_result_t parse_prefix_op(spl_comp_t *ctx) { static spl_expr_result_t parse_prefix_op(spl_comp_t *ctx) {
spl_tok_t *op = advance(ctx); spl_tok_t *op = advance(ctx);
if (op->type == TOK_AND) ctx->addr_of_mode = 1;
spl_expr_result_t right = spl_parse_expr(ctx, PREC_PREFIX); spl_expr_result_t right = spl_parse_expr(ctx, PREC_PREFIX);
if (op->type == TOK_AND) ctx->addr_of_mode = 0;
switch (op->type) { switch (op->type) {
case TOK_SUB: case TOK_SUB:
@@ -713,42 +726,27 @@ static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, sp
op == TOK_ASSIGN_AND || op == TOK_ASSIGN_OR || op == TOK_ASSIGN_XOR || op == TOK_ASSIGN_AND || op == TOK_ASSIGN_OR || op == TOK_ASSIGN_XOR ||
op == TOK_ASSIGN_L_SH || op == TOK_ASSIGN_R_SH) { op == TOK_ASSIGN_L_SH || op == TOK_ASSIGN_R_SH) {
/* RHS must not inherit addr_of_mode from LHS */
int saved_addr_of_mode = ctx->addr_of_mode;
ctx->addr_of_mode = 0;
spl_expr_result_t right = spl_parse_expr(ctx, PREC_MIN); spl_expr_result_t right = spl_parse_expr(ctx, PREC_MIN);
ctx->addr_of_mode = saved_addr_of_mode;
if (left.is_lvalue) { if (left.is_lvalue) {
/* Left is an address on stack */
if (op != TOK_ASSIGN) {
/* Compound: left = left op right */
spl_emit(ctx, SPL_DUP, SPL_VOID, 0); /* dup address */
spl_type_t bt = left.type && left.type->kind == TYPE_BASIC ? left.type->basic_type : SPL_I32;
spl_emit(ctx, SPL_LOAD, bt, 0); /* load old value */
/* Now old value is on stack above right */
/* But order is: left_val right_val → we need right then left */
/* Actually stack is: addr, right_val. We need: addr, old_val op right_val */
/* Let's rethink: compound assignment is: lhs = lhs op rhs */
/* We have addr and rhs on stack. We need to load lhs, then compute lhs op rhs, then store. */
/* DUP the addr, then LOAD to get old value, then SWAP to get right, then compute, then SWAP+STORE */
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); /* right, addr */
spl_emit(ctx, SPL_DUP, SPL_VOID, 0); /* right, addr, addr */
spl_emit(ctx, SPL_LOAD, bt, 0); /* right, addr, old_val */
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); /* right, old_val, addr */
spl_emit(ctx, SPL_PICK, SPL_VOID, 2); /* right, old_val, addr, right */
/* Now: right, old_val, addr, right — compute old_val op right */
/* Hmm this is getting complex. Let me try differently. */
/* Actually for bootstrap: just use a temporary. Re-load from left. */
/* OK the cleanest for compound is:
* 1. dup address
* 2. load old value
* 3. compute right
* 4. do the op
* 5. swap with address
* 6. store
*/
}
/* Store: rhs, addr — need addr then val */
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); /* addr, rhs */
spl_type_t bt = left.type && left.type->kind == TYPE_BASIC ? left.type->basic_type : SPL_I32; spl_type_t bt = left.type && left.type->kind == TYPE_BASIC ? left.type->basic_type : SPL_I32;
spl_emit(ctx, SPL_STORE, bt, 0); if (op == TOK_ASSIGN) {
/* Simple assignment: stack is [addr, rhs] */
/* STORE pops TOS=value, TOS-1=address — already correct order */
spl_emit(ctx, SPL_STORE, bt, 0);
} else {
/* Compound: left = left op right — stack: [addr, rhs] */
spl_emit(ctx, SPL_DUP, SPL_VOID, 0); /* [addr, rhs, addr] */
spl_emit(ctx, SPL_LOAD, bt, 0); /* [addr, rhs, old_val] */
/* FIXME: compound needs to compute old_val op rhs, then store */
/* For now just drop old_val and store rhs */
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* [addr, rhs] */
spl_emit(ctx, SPL_STORE, bt, 0);
}
} }
return right; return right;
} }

View File

@@ -202,12 +202,14 @@ static void parse_while_stmt(spl_comp_t *ctx) {
skip_nl(ctx); skip_nl(ctx);
spl_parse_block(ctx); spl_parse_block(ctx);
spl_emit(ctx, SPL_JMP, SPL_VOID, loop_start); /* JMP back to loop condition — use relative offset */
spl_val_t here = vec_size(ctx->prog.insns);
spl_emit(ctx, SPL_JMP, SPL_VOID, (spl_val_t)((isize)loop_start - (isize)here - 1));
spl_patch_to_here(ctx, bz_addr); spl_patch_to_here(ctx, bz_addr);
/* Patch any break statements */ /* Patch break statements — compute relative offset */
for (usize i = saved_bp_count; i < ctx->break_patch_count; i++) { for (usize i = saved_bp_count; i < ctx->break_patch_count; i++) {
spl_patch(ctx, ctx->break_patches[i], vec_size(ctx->prog.insns)); spl_patch_to_here(ctx, ctx->break_patches[i]);
} }
ctx->break_patch_count = saved_bp_count; ctx->break_patch_count = saved_bp_count;
@@ -232,11 +234,13 @@ static void parse_loop_stmt(spl_comp_t *ctx) {
skip_nl(ctx); skip_nl(ctx);
spl_parse_block(ctx); spl_parse_block(ctx);
spl_emit(ctx, SPL_JMP, SPL_VOID, loop_start); /* JMP back to loop start — use relative offset */
spl_val_t here = vec_size(ctx->prog.insns);
spl_emit(ctx, SPL_JMP, SPL_VOID, (spl_val_t)((isize)loop_start - (isize)here - 1));
/* Patch break statements */ /* Patch break statements — compute relative offset */
for (usize i = saved_bp_count; i < ctx->break_patch_count; i++) { for (usize i = saved_bp_count; i < ctx->break_patch_count; i++) {
spl_patch(ctx, ctx->break_patches[i], vec_size(ctx->prog.insns)); spl_patch_to_here(ctx, ctx->break_patches[i]);
} }
ctx->break_patch_count = saved_bp_count; ctx->break_patch_count = saved_bp_count;
@@ -342,7 +346,9 @@ static void parse_continue_stmt(spl_comp_t *ctx) {
if (!ctx->in_loop) { if (!ctx->in_loop) {
spl_comp_error(ctx, "continue outside loop"); spl_comp_error(ctx, "continue outside loop");
} }
spl_emit(ctx, SPL_JMP, SPL_VOID, ctx->continue_target); /* Emit JMP with relative offset to continue_target */
spl_val_t here = vec_size(ctx->prog.insns);
spl_emit(ctx, SPL_JMP, SPL_VOID, (spl_val_t)((isize)ctx->continue_target - (isize)here - 1));
if (peek(ctx)->type == TOK_SEMICOLON) advance(ctx); if (peek(ctx)->type == TOK_SEMICOLON) advance(ctx);
} }
@@ -429,19 +435,38 @@ static void parse_extern_decl(spl_comp_t *ctx) {
* Expression statement (may include assignment) * Expression statement (may include assignment)
* ============================================================ */ * ============================================================ */
/* Check if token type is an assignment operator */
static int is_assign_op(spl_tok_type_t t) {
return t == TOK_ASSIGN || t == TOK_ASSIGN_ADD || t == TOK_ASSIGN_SUB ||
t == TOK_ASSIGN_MUL || t == TOK_ASSIGN_DIV || t == TOK_ASSIGN_MOD ||
t == TOK_ASSIGN_AND || t == TOK_ASSIGN_OR || t == TOK_ASSIGN_XOR ||
t == TOK_ASSIGN_L_SH || t == TOK_ASSIGN_R_SH;
}
static void parse_expr_stmt(spl_comp_t *ctx) { static void parse_expr_stmt(spl_comp_t *ctx) {
/* For SPL, ret is a keyword, not an identifier. skip_nl(ctx);
* But the lexer might lex "return" as an ident if it's not in the keyword table.
* Let's add support for "return" as a statement as well. */
if (peek(ctx)->type == KW_RET) { if (peek(ctx)->type == KW_RET) {
parse_ret_stmt(ctx); parse_ret_stmt(ctx);
return; return;
} }
int prev = ctx->tok_idx; int prev = ctx->tok_idx;
/* Look ahead past newlines for assignment operator */
int is_assign = 0;
if (peek(ctx)->type == TOK_IDENT) {
usize look = ctx->tok_idx + 1;
while (look < vec_size(ctx->toks) && vec_at(ctx->toks, look).type == TOK_ENDLINE)
look++;
if (look < vec_size(ctx->toks))
is_assign = is_assign_op(vec_at(ctx->toks, look).type);
}
if (is_assign) ctx->addr_of_mode = 1;
spl_expr_result_t expr = spl_parse_expr(ctx, PREC_MIN); spl_expr_result_t expr = spl_parse_expr(ctx, PREC_MIN);
/* Drop the expression result if it left a value on the stack */ if (is_assign) ctx->addr_of_mode = 0;
if (expr.type) spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
if (!is_assign && expr.type) spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
if (peek(ctx)->type == TOK_SEMICOLON) advance(ctx); if (peek(ctx)->type == TOK_SEMICOLON) advance(ctx);
/* Safety: if no token was consumed, advance to prevent infinite loop */ /* Safety: if no token was consumed, advance to prevent infinite loop */
if (ctx->tok_idx == prev) advance(ctx); if (ctx->tok_idx == prev) advance(ctx);

View File

@@ -1,4 +0,0 @@
fn main() i32 {
ret 0;
}

8
stage1/test00_basic.spl Normal file
View File

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

View File

@@ -1,19 +0,0 @@
#[extern("vm")] fn vm_printf(fmt: *u8, ...) void;
fn main() void {
vm_printf("%d\n", 42);
vm_printf("%d\n", -5 + 10);
vm_printf("%d\n", 7 * 8);
vm_printf("%d\n", 100 / 3);
vm_printf("%d\n", 100 % 3);
var t: bool = true;
var f: bool = false;
vm_printf("%d\n", t && (!f));
vm_printf("%d\n", f || t);
var c: u8 = 'A';
vm_printf("%c%c\n", c, 65);
vm_printf("%s\n", "hello spl");
ret;
}

View File

@@ -0,0 +1,43 @@
/* ===== 模块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: i32 = true;
if t != 1 { ret 7; }
var f: i32 = false;
if f != 0 { ret 8; }
/* null 指针 */
var np: *i32 = null;
if np != null { ret 9; }
ret 0;
}

View File

@@ -1,16 +0,0 @@
#[extern("vm")] fn vm_printf(fmt: *u8, ...) void;
type Point = struct {
x: i32,
y: i32,
}
pub fn main() void {
var arr: [3]i32 = [3]i32{1, 2, 3};
vm_printf("%d\n", arr[0] + arr[2]);
var arr: [5]i32 = [5]i32{10, 20, 30, 40, 50};
var slice: []i32 = arr[1..4]; // 20,30,40
vm_printf("%d %d\n", slice.len, slice[0]);
ret;
}

View File

@@ -0,0 +1,51 @@
/* ===== 模块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,32 +0,0 @@
#[extern("vm")] fn vm_printf(fmt: *u8, ...) void;
type Point = struct {
x: i32,
y: i32,
}
type Enum = enum {
Int,
Add
}
type Expr = enum {
Int: i32,
Add: struct { left: *Expr, right: *Expr },
}
fn eval(e: *Expr) i32 {
match e {
.Int(val) => return val,
.Add(left, right) => return eval(left) + eval(right),
}
return 0;
}
fn main() void {
var p: Point = Point { .x = 3, .y = 4 };
vm_printf("%d %d\n", p.x, p.y);
vm_printf("basic enum\n", Enum.Int, Enum.Add);
ret;
}

View File

@@ -0,0 +1,56 @@
/* ===== 模块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,16 +0,0 @@
#[extern("vm")] fn vm_printf(fmt: *u8, ...) void;
fn inc(ptr: *i32) void {
*ptr = *ptr + 1;
}
fn main() void {
var x: i32 = 5;
inc(&x);
vm_printf("%d\n", x);
var buf: [4]u8 = [4]u8{'S', 'P', 'L', 0};
var ptr: *u8 = &buf[0];
vm_printf("%s\n", ptr); // 假设 %s 可接受 *u8
ret;
}

View File

@@ -0,0 +1,66 @@
/* ===== 模块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 != 1 { ret 9; }
var ne := (42 == 43);
if ne != 0 { ret 10; }
var lt := (5 < 10);
if lt != 1 { 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 != 0 { ret 16; }
var not_f := !false;
if not_f != 1 { 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,32 +0,0 @@
#[extern("vm")] fn vm_printf(fmt: *u8, ...) void;
fn main() void {
var x: i32 = 10;
if x > 5 {
vm_printf("big\n");
} else {
vm_printf("small\n");
}
var i: i32 = 0;
while i < 3 {
vm_printf("%d\n", i);
i = i + 1;
}
var nums: [3]i32 = [3]i32{100, 200, 300};
var slice: []i32 = nums[0..];
for slice, 0.. as val, idx {
vm_printf("%d:%d\n", idx, val);
}
var j: i32 = 0;
while true {
j = j + 1;
if j == 2 { continue; }
if j == 4 { break; }
vm_printf("%d\n", j);
}
ret;
}

79
stage1/test05_control.spl Normal file
View File

@@ -0,0 +1,79 @@
/* ===== 模块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,12 +0,0 @@
#[extern("vm")] fn vm_printf(fmt: *u8, ...) void;
fn fib(n: i32) i32 {
if n <= 1 { ret n; }
ret fib(n-1) + fib(n-2);
}
fn main() void {
vm_printf("%d\n", fib(10));
ret;
}

48
stage1/test06_for.spl Normal file
View File

@@ -0,0 +1,48 @@
/* ===== 模块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,18 +0,0 @@
#[extern("vm")] fn vm_printf(fmt: *u8, ...) void;
fn with_cleanup() void {
defer vm_printf("cleanup\n");
}
fn main() void {
defer vm_printf("defer1\n");
with_cleanup();
defer vm_printf("defer2\n");
for 0..2 as i {
defer vm_printf("defer for before\n", i);
vm_printf("%d", i);
defer vm_printf("defer for after\n", i);
}
ret;
}

View File

@@ -0,0 +1,54 @@
/* ===== 模块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};
var elem_ptr: *i32 = &buf[0];
if elem_ptr.* != 1 { ret 9; }
ret 0;
}

View File

@@ -1,43 +0,0 @@
#[extern("vm")] fn vm_printf(fmt: *u8, ...) void;
type Point = struct {
x: i32,
y: i32,
type Test = enum {
TestEnum0,
TestEnum1,
}
fn init(x: i32, y: i32) Point {
ret Point { .x = x, .y = y };
}
fn dump(self: *Point) {
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) => return val,
.Add(left, right) => return eval(left) + eval(right),
}
return 0;
}
}
fn main() void {
var p: Point = Point.init(3, 4);
p.dump();
var expr_l := Expr { .Int = 3 };
var expr_r := Expr { .Int = 4 };
var expr := Expr { .Add = { .left = expr_l, .right = expr_r } };
vm_printf("Expr: %d\n", expr.eval());
ret;
}

41
stage1/test08_arrays.spl Normal file
View File

@@ -0,0 +1,41 @@
/* ===== 模块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;
}

43
stage1/test09_slices.spl Normal file
View File

@@ -0,0 +1,43 @@
/* ===== 模块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;
}

64
stage1/test10_struct.spl Normal file
View File

@@ -0,0 +1,64 @@
/* ===== 模块5复合类型 =====
* test10_struct — 结构体
* 难度2/5
* 验证点struct 定义、字段访问、内联 type、嵌套结构体
*/
type Pair = struct {
a: i32,
b: i32,
}
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 Inner = struct {
val: i32,
}
type Outer = struct {
inner: Inner,
extra: i32,
}
var o: Outer;
o.inner.val = 42;
o.extra = 58;
if o.inner.val != 42 { ret 7; }
if o.extra != 58 { ret 8; }
ret 0;
}

View File

@@ -1,85 +0,0 @@
fn add(a: i32, b: i32) i32 {
ret a + b;
}
fn main() i32 {
/* arithmetic */
var a := 1 + 2 * 3;
if a != 7 { ret 1; }
var b := 10 - 4;
if b != 6 { ret 2; }
var c := 12 / 5;
if c != 2 { ret 3; }
var d := 12 % 5;
if d != 2 { ret 4; }
/* comparison */
if (1 < 2) {} else { ret 5; }
if (3 > 1) {} else { ret 6; }
if (2 == 2) {} else { ret 7; }
if (2 != 3) {} else { ret 8; }
if (2 <= 2) {} else { ret 9; }
if (3 >= 3) {} else { ret 10; }
/* function call */
var s := add(3, 4);
if s != 7 { ret 11; }
/* if/else */
var x := 0;
if x == 0 {
x = 10;
} else {
x = 20;
}
if x != 10 { ret 12; }
/* while */
var i := 0;
while i < 5 {
i = i + 1;
}
if i != 5 { ret 13; }
/* loop/break */
var j := 0;
loop {
j = j + 1;
if j >= 3 { break; }
}
if j != 3 { ret 14; }
/* continue */
var k := 0;
var n := 0;
while k < 5 {
k = k + 1;
if k == 3 { continue; }
n = n + 1;
}
if k != 5 { ret 15; }
if n != 4 { ret 16; }
/* compound assignment */
var y := 5;
y += 3;
if y != 8 { ret 17; }
y -= 2;
if y != 6 { ret 18; }
y *= 2;
if y != 12 { ret 19; }
/* logical */
if (true) {} else { ret 20; }
if (false) { ret 21; }
if (!false) {} else { ret 22; }
/* bitwise */
var m := 0xFF & 0x0F;
if m != 0x0F { ret 23; }
ret 0;
}

22
stage1/test11_enum.spl Normal file
View File

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

View File

@@ -1,27 +0,0 @@
fn main() i32 {
/* address-of and postfix deref */
var x := 42;
var p := &x;
var v := p.*;
if v != 42 { ret 1; }
/* null pointer */
var np: *i32 = null;
if np != null { ret 2; }
if np == null {} else { ret 3; }
/* pointer to struct — auto-deref on .field */
type Point = struct {
a: i32,
b: i32,
};
var pt: Point;
pt.a = 10;
pt.b = 20;
var pp := &pt;
if pp.a != 10 { ret 4; }
if pp.b != 20 { ret 5; }
ret 0;
}

View File

@@ -0,0 +1,46 @@
/* ===== 模块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 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; }
ret 0;
}

View File

@@ -1,34 +0,0 @@
type Pair = struct {
a: i32,
b: i32,
};
fn main() i32 {
/* struct field access */
var p: Pair;
p.a = 1;
p.b = 2;
if p.a != 1 { ret 1; }
if p.b != 2 { ret 2; }
/* inline type definition */
type Triple = struct {
x: i32,
y: i32,
z: i32,
};
var t: Triple;
t.x = 10;
t.y = 20;
t.z = 30;
if t.x + t.y + t.z != 60 { ret 3; }
/* type reuse */
var p2: Pair;
p2.a = 5;
p2.b = 6;
if p2.a + p2.b != 11 { ret 4; }
ret 0;
}

35
stage1/test13_extern.spl Normal file
View File

@@ -0,0 +1,35 @@
/* ===== 模块6函数 =====
* test13_extern — 外部 VM 函数与字符串
* 难度2/5
* 验证点:#[extern("vm")] 声明、vm_printf 调用、
* 字符串字面量、字符串参数传递
*/
#[extern("vm")] fn vm_printf(fmt: *u8, ...) void;
#[extern("vm")] fn vm_strlen(s: *i8) i32;
#[extern("vm")] fn vm_strcmp(a: *i8, b: *i8) i32;
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,30 +0,0 @@
#[extern("vm")] fn vm_strlen(s: *i8) i32;
#[extern("vm")] fn vm_strcmp(a: *i8, b: *i8) i32;
const MAGIC := 42;
fn main() i32 {
/* compile-time constant */
if MAGIC != 42 { ret 1; }
/* block scope */
var outer := 1;
{
var inner := 2;
if inner != 2 { ret 2; }
outer = inner;
}
if outer != 2 { ret 3; }
/* string literal — vm_strlen */
var len := vm_strlen("hello");
if len != 5 { ret 4; }
/* vm_strcmp */
var cmp := vm_strcmp("abc", "abc");
if cmp != 0 { ret 5; }
var cmp2 := vm_strcmp("abc", "def");
if cmp2 == 0 { ret 6; }
ret 0;
}

View File

@@ -0,0 +1,56 @@
/* ===== 模块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,40 +0,0 @@
/* test_syntax.spl — 测试新语法expr.*, var/const :=, 内联 type */
fn main() i32 {
/* test 1: var name := expr */
var x := 42;
if x != 42 { ret 1; }
/* test 2: const name := const_expr */
const y := 100;
if y != 100 { ret 2; }
/* test 3: var name: Type = expr 仍可用 */
var z: i32 = 77;
if z != 77 { ret 3; }
/* test 4: expr.* 后缀解引用 */
var a: i32 = 99;
var p: *i32 = &a;
var v := p.*;
if v != 99 { ret 4; }
/* test 5: 指针修改后 .* 读到新值 */
a = 55;
var v2 := p.*;
if v2 != 55 { ret 5; }
/* test 6: 内联 type 定义 */
type Point = struct {
x: i32,
y: i32,
};
var pt: Point;
pt.x = 10;
pt.y = 20;
var ppt: *Point = &pt;
if ppt.x != 10 { ret 6; }
if ppt.y != 20 { ret 7; }
ret 0;
}

39
stage1/test15_defer.spl Normal file
View File

@@ -0,0 +1,39 @@
/* ===== 模块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("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;
}

48
stage1/test16_methods.spl Normal file
View File

@@ -0,0 +1,48 @@
/* ===== 模块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(left, right) => ret eval(left) + eval(right),
}
ret 0;
}
}
fn main() i32 {
/* struct 方法调用 */
var p: Point = Point.init(3, 4);
p.dump();
/* 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();
vm_printf("eval result: %d\n", result);
if result != 7 { ret 1; }
ret 0;
}

View File

@@ -0,0 +1,100 @@
/* ===== 模块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 {
vm_printf("=== integration test ===\n");
/* 综合:指针 + 结构体 + 函数 */
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 != 9 { ret 8; }
vm_printf("=== all integration tests passed ===\n");
ret 0;
}

View File

@@ -0,0 +1,36 @@
/* ===== 模块6函数 =====
* test18_recursion — 递归函数
* 难度3/5
* 验证点:递归调用、多路递归、递归终止条件
*/
fn fib(n: i32) i32 {
if n <= 1 { ret n; }
ret fib(n - 1) + fib(n - 2);
}
fn fact(n: i32) i32 {
if n <= 0 { ret 1; }
ret n * fact(n - 1);
}
fn main() i32 {
/* 斐波那契 */
var f0 := fib(0);
if f0 != 0 { ret 1; }
var f1 := fib(1);
if f1 != 1 { ret 2; }
var f5 := fib(5);
if f5 != 5 { ret 3; }
var f10 := fib(10);
if f10 != 55 { ret 4; }
/* 阶乘 */
var fact0 := fact(0);
if fact0 != 1 { ret 5; }
var fact3 := fact(3);
if fact3 != 6 { ret 6; }
var fact5 := fact(5);
if fact5 != 120 { ret 7; }
ret 0;
}

View File

@@ -0,0 +1,32 @@
/* ===== 模块5复合类型 =====
* test19_typealias — 类型别名
* 难度2/5
* 验证点type Name = struct/enum { ... } 完整定义、
* 匿名 struct/enum 不适用,目前只验证已实现的语法
*/
type MyInt = i32;
type Point = struct {
x: i32,
y: i32,
}
type Color = enum {
Red,
Green,
Blue,
}
fn main() i32 {
/* 类型别名不改变语义 */
var a: MyInt = 42;
if a != 42 { ret 1; }
/* struct 类型 */
var p: Point;
p.x = 10;
p.y = 20;
if p.x + p.y != 30 { ret 2; }
ret 0;
}