feat: struct参数/返回值 + SourceLoc + 测试补全
- struct 可作函数参数和返回值 (fn make_point -> Point) - SourceLoc 抽象: 所有 ast_make_* 参数 + AstNode 迁移完毕 - sema: +4 struct 类型检查测试 (字段类型/未定义/数量/嵌套) - codegen: +2 struct IR 生成测试 (decl + field_access) - 新增集成测试 14_struct_fn.l 测试: 104 单元 + 14 集成 = 全部通过
This commit is contained in:
+52
-40
@@ -78,7 +78,7 @@ static AstNode* parse_unary(Parser* p, ErrorInfo* error) {
|
||||
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, op->line, op->col);
|
||||
return ast_make_unary(p->arena, uop, operand, tok_loc(op));
|
||||
}
|
||||
|
||||
static AstNode* parse_group(Parser* p, ErrorInfo* error) {
|
||||
@@ -92,15 +92,15 @@ static AstNode* parse_group(Parser* p, ErrorInfo* error) {
|
||||
static AstNode* parse_literal(Parser* p) {
|
||||
const Token* t = advance(p);
|
||||
switch (t->kind) {
|
||||
case TOK_INT_LIT: return ast_make_literal_i64(p->arena, tok_int_value(t), t->line, t->col);
|
||||
case TOK_FLOAT_LIT: return ast_make_literal_f64(p->arena, tok_float_value(t), t->line, t->col);
|
||||
case TOK_TRUE: return ast_make_literal_bool(p->arena, true, t->line, t->col);
|
||||
case TOK_FALSE: return ast_make_literal_bool(p->arena, false, t->line, t->col);
|
||||
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_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';
|
||||
return ast_make_literal_str(p->arena, str, t->line, t->col);
|
||||
return ast_make_literal_str(p->arena, str, tok_loc(t));
|
||||
}
|
||||
default: return NULL;
|
||||
}
|
||||
@@ -137,7 +137,7 @@ static AstNode* parse_struct_init(Parser* p, const Token* name, ErrorInfo* error
|
||||
|
||||
return ast_make_struct_init(p->arena,
|
||||
arena_strdup_impl(p->arena, name->start, name->length),
|
||||
n_arr, v_arr, fcount, name->line, name->col);
|
||||
n_arr, v_arr, fcount, tok_loc(name));
|
||||
}
|
||||
|
||||
// === 标识符 / 函数调用 / 结构体初始化 ===
|
||||
@@ -175,11 +175,11 @@ static AstNode* parse_ident_or_call(Parser* p, ErrorInfo* error) {
|
||||
AstNode** arg_arr = arena_alloc_impl(p->arena, arg_count * sizeof(AstNode*));
|
||||
memcpy(arg_arr, args, arg_count * sizeof(AstNode*));
|
||||
return ast_make_call(p->arena, arena_strdup_impl(p->arena, name->start, name->length),
|
||||
arg_arr, arg_count, name->line, name->col);
|
||||
arg_arr, arg_count, tok_loc(name));
|
||||
}
|
||||
return ast_make_ident(p->arena,
|
||||
arena_strdup_impl(p->arena, name->start, name->length),
|
||||
name->line, name->col);
|
||||
tok_loc(name));
|
||||
}
|
||||
|
||||
// === Pratt 主循环 ===
|
||||
@@ -216,7 +216,7 @@ static AstNode* parse_expr_prec(Parser* p, Precedence min_prec, ErrorInfo* error
|
||||
if (!field) return NULL;
|
||||
left = ast_make_field_access(p->arena, left,
|
||||
arena_strdup_impl(p->arena, field->start, field->length),
|
||||
field->line, field->col);
|
||||
tok_loc(field));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ static AstNode* parse_expr_prec(Parser* p, Precedence min_prec, ErrorInfo* error
|
||||
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, op->line, op->col);
|
||||
left = ast_make_binary(p->arena, tok_to_binop(kind), left, right, tok_loc(op));
|
||||
}
|
||||
|
||||
return left;
|
||||
@@ -271,7 +271,7 @@ static AstNode* parse_struct_decl(Parser* p, ErrorInfo* error) {
|
||||
}
|
||||
fields[fcount++] = ast_make_parameter(p->arena,
|
||||
arena_strdup_impl(p->arena, fname->start, fname->length),
|
||||
field_kind, field_struct_name, fname->line, fname->col);
|
||||
field_kind, field_struct_name, tok_loc(fname));
|
||||
if (peek(p)->kind == TOK_COMMA) advance(p);
|
||||
else break;
|
||||
}
|
||||
@@ -281,7 +281,7 @@ static AstNode* parse_struct_decl(Parser* p, ErrorInfo* error) {
|
||||
memcpy(farr, fields, fcount * sizeof(AstNode*));
|
||||
return ast_make_struct_decl(p->arena,
|
||||
arena_strdup_impl(p->arena, name->start, name->length),
|
||||
farr, fcount, s_tok->line, s_tok->col);
|
||||
farr, fcount, tok_loc(s_tok));
|
||||
}
|
||||
|
||||
// === 语句解析 ===
|
||||
@@ -305,7 +305,7 @@ static AstNode* parse_block(Parser* p, ErrorInfo* error) {
|
||||
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, open->line, open->col);
|
||||
return ast_make_block(p->arena, arr, count, tok_loc(open));
|
||||
}
|
||||
|
||||
static AstNode* parse_statement(Parser* p, ErrorInfo* error) {
|
||||
@@ -342,7 +342,7 @@ static AstNode* parse_statement(Parser* p, ErrorInfo* error) {
|
||||
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, t->line, t->col);
|
||||
annot_type, has_type_annot, is_mut, init, struct_type_name, tok_loc(t));
|
||||
}
|
||||
|
||||
if (t->kind == TOK_IF) {
|
||||
@@ -360,7 +360,7 @@ static AstNode* parse_statement(Parser* p, ErrorInfo* error) {
|
||||
}
|
||||
if (!else_block) return NULL;
|
||||
}
|
||||
return ast_make_if(p->arena, cond, then_block, else_block, t->line, t->col);
|
||||
return ast_make_if(p->arena, cond, then_block, else_block, tok_loc(t));
|
||||
}
|
||||
|
||||
if (t->kind == TOK_WHILE) {
|
||||
@@ -369,7 +369,7 @@ static AstNode* parse_statement(Parser* p, ErrorInfo* error) {
|
||||
if (!cond) return NULL;
|
||||
AstNode* body = parse_block(p, error);
|
||||
if (!body) return NULL;
|
||||
return ast_make_while(p->arena, cond, body, t->line, t->col);
|
||||
return ast_make_while(p->arena, cond, body, tok_loc(t));
|
||||
}
|
||||
|
||||
if (t->kind == TOK_FOR) {
|
||||
@@ -403,20 +403,20 @@ static AstNode* parse_statement(Parser* p, ErrorInfo* error) {
|
||||
const char* vname = arena_strdup_impl(p->arena, var_name->start, var_name->length);
|
||||
|
||||
// 构建: let mut i = start;
|
||||
AstNode* let_stmt = ast_make_let(p->arena, vname, TYPE_UNKNOWN, false, true, start_expr, NULL, var_name->line, var_name->col);
|
||||
AstNode* let_stmt = ast_make_let(p->arena, vname, TYPE_UNKNOWN, false, true, start_expr, NULL, tok_loc(var_name));
|
||||
|
||||
// 构建: i < end (while 条件)
|
||||
AstNode* cond = ast_make_binary(p->arena, OP_LT,
|
||||
ast_make_ident(p->arena, vname, var_name->line, var_name->col),
|
||||
end_expr, var_name->line, var_name->col);
|
||||
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, var_name->line, var_name->col),
|
||||
ast_make_literal_i64(p->arena, 1, var_name->line, var_name->col),
|
||||
var_name->line, var_name->col),
|
||||
var_name->line, var_name->col);
|
||||
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,
|
||||
@@ -424,27 +424,27 @@ static AstNode* parse_statement(Parser* p, ErrorInfo* error) {
|
||||
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->line, body->col);
|
||||
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, t->line, t->col);
|
||||
AstNode* while_loop = ast_make_while(p->arena, cond, new_body, tok_loc(t));
|
||||
|
||||
// 包装: { let mut 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, t->line, t->col);
|
||||
return ast_make_block(p->arena, stmts, 2, tok_loc(t));
|
||||
}
|
||||
|
||||
if (t->kind == TOK_RETURN) {
|
||||
advance(p);
|
||||
if (match(p, TOK_SEMICOLON)) {
|
||||
return ast_make_return(p->arena, NULL, t->line, t->col);
|
||||
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, t->line, t->col);
|
||||
return ast_make_return(p->arena, expr, tok_loc(t));
|
||||
}
|
||||
|
||||
// 赋值语句: ident = expr ;
|
||||
@@ -456,7 +456,7 @@ static AstNode* parse_statement(Parser* p, ErrorInfo* error) {
|
||||
if (!expect(p, TOK_SEMICOLON, error, "缺少 ';'")) return NULL;
|
||||
return ast_make_assign(p->arena,
|
||||
arena_strdup_impl(p->arena, name->start, name->length),
|
||||
value, name->line, name->col);
|
||||
value, tok_loc(name));
|
||||
}
|
||||
|
||||
// 复合赋值: ident += expr → ident = ident + expr
|
||||
@@ -481,12 +481,12 @@ static AstNode* parse_statement(Parser* p, ErrorInfo* error) {
|
||||
|
||||
AstNode* lhs_ident = ast_make_ident(p->arena,
|
||||
arena_strdup_impl(p->arena, name->start, name->length),
|
||||
name->line, name->col);
|
||||
tok_loc(name));
|
||||
AstNode* bin_expr = ast_make_binary(p->arena, binop, lhs_ident, rhs,
|
||||
name->line, name->col);
|
||||
tok_loc(name));
|
||||
return ast_make_assign(p->arena,
|
||||
arena_strdup_impl(p->arena, name->start, name->length),
|
||||
bin_expr, name->line, name->col);
|
||||
bin_expr, tok_loc(name));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,7 +494,7 @@ static AstNode* parse_statement(Parser* p, ErrorInfo* error) {
|
||||
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, t->line, t->col);
|
||||
return ast_make_expr_stmt(p->arena, expr, tok_loc(t));
|
||||
}
|
||||
|
||||
// === 函数解析 ===
|
||||
@@ -512,13 +512,20 @@ static AstNode* parse_function(Parser* p, ErrorInfo* error) {
|
||||
if (!pname) return NULL;
|
||||
if (!expect(p, TOK_COLON, error, "缺少 ':'")) return NULL;
|
||||
const Token* ptype = advance(p);
|
||||
if (!tok_is_type(ptype->kind)) {
|
||||
TypeKind param_kind;
|
||||
const char* param_struct_name = NULL;
|
||||
if (tok_is_type(ptype->kind)) {
|
||||
param_kind = token_to_type(ptype->kind);
|
||||
} else if (ptype->kind == TOK_IDENT) {
|
||||
param_kind = TYPE_STRUCT;
|
||||
param_struct_name = arena_strdup_impl(p->arena, ptype->start, ptype->length);
|
||||
} else {
|
||||
error->message = "无效的参数类型"; error->filename = p->filename;
|
||||
error->line = ptype->line; error->col = ptype->col; return NULL;
|
||||
}
|
||||
params[pcount++] = ast_make_parameter(p->arena,
|
||||
arena_strdup_impl(p->arena, pname->start, pname->length),
|
||||
token_to_type(ptype->kind), NULL, pname->line, pname->col);
|
||||
param_kind, param_struct_name, tok_loc(pname));
|
||||
if (match(p, TOK_COMMA)) continue;
|
||||
else break;
|
||||
}
|
||||
@@ -526,13 +533,18 @@ static AstNode* parse_function(Parser* p, ErrorInfo* error) {
|
||||
|
||||
// 返回类型
|
||||
TypeKind ret = TYPE_VOID;
|
||||
const char* ret_struct_name = NULL;
|
||||
if (match(p, TOK_ARROW)) {
|
||||
const Token* rt = advance(p);
|
||||
if (!tok_is_type(rt->kind)) {
|
||||
if (tok_is_type(rt->kind)) {
|
||||
ret = token_to_type(rt->kind);
|
||||
} else if (rt->kind == TOK_IDENT) {
|
||||
ret = TYPE_STRUCT;
|
||||
ret_struct_name = arena_strdup_impl(p->arena, rt->start, rt->length);
|
||||
} else {
|
||||
error->message = "无效的返回类型"; error->filename = p->filename;
|
||||
error->line = rt->line; error->col = rt->col; return NULL;
|
||||
}
|
||||
ret = token_to_type(rt->kind);
|
||||
}
|
||||
|
||||
AstNode* body = parse_block(p, error);
|
||||
@@ -542,7 +554,7 @@ static AstNode* parse_function(Parser* p, ErrorInfo* error) {
|
||||
memcpy(parr, params, pcount * sizeof(AstNode*));
|
||||
return ast_make_function(p->arena,
|
||||
arena_strdup_impl(p->arena, name->start, name->length),
|
||||
parr, pcount, ret, body, fn_tok->line, fn_tok->col);
|
||||
parr, pcount, ret, ret_struct_name, body, tok_loc(fn_tok));
|
||||
}
|
||||
|
||||
// === 程序入口 ===
|
||||
@@ -572,5 +584,5 @@ AstNode* parse(Arena* a, const Token* tokens, size_t count,
|
||||
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*));
|
||||
return ast_make_program(a, fn_arr, fn_count, st_arr, struct_count, 0, 0);
|
||||
return ast_make_program(a, fn_arr, fn_count, st_arr, struct_count, loc_at(0, 0));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user