stage1 优化重构代码
This commit is contained in:
@@ -240,6 +240,21 @@ int spl_lookup_func(spl_comp_t *ctx, const char *name) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ensure a native function is registered for NCALL dispatch.
|
||||||
|
* Returns the native index. */
|
||||||
|
int spl_ensure_native(spl_comp_t *ctx, const char *name) {
|
||||||
|
vec_for(ctx->prog.natives, ni) {
|
||||||
|
if (strcmp(vec_at(ctx->prog.natives, ni).name, name) == 0)
|
||||||
|
return (int)ni;
|
||||||
|
}
|
||||||
|
spl_native_t nat;
|
||||||
|
nat.name = strdup(name);
|
||||||
|
nat.idx_of_strtab = 0;
|
||||||
|
nat.impl_fn = NULL;
|
||||||
|
vec_push(ctx->prog.natives, nat);
|
||||||
|
return (int)vec_size(ctx->prog.natives) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* ---- String/data management ---- */
|
/* ---- String/data management ---- */
|
||||||
|
|
||||||
int spl_add_string(spl_comp_t *ctx, const char *str) {
|
int spl_add_string(spl_comp_t *ctx, const char *str) {
|
||||||
|
|||||||
@@ -252,8 +252,8 @@ spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *typ
|
|||||||
* so that match arms behave as "enhanced if-conditions".
|
* so that match arms behave as "enhanced if-conditions".
|
||||||
* For enum: parses .VariantName, emits tag comparison, returns variant.
|
* For enum: parses .VariantName, emits tag comparison, returns variant.
|
||||||
* For value: parses expression, emits equality comparison. */
|
* For value: parses expression, emits equality comparison. */
|
||||||
spl_enum_variant_t *spl_emit_match_enum_cmp(spl_comp_t *ctx,
|
spl_enum_variant_t *spl_emit_match_enum_cmp(spl_comp_t *ctx, spl_type_info_t *enum_type,
|
||||||
spl_type_info_t *enum_type, int val_offset);
|
int val_offset);
|
||||||
void spl_emit_match_value_cmp(spl_comp_t *ctx, int val_offset);
|
void spl_emit_match_value_cmp(spl_comp_t *ctx, int val_offset);
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
@@ -292,6 +292,9 @@ int spl_declare_func(spl_comp_t *ctx, const char *name, spl_type_info_t *ret_typ
|
|||||||
int is_extern, int is_pub);
|
int is_extern, int is_pub);
|
||||||
int spl_lookup_func(spl_comp_t *ctx, const char *name);
|
int spl_lookup_func(spl_comp_t *ctx, const char *name);
|
||||||
|
|
||||||
|
/* Ensure a native function is registered for NCALL dispatch, returns index */
|
||||||
|
int spl_ensure_native(spl_comp_t *ctx, const char *name);
|
||||||
|
|
||||||
/* String/data management */
|
/* String/data management */
|
||||||
int spl_add_string(spl_comp_t *ctx, const char *str);
|
int spl_add_string(spl_comp_t *ctx, const char *str);
|
||||||
int spl_add_global_data(spl_comp_t *ctx, void *data, usize size);
|
int spl_add_global_data(spl_comp_t *ctx, void *data, usize size);
|
||||||
|
|||||||
@@ -62,6 +62,9 @@ static int tok_prec(spl_tok_type_t t) {
|
|||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
|
|
||||||
static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, spl_tok_type_t op);
|
static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, spl_tok_type_t op);
|
||||||
|
static void emit_load_or_addr_type(spl_comp_t *ctx, spl_expr_result_t *result,
|
||||||
|
spl_type_info_t *type);
|
||||||
|
static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t left);
|
||||||
|
|
||||||
/* Slice creation from array/slice range expression.
|
/* Slice creation from array/slice range expression.
|
||||||
* Stack in: [base_addr, begin, end]
|
* Stack in: [base_addr, begin, end]
|
||||||
@@ -273,13 +276,11 @@ static spl_expr_result_t parse_float_literal(spl_comp_t *ctx) {
|
|||||||
|
|
||||||
static spl_expr_result_t parse_char_literal(spl_comp_t *ctx) {
|
static spl_expr_result_t parse_char_literal(spl_comp_t *ctx) {
|
||||||
spl_tok_t *t = advance(ctx);
|
spl_tok_t *t = advance(ctx);
|
||||||
/* Lexeme: 'x' or '\n' etc, extract the character value */
|
|
||||||
const char *s = t->lexeme;
|
const char *s = t->lexeme;
|
||||||
usize l = t->len;
|
usize l = t->len;
|
||||||
int64_t val = 0;
|
int64_t val = 0;
|
||||||
if (l >= 3) {
|
if (l >= 3) {
|
||||||
if (s[1] == '\\' && l >= 4) {
|
if (s[1] == '\\' && l >= 4) {
|
||||||
/* Escape sequence */
|
|
||||||
char buf = 0;
|
char buf = 0;
|
||||||
const char *cp = s + 1;
|
const char *cp = s + 1;
|
||||||
spl_decode_escape(&cp, &buf);
|
spl_decode_escape(&cp, &buf);
|
||||||
@@ -295,12 +296,10 @@ static spl_expr_result_t parse_char_literal(spl_comp_t *ctx) {
|
|||||||
|
|
||||||
static spl_expr_result_t parse_string_literal(spl_comp_t *ctx) {
|
static spl_expr_result_t parse_string_literal(spl_comp_t *ctx) {
|
||||||
spl_tok_t *t = advance(ctx);
|
spl_tok_t *t = advance(ctx);
|
||||||
/* Decode the string content (strip quotes, process escapes) */
|
|
||||||
usize slen = t->len;
|
usize slen = t->len;
|
||||||
if (slen >= 2) {
|
if (slen >= 2) {
|
||||||
slen -= 2; /* remove outer quotes */
|
slen -= 2;
|
||||||
}
|
}
|
||||||
/* Build decoded string */
|
|
||||||
char *decoded = malloc(slen + 1);
|
char *decoded = malloc(slen + 1);
|
||||||
usize di = 0;
|
usize di = 0;
|
||||||
for (usize i = 1; i + 1 < t->len; i++) {
|
for (usize i = 1; i + 1 < t->len; i++) {
|
||||||
@@ -315,10 +314,9 @@ static spl_expr_result_t parse_string_literal(spl_comp_t *ctx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
decoded[di] = '\0';
|
decoded[di] = '\0';
|
||||||
/* Add to global data */
|
|
||||||
int gdi = spl_add_global_data(ctx, decoded, di + 1);
|
int gdi = spl_add_global_data(ctx, decoded, di + 1);
|
||||||
free(decoded);
|
free(decoded);
|
||||||
spl_emit(ctx, SPL_GADDR, SPL_PTR, gdi - 1); /* gdi is 1-based from spl_prog_add_data */
|
spl_emit(ctx, SPL_GADDR, SPL_PTR, gdi - 1);
|
||||||
spl_expr_result_t r = {spl_type_ptr(spl_type_basic(SPL_U8)), 0};
|
spl_expr_result_t r = {spl_type_ptr(spl_type_basic(SPL_U8)), 0};
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@@ -328,7 +326,6 @@ static spl_expr_result_t parse_array_literal(spl_comp_t *ctx) {
|
|||||||
advance(ctx); /* skip [ */
|
advance(ctx); /* skip [ */
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
|
|
||||||
/* Parse array length */
|
|
||||||
int len_val;
|
int len_val;
|
||||||
if (!spl_parse_int_literal(ctx, &len_val)) {
|
if (!spl_parse_int_literal(ctx, &len_val)) {
|
||||||
spl_comp_error(ctx, "expected array length");
|
spl_comp_error(ctx, "expected array length");
|
||||||
@@ -341,7 +338,6 @@ static spl_expr_result_t parse_array_literal(spl_comp_t *ctx) {
|
|||||||
expect(ctx, TOK_R_BRACKET);
|
expect(ctx, TOK_R_BRACKET);
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
|
|
||||||
/* Parse element type */
|
|
||||||
spl_type_info_t *elem_type = spl_parse_type(ctx);
|
spl_type_info_t *elem_type = spl_parse_type(ctx);
|
||||||
if (!elem_type) {
|
if (!elem_type) {
|
||||||
spl_expr_result_t r = {0};
|
spl_expr_result_t r = {0};
|
||||||
@@ -352,7 +348,6 @@ static spl_expr_result_t parse_array_literal(spl_comp_t *ctx) {
|
|||||||
expect(ctx, TOK_L_BRACE);
|
expect(ctx, TOK_L_BRACE);
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
|
|
||||||
/* Parse each element value */
|
|
||||||
for (usize i = 0; i < len; i++) {
|
for (usize i = 0; i < len; i++) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
if (peek(ctx)->type == TOK_COMMA)
|
if (peek(ctx)->type == TOK_COMMA)
|
||||||
@@ -363,7 +358,7 @@ static spl_expr_result_t parse_array_literal(spl_comp_t *ctx) {
|
|||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
}
|
}
|
||||||
if (peek(ctx)->type == TOK_COMMA)
|
if (peek(ctx)->type == TOK_COMMA)
|
||||||
advance(ctx); /* trailing comma */
|
advance(ctx);
|
||||||
|
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
expect(ctx, TOK_R_BRACE);
|
expect(ctx, TOK_R_BRACE);
|
||||||
@@ -373,7 +368,7 @@ static spl_expr_result_t parse_array_literal(spl_comp_t *ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Parse slice inline literal: { .ptr = expr, .len = expr }
|
/* 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). */
|
* Expects base address on TOS, consumes it. */
|
||||||
static void parse_slice_inline(spl_comp_t *ctx) {
|
static void parse_slice_inline(spl_comp_t *ctx) {
|
||||||
advance(ctx); /* { */
|
advance(ctx); /* { */
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
@@ -387,36 +382,30 @@ static void parse_slice_inline(spl_comp_t *ctx) {
|
|||||||
advance(ctx);
|
advance(ctx);
|
||||||
spl_tok_t *ftok = advance(ctx);
|
spl_tok_t *ftok = advance(ctx);
|
||||||
char fname[256];
|
char fname[256];
|
||||||
usize fnl = ftok->len < 255 ? ftok->len : 255;
|
spl_tok_copy_name(ftok, fname, sizeof(fname));
|
||||||
memcpy(fname, ftok->lexeme, fnl);
|
|
||||||
fname[fnl] = '\0';
|
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
if (peek(ctx)->type == TOK_ASSIGN)
|
if (peek(ctx)->type == TOK_ASSIGN)
|
||||||
advance(ctx);
|
advance(ctx);
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
|
|
||||||
spl_emit(ctx, SPL_DUP, SPL_VOID, 0); /* [addr, addr] */
|
spl_emit(ctx, SPL_DUP, SPL_VOID, 0);
|
||||||
if (strcmp(fname, "ptr") == 0) {
|
if (strcmp(fname, "ptr") == 0) {
|
||||||
spl_parse_expr(ctx, PREC_MIN);
|
spl_parse_expr(ctx, PREC_MIN);
|
||||||
spl_emit(ctx, SPL_STORE, SPL_PTR, 0); /* [addr] */
|
spl_emit(ctx, SPL_STORE, SPL_PTR, 0);
|
||||||
} else if (strcmp(fname, "len") == 0) {
|
} else if (strcmp(fname, "len") == 0) {
|
||||||
spl_emit(ctx, SPL_PUSH, SPL_USIZE, sizeof(spl_val_t));
|
spl_emit(ctx, SPL_PUSH, SPL_USIZE, sizeof(spl_val_t));
|
||||||
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0); /* [addr, addr+8] */
|
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
|
||||||
spl_parse_expr(ctx, PREC_MIN);
|
spl_parse_expr(ctx, PREC_MIN);
|
||||||
spl_emit(ctx, SPL_STORE, SPL_USIZE, 0); /* [addr] */
|
spl_emit(ctx, SPL_STORE, SPL_USIZE, 0);
|
||||||
}
|
}
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
}
|
}
|
||||||
expect(ctx, TOK_R_BRACE);
|
expect(ctx, TOK_R_BRACE);
|
||||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* drop addr */
|
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse a single .field = value in a struct literal.
|
static void parse_one_field_init(spl_comp_t *ctx, spl_field_vec_t *fields, int base_offset,
|
||||||
* Iterates fields to find the match, emits LADDR + offset, and handles
|
usize extra_offset) {
|
||||||
* 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)
|
if (peek(ctx)->type == TOK_DOT)
|
||||||
advance(ctx);
|
advance(ctx);
|
||||||
spl_tok_t *ftok = advance(ctx);
|
spl_tok_t *ftok = advance(ctx);
|
||||||
@@ -436,13 +425,10 @@ static void parse_one_field_init(spl_comp_t *ctx, spl_field_vec_t *fields,
|
|||||||
spl_emit(ctx, SPL_PUSH, SPL_USIZE, byte_off);
|
spl_emit(ctx, SPL_PUSH, SPL_USIZE, byte_off);
|
||||||
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
|
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
|
||||||
}
|
}
|
||||||
if (f->type && f->type->kind == TYPE_SLICE &&
|
if (f->type && f->type->kind == TYPE_SLICE && peek(ctx)->type == TOK_L_BRACE) {
|
||||||
peek(ctx)->type == TOK_L_BRACE) {
|
|
||||||
parse_slice_inline(ctx);
|
parse_slice_inline(ctx);
|
||||||
} else if (f->type && f->type->kind == TYPE_ARRAY &&
|
} else if (f->type && f->type->kind == TYPE_ARRAY && peek(ctx)->type == TOK_L_BRACKET) {
|
||||||
peek(ctx)->type == TOK_L_BRACKET) {
|
advance(ctx);
|
||||||
/* Inline array initializer: [N]Type{val1, val2, ...} */
|
|
||||||
advance(ctx); /* [ */
|
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
int len_val;
|
int len_val;
|
||||||
if (!spl_parse_int_literal(ctx, &len_val)) {
|
if (!spl_parse_int_literal(ctx, &len_val)) {
|
||||||
@@ -461,7 +447,8 @@ static void parse_one_field_init(spl_comp_t *ctx, spl_field_vec_t *fields,
|
|||||||
spl_type_t st = spl_type_emit_type(elem_type);
|
spl_type_t st = spl_type_emit_type(elem_type);
|
||||||
for (usize i = 0; i < arr_len; i++) {
|
for (usize i = 0; i < arr_len; i++) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
if (peek(ctx)->type == TOK_COMMA) advance(ctx);
|
if (peek(ctx)->type == TOK_COMMA)
|
||||||
|
advance(ctx);
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
}
|
}
|
||||||
spl_emit(ctx, SPL_DUP, SPL_VOID, 0);
|
spl_emit(ctx, SPL_DUP, SPL_VOID, 0);
|
||||||
@@ -473,12 +460,12 @@ static void parse_one_field_init(spl_comp_t *ctx, spl_field_vec_t *fields,
|
|||||||
spl_emit(ctx, SPL_STORE, st, 0);
|
spl_emit(ctx, SPL_STORE, st, 0);
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
}
|
}
|
||||||
if (peek(ctx)->type == TOK_COMMA) advance(ctx);
|
if (peek(ctx)->type == TOK_COMMA)
|
||||||
|
advance(ctx);
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
expect(ctx, TOK_R_BRACE);
|
expect(ctx, TOK_R_BRACE);
|
||||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
|
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
|
||||||
} else if (f->type &&
|
} else if (f->type && (f->type->kind == TYPE_STRUCT || f->type->kind == TYPE_ENUM) &&
|
||||||
(f->type->kind == TYPE_STRUCT || f->type->kind == TYPE_ENUM) &&
|
|
||||||
spl_type_size(f->type) > sizeof(spl_val_t)) {
|
spl_type_size(f->type) > sizeof(spl_val_t)) {
|
||||||
spl_expr_result_t fv = spl_parse_expr(ctx, PREC_MIN);
|
spl_expr_result_t fv = spl_parse_expr(ctx, PREC_MIN);
|
||||||
(void)fv;
|
(void)fv;
|
||||||
@@ -495,9 +482,6 @@ static void parse_one_field_init(spl_comp_t *ctx, spl_field_vec_t *fields,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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. */
|
|
||||||
spl_expr_result_t spl_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);
|
usize sz = spl_type_size(type);
|
||||||
int base_offset = ctx->current_local_bytes;
|
int base_offset = ctx->current_local_bytes;
|
||||||
@@ -558,14 +542,11 @@ spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *typ
|
|||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
}
|
}
|
||||||
} else if (type->kind == TYPE_ENUM) {
|
} else if (type->kind == TYPE_ENUM) {
|
||||||
/* Parse .Variant [= value] */
|
|
||||||
if (peek(ctx)->type == TOK_DOT)
|
if (peek(ctx)->type == TOK_DOT)
|
||||||
advance(ctx);
|
advance(ctx);
|
||||||
spl_tok_t *vtok = advance(ctx);
|
spl_tok_t *vtok = advance(ctx);
|
||||||
char vname[256];
|
char vname[256];
|
||||||
usize vnl = vtok->len < 255 ? vtok->len : 255;
|
spl_tok_copy_name(vtok, vname, sizeof(vname));
|
||||||
memcpy(vname, vtok->lexeme, vnl);
|
|
||||||
vname[vnl] = '\0';
|
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
if (peek(ctx)->type == TOK_ASSIGN)
|
if (peek(ctx)->type == TOK_ASSIGN)
|
||||||
advance(ctx);
|
advance(ctx);
|
||||||
@@ -576,16 +557,13 @@ spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *typ
|
|||||||
spl_enum_variant_t *v = &vec_at(type->variants, vi);
|
spl_enum_variant_t *v = &vec_at(type->variants, vi);
|
||||||
if (strcmp(v->name, vname) == 0) {
|
if (strcmp(v->name, vname) == 0) {
|
||||||
found = 1;
|
found = 1;
|
||||||
/* Store tag at offset 0 */
|
|
||||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_offset);
|
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_offset);
|
||||||
spl_emit(ctx, SPL_PUSH, SPL_I32, v->value);
|
spl_emit(ctx, SPL_PUSH, SPL_I32, v->value);
|
||||||
spl_emit(ctx, SPL_STORE, SPL_I32, 0);
|
spl_emit(ctx, SPL_STORE, SPL_I32, 0);
|
||||||
|
|
||||||
/* Store variant data at offset 4 */
|
|
||||||
const usize DATA_OFFSET = 4;
|
const usize DATA_OFFSET = 4;
|
||||||
if (v->data_type) {
|
if (v->data_type) {
|
||||||
if (v->data_type->kind == TYPE_STRUCT && peek(ctx)->type == TOK_L_BRACE) {
|
if (v->data_type->kind == TYPE_STRUCT && peek(ctx)->type == TOK_L_BRACE) {
|
||||||
/* Struct data: { .field = val, ... } */
|
|
||||||
advance(ctx); /* { */
|
advance(ctx); /* { */
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
while (peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) {
|
while (peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) {
|
||||||
@@ -596,7 +574,8 @@ spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *typ
|
|||||||
}
|
}
|
||||||
if (peek(ctx)->type != TOK_DOT)
|
if (peek(ctx)->type != TOK_DOT)
|
||||||
break;
|
break;
|
||||||
parse_one_field_init(ctx, &v->data_type->fields, base_offset, DATA_OFFSET);
|
parse_one_field_init(ctx, &v->data_type->fields, base_offset,
|
||||||
|
DATA_OFFSET);
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
}
|
}
|
||||||
expect(ctx, TOK_R_BRACE);
|
expect(ctx, TOK_R_BRACE);
|
||||||
@@ -604,7 +583,6 @@ spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *typ
|
|||||||
(v->data_type->kind == TYPE_STRUCT ||
|
(v->data_type->kind == TYPE_STRUCT ||
|
||||||
v->data_type->kind == TYPE_ENUM) &&
|
v->data_type->kind == TYPE_ENUM) &&
|
||||||
spl_type_size(v->data_type) > sizeof(spl_val_t)) {
|
spl_type_size(v->data_type) > sizeof(spl_val_t)) {
|
||||||
/* Multi-slot struct/enum data: copy from temp to enum data area */
|
|
||||||
spl_expr_result_t dv = spl_parse_expr(ctx, PREC_MIN);
|
spl_expr_result_t dv = spl_parse_expr(ctx, PREC_MIN);
|
||||||
(void)dv;
|
(void)dv;
|
||||||
usize nslots = (spl_type_size(v->data_type) + sizeof(spl_val_t) - 1) /
|
usize nslots = (spl_type_size(v->data_type) + sizeof(spl_val_t) - 1) /
|
||||||
@@ -612,7 +590,6 @@ spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *typ
|
|||||||
spl_emit_copy_slots(ctx, base_offset + (int)DATA_OFFSET, nslots);
|
spl_emit_copy_slots(ctx, base_offset + (int)DATA_OFFSET, nslots);
|
||||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
|
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
|
||||||
} else {
|
} else {
|
||||||
/* Simple data: parse expression */
|
|
||||||
spl_expr_result_t dv = spl_parse_expr(ctx, PREC_MIN);
|
spl_expr_result_t dv = spl_parse_expr(ctx, PREC_MIN);
|
||||||
(void)dv;
|
(void)dv;
|
||||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_offset);
|
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_offset);
|
||||||
@@ -633,28 +610,40 @@ spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *typ
|
|||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
expect(ctx, TOK_R_BRACE);
|
expect(ctx, TOK_R_BRACE);
|
||||||
|
|
||||||
/* Return: if size fits in one slot, push packed value. Otherwise push address. */
|
|
||||||
if (sz <= sizeof(spl_val_t)) {
|
if (sz <= sizeof(spl_val_t)) {
|
||||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_offset);
|
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_offset);
|
||||||
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
|
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
|
||||||
return (spl_expr_result_t){type, 0}; /* value on stack */
|
return (spl_expr_result_t){type, 0};
|
||||||
} else {
|
} else {
|
||||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_offset);
|
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_offset);
|
||||||
return (spl_expr_result_t){type, 1}; /* address on stack */
|
return (spl_expr_result_t){type, 1};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int parse_call_args(spl_comp_t *ctx) {
|
||||||
|
int nargs = 0;
|
||||||
|
if (peek(ctx)->type != TOK_R_PAREN) {
|
||||||
|
for (;;) {
|
||||||
|
spl_parse_expr(ctx, PREC_MIN);
|
||||||
|
nargs++;
|
||||||
|
if (peek(ctx)->type == TOK_COMMA) {
|
||||||
|
advance(ctx);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nargs;
|
||||||
|
}
|
||||||
|
|
||||||
static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
|
static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
|
||||||
spl_tok_t *t = advance(ctx);
|
spl_tok_t *t = advance(ctx);
|
||||||
char name[256];
|
char name[256];
|
||||||
usize nlen = t->len < 255 ? t->len : 255;
|
spl_tok_copy_name(t, name, sizeof(name));
|
||||||
memcpy(name, t->lexeme, nlen);
|
|
||||||
name[nlen] = '\0';
|
|
||||||
|
|
||||||
/* Check if it's a function call: ident(...) */
|
/* Check if it's a function call: ident(...) */
|
||||||
if (peek(ctx)->type == TOK_L_PAREN) {
|
if (peek(ctx)->type == TOK_L_PAREN) {
|
||||||
int fi = spl_lookup_func(ctx, name);
|
int fi = spl_lookup_func(ctx, name);
|
||||||
/* Fallback: try qualified name for short-name resolution inside methods */
|
|
||||||
if (fi < 0 && ctx->current_type_name) {
|
if (fi < 0 && ctx->current_type_name) {
|
||||||
char qualified[512];
|
char qualified[512];
|
||||||
snprintf(qualified, sizeof(qualified), "%s.%s", ctx->current_type_name, name);
|
snprintf(qualified, sizeof(qualified), "%s.%s", ctx->current_type_name, name);
|
||||||
@@ -668,44 +657,14 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
|
|||||||
spl_func_info_t *f = &vec_at(ctx->funcs, fi);
|
spl_func_info_t *f = &vec_at(ctx->funcs, fi);
|
||||||
advance(ctx); /* skip ( */
|
advance(ctx); /* skip ( */
|
||||||
|
|
||||||
int nargs = 0;
|
int nargs = parse_call_args(ctx);
|
||||||
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);
|
expect(ctx, TOK_R_PAREN);
|
||||||
|
|
||||||
if (f->is_extern) {
|
if (f->is_extern) {
|
||||||
/* Find the native function index in prog */
|
int nidx = spl_ensure_native(ctx, f->name);
|
||||||
int nidx = -1;
|
|
||||||
vec_for(ctx->prog.natives, ni) {
|
|
||||||
if (strcmp(vec_at(ctx->prog.natives, ni).name, f->name) == 0) {
|
|
||||||
nidx = (int)ni;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (nidx < 0) {
|
|
||||||
/* Register it */
|
|
||||||
spl_native_t nat;
|
|
||||||
nat.name = strdup(f->name);
|
|
||||||
nat.idx_of_strtab = 0;
|
|
||||||
nat.impl_fn = NULL;
|
|
||||||
vec_push(ctx->prog.natives, nat);
|
|
||||||
nidx = (int)vec_size(ctx->prog.natives) - 1;
|
|
||||||
}
|
|
||||||
/* Push native index, then NCALL with imm = nargs */
|
|
||||||
spl_emit(ctx, SPL_PUSH, SPL_I32, nidx);
|
spl_emit(ctx, SPL_PUSH, SPL_I32, nidx);
|
||||||
spl_emit(ctx, SPL_NCALL, SPL_VOID, nargs);
|
spl_emit(ctx, SPL_NCALL, SPL_VOID, nargs);
|
||||||
} else {
|
} else {
|
||||||
/* Regular function call: push func addr, then CALL */
|
|
||||||
spl_val_t addr = vec_at(ctx->prog.funcs, f->func_idx).address;
|
spl_val_t addr = vec_at(ctx->prog.funcs, f->func_idx).address;
|
||||||
spl_emit(ctx, SPL_PUSH, SPL_PTR, addr);
|
spl_emit(ctx, SPL_PUSH, SPL_PTR, addr);
|
||||||
spl_emit(ctx, SPL_CALL, SPL_VOID, nargs);
|
spl_emit(ctx, SPL_CALL, SPL_VOID, nargs);
|
||||||
@@ -718,7 +677,6 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
|
|||||||
/* Variable reference */
|
/* Variable reference */
|
||||||
spl_var_info_t *v = spl_lookup_var(ctx, name);
|
spl_var_info_t *v = spl_lookup_var(ctx, name);
|
||||||
if (v) {
|
if (v) {
|
||||||
/* Check const values first */
|
|
||||||
spl_val_t cv = 0;
|
spl_val_t cv = 0;
|
||||||
if (map_get(ctx->const_values, name, &cv)) {
|
if (map_get(ctx->const_values, name, &cv)) {
|
||||||
spl_emit(ctx, SPL_PUSH, SPL_I32, cv);
|
spl_emit(ctx, SPL_PUSH, SPL_I32, cv);
|
||||||
@@ -729,27 +687,14 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
|
|||||||
spl_type_info_t *vt = v->type;
|
spl_type_info_t *vt = v->type;
|
||||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, v->offset);
|
spl_emit(ctx, SPL_LADDR, SPL_PTR, v->offset);
|
||||||
|
|
||||||
if (vt->kind == TYPE_BASIC || vt->kind == TYPE_PTR) {
|
spl_expr_result_t r;
|
||||||
if (!ctx->addr_of_mode) {
|
emit_load_or_addr_type(ctx, &r, vt);
|
||||||
/* Load value for basic types and pointers */
|
|
||||||
spl_type_t bt = (vt->kind == TYPE_BASIC) ? vt->basic_type : SPL_PTR;
|
|
||||||
spl_emit(ctx, SPL_LOAD, bt, 0);
|
|
||||||
spl_expr_result_t r = {vt, 0};
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
/* In addr_of_mode, keep address on stack */
|
|
||||||
spl_expr_result_t r = {vt, 1};
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
/* Array/struct/slice: address stays on stack */
|
|
||||||
spl_expr_result_t r = {vt, 1};
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if it's a type name (for enum variant access like Color.Red) */
|
/* Check if it's a type name (for enum variant access like Color.Red) */
|
||||||
spl_type_info_t *ttype = spl_resolve_type(ctx, name);
|
spl_type_info_t *ttype = spl_resolve_type(ctx, name);
|
||||||
if (ttype) {
|
if (ttype) {
|
||||||
/* Struct/enum literal: Type { .field = val, ... } */
|
|
||||||
if (peek(ctx)->type == TOK_L_BRACE &&
|
if (peek(ctx)->type == TOK_L_BRACE &&
|
||||||
(ttype->kind == TYPE_STRUCT || ttype->kind == TYPE_ENUM)) {
|
(ttype->kind == TYPE_STRUCT || ttype->kind == TYPE_ENUM)) {
|
||||||
return spl_parse_struct_literal(ctx, ttype);
|
return spl_parse_struct_literal(ctx, ttype);
|
||||||
@@ -770,6 +715,19 @@ static spl_expr_result_t parse_group(spl_comp_t *ctx) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void emit_load_or_addr_type(spl_comp_t *ctx, spl_expr_result_t *result,
|
||||||
|
spl_type_info_t *type) {
|
||||||
|
if (type->kind == TYPE_BASIC || type->kind == TYPE_PTR) {
|
||||||
|
if (!ctx->addr_of_mode) {
|
||||||
|
spl_type_t bt = (type->kind == TYPE_BASIC) ? type->basic_type : SPL_PTR;
|
||||||
|
spl_emit(ctx, SPL_LOAD, bt, 0);
|
||||||
|
*result = (spl_expr_result_t){type, 0};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*result = (spl_expr_result_t){type, 1};
|
||||||
|
}
|
||||||
|
|
||||||
static spl_expr_result_t parse_prefix_op(spl_comp_t *ctx) {
|
static spl_expr_result_t parse_prefix_op(spl_comp_t *ctx) {
|
||||||
spl_tok_t *op = advance(ctx);
|
spl_tok_t *op = advance(ctx);
|
||||||
|
|
||||||
@@ -784,7 +742,6 @@ static spl_expr_result_t parse_prefix_op(spl_comp_t *ctx) {
|
|||||||
spl_emit(ctx, SPL_NEG, SPL_I32, 0);
|
spl_emit(ctx, SPL_NEG, SPL_I32, 0);
|
||||||
break;
|
break;
|
||||||
case TOK_NOT:
|
case TOK_NOT:
|
||||||
/* !expr → EQ 0 */
|
|
||||||
spl_emit(ctx, SPL_PUSH, SPL_I32, 0);
|
spl_emit(ctx, SPL_PUSH, SPL_I32, 0);
|
||||||
spl_emit(ctx, SPL_EQ, SPL_I32, 0);
|
spl_emit(ctx, SPL_EQ, SPL_I32, 0);
|
||||||
break;
|
break;
|
||||||
@@ -792,31 +749,16 @@ static spl_expr_result_t parse_prefix_op(spl_comp_t *ctx) {
|
|||||||
spl_emit(ctx, SPL_NOT, SPL_I32, 0);
|
spl_emit(ctx, SPL_NOT, SPL_I32, 0);
|
||||||
break;
|
break;
|
||||||
case TOK_AND:
|
case TOK_AND:
|
||||||
/* &expr — address-of, already an lvalue */
|
|
||||||
if (!right.is_lvalue) {
|
if (!right.is_lvalue) {
|
||||||
spl_comp_error(ctx, "cannot take address of rvalue");
|
spl_comp_error(ctx, "cannot take address of rvalue");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TOK_MUL:
|
case TOK_MUL:
|
||||||
/* *expr — dereference */
|
|
||||||
if (right.type && right.type->kind == TYPE_PTR && right.type->elem) {
|
if (right.type && right.type->kind == TYPE_PTR && right.type->elem) {
|
||||||
/* If right is still an lvalue, load the pointer value for the target */
|
|
||||||
if (right.is_lvalue) {
|
if (right.is_lvalue) {
|
||||||
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
|
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
|
||||||
}
|
}
|
||||||
spl_type_info_t *elem = right.type->elem;
|
emit_load_or_addr_type(ctx, &right, right.type->elem);
|
||||||
if (elem->kind == TYPE_BASIC || elem->kind == TYPE_PTR) {
|
|
||||||
if (!ctx->addr_of_mode) {
|
|
||||||
spl_type_t bt = (elem->kind == TYPE_BASIC) ? elem->basic_type : SPL_PTR;
|
|
||||||
spl_emit(ctx, SPL_LOAD, bt, 0);
|
|
||||||
right = (spl_expr_result_t){elem, 0};
|
|
||||||
} else {
|
|
||||||
right = (spl_expr_result_t){elem, 1};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Struct/array/slice: keep address on stack */
|
|
||||||
right = (spl_expr_result_t){elem, 1};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -876,7 +818,6 @@ static spl_expr_result_t parse_primary_expr(spl_comp_t *ctx) {
|
|||||||
case TOK_L_BRACE:
|
case TOK_L_BRACE:
|
||||||
return spl_parse_block_expr(ctx);
|
return spl_parse_block_expr(ctx);
|
||||||
case TOK_AT: {
|
case TOK_AT: {
|
||||||
/* @builtin(...) — compiler intrinsic */
|
|
||||||
advance(ctx);
|
advance(ctx);
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
tok = peek(ctx);
|
tok = peek(ctx);
|
||||||
@@ -892,18 +833,7 @@ static spl_expr_result_t parse_primary_expr(spl_comp_t *ctx) {
|
|||||||
if (strcmp(bname, "dbg") == 0) {
|
if (strcmp(bname, "dbg") == 0) {
|
||||||
if (peek(ctx)->type == TOK_L_PAREN) {
|
if (peek(ctx)->type == TOK_L_PAREN) {
|
||||||
advance(ctx);
|
advance(ctx);
|
||||||
int nargs = 0;
|
int nargs = parse_call_args(ctx);
|
||||||
if (peek(ctx)->type != TOK_R_PAREN) {
|
|
||||||
for (;;) {
|
|
||||||
spl_parse_expr(ctx, PREC_MIN);
|
|
||||||
nargs++;
|
|
||||||
if (peek(ctx)->type == TOK_COMMA) {
|
|
||||||
advance(ctx);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect(ctx, TOK_R_PAREN);
|
expect(ctx, TOK_R_PAREN);
|
||||||
for (int i = 0; i < nargs; i++) {
|
for (int i = 0; i < nargs; i++) {
|
||||||
spl_emit(ctx, SPL_DBG, SPL_USIZE, 0);
|
spl_emit(ctx, SPL_DBG, SPL_USIZE, 0);
|
||||||
@@ -931,28 +861,23 @@ static spl_expr_result_t parse_primary_expr(spl_comp_t *ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* Main expression parser (top-level)
|
* Postfix expression parser (.field, [index], [begin..end])
|
||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
|
|
||||||
spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
|
static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t left) {
|
||||||
skip_nl(ctx);
|
|
||||||
spl_expr_result_t left = parse_primary_expr(ctx);
|
|
||||||
if (!left.type)
|
if (!left.type)
|
||||||
return left;
|
return left;
|
||||||
|
|
||||||
/* Infix parsing (precedence climbing) */
|
for (;;) {
|
||||||
while (1) {
|
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
spl_tok_type_t opt = peek(ctx)->type;
|
spl_tok_type_t opt = peek(ctx)->type;
|
||||||
|
|
||||||
/* Postfix operators */
|
/* Postfix . operator */
|
||||||
if (opt == TOK_DOT) {
|
if (opt == TOK_DOT) {
|
||||||
advance(ctx);
|
advance(ctx);
|
||||||
spl_tok_t *field = advance(ctx);
|
spl_tok_t *field = advance(ctx);
|
||||||
char fname[256];
|
char fname[256];
|
||||||
usize fnl = field->len < 255 ? field->len : 255;
|
spl_tok_copy_name(field, fname, sizeof(fname));
|
||||||
memcpy(fname, field->lexeme, fnl);
|
|
||||||
fname[fnl] = '\0';
|
|
||||||
|
|
||||||
/* Compile-time type member resolution (enum variants, nested types) */
|
/* Compile-time type member resolution (enum variants, nested types) */
|
||||||
if (left.type) {
|
if (left.type) {
|
||||||
@@ -965,7 +890,6 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
|
|||||||
|
|
||||||
/* Method call on type/instance: left.field(args) */
|
/* Method call on type/instance: left.field(args) */
|
||||||
if (left.type && peek(ctx)->type == TOK_L_PAREN) {
|
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;
|
spl_type_info_t *methods_type = left.type;
|
||||||
int is_ptr_self = 0;
|
int is_ptr_self = 0;
|
||||||
if (methods_type->kind == TYPE_PTR && methods_type->elem &&
|
if (methods_type->kind == TYPE_PTR && methods_type->elem &&
|
||||||
@@ -986,7 +910,6 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
|
|||||||
|
|
||||||
int nargs = 0;
|
int nargs = 0;
|
||||||
|
|
||||||
/* Check if instance method: first param is self: *Type */
|
|
||||||
int is_instance = 0;
|
int is_instance = 0;
|
||||||
if (func->nparams > 0 && func->param_types[0] &&
|
if (func->nparams > 0 && func->param_types[0] &&
|
||||||
func->param_types[0]->kind == TYPE_PTR &&
|
func->param_types[0]->kind == TYPE_PTR &&
|
||||||
@@ -999,22 +922,10 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
|
|||||||
spl_comp_error(ctx, "cannot call instance method '%s' on type",
|
spl_comp_error(ctx, "cannot call instance method '%s' on type",
|
||||||
fname);
|
fname);
|
||||||
}
|
}
|
||||||
nargs = 1; /* self already on stack */
|
nargs = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse remaining arguments */
|
nargs += parse_call_args(ctx);
|
||||||
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);
|
expect(ctx, TOK_R_PAREN);
|
||||||
|
|
||||||
spl_val_t addr = vec_at(ctx->prog.funcs, func->func_idx).address;
|
spl_val_t addr = vec_at(ctx->prog.funcs, func->func_idx).address;
|
||||||
@@ -1027,12 +938,10 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
|
|||||||
}
|
}
|
||||||
if (found_method)
|
if (found_method)
|
||||||
continue;
|
continue;
|
||||||
/* If method not found, fall through to field access below */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Struct field access */
|
/* Struct field access */
|
||||||
if (left.type && left.type->kind == TYPE_STRUCT) {
|
if (left.type && left.type->kind == TYPE_STRUCT) {
|
||||||
/* The struct address is on stack (as lvalue or from previous computation) */
|
|
||||||
vec_for(left.type->fields, fi) {
|
vec_for(left.type->fields, fi) {
|
||||||
if (strcmp(vec_at(left.type->fields, fi).name, fname) == 0) {
|
if (strcmp(vec_at(left.type->fields, fi).name, fname) == 0) {
|
||||||
spl_field_t *f = &vec_at(left.type->fields, fi);
|
spl_field_t *f = &vec_at(left.type->fields, fi);
|
||||||
@@ -1040,19 +949,7 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
|
|||||||
spl_emit(ctx, SPL_PUSH, SPL_USIZE, f->offset);
|
spl_emit(ctx, SPL_PUSH, SPL_USIZE, f->offset);
|
||||||
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
|
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
|
||||||
}
|
}
|
||||||
/* Load value if basic type */
|
emit_load_or_addr_type(ctx, &left, f->type);
|
||||||
spl_type_info_t *ft = f->type;
|
|
||||||
if (ft->kind == TYPE_BASIC || ft->kind == TYPE_PTR) {
|
|
||||||
if (!ctx->addr_of_mode) {
|
|
||||||
spl_type_t bt = (ft->kind == TYPE_BASIC) ? ft->basic_type : SPL_PTR;
|
|
||||||
spl_emit(ctx, SPL_LOAD, bt, 0);
|
|
||||||
left = (spl_expr_result_t){ft, 0};
|
|
||||||
} else {
|
|
||||||
left = (spl_expr_result_t){ft, 1};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
left = (spl_expr_result_t){ft, 1};
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1063,11 +960,9 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
|
|||||||
if (left.type && left.type->kind == TYPE_PTR && left.type->elem &&
|
if (left.type && left.type->kind == TYPE_PTR && left.type->elem &&
|
||||||
left.type->elem->kind == TYPE_STRUCT) {
|
left.type->elem->kind == TYPE_STRUCT) {
|
||||||
spl_type_info_t *st = left.type->elem;
|
spl_type_info_t *st = left.type->elem;
|
||||||
/* Load pointer value to get struct address if left is still lvalue */
|
|
||||||
if (left.is_lvalue) {
|
if (left.is_lvalue) {
|
||||||
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
|
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
|
||||||
}
|
}
|
||||||
/* Now search field */
|
|
||||||
vec_for(st->fields, fi) {
|
vec_for(st->fields, fi) {
|
||||||
if (strcmp(vec_at(st->fields, fi).name, fname) == 0) {
|
if (strcmp(vec_at(st->fields, fi).name, fname) == 0) {
|
||||||
spl_field_t *f = &vec_at(st->fields, fi);
|
spl_field_t *f = &vec_at(st->fields, fi);
|
||||||
@@ -1075,18 +970,7 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
|
|||||||
spl_emit(ctx, SPL_PUSH, SPL_USIZE, f->offset);
|
spl_emit(ctx, SPL_PUSH, SPL_USIZE, f->offset);
|
||||||
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
|
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
|
||||||
}
|
}
|
||||||
spl_type_info_t *ft = f->type;
|
emit_load_or_addr_type(ctx, &left, f->type);
|
||||||
if (ft->kind == TYPE_BASIC || ft->kind == TYPE_PTR) {
|
|
||||||
if (!ctx->addr_of_mode) {
|
|
||||||
spl_type_t bt = (ft->kind == TYPE_BASIC) ? ft->basic_type : SPL_PTR;
|
|
||||||
spl_emit(ctx, SPL_LOAD, bt, 0);
|
|
||||||
left = (spl_expr_result_t){ft, 0};
|
|
||||||
} else {
|
|
||||||
left = (spl_expr_result_t){ft, 1};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
left = (spl_expr_result_t){ft, 1};
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1097,12 +981,10 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
|
|||||||
if (left.type && left.type->kind == TYPE_SLICE) {
|
if (left.type && left.type->kind == TYPE_SLICE) {
|
||||||
if (strcmp(fname, "len") == 0) {
|
if (strcmp(fname, "len") == 0) {
|
||||||
if (ctx->addr_of_mode) {
|
if (ctx->addr_of_mode) {
|
||||||
/* lvalue: push address of len field at offset sizeof(spl_val_t) */
|
|
||||||
spl_emit(ctx, SPL_PUSH, SPL_U64, (spl_val_t)sizeof(spl_val_t));
|
spl_emit(ctx, SPL_PUSH, SPL_U64, (spl_val_t)sizeof(spl_val_t));
|
||||||
spl_emit(ctx, SPL_ADD, SPL_U64, 0);
|
spl_emit(ctx, SPL_ADD, SPL_U64, 0);
|
||||||
left = (spl_expr_result_t){spl_type_basic(SPL_USIZE), 1};
|
left = (spl_expr_result_t){spl_type_basic(SPL_USIZE), 1};
|
||||||
} else {
|
} else {
|
||||||
/* rvalue: load len value */
|
|
||||||
spl_emit(ctx, SPL_PUSH, SPL_U64, (spl_val_t)sizeof(spl_val_t));
|
spl_emit(ctx, SPL_PUSH, SPL_U64, (spl_val_t)sizeof(spl_val_t));
|
||||||
spl_emit(ctx, SPL_ADD, SPL_U64, 0);
|
spl_emit(ctx, SPL_ADD, SPL_U64, 0);
|
||||||
spl_emit(ctx, SPL_LOAD, SPL_USIZE, 0);
|
spl_emit(ctx, SPL_LOAD, SPL_USIZE, 0);
|
||||||
@@ -1110,7 +992,6 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
|
|||||||
}
|
}
|
||||||
} else if (strcmp(fname, "ptr") == 0) {
|
} else if (strcmp(fname, "ptr") == 0) {
|
||||||
if (ctx->addr_of_mode) {
|
if (ctx->addr_of_mode) {
|
||||||
/* lvalue: ptr is at offset 0, address already on stack */
|
|
||||||
left = (spl_expr_result_t){left.type->elem ? spl_type_ptr(left.type->elem)
|
left = (spl_expr_result_t){left.type->elem ? spl_type_ptr(left.type->elem)
|
||||||
: spl_type_basic(SPL_PTR),
|
: spl_type_basic(SPL_PTR),
|
||||||
1};
|
1};
|
||||||
@@ -1130,18 +1011,7 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
|
|||||||
if (left.is_lvalue) {
|
if (left.is_lvalue) {
|
||||||
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
|
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
|
||||||
}
|
}
|
||||||
spl_type_info_t *elem = left.type->elem;
|
emit_load_or_addr_type(ctx, &left, left.type->elem);
|
||||||
if (elem->kind == TYPE_BASIC || elem->kind == TYPE_PTR) {
|
|
||||||
if (!ctx->addr_of_mode) {
|
|
||||||
spl_type_t bt = (elem->kind == TYPE_BASIC) ? elem->basic_type : SPL_PTR;
|
|
||||||
spl_emit(ctx, SPL_LOAD, bt, 0);
|
|
||||||
left = (spl_expr_result_t){elem, 0};
|
|
||||||
} else {
|
|
||||||
left = (spl_expr_result_t){elem, 1};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
left = (spl_expr_result_t){elem, 1};
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1153,16 +1023,14 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
|
|||||||
if (opt == TOK_L_BRACKET) {
|
if (opt == TOK_L_BRACKET) {
|
||||||
advance(ctx); /* skip [ */
|
advance(ctx); /* skip [ */
|
||||||
if (peek(ctx)->type == TOK_R_BRACKET) {
|
if (peek(ctx)->type == TOK_R_BRACKET) {
|
||||||
advance(ctx); /* empty brackets */
|
advance(ctx);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse index/begin expression before checking for range */
|
|
||||||
spl_parse_expr(ctx, PREC_MIN);
|
spl_parse_expr(ctx, PREC_MIN);
|
||||||
|
|
||||||
/* Check for slice: expr[begin..end] or expr[begin..] */
|
|
||||||
if (peek(ctx)->type == TOK_RANGE) {
|
if (peek(ctx)->type == TOK_RANGE) {
|
||||||
advance(ctx); /* skip .. */
|
advance(ctx);
|
||||||
spl_expr_result_t end_expr = {0};
|
spl_expr_result_t end_expr = {0};
|
||||||
int has_explicit_end = (peek(ctx)->type != TOK_R_BRACKET);
|
int has_explicit_end = (peek(ctx)->type != TOK_R_BRACKET);
|
||||||
if (has_explicit_end) {
|
if (has_explicit_end) {
|
||||||
@@ -1170,13 +1038,10 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
|
|||||||
}
|
}
|
||||||
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 (!has_explicit_end) {
|
||||||
if (left.type && left.type->kind == TYPE_ARRAY) {
|
if (left.type && left.type->kind == TYPE_ARRAY) {
|
||||||
spl_emit(ctx, SPL_PUSH, SPL_U64, left.type->array_len);
|
spl_emit(ctx, SPL_PUSH, SPL_U64, left.type->array_len);
|
||||||
} else if (left.type && left.type->kind == TYPE_SLICE) {
|
} 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_PICK, SPL_VOID, 1);
|
||||||
spl_emit(ctx, SPL_PUSH, SPL_U64, sizeof(spl_val_t));
|
spl_emit(ctx, SPL_PUSH, SPL_U64, sizeof(spl_val_t));
|
||||||
spl_emit(ctx, SPL_ADD, SPL_U64, 0);
|
spl_emit(ctx, SPL_ADD, SPL_U64, 0);
|
||||||
@@ -1184,29 +1049,25 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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 = spl_type_elem_stride(left.type->elem);
|
usize stride = spl_type_elem_stride(left.type->elem);
|
||||||
|
|
||||||
if (left.type->kind == TYPE_SLICE) {
|
if (left.type->kind == TYPE_SLICE) {
|
||||||
/* Stack: [struct_addr, begin, end].
|
|
||||||
* Inline ptr/len: ptr = data_ptr + begin*stride, len = end - begin. */
|
|
||||||
spl_emit(ctx, SPL_PICK, SPL_VOID, 2);
|
spl_emit(ctx, SPL_PICK, SPL_VOID, 2);
|
||||||
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0); /* [s,b,e,data_ptr] */
|
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
|
||||||
spl_emit(ctx, SPL_PICK, SPL_VOID, 2); /* [s,b,e,d,begin] */
|
spl_emit(ctx, SPL_PICK, SPL_VOID, 2);
|
||||||
spl_emit(ctx, SPL_PUSH, SPL_U64, stride);
|
spl_emit(ctx, SPL_PUSH, SPL_U64, stride);
|
||||||
spl_emit(ctx, SPL_MUL, SPL_U64, 0);
|
spl_emit(ctx, SPL_MUL, SPL_U64, 0);
|
||||||
spl_emit(ctx, SPL_ADD, SPL_U64, 0); /* [s,b,e,ptr] */
|
spl_emit(ctx, SPL_ADD, SPL_U64, 0);
|
||||||
spl_emit(ctx, SPL_PICK, SPL_VOID, 1); /* [s,b,e,ptr,end] */
|
spl_emit(ctx, SPL_PICK, SPL_VOID, 1);
|
||||||
spl_emit(ctx, SPL_PICK, SPL_VOID, 3); /* [s,b,e,ptr,end,begin] */
|
spl_emit(ctx, SPL_PICK, SPL_VOID, 3);
|
||||||
spl_emit(ctx, SPL_SUB, SPL_USIZE, 0); /* [s,b,e,ptr,len] */
|
spl_emit(ctx, SPL_SUB, SPL_USIZE, 0);
|
||||||
/* cleanup: drop [s,b,e] */
|
spl_emit(ctx, SPL_ROT, SPL_VOID, 0);
|
||||||
spl_emit(ctx, SPL_ROT, SPL_VOID, 0); /* [s,b,ptr,len,e] */
|
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
|
||||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* [s,b,ptr,len] */
|
spl_emit(ctx, SPL_ROT, SPL_VOID, 0);
|
||||||
spl_emit(ctx, SPL_ROT, SPL_VOID, 0); /* [s,ptr,len,b] */
|
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
|
||||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* [s,ptr,len] */
|
spl_emit(ctx, SPL_ROT, SPL_VOID, 0);
|
||||||
spl_emit(ctx, SPL_ROT, SPL_VOID, 0); /* [ptr,len,s] */
|
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
|
||||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* [ptr,len] */
|
|
||||||
} else {
|
} else {
|
||||||
emit_slice_create(ctx, stride);
|
emit_slice_create(ctx, stride);
|
||||||
}
|
}
|
||||||
@@ -1217,20 +1078,14 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
|
|||||||
|
|
||||||
expect(ctx, TOK_R_BRACKET);
|
expect(ctx, TOK_R_BRACKET);
|
||||||
|
|
||||||
/* Array/slice/pointer indexing */
|
|
||||||
if (left.type && (left.type->kind == TYPE_ARRAY || left.type->kind == TYPE_PTR ||
|
if (left.type && (left.type->kind == TYPE_ARRAY || left.type->kind == TYPE_PTR ||
|
||||||
left.type->kind == TYPE_SLICE)) {
|
left.type->kind == TYPE_SLICE)) {
|
||||||
spl_type_info_t *elem = left.type->elem;
|
spl_type_info_t *elem = left.type->elem;
|
||||||
|
|
||||||
if (left.type->kind == TYPE_SLICE) {
|
if (left.type->kind == TYPE_SLICE) {
|
||||||
/* Slice: stack has [slice_struct_addr, index].
|
|
||||||
* Load data ptr first, then compute element address. */
|
|
||||||
emit_slice_index(ctx, elem);
|
emit_slice_index(ctx, elem);
|
||||||
} else {
|
} else {
|
||||||
/* Stack arrays and pointer indexing */
|
|
||||||
if (left.type->kind == TYPE_PTR && left.is_lvalue) {
|
if (left.type->kind == TYPE_PTR && left.is_lvalue) {
|
||||||
/* Stack: [addr_of_ptr, index]. Swap to get addr on top, load ptr value,
|
|
||||||
* swap back */
|
|
||||||
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
|
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
|
||||||
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
|
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
|
||||||
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
|
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
|
||||||
@@ -1240,21 +1095,34 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
|
|||||||
spl_emit(ctx, SPL_MUL, SPL_U64, 0);
|
spl_emit(ctx, SPL_MUL, SPL_U64, 0);
|
||||||
spl_emit(ctx, SPL_ADD, SPL_U64, 0);
|
spl_emit(ctx, SPL_ADD, SPL_U64, 0);
|
||||||
}
|
}
|
||||||
if (elem && (elem->kind == TYPE_BASIC || elem->kind == TYPE_PTR)) {
|
if (elem)
|
||||||
if (!ctx->addr_of_mode) {
|
emit_load_or_addr_type(ctx, &left, elem);
|
||||||
spl_type_t bt = (elem->kind == TYPE_BASIC) ? elem->basic_type : SPL_PTR;
|
|
||||||
spl_emit(ctx, SPL_LOAD, bt, 0);
|
|
||||||
left = (spl_expr_result_t){elem, 0};
|
|
||||||
} else {
|
|
||||||
left = (spl_expr_result_t){elem, 1};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
left = (spl_expr_result_t){elem, 1};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
* 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) {
|
||||||
|
left = parse_postfix_expr(ctx, left);
|
||||||
|
|
||||||
|
skip_nl(ctx);
|
||||||
|
spl_tok_type_t opt = peek(ctx)->type;
|
||||||
|
|
||||||
/* Binary operators */
|
/* Binary operators */
|
||||||
int prec = tok_prec(opt);
|
int prec = tok_prec(opt);
|
||||||
if (prec == 0 || prec < min_prec)
|
if (prec == 0 || prec < min_prec)
|
||||||
@@ -1276,14 +1144,12 @@ static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, sp
|
|||||||
|
|
||||||
/* Short-circuit logical operators */
|
/* Short-circuit logical operators */
|
||||||
if (op == TOK_AND_AND) {
|
if (op == TOK_AND_AND) {
|
||||||
/* left is already evaluated and on stack. If it's false (0), skip right. */
|
|
||||||
spl_val_t bz_addr = spl_emit_bz(ctx);
|
spl_val_t bz_addr = spl_emit_bz(ctx);
|
||||||
spl_parse_expr(ctx, next_prec);
|
spl_parse_expr(ctx, next_prec);
|
||||||
spl_patch_to_here(ctx, bz_addr);
|
spl_patch_to_here(ctx, bz_addr);
|
||||||
return (spl_expr_result_t){spl_type_basic(SPL_I32), 0};
|
return (spl_expr_result_t){spl_type_basic(SPL_I32), 0};
|
||||||
}
|
}
|
||||||
if (op == TOK_OR_OR) {
|
if (op == TOK_OR_OR) {
|
||||||
/* If left is true (non-zero), skip right. */
|
|
||||||
spl_val_t bnz_addr = spl_emit_bnz(ctx);
|
spl_val_t bnz_addr = spl_emit_bnz(ctx);
|
||||||
spl_parse_expr(ctx, next_prec);
|
spl_parse_expr(ctx, next_prec);
|
||||||
spl_patch_to_here(ctx, bnz_addr);
|
spl_patch_to_here(ctx, bnz_addr);
|
||||||
@@ -1296,7 +1162,6 @@ static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, sp
|
|||||||
op == TOK_ASSIGN_OR || op == TOK_ASSIGN_XOR || op == TOK_ASSIGN_L_SH ||
|
op == TOK_ASSIGN_OR || op == TOK_ASSIGN_XOR || op == TOK_ASSIGN_L_SH ||
|
||||||
op == TOK_ASSIGN_R_SH) {
|
op == TOK_ASSIGN_R_SH) {
|
||||||
|
|
||||||
/* RHS must not inherit addr_of_mode from LHS */
|
|
||||||
int saved_addr_of_mode = ctx->addr_of_mode;
|
int saved_addr_of_mode = ctx->addr_of_mode;
|
||||||
ctx->addr_of_mode = 0;
|
ctx->addr_of_mode = 0;
|
||||||
spl_expr_result_t right = spl_parse_expr(ctx, PREC_MIN);
|
spl_expr_result_t right = spl_parse_expr(ctx, PREC_MIN);
|
||||||
@@ -1307,17 +1172,14 @@ static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, sp
|
|||||||
? (left.type->kind == TYPE_BASIC ? left.type->basic_type : SPL_PTR)
|
? (left.type->kind == TYPE_BASIC ? left.type->basic_type : SPL_PTR)
|
||||||
: SPL_I32;
|
: SPL_I32;
|
||||||
if (op == TOK_ASSIGN) {
|
if (op == TOK_ASSIGN) {
|
||||||
/* Simple assignment: stack is [addr, rhs] */
|
|
||||||
/* STORE pops TOS=value, TOS-1=address — already correct order */
|
|
||||||
spl_emit(ctx, SPL_STORE, bt, 0);
|
spl_emit(ctx, SPL_STORE, bt, 0);
|
||||||
} else {
|
} else {
|
||||||
/* Compound: left = left op right — stack: [addr, rhs] */
|
spl_emit(ctx, SPL_PICK, SPL_VOID, 1);
|
||||||
spl_emit(ctx, SPL_PICK, SPL_VOID, 1); /* [addr, rhs, addr] */
|
spl_emit(ctx, SPL_LOAD, bt, 0);
|
||||||
spl_emit(ctx, SPL_LOAD, bt, 0); /* [addr, rhs, old_val] */
|
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
|
||||||
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); /* [addr, old_val, rhs] */
|
|
||||||
int sop = binop_to_sir(assign_to_binop(op), bt);
|
int sop = binop_to_sir(assign_to_binop(op), bt);
|
||||||
if (sop >= 0)
|
if (sop >= 0)
|
||||||
spl_emit(ctx, sop, bt, 0); /* [addr, result] */
|
spl_emit(ctx, sop, bt, 0);
|
||||||
spl_emit(ctx, SPL_STORE, bt, 0);
|
spl_emit(ctx, SPL_STORE, bt, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1349,9 +1211,7 @@ spl_enum_variant_t *spl_emit_match_enum_cmp(spl_comp_t *ctx, spl_type_info_t *en
|
|||||||
advance(ctx);
|
advance(ctx);
|
||||||
spl_tok_t *vtok = advance(ctx);
|
spl_tok_t *vtok = advance(ctx);
|
||||||
char vname[256];
|
char vname[256];
|
||||||
usize vnl = vtok->len < 255 ? vtok->len : 255;
|
spl_tok_copy_name(vtok, vname, sizeof(vname));
|
||||||
memcpy(vname, vtok->lexeme, vnl);
|
|
||||||
vname[vnl] = '\0';
|
|
||||||
|
|
||||||
vec_for(enum_type->variants, vi) {
|
vec_for(enum_type->variants, vi) {
|
||||||
spl_enum_variant_t *v = &vec_at(enum_type->variants, vi);
|
spl_enum_variant_t *v = &vec_at(enum_type->variants, vi);
|
||||||
|
|||||||
@@ -21,6 +21,44 @@ spl_tok_t *advance(spl_comp_t *ctx) {
|
|||||||
|
|
||||||
/* Shared helper: register a function, declare params, parse body, end function.
|
/* Shared helper: register a function, declare params, parse body, end function.
|
||||||
* Used by both top-level fn decl and methods inside type bodies. */
|
* Used by both top-level fn decl and methods inside type bodies. */
|
||||||
|
/* Shared helper: parse function/method parameter list: (name: type, name: type, ...)
|
||||||
|
* Returns number of params parsed. Stores names in pnames and types in ptypes
|
||||||
|
* (both must be MAX_PARAMS-sized arrays). */
|
||||||
|
enum { MAX_PARAMS = 64 };
|
||||||
|
|
||||||
|
static int parse_params_decl(spl_comp_t *ctx, char pnames[][256], spl_type_info_t *ptypes[]) {
|
||||||
|
int nparams = 0;
|
||||||
|
skip_nl(ctx);
|
||||||
|
if (peek(ctx)->type != TOK_R_PAREN) {
|
||||||
|
while (1) {
|
||||||
|
spl_tok_t *pname = advance(ctx);
|
||||||
|
spl_tok_copy_name(pname, pnames[nparams], 256);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (peek(ctx)->type == TOK_ELLIPSIS) {
|
||||||
|
advance(ctx);
|
||||||
|
skip_nl(ctx);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect(ctx, TOK_R_PAREN);
|
||||||
|
return nparams;
|
||||||
|
}
|
||||||
|
|
||||||
static int parse_fn_body(spl_comp_t *ctx, const char *fn_name, spl_type_info_t *ret_type,
|
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 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);
|
int fi = spl_declare_func(ctx, fn_name, ret_type, nparams, 0, is_pub);
|
||||||
@@ -68,48 +106,15 @@ 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;
|
spl_tok_copy_name(fname_tok, fn_name, sizeof(fn_name));
|
||||||
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);
|
||||||
|
|
||||||
/* Parse parameters — collect names and types */
|
/* Parse parameters — collect names and types */
|
||||||
int nparams = 0;
|
|
||||||
enum { MAX_PARAMS = 64 };
|
|
||||||
char pnames[MAX_PARAMS][256];
|
char pnames[MAX_PARAMS][256];
|
||||||
spl_type_info_t *ptypes[MAX_PARAMS];
|
spl_type_info_t *ptypes[MAX_PARAMS];
|
||||||
skip_nl(ctx);
|
int nparams = parse_params_decl(ctx, pnames, ptypes);
|
||||||
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;
|
|
||||||
}
|
|
||||||
if (peek(ctx)->type == TOK_ELLIPSIS) {
|
|
||||||
advance(ctx);
|
|
||||||
skip_nl(ctx);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect(ctx, TOK_R_PAREN);
|
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
|
|
||||||
/* Return type (default: void) */
|
/* Return type (default: void) */
|
||||||
@@ -124,22 +129,7 @@ static void parse_fn_decl(spl_comp_t *ctx, int is_extern, int is_pub) {
|
|||||||
/* Extern function: register as native, no body */
|
/* Extern function: register as native, no body */
|
||||||
if (is_extern) {
|
if (is_extern) {
|
||||||
spl_declare_func(ctx, fn_name, ret_type, nparams, 1, is_pub);
|
spl_declare_func(ctx, fn_name, ret_type, nparams, 1, is_pub);
|
||||||
/* Add to prog->natives for NCALL dispatch */
|
spl_ensure_native(ctx, fn_name);
|
||||||
int found = -1;
|
|
||||||
vec_for(ctx->prog.natives, ni) {
|
|
||||||
if (strcmp(vec_at(ctx->prog.natives, ni).name, fn_name) == 0) {
|
|
||||||
found = (int)ni;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (found < 0) {
|
|
||||||
spl_native_t nat;
|
|
||||||
memset(&nat, 0, sizeof(nat));
|
|
||||||
nat.name = strdup(fn_name);
|
|
||||||
nat.idx_of_strtab = 0;
|
|
||||||
nat.impl_fn = NULL; /* resolved by VM at runtime */
|
|
||||||
vec_push(ctx->prog.natives, nat);
|
|
||||||
}
|
|
||||||
if (peek(ctx)->type == TOK_SEMICOLON)
|
if (peek(ctx)->type == TOK_SEMICOLON)
|
||||||
advance(ctx);
|
advance(ctx);
|
||||||
return;
|
return;
|
||||||
@@ -158,22 +148,84 @@ static void parse_fn_decl(spl_comp_t *ctx, int is_extern, int is_pub) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* Parse struct/union body (shared for struct and union containers)
|
* Shared helper: parse a method declaration inside a type body.
|
||||||
|
* Used by both struct_body and enum_body parsers.
|
||||||
|
* fn name(params) ret-type { body }
|
||||||
|
* ============================================================ */
|
||||||
|
|
||||||
|
static void parse_method_decl(spl_comp_t *ctx, spl_type_info_t *container) {
|
||||||
|
advance(ctx); /* fn */
|
||||||
|
skip_nl(ctx);
|
||||||
|
spl_tok_t *mname_tok = advance(ctx);
|
||||||
|
char mname[256];
|
||||||
|
spl_tok_copy_name(mname_tok, mname, sizeof(mname));
|
||||||
|
|
||||||
|
/* Build qualified name: TypeName.method_name */
|
||||||
|
char qualified[512];
|
||||||
|
snprintf(qualified, sizeof(qualified), "%s.%s", container->name ? container->name : "anon",
|
||||||
|
mname);
|
||||||
|
|
||||||
|
skip_nl(ctx);
|
||||||
|
expect(ctx, TOK_L_PAREN);
|
||||||
|
|
||||||
|
/* Parse parameters using shared helper */
|
||||||
|
char pnames[MAX_PARAMS][256];
|
||||||
|
spl_type_info_t *ptypes[MAX_PARAMS];
|
||||||
|
int nparams = parse_params_decl(ctx, pnames, ptypes);
|
||||||
|
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 = container->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(container, mname, fi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
* Parse type container body (shared for struct, union, enum)
|
||||||
|
*
|
||||||
|
* For struct/union: fields are added for identifiers
|
||||||
|
* For enum: variants are added for identifiers
|
||||||
*
|
*
|
||||||
* Body supports:
|
* Body supports:
|
||||||
* var name: type; — field declarations
|
* var name: type; — field declarations (struct/union only)
|
||||||
* name: type, — field declarations (old-style)
|
* name: type, — field/variant declarations
|
||||||
|
* name: Type, — enum variant with data
|
||||||
|
* name, — simple enum variant
|
||||||
* type Name = ...; — nested type declarations
|
* type Name = ...; — nested type declarations
|
||||||
* fn name(...) type { } — methods
|
* fn name(...) type { } — methods
|
||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
|
|
||||||
static void parse_struct_body(spl_comp_t *ctx, spl_type_info_t *st) {
|
static void parse_type_body(spl_comp_t *ctx, spl_type_info_t *container, int is_enum) {
|
||||||
if (peek(ctx)->type != TOK_L_BRACE)
|
if (peek(ctx)->type != TOK_L_BRACE)
|
||||||
return;
|
return;
|
||||||
advance(ctx); /* { */
|
advance(ctx); /* { */
|
||||||
|
|
||||||
/* === Pass 1: Parse all nested type declarations first ===
|
/* === Pass 1: Parse all nested type declarations first ===
|
||||||
* This allows field declarations to reference types defined later in the body. */
|
* This allows fields/variants to reference types defined later. */
|
||||||
{
|
{
|
||||||
usize saved = ctx->tok_idx;
|
usize saved = ctx->tok_idx;
|
||||||
int depth = 1;
|
int depth = 1;
|
||||||
@@ -193,11 +245,10 @@ static void parse_struct_body(spl_comp_t *ctx, spl_type_info_t *st) {
|
|||||||
advance(ctx);
|
advance(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Reset to start of body for second pass */
|
|
||||||
ctx->tok_idx = saved;
|
ctx->tok_idx = saved;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* === Pass 2: Parse fields and methods === */
|
/* === Pass 2: Parse fields/variants and methods === */
|
||||||
{
|
{
|
||||||
int depth = 1;
|
int depth = 1;
|
||||||
while (depth > 0 && ctx->tok_idx < vec_size(ctx->toks)) {
|
while (depth > 0 && ctx->tok_idx < vec_size(ctx->toks)) {
|
||||||
@@ -214,10 +265,10 @@ static void parse_struct_body(spl_comp_t *ctx, spl_type_info_t *st) {
|
|||||||
}
|
}
|
||||||
advance(ctx);
|
advance(ctx);
|
||||||
} else if (tt == KW_TYPE && depth == 1) {
|
} else if (tt == KW_TYPE && depth == 1) {
|
||||||
/* Nested type — already parsed in pass 1, skip by re-parsing */
|
/* Nested type — already parsed in pass 1, skip */
|
||||||
parse_type_decl(ctx);
|
parse_type_decl(ctx);
|
||||||
} else if (tt == KW_VAR && depth == 1) {
|
} else if (tt == KW_VAR && depth == 1 && !is_enum) {
|
||||||
/* var name: type; */
|
/* var name: type; (struct/union only) */
|
||||||
advance(ctx); /* var */
|
advance(ctx); /* var */
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
spl_tok_t *ftok = advance(ctx);
|
spl_tok_t *ftok = advance(ctx);
|
||||||
@@ -227,286 +278,54 @@ static void parse_struct_body(spl_comp_t *ctx, spl_type_info_t *st) {
|
|||||||
skip_nl(ctx);
|
skip_nl(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;
|
spl_tok_copy_name(ftok, fname, sizeof(fname));
|
||||||
memcpy(fname, ftok->lexeme, fnl);
|
spl_type_add_field(container, fname, ftype);
|
||||||
fname[fnl] = '\0';
|
|
||||||
spl_type_add_field(st, fname, ftype);
|
|
||||||
}
|
}
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
if (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_COMMA)
|
if (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_COMMA)
|
||||||
advance(ctx);
|
advance(ctx);
|
||||||
} else if (tt == TOK_IDENT && depth == 1) {
|
} else if (tt == TOK_IDENT && depth == 1) {
|
||||||
/* Old-style field: name: type, */
|
if (is_enum) {
|
||||||
spl_tok_t *ftok = advance(ctx);
|
/* Variant: Name or Name: Type */
|
||||||
skip_nl(ctx);
|
spl_tok_t *vtok = advance(ctx);
|
||||||
if (peek(ctx)->type == TOK_COLON) {
|
|
||||||
advance(ctx); /* : */
|
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
spl_type_info_t *ftype = spl_parse_type(ctx);
|
if (peek(ctx)->type == TOK_COLON) {
|
||||||
char fname[256];
|
advance(ctx); /* : */
|
||||||
usize fnl = ftok->len < 255 ? ftok->len : 255;
|
|
||||||
memcpy(fname, ftok->lexeme, fnl);
|
|
||||||
fname[fnl] = '\0';
|
|
||||||
spl_type_add_field(st, fname, ftype);
|
|
||||||
}
|
|
||||||
skip_nl(ctx);
|
|
||||||
if (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_COMMA)
|
|
||||||
advance(ctx);
|
|
||||||
} else if (tt == KW_FN && depth == 1) {
|
|
||||||
/* Method — parse properly using parse_fn_body */
|
|
||||||
advance(ctx); /* fn */
|
|
||||||
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);
|
skip_nl(ctx);
|
||||||
if (peek(ctx)->type == TOK_COLON) {
|
spl_type_info_t *dtype = spl_parse_type(ctx);
|
||||||
advance(ctx); /* : */
|
char vname[256];
|
||||||
skip_nl(ctx);
|
spl_tok_copy_name(vtok, vname, sizeof(vname));
|
||||||
ptypes[nparams] = spl_parse_type(ctx);
|
spl_type_add_variant(container, vname, dtype);
|
||||||
} else {
|
} else {
|
||||||
ptypes[nparams] = spl_type_basic(SPL_I32);
|
char vname[256];
|
||||||
}
|
spl_tok_copy_name(vtok, vname, sizeof(vname));
|
||||||
nparams++;
|
spl_type_add_variant(container, vname, NULL);
|
||||||
skip_nl(ctx);
|
|
||||||
if (peek(ctx)->type == TOK_COMMA) {
|
|
||||||
advance(ctx);
|
|
||||||
skip_nl(ctx);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spl_type_compute_layout(st);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================
|
|
||||||
* Parse enum body
|
|
||||||
*
|
|
||||||
* Body supports:
|
|
||||||
* Name — simple variant
|
|
||||||
* Name: Type — variant with data
|
|
||||||
* var name: type; — field-style variant
|
|
||||||
* type Name = ...; — nested type declarations
|
|
||||||
* fn name(...) type { } — methods (skipped)
|
|
||||||
* ============================================================ */
|
|
||||||
|
|
||||||
static void parse_enum_body(spl_comp_t *ctx, spl_type_info_t *et) {
|
|
||||||
if (peek(ctx)->type != TOK_L_BRACE)
|
|
||||||
return;
|
|
||||||
advance(ctx); /* { */
|
|
||||||
|
|
||||||
/* === Pass 1: Parse all nested type declarations first === */
|
|
||||||
{
|
|
||||||
usize saved = ctx->tok_idx;
|
|
||||||
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) {
|
|
||||||
parse_type_decl(ctx);
|
|
||||||
} else {
|
|
||||||
advance(ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx->tok_idx = saved;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Pass 2: Parse variants and methods === */
|
|
||||||
{
|
|
||||||
int depth = 1;
|
|
||||||
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) {
|
|
||||||
/* Already parsed in pass 1, re-parse to skip */
|
|
||||||
parse_type_decl(ctx);
|
|
||||||
} else if (tt == TOK_IDENT && depth == 1) {
|
|
||||||
/* Variant: Name or Name: Type */
|
|
||||||
spl_tok_t *vtok = advance(ctx);
|
|
||||||
skip_nl(ctx);
|
|
||||||
if (peek(ctx)->type == TOK_COLON) {
|
|
||||||
advance(ctx); /* : */
|
|
||||||
skip_nl(ctx);
|
|
||||||
spl_type_info_t *dtype = spl_parse_type(ctx);
|
|
||||||
char vname[256];
|
|
||||||
usize vnl = vtok->len < 255 ? vtok->len : 255;
|
|
||||||
memcpy(vname, vtok->lexeme, vnl);
|
|
||||||
vname[vnl] = '\0';
|
|
||||||
spl_type_add_variant(et, vname, dtype);
|
|
||||||
} else {
|
} else {
|
||||||
char vname[256];
|
/* Old-style field: name: type, */
|
||||||
usize vnl = vtok->len < 255 ? vtok->len : 255;
|
spl_tok_t *ftok = advance(ctx);
|
||||||
memcpy(vname, vtok->lexeme, vnl);
|
skip_nl(ctx);
|
||||||
vname[vnl] = '\0';
|
if (peek(ctx)->type == TOK_COLON) {
|
||||||
spl_type_add_variant(et, vname, NULL);
|
advance(ctx); /* : */
|
||||||
|
skip_nl(ctx);
|
||||||
|
spl_type_info_t *ftype = spl_parse_type(ctx);
|
||||||
|
char fname[256];
|
||||||
|
spl_tok_copy_name(ftok, fname, sizeof(fname));
|
||||||
|
spl_type_add_field(container, fname, ftype);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
if (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_COMMA)
|
if (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_COMMA)
|
||||||
advance(ctx);
|
advance(ctx);
|
||||||
} else if (tt == KW_FN && depth == 1) {
|
} else if (tt == KW_FN && depth == 1) {
|
||||||
/* Method — parse properly using parse_fn_body */
|
parse_method_decl(ctx, container);
|
||||||
advance(ctx); /* fn */
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 {
|
} else {
|
||||||
advance(ctx);
|
advance(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spl_type_compute_layout(et);
|
spl_type_compute_layout(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
@@ -521,9 +340,7 @@ void parse_type_decl(spl_comp_t *ctx) {
|
|||||||
advance(ctx); /* type */
|
advance(ctx); /* type */
|
||||||
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;
|
spl_tok_copy_name(name_tok, tname, sizeof(tname));
|
||||||
memcpy(tname, name_tok->lexeme, tnl);
|
|
||||||
tname[tnl] = '\0';
|
|
||||||
|
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
expect(ctx, TOK_ASSIGN);
|
expect(ctx, TOK_ASSIGN);
|
||||||
@@ -535,20 +352,20 @@ void parse_type_decl(spl_comp_t *ctx) {
|
|||||||
/* Register type early to allow self-referential fields */
|
/* Register type early to allow self-referential fields */
|
||||||
map_put(ctx->type_defs, strdup(tname), st);
|
map_put(ctx->type_defs, strdup(tname), st);
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
parse_struct_body(ctx, st);
|
parse_type_body(ctx, st, 0);
|
||||||
} else if (peek(ctx)->type == KW_UNION) {
|
} else if (peek(ctx)->type == KW_UNION) {
|
||||||
advance(ctx);
|
advance(ctx);
|
||||||
spl_type_info_t *ut = spl_type_union(tname);
|
spl_type_info_t *ut = spl_type_union(tname);
|
||||||
map_put(ctx->type_defs, strdup(tname), ut);
|
map_put(ctx->type_defs, strdup(tname), ut);
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
parse_struct_body(ctx, ut);
|
parse_type_body(ctx, ut, 0);
|
||||||
} else if (peek(ctx)->type == KW_ENUM) {
|
} else if (peek(ctx)->type == KW_ENUM) {
|
||||||
advance(ctx);
|
advance(ctx);
|
||||||
spl_type_info_t *et = spl_type_enum(tname);
|
spl_type_info_t *et = spl_type_enum(tname);
|
||||||
/* Register type early to allow self-referential variants */
|
/* Register type early to allow self-referential variants */
|
||||||
map_put(ctx->type_defs, strdup(tname), et);
|
map_put(ctx->type_defs, strdup(tname), et);
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
parse_enum_body(ctx, et);
|
parse_type_body(ctx, et, 1);
|
||||||
} else if (peek(ctx)->type == TOK_IDENT ||
|
} else if (peek(ctx)->type == TOK_IDENT ||
|
||||||
(peek(ctx)->type >= KW_AS && peek(ctx)->type <= KW_ANY)) {
|
(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);
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
#include "spl_comp.h"
|
#include "spl_comp.h"
|
||||||
#include "spl_lex_util.h"
|
#include "spl_lex_util.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* Return statement: ret expr;
|
* Return statement: ret expr;
|
||||||
@@ -41,9 +40,7 @@ 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;
|
spl_tok_copy_name(name_tok, vname, sizeof(vname));
|
||||||
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;
|
||||||
@@ -141,6 +138,7 @@ void spl_parse_block(spl_comp_t *ctx) {
|
|||||||
|
|
||||||
/* Forward declaration for block expr */
|
/* Forward declaration for block expr */
|
||||||
static int is_assign_op(spl_tok_type_t t);
|
static int is_assign_op(spl_tok_type_t t);
|
||||||
|
static int lookahead_is_assign(spl_comp_t *ctx);
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* Block expression: { stmts; [trailing_expr] }
|
* Block expression: { stmts; [trailing_expr] }
|
||||||
@@ -174,24 +172,7 @@ spl_expr_result_t spl_parse_block_expr(spl_comp_t *ctx) {
|
|||||||
result = (spl_expr_result_t){0};
|
result = (spl_expr_result_t){0};
|
||||||
} else {
|
} else {
|
||||||
/* Expression — look ahead for assignment */
|
/* Expression — look ahead for assignment */
|
||||||
int is_assign = 0;
|
int is_assign = lookahead_is_assign(ctx);
|
||||||
{
|
|
||||||
usize look = ctx->tok_idx;
|
|
||||||
while (look < vec_size(ctx->toks)) {
|
|
||||||
spl_tok_type_t lt = vec_at(ctx->toks, look).type;
|
|
||||||
if (lt == TOK_SEMICOLON || lt == TOK_ENDLINE || lt == TOK_R_BRACE ||
|
|
||||||
lt == TOK_EOF)
|
|
||||||
break;
|
|
||||||
if (lt == TOK_L_PAREN)
|
|
||||||
break;
|
|
||||||
if (is_assign_op(lt)) {
|
|
||||||
is_assign = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
look++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int saved_addr = ctx->addr_of_mode;
|
int saved_addr = ctx->addr_of_mode;
|
||||||
if (is_assign)
|
if (is_assign)
|
||||||
ctx->addr_of_mode = 1;
|
ctx->addr_of_mode = 1;
|
||||||
@@ -286,11 +267,11 @@ static void loop_exit(spl_comp_t *ctx, spl_loop_save_t *save) {
|
|||||||
static void parse_while_stmt(spl_comp_t *ctx) {
|
static void parse_while_stmt(spl_comp_t *ctx) {
|
||||||
advance(ctx); /* while */
|
advance(ctx); /* while */
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
spl_expr_result_t cond = spl_parse_expr(ctx, PREC_MIN);
|
|
||||||
(void)cond;
|
|
||||||
|
|
||||||
spl_loop_save_t save;
|
spl_loop_save_t save;
|
||||||
loop_enter(ctx, &save);
|
loop_enter(ctx, &save);
|
||||||
|
spl_expr_result_t cond = spl_parse_expr(ctx, PREC_MIN);
|
||||||
|
(void)cond;
|
||||||
spl_val_t bz_addr = spl_emit_bz(ctx);
|
spl_val_t bz_addr = spl_emit_bz(ctx);
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
spl_parse_block(ctx);
|
spl_parse_block(ctx);
|
||||||
@@ -338,9 +319,7 @@ static void parse_for_stmt(spl_comp_t *ctx) {
|
|||||||
|
|
||||||
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;
|
spl_tok_copy_name(ivar, iname, sizeof(iname));
|
||||||
memcpy(iname, ivar->lexeme, inl);
|
|
||||||
iname[inl] = '\0';
|
|
||||||
|
|
||||||
spl_push_scope(ctx);
|
spl_push_scope(ctx);
|
||||||
int ioffset = spl_declare_var(ctx, iname, spl_type_basic(SPL_USIZE), 0);
|
int ioffset = spl_declare_var(ctx, iname, spl_type_basic(SPL_USIZE), 0);
|
||||||
@@ -410,18 +389,14 @@ static void parse_for_stmt(spl_comp_t *ctx) {
|
|||||||
/* Parse val variable name */
|
/* Parse val variable name */
|
||||||
spl_tok_t *vtok = advance(ctx);
|
spl_tok_t *vtok = advance(ctx);
|
||||||
char vname[256];
|
char vname[256];
|
||||||
usize vnl = vtok->len < 255 ? vtok->len : 255;
|
spl_tok_copy_name(vtok, vname, sizeof(vname));
|
||||||
memcpy(vname, vtok->lexeme, vnl);
|
|
||||||
vname[vnl] = '\0';
|
|
||||||
|
|
||||||
/* Parse optional idx variable name */
|
/* Parse optional idx variable name */
|
||||||
char iname[256] = {0};
|
char iname[256] = {0};
|
||||||
if (peek(ctx)->type == TOK_COMMA) {
|
if (peek(ctx)->type == TOK_COMMA) {
|
||||||
advance(ctx);
|
advance(ctx);
|
||||||
spl_tok_t *itok = advance(ctx);
|
spl_tok_t *itok = advance(ctx);
|
||||||
usize inl = itok->len < 255 ? itok->len : 255;
|
spl_tok_copy_name(itok, iname, sizeof(iname));
|
||||||
memcpy(iname, itok->lexeme, inl);
|
|
||||||
iname[inl] = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stack: [slice_addr] or whatever the slice expression left */
|
/* Stack: [slice_addr] or whatever the slice expression left */
|
||||||
@@ -602,9 +577,7 @@ static void parse_match_enum_bindings(spl_comp_t *ctx, spl_enum_variant_t *varia
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
spl_tok_t *btok = advance(ctx);
|
spl_tok_t *btok = advance(ctx);
|
||||||
char bname[256];
|
char bname[256];
|
||||||
usize bnl = btok->len < 255 ? btok->len : 255;
|
spl_tok_copy_name(btok, bname, sizeof(bname));
|
||||||
memcpy(bname, btok->lexeme, bnl);
|
|
||||||
bname[bnl] = '\0';
|
|
||||||
|
|
||||||
spl_type_info_t *btype = spl_type_basic(SPL_I32);
|
spl_type_info_t *btype = spl_type_basic(SPL_I32);
|
||||||
usize field_byte_off = 4; /* skip tag */
|
usize field_byte_off = 4; /* skip tag */
|
||||||
@@ -628,9 +601,7 @@ static void parse_match_enum_bindings(spl_comp_t *ctx, spl_enum_variant_t *varia
|
|||||||
/* Single-value binding */
|
/* Single-value binding */
|
||||||
spl_tok_t *btok = advance(ctx);
|
spl_tok_t *btok = advance(ctx);
|
||||||
char bname[256];
|
char bname[256];
|
||||||
usize bnl = btok->len < 255 ? btok->len : 255;
|
spl_tok_copy_name(btok, bname, sizeof(bname));
|
||||||
memcpy(bname, btok->lexeme, bnl);
|
|
||||||
bname[bnl] = '\0';
|
|
||||||
|
|
||||||
spl_type_info_t *btype = variant->data_type;
|
spl_type_info_t *btype = variant->data_type;
|
||||||
int boffset = spl_declare_var(ctx, bname, btype, 0);
|
int boffset = spl_declare_var(ctx, bname, btype, 0);
|
||||||
@@ -816,9 +787,7 @@ static void parse_extern_decl(spl_comp_t *ctx) {
|
|||||||
skip_nl(ctx);
|
skip_nl(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;
|
spl_tok_copy_name(fname_tok, fn_name, sizeof(fn_name));
|
||||||
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);
|
||||||
@@ -880,6 +849,25 @@ static int is_assign_op(spl_tok_type_t t) {
|
|||||||
t == TOK_ASSIGN_R_SH;
|
t == TOK_ASSIGN_R_SH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Scan ahead to check if the expression at current position is an assignment.
|
||||||
|
* Returns 1 if an assignment operator is found before a statement terminator
|
||||||
|
* or function-call paren. */
|
||||||
|
static int lookahead_is_assign(spl_comp_t *ctx) {
|
||||||
|
usize look = ctx->tok_idx;
|
||||||
|
while (look < vec_size(ctx->toks)) {
|
||||||
|
spl_tok_type_t t = vec_at(ctx->toks, look).type;
|
||||||
|
if (t == TOK_SEMICOLON || t == TOK_ENDLINE || t == TOK_L_BRACE || t == TOK_R_BRACE ||
|
||||||
|
t == TOK_EOF)
|
||||||
|
break;
|
||||||
|
if (t == TOK_L_PAREN)
|
||||||
|
break;
|
||||||
|
if (is_assign_op(t))
|
||||||
|
return 1;
|
||||||
|
look++;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void parse_expr_stmt(spl_comp_t *ctx) {
|
static void parse_expr_stmt(spl_comp_t *ctx) {
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
if (peek(ctx)->type == KW_RET) {
|
if (peek(ctx)->type == KW_RET) {
|
||||||
@@ -889,24 +877,8 @@ static void parse_expr_stmt(spl_comp_t *ctx) {
|
|||||||
|
|
||||||
usize prev = ctx->tok_idx;
|
usize prev = ctx->tok_idx;
|
||||||
|
|
||||||
/* Look ahead for assignment operator (scan past expression tokens) */
|
/* Look ahead for assignment operator */
|
||||||
int is_assign = 0;
|
int is_assign = lookahead_is_assign(ctx);
|
||||||
{
|
|
||||||
usize look = ctx->tok_idx;
|
|
||||||
while (look < vec_size(ctx->toks)) {
|
|
||||||
spl_tok_type_t t = vec_at(ctx->toks, look).type;
|
|
||||||
if (t == TOK_SEMICOLON || t == TOK_ENDLINE || t == TOK_L_BRACE || t == TOK_R_BRACE ||
|
|
||||||
t == TOK_EOF)
|
|
||||||
break;
|
|
||||||
if (t == TOK_L_PAREN)
|
|
||||||
break; /* function call, not assignment */
|
|
||||||
if (is_assign_op(t)) {
|
|
||||||
is_assign = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
look++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_assign)
|
if (is_assign)
|
||||||
ctx->addr_of_mode = 1;
|
ctx->addr_of_mode = 1;
|
||||||
|
|||||||
@@ -403,9 +403,7 @@ spl_type_info_t *spl_parse_type(spl_comp_t *ctx) {
|
|||||||
advance(ctx); /* : */
|
advance(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;
|
spl_tok_copy_name(ftok, fname, sizeof(fname));
|
||||||
memcpy(fname, ftok->lexeme, fnl);
|
|
||||||
fname[fnl] = '\0';
|
|
||||||
spl_type_add_field(t, fname, ftype);
|
spl_type_add_field(t, fname, ftype);
|
||||||
}
|
}
|
||||||
if (peek(ctx)->type == TOK_COMMA)
|
if (peek(ctx)->type == TOK_COMMA)
|
||||||
@@ -430,15 +428,11 @@ spl_type_info_t *spl_parse_type(spl_comp_t *ctx) {
|
|||||||
advance(ctx); /* : */
|
advance(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;
|
spl_tok_copy_name(vtok, vname, sizeof(vname));
|
||||||
memcpy(vname, vtok->lexeme, vnl);
|
|
||||||
vname[vnl] = '\0';
|
|
||||||
spl_type_add_variant(t, vname, dtype);
|
spl_type_add_variant(t, vname, dtype);
|
||||||
} else {
|
} else {
|
||||||
char vname[256];
|
char vname[256];
|
||||||
usize vnl = vtok->len < 255 ? vtok->len : 255;
|
spl_tok_copy_name(vtok, vname, sizeof(vname));
|
||||||
memcpy(vname, vtok->lexeme, vnl);
|
|
||||||
vname[vnl] = '\0';
|
|
||||||
spl_type_add_variant(t, vname, NULL);
|
spl_type_add_variant(t, vname, NULL);
|
||||||
}
|
}
|
||||||
if (peek(ctx)->type == TOK_COMMA)
|
if (peek(ctx)->type == TOK_COMMA)
|
||||||
|
|||||||
Reference in New Issue
Block a user