Compare commits
13 Commits
e60021b684
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 6ebe551ee3 | |||
| ee3f9e0bd0 | |||
| 6d5f8092a7 | |||
| f5c0650a97 | |||
| 06d80f441a | |||
| c8da286d31 | |||
| 0a0667776a | |||
| f7710ede9d | |||
| caf17e16fc | |||
| 71208a87f4 | |||
| 06c8773fac | |||
| 443b22bdf1 | |||
| 0088347576 |
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
cmake_minimum_required(VERSION 3.20)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
project(l_lang VERSION 0.7.0 LANGUAGES C)
|
project(l_lang VERSION 0.8.0 LANGUAGES C)
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 17)
|
set(CMAKE_C_STANDARD 17)
|
||||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ typedef enum {
|
|||||||
TYPE_STRUCT, // 结构体类型
|
TYPE_STRUCT, // 结构体类型
|
||||||
TYPE_ENUM, // 枚举类型
|
TYPE_ENUM, // 枚举类型
|
||||||
TYPE_ARRAY, // 固定大小数组类型
|
TYPE_ARRAY, // 固定大小数组类型
|
||||||
|
TYPE_CLOSURE, // 闭包类型 (函数指针 + 环境指针)
|
||||||
TYPE_GENERIC, // 泛型类型参数(单态化前)
|
TYPE_GENERIC, // 泛型类型参数(单态化前)
|
||||||
TYPE_UNKNOWN, // 尚未推断
|
TYPE_UNKNOWN, // 尚未推断
|
||||||
TYPE_ERROR, // 类型错误
|
TYPE_ERROR, // 类型错误
|
||||||
@@ -36,6 +37,7 @@ static inline const char* type_name(TypeKind kind) {
|
|||||||
case TYPE_STRUCT: return "struct";
|
case TYPE_STRUCT: return "struct";
|
||||||
case TYPE_ENUM: return "enum";
|
case TYPE_ENUM: return "enum";
|
||||||
case TYPE_ARRAY: return "array";
|
case TYPE_ARRAY: return "array";
|
||||||
|
case TYPE_CLOSURE: return "closure";
|
||||||
default: return "<unknown>";
|
default: return "<unknown>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-1
@@ -41,14 +41,26 @@ AstNode* ast_make_function(void* alloc, const char* name, AstNode** params, size
|
|||||||
n->as.function.is_pub = is_pub;
|
n->as.function.is_pub = is_pub;
|
||||||
n->as.function.type_params = type_params;
|
n->as.function.type_params = type_params;
|
||||||
n->as.function.type_param_count = tp_count;
|
n->as.function.type_param_count = tp_count;
|
||||||
|
n->as.function.multi_ret_types = NULL;
|
||||||
|
n->as.function.multi_ret_snames = NULL;
|
||||||
|
n->as.function.multi_ret_count = 0;
|
||||||
|
n->as.function.captured = NULL;
|
||||||
|
n->as.function.cap_types = NULL;
|
||||||
|
n->as.function.cap_count = 0;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstNode* ast_make_parameter(void* alloc, const char* name, TypeKind type,
|
AstNode* ast_make_parameter(void* alloc, const char* name, TypeKind type,
|
||||||
const char* struct_type_name, SourceLoc loc) {
|
const char* struct_type_name, bool is_out,
|
||||||
|
TypeKind arr_elem, const char* arr_elem_sname,
|
||||||
|
int64_t arr_size, SourceLoc loc) {
|
||||||
NEW(alloc, AST_PARAMETER);
|
NEW(alloc, AST_PARAMETER);
|
||||||
n->as.parameter.name = name; n->as.parameter.type = type;
|
n->as.parameter.name = name; n->as.parameter.type = type;
|
||||||
n->as.parameter.struct_type_name = struct_type_name;
|
n->as.parameter.struct_type_name = struct_type_name;
|
||||||
|
n->as.parameter.is_out = is_out;
|
||||||
|
n->as.parameter.arr_elem_type = arr_elem;
|
||||||
|
n->as.parameter.arr_elem_struct = arr_elem_sname;
|
||||||
|
n->as.parameter.arr_size = arr_size;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +76,7 @@ AstNode* ast_make_let(void* alloc, const char* name, TypeKind annot_type, bool h
|
|||||||
NEW(alloc, AST_LET_STMT);
|
NEW(alloc, AST_LET_STMT);
|
||||||
n->as.let_stmt.name = name; n->as.let_stmt.annot_type = annot_type;
|
n->as.let_stmt.name = name; n->as.let_stmt.annot_type = annot_type;
|
||||||
n->as.let_stmt.has_type_annot = has_type_annot; n->as.let_stmt.is_mut = is_mut;
|
n->as.let_stmt.has_type_annot = has_type_annot; n->as.let_stmt.is_mut = is_mut;
|
||||||
|
n->as.let_stmt.is_const = false;
|
||||||
n->as.let_stmt.init = init;
|
n->as.let_stmt.init = init;
|
||||||
n->as.let_stmt.struct_type_name = struct_type_name;
|
n->as.let_stmt.struct_type_name = struct_type_name;
|
||||||
n->as.let_stmt.annot_element_type = annot_elem_type;
|
n->as.let_stmt.annot_element_type = annot_elem_type;
|
||||||
@@ -103,6 +116,20 @@ AstNode* ast_make_expr_stmt(void* alloc, AstNode* expr, SourceLoc loc) {
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AstNode* ast_make_defer_stmt(void* alloc, AstNode* body, SourceLoc loc) {
|
||||||
|
NEW(alloc, AST_DEFER_STMT);
|
||||||
|
n->as.defer_stmt.body = body;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
AstNode* ast_make_list_comp(void* alloc, const char* var, AstNode* arr, AstNode* map, SourceLoc loc) {
|
||||||
|
NEW(alloc, AST_LIST_COMP);
|
||||||
|
n->as.list_comp.var_name = var;
|
||||||
|
n->as.list_comp.array = arr;
|
||||||
|
n->as.list_comp.map_expr = map;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
AstNode* ast_make_binary(void* alloc, BinaryOp op, AstNode* left, AstNode* right, SourceLoc loc) {
|
AstNode* ast_make_binary(void* alloc, BinaryOp op, AstNode* left, AstNode* right, SourceLoc loc) {
|
||||||
NEW(alloc, AST_BINARY_EXPR);
|
NEW(alloc, AST_BINARY_EXPR);
|
||||||
n->as.binary.op = op; n->as.binary.left = left; n->as.binary.right = right;
|
n->as.binary.op = op; n->as.binary.left = left; n->as.binary.right = right;
|
||||||
@@ -261,6 +288,20 @@ AstNode* ast_make_method_call(void* alloc, AstNode* receiver, const char* method
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AstNode* ast_make_lambda(void* alloc, AstNode** params, size_t pcount,
|
||||||
|
TypeKind ret, const char* ret_struct_name,
|
||||||
|
AstNode* body, SourceLoc loc) {
|
||||||
|
NEW(alloc, AST_LAMBDA);
|
||||||
|
n->as.lambda.params = params; n->as.lambda.param_count = pcount;
|
||||||
|
n->as.lambda.return_type = ret;
|
||||||
|
n->as.lambda.return_struct_type_name = ret_struct_name;
|
||||||
|
n->as.lambda.body = body;
|
||||||
|
n->as.lambda.generated_name = NULL;
|
||||||
|
n->as.lambda.captured = NULL;
|
||||||
|
n->as.lambda.captured_count = 0;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
AstNode* ast_make_mod_decl(void* alloc, const char* name, AstNode* sub_ast, SourceLoc loc) {
|
AstNode* ast_make_mod_decl(void* alloc, const char* name, AstNode* sub_ast, SourceLoc loc) {
|
||||||
NEW(alloc, AST_MOD_DECL);
|
NEW(alloc, AST_MOD_DECL);
|
||||||
n->as.mod_decl.name = name;
|
n->as.mod_decl.name = name;
|
||||||
|
|||||||
+26
-4
@@ -15,6 +15,8 @@ typedef enum {
|
|||||||
AST_WHILE_STMT,
|
AST_WHILE_STMT,
|
||||||
AST_RETURN_STMT,
|
AST_RETURN_STMT,
|
||||||
AST_EXPR_STMT,
|
AST_EXPR_STMT,
|
||||||
|
AST_DEFER_STMT,
|
||||||
|
AST_LIST_COMP, // [for x in expr: body]
|
||||||
AST_BINARY_EXPR,
|
AST_BINARY_EXPR,
|
||||||
AST_UNARY_EXPR,
|
AST_UNARY_EXPR,
|
||||||
AST_CALL_EXPR,
|
AST_CALL_EXPR,
|
||||||
@@ -30,6 +32,7 @@ typedef enum {
|
|||||||
AST_ARRAY_ASSIGN_STMT,// arr[i] = expr
|
AST_ARRAY_ASSIGN_STMT,// arr[i] = expr
|
||||||
AST_IMPL_BLOCK, // impl StructName { fn method(...) ... }
|
AST_IMPL_BLOCK, // impl StructName { fn method(...) ... }
|
||||||
AST_METHOD_CALL, // receiver.method(args)
|
AST_METHOD_CALL, // receiver.method(args)
|
||||||
|
AST_LAMBDA, // fn(x: T) -> R { body } 匿名函数/闭包
|
||||||
AST_MOD_DECL, // mod foo;
|
AST_MOD_DECL, // mod foo;
|
||||||
AST_USE_DECL, // use foo::bar;
|
AST_USE_DECL, // use foo::bar;
|
||||||
AST_TRAIT_DECL, // trait Name { fn ... }
|
AST_TRAIT_DECL, // trait Name { fn ... }
|
||||||
@@ -69,13 +72,16 @@ struct AstNode {
|
|||||||
struct { const char* name; struct AstNode** params; size_t param_count;
|
struct { const char* name; struct AstNode** params; size_t param_count;
|
||||||
TypeKind return_type; const char* return_struct_type_name;
|
TypeKind return_type; const char* return_struct_type_name;
|
||||||
struct AstNode* body; bool is_pub;
|
struct AstNode* body; bool is_pub;
|
||||||
const char** type_params; size_t type_param_count; } function;
|
const char** type_params; size_t type_param_count;
|
||||||
|
TypeKind* multi_ret_types; const char** multi_ret_snames; size_t multi_ret_count;
|
||||||
|
const char** captured; TypeKind* cap_types; size_t cap_count; } function;
|
||||||
// AST_PARAMETER (也用作结构体字段: name + type)
|
// AST_PARAMETER (也用作结构体字段: name + type)
|
||||||
struct { const char* name; TypeKind type; const char* struct_type_name; } parameter;
|
struct { const char* name; TypeKind type; const char* struct_type_name; bool is_out;
|
||||||
|
TypeKind arr_elem_type; const char* arr_elem_struct; int64_t arr_size; } parameter;
|
||||||
// AST_BLOCK
|
// AST_BLOCK
|
||||||
struct { struct AstNode** stmts; size_t stmt_count; } block;
|
struct { struct AstNode** stmts; size_t stmt_count; } block;
|
||||||
// AST_LET_STMT
|
// AST_LET_STMT
|
||||||
struct { const char* name; TypeKind annot_type; bool has_type_annot; bool is_mut; struct AstNode* init;
|
struct { const char* name; TypeKind annot_type; bool has_type_annot; bool is_mut; bool is_const; struct AstNode* init;
|
||||||
const char* struct_type_name;
|
const char* struct_type_name;
|
||||||
TypeKind annot_element_type; const char* annot_element_struct_name; int64_t annot_array_size; } let_stmt;
|
TypeKind annot_element_type; const char* annot_element_struct_name; int64_t annot_array_size; } let_stmt;
|
||||||
// AST_ASSIGN_STMT
|
// AST_ASSIGN_STMT
|
||||||
@@ -88,6 +94,10 @@ struct AstNode {
|
|||||||
struct { struct AstNode* expr; } return_stmt;
|
struct { struct AstNode* expr; } return_stmt;
|
||||||
// AST_EXPR_STMT
|
// AST_EXPR_STMT
|
||||||
struct { struct AstNode* expr; } expr_stmt;
|
struct { struct AstNode* expr; } expr_stmt;
|
||||||
|
// AST_DEFER_STMT
|
||||||
|
struct { struct AstNode* body; } defer_stmt;
|
||||||
|
// AST_LIST_COMP
|
||||||
|
struct { const char* var_name; struct AstNode* array; struct AstNode* map_expr; } list_comp;
|
||||||
// AST_BINARY_EXPR
|
// AST_BINARY_EXPR
|
||||||
struct { BinaryOp op; struct AstNode* left; struct AstNode* right; } binary;
|
struct { BinaryOp op; struct AstNode* left; struct AstNode* right; } binary;
|
||||||
// AST_UNARY_EXPR
|
// AST_UNARY_EXPR
|
||||||
@@ -124,6 +134,12 @@ struct AstNode {
|
|||||||
struct { const char* struct_name; struct AstNode** methods; size_t method_count; } impl_block;
|
struct { const char* struct_name; struct AstNode** methods; size_t method_count; } impl_block;
|
||||||
// AST_METHOD_CALL
|
// AST_METHOD_CALL
|
||||||
struct { struct AstNode* receiver; const char* method_name; struct AstNode** args; const char** arg_names; size_t arg_count; } method_call;
|
struct { struct AstNode* receiver; const char* method_name; struct AstNode** args; const char** arg_names; size_t arg_count; } method_call;
|
||||||
|
// AST_LAMBDA
|
||||||
|
struct { struct AstNode** params; size_t param_count;
|
||||||
|
TypeKind return_type; const char* return_struct_type_name;
|
||||||
|
struct AstNode* body;
|
||||||
|
const char* generated_name; // 自动生成的顶层函数名
|
||||||
|
const char** captured; size_t captured_count; } lambda;
|
||||||
// AST_MOD_DECL
|
// AST_MOD_DECL
|
||||||
struct { const char* name; struct AstNode* ast; } mod_decl;
|
struct { const char* name; struct AstNode* ast; } mod_decl;
|
||||||
// AST_USE_DECL
|
// AST_USE_DECL
|
||||||
@@ -143,7 +159,8 @@ AstNode* ast_make_function(void* alloc, const char* name, AstNode** params, size
|
|||||||
TypeKind ret, const char* ret_struct_name, AstNode* body,
|
TypeKind ret, const char* ret_struct_name, AstNode* body,
|
||||||
bool is_pub, const char** type_params, size_t tp_count,
|
bool is_pub, const char** type_params, size_t tp_count,
|
||||||
SourceLoc loc);
|
SourceLoc loc);
|
||||||
AstNode* ast_make_parameter(void* alloc, const char* name, TypeKind type, const char* struct_type_name, SourceLoc loc);
|
AstNode* ast_make_parameter(void* alloc, const char* name, TypeKind type, const char* struct_type_name, bool is_out,
|
||||||
|
TypeKind arr_elem, const char* arr_elem_sname, int64_t arr_size, SourceLoc loc);
|
||||||
AstNode* ast_make_block(void* alloc, AstNode** stmts, size_t count, SourceLoc loc);
|
AstNode* ast_make_block(void* alloc, AstNode** stmts, size_t count, SourceLoc loc);
|
||||||
AstNode* ast_make_let(void* alloc, const char* name, TypeKind annot_type, bool has_type_annot,
|
AstNode* ast_make_let(void* alloc, const char* name, TypeKind annot_type, bool has_type_annot,
|
||||||
bool is_mut, AstNode* init, const char* struct_type_name,
|
bool is_mut, AstNode* init, const char* struct_type_name,
|
||||||
@@ -153,6 +170,8 @@ AstNode* ast_make_if(void* alloc, AstNode* cond, AstNode* then_b, AstNode* else_
|
|||||||
AstNode* ast_make_while(void* alloc, AstNode* cond, AstNode* body, SourceLoc loc);
|
AstNode* ast_make_while(void* alloc, AstNode* cond, AstNode* body, SourceLoc loc);
|
||||||
AstNode* ast_make_return(void* alloc, AstNode* expr, SourceLoc loc);
|
AstNode* ast_make_return(void* alloc, AstNode* expr, SourceLoc loc);
|
||||||
AstNode* ast_make_expr_stmt(void* alloc, AstNode* expr, SourceLoc loc);
|
AstNode* ast_make_expr_stmt(void* alloc, AstNode* expr, SourceLoc loc);
|
||||||
|
AstNode* ast_make_defer_stmt(void* alloc, AstNode* expr, SourceLoc loc);
|
||||||
|
AstNode* ast_make_list_comp(void* alloc, const char* var, AstNode* arr, AstNode* map, SourceLoc loc);
|
||||||
AstNode* ast_make_binary(void* alloc, BinaryOp op, AstNode* left, AstNode* right, SourceLoc loc);
|
AstNode* ast_make_binary(void* alloc, BinaryOp op, AstNode* left, AstNode* right, SourceLoc loc);
|
||||||
AstNode* ast_make_unary(void* alloc, BinaryOp op, AstNode* operand, SourceLoc loc);
|
AstNode* ast_make_unary(void* alloc, BinaryOp op, AstNode* operand, SourceLoc loc);
|
||||||
AstNode* ast_make_call(void* alloc, const char* name, AstNode** args, const char** arg_names, size_t count, SourceLoc loc);
|
AstNode* ast_make_call(void* alloc, const char* name, AstNode** args, const char** arg_names, size_t count, SourceLoc loc);
|
||||||
@@ -176,6 +195,9 @@ AstNode* ast_make_index_expr(void* alloc, AstNode* array, AstNode* index, Source
|
|||||||
AstNode* ast_make_array_assign(void* alloc, const char* name, AstNode* index, AstNode* value, SourceLoc loc);
|
AstNode* ast_make_array_assign(void* alloc, const char* name, AstNode* index, AstNode* value, SourceLoc loc);
|
||||||
AstNode* ast_make_impl_block(void* alloc, const char* struct_name, AstNode** methods, size_t count, SourceLoc loc);
|
AstNode* ast_make_impl_block(void* alloc, const char* struct_name, AstNode** methods, size_t count, SourceLoc loc);
|
||||||
AstNode* ast_make_method_call(void* alloc, AstNode* receiver, const char* method, AstNode** args, const char** arg_names, size_t count, SourceLoc loc);
|
AstNode* ast_make_method_call(void* alloc, AstNode* receiver, const char* method, AstNode** args, const char** arg_names, size_t count, SourceLoc loc);
|
||||||
|
AstNode* ast_make_lambda(void* alloc, AstNode** params, size_t pcount,
|
||||||
|
TypeKind ret, const char* ret_struct_name,
|
||||||
|
AstNode* body, SourceLoc loc);
|
||||||
AstNode* ast_make_mod_decl(void* alloc, const char* name, AstNode* sub_ast, SourceLoc loc);
|
AstNode* ast_make_mod_decl(void* alloc, const char* name, AstNode* sub_ast, SourceLoc loc);
|
||||||
AstNode* ast_make_use_decl(void* alloc, const char* path, const char* item, SourceLoc loc);
|
AstNode* ast_make_use_decl(void* alloc, const char* path, const char* item, SourceLoc loc);
|
||||||
AstNode* ast_make_trait_decl(void* alloc, const char* name, AstNode** methods, size_t count, SourceLoc loc);
|
AstNode* ast_make_trait_decl(void* alloc, const char* name, AstNode** methods, size_t count, SourceLoc loc);
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ typedef void* (*VisitFn)(void* ctx, AstNode* node);
|
|||||||
|
|
||||||
// 遍历表 — 按 AstKind 索引, 未处理的条目为 NULL
|
// 遍历表 — 按 AstKind 索引, 未处理的条目为 NULL
|
||||||
// 新增 AST 节点: 在此表新增一条目, 编译器会警告未初始化的函数指针
|
// 新增 AST 节点: 在此表新增一条目, 编译器会警告未初始化的函数指针
|
||||||
enum { VISIT_TABLE_SIZE = 28 };
|
enum { VISIT_TABLE_SIZE = 29 };
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void* ctx;
|
void* ctx;
|
||||||
|
|||||||
+220
-5
@@ -11,6 +11,13 @@ LLVMTypeRef to_llvm_type(CgCtx* ctx, TypeKind kind) {
|
|||||||
case TYPE_BOOL: return LLVMInt1TypeInContext(ctx->context);
|
case TYPE_BOOL: return LLVMInt1TypeInContext(ctx->context);
|
||||||
case TYPE_CHAR: return LLVMInt8TypeInContext(ctx->context);
|
case TYPE_CHAR: return LLVMInt8TypeInContext(ctx->context);
|
||||||
case TYPE_STR: return LLVMPointerType(LLVMInt8TypeInContext(ctx->context), 0);
|
case TYPE_STR: return LLVMPointerType(LLVMInt8TypeInContext(ctx->context), 0);
|
||||||
|
case TYPE_CLOSURE: {
|
||||||
|
LLVMTypeRef cls_fields[] = {
|
||||||
|
LLVMInt64TypeInContext(ctx->context), // fn_ptr
|
||||||
|
LLVMPointerType(LLVMInt8TypeInContext(ctx->context), 0) // env_ptr
|
||||||
|
};
|
||||||
|
return LLVMStructTypeInContext(ctx->context, cls_fields, 2, false);
|
||||||
|
}
|
||||||
case TYPE_STRUCT:
|
case TYPE_STRUCT:
|
||||||
case TYPE_ENUM: {
|
case TYPE_ENUM: {
|
||||||
LLVMTypeRef fields[] = { LLVMInt64TypeInContext(ctx->context),
|
LLVMTypeRef fields[] = { LLVMInt64TypeInContext(ctx->context),
|
||||||
@@ -235,18 +242,82 @@ static LLVMValueRef cg_call_impl(CgCtx* ctx, AstNode* node) {
|
|||||||
return LLVMBuildCall2(ctx->builder, ctx->printf_ty, ctx->printf_fn,
|
return LLVMBuildCall2(ctx->builder, ctx->printf_ty, ctx->printf_fn,
|
||||||
(LLVMValueRef[]){fmt, arg}, 2, "");
|
(LLVMValueRef[]){fmt, arg}, 2, "");
|
||||||
}
|
}
|
||||||
|
LLVMTypeRef fn_ty = NULL;
|
||||||
LLVMValueRef fn = find_fn(ctx, node->as.call.name);
|
LLVMValueRef fn = find_fn(ctx, node->as.call.name);
|
||||||
if (!fn) return NULL;
|
LLVMValueRef closure_env = NULL;
|
||||||
|
LLVMValueRef gen_fn = NULL; // 闭包对应的生成函数
|
||||||
|
if (fn) {
|
||||||
|
fn_ty = LLVMGlobalGetValueType(fn);
|
||||||
|
} else {
|
||||||
|
VarEntry* cve = NULL;
|
||||||
|
for (VarEntry* e = ctx->var_table; e; e = e->next)
|
||||||
|
if (strcmp(e->name, node->as.call.name) == 0) { cve = e; break; }
|
||||||
|
if (cve && cve->closure_fn) {
|
||||||
|
gen_fn = find_fn(ctx, cve->closure_fn);
|
||||||
|
if (gen_fn) {
|
||||||
|
fn_ty = LLVMGlobalGetValueType(gen_fn);
|
||||||
|
LLVMTypeRef cls_ty = to_llvm_type(ctx, TYPE_CLOSURE);
|
||||||
|
LLVMValueRef cls_val = LLVMBuildLoad2(ctx->builder, cls_ty,
|
||||||
|
cve->alloca, "cls_val");
|
||||||
|
LLVMValueRef fn_val = LLVMBuildExtractValue(ctx->builder,
|
||||||
|
cls_val, 0, "fn_ptr_i64");
|
||||||
|
fn = LLVMBuildIntToPtr(ctx->builder, fn_val,
|
||||||
|
LLVMPointerType(fn_ty, 0), "fn_cast");
|
||||||
|
closure_env = LLVMBuildExtractValue(ctx->builder,
|
||||||
|
cls_val, 1, "env_ptr");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!fn || !fn_ty) return NULL;
|
||||||
LLVMValueRef args[16];
|
LLVMValueRef args[16];
|
||||||
if (node->as.call.arg_count > 16) { ctx->error = "函数参数过多(最多16)"; return NULL; }
|
if (node->as.call.arg_count > 16) { ctx->error = "函数参数过多(最多16)"; return NULL; }
|
||||||
|
FnEntry* fn_entry = find_fn_entry(ctx, node->as.call.name);
|
||||||
for (size_t i = 0; i < node->as.call.arg_count; i++) {
|
for (size_t i = 0; i < node->as.call.arg_count; i++) {
|
||||||
args[i] = codegen_expr(ctx, node->as.call.args[i]);
|
bool is_out = fn_entry && fn_entry->out_params
|
||||||
|
&& i < fn_entry->pc && fn_entry->out_params[i];
|
||||||
|
if (is_out) {
|
||||||
|
// out 参数传 alloca 地址而非加载后的值
|
||||||
|
AstNode* arg = node->as.call.args[i];
|
||||||
|
if (arg->kind == AST_IDENT_EXPR) {
|
||||||
|
args[i] = find_var(ctx, arg->as.ident.name);
|
||||||
|
} else if (arg->kind == AST_INDEX_EXPR) {
|
||||||
|
// arr[i]: 生成 GEP 得到元素指针
|
||||||
|
LLVMValueRef arr_ptr = find_var(ctx, arg->as.index_expr.array->as.ident.name);
|
||||||
|
LLVMValueRef idx_val = codegen_expr(ctx, arg->as.index_expr.index);
|
||||||
|
if (!arr_ptr || !idx_val) return NULL;
|
||||||
|
LLVMValueRef indices[] = {
|
||||||
|
LLVMConstInt(LLVMInt32TypeInContext(ctx->context), 0, false),
|
||||||
|
LLVMBuildIntCast2(ctx->builder, idx_val,
|
||||||
|
LLVMInt32TypeInContext(ctx->context), false, "idx32")
|
||||||
|
};
|
||||||
|
args[i] = LLVMBuildGEP2(ctx->builder,
|
||||||
|
LLVMGetElementType(LLVMTypeOf(arr_ptr)),
|
||||||
|
arr_ptr, indices, 2, "out_gep");
|
||||||
|
} else {
|
||||||
|
args[i] = codegen_expr(ctx, node->as.call.args[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
args[i] = codegen_expr(ctx, node->as.call.args[i]);
|
||||||
|
}
|
||||||
if (!args[i]) return NULL;
|
if (!args[i]) return NULL;
|
||||||
}
|
}
|
||||||
LLVMTypeRef fn_ty = LLVMGlobalGetValueType(fn);
|
// 闭包调用: 若函数有 env 参数, 将其作为第一个参数
|
||||||
|
LLVMValueRef call_args[17];
|
||||||
|
unsigned call_argc = (unsigned)node->as.call.arg_count;
|
||||||
|
// 用生成函数的参数数判断是否需要 pass env
|
||||||
|
bool need_env = closure_env && gen_fn && LLVMCountParams(gen_fn) > call_argc;
|
||||||
|
if (need_env) {
|
||||||
|
call_args[0] = closure_env;
|
||||||
|
for (unsigned i = 0; i < call_argc; i++)
|
||||||
|
call_args[i + 1] = args[i];
|
||||||
|
call_argc++;
|
||||||
|
} else {
|
||||||
|
for (unsigned i = 0; i < call_argc; i++)
|
||||||
|
call_args[i] = args[i];
|
||||||
|
}
|
||||||
LLVMTypeRef ret_ty = LLVMGetReturnType(fn_ty);
|
LLVMTypeRef ret_ty = LLVMGetReturnType(fn_ty);
|
||||||
return LLVMBuildCall2(ctx->builder, fn_ty, fn, args,
|
return LLVMBuildCall2(ctx->builder, fn_ty, fn, call_args,
|
||||||
(unsigned)node->as.call.arg_count,
|
call_argc,
|
||||||
ret_ty == LLVMVoidTypeInContext(ctx->context) ? "" : "call");
|
ret_ty == LLVMVoidTypeInContext(ctx->context) ? "" : "call");
|
||||||
}
|
}
|
||||||
CG_HANDLER(cg_call)
|
CG_HANDLER(cg_call)
|
||||||
@@ -403,6 +474,148 @@ CG_HANDLER(cg_if_expr)
|
|||||||
// === Visitor Dispatch 表 ===
|
// === Visitor Dispatch 表 ===
|
||||||
static AstDispatch cg_dispatch;
|
static AstDispatch cg_dispatch;
|
||||||
|
|
||||||
|
static LLVMValueRef cg_list_comp_impl(CgCtx* ctx, AstNode* node) {
|
||||||
|
TypeInfo* ti = &node->type;
|
||||||
|
LLVMTypeRef elem_ty = to_llvm_type(ctx, ti->element_type);
|
||||||
|
LLVMTypeRef arr_ty = LLVMArrayType(elem_ty,
|
||||||
|
ti->array_size > 0 ? (unsigned)ti->array_size : 1);
|
||||||
|
LLVMValueRef result = LLVMBuildAlloca(ctx->builder, arr_ty, "list");
|
||||||
|
// 初始化为零
|
||||||
|
LLVMBuildStore(ctx->builder, LLVMConstNull(arr_ty), result);
|
||||||
|
// 获取源数组指针 (需要 alloca 做 GEP, 不能用 load 后的值)
|
||||||
|
LLVMValueRef src_ptr = NULL;
|
||||||
|
if (node->as.list_comp.array->kind == AST_IDENT_EXPR) {
|
||||||
|
src_ptr = find_var(ctx, node->as.list_comp.array->as.ident.name);
|
||||||
|
}
|
||||||
|
if (!src_ptr) return NULL;
|
||||||
|
// for i in 0 to N
|
||||||
|
LLVMValueRef func = LLVMGetBasicBlockParent(LLVMGetInsertBlock(ctx->builder));
|
||||||
|
LLVMBasicBlockRef cond_bb = LLVMAppendBasicBlockInContext(ctx->context, func, "lc_cond");
|
||||||
|
LLVMBasicBlockRef body_bb = LLVMAppendBasicBlockInContext(ctx->context, func, "lc_body");
|
||||||
|
LLVMBasicBlockRef exit_bb = LLVMAppendBasicBlockInContext(ctx->context, func, "lc_exit");
|
||||||
|
// 循环变量 i
|
||||||
|
LLVMValueRef i_alloca = LLVMBuildAlloca(ctx->builder,
|
||||||
|
LLVMInt64TypeInContext(ctx->context), "lc_i");
|
||||||
|
LLVMBuildStore(ctx->builder,
|
||||||
|
LLVMConstInt(LLVMInt64TypeInContext(ctx->context), 0, false), i_alloca);
|
||||||
|
LLVMBuildBr(ctx->builder, cond_bb);
|
||||||
|
// 条件块
|
||||||
|
LLVMPositionBuilderAtEnd(ctx->builder, cond_bb);
|
||||||
|
LLVMValueRef i_val = LLVMBuildLoad2(ctx->builder,
|
||||||
|
LLVMInt64TypeInContext(ctx->context), i_alloca, "i");
|
||||||
|
LLVMValueRef end_val = LLVMConstInt(LLVMInt64TypeInContext(ctx->context),
|
||||||
|
(unsigned long long)ti->array_size, false);
|
||||||
|
LLVMValueRef cond = LLVMBuildICmp(ctx->builder, LLVMIntSLT, i_val, end_val, "lc_cond");
|
||||||
|
LLVMBuildCondBr(ctx->builder, cond, body_bb, exit_bb);
|
||||||
|
// 循环体
|
||||||
|
LLVMPositionBuilderAtEnd(ctx->builder, body_bb);
|
||||||
|
LLVMValueRef i32_trunc = LLVMBuildTrunc(ctx->builder, i_val,
|
||||||
|
LLVMInt32TypeInContext(ctx->context), "i32");
|
||||||
|
// 绑定循环变量: var x = arr[i]
|
||||||
|
LLVMValueRef src_indices[] = {
|
||||||
|
LLVMConstInt(LLVMInt32TypeInContext(ctx->context), 0, false), i32_trunc
|
||||||
|
};
|
||||||
|
LLVMValueRef src_gep = LLVMBuildGEP2(ctx->builder, arr_ty, src_ptr, src_indices, 2, "src_gep");
|
||||||
|
LLVMValueRef var_alloca = LLVMBuildAlloca(ctx->builder, elem_ty,
|
||||||
|
node->as.list_comp.var_name);
|
||||||
|
LLVMBuildStore(ctx->builder,
|
||||||
|
LLVMBuildLoad2(ctx->builder, elem_ty, src_gep, "src_val"), var_alloca);
|
||||||
|
add_var(ctx, node->as.list_comp.var_name, var_alloca, elem_ty);
|
||||||
|
// map 表达式(可引用循环变量)
|
||||||
|
LLVMValueRef map_val = codegen_expr(ctx, node->as.list_comp.map_expr);
|
||||||
|
if (!map_val) return NULL;
|
||||||
|
// 结果数组: GEP + store
|
||||||
|
LLVMValueRef dst_indices[] = {
|
||||||
|
LLVMConstInt(LLVMInt32TypeInContext(ctx->context), 0, false),
|
||||||
|
LLVMBuildTrunc(ctx->builder, i_val,
|
||||||
|
LLVMInt32TypeInContext(ctx->context), "i32")
|
||||||
|
};
|
||||||
|
LLVMBuildStore(ctx->builder, map_val,
|
||||||
|
LLVMBuildGEP2(ctx->builder, arr_ty, result, dst_indices, 2, "dst_ptr"));
|
||||||
|
// i = i + 1
|
||||||
|
LLVMValueRef next_i = LLVMBuildAdd(ctx->builder, i_val,
|
||||||
|
LLVMConstInt(LLVMInt64TypeInContext(ctx->context), 1, false), "i_inc");
|
||||||
|
LLVMBuildStore(ctx->builder, next_i, i_alloca);
|
||||||
|
LLVMBuildBr(ctx->builder, cond_bb);
|
||||||
|
// 出口
|
||||||
|
LLVMPositionBuilderAtEnd(ctx->builder, exit_bb);
|
||||||
|
return LLVMBuildLoad2(ctx->builder, arr_ty, result, "list_val");
|
||||||
|
}
|
||||||
|
CG_HANDLER(cg_list_comp)
|
||||||
|
|
||||||
|
static LLVMValueRef cg_lambda_impl(CgCtx* ctx, AstNode* node) {
|
||||||
|
// 获取生成函数
|
||||||
|
LLVMValueRef gen_fn = find_fn(ctx, node->as.lambda.generated_name);
|
||||||
|
if (!gen_fn) return NULL;
|
||||||
|
|
||||||
|
// 闭包结构体: { i64 fn_ptr, i8* env_ptr }
|
||||||
|
LLVMTypeRef cls_ty = to_llvm_type(ctx, TYPE_CLOSURE);
|
||||||
|
LLVMValueRef closure = LLVMBuildAlloca(ctx->builder, cls_ty, "closure");
|
||||||
|
LLVMValueRef fn_ptr = LLVMBuildPtrToInt(ctx->builder, gen_fn,
|
||||||
|
LLVMInt64TypeInContext(ctx->context), "fn_ptr");
|
||||||
|
|
||||||
|
LLVMValueRef env_ptr = LLVMConstNull(
|
||||||
|
LLVMPointerType(LLVMInt8TypeInContext(ctx->context), 0));
|
||||||
|
|
||||||
|
// 若有捕获变量, 构建环境结构体
|
||||||
|
AstNode* fn_ast = NULL;
|
||||||
|
// 在 g_program 中查找对应的函数 AST 获取捕获信息
|
||||||
|
if (g_program) {
|
||||||
|
for (size_t i = 0; i < g_program->as.program.fn_count; i++) {
|
||||||
|
if (g_program->as.program.functions[i]->as.function.name &&
|
||||||
|
strcmp(g_program->as.program.functions[i]->as.function.name,
|
||||||
|
node->as.lambda.generated_name) == 0) {
|
||||||
|
fn_ast = g_program->as.program.functions[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fn_ast && fn_ast->as.function.cap_count > 0) {
|
||||||
|
size_t nc = fn_ast->as.function.cap_count;
|
||||||
|
// 构建 env struct: { cap_type_0, cap_type_1, ... }
|
||||||
|
LLVMTypeRef* ef = arena_alloc(ctx->arena, nc * sizeof(LLVMTypeRef));
|
||||||
|
for (size_t i = 0; i < nc; i++)
|
||||||
|
ef[i] = to_llvm_type(ctx, fn_ast->as.function.cap_types[i]);
|
||||||
|
LLVMTypeRef env_ty = LLVMStructTypeInContext(ctx->context, ef, (unsigned)nc, false);
|
||||||
|
|
||||||
|
// malloc env
|
||||||
|
LLVMValueRef env_size = LLVMSizeOf(env_ty);
|
||||||
|
LLVMValueRef malloc_args[] = { env_size };
|
||||||
|
LLVMValueRef env = LLVMBuildCall2(ctx->builder,
|
||||||
|
LLVMGlobalGetValueType(ctx->malloc_fn), ctx->malloc_fn,
|
||||||
|
malloc_args, 1, "env");
|
||||||
|
env_ptr = LLVMBuildBitCast(ctx->builder, env,
|
||||||
|
LLVMPointerType(LLVMInt8TypeInContext(ctx->context), 0), "env_cast");
|
||||||
|
LLVMValueRef typed_env = LLVMBuildBitCast(ctx->builder, env,
|
||||||
|
LLVMPointerType(env_ty, 0), "env_typed");
|
||||||
|
|
||||||
|
// 存储捕获的值到 env struct
|
||||||
|
for (size_t i = 0; i < nc; i++) {
|
||||||
|
LLVMValueRef cap_alloca = find_var(ctx, fn_ast->as.function.captured[i]);
|
||||||
|
if (!cap_alloca) return NULL;
|
||||||
|
LLVMTypeRef cap_ty = to_llvm_type(ctx, fn_ast->as.function.cap_types[i]);
|
||||||
|
LLVMValueRef cap_val = LLVMBuildLoad2(ctx->builder, cap_ty,
|
||||||
|
cap_alloca, "cap_val");
|
||||||
|
LLVMValueRef gep_idx[] = {
|
||||||
|
LLVMConstInt(LLVMInt32TypeInContext(ctx->context), 0, false),
|
||||||
|
LLVMConstInt(LLVMInt32TypeInContext(ctx->context), (unsigned)i, false)
|
||||||
|
};
|
||||||
|
LLVMValueRef field_ptr = LLVMBuildGEP2(ctx->builder, env_ty,
|
||||||
|
typed_env, gep_idx, 2, "cap_gep");
|
||||||
|
LLVMBuildStore(ctx->builder, cap_val, field_ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 填充 closure struct: { fn_ptr, env_ptr }
|
||||||
|
LLVMValueRef f0 = LLVMBuildStructGEP2(ctx->builder, cls_ty, closure, 0, "cl_f0");
|
||||||
|
LLVMBuildStore(ctx->builder, fn_ptr, f0);
|
||||||
|
LLVMValueRef f1 = LLVMBuildStructGEP2(ctx->builder, cls_ty, closure, 1, "cl_f1");
|
||||||
|
LLVMBuildStore(ctx->builder, env_ptr, f1);
|
||||||
|
|
||||||
|
return LLVMBuildLoad2(ctx->builder, cls_ty, closure, "closure_val");
|
||||||
|
}
|
||||||
|
CG_HANDLER(cg_lambda)
|
||||||
|
|
||||||
void codegen_expr_init(void) {
|
void codegen_expr_init(void) {
|
||||||
ast_dispatch_set(&cg_dispatch, AST_LITERAL_EXPR, cg_literal);
|
ast_dispatch_set(&cg_dispatch, AST_LITERAL_EXPR, cg_literal);
|
||||||
ast_dispatch_set(&cg_dispatch, AST_IDENT_EXPR, cg_ident);
|
ast_dispatch_set(&cg_dispatch, AST_IDENT_EXPR, cg_ident);
|
||||||
@@ -416,6 +629,8 @@ void codegen_expr_init(void) {
|
|||||||
ast_dispatch_set(&cg_dispatch, AST_INDEX_EXPR, cg_index);
|
ast_dispatch_set(&cg_dispatch, AST_INDEX_EXPR, cg_index);
|
||||||
ast_dispatch_set(&cg_dispatch, AST_BLOCK, cg_block);
|
ast_dispatch_set(&cg_dispatch, AST_BLOCK, cg_block);
|
||||||
ast_dispatch_set(&cg_dispatch, AST_IF_STMT, cg_if_expr);
|
ast_dispatch_set(&cg_dispatch, AST_IF_STMT, cg_if_expr);
|
||||||
|
ast_dispatch_set(&cg_dispatch, AST_LIST_COMP, cg_list_comp);
|
||||||
|
ast_dispatch_set(&cg_dispatch, AST_LAMBDA, cg_lambda);
|
||||||
}
|
}
|
||||||
|
|
||||||
// === 统一入口 ===
|
// === 统一入口 ===
|
||||||
|
|||||||
+108
-20
@@ -9,11 +9,14 @@ LLVMValueRef find_var(CgCtx* ctx, const char* name) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_var(CgCtx* ctx, const char* name, LLVMValueRef alloca, LLVMTypeRef alloca_type) {
|
VarEntry* add_var(CgCtx* ctx, const char* name, LLVMValueRef alloca, LLVMTypeRef alloca_type) {
|
||||||
VarEntry* e = arena_alloc(ctx->arena, sizeof(*e));
|
VarEntry* e = arena_alloc(ctx->arena, sizeof(*e));
|
||||||
if (!e) return;
|
if (!e) return NULL;
|
||||||
e->name = name; e->alloca = alloca; e->alloca_type = alloca_type; e->next = ctx->var_table;
|
e->name = name; e->alloca = alloca; e->alloca_type = alloca_type;
|
||||||
|
e->closure_fn = NULL;
|
||||||
|
e->next = ctx->var_table;
|
||||||
ctx->var_table = e;
|
ctx->var_table = e;
|
||||||
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
// === 函数表 ===
|
// === 函数表 ===
|
||||||
@@ -23,17 +26,24 @@ LLVMValueRef find_fn(CgCtx* ctx, const char* name) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_fn(CgCtx* ctx, const char* name, LLVMValueRef fn) {
|
void add_fn(CgCtx* ctx, const char* name, LLVMValueRef fn, bool* out_params, size_t pc) {
|
||||||
FnEntry* e = arena_alloc(ctx->arena, sizeof(*e));
|
FnEntry* e = arena_alloc(ctx->arena, sizeof(*e));
|
||||||
if (!e) return;
|
if (!e) return;
|
||||||
e->name = name; e->fn = fn;
|
e->name = name; e->fn = fn;
|
||||||
e->ret = TYPE_VOID;
|
e->ret = TYPE_VOID;
|
||||||
e->params = NULL;
|
e->params = NULL;
|
||||||
e->pc = 0;
|
e->out_params = out_params;
|
||||||
|
e->pc = pc;
|
||||||
e->next = ctx->fn_table;
|
e->next = ctx->fn_table;
|
||||||
ctx->fn_table = e;
|
ctx->fn_table = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FnEntry* find_fn_entry(CgCtx* ctx, const char* name) {
|
||||||
|
for (FnEntry* e = ctx->fn_table; e; e = e->next)
|
||||||
|
if (strcmp(e->name, name) == 0) return e;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// === 结构体类型表 ===
|
// === 结构体类型表 ===
|
||||||
void add_struct_type(CgCtx* ctx, const char* name, LLVMTypeRef ty, size_t fc) {
|
void add_struct_type(CgCtx* ctx, const char* name, LLVMTypeRef ty, size_t fc) {
|
||||||
StructTypeEntry* e = arena_alloc(ctx->arena, sizeof(*e));
|
StructTypeEntry* e = arena_alloc(ctx->arena, sizeof(*e));
|
||||||
@@ -77,6 +87,13 @@ void cleanup_emit(CgCtx* ctx, size_t from_mark) {
|
|||||||
ctx->cleanup_count = from_mark;
|
ctx->cleanup_count = from_mark;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 发射所有 defer 语句(LIFO 顺序)
|
||||||
|
static void emit_deferred(CgCtx* ctx) {
|
||||||
|
for (size_t i = ctx->defer_count; i > 0; i--)
|
||||||
|
codegen_stmt(ctx, ctx->defer_exprs[i - 1]);
|
||||||
|
ctx->defer_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// === 语句代码生成 ===
|
// === 语句代码生成 ===
|
||||||
void codegen_stmt(CgCtx* ctx, AstNode* node) {
|
void codegen_stmt(CgCtx* ctx, AstNode* node) {
|
||||||
if (!node) return;
|
if (!node) return;
|
||||||
@@ -120,7 +137,11 @@ void codegen_stmt(CgCtx* ctx, AstNode* node) {
|
|||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
add_var(ctx, node->as.let_stmt.name, alloca, var_type);
|
VarEntry* ve = add_var(ctx, node->as.let_stmt.name, alloca, var_type);
|
||||||
|
// 若 init 是 lambda, 记录闭包函数名供后续调用
|
||||||
|
if (node->as.let_stmt.init &&
|
||||||
|
node->as.let_stmt.init->kind == AST_LAMBDA && ve)
|
||||||
|
ve->closure_fn = node->as.let_stmt.init->as.lambda.generated_name;
|
||||||
|
|
||||||
// 自动内存管理: 只追踪 str 堆分配 (拼接/malloc)
|
// 自动内存管理: 只追踪 str 堆分配 (拼接/malloc)
|
||||||
// struct 是栈上值类型,不能 free();含 str 字段时 v0.5 扩展
|
// struct 是栈上值类型,不能 free();含 str 字段时 v0.5 扩展
|
||||||
@@ -146,6 +167,11 @@ void codegen_stmt(CgCtx* ctx, AstNode* node) {
|
|||||||
codegen_expr(ctx, node->as.expr_stmt.expr);
|
codegen_expr(ctx, node->as.expr_stmt.expr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case AST_DEFER_STMT:
|
||||||
|
if (ctx->defer_count < 64)
|
||||||
|
ctx->defer_exprs[ctx->defer_count++] = node->as.defer_stmt.body;
|
||||||
|
break;
|
||||||
|
|
||||||
case AST_RETURN_STMT: {
|
case AST_RETURN_STMT: {
|
||||||
// 先计算返回值
|
// 先计算返回值
|
||||||
LLVMValueRef ret_val = NULL;
|
LLVMValueRef ret_val = NULL;
|
||||||
@@ -168,9 +194,9 @@ void codegen_stmt(CgCtx* ctx, AstNode* node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// return 前释放当前作用域所有 str 堆分配
|
// defer → cleanup → ret 的顺序
|
||||||
|
emit_deferred(ctx);
|
||||||
cleanup_emit(ctx, 0);
|
cleanup_emit(ctx, 0);
|
||||||
// 然后 emit ret
|
|
||||||
if (has_val) LLVMBuildRet(ctx->builder, ret_val);
|
if (has_val) LLVMBuildRet(ctx->builder, ret_val);
|
||||||
else LLVMBuildRetVoid(ctx->builder);
|
else LLVMBuildRetVoid(ctx->builder);
|
||||||
break;
|
break;
|
||||||
@@ -179,10 +205,12 @@ void codegen_stmt(CgCtx* ctx, AstNode* node) {
|
|||||||
case AST_BLOCK: {
|
case AST_BLOCK: {
|
||||||
if (++codegen_depth > MAX_CODEGEN_DEPTH) { codegen_depth--; return; }
|
if (++codegen_depth > MAX_CODEGEN_DEPTH) { codegen_depth--; return; }
|
||||||
size_t block_mark = ctx->cleanup_count;
|
size_t block_mark = ctx->cleanup_count;
|
||||||
|
VarEntry* saved_table = ctx->var_table;
|
||||||
for (size_t i = 0; i < node->as.block.stmt_count; i++) {
|
for (size_t i = 0; i < node->as.block.stmt_count; i++) {
|
||||||
codegen_stmt(ctx, node->as.block.stmts[i]);
|
codegen_stmt(ctx, node->as.block.stmts[i]);
|
||||||
}
|
}
|
||||||
cleanup_emit(ctx, block_mark); // 作用域退出: 释放块内 str 堆分配
|
ctx->var_table = saved_table;
|
||||||
|
cleanup_emit(ctx, block_mark);
|
||||||
codegen_depth--;
|
codegen_depth--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -365,16 +393,38 @@ LLVMModuleRef codegen_module(AstNode* ast, Arena* codegen_arena,
|
|||||||
// 第一遍:声明所有 L 函数
|
// 第一遍:声明所有 L 函数
|
||||||
for (size_t i = 0; i < ast->as.program.fn_count; i++) {
|
for (size_t i = 0; i < ast->as.program.fn_count; i++) {
|
||||||
AstNode* fn = ast->as.program.functions[i];
|
AstNode* fn = ast->as.program.functions[i];
|
||||||
|
bool has_env = fn->as.function.cap_count > 0;
|
||||||
|
size_t total_params = fn->as.function.param_count + (has_env ? 1 : 0);
|
||||||
LLVMTypeRef* ptypes = arena_alloc(ctx.arena,
|
LLVMTypeRef* ptypes = arena_alloc(ctx.arena,
|
||||||
fn->as.function.param_count * sizeof(LLVMTypeRef));
|
total_params * sizeof(LLVMTypeRef));
|
||||||
|
bool* out_params = NULL;
|
||||||
|
if (total_params > 0) {
|
||||||
|
out_params = arena_alloc(ctx.arena, total_params * sizeof(bool));
|
||||||
|
for (size_t j = 0; j < total_params; j++) out_params[j] = false;
|
||||||
|
}
|
||||||
|
// 若有捕获, 第一个参数是 env_ptr
|
||||||
|
size_t poff = 0;
|
||||||
|
if (has_env) {
|
||||||
|
ptypes[0] = LLVMPointerType(LLVMInt8TypeInContext(ctx.context), 0);
|
||||||
|
poff = 1;
|
||||||
|
}
|
||||||
for (size_t j = 0; j < fn->as.function.param_count; j++) {
|
for (size_t j = 0; j < fn->as.function.param_count; j++) {
|
||||||
AstNode* param = fn->as.function.params[j];
|
AstNode* param = fn->as.function.params[j];
|
||||||
|
bool is_out = param->as.parameter.is_out;
|
||||||
|
if (out_params) out_params[j + poff] = is_out;
|
||||||
|
LLVMTypeRef inner_ty;
|
||||||
if (param->as.parameter.type == TYPE_STRUCT &&
|
if (param->as.parameter.type == TYPE_STRUCT &&
|
||||||
param->as.parameter.struct_type_name) {
|
param->as.parameter.struct_type_name) {
|
||||||
ptypes[j] = find_struct_type(&ctx, param->as.parameter.struct_type_name);
|
inner_ty = find_struct_type(&ctx, param->as.parameter.struct_type_name);
|
||||||
|
} else if (param->as.parameter.type == TYPE_ARRAY) {
|
||||||
|
LLVMTypeRef et = param->as.parameter.arr_elem_struct
|
||||||
|
? (find_struct_type(&ctx, param->as.parameter.arr_elem_struct) ?: LLVMInt64TypeInContext(ctx.context))
|
||||||
|
: to_llvm_type(&ctx, param->as.parameter.arr_elem_type);
|
||||||
|
inner_ty = LLVMArrayType(et, (unsigned)param->as.parameter.arr_size);
|
||||||
} else {
|
} else {
|
||||||
ptypes[j] = to_llvm_type(&ctx, param->as.parameter.type);
|
inner_ty = to_llvm_type(&ctx, param->as.parameter.type);
|
||||||
}
|
}
|
||||||
|
ptypes[j + poff] = is_out ? LLVMPointerType(inner_ty, 0) : inner_ty;
|
||||||
}
|
}
|
||||||
LLVMTypeRef ret_ty;
|
LLVMTypeRef ret_ty;
|
||||||
if (fn->as.function.return_type == TYPE_STRUCT &&
|
if (fn->as.function.return_type == TYPE_STRUCT &&
|
||||||
@@ -384,9 +434,9 @@ LLVMModuleRef codegen_module(AstNode* ast, Arena* codegen_arena,
|
|||||||
ret_ty = to_llvm_type(&ctx, fn->as.function.return_type);
|
ret_ty = to_llvm_type(&ctx, fn->as.function.return_type);
|
||||||
}
|
}
|
||||||
LLVMTypeRef fty = LLVMFunctionType(ret_ty,
|
LLVMTypeRef fty = LLVMFunctionType(ret_ty,
|
||||||
ptypes, (unsigned)fn->as.function.param_count, false);
|
ptypes, (unsigned)total_params, false);
|
||||||
LLVMValueRef lfn = LLVMAddFunction(ctx.module, fn->as.function.name, fty);
|
LLVMValueRef lfn = LLVMAddFunction(ctx.module, fn->as.function.name, fty);
|
||||||
add_fn(&ctx, fn->as.function.name, lfn);
|
add_fn(&ctx, fn->as.function.name, lfn, out_params, total_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 第二遍:生成函数体
|
// 第二遍:生成函数体
|
||||||
@@ -399,28 +449,66 @@ LLVMModuleRef codegen_module(AstNode* ast, Arena* codegen_arena,
|
|||||||
// 清空变量表(每个函数独立作用域)
|
// 清空变量表(每个函数独立作用域)
|
||||||
ctx.var_table = NULL;
|
ctx.var_table = NULL;
|
||||||
|
|
||||||
|
// 捕获变量: 第一个参数是 env_ptr, 通过 GEP 注册捕获变量
|
||||||
|
bool has_env = fn->as.function.cap_count > 0;
|
||||||
|
LLVMValueRef env_ptr = NULL;
|
||||||
|
size_t param_offset = 0;
|
||||||
|
if (has_env) {
|
||||||
|
env_ptr = LLVMGetParam(lfn, 0);
|
||||||
|
param_offset = 1;
|
||||||
|
// 生成 env struct 类型并注册捕获变量
|
||||||
|
LLVMTypeRef* ef = arena_alloc(ctx.arena,
|
||||||
|
fn->as.function.cap_count * sizeof(LLVMTypeRef));
|
||||||
|
for (size_t ci = 0; ci < fn->as.function.cap_count; ci++)
|
||||||
|
ef[ci] = to_llvm_type(&ctx, fn->as.function.cap_types[ci]);
|
||||||
|
LLVMTypeRef env_ty = LLVMStructTypeInContext(ctx.context, ef,
|
||||||
|
(unsigned)fn->as.function.cap_count, false);
|
||||||
|
LLVMValueRef typed_env = LLVMBuildBitCast(ctx.builder, env_ptr,
|
||||||
|
LLVMPointerType(env_ty, 0), "env_typed");
|
||||||
|
for (size_t ci = 0; ci < fn->as.function.cap_count; ci++) {
|
||||||
|
LLVMValueRef gep_idx[] = {
|
||||||
|
LLVMConstInt(LLVMInt32TypeInContext(ctx.context), 0, false),
|
||||||
|
LLVMConstInt(LLVMInt32TypeInContext(ctx.context), (unsigned)ci, false)
|
||||||
|
};
|
||||||
|
LLVMValueRef field_ptr = LLVMBuildGEP2(ctx.builder, env_ty,
|
||||||
|
typed_env, gep_idx, 2, "cap_ptr");
|
||||||
|
add_var(&ctx, fn->as.function.captured[ci], field_ptr,
|
||||||
|
to_llvm_type(&ctx, fn->as.function.cap_types[ci]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 将参数注册为变量
|
// 将参数注册为变量
|
||||||
for (size_t j = 0; j < fn->as.function.param_count; j++) {
|
for (size_t j = 0; j < fn->as.function.param_count; j++) {
|
||||||
LLVMValueRef param = LLVMGetParam(lfn, (unsigned)j);
|
LLVMValueRef param = LLVMGetParam(lfn, (unsigned)(j + param_offset));
|
||||||
AstNode* pnode = fn->as.function.params[j];
|
AstNode* pnode = fn->as.function.params[j];
|
||||||
LLVMTypeRef param_ty;
|
LLVMTypeRef param_ty;
|
||||||
if (pnode->as.parameter.type == TYPE_STRUCT &&
|
if (pnode->as.parameter.type == TYPE_STRUCT &&
|
||||||
pnode->as.parameter.struct_type_name) {
|
pnode->as.parameter.struct_type_name) {
|
||||||
param_ty = find_struct_type(&ctx, pnode->as.parameter.struct_type_name);
|
param_ty = find_struct_type(&ctx, pnode->as.parameter.struct_type_name);
|
||||||
|
} else if (pnode->as.parameter.type == TYPE_ARRAY) {
|
||||||
|
LLVMTypeRef et = pnode->as.parameter.arr_elem_struct
|
||||||
|
? (find_struct_type(&ctx, pnode->as.parameter.arr_elem_struct) ?: LLVMInt64TypeInContext(ctx.context))
|
||||||
|
: to_llvm_type(&ctx, pnode->as.parameter.arr_elem_type);
|
||||||
|
param_ty = LLVMArrayType(et, (unsigned)pnode->as.parameter.arr_size);
|
||||||
} else {
|
} else {
|
||||||
param_ty = to_llvm_type(&ctx, pnode->as.parameter.type);
|
param_ty = to_llvm_type(&ctx, pnode->as.parameter.type);
|
||||||
}
|
}
|
||||||
LLVMValueRef alloca = LLVMBuildAlloca(ctx.builder,
|
if (pnode->as.parameter.is_out) {
|
||||||
param_ty, pnode->as.parameter.name);
|
add_var(&ctx, pnode->as.parameter.name, param, param_ty);
|
||||||
LLVMBuildStore(ctx.builder, param, alloca);
|
} else {
|
||||||
add_var(&ctx, pnode->as.parameter.name, alloca, param_ty);
|
LLVMValueRef alloca = LLVMBuildAlloca(ctx.builder,
|
||||||
|
param_ty, pnode->as.parameter.name);
|
||||||
|
LLVMBuildStore(ctx.builder, param, alloca);
|
||||||
|
add_var(&ctx, pnode->as.parameter.name, alloca, param_ty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.defer_count = 0;
|
||||||
codegen_stmt(&ctx, fn->as.function.body);
|
codegen_stmt(&ctx, fn->as.function.body);
|
||||||
|
|
||||||
// 确保函数有终止指令(terminator)
|
// 确保函数有终止指令(terminator)
|
||||||
if (!LLVMGetBasicBlockTerminator(LLVMGetInsertBlock(ctx.builder))) {
|
if (!LLVMGetBasicBlockTerminator(LLVMGetInsertBlock(ctx.builder))) {
|
||||||
// 函数结尾隐式 return: 先释放所有 str 堆分配
|
emit_deferred(&ctx);
|
||||||
cleanup_emit(&ctx, 0);
|
cleanup_emit(&ctx, 0);
|
||||||
if (fn->as.function.return_type == TYPE_VOID)
|
if (fn->as.function.return_type == TYPE_VOID)
|
||||||
LLVMBuildRetVoid(ctx.builder);
|
LLVMBuildRetVoid(ctx.builder);
|
||||||
|
|||||||
@@ -15,11 +15,15 @@
|
|||||||
extern int codegen_depth;
|
extern int codegen_depth;
|
||||||
#define MAX_CODEGEN_DEPTH 1000
|
#define MAX_CODEGEN_DEPTH 1000
|
||||||
|
|
||||||
|
// AST program (由 sema 设置, codegen 读取)
|
||||||
|
extern AstNode* g_program;
|
||||||
|
|
||||||
// === 内部状态 ===
|
// === 内部状态 ===
|
||||||
typedef struct VarEntry {
|
typedef struct VarEntry {
|
||||||
const char* name;
|
const char* name;
|
||||||
LLVMValueRef alloca;
|
LLVMValueRef alloca;
|
||||||
LLVMTypeRef alloca_type;
|
LLVMTypeRef alloca_type;
|
||||||
|
const char* closure_fn; // 闭包对应的生成函数名
|
||||||
struct VarEntry* next;
|
struct VarEntry* next;
|
||||||
} VarEntry;
|
} VarEntry;
|
||||||
|
|
||||||
@@ -28,6 +32,7 @@ typedef struct FnEntry {
|
|||||||
LLVMValueRef fn;
|
LLVMValueRef fn;
|
||||||
TypeKind ret;
|
TypeKind ret;
|
||||||
TypeKind* params;
|
TypeKind* params;
|
||||||
|
bool* out_params; // 哪些参数是 out (引用传递)
|
||||||
size_t pc;
|
size_t pc;
|
||||||
struct FnEntry* next;
|
struct FnEntry* next;
|
||||||
} FnEntry;
|
} FnEntry;
|
||||||
@@ -57,6 +62,8 @@ typedef struct {
|
|||||||
LLVMValueRef* cleanup_list;
|
LLVMValueRef* cleanup_list;
|
||||||
size_t cleanup_count;
|
size_t cleanup_count;
|
||||||
size_t cleanup_cap;
|
size_t cleanup_cap;
|
||||||
|
AstNode* defer_exprs[64];
|
||||||
|
size_t defer_count;
|
||||||
} CgCtx;
|
} CgCtx;
|
||||||
|
|
||||||
// === 类型映射 ===
|
// === 类型映射 ===
|
||||||
@@ -67,9 +74,10 @@ LLVMValueRef coerce_int(CgCtx* ctx, LLVMValueRef val, LLVMTypeRef from_ty, LLVMT
|
|||||||
|
|
||||||
// === 表操作 ===
|
// === 表操作 ===
|
||||||
LLVMValueRef find_var(CgCtx* ctx, const char* name);
|
LLVMValueRef find_var(CgCtx* ctx, const char* name);
|
||||||
void add_var(CgCtx* ctx, const char* name, LLVMValueRef alloca, LLVMTypeRef alloca_type);
|
VarEntry* add_var(CgCtx* ctx, const char* name, LLVMValueRef alloca, LLVMTypeRef alloca_type);
|
||||||
LLVMValueRef find_fn(CgCtx* ctx, const char* name);
|
LLVMValueRef find_fn(CgCtx* ctx, const char* name);
|
||||||
void add_fn(CgCtx* ctx, const char* name, LLVMValueRef fn);
|
FnEntry* find_fn_entry(CgCtx* ctx, const char* name);
|
||||||
|
void add_fn(CgCtx* ctx, const char* name, LLVMValueRef fn, bool* out_params, size_t pc);
|
||||||
void add_struct_type(CgCtx* ctx, const char* name, LLVMTypeRef ty, size_t fc);
|
void add_struct_type(CgCtx* ctx, const char* name, LLVMTypeRef ty, size_t fc);
|
||||||
LLVMTypeRef find_struct_type(CgCtx* ctx, const char* name);
|
LLVMTypeRef find_struct_type(CgCtx* ctx, const char* name);
|
||||||
|
|
||||||
|
|||||||
+6
-3
@@ -57,17 +57,18 @@ static TokenKind check_keyword(const Token* tok) {
|
|||||||
KW("fn", TOK_FN); KW("let", TOK_LET);
|
KW("fn", TOK_FN); KW("let", TOK_LET);
|
||||||
KW("var", TOK_VAR);
|
KW("var", TOK_VAR);
|
||||||
KW("if", TOK_IF); KW("else", TOK_ELSE); KW("guard", TOK_GUARD);
|
KW("if", TOK_IF); KW("else", TOK_ELSE); KW("guard", TOK_GUARD);
|
||||||
|
KW("const", TOK_CONST);
|
||||||
KW("while", TOK_WHILE); KW("for", TOK_FOR); KW("in", TOK_IN);
|
KW("while", TOK_WHILE); KW("for", TOK_FOR); KW("in", TOK_IN);
|
||||||
KW("to", TOK_TO);
|
KW("to", TOK_TO); KW("step", TOK_STEP);
|
||||||
KW("return", TOK_RETURN);
|
KW("return", TOK_RETURN);
|
||||||
KW("i32", TOK_I32); KW("i64", TOK_I64);
|
KW("i32", TOK_I32); KW("i64", TOK_I64);
|
||||||
KW("u64", TOK_U64); KW("f64", TOK_F64);
|
KW("u64", TOK_U64); KW("f64", TOK_F64);
|
||||||
KW("bool", TOK_BOOL); KW("char", TOK_CHAR);
|
KW("bool", TOK_BOOL); KW("char", TOK_CHAR);
|
||||||
KW("str", TOK_STR); KW("void", TOK_VOID);
|
KW("str", TOK_STR); KW("void", TOK_VOID);
|
||||||
KW("struct", TOK_STRUCT); KW("type", TOK_TYPE);
|
KW("struct", TOK_STRUCT); KW("type", TOK_TYPE);
|
||||||
KW("enum", TOK_ENUM); KW("extend", TOK_EXTEND); KW("match", TOK_MATCH);
|
KW("enum", TOK_ENUM); KW("extend", TOK_EXTEND); KW("defer", TOK_DEFER); KW("match", TOK_MATCH);
|
||||||
KW("pub", TOK_PUB); KW("mod", TOK_MOD); KW("use", TOK_USE);
|
KW("pub", TOK_PUB); KW("mod", TOK_MOD); KW("use", TOK_USE);
|
||||||
KW("trait", TOK_TRAIT); KW("Self", TOK_SELF);
|
KW("trait", TOK_TRAIT); KW("Self", TOK_SELF); KW("out", TOK_OUT);
|
||||||
KW("_", TOK_UNDERSCORE);
|
KW("_", TOK_UNDERSCORE);
|
||||||
KW("true", TOK_TRUE); KW("false", TOK_FALSE);
|
KW("true", TOK_TRUE); KW("false", TOK_FALSE);
|
||||||
#undef KW
|
#undef KW
|
||||||
@@ -155,9 +156,11 @@ Token* lex(Arena* a, const char* source, const char* filename,
|
|||||||
else if (c == '&' && peek_next(&l) == '&') { tokens[idx++] = make_token(&l, TOK_AND_AND, l.pos, 2); advance(&l); advance(&l); }
|
else if (c == '&' && peek_next(&l) == '&') { tokens[idx++] = make_token(&l, TOK_AND_AND, l.pos, 2); advance(&l); advance(&l); }
|
||||||
else if (c == '|' && peek_next(&l) == '>') { tokens[idx++] = make_token(&l, TOK_PIPE, l.pos, 2); advance(&l); advance(&l); }
|
else if (c == '|' && peek_next(&l) == '>') { tokens[idx++] = make_token(&l, TOK_PIPE, l.pos, 2); advance(&l); advance(&l); }
|
||||||
else if (c == '|' && peek_next(&l) == '|') { tokens[idx++] = make_token(&l, TOK_PIPE_PIPE, l.pos, 2); advance(&l); advance(&l); }
|
else if (c == '|' && peek_next(&l) == '|') { tokens[idx++] = make_token(&l, TOK_PIPE_PIPE, l.pos, 2); advance(&l); advance(&l); }
|
||||||
|
else if (c == '?' && peek_next(&l) == '?') { tokens[idx++] = make_token(&l, TOK_QMARK_QMARK, l.pos, 2); advance(&l); advance(&l); }
|
||||||
else if (c == '.') { tokens[idx++] = make_token(&l, TOK_DOT, l.pos, 1); advance(&l); }
|
else if (c == '.') { tokens[idx++] = make_token(&l, TOK_DOT, l.pos, 1); advance(&l); }
|
||||||
else if (c == '[') { tokens[idx++] = make_token(&l, TOK_LBRACKET, l.pos, 1); advance(&l); }
|
else if (c == '[') { tokens[idx++] = make_token(&l, TOK_LBRACKET, l.pos, 1); advance(&l); }
|
||||||
else if (c == ']') { tokens[idx++] = make_token(&l, TOK_RBRACKET, l.pos, 1); advance(&l); }
|
else if (c == ']') { tokens[idx++] = make_token(&l, TOK_RBRACKET, l.pos, 1); advance(&l); }
|
||||||
|
else if (c == '#') { tokens[idx++] = make_token(&l, TOK_HASH, l.pos, 1); advance(&l); }
|
||||||
else if (c == '(') { tokens[idx++] = make_token(&l, TOK_LPAREN, l.pos, 1); advance(&l); }
|
else if (c == '(') { tokens[idx++] = make_token(&l, TOK_LPAREN, l.pos, 1); advance(&l); }
|
||||||
else if (c == ')') { tokens[idx++] = make_token(&l, TOK_RPAREN, l.pos, 1); advance(&l); }
|
else if (c == ')') { tokens[idx++] = make_token(&l, TOK_RPAREN, l.pos, 1); advance(&l); }
|
||||||
else if (c == '{') { tokens[idx++] = make_token(&l, TOK_LBRACE, l.pos, 1); advance(&l); }
|
else if (c == '{') { tokens[idx++] = make_token(&l, TOK_LBRACE, l.pos, 1); advance(&l); }
|
||||||
|
|||||||
+6
-5
@@ -5,12 +5,12 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
static const char* NAMES[] = {
|
static const char* NAMES[] = {
|
||||||
[TOK_FN] = "fn", [TOK_LET] = "let", [TOK_VAR] = "var", [TOK_IF] = "if", [TOK_GUARD] = "guard",
|
[TOK_FN] = "fn", [TOK_LET] = "let", [TOK_VAR] = "var", [TOK_CONST] = "const", [TOK_IF] = "if", [TOK_GUARD] = "guard",
|
||||||
[TOK_PUB] = "pub", [TOK_MOD] = "mod", [TOK_USE] = "use",
|
[TOK_PUB] = "pub", [TOK_MOD] = "mod", [TOK_USE] = "use",
|
||||||
[TOK_TRAIT] = "trait", [TOK_SELF] = "Self",
|
[TOK_TRAIT] = "trait", [TOK_SELF] = "Self", [TOK_OUT] = "out",
|
||||||
[TOK_ELSE] = "else", [TOK_WHILE] = "while", [TOK_FOR] = "for", [TOK_IN] = "in", [TOK_RETURN] = "return",
|
[TOK_ELSE] = "else", [TOK_WHILE] = "while", [TOK_FOR] = "for", [TOK_IN] = "in", [TOK_RETURN] = "return",
|
||||||
[TOK_STRUCT] = "struct", [TOK_TYPE] = "type", [TOK_ENUM] = "enum", [TOK_EXTEND] = "extend",
|
[TOK_STRUCT] = "struct", [TOK_TYPE] = "type", [TOK_ENUM] = "enum", [TOK_EXTEND] = "extend",
|
||||||
[TOK_MATCH] = "match",
|
[TOK_DEFER] = "defer", [TOK_MATCH] = "match",
|
||||||
[TOK_I32] = "i32", [TOK_I64] = "i64", [TOK_U64] = "u64", [TOK_F64] = "f64",
|
[TOK_I32] = "i32", [TOK_I64] = "i64", [TOK_U64] = "u64", [TOK_F64] = "f64",
|
||||||
[TOK_BOOL] = "bool", [TOK_CHAR] = "char", [TOK_STR] = "str", [TOK_VOID] = "void",
|
[TOK_BOOL] = "bool", [TOK_CHAR] = "char", [TOK_STR] = "str", [TOK_VOID] = "void",
|
||||||
[TOK_INT_LIT] = "整数", [TOK_FLOAT_LIT] = "浮点数",
|
[TOK_INT_LIT] = "整数", [TOK_FLOAT_LIT] = "浮点数",
|
||||||
@@ -22,14 +22,15 @@ static const char* NAMES[] = {
|
|||||||
[TOK_EQ_EQ] = "==", [TOK_BANG_EQ] = "!=",
|
[TOK_EQ_EQ] = "==", [TOK_BANG_EQ] = "!=",
|
||||||
[TOK_LT] = "<", [TOK_GT] = ">", [TOK_LT_EQ] = "<=", [TOK_GT_EQ] = ">=",
|
[TOK_LT] = "<", [TOK_GT] = ">", [TOK_LT_EQ] = "<=", [TOK_GT_EQ] = ">=",
|
||||||
[TOK_AND_AND] = "&&", [TOK_PIPE_PIPE] = "||", [TOK_PIPE] = "|>", [TOK_BANG] = "!",
|
[TOK_AND_AND] = "&&", [TOK_PIPE_PIPE] = "||", [TOK_PIPE] = "|>", [TOK_BANG] = "!",
|
||||||
[TOK_ARROW] = "->", [TOK_TO] = "to", [TOK_MATCH_ARROW] = "=>",
|
[TOK_ARROW] = "->", [TOK_TO] = "to", [TOK_STEP] = "step", [TOK_MATCH_ARROW] = "=>",
|
||||||
[TOK_PLUS_EQ] = "+=", [TOK_MINUS_EQ] = "-=", [TOK_STAR_EQ] = "*=", [TOK_SLASH_EQ] = "/=",
|
[TOK_PLUS_EQ] = "+=", [TOK_MINUS_EQ] = "-=", [TOK_STAR_EQ] = "*=", [TOK_SLASH_EQ] = "/=",
|
||||||
[TOK_LPAREN] = "(", [TOK_RPAREN] = ")",
|
[TOK_LPAREN] = "(", [TOK_RPAREN] = ")",
|
||||||
[TOK_LBRACE] = "{", [TOK_RBRACE] = "}",
|
[TOK_LBRACE] = "{", [TOK_RBRACE] = "}",
|
||||||
[TOK_LBRACKET] = "[", [TOK_RBRACKET] = "]",
|
[TOK_LBRACKET] = "[", [TOK_RBRACKET] = "]",
|
||||||
[TOK_COMMA] = ",", [TOK_COLON] = ":", [TOK_SEMICOLON] = ";",
|
[TOK_COMMA] = ",", [TOK_COLON] = ":", [TOK_SEMICOLON] = ";",
|
||||||
[TOK_ASSIGN] = "=",
|
[TOK_ASSIGN] = "=",
|
||||||
[TOK_DOT] = ".", [TOK_COLON_COLON] = "::",
|
[TOK_DOT] = ".", [TOK_COLON_COLON] = "::", [TOK_HASH] = "#",
|
||||||
|
[TOK_QMARK_QMARK] = "??",
|
||||||
[TOK_EOF] = "EOF", [TOK_ERROR] = "错误",
|
[TOK_EOF] = "EOF", [TOK_ERROR] = "错误",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -6,9 +6,9 @@
|
|||||||
// === Token 类型枚举 ===
|
// === Token 类型枚举 ===
|
||||||
typedef enum {
|
typedef enum {
|
||||||
// 关键字
|
// 关键字
|
||||||
TOK_FN, TOK_LET, TOK_VAR, TOK_IF, TOK_ELSE, TOK_WHILE, TOK_FOR, TOK_IN, TOK_RETURN, TOK_GUARD,
|
TOK_FN, TOK_LET, TOK_VAR, TOK_CONST, TOK_IF, TOK_ELSE, TOK_WHILE, TOK_FOR, TOK_IN, TOK_RETURN, TOK_GUARD,
|
||||||
TOK_STRUCT, TOK_TYPE, TOK_ENUM, TOK_EXTEND, TOK_MATCH, TOK_PUB, TOK_MOD, TOK_USE,
|
TOK_STRUCT, TOK_TYPE, TOK_ENUM, TOK_EXTEND, TOK_DEFER, TOK_MATCH, TOK_PUB, TOK_MOD, TOK_USE,
|
||||||
TOK_TRAIT, TOK_SELF,
|
TOK_TRAIT, TOK_SELF, TOK_OUT,
|
||||||
// 类型关键字
|
// 类型关键字
|
||||||
TOK_I32, TOK_I64, TOK_U64, TOK_F64, TOK_BOOL, TOK_CHAR, TOK_STR, TOK_VOID,
|
TOK_I32, TOK_I64, TOK_U64, TOK_F64, TOK_BOOL, TOK_CHAR, TOK_STR, TOK_VOID,
|
||||||
// 字面量
|
// 字面量
|
||||||
@@ -19,14 +19,14 @@ typedef enum {
|
|||||||
TOK_PLUS, TOK_MINUS, TOK_STAR, TOK_SLASH, TOK_PERCENT,
|
TOK_PLUS, TOK_MINUS, TOK_STAR, TOK_SLASH, TOK_PERCENT,
|
||||||
TOK_EQ_EQ, TOK_BANG_EQ, TOK_LT, TOK_GT, TOK_LT_EQ, TOK_GT_EQ,
|
TOK_EQ_EQ, TOK_BANG_EQ, TOK_LT, TOK_GT, TOK_LT_EQ, TOK_GT_EQ,
|
||||||
TOK_AND_AND, TOK_PIPE_PIPE, TOK_PIPE, TOK_BANG,
|
TOK_AND_AND, TOK_PIPE_PIPE, TOK_PIPE, TOK_BANG,
|
||||||
TOK_ARROW, TOK_TO, TOK_MATCH_ARROW,
|
TOK_ARROW, TOK_TO, TOK_STEP, TOK_MATCH_ARROW,
|
||||||
TOK_PLUS_EQ, TOK_MINUS_EQ, TOK_STAR_EQ, TOK_SLASH_EQ,
|
TOK_PLUS_EQ, TOK_MINUS_EQ, TOK_STAR_EQ, TOK_SLASH_EQ,
|
||||||
// 分隔符
|
// 分隔符
|
||||||
TOK_LPAREN, TOK_RPAREN, TOK_LBRACE, TOK_RBRACE,
|
TOK_LPAREN, TOK_RPAREN, TOK_LBRACE, TOK_RBRACE,
|
||||||
TOK_LBRACKET, TOK_RBRACKET,
|
TOK_LBRACKET, TOK_RBRACKET,
|
||||||
TOK_COMMA, TOK_COLON, TOK_SEMICOLON, TOK_ASSIGN,
|
TOK_COMMA, TOK_COLON, TOK_SEMICOLON, TOK_ASSIGN,
|
||||||
// 特殊
|
// 特殊
|
||||||
TOK_DOT, TOK_COLON_COLON,
|
TOK_DOT, TOK_COLON_COLON, TOK_HASH, TOK_QMARK_QMARK,
|
||||||
TOK_EOF, TOK_ERROR,
|
TOK_EOF, TOK_ERROR,
|
||||||
} TokenKind;
|
} TokenKind;
|
||||||
|
|
||||||
|
|||||||
@@ -39,25 +39,23 @@ AstNode* desugar_guard(Parser* p, const Token* guard_tok,
|
|||||||
return ast_make_if(p->arena, not_cond, body, NULL, tok_loc(guard_tok));
|
return ast_make_if(p->arena, not_cond, body, NULL, tok_loc(guard_tok));
|
||||||
}
|
}
|
||||||
|
|
||||||
// === for i in start to end { body } → { var i = start; while i < end { body; i = i + 1; } } ===
|
// === for i in start to end [step N] { body } → { var i=start; while i<end { body; i=i+step; } } ===
|
||||||
AstNode* desugar_for(Parser* p, const Token* for_tok,
|
AstNode* desugar_for(Parser* p, const Token* for_tok,
|
||||||
const char* var_name, AstNode* start_expr,
|
const char* var_name, AstNode* start_expr,
|
||||||
AstNode* end_expr, AstNode* body) {
|
AstNode* end_expr, AstNode* step_expr, AstNode* body) {
|
||||||
// var i = start;
|
|
||||||
AstNode* let_stmt = ast_make_let(p->arena, var_name, TYPE_UNKNOWN,
|
AstNode* let_stmt = ast_make_let(p->arena, var_name, TYPE_UNKNOWN,
|
||||||
false, true, start_expr, NULL, 0, NULL, 0, tok_loc(for_tok));
|
false, true, start_expr, NULL, 0, NULL, 0, tok_loc(for_tok));
|
||||||
|
|
||||||
// i < end
|
|
||||||
AstNode* cond = ast_make_binary(p->arena, OP_LT,
|
AstNode* cond = ast_make_binary(p->arena, OP_LT,
|
||||||
ast_make_ident(p->arena, var_name, tok_loc(for_tok)),
|
ast_make_ident(p->arena, var_name, tok_loc(for_tok)),
|
||||||
end_expr, tok_loc(for_tok));
|
end_expr, tok_loc(for_tok));
|
||||||
|
|
||||||
// i = i + 1
|
AstNode* step = step_expr ? step_expr
|
||||||
|
: ast_make_literal_i64(p->arena, 1, tok_loc(for_tok));
|
||||||
AstNode* incr = ast_make_assign(p->arena, var_name,
|
AstNode* incr = ast_make_assign(p->arena, var_name,
|
||||||
ast_make_binary(p->arena, OP_ADD,
|
ast_make_binary(p->arena, OP_ADD,
|
||||||
ast_make_ident(p->arena, var_name, tok_loc(for_tok)),
|
ast_make_ident(p->arena, var_name, tok_loc(for_tok)),
|
||||||
ast_make_literal_i64(p->arena, 1, tok_loc(for_tok)),
|
step, tok_loc(for_tok)),
|
||||||
tok_loc(for_tok)),
|
|
||||||
tok_loc(for_tok));
|
tok_loc(for_tok));
|
||||||
|
|
||||||
// 增量追加到循环体末尾
|
// 增量追加到循环体末尾
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ AstNode* desugar_match(Parser* p, const Token* match_tok,
|
|||||||
AstNode* desugar_guard(Parser* p, const Token* guard_tok,
|
AstNode* desugar_guard(Parser* p, const Token* guard_tok,
|
||||||
AstNode* cond, AstNode* body);
|
AstNode* cond, AstNode* body);
|
||||||
|
|
||||||
// for i in start to end { body } → { var i = start; while i < end { body; i = i + 1; } }
|
// for i in start to end [step N] { body } → { var i=start; while i<end { body; i=i+step; } }
|
||||||
AstNode* desugar_for(Parser* p, const Token* for_tok,
|
AstNode* desugar_for(Parser* p, const Token* for_tok,
|
||||||
const char* var_name, AstNode* start_expr,
|
const char* var_name, AstNode* start_expr,
|
||||||
AstNode* end_expr, AstNode* body);
|
AstNode* end_expr, AstNode* step_expr, AstNode* body);
|
||||||
|
|
||||||
// if let pattern = expr { then } else { else } → { let __match = expr; if __match == pattern ... }
|
// if let pattern = expr { then } else { else } → { let __match = expr; if __match == pattern ... }
|
||||||
AstNode* desugar_if_let(Parser* p, const Token* if_tok,
|
AstNode* desugar_if_let(Parser* p, const Token* if_tok,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ int parse_depth = 0;
|
|||||||
// === 运算符优先级 → Precedence 映射 ===
|
// === 运算符优先级 → Precedence 映射 ===
|
||||||
Precedence tok_to_prec(TokenKind kind) {
|
Precedence tok_to_prec(TokenKind kind) {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
|
case TOK_QMARK_QMARK: return PREC_COALESCE;
|
||||||
case TOK_PIPE_PIPE: return PREC_OR;
|
case TOK_PIPE_PIPE: return PREC_OR;
|
||||||
case TOK_AND_AND: return PREC_AND;
|
case TOK_AND_AND: return PREC_AND;
|
||||||
case TOK_EQ_EQ: case TOK_BANG_EQ:
|
case TOK_EQ_EQ: case TOK_BANG_EQ:
|
||||||
@@ -306,6 +307,55 @@ AstNode* parse_expr_prec(Parser* p, Precedence min_prec, ErrorInfo* error) {
|
|||||||
}
|
}
|
||||||
left = ast_make_if(p->arena, cond, then_block, else_block, tok_loc(if_tok));
|
left = ast_make_if(p->arena, cond, then_block, else_block, tok_loc(if_tok));
|
||||||
}
|
}
|
||||||
|
} else if (tok->kind == TOK_LBRACKET && (tok + 1)->kind == TOK_FOR) {
|
||||||
|
// 列表推导式: [for var in expr: body]
|
||||||
|
advance(p); advance(p); // 跳过 '[' 和 'for'
|
||||||
|
const Token* vname = expect(p, TOK_IDENT, error, "for 后应为变量名");
|
||||||
|
if (!vname) return NULL;
|
||||||
|
if (!expect(p, TOK_IN, error, "缺少 'in'")) return NULL;
|
||||||
|
AstNode* arr = parse_expr(p, error);
|
||||||
|
if (!arr) return NULL;
|
||||||
|
if (!expect(p, TOK_COLON, error, "缺少 ':'")) return NULL;
|
||||||
|
AstNode* body = parse_expr(p, error);
|
||||||
|
if (!body) return NULL;
|
||||||
|
if (!expect(p, TOK_RBRACKET, error, "缺少 ']'")) return NULL;
|
||||||
|
left = ast_make_list_comp(p->arena,
|
||||||
|
arena_strdup_impl(p->arena, vname->start, vname->length),
|
||||||
|
arr, body, tok_loc(tok));
|
||||||
|
} else if (tok->kind == TOK_FN) {
|
||||||
|
// lambda: fn(params) -> RetType { body }
|
||||||
|
const Token* fn_tok = advance(p); // 跳过 fn
|
||||||
|
// 泛型参数暂不支持(lambda用捕获替代)
|
||||||
|
if (!expect(p, TOK_LPAREN, error, "缺少 '('")) return NULL;
|
||||||
|
AstNode* plist[64]; int pc = 0;
|
||||||
|
while (peek(p)->kind != TOK_RPAREN && !error->message) {
|
||||||
|
if (pc >= 64) { error->message = "lambda 参数过多(最多64)"; error->filename = p->filename; error->line = peek(p)->line; error->col = peek(p)->col; return NULL; }
|
||||||
|
bool is_out = match(p, TOK_OUT);
|
||||||
|
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;
|
||||||
|
plist[pc++] = ast_make_parameter(p->arena,
|
||||||
|
arena_strdup_impl(p->arena, pname->start, pname->length),
|
||||||
|
pti.kind, pti.struct_name, is_out,
|
||||||
|
pti.element_type, pti.element_struct_name, pti.array_size,
|
||||||
|
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_sn = NULL;
|
||||||
|
if (match(p, TOK_ARROW)) {
|
||||||
|
TypeInfo rti = parse_type_expr(p, error);
|
||||||
|
if (rti.kind == TYPE_ERROR) return NULL;
|
||||||
|
ret = rti.kind; ret_sn = rti.struct_name;
|
||||||
|
}
|
||||||
|
AstNode* body = parse_block(p, error);
|
||||||
|
if (!body) return NULL;
|
||||||
|
AstNode** parr = arena_alloc_impl(p->arena, pc * sizeof(AstNode*));
|
||||||
|
memcpy(parr, plist, pc * sizeof(AstNode*));
|
||||||
|
left = ast_make_lambda(p->arena, parr, pc, ret, ret_sn, body, tok_loc(fn_tok));
|
||||||
} else if (tok->kind == TOK_MINUS || tok->kind == TOK_BANG) {
|
} else if (tok->kind == TOK_MINUS || tok->kind == TOK_BANG) {
|
||||||
left = parse_unary(p, error);
|
left = parse_unary(p, error);
|
||||||
} else if (tok->kind == TOK_LPAREN) {
|
} else if (tok->kind == TOK_LPAREN) {
|
||||||
@@ -404,6 +454,24 @@ AstNode* parse_expr_prec(Parser* p, Precedence min_prec, ErrorInfo* error) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ?? 空值合并: a ?? b → if a != 0 { a; } else { b; }
|
||||||
|
if (kind == TOK_QMARK_QMARK) {
|
||||||
|
if (PREC_COALESCE <= min_prec) break;
|
||||||
|
advance(p);
|
||||||
|
AstNode* right = parse_expr_prec(p, PREC_COALESCE, error);
|
||||||
|
if (!right) return NULL;
|
||||||
|
AstNode* cond = ast_make_binary(p->arena, OP_NE, left,
|
||||||
|
ast_make_literal_i64(p->arena, 0, left->loc), left->loc);
|
||||||
|
AstNode** t_arr = (AstNode**)arena_alloc_impl(p->arena, sizeof(AstNode*));
|
||||||
|
t_arr[0] = ast_make_expr_stmt(p->arena, left, left->loc);
|
||||||
|
AstNode* then_block = ast_make_block(p->arena, t_arr, 1, left->loc);
|
||||||
|
AstNode** e_arr = (AstNode**)arena_alloc_impl(p->arena, sizeof(AstNode*));
|
||||||
|
e_arr[0] = ast_make_expr_stmt(p->arena, right, right->loc);
|
||||||
|
AstNode* else_block = ast_make_block(p->arena, e_arr, 1, right->loc);
|
||||||
|
left = ast_make_if(p->arena, cond, then_block, else_block, left->loc);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// 中缀运算符
|
// 中缀运算符
|
||||||
Precedence prec = tok_to_prec(kind);
|
Precedence prec = tok_to_prec(kind);
|
||||||
if (prec <= min_prec) break;
|
if (prec <= min_prec) break;
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ static inline const Token* expect(Parser* p, TokenKind k, ErrorInfo* e, const ch
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
PREC_NONE = 0,
|
PREC_NONE = 0,
|
||||||
PREC_PIPE = 10,
|
PREC_PIPE = 10,
|
||||||
|
PREC_COALESCE = 15,
|
||||||
PREC_OR = 20,
|
PREC_OR = 20,
|
||||||
PREC_AND = 30,
|
PREC_AND = 30,
|
||||||
PREC_COMPARE = 40,
|
PREC_COMPARE = 40,
|
||||||
|
|||||||
+149
-16
@@ -4,6 +4,9 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// 当前解析的函数的多返回值 struct 名 (用于 return 语句)
|
||||||
|
static const char* current_multi_ret_name = NULL;
|
||||||
|
|
||||||
// === 结构体声明解析 ===
|
// === 结构体声明解析 ===
|
||||||
AstNode* parse_struct_decl(Parser* p, ErrorInfo* error) {
|
AstNode* parse_struct_decl(Parser* p, ErrorInfo* error) {
|
||||||
const Token* s_tok = advance(p); // 跳过 'struct'
|
const Token* s_tok = advance(p); // 跳过 'struct'
|
||||||
@@ -24,7 +27,9 @@ AstNode* parse_struct_decl(Parser* p, ErrorInfo* error) {
|
|||||||
}
|
}
|
||||||
fields[fcount++] = ast_make_parameter(p->arena,
|
fields[fcount++] = ast_make_parameter(p->arena,
|
||||||
arena_strdup_impl(p->arena, fname->start, fname->length),
|
arena_strdup_impl(p->arena, fname->start, fname->length),
|
||||||
fti.kind, fti.struct_name, tok_loc(fname));
|
fti.kind, fti.struct_name, false,
|
||||||
|
fti.element_type, fti.element_struct_name, fti.array_size,
|
||||||
|
tok_loc(fname));
|
||||||
if (peek(p)->kind == TOK_COMMA) advance(p);
|
if (peek(p)->kind == TOK_COMMA) advance(p);
|
||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
@@ -115,10 +120,11 @@ AstNode* parse_block(Parser* p, ErrorInfo* error) {
|
|||||||
AstNode* parse_statement(Parser* p, ErrorInfo* error) {
|
AstNode* parse_statement(Parser* p, ErrorInfo* error) {
|
||||||
const Token* t = peek(p);
|
const Token* t = peek(p);
|
||||||
|
|
||||||
if (t->kind == TOK_LET || t->kind == TOK_VAR) {
|
if (t->kind == TOK_LET || t->kind == TOK_VAR || t->kind == TOK_CONST) {
|
||||||
bool is_mut = (advance(p)->kind == TOK_VAR);
|
TokenKind decl_kind = advance(p)->kind;
|
||||||
const Token* name = expect(p, TOK_IDENT, error,
|
bool is_mut = (decl_kind == TOK_VAR);
|
||||||
is_mut ? "var 后应为变量名" : "let 后应为变量名");
|
bool is_const = (decl_kind == TOK_CONST);
|
||||||
|
const Token* name = expect(p, TOK_IDENT, error, "变量名");
|
||||||
if (!name) return NULL;
|
if (!name) return NULL;
|
||||||
// 可选的类型标注
|
// 可选的类型标注
|
||||||
TypeKind annot_type = TYPE_UNKNOWN;
|
TypeKind annot_type = TYPE_UNKNOWN;
|
||||||
@@ -141,10 +147,12 @@ AstNode* parse_statement(Parser* p, ErrorInfo* error) {
|
|||||||
AstNode* init = parse_expr(p, error);
|
AstNode* init = parse_expr(p, error);
|
||||||
if (!init) return NULL;
|
if (!init) return NULL;
|
||||||
if (!expect(p, TOK_SEMICOLON, error, "缺少 ';'")) return NULL;
|
if (!expect(p, TOK_SEMICOLON, error, "缺少 ';'")) return NULL;
|
||||||
return ast_make_let(p->arena,
|
AstNode* let_node = ast_make_let(p->arena,
|
||||||
arena_strdup_impl(p->arena, name->start, name->length),
|
arena_strdup_impl(p->arena, name->start, name->length),
|
||||||
annot_type, has_type_annot, is_mut, init, struct_type_name,
|
annot_type, has_type_annot, is_mut, init, struct_type_name,
|
||||||
annot_elem_type, annot_elem_struct, annot_arr_size, tok_loc(t));
|
annot_elem_type, annot_elem_struct, annot_arr_size, tok_loc(t));
|
||||||
|
let_node->as.let_stmt.is_const = is_const;
|
||||||
|
return let_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->kind == TOK_IF) {
|
if (t->kind == TOK_IF) {
|
||||||
@@ -173,10 +181,16 @@ AstNode* parse_statement(Parser* p, ErrorInfo* error) {
|
|||||||
if (!expect(p, TOK_TO, error, "缺少 'to'")) return NULL;
|
if (!expect(p, TOK_TO, error, "缺少 'to'")) return NULL;
|
||||||
AstNode* end_expr = parse_expr(p, error);
|
AstNode* end_expr = parse_expr(p, error);
|
||||||
if (!end_expr) return NULL;
|
if (!end_expr) return NULL;
|
||||||
|
AstNode* step_expr = NULL;
|
||||||
|
if (peek(p)->kind == TOK_STEP) {
|
||||||
|
advance(p);
|
||||||
|
step_expr = parse_expr(p, error);
|
||||||
|
if (!step_expr) return NULL;
|
||||||
|
}
|
||||||
AstNode* body = parse_block(p, error);
|
AstNode* body = parse_block(p, error);
|
||||||
if (!body) return NULL;
|
if (!body) return NULL;
|
||||||
const char* vname = arena_strdup_impl(p->arena, var_name->start, var_name->length);
|
const char* vname = arena_strdup_impl(p->arena, var_name->start, var_name->length);
|
||||||
return desugar_for(p, t, vname, start_expr, end_expr, body);
|
return desugar_for(p, t, vname, start_expr, end_expr, step_expr, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->kind == TOK_MATCH) {
|
if (t->kind == TOK_MATCH) {
|
||||||
@@ -195,8 +209,30 @@ AstNode* parse_statement(Parser* p, ErrorInfo* error) {
|
|||||||
|
|
||||||
if (t->kind == TOK_RETURN) {
|
if (t->kind == TOK_RETURN) {
|
||||||
advance(p);
|
advance(p);
|
||||||
if (match(p, TOK_SEMICOLON)) {
|
if (match(p, TOK_SEMICOLON))
|
||||||
return ast_make_return(p->arena, NULL, tok_loc(t));
|
return ast_make_return(p->arena, NULL, tok_loc(t));
|
||||||
|
// 多返回值: return (e1, e2, ...)
|
||||||
|
if (current_multi_ret_name && peek(p)->kind == TOK_LPAREN) {
|
||||||
|
advance(p); // 跳过 '('
|
||||||
|
AstNode* vals[8]; int vcount = 0;
|
||||||
|
while (peek(p)->kind != TOK_RPAREN && !error->message) {
|
||||||
|
if (vcount >= 8) { error->message = "返回表达式过多(最多8)"; error->filename = p->filename; error->line = peek(p)->line; error->col = peek(p)->col; return NULL; }
|
||||||
|
vals[vcount++] = parse_expr(p, error);
|
||||||
|
if (!vals[vcount-1]) return NULL;
|
||||||
|
if (peek(p)->kind == TOK_COMMA) advance(p); else break;
|
||||||
|
}
|
||||||
|
if (!expect(p, TOK_RPAREN, error, "缺少 ')'")) return NULL;
|
||||||
|
if (!expect(p, TOK_SEMICOLON, error, "缺少 ';'")) return NULL;
|
||||||
|
// 创建 struct init: __ret_funcname { _0: v0, _1: v1, ... }
|
||||||
|
const char** fnames = arena_alloc_impl(p->arena, vcount * sizeof(const char*));
|
||||||
|
for (int i = 0; i < vcount; i++) {
|
||||||
|
char fbuf[4]; snprintf(fbuf, sizeof(fbuf), "_%d", i);
|
||||||
|
fnames[i] = arena_strdup_impl(p->arena, fbuf, strlen(fbuf));
|
||||||
|
}
|
||||||
|
AstNode** varr = arena_alloc_impl(p->arena, vcount * sizeof(AstNode*));
|
||||||
|
memcpy(varr, vals, vcount * sizeof(AstNode*));
|
||||||
|
AstNode* init = ast_make_struct_init(p->arena, current_multi_ret_name, fnames, varr, vcount, tok_loc(t));
|
||||||
|
return ast_make_return(p->arena, init, tok_loc(t));
|
||||||
}
|
}
|
||||||
AstNode* expr = parse_expr(p, error);
|
AstNode* expr = parse_expr(p, error);
|
||||||
if (!expr) return NULL;
|
if (!expr) return NULL;
|
||||||
@@ -204,6 +240,27 @@ AstNode* parse_statement(Parser* p, ErrorInfo* error) {
|
|||||||
return ast_make_return(p->arena, expr, tok_loc(t));
|
return ast_make_return(p->arena, expr, tok_loc(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (t->kind == TOK_DEFER) {
|
||||||
|
advance(p);
|
||||||
|
AstNode* body;
|
||||||
|
if (peek(p)->kind == TOK_LBRACE) {
|
||||||
|
body = parse_block(p, error);
|
||||||
|
} else {
|
||||||
|
AstNode* expr = parse_expr(p, error);
|
||||||
|
if (!expr) return NULL;
|
||||||
|
if (!expect(p, TOK_SEMICOLON, error, "缺少 ';'")) return NULL;
|
||||||
|
body = ast_make_block(p->arena,
|
||||||
|
arena_alloc_impl(p->arena, sizeof(AstNode*)),
|
||||||
|
0, tok_loc(t));
|
||||||
|
AstNode** stmts = arena_alloc_impl(p->arena, sizeof(AstNode*));
|
||||||
|
stmts[0] = ast_make_expr_stmt(p->arena, expr, tok_loc(t));
|
||||||
|
body->as.block.stmts = stmts;
|
||||||
|
body->as.block.stmt_count = 1;
|
||||||
|
}
|
||||||
|
if (!body) return NULL;
|
||||||
|
return ast_make_defer_stmt(p->arena, body, tok_loc(t));
|
||||||
|
}
|
||||||
|
|
||||||
// 数组元素赋值: ident[expr] = expr ;
|
// 数组元素赋值: ident[expr] = expr ;
|
||||||
if (t->kind == TOK_IDENT && (t + 1)->kind == TOK_LBRACKET) {
|
if (t->kind == TOK_IDENT && (t + 1)->kind == TOK_LBRACKET) {
|
||||||
int ahead_idx = 2;
|
int ahead_idx = 2;
|
||||||
@@ -293,6 +350,7 @@ AstNode* parse_function(Parser* p, bool is_pub, ErrorInfo* error) {
|
|||||||
AstNode* params[64]; int pcount = 0;
|
AstNode* params[64]; int pcount = 0;
|
||||||
while (peek(p)->kind != TOK_RPAREN && !error->message) {
|
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; }
|
if (pcount >= 64) { error->message = "函数参数过多 (最多64)"; error->filename = p->filename; error->line = peek(p)->line; error->col = peek(p)->col; return NULL; }
|
||||||
|
bool is_out = match(p, TOK_OUT);
|
||||||
const Token* pname = expect(p, TOK_IDENT, error, "参数名");
|
const Token* pname = expect(p, TOK_IDENT, error, "参数名");
|
||||||
if (!pname) return NULL;
|
if (!pname) return NULL;
|
||||||
if (!expect(p, TOK_COLON, error, "缺少 ':'")) return NULL;
|
if (!expect(p, TOK_COLON, error, "缺少 ':'")) return NULL;
|
||||||
@@ -300,28 +358,71 @@ AstNode* parse_function(Parser* p, bool is_pub, ErrorInfo* error) {
|
|||||||
if (pti.kind == TYPE_ERROR) return NULL;
|
if (pti.kind == TYPE_ERROR) return NULL;
|
||||||
params[pcount++] = ast_make_parameter(p->arena,
|
params[pcount++] = ast_make_parameter(p->arena,
|
||||||
arena_strdup_impl(p->arena, pname->start, pname->length),
|
arena_strdup_impl(p->arena, pname->start, pname->length),
|
||||||
pti.kind, pti.struct_name, tok_loc(pname));
|
pti.kind, pti.struct_name, is_out,
|
||||||
|
pti.element_type, pti.element_struct_name, pti.array_size,
|
||||||
|
tok_loc(pname));
|
||||||
if (match(p, TOK_COMMA)) continue;
|
if (match(p, TOK_COMMA)) continue;
|
||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
if (!expect(p, TOK_RPAREN, error, "缺少 ')'")) return NULL;
|
if (!expect(p, TOK_RPAREN, error, "缺少 ')'")) return NULL;
|
||||||
|
|
||||||
|
// 多返回值
|
||||||
|
TypeKind* multi_ret_types = NULL;
|
||||||
|
const char** multi_ret_snames = NULL;
|
||||||
|
size_t multi_ret_count = 0;
|
||||||
// 返回类型
|
// 返回类型
|
||||||
TypeKind ret = TYPE_VOID;
|
TypeKind ret = TYPE_VOID;
|
||||||
const char* ret_struct_name = NULL;
|
const char* ret_struct_name = NULL;
|
||||||
if (match(p, TOK_ARROW)) {
|
if (match(p, TOK_ARROW)) {
|
||||||
TypeInfo rti = parse_type_expr(p, error);
|
// 多返回值: -> (T1, T2, ...)
|
||||||
if (rti.kind == TYPE_ERROR) return NULL;
|
if (peek(p)->kind == TOK_LPAREN) {
|
||||||
ret = rti.kind;
|
advance(p); // 跳过 '('
|
||||||
ret_struct_name = rti.struct_name;
|
TypeKind ttypes[8]; const char* tstructs[8]; int tcount = 0;
|
||||||
|
while (peek(p)->kind != TOK_RPAREN && !error->message) {
|
||||||
|
if (tcount >= 8) { error->message = "返回类型过多(最多8)"; error->filename = p->filename; error->line = peek(p)->line; error->col = peek(p)->col; return NULL; }
|
||||||
|
TypeInfo ti = parse_type_expr(p, error);
|
||||||
|
if (ti.kind == TYPE_ERROR) return NULL;
|
||||||
|
ttypes[tcount] = ti.kind;
|
||||||
|
tstructs[tcount] = ti.struct_name;
|
||||||
|
tcount++;
|
||||||
|
if (peek(p)->kind == TOK_COMMA) advance(p); else break;
|
||||||
|
}
|
||||||
|
if (!expect(p, TOK_RPAREN, error, "缺少 ')'")) return NULL;
|
||||||
|
if (tcount == 0) { error->message = "返回元组不能为空"; error->filename = p->filename; return NULL; }
|
||||||
|
if (tcount == 1) {
|
||||||
|
ret = ttypes[0]; ret_struct_name = tstructs[0];
|
||||||
|
} else {
|
||||||
|
// 生成隐式 struct 名: __ret_<funcname>
|
||||||
|
size_t nlen = name->length;
|
||||||
|
char* sname = arena_alloc_impl(p->arena, nlen + 7);
|
||||||
|
memcpy(sname, "__ret_", 6);
|
||||||
|
memcpy(sname + 6, name->start, nlen);
|
||||||
|
sname[nlen + 6] = '\0';
|
||||||
|
ret_struct_name = sname;
|
||||||
|
ret = TYPE_STRUCT;
|
||||||
|
// 暂存多返回类型, parse() 中创建隐式 struct
|
||||||
|
multi_ret_types = arena_alloc_impl(p->arena, tcount * sizeof(TypeKind));
|
||||||
|
memcpy(multi_ret_types, ttypes, tcount * sizeof(TypeKind));
|
||||||
|
multi_ret_snames = arena_alloc_impl(p->arena, tcount * sizeof(const char*));
|
||||||
|
memcpy(multi_ret_snames, tstructs, tcount * sizeof(const char*));
|
||||||
|
multi_ret_count = tcount;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TypeInfo rti = parse_type_expr(p, error);
|
||||||
|
if (rti.kind == TYPE_ERROR) return NULL;
|
||||||
|
ret = rti.kind;
|
||||||
|
ret_struct_name = rti.struct_name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// trait 方法签名或普通函数体
|
// trait 方法签名或普通函数体
|
||||||
AstNode* body = NULL;
|
AstNode* body = NULL;
|
||||||
if (match(p, TOK_SEMICOLON)) {
|
if (match(p, TOK_SEMICOLON)) {
|
||||||
body = NULL; // trait 方法签名,无实现
|
body = NULL;
|
||||||
} else {
|
} else {
|
||||||
|
current_multi_ret_name = (multi_ret_count > 0) ? ret_struct_name : NULL;
|
||||||
body = parse_block(p, error);
|
body = parse_block(p, error);
|
||||||
|
current_multi_ret_name = NULL;
|
||||||
if (!body) return NULL;
|
if (!body) return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,9 +433,15 @@ AstNode* parse_function(Parser* p, bool is_pub, ErrorInfo* error) {
|
|||||||
tparr = arena_alloc_impl(p->arena, tp_count * sizeof(const char*));
|
tparr = arena_alloc_impl(p->arena, tp_count * sizeof(const char*));
|
||||||
memcpy(tparr, type_params, tp_count * sizeof(const char*));
|
memcpy(tparr, type_params, tp_count * sizeof(const char*));
|
||||||
}
|
}
|
||||||
return ast_make_function(p->arena,
|
AstNode* fn = ast_make_function(p->arena,
|
||||||
arena_strdup_impl(p->arena, name->start, name->length),
|
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));
|
parr, pcount, ret, ret_struct_name, body, is_pub, tparr, tp_count, tok_loc(fn_tok));
|
||||||
|
if (multi_ret_count > 0) {
|
||||||
|
fn->as.function.multi_ret_types = multi_ret_types;
|
||||||
|
fn->as.function.multi_ret_snames = multi_ret_snames;
|
||||||
|
fn->as.function.multi_ret_count = multi_ret_count;
|
||||||
|
}
|
||||||
|
return fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
// === 模块文件加载 ===
|
// === 模块文件加载 ===
|
||||||
@@ -381,6 +488,7 @@ AstNode* parse(Arena* a, const Token* tokens, size_t count,
|
|||||||
const char* filename, ErrorInfo* error) {
|
const char* filename, ErrorInfo* error) {
|
||||||
Parser p = {.tokens = tokens, .count = count, .pos = 0,
|
Parser p = {.tokens = tokens, .count = count, .pos = 0,
|
||||||
.filename = filename, .arena = a};
|
.filename = filename, .arena = a};
|
||||||
|
current_multi_ret_name = NULL;
|
||||||
AstNode* functions[256]; int fn_count = 0;
|
AstNode* functions[256]; int fn_count = 0;
|
||||||
AstNode* structs[64]; int struct_count = 0;
|
AstNode* structs[64]; int struct_count = 0;
|
||||||
AstNode* aliases[64]; int alias_count = 0;
|
AstNode* aliases[64]; int alias_count = 0;
|
||||||
@@ -392,6 +500,13 @@ AstNode* parse(Arena* a, const Token* tokens, size_t count,
|
|||||||
if (peek(&p)->kind == TOK_PUB) {
|
if (peek(&p)->kind == TOK_PUB) {
|
||||||
is_pub = true; advance(&p);
|
is_pub = true; advance(&p);
|
||||||
}
|
}
|
||||||
|
// 装饰器 #[attr]
|
||||||
|
while (peek(&p)->kind == TOK_HASH) {
|
||||||
|
advance(&p); // 跳过 #
|
||||||
|
if (!expect(&p, TOK_LBRACKET, error, "# 后应为 '['")) return NULL;
|
||||||
|
if (!expect(&p, TOK_IDENT, error, "装饰器名")) return NULL;
|
||||||
|
if (!expect(&p, TOK_RBRACKET, error, "缺少 ']'")) return NULL;
|
||||||
|
}
|
||||||
if (peek(&p)->kind == TOK_TRAIT) {
|
if (peek(&p)->kind == TOK_TRAIT) {
|
||||||
const Token* tt = advance(&p);
|
const Token* tt = advance(&p);
|
||||||
const Token* tname = expect(&p, TOK_IDENT, error, "trait 后应为接口名");
|
const Token* tname = expect(&p, TOK_IDENT, error, "trait 后应为接口名");
|
||||||
@@ -577,7 +692,25 @@ AstNode* parse(Arena* a, const Token* tokens, size_t count,
|
|||||||
}
|
}
|
||||||
} else if (peek(&p)->kind == TOK_FN) {
|
} 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; }
|
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);
|
AstNode* fn = parse_function(&p, is_pub, error);
|
||||||
|
if (!fn) return NULL;
|
||||||
|
// 多返回值: 注册隐式 struct
|
||||||
|
if (fn->as.function.multi_ret_count > 0) {
|
||||||
|
size_t mc = fn->as.function.multi_ret_count;
|
||||||
|
AstNode** flds = arena_alloc_impl(p.arena, mc * sizeof(AstNode*));
|
||||||
|
for (size_t i = 0; i < mc; i++) {
|
||||||
|
char fbuf[4]; snprintf(fbuf, sizeof(fbuf), "_%zu", i);
|
||||||
|
flds[i] = ast_make_parameter(p.arena,
|
||||||
|
arena_strdup_impl(p.arena, fbuf, strlen(fbuf)),
|
||||||
|
fn->as.function.multi_ret_types[i],
|
||||||
|
fn->as.function.multi_ret_snames[i],
|
||||||
|
false, 0, NULL, 0, tok_loc(peek(&p)));
|
||||||
|
}
|
||||||
|
if (struct_count >= 64) { error->message = "结构体过多"; return NULL; }
|
||||||
|
structs[struct_count++] = ast_make_struct_decl(p.arena,
|
||||||
|
fn->as.function.return_struct_type_name, flds, mc, fn->loc);
|
||||||
|
}
|
||||||
|
functions[fn_count++] = fn;
|
||||||
} else {
|
} else {
|
||||||
error->message = "顶层只允许 fn、struct、type、enum、extend、mod 或 use";
|
error->message = "顶层只允许 fn、struct、type、enum、extend、mod 或 use";
|
||||||
error->filename = p.filename;
|
error->filename = p.filename;
|
||||||
|
|||||||
@@ -95,3 +95,7 @@ AstNode* mono_queue[256];
|
|||||||
size_t mono_count = 0;
|
size_t mono_count = 0;
|
||||||
Arena* mono_arena = NULL;
|
Arena* mono_arena = NULL;
|
||||||
AstNode* g_program = NULL; // 当前 AST_PROGRAM(用于查找泛型函数模板)
|
AstNode* g_program = NULL; // 当前 AST_PROGRAM(用于查找泛型函数模板)
|
||||||
|
|
||||||
|
// lambda 队列: 分析时创建的闭包函数
|
||||||
|
AstNode* lambda_queue[256];
|
||||||
|
size_t lambda_count = 0;
|
||||||
|
|||||||
+44
-4
@@ -159,7 +159,13 @@ void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
|||||||
Scope* fn_scope = scope_new(a, scope);
|
Scope* fn_scope = scope_new(a, scope);
|
||||||
for (size_t j = 0; j < mono_fn->as.function.param_count; j++) {
|
for (size_t j = 0; j < mono_fn->as.function.param_count; j++) {
|
||||||
AstNode* p = mono_fn->as.function.params[j];
|
AstNode* p = mono_fn->as.function.params[j];
|
||||||
scope_insert(fn_scope, a, p->as.parameter.name, SYM_PARAMETER, p->as.parameter.type);
|
Symbol* ps = scope_insert(fn_scope, a, p->as.parameter.name, SYM_PARAMETER, p->as.parameter.type);
|
||||||
|
if (ps && p->as.parameter.is_out) { ps->kind = SYM_VARIABLE; ps->is_mut = true; }
|
||||||
|
if (ps && p->as.parameter.type == TYPE_ARRAY) {
|
||||||
|
ps->array_element_type = p->as.parameter.arr_elem_type;
|
||||||
|
ps->array_element_struct_name = p->as.parameter.arr_elem_struct;
|
||||||
|
ps->array_size = p->as.parameter.arr_size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 分析函数体
|
// 分析函数体
|
||||||
current_return_type = mono_fn->as.function.return_type;
|
current_return_type = mono_fn->as.function.return_type;
|
||||||
@@ -197,9 +203,15 @@ void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Symbol* sym = scope_insert(fn_scope, a, p->as.parameter.name, SYM_PARAMETER, pt);
|
Symbol* sym = scope_insert(fn_scope, a, p->as.parameter.name, SYM_PARAMETER, pt);
|
||||||
|
if (sym && p->as.parameter.is_out) { sym->kind = SYM_VARIABLE; sym->is_mut = true; }
|
||||||
if (sym && pt == TYPE_STRUCT && psn) {
|
if (sym && pt == TYPE_STRUCT && psn) {
|
||||||
sym->struct_type_name = psn;
|
sym->struct_type_name = psn;
|
||||||
}
|
}
|
||||||
|
if (sym && pt == TYPE_ARRAY) {
|
||||||
|
sym->array_element_type = p->as.parameter.arr_elem_type;
|
||||||
|
sym->array_element_struct_name = p->as.parameter.arr_elem_struct;
|
||||||
|
sym->array_size = p->as.parameter.arr_size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 解析返回类型的别名
|
// 解析返回类型的别名
|
||||||
const char* ret_sn = node->as.function.return_struct_type_name;
|
const char* ret_sn = node->as.function.return_struct_type_name;
|
||||||
@@ -221,9 +233,10 @@ void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AST_BLOCK:
|
case AST_BLOCK: {
|
||||||
|
Scope* block_scope = scope_new(a, scope);
|
||||||
for (size_t i = 0; i < node->as.block.stmt_count; i++) {
|
for (size_t i = 0; i < node->as.block.stmt_count; i++) {
|
||||||
analyze_node(node->as.block.stmts[i], scope, errors, a);
|
analyze_node(node->as.block.stmts[i], block_scope, errors, a);
|
||||||
}
|
}
|
||||||
// 表达式作为值: 块类型 = 最后一条产生值的语句类型
|
// 表达式作为值: 块类型 = 最后一条产生值的语句类型
|
||||||
if (node->as.block.stmt_count > 0) {
|
if (node->as.block.stmt_count > 0) {
|
||||||
@@ -243,6 +256,7 @@ void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case AST_LET_STMT: {
|
case AST_LET_STMT: {
|
||||||
TypeKind var_type;
|
TypeKind var_type;
|
||||||
@@ -251,9 +265,13 @@ void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
|||||||
|
|
||||||
if (node->as.let_stmt.has_type_annot) {
|
if (node->as.let_stmt.has_type_annot) {
|
||||||
if (node->as.let_stmt.annot_type == TYPE_ARRAY) {
|
if (node->as.let_stmt.annot_type == TYPE_ARRAY) {
|
||||||
// 数组类型标注: 跳过 init 分析 (init 是自引用的占位符)
|
|
||||||
is_array_type = true;
|
is_array_type = true;
|
||||||
var_type = TYPE_ARRAY;
|
var_type = TYPE_ARRAY;
|
||||||
|
// 分析 init — 除非是自引用 (如 let a: i64[3] = a;)
|
||||||
|
bool self_ref = (node->as.let_stmt.init->kind == AST_IDENT_EXPR
|
||||||
|
&& strcmp(node->as.let_stmt.init->as.ident.name,
|
||||||
|
node->as.let_stmt.name) == 0);
|
||||||
|
if (!self_ref) analyze_expr(node->as.let_stmt.init, scope, errors, a);
|
||||||
} else {
|
} else {
|
||||||
analyze_expr(node->as.let_stmt.init, scope, errors, a);
|
analyze_expr(node->as.let_stmt.init, scope, errors, a);
|
||||||
TypeKind inferred = node->as.let_stmt.init->type.kind;
|
TypeKind inferred = node->as.let_stmt.init->type.kind;
|
||||||
@@ -319,6 +337,10 @@ void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
|||||||
"变量 '%s' 重复定义", node->as.let_stmt.name);
|
"变量 '%s' 重复定义", node->as.let_stmt.name);
|
||||||
} else {
|
} else {
|
||||||
sym->is_mut = node->as.let_stmt.is_mut;
|
sym->is_mut = node->as.let_stmt.is_mut;
|
||||||
|
sym->is_const = node->as.let_stmt.is_const;
|
||||||
|
if (node->as.let_stmt.is_const && node->as.let_stmt.init->kind == AST_LITERAL_EXPR) {
|
||||||
|
sym->const_value = node->as.let_stmt.init->as.literal.i64_val;
|
||||||
|
}
|
||||||
if (var_struct_name) {
|
if (var_struct_name) {
|
||||||
sym->type = TYPE_STRUCT;
|
sym->type = TYPE_STRUCT;
|
||||||
sym->struct_type_name = var_struct_name;
|
sym->struct_type_name = var_struct_name;
|
||||||
@@ -472,6 +494,9 @@ void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
|||||||
case AST_EXPR_STMT:
|
case AST_EXPR_STMT:
|
||||||
analyze_expr(node->as.expr_stmt.expr, scope, errors, a);
|
analyze_expr(node->as.expr_stmt.expr, scope, errors, a);
|
||||||
break;
|
break;
|
||||||
|
case AST_DEFER_STMT:
|
||||||
|
analyze_node(node->as.defer_stmt.body, scope, errors, a);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
analyze_expr(node, scope, errors, a);
|
analyze_expr(node, scope, errors, a);
|
||||||
@@ -497,4 +522,19 @@ void sema_analyze(AstNode* ast, ErrorList* errors, Arena* arena) {
|
|||||||
scope_insert_function(global_scope, arena, "print_str", TYPE_VOID, NULL, params_str, NULL, NULL, 1, NULL, 0);
|
scope_insert_function(global_scope, arena, "print_str", TYPE_VOID, NULL, params_str, NULL, NULL, 1, NULL, 0);
|
||||||
|
|
||||||
analyze_node(ast, global_scope, errors, arena);
|
analyze_node(ast, global_scope, errors, arena);
|
||||||
|
|
||||||
|
// 将 lambda 生成的函数追加到 program 的函数列表
|
||||||
|
if (lambda_count > 0 && g_program) {
|
||||||
|
size_t old = g_program->as.program.fn_count;
|
||||||
|
size_t total = old + lambda_count;
|
||||||
|
AstNode** new_fns = arena_alloc_impl(arena, total * sizeof(AstNode*));
|
||||||
|
if (new_fns) {
|
||||||
|
if (old > 0)
|
||||||
|
memcpy(new_fns, g_program->as.program.functions, old * sizeof(AstNode*));
|
||||||
|
memcpy(new_fns + old, lambda_queue, lambda_count * sizeof(AstNode*));
|
||||||
|
g_program->as.program.functions = new_fns;
|
||||||
|
g_program->as.program.fn_count = total;
|
||||||
|
}
|
||||||
|
lambda_count = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ extern size_t mono_count;
|
|||||||
extern Arena* mono_arena;
|
extern Arena* mono_arena;
|
||||||
extern AstNode* g_program;
|
extern AstNode* g_program;
|
||||||
|
|
||||||
|
// === lambda 闭包队列 ===
|
||||||
|
extern AstNode* lambda_queue[256];
|
||||||
|
extern size_t lambda_count;
|
||||||
|
|
||||||
// === 类型推断上下文 ===
|
// === 类型推断上下文 ===
|
||||||
extern TypeKind current_return_type;
|
extern TypeKind current_return_type;
|
||||||
extern const char* current_return_struct_name;
|
extern const char* current_return_struct_name;
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ typedef struct Symbol {
|
|||||||
SymbolKind kind;
|
SymbolKind kind;
|
||||||
TypeKind type; // 变量/参数的类型
|
TypeKind type; // 变量/参数的类型
|
||||||
bool is_mut; // 变量是否可变(可被赋值)
|
bool is_mut; // 变量是否可变(可被赋值)
|
||||||
|
bool is_const; // 编译期常量 (const 声明)
|
||||||
|
int64_t const_value; // 编译期常量值
|
||||||
// 函数特有
|
// 函数特有
|
||||||
TypeKind return_type;
|
TypeKind return_type;
|
||||||
const char* return_struct_type_name; // 返回类型为 struct 时的类型名
|
const char* return_struct_type_name; // 返回类型为 struct 时的类型名
|
||||||
|
|||||||
@@ -226,6 +226,14 @@ bool reorder_named_args(AstNode* node, Symbol* sym, int param_offset,
|
|||||||
|
|
||||||
void analyze_call_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
void analyze_call_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||||
Symbol* sym = scope_lookup(scope, node->as.call.name);
|
Symbol* sym = scope_lookup(scope, node->as.call.name);
|
||||||
|
// 闭包调用: 变量类型为 TYPE_CLOSURE
|
||||||
|
if (sym && sym->kind == SYM_VARIABLE && sym->type == TYPE_CLOSURE) {
|
||||||
|
// 暂不做参数类型检查(MVP), 只分析参数表达式
|
||||||
|
for (size_t i = 0; i < node->as.call.arg_count; i++)
|
||||||
|
analyze_expr(node->as.call.args[i], scope, errors, a);
|
||||||
|
node->type.kind = TYPE_I64; // 默认返回 i64(MVP 限制)
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!sym || sym->kind != SYM_FUNCTION) {
|
if (!sym || sym->kind != SYM_FUNCTION) {
|
||||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||||
"未定义的函数 '%s'", node->as.call.name);
|
"未定义的函数 '%s'", node->as.call.name);
|
||||||
@@ -523,6 +531,164 @@ void analyze_method_call(AstNode* node, Scope* scope, ErrorList* errors, Arena*
|
|||||||
return NULL; \
|
return NULL; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === lambda 表达式分析 ===
|
||||||
|
static int lambda_counter = 0;
|
||||||
|
|
||||||
|
// 遍历 AST 收集自由变量(不在 lambda_scope 但在 parent_scope 中的变量)
|
||||||
|
static void collect_free_vars_impl(AstNode* body, Scope* lambda_scope, Scope* parent_scope,
|
||||||
|
const char** names, TypeKind* types, size_t* count,
|
||||||
|
const char** locals, size_t* local_count) {
|
||||||
|
if (!body || *count >= 16) return;
|
||||||
|
switch (body->kind) {
|
||||||
|
case AST_IDENT_EXPR: {
|
||||||
|
const char* name = body->as.ident.name;
|
||||||
|
// 跳过 lambda 参数和局部变量
|
||||||
|
for (size_t i = 0; i < *local_count; i++)
|
||||||
|
if (strcmp(locals[i], name) == 0) return;
|
||||||
|
// 在父作用域中查找(不在 lambda scope 中)
|
||||||
|
Symbol* sym = scope_lookup(parent_scope, name);
|
||||||
|
if (sym && (sym->kind == SYM_VARIABLE || sym->kind == SYM_PARAMETER)) {
|
||||||
|
for (size_t i = 0; i < *count; i++)
|
||||||
|
if (strcmp(names[i], name) == 0) return;
|
||||||
|
names[*count] = name;
|
||||||
|
types[*count] = sym->type;
|
||||||
|
(*count)++;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case AST_LAMBDA: return;
|
||||||
|
case AST_LET_STMT:
|
||||||
|
// 先分析 init (可能引用外部变量)
|
||||||
|
collect_free_vars_impl(body->as.let_stmt.init, lambda_scope, parent_scope,
|
||||||
|
names, types, count, locals, local_count);
|
||||||
|
// 将新声明的变量加入 locals
|
||||||
|
if (*local_count < 16)
|
||||||
|
locals[(*local_count)++] = body->as.let_stmt.name;
|
||||||
|
return;
|
||||||
|
case AST_BLOCK:
|
||||||
|
for (size_t i = 0; i < body->as.block.stmt_count; i++)
|
||||||
|
collect_free_vars_impl(body->as.block.stmts[i], lambda_scope, parent_scope,
|
||||||
|
names, types, count, locals, local_count);
|
||||||
|
return;
|
||||||
|
case AST_BINARY_EXPR:
|
||||||
|
collect_free_vars_impl(body->as.binary.left, lambda_scope, parent_scope, names, types, count, locals, local_count);
|
||||||
|
collect_free_vars_impl(body->as.binary.right, lambda_scope, parent_scope, names, types, count, locals, local_count);
|
||||||
|
return;
|
||||||
|
case AST_UNARY_EXPR:
|
||||||
|
collect_free_vars_impl(body->as.unary.operand, lambda_scope, parent_scope, names, types, count, locals, local_count);
|
||||||
|
return;
|
||||||
|
case AST_CALL_EXPR:
|
||||||
|
for (size_t i = 0; i < body->as.call.arg_count; i++)
|
||||||
|
collect_free_vars_impl(body->as.call.args[i], lambda_scope, parent_scope, names, types, count, locals, local_count);
|
||||||
|
return;
|
||||||
|
case AST_METHOD_CALL:
|
||||||
|
collect_free_vars_impl(body->as.method_call.receiver, lambda_scope, parent_scope, names, types, count, locals, local_count);
|
||||||
|
for (size_t i = 0; i < body->as.method_call.arg_count; i++)
|
||||||
|
collect_free_vars_impl(body->as.method_call.args[i], lambda_scope, parent_scope, names, types, count, locals, local_count);
|
||||||
|
return;
|
||||||
|
case AST_RETURN_STMT:
|
||||||
|
collect_free_vars_impl(body->as.return_stmt.expr, lambda_scope, parent_scope, names, types, count, locals, local_count);
|
||||||
|
return;
|
||||||
|
case AST_EXPR_STMT:
|
||||||
|
collect_free_vars_impl(body->as.expr_stmt.expr, lambda_scope, parent_scope, names, types, count, locals, local_count);
|
||||||
|
return;
|
||||||
|
case AST_ASSIGN_STMT:
|
||||||
|
collect_free_vars_impl(body->as.assign_stmt.value, lambda_scope, parent_scope, names, types, count, locals, local_count);
|
||||||
|
return;
|
||||||
|
case AST_IF_STMT:
|
||||||
|
collect_free_vars_impl(body->as.if_stmt.cond, lambda_scope, parent_scope, names, types, count, locals, local_count);
|
||||||
|
collect_free_vars_impl(body->as.if_stmt.then_block, lambda_scope, parent_scope, names, types, count, locals, local_count);
|
||||||
|
collect_free_vars_impl(body->as.if_stmt.else_block, lambda_scope, parent_scope, names, types, count, locals, local_count);
|
||||||
|
return;
|
||||||
|
case AST_WHILE_STMT:
|
||||||
|
collect_free_vars_impl(body->as.while_stmt.cond, lambda_scope, parent_scope, names, types, count, locals, local_count);
|
||||||
|
collect_free_vars_impl(body->as.while_stmt.body, lambda_scope, parent_scope, names, types, count, locals, local_count);
|
||||||
|
return;
|
||||||
|
case AST_INDEX_EXPR:
|
||||||
|
collect_free_vars_impl(body->as.index_expr.array, lambda_scope, parent_scope, names, types, count, locals, local_count);
|
||||||
|
collect_free_vars_impl(body->as.index_expr.index, lambda_scope, parent_scope, names, types, count, locals, local_count);
|
||||||
|
return;
|
||||||
|
case AST_FIELD_ACCESS:
|
||||||
|
collect_free_vars_impl(body->as.field_access.object, lambda_scope, parent_scope, names, types, count, locals, local_count);
|
||||||
|
return;
|
||||||
|
case AST_STRUCT_INIT:
|
||||||
|
for (size_t i = 0; i < body->as.struct_init.field_count; i++)
|
||||||
|
collect_free_vars_impl(body->as.struct_init.field_values[i], lambda_scope, parent_scope, names, types, count, locals, local_count);
|
||||||
|
return;
|
||||||
|
default: return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void collect_free_vars(AstNode* body, Scope* ls, Scope* ps,
|
||||||
|
const char** names, TypeKind* types, size_t* count) {
|
||||||
|
// 将 lambda 参数也当作局部变量(不会被捕获)
|
||||||
|
const char* locals[32]; size_t local_count = 0;
|
||||||
|
for (Symbol* s = ls->head; s; s = s->next) {
|
||||||
|
if (local_count < 32) locals[local_count++] = s->name;
|
||||||
|
}
|
||||||
|
collect_free_vars_impl(body, ls, ps, names, types, count, locals, &local_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void analyze_lambda(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||||
|
lambda_counter++;
|
||||||
|
int name_len = snprintf(NULL, 0, "__lambda_%d", lambda_counter) + 1;
|
||||||
|
char* gen_name = arena_alloc_impl(a, name_len);
|
||||||
|
snprintf(gen_name, name_len, "__lambda_%d", lambda_counter);
|
||||||
|
node->as.lambda.generated_name = gen_name;
|
||||||
|
|
||||||
|
// 分析 lambda 体(参数作用域)
|
||||||
|
Scope* lambda_scope = scope_new(a, scope);
|
||||||
|
for (size_t i = 0; i < node->as.lambda.param_count; i++) {
|
||||||
|
AstNode* p = node->as.lambda.params[i];
|
||||||
|
scope_insert(lambda_scope, a, p->as.parameter.name, SYM_PARAMETER, p->as.parameter.type);
|
||||||
|
}
|
||||||
|
TypeKind saved_ret = current_return_type;
|
||||||
|
const char* saved_ret_sn = current_return_struct_name;
|
||||||
|
current_return_type = node->as.lambda.return_type;
|
||||||
|
current_return_struct_name = node->as.lambda.return_struct_type_name;
|
||||||
|
analyze_node(node->as.lambda.body, lambda_scope, errors, a);
|
||||||
|
current_return_type = saved_ret;
|
||||||
|
current_return_struct_name = saved_ret_sn;
|
||||||
|
|
||||||
|
// 收集被捕获的外部变量
|
||||||
|
const char* cap_names[16]; TypeKind cap_types[16]; size_t cap_count = 0;
|
||||||
|
collect_free_vars(node->as.lambda.body, lambda_scope, scope, cap_names, cap_types, &cap_count);
|
||||||
|
|
||||||
|
// 创建顶层函数 AST 节点, 加入队列供 codegen 使用
|
||||||
|
AstNode* fn = ast_make_function(a, gen_name,
|
||||||
|
node->as.lambda.params, node->as.lambda.param_count,
|
||||||
|
node->as.lambda.return_type,
|
||||||
|
node->as.lambda.return_struct_type_name,
|
||||||
|
node->as.lambda.body, false, NULL, 0, node->loc);
|
||||||
|
// 设置捕获信息 (复制到 arena, 局部数组会出作用域)
|
||||||
|
if (cap_count > 0) {
|
||||||
|
const char** cap_names_a = arena_alloc_impl(a, cap_count * sizeof(const char*));
|
||||||
|
TypeKind* cap_types_a = arena_alloc_impl(a, cap_count * sizeof(TypeKind));
|
||||||
|
memcpy(cap_names_a, cap_names, cap_count * sizeof(const char*));
|
||||||
|
memcpy(cap_types_a, cap_types, cap_count * sizeof(TypeKind));
|
||||||
|
fn->as.function.captured = cap_names_a;
|
||||||
|
fn->as.function.cap_types = cap_types_a;
|
||||||
|
fn->as.function.cap_count = cap_count;
|
||||||
|
node->as.lambda.captured = cap_names_a;
|
||||||
|
node->as.lambda.captured_count = cap_count;
|
||||||
|
}
|
||||||
|
if (lambda_count < 256)
|
||||||
|
lambda_queue[lambda_count++] = fn;
|
||||||
|
|
||||||
|
// 注册函数符号(支持递归调用自身)
|
||||||
|
TypeKind* pts = node->as.lambda.param_count > 0
|
||||||
|
? arena_alloc_impl(a, node->as.lambda.param_count * sizeof(TypeKind)) : NULL;
|
||||||
|
for (size_t i = 0; i < node->as.lambda.param_count; i++)
|
||||||
|
pts[i] = node->as.lambda.params[i]->as.parameter.type;
|
||||||
|
scope_insert_function(scope, a, gen_name,
|
||||||
|
node->as.lambda.return_type,
|
||||||
|
node->as.lambda.return_struct_type_name,
|
||||||
|
pts, NULL, NULL, node->as.lambda.param_count, NULL, 0);
|
||||||
|
|
||||||
|
node->type.kind = TYPE_CLOSURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
SEMA_HANDLER(analyze_lambda)
|
||||||
SEMA_HANDLER(analyze_ident_expr)
|
SEMA_HANDLER(analyze_ident_expr)
|
||||||
SEMA_HANDLER(analyze_unary_expr)
|
SEMA_HANDLER(analyze_unary_expr)
|
||||||
SEMA_HANDLER(analyze_binary_expr)
|
SEMA_HANDLER(analyze_binary_expr)
|
||||||
@@ -536,6 +702,27 @@ SEMA_HANDLER(analyze_node) // if-expr / block 委托
|
|||||||
|
|
||||||
static AstDispatch sema_dispatch;
|
static AstDispatch sema_dispatch;
|
||||||
|
|
||||||
|
static void analyze_list_comp(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||||
|
analyze_expr(node->as.list_comp.array, scope, errors, a);
|
||||||
|
TypeInfo* arr_ti = &node->as.list_comp.array->type;
|
||||||
|
if (arr_ti->kind != TYPE_ARRAY) {
|
||||||
|
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||||
|
"列表推导式需要数组类型, 得到 '%s'", type_name(arr_ti->kind));
|
||||||
|
node->type.kind = TYPE_ERROR; return;
|
||||||
|
}
|
||||||
|
Scope* lc_scope = scope_new(a, scope);
|
||||||
|
TypeKind elem_k = arr_ti->element_type;
|
||||||
|
Symbol* var_sym = scope_insert(lc_scope, a, node->as.list_comp.var_name,
|
||||||
|
SYM_VARIABLE, elem_k);
|
||||||
|
if (var_sym) var_sym->struct_type_name = arr_ti->element_struct_name;
|
||||||
|
analyze_expr(node->as.list_comp.map_expr, lc_scope, errors, a);
|
||||||
|
node->type.kind = TYPE_ARRAY;
|
||||||
|
node->type.element_type = arr_ti->element_type;
|
||||||
|
node->type.element_struct_name = arr_ti->element_struct_name;
|
||||||
|
node->type.array_size = arr_ti->array_size;
|
||||||
|
}
|
||||||
|
SEMA_HANDLER(analyze_list_comp)
|
||||||
|
|
||||||
void analyze_expr_init(void) {
|
void analyze_expr_init(void) {
|
||||||
sema_dispatch.ctx = NULL; // 由 analyze_expr 每次设置
|
sema_dispatch.ctx = NULL; // 由 analyze_expr 每次设置
|
||||||
// 新增表达式节点: 在此注册 handler, 编译器会警告缺失
|
// 新增表达式节点: 在此注册 handler, 编译器会警告缺失
|
||||||
@@ -550,6 +737,8 @@ void analyze_expr_init(void) {
|
|||||||
ast_dispatch_set(&sema_dispatch, AST_METHOD_CALL, analyze_method_call_wrap);
|
ast_dispatch_set(&sema_dispatch, AST_METHOD_CALL, analyze_method_call_wrap);
|
||||||
ast_dispatch_set(&sema_dispatch, AST_IF_STMT, analyze_node_wrap);
|
ast_dispatch_set(&sema_dispatch, AST_IF_STMT, analyze_node_wrap);
|
||||||
ast_dispatch_set(&sema_dispatch, AST_BLOCK, analyze_node_wrap);
|
ast_dispatch_set(&sema_dispatch, AST_BLOCK, analyze_node_wrap);
|
||||||
|
ast_dispatch_set(&sema_dispatch, AST_LIST_COMP, analyze_list_comp_wrap);
|
||||||
|
ast_dispatch_set(&sema_dispatch, AST_LAMBDA, analyze_lambda_wrap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fn main() -> i64 {
|
||||||
|
var x = 10;
|
||||||
|
defer { print_str("deferred"); }
|
||||||
|
print_str("normal");
|
||||||
|
print_i64(x);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
fn main() -> i64 {
|
||||||
|
var src: i64[2] = src;
|
||||||
|
src[0] = 10;
|
||||||
|
src[1] = 20;
|
||||||
|
var dst: i64[2] = dst;
|
||||||
|
dst = [for x in src: x * 2];
|
||||||
|
print_i64(dst[0]); // 20
|
||||||
|
print_i64(dst[1]); // 40
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
fn div_mod(a: i64, b: i64) -> (i64, i64) {
|
||||||
|
return (a / b, a % b);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> i64 {
|
||||||
|
let result = div_mod(10, 3);
|
||||||
|
print_i64(result._0); // 3
|
||||||
|
print_i64(result._1); // 1
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
fn main() -> i64 {
|
||||||
|
for i in 0 to 10 step 2 {
|
||||||
|
print_i64(i);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// out 参数测试 — 引用传递
|
||||||
|
fn swap(out x: i64, out y: i64) -> void {
|
||||||
|
let t = x;
|
||||||
|
x = y;
|
||||||
|
y = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn increment(out x: i64) -> void {
|
||||||
|
x = x + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> void {
|
||||||
|
let a = 10;
|
||||||
|
let b = 20;
|
||||||
|
print_i64(a);
|
||||||
|
print_i64(b);
|
||||||
|
swap(a, b);
|
||||||
|
print_i64(a);
|
||||||
|
print_i64(b);
|
||||||
|
increment(a);
|
||||||
|
print_i64(a);
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// out 参数 + 结构体测试
|
||||||
|
struct Point { x: i64, y: i64 }
|
||||||
|
|
||||||
|
fn init_point(out p: Point) -> void {
|
||||||
|
p = Point { x: 100, y: 200 };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn offset_point(out p: Point) -> void {
|
||||||
|
p = Point { x: p.x + 50, y: p.y + 100 };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> void {
|
||||||
|
let p = Point { x: 0, y: 0 };
|
||||||
|
print_i64(p.x);
|
||||||
|
print_i64(p.y);
|
||||||
|
init_point(p);
|
||||||
|
print_i64(p.x);
|
||||||
|
print_i64(p.y);
|
||||||
|
offset_point(p);
|
||||||
|
print_i64(p.x);
|
||||||
|
print_i64(p.y);
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// 闭包测试 — 非捕获 lambda + 变量捕获
|
||||||
|
fn make_adder(base: i64) -> i64 {
|
||||||
|
let adder = fn(x: i64) -> i64 { return x + base; };
|
||||||
|
return adder(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> void {
|
||||||
|
// 测试1: 非捕获 lambda
|
||||||
|
let double = fn(x: i64) -> i64 { return x * 2; };
|
||||||
|
print_i64(double(21)); // 42
|
||||||
|
|
||||||
|
// 测试2: 捕获单个变量
|
||||||
|
let base = 100;
|
||||||
|
let add = fn(x: i64) -> i64 { return x + base; };
|
||||||
|
print_i64(add(50)); // 150
|
||||||
|
|
||||||
|
// 测试3: 捕获多个变量
|
||||||
|
let a = 10;
|
||||||
|
let b = 20;
|
||||||
|
let sum3 = fn(x: i64) -> i64 { return x + a + b; };
|
||||||
|
print_i64(sum3(5)); // 35
|
||||||
|
|
||||||
|
// 测试4: 函数内创建闭包
|
||||||
|
let r = make_adder(200);
|
||||||
|
print_i64(r); // 250
|
||||||
|
}
|
||||||
@@ -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
@@ -129,8 +129,8 @@ void test_codegen_struct_decl() {
|
|||||||
|
|
||||||
/* 构造 AST: struct Point { x: i64, y: i64 } */
|
/* 构造 AST: struct Point { x: i64, y: i64 } */
|
||||||
AstNode* fields[2];
|
AstNode* fields[2];
|
||||||
fields[0] = ast_make_parameter(&a, "x", TYPE_I64, NULL, 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, 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* struct_decl = ast_make_struct_decl(&a, "Point", fields, 2, loc_at(1, 1));
|
||||||
AstNode* structs[] = { struct_decl };
|
AstNode* structs[] = { struct_decl };
|
||||||
|
|
||||||
@@ -185,8 +185,8 @@ void test_codegen_struct_field_access() {
|
|||||||
|
|
||||||
/* 构造 AST: struct Point { x: i64, y: i64 } */
|
/* 构造 AST: struct Point { x: i64, y: i64 } */
|
||||||
AstNode* fields[2];
|
AstNode* fields[2];
|
||||||
fields[0] = ast_make_parameter(&a, "x", TYPE_I64, NULL, 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, 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* struct_decl = ast_make_struct_decl(&a, "Point", fields, 2, loc_at(1, 1));
|
||||||
AstNode* structs[] = { struct_decl };
|
AstNode* structs[] = { struct_decl };
|
||||||
|
|
||||||
@@ -356,13 +356,13 @@ void test_codegen_method_call() {
|
|||||||
|
|
||||||
/* struct Point { x: i64, y: i64 } */
|
/* struct Point { x: i64, y: i64 } */
|
||||||
AstNode* fields[2];
|
AstNode* fields[2];
|
||||||
fields[0] = ast_make_parameter(&a, "x", TYPE_I64, NULL, 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, 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* struct_decl = ast_make_struct_decl(&a, "Point", fields, 2, loc_at(1, 1));
|
||||||
AstNode* structs[] = { struct_decl };
|
AstNode* structs[] = { struct_decl };
|
||||||
|
|
||||||
/* fn Point$get_x(self: Point) -> i64 { return self.x; } */
|
/* fn Point$get_x(self: Point) -> i64 { return self.x; } */
|
||||||
AstNode* self_param = ast_make_parameter(&a, "self", TYPE_STRUCT, "Point", 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* params[] = { self_param };
|
||||||
AstNode* self_ident = ast_make_ident(&a, "self", loc_at(1, 1));
|
AstNode* self_ident = ast_make_ident(&a, "self", loc_at(1, 1));
|
||||||
self_ident->type.kind = TYPE_STRUCT;
|
self_ident->type.kind = TYPE_STRUCT;
|
||||||
|
|||||||
@@ -418,6 +418,72 @@ void test_match_wildcard_only_sema_ok() {
|
|||||||
arena_destroy(&a);
|
arena_destroy(&a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_out_param_assign_ok() {
|
||||||
|
Arena a = arena_create(1);
|
||||||
|
size_t tc; ErrorInfo lex_err = {0};
|
||||||
|
Token* toks = lex(&a,
|
||||||
|
"fn swap(out x: i64, out y: i64) -> void { let t = x; x = y; y = t; return; }"
|
||||||
|
"fn main() -> void { let a = 10; let b = 20; swap(a, b); return; }",
|
||||||
|
"test", &tc, &lex_err);
|
||||||
|
ASSERT(toks != NULL);
|
||||||
|
ErrorInfo parse_err = {0};
|
||||||
|
AstNode* ast = parse(&a, toks, tc, "test", &parse_err);
|
||||||
|
ASSERT(ast != NULL);
|
||||||
|
ErrorList errors; error_init(&errors, &a);
|
||||||
|
sema_analyze(ast, &errors, &a);
|
||||||
|
ASSERT(errors.count == 0); // out 参数赋值不应报错
|
||||||
|
arena_destroy(&a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_in_param_assign_error() {
|
||||||
|
Arena a = arena_create(1);
|
||||||
|
size_t tc; ErrorInfo lex_err = {0};
|
||||||
|
Token* toks = lex(&a,
|
||||||
|
"fn bad(x: i64) -> void { x = 42; return; }"
|
||||||
|
"fn main() -> void { bad(10); return; }",
|
||||||
|
"test", &tc, &lex_err);
|
||||||
|
ASSERT(toks != NULL);
|
||||||
|
ErrorInfo parse_err = {0};
|
||||||
|
AstNode* ast = parse(&a, toks, tc, "test", &parse_err);
|
||||||
|
ASSERT(ast != NULL);
|
||||||
|
ErrorList errors; error_init(&errors, &a);
|
||||||
|
sema_analyze(ast, &errors, &a);
|
||||||
|
ASSERT(errors.count > 0); // 非 out 参数赋值应报错
|
||||||
|
arena_destroy(&a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_lambda_ok() {
|
||||||
|
Arena a = arena_create(1);
|
||||||
|
size_t tc; ErrorInfo lex_err = {0};
|
||||||
|
Token* toks = lex(&a,
|
||||||
|
"fn main() -> void { let f = fn(x: i64) -> i64 { return x * 2; }; return; }",
|
||||||
|
"test", &tc, &lex_err);
|
||||||
|
ASSERT(toks != NULL);
|
||||||
|
ErrorInfo parse_err = {0};
|
||||||
|
AstNode* ast = parse(&a, toks, tc, "test", &parse_err);
|
||||||
|
ASSERT(ast != NULL);
|
||||||
|
ErrorList errors; error_init(&errors, &a);
|
||||||
|
sema_analyze(ast, &errors, &a);
|
||||||
|
ASSERT(errors.count == 0); // lambda 定义应通过
|
||||||
|
arena_destroy(&a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_lambda_call_ok() {
|
||||||
|
Arena a = arena_create(1);
|
||||||
|
size_t tc; ErrorInfo lex_err = {0};
|
||||||
|
Token* toks = lex(&a,
|
||||||
|
"fn main() -> void { let f = fn(x: i64) -> i64 { return x + 1; }; let r = f(41); return; }",
|
||||||
|
"test", &tc, &lex_err);
|
||||||
|
ASSERT(toks != NULL);
|
||||||
|
ErrorInfo parse_err = {0};
|
||||||
|
AstNode* ast = parse(&a, toks, tc, "test", &parse_err);
|
||||||
|
ASSERT(ast != NULL);
|
||||||
|
ErrorList errors; error_init(&errors, &a);
|
||||||
|
sema_analyze(ast, &errors, &a);
|
||||||
|
ASSERT(errors.count == 0); // 闭包调用应通过
|
||||||
|
arena_destroy(&a);
|
||||||
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
TEST_RUN(test_type_error);
|
TEST_RUN(test_type_error);
|
||||||
TEST_RUN(test_undefined_var);
|
TEST_RUN(test_undefined_var);
|
||||||
@@ -443,5 +509,9 @@ int main(void) {
|
|||||||
TEST_RUN(test_match_enum_sema_ok);
|
TEST_RUN(test_match_enum_sema_ok);
|
||||||
TEST_RUN(test_match_int_sema_ok);
|
TEST_RUN(test_match_int_sema_ok);
|
||||||
TEST_RUN(test_match_wildcard_only_sema_ok);
|
TEST_RUN(test_match_wildcard_only_sema_ok);
|
||||||
|
TEST_RUN(test_out_param_assign_ok);
|
||||||
|
TEST_RUN(test_in_param_assign_error);
|
||||||
|
TEST_RUN(test_lambda_ok);
|
||||||
|
TEST_RUN(test_lambda_call_ok);
|
||||||
return test_summary();
|
return test_summary();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user