Files
spl/stage1/spl_ast.c
T
2026-09-14 15:36:43 +08:00

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