stage1 实现06测试

This commit is contained in:
zzy
2026-07-05 22:47:00 +08:00
parent e2e0ebc21f
commit 67c8a137dd
6 changed files with 365 additions and 132 deletions

View File

@@ -638,18 +638,37 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
is_slice = 1; is_slice = 1;
advance(ctx); /* skip .. */ advance(ctx); /* skip .. */
spl_expr_result_t end_expr = {0}; spl_expr_result_t end_expr = {0};
if (peek(ctx)->type != TOK_R_BRACKET) { int has_explicit_end = (peek(ctx)->type != TOK_R_BRACKET);
if (has_explicit_end) {
end_expr = spl_parse_expr(ctx, PREC_MIN); end_expr = spl_parse_expr(ctx, PREC_MIN);
} }
expect(ctx, TOK_R_BRACKET); expect(ctx, TOK_R_BRACKET);
/* Push implicit end value (array length/slice len) before the outer
* type-check so it always runs regardless of left.type validity. */
if (!has_explicit_end) {
if (left.type && left.type->kind == TYPE_ARRAY) {
spl_emit(ctx, SPL_PUSH, SPL_U64, left.type->array_len);
} else if (left.type && left.type->kind == TYPE_SLICE) {
/* TYPE_SLICE: load len from struct at offset sizeof(spl_val_t) */
spl_emit(ctx, SPL_PICK, SPL_VOID, 1);
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_I32, 0);
}
}
/* Generate slice: compute ptr = base + begin * stride, len = end - begin */ /* Generate slice: compute ptr = base + begin * stride, len = end - begin */
if (left.type && (left.type->kind == TYPE_ARRAY || left.type->kind == TYPE_SLICE)) { if (left.type && (left.type->kind == TYPE_ARRAY || left.type->kind == TYPE_SLICE)) {
usize stride = (left.type->kind == TYPE_ARRAY) ? sizeof(spl_val_t) : (left.type->elem ? left.type->elem->byte_size : 4); usize stride = (left.type->kind == TYPE_ARRAY) ? sizeof(spl_val_t) : (left.type->elem ? left.type->elem->byte_size : 4);
/* For TYPE_SLICE, load data ptr from slice struct first */ /* For TYPE_SLICE: convert [struct_addr, begin, end] → [data_ptr, begin, end] */
if (left.type->kind == TYPE_SLICE) { if (left.type->kind == TYPE_SLICE) {
spl_emit(ctx, SPL_PICK, SPL_VOID, 2);
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0); spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
spl_emit(ctx, SPL_ROT, SPL_VOID, 0);
spl_emit(ctx, SPL_ROT, SPL_VOID, 0);
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
} }
emit_slice_create(ctx, stride); emit_slice_create(ctx, stride);

View File

@@ -2,7 +2,6 @@
#include "spl_lexer.h" #include "spl_lexer.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
const char *spl_tok_type_name(spl_tok_type_t type) { const char *spl_tok_type_name(spl_tok_type_t type) {
@@ -33,9 +32,7 @@ void spl_tok_dump(spl_tok_t *tok) {
buf[i] = ' '; buf[i] = ' ';
} }
printf("%s:%zu:%zu %-20s '%s'", printf("%s:%zu:%zu %-20s '%s'", tok->fname ? tok->fname : "", tok->line, tok->col,
tok->fname ? tok->fname : "",
tok->line, tok->col,
spl_tok_type_name(tok->type), buf); spl_tok_type_name(tok->type), buf);
if (tok->type == TOK_INT_LITERAL) { if (tok->type == TOK_INT_LITERAL) {

View File

@@ -2,7 +2,6 @@
#include "spl_lexer.h" #include "spl_lexer.h"
#include <ctype.h> #include <ctype.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>

View File

@@ -1,28 +1,30 @@
/* spl_parser.c — Top-level parser: function declarations, type declarations, etc. */ /* spl_parser.c — Top-level parser: function declarations, type declarations, etc. */
#include "spl_comp.h" #include "spl_comp.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
static spl_tok_t *peek(spl_comp_t *ctx) { static spl_tok_t *peek(spl_comp_t *ctx) { return &vec_at(ctx->toks, ctx->tok_idx); }
return &vec_at(ctx->toks, ctx->tok_idx);
}
static spl_tok_t *advance(spl_comp_t *ctx) { static spl_tok_t *advance(spl_comp_t *ctx) {
spl_tok_t *t = &vec_at(ctx->toks, ctx->tok_idx); spl_tok_t *t = &vec_at(ctx->toks, ctx->tok_idx);
if (t->type != TOK_EOF) ctx->tok_idx++; if (t->type != TOK_EOF)
ctx->tok_idx++;
return t; return t;
} }
static int expect(spl_comp_t *ctx, spl_tok_type_t type) { static int expect(spl_comp_t *ctx, spl_tok_type_t type) {
if (peek(ctx)->type == type) { advance(ctx); return 1; } if (peek(ctx)->type == type) {
spl_comp_error(ctx, "expected '%s', got '%s'", spl_tok_type_name(type), spl_tok_type_name(peek(ctx)->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; return 0;
} }
static void skip_nl(spl_comp_t *ctx) { static void skip_nl(spl_comp_t *ctx) {
while (peek(ctx)->type == TOK_ENDLINE) advance(ctx); while (peek(ctx)->type == TOK_ENDLINE)
advance(ctx);
} }
/* ============================================================ /* ============================================================
@@ -38,7 +40,8 @@ static void parse_fn_decl(spl_comp_t *ctx, int is_extern, int is_pub) {
spl_tok_t *fname_tok = advance(ctx); spl_tok_t *fname_tok = advance(ctx);
char fn_name[256]; char fn_name[256];
usize fnl = fname_tok->len < 255 ? fname_tok->len : 255; usize fnl = fname_tok->len < 255 ? fname_tok->len : 255;
memcpy(fn_name, fname_tok->lexeme, fnl); fn_name[fnl] = '\0'; memcpy(fn_name, fname_tok->lexeme, fnl);
fn_name[fnl] = '\0';
skip_nl(ctx); skip_nl(ctx);
expect(ctx, TOK_L_PAREN); expect(ctx, TOK_L_PAREN);
@@ -65,8 +68,15 @@ static void parse_fn_decl(spl_comp_t *ctx, int is_extern, int is_pub) {
} }
nparams++; nparams++;
skip_nl(ctx); skip_nl(ctx);
if (peek(ctx)->type == TOK_COMMA) { advance(ctx); skip_nl(ctx); continue; } if (peek(ctx)->type == TOK_COMMA) {
if (peek(ctx)->type == TOK_ELLIPSIS) { advance(ctx); skip_nl(ctx); } advance(ctx);
skip_nl(ctx);
continue;
}
if (peek(ctx)->type == TOK_ELLIPSIS) {
advance(ctx);
skip_nl(ctx);
}
break; break;
} }
} }
@@ -77,7 +87,8 @@ static void parse_fn_decl(spl_comp_t *ctx, int is_extern, int is_pub) {
spl_type_info_t *ret_type = spl_type_basic(SPL_VOID); spl_type_info_t *ret_type = spl_type_basic(SPL_VOID);
if (peek(ctx)->type != TOK_SEMICOLON && peek(ctx)->type != TOK_L_BRACE) { if (peek(ctx)->type != TOK_SEMICOLON && peek(ctx)->type != TOK_L_BRACE) {
ret_type = spl_parse_type(ctx); ret_type = spl_parse_type(ctx);
if (!ret_type) ret_type = spl_type_basic(SPL_VOID); if (!ret_type)
ret_type = spl_type_basic(SPL_VOID);
skip_nl(ctx); skip_nl(ctx);
} }
@@ -88,7 +99,8 @@ static void parse_fn_decl(spl_comp_t *ctx, int is_extern, int is_pub) {
int found = -1; int found = -1;
vec_for(ctx->prog.natives, ni) { vec_for(ctx->prog.natives, ni) {
if (strcmp(vec_at(ctx->prog.natives, ni).name, fn_name) == 0) { if (strcmp(vec_at(ctx->prog.natives, ni).name, fn_name) == 0) {
found = (int)ni; break; found = (int)ni;
break;
} }
} }
if (found < 0) { if (found < 0) {
@@ -99,7 +111,8 @@ static void parse_fn_decl(spl_comp_t *ctx, int is_extern, int is_pub) {
nat.impl_fn = NULL; /* resolved by VM at runtime */ nat.impl_fn = NULL; /* resolved by VM at runtime */
vec_push(ctx->prog.natives, nat); vec_push(ctx->prog.natives, nat);
} }
if (peek(ctx)->type == TOK_SEMICOLON) advance(ctx); if (peek(ctx)->type == TOK_SEMICOLON)
advance(ctx);
return; return;
} }
@@ -170,7 +183,8 @@ void parse_type_decl(spl_comp_t *ctx) {
spl_tok_t *name_tok = advance(ctx); spl_tok_t *name_tok = advance(ctx);
char tname[256]; char tname[256];
usize tnl = name_tok->len < 255 ? name_tok->len : 255; usize tnl = name_tok->len < 255 ? name_tok->len : 255;
memcpy(tname, name_tok->lexeme, tnl); tname[tnl] = '\0'; memcpy(tname, name_tok->lexeme, tnl);
tname[tnl] = '\0';
skip_nl(ctx); skip_nl(ctx);
expect(ctx, TOK_ASSIGN); expect(ctx, TOK_ASSIGN);
@@ -192,13 +206,18 @@ void parse_type_decl(spl_comp_t *ctx) {
spl_type_info_t *ftype = spl_parse_type(ctx); spl_type_info_t *ftype = spl_parse_type(ctx);
char fname[256]; char fname[256];
usize fnl = ftok->len < 255 ? ftok->len : 255; usize fnl = ftok->len < 255 ? ftok->len : 255;
memcpy(fname, ftok->lexeme, fnl); fname[fnl] = '\0'; memcpy(fname, ftok->lexeme, fnl);
fname[fnl] = '\0';
spl_type_add_field(st, fname, ftype); spl_type_add_field(st, fname, ftype);
} }
skip_nl(ctx); skip_nl(ctx);
if (peek(ctx)->type == TOK_COMMA) { advance(ctx); skip_nl(ctx); } if (peek(ctx)->type == TOK_COMMA) {
advance(ctx);
skip_nl(ctx);
} }
if (peek(ctx)->type == TOK_R_BRACE) advance(ctx); }
if (peek(ctx)->type == TOK_R_BRACE)
advance(ctx);
} }
spl_type_compute_layout(st); spl_type_compute_layout(st);
map_put(ctx->type_defs, strdup(tname), st); map_put(ctx->type_defs, strdup(tname), st);
@@ -218,22 +237,29 @@ void parse_type_decl(spl_comp_t *ctx) {
spl_type_info_t *dtype = spl_parse_type(ctx); spl_type_info_t *dtype = spl_parse_type(ctx);
char vname[256]; char vname[256];
usize vnl = vtok->len < 255 ? vtok->len : 255; usize vnl = vtok->len < 255 ? vtok->len : 255;
memcpy(vname, vtok->lexeme, vnl); vname[vnl] = '\0'; memcpy(vname, vtok->lexeme, vnl);
vname[vnl] = '\0';
spl_type_add_variant(et, vname, dtype); spl_type_add_variant(et, vname, dtype);
} else { } else {
char vname[256]; char vname[256];
usize vnl = vtok->len < 255 ? vtok->len : 255; usize vnl = vtok->len < 255 ? vtok->len : 255;
memcpy(vname, vtok->lexeme, vnl); vname[vnl] = '\0'; memcpy(vname, vtok->lexeme, vnl);
vname[vnl] = '\0';
spl_type_add_variant(et, vname, NULL); spl_type_add_variant(et, vname, NULL);
} }
skip_nl(ctx); skip_nl(ctx);
if (peek(ctx)->type == TOK_COMMA) { advance(ctx); skip_nl(ctx); } if (peek(ctx)->type == TOK_COMMA) {
advance(ctx);
skip_nl(ctx);
} }
if (peek(ctx)->type == TOK_R_BRACE) advance(ctx); }
if (peek(ctx)->type == TOK_R_BRACE)
advance(ctx);
} }
spl_type_compute_layout(et); spl_type_compute_layout(et);
map_put(ctx->type_defs, strdup(tname), et); map_put(ctx->type_defs, strdup(tname), et);
} else if (peek(ctx)->type == TOK_IDENT || (peek(ctx)->type >= KW_AS && peek(ctx)->type <= KW_ANY)) { } else if (peek(ctx)->type == TOK_IDENT ||
(peek(ctx)->type >= KW_AS && peek(ctx)->type <= KW_ANY)) {
spl_type_info_t *base = spl_parse_type(ctx); spl_type_info_t *base = spl_parse_type(ctx);
if (base) { if (base) {
spl_type_info_t *alias = spl_type_clone(base); spl_type_info_t *alias = spl_type_clone(base);
@@ -244,7 +270,8 @@ void parse_type_decl(spl_comp_t *ctx) {
} }
skip_nl(ctx); skip_nl(ctx);
if (peek(ctx)->type == TOK_SEMICOLON) advance(ctx); if (peek(ctx)->type == TOK_SEMICOLON)
advance(ctx);
} }
/* ============================================================ /* ============================================================
@@ -254,7 +281,8 @@ void parse_type_decl(spl_comp_t *ctx) {
void spl_parse_prog(spl_comp_t *ctx) { void spl_parse_prog(spl_comp_t *ctx) {
while (peek(ctx)->type != TOK_EOF) { while (peek(ctx)->type != TOK_EOF) {
skip_nl(ctx); skip_nl(ctx);
if (peek(ctx)->type == TOK_EOF) break; if (peek(ctx)->type == TOK_EOF)
break;
switch (peek(ctx)->type) { switch (peek(ctx)->type) {
case KW_FN: case KW_FN:
@@ -266,8 +294,10 @@ void spl_parse_prog(spl_comp_t *ctx) {
case KW_PUB: { case KW_PUB: {
advance(ctx); /* skip pub */ advance(ctx); /* skip pub */
skip_nl(ctx); skip_nl(ctx);
if (peek(ctx)->type == KW_FN) parse_fn_decl(ctx, 0, 1); if (peek(ctx)->type == KW_FN)
else if (peek(ctx)->type == KW_TYPE) parse_type_decl(ctx); parse_fn_decl(ctx, 0, 1);
else if (peek(ctx)->type == KW_TYPE)
parse_type_decl(ctx);
break; break;
} }
case TOK_SHARP: case TOK_SHARP:
@@ -275,18 +305,22 @@ void spl_parse_prog(spl_comp_t *ctx) {
advance(ctx); /* # */ advance(ctx); /* # */
if (peek(ctx)->type == TOK_L_BRACKET) { if (peek(ctx)->type == TOK_L_BRACKET) {
advance(ctx); /* [ */ advance(ctx); /* [ */
while (peek(ctx)->type != TOK_R_BRACKET && peek(ctx)->type != TOK_EOF) advance(ctx); while (peek(ctx)->type != TOK_R_BRACKET && peek(ctx)->type != TOK_EOF)
if (peek(ctx)->type == TOK_R_BRACKET) advance(ctx); advance(ctx);
if (peek(ctx)->type == TOK_R_BRACKET)
advance(ctx);
} }
skip_nl(ctx); skip_nl(ctx);
if (peek(ctx)->type == KW_FN) parse_fn_decl(ctx, 1, 0); if (peek(ctx)->type == KW_FN)
parse_fn_decl(ctx, 1, 0);
break; break;
default: { default: {
int prev = ctx->tok_idx; int prev = ctx->tok_idx;
/* Try to parse as a statement */ /* Try to parse as a statement */
spl_parse_stmt(ctx); spl_parse_stmt(ctx);
/* Safety: prevent infinite loop on unrecognized tokens */ /* Safety: prevent infinite loop on unrecognized tokens */
if (ctx->tok_idx == prev) advance(ctx); if (ctx->tok_idx == prev)
advance(ctx);
break; break;
} }
} }

