stage1 完成11-13测试
This commit is contained in:
@@ -21,6 +21,7 @@ typedef enum {
|
|||||||
TYPE_ARRAY,
|
TYPE_ARRAY,
|
||||||
TYPE_SLICE,
|
TYPE_SLICE,
|
||||||
TYPE_STRUCT,
|
TYPE_STRUCT,
|
||||||
|
TYPE_UNION,
|
||||||
TYPE_ENUM,
|
TYPE_ENUM,
|
||||||
TYPE_ENUM_VARIANT, /* enum variant with data */
|
TYPE_ENUM_VARIANT, /* enum variant with data */
|
||||||
TYPE_NAME, /* named alias */
|
TYPE_NAME, /* named alias */
|
||||||
@@ -66,6 +67,7 @@ spl_type_info_t *spl_type_ptr(spl_type_info_t *elem);
|
|||||||
spl_type_info_t *spl_type_array(spl_type_info_t *elem, usize len);
|
spl_type_info_t *spl_type_array(spl_type_info_t *elem, usize len);
|
||||||
spl_type_info_t *spl_type_slice(spl_type_info_t *elem);
|
spl_type_info_t *spl_type_slice(spl_type_info_t *elem);
|
||||||
spl_type_info_t *spl_type_struct(const char *name);
|
spl_type_info_t *spl_type_struct(const char *name);
|
||||||
|
spl_type_info_t *spl_type_union(const char *name);
|
||||||
spl_type_info_t *spl_type_enum(const char *name);
|
spl_type_info_t *spl_type_enum(const char *name);
|
||||||
void spl_type_add_field(spl_type_info_t *st, const char *name, spl_type_info_t *ftype);
|
void spl_type_add_field(spl_type_info_t *st, const char *name, spl_type_info_t *ftype);
|
||||||
void spl_type_add_variant(spl_type_info_t *et, const char *name, spl_type_info_t *dtype);
|
void spl_type_add_variant(spl_type_info_t *et, const char *name, spl_type_info_t *dtype);
|
||||||
@@ -251,4 +253,8 @@ void spl_emit_defer_epilogue(spl_comp_t *ctx);
|
|||||||
spl_type_info_t *spl_resolve_type(spl_comp_t *ctx, const char *name);
|
spl_type_info_t *spl_resolve_type(spl_comp_t *ctx, const char *name);
|
||||||
spl_type_info_t *spl_parse_type(spl_comp_t *ctx);
|
spl_type_info_t *spl_parse_type(spl_comp_t *ctx);
|
||||||
|
|
||||||
|
/* Shared token helpers (defined in spl_parser.c) */
|
||||||
|
spl_tok_t *peek(spl_comp_t *ctx);
|
||||||
|
spl_tok_t *advance(spl_comp_t *ctx);
|
||||||
|
|
||||||
#endif /* __SPL_COMP_H__ */
|
#endif /* __SPL_COMP_H__ */
|
||||||
|
|||||||
@@ -10,14 +10,7 @@
|
|||||||
* Token helpers
|
* Token helpers
|
||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
|
|
||||||
static spl_tok_t *peek(spl_comp_t *ctx) { return &vec_at(ctx->toks, ctx->tok_idx); }
|
/* Token helpers — using shared peek/advance from spl_parser.c */
|
||||||
|
|
||||||
static spl_tok_t *advance(spl_comp_t *ctx) {
|
|
||||||
spl_tok_t *t = &vec_at(ctx->toks, ctx->tok_idx);
|
|
||||||
if (t->type != TOK_EOF)
|
|
||||||
ctx->tok_idx++;
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int match(spl_comp_t *ctx, spl_tok_type_t type) {
|
static int match(spl_comp_t *ctx, spl_tok_type_t type) {
|
||||||
if (peek(ctx)->type == type) {
|
if (peek(ctx)->type == type) {
|
||||||
@@ -156,6 +149,48 @@ static void emit_slice_index(spl_comp_t *ctx, spl_type_info_t *elem) {
|
|||||||
spl_emit(ctx, SPL_ADD, SPL_U64, 0); /* [data_ptr + index * elem_size] */
|
spl_emit(ctx, SPL_ADD, SPL_U64, 0); /* [data_ptr + index * elem_size] */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Try to resolve Type.Member for compile-time type access:
|
||||||
|
* - Enum variants → push variant integer value
|
||||||
|
* - Nested types (struct/enum/union) → return nested type
|
||||||
|
* Uses qualified name (TypeName.Member) first for namespace isolation,
|
||||||
|
* then falls back to simple name lookup.
|
||||||
|
* Returns 1 if resolved. */
|
||||||
|
static int spl_resolve_type_member(spl_comp_t *ctx, spl_type_info_t *type,
|
||||||
|
const char *field, spl_expr_result_t *result) {
|
||||||
|
/* For enum: check variants first */
|
||||||
|
if (type->kind == TYPE_ENUM) {
|
||||||
|
vec_for(type->variants, i) {
|
||||||
|
if (strcmp(vec_at(type->variants, i).name, field) == 0) {
|
||||||
|
spl_emit(ctx, SPL_PUSH, SPL_I32, vec_at(type->variants, i).value);
|
||||||
|
*result = (spl_expr_result_t){spl_type_basic(SPL_I32), 0};
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check nested types — try qualified name (Type.field) first for namespace isolation */
|
||||||
|
if (type->name) {
|
||||||
|
char qualified[512];
|
||||||
|
int qlen = snprintf(qualified, sizeof(qualified), "%s.%s", type->name, field);
|
||||||
|
if (qlen > 0 && (usize)qlen < sizeof(qualified)) {
|
||||||
|
spl_type_info_t *nested = spl_resolve_type(ctx, qualified);
|
||||||
|
if (nested) {
|
||||||
|
*result = (spl_expr_result_t){nested, 1};
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fallback: try simple name lookup */
|
||||||
|
spl_type_info_t *nested = spl_resolve_type(ctx, field);
|
||||||
|
if (nested) {
|
||||||
|
*result = (spl_expr_result_t){nested, 1};
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* SIR opcode for binary operator
|
* SIR opcode for binary operator
|
||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
@@ -470,6 +505,13 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if it's a type name (for enum variant access like Color.Red) */
|
||||||
|
spl_type_info_t *ttype = spl_resolve_type(ctx, name);
|
||||||
|
if (ttype) {
|
||||||
|
spl_expr_result_t r = {ttype, 1};
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
spl_comp_error(ctx, "undefined variable '%s'", name);
|
spl_comp_error(ctx, "undefined variable '%s'", name);
|
||||||
spl_expr_result_t r = {0};
|
spl_expr_result_t r = {0};
|
||||||
return r;
|
return r;
|
||||||
@@ -678,17 +720,13 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
|
|||||||
memcpy(fname, field->lexeme, fnl);
|
memcpy(fname, field->lexeme, fnl);
|
||||||
fname[fnl] = '\0';
|
fname[fnl] = '\0';
|
||||||
|
|
||||||
/* Check for enum variant: Type.Variant */
|
/* Compile-time type member resolution (enum variants, nested types) */
|
||||||
if (left.type && left.type->kind == TYPE_ENUM) {
|
if (left.type) {
|
||||||
/* It's a type-level enum reference */
|
spl_expr_result_t mresult = {0};
|
||||||
vec_for(left.type->variants, vi) {
|
if (spl_resolve_type_member(ctx, left.type, fname, &mresult)) {
|
||||||
if (strcmp(vec_at(left.type->variants, vi).name, fname) == 0) {
|
left = mresult;
|
||||||
spl_emit(ctx, SPL_PUSH, SPL_I32, vec_at(left.type->variants, vi).value);
|
continue;
|
||||||
left = (spl_expr_result_t){spl_type_basic(SPL_I32), 0};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Struct field access */
|
/* Struct field access */
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
#include "spl_comp.h"
|
#include "spl_comp.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static spl_tok_t *peek(spl_comp_t *ctx) { return &vec_at(ctx->toks, ctx->tok_idx); }
|
spl_tok_t *peek(spl_comp_t *ctx) { return &vec_at(ctx->toks, ctx->tok_idx); }
|
||||||
|
|
||||||
static spl_tok_t *advance(spl_comp_t *ctx) {
|
spl_tok_t *advance(spl_comp_t *ctx) {
|
||||||
spl_tok_t *t = &vec_at(ctx->toks, ctx->tok_idx);
|
spl_tok_t *t = &vec_at(ctx->toks, ctx->tok_idx);
|
||||||
if (t->type != TOK_EOF)
|
if (t->type != TOK_EOF)
|
||||||
ctx->tok_idx++;
|
ctx->tok_idx++;
|
||||||
@@ -173,31 +173,55 @@ static void parse_fn_decl(spl_comp_t *ctx, int is_extern, int is_pub) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* Parse type declaration
|
* Parse struct/union body (shared for struct and union containers)
|
||||||
* type Name = struct/enum { ... };
|
*
|
||||||
* type Name = ExistingType;
|
* Body supports:
|
||||||
|
* var name: type; — field declarations
|
||||||
|
* name: type, — field declarations (old-style)
|
||||||
|
* type Name = ...; — nested type declarations
|
||||||
|
* fn name(...) type { } — methods (skipped)
|
||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
|
|
||||||
void parse_type_decl(spl_comp_t *ctx) {
|
static void parse_struct_body(spl_comp_t *ctx, spl_type_info_t *st) {
|
||||||
advance(ctx); /* type */
|
if (peek(ctx)->type != TOK_L_BRACE)
|
||||||
spl_tok_t *name_tok = advance(ctx);
|
return;
|
||||||
char tname[256];
|
advance(ctx); /* { */
|
||||||
usize tnl = name_tok->len < 255 ? name_tok->len : 255;
|
|
||||||
memcpy(tname, name_tok->lexeme, tnl);
|
|
||||||
tname[tnl] = '\0';
|
|
||||||
|
|
||||||
skip_nl(ctx);
|
/* === Pass 1: Parse all nested type declarations first ===
|
||||||
expect(ctx, TOK_ASSIGN);
|
* This allows field declarations to reference types defined later in the body. */
|
||||||
skip_nl(ctx);
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Reset to start of body for second pass */
|
||||||
|
ctx->tok_idx = saved;
|
||||||
|
}
|
||||||
|
|
||||||
if (peek(ctx)->type == KW_STRUCT) {
|
/* === Pass 2: Parse fields and methods === */
|
||||||
advance(ctx);
|
{
|
||||||
spl_type_info_t *st = spl_type_struct(tname);
|
int depth = 1;
|
||||||
skip_nl(ctx);
|
while (depth > 0 && ctx->tok_idx < vec_size(ctx->toks)) {
|
||||||
if (peek(ctx)->type == TOK_L_BRACE) {
|
|
||||||
advance(ctx); /* { */
|
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
while (peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) {
|
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) {
|
||||||
|
/* Nested type — already parsed in pass 1, skip by re-parsing */
|
||||||
|
parse_type_decl(ctx);
|
||||||
|
}
|
||||||
|
else if (tt == KW_VAR && depth == 1) {
|
||||||
|
/* var name: type; */
|
||||||
|
advance(ctx); /* var */
|
||||||
|
skip_nl(ctx);
|
||||||
spl_tok_t *ftok = advance(ctx);
|
spl_tok_t *ftok = advance(ctx);
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
if (peek(ctx)->type == TOK_COLON) {
|
if (peek(ctx)->type == TOK_COLON) {
|
||||||
@@ -211,24 +235,103 @@ void parse_type_decl(spl_comp_t *ctx) {
|
|||||||
spl_type_add_field(st, fname, ftype);
|
spl_type_add_field(st, fname, ftype);
|
||||||
}
|
}
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
if (peek(ctx)->type == TOK_COMMA) {
|
if (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_COMMA)
|
||||||
advance(ctx);
|
advance(ctx);
|
||||||
|
}
|
||||||
|
else if (tt == TOK_IDENT && depth == 1) {
|
||||||
|
/* Old-style field: name: type, */
|
||||||
|
spl_tok_t *ftok = advance(ctx);
|
||||||
|
skip_nl(ctx);
|
||||||
|
if (peek(ctx)->type == TOK_COLON) {
|
||||||
|
advance(ctx); /* : */
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
|
spl_type_info_t *ftype = spl_parse_type(ctx);
|
||||||
|
char fname[256];
|
||||||
|
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 — skip over fn name(params) rettype { body } */
|
||||||
|
advance(ctx); /* fn */
|
||||||
|
while (ctx->tok_idx < vec_size(ctx->toks)) {
|
||||||
|
spl_tok_type_t mt = peek(ctx)->type;
|
||||||
|
if (mt == TOK_SEMICOLON) { advance(ctx); break; }
|
||||||
|
if (mt == TOK_L_BRACE) {
|
||||||
|
/* Skip function body counting braces */
|
||||||
|
advance(ctx);
|
||||||
|
int bd = 1;
|
||||||
|
while (bd > 0 && ctx->tok_idx < vec_size(ctx->toks)) {
|
||||||
|
if (peek(ctx)->type == TOK_L_BRACE) bd++;
|
||||||
|
else if (peek(ctx)->type == TOK_R_BRACE) bd--;
|
||||||
|
advance(ctx);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
advance(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (peek(ctx)->type == TOK_R_BRACE)
|
else {
|
||||||
advance(ctx);
|
advance(ctx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
spl_type_compute_layout(st);
|
}
|
||||||
map_put(ctx->type_defs, strdup(tname), st);
|
|
||||||
} else if (peek(ctx)->type == KW_ENUM) {
|
spl_type_compute_layout(st);
|
||||||
advance(ctx);
|
}
|
||||||
spl_type_info_t *et = spl_type_enum(tname);
|
|
||||||
skip_nl(ctx);
|
/* ============================================================
|
||||||
if (peek(ctx)->type == TOK_L_BRACE) {
|
* Parse enum body
|
||||||
advance(ctx); /* { */
|
*
|
||||||
|
* 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);
|
skip_nl(ctx);
|
||||||
while (peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) {
|
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);
|
spl_tok_t *vtok = advance(ctx);
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
if (peek(ctx)->type == TOK_COLON) {
|
if (peek(ctx)->type == TOK_COLON) {
|
||||||
@@ -248,16 +351,77 @@ void parse_type_decl(spl_comp_t *ctx) {
|
|||||||
spl_type_add_variant(et, vname, NULL);
|
spl_type_add_variant(et, vname, NULL);
|
||||||
}
|
}
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
if (peek(ctx)->type == TOK_COMMA) {
|
if (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_COMMA)
|
||||||
|
advance(ctx);
|
||||||
|
}
|
||||||
|
else if (tt == KW_FN && depth == 1) {
|
||||||
|
/* Method — skip */
|
||||||
|
advance(ctx); /* fn */
|
||||||
|
while (ctx->tok_idx < vec_size(ctx->toks)) {
|
||||||
|
spl_tok_type_t mt = peek(ctx)->type;
|
||||||
|
if (mt == TOK_SEMICOLON) { advance(ctx); break; }
|
||||||
|
if (mt == TOK_L_BRACE) {
|
||||||
|
advance(ctx);
|
||||||
|
int bd = 1;
|
||||||
|
while (bd > 0 && ctx->tok_idx < vec_size(ctx->toks)) {
|
||||||
|
if (peek(ctx)->type == TOK_L_BRACE) bd++;
|
||||||
|
else if (peek(ctx)->type == TOK_R_BRACE) bd--;
|
||||||
|
advance(ctx);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
advance(ctx);
|
advance(ctx);
|
||||||
skip_nl(ctx);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (peek(ctx)->type == TOK_R_BRACE)
|
else {
|
||||||
advance(ctx);
|
advance(ctx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
spl_type_compute_layout(et);
|
}
|
||||||
|
|
||||||
|
spl_type_compute_layout(et);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
* Parse type declaration
|
||||||
|
* type Name = struct { ... };
|
||||||
|
* type Name = union { ... };
|
||||||
|
* type Name = enum { ... };
|
||||||
|
* type Name = ExistingType;
|
||||||
|
* ============================================================ */
|
||||||
|
|
||||||
|
void parse_type_decl(spl_comp_t *ctx) {
|
||||||
|
advance(ctx); /* type */
|
||||||
|
spl_tok_t *name_tok = advance(ctx);
|
||||||
|
char tname[256];
|
||||||
|
usize tnl = name_tok->len < 255 ? name_tok->len : 255;
|
||||||
|
memcpy(tname, name_tok->lexeme, tnl);
|
||||||
|
tname[tnl] = '\0';
|
||||||
|
|
||||||
|
skip_nl(ctx);
|
||||||
|
expect(ctx, TOK_ASSIGN);
|
||||||
|
skip_nl(ctx);
|
||||||
|
|
||||||
|
if (peek(ctx)->type == KW_STRUCT) {
|
||||||
|
advance(ctx);
|
||||||
|
spl_type_info_t *st = spl_type_struct(tname);
|
||||||
|
/* Register type early to allow self-referential fields */
|
||||||
|
map_put(ctx->type_defs, strdup(tname), st);
|
||||||
|
skip_nl(ctx);
|
||||||
|
parse_struct_body(ctx, st);
|
||||||
|
} else if (peek(ctx)->type == KW_UNION) {
|
||||||
|
advance(ctx);
|
||||||
|
spl_type_info_t *ut = spl_type_union(tname);
|
||||||
|
map_put(ctx->type_defs, strdup(tname), ut);
|
||||||
|
skip_nl(ctx);
|
||||||
|
parse_struct_body(ctx, ut);
|
||||||
|
} else if (peek(ctx)->type == KW_ENUM) {
|
||||||
|
advance(ctx);
|
||||||
|
spl_type_info_t *et = spl_type_enum(tname);
|
||||||
|
/* 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);
|
||||||
|
parse_enum_body(ctx, et);
|
||||||
} 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);
|
||||||
|
|||||||
@@ -4,14 +4,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static spl_tok_t *peek(spl_comp_t *ctx) { return &vec_at(ctx->toks, ctx->tok_idx); }
|
/* Token helpers — using shared peek/advance from spl_parser.c */
|
||||||
|
|
||||||
static spl_tok_t *advance(spl_comp_t *ctx) {
|
|
||||||
spl_tok_t *t = &vec_at(ctx->toks, ctx->tok_idx);
|
|
||||||
if (t->type != TOK_EOF)
|
|
||||||
ctx->tok_idx++;
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int expect(spl_comp_t *ctx, spl_tok_type_t type) {
|
static int expect(spl_comp_t *ctx, spl_tok_type_t type) {
|
||||||
if (peek(ctx)->type == type) {
|
if (peek(ctx)->type == type) {
|
||||||
|
|||||||
@@ -136,6 +136,16 @@ spl_type_info_t *spl_type_struct(const char *name) {
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spl_type_info_t *spl_type_union(const char *name) {
|
||||||
|
spl_type_info_t *t = calloc(1, sizeof(spl_type_info_t));
|
||||||
|
t->kind = TYPE_UNION;
|
||||||
|
if (name)
|
||||||
|
t->name = strdup(name);
|
||||||
|
vec_init(t->fields);
|
||||||
|
t->resolved = 0;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
spl_type_info_t *spl_type_enum(const char *name) {
|
spl_type_info_t *spl_type_enum(const char *name) {
|
||||||
spl_type_info_t *t = calloc(1, sizeof(spl_type_info_t));
|
spl_type_info_t *t = calloc(1, sizeof(spl_type_info_t));
|
||||||
t->kind = TYPE_ENUM;
|
t->kind = TYPE_ENUM;
|
||||||
@@ -168,20 +178,34 @@ void spl_type_compute_layout(spl_type_info_t *t) {
|
|||||||
if (!t || t->resolved)
|
if (!t || t->resolved)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (t->kind == TYPE_STRUCT) {
|
if (t->kind == TYPE_STRUCT || t->kind == TYPE_UNION) {
|
||||||
usize offset = 0;
|
usize offset = 0;
|
||||||
|
usize max_field_size = 0;
|
||||||
vec_for(t->fields, i) {
|
vec_for(t->fields, i) {
|
||||||
spl_field_t *f = &vec_at(t->fields, i);
|
spl_field_t *f = &vec_at(t->fields, i);
|
||||||
if (f->type) {
|
if (f->type) {
|
||||||
spl_type_compute_layout(f->type);
|
spl_type_compute_layout(f->type);
|
||||||
f->offset = offset;
|
if (t->kind == TYPE_UNION) {
|
||||||
offset += f->type->byte_size;
|
/* Union: all fields at offset 0, size = max field size */
|
||||||
|
f->offset = 0;
|
||||||
|
if (f->type->byte_size > max_field_size)
|
||||||
|
max_field_size = f->type->byte_size;
|
||||||
|
} else {
|
||||||
|
/* Struct: sequential layout */
|
||||||
|
f->offset = offset;
|
||||||
|
offset += f->type->byte_size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t->byte_size = offset;
|
if (t->kind == TYPE_UNION) {
|
||||||
|
t->byte_size = max_field_size;
|
||||||
|
} else {
|
||||||
|
t->byte_size = offset;
|
||||||
|
}
|
||||||
/* Round up to slot alignment */
|
/* Round up to slot alignment */
|
||||||
usize slot_sz = sizeof(spl_val_t);
|
usize slot_sz = sizeof(spl_val_t);
|
||||||
t->slot_count = (offset + slot_sz - 1) / slot_sz;
|
t->slot_count = (t->byte_size + slot_sz - 1) / slot_sz;
|
||||||
|
if (t->slot_count < 1) t->slot_count = 1;
|
||||||
t->resolved = 1;
|
t->resolved = 1;
|
||||||
} else if (t->kind == TYPE_ENUM) {
|
} else if (t->kind == TYPE_ENUM) {
|
||||||
/* Enums with data need special handling */
|
/* Enums with data need special handling */
|
||||||
@@ -287,6 +311,8 @@ const char *spl_type_str(spl_type_info_t *t) {
|
|||||||
}
|
}
|
||||||
case TYPE_STRUCT:
|
case TYPE_STRUCT:
|
||||||
return t->name ? t->name : "struct";
|
return t->name ? t->name : "struct";
|
||||||
|
case TYPE_UNION:
|
||||||
|
return t->name ? t->name : "union";
|
||||||
case TYPE_ENUM:
|
case TYPE_ENUM:
|
||||||
return t->name ? t->name : "enum";
|
return t->name ? t->name : "enum";
|
||||||
case TYPE_NAME:
|
case TYPE_NAME:
|
||||||
@@ -355,6 +381,67 @@ spl_type_info_t *spl_parse_type(spl_comp_t *ctx) {
|
|||||||
return spl_type_array(elem, len);
|
return spl_type_array(elem, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Inline struct/union/enum type: struct { field: type, ... } */
|
||||||
|
if (tok->type == KW_STRUCT || tok->type == KW_UNION) {
|
||||||
|
int is_union = (tok->type == KW_UNION);
|
||||||
|
ctx->tok_idx++;
|
||||||
|
spl_type_info_t *t = is_union ? spl_type_union(NULL) : spl_type_struct(NULL);
|
||||||
|
if (peek(ctx)->type == TOK_L_BRACE) {
|
||||||
|
advance(ctx); /* { */
|
||||||
|
while (peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) {
|
||||||
|
spl_tok_t *ftok = advance(ctx);
|
||||||
|
if (peek(ctx)->type == TOK_COLON) {
|
||||||
|
advance(ctx); /* : */
|
||||||
|
spl_type_info_t *ftype = spl_parse_type(ctx);
|
||||||
|
char fname[256];
|
||||||
|
usize fnl = ftok->len < 255 ? ftok->len : 255;
|
||||||
|
memcpy(fname, ftok->lexeme, fnl);
|
||||||
|
fname[fnl] = '\0';
|
||||||
|
spl_type_add_field(t, fname, ftype);
|
||||||
|
}
|
||||||
|
if (peek(ctx)->type == TOK_COMMA)
|
||||||
|
advance(ctx);
|
||||||
|
}
|
||||||
|
if (peek(ctx)->type == TOK_R_BRACE)
|
||||||
|
advance(ctx);
|
||||||
|
}
|
||||||
|
spl_type_compute_layout(t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inline enum type: enum { A, B, C, ... } */
|
||||||
|
if (tok->type == KW_ENUM) {
|
||||||
|
ctx->tok_idx++;
|
||||||
|
spl_type_info_t *t = spl_type_enum(NULL);
|
||||||
|
if (peek(ctx)->type == TOK_L_BRACE) {
|
||||||
|
advance(ctx); /* { */
|
||||||
|
while (peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) {
|
||||||
|
spl_tok_t *vtok = advance(ctx);
|
||||||
|
if (peek(ctx)->type == TOK_COLON) {
|
||||||
|
advance(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(t, vname, dtype);
|
||||||
|
} else {
|
||||||
|
char vname[256];
|
||||||
|
usize vnl = vtok->len < 255 ? vtok->len : 255;
|
||||||
|
memcpy(vname, vtok->lexeme, vnl);
|
||||||
|
vname[vnl] = '\0';
|
||||||
|
spl_type_add_variant(t, vname, NULL);
|
||||||
|
}
|
||||||
|
if (peek(ctx)->type == TOK_COMMA)
|
||||||
|
advance(ctx);
|
||||||
|
}
|
||||||
|
if (peek(ctx)->type == TOK_R_BRACE)
|
||||||
|
advance(ctx);
|
||||||
|
}
|
||||||
|
spl_type_compute_layout(t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
/* Identifier: basic type or named type */
|
/* Identifier: basic type or named type */
|
||||||
if (tok->type == TOK_IDENT || ((int)tok->type >= (int)KW_AS && (int)tok->type <= (int)KW_ANY)) {
|
if (tok->type == TOK_IDENT || ((int)tok->type >= (int)KW_AS && (int)tok->type <= (int)KW_ANY)) {
|
||||||
const char *name = tok->lexeme;
|
const char *name = tok->lexeme;
|
||||||
|
|||||||
@@ -28,12 +28,18 @@ fn main() i32 {
|
|||||||
with_cleanup();
|
with_cleanup();
|
||||||
vm_printf("after with_cleanup\n");
|
vm_printf("after with_cleanup\n");
|
||||||
|
|
||||||
|
/* 多个 defer 应逆序执行出作用域应该立刻执行,包括循环作用域 */
|
||||||
|
{
|
||||||
|
defer vm_printf("block defer last\n");
|
||||||
|
defer vm_printf("block defer middle\n");
|
||||||
|
defer vm_printf("block defer first (should print third)\n");
|
||||||
|
}
|
||||||
|
|
||||||
/* 多个 defer 应逆序执行 */
|
/* 多个 defer 应逆序执行 */
|
||||||
defer vm_printf("defer last\n");
|
defer vm_printf("defer last\n");
|
||||||
defer vm_printf("defer middle\n");
|
defer vm_printf("defer middle\n");
|
||||||
defer vm_printf("defer first (should print third)\n");
|
defer vm_printf("defer first (should print third)\n");
|
||||||
|
|
||||||
vm_printf("--- defer test end ---\n");
|
vm_printf("--- defer test end ---\n");
|
||||||
|
|
||||||
ret 0;
|
ret 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user