Files
TransPyV/App/lib/core/Handles/HandlesFunctions.py

988 lines
44 KiB
Python
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.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesBody as HandlesBody
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
import lib.core.Handles.HandlesImports as HandlesImports
# ============================================================
# 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(pool: memhub.MemBuddy | t.CPtr,
decorator_list: list[ast.AST | t.CPtr] | t.CPtr,
imported_modules: str) -> t.CChar | t.CPtr:
"""从 decorator_list 提取 c.Attribute 属性,返回 LLVM IR 属性字符串"""
if decorator_list is None:
return None
dn: t.CSizeT = decorator_list.__len__()
if dn == 0:
return None
attrs_buf: t.CChar | t.CPtr = 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 = args_list.__len__()
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 = _get_attr_name_from_node(arg_node)
if attr_name is None:
continue
# 映射到 LLVM 属性名并追加
if _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(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(attrs_buf: t.CChar | t.CPtr, 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':
_append_str(attrs_buf, " ")
_append_str(attrs_buf, llvm_name)
return 1
def _append_str(buf: t.CChar | t.CPtr, s: str) -> None:
"""将字符串追加到 buf 末尾(用 strlen+strcpy 模拟 strcat"""
if buf is None or s is None:
return
cur_len: t.CSizeT = string.strlen(buf)
string.strcpy(buf + cur_len, s)
# ============================================================
# HandlesFunctions - 函数定义处理trans 单参模式)
#
# 参考 Python 版 TransPyC FunctionHandle
#
# 函数有自己的局部作用域,通过 HandlesVar.enter_scope/exit_scope
# 管理嵌套作用域链,翻译函数体前进入函数作用域,翻译完退出。
# ============================================================
# ============================================================
# _mangle_name - 为名称添加 SHA1 前缀
#
# 返回 "sha1.name" 格式的混淆名。若 ModuleSha1 为 None 或名称已带
# SHA1 前缀16 hex + '.'),则原样返回。
# ============================================================
def _mangle_name(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(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(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 _mangle_name(trans, name)
# ============================================================
# forward_declare_functions - 预扫描所有顶层 FunctionDef创建前向声明
#
# 解决同模块内前向引用问题:如 viperlib.py 中 sprintf(行15) 调用
# vsnprintf(行41),但 vsnprintf 定义在后面。
#
# 对每个顶层 FunctionDef:
# 1. 推断返回类型和参数类型
# 2. 计算 mangled name含 SHA1 前缀)
# 3. 创建 declareIsDeclared=1
# 4. 添加参数
# 5. 注册到函数表
#
# 后续 translate_function_def 会通过 find_func_in_module 找到已有的 declare
# 复用之(清除 IsDeclared跳过参数创建直接添加函数体
# ============================================================
def forward_declare_functions(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
cn_count: t.CSizeT = ch.__len__()
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)
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")
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 fd.name == "main":
mangled_name: str = fd.name
else:
mangled_name = _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
# 注册到函数表(用裸名 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) == 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 = alist.__len__()
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)
if resolved is not None:
param_ty = resolved
pname: t.CChar | t.CPtr = pool.alloc(32)
if pname is not None:
viperlib.snprintf(pname, 32, "%%%s", arg.arg)
llvmlite.add_param(pool, func, param_ty, pname)
return 0
# ============================================================
# 翻译函数定义 FunctionDef(name, args, body, ...)
#
# trans 单参模式:所有共享状态从 trans 获取
# 函数局部作用域通过 enter_scope/exit_scope 管理
# ============================================================
def translate_function_def(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
stdio.printf("[FD] enter name=%s\n", fd.name)
stdio.fflush(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)
# 推断返回类型:优先使用返回类型注解
stdio.printf("[FD] %s 推断返回类型前\n", fd.name)
stdio.fflush(0)
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)
# 如果返回类型注解纯装饰器标记(如 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)
stdio.printf("[FD] %s 推断返回类型后=%d\n", fd.name, ret_ty)
stdio.fflush(0)
# 检测是否为外部声明函数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
stdio.printf("[FD] %s extern=%d state=%d export=%d is_extern_decl=%d\n",
fd.name, has_extern, has_state, has_export, is_extern_decl)
stdio.fflush(0)
# 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 fd.name == "main":
mangled_name: str = fd.name
else:
mangled_name: str = _mangle_func_name(trans, fd.name, 0)
stdio.printf("[FD] %s mangled_name=%s\n", fd.name, mangled_name)
stdio.fflush(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仅声明不定义
func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
pool, mod, mangled_name, ret_ty)
if func is None:
stdio.printf("[FUNC] create_declare %s failed\n", fd.name)
return 0
# 注册到函数表
max_funcs_extern: int = 256
if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs_extern) == 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 = alist_e.__len__()
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:
if 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)
if resolved_e is not None:
param_ty_e = resolved_e
pname_e: t.CChar | t.CPtr = 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: t.CChar | t.CPtr = extract_func_attrs(pool, fd.decorator_list, imported_modules)
if func_attrs_e is not None:
llvmlite.function_set_attrs(func, func_attrs_e)
return 0
# args_node 用于后续 alloca 创建,提前赋值
args_node: ast.Arguments | t.CPtr = fd.args
# 检查是否已有前向声明(由 forward_declare_functions 创建)
stdio.printf("[FD] %s find_func_in_module 前\n", fd.name)
stdio.fflush(0)
func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name)
stdio.printf("[FD] %s find_func_in_module 后=%d\n", fd.name, func)
stdio.fflush(0)
if func is not None and llvmlite.function_is_declared(func) != 0:
# 复用前向声明:清除 IsDeclared 标记,转为 define
func.IsDeclared = 0
# 装饰器属性设置(前向声明时未设置)
func_attrs_reuse: t.CChar | t.CPtr = extract_func_attrs(pool, fd.decorator_list, imported_modules)
if func_attrs_reuse is not None:
llvmlite.function_set_attrs(func, func_attrs_reuse)
stdio.printf("[FD] %s 复用前向声明\n", fd.name)
stdio.fflush(0)
else:
# 创建新的 LLVM 函数(使用 SHA1 混淆名)
stdio.printf("[FD] %s create_function 前\n", fd.name)
stdio.fflush(0)
func = llvmlite.create_function(pool, mod, mangled_name, ret_ty)
stdio.printf("[FD] %s create_function 后=%d\n", fd.name, func)
stdio.fflush(0)
if func is None:
stdio.printf("[FUNC] create_function %s failed\n", fd.name)
return 0
# 提取 @c.Attribute 装饰器属性并设置到函数
func_attrs: t.CChar | t.CPtr = extract_func_attrs(pool, fd.decorator_list, imported_modules)
if func_attrs is not None:
llvmlite.function_set_attrs(func, func_attrs)
# 注册到函数表
max_funcs: int = 256
if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs) == 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 = alist.__len__()
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 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)
if resolved is not None:
param_ty = resolved
pname: t.CChar | t.CPtr = pool.alloc(32)
if pname is not None:
viperlib.snprintf(pname, 32, "%%%s", arg.arg)
llvmlite.add_param(pool, func, param_ty, pname)
stdio.printf("[FD] %s 新函数创建完成\n", fd.name)
stdio.fflush(0)
# 创建 entry 块
stdio.printf("[FD] %s create_block 前\n", fd.name)
stdio.fflush(0)
entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry")
stdio.printf("[FD] %s create_block 后=%d\n", fd.name, entry_blk)
stdio.fflush(0)
if entry_blk is None:
return 0
# 创建函数专属 builder
stdio.printf("[FD] %s new_builder 前\n", fd.name)
stdio.fflush(0)
func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func)
stdio.printf("[FD] %s new_builder 后=%d\n", fd.name, func_builder)
stdio.fflush(0)
if func_builder is None:
return 0
llvmlite.position_at_end(func_builder, entry_blk)
# 进入函数作用域(嵌套符号表)
stdio.printf("[FD] %s enter_scope 前\n", fd.name)
stdio.fflush(0)
HandlesVar.enter_scope(trans.SymTab, HandlesVar.SCOPE_FUNCTION)
stdio.printf("[FD] %s enter_scope 后\n", fd.name)
stdio.fflush(0)
# 为参数创建 alloca
stdio.printf("[FD] %s 参数 alloca 前\n", fd.name)
stdio.fflush(0)
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 = alist2.__len__()
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)
if resolved2 is not None:
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) 回退到类名查找结构体)
if arg2.annotation is not None:
cls_nm: str = 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: t.CChar | t.CPtr = 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)
stdio.printf("[FD] %s 参数 alloca 后\n", fd.name)
stdio.fflush(0)
# 保存模块级作用域状态(仅非变量表相关)
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
trans._cur_func = func
trans._cur_builder = func_builder
# 清空 global/nonlocal 名称集合(新函数作用域)
HT.clear_scope_names(trans)
# 预扫描函数体:为局部变量提前创建 alloca
stdio.printf("[FD] %s pre_scan_allocas 前\n", fd.name)
stdio.fflush(0)
body: list[ast.AST | t.CPtr] | t.CPtr = fd.children
if body is not None:
bn: t.CSizeT = body.__len__()
for bi in range(bn):
stmt: ast.AST | t.CPtr = body.get(bi)
if stmt is not None:
HandlesBody.pre_scan_allocas(trans, stmt)
stdio.printf("[FD] %s pre_scan_allocas 后\n", fd.name)
stdio.fflush(0)
# 翻译函数体
stdio.printf("[FD] %s translate_stmt 前 body_len=%d\n", fd.name,
body.__len__() if body is not None else 0)
stdio.fflush(0)
if body is not None:
bn2: t.CSizeT = body.__len__()
for bi2 in range(bn2):
stmt2: ast.AST | t.CPtr = body.get(bi2)
if stmt2 is not None:
stdio.printf("[FD] %s translate_stmt bi2=%d kd=%d\n", fd.name, bi2, stmt2.kind())
stdio.fflush(0)
HandlesBody.translate_stmt(trans, stmt2)
stdio.printf("[FD] %s translate_stmt bi2=%d\n", fd.name, bi2)
stdio.fflush(0)
# 如果函数体最后一条语句不是 Return添加隐式 ret
last_is_return: int = 0
if body is not None:
bn3: t.CSizeT = body.__len__()
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)
# 恢复模块级作用域(退出函数作用域)
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
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 字节)
# ============================================================
def translate_nested_function_def(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: t.CChar | t.CPtr = pool.alloc(64)
if promoted_name is not None:
viperlib.snprintf(promoted_name, 64, "__closure_%s", func_name)
mangled_promoted: str = _mangle_name(trans, promoted_name)
# 2. 创建提升后的函数: define i32 @__closure_{name}(i8* %env)
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")
# 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, HandlesVar.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)
# 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
# 7. 切换到嵌套函数作用域 + 清空 scope names
trans._cur_func = func
trans._cur_builder = func_builder
trans._cur_func_name = func_name
HT.clear_scope_names(trans)
# 8. 预扫描函数体:为局部变量提前创建 alloca
body: list[ast.AST | t.CPtr] | t.CPtr = fd.children
if body is not None:
bn: t.CSizeT = body.__len__()
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 = body.__len__()
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 = body.__len__()
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
return 0
# 13a. 创建 env: malloc(4 * nested_nonlocal_count) — env 直接存储 i32 值
env_ptr: llvmlite.Value | t.CPtr = None
if nested_nonlocal_count > 0:
env_size: t.CInt64T = nested_nonlocal_count * 4
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
if env_ptr is not None:
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
i32_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_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 not None:
# 在父函数作用域中查找Current 已回到父作用域)
var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, nl_name)
if var_alloca is not None:
# 加载变量值
var_ty: llvmlite.LLVMType | t.CPtr = None
if var_alloca.Ty is not None:
var_ty = var_alloca.Ty.Pointee
if var_ty is None:
var_ty = i32_ty
var_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
parent_builder, var_ty, var_alloca)
if var_val is not None:
# GEP to env[ni*4]
offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, ni * 4)
slot: llvmlite.Value | t.CPtr = llvmlite.build_gep(
parent_builder, i8_ty, env_ptr, offset_val)
if slot is not None:
# bitcast to i32* and store value
slot_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
parent_builder, slot, i32_ptr_ty)
if slot_typed is not None:
# 类型转换(确保 var_val 是 i32
coerced_val: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
parent_builder, var_val, i32_ty)
if coerced_val is not None:
llvmlite.build_store(parent_builder, coerced_val, 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
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: t.CChar | t.CPtr = 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)
# 14. 恢复 scope names
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
return 1
# ============================================================
# 创建 LLVM 函数(简单版本,仅声明)
# ============================================================
def create_function(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 = alist.__len__()
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)
if resolved is not None:
param_ty = resolved
pname: t.CChar | t.CPtr = 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