Files
spl/stage1/spl_ast.c
2026-08-06 19:26:30 +08:00

3434 lines
126 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// WRITE BY AI
/* spl_ast.c SPL AST 模块LL(1) 递归下降解析+ valid/dump/drop */
#include "spl_ast.h"
#include "spl_dumptree.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* 从 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_ASfor 头部序列专用*/
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) {
p->failed = 1; /* 出错即停(上层循环以 !p->failed 提前退出) */
const char *fn = (t && t->fname) ? t->fname : "<unknown>";
usize line = t ? t->line : 0;
usize col = t ? t->col : 0;
LOG_ERROR("%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;
}
/* 用指opPREFIX/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;
}
/* ================================================================
* 字面量解 * ================================================================ */
/* 整数字面量:去下划线后按 0x/0o/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;
/* strtoll base 0 不认 0b/0o 前缀:单独处理 */
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;
}
/* 字符串字面量:解码为 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, &param_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 自身不承载 attrattr 归 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 (!p->failed) {
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 <expr>; */
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"))
kind = SPL_AST_TYPE__F32;
else if (IS_TY("f64"))
kind = SPL_AST_TYPE__F64;
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 (!p.failed) {
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) : "<null>")
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_inlinevec 递归见 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;
}
}