取消了 i8* == i8* 实际使用 strcmp 的规则,修复了诸多 Bug
This commit is contained in:
1 parent
d227bee139
commit
bfb55d68f4
18 files changed
+397
-254
No files matched your search
@@ -7,9 +7,9 @@ import viperlib
|
||||
|
||||
|
||||
# ============================================================
|
||||
# StubGen.Converter - pyi 存根文件生成器
|
||||
# StubGen.Converter - vpi 存根文件生成器
|
||||
#
|
||||
# 从 AST 直接生成 .pyi 存根文件,不依赖 CPython 的 PythonToStubConverter。
|
||||
# 从 AST 直接生成 .vpi 存根文件,不依赖 CPython 的 PythonToStubConverter。
|
||||
# 遍历 Module 节点的 children,提取函数签名、类定义、变量声明、
|
||||
# import 语句,生成 Python 类型存根文件。
|
||||
#
|
||||
@@ -20,7 +20,7 @@ import viperlib
|
||||
# ============================================================
|
||||
# _eval_binop_int / _eval_binop_valid - 递归计算 BinOp 常量值
|
||||
#
|
||||
# 用于 .pyi 存根文件生成时计算 BinOp 表达式(如 A | B, A + B)的整数值。
|
||||
# 用于 .vpi 存根文件生成时计算 BinOp 表达式(如 A | B, A + B)的整数值。
|
||||
# 支持 BitOr/BitAnd/Add/Sub 以及嵌套的 Name(引用已注册的 CDefine 常量)。
|
||||
# ============================================================
|
||||
def _eval_binop_valid(node: ast.AST | t.CPtr) -> int:
|
||||
@@ -105,7 +105,7 @@ _g_pyi_cdefine_found: int = 0
|
||||
|
||||
|
||||
def _lookup_cdefine_for_pyi(name: str) -> int:
|
||||
"""从本地 CDefine 表查找常量值(用于 .pyi 生成时的 BinOp 计算)"""
|
||||
"""从本地 CDefine 表查找常量值(用于 .vpi 生成时的 BinOp 计算)"""
|
||||
import lib.core.Handles.HandlesType as HandlesType
|
||||
val: int = HandlesType.lookup_cdefine_constant(name)
|
||||
if HandlesType.is_cdefine_found() != 0:
|
||||
@@ -472,7 +472,7 @@ def _PyiClass(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _GeneratePyiFromAst - 从 AST 生成 .pyi 存根文件
|
||||
# _GeneratePyiFromAst - 从 AST 生成 .vpi 存根文件
|
||||
#
|
||||
# 遍历 AST Module 节点,提取函数签名、类定义、变量声明、import 语句,
|
||||
# 生成 Python 类型存根文件内容到 buf。
|
||||
@@ -490,7 +490,7 @@ def _PyiClass(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
||||
def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
|
||||
rel_path: str, buf: bytes,
|
||||
buf_size: t.CSizeT) -> t.CSizeT:
|
||||
"""从 AST 生成 .pyi 存根文件内容到 buf"""
|
||||
"""从 AST 生成 .vpi 存根文件内容到 buf"""
|
||||
if tree is None or buf is None or buf_size == 0:
|
||||
return 0
|
||||
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# StubGen 包入口
|
||||
#
|
||||
# 子模块通过绝对导入使用(import lib.StubGen.Converter as Converter),
|
||||
# 此 __init__.py 不做 re-export,避免引入未使用的依赖。
|
||||
# 此 __init__.vp 不做 re-export,避免引入未使用的依赖。
|
||||
# ============================================================
|
||||
+1
-1
@@ -8,7 +8,7 @@ import lib.core.VLogger as VLogger
|
||||
# lib 包入口 - 声明全局 _mbuddy 内存池指针
|
||||
# ============================================================
|
||||
|
||||
# 全局 mbuddy 内存池指针(由 App/main.py 初始化后注入)
|
||||
# 全局 mbuddy 内存池指针(由 App/main.vp 初始化后注入)
|
||||
# 注意: 使用 MemBuddy 类型而非 MemManager,避免虚函数分派不工作时调用父类 alloc 返回 None
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
|
||||
|
||||
@@ -97,8 +97,11 @@ def extract_cdefine_int_value(val_node: ast.AST | t.CPtr) -> int:
|
||||
# Case 4: Call — 如 t.CUnsignedLong(-11)
|
||||
if k == ast.ASTKind.Call:
|
||||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(val_node)
|
||||
if cl.args is not None and cl.args.__len__() > 0:
|
||||
first_arg: ast.AST | t.CPtr = cl.args.get(0)
|
||||
# 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(),
|
||||
# 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错
|
||||
cl_args_list: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||||
if cl_args_list is not None and cl_args_list.__len__() > 0:
|
||||
first_arg: ast.AST | t.CPtr = cl_args_list.get(0)
|
||||
arg_val: int = extract_cdefine_int_value(first_arg)
|
||||
return arg_val
|
||||
return 0
|
||||
|
||||
@@ -242,7 +242,7 @@ class AugAssignHandle(HandlesBase.Mixin):
|
||||
# ============================================================
|
||||
# _apply_aug_op - 应用增强赋值的二元运算
|
||||
#
|
||||
# 支持指针算术: ptr += int / ptr -= int
|
||||
# 支持浮点运算、指针算术: ptr += int / ptr -= int
|
||||
# 整数运算自动类型提升
|
||||
# ============================================================
|
||||
def _apply_aug_op(pool: memhub.MemBuddy | t.CPtr,
|
||||
@@ -250,9 +250,36 @@ def _apply_aug_op(pool: memhub.MemBuddy | t.CPtr,
|
||||
op: int,
|
||||
lhs: llvmlite.Value | t.CPtr,
|
||||
rhs: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""应用增强赋值的二元运算(指针算术 + 整数运算)"""
|
||||
"""应用增强赋值的二元运算(浮点 + 指针算术 + 整数运算)"""
|
||||
lhs_bits: int = HandlesExpr.get_llvm_type_bits(lhs.Ty)
|
||||
rhs_bits: int = HandlesExpr.get_llvm_type_bits(rhs.Ty)
|
||||
lhs_fbits: int = HandlesExpr.get_llvm_float_bits(lhs.Ty)
|
||||
rhs_fbits: int = HandlesExpr.get_llvm_float_bits(rhs.Ty)
|
||||
|
||||
# 浮点运算: 任一操作数为浮点时,使用浮点指令(必须在指针算术之前检查,
|
||||
# 因为 float 的 int bits 为 0,会被误认为指针)
|
||||
if lhs_fbits != 0 or rhs_fbits != 0:
|
||||
# 确定目标浮点类型(使用较大的位宽)
|
||||
target_fbits: int = lhs_fbits
|
||||
if rhs_fbits > target_fbits:
|
||||
target_fbits = rhs_fbits
|
||||
target_float_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
|
||||
if target_fbits == 32:
|
||||
target_float_ty = llvmlite.Float(pool)
|
||||
# 将两个操作数转换为目标浮点类型(int→float via si2fp, float→float via fpext/fptrunc)
|
||||
lhs = HandlesExpr.coerce_to_type(builder, lhs, target_float_ty)
|
||||
rhs = HandlesExpr.coerce_to_type(builder, rhs, target_float_ty)
|
||||
if op == ast.OpKind.Add:
|
||||
return llvmlite.build_fadd(builder, lhs, rhs)
|
||||
if op == ast.OpKind.Sub:
|
||||
return llvmlite.build_fsub(builder, lhs, rhs)
|
||||
if op == ast.OpKind.Mult:
|
||||
return llvmlite.build_fmul(builder, lhs, rhs)
|
||||
if op == ast.OpKind.Div:
|
||||
return llvmlite.build_fdiv(builder, lhs, rhs)
|
||||
if op == ast.OpKind.Mod:
|
||||
return llvmlite.build_frem(builder, lhs, rhs)
|
||||
return None
|
||||
|
||||
# 指针算术: ptr += int / ptr -= int
|
||||
if lhs_bits == 0 and rhs_bits != 0:
|
||||
|
||||
@@ -1842,9 +1842,8 @@ def _clone_annotation(pool: memhub.MemBuddy | t.CPtr,
|
||||
tpn: str = tp_names.get(i)
|
||||
if tpn is not None and string.strcmp(nm.id, tpn) == 0:
|
||||
ta: str = type_args.get(i)
|
||||
# 类型实参可能是复合类型(如 "AST|t.CPtr"),用 _parse_type_string_ptr 解析
|
||||
# 使用 _ptr 包装避免旧编译器对 ast.AST|t.CPtr 返回类型推断为 i32 的 bug
|
||||
parsed_node: ast.AST | t.CPtr = HandlesType._parse_type_string_ptr(pool, ta, nm.ctx)
|
||||
# 类型实参可能是复合类型(如 "AST|t.CPtr"),用 _parse_type_string 解析
|
||||
parsed_node: ast.AST | t.CPtr = HandlesType._parse_type_string(pool, ta, nm.ctx)
|
||||
return parsed_node
|
||||
return ast.Name(pool, nm.id, nm.ctx)
|
||||
return None
|
||||
|
||||
@@ -146,6 +146,37 @@ def is_ptr_type(ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# get_ptr_level - 计算指针层级
|
||||
#
|
||||
# 返回值:
|
||||
# 0 = 非指针(数值/结构体等)
|
||||
# 1 = 一级指针(如 i8*, Struct*)
|
||||
# 2 = 二级指针(如 i8**, Struct**)
|
||||
# 3+ = 更高级指针
|
||||
#
|
||||
# 用于比较运算的类型安全检查:
|
||||
# - 数值(0) vs 数值(0) → 允许
|
||||
# - 一级指针(1) vs 一级指针(1) → 允许
|
||||
# - 数值(0) vs 指针(1+) → 禁止(fast-fail)
|
||||
# - 不同级指针(1 vs 2) → 禁止(fast-fail)
|
||||
# ============================================================
|
||||
def get_ptr_level(ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
"""计算指针层级,0=非指针, 1=一级指针, 2=二级指针..."""
|
||||
if ty is None:
|
||||
return 0
|
||||
level: int = 0
|
||||
cur: llvmlite.LLVMType | t.CPtr = ty
|
||||
while cur is not None:
|
||||
match cur:
|
||||
case llvmlite.LLVMType.Ptr(pointee):
|
||||
level += 1
|
||||
cur = pointee
|
||||
case _:
|
||||
break
|
||||
return level
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 检查类型是否为 Array(独立函数,避免嵌套 match 的编译器 BUG)
|
||||
# ============================================================
|
||||
@@ -252,6 +283,11 @@ def coerce_to_type(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
# 浮点转换
|
||||
val_fbits: int = get_llvm_float_bits(val.Ty)
|
||||
target_fbits: int = get_llvm_float_bits(target_ty)
|
||||
# float ↔ ptr: 禁止(无意义的转换,fast-fail 防止误走入 build_load 路径)
|
||||
if (val_fbits != 0 and is_ptr_type(target_ty) != 0) or \
|
||||
(is_ptr_type(val.Ty) != 0 and target_fbits != 0):
|
||||
VLogger.error("coerce_to_type: 不支持的类型转换 float↔ptr", "Coerce")
|
||||
return val
|
||||
if val_fbits != 0 and target_fbits != 0:
|
||||
if val_fbits == target_fbits:
|
||||
return val
|
||||
@@ -316,6 +352,8 @@ def create_global_string(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
# 去掉 private 链接,和函数一致:stub 中 declare,text 中 define
|
||||
llvmlite.global_set_unnamed_addr(gv, 1)
|
||||
llvmlite.global_set_constant(gv, 1)
|
||||
# LLVM 22+ 不允许 external linkage 全局变量带初始值,设为 internal
|
||||
gv.Linkage = "internal"
|
||||
gv.Initializer = escaped
|
||||
|
||||
arr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, arr_ty)
|
||||
@@ -825,7 +863,7 @@ def translate_compare(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
# 语义依据: Python 中 == None / != None 默认走身份比较,不调用 __eq__/__ne__
|
||||
lhs_node: ast.AST | t.CPtr = cmp.left
|
||||
cmp_with_none: int = 0
|
||||
if op == ast.OpKind.Eq or op == ast.OpKind.Ne:
|
||||
if op == ast.OpKind.Eq or op == ast.OpKind.Ne or op == ast.OpKind.Is or op == ast.OpKind.IsNot:
|
||||
if rhs_node is not None and rhs_node.kind() == ast.ASTKind.Constant:
|
||||
rhs_cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(rhs_node)
|
||||
if rhs_cn is not None and rhs_cn.const_kind == ast.CONST_NONE:
|
||||
@@ -884,18 +922,42 @@ def translate_compare(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
# `x is not y` → 指针/值不等比较
|
||||
predicate = llvmlite.ICMP_NE
|
||||
|
||||
# 隐式类型转换:当一侧是指针(i8*),另一侧是整数时,
|
||||
# 从指针加载第一个字节,使两侧类型一致
|
||||
lhs_is_ptr: int = is_ptr_type(lhs.Ty)
|
||||
rhs_is_ptr: int = is_ptr_type(rhs.Ty)
|
||||
if lhs_is_ptr != 0 and rhs_is_ptr == 0:
|
||||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
lhs = llvmlite.build_load(builder, i8_ty, lhs)
|
||||
elif rhs_is_ptr != 0 and lhs_is_ptr == 0:
|
||||
i8_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
rhs = llvmlite.build_load(builder, i8_ty2, rhs)
|
||||
# === 类型安全检查(BUG2 修复)===
|
||||
# 规则:
|
||||
# - 数值(0) vs 数值(0) → 允许(无关类型,按位宽 sext 对齐)
|
||||
# - 一级指针(1) vs 一级指针(1) → 允许(无关 pointee 类型,地址比较)
|
||||
# - 数值(0) vs 指针(1+) → 禁止(fast-fail,除 None 比较外)
|
||||
# - 不同级指针(1 vs 2 等) → 禁止(fast-fail)
|
||||
#
|
||||
# None 比较跳过此检查(None 被翻译为 null 指针或 0,与任意指针/数值比较合法)
|
||||
if cmp_with_none == 0:
|
||||
lhs_ptr_level: int = get_ptr_level(lhs.Ty)
|
||||
rhs_ptr_level: int = get_ptr_level(rhs.Ty)
|
||||
if lhs_ptr_level != rhs_ptr_level:
|
||||
# 类型不匹配:数值vs指针 或 不同级指针
|
||||
VLogger.error(
|
||||
"比较类型不匹配: lhs 指针层级=%d, rhs 指针层级=%d (禁止数值与指针、不同级指针比较)" % (lhs_ptr_level, rhs_ptr_level),
|
||||
"Compare")
|
||||
return None
|
||||
else:
|
||||
# None 比较: None 被翻译为 i8* null(一级指针)
|
||||
# 如果 lhs 是指针,将 rhs (i8* null) bitcast 为 lhs 的指针类型
|
||||
# 如果 lhs 是数值,将 rhs 转为数值 0(走正常整数比较)
|
||||
lhs_ptr_level_none: int = get_ptr_level(lhs.Ty)
|
||||
rhs_ptr_level_none: int = get_ptr_level(rhs.Ty)
|
||||
if lhs_ptr_level_none != 0 and rhs_ptr_level_none != 0:
|
||||
# 两边都是指针,类型可能不同(如 lhs=Struct*, rhs=i8* null)
|
||||
# 由下方 bitcast 对齐处理,此处不处理
|
||||
pass
|
||||
elif lhs_ptr_level_none != 0 and rhs_ptr_level_none == 0:
|
||||
# lhs 是指针, rhs 是数值 → 将 rhs 转为同层级 null 指针
|
||||
rhs = llvmlite.ConstNull(pool, lhs.Ty, None)
|
||||
elif rhs_ptr_level_none != 0 and lhs_ptr_level_none == 0:
|
||||
# lhs 是数值, rhs 是 i8* null → 将 rhs 转为数值 0(保持 lhs 不变)
|
||||
rhs = llvmlite.const_int32(pool, 0)
|
||||
|
||||
# 类型对齐:icmp 要求两边类型相同,将较窄的整数 sext 到较宽的类型
|
||||
# 类型对齐:icmp 要求两边类型相同
|
||||
# 仅对数值类型做 sext 对齐(指针类型无需对齐,LLVM 允许同层级指针直接 icmp)
|
||||
lhs_bits: int = get_llvm_type_bits(lhs.Ty)
|
||||
rhs_bits: int = get_llvm_type_bits(rhs.Ty)
|
||||
if lhs_bits != 0 and rhs_bits != 0 and lhs_bits != rhs_bits:
|
||||
@@ -904,6 +966,52 @@ def translate_compare(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
else:
|
||||
rhs = llvmlite.build_sext(builder, rhs, lhs.Ty)
|
||||
|
||||
# 指针类型对齐:同层级但不同 pointee 类型的指针需要 bitcast 统一类型
|
||||
# 例如 i8* vs Struct* → 将 rhs bitcast 为 lhs 的类型
|
||||
if lhs_bits == 0 and rhs_bits == 0:
|
||||
lhs_is_ptr_now: int = is_ptr_type(lhs.Ty)
|
||||
rhs_is_ptr_now: int = is_ptr_type(rhs.Ty)
|
||||
if lhs_is_ptr_now != 0 and rhs_is_ptr_now != 0:
|
||||
# 两边都是指针,用 TypePrint 比较类型字符串
|
||||
lhs_ty_buf: t.CChar | t.CPtr = pool.alloc(128)
|
||||
rhs_ty_buf: t.CChar | t.CPtr = pool.alloc(128)
|
||||
if lhs_ty_buf is not None and rhs_ty_buf is not None:
|
||||
llvmlite.TypePrint(lhs_ty_buf, 128, lhs.Ty, pool)
|
||||
llvmlite.TypePrint(rhs_ty_buf, 128, rhs.Ty, pool)
|
||||
if string.strcmp(lhs_ty_buf, rhs_ty_buf) != 0:
|
||||
rhs = llvmlite.build_bitcast(builder, rhs, lhs.Ty)
|
||||
|
||||
# 浮点比较:任一操作数为浮点类型时使用 fcmp 而非 icmp
|
||||
lhs_fbits: int = get_llvm_float_bits(lhs.Ty)
|
||||
rhs_fbits: int = get_llvm_float_bits(rhs.Ty)
|
||||
if lhs_fbits != 0 or rhs_fbits != 0:
|
||||
# 浮点类型对齐(fpext/fptrunc)
|
||||
if lhs_fbits != 0 and rhs_fbits != 0 and lhs_fbits != rhs_fbits:
|
||||
if lhs_fbits < rhs_fbits:
|
||||
lhs = llvmlite.build_fpext(builder, lhs, rhs.Ty)
|
||||
else:
|
||||
rhs = llvmlite.build_fptrunc(builder, rhs, lhs.Ty)
|
||||
elif lhs_fbits != 0 and rhs_fbits == 0:
|
||||
# int → float
|
||||
rhs = llvmlite.build_si2fp(builder, rhs, lhs.Ty)
|
||||
elif rhs_fbits != 0 and lhs_fbits == 0:
|
||||
lhs = llvmlite.build_si2fp(builder, lhs, rhs.Ty)
|
||||
# 映射比较谓词到 fcmp
|
||||
fpredicate: int = llvmlite.FCMP_OEQ
|
||||
if op == ast.OpKind.Eq or op == ast.OpKind.Is:
|
||||
fpredicate = llvmlite.FCMP_OEQ
|
||||
elif op == ast.OpKind.Ne or op == ast.OpKind.IsNot:
|
||||
fpredicate = llvmlite.FCMP_ONE
|
||||
elif op == ast.OpKind.Lt:
|
||||
fpredicate = llvmlite.FCMP_OLT
|
||||
elif op == ast.OpKind.Le:
|
||||
fpredicate = llvmlite.FCMP_OLE
|
||||
elif op == ast.OpKind.Gt:
|
||||
fpredicate = llvmlite.FCMP_OGT
|
||||
elif op == ast.OpKind.Ge:
|
||||
fpredicate = llvmlite.FCMP_OGE
|
||||
return llvmlite.build_fcmp(builder, fpredicate, lhs, rhs)
|
||||
|
||||
return llvmlite.build_icmp(builder, predicate, lhs, rhs)
|
||||
|
||||
|
||||
@@ -1096,9 +1204,9 @@ def translate_boolop(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _build_source_path_from_sha1 - 通过 SHA1 从存储器构建源 .py 文件路径
|
||||
# _build_source_path_from_sha1 - 通过 SHA1 从存储器构建源 .vp/.py 文件路径
|
||||
#
|
||||
# .pyi 文件可能未生成(Phase1 未输出 pyi),此时回退读取源 .py 文件。
|
||||
# .vpi 文件可能未生成(Phase1 未输出 vpi),此时回退读取源 .py 文件。
|
||||
# 从 StubMerger 全局存储器查找 SHA1 对应的相对路径,
|
||||
# 根据 rel_path 前缀选择基础目录:
|
||||
# - rel_path 以 "lib/" 开头 → App 源文件,用 {Config.SourceDir}/{rel_path}
|
||||
@@ -1180,6 +1288,9 @@ def _lookup_cross_module_cdefine(pool: memhub.MemBuddy | t.CPtr,
|
||||
3. imported_modules 遍历(import X):当通过 import X 导入模块时,
|
||||
模块中定义的 CDefine 常量可通过此路径找到(如方法签名默认参数引用)
|
||||
"""
|
||||
# 入口处清零标志,确保所有早退路径(return -1)都返回"未找到"状态
|
||||
# 避免递归调用时前一次成功的标志残留导致误判
|
||||
HandlesType.set_cdefine_found(0)
|
||||
if name is None:
|
||||
return -1
|
||||
if from_imports is None:
|
||||
@@ -1273,7 +1384,7 @@ def _lookup_cross_module_cdefine(pool: memhub.MemBuddy | t.CPtr,
|
||||
if pyi_path is None:
|
||||
return -1
|
||||
|
||||
# 7. 读取 vpi 文件;若不存在或内容过短(空 stub)则回退读取源 .py 文件
|
||||
# 7. 读取 vpi 文件;若不存在或内容过短(空 stub)则回退读取源 .vp/.py 文件
|
||||
PYI_READ_BUF_SIZE: t.CSizeT = 65536
|
||||
pyi_buf: bytes = stdlib.malloc(PYI_READ_BUF_SIZE)
|
||||
if pyi_buf is None:
|
||||
@@ -1283,7 +1394,7 @@ def _lookup_cross_module_cdefine(pool: memhub.MemBuddy | t.CPtr,
|
||||
need_py_fallback: int = 0
|
||||
bytes_read: LONG = 0
|
||||
if pf.closed:
|
||||
# .vpi 文件不存在:回退读取源 .py 文件
|
||||
# .vpi 文件不存在:回退读取源 .vp/.py 文件
|
||||
need_py_fallback = 1
|
||||
else:
|
||||
bytes_read = pf.read_all(pyi_buf, PYI_READ_BUF_SIZE)
|
||||
@@ -1474,7 +1585,7 @@ def _lookup_cross_module_cdefine(pool: memhub.MemBuddy | t.CPtr,
|
||||
|
||||
# 9.5 如果当前模块文件中没找到,递归查找子模块
|
||||
# 处理 from .X import NAME 和 from .X import * 的情况
|
||||
# 例如 ast.__init__.py 中 from .base import CONST_INT, ...
|
||||
# 例如 ast.__init__.vp 中 from .base import CONST_INT, ...
|
||||
# 需要递归查找 ast.base 子模块中的 CONST_INT: t.CDefine = 1
|
||||
if result_found == 0:
|
||||
name_len_rc: t.CSizeT = string.strlen(name)
|
||||
@@ -1725,7 +1836,7 @@ def translate_name_value(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
if HandlesType.is_cdefine_found() != 0:
|
||||
return llvmlite.const_int32(pool, cdef_val)
|
||||
|
||||
# 本地表未找到:尝试跨模块 .pyi 查找(保证多模块查表存表一致)
|
||||
# 本地表未找到:尝试跨模块 .vpi 查找(保证多模块查表存表一致)
|
||||
# 仅对符合 CDefine 命名约定(ALL_CAPS)的名字触发跨模块查找,
|
||||
# 避免对普通变量名(mb/name/ptr/pool/self 等)误触发,造成严重性能损耗
|
||||
if _is_cdefine_name_pattern(nm_id) != 0:
|
||||
@@ -2478,7 +2589,7 @@ def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
trans.SymTab, nm_ma.id)
|
||||
if ma_is_var is None:
|
||||
# 先检查是否是 CDefine 编译期常量 (如 ast.CONST_INT / win32base.INVALID_HANDLE_VALUE)
|
||||
# 模块属性访问的 CDefine 常量需要跨模块查找源 .py / .pyi 文件
|
||||
# 模块属性访问的 CDefine 常量需要跨模块查找源 .vp / .vpi 文件
|
||||
cdef_ma_val: int = HandlesType.lookup_cdefine_constant(at.attr)
|
||||
cd_local: int = HandlesType.is_cdefine_found()
|
||||
if cd_local == 0:
|
||||
@@ -2601,7 +2712,7 @@ def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
return llvmlite.build_load(builder, load_ty_nested, gv_ref_nested)
|
||||
# 未找到全局: 尝试 CDefine 常量查找
|
||||
# 对于 w32.win32base.INVALID_HANDLE_VALUE 等嵌套模块属性访问,
|
||||
# 先从限定模块的 .pyi 文件中查找 CDefine 常量值并内联
|
||||
# 先从限定模块的 .vpi 文件中查找 CDefine 常量值并内联
|
||||
cdef_val_nested: int = HandlesType.lookup_cdefine_constant(at.attr)
|
||||
if HandlesType.is_cdefine_found() == 0:
|
||||
# 构建临时 from_imports "attr:module" 用于跨模块查找
|
||||
|
||||
@@ -384,113 +384,116 @@ def _infer_external_func_ret_ty(pool: memhub.MemBuddy | t.CPtr,
|
||||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
|
||||
# 返回 i8* 的函数(指针返回值,截断会导致错误)
|
||||
if bare_name == "strchr" or func_name == "strchr":
|
||||
if string.strcmp(bare_name, "strchr") == 0 or string.strcmp(func_name, "strchr") == 0:
|
||||
return i8_ptr_ty
|
||||
if bare_name == "strrchr" or func_name == "strrchr":
|
||||
if string.strcmp(bare_name, "strrchr") == 0 or string.strcmp(func_name, "strrchr") == 0:
|
||||
return i8_ptr_ty
|
||||
if bare_name == "strstr" or func_name == "strstr":
|
||||
if string.strcmp(bare_name, "strstr") == 0 or string.strcmp(func_name, "strstr") == 0:
|
||||
return i8_ptr_ty
|
||||
if bare_name == "strcpy" or func_name == "strcpy":
|
||||
if string.strcmp(bare_name, "strcpy") == 0 or string.strcmp(func_name, "strcpy") == 0:
|
||||
return i8_ptr_ty
|
||||
if bare_name == "strncpy" or func_name == "strncpy":
|
||||
if string.strcmp(bare_name, "strncpy") == 0 or string.strcmp(func_name, "strncpy") == 0:
|
||||
return i8_ptr_ty
|
||||
if bare_name == "memset" or func_name == "memset":
|
||||
if string.strcmp(bare_name, "memset") == 0 or string.strcmp(func_name, "memset") == 0:
|
||||
return i8_ptr_ty
|
||||
if bare_name == "memset32" or func_name == "memset32":
|
||||
if string.strcmp(bare_name, "memset32") == 0 or string.strcmp(func_name, "memset32") == 0:
|
||||
return i8_ptr_ty
|
||||
if bare_name == "memcpy" or func_name == "memcpy":
|
||||
if string.strcmp(bare_name, "memcpy") == 0 or string.strcmp(func_name, "memcpy") == 0:
|
||||
return i8_ptr_ty
|
||||
if bare_name == "memmove" or func_name == "memmove":
|
||||
if string.strcmp(bare_name, "memmove") == 0 or string.strcmp(func_name, "memmove") == 0:
|
||||
return i8_ptr_ty
|
||||
# JSON 解析函数返回 JsonValue*(指针)
|
||||
# from json.__parser import parse as json_parse → 别名 json_parse 也需覆盖
|
||||
if bare_name == "parse" or func_name == "parse" or func_name == "json_parse":
|
||||
if string.strcmp(bare_name, "parse") == 0 or string.strcmp(func_name, "parse") == 0 or string.strcmp(func_name, "json_parse") == 0:
|
||||
return i8_ptr_ty
|
||||
# MemBuddy 方法(当类型信息丢失时可能走外部函数路径)
|
||||
if func_name == "alloc":
|
||||
if string.strcmp(func_name, "alloc") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if func_name == "calloc":
|
||||
if string.strcmp(func_name, "calloc") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if func_name == "realloc":
|
||||
if string.strcmp(func_name, "realloc") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if func_name == "alloc_buf":
|
||||
if string.strcmp(func_name, "alloc_buf") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
# VLogger 模块函数(跨模块调用时 stub 未注入,返回指针被截断为 i32 导致崩溃)
|
||||
if func_name == "get_logger":
|
||||
if string.strcmp(func_name, "get_logger") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if func_name == "fmt_buf":
|
||||
if string.strcmp(func_name, "fmt_buf") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
# Config 模块函数(跨模块调用时 stub 未注入,返回 i8* 被 inttoptr i32 截断导致路径损坏)
|
||||
if func_name == "get_includes_binary_dir":
|
||||
if string.strcmp(func_name, "get_includes_binary_dir") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
# HandlesType 模块函数(返回 ast.AST|t.CPtr 联合类型,跨模块推断为 i32 导致指针截断)
|
||||
if string.strcmp(bare_name, "_parse_type_string") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
|
||||
# 返回 i64 的函数
|
||||
if func_name == "strlen":
|
||||
if string.strcmp(func_name, "strlen") == 0:
|
||||
return llvmlite.Int64(pool)
|
||||
if func_name == "atoll":
|
||||
if string.strcmp(func_name, "atoll") == 0:
|
||||
return llvmlite.Int64(pool)
|
||||
|
||||
# 返回 double 的函数
|
||||
if func_name == "atof":
|
||||
if string.strcmp(func_name, "atof") == 0:
|
||||
return llvmlite.Double(pool)
|
||||
|
||||
# 返回 i8 的函数
|
||||
if func_name == "samestr":
|
||||
if string.strcmp(func_name, "samestr") == 0:
|
||||
return llvmlite.Int8(pool)
|
||||
|
||||
# Win32 API 返回指针(VOIDPTR/HANDLE)的函数
|
||||
# stubs 翻译时未注入,需推断返回 i8* 避免指针被截断为 i32 导致解引用崩溃
|
||||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if func_name == "VirtualAlloc":
|
||||
if string.strcmp(func_name, "VirtualAlloc") == 0:
|
||||
return i8_ptr_ty
|
||||
if func_name == "HeapAlloc":
|
||||
if string.strcmp(func_name, "HeapAlloc") == 0:
|
||||
return i8_ptr_ty
|
||||
if func_name == "HeapReAlloc":
|
||||
if string.strcmp(func_name, "HeapReAlloc") == 0:
|
||||
return i8_ptr_ty
|
||||
if func_name == "HeapCreate":
|
||||
if string.strcmp(func_name, "HeapCreate") == 0:
|
||||
return i8_ptr_ty
|
||||
if func_name == "GetProcessHeap":
|
||||
if string.strcmp(func_name, "GetProcessHeap") == 0:
|
||||
return i8_ptr_ty
|
||||
if func_name == "GlobalAlloc":
|
||||
if string.strcmp(func_name, "GlobalAlloc") == 0:
|
||||
return i8_ptr_ty
|
||||
if func_name == "GlobalFree":
|
||||
if string.strcmp(func_name, "GlobalFree") == 0:
|
||||
return i8_ptr_ty
|
||||
if func_name == "GlobalLock":
|
||||
if string.strcmp(func_name, "GlobalLock") == 0:
|
||||
return i8_ptr_ty
|
||||
if func_name == "LocalAlloc":
|
||||
if string.strcmp(func_name, "LocalAlloc") == 0:
|
||||
return i8_ptr_ty
|
||||
if func_name == "LocalFree":
|
||||
if string.strcmp(func_name, "LocalFree") == 0:
|
||||
return i8_ptr_ty
|
||||
if func_name == "GetProcAddress":
|
||||
if string.strcmp(func_name, "GetProcAddress") == 0:
|
||||
return i8_ptr_ty
|
||||
if func_name == "GetModuleHandleA":
|
||||
if string.strcmp(func_name, "GetModuleHandleA") == 0:
|
||||
return i8_ptr_ty
|
||||
if func_name == "GetModuleHandleW":
|
||||
if string.strcmp(func_name, "GetModuleHandleW") == 0:
|
||||
return i8_ptr_ty
|
||||
if func_name == "LoadLibraryA":
|
||||
if string.strcmp(func_name, "LoadLibraryA") == 0:
|
||||
return i8_ptr_ty
|
||||
if func_name == "LoadLibraryW":
|
||||
if string.strcmp(func_name, "LoadLibraryW") == 0:
|
||||
return i8_ptr_ty
|
||||
# Win32 Handle 返回函数(HANDLE = void* = i8*)
|
||||
if func_name == "GetStdHandle":
|
||||
if string.strcmp(func_name, "GetStdHandle") == 0:
|
||||
return i8_ptr_ty
|
||||
if func_name == "CreateFileA":
|
||||
if string.strcmp(func_name, "CreateFileA") == 0:
|
||||
return i8_ptr_ty
|
||||
if func_name == "CreateFileW":
|
||||
if string.strcmp(func_name, "CreateFileW") == 0:
|
||||
return i8_ptr_ty
|
||||
if func_name == "FindFirstFileA":
|
||||
if string.strcmp(func_name, "FindFirstFileA") == 0:
|
||||
return i8_ptr_ty
|
||||
if func_name == "FindFirstFileW":
|
||||
if string.strcmp(func_name, "FindFirstFileW") == 0:
|
||||
return i8_ptr_ty
|
||||
|
||||
# Win32 API 返回 i64 (SIZE_T) 的函数
|
||||
if func_name == "VirtualQuery":
|
||||
if string.strcmp(func_name, "VirtualQuery") == 0:
|
||||
return llvmlite.Int64(pool)
|
||||
if func_name == "HeapSize":
|
||||
if string.strcmp(func_name, "HeapSize") == 0:
|
||||
return llvmlite.Int64(pool)
|
||||
if func_name == "HeapCompact":
|
||||
if string.strcmp(func_name, "HeapCompact") == 0:
|
||||
return llvmlite.Int64(pool)
|
||||
if func_name == "GlobalSize":
|
||||
if string.strcmp(func_name, "GlobalSize") == 0:
|
||||
return llvmlite.Int64(pool)
|
||||
|
||||
# llvmlite build_* 函数返回类型推断
|
||||
@@ -498,10 +501,10 @@ def _infer_external_func_ret_ty(pool: memhub.MemBuddy | t.CPtr,
|
||||
# 大多数 build_* 函数返回 Value*(指针),少数终止指令返回 void
|
||||
if string.strncmp(func_name, "build_", 6) == 0:
|
||||
# 返回 void 的 build_* 函数(终止指令和无返回值指令)
|
||||
if func_name == "build_ret" or func_name == "build_ret_void" or \
|
||||
func_name == "build_store" or func_name == "build_br" or \
|
||||
func_name == "build_cond_br" or func_name == "build_unreachable" or \
|
||||
func_name == "build_switch":
|
||||
if string.strcmp(func_name, "build_ret") == 0 or string.strcmp(func_name, "build_ret_void") == 0 or \
|
||||
string.strcmp(func_name, "build_store") == 0 or string.strcmp(func_name, "build_br") == 0 or \
|
||||
string.strcmp(func_name, "build_cond_br") == 0 or string.strcmp(func_name, "build_unreachable") == 0 or \
|
||||
string.strcmp(func_name, "build_switch") == 0:
|
||||
return llvmlite.Void(pool)
|
||||
# 其他 build_* 函数返回 Value*(指针)
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
@@ -511,19 +514,19 @@ def _infer_external_func_ret_ty(pool: memhub.MemBuddy | t.CPtr,
|
||||
# new_param_node/new_phi_incoming 返回 ParamNode*/PhiIncoming*(指针)
|
||||
# const_int32/const_int64/ConstFloat/ConstZero/ConstNull/ConstInt 返回 Value*(指针)
|
||||
# function_get_name/param_get_ty 等访问器返回指针
|
||||
if func_name == "Int1" or func_name == "Int8" or func_name == "Int16" or \
|
||||
func_name == "Int32" or func_name == "Int64" or func_name == "Ptr" or \
|
||||
func_name == "Func" or func_name == "Array" or func_name == "Struct" or \
|
||||
func_name == "Void" or func_name == "Half" or func_name == "Float" or \
|
||||
func_name == "Double" or func_name == "FP128" or func_name == "Label" or \
|
||||
func_name == "new_param_node" or func_name == "new_phi_incoming" or \
|
||||
func_name == "const_int32" or func_name == "const_int64" or \
|
||||
func_name == "ConstFloat" or func_name == "ConstZero" or \
|
||||
func_name == "ConstNull" or func_name == "ConstInt" or \
|
||||
func_name == "function_get_name" or func_name == "param_get_ty" or \
|
||||
func_name == "value_get_ty" or func_name == "value_get_next" or \
|
||||
func_name == "function_get_ret_ty" or func_name == "function_get_params" or \
|
||||
func_name == "function_get_param_head" or func_name == "param_get_next":
|
||||
if string.strcmp(func_name, "Int1") == 0 or string.strcmp(func_name, "Int8") == 0 or string.strcmp(func_name, "Int16") == 0 or \
|
||||
string.strcmp(func_name, "Int32") == 0 or string.strcmp(func_name, "Int64") == 0 or string.strcmp(func_name, "Ptr") == 0 or \
|
||||
string.strcmp(func_name, "Func") == 0 or string.strcmp(func_name, "Array") == 0 or string.strcmp(func_name, "Struct") == 0 or \
|
||||
string.strcmp(func_name, "Void") == 0 or string.strcmp(func_name, "Half") == 0 or string.strcmp(func_name, "Float") == 0 or \
|
||||
string.strcmp(func_name, "Double") == 0 or string.strcmp(func_name, "FP128") == 0 or string.strcmp(func_name, "Label") == 0 or \
|
||||
string.strcmp(func_name, "new_param_node") == 0 or string.strcmp(func_name, "new_phi_incoming") == 0 or \
|
||||
string.strcmp(func_name, "const_int32") == 0 or string.strcmp(func_name, "const_int64") == 0 or \
|
||||
string.strcmp(func_name, "ConstFloat") == 0 or string.strcmp(func_name, "ConstZero") == 0 or \
|
||||
string.strcmp(func_name, "ConstNull") == 0 or string.strcmp(func_name, "ConstInt") == 0 or \
|
||||
string.strcmp(func_name, "function_get_name") == 0 or string.strcmp(func_name, "param_get_ty") == 0 or \
|
||||
string.strcmp(func_name, "value_get_ty") == 0 or string.strcmp(func_name, "value_get_next") == 0 or \
|
||||
string.strcmp(func_name, "function_get_ret_ty") == 0 or string.strcmp(func_name, "function_get_params") == 0 or \
|
||||
string.strcmp(func_name, "function_get_param_head") == 0 or string.strcmp(func_name, "param_get_next") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
|
||||
# 默认 i32(整数):与本模块函数定义的默认返回类型一致(HandlesFunctions.py line 324)
|
||||
@@ -579,7 +582,7 @@ def _get_external_func_param_ty(pool: memhub.MemBuddy | t.CPtr,
|
||||
api_count: t.CSizeT = win32_apis.__len__()
|
||||
for ai in range(api_count):
|
||||
api_name: str = win32_apis.get(ai)
|
||||
if api_name == func_name:
|
||||
if string.strcmp(api_name, func_name) == 0:
|
||||
return i64_ty
|
||||
|
||||
return None
|
||||
@@ -926,81 +929,81 @@ def _resolve_register(attr_name: str) -> str:
|
||||
return ""
|
||||
|
||||
# Clobber 破坏描述符
|
||||
if attr_name == "CLOBBER_MEMORY": return "memory"
|
||||
if attr_name == "CLOBBER_CC": return "cc"
|
||||
if attr_name == "CLOBBER_RAX": return "rax"
|
||||
if attr_name == "CLOBBER_RBX": return "rbx"
|
||||
if attr_name == "CLOBBER_RCX": return "rcx"
|
||||
if attr_name == "CLOBBER_RDX": return "rdx"
|
||||
if attr_name == "CLOBBER_RSI": return "rsi"
|
||||
if attr_name == "CLOBBER_RDI": return "rdi"
|
||||
if attr_name == "CLOBBER_RBP": return "rbp"
|
||||
if attr_name == "CLOBBER_RSP": return "rsp"
|
||||
if attr_name == "CLOBBER_R8": return "r8"
|
||||
if attr_name == "CLOBBER_R9": return "r9"
|
||||
if attr_name == "CLOBBER_R10": return "r10"
|
||||
if attr_name == "CLOBBER_R11": return "r11"
|
||||
if attr_name == "CLOBBER_R12": return "r12"
|
||||
if attr_name == "CLOBBER_R13": return "r13"
|
||||
if attr_name == "CLOBBER_R14": return "r14"
|
||||
if attr_name == "CLOBBER_R15": return "r15"
|
||||
if attr_name == "CLOBBER_EAX": return "eax"
|
||||
if attr_name == "CLOBBER_EBX": return "ebx"
|
||||
if attr_name == "CLOBBER_ECX": return "ecx"
|
||||
if attr_name == "CLOBBER_EDX": return "edx"
|
||||
if attr_name == "CLOBBER_ESI": return "esi"
|
||||
if attr_name == "CLOBBER_EDI": return "edi"
|
||||
if attr_name == "CLOBBER_DX": return "dx"
|
||||
if attr_name == "CLOBBER_AX": return "ax"
|
||||
if attr_name == "CLOBBER_CX": return "cx"
|
||||
if attr_name == "CLOBBER_SI": return "si"
|
||||
if attr_name == "CLOBBER_DI": return "di"
|
||||
if string.strcmp(attr_name, "CLOBBER_MEMORY") == 0: return "memory"
|
||||
if string.strcmp(attr_name, "CLOBBER_CC") == 0: return "cc"
|
||||
if string.strcmp(attr_name, "CLOBBER_RAX") == 0: return "rax"
|
||||
if string.strcmp(attr_name, "CLOBBER_RBX") == 0: return "rbx"
|
||||
if string.strcmp(attr_name, "CLOBBER_RCX") == 0: return "rcx"
|
||||
if string.strcmp(attr_name, "CLOBBER_RDX") == 0: return "rdx"
|
||||
if string.strcmp(attr_name, "CLOBBER_RSI") == 0: return "rsi"
|
||||
if string.strcmp(attr_name, "CLOBBER_RDI") == 0: return "rdi"
|
||||
if string.strcmp(attr_name, "CLOBBER_RBP") == 0: return "rbp"
|
||||
if string.strcmp(attr_name, "CLOBBER_RSP") == 0: return "rsp"
|
||||
if string.strcmp(attr_name, "CLOBBER_R8") == 0: return "r8"
|
||||
if string.strcmp(attr_name, "CLOBBER_R9") == 0: return "r9"
|
||||
if string.strcmp(attr_name, "CLOBBER_R10") == 0: return "r10"
|
||||
if string.strcmp(attr_name, "CLOBBER_R11") == 0: return "r11"
|
||||
if string.strcmp(attr_name, "CLOBBER_R12") == 0: return "r12"
|
||||
if string.strcmp(attr_name, "CLOBBER_R13") == 0: return "r13"
|
||||
if string.strcmp(attr_name, "CLOBBER_R14") == 0: return "r14"
|
||||
if string.strcmp(attr_name, "CLOBBER_R15") == 0: return "r15"
|
||||
if string.strcmp(attr_name, "CLOBBER_EAX") == 0: return "eax"
|
||||
if string.strcmp(attr_name, "CLOBBER_EBX") == 0: return "ebx"
|
||||
if string.strcmp(attr_name, "CLOBBER_ECX") == 0: return "ecx"
|
||||
if string.strcmp(attr_name, "CLOBBER_EDX") == 0: return "edx"
|
||||
if string.strcmp(attr_name, "CLOBBER_ESI") == 0: return "esi"
|
||||
if string.strcmp(attr_name, "CLOBBER_EDI") == 0: return "edi"
|
||||
if string.strcmp(attr_name, "CLOBBER_DX") == 0: return "dx"
|
||||
if string.strcmp(attr_name, "CLOBBER_AX") == 0: return "ax"
|
||||
if string.strcmp(attr_name, "CLOBBER_CX") == 0: return "cx"
|
||||
if string.strcmp(attr_name, "CLOBBER_SI") == 0: return "si"
|
||||
if string.strcmp(attr_name, "CLOBBER_DI") == 0: return "di"
|
||||
|
||||
# Output 输出约束
|
||||
if attr_name == "OUTPUT_REG": return "=r"
|
||||
if attr_name == "OUTPUT_MEM": return "=m"
|
||||
if attr_name == "OUTPUT_EAX": return "=a"
|
||||
if attr_name == "OUTPUT_EBX": return "=b"
|
||||
if attr_name == "OUTPUT_ECX": return "=c"
|
||||
if attr_name == "OUTPUT_EDX": return "=d"
|
||||
if attr_name == "OUTPUT_ESI": return "=S"
|
||||
if attr_name == "OUTPUT_EDI": return "=D"
|
||||
if attr_name == "OUTPUT_RAX": return "=a"
|
||||
if attr_name == "OUTPUT_RBX": return "=b"
|
||||
if attr_name == "OUTPUT_RCX": return "=c"
|
||||
if attr_name == "OUTPUT_RDX": return "=d"
|
||||
if attr_name == "OUTPUT_RSI": return "=S"
|
||||
if attr_name == "OUTPUT_RDI": return "=D"
|
||||
if string.strcmp(attr_name, "OUTPUT_REG") == 0: return "=r"
|
||||
if string.strcmp(attr_name, "OUTPUT_MEM") == 0: return "=m"
|
||||
if string.strcmp(attr_name, "OUTPUT_EAX") == 0: return "=a"
|
||||
if string.strcmp(attr_name, "OUTPUT_EBX") == 0: return "=b"
|
||||
if string.strcmp(attr_name, "OUTPUT_ECX") == 0: return "=c"
|
||||
if string.strcmp(attr_name, "OUTPUT_EDX") == 0: return "=d"
|
||||
if string.strcmp(attr_name, "OUTPUT_ESI") == 0: return "=S"
|
||||
if string.strcmp(attr_name, "OUTPUT_EDI") == 0: return "=D"
|
||||
if string.strcmp(attr_name, "OUTPUT_RAX") == 0: return "=a"
|
||||
if string.strcmp(attr_name, "OUTPUT_RBX") == 0: return "=b"
|
||||
if string.strcmp(attr_name, "OUTPUT_RCX") == 0: return "=c"
|
||||
if string.strcmp(attr_name, "OUTPUT_RDX") == 0: return "=d"
|
||||
if string.strcmp(attr_name, "OUTPUT_RSI") == 0: return "=S"
|
||||
if string.strcmp(attr_name, "OUTPUT_RDI") == 0: return "=D"
|
||||
|
||||
# Input/Register 输入约束
|
||||
if attr_name == "REG_ANY": return "r"
|
||||
if attr_name == "REG_EAX": return "a"
|
||||
if attr_name == "REG_EBX": return "b"
|
||||
if attr_name == "REG_ECX": return "c"
|
||||
if attr_name == "REG_EDX": return "d"
|
||||
if attr_name == "REG_ESI": return "S"
|
||||
if attr_name == "REG_EDI": return "D"
|
||||
if attr_name == "REG_RAX": return "a"
|
||||
if attr_name == "REG_RBX": return "b"
|
||||
if attr_name == "REG_RCX": return "c"
|
||||
if attr_name == "REG_RDX": return "d"
|
||||
if attr_name == "REG_RSI": return "S"
|
||||
if attr_name == "REG_RDI": return "D"
|
||||
if string.strcmp(attr_name, "REG_ANY") == 0: return "r"
|
||||
if string.strcmp(attr_name, "REG_EAX") == 0: return "a"
|
||||
if string.strcmp(attr_name, "REG_EBX") == 0: return "b"
|
||||
if string.strcmp(attr_name, "REG_ECX") == 0: return "c"
|
||||
if string.strcmp(attr_name, "REG_EDX") == 0: return "d"
|
||||
if string.strcmp(attr_name, "REG_ESI") == 0: return "S"
|
||||
if string.strcmp(attr_name, "REG_EDI") == 0: return "D"
|
||||
if string.strcmp(attr_name, "REG_RAX") == 0: return "a"
|
||||
if string.strcmp(attr_name, "REG_RBX") == 0: return "b"
|
||||
if string.strcmp(attr_name, "REG_RCX") == 0: return "c"
|
||||
if string.strcmp(attr_name, "REG_RDX") == 0: return "d"
|
||||
if string.strcmp(attr_name, "REG_RSI") == 0: return "S"
|
||||
if string.strcmp(attr_name, "REG_RDI") == 0: return "D"
|
||||
|
||||
if attr_name == "INPUT_REG": return "r"
|
||||
if attr_name == "INPUT_MEM": return "m"
|
||||
if attr_name == "INPUT_EAX": return "a"
|
||||
if attr_name == "INPUT_EBX": return "b"
|
||||
if attr_name == "INPUT_ECX": return "c"
|
||||
if attr_name == "INPUT_EDX": return "d"
|
||||
if attr_name == "INPUT_ESI": return "S"
|
||||
if attr_name == "INPUT_EDI": return "D"
|
||||
if attr_name == "INPUT_RAX": return "a"
|
||||
if attr_name == "INPUT_RBX": return "b"
|
||||
if attr_name == "INPUT_RCX": return "c"
|
||||
if attr_name == "INPUT_RDX": return "d"
|
||||
if attr_name == "INPUT_RSI": return "S"
|
||||
if attr_name == "INPUT_RDI": return "D"
|
||||
if string.strcmp(attr_name, "INPUT_REG") == 0: return "r"
|
||||
if string.strcmp(attr_name, "INPUT_MEM") == 0: return "m"
|
||||
if string.strcmp(attr_name, "INPUT_EAX") == 0: return "a"
|
||||
if string.strcmp(attr_name, "INPUT_EBX") == 0: return "b"
|
||||
if string.strcmp(attr_name, "INPUT_ECX") == 0: return "c"
|
||||
if string.strcmp(attr_name, "INPUT_EDX") == 0: return "d"
|
||||
if string.strcmp(attr_name, "INPUT_ESI") == 0: return "S"
|
||||
if string.strcmp(attr_name, "INPUT_EDI") == 0: return "D"
|
||||
if string.strcmp(attr_name, "INPUT_RAX") == 0: return "a"
|
||||
if string.strcmp(attr_name, "INPUT_RBX") == 0: return "b"
|
||||
if string.strcmp(attr_name, "INPUT_RCX") == 0: return "c"
|
||||
if string.strcmp(attr_name, "INPUT_RDX") == 0: return "d"
|
||||
if string.strcmp(attr_name, "INPUT_RSI") == 0: return "S"
|
||||
if string.strcmp(attr_name, "INPUT_RDI") == 0: return "D"
|
||||
|
||||
return ""
|
||||
|
||||
@@ -3770,7 +3773,7 @@ def _translate_call_with_kwargs(pool: memhub.MemBuddy | t.CPtr,
|
||||
call_ret_ty = _infer_external_func_ret_ty(pool, func_name)
|
||||
|
||||
# memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失)
|
||||
if func_name == "memcpy" and actual_count >= 3:
|
||||
if string.strcmp(func_name, "memcpy") == 0 and actual_count >= 3:
|
||||
return _emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst1, mc_src1, mc_num1)
|
||||
return llvmlite.build_call(builder, call_name, head, actual_count, call_ret_ty, 0)
|
||||
|
||||
@@ -4932,7 +4935,7 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
|
||||
|
||||
# 直接调用
|
||||
# memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失)
|
||||
if func_name == "memcpy" and can >= 3:
|
||||
if string.strcmp(func_name, "memcpy") == 0 and can >= 3:
|
||||
return _emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst2, mc_src2, mc_num2)
|
||||
# 别名导入重新推断返回类型:
|
||||
# from X import parse as json_parse → func_name="json_parse" 时 _infer_external_func_ret_ty 返回默认 i32
|
||||
|
||||
@@ -336,7 +336,7 @@ def forward_declare_functions(trans: HT.Translator | t.CPtr,
|
||||
is_extern_decl = 1
|
||||
|
||||
# 计算 mangled name
|
||||
if has_extern != 0 or has_state != 0 or has_export != 0 or fd.name == "main":
|
||||
if has_extern != 0 or has_state != 0 or has_export != 0 or string.strcmp(fd.name, "main") == 0:
|
||||
mangled_name: str = fd.name
|
||||
else:
|
||||
mangled_name = _mangle_func_name(trans, fd.name, 0)
|
||||
@@ -468,7 +468,7 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
|
||||
# SHA1 命名空间:t.CExtern/t.State/t.CExport 不加前缀,直接用裸名
|
||||
# (裸名映射到 C 标准库符号,带 sha1 前缀会导致 undefined reference)
|
||||
# main 函数也不加前缀(程序入口点)
|
||||
if has_extern != 0 or has_state != 0 or has_export != 0 or fd.name == "main":
|
||||
if has_extern != 0 or has_state != 0 or has_export != 0 or string.strcmp(fd.name, "main") == 0:
|
||||
mangled_name: str = fd.name
|
||||
else:
|
||||
mangled_name: str = _mangle_func_name(trans, fd.name, 0)
|
||||
|
||||
@@ -103,7 +103,7 @@ def add_from_import(pool: memhub.MemBuddy | t.CPtr,
|
||||
entry: t.CChar | t.CPtr = pool.alloc(256)
|
||||
if entry is None:
|
||||
return from_imports
|
||||
if original_name is not None and original_name != local_name:
|
||||
if original_name is not None and string.strcmp(original_name, local_name) != 0:
|
||||
viperlib.snprintf(entry, 256, "%s:%s:%s", local_name, module_name, original_name)
|
||||
else:
|
||||
viperlib.snprintf(entry, 256, "%s:%s", local_name, module_name)
|
||||
@@ -262,7 +262,7 @@ def lookup_from_import(from_imports: str, name: str,
|
||||
# ============================================================
|
||||
# 全局 re-export 映射表(module_sha1 + func_name → source_module)
|
||||
#
|
||||
# 当 ast/__init__.py 中有 from .lexer import _lexer_init 时,
|
||||
# 当 ast/__init__.vp 中有 from .lexer import _lexer_init 时,
|
||||
# _lexer_init 被 re-export 为 ast._lexer_init。
|
||||
# 跨模块调用 ast._lexer_init(...) 需使用 ast.lexer 的 SHA1 混淆,
|
||||
# 而非 ast 的 SHA1。
|
||||
@@ -427,10 +427,10 @@ def _resolve_relative_module(pool: memhub.MemBuddy | t.CPtr,
|
||||
# 对于顶级文件(无目录分隔符),返回 None
|
||||
#
|
||||
# 示例:
|
||||
# "llvmlite/__init__.py" → "llvmlite"
|
||||
# "llvmlite/__types.py" → "llvmlite"
|
||||
# "ast/parser.py" → "ast"
|
||||
# "ast.py" → None(顶级文件)
|
||||
# "llvmlite/__init__.vp" → "llvmlite"
|
||||
# "llvmlite/__types.vp" → "llvmlite"
|
||||
# "ast/parser.vp" → "ast"
|
||||
# "ast.vp" → None(顶级文件)
|
||||
# ============================================================
|
||||
def compute_package_from_relpath(pool: memhub.MemBuddy | t.CPtr,
|
||||
rel_path: str) -> str:
|
||||
|
||||
@@ -378,17 +378,12 @@ def _parse_type_string(pool: memhub.MemBuddy | t.CPtr,
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _parse_type_string_ptr - _parse_type_string 的 t.CPtr 返回类型包装
|
||||
# _parse_type_string_ptr 已移除
|
||||
#
|
||||
# 旧编译器对 ast.AST | t.CPtr 跨模块返回类型推断有 bug(解析为 i32),
|
||||
# 用 t.CPtr 包装绕过,外部模块应调用此函数而非 _parse_type_string
|
||||
# 原先用 t.CPtr 包装绕过旧编译器对 ast.AST|t.CPtr 跨模块返回类型
|
||||
# 推断为 i32 的 bug。现在已在 _infer_external_func_ret_ty 中注册
|
||||
# _parse_type_string 返回 i8*,外部模块直接调用 _parse_type_string。
|
||||
# ============================================================
|
||||
def _parse_type_string_ptr(pool: memhub.MemBuddy | t.CPtr,
|
||||
type_str: str,
|
||||
ctx: t.CInt) -> t.CPtr:
|
||||
"""_parse_type_string 的 t.CPtr 返回类型包装(绕过旧编译器类型推断 bug)"""
|
||||
result: ast.AST | t.CPtr = _parse_type_string(pool, type_str, ctx)
|
||||
return result
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -467,7 +462,7 @@ def fatal_error(node: ast.AST | t.CPtr, msg: str):
|
||||
file_name = "<unknown>"
|
||||
stdio.printf("Traceback (most recent call last):\n")
|
||||
stdio.printf(' File "%s", line %d\n', file_name, lineno)
|
||||
if lineno > 0 and file_name != "<unknown>":
|
||||
if lineno > 0 and string.strcmp(file_name, "<unknown>") != 0:
|
||||
src_line: str = _read_source_line(file_name, lineno)
|
||||
if src_line is not None:
|
||||
stdio.printf(" %s\n", src_line)
|
||||
|
||||
@@ -15,7 +15,7 @@ import lib.core.VLogger as VLogger
|
||||
# ============================================================
|
||||
# IncludesScanner - includes 目录递归扫描
|
||||
#
|
||||
# 递归扫描 includes 目录,收集所有 .py 文件路径和 SHA1,
|
||||
# 递归扫描 includes 目录,收集所有 .vp/.py 文件路径和 SHA1,
|
||||
# 为 Phase1 stub 生成和 Phase2 stub 合并提供基础数据。
|
||||
#
|
||||
# 使用 Win32 FindFirstFileA/FindNextFileA 实现目录遍历。
|
||||
@@ -90,7 +90,7 @@ def add_file_entry(result: ScanResult | t.CPtr,
|
||||
if result.Count >= result.Capacity:
|
||||
return 1
|
||||
|
||||
# 计算模块名:rel_path 中的 / 替换为 .,去掉 .py 扩展名
|
||||
# 计算模块名:rel_path 中的 / 替换为 .,去掉 .vp/.py 扩展名
|
||||
rel_len: t.CSizeT = string.strlen(rel_path)
|
||||
mod_buf: str = stdlib.malloc(rel_len + 1)
|
||||
if mod_buf is None:
|
||||
@@ -160,7 +160,7 @@ def compute_file_sha1(pool: memhub.MemBuddy | t.CPtr,
|
||||
if f.closed:
|
||||
return None
|
||||
|
||||
# 分配读取缓冲区(128KB,足够大多数 .py 文件)
|
||||
# 分配读取缓冲区(128KB,足够大多数 .vp/.py 文件)
|
||||
# 使用 stdlib.malloc 避免 mbuddy 池耗尽(每文件 128KB,60+ 文件会耗尽 16MB 池)
|
||||
BUF_SIZE: t.CSizeT = 131072
|
||||
buf: bytes = stdlib.malloc(BUF_SIZE)
|
||||
@@ -221,13 +221,13 @@ def compute_file_sha1(pool: memhub.MemBuddy | t.CPtr,
|
||||
# scan_directory_recursive - 递归扫描目录
|
||||
#
|
||||
# 使用 FindFirstFileA/FindNextFileA 遍历目录树,
|
||||
# 对每个 .py 文件计算 SHA1 并添加到结果中。
|
||||
# 对每个 .vp/.py 文件计算 SHA1 并添加到结果中。
|
||||
# ============================================================
|
||||
def scan_directory_recursive(pool: memhub.MemBuddy | t.CPtr,
|
||||
root_dir: str,
|
||||
rel_prefix: str,
|
||||
result: ScanResult | t.CPtr) -> int:
|
||||
"""递归扫描目录,收集 .py 文件"""
|
||||
"""递归扫描目录,收集 .vp/.py 文件"""
|
||||
if pool is None or root_dir is None or result is None:
|
||||
return 1
|
||||
|
||||
@@ -329,11 +329,11 @@ def scan_directory_recursive(pool: memhub.MemBuddy | t.CPtr,
|
||||
# ============================================================
|
||||
# scan_includes - 扫描 includes 目录入口
|
||||
#
|
||||
# 扫描指定的 includes 目录,返回所有 .py 文件的路径和 SHA1。
|
||||
# 扫描指定的 includes 目录,返回所有 .vp/.py 文件的路径和 SHA1。
|
||||
# ============================================================
|
||||
def scan_includes(pool: memhub.MemBuddy | t.CPtr,
|
||||
includes_dir: str) -> ScanResult | t.CPtr:
|
||||
"""扫描 includes 目录,返回所有 .py 文件的扫描结果"""
|
||||
"""扫描 includes 目录,返回所有 .vp/.py 文件的扫描结果"""
|
||||
if pool is None or includes_dir is None:
|
||||
return None
|
||||
|
||||
@@ -360,6 +360,6 @@ def find_entry_by_module(result: ScanResult | t.CPtr,
|
||||
entry: FileEntry | t.CPtr = (FileEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||||
if entry is not None:
|
||||
if entry.ModuleName is not None:
|
||||
if entry.ModuleName == module_name:
|
||||
if string.strcmp(entry.ModuleName, module_name) == 0:
|
||||
return entry
|
||||
return None
|
||||
@@ -29,7 +29,7 @@ _mbuddy: memhub.MemBuddy | t.CPtr
|
||||
# 源代码缓冲区大小(1MB)
|
||||
SRC_BUF_SIZE: t.CDefine = 1048576
|
||||
|
||||
# pyi 缓冲区大小(256KB)
|
||||
# vpi 缓冲区大小(256KB)
|
||||
PYI_BUF_SIZE: t.CSizeT = 262144
|
||||
|
||||
# 拓扑排序相关常量
|
||||
@@ -480,7 +480,7 @@ def _TopoSortFiles(mb: memhub.MemBuddy | t.CPtr,
|
||||
# ============================================================
|
||||
# RunPhase1 - Phase1: 扫描 includes 目录,按需翻译并生成 stub
|
||||
#
|
||||
# 对每个 .py 文件检查 stub 是否已存在,若不存在则翻译并分离 stub。
|
||||
# 对每个 .vp/.py 文件检查 stub 是否已存在,若不存在则翻译并分离 stub。
|
||||
# "按需翻译":仅对 stub 不存在的文件执行翻译,避免重复工作。
|
||||
#
|
||||
# Args:
|
||||
@@ -684,7 +684,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
if reachable_count > 0:
|
||||
use_reachable = 1
|
||||
# 用可达集合重新生成 _sha1_map.txt(按图求索的最终产物)
|
||||
# Phase B+ 只遍历这些条目,避免编译不需要的 includes(如 asm.py)
|
||||
# Phase B+ 只遍历这些条目,避免编译不需要的 includes(如 asm.vp)
|
||||
StubMerger.WriteIncludesSha1Map(mb, temp_dir, result, reachable_set, reachable_count)
|
||||
# 重新加载 sha1_set,使后续 Phase 1a-pre/1a/1b 的过滤也使用可达集合
|
||||
string.memset(sha1_set, 0, StubMerger.MAX_INCLUDES_SHA1 * 17)
|
||||
@@ -702,7 +702,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
# 只处理可达文件,避免翻译不需要的 includes(如 Test 不依赖 ast 模块)。
|
||||
#
|
||||
# 拓扑排序:预扫描所有文件收集类继承关系,按依赖顺序处理文件,
|
||||
# 确保父类所在文件先于子类所在文件处理(如 base.py 先于 astaux.py)。
|
||||
# 确保父类所在文件先于子类所在文件处理(如 base.vp 先于 astaux.vp)。
|
||||
# ============================================================
|
||||
p1a_reg: int = 0
|
||||
p1a_skp: int = 0
|
||||
|
||||
+36
-22
@@ -45,10 +45,10 @@ class SrcFileEntry:
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _ScanDirForPyFiles - 递归扫描目录,收集 .py 文件到 entries
|
||||
# _ScanDirForPyFiles - 递归扫描目录,收集 .vp/.py 文件到 entries
|
||||
#
|
||||
# 替代旧的非递归 FindFirstFileA(dir/*.py) 扫描,支持子目录
|
||||
# (如 App/lib/core/Handles/)。遇到目录递归扫描,遇到 .py
|
||||
# (如 App/lib/core/Handles/)。遇到目录递归扫描,遇到 .vp/.py
|
||||
# 文件读取内容、计算 SHA1、加入 entries。
|
||||
#
|
||||
# Args:
|
||||
@@ -67,7 +67,7 @@ def _ScanDirForPyFiles(mb: memhub.MemBuddy | t.CPtr,
|
||||
entries: SrcFileEntry | t.CPtr,
|
||||
entry_size: t.CSizeT,
|
||||
file_count: int, max_files: int) -> int:
|
||||
"""递归扫描目录,收集 .py 文件到 entries,返回新的 file_count"""
|
||||
"""递归扫描目录,收集 .vp/.py 文件到 entries,返回新的 file_count"""
|
||||
if dir_path is None or entries is None:
|
||||
return file_count
|
||||
if file_count >= max_files:
|
||||
@@ -184,7 +184,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
viperlib.snprintf(fb, 1024, "多文件项目编译: %s", source_dir)
|
||||
VLogger.info(fb, "project")
|
||||
|
||||
# === 1. 递归扫描 source_dir 下的 .py 文件(包括子目录)===
|
||||
# === 1. 递归扫描 source_dir 下的 .vp/.py 文件(包括子目录)===
|
||||
entry_size: t.CSizeT = SrcFileEntry.__sizeof__()
|
||||
entries: SrcFileEntry | t.CPtr = stdlib.malloc(MAX_SRC_FILES * entry_size)
|
||||
if entries is None:
|
||||
@@ -222,7 +222,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
VLogger.info(fb_inc, "project")
|
||||
|
||||
# 追加 App 源文件 SHA1 到 _sha1_map.txt(人类可读输出,程序内部不读取此文件)
|
||||
# 格式: {sha1}:{rel_path}\n (保留目录结构,如 lib/core/VLogger.py)
|
||||
# 格式: {sha1}:{rel_path}\n (保留目录结构,如 lib/core/VLogger.vp)
|
||||
# 同步追加到内存存储器(AppendToSha1MapStore,供跨模块 CDefine 查找)
|
||||
td_len_am: t.CSizeT = string.strlen(temp_dir)
|
||||
src_dir_len_am: t.CSizeT = string.strlen(source_dir)
|
||||
@@ -246,7 +246,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
if string.strncmp(p_str, source_dir, src_dir_len_am) == 0:
|
||||
rel_path_am = p_str + src_dir_len_am + 1
|
||||
# 同步追加到内存存储器(供跨模块 CDefine 查找)
|
||||
# rel_path_am 格式如 "lib/core/StubMerger.py",与 _sha1_map.txt 一致
|
||||
# rel_path_am 格式如 "lib/core/StubMerger.vp",与 _sha1_map.txt 一致
|
||||
if StubMerger.AppendToSha1MapStore(ent_am.Sha1, rel_path_am) == 0:
|
||||
app_filled += 1
|
||||
# 写入 _sha1_map.txt(人类可读输出)
|
||||
@@ -289,7 +289,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
if path_len_us > src_dir_len_us + 1:
|
||||
if string.strncmp(path_str, source_dir, src_dir_len_us) == 0:
|
||||
rel_path_us = path_str + src_dir_len_us + 1
|
||||
# 使用 _PathToModuleName 转换为点分模块名(处理 __init__.py → 包名)
|
||||
# 使用 _PathToModuleName 转换为点分模块名(处理 __init__.vp → 包名)
|
||||
mod_name_us: str = StubMerger._PathToModuleName(rel_path_us)
|
||||
if mod_name_us is None:
|
||||
continue
|
||||
@@ -369,7 +369,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
# === Phase A-pre: 预注册所有源文件的 struct/enum/union ===
|
||||
# 解决循环引用问题:circ_a 翻译时需要知道 circ_b.ClassB 的 struct 定义
|
||||
# 仅注册 struct/enum/union(declare_only=1),不翻译方法体
|
||||
# 多遍扫描:解决跨文件继承的字母序问题(如 HandlesAnnAssign.py 在 HandlesBase.py 之前,
|
||||
# 多遍扫描:解决跨文件继承的字母序问题(如 HandlesAnnAssign.vp/.py 在 HandlesBase.vp/.py 之前,
|
||||
# AnnAssignHandle 继承 Mixin 时 Mixin 未注册)。每遍注册新类后,下一遍子类可继承。
|
||||
VLogger.info("预注册 struct/enum/union...", "PhaseA")
|
||||
src_dir_len_pre: t.CSizeT = string.strlen(source_dir)
|
||||
@@ -879,7 +879,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
else:
|
||||
exe_path = linker_output
|
||||
|
||||
# 构造最终 .obj 路径列表:main_obj_path 在前,其他 .obj 在后
|
||||
# 构造最终 .obj 路径列表:main_obj_path 在前,reachable .obj 在后
|
||||
final_obj_paths: bytes = stdlib.malloc(OBJ_PATHS_SIZE + 512)
|
||||
if final_obj_paths is None:
|
||||
stdlib.free(entries)
|
||||
@@ -891,32 +891,46 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
mlen: t.CSizeT = string.strlen(main_obj_path)
|
||||
string.strcpy(final_obj_paths, main_obj_path)
|
||||
fop_pos = mlen
|
||||
if obj_paths[0] != '\0':
|
||||
|
||||
# 按图链接:遍历 reachable_set,只收集可达 includes 的 .obj
|
||||
# 不再全量收集 includes.binary 下的所有 .obj
|
||||
if reachable_set is not None and reachable_count > 0:
|
||||
ibd_len_pc: t.CSizeT = string.strlen(includes_binary_dir)
|
||||
ri_pc: int
|
||||
for ri_pc in range(reachable_count):
|
||||
rsha1_pc: str = reachable_set + t.CSizeT(ri_pc) * 17
|
||||
if rsha1_pc[0] == '\0':
|
||||
continue
|
||||
obj_path_pc: str = StubMerger._sliced_path(includes_binary_dir, ibd_len_pc, rsha1_pc, "obj")
|
||||
if obj_path_pc is not None:
|
||||
# 检查 .obj 文件是否存在
|
||||
cf_pc: fileio.File | t.CPtr = fileio.File(obj_path_pc, fileio.MODE.R)
|
||||
if not cf_pc.closed:
|
||||
cf_pc.close()
|
||||
# .obj 存在,追加到 final_obj_paths
|
||||
op_len_pc: t.CSizeT = string.strlen(obj_path_pc)
|
||||
if fop_pos + op_len_pc + 2 < OBJ_PATHS_SIZE + 512:
|
||||
if fop_pos > 0:
|
||||
final_obj_paths[fop_pos] = ' '
|
||||
fop_pos += 1
|
||||
# 追加其他 .obj
|
||||
if obj_paths[0] != '\0':
|
||||
string.strcpy(final_obj_paths + fop_pos, obj_paths)
|
||||
fop_pos += string.strlen(obj_paths)
|
||||
string.strcpy(final_obj_paths + fop_pos, obj_path_pc)
|
||||
fop_pos += op_len_pc
|
||||
final_obj_paths[fop_pos] = '\0'
|
||||
stdlib.free(obj_path_pc)
|
||||
|
||||
final_obj_paths[fop_pos] = '\0'
|
||||
obj_paths_len: t.CSizeT = fop_pos
|
||||
|
||||
# 暂时禁用按图链接:始终全量链接 includes.binary 中的 .obj
|
||||
# 按图链接在 --clean 后 deps.txt 缺失时无法正确工作(跨包传递依赖丢失)
|
||||
# 按图编译(Phase B+)仍保留:只编译 reachable_set 中的缺失 includes
|
||||
# TODO: 待 deps.txt 生成机制完善后(如 Phase A 翻译所有 includes 的 imports),重新启用按图链接
|
||||
|
||||
# 释放 reachable_set(Phase B+ 已使用完毕)
|
||||
# 释放 reachable_set(Phase C 已使用完毕)
|
||||
if reachable_set is not None:
|
||||
stdlib.free(reachable_set)
|
||||
reachable_set = None
|
||||
|
||||
# 始终传 includes_binary_dir 给 link_objs_to_exe,由其全量收集 .obj
|
||||
# 按图链接:不传 includes_binary_dir(传 None),避免全量收集
|
||||
lret: int = BuildPipeline.link_objs_to_exe(
|
||||
final_obj_paths, obj_paths_len,
|
||||
linker_cmd, linker_flags, exe_path,
|
||||
includes_binary_dir)
|
||||
None)
|
||||
|
||||
if lret == 0:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
|
||||
+11
-19
@@ -51,9 +51,6 @@ _sha1_store_mod: bytes # 模块名数组(每个 64 字节,MAX_INCLUDES 个
|
||||
_sha1_store_rel: bytes # 相对路径数组(每个 256 字节,MAX_INCLUDES 个)
|
||||
_sha1_store_count: int # 条目数
|
||||
|
||||
# 可达集合是否不完整(1=有 includes deps.txt 缺失,Phase C 应回退全量链接)
|
||||
_g_reachable_incomplete: int
|
||||
|
||||
# includes 依赖内存存储(不依赖 deps.txt 过程文件)
|
||||
# Phase B+ 前用 declare_only 翻译所有 includes 文件,提取 _imported_modules 存入此处
|
||||
# _BuildReachableSha1Set 从此处读取依赖,不读 deps.txt
|
||||
@@ -436,7 +433,7 @@ def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> in
|
||||
#
|
||||
# Args:
|
||||
# sha1: SHA1 字符串(16 字符 + null)
|
||||
# rel_path: 相对路径(如 "lib/core/StubMerger.py",
|
||||
# rel_path: 相对路径(如 "lib/core/StubMerger.vp",
|
||||
# 不含 includes/ 前缀,与 _sha1_map.txt 格式一致)
|
||||
#
|
||||
# Returns:
|
||||
@@ -465,7 +462,7 @@ def AppendToSha1MapStore(sha1: str, rel_path: str) -> int:
|
||||
sidx_d: t.CSizeT = t.CSizeT(i) * 17
|
||||
if string.strcmp(_sha1_store_arr + sidx_d, sha1) == 0:
|
||||
return 0
|
||||
# 模块名:rel_path "lib/core/StubMerger.py" → "lib.core.StubMerger"
|
||||
# 模块名:rel_path "lib/core/StubMerger.vp" → "lib.core.StubMerger"
|
||||
full_path_buf: bytes = stdlib.malloc(string.strlen(rel_path) + 10)
|
||||
if full_path_buf is None:
|
||||
return 1
|
||||
@@ -506,11 +503,6 @@ def GetSha1StoreCount() -> int:
|
||||
return _sha1_store_count
|
||||
|
||||
|
||||
def IsReachableIncomplete() -> int:
|
||||
"""返回可达集合是否不完整(1=有 deps.txt 缺失,应回退全量链接)"""
|
||||
return _g_reachable_incomplete
|
||||
|
||||
|
||||
# ============================================================
|
||||
# PopulateIncludesDeps - 将 includes 文件的依赖存入内存
|
||||
#
|
||||
@@ -791,7 +783,7 @@ def _CommentOutOpaqueTypeInBuf(out_buf: bytes, type_name_prefix: str) -> int:
|
||||
# ============================================================
|
||||
# _is_submodule_of_imported - 检查模块名是否是已导入包的子模块
|
||||
#
|
||||
# deps.txt 只记录直接导入的模块名(如 "ast"),但包的 __init__.py
|
||||
# deps.txt 只记录直接导入的模块名(如 "ast"),但包的 __init__.vp
|
||||
# 内部 from .lexer import Lexer 会让 IR 引用 ast.lexer 子模块类型。
|
||||
# 当模块名包含 '.' 时,检查其顶层包名是否在 deps_buf 中。
|
||||
#
|
||||
@@ -1198,15 +1190,15 @@ def _LoadAndAppendTextDeclares(temp_dir: str, td_len: t.CSizeT, dep_sha1: str,
|
||||
# ============================================================
|
||||
# _PathToModuleName - 将文件路径转换为模块名
|
||||
#
|
||||
# 输入: "includes/stdio.py" 或 "includes/lib/core/Handles/HandlesType.py"
|
||||
# 输入: "includes/stdio.vp" 或 "includes/lib/core/Handles/HandlesType.vp"
|
||||
# 输出: "stdio" 或 "lib.core.Handles.HandlesType"
|
||||
# 去除 includes/ 前缀和 .py 后缀,/ 替换为 .
|
||||
# 去除 includes/ 前缀和 .vp/.py 后缀,/ 替换为 .
|
||||
# 返回 stdlib.malloc 分配的字符串,调用者负责释放
|
||||
# ============================================================
|
||||
def _PathToModuleName(path: str) -> str:
|
||||
"""将文件路径转换为模块名
|
||||
|
||||
特殊处理 __init__.py:includes/ast/__init__.py → ast(而非 ast.__init__)
|
||||
特殊处理 __init__.vp:includes/ast/__init__.vp → ast(而非 ast.__init__)
|
||||
"""
|
||||
if path is None:
|
||||
return None
|
||||
@@ -1225,10 +1217,10 @@ def _PathToModuleName(path: str) -> str:
|
||||
plen -= 3
|
||||
if plen == 0:
|
||||
return None
|
||||
# 检查是否以 /__init__ 或 \__init__ 结尾(包的 __init__.py)
|
||||
# 检查是否以 /__init__ 或 \__init__ 结尾(包的 __init__.vp)
|
||||
# /__init__ 是 9 个字符:/ _ _ i n i t _ _
|
||||
# 如果是,去掉分隔符+__init__ 后缀,模块名就是包名(如 ast/__init__ → ast)
|
||||
# 注意:顶级 __init__.py(plen=8)不会进入此分支,因为 plen > 9 才检查
|
||||
# 注意:顶级 __init__.vp(plen=8)不会进入此分支,因为 plen > 9 才检查
|
||||
# 同时支持 / 和 \ 两种分隔符(TPC 写入的路径可能混合使用)
|
||||
if plen > 9:
|
||||
tail_off: t.CSizeT = path_start + plen - 9
|
||||
@@ -1369,7 +1361,7 @@ def _AddSha1ToSet(set_buf: t.CChar | t.CPtr, count: int, sha1: str) -> int:
|
||||
# 翻译不需要的 includes(如 Test 不依赖 llvmlite,则不翻译)。
|
||||
#
|
||||
# 算法(工作列表):
|
||||
# 1. 扫描 source_dir 下的 .py 文件,解析 AST 获取 _imported_modules
|
||||
# 1. 扫描 source_dir 下的 .vp/.py 文件,解析 AST 获取 _imported_modules
|
||||
# 2. 构建 SHA1→module_name 映射(从全局内存存储器)
|
||||
# 3. 工作列表递归:模块名 → 查 SHA1 → 加入 reachable_set → 读 .deps.txt → 追加新模块名
|
||||
#
|
||||
@@ -1672,7 +1664,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
||||
# deps_str 为空字符串视为无依赖(合法情况,如叶子模块)
|
||||
else:
|
||||
# 依赖未在内存中找到
|
||||
# 按需过滤: 检查是否是 App 源文件(source_dir 下的 .py 文件)
|
||||
# 按需过滤: 检查是否是 App 源文件(source_dir 下的 .vp/.py 文件)
|
||||
# App 源文件不需要加入 reachable_set(只用于 includes 过滤),跳过
|
||||
sd_len_ff: t.CSizeT = string.strlen(source_dir)
|
||||
mb_len_ff: t.CSizeT = string.strlen(mod_buf)
|
||||
@@ -1852,7 +1844,7 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
|
||||
should_load = 1
|
||||
else:
|
||||
# 传递性依赖:deps.txt 只记录直接导入(如 ast),
|
||||
# 但包的 __init__.py 内部 from .lexer import Lexer
|
||||
# 但包的 __init__.vp 内部 from .lexer import Lexer
|
||||
# 会让 IR 引用 ast.lexer 子模块类型。
|
||||
# 检查 dep_mod_name 是否是已导入包的子模块
|
||||
# (如 ast.lexer 是 ast 的子模块)
|
||||
|
||||
@@ -5,5 +5,5 @@ from stdint import *
|
||||
# core 包入口
|
||||
#
|
||||
# 子模块通过绝对导入使用(import lib.core.X as X),
|
||||
# 此 __init__.py 不做 re-export,避免引入未使用的依赖。
|
||||
# 此 __init__.vp 不做 re-export,避免引入未使用的依赖。
|
||||
# ============================================================
|
||||
+10
-10
@@ -91,17 +91,17 @@ def main() -> int:
|
||||
|
||||
# 注册参数(与 Projectrans.py main() 一致)
|
||||
parser.add_argument("--project", None, argparse.STRING, 0, None, False,
|
||||
argparse.STORE, "project.json 路径(默认查找当前目录)")
|
||||
argparse.STORE, "project.vpj 路径(默认查找当前目录)")
|
||||
parser.add_argument("--src", None, argparse.STRING, 0, None, False,
|
||||
argparse.STORE, "源文件目录(覆盖 project.json)")
|
||||
argparse.STORE, "源文件目录(覆盖 project.vpj)")
|
||||
parser.add_argument("--temp", None, argparse.STRING, 0, None, False,
|
||||
argparse.STORE, "声明接口临时目录(覆盖 project.json)")
|
||||
argparse.STORE, "声明接口临时目录(覆盖 project.vpj)")
|
||||
parser.add_argument("--output", None, argparse.STRING, 0, None, False,
|
||||
argparse.STORE, "输出目录(覆盖 project.json)")
|
||||
argparse.STORE, "输出目录(覆盖 project.vpj)")
|
||||
parser.add_argument("--phase", None, argparse.STRING, 0, None, False,
|
||||
argparse.STORE, "阶段: 1=生成声明, 2=翻译+编译, all=全部")
|
||||
parser.add_argument("--cc", None, argparse.STRING, 0, None, False,
|
||||
argparse.STORE, "LLVM 编译器命令(覆盖 project.json)")
|
||||
argparse.STORE, "LLVM 编译器命令(覆盖 project.vpj)")
|
||||
parser.add_argument("--clean", None, argparse.BOOL, 0, None, False,
|
||||
argparse.STORE_TRUE, "清理 output 和 temp 目录")
|
||||
parser.add_argument("--run", None, argparse.BOOL, 0, None, False,
|
||||
@@ -276,7 +276,7 @@ def main() -> int:
|
||||
log.info(fb3, "phase")
|
||||
|
||||
# === Phase1: 扫描 includes(按需翻译)===
|
||||
# 对 includes 目录中每个 .py 文件,若 stub 不存在则翻译并分离 stub
|
||||
# 对 includes 目录中每个 .vp/.py 文件,若 stub 不存在则翻译并分离 stub
|
||||
if do_phase1 != 0 and Config.IncludesDir is not None:
|
||||
ph1_temp: str = Config.TempDir
|
||||
if ph1_temp is None:
|
||||
@@ -292,7 +292,7 @@ def main() -> int:
|
||||
src_path: str = args.get_str("src")
|
||||
|
||||
# === 多文件项目模式 ===
|
||||
# 当 --project 指定但 --src 未指定时,扫描 source_dir 下所有 .py 文件编译
|
||||
# 当 --project 指定但 --src 未指定时,扫描 source_dir 下所有 .vp/.py 文件编译
|
||||
if src_path is None and project is not None and Config.SourceDir is not None:
|
||||
mf_temp: str = Config.TempDir if Config.TempDir is not None else "."
|
||||
mf_output: str = Config.OutputDir if Config.OutputDir is not None else "."
|
||||
@@ -404,12 +404,12 @@ def main() -> int:
|
||||
log.banner("编译管线")
|
||||
|
||||
# module_name 用源代码内容的 SHA1(前 16 字符),与 Projectrans.py 一致
|
||||
# output_name 从文件名推导(如 test.py -> test.exe),保持可读性
|
||||
# output_name 从文件名推导(如 test.vp -> test.exe),保持可读性
|
||||
module_name: str = Utils.compute_sha1(mb, src_buf)
|
||||
if module_name is None:
|
||||
module_name = "main"
|
||||
output_name: str = "test_prog.exe"
|
||||
# 从文件名提取 output_name(去掉路径和 .py 扩展名)
|
||||
# 从文件名提取 output_name(去掉路径和 .vp/.py 扩展名)
|
||||
src_len: t.CSizeT = string.strlen(src_path)
|
||||
if src_len > 0:
|
||||
# 找到最后一个 / 或 \ 之后的部分
|
||||
@@ -423,7 +423,7 @@ def main() -> int:
|
||||
break
|
||||
if i == 0:
|
||||
base_start = 0
|
||||
# 找到 .py 扩展名
|
||||
# 找到 .vp/.py 扩展名
|
||||
base_end: t.CSizeT = src_len
|
||||
j: t.CSizeT = base_start
|
||||
while j < src_len:
|
||||
|
||||
+1
-2
@@ -3,8 +3,7 @@
|
||||
"name": "TransPyV",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"temp_dir": "./temp",
|
||||
"output_dir": "./output",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||
|
||||
Reference in new issue
Block a user