stage1 优化代码 完成16测试

This commit is contained in:
zzy
2026-07-07 10:40:30 +08:00
parent 69cea030dc
commit 3cf11f922e
14 changed files with 849 additions and 228 deletions

View File

@@ -1,34 +1,10 @@
/* spl_stmt.c — Statement parser + codegen */
#include "spl_comp.h"
#include "spl_lex_util.h"
#include <stdlib.h>
#include <string.h>
/* Token helpers — using shared peek/advance from spl_parser.c */
static int expect(spl_comp_t *ctx, spl_tok_type_t type) {
if (peek(ctx)->type == type) {
advance(ctx);
return 1;
}
spl_comp_error(ctx, "expected '%s', got '%s'", spl_tok_type_name(type),
spl_tok_type_name(peek(ctx)->type));
return 0;
}
static int match(spl_comp_t *ctx, spl_tok_type_t type) {
if (peek(ctx)->type == type) {
advance(ctx);
return 1;
}
return 0;
}
static void skip_nl(spl_comp_t *ctx) {
while (peek(ctx)->type == TOK_ENDLINE)
advance(ctx);
}
/* ============================================================
* Return statement: ret expr;
* ============================================================ */
@@ -49,7 +25,17 @@ static void parse_ret_stmt(spl_comp_t *ctx) {
} else {
spl_expr_result_t val = spl_parse_expr(ctx, PREC_MIN);
(void)val;
spl_type_t rt = ctx->current_ret_type ? ctx->current_ret_type->basic_type : SPL_VOID;
spl_type_t rt = SPL_VOID;
if (ctx->current_ret_type) {
if (ctx->current_ret_type->kind == TYPE_BASIC) {
rt = ctx->current_ret_type->basic_type;
} else if (ctx->current_ret_type->kind == TYPE_PTR) {
rt = SPL_PTR;
} else if (spl_type_slot_count(ctx->current_ret_type) == 1) {
/* 1-slot struct/enum/etc: use PTR type */
rt = SPL_PTR;
}
}
spl_emit(ctx, SPL_RET, rt, 0);
}
if (peek(ctx)->type == TOK_SEMICOLON)
@@ -96,19 +82,44 @@ static void parse_var_decl(spl_comp_t *ctx, int is_const) {
advance(ctx); /* = */
}
/* Allocate stack slot */
if (!var_type)
var_type = spl_type_basic(SPL_I32); /* default type */
/* Init expression: parse before declare to enable type inference */
spl_expr_result_t init = {0};
if (has_init) {
skip_nl(ctx);
init = spl_parse_expr(ctx, PREC_MIN);
}
if (!var_type) {
var_type = init.type ? init.type : spl_type_basic(SPL_I32);
}
int slot = spl_declare_var(ctx, vname, var_type, is_const);
skip_nl(ctx);
/* Init expression */
/* Store init value */
if (has_init) {
spl_expr_result_t init = spl_parse_expr(ctx, PREC_MIN);
(void)init;
if (var_type && var_type->kind == TYPE_ARRAY) {
if (var_type && (var_type->kind == TYPE_STRUCT || var_type->kind == TYPE_ENUM)) {
/* Struct/enum initialization */
usize sc = spl_type_slot_count(var_type);
if (sc == 1) {
/* Single-slot: value on stack, store directly */
spl_emit(ctx, SPL_LADDR, SPL_PTR, slot);
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
spl_emit(ctx, SPL_STORE, SPL_PTR, 0);
} else {
/* Multi-slot: copy from temp addr to var slots */
for (usize i = 0; i < sc; i++) {
if (i < sc - 1)
spl_emit(ctx, SPL_DUP, SPL_VOID, 0);
if (i > 0) {
spl_emit(ctx, SPL_PUSH, SPL_USIZE, i * sizeof(spl_val_t));
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
}
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
spl_emit(ctx, SPL_LADDR, SPL_PTR, slot + (int)i);
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
spl_emit(ctx, SPL_STORE, SPL_PTR, 0);
}
}
} else if (var_type && var_type->kind == TYPE_ARRAY) {
/* Array initialization: store each element in reverse stack order */
spl_type_info_t *elem = var_type->elem;
spl_type_t bt = (elem && elem->kind == TYPE_BASIC) ? elem->basic_type : SPL_I32;
@@ -544,6 +555,211 @@ static void parse_defer_stmt(spl_comp_t *ctx) {
}
}
/* ============================================================
* Match statement: match expr { .Variant(bindings) => stmt, ... }
* ============================================================ */
static void parse_match_stmt(spl_comp_t *ctx) {
advance(ctx); /* match */
skip_nl(ctx);
spl_expr_result_t expr = spl_parse_expr(ctx, PREC_MIN);
/* Determine the enum type (deref pointer if needed) */
spl_type_info_t *enum_type = expr.type;
if (enum_type && enum_type->kind == TYPE_PTR && enum_type->elem &&
enum_type->elem->kind == TYPE_ENUM) {
enum_type = enum_type->elem;
}
if (!enum_type || enum_type->kind != TYPE_ENUM) {
spl_comp_error(ctx, "match expression must be an enum");
return;
}
/* Save the enum address (pointer value) to a temp slot */
int addr_slot = ctx->current_local_slot;
ctx->current_local_slot++;
spl_emit(ctx, SPL_LADDR, SPL_PTR, addr_slot);
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
spl_emit(ctx, SPL_STORE, SPL_PTR, 0);
skip_nl(ctx);
if (peek(ctx)->type == TOK_L_BRACE)
advance(ctx); /* { */
/* Collect JMP-to-end addresses for patching */
enum { MAX_MATCH_ARMS = 32 };
spl_val_t jmp_to_end[MAX_MATCH_ARMS];
int n_jmps = 0;
skip_nl(ctx);
while (peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) {
skip_nl(ctx);
if (peek(ctx)->type == TOK_COMMA) {
advance(ctx);
skip_nl(ctx);
continue;
}
/* Parse .VariantName */
if (peek(ctx)->type == TOK_DOT)
advance(ctx);
spl_tok_t *vtok = advance(ctx);
char vname[256];
usize vnl = vtok->len < 255 ? vtok->len : 255;
memcpy(vname, vtok->lexeme, vnl);
vname[vnl] = '\0';
/* Find the variant in the enum type */
spl_enum_variant_t *variant = NULL;
int vi;
vec_for(enum_type->variants, vi) {
if (strcmp(vec_at(enum_type->variants, vi).name, vname) == 0) {
variant = &vec_at(enum_type->variants, vi);
break;
}
}
if (!variant) {
spl_comp_error(ctx, "unknown variant '%s' in match", vname);
break;
}
/* Compare tag: load [addr_slot+0] == variant->value */
/* Load tag and compare */
spl_emit(ctx, SPL_LADDR, SPL_PTR, addr_slot);
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
spl_emit(ctx, SPL_PUSH, SPL_USIZE, 0);
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
spl_emit(ctx, SPL_LOAD, SPL_I32, 0);
spl_emit(ctx, SPL_PUSH, SPL_I32, variant->value);
spl_emit(ctx, SPL_EQ, SPL_I32, 0);
spl_val_t bz_addr = spl_emit_bz(ctx);
/* This arm matches — parse bindings and body */
skip_nl(ctx);
/* Parse binding list: (name, name, ...) */
int has_parens = 0;
if (peek(ctx)->type == TOK_L_PAREN) {
has_parens = 1;
advance(ctx); /* ( */
skip_nl(ctx);
}
/* Push scope for bindings if there are any */
int scope_pushed = 0;
if (has_parens && peek(ctx)->type != TOK_R_PAREN) {
spl_push_scope(ctx);
scope_pushed = 1;
if (variant->data_type && variant->data_type->kind == TYPE_STRUCT) {
/* Struct data: each struct field is a binding */
int bi = 0;
for (;;) {
spl_tok_t *btok = advance(ctx);
char bname[256];
usize bnl = btok->len < 255 ? btok->len : 255;
memcpy(bname, btok->lexeme, bnl);
bname[bnl] = '\0';
spl_type_info_t *btype = spl_type_basic(SPL_I32);
usize field_byte_off = 4;
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 bslot = spl_declare_var(ctx, bname, btype, 0);
/* Load from enum data and store to variable */
spl_emit(ctx, SPL_LADDR, SPL_PTR, addr_slot);
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
spl_emit(ctx, SPL_PUSH, SPL_USIZE, field_byte_off);
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
spl_type_t bt = (btype->kind == TYPE_BASIC) ? btype->basic_type
: (btype->kind == TYPE_PTR) ? SPL_PTR
: SPL_I32;
spl_emit(ctx, SPL_LOAD, bt, 0);
spl_emit(ctx, SPL_LADDR, SPL_PTR, bslot);
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
spl_emit(ctx, SPL_STORE, bt, 0);
bi++;
skip_nl(ctx);
if (peek(ctx)->type == TOK_COMMA) {
advance(ctx);
skip_nl(ctx);
continue;
}
break;
}
} else if (variant->data_type) {
/* Simple data type: one binding */
spl_tok_t *btok = advance(ctx);
char bname[256];
usize bnl = btok->len < 255 ? btok->len : 255;
memcpy(bname, btok->lexeme, bnl);
bname[bnl] = '\0';
spl_type_info_t *btype = variant->data_type;
int bslot = spl_declare_var(ctx, bname, btype, 0);
/* Load from enum data at offset 4 */
spl_emit(ctx, SPL_LADDR, SPL_PTR, addr_slot);
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
spl_emit(ctx, SPL_PUSH, SPL_USIZE, 4);
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
spl_type_t bt = (btype->kind == TYPE_BASIC) ? btype->basic_type
: (btype->kind == TYPE_PTR) ? SPL_PTR
: SPL_I32;
spl_emit(ctx, SPL_LOAD, bt, 0);
spl_emit(ctx, SPL_LADDR, SPL_PTR, bslot);
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
spl_emit(ctx, SPL_STORE, bt, 0);
}
}
if (has_parens)
expect(ctx, TOK_R_PAREN);
skip_nl(ctx);
/* => (two tokens: = >) */
if (peek(ctx)->type == TOK_ASSIGN) {
advance(ctx);
if (peek(ctx)->type == TOK_GT)
advance(ctx);
}
skip_nl(ctx);
/* Parse arm body statement */
spl_parse_stmt(ctx);
/* Pop scope if we pushed one */
if (scope_pushed) {
spl_emit_defer_epilogue(ctx, ctx->scope_depth);
spl_pop_scope(ctx);
}
/* JMP to end (skip remaining arms) */
if (n_jmps < MAX_MATCH_ARMS)
jmp_to_end[n_jmps++] = spl_emit_jmp(ctx);
/* Patch BZ to here (next arm or end) */
spl_patch_to_here(ctx, bz_addr);
skip_nl(ctx);
}
expect(ctx, TOK_R_BRACE);
/* Patch all JMPs to end */
for (int i = 0; i < n_jmps; i++)
spl_patch_to_here(ctx, jmp_to_end[i]);
/* Release temp slot */
ctx->current_local_slot--;
}
/* ============================================================
* Extern declaration: #[extern("vm")] fn name(...) ret;
* ============================================================ */
@@ -662,7 +878,8 @@ static void parse_expr_stmt(spl_comp_t *ctx) {
if (is_assign)
ctx->addr_of_mode = 0;
if (!is_assign && expr.type && expr.type->kind == TYPE_BASIC && expr.type->basic_type != SPL_VOID)
if (!is_assign && expr.type && expr.type->kind == TYPE_BASIC &&
expr.type->basic_type != SPL_VOID)
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
if (peek(ctx)->type == TOK_SEMICOLON)
advance(ctx);
@@ -712,6 +929,9 @@ void spl_parse_stmt(spl_comp_t *ctx) {
case KW_DEFER:
parse_defer_stmt(ctx);
break;
case KW_MATCH:
parse_match_stmt(ctx);
break;
case KW_TYPE:
parse_type_decl(ctx);
break;