stage1 优化重构代码
This commit is contained in:
@@ -372,10 +372,133 @@ static spl_expr_result_t parse_array_literal(spl_comp_t *ctx) {
|
||||
return (spl_expr_result_t){arr_type, 0};
|
||||
}
|
||||
|
||||
/* Parse slice inline literal: { .ptr = expr, .len = expr }
|
||||
* Expects base address on TOS, consumes it. Stores ptr to base+0, len to base+sizeof(spl_val_t). */
|
||||
static void parse_slice_inline(spl_comp_t *ctx) {
|
||||
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 *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);
|
||||
|
||||
spl_emit(ctx, SPL_DUP, SPL_VOID, 0); /* [addr, addr] */
|
||||
if (strcmp(fname, "ptr") == 0) {
|
||||
spl_parse_expr(ctx, PREC_MIN);
|
||||
spl_emit(ctx, SPL_STORE, SPL_PTR, 0); /* [addr] */
|
||||
} else if (strcmp(fname, "len") == 0) {
|
||||
spl_emit(ctx, SPL_PUSH, SPL_USIZE, sizeof(spl_val_t));
|
||||
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0); /* [addr, addr+8] */
|
||||
spl_parse_expr(ctx, PREC_MIN);
|
||||
spl_emit(ctx, SPL_STORE, SPL_USIZE, 0); /* [addr] */
|
||||
}
|
||||
skip_nl(ctx);
|
||||
}
|
||||
expect(ctx, TOK_R_BRACE);
|
||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* drop addr */
|
||||
}
|
||||
|
||||
/* Parse a single .field = value in a struct literal.
|
||||
* Iterates fields to find the match, emits LADDR + offset, and handles
|
||||
* value parsing (slice inline, array inline, multi-slot struct, basic store).
|
||||
* Reused by both TYPE_STRUCT and TYPE_ENUM variant struct data. */
|
||||
static void parse_one_field_init(spl_comp_t *ctx, spl_field_vec_t *fields,
|
||||
int base_offset, usize extra_offset) {
|
||||
if (peek(ctx)->type == TOK_DOT)
|
||||
advance(ctx);
|
||||
spl_tok_t *ftok = advance(ctx);
|
||||
char fname[256];
|
||||
spl_tok_copy_name(ftok, fname, sizeof(fname));
|
||||
skip_nl(ctx);
|
||||
if (peek(ctx)->type == TOK_ASSIGN)
|
||||
advance(ctx);
|
||||
skip_nl(ctx);
|
||||
|
||||
vec_for(*fields, fi) {
|
||||
spl_field_t *f = &vec_at(*fields, fi);
|
||||
if (strcmp(f->name, fname) == 0) {
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_offset);
|
||||
usize byte_off = extra_offset + f->offset;
|
||||
if (byte_off > 0) {
|
||||
spl_emit(ctx, SPL_PUSH, SPL_USIZE, byte_off);
|
||||
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
|
||||
}
|
||||
if (f->type && f->type->kind == TYPE_SLICE &&
|
||||
peek(ctx)->type == TOK_L_BRACE) {
|
||||
parse_slice_inline(ctx);
|
||||
} else if (f->type && f->type->kind == TYPE_ARRAY &&
|
||||
peek(ctx)->type == TOK_L_BRACKET) {
|
||||
/* Inline array initializer: [N]Type{val1, val2, ...} */
|
||||
advance(ctx); /* [ */
|
||||
skip_nl(ctx);
|
||||
int len_val;
|
||||
if (!spl_parse_int_literal(ctx, &len_val)) {
|
||||
spl_comp_error(ctx, "expected array length");
|
||||
return;
|
||||
}
|
||||
usize arr_len = (usize)len_val;
|
||||
skip_nl(ctx);
|
||||
expect(ctx, TOK_R_BRACKET);
|
||||
skip_nl(ctx);
|
||||
spl_type_info_t *elem_type = spl_parse_type(ctx);
|
||||
skip_nl(ctx);
|
||||
expect(ctx, TOK_L_BRACE);
|
||||
skip_nl(ctx);
|
||||
usize stride = spl_type_elem_stride(elem_type);
|
||||
spl_type_t st = spl_type_emit_type(elem_type);
|
||||
for (usize i = 0; i < arr_len; i++) {
|
||||
if (i > 0) {
|
||||
if (peek(ctx)->type == TOK_COMMA) advance(ctx);
|
||||
skip_nl(ctx);
|
||||
}
|
||||
spl_emit(ctx, SPL_DUP, SPL_VOID, 0);
|
||||
if (i > 0) {
|
||||
spl_emit(ctx, SPL_PUSH, SPL_USIZE, i * stride);
|
||||
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
|
||||
}
|
||||
spl_parse_expr(ctx, PREC_MIN);
|
||||
spl_emit(ctx, SPL_STORE, st, 0);
|
||||
skip_nl(ctx);
|
||||
}
|
||||
if (peek(ctx)->type == TOK_COMMA) advance(ctx);
|
||||
skip_nl(ctx);
|
||||
expect(ctx, TOK_R_BRACE);
|
||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
|
||||
} else if (f->type &&
|
||||
(f->type->kind == TYPE_STRUCT || f->type->kind == TYPE_ENUM) &&
|
||||
spl_type_size(f->type) > sizeof(spl_val_t)) {
|
||||
spl_expr_result_t fv = spl_parse_expr(ctx, PREC_MIN);
|
||||
(void)fv;
|
||||
usize nslots = (spl_type_size(f->type) + sizeof(spl_val_t) - 1) / sizeof(spl_val_t);
|
||||
spl_emit_copy_slots(ctx, base_offset + (int)extra_offset + f->offset, nslots);
|
||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
|
||||
} else {
|
||||
spl_expr_result_t fv = spl_parse_expr(ctx, PREC_MIN);
|
||||
(void)fv;
|
||||
spl_emit(ctx, SPL_STORE, spl_type_emit_type(f->type), 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse struct/enum literal: Type { .field = val, ... }
|
||||
* Allocates temp slots for the value, returns lvalue (addr on stack).
|
||||
* For types fitting in one slot, pushes the packed value directly. */
|
||||
static spl_expr_result_t parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *type) {
|
||||
spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *type) {
|
||||
usize sz = spl_type_size(type);
|
||||
int base_offset = ctx->current_local_bytes;
|
||||
ctx->current_local_bytes += (int)((sz + sizeof(spl_val_t) - 1) & ~(sizeof(spl_val_t) - 1));
|
||||
@@ -396,134 +519,41 @@ static spl_expr_result_t parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *
|
||||
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_offset);
|
||||
if (f->offset > 0) {
|
||||
spl_emit(ctx, SPL_PUSH, SPL_USIZE, f->offset);
|
||||
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
|
||||
}
|
||||
/* Handle inline slice initializer: { .ptr = expr, .len = expr } */
|
||||
if (f->type && f->type->kind == TYPE_SLICE &&
|
||||
peek(ctx)->type == TOK_L_BRACE) {
|
||||
/* Stack: [field_addr] — slice struct start addr */
|
||||
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);
|
||||
|
||||
spl_emit(ctx, SPL_DUP, SPL_VOID, 0); /* [addr, addr] */
|
||||
if (strcmp(sfname, "ptr") == 0) {
|
||||
spl_expr_result_t pv = spl_parse_expr(ctx, PREC_MIN);
|
||||
(void)pv;
|
||||
/* Stack: [addr, addr, ptr_val] — STORE needs [addr, val] */
|
||||
spl_emit(ctx, SPL_STORE, SPL_PTR, 0); /* [addr] */
|
||||
} else if (strcmp(sfname, "len") == 0) {
|
||||
spl_emit(ctx, SPL_PUSH, SPL_USIZE, sizeof(spl_val_t));
|
||||
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0); /* [addr, addr+8] */
|
||||
spl_expr_result_t lv = spl_parse_expr(ctx, PREC_MIN);
|
||||
(void)lv;
|
||||
/* Stack: [addr, addr+8, len_val] — STORE needs [addr, val] */
|
||||
spl_emit(ctx, SPL_STORE, SPL_USIZE, 0); /* [addr] */
|
||||
}
|
||||
skip_nl(ctx);
|
||||
}
|
||||
expect(ctx, TOK_R_BRACE);
|
||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* drop addr */
|
||||
} else if (f->type && f->type->kind == TYPE_ARRAY &&
|
||||
peek(ctx)->type == TOK_L_BRACKET) {
|
||||
/* Inline array initializer: [N]Type{val1, val2, ...}
|
||||
* Stack: [field_addr] — store each element at computed offsets */
|
||||
advance(ctx); /* [ */
|
||||
skip_nl(ctx);
|
||||
int len_val;
|
||||
if (!spl_parse_int_literal(ctx, &len_val)) {
|
||||
spl_comp_error(ctx, "expected array length");
|
||||
spl_expr_result_t r = {0};
|
||||
return r;
|
||||
}
|
||||
usize arr_len = (usize)len_val;
|
||||
skip_nl(ctx);
|
||||
expect(ctx, TOK_R_BRACKET);
|
||||
skip_nl(ctx);
|
||||
spl_type_info_t *elem_type = spl_parse_type(ctx);
|
||||
skip_nl(ctx);
|
||||
expect(ctx, TOK_L_BRACE);
|
||||
skip_nl(ctx);
|
||||
usize stride = spl_type_elem_stride(elem_type);
|
||||
spl_type_t st = spl_type_emit_type(elem_type);
|
||||
for (usize i = 0; i < arr_len; i++) {
|
||||
if (i > 0) {
|
||||
if (peek(ctx)->type == TOK_COMMA)
|
||||
advance(ctx);
|
||||
skip_nl(ctx);
|
||||
}
|
||||
spl_emit(ctx, SPL_DUP, SPL_VOID, 0);
|
||||
if (i > 0) {
|
||||
spl_emit(ctx, SPL_PUSH, SPL_USIZE, i * stride);
|
||||
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
|
||||
}
|
||||
spl_parse_expr(ctx, PREC_MIN);
|
||||
spl_emit(ctx, SPL_STORE, st, 0);
|
||||
skip_nl(ctx);
|
||||
}
|
||||
if (peek(ctx)->type == TOK_COMMA)
|
||||
advance(ctx);
|
||||
skip_nl(ctx);
|
||||
expect(ctx, TOK_R_BRACE);
|
||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
|
||||
} else if (f->type &&
|
||||
(f->type->kind == TYPE_STRUCT || f->type->kind == TYPE_ENUM) &&
|
||||
spl_type_size(f->type) > sizeof(spl_val_t)) {
|
||||
/* Multi-slot struct/enum value: copy temp → field slot by slot
|
||||
* Stack: [field_addr, temp_addr] */
|
||||
spl_expr_result_t fv = spl_parse_expr(ctx, PREC_MIN);
|
||||
(void)fv;
|
||||
usize nslots = (spl_type_size(f->type) + sizeof(spl_val_t) - 1) /
|
||||
sizeof(spl_val_t);
|
||||
spl_emit_copy_slots(ctx, base_offset + f->offset, nslots);
|
||||
/* Drop field_addr from stack (copy_slots consumed temp_addr) */
|
||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
|
||||
} else {
|
||||
spl_expr_result_t fv = spl_parse_expr(ctx, PREC_MIN);
|
||||
(void)fv;
|
||||
spl_emit(ctx, SPL_STORE, spl_type_emit_type(f->type), 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Unrecognized token (not .field or ,), advance to prevent infinite loop */
|
||||
if (peek(ctx)->type != TOK_DOT) {
|
||||
if (peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF)
|
||||
advance(ctx);
|
||||
skip_nl(ctx);
|
||||
continue;
|
||||
}
|
||||
parse_one_field_init(ctx, &type->fields, base_offset, 0);
|
||||
skip_nl(ctx);
|
||||
}
|
||||
} else if (type->kind == TYPE_SLICE) {
|
||||
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];
|
||||
spl_tok_copy_name(ftok, fname, sizeof(fname));
|
||||
skip_nl(ctx);
|
||||
if (peek(ctx)->type == TOK_ASSIGN)
|
||||
advance(ctx);
|
||||
skip_nl(ctx);
|
||||
if (strcmp(fname, "ptr") == 0) {
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_offset);
|
||||
spl_parse_expr(ctx, PREC_MIN);
|
||||
spl_emit(ctx, SPL_STORE, SPL_PTR, 0);
|
||||
} else if (strcmp(fname, "len") == 0) {
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_offset);
|
||||
spl_emit(ctx, SPL_PUSH, SPL_USIZE, sizeof(spl_val_t));
|
||||
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
|
||||
spl_parse_expr(ctx, PREC_MIN);
|
||||
spl_emit(ctx, SPL_STORE, SPL_USIZE, 0);
|
||||
}
|
||||
skip_nl(ctx);
|
||||
}
|
||||
@@ -564,92 +594,9 @@ static spl_expr_result_t parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *
|
||||
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_offset);
|
||||
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);
|
||||
}
|
||||
/* Handle inline slice initializer */
|
||||
if (sf->type && sf->type->kind == TYPE_SLICE &&
|
||||
peek(ctx)->type == TOK_L_BRACE) {
|
||||
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 *ssftok = advance(ctx);
|
||||
char ssfname[256];
|
||||
usize ssfnl = ssftok->len < 255 ? ssftok->len : 255;
|
||||
memcpy(ssfname, ssftok->lexeme, ssfnl);
|
||||
ssfname[ssfnl] = '\0';
|
||||
skip_nl(ctx);
|
||||
if (peek(ctx)->type == TOK_ASSIGN)
|
||||
advance(ctx);
|
||||
skip_nl(ctx);
|
||||
|
||||
spl_emit(ctx, SPL_DUP, SPL_VOID, 0);
|
||||
if (strcmp(ssfname, "ptr") == 0) {
|
||||
spl_expr_result_t pv =
|
||||
spl_parse_expr(ctx, PREC_MIN);
|
||||
(void)pv;
|
||||
spl_emit(ctx, SPL_STORE, SPL_PTR, 0);
|
||||
} else if (strcmp(ssfname, "len") == 0) {
|
||||
spl_emit(ctx, SPL_PUSH, SPL_USIZE,
|
||||
sizeof(spl_val_t));
|
||||
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
|
||||
spl_expr_result_t lv =
|
||||
spl_parse_expr(ctx, PREC_MIN);
|
||||
(void)lv;
|
||||
spl_emit(ctx, SPL_STORE, SPL_USIZE, 0);
|
||||
}
|
||||
skip_nl(ctx);
|
||||
}
|
||||
expect(ctx, TOK_R_BRACE);
|
||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
|
||||
} else if (sf->type &&
|
||||
(sf->type->kind == TYPE_STRUCT ||
|
||||
sf->type->kind == TYPE_ENUM) &&
|
||||
spl_type_size(sf->type) > sizeof(spl_val_t)) {
|
||||
/* Multi-slot struct field in enum variant data */
|
||||
spl_expr_result_t sfv = spl_parse_expr(ctx, PREC_MIN);
|
||||
(void)sfv;
|
||||
usize nslots =
|
||||
(spl_type_size(sf->type) + sizeof(spl_val_t) - 1) /
|
||||
sizeof(spl_val_t);
|
||||
spl_emit_copy_slots(
|
||||
ctx, base_offset + (int)DATA_OFFSET + sf->offset,
|
||||
nslots);
|
||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
|
||||
} else {
|
||||
spl_expr_result_t sfv = spl_parse_expr(ctx, PREC_MIN);
|
||||
(void)sfv;
|
||||
spl_emit(ctx, SPL_STORE, spl_type_emit_type(sf->type), 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (peek(ctx)->type != TOK_DOT)
|
||||
break;
|
||||
parse_one_field_init(ctx, &v->data_type->fields, base_offset, DATA_OFFSET);
|
||||
skip_nl(ctx);
|
||||
}
|
||||
expect(ctx, TOK_R_BRACE);
|
||||
@@ -805,7 +752,7 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
|
||||
/* 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);
|
||||
return spl_parse_struct_literal(ctx, ttype);
|
||||
}
|
||||
spl_expr_result_t r = {ttype, 0};
|
||||
return r;
|
||||
@@ -880,84 +827,71 @@ static spl_expr_result_t parse_prefix_op(spl_comp_t *ctx) {
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* Main expression parser (top-level)
|
||||
* Primary expression (prefix part of Pratt parser)
|
||||
* ============================================================ */
|
||||
|
||||
spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
|
||||
skip_nl(ctx);
|
||||
|
||||
static spl_expr_result_t parse_primary_expr(spl_comp_t *ctx) {
|
||||
spl_tok_t *tok = peek(ctx);
|
||||
if (!tok) {
|
||||
spl_expr_result_t r = {0};
|
||||
return r;
|
||||
}
|
||||
|
||||
spl_expr_result_t left = {0};
|
||||
|
||||
switch (tok->type) {
|
||||
case TOK_INT_LITERAL:
|
||||
left = parse_int_literal(ctx);
|
||||
break;
|
||||
return parse_int_literal(ctx);
|
||||
case TOK_FLOAT_LITERAL:
|
||||
left = parse_float_literal(ctx);
|
||||
break;
|
||||
return parse_float_literal(ctx);
|
||||
case TOK_CHAR_LITERAL:
|
||||
left = parse_char_literal(ctx);
|
||||
break;
|
||||
return parse_char_literal(ctx);
|
||||
case TOK_STRING_LITERAL:
|
||||
left = parse_string_literal(ctx);
|
||||
break;
|
||||
return parse_string_literal(ctx);
|
||||
case KW_TRUE:
|
||||
advance(ctx);
|
||||
spl_emit(ctx, SPL_PUSH, SPL_I32, 1);
|
||||
left = (spl_expr_result_t){spl_type_basic(SPL_I32), 0};
|
||||
break;
|
||||
return (spl_expr_result_t){spl_type_basic(SPL_I32), 0};
|
||||
case KW_FALSE:
|
||||
advance(ctx);
|
||||
spl_emit(ctx, SPL_PUSH, SPL_I32, 0);
|
||||
left = (spl_expr_result_t){spl_type_basic(SPL_I32), 0};
|
||||
break;
|
||||
return (spl_expr_result_t){spl_type_basic(SPL_I32), 0};
|
||||
case KW_NULL:
|
||||
advance(ctx);
|
||||
spl_emit(ctx, SPL_PUSH, SPL_PTR, 0);
|
||||
left = (spl_expr_result_t){spl_type_basic(SPL_PTR), 0};
|
||||
break;
|
||||
return (spl_expr_result_t){spl_type_basic(SPL_PTR), 0};
|
||||
case TOK_IDENT:
|
||||
case KW_BOOL:
|
||||
case KW_VOID:
|
||||
case KW_ANY:
|
||||
left = parse_ident(ctx);
|
||||
break;
|
||||
return parse_ident(ctx);
|
||||
case TOK_L_PAREN:
|
||||
left = parse_group(ctx);
|
||||
break;
|
||||
return parse_group(ctx);
|
||||
case TOK_SUB:
|
||||
case TOK_NOT:
|
||||
case TOK_BIT_NOT:
|
||||
case TOK_AND:
|
||||
case TOK_MUL:
|
||||
left = parse_prefix_op(ctx);
|
||||
break;
|
||||
return parse_prefix_op(ctx);
|
||||
case TOK_L_BRACKET:
|
||||
left = parse_array_literal(ctx);
|
||||
break;
|
||||
return parse_array_literal(ctx);
|
||||
case TOK_L_BRACE:
|
||||
return spl_parse_block_expr(ctx);
|
||||
case TOK_AT: {
|
||||
/* @builtin(...) — compiler intrinsic */
|
||||
advance(ctx); /* consume @ */
|
||||
advance(ctx);
|
||||
skip_nl(ctx);
|
||||
tok = peek(ctx);
|
||||
if (!tok || tok->type != TOK_IDENT) {
|
||||
spl_comp_error(ctx, "expected builtin name after '@'");
|
||||
break;
|
||||
spl_expr_result_t r = {0};
|
||||
return r;
|
||||
}
|
||||
char bname[256];
|
||||
spl_tok_copy_name(tok, bname, sizeof bname);
|
||||
advance(ctx); /* consume builtin name */
|
||||
advance(ctx);
|
||||
|
||||
if (strcmp(bname, "dbg") == 0) {
|
||||
/* @dbg(...) — print VM debug info */
|
||||
if (peek(ctx)->type == TOK_L_PAREN) {
|
||||
advance(ctx); /* skip ( */
|
||||
advance(ctx);
|
||||
int nargs = 0;
|
||||
if (peek(ctx)->type != TOK_R_PAREN) {
|
||||
for (;;) {
|
||||
@@ -971,37 +905,40 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
|
||||
}
|
||||
}
|
||||
expect(ctx, TOK_R_PAREN);
|
||||
|
||||
/* Emit SPL_DBG and DROP for each arg */
|
||||
for (int i = 0; i < nargs; i++) {
|
||||
spl_emit(ctx, SPL_DBG, SPL_USIZE, 0);
|
||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
|
||||
}
|
||||
if (nargs == 0) {
|
||||
if (nargs == 0)
|
||||
spl_emit(ctx, SPL_DBG, SPL_VOID, 0);
|
||||
}
|
||||
} else {
|
||||
/* @dbg with no parens — just debug */
|
||||
spl_emit(ctx, SPL_DBG, SPL_VOID, 0);
|
||||
}
|
||||
/* @dbg is a void expression */
|
||||
left = (spl_expr_result_t){spl_type_basic(SPL_VOID), 0};
|
||||
return (spl_expr_result_t){spl_type_basic(SPL_VOID), 0};
|
||||
} else {
|
||||
spl_comp_error(ctx, "unknown builtin '@%s'", bname);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* If it's a keyword-as-type (i32, u8, etc.), parse as function call target or type
|
||||
* constructor */
|
||||
if (peek(ctx)->type >= KW_AS && peek(ctx)->type <= KW_ANY) {
|
||||
left = parse_ident(ctx);
|
||||
} else {
|
||||
spl_expr_result_t r = {0};
|
||||
return r;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (peek(ctx)->type >= KW_AS && peek(ctx)->type <= KW_ANY) {
|
||||
return parse_ident(ctx);
|
||||
}
|
||||
spl_expr_result_t r = {0};
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* Main expression parser (top-level)
|
||||
* ============================================================ */
|
||||
|
||||
spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
|
||||
skip_nl(ctx);
|
||||
spl_expr_result_t left = parse_primary_expr(ctx);
|
||||
if (!left.type)
|
||||
return left;
|
||||
|
||||
/* Infix parsing (precedence climbing) */
|
||||
while (1) {
|
||||
@@ -1220,8 +1157,10 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Parse index/begin expression before checking for range */
|
||||
spl_parse_expr(ctx, PREC_MIN);
|
||||
|
||||
/* Check for slice: expr[begin..end] or expr[begin..] */
|
||||
spl_expr_result_t index = spl_parse_expr(ctx, PREC_MIN);
|
||||
if (peek(ctx)->type == TOK_RANGE) {
|
||||
advance(ctx); /* skip .. */
|
||||
spl_expr_result_t end_expr = {0};
|
||||
@@ -1394,3 +1333,105 @@ static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, sp
|
||||
}
|
||||
return (spl_expr_result_t){spl_type_basic(SPL_I32), 0};
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* Match arm pattern comparison
|
||||
*
|
||||
* These functions handle the expression-level comparison between
|
||||
* a saved match value and an arm pattern. They belong here in
|
||||
* the expr layer so match arms compose as "enhanced if-conditions"
|
||||
* rather than requiring stmt.c to emit raw comparison instructions.
|
||||
* ============================================================ */
|
||||
|
||||
spl_enum_variant_t *spl_emit_match_enum_cmp(spl_comp_t *ctx, spl_type_info_t *enum_type,
|
||||
int val_offset) {
|
||||
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';
|
||||
|
||||
vec_for(enum_type->variants, vi) {
|
||||
spl_enum_variant_t *v = &vec_at(enum_type->variants, vi);
|
||||
if (strcmp(v->name, vname) == 0) {
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, val_offset);
|
||||
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, v->value);
|
||||
spl_emit(ctx, SPL_EQ, SPL_I32, 0);
|
||||
return v;
|
||||
}
|
||||
}
|
||||
spl_comp_error(ctx, "unknown variant '%s' in match", vname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void spl_emit_match_value_cmp(spl_comp_t *ctx, int val_offset) {
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, val_offset);
|
||||
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
|
||||
spl_parse_expr(ctx, PREC_LOGOR);
|
||||
spl_emit(ctx, SPL_EQ, SPL_I32, 0);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* Return instruction — emit SPL_RET with correct type
|
||||
* ============================================================ */
|
||||
|
||||
void spl_emit_ret(spl_comp_t *ctx, spl_type_info_t *ret_type) {
|
||||
spl_type_t rt = SPL_VOID;
|
||||
if (ret_type) {
|
||||
if (ret_type->kind == TYPE_BASIC) {
|
||||
rt = ret_type->basic_type;
|
||||
} else if (ret_type->kind == TYPE_PTR) {
|
||||
rt = SPL_PTR;
|
||||
} else if (spl_type_size(ret_type) <= sizeof(spl_val_t)) {
|
||||
rt = SPL_PTR;
|
||||
}
|
||||
}
|
||||
spl_emit(ctx, SPL_RET, rt, 0);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* Variable init store — store value from stack to variable
|
||||
* ============================================================ */
|
||||
|
||||
void spl_emit_store_init(spl_comp_t *ctx, int var_offset, spl_type_info_t *var_type) {
|
||||
if (var_type && (var_type->kind == TYPE_STRUCT || var_type->kind == TYPE_ENUM)) {
|
||||
usize sz = spl_type_size(var_type);
|
||||
if (sz <= sizeof(spl_val_t)) {
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, var_offset);
|
||||
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
|
||||
spl_emit(ctx, SPL_STORE, SPL_PTR, 0);
|
||||
} else {
|
||||
usize nslots = (sz + sizeof(spl_val_t) - 1) / sizeof(spl_val_t);
|
||||
spl_emit_copy_slots(ctx, var_offset, nslots);
|
||||
}
|
||||
} else if (var_type && var_type->kind == TYPE_ARRAY) {
|
||||
spl_type_info_t *elem = var_type->elem;
|
||||
spl_type_t bt = (elem && elem->kind == TYPE_BASIC) ? elem->basic_type : SPL_I32;
|
||||
usize stride = spl_type_elem_stride(elem);
|
||||
for (int i = (int)var_type->array_len - 1; i >= 0; i--) {
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, var_offset + (int)(i * stride));
|
||||
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
|
||||
spl_emit(ctx, SPL_STORE, bt, 0);
|
||||
}
|
||||
} else if (var_type && var_type->kind == TYPE_SLICE) {
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, var_offset + (int)sizeof(spl_val_t));
|
||||
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
|
||||
spl_emit(ctx, SPL_STORE, SPL_USIZE, 0);
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, var_offset);
|
||||
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
|
||||
spl_emit(ctx, SPL_STORE, SPL_PTR, 0);
|
||||
} else {
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, var_offset);
|
||||
spl_type_t bt = (var_type->kind == TYPE_BASIC) ? var_type->basic_type
|
||||
: (var_type->kind == TYPE_PTR) ? SPL_PTR
|
||||
: SPL_I32;
|
||||
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
|
||||
spl_emit(ctx, SPL_STORE, bt, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user