Files
ViperC/App/lib/core/Gen/TranslatorGenMixin.vp
T
TermiNexus 9f396f4874 refactor(gen): 完成 P6 机械化迁移——Handler 类并入 Gen Mixin,语句实现单层化
- 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)待编译器缺陷修复后删
2026-08-20 06:40:37 +08:00

800 lines
39 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import 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