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 失败
142 lines
5.9 KiB
Python
142 lines
5.9 KiB
Python
"""集中化 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()
|