feat(gen): 支持 lambda 与 nonlocal 运行时 env 链式共享

- 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 编译崩溃)
This commit is contained in:
TermiNexus committed 2026-08-11 16:10:05 +08:00
1 parent 5c6ba308ae
commit c472ea9798
8 files changed
+763 -61

No files matched your search

+50 -11
View File
@@ -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=否"""
+57 -12
View File
@@ -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 查找失败后才检查
+596 -21
View File
@@ -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 函数(简单版本,仅声明)
# ============================================================
+20 -14
View File
@@ -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)
+12 -1
View File
@@ -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:
+20
View File
@@ -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)
# ============================================================
+3 -2
View File
@@ -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
# ============================================================
@@ -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