#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, ""); 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, ¶ms); 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; }