- 全量降级点改 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 等
2071 lines
110 KiB
Plaintext
2071 lines
110 KiB
Plaintext
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
|