From 54425a50c7e2f7763966863b491f5e63c416865c Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Thu, 17 Sep 2026 00:33:03 +0800 Subject: [PATCH] =?UTF-8?q?stage1=20=E9=87=8D=E6=9E=84=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=20=E8=AF=AD=E6=B3=95=E4=B8=8A=E9=87=8D=E6=96=B0=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E8=A7=A3=E5=8C=85=E8=AF=AD=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gramma.pest | 130 ++- nob.c | 1 + stage1/spl_ast.c | 2303 +--------------------------------------- stage1/spl_ast.h | 129 +-- stage1/spl_lang_type.c | 39 +- stage1/spl_parser.c | 2284 +++++++++++++++++++++++++++++++++++++++ stage1/spl_parser.h | 21 + stage1/spl_sema.c | 203 +++- stage1/spl_type.c | 34 +- stage1/splc0.c | 15 +- 10 files changed, 2681 insertions(+), 2478 deletions(-) create mode 100644 stage1/spl_parser.c create mode 100644 stage1/spl_parser.h diff --git a/gramma.pest b/gramma.pest index 7ffc7c7..0e65b10 100644 --- a/gramma.pest +++ b/gramma.pest @@ -1,4 +1,3 @@ -// 顶层容器 Root = { SOI ~ ContainerMembers ~ EOI } ContainerMembers = { ExternalHeaderList ~ (ContainerDeclaration ~ (COMMA | SEMICOLON)*)* } @@ -22,7 +21,6 @@ ContainerDeclaration = { ComptimeDecl = { KEYWORD_comptime ~ (Block | Expr) } -// 函数声明(可带 comptime 前缀,支持修饰符) FnDecl = { DeclHeader ~ KEYWORD_comptime? ~ KEYWORD_fn ~ IDENTIFIER ~ LPAREN ~ ParamDeclList ~ RPAREN ~ (COLON ~ TypeExpr)? ~ (SEMICOLON | Block) } @@ -30,35 +28,38 @@ FnDecl = { ParamDeclList = { (ParamDecl ~ COMMA)* ~ (ParamDecl | DOT3)? } ParamDecl = { HeaderList? ~ BindingIdent ~ COLON ~ TypeExpr } -// 变量声明(支持修饰符、元组解构与类型推导) VarDecl = { DeclHeader ~ KEYWORD_var ~ VarBody } ConstDecl = { DeclHeader ~ KEYWORD_const ~ VarBody } -VarBody = { VarPattern ~ (COLON ~ TypeExpr)? ~ (EQUAL ~ Expr)? } +VarBody = { Pattern ~ (COLON ~ TypeExpr)? ~ (EQUAL ~ Expr)? } -// 类型声明(支持修饰符) TypeDecl = { DeclHeader ~ KEYWORD_type ~ IDENTIFIER ~ EQUAL ~ TypeExpr } -// 容器成员(支持修饰符) MemberDecl = { DeclHeader ~ IDENTIFIER ~ (COLON ~ TypeExpr)? ~ (EQUAL ~ Expr)? } -// 变量声明左值模式(允许单独标识符) -VarPattern = { VarPatternAtom ~ (COMMA ~ VarPatternAtom)* } -VarPatternAtom = { - BindingIdent - | DOT ~ IDENTIFIER ~ (LBRACKET ~ VarPattern ~ RBRACKET)? - | LPAREN ~ VarPattern ~ RPAREN -} - -// 匹配模式(不允许单独标识符) -MatchPattern = { MatchPatternAtom ~ (COMMA ~ MatchPatternAtom)* } -MatchPatternAtom = { +Pattern = { PatternAtom ~ (COMMA ~ PatternAtom)* } +PatternAtom = { UNDERSCORE - | Expr - | DOT ~ IDENTIFIER ~ (LBRACKET ~ MatchPattern ~ RBRACKET)? - | LPAREN ~ MatchPattern ~ RPAREN + | AnonymousAggregatePattern + | DOT ~ IDENTIFIER ~ (LPAREN ~ Pattern? ~ RPAREN)? + | LPAREN ~ Pattern? ~ RPAREN + | PatternLiteral + | IDENTIFIER +} + +AnonymousAggregatePattern = { DOT ~ LBRACE ~ PatternFieldList? ~ RBRACE } +PatternFieldList = { PatternField ~ ((COMMA | SEMICOLON) ~ PatternField)* ~ (COMMA | SEMICOLON)? } +PatternField = { DOT ~ IDENTIFIER ~ (EQUAL ~ PatternAtom)? } + +PatternLiteral = { + FLOAT_LITERAL + | INTEGER_LITERAL + | CHAR_LITERAL + | STRING_LITERAL + | KEYWORD_true + | KEYWORD_false + | KEYWORD_null } -// 块内语句 Block = { LBRACE ~ Statement* ~ Expr? ~ RBRACE } Statement = { RetStatement @@ -70,7 +71,6 @@ Statement = { | ComptimeStatement } -// 声明语句(内部声明已包含 HeaderList) DeclStatement = { (VarDecl | ConstDecl | TypeDecl) ~ (COMMA | SEMICOLON)? } ExprStatement = { Expr ~ (COMMA | SEMICOLON)? } ComptimeStatement = { ComptimeDecl ~ (COMMA | SEMICOLON)? } @@ -80,11 +80,8 @@ BreakStatement = { KEYWORD_break ~ Label? ~ Expr? ~ (COMMA | SEMICOLON)? } ContinueStatement = { KEYWORD_continue ~ Label? ~ (COMMA | SEMICOLON)? } DeferStatement = { KEYWORD_defer ~ (Block | Statement) ~ (COMMA | SEMICOLON)? } -// 标签定义($ 前缀) Label = { DOLLAR ~ IDENTIFIER } -// ============ 表达式 ============ - Expr = { AssignExpr } AssignExpr = { BoolOrExpr ~ (AssignOp ~ AssignExpr)? } @@ -125,8 +122,8 @@ PrimaryExpr = { | AnonymousAggregateLiteral | ArrayLiteral | AnonymousArrayLiteral - | ComptimeCallExpr // @name(args) - + | VariantConstruct + | ComptimeCallExpr | IDENTIFIER | Block | IfExpr @@ -140,26 +137,74 @@ PrimaryExpr = { TupleLiteral = { ParenExpr } -// ============ 聚合字面量 ============ - AggregateLiteral = { IDENTIFIER ~ LBRACE ~ StructInitList? ~ RBRACE } AnonymousAggregateLiteral = { DOT ~ LBRACE ~ StructInitList? ~ RBRACE } StructInitList = { StructInit ~ ((COMMA | SEMICOLON) ~ StructInit)* ~ (COMMA | SEMICOLON)? } StructInit = { DOT ~ IDENTIFIER ~ (EQUAL ~ Expr)? } -// ============ 数组/切片字面量 ============ +VariantConstruct = { DOT ~ IDENTIFIER ~ (LPAREN ~ ExprList? ~ RPAREN)? } + ArrayLiteral = { - // 切片字面量: []T[1,2,3] - // 数组字面量: [N]T[1,2,3] 或 [_]T[1,2,3] - LBRACKET ~ (INTEGER_LITERAL | UNDERSCORE)? ~ RBRACKET ~ TypeExpr ~ LBRACKET ~ ExprList? ~ RBRACKET + LBRACKET ~ RBRACKET ~ TypeExpr ~ LBRACKET ~ ExprList? ~ RBRACKET + | LBRACKET ~ (INTEGER_LITERAL | UNDERSCORE) ~ RBRACKET ~ TypeExpr ~ LBRACKET ~ ExprList? ~ RBRACKET } AnonymousArrayLiteral = { DOT ~ LBRACKET ~ ExprList? ~ RBRACKET } -// ============ 类型表达式(独立,限制语法) ============ +ExprNoStruct = { AssignExprNoStruct } + +AssignExprNoStruct = { BoolOrExprNoStruct ~ (AssignOp ~ AssignExprNoStruct)? } +BoolOrExprNoStruct = { BoolAndExprNoStruct ~ (BOOL_OR ~ BoolAndExprNoStruct)* } +BoolAndExprNoStruct = { BitOrExprNoStruct ~ (BOOL_AND ~ BitOrExprNoStruct)* } +BitOrExprNoStruct = { BitXorExprNoStruct ~ (PIPE ~ BitXorExprNoStruct)* } +BitXorExprNoStruct = { BitAndExprNoStruct ~ (CARET ~ BitAndExprNoStruct)* } +BitAndExprNoStruct = { CmpEqExprNoStruct ~ (AMPERSAND ~ CmpEqExprNoStruct)* } +CmpEqExprNoStruct = { CmpExprNoStruct ~ ((EQ_EQ | BANG_EQUAL) ~ CmpExprNoStruct)* } +CmpExprNoStruct = { ArrowExprNoStruct ~ ((L_ARROW_EQ | L_ARROW | R_ARROW_EQ | R_ARROW) ~ ArrowExprNoStruct)* } + +ArrowExprNoStruct = { RangeExprNoStruct ~ ((THIN_R_ARROW | THIN_L_ARROW | FAT_D_ARROW | THIN_D_ARROW) ~ RangeExprNoStruct)* } + +RangeExprNoStruct = { ShiftExprNoStruct ~ (DOT2 ~ ShiftExprNoStruct?)? } +ShiftExprNoStruct = { AddExprNoStruct ~ ((L_ARROW2_EQ | L_ARROW2 | R_ARROW2_EQ | R_ARROW2) ~ AddExprNoStruct)* } +AddExprNoStruct = { MulExprNoStruct ~ ((PLUS | MINUS) ~ MulExprNoStruct)* } +MulExprNoStruct = { CastExprNoStruct ~ ((ASTERISK | SLASH | PERCENT) ~ CastExprNoStruct)* } +CastExprNoStruct = { PrefixExprNoStruct ~ (KEYWORD_as ~ TypeExpr)* } +PrefixExprNoStruct = { PrefixOp* ~ PostfixExprNoStruct } + +PostfixExprNoStruct = { + PrimaryExprNoStruct ~ (LPAREN ~ ExprList ~ RPAREN | DOT ~ IDENTIFIER | DOT ~ ASTERISK | LBRACKET ~ Expr ~ RBRACKET | LBRACKET ~ Expr ~ DOT2 ~ Expr? ~ RBRACKET)* +} + +PrimaryExprNoStruct = { + FLOAT_LITERAL + | INTEGER_LITERAL + | CHAR_LITERAL + | STRING_LITERAL + | KEYWORD_true + | KEYWORD_false + | KEYWORD_null + | TupleLiteral + | AnonymousAggregateLiteral + | ArrayLiteral + | AnonymousArrayLiteral + | VariantConstruct + | ComptimeCallExpr + | IDENTIFIER + | Block + | IfExpr + | IfVarExpr + | WhileExpr + | LoopExpr + | ForExpr + | MatchExpr + | FnTypeExpr +} + +VarBodyNoStruct = { Pattern ~ (COLON ~ TypeExpr)? ~ (EQUAL ~ ExprNoStruct)? } + TypeExpr = { HeaderList? ~ TypePrefixExpr } TypePrefixExpr = { ASTERISK* ~ TypePostfixExpr } @@ -208,26 +253,23 @@ FnTypeExpr = { KEYWORD_comptime? ~ KEYWORD_fn ~ LPAREN ~ TypeExprList? ~ RPAREN AggregateTypeExpr = { (KEYWORD_struct | KEYWORD_union | KEYWORD_enum | KEYWORD_shape) ~ LBRACE ~ ContainerMembers ~ RBRACE } -// ============ 控制流 ============ -IfExpr = { KEYWORD_if ~ Expr ~ Block ~ (KEYWORD_else ~ (Block | IfExpr | IfVarExpr))? } -IfVarExpr = { KEYWORD_if ~ VarBody ~ Block ~ (KEYWORD_else ~ (Block | IfExpr | IfVarExpr))? } +IfExpr = { KEYWORD_if ~ ExprNoStruct ~ Block ~ (KEYWORD_else ~ (Block | IfExpr | IfVarExpr))? } +IfVarExpr = { KEYWORD_if ~ KEYWORD_var ~ VarBodyNoStruct ~ Block ~ (KEYWORD_else ~ (Block | IfExpr | IfVarExpr))? } -WhileExpr = { Label? ~ KEYWORD_while ~ Expr ~ Block ~ (KEYWORD_else ~ (Block | Expr))? } +WhileExpr = { Label? ~ KEYWORD_while ~ ExprNoStruct ~ Block ~ (KEYWORD_else ~ (Block | Expr))? } LoopExpr = { Label? ~ KEYWORD_loop ~ Block } -ForExpr = { Label? ~ KEYWORD_for ~ Expr ~ (COMMA ~ Expr)* ~ KEYWORD_as ~ BindingIdent ~ (COMMA ~ BindingIdent)* ~ Block ~ (KEYWORD_else ~ (Block | Expr))? } +ForExpr = { Label? ~ KEYWORD_for ~ Pattern ~ COLON ~ ExprNoStruct ~ (COMMA ~ ExprNoStruct)* ~ Block ~ (KEYWORD_else ~ (Block | Expr))? } -MatchExpr = { KEYWORD_match ~ Expr ~ LBRACE ~ MatchArm* ~ RBRACE } -MatchArm = { MatchPattern ~ (COMMA ~ MatchPattern)* ~ FAT_R_ARROW ~ Block } +MatchExpr = { KEYWORD_match ~ ExprNoStruct ~ LBRACE ~ MatchArm* ~ RBRACE } +MatchArm = { Pattern ~ FAT_R_ARROW ~ Block ~ COMMA? } -// ============ 其他表达式 ============ ComptimeCallExpr = { AT ~ IDENTIFIER ~ LPAREN ~ ExprList? ~ RPAREN } ParenExpr = { - + LPAREN ~ RPAREN | LPAREN ~ Expr ~ COMMA ~ (Expr ~ COMMA)* ~ Expr? ~ RPAREN | LPAREN ~ Expr ~ RPAREN } -// ============ Token 定义 ============ AssignOp = { EQUAL | PLUS_EQ | MINUS_EQ | ASTERISK_EQ | SLASH_EQ | PERCENT_EQ | AMPERSAND_EQ | PIPE_EQ | CARET_EQ | L_ARROW2_EQ | R_ARROW2_EQ } BOOL_OR = { PIPE ~ PIPE } BOOL_AND = { AMPERSAND ~ AMPERSAND } diff --git a/nob.c b/nob.c index 1956e6b..80cb757 100644 --- a/nob.c +++ b/nob.c @@ -27,6 +27,7 @@ static const char *splc0_srcs[] = { "stage1/spl_tok.c", "stage1/spl_lexer.c", "stage1/spl_ast.c", + "stage1/spl_parser.c", "stage1/spl_dumptree.c", "stage1/spl_type.c", "stage1/spl_lang_type.c", diff --git a/stage1/spl_ast.c b/stage1/spl_ast.c index e19c510..413eafe 100644 --- a/stage1/spl_ast.c +++ b/stage1/spl_ast.c @@ -1,22 +1,4 @@ #include "spl_ast.h" -#include "spl_dbg.h" -#include "spl_dumptree.h" -#include "spl_tok.h" - -#define MOVE_VEC(dst, src) \ - do { \ - (dst) = (src); \ - vec_init(src); \ - } while (0) - -static char *sdupn(const char *s, usize n) { - char *r = malloc(n + 1); - if (!r) - return NULL; - memcpy(r, s, n); - r[n] = '\0'; - return r; -} const char *spl_ast_kind_name(spl_ast_node_kind_t kind) { static const char *const names[] = { @@ -57,2289 +39,16 @@ const char *spl_unary_op_name(spl_unary_op_t op) { } } -typedef struct { - spl_ast_t *ast; - spl_diag_t *diag; - usize pos; - int failed; - int stop_as; - int stop_agg; -} parser_t; - -/* token -> dbg 位置;tok 可为 NULL */ -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; -} - -/* 渲染 token: `lexeme` at line:col。 - 传入 NULL 表示 parser 走到了输入流末尾。 */ -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_FATAL(p, kind, tok, ...) \ - do { \ - (p)->failed = 1; \ - 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, __VA_ARGS__ " (got %s)", _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(parser_t *p) { - usize n = vec_size(p->ast->input); - usize i = p->pos; - while (i < n && is_trivia(vec_at(p->ast->input, i).type)) - i++; - p->pos = i; - if (i >= n) - return NULL; - return &vec_at(p->ast->input, i); -} - -static inline const spl_tok_t *advance(parser_t *p) { - const spl_tok_t *t = peek(p); - if (t && t->type != TOK_EOF) - p->pos++; - return t; -} - -static inline spl_ast_node_t *node_at(spl_ast_t *ast, spl_ast_node_ref_t ref) { - return &ast->node_buckets.data[ref]; -} - -static spl_ast_node_ref_t new_node(parser_t *p, spl_ast_node_kind_t kind, const spl_tok_t *tok) { - spl_ast_node_t n = {0}; - n.kind = kind; - n.resolved_def_id = 0; - n.resolved_lang_tid = 0; - vec_init(n.attrs); - if (tok) { - n.dbg.dbg_name = spl_ast_kind_name(kind); - n.dbg.fname = tok->fname; - n.dbg.line = (int)tok->line; - n.dbg.col = (int)tok->col; - } - vec_push(p->ast->node_buckets, n); - return p->ast->node_buckets.size - 1; -} - -static char *intern_string(spl_ast_t *ast, const char *s, usize len) { - char *copy = sdupn(s, len); - if (!copy) - return NULL; - vec_push(ast->str_buckets, copy); - return copy; -} - -#define SET_STR_FIELD(ast, field, tok) \ - do { \ - (field) = intern_string(ast, (tok)->lexeme, (tok)->len); \ - } while (0) - -static spl_ast_node_ref_t mk_bin(parser_t *p, const spl_tok_t *loc, spl_binary_op_t op, - spl_ast_node_ref_t left, spl_ast_node_ref_t right) { - spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_BINARY, loc); - spl_ast_node_t *node = node_at(p->ast, ref); - node->binary.op = op; - node->binary.left = left; - node->binary.right = right; - return ref; -} - -static spl_ast_node_ref_t mk_unary(parser_t *p, const spl_tok_t *loc, spl_unary_op_t op, - spl_ast_node_ref_t operand) { - spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_UNARY, loc); - spl_ast_node_t *node = node_at(p->ast, ref); - node->unary.op = op; - node->unary.operand = operand; - return ref; -} - -static spl_ast_node_ref_t parse_expr(parser_t *p); -static spl_ast_node_ref_vec_t parse_expr_list(parser_t *p); -static spl_ast_node_ref_t parse_block(parser_t *p); -static spl_ast_node_ref_t parse_type_expr(parser_t *p); -static spl_ast_node_ref_t parse_type_comptime_call(parser_t *p); -static spl_ast_node_ref_t parse_statement(parser_t *p); -static spl_ast_node_ref_t parse_container_declaration(parser_t *p); -static spl_ast_node_ref_t parse_param_decl_impl(parser_t *p); -static spl_ast_node_ref_t parse_var_pattern(parser_t *p); -static spl_ast_node_ref_t parse_match_pattern(parser_t *p); - -static spl_ast_node_ref_t parse_cast(parser_t *p); -static spl_ast_node_ref_t parse_prefix(parser_t *p); -static spl_ast_node_ref_t parse_postfix(parser_t *p); -static spl_ast_node_ref_t parse_primary(parser_t *p); -static spl_ast_node_ref_vec_t parse_aggregate_fields(parser_t *p); -static spl_ast_node_ref_t parse_array_literal(parser_t *p); -static spl_ast_node_ref_t parse_comptime_call(parser_t *p); -static spl_ast_node_ref_t parse_if_expr(parser_t *p); -static spl_ast_node_ref_t parse_while_expr(parser_t *p); -static spl_ast_node_ref_t parse_loop_expr(parser_t *p); -static spl_ast_node_ref_t parse_for_expr(parser_t *p); -static spl_ast_node_ref_t parse_match_expr(parser_t *p); -static spl_ast_node_ref_t parse_ret_stmt(parser_t *p); -static spl_ast_node_ref_t parse_break_stmt(parser_t *p); -static spl_ast_node_ref_t parse_continue_stmt(parser_t *p); -static spl_ast_node_ref_t parse_defer_stmt(parser_t *p); -static spl_ast_node_ref_t parse_comptime_stmt(parser_t *p); -static spl_ast_node_ref_t parse_label(parser_t *p); - -static isize parse_int_literal(const spl_tok_t *t) { - char buf[128]; - usize j = 0; - for (usize i = 0; i < t->len && j < sizeof(buf) - 1; i++) { - if (t->lexeme[i] != '_') - buf[j++] = t->lexeme[i]; - } - buf[j] = 0; - /* 字面量按无符号位模式解析,以容纳完整的 u64 值域 */ - 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 *p = t->lexeme + 1; - const char *end = t->lexeme + t->len - 1; - char c = 0; - if (p < end) { - spl_decode_escape(&p, &c); - } - return c; -} - -static char *parse_string_literal(parser_t *p, const spl_tok_t *t, usize *out_len) { - const char *src = t->lexeme + 1; - const char *end = t->lexeme + t->len - 1; - usize cap = t->len + 1; - char *tmp = malloc(cap); - if (!tmp) { - *out_len = 0; - return NULL; - } - char *dst = tmp; - while (src < end) { - char c; - if (spl_decode_escape(&src, &c) == 0) { - *dst++ = c; - } else { - *dst++ = *src; - src++; - } - } - *out_len = (usize)(dst - tmp); - char *interned = intern_string(p->ast, tmp, dst - tmp); - free(tmp); - return interned; -} - -static int can_start_expr(spl_tok_type_t t) { - switch (t) { - case TOK_INT_LITERAL: - case TOK_FLOAT_LITERAL: - case TOK_CHAR_LITERAL: - case TOK_STRING_LITERAL: - case KW_TRUE: - case KW_FALSE: - case KW_NULL: - case KW_UNDEFINED: - case TOK_IDENT: - case TOK_AT: - case TOK_SHARP: - case TOK_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 void parse_tag_list(parser_t *p, spl_ast_node_ref_vec_t *out, int is_external, - int allow_at) { - while (!p->failed) { - const spl_tok_t *t = peek(p); - if (!t || (t->type != TOK_AT && t->type != TOK_SHARP)) - return; - if (!allow_at && t->type == TOK_AT) - return; - - int is_at = (t->type == TOK_AT); - advance(p); - - if (is_external) { - t = peek(p); - if (!t || t->type != TOK_NOT) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '!' in external tag"); - return; - } - advance(p); - } - - t = peek(p); - if (!t || t->type != TOK_IDENT) { - PARSE_FATAL(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; - t = peek(p); - if (!t || t->type != TOK_R_PAREN) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ')' in tag args"); - return; - } - advance(p); - } - vec_push(*out, ref); - } -} - -static void parse_param_list(parser_t *p, spl_ast_node_ref_vec_t *out) { - while (!p->failed) { - const spl_tok_t *t = peek(p); - if (!t) - break; - - if (t->type == TOK_R_PAREN) { - break; - } else if (t->type == TOK_AT || t->type == TOK_SHARP || t->type == TOK_IDENT) { - spl_ast_node_ref_t pd = parse_param_decl_impl(p); - if (pd) - vec_push(*out, pd); - if (peek(p) && peek(p)->type == TOK_COMMA) { - advance(p); - continue; - } - break; - } else if (t->type == TOK_ELLIPSIS) { - advance(p); - spl_ast_node_ref_t pd = new_node(p, SPL_AST_PARAM_DECL, t); - node_at(p->ast, pd)->param_decl.name = NULL; - node_at(p->ast, pd)->param_decl.type_expr = 0; - vec_push(*out, pd); - if (peek(p) && peek(p)->type == TOK_COMMA) - advance(p); - break; - } else { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, - "unexpected token in parameter list"); - break; - } - } -} - -static spl_ast_node_ref_t parse_param_decl_impl(parser_t *p) { - spl_ast_node_ref_vec_t attr_list; - vec_init(attr_list); - parse_tag_list(p, &attr_list, 0, 1); - - const spl_tok_t *name = peek(p); - if (!name || (name->type != TOK_IDENT && name->type != KW_UNDERSCORE)) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, name, "expected parameter name or '_'"); - return 0; - } - advance(p); - - const spl_tok_t *t = peek(p); - if (!t || t->type != TOK_COLON) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ':' in parameter declaration"); - return 0; - } - advance(p); - - parse_tag_list(p, &attr_list, 0, 0); - - spl_ast_node_ref_t type_expr = parse_type_expr(p); - spl_ast_node_ref_t ref = new_node(p, SPL_AST_PARAM_DECL, name); - spl_ast_node_t *param = node_at(p->ast, ref); - MOVE_VEC(param->param_decl.attr_list, attr_list); - SET_STR_FIELD(p->ast, param->param_decl.name, name); - param->param_decl.type_expr = type_expr; - return ref; -} - -static spl_ast_node_ref_t parse_fn_decl(parser_t *p, spl_ast_node_ref_vec_t tag_list) { - const spl_tok_t *kw = peek(p); - if (!kw || kw->type != KW_FN) - return 0; - advance(p); - - const spl_tok_t *name = peek(p); - if (!name || name->type != TOK_IDENT) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, name ? name : kw, "expected function name"); - return 0; - } - advance(p); - - const spl_tok_t *t = peek(p); - if (!t || t->type != TOK_L_PAREN) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '(' in function declaration"); - return 0; - } - advance(p); - - spl_ast_node_ref_vec_t params; - vec_init(params); - parse_param_list(p, ¶ms); - t = peek(p); - if (!t || t->type != TOK_R_PAREN) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ')' in function declaration"); - return 0; - } - advance(p); - - spl_ast_node_ref_t ret_type = 0; - t = peek(p); - if (t && t->type == TOK_COLON) { - advance(p); - ret_type = parse_type_expr(p); - t = peek(p); - } - - spl_ast_node_ref_t body = 0; - if (t && t->type == TOK_L_BRACE) { - body = parse_block(p); - } else if (t && t->type == TOK_SEMICOLON) { - advance(p); - } else { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, - "function declaration must end with ';' or block"); - return 0; - } - - spl_ast_node_ref_t ref = new_node(p, SPL_AST_FN_DECL, kw); - spl_ast_node_t *fn = node_at(p->ast, ref); - MOVE_VEC(fn->fn_decl.tag_list, tag_list); - fn->fn_decl.is_comptime = 0; - SET_STR_FIELD(p->ast, fn->fn_decl.name, name); - fn->fn_decl.params = params; /* params 局部变量,直接转移 */ - fn->fn_decl.ret_type = ret_type; - fn->fn_decl.body = body; - return ref; -} - -static spl_ast_node_ref_t parse_type_decl(parser_t *p, spl_ast_node_ref_vec_t tag_list) { - const spl_tok_t *kw = peek(p); - if (!kw || kw->type != KW_TYPE) - return 0; - advance(p); - - const spl_tok_t *name = peek(p); - if (!name || name->type != TOK_IDENT) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, name ? name : kw, "expected type name"); - return 0; - } - advance(p); - - const spl_tok_t *t = peek(p); - if (!t || t->type != TOK_ASSIGN) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '=' in type declaration"); - return 0; - } - advance(p); - - spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_DECL, kw); - spl_ast_node_t *td = node_at(p->ast, ref); - MOVE_VEC(td->type_decl.attr_list, tag_list); - SET_STR_FIELD(p->ast, td->type_decl.name, name); - spl_ast_node_ref_t type_expr = parse_type_expr(p); - node_at(p->ast, ref)->type_decl.type_expr = type_expr; - - t = peek(p); - if (t && (t->type == TOK_COMMA || t->type == TOK_SEMICOLON)) { - advance(p); - } - return ref; -} - -static spl_ast_node_ref_t parse_var_const_decl(parser_t *p, spl_ast_node_ref_vec_t tag_list, - int is_const) { - const spl_tok_t *kw = peek(p); - if (!kw) - return 0; - if (is_const && kw->type != KW_CONST) - return 0; - if (!is_const && kw->type != KW_VAR) - return 0; - advance(p); - - spl_ast_node_ref_t pattern = parse_var_pattern(p); - if (!pattern) - return 0; - - spl_ast_node_ref_t type_expr = 0; - spl_ast_node_ref_t init_expr = 0; - const spl_tok_t *t = peek(p); - - if (t && t->type == TOK_COLON) { - advance(p); - type_expr = parse_type_expr(p); - t = peek(p); - if (t && t->type == TOK_ASSIGN) { - advance(p); - init_expr = parse_expr(p); - } - } else if (t && t->type == TOK_ASSIGN) { - advance(p); - init_expr = parse_expr(p); - } - - spl_ast_node_ref_t ref = new_node(p, is_const ? SPL_AST_CONST_DECL : SPL_AST_VAR_DECL, kw); - spl_ast_node_t *vc = node_at(p->ast, ref); - MOVE_VEC(vc->var_const_decl.attr_list, tag_list); - vc->var_const_decl.pattern = pattern; - vc->var_const_decl.type = type_expr; - vc->var_const_decl.init_expr = init_expr; - - t = peek(p); - if (t && t->type == TOK_SEMICOLON) { - advance(p); - } - return ref; -} - -static spl_ast_node_ref_t parse_member_decl(parser_t *p, spl_ast_node_ref_vec_t tag_list) { - const spl_tok_t *name = peek(p); - if (!name || name->type != TOK_IDENT) - return 0; - advance(p); - - spl_ast_node_ref_t type_expr = 0; - spl_ast_node_ref_t init_expr = 0; - const spl_tok_t *t = peek(p); - if (t && t->type == TOK_COLON) { - advance(p); - parse_tag_list(p, &tag_list, 0, 0); - type_expr = parse_type_expr(p); - t = peek(p); - if (t && t->type == TOK_ASSIGN) { - advance(p); - init_expr = parse_expr(p); - } - } else if (t && t->type == TOK_ASSIGN) { - advance(p); - init_expr = parse_expr(p); - } - - spl_ast_node_ref_t ref = new_node(p, SPL_AST_MEMBER_DECL, name); - spl_ast_node_t *md = node_at(p->ast, ref); - MOVE_VEC(md->member_decl.attr_list, tag_list); - SET_STR_FIELD(p->ast, md->member_decl.name, name); - md->member_decl.type_expr = type_expr; - md->member_decl.init_expr = init_expr; - - t = peek(p); - if (t && (t->type == TOK_COMMA || t->type == TOK_SEMICOLON)) { - advance(p); - } - return ref; -} - -static spl_ast_node_ref_t parse_comptime_decl(parser_t *p) { - const spl_tok_t *kw = peek(p); - if (!kw || kw->type != KW_COMPTIME) - return 0; - advance(p); - - spl_ast_node_ref_t body = 0; - const spl_tok_t *t = peek(p); - if (t && t->type == TOK_L_BRACE) { - body = parse_block(p); - } else { - body = parse_expr(p); - } - - spl_ast_node_ref_t ref = new_node(p, SPL_AST_COMPTIME_DECL, kw); - node_at(p->ast, ref)->comptime_decl.body = body; - return ref; -} - -static spl_ast_node_ref_t parse_container_declaration(parser_t *p) { - spl_ast_node_ref_vec_t tag_list; - vec_init(tag_list); - parse_tag_list(p, &tag_list, 0, 0); /* 只解析普通 tag */ - - const spl_tok_t *t = peek(p); - if (!t || t->type == TOK_EOF) { - vec_free(tag_list); - return 0; - } - - switch (t->type) { - case KW_FN: - return parse_fn_decl(p, tag_list); - case KW_TYPE: - return parse_type_decl(p, tag_list); - case KW_VAR: - return parse_var_const_decl(p, tag_list, 0); - case KW_CONST: - return parse_var_const_decl(p, tag_list, 1); - case TOK_IDENT: - return parse_member_decl(p, tag_list); - case KW_COMPTIME: - vec_free(tag_list); /* comptime decl 不使用 tag_list */ - return parse_comptime_decl(p); - case TOK_L_BRACE: { - spl_ast_node_ref_t block = parse_block(p); - spl_ast_node_ref_t ref = new_node(p, SPL_AST_TOP_LEVEL_BLOCK, t); - spl_ast_node_t *tb = node_at(p->ast, ref); - MOVE_VEC(tb->top_level_block.tag_list, tag_list); - tb->top_level_block.block = block; - return ref; - } - default: - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, "unrecognized declaration"); - vec_free(tag_list); - return 0; - } -} - -static spl_ast_node_ref_t parse_var_pattern_atom(parser_t *p) { - const spl_tok_t *t = peek(p); - if (!t) - return 0; - - if (t->type == TOK_IDENT) { - advance(p); - spl_ast_node_ref_t ref = new_node(p, SPL_AST_PATTERN_IDENT, t); - SET_STR_FIELD(p->ast, node_at(p->ast, ref)->pattern_ident.name, t); - return ref; - } else if (t->type == KW_UNDERSCORE) { - advance(p); - return new_node(p, SPL_AST_PATTERN_UNDERSCORE, t); - } else if (t->type == TOK_DOT) { - advance(p); - const spl_tok_t *name = peek(p); - if (!name || name->type != TOK_IDENT) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, name, - "expected identifier after '.' in pattern"); - return 0; - } - advance(p); - - spl_ast_node_ref_t ref = new_node(p, SPL_AST_PATTERN_DOT, t); - spl_ast_node_t *pat = node_at(p->ast, ref); - SET_STR_FIELD(p->ast, pat->pattern_dot.name, name); - - if (peek(p) && peek(p)->type == TOK_L_BRACKET) { - advance(p); - spl_ast_node_ref_t sub = parse_var_pattern(p); - node_at(p->ast, ref)->pattern_dot.sub_pattern = sub; - t = peek(p); - if (!t || t->type != TOK_R_BRACKET) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ']' in pattern"); - return 0; - } - advance(p); - } - return ref; - } else if (t->type == TOK_L_PAREN) { - advance(p); - spl_ast_node_ref_t inner = parse_var_pattern(p); - t = peek(p); - if (!t || t->type != TOK_R_PAREN) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ')' in pattern"); - return 0; - } - advance(p); - - spl_ast_node_ref_t ref = new_node(p, SPL_AST_PATTERN_TUPLE, t); - spl_ast_node_t *tuple = node_at(p->ast, ref); - vec_init(tuple->pattern_tuple.patterns); - if (node_at(p->ast, inner)->kind == SPL_AST_PATTERN_LIST) { - tuple->pattern_tuple.patterns = node_at(p->ast, inner)->pattern_list.patterns; - } else { - vec_push(tuple->pattern_tuple.patterns, inner); - } - return ref; - } else { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, "unexpected token in pattern"); - return 0; - } -} - -static spl_ast_node_ref_t parse_var_pattern(parser_t *p) { - spl_ast_node_ref_vec_t patterns; - vec_init(patterns); - - while (!p->failed) { - spl_ast_node_ref_t atom = parse_var_pattern_atom(p); - if (!atom) - break; - vec_push(patterns, atom); - - const spl_tok_t *t = peek(p); - if (t && t->type == TOK_COMMA) { - advance(p); - continue; - } - break; - } - - if (patterns.size == 0) - return 0; - if (patterns.size == 1) { - spl_ast_node_ref_t ref = patterns.data[0]; - vec_free(patterns); - return ref; - } - - spl_ast_node_ref_t ref = new_node(p, SPL_AST_PATTERN_LIST, peek(p)); - node_at(p->ast, ref)->pattern_list.patterns = patterns; - return ref; -} - -static spl_ast_node_ref_t parse_match_pattern(parser_t *p) { - const spl_tok_t *t = peek(p); - if (!t) - return 0; - - /* 如果当前 token 是模式专用起始符,按变量模式解析;否则按表达式解析 */ - if (t->type == KW_UNDERSCORE || t->type == TOK_DOT || t->type == TOK_L_PAREN) { - return parse_var_pattern(p); - } else { - /* 表达式模式:字面量、标识符、块、if 等 */ - return parse_expr(p); - } -} - -static spl_ast_node_ref_t parse_type_base(parser_t *p) { - const spl_tok_t *bt = peek(p); - if (!bt) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, bt, "expected type"); - return 0; - } - - /* 函数类型 */ - if (bt->type == KW_FN) { - advance(p); - const spl_tok_t *t = peek(p); - if (!t || t->type != TOK_L_PAREN) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '(' in function type"); - return 0; - } - advance(p); - - spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_FN, bt); - spl_ast_node_t *fn_type = node_at(p->ast, ref); - fn_type->type_fn.is_comptime = 0; - vec_init(fn_type->type_fn.params); - - while (!p->failed && peek(p) && peek(p)->type != TOK_R_PAREN) { - spl_ast_node_ref_t pt = parse_type_expr(p); - fn_type = node_at(p->ast, ref); // 防悬空 - vec_push(fn_type->type_fn.params, pt); - if (peek(p) && peek(p)->type == TOK_COMMA) { - advance(p); - continue; - } - break; - } - - t = peek(p); - if (!t || t->type != TOK_R_PAREN) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ')' in function type"); - return 0; - } - advance(p); - - if (peek(p) && peek(p)->type == TOK_COLON) { - advance(p); - spl_ast_node_ref_t ret = parse_type_expr(p); - node_at(p->ast, ref)->type_fn.ret_type = ret; - } - return ref; - } - - /* 聚合类型:struct / union / enum / shape */ - if (bt->type == KW_STRUCT || bt->type == KW_UNION || bt->type == KW_ENUM || - bt->type == KW_SHAPE) { - const char *kind_name = (bt->type == KW_STRUCT) ? "struct" - : (bt->type == KW_UNION) ? "union" - : (bt->type == KW_ENUM) ? "enum" - : "shape"; - advance(p); - const spl_tok_t *t = peek(p); - if (!t || t->type != TOK_L_BRACE) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '{' in aggregate type"); - return 0; - } - advance(p); - - spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_AGGREGATE, bt); - spl_ast_node_t *agg = node_at(p->ast, ref); - agg->type_aggregate.kind_name = kind_name; - vec_init(agg->type_aggregate.members); // 存放真正的容器声明节点 - - /* 解析容器成员,直到 '}' */ - while (!p->failed) { - t = peek(p); - if (!t || t->type == TOK_EOF) { - PARSE_FATAL(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; - } - - /* 内建类型和普通路径 */ - if (bt->type == TOK_IDENT || bt->type == KW_BOOL) { - const char *name = bt->lexeme; - usize len = bt->len; - /* 内建类型关键字 */ - if ((len == 2 && strncmp(name, "i8", 2) == 0) || - (len == 2 && strncmp(name, "u8", 2) == 0) || - (len == 3 && strncmp(name, "i16", 3) == 0) || - (len == 3 && strncmp(name, "u16", 3) == 0) || - (len == 3 && strncmp(name, "i32", 3) == 0) || - (len == 3 && strncmp(name, "u32", 3) == 0) || - (len == 3 && strncmp(name, "i64", 3) == 0) || - (len == 3 && strncmp(name, "u64", 3) == 0) || - (len == 5 && strncmp(name, "isize", 5) == 0) || - (len == 5 && strncmp(name, "usize", 5) == 0) || - (len == 3 && strncmp(name, "f32", 3) == 0) || - (len == 3 && strncmp(name, "f64", 3) == 0) || - (len == 4 && strncmp(name, "bool", 4) == 0)) { - advance(p); - spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_PATH, bt); - spl_ast_node_t *tp = node_at(p->ast, ref); - SET_STR_FIELD(p->ast, tp->type_path.name, bt); - vec_init(tp->type_path.generic_args); - return ref; - } - - /* 普通类型路径 */ - advance(p); - spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_PATH, bt); - spl_ast_node_t *tp = node_at(p->ast, ref); - SET_STR_FIELD(p->ast, tp->type_path.name, bt); - vec_init(tp->type_path.generic_args); - - while (peek(p) && peek(p)->type == TOK_DOT) { - advance(p); - const spl_tok_t *seg = peek(p); - if (!seg || seg->type != TOK_IDENT) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, seg, - "expected identifier after '.' in type path"); - break; - } - advance(p); - } - return ref; - } - - if (bt->type == TOK_AT || bt->type == TOK_SHARP) { - return parse_type_comptime_call(p); - } - - if (bt->type == KW_ANY) { - advance(p); - spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_PATH, bt); - spl_ast_node_t *tp = node_at(p->ast, ref); - SET_STR_FIELD(p->ast, tp->type_path.name, bt); - vec_init(tp->type_path.generic_args); - return ref; - } - - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, bt, "unrecognized type"); - return 0; -} - -static spl_ast_node_ref_t parse_type_comptime_call(parser_t *p) { - const spl_tok_t *start = peek(p); - if (!start || (start->type != TOK_AT && start->type != TOK_SHARP)) - return 0; - advance(p); - - const spl_tok_t *name = peek(p); - if (!name || name->type != TOK_IDENT) { - PARSE_FATAL(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); - t = peek(p); - if (!t || t->type != TOK_R_PAREN) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ')' in comptime type"); - vec_free(args); - return 0; - } - advance(p); - } - - spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_COMPTIME_CALL, start); - spl_ast_node_t *cc = node_at(p->ast, ref); - SET_STR_FIELD(p->ast, cc->type_comptime_call.name, name); - cc->type_comptime_call.args = args; - return ref; -} - -static spl_ast_node_ref_t parse_type_expr(parser_t *p) { - const spl_tok_t *t = peek(p); - if (!t) { - PARSE_FATAL(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); - } - - t = peek(p); - if (!t || t->type != TOK_R_BRACKET) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ']' in array type"); - return 0; - } - advance(p); - - spl_ast_node_ref_t elem_type = parse_type_expr(p); - - spl_ast_node_ref_t ref; - if (has_len) { - ref = new_node(p, SPL_AST_TYPE_ARRAY, t); - spl_ast_node_t *arr = node_at(p->ast, ref); - arr->type_array.has_len = true; - arr->type_array.len = len; - arr->type_array.is_underscore_len = is_underscore; - arr->type_array.elem_type = elem_type; - } else { - ref = new_node(p, SPL_AST_TYPE_SLICE, t); - node_at(p->ast, ref)->type_slice.elem_type = elem_type; - } - return ref; - } - - if (t->type == TOK_L_PAREN) { - advance(p); - spl_ast_node_ref_vec_t types; - vec_init(types); - - if (peek(p) && peek(p)->type == TOK_R_PAREN) { - advance(p); - spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_PAREN, t); - node_at(p->ast, ref)->type_paren.types = types; - return ref; - } - - spl_ast_node_ref_t first = parse_type_expr(p); - vec_push(types, first); - - while (peek(p) && peek(p)->type == TOK_COMMA) { - advance(p); - if (peek(p) && peek(p)->type == TOK_R_PAREN) - break; - spl_ast_node_ref_t next = parse_type_expr(p); - vec_push(types, next); - } - - t = peek(p); - if (!t || t->type != TOK_R_PAREN) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ')' in parenthesized type"); - return 0; - } - advance(p); - - if (types.size == 1) { - vec_free(types); - return first; - } - - spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_PAREN, t); - node_at(p->ast, ref)->type_paren.types = types; - return ref; - } - - 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_FATAL(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(parser_t *p) { - spl_ast_node_ref_vec_t vec; - vec_init(vec); - if (p->failed) - return vec; - - const spl_tok_t *t = peek(p); - if (!t || !can_start_expr(t->type)) - return vec; - - vec_push(vec, parse_expr(p)); - while (!p->failed && peek(p) && peek(p)->type == TOK_COMMA) { - advance(p); - if (!peek(p) || !can_start_expr(peek(p)->type)) - break; - vec_push(vec, parse_expr(p)); - } - return vec; -} - -static spl_ast_node_ref_vec_t parse_aggregate_fields(parser_t *p) { - spl_ast_node_ref_vec_t fields; - vec_init(fields); - - const spl_tok_t *t = peek(p); - if (!t || t->type != TOK_L_BRACE) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '{' in aggregate literal"); - return fields; - } - advance(p); - - while (!p->failed) { - t = peek(p); - if (!t || t->type == TOK_R_BRACE || t->type == TOK_EOF) - break; - - if (t->type != TOK_DOT) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, - "expected '.' in aggregate field initializer"); - break; - } - advance(p); - - t = peek(p); - if (!t || t->type != TOK_IDENT) { - PARSE_FATAL(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; - } - - t = peek(p); - if (!t || t->type != TOK_R_BRACE) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '}' in aggregate literal"); - } else { - advance(p); - } - - return fields; -} - -typedef struct { - int prec; - char assoc; // 'L', 'R', 'N' -} op_info_t; - -static op_info_t binary_op_info[] = { -#define X(name, prec, assoc, str) {prec, assoc}, - SPL_BINARY_OP_TABLE -#undef X -}; - -static spl_binary_op_t token_to_binary_op(spl_tok_type_t tt) { - switch (tt) { - case TOK_ASSIGN: - return SPL_OP_ASSIGN; - case TOK_ASSIGN_ADD: - return SPL_OP_ASSIGN_ADD; - case TOK_ASSIGN_SUB: - return SPL_OP_ASSIGN_SUB; - case TOK_ASSIGN_MUL: - return SPL_OP_ASSIGN_MUL; - case TOK_ASSIGN_DIV: - return SPL_OP_ASSIGN_DIV; - case TOK_ASSIGN_MOD: - return SPL_OP_ASSIGN_MOD; - case TOK_ASSIGN_AND: - return SPL_OP_ASSIGN_AND; - case TOK_ASSIGN_OR: - return SPL_OP_ASSIGN_OR; - case TOK_ASSIGN_XOR: - return SPL_OP_ASSIGN_XOR; - case TOK_ASSIGN_L_SH: - return SPL_OP_ASSIGN_LSHIFT; - case TOK_ASSIGN_R_SH: - return SPL_OP_ASSIGN_RSHIFT; - case TOK_OR_OR: - return SPL_OP_BOOL_OR; - case TOK_AND_AND: - return SPL_OP_BOOL_AND; - case TOK_OR: - return SPL_OP_BIT_OR; - case TOK_XOR: - return SPL_OP_BIT_XOR; - case TOK_AND: - return SPL_OP_BIT_AND; - case TOK_EQ: - return SPL_OP_CMP_EQ; - case TOK_NEQ: - return SPL_OP_CMP_NE; - case TOK_LE: - return SPL_OP_CMP_LE; - case TOK_GE: - return SPL_OP_CMP_GE; - case TOK_LT: - return SPL_OP_CMP_LT; - case TOK_GT: - return SPL_OP_CMP_GT; - case TOK_LEFT_ARROW: - return SPL_OP_ARROW_LEFT; - case TOK_RIGHT_ARROW: - return SPL_OP_ARROW_RIGHT; - case TOK_FAT_ARROW_BOTH: - return SPL_OP_ARROW_FAT_BOTH; - case TOK_ARROW_BOTH: - return SPL_OP_ARROW_THIN_BOTH; - case TOK_RIGHT_FAT_ARROW: - return SPL_OP_ARROW_FAT_RIGHT; - case TOK_RANGE: - return SPL_OP_RANGE; - case TOK_L_SH: - return SPL_OP_LSHIFT; - case TOK_R_SH: - return SPL_OP_RSHIFT; - case TOK_ADD: - return SPL_OP_ADD; - case TOK_SUB: - return SPL_OP_SUB; - case TOK_MUL: - return SPL_OP_MUL; - case TOK_DIV: - return SPL_OP_DIV; - case TOK_MOD: - return SPL_OP_MOD; - default: - return (spl_binary_op_t)-1; // 无效 - } -} - -static spl_ast_node_ref_t parse_expr_prec(parser_t *p, int min_prec) { - spl_ast_node_ref_t left = parse_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); // 最小优先级 = range 优先级 + 1 - left = mk_bin(p, t, op, left, right); - continue; - } - - int next_min = info.prec; - if (info.assoc == 'R') { - next_min = info.prec; - } else { - next_min = info.prec + 1; - } - - spl_ast_node_ref_t right = parse_expr_prec(p, next_min); - left = mk_bin(p, t, op, left, right); - } - - return left; -} - -static spl_ast_node_ref_t parse_expr(parser_t *p) { - return parse_expr_prec(p, 1); // 最低优先级 -} - -static spl_ast_node_ref_t parse_cast(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 || p->stop_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(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_FATAL(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(parser_t *p) { - spl_ast_node_ref_t expr = parse_primary(p); - while (!p->failed) { - const spl_tok_t *t = peek(p); - if (!t) - break; - - if (t->type == TOK_L_PAREN) { - advance(p); - spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_CALL, t); - node_at(p->ast, ref)->call.callee = expr; - - spl_ast_node_ref_vec_t args = parse_expr_list(p); - node_at(p->ast, ref)->call.args = args; - - t = peek(p); - if (!t || t->type != TOK_R_PAREN) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ')' in call"); - return expr; - } - advance(p); - expr = ref; - } else if (t->type == TOK_DOT) { - advance(p); - const spl_tok_t *next = peek(p); - if (!next) - break; - if (next->type == TOK_IDENT) { - advance(p); - spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_FIELD, t); - node_at(p->ast, ref)->field.obj = expr; - SET_STR_FIELD(p->ast, node_at(p->ast, ref)->field.field, next); - expr = ref; - } else if (next->type == TOK_MUL) { - advance(p); - spl_ast_node_ref_t ref = mk_unary(p, t, SPL_UNARY_OP_DEREF, expr); - expr = ref; - } else { - PARSE_FATAL(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); - t = peek(p); - if (!t || t->type != TOK_R_BRACKET) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ']' in slice"); - return expr; - } - advance(p); - spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_SLICE, t); - node_at(p->ast, ref)->slice.obj = expr; - node_at(p->ast, ref)->slice.begin = begin; - node_at(p->ast, ref)->slice.end = end; - expr = ref; - } else { - t = peek(p); - if (!t || t->type != TOK_R_BRACKET) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ']' in index"); - return expr; - } - advance(p); - spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_INDEX, t); - node_at(p->ast, ref)->index.obj = expr; - node_at(p->ast, ref)->index.index = begin; - expr = ref; - } - } else { - break; - } - } - return expr; -} - -static spl_ast_node_ref_t parse_primary(parser_t *p) { - const spl_tok_t *t = peek(p); - if (!t) { - PARSE_FATAL(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 = parse_int_literal(t); // FIXME - 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); // FIXME - 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_FATAL(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) { - // 匿名数组字面量:. [ elems ] - advance(p); // 消费 '[' - // 先解析元素列表,避免节点扩容导致 arr 指针失效 - spl_ast_node_ref_vec_t elems = parse_expr_list(p); - const spl_tok_t *close = peek(p); - if (!close || close->type != TOK_R_BRACKET) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, close, "expected ']'"); - return 0; - } - advance(p); // 消费 ']' - spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_ARRAY_LIT, t); - spl_ast_node_t *arr = node_at(p->ast, ref); - arr->array_literal.elems = elems; - arr->array_literal.elem_type = 0; - return ref; - } else { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, nx, "expected '{' or '[' after '.'"); - return 0; - } - } - case TOK_L_BRACKET: - return parse_array_literal(p); - case TOK_L_BRACE: - return parse_block(p); - case TOK_AT: - case TOK_SHARP: - return parse_comptime_call(p); - case TOK_L_PAREN: { - advance(p); - spl_ast_node_ref_vec_t elems; - vec_init(elems); - - if (peek(p) && peek(p)->type == TOK_R_PAREN) { - advance(p); - spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_TUPLE, t); - node_at(p->ast, ref)->tuple.elems = elems; - return ref; - } - - spl_ast_node_ref_t first = parse_expr(p); - if (peek(p) && peek(p)->type == TOK_COMMA) { - vec_push(elems, first); - while (peek(p) && peek(p)->type == TOK_COMMA) { - advance(p); - if (peek(p) && peek(p)->type == TOK_R_PAREN) - break; - vec_push(elems, parse_expr(p)); - } - t = peek(p); - if (!t || t->type != TOK_R_PAREN) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ')'"); - return 0; - } - advance(p); - spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_TUPLE, t); - node_at(p->ast, ref)->tuple.elems = elems; - return ref; - } else { - t = peek(p); - if (!t || t->type != TOK_R_PAREN) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ')'"); - return 0; - } - advance(p); - vec_free(elems); - return first; - } - } - case KW_IF: - return parse_if_expr(p); - case KW_WHILE: - return parse_while_expr(p); - case KW_LOOP: - return parse_loop_expr(p); - case KW_FOR: - return parse_for_expr(p); - case KW_MATCH: - return parse_match_expr(p); - default: - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, "unrecognized expression"); - return 0; - } -} - -static spl_ast_node_ref_t parse_array_literal(parser_t *p) { - const spl_tok_t *start = peek(p); - if (!start || start->type != TOK_L_BRACKET) - return 0; - advance(p); - - bool has_len = false; - isize len = 0; - bool is_underscore = false; - - const spl_tok_t *t = peek(p); - if (t && t->type == TOK_INT_LITERAL) { - len = parse_int_literal(t); - has_len = true; - advance(p); - } else if (t && t->type == KW_UNDERSCORE) { - has_len = true; - is_underscore = true; - advance(p); - } - - t = peek(p); - if (!t || t->type != TOK_R_BRACKET) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ']' in array literal"); - return 0; - } - advance(p); - - spl_ast_node_ref_t elem_type = parse_type_expr(p); - - t = peek(p); - if (!t || t->type != TOK_L_BRACKET) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '[' in array literal"); - return 0; - } - advance(p); - - spl_ast_node_ref_vec_t elems = parse_expr_list(p); - - t = peek(p); - if (!t || t->type != TOK_R_BRACKET) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ']' in array literal"); - return 0; - } - advance(p); - - spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_ARRAY_LIT, start); - spl_ast_node_t *arr = node_at(p->ast, ref); - arr->array_literal.has_len = has_len; - arr->array_literal.len = len; - arr->array_literal.is_underscore_len = is_underscore; - arr->array_literal.elem_type = elem_type; - arr->array_literal.elems = elems; // elems 是局部 vec,直接转移 - return ref; -} - -static spl_ast_node_ref_t parse_comptime_call(parser_t *p) { - const spl_tok_t *start = peek(p); - if (!start || (start->type != TOK_AT && start->type != TOK_SHARP)) - return 0; - advance(p); - - const spl_tok_t *name = peek(p); - if (!name || name->type != TOK_IDENT) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, name, "expected comptime name"); - return 0; - } - advance(p); - - spl_ast_node_ref_vec_t args; - vec_init(args); - int has_paren = 0; - - const spl_tok_t *t = peek(p); - if (t && t->type == TOK_L_PAREN) { - has_paren = 1; - advance(p); - args = parse_expr_list(p); - t = peek(p); - if (!t || t->type != TOK_R_PAREN) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected ')' in comptime call"); - vec_free(args); - return 0; - } - advance(p); - } - - spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_COMPTIME_CALL, start); - spl_ast_node_t *cc = node_at(p->ast, ref); - SET_STR_FIELD(p->ast, cc->comptime_call.name, name); - cc->comptime_call.args = args; - (void)has_paren; - return ref; -} - -static spl_ast_node_ref_t parse_label(parser_t *p) { - const spl_tok_t *t = peek(p); - if (!t || t->type != TOK_DOLLAR) - return 0; - advance(p); - const spl_tok_t *name = peek(p); - if (!name || name->type != TOK_IDENT) { - PARSE_FATAL(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(parser_t *p) { - const spl_tok_t *kw = peek(p); - if (!kw || kw->type != KW_IF) - return 0; - advance(p); - - int is_ifvar = 0; - spl_ast_node_ref_t var_decl = 0; - - const spl_tok_t *t = peek(p); - if (t && t->type == KW_VAR) { - advance(p); - is_ifvar = 1; - - spl_ast_node_ref_t pattern = parse_var_pattern(p); - if (!pattern) - return 0; - - spl_ast_node_ref_t type_expr = 0; - spl_ast_node_ref_t init_expr = 0; - t = peek(p); - if (t && t->type == TOK_COLON) { - advance(p); - type_expr = parse_type_expr(p); - t = peek(p); - if (t && t->type == TOK_ASSIGN) { - advance(p); - init_expr = parse_expr(p); - } else { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '=' in if var"); - return 0; - } - } else if (t && t->type == TOK_ASSIGN) { - advance(p); - init_expr = parse_expr(p); - } else { - PARSE_FATAL(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(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(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(parser_t *p) { - const spl_tok_t *kw = peek(p); - if (!kw || kw->type != KW_FOR) - return 0; - advance(p); - - p->stop_as = 1; - spl_ast_node_ref_vec_t iter_exprs; - vec_init(iter_exprs); - vec_push(iter_exprs, parse_expr(p)); - while (peek(p) && peek(p)->type == TOK_COMMA) { - advance(p); - vec_push(iter_exprs, parse_expr(p)); - } - p->stop_as = 0; - - const spl_tok_t *t = peek(p); - if (!t || t->type != KW_AS) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected 'as' in for loop"); - return 0; - } - advance(p); - - spl_ast_node_ref_vec_t idents; - vec_init(idents); - t = peek(p); - if (!t || (t->type != TOK_IDENT && t->type != KW_UNDERSCORE)) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected binding variable or '_' in for"); - return 0; - } - advance(p); - spl_ast_node_ref_t id_node = new_node(p, SPL_AST_EXPR_IDENT, t); - SET_STR_FIELD(p->ast, node_at(p->ast, id_node)->ident.name, t); - vec_push(idents, id_node); - - while (peek(p) && peek(p)->type == TOK_COMMA) { - advance(p); - t = peek(p); - if (!t || (t->type != TOK_IDENT && t->type != KW_UNDERSCORE)) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, - "expected binding variable or '_' in for"); - return 0; - } - advance(p); - id_node = new_node(p, SPL_AST_EXPR_IDENT, t); - SET_STR_FIELD(p->ast, node_at(p->ast, id_node)->ident.name, t); - vec_push(idents, id_node); - } - - spl_ast_node_ref_t body = parse_block(p); - if (!body) - return 0; - - 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.idents = idents; - fe->for_expr.body = body; - fe->for_expr.else_branch = else_branch; - return ref; -} - -static int parse_match_arm(parser_t *p, spl_ast_node_ref_vec_t *patterns_out, - spl_ast_node_ref_vec_t *bodies_out) { - spl_ast_node_ref_vec_t pats; - vec_init(pats); - - while (!p->failed) { - spl_ast_node_ref_t pat = parse_match_pattern(p); - if (!pat) - break; - vec_push(pats, pat); - if (peek(p) && peek(p)->type == TOK_COMMA) { - advance(p); - continue; - } - break; - } - - const spl_tok_t *t = peek(p); - if (!t || t->type != TOK_RIGHT_FAT_ARROW) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '=>' in match arm"); - return 0; - } - advance(p); - - spl_ast_node_ref_t body; - t = peek(p); - if (!t || t->type != TOK_L_BRACE) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected block after '=>' in match arm"); - return 0; - } - body = parse_block(p); - - for (usize i = 0; i < pats.size; i++) { - vec_push(*patterns_out, pats.data[i]); - vec_push(*bodies_out, body); - } - vec_free(pats); - return 1; -} - -static spl_ast_node_ref_t parse_match_expr(parser_t *p) { - const spl_tok_t *kw = peek(p); - if (!kw || kw->type != KW_MATCH) - return 0; - advance(p); - - p->stop_agg++; - spl_ast_node_ref_t matched_expr = parse_expr(p); - p->stop_agg--; - - const spl_tok_t *t = peek(p); - if (!t || t->type != TOK_L_BRACE) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '{' in match"); - return 0; - } - advance(p); - - spl_ast_node_ref_vec_t patterns, bodies; - vec_init(patterns); - vec_init(bodies); - - while (!p->failed) { - t = peek(p); - if (!t || t->type == TOK_R_BRACE || t->type == TOK_EOF) - break; - if (!parse_match_arm(p, &patterns, &bodies)) - break; - if (peek(p) && peek(p)->type == TOK_COMMA) - advance(p); - } - - t = peek(p); - if (!t || t->type != TOK_R_BRACE) { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, "expected '}' in match"); - return 0; - } - advance(p); - - spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_MATCH, kw); - spl_ast_node_t *me = node_at(p->ast, ref); - me->match_expr.matched_expr = matched_expr; - vec_init(me->match_expr.arms); - for (usize i = 0; i < patterns.size; i++) { - spl_ast_node_ref_t arm = new_node(p, SPL_AST_MATCH_ARM, NULL); - spl_ast_node_t *arm_node = node_at(p->ast, arm); - arm_node->match_arm.pattern = patterns.data[i]; - arm_node->match_arm.body = bodies.data[i]; - - me = node_at(p->ast, ref); /* 每次迭代重新获取 防止 new_node 扩容 */ - vec_push(me->match_expr.arms, arm); - } - vec_free(patterns); - vec_free(bodies); - return ref; -} - -static spl_ast_node_ref_t parse_ret_stmt(parser_t *p) { - const spl_tok_t *kw = peek(p); - if (!kw || kw->type != KW_RET) - return 0; - advance(p); - - spl_ast_node_ref_t expr = 0; - const spl_tok_t *t = peek(p); - if (t && can_start_expr(t->type)) - expr = parse_expr(p); - - t = peek(p); - if (t && t->type == TOK_SEMICOLON) - advance(p); - - spl_ast_node_ref_t ref = new_node(p, SPL_AST_STATEMENT_RET, kw); - node_at(p->ast, ref)->statement_ret.expr = expr; - return ref; -} - -static spl_ast_node_ref_t parse_break_stmt(parser_t *p) { - const spl_tok_t *kw = peek(p); - if (!kw || kw->type != KW_BREAK) - return 0; - advance(p); - - spl_ast_node_ref_t label = parse_label(p); - spl_ast_node_ref_t expr = 0; - const spl_tok_t *t = peek(p); - if (t && can_start_expr(t->type)) - expr = parse_expr(p); - - t = peek(p); - if (t && t->type == TOK_SEMICOLON) - advance(p); - - spl_ast_node_ref_t ref = new_node(p, SPL_AST_STATEMENT_BREAK, kw); - node_at(p->ast, ref)->statement_break.label = label; - node_at(p->ast, ref)->statement_break.expr = expr; - return ref; -} - -static spl_ast_node_ref_t parse_continue_stmt(parser_t *p) { - const spl_tok_t *kw = peek(p); - if (!kw || kw->type != KW_CONTINUE) - return 0; - advance(p); - - spl_ast_node_ref_t label = parse_label(p); - - const spl_tok_t *t = peek(p); - if (t && t->type == TOK_SEMICOLON) - advance(p); - - spl_ast_node_ref_t ref = new_node(p, SPL_AST_STATEMENT_CONTINUE, kw); - node_at(p->ast, ref)->statement_continue.label = label; - return ref; -} - -static spl_ast_node_ref_t parse_defer_stmt(parser_t *p) { - const spl_tok_t *kw = peek(p); - if (!kw || kw->type != KW_DEFER) - return 0; - advance(p); - - spl_ast_node_ref_t body = 0; - const spl_tok_t *t = peek(p); - if (t && t->type == TOK_L_BRACE) { - body = parse_block(p); - } else if (t && can_start_statement(t->type)) { - body = parse_statement(p); - } else { - body = parse_expr(p); - t = peek(p); - if (t && t->type == TOK_SEMICOLON) - advance(p); - } - - spl_ast_node_ref_t ref = new_node(p, SPL_AST_STATEMENT_DEFER, kw); - node_at(p->ast, ref)->statement_defer.body = body; - return ref; -} - -static spl_ast_node_ref_t parse_comptime_stmt(parser_t *p) { - const spl_tok_t *kw = peek(p); - if (!kw || kw->type != KW_COMPTIME) - return 0; - advance(p); - - spl_ast_node_ref_t body = 0; - const spl_tok_t *t = peek(p); - if (t && t->type == TOK_L_BRACE) { - body = parse_block(p); - } else { - body = parse_expr(p); - } - - spl_ast_node_ref_t ref = new_node(p, SPL_AST_STATEMENT_COMPTIME, kw); - node_at(p->ast, ref)->statement_comptime.body = body; - return ref; -} - -static spl_ast_node_ref_t parse_statement(parser_t *p) { - const spl_tok_t *t = peek(p); - if (!t) - return 0; - - switch (t->type) { - case KW_RET: - return parse_ret_stmt(p); - case KW_BREAK: - return parse_break_stmt(p); - case KW_CONTINUE: - return parse_continue_stmt(p); - case KW_DEFER: - return parse_defer_stmt(p); - case KW_COMPTIME: - return parse_comptime_stmt(p); - case KW_VAR: - case KW_CONST: - case KW_TYPE: { - spl_ast_node_ref_vec_t tag_list; - vec_init(tag_list); - parse_tag_list(p, &tag_list, 0, 0); // 解析声明前的普通 tag - - spl_ast_node_ref_t decl; - if (t->type == KW_VAR) - decl = parse_var_const_decl(p, tag_list, 0); - else if (t->type == KW_CONST) - decl = parse_var_const_decl(p, tag_list, 1); - else - decl = parse_type_decl(p, tag_list); - /* 不再 vec_free(tag_list),所有权已转移 */ - if (!decl) - return 0; - - spl_ast_node_ref_t ref = new_node(p, SPL_AST_STATEMENT_DECL, t); - node_at(p->ast, ref)->statement_decl.decl = decl; - return ref; - } - default: { - if (can_start_expr(t->type)) { - spl_ast_node_ref_t expr = parse_expr(p); - if (!expr) - return 0; - spl_ast_node_ref_t ref = new_node(p, SPL_AST_STATEMENT_EXPR, t); - node_at(p->ast, ref)->statement_expr.expr = expr; - return ref; - } else { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, "unrecognized statement"); - return 0; - } - } - } -} - -static spl_ast_node_ref_t parse_block(parser_t *p) { - const spl_tok_t *start = peek(p); - if (!start || start->type != TOK_L_BRACE) { - PARSE_FATAL(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_FATAL(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 if (can_start_expr(t->type)) { - spl_ast_node_ref_t expr = parse_expr(p); - block = node_at(p->ast, ref); - t = peek(p); - if (t && t->type == TOK_SEMICOLON) { - advance(p); - vec_push(block->block.stmts, expr); - } else if (t && t->type == TOK_R_BRACE) { - if (block->block.tail_expr != 0) { - PARSE_FATAL(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_FATAL(p, SPL_DIAG_KIND_PARSE_EXPECTED, t, - "expected ';' or '}' after expression"); - break; - } - } - } else { - PARSE_FATAL(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, "unrecognized token in block"); - break; - } - } - - return ref; -} - void spl_ast_init(spl_ast_t *ast, const spl_tok_vec_t *tok_vec) { ast->input = *tok_vec; vec_init(ast->node_buckets); vec_init(ast->str_buckets); ast->root = 0; - ast->diag = NULL; spl_ast_node_t n = {0}; vec_push(ast->node_buckets, n); } -void spl_ast_parse(spl_ast_t *ast) { - if (!ast || !ast->input.data || ast->node_buckets.size == 0) - return; - - parser_t p; - p.ast = ast; - p.diag = ast->diag; - p.pos = 0; - p.failed = 0; - p.stop_as = 0; - p.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 (!p.failed) { - const spl_tok_t *t = peek(&p); - if (!t || t->type == TOK_EOF) - break; - - if (t->type == TOK_AT || t->type == TOK_SHARP) { - usize save_pos = p.pos; - const spl_tok_t *t2 = NULL; - if (t) { - p.pos++; - t2 = peek(&p); - p.pos = save_pos; - } - if (t2 && t2->type == TOK_NOT) { - parse_tag_list(&p, &external_tags, 1, 1); - continue; - } - } - - spl_ast_node_ref_t decl = parse_container_declaration(&p); - if (decl) - vec_push(declarations, decl); - } - - spl_ast_node_ref_t container_members = new_node(&p, SPL_AST_CONTAINER_MEMBERS, NULL); - spl_ast_node_t *cm = node_at(ast, container_members); - cm->container_members.external_tags = external_tags; - cm->container_members.declarations = declarations; - - spl_ast_node_ref_t root = new_node(&p, SPL_AST_ROOT, NULL); - node_at(ast, root)->root.members = container_members; - - ast->root = root; -} - void spl_ast_drop(spl_ast_t *ast) { if (!ast) return; @@ -2630,7 +339,8 @@ static void dump_node(spl_ast_t *ast, spl_ast_node_ref_t node_ref, dump_stack_t if (node->for_expr.label) dump_node(ast, node->for_expr.label, stack, false); dump_vec(ast, node->for_expr.iter_exprs, stack); - dump_vec(ast, node->for_expr.idents, stack); + if (node->for_expr.pattern) + dump_node(ast, node->for_expr.pattern, stack, false); if (node->for_expr.body) dump_node(ast, node->for_expr.body, stack, false); if (node->for_expr.else_branch) @@ -2702,6 +412,15 @@ static void dump_node(spl_ast_t *ast, spl_ast_node_ref_t node_ref, dump_stack_t dump_vec(ast, node->pattern_list.patterns, stack); break; + case SPL_AST_PATTERN_AGGREGATE: + dump_vec(ast, node->pattern_aggregate.fields, stack); + break; + + case SPL_AST_PATTERN_FIELD: + if (node->pattern_field.pattern) + dump_node(ast, node->pattern_field.pattern, stack, true); + break; + default: break; } diff --git a/stage1/spl_ast.h b/stage1/spl_ast.h index 9ec0cd5..d417a65 100644 --- a/stage1/spl_ast.h +++ b/stage1/spl_ast.h @@ -4,9 +4,6 @@ #include "../stage0/include/utils.h" #include "spl_attr.h" #include "spl_dbg.h" -#include "spl_diag.h" -#include "spl_lexer.h" -#include "spl_mpa.h" #include "spl_tok.h" /* clang-format off */ @@ -74,7 +71,9 @@ X(SPL_AST_PATTERN_UNDERSCORE, V0, pattern_underscore) \ X(SPL_AST_PATTERN_DOT, V0, pattern_dot) \ X(SPL_AST_PATTERN_TUPLE, V0, pattern_tuple) \ - X(SPL_AST_PATTERN_LIST, V0, pattern_list) + X(SPL_AST_PATTERN_LIST, V0, pattern_list) \ + X(SPL_AST_PATTERN_AGGREGATE, V0, pattern_aggregate) \ + X(SPL_AST_PATTERN_FIELD, V0, pattern_field) /* clang-format on */ typedef enum { @@ -143,9 +142,6 @@ typedef enum { SPL_UNARY_OP_DEREF, } spl_unary_op_t; -const char *spl_binary_op_name(spl_binary_op_t op); -const char *spl_unary_op_name(spl_unary_op_t op); - struct spl_ast_node; typedef struct spl_ast_node spl_ast_node_t; typedef usize spl_ast_node_ref_t; @@ -161,138 +157,113 @@ struct spl_ast_node { spl_attr_id_vec_t attrs; union { - /* SPL_AST_ROOT */ struct { - spl_ast_node_ref_t members; /* container_members 节点 */ + spl_ast_node_ref_t members; } root; - /* SPL_AST_CONTAINER_MEMBERS */ struct { - spl_ast_node_ref_vec_t external_tags; /* external_tag_item 节点列表 */ + spl_ast_node_ref_vec_t external_tags; spl_ast_node_ref_vec_t declarations; } container_members; - /* SPL_AST_FN_DECL */ struct { - spl_ast_node_ref_vec_t tag_list; /* tag_item 节点 */ + spl_ast_node_ref_vec_t tag_list; bool is_comptime; const char *name; - spl_ast_node_ref_vec_t params; /* param_decl 节点 */ - spl_ast_node_ref_t ret_type; /* 类型节点,可空 */ - spl_ast_node_ref_t body; /* 表达式节点,可空表示仅声明 */ + spl_ast_node_ref_vec_t params; + spl_ast_node_ref_t ret_type; + spl_ast_node_ref_t body; } fn_decl; - /* SPL_AST_VAR_DECL / SPL_AST_CONST_DECL */ struct { spl_ast_node_ref_vec_t attr_list; - spl_ast_node_ref_t pattern; /* 模式节点 */ - spl_ast_node_ref_t type; /* 类型节点,可空 */ - spl_ast_node_ref_t init_expr; /* 表达式节点,可空 */ + spl_ast_node_ref_t pattern; + spl_ast_node_ref_t type; + spl_ast_node_ref_t init_expr; } var_const_decl; - /* SPL_AST_TYPE_DECL */ struct { spl_ast_node_ref_vec_t attr_list; const char *name; - spl_ast_node_ref_t type_expr; /* 类型节点 */ + spl_ast_node_ref_t type_expr; } type_decl; - /* SPL_AST_MEMBER_DECL */ struct { spl_ast_node_ref_vec_t attr_list; const char *name; - spl_ast_node_ref_t type_expr; /* 可空 */ - spl_ast_node_ref_t init_expr; /* 可空 */ + spl_ast_node_ref_t type_expr; + spl_ast_node_ref_t init_expr; } member_decl; - /* SPL_AST_PARAM_DECL */ struct { spl_ast_node_ref_vec_t attr_list; const char *name; spl_ast_node_ref_t type_expr; } param_decl; - /* SPL_AST_TAG_ITEM / SPL_AST_EXTERNAL_TAG_ITEM */ struct { - bool is_at; /* true: @, false: # */ - bool is_external; /* true: @!或#! */ + bool is_at; + bool is_external; const char *name; spl_ast_node_ref_vec_t args; } tag_item; - /* SPL_AST_COMPTIME_DECL */ struct { - spl_ast_node_ref_t body; /* block 或 expr 节点 */ + spl_ast_node_ref_t body; } comptime_decl; - /* SPL_AST_TOP_LEVEL_BLOCK */ struct { - spl_ast_node_ref_vec_t tag_list; /* tag_item 节点列表 */ - spl_ast_node_ref_t block; /* 表达式节点block */ + spl_ast_node_ref_vec_t tag_list; + spl_ast_node_ref_t block; } top_level_block; - /* SPL_AST_STATEMENT_RET */ struct { - spl_ast_node_ref_t expr; /* 可空 */ + spl_ast_node_ref_t expr; } statement_ret; - /* SPL_AST_STATEMENT_BREAK */ struct { - spl_ast_node_ref_t label; /* 可空 */ - spl_ast_node_ref_t expr; /* 可空 */ + spl_ast_node_ref_t label; + spl_ast_node_ref_t expr; } statement_break; - /* SPL_AST_STATEMENT_CONTINUE */ struct { - spl_ast_node_ref_t label; /* 可空 */ + spl_ast_node_ref_t label; } statement_continue; - /* SPL_AST_STATEMENT_DEFER */ struct { - spl_ast_node_ref_t body; /* block 或 statement 节点 */ + spl_ast_node_ref_t body; } statement_defer; - - /* SPL_AST_STATEMENT_COMPTIME */ struct { - spl_ast_node_ref_t body; /* block 或 expr 节点 */ + spl_ast_node_ref_t body; } statement_comptime; - - /* SPL_AST_STATEMENT_DECL */ struct { - spl_ast_node_ref_t decl; /* var/const/type 声明节点 */ + spl_ast_node_ref_t decl; } statement_decl; - - /* SPL_AST_STATEMENT_EXPR */ struct { spl_ast_node_ref_t expr; } statement_expr; - /* SPL_AST_AGGREGATE_MEMBER */ struct { spl_ast_node_ref_vec_t attr_list; const char *name; - spl_ast_node_ref_t type_expr; /* 可空 */ - spl_ast_node_ref_t init_expr; /* 可空 */ + spl_ast_node_ref_t type_expr; + spl_ast_node_ref_t init_expr; } aggregate_member; - /* SPL_AST_STRUCT_INIT_ITEM */ struct { const char *name; - spl_ast_node_ref_t expr; /* 可空 */ + spl_ast_node_ref_t expr; } struct_init_item; - /* SPL_AST_MATCH_ARM */ struct { - spl_ast_node_ref_t pattern; /* 模式节点 */ - spl_ast_node_ref_t body; /* block 或 expr 节点 */ + spl_ast_node_ref_t pattern; + spl_ast_node_ref_t body; } match_arm; - /* SPL_AST_LABEL */ struct { const char *name; } label; - /* ---- 表达式子类型 ---- */ spl_mpa_int_t int_lit; spl_mpa_float_t float_lit; struct { @@ -305,7 +276,6 @@ struct spl_ast_node { struct { bool val; } bool_lit; - /* null_lit, undefined_lit 无数据 */ struct { const char *name; @@ -356,13 +326,13 @@ struct spl_ast_node { bool has_len; usize len; bool is_underscore_len; - spl_ast_node_ref_t elem_type; /* 可空 匿名时为 NULL */ + spl_ast_node_ref_t elem_type; spl_ast_node_ref_vec_t elems; } array_literal; struct { - const char *name; /* 可空 匿名时为 NULL */ - spl_ast_node_ref_vec_t fields; /* struct_init_item 节点列表 */ + const char *name; + spl_ast_node_ref_vec_t fields; } aggregate_literal; struct { @@ -402,14 +372,14 @@ struct spl_ast_node { struct { spl_ast_node_ref_t label; spl_ast_node_ref_vec_t iter_exprs; - spl_ast_node_ref_vec_t idents; + spl_ast_node_ref_t pattern; spl_ast_node_ref_t body; spl_ast_node_ref_t else_branch; } for_expr; struct { spl_ast_node_ref_t matched_expr; - spl_ast_node_ref_vec_t arms; /* match_arm 节点 */ + spl_ast_node_ref_vec_t arms; } match_expr; struct { @@ -418,7 +388,6 @@ struct spl_ast_node { spl_ast_node_ref_t ret_type; } fn_type; - /* ---- 类型子类型 ---- */ struct { const char *name; spl_ast_node_ref_vec_t generic_args; @@ -451,7 +420,7 @@ struct spl_ast_node { struct { const char *kind_name; - spl_ast_node_ref_vec_t members; /* aggregate_member 节点 */ + spl_ast_node_ref_vec_t members; } type_aggregate; struct { @@ -459,13 +428,10 @@ struct spl_ast_node { spl_ast_node_ref_vec_t args; } type_comptime_call; - /* ---- 模式子类型 ---- */ struct { const char *name; } pattern_ident; - /* pattern_underscore 无数据 */ - struct { const char *name; spl_ast_node_ref_t sub_pattern; @@ -474,10 +440,18 @@ struct spl_ast_node { struct { spl_ast_node_ref_vec_t patterns; } pattern_tuple; - struct { spl_ast_node_ref_vec_t patterns; } pattern_list; + + struct { + spl_ast_node_ref_vec_t fields; + } pattern_aggregate; + + struct { + const char *name; + spl_ast_node_ref_t pattern; + } pattern_field; }; }; @@ -488,8 +462,6 @@ typedef struct spl_ast { spl_ast_node_vec_t node_buckets; spl_ast_cstr_ref_vec_t str_buckets; spl_ast_node_ref_t root; - - spl_diag_t *diag; } spl_ast_t; typedef VEC(spl_ast_t *) spl_ast_ptr_vec_t; @@ -497,9 +469,10 @@ void spl_ast_init(spl_ast_t *ast, const spl_tok_vec_t *tok_vec /*move*/); void spl_ast_drop(spl_ast_t *ast); spl_ast_node_t *spl_ast_node(spl_ast_t *ast, spl_ast_node_ref_t node); -const char *spl_ast_node_name(spl_ast_node_t *node); - -void spl_ast_parse(spl_ast_t *ast); void spl_ast_dump(spl_ast_t *ast, spl_ast_node_ref_t node); +const char *spl_ast_kind_name(spl_ast_node_kind_t kind); +const char *spl_binary_op_name(spl_binary_op_t op); +const char *spl_unary_op_name(spl_unary_op_t op); + #endif /* __SPL_AST_H__ */ diff --git a/stage1/spl_lang_type.c b/stage1/spl_lang_type.c index 95f7518..ff34dae 100644 --- a/stage1/spl_lang_type.c +++ b/stage1/spl_lang_type.c @@ -645,10 +645,24 @@ spl_type_id_t spl_def_get_type_id(spl_lang_type_t *type, spl_def_id_t def_id) { return lang ? spl_lang_type_get_ir_type(type, lang) : 0; } -void spl_lang_type_dump(spl_lang_type_t *type, spl_lang_type_id_t id) { +static void spl_lang_type_dump_rec(spl_lang_type_t *type, spl_lang_type_id_t id, + spl_lang_type_id_vec_t *stack) { + for (usize i = 0; i < vec_size(*stack); i++) { + if (vec_at(*stack, i) == id) { + printf("", id); + return; + } + } + if (vec_size(*stack) > 32) { + printf("..."); + return; + } + vec_push(*stack, id); + spl_lang_type_node_t *n = spl_lang_type_node(type, id); if (!n) { printf("none"); + vec_pop(*stack); return; } switch (n->kind) { @@ -691,7 +705,7 @@ void spl_lang_type_dump(spl_lang_type_t *type, spl_lang_type_id_t id) { } case SPL_LANG_TYPE_PTR: printf("*"); - spl_lang_type_dump(type, n->extra.elem); + spl_lang_type_dump_rec(type, n->extra.elem, stack); break; case SPL_LANG_TYPE_ARRAY: { spl_type_node_t *tn = spl_type_node(&type->ir, n->ir_type_id); @@ -700,31 +714,31 @@ void spl_lang_type_dump(spl_lang_type_t *type, spl_lang_type_id_t id) { } break; case SPL_LANG_TYPE_SLICE: printf("[]"); - spl_lang_type_dump(type, n->extra.elem); + spl_lang_type_dump_rec(type, n->extra.elem, stack); break; case SPL_LANG_TYPE_TUPLE: printf("("); for (usize i = 0; i < vec_size(n->extra.elems); i++) { if (i) printf(","); - spl_lang_type_dump(type, vec_at(n->extra.elems, i)); + spl_lang_type_dump_rec(type, vec_at(n->extra.elems, i), stack); } printf(")"); break; case SPL_LANG_TYPE_RANGE: - spl_lang_type_dump(type, n->extra.elem); + spl_lang_type_dump_rec(type, n->extra.elem, stack); printf(".."); - spl_lang_type_dump(type, n->extra.elem); + spl_lang_type_dump_rec(type, n->extra.elem, stack); break; case SPL_LANG_TYPE_FN: printf("fn("); for (usize i = 0; i < vec_size(n->extra.fn.params); i++) { if (i) printf(","); - spl_lang_type_dump(type, vec_at(n->extra.fn.params, i)); + spl_lang_type_dump_rec(type, vec_at(n->extra.fn.params, i), stack); } printf(")"); - spl_lang_type_dump(type, n->extra.fn.ret); + spl_lang_type_dump_rec(type, n->extra.fn.ret, stack); break; case SPL_LANG_TYPE_STRUCT: case SPL_LANG_TYPE_UNION: @@ -733,6 +747,15 @@ void spl_lang_type_dump(spl_lang_type_t *type, spl_lang_type_id_t id) { spl_type_pure_dump(&type->ir, n->ir_type_id); break; } + + vec_pop(*stack); +} + +void spl_lang_type_dump(spl_lang_type_t *type, spl_lang_type_id_t id) { + spl_lang_type_id_vec_t stack; + vec_init(stack); + spl_lang_type_dump_rec(type, id, &stack); + vec_free(stack); } void spl_type_def_dump(spl_lang_type_t *type, spl_def_id_t id) { diff --git a/stage1/spl_parser.c b/stage1/spl_parser.c new file mode 100644 index 0000000..0ab1766 --- /dev/null +++ b/stage1/spl_parser.c @@ -0,0 +1,2284 @@ +#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 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; + } + + 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); + + 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 type name"); + vec_free(tag_list); + return 0; + } + advance(p); + + 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); + SET_STR_FIELD(p->ast, td->type_decl.name, name); + spl_ast_node_ref_t type_expr = parse_type_expr(p); + node_at(p->ast, ref)->type_decl.type_expr = type_expr; + + 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"); + 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; + } + + if (bt->type == TOK_IDENT || bt->type == KW_BOOL) { + advance(p); + spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_PATH, bt); + spl_ast_node_t *tp = node_at(p->ast, ref); + SET_STR_FIELD(p->ast, tp->type_path.name, bt); + vec_init(tp->type_path.generic_args); + + while (peek(p) && peek(p)->type == TOK_DOT) { + advance(p); + const spl_tok_t *seg = peek(p); + if (!seg || seg->type != TOK_IDENT) { + PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, seg, + "expected identifier after '.' in type path"); + break; + } + advance(p); + } + return ref; + } + + if (bt->type == TOK_AT || bt->type == TOK_SHARP) + return parse_type_comptime_call(p); + + if (bt->type == KW_ANY) { + advance(p); + spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_PATH, bt); + spl_ast_node_t *tp = node_at(p->ast, ref); + SET_STR_FIELD(p->ast, tp->type_path.name, bt); + vec_init(tp->type_path.generic_args); + return ref; + } + + 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; + + if (!expect(p, TOK_L_BRACE, "'{' in match arm body")) + 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 if (can_start_expr(t->type)) { + spl_ast_node_ref_t expr = parse_expr(p); + block = node_at(p->ast, ref); + t = peek(p); + if (t && t->type == TOK_SEMICOLON) { + advance(p); + vec_push(block->block.stmts, expr); + } else if (t && t->type == TOK_R_BRACE) { + if (block->block.tail_expr != 0) { + 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) { + advance(p); + return; + } + if (t->type == TOK_R_BRACE) + 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; +} diff --git a/stage1/spl_parser.h b/stage1/spl_parser.h new file mode 100644 index 0000000..5de68e6 --- /dev/null +++ b/stage1/spl_parser.h @@ -0,0 +1,21 @@ +#ifndef __SPL_PARSER_H__ +#define __SPL_PARSER_H__ + +#include "spl_ast.h" +#include "spl_diag.h" + +typedef struct spl_parser { + spl_ast_t *ast; + spl_diag_t *diag; + usize pos; + int failed; + int stop_agg; + usize error_count; +} spl_parser_t; + +void spl_parser_init(spl_parser_t *p); +void spl_parser_drop(spl_parser_t *p); + +void spl_ast_parse(spl_parser_t *p, spl_ast_t *ast); + +#endif /* __SPL_PARSER_H__ */ diff --git a/stage1/spl_sema.c b/stage1/spl_sema.c index 2de8a3a..eee4d0e 100644 --- a/stage1/spl_sema.c +++ b/stage1/spl_sema.c @@ -833,6 +833,67 @@ static spl_lang_type_id_t sema_block_body(spl_sema_t *sema, spl_ast_node_t *n, return r; } +static void sema_bind_pattern(spl_sema_t *sema, spl_ast_node_ref_t pat_ref, + spl_lang_type_id_t matched_tid) { + if (!pat_ref) + return; + spl_ast_node_t *pat = spl_ast_node(sema->ast, pat_ref); + if (!pat) + return; + + switch (pat->kind) { + case SPL_AST_PATTERN_IDENT: { + const char *name = pat->pattern_ident.name; + spl_symbol_t sym = {.name = name, .kind = SPL_SYMBOL_KIND_VAR}; + sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, name, pat->dbg, sema->ast, pat_ref); + spl_def_resolve(sema->type, sym.node, matched_tid); + if (!spl_scope_insert(sema->scope, sema->scope->current_scope, sym)) { + spl_diag_error(sema->diag, SPL_DIAG_KIND_DUPLICATE_SYMBOL, &pat->dbg, + "duplicate symbol `%s`", name); + } + pat->resolved_def_id = sym.node; + pat->resolved_lang_tid = matched_tid; + return; + } + + case SPL_AST_PATTERN_UNDERSCORE: + return; + + case SPL_AST_PATTERN_TUPLE: { + spl_lang_type_node_t *tn = spl_lang_type_node(sema->type, matched_tid); + if (!tn || tn->kind != SPL_LANG_TYPE_TUPLE) { + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg, + "tuple pattern requires a tuple value"); + return; + } + usize natoms = vec_size(pat->pattern_tuple.patterns); + usize nelems = vec_size(tn->extra.elems); + if (natoms != nelems) { + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg, + "tuple pattern arity mismatch (expected %zu, got %zu)", nelems, natoms); + return; + } + /* 递归 bind 会 push lang_table,tn 会悬垂;先把元素类型拷到本地 */ + spl_lang_type_id_vec_t elem_tids; + vec_init(elem_tids); + for (usize i = 0; i < nelems; ++i) + vec_push(elem_tids, vec_at(tn->extra.elems, i)); + for (usize i = 0; i < natoms; ++i) + sema_bind_pattern(sema, vec_at(pat->pattern_tuple.patterns, i), vec_at(elem_tids, i)); + vec_free(elem_tids); + pat->resolved_lang_tid = matched_tid; + return; + } + + case SPL_AST_PATTERN_DOT: + case SPL_AST_PATTERN_AGGREGATE: + default: + spl_diag_error(sema->diag, SPL_DIAG_KIND_UNHANDLED_NODE, &pat->dbg, + "pattern kind %d not yet supported", (int)pat->kind); + return; + } +} + static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_lang_type_id_t expected) { if (!ref || !expected) @@ -1014,23 +1075,34 @@ static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref, } spl_type_id_t agg_ir = spl_lang_type_get_ir_type(sema->type, expected); - spl_type_node_t *irn = spl_type_node(&sema->type->ir, agg_ir); - if (!irn) { - spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, - "aggregate type unresolved"); - return 0; + + /* 先把每个字段的 ir type_id 拷到本地:循环里 sema_coerce 会 push + type_table,irn 会悬垂。 */ + spl_type_id_vec_t field_ir_ids; + vec_init(field_ir_ids); + { + spl_type_node_t *irn = spl_type_node(&sema->type->ir, agg_ir); + if (!irn) { + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, + "aggregate type unresolved"); + return 0; + } + for (usize i = 0; i < vec_size(irn->agg_type.variants); i++) + vec_push(field_ir_ids, vec_at(irn->agg_type.variants, i).type_id); } if (en->kind == SPL_LANG_TYPE_ENUM) { if (vec_size(n->aggregate_literal.fields) != 1) { spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, "enum literal must have exactly one variant"); + vec_free(field_ir_ids); return 0; } spl_ast_node_t *item = spl_ast_node(sema->ast, vec_at(n->aggregate_literal.fields, 0)); if (!item || item->kind != SPL_AST_STRUCT_INIT_ITEM) { spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, "invalid enum literal"); + vec_free(field_ir_ids); return 0; } usize idx = 0; @@ -1038,14 +1110,22 @@ static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref, &idx)) { spl_diag_error(sema->diag, SPL_DIAG_KIND_NO_FIELD, &item->dbg, "no variant `%s`", item->struct_init_item.name); + vec_free(field_ir_ids); return 0; } - usize field_tid_ir = vec_at(irn->agg_type.variants, idx).type_id; + if (idx >= vec_size(field_ir_ids)) { + vec_free(field_ir_ids); + return 0; + } + usize field_tid_ir = vec_at(field_ir_ids, idx); spl_lang_type_id_t ft = sema_lang_from_ir(sema, field_tid_ir); if (ft && item->struct_init_item.expr) { - if (!sema_coerce(sema, item->struct_init_item.expr, ft)) + if (!sema_coerce(sema, item->struct_init_item.expr, ft)) { + vec_free(field_ir_ids); return 0; + } } + vec_free(field_ir_ids); n->resolved_lang_tid = expected; return expected; } @@ -1061,13 +1141,18 @@ static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref, item->struct_init_item.name); continue; } - usize field_tid_ir = vec_at(irn->agg_type.variants, idx).type_id; + if (idx >= vec_size(field_ir_ids)) + continue; + usize field_tid_ir = vec_at(field_ir_ids, idx); spl_lang_type_id_t ft = sema_lang_from_ir(sema, field_tid_ir); if (ft && item->struct_init_item.expr) { - if (!sema_coerce(sema, item->struct_init_item.expr, ft)) + if (!sema_coerce(sema, item->struct_init_item.expr, ft)) { + vec_free(field_ir_ids); return 0; + } } } + vec_free(field_ir_ids); n->resolved_lang_tid = expected; return expected; } @@ -1671,26 +1756,41 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { return 0; } spl_type_id_t agg_ir = spl_lang_type_get_ir_type(sema->type, agg); - spl_type_node_t *irn = spl_type_node(&sema->type->ir, agg_ir); - if (irn) { - for (usize i = 0; i < vec_size(n->aggregate_literal.fields); ++i) { - spl_ast_node_t *item = - spl_ast_node(sema->ast, vec_at(n->aggregate_literal.fields, i)); - if (!item || item->kind != SPL_AST_STRUCT_INIT_ITEM) - continue; - usize idx = 0; - if (!spl_type_agg_member_idx(&sema->type->ir, agg_ir, item->struct_init_item.name, - &idx)) { - spl_diag_error(sema->diag, SPL_DIAG_KIND_NO_FIELD, &item->dbg, "no field `%s`", - item->struct_init_item.name); - continue; - } - usize field_tid_ir = vec_at(irn->agg_type.variants, idx).type_id; - spl_lang_type_id_t ft = sema_lang_from_ir(sema, field_tid_ir); - if (ft && item->struct_init_item.expr) - sema_coerce(sema, item->struct_init_item.expr, ft); + + /* 循环里 sema_coerce 会 push type_table,irn 会悬垂。 + 先把每个字段的 ir type_id 拷到本地。 */ + spl_type_id_vec_t field_ir_ids; + vec_init(field_ir_ids); + { + spl_type_node_t *irn = spl_type_node(&sema->type->ir, agg_ir); + if (!irn) { + n->resolved_lang_tid = agg; + return agg; } + for (usize i = 0; i < vec_size(irn->agg_type.variants); i++) + vec_push(field_ir_ids, vec_at(irn->agg_type.variants, i).type_id); } + + for (usize i = 0; i < vec_size(n->aggregate_literal.fields); ++i) { + spl_ast_node_t *item = spl_ast_node(sema->ast, vec_at(n->aggregate_literal.fields, i)); + if (!item || item->kind != SPL_AST_STRUCT_INIT_ITEM) + continue; + usize idx = 0; + if (!spl_type_agg_member_idx(&sema->type->ir, agg_ir, item->struct_init_item.name, + &idx)) { + spl_diag_error(sema->diag, SPL_DIAG_KIND_NO_FIELD, &item->dbg, "no field `%s`", + item->struct_init_item.name); + continue; + } + if (idx >= vec_size(field_ir_ids)) + continue; + usize field_tid_ir = vec_at(field_ir_ids, idx); + spl_lang_type_id_t ft = sema_lang_from_ir(sema, field_tid_ir); + if (ft && item->struct_init_item.expr) + sema_coerce(sema, item->struct_init_item.expr, ft); + } + vec_free(field_ir_ids); + n->resolved_lang_tid = agg; return agg; } @@ -1793,28 +1893,39 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { vec_push(sema->label_stack, lbl); sema_push_scope(sema); - for (usize i = 0; i < vec_size(n->for_expr.iter_exprs); ++i) { - spl_lang_type_id_t container_tid = sema_infer(sema, vec_at(n->for_expr.iter_exprs, i)); - spl_lang_type_id_t elem_tid = sema_for_elem_type(sema, container_tid); - if (i < vec_size(n->for_expr.idents)) { - spl_ast_node_t *id_node = spl_ast_node(sema->ast, vec_at(n->for_expr.idents, i)); - if (id_node && id_node->kind == SPL_AST_EXPR_IDENT) { - const char *var_name = id_node->ident.name; - if (strcmp(var_name, "_") != 0) { - spl_symbol_t sym = {.name = var_name, .kind = SPL_SYMBOL_KIND_VAR}; - sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, var_name, id_node->dbg, - sema->ast, vec_at(n->for_expr.idents, i)); - spl_def_resolve(sema->type, sym.node, elem_tid); - if (!spl_scope_insert(sema->scope, sema->scope->current_scope, sym)) { - spl_diag_error(sema->diag, SPL_DIAG_KIND_DUPLICATE_SYMBOL, - &id_node->dbg, "duplicate symbol `%s`", var_name); - } - id_node->resolved_def_id = sym.node; - id_node->resolved_lang_tid = elem_tid; - } + + usize nsrc = vec_size(n->for_expr.iter_exprs); + spl_ast_node_ref_t pat_ref = n->for_expr.pattern; + spl_ast_node_t *pat = pat_ref ? spl_ast_node(sema->ast, pat_ref) : NULL; + + if (pat && pat->kind == SPL_AST_PATTERN_LIST) { + usize natoms = vec_size(pat->pattern_list.patterns); + for (usize i = 0; i < nsrc; ++i) { + spl_lang_type_id_t container_tid = + sema_infer(sema, vec_at(n->for_expr.iter_exprs, i)); + spl_lang_type_id_t elem_tid = sema_for_elem_type(sema, container_tid); + if (i < natoms) + sema_bind_pattern(sema, vec_at(pat->pattern_list.patterns, i), elem_tid); + } + if (natoms > nsrc) { + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg, + "for: pattern has %zu atoms but only %zu sources", natoms, nsrc); + } + } else { + for (usize i = 0; i < nsrc; ++i) { + spl_lang_type_id_t container_tid = + sema_infer(sema, vec_at(n->for_expr.iter_exprs, i)); + if (i == 0 && pat_ref) { + spl_lang_type_id_t elem_tid = sema_for_elem_type(sema, container_tid); + sema_bind_pattern(sema, pat_ref, elem_tid); } } + if (nsrc > 1 && pat_ref) { + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg, + "for: multiple sources require pattern list"); + } } + if (n->for_expr.body) sema_infer(sema, n->for_expr.body); if (n->for_expr.else_branch) diff --git a/stage1/spl_type.c b/stage1/spl_type.c index 3d0a09b..fa5eafe 100644 --- a/stage1/spl_type.c +++ b/stage1/spl_type.c @@ -205,10 +205,23 @@ bool spl_type_is_subtype(const spl_type_t *type, spl_type_id_t sub, spl_type_id_ return false; } -void spl_type_pure_dump(spl_type_t *type, spl_type_id_t id) { +static void spl_type_pure_dump_rec(spl_type_t *type, spl_type_id_t id, spl_type_id_vec_t *stack) { + for (usize i = 0; i < vec_size(*stack); i++) { + if (vec_at(*stack, i) == id) { + printf("", id); + return; + } + } + if (vec_size(*stack) > 32) { + printf("..."); + return; + } + vec_push(*stack, id); + spl_type_node_t *n = spl_type_node(type, id); if (!n) { printf("none"); + vec_pop(*stack); return; } switch (n->kind) { @@ -248,11 +261,11 @@ void spl_type_pure_dump(spl_type_t *type, spl_type_id_t id) { break; case SPL_TYPE_PTR: printf("*"); - spl_type_pure_dump(type, n->ptr_type.pointee); + spl_type_pure_dump_rec(type, n->ptr_type.pointee, stack); break; case SPL_TYPE_ARRAY: printf("[%zu]", n->array_type.len); - spl_type_pure_dump(type, n->array_type.element); + spl_type_pure_dump_rec(type, n->array_type.element, stack); break; case SPL_TYPE_STRUCT: case SPL_TYPE_UNION: @@ -271,7 +284,7 @@ void spl_type_pure_dump(spl_type_t *type, spl_type_id_t id) { printf(", "); spl_type_member_t *m = &n->agg_type.variants.data[i]; printf("%s:", m->name ? m->name : "?"); - spl_type_pure_dump(type, m->type_id); + spl_type_pure_dump_rec(type, m->type_id, stack); } printf("}"); break; @@ -281,12 +294,21 @@ void spl_type_pure_dump(spl_type_t *type, spl_type_id_t id) { for (usize i = 0; i < vec_size(n->fn_type.params); i++) { if (i) printf(","); - spl_type_pure_dump(type, vec_at(n->fn_type.params, i)); + spl_type_pure_dump_rec(type, vec_at(n->fn_type.params, i), stack); } printf(")"); - spl_type_pure_dump(type, n->fn_type.ret); + spl_type_pure_dump_rec(type, n->fn_type.ret, stack); break; } + + vec_pop(*stack); +} + +void spl_type_pure_dump(spl_type_t *type, spl_type_id_t id) { + spl_type_id_vec_t stack; + vec_init(stack); + spl_type_pure_dump_rec(type, id, &stack); + vec_free(stack); } spl_type_id_t spl_type_fn_param_tid(spl_type_t *type, spl_type_id_t fn_tid, usize idx) { diff --git a/stage1/splc0.c b/stage1/splc0.c index 5f04111..c01a2e4 100644 --- a/stage1/splc0.c +++ b/stage1/splc0.c @@ -15,6 +15,7 @@ #include "spl_diag.h" #include "spl_ir2vm.h" #include "spl_lexer.h" +#include "spl_parser.h" #include "spl_sema.h" #include "spl_tok.h" @@ -141,8 +142,11 @@ static spl_ast_t *driver_load(void *user, const char *from_fname, const char *pa spl_tok_vec_t toks = spl_lex(src, key); spl_ast_t *ast = malloc(sizeof *ast); spl_ast_init(ast, &toks); - ast->diag = diag; - spl_ast_parse(ast); + spl_parser_t parser; + spl_parser_init(&parser); + parser.diag = diag; + spl_ast_parse(&parser, ast); + spl_parser_drop(&parser); vec_at(d->modules, idx).ast = ast; vec_at(d->modules, idx).src = src; @@ -161,7 +165,6 @@ static int compile_spl(const char *src, const char *fname, const char *outpath, drv.main_path = strdup(fname); drv.main_toks = spl_lex(src, drv.main_path); spl_ast_init(&drv.main_ast, &drv.main_toks); - drv.main_ast.diag = &diag; map_init(drv.path_to_idx, MAP_HASH_STR, MAP_CMP_STR); vec_init(drv.modules); @@ -190,7 +193,11 @@ static int compile_spl(const char *src, const char *fname, const char *outpath, int sema_ok = 0, a2ir_ok = 0, irb_ok = 0, ir2vm_ok = 0; spl_diag_set_stage(&diag, SPL_STAGE_PARSE); - spl_ast_parse(&drv.main_ast); + spl_parser_t parser; + spl_parser_init(&parser); + parser.diag = &diag; + spl_ast_parse(&parser, &drv.main_ast); + spl_parser_drop(&parser); if (spl_diag_has_error(&diag) || spl_diag_has_fatal(&diag)) { spl_diag_summary(&diag); rc = 1;