#include "spl_ast.h" #include "spl_dbg.h" #include "spl_dumptree.h" #include "spl_tok.h" #define MOVE_VEC(dst, src) \ do { \ (dst) = (src); \ vec_init(src); \ } while (0) 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; } const char *spl_ast_kind_name(spl_ast_node_kind_t kind) { static const char *const names[] = { #define X(a, b, c) #c, SPL_AST_KIND_TABLE #undef X }; if ((usize)kind < sizeof(names) / sizeof(names[0])) return names[kind]; return "?"; } const char *spl_binary_op_name(spl_binary_op_t op) { static const char *const names[] = { #define X(a, b, c, name) #name, SPL_BINARY_OP_TABLE #undef X }; if ((usize)op < sizeof(names) / sizeof(names[0])) return names[op]; return "?"; } const char *spl_unary_op_name(spl_unary_op_t op) { switch (op) { case SPL_UNARY_OP_MINUS: return "neg"; case SPL_UNARY_OP_NOT: return "not"; case SPL_UNARY_OP_BIT_NOT: return "bitnot"; case SPL_UNARY_OP_ADDRESS: return "addr"; default: return "?"; } } typedef struct { spl_ast_t *ast; usize pos; int failed; int stop_as; int stop_agg; } parser_t; static inline int is_trivia(spl_tok_type_t t) { return t == TOK_ENDLINE || t == TOK_LINE_COMMENT; } static inline const spl_tok_t *peek(parser_t *p) { usize n = vec_size(p->ast->input); usize i = p->pos; while (i < n && is_trivia(vec_at(p->ast->input, i).type)) i++; p->pos = i; if (i >= n) return NULL; return &vec_at(p->ast->input, i); } static inline const spl_tok_t *advance(parser_t *p) { const spl_tok_t *t = peek(p); if (t && t->type != TOK_EOF) p->pos++; return t; } static inline spl_ast_node_t *node_at(spl_ast_t *ast, spl_ast_node_ref_t ref) { return &ast->node_buckets.data[ref]; } static spl_ast_node_ref_t new_node(parser_t *p, spl_ast_node_kind_t kind, const spl_tok_t *tok) { spl_ast_node_t n = {0}; n.kind = kind; n.resolved_def_id = 0; n.resolved_type_id = 0; if (tok) { n.dbg.dbg_name = spl_ast_kind_name(kind); n.dbg.fname = tok->fname; n.dbg.line = (int)tok->line; n.dbg.col = (int)tok->col; } vec_push(p->ast->node_buckets, n); return p->ast->node_buckets.size - 1; } static char *intern_string(spl_ast_t *ast, const char *s, usize len) { char *copy = sdupn(s, len); if (!copy) return NULL; vec_push(ast->str_buckets, copy); return copy; } #define SET_STR_FIELD(ast, field, tok) \ do { \ (field) = intern_string(ast, (tok)->lexeme, (tok)->len); \ } while (0) static spl_ast_node_ref_t mk_bin(parser_t *p, const spl_tok_t *loc, spl_binary_op_t 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_BINARY, loc); spl_ast_node_t *node = node_at(p->ast, ref); node->binary.op = op; node->binary.left = left; node->binary.right = right; return ref; } static spl_ast_node_ref_t mk_unary(parser_t *p, const spl_tok_t *loc, spl_unary_op_t op, spl_ast_node_ref_t operand) { spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_UNARY, loc); spl_ast_node_t *node = node_at(p->ast, ref); node->unary.op = op; node->unary.operand = operand; return 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_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_type_comptime_call(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_var_pattern(parser_t *p); static spl_ast_node_ref_t parse_match_pattern(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_fields(parser_t *p); static spl_ast_node_ref_t parse_array_literal(parser_t *p); static spl_ast_node_ref_t parse_comptime_call(parser_t *p); static spl_ast_node_ref_t parse_if_expr(parser_t *p); static spl_ast_node_ref_t parse_while_expr(parser_t *p); static spl_ast_node_ref_t parse_loop_expr(parser_t *p); static spl_ast_node_ref_t parse_for_expr(parser_t *p); static spl_ast_node_ref_t parse_match_expr(parser_t *p); static spl_ast_node_ref_t parse_ret_stmt(parser_t *p); static spl_ast_node_ref_t parse_break_stmt(parser_t *p); static spl_ast_node_ref_t parse_continue_stmt(parser_t *p); static spl_ast_node_ref_t parse_defer_stmt(parser_t *p); static spl_ast_node_ref_t parse_comptime_stmt(parser_t *p); static spl_ast_node_ref_t parse_label(parser_t *p); 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; if (j >= 3 && buf[0] == '0' && (buf[1] == 'b' || buf[1] == 'B')) return (isize)strtoll(buf + 2, NULL, 2); if (j >= 3 && buf[0] == '0' && (buf[1] == 'o' || buf[1] == 'O')) return (isize)strtoll(buf + 2, NULL, 8); 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; } static char *parse_string_literal(parser_t *p, const spl_tok_t *t) { const char *src = t->lexeme + 1; const char *end = t->lexeme + t->len - 1; usize cap = t->len + 1; char *tmp = malloc(cap); if (!tmp) return NULL; char *dst = tmp; while (src < end) { char c; if (spl_decode_escape(&src, &c) == 0) { *dst++ = c; } else { *dst++ = *src; src++; } } *dst = '\0'; char *interned = intern_string(p->ast, tmp, dst - tmp); free(tmp); return interned; } 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 KW_UNDEFINED: case TOK_IDENT: case TOK_AT: case TOK_SHARP: case TOK_L_PAREN: case TOK_L_BRACKET: case TOK_L_BRACE: case TOK_DOT: case TOK_SUB: case TOK_NOT: case TOK_BIT_NOT: case TOK_AND: case TOK_MUL: case KW_IF: case KW_WHILE: case KW_LOOP: case KW_FOR: case KW_MATCH: 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; } } static void parse_tag_list(parser_t *p, spl_ast_node_ref_vec_t *out, int is_external) { while (!p->failed) { const spl_tok_t *t = peek(p); if (!t || (t->type != TOK_AT && t->type != TOK_SHARP)) return; int is_at = (t->type == TOK_AT); advance(p); if (is_external) { t = peek(p); if (!t || t->type != TOK_NOT) { SPL_FATAL(t, "expected '!' in external tag"); return; } advance(p); } t = peek(p); if (!t || t->type != TOK_IDENT) { SPL_FATAL(t, "expected tag name"); return; } advance(p); spl_ast_node_ref_t ref = new_node(p, is_external ? SPL_AST_EXTERNAL_TAG_ITEM : SPL_AST_TAG_ITEM, t); spl_ast_node_t *tag = node_at(p->ast, ref); tag->tag_item.is_at = is_at; tag->tag_item.is_external = is_external; SET_STR_FIELD(p->ast, tag->tag_item.name, t); t = peek(p); if (t && t->type == TOK_L_PAREN) { advance(p); spl_ast_node_ref_vec_t args = parse_expr_list(p); node_at(p->ast, ref)->tag_item.args = args; t = peek(p); if (!t || t->type != TOK_R_PAREN) { SPL_FATAL(t, "expected ')' in tag args"); return; } advance(p); } vec_push(*out, ref); } } static void parse_param_list(parser_t *p, spl_ast_node_ref_vec_t *out) { while (!p->failed) { const spl_tok_t *t = peek(p); if (!t) break; if (t->type == TOK_R_PAREN) { break; } else 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; } break; } else if (t->type == TOK_ELLIPSIS) { advance(p); spl_ast_node_ref_t pd = new_node(p, SPL_AST_PARAM_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); break; // } else if (t->type == KW_VOID) { // advance(p); // t = peek(p); // if (!t || t->type != TOK_R_PAREN) { // SPL_FATAL(t, "expected ')' after void"); // } // break; } else { SPL_FATAL(t, "unexpected token in parameter list"); break; } } } 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_tag_list(p, &attr_list, 0); const spl_tok_t *name = peek(p); if (!name || (name->type != TOK_IDENT && name->type != KW_UNDERSCORE)) { SPL_FATAL(name, "expected parameter name or '_'"); return 0; } advance(p); const spl_tok_t *t = peek(p); if (!t || t->type != TOK_COLON) { SPL_FATAL(t, "expected ':' in parameter declaration"); return 0; } advance(p); spl_ast_node_ref_t type_expr = parse_type_expr(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_PARAM_DECL, name); spl_ast_node_t *param = node_at(p->ast, ref); MOVE_VEC(param->param_decl.attr_list, attr_list); SET_STR_FIELD(p->ast, param->param_decl.name, name); // 若为下划线则存储 "_" param->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 tag_list) { const spl_tok_t *kw = peek(p); if (!kw || kw->type != KW_FN) return 0; advance(p); const spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { SPL_FATAL(name ? name : kw, "expected function name"); return 0; } advance(p); const spl_tok_t *t = peek(p); if (!t || t->type != TOK_L_PAREN) { SPL_FATAL(t, "expected '(' in function declaration"); return 0; } advance(p); spl_ast_node_ref_vec_t params; vec_init(params); parse_param_list(p, ¶ms); t = peek(p); if (!t || t->type != TOK_R_PAREN) { SPL_FATAL(t, "expected ')' in function declaration"); return 0; } advance(p); spl_ast_node_ref_t ret_type = 0; t = peek(p); if (t && t->type == TOK_COLON) { advance(p); ret_type = parse_type_expr(p); t = peek(p); } spl_ast_node_ref_t body = 0; if (t && t->type == TOK_L_BRACE) { body = parse_block(p); } else if (t && t->type == TOK_SEMICOLON) { advance(p); } else { SPL_FATAL(t, "function declaration must end with ';' or block"); return 0; } spl_ast_node_ref_t ref = new_node(p, SPL_AST_FN_DECL, kw); spl_ast_node_t *fn = node_at(p->ast, ref); MOVE_VEC(fn->fn_decl.tag_list, tag_list); fn->fn_decl.is_comptime = 0; SET_STR_FIELD(p->ast, fn->fn_decl.name, name); fn->fn_decl.params = params; /* params 局部变量,直接转移 */ fn->fn_decl.ret_type = ret_type; fn->fn_decl.body = body; return ref; } static spl_ast_node_ref_t parse_type_decl(parser_t *p, spl_ast_node_ref_vec_t tag_list) { const spl_tok_t *kw = peek(p); if (!kw || kw->type != KW_TYPE) return 0; advance(p); const spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { SPL_FATAL(name ? name : kw, "expected type name"); return 0; } advance(p); const spl_tok_t *t = peek(p); if (!t || t->type != TOK_ASSIGN) { SPL_FATAL(t, "expected '=' in type declaration"); return 0; } advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_DECL, kw); spl_ast_node_t *td = node_at(p->ast, ref); MOVE_VEC(td->type_decl.attr_list, tag_list); SET_STR_FIELD(p->ast, td->type_decl.name, name); spl_ast_node_ref_t type_expr = parse_type_expr(p); node_at(p->ast, ref)->type_decl.type_expr = type_expr; 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_const_decl(parser_t *p, spl_ast_node_ref_vec_t tag_list, int is_const) { const spl_tok_t *kw = peek(p); if (!kw) return 0; if (is_const && kw->type != KW_CONST) return 0; if (!is_const && kw->type != KW_VAR) return 0; advance(p); spl_ast_node_ref_t pattern = parse_var_pattern(p); if (!pattern) return 0; spl_ast_node_ref_t type_expr = 0; spl_ast_node_ref_t init_expr = 0; const spl_tok_t *t = peek(p); if (t && t->type == TOK_COLON) { advance(p); type_expr = parse_type_expr(p); t = peek(p); if (t && t->type == TOK_ASSIGN) { advance(p); init_expr = parse_expr(p); } } else if (t && t->type == TOK_ASSIGN) { advance(p); init_expr = parse_expr(p); } spl_ast_node_ref_t ref = new_node(p, is_const ? SPL_AST_CONST_DECL : SPL_AST_VAR_DECL, kw); spl_ast_node_t *vc = node_at(p->ast, ref); MOVE_VEC(vc->var_const_decl.attr_list, tag_list); vc->var_const_decl.pattern = pattern; vc->var_const_decl.type = type_expr; vc->var_const_decl.init_expr = init_expr; t = peek(p); if (t && t->type == TOK_SEMICOLON) { advance(p); } return ref; } static spl_ast_node_ref_t parse_member_decl(parser_t *p, spl_ast_node_ref_vec_t tag_list) { const spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) return 0; advance(p); spl_ast_node_ref_t type_expr = 0; spl_ast_node_ref_t init_expr = 0; const spl_tok_t *t = peek(p); if (t && t->type == TOK_COLON) { advance(p); type_expr = parse_type_expr(p); t = peek(p); if (t && t->type == TOK_ASSIGN) { advance(p); init_expr = parse_expr(p); } } else if (t && t->type == TOK_ASSIGN) { advance(p); init_expr = parse_expr(p); } spl_ast_node_ref_t ref = new_node(p, SPL_AST_MEMBER_DECL, name); spl_ast_node_t *md = node_at(p->ast, ref); MOVE_VEC(md->member_decl.attr_list, tag_list); SET_STR_FIELD(p->ast, md->member_decl.name, name); md->member_decl.type_expr = type_expr; md->member_decl.init_expr = init_expr; t = peek(p); if (t && (t->type == TOK_COMMA || t->type == TOK_SEMICOLON)) { advance(p); } return ref; } static spl_ast_node_ref_t parse_comptime_decl(parser_t *p) { const spl_tok_t *kw = peek(p); if (!kw || kw->type != KW_COMPTIME) return 0; advance(p); spl_ast_node_ref_t body = 0; const spl_tok_t *t = peek(p); if (t && t->type == TOK_L_BRACE) { body = parse_block(p); } else { body = parse_expr(p); } spl_ast_node_ref_t ref = new_node(p, SPL_AST_COMPTIME_DECL, kw); node_at(p->ast, ref)->comptime_decl.body = body; return ref; } static spl_ast_node_ref_t parse_container_declaration(parser_t *p) { spl_ast_node_ref_vec_t tag_list; vec_init(tag_list); parse_tag_list(p, &tag_list, 0); /* 只解析普通 tag */ const spl_tok_t *t = peek(p); if (!t || t->type == TOK_EOF) { vec_free(tag_list); return 0; } switch (t->type) { case KW_FN: return parse_fn_decl(p, tag_list); case KW_TYPE: return parse_type_decl(p, tag_list); case KW_VAR: return parse_var_const_decl(p, tag_list, 0); case KW_CONST: return parse_var_const_decl(p, tag_list, 1); case TOK_IDENT: return parse_member_decl(p, tag_list); case KW_COMPTIME: vec_free(tag_list); /* comptime decl 不使用 tag_list */ return parse_comptime_decl(p); case TOK_L_BRACE: { spl_ast_node_ref_t block = parse_block(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_TOP_LEVEL_BLOCK, t); spl_ast_node_t *tb = node_at(p->ast, ref); MOVE_VEC(tb->top_level_block.tag_list, tag_list); tb->top_level_block.block = block; return ref; } default: SPL_FATAL(t, "unrecognized declaration"); vec_free(tag_list); return 0; } } static spl_ast_node_ref_t parse_var_pattern_atom(parser_t *p) { const spl_tok_t *t = peek(p); if (!t) return 0; if (t->type == TOK_IDENT) { advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_PATTERN_IDENT, t); SET_STR_FIELD(p->ast, node_at(p->ast, ref)->pattern_ident.name, t); return ref; } else if (t->type == KW_UNDERSCORE) { advance(p); return new_node(p, SPL_AST_PATTERN_UNDERSCORE, t); } else if (t->type == TOK_DOT) { advance(p); const spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { SPL_FATAL(name, "expected identifier after '.' in pattern"); return 0; } advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_PATTERN_DOT, t); spl_ast_node_t *pat = node_at(p->ast, ref); SET_STR_FIELD(p->ast, pat->pattern_dot.name, name); if (peek(p) && peek(p)->type == TOK_L_BRACKET) { advance(p); spl_ast_node_ref_t sub = parse_var_pattern(p); node_at(p->ast, ref)->pattern_dot.sub_pattern = sub; t = peek(p); if (!t || t->type != TOK_R_BRACKET) { SPL_FATAL(t, "expected ']' in pattern"); return 0; } advance(p); } return ref; } else if (t->type == TOK_L_PAREN) { advance(p); spl_ast_node_ref_t inner = parse_var_pattern(p); t = peek(p); if (!t || t->type != TOK_R_PAREN) { SPL_FATAL(t, "expected ')' in pattern"); return 0; } advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_PATTERN_TUPLE, t); spl_ast_node_t *tuple = node_at(p->ast, ref); vec_init(tuple->pattern_tuple.patterns); if (node_at(p->ast, inner)->kind == SPL_AST_PATTERN_LIST) { tuple->pattern_tuple.patterns = node_at(p->ast, inner)->pattern_list.patterns; } else { vec_push(tuple->pattern_tuple.patterns, inner); } return ref; } else { SPL_FATAL(t, "unexpected token in pattern"); return 0; } } static spl_ast_node_ref_t parse_var_pattern(parser_t *p) { spl_ast_node_ref_vec_t patterns; vec_init(patterns); while (!p->failed) { spl_ast_node_ref_t atom = parse_var_pattern_atom(p); if (!atom) break; vec_push(patterns, atom); const spl_tok_t *t = peek(p); if (t && t->type == TOK_COMMA) { advance(p); continue; } break; } if (patterns.size == 0) return 0; if (patterns.size == 1) { spl_ast_node_ref_t ref = patterns.data[0]; vec_free(patterns); return ref; } spl_ast_node_ref_t ref = new_node(p, SPL_AST_PATTERN_LIST, peek(p)); node_at(p->ast, ref)->pattern_list.patterns = patterns; return ref; } static spl_ast_node_ref_t parse_match_pattern(parser_t *p) { const spl_tok_t *t = peek(p); if (!t) return 0; /* 如果当前 token 是模式专用起始符,按变量模式解析;否则按表达式解析 */ if (t->type == KW_UNDERSCORE || t->type == TOK_DOT || t->type == TOK_L_PAREN) { return parse_var_pattern(p); } else { /* 表达式模式:字面量、标识符、块、if 等 */ return parse_expr(p); } } static spl_ast_node_ref_t parse_type_base(parser_t *p) { spl_ast_node_ref_vec_t tag_list; vec_init(tag_list); parse_tag_list(p, &tag_list, 0); const spl_tok_t *bt = peek(p); if (!bt) { vec_free(tag_list); SPL_FATAL(bt, "expected type"); return 0; } /* 函数类型 */ if (bt->type == KW_FN) { vec_free(tag_list); advance(p); const spl_tok_t *t = peek(p); if (!t || t->type != TOK_L_PAREN) { SPL_FATAL(t, "expected '(' in function type"); return 0; } advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_FN, bt); spl_ast_node_t *fn_type = node_at(p->ast, ref); fn_type->type_fn.is_comptime = 0; vec_init(fn_type->type_fn.params); while (!p->failed && peek(p) && peek(p)->type != TOK_R_PAREN) { spl_ast_node_ref_t pt = parse_type_expr(p); fn_type = node_at(p->ast, ref); // 防悬空 vec_push(fn_type->type_fn.params, pt); if (peek(p) && peek(p)->type == TOK_COMMA) { advance(p); continue; } break; } t = peek(p); if (!t || t->type != TOK_R_PAREN) { SPL_FATAL(t, "expected ')' in function type"); return 0; } advance(p); if (peek(p) && peek(p)->type == TOK_COLON) { advance(p); spl_ast_node_ref_t ret = parse_type_expr(p); node_at(p->ast, ref)->type_fn.ret_type = ret; } return ref; } /* 聚合类型:struct / union / enum / shape */ if (bt->type == KW_STRUCT || bt->type == KW_UNION || bt->type == KW_ENUM || bt->type == KW_SHAPE) { vec_free(tag_list); /* 聚合类型不使用 tag_list */ const char *kind_name = (bt->type == KW_STRUCT) ? "struct" : (bt->type == KW_UNION) ? "union" : (bt->type == KW_ENUM) ? "enum" : "shape"; advance(p); const spl_tok_t *t = peek(p); if (!t || t->type != TOK_L_BRACE) { SPL_FATAL(t, "expected '{' in aggregate type"); return 0; } advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_AGGREGATE, bt); spl_ast_node_t *agg = node_at(p->ast, ref); agg->type_aggregate.kind_name = kind_name; vec_init(agg->type_aggregate.members); // 存放真正的容器声明节点 /* 解析容器成员,直到 '}' */ while (!p->failed) { t = peek(p); if (!t || t->type == TOK_EOF) { SPL_FATAL(t, "aggregate type missing '}'"); return ref; } if (t->type == TOK_R_BRACE) { advance(p); break; } spl_ast_node_ref_t member = parse_container_declaration(p); if (member) { agg = node_at(p->ast, ref); // 防止节点数组扩容导致悬空 vec_push(agg->type_aggregate.members, member); } /* 跳过可选分隔符 */ t = peek(p); if (t && (t->type == TOK_COMMA || t->type == TOK_SEMICOLON)) { advance(p); } } return ref; } /* 内建类型和普通路径 */ if (bt->type == TOK_IDENT) { const char *name = bt->lexeme; usize len = bt->len; /* 内建类型关键字 */ if ((len == 2 && strncmp(name, "i8", 2) == 0) || (len == 2 && strncmp(name, "u8", 2) == 0) || (len == 3 && strncmp(name, "i16", 3) == 0) || (len == 3 && strncmp(name, "u16", 3) == 0) || (len == 3 && strncmp(name, "i32", 3) == 0) || (len == 3 && strncmp(name, "u32", 3) == 0) || (len == 3 && strncmp(name, "i64", 3) == 0) || (len == 3 && strncmp(name, "u64", 3) == 0) || (len == 5 && strncmp(name, "isize", 5) == 0) || (len == 5 && strncmp(name, "usize", 5) == 0) || (len == 3 && strncmp(name, "f32", 3) == 0) || (len == 3 && strncmp(name, "f64", 3) == 0) || (len == 4 && strncmp(name, "bool", 4) == 0) // (len == 4 && strncmp(name, "void", 4) == 0) || // (len == 3 && strncmp(name, "any", 3) == 0) ) { advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_PATH, bt); spl_ast_node_t *tp = node_at(p->ast, ref); SET_STR_FIELD(p->ast, tp->type_path.name, bt); vec_init(tp->type_path.generic_args); vec_free(tag_list); return ref; } /* 普通类型路径 */ advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_PATH, bt); spl_ast_node_t *tp = node_at(p->ast, ref); SET_STR_FIELD(p->ast, tp->type_path.name, bt); vec_init(tp->type_path.generic_args); while (peek(p) && peek(p)->type == TOK_DOT) { advance(p); const spl_tok_t *seg = peek(p); if (!seg || seg->type != TOK_IDENT) { SPL_FATAL(seg, "expected identifier after '.' in type path"); break; } advance(p); } vec_free(tag_list); return ref; } if (bt->type == TOK_AT || bt->type == TOK_SHARP) { vec_free(tag_list); return parse_type_comptime_call(p); } if (bt->type == KW_ANY) { advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_PATH, bt); spl_ast_node_t *tp = node_at(p->ast, ref); SET_STR_FIELD(p->ast, tp->type_path.name, bt); vec_init(tp->type_path.generic_args); vec_free(tag_list); return ref; } vec_free(tag_list); SPL_FATAL(bt, "unrecognized type"); return 0; } static spl_ast_node_ref_t parse_type_comptime_call(parser_t *p) { const spl_tok_t *start = peek(p); if (!start || (start->type != TOK_AT && start->type != TOK_SHARP)) return 0; advance(p); const spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { SPL_FATAL(name, "expected comptime call name"); return 0; } advance(p); const spl_tok_t *t = peek(p); if (!t || t->type != TOK_L_PAREN) { SPL_FATAL(t, "expected '(' in comptime call"); return 0; } advance(p); spl_ast_node_ref_vec_t args = parse_expr_list(p); t = peek(p); if (!t || t->type != TOK_R_PAREN) { SPL_FATAL(t, "expected ')' in comptime call"); return 0; } advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_COMPTIME_CALL, start); spl_ast_node_t *cc = node_at(p->ast, ref); SET_STR_FIELD(p->ast, cc->type_comptime_call.name, name); cc->type_comptime_call.args = args; return ref; } static spl_ast_node_ref_t parse_type_expr(parser_t *p) { const spl_tok_t *t = peek(p); if (!t) { SPL_FATAL(t, "expected type"); return 0; } if (t->type == TOK_MUL) { advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_POINTER, t); spl_ast_node_ref_t pointee = parse_type_expr(p); node_at(p->ast, ref)->type_pointer.pointee = pointee; return ref; } if (t->type == TOK_L_BRACKET) { advance(p); bool has_len = false; isize len = 0; bool is_underscore = false; t = peek(p); if (t && t->type == TOK_INT_LITERAL) { len = parse_int_literal(t); has_len = true; advance(p); } else if (t && t->type == KW_UNDERSCORE) { has_len = true; is_underscore = true; advance(p); } t = peek(p); if (!t || t->type != TOK_R_BRACKET) { SPL_FATAL(t, "expected ']' in array type"); return 0; } advance(p); spl_ast_node_ref_t elem_type = parse_type_expr(p); spl_ast_node_ref_t ref; if (has_len) { ref = new_node(p, SPL_AST_TYPE_ARRAY, t); spl_ast_node_t *arr = node_at(p->ast, ref); arr->type_array.has_len = true; arr->type_array.len = len; arr->type_array.is_underscore_len = is_underscore; arr->type_array.elem_type = elem_type; } else { ref = new_node(p, SPL_AST_TYPE_SLICE, t); node_at(p->ast, ref)->type_slice.elem_type = elem_type; } return ref; } if (t->type == TOK_L_PAREN) { advance(p); spl_ast_node_ref_vec_t types; vec_init(types); if (peek(p) && peek(p)->type == TOK_R_PAREN) { advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_PAREN, t); node_at(p->ast, ref)->type_paren.types = types; return ref; } spl_ast_node_ref_t first = parse_type_expr(p); vec_push(types, first); while (peek(p) && peek(p)->type == TOK_COMMA) { advance(p); if (peek(p) && peek(p)->type == TOK_R_PAREN) break; spl_ast_node_ref_t next = parse_type_expr(p); vec_push(types, next); } t = peek(p); if (!t || t->type != TOK_R_PAREN) { SPL_FATAL(t, "expected ')' in parenthesized type"); return 0; } advance(p); if (types.size == 1) { vec_free(types); return first; } spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_PAREN, t); node_at(p->ast, ref)->type_paren.types = types; return ref; } return parse_type_base(p); } 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; const 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; } static spl_ast_node_ref_vec_t parse_aggregate_fields(parser_t *p) { spl_ast_node_ref_vec_t fields; vec_init(fields); const spl_tok_t *t = peek(p); if (!t || t->type != TOK_L_BRACE) { SPL_FATAL(t, "expected '{' in aggregate literal"); return fields; // 空 vec,调用者处理 } advance(p); // 消费 '{' while (!p->failed) { t = peek(p); if (!t || t->type == TOK_R_BRACE || t->type == TOK_EOF) break; // 字段必须由 '.' 开头 if (t->type != TOK_DOT) { SPL_FATAL(t, "expected '.' in aggregate field initializer"); break; } advance(p); t = peek(p); if (!t || t->type != TOK_IDENT) { SPL_FATAL(t, "expected field name after '.'"); break; } advance(p); // 创建 struct_init_item 节点 spl_ast_node_ref_t item_ref = new_node(p, SPL_AST_STRUCT_INIT_ITEM, t); spl_ast_node_t *item = node_at(p->ast, item_ref); SET_STR_FIELD(p->ast, item->struct_init_item.name, t); item->struct_init_item.expr = 0; // 可选:= 表达式 if (peek(p) && peek(p)->type == TOK_ASSIGN) { advance(p); spl_ast_node_ref_t expr_ref = parse_expr(p); item = node_at(p->ast, item_ref); // 重新获取,防扩容 item->struct_init_item.expr = expr_ref; } vec_push(fields, item_ref); // 分隔符 t = peek(p); if (t && (t->type == TOK_COMMA || t->type == TOK_SEMICOLON)) { advance(p); continue; } break; } t = peek(p); if (!t || t->type != TOK_R_BRACE) { SPL_FATAL(t, "expected '}' in aggregate literal"); } else { advance(p); // 消费 '}' } return fields; } typedef struct { int prec; char assoc; // 'L', 'R', 'N' } op_info_t; static op_info_t binary_op_info[] = { #define X(name, prec, assoc, str) {prec, assoc}, SPL_BINARY_OP_TABLE #undef X }; static spl_binary_op_t token_to_binary_op(spl_tok_type_t tt) { switch (tt) { case TOK_ASSIGN: return SPL_OP_ASSIGN; case TOK_ASSIGN_ADD: return SPL_OP_ASSIGN_ADD; case TOK_ASSIGN_SUB: return SPL_OP_ASSIGN_SUB; case TOK_ASSIGN_MUL: return SPL_OP_ASSIGN_MUL; case TOK_ASSIGN_DIV: return SPL_OP_ASSIGN_DIV; case TOK_ASSIGN_MOD: return SPL_OP_ASSIGN_MOD; case TOK_ASSIGN_AND: return SPL_OP_ASSIGN_AND; case TOK_ASSIGN_OR: return SPL_OP_ASSIGN_OR; case TOK_ASSIGN_XOR: return SPL_OP_ASSIGN_XOR; case TOK_ASSIGN_L_SH: return SPL_OP_ASSIGN_LSHIFT; case TOK_ASSIGN_R_SH: return SPL_OP_ASSIGN_RSHIFT; case TOK_OR_OR: return SPL_OP_BOOL_OR; case TOK_AND_AND: return SPL_OP_BOOL_AND; case TOK_OR: return SPL_OP_BIT_OR; case TOK_XOR: return SPL_OP_BIT_XOR; case TOK_AND: return SPL_OP_BIT_AND; case TOK_EQ: return SPL_OP_CMP_EQ; case TOK_NEQ: return SPL_OP_CMP_NE; case TOK_LE: return SPL_OP_CMP_LE; case TOK_GE: return SPL_OP_CMP_GE; case TOK_LT: return SPL_OP_CMP_LT; case TOK_GT: return SPL_OP_CMP_GT; case TOK_LEFT_ARROW: return SPL_OP_ARROW_LEFT; case TOK_RIGHT_ARROW: return SPL_OP_ARROW_RIGHT; case TOK_FAT_ARROW_BOTH: return SPL_OP_ARROW_FAT_BOTH; case TOK_ARROW_BOTH: return SPL_OP_ARROW_THIN_BOTH; case TOK_RIGHT_FAT_ARROW: return SPL_OP_ARROW_FAT_RIGHT; case TOK_RANGE: return SPL_OP_RANGE; case TOK_L_SH: return SPL_OP_LSHIFT; case TOK_R_SH: return SPL_OP_RSHIFT; case TOK_ADD: return SPL_OP_ADD; case TOK_SUB: return SPL_OP_SUB; case TOK_MUL: return SPL_OP_MUL; case TOK_DIV: return SPL_OP_DIV; case TOK_MOD: return SPL_OP_MOD; default: return (spl_binary_op_t)-1; // 无效 } } static spl_ast_node_ref_t parse_expr_prec(parser_t *p, int min_prec) { spl_ast_node_ref_t left = parse_prefix(p); if (p->failed) return left; while (!p->failed) { const spl_tok_t *t = peek(p); if (!t) break; spl_binary_op_t op = token_to_binary_op(t->type); if (op == (spl_binary_op_t)-1) break; op_info_t info = binary_op_info[op]; if (info.prec < min_prec) break; advance(p); if (op == SPL_OP_RANGE) { spl_ast_node_ref_t right = 0; if (peek(p) && can_start_expr(peek(p)->type)) right = parse_expr_prec(p, info.prec + 1); // 最小优先级 = range 优先级 + 1 left = mk_bin(p, t, op, left, right); continue; } int next_min = info.prec; if (info.assoc == 'R') { next_min = info.prec; } else { next_min = info.prec + 1; } spl_ast_node_ref_t right = parse_expr_prec(p, next_min); left = mk_bin(p, t, op, left, right); } return left; } static spl_ast_node_ref_t parse_expr(parser_t *p) { return parse_expr_prec(p, 1); // 最低优先级 } static spl_ast_node_ref_t parse_prefix(parser_t *p) { const spl_tok_t *t = peek(p); if (!t) return 0; spl_unary_op_t uop; switch (t->type) { case TOK_SUB: uop = SPL_UNARY_OP_MINUS; break; case TOK_NOT: uop = SPL_UNARY_OP_NOT; break; case TOK_BIT_NOT: uop = SPL_UNARY_OP_BIT_NOT; break; case TOK_AND: uop = SPL_UNARY_OP_ADDRESS; break; default: return parse_postfix(p); } advance(p); spl_ast_node_ref_t operand = parse_prefix(p); return mk_unary(p, t, uop, operand); } static spl_ast_node_ref_t parse_postfix(parser_t *p) { spl_ast_node_ref_t expr = parse_primary(p); while (!p->failed) { const spl_tok_t *t = peek(p); if (!t) break; if (t->type == TOK_L_PAREN) { advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_CALL, t); node_at(p->ast, ref)->call.callee = expr; spl_ast_node_ref_vec_t args = parse_expr_list(p); node_at(p->ast, ref)->call.args = args; t = peek(p); if (!t || t->type != TOK_R_PAREN) { SPL_FATAL(t, "expected ')' in call"); return expr; } advance(p); expr = ref; } else if (t->type == TOK_DOT) { advance(p); const spl_tok_t *next = peek(p); if (!next) break; if (next->type == TOK_IDENT) { advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_FIELD, t); node_at(p->ast, ref)->field.obj = expr; SET_STR_FIELD(p->ast, node_at(p->ast, ref)->field.field, next); expr = ref; } else if (next->type == TOK_MUL) { advance(p); spl_ast_node_ref_t ref = mk_unary(p, t, SPL_UNARY_OP_ADDRESS, expr); expr = ref; } else { SPL_FATAL(next, "expected identifier or '*' after '.'"); break; } } else if (t->type == TOK_L_BRACKET) { advance(p); int range_prec = binary_op_info[SPL_OP_RANGE].prec; spl_ast_node_ref_t begin = parse_expr_prec(p, range_prec + 1); 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); t = peek(p); if (!t || t->type != TOK_R_BRACKET) { SPL_FATAL(t, "expected ']' in slice"); return expr; } advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_SLICE, t); node_at(p->ast, ref)->slice.obj = expr; node_at(p->ast, ref)->slice.begin = begin; node_at(p->ast, ref)->slice.end = end; expr = ref; } else { t = peek(p); if (!t || t->type != TOK_R_BRACKET) { SPL_FATAL(t, "expected ']' in index"); return expr; } advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_INDEX, t); node_at(p->ast, ref)->index.obj = expr; node_at(p->ast, ref)->index.index = begin; expr = ref; } } else if (t->type == KW_AS && !p->stop_as) { advance(p); spl_ast_node_ref_t type = parse_type_expr(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_CAST, t); node_at(p->ast, ref)->cast.expr = expr; node_at(p->ast, ref)->cast.type = type; expr = ref; } else { break; } } return expr; } static spl_ast_node_ref_t parse_primary(parser_t *p) { const spl_tok_t *t = peek(p); if (!t) { SPL_FATAL(t, "unexpected end of expression"); return 0; } switch (t->type) { case TOK_INT_LITERAL: { advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_INT_LIT, t); node_at(p->ast, ref)->int_lit.val = parse_int_literal(t); return ref; } case TOK_FLOAT_LITERAL: { advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_FLOAT_LIT, t); node_at(p->ast, ref)->float_lit.val = parse_float_literal(t); return ref; } case TOK_CHAR_LITERAL: { advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_CHAR_LIT, t); node_at(p->ast, ref)->char_lit.val = parse_char_literal(t); return ref; } case TOK_STRING_LITERAL: { advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_STRING_LIT, t); node_at(p->ast, ref)->string_lit.data = parse_string_literal(p, t); return ref; } case KW_TRUE: case KW_FALSE: { advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_BOOL_LIT, t); node_at(p->ast, ref)->bool_lit.val = (t->type == KW_TRUE); return ref; } case KW_NULL: { advance(p); return new_node(p, SPL_AST_EXPR_NULL_LIT, t); } case KW_UNDEFINED: { advance(p); return new_node(p, SPL_AST_EXPR_UNDEFINED_LIT, t); } case TOK_IDENT: { advance(p); if (peek(p) && peek(p)->type == TOK_L_BRACE && !p->stop_agg) { spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_AGGREGATE_LIT, t); spl_ast_node_t *agg = node_at(p->ast, ref); agg->aggregate_literal.name = intern_string(p->ast, t->lexeme, t->len); spl_ast_node_ref_vec_t fields = parse_aggregate_fields(p); node_at(p->ast, ref)->aggregate_literal.fields = fields; return ref; } /* 普通标识符 */ spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_IDENT, t); node_at(p->ast, ref)->ident.name = intern_string(p->ast, t->lexeme, t->len); return ref; } case TOK_DOT: { advance(p); const spl_tok_t *nx = peek(p); if (!nx) { SPL_FATAL(t, "unexpected '.'"); return 0; } if (nx->type == TOK_L_BRACE && !p->stop_agg) { spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_AGGREGATE_LIT, t); node_at(p->ast, ref)->aggregate_literal.name = NULL; spl_ast_node_ref_vec_t fields = parse_aggregate_fields(p); node_at(p->ast, ref)->aggregate_literal.fields = fields; return ref; } else if (nx->type == TOK_L_BRACKET) { // 匿名数组字面量:. [ elems ] advance(p); // 消费 '[' // 先解析元素列表,避免节点扩容导致 arr 指针失效 spl_ast_node_ref_vec_t elems = parse_expr_list(p); const spl_tok_t *close = peek(p); if (!close || close->type != TOK_R_BRACKET) { SPL_FATAL(close, "expected ']'"); return 0; } advance(p); // 消费 ']' spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_ARRAY_LIT, t); spl_ast_node_t *arr = node_at(p->ast, ref); arr->array_literal.elems = elems; arr->array_literal.elem_type = 0; return ref; } else { SPL_FATAL(nx, "expected '{' or '[' after '.'"); return 0; } } case TOK_L_BRACKET: return parse_array_literal(p); case TOK_L_BRACE: return parse_block(p); case TOK_AT: case TOK_SHARP: return parse_comptime_call(p); case TOK_L_PAREN: { advance(p); spl_ast_node_ref_vec_t elems; vec_init(elems); if (peek(p) && peek(p)->type == TOK_R_PAREN) { advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_TUPLE, t); node_at(p->ast, ref)->tuple.elems = elems; return ref; } spl_ast_node_ref_t first = parse_expr(p); if (peek(p) && peek(p)->type == TOK_COMMA) { vec_push(elems, first); while (peek(p) && peek(p)->type == TOK_COMMA) { advance(p); if (peek(p) && peek(p)->type == TOK_R_PAREN) break; vec_push(elems, parse_expr(p)); } t = peek(p); if (!t || t->type != TOK_R_PAREN) { SPL_FATAL(t, "expected ')'"); return 0; } advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_TUPLE, t); node_at(p->ast, ref)->tuple.elems = elems; return ref; } else { t = peek(p); if (!t || t->type != TOK_R_PAREN) { SPL_FATAL(t, "expected ')'"); return 0; } advance(p); vec_free(elems); return first; } } case KW_IF: return parse_if_expr(p); case KW_WHILE: return parse_while_expr(p); case KW_LOOP: return parse_loop_expr(p); case KW_FOR: return parse_for_expr(p); case KW_MATCH: return parse_match_expr(p); default: SPL_FATAL(t, "unrecognized expression"); return 0; } } static spl_ast_node_ref_t parse_array_literal(parser_t *p) { const spl_tok_t *start = peek(p); if (!start || start->type != TOK_L_BRACKET) return 0; advance(p); bool has_len = false; isize len = 0; bool is_underscore = false; const spl_tok_t *t = peek(p); if (t && t->type == TOK_INT_LITERAL) { len = parse_int_literal(t); has_len = true; advance(p); } else if (t && t->type == KW_UNDERSCORE) { has_len = true; is_underscore = true; advance(p); } t = peek(p); if (!t || t->type != TOK_R_BRACKET) { SPL_FATAL(t, "expected ']' in array literal"); return 0; } advance(p); spl_ast_node_ref_t elem_type = parse_type_expr(p); t = peek(p); if (!t || t->type != TOK_L_BRACKET) { SPL_FATAL(t, "expected '[' in array literal"); return 0; } advance(p); spl_ast_node_ref_vec_t elems = parse_expr_list(p); t = peek(p); if (!t || t->type != TOK_R_BRACKET) { SPL_FATAL(t, "expected ']' in array literal"); return 0; } advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_ARRAY_LIT, start); spl_ast_node_t *arr = node_at(p->ast, ref); arr->array_literal.has_len = has_len; arr->array_literal.len = len; arr->array_literal.is_underscore_len = is_underscore; arr->array_literal.elem_type = elem_type; arr->array_literal.elems = elems; // elems 是局部 vec,直接转移 return ref; } static spl_ast_node_ref_t parse_comptime_call(parser_t *p) { const spl_tok_t *start = peek(p); if (!start || (start->type != TOK_AT && start->type != TOK_SHARP)) return 0; advance(p); const spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { SPL_FATAL(name, "expected comptime call name"); return 0; } advance(p); const spl_tok_t *t = peek(p); if (!t || t->type != TOK_L_PAREN) { SPL_FATAL(t, "expected '(' in comptime call"); return 0; } advance(p); spl_ast_node_ref_vec_t args = parse_expr_list(p); t = peek(p); if (!t || t->type != TOK_R_PAREN) { SPL_FATAL(t, "expected ')' in comptime call"); return 0; } advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_COMPTIME_CALL, start); spl_ast_node_t *cc = node_at(p->ast, ref); SET_STR_FIELD(p->ast, cc->comptime_call.name, name); cc->comptime_call.args = args; return ref; } static spl_ast_node_ref_t parse_label(parser_t *p) { const spl_tok_t *t = peek(p); if (!t || t->type != TOK_DOLLAR) return 0; advance(p); const spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { SPL_FATAL(name, "expected identifier after '$'"); return 0; } advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_LABEL, t); SET_STR_FIELD(p->ast, node_at(p->ast, ref)->label.name, name); return ref; } static spl_ast_node_ref_t parse_if_expr(parser_t *p) { const spl_tok_t *kw = peek(p); if (!kw || kw->type != KW_IF) return 0; advance(p); int is_ifvar = 0; spl_ast_node_ref_t var_decl = 0; const spl_tok_t *t = peek(p); if (t && t->type == KW_VAR) { advance(p); is_ifvar = 1; spl_ast_node_ref_t pattern = parse_var_pattern(p); if (!pattern) return 0; spl_ast_node_ref_t type_expr = 0; spl_ast_node_ref_t init_expr = 0; t = peek(p); if (t && t->type == TOK_COLON) { advance(p); type_expr = parse_type_expr(p); t = peek(p); if (t && t->type == TOK_ASSIGN) { advance(p); init_expr = parse_expr(p); } else { SPL_FATAL(t, "expected '=' in if var"); return 0; } } else if (t && t->type == TOK_ASSIGN) { advance(p); init_expr = parse_expr(p); } else { SPL_FATAL(t, "expected type annotation or '=' in if var"); return 0; } var_decl = new_node(p, SPL_AST_VAR_DECL, kw); spl_ast_node_t *vd = node_at(p->ast, var_decl); vd->var_const_decl.pattern = pattern; vd->var_const_decl.type = type_expr; vd->var_const_decl.init_expr = init_expr; } else { p->stop_agg++; spl_ast_node_ref_t cond = parse_expr(p); p->stop_agg--; if (!cond) return 0; var_decl = cond; } spl_ast_node_ref_t then_block = parse_block(p); if (!then_block) return 0; spl_ast_node_ref_t else_branch = 0; t = peek(p); if (t && t->type == KW_ELSE) { advance(p); t = peek(p); if (t && t->type == KW_IF) { else_branch = parse_if_expr(p); } else { else_branch = parse_block(p); } } spl_ast_node_ref_t ref; if (is_ifvar) { ref = new_node(p, SPL_AST_EXPR_IFVAR, kw); node_at(p->ast, ref)->ifvar_expr.var_decl = var_decl; node_at(p->ast, ref)->ifvar_expr.then_block = then_block; node_at(p->ast, ref)->ifvar_expr.else_branch = else_branch; } else { ref = new_node(p, SPL_AST_EXPR_IF, kw); node_at(p->ast, ref)->if_expr.cond = var_decl; node_at(p->ast, ref)->if_expr.then_block = then_block; node_at(p->ast, ref)->if_expr.else_branch = else_branch; } return ref; } static spl_ast_node_ref_t parse_while_expr(parser_t *p) { const spl_tok_t *kw = peek(p); if (!kw || kw->type != KW_WHILE) return 0; advance(p); spl_ast_node_ref_t label = parse_label(p); p->stop_agg++; spl_ast_node_ref_t cond = parse_expr(p); p->stop_agg--; if (!cond) return 0; spl_ast_node_ref_t body = parse_block(p); if (!body) return 0; spl_ast_node_ref_t else_branch = 0; if (peek(p) && peek(p)->type == KW_ELSE) { advance(p); if (peek(p) && peek(p)->type == TOK_L_BRACE) else_branch = parse_block(p); else else_branch = parse_expr(p); } spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_WHILE, kw); node_at(p->ast, ref)->while_expr.label = label; node_at(p->ast, ref)->while_expr.cond = cond; node_at(p->ast, ref)->while_expr.body = body; node_at(p->ast, ref)->while_expr.else_branch = else_branch; return ref; } static spl_ast_node_ref_t parse_loop_expr(parser_t *p) { const spl_tok_t *kw = peek(p); if (!kw || kw->type != KW_LOOP) return 0; advance(p); spl_ast_node_ref_t label = parse_label(p); spl_ast_node_ref_t body = parse_block(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_LOOP, kw); node_at(p->ast, ref)->loop_expr.label = label; node_at(p->ast, ref)->loop_expr.body = body; return ref; } static spl_ast_node_ref_t parse_for_expr(parser_t *p) { const spl_tok_t *kw = peek(p); if (!kw || kw->type != KW_FOR) return 0; advance(p); spl_ast_node_ref_t label = parse_label(p); // 解析迭代表达式列表(用 stop_as 阻止 'as' 被误解析为类型转换) p->stop_as = 1; spl_ast_node_ref_vec_t iter_exprs; vec_init(iter_exprs); vec_push(iter_exprs, parse_expr(p)); while (peek(p) && peek(p)->type == TOK_COMMA) { advance(p); vec_push(iter_exprs, parse_expr(p)); } p->stop_as = 0; // 必须有关键字 as const spl_tok_t *t = peek(p); if (!t || t->type != KW_AS) { SPL_FATAL(t, "expected 'as' in for loop"); return 0; } advance(p); // 解析绑定变量列表(允许 '_') spl_ast_node_ref_vec_t idents; vec_init(idents); t = peek(p); if (!t || (t->type != TOK_IDENT && t->type != KW_UNDERSCORE)) { SPL_FATAL(t, "expected binding variable or '_' in for"); return 0; } advance(p); spl_ast_node_ref_t id_node = new_node(p, SPL_AST_EXPR_IDENT, t); SET_STR_FIELD(p->ast, node_at(p->ast, id_node)->ident.name, t); vec_push(idents, id_node); while (peek(p) && peek(p)->type == TOK_COMMA) { advance(p); t = peek(p); if (!t || (t->type != TOK_IDENT && t->type != KW_UNDERSCORE)) { SPL_FATAL(t, "expected binding variable or '_' in for"); return 0; } advance(p); id_node = new_node(p, SPL_AST_EXPR_IDENT, t); SET_STR_FIELD(p->ast, node_at(p->ast, id_node)->ident.name, t); vec_push(idents, id_node); } // 循环体必须为块 spl_ast_node_ref_t body = parse_block(p); if (!body) return 0; // 可选的 else 分支 spl_ast_node_ref_t else_branch = 0; if (peek(p) && peek(p)->type == KW_ELSE) { advance(p); if (peek(p) && peek(p)->type == TOK_L_BRACE) else_branch = parse_block(p); else else_branch = parse_expr(p); } spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_FOR, kw); spl_ast_node_t *fe = node_at(p->ast, ref); fe->for_expr.label = label; fe->for_expr.iter_exprs = iter_exprs; fe->for_expr.idents = idents; fe->for_expr.body = body; fe->for_expr.else_branch = else_branch; return ref; } static int parse_match_arm(parser_t *p, spl_ast_node_ref_vec_t *patterns_out, spl_ast_node_ref_vec_t *bodies_out) { spl_ast_node_ref_vec_t pats; vec_init(pats); while (!p->failed) { spl_ast_node_ref_t pat = parse_match_pattern(p); if (!pat) break; vec_push(pats, pat); if (peek(p) && peek(p)->type == TOK_COMMA) { advance(p); continue; } break; } const spl_tok_t *t = peek(p); if (!t || t->type != TOK_RIGHT_FAT_ARROW) { SPL_FATAL(t, "expected '=>' in match arm"); return 0; } advance(p); spl_ast_node_ref_t body; t = peek(p); if (!t || t->type != TOK_L_BRACE) { SPL_FATAL(t, "expected block after '=>' in match arm"); return 0; } body = parse_block(p); for (usize i = 0; i < pats.size; i++) { vec_push(*patterns_out, pats.data[i]); vec_push(*bodies_out, body); } vec_free(pats); return 1; } static spl_ast_node_ref_t parse_match_expr(parser_t *p) { const spl_tok_t *kw = peek(p); if (!kw || kw->type != KW_MATCH) return 0; advance(p); p->stop_agg++; spl_ast_node_ref_t matched_expr = parse_expr(p); p->stop_agg--; const spl_tok_t *t = peek(p); if (!t || t->type != TOK_L_BRACE) { SPL_FATAL(t, "expected '{' in match"); return 0; } advance(p); spl_ast_node_ref_vec_t patterns, bodies; vec_init(patterns); vec_init(bodies); while (!p->failed) { t = peek(p); if (!t || t->type == TOK_R_BRACE || t->type == TOK_EOF) break; if (!parse_match_arm(p, &patterns, &bodies)) break; if (peek(p) && peek(p)->type == TOK_COMMA) advance(p); } t = peek(p); if (!t || t->type != TOK_R_BRACE) { SPL_FATAL(t, "expected '}' in match"); return 0; } advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_MATCH, kw); spl_ast_node_t *me = node_at(p->ast, ref); me->match_expr.matched_expr = matched_expr; vec_init(me->match_expr.arms); for (usize i = 0; i < patterns.size; i++) { spl_ast_node_ref_t arm = new_node(p, SPL_AST_MATCH_ARM, NULL); spl_ast_node_t *arm_node = node_at(p->ast, arm); arm_node->match_arm.pattern = patterns.data[i]; arm_node->match_arm.body = bodies.data[i]; me = node_at(p->ast, ref); /* 每次迭代重新获取 防止 new_node 扩容 */ vec_push(me->match_expr.arms, arm); } vec_free(patterns); vec_free(bodies); return ref; } static spl_ast_node_ref_t parse_ret_stmt(parser_t *p) { const spl_tok_t *kw = peek(p); if (!kw || kw->type != KW_RET) return 0; advance(p); spl_ast_node_ref_t expr = 0; const spl_tok_t *t = peek(p); if (t && can_start_expr(t->type)) expr = parse_expr(p); t = peek(p); if (t && t->type == TOK_SEMICOLON) advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_STATEMENT_RET, kw); node_at(p->ast, ref)->statement_ret.expr = expr; return ref; } static spl_ast_node_ref_t parse_break_stmt(parser_t *p) { const spl_tok_t *kw = peek(p); if (!kw || kw->type != KW_BREAK) return 0; advance(p); spl_ast_node_ref_t label = parse_label(p); spl_ast_node_ref_t expr = 0; const spl_tok_t *t = peek(p); if (t && can_start_expr(t->type)) expr = parse_expr(p); t = peek(p); if (t && t->type == TOK_SEMICOLON) advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_STATEMENT_BREAK, kw); node_at(p->ast, ref)->statement_break.label = label; node_at(p->ast, ref)->statement_break.expr = expr; return ref; } static spl_ast_node_ref_t parse_continue_stmt(parser_t *p) { const spl_tok_t *kw = peek(p); if (!kw || kw->type != KW_CONTINUE) return 0; advance(p); spl_ast_node_ref_t label = parse_label(p); const spl_tok_t *t = peek(p); if (t && t->type == TOK_SEMICOLON) advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_STATEMENT_CONTINUE, kw); node_at(p->ast, ref)->statement_continue.label = label; return ref; } static spl_ast_node_ref_t parse_defer_stmt(parser_t *p) { const spl_tok_t *kw = peek(p); if (!kw || kw->type != KW_DEFER) return 0; advance(p); spl_ast_node_ref_t body = 0; const spl_tok_t *t = peek(p); if (t && t->type == TOK_L_BRACE) { body = parse_block(p); } else if (t && can_start_statement(t->type)) { body = parse_statement(p); } else { body = parse_expr(p); t = peek(p); if (t && t->type == TOK_SEMICOLON) advance(p); } spl_ast_node_ref_t ref = new_node(p, SPL_AST_STATEMENT_DEFER, kw); node_at(p->ast, ref)->statement_defer.body = body; return ref; } static spl_ast_node_ref_t parse_comptime_stmt(parser_t *p) { const spl_tok_t *kw = peek(p); if (!kw || kw->type != KW_COMPTIME) return 0; advance(p); spl_ast_node_ref_t body = 0; const spl_tok_t *t = peek(p); if (t && t->type == TOK_L_BRACE) { body = parse_block(p); } else { body = parse_expr(p); } spl_ast_node_ref_t ref = new_node(p, SPL_AST_STATEMENT_COMPTIME, kw); node_at(p->ast, ref)->statement_comptime.body = body; return ref; } static spl_ast_node_ref_t parse_statement(parser_t *p) { const spl_tok_t *t = peek(p); if (!t) return 0; switch (t->type) { case KW_RET: return parse_ret_stmt(p); case KW_BREAK: return parse_break_stmt(p); case KW_CONTINUE: return parse_continue_stmt(p); case KW_DEFER: return parse_defer_stmt(p); case KW_COMPTIME: return parse_comptime_stmt(p); case KW_VAR: case KW_CONST: case KW_TYPE: { spl_ast_node_ref_vec_t tag_list; vec_init(tag_list); parse_tag_list(p, &tag_list, 0); // 解析声明前的普通 tag spl_ast_node_ref_t decl; if (t->type == KW_VAR) decl = parse_var_const_decl(p, tag_list, 0); else if (t->type == KW_CONST) decl = parse_var_const_decl(p, tag_list, 1); else decl = parse_type_decl(p, tag_list); /* 不再 vec_free(tag_list),所有权已转移 */ if (!decl) return 0; spl_ast_node_ref_t ref = new_node(p, SPL_AST_STATEMENT_DECL, t); node_at(p->ast, ref)->statement_decl.decl = decl; return ref; } default: { if (can_start_expr(t->type)) { spl_ast_node_ref_t expr = parse_expr(p); if (!expr) return 0; spl_ast_node_ref_t ref = new_node(p, SPL_AST_STATEMENT_EXPR, t); node_at(p->ast, ref)->statement_expr.expr = expr; return ref; } else { SPL_FATAL(t, "unrecognized statement"); return 0; } } } } static spl_ast_node_ref_t parse_block(parser_t *p) { const spl_tok_t *start = peek(p); if (!start || start->type != TOK_L_BRACE) { SPL_FATAL(start, "expected '{'"); return 0; } advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_BLOCK, start); spl_ast_node_t *block = node_at(p->ast, ref); vec_init(block->block.stmts); block->block.tail_expr = 0; while (!p->failed) { const spl_tok_t *t = peek(p); if (!t || t->type == TOK_EOF) { SPL_FATAL(t, "block missing '}'"); return ref; } if (t->type == TOK_R_BRACE) { advance(p); break; } if (can_start_statement(t->type)) { spl_ast_node_ref_t stmt = parse_statement(p); block = node_at(p->ast, ref); if (stmt) vec_push(block->block.stmts, stmt); } else if (can_start_expr(t->type)) { spl_ast_node_ref_t expr = parse_expr(p); block = node_at(p->ast, ref); t = peek(p); if (t && t->type == TOK_SEMICOLON) { advance(p); vec_push(block->block.stmts, expr); } else if (t && t->type == TOK_R_BRACE) { if (block->block.tail_expr != 0) { SPL_FATAL(t, "only one tail expression allowed"); } block->block.tail_expr = expr; } else if (expr && node_at(p->ast, expr)->kind == SPL_AST_EXPR_BLOCK) { vec_push(block->block.stmts, expr); // 继续循环,处理下一个语句 } else { SPL_FATAL(t, "expected ';' or '}' after expression"); break; } } else { SPL_FATAL(t, "unrecognized token in block"); break; } } return ref; } void spl_ast_init(spl_ast_t *ast, const spl_tok_vec_t *tok_vec) { ast->input = *tok_vec; vec_init(ast->node_buckets); vec_init(ast->str_buckets); ast->root = 0; ast->parsed = 0; spl_ast_node_t n = {0}; vec_push(ast->node_buckets, n); } void spl_ast_parse(spl_ast_t *ast) { if (!ast || !ast->input.data || ast->node_buckets.size == 0) return; parser_t p; p.ast = ast; p.pos = 0; p.failed = 0; p.stop_as = 0; p.stop_agg = 0; ast->parsed = 0; spl_ast_node_ref_vec_t external_tags; vec_init(external_tags); spl_ast_node_ref_vec_t declarations; vec_init(declarations); while (!p.failed) { const spl_tok_t *t = peek(&p); if (!t || t->type == TOK_EOF) break; if (t->type == TOK_AT || t->type == TOK_SHARP) { usize save_pos = p.pos; const spl_tok_t *t2 = NULL; if (t) { p.pos++; t2 = peek(&p); p.pos = save_pos; } if (t2 && t2->type == TOK_NOT) { parse_tag_list(&p, &external_tags, 1); continue; } } spl_ast_node_ref_t decl = parse_container_declaration(&p); if (decl) vec_push(declarations, decl); } spl_ast_node_ref_t container_members = new_node(&p, SPL_AST_CONTAINER_MEMBERS, NULL); spl_ast_node_t *cm = node_at(ast, container_members); cm->container_members.external_tags = external_tags; cm->container_members.declarations = declarations; spl_ast_node_ref_t root = new_node(&p, SPL_AST_ROOT, NULL); node_at(ast, root)->root.members = container_members; ast->root = root; ast->parsed = p.failed ? -1 : 1; } void spl_ast_drop(spl_ast_t *ast) { if (!ast) return; vec_for(ast->str_buckets, idx) { free(vec_at(ast->str_buckets, idx)); } vec_free(ast->str_buckets); vec_free(ast->node_buckets); vec_free(ast->input); ast->parsed = 0; ast->root = 0; } spl_ast_node_t *spl_ast_node(spl_ast_t *ast, spl_ast_node_ref_t node) { if (!ast || node == 0 || node >= ast->node_buckets.size) return NULL; return &ast->node_buckets.data[node]; } 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; } /* TODO */ } typedef VEC(char) dump_stack_t; static void dump_node(spl_ast_t *ast, spl_ast_node_ref_t node_ref, dump_stack_t *stack, bool last); void spl_ast_dump(spl_ast_t *ast, spl_ast_node_ref_t node) { if (!ast || !node || node >= ast->node_buckets.size) return; dump_stack_t stack; vec_init(stack); printf("AST:\n"); dump_node(ast, node, &stack, true); vec_free(stack); } #define dump_vec(_ast, _vec, _stack) \ do { \ vec_for(_vec, _i) { dump_node(_ast, vec_at(_vec, _i), _stack, _i + 1 == vec_size(_vec)); } \ } while (0) static void dump_node(spl_ast_t *ast, spl_ast_node_ref_t node_ref, dump_stack_t *stack, bool last) { spl_ast_node_t *node = &ast->node_buckets.data[node_ref]; for (usize i = 0; i < vec_size(*stack); i++) printf("%s", vec_at(*stack, i) ? " " : "| "); printf("%s%s #%zu", last ? "`-" : "|-", spl_ast_kind_name(node->kind), node_ref); if (node->dbg.fname) printf(" [%d:%d]", node->dbg.line, node->dbg.col); printf("\n"); vec_push(*stack, last); switch (node->kind) { case SPL_AST_ROOT: if (node->root.members) dump_node(ast, node->root.members, stack, true); break; case SPL_AST_CONTAINER_MEMBERS: dump_vec(ast, node->container_members.external_tags, stack); dump_vec(ast, node->container_members.declarations, stack); break; case SPL_AST_TAG_ITEM: case SPL_AST_EXTERNAL_TAG_ITEM: dump_vec(ast, node->tag_item.args, stack); break; case SPL_AST_FN_DECL: dump_vec(ast, node->fn_decl.tag_list, stack); dump_vec(ast, node->fn_decl.params, stack); if (node->fn_decl.ret_type) dump_node(ast, node->fn_decl.ret_type, stack, false); if (node->fn_decl.body) dump_node(ast, node->fn_decl.body, stack, true); break; case SPL_AST_VAR_DECL: case SPL_AST_CONST_DECL: dump_vec(ast, node->var_const_decl.attr_list, stack); if (node->var_const_decl.pattern) dump_node(ast, node->var_const_decl.pattern, stack, false); if (node->var_const_decl.type) dump_node(ast, node->var_const_decl.type, stack, false); if (node->var_const_decl.init_expr) dump_node(ast, node->var_const_decl.init_expr, stack, true); break; case SPL_AST_TYPE_DECL: if (node->type_decl.type_expr) dump_node(ast, node->type_decl.type_expr, stack, true); break; case SPL_AST_MEMBER_DECL: dump_vec(ast, node->member_decl.attr_list, stack); if (node->member_decl.type_expr) dump_node(ast, node->member_decl.type_expr, stack, false); if (node->member_decl.init_expr) dump_node(ast, node->member_decl.init_expr, stack, true); break; case SPL_AST_PARAM_DECL: dump_vec(ast, node->param_decl.attr_list, stack); if (node->param_decl.type_expr) dump_node(ast, node->param_decl.type_expr, stack, true); break; case SPL_AST_COMPTIME_DECL: if (node->comptime_decl.body) dump_node(ast, node->comptime_decl.body, stack, true); break; case SPL_AST_TOP_LEVEL_BLOCK: dump_vec(ast, node->top_level_block.tag_list, stack); if (node->top_level_block.block) dump_node(ast, node->top_level_block.block, stack, true); break; case SPL_AST_STATEMENT_RET: if (node->statement_ret.expr) dump_node(ast, node->statement_ret.expr, stack, true); break; case SPL_AST_STATEMENT_BREAK: if (node->statement_break.label) dump_node(ast, node->statement_break.label, stack, false); if (node->statement_break.expr) dump_node(ast, node->statement_break.expr, stack, true); break; case SPL_AST_STATEMENT_CONTINUE: if (node->statement_continue.label) dump_node(ast, node->statement_continue.label, stack, true); break; case SPL_AST_STATEMENT_DEFER: case SPL_AST_STATEMENT_COMPTIME: if (node->statement_defer.body) dump_node(ast, node->statement_defer.body, stack, true); break; case SPL_AST_STATEMENT_DECL: if (node->statement_decl.decl) dump_node(ast, node->statement_decl.decl, stack, true); break; case SPL_AST_STATEMENT_EXPR: if (node->statement_expr.expr) dump_node(ast, node->statement_expr.expr, stack, true); break; case SPL_AST_AGGREGATE_MEMBER: dump_vec(ast, node->aggregate_member.attr_list, stack); if (node->aggregate_member.type_expr) dump_node(ast, node->aggregate_member.type_expr, stack, false); if (node->aggregate_member.init_expr) dump_node(ast, node->aggregate_member.init_expr, stack, true); break; case SPL_AST_STRUCT_INIT_ITEM: if (node->struct_init_item.expr) dump_node(ast, node->struct_init_item.expr, stack, true); break; case SPL_AST_MATCH_ARM: if (node->match_arm.pattern) dump_node(ast, node->match_arm.pattern, stack, false); if (node->match_arm.body) dump_node(ast, node->match_arm.body, stack, true); break; case SPL_AST_LABEL: break; case SPL_AST_EXPR_INT_LIT: case SPL_AST_EXPR_FLOAT_LIT: case SPL_AST_EXPR_CHAR_LIT: case SPL_AST_EXPR_STRING_LIT: case SPL_AST_EXPR_BOOL_LIT: case SPL_AST_EXPR_NULL_LIT: case SPL_AST_EXPR_UNDEFINED_LIT: case SPL_AST_EXPR_IDENT: break; case SPL_AST_EXPR_UNARY: if (node->unary.operand) dump_node(ast, node->unary.operand, stack, true); break; case SPL_AST_EXPR_BINARY: if (node->binary.left) dump_node(ast, node->binary.left, stack, false); if (node->binary.right) dump_node(ast, node->binary.right, stack, true); break; case SPL_AST_EXPR_CALL: if (node->call.callee) dump_node(ast, node->call.callee, stack, false); dump_vec(ast, node->call.args, stack); break; case SPL_AST_EXPR_FIELD: if (node->field.obj) dump_node(ast, node->field.obj, stack, true); break; case SPL_AST_EXPR_INDEX: if (node->index.obj) dump_node(ast, node->index.obj, stack, false); if (node->index.index) dump_node(ast, node->index.index, stack, true); break; case SPL_AST_EXPR_SLICE: if (node->slice.obj) dump_node(ast, node->slice.obj, stack, false); if (node->slice.begin) dump_node(ast, node->slice.begin, stack, false); if (node->slice.end) dump_node(ast, node->slice.end, stack, true); break; case SPL_AST_EXPR_CAST: if (node->cast.expr) dump_node(ast, node->cast.expr, stack, false); if (node->cast.type) dump_node(ast, node->cast.type, stack, true); break; case SPL_AST_EXPR_TUPLE: dump_vec(ast, node->tuple.elems, stack); break; case SPL_AST_EXPR_ARRAY_LIT: if (node->array_literal.elem_type) dump_node(ast, node->array_literal.elem_type, stack, false); dump_vec(ast, node->array_literal.elems, stack); break; case SPL_AST_EXPR_AGGREGATE_LIT: dump_vec(ast, node->aggregate_literal.fields, stack); break; case SPL_AST_EXPR_COMPTIME_CALL: dump_vec(ast, node->comptime_call.args, stack); break; case SPL_AST_EXPR_BLOCK: dump_vec(ast, node->block.stmts, stack); if (node->block.tail_expr) dump_node(ast, node->block.tail_expr, stack, true); break; case SPL_AST_EXPR_IF: if (node->if_expr.cond) dump_node(ast, node->if_expr.cond, stack, false); if (node->if_expr.then_block) dump_node(ast, node->if_expr.then_block, stack, false); if (node->if_expr.else_branch) dump_node(ast, node->if_expr.else_branch, stack, true); break; case SPL_AST_EXPR_IFVAR: if (node->ifvar_expr.var_decl) dump_node(ast, node->ifvar_expr.var_decl, stack, false); if (node->ifvar_expr.then_block) dump_node(ast, node->ifvar_expr.then_block, stack, false); if (node->ifvar_expr.else_branch) dump_node(ast, node->ifvar_expr.else_branch, stack, true); break; case SPL_AST_EXPR_WHILE: if (node->while_expr.label) dump_node(ast, node->while_expr.label, stack, false); if (node->while_expr.cond) dump_node(ast, node->while_expr.cond, stack, false); if (node->while_expr.body) dump_node(ast, node->while_expr.body, stack, false); if (node->while_expr.else_branch) dump_node(ast, node->while_expr.else_branch, stack, true); break; case SPL_AST_EXPR_LOOP: if (node->loop_expr.label) dump_node(ast, node->loop_expr.label, stack, false); if (node->loop_expr.body) dump_node(ast, node->loop_expr.body, stack, true); break; case SPL_AST_EXPR_FOR: if (node->for_expr.label) dump_node(ast, node->for_expr.label, stack, false); dump_vec(ast, node->for_expr.iter_exprs, stack); dump_vec(ast, node->for_expr.idents, stack); if (node->for_expr.body) dump_node(ast, node->for_expr.body, stack, false); if (node->for_expr.else_branch) dump_node(ast, node->for_expr.else_branch, stack, true); break; case SPL_AST_EXPR_MATCH: if (node->match_expr.matched_expr) dump_node(ast, node->match_expr.matched_expr, stack, false); dump_vec(ast, node->match_expr.arms, stack); break; case SPL_AST_EXPR_FN_TYPE: dump_vec(ast, node->fn_type.params, stack); if (node->fn_type.ret_type) dump_node(ast, node->fn_type.ret_type, stack, true); break; case SPL_AST_TYPE_PATH: break; case SPL_AST_TYPE_POINTER: if (node->type_pointer.pointee) dump_node(ast, node->type_pointer.pointee, stack, true); break; case SPL_AST_TYPE_ARRAY: if (node->type_array.elem_type) dump_node(ast, node->type_array.elem_type, stack, true); break; case SPL_AST_TYPE_SLICE: if (node->type_slice.elem_type) dump_node(ast, node->type_slice.elem_type, stack, true); break; case SPL_AST_TYPE_FN: dump_vec(ast, node->type_fn.params, stack); if (node->type_fn.ret_type) dump_node(ast, node->type_fn.ret_type, stack, true); break; case SPL_AST_TYPE_PAREN: dump_vec(ast, node->type_paren.types, stack); break; case SPL_AST_TYPE_AGGREGATE: dump_vec(ast, node->type_aggregate.members, stack); break; case SPL_AST_TYPE_COMPTIME_CALL: dump_vec(ast, node->type_comptime_call.args, stack); break; case SPL_AST_PATTERN_IDENT: case SPL_AST_PATTERN_UNDERSCORE: break; case SPL_AST_PATTERN_DOT: if (node->pattern_dot.sub_pattern) dump_node(ast, node->pattern_dot.sub_pattern, stack, true); break; case SPL_AST_PATTERN_TUPLE: dump_vec(ast, node->pattern_tuple.patterns, stack); break; case SPL_AST_PATTERN_LIST: dump_vec(ast, node->pattern_list.patterns, stack); break; default: break; } (void)vec_pop(*stack); }