View File

@@ -1,33 +1,39 @@
/* spl_stmt.c — Statement parser + codegen */ /* spl_stmt.c — Statement parser + codegen */
#include "spl_comp.h" #include "spl_comp.h"
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
static spl_tok_t *peek(spl_comp_t *ctx) { static spl_tok_t *peek(spl_comp_t *ctx) { return &vec_at(ctx->toks, ctx->tok_idx); }
return &vec_at(ctx->toks, ctx->tok_idx);
}
static spl_tok_t *advance(spl_comp_t *ctx) { static spl_tok_t *advance(spl_comp_t *ctx) {
spl_tok_t *t = &vec_at(ctx->toks, ctx->tok_idx); spl_tok_t *t = &vec_at(ctx->toks, ctx->tok_idx);
if (t->type != TOK_EOF) ctx->tok_idx++; if (t->type != TOK_EOF)
ctx->tok_idx++;
return t; return t;
} }
static int expect(spl_comp_t *ctx, spl_tok_type_t type) { static int expect(spl_comp_t *ctx, spl_tok_type_t type) {
if (peek(ctx)->type == type) { advance(ctx); return 1; } if (peek(ctx)->type == type) {
spl_comp_error(ctx, "expected '%s', got '%s'", spl_tok_type_name(type), spl_tok_type_name(peek(ctx)->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; return 0;
} }
static int match(spl_comp_t *ctx, spl_tok_type_t type) { static int match(spl_comp_t *ctx, spl_tok_type_t type) {
if (peek(ctx)->type == type) { advance(ctx); return 1; } if (peek(ctx)->type == type) {
advance(ctx);
return 1;
}
return 0; return 0;
} }
static void skip_nl(spl_comp_t *ctx) { static void skip_nl(spl_comp_t *ctx) {
while (peek(ctx)->type == TOK_ENDLINE) advance(ctx); while (peek(ctx)->type == TOK_ENDLINE)
advance(ctx);
} }
/* ============================================================ /* ============================================================
@@ -48,7 +54,8 @@ static void parse_ret_stmt(spl_comp_t *ctx) {
spl_type_t rt = ctx->current_ret_type ? ctx->current_ret_type->basic_type : SPL_VOID; spl_type_t rt = ctx->current_ret_type ? ctx->current_ret_type->basic_type : SPL_VOID;
spl_emit(ctx, SPL_RET, rt, 0); spl_emit(ctx, SPL_RET, rt, 0);
} }
if (peek(ctx)->type == TOK_SEMICOLON) advance(ctx); if (peek(ctx)->type == TOK_SEMICOLON)
advance(ctx);
} }
/* ============================================================ /* ============================================================
@@ -62,7 +69,8 @@ static void parse_var_decl(spl_comp_t *ctx, int is_const) {
spl_tok_t *name_tok = advance(ctx); spl_tok_t *name_tok = advance(ctx);
char vname[256]; char vname[256];
usize nlen = name_tok->len < 255 ? name_tok->len : 255; usize nlen = name_tok->len < 255 ? name_tok->len : 255;
memcpy(vname, name_tok->lexeme, nlen); vname[nlen] = '\0'; memcpy(vname, name_tok->lexeme, nlen);
vname[nlen] = '\0';
spl_type_info_t *var_type = NULL; spl_type_info_t *var_type = NULL;
int has_init = 0; int has_init = 0;
@@ -84,12 +92,15 @@ static void parse_var_decl(spl_comp_t *ctx, int is_const) {
if (peek(ctx)->type == TOK_COLON_ASSIGN || peek(ctx)->type == TOK_ASSIGN) { if (peek(ctx)->type == TOK_COLON_ASSIGN || peek(ctx)->type == TOK_ASSIGN) {
has_init = 1; has_init = 1;
if (peek(ctx)->type == TOK_COLON_ASSIGN) advance(ctx); if (peek(ctx)->type == TOK_COLON_ASSIGN)
else advance(ctx); /* = */ advance(ctx);
else
advance(ctx); /* = */
} }
/* Allocate stack slot */ /* Allocate stack slot */
if (!var_type) var_type = spl_type_basic(SPL_I32); /* default type */ if (!var_type)
var_type = spl_type_basic(SPL_I32); /* default type */
int slot = spl_declare_var(ctx, vname, var_type, is_const); int slot = spl_declare_var(ctx, vname, var_type, is_const);
skip_nl(ctx); skip_nl(ctx);
@@ -126,7 +137,8 @@ static void parse_var_decl(spl_comp_t *ctx, int is_const) {
} }
} }
if (peek(ctx)->type == TOK_SEMICOLON) advance(ctx); if (peek(ctx)->type == TOK_SEMICOLON)
advance(ctx);
} }
/* ============================================================ /* ============================================================
@@ -145,7 +157,8 @@ void spl_parse_block(spl_comp_t *ctx) {
} }
spl_pop_scope(ctx); spl_pop_scope(ctx);
if (peek(ctx)->type == TOK_R_BRACE) advance(ctx); if (peek(ctx)->type == TOK_R_BRACE)
advance(ctx);
} else { } else {
/* Single statement */ /* Single statement */
spl_parse_stmt(ctx); spl_parse_stmt(ctx);
@@ -257,68 +270,218 @@ static void parse_for_stmt(spl_comp_t *ctx) {
skip_nl(ctx); skip_nl(ctx);
/* Parse the iteration expression(s) */ /* Parse the iteration expression(s) */
spl_expr_result_t start = spl_parse_expr(ctx, PREC_MIN); spl_expr_result_t start_expr = spl_parse_expr(ctx, PREC_MIN);
(void)start;
if (peek(ctx)->type == TOK_RANGE) { if (peek(ctx)->type == TOK_RANGE) {
/* for begin..end as i { body } */ /* ===== Numeric range: for begin..end as i { body } ===== */
advance(ctx); /* .. */ advance(ctx); /* .. */
spl_expr_result_t end = spl_parse_expr(ctx, PREC_MIN); spl_parse_expr(ctx, PREC_MIN); /* end expression */
(void)end; /* Stack: [begin, end] */
skip_nl(ctx); skip_nl(ctx);
if (peek(ctx)->type == KW_AS) { if (peek(ctx)->type != KW_AS) {
skip_nl(ctx);
spl_parse_block(ctx);
return;
}
advance(ctx); /* as */ advance(ctx); /* as */
spl_tok_t *ivar = advance(ctx); spl_tok_t *ivar = advance(ctx);
char iname[256]; char iname[256];
usize inl = ivar->len < 255 ? ivar->len : 255; usize inl = ivar->len < 255 ? ivar->len : 255;
memcpy(iname, ivar->lexeme, inl); iname[inl] = '\0'; memcpy(iname, ivar->lexeme, inl);
iname[inl] = '\0';
/* Declare loop variable */ spl_push_scope(ctx);
spl_type_info_t *itype = spl_type_basic(SPL_I32); int islot = spl_declare_var(ctx, iname, spl_type_basic(SPL_I32), 0);
int islot = spl_declare_var(ctx, iname, itype, 0);
/* Stack: [begin, end]; swap so TOS = begin */
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
/* Store begin to i */
spl_emit(ctx, SPL_LADDR, SPL_PTR, islot);
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
spl_emit(ctx, SPL_STORE, SPL_I32, 0);
/* Stack: [end] */
spl_val_t loop_start = vec_size(ctx->prog.insns);
/* Condition: i < end */
spl_emit(ctx, SPL_LADDR, SPL_PTR, islot);
spl_emit(ctx, SPL_LOAD, SPL_I32, 0);
spl_emit(ctx, SPL_PICK, SPL_VOID, 1);
spl_emit(ctx, SPL_SLT, SPL_I32, 0);
spl_val_t bz_addr = spl_emit_bz(ctx);
/* The loop variable was already set up by the range operator */
/* Store initial value */
/* For now: we need to emit proper loop code. This is a simplification. */
int saved_loop = ctx->in_loop; int saved_loop = ctx->in_loop;
usize saved_continue = ctx->continue_target; usize saved_continue = ctx->continue_target;
usize saved_bp_count = ctx->break_patch_count; usize saved_bp_count = ctx->break_patch_count;
ctx->in_loop = 1; ctx->in_loop = 1;
ctx->continue_target = 0; /* will set after store */ ctx->continue_target = loop_start;
/* Loop: store begin to i, check i < end, body, i++ */ skip_nl(ctx);
/* Stack has: begin, end (from parsing the range expression) */ spl_parse_block(ctx); /* body */
/* Actually we need to emit proper code here. For bootstrap,
let me just handle the simple numeric for loop. */
/* For now, emit a basic loop body */ /* Increment: i = i + 1 */
spl_parse_block(ctx); spl_emit(ctx, SPL_LADDR, SPL_PTR, islot);
spl_emit(ctx, SPL_LADDR, SPL_PTR, islot);
spl_emit(ctx, SPL_LOAD, SPL_I32, 0);
spl_emit(ctx, SPL_PUSH, SPL_I32, 1);
spl_emit(ctx, SPL_ADD, SPL_I32, 0);
spl_emit(ctx, SPL_STORE, SPL_I32, 0);
/* JMP back to condition */
spl_val_t jmp_here = vec_size(ctx->prog.insns);
spl_emit(ctx, SPL_JMP, SPL_VOID, (spl_val_t)((isize)loop_start - (isize)jmp_here - 1));
/* Exit: patch bz, drop end */
spl_patch_to_here(ctx, bz_addr);
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
/* Patch breaks */
for (usize i = saved_bp_count; i < ctx->break_patch_count; i++)
spl_patch_to_here(ctx, ctx->break_patches[i]);
ctx->break_patch_count = saved_bp_count;
ctx->in_loop = saved_loop; ctx->in_loop = saved_loop;
ctx->continue_target = saved_continue; ctx->continue_target = saved_continue;
ctx->break_patch_count = saved_bp_count;
spl_pop_scope(ctx);
return;
} }
} else if (peek(ctx)->type == TOK_COMMA) {
/* for slice, 0.. as val, idx { body } — skip for now */ /* ===== Slice iteration: for slice [as val |, range as val, idx] ===== */
int has_idx = 0;
if (peek(ctx)->type == TOK_COMMA) {
advance(ctx); /* , */ advance(ctx); /* , */
spl_parse_expr(ctx, PREC_MIN); /* skip the range */ spl_parse_expr(ctx, PREC_MIN); /* parse start of range (e.g. 0) */
if (peek(ctx)->type == KW_AS) { if (peek(ctx)->type == TOK_RANGE) {
advance(ctx); advance(ctx); /* .. */
advance(ctx); /* val */ /* consume optional end expression */
if (peek(ctx)->type != KW_AS && peek(ctx)->type != TOK_COMMA &&
peek(ctx)->type != TOK_L_BRACE && peek(ctx)->type != TOK_ENDLINE &&
peek(ctx)->type != TOK_EOF)
spl_parse_expr(ctx, PREC_MIN);
}
has_idx = 1;
/* Range pushed a value; we manage our own idx, drop it */
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
}
if (peek(ctx)->type != KW_AS) {
skip_nl(ctx);
spl_parse_block(ctx);
return;
}
advance(ctx); /* as */
/* Parse val variable name */
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';
/* Parse optional idx variable name */
char iname[256] = {0};
if (peek(ctx)->type == TOK_COMMA) { if (peek(ctx)->type == TOK_COMMA) {
advance(ctx); advance(ctx);
advance(ctx); /* idx */ spl_tok_t *itok = advance(ctx);
usize inl = itok->len < 255 ? itok->len : 255;
memcpy(iname, itok->lexeme, inl);
iname[inl] = '\0';
} }
/* Stack: [slice_addr] or whatever the slice expression left */
spl_push_scope(ctx);
int idx_slot = -1;
if (iname[0])
idx_slot = spl_declare_var(ctx, iname, spl_type_basic(SPL_I32), 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;
} }
if (!elem_type)
elem_type = spl_type_basic(SPL_I32);
int val_slot = spl_declare_var(ctx, vname, elem_type, 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_I32, 0);
spl_emit(ctx, SPL_PUSH, SPL_I32, 0);
/* Stack: [ptr, len, idx=0] */
spl_val_t loop_start = vec_size(ctx->prog.insns);
/* 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_SLT, SPL_I32, 0);
spl_val_t bz_addr = spl_emit_bz(ctx);
/* Store current idx to idx variable */
if (idx_slot >= 0) {
spl_emit(ctx, SPL_PICK, SPL_VOID, 0); /* copy idx (TOS) */
spl_emit(ctx, SPL_LADDR, SPL_PTR, idx_slot);
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
spl_emit(ctx, SPL_STORE, SPL_I32, 0);
}
/* 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 && elem_type->byte_size) ? elem_type->byte_size : 4;
spl_emit(ctx, SPL_PUSH, SPL_U64, sizeof(spl_val_t));
spl_emit(ctx, SPL_MUL, SPL_U64, 0);
spl_emit(ctx, SPL_ADD, SPL_U64, 0);
spl_emit(ctx, SPL_LOAD, SPL_I32, 0);
spl_emit(ctx, SPL_LADDR, SPL_PTR, val_slot);
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
spl_emit(ctx, SPL_STORE, SPL_I32, 0);
/* Loop context */
int saved_loop = ctx->in_loop;
usize saved_continue = ctx->continue_target;
usize saved_bp_count = ctx->break_patch_count;
ctx->in_loop = 1;
ctx->continue_target = loop_start;
skip_nl(ctx); skip_nl(ctx);
spl_parse_block(ctx); spl_parse_block(ctx); /* body */
} else {
/* for ident in ... — skip */ /* Increment idx */
skip_nl(ctx); spl_emit(ctx, SPL_PICK, SPL_VOID, 0); /* copy idx */
spl_parse_block(ctx); spl_emit(ctx, SPL_PUSH, SPL_I32, 1);
} spl_emit(ctx, SPL_ADD, SPL_I32, 0);
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* replace old idx with new */
/* JMP back to condition */
spl_val_t jmp_here = vec_size(ctx->prog.insns);
spl_emit(ctx, SPL_JMP, SPL_VOID, (spl_val_t)((isize)loop_start - (isize)jmp_here - 1));
/* 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 */
/* Patch breaks */
for (usize i = saved_bp_count; i < ctx->break_patch_count; i++)
spl_patch_to_here(ctx, ctx->break_patches[i]);
ctx->break_patch_count = saved_bp_count;
ctx->in_loop = saved_loop;
ctx->continue_target = saved_continue;
spl_pop_scope(ctx);
} }
/* ============================================================ /* ============================================================
@@ -338,7 +501,8 @@ static void parse_break_stmt(spl_comp_t *ctx) {
ctx->break_patch_cap = new_cap; ctx->break_patch_cap = new_cap;
} }
ctx->break_patches[ctx->break_patch_count++] = addr; ctx->break_patches[ctx->break_patch_count++] = addr;
if (peek(ctx)->type == TOK_SEMICOLON) advance(ctx); if (peek(ctx)->type == TOK_SEMICOLON)
advance(ctx);
} }
static void parse_continue_stmt(spl_comp_t *ctx) { static void parse_continue_stmt(spl_comp_t *ctx) {
@@ -349,7 +513,8 @@ static void parse_continue_stmt(spl_comp_t *ctx) {
/* Emit JMP with relative offset to continue_target */ /* Emit JMP with relative offset to continue_target */
spl_val_t here = vec_size(ctx->prog.insns); 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)); spl_emit(ctx, SPL_JMP, SPL_VOID, (spl_val_t)((isize)ctx->continue_target - (isize)here - 1));
if (peek(ctx)->type == TOK_SEMICOLON) advance(ctx); if (peek(ctx)->type == TOK_SEMICOLON)
advance(ctx);
} }
/* ============================================================ /* ============================================================
@@ -379,8 +544,10 @@ static void parse_extern_decl(spl_comp_t *ctx) {
advance(ctx); /* # */ advance(ctx); /* # */
expect(ctx, TOK_L_BRACKET); expect(ctx, TOK_L_BRACKET);
/* Skip extern("vm") or just look for fn */ /* Skip extern("vm") or just look for fn */
while (peek(ctx)->type != TOK_R_BRACKET && peek(ctx)->type != TOK_EOF) advance(ctx); while (peek(ctx)->type != TOK_R_BRACKET && peek(ctx)->type != TOK_EOF)
if (peek(ctx)->type == TOK_R_BRACKET) advance(ctx); advance(ctx);
if (peek(ctx)->type == TOK_R_BRACKET)
advance(ctx);
skip_nl(ctx); skip_nl(ctx);
@@ -390,7 +557,8 @@ static void parse_extern_decl(spl_comp_t *ctx) {
spl_tok_t *fname_tok = advance(ctx); spl_tok_t *fname_tok = advance(ctx);
char fn_name[256]; char fn_name[256];
usize fnl = fname_tok->len < 255 ? fname_tok->len : 255; usize fnl = fname_tok->len < 255 ? fname_tok->len : 255;
memcpy(fn_name, fname_tok->lexeme, fnl); fn_name[fnl] = '\0'; memcpy(fn_name, fname_tok->lexeme, fnl);
fn_name[fnl] = '\0';
skip_nl(ctx); skip_nl(ctx);
expect(ctx, TOK_L_PAREN); expect(ctx, TOK_L_PAREN);
@@ -409,8 +577,15 @@ static void parse_extern_decl(spl_comp_t *ctx) {
} }
nparams++; nparams++;
skip_nl(ctx); skip_nl(ctx);
if (peek(ctx)->type == TOK_COMMA) { advance(ctx); skip_nl(ctx); continue; } if (peek(ctx)->type == TOK_COMMA) {
if (peek(ctx)->type == TOK_ELLIPSIS) { advance(ctx); skip_nl(ctx); } /* variadic */ advance(ctx);
skip_nl(ctx);
continue;
}
if (peek(ctx)->type == TOK_ELLIPSIS) {
advance(ctx);
skip_nl(ctx);
} /* variadic */
break; break;
} }
} }
@@ -421,13 +596,15 @@ static void parse_extern_decl(spl_comp_t *ctx) {
spl_type_info_t *ret_type = spl_type_basic(SPL_VOID); spl_type_info_t *ret_type = spl_type_basic(SPL_VOID);
if (peek(ctx)->type != TOK_SEMICOLON && peek(ctx)->type != TOK_L_BRACE) { if (peek(ctx)->type != TOK_SEMICOLON && peek(ctx)->type != TOK_L_BRACE) {
ret_type = spl_parse_type(ctx); ret_type = spl_parse_type(ctx);
if (!ret_type) ret_type = spl_type_basic(SPL_VOID); if (!ret_type)
ret_type = spl_type_basic(SPL_VOID);
skip_nl(ctx); skip_nl(ctx);
} }
spl_declare_func(ctx, fn_name, ret_type, nparams, 1, 0); spl_declare_func(ctx, fn_name, ret_type, nparams, 1, 0);
if (peek(ctx)->type == TOK_SEMICOLON) advance(ctx); if (peek(ctx)->type == TOK_SEMICOLON)
advance(ctx);
} }
} }
@@ -437,10 +614,10 @@ static void parse_extern_decl(spl_comp_t *ctx) {
/* Check if token type is an assignment operator */ /* Check if token type is an assignment operator */
static int is_assign_op(spl_tok_type_t t) { static int is_assign_op(spl_tok_type_t t) {
return t == TOK_ASSIGN || t == TOK_ASSIGN_ADD || t == TOK_ASSIGN_SUB || return t == TOK_ASSIGN || t == TOK_ASSIGN_ADD || t == TOK_ASSIGN_SUB || t == TOK_ASSIGN_MUL ||
t == TOK_ASSIGN_MUL || t == TOK_ASSIGN_DIV || t == TOK_ASSIGN_MOD || t == TOK_ASSIGN_DIV || t == TOK_ASSIGN_MOD || t == TOK_ASSIGN_AND ||
t == TOK_ASSIGN_AND || t == TOK_ASSIGN_OR || t == TOK_ASSIGN_XOR || t == TOK_ASSIGN_OR || t == TOK_ASSIGN_XOR || t == TOK_ASSIGN_L_SH ||
t == TOK_ASSIGN_L_SH || t == TOK_ASSIGN_R_SH; t == TOK_ASSIGN_R_SH;
} }
static void parse_expr_stmt(spl_comp_t *ctx) { static void parse_expr_stmt(spl_comp_t *ctx) {
@@ -462,14 +639,19 @@ static void parse_expr_stmt(spl_comp_t *ctx) {
is_assign = is_assign_op(vec_at(ctx->toks, look).type); is_assign = is_assign_op(vec_at(ctx->toks, look).type);
} }
if (is_assign) ctx->addr_of_mode = 1; if (is_assign)
ctx->addr_of_mode = 1;
spl_expr_result_t expr = spl_parse_expr(ctx, PREC_MIN); spl_expr_result_t expr = spl_parse_expr(ctx, PREC_MIN);
if (is_assign) ctx->addr_of_mode = 0; if (is_assign)
ctx->addr_of_mode = 0;
if (!is_assign && expr.type) spl_emit(ctx, SPL_DROP, SPL_VOID, 0); if (!is_assign && expr.type)
if (peek(ctx)->type == TOK_SEMICOLON) advance(ctx); spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
if (peek(ctx)->type == TOK_SEMICOLON)
advance(ctx);
/* Safety: if no token was consumed, advance to prevent infinite loop */ /* Safety: if no token was consumed, advance to prevent infinite loop */
if (ctx->tok_idx == prev) advance(ctx); if (ctx->tok_idx == prev)
advance(ctx);
} }
/* ============================================================ /* ============================================================
@@ -479,7 +661,8 @@ static void parse_expr_stmt(spl_comp_t *ctx) {
void spl_parse_stmt(spl_comp_t *ctx) { void spl_parse_stmt(spl_comp_t *ctx) {
skip_nl(ctx); skip_nl(ctx);
if (peek(ctx)->type == TOK_EOF || peek(ctx)->type == TOK_R_BRACE) return; if (peek(ctx)->type == TOK_EOF || peek(ctx)->type == TOK_R_BRACE)
return;
switch (peek(ctx)->type) { switch (peek(ctx)->type) {
case KW_RET: case KW_RET:
@@ -521,7 +704,7 @@ 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_SHARP: /* #[extern(...)] */
parse_extern_decl(ctx); parse_extern_decl(ctx);
break; break;
default: default:

View File

@@ -391,7 +391,8 @@ spl_type_info_t *spl_parse_type(spl_comp_t *ctx) {
} }
spl_type_info_t *spl_resolve_type(spl_comp_t *ctx, const char *name) { spl_type_info_t *spl_resolve_type(spl_comp_t *ctx, const char *name) {
if (!ctx || !name) return NULL; if (!ctx || !name)
return NULL;
spl_type_info_t *found = NULL; spl_type_info_t *found = NULL;
map_get(ctx->type_defs, name, &found); map_get(ctx->type_defs, name, &found);
return found; return found;