// WRITE BY AI /* spl_ast.c SPL AST 模块:LL(1) 递归下降解析+ valid/dump/drop */ #include "spl_ast.h" #include "spl_dumptree.h" #include #include #include #include /* 从 token 复制 lexeme(带长度,NUL 终止),供 AST 字符串字段持有 */ static char *sdupn(const char *s, usize n) { char *r = malloc(n + 1); if (!r) return NULL; memcpy(r, s, n); r[n] = '\0'; return r; } /* ================================================================ * 内联节点解读上下 * * 内联子节点(attr_item/param_decl/prefix_expr/postfix_expr/primary_expr/ * packed_expr/aggregate_init_item/type_atom/prefix_type)不暴露独立 kind * 创建时用占位 * kind,解读(valid/dump/drop)一律按父字段引用类型递归 * * ================================================================ */ typedef enum { CTX_CONTAINER, /* container_item */ CTX_DECL, /* fn/type/var/const/member 声明*/ CTX_ATTR_ITEM, /* attr_item */ CTX_PARAM, /* param_decl */ CTX_BLOCK_ITEM, /* block_item / 尾表达式 */ CTX_EXPR, /* expr */ CTX_PREFIX, /* prefix_expr */ CTX_POSTFIX, /* postfix_expr */ CTX_PRIMARY, /* primary_expr */ CTX_PACKED, /* packed_expr */ CTX_AGG_ITEM, /* aggregate_init_item */ CTX_TYPE_EXPR, /* type_expr */ CTX_TYPE_ATOM, /* type_atom */ CTX_PREFIX_TYPE, /* prefix_type */ } walk_ctx_t; typedef struct { spl_ast_t *ast; usize pos; int failed; int stop_as; /* 0 时后缀表达式不KW_AS(for 头部序列专用*/ int stop_agg; /* 0 IDENT '{' 不作结构体字面量(if/while/match 头部专用*/ } parser_t; /* 前向声明 */ static spl_tok_t *peek(parser_t *p); static spl_tok_t *advance(parser_t *p); static spl_ast_node_ref_t new_node(parser_t *p, spl_ast_node_kind_t kind, spl_tok_t *loc); static spl_ast_node_t *node_at(spl_ast_t *ast, spl_ast_node_ref_t ref); static spl_ast_node_ref_t parse_expr(parser_t *p); static spl_ast_node_ref_vec_t parse_expr_list(parser_t *p); static spl_ast_node_ref_vec_t parse_block(parser_t *p); static spl_ast_node_ref_t parse_type_expr(parser_t *p); static spl_ast_node_ref_t parse_statement(parser_t *p); static spl_ast_node_ref_t parse_container_declaration(parser_t *p); static spl_ast_node_ref_t parse_param_decl_impl(parser_t *p); static spl_ast_node_ref_t parse_bool_or(parser_t *p); static spl_ast_node_ref_t parse_bool_and(parser_t *p); static spl_ast_node_ref_t parse_bit_or(parser_t *p); static spl_ast_node_ref_t parse_bit_xor(parser_t *p); static spl_ast_node_ref_t parse_bit_and(parser_t *p); static spl_ast_node_ref_t parse_cmp_eq(parser_t *p); static spl_ast_node_ref_t parse_cmp(parser_t *p); static spl_ast_node_ref_t parse_range(parser_t *p); static spl_ast_node_ref_t parse_shift(parser_t *p); static spl_ast_node_ref_t parse_add(parser_t *p); static spl_ast_node_ref_t parse_mul(parser_t *p); static spl_ast_node_ref_t parse_prefix(parser_t *p); static spl_ast_node_ref_t parse_postfix(parser_t *p); static spl_ast_node_ref_t parse_primary(parser_t *p); static spl_ast_node_ref_vec_t parse_aggregate_init_body(parser_t *p); static spl_ast_node_ref_t parse_builtin(parser_t *p); static spl_ast_node_ref_t parse_array_literal(parser_t *p); static spl_ast_node_ref_t parse_if(parser_t *p); static spl_ast_node_ref_t parse_ifvar(parser_t *p); static spl_ast_node_ref_t parse_while(parser_t *p); static spl_ast_node_ref_t parse_loop(parser_t *p); static spl_ast_node_ref_t parse_for(parser_t *p); static spl_ast_node_ref_t parse_match(parser_t *p); static int parse_match_arm(parser_t *p, spl_ast_node_ref_vec_t *paced_vec, spl_ast_node_ref_vec_t *block_vec); static spl_ast_node_ref_t parse_ret(parser_t *p); static spl_ast_node_ref_t parse_break(parser_t *p); static spl_ast_node_ref_t parse_continue(parser_t *p); static spl_ast_node_ref_t parse_defer(parser_t *p); static spl_ast_node_ref_t parse_var_decl(parser_t *p, spl_ast_node_ref_vec_t attr_list); static spl_ast_node_ref_t parse_const_decl(parser_t *p, spl_ast_node_ref_vec_t attr_list); static spl_ast_node_ref_t parse_type_decl(parser_t *p, spl_ast_node_ref_vec_t attr_list); static spl_ast_node_ref_t parse_fn_decl(parser_t *p, spl_ast_node_ref_vec_t attr_list); static spl_ast_node_ref_t parse_member_decl(parser_t *p, spl_ast_node_ref_vec_t attr_list); static spl_ast_node_ref_t parse_type_atom(parser_t *p); static void dump_node(spl_ast_t *ast, spl_ast_node_ref_t ref, walk_ctx_t ctx, const char *prefix, int is_last); static void drop_node(spl_ast_t *ast, spl_ast_node_ref_t ref, walk_ctx_t ctx); static void drop_vec(spl_ast_t *ast, spl_ast_node_ref_vec_t *vec, walk_ctx_t ctx); static void validate_node(spl_ast_t *ast, spl_ast_node_ref_t ref, walk_ctx_t ctx); static void validate_vec(spl_ast_t *ast, spl_ast_node_ref_vec_t *vec, walk_ctx_t ctx); /* ================================================================ * 词法辅助 * ================================================================ */ static int is_trivia(spl_tok_type_t t) { return t == TOK_ENDLINE || t == TOK_LINE_COMMENT; } /* 返回下一个有token(跳trivia),不前*/ static spl_tok_t *peek(parser_t *p) { spl_tok_t *toks = p->ast->input.data; usize n = p->ast->input.size; usize i = p->pos; while (i < n && is_trivia(toks[i].type)) i++; p->pos = i; if (i >= n) return NULL; return &toks[i]; } /* 返回当前有效 token 并前进(EOF 处不前进*/ static spl_tok_t *advance(parser_t *p) { spl_tok_t *t = peek(p); if (t && t->type != TOK_EOF) p->pos++; return t; } /* 当前有效 token 的下一个有token */ static spl_tok_t *peek_next(parser_t *p) { usize i = p->pos; spl_tok_t *toks = p->ast->input.data; usize n = p->ast->input.size; while (i < n && is_trivia(toks[i].type)) i++; i++; while (i < n && is_trivia(toks[i].type)) i++; if (i >= n) return NULL; return &toks[i]; } static void parse_error(parser_t *p, spl_tok_t *t, const char *msg) { (void)p; const char *fn = (t && t->fname) ? t->fname : ""; usize line = t ? t->line : 0; usize col = t ? t->col : 0; LOG_FATAL("%s:%llu:%llu: error: %s", fn, (unsigned long long)line, (unsigned long long)col, msg); } static int expect(parser_t *p, spl_tok_type_t type, const char *what) { spl_tok_t *t = peek(p); if (t && t->type == type) { advance(p); return 1; } parse_error(p, t, what); return 0; } /* ================================================================ * 节点创建 * ================================================================ */ static spl_ast_node_ref_t new_node(parser_t *p, spl_ast_node_kind_t kind, spl_tok_t *loc) { spl_ast_node_t n; memset(&n, 0, sizeof(n)); n.kind = kind; if (loc) { n.loc.fname = loc->fname; n.loc.line = loc->line; n.loc.col = loc->col; } vec_push(p->ast->buckets, n); return p->ast->buckets.size - 1; } static spl_ast_node_t *node_at(spl_ast_t *ast, spl_ast_node_ref_t ref) { return &ast->buckets.data[ref]; } static spl_ast_node_ref_t mk_bin(parser_t *p, spl_tok_t *loc, int op, spl_ast_node_ref_t left, spl_ast_node_ref_t right) { spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR, loc); node_at(p->ast, ref)->expr.op = op; node_at(p->ast, ref)->expr.op_expr.left = left; node_at(p->ast, ref)->expr.op_expr.right = right; return ref; } /* 创建 primary_expr 内联节点(占kind=SPL_AST_EXPR*/ static spl_ast_node_ref_t mk_primary(parser_t *p, spl_tok_t *loc, int pk) { spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR, loc); node_at(p->ast, ref)->primary_expr.kind = pk; return ref; } /* op=PRIMARY EXPR 节点包装内联 primary/prefix/postfix 节点 */ static spl_ast_node_ref_t wrap_expr(parser_t *p, spl_ast_node_ref_t inner) { spl_ast_node_ref_t e = new_node(p, SPL_AST_EXPR, NULL); node_at(p->ast, e)->loc = node_at(p->ast, inner)->loc; node_at(p->ast, e)->expr.op = SPL_AST_PRIMARY_EXPR; node_at(p->ast, e)->expr.op_expr.left = inner; return e; } /* 用指op(PREFIX/POSTFIX/PRIMARY)包装内联节*/ static spl_ast_node_ref_t wrap_op_expr(parser_t *p, spl_ast_node_ref_t inner, int op) { spl_ast_node_ref_t e = new_node(p, SPL_AST_EXPR, NULL); node_at(p->ast, e)->loc = node_at(p->ast, inner)->loc; node_at(p->ast, e)->expr.op = op; node_at(p->ast, e)->expr.op_expr.left = inner; return e; } /* ================================================================ * 字面量解 * ================================================================ */ /* 整数字面量:去下划线后按0 解析x/0o/0b/十进制,忽略 0b 特判*/ static isize parse_int_literal(const spl_tok_t *t) { char buf[128]; usize j = 0; for (usize i = 0; i < t->len && j < sizeof(buf) - 1; i++) { if (t->lexeme[i] != '_') buf[j++] = t->lexeme[i]; } buf[j] = 0; return (isize)strtoll(buf, NULL, 0); } static double parse_float_literal(const spl_tok_t *t) { char buf[128]; usize j = 0; for (usize i = 0; i < t->len && j < sizeof(buf) - 1; i++) { if (t->lexeme[i] != '_') buf[j++] = t->lexeme[i]; } buf[j] = 0; return strtod(buf, NULL); } /* 字符字面量:解码转义 */ static char parse_char_literal(const spl_tok_t *t) { const char *p = t->lexeme + 1; const char *end = t->lexeme + t->len - 1; char c = 0; if (p < end) { spl_decode_escape(&p, &c); } return c; } /* 字符串字面量:解码为 C 字符串副本(去引号、展开转义,malloc 分配) * * 所有权约定:该副本spl_ast_drop STRING_LIT 节点free*/ static char *parse_string_literal(const spl_tok_t *t) { const char *p = t->lexeme + 1; const char *end = t->lexeme + t->len - 1; char *out = (char *)malloc(t->len + 1); if (!out) return NULL; char *o = out; while (p < end) { char c; if (spl_decode_escape(&p, &c) == 0) { *o++ = c; } else { /* 非法转义:宽松保留原字符 */ *o++ = *p; p++; } } *o = 0; return out; } /* ================================================================ * 起始判定 * ================================================================ */ static int can_start_expr(spl_tok_type_t t) { switch (t) { case TOK_INT_LITERAL: case TOK_FLOAT_LITERAL: case TOK_CHAR_LITERAL: case TOK_STRING_LITERAL: case KW_TRUE: case KW_FALSE: case KW_NULL: case TOK_IDENT: case TOK_AT: case TOK_SHARP: case TOK_L_PAREN: case TOK_L_BRACKET: case TOK_L_BRACE: case TOK_SUB: case TOK_NOT: case TOK_BIT_NOT: case TOK_AND: case TOK_MUL: return 1; default: return 0; } } static int can_start_type(spl_tok_type_t t) { switch (t) { case TOK_MUL: case TOK_L_BRACKET: case KW_FN: case KW_VOID: case KW_BOOL: case KW_ANY: case TOK_IDENT: return 1; default: return 0; } } static int can_start_statement(spl_tok_type_t t) { switch (t) { case KW_IF: case KW_WHILE: case KW_LOOP: case KW_FOR: case KW_MATCH: case KW_RET: case KW_BREAK: case KW_CONTINUE: case KW_DEFER: case KW_VAR: case KW_CONST: case KW_TYPE: case KW_COMPTIME: return 1; default: return 0; } } /* ================================================================ * 容器层:声明 * ================================================================ */ /* AttrList -> 追加 attr_item 节点out(空out 不变*/ static void parse_attr_list(parser_t *p, spl_ast_node_ref_vec_t *out) { while (1) { spl_tok_t *t = peek(p); if (!t) return; if (t->type != TOK_AT && t->type != TOK_SHARP) return; advance(p); spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { parse_error(p, name, "expected identifier after attribute"); return; } advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_ATTR_LIST, t); node_at(p->ast, ref)->attr_item.ident = sdupn(name->lexeme, name->len); if (peek(p) && peek(p)->type == TOK_L_PAREN) { advance(p); spl_ast_node_ref_vec_t evec = parse_expr_list(p); node_at(p->ast, ref)->attr_item.expr_list = evec; if (!expect(p, TOK_R_PAREN, "expected ')' to close attribute args")) return; } vec_push(*out, ref); } } /* ParamDeclList -> 追加 param_decl 节点out */ static void parse_param_list(parser_t *p, spl_ast_node_ref_vec_t *out) { while (1) { spl_tok_t *t = peek(p); if (!t) return; if (t->type == TOK_AT || t->type == TOK_SHARP || t->type == TOK_IDENT) { spl_ast_node_ref_t pd = parse_param_decl_impl(p); if (pd) vec_push(*out, pd); if (peek(p) && peek(p)->type == TOK_COMMA) { advance(p); continue; } return; } else if (t->type == TOK_ELLIPSIS) { /* 变长参数:追name=NULL、type_expr=NULL 的空 param_decl */ advance(p); spl_ast_node_ref_t pd = new_node(p, SPL_AST_MEMBER_DECL, t); node_at(p->ast, pd)->param_decl.name = NULL; node_at(p->ast, pd)->param_decl.type_expr = 0; vec_push(*out, pd); if (peek(p) && peek(p)->type == TOK_COMMA) advance(p); return; } else if (t->type == KW_VOID) { /* fn(void):无参写法 */ advance(p); return; } return; } } static spl_ast_node_ref_t parse_param_decl_impl(parser_t *p) { spl_ast_node_ref_vec_t attr_list; vec_init(attr_list); parse_attr_list(p, &attr_list); spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { parse_error(p, name, "expected parameter name"); return 0; } advance(p); if (!expect(p, TOK_COLON, "expected ':' in parameter declaration")) return 0; spl_ast_node_ref_t type_expr = parse_type_expr(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_MEMBER_DECL, name); node_at(p->ast, ref)->param_decl.attr_list = attr_list; node_at(p->ast, ref)->param_decl.name = sdupn(name->lexeme, name->len); node_at(p->ast, ref)->param_decl.type_expr = type_expr; return ref; } static spl_ast_node_ref_t parse_fn_decl(parser_t *p, spl_ast_node_ref_vec_t attr_list) { spl_tok_t *kw = peek(p); advance(p); /* KW_FN */ spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { parse_error(p, name ? name : kw, "expected function name"); return 0; } advance(p); if (!expect(p, TOK_L_PAREN, "expected '(' in function declaration")) return 0; spl_ast_node_ref_vec_t param_list; vec_init(param_list); parse_param_list(p, ¶m_list); if (!expect(p, TOK_R_PAREN, "expected ')' in function declaration")) return 0; spl_ast_node_ref_t type_expr = 0; spl_ast_node_ref_vec_t block; vec_init(block); int has_body = 0; spl_tok_t *t = peek(p); if (t && t->type == TOK_SEMICOLON) { advance(p); } else if (t && t->type == TOK_L_BRACE) { block = parse_block(p); has_body = 1; } else if (t && can_start_type(t->type)) { type_expr = parse_type_expr(p); t = peek(p); if (t && t->type == TOK_SEMICOLON) { advance(p); } else if (t && t->type == TOK_L_BRACE) { block = parse_block(p); has_body = 1; } else { parse_error(p, t, "function declaration must end with ';' or a block"); } } else { parse_error(p, t, "expected return type, ';' or a block"); } /* 定义SPL_AST_FN_DEFINE,外部声明(;)用 SPL_AST_FN_DECL */ spl_ast_node_ref_t ref = new_node(p, has_body ? SPL_AST_FN_DEFINE : SPL_AST_FN_DECL, kw); node_at(p->ast, ref)->fn_decl.attr_list = attr_list; node_at(p->ast, ref)->fn_decl.name = sdupn(name->lexeme, name->len); node_at(p->ast, ref)->fn_decl.param_list = param_list; node_at(p->ast, ref)->fn_decl.type_expr = type_expr; node_at(p->ast, ref)->fn_decl.block = block; return ref; } /* TypeDecl <- KEYWORD_type IDENTIFIER EQUAL TypeExpr */ static spl_ast_node_ref_t parse_type_decl(parser_t *p, spl_ast_node_ref_vec_t attr_list) { (void)attr_list; /* type_decl 自身不承载 attr,attr 归 TypeExpr 管理 */ spl_tok_t *kw = peek(p); advance(p); /* KW_TYPE */ spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { parse_error(p, name ? name : kw, "expected type name"); return 0; } advance(p); if (!expect(p, TOK_ASSIGN, "expected '=' in type declaration")) return 0; spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_DECL, kw); node_at(p->ast, ref)->type_decl.name = sdupn(name->lexeme, name->len); spl_ast_node_ref_t te = parse_type_expr(p); node_at(p->ast, ref)->type_decl.type_expr = te; if (peek(p) && (peek(p)->type == TOK_SEMICOLON || peek(p)->type == TOK_COMMA)) advance(p); return ref; } static spl_ast_node_ref_t parse_member_decl(parser_t *p, spl_ast_node_ref_vec_t attr_list) { spl_tok_t *name = peek(p); advance(p); /* TOK_IDENT */ spl_ast_node_ref_t type_expr = 0; if (peek(p) && peek(p)->type == TOK_COLON) { advance(p); type_expr = parse_type_expr(p); } spl_ast_node_ref_t ref = new_node(p, SPL_AST_MEMBER_DECL, name); node_at(p->ast, ref)->member_decl.attr_list = attr_list; node_at(p->ast, ref)->member_decl.name = sdupn(name->lexeme, name->len); node_at(p->ast, ref)->member_decl.type_expr = type_expr; spl_tok_t *t = peek(p); if (t && (t->type == TOK_COMMA || t->type == TOK_SEMICOLON)) advance(p); return ref; } static spl_ast_node_ref_t parse_var_decl(parser_t *p, spl_ast_node_ref_vec_t attr_list) { spl_tok_t *kw = peek(p); advance(p); /* KW_VAR */ spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { parse_error(p, name ? name : kw, "expected variable name"); return 0; } advance(p); spl_ast_node_ref_t type_expr = 0; spl_ast_node_ref_t expr = 0; spl_tok_t *t = peek(p); if (t && t->type == TOK_COLON) { advance(p); type_expr = parse_type_expr(p); } else if (t && t->type == TOK_COLON_ASSIGN) { advance(p); expr = parse_expr(p); } t = peek(p); if (t && t->type == TOK_ASSIGN) { advance(p); expr = parse_expr(p); } if (peek(p) && peek(p)->type == TOK_SEMICOLON) advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_VAR_DECL, kw); node_at(p->ast, ref)->var_decl.attr_list = attr_list; node_at(p->ast, ref)->var_decl.name = sdupn(name->lexeme, name->len); node_at(p->ast, ref)->var_decl.type_expr = type_expr; node_at(p->ast, ref)->var_decl.expr = expr; return ref; } static spl_ast_node_ref_t parse_const_decl(parser_t *p, spl_ast_node_ref_vec_t attr_list) { spl_tok_t *kw = peek(p); advance(p); /* KW_CONST */ spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { parse_error(p, name ? name : kw, "expected constant name"); return 0; } advance(p); spl_ast_node_ref_t type_expr = 0; spl_ast_node_ref_t expr = 0; spl_tok_t *t = peek(p); if (t && t->type == TOK_COLON) { advance(p); type_expr = parse_type_expr(p); } else if (t && t->type == TOK_COLON_ASSIGN) { advance(p); expr = parse_expr(p); } t = peek(p); if (t && t->type == TOK_ASSIGN) { advance(p); expr = parse_expr(p); } if (peek(p) && peek(p)->type == TOK_SEMICOLON) advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_CONST_DECL, kw); node_at(p->ast, ref)->const_decl.attr_list = attr_list; node_at(p->ast, ref)->const_decl.type_expr = type_expr; node_at(p->ast, ref)->const_decl.name = sdupn(name->lexeme, name->len); node_at(p->ast, ref)->const_decl.expr = expr; return ref; } /* ContainerDeclaration <- AttrList? DeclarationBody */ static spl_ast_node_ref_t parse_container_declaration(parser_t *p) { spl_ast_node_ref_vec_t attr_list; vec_init(attr_list); parse_attr_list(p, &attr_list); spl_tok_t *t = peek(p); if (!t || t->type == TOK_EOF) { parse_error(p, t, "unexpected end of file"); return 0; } if (t->type == TOK_L_BRACE) { /* DirectiveBlock(@init {} / #test {}):不实*/ parse_error(p, t, "not implemented: @/# directive block"); return 0; } switch (t->type) { case KW_FN: return parse_fn_decl(p, attr_list); case KW_TYPE: return parse_type_decl(p, attr_list); case KW_VAR: return parse_var_decl(p, attr_list); case KW_CONST: return parse_const_decl(p, attr_list); case KW_COMPTIME: parse_error(p, t, "not implemented: comptime statement"); return 0; case TOK_IDENT: return parse_member_decl(p, attr_list); default: parse_error(p, t, "unrecognized declaration"); return 0; } } /* ================================================================ * 语句 * ================================================================ */ /* Block <- LBRACE BlockItem* Expr? RBRACE */ static spl_ast_node_ref_vec_t parse_block(parser_t *p) { spl_ast_node_ref_vec_t vec; vec_init(vec); if (!expect(p, TOK_L_BRACE, "expected '{'")) return vec; while (1) { spl_tok_t *t = peek(p); if (!t || t->type == TOK_EOF) { parse_error(p, t, "block missing '}'"); break; } if (t->type == TOK_R_BRACE) { advance(p); break; } if (can_start_statement(t->type)) { spl_ast_node_ref_t s = parse_statement(p); if (s) vec_push(vec, s); } else if (can_start_expr(t->type)) { spl_ast_node_ref_t e = parse_expr(p); spl_tok_t *n = peek(p); if (n && n->type == TOK_SEMICOLON) { advance(p); spl_ast_node_ref_t st = new_node(p, SPL_AST_BLOCK_ITEM, t); node_at(p->ast, st)->block_item.kind = SPL_AST_EXPR_STATEMENT; node_at(p->ast, st)->block_item.expr_statement = e; vec_push(vec, st); } else { /* 尾表达式:EXPR 节点直接block vec */ vec_push(vec, e); } } else { parse_error(p, t, "unrecognized statement"); } } return vec; } static spl_ast_node_ref_t parse_statement(parser_t *p) { spl_tok_t *t = peek(p); if (!t) return 0; switch (t->type) { case KW_IF: { spl_tok_t *n = peek_next(p); if (n && n->type == KW_VAR) return parse_ifvar(p); return parse_if(p); } case KW_WHILE: return parse_while(p); case KW_LOOP: return parse_loop(p); case KW_FOR: return parse_for(p); case KW_MATCH: return parse_match(p); case KW_RET: return parse_ret(p); case KW_BREAK: return parse_break(p); case KW_CONTINUE: return parse_continue(p); case KW_DEFER: return parse_defer(p); case KW_VAR: { spl_ast_node_ref_vec_t al; vec_init(al); spl_ast_node_ref_t v = parse_var_decl(p, al); spl_ast_node_ref_t s = new_node(p, SPL_AST_BLOCK_ITEM, t); node_at(p->ast, s)->block_item.kind = SPL_AST_VARDECL; node_at(p->ast, s)->block_item.var_decl = v; return s; } case KW_CONST: { spl_ast_node_ref_vec_t al; vec_init(al); spl_ast_node_ref_t v = parse_const_decl(p, al); spl_ast_node_ref_t s = new_node(p, SPL_AST_BLOCK_ITEM, t); node_at(p->ast, s)->block_item.kind = SPL_AST_CONSTDECL; node_at(p->ast, s)->block_item.const_decl = v; return s; } case KW_TYPE: { spl_ast_node_ref_vec_t al; vec_init(al); spl_ast_node_ref_t v = parse_type_decl(p, al); spl_ast_node_ref_t s = new_node(p, SPL_AST_BLOCK_ITEM, t); node_at(p->ast, s)->block_item.kind = SPL_AST_TYPEDECL; node_at(p->ast, s)->block_item.type_decl = v; return s; } case KW_COMPTIME: parse_error(p, t, "not implemented: comptime statement"); return 0; default: parse_error(p, t, "unrecognized statement"); return 0; } } static spl_ast_node_ref_t parse_if(parser_t *p) { spl_tok_t *kw = peek(p); advance(p); /* KW_IF */ p->stop_agg++; spl_ast_node_ref_t expr = parse_expr(p); p->stop_agg--; spl_ast_node_ref_vec_t if_block = parse_block(p); spl_ast_node_ref_vec_t else_block; vec_init(else_block); if (peek(p) && peek(p)->type == KW_ELSE) { advance(p); spl_tok_t *t = peek(p); if (t && t->type == KW_IF) { vec_push(else_block, parse_if(p)); } else if (t && t->type == KW_VAR) { vec_push(else_block, parse_ifvar(p)); } else { else_block = parse_block(p); } } spl_ast_node_ref_t s = new_node(p, SPL_AST_BLOCK_ITEM, kw); node_at(p->ast, s)->block_item.kind = SPL_AST_IF_STATEMENT; node_at(p->ast, s)->block_item.if_statement.expr = expr; node_at(p->ast, s)->block_item.if_statement.if_block = if_block; node_at(p->ast, s)->block_item.if_statement.else_block = else_block; return s; } static spl_ast_node_ref_t parse_ifvar(parser_t *p) { spl_tok_t *kw = peek(p); advance(p); /* KW_IF */ advance(p); /* KW_VAR */ if (!expect(p, TOK_DOT, "expected '.' in if var")) return 0; spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { parse_error(p, name, "expected variable name in if var"); return 0; } advance(p); char *bind = NULL; if (peek(p) && peek(p)->type == TOK_L_BRACKET) { advance(p); spl_tok_t *b = peek(p); if (!b || b->type != TOK_IDENT) { parse_error(p, b, "expected identifier in if var binding"); return 0; } advance(p); bind = sdupn(b->lexeme, b->len); if (!expect(p, TOK_R_BRACKET, "expected ']' in if var binding")) return 0; } if (!expect(p, TOK_ASSIGN, "expected '=' in if var")) return 0; p->stop_agg++; spl_ast_node_ref_t expr = parse_expr(p); p->stop_agg--; spl_ast_node_ref_vec_t if_block = parse_block(p); spl_ast_node_ref_vec_t else_block; vec_init(else_block); if (peek(p) && peek(p)->type == KW_ELSE) { advance(p); spl_tok_t *t = peek(p); if (t && t->type == KW_IF) { vec_push(else_block, parse_if(p)); } else if (t && t->type == KW_VAR) { vec_push(else_block, parse_ifvar(p)); } else { else_block = parse_block(p); } } spl_ast_node_ref_t packed = new_node(p, SPL_AST_BLOCK_ITEM, kw); node_at(p->ast, packed)->packed_expr.ident = sdupn(name->lexeme, name->len); node_at(p->ast, packed)->packed_expr.bind_ident = bind; node_at(p->ast, packed)->packed_expr.expr = expr; spl_ast_node_ref_t s = new_node(p, SPL_AST_BLOCK_ITEM, kw); node_at(p->ast, s)->block_item.kind = SPL_AST_IFVAR_STATEMENT; node_at(p->ast, s)->block_item.ifvar_statement.packed_expr = packed; node_at(p->ast, s)->block_item.ifvar_statement.if_block = if_block; node_at(p->ast, s)->block_item.ifvar_statement.else_block = else_block; return s; } static spl_ast_node_ref_t parse_while(parser_t *p) { spl_tok_t *kw = peek(p); advance(p); /* KW_WHILE */ p->stop_agg++; spl_ast_node_ref_t expr = parse_expr(p); p->stop_agg--; spl_ast_node_ref_vec_t block = parse_block(p); spl_ast_node_ref_t s = new_node(p, SPL_AST_BLOCK_ITEM, kw); node_at(p->ast, s)->block_item.kind = SPL_AST_WHILE_STATEMENT; node_at(p->ast, s)->block_item.while_statement.expr = expr; node_at(p->ast, s)->block_item.while_statement.while_block = block; return s; } static spl_ast_node_ref_t parse_loop(parser_t *p) { spl_tok_t *kw = peek(p); advance(p); /* KW_LOOP */ spl_ast_node_ref_vec_t block = parse_block(p); spl_ast_node_ref_t s = new_node(p, SPL_AST_BLOCK_ITEM, kw); node_at(p->ast, s)->block_item.kind = SPL_AST_LOOP_STATEMENT; node_at(p->ast, s)->block_item.loop_statement.loop_block = block; return s; } static spl_ast_node_ref_t parse_for(parser_t *p) { spl_tok_t *kw = peek(p); advance(p); /* KW_FOR */ spl_ast_node_ref_vec_t expr_vec; vec_init(expr_vec); p->stop_as = 1; /* for 头部序列as 属于 for,不属于后缀类型转换 */ vec_push(expr_vec, parse_expr(p)); while (peek(p) && peek(p)->type == TOK_COMMA) { advance(p); vec_push(expr_vec, parse_expr(p)); } p->stop_as = 0; if (!expect(p, KW_AS, "expected 'as' in for")) return 0; spl_ast_node_ref_t s = new_node(p, SPL_AST_BLOCK_ITEM, kw); node_at(p->ast, s)->block_item.kind = SPL_AST_FOR_STATEMENT; node_at(p->ast, s)->block_item.for_statement.expr_vec = expr_vec; spl_tok_t *v = peek(p); if (!v || (v->type != TOK_IDENT && v->type != KW_ANY)) { parse_error(p, v, "expected binding variable in for"); return s; } advance(p); vec_push(node_at(p->ast, s)->block_item.for_statement.ident_vec, sdupn(v->lexeme, v->len)); while (peek(p) && peek(p)->type == TOK_COMMA) { advance(p); spl_tok_t *vi = peek(p); if (!vi || (vi->type != TOK_IDENT && vi->type != KW_ANY)) { parse_error(p, vi, "expected binding variable in for"); return s; } advance(p); vec_push(node_at(p->ast, s)->block_item.for_statement.ident_vec, sdupn(vi->lexeme, vi->len)); } spl_ast_node_ref_vec_t fblock = parse_block(p); node_at(p->ast, s)->block_item.for_statement.block = fblock; return s; } static spl_ast_node_ref_t parse_match(parser_t *p) { spl_tok_t *kw = peek(p); advance(p); /* KW_MATCH */ p->stop_agg++; spl_ast_node_ref_t expr = parse_expr(p); p->stop_agg--; if (!expect(p, TOK_L_BRACE, "expected '{' in match")) { return 0; } spl_ast_node_ref_vec_t paced_vec, stmt_vec; vec_init(paced_vec); vec_init(stmt_vec); while (1) { spl_tok_t *t = peek(p); if (!t || t->type == TOK_EOF) { parse_error(p, t, "match missing '}'"); break; } if (t->type == TOK_R_BRACE) { advance(p); break; } if (!parse_match_arm(p, &paced_vec, &stmt_vec)) break; if (peek(p) && peek(p)->type == TOK_COMMA) advance(p); } spl_ast_node_ref_t s = new_node(p, SPL_AST_BLOCK_ITEM, kw); node_at(p->ast, s)->block_item.kind = SPL_AST_MATCH_STATEMENT; node_at(p->ast, s)->block_item.match_statement.expr = expr; node_at(p->ast, s)->block_item.match_statement.paced_exprs = paced_vec; node_at(p->ast, s)->block_item.match_statement.match_block = stmt_vec; return s; } /* MatchArm <- MatchPat (',' MatchPat)* '=>' Block * 模式合并: 多模式共享同一臂体。每个模式生成一个 packed_expr, * 臂体解析一次,其节点引用按模式个数共享写入 block_vec。 * 这样 paced_vec 与 block_vec 一一对应(每模式一条),语义等价 * 于展开为多个独立臂。 */ static int parse_match_arm(parser_t *p, spl_ast_node_ref_vec_t *paced_vec, spl_ast_node_ref_vec_t *block_vec) { spl_tok_t *t = peek(p); if (!t) return 0; spl_ast_node_ref_vec_t modes; vec_init(modes); while (1) { spl_tok_t *mt = peek(p); if (!mt) { parse_error(p, mt, "invalid match arm pattern"); return 0; } spl_ast_node_ref_t pk = new_node(p, SPL_AST_BLOCK_ITEM, mt); node_at(p->ast, pk)->packed_expr.ident = NULL; node_at(p->ast, pk)->packed_expr.bind_ident = NULL; node_at(p->ast, pk)->packed_expr.expr = 0; if (mt->type == TOK_DOT) { advance(p); spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { parse_error(p, name, "expected variant name in match pattern"); return 0; } advance(p); node_at(p->ast, pk)->packed_expr.ident = sdupn(name->lexeme, name->len); if (peek(p) && peek(p)->type == TOK_L_BRACKET) { advance(p); spl_tok_t *b = peek(p); if (!b || b->type != TOK_IDENT) { parse_error(p, b, "expected identifier in match binding"); return 0; } advance(p); node_at(p->ast, pk)->packed_expr.bind_ident = sdupn(b->lexeme, b->len); if (!expect(p, TOK_R_BRACKET, "expected ']' in match binding")) return 0; } } else if (mt->type == KW_ANY) { /* _ 通配;_ 后跟 '{'(且非聚合抑制)按匿名聚合字面量模式解析 */ spl_tok_t *nx = peek_next(p); if (nx && nx->type == TOK_L_BRACE && !p->stop_agg) { spl_ast_node_ref_t pe = parse_expr(p); node_at(p->ast, pk)->packed_expr.expr = pe; } else { advance(p); /* _ 通配 */ } } else if (can_start_expr(mt->type)) { spl_ast_node_ref_t pe = parse_expr(p); node_at(p->ast, pk)->packed_expr.expr = pe; } else { parse_error(p, mt, "invalid match arm pattern"); return 0; } vec_push(modes, pk); if (peek(p) && peek(p)->type == TOK_COMMA) { advance(p); continue; } break; } if (!expect(p, TOK_FAT_ARROW, "expected '=>' in match arm")) return 0; if (!peek(p) || peek(p)->type != TOK_L_BRACE) { parse_error(p, peek(p), "expected '{' block in match arm body"); return 0; } spl_ast_node_ref_vec_t bvec = parse_block(p); spl_ast_node_ref_t pr = mk_primary(p, t, SPL_AST_BLOCK_EXPR); node_at(p->ast, pr)->primary_expr.block_expr = bvec; spl_ast_node_ref_t body = wrap_expr(p, pr); for (usize i = 0; i < modes.size; i++) { vec_push(*paced_vec, modes.data[i]); vec_push(*block_vec, body); } vec_free(modes); return 1; } static spl_ast_node_ref_t parse_ret(parser_t *p) { spl_tok_t *kw = peek(p); advance(p); /* KW_RET */ spl_ast_node_ref_t expr = 0; if (peek(p) && can_start_expr(peek(p)->type)) expr = parse_expr(p); if (peek(p) && peek(p)->type == TOK_SEMICOLON) advance(p); spl_ast_node_ref_t s = new_node(p, SPL_AST_BLOCK_ITEM, kw); node_at(p->ast, s)->block_item.kind = SPL_AST_RET_STATEMENT; node_at(p->ast, s)->block_item.ret_statement.expr = expr; return s; } static spl_ast_node_ref_t parse_break(parser_t *p) { spl_tok_t *kw = peek(p); advance(p); /* KW_BREAK */ if (peek(p) && peek(p)->type == TOK_SEMICOLON) advance(p); spl_ast_node_ref_t s = new_node(p, SPL_AST_BLOCK_ITEM, kw); node_at(p->ast, s)->block_item.kind = SPL_AST_BREAK_STATEMENT; return s; } static spl_ast_node_ref_t parse_continue(parser_t *p) { spl_tok_t *kw = peek(p); advance(p); /* KW_CONTINUE */ if (peek(p) && peek(p)->type == TOK_SEMICOLON) advance(p); spl_ast_node_ref_t s = new_node(p, SPL_AST_BLOCK_ITEM, kw); node_at(p->ast, s)->block_item.kind = SPL_AST_CONTINUE_STATEMENT; return s; } static spl_ast_node_ref_t parse_defer(parser_t *p) { spl_tok_t *kw = peek(p); advance(p); /* KW_DEFER */ spl_ast_node_ref_vec_t vec; vec_init(vec); if (peek(p) && peek(p)->type == TOK_L_BRACE) { vec = parse_block(p); } else if (peek(p) && can_start_statement(peek(p)->type)) { spl_ast_node_ref_t st = parse_statement(p); if (st) vec_push(vec, st); } else { /* ExprStatement: defer ; */ spl_tok_t *t = peek(p); spl_ast_node_ref_t e = parse_expr(p); if (peek(p) && peek(p)->type == TOK_SEMICOLON) advance(p); spl_ast_node_ref_t st = new_node(p, SPL_AST_BLOCK_ITEM, t); node_at(p->ast, st)->block_item.kind = SPL_AST_EXPR_STATEMENT; node_at(p->ast, st)->block_item.expr_statement = e; vec_push(vec, st); } spl_ast_node_ref_t s = new_node(p, SPL_AST_BLOCK_ITEM, kw); node_at(p->ast, s)->block_item.kind = SPL_AST_DEFER_STATEMENT; node_at(p->ast, s)->block_item.defer_statement.block_or_statement = vec; return s; } /* ================================================================ * 表达式(优先级爬升) * ================================================================ */ static int assign_op_of(spl_tok_type_t t) { switch (t) { case TOK_ASSIGN: return SPL_AST_ASSIGN_EXPR; case TOK_ASSIGN_ADD: return SPL_AST_ASSIGN_ADD_EXPR; case TOK_ASSIGN_SUB: return SPL_AST_ASSIGN_sUB_EXPR; case TOK_ASSIGN_MUL: return SPL_AST_ASSIGN_MUL_EXPR; case TOK_ASSIGN_DIV: return SPL_AST_ASSIGN_DIV_EXPR; case TOK_ASSIGN_MOD: return SPL_AST_ASSIGN_MOD_EXPR; case TOK_ASSIGN_AND: return SPL_AST_ASSIGN_AND_EXPR; case TOK_ASSIGN_OR: return SPL_AST_ASSIGN_OR_EXPR; case TOK_ASSIGN_XOR: return SPL_AST_ASSIGN_XOR_EXPR; case TOK_ASSIGN_L_SH: return SPL_AST_ASSIGN_LSHIFT_EXPR; case TOK_ASSIGN_R_SH: return SPL_AST_ASSIGN_USHIFT_EXPR; default: return -1; } } static spl_ast_node_ref_t parse_assign(parser_t *p) { spl_ast_node_ref_t left = parse_bool_or(p); if (p->failed) return left; spl_tok_t *t = peek(p); int op = t ? assign_op_of(t->type) : -1; if (op < 0) return left; advance(p); spl_ast_node_ref_t right = parse_assign(p); return mk_bin(p, t, op, left, right); } static spl_ast_node_ref_t parse_bool_or(parser_t *p) { spl_ast_node_ref_t left = parse_bool_and(p); while (!p->failed) { spl_tok_t *t = peek(p); if (!t || t->type != TOK_OR_OR) break; advance(p); spl_ast_node_ref_t right = parse_bool_and(p); left = mk_bin(p, t, SPL_AST_BOOLOR_EXPR, left, right); } return left; } static spl_ast_node_ref_t parse_bool_and(parser_t *p) { spl_ast_node_ref_t left = parse_bit_or(p); while (!p->failed) { spl_tok_t *t = peek(p); if (!t || t->type != TOK_AND_AND) break; advance(p); spl_ast_node_ref_t right = parse_bit_or(p); left = mk_bin(p, t, SPL_AST_BOOLAND_EXPR, left, right); } return left; } static spl_ast_node_ref_t parse_bit_or(parser_t *p) { spl_ast_node_ref_t left = parse_bit_xor(p); while (!p->failed) { spl_tok_t *t = peek(p); if (!t || t->type != TOK_OR) break; advance(p); spl_ast_node_ref_t right = parse_bit_xor(p); left = mk_bin(p, t, SPL_AST_BITOR_EXPR, left, right); } return left; } static spl_ast_node_ref_t parse_bit_xor(parser_t *p) { spl_ast_node_ref_t left = parse_bit_and(p); while (!p->failed) { spl_tok_t *t = peek(p); if (!t || t->type != TOK_XOR) break; advance(p); spl_ast_node_ref_t right = parse_bit_and(p); left = mk_bin(p, t, SPL_AST_BITXOR_EXPR, left, right); } return left; } static spl_ast_node_ref_t parse_bit_and(parser_t *p) { spl_ast_node_ref_t left = parse_cmp_eq(p); while (!p->failed) { spl_tok_t *t = peek(p); if (!t || t->type != TOK_AND) break; advance(p); spl_ast_node_ref_t right = parse_cmp_eq(p); left = mk_bin(p, t, SPL_AST_BITAND_EXPR, left, right); } return left; } static spl_ast_node_ref_t parse_cmp_eq(parser_t *p) { spl_ast_node_ref_t left = parse_cmp(p); while (!p->failed) { spl_tok_t *t = peek(p); int op = -1; if (t) { if (t->type == TOK_EQ) op = SPL_AST_CMPEQ_EXPR; else if (t->type == TOK_NEQ) op = SPL_AST_CMPNE_EXPR; } if (op < 0) break; advance(p); spl_ast_node_ref_t right = parse_cmp(p); left = mk_bin(p, t, op, left, right); } return left; } static spl_ast_node_ref_t parse_cmp(parser_t *p) { spl_ast_node_ref_t left = parse_range(p); while (!p->failed) { spl_tok_t *t = peek(p); int op = -1; if (t) { if (t->type == TOK_LT) op = SPL_AST_CMP_LT_EXPR; else if (t->type == TOK_GT) op = SPL_AST_CMP_GT_EXPR; else if (t->type == TOK_LE) op = SPL_AST_CMP_LE_EXPR; else if (t->type == TOK_GE) op = SPL_AST_CMP_GE_EXPR; } if (op < 0) break; advance(p); spl_ast_node_ref_t right = parse_range(p); left = mk_bin(p, t, op, left, right); } return left; } static spl_ast_node_ref_t parse_range(parser_t *p) { spl_ast_node_ref_t left = parse_shift(p); if (p->failed) return left; spl_tok_t *t = peek(p); if (t && t->type == TOK_RANGE) { advance(p); spl_ast_node_ref_t right = 0; /* a.. 无右端点 */ if (peek(p) && can_start_expr(peek(p)->type)) right = parse_shift(p); left = mk_bin(p, t, SPL_AST_RANGE_EXPR, left, right); } return left; } static spl_ast_node_ref_t parse_shift(parser_t *p) { spl_ast_node_ref_t left = parse_add(p); while (!p->failed) { spl_tok_t *t = peek(p); int op = -1; if (t) { if (t->type == TOK_L_SH) op = SPL_AST_LSHIFT_EXPR; else if (t->type == TOK_R_SH) op = SPL_AST_RSHIFT_EXPR; } if (op < 0) break; advance(p); spl_ast_node_ref_t right = parse_add(p); left = mk_bin(p, t, op, left, right); } return left; } static spl_ast_node_ref_t parse_add(parser_t *p) { spl_ast_node_ref_t left = parse_mul(p); while (!p->failed) { spl_tok_t *t = peek(p); int op = -1; if (t) { if (t->type == TOK_ADD) op = SPL_AST_ADD_EXPR; else if (t->type == TOK_SUB) op = SPL_AST_SUB_EXPR; } if (op < 0) break; advance(p); spl_ast_node_ref_t right = parse_mul(p); left = mk_bin(p, t, op, left, right); } return left; } static spl_ast_node_ref_t parse_mul(parser_t *p) { spl_ast_node_ref_t left = parse_prefix(p); while (!p->failed) { spl_tok_t *t = peek(p); int op = -1; if (t) { if (t->type == TOK_MUL) op = SPL_AST_MUL_EXPR; else if (t->type == TOK_DIV) op = SPL_AST_DIV_EXPR; else if (t->type == TOK_MOD) op = SPL_AST_MOD_EXPR; } if (op < 0) break; advance(p); spl_ast_node_ref_t right = parse_prefix(p); left = mk_bin(p, t, op, left, right); } return left; } /* PrefixExpr <- PrefixOp* PostfixExpr */ static spl_ast_node_ref_t parse_prefix(parser_t *p) { int ops[16]; spl_tok_t *op_toks[16]; int n = 0; while (n < 16 && !p->failed) { spl_tok_t *t = peek(p); int op = -1; if (t) { switch (t->type) { case TOK_SUB: op = SPL_AST_MINUS_EXPR; break; case TOK_NOT: op = SPL_AST_BANG_EXPR; break; case TOK_BIT_NOT: op = SPL_AST_TILDE_EXPR; break; case TOK_AND: op = SPL_AST_AMPERSAND_EXPR; break; case TOK_MUL: op = SPL_AST_ASTERISK_EXPR; break; default: break; } } if (op < 0) break; ops[n] = op; op_toks[n] = t; n++; advance(p); } spl_ast_node_ref_t inner = parse_postfix(p); /* 从内到外包装(最内层 op 在列表末尾) */ for (int i = n - 1; i >= 0; i--) { spl_ast_node_ref_t pf = new_node(p, SPL_AST_EXPR, op_toks[i]); node_at(p->ast, pf)->prefix_expr.kind = ops[i]; node_at(p->ast, pf)->prefix_expr.postfix_expr = inner; inner = wrap_op_expr(p, pf, SPL_AST_PREFIX_EXPR); } return inner; } /* PostfixExpr <- PrimaryExpr (call/field/deref/index/slice/as)* */ static spl_ast_node_ref_t parse_postfix(parser_t *p) { spl_ast_node_ref_t expr = parse_primary(p); while (!p->failed) { spl_tok_t *t = peek(p); if (!t) break; if (t->type == TOK_L_PAREN) { advance(p); spl_ast_node_ref_t pf = new_node(p, SPL_AST_EXPR, t); node_at(p->ast, pf)->postfix_expr.kind = SPL_AST_CALL_EXPR; node_at(p->ast, pf)->postfix_expr.primary_expr = expr; spl_ast_node_ref_vec_t cvec = parse_expr_list(p); node_at(p->ast, pf)->postfix_expr.call_expr = cvec; if (!expect(p, TOK_R_PAREN, "expected ')' in call")) return expr; expr = wrap_op_expr(p, pf, SPL_AST_POSTFIX_EXPR); } else if (t->type == TOK_DOT) { advance(p); spl_tok_t *n = peek(p); if (n && n->type == TOK_MUL) { advance(p); spl_ast_node_ref_t pf = new_node(p, SPL_AST_EXPR, t); node_at(p->ast, pf)->postfix_expr.kind = SPL_AST_DEREF_EXPR; node_at(p->ast, pf)->postfix_expr.primary_expr = expr; expr = wrap_op_expr(p, pf, SPL_AST_POSTFIX_EXPR); } else if (n && n->type == TOK_IDENT) { advance(p); spl_ast_node_ref_t pf = new_node(p, SPL_AST_EXPR, t); node_at(p->ast, pf)->postfix_expr.kind = SPL_AST_FIELD_EXPR; node_at(p->ast, pf)->postfix_expr.primary_expr = expr; node_at(p->ast, pf)->postfix_expr.field_expr = sdupn(n->lexeme, n->len); expr = wrap_op_expr(p, pf, SPL_AST_POSTFIX_EXPR); } else { parse_error(p, n, "expected identifier or '*' after '.'"); break; } } else if (t->type == TOK_L_BRACKET) { advance(p); /* 切片 begin 用 parse_shift 解析:`a..b` 中 `..` 属切片标记而非 Range 表达式 */ spl_ast_node_ref_t begin = parse_shift(p); if (peek(p) && peek(p)->type == TOK_RANGE) { advance(p); spl_ast_node_ref_t end = 0; if (peek(p) && peek(p)->type != TOK_R_BRACKET) end = parse_expr(p); if (!expect(p, TOK_R_BRACKET, "expected ']' in slice")) return expr; spl_ast_node_ref_t pf = new_node(p, SPL_AST_EXPR, t); node_at(p->ast, pf)->postfix_expr.kind = SPL_AST_SLICE_EXPR; node_at(p->ast, pf)->postfix_expr.primary_expr = expr; node_at(p->ast, pf)->postfix_expr.slice_expr.begin = begin; node_at(p->ast, pf)->postfix_expr.slice_expr.end = end; expr = wrap_op_expr(p, pf, SPL_AST_POSTFIX_EXPR); } else { if (!expect(p, TOK_R_BRACKET, "expected ']' in index")) return expr; spl_ast_node_ref_t pf = new_node(p, SPL_AST_EXPR, t); node_at(p->ast, pf)->postfix_expr.kind = SPL_AST_INDEX_EXPR; node_at(p->ast, pf)->postfix_expr.primary_expr = expr; node_at(p->ast, pf)->postfix_expr.index_expr = begin; expr = wrap_op_expr(p, pf, SPL_AST_POSTFIX_EXPR); } } else if (t->type == KW_AS && !p->stop_as) { advance(p); spl_ast_node_ref_t te = parse_type_expr(p); spl_ast_node_ref_t pf = new_node(p, SPL_AST_EXPR, t); node_at(p->ast, pf)->postfix_expr.kind = SPL_AST_AS_EXPR; node_at(p->ast, pf)->postfix_expr.primary_expr = expr; node_at(p->ast, pf)->postfix_expr.type_expr = te; expr = wrap_op_expr(p, pf, SPL_AST_POSTFIX_EXPR); } else { break; } } return expr; } /* ExprList <- (Expr COMMA)* Expr? */ static spl_ast_node_ref_vec_t parse_expr_list(parser_t *p) { spl_ast_node_ref_vec_t vec; vec_init(vec); if (p->failed) return vec; spl_tok_t *t = peek(p); if (!t || !can_start_expr(t->type)) return vec; vec_push(vec, parse_expr(p)); while (!p->failed && peek(p) && peek(p)->type == TOK_COMMA) { advance(p); if (!peek(p) || !can_start_expr(peek(p)->type)) break; /* 尾逗号宽容 */ vec_push(vec, parse_expr(p)); } return vec; } /* AggregateInitBody <- LBRACE StructInitList? RBRACE * StructInit <- DOT (IDENTIFIER / UNDERSCORE) (EQUAL Expr)? * UNDERSCORE 作为字段名表示匿名(positional)初始化,ident 存 "_"。 * 返回 aggregate_init_item vec。 */ static spl_ast_node_ref_vec_t parse_aggregate_init_body(parser_t *p) { spl_ast_node_ref_vec_t agg_vec; vec_init(agg_vec); if (!expect(p, TOK_L_BRACE, "expected '{' in struct init")) return agg_vec; while (1) { spl_tok_t *s = peek(p); if (!s || s->type == TOK_R_BRACE || s->type == TOK_EOF) break; if (!expect(p, TOK_DOT, "expected '.' in struct init")) return agg_vec; spl_tok_t *f = peek(p); if (!f || f->type != TOK_IDENT) { parse_error(p, f, "expected field name in struct init"); return agg_vec; } advance(p); spl_ast_node_ref_t item = new_node(p, SPL_AST_VAR_DECL, f); node_at(p->ast, item)->aggregate_init_item.ident = sdupn(f->lexeme, f->len); if (peek(p) && peek(p)->type == TOK_ASSIGN) { advance(p); spl_ast_node_ref_t ae = parse_expr(p); node_at(p->ast, item)->aggregate_init_item.expr = ae; } vec_push(agg_vec, item); if (peek(p) && peek(p)->type == TOK_COMMA) { advance(p); continue; } break; } if (!expect(p, TOK_R_BRACE, "expected '}' in struct literal")) return agg_vec; return agg_vec; } static spl_ast_node_ref_t parse_primary(parser_t *p) { spl_tok_t *t = peek(p); if (!t) { parse_error(p, t, "unexpected expression start"); return 0; } switch (t->type) { case TOK_INT_LITERAL: { advance(p); spl_ast_node_ref_t pr = mk_primary(p, t, SPL_AST_INTEGER); node_at(p->ast, pr)->primary_expr.integer_expr = parse_int_literal(t); return wrap_expr(p, pr); } case TOK_FLOAT_LITERAL: { advance(p); spl_ast_node_ref_t pr = mk_primary(p, t, SPL_AST_FLOAT); node_at(p->ast, pr)->primary_expr.float_expr = parse_float_literal(t); return wrap_expr(p, pr); } case TOK_CHAR_LITERAL: { advance(p); spl_ast_node_ref_t pr = mk_primary(p, t, SPL_AST_CHAR_LIT); node_at(p->ast, pr)->primary_expr.char_lit_expr = parse_char_literal(t); return wrap_expr(p, pr); } case TOK_STRING_LITERAL: { advance(p); spl_ast_node_ref_t pr = mk_primary(p, t, SPL_AST_STRING_LIT); node_at(p->ast, pr)->primary_expr.string_lit_expr = parse_string_literal(t); return wrap_expr(p, pr); } case KW_TRUE: { advance(p); return wrap_expr(p, mk_primary(p, t, SPL_AST_TRUE)); } case KW_FALSE: { advance(p); return wrap_expr(p, mk_primary(p, t, SPL_AST_FALSE)); } case KW_NULL: { advance(p); return wrap_expr(p, mk_primary(p, t, SPL_AST_NULL)); } case TOK_IDENT: { advance(p); if (peek(p) && peek(p)->type == TOK_L_BRACE && !p->stop_agg) { /* 结构体字面量 T { .f1 = e1, ... } */ spl_ast_node_ref_vec_t agg_vec = parse_aggregate_init_body(p); spl_ast_node_ref_t pr = mk_primary(p, t, SPL_AST_ARGGREGATE_INIT); node_at(p->ast, pr)->primary_expr.aggregate_init.name = sdupn(t->lexeme, t->len); node_at(p->ast, pr)->primary_expr.aggregate_init.expr = agg_vec; return wrap_expr(p, pr); } spl_ast_node_ref_t pr = mk_primary(p, t, SPL_AST_IDENT); node_at(p->ast, pr)->primary_expr.ident = sdupn(t->lexeme, t->len); return wrap_expr(p, pr); } case TOK_DOT: { /* 匿名聚合字面量 .{ .f = e };primary 位置裸 '.' 非法 */ spl_tok_t *nx = peek_next(p); if (nx && nx->type == TOK_L_BRACE && !p->stop_agg) { advance(p); spl_ast_node_ref_vec_t agg_vec = parse_aggregate_init_body(p); spl_ast_node_ref_t pr = mk_primary(p, t, SPL_AST_ARGGREGATE_INIT); node_at(p->ast, pr)->primary_expr.aggregate_init.name = NULL; node_at(p->ast, pr)->primary_expr.aggregate_init.expr = agg_vec; return wrap_expr(p, pr); } parse_error(p, t, "unexpected '.' in expression"); return 0; } case KW_ANY: parse_error(p, t, "unexpected '_' in expression"); return 0; case TOK_AT: case TOK_SHARP: return parse_builtin(p); case TOK_L_PAREN: { advance(p); spl_ast_node_ref_t e = parse_expr(p); if (!expect(p, TOK_R_PAREN, "expected ')' in parenthesized expression")) return e; spl_ast_node_ref_t pr = mk_primary(p, t, SPL_AST_EXPR_EXPR); node_at(p->ast, pr)->primary_expr.expr = e; return wrap_expr(p, pr); } case TOK_L_BRACKET: return parse_array_literal(p); case TOK_L_BRACE: { spl_ast_node_ref_vec_t bvec = parse_block(p); spl_ast_node_ref_t pr = mk_primary(p, t, SPL_AST_BLOCK_EXPR); node_at(p->ast, pr)->primary_expr.block_expr = bvec; return wrap_expr(p, pr); } default: parse_error(p, t, "unrecognized expression"); return 0; } } /* BuiltinExpr <- (AT / SHARP) IDENTIFIER (LPAREN ExprList? RPAREN) */ static spl_ast_node_ref_t parse_builtin(parser_t *p) { spl_tok_t *t = peek(p); advance(p); /* AT / SHARP */ spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { parse_error(p, name, "expected builtin name"); return 0; } advance(p); if (!expect(p, TOK_L_PAREN, "expected '(' in builtin call")) return 0; spl_ast_node_ref_vec_t args = parse_expr_list(p); if (!expect(p, TOK_R_PAREN, "expected ')' in builtin call")) return 0; spl_ast_node_ref_t pr = mk_primary(p, t, SPL_AST_BUILTIN_EXPR); node_at(p->ast, pr)->primary_expr.builtin_expr.ident = sdupn(name->lexeme, name->len); node_at(p->ast, pr)->primary_expr.builtin_expr.expr_list = args; return wrap_expr(p, pr); } /* ArrayLiteral <- LBRACKET INTEGER RBRACKET TypeExpr LBRACE ExprList? RBRACE */ static spl_ast_node_ref_t parse_array_literal(parser_t *p) { spl_tok_t *t = peek(p); advance(p); /* L_BRACKET */ isize integer = 0; if (peek(p) && peek(p)->type == TOK_INT_LITERAL) { integer = parse_int_literal(peek(p)); advance(p); } if (!expect(p, TOK_R_BRACKET, "expected ']' in array literal")) return 0; spl_ast_node_ref_t te = parse_type_expr(p); if (!expect(p, TOK_L_BRACE, "expected '{' in array literal")) return 0; spl_ast_node_ref_vec_t items = parse_expr_list(p); if (!expect(p, TOK_R_BRACE, "expected '}' in array literal")) return 0; spl_ast_node_ref_t pr = mk_primary(p, t, SPL_AST_ARRAY_LIT); node_at(p->ast, pr)->primary_expr.array_lit_expr.integer = integer; node_at(p->ast, pr)->primary_expr.array_lit_expr.type_expr = te; node_at(p->ast, pr)->primary_expr.array_lit_expr.expr_list = items; return wrap_expr(p, pr); } static spl_ast_node_ref_t parse_expr(parser_t *p) { return parse_assign(p); } /* ================================================================ * 类型表达 * ================================================================ */ /* TypeExpr <- PrefixTypeOp* TypeBase */ static spl_ast_node_ref_t parse_type_expr(parser_t *p) { spl_tok_t *t = peek(p); spl_ast_node_ref_vec_t type_prefixs; vec_init(type_prefixs); while (1) { spl_tok_t *s = peek(p); if (!s) break; if (s->type == TOK_MUL) { advance(p); spl_ast_node_ref_t pf = new_node(p, SPL_AST_TYPE_EXPR, s); node_at(p->ast, pf)->prefix_type.pointer = 1; node_at(p->ast, pf)->prefix_type.array_size = 0; vec_push(type_prefixs, pf); } else if (s->type == TOK_L_BRACKET) { advance(p); int sz = 0; if (peek(p) && peek(p)->type == TOK_INT_LITERAL) { sz = (int)parse_int_literal(peek(p)); advance(p); } if (!expect(p, TOK_R_BRACKET, "expected ']' in array type")) return 0; spl_ast_node_ref_t pf = new_node(p, SPL_AST_TYPE_EXPR, s); node_at(p->ast, pf)->prefix_type.pointer = 2; node_at(p->ast, pf)->prefix_type.array_size = sz; vec_push(type_prefixs, pf); } else { break; } } spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_EXPR, t); node_at(p->ast, ref)->type_expr.type_prefixs = type_prefixs; node_at(p->ast, ref)->type_expr.spl_base_type = NULL; spl_ast_node_ref_vec_t attr_list; vec_init(attr_list); parse_attr_list(p, &attr_list); node_at(p->ast, ref)->type_expr.attr_list = attr_list; spl_tok_t *bt = peek(p); if (bt && bt->type == KW_FN) { node_at(p->ast, ref)->type_expr.kind = SPL_AST_BASE_TYPE_FN; advance(p); /* KW_FN */ if (!expect(p, TOK_L_PAREN, "expected '(' in function type")) return ref; spl_ast_node_ref_vec_t param_list; vec_init(param_list); while (!p->failed && peek(p) && peek(p)->type != TOK_R_PAREN) { spl_ast_node_ref_t pt = parse_type_expr(p); spl_ast_node_ref_t pd = new_node(p, SPL_AST_MEMBER_DECL, t); node_at(p->ast, pd)->param_decl.name = NULL; node_at(p->ast, pd)->param_decl.type_expr = pt; vec_push(param_list, pd); if (peek(p) && peek(p)->type == TOK_COMMA) { advance(p); continue; } break; } if (!expect(p, TOK_R_PAREN, "expected ')' in function type")) return ref; spl_ast_node_ref_t ret = parse_type_expr(p); node_at(p->ast, ref)->type_expr.fn_type.param_list = param_list; node_at(p->ast, ref)->type_expr.fn_type.type_expr = ret; } else if (bt && (bt->type == KW_STRUCT || bt->type == KW_UNION || bt->type == KW_ENUM)) { /* 内联聚合类型: struct { ... } / union { ... } / enum { ... } */ node_at(p->ast, ref)->type_expr.kind = (bt->type == KW_STRUCT) ? SPL_AST_TYPE_STRUCT : (bt->type == KW_UNION) ? SPL_AST_TYPE_UNION : SPL_AST_TYPE_ENUM; advance(p); if (!expect(p, TOK_L_BRACE, "expected '{' in aggregate type")) return ref; spl_ast_node_ref_vec_t members; vec_init(members); while (1) { spl_tok_t *m = peek(p); if (!m || m->type == TOK_R_BRACE || m->type == TOK_EOF) break; spl_ast_node_ref_t md = parse_container_declaration(p); if (md) vec_push(members, md); } if (!expect(p, TOK_R_BRACE, "expected '}' in aggregate type")) return ref; node_at(p->ast, ref)->type_expr.aggregate_list = members; } else { node_at(p->ast, ref)->type_expr.kind = SPL_AST_BASE_TYPE_PATH; spl_ast_node_ref_vec_t type_path; vec_init(type_path); while (1) { spl_ast_node_ref_t atom = parse_type_atom(p); if (!atom) break; vec_push(type_path, atom); if (peek(p) && peek(p)->type == TOK_DOT) { advance(p); continue; } break; } node_at(p->ast, ref)->type_expr.type_path = type_path; if (type_path.size > 0) { spl_ast_node_t *last = node_at(p->ast, type_path.data[type_path.size - 1]); node_at(p->ast, ref)->type_expr.spl_base_type = last->type_atom.ident; } } return ref; } /* TypeAtom <- 内置类型关键/ 内置TOK_IDENT) / _ / 自定义标识符 */ static spl_ast_node_ref_t parse_type_atom(parser_t *p) { spl_tok_t *t = peek(p); if (!t) return 0; spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_EXPR, t); int kind = -1; switch (t->type) { case KW_VOID: kind = SPL_AST_TYPE_VOID; break; case KW_BOOL: kind = SPL_AST_TYPE_BOOL; break; case KW_ANY: kind = SPL_AST_TYPE_ANY; break; case TOK_IDENT: { const char *s = t->lexeme; usize slen = t->len; #define IS_TY(NAME) (slen == (usize)(sizeof(NAME) - 1) && memcmp(s, NAME, sizeof(NAME) - 1) == 0) if (IS_TY("i8")) kind = SPL_AST_TYPE_I8; else if (IS_TY("u8")) kind = SPL_AST_TYPE_U8; else if (IS_TY("i16")) kind = SPL_AST_TYPE_I16; else if (IS_TY("u16")) kind = SPL_AST_TYPE_U16; else if (IS_TY("i32")) kind = SPL_AST_TYPE_I32; else if (IS_TY("u32")) kind = SPL_AST_TYPE_U32; else if (IS_TY("i64")) kind = SPL_AST_TYPE_I64; else if (IS_TY("u64")) kind = SPL_AST_TYPE_U64; else if (IS_TY("isize")) kind = SPL_AST_TYPE_ISIZE; else if (IS_TY("usize")) kind = SPL_AST_TYPE_USIZE; else if (IS_TY("ptr")) kind = SPL_AST_TYPE_PTR; else if (IS_TY("f32") || IS_TY("f64")) { parse_error(p, t, "not implemented: f32/f64 type"); kind = SPL_AST_TYPE_IDENT; } else { kind = SPL_AST_TYPE_IDENT; } #undef IS_TY break; } default: parse_error(p, t, "unrecognized type"); return 0; } node_at(p->ast, ref)->type_atom.kind = kind; node_at(p->ast, ref)->type_atom.ident = sdupn(t->lexeme, t->len); advance(p); return ref; } /* ================================================================ * 公共 API * ================================================================ */ void spl_ast_init(spl_ast_t *ast, const spl_tok_vec_t *tok_vec) { memset(ast, 0, sizeof(*ast)); ast->input = *tok_vec; /* move:共token 数据 */ vec_init(ast->buckets); ast->root = 0; ast->parsed = 0; /* 哨兵节点:ref 0 表示空引用,永不被真正使*/ spl_ast_node_t n; memset(&n, 0, sizeof(n)); vec_push(ast->buckets, n); } void spl_ast_prase(spl_ast_t *ast) { if (!ast || !ast->input.data || ast->buckets.size == 0) return; parser_t p; p.ast = ast; p.pos = 0; p.failed = 0; ast->parsed = 0; spl_ast_node_ref_vec_t members; vec_init(members); while (1) { spl_tok_t *t = peek(&p); if (!t || t->type == TOK_EOF) break; spl_ast_node_ref_t d = parse_container_declaration(&p); if (d) vec_push(members, d); } spl_ast_node_ref_t root = new_node(&p, SPL_AST_CONTAINER_ITEM, NULL); node_at(ast, root)->container_item.members = members; ast->root = root; ast->parsed = p.failed ? -1 : 1; } void spl_ast_drop(spl_ast_t *ast) { if (!ast) return; if (ast->root) drop_node(ast, ast->root, CTX_CONTAINER); vec_free(ast->buckets); vec_free(ast->input); ast->parsed = 0; ast->root = 0; } static walk_ctx_t ctx_from_kind(spl_ast_node_kind_t k) { switch (k) { case SPL_AST_CONTAINER_ITEM: return CTX_CONTAINER; case SPL_AST_FN_DECL: case SPL_AST_FN_DEFINE: case SPL_AST_TYPE_DECL: case SPL_AST_VAR_DECL: case SPL_AST_CONST_DECL: case SPL_AST_MEMBER_DECL: return CTX_DECL; case SPL_AST_BLOCK_ITEM: return CTX_BLOCK_ITEM; case SPL_AST_EXPR: return CTX_EXPR; case SPL_AST_TYPE_EXPR: return CTX_TYPE_EXPR; case SPL_AST_ATTR_LIST: return CTX_ATTR_ITEM; default: return CTX_CONTAINER; } } void spl_ast_valid(spl_ast_t *ast) { if (!ast) return; if (ast->parsed != 1) { printf("valid: AST not parsed successfully (parsed=%d)\n", ast->parsed); return; } validate_node(ast, ast->root, CTX_CONTAINER); } void spl_ast_dump(spl_ast_t *ast, spl_ast_node_ref_t node) { if (!ast || !node || node >= ast->buckets.size) return; dump_node(ast, node, ctx_from_kind(ast->buckets.data[node].kind), "", 1); } /* ================================================================ * dump * ================================================================ */ #define STR(s) ((s) ? (s) : "") static const char *expr_op_name(int op) { switch (op) { case SPL_AST_ASSIGN_EXPR: return "="; case SPL_AST_ASSIGN_ADD_EXPR: return "+="; case SPL_AST_ASSIGN_sUB_EXPR: return "-="; case SPL_AST_ASSIGN_MUL_EXPR: return "*="; case SPL_AST_ASSIGN_DIV_EXPR: return "/="; case SPL_AST_ASSIGN_MOD_EXPR: return "%="; case SPL_AST_ASSIGN_AND_EXPR: return "&="; case SPL_AST_ASSIGN_OR_EXPR: return "|="; case SPL_AST_ASSIGN_XOR_EXPR: return "^="; case SPL_AST_ASSIGN_LSHIFT_EXPR: return "<<="; case SPL_AST_ASSIGN_USHIFT_EXPR: return ">>="; case SPL_AST_BOOLOR_EXPR: return "||"; case SPL_AST_BOOLAND_EXPR: return "&&"; case SPL_AST_BITOR_EXPR: return "|"; case SPL_AST_BITXOR_EXPR: return "^"; case SPL_AST_BITAND_EXPR: return "&"; case SPL_AST_CMPEQ_EXPR: return "=="; case SPL_AST_CMPNE_EXPR: return "!="; case SPL_AST_CMP_LE_EXPR: return "<="; case SPL_AST_CMP_GE_EXPR: return ">="; case SPL_AST_CMP_LT_EXPR: return "<"; case SPL_AST_CMP_GT_EXPR: return ">"; case SPL_AST_RANGE_EXPR: return ".."; case SPL_AST_LSHIFT_EXPR: return "<<"; case SPL_AST_RSHIFT_EXPR: return ">>"; case SPL_AST_ADD_EXPR: return "+"; case SPL_AST_SUB_EXPR: return "-"; case SPL_AST_MUL_EXPR: return "*"; case SPL_AST_DIV_EXPR: return "/"; case SPL_AST_MOD_EXPR: return "%"; case SPL_AST_PREFIX_EXPR: return "prefix"; case SPL_AST_POSTFIX_EXPR: return "postfix"; case SPL_AST_PRIMARY_EXPR: return "primary"; default: return "?"; } } static const char *type_atom_name(int k) { switch (k) { case SPL_AST_TYPE_VOID: return "void"; case SPL_AST_TYPE_BOOL: return "bool"; case SPL_AST_TYPE_I8: return "i8"; case SPL_AST_TYPE_U8: return "u8"; case SPL_AST_TYPE_I16: return "i16"; case SPL_AST_TYPE_U16: return "u16"; case SPL_AST_TYPE_I32: return "i32"; case SPL_AST_TYPE_U32: return "u32"; case SPL_AST_TYPE_I64: return "i64"; case SPL_AST_TYPE_U64: return "u64"; case SPL_AST_TYPE_ISIZE: return "isize"; case SPL_AST_TYPE_USIZE: return "usize"; case SPL_AST_TYPE__F32: return "f32"; case SPL_AST_TYPE__F64: return "f64"; case SPL_AST_TYPE_PTR: return "ptr"; case SPL_AST_TYPE_ANY: return "_"; case SPL_AST_TYPE_IDENT: return "ident"; default: return "?"; } } static const spl_dumptree_style_t *dt = &spl_dumptree_ascii_style; /* 打印一行节点标签:缩进骨架 + 分支符 + label */ static void node_label(const char *prefix, int is_last, const char *fmt, ...) { va_list ap; printf("%s%s ", prefix, is_last ? dt->last_branch : dt->branch); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf("\n"); } /* 以每个子节点为一行递归打印 vec(父级骨架由 prefix/is_last 决定) */ static void dump_vec_children(spl_ast_t *ast, spl_ast_node_ref_vec_t *vec, walk_ctx_t ctx, const char *prefix, int is_last) { char cp[512]; spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); for (usize i = 0; i < vec->size; i++) dump_node(ast, vec->data[i], ctx, cp, (int)(i == vec->size - 1)); } static void dump_node(spl_ast_t *ast, spl_ast_node_ref_t ref, walk_ctx_t ctx, const char *prefix, int is_last); static void dump_vec_children(spl_ast_t *ast, spl_ast_node_ref_vec_t *vec, walk_ctx_t ctx, const char *prefix, int is_last); static void dump_expr(spl_ast_t *ast, spl_ast_node_ref_t ref, const char *prefix, int is_last); static void dump_type_expr(spl_ast_t *ast, spl_ast_node_ref_t ref, const char *prefix, int is_last); static void dump_block(spl_ast_t *ast, spl_ast_node_ref_vec_t *block, const char *prefix, int is_last); static void expr_inline(spl_ast_t *ast, spl_ast_node_ref_t ref, char *out, size_t cap); static void type_inline(spl_ast_t *ast, spl_ast_node_ref_t ref, char *out, size_t cap); /* ---- 内联文本渲染(供树标签使用) ---- */ static void expr_list_inline(spl_ast_t *ast, spl_ast_node_ref_vec_t *vec, char *out, size_t cap); static void agg_items_inline(spl_ast_t *ast, spl_ast_node_ref_vec_t *items, char *out, size_t cap); /* 字符串字面量转义:写入 "..." */ static void escape_string(char *out, size_t cap, const char *s) { size_t w = strlen(out); out[w++] = '"'; for (; *s && w < cap - 2; s++) { unsigned char c = (unsigned char)*s; switch (c) { case '\n': out[w++] = '\\'; out[w++] = 'n'; break; case '\t': out[w++] = '\\'; out[w++] = 't'; break; case '\r': out[w++] = '\\'; out[w++] = 'r'; break; case '"': out[w++] = '\\'; out[w++] = '"'; break; case '\\': out[w++] = '\\'; out[w++] = '\\'; break; default: if (c < 0x20 || c == 0x7f) { if (w + 4 >= cap) break; out[w++] = '\\'; out[w++] = 'x'; out[w++] = "0123456789abcdef"[c >> 4]; out[w++] = "0123456789abcdef"[c & 15]; } else if (w + 1 < cap) { out[w++] = (char)c; } break; } } out[w++] = '"'; out[w] = '\0'; } /* 表达式完整文本(含 primary/prefix/postfix 包装折叠) */ static void expr_inline(spl_ast_t *ast, spl_ast_node_ref_t ref, char *out, size_t cap) { if (!ref || ref >= ast->buckets.size) { strncat(out, "?", cap - strlen(out) - 1); return; } spl_ast_node_t *n = &ast->buckets.data[ref]; char tmp[512]; int op = n->expr.op; switch (op) { case SPL_AST_PRIMARY_EXPR: { spl_ast_node_t *pn = &ast->buckets.data[n->expr.op_expr.left]; switch (pn->primary_expr.kind) { case SPL_AST_INTEGER: snprintf(tmp, sizeof tmp, "%lld", (long long)pn->primary_expr.integer_expr); break; case SPL_AST_FLOAT: snprintf(tmp, sizeof tmp, "%g", pn->primary_expr.float_expr); break; case SPL_AST_CHAR_LIT: snprintf(tmp, sizeof tmp, "'%c'", (int)pn->primary_expr.char_lit_expr); break; case SPL_AST_STRING_LIT: tmp[0] = '\0'; escape_string(tmp, sizeof tmp, STR(pn->primary_expr.string_lit_expr)); break; case SPL_AST_TRUE: snprintf(tmp, sizeof tmp, "true"); break; case SPL_AST_FALSE: snprintf(tmp, sizeof tmp, "false"); break; case SPL_AST_NULL: snprintf(tmp, sizeof tmp, "null"); break; case SPL_AST_IDENT: snprintf(tmp, sizeof tmp, "%s", STR(pn->primary_expr.ident)); break; case SPL_AST_ARGGREGATE_INIT: snprintf(tmp, sizeof tmp, "%s{ ", STR(pn->primary_expr.aggregate_init.name)); agg_items_inline(ast, &pn->primary_expr.aggregate_init.expr, tmp, sizeof tmp); strncat(tmp, " }", sizeof tmp - strlen(tmp) - 1); break; case SPL_AST_EXPR_EXPR: tmp[0] = '('; tmp[1] = '\0'; expr_inline(ast, pn->primary_expr.expr, tmp, sizeof tmp); strncat(tmp, ")", sizeof tmp - strlen(tmp) - 1); break; case SPL_AST_ARRAY_LIT: snprintf(tmp, sizeof tmp, "[%lld]", (long long)pn->primary_expr.array_lit_expr.integer); if (pn->primary_expr.array_lit_expr.type_expr) type_inline(ast, pn->primary_expr.array_lit_expr.type_expr, tmp, sizeof tmp); strncat(tmp, "{ ", sizeof tmp - strlen(tmp) - 1); expr_list_inline(ast, &pn->primary_expr.array_lit_expr.expr_list, tmp, sizeof tmp); strncat(tmp, " }", sizeof tmp - strlen(tmp) - 1); break; case SPL_AST_BUILTIN_EXPR: snprintf(tmp, sizeof tmp, "@%s(", STR(pn->primary_expr.builtin_expr.ident)); expr_list_inline(ast, &pn->primary_expr.builtin_expr.expr_list, tmp, sizeof tmp); strncat(tmp, ")", sizeof tmp - strlen(tmp) - 1); break; case SPL_AST_BLOCK_EXPR: snprintf(tmp, sizeof tmp, "{...}"); break; default: snprintf(tmp, sizeof tmp, "?"); break; } strncat(out, tmp, cap - strlen(out) - 1); break; } case SPL_AST_PREFIX_EXPR: { spl_ast_node_t *pn = &ast->buckets.data[n->expr.op_expr.left]; const char *pn_txt = "?"; switch (pn->prefix_expr.kind) { case SPL_AST_MINUS_EXPR: pn_txt = "-"; break; case SPL_AST_BANG_EXPR: pn_txt = "!"; break; case SPL_AST_TILDE_EXPR: pn_txt = "~"; break; case SPL_AST_AMPERSAND_EXPR: pn_txt = "&"; break; case SPL_AST_ASTERISK_EXPR: pn_txt = "*"; break; } strncat(out, pn_txt, cap - strlen(out) - 1); expr_inline(ast, pn->prefix_expr.postfix_expr, out, cap); break; } case SPL_AST_POSTFIX_EXPR: { spl_ast_node_t *pn = &ast->buckets.data[n->expr.op_expr.left]; expr_inline(ast, pn->postfix_expr.primary_expr, out, cap); switch (pn->postfix_expr.kind) { case SPL_AST_CALL_EXPR: strncat(out, "(", cap - strlen(out) - 1); expr_list_inline(ast, &pn->postfix_expr.call_expr, out, cap); strncat(out, ")", cap - strlen(out) - 1); break; case SPL_AST_FIELD_EXPR: { char t[256]; snprintf(t, sizeof t, ".%s", STR(pn->postfix_expr.field_expr)); strncat(out, t, cap - strlen(out) - 1); break; } case SPL_AST_DEREF_EXPR: strncat(out, ".*", cap - strlen(out) - 1); break; case SPL_AST_INDEX_EXPR: strncat(out, "[", cap - strlen(out) - 1); expr_inline(ast, pn->postfix_expr.index_expr, out, cap); strncat(out, "]", cap - strlen(out) - 1); break; case SPL_AST_SLICE_EXPR: strncat(out, "[", cap - strlen(out) - 1); if (pn->postfix_expr.slice_expr.begin) expr_inline(ast, pn->postfix_expr.slice_expr.begin, out, cap); strncat(out, "..", cap - strlen(out) - 1); if (pn->postfix_expr.slice_expr.end) expr_inline(ast, pn->postfix_expr.slice_expr.end, out, cap); strncat(out, "]", cap - strlen(out) - 1); break; case SPL_AST_AS_EXPR: strncat(out, " as ", cap - strlen(out) - 1); if (pn->postfix_expr.type_expr) type_inline(ast, pn->postfix_expr.type_expr, out, cap); break; default: break; } break; } default: expr_inline(ast, n->expr.op_expr.left, out, cap); { char t[64]; snprintf(t, sizeof t, " %s ", expr_op_name(op)); strncat(out, t, cap - strlen(out) - 1); } if (n->expr.op_expr.right) expr_inline(ast, n->expr.op_expr.right, out, cap); break; } } /* 逗号分隔的表达式文本 */ static void expr_list_inline(spl_ast_t *ast, spl_ast_node_ref_vec_t *vec, char *out, size_t cap) { for (usize i = 0; i < vec->size; i++) { if (i) strncat(out, ", ", cap - strlen(out) - 1); expr_inline(ast, vec->data[i], out, cap); } } /* 属性文本:@name(args) */ static void attrs_inline(spl_ast_t *ast, spl_ast_node_ref_vec_t *attrs, char *out, size_t cap) { for (usize i = 0; i < attrs->size; i++) { spl_ast_node_t *a = &ast->buckets.data[attrs->data[i]]; char t[256]; snprintf(t, sizeof t, "@%s(", STR(a->attr_item.ident)); strncat(out, t, cap - strlen(out) - 1); expr_list_inline(ast, &a->attr_item.expr_list, out, cap); strncat(out, ") ", cap - strlen(out) - 1); } } /* 参数文本:a: T, b: U */ static void params_inline(spl_ast_t *ast, spl_ast_node_ref_vec_t *params, char *out, size_t cap) { for (usize i = 0; i < params->size; i++) { spl_ast_node_t *p = &ast->buckets.data[params->data[i]]; if (i) strncat(out, ", ", cap - strlen(out) - 1); if (!p->param_decl.name) { strncat(out, "...", cap - strlen(out) - 1); continue; } attrs_inline(ast, &p->param_decl.attr_list, out, cap); char t[256]; snprintf(t, sizeof t, "%s: ", STR(p->param_decl.name)); strncat(out, t, cap - strlen(out) - 1); if (p->param_decl.type_expr) type_inline(ast, p->param_decl.type_expr, out, cap); else strncat(out, "?", cap - strlen(out) - 1); } } /* 聚合初始化项文本:.f = expr */ static void agg_items_inline(spl_ast_t *ast, spl_ast_node_ref_vec_t *items, char *out, size_t cap) { for (usize i = 0; i < items->size; i++) { spl_ast_node_t *it = &ast->buckets.data[items->data[i]]; if (i) strncat(out, ", ", cap - strlen(out) - 1); char t[128]; snprintf(t, sizeof t, ".%s", STR(it->aggregate_init_item.ident)); strncat(out, t, cap - strlen(out) - 1); if (it->aggregate_init_item.expr) { strncat(out, " = ", cap - strlen(out) - 1); expr_inline(ast, it->aggregate_init_item.expr, out, cap); } } } /* 完整类型文本(含前缀指针/数组):*u8 / []u8 / [4]i32 / fn(a: i32) void */ static void type_inline(spl_ast_t *ast, spl_ast_node_ref_t ref, char *out, size_t cap) { if (!ref || ref >= ast->buckets.size) { strncat(out, "?", cap - strlen(out) - 1); return; } spl_ast_node_t *n = &ast->buckets.data[ref]; for (usize i = 0; i < n->type_expr.type_prefixs.size; i++) { spl_ast_node_t *pt = &ast->buckets.data[n->type_expr.type_prefixs.data[i]]; char t[32]; if (pt->prefix_type.pointer == 1) snprintf(t, sizeof t, "*"); else if (pt->prefix_type.array_size != 0) snprintf(t, sizeof t, "[%d]", pt->prefix_type.array_size); else snprintf(t, sizeof t, "[]"); strncat(out, t, cap - strlen(out) - 1); } if (n->type_expr.attr_list.size) attrs_inline(ast, &n->type_expr.attr_list, out, cap); char t[256]; switch (n->type_expr.kind) { case SPL_AST_BASE_TYPE_FN: snprintf(t, sizeof t, "fn("); strncat(out, t, cap - strlen(out) - 1); params_inline(ast, &n->type_expr.fn_type.param_list, out, cap); strncat(out, ") ", cap - strlen(out) - 1); type_inline(ast, n->type_expr.fn_type.type_expr, out, cap); break; case SPL_AST_TYPE_STRUCT: case SPL_AST_TYPE_UNION: case SPL_AST_TYPE_ENUM: { const char *kw = n->type_expr.kind == SPL_AST_TYPE_STRUCT ? "struct" : n->type_expr.kind == SPL_AST_TYPE_UNION ? "union" : "enum"; snprintf(t, sizeof t, "%s{ ", kw); strncat(out, t, cap - strlen(out) - 1); for (usize i = 0; i < n->type_expr.aggregate_list.size; i++) { spl_ast_node_t *m = &ast->buckets.data[n->type_expr.aggregate_list.data[i]]; if (m->kind == SPL_AST_MEMBER_DECL) { snprintf(t, sizeof t, "%s: ", STR(m->member_decl.name)); strncat(out, t, cap - strlen(out) - 1); if (m->member_decl.type_expr) type_inline(ast, m->member_decl.type_expr, out, cap); else strncat(out, "?", cap - strlen(out) - 1); } else if (m->kind == SPL_AST_FN_DECL || m->kind == SPL_AST_FN_DEFINE) { snprintf(t, sizeof t, "fn %s(", STR(m->fn_decl.name)); strncat(out, t, cap - strlen(out) - 1); params_inline(ast, &m->fn_decl.param_list, out, cap); strncat(out, ") ", cap - strlen(out) - 1); if (m->fn_decl.type_expr) type_inline(ast, m->fn_decl.type_expr, out, cap); } else { strncat(out, "...", cap - strlen(out) - 1); } strncat(out, ", ", cap - strlen(out) - 1); } strncat(out, "}", cap - strlen(out) - 1); break; } default: { for (usize i = 0; i < n->type_expr.type_path.size; i++) { spl_ast_node_t *at = &ast->buckets.data[n->type_expr.type_path.data[i]]; if (i) strncat(out, ".", cap - strlen(out) - 1); if (at->type_atom.kind == SPL_AST_TYPE_IDENT) strncat(out, STR(at->type_atom.ident), cap - strlen(out) - 1); else strncat(out, type_atom_name(at->type_atom.kind), cap - strlen(out) - 1); } if (!n->type_expr.type_path.size) strncat(out, "?", cap - strlen(out) - 1); break; } } } /* 聚合初始化项文本已由 agg_items_inline 提供 */ /* ---- 树版表达式渲染 ---- */ /* 解包 BLOCK_EXPR 包装,返回 block_item 列表(match 臂体) */ static spl_ast_node_ref_vec_t *unwrap_block_expr(spl_ast_t *ast, spl_ast_node_ref_t ref) { spl_ast_node_t *n = &ast->buckets.data[ref]; spl_ast_node_t *p = &ast->buckets.data[n->expr.op_expr.left]; return &p->primary_expr.block_expr; } /* 单行 packed_expr 模式文本(非表达式模式) */ static void pattern_inline(spl_ast_t *ast, spl_ast_node_ref_t ref, char *out, size_t cap) { out[0] = '\0'; if (!ref || ref >= ast->buckets.size) return; spl_ast_node_t *n = &ast->buckets.data[ref]; if (n->packed_expr.expr) { expr_inline(ast, n->packed_expr.expr, out, cap); } else if (n->packed_expr.ident) { char t[128]; if (n->packed_expr.bind_ident) snprintf(t, sizeof t, ".%s[%s]", STR(n->packed_expr.ident), STR(n->packed_expr.bind_ident)); else snprintf(t, sizeof t, ".%s", STR(n->packed_expr.ident)); strncat(out, t, cap - strlen(out) - 1); } else { strncat(out, "_", cap - strlen(out) - 1); } } /* packed_expr 作为一行节点 */ static void dump_packed(spl_ast_t *ast, spl_ast_node_ref_t ref, const char *prefix, int is_last) { spl_ast_node_t *n = &ast->buckets.data[ref]; if (n->packed_expr.expr) { dump_expr(ast, n->packed_expr.expr, prefix, is_last); return; } char t[128]; pattern_inline(ast, ref, t, sizeof t); node_label(prefix, is_last, "%s", t); } /* match 臂:模式 + 体(BLOCK_EXPR) */ static void dump_arm(spl_ast_t *ast, spl_ast_node_ref_t pat, spl_ast_node_ref_t body, const char *prefix, int is_last) { spl_ast_node_t *n = &ast->buckets.data[pat]; char cp[512]; if (n->packed_expr.expr) { node_label(prefix, is_last, "Arm"); spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); dump_expr(ast, n->packed_expr.expr, cp, 0); dump_block(ast, unwrap_block_expr(ast, body), cp, 1); return; } char t[128]; pattern_inline(ast, pat, t, sizeof t); node_label(prefix, is_last, "Arm %s", t); spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); dump_block(ast, unwrap_block_expr(ast, body), cp, 1); } /* primary_expr 树版:label + 子节点 */ static void dump_primary_expr(spl_ast_t *ast, spl_ast_node_ref_t ref, const char *prefix, int is_last) { spl_ast_node_t *n = &ast->buckets.data[ref]; char cp[512]; switch (n->primary_expr.kind) { case SPL_AST_INTEGER: node_label(prefix, is_last, "Integer %lld", (long long)n->primary_expr.integer_expr); break; case SPL_AST_FLOAT: node_label(prefix, is_last, "Float %g", n->primary_expr.float_expr); break; case SPL_AST_CHAR_LIT: node_label(prefix, is_last, "Char '%c'", (int)n->primary_expr.char_lit_expr); break; case SPL_AST_STRING_LIT: { char t[512]; t[0] = '\0'; escape_string(t, sizeof t, STR(n->primary_expr.string_lit_expr)); node_label(prefix, is_last, "String %s", t); break; } case SPL_AST_TRUE: node_label(prefix, is_last, "Bool true"); break; case SPL_AST_FALSE: node_label(prefix, is_last, "Bool false"); break; case SPL_AST_NULL: node_label(prefix, is_last, "Null"); break; case SPL_AST_IDENT: node_label(prefix, is_last, "Ident %s", STR(n->primary_expr.ident)); break; case SPL_AST_ARGGREGATE_INIT: node_label(prefix, is_last, "AggInit %s", STR(n->primary_expr.aggregate_init.name)); spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); for (usize i = 0; i < n->primary_expr.aggregate_init.expr.size; i++) { spl_ast_node_t *it = &ast->buckets.data[n->primary_expr.aggregate_init.expr.data[i]]; int it_last = (int)(i == n->primary_expr.aggregate_init.expr.size - 1); node_label(cp, it_last, "Field .%s", STR(it->aggregate_init_item.ident)); if (it->aggregate_init_item.expr) { char cq[512]; spl_dumptree_child_prefix(dt, cp, it_last, cq, sizeof cq); dump_expr(ast, it->aggregate_init_item.expr, cq, 1); } } break; case SPL_AST_EXPR_EXPR: dump_expr(ast, n->primary_expr.expr, prefix, is_last); break; case SPL_AST_ARRAY_LIT: node_label(prefix, is_last, "Array [%lld]", (long long)n->primary_expr.array_lit_expr.integer); spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); if (n->primary_expr.array_lit_expr.type_expr) dump_type_expr(ast, n->primary_expr.array_lit_expr.type_expr, cp, (int)(n->primary_expr.array_lit_expr.expr_list.size == 0)); for (usize i = 0; i < n->primary_expr.array_lit_expr.expr_list.size; i++) dump_expr(ast, n->primary_expr.array_lit_expr.expr_list.data[i], cp, (int)(i == n->primary_expr.array_lit_expr.expr_list.size - 1)); break; case SPL_AST_BUILTIN_EXPR: node_label(prefix, is_last, "Builtin @%s", STR(n->primary_expr.builtin_expr.ident)); spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); for (usize i = 0; i < n->primary_expr.builtin_expr.expr_list.size; i++) dump_expr(ast, n->primary_expr.builtin_expr.expr_list.data[i], cp, (int)(i == n->primary_expr.builtin_expr.expr_list.size - 1)); break; case SPL_AST_BLOCK_EXPR: node_label(prefix, is_last, "BlockExpr"); dump_vec_children(ast, &n->primary_expr.block_expr, CTX_BLOCK_ITEM, prefix, is_last); break; default: node_label(prefix, is_last, "?"); break; } } /* postfix_expr 树版:label + 子节点 */ static void dump_postfix_expr(spl_ast_t *ast, spl_ast_node_ref_t ref, const char *prefix, int is_last) { spl_ast_node_t *n = &ast->buckets.data[ref]; spl_ast_node_ref_t tgt = n->postfix_expr.primary_expr; char cp[512]; spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); switch (n->postfix_expr.kind) { case SPL_AST_CALL_EXPR: { usize nkids = 1 + n->postfix_expr.call_expr.size; node_label(prefix, is_last, "Call"); dump_expr(ast, tgt, cp, (int)(nkids == 1)); for (usize i = 0; i < n->postfix_expr.call_expr.size; i++) dump_expr(ast, n->postfix_expr.call_expr.data[i], cp, (int)(i == n->postfix_expr.call_expr.size - 1)); break; } case SPL_AST_FIELD_EXPR: node_label(prefix, is_last, "Field .%s", STR(n->postfix_expr.field_expr)); dump_expr(ast, tgt, cp, 1); break; case SPL_AST_DEREF_EXPR: node_label(prefix, is_last, "Deref"); dump_expr(ast, tgt, cp, 1); break; case SPL_AST_INDEX_EXPR: node_label(prefix, is_last, "Index"); dump_expr(ast, tgt, cp, 0); dump_expr(ast, n->postfix_expr.index_expr, cp, 1); break; case SPL_AST_SLICE_EXPR: node_label(prefix, is_last, "Slice"); dump_expr(ast, tgt, cp, 0); if (n->postfix_expr.slice_expr.begin) dump_expr(ast, n->postfix_expr.slice_expr.begin, cp, 0); if (n->postfix_expr.slice_expr.end) dump_expr(ast, n->postfix_expr.slice_expr.end, cp, 1); break; case SPL_AST_AS_EXPR: { char t[256]; t[0] = '\0'; if (n->postfix_expr.type_expr) type_inline(ast, n->postfix_expr.type_expr, t, sizeof t); node_label(prefix, is_last, "As %s", t); dump_expr(ast, tgt, cp, 1); break; } default: node_label(prefix, is_last, "?"); break; } } /* primary_expr 树版见 dump_primary_expr */ /* 表达式树版:EXPR 包装层折叠,直接显示具体节点类型 */ static void dump_expr(spl_ast_t *ast, spl_ast_node_ref_t ref, const char *prefix, int is_last) { if (!ref || ref >= ast->buckets.size) { node_label(prefix, is_last, "?"); return; } spl_ast_node_t *n = &ast->buckets.data[ref]; char cp[512]; int op = n->expr.op; switch (op) { case SPL_AST_PRIMARY_EXPR: dump_primary_expr(ast, n->expr.op_expr.left, prefix, is_last); break; case SPL_AST_PREFIX_EXPR: { spl_ast_node_t *pn = &ast->buckets.data[n->expr.op_expr.left]; const char *nm = "?"; switch (pn->prefix_expr.kind) { case SPL_AST_MINUS_EXPR: nm = "Neg"; break; case SPL_AST_BANG_EXPR: nm = "Not"; break; case SPL_AST_TILDE_EXPR: nm = "BitNot"; break; case SPL_AST_AMPERSAND_EXPR: nm = "Addr"; break; case SPL_AST_ASTERISK_EXPR: nm = "Star"; break; } node_label(prefix, is_last, "%s", nm); spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); dump_expr(ast, pn->prefix_expr.postfix_expr, cp, 1); break; } case SPL_AST_POSTFIX_EXPR: dump_postfix_expr(ast, n->expr.op_expr.left, prefix, is_last); break; default: node_label(prefix, is_last, "%s", expr_op_name(op)); spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); dump_expr(ast, n->expr.op_expr.left, cp, 0); if (n->expr.op_expr.right) dump_expr(ast, n->expr.op_expr.right, cp, 1); break; } } /* 代码块树版 */ static void dump_block(spl_ast_t *ast, spl_ast_node_ref_vec_t *block, const char *prefix, int is_last) { node_label(prefix, is_last, "Block"); dump_vec_children(ast, block, CTX_BLOCK_ITEM, prefix, is_last); } /* 模式文本见 pattern_inline;vec 递归见 dump_vec_children */ /* 类型节点树版:聚合(struct/union/enum)展开为子树,其余内联为 Type 标签 */ static void dump_type_expr(spl_ast_t *ast, spl_ast_node_ref_t ref, const char *prefix, int is_last) { if (!ref || ref >= ast->buckets.size) { node_label(prefix, is_last, "?"); return; } spl_ast_node_t *n = &ast->buckets.data[ref]; int agg = n->type_expr.kind == SPL_AST_TYPE_STRUCT || n->type_expr.kind == SPL_AST_TYPE_UNION || n->type_expr.kind == SPL_AST_TYPE_ENUM; if (!agg && n->type_expr.kind == SPL_AST_BASE_TYPE_PATH) { char t[512]; t[0] = '\0'; type_inline(ast, ref, t, sizeof t); node_label(prefix, is_last, "Type %s", t); return; } const char *nm = n->type_expr.kind == SPL_AST_TYPE_STRUCT ? "Struct" : n->type_expr.kind == SPL_AST_TYPE_UNION ? "Union" : n->type_expr.kind == SPL_AST_TYPE_ENUM ? "Enum" : "FnType"; node_label(prefix, is_last, "%s", nm); char cp[512]; spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); if (agg) { for (usize i = 0; i < n->type_expr.aggregate_list.size; i++) dump_node(ast, n->type_expr.aggregate_list.data[i], CTX_DECL, cp, (int)(i == n->type_expr.aggregate_list.size - 1)); } else { usize np = n->type_expr.fn_type.param_list.size; int has_ret = n->type_expr.fn_type.type_expr != 0; for (usize i = 0; i < np; i++) dump_node(ast, n->type_expr.fn_type.param_list.data[i], CTX_PARAM, cp, (int)(i == np - 1 && !has_ret)); if (has_ret) dump_type_expr(ast, n->type_expr.fn_type.type_expr, cp, 1); } } static void dump_node(spl_ast_t *ast, spl_ast_node_ref_t ref, walk_ctx_t ctx, const char *prefix, int is_last) { if (!ref || ref >= ast->buckets.size) return; spl_ast_node_t *n = &ast->buckets.data[ref]; char cp[512]; switch (ctx) { case CTX_CONTAINER: printf("Program\n"); dump_vec_children(ast, &n->container_item.members, CTX_DECL, "", 1); break; case CTX_DECL: switch (n->kind) { case SPL_AST_FN_DECL: case SPL_AST_FN_DEFINE: { int is_define = (n->kind == SPL_AST_FN_DEFINE); node_label(prefix, is_last, "%s %s", is_define ? "FnDefine" : "FnDecl", STR(n->fn_decl.name)); usize total = n->fn_decl.attr_list.size + n->fn_decl.param_list.size + (n->fn_decl.type_expr ? 1 : 0) + (is_define && n->fn_decl.block.size ? 1 : 0); if (total) { spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); usize k = 0; for (usize i = 0; i < n->fn_decl.attr_list.size; i++) dump_node(ast, n->fn_decl.attr_list.data[i], CTX_ATTR_ITEM, cp, (int)(++k == total)); for (usize i = 0; i < n->fn_decl.param_list.size; i++) dump_node(ast, n->fn_decl.param_list.data[i], CTX_PARAM, cp, (int)(++k == total)); if (n->fn_decl.type_expr) dump_type_expr(ast, n->fn_decl.type_expr, cp, (int)(++k == total)); if (is_define && n->fn_decl.block.size) dump_block(ast, &n->fn_decl.block, cp, (int)(++k == total)); } break; } case SPL_AST_TYPE_DECL: node_label(prefix, is_last, "TypeDecl %s", STR(n->type_decl.name)); if (n->type_decl.type_expr) { spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); dump_type_expr(ast, n->type_decl.type_expr, cp, 1); } break; case SPL_AST_VAR_DECL: { node_label(prefix, is_last, "VarDecl %s", STR(n->var_decl.name)); usize total = n->var_decl.attr_list.size + (n->var_decl.type_expr ? 1 : 0) + (n->var_decl.expr ? 1 : 0); if (total) { spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); usize k = 0; for (usize i = 0; i < n->var_decl.attr_list.size; i++) dump_node(ast, n->var_decl.attr_list.data[i], CTX_ATTR_ITEM, cp, (int)(++k == total)); if (n->var_decl.type_expr) dump_type_expr(ast, n->var_decl.type_expr, cp, (int)(++k == total)); if (n->var_decl.expr) dump_expr(ast, n->var_decl.expr, cp, (int)(++k == total)); } break; } case SPL_AST_CONST_DECL: { node_label(prefix, is_last, "ConstDecl %s", STR(n->const_decl.name)); usize total = n->const_decl.attr_list.size + (n->const_decl.type_expr ? 1 : 0) + (n->const_decl.expr ? 1 : 0); if (total) { spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); usize k = 0; for (usize i = 0; i < n->const_decl.attr_list.size; i++) dump_node(ast, n->const_decl.attr_list.data[i], CTX_ATTR_ITEM, cp, (int)(++k == total)); if (n->const_decl.type_expr) dump_type_expr(ast, n->const_decl.type_expr, cp, (int)(++k == total)); if (n->const_decl.expr) dump_expr(ast, n->const_decl.expr, cp, (int)(++k == total)); } break; } case SPL_AST_MEMBER_DECL: { node_label(prefix, is_last, "Member %s", STR(n->member_decl.name)); usize total = n->member_decl.attr_list.size + (n->member_decl.type_expr ? 1 : 0); if (total) { spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); usize k = 0; for (usize i = 0; i < n->member_decl.attr_list.size; i++) dump_node(ast, n->member_decl.attr_list.data[i], CTX_ATTR_ITEM, cp, (int)(++k == total)); if (n->member_decl.type_expr) dump_type_expr(ast, n->member_decl.type_expr, cp, (int)(++k == total)); } break; } default: node_label(prefix, is_last, "Decl ?"); break; } break; case CTX_ATTR_ITEM: node_label(prefix, is_last, "Attr @%s", STR(n->attr_item.ident)); if (n->attr_item.expr_list.size) { spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); for (usize i = 0; i < n->attr_item.expr_list.size; i++) dump_expr(ast, n->attr_item.expr_list.data[i], cp, (int)(i == n->attr_item.expr_list.size - 1)); } break; case CTX_PARAM: if (n->param_decl.name) { node_label(prefix, is_last, "Param %s", STR(n->param_decl.name)); if (n->param_decl.attr_list.size || n->param_decl.type_expr) { spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); usize total = n->param_decl.attr_list.size + (n->param_decl.type_expr ? 1 : 0); usize k = 0; for (usize i = 0; i < n->param_decl.attr_list.size; i++) dump_node(ast, n->param_decl.attr_list.data[i], CTX_ATTR_ITEM, cp, (int)(++k == total)); if (n->param_decl.type_expr) dump_type_expr(ast, n->param_decl.type_expr, cp, (int)(++k == total)); } } else { node_label(prefix, is_last, "Param ..."); } break; case CTX_BLOCK_ITEM: if (n->kind == SPL_AST_EXPR) { dump_expr(ast, ref, prefix, is_last); break; } switch (n->block_item.kind) { case SPL_AST_IF_STATEMENT: { node_label(prefix, is_last, "If"); usize nkids = 1 + (n->block_item.if_statement.if_block.size ? 1 : 0) + (n->block_item.if_statement.else_block.size ? 1 : 0); spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); usize k = 0; dump_expr(ast, n->block_item.if_statement.expr, cp, (int)(++k == nkids)); if (n->block_item.if_statement.if_block.size) dump_block(ast, &n->block_item.if_statement.if_block, cp, (int)(++k == nkids)); if (n->block_item.if_statement.else_block.size) dump_block(ast, &n->block_item.if_statement.else_block, cp, (int)(++k == nkids)); break; } case SPL_AST_IFVAR_STATEMENT: { node_label(prefix, is_last, "IfVar"); usize nkids = 1 + (n->block_item.ifvar_statement.if_block.size ? 1 : 0) + (n->block_item.ifvar_statement.else_block.size ? 1 : 0); spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); usize k = 0; dump_packed(ast, n->block_item.ifvar_statement.packed_expr, cp, (int)(++k == nkids)); if (n->block_item.ifvar_statement.if_block.size) dump_block(ast, &n->block_item.ifvar_statement.if_block, cp, (int)(++k == nkids)); if (n->block_item.ifvar_statement.else_block.size) dump_block(ast, &n->block_item.ifvar_statement.else_block, cp, (int)(++k == nkids)); break; } case SPL_AST_WHILE_STATEMENT: { node_label(prefix, is_last, "While"); usize nkids = 1 + (n->block_item.while_statement.while_block.size ? 1 : 0); spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); usize k = 0; dump_expr(ast, n->block_item.while_statement.expr, cp, (int)(++k == nkids)); if (n->block_item.while_statement.while_block.size) dump_block(ast, &n->block_item.while_statement.while_block, cp, (int)(++k == nkids)); break; } case SPL_AST_LOOP_STATEMENT: node_label(prefix, is_last, "Loop"); if (n->block_item.loop_statement.loop_block.size) { spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); dump_block(ast, &n->block_item.loop_statement.loop_block, cp, 1); } break; case SPL_AST_FOR_STATEMENT: { node_label(prefix, is_last, "For"); usize nkids = n->block_item.for_statement.expr_vec.size + n->block_item.for_statement.ident_vec.size + (n->block_item.for_statement.block.size ? 1 : 0); if (nkids) { spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); usize k = 0; for (usize i = 0; i < n->block_item.for_statement.expr_vec.size; i++) dump_expr(ast, n->block_item.for_statement.expr_vec.data[i], cp, (int)(++k == nkids)); for (usize i = 0; i < n->block_item.for_statement.ident_vec.size; i++) { const char *bi = STR(n->block_item.for_statement.ident_vec.data[i]); node_label(cp, (int)(++k == nkids), "Bind %s", bi); } if (n->block_item.for_statement.block.size) dump_block(ast, &n->block_item.for_statement.block, cp, (int)(++k == nkids)); } break; } case SPL_AST_MATCH_STATEMENT: { node_label(prefix, is_last, "Match"); spl_ast_node_ref_vec_t *pp = &n->block_item.match_statement.paced_exprs; spl_ast_node_ref_vec_t *mb = &n->block_item.match_statement.match_block; usize nkids = 1 + pp->size; spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); usize k = 0; dump_expr(ast, n->block_item.match_statement.expr, cp, (int)(++k == nkids)); for (usize i = 0; i < pp->size && i < mb->size; i++) dump_arm(ast, pp->data[i], mb->data[i], cp, (int)(++k == nkids)); break; } case SPL_AST_RET_STATEMENT: node_label(prefix, is_last, "Ret"); if (n->block_item.ret_statement.expr) { spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); dump_expr(ast, n->block_item.ret_statement.expr, cp, 1); } break; case SPL_AST_BREAK_STATEMENT: node_label(prefix, is_last, "Break"); break; case SPL_AST_CONTINUE_STATEMENT: node_label(prefix, is_last, "Continue"); break; case SPL_AST_DEFER_STATEMENT: node_label(prefix, is_last, "Defer"); if (n->block_item.defer_statement.block_or_statement.size) { spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); dump_vec_children(ast, &n->block_item.defer_statement.block_or_statement, CTX_BLOCK_ITEM, cp, 1); } break; case SPL_AST_VARDECL: dump_node(ast, n->block_item.var_decl, CTX_DECL, prefix, is_last); break; case SPL_AST_CONSTDECL: dump_node(ast, n->block_item.const_decl, CTX_DECL, prefix, is_last); break; case SPL_AST_TYPEDECL: dump_node(ast, n->block_item.type_decl, CTX_DECL, prefix, is_last); break; case SPL_AST_EXPR_STATEMENT: node_label(prefix, is_last, "ExprStmt"); if (n->block_item.expr_statement) { spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); dump_expr(ast, n->block_item.expr_statement, cp, 1); } break; default: node_label(prefix, is_last, "BlockItem ?"); break; } break; case CTX_EXPR: dump_expr(ast, ref, prefix, is_last); break; case CTX_PREFIX: case CTX_POSTFIX: case CTX_PRIMARY: node_label(prefix, is_last, "?"); break; case CTX_PACKED: dump_packed(ast, ref, prefix, is_last); break; case CTX_AGG_ITEM: node_label(prefix, is_last, "Field .%s", STR(n->aggregate_init_item.ident)); if (n->aggregate_init_item.expr) { spl_dumptree_child_prefix(dt, prefix, is_last, cp, sizeof cp); dump_expr(ast, n->aggregate_init_item.expr, cp, 1); } break; case CTX_TYPE_EXPR: dump_type_expr(ast, ref, prefix, is_last); break; case CTX_TYPE_ATOM: { char t[128]; t[0] = '\0'; if (n->type_atom.kind == SPL_AST_TYPE_IDENT) strncat(t, STR(n->type_atom.ident), sizeof t - strlen(t) - 1); else strncat(t, type_atom_name(n->type_atom.kind), sizeof t - strlen(t) - 1); node_label(prefix, is_last, "%s", t); break; } case CTX_PREFIX_TYPE: if (n->prefix_type.pointer == 1) node_label(prefix, is_last, "*"); else if (n->prefix_type.array_size != 0) node_label(prefix, is_last, "[%d]", n->prefix_type.array_size); else node_label(prefix, is_last, "[]"); break; default: node_label(prefix, is_last, "?"); break; } } static void drop_vec(spl_ast_t *ast, spl_ast_node_ref_vec_t *vec, walk_ctx_t ctx) { for (usize i = 0; i < vec->size; i++) { drop_node(ast, vec->data[i], ctx); } vec_free(*vec); } static void drop_node(spl_ast_t *ast, spl_ast_node_ref_t ref, walk_ctx_t ctx) { if (!ref || ref >= ast->buckets.size) return; spl_ast_node_t *n = &ast->buckets.data[ref]; switch (ctx) { case CTX_CONTAINER: drop_vec(ast, &n->container_item.members, CTX_DECL); break; case CTX_DECL: switch (n->kind) { case SPL_AST_FN_DECL: case SPL_AST_FN_DEFINE: free((void *)n->fn_decl.name); drop_vec(ast, &n->fn_decl.attr_list, CTX_ATTR_ITEM); drop_vec(ast, &n->fn_decl.param_list, CTX_PARAM); drop_node(ast, n->fn_decl.type_expr, CTX_TYPE_EXPR); drop_vec(ast, &n->fn_decl.block, CTX_BLOCK_ITEM); break; case SPL_AST_TYPE_DECL: free((void *)n->type_decl.name); drop_node(ast, n->type_decl.type_expr, CTX_TYPE_EXPR); break; case SPL_AST_VAR_DECL: free((void *)n->var_decl.name); drop_vec(ast, &n->var_decl.attr_list, CTX_ATTR_ITEM); drop_node(ast, n->var_decl.type_expr, CTX_TYPE_EXPR); drop_node(ast, n->var_decl.expr, CTX_EXPR); break; case SPL_AST_CONST_DECL: free((void *)n->const_decl.name); drop_vec(ast, &n->const_decl.attr_list, CTX_ATTR_ITEM); drop_node(ast, n->const_decl.type_expr, CTX_TYPE_EXPR); drop_node(ast, n->const_decl.expr, CTX_EXPR); break; case SPL_AST_MEMBER_DECL: free((void *)n->member_decl.name); drop_vec(ast, &n->member_decl.attr_list, CTX_ATTR_ITEM); drop_node(ast, n->member_decl.type_expr, CTX_TYPE_EXPR); break; default: break; } break; case CTX_ATTR_ITEM: free((void *)n->attr_item.ident); drop_vec(ast, &n->attr_item.expr_list, CTX_EXPR); break; case CTX_PARAM: free((void *)n->param_decl.name); drop_vec(ast, &n->param_decl.attr_list, CTX_ATTR_ITEM); drop_node(ast, n->param_decl.type_expr, CTX_TYPE_EXPR); break; case CTX_BLOCK_ITEM: if (n->kind == SPL_AST_EXPR) { drop_node(ast, ref, CTX_EXPR); break; } switch (n->block_item.kind) { case SPL_AST_IF_STATEMENT: drop_node(ast, n->block_item.if_statement.expr, CTX_EXPR); drop_vec(ast, &n->block_item.if_statement.if_block, CTX_BLOCK_ITEM); drop_vec(ast, &n->block_item.if_statement.else_block, CTX_BLOCK_ITEM); break; case SPL_AST_IFVAR_STATEMENT: drop_node(ast, n->block_item.ifvar_statement.packed_expr, CTX_PACKED); drop_vec(ast, &n->block_item.ifvar_statement.if_block, CTX_BLOCK_ITEM); drop_vec(ast, &n->block_item.ifvar_statement.else_block, CTX_BLOCK_ITEM); break; case SPL_AST_WHILE_STATEMENT: drop_node(ast, n->block_item.while_statement.expr, CTX_EXPR); drop_vec(ast, &n->block_item.while_statement.while_block, CTX_BLOCK_ITEM); break; case SPL_AST_LOOP_STATEMENT: drop_vec(ast, &n->block_item.loop_statement.loop_block, CTX_BLOCK_ITEM); break; case SPL_AST_FOR_STATEMENT: drop_vec(ast, &n->block_item.for_statement.expr_vec, CTX_EXPR); for (usize fi = 0; fi < n->block_item.for_statement.ident_vec.size; fi++) free(n->block_item.for_statement.ident_vec.data[fi]); vec_free(n->block_item.for_statement.ident_vec); drop_vec(ast, &n->block_item.for_statement.block, CTX_BLOCK_ITEM); break; case SPL_AST_MATCH_STATEMENT: drop_node(ast, n->block_item.match_statement.expr, CTX_EXPR); drop_vec(ast, &n->block_item.match_statement.paced_exprs, CTX_PACKED); { /* match_block 含共享 body 引用(模式合并),去重后 drop 防重复释放 */ spl_ast_node_ref_vec_t dedup; vec_init(dedup); for (usize di = 0; di < n->block_item.match_statement.match_block.size; di++) { spl_ast_node_ref_t r = n->block_item.match_statement.match_block.data[di]; int found = 0; for (usize dj = 0; dj < dedup.size; dj++) { if (dedup.data[dj] == r) { found = 1; break; } } if (!found) vec_push(dedup, r); } drop_vec(ast, &dedup, CTX_BLOCK_ITEM); } vec_free(n->block_item.match_statement.match_block); break; case SPL_AST_RET_STATEMENT: drop_node(ast, n->block_item.ret_statement.expr, CTX_EXPR); break; case SPL_AST_DEFER_STATEMENT: drop_vec(ast, &n->block_item.defer_statement.block_or_statement, CTX_BLOCK_ITEM); break; case SPL_AST_VARDECL: drop_node(ast, n->block_item.var_decl, CTX_DECL); break; case SPL_AST_CONSTDECL: drop_node(ast, n->block_item.const_decl, CTX_DECL); break; case SPL_AST_TYPEDECL: drop_node(ast, n->block_item.type_decl, CTX_DECL); break; case SPL_AST_EXPR_STATEMENT: drop_node(ast, n->block_item.expr_statement, CTX_EXPR); break; default: break; } break; case CTX_EXPR: switch (n->expr.op) { case SPL_AST_PREFIX_EXPR: drop_node(ast, n->expr.op_expr.left, CTX_PREFIX); break; case SPL_AST_POSTFIX_EXPR: drop_node(ast, n->expr.op_expr.left, CTX_POSTFIX); break; case SPL_AST_PRIMARY_EXPR: drop_node(ast, n->expr.op_expr.left, CTX_PRIMARY); break; default: drop_node(ast, n->expr.op_expr.left, CTX_EXPR); drop_node(ast, n->expr.op_expr.right, CTX_EXPR); break; } break; case CTX_PREFIX: drop_node(ast, n->prefix_expr.postfix_expr, CTX_EXPR); break; case CTX_POSTFIX: drop_node(ast, n->postfix_expr.primary_expr, CTX_PRIMARY); if (n->postfix_expr.kind == SPL_AST_FIELD_EXPR) free((void *)n->postfix_expr.field_expr); switch (n->postfix_expr.kind) { case SPL_AST_CALL_EXPR: drop_vec(ast, &n->postfix_expr.call_expr, CTX_EXPR); break; case SPL_AST_INDEX_EXPR: drop_node(ast, n->postfix_expr.index_expr, CTX_EXPR); break; case SPL_AST_SLICE_EXPR: drop_node(ast, n->postfix_expr.slice_expr.begin, CTX_EXPR); drop_node(ast, n->postfix_expr.slice_expr.end, CTX_EXPR); break; case SPL_AST_AS_EXPR: drop_node(ast, n->postfix_expr.type_expr, CTX_TYPE_EXPR); break; default: break; } break; case CTX_PRIMARY: switch (n->primary_expr.kind) { case SPL_AST_STRING_LIT: /* string_lit_expr 为解析出C 字符串副本,须释*/ free((void *)n->primary_expr.string_lit_expr); break; case SPL_AST_ARGGREGATE_INIT: free((void *)n->primary_expr.aggregate_init.name); drop_vec(ast, &n->primary_expr.aggregate_init.expr, CTX_AGG_ITEM); break; case SPL_AST_EXPR_EXPR: drop_node(ast, n->primary_expr.expr, CTX_EXPR); break; case SPL_AST_ARRAY_LIT: drop_node(ast, n->primary_expr.array_lit_expr.type_expr, CTX_TYPE_EXPR); drop_vec(ast, &n->primary_expr.array_lit_expr.expr_list, CTX_EXPR); break; case SPL_AST_BUILTIN_EXPR: free((void *)n->primary_expr.builtin_expr.ident); drop_vec(ast, &n->primary_expr.builtin_expr.expr_list, CTX_EXPR); break; case SPL_AST_BLOCK_EXPR: drop_vec(ast, &n->primary_expr.block_expr, CTX_BLOCK_ITEM); break; case SPL_AST_IDENT: free((void *)n->primary_expr.ident); break; default: break; } break; case CTX_PACKED: free((void *)n->packed_expr.ident); free((void *)n->packed_expr.bind_ident); drop_node(ast, n->packed_expr.expr, CTX_EXPR); break; case CTX_AGG_ITEM: free((void *)n->aggregate_init_item.ident); drop_node(ast, n->aggregate_init_item.expr, CTX_EXPR); break; case CTX_TYPE_EXPR: drop_vec(ast, &n->type_expr.type_prefixs, CTX_PREFIX_TYPE); drop_vec(ast, &n->type_expr.attr_list, CTX_ATTR_ITEM); if (n->type_expr.kind == SPL_AST_BASE_TYPE_FN) { drop_vec(ast, &n->type_expr.fn_type.param_list, CTX_PARAM); drop_node(ast, n->type_expr.fn_type.type_expr, CTX_TYPE_EXPR); } else if (n->type_expr.kind == SPL_AST_TYPE_STRUCT || n->type_expr.kind == SPL_AST_TYPE_UNION || n->type_expr.kind == SPL_AST_TYPE_ENUM) { drop_vec(ast, &n->type_expr.aggregate_list, CTX_DECL); } else { drop_vec(ast, &n->type_expr.type_path, CTX_TYPE_ATOM); } break; case CTX_TYPE_ATOM: free((void *)n->type_atom.ident); break; default: break; } } /* ================================================================ * valid(结构校验) * ================================================================ */ static void validate_vec(spl_ast_t *ast, spl_ast_node_ref_vec_t *vec, walk_ctx_t ctx) { for (usize i = 0; i < vec->size; i++) { validate_node(ast, vec->data[i], ctx); } } static void validate_node(spl_ast_t *ast, spl_ast_node_ref_t ref, walk_ctx_t ctx) { if (!ref) return; if (ref >= ast->buckets.size) { printf("valid: invalid node reference %llu\n", (unsigned long long)ref); return; } spl_ast_node_t *n = &ast->buckets.data[ref]; switch (ctx) { case CTX_CONTAINER: validate_vec(ast, &n->container_item.members, CTX_DECL); break; case CTX_DECL: switch (n->kind) { case SPL_AST_FN_DECL: case SPL_AST_FN_DEFINE: if (!n->fn_decl.name) printf("valid: function missing name\n"); validate_vec(ast, &n->fn_decl.attr_list, CTX_ATTR_ITEM); validate_vec(ast, &n->fn_decl.param_list, CTX_PARAM); validate_node(ast, n->fn_decl.type_expr, CTX_TYPE_EXPR); validate_vec(ast, &n->fn_decl.block, CTX_BLOCK_ITEM); break; case SPL_AST_TYPE_DECL: if (!n->type_decl.name) printf("valid: type declaration missing name\n"); validate_node(ast, n->type_decl.type_expr, CTX_TYPE_EXPR); break; case SPL_AST_VAR_DECL: if (!n->var_decl.name) printf("valid: variable declaration missing name\n"); validate_vec(ast, &n->var_decl.attr_list, CTX_ATTR_ITEM); validate_node(ast, n->var_decl.type_expr, CTX_TYPE_EXPR); validate_node(ast, n->var_decl.expr, CTX_EXPR); break; case SPL_AST_CONST_DECL: if (!n->const_decl.name) printf("valid: constant declaration missing name\n"); validate_vec(ast, &n->const_decl.attr_list, CTX_ATTR_ITEM); validate_node(ast, n->const_decl.type_expr, CTX_TYPE_EXPR); validate_node(ast, n->const_decl.expr, CTX_EXPR); break; case SPL_AST_MEMBER_DECL: if (!n->member_decl.name) printf("valid: member declaration missing name\n"); validate_vec(ast, &n->member_decl.attr_list, CTX_ATTR_ITEM); validate_node(ast, n->member_decl.type_expr, CTX_TYPE_EXPR); break; default: break; } break; case CTX_ATTR_ITEM: if (!n->attr_item.ident) printf("valid: attribute missing name\n"); validate_vec(ast, &n->attr_item.expr_list, CTX_EXPR); break; case CTX_PARAM: validate_vec(ast, &n->param_decl.attr_list, CTX_ATTR_ITEM); validate_node(ast, n->param_decl.type_expr, CTX_TYPE_EXPR); break; case CTX_BLOCK_ITEM: if (n->kind == SPL_AST_EXPR) { validate_node(ast, ref, CTX_EXPR); break; } switch (n->block_item.kind) { case SPL_AST_IF_STATEMENT: validate_node(ast, n->block_item.if_statement.expr, CTX_EXPR); validate_vec(ast, &n->block_item.if_statement.if_block, CTX_BLOCK_ITEM); validate_vec(ast, &n->block_item.if_statement.else_block, CTX_BLOCK_ITEM); break; case SPL_AST_IFVAR_STATEMENT: validate_node(ast, n->block_item.ifvar_statement.packed_expr, CTX_PACKED); validate_vec(ast, &n->block_item.ifvar_statement.if_block, CTX_BLOCK_ITEM); validate_vec(ast, &n->block_item.ifvar_statement.else_block, CTX_BLOCK_ITEM); break; case SPL_AST_WHILE_STATEMENT: validate_node(ast, n->block_item.while_statement.expr, CTX_EXPR); validate_vec(ast, &n->block_item.while_statement.while_block, CTX_BLOCK_ITEM); break; case SPL_AST_LOOP_STATEMENT: validate_vec(ast, &n->block_item.loop_statement.loop_block, CTX_BLOCK_ITEM); break; case SPL_AST_FOR_STATEMENT: validate_vec(ast, &n->block_item.for_statement.expr_vec, CTX_EXPR); validate_vec(ast, &n->block_item.for_statement.block, CTX_BLOCK_ITEM); break; case SPL_AST_MATCH_STATEMENT: validate_node(ast, n->block_item.match_statement.expr, CTX_EXPR); validate_vec(ast, &n->block_item.match_statement.paced_exprs, CTX_PACKED); validate_vec(ast, &n->block_item.match_statement.match_block, CTX_BLOCK_ITEM); if (n->block_item.match_statement.paced_exprs.size != n->block_item.match_statement.match_block.size) printf("valid: match arm pattern/statement count mismatch\n"); break; case SPL_AST_RET_STATEMENT: validate_node(ast, n->block_item.ret_statement.expr, CTX_EXPR); break; case SPL_AST_DEFER_STATEMENT: validate_vec(ast, &n->block_item.defer_statement.block_or_statement, CTX_BLOCK_ITEM); break; case SPL_AST_VARDECL: validate_node(ast, n->block_item.var_decl, CTX_DECL); break; case SPL_AST_CONSTDECL: validate_node(ast, n->block_item.const_decl, CTX_DECL); break; case SPL_AST_TYPEDECL: validate_node(ast, n->block_item.type_decl, CTX_DECL); break; case SPL_AST_EXPR_STATEMENT: validate_node(ast, n->block_item.expr_statement, CTX_EXPR); break; default: break; } break; case CTX_EXPR: switch (n->expr.op) { case SPL_AST_PREFIX_EXPR: validate_node(ast, n->expr.op_expr.left, CTX_PREFIX); break; case SPL_AST_POSTFIX_EXPR: validate_node(ast, n->expr.op_expr.left, CTX_POSTFIX); break; case SPL_AST_PRIMARY_EXPR: validate_node(ast, n->expr.op_expr.left, CTX_PRIMARY); break; default: validate_node(ast, n->expr.op_expr.left, CTX_EXPR); validate_node(ast, n->expr.op_expr.right, CTX_EXPR); break; } break; case CTX_PREFIX: validate_node(ast, n->prefix_expr.postfix_expr, CTX_EXPR); break; case CTX_POSTFIX: validate_node(ast, n->postfix_expr.primary_expr, CTX_PRIMARY); switch (n->postfix_expr.kind) { case SPL_AST_CALL_EXPR: validate_vec(ast, &n->postfix_expr.call_expr, CTX_EXPR); break; case SPL_AST_INDEX_EXPR: validate_node(ast, n->postfix_expr.index_expr, CTX_EXPR); break; case SPL_AST_SLICE_EXPR: validate_node(ast, n->postfix_expr.slice_expr.begin, CTX_EXPR); validate_node(ast, n->postfix_expr.slice_expr.end, CTX_EXPR); break; case SPL_AST_AS_EXPR: validate_node(ast, n->postfix_expr.type_expr, CTX_TYPE_EXPR); break; default: break; } break; case CTX_PRIMARY: switch (n->primary_expr.kind) { case SPL_AST_IDENT: if (!n->primary_expr.ident) printf("valid: identifier missing name\n"); break; case SPL_AST_ARGGREGATE_INIT: validate_vec(ast, &n->primary_expr.aggregate_init.expr, CTX_AGG_ITEM); break; case SPL_AST_EXPR_EXPR: validate_node(ast, n->primary_expr.expr, CTX_EXPR); break; case SPL_AST_ARRAY_LIT: validate_node(ast, n->primary_expr.array_lit_expr.type_expr, CTX_TYPE_EXPR); validate_vec(ast, &n->primary_expr.array_lit_expr.expr_list, CTX_EXPR); break; case SPL_AST_BUILTIN_EXPR: validate_vec(ast, &n->primary_expr.builtin_expr.expr_list, CTX_EXPR); break; case SPL_AST_BLOCK_EXPR: validate_vec(ast, &n->primary_expr.block_expr, CTX_BLOCK_ITEM); break; default: break; } break; case CTX_PACKED: validate_node(ast, n->packed_expr.expr, CTX_EXPR); break; case CTX_AGG_ITEM: validate_node(ast, n->aggregate_init_item.expr, CTX_EXPR); break; case CTX_TYPE_EXPR: validate_vec(ast, &n->type_expr.type_prefixs, CTX_PREFIX_TYPE); validate_vec(ast, &n->type_expr.attr_list, CTX_ATTR_ITEM); if (n->type_expr.kind == SPL_AST_BASE_TYPE_FN) { validate_vec(ast, &n->type_expr.fn_type.param_list, CTX_PARAM); validate_node(ast, n->type_expr.fn_type.type_expr, CTX_TYPE_EXPR); } else if (n->type_expr.kind == SPL_AST_TYPE_STRUCT || n->type_expr.kind == SPL_AST_TYPE_UNION || n->type_expr.kind == SPL_AST_TYPE_ENUM) { validate_vec(ast, &n->type_expr.aggregate_list, CTX_DECL); } else { validate_vec(ast, &n->type_expr.type_path, CTX_TYPE_ATOM); } break; default: break; } }