2151 lines
66 KiB
C
2151 lines
66 KiB
C
#include "spl_ast.h"
|
||
#include "spl_dbg.h"
|
||
#include "spl_dumptree.h"
|
||
#include "spl_tok.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_AS for 专用 */
|
||
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.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 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, ¶m_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_MEMBERS, begin);
|
||
node_at(ast, root)->container_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;
|
||
}
|
||
|
||
spl_ast_node_t *spl_ast_node(spl_ast_t *ast, spl_ast_node_ref_t node) {
|
||
if (!ast || node == 0)
|
||
return NULL;
|
||
return &vec_at(ast->node_buckets, 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, 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.fname)
|
||
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_MEMBERS:
|
||
dump_vec(ast, node->container_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);
|
||
}
|