stage1 优化代码 完成16测试
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
/* spl_parser.c — Top-level parser: function declarations, type declarations, etc. */
|
||||
|
||||
#include "spl_comp.h"
|
||||
#include "spl_lex_util.h"
|
||||
#include <string.h>
|
||||
|
||||
spl_tok_t *peek(spl_comp_t *ctx) { return &vec_at(ctx->toks, ctx->tok_idx); }
|
||||
@@ -12,20 +13,6 @@ spl_tok_t *advance(spl_comp_t *ctx) {
|
||||
return t;
|
||||
}
|
||||
|
||||
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 void skip_nl(spl_comp_t *ctx) {
|
||||
while (peek(ctx)->type == TOK_ENDLINE)
|
||||
advance(ctx);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* Parse function definition
|
||||
@@ -33,6 +20,48 @@ static void skip_nl(spl_comp_t *ctx) {
|
||||
* or fn name(params) ret-type; (forward decl, not used for stage1)
|
||||
* ============================================================ */
|
||||
|
||||
/* Shared helper: register a function, declare params, parse body, end function.
|
||||
* Used by both top-level fn decl and methods inside type bodies. */
|
||||
static int parse_fn_body(spl_comp_t *ctx, const char *fn_name, spl_type_info_t *ret_type,
|
||||
int nparams, char pnames[][256], spl_type_info_t *ptypes[], int is_pub) {
|
||||
int fi = spl_declare_func(ctx, fn_name, ret_type, nparams, 0, is_pub);
|
||||
ctx->current_func_idx = fi;
|
||||
ctx->current_ret_type = ret_type;
|
||||
ctx->current_local_slot = 0;
|
||||
|
||||
spl_push_scope(ctx);
|
||||
|
||||
for (int i = 0; i < nparams; i++) {
|
||||
spl_declare_var(ctx, pnames[i], ptypes[i], 0);
|
||||
}
|
||||
|
||||
skip_nl(ctx);
|
||||
if (peek(ctx)->type == TOK_L_BRACE) {
|
||||
advance(ctx); /* { */
|
||||
skip_nl(ctx);
|
||||
|
||||
spl_val_t alloc_addr = vec_size(ctx->prog.insns);
|
||||
spl_emit(ctx, SPL_ALLOC, SPL_VOID, 0);
|
||||
|
||||
while (peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) {
|
||||
spl_parse_stmt(ctx);
|
||||
skip_nl(ctx);
|
||||
}
|
||||
|
||||
spl_patch(ctx, alloc_addr, ctx->current_local_slot - nparams);
|
||||
expect(ctx, TOK_R_BRACE);
|
||||
}
|
||||
|
||||
spl_emit_defer_epilogue(ctx, ctx->scope_depth);
|
||||
spl_pop_scope(ctx);
|
||||
|
||||
spl_emit(ctx, SPL_RET, SPL_VOID, 0);
|
||||
spl_prog_end_func(&ctx->prog, fi);
|
||||
ctx->current_func_idx = -1;
|
||||
ctx->current_ret_type = NULL;
|
||||
return fi;
|
||||
}
|
||||
|
||||
static void parse_fn_decl(spl_comp_t *ctx, int is_extern, int is_pub) {
|
||||
advance(ctx); /* fn */
|
||||
skip_nl(ctx);
|
||||
@@ -124,53 +153,8 @@ static void parse_fn_decl(spl_comp_t *ctx, int is_extern, int is_pub) {
|
||||
|
||||
skip_nl(ctx);
|
||||
|
||||
/* Declare function in prog */
|
||||
int fi = spl_declare_func(ctx, fn_name, ret_type, nparams, 0, is_pub);
|
||||
ctx->current_func_idx = fi;
|
||||
ctx->current_ret_type = ret_type;
|
||||
ctx->current_local_slot = 0;
|
||||
|
||||
/* Push function scope for params + locals */
|
||||
spl_push_scope(ctx);
|
||||
|
||||
/* Declare parameters as variables in the function scope */
|
||||
for (int i = 0; i < nparams; i++) {
|
||||
spl_declare_var(ctx, pnames[i], ptypes[i], 0);
|
||||
}
|
||||
|
||||
/* Parse body */
|
||||
skip_nl(ctx);
|
||||
if (peek(ctx)->type == TOK_L_BRACE) {
|
||||
advance(ctx); /* { */
|
||||
skip_nl(ctx);
|
||||
|
||||
/* Emit ALLOC placeholder to reserve stack space for locals.
|
||||
* Without ALLOC, PUSH in expressions overwrites variable slots
|
||||
* because the stack and locals share the same memory. */
|
||||
spl_val_t alloc_addr = vec_size(ctx->prog.insns);
|
||||
spl_emit(ctx, SPL_ALLOC, SPL_VOID, 0);
|
||||
|
||||
while (peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) {
|
||||
spl_parse_stmt(ctx);
|
||||
skip_nl(ctx);
|
||||
}
|
||||
|
||||
/* Patch ALLOC to local slot count only (excludes param slots) */
|
||||
spl_patch(ctx, alloc_addr, ctx->current_local_slot - nparams);
|
||||
|
||||
expect(ctx, TOK_R_BRACE);
|
||||
}
|
||||
|
||||
spl_emit_defer_epilogue(ctx, ctx->scope_depth);
|
||||
spl_pop_scope(ctx);
|
||||
|
||||
/* Emit implicit RET for void functions without explicit return */
|
||||
spl_emit(ctx, SPL_RET, SPL_VOID, 0);
|
||||
|
||||
/* End function */
|
||||
spl_prog_end_func(&ctx->prog, fi);
|
||||
ctx->current_func_idx = -1;
|
||||
ctx->current_ret_type = NULL;
|
||||
/* Use shared helper for function body parsing */
|
||||
parse_fn_body(ctx, fn_name, ret_type, nparams, pnames, ptypes, is_pub);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
@@ -180,7 +164,7 @@ static void parse_fn_decl(spl_comp_t *ctx, int is_extern, int is_pub) {
|
||||
* var name: type; — field declarations
|
||||
* name: type, — field declarations (old-style)
|
||||
* type Name = ...; — nested type declarations
|
||||
* fn name(...) type { } — methods (skipped)
|
||||
* fn name(...) type { } — methods
|
||||
* ============================================================ */
|
||||
|
||||
static void parse_struct_body(spl_comp_t *ctx, spl_type_info_t *st) {
|
||||
@@ -195,9 +179,15 @@ static void parse_struct_body(spl_comp_t *ctx, spl_type_info_t *st) {
|
||||
int depth = 1;
|
||||
while (depth > 0 && ctx->tok_idx < vec_size(ctx->toks)) {
|
||||
spl_tok_type_t tt = peek(ctx)->type;
|
||||
if (tt == TOK_L_BRACE) { depth++; advance(ctx); }
|
||||
else if (tt == TOK_R_BRACE) { depth--; if (depth == 0) break; advance(ctx); }
|
||||
else if (tt == KW_TYPE && depth == 1) {
|
||||
if (tt == TOK_L_BRACE) {
|
||||
depth++;
|
||||
advance(ctx);
|
||||
} else if (tt == TOK_R_BRACE) {
|
||||
depth--;
|
||||
if (depth == 0)
|
||||
break;
|
||||
advance(ctx);
|
||||
} else if (tt == KW_TYPE && depth == 1) {
|
||||
parse_type_decl(ctx);
|
||||
} else {
|
||||
advance(ctx);
|
||||
@@ -213,13 +203,20 @@ static void parse_struct_body(spl_comp_t *ctx, spl_type_info_t *st) {
|
||||
while (depth > 0 && ctx->tok_idx < vec_size(ctx->toks)) {
|
||||
skip_nl(ctx);
|
||||
spl_tok_type_t tt = peek(ctx)->type;
|
||||
if (tt == TOK_L_BRACE) { depth++; advance(ctx); }
|
||||
else if (tt == TOK_R_BRACE) { depth--; if (depth == 0) { advance(ctx); break; } advance(ctx); }
|
||||
else if (tt == KW_TYPE && depth == 1) {
|
||||
if (tt == TOK_L_BRACE) {
|
||||
depth++;
|
||||
advance(ctx);
|
||||
} else if (tt == TOK_R_BRACE) {
|
||||
depth--;
|
||||
if (depth == 0) {
|
||||
advance(ctx);
|
||||
break;
|
||||
}
|
||||
advance(ctx);
|
||||
} else if (tt == KW_TYPE && depth == 1) {
|
||||
/* Nested type — already parsed in pass 1, skip by re-parsing */
|
||||
parse_type_decl(ctx);
|
||||
}
|
||||
else if (tt == KW_VAR && depth == 1) {
|
||||
} else if (tt == KW_VAR && depth == 1) {
|
||||
/* var name: type; */
|
||||
advance(ctx); /* var */
|
||||
skip_nl(ctx);
|
||||
@@ -238,8 +235,7 @@ static void parse_struct_body(spl_comp_t *ctx, spl_type_info_t *st) {
|
||||
skip_nl(ctx);
|
||||
if (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_COMMA)
|
||||
advance(ctx);
|
||||
}
|
||||
else if (tt == TOK_IDENT && depth == 1) {
|
||||
} else if (tt == TOK_IDENT && depth == 1) {
|
||||
/* Old-style field: name: type, */
|
||||
spl_tok_t *ftok = advance(ctx);
|
||||
skip_nl(ctx);
|
||||
@@ -256,28 +252,86 @@ static void parse_struct_body(spl_comp_t *ctx, spl_type_info_t *st) {
|
||||
skip_nl(ctx);
|
||||
if (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_COMMA)
|
||||
advance(ctx);
|
||||
}
|
||||
else if (tt == KW_FN && depth == 1) {
|
||||
/* Method — skip over fn name(params) rettype { body } */
|
||||
} else if (tt == KW_FN && depth == 1) {
|
||||
/* Method — parse properly using parse_fn_body */
|
||||
advance(ctx); /* fn */
|
||||
while (ctx->tok_idx < vec_size(ctx->toks)) {
|
||||
spl_tok_type_t mt = peek(ctx)->type;
|
||||
if (mt == TOK_SEMICOLON) { advance(ctx); break; }
|
||||
if (mt == TOK_L_BRACE) {
|
||||
/* Skip function body counting braces */
|
||||
advance(ctx);
|
||||
int bd = 1;
|
||||
while (bd > 0 && ctx->tok_idx < vec_size(ctx->toks)) {
|
||||
if (peek(ctx)->type == TOK_L_BRACE) bd++;
|
||||
else if (peek(ctx)->type == TOK_R_BRACE) bd--;
|
||||
skip_nl(ctx);
|
||||
spl_tok_t *mname_tok = advance(ctx);
|
||||
char mname[256];
|
||||
usize mnl = mname_tok->len < 255 ? mname_tok->len : 255;
|
||||
memcpy(mname, mname_tok->lexeme, mnl);
|
||||
mname[mnl] = '\0';
|
||||
|
||||
/* Build qualified name: TypeName.method_name */
|
||||
char qualified[512];
|
||||
snprintf(qualified, sizeof(qualified), "%s.%s", st->name ? st->name : "anon",
|
||||
mname);
|
||||
|
||||
skip_nl(ctx);
|
||||
expect(ctx, TOK_L_PAREN);
|
||||
|
||||
/* Parse parameters */
|
||||
int nparams = 0;
|
||||
enum { MAX_PARAMS = 64 };
|
||||
char pnames[MAX_PARAMS][256];
|
||||
spl_type_info_t *ptypes[MAX_PARAMS];
|
||||
skip_nl(ctx);
|
||||
if (peek(ctx)->type != TOK_R_PAREN) {
|
||||
while (1) {
|
||||
spl_tok_t *pname = advance(ctx);
|
||||
usize pnl = pname->len < 255 ? pname->len : 255;
|
||||
memcpy(pnames[nparams], pname->lexeme, pnl);
|
||||
pnames[nparams][pnl] = '\0';
|
||||
skip_nl(ctx);
|
||||
if (peek(ctx)->type == TOK_COLON) {
|
||||
advance(ctx); /* : */
|
||||
skip_nl(ctx);
|
||||
ptypes[nparams] = spl_parse_type(ctx);
|
||||
} else {
|
||||
ptypes[nparams] = spl_type_basic(SPL_I32);
|
||||
}
|
||||
nparams++;
|
||||
skip_nl(ctx);
|
||||
if (peek(ctx)->type == TOK_COMMA) {
|
||||
advance(ctx);
|
||||
skip_nl(ctx);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
advance(ctx);
|
||||
}
|
||||
}
|
||||
else {
|
||||
expect(ctx, TOK_R_PAREN);
|
||||
skip_nl(ctx);
|
||||
|
||||
/* Return type (default: void) */
|
||||
spl_type_info_t *ret_type = spl_type_basic(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);
|
||||
skip_nl(ctx);
|
||||
}
|
||||
|
||||
/* Set current_type_name for short-name resolution inside method body */
|
||||
const char *saved_type_name = ctx->current_type_name;
|
||||
ctx->current_type_name = st->name;
|
||||
|
||||
int fi = parse_fn_body(ctx, qualified, ret_type, nparams, pnames, ptypes, 0);
|
||||
|
||||
{
|
||||
spl_func_info_t *f = &vec_at(ctx->funcs, fi);
|
||||
f->param_types = calloc(nparams, sizeof(spl_type_info_t *));
|
||||
f->param_names = calloc(nparams, sizeof(char *));
|
||||
for (int i = 0; i < nparams; i++) {
|
||||
f->param_types[i] = ptypes[i];
|
||||
f->param_names[i] = strdup(pnames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
ctx->current_type_name = saved_type_name;
|
||||
|
||||
spl_type_add_method(st, mname, fi);
|
||||
} else {
|
||||
advance(ctx);
|
||||
}
|
||||
}
|
||||
@@ -308,9 +362,15 @@ static void parse_enum_body(spl_comp_t *ctx, spl_type_info_t *et) {
|
||||
int depth = 1;
|
||||
while (depth > 0 && ctx->tok_idx < vec_size(ctx->toks)) {
|
||||
spl_tok_type_t tt = peek(ctx)->type;
|
||||
if (tt == TOK_L_BRACE) { depth++; advance(ctx); }
|
||||
else if (tt == TOK_R_BRACE) { depth--; if (depth == 0) break; advance(ctx); }
|
||||
else if (tt == KW_TYPE && depth == 1) {
|
||||
if (tt == TOK_L_BRACE) {
|
||||
depth++;
|
||||
advance(ctx);
|
||||
} else if (tt == TOK_R_BRACE) {
|
||||
depth--;
|
||||
if (depth == 0)
|
||||
break;
|
||||
advance(ctx);
|
||||
} else if (tt == KW_TYPE && depth == 1) {
|
||||
parse_type_decl(ctx);
|
||||
} else {
|
||||
advance(ctx);
|
||||
@@ -325,13 +385,20 @@ static void parse_enum_body(spl_comp_t *ctx, spl_type_info_t *et) {
|
||||
while (depth > 0 && ctx->tok_idx < vec_size(ctx->toks)) {
|
||||
skip_nl(ctx);
|
||||
spl_tok_type_t tt = peek(ctx)->type;
|
||||
if (tt == TOK_L_BRACE) { depth++; advance(ctx); }
|
||||
else if (tt == TOK_R_BRACE) { depth--; if (depth == 0) { advance(ctx); break; } advance(ctx); }
|
||||
else if (tt == KW_TYPE && depth == 1) {
|
||||
if (tt == TOK_L_BRACE) {
|
||||
depth++;
|
||||
advance(ctx);
|
||||
} else if (tt == TOK_R_BRACE) {
|
||||
depth--;
|
||||
if (depth == 0) {
|
||||
advance(ctx);
|
||||
break;
|
||||
}
|
||||
advance(ctx);
|
||||
} else if (tt == KW_TYPE && depth == 1) {
|
||||
/* Already parsed in pass 1, re-parse to skip */
|
||||
parse_type_decl(ctx);
|
||||
}
|
||||
else if (tt == TOK_IDENT && depth == 1) {
|
||||
} else if (tt == TOK_IDENT && depth == 1) {
|
||||
/* Variant: Name or Name: Type */
|
||||
spl_tok_t *vtok = advance(ctx);
|
||||
skip_nl(ctx);
|
||||
@@ -354,27 +421,86 @@ static void parse_enum_body(spl_comp_t *ctx, spl_type_info_t *et) {
|
||||
skip_nl(ctx);
|
||||
if (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_COMMA)
|
||||
advance(ctx);
|
||||
}
|
||||
else if (tt == KW_FN && depth == 1) {
|
||||
/* Method — skip */
|
||||
} else if (tt == KW_FN && depth == 1) {
|
||||
/* Method — parse properly using parse_fn_body */
|
||||
advance(ctx); /* fn */
|
||||
while (ctx->tok_idx < vec_size(ctx->toks)) {
|
||||
spl_tok_type_t mt = peek(ctx)->type;
|
||||
if (mt == TOK_SEMICOLON) { advance(ctx); break; }
|
||||
if (mt == TOK_L_BRACE) {
|
||||
advance(ctx);
|
||||
int bd = 1;
|
||||
while (bd > 0 && ctx->tok_idx < vec_size(ctx->toks)) {
|
||||
if (peek(ctx)->type == TOK_L_BRACE) bd++;
|
||||
else if (peek(ctx)->type == TOK_R_BRACE) bd--;
|
||||
skip_nl(ctx);
|
||||
spl_tok_t *mname_tok = advance(ctx);
|
||||
char mname[256];
|
||||
usize mnl = mname_tok->len < 255 ? mname_tok->len : 255;
|
||||
memcpy(mname, mname_tok->lexeme, mnl);
|
||||
mname[mnl] = '\0';
|
||||
|
||||
/* Build qualified name: TypeName.method_name */
|
||||
char qualified[512];
|
||||
snprintf(qualified, sizeof(qualified), "%s.%s", et->name ? et->name : "anon",
|
||||
mname);
|
||||
|
||||
skip_nl(ctx);
|
||||
expect(ctx, TOK_L_PAREN);
|
||||
|
||||
/* Parse parameters */
|
||||
int nparams = 0;
|
||||
enum { MAX_PARAMS = 64 };
|
||||
char pnames[MAX_PARAMS][256];
|
||||
spl_type_info_t *ptypes[MAX_PARAMS];
|
||||
skip_nl(ctx);
|
||||
if (peek(ctx)->type != TOK_R_PAREN) {
|
||||
while (1) {
|
||||
spl_tok_t *pname = advance(ctx);
|
||||
usize pnl = pname->len < 255 ? pname->len : 255;
|
||||
memcpy(pnames[nparams], pname->lexeme, pnl);
|
||||
pnames[nparams][pnl] = '\0';
|
||||
skip_nl(ctx);
|
||||
if (peek(ctx)->type == TOK_COLON) {
|
||||
advance(ctx); /* : */
|
||||
skip_nl(ctx);
|
||||
ptypes[nparams] = spl_parse_type(ctx);
|
||||
} else {
|
||||
ptypes[nparams] = spl_type_basic(SPL_I32);
|
||||
}
|
||||
nparams++;
|
||||
skip_nl(ctx);
|
||||
if (peek(ctx)->type == TOK_COMMA) {
|
||||
advance(ctx);
|
||||
skip_nl(ctx);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
advance(ctx);
|
||||
}
|
||||
}
|
||||
else {
|
||||
expect(ctx, TOK_R_PAREN);
|
||||
skip_nl(ctx);
|
||||
|
||||
/* Return type (default: void) */
|
||||
spl_type_info_t *ret_type = spl_type_basic(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);
|
||||
skip_nl(ctx);
|
||||
}
|
||||
|
||||
/* Set current_type_name for short-name resolution inside method body */
|
||||
const char *saved_type_name = ctx->current_type_name;
|
||||
ctx->current_type_name = et->name;
|
||||
|
||||
int fi = parse_fn_body(ctx, qualified, ret_type, nparams, pnames, ptypes, 0);
|
||||
|
||||
ctx->current_type_name = saved_type_name;
|
||||
|
||||
{
|
||||
spl_func_info_t *f = &vec_at(ctx->funcs, fi);
|
||||
f->param_types = calloc(nparams, sizeof(spl_type_info_t *));
|
||||
f->param_names = calloc(nparams, sizeof(char *));
|
||||
for (int i = 0; i < nparams; i++) {
|
||||
f->param_types[i] = ptypes[i];
|
||||
f->param_names[i] = strdup(pnames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
spl_type_add_method(et, mname, fi);
|
||||
} else {
|
||||
advance(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user