Files
TransPyC/lib/_bootstrap.py
T
TermiNexus 6fc9e19e24 feat(vast): 新增自研 Viper/Python 语法解析器取代标准库 ast
TPC 侧取缔对 Python 标准库 ast 模块的依赖,改用 lib/vast 包:
- Nodes: 与 CPython 3.12 ast 完全同构的 131 个节点类(含抽象基类继承)
- Tokenizer: 词法分析(缩进/字符串/f-string/数字/运算符/软关键字)
- ExprParser: 表达式递归下降解析(优先级/lambda/推导式/f-string/切片)
- Parser: 语句解析(def/class/if/for/try/with/match/import/注解)
- Utils/Unparser: walk/dump/unparse/copy_location/literal_eval 等辅助
- 软关键字 fn/fun/func/function 并入解析器, 废除 ExpandSoftKeywords 预处理
- lib/_bootstrap 将 lib 目录加入 sys.path, import vast as ast 零修改替换
- 52 个文件 import ast 替换为 import vast as ast; 94 文件差分测试 0 失败
2026-08-17 09:36:38 +08:00

142 lines
5.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""集中化 sys.path 引导模块
在首次导入时一次性设置好编译器运行所需的 sys.path:
- 项目根目录:让 ``import TransPyC``、``from StubGen import``、动态 importlib 能解析
- lib/includes:让用户注解模块中的 ``import t`` / ``import c`` 能解析
入口点(TransPyC.py / Projectrans.py)应在最开头 ``import lib._bootstrap``。
lib 内部模块也可 ``import lib._bootstrap`` 作为安全网,重复导入是无副作用的 no-op。
"""
from __future__ import annotations
import os
import sys
_BOOTSTRAPPED: bool = False
def _bootstrap() -> None:
global _BOOTSTRAPPED
if _BOOTSTRAPPED:
return
_BOOTSTRAPPED = True
# lib/_bootstrap.py 所在目录
_LibDir: str = os.path.dirname(os.path.abspath(__file__))
# 项目根目录 = lib 的父目录
_ProjectRoot: str = os.path.dirname(_LibDir)
# lib/includes 目录(编译器内部类型系统 t.py / c.py)
_IncludesDir: str = os.path.join(_LibDir, 'includes')
if _ProjectRoot not in sys.path:
sys.path.insert(0, _ProjectRoot)
if _LibDir not in sys.path:
# lib 目录入 path:使 vast 包(lib/vast/)可直接 import vast
sys.path.append(_LibDir)
if _IncludesDir not in sys.path:
sys.path.append(_IncludesDir)
# ============================================================
# LLVM IR 兼容性补丁:llvmlite 不允许 void* 指针类型
#
# LLVM IR 规范中不存在 void*,C 的 void* 在 IR 层对应的是 i8*。
# 但编译链(REnum / Python 推理)可能错误地构造 ir.PointerType(ir.VoidType()),
# 这会导致 llc 报 "pointers to void are invalid - use i8* instead" 直接失败。
#
# 这里在入口对 ir.PointerType.__new__ 和 __init__ 做 monkey patch:
# 所有传入 VoidType 的 pointee(无论多少级 Ptr 嵌套)都自动替换为 i8。
# 这样 _nonlocal_types / 闭包环境 / 任何代码路径产生的 Ptr(Void) 都会被静默修正。
# ============================================================
try:
import llvmlite.ir as _llvmlite_ir
except Exception: # noqa: BLE001
_llvmlite_ir = None # type: ignore[assignment]
if _llvmlite_ir is not None:
_I8 = _llvmlite_ir.IntType(8)
def _IsBadPointee(pointee) -> bool:
"""只在明确传入了 VoidType 或 Ptr(...Void...) 这类坏 pointee 时返回 True;
None 由 llvmlite 内部 super 调用使用,不能替换!"""
if pointee is None:
return False
cur = pointee
while isinstance(cur, _llvmlite_ir.PointerType):
if isinstance(getattr(cur, 'pointee', None), _llvmlite_ir.VoidType):
return True
cur = getattr(cur, 'pointee', None)
if isinstance(pointee, _llvmlite_ir.VoidType):
return True
return False
# llvmlite 内部:PointerType(pointee=Int8) 实际返回的是内部类 _TypedPointerType 实例,
# 它的 __init__ 会 super 调 PointerType.__init__(pointee=None, addrspace),
# 因此我们只在明确看到 VoidType 传入(pointee is not None)时才做替换。
def _PatchPointerInitAndNew(cls) -> None:
try:
orig_new = cls.__new__
orig_init = cls.__init__
except Exception: # noqa: BLE001
return
if getattr(orig_init, '__void_patch_applied__', False):
return
def _patched_new(klass, pointee=None, addrspace=None, *args, **kwargs):
if _IsBadPointee(pointee):
return orig_new(klass, _I8, addrspace, *args, **kwargs)
return orig_new(klass, pointee, addrspace, *args, **kwargs)
def _patched_init(self_self, pointee=None, addrspace=None, *args, **kwargs):
if _IsBadPointee(pointee):
return orig_init(self_self, _I8, addrspace, *args, **kwargs)
return orig_init(self_self, pointee, addrspace, *args, **kwargs)
_patched_init.__void_patch_applied__ = True # type: ignore[attr-defined]
try:
cls.__new__ = _patched_new # type: ignore[method-assign]
cls.__init__ = _patched_init # type: ignore[method-assign]
except Exception: # noqa: BLE001
pass
import inspect as _inspect
# 收集所有继承自 PointerType 的类(含 _TypedPointerType)
_all_ir_classes: list = [
obj for _name, obj in vars(_llvmlite_ir).items()
if _inspect.isclass(obj)
]
for _cls in _all_ir_classes:
if issubclass(_cls, _llvmlite_ir.PointerType) or _cls is _llvmlite_ir.PointerType:
_PatchPointerInitAndNew(_cls)
# 同步 patch as_pointer() 的结果(它走的是 PointerType 构造器,但保险起见)
_as_pointer_patched = set()
def _PatchAsPointer(holder_cls) -> None:
if not hasattr(holder_cls, 'as_pointer') or id(holder_cls.as_pointer) in _as_pointer_patched:
return
_orig = holder_cls.as_pointer
def _PatchedAsPointer(self_self, *aa, **kk):
res = _orig(self_self, *aa, **kk)
rcur = res
while isinstance(rcur, _llvmlite_ir.PointerType):
if isinstance(getattr(rcur, 'pointee', None), _llvmlite_ir.VoidType):
return _I8.as_pointer()
rcur = getattr(rcur, 'pointee', None)
return res
try:
holder_cls.as_pointer = _PatchedAsPointer # type: ignore[attr-defined]
_as_pointer_patched.add(id(_orig))
except Exception: # noqa: BLE001
pass
for _obj in _all_ir_classes:
if hasattr(_obj, 'as_pointer') and callable(getattr(_obj, 'as_pointer', None)):
_PatchAsPointer(_obj)
_bootstrap()