stage1 重构测试且成功00-05
This commit is contained in:
@@ -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),
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 声明
|
## 声明
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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,12 +388,17 @@ 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) {
|
||||||
|
if (!ctx->addr_of_mode) {
|
||||||
/* Load value for basic types and pointers */
|
/* Load value for basic types and pointers */
|
||||||
spl_type_t bt = (vt->kind == TYPE_BASIC) ? vt->basic_type : SPL_PTR;
|
spl_type_t bt = (vt->kind == TYPE_BASIC) ? vt->basic_type : SPL_PTR;
|
||||||
spl_emit(ctx, SPL_LOAD, bt, 0);
|
spl_emit(ctx, SPL_LOAD, bt, 0);
|
||||||
spl_expr_result_t r = { vt, 0 };
|
spl_expr_result_t r = { vt, 0 };
|
||||||
return r;
|
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 */
|
/* Array/struct/slice: address stays on stack */
|
||||||
spl_expr_result_t r = { vt, 1 };
|
spl_expr_result_t r = { vt, 1 };
|
||||||
return r;
|
return r;
|
||||||
@@ -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;
|
||||||
|
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);
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
|
|
||||||
fn main() i32 {
|
|
||||||
ret 0;
|
|
||||||
}
|
|
||||||
8
stage1/test00_basic.spl
Normal file
8
stage1/test00_basic.spl
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/* ===== 模块1:核心基础 =====
|
||||||
|
* test00_basic — 最小程序 / 返回码
|
||||||
|
* 难度:1/5
|
||||||
|
* 验证点:函数定义、整型返回、ret 语句
|
||||||
|
*/
|
||||||
|
fn main() i32 {
|
||||||
|
ret 0;
|
||||||
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
43
stage1/test01_literals.spl
Normal file
43
stage1/test01_literals.spl
Normal 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;
|
||||||
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
51
stage1/test02_variables.spl
Normal file
51
stage1/test02_variables.spl
Normal 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;
|
||||||
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
56
stage1/test03_arithmetic.spl
Normal file
56
stage1/test03_arithmetic.spl
Normal 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;
|
||||||
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
66
stage1/test04_operators.spl
Normal file
66
stage1/test04_operators.spl
Normal 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;
|
||||||
|
}
|
||||||
@@ -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
79
stage1/test05_control.spl
Normal 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;
|
||||||
|
}
|
||||||
@@ -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
48
stage1/test06_for.spl
Normal 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;
|
||||||
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
54
stage1/test07_pointers.spl
Normal file
54
stage1/test07_pointers.spl
Normal 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;
|
||||||
|
}
|
||||||
@@ -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
41
stage1/test08_arrays.spl
Normal 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
43
stage1/test09_slices.spl
Normal 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
64
stage1/test10_struct.spl
Normal 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;
|
||||||
|
}
|
||||||
@@ -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
22
stage1/test11_enum.spl
Normal 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;
|
||||||
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
46
stage1/test12_functions.spl
Normal file
46
stage1/test12_functions.spl
Normal 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;
|
||||||
|
}
|
||||||
@@ -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
35
stage1/test13_extern.spl
Normal 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;
|
||||||
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
56
stage1/test14_assignment.spl
Normal file
56
stage1/test14_assignment.spl
Normal 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;
|
||||||
|
}
|
||||||
@@ -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
39
stage1/test15_defer.spl
Normal 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
48
stage1/test16_methods.spl
Normal 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;
|
||||||
|
}
|
||||||
100
stage1/test17_integration.spl
Normal file
100
stage1/test17_integration.spl
Normal 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;
|
||||||
|
}
|
||||||
36
stage1/test18_recursion.spl
Normal file
36
stage1/test18_recursion.spl
Normal 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;
|
||||||
|
}
|
||||||
32
stage1/test19_typealias.spl
Normal file
32
stage1/test19_typealias.spl
Normal 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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user