From c472ea9798cb6b96cd03be41cee413149de85740 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 11 Aug 2026 16:10:05 +0800 Subject: [PATCH] =?UTF-8?q?feat(gen):=20=E6=94=AF=E6=8C=81=20lambda=20?= =?UTF-8?q?=E4=B8=8E=20nonlocal=20=E8=BF=90=E8=A1=8C=E6=97=B6=20env=20?= =?UTF-8?q?=E9=93=BE=E5=BC=8F=E5=85=B1=E4=BA=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - translate_lambda 提升 __lambda_{id}(i8* env, args...) + 捕获变量堆存储 - _lambda_scan_body 递归收集捕获变量;HandlesAssign 注册 lambda 闭包名 - translate_closure_call 支持带参(实参链表 + 函数类型 i32(i8*, args...)*) - 嵌套函数参数支持(提升函数签名 + 参数 alloca) - nonlocal 改为运行时 env 链式共享:父函数局部新建堆+重定向 VarEntry; 父函数中为 nonlocal 时从父函数 env 读堆地址(_load_raw_var_ptr) - 全局数组 initializer 按声明长度补齐补零 - LambdaCount 计数器迁移到 trans._lambda_count(修复 TPC 编译崩溃) --- App/lib/core/Gen/CallGenMixin.vp | 61 ++- App/lib/core/Gen/ExprGenMixin.vp | 69 ++- App/lib/core/Gen/FuncGenMixin.vp | 617 +++++++++++++++++++++- App/lib/core/Gen/TranslatorGenMixin.vp | 34 +- App/lib/core/Handles/HandlesAssign.vp | 13 +- App/lib/core/Handles/HandlesExpr.vp | 20 + App/lib/core/Handles/HandlesExprCall.vp | 5 +- App/lib/core/Handles/HandlesTranslator.vp | 5 + 8 files changed, 763 insertions(+), 61 deletions(-) diff --git a/App/lib/core/Gen/CallGenMixin.vp b/App/lib/core/Gen/CallGenMixin.vp index 166e5bd..a3e0653 100644 --- a/App/lib/core/Gen/CallGenMixin.vp +++ b/App/lib/core/Gen/CallGenMixin.vp @@ -5790,14 +5790,27 @@ class CallGenMixin: # 闭包变量(嵌套函数提升,已注册到闭包名集合):提取 fn_ptr/env_ptr 间接调用 if HandlesExprCall.is_closure_name(func_name) != 0: return HandlesExprCall.translate_closure_call(pool, builder, mod, fp_alloca, - cargs, can) + cargs, can, trans) # 函数指针变量(t.Callable 注解 → i8** alloca):按实参构造签名间接调用 if HandlesExprCall._is_func_ptr_alloca(fp_alloca) != 0: - return HandlesExprCall._translate_func_ptr_call(pool, builder, mod, fp_alloca, - func_name, cargs, can, trans) + # 区分 t.Callable(真函数指针)vs t.CPtr(闭包指针): + # t.CPtr 变量(如 f: t.CPtr = make_counter())存的是闭包结构 + # {fn_ptr, env_ptr},调用必须提取 env 传参;若按函数指针直接 + # call,跳转到闭包结构数据地址崩溃(ClosureCallTest 运行时崩溃)。 + ve_fp: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, func_name) + is_cptr_annot_fp: int = 0 + if ve_fp is not None and ve_fp.AnnotClassName is not None: + if string.strstr(ve_fp.AnnotClassName, "CPtr") is not None: + is_cptr_annot_fp = 1 + if is_cptr_annot_fp == 0: + return HandlesExprCall._translate_func_ptr_call(pool, builder, mod, fp_alloca, + func_name, cargs, can, trans) + return HandlesExprCall.translate_closure_call(pool, builder, mod, fp_alloca, + cargs, can, trans) # 其他 i8* 变量按闭包调用路径处理 return HandlesExprCall.translate_closure_call(pool, builder, mod, fp_alloca, - cargs, can) + cargs, can, trans) # 翻译参数并链接 # 有关键字参数且找到函数定义时,按参数名匹配 @@ -6511,8 +6524,9 @@ class CallGenMixin: mod: llvmlite.LLVMModule | t.CPtr, closure_alloca: llvmlite.Value | t.CPtr, cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT) -> llvmlite.Value | t.CPtr: - """通过闭包指针间接调用""" + can: t.CSizeT, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """通过闭包指针间接调用(支持带参 lambda:i32(i8*, args...))""" if builder is None or closure_alloca is None: return None @@ -6542,17 +6556,42 @@ class CallGenMixin: if env_ptr is None: return None - # 4. bitcast fn_raw to i32 (i8*)* + # 4. 构建参数:env 头 + 实参尾(带参 lambda 时翻译实参) + total_args: int = 1 + arg_head: llvmlite.Value | t.CPtr = env_ptr + arg_tail: llvmlite.Value | t.CPtr = env_ptr param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) - func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, param_node, 1) + pn_tail: llvmlite.ParamNode | t.CPtr = param_node + if can > 0 and cargs is not None and trans is not None: + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is None: + continue + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is None or arg_val.Ty is None: + continue + arg_val.Next = None + if arg_tail is not None: + arg_tail.Next = arg_val + arg_tail = arg_val + pn_new: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, arg_val.Ty) + if pn_new is not None: + pn_tail.Next = pn_new + pn_tail = pn_new + total_args += 1 + if total_args == 1: + env_ptr.Next = None + + # 5. bitcast fn_raw 到函数指针类型 i32(i8*, [args...])* + func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, param_node, total_args) func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty) fn_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, fn_raw, func_ptr_ty) if fn_typed is None: return None - # 5. 间接调用: call i32 %fn_typed(i8* %env_ptr) - env_ptr.Next = None - return llvmlite.build_call_indirect(builder, fn_typed, env_ptr, 1, i32_ty) + # 6. 间接调用: call i32 %fn_typed(env, args...) + return llvmlite.build_call_indirect(builder, fn_typed, arg_head, total_args, i32_ty) def _is_func_ptr_alloca(self, alloca: llvmlite.Value | t.CPtr) -> int: """判断 alloca 是否为函数指针变量(类型 Ptr(Ptr(i8))),1=是 / 0=否""" diff --git a/App/lib/core/Gen/ExprGenMixin.vp b/App/lib/core/Gen/ExprGenMixin.vp index aef36c8..fcff3df 100644 --- a/App/lib/core/Gen/ExprGenMixin.vp +++ b/App/lib/core/Gen/ExprGenMixin.vp @@ -11,6 +11,7 @@ import w32.fileio as fileio import lib.core.Handles.HandlesBase as HandlesBase import lib.core.Handles.HandlesTranslator as HT import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesExpr as HandlesExpr import lib.core.Handles.HandlesExprOps as HandlesExprOps import lib.core.Handles.HandlesExprCall as HandlesExprCall import lib.core.Handles.HandlesNonlocal as HandlesNonlocal @@ -187,6 +188,25 @@ class ExprGenMixin: break return level + # ============================================================ + # _is_zero_int_literal - 判断 AST 节点是否为整数字面量 0 + # + # 用于指针判空比较(ptr != 0 / ptr == 0):指针与字面量 0 比较时 + # 0 视为 NULL,允许并转成 null 指针(比较类型检查的例外)。 + # ============================================================ + def _is_zero_int_literal(self, node: ast.AST | t.CPtr) -> int: + """判断节点是否为整数字面量 0,返回 1=是 / 0=否""" + if node is None: + return 0 + if node.kind() != ast.ASTKind.Constant: + return 0 + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + if cn is None or cn.const_kind != ast.CONST_INT: + return 0 + if cn.int_val == 0: + return 1 + return 0 + # ============================================================ # is_array_type - 检查类型是否为 Array # @@ -883,6 +903,10 @@ class ExprGenMixin: return self.translate_list_literal(builder, pool, mod, node, None, trans) elif k == ast.ASTKind.IfExp: return self.translate_ifexp(builder, pool, mod, node, trans) + elif k == ast.ASTKind.Lambda: + # 模块级委托:translate_lambda 定义在 FuncGenMixin(跨 Mixin + # 方法不能 self. 直接调用,见 HandlesExpr.translate_lambda) + return HandlesExpr.translate_lambda(builder, pool, mod, node, trans) return None # ============================================================ @@ -1237,18 +1261,33 @@ class ExprGenMixin: lhs_ptr_level: int = self.get_ptr_level(lhs.Ty) rhs_ptr_level: int = self.get_ptr_level(rhs.Ty) if lhs_ptr_level != rhs_ptr_level: - # 类型不匹配:数值vs指针 或 不同级指针 - # 用 fmt_buf 构造可读消息(Viper % 格式化在部分路径生成 null) - fmt_msg: t.CChar | t.CPtr = VLogger.fmt_buf() - if fmt_msg is not None: - viperlib.snprintf( - fmt_msg, 1024, - "比较类型不匹配(行 %d): lhs 层级=%d (ty=%p), rhs 层级=%d (ty=%p)", - cmp.lineno, lhs_ptr_level, lhs.Ty, rhs_ptr_level, rhs.Ty) - VLogger.error(fmt_msg, "Compare") + # 指针 vs 整数字面量 0(判空模式 ptr != 0 / ptr == 0): + # 0 视为 NULL,转成与指针侧同类型的 null 指针(icmp 需要同类型), + # 不报类型不匹配(ClassArrayTest 的 if ptr != 0 等常见模式)。 + zero_is_rhs: int = 0 + zero_is_lhs: int = 0 + if rhs_ptr_level == 0 and self._is_zero_int_literal(rhs_node) != 0: + zero_is_rhs = 1 + if lhs_ptr_level == 0 and self._is_zero_int_literal(lhs_node) != 0: + zero_is_lhs = 1 + if zero_is_rhs != 0 or zero_is_lhs != 0: + if zero_is_rhs != 0: + rhs = llvmlite.ConstNull(pool, lhs.Ty, "null") + else: + lhs = llvmlite.ConstNull(pool, rhs.Ty, "null") else: - VLogger.error("比较类型不匹配: 数值与指针/不同级指针比较", "Compare") - return None + # 类型不匹配:数值vs指针 或 不同级指针 + # 用 fmt_buf 构造可读消息(Viper % 格式化在部分路径生成 null) + fmt_msg: t.CChar | t.CPtr = VLogger.fmt_buf() + if fmt_msg is not None: + viperlib.snprintf( + fmt_msg, 1024, + "比较类型不匹配(行 %d): lhs 层级=%d (ty=%p), rhs 层级=%d (ty=%p)", + cmp.lineno, lhs_ptr_level, lhs.Ty, rhs_ptr_level, rhs.Ty) + VLogger.error(fmt_msg, "Compare") + else: + VLogger.error("比较类型不匹配: 数值与指针/不同级指针比较", "Compare") + return None else: # None 比较: None 被翻译为 i8* null(一级指针) # 如果 lhs 是指针,将 rhs (i8* null) bitcast 为 lhs 的指针类型 @@ -1262,7 +1301,7 @@ class ExprGenMixin: pass elif lhs_ptr_level_none != 0 and rhs_ptr_level_none == 0: # lhs 是指针, rhs 是数值 → 将 rhs 转为同层级 null 指针 - rhs = llvmlite.ConstNull(pool, lhs.Ty, None) + rhs = llvmlite.ConstNull(pool, lhs.Ty, "null") elif rhs_ptr_level_none != 0 and lhs_ptr_level_none == 0: # 检查 lhs 是否是结构体值类型(非指针的 Struct) lhs_is_struct_none: int = 0 @@ -2225,6 +2264,12 @@ class ExprGenMixin: match load_ty: case llvmlite.LLVMType.Struct(_, _, _): return alloca + case llvmlite.LLVMType.Array(_, _): + # 数组变量按 C 语义退化为指针(返回数组基址),而非整体 + # load 数组值——如 printf("%s", str_arr) 应传数组首地址, + # load [N x i8] 值传给 %s 会读到错误数据崩溃 + # (ClassArrayTest TestCharArray 运行时崩溃根因)。 + return alloca return llvmlite.build_load(builder, load_ty, alloca) # 模块别名检查:SymTab 查找失败后才检查 diff --git a/App/lib/core/Gen/FuncGenMixin.vp b/App/lib/core/Gen/FuncGenMixin.vp index dc7992a..395e67b 100644 --- a/App/lib/core/Gen/FuncGenMixin.vp +++ b/App/lib/core/Gen/FuncGenMixin.vp @@ -10,7 +10,9 @@ import stdlib import lib.core.VLogger as VLogger import lib.core.Handles.HandlesTranslator as HT import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesExpr as HandlesExpr import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal import lib.core.Handles.HandlesType as HandlesType import lib.core.Handles.HandlesBody as HandlesBody import lib.core.Handles.HandlesImports as HandlesImports @@ -884,13 +886,53 @@ class FuncGenMixin: viperlib.snprintf(promoted_name, 64, "__closure_%s", func_name) mangled_promoted: str = self._mangle_name(trans, promoted_name) - # 2. 创建提升后的函数: define i32 @__closure_{name}(i8* %env) + # 2. 创建提升后的函数: define i32 @__closure_{name}(i8* %env, args...) func: llvmlite.Function | t.CPtr = llvmlite.create_function( pool, mod, mangled_promoted, i32_ty) if func is None: return 0 llvmlite.add_param(pool, func, i8_ptr_ty, "%env") + # 2a. 嵌套函数参数:加入提升函数签名(i8* %env, 参数...), + # 类型存入 param_tys 缓冲(CVoid 跳过,与 alloca 创建索引对齐) + imported_modules: str = trans._imported_modules + from_imports: str = trans._from_imports + param_tys: t.CVoid | t.CPtr = pool.alloc(8 * 64) + if param_tys is not None: + string.memset(param_tys, 0, 8 * 64) + param_count: int = 0 + if fd.args is not None: + ags_n: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args) + if ags_n.args is not None: + alist_n: list[ast.AST | t.CPtr] | t.CPtr = ags_n.args + an_n: t.CSizeT = alist_n.__len__() + for ai_n in range(an_n): + arg_n: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist_n.get(ai_n)) + if arg_n is None or arg_n.arg is None: + continue + if arg_n.annotation is not None: + if HandlesType._is_t_attr(arg_n.annotation, "CVoid", imported_modules) != 0: + continue + pty_n: llvmlite.LLVMType | t.CPtr = i32_ty + if arg_n.annotation is not None: + resolved_n: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, arg_n.annotation, imported_modules, from_imports, trans) + if resolved_n is not None: + match resolved_n: + case llvmlite.LLVMType.Struct(_, _, _): + pty_n = llvmlite.Ptr(pool, resolved_n) + case _: + pty_n = resolved_n + if param_count < 64 and param_tys is not None: + pty_slot_n: str | t.CPtr = (t.CVoid | t.CPtr)( + t.CUInt64T(param_tys) + param_count * 8) + pty_slot_n[0] = pty_n + pname_n: t.CChar | t.CPtr = pool.alloc(32) + if pname_n is not None: + viperlib.snprintf(pname_n, 32, "%%%s", arg_n.arg) + llvmlite.add_param(pool, func, pty_n, pname_n) + param_count += 1 + # 3. 创建 entry 块 + builder entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") if entry_blk is None: @@ -910,6 +952,46 @@ class FuncGenMixin: env_param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "%env") llvmlite.build_store(func_builder, env_param_val, env_alloca) + # 5a. 创建嵌套函数参数 alloca(函数体内参数名可引用,如 + # accumulate(n) 内 for i in range(n)、set_result(val) 内 result = val) + if fd.args is not None: + ags_p: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args) + if ags_p.args is not None: + alist_p: list[ast.AST | t.CPtr] | t.CPtr = ags_p.args + idx_p: int = 0 + apn: t.CSizeT = alist_p.__len__() + for api in range(apn): + arg_p: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist_p.get(api)) + if arg_p is None or arg_p.arg is None: + continue + if arg_p.annotation is not None: + if HandlesType._is_t_attr(arg_p.annotation, "CVoid", imported_modules) != 0: + continue + if idx_p >= param_count: + break + pty2_n: llvmlite.LLVMType | t.CPtr = i32_ty + if param_tys is not None: + ty_addr_n: t.CUInt64T = t.CUInt64T(param_tys) + idx_p * 8 + ty_slot_n: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr_n) + pty2_n = (llvmlite.LLVMType | t.CPtr)(ty_slot_n[0]) + if pty2_n is None: + pty2_n = i32_ty + p_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, pty2_n) + if p_alloca is not None: + HandlesVar.define_var(trans.SymTab, arg_p.arg, p_alloca) + if arg_p.annotation is not None: + cls_nm_p: str = HandlesType.extract_class_name_from_annotation( + arg_p.annotation, imported_modules) + if cls_nm_p is not None: + HandlesVar.set_var_annot_class_name( + trans.SymTab, arg_p.arg, cls_nm_p) + pname2_n: t.CChar | t.CPtr = pool.alloc(32) + if pname2_n is not None: + viperlib.snprintf(pname2_n, 32, "%%%s", arg_p.arg) + p_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, pty2_n, pname2_n) + llvmlite.build_store(func_builder, p_val, p_alloca) + idx_p += 1 + # 6. 保存父函数作用域状态(仅非变量表相关) old_func: llvmlite.Function | t.CPtr = trans._cur_func old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder @@ -989,7 +1071,16 @@ class FuncGenMixin: env_ptr = llvmlite.build_call( parent_builder, "malloc", env_size_val, 1, i8_ptr_ty, 0) - # 为每个 nonlocal 变量存储 alloca 指针到 env(共享存储,修改互相可见) + # 为每个 nonlocal 变量建立堆存储并注册到 env: + # 运行时 env 链式共享(无需编译期映射——映射存编译期 Value 对象 + # 地址会被 inttoptr 当运行时堆地址解引用崩溃;存整型也拿不到 + # 运行时 malloc 结果): + # - 变量是父函数局部(lookup_current 在当前作用域找到 alloca) + # → 新建堆(malloc + 拷贝当前值),并把父函数 VarEntry.Alloca + # 重定向到堆——父函数后续读写走共享堆 + # - 变量是父函数的 nonlocal(多层嵌套,当前作用域无 alloca) + # → 从父函数 env 读该变量的堆地址(_load_raw_var_ptr), + # env[ni] = 同一堆地址(运行时链式共享,各层写同一堆) if env_ptr is not None: i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty) for ni in range(nested_nonlocal_count): @@ -997,25 +1088,52 @@ class FuncGenMixin: name_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + ni * 8 nl_slot: str | t.CPtr = (t.CVoid | t.CPtr)(name_addr) nl_name: str = nl_slot[0] - if nl_name is not None: - # 在父函数作用域中查找(Current 已回到父作用域) - var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, nl_name) - if var_alloca is not None: - # bitcast alloca 指针为 i8*(擦除类型信息) - alloca_as_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - parent_builder, var_alloca, i8_ptr_ty) - if alloca_as_i8 is not None: - # GEP to env[ni*8] - offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, ni * 8) - slot: llvmlite.Value | t.CPtr = llvmlite.build_gep( - parent_builder, i8_ty, env_ptr, offset_val) - if slot is not None: - # bitcast to i8** and store alloca pointer - slot_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - parent_builder, slot, i8_ptr_ptr_ty) - if slot_typed is not None: - llvmlite.build_store(parent_builder, alloca_as_i8, slot_typed) + if nl_name is None: + continue + heap_store: llvmlite.Value | t.CPtr = None + local_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( + trans.SymTab, nl_name) + if local_alloca is not None and local_alloca.Ty is not None: + # 父函数局部变量:新建堆存储 + 拷贝当前值 + 重定向 + nl_load_ty: llvmlite.LLVMType | t.CPtr = local_alloca.Ty.Pointee + if nl_load_ty is not None: + cur_val_nl: llvmlite.Value | t.CPtr = llvmlite.build_load( + parent_builder, nl_load_ty, local_alloca) + eight_c: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 8) + if eight_c is not None: + eight_c.Next = None + var_storage: llvmlite.Value | t.CPtr = llvmlite.build_call( + parent_builder, "malloc", eight_c, 1, i8_ptr_ty, 0) + if var_storage is not None: + # 拷贝当前值到堆存储 + st_slot_nl: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + parent_builder, var_storage, llvmlite.Ptr(pool, nl_load_ty)) + if st_slot_nl is not None and cur_val_nl is not None: + llvmlite.build_store(parent_builder, cur_val_nl, st_slot_nl) + # 父函数 VarEntry.Alloca 重定向到堆(父函数读写走共享堆) + ve_nl: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, nl_name) + if ve_nl is not None: + heap_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + parent_builder, var_storage, llvmlite.Ptr(pool, nl_load_ty)) + if heap_typed is not None: + ve_nl.Alloca = heap_typed + heap_store = var_storage + else: + # 父函数中该变量是 nonlocal(多层嵌套):从父函数 env + # 读堆地址(运行时链式共享同一堆),不新建 + heap_store = HandlesNonlocal._load_raw_var_ptr(trans, nl_name) + if heap_store is None: + continue + # env[ni] = 堆存储地址(共享) + offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, ni * 8) + slot: llvmlite.Value | t.CPtr = llvmlite.build_gep( + parent_builder, i8_ty, env_ptr, offset_val) + if slot is not None: + slot_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + parent_builder, slot, i8_ptr_ptr_ty) + if slot_typed is not None: + llvmlite.build_store(parent_builder, heap_store, slot_typed) # 13b. 创建闭包结构: malloc(16) closure_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 16) @@ -1087,6 +1205,463 @@ class FuncGenMixin: return 1 + # ============================================================ + # translate_lambda - 翻译 lambda 表达式 + # + # 与 translate_nested_function_def 同架构(TPV 闭包 {i8* fn_ptr, + # i8* env_ptr},16 字节): + # 1. 提升函数 __lambda_{id}(i8* %env, [args...]) — 恒返回 i32 + # 2. 捕获变量按值拷贝到堆存储(env[i] = 堆地址),避免闭包返回 + # 后父栈帧销毁导致悬垂 + # 3. 创建闭包 {fn_ptr, env_ptr},返回 i8* 闭包指针 + # 赋值语句据此创建 i8** alloca,调用走 translate_closure_call + # ============================================================ + def translate_lambda(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译 lambda 表达式,返回闭包指针(i8*)""" + if node is None or trans is None or builder is None: + return None + lam: ast.Lambda | t.CPtr = (ast.Lambda | t.CPtr)(node) + if lam is None: + return None + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty) + + # 1. lambda id + 提升函数名 + # 注意:计数器放 trans(_lambda_count)而非 self——Mixin 类自身无字段, + # self.新字段在 TPC 编译 Mixin 时查 class_members 失败触发未完成的 + # _PreRegisterClassMembers fallback 崩溃(FuncGen.py L437) + lambda_id: int = trans._lambda_count + trans._lambda_count += 1 + pname_buf: t.CChar | t.CPtr = pool.alloc(64) + if pname_buf is None: + return None + viperlib.snprintf(pname_buf, 64, "__lambda_%d", lambda_id) + mangled_promoted: str = self._mangle_name(trans, pname_buf) + + # 2. 解析参数(名称 + 类型,类型默认 i32,有注解则解析) + param_names: t.CChar | t.CPtr = pool.alloc(32 * 64) # 64 参数 × 32 字节名 + if param_names is None: + return None + string.memset(param_names, 0, 32 * 64) + param_tys: t.CVoid | t.CPtr = pool.alloc(8 * 64) # LLVMType 指针槽 + if param_tys is None: + return None + string.memset(param_tys, 0, 8 * 64) + param_count: int = 0 + if lam.args is not None: + ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(lam.args) + if ags.args is not None: + alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args + pn: t.CSizeT = alist.__len__() + for pi in range(pn): + if param_count >= 64: + break + arg_n: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(pi)) + if arg_n is None or arg_n.arg is None: + continue + string.strncpy(param_names + param_count * 32, arg_n.arg, 31) + p_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if arg_n.annotation is not None: + resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, arg_n.annotation, trans._imported_modules, trans._from_imports, trans) + if resolved is not None: + match resolved: + case llvmlite.LLVMType.Struct(_, _, _): + p_ty = llvmlite.Ptr(pool, resolved) + case _: + p_ty = resolved + ty_slot_p: str | t.CPtr = (t.CVoid | t.CPtr)( + t.CUInt64T(param_tys) + param_count * 8) + ty_slot_p[0] = p_ty + param_count += 1 + + # 3. 收集捕获变量(body 中的外部 Name 引用) + cap_names: t.CChar | t.CPtr = pool.alloc(64 * 64) # 64 捕获 × 64 字节名 + if cap_names is None: + return None + string.memset(cap_names, 0, 64 * 64) + cap_allocas: t.CVoid | t.CPtr = pool.alloc(8 * 64) # 父函数 alloca 指针槽 + if cap_allocas is None: + return None + string.memset(cap_allocas, 0, 8 * 64) + cap_tys: t.CVoid | t.CPtr = pool.alloc(8 * 64) # 捕获变量类型槽 + if cap_tys is None: + return None + string.memset(cap_tys, 0, 8 * 64) + cap_count: int = self._lambda_scan_body( + trans, lam.body, param_names, param_count, + cap_names, cap_allocas, cap_tys, 0) + + # 4. 创建提升函数 __lambda_{id}(i8* %env, [args...]) + func: llvmlite.Function | t.CPtr = llvmlite.create_function( + pool, mod, mangled_promoted, i32_ty) + if func is None: + return None + llvmlite.add_param(pool, func, i8_ptr_ty, "%env") + for pi2 in range(param_count): + ty_addr2: t.CUInt64T = t.CUInt64T(param_tys) + pi2 * 8 + ty_slot2: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr2) + p_ty2: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(ty_slot2[0]) + if p_ty2 is None: + p_ty2 = i32_ty + pname_l: t.CChar | t.CPtr = pool.alloc(32) + if pname_l is not None: + viperlib.snprintf(pname_l, 32, "%%%s", param_names + pi2 * 32) + llvmlite.add_param(pool, func, p_ty2, pname_l) + + # 5. entry 块 + builder + entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") + if entry_blk is None: + return None + func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) + if func_builder is None: + return None + llvmlite.position_at_end(func_builder, entry_blk) + + # 6. 进入 lambda 作用域 + HandlesVar.enter_scope(trans.SymTab, SCOPE_FUNCTION) + + # 7. _env_ptr alloca(存储 %env 参数) + env_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, i8_ptr_ty) + if env_alloca is not None: + HandlesVar.define_var(trans.SymTab, "_env_ptr", env_alloca) + env_param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "%env") + llvmlite.build_store(func_builder, env_param_val, env_alloca) + + # 8. 保存父函数状态并切换到提升函数 + old_func: llvmlite.Function | t.CPtr = trans._cur_func + old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + old_func_name: str = trans._cur_func_name + old_global_count: int = trans._global_name_count + old_nonlocal_count: int = trans._nonlocal_name_count + old_env_count: int = trans._closure_env_count + trans._cur_func = func + trans._cur_builder = func_builder + trans._cur_func_name = mangled_promoted + HT.clear_scope_names(trans) + + # 9. 捕获变量:从 env 堆槽加载值到局部 alloca + for ci in range(cap_count): + cap_addr: t.CUInt64T = t.CUInt64T(cap_names) + ci * 64 + cap_slot: t.CChar | t.CPtr = (t.CChar | t.CPtr)(cap_addr) + if cap_slot[0] == '\0': + continue + ty_addr3: t.CUInt64T = t.CUInt64T(cap_tys) + ci * 8 + ty_slot3: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr3) + cap_ty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(ty_slot3[0]) + if cap_ty is None: + continue + off_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, ci * 8) + slot_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + func_builder, i8_ty, env_param_val, off_val) + if slot_addr is None: + continue + storage_addr: llvmlite.Value | t.CPtr = llvmlite.build_load( + func_builder, i8_ptr_ty, slot_addr) + if storage_addr is None: + continue + st_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + func_builder, storage_addr, llvmlite.Ptr(pool, cap_ty)) + if st_typed is None: + continue + cap_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + func_builder, cap_ty, st_typed) + if cap_val is None: + continue + var_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, cap_ty) + if var_alloca is not None: + llvmlite.build_store(func_builder, cap_val, var_alloca) + HandlesVar.define_var(trans.SymTab, cap_slot, var_alloca) + + # 10. 参数 alloca + for pi3 in range(param_count): + ty_addr4: t.CUInt64T = t.CUInt64T(param_tys) + pi3 * 8 + ty_slot4: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr4) + p_ty3: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(ty_slot4[0]) + if p_ty3 is None: + p_ty3 = i32_ty + pname_ref: t.CChar | t.CPtr = pool.alloc(32) + if pname_ref is not None: + viperlib.snprintf(pname_ref, 32, "%%%s", param_names + pi3 * 32) + param_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, p_ty3, pname_ref) + arg_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, p_ty3) + if arg_alloca is not None: + llvmlite.build_store(func_builder, param_ref, arg_alloca) + HandlesVar.define_var(trans.SymTab, param_names + pi3 * 32, arg_alloca) + + # 11. 翻译 body 表达式,coerce 到 i32 后 ret + body_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + func_builder, pool, mod, lam.body, None, 0, trans) + if body_val is not None and body_val.Ty is not None: + if HandlesExpr.get_llvm_type_bits(body_val.Ty) == 32 \ + and HandlesExpr.is_ptr_type(body_val.Ty) == 0: + llvmlite.build_ret(func_builder, body_val) + else: + ret_val: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( + func_builder, body_val, i32_ty, lam.body) + if ret_val is not None: + llvmlite.build_ret(func_builder, ret_val) + else: + zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + llvmlite.build_ret(func_builder, zero_val) + else: + zero_val2: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + llvmlite.build_ret(func_builder, zero_val2) + + # 12. 退出 lambda 作用域,恢复父函数状态 + HandlesVar.exit_scope(trans.SymTab) + trans._cur_func = old_func + trans._cur_builder = old_builder + trans._cur_func_name = old_func_name + trans._global_name_count = old_global_count + trans._nonlocal_name_count = old_nonlocal_count + trans._closure_env_count = old_env_count + + # 13. 在父函数中创建 env(每个捕获变量 8 字节堆存储,env[i] = 堆地址) + env_ptr: llvmlite.Value | t.CPtr = None + if cap_count > 0: + env_size: t.CInt64T = cap_count * 8 + env_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, env_size) + if env_size_val is not None: + env_size_val.Next = None + env_ptr = llvmlite.build_call( + builder, "malloc", env_size_val, 1, i8_ptr_ty, 0) + if env_ptr is not None: + for ci3 in range(cap_count): + cap_addr3: t.CUInt64T = t.CUInt64T(cap_names) + ci3 * 64 + cap_slot3: t.CChar | t.CPtr = (t.CChar | t.CPtr)(cap_addr3) + if cap_slot3[0] == '\0': + continue + al_addr: t.CUInt64T = t.CUInt64T(cap_allocas) + ci3 * 8 + al_slot: str | t.CPtr = (t.CVoid | t.CPtr)(al_addr) + var_alloca2: llvmlite.Value | t.CPtr = ( + llvmlite.Value | t.CPtr)(al_slot[0]) + if var_alloca2 is None: + continue + ty_addr5: t.CUInt64T = t.CUInt64T(cap_tys) + ci3 * 8 + ty_slot5: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr5) + cap_ty2: llvmlite.LLVMType | t.CPtr = ( + llvmlite.LLVMType | t.CPtr)(ty_slot5[0]) + if cap_ty2 is None: + continue + # 堆存储大小:位宽/8,至少 8 字节(容纳指针/标量) + ty_bits: int = HandlesExpr.get_llvm_type_bits(cap_ty2) + st_size: int = 8 + if ty_bits > 64: + st_size = ty_bits // 8 + st_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, st_size) + if st_size_val is not None: + st_size_val.Next = None + var_storage: llvmlite.Value | t.CPtr = llvmlite.build_call( + builder, "malloc", st_size_val, 1, i8_ptr_ty, 0) + if var_storage is not None: + cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, cap_ty2, var_alloca2) + if cur_val is not None: + st_slot5: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, var_storage, llvmlite.Ptr(pool, cap_ty2)) + if st_slot5 is not None: + llvmlite.build_store(builder, cur_val, st_slot5) + off_val2: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, ci3 * 8) + slot2: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i8_ty, env_ptr, off_val2) + if slot2 is not None: + slot_typed2: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, slot2, i8_ptr_ptr_ty) + if slot_typed2 is not None: + llvmlite.build_store(builder, var_storage, slot_typed2) + + # 14. 在父函数中创建闭包 malloc(16) + closure_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 16) + if closure_size_val is not None: + closure_size_val.Next = None + closure_ptr: llvmlite.Value | t.CPtr = llvmlite.build_call( + builder, "malloc", closure_size_val, 1, i8_ptr_ty, 0) + if closure_ptr is None: + return None + + # 15. [0] = fn_ptr(函数引用 bitcast 到 i8*) + fn_param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) + fn_func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, fn_param_node, 1) + fn_func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, fn_func_ty) + fn_ptr_name: t.CChar | t.CPtr = pool.alloc(64) + if fn_ptr_name is not None: + if string.strchr(mangled_promoted, '.') is not None: + viperlib.snprintf(fn_ptr_name, 64, "@\"%s\"", mangled_promoted) + else: + viperlib.snprintf(fn_ptr_name, 64, "@%s", mangled_promoted) + fn_ptr_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, fn_func_ptr_ty, fn_ptr_name) + fn_as_i8ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, fn_ptr_val, i8_ptr_ty) + fn_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, closure_ptr, llvmlite.Ptr(pool, i8_ptr_ty)) + if fn_slot is not None and fn_as_i8ptr is not None: + llvmlite.build_store(builder, fn_as_i8ptr, fn_slot) + + # 16. [8] = env_ptr(无捕获存 null) + eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 8) + env_slot_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i8_ty, closure_ptr, eight_val) + if env_slot_addr is not None: + env_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, env_slot_addr, llvmlite.Ptr(pool, i8_ptr_ty)) + if env_slot is not None: + if env_ptr is not None: + llvmlite.build_store(builder, env_ptr, env_slot) + else: + null_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "null") + llvmlite.build_store(builder, null_val, env_slot) + + # 17. 返回闭包指针(i8*) + return closure_ptr + + # ============================================================ + # _lambda_scan_body - 递归扫描 lambda body 中的 Name 引用 + # + # 收集外部变量(排除 lambda 参数、模块级全局、已捕获项), + # 记录到 cap_names/cap_allocas/cap_tys 三个并行缓冲。 + # 返回更新后的捕获数量(递归调用逐层累加)。 + # ============================================================ + def _lambda_scan_body(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr, + param_names: t.CChar | t.CPtr, + param_count: int, + cap_names: t.CChar | t.CPtr, + cap_allocas: t.CVoid | t.CPtr, + cap_tys: t.CVoid | t.CPtr, + cap_count: int) -> int: + """递归扫描 lambda body 中的 Name 引用,收集捕获变量""" + if node is None or trans is None: + return cap_count + k: int = node.kind() + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is None: + return cap_count + # 排除 lambda 参数 + for pi in range(param_count): + if string.strcmp(param_names + pi * 32, nm.id) == 0: + return cap_count + # 已捕获跳过 + for ci in range(cap_count): + if string.strcmp(cap_names + ci * 64, nm.id) == 0: + return cap_count + # 查当前作用域链 + alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) + if alloca is None or alloca.Ty is None: + return cap_count + pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if pointee is None: + return cap_count + # 跳过模块级全局(body 直接解析全局,无需 env 捕获) + mod_gv: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(trans.SymTab, nm.id) + if mod_gv is not None: + if t.CUInt64T(mod_gv) == t.CUInt64T(alloca): + return cap_count + if cap_count >= 64: + return cap_count + string.strncpy(cap_names + cap_count * 64, nm.id, 63) + al_slot: str | t.CPtr = (t.CVoid | t.CPtr)( + t.CUInt64T(cap_allocas) + cap_count * 8) + al_slot[0] = alloca + ty_slot: str | t.CPtr = (t.CVoid | t.CPtr)( + t.CUInt64T(cap_tys) + cap_count * 8) + ty_slot[0] = pointee + return cap_count + 1 + # 递归遍历常见表达式子节点 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + cc1: int = self._lambda_scan_body(trans, bop.left, param_names, param_count, + cap_names, cap_allocas, cap_tys, cap_count) + return self._lambda_scan_body(trans, bop.right, param_names, param_count, + cap_names, cap_allocas, cap_tys, cc1) + if k == ast.ASTKind.UnaryOp: + uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + return self._lambda_scan_body(trans, uop.operand, param_names, param_count, + cap_names, cap_allocas, cap_tys, cap_count) + if k == ast.ASTKind.BoolOp: + bop2: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) + cc2: int = cap_count + if bop2.values is not None: + vs: list[ast.AST | t.CPtr] | t.CPtr = bop2.values + vn: t.CSizeT = vs.__len__() + for vi in range(vn): + cc2 = self._lambda_scan_body(trans, vs.get(vi), param_names, param_count, + cap_names, cap_allocas, cap_tys, cc2) + return cc2 + if k == ast.ASTKind.Compare: + cmp: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) + cc3: int = self._lambda_scan_body(trans, cmp.left, param_names, param_count, + cap_names, cap_allocas, cap_tys, cap_count) + if cmp.comparators is not None: + cl: list[ast.AST | t.CPtr] | t.CPtr = cmp.comparators + cn: t.CSizeT = cl.__len__() + for cvi in range(cn): + cc3 = self._lambda_scan_body(trans, cl.get(cvi), param_names, param_count, + cap_names, cap_allocas, cap_tys, cc3) + return cc3 + if k == ast.ASTKind.Call: + cal: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + cc4: int = self._lambda_scan_body(trans, cal.func, param_names, param_count, + cap_names, cap_allocas, cap_tys, cap_count) + if cal.args is not None: + als: list[ast.AST | t.CPtr] | t.CPtr = cal.args + an: t.CSizeT = als.__len__() + for ai in range(an): + cc4 = self._lambda_scan_body(trans, als.get(ai), param_names, param_count, + cap_names, cap_allocas, cap_tys, cc4) + if cal.keywords is not None: + kws: list[ast.AST | t.CPtr] | t.CPtr = cal.keywords + kn: t.CSizeT = kws.__len__() + for ki in range(kn): + kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(kws.get(ki)) + if kw is not None and kw.value is not None: + cc4 = self._lambda_scan_body(trans, kw.value, param_names, param_count, + cap_names, cap_allocas, cap_tys, cc4) + return cc4 + if k == ast.ASTKind.Subscript: + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + cc5: int = self._lambda_scan_body(trans, sub.value, param_names, param_count, + cap_names, cap_allocas, cap_tys, cap_count) + if sub.slice is not None: + cc5 = self._lambda_scan_body(trans, sub.slice, param_names, param_count, + cap_names, cap_allocas, cap_tys, cc5) + return cc5 + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + return self._lambda_scan_body(trans, at.value, param_names, param_count, + cap_names, cap_allocas, cap_tys, cap_count) + if k == ast.ASTKind.IfExp: + ie: ast.IfExp | t.CPtr = (ast.IfExp | t.CPtr)(node) + cc6: int = self._lambda_scan_body(trans, ie.test, param_names, param_count, + cap_names, cap_allocas, cap_tys, cap_count) + cc6 = self._lambda_scan_body(trans, ie.body, param_names, param_count, + cap_names, cap_allocas, cap_tys, cc6) + return self._lambda_scan_body(trans, ie.orelse, param_names, param_count, + cap_names, cap_allocas, cap_tys, cc6) + if k == ast.ASTKind.List: + ls: ast.List | t.CPtr = (ast.List | t.CPtr)(node) + cc7: int = cap_count + if ls.elts is not None: + es: list[ast.AST | t.CPtr] | t.CPtr = ls.elts + en: t.CSizeT = es.__len__() + for ei in range(en): + cc7 = self._lambda_scan_body(trans, es.get(ei), param_names, param_count, + cap_names, cap_allocas, cap_tys, cc7) + return cc7 + if k == ast.ASTKind.Lambda: + lam2: ast.Lambda | t.CPtr = (ast.Lambda | t.CPtr)(node) + return self._lambda_scan_body(trans, lam2.body, param_names, param_count, + cap_names, cap_allocas, cap_tys, cap_count) + return cap_count + # ============================================================ # 创建 LLVM 函数(简单版本,仅声明) # ============================================================ diff --git a/App/lib/core/Gen/TranslatorGenMixin.vp b/App/lib/core/Gen/TranslatorGenMixin.vp index afa0b1c..7f729d6 100644 --- a/App/lib/core/Gen/TranslatorGenMixin.vp +++ b/App/lib/core/Gen/TranslatorGenMixin.vp @@ -241,7 +241,9 @@ class TranslatorGenMixin: elts_count: t.CSizeT = elts.__len__() # 计算缓冲区大小: 每个元素最多 "i32 -9223372036854775808, " 约 26 字符 - buf_size: t.CSizeT = 64 + elts_count * 32 + # 按数组声明长度 arr_count 计算(元素不足时补零,可能多于 elts_count) + cnt_total: t.CSizeT = t.CSizeT(arr_count) + buf_size: t.CSizeT = 64 + cnt_total * 32 buf: t.CChar | t.CPtr = pool.alloc(buf_size) if buf is None: return None @@ -250,21 +252,25 @@ class TranslatorGenMixin: written: t.CInt = viperlib.snprintf(buf, buf_size, "[") pos: t.CSizeT = t.CSizeT(written) - # 逐个元素写入 + # 逐个元素写入:元素数必须与数组声明长度 arr_count 一致, + # 列表元素不足时补零(如 g_arr: t.CArray[t.CInt, 4] = [0] → + # [i32 0, i32 0, i32 0, i32 0]),否则 llc 报 + # "constant expression type mismatch: got type '[1 x i32]' but expected '[4 x i32]'" i: t.CSizeT = 0 - while i < elts_count: - elem_node: ast.AST | t.CPtr = elts.get(i) - # 直接从 Constant 节点提取 int_val(避免 extract_cdefine_int_value 的 t.CInt 截断) + while i < cnt_total: elem_val: t.CInt64T = 0 - if elem_node is not None: - ek: int = elem_node.kind() - if ek == ast.ASTKind.Constant: - ec: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(elem_node) - if ec is not None and ec.const_kind == ast.CONST_INT: - elem_val = ec.int_val - elif ek == ast.ASTKind.UnaryOp: - # 负数: UnaryOp(USub, Constant) - elem_val = HandlesAnnAssign.extract_cdefine_int_value(elem_node) + if i < elts_count: + elem_node: ast.AST | t.CPtr = elts.get(i) + # 直接从 Constant 节点提取 int_val(避免 extract_cdefine_int_value 的 t.CInt 截断) + if elem_node is not None: + ek: int = elem_node.kind() + if ek == ast.ASTKind.Constant: + ec: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(elem_node) + if ec is not None and ec.const_kind == ast.CONST_INT: + elem_val = ec.int_val + elif ek == ast.ASTKind.UnaryOp: + # 负数: UnaryOp(USub, Constant) + elem_val = HandlesAnnAssign.extract_cdefine_int_value(elem_node) if i > 0: written = viperlib.snprintf(buf + pos, buf_size - pos, ", ") pos += t.CSizeT(written) diff --git a/App/lib/core/Handles/HandlesAssign.vp b/App/lib/core/Handles/HandlesAssign.vp index 76bfcfd..11d8e61 100644 --- a/App/lib/core/Handles/HandlesAssign.vp +++ b/App/lib/core/Handles/HandlesAssign.vp @@ -294,8 +294,12 @@ class AssignHandle(HandlesBase.Mixin): if tk == ast.ASTKind.Attribute: # property setter 拦截: obj.attr = v 且 attr 是 @x.setter 方法时, # 生成 call Class.attr$set(obj, v),跳过字段存储 + # 注意参数顺序:_try_property_setter(pool, builder, mod, ...)—— + # 旧代码传 (builder, pool, ...) 导致 pool/builder 错位,pool 参数 + # 实际是 IRBuilder 对象,pool.alloc 虚调用读 IRBuilder[0] 当 vtable + # 跳到垃圾地址崩溃(BuiltinDecoratorTest Phase A 崩溃根因)。 if HandlesExprCall._try_property_setter( - builder, pool, mod, target, rhs_val, self.Trans) == 1: + pool, builder, mod, target, rhs_val, self.Trans) == 1: continue field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( builder, pool, mod, target, self.Trans) @@ -392,6 +396,13 @@ class AssignHandle(HandlesBase.Mixin): store_val = HandlesExpr.coerce_to_type( builder, rhs_val, alloca_ty, node) llvmlite.build_store(builder, store_val, alloca) + # lambda 表达式赋给变量:注册为闭包变量名, + # 调用分派(is_closure_name)才走闭包间接调用路径; + # 否则 i8** alloca 被 _is_func_ptr_alloca 误判为 + # 函数指针,无参 call 直接跳闭包数据崩溃 + if asgn.value is not None \ + and asgn.value.kind() == ast.ASTKind.Lambda: + HandlesExprCall.register_closure_name(nm.id) existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( self.Trans.SymTab, nm.id) if existing is None: diff --git a/App/lib/core/Handles/HandlesExpr.vp b/App/lib/core/Handles/HandlesExpr.vp index 4819840..07ababe 100644 --- a/App/lib/core/Handles/HandlesExpr.vp +++ b/App/lib/core/Handles/HandlesExpr.vp @@ -375,6 +375,26 @@ def translate_value(builder: llvmlite.IRBuilder | t.CPtr, return None +# ============================================================ +# 翻译 lambda 表达式 — 模块级委托 +# +# translate_lambda 定义在 FuncGenMixin(跨 Mixin 方法),ExprGenMixin +# 不能 self. 直接调用(NoVTable 下方法 mangle 成定义类符号,跨 Mixin +# self 调用会解析失败),与 translate_value 同模式走模块级委托。 +# ============================================================ +def translate_lambda(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译 lambda 表达式,返回闭包指针(i8*)(委托到 gen.translate_lambda)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.translate_lambda(builder, pool, mod, node, trans) + return None + + # ============================================================ # 翻译三元表达式 IfExp(test, body, orelse) # ============================================================ diff --git a/App/lib/core/Handles/HandlesExprCall.vp b/App/lib/core/Handles/HandlesExprCall.vp index 870b41e..f7498f8 100644 --- a/App/lib/core/Handles/HandlesExprCall.vp +++ b/App/lib/core/Handles/HandlesExprCall.vp @@ -1198,12 +1198,13 @@ def translate_closure_call(pool: memhub.MemBuddy | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, closure_alloca: llvmlite.Value | t.CPtr, cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT) -> llvmlite.Value | t.CPtr: + can: t.CSizeT, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: """通过闭包指针间接调用(委托到 gen.translate_closure_call)""" import lib.core.Gen.Generator as Generator g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) if g is not None: - return g.translate_closure_call(pool, builder, mod, closure_alloca, cargs, can) + return g.translate_closure_call(pool, builder, mod, closure_alloca, cargs, can, trans) return None # ============================================================ diff --git a/App/lib/core/Handles/HandlesTranslator.vp b/App/lib/core/Handles/HandlesTranslator.vp index f8f211e..c9fd161 100644 --- a/App/lib/core/Handles/HandlesTranslator.vp +++ b/App/lib/core/Handles/HandlesTranslator.vp @@ -122,6 +122,10 @@ class Translator: # 闭包 env 中的 nonlocal 变量偏移映射(每个 nonlocal 变量在 env 中的字节偏移) _closure_env_offsets: t.CInt _closure_env_count: t.CInt + # lambda 表达式全局唯一 ID 计数器(生成提升函数名 __lambda_{id}) + # 独立于 _closure_env_count:后者随函数进入被 clear_scope_names 重置, + # lambda ID 需跨函数全局唯一(提升函数名避免冲突) + _lambda_count: t.CInt # 泛型特化上下文:当前正在特化的类型参数名/实参名列表 # 由 _specialize_generic_class 设置,方法体翻译时用于将 T 替换为具体类型 @@ -177,6 +181,7 @@ class Translator: self.CurrentPackage = None self._closure_env_offsets = 0 self._closure_env_count = 0 + self._lambda_count = 0 self.GenericTypeParamNames = None self.GenericTypeArgs = None self._declare_only = 0