stage1 初步实现
This commit is contained in:
@@ -548,7 +548,7 @@ void spl_vm_init_ex(spl_vm_t *vm, int stack_size, int call_depth) {
|
||||
#endif
|
||||
if (!vm)
|
||||
return;
|
||||
vm->config.max_stack_depth = stack_size > 0 ? stack_size : 1024 * 8;
|
||||
vm->config.max_stack_depth = stack_size > 0 ? stack_size : 1024 * 1024 * 8;
|
||||
vm->config.max_call_depth = call_depth > 0 ? call_depth : 128;
|
||||
|
||||
vec_init(vm->stacks);
|
||||
@@ -989,6 +989,8 @@ int spl_vm_run_once(spl_vm_t *vm) {
|
||||
}
|
||||
|
||||
case SPL_HALT:
|
||||
if (ins->imm)
|
||||
vm->exit_code = (int)ins->imm;
|
||||
return 1;
|
||||
|
||||
/* ========== Stack / Frame Local Memory ========== */
|
||||
|
||||
@@ -1786,10 +1786,11 @@ static spl_ast_node_ref_t parse_type_atom(parser_t *p) {
|
||||
kind = SPL_AST_TYPE_USIZE;
|
||||
else if (IS_TY("ptr"))
|
||||
kind = SPL_AST_TYPE_PTR;
|
||||
else if (IS_TY("f32") || IS_TY("f64")) {
|
||||
parse_error(p, t, "not implemented: f32/f64 type");
|
||||
kind = SPL_AST_TYPE_IDENT;
|
||||
} else {
|
||||
else if (IS_TY("f32"))
|
||||
kind = SPL_AST_TYPE__F32;
|
||||
else if (IS_TY("f64"))
|
||||
kind = SPL_AST_TYPE__F64;
|
||||
else {
|
||||
kind = SPL_AST_TYPE_IDENT;
|
||||
}
|
||||
#undef IS_TY
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
* 设计要点 * - 名称解析自包含:局部变类型用自身环境栈;顶层类函数sema root scope 与聚合成员表 * -
|
||||
* 变量落在内存槽(@mem.alloca),写走 @mem.load/store;表达式临时值为 SSA * - 控制流用"块表 +
|
||||
* fixup 补丁":分跳转目标在函数末尾回填为块首指令node ref * -
|
||||
* 聚合字段访问:读@agg.extract,写字节地址直写"(@mem.offset + @mem.store<EFBFBD>?* - 枚举=
|
||||
* 聚合字段访问:读@agg.extract,写字节地址直写"(@mem.offset + @mem.store* - 枚举=
|
||||
* agg.construct(enum)([tag, payload?]);match tag 分发 * - defer 按作用域逆序执行(正常退/ ret /
|
||||
* break / continue 全覆盖) */
|
||||
|
||||
#include "spl_ast2ir.h"
|
||||
#include "spl_builtin.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -133,7 +134,7 @@ static spl_def_id_t def_for_type(spl_ast2ir_t *a, spl_type_id_t tid) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
/* 判断 agg_def 条目是否为结构字段(SPL_DEF_MEMBER<EFBFBD>?*/
|
||||
/* 判断 agg_def 条目是否为结构字段(SPL_DEF_MEMBER*/
|
||||
static int agg_entry_is_field(spl_ast2ir_t *a, const spl_var_def_t *e) {
|
||||
if (!e->def_id)
|
||||
return 0;
|
||||
@@ -141,7 +142,7 @@ static int agg_entry_is_field(spl_ast2ir_t *a, const spl_var_def_t *e) {
|
||||
return ed && ed->kind == SPL_DEF_MEMBER;
|
||||
}
|
||||
|
||||
/* 命名空间成员类型(方<EFBFBD>?嵌套类型/static var):按名任意 kind */
|
||||
/* 命名空间成员类型(方嵌套类型/static var):按名任意 kind */
|
||||
static spl_type_id_t agg_member_type(spl_ast2ir_t *a, spl_type_id_t agg_tid, const char *name) {
|
||||
agg_tid = underlying(a->sema, agg_tid);
|
||||
spl_def_id_t d = def_for_type(a, agg_tid);
|
||||
@@ -155,7 +156,7 @@ static spl_type_id_t agg_member_type(spl_ast2ir_t *a, spl_type_id_t agg_tid, con
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 结构字段序号 = 相对 SPL_DEF_MEMBER 的位置(<EFBFBD>?type.agg_field_types 按序对齐<EFBFBD>?*/
|
||||
/* 结构字段序号 = 相对 SPL_DEF_MEMBER 的位置(type.agg_field_types 按序对齐*/
|
||||
static isize agg_member_index(spl_ast2ir_t *a, spl_type_id_t agg_tid, const char *name) {
|
||||
agg_tid = underlying(a->sema, agg_tid);
|
||||
spl_def_id_t d = def_for_type(a, agg_tid);
|
||||
@@ -188,7 +189,7 @@ static spl_type_id_t agg_field_tid_at(spl_ast2ir_t *a, spl_type_id_t agg_tid, is
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 按字段序号查成员名(agg_def 中第 idx <EFBFBD>?SPL_DEF_MEMBER 条目<EFBFBD>?*/
|
||||
/* 按字段序号查成员名(agg_def 中第 idx SPL_DEF_MEMBER 条目*/
|
||||
static const char *agg_field_name_at(spl_ast2ir_t *a, spl_type_id_t agg_tid, isize idx) {
|
||||
agg_tid = underlying(a->sema, agg_tid);
|
||||
spl_def_id_t d = def_for_type(a, agg_tid);
|
||||
@@ -289,6 +290,7 @@ typedef struct {
|
||||
VEC(spl_type_id_t) types; /* nodes 平行的结果类型表 */
|
||||
int terminated;
|
||||
spl_type_id_t hint;
|
||||
usize cur_src; /* 当前语句AST 节点 ref(调试行号) */
|
||||
int err;
|
||||
} fnctx_t;
|
||||
|
||||
@@ -342,6 +344,7 @@ static spl_ir_node_ref_t emit_node(spl_ast2ir_t *a, fnctx_t *fc) {
|
||||
fc->terminated = 0;
|
||||
}
|
||||
spl_ir_node_ref_t r = spl_ir_alloc_node(&a->ir, fc->fn);
|
||||
spl_ir_node(&a->ir, fc->fn, r)->src_ref = fc->cur_src; /* 调试行号 */
|
||||
if (fc->cur_block < fc->blocks.size && !fc->blocks.data[fc->cur_block].first)
|
||||
fc->blocks.data[fc->cur_block].first = r;
|
||||
if (fc->types.size == 0) {
|
||||
@@ -533,7 +536,7 @@ static spl_ir_node_ref_t emit_offset(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t
|
||||
return n;
|
||||
}
|
||||
|
||||
/* 字段地址:mem.field_ptr(agg_tid, agg, idx) → *field_type。布局偏移由 ir2vm 算,ast2ir 不算。 */
|
||||
/* 字段地址:mem.field_ptr(agg_tid, agg, idx) *field_type。布局偏移ir2vm 算,ast2ir 不算*/
|
||||
static spl_ir_node_ref_t emit_field(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t agg_tid,
|
||||
spl_ir_node_ref_t ptr, isize fidx) {
|
||||
spl_type_id_t fty = agg_field_tid_or_builtin(a, agg_tid, fidx);
|
||||
@@ -548,7 +551,7 @@ static spl_ir_node_ref_t emit_field(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t
|
||||
return n;
|
||||
}
|
||||
|
||||
/* 全局静态数据地址:mem.global_alloc(tid, gdata_idx) <EFBFBD>?*tid */
|
||||
/* 全局静态数据地址:mem.global_alloc(tid, gdata_idx) *tid */
|
||||
static spl_ir_node_ref_t emit_global_alloc(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid,
|
||||
usize gdata_idx) {
|
||||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||||
@@ -665,7 +668,7 @@ static ir_env_t *env_find(fnctx_t *fc, const char *name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* def_id 优先定位(sema 已作用域解析,绕开同名遮蔽歧义);<EFBFBD>?def_id 时兜底名<EFBFBD>?*/
|
||||
/* def_id 优先定位(sema 已作用域解析,绕开同名遮蔽歧义);def_id 时兜底名*/
|
||||
static ir_env_t *env_find_def(fnctx_t *fc, spl_def_id_t def_id, const char *name) {
|
||||
if (def_id) {
|
||||
for (usize i = fc->env.size; i > 0; i--) {
|
||||
@@ -740,7 +743,7 @@ static spl_ir_node_ref_t enum_tag_of(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t
|
||||
return emit_agg_extract(a, fc, enum_tid, enum_tag_tid(a), 0, val);
|
||||
}
|
||||
|
||||
/* tid 是否<EFBFBD>?enum */
|
||||
/* tid 是否enum */
|
||||
static int is_enum_expand(spl_ast2ir_t *a, spl_type_id_t tid, spl_type_id_t *out_enum) {
|
||||
spl_type_node_t *t = tn(a->sema, underlying(a->sema, tid));
|
||||
if (t && t->kind == SPL_TYPE_ENUM) {
|
||||
@@ -865,13 +868,13 @@ static spl_type_id_t resolve_type_expr(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_nod
|
||||
spl_ast_node_t *n = node_at(a->sema, ref);
|
||||
if (!n)
|
||||
return 0;
|
||||
/* 首<EFBFBD>?sema 注解:resolved_def_id <EFBFBD>?def <EFBFBD>?类型(聚<EFBFBD>?别名/命名类型<EFBFBD>?*/
|
||||
/* 首sema 注解:resolved_def_id def 类型(聚别名/命名类型*/
|
||||
if (n->resolved_def_id) {
|
||||
spl_def_node_t *d = def_at(a->sema, n->resolved_def_id);
|
||||
if (d && d->type_id)
|
||||
return d->type_id;
|
||||
}
|
||||
/* 兜底:组<EFBFBD>?内置类型(sema 不为其建 def <EFBFBD>?*T、[]T、fn(...)、关键字、别名到组合<EFBFBD>?*/
|
||||
/* 兜底:组内置类型(sema 不为其建 def *T、[]T、fn(...)、关键字、别名到组合*/
|
||||
spl_type_id_t base = 0;
|
||||
switch (n->type_expr.kind) {
|
||||
case SPL_AST_BASE_TYPE_PATH:
|
||||
@@ -898,7 +901,7 @@ static spl_type_id_t resolve_type_expr(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_nod
|
||||
case SPL_AST_TYPE_STRUCT:
|
||||
case SPL_AST_TYPE_UNION:
|
||||
case SPL_AST_TYPE_ENUM:
|
||||
/* 内联聚合不应走到这里(sema 已注解其 def);防御性报<EFBFBD>?*/
|
||||
/* 内联聚合不应走到这里(sema 已注解其 def);防御性报*/
|
||||
diag(a, fc, ref, "inline aggregate not annotated by sema");
|
||||
return 0;
|
||||
default:
|
||||
@@ -1019,7 +1022,7 @@ static spl_ast_node_ref_t field_chain_base(spl_ast2ir_t *a, spl_ast_node_t *pf,
|
||||
return bref;
|
||||
}
|
||||
|
||||
/* 字段链的存储地址(root.a.b 地址 + 字段类型<EFBFBD>?*/
|
||||
/* 字段链的存储地址(root.a.b 地址 + 字段类型*/
|
||||
static spl_ir_node_ref_t lower_field_address(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t bref,
|
||||
spl_type_id_t *out_tid) {
|
||||
spl_ast_node_t *n = node_at(a->sema, bref);
|
||||
@@ -1031,7 +1034,7 @@ static spl_ir_node_ref_t lower_field_address(spl_ast2ir_t *a, fnctx_t *fc, spl_a
|
||||
const char *names[MAX_FIELD_CHAIN];
|
||||
int nf = 0;
|
||||
spl_ast_node_ref_t root_ref = field_chain_base(a, pf, names, &nf);
|
||||
/* 类型命名空间基址:Foo.counter(全局 var/const <EFBFBD>?lvalue = <EFBFBD>?gdata 地址<EFBFBD>?*/
|
||||
/* 类型命名空间基址:Foo.counter(全局 var/const lvalue = gdata 地址*/
|
||||
spl_type_id_t ns = type_of_type_ref(a, fc, root_ref);
|
||||
if (ns && nf == 1) {
|
||||
spl_def_id_t gdef = def_for_type(a, ns);
|
||||
@@ -1134,10 +1137,13 @@ static spl_ir_node_ref_t index_addr(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t
|
||||
base_addr = base_lv ? emit_load(a, fc, base_t, base_lv) : base_addr;
|
||||
elem_t = underlying(a->sema, bt->ptr_pointee);
|
||||
} else if (bt && bt->kind == SPL_TYPE_SLICE) {
|
||||
spl_ir_node_ref_t slv = base_lv ? emit_load(a, fc, base_t, base_lv) : base_addr;
|
||||
elem_t = bt->slice_element;
|
||||
spl_type_id_t ep = spl_type_ptr((spl_type_t *)&a->sema->type, elem_t);
|
||||
base_addr = emit_agg_extract(a, fc, base_t, ep, 0, slv);
|
||||
if (base_lv) {
|
||||
spl_ir_node_ref_t slv = emit_load(a, fc, base_t, base_lv);
|
||||
spl_type_id_t ep = spl_type_ptr((spl_type_t *)&a->sema->type, elem_t);
|
||||
base_addr = emit_agg_extract(a, fc, base_t, ep, 0, slv);
|
||||
}
|
||||
/* base_lv==0 时 base_addr 已是切片表达式中提取出的 ptr 标量,直接复用 */
|
||||
} else {
|
||||
diag(a, fc, 0, "index requires array/slice/pointer");
|
||||
return 0;
|
||||
@@ -1442,7 +1448,7 @@ static spl_ir_node_ref_t lower_primary(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_nod
|
||||
}
|
||||
spl_type_id_t ft = agg_field_tid_or_builtin(a, hint_t, fidx);
|
||||
spl_ir_node_ref_t v = lower_expr(a, fc, item->aggregate_init_item.expr);
|
||||
/* 字段是指针、值是聚合 lvalue:自动取地址<EFBFBD>?left = expr 语义<EFBFBD>?*/
|
||||
/* 字段是指针、值是聚合 lvalue:自动取地址left = expr 语义*/
|
||||
spl_type_node_t *fld_t = ft ? tn(a->sema, ft) : NULL;
|
||||
spl_type_node_t *v_t = tn(a->sema, underlying(a->sema, node_type(fc, v)));
|
||||
if (fld_t && fld_t->kind == SPL_TYPE_PTR && v_t &&
|
||||
@@ -1525,7 +1531,7 @@ static spl_ir_node_ref_t lower_primary(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_nod
|
||||
fc->hint = tt->agg_field_types.data[i];
|
||||
spl_ir_node_ref_t v = lower_expr(a, fc, item->aggregate_init_item.expr);
|
||||
fc->hint = 0;
|
||||
/* 字段是指针、值是聚合 lvalue:自动取地址<EFBFBD>?left = expr 语义<EFBFBD>?*/
|
||||
/* 字段是指针、值是聚合 lvalue:自动取地址left = expr 语义*/
|
||||
spl_type_node_t *fld_t = tn(a->sema, tt->agg_field_types.data[i]);
|
||||
spl_type_node_t *v_t = tn(a->sema, underlying(a->sema, node_type(fc, v)));
|
||||
if (fld_t && fld_t->kind == SPL_TYPE_PTR && v_t &&
|
||||
@@ -1547,22 +1553,80 @@ static spl_ir_node_ref_t lower_primary(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_nod
|
||||
}
|
||||
case SPL_AST_BUILTIN_EXPR: {
|
||||
const char *id = pn->primary_expr.builtin_expr.ident;
|
||||
if (strcmp(id, "sizeof") == 0 && pn->primary_expr.builtin_expr.expr_list.size) {
|
||||
const spl_builtin_t *bi = spl_builtin_lookup(id);
|
||||
if (!bi) {
|
||||
diag(a, fc, 0, "unsupported builtin call");
|
||||
return 0;
|
||||
}
|
||||
usize nargs = pn->primary_expr.builtin_expr.expr_list.size;
|
||||
if (nargs < (usize)bi->min_args || (bi->max_args >= 0 && nargs > (usize)bi->max_args)) {
|
||||
diag(a, fc, 0, "builtin @arg count mismatch");
|
||||
return 0;
|
||||
}
|
||||
/* @sizeof / @bitsizeof / @alignof / @field_count: 单类型参数 → 对应 IR 类型查询节点 */
|
||||
if (bi->kind == SPL_BUILTIN_SIZE_OF || bi->kind == SPL_BUILTIN_BITSIZE_OF ||
|
||||
bi->kind == SPL_BUILTIN_ALIGN_OF || bi->kind == SPL_BUILTIN_FIELD_COUNT) {
|
||||
spl_type_id_t t =
|
||||
type_from_type_like(a, fc, pn->primary_expr.builtin_expr.expr_list.data[0]);
|
||||
if (!t) {
|
||||
diag(a, fc, 0, "sizeof: cannot resolve type");
|
||||
diag(a, fc, 0, "builtin @type query: cannot resolve type");
|
||||
return 0;
|
||||
}
|
||||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||||
spl_ir_node_t *e = enode(a, fc, n);
|
||||
e->kind = SPL_IR_TYPE_SIZEOF;
|
||||
e->ir_sizeof.tid = t;
|
||||
switch (bi->kind) {
|
||||
case SPL_BUILTIN_SIZE_OF:
|
||||
e->kind = SPL_IR_TYPE_SIZEOF;
|
||||
e->ir_sizeof.tid = t;
|
||||
break;
|
||||
case SPL_BUILTIN_BITSIZE_OF:
|
||||
e->kind = SPL_IR_TYPE_BITSIZEOF;
|
||||
e->bitsizeof.tid = t;
|
||||
break;
|
||||
case SPL_BUILTIN_ALIGN_OF:
|
||||
e->kind = SPL_IR_TYPE_ALIGNOF;
|
||||
e->ir_alignof.tid = t;
|
||||
break;
|
||||
default:
|
||||
e->kind = SPL_IR_TYPE_FIELD_COUNT;
|
||||
e->field_count.tid = t;
|
||||
break;
|
||||
}
|
||||
set_ntype(fc, n, kw_type(a, "usize"));
|
||||
return n;
|
||||
}
|
||||
if (strcmp(id, "dbg") == 0) {
|
||||
for (usize i = 0; i < pn->primary_expr.builtin_expr.expr_list.size; i++)
|
||||
/* @offsetof(T, field): 字段名 → 索引常量节点 */
|
||||
if (bi->kind == SPL_BUILTIN_OFFSET_OF) {
|
||||
spl_type_id_t t =
|
||||
type_from_type_like(a, fc, pn->primary_expr.builtin_expr.expr_list.data[0]);
|
||||
spl_ast_node_t *farg =
|
||||
node_at(a->sema, pn->primary_expr.builtin_expr.expr_list.data[1]);
|
||||
if (!t || !farg || farg->kind != SPL_AST_EXPR) {
|
||||
diag(a, fc, 0, "@offsetof: invalid arguments");
|
||||
return 0;
|
||||
}
|
||||
spl_ast_node_t *fn_ = farg->expr.op == SPL_AST_PRIMARY_EXPR
|
||||
? node_at(a->sema, farg->expr.op_expr.left)
|
||||
: NULL;
|
||||
const char *fname =
|
||||
(fn_ && fn_->primary_expr.kind == SPL_AST_IDENT) ? fn_->primary_expr.ident : NULL;
|
||||
isize fidx = fname ? agg_index_or_builtin(a, t, fname) : -1;
|
||||
if (fidx < 0) {
|
||||
diag(a, fc, 0, "@offsetof: unknown field");
|
||||
return 0;
|
||||
}
|
||||
spl_ir_node_ref_t idx = const_int(a, fc, kw_type(a, "usize"), (usize)fidx);
|
||||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||||
spl_ir_node_t *e = enode(a, fc, n);
|
||||
e->kind = SPL_IR_TYPE_OFFSETOF;
|
||||
e->ir_offsetof.tid = t;
|
||||
e->ir_offsetof.field_idx = idx;
|
||||
set_ntype(fc, n, kw_type(a, "usize"));
|
||||
return n;
|
||||
}
|
||||
/* @dbg(args...): 逐参数求值(副作用),发射断点 */
|
||||
if (bi->kind == SPL_BUILTIN_DBG) {
|
||||
for (usize i = 0; i < nargs; i++)
|
||||
lower_expr(a, fc, pn->primary_expr.builtin_expr.expr_list.data[i]);
|
||||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||||
spl_ir_node_t *e = enode(a, fc, n);
|
||||
@@ -1570,7 +1634,31 @@ static spl_ir_node_ref_t lower_primary(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_nod
|
||||
set_ntype(fc, n, kw_type(a, "void"));
|
||||
return n;
|
||||
}
|
||||
diag(a, fc, 0, "unsupported builtin call");
|
||||
/* @assert(cond): 若 cond 为假 → trap(HALT) */
|
||||
if (bi->kind == SPL_BUILTIN_ASSERT) {
|
||||
spl_ir_node_ref_t c =
|
||||
lower_expr(a, fc, pn->primary_expr.builtin_expr.expr_list.data[0]);
|
||||
usize trap_b = new_block(fc);
|
||||
usize exit_b = new_block(fc);
|
||||
emit_br(a, fc, c, exit_b, trap_b);
|
||||
begin_block(fc, trap_b);
|
||||
{
|
||||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||||
spl_ir_node_t *e = enode(a, fc, n);
|
||||
e->kind = SPL_IR_CONTROL_TRAP;
|
||||
set_ntype(fc, n, kw_type(a, "void"));
|
||||
fc->terminated = 1;
|
||||
}
|
||||
begin_block(fc, exit_b);
|
||||
spl_ir_node_ref_t r = emit_node(a, fc);
|
||||
spl_ir_node_t *e = enode(a, fc, r);
|
||||
e->kind = SPL_IR_TYPE_CONST;
|
||||
e->type_const.tid = kw_type(a, "void");
|
||||
set_ntype(fc, r, kw_type(a, "void"));
|
||||
return r;
|
||||
}
|
||||
/* @import: 预留未实现 */
|
||||
diag(a, fc, 0, "builtin @import not implemented");
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
@@ -1719,7 +1807,7 @@ static int resolve_callee(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t base,
|
||||
vt = underlying(a->sema, vtt->ptr_pointee);
|
||||
vtt = tn(a->sema, vt);
|
||||
}
|
||||
/* enum 方法:在原 enum def 上查找 */
|
||||
/* enum 方法:在enum def 上查*/
|
||||
spl_type_id_t lookup = vt;
|
||||
spl_type_id_t e0 = 0;
|
||||
if (vtt && is_enum_expand(a, vt, &e0))
|
||||
@@ -1759,7 +1847,7 @@ static spl_ir_node_ref_t lower_field(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_
|
||||
if (vidx >= 0)
|
||||
return enum_variant_value(a, fc, ttr, vidx);
|
||||
}
|
||||
/* 聚合命名空间成员:static var/const <EFBFBD>?全局数据 */
|
||||
/* 聚合命名空间成员:static var/const 全局数据 */
|
||||
spl_def_id_t gdef = def_for_type(a, ttr);
|
||||
spl_def_node_t *gd = gdef ? def_at(a->sema, gdef) : NULL;
|
||||
for (usize i = 0; gd && i < gd->agg_def.size; i++) {
|
||||
@@ -1868,6 +1956,12 @@ static spl_ir_node_ref_t lower_postfix(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_nod
|
||||
case SPL_AST_SLICE_EXPR: {
|
||||
spl_type_id_t bt = 0;
|
||||
spl_ir_node_ref_t base_lv = lower_lvalue(a, fc, pf->postfix_expr.primary_expr, &bt);
|
||||
spl_ir_node_ref_t base_val = 0;
|
||||
if (!base_lv) {
|
||||
/* base 是切片/数组表达式(如 arr[1..4][1..2]):取值后提取字段 */
|
||||
base_val = lower_expr(a, fc, pf->postfix_expr.primary_expr);
|
||||
bt = node_type(fc, base_val);
|
||||
}
|
||||
spl_type_node_t *tt = tn(a->sema, underlying(a->sema, bt));
|
||||
if (!tt || (tt->kind != SPL_TYPE_ARRAY && tt->kind != SPL_TYPE_SLICE)) {
|
||||
diag(a, fc, 0, "slice requires array/slice");
|
||||
@@ -1882,7 +1976,7 @@ static spl_ir_node_ref_t lower_postfix(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_nod
|
||||
base_ptr = base_lv;
|
||||
total_len = const_int(a, fc, kw_type(a, "usize"), tt->array_type.len);
|
||||
} else {
|
||||
spl_ir_node_ref_t slv = emit_load(a, fc, bt, base_lv);
|
||||
spl_ir_node_ref_t slv = base_lv ? emit_load(a, fc, bt, base_lv) : base_val;
|
||||
spl_type_id_t ep = spl_type_ptr((spl_type_t *)&a->sema->type, elem);
|
||||
base_ptr = emit_agg_extract(a, fc, bt, ep, 0, slv);
|
||||
total_len = emit_agg_extract(a, fc, bt, kw_type(a, "usize"), 1, slv);
|
||||
@@ -2167,7 +2261,7 @@ static spl_ir_node_ref_t lower_assign(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node
|
||||
lt = it->tid;
|
||||
target = it->slot;
|
||||
} else {
|
||||
/* 全局 var(顶<EFBFBD>?/ 命名空间裸名<EFBFBD>?*/
|
||||
/* 全局 var(顶/ 命名空间裸名*/
|
||||
spl_def_id_t def = pn->resolved_def_id;
|
||||
if (!def)
|
||||
def = root_lookup(a, pn->primary_expr.ident);
|
||||
@@ -2276,6 +2370,8 @@ static spl_ir_node_ref_t lower_expr(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_r
|
||||
spl_ast_node_t *n = node_at(a->sema, ref);
|
||||
if (!n || n->kind != SPL_AST_EXPR)
|
||||
return 0;
|
||||
if (ref)
|
||||
fc->cur_src = ref; /* 调试行号:当前语*/
|
||||
switch (n->expr.op) {
|
||||
case SPL_AST_PRIMARY_EXPR:
|
||||
return lower_primary(a, fc, node_at(a->sema, n->expr.op_expr.left));
|
||||
@@ -2369,6 +2465,9 @@ static void lower_var_decl(spl_ast2ir_t *a, fnctx_t *fc, const char *name, spl_d
|
||||
emit_store(a, fc, tid, slot, v);
|
||||
}
|
||||
env_add(fc, name, def_id, tid, slot, 0, 0, 1);
|
||||
/* 调试:登记变量名 alloca 节点 */
|
||||
spl_ir_dbg_var_t dv = {name, slot, tid, 0, 0};
|
||||
vec_push(a->ir.funcs.data[fc->fn].dbg_vars, dv);
|
||||
}
|
||||
|
||||
static void lower_if(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *b) {
|
||||
@@ -2468,6 +2567,18 @@ static void for_seq_setup(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t eref,
|
||||
spl_ir_node_ref_t v = lower_expr(a, fc, eref);
|
||||
spl_type_id_t vt = underlying(a->sema, node_type(fc, v));
|
||||
spl_type_node_t *vtt = vt ? tn(a->sema, vt) : NULL;
|
||||
if (vtt && vtt->kind == SPL_TYPE_RANGE) {
|
||||
/* Range 值:内部 { begin, end },迭代 begin..end-1 */
|
||||
s->kind = FOR_RANGE;
|
||||
s->elem_tid = vtt->range_element;
|
||||
s->begin_slot = emit_alloca(a, fc, s->elem_tid);
|
||||
emit_store(a, fc, s->elem_tid, s->begin_slot,
|
||||
emit_agg_extract(a, fc, vt, s->elem_tid, 0, v));
|
||||
spl_ir_node_ref_t end = emit_agg_extract(a, fc, vt, s->elem_tid, 1, v);
|
||||
spl_ir_node_ref_t b = emit_load(a, fc, s->elem_tid, s->begin_slot);
|
||||
s->len = emit_arith(a, fc, SPL_IR_ARITH_SUB, s->elem_tid, end, b);
|
||||
return;
|
||||
}
|
||||
if (vtt && vtt->kind == SPL_TYPE_SLICE) {
|
||||
s->kind = FOR_SLICE;
|
||||
s->elem_tid = vtt->slice_element;
|
||||
@@ -2640,13 +2751,26 @@ static void lower_match(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *b) {
|
||||
emit_jmp(a, fc, body_b);
|
||||
} else {
|
||||
spl_ir_node_ref_t cond = 0;
|
||||
if (is_enum && pk->packed_expr.ident) {
|
||||
isize vidx = enum_variant_index(a, st, pk->packed_expr.ident);
|
||||
if (vidx < 0)
|
||||
vidx = 0;
|
||||
spl_ir_node_ref_t tv = emit_load(a, fc, tag_t, tag_slot);
|
||||
spl_ir_node_ref_t idxc = const_int(a, fc, tag_t, (usize)vidx);
|
||||
cond = emit_cmp(a, fc, SPL_IR_CMP_EQ, tag_t, tv, idxc);
|
||||
const char *vname = NULL;
|
||||
if (is_enum) {
|
||||
/* 变体名:`.Red`(ident)或 `Tag.ident`(expr 字段路径)两种形式 */
|
||||
vname = pk->packed_expr.ident;
|
||||
if (!vname && pk->packed_expr.expr) {
|
||||
spl_ast_node_t *en = node_at(a->sema, pk->packed_expr.expr);
|
||||
if (en && en->kind == SPL_AST_EXPR && en->expr.op == SPL_AST_POSTFIX_EXPR) {
|
||||
spl_ast_node_t *epf = node_at(a->sema, en->expr.op_expr.left);
|
||||
if (epf && epf->postfix_expr.kind == SPL_AST_FIELD_EXPR)
|
||||
vname = epf->postfix_expr.field_expr;
|
||||
}
|
||||
}
|
||||
if (vname) {
|
||||
isize vidx = enum_variant_index(a, st, vname);
|
||||
if (vidx < 0)
|
||||
vidx = 0;
|
||||
spl_ir_node_ref_t tv = emit_load(a, fc, tag_t, tag_slot);
|
||||
spl_ir_node_ref_t idxc = const_int(a, fc, tag_t, (usize)vidx);
|
||||
cond = emit_cmp(a, fc, SPL_IR_CMP_EQ, tag_t, tv, idxc);
|
||||
}
|
||||
} else if (is_int && pk->packed_expr.expr) {
|
||||
spl_ir_node_ref_t sv = emit_load(a, fc, st, subj_slot);
|
||||
spl_ir_node_ref_t pv = lower_expr(a, fc, pk->packed_expr.expr);
|
||||
@@ -2665,7 +2789,7 @@ static void lower_match(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *b) {
|
||||
spl_type_id_t pt = enum_payload_tid(a, st, vidx);
|
||||
if (pt) {
|
||||
spl_ir_node_ref_t sv = emit_load(a, fc, st, subj_slot);
|
||||
/* enum 布局 = tag(0) + payload(8):直接提<EFBFBD>?payload,field_tid = 变体具体类型 */
|
||||
/* enum 布局 = tag(0) + payload(8):直接提payload,field_tid = 变体具体类型 */
|
||||
spl_ir_node_ref_t pv = emit_agg_extract(a, fc, st, pt, 1, sv);
|
||||
spl_ir_node_ref_t bslot = emit_alloca(a, fc, pt);
|
||||
emit_store(a, fc, pt, bslot, pv);
|
||||
@@ -2729,9 +2853,23 @@ static void lower_stmt(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref) {
|
||||
case SPL_AST_IF_STATEMENT:
|
||||
lower_if(a, fc, b);
|
||||
break;
|
||||
case SPL_AST_IFVAR_STATEMENT:
|
||||
diag(a, fc, ref, "if-var not supported");
|
||||
case SPL_AST_IFVAR_STATEMENT: {
|
||||
/* if var .x[y] = e { }:绑定新变量 y = e,进入 if 块(sema 语义)
|
||||
* 若 bind_ident 为空(if var .x = e),则不绑定,仅进入 if 块 */
|
||||
spl_ast_node_t *pk = node_at(a->sema, b->block_item.ifvar_statement.packed_expr);
|
||||
if (pk && pk->packed_expr.bind_ident && pk->packed_expr.expr) {
|
||||
spl_ir_node_ref_t ev = lower_expr(a, fc, pk->packed_expr.expr);
|
||||
spl_type_id_t vt = underlying(a->sema, node_type(fc, ev));
|
||||
spl_ir_node_ref_t bslot = emit_alloca(a, fc, vt);
|
||||
emit_store(a, fc, vt, bslot, ev);
|
||||
env_add(fc, pk->packed_expr.bind_ident, 0, vt, bslot, 0, 0, 0);
|
||||
}
|
||||
env_push(fc);
|
||||
lower_block(a, fc, &b->block_item.ifvar_statement.if_block);
|
||||
env_pop(fc);
|
||||
/* else 分支:无失败语义,不发射 */
|
||||
break;
|
||||
}
|
||||
case SPL_AST_WHILE_STATEMENT:
|
||||
lower_while(a, fc, b);
|
||||
break;
|
||||
@@ -2784,7 +2922,7 @@ static void lower_stmt(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref) {
|
||||
* ================================================================ */
|
||||
|
||||
static spl_ir_func_ref_t a2ir_fn_of(spl_ast2ir_t *a, spl_type_id_t fn_tid) {
|
||||
/* 懒扫描:IR func 已记<EFBFBD>?fn_tid(spl_type_fn 不去重,fn_tid 唯一<EFBFBD>?*/
|
||||
/* 懒扫描:IR func 已记fn_tid(spl_type_fn 不去重,fn_tid 唯一*/
|
||||
for (usize i = 1; i < a->ir.funcs.size; i++) {
|
||||
if (a->ir.funcs.data[i].fn_tid == fn_tid)
|
||||
return i;
|
||||
@@ -2818,6 +2956,9 @@ static void lower_func_body(spl_ast2ir_t *a, spl_ir_func_ref_t fid, spl_type_id_
|
||||
spl_ir_node_ref_t slot = emit_alloca(a, &fc, pt);
|
||||
emit_store(a, &fc, pt, slot, pr);
|
||||
env_add(&fc, pd->param_decl.name, pd->resolved_def_id, pt, slot, 0, 0, 0);
|
||||
/* 调试:参数登记(值在参数区,fp 偏移ir2vm param_off 填) */
|
||||
spl_ir_dbg_var_t dv = {pd->param_decl.name, slot, pt, 1, (usize)i};
|
||||
vec_push(a->ir.funcs.data[fid].dbg_vars, dv);
|
||||
}
|
||||
begin_block(&fc, new_block(&fc));
|
||||
lower_block(a, &fc, &fn->fn_decl.block);
|
||||
@@ -2870,10 +3011,10 @@ void spl_ast2ir_drop(spl_ast2ir_t *ast2ir) {
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* 全局数据(聚合类型下 / 顶层<EFBFBD>?var、const<EFBFBD>?
|
||||
* 全局数据(聚合类型下 / 顶层var、const
|
||||
* ================================================================ */
|
||||
|
||||
/* 常量折叠:仅支持字面量(int/char/float/string/null)与一元负<EFBFBD>?*/
|
||||
/* 常量折叠:仅支持字面量(int/char/float/string/null)与一元负*/
|
||||
typedef struct {
|
||||
int const_init;
|
||||
isize int_v;
|
||||
@@ -2937,6 +3078,13 @@ static void collect_gdata_list(spl_ast2ir_t *a, spl_ast_node_ref_vec_t *members)
|
||||
} else if (m->kind == SPL_AST_CONST_DECL) {
|
||||
mname = m->const_decl.name;
|
||||
iexpr = m->const_decl.expr;
|
||||
} else if (m->kind == SPL_AST_MEMBER_DECL) {
|
||||
/* 顶层裸成员(文件级 IDENT: T)视为全局 var;聚合体内 MEMBER_DECL 是字段不收集 */
|
||||
spl_def_node_t *md = m->resolved_def_id ? def_at(a->sema, m->resolved_def_id) : NULL;
|
||||
if (!md || md->kind != SPL_DEF_VAR)
|
||||
continue;
|
||||
mname = m->member_decl.name;
|
||||
iexpr = 0;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
@@ -2950,7 +3098,7 @@ static void collect_gdata_list(spl_ast2ir_t *a, spl_ast_node_ref_vec_t *members)
|
||||
spl_type_id_t g_tid = d->type_id;
|
||||
if (iexpr)
|
||||
fold_const_init(a, iexpr, &g);
|
||||
/* 全局 value = type.const 节点(标量折叠值;聚合/无 init 零) */
|
||||
/* 全局 value = type.const 节点(标量折叠值;聚合/init 零) */
|
||||
spl_ir_node_t v;
|
||||
memset(&v, 0, sizeof v);
|
||||
v.kind = SPL_IR_TYPE_CONST;
|
||||
@@ -2987,7 +3135,7 @@ static void collect_gdata(spl_ast2ir_t *a) {
|
||||
}
|
||||
}
|
||||
|
||||
/* def_id <EFBFBD>?gdata value 节点索引;未命中返回 -1 */
|
||||
/* def_id gdata value 节点索引;未命中返回 -1 */
|
||||
static isize gdata_index_by_def(spl_ast2ir_t *a, spl_def_id_t def_id) {
|
||||
for (usize i = 0; i < a->gdata_ref.size; i++)
|
||||
if (a->gdata_ref.data[i].def_id == def_id)
|
||||
|
||||
28
stage1/spl_builtin.c
Normal file
28
stage1/spl_builtin.c
Normal file
@@ -0,0 +1,28 @@
|
||||
/* spl_builtin.c — 内置函数集中注册表实现 */
|
||||
|
||||
#include "spl_builtin.h"
|
||||
#include "../stage0/include/utils.h"
|
||||
#include <string.h>
|
||||
|
||||
static const spl_builtin_t k_builtins[] = {
|
||||
{"sizeof", SPL_BUILTIN_SIZE_OF, 1, 1, 0},
|
||||
{"bitsizeof", SPL_BUILTIN_BITSIZE_OF, 1, 1, 0},
|
||||
{"alignof", SPL_BUILTIN_ALIGN_OF, 1, 1, 0},
|
||||
{"offsetof", SPL_BUILTIN_OFFSET_OF, 2, 2, 0},
|
||||
{"field_count", SPL_BUILTIN_FIELD_COUNT, 1, 1, 0},
|
||||
{"dbg", SPL_BUILTIN_DBG, 0, -1, 1},
|
||||
{"assert", SPL_BUILTIN_ASSERT, 1, 1, 1},
|
||||
{"import", SPL_BUILTIN_IMPORT, 1, 1, 1},
|
||||
};
|
||||
|
||||
const spl_builtin_t *spl_builtin_lookup(const char *name) {
|
||||
if (!name)
|
||||
return NULL;
|
||||
for (usize i = 0; i < sizeof(k_builtins) / sizeof(k_builtins[0]); i++) {
|
||||
if (strcmp(k_builtins[i].name, name) == 0)
|
||||
return &k_builtins[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int spl_builtin_count(void) { return (int)(sizeof(k_builtins) / sizeof(k_builtins[0])); }
|
||||
43
stage1/spl_builtin.h
Normal file
43
stage1/spl_builtin.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* spl_builtin.h — 内置函数集中注册表
|
||||
*
|
||||
* @builtin 名称/类别/参数/返回类型的单一事实来源。
|
||||
* sema(类型推导)与 ast2ir(IR 发射)各自按 kind 分发实现。
|
||||
*/
|
||||
#ifndef __SPL_BUILTIN_H__
|
||||
#define __SPL_BUILTIN_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
SPL_BUILTIN_SIZE_OF, /* @sizeof(T) -> usize */
|
||||
SPL_BUILTIN_BITSIZE_OF, /* @bitsizeof(T) -> usize */
|
||||
SPL_BUILTIN_ALIGN_OF, /* @alignof(T) -> usize */
|
||||
SPL_BUILTIN_OFFSET_OF, /* @offsetof(T, field) -> usize */
|
||||
SPL_BUILTIN_FIELD_COUNT, /* @field_count(T) -> usize */
|
||||
SPL_BUILTIN_DBG, /* @dbg(args...) -> void */
|
||||
SPL_BUILTIN_ASSERT, /* @assert(cond) -> void */
|
||||
SPL_BUILTIN_IMPORT, /* @import(path) -> 模块 (预留) */
|
||||
SPL_BUILTIN_COUNT
|
||||
} spl_builtin_kind_t;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
spl_builtin_kind_t kind;
|
||||
int min_args; /* 参数个数下限 */
|
||||
int max_args; /* 参数个数上限,-1 = 不限 */
|
||||
int ret_is_void; /* 1 = void 返回 */
|
||||
} spl_builtin_t;
|
||||
|
||||
/* 按名称查找内置;未注册返回 NULL */
|
||||
const spl_builtin_t *spl_builtin_lookup(const char *name);
|
||||
|
||||
/* 内置总数 */
|
||||
int spl_builtin_count(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SPL_BUILTIN_H__ */
|
||||
@@ -44,6 +44,7 @@ void spl_ir_drop(spl_ir_t *ir) {
|
||||
node_drop_vecs(&f->nodes.data[j]);
|
||||
vec_free(f->nodes);
|
||||
vec_free(f->labels);
|
||||
vec_free(f->dbg_vars);
|
||||
}
|
||||
vec_free(ir->funcs);
|
||||
for (usize i = 0; i < ir->gdata.size; i++)
|
||||
@@ -56,6 +57,7 @@ spl_ir_func_ref_t spl_ir_alloc_fn(spl_ir_t *ir) {
|
||||
memset(&f, 0, sizeof f);
|
||||
vec_init(f.nodes);
|
||||
vec_init(f.labels);
|
||||
vec_init(f.dbg_vars);
|
||||
vec_push(ir->funcs, f);
|
||||
return ir->funcs.size - 1;
|
||||
}
|
||||
@@ -504,3 +506,14 @@ void spl_ir_dump(spl_ir_t *ir, const spl_type_t *ty) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *spl_ir_kind_name(spl_ir_kind_t kind) {
|
||||
static const char *const names[] = {
|
||||
#define X(a, b, c) #a,
|
||||
SPL_IR_FN_TABLE
|
||||
#undef X
|
||||
};
|
||||
if ((usize)kind < sizeof(names) / sizeof(names[0]))
|
||||
return names[kind];
|
||||
return "?";
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@ typedef usize spl_ir_func_ref_t; /* 0 is error */
|
||||
|
||||
typedef struct {
|
||||
spl_ir_kind_t kind;
|
||||
usize src_ref; /* AST 节点 ref(调试行号用,ast2ir 注解) */
|
||||
union {
|
||||
struct {
|
||||
spl_type_id_t tid;
|
||||
@@ -236,12 +237,25 @@ typedef struct {
|
||||
};
|
||||
} spl_ir_attr_t;
|
||||
typedef VEC(spl_ir_attr_t) spl_ir_attr_vec_t;
|
||||
|
||||
/* 调试:函数内变量(名 → 内存位置)。alloca 节点或参数槽。 */
|
||||
typedef struct {
|
||||
const char *name; /* 指向 AST 字符串,不拥有 */
|
||||
spl_ir_node_ref_t alloca; /* 非参数:alloca 节点 ref */
|
||||
spl_type_id_t tid;
|
||||
int is_param; /* 参数则用 param_idx */
|
||||
usize param_idx;
|
||||
usize offset; /* fp 字节偏移(LADDR imm 语义;ir2vm 填) */
|
||||
} spl_ir_dbg_var_t;
|
||||
typedef VEC(spl_ir_dbg_var_t) spl_ir_dbg_var_vec_t;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
spl_ir_attr_t attr;
|
||||
spl_type_id_t fn_tid;
|
||||
spl_ir_node_vec_t nodes;
|
||||
spl_ir_node_ref_vec_t labels;
|
||||
spl_ir_dbg_var_vec_t dbg_vars; /* 调试变量表(fp 偏移在 ir2vm 填) */
|
||||
} spl_ir_func_t;
|
||||
|
||||
typedef VEC(spl_ir_func_t) spl_ir_func_vec_t;
|
||||
@@ -261,5 +275,6 @@ spl_ir_node_t *spl_ir_node(spl_ir_t *ir, spl_ir_func_ref_t fn_id, spl_ir_node_re
|
||||
spl_ir_func_t *spl_ir_func(spl_ir_t *ir, spl_ir_func_ref_t fn_id);
|
||||
|
||||
void spl_ir_dump(spl_ir_t *ir, const spl_type_t *ty);
|
||||
const char *spl_ir_kind_name(spl_ir_kind_t kind);
|
||||
|
||||
#endif /* __SPL_IR_H__ */
|
||||
|
||||
@@ -709,7 +709,16 @@ static void emit_node(fctx_t *fc, spl_ir_node_ref_t ref) {
|
||||
emit_value(fc, n->arith.left);
|
||||
if (n->arith.right)
|
||||
emit_value(fc, n->arith.right);
|
||||
emit_arith(fc, arith_op(n->kind, is_signed_type(ty, tid)), arith_tag(ty, tid));
|
||||
spl_opcode_t aop = arith_op(n->kind, is_signed_type(ty, tid));
|
||||
/* 浮点除法/取余:VM 的 DIV_S/REM_S 宏(DIV_REM_S)含 float 分支,DIV_U/REM_U 无 */
|
||||
spl_type_node_t *at = tn(ty, under(ty, tid));
|
||||
if (at && at->kind == SPL_TYPE_FLOAT) {
|
||||
if (n->kind == SPL_IR_ARITH_DIV)
|
||||
aop = SPL_DIV_S;
|
||||
else if (n->kind == SPL_IR_ARITH_REM)
|
||||
aop = SPL_REM_S;
|
||||
}
|
||||
emit_arith(fc, aop, arith_tag(ty, tid));
|
||||
emit_store_vreg(fc, ref);
|
||||
return;
|
||||
}
|
||||
@@ -753,6 +762,11 @@ static void emit_node(fctx_t *fc, spl_ir_node_ref_t ref) {
|
||||
emit_value(fc, n->cmp.a);
|
||||
emit_value(fc, n->cmp.b);
|
||||
spl_opcode_t op;
|
||||
/* 浮点顺序比较:VM 的 CMP_U 无 float 分支,须走 CMP_S(SLT/SLE/SGT/SGE 含 float case) */
|
||||
int is_f = 0;
|
||||
spl_type_node_t *ct = tn(ty, under(ty, tid));
|
||||
if (ct && ct->kind == SPL_TYPE_FLOAT)
|
||||
is_f = 1;
|
||||
switch (n->kind) {
|
||||
case SPL_IR_CMP_EQ:
|
||||
op = SPL_EQ;
|
||||
@@ -761,16 +775,16 @@ static void emit_node(fctx_t *fc, spl_ir_node_ref_t ref) {
|
||||
op = SPL_NE;
|
||||
break;
|
||||
case SPL_IR_CMP_LT:
|
||||
op = is_signed_type(ty, tid) ? SPL_SLT : SPL_ULT;
|
||||
op = (is_signed_type(ty, tid) || is_f) ? SPL_SLT : SPL_ULT;
|
||||
break;
|
||||
case SPL_IR_CMP_LE:
|
||||
op = is_signed_type(ty, tid) ? SPL_SLE : SPL_ULE;
|
||||
op = (is_signed_type(ty, tid) || is_f) ? SPL_SLE : SPL_ULE;
|
||||
break;
|
||||
case SPL_IR_CMP_GT:
|
||||
op = is_signed_type(ty, tid) ? SPL_SGT : SPL_UGT;
|
||||
op = (is_signed_type(ty, tid) || is_f) ? SPL_SGT : SPL_UGT;
|
||||
break;
|
||||
default:
|
||||
op = is_signed_type(ty, tid) ? SPL_SGE : SPL_UGE;
|
||||
op = (is_signed_type(ty, tid) || is_f) ? SPL_SGE : SPL_UGE;
|
||||
break;
|
||||
}
|
||||
emit_arith(fc, op, arith_tag(ty, tid));
|
||||
@@ -845,8 +859,13 @@ static void emit_node(fctx_t *fc, spl_ir_node_ref_t ref) {
|
||||
case SPL_IR_MEM_OFFSET: {
|
||||
emit_value(fc, n->mem_offset.ptr);
|
||||
emit_value(fc, n->mem_offset.offset);
|
||||
emit_push(fc, type_size(ty, n->mem_offset.tid));
|
||||
emit_arith(fc, SPL_MUL, SPL_USIZE);
|
||||
/* 指针运算(C 语义):*_(void 元素)看成整数,偏移即字节、不 scale;
|
||||
* *T(非 void)偏移为元素索引,乘 sizeof(T)。 */
|
||||
spl_type_id_t ut = under(ty, n->mem_offset.tid);
|
||||
if (!is_void(ty, ut)) {
|
||||
emit_push(fc, type_size(ty, n->mem_offset.tid));
|
||||
emit_arith(fc, SPL_MUL, SPL_USIZE);
|
||||
}
|
||||
emit_arith(fc, SPL_ADD, SPL_USIZE);
|
||||
emit_store_vreg(fc, ref);
|
||||
return;
|
||||
@@ -1032,14 +1051,18 @@ static void emit_node(fctx_t *fc, spl_ir_node_ref_t ref) {
|
||||
vec_push(fc->c->fnfixes, fx);
|
||||
add_insn(fc, SPL_CALL, SPL_VOID, nargs);
|
||||
}
|
||||
if (ret && !is_agg(ty, ret))
|
||||
emit_store_vreg(fc, ref);
|
||||
} else {
|
||||
/* 间接调用:栈 [args, func_addr, nargs] CALLI */
|
||||
emit_value(fc, n->control_call.func);
|
||||
/* 间接调用:栈 [args, nargs, func_addr] CALLI(VM: POP addr, POP nargs)
|
||||
* 先 push 实参(上方循环),再 push nargs,最后 push func_addr */
|
||||
emit_push(fc, nargs);
|
||||
emit_value(fc, n->control_call.func);
|
||||
add_insn(fc, SPL_CALLI, SPL_VOID, 0);
|
||||
/* 返回值留在栈顶,与直接调用一致:存入 vreg */
|
||||
if (ret && !is_agg(ty, ret))
|
||||
emit_store_vreg(fc, ref);
|
||||
}
|
||||
if (ret && !is_agg(ty, ret))
|
||||
emit_store_vreg(fc, ref);
|
||||
return;
|
||||
}
|
||||
case SPL_IR_CONTROL_RET: {
|
||||
@@ -1065,10 +1088,12 @@ static void emit_node(fctx_t *fc, spl_ir_node_ref_t ref) {
|
||||
return;
|
||||
}
|
||||
case SPL_IR_CONTROL_UNREACHABLE:
|
||||
case SPL_IR_CONTROL_TRAP:
|
||||
diag(fc->c, fc->fid, ref, "control.unreachable/trap not implemented");
|
||||
add_insn(fc, SPL_HALT, SPL_VOID, 0);
|
||||
return;
|
||||
case SPL_IR_CONTROL_TRAP:
|
||||
/* trap → halt 带非零退出码(assert 失败语义) */
|
||||
add_insn(fc, SPL_HALT, SPL_VOID, 1);
|
||||
return;
|
||||
case SPL_IR_DBG_BREAKPOINT:
|
||||
add_insn(fc, SPL_BK, SPL_VOID, 0);
|
||||
return;
|
||||
@@ -1185,8 +1210,9 @@ static void gen_func(ctx_t *c, spl_ir_func_ref_t fid) {
|
||||
usize locals = 0;
|
||||
for (usize ref = 1; ref < fc.f->nodes.size; ref++) {
|
||||
spl_ir_node_t *rn = &fc.f->nodes.data[ref];
|
||||
if (!produces_value(rn->kind))
|
||||
continue;
|
||||
/* 无条件分配(不按 produces_value 过滤):某些节点 produces_value 误报 0 但
|
||||
* 仍会被 emit_value 引用并 store_vreg(如聚合字段提取编译成的节点)。若跳过则
|
||||
* vreg_off 保持 calloc 的 0,多个节点共享槽 0 互相覆盖(指针偏移/写地址损坏根源)。 */
|
||||
spl_type_id_t tid = 0;
|
||||
if (!needs_vreg_slot(fc.f, ref)) {
|
||||
/* 聚合值参数:分配 vreg(prologue 从参数区 memcpy 进来) */
|
||||
@@ -1200,8 +1226,13 @@ static void gen_func(ctx_t *c, spl_ir_func_ref_t fid) {
|
||||
if (rn->kind == SPL_IR_MEM_ALLOCA)
|
||||
tid = rn->mem_alloc.tid;
|
||||
}
|
||||
if (!tid)
|
||||
if (!tid) {
|
||||
/* tid 未解析(MEM_LOAD / BITCAST 未标 tid 等):占位一个 usize 槽,
|
||||
* 否则 vreg_off 保持 0,多个节点共享槽 0 互相覆盖。 */
|
||||
fc.vreg_off[ref] = align_up(locals, 8);
|
||||
locals = fc.vreg_off[ref] + 8;
|
||||
continue;
|
||||
}
|
||||
usize sz = type_size(ty, tid);
|
||||
usize al = type_align(ty, tid);
|
||||
if (is_agg(ty, tid))
|
||||
@@ -1211,7 +1242,9 @@ static void gen_func(ctx_t *c, spl_ir_func_ref_t fid) {
|
||||
locals += sz;
|
||||
}
|
||||
fc.temp_off = align_up(locals, 8);
|
||||
locals = fc.temp_off + 8; /* mem.set 计数器槽 */
|
||||
/* 临时区(bytes):表达式/调用的 PUSH/POP 堆叠、store/bnz 的弹栈会临时压低 sp,
|
||||
* 若无此区 sp 会降入 vreg 槽区覆盖尚未使用的 vreg(大数组构造等深表达式)。 */
|
||||
locals = fc.temp_off + 8 + 1024 * 8;
|
||||
fc.locals_bytes = locals;
|
||||
|
||||
/* prologue:ALLOC + 聚合值参数 memcpy(参数区 → param vreg) */
|
||||
|
||||
@@ -79,9 +79,17 @@
|
||||
* ================================================================
|
||||
*/
|
||||
|
||||
/* 调试映射:每函数 IR 节点 → 首条指令 ip(调试器显示当前 IR 节点用) */
|
||||
typedef struct {
|
||||
spl_ir_func_ref_t fid;
|
||||
VEC(usize) node_first_ip; /* 索引 = IR 节点 ref,值 = 该节点首指令绝对 ip */
|
||||
} spl_ir2vm_fdbg_t;
|
||||
typedef VEC(spl_ir2vm_fdbg_t) spl_ir2vm_fdbg_vec_t;
|
||||
|
||||
typedef struct {
|
||||
const spl_ir_t *ir;
|
||||
const spl_type_t *type;
|
||||
spl_ir2vm_fdbg_vec_t fdbg; /* ir2vm_run 后填充;splc0 -g 读取生成 debug 段 */
|
||||
} spl_ir2vm_t;
|
||||
|
||||
void spl_ir2vm_init(spl_ir2vm_t *ctx, const spl_ir_t *ir, const spl_type_t *type);
|
||||
|
||||
@@ -270,7 +270,8 @@ spl_tok_vec_t spl_lex(const char *source, const char *fname) {
|
||||
/* Hex literal */
|
||||
offset += 2;
|
||||
col += 2;
|
||||
while (offset < len && isxdigit((unsigned char)source[offset])) {
|
||||
while (offset < len &&
|
||||
(isxdigit((unsigned char)source[offset]) || source[offset] == '_')) {
|
||||
offset++;
|
||||
col++;
|
||||
}
|
||||
@@ -280,7 +281,8 @@ spl_tok_vec_t spl_lex(const char *source, const char *fname) {
|
||||
/* Binary literal */
|
||||
offset += 2;
|
||||
col += 2;
|
||||
while (offset < len && (source[offset] == '0' || source[offset] == '1')) {
|
||||
while (offset < len && (source[offset] == '0' || source[offset] == '1' ||
|
||||
source[offset] == '_')) {
|
||||
offset++;
|
||||
col++;
|
||||
}
|
||||
@@ -290,7 +292,8 @@ spl_tok_vec_t spl_lex(const char *source, const char *fname) {
|
||||
/* Octal literal */
|
||||
offset += 2;
|
||||
col += 2;
|
||||
while (offset < len && source[offset] >= '0' && source[offset] <= '7') {
|
||||
while (offset < len && ((source[offset] >= '0' && source[offset] <= '7') ||
|
||||
source[offset] == '_')) {
|
||||
offset++;
|
||||
col++;
|
||||
}
|
||||
@@ -299,7 +302,8 @@ spl_tok_vec_t spl_lex(const char *source, const char *fname) {
|
||||
}
|
||||
|
||||
/* Decimal integer or float */
|
||||
while (offset < len && isdigit((unsigned char)source[offset])) {
|
||||
while (offset < len &&
|
||||
(isdigit((unsigned char)source[offset]) || source[offset] == '_')) {
|
||||
offset++;
|
||||
col++;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// WRITE BY AI
|
||||
// WRITE BY AI
|
||||
/* spl_sema.c SPL 语义分析
|
||||
*
|
||||
* 两趟 AST 遍历(splc0 显式先 run 再 check):
|
||||
@@ -9,6 +9,7 @@
|
||||
* 命名实体放 def_table,两张表 id 空间完全独立。
|
||||
*/
|
||||
#include "spl_sema.h"
|
||||
#include "spl_builtin.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -456,6 +457,13 @@ static void sema_const_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_
|
||||
if (!n)
|
||||
return;
|
||||
register_binding(sema, n->const_decl.name, n->const_decl.type_expr, scope, agg_def, ref);
|
||||
/* 标记 const:赋值检查拒绝写入 */
|
||||
spl_ast_node_t *nn = node_at(sema->ast, ref);
|
||||
if (nn && nn->resolved_def_id) {
|
||||
spl_def_node_t *d = def_at(sema, nn->resolved_def_id);
|
||||
if (d)
|
||||
d->var_def.is_const = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* fn 声明:建 fn type + FN_PARAMS def + 登记名字。不建 fn_scope(由 check 新建)。
|
||||
@@ -580,6 +588,29 @@ static bool expr_is_int_literal(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
}
|
||||
}
|
||||
|
||||
/* 浮点字面量(含负号前缀):允许拓宽/窄化到目标浮点类型 */
|
||||
static bool expr_is_float_literal(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
spl_ast_node_t *n = node_at(sema->ast, ref);
|
||||
if (!n || n->kind != SPL_AST_EXPR)
|
||||
return false;
|
||||
switch (n->expr.op) {
|
||||
case SPL_AST_PRIMARY_EXPR: {
|
||||
spl_ast_node_t *pn = node_at(sema->ast, n->expr.op_expr.left);
|
||||
int k = pn && pn->kind == SPL_AST_EXPR ? (int)pn->primary_expr.kind : -1;
|
||||
return k == SPL_AST_FLOAT;
|
||||
}
|
||||
case SPL_AST_PREFIX_EXPR:
|
||||
return expr_is_float_literal(sema, n->expr.op_expr.left);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* 字面量(整型或浮点):检查时允许类型拓宽 */
|
||||
static bool expr_is_literal(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
return expr_is_int_literal(sema, ref) || expr_is_float_literal(sema, ref);
|
||||
}
|
||||
|
||||
/* 打开 SPL_TYPE_ID 绑定节点,返回真实类型(newtype 预留;当前无调用产生该节点) */
|
||||
static spl_type_id_t underlying(spl_sema_t *sema, spl_type_id_t tid) {
|
||||
spl_type_node_t *t = type_node(sema, tid);
|
||||
@@ -650,6 +681,9 @@ static int type_compatible(spl_sema_t *sema, spl_type_id_t dst, spl_type_id_t sr
|
||||
/* 字面量值已隐含满足范围(检查时由调用方保证),此处允许拓宽 */
|
||||
return 1;
|
||||
}
|
||||
/* 浮点字面量可赋值到目标浮点(f64 字面量 → f32 变量,值可表示则允许) */
|
||||
if (is_literal && d->kind == SPL_TYPE_FLOAT && s->kind == SPL_TYPE_FLOAT)
|
||||
return 1;
|
||||
/* isize/usize(机器字宽)与 i32 混合:比较/算术/传参可用(splc1 与旧测试事实标准) */
|
||||
if (d->kind == SPL_TYPE_INT && s->kind == SPL_TYPE_INT) {
|
||||
int dbits = d->int_type.bits, sbits = s->int_type.bits;
|
||||
@@ -772,8 +806,8 @@ static spl_type_id_t infer_binary_cmp(spl_sema_t *sema, spl_ast_node_ref_t ref,
|
||||
return 0;
|
||||
}
|
||||
int w = 0;
|
||||
if (type_compatible(sema, l, r, expr_is_int_literal(sema, e->expr.op_expr.right), &w) ||
|
||||
type_compatible(sema, r, l, expr_is_int_literal(sema, e->expr.op_expr.left), &w)) {
|
||||
if (type_compatible(sema, l, r, expr_is_literal(sema, e->expr.op_expr.right), &w) ||
|
||||
type_compatible(sema, r, l, expr_is_literal(sema, e->expr.op_expr.left), &w)) {
|
||||
return spl_type_bool(&sema->type);
|
||||
}
|
||||
sema_error(sema, ref, "type mismatch in comparison");
|
||||
@@ -919,7 +953,7 @@ static spl_type_id_t infer_agg_init(spl_sema_t *sema, spl_ast_node_ref_t ref, sp
|
||||
int w = 0;
|
||||
if (!expr_is_null_literal(sema, item->aggregate_init_item.expr) && et &&
|
||||
!type_compatible(sema, mt, et,
|
||||
expr_is_int_literal(sema, item->aggregate_init_item.expr), &w)) {
|
||||
expr_is_literal(sema, item->aggregate_init_item.expr), &w)) {
|
||||
sema_error(sema, iref, "field type mismatch in aggregate literal");
|
||||
}
|
||||
}
|
||||
@@ -942,8 +976,7 @@ static spl_type_id_t infer_array_lit(spl_sema_t *sema, spl_ast_node_ref_t ref, s
|
||||
int w = 0;
|
||||
if (!type_compatible(
|
||||
sema, elem, et,
|
||||
expr_is_int_literal(sema, pn->primary_expr.array_lit_expr.expr_list.data[i]),
|
||||
&w)) {
|
||||
expr_is_literal(sema, pn->primary_expr.array_lit_expr.expr_list.data[i]), &w)) {
|
||||
sema_error(sema, pn->primary_expr.array_lit_expr.expr_list.data[i],
|
||||
"element type mismatch in array literal");
|
||||
}
|
||||
@@ -1017,16 +1050,35 @@ static spl_type_id_t infer_primary(spl_sema_t *sema, spl_ast_node_ref_t ref, spl
|
||||
return infer_expr(sema, pn->primary_expr.expr);
|
||||
case SPL_AST_ARRAY_LIT:
|
||||
return infer_array_lit(sema, ref, n);
|
||||
case SPL_AST_BUILTIN_EXPR:
|
||||
/* 内置调用:先推断实参,类型按名称约定 */
|
||||
for (usize i = 0; i < pn->primary_expr.builtin_expr.expr_list.size; i++)
|
||||
case SPL_AST_BUILTIN_EXPR: {
|
||||
/* 内置调用:类型按注册表约定,参数按需推断(offsetof 字段名参数非表达式) */
|
||||
const spl_builtin_t *bi = spl_builtin_lookup(pn->primary_expr.builtin_expr.ident);
|
||||
if (!bi) {
|
||||
sema_error(sema, ref, "unknown builtin");
|
||||
return 0;
|
||||
}
|
||||
usize nargs = pn->primary_expr.builtin_expr.expr_list.size;
|
||||
if (nargs < (usize)bi->min_args || (bi->max_args >= 0 && nargs > (usize)bi->max_args)) {
|
||||
char buf[96];
|
||||
snprintf(buf, sizeof buf, "builtin @%s: arg count mismatch", bi->name);
|
||||
sema_error(sema, ref, buf);
|
||||
return 0;
|
||||
}
|
||||
for (usize i = 0; i < nargs; i++) {
|
||||
/* offsetof 第二参数为字段标识符,不按表达式推断 */
|
||||
if (bi->kind == SPL_BUILTIN_OFFSET_OF && i == 1)
|
||||
continue;
|
||||
infer_expr(sema, pn->primary_expr.builtin_expr.expr_list.data[i]);
|
||||
if (strcmp(pn->primary_expr.builtin_expr.ident, "sizeof") == 0)
|
||||
return spl_type_int(&sema->type, sizeof(usize) * 8, 0);
|
||||
if (strcmp(pn->primary_expr.builtin_expr.ident, "dbg") == 0 ||
|
||||
strcmp(pn->primary_expr.builtin_expr.ident, "assert") == 0)
|
||||
}
|
||||
if (bi->ret_is_void)
|
||||
return spl_type_void(&sema->type);
|
||||
return spl_type_void(&sema->type);
|
||||
if (bi->kind == SPL_BUILTIN_SIZE_OF || bi->kind == SPL_BUILTIN_BITSIZE_OF ||
|
||||
bi->kind == SPL_BUILTIN_ALIGN_OF || bi->kind == SPL_BUILTIN_OFFSET_OF ||
|
||||
bi->kind == SPL_BUILTIN_FIELD_COUNT)
|
||||
return spl_type_int(&sema->type, sizeof(usize) * 8, 0);
|
||||
sema_error(sema, ref, "unsupported builtin");
|
||||
return 0;
|
||||
}
|
||||
case SPL_AST_BLOCK_EXPR: {
|
||||
/* 块表达式:有独立 scope;逐语句检查,返回末尾表达式类型(无则 void) */
|
||||
spl_ast_node_ref_vec_t *items = &pn->primary_expr.block_expr;
|
||||
@@ -1223,7 +1275,7 @@ static spl_type_id_t infer_postfix(spl_sema_t *sema, spl_ast_node_ref_t ref, spl
|
||||
int w = 0;
|
||||
if (!expr_is_null_literal(sema, args->data[i]) && at &&
|
||||
!type_compatible(sema, t->fn_type.params.data[i], at,
|
||||
expr_is_int_literal(sema, args->data[i]), &w)) {
|
||||
expr_is_literal(sema, args->data[i]), &w)) {
|
||||
sema_error(sema, args->data[i], "argument type mismatch");
|
||||
}
|
||||
}
|
||||
@@ -1299,10 +1351,24 @@ static spl_type_id_t infer_expr(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
sema_error(sema, ref, "bad assignment");
|
||||
return 0;
|
||||
}
|
||||
/* 不可写检查:赋值目标为 const 变量时拒绝 */
|
||||
{
|
||||
spl_ast_node_t *lhs = node_at(sema->ast, n->expr.op_expr.left);
|
||||
if (lhs && lhs->kind == SPL_AST_EXPR && lhs->expr.op == SPL_AST_PRIMARY_EXPR) {
|
||||
spl_ast_node_t *lpn = node_at(sema->ast, lhs->expr.op_expr.left);
|
||||
if (lpn && lpn->kind == SPL_AST_EXPR &&
|
||||
lpn->primary_expr.kind == SPL_AST_IDENT && lpn->resolved_def_id) {
|
||||
spl_def_node_t *ld = def_at(sema, lpn->resolved_def_id);
|
||||
if (ld && ld->kind == SPL_DEF_VAR && ld->var_def.is_const) {
|
||||
sema_error(sema, ref, "cannot assign to const");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int w = 0;
|
||||
if (!expr_is_null_literal(sema, n->expr.op_expr.right) &&
|
||||
!type_compatible(sema, l, r, expr_is_int_literal(sema, n->expr.op_expr.right),
|
||||
&w)) {
|
||||
!type_compatible(sema, l, r, expr_is_literal(sema, n->expr.op_expr.right), &w)) {
|
||||
sema_error(sema, ref, "assignment type mismatch");
|
||||
return 0;
|
||||
}
|
||||
@@ -1361,7 +1427,7 @@ static void check_var_init(spl_sema_t *sema, spl_ast_node_ref_t ref, const char
|
||||
if (dt) {
|
||||
int w = 0;
|
||||
if (!expr_is_null_literal(sema, init_expr) && it &&
|
||||
!type_compatible(sema, dt, it, expr_is_int_literal(sema, init_expr), &w)) {
|
||||
!type_compatible(sema, dt, it, expr_is_literal(sema, init_expr), &w)) {
|
||||
sema_error(sema, ref, "initializer type mismatch");
|
||||
} else if (w) {
|
||||
sema_warn(sema, ref, "pointer conversion involves wildcard");
|
||||
@@ -1427,7 +1493,7 @@ static spl_type_id_t infer_agg_init_with_type(spl_sema_t *sema, spl_ast_node_ref
|
||||
int w = 0;
|
||||
if (!expr_is_null_literal(sema, item->aggregate_init_item.expr) && et &&
|
||||
!type_compatible(sema, mt, et,
|
||||
expr_is_int_literal(sema, item->aggregate_init_item.expr), &w)) {
|
||||
expr_is_literal(sema, item->aggregate_init_item.expr), &w)) {
|
||||
sema_error(sema, iref, "field type mismatch in aggregate literal");
|
||||
}
|
||||
}
|
||||
@@ -1492,6 +1558,33 @@ static void check_match(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t
|
||||
sema_error(sema, ref, "match: arm pattern/body count mismatch");
|
||||
return;
|
||||
}
|
||||
/* 穷举检查:enum 必须覆盖所有变体,或含通配 _(含表达式的整数 match 免检) */
|
||||
{
|
||||
spl_def_id_t adef = def_for_type(sema, mtype);
|
||||
spl_def_node_t *ad = adef ? &sema->type.def_table.data[adef] : NULL;
|
||||
int is_enum_agg = ad && ad->kind == SPL_DEF_AGG;
|
||||
if (is_enum_agg) {
|
||||
int has_wild = 0;
|
||||
usize covered = 0;
|
||||
for (usize i = 0; i < arms->size; i++) {
|
||||
spl_ast_node_t *pk = node_at(sema->ast, arms->data[i]);
|
||||
if (!pk)
|
||||
continue;
|
||||
/* _ 通配:ident 与 expr 均为空 */
|
||||
if (!pk->packed_expr.ident && !pk->packed_expr.expr) {
|
||||
has_wild = 1;
|
||||
break;
|
||||
}
|
||||
if (pk->packed_expr.ident) {
|
||||
/* 变体被覆盖:匹配臂中出现的合法变体计数 */
|
||||
if (agg_member_type(sema, mtype, pk->packed_expr.ident))
|
||||
covered++;
|
||||
}
|
||||
}
|
||||
if (!has_wild && covered < ad->agg_def.size)
|
||||
sema_error(sema, ref, "match must be exhaustive");
|
||||
}
|
||||
}
|
||||
for (usize i = 0; i < arms->size; i++) {
|
||||
spl_ast_node_t *pk = node_at(sema->ast, arms->data[i]);
|
||||
if (!pk)
|
||||
@@ -1517,7 +1610,7 @@ static void check_match(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t
|
||||
spl_type_id_t et = infer_expr(sema, pk->packed_expr.expr);
|
||||
int w = 0;
|
||||
if (is_int_tid(sema, mtype) && et &&
|
||||
!type_compatible(sema, mtype, et, expr_is_int_literal(sema, pk->packed_expr.expr),
|
||||
!type_compatible(sema, mtype, et, expr_is_literal(sema, pk->packed_expr.expr),
|
||||
&w)) {
|
||||
sema_error(sema, pk->packed_expr.expr, "match arm pattern type mismatch");
|
||||
}
|
||||
@@ -1625,7 +1718,7 @@ static void check_stmt(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_sema_ctx_t
|
||||
if (ctx.ret) {
|
||||
if (!expr_is_null_literal(sema, rd->block_item.ret_statement.expr) && et &&
|
||||
!type_compatible(sema, ctx.ret, et,
|
||||
expr_is_int_literal(sema, rd->block_item.ret_statement.expr),
|
||||
expr_is_literal(sema, rd->block_item.ret_statement.expr),
|
||||
NULL)) {
|
||||
sema_error(sema, rd->block_item.ret_statement.expr, "ret type mismatch");
|
||||
}
|
||||
@@ -1668,9 +1761,17 @@ static void check_block(spl_sema_t *sema, spl_ast_node_ref_vec_t *block, spl_sco
|
||||
b->block_item.var_decl);
|
||||
} else if (b->block_item.kind == SPL_AST_CONSTDECL) {
|
||||
spl_ast_node_t *cd = node_at(sema->ast, b->block_item.const_decl);
|
||||
if (cd)
|
||||
if (cd) {
|
||||
register_binding(sema, cd->const_decl.name, cd->const_decl.type_expr, scope, 0,
|
||||
b->block_item.const_decl);
|
||||
/* 标记 const:赋值检查拒绝写入 */
|
||||
spl_ast_node_t *cn = node_at(sema->ast, b->block_item.const_decl);
|
||||
if (cn && cn->resolved_def_id) {
|
||||
spl_def_node_t *cdd = def_at(sema, cn->resolved_def_id);
|
||||
if (cdd)
|
||||
cdd->var_def.is_const = 1;
|
||||
}
|
||||
}
|
||||
} else if (b->block_item.kind == SPL_AST_TYPEDECL) {
|
||||
spl_ast_node_t *td = node_at(sema->ast, b->block_item.type_decl);
|
||||
if (td)
|
||||
@@ -1826,6 +1927,9 @@ void spl_sema_run(spl_sema_t *sema) {
|
||||
sema_var_decl(sema, mref, sema->root_scope, sema->root_def);
|
||||
else if (m->kind == SPL_AST_CONST_DECL)
|
||||
sema_const_decl(sema, mref, sema->root_scope, sema->root_def);
|
||||
else if (m->kind == SPL_AST_MEMBER_DECL && m->member_decl.name)
|
||||
register_binding(sema, m->member_decl.name, m->member_decl.type_expr, sema->root_scope,
|
||||
sema->root_def, mref);
|
||||
}
|
||||
sema->current_scope = sema->root_scope;
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ typedef struct {
|
||||
spl_def_id_t def_id;
|
||||
spl_type_id_t type_id;
|
||||
usize scope_id;
|
||||
int is_const; /* var_def 是否为 const 声明(只读) */
|
||||
} spl_var_def_t;
|
||||
typedef VEC(spl_var_def_t) spl_var_def_vec_t;
|
||||
|
||||
|
||||
@@ -168,7 +168,50 @@ static int cmd_dump(const char *flags, const char *path) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int compile_spl(const char *src, const char *fname, const char *outpath) {
|
||||
static spl_ast_node_t *ast_node_at(spl_ast_t *ast, spl_ast_node_ref_t ref) {
|
||||
if (ref == 0 || ref >= ast->buckets.size)
|
||||
return NULL;
|
||||
return &ast->buckets.data[ref];
|
||||
}
|
||||
|
||||
static int ast_line(spl_ast_t *ast, spl_ast_node_ref_t ref) {
|
||||
spl_ast_node_t *n = ast_node_at(ast, ref);
|
||||
return n ? n->loc.line : 0;
|
||||
}
|
||||
|
||||
/* -g:在 .sir 尾部追加 debug 段(文本:IR 行 + VAR 行),spl_cli -g 读取 */
|
||||
static void gen_debug_map(const char *outpath, spl_ast_t *ast, const spl_ir_t *ir,
|
||||
const spl_ir2vm_t *ir2vm) {
|
||||
FILE *f = fopen(outpath, "ab");
|
||||
if (!f)
|
||||
return;
|
||||
fprintf(f, "SPLDBG\n");
|
||||
for (usize i = 0; i < ir2vm->fdbg.size; i++) {
|
||||
const spl_ir2vm_fdbg_t *fd = &ir2vm->fdbg.data[i];
|
||||
if (fd->fid >= ir->funcs.size)
|
||||
continue;
|
||||
const spl_ir_func_t *fn = &ir->funcs.data[fd->fid];
|
||||
const char *fname = fn->name ? fn->name : "?";
|
||||
for (usize ref = 1; ref < fd->node_first_ip.size; ref++) {
|
||||
usize ip = fd->node_first_ip.data[ref];
|
||||
if (ip == (usize)-1)
|
||||
continue;
|
||||
const spl_ir_node_t *n = &fn->nodes.data[ref];
|
||||
fprintf(f, "IR %zu %zu %d %s\n", ip, ref, ast_line(ast, n->src_ref),
|
||||
spl_ir_kind_name(n->kind));
|
||||
}
|
||||
for (usize j = 0; j < fn->dbg_vars.size; j++) {
|
||||
const spl_ir_dbg_var_t *dv = &fn->dbg_vars.data[j];
|
||||
if (!dv->name)
|
||||
continue;
|
||||
fprintf(f, "VAR %s %s %zu %zu %d\n", fname, dv->name, dv->offset, dv->tid,
|
||||
dv->is_param);
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static int compile_spl(const char *src, const char *fname, const char *outpath, int gen_debug) {
|
||||
spl_tok_vec_t toks = spl_lex(src, fname);
|
||||
spl_ast_t ast;
|
||||
spl_ast_init(&ast, &toks);
|
||||
@@ -203,6 +246,8 @@ static int compile_spl(const char *src, const char *fname, const char *outpath)
|
||||
spl_ir2vm_t ir2vm;
|
||||
spl_ir2vm_init(&ir2vm, &a2ir.ir, &sema.type);
|
||||
int rc = spl_ir2vm_run(&ir2vm, outpath);
|
||||
if (gen_debug && rc == 0)
|
||||
gen_debug_map(outpath, &ast, &a2ir.ir, &ir2vm);
|
||||
spl_ir2vm_drop(&ir2vm);
|
||||
spl_ast2ir_drop(&a2ir);
|
||||
spl_sema_drop(&sema);
|
||||
@@ -212,36 +257,45 @@ static int compile_spl(const char *src, const char *fname, const char *outpath)
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 2) {
|
||||
LOG_FATAL("Usage: splc0 [--dump <flags>] <in> [out]\n");
|
||||
LOG_FATAL("Usage: splc0 [--dump <flags>] <in> [out]");
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) {
|
||||
LOG_INFO("splc0 <in> <out> compile (.spl -> .sir, 阶段 B)\n");
|
||||
LOG_INFO("splc0 --dump <flags> <file> dump: tokens,ast,sema,ir,all\n");
|
||||
LOG_INFO("splc0 <in> <out> compile (.spl -> .sir, stage B)");
|
||||
LOG_INFO("splc0 --dump <flags> <file> dump: tokens,ast,sema,ir,all");
|
||||
return 0;
|
||||
}
|
||||
int argi = 1;
|
||||
if (argi >= argc) {
|
||||
LOG_FATAL("Usage: splc0 [--dump <flags>] <in> [out]\n");
|
||||
LOG_FATAL("Usage: splc0 [--dump <flags>] <in> [out]");
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(argv[argi], "--dump") == 0) {
|
||||
if (argc < argi + 3) {
|
||||
LOG_INFO("splc0: --dump need <flags> <file>\n");
|
||||
LOG_INFO("splc0: --dump need <flags> <file>");
|
||||
return 1;
|
||||
}
|
||||
return cmd_dump(argv[argi + 1], argv[argi + 2]);
|
||||
}
|
||||
/* splc0 <in> <out> */
|
||||
/* splc0 [-g] <in> <out> */
|
||||
if (argc < argi + 2) {
|
||||
LOG_FATAL("Usage: splc0 <in> <out> or splc0 --dump <flags> <file>\n");
|
||||
LOG_FATAL("Usage: splc0 <in> <out> [-g] or splc0 --dump <flags> <file>\n");
|
||||
return 1;
|
||||
}
|
||||
int gen_debug = 0;
|
||||
if (strcmp(argv[argi], "-g") == 0) {
|
||||
gen_debug = 1;
|
||||
argi++;
|
||||
}
|
||||
if (argc < argi + 2) {
|
||||
LOG_FATAL("Usage: splc0 <in> <out> [-g] or splc0 --dump <flags> <file>\n");
|
||||
return 1;
|
||||
}
|
||||
long len;
|
||||
char *src = read_file(argv[argi], &len);
|
||||
if (!src)
|
||||
return 1;
|
||||
int rc = compile_spl(src, argv[argi], argv[argi + 1]);
|
||||
int rc = compile_spl(src, argv[argi], argv[argi + 1], gen_debug);
|
||||
free(src);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
/* spc_vm.c launcher for stage 1 */
|
||||
|
||||
#include "../stage0/spl_mcode.h"
|
||||
#include "../stage0/spl_syscall.h"
|
||||
#include "../stage0/spl_vm.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
int argi = 1;
|
||||
|
||||
/* Parse flags: --entry <name>, --trace, -d */
|
||||
const char *entry = "main";
|
||||
int trace = 0;
|
||||
int debug_addr = 0;
|
||||
for (int i = argi; i < argc; i += 1) {
|
||||
if (strcmp(argv[i], "--entry") == 0 && i + 1 < argc) {
|
||||
entry = argv[++i];
|
||||
} else if (strcmp(argv[i], "--trace") == 0) {
|
||||
trace = 1;
|
||||
} else if (strcmp(argv[i], "-d") == 0) {
|
||||
debug_addr = 1;
|
||||
} else if (argv[i][0] != '-') {
|
||||
argi = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argi >= argc) {
|
||||
fprintf(stderr, "Usage: spc_vm [-d] [--trace] <file.sir> [args...]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *path = argv[argi++];
|
||||
const char **spl_argv = argv + (argi - 1);
|
||||
int spl_argc = (int)(argc - (argi - 1));
|
||||
|
||||
spl_prog_t prog;
|
||||
if (spl_prog_load_from_file(path, &prog) != 0) {
|
||||
fprintf(stderr, "spc_vm: cannot load '%s'\n", path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
spl_syscall_register(&prog);
|
||||
|
||||
spl_vm_t vm;
|
||||
spl_vm_init(&vm);
|
||||
if (spl_vm_load_prog(&vm, &prog) != 0) {
|
||||
fprintf(stderr, "vm: prog '%s' not found\n", entry);
|
||||
spl_prog_drop(&prog);
|
||||
return 1;
|
||||
}
|
||||
if (spl_vm_prepare(&vm, entry, spl_argc, spl_argv, NULL) != 0) {
|
||||
fprintf(stderr, "vm: entry point '%s' not found\n", entry);
|
||||
spl_prog_drop(&prog);
|
||||
return 1;
|
||||
}
|
||||
spl_vm_set_trace(&vm, trace);
|
||||
if (debug_addr)
|
||||
spl_vm_set_debug(&vm, 1);
|
||||
|
||||
int ret = spl_vm_run_until(&vm, 0);
|
||||
spl_vm_drop(&vm);
|
||||
spl_prog_drop(&prog);
|
||||
|
||||
return (int)vm.exit_code;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
/* ===== 模块1:核心基础 =====
|
||||
* test00_basic — 最小程序 / 返回码
|
||||
* 难度:1/5
|
||||
* 验证点:函数定义、整型返回、ret 语句
|
||||
*/
|
||||
fn main() i32 {
|
||||
ret 0;
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/* ===== 模块1:核心基础 =====
|
||||
* test01_literals — 全部字面量形式
|
||||
* 难度:1/5
|
||||
* 验证点:十进制/十六进制/二进制/八进制整数、
|
||||
* 字符字面量、字符串字面量、布尔字面量、null
|
||||
*/
|
||||
fn main() i32 {
|
||||
/* 整数:十进制 */
|
||||
var a: i32 = 42;
|
||||
if a != 42 { ret 1; }
|
||||
|
||||
/* 整数:十六进制 */
|
||||
var b: i32 = 0xFF;
|
||||
if b != 255 { ret 2; }
|
||||
|
||||
/* 整数:二进制 */
|
||||
var c: i32 = 0b1010;
|
||||
if c != 10 { ret 3; }
|
||||
|
||||
/* 整数:八进制 */
|
||||
var d: i32 = 0o77;
|
||||
if d != 63 { ret 4; }
|
||||
|
||||
/* 字符字面量 */
|
||||
var ch: i32 = 'A';
|
||||
if ch != 65 { ret 5; }
|
||||
|
||||
/* 字符转义 */
|
||||
var nl: i32 = '\n';
|
||||
if nl != 10 { ret 6; }
|
||||
|
||||
/* 布尔字面量 */
|
||||
var t: bool = true;
|
||||
if !t { ret 7; }
|
||||
var f: bool = false;
|
||||
if f { ret 8; }
|
||||
|
||||
/* null 指针 */
|
||||
var np: *i32 = null;
|
||||
if np != null { ret 9; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/* ===== 模块1:核心基础 =====
|
||||
* test02_variables — 变量与常量声明
|
||||
* 难度:1/5
|
||||
* 验证点:var 声明 + 类型注解、var 声明 + 初始化、
|
||||
* const 声明、var := 短声明、const := 短声明
|
||||
*/
|
||||
fn main() i32 {
|
||||
/* var 带类型注解与初始化 */
|
||||
var a: i32 = 10;
|
||||
if a != 10 { ret 1; }
|
||||
|
||||
/* var 先声明后赋值 */
|
||||
var b: i32;
|
||||
b = 20;
|
||||
if b != 20 { ret 2; }
|
||||
|
||||
/* const 声明 */
|
||||
const c: i32 = 30;
|
||||
if c != 30 { ret 3; }
|
||||
|
||||
/* var := 短声明(类型推断) */
|
||||
var d := 40;
|
||||
if d != 40 { ret 4; }
|
||||
|
||||
/* const := 短声明 */
|
||||
const e := 50;
|
||||
if e != 50 { ret 5; }
|
||||
|
||||
/* 多类型变量 */
|
||||
var i8v: i8 = 127;
|
||||
if i8v != 127 { ret 6; }
|
||||
|
||||
var u8v: u8 = 255;
|
||||
if u8v != 255 { ret 7; }
|
||||
|
||||
var i16v: i16 = 32767;
|
||||
if i16v != 32767 { ret 8; }
|
||||
|
||||
var u16v: u16 = 65535;
|
||||
if u16v != 65535 { ret 9; }
|
||||
|
||||
var u32v: u32 = 4294967295;
|
||||
if u32v != 4294967295 { ret 10; }
|
||||
|
||||
/* 指针类型变量 */
|
||||
var x: i32 = 100;
|
||||
var p: *i32 = &x;
|
||||
if p == null { ret 11; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/* ===== 模块2:表达式 =====
|
||||
* test03_arithmetic — 算术运算
|
||||
* 难度:1/5
|
||||
* 验证点:加、减、乘、除、取模、负数、混合运算优先级
|
||||
*/
|
||||
fn main() i32 {
|
||||
/* 加法 */
|
||||
var a := 12 + 34;
|
||||
if a != 46 { ret 1; }
|
||||
|
||||
/* 减法 */
|
||||
var b := 100 - 23;
|
||||
if b != 77 { ret 2; }
|
||||
|
||||
/* 乘法 */
|
||||
var c := 7 * 8;
|
||||
if c != 56 { ret 3; }
|
||||
|
||||
/* 除法 */
|
||||
var d := 100 / 3;
|
||||
if d != 33 { ret 4; }
|
||||
|
||||
/* 取模 */
|
||||
var e := 100 % 3;
|
||||
if e != 1 { ret 5; }
|
||||
|
||||
/* 负数 */
|
||||
var f := -5;
|
||||
if f != -5 { ret 6; }
|
||||
|
||||
/* 负数运算 */
|
||||
var g := -10 + 3;
|
||||
if g != -7 { ret 7; }
|
||||
|
||||
/* 运算优先级:乘优先于加 */
|
||||
var h := 2 + 3 * 4;
|
||||
if h != 14 { ret 8; }
|
||||
|
||||
/* 括号改变优先级 */
|
||||
var i := (2 + 3) * 4;
|
||||
if i != 20 { ret 9; }
|
||||
|
||||
/* 连续运算 */
|
||||
var j := 1 + 2 + 3 + 4 + 5;
|
||||
if j != 15 { ret 10; }
|
||||
|
||||
/* 混合运算 */
|
||||
var k := 10 * 2 - 8 / 4;
|
||||
if k != 18 { ret 11; }
|
||||
|
||||
/* 负数取模 */
|
||||
var l := -7 % 3;
|
||||
if l != -1 { ret 12; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/* ===== 模块2:表达式 =====
|
||||
* test04_operators — 比较/逻辑/位运算 + 短路求值
|
||||
* 难度:2/5
|
||||
* 验证点:== != < <= > >=、&& || !、& | ^ ~ << >>、&&/|| 短路
|
||||
*/
|
||||
fn main() i32 {
|
||||
/* ---- 比较运算 ---- */
|
||||
if (1 < 2) {} else { ret 1; }
|
||||
if (3 > 1) {} else { ret 2; }
|
||||
if (2 == 2) {} else { ret 3; }
|
||||
if (2 != 3) {} else { ret 4; }
|
||||
if (2 <= 2) {} else { ret 5; }
|
||||
if (2 <= 3) {} else { ret 6; }
|
||||
if (3 >= 3) {} else { ret 7; }
|
||||
if (3 >= 2) {} else { ret 8; }
|
||||
|
||||
/* 比较结果为 0/1 */
|
||||
var eq := (42 == 42);
|
||||
if !eq { ret 9; }
|
||||
var ne := (42 == 43);
|
||||
if ne { ret 10; }
|
||||
var lt := (5 < 10);
|
||||
if !lt { ret 11; }
|
||||
|
||||
/* ---- 逻辑运算 ---- */
|
||||
if (true) {} else { ret 12; }
|
||||
if (!false) {} else { ret 13; }
|
||||
if (true && true) {} else { ret 14; }
|
||||
if (false || true) {} else { ret 15; }
|
||||
|
||||
/* 逻辑非 */
|
||||
var not_t := !true;
|
||||
if not_t { ret 16; }
|
||||
var not_f := !false;
|
||||
if !not_f { ret 17; }
|
||||
|
||||
// /* ---- 短路求值 ---- */
|
||||
// var short1 := 0;
|
||||
// var short2 := 0;
|
||||
// if (false && { short1 = 1; true; }) {} else {}
|
||||
// if short1 != 0 { ret 18; } /* 右侧未执行 */
|
||||
|
||||
/* ---- 位运算 ---- */
|
||||
var band := 0xFF & 0x0F;
|
||||
if band != 0x0F { ret 19; }
|
||||
|
||||
var bor := 0xF0 | 0x0F;
|
||||
if bor != 0xFF { ret 20; }
|
||||
|
||||
var bxor := 0xFF ^ 0x0F;
|
||||
if bxor != 0xF0 { ret 21; }
|
||||
|
||||
var bnot := ~0xFF;
|
||||
/* ~0xFF 在 32 位下 = 0xFFFFFF00,即 -256 */
|
||||
if bnot != -256 { ret 22; }
|
||||
|
||||
/* 左移 */
|
||||
var shl := 1 << 3;
|
||||
if shl != 8 { ret 23; }
|
||||
|
||||
/* 右移 */
|
||||
var shr := 16 >> 2;
|
||||
if shr != 4 { ret 24; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/* ===== 模块3:控制流 =====
|
||||
* test05_control — 分支与循环
|
||||
* 难度:2/5
|
||||
* 验证点:if/else、while、loop、break、continue
|
||||
*/
|
||||
fn main() i32 {
|
||||
/* ---- if/else ---- */
|
||||
var x: i32 = 10;
|
||||
if x > 5 {
|
||||
x = 0;
|
||||
} else {
|
||||
x = 1;
|
||||
}
|
||||
if x != 0 { ret 1; }
|
||||
|
||||
/* else 分支 */
|
||||
var y: i32 = 1;
|
||||
if y > 5 {
|
||||
y = 10;
|
||||
} else {
|
||||
y = 20;
|
||||
}
|
||||
if y != 20 { ret 2; }
|
||||
|
||||
/* if 不带 else */
|
||||
var z: i32 = 0;
|
||||
if z == 0 {
|
||||
z = 99;
|
||||
}
|
||||
if z != 99 { ret 3; }
|
||||
|
||||
/* ---- while ---- */
|
||||
var i: i32 = 0;
|
||||
while i < 5 {
|
||||
i = i + 1;
|
||||
}
|
||||
if i != 5 { ret 4; }
|
||||
|
||||
/* while 条件为 false */
|
||||
var j: i32 = 0;
|
||||
while j > 0 {
|
||||
j = j + 1;
|
||||
}
|
||||
if j != 0 { ret 5; }
|
||||
|
||||
/* ---- loop / break ---- */
|
||||
var k: i32 = 0;
|
||||
loop {
|
||||
k = k + 1;
|
||||
if k >= 3 { break; }
|
||||
}
|
||||
if k != 3 { ret 6; }
|
||||
|
||||
/* ---- continue ---- */
|
||||
var n: i32 = 0;
|
||||
var m: i32 = 0;
|
||||
while n < 5 {
|
||||
n = n + 1;
|
||||
if n == 3 { continue; }
|
||||
m = m + 1;
|
||||
}
|
||||
if n != 5 { ret 7; }
|
||||
if m != 4 { ret 8; }
|
||||
|
||||
/* ---- 嵌套控制流 ---- */
|
||||
var total: i32 = 0;
|
||||
var p: i32 = 0;
|
||||
while p < 3 {
|
||||
var q: i32 = 0;
|
||||
while q < 4 {
|
||||
total = total + 1;
|
||||
q = q + 1;
|
||||
}
|
||||
p = p + 1;
|
||||
}
|
||||
if total != 12 { ret 9; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/* ===== 模块3:控制流 =====
|
||||
* test06_for — for 区间循环
|
||||
* 难度:2/5
|
||||
* 验证点:for begin..end as i、for slice as val、for slice,0.. as val,idx
|
||||
*/
|
||||
@extern(vm) fn vm_printf(fmt: *u8, ...) void;
|
||||
|
||||
fn main() i32 {
|
||||
/* for 数值区间:for 0..N as i */
|
||||
var sum: i32 = 0;
|
||||
for 0..5 as i {
|
||||
sum = sum + i;
|
||||
}
|
||||
/* 0+1+2+3+4 = 10 */
|
||||
if sum != 10 { ret 1; }
|
||||
|
||||
/* for 数值区间:非 0 起始 */
|
||||
var sum2: i32 = 0;
|
||||
for 3..7 as i {
|
||||
sum2 = sum2 + i;
|
||||
}
|
||||
/* 3+4+5+6 = 18 */
|
||||
if sum2 != 18 { ret 2; }
|
||||
|
||||
/* for 遍历切片 */
|
||||
var arr: [4]i32 = [4]i32{10, 20, 30, 40};
|
||||
var sl: []i32 = arr[0..];
|
||||
var total: i32 = 0;
|
||||
for sl as val {
|
||||
total = total + val;
|
||||
}
|
||||
/* 10+20+30+40 = 100 */
|
||||
if total != 100 { ret 3; }
|
||||
|
||||
/* for 遍历切片 + 索引 */
|
||||
var arr2: [3]i32 = [3]i32{100, 200, 300};
|
||||
var sl2: []i32 = arr2[0..];
|
||||
var sum_val: i32 = 0;
|
||||
var sum_idx: i32 = 0;
|
||||
for sl2, 0.. as val, idx {
|
||||
sum_val = sum_val + val;
|
||||
sum_idx = sum_idx + idx;
|
||||
}
|
||||
if sum_val != 600 { ret 4; }
|
||||
if sum_idx != 3 { ret 5; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/* ===== 模块4:指针 =====
|
||||
* test07_pointers — 指针操作
|
||||
* 难度:2/5
|
||||
* 验证点:& 取地址、* 解引用、null 空指针、指针自动解引用(->)、.* 后缀解引用
|
||||
*/
|
||||
fn inc(ptr: *i32) void {
|
||||
*ptr = *ptr + 1;
|
||||
}
|
||||
|
||||
fn main() i32 {
|
||||
/* ---- & 取地址和 * 解引用 ---- */
|
||||
var x: i32 = 42;
|
||||
var p: *i32 = &x;
|
||||
var v := p.*;
|
||||
if v != 42 { ret 1; }
|
||||
|
||||
/* 通过指针修改 */
|
||||
p.* = 99;
|
||||
if x != 99 { ret 2; }
|
||||
|
||||
/* 指针作为函数参数 */
|
||||
var y: i32 = 5;
|
||||
inc(&y);
|
||||
if y != 6 { ret 3; }
|
||||
|
||||
/* ---- null 空指针 ---- */
|
||||
var np: *i32 = null;
|
||||
if np != null { ret 4; }
|
||||
if np == null {} else { ret 5; }
|
||||
|
||||
/* ---- 指针自动解引用(ptr.field 相当于 ptr->field) ---- */
|
||||
type Point = struct {
|
||||
a: i32,
|
||||
b: i32,
|
||||
};
|
||||
|
||||
var pt: Point;
|
||||
pt.a = 10;
|
||||
pt.b = 20;
|
||||
var pp: *Point = &pt;
|
||||
if pp.a != 10 { ret 6; }
|
||||
if pp.b != 20 { ret 7; }
|
||||
|
||||
/* 通过指针修改字段 */
|
||||
pp.a = 30;
|
||||
if pt.a != 30 { ret 8; }
|
||||
|
||||
/* ---- 指向数组元素的指针 ---- */
|
||||
var buf: [4]i32 = [4]i32{1, 2, 3, 4};
|
||||
// @dbg(); /* 数组初始化后的栈状态 */
|
||||
var elem_ptr: *i32 = &buf[0];
|
||||
// @dbg(); /* &buf[0] 之后:栈上应有指针值 */
|
||||
var loaded := elem_ptr.*;
|
||||
// @dbg(); /* 解引用后:loaded 值 */
|
||||
if loaded != 1 { ret 9; }
|
||||
|
||||
elem_ptr = &buf[1];
|
||||
// @dbg(); /* &buf[1] 之后 */
|
||||
var loaded2 := elem_ptr.*;
|
||||
// @dbg(); /* 解引用后:loaded2 值 */
|
||||
if loaded2 != 2 { ret 10; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/* ===== 模块5:复合类型 =====
|
||||
* test08_arrays — 数组
|
||||
* 难度:2/5
|
||||
* 验证点:数组字面量 [N]T{...}、数组索引、数组元素修改
|
||||
*/
|
||||
fn main() i32 {
|
||||
/* 数组字面量 */
|
||||
var arr: [3]i32 = [3]i32{1, 2, 3};
|
||||
if arr[0] != 1 { ret 1; }
|
||||
if arr[1] != 2 { ret 2; }
|
||||
if arr[2] != 3 { ret 3; }
|
||||
|
||||
/* 数组元素修改 */
|
||||
arr[1] = 99;
|
||||
if arr[1] != 99 { ret 4; }
|
||||
|
||||
/* 数组求和 */
|
||||
var nums: [5]i32 = [5]i32{10, 20, 30, 40, 50};
|
||||
var sum: i32 = 0;
|
||||
sum = sum + nums[0];
|
||||
sum = sum + nums[1];
|
||||
sum = sum + nums[2];
|
||||
sum = sum + nums[3];
|
||||
sum = sum + nums[4];
|
||||
if sum != 150 { ret 5; }
|
||||
|
||||
/* 数组通过循环访问(while) */
|
||||
var vals: [4]i32 = [4]i32{2, 4, 6, 8};
|
||||
var i: i32 = 0;
|
||||
var s: i32 = 0;
|
||||
while i < 4 {
|
||||
s = s + vals[i];
|
||||
i = i + 1;
|
||||
}
|
||||
if s != 20 { ret 6; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/* ===== 模块5:复合类型 =====
|
||||
* test09_slices — 切片
|
||||
* 难度:2/5
|
||||
* 验证点:arr[begin..end] 创建切片、arr[begin..] 到末尾、
|
||||
* 切片索引访问、slice.len、slice.ptr
|
||||
*/
|
||||
fn main() i32 {
|
||||
/* 从数组创建切片 */
|
||||
var arr: [5]i32 = [5]i32{10, 20, 30, 40, 50};
|
||||
var slice: []i32 = arr[1..4];
|
||||
|
||||
/* 切片长度 */
|
||||
if slice.len != 3 { ret 1; }
|
||||
|
||||
/* 切片元素访问 */
|
||||
if slice[0] != 20 { ret 2; }
|
||||
if slice[1] != 30 { ret 3; }
|
||||
if slice[2] != 40 { ret 4; }
|
||||
|
||||
/* 省略结束值:arr[begin..] */
|
||||
var full: []i32 = arr[0..];
|
||||
if full.len != 5 { ret 5; }
|
||||
if full[0] != 10 { ret 6; }
|
||||
if full[4] != 50 { ret 7; }
|
||||
|
||||
/* 从开头到中间 */
|
||||
var head: []i32 = arr[0..3];
|
||||
if head.len != 3 { ret 8; }
|
||||
if head[0] != 10 { ret 9; }
|
||||
|
||||
/* 切片遍历(配合 for)*/
|
||||
var nums: [3]i32 = [3]i32{100, 200, 300};
|
||||
var sl: []i32 = nums[0..];
|
||||
var total: i32 = 0;
|
||||
var i: i32 = 0;
|
||||
while i < sl.len {
|
||||
total = total + sl[i];
|
||||
i = i + 1;
|
||||
}
|
||||
if total != 600 { ret 10; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
@@ -1,215 +0,0 @@
|
||||
/* ===== 模块5:复合类型 =====
|
||||
* test10_struct — 结构体
|
||||
* 难度:2/5
|
||||
* 验证点:struct 定义、字段访问、内联 type、嵌套结构体
|
||||
*/
|
||||
type Pair = struct {
|
||||
a: i32,
|
||||
b: i32,
|
||||
}
|
||||
|
||||
type Three = struct {
|
||||
a: i64,
|
||||
b: i64,
|
||||
c: i64,
|
||||
}
|
||||
|
||||
type Tag = enum {
|
||||
Unknown,
|
||||
BlockComment,
|
||||
LineComment,
|
||||
Ident,
|
||||
Number,
|
||||
}
|
||||
|
||||
type Token = struct {
|
||||
loc_start: i32,
|
||||
loc_end: i32,
|
||||
tag: Tag,
|
||||
}
|
||||
|
||||
fn make_three(a: i64, b: i64, c: i64) Three {
|
||||
ret Three { .a = a, .b = b, .c = c };
|
||||
}
|
||||
|
||||
fn sum_three(t: Three) i64 {
|
||||
ret t.a + t.b + t.c;
|
||||
}
|
||||
|
||||
fn make_token(s: i32, e: i32, t: Tag) Token {
|
||||
ret Token { .loc_start = s, .loc_end = e, .tag = t };
|
||||
}
|
||||
|
||||
fn test_ret_enum_struct() i32 {
|
||||
var tok := make_token(10, 20, Tag.BlockComment);
|
||||
if tok.loc_start != 10 { ret 1; }
|
||||
if tok.loc_end != 20 { ret 2; }
|
||||
if tok.tag != Tag.BlockComment { ret 3; }
|
||||
ret 0;
|
||||
}
|
||||
|
||||
fn test_nested_ret_enum() i32 {
|
||||
var tok := make_token(1, 5, Tag.Ident);
|
||||
if tok.tag != Tag.Ident { ret 1; }
|
||||
var tok2 := make_token(6, 9, Tag.Number);
|
||||
if tok2.tag != Tag.Number { ret 2; }
|
||||
if tok.tag != Tag.Ident { ret 3; }
|
||||
ret 0;
|
||||
}
|
||||
|
||||
fn test_copy_token() i32 {
|
||||
var tok := make_token(0, 100, Tag.LineComment);
|
||||
var c := tok;
|
||||
if c.loc_start != 0 { ret 1; }
|
||||
if c.tag != Tag.LineComment { ret 2; }
|
||||
c.tag = Tag.Ident;
|
||||
if tok.tag != Tag.LineComment { ret 3; }
|
||||
if c.tag != Tag.Ident { ret 4; }
|
||||
ret 0;
|
||||
}
|
||||
|
||||
fn test_pass_token(t: Token) i32 {
|
||||
if t.tag != Tag.Number { ret 1; }
|
||||
if t.loc_start != 42 { ret 2; }
|
||||
ret 0;
|
||||
}
|
||||
|
||||
fn test_param_pass_token() i32 {
|
||||
var tok := make_token(42, 99, Tag.Number);
|
||||
var r := test_pass_token(tok);
|
||||
if r != 0 { ret r; }
|
||||
ret 0;
|
||||
}
|
||||
|
||||
fn test_get_tag(tok: Token) Tag {
|
||||
ret tok.tag;
|
||||
}
|
||||
|
||||
fn test_chain_func_call() i32 {
|
||||
var tok := make_token(1, 2, Tag.BlockComment);
|
||||
var tg := test_get_tag(tok);
|
||||
if tg != Tag.BlockComment { ret 1; }
|
||||
var tok2 := make_token(3, 4, Tag.LineComment);
|
||||
var tg2 := test_get_tag(tok2);
|
||||
if tg2 != Tag.LineComment { ret 2; }
|
||||
ret 0;
|
||||
}
|
||||
|
||||
fn test_ret_multi_slot_struct() i32 {
|
||||
var t := make_three(10, 20, 30);
|
||||
if t.a != 10 { ret 1; }
|
||||
if t.b != 20 { ret 2; }
|
||||
if t.c != 30 { ret 3; }
|
||||
ret 0;
|
||||
}
|
||||
|
||||
fn test_pass_struct_by_value() i32 {
|
||||
var t := make_three(10, 20, 30);
|
||||
var sum := sum_three(t);
|
||||
if sum != 60 { ret 1; }
|
||||
ret 0;
|
||||
}
|
||||
|
||||
fn test_copy_struct() i32 {
|
||||
var t := make_three(10, 20, 30);
|
||||
var t2: Three;
|
||||
t2 = t;
|
||||
if t2.a != 10 { ret 1; }
|
||||
t2.a = 99;
|
||||
if t.a != 10 { ret 2; }
|
||||
if t2.a != 99 { ret 3; }
|
||||
ret 0;
|
||||
}
|
||||
|
||||
fn test_multi_calls() i32 {
|
||||
var ta := make_three(5, 10, 15);
|
||||
var tb := make_three(20, 25, 30);
|
||||
if ta.a + ta.b + ta.c != 30 { ret 1; }
|
||||
if tb.a + tb.b + tb.c != 75 { ret 2; }
|
||||
ret 0;
|
||||
}
|
||||
|
||||
fn test_literal_arg() i32 {
|
||||
var sum := sum_three(Three { .a = 7, .b = 8, .c = 9 });
|
||||
if sum != 24 { ret 1; }
|
||||
ret 0;
|
||||
}
|
||||
|
||||
fn main() i32 {
|
||||
/* struct 字段访问 */
|
||||
var p: Pair;
|
||||
p.a = 1;
|
||||
p.b = 2;
|
||||
if p.a != 1 { ret 1; }
|
||||
if p.b != 2 { ret 2; }
|
||||
|
||||
/* 同一类型复用 */
|
||||
var p2: Pair;
|
||||
p2.a = 10;
|
||||
p2.b = 20;
|
||||
if p2.a + p2.b != 30 { ret 3; }
|
||||
|
||||
/* 不影响其他实例 */
|
||||
if p.a != 1 { ret 4; }
|
||||
|
||||
/* 内联 type 定义(在函数内) */
|
||||
type Triple = struct {
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
}
|
||||
|
||||
var t: Triple;
|
||||
t.x = 5;
|
||||
t.y = 10;
|
||||
t.z = 15;
|
||||
if t.x + t.y + t.z != 30 { ret 5; }
|
||||
|
||||
/* 结构体字段运算 */
|
||||
var calc: Pair;
|
||||
calc.a = 7;
|
||||
calc.b = 3;
|
||||
var r := calc.a * calc.b + calc.a - calc.b;
|
||||
if r != 25 { ret 6; }
|
||||
|
||||
/* 结构体嵌套 */
|
||||
type Outer = struct {
|
||||
inner: Inner,
|
||||
extra: i32,
|
||||
type Inner = struct {
|
||||
val: i32,
|
||||
}
|
||||
}
|
||||
|
||||
var o: Outer;
|
||||
o.inner.val = 42;
|
||||
o.extra = 58;
|
||||
if o.inner.val != 42 { ret 7; }
|
||||
if o.extra != 58 { ret 8; }
|
||||
|
||||
/* 多 slot 结构体返回值测试 */
|
||||
var r9 := test_ret_multi_slot_struct();
|
||||
if r9 != 0 { ret 100; }
|
||||
var r10 := test_pass_struct_by_value();
|
||||
if r10 != 0 { ret 101; }
|
||||
var r11 := test_copy_struct();
|
||||
if r11 != 0 { ret 102; }
|
||||
var r12 := test_multi_calls();
|
||||
if r12 != 0 { ret 103; }
|
||||
var r13 := test_literal_arg();
|
||||
if r13 != 0 { ret 104; }
|
||||
|
||||
/* 含 enum 字段的结构体返回值测试 */
|
||||
var r14 := test_ret_enum_struct();
|
||||
if r14 != 0 { ret 110; }
|
||||
var r15 := test_nested_ret_enum();
|
||||
if r15 != 0 { ret 111; }
|
||||
var r16 := test_copy_token();
|
||||
if r16 != 0 { ret 112; }
|
||||
var r17 := test_param_pass_token();
|
||||
if r17 != 0 { ret 113; }
|
||||
var r18 := test_chain_func_call();
|
||||
if r18 != 0 { ret 114; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/* ===== 模块5:复合类型 =====
|
||||
* test11_enum — 枚举
|
||||
* 难度:3/5
|
||||
* 验证点:enum 定义、简单枚举值、带数据枚举变体
|
||||
*/
|
||||
@extern(vm) fn vm_printf(fmt: *u8, ...) void;
|
||||
|
||||
type Color = enum {
|
||||
Red,
|
||||
Green,
|
||||
Blue,
|
||||
}
|
||||
|
||||
type Expr = enum {
|
||||
val: i32,
|
||||
tag: Tag,
|
||||
|
||||
type Tag = enum {
|
||||
TagA,
|
||||
TagB,
|
||||
TagC,
|
||||
}
|
||||
}
|
||||
|
||||
fn main() i32 {
|
||||
vm_printf("enum values: %d %d %d\n", Color.Red, Color.Green, Color.Blue);
|
||||
vm_printf("enum values: %d %d %d\n", Expr.Tag.TagA, Expr.Tag.TagB, Expr.Tag.TagC);
|
||||
ret 0;
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/* ===== 模块6:函数 =====
|
||||
* test12_functions — 函数调用
|
||||
* 难度:2/5
|
||||
* 验证点:函数定义与调用、参数传递、返回值、多个参数
|
||||
*/
|
||||
fn add(a: i32, b: i32) i32 {
|
||||
ret a + b;
|
||||
}
|
||||
|
||||
fn sub(a: i32, b: i32) i32 {
|
||||
ret a - b;
|
||||
}
|
||||
|
||||
fn mul(a: i32, b: i32) i32 {
|
||||
ret a * b;
|
||||
}
|
||||
|
||||
fn identity(x: i32) i32 {
|
||||
ret x;
|
||||
}
|
||||
|
||||
fn addr(x: *i32) *i32 {
|
||||
ret x;
|
||||
}
|
||||
|
||||
fn main() i32 {
|
||||
/* 函数调用 */
|
||||
var r1 := add(3, 4);
|
||||
if r1 != 7 { ret 1; }
|
||||
|
||||
var r2 := sub(10, 3);
|
||||
if r2 != 7 { ret 2; }
|
||||
|
||||
var r3 := mul(6, 7);
|
||||
if r3 != 42 { ret 3; }
|
||||
|
||||
/* 函数嵌套调用 */
|
||||
var r4 := add(mul(2, 3), sub(10, 4));
|
||||
if r4 != 12 { ret 4; }
|
||||
|
||||
/* 函数返回值的传递 */
|
||||
var r5 := identity(99);
|
||||
if r5 != 99 { ret 5; }
|
||||
|
||||
/* 多个参数 */
|
||||
var r6 := add(add(1, 2), add(3, 4));
|
||||
if r6 != 10 { ret 6; }
|
||||
|
||||
/* 返回地址 */
|
||||
var r7 := addr(&r6);
|
||||
if r7 != &r6 { ret 7; }
|
||||
if r7.* != 10 { ret 8; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/* ===== 模块6:函数 =====
|
||||
* test13_extern — 外部 VM 函数与字符串
|
||||
* 难度:2/5
|
||||
* 验证点:@extern(vm) 声明、vm_printf 调用、
|
||||
* 字符串字面量、字符串参数传递
|
||||
*/
|
||||
@extern(vm) fn vm_printf(fmt: *u8, ...) void;
|
||||
@extern(vm) fn vm_strlen(s: *u8) i32;
|
||||
@extern(vm) fn vm_strcmp(a: *u8, b: *u8) i32;
|
||||
|
||||
fn main() i32 {
|
||||
/* vm_printf 输出测试 */
|
||||
vm_printf("hello spl\n");
|
||||
vm_printf("%d %d %d\n", 1, 2, 3);
|
||||
vm_printf("chars: %c%c\n", 'A', 'B');
|
||||
|
||||
/* 字符串字面量用于 extern */
|
||||
var len := vm_strlen("hello");
|
||||
if len != 5 { ret 1; }
|
||||
|
||||
/* 字符串比较 */
|
||||
var cmp := vm_strcmp("abc", "abc");
|
||||
if cmp != 0 { ret 2; }
|
||||
|
||||
var cmp2 := vm_strcmp("abc", "def");
|
||||
if cmp2 == 0 { ret 3; }
|
||||
|
||||
/* 字符串作为格式化参数 */
|
||||
vm_printf("string test: %s %s\n", "foo", "bar");
|
||||
|
||||
/* vm_printf 返回 void(不关心返回值)*/
|
||||
vm_printf("all extern tests done\n");
|
||||
|
||||
ret 0;
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/* ===== 模块7:高级特性 =====
|
||||
* test14_assignment — 复合赋值
|
||||
* 难度:2/5
|
||||
* 验证点:+= -= *= /= %= &= |= ^= <<= >>=
|
||||
*/
|
||||
fn main() i32 {
|
||||
var x: i32 = 10;
|
||||
|
||||
/* += */
|
||||
x += 5;
|
||||
if x != 15 { ret 1; }
|
||||
|
||||
/* -= */
|
||||
x -= 3;
|
||||
if x != 12 { ret 2; }
|
||||
|
||||
/* *= */
|
||||
x *= 2;
|
||||
if x != 24 { ret 3; }
|
||||
|
||||
/* /= */
|
||||
x /= 4;
|
||||
if x != 6 { ret 4; }
|
||||
|
||||
/* %= */
|
||||
var y: i32 = 17;
|
||||
y %= 5;
|
||||
if y != 2 { ret 5; }
|
||||
|
||||
/* &= */
|
||||
var a: i32 = 0xFF;
|
||||
a &= 0x0F;
|
||||
if a != 0x0F { ret 6; }
|
||||
|
||||
/* |= */
|
||||
var b: i32 = 0xF0;
|
||||
b |= 0x0F;
|
||||
if b != 0xFF { ret 7; }
|
||||
|
||||
/* ^= */
|
||||
var c: i32 = 0xFF;
|
||||
c ^= 0xF0;
|
||||
if c != 0x0F { ret 8; }
|
||||
|
||||
/* <<= */
|
||||
var d: i32 = 1;
|
||||
d <<= 4;
|
||||
if d != 16 { ret 9; }
|
||||
|
||||
/* >>= */
|
||||
var e: i32 = 64;
|
||||
e >>= 3;
|
||||
if e != 8 { ret 10; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/* ===== 模块7:高级特性 =====
|
||||
* test15_defer — 延迟执行
|
||||
* 难度:3/5
|
||||
* 验证点:defer 语句、defer 块、多个 defer(逆序执行)、
|
||||
* 函数中 defer、块作用域 defer
|
||||
*/
|
||||
@extern(vm) fn vm_printf(fmt: *u8, ...) void;
|
||||
|
||||
fn with_cleanup() void {
|
||||
defer vm_printf(" inner defer\n");
|
||||
vm_printf(" inside with_cleanup\n");
|
||||
}
|
||||
|
||||
fn main() i32 {
|
||||
vm_printf("--- defer test ---\n");
|
||||
|
||||
/* defer 语句 */
|
||||
defer vm_printf("defer1\n");
|
||||
vm_printf("after defer1\n");
|
||||
|
||||
/* defer 块 */
|
||||
defer {
|
||||
vm_printf("defer block\n");
|
||||
}
|
||||
vm_printf("after defer block\n");
|
||||
|
||||
/* 函数内 defer */
|
||||
with_cleanup();
|
||||
vm_printf("after with_cleanup\n");
|
||||
|
||||
/* 多个 defer 应逆序执行出作用域应该立刻执行,包括循环作用域 */
|
||||
{
|
||||
defer vm_printf("block defer last\n");
|
||||
defer vm_printf("block defer middle\n");
|
||||
defer vm_printf("block defer first (should print third)\n");
|
||||
}
|
||||
|
||||
/* 多个 defer 应逆序执行 */
|
||||
defer vm_printf("defer last\n");
|
||||
defer vm_printf("defer middle\n");
|
||||
defer vm_printf("defer first (should print third)\n");
|
||||
|
||||
vm_printf("--- defer test end ---\n");
|
||||
ret 0;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/* ===== 模块7:高级特性 =====
|
||||
* test16_methods — 类型关联方法
|
||||
* 难度:3/5
|
||||
* 验证点:struct 方法、enum 方法、self 参数自动填充、方法调用
|
||||
*/
|
||||
@extern(vm) fn vm_printf(fmt: *u8, ...) void;
|
||||
|
||||
type Point = struct {
|
||||
x: i32,
|
||||
y: i32,
|
||||
|
||||
fn init(x: i32, y: i32) Point {
|
||||
ret Point { .x = x, .y = y };
|
||||
}
|
||||
|
||||
fn dump(self: *Point) void {
|
||||
vm_printf("Point(%d, %d)\n", self.x, self.y);
|
||||
}
|
||||
}
|
||||
|
||||
type Expr = enum {
|
||||
Int: i32,
|
||||
Add: struct { left: *Expr, right: *Expr },
|
||||
|
||||
fn eval(self: *Expr) i32 {
|
||||
match self {
|
||||
.Int[val] => { ret val; },
|
||||
.Add[sub] => { ret eval(sub.left) + eval(sub.right); }
|
||||
}
|
||||
ret 0;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() i32 {
|
||||
/* struct 方法调用 */
|
||||
var p: Point = Point.init(3, 4);
|
||||
p.dump(&p);
|
||||
|
||||
/* enum 方法 + match */
|
||||
var expr_l := Expr { .Int = 3 };
|
||||
var expr_r := Expr { .Int = 4 };
|
||||
var expr := Expr { .Add = .{ .left = expr_l, .right = expr_r } };
|
||||
var result := expr.eval(&expr);
|
||||
vm_printf("eval result: %d\n", result);
|
||||
if result != 7 { ret 1; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/* ===== 模块8:综合 =====
|
||||
* test17_integration — 综合测试
|
||||
* 难度:3/5
|
||||
* 验证点:多特性组合——指针 + 结构体 + 函数 + 循环 + 数组 + 切片
|
||||
*/
|
||||
@extern(vm) fn vm_printf(fmt: *u8, ...) void;
|
||||
|
||||
type Point = struct {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
/* 计算点积 */
|
||||
fn dot(a: *Point, b: *Point) i32 {
|
||||
ret a.x * b.x + a.y * b.y;
|
||||
}
|
||||
|
||||
/* 递归斐波那契 */
|
||||
fn fib(n: i32) i32 {
|
||||
if n <= 1 { ret n; }
|
||||
ret fib(n - 1) + fib(n - 2);
|
||||
}
|
||||
|
||||
fn main() i32 {
|
||||
/* 综合:指针 + 结构体 + 函数 */
|
||||
var p1: Point;
|
||||
p1.x = 3;
|
||||
p1.y = 4;
|
||||
|
||||
var p2: Point;
|
||||
p2.x = 5;
|
||||
p2.y = 6;
|
||||
|
||||
var d := dot(&p1, &p2);
|
||||
/* 3*5 + 4*6 = 15 + 24 = 39 */
|
||||
if d != 39 { ret 1; }
|
||||
|
||||
/* 综合:数组 + while 循环 */
|
||||
var arr: [5]i32 = [5]i32{1, 2, 3, 4, 5};
|
||||
var sum: i32 = 0;
|
||||
var i: i32 = 0;
|
||||
while i < 5 {
|
||||
sum = sum + arr[i];
|
||||
i = i + 1;
|
||||
}
|
||||
if sum != 15 { ret 2; }
|
||||
|
||||
/* 综合:切片 + for */
|
||||
var sl: []i32 = arr[1..4];
|
||||
var sl_sum: i32 = 0;
|
||||
for sl as val {
|
||||
sl_sum = sl_sum + val;
|
||||
}
|
||||
if sl_sum != 9 { ret 3; } /* 2+3+4 */
|
||||
|
||||
/* 综合:递归 */
|
||||
var f := fib(10);
|
||||
if f != 55 { ret 4; }
|
||||
|
||||
/* 综合:loop/break/continue */
|
||||
var n: i32 = 0;
|
||||
var count: i32 = 0;
|
||||
loop {
|
||||
n = n + 1;
|
||||
if n == 2 { continue; }
|
||||
count = count + 1;
|
||||
if n >= 5 { break; }
|
||||
}
|
||||
/* 执行 n=1,3,4,5 共 4 次 (n=2 被 continue) */
|
||||
if count != 4 { ret 5; }
|
||||
|
||||
/* 综合:指针修改结构体 */
|
||||
var pp: *Point = &p1;
|
||||
pp.x = 10;
|
||||
pp.y = 20;
|
||||
if p1.x != 10 { ret 6; }
|
||||
if p1.y != 20 { ret 7; }
|
||||
|
||||
/* 综合:嵌套控制流 */
|
||||
var mat: [3]i32 = [3]i32{1, 2, 3};
|
||||
var outer_sum: i32 = 0;
|
||||
var j: i32 = 0;
|
||||
while j < 3 {
|
||||
var k: i32 = 0;
|
||||
while k < 3 {
|
||||
if mat[j] > mat[k] {
|
||||
outer_sum = outer_sum + 1;
|
||||
}
|
||||
k = k + 1;
|
||||
}
|
||||
j = j + 1;
|
||||
}
|
||||
if outer_sum != 3 { ret 8; }
|
||||
ret 0;
|
||||
}
|
||||
@@ -1,488 +0,0 @@
|
||||
/* ===== 模块4:match 语句 =====
|
||||
* test18_match — match 枚举匹配 + 整数匹配(类似 switch)
|
||||
* 难度:3/5
|
||||
* 验证点:枚举匹配、带数据绑定、结构体字段绑定、枚举指针、
|
||||
* 整数自变量匹配、默认分支 _
|
||||
*/
|
||||
|
||||
/* ---- 简单枚举(无数据) ---- */
|
||||
type Color = enum {
|
||||
Red;
|
||||
Green;
|
||||
Blue;
|
||||
}
|
||||
|
||||
/* ---- 带 i32 数据的枚举 ---- */
|
||||
type Optional = enum {
|
||||
Some: i32;
|
||||
None;
|
||||
}
|
||||
|
||||
/* ---- 带结构体数据的枚举 ---- */
|
||||
type Point = struct {
|
||||
x: i32;
|
||||
y: i32;
|
||||
}
|
||||
|
||||
type Shape = enum {
|
||||
Circle: i32;
|
||||
Rect: Point;
|
||||
}
|
||||
|
||||
/* ---- 多变体枚举 ---- */
|
||||
type ActionResult = enum {
|
||||
Success: i32;
|
||||
NotFound;
|
||||
Timeout: i32;
|
||||
Error: *u8;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 测试 1: 无数据枚举匹配
|
||||
* ============================================================ */
|
||||
|
||||
fn test_color_match() i32 {
|
||||
var c: Color = Color { .Red };
|
||||
var val: i32 = 0;
|
||||
|
||||
match c {
|
||||
.Red => { val = 1; },
|
||||
.Green => { val = 2; },
|
||||
.Blue => { val = 3; }
|
||||
}
|
||||
if val != 1 { ret 1; }
|
||||
|
||||
c = Color { .Green };
|
||||
match c {
|
||||
.Red => { val = 0; },
|
||||
.Green => { val = 2; },
|
||||
.Blue => { val = 0; }
|
||||
}
|
||||
if val != 2 { ret 2; }
|
||||
|
||||
c = Color { .Blue };
|
||||
match c {
|
||||
.Red => { val = 0; },
|
||||
.Green => { val = 0; },
|
||||
.Blue => { val = 3; }
|
||||
}
|
||||
if val != 3 { ret 3; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 测试 2: 带 i32 数据枚举匹配
|
||||
* ============================================================ */
|
||||
|
||||
fn test_optional_match() i32 {
|
||||
var o: Optional = Optional { .Some = 42 };
|
||||
|
||||
match o {
|
||||
.Some[val] => {
|
||||
if val != 42 { ret 1; }
|
||||
},
|
||||
.None => {
|
||||
ret 2;
|
||||
}
|
||||
}
|
||||
|
||||
o = Optional { .None };
|
||||
var is_none: i32 = 0;
|
||||
match o {
|
||||
.Some[val] => {},
|
||||
.None => { is_none = 1; }
|
||||
}
|
||||
if is_none != 1 { ret 3; }
|
||||
|
||||
/* 多次提取不同值 */
|
||||
o = Optional { .Some = 99 };
|
||||
match o {
|
||||
.Some[val] => {
|
||||
if val != 99 { ret 4; }
|
||||
},
|
||||
.None => { ret 5; }
|
||||
}
|
||||
|
||||
ret 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 测试 3: 带结构体数据枚举匹配(多字段绑定)
|
||||
* ============================================================ */
|
||||
|
||||
fn test_shape_match() i32 {
|
||||
/* Circle: 单数据 */
|
||||
var s: Shape = Shape { .Circle = 10 };
|
||||
match s {
|
||||
.Circle[r] => {
|
||||
if r != 10 { ret 1; }
|
||||
},
|
||||
.Rect[p] => {
|
||||
ret 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Rect: 结构体数据,绑定为 (x, y) 对应 Point 的字段 */
|
||||
s = Shape { .Rect = Point { .x = 3, .y = 4 } };
|
||||
match s {
|
||||
.Circle[r] => { ret 3; },
|
||||
.Rect[p] => {
|
||||
if p.x != 3 { ret 4; }
|
||||
if p.y != 4 { ret 5; }
|
||||
}
|
||||
}
|
||||
|
||||
ret 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 测试 4: 多数据变体枚举匹配
|
||||
* ============================================================ */
|
||||
|
||||
fn test_action_result_match() i32 {
|
||||
var r: ActionResult = ActionResult { .Success = 200 };
|
||||
match r {
|
||||
.Success[code] => {
|
||||
if code != 200 { ret 1; }
|
||||
},
|
||||
.NotFound => {
|
||||
ret 2;
|
||||
},
|
||||
.Timeout[ms] => {
|
||||
ret 3;
|
||||
},
|
||||
.Error[msg] => {
|
||||
ret 4;
|
||||
}
|
||||
}
|
||||
|
||||
r = ActionResult { .NotFound };
|
||||
var found: i32 = 1;
|
||||
match r {
|
||||
.Success[code] => { found = 0; },
|
||||
.NotFound => { },
|
||||
.Timeout[ms] => { found = 0; },
|
||||
.Error[msg] => { found = 0; }
|
||||
}
|
||||
if found != 1 { ret 5; }
|
||||
|
||||
r = ActionResult { .Timeout = 5000 };
|
||||
match r {
|
||||
.Success[code] => { ret 6; },
|
||||
.NotFound => { ret 7; },
|
||||
.Timeout[ms] => {
|
||||
if ms != 5000 { ret 8; }
|
||||
},
|
||||
.Error[msg] => { ret 9; }
|
||||
}
|
||||
|
||||
ret 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 测试 5: 枚举指针匹配
|
||||
* ============================================================ */
|
||||
|
||||
fn test_ptr_match() i32 {
|
||||
var c: Color = Color { .Green };
|
||||
var p: *Color = &c;
|
||||
|
||||
match p {
|
||||
.Red => { ret 1; },
|
||||
.Green => { },
|
||||
.Blue => { ret 2; }
|
||||
}
|
||||
|
||||
/* 修改后通过指针匹配 */
|
||||
c = Color { .Blue };
|
||||
match p {
|
||||
.Red => { ret 3; },
|
||||
.Green => { ret 4; },
|
||||
.Blue => { }
|
||||
}
|
||||
|
||||
ret 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 测试 6: match 作为函数返回值
|
||||
* ============================================================ */
|
||||
|
||||
fn classify_color(c: Color) i32 {
|
||||
match c {
|
||||
.Red => { ret 1; },
|
||||
.Green => { ret 2; },
|
||||
.Blue => { ret 3; }
|
||||
}
|
||||
ret 0;
|
||||
}
|
||||
|
||||
fn test_match_in_func() i32 {
|
||||
var r: i32;
|
||||
|
||||
r = classify_color(Color { .Red });
|
||||
if r != 1 { ret 1; }
|
||||
|
||||
r = classify_color(Color { .Green });
|
||||
if r != 2 { ret 2; }
|
||||
|
||||
r = classify_color(Color { .Blue });
|
||||
if r != 3 { ret 3; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 测试 7: match 嵌套在循环中
|
||||
* ============================================================ */
|
||||
|
||||
fn test_match_in_loop() i32 {
|
||||
var i: i32 = 0;
|
||||
var sum: i32 = 0;
|
||||
|
||||
while i < 3 {
|
||||
var o: Optional;
|
||||
if i == 0 {
|
||||
o = Optional { .Some = 10 };
|
||||
} else if i == 1 {
|
||||
o = Optional { .Some = 20 };
|
||||
} else {
|
||||
o = Optional { .Some = 30 };
|
||||
}
|
||||
|
||||
match o {
|
||||
.Some[val] => {
|
||||
sum = sum + val;
|
||||
},
|
||||
.None => { }
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
if sum != 60 { ret 1; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 测试 8: 整数 match(类似 switch)
|
||||
* ============================================================ */
|
||||
|
||||
fn test_int_match() i32 {
|
||||
var x: i32 = 2;
|
||||
var result: i32 = 0;
|
||||
|
||||
match x {
|
||||
1 => { result = 10; },
|
||||
2 => { result = 20; },
|
||||
3 => { result = 30; }
|
||||
}
|
||||
if result != 20 { ret 1; }
|
||||
|
||||
/* 匹配第一个值 */
|
||||
x = 1;
|
||||
match x {
|
||||
1 => { result = 100; },
|
||||
2 => { result = 200; },
|
||||
3 => { result = 300; }
|
||||
}
|
||||
if result != 100 { ret 2; }
|
||||
|
||||
/* 匹配最后一个值 */
|
||||
x = 3;
|
||||
match x {
|
||||
1 => { result = 1000; },
|
||||
2 => { result = 2000; },
|
||||
3 => { result = 3000; }
|
||||
}
|
||||
if result != 3000 { ret 3; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 测试 9: 整数 match 带默认分支 _
|
||||
* ============================================================ */
|
||||
|
||||
fn test_int_match_default() i32 {
|
||||
var x: i32 = 99;
|
||||
var result: i32 = 0;
|
||||
|
||||
match x {
|
||||
1 => { result = 1; },
|
||||
2 => { result = 2; },
|
||||
_ => { result = 99; }
|
||||
}
|
||||
if result != 99 { ret 1; }
|
||||
|
||||
/* 默认分支未触发 */
|
||||
x = 1;
|
||||
match x {
|
||||
1 => { result = 1; },
|
||||
2 => { result = 2; },
|
||||
_ => { result = 99; }
|
||||
}
|
||||
if result != 1 { ret 2; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 测试 10: 整数 match 多个值跳转到相同逻辑
|
||||
* ============================================================ */
|
||||
|
||||
fn test_int_match_multi() i32 {
|
||||
var x: i32 = 2;
|
||||
var result: i32 = 0;
|
||||
|
||||
/* 每个分支独立 */
|
||||
match x {
|
||||
0 => { result = 0; },
|
||||
1 => { result = 1; },
|
||||
2 => { result = 2; },
|
||||
3 => { result = 3; }
|
||||
}
|
||||
if result != 2 { ret 1; }
|
||||
|
||||
/* 负数和零 */
|
||||
x = -1;
|
||||
match x {
|
||||
-1 => { result = -1; },
|
||||
0 => { result = 0; },
|
||||
1 => { result = 1; }
|
||||
}
|
||||
if result != -1 { ret 2; }
|
||||
|
||||
x = 0;
|
||||
match x {
|
||||
-1 => { result = -1; },
|
||||
0 => { result = 0; },
|
||||
1 => { result = 1; }
|
||||
}
|
||||
if result != 0 { ret 3; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 测试 11a: match 多值 fallthrough: 1, 2, 3 => body
|
||||
* ============================================================ */
|
||||
|
||||
fn test_int_match_fallthrough() i32 {
|
||||
var x: i32;
|
||||
var r: i32;
|
||||
|
||||
/* 三个值映射到同一个 body */
|
||||
x = 1; r = 0;
|
||||
match x {
|
||||
1, 2, 3 => { r = 10; },
|
||||
4, 5 => { r = 20; }
|
||||
}
|
||||
if r != 10 { ret 1; }
|
||||
|
||||
x = 3;
|
||||
match x {
|
||||
1, 2, 3 => { r = 10; },
|
||||
4, 5 => { r = 20; }
|
||||
}
|
||||
if r != 10 { ret 2; }
|
||||
|
||||
x = 5;
|
||||
match x {
|
||||
1, 2, 3 => { r = 10; },
|
||||
4, 5 => { r = 20; }
|
||||
}
|
||||
if r != 20 { ret 3; }
|
||||
|
||||
/* 单一值(非fallthrough)仍然正常 */
|
||||
x = 7; r = 0;
|
||||
match x {
|
||||
1 => { r = 1; },
|
||||
7 => { r = 7; }
|
||||
}
|
||||
if r != 7 { ret 4; }
|
||||
|
||||
/* 多个负数值 */
|
||||
x = -2; r = 0;
|
||||
match x {
|
||||
-3, -2, -1 => { r = 100; },
|
||||
0, 1 => { r = 200; }
|
||||
}
|
||||
if r != 100 { ret 5; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 测试 11b: match with body 中修改变量
|
||||
* ============================================================ */
|
||||
|
||||
fn test_match_with_side_effects() i32 {
|
||||
var x: i32 = 3;
|
||||
var acc: i32 = 0;
|
||||
|
||||
match x {
|
||||
1 => { acc = acc + 1; },
|
||||
2 => { acc = acc + 2; },
|
||||
3 => { acc = acc + 3; },
|
||||
4 => { acc = acc + 4; }
|
||||
}
|
||||
if acc != 3 { ret 1; }
|
||||
|
||||
/* 再次 match 同一个变量 */
|
||||
match x {
|
||||
1 => { acc = acc + 1; },
|
||||
2 => { acc = acc + 2; },
|
||||
3 => { acc = acc + 3; },
|
||||
4 => { acc = acc + 4; }
|
||||
}
|
||||
if acc != 6 { ret 2; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 主函数
|
||||
* ============================================================ */
|
||||
|
||||
fn main() i32 {
|
||||
var r: i32;
|
||||
|
||||
r = test_color_match();
|
||||
if r != 0 { ret r; }
|
||||
|
||||
r = test_optional_match();
|
||||
if r != 0 { ret r + 10; }
|
||||
|
||||
r = test_shape_match();
|
||||
if r != 0 { ret r + 20; }
|
||||
|
||||
r = test_action_result_match();
|
||||
if r != 0 { ret r + 30; }
|
||||
|
||||
r = test_ptr_match();
|
||||
if r != 0 { ret r + 40; }
|
||||
|
||||
r = test_match_in_func();
|
||||
if r != 0 { ret r + 50; }
|
||||
|
||||
r = test_match_in_loop();
|
||||
if r != 0 { ret r + 60; }
|
||||
|
||||
r = test_int_match();
|
||||
if r != 0 { ret r + 70; }
|
||||
|
||||
r = test_int_match_default();
|
||||
if r != 0 { ret r + 80; }
|
||||
|
||||
r = test_int_match_multi();
|
||||
if r != 0 { ret r + 90; }
|
||||
|
||||
r = test_match_with_side_effects();
|
||||
if r != 0 { ret r + 100; }
|
||||
|
||||
r = test_int_match_fallthrough();
|
||||
if r != 0 { ret r + 110; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
/* ===== 进阶数组与切片 =====
|
||||
* test19_hardarray — 多维数组、多维切片、切片构造、字符串测试
|
||||
* 难度:4/5
|
||||
* 验证点:多维数组索引与修改、多维切片、切片字段读写、扁平指针访问、字符串切片
|
||||
*/
|
||||
fn test_string() i32 {
|
||||
/* ============================
|
||||
* String test: str is []u8
|
||||
* ============================ */
|
||||
var data: *u8 = "hello";
|
||||
var s: []u8 = .{ .ptr = data, .len = 5 };
|
||||
|
||||
if s.len != 5 { ret 100; }
|
||||
if s[0] != 104 { ret 101; } /* 'h' */
|
||||
if s[1] != 101 { ret 102; } /* 'e' */
|
||||
if s[4] != 111 { ret 103; } /* 'o' */
|
||||
|
||||
/* Slice the string slice */
|
||||
var sub: []u8 = s[1..4];
|
||||
if sub.len != 3 { ret 104; }
|
||||
if sub[0] != 101 { ret 105; } /* 'e' */
|
||||
if sub[2] != 108 { ret 106; } /* 'l' */
|
||||
|
||||
/* Modify through slice → original changes */
|
||||
s[0] = 72; /* 'H' */
|
||||
if data[0] != 72 { ret 107; }
|
||||
|
||||
/* Full slice */
|
||||
var full: []u8 = s[0..];
|
||||
if full.len != 5 { ret 108; }
|
||||
if full[0] != 72 { ret 109; }
|
||||
|
||||
/* Construct slice from pointer via field assignment */
|
||||
var s2: []u8;
|
||||
s2.ptr = data;
|
||||
s2.len = 3;
|
||||
if s2.len != 3 { ret 110; }
|
||||
if s2[0] != 72 { ret 111; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
|
||||
fn main() i32 {
|
||||
/* ============================
|
||||
* Part 1: 多维数组(逐元素初始化)
|
||||
* ============================ */
|
||||
var matrix: [2][3]i32;
|
||||
matrix[0][0] = 1; matrix[0][1] = 2; matrix[0][2] = 3;
|
||||
matrix[1][0] = 4; matrix[1][1] = 5; matrix[1][2] = 6;
|
||||
|
||||
if matrix[0][0] != 1 { ret 1; }
|
||||
if matrix[0][1] != 2 { ret 2; }
|
||||
if matrix[0][2] != 3 { ret 3; }
|
||||
if matrix[1][0] != 4 { ret 4; }
|
||||
if matrix[1][1] != 5 { ret 5; }
|
||||
if matrix[1][2] != 6 { ret 6; }
|
||||
|
||||
/* 元素修改 */
|
||||
matrix[0][0] = 10;
|
||||
matrix[1][2] = 60;
|
||||
if matrix[0][0] != 10 { ret 7; }
|
||||
if matrix[1][2] != 60 { ret 8; }
|
||||
|
||||
/* ============================
|
||||
* Part 2: 嵌套循环遍历多维数组
|
||||
* ============================ */
|
||||
var big: [3][4]i32;
|
||||
big[0][0] = 1; big[0][1] = 2; big[0][2] = 3; big[0][3] = 4;
|
||||
big[1][0] = 5; big[1][1] = 6; big[1][2] = 7; big[1][3] = 8;
|
||||
big[2][0] = 9; big[2][1] = 10; big[2][2] = 11; big[2][3] = 12;
|
||||
|
||||
var total: i32 = 0;
|
||||
var i: i32 = 0;
|
||||
while i < 3 {
|
||||
var j: i32 = 0;
|
||||
while j < 4 {
|
||||
total = total + big[i][j];
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
if total != 78 { ret 9; }
|
||||
|
||||
/* ============================
|
||||
* Part 3: &取地址 + 扁平指针访问
|
||||
* ============================ */
|
||||
var flat: *i32 = &matrix[0][0];
|
||||
if flat[0] != 10 { ret 10; }
|
||||
if flat[1] != 2 { ret 11; }
|
||||
if flat[2] != 3 { ret 12; }
|
||||
if flat[3] != 4 { ret 13; }
|
||||
if flat[4] != 5 { ret 14; }
|
||||
if flat[5] != 60 { ret 15; }
|
||||
|
||||
/* ============================
|
||||
* Part 4: 多维数组切片
|
||||
* ============================ */
|
||||
var row: []i32 = matrix[0][0..3];
|
||||
if row.len != 3 { ret 16; }
|
||||
if row[0] != 10 { ret 17; }
|
||||
if row[1] != 2 { ret 18; }
|
||||
if row[2] != 3 { ret 19; }
|
||||
|
||||
/* 切取第二行 */
|
||||
var row2: []i32 = matrix[1][0..];
|
||||
if row2.len != 3 { ret 20; }
|
||||
if row2[0] != 4 { ret 21; }
|
||||
if row2[2] != 60 { ret 22; }
|
||||
|
||||
/* ============================
|
||||
* Part 5: 切片的切片
|
||||
* ============================ */
|
||||
var sub: []i32 = row[1..3];
|
||||
if sub.len != 2 { ret 23; }
|
||||
if sub[0] != 2 { ret 24; }
|
||||
if sub[1] != 3 { ret 25; }
|
||||
|
||||
/* ============================
|
||||
* Part 6: 切片字段读写
|
||||
* ============================ */
|
||||
var arr: [4]i32;
|
||||
arr[0] = 100; arr[1] = 200; arr[2] = 300; arr[3] = 400;
|
||||
var custom: []i32;
|
||||
custom.ptr = &arr[1];
|
||||
custom.len = 2;
|
||||
|
||||
if custom.len != 2 { ret 26; }
|
||||
if custom[0] != 200 { ret 27; }
|
||||
if custom[1] != 300 { ret 28; }
|
||||
|
||||
/* 修改切片长度 */
|
||||
custom.len = 3;
|
||||
if custom.len != 3 { ret 29; }
|
||||
if custom[2] != 400 { ret 30; }
|
||||
|
||||
/* ============================
|
||||
* Part 7: 空范围 / 全切片
|
||||
* ============================ */
|
||||
var full: []i32 = arr[0..];
|
||||
if full.len != 4 { ret 31; }
|
||||
if full[0] != 100 { ret 32; }
|
||||
if full[3] != 400 { ret 33; }
|
||||
|
||||
/* ============================
|
||||
* Part 8: 从指针构造切片
|
||||
* ============================ */
|
||||
var data: [5]i32;
|
||||
data[0] = 10; data[1] = 20; data[2] = 30; data[3] = 40; data[4] = 50;
|
||||
var p: *i32 = &data[2];
|
||||
var from_ptr: []i32 = .{ .ptr = p, .len = 2 };
|
||||
var from_ptr2: []i32;
|
||||
from_ptr2.ptr = p;
|
||||
from_ptr2.len = 2;
|
||||
|
||||
if from_ptr.len != 2 { ret 34; }
|
||||
if from_ptr[0] != 30 { ret 35; }
|
||||
if from_ptr[1] != 40 { ret 36; }
|
||||
|
||||
if from_ptr2.len != 2 { ret 37; }
|
||||
if from_ptr2[0] != 30 { ret 38; }
|
||||
if from_ptr2[1] != 40 { ret 39; }
|
||||
|
||||
/* ============================
|
||||
* Part 9: 切片元素修改反映到原始数组
|
||||
* ============================ */
|
||||
row2[0] = 99;
|
||||
if matrix[1][0] != 99 { ret 40; }
|
||||
|
||||
/* ============================
|
||||
* Part 10: 1D 数组字面量仍然正常
|
||||
* ============================ */
|
||||
var literal: [3]i32 = [3]i32{10, 20, 30};
|
||||
if literal[0] != 10 { ret 41; }
|
||||
if literal[1] != 20 { ret 42; }
|
||||
if literal[2] != 30 { ret 43; }
|
||||
|
||||
/* ============================
|
||||
* Part 11: 字符串切片测试
|
||||
* ============================ */
|
||||
var r: i32 = test_string();
|
||||
if r != 0 { ret r; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
@@ -1,320 +0,0 @@
|
||||
/* ===== å¤<C3A5>æ<EFBFBD>‚类型嵌套综å<C2BC>ˆæµ‹è¯• =====
|
||||
* test20_complex â€?结构体嵌套ã€<C3A3>切片ã€<C3A3>数组ã€<C3A3>方法ã€<C3A3>类型别å<C2AB><C3A5>ã€<C3A3>枚举ç‰
|
||||
* 难度�/5
|
||||
*/
|
||||
/* ---- 基础结构�---- */
|
||||
type Point = struct {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
/* ---- 嵌套结构�---- */
|
||||
type Rect = struct {
|
||||
min: Point,
|
||||
max: Point,
|
||||
}
|
||||
|
||||
/* ---- å<>«åˆ‡ç‰‡å—段的结构ä½?(æ ¸å¿ƒ bug 测试) ---- */
|
||||
type Buffer = struct {
|
||||
data: []u8,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
/* ---- å<>«æ•°ç»„å—æ®µçš„结构ä½?---- */
|
||||
type MatrixRow = struct {
|
||||
items: [4]i32,
|
||||
}
|
||||
|
||||
/* ---- å<>«æŒ‡é’ˆå—段的结构ä½?---- */
|
||||
type Node = struct {
|
||||
ptr: *i32,
|
||||
val: i32,
|
||||
}
|
||||
|
||||
/* ---- 多层级嵌套:结构体里的结构体里的切片 ---- */
|
||||
type Bundle = struct {
|
||||
name: *u8,
|
||||
buf: Buffer,
|
||||
row: MatrixRow,
|
||||
pt: Point,
|
||||
}
|
||||
|
||||
/* ---- 枚举å<C2BE>«æ•°æ<C2B0>?---- */
|
||||
type Status = enum {
|
||||
Active: i32;
|
||||
Inactive;
|
||||
Pending: Point;
|
||||
}
|
||||
|
||||
/* ---- å<>«æ–¹æ³•的结构ä½?(方法定义在结构体内部) ---- */
|
||||
type Counter = struct {
|
||||
val: i32,
|
||||
|
||||
fn inc(self: *Counter) i32 {
|
||||
self.val = self.val + 1;
|
||||
ret self.val;
|
||||
}
|
||||
|
||||
fn add(self: *Counter, n: i32) i32 {
|
||||
self.val = self.val + n;
|
||||
ret self.val;
|
||||
}
|
||||
|
||||
fn reset(self: *Counter) {
|
||||
self.val = 0;
|
||||
}
|
||||
|
||||
fn get(self: *Counter) i32 {
|
||||
ret self.val;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 测试 1: 切片在结构体内部åˆ<C3A5>å§‹åŒ?(ä¿®å¤<C3A5>çš„æ ¸å¿?bug)
|
||||
* ============================================================ */
|
||||
|
||||
fn test_slice_in_struct() i32 {
|
||||
var raw: [4]u8;
|
||||
raw[0] = 65; raw[1] = 66; raw[2] = 67; raw[3] = 68;
|
||||
|
||||
/* Bug fix: { .ptr = ..., .len = ... } inside struct literal */
|
||||
var b: Buffer = Buffer { .data = .{ .ptr = &raw[0], .len = 4 }, .len = 4 };
|
||||
|
||||
if b.len != 4 { ret 1; }
|
||||
if b.data[0] != 65 { ret 2; }
|
||||
if b.data[1] != 66 { ret 3; }
|
||||
if b.data[3] != 68 { ret 4; }
|
||||
|
||||
/* Modify through slice �verify reflection */
|
||||
b.data[0] = 90;
|
||||
if raw[0] != 90 { ret 5; }
|
||||
|
||||
/* Initialize with shorter slice */
|
||||
var b2: Buffer = Buffer { .data = .{ .ptr = &raw[2], .len = 2 }, .len = 2 };
|
||||
if b2.len != 2 { ret 6; }
|
||||
if b2.data[0] != 67 { ret 7; }
|
||||
|
||||
/* Slice field assignment via field access */
|
||||
b2.data.ptr = &raw[0];
|
||||
b2.data.len = 4;
|
||||
if b2.data[0] != 90 { ret 8; }
|
||||
if b2.data.len != 4 { ret 9; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 测试 2: 结构体å<E2809C>«æ•°ç»„å—æ®µ
|
||||
* ============================================================ */
|
||||
|
||||
fn test_struct_with_array() i32 {
|
||||
var mr: MatrixRow = MatrixRow { .items = [4]i32{10, 20, 30, 40} };
|
||||
|
||||
if mr.items[0] != 10 { ret 1; }
|
||||
if mr.items[1] != 20 { ret 2; }
|
||||
if mr.items[2] != 30 { ret 3; }
|
||||
if mr.items[3] != 40 { ret 4; }
|
||||
|
||||
/* ä¿®æ”¹æ•°ç»„å…ƒç´ */
|
||||
mr.items[2] = 99;
|
||||
if mr.items[2] != 99 { ret 5; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 测试 3: 嵌套结构体åˆ<C3A5>始化
|
||||
* ============================================================ */
|
||||
|
||||
fn test_nested_struct() i32 {
|
||||
var p: Point = Point { .x = 5, .y = 10 };
|
||||
if p.x != 5 { ret 1; }
|
||||
if p.y != 10 { ret 2; }
|
||||
|
||||
/* 嵌套结构体å—é<E28094>¢é‡<C3A9> */
|
||||
var r: Rect = Rect {
|
||||
.min = Point { .x = 1, .y = 2 },
|
||||
.max = Point { .x = 3, .y = 4 }
|
||||
};
|
||||
if r.min.x != 1 { ret 3; }
|
||||
if r.min.y != 2 { ret 4; }
|
||||
if r.max.x != 3 { ret 5; }
|
||||
if r.max.y != 4 { ret 6; }
|
||||
|
||||
/* ä¿®æ”¹åµŒå¥—å—æ®µ */
|
||||
r.min.x = 100;
|
||||
if r.min.x != 100 { ret 7; }
|
||||
if r.min.y != 2 { ret 8; } /* unchanged */
|
||||
|
||||
ret 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 测试 4: 结构体æˆ<C3A6>员方æ³?(实例方法调用)
|
||||
* ============================================================ */
|
||||
|
||||
fn test_struct_method() i32 {
|
||||
var c: Counter = Counter { .val = 0 };
|
||||
|
||||
/* 实例方法调用 c.inc(&c) */
|
||||
var r1: i32 = c.inc(&c);
|
||||
if r1 != 1 { ret 1; }
|
||||
if c.val != 1 { ret 2; }
|
||||
|
||||
/* 带å<C2A6>‚数方法调ç”?c.add(&c, n) */
|
||||
var r2: i32 = c.add(&c, 5);
|
||||
if r2 != 6 { ret 3; }
|
||||
if c.val != 6 { ret 4; }
|
||||
|
||||
/* 连ç»è°ƒç”¨ (显å¼<C3A5> self) */
|
||||
c.reset(&c);
|
||||
if c.val != 0 { ret 5; }
|
||||
|
||||
c.add(&c, 10);
|
||||
c.inc(&c);
|
||||
var r3: i32 = c.get(&c);
|
||||
if r3 != 11 { ret 6; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 测试 5: 结构体å<E2809C>«æŒ‡é’ˆå—段
|
||||
* ============================================================ */
|
||||
|
||||
fn test_ptr_in_struct() i32 {
|
||||
var v: i32 = 42;
|
||||
var n: Node = Node { .ptr = &v, .val = 99 };
|
||||
|
||||
if n.val != 99 { ret 1; }
|
||||
if n.ptr[0] != 42 { ret 2; }
|
||||
|
||||
/* 通过指针修改 */
|
||||
v = 100;
|
||||
if n.ptr[0] != 100 { ret 3; }
|
||||
|
||||
/* 通过指针在结构体内修�*/
|
||||
n.ptr[0] = 200;
|
||||
if v != 200 { ret 4; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 测试 6: 多层级å¤<C3A5>æ<EFBFBD>‚嵌å¥?
|
||||
* ============================================================ */
|
||||
|
||||
fn test_complex_nesting() i32 {
|
||||
var str_data: [5]u8;
|
||||
str_data[0] = 72; str_data[1] = 101;
|
||||
str_data[2] = 108; str_data[3] = 108; str_data[4] = 111;
|
||||
|
||||
var bundle: Bundle = Bundle {
|
||||
.name = &str_data[0],
|
||||
.buf = Buffer { .data = .{ .ptr = &str_data[1], .len = 3 }, .len = 3 },
|
||||
.row = MatrixRow { .items = [4]i32{1, 2, 3, 4} },
|
||||
.pt = Point { .x = -5, .y = 15 }
|
||||
};
|
||||
|
||||
/* Verify name */
|
||||
if bundle.name[0] != 72 { ret 1; }
|
||||
if bundle.name[4] != 111 { ret 2; }
|
||||
|
||||
/* Verify nested slice */
|
||||
if bundle.buf.len != 3 { ret 3; }
|
||||
if bundle.buf.data[0] != 101 { ret 4; }
|
||||
if bundle.buf.data[2] != 108 { ret 5; }
|
||||
|
||||
/* Verify array field */
|
||||
if bundle.row.items[0] != 1 { ret 6; }
|
||||
if bundle.row.items[3] != 4 { ret 7; }
|
||||
|
||||
/* Verify nested struct field */
|
||||
if bundle.pt.x != -5 { ret 8; }
|
||||
if bundle.pt.y != 15 { ret 9; }
|
||||
|
||||
/* Modify nested slice */
|
||||
bundle.buf.data[1] = 87; /* 'W' */
|
||||
if str_data[2] != 87 { ret 10; }
|
||||
|
||||
/* Modify nested array */
|
||||
bundle.row.items[2] = 33;
|
||||
if bundle.row.items[2] != 33 { ret 11; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 测试 7: 枚举å<C2BE>«ç»“构体数æ<C2B0>®
|
||||
* ============================================================ */
|
||||
|
||||
fn test_enum_complex() i32 {
|
||||
var s: Status = Status { .Active = 42 };
|
||||
|
||||
/* Verify active variant */
|
||||
match s {
|
||||
.Active[val] => {
|
||||
if val != 42 { ret 1; }
|
||||
},
|
||||
.Inactive => {
|
||||
ret 2;
|
||||
},
|
||||
.Pending[p] => {
|
||||
ret 3;
|
||||
}
|
||||
}
|
||||
|
||||
/* Test Inactive variant */
|
||||
var s2: Status = Status { .Inactive };
|
||||
var is_inactive: i32 = 0;
|
||||
match s2 {
|
||||
.Active[val] => {},
|
||||
.Inactive => { is_inactive = 1; },
|
||||
.Pending[p] => {}
|
||||
}
|
||||
if is_inactive != 1 { ret 4; }
|
||||
|
||||
/* Test Pending variant with struct data */
|
||||
var s3: Status = Status { .Pending = Point { .x = 7, .y = 8 } };
|
||||
match s3 {
|
||||
.Active[val] => { ret 5; },
|
||||
.Inactive => { ret 6; },
|
||||
.Pending[p] => {
|
||||
if p.x != 7 { ret 7; }
|
||||
if p.y != 8 { ret 8; }
|
||||
}
|
||||
}
|
||||
|
||||
ret 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 主函�
|
||||
* ============================================================ */
|
||||
|
||||
fn main() i32 {
|
||||
var r: i32;
|
||||
|
||||
r = test_slice_in_struct();
|
||||
if r != 0 { ret r; }
|
||||
|
||||
r = test_struct_with_array();
|
||||
if r != 0 { ret r + 100; }
|
||||
|
||||
r = test_nested_struct();
|
||||
if r != 0 { ret r + 200; }
|
||||
|
||||
r = test_struct_method();
|
||||
if r != 0 { ret r + 300; }
|
||||
|
||||
r = test_ptr_in_struct();
|
||||
if r != 0 { ret r + 400; }
|
||||
|
||||
r = test_complex_nesting();
|
||||
if r != 0 { ret r + 500; }
|
||||
|
||||
r = test_enum_complex();
|
||||
if r != 0 { ret r + 600; }
|
||||
|
||||
ret 0;
|
||||
}
|
||||
Reference in New Issue
Block a user