diff --git a/App/lib/StubGen/Converter.vp b/App/lib/StubGen/Converter.vp index b354e8b..f173168 100644 --- a/App/lib/StubGen/Converter.vp +++ b/App/lib/StubGen/Converter.vp @@ -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 diff --git a/App/lib/StubGen/__init__.vp b/App/lib/StubGen/__init__.vp index 5463157..6f60be0 100644 --- a/App/lib/StubGen/__init__.vp +++ b/App/lib/StubGen/__init__.vp @@ -2,5 +2,5 @@ # StubGen 包入口 # # 子模块通过绝对导入使用(import lib.StubGen.Converter as Converter), -# 此 __init__.py 不做 re-export,避免引入未使用的依赖。 +# 此 __init__.vp 不做 re-export,避免引入未使用的依赖。 # ============================================================ diff --git a/App/lib/__init__.vp b/App/lib/__init__.vp index fb867ea..d8f5f11 100644 --- a/App/lib/__init__.vp +++ b/App/lib/__init__.vp @@ -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 diff --git a/App/lib/core/Handles/HandlesAnnAssign.vp b/App/lib/core/Handles/HandlesAnnAssign.vp index 9096f84..3610471 100644 --- a/App/lib/core/Handles/HandlesAnnAssign.vp +++ b/App/lib/core/Handles/HandlesAnnAssign.vp @@ -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 diff --git a/App/lib/core/Handles/HandlesAugAssign.vp b/App/lib/core/Handles/HandlesAugAssign.vp index 31d8400..a8d471e 100644 --- a/App/lib/core/Handles/HandlesAugAssign.vp +++ b/App/lib/core/Handles/HandlesAugAssign.vp @@ -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: diff --git a/App/lib/core/Handles/HandlesClassDef.vp b/App/lib/core/Handles/HandlesClassDef.vp index 8e41ab0..802ac11 100644 --- a/App/lib/core/Handles/HandlesClassDef.vp +++ b/App/lib/core/Handles/HandlesClassDef.vp @@ -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 diff --git a/App/lib/core/Handles/HandlesExpr.vp b/App/lib/core/Handles/HandlesExpr.vp index 9b950a9..4ab24d8 100644 --- a/App/lib/core/Handles/HandlesExpr.vp +++ b/App/lib/core/Handles/HandlesExpr.vp @@ -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" 用于跨模块查找 diff --git a/App/lib/core/Handles/HandlesExprCall.vp b/App/lib/core/Handles/HandlesExprCall.vp index 7b99c5f..1d352ec 100644 --- a/App/lib/core/Handles/HandlesExprCall.vp +++ b/App/lib/core/Handles/HandlesExprCall.vp @@ -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 diff --git a/App/lib/core/Handles/HandlesFunctions.vp b/App/lib/core/Handles/HandlesFunctions.vp index 96d1abd..aa48ed8 100644 --- a/App/lib/core/Handles/HandlesFunctions.vp +++ b/App/lib/core/Handles/HandlesFunctions.vp @@ -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) diff --git a/App/lib/core/Handles/HandlesImports.vp b/App/lib/core/Handles/HandlesImports.vp index 4d9512a..0a4f8a6 100644 --- a/App/lib/core/Handles/HandlesImports.vp +++ b/App/lib/core/Handles/HandlesImports.vp @@ -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: diff --git a/App/lib/core/Handles/HandlesType.vp b/App/lib/core/Handles/HandlesType.vp index ecb4f7e..4960821 100644 --- a/App/lib/core/Handles/HandlesType.vp +++ b/App/lib/core/Handles/HandlesType.vp @@ -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 = "" stdio.printf("Traceback (most recent call last):\n") stdio.printf(' File "%s", line %d\n', file_name, lineno) - if lineno > 0 and file_name != "": + if lineno > 0 and string.strcmp(file_name, "") != 0: src_line: str = _read_source_line(file_name, lineno) if src_line is not None: stdio.printf(" %s\n", src_line) diff --git a/App/lib/core/IncludesScanner.vp b/App/lib/core/IncludesScanner.vp index c03793c..bf588b7 100644 --- a/App/lib/core/IncludesScanner.vp +++ b/App/lib/core/IncludesScanner.vp @@ -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 diff --git a/App/lib/core/Phase1.vp b/App/lib/core/Phase1.vp index 899a864..11b432e 100644 --- a/App/lib/core/Phase1.vp +++ b/App/lib/core/Phase1.vp @@ -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 diff --git a/App/lib/core/Phase2.vp b/App/lib/core/Phase2.vp index 567f08b..262aec6 100644 --- a/App/lib/core/Phase2.vp +++ b/App/lib/core/Phase2.vp @@ -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': - 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) - final_obj_paths[fop_pos] = '\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 + 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() diff --git a/App/lib/core/StubMerger.vp b/App/lib/core/StubMerger.vp index 3833d3a..02ced4c 100644 --- a/App/lib/core/StubMerger.vp +++ b/App/lib/core/StubMerger.vp @@ -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 的子模块) diff --git a/App/lib/core/__init__.vp b/App/lib/core/__init__.vp index bc8c2f7..5072cea 100644 --- a/App/lib/core/__init__.vp +++ b/App/lib/core/__init__.vp @@ -5,5 +5,5 @@ from stdint import * # core 包入口 # # 子模块通过绝对导入使用(import lib.core.X as X), -# 此 __init__.py 不做 re-export,避免引入未使用的依赖。 +# 此 __init__.vp 不做 re-export,避免引入未使用的依赖。 # ============================================================ diff --git a/App/main.vp b/App/main.vp index b747af3..58bfbb7 100644 --- a/App/main.vp +++ b/App/main.vp @@ -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: diff --git a/project.json b/project.json index bdf4f80..ce786c1 100644 --- a/project.json +++ b/project.json @@ -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"]