Files
spl/stage1/spl_parser.c
T

2306 lines
71 KiB
C

#include "spl_parser.h"
#include "spl_lexer.h"
#include "spl_tok.h"
#define MOVE_VEC(dst, src) \
do { \
(dst) = (src); \
vec_init(src); \
} while (0)
static char *sdupn(const char *s, usize n) {
char *r = malloc(n + 1);
if (!r)
return NULL;
memcpy(r, s, n);
r[n] = '\0';
return r;
}
static spl_dbg_node_t tok_to_dbg(const spl_tok_t *t) {
spl_dbg_node_t d = {0};
if (t) {
d.fname = t->fname;
d.line = (int)t->line;
d.col = (int)t->col;
}
return d;
}
static void tok_desc(const spl_tok_t *t, char *buf, usize cap) {
if (!t) {
snprintf(buf, cap, "<no token>");
return;
}
if (t->type == TOK_EOF) {
snprintf(buf, cap, "EOF");
return;
}
const char *kind = spl_tok_type_name(t->type);
if (t->type == TOK_ENDLINE) {
snprintf(buf, cap, "ENDLINE at %zu:%zu", t->line, t->col);
return;
}
if (!t->lexeme || t->len == 0) {
snprintf(buf, cap, "%s at %zu:%zu", kind, t->line, t->col);
return;
}
int n = (int)(t->len > 32 ? 32 : t->len);
snprintf(buf, cap, "%s `%.*s` at %s:%zu:%zu", kind, n, t->lexeme, t->fname, t->line, t->col);
}
#define PARSE_ERROR(p, kind, tok, fmt, ...) \
do { \
(p)->error_count++; \
if ((p)->diag) { \
char _tb[80]; \
tok_desc((tok), _tb, sizeof _tb); \
spl_dbg_node_t _pd = tok_to_dbg(tok); \
spl_diag_error((p)->diag, (kind), &_pd, fmt " (got %s)", ##__VA_ARGS__, _tb); \
} \
} while (0)
#define PARSE_FATAL(p, kind, tok, fmt, ...) \
do { \
(p)->failed = 1; \
(p)->error_count++; \
if ((p)->diag) { \
char _tb[80]; \
tok_desc((tok), _tb, sizeof _tb); \
spl_dbg_node_t _pd = tok_to_dbg(tok); \
spl_diag_fatal((p)->diag, (kind), &_pd, fmt " (got %s)", ##__VA_ARGS__, _tb); \
} \
} while (0)
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(spl_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(spl_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(spl_parser_t *p, spl_ast_node_kind_t kind,
const spl_tok_t *tok) {
spl_ast_node_t n = {0};
n.kind = kind;
n.resolved_def_id = 0;
n.resolved_lang_tid = 0;
vec_init(n.attrs);
if (tok) {
n.dbg.fname = tok->fname;
n.dbg.line = (int)tok->line;
n.dbg.col = (int)tok->col;
}
vec_push(p->ast->node_buckets, n);
return p->ast->node_buckets.size - 1;
}
static char *intern_string(spl_ast_t *ast, const char *s, usize len) {
char *copy = sdupn(s, len);
if (!copy)
return NULL;
vec_push(ast->str_buckets, copy);
return copy;
}
#define SET_STR_FIELD(ast, field, tok) \
do { \
(field) = intern_string(ast, (tok)->lexeme, (tok)->len); \
} while (0)
static int expect(spl_parser_t *p, spl_tok_type_t tt, const char *what) {
const spl_tok_t *t = peek(p);
if (!t || t->type != tt) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected %s", what);
return 0;
}
advance(p);
return 1;
}
static isize parse_int_literal(const spl_tok_t *t) {
char buf[128];
usize j = 0;
for (usize i = 0; i < t->len && j < sizeof(buf) - 1; i++) {
if (t->lexeme[i] != '_')
buf[j++] = t->lexeme[i];
}
buf[j] = 0;
if (j >= 3 && buf[0] == '0' && (buf[1] == 'b' || buf[1] == 'B'))
return (isize)strtoull(buf + 2, NULL, 2);
if (j >= 3 && buf[0] == '0' && (buf[1] == 'o' || buf[1] == 'O'))
return (isize)strtoull(buf + 2, NULL, 8);
if (j >= 3 && buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X'))
return (isize)strtoull(buf, NULL, 16);
return (isize)strtoull(buf, NULL, 10);
}
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 *s = t->lexeme + 1;
const char *end = t->lexeme + t->len - 1;
char c = 0;
if (s < end)
spl_decode_escape(&s, &c);
return c;
}
static char *parse_string_literal(spl_parser_t *p, const spl_tok_t *t, usize *out_len) {
const char *src = t->lexeme + 1;
const char *end = t->lexeme + t->len - 1;
usize cap = t->len + 1;
char *tmp = malloc(cap);
if (!tmp) {
*out_len = 0;
return NULL;
}
char *dst = tmp;
while (src < end) {
char c;
if (spl_decode_escape(&src, &c) == 0) {
*dst++ = c;
} else {
*dst++ = *src;
src++;
}
}
*out_len = (usize)(dst - tmp);
char *interned = intern_string(p->ast, tmp, dst - tmp);
free(tmp);
return interned;
}
static int can_start_expr(spl_tok_type_t t) {
switch (t) {
case TOK_INT_LITERAL:
case TOK_FLOAT_LITERAL:
case TOK_CHAR_LITERAL:
case TOK_STRING_LITERAL:
case KW_TRUE:
case KW_FALSE:
case KW_NULL:
case KW_UNDEFINED:
case TOK_IDENT:
case TOK_AT:
case TOK_SHARP:
case TOK_DOLLAR:
case TOK_L_PAREN:
case TOK_L_BRACKET:
case TOK_L_BRACE:
case TOK_DOT:
case TOK_SUB:
case TOK_NOT:
case TOK_BIT_NOT:
case TOK_AND:
case TOK_MUL:
case KW_IF:
case KW_WHILE:
case KW_LOOP:
case KW_FOR:
case KW_MATCH:
return 1;
default:
return 0;
}
}
static int can_start_statement(spl_tok_type_t t) {
switch (t) {
case KW_IF:
case KW_WHILE:
case KW_LOOP:
case KW_FOR:
case KW_MATCH:
case KW_RET:
case KW_BREAK:
case KW_CONTINUE:
case KW_DEFER:
case KW_VAR:
case KW_CONST:
case KW_TYPE:
case KW_COMPTIME:
return 1;
default:
return 0;
}
}
static int is_builtin_type_kw(spl_tok_type_t t) {
switch (t) {
// case KW_I8:
// case KW_U8:
// case KW_I16:
// case KW_U16:
// case KW_I32:
// case KW_U32:
// case KW_I64:
// case KW_U64:
// case KW_F32:
// case KW_F64:
// case KW_ISIZE:
// case KW_USIZE:
case KW_BOOL:
// case KW_VOID:
// case KW_PTR:
case KW_ANY:
return 1;
default:
return 0;
}
}
static spl_ast_node_ref_t parse_expr(spl_parser_t *p);
static spl_ast_node_ref_vec_t parse_expr_list(spl_parser_t *p);
static spl_ast_node_ref_t parse_block(spl_parser_t *p);
static spl_ast_node_ref_t parse_type_expr(spl_parser_t *p);
static spl_ast_node_ref_t parse_type_comptime_call(spl_parser_t *p);
static spl_ast_node_ref_t parse_statement(spl_parser_t *p);
static spl_ast_node_ref_t parse_container_declaration(spl_parser_t *p);
static spl_ast_node_ref_t parse_param_decl_impl(spl_parser_t *p);
static spl_ast_node_ref_t parse_pattern(spl_parser_t *p);
static spl_ast_node_ref_t parse_pattern_atom(spl_parser_t *p);
static spl_ast_node_ref_t parse_pattern_aggregate(spl_parser_t *p, const spl_tok_t *start);
static spl_ast_node_ref_t parse_cast(spl_parser_t *p);
static spl_ast_node_ref_t parse_prefix(spl_parser_t *p);
static spl_ast_node_ref_t parse_postfix(spl_parser_t *p);
static spl_ast_node_ref_t parse_primary(spl_parser_t *p);
static spl_ast_node_ref_vec_t parse_aggregate_fields(spl_parser_t *p);
static spl_ast_node_ref_t parse_array_literal(spl_parser_t *p);
static spl_ast_node_ref_t parse_comptime_call(spl_parser_t *p);
static spl_ast_node_ref_t parse_if_expr(spl_parser_t *p);
static spl_ast_node_ref_t parse_while_expr(spl_parser_t *p);
static spl_ast_node_ref_t parse_loop_expr(spl_parser_t *p);
static spl_ast_node_ref_t parse_for_expr(spl_parser_t *p);
static spl_ast_node_ref_t parse_match_expr(spl_parser_t *p);
static spl_ast_node_ref_t parse_ret_stmt(spl_parser_t *p);
static spl_ast_node_ref_t parse_break_stmt(spl_parser_t *p);
static spl_ast_node_ref_t parse_continue_stmt(spl_parser_t *p);
static spl_ast_node_ref_t parse_defer_stmt(spl_parser_t *p);
static spl_ast_node_ref_t parse_comptime_stmt(spl_parser_t *p);
static spl_ast_node_ref_t parse_label(spl_parser_t *p);
/* ---------- Pattern ---------- */
static spl_ast_node_ref_t parse_pattern_atom(spl_parser_t *p) {
const spl_tok_t *t = peek(p);
if (!t)
return 0;
switch (t->type) {
case KW_UNDERSCORE:
advance(p);
return new_node(p, SPL_AST_PATTERN_UNDERSCORE, t);
case TOK_DOT: {
advance(p);
const spl_tok_t *nx = peek(p);
if (nx && nx->type == TOK_L_BRACE)
return parse_pattern_aggregate(p, t);
if (!nx || nx->type != TOK_IDENT) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, nx, "expected variant name after '.'");
return 0;
}
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_PATTERN_DOT, t);
spl_ast_node_t *pat = node_at(p->ast, ref);
SET_STR_FIELD(p->ast, pat->pattern_dot.name, nx);
pat->pattern_dot.sub_pattern = 0;
if (peek(p) && peek(p)->type == TOK_L_PAREN) {
advance(p);
if (peek(p) && peek(p)->type != TOK_R_PAREN) {
spl_ast_node_ref_t sub = parse_pattern(p);
node_at(p->ast, ref)->pattern_dot.sub_pattern = sub;
}
expect(p, TOK_R_PAREN, "')' after variant payload");
}
return ref;
}
case TOK_L_PAREN: {
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_PATTERN_TUPLE, t);
spl_ast_node_t *tuple = node_at(p->ast, ref);
vec_init(tuple->pattern_tuple.patterns);
if (peek(p) && peek(p)->type == TOK_R_PAREN) {
advance(p);
return ref;
}
spl_ast_node_ref_t inner = parse_pattern(p);
expect(p, TOK_R_PAREN, "')' in tuple pattern");
tuple = node_at(p->ast, ref);
if (inner && node_at(p->ast, inner)->kind == SPL_AST_PATTERN_LIST) {
spl_ast_node_t *inner_node = node_at(p->ast, inner);
MOVE_VEC(tuple->pattern_tuple.patterns, inner_node->pattern_list.patterns);
} else if (inner) {
vec_push(tuple->pattern_tuple.patterns, inner);
}
return ref;
}
case TOK_INT_LITERAL: {
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_INT_LIT, t);
node_at(p->ast, ref)->int_lit.bits = (uint64_t)parse_int_literal(t);
return ref;
}
case TOK_FLOAT_LITERAL: {
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_FLOAT_LIT, t);
node_at(p->ast, ref)->float_lit.bits = parse_float_literal(t);
return ref;
}
case TOK_CHAR_LITERAL: {
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_CHAR_LIT, t);
node_at(p->ast, ref)->char_lit.val = parse_char_literal(t);
return ref;
}
case TOK_STRING_LITERAL: {
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_STRING_LIT, t);
usize len = 0;
const char *data = parse_string_literal(p, t, &len);
spl_ast_node_t *node = node_at(p->ast, ref);
node->string_lit.data = data;
node->string_lit.len = len;
return ref;
}
case KW_TRUE:
case KW_FALSE: {
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_BOOL_LIT, t);
node_at(p->ast, ref)->bool_lit.val = (t->type == KW_TRUE);
return ref;
}
case KW_NULL:
advance(p);
return new_node(p, SPL_AST_EXPR_NULL_LIT, t);
case TOK_IDENT: {
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_PATTERN_IDENT, t);
SET_STR_FIELD(p->ast, node_at(p->ast, ref)->pattern_ident.name, t);
return ref;
}
case TOK_AND: {
/* `&name`:解包左值引用绑定。仅允许作用于绑定名。 */
advance(p);
const spl_tok_t *nx = peek(p);
if (!nx || nx->type != TOK_IDENT) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, nx, "expected binding name after '&'");
return 0;
}
spl_ast_node_ref_t inner = parse_pattern_atom(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_PATTERN_REF, t);
node_at(p->ast, ref)->pattern_ref.pat = inner;
return ref;
}
default:
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, "unexpected token in pattern");
return 0;
}
}
static spl_ast_node_ref_t parse_pattern_aggregate(spl_parser_t *p, const spl_tok_t *start) {
/* 已消费 '.',当前应为 '{' */
if (!expect(p, TOK_L_BRACE, "'{' after '.'"))
return 0;
spl_ast_node_ref_t ref = new_node(p, SPL_AST_PATTERN_AGGREGATE, start);
spl_ast_node_t *agg = node_at(p->ast, ref);
vec_init(agg->pattern_aggregate.fields);
while (!p->failed) {
const spl_tok_t *t = peek(p);
if (!t || t->type == TOK_R_BRACE || t->type == TOK_EOF)
break;
if (t->type != TOK_DOT) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '.' in aggregate pattern");
break;
}
advance(p);
const spl_tok_t *name = peek(p);
if (!name || name->type != TOK_IDENT) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, name, "expected field name");
break;
}
advance(p);
spl_ast_node_ref_t field = new_node(p, SPL_AST_PATTERN_FIELD, name);
spl_ast_node_t *f = node_at(p->ast, field);
SET_STR_FIELD(p->ast, f->pattern_field.name, name);
f->pattern_field.pattern = 0;
if (peek(p) && peek(p)->type == TOK_ASSIGN) {
advance(p);
spl_ast_node_ref_t sub = parse_pattern_atom(p);
f = node_at(p->ast, field);
f->pattern_field.pattern = sub;
}
agg = node_at(p->ast, ref);
vec_push(agg->pattern_aggregate.fields, field);
t = peek(p);
if (t && (t->type == TOK_COMMA || t->type == TOK_SEMICOLON)) {
advance(p);
continue;
}
break;
}
expect(p, TOK_R_BRACE, "'}' in aggregate pattern");
return ref;
}
static spl_ast_node_ref_t parse_pattern(spl_parser_t *p) {
spl_ast_node_ref_vec_t atoms;
vec_init(atoms);
while (!p->failed) {
spl_ast_node_ref_t atom = parse_pattern_atom(p);
if (!atom)
break;
vec_push(atoms, atom);
const spl_tok_t *t = peek(p);
if (t && t->type == TOK_COMMA) {
advance(p);
continue;
}
break;
}
if (atoms.size == 0)
return 0;
if (atoms.size == 1) {
spl_ast_node_ref_t r = atoms.data[0];
vec_free(atoms);
return r;
}
spl_ast_node_ref_t ref = new_node(p, SPL_AST_PATTERN_LIST, peek(p));
node_at(p->ast, ref)->pattern_list.patterns = atoms;
return ref;
}
/* ---------- 声明 ---------- */
static void parse_tag_list(spl_parser_t *p, spl_ast_node_ref_vec_t *out, int is_external,
int allow_at) {
while (!p->failed) {
const spl_tok_t *t = peek(p);
if (!t || (t->type != TOK_AT && t->type != TOK_SHARP))
return;
if (!allow_at && t->type == TOK_AT)
return;
int is_at = (t->type == TOK_AT);
advance(p);
if (is_external) {
t = peek(p);
if (!t || t->type != TOK_NOT) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '!' in external tag");
return;
}
advance(p);
}
t = peek(p);
if (!t || t->type != TOK_IDENT) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected tag name");
return;
}
advance(p);
spl_ast_node_ref_t ref =
new_node(p, is_external ? SPL_AST_EXTERNAL_TAG_ITEM : SPL_AST_TAG_ITEM, t);
spl_ast_node_t *tag = node_at(p->ast, ref);
tag->tag_item.is_at = is_at;
tag->tag_item.is_external = is_external;
SET_STR_FIELD(p->ast, tag->tag_item.name, t);
t = peek(p);
if (t && t->type == TOK_L_PAREN) {
advance(p);
spl_ast_node_ref_vec_t args = parse_expr_list(p);
node_at(p->ast, ref)->tag_item.args = args;
if (!expect(p, TOK_R_PAREN, "')' in tag args"))
return;
}
vec_push(*out, ref);
}
}
static void parse_param_list(spl_parser_t *p, spl_ast_node_ref_vec_t *out) {
while (!p->failed) {
const spl_tok_t *t = peek(p);
if (!t)
break;
if (t->type == TOK_R_PAREN) {
break;
} else if (t->type == TOK_AT || t->type == TOK_SHARP || t->type == TOK_IDENT) {
spl_ast_node_ref_t pd = parse_param_decl_impl(p);
if (pd)
vec_push(*out, pd);
if (peek(p) && peek(p)->type == TOK_COMMA) {
advance(p);
continue;
}
break;
} else if (t->type == TOK_ELLIPSIS) {
advance(p);
spl_ast_node_ref_t pd = new_node(p, SPL_AST_PARAM_DECL, t);
node_at(p->ast, pd)->param_decl.name = NULL;
node_at(p->ast, pd)->param_decl.type_expr = 0;
vec_push(*out, pd);
if (peek(p) && peek(p)->type == TOK_COMMA)
advance(p);
break;
} else {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t,
"unexpected token in parameter list");
break;
}
}
}
static spl_ast_node_ref_t parse_param_decl_impl(spl_parser_t *p) {
spl_ast_node_ref_vec_t attr_list;
vec_init(attr_list);
parse_tag_list(p, &attr_list, 0, 1);
const spl_tok_t *name = peek(p);
if (!name || (name->type != TOK_IDENT && name->type != KW_UNDERSCORE)) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, name, "expected parameter name or '_'");
vec_free(attr_list);
return 0;
}
advance(p);
if (!expect(p, TOK_COLON, "':' in parameter declaration")) {
vec_free(attr_list);
return 0;
}
parse_tag_list(p, &attr_list, 0, 0);
spl_ast_node_ref_t type_expr = parse_type_expr(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_PARAM_DECL, name);
spl_ast_node_t *param = node_at(p->ast, ref);
MOVE_VEC(param->param_decl.attr_list, attr_list);
SET_STR_FIELD(p->ast, param->param_decl.name, name);
param->param_decl.type_expr = type_expr;
return ref;
}
static spl_ast_node_ref_t parse_fn_decl(spl_parser_t *p, spl_ast_node_ref_vec_t tag_list) {
const spl_tok_t *kw = peek(p);
if (!kw || kw->type != KW_FN)
return 0;
advance(p);
const spl_tok_t *name = peek(p);
if (!name || name->type != TOK_IDENT) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, name ? name : kw, "expected function name");
vec_free(tag_list);
return 0;
}
advance(p);
if (!expect(p, TOK_L_PAREN, "'(' in function declaration")) {
vec_free(tag_list);
return 0;
}
spl_ast_node_ref_vec_t params;
vec_init(params);
parse_param_list(p, &params);
if (!expect(p, TOK_R_PAREN, "')' in function declaration")) {
vec_free(tag_list);
vec_free(params);
return 0;
}
spl_ast_node_ref_t ret_type = 0;
const spl_tok_t *t = peek(p);
if (t && t->type == TOK_COLON) {
advance(p);
ret_type = parse_type_expr(p);
t = peek(p);
}
spl_ast_node_ref_t body = 0;
if (t && t->type == TOK_L_BRACE) {
body = parse_block(p);
} else if (t && t->type == TOK_SEMICOLON) {
advance(p);
} else {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t,
"function declaration must end with ';' or block");
vec_free(tag_list);
vec_free(params);
return 0;
}
spl_ast_node_ref_t ref = new_node(p, SPL_AST_FN_DECL, kw);
spl_ast_node_t *fn = node_at(p->ast, ref);
MOVE_VEC(fn->fn_decl.tag_list, tag_list);
fn->fn_decl.is_comptime = 0;
SET_STR_FIELD(p->ast, fn->fn_decl.name, name);
fn->fn_decl.params = params;
fn->fn_decl.ret_type = ret_type;
fn->fn_decl.body = body;
return ref;
}
static spl_ast_node_ref_t parse_type_decl(spl_parser_t *p, spl_ast_node_ref_vec_t tag_list) {
const spl_tok_t *kw = peek(p);
if (!kw || kw->type != KW_TYPE)
return 0;
advance(p);
spl_ast_node_ref_t pattern = parse_pattern(p);
if (!pattern) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, peek(p), "expected pattern after 'type'");
vec_free(tag_list);
return 0;
}
if (!expect(p, TOK_ASSIGN, "'=' in type declaration")) {
vec_free(tag_list);
return 0;
}
spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_DECL, kw);
spl_ast_node_t *td = node_at(p->ast, ref);
MOVE_VEC(td->type_decl.attr_list, tag_list);
td->type_decl.pattern = pattern;
spl_ast_node_ref_t type_expr = parse_type_expr(p);
td = node_at(p->ast, ref); /* parse_type_expr 可能 push node_buckets,重新取 */
td->type_decl.type_expr = type_expr;
const spl_tok_t *t = peek(p);
if (t && (t->type == TOK_COMMA || t->type == TOK_SEMICOLON))
advance(p);
return ref;
}
static spl_ast_node_ref_t parse_var_const_decl(spl_parser_t *p, spl_ast_node_ref_vec_t tag_list,
int is_const) {
const spl_tok_t *kw = peek(p);
if (!kw)
return 0;
if (is_const && kw->type != KW_CONST)
return 0;
if (!is_const && kw->type != KW_VAR)
return 0;
advance(p);
spl_ast_node_ref_t pattern = parse_pattern(p);
if (!pattern) {
vec_free(tag_list);
return 0;
}
spl_ast_node_ref_t type_expr = 0;
spl_ast_node_ref_t init_expr = 0;
const spl_tok_t *t = peek(p);
if (t && t->type == TOK_COLON) {
advance(p);
type_expr = parse_type_expr(p);
t = peek(p);
if (t && t->type == TOK_ASSIGN) {
advance(p);
init_expr = parse_expr(p);
}
} else if (t && t->type == TOK_ASSIGN) {
advance(p);
init_expr = parse_expr(p);
}
spl_ast_node_ref_t ref = new_node(p, is_const ? SPL_AST_CONST_DECL : SPL_AST_VAR_DECL, kw);
spl_ast_node_t *vc = node_at(p->ast, ref);
MOVE_VEC(vc->var_const_decl.attr_list, tag_list);
vc->var_const_decl.pattern = pattern;
vc->var_const_decl.type = type_expr;
vc->var_const_decl.init_expr = init_expr;
t = peek(p);
if (t && t->type == TOK_SEMICOLON)
advance(p);
return ref;
}
static spl_ast_node_ref_t parse_member_decl(spl_parser_t *p, spl_ast_node_ref_vec_t tag_list) {
const spl_tok_t *name = peek(p);
if (!name || name->type != TOK_IDENT)
return 0;
advance(p);
spl_ast_node_ref_t type_expr = 0;
spl_ast_node_ref_t init_expr = 0;
const spl_tok_t *t = peek(p);
if (t && t->type == TOK_COLON) {
advance(p);
parse_tag_list(p, &tag_list, 0, 0);
type_expr = parse_type_expr(p);
t = peek(p);
if (t && t->type == TOK_ASSIGN) {
advance(p);
init_expr = parse_expr(p);
}
} else if (t && t->type == TOK_ASSIGN) {
advance(p);
init_expr = parse_expr(p);
}
spl_ast_node_ref_t ref = new_node(p, SPL_AST_MEMBER_DECL, name);
spl_ast_node_t *md = node_at(p->ast, ref);
MOVE_VEC(md->member_decl.attr_list, tag_list);
SET_STR_FIELD(p->ast, md->member_decl.name, name);
md->member_decl.type_expr = type_expr;
md->member_decl.init_expr = init_expr;
t = peek(p);
if (t && (t->type == TOK_COMMA || t->type == TOK_SEMICOLON))
advance(p);
return ref;
}
static spl_ast_node_ref_t parse_comptime_decl(spl_parser_t *p) {
const spl_tok_t *kw = peek(p);
if (!kw || kw->type != KW_COMPTIME)
return 0;
advance(p);
spl_ast_node_ref_t body = 0;
const spl_tok_t *t = peek(p);
if (t && t->type == TOK_L_BRACE)
body = parse_block(p);
else
body = parse_expr(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_COMPTIME_DECL, kw);
node_at(p->ast, ref)->comptime_decl.body = body;
return ref;
}
static spl_ast_node_ref_t parse_container_declaration(spl_parser_t *p) {
spl_ast_node_ref_vec_t tag_list;
vec_init(tag_list);
parse_tag_list(p, &tag_list, 0, 0);
const spl_tok_t *t = peek(p);
if (!t || t->type == TOK_EOF) {
vec_free(tag_list);
return 0;
}
switch (t->type) {
case KW_FN:
return parse_fn_decl(p, tag_list);
case KW_TYPE:
return parse_type_decl(p, tag_list);
case KW_VAR:
return parse_var_const_decl(p, tag_list, 0);
case KW_CONST:
return parse_var_const_decl(p, tag_list, 1);
case TOK_IDENT:
return parse_member_decl(p, tag_list);
case KW_COMPTIME:
vec_free(tag_list);
return parse_comptime_decl(p);
case TOK_L_BRACE: {
spl_ast_node_ref_t block = parse_block(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_TOP_LEVEL_BLOCK, t);
spl_ast_node_t *tb = node_at(p->ast, ref);
MOVE_VEC(tb->top_level_block.tag_list, tag_list);
tb->top_level_block.block = block;
return ref;
}
default:
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, "unrecognized declaration");
advance(p); /* 消费该 token,避免调用方在错误恢复时原地死循环 */
vec_free(tag_list);
return 0;
}
}
/* ---------- 类型 ---------- */
static spl_ast_node_ref_t parse_type_base(spl_parser_t *p) {
const spl_tok_t *bt = peek(p);
if (!bt) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, bt, "expected type");
return 0;
}
if (bt->type == KW_FN) {
advance(p);
if (!expect(p, TOK_L_PAREN, "'(' in function type"))
return 0;
spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_FN, bt);
spl_ast_node_t *fn_type = node_at(p->ast, ref);
fn_type->type_fn.is_comptime = 0;
vec_init(fn_type->type_fn.params);
while (!p->failed && peek(p) && peek(p)->type != TOK_R_PAREN) {
spl_ast_node_ref_t pt = parse_type_expr(p);
fn_type = node_at(p->ast, ref);
vec_push(fn_type->type_fn.params, pt);
if (peek(p) && peek(p)->type == TOK_COMMA) {
advance(p);
continue;
}
break;
}
if (!expect(p, TOK_R_PAREN, "')' in function type"))
return ref;
if (peek(p) && peek(p)->type == TOK_COLON) {
advance(p);
spl_ast_node_ref_t ret = parse_type_expr(p);
node_at(p->ast, ref)->type_fn.ret_type = ret;
}
return ref;
}
if (bt->type == KW_STRUCT || bt->type == KW_UNION || bt->type == KW_ENUM ||
bt->type == KW_SHAPE) {
const char *kind_name = (bt->type == KW_STRUCT) ? "struct"
: (bt->type == KW_UNION) ? "union"
: (bt->type == KW_ENUM) ? "enum"
: "shape";
advance(p);
if (!expect(p, TOK_L_BRACE, "'{' in aggregate type"))
return 0;
spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_AGGREGATE, bt);
spl_ast_node_t *agg = node_at(p->ast, ref);
agg->type_aggregate.kind_name = kind_name;
vec_init(agg->type_aggregate.members);
while (!p->failed) {
const spl_tok_t *t = peek(p);
if (!t || t->type == TOK_EOF) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "aggregate type missing '}'");
return ref;
}
if (t->type == TOK_R_BRACE) {
advance(p);
break;
}
spl_ast_node_ref_t member = parse_container_declaration(p);
if (member) {
agg = node_at(p->ast, ref);
vec_push(agg->type_aggregate.members, member);
}
t = peek(p);
if (t && (t->type == TOK_COMMA || t->type == TOK_SEMICOLON))
advance(p);
}
return ref;
}
/* 内建类型 keyword + 普通标识符类型路径 */
if (bt->type == TOK_IDENT || is_builtin_type_kw(bt->type)) {
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_PATH, bt);
spl_ast_node_t *tp = node_at(p->ast, ref);
SET_STR_FIELD(p->ast, tp->type_path.name, bt);
vec_init(tp->type_path.generic_args);
return ref;
}
if (bt->type == TOK_AT || bt->type == TOK_SHARP)
return parse_type_comptime_call(p);
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, bt, "unrecognized type");
return 0;
}
static spl_ast_node_ref_t parse_type_comptime_call(spl_parser_t *p) {
const spl_tok_t *start = peek(p);
if (!start || (start->type != TOK_AT && start->type != TOK_SHARP))
return 0;
advance(p);
const spl_tok_t *name = peek(p);
if (!name || name->type != TOK_IDENT) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, name, "expected comptime name");
return 0;
}
advance(p);
spl_ast_node_ref_vec_t args;
vec_init(args);
const spl_tok_t *t = peek(p);
if (t && t->type == TOK_L_PAREN) {
advance(p);
args = parse_expr_list(p);
if (!expect(p, TOK_R_PAREN, "')' in comptime type")) {
vec_free(args);
return 0;
}
}
spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_COMPTIME_CALL, start);
spl_ast_node_t *cc = node_at(p->ast, ref);
SET_STR_FIELD(p->ast, cc->type_comptime_call.name, name);
cc->type_comptime_call.args = args;
return ref;
}
static spl_ast_node_ref_t parse_type_expr(spl_parser_t *p) {
const spl_tok_t *t = peek(p);
if (!t) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected type");
return 0;
}
if (t->type == TOK_MUL) {
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_POINTER, t);
spl_ast_node_ref_t pointee = parse_type_expr(p);
node_at(p->ast, ref)->type_pointer.pointee = pointee;
return ref;
}
if (t->type == TOK_L_BRACKET) {
advance(p);
bool has_len = false;
isize len = 0;
bool is_underscore = false;
t = peek(p);
if (t && t->type == TOK_INT_LITERAL) {
len = parse_int_literal(t);
has_len = true;
advance(p);
} else if (t && t->type == KW_UNDERSCORE) {
has_len = true;
is_underscore = true;
advance(p);
}
if (!expect(p, TOK_R_BRACKET, "']' in array type"))
return 0;
spl_ast_node_ref_t elem_type = parse_type_expr(p);
spl_ast_node_ref_t ref;
if (has_len) {
ref = new_node(p, SPL_AST_TYPE_ARRAY, t);
spl_ast_node_t *arr = node_at(p->ast, ref);
arr->type_array.has_len = true;
arr->type_array.len = len;
arr->type_array.is_underscore_len = is_underscore;
arr->type_array.elem_type = elem_type;
} else {
ref = new_node(p, SPL_AST_TYPE_SLICE, t);
node_at(p->ast, ref)->type_slice.elem_type = elem_type;
}
return ref;
}
if (t->type == TOK_L_PAREN) {
advance(p);
spl_ast_node_ref_vec_t types;
vec_init(types);
if (peek(p) && peek(p)->type == TOK_R_PAREN) {
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_PAREN, t);
node_at(p->ast, ref)->type_paren.types = types;
return ref;
}
spl_ast_node_ref_t first = parse_type_expr(p);
vec_push(types, first);
while (peek(p) && peek(p)->type == TOK_COMMA) {
advance(p);
if (peek(p) && peek(p)->type == TOK_R_PAREN)
break;
spl_ast_node_ref_t next = parse_type_expr(p);
vec_push(types, next);
}
if (!expect(p, TOK_R_PAREN, "')' in parenthesized type"))
return 0;
if (types.size == 1) {
vec_free(types);
return first;
}
spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_PAREN, t);
node_at(p->ast, ref)->type_paren.types = types;
return ref;
}
spl_ast_node_ref_t base = parse_type_base(p);
if (p->failed || !base)
return base;
while (peek(p) && peek(p)->type == TOK_DOT) {
const spl_tok_t *dot = peek(p);
advance(p);
const spl_tok_t *seg = peek(p);
if (!seg || seg->type != TOK_IDENT) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, seg ? seg : dot,
"type: expected identifier after '.'");
return base;
}
advance(p);
spl_ast_node_ref_t sel = new_node(p, SPL_AST_EXPR_FIELD, dot);
node_at(p->ast, sel)->field.obj = base;
SET_STR_FIELD(p->ast, node_at(p->ast, sel)->field.field, seg);
base = sel;
}
return base;
}
/* ---------- 表达式 ---------- */
static spl_ast_node_ref_vec_t parse_expr_list(spl_parser_t *p) {
spl_ast_node_ref_vec_t vec;
vec_init(vec);
if (p->failed)
return vec;
const spl_tok_t *t = peek(p);
if (!t || !can_start_expr(t->type))
return vec;
vec_push(vec, parse_expr(p));
while (!p->failed && peek(p) && peek(p)->type == TOK_COMMA) {
advance(p);
if (!peek(p) || !can_start_expr(peek(p)->type))
break;
vec_push(vec, parse_expr(p));
}
return vec;
}
static spl_ast_node_ref_vec_t parse_aggregate_fields(spl_parser_t *p) {
spl_ast_node_ref_vec_t fields;
vec_init(fields);
if (!expect(p, TOK_L_BRACE, "'{' in aggregate literal"))
return fields;
while (!p->failed) {
const spl_tok_t *t = peek(p);
if (!t || t->type == TOK_R_BRACE || t->type == TOK_EOF)
break;
if (t->type != TOK_DOT) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '.' in aggregate field");
break;
}
advance(p);
t = peek(p);
if (!t || t->type != TOK_IDENT) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected field name after '.'");
break;
}
advance(p);
spl_ast_node_ref_t item_ref = new_node(p, SPL_AST_STRUCT_INIT_ITEM, t);
spl_ast_node_t *item = node_at(p->ast, item_ref);
SET_STR_FIELD(p->ast, item->struct_init_item.name, t);
item->struct_init_item.expr = 0;
if (peek(p) && peek(p)->type == TOK_ASSIGN) {
advance(p);
spl_ast_node_ref_t expr_ref = parse_expr(p);
item = node_at(p->ast, item_ref);
item->struct_init_item.expr = expr_ref;
}
vec_push(fields, item_ref);
t = peek(p);
if (t && (t->type == TOK_COMMA || t->type == TOK_SEMICOLON)) {
advance(p);
continue;
}
break;
}
expect(p, TOK_R_BRACE, "'}' in aggregate literal");
return fields;
}
typedef struct {
int prec;
char assoc;
} op_info_t;
static op_info_t binary_op_info[] = {
#define X(name, prec, assoc, str) {prec, assoc},
SPL_BINARY_OP_TABLE
#undef X
};
static spl_binary_op_t token_to_binary_op(spl_tok_type_t tt) {
switch (tt) {
case TOK_ASSIGN:
return SPL_OP_ASSIGN;
case TOK_ASSIGN_ADD:
return SPL_OP_ASSIGN_ADD;
case TOK_ASSIGN_SUB:
return SPL_OP_ASSIGN_SUB;
case TOK_ASSIGN_MUL:
return SPL_OP_ASSIGN_MUL;
case TOK_ASSIGN_DIV:
return SPL_OP_ASSIGN_DIV;
case TOK_ASSIGN_MOD:
return SPL_OP_ASSIGN_MOD;
case TOK_ASSIGN_AND:
return SPL_OP_ASSIGN_AND;
case TOK_ASSIGN_OR:
return SPL_OP_ASSIGN_OR;
case TOK_ASSIGN_XOR:
return SPL_OP_ASSIGN_XOR;
case TOK_ASSIGN_L_SH:
return SPL_OP_ASSIGN_LSHIFT;
case TOK_ASSIGN_R_SH:
return SPL_OP_ASSIGN_RSHIFT;
case TOK_OR_OR:
return SPL_OP_BOOL_OR;
case TOK_AND_AND:
return SPL_OP_BOOL_AND;
case TOK_OR:
return SPL_OP_BIT_OR;
case TOK_XOR:
return SPL_OP_BIT_XOR;
case TOK_AND:
return SPL_OP_BIT_AND;
case TOK_EQ:
return SPL_OP_CMP_EQ;
case TOK_NEQ:
return SPL_OP_CMP_NE;
case TOK_LE:
return SPL_OP_CMP_LE;
case TOK_GE:
return SPL_OP_CMP_GE;
case TOK_LT:
return SPL_OP_CMP_LT;
case TOK_GT:
return SPL_OP_CMP_GT;
case TOK_LEFT_ARROW:
return SPL_OP_ARROW_LEFT;
case TOK_RIGHT_ARROW:
return SPL_OP_ARROW_RIGHT;
case TOK_FAT_ARROW_BOTH:
return SPL_OP_ARROW_FAT_BOTH;
case TOK_ARROW_BOTH:
return SPL_OP_ARROW_THIN_BOTH;
case TOK_RIGHT_FAT_ARROW:
return SPL_OP_ARROW_FAT_RIGHT;
case TOK_RANGE:
return SPL_OP_RANGE;
case TOK_L_SH:
return SPL_OP_LSHIFT;
case TOK_R_SH:
return SPL_OP_RSHIFT;
case TOK_ADD:
return SPL_OP_ADD;
case TOK_SUB:
return SPL_OP_SUB;
case TOK_MUL:
return SPL_OP_MUL;
case TOK_DIV:
return SPL_OP_DIV;
case TOK_MOD:
return SPL_OP_MOD;
default:
return (spl_binary_op_t)-1;
}
}
static spl_ast_node_ref_t mk_bin(spl_parser_t *p, const spl_tok_t *loc, spl_binary_op_t op,
spl_ast_node_ref_t left, spl_ast_node_ref_t right) {
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_BINARY, loc);
spl_ast_node_t *node = node_at(p->ast, ref);
node->binary.op = op;
node->binary.left = left;
node->binary.right = right;
return ref;
}
static spl_ast_node_ref_t mk_unary(spl_parser_t *p, const spl_tok_t *loc, spl_unary_op_t op,
spl_ast_node_ref_t operand) {
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_UNARY, loc);
spl_ast_node_t *node = node_at(p->ast, ref);
node->unary.op = op;
node->unary.operand = operand;
return ref;
}
static spl_ast_node_ref_t parse_expr_prec(spl_parser_t *p, int min_prec) {
spl_ast_node_ref_t left = parse_cast(p);
if (p->failed)
return left;
while (!p->failed) {
const spl_tok_t *t = peek(p);
if (!t)
break;
spl_binary_op_t op = token_to_binary_op(t->type);
if (op == (spl_binary_op_t)-1)
break;
op_info_t info = binary_op_info[op];
if (info.prec < min_prec)
break;
advance(p);
if (op == SPL_OP_RANGE) {
spl_ast_node_ref_t right = 0;
if (peek(p) && can_start_expr(peek(p)->type))
right = parse_expr_prec(p, info.prec + 1);
left = mk_bin(p, t, op, left, right);
continue;
}
int next_min = (info.assoc == 'R') ? info.prec : info.prec + 1;
spl_ast_node_ref_t right = parse_expr_prec(p, next_min);
left = mk_bin(p, t, op, left, right);
}
return left;
}
static spl_ast_node_ref_t parse_expr(spl_parser_t *p) { return parse_expr_prec(p, 1); }
static spl_ast_node_ref_t parse_cast(spl_parser_t *p) {
spl_ast_node_ref_t expr = parse_prefix(p);
while (!p->failed) {
const spl_tok_t *t = peek(p);
if (!t || t->type != KW_AS)
break;
advance(p);
spl_ast_node_ref_t type = parse_type_expr(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_CAST, t);
node_at(p->ast, ref)->cast.expr = expr;
node_at(p->ast, ref)->cast.type = type;
expr = ref;
}
return expr;
}
static spl_ast_node_ref_t parse_prefix(spl_parser_t *p) {
const spl_tok_t *t = peek(p);
if (!t)
return 0;
if (t->type == TOK_DOLLAR) {
spl_ast_node_ref_t label = parse_label(p);
const spl_tok_t *kw = peek(p);
spl_ast_node_ref_t ref = 0;
if (kw && kw->type == KW_WHILE)
ref = parse_while_expr(p);
else if (kw && kw->type == KW_LOOP)
ref = parse_loop_expr(p);
else if (kw && kw->type == KW_FOR)
ref = parse_for_expr(p);
else {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, kw, "expected while/loop/for after label");
return 0;
}
if (!ref)
return 0;
spl_ast_node_t *n = node_at(p->ast, ref);
switch (n->kind) {
case SPL_AST_EXPR_WHILE:
n->while_expr.label = label;
break;
case SPL_AST_EXPR_LOOP:
n->loop_expr.label = label;
break;
case SPL_AST_EXPR_FOR:
n->for_expr.label = label;
break;
default:
break;
}
return ref;
}
spl_unary_op_t uop;
switch (t->type) {
case TOK_SUB:
uop = SPL_UNARY_OP_MINUS;
break;
case TOK_NOT:
uop = SPL_UNARY_OP_NOT;
break;
case TOK_BIT_NOT:
uop = SPL_UNARY_OP_BIT_NOT;
break;
case TOK_AND:
uop = SPL_UNARY_OP_ADDRESS;
break;
default:
return parse_postfix(p);
}
advance(p);
spl_ast_node_ref_t operand = parse_prefix(p);
return mk_unary(p, t, uop, operand);
}
static spl_ast_node_ref_t parse_postfix(spl_parser_t *p) {
spl_ast_node_ref_t expr = parse_primary(p);
while (!p->failed) {
const spl_tok_t *t = peek(p);
if (!t)
break;
if (t->type == TOK_L_PAREN) {
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_CALL, t);
node_at(p->ast, ref)->call.callee = expr;
spl_ast_node_ref_vec_t args = parse_expr_list(p);
node_at(p->ast, ref)->call.args = args;
if (!expect(p, TOK_R_PAREN, "')' in call"))
return expr;
expr = ref;
} else if (t->type == TOK_DOT) {
advance(p);
const spl_tok_t *next = peek(p);
if (!next)
break;
if (next->type == TOK_IDENT) {
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_FIELD, t);
node_at(p->ast, ref)->field.obj = expr;
SET_STR_FIELD(p->ast, node_at(p->ast, ref)->field.field, next);
expr = ref;
} else if (next->type == TOK_MUL) {
advance(p);
expr = mk_unary(p, t, SPL_UNARY_OP_DEREF, expr);
} else {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, next,
"expected identifier or '*' after '.'");
break;
}
} else if (t->type == TOK_L_BRACKET) {
advance(p);
int range_prec = binary_op_info[SPL_OP_RANGE].prec;
spl_ast_node_ref_t begin = parse_expr_prec(p, range_prec + 1);
if (peek(p) && peek(p)->type == TOK_RANGE) {
advance(p);
spl_ast_node_ref_t end = 0;
if (peek(p) && peek(p)->type != TOK_R_BRACKET)
end = parse_expr(p);
if (!expect(p, TOK_R_BRACKET, "']' in slice"))
return expr;
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_SLICE, t);
node_at(p->ast, ref)->slice.obj = expr;
node_at(p->ast, ref)->slice.begin = begin;
node_at(p->ast, ref)->slice.end = end;
expr = ref;
} else {
if (!expect(p, TOK_R_BRACKET, "']' in index"))
return expr;
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_INDEX, t);
node_at(p->ast, ref)->index.obj = expr;
node_at(p->ast, ref)->index.index = begin;
expr = ref;
}
} else {
break;
}
}
return expr;
}
static spl_ast_node_ref_t parse_variant_construct(spl_parser_t *p, const spl_tok_t *dot) {
/* 已消费 '.',当前 token 是 IDENT */
const spl_tok_t *name = advance(p);
spl_ast_node_ref_vec_t fields;
vec_init(fields);
spl_ast_node_ref_t field = new_node(p, SPL_AST_STRUCT_INIT_ITEM, name);
node_at(p->ast, field)->struct_init_item.name = intern_string(p->ast, name->lexeme, name->len);
node_at(p->ast, field)->struct_init_item.expr = 0;
if (peek(p) && peek(p)->type == TOK_L_PAREN) {
advance(p);
spl_ast_node_ref_vec_t args;
vec_init(args);
if (peek(p) && peek(p)->type != TOK_R_PAREN)
args = parse_expr_list(p);
expect(p, TOK_R_PAREN, "')' after variant payload");
spl_ast_node_ref_t expr = 0;
if (args.size == 1) {
expr = args.data[0];
} else {
expr = new_node(p, SPL_AST_EXPR_TUPLE, name);
node_at(p->ast, expr)->tuple.elems = args;
vec_init(args);
}
vec_free(args);
node_at(p->ast, field)->struct_init_item.expr = expr;
}
vec_push(fields, field);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_AGGREGATE_LIT, dot);
spl_ast_node_t *agg = node_at(p->ast, ref);
agg->aggregate_literal.name = NULL;
agg->aggregate_literal.fields = fields;
return ref;
}
static spl_ast_node_ref_t parse_primary(spl_parser_t *p) {
const spl_tok_t *t = peek(p);
if (!t) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, "unexpected end of expression");
return 0;
}
switch (t->type) {
case TOK_INT_LITERAL: {
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_INT_LIT, t);
node_at(p->ast, ref)->int_lit.bits = (uint64_t)parse_int_literal(t);
return ref;
}
case TOK_FLOAT_LITERAL: {
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_FLOAT_LIT, t);
node_at(p->ast, ref)->float_lit.bits = parse_float_literal(t);
return ref;
}
case TOK_CHAR_LITERAL: {
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_CHAR_LIT, t);
node_at(p->ast, ref)->char_lit.val = parse_char_literal(t);
return ref;
}
case TOK_STRING_LITERAL: {
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_STRING_LIT, t);
usize len = 0;
const char *data = parse_string_literal(p, t, &len);
spl_ast_node_t *node = node_at(p->ast, ref);
node->string_lit.data = data;
node->string_lit.len = len;
return ref;
}
case KW_TRUE:
case KW_FALSE: {
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_BOOL_LIT, t);
node_at(p->ast, ref)->bool_lit.val = (t->type == KW_TRUE);
return ref;
}
case KW_NULL:
advance(p);
return new_node(p, SPL_AST_EXPR_NULL_LIT, t);
case KW_UNDEFINED:
advance(p);
return new_node(p, SPL_AST_EXPR_UNDEFINED_LIT, t);
case TOK_IDENT: {
advance(p);
if (peek(p) && peek(p)->type == TOK_L_BRACE && !p->stop_agg) {
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_AGGREGATE_LIT, t);
spl_ast_node_t *agg = node_at(p->ast, ref);
agg->aggregate_literal.name = intern_string(p->ast, t->lexeme, t->len);
spl_ast_node_ref_vec_t fields = parse_aggregate_fields(p);
node_at(p->ast, ref)->aggregate_literal.fields = fields;
return ref;
}
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_IDENT, t);
node_at(p->ast, ref)->ident.name = intern_string(p->ast, t->lexeme, t->len);
return ref;
}
case TOK_DOT: {
advance(p);
const spl_tok_t *nx = peek(p);
if (!nx) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, "unexpected '.'");
return 0;
}
if (nx->type == TOK_L_BRACE && !p->stop_agg) {
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_AGGREGATE_LIT, t);
node_at(p->ast, ref)->aggregate_literal.name = NULL;
spl_ast_node_ref_vec_t fields = parse_aggregate_fields(p);
node_at(p->ast, ref)->aggregate_literal.fields = fields;
return ref;
} else if (nx->type == TOK_L_BRACKET) {
advance(p);
spl_ast_node_ref_vec_t elems = parse_expr_list(p);
if (!expect(p, TOK_R_BRACKET, "']' in array literal"))
return 0;
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_ARRAY_LIT, t);
spl_ast_node_t *arr = node_at(p->ast, ref);
arr->array_literal.elems = elems;
arr->array_literal.elem_type = 0;
return ref;
} else if (nx->type == TOK_IDENT) {
return parse_variant_construct(p, t);
} else {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, nx,
"expected '{', '[' or identifier after '.'");
return 0;
}
}
case TOK_L_BRACKET:
return parse_array_literal(p);
case TOK_L_BRACE:
return parse_block(p);
case TOK_AT:
case TOK_SHARP:
return parse_comptime_call(p);
case TOK_L_PAREN: {
advance(p);
spl_ast_node_ref_vec_t elems;
vec_init(elems);
if (peek(p) && peek(p)->type == TOK_R_PAREN) {
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_TUPLE, t);
node_at(p->ast, ref)->tuple.elems = elems;
return ref;
}
spl_ast_node_ref_t first = parse_expr(p);
if (peek(p) && peek(p)->type == TOK_COMMA) {
vec_push(elems, first);
while (peek(p) && peek(p)->type == TOK_COMMA) {
advance(p);
if (peek(p) && peek(p)->type == TOK_R_PAREN)
break;
vec_push(elems, parse_expr(p));
}
if (!expect(p, TOK_R_PAREN, "')' in tuple literal"))
return 0;
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_TUPLE, t);
node_at(p->ast, ref)->tuple.elems = elems;
return ref;
} else {
if (!expect(p, TOK_R_PAREN, "')' in paren expression"))
return 0;
vec_free(elems);
return first;
}
}
case KW_IF:
return parse_if_expr(p);
case KW_WHILE:
return parse_while_expr(p);
case KW_LOOP:
return parse_loop_expr(p);
case KW_FOR:
return parse_for_expr(p);
case KW_MATCH:
return parse_match_expr(p);
default:
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, "unrecognized expression");
return 0;
}
}
static spl_ast_node_ref_t parse_array_literal(spl_parser_t *p) {
const spl_tok_t *start = peek(p);
if (!start || start->type != TOK_L_BRACKET)
return 0;
advance(p);
bool has_len = false;
isize len = 0;
bool is_underscore = false;
const spl_tok_t *t = peek(p);
if (t && t->type == TOK_INT_LITERAL) {
len = parse_int_literal(t);
has_len = true;
advance(p);
} else if (t && t->type == KW_UNDERSCORE) {
has_len = true;
is_underscore = true;
advance(p);
}
if (!expect(p, TOK_R_BRACKET, "']' in array literal"))
return 0;
spl_ast_node_ref_t elem_type = parse_type_expr(p);
if (!expect(p, TOK_L_BRACKET, "'[' in array literal"))
return 0;
spl_ast_node_ref_vec_t elems = parse_expr_list(p);
if (!expect(p, TOK_R_BRACKET, "']' in array literal"))
return 0;
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_ARRAY_LIT, start);
spl_ast_node_t *arr = node_at(p->ast, ref);
arr->array_literal.has_len = has_len;
arr->array_literal.len = (usize)len;
arr->array_literal.is_underscore_len = is_underscore;
arr->array_literal.elem_type = elem_type;
arr->array_literal.elems = elems;
return ref;
}
static spl_ast_node_ref_t parse_comptime_call(spl_parser_t *p) {
const spl_tok_t *start = peek(p);
if (!start || (start->type != TOK_AT && start->type != TOK_SHARP))
return 0;
advance(p);
const spl_tok_t *name = peek(p);
if (!name || name->type != TOK_IDENT) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, name, "expected comptime name");
return 0;
}
advance(p);
spl_ast_node_ref_vec_t args;
vec_init(args);
const spl_tok_t *t = peek(p);
if (t && t->type == TOK_L_PAREN) {
advance(p);
args = parse_expr_list(p);
if (!expect(p, TOK_R_PAREN, "')' in comptime call")) {
vec_free(args);
return 0;
}
}
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_COMPTIME_CALL, start);
spl_ast_node_t *cc = node_at(p->ast, ref);
SET_STR_FIELD(p->ast, cc->comptime_call.name, name);
cc->comptime_call.args = args;
return ref;
}
static spl_ast_node_ref_t parse_label(spl_parser_t *p) {
const spl_tok_t *t = peek(p);
if (!t || t->type != TOK_DOLLAR)
return 0;
advance(p);
const spl_tok_t *name = peek(p);
if (!name || name->type != TOK_IDENT) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, name, "expected identifier after '$'");
return 0;
}
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_LABEL, t);
SET_STR_FIELD(p->ast, node_at(p->ast, ref)->label.name, name);
return ref;
}
static spl_ast_node_ref_t parse_if_expr(spl_parser_t *p) {
const spl_tok_t *kw = peek(p);
if (!kw || kw->type != KW_IF)
return 0;
advance(p);
int is_ifvar = 0;
spl_ast_node_ref_t var_decl = 0;
const spl_tok_t *t = peek(p);
if (t && t->type == KW_VAR) {
advance(p);
is_ifvar = 1;
spl_ast_node_ref_t pattern = parse_pattern(p);
if (!pattern)
return 0;
spl_ast_node_ref_t type_expr = 0;
spl_ast_node_ref_t init_expr = 0;
t = peek(p);
if (t && t->type == TOK_COLON) {
advance(p);
type_expr = parse_type_expr(p);
t = peek(p);
if (t && t->type == TOK_ASSIGN) {
advance(p);
p->stop_agg++;
init_expr = parse_expr(p);
p->stop_agg--;
} else {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '=' in if var");
return 0;
}
} else if (t && t->type == TOK_ASSIGN) {
advance(p);
p->stop_agg++;
init_expr = parse_expr(p);
p->stop_agg--;
} else {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, t,
"expected type annotation or '=' in if var");
return 0;
}
var_decl = new_node(p, SPL_AST_VAR_DECL, kw);
spl_ast_node_t *vd = node_at(p->ast, var_decl);
vd->var_const_decl.pattern = pattern;
vd->var_const_decl.type = type_expr;
vd->var_const_decl.init_expr = init_expr;
} else {
p->stop_agg++;
spl_ast_node_ref_t cond = parse_expr(p);
p->stop_agg--;
if (!cond)
return 0;
var_decl = cond;
}
spl_ast_node_ref_t then_block = parse_block(p);
if (!then_block)
return 0;
spl_ast_node_ref_t else_branch = 0;
t = peek(p);
if (t && t->type == KW_ELSE) {
advance(p);
t = peek(p);
if (t && t->type == KW_IF)
else_branch = parse_if_expr(p);
else
else_branch = parse_block(p);
}
spl_ast_node_ref_t ref;
if (is_ifvar) {
ref = new_node(p, SPL_AST_EXPR_IFVAR, kw);
node_at(p->ast, ref)->ifvar_expr.var_decl = var_decl;
node_at(p->ast, ref)->ifvar_expr.then_block = then_block;
node_at(p->ast, ref)->ifvar_expr.else_branch = else_branch;
} else {
ref = new_node(p, SPL_AST_EXPR_IF, kw);
node_at(p->ast, ref)->if_expr.cond = var_decl;
node_at(p->ast, ref)->if_expr.then_block = then_block;
node_at(p->ast, ref)->if_expr.else_branch = else_branch;
}
return ref;
}
static spl_ast_node_ref_t parse_while_expr(spl_parser_t *p) {
const spl_tok_t *kw = peek(p);
if (!kw || kw->type != KW_WHILE)
return 0;
advance(p);
p->stop_agg++;
spl_ast_node_ref_t cond = parse_expr(p);
p->stop_agg--;
if (!cond)
return 0;
spl_ast_node_ref_t body = parse_block(p);
if (!body)
return 0;
spl_ast_node_ref_t else_branch = 0;
if (peek(p) && peek(p)->type == KW_ELSE) {
advance(p);
if (peek(p) && peek(p)->type == TOK_L_BRACE)
else_branch = parse_block(p);
else
else_branch = parse_expr(p);
}
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_WHILE, kw);
node_at(p->ast, ref)->while_expr.label = 0;
node_at(p->ast, ref)->while_expr.cond = cond;
node_at(p->ast, ref)->while_expr.body = body;
node_at(p->ast, ref)->while_expr.else_branch = else_branch;
return ref;
}
static spl_ast_node_ref_t parse_loop_expr(spl_parser_t *p) {
const spl_tok_t *kw = peek(p);
if (!kw || kw->type != KW_LOOP)
return 0;
advance(p);
spl_ast_node_ref_t body = parse_block(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_LOOP, kw);
node_at(p->ast, ref)->loop_expr.label = 0;
node_at(p->ast, ref)->loop_expr.body = body;
return ref;
}
static spl_ast_node_ref_t parse_for_expr(spl_parser_t *p) {
const spl_tok_t *kw = peek(p);
if (!kw || kw->type != KW_FOR)
return 0;
advance(p);
spl_ast_node_ref_t pattern = parse_pattern(p);
if (!pattern) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, peek(p), "expected pattern in for");
return 0;
}
if (!expect(p, TOK_COLON, "':' after for pattern"))
return 0;
spl_ast_node_ref_vec_t iter_exprs;
vec_init(iter_exprs);
p->stop_agg++;
vec_push(iter_exprs, parse_expr(p));
while (peek(p) && peek(p)->type == TOK_COMMA) {
advance(p);
vec_push(iter_exprs, parse_expr(p));
}
p->stop_agg--;
spl_ast_node_ref_t body = parse_block(p);
if (!body) {
vec_free(iter_exprs);
return 0;
}
spl_ast_node_ref_t else_branch = 0;
if (peek(p) && peek(p)->type == KW_ELSE) {
advance(p);
if (peek(p) && peek(p)->type == TOK_L_BRACE)
else_branch = parse_block(p);
else
else_branch = parse_expr(p);
}
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_FOR, kw);
spl_ast_node_t *fe = node_at(p->ast, ref);
fe->for_expr.label = 0;
fe->for_expr.iter_exprs = iter_exprs;
fe->for_expr.pattern = pattern;
fe->for_expr.body = body;
fe->for_expr.else_branch = else_branch;
return ref;
}
static spl_ast_node_ref_t parse_match_expr(spl_parser_t *p) {
const spl_tok_t *kw = peek(p);
if (!kw || kw->type != KW_MATCH)
return 0;
advance(p);
p->stop_agg++;
spl_ast_node_ref_t matched_expr = parse_expr(p);
p->stop_agg--;
if (!expect(p, TOK_L_BRACE, "'{' in match"))
return 0;
spl_ast_node_ref_vec_t patterns, bodies;
vec_init(patterns);
vec_init(bodies);
while (!p->failed) {
const spl_tok_t *t = peek(p);
if (!t || t->type == TOK_R_BRACE || t->type == TOK_EOF)
break;
spl_ast_node_ref_t pat = parse_pattern(p);
if (!pat)
break;
if (!expect(p, TOK_RIGHT_FAT_ARROW, "'=>' in match arm"))
break;
spl_ast_node_ref_t body = parse_block(p);
vec_push(patterns, pat);
vec_push(bodies, body);
if (peek(p) && peek(p)->type == TOK_COMMA)
advance(p);
}
if (!expect(p, TOK_R_BRACE, "'}' in match"))
return 0;
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_MATCH, kw);
spl_ast_node_t *me = node_at(p->ast, ref);
me->match_expr.matched_expr = matched_expr;
vec_init(me->match_expr.arms);
for (usize i = 0; i < patterns.size; i++) {
spl_ast_node_ref_t arm = new_node(p, SPL_AST_MATCH_ARM, NULL);
spl_ast_node_t *arm_node = node_at(p->ast, arm);
arm_node->match_arm.pattern = patterns.data[i];
arm_node->match_arm.body = bodies.data[i];
me = node_at(p->ast, ref);
vec_push(me->match_expr.arms, arm);
}
vec_free(patterns);
vec_free(bodies);
return ref;
}
static spl_ast_node_ref_t parse_ret_stmt(spl_parser_t *p) {
const spl_tok_t *kw = peek(p);
if (!kw || kw->type != KW_RET)
return 0;
advance(p);
spl_ast_node_ref_t expr = 0;
const spl_tok_t *t = peek(p);
if (t && can_start_expr(t->type))
expr = parse_expr(p);
t = peek(p);
if (t && t->type == TOK_SEMICOLON)
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_STATEMENT_RET, kw);
node_at(p->ast, ref)->statement_ret.expr = expr;
return ref;
}
static spl_ast_node_ref_t parse_break_stmt(spl_parser_t *p) {
const spl_tok_t *kw = peek(p);
if (!kw || kw->type != KW_BREAK)
return 0;
advance(p);
spl_ast_node_ref_t label = parse_label(p);
spl_ast_node_ref_t expr = 0;
const spl_tok_t *t = peek(p);
if (t && can_start_expr(t->type))
expr = parse_expr(p);
t = peek(p);
if (t && t->type == TOK_SEMICOLON)
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_STATEMENT_BREAK, kw);
node_at(p->ast, ref)->statement_break.label = label;
node_at(p->ast, ref)->statement_break.expr = expr;
return ref;
}
static spl_ast_node_ref_t parse_continue_stmt(spl_parser_t *p) {
const spl_tok_t *kw = peek(p);
if (!kw || kw->type != KW_CONTINUE)
return 0;
advance(p);
spl_ast_node_ref_t label = parse_label(p);
const spl_tok_t *t = peek(p);
if (t && t->type == TOK_SEMICOLON)
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_STATEMENT_CONTINUE, kw);
node_at(p->ast, ref)->statement_continue.label = label;
return ref;
}
static spl_ast_node_ref_t parse_defer_stmt(spl_parser_t *p) {
const spl_tok_t *kw = peek(p);
if (!kw || kw->type != KW_DEFER)
return 0;
advance(p);
spl_ast_node_ref_t body = 0;
const spl_tok_t *t = peek(p);
if (t && t->type == TOK_L_BRACE) {
body = parse_block(p);
} else if (t && can_start_statement(t->type)) {
body = parse_statement(p);
} else {
body = parse_expr(p);
t = peek(p);
if (t && t->type == TOK_SEMICOLON)
advance(p);
}
spl_ast_node_ref_t ref = new_node(p, SPL_AST_STATEMENT_DEFER, kw);
node_at(p->ast, ref)->statement_defer.body = body;
return ref;
}
static spl_ast_node_ref_t parse_comptime_stmt(spl_parser_t *p) {
const spl_tok_t *kw = peek(p);
if (!kw || kw->type != KW_COMPTIME)
return 0;
advance(p);
spl_ast_node_ref_t body = 0;
const spl_tok_t *t = peek(p);
if (t && t->type == TOK_L_BRACE)
body = parse_block(p);
else
body = parse_expr(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_STATEMENT_COMPTIME, kw);
node_at(p->ast, ref)->statement_comptime.body = body;
return ref;
}
static spl_ast_node_ref_t parse_statement(spl_parser_t *p) {
const spl_tok_t *t = peek(p);
if (!t)
return 0;
switch (t->type) {
case KW_RET:
return parse_ret_stmt(p);
case KW_BREAK:
return parse_break_stmt(p);
case KW_CONTINUE:
return parse_continue_stmt(p);
case KW_DEFER:
return parse_defer_stmt(p);
case KW_COMPTIME:
return parse_comptime_stmt(p);
case KW_VAR:
case KW_CONST:
case KW_TYPE: {
spl_ast_node_ref_vec_t tag_list;
vec_init(tag_list);
parse_tag_list(p, &tag_list, 0, 0);
spl_ast_node_ref_t decl;
if (t->type == KW_VAR)
decl = parse_var_const_decl(p, tag_list, 0);
else if (t->type == KW_CONST)
decl = parse_var_const_decl(p, tag_list, 1);
else
decl = parse_type_decl(p, tag_list);
if (!decl)
return 0;
spl_ast_node_ref_t ref = new_node(p, SPL_AST_STATEMENT_DECL, t);
node_at(p->ast, ref)->statement_decl.decl = decl;
return ref;
}
default: {
if (can_start_expr(t->type)) {
spl_ast_node_ref_t expr = parse_expr(p);
if (!expr)
return 0;
spl_ast_node_ref_t ref = new_node(p, SPL_AST_STATEMENT_EXPR, t);
node_at(p->ast, ref)->statement_expr.expr = expr;
return ref;
}
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, "unrecognized statement");
return 0;
}
}
}
static spl_ast_node_ref_t parse_block(spl_parser_t *p) {
const spl_tok_t *start = peek(p);
if (!start || start->type != TOK_L_BRACE) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, start, "expected '{'");
return 0;
}
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_BLOCK, start);
spl_ast_node_t *block = node_at(p->ast, ref);
vec_init(block->block.stmts);
block->block.tail_expr = 0;
while (!p->failed) {
const spl_tok_t *t = peek(p);
if (!t || t->type == TOK_EOF) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "block missing '}'");
return ref;
}
if (t->type == TOK_R_BRACE) {
advance(p);
break;
}
if (can_start_statement(t->type)) {
spl_ast_node_ref_t stmt = parse_statement(p);
block = node_at(p->ast, ref);
if (stmt)
vec_push(block->block.stmts, stmt);
else
break;
} else if (can_start_expr(t->type)) {
spl_ast_node_ref_t expr = parse_expr(p);
if (!expr)
break;
block = node_at(p->ast, ref);
t = peek(p);
if (t && t->type == TOK_SEMICOLON) {
advance(p);
vec_push(block->block.stmts, expr);
} else if (t && t->type == TOK_R_BRACE) {
if (block->block.tail_expr != 0) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t,
"only one tail expression allowed");
}
block->block.tail_expr = expr;
} else {
spl_ast_node_kind_t k = node_at(p->ast, expr)->kind;
bool block_like =
(k == SPL_AST_EXPR_BLOCK || k == SPL_AST_EXPR_IF || k == SPL_AST_EXPR_IFVAR ||
k == SPL_AST_EXPR_WHILE || k == SPL_AST_EXPR_LOOP || k == SPL_AST_EXPR_FOR ||
k == SPL_AST_EXPR_MATCH);
if (block_like)
vec_push(block->block.stmts, expr);
else {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, t,
"expected ';' or '}' after expression");
break;
}
}
} else {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, "unrecognized token in block");
break;
}
}
return ref;
}
/* ---------- 入口 ---------- */
void spl_parser_init(spl_parser_t *parser) {
parser->ast = NULL;
parser->diag = NULL;
parser->pos = 0;
parser->failed = 0;
parser->stop_agg = 0;
parser->error_count = 0;
}
void spl_parser_drop(spl_parser_t *parser) { (void)parser; }
static void skip_to_sync(spl_parser_t *p) {
while (!p->failed) {
const spl_tok_t *t = peek(p);
if (!t || t->type == TOK_EOF)
return;
if (t->type == TOK_SEMICOLON || t->type == TOK_R_BRACE) {
advance(p);
return;
}
advance(p);
}
}
void spl_ast_parse(spl_parser_t *parser, spl_ast_t *ast) {
if (!ast || !ast->input.data || ast->node_buckets.size == 0)
return;
parser->ast = ast;
parser->pos = 0;
parser->failed = 0;
parser->stop_agg = 0;
spl_ast_node_ref_vec_t external_tags;
vec_init(external_tags);
spl_ast_node_ref_vec_t declarations;
vec_init(declarations);
while (!parser->failed) {
const spl_tok_t *t = peek(parser);
if (!t || t->type == TOK_EOF)
break;
if (t->type == TOK_AT || t->type == TOK_SHARP) {
usize save_pos = parser->pos;
const spl_tok_t *t2 = NULL;
parser->pos++;
t2 = peek(parser);
parser->pos = save_pos;
if (t2 && t2->type == TOK_NOT) {
parse_tag_list(parser, &external_tags, 1, 1);
continue;
}
}
spl_ast_node_ref_t decl = parse_container_declaration(parser);
if (decl) {
vec_push(declarations, decl);
} else if (!parser->failed) {
const spl_tok_t *at = peek(parser);
if (at && at->type != TOK_EOF) {
skip_to_sync(parser);
} else {
break;
}
}
}
spl_ast_node_ref_t container_members = new_node(parser, SPL_AST_CONTAINER_MEMBERS, NULL);
spl_ast_node_t *cm = node_at(ast, container_members);
cm->container_members.external_tags = external_tags;
cm->container_members.declarations = declarations;
spl_ast_node_ref_t root = new_node(parser, SPL_AST_ROOT, NULL);
node_at(ast, root)->root.members = container_members;
ast->root = root;
}