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:
1 parent
5c6ba308ae
commit
c472ea9798
8 files changed
+763
-61
No files matched your search
@@ -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=否"""
|
||||
|
||||
@@ -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 查找失败后才检查
|
||||
|
||||
@@ -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 函数(简单版本,仅声明)
|
||||
# ============================================================
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
# ============================================================
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user