Files
ViperC/App/lib/core/Gen/FuncGenMixin.vp
T
TermiNexus 9d3483e97e refactor: 全面 fail-fast 化(去兜底)+ 泛型补译/解引用宽度修复
- 全量降级点改 fail-fast:23 文件约 140+ 处静默 i32/i8*/void/continue 兜底改为 HandlesType.fatal_error(python traceback 风格)或 VLogger.error 终止,暴露上游根因;保留语言语义默认(无注解 i32/infer 链/CIf/star 回退)
- 泛型特化 Phase B 补译 reemit 强制发射方法体(修复 list[...] define 缺失)
- c.Deref 读取宽度仅按赋值直接 RHS 推断(修复 CurAssignAnnot 残留误判 i32)
- 类型别名清理:t.CChar|t.CPtr→str、t.CInt→int 等
2026-08-13 02:11:49 +08:00

2071 lines
110 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import viperlib
import stdio
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
import lib.core.Handles.HandlesClassDef as HandlesClassDef
# ============================================================
# FuncGenMixin - 函数/方法声明与翻译 Mixin(对象化 P5-1,wiki/14-oo-refactor.md)
#
# 从 HandlesFunctions.vp 迁移:模块级纯函数(trans 首参,无全局状态)
# → 类方法(self 替代,trans 参数保留)。
#
# 迁移原则(与 P2/P3/P4 一致,行为零变化):
# 1. 方法保留原函数签名(含 trans 首参),仅函数体内的
# 本模块函数调用改为 self.xxx(...)
# 2. 外部模块调用(HandlesExprCall.xxx/HandlesType.xxx 等)保留模块前缀
# 3. HandlesFunctions.vp 原函数保留为"委托":本地模块级单例 _g_gen
# (BuildPipeline/main 注入)cast 成 Generator 类型
#
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
# ============================================================
# ============================================================
# HandlesFunctions - 函数定义处理(trans 单参模式)
#
# 参考 Python 版 TransPyC FunctionHandle
#
# 函数有自己的局部作用域,通过 HandlesVar.enter_scope/exit_scope
# 管理嵌套作用域链,翻译函数体前进入函数作用域,翻译完退出。
# ============================================================
# 作用域类型常量(本地副本,与 HandlesFunctions.vp 保持一致)
SCOPE_FUNCTION: t.CDefine = 1
# ============================================================
# FuncGenMixin - 函数属性/命名/声明/翻译
# ============================================================
@t.NoVTable
class FuncGenMixin:
"""函数/方法翻译 Mixin(纯方法化迁移,无状态字段)"""
# ============================================================
# extract_func_attrs - 从 decorator_list 提取 c.Attribute 属性
#
# 支持 @c.Attribute(t.attr.xxx()) 和 @c.Attribute(t.attr.xxx) 形式
# 也支持 @c.Attribute(t.attr.llvm.xxx) 形式
#
# 返回 LLVM IR 属性字符串(如 "alwaysinline nounwind"),无属性返回 None
# ============================================================
def extract_func_attrs(self, pool: memhub.MemBuddy | t.CPtr,
decorator_list: list[ast.AST | t.CPtr] | t.CPtr,
imported_modules: str) -> str:
"""从 decorator_list 提取 c.Attribute 属性,返回 LLVM IR 属性字符串"""
if decorator_list is None:
return None
dn: t.CSizeT = len(decorator_list)
if dn == 0:
return None
attrs_buf: str = pool.alloc(256)
if attrs_buf is None:
return None
attrs_buf[0] = '\0'
found_any: int = 0
for di in range(dn):
deco: ast.AST | t.CPtr = decorator_list.get(di)
if deco is None or deco.kind() != ast.ASTKind.Call:
continue
call_node: ast.Call | t.CPtr = (ast.Call | t.CPtr)(deco)
if call_node.func is None or call_node.func.kind() != ast.ASTKind.Attribute:
continue
# 检测 c.Attribute
func_attr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(call_node.func)
if func_attr.attr is None or string.strcmp(func_attr.attr, "Attribute") != 0:
continue
if func_attr.value is None or func_attr.value.kind() != ast.ASTKind.Name:
continue
c_name: ast.Name | t.CPtr = (ast.Name | t.CPtr)(func_attr.value)
if c_name.id is None or string.strcmp(c_name.id, "c") != 0:
continue
if HandlesImports.is_module_imported(imported_modules, "c") == 0:
continue
# 遍历参数提取属性
if call_node.args is None:
continue
args_list: list[ast.AST | t.CPtr] | t.CPtr = call_node.args
an: t.CSizeT = len(args_list)
for ai in range(an):
arg_node: ast.AST | t.CPtr = args_list.get(ai)
if arg_node is None:
continue
# 提取属性名(t.attr.xxx / t.attr.xxx() / t.attr.llvm.xxx)
attr_name: str = self._get_attr_name_from_node(arg_node)
if attr_name is None:
continue
# 映射到 LLVM 属性名并追加
if self._append_llvm_attr(attrs_buf, attr_name) != 0:
found_any = 1
# 追加成功后,如果不是最后一个属性,添加空格分隔
# 在下一次追加前由 _append_str 处理
if found_any == 0:
return None
return attrs_buf
def _get_attr_name_from_node(self, node: ast.AST | t.CPtr) -> str:
"""从 AST 节点提取属性名
支持:
- Call(func=Attribute(...)): t.attr.always_inline() -> "always_inline"
- Attribute: t.attr.packed -> "packed"
- Attribute(t.attr.llvm.xxx): t.attr.llvm.nounwind -> "nounwind"
"""
if node is None:
return None
k: int = node.kind()
# Call 节点: t.attr.always_inline()
if k == ast.ASTKind.Call:
call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
if call.func is None or call.func.kind() != ast.ASTKind.Attribute:
return None
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(call.func)
return at.attr
# Attribute 节点: t.attr.packed 或 t.attr.llvm.nounwind
if k == ast.ASTKind.Attribute:
at2: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
return at2.attr
return None
def _append_llvm_attr(self, attrs_buf: str, attr_name: str) -> int:
"""将属性名映射到 LLVM 属性名并追加到缓冲区
返回 1 表示已追加,0 表示不支持该属性
"""
if attrs_buf is None or attr_name is None:
return 0
# 先确定映射的 LLVM 属性名
llvm_name: str = None
if string.strcmp(attr_name, "always_inline") == 0:
llvm_name = "alwaysinline"
elif string.strcmp(attr_name, "noinline") == 0:
llvm_name = "noinline"
elif string.strcmp(attr_name, "noreturn") == 0:
llvm_name = "noreturn"
elif string.strcmp(attr_name, "pure") == 0:
llvm_name = "readonly"
elif string.strcmp(attr_name, "const") == 0:
llvm_name = "readnone"
elif string.strcmp(attr_name, "nounwind") == 0:
llvm_name = "nounwind"
elif string.strcmp(attr_name, "noredzone") == 0:
llvm_name = "noredzone"
elif string.strcmp(attr_name, "willreturn") == 0:
llvm_name = "willreturn"
elif string.strcmp(attr_name, "mustprogress") == 0:
llvm_name = "mustprogress"
else:
# packed/aligned/section/visibility/weak 等不支持作为函数内联属性
return 0
# 支持的属性:如果缓冲区非空,先追加空格分隔
if attrs_buf[0] != '\0':
self._append_str(attrs_buf, " ")
self._append_str(attrs_buf, llvm_name)
return 1
def _append_str(self, buf: str, s: str,
max_len: t.CSizeT = 256) -> None:
"""将字符串追加到 buf 末尾(有界,防 strcpy 越界写穿定长缓冲)"""
if buf is None or s is None:
return
cur_len: t.CSizeT = string.strlen(buf)
s_len: t.CSizeT = string.strlen(s)
if cur_len + s_len + 1 > max_len:
return # 无剩余容量:丢弃本次追加,避免越界写
string.strcpy(buf + cur_len, s)
# ============================================================
# _mangle_name - 为名称添加 SHA1 前缀
#
# 返回 "sha1.name" 格式的混淆名。若 ModuleSha1 为 None 或名称已带
# SHA1 前缀(16 hex + '.'),则原样返回。
# ============================================================
def _mangle_name(self, trans: HT.Translator | t.CPtr, name: str) -> str:
"""为任意名称添加 SHA1 前缀(不做 main/export 检查)"""
if trans is None or name is None:
return name
if trans.ModuleSha1 is None:
return name
name_len: t.CSizeT = string.strlen(name)
# 已带 SHA1 前缀(16 hex + '.')则跳过
if name_len > 17:
is_sha1: int = 1
for i in range(16):
c: t.CChar = name[i]
if not (('0' <= c <= '9') or ('a' <= c <= 'f')):
is_sha1 = 0
break
if is_sha1 != 0 and name[16] == '.':
return name
sha1: str = trans.ModuleSha1
sha1_len: t.CSizeT = string.strlen(sha1)
mangled: str = stdlib.malloc(sha1_len + name_len + 2)
if mangled is None:
return name
string.strcpy(mangled, sha1)
mangled[sha1_len] = '.'
string.strcpy(mangled + sha1_len + 1, name)
return mangled
# ============================================================
# _mangle_name_with_sha1 — 用指定 SHA1 为名称添加前缀
#
# 用于跨模块 vtable 继承: 继承方法需要用父模块的 SHA1 做 mangling,
# 而非当前模块的 SHA1。
# ============================================================
def _mangle_name_with_sha1(self, sha1: str, name: str) -> str:
"""用指定 SHA1 为名称添加前缀(不做 main/export 检查)"""
if sha1 is None or name is None:
return name
name_len: t.CSizeT = string.strlen(name)
# 已带 SHA1 前缀(16 hex + '.')则跳过
if name_len > 17:
is_sha1: int = 1
for i in range(16):
c2: t.CChar = name[i]
if not (('0' <= c2 <= '9') or ('a' <= c2 <= 'f')):
is_sha1 = 0
break
if is_sha1 != 0 and name[16] == '.':
return name
sha1_len: t.CSizeT = string.strlen(sha1)
mangled: str = stdlib.malloc(sha1_len + name_len + 2)
if mangled is None:
return name
string.strcpy(mangled, sha1)
mangled[sha1_len] = '.'
string.strcpy(mangled + sha1_len + 1, name)
return mangled
# ============================================================
# _mangle_func_name - 为函数名添加 SHA1 前缀(含 main/export 检查)
#
# 规则:
# - main 函数不加前缀(程序入口点)
# - has_export 非 0 时不加前缀(t.CExport 导出函数)
# - 已带 SHA1 前缀的不再加
# - ModuleSha1 为 None 时不加前缀
# ============================================================
def _mangle_func_name(self, trans: HT.Translator | t.CPtr, name: str,
has_export: int) -> str:
"""为函数名添加 SHA1 前缀(检查 main/export)"""
if trans is None or name is None:
return name
if has_export != 0:
return name
if string.strcmp(name, "main") == 0:
return name
return self._mangle_name(trans, name)
# ============================================================
# forward_declare_functions - 预扫描所有顶层 FunctionDef,创建前向声明
#
# 解决同模块内前向引用问题:如 viperlib.py 中 sprintf(行15) 调用
# vsnprintf(行41),但 vsnprintf 定义在后面。
#
# 对每个顶层 FunctionDef:
# 1. 推断返回类型和参数类型
# 2. 计算 mangled name(含 SHA1 前缀)
# 3. 创建 declare(IsDeclared=1)
# 4. 添加参数
# 5. 注册到函数表
#
# 后续 translate_function_def 会通过 find_func_in_module 找到已有的 declare,
# 复用之(清除 IsDeclared,跳过参数创建,直接添加函数体)。
# ============================================================
def forward_declare_functions(self, trans: HT.Translator | t.CPtr,
tree: ast.AST | t.CPtr) -> int:
"""预扫描所有顶层 FunctionDef,创建前向声明"""
if trans is None or tree is None:
return 0
pool: memhub.MemBuddy | t.CPtr = trans.Pool
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
if pool is None or mod is None:
return 0
imported_modules: str = trans._imported_modules
from_imports: str = trans._from_imports
funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs
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)
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
if ch is None:
return 0
# 解析函数签名期间临时切换到"仅声明"模式:
# 签名里的泛型类注解(如 _empty_like(a: ndarray[t.CDouble]))会触发泛型特化,
# 若此时特化立即翻译方法体,方法体前向引用同模块后续函数(如 _empty_like 自身)
# 会因 declare 尚未创建而报"裸名调用未定义且未导入"。
# 临时 declare_only=1 使特化只注册结构体(mark_only 不译方法体),
# 方法体由后续 resolve_annotation_type 命中已注册结构体时补译
# (_specialize_generic_class 的 Phase B 补译分支)。
saved_declare_only: int = trans._declare_only
trans._declare_only = 1
cn_count: t.CSizeT = len(ch)
for ci in range(cn_count):
child: ast.AST | t.CPtr = ch.get(ci)
if child is None:
continue
if child.kind() != ast.ASTKind.FunctionDef:
continue
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child)
if fd is None or fd.name is None:
continue
# 推断返回类型
ret_ty: llvmlite.LLVMType | t.CPtr = None
if fd.returns is not None:
ret_ty = HandlesType.resolve_annotation_type(
pool, fd.returns, imported_modules, from_imports, trans)
if ret_ty is None and fd.returns is not None:
if HandlesType.has_decorator_marker(fd.returns, "State") != 0:
ret_ty = llvmlite.Void(pool)
if ret_ty is None:
ret_ty = i32_ty
# 检测 CExtern/State/CExport
has_extern: int = 0
has_state: int = 0
has_export: int = 0
if fd.returns is not None:
has_extern = HandlesType.has_decorator_marker(fd.returns, "CExtern")
has_state = HandlesType.has_decorator_marker(fd.returns, "State")
has_export = HandlesType.has_decorator_marker(fd.returns, "CExport")
# 装饰器形式存储类标记(@t.CExport/@t.CExtern/@t.State/@t.CStatic)
# 对齐 TPC HandlesFunctions._extract_decorator_storage_flags;
# CExport/CExtern/State 影响函数名(导出裸名),CStatic 仅标记。
# 注意: 用 HandlesClassDef._has_decorator 委托而非 self._has_decorator
# (Mixin 是 @t.NoVTable 静态绑定,跨 Mixin 方法经 MRO 调用会生成
# 不存在的 FuncGenMixin._has_decorator → 链接 undefined symbol)
if fd.decorator_list is not None:
if has_extern == 0 and HandlesClassDef._has_decorator(fd.decorator_list, "CExtern") == 1:
has_extern = 1
if has_state == 0 and HandlesClassDef._has_decorator(fd.decorator_list, "State") == 1:
has_state = 1
if has_export == 0 and HandlesClassDef._has_decorator(fd.decorator_list, "CExport") == 1:
has_export = 1
is_extern_decl: int = 0
if has_extern != 0 or has_state != 0:
is_extern_decl = 1
# 计算 mangled name
if has_extern != 0 or has_state != 0 or has_export != 0 or string.strcmp(fd.name, "main") == 0:
mangled_name: str = fd.name
else:
mangled_name = self._mangle_func_name(trans, fd.name, 0)
# 如果函数已存在(如重复定义),跳过
existing: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name)
if existing is not None:
continue
# 创建 declare
func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
pool, mod, mangled_name, ret_ty)
if func is None:
continue
# 提取默认参数信息
# 注意: 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(),
# 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错
fd_args_node: ast.Arguments | t.CPtr = fd.args
fd_defaults: t.CVoid | t.CPtr = None
fd_default_count: int = 0
fd_param_count: int = 0
if fd_args_node is not None:
fd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd_args_node)
if fd_ags.args is not None:
fd_alist: list[ast.AST | t.CPtr] | t.CPtr = fd_ags.args
fd_param_count = len(fd_alist)
if fd_ags.defaults is not None:
fd_dlist: list[ast.AST | t.CPtr] | t.CPtr = fd_ags.defaults
fd_defaults = fd_dlist
fd_default_count = len(fd_dlist)
# 注册到函数表(用裸名 fd.name,不是 mangled_name)
max_funcs: int = 256
cur_count: int = trans._func_count
if HandlesExprCall.add_func_to_table(funcs_ptr, cur_count, fd.name, func, max_funcs,
fd_defaults, fd_default_count, fd_param_count,
trans.Pool) == 0:
trans._func_count = cur_count + 1
# 注册 CExport 函数到全局表
if (has_export != 0 or has_state != 0) and trans.ModuleSha1 is not None:
HandlesExprCall.register_cexport_func(trans.ModuleSha1, fd.name)
# 添加参数
args_node: ast.Arguments | t.CPtr = fd.args
if args_node is not None:
ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
if ags.args is not None:
alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args
an: t.CSizeT = len(alist)
for ai in range(an):
arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai))
if arg is None or arg.arg is None:
continue
# t.CVoid 表示空参:跳过
if arg.annotation is not None:
if HandlesType._is_t_attr(arg.annotation, "CVoid", imported_modules) != 0:
continue
param_ty: llvmlite.LLVMType | t.CPtr = i32_ty
if arg.annotation is not None:
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, arg.annotation, imported_modules, from_imports, trans)
if resolved is not None:
# 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致)
# CArray 形参 → 元素指针 ty*(C 数组衰减,与 add_param 一致)
match resolved:
case llvmlite.LLVMType.Struct(_, _, _):
param_ty = llvmlite.Ptr(pool, resolved)
case llvmlite.LLVMType.Array(aelem_ty, _):
param_ty = llvmlite.Ptr(pool, aelem_ty)
case _:
param_ty = resolved
pname: str = pool.alloc(32)
if pname is not None:
viperlib.snprintf(pname, 32, "%%%s", arg.arg)
llvmlite.add_param(pool, func, param_ty, pname)
# *args 变长参数:设置 IsVarArg=1,生成 ... 后缀
if ags.vararg is not None:
func.IsVarArg = 1
# 参数添加完成,补全全局函数表的 TypeStr(供 vtable 在 func 被 reset 后使用)
HandlesExprCall.update_global_func_typestr(trans.Pool, fd.name, func)
# 恢复原始声明模式
trans._declare_only = saved_declare_only
return 0
# ============================================================
# 翻译函数定义 FunctionDef(name, args, body, ...)
#
# trans 单参模式:所有共享状态从 trans 获取
# 函数局部作用域通过 enter_scope/exit_scope 管理
# ============================================================
def translate_function_def(self, trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译函数定义,返回新增的变量数(通常为 0,函数定义不增加当前作用域变量)"""
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node)
if fd is None or fd.name is None:
return 0
pool: memhub.MemBuddy | t.CPtr = trans.Pool
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
imported_modules: str = trans._imported_modules
from_imports: str = trans._from_imports
funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs
func_count: int = trans._func_count
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
# 推断返回类型:优先使用返回类型注解
ret_ty: llvmlite.LLVMType | t.CPtr = None
if fd.returns is not None:
ret_ty = HandlesType.resolve_annotation_type(
pool, fd.returns, imported_modules, from_imports, trans)
# 如果返回类型注解纯装饰器标记(如 t.State,无实际类型),使用 void
# 注意:必须在 infer_return_type 之前检测,因为 infer_return_type 至少返回 i32
if ret_ty is None and fd.returns is not None:
if HandlesType.has_decorator_marker(fd.returns, "State") != 0:
ret_ty = llvmlite.Void(pool)
# 如果仍然为 None,扫描 return 语句推断(至少返回 i32)
if ret_ty is None:
param_types_str: str = HandlesType.build_param_types_str(pool, fd.args)
ret_ty = HandlesType.infer_return_type(
pool, fd.children, param_types_str)
# 检测是否为外部声明函数(t.CExtern 或 t.State)
# 语义:t.CExtern 忽略 body 体,仅生成 declare(由链接器解析符号)
# t.State = t.CExtern + t.CExport(既是声明又是导出)
# t.CExport 导出函数不加 SHA1 前缀
# t.CExtern/t.State/t.CExport 都不加 SHA1 前缀,直接映射到 C 标准库函数名
is_extern_decl: int = 0
has_export: int = 0
has_extern: int = 0
has_state: int = 0
if fd.returns is not None:
has_extern = HandlesType.has_decorator_marker(fd.returns, "CExtern")
has_state = HandlesType.has_decorator_marker(fd.returns, "State")
has_export = HandlesType.has_decorator_marker(fd.returns, "CExport")
# t.CExtern/t.State 忽略 body 体,仅声明(无论 body 是否为 pass)
if has_extern != 0 or has_state != 0:
is_extern_decl = 1
# 装饰器形式存储类标记(@t.CExport/@t.CExtern/@t.State/@t.CStatic),
# 对齐 TPC HandlesFunctions._extract_decorator_storage_flags(与
# forward_declare_functions 一致,保证 declare 与 define 同名同语义)。
# 用 HandlesClassDef._has_decorator 委托(Mixin 静态绑定不能 self. 跨类调)
if fd.decorator_list is not None:
if has_extern == 0 and HandlesClassDef._has_decorator(fd.decorator_list, "CExtern") == 1:
has_extern = 1
if has_state == 0 and HandlesClassDef._has_decorator(fd.decorator_list, "State") == 1:
has_state = 1
if has_export == 0 and HandlesClassDef._has_decorator(fd.decorator_list, "CExport") == 1:
has_export = 1
if (has_extern != 0 or has_state != 0) and is_extern_decl == 0:
is_extern_decl = 1
# SHA1 命名空间:t.CExtern/t.State/t.CExport 不加前缀,直接用裸名
# (裸名映射到 C 标准库符号,带 sha1 前缀会导致 undefined reference)
# main 函数也不加前缀(程序入口点)
if has_extern != 0 or has_state != 0 or has_export != 0 or string.strcmp(fd.name, "main") == 0:
mangled_name: str = fd.name
else:
mangled_name: str = self._mangle_func_name(trans, fd.name, 0)
# 注册 CExport 函数到全局表(供跨模块调用查表)
# t.CExport 函数定义用裸名(@strlen),跨模块调用需查表确认用裸名而非 @{sha1}.func
if (has_export != 0 or has_state != 0) and trans.ModuleSha1 is not None:
HandlesExprCall.register_cexport_func(trans.ModuleSha1, fd.name)
if is_extern_decl != 0:
# 外部声明函数:生成 declare(仅声明,不定义)
# 先检查是否已由 forward_declare_functions 创建,避免重复 declare
existing_extern: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name)
if existing_extern is not None:
# 已存在前向声明,复用之,不再重复创建
return 0
func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
pool, mod, mangled_name, ret_ty)
if func is None:
return 0
# 注册到函数表
max_funcs_extern: int = 256
if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs_extern, None, 0, 0, pool) == 0:
trans._func_count = func_count + 1
# 添加参数(支持类型注解)
args_node_extern: ast.Arguments | t.CPtr = fd.args
if args_node_extern is not None:
ags_e: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node_extern)
if ags_e.args is not None:
alist_e: list[ast.AST | t.CPtr] | t.CPtr = ags_e.args
an_e: t.CSizeT = len(alist_e)
for ai_e in range(an_e):
arg_e: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist_e.get(ai_e))
if arg_e is not None and arg_e.arg is not None:
# t.CVoid 表示空参:跳过,不添加到函数签名
if arg_e.annotation is not None \
and HandlesType._is_t_attr(arg_e.annotation, "CVoid", imported_modules) != 0:
continue
param_ty_e: llvmlite.LLVMType | t.CPtr = i32_ty
if arg_e.annotation is not None:
resolved_e: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, arg_e.annotation, imported_modules, from_imports, trans)
if resolved_e is None:
# fail-fast:外部声明函数参数有注解但类型解析失败,
# 不再静默保持 i32(声明签名错误会在 ABI 层暴露)
HandlesType.fatal_error(
arg_e, f"参数 '{arg_e.arg}' 类型解析失败: {HandlesType.annotation_to_str(arg_e.annotation)}",
"NameError")
resolved_e = i32_ty # 不可达(fatal_error 已退出)
if resolved_e is not None:
# 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致)
# CArray 形参 → 元素指针 ty*(C 数组衰减)
match resolved_e:
case llvmlite.LLVMType.Struct(_, _, _):
param_ty_e = llvmlite.Ptr(pool, resolved_e)
case llvmlite.LLVMType.Array(aelem_ty_e, _):
param_ty_e = llvmlite.Ptr(pool, aelem_ty_e)
case _:
param_ty_e = resolved_e
pname_e: str = pool.alloc(32)
if pname_e is not None:
viperlib.snprintf(pname_e, 32, "%%%s", arg_e.arg)
llvmlite.add_param(pool, func, param_ty_e, pname_e)
# 提取 @c.Attribute 装饰器属性并设置到函数
func_attrs_e: str = self.extract_func_attrs(pool, fd.decorator_list, imported_modules)
if func_attrs_e is not None:
llvmlite.function_set_attrs(func, func_attrs_e)
# 参数添加完成,补全全局函数表的 TypeStr
HandlesExprCall.update_global_func_typestr(pool, fd.name, func)
return 0
# args_node 用于后续 alloca 创建,提前赋值
args_node: ast.Arguments | t.CPtr = fd.args
# 检查是否已有前向声明(由 forward_declare_functions 创建)
func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name)
if func is not None and llvmlite.function_is_declared(func) != 0:
# 复用前向声明:清除 IsDeclared 标记,转为 define
func.IsDeclared = 0
# 装饰器属性设置(前向声明时未设置)
func_attrs_reuse: str = self.extract_func_attrs(pool, fd.decorator_list, imported_modules)
if func_attrs_reuse is not None:
llvmlite.function_set_attrs(func, func_attrs_reuse)
else:
# 创建新的 LLVM 函数(使用 SHA1 混淆名)
func = llvmlite.create_function(pool, mod, mangled_name, ret_ty)
if func is None:
fb_cf: str = VLogger.fmt_buf()
if fb_cf is not None:
viperlib.snprintf(fb_cf, 1024, "create_function %s failed", fd.name)
VLogger.error(fb_cf, "FUNC")
return 0
# 提取 @c.Attribute 装饰器属性并设置到函数
func_attrs: str = self.extract_func_attrs(pool, fd.decorator_list, imported_modules)
if func_attrs is not None:
llvmlite.function_set_attrs(func, func_attrs)
# 提取默认参数信息
tfd_defaults: t.CVoid | t.CPtr = None
tfd_default_count: int = 0
tfd_param_count: int = 0
if args_node is not None:
tfd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
if tfd_ags.args is not None:
tfd_alist: list[ast.AST | t.CPtr] | t.CPtr = tfd_ags.args
tfd_param_count = len(tfd_alist)
if tfd_ags.defaults is not None:
tfd_dlist: list[ast.AST | t.CPtr] | t.CPtr = tfd_ags.defaults
tfd_defaults = tfd_dlist
tfd_default_count = len(tfd_dlist)
# 注册到函数表
max_funcs: int = 256
if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs,
tfd_defaults, tfd_default_count, tfd_param_count,
trans.Pool) == 0:
trans._func_count = func_count + 1
# 添加参数(支持类型注解)
if args_node is not None:
ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
if ags.args is not None:
alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args
an: t.CSizeT = len(alist)
for ai in range(an):
arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai))
if arg is not None and arg.arg is not None:
# t.CVoid 表示空参:跳过,不添加到函数签名
if arg.annotation is not None \
and HandlesType._is_t_attr(arg.annotation, "CVoid", imported_modules) != 0:
continue
param_ty: llvmlite.LLVMType | t.CPtr = i32_ty
if arg.annotation is not None:
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, arg.annotation, imported_modules, from_imports, trans)
if resolved is not None:
# 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致)
# CArray 形参 → 元素指针 ty*(C 数组衰减:final(out: t.CArray[..., N])
# 的 out 指向调用方数组首元素;传 Ptr(数组) 会使 out[i] 的
# GEP 以整个数组为步长错位,摘要垃圾根因)
match resolved:
case llvmlite.LLVMType.Struct(_, _, _):
param_ty = llvmlite.Ptr(pool, resolved)
case llvmlite.LLVMType.Array(aelem_ty, _):
param_ty = llvmlite.Ptr(pool, aelem_ty)
case _:
param_ty = resolved
pname: str = pool.alloc(32)
if pname is not None:
viperlib.snprintf(pname, 32, "%%%s", arg.arg)
llvmlite.add_param(pool, func, param_ty, pname)
# *args 变长参数:设置 IsVarArg=1,生成 ... 后缀
if ags.vararg is not None:
func.IsVarArg = 1
# 参数添加完成,补全全局函数表的 TypeStr
HandlesExprCall.update_global_func_typestr(trans.Pool, fd.name, func)
# 创建 entry 块
entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry")
if entry_blk is None:
return 0
# 创建函数专属 builder
func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func)
if func_builder is None:
return 0
llvmlite.position_at_end(func_builder, entry_blk)
# 进入函数作用域(嵌套符号表)
HandlesVar.enter_scope(trans.SymTab, SCOPE_FUNCTION)
# PEP 695 泛型函数: def f[T](...) — 设置泛型上下文,类型参数映射到 "int" 兜底。
# TPV 无泛型函数特化机制(类泛型走 _specialize_generic_class),泛型函数按普通
# 函数编译;设置上下文使参数注解 T / 方法体中的 T(x) 转换可解析为 int。
# (注意与类特化的 set_generic_context 一样是全局状态,需在退出作用域前清除。)
tp_names_fn: list[str] | t.CPtr = None
if fd.type_params is not None:
tp_names_fn = fd.type_params
tp_args_fn: list[str] | t.CPtr = list[str](pool, 8)
if tp_args_fn is not None:
tpn_fn: t.CSizeT = len(fd.type_params)
tpi_fn: t.CSizeT = 0
for tpi_fn in range(tpn_fn):
tp_args_fn.append("int")
HandlesType.set_generic_context(tp_names_fn, tp_args_fn)
# 为参数创建 alloca
if args_node is not None:
ags2: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
if ags2.args is not None:
alist2: list[ast.AST | t.CPtr] | t.CPtr = ags2.args
an2: t.CSizeT = len(alist2)
for ai2 in range(an2):
arg2: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist2.get(ai2))
if arg2 is not None and arg2.arg is not None:
# t.CVoid 表示空参:跳过,不创建 alloca
if arg2.annotation is not None:
if HandlesType._is_t_attr(arg2.annotation, "CVoid", imported_modules) != 0:
continue
param_ty2: llvmlite.LLVMType | t.CPtr = i32_ty
if arg2.annotation is not None:
resolved2: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, arg2.annotation, imported_modules, from_imports, trans)
if resolved2 is None:
# fail-fast:参数有注解但类型解析失败,不再静默保持 i32
HandlesType.fatal_error(
arg2, f"参数 '{arg2.arg}' 类型解析失败: {HandlesType.annotation_to_str(arg2.annotation)}",
"NameError")
resolved2 = i32_ty # 不可达(fatal_error 已退出)
if resolved2 is not None:
# 与 add_param 保持一致:裸类形参 → Ptr(struct)(对象即指针);
# CArray 形参 → 元素指针 ty*(数组衰减,alloca 类型须与形参一致,
# 否则 store ty* 到 [N x ty]* 容器类型不匹配)
match resolved2:
case llvmlite.LLVMType.Struct(_, _, _):
param_ty2 = llvmlite.Ptr(pool, resolved2)
case llvmlite.LLVMType.Array(aelem_ty2, _):
param_ty2 = llvmlite.Ptr(pool, aelem_ty2)
case _:
param_ty2 = resolved2
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, param_ty2)
if alloca is not None:
HandlesVar.define_var(trans.SymTab, arg2.arg, alloca)
# 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体)
cls_nm: str = None
if arg2.annotation is not None:
cls_nm = HandlesType.extract_class_name_from_annotation(
arg2.annotation, imported_modules)
if cls_nm is not None:
HandlesVar.set_var_annot_class_name(
trans.SymTab, arg2.arg, cls_nm)
pname2: str = pool.alloc(32)
if pname2 is not None:
viperlib.snprintf(pname2, 32, "%%%s", arg2.arg)
param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(
pool, param_ty2, pname2)
llvmlite.build_store(func_builder, param_val, alloca)
# *args 变长参数:创建 va_list 缓冲区 + 调用 va_start + 注册到符号表
# 生成 IR:
# %args_va = alloca [24 x i8], align 16 ; va_list 缓冲区(Win64 __va_list_tag)
# %args = bitcast [24 x i8]* %args_va to i8*
# call void @llvm.va_start(i8* %args) ; 初始化 va_list
# 用户函数体内可通过 args 名字读取 va_list 地址(i8*),或用 arg(type) 糖函数
if ags2.vararg is not None:
vararg_node: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(ags2.vararg)
if vararg_node is not None and vararg_node.arg is not None:
vararg_name_str: str = vararg_node.arg
# va_list 缓冲区 24 字节(Win64 的 __va_list_tag = {i32,i32,i8*,i8*})+ 16 对齐
# (对齐 TPC HandlesFunctions.py:1739-1741)
i8_ty_va: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty_va: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_va)
va_buf_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty_va, 24)
va_list_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca_aligned(
func_builder, va_buf_ty, 16)
if va_list_alloca is not None:
# i8* 地址(指向 24 字节 va_list 缓冲区)——vararg 名的值语义
va_list_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
func_builder, va_list_alloca, i8_ptr_ty_va)
if va_list_addr is not None:
# 注册到符号表(translate_name_value 对 vararg 名特殊处理返回地址)
HandlesVar.define_var(trans.SymTab, vararg_name_str, va_list_alloca)
# 调用 @llvm.va_start(i8* %va_list_addr)
void_ty_va: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
llvmlite.build_call(func_builder, "llvm.va_start",
va_list_addr, 1, void_ty_va, 0)
# 保存到 trans 供 arg(type) 糖函数与 vararg 名翻译使用
trans._va_list_ptr = va_list_addr
trans._vararg_name = vararg_name_str
# 保存模块级作用域状态(仅非变量表相关)
old_func: llvmlite.Function | t.CPtr = trans._cur_func
old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
old_global_count: int = trans._global_name_count
old_nonlocal_count: int = trans._nonlocal_name_count
old_env_count: int = trans._closure_env_count
old_va_list_ptr: llvmlite.Value | t.CPtr = trans._va_list_ptr
old_vararg_name: str = trans._vararg_name
trans._cur_func = func
trans._cur_builder = func_builder
# 清空 global/nonlocal 名称集合(新函数作用域)
HT.clear_scope_names(trans)
# 重置链内 nonlocal 堆预建标志(每函数只建一次;多嵌套函数定义
# 共享同一堆,防重复 malloc + 二次重定向 VarEntry)
trans._nl_chain_done = 0
# 预扫描函数体:
# 1. 先预扫描 Global/Nonlocal 声明(Python 语义:global/nonlocal
# 对整个函数作用域生效,与声明位置无关,故须在任何赋值前注册)
# 2. 再预扫描 AnnAssign 为局部变量提前创建 alloca
body: list[ast.AST | t.CPtr] | t.CPtr = fd.children
if body is not None:
bn: t.CSizeT = len(body)
for bi in range(bn):
stmt: ast.AST | t.CPtr = body.get(bi)
if stmt is not None:
HandlesBody.pre_scan_scope_decls(trans, stmt)
for bi in range(bn):
stmt: ast.AST | t.CPtr = body.get(bi)
if stmt is not None:
HandlesBody.pre_scan_allocas(trans, stmt)
# 翻译函数体
if body is not None:
bn2: t.CSizeT = len(body)
for bi2 in range(bn2):
stmt2: ast.AST | t.CPtr = body.get(bi2)
if stmt2 is not None:
# 嵌套函数定义前:预扫描其链内 nonlocal 并建堆
# (不同层捕获不同变量的场景,见 _prepare_chain_nonlocals)
if stmt2.kind() == ast.ASTKind.FunctionDef:
self._prepare_chain_nonlocals(
trans, stmt2, pool, func_builder, mod,
llvmlite.Int8(pool), llvmlite.Ptr(pool, llvmlite.Int8(pool)))
HandlesBody.translate_stmt(trans, stmt2)
# 如果函数体最后一条语句不是 Return,添加隐式 ret
last_is_return: int = 0
if body is not None:
bn3: t.CSizeT = len(body)
if bn3 > 0:
last_stmt: ast.AST | t.CPtr = body.get(bn3 - 1)
if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return:
last_is_return = 1
if last_is_return == 0:
if llvmlite.builder_cur_block_is_terminated(func_builder) == 0:
# 根据返回类型生成正确的零值返回
# 必须覆盖浮点返回类型:double/float 函数生成 ConstFloat(0.0),
# 否则默认 ret i32 0 类型不匹配(llc: value doesn't match function result type)
_is_void: int = 0
_is_ptr: int = 0
_is_float: int = 0
if ret_ty is not None:
match ret_ty:
case llvmlite.LLVMType.Void():
_is_void = 1
case llvmlite.LLVMType.Ptr(_pe):
_is_ptr = 1
case llvmlite.LLVMType.Float(_fb):
_is_float = 1
if _is_void != 0:
llvmlite.build_ret_void(func_builder)
elif _is_ptr != 0:
_null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, ret_ty, "null")
llvmlite.build_ret(func_builder, _null_val)
elif _is_float != 0:
_zero_f: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, ret_ty, 0.0)
llvmlite.build_ret(func_builder, _zero_f)
else:
_zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
llvmlite.build_ret(func_builder, _zero_val)
# 恢复模块级作用域(退出函数作用域)
if tp_names_fn is not None:
HandlesType.clear_generic_context()
HandlesVar.exit_scope(trans.SymTab)
trans._cur_func = old_func
trans._cur_builder = old_builder
trans._global_name_count = old_global_count
trans._nonlocal_name_count = old_nonlocal_count
trans._closure_env_count = old_env_count
trans._va_list_ptr = old_va_list_ptr
trans._vararg_name = old_vararg_name
return 0
# ============================================================
# translate_nested_function_def - 嵌套函数提升 + 闭包创建
#
# 将嵌套函数提升为顶层函数 @__closure_{name}(i8* %env) -> i32,
# 在父函数中创建闭包对象 {i8* fn_ptr, i8* env_ptr} 并存储到
# 以函数名命名的局部变量中。
#
# 闭包结构: {i8* fn_ptr, i8* env_ptr} (16 字节, malloc 分配)
# Env 结构: {i8* ptr0, i8* ptr1, ...} (每个 nonlocal 变量 8 字节,指向父函数 alloca)
# ============================================================
def translate_nested_function_def(self, trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译嵌套函数定义:提升为顶层函数 + 创建闭包"""
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node)
if fd is None or fd.name is None:
return 0
pool: memhub.MemBuddy | t.CPtr = trans.Pool
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
func_name: str = fd.name
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)
# 1. 构建提升后的函数名: __closure_{name}(加 SHA1 前缀避免跨模块冲突)
promoted_name: str = pool.alloc(64)
if promoted_name is not None:
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, 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 = len(alist_n)
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 llvmlite.LLVMType.Array(aelem_ty_n, _):
pty_n = llvmlite.Ptr(pool, aelem_ty_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: str = 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:
return 0
func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func)
if func_builder is None:
return 0
llvmlite.position_at_end(func_builder, entry_blk)
# 4. 进入嵌套函数作用域(嵌套符号表)
HandlesVar.enter_scope(trans.SymTab, SCOPE_FUNCTION)
# 5. 创建 _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)
# 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 = len(alist_p)
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: str = 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
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
# nonlocal 集合独立缓冲:嵌套函数注册 nonlocal 写入共享缓冲 [0] 会
# 覆盖父函数集合(ClosureTest2 Test 7 不同变量场景:level2 的 b 覆盖
# level1 的 a → level1 env[0] 存错)。嵌套函数用独立缓冲,翻译完恢复。
saved_nl_names: t.CVoid | t.CPtr = trans._nonlocal_names
saved_nl_types: t.CVoid | t.CPtr = trans._nonlocal_types
# 7. 切换到嵌套函数作用域 + 清空 scope names
trans._cur_func = func
trans._cur_builder = func_builder
trans._cur_func_name = func_name
HT.clear_scope_names(trans)
# 嵌套函数独立 nonlocal 缓冲(避免覆盖父函数集合)
trans._nonlocal_names = stdlib.malloc(HT.MAX_GLOBAL_NAMES * 8)
trans._nonlocal_types = stdlib.malloc(HT.MAX_GLOBAL_NAMES * 8)
if trans._nonlocal_names is not None:
string.memset(trans._nonlocal_names, 0, HT.MAX_GLOBAL_NAMES * 8)
if trans._nonlocal_types is not None:
string.memset(trans._nonlocal_types, 0, HT.MAX_GLOBAL_NAMES * 8)
# 8. 预扫描函数体:
# a. 先预扫描 Global/Nonlocal 声明(Python 语义:对整个函数作用域生效)
# b. 再预扫描 AnnAssign 为局部变量提前创建 alloca
body: list[ast.AST | t.CPtr] | t.CPtr = fd.children
if body is not None:
bn: t.CSizeT = len(body)
for bi in range(bn):
stmt: ast.AST | t.CPtr = body.get(bi)
if stmt is not None:
HandlesBody.pre_scan_scope_decls(trans, stmt)
for bi in range(bn):
stmt: ast.AST | t.CPtr = body.get(bi)
if stmt is not None:
HandlesBody.pre_scan_allocas(trans, stmt)
# 9. 翻译函数体(Nonlocal 语句会填充 _nonlocal_names)
if body is not None:
bn2: t.CSizeT = len(body)
for bi2 in range(bn2):
stmt2: ast.AST | t.CPtr = body.get(bi2)
if stmt2 is not None:
HandlesBody.translate_stmt(trans, stmt2)
# 10. 隐式 ret
last_is_return: int = 0
if body is not None:
bn3: t.CSizeT = len(body)
if bn3 > 0:
last_stmt: ast.AST | t.CPtr = body.get(bn3 - 1)
if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return:
last_is_return = 1
if last_is_return == 0:
zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
llvmlite.build_ret(func_builder, zero_val)
# 11. 保存嵌套函数的 nonlocal 信息
nested_nonlocal_count: int = trans._nonlocal_name_count
# 12. 退出嵌套函数作用域,回到父函数作用域(保留 _nonlocal_names 用于 env 创建)
HandlesVar.exit_scope(trans.SymTab)
trans._cur_func = old_func
trans._cur_builder = old_builder
# NOTE: _nonlocal_names 和 _nonlocal_name_count 仍为嵌套函数的值
# 13. 在父函数中创建闭包对象
parent_builder: llvmlite.IRBuilder | t.CPtr = old_builder
if parent_builder is None:
# 无 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
trans._nonlocal_names = saved_nl_names
trans._nonlocal_types = saved_nl_types
return 0
# 13a. 创建 env: malloc(8 * nested_nonlocal_count) — env 存储指针数组
# 每个 nonlocal 变量占 8 字节(i8*),指向父函数的 alloca(共享存储)
env_ptr: llvmlite.Value | t.CPtr = None
if nested_nonlocal_count > 0:
env_size: t.CInt64T = nested_nonlocal_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(
parent_builder, "malloc", env_size_val, 1, i8_ptr_ty, 0)
# 为每个 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):
# 从 _nonlocal_names 缓冲区读取名称
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 None:
continue
heap_store: llvmlite.Value | t.CPtr = None
# 1. 优先查全局堆地址映射(_prepare_chain_nonlocals 已为
# 链内 nonlocal 建堆并 store 到 @nlheap.*;不同层捕获
# 不同变量时(ClosureTest2 Test 7)level2 的 b 经此共享)
gname_ck: str = self._nl_heap_global_name(
pool, trans, nl_name)
if gname_ck is not None \
and self._nl_heap_global_exists(mod, gname_ck) != 0:
gv_ref0: llvmlite.Value | t.CPtr = self._nl_heap_global_ref(
pool, trans, nl_name)
if gv_ref0 is not None:
heap_store = llvmlite.build_load(
parent_builder, i8_ptr_ty, gv_ref0)
if heap_store is 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)
# 堆存储大小按类型字节数:数组(如 [4 x i32]=16 字节)
# 不能固定 8 字节(越界写崩溃);指针/标量 ≥ 8 字节
st_size: t.CInt = self._type_byte_size(pool, nl_load_ty)
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(
parent_builder, "malloc", st_size_val, 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)
heap_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
parent_builder, var_storage, llvmlite.Ptr(pool, nl_load_ty))
if ve_nl is not None and heap_typed is not None:
ve_nl.Alloca = heap_typed
# 记录到全局映射(后续层/父函数可见)
gv_ref_new: llvmlite.Value | t.CPtr = None
if gname_ck is not None \
and self._nl_heap_global_exists(mod, gname_ck) == 0:
gv_new: llvmlite.GlobalVariable | t.CPtr = \
llvmlite.new_global_variable(pool, gname_ck, i8_ptr_ty)
if gv_new is not None:
# 清除 external linkage + 零初始化(防 undefined reference)
gv_new.Linkage = None
gv_new.Initializer = "null"
llvmlite.module_add_global(mod, gv_new)
gv_ref_new = self._nl_heap_global_ref(pool, trans, nl_name)
if gv_ref_new is not None:
llvmlite.build_store(
parent_builder, var_storage, gv_ref_new)
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)
if closure_size_val is not None:
closure_size_val.Next = None
closure_ptr: llvmlite.Value | t.CPtr = llvmlite.build_call(
parent_builder, "malloc", closure_size_val, 1, i8_ptr_ty, 0)
if closure_ptr is None:
# malloc 失败,恢复状态
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
trans._nonlocal_names = saved_nl_names
trans._nonlocal_types = saved_nl_types
return 0
# 13c. 存储 fn_ptr 到 offset 0
# 创建函数指针类型 i32(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)
# 创建函数引用 Value(类型为 i32(i8*)*,使用 SHA1 混淆名)
fn_ptr_name: str = pool.alloc(64)
if fn_ptr_name is not None:
# SHA1 前缀名含 '.' 需要加引号(如 @"sha1.__closure_func")
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)
# bitcast 函数指针到 i8*(闭包存储 i8* 类型)
fn_as_i8ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
parent_builder, fn_ptr_val, i8_ptr_ty)
fn_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
parent_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(parent_builder, fn_as_i8ptr, fn_slot)
# 13d. 存储 env_ptr 到 offset 8
eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 8)
env_slot_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(
parent_builder, i8_ty, closure_ptr, eight_val)
if env_slot_addr is not None:
env_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
parent_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(parent_builder, env_ptr, env_slot)
else:
# 无 nonlocal 变量,存储 null
null_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "null")
llvmlite.build_store(parent_builder, null_val, env_slot)
# 13e. 将闭包指针存储到父函数的局部变量 {func_name}
closure_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(parent_builder, i8_ptr_ty)
if closure_alloca is not None:
llvmlite.build_store(parent_builder, closure_ptr, closure_alloca)
HandlesVar.define_var(trans.SymTab, func_name, closure_alloca)
# 注册闭包变量名(供调用时区分闭包 vs 函数指针变量,
# 两者 alloca 类型同为 i8**,_is_func_ptr_alloca 无法区分)
HandlesExprCall.register_closure_name(func_name)
# 14. 恢复 scope names(含 nonlocal 集合指针)
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
trans._nonlocal_names = saved_nl_names
trans._nonlocal_types = saved_nl_types
return 1
# ============================================================
# _type_byte_size - 计算 LLVM 类型占用的字节大小(递归)
#
# 用于 nonlocal 共享堆存储分配:数组(如 [4 x i32]=16 字节)不能
# 用固定 8 字节(越界写破坏 canary/邻块 → 运行时崩溃,
# ClosureTest2 Test 4 非local 数组崩溃根因)。未知类型保守返回 8。
# ============================================================
def _type_byte_size(self, pool: memhub.MemBuddy | t.CPtr,
ty: llvmlite.LLVMType | t.CPtr) -> t.CInt:
"""计算 LLVM 类型占用的字节大小(递归),未知类型返回 8"""
if ty is None:
return 8
match ty:
case llvmlite.LLVMType.Int(bits):
sz_i: t.CInt = (bits + 7) // 8
if sz_i < 8:
sz_i = 8
return sz_i
case llvmlite.LLVMType.Ptr(_pe):
return 8
case llvmlite.LLVMType.Float(fb):
if fb == 64:
return 8
if fb >= 128:
return 16
return 4
case llvmlite.LLVMType.Array(et, cnt):
esz: t.CInt = self._type_byte_size(pool, et)
return esz * cnt
case _:
return 8
# ============================================================
# _nl_heap_global_name - nonlocal 堆地址全局映射变量名
#
# 变量名: nlheap_{sha1}.{name}(全局变量,跨函数可见;SSA 编号是函数
# 局部的,跨函数传递堆地址只能经全局变量/模块级映射)。
# ============================================================
def _nl_heap_global_name(self, pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr,
name: str) -> str:
"""构造 nonlocal 堆地址全局映射变量名 nlheap_{sha1}.{name}"""
if pool is None or trans is None or name is None:
return None
mangled: str = self._mangle_name(trans, name)
buf: str = pool.alloc(160)
if buf is not None:
viperlib.snprintf(buf, 160, "nlheap_%s", mangled)
return buf
# ============================================================
# _nl_heap_global_ref - 全局映射变量引用 Value(i8**)
# ============================================================
def _nl_heap_global_ref(self, pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr,
name: str) -> llvmlite.Value | t.CPtr:
"""获取 nonlocal 堆地址全局映射变量的引用(@"..." 引号包裹)"""
if pool is None or trans is None or name is None:
return None
gname: str = self._nl_heap_global_name(pool, trans, name)
if gname is None:
return None
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
ref_buf: str = pool.alloc(176)
if ref_buf is None:
return None
viperlib.snprintf(ref_buf, 176, "@\"%s\"", gname)
return llvmlite.SSAValue(pool, llvmlite.Ptr(pool, i8_ptr_ty), ref_buf)
# ============================================================
# _nl_heap_global_exists - 检查 nonlocal 堆地址全局映射变量是否存在
# ============================================================
def _nl_heap_global_exists(self, mod: llvmlite.LLVMModule | t.CPtr,
gname: str) -> int:
"""检查全局映射变量 gname 是否已在模块中,1=存在"""
if mod is None or gname is None:
return 0
gcur: llvmlite.GlobalVariable | t.CPtr = mod.GlobalHead
while gcur is not None:
if gcur.Name is not None and string.strcmp(gcur.Name, gname) == 0:
return 1
gcur = gcur.Next
return 0
# ============================================================
# _collect_chain_nonlocals - 递归收集嵌套函数链内 nonlocal 声明
#
# 遍历 node(FunctionDef)的 children:遇嵌套 FunctionDef 递归,
# 遇 Nonlocal 语句收集变量名(去重)。返回更新后的计数。
# ============================================================
def _collect_chain_nonlocals(self, trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr,
names: t.CVoid | t.CPtr,
count: int) -> int:
"""递归收集 node(FunctionDef)链内所有 nonlocal 声明名(去重)"""
if node is None or names is None:
return count
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node)
if fd is None or fd.children is None:
return count
ch: list[ast.AST | t.CPtr] | t.CPtr = fd.children
cn: t.CSizeT = len(ch)
for ci in range(cn):
st: ast.AST | t.CPtr = ch.get(ci)
if st is None:
continue
k: int = st.kind()
if k == ast.ASTKind.FunctionDef:
count = self._collect_chain_nonlocals(trans, st, names, count)
elif k == ast.ASTKind.Nonlocal:
nl_node: ast.Nonlocal | t.CPtr = (ast.Nonlocal | t.CPtr)(st)
if nl_node is not None and nl_node.names is not None:
nl_list: list[ast.AST | t.CPtr] | t.CPtr = nl_node.names
nn: t.CSizeT = len(nl_list)
for ni in range(nn):
nm_node: ast.AST | t.CPtr = nl_list.get(ni)
if nm_node is None:
continue
nm_x: ast.Name | t.CPtr = (ast.Name | t.CPtr)(nm_node)
if nm_x is None or nm_x.id is None:
continue
dup: int = 0
for di in range(count):
if string.strcmp((str)(
t.CUInt64T(names) + di * 8), nm_x.id) == 0:
dup = 1
break
if dup == 0 and count < 64:
nm_slot: str | t.CPtr = (t.CVoid | t.CPtr)(
t.CUInt64T(names) + count * 8)
nm_slot[0] = nm_x.id
count += 1
return count
# ============================================================
# _prepare_chain_nonlocals - 预扫描嵌套函数链内 nonlocal 并建堆
#
# 在翻译嵌套函数定义(translate_nested_function_def)之前调用。
# 场景(ClosureTest2 Test 7):level1→a、level2→b、level3→c_val 各自
# nonlocal 不同变量,都定义在最外层函数——level1 env 无 b 槽,level2
# 无法经 env 链获取 b 的堆。此处在最外层函数中为链内所有 nonlocal
# 建堆 + 重定向 VarEntry + 把堆地址 store 到模块级映射
# @nlheap.{sha1}.{name}(全局变量跨函数可见),内层闭包创建时从映射 load。
# ============================================================
def _prepare_chain_nonlocals(self, trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr,
pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
i8_ty: llvmlite.LLVMType | t.CPtr,
i8_ptr_ty: llvmlite.LLVMType | t.CPtr) -> int:
"""预收集嵌套函数链内 nonlocal 并建堆,1 成功"""
if node is None or trans is None or builder is None or mod is None:
return 0
# 每函数只预建一次:多个嵌套函数定义共享同一堆(防重复 malloc +
# 二次重定向 VarEntry.Alloca 导致兄弟闭包各持一堆,计数不同步)
if trans._nl_chain_done != 0:
return 1
if trans._nl_chain_names is None:
trans._nl_chain_names = pool.alloc(8 * 64)
if trans._nl_chain_names is not None:
string.memset(trans._nl_chain_names, 0, 8 * 64)
if trans._nl_chain_names is None:
return 0
trans._nl_chain_count = self._collect_chain_nonlocals(
trans, node, trans._nl_chain_names, 0)
trans._nl_chain_done = 1
for ci in range(trans._nl_chain_count):
nm_slot: str | t.CPtr = (t.CVoid | t.CPtr)(
t.CUInt64T(trans._nl_chain_names) + ci * 8)
nl_name: str = nm_slot[0]
if nl_name is None:
continue
# 只在"定义它的函数"(当前顶层作用域有 alloca)中建堆
local_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_current(
trans.SymTab, nl_name)
if local_alloca is None or local_alloca.Ty is None:
continue
nl_ty: llvmlite.LLVMType | t.CPtr = local_alloca.Ty.Pointee
if nl_ty is None:
continue
gname: str = self._nl_heap_global_name(pool, trans, nl_name)
if gname is None:
continue
# 建堆(按类型字节大小)并拷贝当前值——每次本函数执行都新建共享堆,
# 并 store 到模块级映射(跨函数可见)。注意:不能因映射变量已存在
# 就跳过(前一个测试函数已把 @nlheap.* 加入模块——若跳过,本函数
# 运行时 @nlheap.* 保持上一函数的堆地址,env 读到错堆。
# ClosureTest2 Test 7 根因)。映射变量仅首次 add(模块去重),
# store 指令每次照发。
st_size: t.CInt = self._type_byte_size(pool, nl_ty)
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 None:
continue
cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, nl_ty, local_alloca)
st_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, var_storage, llvmlite.Ptr(pool, nl_ty))
if st_slot is not None and cur_val is not None:
llvmlite.build_store(builder, cur_val, st_slot)
# 重定向 VarEntry(父函数读写走共享堆)
ve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
trans.SymTab, nl_name)
if ve is not None:
heap_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, var_storage, llvmlite.Ptr(pool, nl_ty))
if heap_typed is not None:
ve.Alloca = heap_typed
# 创建/复用全局映射变量并 store 堆地址(跨函数可见)
gv_found: llvmlite.GlobalVariable | t.CPtr = None
gcur: llvmlite.GlobalVariable | t.CPtr = mod.GlobalHead
while gcur is not None:
if gcur.Name is not None and string.strcmp(gcur.Name, gname) == 0:
gv_found = gcur
break
gcur = gcur.Next
if gv_found is None:
gv_found = llvmlite.new_global_variable(pool, gname, i8_ptr_ty)
if gv_found is not None:
# 清除 external linkage 并给零初始化,否则打印为 external
# 声明、store 引用无定义体 → 链接 undefined reference
gv_found.Linkage = None
gv_found.Initializer = "null"
llvmlite.module_add_global(mod, gv_found)
if gv_found is not None:
gv_ref: llvmlite.Value | t.CPtr = self._nl_heap_global_ref(
pool, trans, nl_name)
if gv_ref is not None:
llvmlite.build_store(builder, var_storage, gv_ref)
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: str = 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: str = 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 = len(alist)
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 None:
# fail-fast:lambda 参数有注解但类型解析失败,不再静默保持 i32
HandlesType.fatal_error(
arg_n, f"参数 '{arg_n.arg}' 类型解析失败: {HandlesType.annotation_to_str(arg_n.annotation)}",
"NameError")
resolved = i32_ty # 不可达(fatal_error 已退出)
if resolved is not None:
match resolved:
case llvmlite.LLVMType.Struct(_, _, _):
p_ty = llvmlite.Ptr(pool, resolved)
case llvmlite.LLVMType.Array(aelem_ty_l, _):
p_ty = llvmlite.Ptr(pool, aelem_ty_l)
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: str = 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: str = 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: str = (str)(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:
# fail-fast:lambda 参数类型槽缺失(内部状态不一致),不再静默保持 i32
HandlesType.fatal_error(
lam, f"lambda 参数 '{param_names + pi3 * 32}' 类型信息缺失", "InternalCompilerError")
p_ty3 = i32_ty # 不可达(fatal_error 已退出)
pname_ref: str = 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:
# fail-fast:lambda 体类型转换失败,不再静默 ret 0
HandlesType.fatal_error(lam.body, "lambda 体表达式翻译失败", "TypeError")
else:
# fail-fast:lambda 体翻译失败,不再静默 ret 0
HandlesType.fatal_error(lam.body, "lambda 体表达式翻译失败", "TypeError")
# 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: str = (str)(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: str = 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: str,
param_count: int,
cap_names: str,
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 = len(vs)
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 = len(cl)
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 = len(als)
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 = len(kws)
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 = len(es)
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 函数(简单版本,仅声明)
# ============================================================
def create_function(self, pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
name: str,
args_node: ast.AST | t.CPtr,
ret_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Function | t.CPtr:
"""创建 LLVM 函数并添加参数"""
if name is None or mod is None:
return None
func: llvmlite.Function | t.CPtr = llvmlite.create_function(pool, mod, name, ret_ty)
if func is None:
return None
if args_node is not None:
ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
if ags.args is not None:
alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args
an: t.CSizeT = len(alist)
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
for ai in range(an):
arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai))
if arg is not None and arg.arg is not None:
# t.CVoid 表示空参:跳过
if arg.annotation is not None:
if arg.annotation.kind() == ast.ASTKind.Attribute:
at_cf: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg.annotation)
if at_cf.attr is not None and string.strcmp(at_cf.attr, "CVoid") == 0:
continue
param_ty: llvmlite.LLVMType | t.CPtr = i32_ty
if arg.annotation is not None:
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, arg.annotation, None, None, None)
if resolved is not None:
param_ty = resolved
pname: str = pool.alloc(32)
if pname is not None:
viperlib.snprintf(pname, 32, "%%%s", arg.arg)
llvmlite.add_param(pool, func, param_ty, pname)
return func