Compare commits

...

3 Commits

Author SHA1 Message Date
zzy
a2d5dd9ce8 stage1 整理代码 修复错误 2026-07-21 20:00:19 +08:00
zzy
7c5bb41e09 stage1 整理代码 提供更多错误信息 2026-07-21 09:56:19 +08:00
zzy
459b6188a9 stage1 - 全面重构 stage1 编译器架构:类型系统(arena + items)、IR 发射层(spl_emit.h/c)、统一所有 emit 调用点。
- 实现 as 类型转换运算符、修复 &&/|| 短路求值 bug。
- 在 splc1.spl 中实现 Vec/Map/Emit 基础库(~50 个方法)。
- 修复实例方法调用中 self 参数被错误丢弃的 bug。
2026-07-20 20:53:41 +08:00
20 changed files with 485 additions and 344 deletions

View File

@@ -152,6 +152,7 @@ static int spl_type_size(spl_type_t t) {
_r = (spl_val_t)((int64_t)_a OP(int64_t) _b); \ _r = (spl_val_t)((int64_t)_a OP(int64_t) _b); \
break; \ break; \
case SPL_U64: \ case SPL_U64: \
case SPL_PTR: \
case SPL_USIZE: \ case SPL_USIZE: \
case SPL_ISIZE: \ case SPL_ISIZE: \
_r = _a OP _b; \ _r = _a OP _b; \
@@ -213,6 +214,7 @@ static int spl_type_size(spl_type_t t) {
_r = (spl_val_t)((int64_t)_a OP(int64_t) _b); \ _r = (spl_val_t)((int64_t)_a OP(int64_t) _b); \
break; \ break; \
case SPL_U64: \ case SPL_U64: \
case SPL_PTR: \
case SPL_USIZE: \ case SPL_USIZE: \
case SPL_ISIZE: \ case SPL_ISIZE: \
_r = (spl_val_t)((int64_t)_a OP(int64_t) _b); \ _r = (spl_val_t)((int64_t)_a OP(int64_t) _b); \
@@ -254,6 +256,7 @@ static int spl_type_size(spl_type_t t) {
_r = (spl_val_t)((uint64_t)_a OP(uint64_t) _b); \ _r = (spl_val_t)((uint64_t)_a OP(uint64_t) _b); \
break; \ break; \
case SPL_U64: \ case SPL_U64: \
case SPL_PTR: \
case SPL_USIZE: \ case SPL_USIZE: \
case SPL_ISIZE: \ case SPL_ISIZE: \
_r = _a OP _b; \ _r = _a OP _b; \
@@ -346,6 +349,7 @@ static int spl_type_size(spl_type_t t) {
_r = (int64_t)_a OP(int64_t) _b; \ _r = (int64_t)_a OP(int64_t) _b; \
break; \ break; \
case SPL_U64: \ case SPL_U64: \
case SPL_PTR: \
case SPL_USIZE: \ case SPL_USIZE: \
case SPL_ISIZE: \ case SPL_ISIZE: \
_r = _a OP _b; \ _r = _a OP _b; \
@@ -399,6 +403,7 @@ static int spl_type_size(spl_type_t t) {
_r = (uint64_t)_a OP(uint64_t) _b; \ _r = (uint64_t)_a OP(uint64_t) _b; \
break; \ break; \
case SPL_U64: \ case SPL_U64: \
case SPL_PTR: \
case SPL_USIZE: \ case SPL_USIZE: \
case SPL_ISIZE: \ case SPL_ISIZE: \
_r = _a OP _b; \ _r = _a OP _b; \
@@ -665,7 +670,8 @@ int spl_vm_run_once(spl_vm_t *vm) {
if (vm->trace) { if (vm->trace) {
fprintf(stderr, "vm: ip=%zd op=%s type=%s imm=%zu sp=%zd fp=%zd\n", vm->ip - 1, fprintf(stderr, "vm: ip=%zd op=%s type=%s imm=%zu sp=%zd fp=%zd\n", vm->ip - 1,
spl_opcode_name(ins->opcode), spl_type_tag_name(ins->type), ins->imm, vm->sp, vm->fp); spl_opcode_name(ins->opcode), spl_type_tag_name(ins->type), ins->imm, vm->sp,
vm->fp);
} }
switch (ins->opcode) { switch (ins->opcode) {
@@ -1084,7 +1090,7 @@ void spl_vm_dump_instr(spl_vm_t *vm, spl_val_t ip) {
return; return;
spl_ins_t *ins = &vec_at(vm->prog->insns, ip); spl_ins_t *ins = &vec_at(vm->prog->insns, ip);
fprintf(stderr, " instr at ip=%zd: op=%s type=%s imm=%zu\n", ip, spl_opcode_name(ins->opcode), fprintf(stderr, " instr at ip=%zd: op=%s type=%s imm=%zu\n", ip, spl_opcode_name(ins->opcode),
spl_type_tag_name(ins->type), ins->imm); spl_type_tag_name(ins->type), ins->imm);
} }
void spl_vm_stackdump(spl_vm_t *vm, spl_val_t sp) { void spl_vm_stackdump(spl_vm_t *vm, spl_val_t sp) {

View File

@@ -1,6 +1,7 @@
/* spl_comp.c — SPL compiler main logic and codegen helpers */ /* spl_comp.c — SPL compiler main logic and codegen helpers */
#include "spl_comp.h" #include "spl_comp.h"
#include "spl_lex_util.h"
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@@ -61,10 +62,8 @@ void spl_comp_reset(spl_comp_t *ctx) {
ctx->addr_of_mode = 0; ctx->addr_of_mode = 0;
free(ctx->break_patches); free(ctx->break_patches);
ctx->break_patches = NULL; ctx->break_patches = NULL;
vec_free(ctx->emit.call_fixups); vec_free(ctx->emit.fixups);
vec_init(ctx->emit.call_fixups); vec_init(ctx->emit.fixups);
vec_free(ctx->emit.call_fixup_funcs);
vec_init(ctx->emit.call_fixup_funcs);
} }
void spl_comp_error(spl_comp_t *ctx, const char *fmt, ...) { void spl_comp_error(spl_comp_t *ctx, const char *fmt, ...) {
@@ -172,8 +171,7 @@ int spl_lookup_func(spl_comp_t *ctx, const char *name) {
if (items) { if (items) {
vec_for(*items, j) { vec_for(*items, j) {
spl_type_item_t *it = &vec_at(*items, j); spl_type_item_t *it = &vec_at(*items, j);
if (it->item_kind == ITEM_METHOD && it->name && if (it->item_kind == ITEM_METHOD && it->name && strcmp(it->name, name) == 0)
strcmp(it->name, name) == 0)
return it->method.func_idx; return it->method.func_idx;
} }
} }
@@ -211,54 +209,6 @@ int spl_add_global_data(spl_comp_t *ctx, void *data, usize size) {
return spl_prog_add_data(&ctx->prog, data, size); return spl_prog_add_data(&ctx->prog, data, size);
} }
/* ---- Defer ---- */
void spl_emit_defer(spl_comp_t *ctx) {
if (ctx->defer_count >= DEFER_MAX)
return;
spl_val_t jmp_skip = emit_jmp_here(&ctx->emit);
spl_defer_entry_t *e = &ctx->defer_stack[ctx->defer_count];
e->body_start = jmp_skip + 1;
e->jmp_exit = 0;
e->depth = ctx->scope_depth;
e->count_at_decl = ctx->defer_count;
ctx->defer_count++;
}
void spl_emit_defer_epilogue(spl_comp_t *ctx, int depth) {
for (int i = 0; i < ctx->defer_count; i++) {
if (ctx->defer_stack[i].depth != depth)
continue;
spl_defer_entry_t *e = &ctx->defer_stack[i];
spl_val_t skip_addr = e->body_start - 1;
spl_val_t skip_target = e->jmp_exit + 1;
emit_patch(&ctx->emit, skip_addr, skip_target - skip_addr - 1);
}
for (int i = ctx->defer_count - 1; i >= 0; i--) {
if (ctx->defer_stack[i].depth != depth)
continue;
spl_defer_entry_t *e = &ctx->defer_stack[i];
spl_val_t here = vec_size(ctx->prog.insns);
spl_val_t jmp_offset = (spl_val_t)((isize)e->body_start - (isize)here - 1);
emit_jmp(&ctx->emit, jmp_offset);
if (e->jmp_exit > 0)
emit_patch(&ctx->emit, e->jmp_exit, here + 1 - e->jmp_exit - 1);
}
int new_count = 0;
for (int i = 0; i < ctx->defer_count; i++) {
if (ctx->defer_stack[i].depth != depth)
ctx->defer_stack[new_count++] = ctx->defer_stack[i];
}
ctx->defer_count = new_count;
}
/* ---- Register runtime natives ---- */ /* ---- Register runtime natives ---- */
void spl_comp_register(spl_prog_t *prog) { (void)prog; } void spl_comp_register(spl_prog_t *prog) { (void)prog; }

View File

@@ -10,8 +10,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "spl_type.h"
#include "spl_emit.h" #include "spl_emit.h"
#include "spl_type.h"
/* Forward declarations */ /* Forward declarations */
typedef struct spl_comp spl_comp_t; typedef struct spl_comp spl_comp_t;
@@ -162,8 +162,7 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec);
spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, int type_idx); spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, int type_idx);
/* Match arm pattern comparison */ /* Match arm pattern comparison */
int spl_emit_match_enum_cmp(spl_comp_t *ctx, int enum_type_idx, int val_offset, int spl_emit_match_enum_cmp(spl_comp_t *ctx, int enum_type_idx, int val_offset, int by_value);
int by_value);
void spl_emit_match_value_cmp(spl_comp_t *ctx, int val_offset); void spl_emit_match_value_cmp(spl_comp_t *ctx, int val_offset);
/* ============================================================ /* ============================================================
@@ -178,9 +177,6 @@ spl_expr_result_t spl_parse_block_expr(spl_comp_t *ctx);
* Remaining helpers in spl_comp.c * Remaining helpers in spl_comp.c
* ============================================================ */ * ============================================================ */
void spl_emit_ret(spl_comp_t *ctx, int ret_type_idx);
void spl_emit_store_init(spl_comp_t *ctx, int var_offset, int var_type_idx);
/* Variable management */ /* Variable management */
int spl_declare_var(spl_comp_t *ctx, const char *name, int type_idx, int is_const); int spl_declare_var(spl_comp_t *ctx, const char *name, int type_idx, int is_const);
spl_var_info_t *spl_lookup_var(spl_comp_t *ctx, const char *name); spl_var_info_t *spl_lookup_var(spl_comp_t *ctx, const char *name);
@@ -200,15 +196,7 @@ int spl_add_global_data(spl_comp_t *ctx, void *data, usize size);
void spl_push_scope(spl_comp_t *ctx); void spl_push_scope(spl_comp_t *ctx);
void spl_pop_scope(spl_comp_t *ctx); void spl_pop_scope(spl_comp_t *ctx);
/* Defer */
void spl_emit_defer(spl_comp_t *ctx);
void spl_emit_defer_epilogue(spl_comp_t *ctx, int depth);
/* Register runtime natives (stub) */ /* Register runtime natives (stub) */
void spl_comp_register(spl_prog_t *prog); void spl_comp_register(spl_prog_t *prog);
/* Shared token helpers (defined in spl_parser.c) */
spl_tok_t *peek(spl_comp_t *ctx);
spl_tok_t *advance(spl_comp_t *ctx);
#endif /* __SPL_COMP_H__ */ #endif /* __SPL_COMP_H__ */

View File

@@ -1,6 +1,7 @@
/* spl_emit.c — IR emission: frame allocator + Layer 1/2 ops */ /* spl_emit.c — IR emission: frame allocator + Layer 1/2 ops */
#include "spl_emit.h" #include "spl_emit.h"
#include "spl_comp.h"
#include "spl_type.h" #include "spl_type.h"
#include <string.h> #include <string.h>
@@ -11,15 +12,13 @@
void spl_emit_init(spl_emit_t *e, spl_prog_t *prog) { void spl_emit_init(spl_emit_t *e, spl_prog_t *prog) {
memset(e, 0, sizeof(*e)); memset(e, 0, sizeof(*e));
e->prog = prog; e->prog = prog;
vec_init(e->call_fixups); vec_init(e->fixups);
vec_init(e->call_fixup_funcs);
} }
void spl_emit_drop(spl_emit_t *e) { void spl_emit_drop(spl_emit_t *e) {
if (!e) if (!e)
return; return;
vec_free(e->call_fixups); vec_free(e->fixups);
vec_free(e->call_fixup_funcs);
} }
/* ============================================================ /* ============================================================
@@ -30,8 +29,7 @@ int fa_alloc_type(spl_frame_alloc_t *fa, spl_type_ctx_t *tctx, int type_idx) {
return fa_alloc(fa, spl_type_size(tctx, type_idx)); return fa_alloc(fa, spl_type_size(tctx, type_idx));
} }
static spl_val_t emit_raw(spl_emit_t *e, uint16_t opcode, uint16_t type, spl_val_t emit_raw(spl_emit_t *e, uint16_t opcode, uint16_t type, spl_val_t imm) {
spl_val_t imm) {
return spl_prog_emit(e->prog, opcode, type, imm); return spl_prog_emit(e->prog, opcode, type, imm);
} }
@@ -46,19 +44,11 @@ void emit_rot(spl_emit_t *e) { emit_raw(e, SPL_ROT, SPL_VOID, 0); }
void emit_pick(spl_emit_t *e, int n) { emit_raw(e, SPL_PICK, SPL_VOID, n); } void emit_pick(spl_emit_t *e, int n) { emit_raw(e, SPL_PICK, SPL_VOID, n); }
void emit_push_i32(spl_emit_t *e, int v) { emit_raw(e, SPL_PUSH, SPL_I32, (spl_val_t)v); } void emit_push_i32(spl_emit_t *e, int v) { emit_raw(e, SPL_PUSH, SPL_I32, (spl_val_t)v); }
void emit_push_usize(spl_emit_t *e, usize v) { void emit_push_usize(spl_emit_t *e, usize v) { emit_raw(e, SPL_PUSH, SPL_USIZE, (spl_val_t)v); }
emit_raw(e, SPL_PUSH, SPL_USIZE, (spl_val_t)v); void emit_push_u64(spl_emit_t *e, uint64_t v) { emit_raw(e, SPL_PUSH, SPL_U64, (spl_val_t)v); }
} void emit_push_f64(spl_emit_t *e, uint64_t v) { emit_raw(e, SPL_PUSH, SPL_F64, (spl_val_t)v); }
void emit_push_u64(spl_emit_t *e, uint64_t v) {
emit_raw(e, SPL_PUSH, SPL_U64, (spl_val_t)v);
}
void emit_push_f64(spl_emit_t *e, uint64_t v) {
emit_raw(e, SPL_PUSH, SPL_F64, (spl_val_t)v);
}
void emit_push_ptr(spl_emit_t *e, spl_val_t v) { emit_raw(e, SPL_PUSH, SPL_PTR, v); } void emit_push_ptr(spl_emit_t *e, spl_val_t v) { emit_raw(e, SPL_PUSH, SPL_PTR, v); }
void emit_push_type(spl_emit_t *e, uint16_t bt, spl_val_t v) { void emit_push_type(spl_emit_t *e, uint16_t bt, spl_val_t v) { emit_raw(e, SPL_PUSH, bt, v); }
emit_raw(e, SPL_PUSH, bt, v);
}
void emit_load_ptr(spl_emit_t *e) { emit_raw(e, SPL_LOAD, SPL_PTR, 0); } void emit_load_ptr(spl_emit_t *e) { emit_raw(e, SPL_LOAD, SPL_PTR, 0); }
void emit_load_usize(spl_emit_t *e) { emit_raw(e, SPL_LOAD, SPL_USIZE, 0); } void emit_load_usize(spl_emit_t *e) { emit_raw(e, SPL_LOAD, SPL_USIZE, 0); }
@@ -95,9 +85,7 @@ void emit_laddr(spl_emit_t *e, int offset) { emit_raw(e, SPL_LADDR, SPL_PTR, off
void emit_gaddr(spl_emit_t *e, int idx) { emit_raw(e, SPL_GADDR, SPL_PTR, idx); } void emit_gaddr(spl_emit_t *e, int idx) { emit_raw(e, SPL_GADDR, SPL_PTR, idx); }
void emit_call(spl_emit_t *e, int nargs) { emit_raw(e, SPL_CALL, SPL_VOID, nargs); } void emit_call(spl_emit_t *e, int nargs) { emit_raw(e, SPL_CALL, SPL_VOID, nargs); }
void emit_ncall(spl_emit_t *e, int nargs) { void emit_ncall(spl_emit_t *e, int nargs) { emit_raw(e, SPL_NCALL, SPL_VOID, nargs); }
emit_raw(e, SPL_NCALL, SPL_VOID, nargs);
}
void emit_alloc(spl_emit_t *e, int slots) { emit_raw(e, SPL_ALLOC, SPL_VOID, slots); } void emit_alloc(spl_emit_t *e, int slots) { emit_raw(e, SPL_ALLOC, SPL_VOID, slots); }
void emit_binop(spl_emit_t *e, uint16_t op, uint16_t bt) { emit_raw(e, op, bt, 0); } void emit_binop(spl_emit_t *e, uint16_t op, uint16_t bt) { emit_raw(e, op, bt, 0); }
@@ -143,8 +131,8 @@ void emit_copy_addr_to_addr(spl_emit_t *e, usize nslots, int depth) {
emit_drop(e); emit_drop(e);
} }
void emit_load_to_var(spl_emit_t *e, spl_type_ctx_t *tctx, int ptr_slot_offset, void emit_load_to_var(spl_emit_t *e, spl_type_ctx_t *tctx, int ptr_slot_offset, usize byte_offset,
usize byte_offset, int data_type_idx, int var_offset) { int data_type_idx, int var_offset) {
emit_laddr(e, ptr_slot_offset); emit_laddr(e, ptr_slot_offset);
emit_load_ptr(e); emit_load_ptr(e);
emit_ptr_add(e, byte_offset); emit_ptr_add(e, byte_offset);
@@ -176,8 +164,8 @@ void emit_ptr_add(spl_emit_t *e, usize byte_off) {
spl_val_t emit_call_with_fixup(spl_emit_t *e, int nargs, int func_idx) { spl_val_t emit_call_with_fixup(spl_emit_t *e, int nargs, int func_idx) {
spl_val_t fixup_addr = emit_raw(e, SPL_PUSH, SPL_PTR, 0); spl_val_t fixup_addr = emit_raw(e, SPL_PUSH, SPL_PTR, 0);
emit_call(e, nargs); emit_call(e, nargs);
vec_push(e->call_fixups, fixup_addr); spl_fixup_entry_t fe = {fixup_addr, func_idx};
vec_push(e->call_fixup_funcs, func_idx); vec_push(e->fixups, fe);
return fixup_addr; return fixup_addr;
} }
@@ -192,12 +180,100 @@ void emit_return(spl_emit_t *e, spl_type_ctx_t *tctx, int ret_type_idx) {
} }
void emit_patch_call_fixups(spl_emit_t *e, spl_prog_t *prog) { void emit_patch_call_fixups(spl_emit_t *e, spl_prog_t *prog) {
for (usize i = 0; i < vec_size(e->call_fixups); i++) { for (usize i = 0; i < vec_size(e->fixups); i++) {
spl_val_t insn_idx = vec_at(e->call_fixups, i); spl_fixup_entry_t *fe = &vec_at(e->fixups, i);
int pfi = vec_at(e->call_fixup_funcs, i); if (fe->func_idx >= 0 && fe->func_idx < (int)vec_size(prog->funcs)) {
if (pfi >= 0 && pfi < (int)vec_size(prog->funcs)) { spl_val_t addr = vec_at(prog->funcs, fe->func_idx).address;
spl_val_t addr = vec_at(prog->funcs, pfi).address; vec_at(prog->insns, fe->insn_idx).imm = addr;
vec_at(prog->insns, insn_idx).imm = addr;
} }
} }
} }
void spl_emit_ret(spl_comp_t *ctx, int ret_type_idx) {
if (spl_type_needs_multi_slot(&ctx->tctx, ret_type_idx)) {
emit_laddr(&ctx->emit, (int)sizeof(spl_val_t));
emit_swap(&ctx->emit);
emit_copy_addr_to_addr(&ctx->emit, spl_type_slot_count(&ctx->tctx, ret_type_idx), 0);
}
emit_return(&ctx->emit, &ctx->tctx, ret_type_idx);
}
void spl_emit_store_init(spl_comp_t *ctx, int var_offset, int var_type_idx) {
if (var_type_idx >= 0 && (spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_STRUCT ||
spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_ENUM)) {
usize sz = spl_type_size(&ctx->tctx, var_type_idx);
if (sz <= sizeof(spl_val_t)) {
emit_store_to_laddr(&ctx->emit, var_offset,
spl_type_emit_type(&ctx->tctx, var_type_idx));
} else {
usize nslots = (sz + sizeof(spl_val_t) - 1) / sizeof(spl_val_t);
emit_frame_copy(&ctx->emit, var_offset, nslots);
}
} else if (var_type_idx >= 0 && spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_ARRAY) {
int elem_idx = spl_type_elem_type(&ctx->tctx, var_type_idx);
spl_type_t bt = spl_type_emit_type(&ctx->tctx, elem_idx);
usize stride = spl_type_elem_stride(&ctx->tctx, elem_idx);
int arr_len = (int)spl_type_array_len(&ctx->tctx, var_type_idx);
for (int i = arr_len - 1; i >= 0; i--) {
emit_laddr(&ctx->emit, var_offset + (int)(i * stride));
emit_swap(&ctx->emit);
if (elem_idx >= 0 && !spl_type_is_scalar(&ctx->tctx, elem_idx)) {
emit_copy_addr_to_addr(&ctx->emit, spl_type_slot_count(&ctx->tctx, elem_idx), 0);
} else {
emit_store_type(&ctx->emit, bt);
}
}
} else if (var_type_idx >= 0 && spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_SLICE) {
emit_store_to_laddr(&ctx->emit, var_offset + (int)sizeof(spl_val_t), SPL_USIZE);
emit_store_to_laddr(&ctx->emit, var_offset, SPL_PTR);
} else {
spl_type_t bt = spl_type_emit_type(&ctx->tctx, var_type_idx);
emit_store_to_laddr(&ctx->emit, var_offset, bt);
}
}
void spl_emit_defer(spl_comp_t *ctx) {
if (ctx->defer_count >= DEFER_MAX)
return;
spl_val_t jmp_skip = emit_jmp_here(&ctx->emit);
spl_defer_entry_t *e = &ctx->defer_stack[ctx->defer_count];
e->body_start = jmp_skip + 1;
e->jmp_exit = 0;
e->depth = ctx->scope_depth;
e->count_at_decl = ctx->defer_count;
ctx->defer_count++;
}
void spl_emit_defer_epilogue(spl_comp_t *ctx, int depth) {
for (int i = 0; i < ctx->defer_count; i++) {
if (ctx->defer_stack[i].depth != depth)
continue;
spl_defer_entry_t *e = &ctx->defer_stack[i];
spl_val_t skip_addr = e->body_start - 1;
spl_val_t skip_target = e->jmp_exit + 1;
emit_patch(&ctx->emit, skip_addr, skip_target - skip_addr - 1);
}
for (int i = ctx->defer_count - 1; i >= 0; i--) {
if (ctx->defer_stack[i].depth != depth)
continue;
spl_defer_entry_t *e = &ctx->defer_stack[i];
spl_val_t here = vec_size(ctx->prog.insns);
spl_val_t jmp_offset = (spl_val_t)((isize)e->body_start - (isize)here - 1);
emit_jmp(&ctx->emit, jmp_offset);
if (e->jmp_exit > 0)
emit_patch(&ctx->emit, e->jmp_exit, here + 1 - e->jmp_exit - 1);
}
int new_count = 0;
for (int i = 0; i < ctx->defer_count; i++) {
if (ctx->defer_stack[i].depth != depth)
ctx->defer_stack[new_count++] = ctx->defer_stack[i];
}
ctx->defer_count = new_count;
}

View File

@@ -48,11 +48,15 @@ static inline void fa_free(spl_frame_alloc_t *fa, int mark) { fa->current_bytes
* Emit context * Emit context
* ============================================================ */ * ============================================================ */
typedef struct {
spl_val_t insn_idx;
int func_idx;
} spl_fixup_entry_t;
typedef struct { typedef struct {
spl_prog_t *prog; spl_prog_t *prog;
spl_frame_alloc_t frame; spl_frame_alloc_t frame;
VEC(spl_val_t) call_fixups; VEC(spl_fixup_entry_t) fixups;
VEC(int) call_fixup_funcs;
} spl_emit_t; } spl_emit_t;
void spl_emit_init(spl_emit_t *e, spl_prog_t *prog); void spl_emit_init(spl_emit_t *e, spl_prog_t *prog);
@@ -119,14 +123,17 @@ void emit_binop(spl_emit_t *e, uint16_t op, uint16_t bt);
void emit_dbg_void(spl_emit_t *e); void emit_dbg_void(spl_emit_t *e);
void emit_dbg_usize(spl_emit_t *e); void emit_dbg_usize(spl_emit_t *e);
/* Low-level emit (raw opcode + type + imm) */
spl_val_t emit_raw(spl_emit_t *e, uint16_t opcode, uint16_t type, spl_val_t imm);
/* ============================================================ /* ============================================================
* Layer 2 — semantic-level helpers * Layer 2 — semantic-level helpers
* ============================================================ */ * ============================================================ */
void emit_frame_copy(spl_emit_t *e, int dest_offset, usize nslots); void emit_frame_copy(spl_emit_t *e, int dest_offset, usize nslots);
void emit_copy_addr_to_addr(spl_emit_t *e, usize nslots, int depth); void emit_copy_addr_to_addr(spl_emit_t *e, usize nslots, int depth);
void emit_load_to_var(spl_emit_t *e, spl_type_ctx_t *tctx, int ptr_slot_offset, void emit_load_to_var(spl_emit_t *e, spl_type_ctx_t *tctx, int ptr_slot_offset, usize byte_offset,
usize byte_offset, int data_type_idx, int var_offset); int data_type_idx, int var_offset);
void emit_store_to_laddr(spl_emit_t *e, int offset, uint16_t type); void emit_store_to_laddr(spl_emit_t *e, int offset, uint16_t type);
void emit_ptr_add(spl_emit_t *e, usize byte_off); void emit_ptr_add(spl_emit_t *e, usize byte_off);
spl_val_t emit_call_with_fixup(spl_emit_t *e, int nargs, int func_idx); spl_val_t emit_call_with_fixup(spl_emit_t *e, int nargs, int func_idx);
@@ -135,4 +142,14 @@ void emit_return(spl_emit_t *e, spl_type_ctx_t *tctx, int ret_type_idx);
/* Patch all fixups */ /* Patch all fixups */
void emit_patch_call_fixups(spl_emit_t *e, spl_prog_t *prog); void emit_patch_call_fixups(spl_emit_t *e, spl_prog_t *prog);
/* ============================================================
* Layer 3 — compiler-level helpers (need spl_comp_t for tctx)
* ============================================================ */
struct spl_comp;
void spl_emit_ret(struct spl_comp *ctx, int ret_type_idx);
void spl_emit_store_init(struct spl_comp *ctx, int var_offset, int var_type_idx);
void spl_emit_defer(struct spl_comp *ctx);
void spl_emit_defer_epilogue(struct spl_comp *ctx, int depth);
#endif /* __SPL_EMIT_H__ */ #endif /* __SPL_EMIT_H__ */

View File

@@ -52,8 +52,7 @@ static int tok_prec(spl_tok_type_t t) {
} }
static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, spl_tok_type_t op); static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, spl_tok_type_t op);
static void emit_load_or_addr_type(spl_comp_t *ctx, spl_expr_result_t *result, static void emit_load_or_addr_type(spl_comp_t *ctx, spl_expr_result_t *result, int type_idx);
int type_idx);
static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t left); static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t left);
static void emit_slice_create(spl_comp_t *ctx, usize stride) { static void emit_slice_create(spl_comp_t *ctx, usize stride) {
@@ -90,7 +89,8 @@ static int spl_resolve_type_member(spl_comp_t *ctx, int type_idx, const char *fi
spl_type_item_vec_t *items = spl_type_items(&ctx->tctx, type_idx); spl_type_item_vec_t *items = spl_type_items(&ctx->tctx, type_idx);
vec_for(*items, i) { vec_for(*items, i) {
spl_type_item_t *it = &vec_at(*items, i); spl_type_item_t *it = &vec_at(*items, i);
if (it->item_kind != ITEM_VARIANT) continue; if (it->item_kind != ITEM_VARIANT)
continue;
if (strcmp(it->name, field) == 0) { if (strcmp(it->name, field) == 0) {
emit_push_i32(&ctx->emit, it->enum_field.value); emit_push_i32(&ctx->emit, it->enum_field.value);
*result = (spl_expr_result_t){type_idx, 0}; *result = (spl_expr_result_t){type_idx, 0};
@@ -365,7 +365,8 @@ static void parse_one_field_init(spl_comp_t *ctx, spl_type_item_vec_t *items, in
vec_for(*items, fi) { vec_for(*items, fi) {
spl_type_item_t *it = &vec_at(*items, fi); spl_type_item_t *it = &vec_at(*items, fi);
if (it->item_kind != ITEM_FIELD) continue; if (it->item_kind != ITEM_FIELD)
continue;
if (strcmp(it->name, fname) == 0) { if (strcmp(it->name, fname) == 0) {
emit_laddr(&ctx->emit, base_offset); emit_laddr(&ctx->emit, base_offset);
usize byte_off = extra_offset + it->aggregate_field.offset; usize byte_off = extra_offset + it->aggregate_field.offset;
@@ -401,9 +402,13 @@ static void parse_one_field_init(spl_comp_t *ctx, spl_type_item_vec_t *items, in
} }
emit_dup(&ctx->emit); emit_dup(&ctx->emit);
emit_ptr_add(&ctx->emit, i * stride); emit_ptr_add(&ctx->emit, i * stride);
int saved_aom = ctx->addr_of_mode;
ctx->addr_of_mode = 0;
spl_parse_expr(ctx, PREC_MIN); spl_parse_expr(ctx, PREC_MIN);
ctx->addr_of_mode = saved_aom;
if (elem_type_idx >= 0 && !spl_type_is_scalar(&ctx->tctx, elem_type_idx)) { if (elem_type_idx >= 0 && !spl_type_is_scalar(&ctx->tctx, elem_type_idx)) {
emit_copy_addr_to_addr(&ctx->emit, spl_type_slot_count(&ctx->tctx, elem_type_idx), 1); emit_copy_addr_to_addr(&ctx->emit,
spl_type_slot_count(&ctx->tctx, elem_type_idx), 1);
} else { } else {
emit_store_type(&ctx->emit, st); emit_store_type(&ctx->emit, st);
} }
@@ -425,8 +430,11 @@ static void parse_one_field_init(spl_comp_t *ctx, spl_type_item_vec_t *items, in
fv = spl_parse_expr(ctx, PREC_MIN); fv = spl_parse_expr(ctx, PREC_MIN);
} }
(void)fv; (void)fv;
usize nslots = (spl_type_size(&ctx->tctx, ft_idx) + sizeof(spl_val_t) - 1) / sizeof(spl_val_t); usize nslots =
emit_frame_copy(&ctx->emit, base_offset + (int)extra_offset + (int)it->aggregate_field.offset, nslots); (spl_type_size(&ctx->tctx, ft_idx) + sizeof(spl_val_t) - 1) / sizeof(spl_val_t);
emit_frame_copy(&ctx->emit,
base_offset + (int)extra_offset + (int)it->aggregate_field.offset,
nslots);
emit_drop(&ctx->emit); emit_drop(&ctx->emit);
} else { } else {
spl_expr_result_t fv = spl_parse_expr(ctx, PREC_MIN); spl_expr_result_t fv = spl_parse_expr(ctx, PREC_MIN);
@@ -512,7 +520,8 @@ spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, int type_idx) {
spl_type_item_vec_t *items = spl_type_items(&ctx->tctx, type_idx); spl_type_item_vec_t *items = spl_type_items(&ctx->tctx, type_idx);
vec_for(*items, vi) { vec_for(*items, vi) {
spl_type_item_t *v = &vec_at(*items, vi); spl_type_item_t *v = &vec_at(*items, vi);
if (v->item_kind != ITEM_VARIANT) continue; if (v->item_kind != ITEM_VARIANT)
continue;
if (strcmp(v->name, vname) == 0) { if (strcmp(v->name, vname) == 0) {
found = 1; found = 1;
emit_laddr(&ctx->emit, base_offset); emit_laddr(&ctx->emit, base_offset);
@@ -620,15 +629,16 @@ static void spl_check_arg_type(spl_comp_t *ctx, const char *fname, int arg_type_
} }
} }
static int parse_call_args_checked(spl_comp_t *ctx, const char *fname, static int parse_call_args_checked(spl_comp_t *ctx, const char *fname, int *param_type_indices,
int *param_type_indices, int nparams) { int nparams) {
int nargs = 0; int nargs = 0;
int nlogical = 0; int nlogical = 0;
if (peek(ctx)->type != TOK_R_PAREN) { if (peek(ctx)->type != TOK_R_PAREN) {
for (;;) { for (;;) {
spl_expr_result_t arg = spl_parse_expr(ctx, PREC_MIN); spl_expr_result_t arg = spl_parse_expr(ctx, PREC_MIN);
if (param_type_indices && nlogical < nparams && param_type_indices[nlogical] >= 0) if (param_type_indices && nlogical < nparams && param_type_indices[nlogical] >= 0)
spl_check_arg_type(ctx, fname, arg.type_idx, param_type_indices[nlogical], nlogical); spl_check_arg_type(ctx, fname, arg.type_idx, param_type_indices[nlogical],
nlogical);
int arg_slots = 1; int arg_slots = 1;
if (param_type_indices && nlogical < nparams && param_type_indices[nlogical] >= 0 && if (param_type_indices && nlogical < nparams && param_type_indices[nlogical] >= 0 &&
@@ -636,7 +646,8 @@ static int parse_call_args_checked(spl_comp_t *ctx, const char *fname,
spl_type_kind(&ctx->tctx, param_type_indices[nlogical]) != TYPE_PTR && spl_type_kind(&ctx->tctx, param_type_indices[nlogical]) != TYPE_PTR &&
spl_type_needs_multi_slot(&ctx->tctx, param_type_indices[nlogical])) { spl_type_needs_multi_slot(&ctx->tctx, param_type_indices[nlogical])) {
usize nslots = (spl_type_size(&ctx->tctx, param_type_indices[nlogical]) + usize nslots = (spl_type_size(&ctx->tctx, param_type_indices[nlogical]) +
sizeof(spl_val_t) - 1) / sizeof(spl_val_t); sizeof(spl_val_t) - 1) /
sizeof(spl_val_t);
for (usize i = 0; i < nslots; i++) { for (usize i = 0; i < nslots; i++) {
emit_dup(&ctx->emit); emit_dup(&ctx->emit);
emit_ptr_add(&ctx->emit, i * sizeof(spl_val_t)); emit_ptr_add(&ctx->emit, i * sizeof(spl_val_t));
@@ -738,8 +749,7 @@ static spl_expr_result_t parse_group(spl_comp_t *ctx) {
return r; return r;
} }
static void emit_load_or_addr_type(spl_comp_t *ctx, spl_expr_result_t *result, static void emit_load_or_addr_type(spl_comp_t *ctx, spl_expr_result_t *result, int type_idx) {
int type_idx) {
if (spl_type_is_scalar(&ctx->tctx, type_idx)) { if (spl_type_is_scalar(&ctx->tctx, type_idx)) {
if (!ctx->addr_of_mode) { if (!ctx->addr_of_mode) {
emit_load_type(&ctx->emit, spl_type_emit_type(&ctx->tctx, type_idx)); emit_load_type(&ctx->emit, spl_type_emit_type(&ctx->tctx, type_idx));
@@ -774,10 +784,10 @@ static spl_expr_result_t parse_prefix_op(spl_comp_t *ctx) {
if (!right.is_lvalue) { if (!right.is_lvalue) {
spl_comp_error(ctx, "cannot take address of rvalue"); spl_comp_error(ctx, "cannot take address of rvalue");
} }
right.type_idx = spl_type_ptr(&ctx->tctx, right.type_idx);
break; break;
case TOK_MUL: case TOK_MUL:
if (right.type_idx >= 0 && if (right.type_idx >= 0 && spl_type_kind(&ctx->tctx, right.type_idx) == TYPE_PTR &&
spl_type_kind(&ctx->tctx, right.type_idx) == TYPE_PTR &&
spl_type_elem_type(&ctx->tctx, right.type_idx) >= 0) { spl_type_elem_type(&ctx->tctx, right.type_idx) >= 0) {
if (right.is_lvalue) { if (right.is_lvalue) {
emit_load_ptr(&ctx->emit); emit_load_ptr(&ctx->emit);
@@ -865,6 +875,18 @@ static spl_expr_result_t parse_primary_expr(spl_comp_t *ctx) {
emit_dbg_void(&ctx->emit); emit_dbg_void(&ctx->emit);
} }
return (spl_expr_result_t){spl_type_basic(&ctx->tctx, SPL_VOID), 0}; return (spl_expr_result_t){spl_type_basic(&ctx->tctx, SPL_VOID), 0};
} else if (strcmp(bname, "sizeof") == 0) {
expect(ctx, TOK_L_PAREN);
int ti = spl_type_parse(&ctx->tctx, ctx);
expect(ctx, TOK_R_PAREN);
if (ti < 0) {
spl_comp_error(ctx, "@sizeof: invalid type");
spl_expr_result_t r = {-1, 0};
return r;
}
usize sz = spl_type_size(&ctx->tctx, ti);
emit_push_usize(&ctx->emit, sz);
return (spl_expr_result_t){spl_type_basic(&ctx->tctx, SPL_USIZE), 0};
} else { } else {
spl_comp_error(ctx, "unknown builtin '@%s'", bname); spl_comp_error(ctx, "unknown builtin '@%s'", bname);
spl_expr_result_t r = {-1, 0}; spl_expr_result_t r = {-1, 0};
@@ -907,9 +929,8 @@ static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t l
int is_ptr_self = 0; int is_ptr_self = 0;
if (spl_type_kind(&ctx->tctx, methods_type_idx) == TYPE_PTR) { if (spl_type_kind(&ctx->tctx, methods_type_idx) == TYPE_PTR) {
int elem_idx = spl_type_elem_type(&ctx->tctx, methods_type_idx); int elem_idx = spl_type_elem_type(&ctx->tctx, methods_type_idx);
if (elem_idx >= 0 && if (elem_idx >= 0 && (spl_type_kind(&ctx->tctx, elem_idx) == TYPE_STRUCT ||
(spl_type_kind(&ctx->tctx, elem_idx) == TYPE_STRUCT || spl_type_kind(&ctx->tctx, elem_idx) == TYPE_ENUM)) {
spl_type_kind(&ctx->tctx, elem_idx) == TYPE_ENUM)) {
is_ptr_self = 1; is_ptr_self = 1;
methods_type_idx = elem_idx; methods_type_idx = elem_idx;
} }
@@ -919,7 +940,8 @@ static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t l
spl_type_item_vec_t *m_items = spl_type_items(&ctx->tctx, methods_type_idx); spl_type_item_vec_t *m_items = spl_type_items(&ctx->tctx, methods_type_idx);
vec_for(*m_items, mi) { vec_for(*m_items, mi) {
spl_type_item_t *mit = &vec_at(*m_items, mi); spl_type_item_t *mit = &vec_at(*m_items, mi);
if (mit->item_kind != ITEM_METHOD) continue; if (mit->item_kind != ITEM_METHOD)
continue;
if (strcmp(mit->name, fname) == 0) { if (strcmp(mit->name, fname) == 0) {
spl_func_info_t *func = &vec_at(ctx->funcs, mit->method.func_idx); spl_func_info_t *func = &vec_at(ctx->funcs, mit->method.func_idx);
@@ -929,9 +951,11 @@ static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t l
int nargs = 0; int nargs = 0;
int is_instance = 0; int is_instance = 0;
if (func->nparams > 0 && func->param_type_indices[0] >= 0 && if (func->nparams > 0 && func->param_type_indices &&
func->param_type_indices[0] >= 0 &&
spl_type_kind(&ctx->tctx, func->param_type_indices[0]) == TYPE_PTR && spl_type_kind(&ctx->tctx, func->param_type_indices[0]) == TYPE_PTR &&
spl_type_elem_type(&ctx->tctx, func->param_type_indices[0]) == methods_type_idx) { spl_type_elem_type(&ctx->tctx, func->param_type_indices[0]) ==
methods_type_idx) {
is_instance = 1; is_instance = 1;
} }
@@ -947,10 +971,6 @@ static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t l
{ {
int *cp = func->param_type_indices; int *cp = func->param_type_indices;
int cn = func->nparams; int cn = func->nparams;
if (is_instance && cn > 0) {
cp++;
cn--;
}
nargs += parse_call_args_checked(ctx, func->name, cp, cn); nargs += parse_call_args_checked(ctx, func->name, cp, cn);
} }
expect(ctx, TOK_R_PAREN); expect(ctx, TOK_R_PAREN);
@@ -978,7 +998,8 @@ static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t l
spl_type_item_vec_t *f_items = spl_type_items(&ctx->tctx, left.type_idx); spl_type_item_vec_t *f_items = spl_type_items(&ctx->tctx, left.type_idx);
vec_for(*f_items, fi) { vec_for(*f_items, fi) {
spl_type_item_t *fit = &vec_at(*f_items, fi); spl_type_item_t *fit = &vec_at(*f_items, fi);
if (fit->item_kind != ITEM_FIELD) continue; if (fit->item_kind != ITEM_FIELD)
continue;
if (strcmp(fit->name, fname) == 0) { if (strcmp(fit->name, fname) == 0) {
emit_ptr_add(&ctx->emit, fit->aggregate_field.offset); emit_ptr_add(&ctx->emit, fit->aggregate_field.offset);
emit_load_or_addr_type(ctx, &left, fit->aggregate_field.type_idx); emit_load_or_addr_type(ctx, &left, fit->aggregate_field.type_idx);
@@ -997,7 +1018,8 @@ static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t l
spl_type_item_vec_t *st_items = spl_type_items(&ctx->tctx, elem_idx); spl_type_item_vec_t *st_items = spl_type_items(&ctx->tctx, elem_idx);
vec_for(*st_items, si) { vec_for(*st_items, si) {
spl_type_item_t *sit = &vec_at(*st_items, si); spl_type_item_t *sit = &vec_at(*st_items, si);
if (sit->item_kind != ITEM_FIELD) continue; if (sit->item_kind != ITEM_FIELD)
continue;
if (strcmp(sit->name, fname) == 0) { if (strcmp(sit->name, fname) == 0) {
emit_ptr_add(&ctx->emit, sit->aggregate_field.offset); emit_ptr_add(&ctx->emit, sit->aggregate_field.offset);
emit_load_or_addr_type(ctx, &left, sit->aggregate_field.type_idx); emit_load_or_addr_type(ctx, &left, sit->aggregate_field.type_idx);
@@ -1024,13 +1046,15 @@ static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t l
int sl_elem_idx = spl_type_elem_type(&ctx->tctx, left.type_idx); int sl_elem_idx = spl_type_elem_type(&ctx->tctx, left.type_idx);
if (ctx->addr_of_mode) { if (ctx->addr_of_mode) {
left = (spl_expr_result_t){sl_elem_idx >= 0 left = (spl_expr_result_t){sl_elem_idx >= 0
? spl_type_ptr(&ctx->tctx, sl_elem_idx) ? spl_type_ptr(&ctx->tctx, sl_elem_idx)
: spl_type_basic(&ctx->tctx, SPL_PTR), 1}; : spl_type_basic(&ctx->tctx, SPL_PTR),
1};
} else { } else {
emit_load_ptr(&ctx->emit); emit_load_ptr(&ctx->emit);
left = (spl_expr_result_t){sl_elem_idx >= 0 left = (spl_expr_result_t){sl_elem_idx >= 0
? spl_type_ptr(&ctx->tctx, sl_elem_idx) ? spl_type_ptr(&ctx->tctx, sl_elem_idx)
: spl_type_basic(&ctx->tctx, SPL_PTR), 0}; : spl_type_basic(&ctx->tctx, SPL_PTR),
0};
} }
} }
continue; continue;
@@ -1059,22 +1083,30 @@ static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t l
continue; continue;
} }
int saved_aom = ctx->addr_of_mode;
ctx->addr_of_mode = 0;
spl_parse_expr(ctx, PREC_MIN); spl_parse_expr(ctx, PREC_MIN);
ctx->addr_of_mode = saved_aom;
if (peek(ctx)->type == TOK_RANGE) { if (peek(ctx)->type == TOK_RANGE) {
advance(ctx); advance(ctx);
spl_expr_result_t end_expr = {-1, 0}; spl_expr_result_t end_expr = {-1, 0};
int has_explicit_end = (peek(ctx)->type != TOK_R_BRACKET); int has_explicit_end = (peek(ctx)->type != TOK_R_BRACKET);
if (has_explicit_end) { if (has_explicit_end) {
int saved_aom = ctx->addr_of_mode;
ctx->addr_of_mode = 0;
end_expr = spl_parse_expr(ctx, PREC_MIN); end_expr = spl_parse_expr(ctx, PREC_MIN);
ctx->addr_of_mode = saved_aom;
} }
(void)end_expr; (void)end_expr;
expect(ctx, TOK_R_BRACKET); expect(ctx, TOK_R_BRACKET);
if (!has_explicit_end) { if (!has_explicit_end) {
if (left.type_idx >= 0 && spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_ARRAY) { if (left.type_idx >= 0 &&
spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_ARRAY) {
emit_push_u64(&ctx->emit, spl_type_array_len(&ctx->tctx, left.type_idx)); emit_push_u64(&ctx->emit, spl_type_array_len(&ctx->tctx, left.type_idx));
} else if (left.type_idx >= 0 && spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_SLICE) { } else if (left.type_idx >= 0 &&
spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_SLICE) {
emit_pick(&ctx->emit, 1); emit_pick(&ctx->emit, 1);
emit_push_u64(&ctx->emit, sizeof(spl_val_t)); emit_push_u64(&ctx->emit, sizeof(spl_val_t));
emit_add_u64(&ctx->emit); emit_add_u64(&ctx->emit);
@@ -1108,19 +1140,25 @@ static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t l
emit_slice_create(ctx, stride); emit_slice_create(ctx, stride);
} }
} }
left = (spl_expr_result_t){left.type_idx >= 0 left = (spl_expr_result_t){
left.type_idx >= 0
? spl_type_slice(&ctx->tctx, spl_type_elem_type(&ctx->tctx, left.type_idx)) ? spl_type_slice(&ctx->tctx, spl_type_elem_type(&ctx->tctx, left.type_idx))
: -1, 0}; : -1,
0};
continue; continue;
} }
expect(ctx, TOK_R_BRACKET); expect(ctx, TOK_R_BRACKET);
if (left.type_idx >= 0 && if (left.type_idx >= 0 && (spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_ARRAY ||
(spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_ARRAY || spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_PTR ||
spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_PTR || spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_SLICE)) {
spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_SLICE)) {
int idx_elem_idx = spl_type_elem_type(&ctx->tctx, left.type_idx); int idx_elem_idx = spl_type_elem_type(&ctx->tctx, left.type_idx);
/* void* -> treat as u8* */
if (idx_elem_idx >= 0 && spl_type_kind(&ctx->tctx, idx_elem_idx) == TYPE_BASIC &&
spl_type_basic_type(&ctx->tctx, idx_elem_idx) == SPL_VOID) {
idx_elem_idx = spl_type_basic(&ctx->tctx, SPL_U8);
}
if (spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_SLICE) { if (spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_SLICE) {
emit_slice_index(ctx, idx_elem_idx); emit_slice_index(ctx, idx_elem_idx);
@@ -1141,6 +1179,34 @@ static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t l
continue; continue;
} }
if (opt == KW_AS) {
usize saved = ctx->tok_idx;
int saved_err = ctx->has_error;
char saved_msg[COMP_ERROR_MAX];
memcpy(saved_msg, ctx->error_msg, COMP_ERROR_MAX);
advance(ctx); /* as */
skip_nl(ctx);
int target_type_idx = spl_type_parse(&ctx->tctx, ctx);
if (target_type_idx < 0) {
ctx->tok_idx = saved;
ctx->has_error = saved_err;
memcpy(ctx->error_msg, saved_msg, COMP_ERROR_MAX);
break;
}
usize src_sz = spl_type_size(&ctx->tctx, left.type_idx);
usize dst_sz = spl_type_size(&ctx->tctx, target_type_idx);
if (dst_sz > src_sz) {
int src_signed =
spl_type_is_integer(spl_type_basic_type(&ctx->tctx, left.type_idx));
uint16_t opc = src_signed ? SPL_SEXT : SPL_ZEXT;
emit_raw(&ctx->emit, opc, 0, dst_sz * 8);
} else if (dst_sz < src_sz) {
emit_raw(&ctx->emit, SPL_TRUNC, 0, dst_sz * 8);
}
left = (spl_expr_result_t){target_type_idx, 0};
continue;
}
break; break;
} }
return left; return left;
@@ -1175,13 +1241,19 @@ static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, sp
if (op == TOK_AND_AND) { if (op == TOK_AND_AND) {
spl_val_t bz_addr = emit_bz_here(&ctx->emit); spl_val_t bz_addr = emit_bz_here(&ctx->emit);
spl_parse_expr(ctx, next_prec); spl_parse_expr(ctx, next_prec);
spl_val_t jmp_addr = emit_jmp_here(&ctx->emit);
emit_patch_here(&ctx->emit, bz_addr); emit_patch_here(&ctx->emit, bz_addr);
emit_push_i32(&ctx->emit, 0);
emit_patch_here(&ctx->emit, jmp_addr);
return (spl_expr_result_t){spl_type_basic(&ctx->tctx, SPL_I32), 0}; return (spl_expr_result_t){spl_type_basic(&ctx->tctx, SPL_I32), 0};
} }
if (op == TOK_OR_OR) { if (op == TOK_OR_OR) {
spl_val_t bnz_addr = emit_bnz_here(&ctx->emit); spl_val_t bnz_addr = emit_bnz_here(&ctx->emit);
spl_parse_expr(ctx, next_prec); spl_parse_expr(ctx, next_prec);
spl_val_t jmp_addr = emit_jmp_here(&ctx->emit);
emit_patch_here(&ctx->emit, bnz_addr); emit_patch_here(&ctx->emit, bnz_addr);
emit_push_i32(&ctx->emit, 1);
emit_patch_here(&ctx->emit, jmp_addr);
return (spl_expr_result_t){spl_type_basic(&ctx->tctx, SPL_I32), 0}; return (spl_expr_result_t){spl_type_basic(&ctx->tctx, SPL_I32), 0};
} }
@@ -1198,9 +1270,9 @@ static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, sp
if (left.is_lvalue) { if (left.is_lvalue) {
spl_type_t bt = spl_type_emit_type(&ctx->tctx, left.type_idx); spl_type_t bt = spl_type_emit_type(&ctx->tctx, left.type_idx);
if (op == TOK_ASSIGN && left.type_idx >= 0 && if (op == TOK_ASSIGN && left.type_idx >= 0 &&
!spl_type_is_scalar(&ctx->tctx, left.type_idx) && !spl_type_is_scalar(&ctx->tctx, left.type_idx) && right.is_lvalue) {
right.is_lvalue) { emit_copy_addr_to_addr(&ctx->emit, spl_type_slot_count(&ctx->tctx, left.type_idx),
emit_copy_addr_to_addr(&ctx->emit, spl_type_slot_count(&ctx->tctx, left.type_idx), 0); 0);
} else if (op == TOK_ASSIGN) { } else if (op == TOK_ASSIGN) {
emit_store_type(&ctx->emit, bt); emit_store_type(&ctx->emit, bt);
} else { } else {
@@ -1233,8 +1305,7 @@ static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, sp
return (spl_expr_result_t){result_type_idx, 0}; return (spl_expr_result_t){result_type_idx, 0};
} }
int spl_emit_match_enum_cmp(spl_comp_t *ctx, int enum_type_idx, int spl_emit_match_enum_cmp(spl_comp_t *ctx, int enum_type_idx, int val_offset, int by_value) {
int val_offset, int by_value) {
char vname[256]; char vname[256];
if (peek(ctx)->type == TOK_DOT) { if (peek(ctx)->type == TOK_DOT) {
@@ -1259,27 +1330,27 @@ int spl_emit_match_enum_cmp(spl_comp_t *ctx, int enum_type_idx,
spl_tok_copy_name(vtok, vname, sizeof(vname)); spl_tok_copy_name(vtok, vname, sizeof(vname));
} }
lookup: lookup: {
{ spl_type_item_vec_t *e_items = spl_type_items(&ctx->tctx, enum_type_idx);
spl_type_item_vec_t *e_items = spl_type_items(&ctx->tctx, enum_type_idx); vec_for(*e_items, vi) {
vec_for(*e_items, vi) { spl_type_item_t *vit = &vec_at(*e_items, vi);
spl_type_item_t *vit = &vec_at(*e_items, vi); if (vit->item_kind != ITEM_VARIANT)
if (vit->item_kind != ITEM_VARIANT) continue; continue;
if (strcmp(vit->name, vname) == 0) { if (strcmp(vit->name, vname) == 0) {
emit_laddr(&ctx->emit, val_offset); emit_laddr(&ctx->emit, val_offset);
if (by_value) { if (by_value) {
emit_load_type(&ctx->emit, SPL_I32); emit_load_type(&ctx->emit, SPL_I32);
} else { } else {
emit_load_ptr(&ctx->emit); emit_load_ptr(&ctx->emit);
emit_ptr_add(&ctx->emit, 0); emit_ptr_add(&ctx->emit, 0);
emit_load_type(&ctx->emit, SPL_I32); emit_load_type(&ctx->emit, SPL_I32);
}
emit_push_i32(&ctx->emit, vit->enum_field.value);
emit_binop(&ctx->emit, SPL_EQ, SPL_I32);
return (int)vi;
} }
emit_push_i32(&ctx->emit, vit->enum_field.value);
emit_binop(&ctx->emit, SPL_EQ, SPL_I32);
return (int)vi;
} }
} }
}
spl_comp_error(ctx, "unknown variant '%s' in match", vname); spl_comp_error(ctx, "unknown variant '%s' in match", vname);
return -1; return -1;
} }
@@ -1290,49 +1361,3 @@ void spl_emit_match_value_cmp(spl_comp_t *ctx, int val_offset) {
spl_parse_expr(ctx, PREC_LOGOR); spl_parse_expr(ctx, PREC_LOGOR);
emit_binop(&ctx->emit, SPL_EQ, SPL_I32); emit_binop(&ctx->emit, SPL_EQ, SPL_I32);
} }
void spl_emit_ret(spl_comp_t *ctx, int ret_type_idx) {
if (spl_type_needs_multi_slot(&ctx->tctx, ret_type_idx)) {
/* Stack: [src_addr] — copy from src into fp+sizeof(spl_val_t) return area */
emit_laddr(&ctx->emit, (int)sizeof(spl_val_t));
emit_swap(&ctx->emit);
emit_copy_addr_to_addr(&ctx->emit,
spl_type_slot_count(&ctx->tctx, ret_type_idx), 0);
/* Stack empty after copy. emit_return pushes laddr + ret. */
}
emit_return(&ctx->emit, &ctx->tctx, ret_type_idx);
}
void spl_emit_store_init(spl_comp_t *ctx, int var_offset, int var_type_idx) {
if (var_type_idx >= 0 &&
(spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_STRUCT ||
spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_ENUM)) {
usize sz = spl_type_size(&ctx->tctx, var_type_idx);
if (sz <= sizeof(spl_val_t)) {
emit_store_to_laddr(&ctx->emit, var_offset, spl_type_emit_type(&ctx->tctx, var_type_idx));
} else {
usize nslots = (sz + sizeof(spl_val_t) - 1) / sizeof(spl_val_t);
emit_frame_copy(&ctx->emit, var_offset, nslots);
}
} else if (var_type_idx >= 0 && spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_ARRAY) {
int elem_idx = spl_type_elem_type(&ctx->tctx, var_type_idx);
spl_type_t bt = spl_type_emit_type(&ctx->tctx, elem_idx);
usize stride = spl_type_elem_stride(&ctx->tctx, elem_idx);
int arr_len = (int)spl_type_array_len(&ctx->tctx, var_type_idx);
for (int i = arr_len - 1; i >= 0; i--) {
emit_laddr(&ctx->emit, var_offset + (int)(i * stride));
emit_swap(&ctx->emit);
if (elem_idx >= 0 && !spl_type_is_scalar(&ctx->tctx, elem_idx)) {
emit_copy_addr_to_addr(&ctx->emit, spl_type_slot_count(&ctx->tctx, elem_idx), 0);
} else {
emit_store_type(&ctx->emit, bt);
}
}
} else if (var_type_idx >= 0 && spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_SLICE) {
emit_store_to_laddr(&ctx->emit, var_offset + (int)sizeof(spl_val_t), SPL_USIZE);
emit_store_to_laddr(&ctx->emit, var_offset, SPL_PTR);
} else {
spl_type_t bt = spl_type_emit_type(&ctx->tctx, var_type_idx);
emit_store_to_laddr(&ctx->emit, var_offset, bt);
}
}

View File

@@ -4,6 +4,15 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
spl_tok_t *peek(spl_comp_t *ctx) { return &vec_at(ctx->toks, ctx->tok_idx); }
spl_tok_t *advance(spl_comp_t *ctx) {
spl_tok_t *t = &vec_at(ctx->toks, ctx->tok_idx);
if (t->type != TOK_EOF)
ctx->tok_idx++;
return t;
}
int expect(spl_comp_t *ctx, spl_tok_type_t type) { int expect(spl_comp_t *ctx, spl_tok_type_t type) {
if (peek(ctx)->type == type) { if (peek(ctx)->type == type) {
advance(ctx); advance(ctx);

View File

@@ -4,11 +4,23 @@
#include "spl_comp.h" #include "spl_comp.h"
/* Token stream access */
spl_tok_t *peek(spl_comp_t *ctx);
spl_tok_t *advance(spl_comp_t *ctx);
/* Token matching helpers */ /* Token matching helpers */
int expect(spl_comp_t *ctx, spl_tok_type_t type); int expect(spl_comp_t *ctx, spl_tok_type_t type);
int match(spl_comp_t *ctx, spl_tok_type_t type); int match(spl_comp_t *ctx, spl_tok_type_t type);
void skip_nl(spl_comp_t *ctx); void skip_nl(spl_comp_t *ctx);
/* Token introspection */
const char *spl_tok_type_name(spl_tok_type_t type);
void spl_tok_dump(spl_tok_t *tok);
void spl_tok_vec_dump(spl_tok_vec_t *toks);
void spl_tok_vec_drop(spl_tok_vec_t *toks);
usize spl_tok_copy_name(spl_tok_t *tok, char *buf, usize buf_size);
const char *spl_tok_loc_str(spl_comp_t *ctx);
/* Parse an integer literal value, handling optional '-' prefix for negatives. /* Parse an integer literal value, handling optional '-' prefix for negatives.
* Returns 1 on success (value in *val), 0 if current token isn't an integer. * Returns 1 on success (value in *val), 0 if current token isn't an integer.
* On success, advances past all consumed tokens. On failure, does not advance. */ * On success, advances past all consumed tokens. On failure, does not advance. */

View File

@@ -17,6 +17,7 @@
X(defer , KW_DEFER , SPL_V0) \ X(defer , KW_DEFER , SPL_V0) \
X(else , KW_ELSE , SPL_V0) \ X(else , KW_ELSE , SPL_V0) \
X(enum , KW_ENUM , SPL_V0) \ X(enum , KW_ENUM , SPL_V0) \
X(extern , KW_EXTERN , SPL_V0) \
X(false , KW_FALSE , SPL_V0) \ X(false , KW_FALSE , SPL_V0) \
X(fn , KW_FN , SPL_V0) \ X(fn , KW_FN , SPL_V0) \
X(for , KW_FOR , SPL_V0) \ X(for , KW_FOR , SPL_V0) \
@@ -129,13 +130,6 @@ typedef VEC(spl_tok_t) spl_tok_vec_t;
/* Lexer entry point */ /* Lexer entry point */
spl_tok_vec_t spl_lex(const char *source, const char *fname); spl_tok_vec_t spl_lex(const char *source, const char *fname);
/* Utility functions */
const char *spl_tok_type_name(spl_tok_type_t type);
void spl_tok_dump(spl_tok_t *tok);
void spl_tok_vec_dump(spl_tok_vec_t *toks);
void spl_tok_vec_drop(spl_tok_vec_t *toks);
usize spl_tok_copy_name(spl_tok_t *tok, char *buf, usize buf_size);
/* Decode escape sequence, advance *s past it. Returns 0 on success. */ /* Decode escape sequence, advance *s past it. Returns 0 on success. */
int spl_decode_escape(const char **s, char *out); int spl_decode_escape(const char **s, char *out);

View File

@@ -4,15 +4,6 @@
#include "spl_lex_util.h" #include "spl_lex_util.h"
#include <string.h> #include <string.h>
spl_tok_t *peek(spl_comp_t *ctx) { return &vec_at(ctx->toks, ctx->tok_idx); }
spl_tok_t *advance(spl_comp_t *ctx) {
spl_tok_t *t = &vec_at(ctx->toks, ctx->tok_idx);
if (t->type != TOK_EOF)
ctx->tok_idx++;
return t;
}
/* ============================================================ /* ============================================================
* Parse function definition * Parse function definition
* ============================================================ */ * ============================================================ */
@@ -52,9 +43,20 @@ static int parse_params_decl(spl_comp_t *ctx, char pnames[][256], int ptypes[])
return nparams; return nparams;
} }
static int parse_fn_body(spl_comp_t *ctx, const char *fn_name, int ret_type_idx, static int parse_fn_body(spl_comp_t *ctx, const char *fn_name, int ret_type_idx, int nparams,
int nparams, char pnames[][256], int ptypes[], int is_pub) { char pnames[][256], int ptypes[], int is_pub) {
int fi = spl_declare_func(ctx, fn_name, ret_type_idx, nparams, 0, is_pub); int fi = spl_declare_func(ctx, fn_name, ret_type_idx, nparams, 0, is_pub);
{
spl_func_info_t *f = &vec_at(ctx->funcs, fi);
f->param_type_indices = calloc(nparams, sizeof(int));
f->param_names = calloc(nparams, sizeof(char *));
for (int i = 0; i < nparams; i++) {
f->param_type_indices[i] = ptypes[i];
f->param_names[i] = strdup(pnames[i]);
}
}
ctx->current_func_idx = fi; ctx->current_func_idx = fi;
ctx->current_ret_type_idx = ret_type_idx; ctx->current_ret_type_idx = ret_type_idx;
fa_init(&ctx->emit.frame); fa_init(&ctx->emit.frame);
@@ -84,8 +86,7 @@ static int parse_fn_body(spl_comp_t *ctx, const char *fn_name, int ret_type_idx,
total_phys_slots += (int)((psz + sizeof(spl_val_t) - 1) / sizeof(spl_val_t)); total_phys_slots += (int)((psz + sizeof(spl_val_t) - 1) / sizeof(spl_val_t));
} }
if (spl_type_needs_multi_slot(&ctx->tctx, ret_type_idx)) { if (spl_type_needs_multi_slot(&ctx->tctx, ret_type_idx)) {
usize min_bytes = usize min_bytes = spl_type_slot_count(&ctx->tctx, ret_type_idx) * sizeof(spl_val_t);
spl_type_slot_count(&ctx->tctx, ret_type_idx) * sizeof(spl_val_t);
if ((usize)ctx->emit.frame.peak_bytes < min_bytes) if ((usize)ctx->emit.frame.peak_bytes < min_bytes)
ctx->emit.frame.peak_bytes = (int)min_bytes; ctx->emit.frame.peak_bytes = (int)min_bytes;
} }
@@ -97,18 +98,11 @@ static int parse_fn_body(spl_comp_t *ctx, const char *fn_name, int ret_type_idx,
spl_emit_defer_epilogue(ctx, ctx->scope_depth); spl_emit_defer_epilogue(ctx, ctx->scope_depth);
spl_pop_scope(ctx); spl_pop_scope(ctx);
emit_return(&ctx->emit, &ctx->tctx, ctx->current_ret_type_idx);
{ {
spl_func_info_t *f = &vec_at(ctx->funcs, fi); spl_func_info_t *f = &vec_at(ctx->funcs, fi);
f->param_type_indices = calloc(nparams, sizeof(int)); spl_prog_end_func(&ctx->prog, f->func_idx);
f->param_names = calloc(nparams, sizeof(char *));
for (int i = 0; i < nparams; i++) {
f->param_type_indices[i] = ptypes[i];
f->param_names[i] = strdup(pnames[i]);
}
} }
emit_return(&ctx->emit, &ctx->tctx, ctx->current_ret_type_idx);
spl_prog_end_func(&ctx->prog, fi);
ctx->current_func_idx = -1; ctx->current_func_idx = -1;
ctx->current_ret_type_idx = -1; ctx->current_ret_type_idx = -1;
return fi; return fi;
@@ -137,9 +131,13 @@ static void parse_fn_decl(spl_comp_t *ctx, int is_extern, int is_pub) {
skip_nl(ctx); skip_nl(ctx);
} }
int fi;
if (is_extern) { if (is_extern) {
spl_declare_func(ctx, fn_name, ret_type_idx, nparams, 1, is_pub); fi = spl_declare_func(ctx, fn_name, ret_type_idx, nparams, 1, is_pub);
spl_ensure_native(ctx, fn_name); spl_ensure_native(ctx, fn_name);
if (ctx->tctx.current_type_idx == 0)
spl_type_add_method(&ctx->tctx, 0, fn_name, fi);
if (peek(ctx)->type == TOK_SEMICOLON) if (peek(ctx)->type == TOK_SEMICOLON)
advance(ctx); advance(ctx);
return; return;
@@ -152,7 +150,9 @@ static void parse_fn_decl(spl_comp_t *ctx, int is_extern, int is_pub) {
skip_nl(ctx); skip_nl(ctx);
parse_fn_body(ctx, fn_name, ret_type_idx, nparams, pnames, ptypes, is_pub); fi = parse_fn_body(ctx, fn_name, ret_type_idx, nparams, pnames, ptypes, is_pub);
if (ctx->tctx.current_type_idx == 0)
spl_type_add_method(&ctx->tctx, 0, fn_name, fi);
} }
/* ============================================================ /* ============================================================
@@ -211,10 +211,13 @@ static void skip_type_decl(spl_comp_t *ctx) {
int bd = 1; int bd = 1;
advance(ctx); advance(ctx);
while (bd > 0 && ctx->tok_idx < vec_size(ctx->toks)) { while (bd > 0 && ctx->tok_idx < vec_size(ctx->toks)) {
if (peek(ctx)->type == TOK_L_BRACE) spl_tok_type_t tt = peek(ctx)->type;
if (tt == TOK_L_BRACE)
bd++; bd++;
else if (peek(ctx)->type == TOK_R_BRACE) else if (tt == TOK_R_BRACE)
bd--; bd--;
else if (tt == TOK_EOF)
break;
advance(ctx); advance(ctx);
} }
} else { } else {
@@ -251,6 +254,8 @@ static void parse_type_body(spl_comp_t *ctx, int container_type_idx, int is_enum
advance(ctx); advance(ctx);
} else if (tt == KW_TYPE && depth == 1) { } else if (tt == KW_TYPE && depth == 1) {
parse_type_decl(ctx); parse_type_decl(ctx);
} else if (tt == TOK_EOF) {
break;
} else { } else {
advance(ctx); advance(ctx);
} }
@@ -280,10 +285,35 @@ static void parse_type_body(spl_comp_t *ctx, int container_type_idx, int is_enum
spl_tok_t *name_tok = advance(ctx); spl_tok_t *name_tok = advance(ctx);
char mname[256]; char mname[256];
spl_tok_copy_name(name_tok, mname, sizeof(mname)); spl_tok_copy_name(name_tok, mname, sizeof(mname));
/* Count parameters for forward reference */
int pcount = 0;
if (peek(ctx)->type == TOK_L_PAREN) {
advance(ctx); /* ( */
skip_nl(ctx);
if (peek(ctx)->type != TOK_R_PAREN) {
pcount = 1;
for (;;) {
advance(ctx); /* skip param name or type token */
skip_nl(ctx);
if (peek(ctx)->type == TOK_R_PAREN)
break;
if (peek(ctx)->type == TOK_COMMA) {
advance(ctx); /* , */
skip_nl(ctx);
pcount++;
}
}
}
advance(ctx); /* ) */
}
char qualified[512]; char qualified[512];
snprintf(qualified, sizeof(qualified), "%s.%s", cname, mname); snprintf(qualified, sizeof(qualified), "%s.%s", cname, mname);
int fi = spl_declare_func(ctx, qualified, -1, 0, 0, 0); int fi = spl_declare_func(ctx, qualified, -1, pcount, 0, 0);
spl_type_add_method(&ctx->tctx, container_type_idx, mname, fi); spl_type_add_method(&ctx->tctx, container_type_idx, mname, fi);
} else if (tt == TOK_EOF) {
break;
} else { } else {
advance(ctx); advance(ctx);
} }
@@ -339,6 +369,8 @@ static void parse_type_body(spl_comp_t *ctx, int container_type_idx, int is_enum
spl_tok_copy_name(vtok, vname, sizeof(vname)); spl_tok_copy_name(vtok, vname, sizeof(vname));
spl_type_add_variant(&ctx->tctx, container_type_idx, vname, spl_type_add_variant(&ctx->tctx, container_type_idx, vname,
dtype >= 0 ? dtype : -1); dtype >= 0 ? dtype : -1);
} else if (tt == TOK_EOF) {
break;
} else { } else {
char vname[256]; char vname[256];
spl_tok_copy_name(vtok, vname, sizeof(vname)); spl_tok_copy_name(vtok, vname, sizeof(vname));
@@ -449,21 +481,42 @@ void spl_parse_prog(spl_comp_t *ctx) {
parse_type_decl(ctx); parse_type_decl(ctx);
break; break;
} }
case TOK_SHARP: case TOK_AT:
advance(ctx); /* # */ case TOK_SHARP: {
if (peek(ctx)->type == TOK_L_BRACKET) { int tt = peek(ctx)->type;
advance(ctx); /* [ */ advance(ctx); /* @ or # */
while (peek(ctx)->type != TOK_R_BRACKET && peek(ctx)->type != TOK_EOF) skip_nl(ctx);
advance(ctx); if (tt == TOK_AT) {
if (peek(ctx)->type == TOK_R_BRACKET) /* @extern(vm) fn ... */
advance(ctx); if (peek(ctx)->type == KW_EXTERN) {
advance(ctx); /* extern */
skip_nl(ctx);
if (peek(ctx)->type == TOK_L_PAREN) {
advance(ctx); /* ( */
skip_nl(ctx);
advance(ctx); /* target name (e.g. "vm") */
skip_nl(ctx);
if (peek(ctx)->type == TOK_R_PAREN)
advance(ctx);
}
}
} else {
/* #[extern("vm")] fn ... (legacy) */
if (peek(ctx)->type == TOK_L_BRACKET) {
advance(ctx); /* [ */
while (peek(ctx)->type != TOK_R_BRACKET && peek(ctx)->type != TOK_EOF)
advance(ctx);
if (peek(ctx)->type == TOK_R_BRACKET)
advance(ctx);
}
} }
skip_nl(ctx); skip_nl(ctx);
if (peek(ctx)->type == KW_FN) if (peek(ctx)->type == KW_FN)
parse_fn_decl(ctx, 1, 0); parse_fn_decl(ctx, 1, 0);
break; break;
}
default: { default: {
int prev = ctx->tok_idx; usize prev = ctx->tok_idx;
spl_parse_stmt(ctx); spl_parse_stmt(ctx);
if (ctx->tok_idx == prev) if (ctx->tok_idx == prev)
advance(ctx); advance(ctx);

View File

@@ -163,10 +163,11 @@ spl_expr_result_t spl_parse_block_expr(spl_comp_t *ctx) {
} }
spl_tok_type_t t = peek(ctx)->type; spl_tok_type_t t = peek(ctx)->type;
int is_keyword = (t == KW_RET || t == KW_VAR || t == KW_CONST || t == KW_IF || int is_keyword =
t == KW_WHILE || t == KW_LOOP || t == KW_FOR || t == KW_BREAK || (t == KW_RET || t == KW_VAR || t == KW_CONST || t == KW_IF || t == KW_WHILE ||
t == KW_CONTINUE || t == KW_DEFER || t == KW_MATCH || t == KW_TYPE || t == KW_LOOP || t == KW_FOR || t == KW_BREAK || t == KW_CONTINUE || t == KW_DEFER ||
t == TOK_L_BRACE || t == TOK_SHARP || t == TOK_LINE_COMMENT); t == KW_MATCH || t == KW_TYPE || t == TOK_L_BRACE || t == TOK_AT || t == TOK_SHARP ||
t == TOK_LINE_COMMENT);
if (is_keyword) { if (is_keyword) {
/* Keyword statement — produces void */ /* Keyword statement — produces void */
@@ -433,7 +434,7 @@ static void parse_for_stmt(spl_comp_t *ctx) {
/* Condition: idx < len */ /* Condition: idx < len */
emit_pick(&ctx->emit, 1); /* copy len */ emit_pick(&ctx->emit, 1); /* copy len */
emit_pick(&ctx->emit, 1); /* copy idx */ emit_pick(&ctx->emit, 1); /* copy idx */
emit_swap(&ctx->emit); /* [idx, len] → [len, idx] → SWAP → [idx, len] */ emit_swap(&ctx->emit); /* [idx, len] → [len, idx] → SWAP → [idx, len] */
emit_ult_usize(&ctx->emit); emit_ult_usize(&ctx->emit);
spl_val_t bz_addr = emit_bz_here(&ctx->emit); spl_val_t bz_addr = emit_bz_here(&ctx->emit);
@@ -454,7 +455,8 @@ static void parse_for_stmt(spl_comp_t *ctx) {
spl_type_size(&ctx->tctx, elem_type_idx) > sizeof(spl_val_t)) { spl_type_size(&ctx->tctx, elem_type_idx) > sizeof(spl_val_t)) {
emit_frame_copy(&ctx->emit, val_offset, spl_type_slot_count(&ctx->tctx, elem_type_idx)); emit_frame_copy(&ctx->emit, val_offset, spl_type_slot_count(&ctx->tctx, elem_type_idx));
} else { } else {
spl_type_t elem_bt = elem_type_idx >= 0 ? spl_type_emit_type(&ctx->tctx, elem_type_idx) : SPL_I32; spl_type_t elem_bt =
elem_type_idx >= 0 ? spl_type_emit_type(&ctx->tctx, elem_type_idx) : SPL_I32;
emit_load_type(&ctx->emit, elem_bt); emit_load_type(&ctx->emit, elem_bt);
emit_store_to_laddr(&ctx->emit, val_offset, elem_bt); emit_store_to_laddr(&ctx->emit, val_offset, elem_bt);
} }
@@ -545,8 +547,8 @@ static void parse_defer_stmt(spl_comp_t *ctx) {
/* Parse an enum variant pattern in a match arm: .VariantName /* Parse an enum variant pattern in a match arm: .VariantName
* Delegates comparison to expr layer (spl_emit_match_enum_cmp). * Delegates comparison to expr layer (spl_emit_match_enum_cmp).
* Returns the variant item index, or -1 on error. */ * Returns the variant item index, or -1 on error. */
static int parse_match_enum_variant(spl_comp_t *ctx, int enum_type_idx, static int parse_match_enum_variant(spl_comp_t *ctx, int enum_type_idx, int val_offset,
int val_offset, int by_value) { int by_value) {
return spl_emit_match_enum_cmp(ctx, enum_type_idx, val_offset, by_value); return spl_emit_match_enum_cmp(ctx, enum_type_idx, val_offset, by_value);
} }
@@ -561,9 +563,8 @@ static void parse_match_value_pattern(spl_comp_t *ctx, int val_offset) {
* Declares local variables and loads corresponding field data * Declares local variables and loads corresponding field data
* from the matched value's data area (offset 4+). * from the matched value's data area (offset 4+).
* Sets *scope_pushed = 1 if bindings declared. */ * Sets *scope_pushed = 1 if bindings declared. */
static void parse_match_enum_bindings(spl_comp_t *ctx, int enum_type_idx, static void parse_match_enum_bindings(spl_comp_t *ctx, int enum_type_idx, int variant_item_idx,
int variant_item_idx, int val_offset, int val_offset, int *scope_pushed) {
int *scope_pushed) {
advance(ctx); /* ( */ advance(ctx); /* ( */
skip_nl(ctx); skip_nl(ctx);
if (peek(ctx)->type == TOK_R_PAREN) { if (peek(ctx)->type == TOK_R_PAREN) {
@@ -603,7 +604,8 @@ static void parse_match_enum_bindings(spl_comp_t *ctx, int enum_type_idx,
} }
} }
int boffset = spl_declare_var(ctx, bname, btype_idx, 0); int boffset = spl_declare_var(ctx, bname, btype_idx, 0);
emit_load_to_var(&ctx->emit, &ctx->tctx, val_offset, field_byte_off, btype_idx, boffset); emit_load_to_var(&ctx->emit, &ctx->tctx, val_offset, field_byte_off, btype_idx,
boffset);
bi++; bi++;
skip_nl(ctx); skip_nl(ctx);
@@ -721,7 +723,8 @@ static void parse_match_stmt(spl_comp_t *ctx) {
skip_nl(ctx); skip_nl(ctx);
if (peek(ctx)->type != TOK_ASSIGN) { if (peek(ctx)->type != TOK_ASSIGN) {
if (n_bnz < 128) if (n_bnz < 128)
bnz_addrs[n_bnz++] = emit_bnz_here(&ctx->emit); /* fallthrough to body */ bnz_addrs[n_bnz++] =
emit_bnz_here(&ctx->emit); /* fallthrough to body */
continue; continue;
} }
break; break;
@@ -738,8 +741,8 @@ static void parse_match_stmt(spl_comp_t *ctx) {
/* --- Parse enum bindings (only for last variant) --- */ /* --- Parse enum bindings (only for last variant) --- */
if (is_enum_match && has_parens && arm_variant_item >= 0) { if (is_enum_match && has_parens && arm_variant_item >= 0) {
parse_match_enum_bindings(ctx, enum_type_idx, arm_variant_item, parse_match_enum_bindings(ctx, enum_type_idx, arm_variant_item, val_offset,
val_offset, &scope_pushed); &scope_pushed);
} }
skip_nl(ctx); skip_nl(ctx);
@@ -793,13 +796,31 @@ static void parse_match_stmt(spl_comp_t *ctx) {
* ============================================================ */ * ============================================================ */
static void parse_extern_decl(spl_comp_t *ctx) { static void parse_extern_decl(spl_comp_t *ctx) {
advance(ctx); /* # */ int tt = peek(ctx)->type;
expect(ctx, TOK_L_BRACKET); advance(ctx); /* @ or # */
/* Skip extern("vm") or just look for fn */ skip_nl(ctx);
while (peek(ctx)->type != TOK_R_BRACKET && peek(ctx)->type != TOK_EOF) if (tt == TOK_AT) {
advance(ctx); /* @extern(vm) fn ... */
if (peek(ctx)->type == TOK_R_BRACKET) if (peek(ctx)->type == KW_EXTERN) {
advance(ctx); advance(ctx); /* extern */
skip_nl(ctx);
if (peek(ctx)->type == TOK_L_PAREN) {
advance(ctx); /* ( */
skip_nl(ctx);
advance(ctx); /* target name */
skip_nl(ctx);
if (peek(ctx)->type == TOK_R_PAREN)
advance(ctx);
}
}
} else {
/* #[extern("vm")] fn ... (legacy) */
expect(ctx, TOK_L_BRACKET);
while (peek(ctx)->type != TOK_R_BRACKET && peek(ctx)->type != TOK_EOF)
advance(ctx);
if (peek(ctx)->type == TOK_R_BRACKET)
advance(ctx);
}
skip_nl(ctx); skip_nl(ctx);
@@ -970,7 +991,21 @@ void spl_parse_stmt(spl_comp_t *ctx) {
case TOK_LINE_COMMENT: case TOK_LINE_COMMENT:
advance(ctx); advance(ctx);
break; break;
case TOK_SHARP: /* #[extern(...)] */ case TOK_AT: { /* @extern(...) or @dbg/@@sizeof expression */
usize saved = ctx->tok_idx;
advance(ctx); /* @ */
skip_nl(ctx);
spl_tok_t *t = peek(ctx);
if (t && t->type == KW_EXTERN) {
ctx->tok_idx = saved;
parse_extern_decl(ctx);
} else {
ctx->tok_idx = saved;
parse_expr_stmt(ctx);
}
break;
}
case TOK_SHARP: /* #[extern(...)] (legacy) */
parse_extern_decl(ctx); parse_extern_decl(ctx);
break; break;
default: default:

View File

@@ -192,9 +192,7 @@ int spl_type_ptr(spl_type_ctx_t *tctx, int elem_type_idx) {
} }
int spl_type_array(spl_type_ctx_t *tctx, int elem_type_idx, usize len) { int spl_type_array(spl_type_ctx_t *tctx, int elem_type_idx, usize len) {
spl_type_info_t *elem = (elem_type_idx >= 0) spl_type_info_t *elem = (elem_type_idx >= 0) ? &vec_at(tctx->types, elem_type_idx) : NULL;
? &vec_at(tctx->types, elem_type_idx)
: NULL;
spl_type_info_t t; spl_type_info_t t;
memset(&t, 0, sizeof(t)); memset(&t, 0, sizeof(t));
@@ -310,8 +308,7 @@ int spl_type_alias(spl_type_ctx_t *tctx, const char *name, int target_type_idx)
* Item management * Item management
* ============================================================ */ * ============================================================ */
void spl_type_add_field(spl_type_ctx_t *tctx, int type_idx, const char *name, void spl_type_add_field(spl_type_ctx_t *tctx, int type_idx, const char *name, int field_type_idx) {
int field_type_idx) {
spl_type_info_t *t = &vec_at(tctx->types, type_idx); spl_type_info_t *t = &vec_at(tctx->types, type_idx);
spl_type_item_t item; spl_type_item_t item;
memset(&item, 0, sizeof(item)); memset(&item, 0, sizeof(item));
@@ -322,8 +319,7 @@ void spl_type_add_field(spl_type_ctx_t *tctx, int type_idx, const char *name,
vec_push(t->items, item); vec_push(t->items, item);
} }
void spl_type_add_variant(spl_type_ctx_t *tctx, int type_idx, const char *name, void spl_type_add_variant(spl_type_ctx_t *tctx, int type_idx, const char *name, int data_type_idx) {
int data_type_idx) {
spl_type_info_t *t = &vec_at(tctx->types, type_idx); spl_type_info_t *t = &vec_at(tctx->types, type_idx);
spl_type_item_t item; spl_type_item_t item;
memset(&item, 0, sizeof(item)); memset(&item, 0, sizeof(item));
@@ -334,15 +330,13 @@ void spl_type_add_variant(spl_type_ctx_t *tctx, int type_idx, const char *name,
vec_push(t->items, item); vec_push(t->items, item);
} }
void spl_type_add_method(spl_type_ctx_t *tctx, int type_idx, const char *name, void spl_type_add_method(spl_type_ctx_t *tctx, int type_idx, const char *name, int func_idx) {
int func_idx) {
spl_type_info_t *t = &vec_at(tctx->types, type_idx); spl_type_info_t *t = &vec_at(tctx->types, type_idx);
/* Deduplicate: update existing method entry */ /* Deduplicate: update existing method entry */
vec_for(t->items, i) { vec_for(t->items, i) {
spl_type_item_t *it = &vec_at(t->items, i); spl_type_item_t *it = &vec_at(t->items, i);
if (it->item_kind == ITEM_METHOD && it->name && if (it->item_kind == ITEM_METHOD && it->name && strcmp(it->name, name) == 0) {
strcmp(it->name, name) == 0) {
it->method.func_idx = func_idx; it->method.func_idx = func_idx;
return; return;
} }
@@ -357,7 +351,7 @@ void spl_type_add_method(spl_type_ctx_t *tctx, int type_idx, const char *name,
} }
void spl_type_add_nested(spl_type_ctx_t *tctx, int parent_idx, const char *name, void spl_type_add_nested(spl_type_ctx_t *tctx, int parent_idx, const char *name,
int child_type_idx) { int child_type_idx) {
spl_type_info_t *t = &vec_at(tctx->types, parent_idx); spl_type_info_t *t = &vec_at(tctx->types, parent_idx);
spl_type_item_t item; spl_type_item_t item;
memset(&item, 0, sizeof(item)); memset(&item, 0, sizeof(item));
@@ -387,8 +381,7 @@ void spl_type_compute_layout(spl_type_ctx_t *tctx, int type_idx) {
spl_type_item_t *it = &vec_at(t->items, i); spl_type_item_t *it = &vec_at(t->items, i);
if (it->item_kind == ITEM_FIELD && it->aggregate_field.type_idx >= 0) { if (it->item_kind == ITEM_FIELD && it->aggregate_field.type_idx >= 0) {
spl_type_compute_layout(tctx, it->aggregate_field.type_idx); spl_type_compute_layout(tctx, it->aggregate_field.type_idx);
spl_type_info_t *ft = spl_type_info_t *ft = &vec_at(tctx->types, it->aggregate_field.type_idx);
&vec_at(tctx->types, it->aggregate_field.type_idx);
it->aggregate_field.offset = offset; it->aggregate_field.offset = offset;
offset += ft->byte_size; offset += ft->byte_size;
} }
@@ -407,8 +400,7 @@ void spl_type_compute_layout(spl_type_ctx_t *tctx, int type_idx) {
spl_type_item_t *it = &vec_at(t->items, i); spl_type_item_t *it = &vec_at(t->items, i);
if (it->item_kind == ITEM_FIELD && it->aggregate_field.type_idx >= 0) { if (it->item_kind == ITEM_FIELD && it->aggregate_field.type_idx >= 0) {
spl_type_compute_layout(tctx, it->aggregate_field.type_idx); spl_type_compute_layout(tctx, it->aggregate_field.type_idx);
spl_type_info_t *ft = spl_type_info_t *ft = &vec_at(tctx->types, it->aggregate_field.type_idx);
&vec_at(tctx->types, it->aggregate_field.type_idx);
it->aggregate_field.offset = 0; it->aggregate_field.offset = 0;
if (ft->byte_size > max_sz) if (ft->byte_size > max_sz)
max_sz = ft->byte_size; max_sz = ft->byte_size;
@@ -426,11 +418,9 @@ void spl_type_compute_layout(spl_type_ctx_t *tctx, int type_idx) {
usize max_dsize = 0; usize max_dsize = 0;
vec_for(t->items, i) { vec_for(t->items, i) {
spl_type_item_t *it = &vec_at(t->items, i); spl_type_item_t *it = &vec_at(t->items, i);
if (it->item_kind == ITEM_VARIANT && if (it->item_kind == ITEM_VARIANT && it->enum_field.type_idx >= 0) {
it->enum_field.type_idx >= 0) {
spl_type_compute_layout(tctx, it->enum_field.type_idx); spl_type_compute_layout(tctx, it->enum_field.type_idx);
spl_type_info_t *dt = spl_type_info_t *dt = &vec_at(tctx->types, it->enum_field.type_idx);
&vec_at(tctx->types, it->enum_field.type_idx);
if (dt->byte_size > max_dsize) if (dt->byte_size > max_dsize)
max_dsize = dt->byte_size; max_dsize = dt->byte_size;
} }
@@ -543,8 +533,7 @@ int spl_type_is_scalar(spl_type_ctx_t *tctx, int type_idx) {
} }
int spl_type_needs_multi_slot(spl_type_ctx_t *tctx, int type_idx) { int spl_type_needs_multi_slot(spl_type_ctx_t *tctx, int type_idx) {
return !spl_type_is_scalar(tctx, type_idx) && return !spl_type_is_scalar(tctx, type_idx) && spl_type_slot_count(tctx, type_idx) > 1;
spl_type_slot_count(tctx, type_idx) > 1;
} }
int spl_type_is_aggregate(spl_type_ctx_t *tctx, int type_idx) { int spl_type_is_aggregate(spl_type_ctx_t *tctx, int type_idx) {
@@ -629,21 +618,18 @@ const char *spl_type_str(spl_type_ctx_t *tctx, int type_idx) {
} }
case TYPE_PTR: { case TYPE_PTR: {
static char buf[64]; static char buf[64];
snprintf(buf, sizeof(buf), "*%s", snprintf(buf, sizeof(buf), "*%s", spl_type_str(tctx, spl_type_elem_type(tctx, type_idx)));
spl_type_str(tctx, spl_type_elem_type(tctx, type_idx)));
return buf; return buf;
} }
case TYPE_ARRAY: { case TYPE_ARRAY: {
static char buf[64]; static char buf[64];
snprintf(buf, sizeof(buf), "[%zu]%s", snprintf(buf, sizeof(buf), "[%zu]%s", spl_type_array_len(tctx, type_idx),
spl_type_array_len(tctx, type_idx),
spl_type_str(tctx, spl_type_elem_type(tctx, type_idx))); spl_type_str(tctx, spl_type_elem_type(tctx, type_idx)));
return buf; return buf;
} }
case TYPE_SLICE: { case TYPE_SLICE: {
static char buf[64]; static char buf[64];
snprintf(buf, sizeof(buf), "[]%s", snprintf(buf, sizeof(buf), "[]%s", spl_type_str(tctx, spl_type_elem_type(tctx, type_idx)));
spl_type_str(tctx, spl_type_elem_type(tctx, type_idx)));
return buf; return buf;
} }
case TYPE_STRUCT: case TYPE_STRUCT:
@@ -661,8 +647,7 @@ const char *spl_type_str(spl_type_ctx_t *tctx, int type_idx) {
* Item iteration * Item iteration
* ============================================================ */ * ============================================================ */
int spl_type_item_count(spl_type_ctx_t *tctx, int type_idx, int spl_type_item_count(spl_type_ctx_t *tctx, int type_idx, spl_type_item_kind_t kind) {
spl_type_item_kind_t kind) {
if (type_idx < 0) if (type_idx < 0)
return 0; return 0;
spl_type_info_t *t = &vec_at(tctx->types, type_idx); spl_type_info_t *t = &vec_at(tctx->types, type_idx);
@@ -674,8 +659,7 @@ int spl_type_item_count(spl_type_ctx_t *tctx, int type_idx,
return count; return count;
} }
spl_type_item_t *spl_type_item_at(spl_type_ctx_t *tctx, int type_idx, spl_type_item_t *spl_type_item_at(spl_type_ctx_t *tctx, int type_idx, int item_index) {
int item_index) {
if (type_idx < 0) if (type_idx < 0)
return NULL; return NULL;
spl_type_info_t *t = &vec_at(tctx->types, type_idx); spl_type_info_t *t = &vec_at(tctx->types, type_idx);
@@ -685,8 +669,7 @@ spl_type_item_t *spl_type_item_at(spl_type_ctx_t *tctx, int type_idx,
} }
spl_type_item_t *spl_type_first_of_kind(spl_type_ctx_t *tctx, int type_idx, spl_type_item_t *spl_type_first_of_kind(spl_type_ctx_t *tctx, int type_idx,
spl_type_item_kind_t kind, spl_type_item_kind_t kind, int *count) {
int *count) {
if (type_idx < 0) { if (type_idx < 0) {
if (count) if (count)
*count = 0; *count = 0;
@@ -737,15 +720,13 @@ int spl_type_resolve(spl_type_ctx_t *tctx, const char *name) {
return -1; return -1;
} }
int spl_type_resolve_in(spl_type_ctx_t *tctx, int parent_idx, int spl_type_resolve_in(spl_type_ctx_t *tctx, int parent_idx, const char *name) {
const char *name) {
if (parent_idx < 0 || !name) if (parent_idx < 0 || !name)
return -1; return -1;
spl_type_info_t *t = &vec_at(tctx->types, parent_idx); spl_type_info_t *t = &vec_at(tctx->types, parent_idx);
vec_for(t->items, i) { vec_for(t->items, i) {
spl_type_item_t *it = &vec_at(t->items, i); spl_type_item_t *it = &vec_at(t->items, i);
if (it->item_kind == ITEM_NESTED_TYPE && it->name && if (it->item_kind == ITEM_NESTED_TYPE && it->name && strcmp(it->name, name) == 0)
strcmp(it->name, name) == 0)
return it->nested_type.type_idx; return it->nested_type.type_idx;
} }
return -1; return -1;
@@ -859,8 +840,7 @@ int spl_type_parse(spl_type_ctx_t *tctx, struct spl_comp *ctx) {
} }
/* Identifier: basic type or named type */ /* Identifier: basic type or named type */
if (tok->type == TOK_IDENT || if (tok->type == TOK_IDENT || ((int)tok->type >= (int)KW_AS && (int)tok->type <= (int)KW_ANY)) {
((int)tok->type >= (int)KW_AS && (int)tok->type <= (int)KW_ANY)) {
const char *name = tok->lexeme; const char *name = tok->lexeme;
usize len = tok->len; usize len = tok->len;

View File

@@ -79,9 +79,9 @@ typedef struct spl_type_info {
spl_type_kind_t kind; spl_type_kind_t kind;
spl_type_t basic_type; /* for TYPE_BASIC */ spl_type_t basic_type; /* for TYPE_BASIC */
spl_type_item_vec_t items; spl_type_item_vec_t items;
usize byte_size; /* total byte size (cached) */ usize byte_size; /* total byte size (cached) */
usize slot_count; /* stack slot count (cached) */ usize slot_count; /* stack slot count (cached) */
int resolved; /* layout computed */ int resolved; /* layout computed */
int parent_type_idx; /* enclosing type, -1 for root */ int parent_type_idx; /* enclosing type, -1 for root */
} spl_type_info_t; } spl_type_info_t;
@@ -127,14 +127,11 @@ int spl_type_alias(spl_type_ctx_t *tctx, const char *name, int target_type_idx);
* Item management — add members to aggregate types * Item management — add members to aggregate types
* ============================================================ */ * ============================================================ */
void spl_type_add_field(spl_type_ctx_t *tctx, int type_idx, const char *name, void spl_type_add_field(spl_type_ctx_t *tctx, int type_idx, const char *name, int field_type_idx);
int field_type_idx); void spl_type_add_variant(spl_type_ctx_t *tctx, int type_idx, const char *name, int data_type_idx);
void spl_type_add_variant(spl_type_ctx_t *tctx, int type_idx, const char *name, void spl_type_add_method(spl_type_ctx_t *tctx, int type_idx, const char *name, int func_idx);
int data_type_idx);
void spl_type_add_method(spl_type_ctx_t *tctx, int type_idx, const char *name,
int func_idx);
void spl_type_add_nested(spl_type_ctx_t *tctx, int parent_idx, const char *name, void spl_type_add_nested(spl_type_ctx_t *tctx, int parent_idx, const char *name,
int child_type_idx); int child_type_idx);
/* ============================================================ /* ============================================================
* Layout — compute byte_size / slot_count, set resolved * Layout — compute byte_size / slot_count, set resolved
@@ -185,13 +182,11 @@ const char *spl_type_str(spl_type_ctx_t *tctx, int type_idx);
* Item iteration — filter by item_kind * Item iteration — filter by item_kind
* ============================================================ */ * ============================================================ */
int spl_type_item_count(spl_type_ctx_t *tctx, int type_idx, int spl_type_item_count(spl_type_ctx_t *tctx, int type_idx, spl_type_item_kind_t kind);
spl_type_item_kind_t kind); spl_type_item_t *spl_type_item_at(spl_type_ctx_t *tctx, int type_idx, int item_index);
spl_type_item_t *spl_type_item_at(spl_type_ctx_t *tctx, int type_idx,
int item_index);
/* Returns pointer to first item of given kind, with *count set */ /* Returns pointer to first item of given kind, with *count set */
spl_type_item_t *spl_type_first_of_kind(spl_type_ctx_t *tctx, int type_idx, spl_type_item_t *spl_type_first_of_kind(spl_type_ctx_t *tctx, int type_idx,
spl_type_item_kind_t kind, int *count); spl_type_item_kind_t kind, int *count);
/* Get raw items vec for direct iteration (avoids double-lookup) */ /* Get raw items vec for direct iteration (avoids double-lookup) */
spl_type_item_vec_t *spl_type_items(spl_type_ctx_t *tctx, int type_idx); spl_type_item_vec_t *spl_type_items(spl_type_ctx_t *tctx, int type_idx);

View File

@@ -7,6 +7,7 @@
#include "../stage0/spl_ir.h" #include "../stage0/spl_ir.h"
#include "spl_comp.h" #include "spl_comp.h"
#include "spl_lex_util.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>

View File

@@ -3,7 +3,7 @@
* 难度2/5 * 难度2/5
* 验证点for begin..end as i、for slice as val、for slice,0.. as val,idx * 验证点for begin..end as i、for slice as val、for slice,0.. as val,idx
*/ */
#[extern("vm")] fn vm_printf(fmt: *u8, ...) void; @extern(vm) fn vm_printf(fmt: *u8, ...) void;
fn main() i32 { fn main() i32 {
/* for 数值区间for 0..N as i */ /* for 数值区间for 0..N as i */

View File

@@ -3,7 +3,7 @@
* 难度3/5 * 难度3/5
* 验证点enum 定义、简单枚举值、带数据枚举变体 * 验证点enum 定义、简单枚举值、带数据枚举变体
*/ */
#[extern("vm")] fn vm_printf(fmt: *u8, ...) void; @extern(vm) fn vm_printf(fmt: *u8, ...) void;
type Color = enum { type Color = enum {
Red, Red,

View File

@@ -1,12 +1,12 @@
/* ===== 模块6函数 ===== /* ===== 模块6函数 =====
* test13_extern — 外部 VM 函数与字符串 * test13_extern — 外部 VM 函数与字符串
* 难度2/5 * 难度2/5
* 验证点:#[extern("vm")] 声明、vm_printf 调用、 * 验证点:@extern(vm) 声明、vm_printf 调用、
* 字符串字面量、字符串参数传递 * 字符串字面量、字符串参数传递
*/ */
#[extern("vm")] fn vm_printf(fmt: *u8, ...) void; @extern(vm) fn vm_printf(fmt: *u8, ...) void;
#[extern("vm")] fn vm_strlen(s: *i8) i32; @extern(vm) fn vm_strlen(s: *i8) i32;
#[extern("vm")] fn vm_strcmp(a: *i8, b: *i8) i32; @extern(vm) fn vm_strcmp(a: *i8, b: *i8) i32;
fn main() i32 { fn main() i32 {
/* vm_printf 输出测试 */ /* vm_printf 输出测试 */

View File

@@ -4,7 +4,7 @@
* 验证点defer 语句、defer 块、多个 defer逆序执行 * 验证点defer 语句、defer 块、多个 defer逆序执行
* 函数中 defer、块作用域 defer * 函数中 defer、块作用域 defer
*/ */
#[extern("vm")] fn vm_printf(fmt: *u8, ...) void; @extern(vm) fn vm_printf(fmt: *u8, ...) void;
fn with_cleanup() void { fn with_cleanup() void {
defer vm_printf(" inner defer\n"); defer vm_printf(" inner defer\n");

View File

@@ -3,7 +3,7 @@
* 难度3/5 * 难度3/5
* 验证点struct 方法、enum 方法、self 参数自动填充、方法调用 * 验证点struct 方法、enum 方法、self 参数自动填充、方法调用
*/ */
#[extern("vm")] fn vm_printf(fmt: *u8, ...) void; @extern(vm) fn vm_printf(fmt: *u8, ...) void;
type Point = struct { type Point = struct {
x: i32, x: i32,

View File

@@ -3,7 +3,7 @@
* 难度3/5 * 难度3/5
* 验证点:多特性组合——指针 + 结构体 + 函数 + 循环 + 数组 + 切片 * 验证点:多特性组合——指针 + 结构体 + 函数 + 循环 + 数组 + 切片
*/ */
#[extern("vm")] fn vm_printf(fmt: *u8, ...) void; @extern(vm) fn vm_printf(fmt: *u8, ...) void;
type Point = struct { type Point = struct {
x: i32, x: i32,