fix: AST_PARAMETER 增加数组元素类型字段 + 五子棋集成测试

问题: 函数参数声明 i64[N] 只在 TypeInfo 存储数组信息, AST_PARAMETER
仅存 TypeKind(TYPE_ARRAY), 丢失元素类型和大小, 导致 sema 将参数
数组误判为 i32[N], codegen 生成 void GEP 而崩溃。

修复:
- AST_PARAMETER 新增 arr_elem_type/arr_elem_struct/arr_size 字段
- parser 传入 parse_type_expr 的完整数组信息
- sema 将数组信息从 AST 节点复制到 Symbol
- codegen 为数组参数生成正确的 LLVMArrayType

附加: 45_gomoku.l — 5x5 五子棋双AI对弈, 测试数组/函数/循环/字符串

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 18:48:04 +08:00
parent ee3f9e0bd0
commit 6ebe551ee3
8 changed files with 110 additions and 14 deletions
+63
View File
@@ -0,0 +1,63 @@
// === 五子棋 5x5 — L Language 综合测试 (带简单AI) ===
fn idx(x: i64, y: i64) -> i64 { return y * 5 + x; }
fn count_dir(b: i64[25], x: i64, y: i64, dx: i64, dy: i64, color: i64) -> i64 {
var cx = x + dx; var cy = y + dy; var n = 0;
while cx >= 0 { if cx > 4 { return n; } if cy < 0 { return n; } if cy > 4 { return n; }
if b[idx(cx, cy)] != color { return n; }
n = n + 1; cx = cx + dx; cy = cy + dy; }
return n;
}
fn score_pos(b: i64[25], x: i64, y: i64, c: i64) -> i64 {
if b[idx(x, y)] != 0 { return -1; }
var h = count_dir(b, x, y, 1, 0, c) + count_dir(b, x, y, -1, 0, c);
var v = count_dir(b, x, y, 0, 1, c) + count_dir(b, x, y, 0, -1, c);
var d = count_dir(b, x, y, 1, 1, c) + count_dir(b, x, y, -1, -1, c);
var e = count_dir(b, x, y, 1, -1, c) + count_dir(b, x, y, -1, 1, c);
if h > 2 { return 1000; } if v > 2 { return 1000; }
if d > 2 { return 1000; } if e > 2 { return 1000; }
return h + v + d + e;
}
fn ai(b: i64[25], c: i64) -> i64 {
var bx = 2; var by = 2; var bs = -1; var x = 0;
while x < 5 { var y = 0; while y < 5 {
var s = score_pos(b, x, y, c);
if s > bs { bs = s; bx = x; by = y; }
y = y + 1; } x = x + 1; }
return by * 100 + bx;
}
fn won(b: i64[25], x: i64, y: i64) -> bool {
var c = b[idx(x, y)]; if c == 0 { return false; }
if count_dir(b, x, y, 1, 0, c) + count_dir(b, x, y, -1, 0, c) > 2 { return true; }
if count_dir(b, x, y, 0, 1, c) + count_dir(b, x, y, 0, -1, c) > 2 { return true; }
if count_dir(b, x, y, 1, 1, c) + count_dir(b, x, y, -1, -1, c) > 2 { return true; }
if count_dir(b, x, y, 1, -1, c) + count_dir(b, x, y, -1, 1, c) > 2 { return true; }
return false;
}
fn print5(b: i64[25]) -> void {
var r = 0; while r < 5 {
var line = ""; var c = 0; while c < 5 {
var v = b[idx(c, r)];
if v == 0 { line = line + ". "; }
if v == 1 { line = line + "X "; }
if v == 2 { line = line + "O "; }
c = c + 1; } print_str(line); r = r + 1; }
}
fn main() -> void {
var b: i64[25] = b; var i = 0; while i < 25 { b[i] = 0; i = i + 1; }
b[idx(2, 2)] = 1; var turn = 2; var n = 1;
while n < 25 {
var mv = ai(b, turn); var y = mv / 100; var x = mv - y * 100;
b[idx(x, y)] = turn;
if turn == 1 { print_str("X: "); } else { print_str("O: "); }
print_i64(x); print_i64(y);
if won(b, x, y) { print5(b); if turn == 1 { print_str("X wins!"); } else { print_str("O wins!"); } return; }
n = n + 1; if turn == 1 { turn = 2; } else { turn = 1; }
}
print5(b); print_str("Draw");
}
+7 -7
View File
@@ -129,8 +129,8 @@ void test_codegen_struct_decl() {
/* 构造 AST: struct Point { x: i64, y: i64 } */
AstNode* fields[2];
fields[0] = ast_make_parameter(&a, "x", TYPE_I64, NULL, false, loc_at(1, 1));
fields[1] = ast_make_parameter(&a, "y", TYPE_I64, NULL, false, loc_at(1, 1));
fields[0] = ast_make_parameter(&a, "x", TYPE_I64, NULL, false, 0, NULL, 0, loc_at(1, 1));
fields[1] = ast_make_parameter(&a, "y", TYPE_I64, NULL, false, 0, NULL, 0, loc_at(1, 1));
AstNode* struct_decl = ast_make_struct_decl(&a, "Point", fields, 2, loc_at(1, 1));
AstNode* structs[] = { struct_decl };
@@ -185,8 +185,8 @@ void test_codegen_struct_field_access() {
/* 构造 AST: struct Point { x: i64, y: i64 } */
AstNode* fields[2];
fields[0] = ast_make_parameter(&a, "x", TYPE_I64, NULL, false, loc_at(1, 1));
fields[1] = ast_make_parameter(&a, "y", TYPE_I64, NULL, false, loc_at(1, 1));
fields[0] = ast_make_parameter(&a, "x", TYPE_I64, NULL, false, 0, NULL, 0, loc_at(1, 1));
fields[1] = ast_make_parameter(&a, "y", TYPE_I64, NULL, false, 0, NULL, 0, loc_at(1, 1));
AstNode* struct_decl = ast_make_struct_decl(&a, "Point", fields, 2, loc_at(1, 1));
AstNode* structs[] = { struct_decl };
@@ -356,13 +356,13 @@ void test_codegen_method_call() {
/* struct Point { x: i64, y: i64 } */
AstNode* fields[2];
fields[0] = ast_make_parameter(&a, "x", TYPE_I64, NULL, false, loc_at(1, 1));
fields[1] = ast_make_parameter(&a, "y", TYPE_I64, NULL, false, loc_at(1, 1));
fields[0] = ast_make_parameter(&a, "x", TYPE_I64, NULL, false, 0, NULL, 0, loc_at(1, 1));
fields[1] = ast_make_parameter(&a, "y", TYPE_I64, NULL, false, 0, NULL, 0, loc_at(1, 1));
AstNode* struct_decl = ast_make_struct_decl(&a, "Point", fields, 2, loc_at(1, 1));
AstNode* structs[] = { struct_decl };
/* fn Point$get_x(self: Point) -> i64 { return self.x; } */
AstNode* self_param = ast_make_parameter(&a, "self", TYPE_STRUCT, "Point", false, loc_at(1, 1));
AstNode* self_param = ast_make_parameter(&a, "self", TYPE_STRUCT, "Point", false, 0, NULL, 0, loc_at(1, 1));
AstNode* params[] = { self_param };
AstNode* self_ident = ast_make_ident(&a, "self", loc_at(1, 1));
self_ident->type.kind = TYPE_STRUCT;