1223 lines
56 KiB
C
1223 lines
56 KiB
C
#include "parser.h"
|
||
#include "lexer.h"
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
|
||
typedef struct {
|
||
const Token* tokens;
|
||
size_t count;
|
||
size_t pos;
|
||
const char* filename;
|
||
Arena* arena;
|
||
} Parser;
|
||
|
||
// === 递归深度限制 ===
|
||
static int parse_depth = 0;
|
||
#define MAX_PARSE_DEPTH 1000
|
||
|
||
// === 向前看 ===
|
||
static const Token* peek(const Parser* p) { return &p->tokens[p->pos]; }
|
||
static const Token* advance(Parser* p) { return &p->tokens[p->pos++]; }
|
||
static bool match(Parser* p, TokenKind k) {
|
||
if (peek(p)->kind == k) { p->pos++; return true; }
|
||
return false;
|
||
}
|
||
static const Token* expect(Parser* p, TokenKind k, ErrorInfo* e, const char* msg) {
|
||
if (peek(p)->kind == k) return advance(p);
|
||
e->message = msg; e->filename = p->filename;
|
||
e->line = peek(p)->line; e->col = peek(p)->col;
|
||
return NULL;
|
||
}
|
||
|
||
// === 运算符优先级定义 ===
|
||
typedef enum {
|
||
PREC_NONE = 0,
|
||
PREC_PIPE = 10,
|
||
PREC_OR = 20,
|
||
PREC_AND = 30,
|
||
PREC_COMPARE = 40,
|
||
PREC_TERM = 50,
|
||
PREC_FACTOR = 60,
|
||
PREC_UNARY = 70,
|
||
PREC_POSTFIX = 80, // .field, call()
|
||
} Precedence;
|
||
|
||
static Precedence tok_to_prec(TokenKind kind) {
|
||
switch (kind) {
|
||
case TOK_PIPE_PIPE: return PREC_OR;
|
||
case TOK_AND_AND: return PREC_AND;
|
||
case TOK_EQ_EQ: case TOK_BANG_EQ:
|
||
case TOK_LT: case TOK_GT: case TOK_LT_EQ: case TOK_GT_EQ: return PREC_COMPARE;
|
||
case TOK_PLUS: case TOK_MINUS: return PREC_TERM;
|
||
case TOK_STAR: case TOK_SLASH: case TOK_PERCENT: return PREC_FACTOR;
|
||
default: return PREC_NONE;
|
||
}
|
||
}
|
||
|
||
static BinaryOp tok_to_binop(TokenKind kind) {
|
||
switch (kind) {
|
||
case TOK_PLUS: return OP_ADD; case TOK_MINUS: return OP_SUB;
|
||
case TOK_STAR: return OP_MUL; case TOK_SLASH: return OP_DIV;
|
||
case TOK_PERCENT: return OP_MOD;
|
||
case TOK_EQ_EQ: return OP_EQ; case TOK_BANG_EQ: return OP_NE;
|
||
case TOK_LT: return OP_LT; case TOK_GT: return OP_GT;
|
||
case TOK_LT_EQ: return OP_LE; case TOK_GT_EQ: return OP_GE;
|
||
case TOK_AND_AND: return OP_AND; case TOK_PIPE_PIPE: return OP_OR;
|
||
default: return OP_ADD;
|
||
}
|
||
}
|
||
|
||
// 向前声明
|
||
static AstNode* parse_expr(Parser* p, ErrorInfo* error);
|
||
static AstNode* parse_expr_prec(Parser* p, Precedence prec, ErrorInfo* error);
|
||
static AstNode* parse_block(Parser* p, ErrorInfo* error);
|
||
static AstNode* parse_statement(Parser* p, ErrorInfo* error);
|
||
static AstNode* parse_function(Parser* p, bool is_pub, ErrorInfo* error);
|
||
|
||
// === 前缀解析 ===
|
||
static AstNode* parse_unary(Parser* p, ErrorInfo* error) {
|
||
const Token* op = advance(p);
|
||
AstNode* operand = parse_expr_prec(p, PREC_UNARY, error);
|
||
if (!operand) return NULL;
|
||
BinaryOp uop = (op->kind == TOK_MINUS) ? OP_NEG : OP_NOT;
|
||
return ast_make_unary(p->arena, uop, operand, tok_loc(op));
|
||
}
|
||
|
||
static AstNode* parse_group(Parser* p, ErrorInfo* error) {
|
||
advance(p); // 跳过 (
|
||
AstNode* expr = parse_expr(p, error);
|
||
if (!expr) return NULL;
|
||
if (!expect(p, TOK_RPAREN, error, "缺少 ')'")) return NULL;
|
||
return expr;
|
||
}
|
||
|
||
static AstNode* parse_literal(Parser* p, ErrorInfo* error) {
|
||
const Token* t = advance(p);
|
||
switch (t->kind) {
|
||
case TOK_INT_LIT: return ast_make_literal_i64(p->arena, tok_int_value(t), tok_loc(t));
|
||
case TOK_FLOAT_LIT: return ast_make_literal_f64(p->arena, tok_float_value(t), tok_loc(t));
|
||
case TOK_CHAR_LIT: {
|
||
int64_t val = 0;
|
||
if (t->length >= 2 && t->start[0] == '\\') {
|
||
switch (t->start[1]) {
|
||
case 'n': val = '\n'; break;
|
||
case 't': val = '\t'; break;
|
||
case '\\': val = '\\'; break;
|
||
case '\'': val = '\''; break;
|
||
default: val = t->start[1]; break;
|
||
}
|
||
} else {
|
||
val = (unsigned char)t->start[0];
|
||
}
|
||
return ast_make_literal_char(p->arena, (int)val, tok_loc(t));
|
||
}
|
||
case TOK_TRUE: return ast_make_literal_bool(p->arena, true, tok_loc(t));
|
||
case TOK_FALSE: return ast_make_literal_bool(p->arena, false, tok_loc(t));
|
||
case TOK_STR_LIT: {
|
||
char* str = arena_alloc_impl(p->arena, t->length + 1);
|
||
memcpy(str, t->start, t->length);
|
||
str[t->length] = '\0';
|
||
// 字符串插值: "Hello, \(name)!" → "Hello, " + name + "!"
|
||
char* interp = strstr(str, "\\(");
|
||
if (interp) {
|
||
*interp = '\0'; // 截断前半部分
|
||
char* pre = str;
|
||
char* expr_start = interp + 2; // 跳过 \(
|
||
char* close = strchr(expr_start, ')');
|
||
if (!close) {
|
||
error->message = "字符串插值缺少 ')'"; error->filename = p->filename;
|
||
error->line = t->line; error->col = t->col; return NULL;
|
||
}
|
||
*close = '\0';
|
||
char* post = close + 1;
|
||
// 生成: pre + expr + post
|
||
AstNode* result = ast_make_literal_str(p->arena,
|
||
arena_strdup_impl(p->arena, pre, strlen(pre)), tok_loc(t));
|
||
// 将插值表达式按标识符解析
|
||
AstNode* expr = ast_make_ident(p->arena,
|
||
arena_strdup_impl(p->arena, expr_start, strlen(expr_start)), tok_loc(t));
|
||
result = ast_make_binary(p->arena, OP_ADD, result, expr, tok_loc(t));
|
||
if (post[0] != '\0') {
|
||
AstNode* post_str = ast_make_literal_str(p->arena,
|
||
arena_strdup_impl(p->arena, post, strlen(post)), tok_loc(t));
|
||
result = ast_make_binary(p->arena, OP_ADD, result, post_str, tok_loc(t));
|
||
}
|
||
return result;
|
||
}
|
||
return ast_make_literal_str(p->arena, str, tok_loc(t));
|
||
}
|
||
default: return NULL;
|
||
}
|
||
}
|
||
|
||
// === 结构体初始化解析: Name { field: val, ... } ===
|
||
static AstNode* parse_struct_init(Parser* p, const Token* name, ErrorInfo* error) {
|
||
advance(p); // 跳过 '{'
|
||
const char* fnames[32];
|
||
AstNode* fvals[32];
|
||
int fcount = 0;
|
||
|
||
while (peek(p)->kind != TOK_RBRACE && !error->message) {
|
||
if (fcount >= 32) { error->message = "结构体初始化字段过多 (最多32)"; error->filename = p->filename; error->line = peek(p)->line; error->col = peek(p)->col; return NULL; }
|
||
const Token* fname = expect(p, TOK_IDENT, error, "字段名");
|
||
if (!fname) return NULL;
|
||
if (!expect(p, TOK_COLON, error, "缺少 ':'")) return NULL;
|
||
AstNode* val = parse_expr(p, error);
|
||
if (!val) return NULL;
|
||
|
||
fnames[fcount] = arena_strdup_impl(p->arena, fname->start, fname->length);
|
||
fvals[fcount] = val;
|
||
fcount++;
|
||
|
||
if (peek(p)->kind == TOK_COMMA) advance(p);
|
||
else break;
|
||
}
|
||
if (!expect(p, TOK_RBRACE, error, "缺少 '}'")) return NULL;
|
||
|
||
const char** n_arr = arena_alloc_impl(p->arena, fcount * sizeof(const char*));
|
||
memcpy(n_arr, fnames, fcount * sizeof(const char*));
|
||
AstNode** v_arr = arena_alloc_impl(p->arena, fcount * sizeof(AstNode*));
|
||
memcpy(v_arr, fvals, fcount * sizeof(AstNode*));
|
||
|
||
return ast_make_struct_init(p->arena,
|
||
arena_strdup_impl(p->arena, name->start, name->length),
|
||
n_arr, v_arr, fcount, tok_loc(name));
|
||
}
|
||
|
||
// === 标识符 / 函数调用 / 结构体初始化 ===
|
||
static AstNode* parse_ident_or_call(Parser* p, ErrorInfo* error) {
|
||
const Token* name = advance(p);
|
||
|
||
// 枚举变体或模块函数: Name::Variant 或 Name::fn
|
||
if (peek(p)->kind == TOK_COLON_COLON) {
|
||
advance(p); // 跳过 ::
|
||
const Token* variant = expect(p, TOK_IDENT, error, "枚举变体名");
|
||
if (!variant) return NULL;
|
||
// Name::fn 或 Name::Variant 或 Name::Variant(payload)
|
||
if (peek(p)->kind == TOK_LPAREN) {
|
||
// 前进探测: 检查括号内是否有多参数或命名参数(→函数调用)还是单表达式(→枚举payload)
|
||
size_t probe = p->pos + 1;
|
||
int paren_depth = 1;
|
||
bool has_comma = false, has_named = false;
|
||
while (paren_depth > 0 && p->tokens[probe].kind != TOK_EOF) {
|
||
if (p->tokens[probe].kind == TOK_LPAREN) paren_depth++;
|
||
else if (p->tokens[probe].kind == TOK_RPAREN) { paren_depth--; if (paren_depth == 0) break; }
|
||
else if (paren_depth == 1 && p->tokens[probe].kind == TOK_COMMA) has_comma = true;
|
||
else if (paren_depth == 1 && p->tokens[probe].kind == TOK_COLON) has_named = true;
|
||
probe++;
|
||
}
|
||
if (has_comma || has_named) {
|
||
// 模块函数调用: Name::fn(a, b) 或 Name::fn(x: 1)
|
||
advance(p); // 跳过 '('
|
||
AstNode* args[16]; const char* arg_names[16]; int arg_count = 0;
|
||
bool seen_named = false;
|
||
while (peek(p)->kind != TOK_RPAREN && !error->message) {
|
||
if (arg_count >= 16) { error->message = "参数过多"; error->filename = p->filename; error->line = peek(p)->line; error->col = peek(p)->col; return NULL; }
|
||
if (peek(p)->kind == TOK_IDENT && (p->tokens[p->pos + 1].kind == TOK_COLON)) {
|
||
const Token* aname = advance(p); advance(p);
|
||
arg_names[arg_count] = arena_strdup_impl(p->arena, aname->start, aname->length);
|
||
seen_named = true;
|
||
} else {
|
||
if (seen_named) { error->message = "命名参数必须放在位置参数之后"; error->filename = p->filename; error->line = peek(p)->line; error->col = peek(p)->col; return NULL; }
|
||
arg_names[arg_count] = NULL;
|
||
}
|
||
args[arg_count] = parse_expr(p, error);
|
||
if (!args[arg_count]) return NULL;
|
||
arg_count++;
|
||
if (peek(p)->kind == TOK_COMMA) advance(p); else break;
|
||
}
|
||
if (!expect(p, TOK_RPAREN, error, "缺少 ')'")) return NULL;
|
||
AstNode** arg_arr = arena_alloc_impl(p->arena, arg_count * sizeof(AstNode*));
|
||
memcpy(arg_arr, args, arg_count * sizeof(AstNode*));
|
||
const char** name_arr = seen_named
|
||
? memcpy(arena_alloc_impl(p->arena, arg_count * sizeof(const char*)), arg_names, arg_count * sizeof(const char*))
|
||
: NULL;
|
||
char* full_name = arena_alloc_impl(p->arena, name->length + variant->length + 4);
|
||
sprintf(full_name, "%.*s::%.*s", name->length, name->start, variant->length, variant->start);
|
||
return ast_make_call(p->arena, full_name, arg_arr, name_arr, arg_count, tok_loc(name));
|
||
}
|
||
}
|
||
// 枚举 payload: Name::Variant 或 Name::Variant(expr)
|
||
AstNode* payload = NULL;
|
||
if (match(p, TOK_LPAREN)) {
|
||
payload = parse_expr(p, error);
|
||
if (!payload) return NULL;
|
||
if (!expect(p, TOK_RPAREN, error, "缺少 ')'")) return NULL;
|
||
}
|
||
return ast_make_enum_variant(p->arena,
|
||
arena_strdup_impl(p->arena, name->start, name->length),
|
||
arena_strdup_impl(p->arena, variant->start, variant->length),
|
||
payload, tok_loc(name));
|
||
}
|
||
|
||
// 结构体初始化: Name { field: val, ... }
|
||
// 用提前看来区别 struct init 和 block:
|
||
// struct init → { IDENT COLON ... ;block → { 可能是 let/if/while/...
|
||
if (peek(p)->kind == TOK_LBRACE) {
|
||
const Token* after_brace = &p->tokens[p->pos + 1];
|
||
if (after_brace->kind == TOK_IDENT) {
|
||
const Token* after_fname = &p->tokens[p->pos + 2];
|
||
if (after_fname->kind == TOK_COLON) {
|
||
return parse_struct_init(p, name, error);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 函数调用: name(...)
|
||
if (match(p, TOK_LPAREN)) {
|
||
AstNode* args[16]; const char* arg_names[16]; int arg_count = 0;
|
||
bool seen_named = false;
|
||
while (peek(p)->kind != TOK_RPAREN && !error->message) {
|
||
if (arg_count >= 16) {
|
||
error->message = "函数参数过多"; error->filename = p->filename;
|
||
error->line = peek(p)->line; error->col = peek(p)->col; return NULL;
|
||
}
|
||
// 命名参数: name: expr
|
||
if (peek(p)->kind == TOK_IDENT && (p->tokens[p->pos + 1].kind == TOK_COLON)) {
|
||
const Token* aname = advance(p); advance(p); // 跳过标识符和 ':'
|
||
arg_names[arg_count] = arena_strdup_impl(p->arena, aname->start, aname->length);
|
||
seen_named = true;
|
||
} else {
|
||
if (seen_named) {
|
||
error->message = "命名参数必须放在位置参数之后"; error->filename = p->filename;
|
||
error->line = peek(p)->line; error->col = peek(p)->col; return NULL;
|
||
}
|
||
arg_names[arg_count] = NULL;
|
||
}
|
||
args[arg_count] = parse_expr(p, error);
|
||
if (!args[arg_count]) return NULL;
|
||
arg_count++;
|
||
if (peek(p)->kind == TOK_COMMA) advance(p);
|
||
else break;
|
||
}
|
||
if (!expect(p, TOK_RPAREN, error, "缺少 ')'")) return NULL;
|
||
AstNode** arg_arr = arena_alloc_impl(p->arena, arg_count * sizeof(AstNode*));
|
||
memcpy(arg_arr, args, arg_count * sizeof(AstNode*));
|
||
const char** name_arr = seen_named
|
||
? memcpy(arena_alloc_impl(p->arena, arg_count * sizeof(const char*)), arg_names, arg_count * sizeof(const char*))
|
||
: NULL;
|
||
return ast_make_call(p->arena, arena_strdup_impl(p->arena, name->start, name->length),
|
||
arg_arr, name_arr, arg_count, tok_loc(name));
|
||
}
|
||
return ast_make_ident(p->arena,
|
||
arena_strdup_impl(p->arena, name->start, name->length),
|
||
tok_loc(name));
|
||
}
|
||
|
||
// === Pratt 主循环 ===
|
||
static AstNode* parse_expr_prec(Parser* p, Precedence min_prec, ErrorInfo* error) {
|
||
const Token* tok = peek(p);
|
||
AstNode* left = NULL;
|
||
|
||
// 前缀解析
|
||
if (tok->kind == TOK_IF) {
|
||
const Token* if_tok = advance(p);
|
||
// if let: if let Pattern = expr { then } else { else } → 去糖为 let+if
|
||
if (peek(p)->kind == TOK_LET) {
|
||
advance(p); // 跳过 let
|
||
// 解析模式: Enum::Variant 或 Enum::Variant(var)
|
||
AstNode* pattern = parse_expr(p, error); // 解析枚举变体
|
||
if (!pattern) return NULL;
|
||
if (!expect(p, TOK_ASSIGN, error, "if let 缺少 '='")) return NULL;
|
||
AstNode* match_expr = parse_expr(p, error);
|
||
if (!match_expr) return NULL;
|
||
AstNode* then_block = parse_block(p, error);
|
||
if (!then_block) return NULL;
|
||
AstNode* else_block = NULL;
|
||
if (match(p, TOK_ELSE)) {
|
||
if (peek(p)->kind == TOK_IF)
|
||
else_block = parse_expr_prec(p, min_prec, error);
|
||
else
|
||
else_block = parse_block(p, error);
|
||
if (!else_block) return NULL;
|
||
}
|
||
// 去糖: { let __match = expr; if __match == pattern { then } else { else } }
|
||
static int iflet_counter = 0;
|
||
char vname_buf[32];
|
||
snprintf(vname_buf, sizeof(vname_buf), "__iflet_%d", iflet_counter++);
|
||
const char* vname = arena_strdup_impl(p->arena, vname_buf, strlen(vname_buf));
|
||
AstNode* let_stmt = ast_make_let(p->arena,
|
||
vname, TYPE_UNKNOWN,
|
||
false, false, match_expr, NULL, 0, NULL, 0, tok_loc(if_tok));
|
||
AstNode* cond = ast_make_binary(p->arena, OP_EQ,
|
||
ast_make_ident(p->arena, vname, tok_loc(if_tok)),
|
||
pattern, tok_loc(if_tok));
|
||
AstNode* if_stmt = ast_make_if(p->arena, cond, then_block, else_block, tok_loc(if_tok));
|
||
AstNode* stmts[2] = { let_stmt, if_stmt };
|
||
AstNode** arr = arena_alloc_impl(p->arena, 2 * sizeof(AstNode*));
|
||
memcpy(arr, stmts, 2 * sizeof(AstNode*));
|
||
left = ast_make_block(p->arena, arr, 2, tok_loc(if_tok));
|
||
} else {
|
||
// if-expr: if cond { then } else { else }
|
||
AstNode* cond = parse_expr(p, error);
|
||
if (!cond) return NULL;
|
||
AstNode* then_block = parse_block(p, error);
|
||
if (!then_block) return NULL;
|
||
AstNode* else_block = NULL;
|
||
if (match(p, TOK_ELSE)) {
|
||
if (peek(p)->kind == TOK_IF)
|
||
else_block = parse_expr_prec(p, min_prec, error);
|
||
else
|
||
else_block = parse_block(p, error);
|
||
if (!else_block) return NULL;
|
||
}
|
||
left = ast_make_if(p->arena, cond, then_block, else_block, tok_loc(if_tok));
|
||
}
|
||
} else if (tok->kind == TOK_MINUS || tok->kind == TOK_BANG) {
|
||
left = parse_unary(p, error);
|
||
} else if (tok->kind == TOK_LPAREN) {
|
||
left = parse_group(p, error);
|
||
} else if (tok->kind == TOK_INT_LIT || tok->kind == TOK_FLOAT_LIT ||
|
||
tok->kind == TOK_CHAR_LIT ||
|
||
tok->kind == TOK_TRUE || tok->kind == TOK_FALSE ||
|
||
tok->kind == TOK_STR_LIT) {
|
||
left = parse_literal(p, error);
|
||
} else if (tok->kind == TOK_IDENT) {
|
||
left = parse_ident_or_call(p, error);
|
||
} else {
|
||
error->message = "无法识别的表达式"; error->filename = p->filename;
|
||
error->line = tok->line; error->col = tok->col;
|
||
return NULL;
|
||
}
|
||
if (!left) return NULL;
|
||
|
||
// 中缀/后置解析循环
|
||
while (!error->message) {
|
||
TokenKind kind = peek(p)->kind;
|
||
|
||
// 管道: expr |> func(args...) → func(args..., expr)
|
||
if (kind == TOK_PIPE) {
|
||
Precedence prec = PREC_PIPE;
|
||
if (prec <= min_prec) break;
|
||
const Token* op = advance(p);
|
||
// RHS 必须是函数调用(不带管道时解析)
|
||
AstNode* right = parse_expr_prec(p, prec, error);
|
||
if (!right) return NULL;
|
||
if (right->kind != AST_CALL_EXPR) {
|
||
error->message = "管道右侧必须是函数调用"; error->filename = p->filename;
|
||
error->line = op->line; error->col = op->col;
|
||
return NULL;
|
||
}
|
||
// 将 left 作为第一个参数插入(F#/Elixir 风格)
|
||
if (right->as.call.arg_count >= 16) {
|
||
error->message = "管道参数过多"; error->filename = p->filename;
|
||
error->line = op->line; error->col = op->col; return NULL;
|
||
}
|
||
AstNode** new_args = arena_alloc_impl(p->arena, (right->as.call.arg_count + 1) * sizeof(AstNode*));
|
||
new_args[0] = left;
|
||
memcpy(new_args + 1, right->as.call.args, right->as.call.arg_count * sizeof(AstNode*));
|
||
right->as.call.args = new_args;
|
||
right->as.call.arg_count++;
|
||
left = right;
|
||
continue;
|
||
}
|
||
|
||
// 后置字段访问: expr.field 或 expr.method(args)
|
||
if (kind == TOK_DOT) {
|
||
advance(p); // 跳过 '.'
|
||
const Token* field = expect(p, TOK_IDENT, error, "缺少字段名");
|
||
if (!field) return NULL;
|
||
const char* member_name = arena_strdup_impl(p->arena, field->start, field->length);
|
||
// 方法调用: expr.method(args)
|
||
if (peek(p)->kind == TOK_LPAREN) {
|
||
advance(p); // 跳过 '('
|
||
AstNode* args[16]; const char* arg_names[16]; int arg_count = 0;
|
||
bool seen_named = false;
|
||
while (peek(p)->kind != TOK_RPAREN && !error->message) {
|
||
if (arg_count >= 16) { error->message = "参数过多"; error->filename = p->filename; error->line = peek(p)->line; error->col = peek(p)->col; return NULL; }
|
||
if (peek(p)->kind == TOK_IDENT && (p->tokens[p->pos + 1].kind == TOK_COLON)) {
|
||
const Token* aname = advance(p); advance(p);
|
||
arg_names[arg_count] = arena_strdup_impl(p->arena, aname->start, aname->length);
|
||
seen_named = true;
|
||
} else {
|
||
if (seen_named) { error->message = "命名参数必须放在位置参数之后"; error->filename = p->filename; error->line = peek(p)->line; error->col = peek(p)->col; return NULL; }
|
||
arg_names[arg_count] = NULL;
|
||
}
|
||
args[arg_count] = parse_expr(p, error);
|
||
if (!args[arg_count]) return NULL;
|
||
arg_count++;
|
||
if (peek(p)->kind == TOK_COMMA) advance(p); else break;
|
||
}
|
||
if (!expect(p, TOK_RPAREN, error, "缺少 ')'")) return NULL;
|
||
AstNode** arg_arr = arena_alloc_impl(p->arena, arg_count * sizeof(AstNode*));
|
||
memcpy(arg_arr, args, arg_count * sizeof(AstNode*));
|
||
const char** name_arr = seen_named
|
||
? memcpy(arena_alloc_impl(p->arena, arg_count * sizeof(const char*)), arg_names, arg_count * sizeof(const char*))
|
||
: NULL;
|
||
left = ast_make_method_call(p->arena, left, member_name, arg_arr, name_arr, arg_count, tok_loc(field));
|
||
} else {
|
||
left = ast_make_field_access(p->arena, left, member_name, tok_loc(field));
|
||
}
|
||
continue;
|
||
}
|
||
|
||
// 后置索引: expr[expr]
|
||
if (kind == TOK_LBRACKET) {
|
||
const Token* lbrack = advance(p); // 跳过 '['
|
||
AstNode* index = parse_expr(p, error);
|
||
if (!index) return NULL;
|
||
if (!expect(p, TOK_RBRACKET, error, "缺少 ']'")) return NULL;
|
||
left = ast_make_index_expr(p->arena, left, index, tok_loc(lbrack));
|
||
continue;
|
||
}
|
||
|
||
// 中缀运算符
|
||
Precedence prec = tok_to_prec(kind);
|
||
if (prec <= min_prec) break;
|
||
|
||
const Token* op = advance(p);
|
||
AstNode* right = parse_expr_prec(p, prec, error);
|
||
if (!right) return NULL;
|
||
left = ast_make_binary(p->arena, tok_to_binop(kind), left, right, tok_loc(op));
|
||
}
|
||
|
||
return left;
|
||
}
|
||
|
||
static AstNode* parse_expr(Parser* p, ErrorInfo* error) {
|
||
return parse_expr_prec(p, PREC_NONE, error);
|
||
}
|
||
|
||
// === 类型工具 ===
|
||
static TypeKind token_to_type(TokenKind k) {
|
||
switch (k) {
|
||
case TOK_I32: return TYPE_I32;
|
||
case TOK_I64: return TYPE_I64;
|
||
case TOK_U64: return TYPE_U64;
|
||
case TOK_F64: return TYPE_F64;
|
||
case TOK_BOOL: return TYPE_BOOL;
|
||
case TOK_CHAR: return TYPE_CHAR;
|
||
case TOK_STR: return TYPE_STR;
|
||
default: return TYPE_VOID;
|
||
}
|
||
}
|
||
|
||
// === 类型表达式解析(内置类型/结构体名/数组类型)===
|
||
// 数组支持后置语法: T[N], T[N][M] 等
|
||
static TypeInfo parse_type_expr(Parser* p, ErrorInfo* error) {
|
||
const Token* t = peek(p);
|
||
TypeInfo ti = {0};
|
||
|
||
// Self 类型(trait 中引用实现者自身类型)
|
||
if (t->kind == TOK_SELF) {
|
||
advance(p);
|
||
ti.kind = TYPE_STRUCT;
|
||
ti.struct_name = "Self";
|
||
return ti;
|
||
}
|
||
|
||
// 解析基础类型
|
||
if (tok_is_type(t->kind)) {
|
||
advance(p);
|
||
ti.kind = token_to_type(t->kind);
|
||
} else if (t->kind == TOK_IDENT) {
|
||
advance(p);
|
||
ti.kind = TYPE_STRUCT;
|
||
ti.struct_name = arena_strdup_impl(p->arena, t->start, t->length);
|
||
} else {
|
||
error->message = "无效的类型"; error->filename = p->filename;
|
||
error->line = t->line; error->col = t->col;
|
||
ti.kind = TYPE_ERROR;
|
||
return ti;
|
||
}
|
||
|
||
// 后置数组维度: Type[N] → TYPE_ARRAY
|
||
if (peek(p)->kind == TOK_LBRACKET) {
|
||
advance(p); // 跳过 '['
|
||
const Token* size_tok = expect(p, TOK_INT_LIT, error, "数组大小必须是整数常量");
|
||
if (!size_tok) { ti.kind = TYPE_ERROR; return ti; }
|
||
int64_t size = tok_int_value(size_tok);
|
||
if (!expect(p, TOK_RBRACKET, error, "缺少 ']'")) {
|
||
ti.kind = TYPE_ERROR; return ti;
|
||
}
|
||
TypeInfo arr_ti = {0};
|
||
arr_ti.kind = TYPE_ARRAY;
|
||
arr_ti.element_type = ti.kind;
|
||
arr_ti.element_struct_name = ti.struct_name;
|
||
arr_ti.array_size = size;
|
||
return arr_ti;
|
||
}
|
||
|
||
return ti;
|
||
}
|
||
|
||
// === 结构体声明解析 ===
|
||
static AstNode* parse_struct_decl(Parser* p, ErrorInfo* error) {
|
||
const Token* s_tok = advance(p); // 跳过 'struct'
|
||
const Token* name = expect(p, TOK_IDENT, error, "struct 后应为结构体名");
|
||
if (!name) return NULL;
|
||
if (!expect(p, TOK_LBRACE, error, "缺少 '{'")) return NULL;
|
||
|
||
AstNode* fields[32]; int fcount = 0;
|
||
while (peek(p)->kind != TOK_RBRACE && !error->message) {
|
||
if (fcount >= 32) { error->message = "结构体字段过多 (最多32)"; error->filename = p->filename; error->line = peek(p)->line; error->col = peek(p)->col; return NULL; }
|
||
const Token* fname = expect(p, TOK_IDENT, error, "字段名");
|
||
if (!fname) return NULL;
|
||
if (!expect(p, TOK_COLON, error, "缺少 ':'")) return NULL;
|
||
TypeInfo fti = parse_type_expr(p, error);
|
||
if (fti.kind == TYPE_ERROR) {
|
||
error->filename = p->filename;
|
||
return NULL;
|
||
}
|
||
fields[fcount++] = ast_make_parameter(p->arena,
|
||
arena_strdup_impl(p->arena, fname->start, fname->length),
|
||
fti.kind, fti.struct_name, tok_loc(fname));
|
||
if (peek(p)->kind == TOK_COMMA) advance(p);
|
||
else break;
|
||
}
|
||
if (!expect(p, TOK_RBRACE, error, "缺少 '}'")) return NULL;
|
||
|
||
AstNode** farr = arena_alloc_impl(p->arena, fcount * sizeof(AstNode*));
|
||
memcpy(farr, fields, fcount * sizeof(AstNode*));
|
||
return ast_make_struct_decl(p->arena,
|
||
arena_strdup_impl(p->arena, name->start, name->length),
|
||
farr, fcount, tok_loc(s_tok));
|
||
}
|
||
|
||
// === match 语句解析(脱糖为 let + if-else 链)===
|
||
// match <expr> { pat1 => { body1 }, pat2 => { body2 }, _ => { body_default } }
|
||
// → { let __match_val = <expr>; if __match_val == pat1 { body1 } else if __match_val == pat2 { body2 } else { body_default } }
|
||
static AstNode* parse_match_stmt(Parser* p, ErrorInfo* error) {
|
||
const Token* match_tok = advance(p); // 跳过 'match'
|
||
|
||
// 解析被匹配的表达式
|
||
AstNode* matched = parse_expr(p, error);
|
||
if (!matched) return NULL;
|
||
|
||
if (!expect(p, TOK_LBRACE, error, "match 后缺少 '{'")) return NULL;
|
||
|
||
// 分配临时变量名
|
||
const char* varname = arena_strdup_impl(p->arena, "__match_val", 12);
|
||
|
||
// 收集所有分支
|
||
enum { MAX_ARMS = 64 };
|
||
bool arm_is_wildcard[MAX_ARMS];
|
||
AstNode* arm_pattern[MAX_ARMS];
|
||
AstNode* arm_body[MAX_ARMS];
|
||
int arm_count = 0;
|
||
|
||
while (peek(p)->kind != TOK_RBRACE && !error->message) {
|
||
if (arm_count >= MAX_ARMS) {
|
||
error->message = "match 分支过多 (最多64)";
|
||
error->filename = p->filename;
|
||
error->line = peek(p)->line; error->col = peek(p)->col;
|
||
return NULL;
|
||
}
|
||
|
||
if (peek(p)->kind == TOK_UNDERSCORE) {
|
||
arm_is_wildcard[arm_count] = true;
|
||
arm_pattern[arm_count] = NULL;
|
||
advance(p); // 跳过 '_'
|
||
} else {
|
||
arm_is_wildcard[arm_count] = false;
|
||
arm_pattern[arm_count] = parse_expr(p, error);
|
||
if (!arm_pattern[arm_count]) return NULL;
|
||
}
|
||
|
||
// 解析 '=>'
|
||
if (!expect(p, TOK_MATCH_ARROW, error, "match 分支缺少 '=>'")) return NULL;
|
||
|
||
// 解析分支体(必须是一个代码块)
|
||
arm_body[arm_count] = parse_block(p, error);
|
||
if (!arm_body[arm_count]) return NULL;
|
||
|
||
arm_count++;
|
||
|
||
// 跳过可选逗号
|
||
if (peek(p)->kind == TOK_COMMA) advance(p);
|
||
}
|
||
|
||
if (!expect(p, TOK_RBRACE, error, "缺少 '}'")) return NULL;
|
||
|
||
if (arm_count == 0) {
|
||
error->message = "match 表达式至少需要一个分支";
|
||
error->filename = p->filename;
|
||
error->line = match_tok->line; error->col = match_tok->col;
|
||
return NULL;
|
||
}
|
||
|
||
// 从最后一个分支往前构建 if-else 链(最后一个分支 = 最内层 else)
|
||
AstNode* result = NULL;
|
||
for (int i = arm_count - 1; i >= 0; i--) {
|
||
if (arm_is_wildcard[i]) {
|
||
// 通配符分支:if (true) { body } else { result }
|
||
AstNode* true_cond = ast_make_literal_bool(p->arena, true, tok_loc(match_tok));
|
||
result = ast_make_if(p->arena, true_cond, arm_body[i], result, tok_loc(match_tok));
|
||
} else {
|
||
// if (__match_val == pattern) { body } else { result }
|
||
AstNode* cond = ast_make_binary(p->arena, OP_EQ,
|
||
ast_make_ident(p->arena, varname, tok_loc(match_tok)),
|
||
arm_pattern[i], tok_loc(match_tok));
|
||
result = ast_make_if(p->arena, cond, arm_body[i], result, tok_loc(match_tok));
|
||
}
|
||
}
|
||
|
||
// 构建 let __match_val = <matched>;
|
||
AstNode* let_stmt = ast_make_let(p->arena, varname, TYPE_UNKNOWN,
|
||
false, false, matched, NULL, 0, NULL, 0, tok_loc(match_tok));
|
||
|
||
// 包装为代码块: { let __match_val = <expr>; <if-else 链> }
|
||
AstNode* stmts_arr[2] = { let_stmt, result };
|
||
AstNode** stmts = arena_alloc_impl(p->arena, 2 * sizeof(AstNode*));
|
||
memcpy(stmts, stmts_arr, 2 * sizeof(AstNode*));
|
||
return ast_make_block(p->arena, stmts, 2, tok_loc(match_tok));
|
||
}
|
||
|
||
// === 语句解析 ===
|
||
|
||
static AstNode* parse_block(Parser* p, ErrorInfo* error) {
|
||
if (++parse_depth > MAX_PARSE_DEPTH) {
|
||
error->message = "嵌套过深"; error->filename = p->filename;
|
||
error->line = peek(p)->line; error->col = peek(p)->col;
|
||
parse_depth--; return NULL;
|
||
}
|
||
const Token* open = peek(p);
|
||
if (!expect(p, TOK_LBRACE, error, "缺少 '{'")) { parse_depth--; return NULL; }
|
||
AstNode* stmts[256]; int count = 0;
|
||
while (peek(p)->kind != TOK_RBRACE && peek(p)->kind != TOK_EOF && !error->message) {
|
||
if (count >= 256) { error->message = "代码块语句过多 (最多256)"; error->filename = p->filename; error->line = peek(p)->line; error->col = peek(p)->col; parse_depth--; return NULL; }
|
||
AstNode* s = parse_statement(p, error);
|
||
if (!s) { parse_depth--; return NULL; }
|
||
stmts[count++] = s;
|
||
}
|
||
if (!expect(p, TOK_RBRACE, error, "缺少 '}'")) { parse_depth--; return NULL; }
|
||
AstNode** arr = arena_alloc_impl(p->arena, count * sizeof(AstNode*));
|
||
memcpy(arr, stmts, count * sizeof(AstNode*));
|
||
parse_depth--;
|
||
return ast_make_block(p->arena, arr, count, tok_loc(open));
|
||
}
|
||
|
||
static AstNode* parse_statement(Parser* p, ErrorInfo* error) {
|
||
const Token* t = peek(p);
|
||
|
||
if (t->kind == TOK_LET || t->kind == TOK_VAR) {
|
||
bool is_mut = (advance(p)->kind == TOK_VAR);
|
||
const Token* name = expect(p, TOK_IDENT, error,
|
||
is_mut ? "var 后应为变量名" : "let 后应为变量名");
|
||
if (!name) return NULL;
|
||
// 可选的类型标注
|
||
TypeKind annot_type = TYPE_UNKNOWN;
|
||
bool has_type_annot = false;
|
||
const char* struct_type_name = NULL;
|
||
TypeKind annot_elem_type = 0;
|
||
const char* annot_elem_struct = NULL;
|
||
int64_t annot_arr_size = 0;
|
||
if (match(p, TOK_COLON)) {
|
||
TypeInfo ti = parse_type_expr(p, error);
|
||
if (ti.kind == TYPE_ERROR) return NULL;
|
||
annot_type = ti.kind;
|
||
struct_type_name = ti.struct_name;
|
||
annot_elem_type = ti.element_type;
|
||
annot_elem_struct = ti.element_struct_name;
|
||
annot_arr_size = ti.array_size;
|
||
has_type_annot = true;
|
||
}
|
||
if (!expect(p, TOK_ASSIGN, error, "缺少 '='")) return NULL;
|
||
AstNode* init = parse_expr(p, error);
|
||
if (!init) return NULL;
|
||
if (!expect(p, TOK_SEMICOLON, error, "缺少 ';'")) return NULL;
|
||
return ast_make_let(p->arena,
|
||
arena_strdup_impl(p->arena, name->start, name->length),
|
||
annot_type, has_type_annot, is_mut, init, struct_type_name,
|
||
annot_elem_type, annot_elem_struct, annot_arr_size, tok_loc(t));
|
||
}
|
||
|
||
if (t->kind == TOK_IF) {
|
||
// 委托给表达式解析器(含 if let 去糖)
|
||
AstNode* if_expr = parse_expr_prec(p, PREC_NONE, error);
|
||
if (!if_expr) return NULL;
|
||
return if_expr; // AST_IF_STMT 或 AST_BLOCK(if-let去糖)
|
||
}
|
||
|
||
if (t->kind == TOK_WHILE) {
|
||
advance(p);
|
||
AstNode* cond = parse_expr(p, error);
|
||
if (!cond) return NULL;
|
||
AstNode* body = parse_block(p, error);
|
||
if (!body) return NULL;
|
||
return ast_make_while(p->arena, cond, body, tok_loc(t));
|
||
}
|
||
|
||
if (t->kind == TOK_FOR) {
|
||
advance(p); // 跳过 'for'
|
||
|
||
// 解析循环变量名
|
||
const Token* var_name = expect(p, TOK_IDENT, error, "for 后应为变量名");
|
||
if (!var_name) return NULL;
|
||
|
||
// 解析 'in'
|
||
if (!expect(p, TOK_IN, error, "缺少 'in'")) return NULL;
|
||
|
||
// 解析起始表达式
|
||
AstNode* start_expr = parse_expr(p, error);
|
||
if (!start_expr) return NULL;
|
||
|
||
// 解析 'to'
|
||
if (!expect(p, TOK_TO, error, "缺少 'to'")) return NULL;
|
||
|
||
// 解析结束表达式
|
||
AstNode* end_expr = parse_expr(p, error);
|
||
if (!end_expr) return NULL;
|
||
|
||
// 解析循环体
|
||
AstNode* body = parse_block(p, error);
|
||
if (!body) return NULL;
|
||
|
||
// 脱糖: for i in start to end { body; }
|
||
// → { var i = start; while i < end { body; i = i + 1; } }
|
||
|
||
const char* vname = arena_strdup_impl(p->arena, var_name->start, var_name->length);
|
||
|
||
// 构建: var i = start;
|
||
AstNode* let_stmt = ast_make_let(p->arena, vname, TYPE_UNKNOWN, false, true, start_expr, NULL, 0, NULL, 0, tok_loc(var_name));
|
||
|
||
// 构建: i < end (while 条件)
|
||
AstNode* cond = ast_make_binary(p->arena, OP_LT,
|
||
ast_make_ident(p->arena, vname, tok_loc(var_name)),
|
||
end_expr, tok_loc(var_name));
|
||
|
||
// 构建: i = i + 1 (循环增量)
|
||
AstNode* incr = ast_make_assign(p->arena, vname,
|
||
ast_make_binary(p->arena, OP_ADD,
|
||
ast_make_ident(p->arena, vname, tok_loc(var_name)),
|
||
ast_make_literal_i64(p->arena, 1, tok_loc(var_name)),
|
||
tok_loc(var_name)),
|
||
tok_loc(var_name));
|
||
|
||
// 将增量追加到循环体末尾
|
||
AstNode** new_stmts = arena_alloc_impl(p->arena,
|
||
(body->as.block.stmt_count + 1) * sizeof(AstNode*));
|
||
memcpy(new_stmts, body->as.block.stmts, body->as.block.stmt_count * sizeof(AstNode*));
|
||
new_stmts[body->as.block.stmt_count] = incr;
|
||
AstNode* new_body = ast_make_block(p->arena, new_stmts,
|
||
body->as.block.stmt_count + 1, body->loc);
|
||
|
||
// 构建: while i < end { ... body ... ; i = i + 1; }
|
||
AstNode* while_loop = ast_make_while(p->arena, cond, new_body, tok_loc(t));
|
||
|
||
// 包装: { var i = start; while i < end { ... } }
|
||
AstNode* stmts_arr[2] = { let_stmt, while_loop };
|
||
AstNode** stmts = arena_alloc_impl(p->arena, 2 * sizeof(AstNode*));
|
||
memcpy(stmts, stmts_arr, 2 * sizeof(AstNode*));
|
||
return ast_make_block(p->arena, stmts, 2, tok_loc(t));
|
||
}
|
||
|
||
if (t->kind == TOK_MATCH) {
|
||
return parse_match_stmt(p, error);
|
||
}
|
||
|
||
if (t->kind == TOK_GUARD) {
|
||
// guard expr else { ... } → if !(expr) { ... }
|
||
const Token* guard_tok = advance(p);
|
||
AstNode* cond = parse_expr(p, error);
|
||
if (!cond) return NULL;
|
||
if (!expect(p, TOK_ELSE, error, "guard 缺少 'else'")) return NULL;
|
||
AstNode* body = parse_block(p, error);
|
||
if (!body) return NULL;
|
||
// 去糖: if !cond { body }
|
||
AstNode* not_cond = ast_make_unary(p->arena, OP_NOT, cond, tok_loc(guard_tok));
|
||
return ast_make_if(p->arena, not_cond, body, NULL, tok_loc(guard_tok));
|
||
}
|
||
|
||
if (t->kind == TOK_RETURN) {
|
||
advance(p);
|
||
if (match(p, TOK_SEMICOLON)) {
|
||
return ast_make_return(p->arena, NULL, tok_loc(t));
|
||
}
|
||
AstNode* expr = parse_expr(p, error);
|
||
if (!expr) return NULL;
|
||
if (!expect(p, TOK_SEMICOLON, error, "缺少 ';'")) return NULL;
|
||
return ast_make_return(p->arena, expr, tok_loc(t));
|
||
}
|
||
|
||
// 数组元素赋值: ident[expr] = expr ;
|
||
// 需要前瞻: 检查 ']' 后面是否是 '=' (而非 ';' 或其它)
|
||
if (t->kind == TOK_IDENT && (t + 1)->kind == TOK_LBRACKET) {
|
||
// 向前扫描找到对应的 ']'(不支持嵌套 '[' 在索引中)
|
||
int ahead_idx = 2;
|
||
int bracket_depth = 1;
|
||
while (bracket_depth > 0 && (t + ahead_idx)->kind != TOK_EOF) {
|
||
if ((t + ahead_idx)->kind == TOK_LBRACKET) bracket_depth++;
|
||
else if ((t + ahead_idx)->kind == TOK_RBRACKET) bracket_depth--;
|
||
if (bracket_depth > 0) ahead_idx++;
|
||
}
|
||
// 检查 ']' 后是否是 '='
|
||
if ((t + ahead_idx + 1)->kind == TOK_ASSIGN) {
|
||
const Token* name = advance(p); // 消费标识符
|
||
advance(p); // 消费 '['
|
||
AstNode* index = parse_expr(p, error);
|
||
if (!index) return NULL;
|
||
if (!expect(p, TOK_RBRACKET, error, "缺少 ']'")) return NULL;
|
||
if (!expect(p, TOK_ASSIGN, error, "缺少 '='")) return NULL;
|
||
AstNode* value = parse_expr(p, error);
|
||
if (!value) return NULL;
|
||
if (!expect(p, TOK_SEMICOLON, error, "缺少 ';'")) return NULL;
|
||
return ast_make_array_assign(p->arena,
|
||
arena_strdup_impl(p->arena, name->start, name->length),
|
||
index, value, tok_loc(name));
|
||
}
|
||
// 否则: 不是数组赋值, 回退到下方表达式语句处理
|
||
}
|
||
|
||
// 赋值语句: ident = expr ;
|
||
if (t->kind == TOK_IDENT && (t + 1)->kind == TOK_ASSIGN) {
|
||
const Token* name = advance(p); // 消费标识符
|
||
advance(p); // 消费 '='
|
||
AstNode* value = parse_expr(p, error);
|
||
if (!value) return NULL;
|
||
if (!expect(p, TOK_SEMICOLON, error, "缺少 ';'")) return NULL;
|
||
return ast_make_assign(p->arena,
|
||
arena_strdup_impl(p->arena, name->start, name->length),
|
||
value, tok_loc(name));
|
||
}
|
||
|
||
// 复合赋值: ident += expr → ident = ident + expr
|
||
if (t->kind == TOK_IDENT) {
|
||
TokenKind next_kind = (t + 1)->kind;
|
||
if (next_kind >= TOK_PLUS_EQ && next_kind <= TOK_SLASH_EQ) {
|
||
const Token* name = advance(p); // 消费标识符
|
||
TokenKind comp_op = advance(p)->kind;
|
||
|
||
BinaryOp binop;
|
||
switch (comp_op) {
|
||
case TOK_PLUS_EQ: binop = OP_ADD; break;
|
||
case TOK_MINUS_EQ: binop = OP_SUB; break;
|
||
case TOK_STAR_EQ: binop = OP_MUL; break;
|
||
case TOK_SLASH_EQ: binop = OP_DIV; break;
|
||
default: break;
|
||
}
|
||
|
||
AstNode* rhs = parse_expr(p, error);
|
||
if (!rhs) return NULL;
|
||
if (!expect(p, TOK_SEMICOLON, error, "缺少 ';'")) return NULL;
|
||
|
||
AstNode* lhs_ident = ast_make_ident(p->arena,
|
||
arena_strdup_impl(p->arena, name->start, name->length),
|
||
tok_loc(name));
|
||
AstNode* bin_expr = ast_make_binary(p->arena, binop, lhs_ident, rhs,
|
||
tok_loc(name));
|
||
return ast_make_assign(p->arena,
|
||
arena_strdup_impl(p->arena, name->start, name->length),
|
||
bin_expr, tok_loc(name));
|
||
}
|
||
}
|
||
|
||
// 表达式语句
|
||
AstNode* expr = parse_expr(p, error);
|
||
if (!expr) return NULL;
|
||
if (!expect(p, TOK_SEMICOLON, error, "缺少 ';'")) return NULL;
|
||
return ast_make_expr_stmt(p->arena, expr, tok_loc(t));
|
||
}
|
||
|
||
// === 函数解析 ===
|
||
static AstNode* parse_function(Parser* p, bool is_pub, ErrorInfo* error) {
|
||
const Token* fn_tok = advance(p); // fn
|
||
const Token* name = expect(p, TOK_IDENT, error, "fn 后应为函数名");
|
||
if (!name) return NULL;
|
||
// 泛型类型参数: <T, U, ...>
|
||
const char* type_params[8]; int tp_count = 0;
|
||
if (peek(p)->kind == TOK_LT) {
|
||
advance(p); // 跳过 '<'
|
||
while (peek(p)->kind != TOK_GT && !error->message) {
|
||
if (tp_count >= 8) { error->message = "类型参数过多 (最多8)"; error->filename = p->filename; error->line = peek(p)->line; error->col = peek(p)->col; return NULL; }
|
||
const Token* tp = expect(p, TOK_IDENT, error, "类型参数名");
|
||
if (!tp) return NULL;
|
||
type_params[tp_count++] = arena_strdup_impl(p->arena, tp->start, tp->length);
|
||
if (peek(p)->kind == TOK_COMMA) advance(p); else break;
|
||
}
|
||
if (!expect(p, TOK_GT, error, "缺少 '>'")) return NULL;
|
||
}
|
||
if (!expect(p, TOK_LPAREN, error, "缺少 '('")) return NULL;
|
||
|
||
// 参数列表(泛型参数可标注为类型参数名)
|
||
AstNode* params[64]; int pcount = 0;
|
||
while (peek(p)->kind != TOK_RPAREN && !error->message) {
|
||
if (pcount >= 64) { error->message = "函数参数过多 (最多64)"; error->filename = p->filename; error->line = peek(p)->line; error->col = peek(p)->col; return NULL; }
|
||
const Token* pname = expect(p, TOK_IDENT, error, "参数名");
|
||
if (!pname) return NULL;
|
||
if (!expect(p, TOK_COLON, error, "缺少 ':'")) return NULL;
|
||
TypeInfo pti = parse_type_expr(p, error);
|
||
if (pti.kind == TYPE_ERROR) return NULL;
|
||
params[pcount++] = ast_make_parameter(p->arena,
|
||
arena_strdup_impl(p->arena, pname->start, pname->length),
|
||
pti.kind, pti.struct_name, tok_loc(pname));
|
||
if (match(p, TOK_COMMA)) continue;
|
||
else break;
|
||
}
|
||
if (!expect(p, TOK_RPAREN, error, "缺少 ')'")) return NULL;
|
||
|
||
// 返回类型
|
||
TypeKind ret = TYPE_VOID;
|
||
const char* ret_struct_name = NULL;
|
||
if (match(p, TOK_ARROW)) {
|
||
TypeInfo rti = parse_type_expr(p, error);
|
||
if (rti.kind == TYPE_ERROR) return NULL;
|
||
ret = rti.kind;
|
||
ret_struct_name = rti.struct_name;
|
||
}
|
||
|
||
// trait 方法签名或普通函数体
|
||
AstNode* body = NULL;
|
||
if (match(p, TOK_SEMICOLON)) {
|
||
body = NULL; // trait 方法签名,无实现
|
||
} else {
|
||
body = parse_block(p, error);
|
||
if (!body) return NULL;
|
||
}
|
||
|
||
AstNode** parr = arena_alloc_impl(p->arena, pcount * sizeof(AstNode*));
|
||
memcpy(parr, params, pcount * sizeof(AstNode*));
|
||
const char** tparr = NULL;
|
||
if (tp_count > 0) {
|
||
tparr = arena_alloc_impl(p->arena, tp_count * sizeof(const char*));
|
||
memcpy(tparr, type_params, tp_count * sizeof(const char*));
|
||
}
|
||
return ast_make_function(p->arena,
|
||
arena_strdup_impl(p->arena, name->start, name->length),
|
||
parr, pcount, ret, ret_struct_name, body, is_pub, tparr, tp_count, tok_loc(fn_tok));
|
||
}
|
||
|
||
// === 模块文件加载辅助 ===
|
||
// parse 前向声明(定义在后面)
|
||
AstNode* parse(Arena* a, const Token* tokens, size_t count,
|
||
const char* filename, ErrorInfo* error);
|
||
|
||
static AstNode* load_module(Arena* a, const char* parent_file,
|
||
const char* mod_name, ErrorInfo* error) {
|
||
// 构造模块文件路径: 同目录下 mod_name.l
|
||
char mod_path[512];
|
||
const char* last_slash = strrchr(parent_file, '/');
|
||
const char* last_bs = strrchr(parent_file, '\\');
|
||
const char* dir_end = parent_file;
|
||
if (last_slash && last_slash > dir_end) dir_end = last_slash;
|
||
if (last_bs && last_bs > dir_end) dir_end = last_bs;
|
||
if (dir_end != parent_file) {
|
||
size_t dir_len = dir_end - parent_file + 1;
|
||
memcpy(mod_path, parent_file, dir_len);
|
||
snprintf(mod_path + dir_len, sizeof(mod_path) - dir_len, "%s.l", mod_name);
|
||
} else {
|
||
snprintf(mod_path, sizeof(mod_path), "%s.l", mod_name);
|
||
}
|
||
// 读取文件
|
||
FILE* f = fopen(mod_path, "rb");
|
||
if (!f) {
|
||
error->message = "无法打开模块文件"; error->filename = mod_path;
|
||
error->line = 0; error->col = 0;
|
||
return NULL;
|
||
}
|
||
fseek(f, 0, SEEK_END);
|
||
size_t sz = ftell(f); fseek(f, 0, SEEK_SET);
|
||
char* src = malloc(sz + 1);
|
||
if (!src) { fclose(f); return NULL; }
|
||
fread(src, 1, sz, f); src[sz] = '\0'; fclose(f);
|
||
|
||
size_t tc;
|
||
ErrorInfo lex_err = {0};
|
||
Token* toks = lex(a, src, mod_path, &tc, &lex_err);
|
||
free(src);
|
||
if (!toks) { *error = lex_err; return NULL; }
|
||
|
||
AstNode* ast = parse(a, toks, tc, mod_path, error);
|
||
return ast;
|
||
}
|
||
|
||
// === 程序入口 ===
|
||
AstNode* parse(Arena* a, const Token* tokens, size_t count,
|
||
const char* filename, ErrorInfo* error) {
|
||
Parser p = {.tokens = tokens, .count = count, .pos = 0,
|
||
.filename = filename, .arena = a};
|
||
AstNode* functions[256]; int fn_count = 0;
|
||
AstNode* structs[64]; int struct_count = 0;
|
||
AstNode* aliases[64]; int alias_count = 0;
|
||
AstNode* enums[64]; int enum_count = 0;
|
||
AstNode* impls[64]; int impl_count = 0;
|
||
AstNode* mods[64]; int mod_count = 0;
|
||
AstNode* uses[64]; int use_count = 0;
|
||
while (peek(&p)->kind != TOK_EOF && !error->message) {
|
||
// pub 前缀
|
||
bool is_pub = false;
|
||
if (peek(&p)->kind == TOK_PUB) {
|
||
is_pub = true; advance(&p);
|
||
}
|
||
if (peek(&p)->kind == TOK_TRAIT) {
|
||
const Token* tt = advance(&p);
|
||
const Token* tname = expect(&p, TOK_IDENT, error, "trait 后应为接口名");
|
||
if (!tname) return NULL;
|
||
if (!expect(&p, TOK_LBRACE, error, "缺少 '{'")) return NULL;
|
||
AstNode* methods[64]; int mcount = 0;
|
||
while (peek(&p)->kind != TOK_RBRACE && !error->message) {
|
||
if (mcount >= 64) { error->message = "trait 方法过多(最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
|
||
if (peek(&p)->kind != TOK_FN) { error->message = "trait 内只允许 fn"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
|
||
// trait 方法只解析签名(body 为空)
|
||
AstNode* m = parse_function(&p, false, error);
|
||
if (!m) return NULL;
|
||
m->as.function.body = NULL; // trait 方法无实现
|
||
methods[mcount++] = m;
|
||
if (peek(&p)->kind == TOK_COMMA) advance(&p);
|
||
}
|
||
if (!expect(&p, TOK_RBRACE, error, "缺少 '}'")) return NULL;
|
||
AstNode** marr = arena_alloc_impl(p.arena, mcount * sizeof(AstNode*));
|
||
memcpy(marr, methods, mcount * sizeof(AstNode*));
|
||
// 复用 impl_count 存储 trait(共用计数)
|
||
if (impl_count >= 64) { error->message = "trait 过多(最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
|
||
impls[impl_count++] = ast_make_trait_decl(p.arena,
|
||
arena_strdup_impl(p.arena, tname->start, tname->length),
|
||
marr, mcount, tok_loc(tt));
|
||
} else if (peek(&p)->kind == TOK_STRUCT) {
|
||
if (struct_count >= 64) { error->message = "结构体过多 (最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
|
||
structs[struct_count++] = parse_struct_decl(&p, error);
|
||
} else if (peek(&p)->kind == TOK_TYPE) {
|
||
if (alias_count >= 64) { error->message = "类型别名过多 (最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
|
||
const Token* type_tok = advance(&p); // 跳过 'type'
|
||
const Token* alias_name = expect(&p, TOK_IDENT, error, "type 后应为别名");
|
||
if (!alias_name) return NULL;
|
||
if (!expect(&p, TOK_ASSIGN, error, "缺少 '='")) return NULL;
|
||
TypeInfo rti = parse_type_expr(&p, error);
|
||
if (rti.kind == TYPE_ERROR) return NULL;
|
||
if (!expect(&p, TOK_SEMICOLON, error, "缺少 ';'")) return NULL;
|
||
aliases[alias_count++] = ast_make_type_alias(a,
|
||
arena_strdup_impl(a, alias_name->start, alias_name->length),
|
||
rti.kind, rti.struct_name, tok_loc(type_tok));
|
||
} else if (peek(&p)->kind == TOK_ENUM) {
|
||
advance(&p);
|
||
const Token* name = expect(&p, TOK_IDENT, error, "enum 后应为枚举名");
|
||
if (!name) return NULL;
|
||
if (!expect(&p, TOK_LBRACE, error, "缺少 '{'")) return NULL;
|
||
const char* variants[64];
|
||
TypeKind payload_types[64];
|
||
const char* payload_snames[64];
|
||
int vcount = 0;
|
||
while (peek(&p)->kind != TOK_RBRACE && !error->message) {
|
||
if (vcount >= 64) { error->message = "枚举变体过多(最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
|
||
const Token* vname = expect(&p, TOK_IDENT, error, "变体名");
|
||
if (!vname) return NULL;
|
||
variants[vcount] = arena_strdup_impl(p.arena, vname->start, vname->length);
|
||
payload_types[vcount] = TYPE_VOID;
|
||
payload_snames[vcount] = NULL;
|
||
// 可选 payload: Variant(Type)
|
||
if (peek(&p)->kind == TOK_LPAREN) {
|
||
advance(&p);
|
||
TypeInfo pti = parse_type_expr(&p, error);
|
||
if (pti.kind == TYPE_ERROR) return NULL;
|
||
payload_types[vcount] = pti.kind;
|
||
payload_snames[vcount] = pti.struct_name;
|
||
if (!expect(&p, TOK_RPAREN, error, "缺少 ')'")) return NULL;
|
||
}
|
||
vcount++;
|
||
if (peek(&p)->kind == TOK_COMMA) advance(&p); else break;
|
||
}
|
||
if (!expect(&p, TOK_RBRACE, error, "缺少 '}'")) return NULL;
|
||
const char** v_arr = arena_alloc_impl(p.arena, vcount * sizeof(const char*));
|
||
memcpy(v_arr, variants, vcount * sizeof(const char*));
|
||
TypeKind* pt_arr = arena_alloc_impl(p.arena, vcount * sizeof(TypeKind));
|
||
memcpy(pt_arr, payload_types, vcount * sizeof(TypeKind));
|
||
const char** ps_arr = arena_alloc_impl(p.arena, vcount * sizeof(const char*));
|
||
memcpy(ps_arr, payload_snames, vcount * sizeof(const char*));
|
||
AstNode* enum_decl = ast_make_enum_decl(p.arena,
|
||
arena_strdup_impl(p.arena, name->start, name->length),
|
||
v_arr, pt_arr, ps_arr, vcount, tok_loc(name));
|
||
if (enum_count >= 64) { error->message = "枚举过多 (最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
|
||
enums[enum_count++] = enum_decl;
|
||
} else if (peek(&p)->kind == TOK_EXTEND) {
|
||
const Token* i_tok = advance(&p);
|
||
const Token* first = expect(&p, TOK_IDENT, error, "extend 后应为结构体名");
|
||
if (!first) return NULL;
|
||
const char* trait_name = NULL;
|
||
const char* struct_name;
|
||
// extend Trait Struct { ... }(trait 实现:两个标识符)
|
||
if (peek(&p)->kind == TOK_IDENT) {
|
||
trait_name = arena_strdup_impl(p.arena, first->start, first->length);
|
||
struct_name = arena_strdup_impl(p.arena, peek(&p)->start, peek(&p)->length);
|
||
advance(&p);
|
||
} else {
|
||
struct_name = arena_strdup_impl(p.arena, first->start, first->length);
|
||
}
|
||
if (!expect(&p, TOK_LBRACE, error, "缺少 '{'")) return NULL;
|
||
AstNode* methods[64]; int mcount = 0;
|
||
while (peek(&p)->kind != TOK_RBRACE && !error->message) {
|
||
if (mcount >= 64) { error->message = "方法过多 (最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
|
||
if (peek(&p)->kind != TOK_FN) { error->message = "extend 块内只允许 fn"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
|
||
AstNode* m = parse_function(&p, false, error);
|
||
if (!m) return NULL;
|
||
// trait 实现: 方法名 mangled 为 TraitName$methodName
|
||
if (trait_name) {
|
||
char* mn = arena_alloc_impl(p.arena, strlen(trait_name) + strlen(m->as.function.name) + 4);
|
||
sprintf(mn, "%s$%s", trait_name, m->as.function.name);
|
||
m->as.function.name = mn;
|
||
}
|
||
methods[mcount++] = m;
|
||
}
|
||
if (!expect(&p, TOK_RBRACE, error, "缺少 '}'")) return NULL;
|
||
AstNode** m_arr = arena_alloc_impl(p.arena, mcount * sizeof(AstNode*));
|
||
memcpy(m_arr, methods, mcount * sizeof(AstNode*));
|
||
if (impl_count >= 64) { error->message = "extend 块过多 (最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
|
||
impls[impl_count++] = ast_make_impl_block(p.arena, struct_name, m_arr, mcount, tok_loc(i_tok));
|
||
} else if (peek(&p)->kind == TOK_MOD) {
|
||
advance(&p);
|
||
const Token* mn = expect(&p, TOK_IDENT, error, "mod 后应为模块名");
|
||
if (!mn) return NULL;
|
||
if (!expect(&p, TOK_SEMICOLON, error, "缺少 ';'")) return NULL;
|
||
const char* mod_name = arena_strdup_impl(p.arena, mn->start, mn->length);
|
||
AstNode* sub = load_module(a, filename, mod_name, error);
|
||
if (!sub) return NULL;
|
||
// 合并子模块项到当前文件(以 mod_name:: 为前缀)
|
||
for (size_t i = 0; i < sub->as.program.fn_count; i++) {
|
||
AstNode* fn = sub->as.program.functions[i];
|
||
if (fn->as.function.is_pub) {
|
||
char* mangled = arena_alloc_impl(p.arena, strlen(mod_name) + strlen(fn->as.function.name) + 4);
|
||
sprintf(mangled, "%s::%s", mod_name, fn->as.function.name);
|
||
fn->as.function.name = mangled;
|
||
if (fn_count >= 256) { error->message = "函数过多"; error->filename = p.filename; return NULL; }
|
||
functions[fn_count++] = fn;
|
||
}
|
||
}
|
||
for (size_t i = 0; i < sub->as.program.struct_count; i++) {
|
||
if (struct_count >= 64) break;
|
||
structs[struct_count++] = sub->as.program.structs[i];
|
||
}
|
||
for (size_t i = 0; i < sub->as.program.enum_count; i++) {
|
||
if (enum_count >= 64) break;
|
||
enums[enum_count++] = sub->as.program.enums[i];
|
||
}
|
||
if (mod_count < 64) mods[mod_count++] = ast_make_mod_decl(a, mod_name, sub, tok_loc(mn));
|
||
} else if (peek(&p)->kind == TOK_USE) {
|
||
advance(&p);
|
||
const Token* path_tok = expect(&p, TOK_IDENT, error, "use 后应为模块名");
|
||
if (!path_tok) return NULL;
|
||
if (!expect(&p, TOK_COLON_COLON, error, "缺少 '::'")) return NULL;
|
||
const Token* item_tok = expect(&p, TOK_IDENT, error, "use 后应为项目名");
|
||
if (!item_tok) return NULL;
|
||
if (!expect(&p, TOK_SEMICOLON, error, "缺少 ';'")) return NULL;
|
||
if (use_count >= 64) { error->message = "use 过多 (最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
|
||
uses[use_count++] = ast_make_use_decl(a,
|
||
arena_strdup_impl(p.arena, path_tok->start, path_tok->length),
|
||
arena_strdup_impl(p.arena, item_tok->start, item_tok->length),
|
||
tok_loc(path_tok));
|
||
} else if (peek(&p)->kind == TOK_FN) {
|
||
if (fn_count >= 256) { error->message = "函数过多 (最多256)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
|
||
functions[fn_count++] = parse_function(&p, is_pub, error);
|
||
} else {
|
||
error->message = "顶层只允许 fn、struct、type、enum、extend、mod 或 use";
|
||
error->filename = p.filename;
|
||
error->line = peek(&p)->line;
|
||
error->col = peek(&p)->col;
|
||
return NULL;
|
||
}
|
||
}
|
||
if (error->message) return NULL;
|
||
AstNode** fn_arr = arena_alloc_impl(a, fn_count * sizeof(AstNode*));
|
||
memcpy(fn_arr, functions, fn_count * sizeof(AstNode*));
|
||
AstNode** st_arr = arena_alloc_impl(a, struct_count * sizeof(AstNode*));
|
||
memcpy(st_arr, structs, struct_count * sizeof(AstNode*));
|
||
AstNode** al_arr = arena_alloc_impl(a, alias_count * sizeof(AstNode*));
|
||
memcpy(al_arr, aliases, alias_count * sizeof(AstNode*));
|
||
AstNode** en_arr = arena_alloc_impl(a, enum_count * sizeof(AstNode*));
|
||
memcpy(en_arr, enums, enum_count * sizeof(AstNode*));
|
||
AstNode** im_arr = arena_alloc_impl(a, impl_count * sizeof(AstNode*));
|
||
memcpy(im_arr, impls, impl_count * sizeof(AstNode*));
|
||
return ast_make_program(a, fn_arr, fn_count, st_arr, struct_count,
|
||
al_arr, alias_count, en_arr, enum_count,
|
||
im_arr, impl_count, loc_at(0, 0));
|
||
}
|