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,7 +1,7 @@
/* spl_expr.c — Expression parser + codegen (Pratt parser / precedence climbing) */
#include "spl_comp.h"
#include <ctype.h>
#include "spl_lex_util.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -10,32 +10,6 @@
* Token helpers
* ============================================================ */
/* Token helpers — using shared peek/advance from spl_parser.c */
static int match(spl_comp_t *ctx, spl_tok_type_t type) {
if (peek(ctx)->type == type) {
advance(ctx);
return 1;
}
return 0;
}
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;
}
/* Skip newline tokens */
static void skip_nl(spl_comp_t *ctx) {
while (peek(ctx)->type == TOK_ENDLINE)
advance(ctx);
}
/* Check if current token starts a statement */
static int is_stmt_start(spl_comp_t *ctx) {
spl_tok_type_t t = peek(ctx)->type;
@@ -155,8 +129,8 @@ static void emit_slice_index(spl_comp_t *ctx, spl_type_info_t *elem) {
* Uses qualified name (TypeName.Member) first for namespace isolation,
* then falls back to simple name lookup.
* Returns 1 if resolved. */
static int spl_resolve_type_member(spl_comp_t *ctx, spl_type_info_t *type,
const char *field, spl_expr_result_t *result) {
static int spl_resolve_type_member(spl_comp_t *ctx, spl_type_info_t *type, const char *field,
spl_expr_result_t *result) {
/* For enum: check variants first */
if (type->kind == TYPE_ENUM) {
vec_for(type->variants, i) {
@@ -198,17 +172,28 @@ static int spl_resolve_type_member(spl_comp_t *ctx, spl_type_info_t *type,
/* Map assignment operator token (e.g. +=) to corresponding binary operator (e.g. +) */
static spl_tok_type_t assign_to_binop(spl_tok_type_t t) {
switch (t) {
case TOK_ASSIGN_ADD: return TOK_ADD;
case TOK_ASSIGN_SUB: return TOK_SUB;
case TOK_ASSIGN_MUL: return TOK_MUL;
case TOK_ASSIGN_DIV: return TOK_DIV;
case TOK_ASSIGN_MOD: return TOK_MOD;
case TOK_ASSIGN_AND: return TOK_AND;
case TOK_ASSIGN_OR: return TOK_OR;
case TOK_ASSIGN_XOR: return TOK_XOR;
case TOK_ASSIGN_L_SH: return TOK_L_SH;
case TOK_ASSIGN_R_SH: return TOK_R_SH;
default: return (spl_tok_type_t)-1;
case TOK_ASSIGN_ADD:
return TOK_ADD;
case TOK_ASSIGN_SUB:
return TOK_SUB;
case TOK_ASSIGN_MUL:
return TOK_MUL;
case TOK_ASSIGN_DIV:
return TOK_DIV;
case TOK_ASSIGN_MOD:
return TOK_MOD;
case TOK_ASSIGN_AND:
return TOK_AND;
case TOK_ASSIGN_OR:
return TOK_OR;
case TOK_ASSIGN_XOR:
return TOK_XOR;
case TOK_ASSIGN_L_SH:
return TOK_L_SH;
case TOK_ASSIGN_R_SH:
return TOK_R_SH;
default:
return (spl_tok_type_t)-1;
}
}
@@ -398,10 +383,165 @@ static spl_expr_result_t parse_array_literal(spl_comp_t *ctx) {
return (spl_expr_result_t){arr_type, 0};
}
/* Parse a type name with optional .field suffix for enum variants:
* TypeName
* TypeName.field
*/
/* Determine correct STORE type for a type (handles ptr = 8 bytes). */
static spl_type_t spl_store_type(spl_type_info_t *type) {
if (!type)
return SPL_I32;
if (type->kind == TYPE_BASIC)
return type->basic_type;
if (type->kind == TYPE_PTR)
return SPL_PTR;
if (spl_type_slot_count(type) <= 1)
return SPL_PTR;
return SPL_I32;
}
/* Parse struct/enum literal: Type { .field = val, ... }
* Allocates temp slots for the value, returns lvalue (addr on stack).
* For single-slot types, pushes the packed value directly. */
static spl_expr_result_t parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *type) {
usize sc = spl_type_slot_count(type);
int base_slot = ctx->current_local_slot;
ctx->current_local_slot += (int)sc;
advance(ctx); /* { */
skip_nl(ctx);
if (type->kind == TYPE_STRUCT) {
while (peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) {
if (peek(ctx)->type == TOK_COMMA) {
advance(ctx);
skip_nl(ctx);
continue;
}
if (peek(ctx)->type == TOK_DOT) {
advance(ctx);
spl_tok_t *ftok = advance(ctx);
char fname[256];
usize fnl = ftok->len < 255 ? ftok->len : 255;
memcpy(fname, ftok->lexeme, fnl);
fname[fnl] = '\0';
skip_nl(ctx);
if (peek(ctx)->type == TOK_ASSIGN)
advance(ctx);
skip_nl(ctx);
vec_for(type->fields, fi) {
spl_field_t *f = &vec_at(type->fields, fi);
if (strcmp(f->name, fname) == 0) {
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_slot);
if (f->offset > 0) {
spl_emit(ctx, SPL_PUSH, SPL_USIZE, f->offset);
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
}
spl_expr_result_t fv = spl_parse_expr(ctx, PREC_MIN);
(void)fv;
spl_emit(ctx, SPL_STORE, spl_store_type(f->type), 0);
break;
}
}
}
skip_nl(ctx);
}
} else if (type->kind == TYPE_ENUM) {
/* Parse .Variant [= value] */
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';
skip_nl(ctx);
if (peek(ctx)->type == TOK_ASSIGN)
advance(ctx);
skip_nl(ctx);
int found = 0;
vec_for(type->variants, vi) {
spl_enum_variant_t *v = &vec_at(type->variants, vi);
if (strcmp(v->name, vname) == 0) {
found = 1;
/* Store tag at offset 0 */
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_slot);
spl_emit(ctx, SPL_PUSH, SPL_I32, v->value);
spl_emit(ctx, SPL_STORE, SPL_I32, 0);
/* Store variant data at offset 4 */
const usize DATA_OFFSET = 4;
if (v->data_type) {
if (v->data_type->kind == TYPE_STRUCT && peek(ctx)->type == TOK_L_BRACE) {
/* Struct data: { .field = val, ... } */
advance(ctx); /* { */
skip_nl(ctx);
while (peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) {
if (peek(ctx)->type == TOK_COMMA) {
advance(ctx);
skip_nl(ctx);
continue;
}
if (peek(ctx)->type == TOK_DOT)
advance(ctx);
spl_tok_t *sftok = advance(ctx);
char sfname[256];
usize sfnl = sftok->len < 255 ? sftok->len : 255;
memcpy(sfname, sftok->lexeme, sfnl);
sfname[sfnl] = '\0';
skip_nl(ctx);
if (peek(ctx)->type == TOK_ASSIGN)
advance(ctx);
skip_nl(ctx);
vec_for(v->data_type->fields, sfi) {
spl_field_t *sf = &vec_at(v->data_type->fields, sfi);
if (strcmp(sf->name, sfname) == 0) {
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_slot);
usize byte_off = DATA_OFFSET + sf->offset;
if (byte_off > 0) {
spl_emit(ctx, SPL_PUSH, SPL_USIZE, byte_off);
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
}
spl_expr_result_t sfv = spl_parse_expr(ctx, PREC_MIN);
(void)sfv;
spl_emit(ctx, SPL_STORE, spl_store_type(sf->type), 0);
break;
}
}
skip_nl(ctx);
}
expect(ctx, TOK_R_BRACE);
} else {
/* Simple data: parse expression */
spl_expr_result_t dv = spl_parse_expr(ctx, PREC_MIN);
(void)dv;
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_slot);
spl_emit(ctx, SPL_PUSH, SPL_USIZE, DATA_OFFSET);
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
spl_type_t bt = spl_store_type(v->data_type);
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
spl_emit(ctx, SPL_STORE, bt, 0);
}
}
break;
}
}
if (!found)
spl_comp_error(ctx, "unknown enum variant '%s'", vname);
}
skip_nl(ctx);
expect(ctx, TOK_R_BRACE);
/* Return: for single-slot, push packed value. For multi-slot, push address. */
if (sc == 1) {
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_slot);
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
return (spl_expr_result_t){type, 0}; /* value on stack */
} else {
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_slot);
return (spl_expr_result_t){type, 1}; /* address on stack */
}
}
static spl_type_info_t *parse_qualified_type(spl_comp_t *ctx, const char *name) {
/* Check if it's a known type */
spl_type_info_t *t = spl_resolve_type(ctx, name);
@@ -436,6 +576,12 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
/* Check if it's a function call: ident(...) */
if (peek(ctx)->type == TOK_L_PAREN) {
int fi = spl_lookup_func(ctx, name);
/* Fallback: try qualified name for short-name resolution inside methods */
if (fi < 0 && ctx->current_type_name) {
char qualified[512];
snprintf(qualified, sizeof(qualified), "%s.%s", ctx->current_type_name, name);
fi = spl_lookup_func(ctx, qualified);
}
if (fi < 0) {
spl_comp_error(ctx, "unknown function '%s'", name);
spl_expr_result_t r = {0};
@@ -525,7 +671,12 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
/* Check if it's a type name (for enum variant access like Color.Red) */
spl_type_info_t *ttype = spl_resolve_type(ctx, name);
if (ttype) {
spl_expr_result_t r = {ttype, 1};
/* Struct/enum literal: Type { .field = val, ... } */
if (peek(ctx)->type == TOK_L_BRACE &&
(ttype->kind == TYPE_STRUCT || ttype->kind == TYPE_ENUM)) {
return parse_struct_literal(ctx, ttype);
}
spl_expr_result_t r = {ttype, 0};
return r;
}
@@ -669,9 +820,7 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
break;
}
char bname[256];
usize bnlen = tok->len < 255 ? tok->len : 255;
memcpy(bname, tok->lexeme, bnlen);
bname[bnlen] = '\0';
spl_tok_copy_name(tok, bname, sizeof bname);
advance(ctx); /* consume builtin name */
if (strcmp(bname, "dbg") == 0) {
@@ -746,6 +895,73 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
}
}
/* Method call on type/instance: left.field(args) */
if (left.type && peek(ctx)->type == TOK_L_PAREN) {
/* Determine the type that owns methods (deref pointer if needed) */
spl_type_info_t *methods_type = left.type;
int is_ptr_self = 0;
if (methods_type->kind == TYPE_PTR && methods_type->elem &&
(methods_type->elem->kind == TYPE_STRUCT ||
methods_type->elem->kind == TYPE_ENUM)) {
is_ptr_self = 1;
methods_type = methods_type->elem;
}
int found_method = 0;
vec_for(methods_type->methods, mi) {
if (strcmp(vec_at(methods_type->methods, mi).name, fname) == 0) {
spl_method_info_t *method = &vec_at(methods_type->methods, mi);
spl_func_info_t *func = &vec_at(ctx->funcs, method->func_idx);
advance(ctx); /* ( */
found_method = 1;
int nargs = 0;
/* Check if instance method: first param is self: *Type */
int is_instance = 0;
if (func->nparams > 0 && func->param_types[0] &&
func->param_types[0]->kind == TYPE_PTR &&
func->param_types[0]->elem == methods_type) {
is_instance = 1;
}
if (is_instance) {
if (!left.is_lvalue && !is_ptr_self) {
spl_comp_error(ctx, "cannot call instance method '%s' on type",
fname);
}
nargs = 1; /* self already on stack */
}
/* Parse remaining arguments */
if (peek(ctx)->type != TOK_R_PAREN) {
for (;;) {
spl_expr_result_t arg = spl_parse_expr(ctx, PREC_MIN);
(void)arg;
nargs++;
if (peek(ctx)->type == TOK_COMMA) {
advance(ctx);
continue;
}
break;
}
}
expect(ctx, TOK_R_PAREN);
spl_val_t addr = vec_at(ctx->prog.funcs, func->func_idx).address;
spl_emit(ctx, SPL_PUSH, SPL_PTR, addr);
spl_emit(ctx, SPL_CALL, SPL_VOID, nargs);
left = (spl_expr_result_t){func->ret_type, 0};
break;
}
}
if (found_method)
continue;
/* If method not found, fall through to field access below */
}
/* Struct field access */
if (left.type && left.type->kind == TYPE_STRUCT) {
/* The struct address is on stack (as lvalue or from previous computation) */
@@ -998,12 +1214,12 @@ static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, sp
spl_emit(ctx, SPL_STORE, bt, 0);
} else {
/* Compound: left = left op right — stack: [addr, rhs] */
spl_emit(ctx, SPL_PICK, SPL_VOID, 1); /* [addr, rhs, addr] */
spl_emit(ctx, SPL_LOAD, bt, 0); /* [addr, rhs, old_val] */
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); /* [addr, old_val, rhs] */
spl_emit(ctx, SPL_PICK, SPL_VOID, 1); /* [addr, rhs, addr] */
spl_emit(ctx, SPL_LOAD, bt, 0); /* [addr, rhs, old_val] */
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); /* [addr, old_val, rhs] */
int sop = binop_to_sir(assign_to_binop(op), bt);
if (sop >= 0)
spl_emit(ctx, sop, bt, 0); /* [addr, result] */
spl_emit(ctx, sop, bt, 0); /* [addr, result] */
spl_emit(ctx, SPL_STORE, bt, 0);
}
}