stage1 重构代码
This commit is contained in:
@@ -20,11 +20,11 @@ static void parse_ret_stmt(spl_comp_t *ctx) {
|
||||
if (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_R_BRACE ||
|
||||
peek(ctx)->type == TOK_ENDLINE) {
|
||||
/* void return */
|
||||
spl_emit(ctx, SPL_RET, SPL_VOID, 0);
|
||||
emit_return(&ctx->emit, &ctx->tctx, ctx->current_ret_type_idx);
|
||||
} else {
|
||||
spl_expr_result_t val = spl_parse_expr(ctx, PREC_MIN);
|
||||
(void)val;
|
||||
spl_emit_ret(ctx, ctx->current_ret_type);
|
||||
spl_emit_ret(ctx, ctx->current_ret_type_idx);
|
||||
}
|
||||
if (peek(ctx)->type == TOK_SEMICOLON)
|
||||
advance(ctx);
|
||||
@@ -42,7 +42,7 @@ static void parse_var_decl(spl_comp_t *ctx, int is_const) {
|
||||
char vname[256];
|
||||
spl_tok_copy_name(name_tok, vname, sizeof(vname));
|
||||
|
||||
spl_type_info_t *var_type = NULL;
|
||||
int var_type_idx = -1;
|
||||
int has_init = 0;
|
||||
|
||||
skip_nl(ctx);
|
||||
@@ -55,7 +55,7 @@ static void parse_var_decl(spl_comp_t *ctx, int is_const) {
|
||||
/* := is colon-assign */
|
||||
has_init = 1;
|
||||
} else {
|
||||
var_type = spl_parse_type(ctx);
|
||||
var_type_idx = spl_type_parse(&ctx->tctx, ctx);
|
||||
skip_nl(ctx);
|
||||
}
|
||||
}
|
||||
@@ -75,35 +75,37 @@ static void parse_var_decl(spl_comp_t *ctx, int is_const) {
|
||||
skip_nl(ctx);
|
||||
/* Inline struct/enum/slice literal: var x: Type = { .field = val }
|
||||
* Don't call spl_parse_expr — { would be consumed as block expression */
|
||||
if (var_type && peek(ctx)->type == TOK_L_BRACE &&
|
||||
(var_type->kind == TYPE_STRUCT || var_type->kind == TYPE_ENUM ||
|
||||
var_type->kind == TYPE_SLICE)) {
|
||||
if (var_type_idx >= 0 && peek(ctx)->type == TOK_L_BRACE &&
|
||||
(spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_STRUCT ||
|
||||
spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_ENUM ||
|
||||
spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_SLICE)) {
|
||||
inline_lit = 1;
|
||||
} else {
|
||||
init = spl_parse_expr(ctx, PREC_MIN);
|
||||
}
|
||||
}
|
||||
|
||||
if (!var_type) {
|
||||
var_type = init.type ? init.type : spl_type_basic(SPL_I32);
|
||||
if (var_type_idx < 0) {
|
||||
var_type_idx = init.type_idx >= 0 ? init.type_idx : spl_type_basic(&ctx->tctx, SPL_I32);
|
||||
}
|
||||
int offset = spl_declare_var(ctx, vname, var_type, is_const);
|
||||
int offset = spl_declare_var(ctx, vname, var_type_idx, is_const);
|
||||
|
||||
/* Store init value */
|
||||
if (has_init) {
|
||||
if (inline_lit && (var_type->kind == TYPE_STRUCT || var_type->kind == TYPE_ENUM ||
|
||||
var_type->kind == TYPE_SLICE)) {
|
||||
if (inline_lit && (spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_STRUCT ||
|
||||
spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_ENUM ||
|
||||
spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_SLICE)) {
|
||||
/* Inline struct/enum/slice literal: var x: Type = { .field = val }
|
||||
* Use spl_parse_struct_literal to handle field parsing uniformly. */
|
||||
spl_parse_struct_literal(ctx, var_type);
|
||||
if (var_type->kind == TYPE_SLICE) {
|
||||
spl_parse_struct_literal(ctx, var_type_idx);
|
||||
if (spl_type_kind(&ctx->tctx, var_type_idx) == TYPE_SLICE) {
|
||||
/* Slice: copy 2 temp slots to variable */
|
||||
spl_emit_copy_slots(ctx, offset, 2);
|
||||
emit_frame_copy(&ctx->emit, offset, 2);
|
||||
} else {
|
||||
spl_emit_store_init(ctx, offset, var_type);
|
||||
spl_emit_store_init(ctx, offset, var_type_idx);
|
||||
}
|
||||
} else {
|
||||
spl_emit_store_init(ctx, offset, var_type);
|
||||
spl_emit_store_init(ctx, offset, var_type_idx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,8 +184,9 @@ spl_expr_result_t spl_parse_block_expr(spl_comp_t *ctx) {
|
||||
skip_nl(ctx);
|
||||
if (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_ENDLINE) {
|
||||
/* Expression statement: drop value, consume ; */
|
||||
if (!is_assign && expr.type && spl_type_emit_type(expr.type) != SPL_VOID)
|
||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
|
||||
if (!is_assign && expr.type_idx >= 0 &&
|
||||
spl_type_emit_type(&ctx->tctx, expr.type_idx) != SPL_VOID)
|
||||
emit_drop(&ctx->emit);
|
||||
while (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_ENDLINE)
|
||||
advance(ctx);
|
||||
result = (spl_expr_result_t){0};
|
||||
@@ -211,21 +214,21 @@ static void parse_if_stmt(spl_comp_t *ctx) {
|
||||
spl_expr_result_t cond = spl_parse_expr(ctx, PREC_MIN);
|
||||
(void)cond;
|
||||
|
||||
spl_val_t bz_addr = spl_emit_bz(ctx);
|
||||
spl_val_t bz_addr = emit_bz_here(&ctx->emit);
|
||||
skip_nl(ctx);
|
||||
spl_parse_block(ctx);
|
||||
|
||||
spl_val_t jmp_addr = 0;
|
||||
skip_nl(ctx);
|
||||
if (peek(ctx)->type == KW_ELSE) {
|
||||
jmp_addr = spl_emit_jmp(ctx);
|
||||
spl_patch_to_here(ctx, bz_addr);
|
||||
jmp_addr = emit_jmp_here(&ctx->emit);
|
||||
emit_patch_here(&ctx->emit, bz_addr);
|
||||
advance(ctx); /* else */
|
||||
skip_nl(ctx);
|
||||
spl_parse_block(ctx);
|
||||
spl_patch_to_here(ctx, jmp_addr);
|
||||
emit_patch_here(&ctx->emit, jmp_addr);
|
||||
} else {
|
||||
spl_patch_to_here(ctx, bz_addr);
|
||||
emit_patch_here(&ctx->emit, bz_addr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,9 +254,9 @@ static void loop_enter(spl_comp_t *ctx, spl_loop_save_t *save) {
|
||||
|
||||
static void loop_exit(spl_comp_t *ctx, spl_loop_save_t *save) {
|
||||
spl_val_t here = vec_size(ctx->prog.insns);
|
||||
spl_emit(ctx, SPL_JMP, SPL_VOID, (spl_val_t)((isize)save->loop_start - (isize)here - 1));
|
||||
emit_jmp(&ctx->emit, (spl_val_t)((isize)save->loop_start - (isize)here - 1));
|
||||
for (usize i = save->saved_bp_count; i < ctx->break_patch_count; i++)
|
||||
spl_patch_to_here(ctx, ctx->break_patches[i]);
|
||||
emit_patch_here(&ctx->emit, ctx->break_patches[i]);
|
||||
ctx->break_patch_count = save->saved_bp_count;
|
||||
ctx->in_loop = save->saved_loop;
|
||||
ctx->continue_target = save->saved_continue;
|
||||
@@ -271,11 +274,11 @@ static void parse_while_stmt(spl_comp_t *ctx) {
|
||||
loop_enter(ctx, &save);
|
||||
spl_expr_result_t cond = spl_parse_expr(ctx, PREC_MIN);
|
||||
(void)cond;
|
||||
spl_val_t bz_addr = spl_emit_bz(ctx);
|
||||
spl_val_t bz_addr = emit_bz_here(&ctx->emit);
|
||||
skip_nl(ctx);
|
||||
spl_parse_block(ctx);
|
||||
loop_exit(ctx, &save);
|
||||
spl_patch_to_here(ctx, bz_addr);
|
||||
emit_patch_here(&ctx->emit, bz_addr);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
@@ -321,41 +324,39 @@ static void parse_for_stmt(spl_comp_t *ctx) {
|
||||
spl_tok_copy_name(ivar, iname, sizeof(iname));
|
||||
|
||||
spl_push_scope(ctx);
|
||||
int ioffset = spl_declare_var(ctx, iname, spl_type_basic(SPL_USIZE), 0);
|
||||
int ioffset = spl_declare_var(ctx, iname, spl_type_basic(&ctx->tctx, SPL_USIZE), 0);
|
||||
|
||||
/* Stack: [begin, end]; swap so TOS = begin */
|
||||
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
|
||||
emit_swap(&ctx->emit);
|
||||
/* Store begin to i */
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, ioffset);
|
||||
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
|
||||
spl_emit(ctx, SPL_STORE, SPL_USIZE, 0);
|
||||
emit_store_to_laddr(&ctx->emit, ioffset, SPL_USIZE);
|
||||
/* Stack: [end] */
|
||||
|
||||
/* Condition: i < end */
|
||||
spl_loop_save_t save;
|
||||
loop_enter(ctx, &save);
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, ioffset);
|
||||
spl_emit(ctx, SPL_LOAD, SPL_USIZE, 0);
|
||||
spl_emit(ctx, SPL_PICK, SPL_VOID, 1);
|
||||
spl_emit(ctx, SPL_ULT, SPL_USIZE, 0);
|
||||
spl_val_t bz_addr = spl_emit_bz(ctx);
|
||||
emit_laddr(&ctx->emit, ioffset);
|
||||
emit_load_usize(&ctx->emit);
|
||||
emit_pick(&ctx->emit, 1);
|
||||
emit_ult_usize(&ctx->emit);
|
||||
spl_val_t bz_addr = emit_bz_here(&ctx->emit);
|
||||
|
||||
skip_nl(ctx);
|
||||
spl_parse_block(ctx); /* body */
|
||||
|
||||
/* Increment: i = i + 1 */
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, ioffset);
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, ioffset);
|
||||
spl_emit(ctx, SPL_LOAD, SPL_USIZE, 0);
|
||||
spl_emit(ctx, SPL_PUSH, SPL_USIZE, 1);
|
||||
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
|
||||
spl_emit(ctx, SPL_STORE, SPL_USIZE, 0);
|
||||
emit_laddr(&ctx->emit, ioffset);
|
||||
emit_laddr(&ctx->emit, ioffset);
|
||||
emit_load_usize(&ctx->emit);
|
||||
emit_push_usize(&ctx->emit, 1);
|
||||
emit_add_usize(&ctx->emit);
|
||||
emit_store_usize(&ctx->emit);
|
||||
|
||||
loop_exit(ctx, &save);
|
||||
|
||||
/* Exit: patch bz, drop end */
|
||||
spl_patch_to_here(ctx, bz_addr);
|
||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
|
||||
emit_patch_here(&ctx->emit, bz_addr);
|
||||
emit_drop(&ctx->emit);
|
||||
|
||||
spl_emit_defer_epilogue(ctx, ctx->scope_depth);
|
||||
spl_pop_scope(ctx);
|
||||
@@ -375,7 +376,7 @@ static void parse_for_stmt(spl_comp_t *ctx) {
|
||||
spl_parse_expr(ctx, PREC_MIN);
|
||||
}
|
||||
/* Range pushed a value; we manage our own idx, drop it */
|
||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
|
||||
emit_drop(&ctx->emit);
|
||||
}
|
||||
|
||||
if (peek(ctx)->type != KW_AS) {
|
||||
@@ -403,82 +404,78 @@ static void parse_for_stmt(spl_comp_t *ctx) {
|
||||
|
||||
int idx_offset = -1;
|
||||
if (iname[0])
|
||||
idx_offset = spl_declare_var(ctx, iname, spl_type_basic(SPL_USIZE), 0);
|
||||
idx_offset = spl_declare_var(ctx, iname, spl_type_basic(&ctx->tctx, SPL_USIZE), 0);
|
||||
|
||||
spl_type_info_t *elem_type = NULL;
|
||||
if (start_expr.type) {
|
||||
if (start_expr.type->kind == TYPE_SLICE)
|
||||
elem_type = start_expr.type->elem;
|
||||
else if (start_expr.type->kind == TYPE_PTR && start_expr.type->elem)
|
||||
elem_type = start_expr.type->elem;
|
||||
int elem_type_idx = -1;
|
||||
if (start_expr.type_idx >= 0) {
|
||||
if (spl_type_kind(&ctx->tctx, start_expr.type_idx) == TYPE_SLICE)
|
||||
elem_type_idx = spl_type_elem_type(&ctx->tctx, start_expr.type_idx);
|
||||
else if (spl_type_kind(&ctx->tctx, start_expr.type_idx) == TYPE_PTR &&
|
||||
spl_type_elem_type(&ctx->tctx, start_expr.type_idx) >= 0)
|
||||
elem_type_idx = spl_type_elem_type(&ctx->tctx, start_expr.type_idx);
|
||||
}
|
||||
if (!elem_type)
|
||||
elem_type = spl_type_basic(SPL_I32);
|
||||
int val_offset = spl_declare_var(ctx, vname, elem_type, 0);
|
||||
if (elem_type_idx < 0)
|
||||
elem_type_idx = spl_type_basic(&ctx->tctx, SPL_I32);
|
||||
int val_offset = spl_declare_var(ctx, vname, elem_type_idx, 0);
|
||||
|
||||
/* Extract ptr and len from slice, push index=0: stack [ptr, len, idx] */
|
||||
spl_emit(ctx, SPL_DUP, SPL_VOID, 0);
|
||||
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
|
||||
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
|
||||
spl_emit(ctx, SPL_PUSH, SPL_U64, sizeof(spl_val_t));
|
||||
spl_emit(ctx, SPL_ADD, SPL_U64, 0);
|
||||
spl_emit(ctx, SPL_LOAD, SPL_USIZE, 0);
|
||||
spl_emit(ctx, SPL_PUSH, SPL_USIZE, 0);
|
||||
emit_dup(&ctx->emit);
|
||||
emit_load_ptr(&ctx->emit);
|
||||
emit_swap(&ctx->emit);
|
||||
emit_ptr_add(&ctx->emit, sizeof(spl_val_t));
|
||||
emit_load_usize(&ctx->emit);
|
||||
emit_push_usize(&ctx->emit, 0);
|
||||
/* Stack: [ptr, len, idx=0] */
|
||||
|
||||
spl_loop_save_t save;
|
||||
loop_enter(ctx, &save);
|
||||
|
||||
/* Condition: idx < len */
|
||||
spl_emit(ctx, SPL_PICK, SPL_VOID, 1); /* copy len */
|
||||
spl_emit(ctx, SPL_PICK, SPL_VOID, 1); /* copy idx */
|
||||
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); /* [idx, len] → [len, idx] → SWAP → [idx, len] */
|
||||
spl_emit(ctx, SPL_ULT, SPL_USIZE, 0);
|
||||
spl_val_t bz_addr = spl_emit_bz(ctx);
|
||||
emit_pick(&ctx->emit, 1); /* copy len */
|
||||
emit_pick(&ctx->emit, 1); /* copy idx */
|
||||
emit_swap(&ctx->emit); /* [idx, len] → [len, idx] → SWAP → [idx, len] */
|
||||
emit_ult_usize(&ctx->emit);
|
||||
spl_val_t bz_addr = emit_bz_here(&ctx->emit);
|
||||
|
||||
/* Store current idx to idx variable */
|
||||
if (idx_offset >= 0) {
|
||||
spl_emit(ctx, SPL_PICK, SPL_VOID, 0); /* copy idx (TOS) */
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, idx_offset);
|
||||
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
|
||||
spl_emit(ctx, SPL_STORE, SPL_USIZE, 0);
|
||||
emit_pick(&ctx->emit, 0); /* copy idx (TOS) */
|
||||
emit_store_to_laddr(&ctx->emit, idx_offset, SPL_USIZE);
|
||||
}
|
||||
|
||||
/* Load slice[idx] and store to val */
|
||||
spl_emit(ctx, SPL_PICK, SPL_VOID, 2); /* copy ptr: [ptr, len, idx, ptr] */
|
||||
spl_emit(ctx, SPL_PICK, SPL_VOID, 1); /* copy idx: [ptr, len, idx, ptr, idx] */
|
||||
usize elem_byte_size = elem_type ? spl_type_size(elem_type) : 4;
|
||||
spl_emit(ctx, SPL_PUSH, SPL_U64, elem_byte_size);
|
||||
spl_emit(ctx, SPL_MUL, SPL_U64, 0);
|
||||
spl_emit(ctx, SPL_ADD, SPL_U64, 0);
|
||||
if (elem_type && !spl_type_is_scalar(elem_type) &&
|
||||
spl_type_size(elem_type) > sizeof(spl_val_t)) {
|
||||
spl_emit_copy_slots(ctx, val_offset, spl_type_slot_count(elem_type));
|
||||
emit_pick(&ctx->emit, 2); /* copy ptr: [ptr, len, idx, ptr] */
|
||||
emit_pick(&ctx->emit, 1); /* copy idx: [ptr, len, idx, ptr, idx] */
|
||||
usize elem_byte_size = elem_type_idx >= 0 ? spl_type_size(&ctx->tctx, elem_type_idx) : 4;
|
||||
emit_push_u64(&ctx->emit, elem_byte_size);
|
||||
emit_mul_u64(&ctx->emit);
|
||||
emit_add_u64(&ctx->emit);
|
||||
if (elem_type_idx >= 0 && !spl_type_is_scalar(&ctx->tctx, elem_type_idx) &&
|
||||
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));
|
||||
} else {
|
||||
spl_type_t elem_bt = elem_type ? spl_type_emit_type(elem_type) : SPL_I32;
|
||||
spl_emit(ctx, SPL_LOAD, elem_bt, 0);
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, val_offset);
|
||||
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
|
||||
spl_emit(ctx, SPL_STORE, elem_bt, 0);
|
||||
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_store_to_laddr(&ctx->emit, val_offset, elem_bt);
|
||||
}
|
||||
|
||||
skip_nl(ctx);
|
||||
spl_parse_block(ctx); /* body */
|
||||
|
||||
/* Increment idx */
|
||||
spl_emit(ctx, SPL_PICK, SPL_VOID, 0); /* copy idx */
|
||||
spl_emit(ctx, SPL_PUSH, SPL_USIZE, 1);
|
||||
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
|
||||
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
|
||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* replace old idx with new */
|
||||
emit_pick(&ctx->emit, 0); /* copy idx */
|
||||
emit_push_usize(&ctx->emit, 1);
|
||||
emit_add_usize(&ctx->emit);
|
||||
emit_swap(&ctx->emit);
|
||||
emit_drop(&ctx->emit); /* replace old idx with new */
|
||||
|
||||
loop_exit(ctx, &save);
|
||||
|
||||
/* Exit: patch bz, drop idx, len, ptr */
|
||||
spl_patch_to_here(ctx, bz_addr);
|
||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* drop idx */
|
||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* drop len */
|
||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* drop ptr */
|
||||
emit_patch_here(&ctx->emit, bz_addr);
|
||||
emit_drop(&ctx->emit); /* drop idx */
|
||||
emit_drop(&ctx->emit); /* drop len */
|
||||
emit_drop(&ctx->emit); /* drop ptr */
|
||||
|
||||
spl_pop_scope(ctx);
|
||||
}
|
||||
@@ -493,7 +490,7 @@ static void parse_break_stmt(spl_comp_t *ctx) {
|
||||
spl_comp_error(ctx, "break outside loop");
|
||||
}
|
||||
/* Emit JMP with placeholder, add to patch list */
|
||||
spl_val_t addr = spl_emit_jmp(ctx);
|
||||
spl_val_t addr = emit_jmp_here(&ctx->emit);
|
||||
if (ctx->break_patch_cap <= ctx->break_patch_count) {
|
||||
usize new_cap = ctx->break_patch_cap ? ctx->break_patch_cap * 2 : 8;
|
||||
ctx->break_patches = realloc(ctx->break_patches, new_cap * sizeof(usize));
|
||||
@@ -511,7 +508,7 @@ static void parse_continue_stmt(spl_comp_t *ctx) {
|
||||
}
|
||||
/* Emit JMP with relative offset to continue_target */
|
||||
spl_val_t here = vec_size(ctx->prog.insns);
|
||||
spl_emit(ctx, SPL_JMP, SPL_VOID, (spl_val_t)((isize)ctx->continue_target - (isize)here - 1));
|
||||
emit_jmp(&ctx->emit, (spl_val_t)((isize)ctx->continue_target - (isize)here - 1));
|
||||
if (peek(ctx)->type == TOK_SEMICOLON)
|
||||
advance(ctx);
|
||||
}
|
||||
@@ -537,7 +534,7 @@ static void parse_defer_stmt(spl_comp_t *ctx) {
|
||||
/* Emit JMP exit placeholder — will be patched at scope exit */
|
||||
if (ctx->defer_count > 0) {
|
||||
spl_defer_entry_t *e = &ctx->defer_stack[ctx->defer_count - 1];
|
||||
e->jmp_exit = spl_emit_jmp(ctx);
|
||||
e->jmp_exit = emit_jmp_here(&ctx->emit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -547,10 +544,10 @@ static void parse_defer_stmt(spl_comp_t *ctx) {
|
||||
|
||||
/* Parse an enum variant pattern in a match arm: .VariantName
|
||||
* Delegates comparison to expr layer (spl_emit_match_enum_cmp).
|
||||
* Returns the variant for binding parsing, or NULL on error. */
|
||||
static spl_enum_variant_t *parse_match_enum_variant(spl_comp_t *ctx, spl_type_info_t *enum_type,
|
||||
int val_offset, int by_value) {
|
||||
return spl_emit_match_enum_cmp(ctx, enum_type, val_offset, by_value);
|
||||
* Returns the variant item index, or -1 on error. */
|
||||
static int parse_match_enum_variant(spl_comp_t *ctx, int enum_type_idx,
|
||||
int val_offset, int by_value) {
|
||||
return spl_emit_match_enum_cmp(ctx, enum_type_idx, val_offset, by_value);
|
||||
}
|
||||
|
||||
/* Parse a value pattern in a match arm (non-enum).
|
||||
@@ -564,7 +561,8 @@ static void parse_match_value_pattern(spl_comp_t *ctx, int val_offset) {
|
||||
* Declares local variables and loads corresponding field data
|
||||
* from the matched value's data area (offset 4+).
|
||||
* Sets *scope_pushed = 1 if bindings declared. */
|
||||
static void parse_match_enum_bindings(spl_comp_t *ctx, spl_enum_variant_t *variant, int val_offset,
|
||||
static void parse_match_enum_bindings(spl_comp_t *ctx, int enum_type_idx,
|
||||
int variant_item_idx, int val_offset,
|
||||
int *scope_pushed) {
|
||||
advance(ctx); /* ( */
|
||||
skip_nl(ctx);
|
||||
@@ -576,22 +574,36 @@ static void parse_match_enum_bindings(spl_comp_t *ctx, spl_enum_variant_t *varia
|
||||
spl_push_scope(ctx);
|
||||
*scope_pushed = 1;
|
||||
|
||||
if (variant->data_type && variant->data_type->kind == TYPE_STRUCT) {
|
||||
spl_type_item_t *var_item = spl_type_item_at(&ctx->tctx, enum_type_idx, variant_item_idx);
|
||||
int data_type_idx = var_item ? var_item->enum_field.type_idx : -1;
|
||||
|
||||
if (data_type_idx >= 0 && spl_type_kind(&ctx->tctx, data_type_idx) == TYPE_STRUCT) {
|
||||
/* Multi-field struct destructuring: one binding per struct field */
|
||||
spl_type_item_vec_t *data_items = spl_type_items(&ctx->tctx, data_type_idx);
|
||||
int bi = 0;
|
||||
for (;;) {
|
||||
spl_tok_t *btok = advance(ctx);
|
||||
char bname[256];
|
||||
spl_tok_copy_name(btok, bname, sizeof(bname));
|
||||
|
||||
spl_type_info_t *btype = spl_type_basic(SPL_I32);
|
||||
usize field_byte_off = 4; /* skip tag */
|
||||
if ((usize)bi < vec_size(variant->data_type->fields)) {
|
||||
btype = vec_at(variant->data_type->fields, bi).type;
|
||||
field_byte_off = 4 + vec_at(variant->data_type->fields, bi).offset;
|
||||
int btype_idx = spl_type_basic(&ctx->tctx, SPL_I32);
|
||||
usize field_byte_off = ENUM_TAG_SIZE; /* skip tag */
|
||||
{
|
||||
int fcount = 0;
|
||||
vec_for(*data_items, di) {
|
||||
spl_type_item_t *fit = &vec_at(*data_items, di);
|
||||
if (fit->item_kind == ITEM_FIELD) {
|
||||
if (fcount == bi) {
|
||||
btype_idx = fit->aggregate_field.type_idx;
|
||||
field_byte_off = ENUM_TAG_SIZE + fit->aggregate_field.offset;
|
||||
break;
|
||||
}
|
||||
fcount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
int boffset = spl_declare_var(ctx, bname, btype, 0);
|
||||
spl_emit_load_to_var(ctx, val_offset, field_byte_off, btype, boffset);
|
||||
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);
|
||||
|
||||
bi++;
|
||||
skip_nl(ctx);
|
||||
@@ -602,15 +614,14 @@ static void parse_match_enum_bindings(spl_comp_t *ctx, spl_enum_variant_t *varia
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (variant->data_type) {
|
||||
} else if (data_type_idx >= 0) {
|
||||
/* Single-value binding */
|
||||
spl_tok_t *btok = advance(ctx);
|
||||
char bname[256];
|
||||
spl_tok_copy_name(btok, bname, sizeof(bname));
|
||||
|
||||
spl_type_info_t *btype = variant->data_type;
|
||||
int boffset = spl_declare_var(ctx, bname, btype, 0);
|
||||
spl_emit_load_to_var(ctx, val_offset, 4, btype, boffset);
|
||||
int boffset = spl_declare_var(ctx, bname, data_type_idx, 0);
|
||||
emit_load_to_var(&ctx->emit, &ctx->tctx, val_offset, ENUM_TAG_SIZE, data_type_idx, boffset);
|
||||
}
|
||||
|
||||
expect(ctx, TOK_R_PAREN);
|
||||
@@ -633,37 +644,36 @@ static void parse_match_stmt(spl_comp_t *ctx) {
|
||||
|
||||
/* Determine match type */
|
||||
int is_enum_match = 0;
|
||||
spl_type_info_t *enum_type = NULL;
|
||||
spl_type_info_t *t = expr.type;
|
||||
if (t && t->kind == TYPE_ENUM) {
|
||||
int enum_type_idx = -1;
|
||||
int type_idx = expr.type_idx;
|
||||
if (type_idx >= 0 && spl_type_kind(&ctx->tctx, type_idx) == TYPE_ENUM) {
|
||||
is_enum_match = 1;
|
||||
enum_type = t;
|
||||
} else if (t && t->kind == TYPE_PTR && t->elem && t->elem->kind == TYPE_ENUM) {
|
||||
enum_type_idx = type_idx;
|
||||
} else if (type_idx >= 0 && spl_type_kind(&ctx->tctx, type_idx) == TYPE_PTR &&
|
||||
spl_type_elem_type(&ctx->tctx, type_idx) >= 0 &&
|
||||
spl_type_kind(&ctx->tctx, spl_type_elem_type(&ctx->tctx, type_idx)) == TYPE_ENUM) {
|
||||
is_enum_match = 1;
|
||||
enum_type = t->elem;
|
||||
} else if (!(t && t->kind == TYPE_BASIC && spl_type_is_integer(t->basic_type))) {
|
||||
enum_type_idx = spl_type_elem_type(&ctx->tctx, type_idx);
|
||||
} else if (!(type_idx >= 0 && spl_type_kind(&ctx->tctx, type_idx) == TYPE_BASIC &&
|
||||
spl_type_is_integer(spl_type_basic_type(&ctx->tctx, type_idx)))) {
|
||||
spl_comp_error(ctx, "match expression must be an enum or integer type");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Scalar enums store the raw tag directly; others store a pointer */
|
||||
int match_by_value = (t && t->kind == TYPE_ENUM && spl_type_is_scalar(t));
|
||||
int match_by_value = (type_idx >= 0 && spl_type_kind(&ctx->tctx, type_idx) == TYPE_ENUM &&
|
||||
spl_type_is_scalar(&ctx->tctx, type_idx));
|
||||
|
||||
/* Save match value to temp slot */
|
||||
int val_offset = ctx->current_local_bytes;
|
||||
ctx->current_local_bytes += (int)sizeof(spl_val_t);
|
||||
if (ctx->current_local_bytes > ctx->peak_local_bytes)
|
||||
ctx->peak_local_bytes = ctx->current_local_bytes;
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, val_offset);
|
||||
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
|
||||
spl_emit(ctx, SPL_STORE, spl_type_emit_type(t), 0);
|
||||
int val_offset = fa_alloc_temp(&ctx->emit.frame, 1);
|
||||
emit_store_to_laddr(&ctx->emit, val_offset, spl_type_emit_type(&ctx->tctx, type_idx));
|
||||
|
||||
skip_nl(ctx);
|
||||
if (peek(ctx)->type == TOK_L_BRACE)
|
||||
advance(ctx); /* { */
|
||||
|
||||
/* Collect JMP-to-end addresses for patching */
|
||||
enum { MAX_MATCH_ARMS = 32 };
|
||||
enum { MAX_MATCH_ARMS = 128 };
|
||||
spl_val_t jmp_to_end[MAX_MATCH_ARMS];
|
||||
int n_jmps = 0;
|
||||
|
||||
@@ -680,9 +690,9 @@ static void parse_match_stmt(spl_comp_t *ctx) {
|
||||
int scope_pushed = 0;
|
||||
int has_parens = 0;
|
||||
spl_val_t body_start = 0;
|
||||
spl_val_t bnz_addrs[16];
|
||||
spl_val_t bnz_addrs[128];
|
||||
int n_bnz = 0;
|
||||
spl_enum_variant_t *arm_variant = NULL;
|
||||
int arm_variant_item = -1;
|
||||
|
||||
/* --- Parse arm pattern(s): comma-separated with fallthrough --- */
|
||||
if (peek(ctx)->type == KW_ANY) {
|
||||
@@ -691,8 +701,8 @@ static void parse_match_stmt(spl_comp_t *ctx) {
|
||||
} else {
|
||||
for (;;) {
|
||||
if (is_enum_match) {
|
||||
arm_variant =
|
||||
parse_match_enum_variant(ctx, enum_type, val_offset, match_by_value);
|
||||
arm_variant_item =
|
||||
parse_match_enum_variant(ctx, enum_type_idx, val_offset, match_by_value);
|
||||
if (ctx->has_error)
|
||||
break;
|
||||
skip_nl(ctx);
|
||||
@@ -710,7 +720,8 @@ static void parse_match_stmt(spl_comp_t *ctx) {
|
||||
advance(ctx);
|
||||
skip_nl(ctx);
|
||||
if (peek(ctx)->type != TOK_ASSIGN) {
|
||||
bnz_addrs[n_bnz++] = spl_emit_bnz(ctx); /* fallthrough to body */
|
||||
if (n_bnz < 128)
|
||||
bnz_addrs[n_bnz++] = emit_bnz_here(&ctx->emit); /* fallthrough to body */
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@@ -720,14 +731,15 @@ static void parse_match_stmt(spl_comp_t *ctx) {
|
||||
|
||||
/* Last pattern: BZ past body if no match */
|
||||
if (!ctx->has_error) {
|
||||
bz_addr = spl_emit_bz(ctx);
|
||||
bz_addr = emit_bz_here(&ctx->emit);
|
||||
body_start = vec_size(ctx->prog.insns);
|
||||
}
|
||||
}
|
||||
|
||||
/* --- Parse enum bindings (only for last variant) --- */
|
||||
if (is_enum_match && has_parens && arm_variant) {
|
||||
parse_match_enum_bindings(ctx, arm_variant, val_offset, &scope_pushed);
|
||||
if (is_enum_match && has_parens && arm_variant_item >= 0) {
|
||||
parse_match_enum_bindings(ctx, enum_type_idx, arm_variant_item,
|
||||
val_offset, &scope_pushed);
|
||||
}
|
||||
|
||||
skip_nl(ctx);
|
||||
@@ -751,16 +763,16 @@ static void parse_match_stmt(spl_comp_t *ctx) {
|
||||
|
||||
/* JMP to end (skip remaining arms) */
|
||||
if (n_jmps < MAX_MATCH_ARMS)
|
||||
jmp_to_end[n_jmps++] = spl_emit_jmp(ctx);
|
||||
jmp_to_end[n_jmps++] = emit_jmp_here(&ctx->emit);
|
||||
|
||||
/* Patch BZ to here (next arm or end) */
|
||||
if (bz_addr)
|
||||
spl_patch_to_here(ctx, bz_addr);
|
||||
emit_patch_here(&ctx->emit, bz_addr);
|
||||
|
||||
/* Patch BNZ fallthroughs to body start */
|
||||
for (int i = 0; i < n_bnz; i++) {
|
||||
spl_val_t offset = body_start - bnz_addrs[i] - 1;
|
||||
spl_patch(ctx, bnz_addrs[i], offset);
|
||||
emit_patch(&ctx->emit, bnz_addrs[i], offset);
|
||||
}
|
||||
|
||||
skip_nl(ctx);
|
||||
@@ -770,10 +782,10 @@ static void parse_match_stmt(spl_comp_t *ctx) {
|
||||
|
||||
/* Patch all JMPs to end */
|
||||
for (int i = 0; i < n_jmps; i++)
|
||||
spl_patch_to_here(ctx, jmp_to_end[i]);
|
||||
emit_patch_here(&ctx->emit, jmp_to_end[i]);
|
||||
|
||||
/* Release temp slot */
|
||||
ctx->current_local_bytes -= (int)sizeof(spl_val_t);
|
||||
fa_free(&ctx->emit.frame, val_offset);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
@@ -811,7 +823,7 @@ static void parse_extern_decl(spl_comp_t *ctx) {
|
||||
if (peek(ctx)->type == TOK_COLON) {
|
||||
advance(ctx); /* : */
|
||||
skip_nl(ctx);
|
||||
spl_parse_type(ctx); /* skip type */
|
||||
spl_type_parse(&ctx->tctx, ctx); /* skip type */
|
||||
}
|
||||
nparams++;
|
||||
skip_nl(ctx);
|
||||
@@ -831,15 +843,15 @@ static void parse_extern_decl(spl_comp_t *ctx) {
|
||||
skip_nl(ctx);
|
||||
|
||||
/* Return type */
|
||||
spl_type_info_t *ret_type = spl_type_basic(SPL_VOID);
|
||||
int ret_type_idx = spl_type_basic(&ctx->tctx, SPL_VOID);
|
||||
if (peek(ctx)->type != TOK_SEMICOLON && peek(ctx)->type != TOK_L_BRACE) {
|
||||
ret_type = spl_parse_type(ctx);
|
||||
if (!ret_type)
|
||||
ret_type = spl_type_basic(SPL_VOID);
|
||||
ret_type_idx = spl_type_parse(&ctx->tctx, ctx);
|
||||
if (ret_type_idx < 0)
|
||||
ret_type_idx = spl_type_basic(&ctx->tctx, SPL_VOID);
|
||||
skip_nl(ctx);
|
||||
}
|
||||
|
||||
spl_declare_func(ctx, fn_name, ret_type, nparams, 1, 0);
|
||||
spl_declare_func(ctx, fn_name, ret_type_idx, nparams, 1, 0);
|
||||
|
||||
if (peek(ctx)->type == TOK_SEMICOLON)
|
||||
advance(ctx);
|
||||
@@ -895,8 +907,9 @@ static void parse_expr_stmt(spl_comp_t *ctx) {
|
||||
if (is_assign)
|
||||
ctx->addr_of_mode = 0;
|
||||
|
||||
if (!is_assign && expr.type && spl_type_emit_type(expr.type) != SPL_VOID)
|
||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
|
||||
if (!is_assign && expr.type_idx >= 0 &&
|
||||
spl_type_emit_type(&ctx->tctx, expr.type_idx) != SPL_VOID)
|
||||
emit_drop(&ctx->emit);
|
||||
if (peek(ctx)->type == TOK_SEMICOLON)
|
||||
advance(ctx);
|
||||
/* Safety: if no token was consumed, advance to prevent infinite loop */
|
||||
|
||||
Reference in New Issue
Block a user