#include "spl_ast.h" #include "spl_dbg.h" #include "spl_dumptree.h" #include "spl_tok.h" static char *sdupn(const char *s, usize n) { char *r = malloc(n + 1); if (!r) return NULL; memcpy(r, s, n); r[n] = '\0'; return r; } const char *spl_ast_kind_name(spl_ast_node_kind_t kind) { static const char *const names[] = { #define X(a, b, c) #c, SPL_AST_KIND_TABLE #undef X }; if ((usize)kind < sizeof(names) / sizeof(names[0])) return names[kind]; return "?"; } typedef struct { spl_ast_t *ast; usize pos; int failed; int stop_as; /* 0 时后缀表达式不KW_AS for 专用 */ int stop_agg; /* 0 IDENT '{' 不作结构体字面量 if/while/match 时专用 */ } parser_t; static inline int is_trivia(spl_tok_type_t t) { return t == TOK_ENDLINE || t == TOK_LINE_COMMENT; } static inline const spl_tok_t *peek(parser_t *p) { usize n = vec_size(p->ast->input); usize i = p->pos; while (i < n && is_trivia(vec_at(p->ast->input, i).type)) i++; p->pos = i; if (i >= n) return NULL; return &vec_at(p->ast->input, i); } static inline const spl_tok_t *advance(parser_t *p) { const spl_tok_t *t = peek(p); if (t && t->type != TOK_EOF) p->pos++; return t; } static inline spl_ast_node_t *node_at(spl_ast_t *ast, spl_ast_node_ref_t ref) { return &ast->node_buckets.data[ref]; } static spl_ast_node_ref_t new_node(parser_t *p, spl_ast_node_kind_t kind, const spl_tok_t *tok) { spl_ast_node_t n = {0}; n.kind = kind; if (tok) { n.dbg.dbg_name = spl_ast_kind_name(kind); n.dbg.fname = tok->fname; n.dbg.line = (int)tok->line; n.dbg.col = (int)tok->col; } vec_push(p->ast->node_buckets, n); return p->ast->node_buckets.size - 1; } static spl_ast_node_ref_t mk_bin(parser_t *p, const spl_tok_t *loc, spl_ast_node_kind_t op, spl_ast_node_ref_t left, spl_ast_node_ref_t right) { spl_ast_node_ref_t ref = new_node(p, op, loc); node_at(p->ast, ref)->op_expr.left = left; node_at(p->ast, ref)->op_expr.right = right; return ref; } /* 前向声明 */ static spl_ast_node_ref_t parse_expr(parser_t *p); static spl_ast_node_ref_vec_t parse_expr_list(parser_t *p); static spl_ast_node_ref_vec_t parse_block(parser_t *p); static spl_ast_node_ref_t parse_type_expr(parser_t *p); static spl_ast_node_ref_t parse_type_base(parser_t *p); static spl_ast_node_ref_t parse_statement(parser_t *p); static spl_ast_node_ref_t parse_container_declaration(parser_t *p); static spl_ast_node_ref_t parse_param_decl_impl(parser_t *p); static spl_ast_node_ref_t parse_bool_or(parser_t *p); static spl_ast_node_ref_t parse_bool_and(parser_t *p); static spl_ast_node_ref_t parse_bit_or(parser_t *p); static spl_ast_node_ref_t parse_bit_xor(parser_t *p); static spl_ast_node_ref_t parse_bit_and(parser_t *p); static spl_ast_node_ref_t parse_cmp_eq(parser_t *p); static spl_ast_node_ref_t parse_cmp(parser_t *p); static spl_ast_node_ref_t parse_range(parser_t *p); static spl_ast_node_ref_t parse_shift(parser_t *p); static spl_ast_node_ref_t parse_add(parser_t *p); static spl_ast_node_ref_t parse_mul(parser_t *p); static spl_ast_node_ref_t parse_prefix(parser_t *p); static spl_ast_node_ref_t parse_postfix(parser_t *p); static spl_ast_node_ref_t parse_primary(parser_t *p); static spl_ast_node_ref_vec_t parse_aggregate_init_body(parser_t *p); static spl_ast_node_ref_t parse_builtin(parser_t *p); static spl_ast_node_ref_t parse_array_literal(parser_t *p); static spl_ast_node_ref_t parse_if(parser_t *p); static spl_ast_node_ref_t parse_while(parser_t *p); static spl_ast_node_ref_t parse_loop(parser_t *p); static spl_ast_node_ref_t parse_for(parser_t *p); static spl_ast_node_ref_t parse_match(parser_t *p); static int parse_match_arm(parser_t *p, spl_ast_node_ref_vec_t *paced_vec, spl_ast_node_ref_vec_t *block_vec); static spl_ast_node_ref_t parse_ret(parser_t *p); static spl_ast_node_ref_t parse_break(parser_t *p); static spl_ast_node_ref_t parse_continue(parser_t *p); static spl_ast_node_ref_t parse_defer(parser_t *p); static isize parse_int_literal(const spl_tok_t *t) { char buf[128]; usize j = 0; for (usize i = 0; i < t->len && j < sizeof(buf) - 1; i++) { if (t->lexeme[i] != '_') buf[j++] = t->lexeme[i]; } buf[j] = 0; /* strtoll base 0 不认 0b/0o 前缀:单独处理 */ if (j >= 3 && buf[0] == '0' && (buf[1] == 'b' || buf[1] == 'B')) return (isize)strtoll(buf + 2, NULL, 2); if (j >= 3 && buf[0] == '0' && (buf[1] == 'o' || buf[1] == 'O')) return (isize)strtoll(buf + 2, NULL, 8); return (isize)strtoll(buf, NULL, 0); } static double parse_float_literal(const spl_tok_t *t) { char buf[128]; usize j = 0; for (usize i = 0; i < t->len && j < sizeof(buf) - 1; i++) { if (t->lexeme[i] != '_') buf[j++] = t->lexeme[i]; } buf[j] = 0; return strtod(buf, NULL); } static char parse_char_literal(const spl_tok_t *t) { const char *p = t->lexeme + 1; const char *end = t->lexeme + t->len - 1; char c = 0; if (p < end) { spl_decode_escape(&p, &c); } return c; } static char *parse_string_literal(const spl_tok_t *t) { const char *p = t->lexeme + 1; const char *end = t->lexeme + t->len - 1; char *out = (char *)malloc(t->len + 1); if (!out) return NULL; char *o = out; while (p < end) { char c; if (spl_decode_escape(&p, &c) == 0) { *o++ = c; } else { /* 非法转义:宽松保留原字符 */ *o++ = *p; p++; } } *o = 0; return out; } // 起始判定 static int can_start_expr(spl_tok_type_t t) { switch (t) { case TOK_INT_LITERAL: case TOK_FLOAT_LITERAL: case TOK_CHAR_LITERAL: case TOK_STRING_LITERAL: case KW_TRUE: case KW_FALSE: case KW_NULL: case TOK_IDENT: case TOK_AT: case TOK_SHARP: case TOK_L_PAREN: case TOK_L_BRACKET: case TOK_L_BRACE: case TOK_SUB: case TOK_NOT: case TOK_BIT_NOT: case TOK_AND: case TOK_MUL: return 1; default: return 0; } } static int can_start_statement(spl_tok_type_t t) { switch (t) { case KW_IF: case KW_WHILE: case KW_LOOP: case KW_FOR: case KW_MATCH: case KW_RET: case KW_BREAK: case KW_CONTINUE: case KW_DEFER: case KW_VAR: case KW_CONST: case KW_TYPE: case KW_COMPTIME: return 1; default: return 0; } } // 容器层声明 static void parse_attr_list(parser_t *p, spl_ast_node_ref_vec_t *out) { const spl_tok_t *t = NULL; while (1) { t = peek(p); if (!t) return; if (t->type != TOK_AT && t->type != TOK_SHARP) return; advance(p); t = peek(p); if (!t || t->type != TOK_IDENT) { SPL_FATAL(t, "expected identifier after attribute"); return; } advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_ATTR_ITEM, t); node_at(p->ast, ref)->attr_item.ident = sdupn(t->lexeme, t->len); t = peek(p); if (t != NULL && t->type == TOK_L_PAREN) { advance(p); spl_ast_node_ref_vec_t evec = parse_expr_list(p); node_at(p->ast, ref)->attr_item.expr_list = evec; t = peek(p); if (t == NULL || t->type != TOK_R_PAREN) { SPL_FATAL(t, "expected ')' to close attribute args"); } advance(p); return; } vec_push(*out, ref); } } static void parse_param_list(parser_t *p, spl_ast_node_ref_vec_t *out) { while (1) { const spl_tok_t *t = peek(p); if (!t) { break; } if (t->type == TOK_R_PAREN) { break; } else if (t->type == TOK_AT || t->type == TOK_SHARP || t->type == TOK_IDENT) { spl_ast_node_ref_t pd = parse_param_decl_impl(p); if (pd) vec_push(*out, pd); if (peek(p) && peek(p)->type == TOK_COMMA) { advance(p); continue; } break; } else if (t->type == TOK_ELLIPSIS) { // 变长参数: 追加 name=NULL、type_expr=NULL 的空 param_decl advance(p); spl_ast_node_ref_t pd = new_node(p, SPL_AST_PARAM_DECL, t); node_at(p->ast, pd)->param_decl.name = NULL; node_at(p->ast, pd)->param_decl.type_expr = 0; vec_push(*out, pd); if (peek(p) && peek(p)->type == TOK_COMMA) advance(p); break; } else if (t->type == KW_VOID) { // fn(void): 无参写法 advance(p); t = peek(p); Assert(t && t->type == TOK_R_PAREN); break; } else { UNREACHABLE(); } } } static spl_ast_node_ref_t parse_param_decl_impl(parser_t *p) { spl_ast_node_ref_vec_t attr_list; vec_init(attr_list); parse_attr_list(p, &attr_list); const spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { SPL_FATAL(name, "expected parameter name"); return 0; } advance(p); const spl_tok_t *t = peek(p); if (t == NULL || t->type != TOK_COLON) { SPL_FATAL(t, "expected ':' in parameter declaration"); return 0; } advance(p); spl_ast_node_ref_t type_expr = parse_type_expr(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_PARAM_DECL, name); node_at(p->ast, ref)->param_decl.attr_list = attr_list; node_at(p->ast, ref)->param_decl.name = sdupn(name->lexeme, name->len); node_at(p->ast, ref)->param_decl.type_expr = type_expr; return ref; } static spl_ast_node_ref_t parse_fn_decl(parser_t *p, spl_ast_node_ref_vec_t attr_list) { const spl_tok_t *kw = peek(p); Assert(kw && kw->type == KW_FN); advance(p); const spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { SPL_FATAL(name ? name : kw, "expected function name"); return 0; } advance(p); const spl_tok_t *t = peek(p); if (t == NULL || t->type != TOK_L_PAREN) { SPL_FATAL(t, "expected '(' in function declaration"); return 0; } advance(p); spl_ast_node_ref_vec_t param_list; vec_init(param_list); parse_param_list(p, ¶m_list); t = peek(p); if (t == NULL || t->type != TOK_R_PAREN) { SPL_FATAL(t, "expected ')' in function declaration"); return 0; } advance(p); spl_ast_node_ref_t type_expr = 0; spl_ast_node_ref_vec_t block; vec_init(block); int has_body = 0; t = peek(p); Assert(t != NULL); if (t->type != TOK_SEMICOLON && t->type != TOK_L_BRACE) { type_expr = parse_type_expr(p); t = peek(p); } if (t && t->type == TOK_SEMICOLON) { advance(p); } else if (t && t->type == TOK_L_BRACE) { block = parse_block(p); has_body = 1; } else { SPL_FATAL(t, "function declaration must end with ';' or a block"); } spl_ast_node_ref_t ref = new_node(p, has_body ? SPL_AST_FN_DEFINE : SPL_AST_FN_DECL, kw); node_at(p->ast, ref)->fn_decl.attr_list = attr_list; node_at(p->ast, ref)->fn_decl.name = sdupn(name->lexeme, name->len); node_at(p->ast, ref)->fn_decl.param_list = param_list; node_at(p->ast, ref)->fn_decl.type_expr = type_expr; node_at(p->ast, ref)->fn_decl.block = block; return ref; } static spl_ast_node_ref_t parse_type_decl(parser_t *p, spl_ast_node_ref_vec_t attr_list) { (void)attr_list; const spl_tok_t *kw = peek(p); Assert(kw && kw->type == KW_TYPE); advance(p); const spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { SPL_FATAL(name ? name : kw, "expected type name"); return 0; } advance(p); const spl_tok_t *t = peek(p); if (t == NULL || t->type != TOK_ASSIGN) { SPL_FATAL(t, "expected '=' in type declaration"); return 0; } advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_DECL, kw); node_at(p->ast, ref)->type_decl.name = sdupn(name->lexeme, name->len); spl_ast_node_ref_t te = parse_type_expr(p); node_at(p->ast, ref)->type_decl.type_expr = te; t = peek(p); if (t && (t->type == TOK_COMMA || t->type == TOK_SEMICOLON)) { advance(p); } else { LOG_WARN("need comma or semicolon with member decl"); } return ref; } static spl_ast_node_ref_t parse_member_decl(parser_t *p, spl_ast_node_ref_vec_t attr_list) { const spl_tok_t *name = peek(p); Assert(name && name->type == TOK_IDENT); advance(p); const spl_tok_t *t = NULL; spl_ast_node_ref_t type_expr = 0; t = peek(p); if (t && t->type == TOK_COLON) { advance(p); type_expr = parse_type_expr(p); } spl_ast_node_ref_t ref = new_node(p, SPL_AST_MEMBER_DECL, name); node_at(p->ast, ref)->member_decl.attr_list = attr_list; node_at(p->ast, ref)->member_decl.name = sdupn(name->lexeme, name->len); node_at(p->ast, ref)->member_decl.type_expr = type_expr; t = peek(p); if (t && (t->type == TOK_COMMA || t->type == TOK_SEMICOLON)) { advance(p); } else { LOG_WARN("need comma or semicolon with member decl"); } return ref; } static spl_ast_node_ref_t parse_var_const_decl(parser_t *p, spl_ast_node_ref_vec_t attr_list, int is_const) { const spl_tok_t *kw = peek(p); Assert(kw); if (is_const) { Assert(kw->type == KW_CONST); } else { Assert(kw->type == KW_VAR); } advance(p); const spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { SPL_FATAL(name ? name : kw, "expected variable name"); return 0; } advance(p); spl_ast_node_ref_t type_expr = 0; spl_ast_node_ref_t expr = 0; const spl_tok_t *t = peek(p); if (t && t->type == TOK_COLON) { advance(p); type_expr = parse_type_expr(p); t = peek(p); if (t && t->type == TOK_ASSIGN) { advance(p); expr = parse_expr(p); } else { SPL_FATAL(t ? t : kw, "need assign in var decl"); } } else if (t && t->type == TOK_COLON_ASSIGN) { advance(p); expr = parse_expr(p); } spl_ast_node_ref_t ref = new_node(p, is_const ? SPL_AST_CONST_DECL : SPL_AST_VAR_DECL, kw); node_at(p->ast, ref)->var_const_decl.attr_list = attr_list; node_at(p->ast, ref)->var_const_decl.name = sdupn(name->lexeme, name->len); node_at(p->ast, ref)->var_const_decl.type_expr = type_expr; node_at(p->ast, ref)->var_const_decl.expr = expr; t = peek(p); if (t && t->type == TOK_SEMICOLON) { advance(p); } else { LOG_WARN("need semicolon in decl var/const"); } return ref; } static spl_ast_node_ref_t parse_container_declaration(parser_t *p) { spl_ast_node_ref_vec_t attr_list; vec_init(attr_list); parse_attr_list(p, &attr_list); const spl_tok_t *t = peek(p); if (!t || t->type == TOK_EOF) { SPL_FATAL(t, "unexpected end of file"); return 0; } if (t->type == TOK_L_BRACE) { /* DirectiveBlock(@init {} / #test {}):不实现 */ SPL_FATAL(t, "not implemented: @/# directive block"); return 0; } switch (t->type) { case KW_FN: return parse_fn_decl(p, attr_list); case KW_TYPE: return parse_type_decl(p, attr_list); case KW_VAR: return parse_var_const_decl(p, attr_list, false); case KW_CONST: return parse_var_const_decl(p, attr_list, true); case TOK_IDENT: return parse_member_decl(p, attr_list); case KW_COMPTIME: SPL_FATAL(t, "not implemented: comptime statement"); return 0; default: SPL_FATAL(t, "unrecognized declaration"); return 0; } } // 语句 static spl_ast_node_ref_vec_t parse_block(parser_t *p) { spl_ast_node_ref_vec_t vec; vec_init(vec); const spl_tok_t *t = peek(p); if (t == NULL || t->type != TOK_L_BRACE) { SPL_FATAL(t, "expected '{'"); return vec; } advance(p); while (!p->failed) { t = peek(p); if (!t || t->type == TOK_EOF) { SPL_FATAL(t, "block missing '}'"); break; } if (t->type == TOK_R_BRACE) { advance(p); break; } if (can_start_statement(t->type)) { spl_ast_node_ref_t s = parse_statement(p); if (s) { vec_push(vec, s); } else { UNREACHABLE(); } } else if (can_start_expr(t->type)) { spl_ast_node_ref_t e = parse_expr(p); t = peek(p); if (t && t->type == TOK_SEMICOLON) { advance(p); vec_push(vec, e); } else { // Tail expretion UNREACHABLE(); } } else { SPL_FATAL(t, "unrecognized statement"); } } return vec; } static spl_ast_node_ref_t parse_statement(parser_t *p) { const spl_tok_t *t = peek(p); if (!t) return 0; switch (t->type) { case KW_IF: return parse_if(p); case KW_WHILE: return parse_while(p); case KW_LOOP: return parse_loop(p); case KW_FOR: return parse_for(p); case KW_MATCH: return parse_match(p); case KW_RET: return parse_ret(p); case KW_BREAK: return parse_break(p); case KW_CONTINUE: return parse_continue(p); case KW_DEFER: return parse_defer(p); case KW_VAR: { spl_ast_node_ref_vec_t al; vec_init(al); return parse_var_const_decl(p, al, false); } case KW_CONST: { spl_ast_node_ref_vec_t al; vec_init(al); return parse_var_const_decl(p, al, true); } case KW_TYPE: { spl_ast_node_ref_vec_t al; vec_init(al); return parse_type_decl(p, al); } case KW_COMPTIME: SPL_FATAL(t, "not implemented: comptime statement"); return 0; default: SPL_FATAL(t, "unrecognized statement"); return 0; } } static spl_ast_node_ref_t parse_if(parser_t *p) { const spl_tok_t *kw = peek(p); Assert(kw && kw->type == KW_IF); advance(p); int is_ifvar = false; char *bind = NULL; const spl_tok_t *name = NULL; const spl_tok_t *t = peek(p); if (t && t->type == KW_VAR) { advance(p); t = peek(p); if (t == NULL || t->type != TOK_DOT) { SPL_FATAL(t, "expected '.' in if var"); return 0; } name = peek(p); if (!name || name->type != TOK_IDENT) { SPL_FATAL(name, "expected variable name in if var"); return 0; } advance(p); t = peek(p); if (t && t->type == TOK_L_BRACKET) { advance(p); t = peek(p); if (!t || t->type != TOK_IDENT) { SPL_FATAL(t, "expected identifier in if var binding"); return 0; } advance(p); bind = sdupn(t->lexeme, t->len); t = peek(p); if (t == NULL || t->type != TOK_R_BRACKET) { SPL_FATAL(t, "expected ']' in if var binding"); return 0; } advance(p); } t = peek(p); if (t == NULL || t->type != TOK_ASSIGN) { SPL_FATAL(t, "expected '=' in if var"); } advance(p); return 0; } p->stop_agg++; spl_ast_node_ref_t expr = parse_expr(p); p->stop_agg--; spl_ast_node_ref_vec_t if_block = parse_block(p); spl_ast_node_ref_vec_t else_block; vec_init(else_block); t = peek(p); if (t && t->type == KW_ELSE) { advance(p); t = peek(p); if (t && t->type == KW_IF) { vec_push(else_block, parse_if(p)); } else { else_block = parse_block(p); } } spl_ast_node_ref_t s = 0; if (is_ifvar) { Assert(name != NULL && bind != NULL); spl_ast_node_ref_t packed = new_node(p, SPL_AST_PACKED_EXPR, kw); node_at(p->ast, packed)->packed_expr.ident = sdupn(name->lexeme, name->len); node_at(p->ast, packed)->packed_expr.bind_ident = bind; node_at(p->ast, packed)->packed_expr.expr = expr; s = new_node(p, SPL_AST_IFVAR_STATEMENT, kw); node_at(p->ast, s)->ifvar_statement.packed_expr = packed; node_at(p->ast, s)->ifvar_statement.if_block = if_block; node_at(p->ast, s)->ifvar_statement.else_block = else_block; } else { s = new_node(p, SPL_AST_IF_STATEMENT, kw); node_at(p->ast, s)->if_statement.expr = expr; node_at(p->ast, s)->if_statement.if_block = if_block; node_at(p->ast, s)->if_statement.else_block = else_block; } return s; } static spl_ast_node_ref_t parse_while(parser_t *p) { const spl_tok_t *kw = peek(p); Assert(kw && kw->type == KW_WHILE); advance(p); p->stop_agg++; spl_ast_node_ref_t expr = parse_expr(p); p->stop_agg--; spl_ast_node_ref_vec_t block = parse_block(p); spl_ast_node_ref_t s = new_node(p, SPL_AST_WHILE_STATEMENT, kw); node_at(p->ast, s)->while_statement.expr = expr; node_at(p->ast, s)->while_statement.while_block = block; return s; } static spl_ast_node_ref_t parse_loop(parser_t *p) { const spl_tok_t *kw = peek(p); Assert(kw && kw->type == KW_LOOP); advance(p); spl_ast_node_ref_vec_t block = parse_block(p); spl_ast_node_ref_t s = new_node(p, SPL_AST_LOOP_STATEMENT, kw); node_at(p->ast, s)->loop_statement.loop_block = block; return s; } static spl_ast_node_ref_t parse_for(parser_t *p) { const spl_tok_t *kw = peek(p); Assert(kw && kw->type == KW_FOR); advance(p); spl_ast_node_ref_vec_t expr_vec; vec_init(expr_vec); // For as is not type case p->stop_as = 1; vec_push(expr_vec, parse_expr(p)); while (peek(p) && peek(p)->type == TOK_COMMA) { advance(p); vec_push(expr_vec, parse_expr(p)); } p->stop_as = 0; const spl_tok_t *t = peek(p); if (t == NULL || t->type != KW_AS) { SPL_FATAL(t, "expected 'as' in for"); return 0; } advance(p); spl_ast_node_ref_t s = new_node(p, SPL_AST_FOR_STATEMENT, kw); node_at(p->ast, s)->for_statement.expr_vec = expr_vec; t = peek(p); if (!t || (t->type != TOK_IDENT && t->type != KW_ANY)) { SPL_FATAL(t, "expected binding variable in for"); return s; } advance(p); vec_push(node_at(p->ast, s)->for_statement.ident_vec, sdupn(t->lexeme, t->len)); while (peek(p) && peek(p)->type == TOK_COMMA) { advance(p); t = peek(p); if (!t || (t->type != TOK_IDENT && t->type != KW_ANY)) { SPL_FATAL(t, "expected binding variable in for"); return s; } advance(p); vec_push(node_at(p->ast, s)->for_statement.ident_vec, sdupn(t->lexeme, t->len)); } spl_ast_node_ref_vec_t fblock = parse_block(p); node_at(p->ast, s)->for_statement.block = fblock; return s; } static spl_ast_node_ref_t parse_match(parser_t *p) { const spl_tok_t *kw = peek(p); Assert(kw && kw->type == KW_MATCH); advance(p); p->stop_agg++; spl_ast_node_ref_t expr = parse_expr(p); p->stop_agg--; const spl_tok_t *t = peek(p); if (t == NULL || t->type != TOK_L_BRACE) { SPL_FATAL(t, "expected '{' in match"); return 0; } advance(p); spl_ast_node_ref_vec_t paced_vec, stmt_vec; vec_init(paced_vec); vec_init(stmt_vec); while (1) { t = peek(p); if (!t || t->type == TOK_EOF) { SPL_FATAL(t, "match missing '}'"); break; } if (t->type == TOK_R_BRACE) { advance(p); break; } if (!parse_match_arm(p, &paced_vec, &stmt_vec)) break; t = peek(p); if (t && t->type == TOK_COMMA) advance(p); } spl_ast_node_ref_t s = new_node(p, SPL_AST_MATCH_STATEMENT, kw); node_at(p->ast, s)->match_statement.expr = expr; node_at(p->ast, s)->match_statement.paced_exprs = paced_vec; node_at(p->ast, s)->match_statement.match_block = stmt_vec; return s; } static int parse_match_arm(parser_t *p, spl_ast_node_ref_vec_t *paced_vec, spl_ast_node_ref_vec_t *block_vec) { const spl_tok_t *t = peek(p); if (!t) return 0; spl_ast_node_ref_vec_t modes; vec_init(modes); while (1) { const spl_tok_t *mt = peek(p); if (!mt) { SPL_FATAL(mt, "invalid match arm pattern"); return 0; } spl_ast_node_ref_t pk = new_node(p, SPL_AST_PACKED_EXPR, mt); node_at(p->ast, pk)->packed_expr.ident = NULL; node_at(p->ast, pk)->packed_expr.bind_ident = NULL; node_at(p->ast, pk)->packed_expr.expr = 0; if (mt->type == TOK_DOT) { advance(p); const spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { SPL_FATAL(name, "expected variant name in match pattern"); return 0; } advance(p); node_at(p->ast, pk)->packed_expr.ident = sdupn(name->lexeme, name->len); if (peek(p) && peek(p)->type == TOK_L_BRACKET) { advance(p); const spl_tok_t *b = peek(p); if (!b || b->type != TOK_IDENT) { SPL_FATAL(b, "expected identifier in match binding"); return 0; } advance(p); node_at(p->ast, pk)->packed_expr.bind_ident = sdupn(b->lexeme, b->len); t = peek(p); if (t == NULL || t->type != TOK_R_BRACKET) { SPL_FATAL(t, "expected ']' in match binding"); return 0; } advance(p); } } else if (mt->type == KW_ANY) { t = peek(p); if (t && t->type == TOK_L_BRACE && !p->stop_agg) { spl_ast_node_ref_t pe = parse_expr(p); node_at(p->ast, pk)->packed_expr.expr = pe; } else { advance(p); } } else if (can_start_expr(mt->type)) { spl_ast_node_ref_t pe = parse_expr(p); node_at(p->ast, pk)->packed_expr.expr = pe; } else { SPL_FATAL(mt, "invalid match arm pattern"); return 0; } vec_push(modes, pk); if (peek(p) && peek(p)->type == TOK_COMMA) { advance(p); continue; } break; } t = peek(p); if (t == NULL || t->type != TOK_FAT_ARROW) { SPL_FATAL(t, "expected '=>' in match arm"); return 0; } advance(p); t = peek(p); if (!t || t->type != TOK_L_BRACE) { SPL_FATAL(t, "expected '{' block in match arm body"); return 0; } spl_ast_node_ref_vec_t bvec = parse_block(p); spl_ast_node_ref_t body = new_node(p, SPL_AST_BLOCK_EXPR, t); node_at(p->ast, body)->primary_expr.block_expr = bvec; for (usize i = 0; i < modes.size; i++) { vec_push(*paced_vec, modes.data[i]); vec_push(*block_vec, body); } vec_free(modes); return 1; } static spl_ast_node_ref_t parse_ret(parser_t *p) { const spl_tok_t *kw = peek(p); Assert(kw && kw->type == KW_RET); advance(p); spl_ast_node_ref_t expr = 0; const spl_tok_t *t = peek(p); if (t && can_start_expr(t->type)) expr = parse_expr(p); t = peek(p); if (t && t->type == TOK_SEMICOLON) advance(p); spl_ast_node_ref_t s = new_node(p, SPL_AST_RET_STATEMENT, kw); node_at(p->ast, s)->ret_statement.expr = expr; return s; } static spl_ast_node_ref_t parse_break(parser_t *p) { const spl_tok_t *kw = peek(p); Assert(kw && kw->type == KW_BREAK); advance(p); const spl_tok_t *t = peek(p); if (t && t->type == TOK_SEMICOLON) advance(p); return new_node(p, SPL_AST_BREAK_STATEMENT, kw); } static spl_ast_node_ref_t parse_continue(parser_t *p) { const spl_tok_t *kw = peek(p); Assert(kw && kw->type == KW_CONTINUE); advance(p); const spl_tok_t *t = peek(p); if (t && t->type == TOK_SEMICOLON) advance(p); return new_node(p, SPL_AST_CONTINUE_STATEMENT, kw); } static spl_ast_node_ref_t parse_defer(parser_t *p) { const spl_tok_t *kw = peek(p); Assert(kw && kw->type == KW_DEFER); advance(p); spl_ast_node_ref_vec_t vec; vec_init(vec); const spl_tok_t *t = peek(p); if (t && t->type == TOK_L_BRACE) { vec = parse_block(p); } else if (t && can_start_statement(t->type)) { spl_ast_node_ref_t st = parse_statement(p); if (st) vec_push(vec, st); } else { spl_ast_node_ref_t e = parse_expr(p); t = peek(p); if (t && t->type == TOK_SEMICOLON) advance(p); vec_push(vec, e); } spl_ast_node_ref_t s = new_node(p, SPL_AST_DEFER_STATEMENT, kw); node_at(p->ast, s)->defer_statement.block_or_statement = vec; return s; } // 表达式 static spl_ast_node_kind_t assign_op_of(spl_tok_type_t t) { switch (t) { case TOK_ASSIGN: return SPL_AST_ASSIGN_EXPR; case TOK_ASSIGN_ADD: return SPL_AST_ASSIGN_ADD_EXPR; case TOK_ASSIGN_SUB: return SPL_AST_ASSIGN_SUB_EXPR; case TOK_ASSIGN_MUL: return SPL_AST_ASSIGN_MUL_EXPR; case TOK_ASSIGN_DIV: return SPL_AST_ASSIGN_DIV_EXPR; case TOK_ASSIGN_MOD: return SPL_AST_ASSIGN_MOD_EXPR; case TOK_ASSIGN_AND: return SPL_AST_ASSIGN_AND_EXPR; case TOK_ASSIGN_OR: return SPL_AST_ASSIGN_OR_EXPR; case TOK_ASSIGN_XOR: return SPL_AST_ASSIGN_XOR_EXPR; case TOK_ASSIGN_L_SH: return SPL_AST_ASSIGN_LSHIFT_EXPR; case TOK_ASSIGN_R_SH: return SPL_AST_ASSIGN_USHIFT_EXPR; default: return SPL_AST_COUNT; } } static spl_ast_node_ref_t parse_assign(parser_t *p) { spl_ast_node_ref_t left = parse_bool_or(p); if (p->failed) return left; const spl_tok_t *t = peek(p); spl_ast_node_kind_t op = t ? assign_op_of(t->type) : SPL_AST_COUNT; if (op == SPL_AST_COUNT) return left; advance(p); spl_ast_node_ref_t right = parse_assign(p); return mk_bin(p, t, op, left, right); } static spl_ast_node_ref_t parse_bool_or(parser_t *p) { spl_ast_node_ref_t left = parse_bool_and(p); while (!p->failed) { const spl_tok_t *t = peek(p); if (!t || t->type != TOK_OR_OR) break; advance(p); spl_ast_node_ref_t right = parse_bool_and(p); left = mk_bin(p, t, SPL_AST_BOOL_OR_EXPR, left, right); } return left; } static spl_ast_node_ref_t parse_bool_and(parser_t *p) { spl_ast_node_ref_t left = parse_bit_or(p); while (!p->failed) { const spl_tok_t *t = peek(p); if (!t || t->type != TOK_AND_AND) break; advance(p); spl_ast_node_ref_t right = parse_bit_or(p); left = mk_bin(p, t, SPL_AST_BOOL_AND_EXPR, left, right); } return left; } static spl_ast_node_ref_t parse_bit_or(parser_t *p) { spl_ast_node_ref_t left = parse_bit_xor(p); while (!p->failed) { const spl_tok_t *t = peek(p); if (!t || t->type != TOK_OR) break; advance(p); spl_ast_node_ref_t right = parse_bit_xor(p); left = mk_bin(p, t, SPL_AST_BIT_OR_EXPR, left, right); } return left; } static spl_ast_node_ref_t parse_bit_xor(parser_t *p) { spl_ast_node_ref_t left = parse_bit_and(p); while (!p->failed) { const spl_tok_t *t = peek(p); if (!t || t->type != TOK_XOR) break; advance(p); spl_ast_node_ref_t right = parse_bit_and(p); left = mk_bin(p, t, SPL_AST_BIT_XOR_EXPR, left, right); } return left; } static spl_ast_node_ref_t parse_bit_and(parser_t *p) { spl_ast_node_ref_t left = parse_cmp_eq(p); while (!p->failed) { const spl_tok_t *t = peek(p); if (!t || t->type != TOK_AND) break; advance(p); spl_ast_node_ref_t right = parse_cmp_eq(p); left = mk_bin(p, t, SPL_AST_BIT_AND_EXPR, left, right); } return left; } static spl_ast_node_ref_t parse_cmp_eq(parser_t *p) { spl_ast_node_ref_t left = parse_cmp(p); while (!p->failed) { const spl_tok_t *t = peek(p); spl_ast_node_kind_t op = SPL_AST_COUNT; if (t) { if (t->type == TOK_EQ) op = SPL_AST_CMP_EQ_EXPR; else if (t->type == TOK_NEQ) op = SPL_AST_CMP_NE_EXPR; } if (op == SPL_AST_COUNT) break; advance(p); spl_ast_node_ref_t right = parse_cmp(p); left = mk_bin(p, t, op, left, right); } return left; } static spl_ast_node_ref_t parse_cmp(parser_t *p) { spl_ast_node_ref_t left = parse_range(p); while (!p->failed) { const spl_tok_t *t = peek(p); spl_ast_node_kind_t op = SPL_AST_COUNT; if (t) { if (t->type == TOK_LT) op = SPL_AST_CMP_LT_EXPR; else if (t->type == TOK_GT) op = SPL_AST_CMP_GT_EXPR; else if (t->type == TOK_LE) op = SPL_AST_CMP_LE_EXPR; else if (t->type == TOK_GE) op = SPL_AST_CMP_GE_EXPR; } if (op == SPL_AST_COUNT) break; advance(p); spl_ast_node_ref_t right = parse_range(p); left = mk_bin(p, t, op, left, right); } return left; } static spl_ast_node_ref_t parse_range(parser_t *p) { spl_ast_node_ref_t left = parse_shift(p); if (p->failed) return left; const spl_tok_t *t = peek(p); if (t && t->type == TOK_RANGE) { advance(p); spl_ast_node_ref_t right = 0; /* a.. 无右端点 */ if (peek(p) && can_start_expr(peek(p)->type)) right = parse_shift(p); left = mk_bin(p, t, SPL_AST_RANGE_EXPR, left, right); } return left; } static spl_ast_node_ref_t parse_shift(parser_t *p) { spl_ast_node_ref_t left = parse_add(p); while (!p->failed) { const spl_tok_t *t = peek(p); spl_ast_node_kind_t op = SPL_AST_COUNT; if (t) { if (t->type == TOK_L_SH) op = SPL_AST_LSHIFT_EXPR; else if (t->type == TOK_R_SH) op = SPL_AST_RSHIFT_EXPR; } if (op == SPL_AST_COUNT) break; advance(p); spl_ast_node_ref_t right = parse_add(p); left = mk_bin(p, t, op, left, right); } return left; } static spl_ast_node_ref_t parse_add(parser_t *p) { spl_ast_node_ref_t left = parse_mul(p); while (!p->failed) { const spl_tok_t *t = peek(p); spl_ast_node_kind_t op = SPL_AST_COUNT; if (t) { if (t->type == TOK_ADD) op = SPL_AST_ADD_EXPR; else if (t->type == TOK_SUB) op = SPL_AST_SUB_EXPR; } if (op == SPL_AST_COUNT) break; advance(p); spl_ast_node_ref_t right = parse_mul(p); left = mk_bin(p, t, op, left, right); } return left; } static spl_ast_node_ref_t parse_mul(parser_t *p) { spl_ast_node_ref_t left = parse_prefix(p); while (!p->failed) { const spl_tok_t *t = peek(p); spl_ast_node_kind_t op = SPL_AST_COUNT; if (t) { if (t->type == TOK_MUL) op = SPL_AST_MUL_EXPR; else if (t->type == TOK_DIV) op = SPL_AST_DIV_EXPR; else if (t->type == TOK_MOD) op = SPL_AST_MOD_EXPR; } if (op == SPL_AST_COUNT) break; advance(p); spl_ast_node_ref_t right = parse_prefix(p); left = mk_bin(p, t, op, left, right); } return left; } static spl_ast_node_ref_t parse_prefix(parser_t *p) { const spl_tok_t *t = peek(p); Assert(t != NULL); spl_ast_node_kind_t op; switch (t->type) { case TOK_SUB: op = SPL_AST_MINUS_EXPR; break; case TOK_NOT: op = SPL_AST_NOT_EXPR; break; case TOK_BIT_NOT: op = SPL_AST_BIT_NOT_EXPR; break; case TOK_AND: op = SPL_AST_ADDRESS_EXPR; break; default: return parse_postfix(p); } advance(p); spl_ast_node_ref_t inner = parse_prefix(p); spl_ast_node_ref_t pf = new_node(p, op, t); node_at(p->ast, pf)->prefix_expr.postfix_expr = inner; return pf; } static spl_ast_node_ref_t parse_postfix(parser_t *p) { spl_ast_node_ref_t expr = parse_primary(p); while (!p->failed) { const spl_tok_t *t = peek(p); if (!t) break; if (t->type == TOK_L_PAREN) { advance(p); spl_ast_node_ref_t pf = new_node(p, SPL_AST_CALL_EXPR, t); node_at(p->ast, pf)->postfix_expr.primary_expr = expr; spl_ast_node_ref_vec_t cvec = parse_expr_list(p); node_at(p->ast, pf)->postfix_expr.call_expr = cvec; t = peek(p); if (t == NULL || t->type != TOK_R_PAREN) { SPL_FATAL(t, "expected ')' in call"); return expr; } advance(p); expr = pf; } else if (t->type == TOK_DOT) { advance(p); const spl_tok_t *n = peek(p); if (n && n->type == TOK_MUL) { advance(p); spl_ast_node_ref_t pf = new_node(p, SPL_AST_DEREF_EXPR, t); node_at(p->ast, pf)->postfix_expr.primary_expr = expr; expr = pf; } else if (n && n->type == TOK_IDENT) { advance(p); spl_ast_node_ref_t pf = new_node(p, SPL_AST_FIELD_EXPR, t); node_at(p->ast, pf)->postfix_expr.primary_expr = expr; node_at(p->ast, pf)->postfix_expr.field_expr = sdupn(n->lexeme, n->len); expr = pf; } else { SPL_FATAL(n, "expected identifier or '*' after '.'"); break; } } else if (t->type == TOK_L_BRACKET) { advance(p); spl_ast_node_ref_t begin = parse_shift(p); if (peek(p) && peek(p)->type == TOK_RANGE) { advance(p); spl_ast_node_ref_t end = 0; if (peek(p) && peek(p)->type != TOK_R_BRACKET) end = parse_expr(p); t = peek(p); if (t == NULL || t->type != TOK_R_BRACKET) { SPL_FATAL(t, "expected ']' in slice"); return expr; } advance(p); spl_ast_node_ref_t pf = new_node(p, SPL_AST_SLICE_EXPR, t); node_at(p->ast, pf)->postfix_expr.primary_expr = expr; node_at(p->ast, pf)->postfix_expr.slice_expr.begin = begin; node_at(p->ast, pf)->postfix_expr.slice_expr.end = end; expr = pf; } else { t = peek(p); if (t == NULL || t->type != TOK_R_BRACKET) { SPL_FATAL(t, "expected ']' in index"); return expr; } advance(p); spl_ast_node_ref_t pf = new_node(p, SPL_AST_INDEX_EXPR, t); node_at(p->ast, pf)->postfix_expr.primary_expr = expr; node_at(p->ast, pf)->postfix_expr.index_expr = begin; expr = pf; } } else if (t->type == KW_AS && !p->stop_as) { advance(p); spl_ast_node_ref_t te = parse_type_expr(p); spl_ast_node_ref_t pf = new_node(p, SPL_AST_AS_EXPR, t); node_at(p->ast, pf)->postfix_expr.primary_expr = expr; node_at(p->ast, pf)->postfix_expr.type_expr = te; expr = pf; } else { break; } } return expr; } static spl_ast_node_ref_vec_t parse_expr_list(parser_t *p) { spl_ast_node_ref_vec_t vec; vec_init(vec); if (p->failed) return vec; const spl_tok_t *t = peek(p); if (!t || !can_start_expr(t->type)) return vec; vec_push(vec, parse_expr(p)); while (!p->failed && peek(p) && peek(p)->type == TOK_COMMA) { advance(p); if (!peek(p) || !can_start_expr(peek(p)->type)) break; // 尾逗号宽容 vec_push(vec, parse_expr(p)); } return vec; } static spl_ast_node_ref_vec_t parse_aggregate_init_body(parser_t *p) { spl_ast_node_ref_vec_t agg_vec; vec_init(agg_vec); const spl_tok_t *t = peek(p); if (t == NULL || t->type != TOK_L_BRACE) { SPL_FATAL(t, "expected '{' in struct init"); return agg_vec; } advance(p); while (1) { t = peek(p); if (!t || t->type == TOK_R_BRACE || t->type == TOK_EOF) break; t = peek(p); if (t == NULL || t->type != TOK_DOT) { SPL_FATAL(t, "expected '.' in struct init"); return agg_vec; } advance(p); t = peek(p); if (!t || t->type != TOK_IDENT) { SPL_FATAL(t, "expected field name in struct init"); return agg_vec; } advance(p); spl_ast_node_ref_t item = new_node(p, SPL_AST_ARGG_INIT_ITEM, t); node_at(p->ast, item)->aggregate_init_item.ident = sdupn(t->lexeme, t->len); if (peek(p) && peek(p)->type == TOK_ASSIGN) { advance(p); spl_ast_node_ref_t ae = parse_expr(p); node_at(p->ast, item)->aggregate_init_item.expr = ae; } vec_push(agg_vec, item); if (peek(p) && peek(p)->type == TOK_COMMA) { advance(p); continue; } break; } t = peek(p); if (t == NULL || t->type != TOK_R_BRACE) { SPL_FATAL(t, "expected '}' in struct literal"); return agg_vec; } advance(p); return agg_vec; } static spl_ast_node_ref_t parse_primary(parser_t *p) { const spl_tok_t *t = peek(p); if (!t) { SPL_FATAL(t, "unexpected expression start"); return 0; } switch (t->type) { case TOK_INT_LITERAL: { advance(p); spl_ast_node_ref_t pr = new_node(p, SPL_AST_EXPR_INTEGER_LIT, t); node_at(p->ast, pr)->primary_expr.integer_expr = parse_int_literal(t); return pr; } case TOK_FLOAT_LITERAL: { advance(p); spl_ast_node_ref_t pr = new_node(p, SPL_AST_EXPR_FLOAT_LIT, t); node_at(p->ast, pr)->primary_expr.float_expr = parse_float_literal(t); return pr; } case TOK_CHAR_LITERAL: { advance(p); spl_ast_node_ref_t pr = new_node(p, SPL_AST_EXPR_CHAR_LIT, t); node_at(p->ast, pr)->primary_expr.char_lit_expr = parse_char_literal(t); return pr; } case TOK_STRING_LITERAL: { advance(p); spl_ast_node_ref_t pr = new_node(p, SPL_AST_EXPR_STRING_LIT, t); node_at(p->ast, pr)->primary_expr.string_lit_expr = parse_string_literal(t); return pr; } case KW_TRUE: { advance(p); return new_node(p, SPL_AST_EXPR_TRUE, t); } case KW_FALSE: { advance(p); return new_node(p, SPL_AST_EXPR_FALSE, t); } case KW_NULL: { advance(p); return new_node(p, SPL_AST_EXPR_NULL, t); } case KW_UNDEFINDED: { advance(p); return new_node(p, SPL_AST_EXPR_UNDEFINED, t); } case TOK_IDENT: { advance(p); if (peek(p) && peek(p)->type == TOK_L_BRACE && !p->stop_agg) { spl_ast_node_ref_vec_t agg_vec = parse_aggregate_init_body(p); spl_ast_node_ref_t pr = new_node(p, SPL_AST_ARGGREGATE_INIT, t); node_at(p->ast, pr)->primary_expr.aggregate_init.name = sdupn(t->lexeme, t->len); node_at(p->ast, pr)->primary_expr.aggregate_init.expr = agg_vec; return pr; } spl_ast_node_ref_t pr = new_node(p, SPL_AST_EXPR_IDENT, t); node_at(p->ast, pr)->primary_expr.ident = sdupn(t->lexeme, t->len); return pr; } case TOK_DOT: { advance(p); const spl_tok_t *nx = peek(p); if (nx && nx->type == TOK_L_BRACE && !p->stop_agg) { spl_ast_node_ref_vec_t agg_vec = parse_aggregate_init_body(p); spl_ast_node_ref_t pr = new_node(p, SPL_AST_ARGGREGATE_INIT, t); node_at(p->ast, pr)->primary_expr.aggregate_init.name = NULL; node_at(p->ast, pr)->primary_expr.aggregate_init.expr = agg_vec; return pr; } SPL_FATAL(t, "unexpected '.' in expression"); return 0; } case KW_ANY: SPL_FATAL(t, "unexpected '_' in expression"); return 0; case TOK_AT: case TOK_SHARP: return parse_builtin(p); case TOK_L_PAREN: { advance(p); spl_ast_node_ref_t e = parse_expr(p); t = peek(p); if (t == NULL || t->type != TOK_R_PAREN) { SPL_FATAL(t, "expected ')' in parenthesized expression"); return e; } advance(p); return e; } case TOK_L_BRACKET: return parse_array_literal(p); case TOK_L_BRACE: { spl_ast_node_ref_vec_t bvec = parse_block(p); spl_ast_node_ref_t pr = new_node(p, SPL_AST_BLOCK_EXPR, t); node_at(p->ast, pr)->primary_expr.block_expr = bvec; return pr; } default: SPL_FATAL(t, "unrecognized expression"); return 0; } } static spl_ast_node_ref_t parse_builtin(parser_t *p) { const spl_tok_t *t = peek(p); Assert(t && (t->type == TOK_AT || t->type == TOK_SHARP)); advance(p); const spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { SPL_FATAL(name, "expected builtin name"); return 0; } advance(p); t = peek(p); if (t == NULL || t->type != TOK_L_PAREN) { SPL_FATAL(t, "expected '(' in builtin call"); return 0; } advance(p); spl_ast_node_ref_vec_t args = parse_expr_list(p); t = peek(p); if (t == NULL || t->type != TOK_R_PAREN) { SPL_FATAL(t, "expected ')' in builtin call"); return 0; } advance(p); spl_ast_node_ref_t pr = new_node(p, SPL_AST_BUILTIN_EXPR, t); node_at(p->ast, pr)->primary_expr.builtin_expr.ident = sdupn(name->lexeme, name->len); node_at(p->ast, pr)->primary_expr.builtin_expr.expr_list = args; return pr; } static spl_ast_node_ref_t parse_array_literal(parser_t *p) { const spl_tok_t *t = peek(p); advance(p); /* L_BRACKET */ isize integer = 0; t = peek(p); if (t && t->type == TOK_INT_LITERAL) { integer = parse_int_literal(t); advance(p); } t = peek(p); if (t == NULL || t->type != TOK_R_BRACKET) { SPL_FATAL(t, "expected ']' in array literal"); return 0; } advance(p); spl_ast_node_ref_t te = parse_type_expr(p); t = peek(p); if (t == NULL || t->type != TOK_L_BRACE) { SPL_FATAL(t, "expected '{' in array literal"); return 0; } advance(p); spl_ast_node_ref_vec_t items = parse_expr_list(p); t = peek(p); if (t == NULL || t->type != TOK_R_BRACE) { SPL_FATAL(t, "expected '}' in array literal"); return 0; } advance(p); spl_ast_node_ref_t pr = new_node(p, SPL_AST_ARRAY_LIT, t); node_at(p->ast, pr)->primary_expr.array_lit_expr.integer = integer; node_at(p->ast, pr)->primary_expr.array_lit_expr.type_expr = te; node_at(p->ast, pr)->primary_expr.array_lit_expr.expr_list = items; return pr; } static spl_ast_node_ref_t parse_expr(parser_t *p) { return parse_assign(p); } // 类型表达式 static spl_ast_node_kind_t type_atom_kind_of(spl_tok_type_t tt) { switch (tt) { case KW_VOID: return SPL_AST_TYPE_VOID; case KW_BOOL: return SPL_AST_TYPE_BOOL; case KW_ANY: return SPL_AST_TYPE_ANY; default: return SPL_AST_COUNT; } } static const struct { const char *name; spl_ast_node_kind_t kind; } type_kw_table[] = { {"i8", SPL_AST_TYPE_I8}, {"u8", SPL_AST_TYPE_U8}, {"i16", SPL_AST_TYPE_I16}, {"u16", SPL_AST_TYPE_U16}, {"i32", SPL_AST_TYPE_I32}, {"u32", SPL_AST_TYPE_U32}, {"i64", SPL_AST_TYPE_I64}, {"u64", SPL_AST_TYPE_U64}, {"isize", SPL_AST_TYPE_ISIZE}, {"usize", SPL_AST_TYPE_USIZE}, {"f32", SPL_AST_TYPE__F32}, {"f64", SPL_AST_TYPE__F64}, }; static spl_ast_node_kind_t type_kw_kind_of(const spl_tok_t *t) { if (t->type == TOK_IDENT) { const char *s = t->lexeme; usize slen = t->len; for (usize i = 0; i < sizeof(type_kw_table) / sizeof(type_kw_table[0]); i++) { const char *nm = type_kw_table[i].name; if (slen == strlen(nm) && memcmp(s, nm, slen) == 0) return type_kw_table[i].kind; } return SPL_AST_COUNT; } return type_atom_kind_of(t->type); } static spl_ast_node_ref_t parse_type_expr(parser_t *p) { const spl_tok_t *t = peek(p); if (!t) { SPL_FATAL(t, "expected type"); return 0; } if (t->type == TOK_MUL) { advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_POINTER, t); node_at(p->ast, ref)->type_expr.pointer_type.pointee = parse_type_expr(p); return ref; } if (t->type == TOK_L_BRACKET) { advance(p); spl_ast_node_ref_t sz = 0; t = peek(p); if (t && t->type == TOK_INT_LITERAL) { sz = new_node(p, SPL_AST_EXPR_INTEGER_LIT, t); node_at(p->ast, sz)->primary_expr.integer_expr = parse_int_literal(peek(p)); advance(p); } t = peek(p); if (t == NULL || t->type != TOK_R_BRACKET) { SPL_FATAL(t, "expected ']' in array type"); return 0; } advance(p); spl_ast_node_ref_t ref = 0; if (sz == 0) { ref = new_node(p, SPL_AST_TYPE_SLICE, t); node_at(p->ast, ref)->type_expr.slice_type.element = parse_type_expr(p); } else { ref = new_node(p, SPL_AST_TYPE_ARRAY, t); node_at(p->ast, ref)->type_expr.array_type.element = parse_type_expr(p); node_at(p->ast, ref)->type_expr.array_type.size = sz; } Assert(ref != 0); return ref; } return parse_type_base(p); } static spl_ast_node_ref_t parse_type_base(parser_t *p) { spl_ast_node_ref_vec_t attr_list; vec_init(attr_list); parse_attr_list(p, &attr_list); spl_ast_node_ref_t base = 0; const spl_tok_t *bt = peek(p); if (!bt) { SPL_FATAL(bt, "expected type base"); return 0; } const spl_tok_t *t = NULL; if (bt->type == KW_FN) { advance(p); /* KW_FN */ t = peek(p); if (t == NULL || t->type != TOK_L_PAREN) { SPL_FATAL(t, "expected '(' in function type"); return 0; } advance(p); base = new_node(p, SPL_AST_BASE_TYPE_FN, bt); node_at(p->ast, base)->type_expr.attr_list = attr_list; spl_ast_node_ref_vec_t param_list; vec_init(param_list); while (!p->failed && peek(p) && peek(p)->type != TOK_R_PAREN) { spl_ast_node_ref_t pt = parse_type_expr(p); vec_push(param_list, pt); if (peek(p) && peek(p)->type == TOK_COMMA) { advance(p); continue; } break; } t = peek(p); if (t == NULL || t->type != TOK_R_PAREN) { SPL_FATAL(t, "expected ')' in function type"); return 0; } advance(p); spl_ast_node_ref_t ret = parse_type_expr(p); node_at(p->ast, base)->type_expr.fn_type.param_list = param_list; node_at(p->ast, base)->type_expr.fn_type.type_expr = ret; return base; } if (bt->type == KW_STRUCT || bt->type == KW_UNION || bt->type == KW_ENUM) { spl_ast_node_kind_t aggk = (bt->type == KW_STRUCT) ? SPL_AST_TYPE_STRUCT : (bt->type == KW_UNION) ? SPL_AST_TYPE_UNION : SPL_AST_TYPE_ENUM; advance(p); t = peek(p); if (t == NULL || t->type != TOK_L_BRACE) { SPL_FATAL(t, "expected '{' in aggregate type"); return 0; } advance(p); base = new_node(p, aggk, bt); node_at(p->ast, base)->type_expr.attr_list = attr_list; spl_ast_node_ref_vec_t members; vec_init(members); while (1) { t = peek(p); if (!t || t->type == TOK_R_BRACE || t->type == TOK_EOF) break; spl_ast_node_ref_t md = parse_container_declaration(p); if (md) vec_push(members, md); } t = peek(p); if (t == NULL || t->type != TOK_R_BRACE) { SPL_FATAL(t, "expected '}' in aggregate type"); return 0; } advance(p); node_at(p->ast, base)->type_expr.aggregate_list = members; return base; } spl_ast_node_kind_t kwk = type_kw_kind_of(bt); if (kwk != SPL_AST_COUNT) { advance(p); base = new_node(p, kwk, bt); node_at(p->ast, base)->type_expr.attr_list = attr_list; return base; } if (bt->type != TOK_IDENT) { SPL_FATAL(bt, "unrecognized type"); return 0; } base = new_node(p, SPL_AST_BASE_TYPE_PATH, bt); node_at(p->ast, base)->type_expr.attr_list = attr_list; while (1) { t = peek(p); if (!t || t->type != TOK_IDENT) { SPL_FATAL(t, "unrecognized type atom"); break; } vec_push(node_at(p->ast, base)->type_expr.type_path.ident_vec, sdupn(t->lexeme, t->len)); advance(p); if (peek(p) && peek(p)->type == TOK_DOT) { advance(p); continue; } break; } return base; } void spl_ast_init(spl_ast_t *ast, const spl_tok_vec_t *tok_vec) { ast->input = *tok_vec; // move vec_init(ast->node_buckets); vec_init(ast->str_buckets); ast->root = 0; ast->parsed = 0; spl_ast_node_t n = {0}; vec_push(ast->node_buckets, n); } void spl_ast_prase(spl_ast_t *ast) { if (!ast || !ast->input.data || ast->node_buckets.size == 0) return; parser_t p; p.ast = ast; p.pos = 0; p.failed = 0; ast->parsed = 0; spl_tok_t *begin = &vec_at(ast->input, 0); spl_ast_node_ref_vec_t members; vec_init(members); while (!p.failed) { const spl_tok_t *t = peek(&p); if (!t || t->type == TOK_EOF) break; spl_ast_node_ref_t d = parse_container_declaration(&p); if (d) vec_push(members, d); } spl_ast_node_ref_t root = new_node(&p, SPL_AST_CONTAINER_ITEM, begin); node_at(ast, root)->container_item.members = members; ast->root = root; ast->parsed = p.failed ? -1 : 1; } void spl_ast_drop(spl_ast_t *ast) { if (!ast) return; vec_for(ast->str_buckets, idx) { free(vec_at(ast->str_buckets, idx)); } vec_free(ast->str_buckets); vec_free(ast->node_buckets); vec_free(ast->input); ast->parsed = 0; ast->root = 0; } void spl_ast_valid(spl_ast_t *ast) { if (!ast) return; if (ast->parsed != 1) { printf("valid: AST not parsed successfully (parsed=%d)\n", ast->parsed); return; } // TODO } typedef VEC(char) dump_stack_t; static void dump_node(spl_ast_t *ast, spl_ast_node_ref_t node_ref, dump_stack_t *stack, int last); void spl_ast_dump(spl_ast_t *ast, spl_ast_node_ref_t node) { if (!ast || !node || node >= ast->node_buckets.size) return; dump_stack_t stack; vec_init(stack); dump_node(ast, node, &stack, 1); } #define dump_vec(_ast, _vec, _stack) \ do { \ vec_for(_vec, _i) { dump_node(_ast, vec_at(_vec, _i), _stack, _i + 1 == vec_size(_vec)); } \ } while (0) static void dump_node(spl_ast_t *ast, spl_ast_node_ref_t node_ref, dump_stack_t *stack, int last) { spl_ast_node_t *node = &vec_at(ast->node_buckets, node_ref); for (usize i = 0; i < vec_size(*stack); i++) printf("%s", vec_at(*stack, i) ? " " : "| "); printf("%s%s #%zu", last ? "`-" : "|-", spl_ast_kind_name(node->kind), node_ref); if (node->dbg.fname) printf(" (%d:%d)", node->dbg.line, node->dbg.col); printf("\n"); vec_push(*stack, last); switch (node->kind) { case SPL_AST_NONE: UNREACHABLE(); break; case SPL_AST_CONTAINER_ITEM: dump_vec(ast, node->container_item.attr_list, stack); dump_vec(ast, node->container_item.members, stack); break; case SPL_AST_FN_DECL: case SPL_AST_FN_DEFINE: dump_vec(ast, node->fn_decl.attr_list, stack); dump_vec(ast, node->fn_decl.param_list, stack); if (node->fn_decl.type_expr) dump_node(ast, node->fn_decl.type_expr, stack, 1); dump_vec(ast, node->fn_decl.block, stack); break; case SPL_AST_TYPE_DECL: if (node->type_decl.type_expr) dump_node(ast, node->type_decl.type_expr, stack, 1); break; case SPL_AST_VAR_DECL: case SPL_AST_CONST_DECL: dump_vec(ast, node->var_const_decl.attr_list, stack); if (node->var_const_decl.type_expr) dump_node(ast, node->var_const_decl.type_expr, stack, 0); if (node->var_const_decl.expr) dump_node(ast, node->var_const_decl.expr, stack, 1); break; case SPL_AST_MEMBER_DECL: dump_vec(ast, node->member_decl.attr_list, stack); if (node->member_decl.type_expr) dump_node(ast, node->member_decl.type_expr, stack, 1); break; case SPL_AST_PARAM_DECL: dump_vec(ast, node->param_decl.attr_list, stack); if (node->param_decl.type_expr) dump_node(ast, node->param_decl.type_expr, stack, 1); break; case SPL_AST_ATTR_ITEM: dump_vec(ast, node->attr_item.expr_list, stack); break; case SPL_AST_ARGG_INIT_ITEM: if (node->aggregate_init_item.expr) dump_node(ast, node->aggregate_init_item.expr, stack, 1); break; case SPL_AST_IF_STATEMENT: if (node->if_statement.expr) dump_node(ast, node->if_statement.expr, stack, 0); dump_vec(ast, node->if_statement.if_block, stack); dump_vec(ast, node->if_statement.else_block, stack); break; case SPL_AST_IFVAR_STATEMENT: if (node->ifvar_statement.packed_expr) dump_node(ast, node->ifvar_statement.packed_expr, stack, 0); dump_vec(ast, node->ifvar_statement.if_block, stack); dump_vec(ast, node->ifvar_statement.else_block, stack); break; case SPL_AST_WHILE_STATEMENT: if (node->while_statement.expr) dump_node(ast, node->while_statement.expr, stack, 0); dump_vec(ast, node->while_statement.while_block, stack); break; case SPL_AST_LOOP_STATEMENT: dump_vec(ast, node->loop_statement.loop_block, stack); break; case SPL_AST_FOR_STATEMENT: dump_vec(ast, node->for_statement.expr_vec, stack); for (usize i = 0; i < vec_size(node->for_statement.ident_vec); i++) { for (usize j = 0; j < vec_size(*stack); j++) printf("%s", vec_at(*stack, j) ? " " : "| "); printf("%sfor_binding %s\n", i + 1 == vec_size(node->for_statement.ident_vec) ? "`-" : "|-", node->for_statement.ident_vec.data[i]); } dump_vec(ast, node->for_statement.block, stack); break; case SPL_AST_MATCH_STATEMENT: if (node->match_statement.expr) dump_node(ast, node->match_statement.expr, stack, 0); dump_vec(ast, node->match_statement.paced_exprs, stack); dump_vec(ast, node->match_statement.match_block, stack); break; case SPL_AST_RET_STATEMENT: if (node->ret_statement.expr) dump_node(ast, node->ret_statement.expr, stack, 1); break; case SPL_AST_DEFER_STATEMENT: dump_vec(ast, node->defer_statement.block_or_statement, stack); break; case SPL_AST_PACKED_EXPR: if (node->packed_expr.expr) dump_node(ast, node->packed_expr.expr, stack, 1); break; case SPL_AST_ASSIGN_EXPR: case SPL_AST_ASSIGN_ADD_EXPR: case SPL_AST_ASSIGN_SUB_EXPR: case SPL_AST_ASSIGN_MUL_EXPR: case SPL_AST_ASSIGN_DIV_EXPR: case SPL_AST_ASSIGN_MOD_EXPR: case SPL_AST_ASSIGN_AND_EXPR: case SPL_AST_ASSIGN_OR_EXPR: case SPL_AST_ASSIGN_XOR_EXPR: case SPL_AST_ASSIGN_LSHIFT_EXPR: case SPL_AST_ASSIGN_USHIFT_EXPR: case SPL_AST_BOOL_OR_EXPR: case SPL_AST_BOOL_AND_EXPR: case SPL_AST_BIT_OR_EXPR: case SPL_AST_BIT_XOR_EXPR: case SPL_AST_BIT_AND_EXPR: case SPL_AST_CMP_EQ_EXPR: case SPL_AST_CMP_NE_EXPR: case SPL_AST_CMP_LE_EXPR: case SPL_AST_CMP_GE_EXPR: case SPL_AST_CMP_LT_EXPR: case SPL_AST_CMP_GT_EXPR: case SPL_AST_RANGE_EXPR: case SPL_AST_LSHIFT_EXPR: case SPL_AST_RSHIFT_EXPR: case SPL_AST_ADD_EXPR: case SPL_AST_SUB_EXPR: case SPL_AST_MUL_EXPR: case SPL_AST_DIV_EXPR: case SPL_AST_MOD_EXPR: if (node->op_expr.left) dump_node(ast, node->op_expr.left, stack, 0); if (node->op_expr.right) dump_node(ast, node->op_expr.right, stack, 1); break; case SPL_AST_MINUS_EXPR: case SPL_AST_NOT_EXPR: case SPL_AST_BIT_NOT_EXPR: case SPL_AST_ADDRESS_EXPR: if (node->prefix_expr.postfix_expr) dump_node(ast, node->prefix_expr.postfix_expr, stack, 1); break; case SPL_AST_CALL_EXPR: if (node->postfix_expr.primary_expr) dump_node(ast, node->postfix_expr.primary_expr, stack, 0); dump_vec(ast, node->postfix_expr.call_expr, stack); break; case SPL_AST_FIELD_EXPR: case SPL_AST_DEREF_EXPR: if (node->postfix_expr.primary_expr) dump_node(ast, node->postfix_expr.primary_expr, stack, 1); break; case SPL_AST_INDEX_EXPR: if (node->postfix_expr.primary_expr) dump_node(ast, node->postfix_expr.primary_expr, stack, 0); if (node->postfix_expr.index_expr) dump_node(ast, node->postfix_expr.index_expr, stack, 1); break; case SPL_AST_SLICE_EXPR: if (node->postfix_expr.primary_expr) dump_node(ast, node->postfix_expr.primary_expr, stack, 0); if (node->postfix_expr.slice_expr.begin) dump_node(ast, node->postfix_expr.slice_expr.begin, stack, 0); if (node->postfix_expr.slice_expr.end) dump_node(ast, node->postfix_expr.slice_expr.end, stack, 1); break; case SPL_AST_AS_EXPR: if (node->postfix_expr.primary_expr) dump_node(ast, node->postfix_expr.primary_expr, stack, 0); if (node->postfix_expr.type_expr) dump_node(ast, node->postfix_expr.type_expr, stack, 1); break; case SPL_AST_EXPR_INTEGER_LIT: case SPL_AST_EXPR_FLOAT_LIT: case SPL_AST_EXPR_CHAR_LIT: case SPL_AST_EXPR_STRING_LIT: case SPL_AST_EXPR_TRUE: case SPL_AST_EXPR_FALSE: case SPL_AST_EXPR_NULL: case SPL_AST_EXPR_UNDEFINED: case SPL_AST_EXPR_IDENT: break; case SPL_AST_ARGGREGATE_INIT: dump_vec(ast, node->primary_expr.aggregate_init.expr, stack); break; case SPL_AST_EXPR_EXPR: if (node->primary_expr.expr) dump_node(ast, node->primary_expr.expr, stack, 1); break; case SPL_AST_ARRAY_LIT: if (node->primary_expr.array_lit_expr.type_expr) dump_node(ast, node->primary_expr.array_lit_expr.type_expr, stack, 0); dump_vec(ast, node->primary_expr.array_lit_expr.expr_list, stack); break; case SPL_AST_BUILTIN_EXPR: dump_vec(ast, node->primary_expr.builtin_expr.expr_list, stack); break; case SPL_AST_BLOCK_EXPR: dump_vec(ast, node->primary_expr.block_expr, stack); break; case SPL_AST_BASE_TYPE_FN: dump_vec(ast, node->type_expr.attr_list, stack); dump_vec(ast, node->type_expr.fn_type.param_list, stack); if (node->type_expr.fn_type.type_expr) dump_node(ast, node->type_expr.fn_type.type_expr, stack, 1); break; case SPL_AST_BASE_TYPE_PATH: dump_vec(ast, node->type_expr.attr_list, stack); break; case SPL_AST_TYPE_POINTER: dump_vec(ast, node->type_expr.attr_list, stack); if (node->type_expr.pointer_type.pointee) dump_node(ast, node->type_expr.pointer_type.pointee, stack, 1); break; case SPL_AST_TYPE_SLICE: dump_vec(ast, node->type_expr.attr_list, stack); if (node->type_expr.slice_type.element) dump_node(ast, node->type_expr.slice_type.element, stack, 1); break; case SPL_AST_TYPE_ARRAY: dump_vec(ast, node->type_expr.attr_list, stack); if (node->type_expr.array_type.element) dump_node(ast, node->type_expr.array_type.element, stack, 0); if (node->type_expr.array_type.size) dump_node(ast, node->type_expr.array_type.size, stack, 1); break; case SPL_AST_TYPE_STRUCT: case SPL_AST_TYPE_UNION: case SPL_AST_TYPE_ENUM: dump_vec(ast, node->type_expr.attr_list, stack); dump_vec(ast, node->type_expr.aggregate_list, stack); break; case SPL_AST_TYPE_VOID: case SPL_AST_TYPE_BOOL: case SPL_AST_TYPE_OPAQUE: case SPL_AST_TYPE_I8: case SPL_AST_TYPE_U8: case SPL_AST_TYPE_I16: case SPL_AST_TYPE_U16: case SPL_AST_TYPE_I32: case SPL_AST_TYPE_U32: case SPL_AST_TYPE_I64: case SPL_AST_TYPE_U64: case SPL_AST_TYPE_ISIZE: case SPL_AST_TYPE_USIZE: case SPL_AST_TYPE__F32: case SPL_AST_TYPE__F64: case SPL_AST_TYPE_ANY: case SPL_AST_TYPE_IDENT: break; case SPL_AST__COMPTIME_STMT: case SPL_AST__DIRECTIVE_BLOCK: case SPL_AST_TRY_STATEMENT: case SPL_AST_CATCH_STATEMENT: case SPL_AST_ERRDEFER_STATEMEMT: case SPL_AST_EXPR_STATEMENT: case SPL_AST_BREAK_STATEMENT: case SPL_AST_CONTINUE_STATEMENT: break; case SPL_AST_COUNT: UNREACHABLE(); break; } (void)vec_pop(*stack); }