diff --git a/stage1/spl.md b/stage1/spl.md index 48abd25..35ea20d 100644 --- a/stage1/spl.md +++ b/stage1/spl.md @@ -120,6 +120,50 @@ type Name = enum { A, B, C, ... }; `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), +} +``` + --- ## 声明 diff --git a/stage1/spl_comp.c b/stage1/spl_comp.c index 0a51c6c..7fadf3f 100644 --- a/stage1/spl_comp.c +++ b/stage1/spl_comp.c @@ -56,6 +56,7 @@ void spl_comp_reset(spl_comp_t *ctx) { ctx->continue_target = 0; ctx->defer_count = 0; ctx->next_gdata_idx = 0; + ctx->addr_of_mode = 0; free(ctx->break_patches); ctx->break_patches = NULL; } diff --git a/stage1/spl_comp.h b/stage1/spl_comp.h index 118f558..907e130 100644 --- a/stage1/spl_comp.h +++ b/stage1/spl_comp.h @@ -159,6 +159,8 @@ typedef struct { /* Const values */ MAP(const char *, spl_val_t) const_values; + + int addr_of_mode; /* 1 = inside & operator, suppress loads */ } spl_comp_t; /* Initialize/destroy compiler context */ @@ -187,10 +189,10 @@ void parse_type_decl(spl_comp_t *ctx); /* Precedence levels for Pratt parser */ enum { - PREC_MIN = 0, PREC_LOGOR = 1, PREC_LOGAND = 2, PREC_OR = 3, - PREC_XOR = 4, PREC_AND = 5, PREC_CMPEQ = 6, PREC_CMP = 7, - PREC_SHIFT = 8, PREC_ADD = 9, PREC_MUL = 10, PREC_PREFIX = 11, - PREC_POSTFIX = 12 + PREC_MIN = 0, PREC_ASSIGN = 1, PREC_LOGOR = 2, PREC_LOGAND = 3, PREC_OR = 4, + PREC_XOR = 5, PREC_AND = 6, PREC_CMPEQ = 7, PREC_CMP = 8, + PREC_SHIFT = 9, PREC_ADD = 10, PREC_MUL = 11, PREC_PREFIX = 12, + PREC_POSTFIX = 13 }; /* Result of expression codegen */ diff --git a/stage1/spl_expr.c b/stage1/spl_expr.c index 1083258..93b48b3 100644 --- a/stage1/spl_expr.c +++ b/stage1/spl_expr.c @@ -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_ADD: case TOK_SUB: return PREC_ADD; 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; } } @@ -195,7 +200,7 @@ static spl_expr_result_t parse_char_literal(spl_comp_t *ctx) { if (s[1] == '\\' && l >= 4) { /* Escape sequence */ char buf = 0; - const char *cp = s + 2; + const char *cp = s + 1; spl_decode_escape(&cp, &buf); val = (unsigned char)buf; } 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); if (vt->kind == TYPE_BASIC || vt->kind == TYPE_PTR) { - /* Load value for basic types and pointers */ - spl_type_t bt = (vt->kind == TYPE_BASIC) ? vt->basic_type : SPL_PTR; - spl_emit(ctx, SPL_LOAD, bt, 0); - spl_expr_result_t r = { vt, 0 }; + if (!ctx->addr_of_mode) { + /* Load value for basic types and pointers */ + spl_type_t bt = (vt->kind == TYPE_BASIC) ? vt->basic_type : SPL_PTR; + 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; } /* 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) { 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); + if (op->type == TOK_AND) ctx->addr_of_mode = 0; switch (op->type) { 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_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); + ctx->addr_of_mode = saved_addr_of_mode; 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_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; } diff --git a/stage1/spl_stmt.c b/stage1/spl_stmt.c index 298a5ad..f01b6f4 100644 --- a/stage1/spl_stmt.c +++ b/stage1/spl_stmt.c @@ -202,12 +202,14 @@ static void parse_while_stmt(spl_comp_t *ctx) { skip_nl(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); - /* Patch any break statements */ + /* Patch break statements — compute relative offset */ 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; @@ -232,11 +234,13 @@ static void parse_loop_stmt(spl_comp_t *ctx) { skip_nl(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++) { - 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; @@ -342,7 +346,9 @@ static void parse_continue_stmt(spl_comp_t *ctx) { if (!ctx->in_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); } @@ -429,19 +435,38 @@ static void parse_extern_decl(spl_comp_t *ctx) { * 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) { - /* For SPL, ret is a keyword, not an identifier. - * 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. */ + skip_nl(ctx); if (peek(ctx)->type == KW_RET) { parse_ret_stmt(ctx); return; } 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); - /* Drop the expression result if it left a value on the stack */ - if (expr.type) spl_emit(ctx, SPL_DROP, SPL_VOID, 0); + if (is_assign) ctx->addr_of_mode = 0; + + if (!is_assign && expr.type) spl_emit(ctx, SPL_DROP, SPL_VOID, 0); if (peek(ctx)->type == TOK_SEMICOLON) advance(ctx); /* Safety: if no token was consumed, advance to prevent infinite loop */ if (ctx->tok_idx == prev) advance(ctx); diff --git a/stage1/test00.spl b/stage1/test00.spl deleted file mode 100644 index 61bd6e5..0000000 --- a/stage1/test00.spl +++ /dev/null @@ -1,4 +0,0 @@ - -fn main() i32 { - ret 0; -} diff --git a/stage1/test00_basic.spl b/stage1/test00_basic.spl new file mode 100644 index 0000000..d235944 --- /dev/null +++ b/stage1/test00_basic.spl @@ -0,0 +1,8 @@ +/* ===== 模块1:核心基础 ===== + * test00_basic — 最小程序 / 返回码 + * 难度:1/5 + * 验证点:函数定义、整型返回、ret 语句 + */ +fn main() i32 { + ret 0; +} diff --git a/stage1/test01.spl b/stage1/test01.spl deleted file mode 100644 index 93f7967..0000000 --- a/stage1/test01.spl +++ /dev/null @@ -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; -} diff --git a/stage1/test01_literals.spl b/stage1/test01_literals.spl new file mode 100644 index 0000000..27fb602 --- /dev/null +++ b/stage1/test01_literals.spl @@ -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; +} diff --git a/stage1/test02.spl b/stage1/test02.spl deleted file mode 100644 index cb2d050..0000000 --- a/stage1/test02.spl +++ /dev/null @@ -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; -} diff --git a/stage1/test02_variables.spl b/stage1/test02_variables.spl new file mode 100644 index 0000000..feba842 --- /dev/null +++ b/stage1/test02_variables.spl @@ -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; +} diff --git a/stage1/test03.spl b/stage1/test03.spl deleted file mode 100644 index a18cb67..0000000 --- a/stage1/test03.spl +++ /dev/null @@ -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; -} diff --git a/stage1/test03_arithmetic.spl b/stage1/test03_arithmetic.spl new file mode 100644 index 0000000..e590599 --- /dev/null +++ b/stage1/test03_arithmetic.spl @@ -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; +} diff --git a/stage1/test04.spl b/stage1/test04.spl deleted file mode 100644 index d1d5d61..0000000 --- a/stage1/test04.spl +++ /dev/null @@ -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; -} diff --git a/stage1/test04_operators.spl b/stage1/test04_operators.spl new file mode 100644 index 0000000..98e9077 --- /dev/null +++ b/stage1/test04_operators.spl @@ -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; +} diff --git a/stage1/test05.spl b/stage1/test05.spl deleted file mode 100644 index c18fddb..0000000 --- a/stage1/test05.spl +++ /dev/null @@ -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; -} diff --git a/stage1/test05_control.spl b/stage1/test05_control.spl new file mode 100644 index 0000000..9133848 --- /dev/null +++ b/stage1/test05_control.spl @@ -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; +} diff --git a/stage1/test06.spl b/stage1/test06.spl deleted file mode 100644 index 27bbc25..0000000 --- a/stage1/test06.spl +++ /dev/null @@ -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; -} diff --git a/stage1/test06_for.spl b/stage1/test06_for.spl new file mode 100644 index 0000000..e2b661d --- /dev/null +++ b/stage1/test06_for.spl @@ -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; +} diff --git a/stage1/test07.spl b/stage1/test07.spl deleted file mode 100644 index 5b3f9f5..0000000 --- a/stage1/test07.spl +++ /dev/null @@ -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; -} diff --git a/stage1/test07_pointers.spl b/stage1/test07_pointers.spl new file mode 100644 index 0000000..0799f35 --- /dev/null +++ b/stage1/test07_pointers.spl @@ -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; +} diff --git a/stage1/test08.spl b/stage1/test08.spl deleted file mode 100644 index c4dd411..0000000 --- a/stage1/test08.spl +++ /dev/null @@ -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; -} diff --git a/stage1/test08_arrays.spl b/stage1/test08_arrays.spl new file mode 100644 index 0000000..d0a4b24 --- /dev/null +++ b/stage1/test08_arrays.spl @@ -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; +} diff --git a/stage1/test09_slices.spl b/stage1/test09_slices.spl new file mode 100644 index 0000000..cd2fe2b --- /dev/null +++ b/stage1/test09_slices.spl @@ -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; +} diff --git a/stage1/test10_struct.spl b/stage1/test10_struct.spl new file mode 100644 index 0000000..36e4183 --- /dev/null +++ b/stage1/test10_struct.spl @@ -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; +} diff --git a/stage1/test11.spl b/stage1/test11.spl deleted file mode 100644 index 68d8f23..0000000 --- a/stage1/test11.spl +++ /dev/null @@ -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; -} diff --git a/stage1/test11_enum.spl b/stage1/test11_enum.spl new file mode 100644 index 0000000..7a116c9 --- /dev/null +++ b/stage1/test11_enum.spl @@ -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; +} diff --git a/stage1/test12.spl b/stage1/test12.spl deleted file mode 100644 index c0d8b2a..0000000 --- a/stage1/test12.spl +++ /dev/null @@ -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; -} diff --git a/stage1/test12_functions.spl b/stage1/test12_functions.spl new file mode 100644 index 0000000..a9d29c2 --- /dev/null +++ b/stage1/test12_functions.spl @@ -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; +} diff --git a/stage1/test13.spl b/stage1/test13.spl deleted file mode 100644 index 0f11bcf..0000000 --- a/stage1/test13.spl +++ /dev/null @@ -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; -} diff --git a/stage1/test13_extern.spl b/stage1/test13_extern.spl new file mode 100644 index 0000000..a388075 --- /dev/null +++ b/stage1/test13_extern.spl @@ -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; +} diff --git a/stage1/test14.spl b/stage1/test14.spl deleted file mode 100644 index e7e77ad..0000000 --- a/stage1/test14.spl +++ /dev/null @@ -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; -} diff --git a/stage1/test14_assignment.spl b/stage1/test14_assignment.spl new file mode 100644 index 0000000..5d34ee4 --- /dev/null +++ b/stage1/test14_assignment.spl @@ -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; +} diff --git a/stage1/test15.spl b/stage1/test15.spl deleted file mode 100644 index 522e7d2..0000000 --- a/stage1/test15.spl +++ /dev/null @@ -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; -} diff --git a/stage1/test15_defer.spl b/stage1/test15_defer.spl new file mode 100644 index 0000000..0e21138 --- /dev/null +++ b/stage1/test15_defer.spl @@ -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; +} diff --git a/stage1/test16_methods.spl b/stage1/test16_methods.spl new file mode 100644 index 0000000..cccbe6b --- /dev/null +++ b/stage1/test16_methods.spl @@ -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; +} diff --git a/stage1/test17_integration.spl b/stage1/test17_integration.spl new file mode 100644 index 0000000..4b5c02a --- /dev/null +++ b/stage1/test17_integration.spl @@ -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; +} diff --git a/stage1/test18_recursion.spl b/stage1/test18_recursion.spl new file mode 100644 index 0000000..1ba7b38 --- /dev/null +++ b/stage1/test18_recursion.spl @@ -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; +} diff --git a/stage1/test19_typealias.spl b/stage1/test19_typealias.spl new file mode 100644 index 0000000..ac7d5cb --- /dev/null +++ b/stage1/test19_typealias.spl @@ -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; +}