Files
spl/stage1/spl_ast.c
2026-08-12 10:29:38 +08:00

2157 lines
66 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
*
* 设计:节点 kind 是唯一身份(扁平化)。无 `SPL_AST_EXPR`/`SPL_AST_BLOCK_ITEM`
* 等外壳类别--每个表达式/语句/类型节点直接用具体 kind。
* 子节点以 spl_ast_node_ref 引用ref 0 = 空union 数据由 kind 决定解释。
*/
#include "spl_ast.h"
#include "spl_dbg.h"
#include "spl_dumptree.h"
#include "spl_tok.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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 "?";
}
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 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;
if (tok) {
n.dbg.dbg_name = spl_ast_kind_name(kind);
n.dbg.fpath = 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 spl_ast_node_ref_t mk_bin(parser_t *p, const spl_tok_t *loc, spl_ast_node_kind_t op,
spl_ast_node_ref_t left, spl_ast_node_ref_t right) {
spl_ast_node_ref_t ref = new_node(p, op, loc);
node_at(p->ast, ref)->op_expr.left = left;
node_at(p->ast, ref)->op_expr.right = right;
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_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_type_base(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_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 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;
}
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_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_attr_list(parser_t *p, spl_ast_node_ref_vec_t *out) {
const spl_tok_t *t = NULL;
while (1) {
t = peek(p);
if (!t)
return;
if (t->type != TOK_AT && t->type != TOK_SHARP)
return;
advance(p);
t = peek(p);
if (!t || t->type != TOK_IDENT) {
SPL_FATAL(t, "expected identifier after attribute");
return;
}
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_ATTR_ITEM, t);
node_at(p->ast, ref)->attr_item.ident = sdupn(t->lexeme, t->len);
t = peek(p);
if (t != NULL && t->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;
t = peek(p);
if (t == NULL || t->type != TOK_R_PAREN) {
SPL_FATAL(t, "expected ')' to close attribute args");
}
advance(p);
return;
}
vec_push(*out, ref);
}
}
static void parse_param_list(parser_t *p, spl_ast_node_ref_vec_t *out) {
while (1) {
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) {
// 变长参数: 追加 name=NULL、type_expr=NULL 的空 param_decl
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) {
// fn(void): 无参写法
advance(p);
t = peek(p);
Assert(t && t->type == TOK_R_PAREN);
break;
} else {
UNREACHABLE();
}
}
}
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);
const spl_tok_t *name = peek(p);
if (!name || name->type != TOK_IDENT) {
SPL_FATAL(name, "expected parameter name");
return 0;
}
advance(p);
const spl_tok_t *t = peek(p);
if (t == NULL || t->type != TOK_COLON) {
SPL_FATAL(t, "expected ':' in parameter declaration");
return 0;
}
advance(p);
spl_ast_node_ref_t type_expr = parse_type_expr(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_PARAM_DECL, name);
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) {
const spl_tok_t *kw = peek(p);
Assert(kw && kw->type == KW_FN);
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 == NULL || t->type != TOK_L_PAREN) {
SPL_FATAL(t, "expected '(' in function declaration");
return 0;
}
advance(p);
spl_ast_node_ref_vec_t param_list;
vec_init(param_list);
parse_param_list(p, &param_list);
t = peek(p);
if (t == NULL || t->type != TOK_R_PAREN) {
SPL_FATAL(t, "expected ')' in function declaration");
return 0;
}
advance(p);
spl_ast_node_ref_t type_expr = 0;
spl_ast_node_ref_vec_t block;
vec_init(block);
int has_body = 0;
t = peek(p);
Assert(t != NULL);
if (t->type != TOK_SEMICOLON && t->type != TOK_L_BRACE) {
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 {
SPL_FATAL(t, "function declaration must end with ';' or a block");
}
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;
}
static spl_ast_node_ref_t parse_type_decl(parser_t *p, spl_ast_node_ref_vec_t attr_list) {
(void)attr_list;
const spl_tok_t *kw = peek(p);
Assert(kw && kw->type == KW_TYPE);
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 == NULL || 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);
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;
t = peek(p);
if (t && (t->type == TOK_COMMA || t->type == TOK_SEMICOLON)) {
advance(p);
} else {
LOG_WARN("need comma or semicolon with member decl");
}
return ref;
}
static spl_ast_node_ref_t parse_member_decl(parser_t *p, spl_ast_node_ref_vec_t attr_list) {
const spl_tok_t *name = peek(p);
Assert(name && name->type == TOK_IDENT);
advance(p);
const spl_tok_t *t = NULL;
spl_ast_node_ref_t type_expr = 0;
t = peek(p);
if (t && t->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;
t = peek(p);
if (t && (t->type == TOK_COMMA || t->type == TOK_SEMICOLON)) {
advance(p);
} else {
LOG_WARN("need comma or semicolon with member decl");
}
return ref;
}
static spl_ast_node_ref_t parse_var_const_decl(parser_t *p, spl_ast_node_ref_vec_t attr_list,
int is_const) {
const spl_tok_t *kw = peek(p);
Assert(kw);
if (is_const) {
Assert(kw->type == KW_CONST);
} else {
Assert(kw->type == KW_VAR);
}
advance(p);
const spl_tok_t *name = peek(p);
if (!name || name->type != TOK_IDENT) {
SPL_FATAL(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;
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);
expr = parse_expr(p);
} else {
SPL_FATAL(t ? t : kw, "need assign in var decl");
}
} else if (t && t->type == TOK_COLON_ASSIGN) {
advance(p);
expr = parse_expr(p);
}
spl_ast_node_ref_t ref = new_node(p, is_const ? SPL_AST_CONST_DECL : SPL_AST_VAR_DECL, kw);
node_at(p->ast, ref)->var_const_decl.attr_list = attr_list;
node_at(p->ast, ref)->var_const_decl.name = sdupn(name->lexeme, name->len);
node_at(p->ast, ref)->var_const_decl.type_expr = type_expr;
node_at(p->ast, ref)->var_const_decl.expr = expr;
t = peek(p);
if (t && t->type == TOK_SEMICOLON) {
advance(p);
} else {
LOG_WARN("need semicolon in decl var/const");
}
return ref;
}
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);
const spl_tok_t *t = peek(p);
if (!t || t->type == TOK_EOF) {
SPL_FATAL(t, "unexpected end of file");
return 0;
}
if (t->type == TOK_L_BRACE) {
/* DirectiveBlock@init {} / #test {}):不实现 */
SPL_FATAL(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_const_decl(p, attr_list, false);
case KW_CONST:
return parse_var_const_decl(p, attr_list, true);
case TOK_IDENT:
return parse_member_decl(p, attr_list);
case KW_COMPTIME:
SPL_FATAL(t, "not implemented: comptime statement");
return 0;
default:
SPL_FATAL(t, "unrecognized declaration");
return 0;
}
}
// 语句
static spl_ast_node_ref_vec_t parse_block(parser_t *p) {
spl_ast_node_ref_vec_t vec;
vec_init(vec);
const spl_tok_t *t = peek(p);
if (t == NULL || t->type != TOK_L_BRACE) {
SPL_FATAL(t, "expected '{'");
return vec;
}
advance(p);
while (!p->failed) {
t = peek(p);
if (!t || t->type == TOK_EOF) {
SPL_FATAL(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 {
UNREACHABLE();
}
} else if (can_start_expr(t->type)) {
spl_ast_node_ref_t e = parse_expr(p);
t = peek(p);
if (t && t->type == TOK_SEMICOLON) {
advance(p);
vec_push(vec, e);
} else {
// Tail expretion
UNREACHABLE();
}
} else {
SPL_FATAL(t, "unrecognized statement");
}
}
return vec;
}
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_IF:
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);
return parse_var_const_decl(p, al, false);
}
case KW_CONST: {
spl_ast_node_ref_vec_t al;
vec_init(al);
return parse_var_const_decl(p, al, true);
}
case KW_TYPE: {
spl_ast_node_ref_vec_t al;
vec_init(al);
return parse_type_decl(p, al);
}
case KW_COMPTIME:
SPL_FATAL(t, "not implemented: comptime statement");
return 0;
default:
SPL_FATAL(t, "unrecognized statement");
return 0;
}
}
static spl_ast_node_ref_t parse_if(parser_t *p) {
const spl_tok_t *kw = peek(p);
Assert(kw && kw->type == KW_IF);
advance(p);
int is_ifvar = false;
char *bind = NULL;
const spl_tok_t *name = NULL;
const spl_tok_t *t = peek(p);
if (t && t->type == KW_VAR) {
advance(p);
t = peek(p);
if (t == NULL || t->type != TOK_DOT) {
SPL_FATAL(t, "expected '.' in if var");
return 0;
}
name = peek(p);
if (!name || name->type != TOK_IDENT) {
SPL_FATAL(name, "expected variable name in if var");
return 0;
}
advance(p);
t = peek(p);
if (t && t->type == TOK_L_BRACKET) {
advance(p);
t = peek(p);
if (!t || t->type != TOK_IDENT) {
SPL_FATAL(t, "expected identifier in if var binding");
return 0;
}
advance(p);
bind = sdupn(t->lexeme, t->len);
t = peek(p);
if (t == NULL || t->type != TOK_R_BRACKET) {
SPL_FATAL(t, "expected ']' in if var binding");
return 0;
}
advance(p);
}
t = peek(p);
if (t == NULL || t->type != TOK_ASSIGN) {
SPL_FATAL(t, "expected '=' in if var");
}
advance(p);
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);
t = peek(p);
if (t && t->type == KW_ELSE) {
advance(p);
t = peek(p);
if (t && t->type == KW_IF) {
vec_push(else_block, parse_if(p));
} else {
else_block = parse_block(p);
}
}
spl_ast_node_ref_t s = 0;
if (is_ifvar) {
Assert(name != NULL && bind != NULL);
spl_ast_node_ref_t packed = new_node(p, SPL_AST_PACKED_EXPR, 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;
s = new_node(p, SPL_AST_IFVAR_STATEMENT, kw);
node_at(p->ast, s)->ifvar_statement.packed_expr = packed;
node_at(p->ast, s)->ifvar_statement.if_block = if_block;
node_at(p->ast, s)->ifvar_statement.else_block = else_block;
} else {
s = new_node(p, SPL_AST_IF_STATEMENT, kw);
node_at(p->ast, s)->if_statement.expr = expr;
node_at(p->ast, s)->if_statement.if_block = if_block;
node_at(p->ast, s)->if_statement.else_block = else_block;
}
return s;
}
static spl_ast_node_ref_t parse_while(parser_t *p) {
const spl_tok_t *kw = peek(p);
Assert(kw && kw->type == KW_WHILE);
advance(p);
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_WHILE_STATEMENT, kw);
node_at(p->ast, s)->while_statement.expr = expr;
node_at(p->ast, s)->while_statement.while_block = block;
return s;
}
static spl_ast_node_ref_t parse_loop(parser_t *p) {
const spl_tok_t *kw = peek(p);
Assert(kw && kw->type == KW_LOOP);
advance(p);
spl_ast_node_ref_vec_t block = parse_block(p);
spl_ast_node_ref_t s = new_node(p, SPL_AST_LOOP_STATEMENT, kw);
node_at(p->ast, s)->loop_statement.loop_block = block;
return s;
}
static spl_ast_node_ref_t parse_for(parser_t *p) {
const spl_tok_t *kw = peek(p);
Assert(kw && kw->type == KW_FOR);
advance(p);
spl_ast_node_ref_vec_t expr_vec;
vec_init(expr_vec);
// For as is not type case
p->stop_as = 1;
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;
const spl_tok_t *t = peek(p);
if (t == NULL || t->type != KW_AS) {
SPL_FATAL(t, "expected 'as' in for");
return 0;
}
advance(p);
spl_ast_node_ref_t s = new_node(p, SPL_AST_FOR_STATEMENT, kw);
node_at(p->ast, s)->for_statement.expr_vec = expr_vec;
t = peek(p);
if (!t || (t->type != TOK_IDENT && t->type != KW_ANY)) {
SPL_FATAL(t, "expected binding variable in for");
return s;
}
advance(p);
vec_push(node_at(p->ast, s)->for_statement.ident_vec, sdupn(t->lexeme, t->len));
while (peek(p) && peek(p)->type == TOK_COMMA) {
advance(p);
t = peek(p);
if (!t || (t->type != TOK_IDENT && t->type != KW_ANY)) {
SPL_FATAL(t, "expected binding variable in for");
return s;
}
advance(p);
vec_push(node_at(p->ast, s)->for_statement.ident_vec, sdupn(t->lexeme, t->len));
}
spl_ast_node_ref_vec_t fblock = parse_block(p);
node_at(p->ast, s)->for_statement.block = fblock;
return s;
}
static spl_ast_node_ref_t parse_match(parser_t *p) {
const spl_tok_t *kw = peek(p);
Assert(kw && kw->type == KW_MATCH);
advance(p);
p->stop_agg++;
spl_ast_node_ref_t expr = parse_expr(p);
p->stop_agg--;
const spl_tok_t *t = peek(p);
if (t == NULL || t->type != TOK_L_BRACE) {
SPL_FATAL(t, "expected '{' in match");
return 0;
}
advance(p);
spl_ast_node_ref_vec_t paced_vec, stmt_vec;
vec_init(paced_vec);
vec_init(stmt_vec);
while (1) {
t = peek(p);
if (!t || t->type == TOK_EOF) {
SPL_FATAL(t, "match missing '}'");
break;
}
if (t->type == TOK_R_BRACE) {
advance(p);
break;
}
if (!parse_match_arm(p, &paced_vec, &stmt_vec))
break;
t = peek(p);
if (t && t->type == TOK_COMMA)
advance(p);
}
spl_ast_node_ref_t s = new_node(p, SPL_AST_MATCH_STATEMENT, kw);
node_at(p->ast, s)->match_statement.expr = expr;
node_at(p->ast, s)->match_statement.paced_exprs = paced_vec;
node_at(p->ast, s)->match_statement.match_block = stmt_vec;
return s;
}
static int parse_match_arm(parser_t *p, spl_ast_node_ref_vec_t *paced_vec,
spl_ast_node_ref_vec_t *block_vec) {
const spl_tok_t *t = peek(p);
if (!t)
return 0;
spl_ast_node_ref_vec_t modes;
vec_init(modes);
while (1) {
const spl_tok_t *mt = peek(p);
if (!mt) {
SPL_FATAL(mt, "invalid match arm pattern");
return 0;
}
spl_ast_node_ref_t pk = new_node(p, SPL_AST_PACKED_EXPR, 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);
const spl_tok_t *name = peek(p);
if (!name || name->type != TOK_IDENT) {
SPL_FATAL(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);
const spl_tok_t *b = peek(p);
if (!b || b->type != TOK_IDENT) {
SPL_FATAL(b, "expected identifier in match binding");
return 0;
}
advance(p);
node_at(p->ast, pk)->packed_expr.bind_ident = sdupn(b->lexeme, b->len);
t = peek(p);
if (t == NULL || t->type != TOK_R_BRACKET) {
SPL_FATAL(t, "expected ']' in match binding");
return 0;
}
advance(p);
}
} else if (mt->type == KW_ANY) {
t = peek(p);
if (t && t->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 {
SPL_FATAL(mt, "invalid match arm pattern");
return 0;
}
vec_push(modes, pk);
if (peek(p) && peek(p)->type == TOK_COMMA) {
advance(p);
continue;
}
break;
}
t = peek(p);
if (t == NULL || t->type != TOK_FAT_ARROW) {
SPL_FATAL(t, "expected '=>' in match arm");
return 0;
}
advance(p);
t = peek(p);
if (!t || t->type != TOK_L_BRACE) {
SPL_FATAL(t, "expected '{' block in match arm body");
return 0;
}
spl_ast_node_ref_vec_t bvec = parse_block(p);
spl_ast_node_ref_t body = new_node(p, SPL_AST_BLOCK_EXPR, t);
node_at(p->ast, body)->primary_expr.block_expr = bvec;
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) {
const spl_tok_t *kw = peek(p);
Assert(kw && kw->type == KW_RET);
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 s = new_node(p, SPL_AST_RET_STATEMENT, kw);
node_at(p->ast, s)->ret_statement.expr = expr;
return s;
}
static spl_ast_node_ref_t parse_break(parser_t *p) {
const spl_tok_t *kw = peek(p);
Assert(kw && kw->type == KW_BREAK);
advance(p);
const spl_tok_t *t = peek(p);
if (t && t->type == TOK_SEMICOLON)
advance(p);
return new_node(p, SPL_AST_BREAK_STATEMENT, kw);
}
static spl_ast_node_ref_t parse_continue(parser_t *p) {
const spl_tok_t *kw = peek(p);
Assert(kw && kw->type == KW_CONTINUE);
advance(p);
const spl_tok_t *t = peek(p);
if (t && t->type == TOK_SEMICOLON)
advance(p);
return new_node(p, SPL_AST_CONTINUE_STATEMENT, kw);
}
static spl_ast_node_ref_t parse_defer(parser_t *p) {
const spl_tok_t *kw = peek(p);
Assert(kw && kw->type == KW_DEFER);
advance(p);
spl_ast_node_ref_vec_t vec;
vec_init(vec);
const spl_tok_t *t = peek(p);
if (t && t->type == TOK_L_BRACE) {
vec = parse_block(p);
} else if (t && can_start_statement(t->type)) {
spl_ast_node_ref_t st = parse_statement(p);
if (st)
vec_push(vec, st);
} else {
spl_ast_node_ref_t e = parse_expr(p);
t = peek(p);
if (t && t->type == TOK_SEMICOLON)
advance(p);
vec_push(vec, e);
}
spl_ast_node_ref_t s = new_node(p, SPL_AST_DEFER_STATEMENT, kw);
node_at(p->ast, s)->defer_statement.block_or_statement = vec;
return s;
}
// 表达式
static spl_ast_node_kind_t 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 SPL_AST_COUNT;
}
}
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;
const spl_tok_t *t = peek(p);
spl_ast_node_kind_t op = t ? assign_op_of(t->type) : SPL_AST_COUNT;
if (op == SPL_AST_COUNT)
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) {
const 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_BOOL_OR_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) {
const 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_BOOL_AND_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) {
const 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_BIT_OR_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) {
const 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_BIT_XOR_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) {
const 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_BIT_AND_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) {
const spl_tok_t *t = peek(p);
spl_ast_node_kind_t op = SPL_AST_COUNT;
if (t) {
if (t->type == TOK_EQ)
op = SPL_AST_CMP_EQ_EXPR;
else if (t->type == TOK_NEQ)
op = SPL_AST_CMP_NE_EXPR;
}
if (op == SPL_AST_COUNT)
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) {
const spl_tok_t *t = peek(p);
spl_ast_node_kind_t op = SPL_AST_COUNT;
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 == SPL_AST_COUNT)
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;
const 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) {
const spl_tok_t *t = peek(p);
spl_ast_node_kind_t op = SPL_AST_COUNT;
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 == SPL_AST_COUNT)
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) {
const spl_tok_t *t = peek(p);
spl_ast_node_kind_t op = SPL_AST_COUNT;
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 == SPL_AST_COUNT)
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) {
const spl_tok_t *t = peek(p);
spl_ast_node_kind_t op = SPL_AST_COUNT;
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 == SPL_AST_COUNT)
break;
advance(p);
spl_ast_node_ref_t right = parse_prefix(p);
left = mk_bin(p, t, op, left, right);
}
return left;
}
static spl_ast_node_ref_t parse_prefix(parser_t *p) {
const spl_tok_t *t = peek(p);
Assert(t != NULL);
spl_ast_node_kind_t op;
switch (t->type) {
case TOK_SUB:
op = SPL_AST_MINUS_EXPR;
break;
case TOK_NOT:
op = SPL_AST_NOT_EXPR;
break;
case TOK_BIT_NOT:
op = SPL_AST_BIT_NOT_EXPR;
break;
case TOK_AND:
op = SPL_AST_ADDRESS_EXPR;
break;
default:
return parse_postfix(p);
}
advance(p);
spl_ast_node_ref_t inner = parse_prefix(p);
spl_ast_node_ref_t pf = new_node(p, op, t);
node_at(p->ast, pf)->prefix_expr.postfix_expr = inner;
return pf;
}
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 pf = new_node(p, SPL_AST_CALL_EXPR, t);
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;
t = peek(p);
if (t == NULL || t->type != TOK_R_PAREN) {
SPL_FATAL(t, "expected ')' in call");
return expr;
}
advance(p);
expr = pf;
} else if (t->type == TOK_DOT) {
advance(p);
const 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_DEREF_EXPR, t);
node_at(p->ast, pf)->postfix_expr.primary_expr = expr;
expr = pf;
} else if (n && n->type == TOK_IDENT) {
advance(p);
spl_ast_node_ref_t pf = new_node(p, SPL_AST_FIELD_EXPR, t);
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 = pf;
} else {
SPL_FATAL(n, "expected identifier or '*' after '.'");
break;
}
} else if (t->type == TOK_L_BRACKET) {
advance(p);
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);
t = peek(p);
if (t == NULL || t->type != TOK_R_BRACKET) {
SPL_FATAL(t, "expected ']' in slice");
return expr;
}
advance(p);
spl_ast_node_ref_t pf = new_node(p, SPL_AST_SLICE_EXPR, t);
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 = pf;
} else {
t = peek(p);
if (t == NULL || t->type != TOK_R_BRACKET) {
SPL_FATAL(t, "expected ']' in index");
return expr;
}
advance(p);
spl_ast_node_ref_t pf = new_node(p, SPL_AST_INDEX_EXPR, t);
node_at(p->ast, pf)->postfix_expr.primary_expr = expr;
node_at(p->ast, pf)->postfix_expr.index_expr = begin;
expr = pf;
}
} 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_AS_EXPR, t);
node_at(p->ast, pf)->postfix_expr.primary_expr = expr;
node_at(p->ast, pf)->postfix_expr.type_expr = te;
expr = pf;
} else {
break;
}
}
return 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;
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_init_body(parser_t *p) {
spl_ast_node_ref_vec_t agg_vec;
vec_init(agg_vec);
const spl_tok_t *t = peek(p);
if (t == NULL || t->type != TOK_L_BRACE) {
SPL_FATAL(t, "expected '{' in struct init");
return agg_vec;
}
advance(p);
while (1) {
t = peek(p);
if (!t || t->type == TOK_R_BRACE || t->type == TOK_EOF)
break;
t = peek(p);
if (t == NULL || t->type != TOK_DOT) {
SPL_FATAL(t, "expected '.' in struct init");
return agg_vec;
}
advance(p);
t = peek(p);
if (!t || t->type != TOK_IDENT) {
SPL_FATAL(t, "expected field name in struct init");
return agg_vec;
}
advance(p);
spl_ast_node_ref_t item = new_node(p, SPL_AST_ARGG_INIT_ITEM, t);
node_at(p->ast, item)->aggregate_init_item.ident = sdupn(t->lexeme, t->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;
}
t = peek(p);
if (t == NULL || t->type != TOK_R_BRACE) {
SPL_FATAL(t, "expected '}' in struct literal");
return agg_vec;
}
advance(p);
return agg_vec;
}
static spl_ast_node_ref_t parse_primary(parser_t *p) {
const spl_tok_t *t = peek(p);
if (!t) {
SPL_FATAL(t, "unexpected expression start");
return 0;
}
switch (t->type) {
case TOK_INT_LITERAL: {
advance(p);
spl_ast_node_ref_t pr = new_node(p, SPL_AST_EXPR_INTEGER_LIT, t);
node_at(p->ast, pr)->primary_expr.integer_expr = parse_int_literal(t);
return pr;
}
case TOK_FLOAT_LITERAL: {
advance(p);
spl_ast_node_ref_t pr = new_node(p, SPL_AST_EXPR_FLOAT_LIT, t);
node_at(p->ast, pr)->primary_expr.float_expr = parse_float_literal(t);
return pr;
}
case TOK_CHAR_LITERAL: {
advance(p);
spl_ast_node_ref_t pr = new_node(p, SPL_AST_EXPR_CHAR_LIT, t);
node_at(p->ast, pr)->primary_expr.char_lit_expr = parse_char_literal(t);
return pr;
}
case TOK_STRING_LITERAL: {
advance(p);
spl_ast_node_ref_t pr = new_node(p, SPL_AST_EXPR_STRING_LIT, t);
node_at(p->ast, pr)->primary_expr.string_lit_expr = parse_string_literal(t);
return pr;
}
case KW_TRUE: {
advance(p);
return new_node(p, SPL_AST_EXPR_TRUE, t);
}
case KW_FALSE: {
advance(p);
return new_node(p, SPL_AST_EXPR_FALSE, t);
}
case KW_NULL: {
advance(p);
return new_node(p, SPL_AST_EXPR_NULL, t);
}
case KW_UNDEFINDED: {
advance(p);
return new_node(p, SPL_AST_EXPR_UNDEFINED, t);
}
case TOK_IDENT: {
advance(p);
if (peek(p) && peek(p)->type == TOK_L_BRACE && !p->stop_agg) {
spl_ast_node_ref_vec_t agg_vec = parse_aggregate_init_body(p);
spl_ast_node_ref_t pr = new_node(p, SPL_AST_ARGGREGATE_INIT, t);
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 pr;
}
spl_ast_node_ref_t pr = new_node(p, SPL_AST_EXPR_IDENT, t);
node_at(p->ast, pr)->primary_expr.ident = sdupn(t->lexeme, t->len);
return pr;
}
case TOK_DOT: {
advance(p);
const spl_tok_t *nx = peek(p);
if (nx && nx->type == TOK_L_BRACE && !p->stop_agg) {
spl_ast_node_ref_vec_t agg_vec = parse_aggregate_init_body(p);
spl_ast_node_ref_t pr = new_node(p, SPL_AST_ARGGREGATE_INIT, t);
node_at(p->ast, pr)->primary_expr.aggregate_init.name = NULL;
node_at(p->ast, pr)->primary_expr.aggregate_init.expr = agg_vec;
return pr;
}
SPL_FATAL(t, "unexpected '.' in expression");
return 0;
}
case KW_ANY:
SPL_FATAL(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);
t = peek(p);
if (t == NULL || t->type != TOK_R_PAREN) {
SPL_FATAL(t, "expected ')' in parenthesized expression");
return e;
}
advance(p);
return e;
}
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 = new_node(p, SPL_AST_BLOCK_EXPR, t);
node_at(p->ast, pr)->primary_expr.block_expr = bvec;
return pr;
}
default:
SPL_FATAL(t, "unrecognized expression");
return 0;
}
}
static spl_ast_node_ref_t parse_builtin(parser_t *p) {
const spl_tok_t *t = peek(p);
Assert(t && (t->type == TOK_AT || t->type == TOK_SHARP));
advance(p);
const spl_tok_t *name = peek(p);
if (!name || name->type != TOK_IDENT) {
SPL_FATAL(name, "expected builtin name");
return 0;
}
advance(p);
t = peek(p);
if (t == NULL || t->type != TOK_L_PAREN) {
SPL_FATAL(t, "expected '(' in builtin call");
return 0;
}
advance(p);
spl_ast_node_ref_vec_t args = parse_expr_list(p);
t = peek(p);
if (t == NULL || t->type != TOK_R_PAREN) {
SPL_FATAL(t, "expected ')' in builtin call");
return 0;
}
advance(p);
spl_ast_node_ref_t pr = new_node(p, SPL_AST_BUILTIN_EXPR, t);
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 pr;
}
static spl_ast_node_ref_t parse_array_literal(parser_t *p) {
const spl_tok_t *t = peek(p);
advance(p); /* L_BRACKET */
isize integer = 0;
t = peek(p);
if (t && t->type == TOK_INT_LITERAL) {
integer = parse_int_literal(t);
advance(p);
}
t = peek(p);
if (t == NULL || t->type != TOK_R_BRACKET) {
SPL_FATAL(t, "expected ']' in array literal");
return 0;
}
advance(p);
spl_ast_node_ref_t te = parse_type_expr(p);
t = peek(p);
if (t == NULL || t->type != TOK_L_BRACE) {
SPL_FATAL(t, "expected '{' in array literal");
return 0;
}
advance(p);
spl_ast_node_ref_vec_t items = parse_expr_list(p);
t = peek(p);
if (t == NULL || t->type != TOK_R_BRACE) {
SPL_FATAL(t, "expected '}' in array literal");
return 0;
}
advance(p);
spl_ast_node_ref_t pr = new_node(p, SPL_AST_ARRAY_LIT, t);
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 pr;
}
static spl_ast_node_ref_t parse_expr(parser_t *p) { return parse_assign(p); }
// 类型表达式
static spl_ast_node_kind_t type_atom_kind_of(spl_tok_type_t tt) {
switch (tt) {
case KW_VOID:
return SPL_AST_TYPE_VOID;
case KW_BOOL:
return SPL_AST_TYPE_BOOL;
case KW_ANY:
return SPL_AST_TYPE_ANY;
default:
return SPL_AST_COUNT;
}
}
static const struct {
const char *name;
spl_ast_node_kind_t kind;
} type_kw_table[] = {
{"i8", SPL_AST_TYPE_I8}, {"u8", SPL_AST_TYPE_U8}, {"i16", SPL_AST_TYPE_I16},
{"u16", SPL_AST_TYPE_U16}, {"i32", SPL_AST_TYPE_I32}, {"u32", SPL_AST_TYPE_U32},
{"i64", SPL_AST_TYPE_I64}, {"u64", SPL_AST_TYPE_U64}, {"isize", SPL_AST_TYPE_ISIZE},
{"usize", SPL_AST_TYPE_USIZE}, {"f32", SPL_AST_TYPE__F32}, {"f64", SPL_AST_TYPE__F64},
};
static spl_ast_node_kind_t type_kw_kind_of(const spl_tok_t *t) {
if (t->type == TOK_IDENT) {
const char *s = t->lexeme;
usize slen = t->len;
for (usize i = 0; i < sizeof(type_kw_table) / sizeof(type_kw_table[0]); i++) {
const char *nm = type_kw_table[i].name;
if (slen == strlen(nm) && memcmp(s, nm, slen) == 0)
return type_kw_table[i].kind;
}
return SPL_AST_COUNT;
}
return type_atom_kind_of(t->type);
}
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);
node_at(p->ast, ref)->type_expr.pointer_type.pointee = parse_type_expr(p);
return ref;
}
if (t->type == TOK_L_BRACKET) {
advance(p);
spl_ast_node_ref_t sz = 0;
t = peek(p);
if (t && t->type == TOK_INT_LITERAL) {
sz = new_node(p, SPL_AST_EXPR_INTEGER_LIT, t);
node_at(p->ast, sz)->primary_expr.integer_expr = parse_int_literal(peek(p));
advance(p);
}
t = peek(p);
if (t == NULL || t->type != TOK_R_BRACKET) {
SPL_FATAL(t, "expected ']' in array type");
return 0;
}
advance(p);
spl_ast_node_ref_t ref = 0;
if (sz == 0) {
ref = new_node(p, SPL_AST_TYPE_SLICE, t);
node_at(p->ast, ref)->type_expr.slice_type.element = parse_type_expr(p);
} else {
ref = new_node(p, SPL_AST_TYPE_ARRAY, t);
node_at(p->ast, ref)->type_expr.array_type.element = parse_type_expr(p);
node_at(p->ast, ref)->type_expr.array_type.size = sz;
}
Assert(ref != 0);
return ref;
}
return parse_type_base(p);
}
static spl_ast_node_ref_t parse_type_base(parser_t *p) {
spl_ast_node_ref_vec_t attr_list;
vec_init(attr_list);
parse_attr_list(p, &attr_list);
spl_ast_node_ref_t base = 0;
const spl_tok_t *bt = peek(p);
if (!bt) {
SPL_FATAL(bt, "expected type base");
return 0;
}
const spl_tok_t *t = NULL;
if (bt->type == KW_FN) {
advance(p); /* KW_FN */
t = peek(p);
if (t == NULL || t->type != TOK_L_PAREN) {
SPL_FATAL(t, "expected '(' in function type");
return 0;
}
advance(p);
base = new_node(p, SPL_AST_BASE_TYPE_FN, bt);
node_at(p->ast, base)->type_expr.attr_list = attr_list;
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);
vec_push(param_list, pt);
if (peek(p) && peek(p)->type == TOK_COMMA) {
advance(p);
continue;
}
break;
}
t = peek(p);
if (t == NULL || t->type != TOK_R_PAREN) {
SPL_FATAL(t, "expected ')' in function type");
return 0;
}
advance(p);
spl_ast_node_ref_t ret = parse_type_expr(p);
node_at(p->ast, base)->type_expr.fn_type.param_list = param_list;
node_at(p->ast, base)->type_expr.fn_type.type_expr = ret;
return base;
}
if (bt->type == KW_STRUCT || bt->type == KW_UNION || bt->type == KW_ENUM) {
spl_ast_node_kind_t aggk = (bt->type == KW_STRUCT) ? SPL_AST_TYPE_STRUCT
: (bt->type == KW_UNION) ? SPL_AST_TYPE_UNION
: SPL_AST_TYPE_ENUM;
advance(p);
t = peek(p);
if (t == NULL || t->type != TOK_L_BRACE) {
SPL_FATAL(t, "expected '{' in aggregate type");
return 0;
}
advance(p);
base = new_node(p, aggk, bt);
node_at(p->ast, base)->type_expr.attr_list = attr_list;
spl_ast_node_ref_vec_t members;
vec_init(members);
while (1) {
t = peek(p);
if (!t || t->type == TOK_R_BRACE || t->type == TOK_EOF)
break;
spl_ast_node_ref_t md = parse_container_declaration(p);
if (md)
vec_push(members, md);
}
t = peek(p);
if (t == NULL || t->type != TOK_R_BRACE) {
SPL_FATAL(t, "expected '}' in aggregate type");
return 0;
}
advance(p);
node_at(p->ast, base)->type_expr.aggregate_list = members;
return base;
}
spl_ast_node_kind_t kwk = type_kw_kind_of(bt);
if (kwk != SPL_AST_COUNT) {
advance(p);
base = new_node(p, kwk, bt);
node_at(p->ast, base)->type_expr.attr_list = attr_list;
return base;
}
if (bt->type != TOK_IDENT) {
SPL_FATAL(bt, "unrecognized type");
return 0;
}
base = new_node(p, SPL_AST_BASE_TYPE_PATH, bt);
node_at(p->ast, base)->type_expr.attr_list = attr_list;
while (1) {
t = peek(p);
if (!t || t->type != TOK_IDENT) {
SPL_FATAL(t, "unrecognized type atom");
break;
}
vec_push(node_at(p->ast, base)->type_expr.type_path.ident_vec, sdupn(t->lexeme, t->len));
advance(p);
if (peek(p) && peek(p)->type == TOK_DOT) {
advance(p);
continue;
}
break;
}
return base;
}
void spl_ast_init(spl_ast_t *ast, const spl_tok_vec_t *tok_vec) {
ast->input = *tok_vec; // move
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_prase(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;
ast->parsed = 0;
spl_tok_t *begin = &vec_at(ast->input, 0);
spl_ast_node_ref_vec_t members;
vec_init(members);
while (!p.failed) {
const 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, begin);
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;
vec_for(ast->str_buckets, idx) { free(vec_at(ast->str_buckets, idx)); }
vec_free(ast->str_buckets);
vec_free(ast->node_buckets);
vec_free(ast->input);
ast->parsed = 0;
ast->root = 0;
}
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, int 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);
dump_node(ast, node, &stack, 1);
}
#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, int last) {
spl_ast_node_t *node = &vec_at(ast->node_buckets, 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.fpath)
printf(" (%d:%d)", node->dbg.line, node->dbg.col);
printf("\n");
vec_push(*stack, last);
switch (node->kind) {
case SPL_AST_NONE:
UNREACHABLE();
break;
case SPL_AST_CONTAINER_ITEM:
dump_vec(ast, node->container_item.attr_list, stack);
dump_vec(ast, node->container_item.members, stack);
break;
case SPL_AST_FN_DECL:
case SPL_AST_FN_DEFINE:
dump_vec(ast, node->fn_decl.attr_list, stack);
dump_vec(ast, node->fn_decl.param_list, stack);
if (node->fn_decl.type_expr)
dump_node(ast, node->fn_decl.type_expr, stack, 1);
dump_vec(ast, node->fn_decl.block, stack);
break;
case SPL_AST_TYPE_DECL:
if (node->type_decl.type_expr)
dump_node(ast, node->type_decl.type_expr, stack, 1);
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.type_expr)
dump_node(ast, node->var_const_decl.type_expr, stack, 0);
if (node->var_const_decl.expr)
dump_node(ast, node->var_const_decl.expr, stack, 1);
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, 1);
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, 1);
break;
case SPL_AST_ATTR_ITEM:
dump_vec(ast, node->attr_item.expr_list, stack);
break;
case SPL_AST_ARGG_INIT_ITEM:
if (node->aggregate_init_item.expr)
dump_node(ast, node->aggregate_init_item.expr, stack, 1);
break;
case SPL_AST_IF_STATEMENT:
if (node->if_statement.expr)
dump_node(ast, node->if_statement.expr, stack, 0);
dump_vec(ast, node->if_statement.if_block, stack);
dump_vec(ast, node->if_statement.else_block, stack);
break;
case SPL_AST_IFVAR_STATEMENT:
if (node->ifvar_statement.packed_expr)
dump_node(ast, node->ifvar_statement.packed_expr, stack, 0);
dump_vec(ast, node->ifvar_statement.if_block, stack);
dump_vec(ast, node->ifvar_statement.else_block, stack);
break;
case SPL_AST_WHILE_STATEMENT:
if (node->while_statement.expr)
dump_node(ast, node->while_statement.expr, stack, 0);
dump_vec(ast, node->while_statement.while_block, stack);
break;
case SPL_AST_LOOP_STATEMENT:
dump_vec(ast, node->loop_statement.loop_block, stack);
break;
case SPL_AST_FOR_STATEMENT:
dump_vec(ast, node->for_statement.expr_vec, stack);
for (usize i = 0; i < vec_size(node->for_statement.ident_vec); i++) {
for (usize j = 0; j < vec_size(*stack); j++)
printf("%s", vec_at(*stack, j) ? " " : "| ");
printf("%sfor_binding %s\n",
i + 1 == vec_size(node->for_statement.ident_vec) ? "`-" : "|-",
node->for_statement.ident_vec.data[i]);
}
dump_vec(ast, node->for_statement.block, stack);
break;
case SPL_AST_MATCH_STATEMENT:
if (node->match_statement.expr)
dump_node(ast, node->match_statement.expr, stack, 0);
dump_vec(ast, node->match_statement.paced_exprs, stack);
dump_vec(ast, node->match_statement.match_block, stack);
break;
case SPL_AST_RET_STATEMENT:
if (node->ret_statement.expr)
dump_node(ast, node->ret_statement.expr, stack, 1);
break;
case SPL_AST_DEFER_STATEMENT:
dump_vec(ast, node->defer_statement.block_or_statement, stack);
break;
case SPL_AST_PACKED_EXPR:
if (node->packed_expr.expr)
dump_node(ast, node->packed_expr.expr, stack, 1);
break;
case SPL_AST_ASSIGN_EXPR:
case SPL_AST_ASSIGN_ADD_EXPR:
case SPL_AST_ASSIGN_SUB_EXPR:
case SPL_AST_ASSIGN_MUL_EXPR:
case SPL_AST_ASSIGN_DIV_EXPR:
case SPL_AST_ASSIGN_MOD_EXPR:
case SPL_AST_ASSIGN_AND_EXPR:
case SPL_AST_ASSIGN_OR_EXPR:
case SPL_AST_ASSIGN_XOR_EXPR:
case SPL_AST_ASSIGN_LSHIFT_EXPR:
case SPL_AST_ASSIGN_USHIFT_EXPR:
case SPL_AST_BOOL_OR_EXPR:
case SPL_AST_BOOL_AND_EXPR:
case SPL_AST_BIT_OR_EXPR:
case SPL_AST_BIT_XOR_EXPR:
case SPL_AST_BIT_AND_EXPR:
case SPL_AST_CMP_EQ_EXPR:
case SPL_AST_CMP_NE_EXPR:
case SPL_AST_CMP_LE_EXPR:
case SPL_AST_CMP_GE_EXPR:
case SPL_AST_CMP_LT_EXPR:
case SPL_AST_CMP_GT_EXPR:
case SPL_AST_RANGE_EXPR:
case SPL_AST_LSHIFT_EXPR:
case SPL_AST_RSHIFT_EXPR:
case SPL_AST_ADD_EXPR:
case SPL_AST_SUB_EXPR:
case SPL_AST_MUL_EXPR:
case SPL_AST_DIV_EXPR:
case SPL_AST_MOD_EXPR:
if (node->op_expr.left)
dump_node(ast, node->op_expr.left, stack, 0);
if (node->op_expr.right)
dump_node(ast, node->op_expr.right, stack, 1);
break;
case SPL_AST_MINUS_EXPR:
case SPL_AST_NOT_EXPR:
case SPL_AST_BIT_NOT_EXPR:
case SPL_AST_ADDRESS_EXPR:
if (node->prefix_expr.postfix_expr)
dump_node(ast, node->prefix_expr.postfix_expr, stack, 1);
break;
case SPL_AST_CALL_EXPR:
if (node->postfix_expr.primary_expr)
dump_node(ast, node->postfix_expr.primary_expr, stack, 0);
dump_vec(ast, node->postfix_expr.call_expr, stack);
break;
case SPL_AST_FIELD_EXPR:
case SPL_AST_DEREF_EXPR:
if (node->postfix_expr.primary_expr)
dump_node(ast, node->postfix_expr.primary_expr, stack, 1);
break;
case SPL_AST_INDEX_EXPR:
if (node->postfix_expr.primary_expr)
dump_node(ast, node->postfix_expr.primary_expr, stack, 0);
if (node->postfix_expr.index_expr)
dump_node(ast, node->postfix_expr.index_expr, stack, 1);
break;
case SPL_AST_SLICE_EXPR:
if (node->postfix_expr.primary_expr)
dump_node(ast, node->postfix_expr.primary_expr, stack, 0);
if (node->postfix_expr.slice_expr.begin)
dump_node(ast, node->postfix_expr.slice_expr.begin, stack, 0);
if (node->postfix_expr.slice_expr.end)
dump_node(ast, node->postfix_expr.slice_expr.end, stack, 1);
break;
case SPL_AST_AS_EXPR:
if (node->postfix_expr.primary_expr)
dump_node(ast, node->postfix_expr.primary_expr, stack, 0);
if (node->postfix_expr.type_expr)
dump_node(ast, node->postfix_expr.type_expr, stack, 1);
break;
case SPL_AST_EXPR_INTEGER_LIT:
case SPL_AST_EXPR_FLOAT_LIT:
case SPL_AST_EXPR_CHAR_LIT:
case SPL_AST_EXPR_STRING_LIT:
case SPL_AST_EXPR_TRUE:
case SPL_AST_EXPR_FALSE:
case SPL_AST_EXPR_NULL:
case SPL_AST_EXPR_UNDEFINED:
case SPL_AST_EXPR_IDENT:
break;
case SPL_AST_ARGGREGATE_INIT:
dump_vec(ast, node->primary_expr.aggregate_init.expr, stack);
break;
case SPL_AST_EXPR_EXPR:
if (node->primary_expr.expr)
dump_node(ast, node->primary_expr.expr, stack, 1);
break;
case SPL_AST_ARRAY_LIT:
if (node->primary_expr.array_lit_expr.type_expr)
dump_node(ast, node->primary_expr.array_lit_expr.type_expr, stack, 0);
dump_vec(ast, node->primary_expr.array_lit_expr.expr_list, stack);
break;
case SPL_AST_BUILTIN_EXPR:
dump_vec(ast, node->primary_expr.builtin_expr.expr_list, stack);
break;
case SPL_AST_BLOCK_EXPR:
dump_vec(ast, node->primary_expr.block_expr, stack);
break;
case SPL_AST_BASE_TYPE_FN:
dump_vec(ast, node->type_expr.attr_list, stack);
dump_vec(ast, node->type_expr.fn_type.param_list, stack);
if (node->type_expr.fn_type.type_expr)
dump_node(ast, node->type_expr.fn_type.type_expr, stack, 1);
break;
case SPL_AST_BASE_TYPE_PATH:
dump_vec(ast, node->type_expr.attr_list, stack);
break;
case SPL_AST_TYPE_POINTER:
dump_vec(ast, node->type_expr.attr_list, stack);
if (node->type_expr.pointer_type.pointee)
dump_node(ast, node->type_expr.pointer_type.pointee, stack, 1);
break;
case SPL_AST_TYPE_SLICE:
dump_vec(ast, node->type_expr.attr_list, stack);
if (node->type_expr.slice_type.element)
dump_node(ast, node->type_expr.slice_type.element, stack, 1);
break;
case SPL_AST_TYPE_ARRAY:
dump_vec(ast, node->type_expr.attr_list, stack);
if (node->type_expr.array_type.element)
dump_node(ast, node->type_expr.array_type.element, stack, 0);
if (node->type_expr.array_type.size)
dump_node(ast, node->type_expr.array_type.size, stack, 1);
break;
case SPL_AST_TYPE_STRUCT:
case SPL_AST_TYPE_UNION:
case SPL_AST_TYPE_ENUM:
dump_vec(ast, node->type_expr.attr_list, stack);
dump_vec(ast, node->type_expr.aggregate_list, stack);
break;
case SPL_AST_TYPE_VOID:
case SPL_AST_TYPE_BOOL:
case SPL_AST_TYPE_OPAQUE:
case SPL_AST_TYPE_I8:
case SPL_AST_TYPE_U8:
case SPL_AST_TYPE_I16:
case SPL_AST_TYPE_U16:
case SPL_AST_TYPE_I32:
case SPL_AST_TYPE_U32:
case SPL_AST_TYPE_I64:
case SPL_AST_TYPE_U64:
case SPL_AST_TYPE_ISIZE:
case SPL_AST_TYPE_USIZE:
case SPL_AST_TYPE__F32:
case SPL_AST_TYPE__F64:
case SPL_AST_TYPE_ANY:
case SPL_AST_TYPE_IDENT:
break;
case SPL_AST__COMPTIME_STMT:
case SPL_AST__DIRECTIVE_BLOCK:
case SPL_AST_TRY_STATEMENT:
case SPL_AST_CATCH_STATEMENT:
case SPL_AST_ERRDEFER_STATEMEMT:
case SPL_AST_EXPR_STATEMENT:
case SPL_AST_BREAK_STATEMENT:
case SPL_AST_CONTINUE_STATEMENT:
break;
case SPL_AST_COUNT:
UNREACHABLE();
break;
}
(void)vec_pop(*stack);
}