From 81d4ff3ac4a5badcec7213f623f63c111d0a481b Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Mon, 17 Aug 2026 07:21:00 +0800 Subject: [PATCH] =?UTF-8?q?refactor(gen):=20TypeGenMixin=20=E6=8B=86=205?= =?UTF-8?q?=20=E7=BB=84=EF=BC=88Base/CDef/CType/Resolve/Err=EF=BC=8C2643?= =?UTF-8?q?=E2=86=9244=20=E8=A1=8C=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/lib/core/Gen/Generator.vp | 8 + App/lib/core/Gen/TypeGenBase.vp | 239 +++ App/lib/core/Gen/TypeGenCDef.vp | 306 ++++ App/lib/core/Gen/TypeGenCType.vp | 330 ++++ App/lib/core/Gen/TypeGenErr.vp | 397 ++++ App/lib/core/Gen/TypeGenMixin.vp | 2609 +-------------------------- App/lib/core/Gen/TypeGenResolve.vp | 1456 +++++++++++++++ App/lib/core/Handles/HandlesType.vp | 7 +- 8 files changed, 2746 insertions(+), 2606 deletions(-) create mode 100644 App/lib/core/Gen/TypeGenBase.vp create mode 100644 App/lib/core/Gen/TypeGenCDef.vp create mode 100644 App/lib/core/Gen/TypeGenCType.vp create mode 100644 App/lib/core/Gen/TypeGenErr.vp create mode 100644 App/lib/core/Gen/TypeGenResolve.vp diff --git a/App/lib/core/Gen/Generator.vp b/App/lib/core/Gen/Generator.vp index dcfb9fb..35a336a 100644 --- a/App/lib/core/Gen/Generator.vp +++ b/App/lib/core/Gen/Generator.vp @@ -4,6 +4,11 @@ import memhub import llvmlite import lib.core.Gen.BaseGenMixin as BaseGenMixin import lib.core.Gen.TypeGenMixin as TypeGenMixin +import lib.core.Gen.TypeGenBase as TypeGenBase +import lib.core.Gen.TypeGenCDef as TypeGenCDef +import lib.core.Gen.TypeGenCType as TypeGenCType +import lib.core.Gen.TypeGenResolve as TypeGenResolve +import lib.core.Gen.TypeGenErr as TypeGenErr import lib.core.Gen.StructGenMixin as StructGenMixin import lib.core.Gen.ExprGenMixin as ExprGenMixin import lib.core.Gen.CallGenMixin as CallGenMixin @@ -45,6 +50,9 @@ import lib.core.Handles.HandlesExprCall as HandlesExprCall # ============================================================ @t.NoVTable class Generator(BaseGenMixin.BaseGenMixin, TypeGenMixin.TypeGenMixin, + TypeGenBase.TypeGenBase, TypeGenCDef.TypeGenCDef, + TypeGenCType.TypeGenCType, TypeGenResolve.TypeGenResolve, + TypeGenErr.TypeGenErr, StructGenMixin.StructGenMixin, ExprGenMixin.ExprGenMixin, CallGenMixin.CallGenMixin, CallGenBase.CallGenBase, CallGenLeafKit.CallGenLeafKit, CallGenCBuiltin.CallGenCBuiltin, diff --git a/App/lib/core/Gen/TypeGenBase.vp b/App/lib/core/Gen/TypeGenBase.vp new file mode 100644 index 0000000..ea17530 --- /dev/null +++ b/App/lib/core/Gen/TypeGenBase.vp @@ -0,0 +1,239 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import viperlib +import stdio +import stdlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprOps as HandlesExprOps +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesEnum as HandlesEnum +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.StubMerger as StubMerger +import lib.core.CompilerFactory as CompilerFactory + + + +# ============================================================ +# TypeGenBase - TypeGenMixin 拆分(阶段 D):字段 + InitTypeGen + trace/临时目录/generic 上下文 +# +# 继承 TypeGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesType 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class TypeGenBase: + """字段 + InitTypeGen + trace/临时目录/generic 上下文""" + + # --- 仿 Python Traceback 调用栈(原 _g_trace_frames/_g_trace_count) --- + TraceFrames: HandlesType.TraceFrame | t.CPtr # malloc 数组(TRACE_MAX 槽) + TraceCount: int + + # --- 全局 temp_dir(原 _g_temp_dir) --- + TempDir: str + + # --- 全局泛型特化上下文(原 _g_generic_tp_names/_g_generic_type_args) --- + GenericTpNames: list[str] | t.CPtr + GenericTypeArgs: list[str] | t.CPtr + # 嵌套安全栈:set_generic_context 压入外层值,clear_generic_context 弹出 + # 恢复(原单槽赋值:嵌套特化/泛型函数翻译退出时把外层上下文清成 None → + # 外层方法体后续的 T 替换丢失 → T.__sizeof__() NameError,VectorGenericTest + # 特化 Vector[int].__init__ 回归根因)。 + GenericCtxStack: t.CSizeT | t.CPtr # i64* 固定数组:每层 2 个槽(tp_names, type_args 指针) + GenericCtxDepth: int + + # --- 全局 CDefine 编译期常量表(原 _g_cdefine_*) --- + CDefineNames: list[str] | t.CPtr + CDefineValues: list[str] | t.CPtr + CDefineDoubleFlags: list[int] | t.CPtr + CDefineStrFlags: list[int] | t.CPtr # 1=字符串值(如 ZLIB_VERSION: t.CDefine = "1.3.2") + CDefineIsDouble: int + CDefineIsStr: int + CDefineFound: int + + # --- 跨模块 CDefine 查找缓存(perm_pool 永久分配,跨文件复用) --- + # 2026-08-14:跨模块 CDefine 查找(_lookup_cross_module_cdefine)结果缓存到 + # perm_pool,reset_to(mark2)/clear_cdefine_constants 不清除 → 跨文件复用, + # CONST_INT 递归查找只做一次(NewAstTest OOM 根因)。 + XmodCdefNames: list[str] | t.CPtr + XmodCdefValues: list[str] | t.CPtr + XmodCdefDoubleFlags: list[int] | t.CPtr + XmodCdefStrFlags: list[int] | t.CPtr + + # --- 当前模块 SHA1(原 _g_current_module_sha1) --- + CurrentModuleSha1: str + + # --- 全局 CTypedef 表(原 _g_ctypedef_*) --- + CTypedefNames: list[str] | t.CPtr + CTypedefTypeStrs: list[str] | t.CPtr + CTypedefFound: int + CTypedefResolveDepth: int + CTypedefVisiting: list[str] | t.CPtr + + # --- 常量整数表达式计算成功标志(原 _g_const_eval_ok) --- + ConstEvalOk: int + + # --- 全局当前文件名(原 _g_current_file) --- + CurrentFile: str + def InitTypeGen(self) -> int: + """初始化类型 Mixin 字段(子类构造时内联调用,规避 NoVTable 继承符号不转发)""" + if self is None: + return 1 + self.TraceFrames = None + self.TraceCount = 0 + self.TempDir = None + self.GenericTpNames = None + self.GenericTypeArgs = None + self.GenericCtxStack = None + self.GenericCtxDepth = 0 + self.CDefineNames = None + self.CDefineValues = None + self.CDefineDoubleFlags = None + self.CDefineStrFlags = None + self.CDefineIsDouble = 0 + self.CDefineIsStr = 0 + self.CDefineFound = 0 + self.XmodCdefNames = None + self.XmodCdefValues = None + self.XmodCdefDoubleFlags = None + self.XmodCdefStrFlags = None + self.CurrentModuleSha1 = None + self.CTypedefNames = None + self.CTypedefTypeStrs = None + self.CTypedefFound = 0 + self.CTypedefResolveDepth = 0 + self.CTypedefVisiting = None + self.ConstEvalOk = 0 + self.CurrentFile = None + return 0 + # ============================================================ + # P2 迁移方法(函数体来自 HandlesType.vp,全局变量改 self.字段, + # 同模块函数调用改 self.方法;签名与 HandlesType 原函数一致) + # ============================================================ + + def _ensure_trace_init(self) -> int: + """确保调用栈已初始化(懒加载,用 malloc 不依赖 pool)""" + if self.TraceFrames is not None: + return 1 + entry_size: t.CSizeT = HandlesType.TraceFrame.__sizeof__() + self.TraceFrames = CompilerFactory.get_perm_pool().alloc(entry_size * TRACE_MAX) + if self.TraceFrames is None: + return 0 + string.memset(self.TraceFrames, 0, entry_size * TRACE_MAX) + return 1 + def _get_trace_frame(self, i: int) -> HandlesType.TraceFrame | t.CPtr: + """获取第 i 个 TraceFrame 槽位""" + if self.TraceFrames is None or i < 0 or i >= TRACE_MAX: + return None + entry_size: t.CSizeT = HandlesType.TraceFrame.__sizeof__() + addr: t.CUInt64T = t.CUInt64T(self.TraceFrames) + i * entry_size + return (HandlesType.TraceFrame | t.CPtr)(t.CVoid(addr, t.CPtr)) + def push_trace(self, file_name: str, lineno: int, col_start: int = 0, col_end: int = 0): + """压入一个翻译上下文帧(进入新的翻译作用域时调用)""" + if self._ensure_trace_init() == 0: + return + if self.TraceCount >= TRACE_MAX: + return + frame: HandlesType.TraceFrame | t.CPtr = self._get_trace_frame(self.TraceCount) + if frame is None: + return + frame.file_name = file_name + frame.lineno = lineno + frame.col_start = col_start + frame.col_end = col_end + self.TraceCount += 1 + def pop_trace(self): + """弹出栈顶帧(退出翻译作用域时调用)""" + if self.TraceCount <= 0: + return + self.TraceCount -= 1 + frame: HandlesType.TraceFrame | t.CPtr = self._get_trace_frame(self.TraceCount) + if frame is not None: + frame.file_name = None + frame.lineno = 0 + frame.col_start = 0 + frame.col_end = 0 + def clear_trace(self): + """清空调用栈(每个文件翻译开始前调用)""" + i: int + for i in range(self.TraceCount): + frame: HandlesType.TraceFrame | t.CPtr = self._get_trace_frame(i) + if frame is not None: + frame.file_name = None + frame.lineno = 0 + frame.col_start = 0 + frame.col_end = 0 + self.TraceCount = 0 + def set_temp_dir(self, temp_dir: str) -> None: + """设置全局 temp_dir(每个项目编译开始时由 BuildPipeline/Phase1 设置)""" + self.TempDir = temp_dir + def get_temp_dir(self) -> str: + """获取全局 temp_dir""" + return self.TempDir + def set_current_module_sha1(self, sha1: str) -> None: + """设置当前正在编译的模块 SHA1(Phase1 在模块开始翻译前调用)""" + self.CurrentModuleSha1 = sha1 + def _dbg_check_ast_floats(self, mb: memhub.MemBuddy | t.CPtr, + tree: ast.AST | t.CPtr, tag: str): + """已移除调试插桩(占位保留签名,避免外部调用引用失败)""" + pass + def set_generic_context(self, tp_names: list[str] | t.CPtr, + type_args: list[str] | t.CPtr): + """设置泛型特化上下文(进入泛型类方法体翻译时调用),嵌套安全 + + 先压栈当前(外层)上下文,再设置新值。clear_generic_context 弹出恢复, + 避免嵌套特化/泛型函数翻译退出时清空外层上下文(T.__sizeof__() 回归根因)。 + """ + if self.GenericCtxStack is None: + self.GenericCtxStack = stdlib.malloc(8 * 2 * 32) + if self.GenericCtxStack is None: + self.GenericTpNames = tp_names + self.GenericTypeArgs = type_args + return + self.GenericCtxDepth = 0 + if self.GenericCtxDepth < 32: + self.GenericCtxStack[self.GenericCtxDepth * 2] = t.CSizeT(self.GenericTpNames) + self.GenericCtxStack[self.GenericCtxDepth * 2 + 1] = t.CSizeT(self.GenericTypeArgs) + self.GenericCtxDepth += 1 + self.GenericTpNames = tp_names + self.GenericTypeArgs = type_args + + def clear_generic_context(self): + """清除泛型特化上下文(离开泛型类方法体翻译时调用),恢复外层而非置 None""" + if self.GenericCtxDepth > 0: + self.GenericCtxDepth -= 1 + self.GenericTpNames = (list[str] | t.CPtr)(t.CVoid( + self.GenericCtxStack[self.GenericCtxDepth * 2], t.CPtr)) + self.GenericTypeArgs = (list[str] | t.CPtr)(t.CVoid( + self.GenericCtxStack[self.GenericCtxDepth * 2 + 1], t.CPtr)) + else: + self.GenericTpNames = None + self.GenericTypeArgs = None + def resolve_generic_type_name(self, name: str) -> str: + """如果 name 是泛型类型参数,返回对应的具体类型名;否则返回 name 本身 + + 用于表达式中的 T 替换(如 T.__sizeof__() → int.__sizeof__()) + """ + if name is None: + return name + if self.GenericTpNames is not None and self.GenericTypeArgs is not None: + rg_n: t.CSizeT = len(self.GenericTpNames) + rg_i: t.CSizeT + for rg_i in range(rg_n): + rg_tpn: str = self.GenericTpNames.get(rg_i) + if rg_tpn is not None and string.strcmp(name, rg_tpn) == 0: + rg_ta: str = self.GenericTypeArgs.get(rg_i) + if rg_ta is not None: + return rg_ta + return name \ No newline at end of file diff --git a/App/lib/core/Gen/TypeGenCDef.vp b/App/lib/core/Gen/TypeGenCDef.vp new file mode 100644 index 0000000..b1e11c3 --- /dev/null +++ b/App/lib/core/Gen/TypeGenCDef.vp @@ -0,0 +1,306 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import viperlib +import stdio +import stdlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprOps as HandlesExprOps +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesEnum as HandlesEnum +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.StubMerger as StubMerger +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.TypeGenBase as TypeGenBase + +# ============================================================ +# TypeGenCDef - TypeGenMixin 拆分(阶段 D):CDefine 编译期常量表(register/lookup/is/set/clear) +# +# 继承 TypeGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesType 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class TypeGenCDef(TypeGenBase.TypeGenBase): + """CDefine 编译期常量表(register/lookup/is/set/clear)""" + + def register_cdefine_constant(self, pool: memhub.MemBuddy | t.CPtr, + name: str, value: t.CInt64T) -> None: + """注册 CDefine 编译期常量到本地表 + + 值以十进制字符串存储(64 位 %lld)。大整数 CDefine(如 + sys.maxsize = 9223372036854775807)必须全精度保存,否则 %d 32 位截断 + 成 -1(0xFFFFFFFF)→ 读回 4294967295(SysLibTest maxsize FAIL 根因)。 + 0xFFFFFFFF 仍存为 "4294967295",常量生成端 const_int32 内部截断回 -1。 + """ + if self.CDefineNames is None: + self.CDefineNames = list[str](pool, 64) + self.CDefineValues = list[str](pool, 64) + self.CDefineDoubleFlags = list[int](pool, 64) + self.CDefineStrFlags = list[int](pool, 64) + self.CDefineNames.append(name) + val_buf: str = pool.alloc(32) + if val_buf is not None: + viperlib.snprintf(val_buf, 32, "%lld", value) + self.CDefineValues.append(val_buf) + else: + self.CDefineValues.append("0") + if self.CDefineDoubleFlags is not None: + self.CDefineDoubleFlags.append(0) + if self.CDefineStrFlags is not None: + self.CDefineStrFlags.append(0) + def register_cdefine_double(self, pool: memhub.MemBuddy | t.CPtr, + name: str, value: double) -> None: + """注册浮点 CDefine 编译期常量(如 U_M_PI: t.CDefine = 3.14159...) + + 值以 %f 文本存储并标记浮点,供 translate_value 返回浮点常量。 + """ + if self.CDefineNames is None: + self.CDefineNames = list[str](pool, 64) + self.CDefineValues = list[str](pool, 64) + self.CDefineDoubleFlags = list[int](pool, 64) + self.CDefineStrFlags = list[int](pool, 64) + self.CDefineNames.append(name) + val_buf: str = pool.alloc(32) + if val_buf is not None: + # 用 CRT stdio.snprintf 而非 viperlib.snprintf:viperlib 自实现格式化器的 + # %g 浮点路径有 bug(%.17g 输出错误值,如 pi 显示 3.1397985 而非 3.1415926, + # 位模式 %a 正确),会导致 CDefine 表存错文本 → lookup 生成错 LLVM 常量。 + stdio.snprintf(val_buf, 32, "%.17g", value) + self.CDefineValues.append(val_buf) + else: + self.CDefineValues.append("0") + if self.CDefineDoubleFlags is not None: + self.CDefineDoubleFlags.append(1) + if self.CDefineStrFlags is not None: + self.CDefineStrFlags.append(0) + # fail-fast:CDefine 值缓冲区分配失败必须终止编译, + if val_buf is None: + VLogger.error("CDefine 浮点值缓冲区分配失败", "CDEF-DBG") + HandlesType.fatal_error(None, "CDefine 浮点值缓冲区分配失败", "MemoryError") + def register_cdefine_string(self, pool: memhub.MemBuddy | t.CPtr, + name: str, value: str) -> None: + """注册字符串 CDefine 编译期常量(如 ZLIB_VERSION: t.CDefine = "1.3.2") + + 字符串值深拷贝到 pool(AST 节点的 str_val 可能被 pool 操作覆写, + 与浮点 CDefine 的恢复同理)。 + """ + if pool is None or name is None: + return + if value is None: + HandlesType.fatal_error(None, f"CDefine 字符串值缺失: {name}", "InternalCompilerError") + return + if self.CDefineNames is None: + self.CDefineNames = list[str](pool, 64) + self.CDefineValues = list[str](pool, 64) + self.CDefineDoubleFlags = list[int](pool, 64) + self.CDefineStrFlags = list[int](pool, 64) + self.CDefineNames.append(name) + vlen: t.CSizeT = string.strlen(value) + vcopy: str = pool.alloc(vlen + 1) + if vcopy is None: + HandlesType.fatal_error(None, f"CDefine 字符串值分配失败: {name}", "MemoryError") + return + string.strcpy(vcopy, value) + self.CDefineValues.append(vcopy) + if self.CDefineDoubleFlags is not None: + self.CDefineDoubleFlags.append(0) + if self.CDefineStrFlags is not None: + self.CDefineStrFlags.append(1) + # 同步设置"最近注册/查表结果为字符串"标志(is_cdefine_str() 读取)。 + # 跨模块字符串 CDefine 读回(_lookup_cross_module_cdefine 字符串分支只调 + # 本函数 + 尾部 set_cdefine_found,无 lookup_cdefine_string 回查)→ 若此处 + # 不设标志,属性路径 is_cdefine_str()==0 → 退化为整数分支返回 0 → + # IR 生成 inttoptr i32 0(NULL)→ 运行时报 (null-) + strlen(NULL-) 崩溃 + # (test_pyzlib.vp pyzlib.ZLIB_VERSION 根因)。 + self.CDefineIsStr = 1 + self.CDefineFound = 1 + # ============================================================ + # 跨模块 CDefine 查找缓存(perm_pool 永久分配,跨文件复用) + # ============================================================ + def register_xmod_cdefine(self, name: str, value_str: str, + is_double: int, is_str: int) -> None: + """注册跨模块 CDefine 查找结果到 perm_pool 全局缓存(跨文件复用) + + Args: + name: CDefine 常量名(如 CONST_INT) + value_str: 值文本(十进制/浮点/字符串) + is_double: 1=浮点值 + is_str: 1=字符串值 + """ + if name is None or value_str is None: + return + # 去重:同名已缓存则跳过(首次查找结果为准,CDefine 全局唯一约定) + if self.XmodCdefNames is not None: + x_n: t.CSizeT = len(self.XmodCdefNames) + x_i: t.CSizeT + for x_i in range(x_n): + x_nm: str = self.XmodCdefNames.get(x_i) + if x_nm is not None and string.strcmp(x_nm, name) == 0: + return + perm: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool() + if self.XmodCdefNames is None: + self.XmodCdefNames = list[str](perm, 64) + self.XmodCdefValues = list[str](perm, 64) + self.XmodCdefDoubleFlags = list[int](perm, 64) + self.XmodCdefStrFlags = list[int](perm, 64) + # key/value 深拷贝到 perm_pool:入参(pool.alloc 临时缓冲)在 + # reset_to(mark2) 后悬空,append 只存指针 → 必须深拷贝跨 reset 存活 + klen: t.CSizeT = string.strlen(name) + kcopy: str = perm.alloc(klen + 1) + if kcopy is None: + return + string.strcpy(kcopy, name) + vlen: t.CSizeT = string.strlen(value_str) + vcopy: str = perm.alloc(vlen + 1) + if vcopy is None: + return + string.strcpy(vcopy, value_str) + self.XmodCdefNames.append(kcopy) + self.XmodCdefValues.append(vcopy) + if self.XmodCdefDoubleFlags is not None: + self.XmodCdefDoubleFlags.append(is_double) + if self.XmodCdefStrFlags is not None: + self.XmodCdefStrFlags.append(is_str) + def lookup_xmod_cdefine(self, name: str) -> str: + """查找跨模块 CDefine 缓存,命中设置 found/is_double/is_str 标志 + + Returns: + 值文本(命中),未命中返回 None + """ + self.CDefineFound = 0 + self.CDefineIsDouble = 0 + self.CDefineIsStr = 0 + if name is None or self.XmodCdefNames is None: + return None + n: t.CSizeT = len(self.XmodCdefNames) + i: t.CSizeT + for i in range(n): + nm: str = self.XmodCdefNames.get(i) + if nm is not None and string.strcmp(nm, name) == 0: + val_str: str = self.XmodCdefValues.get(i) + if val_str is not None: + self.CDefineFound = 1 + if self.XmodCdefStrFlags is not None and self.XmodCdefStrFlags.get(i) == 1: + self.CDefineIsStr = 1 + elif self.XmodCdefDoubleFlags is not None and self.XmodCdefDoubleFlags.get(i) == 1: + self.CDefineIsDouble = 1 + return val_str + return None + def lookup_cdefine_constant(self, name: str) -> t.CInt64T: + """查找 CDefine 编译期常量 + + 返回找到的值(64 位,大整数 CDefine 如 sys.maxsize 全精度)。 + 由于 -1 是合法值(如 INVALID_HANDLE_VALUE=0xFFFFFFFF=-1), + 用全局 _g_cdefine_found 标志区分"未找到"和值为 -1。 + 调用方应在调用后检查 _g_cdefine_found。 + 浮点 CDefine 项返回整数部分(与 _g_cdefine_is_double 标志配合)。 + """ + self.CDefineFound = 0 + self.CDefineIsDouble = 0 + self.CDefineIsStr = 0 + if self.CDefineNames is None: + return 0 + n: t.CSizeT = len(self.CDefineNames) + i: t.CSizeT + for i in range(n): + nm: str = self.CDefineNames.get(i) + if nm is not None and string.strcmp(nm, name) == 0: + val_str: str = self.CDefineValues.get(i) + if val_str is not None: + self.CDefineFound = 1 + if self.CDefineStrFlags is not None and self.CDefineStrFlags.get(i) == 1: + # 字符串 CDefine(如 ZLIB_VERSION="1.3.2"):整数查询路径 + # 标记 is_str,调用方改用 lookup_cdefine_string 取字符串。 + self.CDefineIsStr = 1 + return 0 + if self.CDefineDoubleFlags is not None and self.CDefineDoubleFlags.get(i) == 1: + self.CDefineIsDouble = 1 + return string.atoll(val_str) + return string.atoll(val_str) + return 0 + def lookup_cdefine_double(self, name: str) -> double: + """查找 CDefine 编译期常量,返回 double 值(浮点/整数统一) + + 与 lookup_cdefine_constant 共享 _g_cdefine_found / _g_cdefine_is_double + (found=1 且 is_double=1 → 浮点 CDefine,应返回浮点常量)。 + """ + self.CDefineFound = 0 + self.CDefineIsDouble = 0 + self.CDefineIsStr = 0 + if self.CDefineNames is None: + return 0.0 + n: t.CSizeT = len(self.CDefineNames) + i: t.CSizeT + for i in range(n): + nm: str = self.CDefineNames.get(i) + if nm is not None and string.strcmp(nm, name) == 0: + val_str: str = self.CDefineValues.get(i) + if val_str is not None: + self.CDefineFound = 1 + if self.CDefineStrFlags is not None and self.CDefineStrFlags.get(i) == 1: + self.CDefineIsStr = 1 + return 0.0 + if self.CDefineDoubleFlags is not None and self.CDefineDoubleFlags.get(i) == 1: + self.CDefineIsDouble = 1 + ret_d: double = string.atof(val_str) + return ret_d + ret_i2: double = double(string.atoll(val_str)) + return ret_i2 + return 0.0 + def lookup_cdefine_string(self, name: str) -> str: + """查找 CDefine 编译期字符串值(found=1 且 is_str=1 时有效) + + 返回的字符串指针位于 pool 内(当前模块生命周期内有效), + 调用方应尽快用于 create_global_string 拷贝到 LLVM 常量。 + """ + self.CDefineFound = 0 + self.CDefineIsDouble = 0 + self.CDefineIsStr = 0 + if self.CDefineNames is None: + return None + n: t.CSizeT = len(self.CDefineNames) + i: t.CSizeT + for i in range(n): + nm: str = self.CDefineNames.get(i) + if nm is not None and string.strcmp(nm, name) == 0: + val_str: str = self.CDefineValues.get(i) + if val_str is not None: + self.CDefineFound = 1 + if self.CDefineStrFlags is not None and self.CDefineStrFlags.get(i) == 1: + self.CDefineIsStr = 1 + return val_str + return val_str + return None + def is_cdefine_str(self) -> int: + """检查最近一次 CDefine 查找命中的是否是字符串常量""" + return self.CDefineIsStr + def is_cdefine_double(self) -> int: + """检查最近一次 CDefine 查找命中的是否是浮点常量""" + return self.CDefineIsDouble + def is_cdefine_found(self) -> int: + """检查上次 lookup_cdefine_constant 是否找到值""" + return self.CDefineFound + def set_cdefine_found(self, val: int) -> None: + """设置 cdefine_found 标志(供跨模块查找函数使用)""" + self.CDefineFound = val + def clear_cdefine_constants(self) -> None: + """清空 CDefine 常量表(模块切换时调用)""" + self.CDefineNames = None + self.CDefineValues = None + self.CDefineDoubleFlags = None + self.CDefineStrFlags = None + self.CDefineIsStr = 0 \ No newline at end of file diff --git a/App/lib/core/Gen/TypeGenCType.vp b/App/lib/core/Gen/TypeGenCType.vp new file mode 100644 index 0000000..9c2e624 --- /dev/null +++ b/App/lib/core/Gen/TypeGenCType.vp @@ -0,0 +1,330 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import viperlib +import stdio +import stdlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprOps as HandlesExprOps +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesEnum as HandlesEnum +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.StubMerger as StubMerger +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.TypeGenBase as TypeGenBase + +# ============================================================ +# TypeGenCType - TypeGenMixin 拆分(阶段 D):CTypedef 表(register/lookup/ScanCTypedefDeclarations/_eval_const_int_expr) +# +# 继承 TypeGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesType 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class TypeGenCType(TypeGenBase.TypeGenBase): + """CTypedef 表(register/lookup/ScanCTypedefDeclarations/_eval_const_int_expr)""" + + def register_ctypedef(self, pool: memhub.MemBuddy | t.CPtr, + name: str, type_str: str) -> None: + """注册 CTypedef 到本地表 + + Args: + pool: 内存池 + name: CTypedef 名称(如 "HANDLE") + type_str: 类型表达式字符串(如 "VOIDPTR" 或 "t.CVoid | t.CPtr") + """ + if name is None or type_str is None or pool is None: + return + if self.CTypedefNames is None: + self.CTypedefNames = list[str](pool, 64) + self.CTypedefTypeStrs = list[str](pool, 64) + # 去重:若已存在同名 CTypedef,更新其类型字符串 + if self.CTypedefNames is not None: + exist_n: t.CSizeT = len(self.CTypedefNames) + ei: t.CSizeT + for ei in range(exist_n): + en: str = self.CTypedefNames.get(ei) + if en is not None and string.strcmp(en, name) == 0: + # 已存在,更新类型字符串 + self.CTypedefTypeStrs.set(ei, type_str) + return + self.CTypedefNames.append(name) + self.CTypedefTypeStrs.append(type_str) + def lookup_ctypedef(self, name: str) -> str: + """查找 CTypedef,返回类型表达式字符串 + + 返回找到的类型表达式字符串,未找到返回 None。 + 调用方应在调用后检查 _g_ctypedef_found 标志区分"未找到"和"空字符串"。 + """ + self.CTypedefFound = 0 + if name is None: + return None + if self.CTypedefNames is None: + return None + n: t.CSizeT = len(self.CTypedefNames) + i: t.CSizeT + for i in range(n): + nm: str = self.CTypedefNames.get(i) + if nm is not None and string.strcmp(nm, name) == 0: + ts: str = self.CTypedefTypeStrs.get(i) + self.CTypedefFound = 1 + return ts + return None + def is_ctypedef_found(self) -> int: + """检查上次 lookup_ctypedef 是否找到值""" + return self.CTypedefFound + def clear_ctypedefs(self) -> None: + """清空 CTypedef 表(模块切换时调用)""" + self.CTypedefNames = None + self.CTypedefTypeStrs = None + self.CTypedefResolveDepth = 0 + self.CTypedefVisiting = None + def _ctypedef_push_visiting(self, pool: memhub.MemBuddy | t.CPtr, name: str) -> int: + """将 CTypedef 名加入正在解析列表(循环检测) + + Returns: + 0=成功加入(无循环),1=检测到循环 + """ + if name is None: + return 0 + if self.CTypedefVisiting is None: + self.CTypedefVisiting = list[str](pool, 32) + if self.CTypedefVisiting is None: + return 0 + vn: t.CSizeT = len(self.CTypedefVisiting) + vi: t.CSizeT + for vi in range(vn): + vs: str = self.CTypedefVisiting.get(vi) + if vs is not None and string.strcmp(vs, name) == 0: + return 1 # 循环检测 + self.CTypedefVisiting.append(name) + return 0 + def _ctypedef_pop_visiting(self) -> None: + """从正在解析列表弹出最后一个 CTypedef 名""" + if self.CTypedefVisiting is None: + return + vn: t.CSizeT = len(self.CTypedefVisiting) + if vn > 0: + self.CTypedefVisiting.pop() + def _is_ctypedef_annotation(self, annotation: ast.AST | t.CPtr) -> int: + """检测类型注解是否为 t.CTypedef + + Args: + annotation: 类型注解 AST 节点 + + Returns: + 1=是 t.CTypedef,0=否 + """ + if annotation is None: + return 0 + if annotation.kind() != ast.ASTKind.Attribute: + return 0 + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annotation) + if at.attr is None: + return 0 + if string.strcmp(at.attr, "CTypedef") != 0: + return 0 + if at.value is None or at.value.kind() != ast.ASTKind.Name: + return 0 + mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if mod_nm.id is None: + return 0 + if string.strcmp(mod_nm.id, "t") != 0: + return 0 + return 1 + def ScanCTypedefDeclarations(self, pool: memhub.MemBuddy | t.CPtr, + tree: ast.AST | t.CPtr) -> int: + """扫描 AST 顶层节点,注册所有 NAME: t.CTypedef = Type 声明 + + 在 _translate_module_level 中、模块级变量预注册之前调用, + 确保 CTypedef 名称在类型解析时可用。 + + Args: + pool: 内存池 + tree: 模块 AST 根节点 + + Returns: + 注册的 CTypedef 数量 + """ + if pool is None or tree is None: + return 0 + ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children + if ch is None: + return 0 + n: t.CSizeT = len(ch) + count: int = 0 + i: t.CSizeT + for i in range(n): + child: ast.AST | t.CPtr = ch.get(i) + if child is None: + continue + if child.kind() != ast.ASTKind.AnnAssign: + continue + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(child) + # 检测注解是否为 t.CTypedef + if self._is_ctypedef_annotation(aa.annotation) == 0: + continue + # 提取目标名称(必须是 Name 节点) + if aa.target is None or aa.target.kind() != ast.ASTKind.Name: + continue + tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) + if tgt.id is None: + continue + # 提取类型表达式字符串(从 value AST 节点) + if aa.value is None: + continue + type_str: str = HandlesType._get_type_name_from_annotation(pool, aa.value) + if type_str is None: + continue + # 注册 CTypedef + self.register_ctypedef(pool, tgt.id, type_str) + count += 1 + return count + def _eval_const_int_expr(self, node: ast.AST | t.CPtr, + pool: memhub.MemBuddy | t.CPtr = None, + from_imports: str = None, + imported_modules: str = None) -> int: + """递归计算常量整数表达式 + + pool/from_imports/imported_modules:跨模块 CDefine 查找上下文 + (t.CArray count 引用依赖模块的 CDefine,如 SHA512_BLOCK_LEN 定义在 + hashlib/__sha512.vp,本地 CDefine 表每模块清空,需跨模块回退查找)。 + """ + if node is None: + self.ConstEvalOk = 0 + return 0 + k: int = node.kind() + + # Constant: 整数字面量 + if k == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + if cn.const_kind == ast.CONST_INT: + self.ConstEvalOk = 1 + return cn.int_val + self.ConstEvalOk = 0 + return 0 + + # Name: CDefine 常量名(本地表优先,未命中走跨模块查找) + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is None: + self.ConstEvalOk = 0 + return 0 + val: int = HandlesType.lookup_cdefine_constant(nm.id) + if HandlesType.is_cdefine_found() == 0: + # 本地表未命中:跨模块 CDefine 查找 + # 用 HandlesExpr 模块级委托(self._lookup_cross_module_cdefine 是 + # ExprGenMixin 方法,TypeGenMixin 直接调用会生成未定义引用) + if (from_imports is not None or imported_modules is not None) \ + and pool is not None: + import lib.core.Handles.HandlesExpr as HandlesExpr + x_val: int = HandlesExpr._lookup_cross_module_cdefine( + pool, nm.id, from_imports, imported_modules) + if HandlesType.is_cdefine_found() != 0: + self.ConstEvalOk = 1 + return x_val + # 定位日志:跨模块 CDefine 查找失败(t.CArray count 场景) + fb_cdf: str = VLogger.fmt_buf() + if fb_cdf is not None: + viperlib.snprintf(fb_cdf, 1024, + "[CDEF-MISS] name=%s fi=%s im=%s", + nm.id, + from_imports if from_imports is not None else "(null)", + imported_modules if imported_modules is not None else "(null)") + VLogger.error(fb_cdf, "CDEF") + self.ConstEvalOk = 0 + return 0 + self.ConstEvalOk = 1 + return val + + # Attribute: 模块限定常量名,如 hashlib.MD5_DIGEST_LEN + # (t.CArray[t.CUInt8T, hashlib.MD5_DIGEST_LEN] 的 count 是 Attribute, + # 复用跨模块 CDefine 查找:*:模块 → 源文件提取;re-export 常量由 + # _lookup_cross_module_cdefine 的 from-import 递归子模块兜底) + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at.attr is None: + self.ConstEvalOk = 0 + return 0 + if at.value is not None and at.value.kind() == ast.ASTKind.Name: + at_mod: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if at_mod.id is not None: + if (from_imports is not None or imported_modules is not None) \ + and pool is not None: + mod_len: t.CSizeT = string.strlen(at_mod.id) + fi_buf: str = pool.alloc(mod_len + 3) + if fi_buf is not None: + fi_buf[0] = '*' + fi_buf[1] = ':' + for mi in range(mod_len): + fi_buf[2 + mi] = at_mod.id[mi] + fi_buf[2 + mod_len] = '\0' + import lib.core.Handles.HandlesExpr as HandlesExpr + av: int = HandlesExpr._lookup_cross_module_cdefine( + pool, at.attr, fi_buf, imported_modules) + if HandlesType.is_cdefine_found() != 0: + self.ConstEvalOk = 1 + return av + self.ConstEvalOk = 0 + return 0 + + # BinOp: 算术/位运算 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + # 递归计算左操作数 + lv: int = self._eval_const_int_expr(bop.left, pool, from_imports, imported_modules) + if self.ConstEvalOk == 0: + return 0 + # 递归计算右操作数 + rv: int = self._eval_const_int_expr(bop.right, pool, from_imports, imported_modules) + if self.ConstEvalOk == 0: + return 0 + # 根据运算符执行计算 + if bop.op == ast.OpKind.Add: + self.ConstEvalOk = 1 + return lv + rv + if bop.op == ast.OpKind.Sub: + self.ConstEvalOk = 1 + return lv - rv + if bop.op == ast.OpKind.Mult: + self.ConstEvalOk = 1 + return lv * rv + if bop.op == ast.OpKind.Div: + # 整数常量除法:与 FloorDiv 一致(对齐 TPC ConstEvaluator L354-355) + if rv == 0: + self.ConstEvalOk = 0 + return 0 + self.ConstEvalOk = 1 + return lv // rv + if bop.op == ast.OpKind.FloorDiv: + if rv == 0: + self.ConstEvalOk = 0 + return 0 + self.ConstEvalOk = 1 + return lv // rv + if bop.op == ast.OpKind.BitOr: + self.ConstEvalOk = 1 + return lv | rv + if bop.op == ast.OpKind.BitAnd: + self.ConstEvalOk = 1 + return lv & rv + # 不支持的运算符 + self.ConstEvalOk = 0 + return 0 + + # 不支持的节点类型 + self.ConstEvalOk = 0 + return 0 \ No newline at end of file diff --git a/App/lib/core/Gen/TypeGenErr.vp b/App/lib/core/Gen/TypeGenErr.vp new file mode 100644 index 0000000..c41bcd7 --- /dev/null +++ b/App/lib/core/Gen/TypeGenErr.vp @@ -0,0 +1,397 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import viperlib +import stdio +import stdlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprOps as HandlesExprOps +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesEnum as HandlesEnum +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.StubMerger as StubMerger +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.TypeGenBase as TypeGenBase + +# ============================================================ +# TypeGenErr - TypeGenMixin 拆分(阶段 D):错误上报/源行读取/类型推断(fatal_error/infer_* 等) +# +# 继承 TypeGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesType 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class TypeGenErr(TypeGenBase.TypeGenBase): + """错误上报/源行读取/类型推断(fatal_error/infer_* 等)""" + + def _read_source_line(self, file_path: str, lineno: int) -> str: + """从源文件读取第 lineno 行内容""" + if file_path is None or lineno <= 0: + return None + f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R) + if f.closed: + return None + # 按文件实际大小分配缓冲区:固定 256KB 会截断大源文件,末尾行号读不到 → + # 误报"文件不存在或行号超出范围"(如 CallGenMixin.vp 555KB/9236 行的第 + # 8390 行)。64MB 上限防御异常超大文件整体读取。 + fsize: LONGLONG = f.size() + if fsize <= 0 or fsize > 67108864: + f.close() + return None + src_size: t.CSizeT = t.CSizeT(fsize) + buf: bytes = stdlib.malloc(src_size + 1) + if buf is None: + f.close() + return None + bytes_read: LONG = f.read_all(buf, ULONG(src_size + 1)) + f.close() + if bytes_read <= 0: + stdlib.free(buf) + return None + # 逐行查找第 lineno 行 + cur_line: int = 1 + line_start: t.CSizeT = 0 + for i in range(bytes_read): + if buf[i] == '\n': + if cur_line == lineno: + line_len: t.CSizeT = i - line_start + if line_len > 0 and buf[line_start + line_len - 1] == '\r': + line_len -= 1 + line_buf: bytes = stdlib.malloc(line_len + 1) + if line_buf is not None: + string.strncpy(line_buf, buf + line_start, line_len) + line_buf[line_len] = '\0' + stdlib.free(buf) + return line_buf + stdlib.free(buf) + return None + cur_line += 1 + line_start = i + 1 + stdlib.free(buf) + return None + def read_source_line(self, file_path: str, lineno: int) -> str: + """公开包装:从源文件读取第 lineno 行内容(供 traceback 展示)""" + return self._read_source_line(file_path, lineno) + def dump_parse_traceback(self, file_path: str): + """解析失败时以 Python 风格输出 traceback(仿 fatal_error)""" + err_line: int = ast.get_parse_err_line() + err_col: int = ast.get_parse_err_col() + err_msg: str = ast.get_parse_err_msg() + stdio.printf("Traceback (most recent call last):\n") + if file_path is None or file_path[0] == 0: + file_path = "" + if err_line > 0: + stdio.printf(' File "%s", line %d\n', file_path, err_line) + src: str = self._read_source_line(file_path, err_line) + if src is not None: + stdio.printf(" %s\n", src) + # 列标记:在出错 token 起始列下方标 ^(parser 的 col_offset 是 0-based, + # 前缀 4 空格 + err_col 个空格后落点恰好是该 token 首字符) + if err_col > 0: + stdio.printf(" ") + c: int + for c in range(err_col): + stdio.printf(" ") + stdio.printf("^\n") + stdlib.free(src) + else: + stdio.printf(' File "%s"\n', file_path) + if err_msg is None or err_msg[0] == 0: + err_msg = "语法错误" + stdio.printf("SyntaxError: %s\n", err_msg) + def fatal_error(self, node: ast.AST | t.CPtr, msg: str, + err_type: str = "SyntaxError", + col_start: int = 0, col_end: int = 0): + """以 Python 风格报错并退出(支持多帧、错误类型、列范围) + + 向后兼容:err_type/col_start/col_end 有默认值,旧调用 fatal_error(node, msg) 仍可用。 + """ + stdio.printf("Traceback (most recent call last):\n") + # 输出调用栈帧(从底到顶) + i: int + for i in range(self.TraceCount): + frame: HandlesType.TraceFrame | t.CPtr = HandlesType._get_trace_frame(i) + if frame is not None and frame.file_name is not None: + if frame.lineno > 0: + stdio.printf(' File "%s", line %d\n', frame.file_name, frame.lineno) + src: str = self._read_source_line(frame.file_name, frame.lineno) + if src is not None: + stdio.printf(" %s\n", src) + stdlib.free(src) + else: + stdio.printf(' File "%s"\n', frame.file_name) + # 输出当前帧(node 对应的位置) + lineno: int = 0 + if node is not None: + lineno = node.lineno + file_name: str = self.CurrentFile + if file_name is None: + file_name = "" + # 行号兜底:克隆/构造节点 lineno 可能为 0(如泛型特化 _clone_arguments 的 + # ast.Arg 构造器硬编码 0,astaux.vp L139)。此时回退到 trace 栈最后一个 + # 有效帧(文件+行号)作为出错位置,避免输出误导性的 "line 0"。 + if lineno <= 0 and self.TraceCount > 0: + ti_b: int = self.TraceCount - 1 + while ti_b >= 0: + tfb: HandlesType.TraceFrame | t.CPtr = HandlesType._get_trace_frame(ti_b) + if tfb is not None and tfb.file_name is not None and tfb.lineno > 0: + file_name = tfb.file_name + lineno = tfb.lineno + break + ti_b -= 1 + # 行号合理性防御:先读取该行源码,验证 node.lineno 是否落在当前文件内。 + # 若读不到(文件不存在或行号超出范围),说明文件/行号归属不可信 + # (如 AST 树被内存复用/串扰后跨文件报错),打印警告而非误导性行号。 + src_line: str = None + line_ok: int = 1 + if lineno > 0 and string.strcmp(file_name, "") != 0: + src_line = self._read_source_line(file_name, lineno) + if src_line is None: + line_ok = 0 + if line_ok == 0: + stdio.printf(' File "%s", line %d (!! 无法读取该行源码:文件不存在或行号超出范围,错误可能来自被复用的 AST 树,请以错误消息为准)\n', + file_name, lineno) + else: + stdio.printf(' File "%s", line %d\n', file_name, lineno) + if src_line is not None: + stdio.printf(" %s\n", src_line) + # 列范围标记:在源代码行下方用 ^ 标记出错范围 + if col_start > 0 and col_end >= col_start: + stdio.printf(" ") + j: int + for j in range(col_end): + if j >= col_start - 1 and j < col_end: + stdio.printf("^") + else: + stdio.printf(" ") + stdio.printf("\n") + stdlib.free(src_line) + # 输出错误类型 + 消息 + if err_type is None or err_type[0] == 0: + err_type = "SyntaxError" + stdio.printf("%s: %s\n", err_type, msg) + sys.exit(1) + + def fatal_type_error(self, node: ast.AST | t.CPtr, msg: str, + col_start: int = 0, col_end: int = 0): + """以 Python 风格报错并退出(TypeError 版本)""" + self.fatal_error(node, msg, "TypeError", col_start, col_end) + def try_extract_callable_ret(self, pool: memhub.MemBuddy | t.CPtr, + annot: ast.AST | t.CPtr, + imported_modules: str, + from_imports: str, + trans: HT.Translator | t.CPtr) -> llvmlite.LLVMType | t.CPtr: + """提取 t.Callable 注解的返回类型 LLVMType;非 Callable 注解返回 None""" + if annot is None or annot.kind() != ast.ASTKind.Subscript: + return None + sub_cr: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot) + if sub_cr.value is None or sub_cr.value.kind() != ast.ASTKind.Attribute: + return None + at_cr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sub_cr.value) + if at_cr.attr is None or string.strcmp(at_cr.attr, "Callable") != 0: + return None + # slice 必须是 Tuple(elts=[args_list, ret_node]) + if sub_cr.slice is None or sub_cr.slice.kind() != ast.ASTKind.Tuple: + return None + tp_cr: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub_cr.slice) + if tp_cr.elts is None or len(tp_cr.elts) != 2: + return None + ret_node_cr: ast.AST | t.CPtr = tp_cr.elts.get(1) + if ret_node_cr is None: + return None + return HandlesType.resolve_annotation_type(pool, ret_node_cr, imported_modules, from_imports, trans) + def has_decorator_marker(self, node: ast.AST | t.CPtr, + marker_name: str) -> int: + """检测类型注解中是否包含指定的装饰器标记""" + if node is None or marker_name is None: + return 0 + + k: int = node.kind() + + # Attribute 节点: t.CExtern, t.State, t.CExport, t.CInline + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at.attr is not None: + if string.strcmp(at.attr, marker_name) == 0: + return 1 + return 0 + + # BinOp 节点: int | t.CExtern(递归检测左右子节点) + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if self.has_decorator_marker(bop.left, marker_name) != 0: + return 1 + if self.has_decorator_marker(bop.right, marker_name) != 0: + return 1 + return 0 + + return 0 + def is_pass_body(self, body: list[ast.AST | t.CPtr] | t.CPtr) -> int: + """检测函数体是否为 pass(空体或仅含 pass 语句)""" + if body is None: + return 1 + bn: t.CSizeT = len(body) + if bn == 0: + return 1 + if bn == 1: + stmt: ast.AST | t.CPtr = body.get(0) + if stmt is not None and stmt.kind() == ast.ASTKind.Pass: + return 1 + return 0 + def get_llvm_type_bits(self, ty: llvmlite.LLVMType | t.CPtr) -> int: + """获取 LLVM 整数类型的位宽,非整数类型返回 0""" + if ty is None: + return 0 + match ty: + case llvmlite.LLVMType.Int(bits): + return bits + case _: + return 0 + def infer_expr_type(self, pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr, + param_types: str) -> llvmlite.LLVMType | t.CPtr: + """推断表达式的 LLVM 类型 + + param_types 格式: "name:bits,name:bits,..." + """ + if node is None: + return llvmlite.Int32(pool) + + k: int = node.kind() + + if k == ast.ASTKind.Constant: + return llvmlite.Int32(pool) + + elif k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is not None and param_types is not None: + # 在 param_types 中查找: "name:bits" 格式 + search_key: str = pool.alloc(64) + if search_key is not None: + viperlib.snprintf(search_key, 64, "%s:", nm.id) + found: str = string.strstr(param_types, search_key) + if found is not None: + colon_pos: t.CSizeT = string.strlen(nm.id) + 1 + bits_str: str = found + colon_pos + bits: int = 0 + for bi in range(4): + ch: t.CChar = bits_str[bi] + if ch >= '0' and ch <= '9': + bits = bits * 10 + (ch - '0') + else: + break + if bits == 64: + return llvmlite.Int64(pool) + elif bits == 16: + return llvmlite.Int16(pool) + elif bits == 8: + return llvmlite.Int8(pool) + return llvmlite.Int32(pool) + + elif k == ast.ASTKind.BinOp: + binop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + lhs_ty: llvmlite.LLVMType | t.CPtr = self.infer_expr_type( + pool, binop.left, param_types) + rhs_ty: llvmlite.LLVMType | t.CPtr = self.infer_expr_type( + pool, binop.right, param_types) + lhs_bits: int = self.get_llvm_type_bits(lhs_ty) + rhs_bits: int = self.get_llvm_type_bits(rhs_ty) + if lhs_bits >= rhs_bits: + return lhs_ty + return rhs_ty + + return llvmlite.Int32(pool) + def infer_return_type(self, pool: memhub.MemBuddy | t.CPtr, + body: list[ast.AST | t.CPtr] | t.CPtr, + param_types: str) -> llvmlite.LLVMType | t.CPtr: + """扫描函数体中的 return 语句,推断返回类型""" + if body is None: + return llvmlite.Int32(pool) + + ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + bn: t.CSizeT = len(body) + for bi in range(bn): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None and stmt.kind() == ast.ASTKind.Return: + rt: ast.Return | t.CPtr = (ast.Return | t.CPtr)(stmt) + if rt.value is not None: + expr_ty: llvmlite.LLVMType | t.CPtr = self.infer_expr_type( + pool, rt.value, param_types) + if expr_ty is not None: + cur_bits: int = self.get_llvm_type_bits(ret_ty) + new_bits: int = self.get_llvm_type_bits(expr_ty) + if new_bits > cur_bits: + ret_ty = expr_ty + return ret_ty + def build_param_types_str(self, pool: memhub.MemBuddy | t.CPtr, + args_node: ast.AST | t.CPtr) -> str: + """构建参数类型编码字符串 "name:bits,name:bits,..." """ + if args_node is None: + return None + ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if ags.args is None: + return None + alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args + an: t.CSizeT = len(alist) + if an == 0: + return None + + buf_size: t.CSizeT = an * 32 + 1 + buf: str = pool.alloc(buf_size) + if buf is None: + return None + buf[0] = '\0' + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + for ai in range(an): + arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) + if arg is not None and arg.arg is not None: + param_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if arg.annotation is not None: + # 直接调用 map_t_type 解析 Attribute 注解 + if arg.annotation.kind() == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg.annotation) + if at.attr is not None: + resolved: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, at.attr) + if resolved is not None: + param_ty = resolved + bits: int = self.get_llvm_type_bits(param_ty) + if bits == 0: + bits = 32 + tmp: str = pool.alloc(32) + if tmp is not None: + viperlib.snprintf(tmp, 32, "%s:%d", arg.arg, bits) + if ai > 0: + self._strappend(buf, buf_size, ",") + self._strappend(buf, buf_size, tmp) + return buf + def _strappend(self, dst: str, dst_size: t.CSizeT, src: str): + """将 src 追加到 dst 末尾""" + if dst is None or src is None: + return + dlen: t.CSizeT = string.strlen(dst) + slen: t.CSizeT = string.strlen(src) + remain: t.CSizeT = dst_size - dlen + if remain <= 0: + return + # 内联 min(slen, remain - 1) 避免 builtin min 未定义(TransPyV 无 builtin min) + limit: t.CSizeT = slen + cap: t.CSizeT = remain - 1 + if cap < limit: + limit = cap + for i in range(limit): + dst[dlen + i] = src[i] + dst[dlen + i] = '\0' \ No newline at end of file diff --git a/App/lib/core/Gen/TypeGenMixin.vp b/App/lib/core/Gen/TypeGenMixin.vp index 90b1be9..0be0f84 100644 --- a/App/lib/core/Gen/TypeGenMixin.vp +++ b/App/lib/core/Gen/TypeGenMixin.vp @@ -16,19 +16,14 @@ import lib.core.Handles.HandlesImports as HandlesImports import lib.core.Handles.HandlesStruct as HandlesStruct import lib.core.Handles.HandlesEnum as HandlesEnum import lib.core.Handles.HandlesType as HandlesType +import lib.core.Gen.TypeGenBase as TypeGenBase # ============================================================ # TypeGenMixin - 类型映射与解析 Mixin(对象化 P2,wiki/14-oo-refactor.md) # -# 从 HandlesType.vp 迁移: -# 全局状态(_g_trace_*/_g_temp_dir/_g_cdefine_*/_g_ctypedef_*/...)→ 本类字段 -# 模块级函数(map_t_type/resolve_annotation_type/...)→ 本类方法 -# -# 迁移原则(P2 阶段,行为零变化): -# 1. 方法保留原函数签名(含 pool 首参),仅函数体内的全局变量改为 self.字段 -# 2. HandlesType.vp 原函数保留为"一行委托":延迟 import Gen 取全局单例 → 调本类方法 -# 3. P4/P5 签名瘦身时再去 pool 参数、改用 self.Pool +# 500~1500 行/文件架构重构阶段 D:全部方法已拆至 +# TypeGenBase/CDef/CType/Resolve/Err,本文件保留类声明(Generator 继承链入口)。 # # @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整,无 vtable 开销)。 # ============================================================ @@ -45,2599 +40,5 @@ MAX_CTYPEDEF_DEPTH: t.CDefine = 10 # TypeGenMixin - 类型映射/注解解析/编译期常量表/错误上报 # ============================================================ @t.NoVTable -class TypeGenMixin: - """类型映射与解析 Mixin(状态从 HandlesType 全局变量迁入)""" - - # --- 仿 Python Traceback 调用栈(原 _g_trace_frames/_g_trace_count) --- - TraceFrames: HandlesType.TraceFrame | t.CPtr # malloc 数组(TRACE_MAX 槽) - TraceCount: int - - # --- 全局 temp_dir(原 _g_temp_dir) --- - TempDir: str - - # --- 全局泛型特化上下文(原 _g_generic_tp_names/_g_generic_type_args) --- - GenericTpNames: list[str] | t.CPtr - GenericTypeArgs: list[str] | t.CPtr - # 嵌套安全栈:set_generic_context 压入外层值,clear_generic_context 弹出 - # 恢复(原单槽赋值:嵌套特化/泛型函数翻译退出时把外层上下文清成 None → - # 外层方法体后续的 T 替换丢失 → T.__sizeof__() NameError,VectorGenericTest - # 特化 Vector[int].__init__ 回归根因)。 - GenericCtxStack: t.CSizeT | t.CPtr # i64* 固定数组:每层 2 个槽(tp_names, type_args 指针) - GenericCtxDepth: int - - # --- 全局 CDefine 编译期常量表(原 _g_cdefine_*) --- - CDefineNames: list[str] | t.CPtr - CDefineValues: list[str] | t.CPtr - CDefineDoubleFlags: list[int] | t.CPtr - CDefineStrFlags: list[int] | t.CPtr # 1=字符串值(如 ZLIB_VERSION: t.CDefine = "1.3.2") - CDefineIsDouble: int - CDefineIsStr: int - CDefineFound: int - - # --- 跨模块 CDefine 查找缓存(perm_pool 永久分配,跨文件复用) --- - # 2026-08-14:跨模块 CDefine 查找(_lookup_cross_module_cdefine)结果缓存到 - # perm_pool,reset_to(mark2)/clear_cdefine_constants 不清除 → 跨文件复用, - # CONST_INT 递归查找只做一次(NewAstTest OOM 根因)。 - XmodCdefNames: list[str] | t.CPtr - XmodCdefValues: list[str] | t.CPtr - XmodCdefDoubleFlags: list[int] | t.CPtr - XmodCdefStrFlags: list[int] | t.CPtr - - # --- 当前模块 SHA1(原 _g_current_module_sha1) --- - CurrentModuleSha1: str - - # --- 全局 CTypedef 表(原 _g_ctypedef_*) --- - CTypedefNames: list[str] | t.CPtr - CTypedefTypeStrs: list[str] | t.CPtr - CTypedefFound: int - CTypedefResolveDepth: int - CTypedefVisiting: list[str] | t.CPtr - - # --- 常量整数表达式计算成功标志(原 _g_const_eval_ok) --- - ConstEvalOk: int - - # --- 全局当前文件名(原 _g_current_file) --- - CurrentFile: str - - def InitTypeGen(self) -> int: - """初始化类型 Mixin 字段(子类构造时内联调用,规避 NoVTable 继承符号不转发)""" - if self is None: - return 1 - self.TraceFrames = None - self.TraceCount = 0 - self.TempDir = None - self.GenericTpNames = None - self.GenericTypeArgs = None - self.GenericCtxStack = None - self.GenericCtxDepth = 0 - self.CDefineNames = None - self.CDefineValues = None - self.CDefineDoubleFlags = None - self.CDefineStrFlags = None - self.CDefineIsDouble = 0 - self.CDefineIsStr = 0 - self.CDefineFound = 0 - self.XmodCdefNames = None - self.XmodCdefValues = None - self.XmodCdefDoubleFlags = None - self.XmodCdefStrFlags = None - self.CurrentModuleSha1 = None - self.CTypedefNames = None - self.CTypedefTypeStrs = None - self.CTypedefFound = 0 - self.CTypedefResolveDepth = 0 - self.CTypedefVisiting = None - self.ConstEvalOk = 0 - self.CurrentFile = None - return 0 - - # ============================================================ - # P2 迁移方法(函数体来自 HandlesType.vp,全局变量改 self.字段, - # 同模块函数调用改 self.方法;签名与 HandlesType 原函数一致) - # ============================================================ - - def _ensure_trace_init(self) -> int: - """确保调用栈已初始化(懒加载,用 malloc 不依赖 pool)""" - if self.TraceFrames is not None: - return 1 - entry_size: t.CSizeT = HandlesType.TraceFrame.__sizeof__() - self.TraceFrames = CompilerFactory.get_perm_pool().alloc(entry_size * TRACE_MAX) - if self.TraceFrames is None: - return 0 - string.memset(self.TraceFrames, 0, entry_size * TRACE_MAX) - return 1 - - def _get_trace_frame(self, i: int) -> HandlesType.TraceFrame | t.CPtr: - """获取第 i 个 TraceFrame 槽位""" - if self.TraceFrames is None or i < 0 or i >= TRACE_MAX: - return None - entry_size: t.CSizeT = HandlesType.TraceFrame.__sizeof__() - addr: t.CUInt64T = t.CUInt64T(self.TraceFrames) + i * entry_size - return (HandlesType.TraceFrame | t.CPtr)(t.CVoid(addr, t.CPtr)) - - def push_trace(self, file_name: str, lineno: int, col_start: int = 0, col_end: int = 0): - """压入一个翻译上下文帧(进入新的翻译作用域时调用)""" - if self._ensure_trace_init() == 0: - return - if self.TraceCount >= TRACE_MAX: - return - frame: HandlesType.TraceFrame | t.CPtr = self._get_trace_frame(self.TraceCount) - if frame is None: - return - frame.file_name = file_name - frame.lineno = lineno - frame.col_start = col_start - frame.col_end = col_end - self.TraceCount += 1 - - def pop_trace(self): - """弹出栈顶帧(退出翻译作用域时调用)""" - if self.TraceCount <= 0: - return - self.TraceCount -= 1 - frame: HandlesType.TraceFrame | t.CPtr = self._get_trace_frame(self.TraceCount) - if frame is not None: - frame.file_name = None - frame.lineno = 0 - frame.col_start = 0 - frame.col_end = 0 - - def clear_trace(self): - """清空调用栈(每个文件翻译开始前调用)""" - i: int - for i in range(self.TraceCount): - frame: HandlesType.TraceFrame | t.CPtr = self._get_trace_frame(i) - if frame is not None: - frame.file_name = None - frame.lineno = 0 - frame.col_start = 0 - frame.col_end = 0 - self.TraceCount = 0 - - def set_temp_dir(self, temp_dir: str) -> None: - """设置全局 temp_dir(每个项目编译开始时由 BuildPipeline/Phase1 设置)""" - self.TempDir = temp_dir - - def get_temp_dir(self) -> str: - """获取全局 temp_dir""" - return self.TempDir - - def set_current_module_sha1(self, sha1: str) -> None: - """设置当前正在编译的模块 SHA1(Phase1 在模块开始翻译前调用)""" - self.CurrentModuleSha1 = sha1 - - def _dbg_check_ast_floats(self, mb: memhub.MemBuddy | t.CPtr, - tree: ast.AST | t.CPtr, tag: str): - """已移除调试插桩(占位保留签名,避免外部调用引用失败)""" - pass - - def register_cdefine_constant(self, pool: memhub.MemBuddy | t.CPtr, - name: str, value: t.CInt64T) -> None: - """注册 CDefine 编译期常量到本地表 - - 值以十进制字符串存储(64 位 %lld)。大整数 CDefine(如 - sys.maxsize = 9223372036854775807)必须全精度保存,否则 %d 32 位截断 - 成 -1(0xFFFFFFFF)→ 读回 4294967295(SysLibTest maxsize FAIL 根因)。 - 0xFFFFFFFF 仍存为 "4294967295",常量生成端 const_int32 内部截断回 -1。 - """ - if self.CDefineNames is None: - self.CDefineNames = list[str](pool, 64) - self.CDefineValues = list[str](pool, 64) - self.CDefineDoubleFlags = list[int](pool, 64) - self.CDefineStrFlags = list[int](pool, 64) - self.CDefineNames.append(name) - val_buf: str = pool.alloc(32) - if val_buf is not None: - viperlib.snprintf(val_buf, 32, "%lld", value) - self.CDefineValues.append(val_buf) - else: - self.CDefineValues.append("0") - if self.CDefineDoubleFlags is not None: - self.CDefineDoubleFlags.append(0) - if self.CDefineStrFlags is not None: - self.CDefineStrFlags.append(0) - - def register_cdefine_double(self, pool: memhub.MemBuddy | t.CPtr, - name: str, value: double) -> None: - """注册浮点 CDefine 编译期常量(如 U_M_PI: t.CDefine = 3.14159...) - - 值以 %f 文本存储并标记浮点,供 translate_value 返回浮点常量。 - """ - if self.CDefineNames is None: - self.CDefineNames = list[str](pool, 64) - self.CDefineValues = list[str](pool, 64) - self.CDefineDoubleFlags = list[int](pool, 64) - self.CDefineStrFlags = list[int](pool, 64) - self.CDefineNames.append(name) - val_buf: str = pool.alloc(32) - if val_buf is not None: - # 用 CRT stdio.snprintf 而非 viperlib.snprintf:viperlib 自实现格式化器的 - # %g 浮点路径有 bug(%.17g 输出错误值,如 pi 显示 3.1397985 而非 3.1415926, - # 位模式 %a 正确),会导致 CDefine 表存错文本 → lookup 生成错 LLVM 常量。 - stdio.snprintf(val_buf, 32, "%.17g", value) - self.CDefineValues.append(val_buf) - else: - self.CDefineValues.append("0") - if self.CDefineDoubleFlags is not None: - self.CDefineDoubleFlags.append(1) - if self.CDefineStrFlags is not None: - self.CDefineStrFlags.append(0) - # fail-fast:CDefine 值缓冲区分配失败必须终止编译, - if val_buf is None: - VLogger.error("CDefine 浮点值缓冲区分配失败", "CDEF-DBG") - HandlesType.fatal_error(None, "CDefine 浮点值缓冲区分配失败", "MemoryError") - - def register_cdefine_string(self, pool: memhub.MemBuddy | t.CPtr, - name: str, value: str) -> None: - """注册字符串 CDefine 编译期常量(如 ZLIB_VERSION: t.CDefine = "1.3.2") - - 字符串值深拷贝到 pool(AST 节点的 str_val 可能被 pool 操作覆写, - 与浮点 CDefine 的恢复同理)。 - """ - if pool is None or name is None: - return - if value is None: - HandlesType.fatal_error(None, f"CDefine 字符串值缺失: {name}", "InternalCompilerError") - return - if self.CDefineNames is None: - self.CDefineNames = list[str](pool, 64) - self.CDefineValues = list[str](pool, 64) - self.CDefineDoubleFlags = list[int](pool, 64) - self.CDefineStrFlags = list[int](pool, 64) - self.CDefineNames.append(name) - vlen: t.CSizeT = string.strlen(value) - vcopy: str = pool.alloc(vlen + 1) - if vcopy is None: - HandlesType.fatal_error(None, f"CDefine 字符串值分配失败: {name}", "MemoryError") - return - string.strcpy(vcopy, value) - self.CDefineValues.append(vcopy) - if self.CDefineDoubleFlags is not None: - self.CDefineDoubleFlags.append(0) - if self.CDefineStrFlags is not None: - self.CDefineStrFlags.append(1) - # 同步设置"最近注册/查表结果为字符串"标志(is_cdefine_str() 读取)。 - # 跨模块字符串 CDefine 读回(_lookup_cross_module_cdefine 字符串分支只调 - # 本函数 + 尾部 set_cdefine_found,无 lookup_cdefine_string 回查)→ 若此处 - # 不设标志,属性路径 is_cdefine_str()==0 → 退化为整数分支返回 0 → - # IR 生成 inttoptr i32 0(NULL)→ 运行时报 (null-) + strlen(NULL-) 崩溃 - # (test_pyzlib.vp pyzlib.ZLIB_VERSION 根因)。 - self.CDefineIsStr = 1 - self.CDefineFound = 1 - - # ============================================================ - # 跨模块 CDefine 查找缓存(perm_pool 永久分配,跨文件复用) - # ============================================================ - def register_xmod_cdefine(self, name: str, value_str: str, - is_double: int, is_str: int) -> None: - """注册跨模块 CDefine 查找结果到 perm_pool 全局缓存(跨文件复用) - - Args: - name: CDefine 常量名(如 CONST_INT) - value_str: 值文本(十进制/浮点/字符串) - is_double: 1=浮点值 - is_str: 1=字符串值 - """ - if name is None or value_str is None: - return - # 去重:同名已缓存则跳过(首次查找结果为准,CDefine 全局唯一约定) - if self.XmodCdefNames is not None: - x_n: t.CSizeT = len(self.XmodCdefNames) - x_i: t.CSizeT - for x_i in range(x_n): - x_nm: str = self.XmodCdefNames.get(x_i) - if x_nm is not None and string.strcmp(x_nm, name) == 0: - return - perm: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool() - if self.XmodCdefNames is None: - self.XmodCdefNames = list[str](perm, 64) - self.XmodCdefValues = list[str](perm, 64) - self.XmodCdefDoubleFlags = list[int](perm, 64) - self.XmodCdefStrFlags = list[int](perm, 64) - # key/value 深拷贝到 perm_pool:入参(pool.alloc 临时缓冲)在 - # reset_to(mark2) 后悬空,append 只存指针 → 必须深拷贝跨 reset 存活 - klen: t.CSizeT = string.strlen(name) - kcopy: str = perm.alloc(klen + 1) - if kcopy is None: - return - string.strcpy(kcopy, name) - vlen: t.CSizeT = string.strlen(value_str) - vcopy: str = perm.alloc(vlen + 1) - if vcopy is None: - return - string.strcpy(vcopy, value_str) - self.XmodCdefNames.append(kcopy) - self.XmodCdefValues.append(vcopy) - if self.XmodCdefDoubleFlags is not None: - self.XmodCdefDoubleFlags.append(is_double) - if self.XmodCdefStrFlags is not None: - self.XmodCdefStrFlags.append(is_str) - - def lookup_xmod_cdefine(self, name: str) -> str: - """查找跨模块 CDefine 缓存,命中设置 found/is_double/is_str 标志 - - Returns: - 值文本(命中),未命中返回 None - """ - self.CDefineFound = 0 - self.CDefineIsDouble = 0 - self.CDefineIsStr = 0 - if name is None or self.XmodCdefNames is None: - return None - n: t.CSizeT = len(self.XmodCdefNames) - i: t.CSizeT - for i in range(n): - nm: str = self.XmodCdefNames.get(i) - if nm is not None and string.strcmp(nm, name) == 0: - val_str: str = self.XmodCdefValues.get(i) - if val_str is not None: - self.CDefineFound = 1 - if self.XmodCdefStrFlags is not None and self.XmodCdefStrFlags.get(i) == 1: - self.CDefineIsStr = 1 - elif self.XmodCdefDoubleFlags is not None and self.XmodCdefDoubleFlags.get(i) == 1: - self.CDefineIsDouble = 1 - return val_str - return None - - def lookup_cdefine_constant(self, name: str) -> t.CInt64T: - """查找 CDefine 编译期常量 - - 返回找到的值(64 位,大整数 CDefine 如 sys.maxsize 全精度)。 - 由于 -1 是合法值(如 INVALID_HANDLE_VALUE=0xFFFFFFFF=-1), - 用全局 _g_cdefine_found 标志区分"未找到"和值为 -1。 - 调用方应在调用后检查 _g_cdefine_found。 - 浮点 CDefine 项返回整数部分(与 _g_cdefine_is_double 标志配合)。 - """ - self.CDefineFound = 0 - self.CDefineIsDouble = 0 - self.CDefineIsStr = 0 - if self.CDefineNames is None: - return 0 - n: t.CSizeT = len(self.CDefineNames) - i: t.CSizeT - for i in range(n): - nm: str = self.CDefineNames.get(i) - if nm is not None and string.strcmp(nm, name) == 0: - val_str: str = self.CDefineValues.get(i) - if val_str is not None: - self.CDefineFound = 1 - if self.CDefineStrFlags is not None and self.CDefineStrFlags.get(i) == 1: - # 字符串 CDefine(如 ZLIB_VERSION="1.3.2"):整数查询路径 - # 标记 is_str,调用方改用 lookup_cdefine_string 取字符串。 - self.CDefineIsStr = 1 - return 0 - if self.CDefineDoubleFlags is not None and self.CDefineDoubleFlags.get(i) == 1: - self.CDefineIsDouble = 1 - return string.atoll(val_str) - return string.atoll(val_str) - return 0 - - def lookup_cdefine_double(self, name: str) -> double: - """查找 CDefine 编译期常量,返回 double 值(浮点/整数统一) - - 与 lookup_cdefine_constant 共享 _g_cdefine_found / _g_cdefine_is_double - (found=1 且 is_double=1 → 浮点 CDefine,应返回浮点常量)。 - """ - self.CDefineFound = 0 - self.CDefineIsDouble = 0 - self.CDefineIsStr = 0 - if self.CDefineNames is None: - return 0.0 - n: t.CSizeT = len(self.CDefineNames) - i: t.CSizeT - for i in range(n): - nm: str = self.CDefineNames.get(i) - if nm is not None and string.strcmp(nm, name) == 0: - val_str: str = self.CDefineValues.get(i) - if val_str is not None: - self.CDefineFound = 1 - if self.CDefineStrFlags is not None and self.CDefineStrFlags.get(i) == 1: - self.CDefineIsStr = 1 - return 0.0 - if self.CDefineDoubleFlags is not None and self.CDefineDoubleFlags.get(i) == 1: - self.CDefineIsDouble = 1 - ret_d: double = string.atof(val_str) - return ret_d - ret_i2: double = double(string.atoll(val_str)) - return ret_i2 - return 0.0 - - def lookup_cdefine_string(self, name: str) -> str: - """查找 CDefine 编译期字符串值(found=1 且 is_str=1 时有效) - - 返回的字符串指针位于 pool 内(当前模块生命周期内有效), - 调用方应尽快用于 create_global_string 拷贝到 LLVM 常量。 - """ - self.CDefineFound = 0 - self.CDefineIsDouble = 0 - self.CDefineIsStr = 0 - if self.CDefineNames is None: - return None - n: t.CSizeT = len(self.CDefineNames) - i: t.CSizeT - for i in range(n): - nm: str = self.CDefineNames.get(i) - if nm is not None and string.strcmp(nm, name) == 0: - val_str: str = self.CDefineValues.get(i) - if val_str is not None: - self.CDefineFound = 1 - if self.CDefineStrFlags is not None and self.CDefineStrFlags.get(i) == 1: - self.CDefineIsStr = 1 - return val_str - return val_str - return None - - def is_cdefine_str(self) -> int: - """检查最近一次 CDefine 查找命中的是否是字符串常量""" - return self.CDefineIsStr - - def is_cdefine_double(self) -> int: - """检查最近一次 CDefine 查找命中的是否是浮点常量""" - return self.CDefineIsDouble - - def is_cdefine_found(self) -> int: - """检查上次 lookup_cdefine_constant 是否找到值""" - return self.CDefineFound - - def set_cdefine_found(self, val: int) -> None: - """设置 cdefine_found 标志(供跨模块查找函数使用)""" - self.CDefineFound = val - - def clear_cdefine_constants(self) -> None: - """清空 CDefine 常量表(模块切换时调用)""" - self.CDefineNames = None - self.CDefineValues = None - self.CDefineDoubleFlags = None - self.CDefineStrFlags = None - self.CDefineIsStr = 0 - - def register_ctypedef(self, pool: memhub.MemBuddy | t.CPtr, - name: str, type_str: str) -> None: - """注册 CTypedef 到本地表 - - Args: - pool: 内存池 - name: CTypedef 名称(如 "HANDLE") - type_str: 类型表达式字符串(如 "VOIDPTR" 或 "t.CVoid | t.CPtr") - """ - if name is None or type_str is None or pool is None: - return - if self.CTypedefNames is None: - self.CTypedefNames = list[str](pool, 64) - self.CTypedefTypeStrs = list[str](pool, 64) - # 去重:若已存在同名 CTypedef,更新其类型字符串 - if self.CTypedefNames is not None: - exist_n: t.CSizeT = len(self.CTypedefNames) - ei: t.CSizeT - for ei in range(exist_n): - en: str = self.CTypedefNames.get(ei) - if en is not None and string.strcmp(en, name) == 0: - # 已存在,更新类型字符串 - self.CTypedefTypeStrs.set(ei, type_str) - return - self.CTypedefNames.append(name) - self.CTypedefTypeStrs.append(type_str) - - def lookup_ctypedef(self, name: str) -> str: - """查找 CTypedef,返回类型表达式字符串 - - 返回找到的类型表达式字符串,未找到返回 None。 - 调用方应在调用后检查 _g_ctypedef_found 标志区分"未找到"和"空字符串"。 - """ - self.CTypedefFound = 0 - if name is None: - return None - if self.CTypedefNames is None: - return None - n: t.CSizeT = len(self.CTypedefNames) - i: t.CSizeT - for i in range(n): - nm: str = self.CTypedefNames.get(i) - if nm is not None and string.strcmp(nm, name) == 0: - ts: str = self.CTypedefTypeStrs.get(i) - self.CTypedefFound = 1 - return ts - return None - - def is_ctypedef_found(self) -> int: - """检查上次 lookup_ctypedef 是否找到值""" - return self.CTypedefFound - - def clear_ctypedefs(self) -> None: - """清空 CTypedef 表(模块切换时调用)""" - self.CTypedefNames = None - self.CTypedefTypeStrs = None - self.CTypedefResolveDepth = 0 - self.CTypedefVisiting = None - - def _ctypedef_push_visiting(self, pool: memhub.MemBuddy | t.CPtr, name: str) -> int: - """将 CTypedef 名加入正在解析列表(循环检测) - - Returns: - 0=成功加入(无循环),1=检测到循环 - """ - if name is None: - return 0 - if self.CTypedefVisiting is None: - self.CTypedefVisiting = list[str](pool, 32) - if self.CTypedefVisiting is None: - return 0 - vn: t.CSizeT = len(self.CTypedefVisiting) - vi: t.CSizeT - for vi in range(vn): - vs: str = self.CTypedefVisiting.get(vi) - if vs is not None and string.strcmp(vs, name) == 0: - return 1 # 循环检测 - self.CTypedefVisiting.append(name) - return 0 - - def _ctypedef_pop_visiting(self) -> None: - """从正在解析列表弹出最后一个 CTypedef 名""" - if self.CTypedefVisiting is None: - return - vn: t.CSizeT = len(self.CTypedefVisiting) - if vn > 0: - self.CTypedefVisiting.pop() - - def _is_ctypedef_annotation(self, annotation: ast.AST | t.CPtr) -> int: - """检测类型注解是否为 t.CTypedef - - Args: - annotation: 类型注解 AST 节点 - - Returns: - 1=是 t.CTypedef,0=否 - """ - if annotation is None: - return 0 - if annotation.kind() != ast.ASTKind.Attribute: - return 0 - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annotation) - if at.attr is None: - return 0 - if string.strcmp(at.attr, "CTypedef") != 0: - return 0 - if at.value is None or at.value.kind() != ast.ASTKind.Name: - return 0 - mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if mod_nm.id is None: - return 0 - if string.strcmp(mod_nm.id, "t") != 0: - return 0 - return 1 - - def ScanCTypedefDeclarations(self, pool: memhub.MemBuddy | t.CPtr, - tree: ast.AST | t.CPtr) -> int: - """扫描 AST 顶层节点,注册所有 NAME: t.CTypedef = Type 声明 - - 在 _translate_module_level 中、模块级变量预注册之前调用, - 确保 CTypedef 名称在类型解析时可用。 - - Args: - pool: 内存池 - tree: 模块 AST 根节点 - - Returns: - 注册的 CTypedef 数量 - """ - if pool is None or tree is None: - return 0 - ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children - if ch is None: - return 0 - n: t.CSizeT = len(ch) - count: int = 0 - i: t.CSizeT - for i in range(n): - child: ast.AST | t.CPtr = ch.get(i) - if child is None: - continue - if child.kind() != ast.ASTKind.AnnAssign: - continue - aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(child) - # 检测注解是否为 t.CTypedef - if self._is_ctypedef_annotation(aa.annotation) == 0: - continue - # 提取目标名称(必须是 Name 节点) - if aa.target is None or aa.target.kind() != ast.ASTKind.Name: - continue - tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) - if tgt.id is None: - continue - # 提取类型表达式字符串(从 value AST 节点) - if aa.value is None: - continue - type_str: str = self._get_type_name_from_annotation(pool, aa.value) - if type_str is None: - continue - # 注册 CTypedef - self.register_ctypedef(pool, tgt.id, type_str) - count += 1 - return count - - def _eval_const_int_expr(self, node: ast.AST | t.CPtr, - pool: memhub.MemBuddy | t.CPtr = None, - from_imports: str = None, - imported_modules: str = None) -> int: - """递归计算常量整数表达式 - - pool/from_imports/imported_modules:跨模块 CDefine 查找上下文 - (t.CArray count 引用依赖模块的 CDefine,如 SHA512_BLOCK_LEN 定义在 - hashlib/__sha512.vp,本地 CDefine 表每模块清空,需跨模块回退查找)。 - """ - if node is None: - self.ConstEvalOk = 0 - return 0 - k: int = node.kind() - - # Constant: 整数字面量 - if k == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) - if cn.const_kind == ast.CONST_INT: - self.ConstEvalOk = 1 - return cn.int_val - self.ConstEvalOk = 0 - return 0 - - # Name: CDefine 常量名(本地表优先,未命中走跨模块查找) - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm.id is None: - self.ConstEvalOk = 0 - return 0 - val: int = self.lookup_cdefine_constant(nm.id) - if self.is_cdefine_found() == 0: - # 本地表未命中:跨模块 CDefine 查找 - # 用 HandlesExpr 模块级委托(self._lookup_cross_module_cdefine 是 - # ExprGenMixin 方法,TypeGenMixin 直接调用会生成未定义引用) - if (from_imports is not None or imported_modules is not None) \ - and pool is not None: - import lib.core.Handles.HandlesExpr as HandlesExpr - x_val: int = HandlesExpr._lookup_cross_module_cdefine( - pool, nm.id, from_imports, imported_modules) - if HandlesType.is_cdefine_found() != 0: - self.ConstEvalOk = 1 - return x_val - # 定位日志:跨模块 CDefine 查找失败(t.CArray count 场景) - fb_cdf: str = VLogger.fmt_buf() - if fb_cdf is not None: - viperlib.snprintf(fb_cdf, 1024, - "[CDEF-MISS] name=%s fi=%s im=%s", - nm.id, - from_imports if from_imports is not None else "(null)", - imported_modules if imported_modules is not None else "(null)") - VLogger.error(fb_cdf, "CDEF") - self.ConstEvalOk = 0 - return 0 - self.ConstEvalOk = 1 - return val - - # Attribute: 模块限定常量名,如 hashlib.MD5_DIGEST_LEN - # (t.CArray[t.CUInt8T, hashlib.MD5_DIGEST_LEN] 的 count 是 Attribute, - # 复用跨模块 CDefine 查找:*:模块 → 源文件提取;re-export 常量由 - # _lookup_cross_module_cdefine 的 from-import 递归子模块兜底) - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at.attr is None: - self.ConstEvalOk = 0 - return 0 - if at.value is not None and at.value.kind() == ast.ASTKind.Name: - at_mod: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if at_mod.id is not None: - if (from_imports is not None or imported_modules is not None) \ - and pool is not None: - mod_len: t.CSizeT = string.strlen(at_mod.id) - fi_buf: str = pool.alloc(mod_len + 3) - if fi_buf is not None: - fi_buf[0] = '*' - fi_buf[1] = ':' - for mi in range(mod_len): - fi_buf[2 + mi] = at_mod.id[mi] - fi_buf[2 + mod_len] = '\0' - import lib.core.Handles.HandlesExpr as HandlesExpr - av: int = HandlesExpr._lookup_cross_module_cdefine( - pool, at.attr, fi_buf, imported_modules) - if HandlesType.is_cdefine_found() != 0: - self.ConstEvalOk = 1 - return av - self.ConstEvalOk = 0 - return 0 - - # BinOp: 算术/位运算 - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - # 递归计算左操作数 - lv: int = self._eval_const_int_expr(bop.left, pool, from_imports, imported_modules) - if self.ConstEvalOk == 0: - return 0 - # 递归计算右操作数 - rv: int = self._eval_const_int_expr(bop.right, pool, from_imports, imported_modules) - if self.ConstEvalOk == 0: - return 0 - # 根据运算符执行计算 - if bop.op == ast.OpKind.Add: - self.ConstEvalOk = 1 - return lv + rv - if bop.op == ast.OpKind.Sub: - self.ConstEvalOk = 1 - return lv - rv - if bop.op == ast.OpKind.Mult: - self.ConstEvalOk = 1 - return lv * rv - if bop.op == ast.OpKind.Div: - # 整数常量除法:与 FloorDiv 一致(对齐 TPC ConstEvaluator L354-355) - if rv == 0: - self.ConstEvalOk = 0 - return 0 - self.ConstEvalOk = 1 - return lv // rv - if bop.op == ast.OpKind.FloorDiv: - if rv == 0: - self.ConstEvalOk = 0 - return 0 - self.ConstEvalOk = 1 - return lv // rv - if bop.op == ast.OpKind.BitOr: - self.ConstEvalOk = 1 - return lv | rv - if bop.op == ast.OpKind.BitAnd: - self.ConstEvalOk = 1 - return lv & rv - # 不支持的运算符 - self.ConstEvalOk = 0 - return 0 - - # 不支持的节点类型 - self.ConstEvalOk = 0 - return 0 - - def set_generic_context(self, tp_names: list[str] | t.CPtr, - type_args: list[str] | t.CPtr): - """设置泛型特化上下文(进入泛型类方法体翻译时调用),嵌套安全 - - 先压栈当前(外层)上下文,再设置新值。clear_generic_context 弹出恢复, - 避免嵌套特化/泛型函数翻译退出时清空外层上下文(T.__sizeof__() 回归根因)。 - """ - if self.GenericCtxStack is None: - self.GenericCtxStack = stdlib.malloc(8 * 2 * 32) - if self.GenericCtxStack is None: - self.GenericTpNames = tp_names - self.GenericTypeArgs = type_args - return - self.GenericCtxDepth = 0 - if self.GenericCtxDepth < 32: - self.GenericCtxStack[self.GenericCtxDepth * 2] = t.CSizeT(self.GenericTpNames) - self.GenericCtxStack[self.GenericCtxDepth * 2 + 1] = t.CSizeT(self.GenericTypeArgs) - self.GenericCtxDepth += 1 - self.GenericTpNames = tp_names - self.GenericTypeArgs = type_args - - def clear_generic_context(self): - """清除泛型特化上下文(离开泛型类方法体翻译时调用),恢复外层而非置 None""" - if self.GenericCtxDepth > 0: - self.GenericCtxDepth -= 1 - self.GenericTpNames = (list[str] | t.CPtr)(t.CVoid( - self.GenericCtxStack[self.GenericCtxDepth * 2], t.CPtr)) - self.GenericTypeArgs = (list[str] | t.CPtr)(t.CVoid( - self.GenericCtxStack[self.GenericCtxDepth * 2 + 1], t.CPtr)) - else: - self.GenericTpNames = None - self.GenericTypeArgs = None - - def resolve_generic_type_name(self, name: str) -> str: - """如果 name 是泛型类型参数,返回对应的具体类型名;否则返回 name 本身 - - 用于表达式中的 T 替换(如 T.__sizeof__() → int.__sizeof__()) - """ - if name is None: - return name - if self.GenericTpNames is not None and self.GenericTypeArgs is not None: - rg_n: t.CSizeT = len(self.GenericTpNames) - rg_i: t.CSizeT - for rg_i in range(rg_n): - rg_tpn: str = self.GenericTpNames.get(rg_i) - if rg_tpn is not None and string.strcmp(name, rg_tpn) == 0: - rg_ta: str = self.GenericTypeArgs.get(rg_i) - if rg_ta is not None: - return rg_ta - return name - - def _get_type_name_from_annotation(self, pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr) -> str: - """从类型注解节点提取类型名(支持 Name/Attribute/BinOp)""" - if node is None: - return None - k: int = node.kind() - # Constant: 字符串注解,直接返回字符串值 - if k == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) - if cn.const_kind == ast.CONST_STR and cn.str_val is not None: - return cn.str_val - return None - # Name: 直接返回 id(泛型特化上下文内先做 T 替换,避免 ndarray[T] 中 T 未解析 - # 导致 _specialize_generic_class("ndarray", ["T"]) 二次递归崩溃) - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - return self.resolve_generic_type_name(nm.id) - # Attribute: 构造 "module.attr" 格式 - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at.attr is None: - return None - if at.value is not None and at.value.kind() == ast.ASTKind.Name: - mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if mod_nm.id is not None: - total: t.CSizeT = string.strlen(mod_nm.id) + 1 + string.strlen(at.attr) + 1 - buf: str = pool.alloc(total) - if buf is not None: - buf[0] = '\0' - string.strcat(buf, mod_nm.id) - string.strcat(buf, ".") - string.strcat(buf, at.attr) - return buf - return at.attr - # BinOp (BitOr): 构造 "left|right" 格式 - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - if bop.op == ast.OpKind.BitOr: - left_str: str = self._get_type_name_from_annotation(pool, bop.left) - right_str: str = self._get_type_name_from_annotation(pool, bop.right) - if left_str is not None and right_str is not None: - total2: t.CSizeT = string.strlen(left_str) + 1 + string.strlen(right_str) + 1 - buf2: str = pool.alloc(total2) - if buf2 is not None: - buf2[0] = '\0' - string.strcat(buf2, left_str) - string.strcat(buf2, "|") - string.strcat(buf2, right_str) - return buf2 - return None - return None - - def _parse_type_string(self, pool: memhub.MemBuddy | t.CPtr, - type_str: str, - ctx: t.CInt) -> ast.AST | t.CPtr: - """将类型名字符串解析为 AST 节点 - - 正确处理 '|' 与 '.' 周围的空格(如 "ParsedArgs | t.CPtr"): - - '|' 分割后左段可能带尾随空格("ParsedArgs "),右段可能带前导空格(" t.CPtr") - - 段内空格会导致 Name.id 带空格("ParsedArgs "、" t"),结构体/模块按名查找失败, - 最终退化 i8*/i32,如 parse_args -> "ParsedArgs | t.CPtr" 解析出垃圾类型。 - """ - if type_str is None or pool is None: - return None - - # 跳过前导空格('|' 分割后的右段可能带前导空格) - while type_str[0] == ' ': - type_str += 1 - - seg_len: t.CSizeT = string.strlen(type_str) - # 去除段尾随空格('|' 分割后的左段可能带尾随空格) - while seg_len > 0 and type_str[seg_len - 1] == ' ': - seg_len -= 1 - - # 检查是否包含 | (BinOp):只在有效段 [0, seg_len) 内查找 - pipe_idx: t.CSizeT = seg_len - pi: t.CSizeT = 0 - while pi < seg_len: - if type_str[pi] == '|': - pipe_idx = pi - break - pi += 1 - if pipe_idx < seg_len: - # 左段复制到独立缓冲(trim 尾随空格),不破坏原字符串 - left_len: t.CSizeT = pipe_idx - while left_len > 0 and type_str[left_len - 1] == ' ': - left_len -= 1 - left_buf: bytes = stdlib.malloc(left_len + 1) - if left_buf is None: - return None - string.strncpy(left_buf, type_str, left_len) - left_buf[left_len] = '\0' - left_node: ast.AST | t.CPtr = self._parse_type_string(pool, left_buf, ctx) - # 右段前导空格由递归入口跳过 - right_node: ast.AST | t.CPtr = self._parse_type_string( - pool, type_str + pipe_idx + 1, ctx) - stdlib.free(left_buf) - if left_node is not None and right_node is not None: - return ast.BinOp(pool, left_node, ast.OpKind.BitOr, right_node) - return None - - # 检查是否包含 . (Attribute):只在有效段 [0, seg_len) 内查找 - dot_idx: t.CSizeT = seg_len - di: t.CSizeT = 0 - while di < seg_len: - if type_str[di] == '.': - dot_idx = di - break - di += 1 - if dot_idx < seg_len: - # 模块名段 trim 尾随空格 - mod_len: t.CSizeT = dot_idx - while mod_len > 0 and type_str[mod_len - 1] == ' ': - mod_len -= 1 - mod_buf: bytes = stdlib.malloc(mod_len + 1) - if mod_buf is None: - return None - string.strncpy(mod_buf, type_str, mod_len) - mod_buf[mod_len] = '\0' - module_node: ast.AST | t.CPtr = ast.Name(pool, mod_buf, ctx) - # attr 段 trim 尾随空格 - attr_str: str = type_str + dot_idx + 1 - attr_len: t.CSizeT = string.strlen(attr_str) - while attr_len > 0 and attr_str[attr_len - 1] == ' ': - attr_len -= 1 - attr_buf: bytes = stdlib.malloc(attr_len + 1) - if attr_buf is None: - stdlib.free(mod_buf) - return None - string.strncpy(attr_buf, attr_str, attr_len) - attr_buf[attr_len] = '\0' - attr_node: ast.AST | t.CPtr = ast.Attribute(pool, module_node, attr_buf, ctx) - stdlib.free(mod_buf) - stdlib.free(attr_buf) - return attr_node - - # 普通 Name(trim 尾随空格,ast.Name 内部 _copy_str 复制) - name_buf: bytes = stdlib.malloc(seg_len + 1) - if name_buf is None: - return None - string.strncpy(name_buf, type_str, seg_len) - name_buf[seg_len] = '\0' - name_node: ast.AST | t.CPtr = ast.Name(pool, name_buf, ctx) - stdlib.free(name_buf) - return name_node - - def set_current_file(self, file_path: str): - """设置当前编译的文件名(供报错使用)""" - self.CurrentFile = file_path - - def get_current_file(self) -> str: - """获取当前编译的文件名(供报错归因使用)""" - return self.CurrentFile - - def _read_source_line(self, file_path: str, lineno: int) -> str: - """从源文件读取第 lineno 行内容""" - if file_path is None or lineno <= 0: - return None - f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R) - if f.closed: - return None - # 按文件实际大小分配缓冲区:固定 256KB 会截断大源文件,末尾行号读不到 → - # 误报"文件不存在或行号超出范围"(如 CallGenMixin.vp 555KB/9236 行的第 - # 8390 行)。64MB 上限防御异常超大文件整体读取。 - fsize: LONGLONG = f.size() - if fsize <= 0 or fsize > 67108864: - f.close() - return None - src_size: t.CSizeT = t.CSizeT(fsize) - buf: bytes = stdlib.malloc(src_size + 1) - if buf is None: - f.close() - return None - bytes_read: LONG = f.read_all(buf, ULONG(src_size + 1)) - f.close() - if bytes_read <= 0: - stdlib.free(buf) - return None - # 逐行查找第 lineno 行 - cur_line: int = 1 - line_start: t.CSizeT = 0 - for i in range(bytes_read): - if buf[i] == '\n': - if cur_line == lineno: - line_len: t.CSizeT = i - line_start - if line_len > 0 and buf[line_start + line_len - 1] == '\r': - line_len -= 1 - line_buf: bytes = stdlib.malloc(line_len + 1) - if line_buf is not None: - string.strncpy(line_buf, buf + line_start, line_len) - line_buf[line_len] = '\0' - stdlib.free(buf) - return line_buf - stdlib.free(buf) - return None - cur_line += 1 - line_start = i + 1 - stdlib.free(buf) - return None - - def read_source_line(self, file_path: str, lineno: int) -> str: - """公开包装:从源文件读取第 lineno 行内容(供 traceback 展示)""" - return self._read_source_line(file_path, lineno) - - def dump_parse_traceback(self, file_path: str): - """解析失败时以 Python 风格输出 traceback(仿 fatal_error)""" - err_line: int = ast.get_parse_err_line() - err_col: int = ast.get_parse_err_col() - err_msg: str = ast.get_parse_err_msg() - stdio.printf("Traceback (most recent call last):\n") - if file_path is None or file_path[0] == 0: - file_path = "" - if err_line > 0: - stdio.printf(' File "%s", line %d\n', file_path, err_line) - src: str = self._read_source_line(file_path, err_line) - if src is not None: - stdio.printf(" %s\n", src) - # 列标记:在出错 token 起始列下方标 ^(parser 的 col_offset 是 0-based, - # 前缀 4 空格 + err_col 个空格后落点恰好是该 token 首字符) - if err_col > 0: - stdio.printf(" ") - c: int - for c in range(err_col): - stdio.printf(" ") - stdio.printf("^\n") - stdlib.free(src) - else: - stdio.printf(' File "%s"\n', file_path) - if err_msg is None or err_msg[0] == 0: - err_msg = "语法错误" - stdio.printf("SyntaxError: %s\n", err_msg) - - def fatal_error(self, node: ast.AST | t.CPtr, msg: str, - err_type: str = "SyntaxError", - col_start: int = 0, col_end: int = 0): - """以 Python 风格报错并退出(支持多帧、错误类型、列范围) - - 向后兼容:err_type/col_start/col_end 有默认值,旧调用 fatal_error(node, msg) 仍可用。 - """ - stdio.printf("Traceback (most recent call last):\n") - # 输出调用栈帧(从底到顶) - i: int - for i in range(self.TraceCount): - frame: HandlesType.TraceFrame | t.CPtr = self._get_trace_frame(i) - if frame is not None and frame.file_name is not None: - if frame.lineno > 0: - stdio.printf(' File "%s", line %d\n', frame.file_name, frame.lineno) - src: str = self._read_source_line(frame.file_name, frame.lineno) - if src is not None: - stdio.printf(" %s\n", src) - stdlib.free(src) - else: - stdio.printf(' File "%s"\n', frame.file_name) - # 输出当前帧(node 对应的位置) - lineno: int = 0 - if node is not None: - lineno = node.lineno - file_name: str = self.CurrentFile - if file_name is None: - file_name = "" - # 行号兜底:克隆/构造节点 lineno 可能为 0(如泛型特化 _clone_arguments 的 - # ast.Arg 构造器硬编码 0,astaux.vp L139)。此时回退到 trace 栈最后一个 - # 有效帧(文件+行号)作为出错位置,避免输出误导性的 "line 0"。 - if lineno <= 0 and self.TraceCount > 0: - ti_b: int = self.TraceCount - 1 - while ti_b >= 0: - tfb: HandlesType.TraceFrame | t.CPtr = self._get_trace_frame(ti_b) - if tfb is not None and tfb.file_name is not None and tfb.lineno > 0: - file_name = tfb.file_name - lineno = tfb.lineno - break - ti_b -= 1 - # 行号合理性防御:先读取该行源码,验证 node.lineno 是否落在当前文件内。 - # 若读不到(文件不存在或行号超出范围),说明文件/行号归属不可信 - # (如 AST 树被内存复用/串扰后跨文件报错),打印警告而非误导性行号。 - src_line: str = None - line_ok: int = 1 - if lineno > 0 and string.strcmp(file_name, "") != 0: - src_line = self._read_source_line(file_name, lineno) - if src_line is None: - line_ok = 0 - if line_ok == 0: - stdio.printf(' File "%s", line %d (!! 无法读取该行源码:文件不存在或行号超出范围,错误可能来自被复用的 AST 树,请以错误消息为准)\n', - file_name, lineno) - else: - stdio.printf(' File "%s", line %d\n', file_name, lineno) - if src_line is not None: - stdio.printf(" %s\n", src_line) - # 列范围标记:在源代码行下方用 ^ 标记出错范围 - if col_start > 0 and col_end >= col_start: - stdio.printf(" ") - j: int - for j in range(col_end): - if j >= col_start - 1 and j < col_end: - stdio.printf("^") - else: - stdio.printf(" ") - stdio.printf("\n") - stdlib.free(src_line) - # 输出错误类型 + 消息 - if err_type is None or err_type[0] == 0: - err_type = "SyntaxError" - stdio.printf("%s: %s\n", err_type, msg) - sys.exit(1) - - def fatal_type_error(self, node: ast.AST | t.CPtr, msg: str, - col_start: int = 0, col_end: int = 0): - """以 Python 风格报错并退出(TypeError 版本)""" - self.fatal_error(node, msg, "TypeError", col_start, col_end) - - def try_extract_callable_ret(self, pool: memhub.MemBuddy | t.CPtr, - annot: ast.AST | t.CPtr, - imported_modules: str, - from_imports: str, - trans: HT.Translator | t.CPtr) -> llvmlite.LLVMType | t.CPtr: - """提取 t.Callable 注解的返回类型 LLVMType;非 Callable 注解返回 None""" - if annot is None or annot.kind() != ast.ASTKind.Subscript: - return None - sub_cr: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot) - if sub_cr.value is None or sub_cr.value.kind() != ast.ASTKind.Attribute: - return None - at_cr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sub_cr.value) - if at_cr.attr is None or string.strcmp(at_cr.attr, "Callable") != 0: - return None - # slice 必须是 Tuple(elts=[args_list, ret_node]) - if sub_cr.slice is None or sub_cr.slice.kind() != ast.ASTKind.Tuple: - return None - tp_cr: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub_cr.slice) - if tp_cr.elts is None or len(tp_cr.elts) != 2: - return None - ret_node_cr: ast.AST | t.CPtr = tp_cr.elts.get(1) - if ret_node_cr is None: - return None - return self.resolve_annotation_type(pool, ret_node_cr, imported_modules, from_imports, trans) - - def map_t_type(self, pool: memhub.MemBuddy | t.CPtr, - type_name: str) -> llvmlite.LLVMType | t.CPtr: - """将 t.CXxx / c.CXxx 类型名映射到 LLVMType - - 注意: str = i8* = str = bytes - """ - if type_name is None: - return None - - # 基本整数类型 - if string.strcmp(type_name, "CInt") == 0: - return llvmlite.Int32(pool) - elif string.strcmp(type_name, "CChar") == 0: - return llvmlite.Int8(pool) - elif string.strcmp(type_name, "CShort") == 0: - return llvmlite.Int16(pool) - elif string.strcmp(type_name, "CLong") == 0: - return llvmlite.Int64(pool) - elif string.strcmp(type_name, "CLongLong") == 0: - return llvmlite.Int64(pool) - # 精确宽度有符号类型 - elif string.strcmp(type_name, "CInt8T") == 0: - return llvmlite.Int8(pool) - elif string.strcmp(type_name, "CInt16T") == 0: - return llvmlite.Int16(pool) - elif string.strcmp(type_name, "CInt32T") == 0: - return llvmlite.Int32(pool) - elif string.strcmp(type_name, "CInt64T") == 0: - return llvmlite.Int64(pool) - # 精确宽度无符号类型 - elif string.strcmp(type_name, "CUInt8T") == 0: - return llvmlite.Int8(pool) - elif string.strcmp(type_name, "CUInt16T") == 0: - return llvmlite.Int16(pool) - elif string.strcmp(type_name, "CUInt32T") == 0: - return llvmlite.Int32(pool) - elif string.strcmp(type_name, "CUInt64T") == 0: - return llvmlite.Int64(pool) - # 浮点类型 - elif string.strcmp(type_name, "CFloat") == 0: - return llvmlite.Float(pool) - elif string.strcmp(type_name, "CDouble") == 0: - return llvmlite.Double(pool) - # 精确宽度浮点类型(t.py 的 float_map: 8/16→half, 32→float, 64→double, 128→fp128) - elif string.strcmp(type_name, "CFloat8T") == 0: - return llvmlite.Half(pool) - elif string.strcmp(type_name, "CFloat16T") == 0: - return llvmlite.Half(pool) - elif string.strcmp(type_name, "CFloat32T") == 0: - return llvmlite.Float(pool) - elif string.strcmp(type_name, "CFloat64T") == 0: - return llvmlite.Double(pool) - elif string.strcmp(type_name, "CFloat128T") == 0: - return llvmlite.FP128(pool) - # 指针/void: t.CPtr = i8*, str = i8* = str = bytes - elif string.strcmp(type_name, "CPtr") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - elif string.strcmp(type_name, "CVoid") == 0: - return llvmlite.Void(pool) - # CNeedPtr/CAutoPtr: 参数自动取地址标记,LLVM 层均为通用指针 i8*。 - # (TPC 中二者继承 CPtr;TPV 未实现调用点自动取地址,非指针实参应在调用点报错, - # 而非静默降级为 i32 导致指针截断。) - elif string.strcmp(type_name, "CNeedPtr") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - elif string.strcmp(type_name, "CAutoPtr") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - # 无符号修饰 - elif string.strcmp(type_name, "CUnsigned") == 0: - return llvmlite.Int32(pool) - elif string.strcmp(type_name, "CUnsignedInt") == 0: - return llvmlite.Int32(pool) - elif string.strcmp(type_name, "CUnsignedChar") == 0: - return llvmlite.Int8(pool) - elif string.strcmp(type_name, "CUnsignedShort") == 0: - return llvmlite.Int16(pool) - elif string.strcmp(type_name, "CUnsignedLong") == 0: - return llvmlite.Int64(pool) - elif string.strcmp(type_name, "CUnsignedLongLong") == 0: - return llvmlite.Int64(pool) - # size_t / ptr 类型 - elif string.strcmp(type_name, "CSizeT") == 0: - return llvmlite.Int64(pool) - elif string.strcmp(type_name, "CIntPtrT") == 0: - return llvmlite.Int64(pool) - elif string.strcmp(type_name, "CUIntPtrT") == 0: - return llvmlite.Int64(pool) - # bool - elif string.strcmp(type_name, "CBool") == 0: - # bool = t.CBool = i1(LLVM 1 位整数,语义与 C _Bool 一致) - return llvmlite.Int1(pool) - # ptrdiff_t - elif string.strcmp(type_name, "CPtrDiffT") == 0: - return llvmlite.Int64(pool) - - # ============================================================ - # stdint.py 大写别名(Win32/TransPyC 风格) - # ============================================================ - # 整数类型 - elif string.strcmp(type_name, "INT") == 0: - return llvmlite.Int32(pool) - elif string.strcmp(type_name, "BOOL") == 0: - return llvmlite.Int32(pool) - elif string.strcmp(type_name, "UINT") == 0: - return llvmlite.Int32(pool) - elif string.strcmp(type_name, "BYTE") == 0: - return llvmlite.Int8(pool) - elif string.strcmp(type_name, "WORD") == 0: - return llvmlite.Int16(pool) - elif string.strcmp(type_name, "DWORD") == 0: - return llvmlite.Int32(pool) - elif string.strcmp(type_name, "QWORD") == 0: - return llvmlite.Int64(pool) - elif string.strcmp(type_name, "TCHAR") == 0: - return llvmlite.Int8(pool) - elif string.strcmp(type_name, "VOID") == 0: - return llvmlite.Void(pool) - elif string.strcmp(type_name, "SHORT") == 0: - return llvmlite.Int16(pool) - elif string.strcmp(type_name, "USHORT") == 0: - return llvmlite.Int16(pool) - elif string.strcmp(type_name, "LONGLONG") == 0: - return llvmlite.Int64(pool) - elif string.strcmp(type_name, "ULONGLONG") == 0: - return llvmlite.Int64(pool) - elif string.strcmp(type_name, "LONG") == 0: - return llvmlite.Int64(pool) - elif string.strcmp(type_name, "ULONG") == 0: - return llvmlite.Int64(pool) - elif string.strcmp(type_name, "WCHAR") == 0: - return llvmlite.Int16(pool) - elif string.strcmp(type_name, "FLOAT") == 0: - return llvmlite.Float(pool) - elif string.strcmp(type_name, "DOUBLE") == 0: - return llvmlite.Double(pool) - # 小写裸名浮点类型(float = t.CFloat = f32, double = t.CDouble = f64) - elif string.strcmp(type_name, "float") == 0: - return llvmlite.Float(pool) - elif string.strcmp(type_name, "double") == 0: - return llvmlite.Double(pool) - elif string.strcmp(type_name, "FSIZE_t") == 0: - return llvmlite.Int32(pool) - elif string.strcmp(type_name, "LBA_t") == 0: - return llvmlite.Int32(pool) - # 定长整数 - elif string.strcmp(type_name, "INT8") == 0: - return llvmlite.Int8(pool) - elif string.strcmp(type_name, "INT16") == 0: - return llvmlite.Int16(pool) - elif string.strcmp(type_name, "INT32") == 0: - return llvmlite.Int32(pool) - elif string.strcmp(type_name, "INT64") == 0: - return llvmlite.Int64(pool) - elif string.strcmp(type_name, "UINT8") == 0: - return llvmlite.Int8(pool) - elif string.strcmp(type_name, "UINT16") == 0: - return llvmlite.Int16(pool) - elif string.strcmp(type_name, "UINT32") == 0: - return llvmlite.Int32(pool) - elif string.strcmp(type_name, "UINT64") == 0: - return llvmlite.Int64(pool) - elif string.strcmp(type_name, "CHAR8") == 0: - return llvmlite.Int8(pool) - elif string.strcmp(type_name, "CHAR16") == 0: - return llvmlite.Int16(pool) - elif string.strcmp(type_name, "CHAR32") == 0: - return llvmlite.Int32(pool) - # 小写简写 - elif string.strcmp(type_name, "i8") == 0: - return llvmlite.Int8(pool) - elif string.strcmp(type_name, "i16") == 0: - return llvmlite.Int16(pool) - elif string.strcmp(type_name, "i32") == 0: - return llvmlite.Int32(pool) - elif string.strcmp(type_name, "i64") == 0: - return llvmlite.Int64(pool) - elif string.strcmp(type_name, "u8") == 0: - return llvmlite.Int8(pool) - elif string.strcmp(type_name, "u16") == 0: - return llvmlite.Int16(pool) - elif string.strcmp(type_name, "u32") == 0: - return llvmlite.Int32(pool) - elif string.strcmp(type_name, "u64") == 0: - return llvmlite.Int64(pool) - # size_t 系列 - elif string.strcmp(type_name, "SIZE_T") == 0: - return llvmlite.Int64(pool) - elif string.strcmp(type_name, "SSIZE_T") == 0: - return llvmlite.Int64(pool) - elif string.strcmp(type_name, "PTRDIFF_T") == 0: - return llvmlite.Int64(pool) - - # stdint 指针类型(XxxPTR = XxxType | t.CPtr) - elif string.strcmp(type_name, "INTPTR") == 0: - return llvmlite.Ptr(pool, llvmlite.Int32(pool)) - elif string.strcmp(type_name, "UINTPTR") == 0: - return llvmlite.Ptr(pool, llvmlite.Int32(pool)) - elif string.strcmp(type_name, "BYTEPTR") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - elif string.strcmp(type_name, "CHARLIST") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - elif string.strcmp(type_name, "SHORTPTR") == 0: - return llvmlite.Ptr(pool, llvmlite.Int16(pool)) - elif string.strcmp(type_name, "USHORTPTR") == 0: - return llvmlite.Ptr(pool, llvmlite.Int16(pool)) - elif string.strcmp(type_name, "WCHARPTR") == 0: - return llvmlite.Ptr(pool, llvmlite.Int16(pool)) - elif string.strcmp(type_name, "CHARPTR") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - elif string.strcmp(type_name, "VOIDPTR") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - # Windows API 跨模块 typedef(win32base.py 中定义) - # HANDLE = VOIDPTR = i8*,LPCSTR = const char* = i8*,LPCWSTR = const wchar_t* = i16* - elif string.strcmp(type_name, "HANDLE") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - elif string.strcmp(type_name, "LPCSTR") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - elif string.strcmp(type_name, "LPCWSTR") == 0: - return llvmlite.Ptr(pool, llvmlite.Int16(pool)) - elif string.strcmp(type_name, "INT8PTR") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - elif string.strcmp(type_name, "INT16PTR") == 0: - return llvmlite.Ptr(pool, llvmlite.Int16(pool)) - elif string.strcmp(type_name, "INT32PTR") == 0: - return llvmlite.Ptr(pool, llvmlite.Int32(pool)) - elif string.strcmp(type_name, "INT64PTR") == 0: - return llvmlite.Ptr(pool, llvmlite.Int64(pool)) - elif string.strcmp(type_name, "UINT8PTR") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - elif string.strcmp(type_name, "UINT16PTR") == 0: - return llvmlite.Ptr(pool, llvmlite.Int16(pool)) - elif string.strcmp(type_name, "UINT32PTR") == 0: - return llvmlite.Ptr(pool, llvmlite.Int32(pool)) - elif string.strcmp(type_name, "UINT64PTR") == 0: - return llvmlite.Ptr(pool, llvmlite.Int64(pool)) - elif string.strcmp(type_name, "CHAR8PTR") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - elif string.strcmp(type_name, "CHAR16PTR") == 0: - return llvmlite.Ptr(pool, llvmlite.Int16(pool)) - elif string.strcmp(type_name, "CHAR32PTR") == 0: - return llvmlite.Ptr(pool, llvmlite.Int32(pool)) - - # C 标准 小写 _t 类型 - elif string.strcmp(type_name, "int8_t") == 0: - return llvmlite.Int8(pool) - elif string.strcmp(type_name, "int16_t") == 0: - return llvmlite.Int16(pool) - elif string.strcmp(type_name, "int32_t") == 0: - return llvmlite.Int32(pool) - elif string.strcmp(type_name, "int64_t") == 0: - return llvmlite.Int64(pool) - elif string.strcmp(type_name, "uint8_t") == 0: - return llvmlite.Int8(pool) - elif string.strcmp(type_name, "uint16_t") == 0: - return llvmlite.Int16(pool) - elif string.strcmp(type_name, "uint32_t") == 0: - return llvmlite.Int32(pool) - elif string.strcmp(type_name, "uint64_t") == 0: - return llvmlite.Int64(pool) - elif string.strcmp(type_name, "size_t") == 0: - return llvmlite.Int64(pool) - elif string.strcmp(type_name, "ssize_t") == 0: - return llvmlite.Int64(pool) - elif string.strcmp(type_name, "ptrdiff_t") == 0: - return llvmlite.Int64(pool) - elif string.strcmp(type_name, "intptr_t") == 0: - return llvmlite.Int64(pool) - elif string.strcmp(type_name, "uintptr_t") == 0: - return llvmlite.Int64(pool) - elif string.strcmp(type_name, "wchar_t") == 0: - return llvmlite.Int16(pool) - elif string.strcmp(type_name, "char8_t") == 0: - return llvmlite.Int8(pool) - elif string.strcmp(type_name, "char16_t") == 0: - return llvmlite.Int16(pool) - elif string.strcmp(type_name, "char32_t") == 0: - return llvmlite.Int32(pool) - elif string.strcmp(type_name, "_Bool") == 0: - return llvmlite.Int8(pool) - return None - - def _is_t_attr(self, node: ast.AST | t.CPtr, - attr_name: str, - imported_modules: str) -> int: - """检测节点是否是 t.attr_name 形式(含 from t import attr_name 的裸名) - - 支持两种写法(与 TPC 的 IsTModule 检查对齐): - - t.CPtr / t.CVoid(Attribute 形式) - - 裸名 CPtr / CVoid(from t import CPtr 形式) - 裸名识别是必要功能:测试/库代码大量用 `from t import CPtr` 后直接写 - `X | CPtr`、`CVoid` 参数注解等,若只认 t.XXX 会漏判。 - """ - if node is None or attr_name is None: - return 0 - if node.kind() == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at.attr is None: - return 0 - if string.strcmp(at.attr, attr_name) != 0: - return 0 - if at.value is None or at.value.kind() != ast.ASTKind.Name: - return 0 - val_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if val_nm.id is None: - return 0 - if string.strcmp(val_nm.id, "t") == 0: - # t 是内建库(SHA1 豁免),可能不在 _imported_modules 中。 - # 显式写 t.CPtr / t.CVoid 即确指 t 模块,无需 imported_modules 确认。 - return 1 - return 0 - # 裸名形式: from t import attr_name → Name(id == attr_name) - if node.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm.id is None: - return 0 - if string.strcmp(nm.id, attr_name) != 0: - return 0 - # 裸名需确认 t 模块已导入(from t import X 会注册 t 到 _imported_modules) - if HandlesImports.is_module_imported(imported_modules, "t") == 0: - return 0 - return 1 - return 0 - - def _is_cptr_marker(self, node: ast.AST | t.CPtr, - imported_modules: str) -> int: - """检测节点是否为 CPtr 指针标记,返回 1=是 / 0=否""" - if self._is_t_attr(node, "CPtr", imported_modules) != 0: - return 1 - if node is not None and node.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm.id is not None and string.strcmp(nm.id, "CPtr") == 0: - return 1 - return 0 - - def _is_cptr_subscript(self, node: ast.AST | t.CPtr) -> int: - """检测节点是否为 t.CPtr[T] 下标指针类型(t.CPtr[t.CPtr] / t.CPtr[t.CInt] 等) - - 用于联合类型 X | t.CPtr[T] 的指针层级合并(TPC 联合合并规则: - CPtr 侧贡献 PtrCount,另一侧提供 BaseType)。t.CPtr[...] 不是 - 普通 CPtr 标记(_is_cptr_marker 只认 t.CPtr/CPtr 裸形式)。 - """ - if node is None or node.kind() != ast.ASTKind.Subscript: - return 0 - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - if sub.value is None or sub.value.kind() != ast.ASTKind.Attribute: - return 0 - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sub.value) - if at.attr is None or string.strcmp(at.attr, "CPtr") != 0: - return 0 - if at.value is None or at.value.kind() != ast.ASTKind.Name: - return 0 - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm.id is None or string.strcmp(nm.id, "t") != 0: - return 0 - return 1 - - def _is_cvoid_marker(self, node: ast.AST | t.CPtr, - imported_modules: str) -> int: - """检测节点是否为 CVoid 指针标记,返回 1=是 / 0=否""" - if self._is_t_attr(node, "CVoid", imported_modules) != 0: - return 1 - if node is not None and node.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm.id is not None and string.strcmp(nm.id, "CVoid") == 0: - return 1 - return 0 - - def annotation_to_str(self, annot: ast.AST | t.CPtr) -> str: - """将类型注解 AST 转换为可读字符串,返回 None=无法提取 - - 注意:返回的字符串可能由 malloc 分配,调用方无需释放(错误路径用)。 - """ - if annot is None: - return "" - k: int = annot.kind() - - # Constant 节点: 字符串注解 - if k == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(annot) - if cn.const_kind == ast.CONST_STR and cn.str_val is not None: - return cn.str_val - return "" - - # Name 节点: bool, int, MemBuddy - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annot) - if nm.id is not None: - return nm.id - return "" - - # Attribute 节点: t.CBool, memhub.MemBuddy - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot) - if at.attr is None: - return "" - if at.value is not None: - prefix: str = self.annotation_to_str(at.value) - if prefix is not None: - buf: str = stdlib.malloc( - string.strlen(prefix) + string.strlen(at.attr) + 2) - if buf is not None: - viperlib.snprintf(buf, - string.strlen(prefix) + string.strlen(at.attr) + 2, - "%s.%s", prefix, at.attr) - return buf - return at.attr - - # Subscript 节点: list[...], t.CArray[...] - if k == ast.ASTKind.Subscript: - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot) - base: str = self.annotation_to_str(sub.value) - if base is not None: - buf2: str = stdlib.malloc(string.strlen(base) + 5) - if buf2 is not None: - viperlib.snprintf(buf2, string.strlen(base) + 5, - "%s[...]", base) - return buf2 - return "" - - # BinOp 节点: A | B (联合类型) - if k == ast.ASTKind.BinOp: - bo: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot) - left_s: str = self.annotation_to_str(bo.left) - right_s: str = self.annotation_to_str(bo.right) - if left_s is not None and right_s is not None: - buf3: str = stdlib.malloc( - string.strlen(left_s) + string.strlen(right_s) + 5) - if buf3 is not None: - viperlib.snprintf(buf3, - string.strlen(left_s) + string.strlen(right_s) + 5, - "%s | %s", left_s, right_s) - return buf3 - return "" - - return "" - - def extract_class_name_from_annotation(self, node: ast.AST | t.CPtr, - imported_modules: str, - pool: memhub.MemBuddy | t.CPtr = None) -> str: - """从类型注解 AST 中提取类名,返回 None=无法提取 - - pool 可用时,对泛型 Subscript(如 list[AST | t.CPtr])返回 mangled name - (如 "list[ast.AST|t.CPtr]"),与 resolve_annotation_type 的 mangled name 格式一致, - 使 find_struct 能找到特化的泛型结构体。 - pool 为 None 时,对 Subscript 只返回裸类名(如 "list"),保持向后兼容。 - """ - if node is None: - return None - k: int = node.kind() - - # Constant 节点: 字符串注解(如 'MemManager'),简单类名直接返回 - if k == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) - if cn.const_kind == ast.CONST_STR and cn.str_val is not None: - # 仅处理简单类名(不含 . 和 |),复杂形式返回 None - if string.strchr(cn.str_val, 46) is None and string.strchr(cn.str_val, 124) is None: - if string.strcmp(cn.str_val, "str") == 0: - return None - if string.strcmp(cn.str_val, "int") == 0: - return None - if string.strcmp(cn.str_val, "bytes") == 0: - return None - if string.strcmp(cn.str_val, "bool") == 0: - return None - if string.strcmp(cn.str_val, "float") == 0: - return None - if string.strcmp(cn.str_val, "double") == 0: - return None - return cn.str_val - return None - - # Name 节点: MemBuddy → "MemBuddy" - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm.id is None: - return None - # 泛型特化上下文:T → 具体类型(特化方法体内局部变量注解 - # 如 `cur: T | t.CPtr` 未被 _clone_classdef_for_spec 克隆替换, - # 依赖此处在翻译时经上下文解析;否则 cur.annot="T", - # 属性访问 cur.Next → lookup_field_by_class("T") 未注册报错) - resolved_id: str = self.resolve_generic_type_name(nm.id) - if resolved_id is None: - return None - # 跳过内置类型名 - if string.strcmp(resolved_id, "str") == 0: - return None - if string.strcmp(resolved_id, "bytes") == 0: - return None - if string.strcmp(resolved_id, "bool") == 0: - return None - if string.strcmp(resolved_id, "float") == 0: - return None - if string.strcmp(resolved_id, "double") == 0: - return None - return resolved_id - - # Attribute 节点: memhub.MemBuddy → "memhub.MemBuddy"(模块限定名) - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at.attr is None: - return None - # t.XXX 内置类型:返回 XXX(如 t.CUInt32T → "CUInt32T"), - # 供 AnnotClassName 记录变量类型名(_type_name_unsigned 判断无符号性时使用)。 - # 消费方(find_struct/lookup_field_by_class)对非结构体名返回 None 优雅降级。 - if at.value is not None and at.value.kind() == ast.ASTKind.Name: - val_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if val_nm2.id is not None and string.strcmp(val_nm2.id, "t") == 0: - return at.attr - # 返回模块限定名 "module.Class"(如 "memhub.MemBuddy") - mod_qual_buf: str = stdlib.malloc( - string.strlen(val_nm2.id) + string.strlen(at.attr) + 2) - if mod_qual_buf is not None: - viperlib.snprintf(mod_qual_buf, - string.strlen(val_nm2.id) + string.strlen(at.attr) + 2, - "%s.%s", val_nm2.id, at.attr) - return mod_qual_buf - return at.attr - - # BinOp 节点: 联合类型 A | B - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - if bop.op == ast.OpKind.BitOr: - left_is_cptr: int = self._is_cptr_marker(bop.left, imported_modules) - right_is_cptr: int = self._is_cptr_marker(bop.right, imported_modules) - # 提取非 CPtr 一边的类名 - if left_is_cptr != 0 and right_is_cptr == 0: - return self.extract_class_name_from_annotation(bop.right, imported_modules, pool) - if right_is_cptr != 0 and left_is_cptr == 0: - return self.extract_class_name_from_annotation(bop.left, imported_modules, pool) - # 无 CPtr 标记:尝试两边 - if left_is_cptr == 0 and right_is_cptr == 0: - left_name: str = self.extract_class_name_from_annotation(bop.left, imported_modules, pool) - if left_name is not None: - return left_name - return self.extract_class_name_from_annotation(bop.right, imported_modules, pool) - return None - - # BUG 1 方案3:Subscript 节点拼接 mangled name - # list[AST | t.CPtr] → "list[ast.AST|t.CPtr]"(pool 可用时) - # 与 resolve_annotation_type 的 mangled name 格式一致,使 find_struct 能找到特化结构体 - if k == ast.ASTKind.Subscript: - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - if sub.value is None: - return None - base_name: str = self.extract_class_name_from_annotation(sub.value, imported_modules, pool) - if base_name is None: - return None - # pool 不可用时,只返回裸类名(向后兼容) - if pool is None or sub.slice is None: - return base_name - # pool 可用:拼接 mangled name "base_name[slice_name]" - # slice 是 Tuple 时用逗号分隔多个参数,否则单个参数 - slice_name: str = None - if sub.slice.kind() == ast.ASTKind.Tuple: - # Tuple slice: dict[str, int] → "str,int" - sub_tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice) - if sub_tup.elts is not None: - tup_elts_sn: list[ast.AST | t.CPtr] | t.CPtr = sub_tup.elts - tn_sn: t.CSizeT = len(tup_elts_sn) - # 计算总长度 - tup_total: t.CSizeT = 1 - ti_sn: t.CSizeT - for ti_sn in range(tn_sn): - if ti_sn > 0: - tup_total += 1 - elt_node: ast.AST | t.CPtr = tup_elts_sn.get(ti_sn) - elt_name: str = self._get_type_name_from_annotation(pool, elt_node) - if elt_name is not None: - tup_total += string.strlen(elt_name) - tup_buf: str = pool.alloc(tup_total) - if tup_buf is not None: - tup_buf[0] = '\0' - for ti_sn in range(tn_sn): - if ti_sn > 0: - string.strcat(tup_buf, ",") - elt_node2: ast.AST | t.CPtr = tup_elts_sn.get(ti_sn) - elt_name2: str = self._get_type_name_from_annotation(pool, elt_node2) - if elt_name2 is not None: - string.strcat(tup_buf, elt_name2) - slice_name = tup_buf - else: - # 非 Tuple slice: list[AST | t.CPtr] → "ast.AST|t.CPtr" - slice_name = self._get_type_name_from_annotation(pool, sub.slice) - if slice_name is None: - return base_name - # 拼接 "base_name[slice_name]" - mangled_total: t.CSizeT = string.strlen(base_name) + 1 + string.strlen(slice_name) + 1 + 1 - mangled_buf: str = pool.alloc(mangled_total) - if mangled_buf is None: - return base_name - mangled_buf[0] = '\0' - string.strcat(mangled_buf, base_name) - string.strcat(mangled_buf, "[") - string.strcat(mangled_buf, slice_name) - string.strcat(mangled_buf, "]") - return mangled_buf - - return None - - def _resolve_generic_subscript_ty(self, pool: memhub.MemBuddy | t.CPtr, - sub: ast.Subscript | t.CPtr, - gen_cls_name: str, - trans: HT.Translator | t.CPtr, - imported_modules: str, - from_imports: str) -> llvmlite.LLVMType | t.CPtr: - """解析泛型类类型注解(特化或查找已注册结构体),失败返回 None""" - if pool is None or sub is None or gen_cls_name is None: - return None - # tuple[T1, T2, ...] → 匿名结构体 {T1, T2, ...}(多返回值打包, - # 对齐 TPC LLVMTypeMapper._resolve_subscript 的 '{ ty1, ty2 }')。 - # 用于函数 `-> tuple[str, t.CUnsignedShort]`(如 binascii.b2a_hqx) - # 与调用端 `a, b = f()` 的打包/解包。 - if string.strcmp(gen_cls_name, "tuple") == 0: - tp_elts: list[ast.AST | t.CPtr] | t.CPtr = None - tp_count: t.CSizeT = 0 - if sub.slice.kind() == ast.ASTKind.Tuple: - tp_tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice) - if tp_tup.elts is not None: - tp_elts = tp_tup.elts - tp_count = len(tp_elts) - else: - tp_single: list[ast.AST | t.CPtr] | t.CPtr = list[ast.AST | t.CPtr](pool, 1) - if tp_single is not None: - tp_single.append(sub.slice) - tp_elts = tp_single - tp_count = 1 - if tp_count == 0 or tp_elts is None: - return None - tup_head: llvmlite.ParamNode | t.CPtr = None - tup_tail: llvmlite.ParamNode | t.CPtr = None - tui: t.CSizeT - for tui in range(tp_count): - tup_elt: ast.AST | t.CPtr = tp_elts.get(tui) - if tup_elt is None: - continue - tup_ety: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( - pool, tup_elt, imported_modules, from_imports, trans) - if tup_ety is None: - return None - tup_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, tup_ety) - if tup_node is None: - return None - if tup_head is None: - tup_head = tup_node - else: - llvmlite.paramnode_set_next(tup_tail, tup_node) - tup_tail = tup_node - if tup_head is None: - return None - return llvmlite.Struct(pool, tup_head, tp_count, None) - # 先收集类型实参名,再分配缓冲区拼接 mangled name(elem_size=8:str 是指针) - gen_arg_names: list[str] | t.CPtr = list[str](pool, 8) - if sub.slice.kind() == ast.ASTKind.Tuple: - gen_tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice) - gen_elts: list[ast.AST | t.CPtr] | t.CPtr = gen_tp.elts - if gen_elts is not None: - gen_en: t.CSizeT = len(gen_elts) - gen_ei: t.CSizeT - for gen_ei in range(gen_en): - gen_elt: ast.AST | t.CPtr = gen_elts.get(gen_ei) - gen_tn: str = self._get_type_name_from_annotation(pool, gen_elt) - gen_arg_names.append(gen_tn) - else: - gen_tn_single: str = self._get_type_name_from_annotation(pool, sub.slice) - gen_arg_names.append(gen_tn_single) - # 计算总长度并分配缓冲区 - gen_total: t.CSizeT = string.strlen(gen_cls_name) + 2 # "[" 和 "]" - gen_an: t.CSizeT = len(gen_arg_names) - gen_ai: t.CSizeT - for gen_ai in range(gen_an): - if gen_ai > 0: - gen_total += 1 # "," - gen_atn: str = gen_arg_names.get(gen_ai) - if gen_atn is not None: - gen_total += string.strlen(gen_atn) - gen_total += 1 # NUL - gen_mangled: str = pool.alloc(gen_total) - if gen_mangled is None: - return None - gen_mangled[0] = '\0' - string.strcat(gen_mangled, gen_cls_name) - string.strcat(gen_mangled, "[") - for gen_ai in range(gen_an): - if gen_ai > 0: - string.strcat(gen_mangled, ",") - gen_atn: str = gen_arg_names.get(gen_ai) - if gen_atn is not None: - string.strcat(gen_mangled, gen_atn) - string.strcat(gen_mangled, "]") - # 查找已特化的 struct(特化由实例化调用 list[int](pool) 触发) - gen_spec_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(gen_mangled) - if gen_spec_ty is not None: - # 治本修复:Phase B 补译泛型特化类方法体 - # Phase 1a(declare_only==1)特化时只注册结构体不译方法体(MethodsEmitted==0), - # Phase B(declare_only==0)解析字段类型命中已注册结构体时本会早返回, - # 导致方法体永远不生成 → GSList[Line].append 等符号只有 declare 无 define → 链接失败。 - # 此处 Phase B 且方法体未译时,调用 _specialize_generic_class 走其已注册分支补译方法体。 - if trans is not None and trans._declare_only == 0: - import lib.core.Handles.HandlesClassDef as HandlesClassDef - gen_spec_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(gen_mangled) - if gen_spec_entry is not None and gen_spec_entry.MethodsEmitted == 0: - # 错误定位:压入触发特化的调用方帧(注解所在文件+行号), - # 使特化方法体报错(如参数类型解析失败)能追溯到用户代码 - # (如 devfs copy.vp 的 list[devfs_directory,MAX_DIRECTORIES] 注解) - gen_cur_f: str = HandlesType.get_current_file() - HandlesType.push_trace(gen_cur_f, sub.lineno) - HandlesClassDef._specialize_generic_class(trans, gen_cls_name, gen_arg_names) - HandlesType.pop_trace() - return gen_spec_ty - # 未特化:尝试主动触发泛型特化(与 TPC _HandleSubscript 对齐) - # 当 trans 可用时,检查是否是泛型模板并触发特化 - if trans is not None: - import lib.core.Handles.HandlesClassDef as HandlesClassDef - import lib.core.Handles.HandlesExprCall as HandlesExprCall - template_cd_chk: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(gen_cls_name) - if template_cd_chk is not None: - type_args_chk: list[str] | t.CPtr = HandlesExprCall._extract_type_args_from_slice( - pool, sub.slice) - if type_args_chk is not None and len(type_args_chk) > 0: - # 错误定位:压入触发特化的调用方帧(注解所在文件+行号) - gen_cur_f2: str = HandlesType.get_current_file() - HandlesType.push_trace(gen_cur_f2, sub.lineno) - spec_name_chk: str = HandlesClassDef._specialize_generic_class( - trans, gen_cls_name, type_args_chk) - HandlesType.pop_trace() - if spec_name_chk is not None: - gen_spec_ty = HandlesStruct.get_struct_type(gen_mangled) - if gen_spec_ty is not None: - return gen_spec_ty - # 未特化:返回 None(不报错,让后续流程处理) - return None - - def resolve_annotation_type(self, pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr, - imported_modules: str, - from_imports: str, - trans: HT.Translator | t.CPtr = None) -> llvmlite.LLVMType | t.CPtr: - """解析类型注解节点为 LLVMType - - Args: - pool: 内存分配器 - node: 类型注解 AST 节点(Name 或 Attribute) - imported_modules: 已导入模块名字符串(空格分隔) - from_imports: from-import 映射字符串("name:module name:module" 格式) - trans: 翻译器对象(可选,用于触发泛型特化) - """ - if node is None: - return None - - k: int = node.kind() - - # Constant 节点: 字符串注解(如 'MemManager'),当作无引号的 Name/Attribute/BinOp 处理 - if k == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) - # -> None 无返回值注解 → Void(追加89:-> None 被 parser 解析为 - # CONST_NONE 常量而非 Name('None'),此前直接 return None → ret_ty - # 回退 i32 → 掉出末尾被 fail-fast 误杀,BuildPipeline.set_asan_mode - # "依旧"根因;Name 分支的 "None" 归一为字符串注解形式的双保险) - if cn.const_kind == ast.CONST_NONE: - return llvmlite.Void(pool) - if cn.const_kind == ast.CONST_STR and cn.str_val is not None: - sub_node: ast.AST | t.CPtr = self._parse_type_string(pool, cn.str_val, ast.ASTCtx.Load) - if sub_node is not None: - return self.resolve_annotation_type(pool, sub_node, imported_modules, from_imports, trans) - return None - - # Name 节点: str, int, bytes, from-import 名称, class 名称等 - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm.id is None: - return None - # 泛型类型参数 T 替换:在泛型特化上下文中,将 T 替换为具体类型 - if self.GenericTpNames is not None and self.GenericTypeArgs is not None: - gp_n: t.CSizeT = len(self.GenericTpNames) - gp_i: t.CSizeT - for gp_i in range(gp_n): - gp_tpn: str = self.GenericTpNames.get(gp_i) - if gp_tpn is not None and string.strcmp(nm.id, gp_tpn) == 0: - gp_ta: str = self.GenericTypeArgs.get(gp_i) - if gp_ta is not None: - # 自映射/污染实参防护(泛型循环套用): - # 1) 实参与参数名完全一致(T→T) - # 2) 实参串包含任一类型参数名(如 "T | t.CPtr"、" T "、 - # "list[T]")——_parse_type_string 解析后仍会产出 - # Name(参数名) → 递归再次进入本分支 → 无条件自递归 - # 无退出条件 → 编译卡死。该递归不经 _specialize_generic_class - # 的深度守卫(GenericSpecDepth),必须在此拦截。 - # 直接返回 None 让上层回落(fail-fast:宁可类型退化 - # 也不静默卡死)。 - if string.strcmp(gp_ta, gp_tpn) == 0: - return None - polluted: int = 0 - gp_j: t.CSizeT - for gp_j in range(gp_n): - gp_pn: str = self.GenericTpNames.get(gp_j) - if gp_pn is not None and string.strstr(gp_ta, gp_pn) is not None: - polluted = 1 - break - if polluted != 0: - return None - # 用具体类型名递归解析(支持 BinOp/Attribute 类型实参) - gp_sub_node: ast.AST | t.CPtr = self._parse_type_string(pool, gp_ta, nm.ctx) - if gp_sub_node is not None: - return self.resolve_annotation_type(pool, gp_sub_node, imported_modules, from_imports, trans) - # str = bytes = str = i8* - if string.strcmp(nm.id, "str") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - # -> None 无返回值注解 → Void(追加89:与 VpiReader "None"→Void - # 归一对齐;缺失时 -> None 解析失败回退 i32,函数掉出末尾被 - # fail-fast 误杀,BuildPipeline.set_asan_mode 根因) - elif string.strcmp(nm.id, "None") == 0: - return llvmlite.Void(pool) - elif string.strcmp(nm.id, "int") == 0: - return llvmlite.Int32(pool) - elif string.strcmp(nm.id, "bytes") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - elif string.strcmp(nm.id, "bool") == 0: - # bool = t.CBool = i1(与 map_t_type 中 CBool 映射一致) - return llvmlite.Int1(pool) - # 裸名浮点类型: float = t.CFloat = f32, double = t.CDouble = f64 - elif string.strcmp(nm.id, "float") == 0: - return llvmlite.Float(pool) - elif string.strcmp(nm.id, "double") == 0: - return llvmlite.Double(pool) - # class 名称: 查找已注册的 StructType,返回 StructType 本身(不包装 Ptr) - # 这样 build_alloca 会分配结构体大小的空间,alloca 返回 struct_ty* - # 命名空间隔离:严格模式下仅解析可见的结构体 - # 跨模块同名类优先:当前模块自身定义了同名类时,用 find_struct_by_module - # 命中本模块的类(如 main.vp 的 G5Node 不再被 g5container.vp 预注册的 - # G5Node 顶掉,避免 alloca 用本模块类型、load 用他模块类型的混用)。 - # 本模块未定义时回退按裸名全局查找(import 来的类走此路径)。 - if trans is not None and trans.ModuleSha1 is not None: - own_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module(nm.id, trans.ModuleSha1) - if own_entry is not None and own_entry.Ty is not None: - # 有 __new__ 的类(堆对象)注解 → Ptr(struct)(引用语义,对齐 TPC)。 - # 否则无 __new__ 的类(栈对象,如 Point)保持 struct 值语义: - # 构造返回栈 alloca 指针,赋给 struct 值变量时 coerce load 拷贝。 - # 背景:d: dict = dict(bd) 的 dict 是堆对象(__new__ 分配), - # 裸名注解按值解析会让 sub: dict = sub_p 把 i8* 当 struct 解引用 - # 崩溃(DictTest Test 13)。 - if own_entry.HasNew != 0: - return llvmlite.Ptr(pool, own_entry.Ty) - return own_entry.Ty - if HandlesStruct.is_struct_visible(nm.id) != 0: - struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(nm.id) - if struct_ty is not None: - nm_entry_s: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) - nm_has_new_s: int = 0 - if nm_entry_s is not None: - nm_has_new_s = nm_entry_s.HasNew - if nm_has_new_s != 0: - return llvmlite.Ptr(pool, struct_ty) - return struct_ty - # 枚举类(t.CEnum)裸名注解 → 底层整数类型 - # 如 fat32_types.vp 内部 `res: FRESULT = ...`(FRESULT 是枚举非结构体) - if HandlesEnum.is_enum_class(nm.id) == 1: - return HandlesEnum.get_enum_base_type(nm.id) - # CTypedef 动态查表:查动态 CTypedef 表,递归解析类型表达式 - # 用户自定义 CTypedef(如 MyHandle: t.CTypedef = VOIDPTR)在此解析 - # 递归深度限制 MAX_CTYPEDEF_DEPTH 防止无限递归,循环检测防止 A→B→A - if self.CTypedefResolveDepth < MAX_CTYPEDEF_DEPTH: - ctypedef_str: str = self.lookup_ctypedef(nm.id) - if ctypedef_str is not None and self.CTypedefFound != 0: - # 循环检测:将当前 CTypedef 名加入正在解析列表 - if self._ctypedef_push_visiting(pool, nm.id) == 0: - # 用 _parse_type_string 把类型字符串转回 AST,递归解析 - inner_node: ast.AST | t.CPtr = self._parse_type_string(pool, ctypedef_str, nm.ctx) - if inner_node is not None: - self.CTypedefResolveDepth += 1 - inner_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( - pool, inner_node, imported_modules, from_imports, trans) - self.CTypedefResolveDepth -= 1 - self._ctypedef_pop_visiting() - if inner_ty is not None: - return inner_ty - else: - self._ctypedef_pop_visiting() - # 兜底: 尝试 map_t_type 中的硬编码 typedef 映射(VOIDPTR, HANDLE, ULONG 等) - # 这些是跨模块通用的 C typedef 名,即使 from-import 查找失败也能解析 - # 注意:from-import 的结构体名若未注册,get_struct_type 已返回 None, - # 此处 map_t_type 对结构体名也返回 None,由上层 declare_only 机制延迟到下一遍 - mapped_ty_fallback: llvmlite.LLVMType | t.CPtr = self.map_t_type(pool, nm.id) - if mapped_ty_fallback is not None: - return mapped_ty_fallback - return None - - # Attribute 节点: t.CInt, t.CUInt64T, namespace_defs.PlainStruct 等 - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at.attr is None: - return None - # 检查 value 是否是 Name('t') 或 Name('c') - if at.value is not None and at.value.kind() == ast.ASTKind.Name: - val_name: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if val_name.id is not None: - # t/c 是内建库(SHA1 豁免),显式写 t.XXX 即确指内建库, - # 不依赖 imported_modules(t 可能不在其中,如 vpi 注入上下文) - is_builtin_attr: int = 0 - if string.strcmp(val_name.id, "t") == 0 or string.strcmp(val_name.id, "c") == 0: - is_builtin_attr = 1 - if is_builtin_attr == 0: - mod_imp: int = HandlesImports.is_module_imported(imported_modules, val_name.id) - if mod_imp == 0: - return None - # 先尝试内置类型映射(int 等) - mapped_ty: llvmlite.LLVMType | t.CPtr = self.map_t_type(pool, at.attr) - if mapped_ty is not None: - return mapped_ty - # 模块限定类类型:Module.ClassName(命名空间隔离) - mod_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(at.attr) - if mod_struct_ty is not None: - return mod_struct_ty - # 模块限定枚举类型:Module.EnumClass(如 fat32_types.FRESULT, - # t.CEnum 枚举类非结构体,get_struct_type 查不到) - if HandlesEnum.is_enum_class(at.attr) == 1: - return HandlesEnum.get_enum_base_type(at.attr) - # 模块限定 typedef(posix.DIR = t.CTypedef = t.CVoid|t.CPtr 等): - # 与 Name 分支(L1986-2009)同一套 lookup_ctypedef + 递归解析。 - # 追加20只补了嵌套 Attribute(mod.sub.Typedef);单层 - # Module.Typedef(value=Name 非 t/c)同样缺失——shutil.vp - # L190 `dirp: posix.DIR` 变量注解解析失败根因。 - if self.CTypedefResolveDepth < MAX_CTYPEDEF_DEPTH: - mod_td_str: str = self.lookup_ctypedef(at.attr) - if mod_td_str is not None and self.CTypedefFound != 0: - if self._ctypedef_push_visiting(pool, at.attr) == 0: - mod_td_inner: ast.AST | t.CPtr = self._parse_type_string( - pool, mod_td_str, at.ctx) - if mod_td_inner is not None: - self.CTypedefResolveDepth += 1 - mod_td_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( - pool, mod_td_inner, imported_modules, from_imports, trans) - self.CTypedefResolveDepth -= 1 - self._ctypedef_pop_visiting() - if mod_td_ty is not None: - return mod_td_ty - else: - self._ctypedef_pop_visiting() - return None - # 嵌套 Attribute: w32.win32base.SECURITY_ATTRIBUTES 等三级及以上限定名 - # at.value 是 Attribute 而非 Name,递归提取最终类名(at.attr)查结构体表 - # find_struct 支持模块限定名回退,此处用最外层 attr(简单类名)即可 - if at.value is not None and at.value.kind() == ast.ASTKind.Attribute: - nested_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(at.attr) - if nested_struct_ty is not None: - return nested_struct_ty - # 嵌套模块限定的枚举类(fat32_types.FRESULT 三级名):查枚举基类型 - if HandlesEnum.is_enum_class(at.attr) == 1: - return HandlesEnum.get_enum_base_type(at.attr) - # 嵌套模块限定的 typedef(w32.win32base.HANDLE = t.CTypedef = VOIDPTR): - # 与 Name 分支(L1986-2009)同一套 lookup_ctypedef + 递归 + map_t_type 兜底。 - # 此前只查 struct/enum → w32.win32base.HANDLE 解析失败(fail-fast 报 - # NameError: 'w32.win32base.HANDLE' is not defined,FileIoTest 根因)。 - if self.CTypedefResolveDepth < MAX_CTYPEDEF_DEPTH: - nested_td_str: str = self.lookup_ctypedef(at.attr) - if nested_td_str is not None and self.CTypedefFound != 0: - if self._ctypedef_push_visiting(pool, at.attr) == 0: - nested_inner: ast.AST | t.CPtr = self._parse_type_string( - pool, nested_td_str, at.ctx) - if nested_inner is not None: - self.CTypedefResolveDepth += 1 - nested_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( - pool, nested_inner, imported_modules, from_imports, trans) - self.CTypedefResolveDepth -= 1 - self._ctypedef_pop_visiting() - if nested_ty is not None: - return nested_ty - else: - self._ctypedef_pop_visiting() - mapped_ty_na: llvmlite.LLVMType | t.CPtr = self.map_t_type(pool, at.attr) - if mapped_ty_na is not None: - return mapped_ty_na - return None - - # BinOp 节点: 联合类型注解 A | B - # 处理三种语义: - # 1. ActualType | t.CPtr → Ptr(ActualType)(指针包装,如 MemBuddy | t.CPtr → MemBuddy*) - # 2. t.CVoid | t.CPtr → i8* (void* 等价于 i8*) - # 3. ActualType | DecoratorMarker → ActualType(忽略装饰器标记如 CExport/CExtern) - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - if bop.op == ast.OpKind.BitOr: - # 检测 t.CPtr 标记(指针包装标记,支持 t.CPtr 与 from t import CPtr 裸名) - left_is_cptr: int = self._is_cptr_marker(bop.left, imported_modules) - right_is_cptr: int = self._is_cptr_marker(bop.right, imported_modules) - if left_is_cptr != 0 or right_is_cptr != 0: - # 有 CPtr 标记:解析非 CPtr 一边的实际类型,包装为 Ptr - # left 是 CPtr → other 是 right;right 是 CPtr → other 是 left - other_node: ast.AST | t.CPtr = bop.left - if left_is_cptr != 0: - other_node = bop.right - # 检测另一边是否是 t.CVoid (void* = i8*) - # 严格验证完整形式(Attribute(t.CVoid) 的 value 是 Name("t"), - # 或裸名 CVoid 且 t 已导入),防止解析异常节点被误判为 CVoid。 - other_is_cvoid: int = 0 - if other_node is not None: - if other_node.kind() == ast.ASTKind.Attribute: - oat2: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(other_node) - if oat2.attr is not None and string.strcmp(oat2.attr, "CVoid") == 0: - if oat2.value is not None and oat2.value.kind() == ast.ASTKind.Name: - ov2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(oat2.value) - if ov2.id is not None and string.strcmp(ov2.id, "t") == 0: - other_is_cvoid = 1 - elif other_node.kind() == ast.ASTKind.Name: - onm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(other_node) - if onm2.id is not None and string.strcmp(onm2.id, "CVoid") == 0: - if HandlesImports.is_module_imported(imported_modules, "t") != 0: - other_is_cvoid = 1 - if other_is_cvoid != 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - other_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( - pool, other_node, imported_modules, from_imports, trans) - # 仅裸名(Name)场景验证解析结果必须是已注册 struct: - # 损坏节点可能解析出基础类型垃圾(如 Int8 → Ptr(i8))。 - # Attribute 场景(Module.Class / t.XXX)resolve 结果直接可用 - # (如 t.CUInt64T → i64、memhub.MemBuddy → MemBuddy*), - # 不得踢进 fallback——否则按 Name 布局读 Attribute 字段会得到 - # 垃圾类名,字段类型错误(如 free_lists 从 i64* 变 i8*)导致 - # 运行时 GEP 步长错误崩溃。 - other_is_name: int = 0 - if other_node is not None and other_node.kind() == ast.ASTKind.Name: - other_is_name = 1 - if other_ty is not None and other_is_name != 0: - if HandlesStruct.find_struct_by_type(other_ty) is None: - # 泛型类型参数(T→int 等)经上下文替换解析出的合法标量 - # 必须保留——"Name 且未注册 struct 即丢弃"本为拦截损坏 - # 节点解析出基础类型垃圾,但会误杀泛型替换的合法标量, - # 导致 T | t.CPtr(T=int)退化为 i8*:list[int] elem_ptr - # 按 8 字节槽写、elem_size=4 步长读 → 元素互相覆盖, - # pop 读到 0(ListTest 根因)。泛型参数名放行。 - keep_other_ty: int = 0 - if self.GenericTpNames is not None: - other_nm_x: ast.Name | t.CPtr = (ast.Name | t.CPtr)(other_node) - gtn_nx: t.CSizeT = len(self.GenericTpNames) - gtn_ix: t.CSizeT - for gtn_ix in range(gtn_nx): - gtn_nmx: str = self.GenericTpNames.get(gtn_ix) - if gtn_nmx is not None and other_nm_x.id is not None: - if string.strcmp(gtn_nmx, other_nm_x.id) == 0: - keep_other_ty = 1 - break - # 内建标量类型名(int/str/bytes/bool/float/double)是合法 - # 标量,不是损坏节点解析出的垃圾:int | t.CPtr 应解析为 - # i32*(int 指针),若按"Name 未注册 struct 即丢弃"踢掉 - # int → 联合退化为 i8* → int_ptr[0]=val 写 1 字节截断、 - # 读回符号扩展(DictTest key5=500 读出 -12 根因)。 - if keep_other_ty == 0 and other_node is not None and other_node.kind() == ast.ASTKind.Name: - other_nm_b: ast.Name | t.CPtr = (ast.Name | t.CPtr)(other_node) - if other_nm_b.id is not None: - if string.strcmp(other_nm_b.id, "int") == 0 or \ - string.strcmp(other_nm_b.id, "str") == 0 or \ - string.strcmp(other_nm_b.id, "bytes") == 0 or \ - string.strcmp(other_nm_b.id, "bool") == 0 or \ - string.strcmp(other_nm_b.id, "float") == 0 or \ - string.strcmp(other_nm_b.id, "double") == 0: - keep_other_ty = 1 - if keep_other_ty == 0: - other_ty = None - if other_ty is None: - # 严格模式(App 文件)下裸类名不可见时,回退到全局 - # struct 注册表按类名查找。X | t.CPtr 是明确的指针包装 - # 注解(如 vpi stub 的 "ParsedArgs | t.CPtr"),X 已注册 - # 时不应静默退化为 i8*——i8* 会让方法返回值的无注解变量 - # (如 args = parser.parse_args())类型退化,后续 obj.method - # get_class_name_by_type 查不到类名,误报 - # "跨模块调用 'args.get_str' 找不到模块 SHA1"。 - # 仅裸名(Name)场景回退:Attribute 场景 resolve 已成功。 - other_cls_nm: str = None - if other_node is not None and other_node.kind() == ast.ASTKind.Name: - other_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(other_node) - if other_nm.id is not None: - other_cls_nm = other_nm.id - if other_cls_nm is not None: - other_cls_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(other_cls_nm) - if other_cls_ty is not None: - return llvmlite.Ptr(pool, other_cls_ty) - # 类名未注册:可能是前向自我引用(如 json 的 - # 'JsonValue' | t.CPtr 字段引用自身类,类体处理中 - # 尚未注册)或 Phase A-pre 依赖类延迟到下一遍注册。 - # 回退 Ptr(i8) 由 AnnotClassName 恢复 + 多遍注册收敛 - # 处理,禁止 fail-fast(误杀合法前向引用)。 - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - return llvmlite.Ptr(pool, other_ty) - - # t.CPtr[...] 下标指针标记(t.CPtr[T] 非普通 CPtr 标记,_is_cptr_marker - # 不识别 Subscript): X | t.CPtr[T] → 指针层级合并(对齐 TPC 联合合并 - # 规则 HandlesTypeMerge.py L864-884:CPtr 侧贡献 PtrCount,另一侧提供 - # BaseType)。如 t.CUInt8T | t.CPtr[t.CPtr] → u8**。此前左右都不是 - # CPtr 标记 → 落下方"无 CPtr 标记"分支返回左值 i8 → c.Deref(out) 报 - # "参数不是指针类型"(zdeflate.vp compress out 根因)。 - cptr_sub_side: ast.AST | t.CPtr = None - cptr_other: ast.AST | t.CPtr = None - if self._is_cptr_subscript(bop.left) != 0: - cptr_sub_side = bop.left - cptr_other = bop.right - elif self._is_cptr_subscript(bop.right) != 0: - cptr_sub_side = bop.right - cptr_other = bop.left - if cptr_sub_side is not None and cptr_other is not None: - cptr_sub_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( - pool, cptr_sub_side, imported_modules, from_imports, trans) - cptr_other_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( - pool, cptr_other, imported_modules, from_imports, trans) - if cptr_sub_ty is not None and cptr_other_ty is not None: - # 计算 CPtr 侧外层 Ptr 嵌套数(如 t.CPtr[t.CPtr]=i8** → 2 层) - cptr_level: int = 0 - cur_lvl: llvmlite.LLVMType | t.CPtr = cptr_sub_ty - while cur_lvl is not None: - match cur_lvl: - case llvmlite.LLVMType.Ptr(_): - cptr_level += 1 - cur_lvl = cur_lvl.Pointee - case _: - break - # 结果 = 另一侧类型外包 N 层 Ptr - res_ty: llvmlite.LLVMType | t.CPtr = cptr_other_ty - li2: int = 0 - while li2 < cptr_level: - res_ty = llvmlite.Ptr(pool, res_ty) - li2 += 1 - return res_ty - - # 无 CPtr 标记:返回第一个非 None(装饰器标记如 CExport/CExtern 被忽略) - left_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( - pool, bop.left, imported_modules, from_imports, trans) - if left_ty is not None: - return left_ty - right_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( - pool, bop.right, imported_modules, from_imports, trans) - if right_ty is not None: - return right_ty - return None - - # Subscript 节点: t.CArray[elem_ty, count] → [count x elem_ty] - # t.CArray[elem_ty] → Ptr(elem_ty)(静态推导长度数组) - # list[int] → 特化类 struct type(泛型类类型注解) - # value 是 Attribute(Name('t'), 'CArray') 或 Name('list')(泛型类) - # slice 是 Tuple(elts=[elem_ty_node, count_node]) 或单 elem_ty_node - if k == ast.ASTKind.Subscript: - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - if sub.value is None or sub.slice is None: - self.fatal_type_error(node, "Subscript 节点缺少 value 或 slice") - # 泛型类类型注解: list[int] → 查找已特化的 struct(value 是 Name 泛型类名) - if sub.value.kind() == ast.ASTKind.Name: - gen_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) - if gen_nm.id is not None: - # 裸名 CArray(from t import * 场景,如 core.vp 的 - # `__python_suffix__: CArray[str] = ["py", ...]`):与 t.CArray - # 语义等价。否则走泛型模板查找失败(CArray 不是泛型类模板)→ - # 字段类型退化 Ptr(i8) → __before_init__ 默认值 List 字面量误走 - # 动态 list 构造(list[str].__new__/append 符号未生成 → 链接 - # undefined reference,Termination4K3 链接失败根因)。 - if string.strcmp(gen_nm.id, "CArray") == 0: - # 单参数: CArray[elem_ty] → Ptr(elem_ty)(静态推导长度数组) - if sub.slice.kind() != ast.ASTKind.Tuple: - elem_n: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( - pool, sub.slice, imported_modules, from_imports, trans) - if elem_n is None: - return None - return llvmlite.Ptr(pool, elem_n) - # 双参数: CArray[elem_ty, count] → [count x elem_ty] - tup_n: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice) - if tup_n.elts is None or len(tup_n.elts) < 2: - return None - elem_node_n: ast.AST | t.CPtr = tup_n.elts.get(0) - count_node_n: ast.AST | t.CPtr = tup_n.elts.get(1) - if elem_node_n is None or count_node_n is None: - return None - elem_ty_n: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( - pool, elem_node_n, imported_modules, from_imports, trans) - if elem_ty_n is None: - return None - # count=None → Ptr(elem)(等价单参) - if count_node_n.kind() == ast.ASTKind.Constant: - cnt_n: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(count_node_n) - if cnt_n.const_kind == ast.CONST_NONE: - return llvmlite.Ptr(pool, elem_ty_n) - count_n: int = self._eval_const_int_expr( - count_node_n, pool, from_imports, imported_modules) - if self.ConstEvalOk == 0 or count_n <= 0: - return None - return llvmlite.Array(pool, elem_ty_n, count_n) - return self._resolve_generic_subscript_ty(pool, sub, gen_nm.id, trans, - imported_modules, from_imports) - # 检查 value 是否是 Attribute(t.CArray / t.Callable / 模块限定泛型类如 numpy.ndarray[T]) - if sub.value.kind() != ast.ASTKind.Attribute: - self.fatal_type_error(node, "不支持的 Subscript 类型注解(仅支持 t.CArray / t.Callable)") - arr_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sub.value) - if arr_at.attr is None: - self.fatal_type_error(node, "Subscript Attribute 缺少 attr") - # 模块限定泛型类: numpy.ndarray[t.CDouble] → 裸类名 ndarray 走泛型特化 - # (在 t.CArray / t.Callable 检查之前;模板已注册即视为泛型类) - if trans is not None: - import lib.core.Handles.HandlesClassDef as HandlesClassDef - if HandlesClassDef._find_generic_template(arr_at.attr) is not None: - return self._resolve_generic_subscript_ty(pool, sub, arr_at.attr, trans, - imported_modules, from_imports) - if arr_at.value is None or arr_at.value.kind() != ast.ASTKind.Name: - self.fatal_type_error(node, "t.CArray / t.Callable 必须通过模块名限定") - arr_val_name: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arr_at.value) - if arr_val_name.id is None: - self.fatal_type_error(node, "Subscript 模块名为 None") - # 函数指针类型: t.Callable[[A, B], Ret] → i8* - # 与 TPV 函数传指针惯例一致(函数值 bitcast 为 i8* 存储,调用时按实参重建签名) - if string.strcmp(arr_at.attr, "Callable") == 0: - if HandlesImports.is_module_imported(imported_modules, arr_val_name.id) == 0: - self.fatal_type_error(node, "t.Callable 模块未导入") - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - # 指针类型: t.CPtr[T] → Ptr(T)(指向 T 的指针,T 自身可含指针层级) - # t.CPtr[t.CPtr] → Ptr(Ptr(CPtr=i8*)) = i8**(双指针) - # t.CPtr[t.CInt] → i32*(DeclarationGenerator.py L1014-1016 文档化语法)。 - # 此前缺失 → t.CUInt8T | t.CPtr[t.CPtr] 联合退化为左值 i8 → - # c.Deref(out) 报"参数不是指针类型"(zdeflate.vp compress out 根因) - if string.strcmp(arr_at.attr, "CPtr") == 0: - if HandlesImports.is_module_imported(imported_modules, arr_val_name.id) == 0: - self.fatal_type_error(node, "t.CPtr 模块未导入") - inner_cptr_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( - pool, sub.slice, imported_modules, from_imports, trans) - if inner_cptr_ty is None: - self.fatal_type_error(sub.slice, "t.CPtr[?] 元素类型解析失败") - return llvmlite.Ptr(pool, inner_cptr_ty) - if string.strcmp(arr_at.attr, "CArray") != 0: - self.fatal_type_error(node, "不支持的 Subscript 类型注解(仅支持 t.CArray / t.Callable)") - if HandlesImports.is_module_imported(imported_modules, arr_val_name.id) == 0: - self.fatal_type_error(node, "t.CArray 模块未导入") - # 单参数形式: t.CArray[elem_ty] → Ptr(elem_ty) - # 相当于 t.CArray[elem_ty, None],表示静态推导长度数组 - if sub.slice.kind() != ast.ASTKind.Tuple: - elem_ty_single: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( - pool, sub.slice, imported_modules, from_imports, trans) - if elem_ty_single is None: - self.fatal_type_error(sub.slice, "t.CArray[?] 元素类型解析失败") - return llvmlite.Ptr(pool, elem_ty_single) - # 双参数形式: t.CArray[elem_ty, count] → [count x elem_ty] - tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice) - if tup.elts is None: - self.fatal_type_error(node, "t.CArray Tuple 缺少 elts") - elts_list: list[ast.AST | t.CPtr] | t.CPtr = tup.elts - elts_n: t.CSizeT = len(elts_list) - if elts_n < 2: - self.fatal_type_error(node, "t.CArray Tuple 元素不足") - elem_node: ast.AST | t.CPtr = elts_list.get(0) - count_node: ast.AST | t.CPtr = elts_list.get(1) - if elem_node is None or count_node is None: - self.fatal_type_error(node, "t.CArray Tuple 元素为 None") - # 递归解析元素类型 - elem_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( - pool, elem_node, imported_modules, from_imports, trans) - if elem_ty is None: - self.fatal_type_error(elem_node, "t.CArray 元素类型解析失败") - # 解析 count(支持整数常量、None、CDefine 常量名、常量表达式如 2*MAX) - # t.CArray[elem_ty, None] 等价于单参数形式 → Ptr(elem_ty) - # t.CArray[elem_ty, NAME] 其中 NAME: t.CDefine = value → [value x elem_ty] - # t.CArray[elem_ty, 2 * MAX] 常量表达式静态计算 → [2*MAX x elem_ty] - count_val: int = 0 - if count_node.kind() == ast.ASTKind.Constant: - cnt_cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(count_node) - if cnt_cn.const_kind == ast.CONST_NONE: - return llvmlite.Ptr(pool, elem_ty) - # 统一用 _eval_const_int_expr 计算常量整数表达式 - # 支持 Constant(INT)、Name(CDefine)、BinOp(2*MAX 等算术/位运算) - # 传入 pool/from_imports/imported_modules 支持跨模块 CDefine 查找 - # (如 SHA512_BLOCK_LEN 定义在 hashlib/__sha512.vp,当前模块表不含) - count_val = self._eval_const_int_expr(count_node, pool, from_imports, imported_modules) - if self.ConstEvalOk == 0: - self.fatal_type_error(count_node, "t.CArray count 必须是整数常量、None、CDefine 常量名或常量表达式") - if count_val <= 0: - self.fatal_type_error(count_node, "t.CArray count 必须为正数") - # 创建 ArrayType(不包装 Ptr) - # 这样 build_alloca 会分配数组大小的空间,alloca 返回 [N x elem_ty]* - return llvmlite.Array(pool, elem_ty, count_val) - - # 未知 AST kind:fail-fast,不宽容返回 None - self.fatal_type_error(node, "不支持的类型注解语法") - # 追加89 块设计:fatal_type_error 调用后补显式 return(运行时不可达, - # 保证方法末尾块被正确 terminated,不做 noreturn 函数名白名单) - return None - - def has_decorator_marker(self, node: ast.AST | t.CPtr, - marker_name: str) -> int: - """检测类型注解中是否包含指定的装饰器标记""" - if node is None or marker_name is None: - return 0 - - k: int = node.kind() - - # Attribute 节点: t.CExtern, t.State, t.CExport, t.CInline - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at.attr is not None: - if string.strcmp(at.attr, marker_name) == 0: - return 1 - return 0 - - # BinOp 节点: int | t.CExtern(递归检测左右子节点) - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - if self.has_decorator_marker(bop.left, marker_name) != 0: - return 1 - if self.has_decorator_marker(bop.right, marker_name) != 0: - return 1 - return 0 - - return 0 - - def is_pass_body(self, body: list[ast.AST | t.CPtr] | t.CPtr) -> int: - """检测函数体是否为 pass(空体或仅含 pass 语句)""" - if body is None: - return 1 - bn: t.CSizeT = len(body) - if bn == 0: - return 1 - if bn == 1: - stmt: ast.AST | t.CPtr = body.get(0) - if stmt is not None and stmt.kind() == ast.ASTKind.Pass: - return 1 - return 0 - - def get_llvm_type_bits(self, ty: llvmlite.LLVMType | t.CPtr) -> int: - """获取 LLVM 整数类型的位宽,非整数类型返回 0""" - if ty is None: - return 0 - match ty: - case llvmlite.LLVMType.Int(bits): - return bits - case _: - return 0 - - def infer_expr_type(self, pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr, - param_types: str) -> llvmlite.LLVMType | t.CPtr: - """推断表达式的 LLVM 类型 - - param_types 格式: "name:bits,name:bits,..." - """ - if node is None: - return llvmlite.Int32(pool) - - k: int = node.kind() - - if k == ast.ASTKind.Constant: - return llvmlite.Int32(pool) - - elif k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm.id is not None and param_types is not None: - # 在 param_types 中查找: "name:bits" 格式 - search_key: str = pool.alloc(64) - if search_key is not None: - viperlib.snprintf(search_key, 64, "%s:", nm.id) - found: str = string.strstr(param_types, search_key) - if found is not None: - colon_pos: t.CSizeT = string.strlen(nm.id) + 1 - bits_str: str = found + colon_pos - bits: int = 0 - for bi in range(4): - ch: t.CChar = bits_str[bi] - if ch >= '0' and ch <= '9': - bits = bits * 10 + (ch - '0') - else: - break - if bits == 64: - return llvmlite.Int64(pool) - elif bits == 16: - return llvmlite.Int16(pool) - elif bits == 8: - return llvmlite.Int8(pool) - return llvmlite.Int32(pool) - - elif k == ast.ASTKind.BinOp: - binop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - lhs_ty: llvmlite.LLVMType | t.CPtr = self.infer_expr_type( - pool, binop.left, param_types) - rhs_ty: llvmlite.LLVMType | t.CPtr = self.infer_expr_type( - pool, binop.right, param_types) - lhs_bits: int = self.get_llvm_type_bits(lhs_ty) - rhs_bits: int = self.get_llvm_type_bits(rhs_ty) - if lhs_bits >= rhs_bits: - return lhs_ty - return rhs_ty - - return llvmlite.Int32(pool) - - def infer_return_type(self, pool: memhub.MemBuddy | t.CPtr, - body: list[ast.AST | t.CPtr] | t.CPtr, - param_types: str) -> llvmlite.LLVMType | t.CPtr: - """扫描函数体中的 return 语句,推断返回类型""" - if body is None: - return llvmlite.Int32(pool) - - ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - bn: t.CSizeT = len(body) - for bi in range(bn): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None and stmt.kind() == ast.ASTKind.Return: - rt: ast.Return | t.CPtr = (ast.Return | t.CPtr)(stmt) - if rt.value is not None: - expr_ty: llvmlite.LLVMType | t.CPtr = self.infer_expr_type( - pool, rt.value, param_types) - if expr_ty is not None: - cur_bits: int = self.get_llvm_type_bits(ret_ty) - new_bits: int = self.get_llvm_type_bits(expr_ty) - if new_bits > cur_bits: - ret_ty = expr_ty - return ret_ty - - def build_param_types_str(self, pool: memhub.MemBuddy | t.CPtr, - args_node: ast.AST | t.CPtr) -> str: - """构建参数类型编码字符串 "name:bits,name:bits,..." """ - if args_node is None: - return None - ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) - if ags.args is None: - return None - alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args - an: t.CSizeT = len(alist) - if an == 0: - return None - - buf_size: t.CSizeT = an * 32 + 1 - buf: str = pool.alloc(buf_size) - if buf is None: - return None - buf[0] = '\0' - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - for ai in range(an): - arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) - if arg is not None and arg.arg is not None: - param_ty: llvmlite.LLVMType | t.CPtr = i32_ty - if arg.annotation is not None: - # 直接调用 map_t_type 解析 Attribute 注解 - if arg.annotation.kind() == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg.annotation) - if at.attr is not None: - resolved: llvmlite.LLVMType | t.CPtr = self.map_t_type(pool, at.attr) - if resolved is not None: - param_ty = resolved - bits: int = self.get_llvm_type_bits(param_ty) - if bits == 0: - bits = 32 - tmp: str = pool.alloc(32) - if tmp is not None: - viperlib.snprintf(tmp, 32, "%s:%d", arg.arg, bits) - if ai > 0: - self._strappend(buf, buf_size, ",") - self._strappend(buf, buf_size, tmp) - return buf - - def _strappend(self, dst: str, dst_size: t.CSizeT, src: str): - """将 src 追加到 dst 末尾""" - if dst is None or src is None: - return - dlen: t.CSizeT = string.strlen(dst) - slen: t.CSizeT = string.strlen(src) - remain: t.CSizeT = dst_size - dlen - if remain <= 0: - return - # 内联 min(slen, remain - 1) 避免 builtin min 未定义(TransPyV 无 builtin min) - limit: t.CSizeT = slen - cap: t.CSizeT = remain - 1 - if cap < limit: - limit = cap - for i in range(limit): - dst[dlen + i] = src[i] - dst[dlen + i] = '\0' +class TypeGenMixin(TypeGenBase.TypeGenBase): + """类型映射与解析 Mixin(阶段 D 拆分后顶层,方法全部在子 Mixin)""" diff --git a/App/lib/core/Gen/TypeGenResolve.vp b/App/lib/core/Gen/TypeGenResolve.vp new file mode 100644 index 0000000..b854d8b --- /dev/null +++ b/App/lib/core/Gen/TypeGenResolve.vp @@ -0,0 +1,1456 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import viperlib +import stdio +import stdlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprOps as HandlesExprOps +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesEnum as HandlesEnum +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.StubMerger as StubMerger +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.TypeGenBase as TypeGenBase + +# ============================================================ +# TypeGenResolve - TypeGenMixin 拆分(阶段 D):类型映射/注解解析(map_t_type/resolve_annotation_type 等) +# +# 继承 TypeGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesType 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class TypeGenResolve(TypeGenBase.TypeGenBase): + """类型映射/注解解析(map_t_type/resolve_annotation_type 等)""" + + def _get_type_name_from_annotation(self, pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr) -> str: + """从类型注解节点提取类型名(支持 Name/Attribute/BinOp)""" + if node is None: + return None + k: int = node.kind() + # Constant: 字符串注解,直接返回字符串值 + if k == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + if cn.const_kind == ast.CONST_STR and cn.str_val is not None: + return cn.str_val + return None + # Name: 直接返回 id(泛型特化上下文内先做 T 替换,避免 ndarray[T] 中 T 未解析 + # 导致 _specialize_generic_class("ndarray", ["T"]) 二次递归崩溃) + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + return HandlesType.resolve_generic_type_name(nm.id) + # Attribute: 构造 "module.attr" 格式 + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at.attr is None: + return None + if at.value is not None and at.value.kind() == ast.ASTKind.Name: + mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if mod_nm.id is not None: + total: t.CSizeT = string.strlen(mod_nm.id) + 1 + string.strlen(at.attr) + 1 + buf: str = pool.alloc(total) + if buf is not None: + buf[0] = '\0' + string.strcat(buf, mod_nm.id) + string.strcat(buf, ".") + string.strcat(buf, at.attr) + return buf + return at.attr + # BinOp (BitOr): 构造 "left|right" 格式 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if bop.op == ast.OpKind.BitOr: + left_str: str = self._get_type_name_from_annotation(pool, bop.left) + right_str: str = self._get_type_name_from_annotation(pool, bop.right) + if left_str is not None and right_str is not None: + total2: t.CSizeT = string.strlen(left_str) + 1 + string.strlen(right_str) + 1 + buf2: str = pool.alloc(total2) + if buf2 is not None: + buf2[0] = '\0' + string.strcat(buf2, left_str) + string.strcat(buf2, "|") + string.strcat(buf2, right_str) + return buf2 + return None + return None + def _parse_type_string(self, pool: memhub.MemBuddy | t.CPtr, + type_str: str, + ctx: t.CInt) -> ast.AST | t.CPtr: + """将类型名字符串解析为 AST 节点 + + 正确处理 '|' 与 '.' 周围的空格(如 "ParsedArgs | t.CPtr"): + - '|' 分割后左段可能带尾随空格("ParsedArgs "),右段可能带前导空格(" t.CPtr") + - 段内空格会导致 Name.id 带空格("ParsedArgs "、" t"),结构体/模块按名查找失败, + 最终退化 i8*/i32,如 parse_args -> "ParsedArgs | t.CPtr" 解析出垃圾类型。 + """ + if type_str is None or pool is None: + return None + + # 跳过前导空格('|' 分割后的右段可能带前导空格) + while type_str[0] == ' ': + type_str += 1 + + seg_len: t.CSizeT = string.strlen(type_str) + # 去除段尾随空格('|' 分割后的左段可能带尾随空格) + while seg_len > 0 and type_str[seg_len - 1] == ' ': + seg_len -= 1 + + # 检查是否包含 | (BinOp):只在有效段 [0, seg_len) 内查找 + pipe_idx: t.CSizeT = seg_len + pi: t.CSizeT = 0 + while pi < seg_len: + if type_str[pi] == '|': + pipe_idx = pi + break + pi += 1 + if pipe_idx < seg_len: + # 左段复制到独立缓冲(trim 尾随空格),不破坏原字符串 + left_len: t.CSizeT = pipe_idx + while left_len > 0 and type_str[left_len - 1] == ' ': + left_len -= 1 + left_buf: bytes = stdlib.malloc(left_len + 1) + if left_buf is None: + return None + string.strncpy(left_buf, type_str, left_len) + left_buf[left_len] = '\0' + left_node: ast.AST | t.CPtr = self._parse_type_string(pool, left_buf, ctx) + # 右段前导空格由递归入口跳过 + right_node: ast.AST | t.CPtr = self._parse_type_string( + pool, type_str + pipe_idx + 1, ctx) + stdlib.free(left_buf) + if left_node is not None and right_node is not None: + return ast.BinOp(pool, left_node, ast.OpKind.BitOr, right_node) + return None + + # 检查是否包含 . (Attribute):只在有效段 [0, seg_len) 内查找 + dot_idx: t.CSizeT = seg_len + di: t.CSizeT = 0 + while di < seg_len: + if type_str[di] == '.': + dot_idx = di + break + di += 1 + if dot_idx < seg_len: + # 模块名段 trim 尾随空格 + mod_len: t.CSizeT = dot_idx + while mod_len > 0 and type_str[mod_len - 1] == ' ': + mod_len -= 1 + mod_buf: bytes = stdlib.malloc(mod_len + 1) + if mod_buf is None: + return None + string.strncpy(mod_buf, type_str, mod_len) + mod_buf[mod_len] = '\0' + module_node: ast.AST | t.CPtr = ast.Name(pool, mod_buf, ctx) + # attr 段 trim 尾随空格 + attr_str: str = type_str + dot_idx + 1 + attr_len: t.CSizeT = string.strlen(attr_str) + while attr_len > 0 and attr_str[attr_len - 1] == ' ': + attr_len -= 1 + attr_buf: bytes = stdlib.malloc(attr_len + 1) + if attr_buf is None: + stdlib.free(mod_buf) + return None + string.strncpy(attr_buf, attr_str, attr_len) + attr_buf[attr_len] = '\0' + attr_node: ast.AST | t.CPtr = ast.Attribute(pool, module_node, attr_buf, ctx) + stdlib.free(mod_buf) + stdlib.free(attr_buf) + return attr_node + + # 普通 Name(trim 尾随空格,ast.Name 内部 _copy_str 复制) + name_buf: bytes = stdlib.malloc(seg_len + 1) + if name_buf is None: + return None + string.strncpy(name_buf, type_str, seg_len) + name_buf[seg_len] = '\0' + name_node: ast.AST | t.CPtr = ast.Name(pool, name_buf, ctx) + stdlib.free(name_buf) + return name_node + def set_current_file(self, file_path: str): + """设置当前编译的文件名(供报错使用)""" + self.CurrentFile = file_path + def get_current_file(self) -> str: + """获取当前编译的文件名(供报错归因使用)""" + return self.CurrentFile + def map_t_type(self, pool: memhub.MemBuddy | t.CPtr, + type_name: str) -> llvmlite.LLVMType | t.CPtr: + """将 t.CXxx / c.CXxx 类型名映射到 LLVMType + + 注意: str = i8* = str = bytes + """ + if type_name is None: + return None + + # 基本整数类型 + if string.strcmp(type_name, "CInt") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "CChar") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "CShort") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "CLong") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "CLongLong") == 0: + return llvmlite.Int64(pool) + # 精确宽度有符号类型 + elif string.strcmp(type_name, "CInt8T") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "CInt16T") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "CInt32T") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "CInt64T") == 0: + return llvmlite.Int64(pool) + # 精确宽度无符号类型 + elif string.strcmp(type_name, "CUInt8T") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "CUInt16T") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "CUInt32T") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "CUInt64T") == 0: + return llvmlite.Int64(pool) + # 浮点类型 + elif string.strcmp(type_name, "CFloat") == 0: + return llvmlite.Float(pool) + elif string.strcmp(type_name, "CDouble") == 0: + return llvmlite.Double(pool) + # 精确宽度浮点类型(t.py 的 float_map: 8/16→half, 32→float, 64→double, 128→fp128) + elif string.strcmp(type_name, "CFloat8T") == 0: + return llvmlite.Half(pool) + elif string.strcmp(type_name, "CFloat16T") == 0: + return llvmlite.Half(pool) + elif string.strcmp(type_name, "CFloat32T") == 0: + return llvmlite.Float(pool) + elif string.strcmp(type_name, "CFloat64T") == 0: + return llvmlite.Double(pool) + elif string.strcmp(type_name, "CFloat128T") == 0: + return llvmlite.FP128(pool) + # 指针/void: t.CPtr = i8*, str = i8* = str = bytes + elif string.strcmp(type_name, "CPtr") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + elif string.strcmp(type_name, "CVoid") == 0: + return llvmlite.Void(pool) + # CNeedPtr/CAutoPtr: 参数自动取地址标记,LLVM 层均为通用指针 i8*。 + # (TPC 中二者继承 CPtr;TPV 未实现调用点自动取地址,非指针实参应在调用点报错, + # 而非静默降级为 i32 导致指针截断。) + elif string.strcmp(type_name, "CNeedPtr") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + elif string.strcmp(type_name, "CAutoPtr") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + # 无符号修饰 + elif string.strcmp(type_name, "CUnsigned") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "CUnsignedInt") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "CUnsignedChar") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "CUnsignedShort") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "CUnsignedLong") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "CUnsignedLongLong") == 0: + return llvmlite.Int64(pool) + # size_t / ptr 类型 + elif string.strcmp(type_name, "CSizeT") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "CIntPtrT") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "CUIntPtrT") == 0: + return llvmlite.Int64(pool) + # bool + elif string.strcmp(type_name, "CBool") == 0: + # bool = t.CBool = i1(LLVM 1 位整数,语义与 C _Bool 一致) + return llvmlite.Int1(pool) + # ptrdiff_t + elif string.strcmp(type_name, "CPtrDiffT") == 0: + return llvmlite.Int64(pool) + + # ============================================================ + # stdint.py 大写别名(Win32/TransPyC 风格) + # ============================================================ + # 整数类型 + elif string.strcmp(type_name, "INT") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "BOOL") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "UINT") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "BYTE") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "WORD") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "DWORD") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "QWORD") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "TCHAR") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "VOID") == 0: + return llvmlite.Void(pool) + elif string.strcmp(type_name, "SHORT") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "USHORT") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "LONGLONG") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "ULONGLONG") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "LONG") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "ULONG") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "WCHAR") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "FLOAT") == 0: + return llvmlite.Float(pool) + elif string.strcmp(type_name, "DOUBLE") == 0: + return llvmlite.Double(pool) + # 小写裸名浮点类型(float = t.CFloat = f32, double = t.CDouble = f64) + elif string.strcmp(type_name, "float") == 0: + return llvmlite.Float(pool) + elif string.strcmp(type_name, "double") == 0: + return llvmlite.Double(pool) + elif string.strcmp(type_name, "FSIZE_t") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "LBA_t") == 0: + return llvmlite.Int32(pool) + # 定长整数 + elif string.strcmp(type_name, "INT8") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "INT16") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "INT32") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "INT64") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "UINT8") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "UINT16") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "UINT32") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "UINT64") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "CHAR8") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "CHAR16") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "CHAR32") == 0: + return llvmlite.Int32(pool) + # 小写简写 + elif string.strcmp(type_name, "i8") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "i16") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "i32") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "i64") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "u8") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "u16") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "u32") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "u64") == 0: + return llvmlite.Int64(pool) + # size_t 系列 + elif string.strcmp(type_name, "SIZE_T") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "SSIZE_T") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "PTRDIFF_T") == 0: + return llvmlite.Int64(pool) + + # stdint 指针类型(XxxPTR = XxxType | t.CPtr) + elif string.strcmp(type_name, "INTPTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int32(pool)) + elif string.strcmp(type_name, "UINTPTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int32(pool)) + elif string.strcmp(type_name, "BYTEPTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + elif string.strcmp(type_name, "CHARLIST") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + elif string.strcmp(type_name, "SHORTPTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int16(pool)) + elif string.strcmp(type_name, "USHORTPTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int16(pool)) + elif string.strcmp(type_name, "WCHARPTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int16(pool)) + elif string.strcmp(type_name, "CHARPTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + elif string.strcmp(type_name, "VOIDPTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + # Windows API 跨模块 typedef(win32base.py 中定义) + # HANDLE = VOIDPTR = i8*,LPCSTR = const char* = i8*,LPCWSTR = const wchar_t* = i16* + elif string.strcmp(type_name, "HANDLE") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + elif string.strcmp(type_name, "LPCSTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + elif string.strcmp(type_name, "LPCWSTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int16(pool)) + elif string.strcmp(type_name, "INT8PTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + elif string.strcmp(type_name, "INT16PTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int16(pool)) + elif string.strcmp(type_name, "INT32PTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int32(pool)) + elif string.strcmp(type_name, "INT64PTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int64(pool)) + elif string.strcmp(type_name, "UINT8PTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + elif string.strcmp(type_name, "UINT16PTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int16(pool)) + elif string.strcmp(type_name, "UINT32PTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int32(pool)) + elif string.strcmp(type_name, "UINT64PTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int64(pool)) + elif string.strcmp(type_name, "CHAR8PTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + elif string.strcmp(type_name, "CHAR16PTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int16(pool)) + elif string.strcmp(type_name, "CHAR32PTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int32(pool)) + + # C 标准 小写 _t 类型 + elif string.strcmp(type_name, "int8_t") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "int16_t") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "int32_t") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "int64_t") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "uint8_t") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "uint16_t") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "uint32_t") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "uint64_t") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "size_t") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "ssize_t") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "ptrdiff_t") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "intptr_t") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "uintptr_t") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "wchar_t") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "char8_t") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "char16_t") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "char32_t") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "_Bool") == 0: + return llvmlite.Int8(pool) + return None + def _is_t_attr(self, node: ast.AST | t.CPtr, + attr_name: str, + imported_modules: str) -> int: + """检测节点是否是 t.attr_name 形式(含 from t import attr_name 的裸名) + + 支持两种写法(与 TPC 的 IsTModule 检查对齐): + - t.CPtr / t.CVoid(Attribute 形式) + - 裸名 CPtr / CVoid(from t import CPtr 形式) + 裸名识别是必要功能:测试/库代码大量用 `from t import CPtr` 后直接写 + `X | CPtr`、`CVoid` 参数注解等,若只认 t.XXX 会漏判。 + """ + if node is None or attr_name is None: + return 0 + if node.kind() == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at.attr is None: + return 0 + if string.strcmp(at.attr, attr_name) != 0: + return 0 + if at.value is None or at.value.kind() != ast.ASTKind.Name: + return 0 + val_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if val_nm.id is None: + return 0 + if string.strcmp(val_nm.id, "t") == 0: + # t 是内建库(SHA1 豁免),可能不在 _imported_modules 中。 + # 显式写 t.CPtr / t.CVoid 即确指 t 模块,无需 imported_modules 确认。 + return 1 + return 0 + # 裸名形式: from t import attr_name → Name(id == attr_name) + if node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is None: + return 0 + if string.strcmp(nm.id, attr_name) != 0: + return 0 + # 裸名需确认 t 模块已导入(from t import X 会注册 t 到 _imported_modules) + if HandlesImports.is_module_imported(imported_modules, "t") == 0: + return 0 + return 1 + return 0 + def _is_cptr_marker(self, node: ast.AST | t.CPtr, + imported_modules: str) -> int: + """检测节点是否为 CPtr 指针标记,返回 1=是 / 0=否""" + if self._is_t_attr(node, "CPtr", imported_modules) != 0: + return 1 + if node is not None and node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is not None and string.strcmp(nm.id, "CPtr") == 0: + return 1 + return 0 + def _is_cptr_subscript(self, node: ast.AST | t.CPtr) -> int: + """检测节点是否为 t.CPtr[T] 下标指针类型(t.CPtr[t.CPtr] / t.CPtr[t.CInt] 等) + + 用于联合类型 X | t.CPtr[T] 的指针层级合并(TPC 联合合并规则: + CPtr 侧贡献 PtrCount,另一侧提供 BaseType)。t.CPtr[...] 不是 + 普通 CPtr 标记(_is_cptr_marker 只认 t.CPtr/CPtr 裸形式)。 + """ + if node is None or node.kind() != ast.ASTKind.Subscript: + return 0 + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + if sub.value is None or sub.value.kind() != ast.ASTKind.Attribute: + return 0 + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sub.value) + if at.attr is None or string.strcmp(at.attr, "CPtr") != 0: + return 0 + if at.value is None or at.value.kind() != ast.ASTKind.Name: + return 0 + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm.id is None or string.strcmp(nm.id, "t") != 0: + return 0 + return 1 + def _is_cvoid_marker(self, node: ast.AST | t.CPtr, + imported_modules: str) -> int: + """检测节点是否为 CVoid 指针标记,返回 1=是 / 0=否""" + if self._is_t_attr(node, "CVoid", imported_modules) != 0: + return 1 + if node is not None and node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is not None and string.strcmp(nm.id, "CVoid") == 0: + return 1 + return 0 + def annotation_to_str(self, annot: ast.AST | t.CPtr) -> str: + """将类型注解 AST 转换为可读字符串,返回 None=无法提取 + + 注意:返回的字符串可能由 malloc 分配,调用方无需释放(错误路径用)。 + """ + if annot is None: + return "" + k: int = annot.kind() + + # Constant 节点: 字符串注解 + if k == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(annot) + if cn.const_kind == ast.CONST_STR and cn.str_val is not None: + return cn.str_val + return "" + + # Name 节点: bool, int, MemBuddy + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annot) + if nm.id is not None: + return nm.id + return "" + + # Attribute 节点: t.CBool, memhub.MemBuddy + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot) + if at.attr is None: + return "" + if at.value is not None: + prefix: str = self.annotation_to_str(at.value) + if prefix is not None: + buf: str = stdlib.malloc( + string.strlen(prefix) + string.strlen(at.attr) + 2) + if buf is not None: + viperlib.snprintf(buf, + string.strlen(prefix) + string.strlen(at.attr) + 2, + "%s.%s", prefix, at.attr) + return buf + return at.attr + + # Subscript 节点: list[...], t.CArray[...] + if k == ast.ASTKind.Subscript: + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot) + base: str = self.annotation_to_str(sub.value) + if base is not None: + buf2: str = stdlib.malloc(string.strlen(base) + 5) + if buf2 is not None: + viperlib.snprintf(buf2, string.strlen(base) + 5, + "%s[...]", base) + return buf2 + return "" + + # BinOp 节点: A | B (联合类型) + if k == ast.ASTKind.BinOp: + bo: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot) + left_s: str = self.annotation_to_str(bo.left) + right_s: str = self.annotation_to_str(bo.right) + if left_s is not None and right_s is not None: + buf3: str = stdlib.malloc( + string.strlen(left_s) + string.strlen(right_s) + 5) + if buf3 is not None: + viperlib.snprintf(buf3, + string.strlen(left_s) + string.strlen(right_s) + 5, + "%s | %s", left_s, right_s) + return buf3 + return "" + + return "" + def extract_class_name_from_annotation(self, node: ast.AST | t.CPtr, + imported_modules: str, + pool: memhub.MemBuddy | t.CPtr = None) -> str: + """从类型注解 AST 中提取类名,返回 None=无法提取 + + pool 可用时,对泛型 Subscript(如 list[AST | t.CPtr])返回 mangled name + (如 "list[ast.AST|t.CPtr]"),与 resolve_annotation_type 的 mangled name 格式一致, + 使 find_struct 能找到特化的泛型结构体。 + pool 为 None 时,对 Subscript 只返回裸类名(如 "list"),保持向后兼容。 + """ + if node is None: + return None + k: int = node.kind() + + # Constant 节点: 字符串注解(如 'MemManager'),简单类名直接返回 + if k == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + if cn.const_kind == ast.CONST_STR and cn.str_val is not None: + # 仅处理简单类名(不含 . 和 |),复杂形式返回 None + if string.strchr(cn.str_val, 46) is None and string.strchr(cn.str_val, 124) is None: + if string.strcmp(cn.str_val, "str") == 0: + return None + if string.strcmp(cn.str_val, "int") == 0: + return None + if string.strcmp(cn.str_val, "bytes") == 0: + return None + if string.strcmp(cn.str_val, "bool") == 0: + return None + if string.strcmp(cn.str_val, "float") == 0: + return None + if string.strcmp(cn.str_val, "double") == 0: + return None + return cn.str_val + return None + + # Name 节点: MemBuddy → "MemBuddy" + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is None: + return None + # 泛型特化上下文:T → 具体类型(特化方法体内局部变量注解 + # 如 `cur: T | t.CPtr` 未被 _clone_classdef_for_spec 克隆替换, + # 依赖此处在翻译时经上下文解析;否则 cur.annot="T", + # 属性访问 cur.Next → lookup_field_by_class("T") 未注册报错) + resolved_id: str = HandlesType.resolve_generic_type_name(nm.id) + if resolved_id is None: + return None + # 跳过内置类型名 + if string.strcmp(resolved_id, "str") == 0: + return None + if string.strcmp(resolved_id, "bytes") == 0: + return None + if string.strcmp(resolved_id, "bool") == 0: + return None + if string.strcmp(resolved_id, "float") == 0: + return None + if string.strcmp(resolved_id, "double") == 0: + return None + return resolved_id + + # Attribute 节点: memhub.MemBuddy → "memhub.MemBuddy"(模块限定名) + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at.attr is None: + return None + # t.XXX 内置类型:返回 XXX(如 t.CUInt32T → "CUInt32T"), + # 供 AnnotClassName 记录变量类型名(_type_name_unsigned 判断无符号性时使用)。 + # 消费方(find_struct/lookup_field_by_class)对非结构体名返回 None 优雅降级。 + if at.value is not None and at.value.kind() == ast.ASTKind.Name: + val_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if val_nm2.id is not None and string.strcmp(val_nm2.id, "t") == 0: + return at.attr + # 返回模块限定名 "module.Class"(如 "memhub.MemBuddy") + mod_qual_buf: str = stdlib.malloc( + string.strlen(val_nm2.id) + string.strlen(at.attr) + 2) + if mod_qual_buf is not None: + viperlib.snprintf(mod_qual_buf, + string.strlen(val_nm2.id) + string.strlen(at.attr) + 2, + "%s.%s", val_nm2.id, at.attr) + return mod_qual_buf + return at.attr + + # BinOp 节点: 联合类型 A | B + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if bop.op == ast.OpKind.BitOr: + left_is_cptr: int = self._is_cptr_marker(bop.left, imported_modules) + right_is_cptr: int = self._is_cptr_marker(bop.right, imported_modules) + # 提取非 CPtr 一边的类名 + if left_is_cptr != 0 and right_is_cptr == 0: + return self.extract_class_name_from_annotation(bop.right, imported_modules, pool) + if right_is_cptr != 0 and left_is_cptr == 0: + return self.extract_class_name_from_annotation(bop.left, imported_modules, pool) + # 无 CPtr 标记:尝试两边 + if left_is_cptr == 0 and right_is_cptr == 0: + left_name: str = self.extract_class_name_from_annotation(bop.left, imported_modules, pool) + if left_name is not None: + return left_name + return self.extract_class_name_from_annotation(bop.right, imported_modules, pool) + return None + + # BUG 1 方案3:Subscript 节点拼接 mangled name + # list[AST | t.CPtr] → "list[ast.AST|t.CPtr]"(pool 可用时) + # 与 resolve_annotation_type 的 mangled name 格式一致,使 find_struct 能找到特化结构体 + if k == ast.ASTKind.Subscript: + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + if sub.value is None: + return None + base_name: str = self.extract_class_name_from_annotation(sub.value, imported_modules, pool) + if base_name is None: + return None + # pool 不可用时,只返回裸类名(向后兼容) + if pool is None or sub.slice is None: + return base_name + # pool 可用:拼接 mangled name "base_name[slice_name]" + # slice 是 Tuple 时用逗号分隔多个参数,否则单个参数 + slice_name: str = None + if sub.slice.kind() == ast.ASTKind.Tuple: + # Tuple slice: dict[str, int] → "str,int" + sub_tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice) + if sub_tup.elts is not None: + tup_elts_sn: list[ast.AST | t.CPtr] | t.CPtr = sub_tup.elts + tn_sn: t.CSizeT = len(tup_elts_sn) + # 计算总长度 + tup_total: t.CSizeT = 1 + ti_sn: t.CSizeT + for ti_sn in range(tn_sn): + if ti_sn > 0: + tup_total += 1 + elt_node: ast.AST | t.CPtr = tup_elts_sn.get(ti_sn) + elt_name: str = self._get_type_name_from_annotation(pool, elt_node) + if elt_name is not None: + tup_total += string.strlen(elt_name) + tup_buf: str = pool.alloc(tup_total) + if tup_buf is not None: + tup_buf[0] = '\0' + for ti_sn in range(tn_sn): + if ti_sn > 0: + string.strcat(tup_buf, ",") + elt_node2: ast.AST | t.CPtr = tup_elts_sn.get(ti_sn) + elt_name2: str = self._get_type_name_from_annotation(pool, elt_node2) + if elt_name2 is not None: + string.strcat(tup_buf, elt_name2) + slice_name = tup_buf + else: + # 非 Tuple slice: list[AST | t.CPtr] → "ast.AST|t.CPtr" + slice_name = self._get_type_name_from_annotation(pool, sub.slice) + if slice_name is None: + return base_name + # 拼接 "base_name[slice_name]" + mangled_total: t.CSizeT = string.strlen(base_name) + 1 + string.strlen(slice_name) + 1 + 1 + mangled_buf: str = pool.alloc(mangled_total) + if mangled_buf is None: + return base_name + mangled_buf[0] = '\0' + string.strcat(mangled_buf, base_name) + string.strcat(mangled_buf, "[") + string.strcat(mangled_buf, slice_name) + string.strcat(mangled_buf, "]") + return mangled_buf + + return None + def _resolve_generic_subscript_ty(self, pool: memhub.MemBuddy | t.CPtr, + sub: ast.Subscript | t.CPtr, + gen_cls_name: str, + trans: HT.Translator | t.CPtr, + imported_modules: str, + from_imports: str) -> llvmlite.LLVMType | t.CPtr: + """解析泛型类类型注解(特化或查找已注册结构体),失败返回 None""" + if pool is None or sub is None or gen_cls_name is None: + return None + # tuple[T1, T2, ...] → 匿名结构体 {T1, T2, ...}(多返回值打包, + # 对齐 TPC LLVMTypeMapper._resolve_subscript 的 '{ ty1, ty2 }')。 + # 用于函数 `-> tuple[str, t.CUnsignedShort]`(如 binascii.b2a_hqx) + # 与调用端 `a, b = f()` 的打包/解包。 + if string.strcmp(gen_cls_name, "tuple") == 0: + tp_elts: list[ast.AST | t.CPtr] | t.CPtr = None + tp_count: t.CSizeT = 0 + if sub.slice.kind() == ast.ASTKind.Tuple: + tp_tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice) + if tp_tup.elts is not None: + tp_elts = tp_tup.elts + tp_count = len(tp_elts) + else: + tp_single: list[ast.AST | t.CPtr] | t.CPtr = list[ast.AST | t.CPtr](pool, 1) + if tp_single is not None: + tp_single.append(sub.slice) + tp_elts = tp_single + tp_count = 1 + if tp_count == 0 or tp_elts is None: + return None + tup_head: llvmlite.ParamNode | t.CPtr = None + tup_tail: llvmlite.ParamNode | t.CPtr = None + tui: t.CSizeT + for tui in range(tp_count): + tup_elt: ast.AST | t.CPtr = tp_elts.get(tui) + if tup_elt is None: + continue + tup_ety: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( + pool, tup_elt, imported_modules, from_imports, trans) + if tup_ety is None: + return None + tup_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, tup_ety) + if tup_node is None: + return None + if tup_head is None: + tup_head = tup_node + else: + llvmlite.paramnode_set_next(tup_tail, tup_node) + tup_tail = tup_node + if tup_head is None: + return None + return llvmlite.Struct(pool, tup_head, tp_count, None) + # 先收集类型实参名,再分配缓冲区拼接 mangled name(elem_size=8:str 是指针) + gen_arg_names: list[str] | t.CPtr = list[str](pool, 8) + if sub.slice.kind() == ast.ASTKind.Tuple: + gen_tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice) + gen_elts: list[ast.AST | t.CPtr] | t.CPtr = gen_tp.elts + if gen_elts is not None: + gen_en: t.CSizeT = len(gen_elts) + gen_ei: t.CSizeT + for gen_ei in range(gen_en): + gen_elt: ast.AST | t.CPtr = gen_elts.get(gen_ei) + gen_tn: str = self._get_type_name_from_annotation(pool, gen_elt) + gen_arg_names.append(gen_tn) + else: + gen_tn_single: str = self._get_type_name_from_annotation(pool, sub.slice) + gen_arg_names.append(gen_tn_single) + # 计算总长度并分配缓冲区 + gen_total: t.CSizeT = string.strlen(gen_cls_name) + 2 # "[" 和 "]" + gen_an: t.CSizeT = len(gen_arg_names) + gen_ai: t.CSizeT + for gen_ai in range(gen_an): + if gen_ai > 0: + gen_total += 1 # "," + gen_atn: str = gen_arg_names.get(gen_ai) + if gen_atn is not None: + gen_total += string.strlen(gen_atn) + gen_total += 1 # NUL + gen_mangled: str = pool.alloc(gen_total) + if gen_mangled is None: + return None + gen_mangled[0] = '\0' + string.strcat(gen_mangled, gen_cls_name) + string.strcat(gen_mangled, "[") + for gen_ai in range(gen_an): + if gen_ai > 0: + string.strcat(gen_mangled, ",") + gen_atn: str = gen_arg_names.get(gen_ai) + if gen_atn is not None: + string.strcat(gen_mangled, gen_atn) + string.strcat(gen_mangled, "]") + # 查找已特化的 struct(特化由实例化调用 list[int](pool) 触发) + gen_spec_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(gen_mangled) + if gen_spec_ty is not None: + # 治本修复:Phase B 补译泛型特化类方法体 + # Phase 1a(declare_only==1)特化时只注册结构体不译方法体(MethodsEmitted==0), + # Phase B(declare_only==0)解析字段类型命中已注册结构体时本会早返回, + # 导致方法体永远不生成 → GSList[Line].append 等符号只有 declare 无 define → 链接失败。 + # 此处 Phase B 且方法体未译时,调用 _specialize_generic_class 走其已注册分支补译方法体。 + if trans is not None and trans._declare_only == 0: + import lib.core.Handles.HandlesClassDef as HandlesClassDef + gen_spec_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(gen_mangled) + if gen_spec_entry is not None and gen_spec_entry.MethodsEmitted == 0: + # 错误定位:压入触发特化的调用方帧(注解所在文件+行号), + # 使特化方法体报错(如参数类型解析失败)能追溯到用户代码 + # (如 devfs copy.vp 的 list[devfs_directory,MAX_DIRECTORIES] 注解) + gen_cur_f: str = HandlesType.get_current_file() + HandlesType.push_trace(gen_cur_f, sub.lineno) + HandlesClassDef._specialize_generic_class(trans, gen_cls_name, gen_arg_names) + HandlesType.pop_trace() + return gen_spec_ty + # 未特化:尝试主动触发泛型特化(与 TPC _HandleSubscript 对齐) + # 当 trans 可用时,检查是否是泛型模板并触发特化 + if trans is not None: + import lib.core.Handles.HandlesClassDef as HandlesClassDef + import lib.core.Handles.HandlesExprCall as HandlesExprCall + template_cd_chk: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(gen_cls_name) + if template_cd_chk is not None: + type_args_chk: list[str] | t.CPtr = HandlesExprCall._extract_type_args_from_slice( + pool, sub.slice) + if type_args_chk is not None and len(type_args_chk) > 0: + # 错误定位:压入触发特化的调用方帧(注解所在文件+行号) + gen_cur_f2: str = HandlesType.get_current_file() + HandlesType.push_trace(gen_cur_f2, sub.lineno) + spec_name_chk: str = HandlesClassDef._specialize_generic_class( + trans, gen_cls_name, type_args_chk) + HandlesType.pop_trace() + if spec_name_chk is not None: + gen_spec_ty = HandlesStruct.get_struct_type(gen_mangled) + if gen_spec_ty is not None: + return gen_spec_ty + # 未特化:返回 None(不报错,让后续流程处理) + return None + def resolve_annotation_type(self, pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr, + imported_modules: str, + from_imports: str, + trans: HT.Translator | t.CPtr = None) -> llvmlite.LLVMType | t.CPtr: + """解析类型注解节点为 LLVMType + + Args: + pool: 内存分配器 + node: 类型注解 AST 节点(Name 或 Attribute) + imported_modules: 已导入模块名字符串(空格分隔) + from_imports: from-import 映射字符串("name:module name:module" 格式) + trans: 翻译器对象(可选,用于触发泛型特化) + """ + if node is None: + return None + + k: int = node.kind() + + # Constant 节点: 字符串注解(如 'MemManager'),当作无引号的 Name/Attribute/BinOp 处理 + if k == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + # -> None 无返回值注解 → Void(追加89:-> None 被 parser 解析为 + # CONST_NONE 常量而非 Name('None'),此前直接 return None → ret_ty + # 回退 i32 → 掉出末尾被 fail-fast 误杀,BuildPipeline.set_asan_mode + # "依旧"根因;Name 分支的 "None" 归一为字符串注解形式的双保险) + if cn.const_kind == ast.CONST_NONE: + return llvmlite.Void(pool) + if cn.const_kind == ast.CONST_STR and cn.str_val is not None: + sub_node: ast.AST | t.CPtr = self._parse_type_string(pool, cn.str_val, ast.ASTCtx.Load) + if sub_node is not None: + return self.resolve_annotation_type(pool, sub_node, imported_modules, from_imports, trans) + return None + + # Name 节点: str, int, bytes, from-import 名称, class 名称等 + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is None: + return None + # 泛型类型参数 T 替换:在泛型特化上下文中,将 T 替换为具体类型 + if self.GenericTpNames is not None and self.GenericTypeArgs is not None: + gp_n: t.CSizeT = len(self.GenericTpNames) + gp_i: t.CSizeT + for gp_i in range(gp_n): + gp_tpn: str = self.GenericTpNames.get(gp_i) + if gp_tpn is not None and string.strcmp(nm.id, gp_tpn) == 0: + gp_ta: str = self.GenericTypeArgs.get(gp_i) + if gp_ta is not None: + # 自映射/污染实参防护(泛型循环套用): + # 1) 实参与参数名完全一致(T→T) + # 2) 实参串包含任一类型参数名(如 "T | t.CPtr"、" T "、 + # "list[T]")——_parse_type_string 解析后仍会产出 + # Name(参数名) → 递归再次进入本分支 → 无条件自递归 + # 无退出条件 → 编译卡死。该递归不经 _specialize_generic_class + # 的深度守卫(GenericSpecDepth),必须在此拦截。 + # 直接返回 None 让上层回落(fail-fast:宁可类型退化 + # 也不静默卡死)。 + if string.strcmp(gp_ta, gp_tpn) == 0: + return None + polluted: int = 0 + gp_j: t.CSizeT + for gp_j in range(gp_n): + gp_pn: str = self.GenericTpNames.get(gp_j) + if gp_pn is not None and string.strstr(gp_ta, gp_pn) is not None: + polluted = 1 + break + if polluted != 0: + return None + # 用具体类型名递归解析(支持 BinOp/Attribute 类型实参) + gp_sub_node: ast.AST | t.CPtr = self._parse_type_string(pool, gp_ta, nm.ctx) + if gp_sub_node is not None: + return self.resolve_annotation_type(pool, gp_sub_node, imported_modules, from_imports, trans) + # str = bytes = str = i8* + if string.strcmp(nm.id, "str") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + # -> None 无返回值注解 → Void(追加89:与 VpiReader "None"→Void + # 归一对齐;缺失时 -> None 解析失败回退 i32,函数掉出末尾被 + # fail-fast 误杀,BuildPipeline.set_asan_mode 根因) + elif string.strcmp(nm.id, "None") == 0: + return llvmlite.Void(pool) + elif string.strcmp(nm.id, "int") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(nm.id, "bytes") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + elif string.strcmp(nm.id, "bool") == 0: + # bool = t.CBool = i1(与 map_t_type 中 CBool 映射一致) + return llvmlite.Int1(pool) + # 裸名浮点类型: float = t.CFloat = f32, double = t.CDouble = f64 + elif string.strcmp(nm.id, "float") == 0: + return llvmlite.Float(pool) + elif string.strcmp(nm.id, "double") == 0: + return llvmlite.Double(pool) + # class 名称: 查找已注册的 StructType,返回 StructType 本身(不包装 Ptr) + # 这样 build_alloca 会分配结构体大小的空间,alloca 返回 struct_ty* + # 命名空间隔离:严格模式下仅解析可见的结构体 + # 跨模块同名类优先:当前模块自身定义了同名类时,用 find_struct_by_module + # 命中本模块的类(如 main.vp 的 G5Node 不再被 g5container.vp 预注册的 + # G5Node 顶掉,避免 alloca 用本模块类型、load 用他模块类型的混用)。 + # 本模块未定义时回退按裸名全局查找(import 来的类走此路径)。 + if trans is not None and trans.ModuleSha1 is not None: + own_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module(nm.id, trans.ModuleSha1) + if own_entry is not None and own_entry.Ty is not None: + # 有 __new__ 的类(堆对象)注解 → Ptr(struct)(引用语义,对齐 TPC)。 + # 否则无 __new__ 的类(栈对象,如 Point)保持 struct 值语义: + # 构造返回栈 alloca 指针,赋给 struct 值变量时 coerce load 拷贝。 + # 背景:d: dict = dict(bd) 的 dict 是堆对象(__new__ 分配), + # 裸名注解按值解析会让 sub: dict = sub_p 把 i8* 当 struct 解引用 + # 崩溃(DictTest Test 13)。 + if own_entry.HasNew != 0: + return llvmlite.Ptr(pool, own_entry.Ty) + return own_entry.Ty + if HandlesStruct.is_struct_visible(nm.id) != 0: + struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(nm.id) + if struct_ty is not None: + nm_entry_s: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) + nm_has_new_s: int = 0 + if nm_entry_s is not None: + nm_has_new_s = nm_entry_s.HasNew + if nm_has_new_s != 0: + return llvmlite.Ptr(pool, struct_ty) + return struct_ty + # 枚举类(t.CEnum)裸名注解 → 底层整数类型 + # 如 fat32_types.vp 内部 `res: FRESULT = ...`(FRESULT 是枚举非结构体) + if HandlesEnum.is_enum_class(nm.id) == 1: + return HandlesEnum.get_enum_base_type(nm.id) + # CTypedef 动态查表:查动态 CTypedef 表,递归解析类型表达式 + # 用户自定义 CTypedef(如 MyHandle: t.CTypedef = VOIDPTR)在此解析 + # 递归深度限制 MAX_CTYPEDEF_DEPTH 防止无限递归,循环检测防止 A→B→A + if self.CTypedefResolveDepth < MAX_CTYPEDEF_DEPTH: + ctypedef_str: str = HandlesType.lookup_ctypedef(nm.id) + if ctypedef_str is not None and self.CTypedefFound != 0: + # 循环检测:将当前 CTypedef 名加入正在解析列表 + if HandlesType._ctypedef_push_visiting(pool, nm.id) == 0: + # 用 _parse_type_string 把类型字符串转回 AST,递归解析 + inner_node: ast.AST | t.CPtr = self._parse_type_string(pool, ctypedef_str, nm.ctx) + if inner_node is not None: + self.CTypedefResolveDepth += 1 + inner_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( + pool, inner_node, imported_modules, from_imports, trans) + self.CTypedefResolveDepth -= 1 + HandlesType._ctypedef_pop_visiting() + if inner_ty is not None: + return inner_ty + else: + HandlesType._ctypedef_pop_visiting() + # 兜底: 尝试 map_t_type 中的硬编码 typedef 映射(VOIDPTR, HANDLE, ULONG 等) + # 这些是跨模块通用的 C typedef 名,即使 from-import 查找失败也能解析 + # 注意:from-import 的结构体名若未注册,get_struct_type 已返回 None, + # 此处 map_t_type 对结构体名也返回 None,由上层 declare_only 机制延迟到下一遍 + mapped_ty_fallback: llvmlite.LLVMType | t.CPtr = self.map_t_type(pool, nm.id) + if mapped_ty_fallback is not None: + return mapped_ty_fallback + return None + + # Attribute 节点: t.CInt, t.CUInt64T, namespace_defs.PlainStruct 等 + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at.attr is None: + return None + # 检查 value 是否是 Name('t') 或 Name('c') + if at.value is not None and at.value.kind() == ast.ASTKind.Name: + val_name: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if val_name.id is not None: + # t/c 是内建库(SHA1 豁免),显式写 t.XXX 即确指内建库, + # 不依赖 imported_modules(t 可能不在其中,如 vpi 注入上下文) + is_builtin_attr: int = 0 + if string.strcmp(val_name.id, "t") == 0 or string.strcmp(val_name.id, "c") == 0: + is_builtin_attr = 1 + if is_builtin_attr == 0: + mod_imp: int = HandlesImports.is_module_imported(imported_modules, val_name.id) + if mod_imp == 0: + return None + # 先尝试内置类型映射(int 等) + mapped_ty: llvmlite.LLVMType | t.CPtr = self.map_t_type(pool, at.attr) + if mapped_ty is not None: + return mapped_ty + # 模块限定类类型:Module.ClassName(命名空间隔离) + mod_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(at.attr) + if mod_struct_ty is not None: + return mod_struct_ty + # 模块限定枚举类型:Module.EnumClass(如 fat32_types.FRESULT, + # t.CEnum 枚举类非结构体,get_struct_type 查不到) + if HandlesEnum.is_enum_class(at.attr) == 1: + return HandlesEnum.get_enum_base_type(at.attr) + # 模块限定 typedef(posix.DIR = t.CTypedef = t.CVoid|t.CPtr 等): + # 与 Name 分支(L1986-2009)同一套 lookup_ctypedef + 递归解析。 + # 追加20只补了嵌套 Attribute(mod.sub.Typedef);单层 + # Module.Typedef(value=Name 非 t/c)同样缺失——shutil.vp + # L190 `dirp: posix.DIR` 变量注解解析失败根因。 + if self.CTypedefResolveDepth < MAX_CTYPEDEF_DEPTH: + mod_td_str: str = HandlesType.lookup_ctypedef(at.attr) + if mod_td_str is not None and self.CTypedefFound != 0: + if HandlesType._ctypedef_push_visiting(pool, at.attr) == 0: + mod_td_inner: ast.AST | t.CPtr = self._parse_type_string( + pool, mod_td_str, at.ctx) + if mod_td_inner is not None: + self.CTypedefResolveDepth += 1 + mod_td_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( + pool, mod_td_inner, imported_modules, from_imports, trans) + self.CTypedefResolveDepth -= 1 + HandlesType._ctypedef_pop_visiting() + if mod_td_ty is not None: + return mod_td_ty + else: + HandlesType._ctypedef_pop_visiting() + return None + # 嵌套 Attribute: w32.win32base.SECURITY_ATTRIBUTES 等三级及以上限定名 + # at.value 是 Attribute 而非 Name,递归提取最终类名(at.attr)查结构体表 + # find_struct 支持模块限定名回退,此处用最外层 attr(简单类名)即可 + if at.value is not None and at.value.kind() == ast.ASTKind.Attribute: + nested_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(at.attr) + if nested_struct_ty is not None: + return nested_struct_ty + # 嵌套模块限定的枚举类(fat32_types.FRESULT 三级名):查枚举基类型 + if HandlesEnum.is_enum_class(at.attr) == 1: + return HandlesEnum.get_enum_base_type(at.attr) + # 嵌套模块限定的 typedef(w32.win32base.HANDLE = t.CTypedef = VOIDPTR): + # 与 Name 分支(L1986-2009)同一套 lookup_ctypedef + 递归 + map_t_type 兜底。 + # 此前只查 struct/enum → w32.win32base.HANDLE 解析失败(fail-fast 报 + # NameError: 'w32.win32base.HANDLE' is not defined,FileIoTest 根因)。 + if self.CTypedefResolveDepth < MAX_CTYPEDEF_DEPTH: + nested_td_str: str = HandlesType.lookup_ctypedef(at.attr) + if nested_td_str is not None and self.CTypedefFound != 0: + if HandlesType._ctypedef_push_visiting(pool, at.attr) == 0: + nested_inner: ast.AST | t.CPtr = self._parse_type_string( + pool, nested_td_str, at.ctx) + if nested_inner is not None: + self.CTypedefResolveDepth += 1 + nested_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( + pool, nested_inner, imported_modules, from_imports, trans) + self.CTypedefResolveDepth -= 1 + HandlesType._ctypedef_pop_visiting() + if nested_ty is not None: + return nested_ty + else: + HandlesType._ctypedef_pop_visiting() + mapped_ty_na: llvmlite.LLVMType | t.CPtr = self.map_t_type(pool, at.attr) + if mapped_ty_na is not None: + return mapped_ty_na + return None + + # BinOp 节点: 联合类型注解 A | B + # 处理三种语义: + # 1. ActualType | t.CPtr → Ptr(ActualType)(指针包装,如 MemBuddy | t.CPtr → MemBuddy*) + # 2. t.CVoid | t.CPtr → i8* (void* 等价于 i8*) + # 3. ActualType | DecoratorMarker → ActualType(忽略装饰器标记如 CExport/CExtern) + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if bop.op == ast.OpKind.BitOr: + # 检测 t.CPtr 标记(指针包装标记,支持 t.CPtr 与 from t import CPtr 裸名) + left_is_cptr: int = self._is_cptr_marker(bop.left, imported_modules) + right_is_cptr: int = self._is_cptr_marker(bop.right, imported_modules) + if left_is_cptr != 0 or right_is_cptr != 0: + # 有 CPtr 标记:解析非 CPtr 一边的实际类型,包装为 Ptr + # left 是 CPtr → other 是 right;right 是 CPtr → other 是 left + other_node: ast.AST | t.CPtr = bop.left + if left_is_cptr != 0: + other_node = bop.right + # 检测另一边是否是 t.CVoid (void* = i8*) + # 严格验证完整形式(Attribute(t.CVoid) 的 value 是 Name("t"), + # 或裸名 CVoid 且 t 已导入),防止解析异常节点被误判为 CVoid。 + other_is_cvoid: int = 0 + if other_node is not None: + if other_node.kind() == ast.ASTKind.Attribute: + oat2: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(other_node) + if oat2.attr is not None and string.strcmp(oat2.attr, "CVoid") == 0: + if oat2.value is not None and oat2.value.kind() == ast.ASTKind.Name: + ov2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(oat2.value) + if ov2.id is not None and string.strcmp(ov2.id, "t") == 0: + other_is_cvoid = 1 + elif other_node.kind() == ast.ASTKind.Name: + onm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(other_node) + if onm2.id is not None and string.strcmp(onm2.id, "CVoid") == 0: + if HandlesImports.is_module_imported(imported_modules, "t") != 0: + other_is_cvoid = 1 + if other_is_cvoid != 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + other_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( + pool, other_node, imported_modules, from_imports, trans) + # 仅裸名(Name)场景验证解析结果必须是已注册 struct: + # 损坏节点可能解析出基础类型垃圾(如 Int8 → Ptr(i8))。 + # Attribute 场景(Module.Class / t.XXX)resolve 结果直接可用 + # (如 t.CUInt64T → i64、memhub.MemBuddy → MemBuddy*), + # 不得踢进 fallback——否则按 Name 布局读 Attribute 字段会得到 + # 垃圾类名,字段类型错误(如 free_lists 从 i64* 变 i8*)导致 + # 运行时 GEP 步长错误崩溃。 + other_is_name: int = 0 + if other_node is not None and other_node.kind() == ast.ASTKind.Name: + other_is_name = 1 + if other_ty is not None and other_is_name != 0: + if HandlesStruct.find_struct_by_type(other_ty) is None: + # 泛型类型参数(T→int 等)经上下文替换解析出的合法标量 + # 必须保留——"Name 且未注册 struct 即丢弃"本为拦截损坏 + # 节点解析出基础类型垃圾,但会误杀泛型替换的合法标量, + # 导致 T | t.CPtr(T=int)退化为 i8*:list[int] elem_ptr + # 按 8 字节槽写、elem_size=4 步长读 → 元素互相覆盖, + # pop 读到 0(ListTest 根因)。泛型参数名放行。 + keep_other_ty: int = 0 + if self.GenericTpNames is not None: + other_nm_x: ast.Name | t.CPtr = (ast.Name | t.CPtr)(other_node) + gtn_nx: t.CSizeT = len(self.GenericTpNames) + gtn_ix: t.CSizeT + for gtn_ix in range(gtn_nx): + gtn_nmx: str = self.GenericTpNames.get(gtn_ix) + if gtn_nmx is not None and other_nm_x.id is not None: + if string.strcmp(gtn_nmx, other_nm_x.id) == 0: + keep_other_ty = 1 + break + # 内建标量类型名(int/str/bytes/bool/float/double)是合法 + # 标量,不是损坏节点解析出的垃圾:int | t.CPtr 应解析为 + # i32*(int 指针),若按"Name 未注册 struct 即丢弃"踢掉 + # int → 联合退化为 i8* → int_ptr[0]=val 写 1 字节截断、 + # 读回符号扩展(DictTest key5=500 读出 -12 根因)。 + if keep_other_ty == 0 and other_node is not None and other_node.kind() == ast.ASTKind.Name: + other_nm_b: ast.Name | t.CPtr = (ast.Name | t.CPtr)(other_node) + if other_nm_b.id is not None: + if string.strcmp(other_nm_b.id, "int") == 0 or \ + string.strcmp(other_nm_b.id, "str") == 0 or \ + string.strcmp(other_nm_b.id, "bytes") == 0 or \ + string.strcmp(other_nm_b.id, "bool") == 0 or \ + string.strcmp(other_nm_b.id, "float") == 0 or \ + string.strcmp(other_nm_b.id, "double") == 0: + keep_other_ty = 1 + if keep_other_ty == 0: + other_ty = None + if other_ty is None: + # 严格模式(App 文件)下裸类名不可见时,回退到全局 + # struct 注册表按类名查找。X | t.CPtr 是明确的指针包装 + # 注解(如 vpi stub 的 "ParsedArgs | t.CPtr"),X 已注册 + # 时不应静默退化为 i8*——i8* 会让方法返回值的无注解变量 + # (如 args = parser.parse_args())类型退化,后续 obj.method + # get_class_name_by_type 查不到类名,误报 + # "跨模块调用 'args.get_str' 找不到模块 SHA1"。 + # 仅裸名(Name)场景回退:Attribute 场景 resolve 已成功。 + other_cls_nm: str = None + if other_node is not None and other_node.kind() == ast.ASTKind.Name: + other_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(other_node) + if other_nm.id is not None: + other_cls_nm = other_nm.id + if other_cls_nm is not None: + other_cls_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(other_cls_nm) + if other_cls_ty is not None: + return llvmlite.Ptr(pool, other_cls_ty) + # 类名未注册:可能是前向自我引用(如 json 的 + # 'JsonValue' | t.CPtr 字段引用自身类,类体处理中 + # 尚未注册)或 Phase A-pre 依赖类延迟到下一遍注册。 + # 回退 Ptr(i8) 由 AnnotClassName 恢复 + 多遍注册收敛 + # 处理,禁止 fail-fast(误杀合法前向引用)。 + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + return llvmlite.Ptr(pool, other_ty) + + # t.CPtr[...] 下标指针标记(t.CPtr[T] 非普通 CPtr 标记,_is_cptr_marker + # 不识别 Subscript): X | t.CPtr[T] → 指针层级合并(对齐 TPC 联合合并 + # 规则 HandlesTypeMerge.py L864-884:CPtr 侧贡献 PtrCount,另一侧提供 + # BaseType)。如 t.CUInt8T | t.CPtr[t.CPtr] → u8**。此前左右都不是 + # CPtr 标记 → 落下方"无 CPtr 标记"分支返回左值 i8 → c.Deref(out) 报 + # "参数不是指针类型"(zdeflate.vp compress out 根因)。 + cptr_sub_side: ast.AST | t.CPtr = None + cptr_other: ast.AST | t.CPtr = None + if self._is_cptr_subscript(bop.left) != 0: + cptr_sub_side = bop.left + cptr_other = bop.right + elif self._is_cptr_subscript(bop.right) != 0: + cptr_sub_side = bop.right + cptr_other = bop.left + if cptr_sub_side is not None and cptr_other is not None: + cptr_sub_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( + pool, cptr_sub_side, imported_modules, from_imports, trans) + cptr_other_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( + pool, cptr_other, imported_modules, from_imports, trans) + if cptr_sub_ty is not None and cptr_other_ty is not None: + # 计算 CPtr 侧外层 Ptr 嵌套数(如 t.CPtr[t.CPtr]=i8** → 2 层) + cptr_level: int = 0 + cur_lvl: llvmlite.LLVMType | t.CPtr = cptr_sub_ty + while cur_lvl is not None: + match cur_lvl: + case llvmlite.LLVMType.Ptr(_): + cptr_level += 1 + cur_lvl = cur_lvl.Pointee + case _: + break + # 结果 = 另一侧类型外包 N 层 Ptr + res_ty: llvmlite.LLVMType | t.CPtr = cptr_other_ty + li2: int = 0 + while li2 < cptr_level: + res_ty = llvmlite.Ptr(pool, res_ty) + li2 += 1 + return res_ty + + # 无 CPtr 标记:返回第一个非 None(装饰器标记如 CExport/CExtern 被忽略) + left_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( + pool, bop.left, imported_modules, from_imports, trans) + if left_ty is not None: + return left_ty + right_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( + pool, bop.right, imported_modules, from_imports, trans) + if right_ty is not None: + return right_ty + return None + + # Subscript 节点: t.CArray[elem_ty, count] → [count x elem_ty] + # t.CArray[elem_ty] → Ptr(elem_ty)(静态推导长度数组) + # list[int] → 特化类 struct type(泛型类类型注解) + # value 是 Attribute(Name('t'), 'CArray') 或 Name('list')(泛型类) + # slice 是 Tuple(elts=[elem_ty_node, count_node]) 或单 elem_ty_node + if k == ast.ASTKind.Subscript: + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + if sub.value is None or sub.slice is None: + HandlesType.fatal_type_error(node, "Subscript 节点缺少 value 或 slice") + # 泛型类类型注解: list[int] → 查找已特化的 struct(value 是 Name 泛型类名) + if sub.value.kind() == ast.ASTKind.Name: + gen_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) + if gen_nm.id is not None: + # 裸名 CArray(from t import * 场景,如 core.vp 的 + # `__python_suffix__: CArray[str] = ["py", ...]`):与 t.CArray + # 语义等价。否则走泛型模板查找失败(CArray 不是泛型类模板)→ + # 字段类型退化 Ptr(i8) → __before_init__ 默认值 List 字面量误走 + # 动态 list 构造(list[str].__new__/append 符号未生成 → 链接 + # undefined reference,Termination4K3 链接失败根因)。 + if string.strcmp(gen_nm.id, "CArray") == 0: + # 单参数: CArray[elem_ty] → Ptr(elem_ty)(静态推导长度数组) + if sub.slice.kind() != ast.ASTKind.Tuple: + elem_n: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( + pool, sub.slice, imported_modules, from_imports, trans) + if elem_n is None: + return None + return llvmlite.Ptr(pool, elem_n) + # 双参数: CArray[elem_ty, count] → [count x elem_ty] + tup_n: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice) + if tup_n.elts is None or len(tup_n.elts) < 2: + return None + elem_node_n: ast.AST | t.CPtr = tup_n.elts.get(0) + count_node_n: ast.AST | t.CPtr = tup_n.elts.get(1) + if elem_node_n is None or count_node_n is None: + return None + elem_ty_n: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( + pool, elem_node_n, imported_modules, from_imports, trans) + if elem_ty_n is None: + return None + # count=None → Ptr(elem)(等价单参) + if count_node_n.kind() == ast.ASTKind.Constant: + cnt_n: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(count_node_n) + if cnt_n.const_kind == ast.CONST_NONE: + return llvmlite.Ptr(pool, elem_ty_n) + count_n: int = HandlesType._eval_const_int_expr( + count_node_n, pool, from_imports, imported_modules) + if self.ConstEvalOk == 0 or count_n <= 0: + return None + return llvmlite.Array(pool, elem_ty_n, count_n) + return self._resolve_generic_subscript_ty(pool, sub, gen_nm.id, trans, + imported_modules, from_imports) + # 检查 value 是否是 Attribute(t.CArray / t.Callable / 模块限定泛型类如 numpy.ndarray[T]) + if sub.value.kind() != ast.ASTKind.Attribute: + HandlesType.fatal_type_error(node, "不支持的 Subscript 类型注解(仅支持 t.CArray / t.Callable)") + arr_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sub.value) + if arr_at.attr is None: + HandlesType.fatal_type_error(node, "Subscript Attribute 缺少 attr") + # 模块限定泛型类: numpy.ndarray[t.CDouble] → 裸类名 ndarray 走泛型特化 + # (在 t.CArray / t.Callable 检查之前;模板已注册即视为泛型类) + if trans is not None: + import lib.core.Handles.HandlesClassDef as HandlesClassDef + if HandlesClassDef._find_generic_template(arr_at.attr) is not None: + return self._resolve_generic_subscript_ty(pool, sub, arr_at.attr, trans, + imported_modules, from_imports) + if arr_at.value is None or arr_at.value.kind() != ast.ASTKind.Name: + HandlesType.fatal_type_error(node, "t.CArray / t.Callable 必须通过模块名限定") + arr_val_name: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arr_at.value) + if arr_val_name.id is None: + HandlesType.fatal_type_error(node, "Subscript 模块名为 None") + # 函数指针类型: t.Callable[[A, B], Ret] → i8* + # 与 TPV 函数传指针惯例一致(函数值 bitcast 为 i8* 存储,调用时按实参重建签名) + if string.strcmp(arr_at.attr, "Callable") == 0: + if HandlesImports.is_module_imported(imported_modules, arr_val_name.id) == 0: + HandlesType.fatal_type_error(node, "t.Callable 模块未导入") + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + # 指针类型: t.CPtr[T] → Ptr(T)(指向 T 的指针,T 自身可含指针层级) + # t.CPtr[t.CPtr] → Ptr(Ptr(CPtr=i8*)) = i8**(双指针) + # t.CPtr[t.CInt] → i32*(DeclarationGenerator.py L1014-1016 文档化语法)。 + # 此前缺失 → t.CUInt8T | t.CPtr[t.CPtr] 联合退化为左值 i8 → + # c.Deref(out) 报"参数不是指针类型"(zdeflate.vp compress out 根因) + if string.strcmp(arr_at.attr, "CPtr") == 0: + if HandlesImports.is_module_imported(imported_modules, arr_val_name.id) == 0: + HandlesType.fatal_type_error(node, "t.CPtr 模块未导入") + inner_cptr_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( + pool, sub.slice, imported_modules, from_imports, trans) + if inner_cptr_ty is None: + HandlesType.fatal_type_error(sub.slice, "t.CPtr[?] 元素类型解析失败") + return llvmlite.Ptr(pool, inner_cptr_ty) + if string.strcmp(arr_at.attr, "CArray") != 0: + HandlesType.fatal_type_error(node, "不支持的 Subscript 类型注解(仅支持 t.CArray / t.Callable)") + if HandlesImports.is_module_imported(imported_modules, arr_val_name.id) == 0: + HandlesType.fatal_type_error(node, "t.CArray 模块未导入") + # 单参数形式: t.CArray[elem_ty] → Ptr(elem_ty) + # 相当于 t.CArray[elem_ty, None],表示静态推导长度数组 + if sub.slice.kind() != ast.ASTKind.Tuple: + elem_ty_single: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( + pool, sub.slice, imported_modules, from_imports, trans) + if elem_ty_single is None: + HandlesType.fatal_type_error(sub.slice, "t.CArray[?] 元素类型解析失败") + return llvmlite.Ptr(pool, elem_ty_single) + # 双参数形式: t.CArray[elem_ty, count] → [count x elem_ty] + tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice) + if tup.elts is None: + HandlesType.fatal_type_error(node, "t.CArray Tuple 缺少 elts") + elts_list: list[ast.AST | t.CPtr] | t.CPtr = tup.elts + elts_n: t.CSizeT = len(elts_list) + if elts_n < 2: + HandlesType.fatal_type_error(node, "t.CArray Tuple 元素不足") + elem_node: ast.AST | t.CPtr = elts_list.get(0) + count_node: ast.AST | t.CPtr = elts_list.get(1) + if elem_node is None or count_node is None: + HandlesType.fatal_type_error(node, "t.CArray Tuple 元素为 None") + # 递归解析元素类型 + elem_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( + pool, elem_node, imported_modules, from_imports, trans) + if elem_ty is None: + HandlesType.fatal_type_error(elem_node, "t.CArray 元素类型解析失败") + # 解析 count(支持整数常量、None、CDefine 常量名、常量表达式如 2*MAX) + # t.CArray[elem_ty, None] 等价于单参数形式 → Ptr(elem_ty) + # t.CArray[elem_ty, NAME] 其中 NAME: t.CDefine = value → [value x elem_ty] + # t.CArray[elem_ty, 2 * MAX] 常量表达式静态计算 → [2*MAX x elem_ty] + count_val: int = 0 + if count_node.kind() == ast.ASTKind.Constant: + cnt_cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(count_node) + if cnt_cn.const_kind == ast.CONST_NONE: + return llvmlite.Ptr(pool, elem_ty) + # 统一用 _eval_const_int_expr 计算常量整数表达式 + # 支持 Constant(INT)、Name(CDefine)、BinOp(2*MAX 等算术/位运算) + # 传入 pool/from_imports/imported_modules 支持跨模块 CDefine 查找 + # (如 SHA512_BLOCK_LEN 定义在 hashlib/__sha512.vp,当前模块表不含) + count_val = HandlesType._eval_const_int_expr(count_node, pool, from_imports, imported_modules) + if self.ConstEvalOk == 0: + HandlesType.fatal_type_error(count_node, "t.CArray count 必须是整数常量、None、CDefine 常量名或常量表达式") + if count_val <= 0: + HandlesType.fatal_type_error(count_node, "t.CArray count 必须为正数") + # 创建 ArrayType(不包装 Ptr) + # 这样 build_alloca 会分配数组大小的空间,alloca 返回 [N x elem_ty]* + return llvmlite.Array(pool, elem_ty, count_val) + + # 未知 AST kind:fail-fast,不宽容返回 None + HandlesType.fatal_type_error(node, "不支持的类型注解语法") + # 追加89 块设计:fatal_type_error 调用后补显式 return(运行时不可达, + # 保证方法末尾块被正确 terminated,不做 noreturn 函数名白名单) + return None \ No newline at end of file diff --git a/App/lib/core/Handles/HandlesType.vp b/App/lib/core/Handles/HandlesType.vp index 600b2ed..6d9a640 100644 --- a/App/lib/core/Handles/HandlesType.vp +++ b/App/lib/core/Handles/HandlesType.vp @@ -378,12 +378,15 @@ def ScanCTypedefDeclarations(pool: memhub.MemBuddy | t.CPtr, return 0 -def _eval_const_int_expr(node: ast.AST | t.CPtr) -> int: +def _eval_const_int_expr(node: ast.AST | t.CPtr, + pool: memhub.MemBuddy | t.CPtr = None, + from_imports: str = None, + imported_modules: str = None) -> int: """递归计算常量整数表达式(委托到 gen._eval_const_int_expr)""" import lib.core.Gen.Generator as Generator g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) if g is not None: - return g._eval_const_int_expr(node) + return g._eval_const_int_expr(node, pool, from_imports, imported_modules) return 0