Phase A-pre(App 预注册)此前不做导入处理、不注入依赖 .vpi,导致包重导出 类的字段注解在预注册期只能保留「包前缀」(1abcd…),并被冻结进结构体布局; 阶段 A 构造函数侧却能借包别名 entry 校正为真定义前缀(e70bd…),两处票名 分裂 ⇒「非基本类型指针不可隐式转换」(现场 ClassGenGeneric.vp:92)。 改动(只放开 App 预注册,不动 includes 预注册那条防依赖环自锁的约束): - Translator 新增 _pre_allow_dep_inject 开关,并在导入处理门拆成两道: ①导入处理 + 自动容器可见性 + LoadDepVpiIntoModule —— 全量翻译与 App 预注册共用; ②模块级变量预注册 + 函数前向声明 —— 仍只在全量翻译做。 - BuildPipeline.TranslateFileGetTrans 新增 pre_allow_dep_inject 参数并写入 Translator。 - Phase2 App 预注册调用点传 1;includes 预注册保持默认 0。
1026 lines
53 KiB
Plaintext
1026 lines
53 KiB
Plaintext
import lib.core.Gen.GenApi as GenApi
|
||
import lib.core.Gen.GenTypes as GenTypes
|
||
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.Projectrans.Config as Config
|
||
import lib.Stub.StubMerger.StubMergerBuild as StubMergerBuild
|
||
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
|
||
import lib.core.Gen.Generator as Generator
|
||
import lib.core.Gen.DebugInfoGen as DebugInfoGen
|
||
|
||
# ============================================================
|
||
# Gen/Translator.vp - 翻译器状态管理 + 主入口
|
||
#
|
||
# 负责: 1) Translator 类(状态管理:Module/变量表/函数表/导入)
|
||
# 2) translate() 主翻译入口 3) dump_ir() IR 输出
|
||
# global/nonlocal 名称管理委托函数在 lib.core.Gen.GenApi,
|
||
# TranslatorGenMixin 侧另有同名一行委托。
|
||
# ============================================================
|
||
|
||
|
||
|
||
# ============================================================
|
||
# HandlesTranslator - 翻译器状态管理 + 主入口
|
||
#
|
||
# 从 translator.py 拆分出来,负责:
|
||
# 1. Translator 类 - 状态管理(Module, 变量表, 函数表, 导入)
|
||
# 2. translate() - 主翻译入口
|
||
# 3. dump_ir() - IR 输出
|
||
#
|
||
# 语句/表达式翻译全部委托给 Handles 模块:
|
||
# HandlesMain - wrapper main 创建 + children 遍历
|
||
# HandlesBody - 语句分派
|
||
# HandlesExpr - 表达式翻译
|
||
# HandlesFunctions - 函数定义处理
|
||
# 注意:str = bytes = str = i8*
|
||
#
|
||
# P6-E 对象化重构:模块级 global/nonlocal 名称管理函数已迁移为
|
||
# lib.core.Gen.TranslatorGenMixin 的方法,本模块保留同名模块级
|
||
# 函数作为"一行委托"(同 P2-P5 模式)。Translator 类保留在本模块。
|
||
# ============================================================
|
||
|
||
# 常量
|
||
# 作用域变量表容量上限(唯一真源)。分配点 VarGenMixin.init_vars
|
||
# (HT.MAX_VARS * VarEntry.__sizeof__())与守卫 VarGenMixin.add_var
|
||
# (var_count >= HT.MAX_VARS)都取本常量,两者结构上不可能各自漂移。
|
||
define MAX_VARS = 1024
|
||
# 函数表容量上限(唯一真源)。分配点在本模块 _init_state
|
||
# (GenApi.init_func_table(pool, MAX_FUNCS));注册侧守卫上限由
|
||
# FuncGenDef/ClassGenVTable/AsyncGenMixin/VpiReader 传给
|
||
# CallGenLeafKit.add_func_to_table 的 max_count 给出,必须 <= 本容量。
|
||
define MAX_FUNCS = 1024
|
||
# 引用口径(同 CallGenBase.vp 常量段):跨模块 t.CDefine 只能在函数体内读,
|
||
# 故引用方一律写限定名 HT.MAX_VARS / HT.MAX_FUNCS,且不得用于模块级
|
||
# CDefine 初始化式。
|
||
# global/nonlocal 名称表容量上限(唯一真源)。TranslatorGenMixin 的
|
||
# add_global_name/add_nonlocal_name 越界守卫与 FuncGenMixin 的嵌套 nonlocal
|
||
# 缓冲分配均经 HT.MAX_GLOBAL_NAMES 引用本常量;缓冲分配(Translator._init_state)
|
||
# 与守卫必须同值,单改任一侧都会造成堆越界写或有效容量缩水。
|
||
define MAX_GLOBAL_NAMES = 128
|
||
# 协程表容量(TPV-M1):async 函数数 / 协程变量·局部名数
|
||
define MAX_CORO_FUNCS = 256
|
||
define MAX_CORO_VARS = 256
|
||
define MAX_CORO_TRY = 16
|
||
|
||
# 翻译主环最大递归深度(translate_stmt/translate_value 嵌套)。AST 自引用环
|
||
# 或翻译 bug 可致翻译主环(语句/表达式/调用)无限递归 → ASan stack-overflow。
|
||
# match 守卫(MatchTranslateDepth)只保护 match 递归,本常量保护语句/表达式
|
||
# 翻译环(fail-fast,对齐 TypeGenResolve 深度守卫模式)。
|
||
define TRANSLATE_MAX_DEPTH = 256
|
||
|
||
|
||
# ============================================================
|
||
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
|
||
# ============================================================
|
||
|
||
novirtual class Translator:
|
||
"""翻译器:管理编译状态,委托 Handles 模块执行翻译"""
|
||
|
||
# LLVM 上下文(共享状态)
|
||
Module: llvmlite.LLVMModule*
|
||
Pool: memhub.MemBuddy*
|
||
|
||
# 函数表
|
||
_funcs: GenTypes.FuncEntry*
|
||
_func_count: int
|
||
|
||
# 协程(TPV-M1 async def / await / coro.coro_run)
|
||
# _async_funcs: 已注册 async 函数裸名表(char* 数组,8 字节/项)
|
||
# _coro_var_async: 变量名→async 函数名 成对表(char* 数组,16 字节/项)
|
||
# _coro_locals: 当前 async 函数局部变量名表(char* 数组,8 字节/项)
|
||
# _coro_frames: async 名→帧类型 成对表(16 字节/项 = char* + LLVMType*)
|
||
_async_funcs: str
|
||
_async_func_count: int
|
||
_coro_var_async: str
|
||
_coro_var_async_count: int
|
||
_coro_locals: str
|
||
_coro_local_count: int
|
||
_coro_frames: str
|
||
_coro_frame_count: int
|
||
# resume_<name> 翻译上下文(AsyncGenMixin 段翻译共享)
|
||
_coro_state_ptr: llvmlite.Value*
|
||
_coro_done_ptr: llvmlite.Value*
|
||
_coro_ret_ptr: llvmlite.Value*
|
||
_coro_exit_bb: rawptr[llvmlite.BasicBlock]
|
||
_coro_await_slot: llvmlite.Value*
|
||
_coro_frame: llvmlite.Value*
|
||
_coro_next_state: int
|
||
_coro_nseg: int
|
||
# M2:async 参数表(char* 数组,8 字节/项)+ 预扫描计数
|
||
_coro_params: str
|
||
_coro_param_count: int
|
||
_coro_hoist_count: int # __await_N 槽计数(预扫描与翻译共用,序一致)
|
||
_coro_await_count: int # 总 await 数(= 恢复块数 = switch case 数)
|
||
_coro_local_base: int # 局部槽起始 index(= 3 + nparams)
|
||
_coro_extra_base: int # 额外槽(__await_N)起始 index
|
||
_coro_break_bb: rawptr[llvmlite.BasicBlock] # While break 目标(M2 单层)
|
||
_coro_continue_bb: rawptr[llvmlite.BasicBlock] # While continue 目标
|
||
_coro_state_bbs: sizet* # 预建 state 块数组(await 恢复块定位)
|
||
# M3-M7 协程扩展
|
||
_coro_exc_ptr: llvmlite.Value* # 帧 exc 槽(i32,M4)
|
||
_coro_msg_ptr: llvmlite.Value* # 帧 msg 槽(i8*,M7)
|
||
_coro_wake_ptr: llvmlite.Value* # 帧 wake 槽(i64,M3 coro_sleep)
|
||
_coro_try_stack: sizet* # try 栈:except/finally 块指针数组(8B/项)
|
||
_coro_try_stack_count: int
|
||
_coro_for_counter: int # range-For 编号(M3,翻译期递增)
|
||
_coro_scan_for_count: int # 预扫描期 For 计数
|
||
_coro_uses_sleep: int # 函数体是否用 coro_sleep(预扫描置位)
|
||
_coro_extra_types: str # 额外槽类型表(i8 数组:1=i32 2=i64)
|
||
_coro_extra_count: int # 额外槽总数
|
||
_coro_await_slots: int | t.CPtr # __await_N 的帧相对槽 index(预扫描填)
|
||
_coro_for_slots: int | t.CPtr # range-For N 的 __f_idx 帧相对槽 index(预扫描填)
|
||
# per-async wake 槽 index 表(coro_run/gather 轮询反查用)
|
||
_coro_wake_names: str # char* 数组(8B/项)
|
||
_coro_wake_idxs: int | t.CPtr # i32 数组(4B/项,-1=无 wake 槽)
|
||
_coro_wake_count: int
|
||
|
||
# 导入模块跟踪
|
||
_imported_modules: str
|
||
_from_imports: str
|
||
|
||
# 当前翻译上下文
|
||
_cur_func: llvmlite.Function*
|
||
_cur_builder: llvmlite.IRBuilder*
|
||
|
||
# 当前赋值语句的注解节点(AnnAssign 翻译 rhs 前设置,Assign 翻译前清空)。
|
||
# 供裸名泛型构造从注解推断类型实参:`s: Stack[int] = Stack()` 用注解里的
|
||
# int 特化(消费者见 CallGenCtor.vp 的 CurAssignNode/CurAssignAnnot 判定)。
|
||
CurAssignAnnot: ast.AST*
|
||
|
||
# 当前赋值语句的 RHS 节点(AnnAssign 翻译 rhs 前设置,rhs 翻译后清除)。
|
||
# 供裸名泛型构造判定"构造调用是否为赋值直接 RHS":仅该 identity 命中时才用
|
||
# CurAssignAnnot 推断类型实参(对齐 TPC 的直接 RHS 检查)。
|
||
CurAssignNode: ast.AST*
|
||
|
||
# 当前函数的返回注解节点(translate_function_def 进入函数体前设置,退出时
|
||
# 恢复外层函数的值)。供裸名泛型构造回退推断类型实参:`-> Stack[int]` 里
|
||
# `return Stack()` 用注解里的 int 特化(与 CurAssignAnnot 同类的上下文通道)。
|
||
CurFuncRetAnnot: ast.AST*
|
||
|
||
# 当前 Return 语句的直接值节点(translate_return 翻译返回值前设置,翻译后
|
||
# 清除)。与 CurAssignNode 同款的 identity 判定:仅「裸名泛型构造就是 return
|
||
# 的直接值」时才用 CurFuncRetAnnot(嵌套调用如 return f(Stack()) 不推断)。
|
||
CurRetNode: ast.AST*
|
||
|
||
# 循环控制流目标(break/continue)
|
||
_break_bb: rawptr[llvmlite.BasicBlock]
|
||
_continue_bb: rawptr[llvmlite.BasicBlock]
|
||
|
||
# 独立标签计数器(不与 builder.Counter 共享,避免 SSA 编号非单调)
|
||
_label_counter: int
|
||
|
||
# 追加90:控制流 merge 块可达性(1=有 br 进入可达/0=全分支 return 结构性不可达)
|
||
_ctrl_merge_reachable: int
|
||
|
||
# match 翻译递归深度(match → case body → translate_value → 嵌套 match)。
|
||
# 守卫:AST 自引用环(子节点回指祖先)或翻译 bug 导致的无限递归在此
|
||
# fail-fast(对齐 TypeGenResolve 深度守卫,防 ASan stack-overflow)。
|
||
MatchTranslateDepth: int
|
||
|
||
# 翻译主环递归深度(translate_stmt/translate_value 入口计数)。match 守卫
|
||
# 只覆盖 match 递归;语句/表达式/调用环(如 translate_value ↔ translate_call)
|
||
# 由本字段守卫,超 TRANSLATE_MAX_DEPTH 即 fail-fast(防 ASan stack-overflow)。
|
||
TranslateDepth: int
|
||
|
||
# global 声明的变量名集合(当前函数内)
|
||
_global_names: str
|
||
_global_name_count: int
|
||
|
||
# nonlocal 声明的变量名集合(当前函数内)
|
||
_nonlocal_names: str
|
||
_nonlocal_name_count: int
|
||
# nonlocal 变量的类型信息(LLVMType 指针数组,与 _nonlocal_names 一一对应)
|
||
# 用于 env 指针数组方案:子函数访问 nonlocal 变量时需要知道原始类型
|
||
_nonlocal_types: str
|
||
|
||
# 闭包相关:当前函数名(用于嵌套函数提升命名)
|
||
_cur_func_name: str
|
||
|
||
# *args 变长参数支持:当前函数的 va_list 指针(i8* alloca)
|
||
# 仅当函数声明了 *args 时设置,供 arg(type) 糖函数使用
|
||
_va_list_ptr: llvmlite.Value*
|
||
# *args 参数名(如 "args"),用于符号表注册
|
||
_vararg_name: str
|
||
|
||
# OOP iter 协议:当前 __next__ 方法的隐藏 stop-flag 参数(i1*)。
|
||
# _translate_method 注入 __stop_iter_flag__ 参数时设置;translate_raise
|
||
# 检测 raise StopIteration 时对该指针 store 1(对齐 TPC HandlesRaise.py)。
|
||
# 非 __next__ 函数中为 None。
|
||
_stop_iter_flag_ptr: llvmlite.Value*
|
||
|
||
# try-except 机制(对齐 TPC HandlesTry.py):当前最内层 try 的
|
||
# 分发块 + 异常编码/消息 alloca。translate_try 设置,translate_raise
|
||
# 与调用侧 EH 检测写入/跳转。try 外为 None。
|
||
_eh_dispatch_bb: rawptr[llvmlite.BasicBlock]
|
||
_eh_code_ptr: llvmlite.Value*
|
||
_eh_msg_ptr: llvmlite.Value*
|
||
# 当前函数的 __eh_msg_out__(i8**)/__eh_code_out__(i32*)输出参数
|
||
# (函数签名含 raise 时由 translate_function_def/_translate_method 注入)。
|
||
# 无 EH 参数时 _cur_func_has_eh == 0。
|
||
_eh_msg_out_param: llvmlite.Value*
|
||
_eh_code_out_param: llvmlite.Value*
|
||
_cur_func_has_eh: int
|
||
|
||
# 模块 SHA1 前缀(16 字符),用于函数名混淆(SHA1 命名空间)
|
||
ModuleSha1: str
|
||
# 当前文件所属包名(如 "llvmlite"),用于解析相对导入(from . import ...)
|
||
# None 表示当前文件是顶级模块(无包),相对导入无法解析
|
||
CurrentPackage: str
|
||
# 闭包 env 中的 nonlocal 变量偏移映射(每个 nonlocal 变量在 env 中的字节偏移)
|
||
_closure_env_offsets: int
|
||
_closure_env_count: int
|
||
# lambda 表达式全局唯一 ID 计数器(生成提升函数名 __lambda_{id})
|
||
# 独立于 _closure_env_count:后者随函数进入被 clear_scope_names 重置,
|
||
# lambda ID 需跨函数全局唯一(提升函数名避免冲突)
|
||
_lambda_count: int
|
||
# 函数链内 nonlocal 变量集合(预扫描收集,含嵌套函数声明的 nonlocal)。
|
||
# 用于"不同层捕获不同变量"场景(如 level1→a, level2→b):b 定义在最外层
|
||
# 但 level1 不捕获——level1 env 无 b 槽,level2 无法经 env 链获取 b 的堆。
|
||
# 解决:在最外层函数中为链内所有 nonlocal 建堆,并把堆地址 store 到
|
||
# 模块级映射变量 @nlheap.{sha1}.{name};内层闭包创建时从映射 load。
|
||
_nl_chain_names: t.CPtr
|
||
_nl_chain_count: int
|
||
# 链内 nonlocal 堆预建标志(每函数只建一次):translate_function_def 进入
|
||
# 新函数时重置为 0;_prepare_chain_nonlocals 首次调用置 1。多个嵌套函数
|
||
# 定义共享同一堆(防重复 malloc + 二次重定向 VarEntry.Alloca)。
|
||
_nl_chain_done: int
|
||
|
||
# 泛型特化上下文:当前正在特化的类型参数名/实参名列表
|
||
# 由 _specialize_generic_class 设置,方法体翻译时用于将 T 替换为具体类型
|
||
# None 表示不在泛型特化上下文中
|
||
GenericTypeParamNames: list[str]*
|
||
GenericTypeArgs: list[str]*
|
||
|
||
# Phase 1a 声明模式标志:1=只注册 struct/enum/union 不翻译代码体,0=全量翻译
|
||
_declare_only: int
|
||
|
||
# App 预注册(Phase A-pre)专用开关:置 1 时,即使 _declare_only != 0 也执行
|
||
# 导入语句处理与 LoadDepVpiIntoModule(依赖 stub 注入),使**类字段注解在预注册期
|
||
# 就与阶段 A 处于同一上下文**。
|
||
# 为什么需要:预注册期要注册类的字段类型,而包重导出类的票名前缀校正
|
||
# (`_class_true_def_sha1`)依赖包 __init__ 注入时登记的别名 entry;预注册期不注入
|
||
# ⇒ 只能保留**包前缀**,该票名被冻结进结构体布局,与阶段 A 构造函数侧解析出的
|
||
# 真定义前缀分裂 ⇒「指针隐式转指针已禁止」(现场 ClassGenGeneric.vp:92,
|
||
# `list[ast.ClassDef*]`:预注册得 1abcd….ClassDef*、阶段 A 得 e70bd….ClassDef*)。
|
||
# 只对 **App 预注册**置位:includes 预注册(Phase A-pre-inc)必须保持不注入,
|
||
# 否则依赖环自锁(见下方 `_declare_only == 0` 门处注释)。
|
||
_pre_allow_dep_inject: int
|
||
|
||
# 嵌套作用域符号表
|
||
SymTab: rawptr[GenTypes.SymbolTable]
|
||
|
||
# REPL 模式上下文(M2 会话变量):None ⇒ 非 REPL(普通编译路径逐字不变)。
|
||
# 仅 Repl.vp 在翻译片段前置位、翻译后清空;Gen 侧全部会话槽拦截点以
|
||
# `trans.ReplCtx is not None` 为唯一守卫。
|
||
ReplCtx: rawptr[GenTypes.ReplCtx]
|
||
|
||
def __init__(self):
|
||
self.Module = None
|
||
self.Pool = None
|
||
self._funcs = None
|
||
self._func_count = 0
|
||
self._cur_func = None
|
||
self._cur_builder = None
|
||
self._break_bb = None
|
||
self._continue_bb = None
|
||
self._label_counter = 0
|
||
self._imported_modules = None
|
||
self._from_imports = None
|
||
self._global_names = None
|
||
self._global_name_count = 0
|
||
self._nonlocal_names = None
|
||
self._nonlocal_name_count = 0
|
||
self._nonlocal_types = None
|
||
self._cur_func_name = None
|
||
self._va_list_ptr = None
|
||
self._vararg_name = None
|
||
self._stop_iter_flag_ptr = None
|
||
self._eh_dispatch_bb = None
|
||
self._eh_code_ptr = None
|
||
self._eh_msg_ptr = None
|
||
self._eh_msg_out_param = None
|
||
self._eh_code_out_param = None
|
||
self._cur_func_has_eh = 0
|
||
self.ModuleSha1 = None
|
||
self.CurrentPackage = None
|
||
self._closure_env_offsets = 0
|
||
self._closure_env_count = 0
|
||
self._lambda_count = 0
|
||
self._nl_chain_names = None
|
||
self._nl_chain_count = 0
|
||
self._nl_chain_done = 0
|
||
self.GenericTypeParamNames = None
|
||
self.GenericTypeArgs = None
|
||
self._declare_only = 0
|
||
self._pre_allow_dep_inject = 0
|
||
self.SymTab = None
|
||
# REPL 模式上下文:默认未设置(= 非 REPL,Gen 侧拦截全部旁路)
|
||
self.ReplCtx = None
|
||
self._async_funcs = None
|
||
self._async_func_count = 0
|
||
self._coro_var_async = None
|
||
self._coro_var_async_count = 0
|
||
self._coro_locals = None
|
||
self._coro_local_count = 0
|
||
self._coro_frames = None
|
||
self._coro_frame_count = 0
|
||
self._coro_state_ptr = None
|
||
self._coro_done_ptr = None
|
||
self._coro_ret_ptr = None
|
||
self._coro_exit_bb = None
|
||
self._coro_await_slot = None
|
||
self._coro_frame = None
|
||
self._coro_next_state = 1
|
||
self._coro_nseg = 0
|
||
self._coro_params = None
|
||
self._coro_param_count = 0
|
||
self._coro_hoist_count = 0
|
||
self._coro_await_count = 0
|
||
self._coro_local_base = 3
|
||
self._coro_extra_base = 3
|
||
self._coro_break_bb = None
|
||
self._coro_continue_bb = None
|
||
self._coro_state_bbs = None
|
||
self._coro_exc_ptr = None
|
||
self._coro_msg_ptr = None
|
||
self._coro_wake_ptr = None
|
||
self._coro_try_stack = None
|
||
self._coro_try_stack_count = 0
|
||
self._coro_for_counter = 0
|
||
self._coro_scan_for_count = 0
|
||
self._coro_uses_sleep = 0
|
||
self._coro_extra_types = None
|
||
self._coro_extra_count = 0
|
||
self._coro_await_slots = None
|
||
self._coro_for_slots = None
|
||
self._coro_wake_names = None
|
||
self._coro_wake_idxs = None
|
||
self._coro_wake_count = 0
|
||
|
||
# ============================================================
|
||
# 状态初始化
|
||
# ============================================================
|
||
def _init_state(self, pool: memhub.MemBuddy*):
|
||
"""初始化变量表、函数表和子 Handle"""
|
||
self.Pool = pool
|
||
if self._funcs is None:
|
||
self._funcs = GenApi.init_func_table(pool, MAX_FUNCS)
|
||
# 嵌套作用域符号表(新版)
|
||
if self.SymTab is None:
|
||
self.SymTab = GenApi.init_symbol_table(pool)
|
||
# global/nonlocal 名称集合缓冲区(MAX_GLOBAL_NAMES 个 char* 指针 = 128*8 字节)
|
||
if self._global_names is None:
|
||
self._global_names = stdlib.malloc(MAX_GLOBAL_NAMES * 8)
|
||
if self._global_names is not None:
|
||
string.memset(self._global_names, 0, MAX_GLOBAL_NAMES * 8)
|
||
self._global_name_count = 0
|
||
if self._nonlocal_names is None:
|
||
self._nonlocal_names = stdlib.malloc(MAX_GLOBAL_NAMES * 8)
|
||
if self._nonlocal_names is not None:
|
||
string.memset(self._nonlocal_names, 0, MAX_GLOBAL_NAMES * 8)
|
||
self._nonlocal_name_count = 0
|
||
# nonlocal 变量类型数组(LLVMType 指针数组,与 _nonlocal_names 一一对应)
|
||
if self._nonlocal_types is None:
|
||
self._nonlocal_types = stdlib.malloc(MAX_GLOBAL_NAMES * 8)
|
||
if self._nonlocal_types is not None:
|
||
string.memset(self._nonlocal_types, 0, MAX_GLOBAL_NAMES * 8)
|
||
|
||
# 协程表(TPV-M1):async 函数名 / 变量→async 映射 / 局部名 / 帧类型
|
||
if self._async_funcs is None:
|
||
self._async_funcs = stdlib.malloc(MAX_CORO_FUNCS * 8)
|
||
if self._async_funcs is not None:
|
||
string.memset(self._async_funcs, 0, MAX_CORO_FUNCS * 8)
|
||
self._async_func_count = 0
|
||
if self._coro_var_async is None:
|
||
self._coro_var_async = stdlib.malloc(MAX_CORO_VARS * 16)
|
||
if self._coro_var_async is not None:
|
||
string.memset(self._coro_var_async, 0, MAX_CORO_VARS * 16)
|
||
self._coro_var_async_count = 0
|
||
if self._coro_locals is None:
|
||
self._coro_locals = stdlib.malloc(MAX_CORO_VARS * 8)
|
||
if self._coro_locals is not None:
|
||
string.memset(self._coro_locals, 0, MAX_CORO_VARS * 8)
|
||
if self._coro_params is None:
|
||
self._coro_params = stdlib.malloc(MAX_CORO_VARS * 8)
|
||
if self._coro_params is not None:
|
||
string.memset(self._coro_params, 0, MAX_CORO_VARS * 8)
|
||
if self._coro_try_stack is None:
|
||
self._coro_try_stack = stdlib.malloc(MAX_CORO_TRY * 8)
|
||
if self._coro_try_stack is not None:
|
||
string.memset(self._coro_try_stack, 0, MAX_CORO_TRY * 8)
|
||
if self._coro_extra_types is None:
|
||
self._coro_extra_types = stdlib.malloc(MAX_CORO_VARS)
|
||
if self._coro_extra_types is not None:
|
||
string.memset(self._coro_extra_types, 0, MAX_CORO_VARS)
|
||
if self._coro_await_slots is None:
|
||
self._coro_await_slots = stdlib.malloc(MAX_CORO_VARS * 4)
|
||
if self._coro_await_slots is not None:
|
||
string.memset(self._coro_await_slots, 0, MAX_CORO_VARS * 4)
|
||
if self._coro_for_slots is None:
|
||
self._coro_for_slots = stdlib.malloc(MAX_CORO_VARS * 4)
|
||
if self._coro_for_slots is not None:
|
||
string.memset(self._coro_for_slots, 0, MAX_CORO_VARS * 4)
|
||
if self._coro_wake_names is None:
|
||
self._coro_wake_names = stdlib.malloc(MAX_CORO_FUNCS * 8)
|
||
if self._coro_wake_names is not None:
|
||
string.memset(self._coro_wake_names, 0, MAX_CORO_FUNCS * 8)
|
||
if self._coro_wake_idxs is None:
|
||
self._coro_wake_idxs = stdlib.malloc(MAX_CORO_FUNCS * 4)
|
||
if self._coro_wake_idxs is not None:
|
||
string.memset(self._coro_wake_idxs, 0, MAX_CORO_FUNCS * 4)
|
||
self._coro_local_count = 0
|
||
if self._coro_frames is None:
|
||
self._coro_frames = stdlib.malloc(MAX_CORO_FUNCS * 16)
|
||
if self._coro_frames is not None:
|
||
string.memset(self._coro_frames, 0, MAX_CORO_FUNCS * 16)
|
||
self._coro_frame_count = 0
|
||
|
||
# ============================================================
|
||
# 主翻译入口
|
||
# ============================================================
|
||
def translate(self, tree: ast.AST*) -> int:
|
||
"""将 AST 翻译为 LLVM IR"""
|
||
if tree is None:
|
||
return 1
|
||
if _mbuddy is None:
|
||
return 1
|
||
|
||
pool: memhub.MemBuddy* = _mbuddy
|
||
|
||
# OOM 归属:把「阶段/当前模块」写进 memhub 的分配上下文。池耗尽时 memhub 会打印
|
||
# ctx=阶段/模块,从而知道是在翻译哪个模块时被吃满(SetAllocCtx 只存指针不拷贝,
|
||
# ModuleSha1 由调用方在 translate 前设置且与本次翻译同寿命)。此前无人设置该上下文。
|
||
memhub.SetAllocCtx("translate", self.ModuleSha1)
|
||
|
||
# 初始化状态
|
||
self._init_state(pool)
|
||
|
||
# 创建 LLVM 模块
|
||
mod: llvmlite.LLVMModule* = llvmlite.new_module(pool, "main")
|
||
if mod is None:
|
||
VLogger.error("NewModule returned NULL", "TR")
|
||
return 1
|
||
self.Module = mod
|
||
|
||
# --traceback: reset per-module DWARF state (no-op when DI is disabled).
|
||
DebugInfoGen.BeginModule(mod, GenApi.get_current_file())
|
||
|
||
# 设置目标(优先使用 project.vpj 中的配置)
|
||
triple: str = Config.TargetTriple
|
||
if triple is None:
|
||
triple = "x86_64-pc-windows-msvc"
|
||
llvmlite.module_set_target(mod, triple)
|
||
|
||
# 类型
|
||
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
|
||
|
||
# 声明 printf
|
||
printf_func: llvmlite.Function* = llvmlite.create_declare(pool, mod, "printf", i32_ty)
|
||
if printf_func is None:
|
||
VLogger.error("CreateDeclare printf returned NULL", "TR")
|
||
return 1
|
||
llvmlite.add_param(pool, printf_func, i8_ptr_ty, "fmt")
|
||
printf_func.IsVarArg = 1
|
||
# 声明 LLVM va_start/va_end intrinsic(供 *args 函数体内使用)
|
||
# declare void @llvm.va_start(i8*)
|
||
# declare void @llvm.va_end(i8*)
|
||
void_ty_decl: llvmlite.LLVMType* = llvmlite.Void(pool)
|
||
va_start_func: llvmlite.Function* = llvmlite.create_declare(pool, mod, "llvm.va_start", void_ty_decl)
|
||
if va_start_func is not None:
|
||
llvmlite.add_param(pool, va_start_func, i8_ptr_ty, "ap")
|
||
va_end_func: llvmlite.Function* = llvmlite.create_declare(pool, mod, "llvm.va_end", void_ty_decl)
|
||
if va_end_func is not None:
|
||
llvmlite.add_param(pool, va_end_func, i8_ptr_ty, "ap")
|
||
|
||
# 声明 malloc(闭包分配用)
|
||
malloc_func: llvmlite.Function* = llvmlite.create_declare(pool, mod, "malloc", i8_ptr_ty)
|
||
if malloc_func is not None:
|
||
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
|
||
llvmlite.add_param(pool, malloc_func, i64_ty, "size")
|
||
|
||
# 检查用户是否定义了 main 函数
|
||
has_user_main: int = 0
|
||
ch: list[ast.AST*]* = tree.children
|
||
if ch is not None:
|
||
cn_count: sizet = len(ch)
|
||
for ci in range(cn_count):
|
||
child: ast.AST* = ch.get(ci)
|
||
if child is not None and child.kind() == ast.ASTKind.FunctionDef:
|
||
fd: ast.FunctionDef* = ast.FunctionDef*(child)
|
||
if fd is not None and fd.name is not None:
|
||
if string.strcmp(fd.name, "main") == 0:
|
||
has_user_main = 1
|
||
break
|
||
|
||
if self._declare_only != 0:
|
||
# Phase 1a-pre(2=import扫描) / Phase 1a(1=struct注册): 只处理模块级,不创建 main 函数和 builder
|
||
self._translate_module_level(pool, mod, tree)
|
||
elif has_user_main == 0:
|
||
# 无用户 main → 只翻译模块级语句,不创建 wrapper main
|
||
# (避免每个文件都生成 define i32 @main() 导致链接冲突;只有 def main() 的入口文件才生成)
|
||
self._translate_module_level(pool, mod, tree)
|
||
else:
|
||
# 用户已定义 main → 委托 HandlesMain 翻译模块级
|
||
self._translate_module_level(pool, mod, tree)
|
||
|
||
# --traceback: register module-level !llvm.dbg.cu / !llvm.module.flags
|
||
# before the caller dumps the IR. Idempotent; no-op when no define got a
|
||
# DISubprogram (stub / _declare_only) or when DI is disabled.
|
||
DebugInfoGen.Finalize(pool)
|
||
|
||
return 0
|
||
# ============================================================
|
||
# 包装 main 函数(无用户 main 时)→ 委托 HandlesMain
|
||
# ============================================================
|
||
def _translate_wrapper_main(self, pool: memhub.MemBuddy*,
|
||
mod: llvmlite.LLVMModule*,
|
||
tree: ast.AST*,
|
||
i32_ty: llvmlite.LLVMType*):
|
||
"""委托 GenApi.create_wrapper_main() 创建包装 main(trans 单参)"""
|
||
added: int = GenApi.create_wrapper_main(self, tree, i32_ty)
|
||
|
||
# ============================================================
|
||
# 模块级翻译(用户已定义 main)→ 委托 HandlesMain
|
||
# ============================================================
|
||
def _translate_module_level(self, pool: memhub.MemBuddy*,
|
||
mod: llvmlite.LLVMModule*,
|
||
tree: ast.AST*):
|
||
"""委托 GenApi.translate_children() 翻译模块级语句(trans 单参)"""
|
||
# 【文件级类名预登记:三种模式都必须先做(2026-09-30)】
|
||
# `_norm_type_arg_name` 规则 5.5 的第五类证据(is_file_class +
|
||
# get_file_module_sha1)**只由本调用建立**,而下方 prologue 整块被
|
||
# `_declare_only == 0` 门住 ⇒ Phase 1a(_declare_only == 1)的
|
||
# `_prescan_funcdef_signatures` 解析**模块级函数签名**注解时,证据⑤ 恒落空:
|
||
# 现场 includes/ast/base.vp —— 类型实参裸名 'AST' 的 ①②③④ 也全落空
|
||
# (该类尚未 register_struct;"类定义窗口"还停在更早的 enum ASTFlag,
|
||
# CurDefClassName 不会在类结束后复位)⇒ 实参特化名被冻结成**裸名**版本,
|
||
# 与 1b 全量翻译期解析出的带 SHA1 形式分裂成两个特化结构体名,最终以
|
||
# "非基本类型指针不可隐式转换"报出。
|
||
# 登记只依赖 tree + 本文件模块 SHA1,与导入、类定义窗口、类定义顺序都无关,
|
||
# 故提到门之前,三种模式(1a=1 / 1a-pre=2 / 全量=0)共用。
|
||
GenApi.register_file_classes(pool, self.ModuleSha1, tree)
|
||
# 本文件顶层函数名预登记(同址、同目的):依赖 vpi 注入的**裸名**声明
|
||
# (extern/state/export 不带 SHA1 前缀)若与本文件自己的声明同名,会先占用
|
||
# 该名字,使本文件声明在 forward_declare_functions 被静默丢弃(调用点改按
|
||
# 依赖签名 coerce)。现场:includes/socket.vp 的 extern def connect 被
|
||
# w32.winsock2 的 connect 顶掉 → socket.vp:236 报
|
||
# 「指针隐式转指针已禁止:SocketAddr* → WSASocketAddr*」。
|
||
GenApi.register_file_funcs(pool, tree)
|
||
# 先处理导入语句,再创建前向声明,解决前向引用问题。
|
||
# 两道门分开:
|
||
# ① 导入处理 + 自动容器可见性 + 依赖 vpi 注入 —— 全量翻译**与 App 预注册**
|
||
# (_pre_allow_dep_inject,见 Translator 字段说明)都要做,使类字段注解
|
||
# 在预注册期即与阶段 A 同上下文(否则包重导出类的票名前缀会分裂:
|
||
# list[ast.ClassDef*] 现场);
|
||
# ② 模块级变量预注册 + 函数前向声明 —— 仍只在全量翻译做(声明期跳过,
|
||
# 保持 Phase A-pre 的"只注册 struct/enum/union"语义)。
|
||
# includes 预注册(Phase A-pre-inc)两者都不做:_pre_allow_dep_inject 只由
|
||
# App 预注册置位,避免依赖环自锁。
|
||
if self._declare_only == 0 or self._pre_allow_dep_inject != 0:
|
||
# 预处理导入语句,确保 _imported_modules 和 _from_imports 已填充
|
||
# (前向声明需要解析类型注解,如 t.CArray[str] 依赖 t 模块已导入)
|
||
# 记录最后处理的 import 行号,供 vpi 注入错误上下文帧定位
|
||
cur_imp_lineno: int = 0
|
||
ch: list[ast.AST*]* = tree.children
|
||
if ch is not None:
|
||
cn_count: sizet = len(ch)
|
||
for ci in range(cn_count):
|
||
child: ast.AST* = ch.get(ci)
|
||
if child is None:
|
||
continue
|
||
kd: int = child.kind()
|
||
if kd == ast.ASTKind.Import:
|
||
cur_imp_lineno = child.lineno
|
||
GenApi.translate_import(self, child)
|
||
elif kd == ast.ASTKind.ImportFrom:
|
||
cur_imp_lineno = child.lineno
|
||
GenApi.translate_import_from_module(self, child)
|
||
GenApi.translate_import_from_names(self, child)
|
||
# 对齐 TPC _inject_auto_imports:检测源文件对 list/dict 容器的使用
|
||
# (裸名注解 d: dict / 构造 dict(...) / 下标 list[T]),自动把容器
|
||
# 类标记为可见结构体。背景:_list.vp/_dict.vp 定义内建容器类且已由
|
||
# Phase1 注册,但源文件不显式 import 它们(TPC 在翻译前自动注入
|
||
# import _list/_dict);TPV 用可见性机制等效替代——否则裸名
|
||
# `d: dict` 注解 resolve_annotation_type 时 is_struct_visible=0
|
||
# 解析失败(DictTest 的 "变量类型注解解析失败")。
|
||
self._inject_auto_container_visibility(pool, tree)
|
||
# CTypedef 声明由 Phase1 1b 文本扫描注册(RegisterCTypedefFromSource)——
|
||
# AST 字符串字段 token 零拷贝指向 src_buf,跨阶段内容不稳定,此处 AST 扫描
|
||
# 读 attr 会 0xC0000005,故移除。
|
||
# 跨模块 .vpi 注入:加载依赖模块的 .vpi,把函数 declare 注入当前模块。
|
||
# 注入条件 = 全量翻译,或 **App 预注册**(_pre_allow_dep_inject):后者必须
|
||
# 与阶段 A 同上下文,否则预注册期解析出的类字段票名(包重导出类的
|
||
# 真定义前缀校正依赖包别名 entry)会与阶段 A 分裂。includes 预注册
|
||
# (Phase A-pre-inc)不置位该开关 ⇒ 仍不注入,避免依赖环自锁。
|
||
if self._imported_modules is not None:
|
||
# 错误上下文帧:当前模块触发依赖 stub 加载的 import 位置
|
||
GenApi.push_trace(GenApi.get_current_file(), cur_imp_lineno)
|
||
StubMergerBuild.LoadDepVpiIntoModule(pool, mod, self._imported_modules, self._from_imports, GenApi.get_temp_dir(), self)
|
||
GenApi.pop_trace()
|
||
# 文件级类名预登记已提前到本函数开头执行(覆盖三种 _declare_only 模式;
|
||
# 为什么必须早于模块级变量/前向声明,见那里的说明)。
|
||
# 模块级变量预注册 + 函数前向声明:仍**只在全量翻译**做(声明期跳过,
|
||
# 保持 Phase A-pre"只注册 struct/enum/union"的语义)。
|
||
if self._declare_only == 0:
|
||
# 预注册模块级变量(AnnAssign/Assign)到 SymTab
|
||
# 解决时序问题:class Logger 的 __init__ 引用 _mbuddy 时,
|
||
# _mbuddy 的 AnnAssign 在 AST 中位于 class Logger 之后,
|
||
# 按 AST 顺序翻译时 _mbuddy 尚未注册 → lookup_var 返回 None → rhs_val is None
|
||
# 预处理先于 translate_children 注册所有模块级变量,
|
||
# 后续 translate_children 遍历到同一 AnnAssign 时 handle_module_level_var
|
||
# 通过 lookup_module_var 检测已存在并跳过(HandlesMain.py:206-209)
|
||
if ch is not None:
|
||
for ci in range(cn_count):
|
||
child: ast.AST* = ch.get(ci)
|
||
if child is None:
|
||
continue
|
||
kd_mv: int = child.kind()
|
||
if kd_mv == ast.ASTKind.AnnAssign or kd_mv == ast.ASTKind.Assign:
|
||
GenApi.handle_module_level_var(self, child)
|
||
# 创建前向声明
|
||
GenApi.forward_declare_functions(self, tree)
|
||
added: int = GenApi.translate_children(self, tree)
|
||
|
||
# 容器模块自动可见性注入(对齐 TPC _inject_auto_imports)
|
||
# TPC 在翻译前自动注入 `import _list / import _dict (+json)`,使 list/dict 内建容器类
|
||
# 在符号表中可见;TPV 用可见性机制等效替代:_list.vp/_dict.vp 已由 Phase1 注册,
|
||
# 这里只需在当前文件翻译时把容器类名标记为可见结构体,裸名注解/构造即可解析。
|
||
# 检测模式(与 TPC Phase2Translator._inject_auto_imports 一致):
|
||
# - AnnAssign 注解裸名 Name(list/dict):d: dict
|
||
# - 构造调用 func 裸名 Name(list/dict):dict(bd)
|
||
# - Subscript 的 value 裸名 Name(list/dict):list[int]
|
||
def _inject_auto_container_visibility(self, pool: memhub.MemBuddy*,
|
||
tree: ast.AST*):
|
||
"""检测 list/dict 容器使用,注入容器类可见性"""
|
||
if tree is None or tree.children is None:
|
||
return
|
||
# 用栈式缓冲区传递检测结果(跨函数参数用 4 字节 int 指针)
|
||
need_list_box: t.CPtr = stdlib.malloc(4)
|
||
need_dict_box: t.CPtr = stdlib.malloc(4)
|
||
if need_list_box is None or need_dict_box is None:
|
||
if need_list_box is not None:
|
||
stdlib.free(need_list_box)
|
||
if need_dict_box is not None:
|
||
stdlib.free(need_dict_box)
|
||
return
|
||
need_list_box[0] = 0
|
||
need_dict_box[0] = 0
|
||
self._scan_container_usage(tree, need_list_box, need_dict_box)
|
||
if need_dict_box[0] != 0:
|
||
# dict 类可见 + _dict 模块导入(构造/方法调用的 SHA1 解析)
|
||
GenApi.add_visible_struct(pool, "dict")
|
||
if self._imported_modules is None or \
|
||
GenApi.is_module_imported(self._imported_modules, "_dict") == 0:
|
||
# [FIX 2026-08-31] 破环:_dict 自身依赖含当前模块则跳过注入。
|
||
# 对齐 Phase1Main._InjectedCreatesCycle,覆盖所有 translate 路径
|
||
# (Phase1 1b / Phase2 pre-inc / PhaseA)——否则 _list/_dict 显式
|
||
# import memhub 且 memhub 用容器泛型时成 2-环,Phase A 永不收敛。
|
||
if self._ContainerInjectionCreatesCycle("_dict") == 0:
|
||
self._imported_modules = GenApi.add_imported_module(pool, self._imported_modules, "_dict")
|
||
if need_list_box[0] != 0:
|
||
GenApi.add_visible_struct(pool, "list")
|
||
if self._imported_modules is None or \
|
||
GenApi.is_module_imported(self._imported_modules, "_list") == 0:
|
||
if self._ContainerInjectionCreatesCycle("_list") == 0:
|
||
self._imported_modules = GenApi.add_imported_module(pool, self._imported_modules, "_list")
|
||
stdlib.free(need_list_box)
|
||
stdlib.free(need_dict_box)
|
||
|
||
def _ContainerInjectionCreatesCycle(self, mod_name: str) -> int:
|
||
"""注入 mod_name(_list/_dict)前检查是否成环,返回 1=成环需跳过注入。
|
||
|
||
判断被注入模块自身的 deps 是否已含当前模块名。若命中(如 _list 显式
|
||
import memhub,而 memhub 因 `__provides__: list[str]` 注解要注入 _list)
|
||
→ memhub↔_list 循环依赖 → Phase A 多遍收敛死锁(gfx.vp "无法完成翻译"
|
||
根因)。对齐 Phase1Main._InjectedCreatesCycle,但本方法走 self.ModuleSha1
|
||
查 RelPath,覆盖所有 translate 路径(Phase1 1b 全量翻译、Phase2 pre-inc/
|
||
PhaseA 都会执行 _inject_auto_container_visibility)。命中则跳过注入:
|
||
去掉环边后,_list 已因当前模块被其依赖而处于闭包,list 类仍由
|
||
add_visible_struct 可见、泛型模板已由 Phase1 注册。
|
||
"""
|
||
if mod_name is None or self.ModuleSha1 is None:
|
||
return 0
|
||
inj_sha1: str = StubMergerStore.LookupSha1ByModName(mod_name)
|
||
if inj_sha1 is None:
|
||
return 0
|
||
inj_deps: str = StubMergerStore.LookupIncludesDeps(inj_sha1)
|
||
if inj_deps is None:
|
||
return 0
|
||
# 当前模块名 = RelPath 基名(最后 '/' 或 '\\' 之后)去扩展名
|
||
rel_path: str = StubMergerStore.LookupSha1RelPath(self.ModuleSha1)
|
||
if rel_path is None:
|
||
return 0
|
||
base: str = string.strrchr(rel_path, '/')
|
||
if base is None:
|
||
base = string.strrchr(rel_path, '\\')
|
||
if base is not None:
|
||
base = base + 1
|
||
else:
|
||
base = rel_path
|
||
dot: str = string.strchr(base, '.')
|
||
nm_buf: bytes = stdlib.malloc(128)
|
||
if nm_buf is None:
|
||
return 0
|
||
if dot is not None:
|
||
nm_len: sizet = sizet(uint64(dot) - uint64(base))
|
||
if nm_len > 127:
|
||
nm_len = 127
|
||
string.strncpy(nm_buf, base, nm_len)
|
||
nm_buf[nm_len] = '\0'
|
||
else:
|
||
string.strncpy(nm_buf, base, 127)
|
||
nm_buf[127] = '\0'
|
||
# 词边界精确匹配:inj_deps 中是否有 token 与当前模块名相同
|
||
nm_len2: sizet = string.strlen(nm_buf)
|
||
d_len: sizet = string.strlen(inj_deps)
|
||
dp: sizet = 0
|
||
while dp < d_len:
|
||
ts: sizet = dp
|
||
while dp < d_len and inj_deps[dp] != ' ':
|
||
dp += 1
|
||
tl: sizet = dp - ts
|
||
if dp < d_len:
|
||
dp += 1
|
||
if tl > 0 and tl == nm_len2 and string.strncmp(inj_deps + ts, nm_buf, tl) == 0:
|
||
stdlib.free(nm_buf)
|
||
return 1
|
||
stdlib.free(nm_buf)
|
||
return 0
|
||
|
||
def _scan_container_usage(self, node: ast.AST*,
|
||
need_list_box: t.CPtr,
|
||
need_dict_box: t.CPtr):
|
||
"""递归扫描 AST 语句结构,检测 list/dict 容器使用"""
|
||
if node is None:
|
||
return
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.AnnAssign:
|
||
aa_s: ast.AnnAssign* = ast.AnnAssign*(node)
|
||
if aa_s.annotation is not None:
|
||
self._check_container_type_node(aa_s.annotation, need_list_box, need_dict_box)
|
||
elif k == ast.ASTKind.Call:
|
||
cl_s: ast.Call* = ast.Call*(node)
|
||
if cl_s.func is not None:
|
||
self._check_container_type_node(cl_s.func, need_list_box, need_dict_box)
|
||
elif k == ast.ASTKind.Subscript:
|
||
sub_s: ast.Subscript* = ast.Subscript*(node)
|
||
if sub_s.value is not None:
|
||
self._check_container_type_node(sub_s.value, need_list_box, need_dict_box)
|
||
elif k == ast.ASTKind.FunctionDef:
|
||
fd_s: ast.FunctionDef* = ast.FunctionDef*(node)
|
||
if fd_s.returns is not None:
|
||
self._check_container_type_node(fd_s.returns, need_list_box, need_dict_box)
|
||
if fd_s.args is not None:
|
||
args_s: ast.Arguments* = ast.Arguments*(fd_s.args)
|
||
if args_s.args is not None:
|
||
args_list_s: list[ast.AST*]* = args_s.args
|
||
an_s: sizet = len(args_list_s)
|
||
ai_s: sizet
|
||
for ai_s in range(an_s):
|
||
arg_s: ast.AST* = args_list_s.get(ai_s)
|
||
if arg_s is not None:
|
||
ag_s: ast.Arg* = ast.Arg*(arg_s)
|
||
if ag_s.annotation is not None:
|
||
self._check_container_type_node(ag_s.annotation, need_list_box, need_dict_box)
|
||
# `[...]`/`{}` 字面量不触发 _list/_dict 导入:字面量广泛用于编译期常量列表
|
||
# (c.Asm 的 op/inp/out CLOBBER 参数、数组数据初始化),并非 list 容器使用。
|
||
# list/dict 容器的真实使用由类型位置检测覆盖:`x: list` / `list[...]` 注解、
|
||
# `list(...)`/`dict(...)` 构造(_check_container_type_node 的 AnnAssign.annotation /
|
||
# Call.func / Subscript.value 分支)。无注解 `x = [...]` 若意图 list,会在
|
||
# translate_list_literal 阶段 fail-fast 提示 _list 未注册(需显式注解)。
|
||
# 递归语句块子节点
|
||
if node.children is not None:
|
||
ch_s: list[ast.AST*]* = node.children
|
||
n_s: sizet = len(ch_s)
|
||
for ci_s in range(n_s):
|
||
self._scan_container_usage(ch_s.get(ci_s), need_list_box, need_dict_box)
|
||
|
||
def _check_container_type_node(self, node: ast.AST*,
|
||
need_list_box: t.CPtr,
|
||
need_dict_box: t.CPtr):
|
||
"""检测类型位置节点是否为 list/dict(支持 Name / Subscript / BinOp 递归)"""
|
||
if node is None:
|
||
return
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.Name:
|
||
nm_s: ast.Name* = ast.Name*(node)
|
||
if nm_s.id is not None:
|
||
if string.strcmp(nm_s.id, "dict") == 0:
|
||
need_dict_box[0] = 1
|
||
elif string.strcmp(nm_s.id, "list") == 0:
|
||
need_list_box[0] = 1
|
||
elif k == ast.ASTKind.Subscript:
|
||
sub_s: ast.Subscript* = ast.Subscript*(node)
|
||
if sub_s.value is not None:
|
||
self._check_container_type_node(sub_s.value, need_list_box, need_dict_box)
|
||
# rawptr[list[int]] / list[AST] 等:slice 里可能含 list,需下钻
|
||
if sub_s.slice is not None:
|
||
self._check_container_type_node(sub_s.slice, need_list_box, need_dict_box)
|
||
elif k == ast.ASTKind.BinOp:
|
||
bop_s: ast.BinOp* = ast.BinOp*(node)
|
||
self._check_container_type_node(ast.binop_get_left(bop_s), need_list_box, need_dict_box)
|
||
self._check_container_type_node(ast.binop_get_right(bop_s), need_list_box, need_dict_box)
|
||
|
||
def _annotation_is_container(self, ann: ast.AST*) -> int:
|
||
"""注解是否为 list/dict 容器(Name 裸名或 Subscript list[...]/dict[...])
|
||
|
||
数组初始化(t.CArray[...] / 裸数组注解)返回 0,避免 _scan_container_usage
|
||
把数组字面量误判为 list 容器使用(FIX 2026-08-30)。
|
||
"""
|
||
while ann is not None:
|
||
ak: int = ann.kind()
|
||
if ak == ast.ASTKind.Name:
|
||
nm_c: ast.Name* = ast.Name*(ann)
|
||
if nm_c.id is not None:
|
||
if string.strcmp(nm_c.id, "list") == 0:
|
||
return 1
|
||
if string.strcmp(nm_c.id, "dict") == 0:
|
||
return 1
|
||
return 0
|
||
elif ak == ast.ASTKind.Subscript:
|
||
sub_c: ast.Subscript* = ast.Subscript*(ann)
|
||
ann = sub_c.value
|
||
else:
|
||
return 0
|
||
return 0
|
||
|
||
|
||
# ============================================================
|
||
# IR 输出
|
||
# ============================================================
|
||
def dump_ir(self, buf: bytes, size: sizet, mode: int):
|
||
"""将 LLVM IR 输出到缓冲区
|
||
|
||
mode: 0=完整, 1=stub(仅声明), 2=text(仅代码)
|
||
"""
|
||
if self.Module is None or buf is None:
|
||
return
|
||
if _mbuddy is None:
|
||
return
|
||
buf[0] = '\0'
|
||
llvmlite.LLVMModulePrint(buf, size, self.Module, _mbuddy, mode)
|
||
|
||
|
||
# ============================================================
|
||
# --traceback: startup Install() ctor injection
|
||
#
|
||
# Lives here (not in BuildPipeline) because this module already imports
|
||
# llvmlite. Calling llvmlite.* from a module without that import mangles the
|
||
# calls with the package (__init__) SHA1, which no object defines, instead of
|
||
# the defining submodule's SHA1 (link-time undefined symbol). BuildPipeline
|
||
# only decides whether to trigger the injection.
|
||
#
|
||
# Injects into the traceback module's IR:
|
||
# define void @__traceback_install_ctor() { entry: call @Install(); ret void }
|
||
# plus an appending-linkage @llvm.global_ctors so the CRT runs Install() once at
|
||
# process start (mirrors TPC BaseGen._RegisterTracebackInstallViaCtor).
|
||
# fail-fast: a pre-existing @llvm.global_ctors, or a missing Install symbol,
|
||
# aborts the build (silent degradation would leave the product without a map).
|
||
# ============================================================
|
||
|
||
# _tb_module_has_global_ctors - does the module already define @llvm.global_ctors
|
||
def _tb_module_has_global_ctors(mod: llvmlite.LLVMModule*) -> int:
|
||
if mod is None:
|
||
return 0
|
||
g: llvmlite.GlobalVariable* = mod.GlobalHead
|
||
steps: sizet = 0
|
||
while g is not None:
|
||
steps += 1
|
||
if steps > 100000:
|
||
break
|
||
if g.Name is not None and string.strcmp(g.Name, "llvm.global_ctors") == 0:
|
||
return 1
|
||
g = g.Next
|
||
return 0
|
||
|
||
|
||
# _tb_find_install_function - locate this module's own Install()
|
||
#
|
||
# Accepts "<16hex>.Install" (the usual SHA1-mangled form) or the bare name.
|
||
def _tb_find_install_function(mod: llvmlite.LLVMModule*) -> llvmlite.Function*:
|
||
if mod is None:
|
||
return None
|
||
cur: llvmlite.Function* = mod.FuncHead
|
||
steps: sizet = 0
|
||
while cur is not None:
|
||
steps += 1
|
||
if steps > 100000:
|
||
return None
|
||
nm: str = llvmlite.function_get_name(cur)
|
||
if nm is not None:
|
||
if string.strcmp(nm, "Install") == 0:
|
||
return cur
|
||
nl: sizet = llvmlite.function_get_name_len(cur)
|
||
if nl == 24 and string.strcmp(nm + 16, ".Install") == 0:
|
||
return cur
|
||
cur = llvmlite.function_get_next(cur)
|
||
return None
|
||
|
||
|
||
# InjectTracebackInstallCtor - inject startup Install() ctor into the module
|
||
#
|
||
# NOTE: FunctionPrint has no linkage field, so the ctor is emitted with default
|
||
# (external) linkage instead of TPC's 'internal'; only traceback.vp defines it,
|
||
# so there is no symbol clash.
|
||
def InjectTracebackInstallCtor(tr: rawptr[Translator]) -> int:
|
||
if tr is None or tr.Module is None:
|
||
return 0
|
||
if tr._declare_only != 0:
|
||
return 0
|
||
pool: memhub.MemBuddy* = tr.Pool
|
||
if pool is None:
|
||
VLogger.error("--traceback: 内存池未初始化,无法注入 Install 构造器", "TRACEBACK")
|
||
return 1
|
||
mod: llvmlite.LLVMModule* = tr.Module
|
||
if _tb_module_has_global_ctors(mod) != 0:
|
||
VLogger.error("--traceback: 模块内已存在 @llvm.global_ctors,无法注入 traceback 启动期构造器(不静默降级)", "TRACEBACK")
|
||
return 1
|
||
install_fn: llvmlite.Function* = _tb_find_install_function(mod)
|
||
if install_fn is None:
|
||
VLogger.error("--traceback: 在 traceback 模块内找不到 Install() 函数,无法注入启动期构造器(不静默降级)", "TRACEBACK")
|
||
return 1
|
||
|
||
# 1) ctor: entry { call <ret> @Install(); ret void }
|
||
void_ty: llvmlite.LLVMType* = llvmlite.Void(pool)
|
||
ctor: llvmlite.Function* = llvmlite.new_function(pool, "__traceback_install_ctor", void_ty)
|
||
if ctor is None:
|
||
VLogger.error("--traceback: 构造器函数分配失败", "TRACEBACK")
|
||
return 1
|
||
blk: llvmlite.BasicBlock* = llvmlite.new_basic_block(pool, "entry")
|
||
if blk is None:
|
||
VLogger.error("--traceback: 构造器基本块分配失败", "TRACEBACK")
|
||
return 1
|
||
llvmlite.function_add_block(ctor, blk)
|
||
llvmlite.module_add_function(mod, ctor)
|
||
builder: llvmlite.IRBuilder* = llvmlite.new_builder(pool, ctor)
|
||
if builder is None:
|
||
VLogger.error("--traceback: 构造器 IRBuilder 分配失败", "TRACEBACK")
|
||
return 1
|
||
llvmlite.position_at_end(builder, blk)
|
||
iname: str = llvmlite.function_get_name(install_fn)
|
||
install_ret: llvmlite.LLVMType* = llvmlite.function_get_ret_ty(install_fn)
|
||
llvmlite.build_call(builder, iname, None, 0, install_ret, 0)
|
||
llvmlite.build_ret_void(builder)
|
||
|
||
# 2) @llvm.global_ctors = appending global [1 x {i32, void ()*, i8*}] [ ... ]
|
||
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||
i8p_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
|
||
fnv_ty: llvmlite.LLVMType* = llvmlite.Func(pool, void_ty, None, 0)
|
||
fnp_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, fnv_ty)
|
||
f1: llvmlite.ParamNode* = llvmlite.new_param_node(pool, i32_ty)
|
||
f2: llvmlite.ParamNode* = llvmlite.new_param_node(pool, fnp_ty)
|
||
f3: llvmlite.ParamNode* = llvmlite.new_param_node(pool, i8p_ty)
|
||
if f1 is None or f2 is None or f3 is None:
|
||
VLogger.error("--traceback: global_ctors 结构体字段分配失败", "TRACEBACK")
|
||
return 1
|
||
llvmlite.paramnode_set_next(f1, f2)
|
||
llvmlite.paramnode_set_next(f2, f3)
|
||
elem_ty: llvmlite.LLVMType* = llvmlite.Struct(pool, f1, 3, None)
|
||
arr_ty: llvmlite.LLVMType* = llvmlite.Array(pool, elem_ty, 1)
|
||
if elem_ty is None or arr_ty is None:
|
||
VLogger.error("--traceback: global_ctors 类型构造失败", "TRACEBACK")
|
||
return 1
|
||
gv: llvmlite.GlobalVariable* = llvmlite.new_global_variable(pool, "llvm.global_ctors", arr_ty)
|
||
if gv is None:
|
||
VLogger.error("--traceback: @llvm.global_ctors 全局变量分配失败", "TRACEBACK")
|
||
return 1
|
||
llvmlite.global_set_linkage(gv, "appending")
|
||
gv.Initializer = "[{ i32, void ()*, i8* } { i32 65535, void ()* @__traceback_install_ctor, i8* null }]"
|
||
llvmlite.module_add_global(mod, gv)
|
||
VLogger.info("--traceback: 已注入启动期 Install() 构造器(@llvm.global_ctors)", "TRACEBACK")
|
||
return 0
|
||
|
||
|
||
# ============================================================
|
||
# Mixin - Handler 非多态基类(自 HandlesBase 迁入)
|
||
#
|
||
# 持有 Translator 回指针。ExprCallHandle 等跨模块 handler 类经
|
||
# `class X(Translator.Mixin)` 继承(TPV 支持模块限定基类继承)。
|
||
# ============================================================
|
||
novirtual class Mixin:
|
||
"""所有 Handle 的非多态基类:持有 Translator 回指针 + 共享委托方法"""
|
||
Trans: Translator | t.CPtr
|
||
|
||
def InitMixin(self, trans: Translator | t.CPtr) -> int:
|
||
"""初始化 Mixin 字段(子类 __init__ 中调用)"""
|
||
self.Trans = trans
|
||
return 0
|
||
|
||
|
||
# ============================================================
|
||
|
||
# 全局 mbuddy 指针
|
||
_mbuddy: memhub.MemBuddy*
|
||
|