- 10 个 Handler 类主方法迁入 Gen:Assign/AnnAssign/AugAssign→AssignGenMixin, If/While/For/Return→StmtGenCifMixin,Match→新建 MatchGenMixin(注册 Generator MRO), Imports→ImportsGenMixin;方法体 self.Trans→trans,签名加 trans 首参 - 分派改:StmtGenMixin.translate_stmt 同链 self.translate_xxx + 跨链经 Handles 委托壳 (NoVTable 静态绑定约束);ExprCall 分派改走 ExprCallCall 壳 - 清理:HandlesTranslator 删 11 个 Handler 字段与 _init_state 创建段; StmtGenCifMixin 删 5 个 NewXxxHandle 工厂;main/BuildPipeline 补 HandlesAssign._g_gen 注入 - 委托壳保留:跨 Mixin 桥(Assign/AnnAssign/AugAssign/Match/Imports)待编译器缺陷修复后删
800 lines
39 KiB
Plaintext
800 lines
39 KiB
Plaintext
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdio
|
||
import stdlib
|
||
import viperlib
|
||
import lib.core.VLogger as VLogger
|
||
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.HandlesImports as HandlesImports
|
||
import lib.core.Handles.HandlesBody as HandlesBody
|
||
import lib.core.Handles.HandlesFunctions as HandlesFunctions
|
||
import lib.core.Handles.HandlesType as HandlesType
|
||
import lib.core.Handles.HandlesClassDef as HandlesClassDef
|
||
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
|
||
import lib.core.Handles.ExprCallBase as ExprCallBase
|
||
|
||
|
||
# ============================================================
|
||
# TranslatorGenMixin - 翻译驱动 Mixin(对象化 P6-E)
|
||
#
|
||
# 从 HandlesMain.vp / HandlesTranslator.vp 迁移:模块级纯函数
|
||
# (trans 首参)→ 类方法。包含:
|
||
# - 模块级翻译入口(translate_children/create_wrapper_main/
|
||
# handle_module_level_var 等,原 HandlesMain.vp)
|
||
# - global/nonlocal 名称管理辅助函数(原 HandlesTranslator.vp)
|
||
#
|
||
# 迁移原则(与 P2-P5 一致,行为零变化):
|
||
# 1. 方法保留原函数签名(含 trans/pool 首参),仅函数体内的
|
||
# 本模块函数调用改为 self.xxx(...)
|
||
# 2. 外部模块调用(HandlesType.xxx/HandlesVar.xxx 等)保留模块前缀
|
||
# 3. HandlesMain/HandlesTranslator 原函数保留为"委托":本地模块级
|
||
# 单例 _g_gen(BuildPipeline/main 注入)cast 成 Generator 类型
|
||
# 4. 嵌套函数保持嵌套
|
||
#
|
||
# 常量(MAX_VARS/MAX_FUNCS/MAX_GLOBAL_NAMES)与原模块保持一致。
|
||
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
|
||
# ============================================================
|
||
|
||
|
||
# ============================================================
|
||
# 常量(与 HandlesTranslator 保持一致)
|
||
# ============================================================
|
||
MAX_VARS: t.CDefine = 1024
|
||
MAX_FUNCS: t.CDefine = 1024
|
||
MAX_GLOBAL_NAMES: t.CDefine = 32
|
||
|
||
|
||
# ============================================================
|
||
# TranslatorGenMixin - 翻译驱动(模块级翻译入口 + 作用域名称管理)
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class TranslatorGenMixin:
|
||
"""翻译驱动 Mixin(P6 方法化)"""
|
||
|
||
# ============================================================
|
||
# _register_cexport_from_funcdef - Phase 1a 预注册 CExport/State 函数
|
||
#
|
||
# 解决翻译顺序依赖问题:Phase 1b 按字母序翻译,后翻译的模块的
|
||
# CExport 函数无法被先翻译的模块正确识别为裸名调用。
|
||
# Phase 1a 预注册所有 CExport/State 函数名到全局表。
|
||
# ============================================================
|
||
def _register_cexport_from_funcdef(self, trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""预注册 CExport/State 函数到全局表(仅注册,不生成 IR)"""
|
||
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node)
|
||
if fd is None or fd.name is None:
|
||
return 0
|
||
if trans is None or trans.ModuleSha1 is None:
|
||
return 0
|
||
|
||
# 检查返回类型是否有 CExport 或 State 标记
|
||
has_export: int = 0
|
||
has_state: int = 0
|
||
if fd.returns is not None:
|
||
has_export = HandlesType.has_decorator_marker(fd.returns, "CExport")
|
||
has_state = HandlesType.has_decorator_marker(fd.returns, "State")
|
||
|
||
if has_export != 0 or has_state != 0:
|
||
ExprCallBase.register_cexport_func(trans.ModuleSha1, fd.name)
|
||
|
||
return 0
|
||
|
||
# ============================================================
|
||
# translate_children - 遍历 AST 子节点并分派翻译
|
||
#
|
||
# 对应 TransPyC translator._translate_children()
|
||
# 共享状态从 trans 获取,imported_modules/from_imports 更新到 trans
|
||
# ============================================================
|
||
def translate_children(self, trans: HT.Translator | t.CPtr,
|
||
tree: ast.AST | t.CPtr) -> int:
|
||
"""遍历 tree.children 并翻译每个子节点
|
||
|
||
Args:
|
||
trans: 翻译器(含所有共享状态)
|
||
tree: AST 模块节点
|
||
|
||
Returns:
|
||
t.CInt: 新增的变量数
|
||
"""
|
||
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||
if ch is None:
|
||
return 0
|
||
|
||
cn_count: t.CSizeT = len(ch)
|
||
added_total: int = 0
|
||
|
||
for ci in range(cn_count):
|
||
child: ast.AST | t.CPtr = ch.get(ci)
|
||
if child is None: continue
|
||
kd: int = child.kind()
|
||
|
||
# _declare_only == 0 时,_translate_module_level 已预处理导入语句,
|
||
# 此处跳过避免重复处理(from_imports 条目重复)
|
||
if trans._declare_only == 0 and (kd == ast.ASTKind.Import or kd == ast.ASTKind.ImportFrom):
|
||
continue
|
||
if kd == ast.ASTKind.Import:
|
||
HandlesImports.translate_import(trans, child)
|
||
elif kd == ast.ASTKind.ImportFrom:
|
||
HandlesImports.translate_import_from_module(trans, child)
|
||
HandlesImports.translate_import_from_names(trans, child)
|
||
elif kd == ast.ASTKind.FunctionDef:
|
||
# Phase 1a 声明模式:只注册 CExport/State 函数到全局表(解决翻译顺序依赖)
|
||
# Phase 1b 全量翻译:正常翻译函数体
|
||
if trans._declare_only == 0:
|
||
added: int = HandlesFunctions.translate_function_def(trans, child)
|
||
added_total += added
|
||
elif trans._declare_only == 1:
|
||
self._register_cexport_from_funcdef(trans, child)
|
||
# 预解析函数签名类型,触发泛型类特化(如 numpy 的 _empty_like
|
||
# 签名 ndarray[t.CDouble] → 特化结构体注册)。
|
||
# 1a 阶段在 mark1 之前,特化结构体的 Ty/Fields 分配在 mark1 前,
|
||
# 不被 1b 的 mark/reset 回收 → 避免 Phase2 翻译 App 文件时 UAF
|
||
# (Phase1 1b 才触发特化时,结构体 Ty/Fields 在 pool 被 reset 覆写)。
|
||
# 仅触发特化,不验证结果(1b 全量翻译时仍会重新解析)。
|
||
self._prescan_funcdef_signatures(trans, child)
|
||
elif kd == ast.ASTKind.ClassDef:
|
||
# ClassDef 在模块级直接处理(不需要 builder)
|
||
# _declare_only=2(import扫描模式)时跳过,只处理 import 依赖
|
||
if trans._declare_only != 2:
|
||
HandlesClassDef.translate_class_def(trans, child)
|
||
elif trans._declare_only == 0 and trans._cur_builder is not None:
|
||
# 有 builder → 委托 HandlesBody 分派
|
||
added = HandlesBody.translate_stmt(trans, child)
|
||
added_total += added
|
||
elif kd == ast.ASTKind.AnnAssign and trans._declare_only != 2:
|
||
# 模块级 AnnAssign
|
||
# _declare_only=2(import扫描模式)时跳过
|
||
# _declare_only=1(struct注册模式)时只处理 CDefine(在 handle_module_level_var 内部判断)
|
||
# _declare_only=0(全量翻译)时处理所有模块级 AnnAssign
|
||
added = self.handle_module_level_var(trans, child)
|
||
added_total += added
|
||
elif trans._declare_only == 0 and kd == ast.ASTKind.Assign:
|
||
# 无 builder 的模块级 Assign → 创建全局变量(仅全量翻译模式)
|
||
added = self.handle_module_level_var(trans, child)
|
||
added_total += added
|
||
|
||
return added_total
|
||
|
||
# ============================================================
|
||
# _prescan_funcdef_signatures - 1a 阶段预解析模块级函数签名
|
||
#
|
||
# 触发泛型类特化(如 numpy 的 _empty_like 签名 ndarray[t.CDouble]),
|
||
# 使特化结构体在 mark1 前注册(Ty/Fields 不被 1b 的 mark/reset 回收),
|
||
# 避免 Phase2 翻译 App 文件时访问悬空结构体(UAF)。
|
||
# 仅解析类型触发特化,不验证结果(1b 全量翻译时重新解析)。
|
||
# ============================================================
|
||
def _prescan_funcdef_signatures(self, trans: HT.Translator | t.CPtr,
|
||
fd: ast.FunctionDef | t.CPtr) -> None:
|
||
"""预解析模块级函数签名的返回/参数类型,触发泛型类特化"""
|
||
if trans is None or fd is None:
|
||
return
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
if pool is None:
|
||
return
|
||
imp: str = trans._imported_modules
|
||
fi: str = trans._from_imports
|
||
if fd.returns is not None:
|
||
HandlesType.resolve_annotation_type(pool, fd.returns, imp, fi, trans)
|
||
if fd.args is not None:
|
||
ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args)
|
||
if ags.args is not None:
|
||
al: list[ast.AST | t.CPtr] | t.CPtr = ags.args
|
||
an: t.CSizeT = len(al)
|
||
ai: t.CSizeT
|
||
for ai in range(an):
|
||
ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(al.get(ai))
|
||
if ag is not None and ag.annotation is not None:
|
||
HandlesType.resolve_annotation_type(pool, ag.annotation, imp, fi, trans)
|
||
|
||
# ============================================================
|
||
# _build_array_initializer_text - 从 AST List 生成 LLVM IR 数组初始化器
|
||
#
|
||
# 生成格式: [N x elem_ty] [elem_ty val0, elem_ty val1, ...]
|
||
# 用于模块级 t.CArray 列表字面量初始化(不依赖 builder,直接生成常量初始化器)
|
||
# ============================================================
|
||
def _build_array_initializer_text(self, pool: memhub.MemBuddy | t.CPtr,
|
||
var_ty: llvmlite.LLVMType | t.CPtr,
|
||
list_node: ast.List | t.CPtr) -> str:
|
||
"""从 AST List 节点生成 LLVM IR 数组初始化器文本,None 失败"""
|
||
if var_ty is None or list_node is None:
|
||
return None
|
||
|
||
# 重新进行类型转换,确保 TPV 编译器正确识别 ast.List 类型
|
||
# (避免 init_list_node 初始值为 None 时类型推断退化为 t.CPtr)
|
||
ln: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node)
|
||
if ln is None:
|
||
return None
|
||
|
||
# 从 var_ty 提取数组元素类型和数量
|
||
elem_ty: llvmlite.LLVMType | t.CPtr = None
|
||
arr_count: t.CInt = 0
|
||
match var_ty:
|
||
case llvmlite.LLVMType.Array(et, cnt):
|
||
elem_ty = et
|
||
arr_count = cnt
|
||
|
||
if elem_ty is None or arr_count <= 0:
|
||
return None
|
||
|
||
# 确定元素类型的 IR 表示
|
||
elem_ir_ty: str = "i8"
|
||
match elem_ty:
|
||
case llvmlite.LLVMType.Int(bits):
|
||
if bits == 8:
|
||
elem_ir_ty = "i8"
|
||
elif bits == 16:
|
||
elem_ir_ty = "i16"
|
||
elif bits == 32:
|
||
elem_ir_ty = "i32"
|
||
elif bits == 64:
|
||
elem_ir_ty = "i64"
|
||
|
||
# 获取列表元素(通过 ln.elts 而非 list_node.elts,确保类型正确识别)
|
||
elts: list[ast.AST | t.CPtr] | t.CPtr = ln.elts
|
||
if elts is None:
|
||
return None
|
||
elts_count: t.CSizeT = len(elts)
|
||
|
||
# 计算缓冲区大小: 每个元素最多 "i32 -9223372036854775808, " 约 26 字符
|
||
# 按数组声明长度 arr_count 计算(元素不足时补零,可能多于 elts_count)
|
||
cnt_total: t.CSizeT = t.CSizeT(arr_count)
|
||
buf_size: t.CSizeT = 64 + cnt_total * 32
|
||
buf: str = pool.alloc(buf_size)
|
||
if buf is None:
|
||
return None
|
||
|
||
# 写入前缀: "["(类型前缀由 _print_global 输出,初始化器只需元素列表)
|
||
written: t.CInt = viperlib.snprintf(buf, buf_size, "[")
|
||
pos: t.CSizeT = t.CSizeT(written)
|
||
|
||
# 逐个元素写入:元素数必须与数组声明长度 arr_count 一致,
|
||
# 列表元素不足时补零(如 g_arr: t.CArray[t.CInt, 4] = [0] →
|
||
# [i32 0, i32 0, i32 0, i32 0]),否则 llc 报
|
||
# "constant expression type mismatch: got type '[1 x i32]' but expected '[4 x i32]'"
|
||
i: t.CSizeT = 0
|
||
while i < cnt_total:
|
||
elem_val: t.CInt64T = 0
|
||
if i < elts_count:
|
||
elem_node: ast.AST | t.CPtr = elts.get(i)
|
||
# 直接从 Constant 节点提取 int_val(避免 extract_cdefine_int_value 的 t.CInt 截断)
|
||
if elem_node is not None:
|
||
ek: int = elem_node.kind()
|
||
if ek == ast.ASTKind.Constant:
|
||
ec: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(elem_node)
|
||
if ec is not None and ec.const_kind == ast.CONST_INT:
|
||
elem_val = ec.int_val
|
||
elif ek == ast.ASTKind.UnaryOp:
|
||
# 负数: UnaryOp(USub, Constant)
|
||
elem_val = HandlesAnnAssign.extract_cdefine_int_value(elem_node)
|
||
if i > 0:
|
||
written = viperlib.snprintf(buf + pos, buf_size - pos, ", ")
|
||
pos += t.CSizeT(written)
|
||
written = viperlib.snprintf(buf + pos, buf_size - pos, "%s %lld", elem_ir_ty, elem_val)
|
||
pos += t.CSizeT(written)
|
||
i += 1
|
||
|
||
# 写入后缀 "]"
|
||
viperlib.snprintf(buf + pos, buf_size - pos, "]")
|
||
return buf
|
||
|
||
# ============================================================
|
||
# _build_string_array_initializer_text - 字符串字面量初始化数组全局
|
||
#
|
||
# t.CArray[t.CChar, N] = "..." → [i8 b0, i8 b1, ..., i8 0, ...]
|
||
# (字符串字节 + 零填充到数组长度;空串返回 zeroinitializer)。
|
||
# 此前统一走字符串指针 GEP 初始化器 → @g = global [N x i8] <ptr>
|
||
# 类型不匹配(llc constant expression type mismatch,
|
||
# pyzlib_error_msg = global [512 x i8] <GEP ptr> 根因)。
|
||
# ============================================================
|
||
def _build_string_array_initializer_text(self, pool: memhub.MemBuddy | t.CPtr,
|
||
var_ty: llvmlite.LLVMType | t.CPtr,
|
||
str_val: str) -> str:
|
||
"""字符串字面量初始化数组全局,返回初始化器文本或 None"""
|
||
if var_ty is None or str_val is None:
|
||
return None
|
||
arr_count: t.CInt = 0
|
||
match var_ty:
|
||
case llvmlite.LLVMType.Array(_, cnt):
|
||
arr_count = cnt
|
||
if arr_count <= 0:
|
||
return None
|
||
slen: t.CSizeT = string.strlen(str_val)
|
||
if slen == 0:
|
||
return "zeroinitializer"
|
||
buf_size: t.CSizeT = 64 + t.CSizeT(arr_count) * 16
|
||
buf: str = pool.alloc(buf_size)
|
||
if buf is None:
|
||
return None
|
||
written: t.CInt = viperlib.snprintf(buf, buf_size, "[")
|
||
pos: t.CSizeT = t.CSizeT(written)
|
||
i: t.CSizeT = 0
|
||
while i < t.CSizeT(arr_count):
|
||
if i > 0:
|
||
written = viperlib.snprintf(buf + pos, buf_size - pos, ", ")
|
||
pos += t.CSizeT(written)
|
||
bv: t.CInt64T = 0
|
||
if i < slen:
|
||
bv = t.CInt64T(str_val[i])
|
||
written = viperlib.snprintf(buf + pos, buf_size - pos, "i8 %lld", bv)
|
||
pos += t.CSizeT(written)
|
||
i += 1
|
||
viperlib.snprintf(buf + pos, buf_size - pos, "]")
|
||
return buf
|
||
|
||
# ============================================================
|
||
# _build_string_ptr_initializer - 为字符串字面量初始化指针类型全局变量
|
||
#
|
||
# 创建内部字符串常量全局 @.str.{var_name} = private constant [len+1 x i8] c"...\00"
|
||
# 返回 GEP 初始化器文本: getelementptr inbounds ([len+1 x i8], [len+1 x i8]* @.str.{var_name}, i32 0, i32 0)
|
||
# 用于 b64_tab: t.CArray[t.CChar, None] = "ABC..." 等字符串初始化指针类型
|
||
# ============================================================
|
||
def _build_string_ptr_initializer(self, pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
var_name: str,
|
||
str_val: str) -> str:
|
||
"""为字符串字面量创建内部常量全局并返回 GEP 初始化器文本,None 失败"""
|
||
if str_val is None or var_name is None:
|
||
return None
|
||
|
||
# 构造内部字符串常量名称: .str.{var_name}
|
||
str_name_buf: str = pool.alloc(64)
|
||
if str_name_buf is None:
|
||
return None
|
||
viperlib.snprintf(str_name_buf, 64, ".str.%s", var_name)
|
||
|
||
# 调用 llvmlite.create_global_string 创建字符串常量全局
|
||
str_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.create_global_string(
|
||
pool, mod, str_name_buf, str_val)
|
||
if str_gv is None:
|
||
return None
|
||
|
||
# 生成 GEP 初始化器文本
|
||
str_len: t.CSizeT = string.strlen(str_val)
|
||
init_buf: str = pool.alloc(128)
|
||
if init_buf is None:
|
||
return None
|
||
viperlib.snprintf(init_buf, 128,
|
||
"getelementptr inbounds ([%d x i8], [%d x i8]* @%s, i32 0, i32 0)",
|
||
str_len + 1, str_len + 1, str_name_buf)
|
||
return init_buf
|
||
|
||
# ============================================================
|
||
# handle_module_level_var - 模块级变量声明 → 创建 LLVM 全局变量
|
||
#
|
||
# 当用户已定义 main(无 wrapper main builder)时,模块级
|
||
# AnnAssign/Assign 创建全局变量 @var_name 并注册到 SymTab 模块作用域
|
||
# 支持整数、列表字面量、字符串字面量初始值
|
||
# ============================================================
|
||
def handle_module_level_var(self, trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""处理模块级变量声明,创建全局变量"""
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||
|
||
# CDefine 注解: 编译期常量,不创建全局变量
|
||
# 注册到全局 CDefine 表供 t.CArray[elem_ty, NAME] 解析
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.AnnAssign:
|
||
aa_cd: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||
if aa_cd is not None and aa_cd.target is not None:
|
||
if aa_cd.target.kind() == ast.ASTKind.Name:
|
||
nm_cd: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa_cd.target)
|
||
if nm_cd.id is not None:
|
||
if HandlesAnnAssign.is_cdefine_annotation(aa_cd.annotation) != 0:
|
||
# 浮点/整数自动识别注册(浮点 CDefine 如 vipermath U_M_PI)
|
||
HandlesAnnAssign._register_cdefine_from_value(
|
||
pool, nm_cd.id, aa_cd.value)
|
||
return 0
|
||
# CTypedef 注解(如 posix.vp mode_t: t.CTypedef = t.CUInt32T):
|
||
# 不创建全局变量——否则生成 @mode_t 符号 → 链接 duplicate
|
||
# symbol warning。预注册阶段(forward_declare_functions
|
||
# 之前)按需注册到 CTypedef 表:翻译期表已被 clear_ctypedefs
|
||
# 清空(每文件隔离),若不在此时注册,S_ISREG(mode: mode_t)
|
||
# 等函数参数注解在 FuncGenDef 正式翻译时查表失败 →
|
||
# NameError: mode_t(AstTest/posix.vp 根因;模块级 AnnAssign
|
||
# 经本函数分派,不经过 AnnAssignHandle.Handle 的注册分支)。
|
||
if HandlesAnnAssign.is_ctypedef_annotation(aa_cd.annotation) != 0:
|
||
ctd_str: str = HandlesType._get_type_name_from_annotation(
|
||
pool, aa_cd.value)
|
||
if ctd_str is not None:
|
||
HandlesType.register_ctypedef(pool, nm_cd.id, ctd_str)
|
||
return 0
|
||
|
||
# _declare_only=1(struct注册模式)时只处理 CDefine,不创建全局变量
|
||
# CDefine 已在上面处理并返回,到这里说明不是 CDefine,直接跳过
|
||
if trans._declare_only == 1:
|
||
return 0
|
||
|
||
var_name: str = None
|
||
var_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
init_val: t.CInt64T = 0
|
||
init_kind: int = 0 # 0=none, 1=int, 2=list, 3=str
|
||
init_str_val: str = None
|
||
init_list_node: ast.List | t.CPtr = None
|
||
|
||
if k == ast.ASTKind.AnnAssign:
|
||
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||
if aa is None or aa.target is None:
|
||
return 0
|
||
if aa.target.kind() != ast.ASTKind.Name:
|
||
return 0
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target)
|
||
var_name = nm.id
|
||
# 解析类型
|
||
if aa.annotation is not None:
|
||
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
||
pool, aa.annotation, trans._imported_modules, trans._from_imports, trans)
|
||
if resolved is not None:
|
||
var_ty = resolved
|
||
# 解析初始值(支持整数、列表字面量、字符串字面量)
|
||
if aa.value is not None:
|
||
val_kind: int = aa.value.kind()
|
||
if val_kind == ast.ASTKind.Constant:
|
||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(aa.value)
|
||
if cn.const_kind == ast.CONST_INT:
|
||
init_val = cn.int_val
|
||
init_kind = 1
|
||
elif cn.const_kind == ast.CONST_STR:
|
||
init_str_val = cn.str_val
|
||
init_kind = 3
|
||
elif val_kind == ast.ASTKind.List:
|
||
init_list_node = (ast.List | t.CPtr)(aa.value)
|
||
init_kind = 2
|
||
elif k == ast.ASTKind.Assign:
|
||
asgn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node)
|
||
if asgn is None or asgn.targets is None:
|
||
return 0
|
||
targets: list[ast.AST | t.CPtr] | t.CPtr = asgn.targets
|
||
if len(targets) < 1:
|
||
return 0
|
||
t0: ast.AST | t.CPtr = targets.get(0)
|
||
if t0 is None or t0.kind() != ast.ASTKind.Name:
|
||
return 0
|
||
nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(t0)
|
||
var_name = nm2.id
|
||
if asgn.value is not None:
|
||
val_kind2: int = asgn.value.kind()
|
||
if val_kind2 == ast.ASTKind.Constant:
|
||
cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(asgn.value)
|
||
if cn2.const_kind == ast.CONST_INT:
|
||
init_val = cn2.int_val
|
||
init_kind = 1
|
||
elif cn2.const_kind == ast.CONST_STR:
|
||
init_str_val = cn2.str_val
|
||
init_kind = 3
|
||
elif val_kind2 == ast.ASTKind.List:
|
||
init_list_node = (ast.List | t.CPtr)(asgn.value)
|
||
init_kind = 2
|
||
|
||
if var_name is None:
|
||
return 0
|
||
|
||
# __all__ 是 Python 模块元数据(公开名列表),无运行时语义:
|
||
# StubGen 的 .vpi 不为其生成 stub 声明(无注解模块级赋值不产出 vpi
|
||
# 条目),此处同样跳过全局创建——否则无注解 list-of-strings 全局
|
||
# 类型推断缺失(var_ty 默认 i32)→ _build_array_initializer_text
|
||
# 返回 None → fail-fast "初始化器构建失败" 误报
|
||
# (Projectrans/__init__.vp 追加83 根因)。与 CDefine/CTypedef
|
||
# 同类:编译期/元数据实体不落入 LLVM 全局。
|
||
if string.strcmp(var_name, "__all__") == 0:
|
||
return 0
|
||
|
||
# 检查是否已注册
|
||
existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
|
||
trans.SymTab, var_name)
|
||
if existing is not None:
|
||
return 0
|
||
|
||
# 创建全局变量 @var_name
|
||
# 先确保 var_ty 中的跨模块结构体类型在模块中有 opaque 声明
|
||
# 否则 @var_name = global %"sha1.ClassName"* zeroinitializer 会报
|
||
# "use of undefined type named 'sha1.ClassName'" 错误
|
||
# (如 _mbuddy: memhub.MemManager | t.CPtr → Ptr(Struct("aeb3...MemManager")))
|
||
llvmlite.module_ensure_opaque_for_type(mod, pool, var_ty)
|
||
# 模块级全局命名带 SHA1 前缀(对齐函数名 mangling):多个模块声明同名
|
||
# 全局(如 _mbuddy)时各自独立命名,消除 ld.lld duplicate symbol。
|
||
# SymTab 注册 key 保持裸名(查找逻辑零改动),LLVM 符号名用 mangled 名。
|
||
mangled_name: str = HandlesFunctions._mangle_name(trans, var_name)
|
||
gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, mangled_name, var_ty)
|
||
if gv is None:
|
||
return 0
|
||
llvmlite.module_add_global(mod, gv)
|
||
|
||
# 设置初始值(有初始值时清除 external linkage,因为 LLVM 22+ 不允许 external global 带初始值)
|
||
gv.Linkage = None
|
||
if init_kind == 1:
|
||
# 整数初始值
|
||
init_buf: str = pool.alloc(48)
|
||
if init_buf is not None:
|
||
viperlib.snprintf(init_buf, 48, "%lld", init_val)
|
||
gv.Initializer = init_buf
|
||
elif init_kind == 2:
|
||
# 列表字面量 → 数组初始化器 [N x elem_ty] [elem_ty val0, ...]
|
||
arr_init: str = self._build_array_initializer_text(pool, var_ty, init_list_node)
|
||
if arr_init is not None:
|
||
gv.Initializer = arr_init
|
||
else:
|
||
# 初始化器构建失败:直接报错终止(fail-fast),不再回退 zeroinitializer
|
||
HandlesType.fatal_error(node, f"模块级变量 '{var_name}' 初始化器构建失败", "TypeError")
|
||
elif init_kind == 3:
|
||
# 字符串字面量初始化
|
||
# 数组类型(t.CArray[t.CChar, N]):字节数组初始化器(字符串内容 + 零填充)
|
||
# ——此前统一走字符串指针 GEP 初始化器 → @g = global [N x i8] <ptr> 类型
|
||
# 不匹配(llc constant expression type mismatch,pyzlib_error_msg 根因)
|
||
is_arr_g: int = 0
|
||
match var_ty:
|
||
case llvmlite.LLVMType.Array(_, _):
|
||
is_arr_g = 1
|
||
case _:
|
||
pass
|
||
if is_arr_g != 0:
|
||
arr_str_init: str = self._build_string_array_initializer_text(
|
||
pool, var_ty, init_str_val)
|
||
if arr_str_init is not None:
|
||
gv.Initializer = arr_str_init
|
||
else:
|
||
HandlesType.fatal_error(
|
||
node, f"模块级数组变量 '{var_name}' 字符串初始化器构建失败", "TypeError")
|
||
else:
|
||
# 指针类型(如 b64_tab: t.CArray[t.CChar, None] = "ABC..."):
|
||
# 创建字符串常量全局 + GEP 引用
|
||
str_init: str = self._build_string_ptr_initializer(pool, mod, var_name, init_str_val)
|
||
if str_init is not None:
|
||
gv.Initializer = str_init
|
||
else:
|
||
HandlesType.fatal_error(
|
||
node, f"模块级变量 '{var_name}' 初始化器构建失败", "TypeError")
|
||
else:
|
||
# 使用 zeroinitializer 而非 "0":指针类型必须用 null/zeroinitializer,
|
||
# 整数/聚合类型也兼容 zeroinitializer,避免 "integer constant must have integer type"
|
||
gv.Initializer = "zeroinitializer"
|
||
|
||
# 创建 Value 引用(@mangled_name, 类型为 var_ty*)
|
||
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
|
||
ref_name: str = pool.alloc(96)
|
||
if ref_name is not None:
|
||
# mangled 名带 SHA1 前缀(数字开头),引用必须加引号(对齐 make_global_ref)
|
||
if HandlesClassDef._vtable_name_needs_quote(mangled_name) != 0:
|
||
viperlib.snprintf(ref_name, 96, "@\"%s\"", mangled_name)
|
||
else:
|
||
viperlib.snprintf(ref_name, 96, "@%s", mangled_name)
|
||
gv_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, var_ptr_ty, ref_name)
|
||
|
||
# 注册到模块作用域
|
||
if HandlesVar.define_module_var(trans.SymTab, var_name, gv_ref) == 0:
|
||
# 设置 AnnotClassName(联合类型如 Logger|t.CPtr 简化为 Ptr(i8) 时,
|
||
# 属性访问需要通过 AnnotClassName 回退到类名查找结构体)
|
||
if k == ast.ASTKind.AnnAssign:
|
||
aa_ml: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||
if aa_ml is not None and aa_ml.annotation is not None:
|
||
cls_nm_ml: str = HandlesType.extract_class_name_from_annotation(
|
||
aa_ml.annotation, trans._imported_modules, pool)
|
||
if cls_nm_ml is not None:
|
||
HandlesVar.set_var_annot_class_name(
|
||
trans.SymTab, var_name, cls_nm_ml)
|
||
return 1
|
||
return 0
|
||
|
||
# ============================================================
|
||
# create_wrapper_main - 创建包装 main 函数
|
||
#
|
||
# 当用户未定义 main 函数时调用。
|
||
# 创建 main() -> i32 函数 → 设置 trans._cur_func/_cur_builder →
|
||
# 预扫描 alloca → 翻译子节点 → ret 0
|
||
# ============================================================
|
||
def create_wrapper_main(self, trans: HT.Translator | t.CPtr,
|
||
tree: ast.AST | t.CPtr,
|
||
i32_ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||
"""创建包装 main 函数并翻译所有顶层语句
|
||
|
||
Args:
|
||
trans: 翻译器(含所有共享状态)
|
||
tree: AST 模块节点
|
||
i32_ty: i32 LLVMType
|
||
|
||
Returns:
|
||
t.CInt: 新增的变量数
|
||
"""
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||
|
||
main_func: llvmlite.Function | t.CPtr = llvmlite.create_function(
|
||
pool, mod, "main", i32_ty)
|
||
if main_func is None:
|
||
VLogger.error("CreateFunction main returned NULL", "TR")
|
||
return 0
|
||
|
||
entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
|
||
pool, main_func, "entry")
|
||
if entry_blk is None:
|
||
VLogger.error("CreateBlock returned NULL", "TR")
|
||
return 0
|
||
|
||
builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, main_func)
|
||
if builder is None:
|
||
VLogger.error("NewBuilder returned NULL", "TR")
|
||
return 0
|
||
llvmlite.position_at_end(builder, entry_blk)
|
||
|
||
# 设置当前翻译上下文(供 Handle 通过 self.Trans._cur_builder 访问)
|
||
trans._cur_func = main_func
|
||
trans._cur_builder = builder
|
||
|
||
# 预处理模块级变量:为 AnnAssign/Assign 创建 LLVM 全局变量
|
||
# 必须在 pre_scan_allocas 之前执行,否则 PreScan 会创建局部 alloca,
|
||
# 导致其他函数通过 SSA 编号引用 wrapper main 的局部变量(无效 IR)
|
||
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||
if ch is not None:
|
||
cn_count: t.CSizeT = len(ch)
|
||
for ci in range(cn_count):
|
||
child: ast.AST | t.CPtr = ch.get(ci)
|
||
if child is not None:
|
||
kd: int = child.kind()
|
||
if kd == ast.ASTKind.AnnAssign or kd == ast.ASTKind.Assign:
|
||
self.handle_module_level_var(trans, child)
|
||
|
||
# 预扫描顶层语句:为函数内 AnnAssign 提前创建 alloca
|
||
# (模块级变量已在上面注册到模块作用域,PreScan 的 lookup_current 会跳过它们)
|
||
if ch is not None:
|
||
for ci in range(cn_count):
|
||
child: ast.AST | t.CPtr = ch.get(ci)
|
||
if child is not None:
|
||
HandlesBody.pre_scan_allocas(trans, child)
|
||
|
||
# 翻译子节点
|
||
added_total: int = self.translate_children(trans, tree)
|
||
|
||
# 返回 0
|
||
zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||
llvmlite.build_ret(builder, zero_val)
|
||
|
||
return added_total
|
||
|
||
# ============================================================
|
||
# global/nonlocal 名称管理(迁移自 HandlesTranslator.vp 模块级函数)
|
||
# ============================================================
|
||
def add_global_name(self, trans: HT.Translator | t.CPtr, name: str):
|
||
"""添加一个 global 变量名"""
|
||
if trans is None or name is None:
|
||
return
|
||
if trans._global_names is None:
|
||
return
|
||
# 检查是否已存在
|
||
if self.is_global_name(trans, name) != 0:
|
||
return
|
||
if trans._global_name_count >= MAX_GLOBAL_NAMES:
|
||
pool_err: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
err_buf: str = None
|
||
if pool_err is not None:
|
||
err_buf = pool_err.alloc(256)
|
||
if err_buf is not None:
|
||
viperlib.snprintf(err_buf, 256, "global 变量数量超过上限 MAX_GLOBAL_NAMES=%d,请减少 global 声明或增大 MAX_GLOBAL_NAMES", MAX_GLOBAL_NAMES)
|
||
VLogger.error(err_buf, "ScopeDecl")
|
||
else:
|
||
VLogger.error("global 变量数量超过上限,请减少 global 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl")
|
||
return
|
||
entry_addr: t.CUInt64T = t.CUInt64T(trans._global_names) + trans._global_name_count * 8
|
||
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
|
||
slot_ptr[0] = name
|
||
trans._global_name_count += 1
|
||
|
||
def is_global_name(self, trans: HT.Translator | t.CPtr, name: str) -> int:
|
||
"""检查 name 是否在当前函数的 global 集合中"""
|
||
if trans is None or name is None or trans._global_names is None:
|
||
return 0
|
||
for i in range(trans._global_name_count):
|
||
entry_addr: t.CUInt64T = t.CUInt64T(trans._global_names) + i * 8
|
||
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
|
||
entry: str = slot_ptr[0]
|
||
if entry is not None:
|
||
if string.strcmp(entry, name) == 0:
|
||
return 1
|
||
return 0
|
||
|
||
def add_nonlocal_name(self, trans: HT.Translator | t.CPtr, name: str,
|
||
var_ty: llvmlite.LLVMType | t.CPtr = None):
|
||
"""添加一个 nonlocal 变量名
|
||
|
||
Args:
|
||
name: nonlocal 变量名
|
||
var_ty: 变量的 LLVM 类型(用于 env 指针数组方案的类型恢复,
|
||
None 时回退为 i32)
|
||
"""
|
||
if trans is None or name is None:
|
||
return
|
||
if trans._nonlocal_names is None:
|
||
return
|
||
if self.is_nonlocal_name(trans, name) != 0:
|
||
# 已存在:更新类型信息(可能在预扫描时类型未知,正式翻译时更新)
|
||
# _nonlocal_types 每槽 8 字节,存 LLVMType* 指针。
|
||
# 用 str|t.CPtr (i8**) 二级指针存取(与 _nonlocal_names 模式一致),
|
||
# [0] 解引用只拷贝 8 字节指针,避免值拷贝 24+ 字节 LLVMType 结构体溢出。
|
||
if var_ty is not None and trans._nonlocal_types is not None:
|
||
idx: int = self.get_nonlocal_index(trans, name)
|
||
if idx >= 0:
|
||
ty_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + idx * 8
|
||
ty_slot: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr)
|
||
ty_slot[0] = var_ty
|
||
return
|
||
if trans._nonlocal_name_count >= MAX_GLOBAL_NAMES:
|
||
pool_err_nl: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
err_buf_nl: str = None
|
||
if pool_err_nl is not None:
|
||
err_buf_nl = pool_err_nl.alloc(256)
|
||
if err_buf_nl is not None:
|
||
viperlib.snprintf(err_buf_nl, 256, "nonlocal 变量数量超过上限 MAX_GLOBAL_NAMES=%d,请减少 nonlocal 声明或增大 MAX_GLOBAL_NAMES", MAX_GLOBAL_NAMES)
|
||
VLogger.error(err_buf_nl, "ScopeDecl")
|
||
else:
|
||
VLogger.error("nonlocal 变量数量超过上限,请减少 nonlocal 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl")
|
||
return
|
||
entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + trans._nonlocal_name_count * 8
|
||
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
|
||
slot_ptr[0] = name
|
||
# 存储类型信息(用 str|t.CPtr = i8** 二级指针,与 _nonlocal_names 一致)
|
||
if trans._nonlocal_types is not None:
|
||
ty_addr2: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + trans._nonlocal_name_count * 8
|
||
ty_slot2: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr2)
|
||
# var_ty 为 None 时直接报错终止(fail-fast),不再默认 i32
|
||
stored_ty: llvmlite.LLVMType | t.CPtr = var_ty
|
||
if stored_ty is None:
|
||
HandlesType.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法注册", "TypeError")
|
||
return
|
||
ty_slot2[0] = stored_ty
|
||
trans._nonlocal_name_count += 1
|
||
trans._closure_env_count += 1
|
||
|
||
def get_nonlocal_type(self, trans: HT.Translator | t.CPtr,
|
||
name: str) -> llvmlite.LLVMType | t.CPtr:
|
||
"""获取 nonlocal 变量的 LLVM 类型
|
||
|
||
Returns: 找到的类型指针,找不到返回 None
|
||
"""
|
||
if trans is None or name is None or trans._nonlocal_types is None:
|
||
return None
|
||
idx: int = self.get_nonlocal_index(trans, name)
|
||
if idx < 0:
|
||
return None
|
||
ty_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + idx * 8
|
||
ty_slot: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr)
|
||
return (llvmlite.LLVMType | t.CPtr)(ty_slot[0])
|
||
|
||
def is_nonlocal_name(self, trans: HT.Translator | t.CPtr, name: str) -> int:
|
||
"""检查 name 是否在当前函数的 nonlocal 集合中"""
|
||
if trans is None or name is None or trans._nonlocal_names is None:
|
||
return 0
|
||
for i in range(trans._nonlocal_name_count):
|
||
entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + i * 8
|
||
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
|
||
entry: str = slot_ptr[0]
|
||
if entry is not None:
|
||
if string.strcmp(entry, name) == 0:
|
||
return 1
|
||
return 0
|
||
|
||
def get_nonlocal_index(self, trans: HT.Translator | t.CPtr, name: str) -> int:
|
||
"""获取 nonlocal 变量在 env 中的索引(0-based),找不到返回 -1"""
|
||
if trans is None or name is None or trans._nonlocal_names is None:
|
||
return -1
|
||
for i in range(trans._nonlocal_name_count):
|
||
entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + i * 8
|
||
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
|
||
entry: str = slot_ptr[0]
|
||
if entry is not None:
|
||
if string.strcmp(entry, name) == 0:
|
||
return i
|
||
return -1
|
||
|
||
def clear_scope_names(self, trans: HT.Translator | t.CPtr):
|
||
"""清空当前函数的 global/nonlocal 名称集合(进入新函数时调用)"""
|
||
if trans is None:
|
||
return
|
||
trans._global_name_count = 0
|
||
trans._nonlocal_name_count = 0
|
||
trans._closure_env_count = 0
|