From ad473f245c15ef7efdc67821ee515bfedc0436bf Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Mon, 6 Jul 2026 13:00:55 +0800 Subject: [PATCH] =?UTF-8?q?stage1=20=E5=AE=8C=E6=88=9011-13=E6=B5=8B?= =?UTF-8?q?=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stage1/spl_comp.h | 6 + stage1/spl_expr.c | 74 ++++++++++--- stage1/spl_parser.c | 238 +++++++++++++++++++++++++++++++++------- stage1/spl_stmt.c | 9 +- stage1/spl_type.c | 97 +++++++++++++++- stage1/test15_defer.spl | 8 +- 6 files changed, 363 insertions(+), 69 deletions(-) diff --git a/stage1/spl_comp.h b/stage1/spl_comp.h index 85b616b..2f6194c 100644 --- a/stage1/spl_comp.h +++ b/stage1/spl_comp.h @@ -21,6 +21,7 @@ typedef enum { TYPE_ARRAY, TYPE_SLICE, TYPE_STRUCT, + TYPE_UNION, TYPE_ENUM, TYPE_ENUM_VARIANT, /* enum variant with data */ 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_slice(spl_type_info_t *elem); 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); 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); @@ -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_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__ */ diff --git a/stage1/spl_expr.c b/stage1/spl_expr.c index 3111e0b..11ff812 100644 --- a/stage1/spl_expr.c +++ b/stage1/spl_expr.c @@ -10,14 +10,7 @@ * Token helpers * ============================================================ */ -static 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 *t = &vec_at(ctx->toks, ctx->tok_idx); - if (t->type != TOK_EOF) - ctx->tok_idx++; - return t; -} +/* Token helpers — using shared peek/advance from spl_parser.c */ static int match(spl_comp_t *ctx, spl_tok_type_t 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] */ } +/* 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 * ============================================================ */ @@ -470,6 +505,13 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) { 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_expr_result_t r = {0}; 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); fname[fnl] = '\0'; - /* Check for enum variant: Type.Variant */ - if (left.type && left.type->kind == TYPE_ENUM) { - /* It's a type-level enum reference */ - vec_for(left.type->variants, vi) { - if (strcmp(vec_at(left.type->variants, vi).name, fname) == 0) { - spl_emit(ctx, SPL_PUSH, SPL_I32, vec_at(left.type->variants, vi).value); - left = (spl_expr_result_t){spl_type_basic(SPL_I32), 0}; - break; - } + /* Compile-time type member resolution (enum variants, nested types) */ + if (left.type) { + spl_expr_result_t mresult = {0}; + if (spl_resolve_type_member(ctx, left.type, fname, &mresult)) { + left = mresult; + continue; } - continue; } /* Struct field access */ diff --git a/stage1/spl_parser.c b/stage1/spl_parser.c index 47350ca..ff7a767 100644 --- a/stage1/spl_parser.c +++ b/stage1/spl_parser.c @@ -3,9 +3,9 @@ #include "spl_comp.h" #include -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); if (t->type != TOK_EOF) 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 - * type Name = struct/enum { ... }; - * type Name = ExistingType; + * Parse struct/union body (shared for struct and union containers) + * + * 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) { - 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'; +static void parse_struct_body(spl_comp_t *ctx, spl_type_info_t *st) { + if (peek(ctx)->type != TOK_L_BRACE) + return; + advance(ctx); /* { */ - skip_nl(ctx); - expect(ctx, TOK_ASSIGN); - skip_nl(ctx); + /* === Pass 1: Parse all nested type declarations first === + * This allows field declarations to reference types defined later in the body. */ + { + 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) { - advance(ctx); - spl_type_info_t *st = spl_type_struct(tname); - skip_nl(ctx); - if (peek(ctx)->type == TOK_L_BRACE) { - advance(ctx); /* { */ + /* === Pass 2: Parse fields and methods === */ + { + int depth = 1; + while (depth > 0 && ctx->tok_idx < vec_size(ctx->toks)) { 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); skip_nl(ctx); 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); } 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 == 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); + 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); + } } - spl_type_compute_layout(st); - map_put(ctx->type_defs, strdup(tname), st); - } else if (peek(ctx)->type == KW_ENUM) { - advance(ctx); - spl_type_info_t *et = spl_type_enum(tname); - skip_nl(ctx); - if (peek(ctx)->type == TOK_L_BRACE) { - 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); - 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); skip_nl(ctx); 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); } 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); - skip_nl(ctx); } } - if (peek(ctx)->type == TOK_R_BRACE) + else { 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); + skip_nl(ctx); + parse_enum_body(ctx, et); } else if (peek(ctx)->type == TOK_IDENT || (peek(ctx)->type >= KW_AS && peek(ctx)->type <= KW_ANY)) { spl_type_info_t *base = spl_parse_type(ctx); diff --git a/stage1/spl_stmt.c b/stage1/spl_stmt.c index a96f570..0faf193 100644 --- a/stage1/spl_stmt.c +++ b/stage1/spl_stmt.c @@ -4,14 +4,7 @@ #include #include -static 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 *t = &vec_at(ctx->toks, ctx->tok_idx); - if (t->type != TOK_EOF) - ctx->tok_idx++; - return t; -} +/* Token helpers — using shared peek/advance from spl_parser.c */ static int expect(spl_comp_t *ctx, spl_tok_type_t type) { if (peek(ctx)->type == type) { diff --git a/stage1/spl_type.c b/stage1/spl_type.c index 73cd409..5ed0b9d 100644 --- a/stage1/spl_type.c +++ b/stage1/spl_type.c @@ -136,6 +136,16 @@ spl_type_info_t *spl_type_struct(const char *name) { 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 *t = calloc(1, sizeof(spl_type_info_t)); t->kind = TYPE_ENUM; @@ -168,20 +178,34 @@ void spl_type_compute_layout(spl_type_info_t *t) { if (!t || t->resolved) return; - if (t->kind == TYPE_STRUCT) { + if (t->kind == TYPE_STRUCT || t->kind == TYPE_UNION) { usize offset = 0; + usize max_field_size = 0; vec_for(t->fields, i) { spl_field_t *f = &vec_at(t->fields, i); if (f->type) { spl_type_compute_layout(f->type); - f->offset = offset; - offset += f->type->byte_size; + if (t->kind == TYPE_UNION) { + /* 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 */ 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; } else if (t->kind == TYPE_ENUM) { /* Enums with data need special handling */ @@ -287,6 +311,8 @@ const char *spl_type_str(spl_type_info_t *t) { } case TYPE_STRUCT: return t->name ? t->name : "struct"; + case TYPE_UNION: + return t->name ? t->name : "union"; case TYPE_ENUM: return t->name ? t->name : "enum"; case TYPE_NAME: @@ -355,6 +381,67 @@ spl_type_info_t *spl_parse_type(spl_comp_t *ctx) { 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 */ if (tok->type == TOK_IDENT || ((int)tok->type >= (int)KW_AS && (int)tok->type <= (int)KW_ANY)) { const char *name = tok->lexeme; diff --git a/stage1/test15_defer.spl b/stage1/test15_defer.spl index 0e21138..c0c34e9 100644 --- a/stage1/test15_defer.spl +++ b/stage1/test15_defer.spl @@ -28,12 +28,18 @@ fn main() i32 { with_cleanup(); 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 vm_printf("defer last\n"); defer vm_printf("defer middle\n"); defer vm_printf("defer first (should print third)\n"); vm_printf("--- defer test end ---\n"); - ret 0; }