From 89995dffde0f5d231314b3457e1dbc67f23bd252 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Fri, 21 Aug 2026 06:32:40 +0800 Subject: [PATCH] =?UTF-8?q?refactor(gen):=20=E5=8E=BB=E9=99=A4=20Handles?= =?UTF-8?q?=20=E5=A7=94=E6=89=98=E5=B1=82=E2=80=94=E2=80=94=E9=93=BE?= =?UTF-8?q?=E5=BC=8F=E5=8C=96=20+=20GenTypes/GenApi=20=E8=BF=81=E7=A7=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Gen 内部 1742 处 HandlesX.func() 改 self.Gen.Y.method() 链式调用 - 数据类/常量迁移 GenTypes.vp(10 类 + CLASS_META_*/META_*/SEQ_KIND_*/FIELD_MAX 等) - 管线/保留文件经 GenApi.vp 模块级入口(48 函数带类型注解,从 Gen 方法签名自动生成) - 删除 26 个纯委托 Handles 文件,仅留 5 个实体文件(Base/Translator/Expr/ExprCall/ExprCallTable) - 修复字段分裂:TypeGenErr CurrentFile/TraceCount 链式化;CallGenBase TempDir/Cexport 真源化 --- App/lib/StubGen/Converter.vp | 1819 +++--- App/lib/StubGen/VpiReader.vp | 2724 +++++---- App/lib/core/BuildPipeline.vp | 1916 ++++--- App/lib/core/Gen/AssignGenMixin.vp | 4454 ++++++++------- App/lib/core/Gen/BaseGenMixin.vp | 118 +- App/lib/core/Gen/CallGenBase.vp | 2033 ++++--- App/lib/core/Gen/CallGenCBuiltin.vp | 2821 +++++----- App/lib/core/Gen/CallGenCall.vp | 3141 ++++++----- App/lib/core/Gen/CallGenCtor.vp | 1968 ++++--- App/lib/core/Gen/CallGenDispatch.vp | 3035 +++++----- App/lib/core/Gen/CallGenFd.vp | 813 ++- App/lib/core/Gen/CallGenLeafKit.vp | 2617 +++++---- App/lib/core/Gen/CallGenLib.vp | 1125 ++-- App/lib/core/Gen/CallGenMixin.vp | 2313 ++++---- App/lib/core/Gen/CallGenProp.vp | 831 ++- App/lib/core/Gen/CallGenVa.vp | 658 ++- App/lib/core/Gen/CallGenVt.vp | 471 +- App/lib/core/Gen/ClassGenBase.vp | 2280 ++++---- App/lib/core/Gen/ClassGenDef.vp | 1146 ++-- App/lib/core/Gen/ClassGenEnum.vp | 2316 ++++---- App/lib/core/Gen/ClassGenGeneric.vp | 1422 +++-- App/lib/core/Gen/ClassGenMixin.vp | 57 +- App/lib/core/Gen/ClassGenVTable.vp | 2622 +++++---- App/lib/core/Gen/ExprGenAttr.vp | 2397 ++++---- App/lib/core/Gen/ExprGenBase.vp | 1030 ++-- App/lib/core/Gen/ExprGenCdef.vp | 2167 ++++--- App/lib/core/Gen/ExprGenCls.vp | 994 ++-- App/lib/core/Gen/ExprGenConst.vp | 787 ++- App/lib/core/Gen/ExprGenFstr.vp | 1010 ++-- App/lib/core/Gen/ExprGenMixin.vp | 251 +- App/lib/core/Gen/ExprGenName.vp | 2102 ++++--- App/lib/core/Gen/ExprGenOps.vp | 2453 ++++---- App/lib/core/Gen/FuncGenBase.vp | 658 ++- App/lib/core/Gen/FuncGenDef.vp | 2469 ++++---- App/lib/core/Gen/FuncGenMixin.vp | 2353 ++++---- App/lib/core/Gen/GenApi.vp | 491 ++ App/lib/core/Gen/GenTypes.vp | 193 + App/lib/core/Gen/Generator.vp | 584 +- App/lib/core/Gen/ImportsGenMixin.vp | 1514 ++--- App/lib/core/Gen/MatchGenMixin.vp | 2610 +++++---- App/lib/core/Gen/StmtGenCifMixin.vp | 5032 +++++++++-------- App/lib/core/Gen/StmtGenDeclMixin.vp | 1020 ++-- App/lib/core/Gen/StmtGenMixin.vp | 1512 +++-- App/lib/core/Gen/StructGenMixin.vp | 2680 ++++----- App/lib/core/Gen/TranslatorGenMixin.vp | 1592 +++--- App/lib/core/Gen/TypeGenBase.vp | 43 +- App/lib/core/Gen/TypeGenCDef.vp | 602 +- App/lib/core/Gen/TypeGenCType.vp | 837 ++- App/lib/core/Gen/TypeGenErr.vp | 31 +- App/lib/core/Gen/TypeGenMixin.vp | 84 +- App/lib/core/Gen/TypeGenResolve.vp | 2901 +++++----- App/lib/core/Gen/VarGenMixin.vp | 807 +-- App/lib/core/Handles/ExprCallBase.vp | 246 - App/lib/core/Handles/ExprCallCall.vp | 338 -- App/lib/core/Handles/ExprCallCtor.vp | 622 --- App/lib/core/Handles/ExprCallDeref.vp | 291 - App/lib/core/Handles/ExprCallHandle.vp | 287 - App/lib/core/Handles/ExprCallTable.vp | 403 +- App/lib/core/Handles/ForHandleBase.vp | 18 - App/lib/core/Handles/ForHandleIter.vp | 20 - App/lib/core/Handles/HandlesAnnAssign.vp | 234 - App/lib/core/Handles/HandlesAssign.vp | 51 - App/lib/core/Handles/HandlesAugAssign.vp | 34 - App/lib/core/Handles/HandlesBody.vp | 168 - App/lib/core/Handles/HandlesClassDef.vp | 1200 ---- App/lib/core/Handles/HandlesEnum.vp | 166 - App/lib/core/Handles/HandlesExpr.vp | 1904 +++---- App/lib/core/Handles/HandlesExprCall.vp | 280 +- App/lib/core/Handles/HandlesExprOps.vp | 116 - App/lib/core/Handles/HandlesFor.vp | 55 - App/lib/core/Handles/HandlesFunctions.vp | 143 - App/lib/core/Handles/HandlesIf.vp | 42 - App/lib/core/Handles/HandlesImports.vp | 326 -- App/lib/core/Handles/HandlesMain.vp | 172 - App/lib/core/Handles/HandlesMatch.vp | 74 - App/lib/core/Handles/HandlesNonlocal.vp | 126 - App/lib/core/Handles/HandlesReturn.vp | 33 - App/lib/core/Handles/HandlesStruct.vp | 544 -- App/lib/core/Handles/HandlesTranslator.vp | 1210 ++-- App/lib/core/Handles/HandlesType.vp | 598 -- App/lib/core/Handles/HandlesVar.vp | 371 -- App/lib/core/Handles/HandlesWhile.vp | 40 - App/lib/core/Handles/__init__.vp | 32 +- App/lib/core/Phase1.vp | 87 +- App/lib/core/Phase1Main.vp | 1942 ++++--- App/lib/core/Phase1Scan.vp | 1006 ++-- App/lib/core/Phase1Topo.vp | 829 ++- App/lib/core/Phase2.vp | 2574 +++++---- App/lib/core/StubMerger.vp | 158 +- App/lib/core/StubMergerBuild.vp | 2459 ++++---- App/lib/core/StubMergerCollect.vp | 570 +- App/lib/core/StubMergerIR.vp | 831 ++- App/lib/core/StubMergerStore.vp | 816 ++- App/lib/core/StubMergerTopo.vp | 334 +- App/main.vp | 1385 +++-- _ExprGenMixin_backup.vp | 6203 --------------------- 96 files changed, 50608 insertions(+), 62634 deletions(-) create mode 100644 App/lib/core/Gen/GenApi.vp create mode 100644 App/lib/core/Gen/GenTypes.vp delete mode 100644 App/lib/core/Handles/ExprCallBase.vp delete mode 100644 App/lib/core/Handles/ExprCallCall.vp delete mode 100644 App/lib/core/Handles/ExprCallCtor.vp delete mode 100644 App/lib/core/Handles/ExprCallDeref.vp delete mode 100644 App/lib/core/Handles/ExprCallHandle.vp delete mode 100644 App/lib/core/Handles/ForHandleBase.vp delete mode 100644 App/lib/core/Handles/ForHandleIter.vp delete mode 100644 App/lib/core/Handles/HandlesAnnAssign.vp delete mode 100644 App/lib/core/Handles/HandlesAssign.vp delete mode 100644 App/lib/core/Handles/HandlesAugAssign.vp delete mode 100644 App/lib/core/Handles/HandlesBody.vp delete mode 100644 App/lib/core/Handles/HandlesClassDef.vp delete mode 100644 App/lib/core/Handles/HandlesEnum.vp delete mode 100644 App/lib/core/Handles/HandlesExprOps.vp delete mode 100644 App/lib/core/Handles/HandlesFor.vp delete mode 100644 App/lib/core/Handles/HandlesFunctions.vp delete mode 100644 App/lib/core/Handles/HandlesIf.vp delete mode 100644 App/lib/core/Handles/HandlesImports.vp delete mode 100644 App/lib/core/Handles/HandlesMain.vp delete mode 100644 App/lib/core/Handles/HandlesMatch.vp delete mode 100644 App/lib/core/Handles/HandlesNonlocal.vp delete mode 100644 App/lib/core/Handles/HandlesReturn.vp delete mode 100644 App/lib/core/Handles/HandlesStruct.vp delete mode 100644 App/lib/core/Handles/HandlesType.vp delete mode 100644 App/lib/core/Handles/HandlesVar.vp delete mode 100644 App/lib/core/Handles/HandlesWhile.vp delete mode 100644 _ExprGenMixin_backup.vp diff --git a/App/lib/StubGen/Converter.vp b/App/lib/StubGen/Converter.vp index ad795a3..0e3b0ff 100644 --- a/App/lib/StubGen/Converter.vp +++ b/App/lib/StubGen/Converter.vp @@ -1,909 +1,910 @@ -import t, c -from stdint import * -import ast -import string -import memhub -import viperlib -import stdlib - -# ============================================================ -# StubGen.Converter - vpi 存根文件生成器 -# -# 从 AST 直接生成 .vpi 存根文件,不依赖 CPython 的 PythonToStubConverter。 -# 遍历 Module 节点的 children,提取函数签名、类定义、变量声明、 -# import 语句,生成 Python 类型存根文件。 -# -# 本文件使用 Viper 语法实现,可被 TPC 编译为原生码。 -# ============================================================ - - -# ============================================================ -# _eval_binop_int / _eval_binop_valid - 递归计算 BinOp 常量值 -# -# 用于 .vpi 存根文件生成时计算 BinOp 表达式(如 A | B, A + B)的整数值。 -# 支持 BitOr/BitAnd/Add/Sub 以及嵌套的 Name(引用已注册的 CDefine 常量)。 -# ============================================================ -def _eval_binop_valid(node: ast.AST | t.CPtr) -> int: - """检查 BinOp 节点是否可计算(所有叶子节点都是常量或已注册的 CDefine)""" - if node is None: - return 0 - k: int = node.kind() - if k == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) - if cn.const_kind == ast.CONST_INT: - return 1 - return 0 - if k == ast.ASTKind.UnaryOp: - uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) - if uop.operand is not None: - return _eval_binop_valid(uop.operand) - return 0 - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - if bop.left is not None and bop.right is not None: - if _eval_binop_valid(bop.left) != 0: - if _eval_binop_valid(bop.right) != 0: - return 1 - return 0 - if k == ast.ASTKind.Name: - # Name 引用:检查是否是已注册的 CDefine 常量 - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm.id is not None: - # 从本地 CDefine 表查找 - val: int = _lookup_cdefine_for_pyi(nm.id) - if _pyi_cdefine_found() != 0: - return 1 - return 0 - return 0 - - -def _eval_binop_int(node: ast.AST | t.CPtr) -> t.CInt64T: - """递归计算 BinOp 节点的整数值(64 位,避免大整数 CDefine 截断)""" - if node is None: - return 0 - k: int = node.kind() - if k == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) - if cn.const_kind == ast.CONST_INT: - return cn.int_val - return 0 - if k == ast.ASTKind.UnaryOp: - uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) - if uop.op == ast.OpKind.USub and uop.operand is not None: - return -_eval_binop_int(uop.operand) - if uop.op == ast.OpKind.UAdd and uop.operand is not None: - return _eval_binop_int(uop.operand) - if uop.op == ast.OpKind.Invert and uop.operand is not None: - return ~_eval_binop_int(uop.operand) - return 0 - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - if bop.left is None or bop.right is None: - return 0 - lv: t.CInt64T = _eval_binop_int(bop.left) - rv: t.CInt64T = _eval_binop_int(bop.right) - if bop.op == ast.OpKind.BitOr: - return lv | rv - if bop.op == ast.OpKind.BitAnd: - return lv & rv - if bop.op == ast.OpKind.BitXor: - return lv ^ rv - if bop.op == ast.OpKind.Add: - return lv + rv - if bop.op == ast.OpKind.Sub: - return lv - rv - if bop.op == ast.OpKind.Mult: - return lv * rv - if bop.op == ast.OpKind.Div: - return lv // rv - if bop.op == ast.OpKind.FloorDiv: - return lv // rv - if bop.op == ast.OpKind.Mod: - return lv % rv - if bop.op == ast.OpKind.LShift: - return lv << rv - if bop.op == ast.OpKind.RShift: - return lv >> rv - return 0 - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm.id is not None: - return _lookup_cdefine_for_pyi(nm.id) - return 0 - return 0 - - -# CDefine 查找的前向声明(实际实现在 HandlesType) -# 避免循环依赖,使用弱引用 -_g_pyi_cdefine_found: int = 0 - -# 本文件 CDefine 值缓存(vpi 生成专用): -# Phase1 生成 .vpi(L1614)早于翻译阶段的 CDefine 注册(L1629+),此时 -# HandlesType 全局表为空 → BinOp 内 Name 引用查表失败退化为 0(ZDEFLATE -# WINDOW_SIZE = 1<<0 = 1、MASK = 0-1 = -1,跨模块读回错误常量根因)。 -# _GeneratePyiFromAst 开头按声明顺序注册到本缓存,Name 引用先查缓存。 -# 值缓存用 C 数组(t.CInt64T*)而非 list[int]:TPC 对 list[int].get 会误解析为 -# list[str].get(返回元素指针 i8*)→ ptrtoint 返回元素地址而非值 → MASK 变成 -# 20323785277439(地址-1)。C 数组索引 [i] 直接返回 i64 值,可靠。 -_g_pyi_cdef_names: list[str] | t.CPtr = None -_g_pyi_cdef_vals: t.CInt64T | t.CPtr = None -_g_pyi_cdef_count: t.CInt = 0 - - -def _lookup_cdefine_for_pyi(name: str) -> t.CInt64T: - """从本文件缓存 / 本地 CDefine 表查找常量值(用于 .vpi 生成时的 BinOp 计算)""" - global _g_pyi_cdefine_found - # 优先查本文件 CDefine 缓存(vpi 生成早于翻译阶段注册,全局表为空) - if _g_pyi_cdef_names is not None and _g_pyi_cdef_vals is not None: - # 循环上限用 _g_pyi_cdef_count 而非 len(_g_pyi_cdef_names): - # list[str] | t.CPtr 联合类型下 TPV 的 len() 回退 strlen(把 list 对象 - # 指针当字符串算长度 → 垃圾小值 → 靠后注册项查不到,ZDEFLATE_HASH_MASK - # = lookup(HASH_SIZE) 失败 = 0-1 = -1 根因;WINDOW_MASK 查位置 1 恰好 - # 在 strlen 结果内所以碰巧正确)。 - pn: t.CSizeT = t.CSizeT(_g_pyi_cdef_count) - pi: t.CSizeT - for pi in range(pn): - pnm: str = _g_pyi_cdef_names.get(pi) - if pnm is not None and string.strcmp(pnm, name) == 0: - _g_pyi_cdefine_found = 1 - return _g_pyi_cdef_vals[pi] - import lib.core.Handles.HandlesType as HandlesType - val: t.CInt64T = HandlesType.lookup_cdefine_constant(name) - if HandlesType.is_cdefine_found() != 0: - _g_pyi_cdefine_found = 1 - return val - _g_pyi_cdefine_found = 0 - return 0 - - -def _eval_cdefine_value_cache(node: ast.AST | t.CPtr) -> t.CInt64T: - """求值 CDefine 值(Constant/UnaryOp/BinOp/Call/Name),供 vpi 预处理注册缓存""" - if node is None: - return 0 - k: int = node.kind() - if k == ast.ASTKind.Constant: - cn_c: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) - if cn_c.const_kind == ast.CONST_INT: - return cn_c.int_val - if cn_c.const_kind == ast.CONST_BOOL: - return cn_c.int_val - # STR/FLOAT/NONE 不参与整数 BinOp 引用(注册 0 无害) - return 0 - if k == ast.ASTKind.UnaryOp: - return _eval_binop_int(node) - if k == ast.ASTKind.BinOp: - return _eval_binop_int(node) - if k == ast.ASTKind.Call: - cl_c: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) - if cl_c.args is not None and cl_c.args.__len__() > 0: - return _eval_cdefine_value_cache(cl_c.args.get(0)) - return 0 - if k == ast.ASTKind.Name: - nm_c: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm_c.id is not None: - return _lookup_cdefine_for_pyi(nm_c.id) - return 0 - return 0 - - -def _pyi_cdefine_found() -> int: - """返回上次 _lookup_cdefine_for_pyi 的查找结果状态""" - return _g_pyi_cdefine_found - - -# ============================================================ -# _PyiEmit - 追加字符串到缓冲区 -# -# 将 text 追加到 buf 的 pos 位置,返回新的 pos。 -# 自动处理缓冲区溢出(截断)。 -# ============================================================ -def _PyiEmit(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT, - text: str) -> t.CSizeT: - """追加 text 到 buf 的 pos 位置,返回新的 pos""" - if buf is None or text is None or pos >= buf_size: - return pos - tlen: t.CSizeT = string.strlen(text) - if tlen == 0: - return pos - remain: t.CSizeT = buf_size - pos - if tlen >= remain: - tlen = remain - 1 - if tlen > 0: - string.memcpy(buf + pos, text, tlen) - return pos + tlen - - -# ============================================================ -# _PyiIndent - 追加缩进空格 -# -# 追加 level*4 个空格到 buf 的 pos 位置。 -# ============================================================ -def _PyiIndent(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT, - level: int) -> t.CSizeT: - """追加 level*4 个空格到 buf,返回新的 pos""" - i: int = 0 - while i < level: - pos = _PyiEmit(buf, buf_size, pos, " ") - i += 1 - return pos - - -# ============================================================ -# _PyiTypeStr - 递归生成类型注解字符串 -# -# 将 AST 类型注解节点转换为字符串表示,写入 buf 的 pos 位置。 -# 支持: Name, Attribute, Subscript, BinOp(|), Constant(前向引用), Tuple -# ============================================================ -def _PyiTypeStr(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT, - annot: ast.AST | t.CPtr) -> t.CSizeT: - """递归生成类型注解字符串,返回新的 pos""" - if annot is None: - return _PyiEmit(buf, buf_size, pos, "t.CInt") - - k: int = annot.kind() - - # Name: 简单类型名 (如 int, str, MyClass) - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annot) - if nm.id is not None: - return _PyiEmit(buf, buf_size, pos, nm.id) - return _PyiEmit(buf, buf_size, pos, "t.CInt") - - # Attribute: 属性引用 (如 t.CInt, memhub.MemBuddy) - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot) - pos = _PyiTypeStr(buf, buf_size, pos, at.value) - pos = _PyiEmit(buf, buf_size, pos, ".") - if at.attr is not None: - pos = _PyiEmit(buf, buf_size, pos, at.attr) - return pos - - # Subscript: 下标类型 (如 list[int], t.CArray[elem, count]) - if k == ast.ASTKind.Subscript: - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot) - pos = _PyiTypeStr(buf, buf_size, pos, sub.value) - pos = _PyiEmit(buf, buf_size, pos, "[") - pos = _PyiTypeStr(buf, buf_size, pos, sub.slice) - pos = _PyiEmit(buf, buf_size, pos, "]") - return pos - - # BinOp: 联合类型 (如 int | str, File | t.CPtr) - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot) - pos = _PyiTypeStr(buf, buf_size, pos, bop.left) - pos = _PyiEmit(buf, buf_size, pos, " | ") - pos = _PyiTypeStr(buf, buf_size, pos, bop.right) - return pos - - # Constant: 字符串前向引用 (如 'MyClass')、None 或数字常量(CArray count) - if k == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(annot) - if cn.const_kind == ast.CONST_STR: - pos = _PyiEmit(buf, buf_size, pos, "'") - if cn.str_val is not None: - pos = _PyiEmit(buf, buf_size, pos, cn.str_val) - pos = _PyiEmit(buf, buf_size, pos, "'") - return pos - if cn.const_kind == ast.CONST_NONE: - return _PyiEmit(buf, buf_size, pos, "None") - # 数字常量(t.CArray[t.CUInt32T, 64] 的 count 等):输出数值本身, - # 而不是回退 t.CInt——否则 vpi 生成 "t.CArray[..., t.CInt]" 在加载 - # stub 时触发 TypeError(count 必须是整数常量、None、CDefine 常量名 - # 或常量表达式)。 - if cn.const_kind == ast.CONST_INT or cn.const_kind == ast.CONST_CHAR: - num_buf_ct: str = stdlib.malloc(24) - if num_buf_ct is not None: - viperlib.snprintf(num_buf_ct, 24, "%d", cn.int_val) - pos = _PyiEmit(buf, buf_size, pos, num_buf_ct) - stdlib.free(num_buf_ct) - return pos - return _PyiEmit(buf, buf_size, pos, "t.CInt") - - # Tuple: 多参数下标 (如 Dict[str, int]) - if k == ast.ASTKind.Tuple: - tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(annot) - if tup.elts is not None: - tup_elts: list[ast.AST | t.CPtr] | t.CPtr = tup.elts - tn: t.CSizeT = tup_elts.__len__() - ti: t.CSizeT = 0 - while ti < tn: - if ti > 0: - pos = _PyiEmit(buf, buf_size, pos, ", ") - el: ast.AST | t.CPtr = tup_elts.get(ti) - pos = _PyiTypeStr(buf, buf_size, pos, el) - ti += 1 - return pos - - # Call: 函数调用表达式 (用于装饰器如 @t.NoVTable()) - if k == ast.ASTKind.Call: - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(annot) - pos = _PyiTypeStr(buf, buf_size, pos, cl.func) - pos = _PyiEmit(buf, buf_size, pos, "(") - if cl.args is not None: - cl_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args - can: t.CSizeT = cl_args.__len__() - cai: t.CSizeT = 0 - while cai < can: - if cai > 0: - pos = _PyiEmit(buf, buf_size, pos, ", ") - ca: ast.AST | t.CPtr = cl_args.get(cai) - pos = _PyiTypeStr(buf, buf_size, pos, ca) - cai += 1 - pos = _PyiEmit(buf, buf_size, pos, ")") - return pos - - # 未知类型,回退到 t.CInt - return _PyiEmit(buf, buf_size, pos, "t.CInt") - - -# ============================================================ -# _PyiFunction - 生成函数签名 -# -# 格式: def name(param: Type, ...) -> ReturnType: pass -# ============================================================ -def _PyiFunction(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT, - fn: ast.FunctionDef | t.CPtr, - indent_level: int, class_name: str) -> t.CSizeT: - """生成函数签名到 buf,返回新的 pos""" - # 装饰器 - if fn.decorator_list is not None: - fn_decorator_list: list[ast.AST | t.CPtr] | t.CPtr = fn.decorator_list - dn: t.CSizeT = fn_decorator_list.__len__() - di: t.CSizeT = 0 - while di < dn: - dec: ast.AST | t.CPtr = fn_decorator_list.get(di) - if dec is not None: - pos = _PyiIndent(buf, buf_size, pos, indent_level) - pos = _PyiEmit(buf, buf_size, pos, "@") - pos = _PyiTypeStr(buf, buf_size, pos, dec) - pos = _PyiEmit(buf, buf_size, pos, "\n") - di += 1 - - pos = _PyiIndent(buf, buf_size, pos, indent_level) - pos = _PyiEmit(buf, buf_size, pos, "def ") - if fn.name is not None: - pos = _PyiEmit(buf, buf_size, pos, fn.name) - pos = _PyiEmit(buf, buf_size, pos, "(") - - # 参数列表 - args_node: ast.AST | t.CPtr = fn.args - if args_node is not None: - args: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) - first: int = 1 - - # 位置参数 - if args.args is not None: - args_args: list[ast.AST | t.CPtr] | t.CPtr = args.args - an: t.CSizeT = args_args.__len__() - ai: t.CSizeT = 0 - while ai < an: - if first == 0: - pos = _PyiEmit(buf, buf_size, pos, ", ") - first = 0 - ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(args_args.get(ai)) - if ag.arg is not None: - pos = _PyiEmit(buf, buf_size, pos, ag.arg) - if ag.annotation is not None: - pos = _PyiEmit(buf, buf_size, pos, ": ") - pos = _PyiTypeStr(buf, buf_size, pos, ag.annotation) - ai += 1 - - # *args - if args.vararg is not None: - if first == 0: - pos = _PyiEmit(buf, buf_size, pos, ", ") - first = 0 - pos = _PyiEmit(buf, buf_size, pos, "*") - va: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(args.vararg) - if va.arg is not None: - pos = _PyiEmit(buf, buf_size, pos, va.arg) - - # **kwargs - if args.kwarg is not None: - if first == 0: - pos = _PyiEmit(buf, buf_size, pos, ", ") - first = 0 - pos = _PyiEmit(buf, buf_size, pos, "**") - kw: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(args.kwarg) - if kw.arg is not None: - pos = _PyiEmit(buf, buf_size, pos, kw.arg) - - pos = _PyiEmit(buf, buf_size, pos, ")") - - # 返回类型 - if fn.returns is not None: - pos = _PyiEmit(buf, buf_size, pos, " -> ") - pos = _PyiTypeStr(buf, buf_size, pos, fn.returns) - - pos = _PyiEmit(buf, buf_size, pos, ": pass\n") - return pos - - -# ============================================================ -# _PyiClass - 生成类定义 -# -# 格式: -# class Name(Base): -# field: Type -# def method(self: Name, ...) -> RetType: pass -# ============================================================ -def _PyiClass(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT, - cls: ast.ClassDef | t.CPtr, indent_level: int) -> t.CSizeT: - """生成类定义到 buf,返回新的 pos""" - # 装饰器 - if cls.decorator_list is not None: - cls_decorator_list: list[ast.AST | t.CPtr] | t.CPtr = cls.decorator_list - dcn: t.CSizeT = cls_decorator_list.__len__() - dci: t.CSizeT = 0 - while dci < dcn: - ddec: ast.AST | t.CPtr = cls_decorator_list.get(dci) - if ddec is not None: - pos = _PyiIndent(buf, buf_size, pos, indent_level) - pos = _PyiEmit(buf, buf_size, pos, "@") - pos = _PyiTypeStr(buf, buf_size, pos, ddec) - pos = _PyiEmit(buf, buf_size, pos, "\n") - dci += 1 - - pos = _PyiIndent(buf, buf_size, pos, indent_level) - pos = _PyiEmit(buf, buf_size, pos, "class ") - if cls.name is not None: - pos = _PyiEmit(buf, buf_size, pos, cls.name) - - # PEP 695 类型参数 (class Foo[T]:) - if cls.type_params is not None: - cls_type_params: list[ast.AST | t.CPtr] | t.CPtr = cls.type_params - tpn: t.CSizeT = cls_type_params.__len__() - if tpn > 0: - pos = _PyiEmit(buf, buf_size, pos, "[") - tpi: t.CSizeT = 0 - while tpi < tpn: - if tpi > 0: - pos = _PyiEmit(buf, buf_size, pos, ", ") - tpname: str = cls_type_params.get(tpi) - if tpname is not None: - pos = _PyiEmit(buf, buf_size, pos, tpname) - tpi += 1 - pos = _PyiEmit(buf, buf_size, pos, "]") - - # 基类 - if cls.bases is not None: - cls_bases: list[ast.AST | t.CPtr] | t.CPtr = cls.bases - bn: t.CSizeT = cls_bases.__len__() - if bn > 0: - pos = _PyiEmit(buf, buf_size, pos, "(") - bi: t.CSizeT = 0 - while bi < bn: - if bi > 0: - pos = _PyiEmit(buf, buf_size, pos, ", ") - base: ast.AST | t.CPtr = cls_bases.get(bi) - pos = _PyiTypeStr(buf, buf_size, pos, base) - bi += 1 - pos = _PyiEmit(buf, buf_size, pos, ")") - - pos = _PyiEmit(buf, buf_size, pos, ":\n") - - # 类成员 - has_member: int = 0 - - if cls.children is not None: - cls_children: list[ast.AST | t.CPtr] | t.CPtr = cls.children - cn: t.CSizeT = cls_children.__len__() - ci: t.CSizeT = 0 - while ci < cn: - stmt: ast.AST | t.CPtr = cls_children.get(ci) - if stmt is not None: - sk: int = stmt.kind() - - # 方法 - if sk == ast.ASTKind.FunctionDef: - mfn: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) - # __init__ 方法:先提取 self.x: Type 属性 - if mfn.name is not None and string.strcmp(mfn.name, "__init__") == 0: - if mfn.children is not None: - mfn_children: list[ast.AST | t.CPtr] | t.CPtr = mfn.children - icn: t.CSizeT = mfn_children.__len__() - ici: t.CSizeT = 0 - while ici < icn: - ibody: ast.AST | t.CPtr = mfn_children.get(ici) - if ibody is not None and ibody.kind() == ast.ASTKind.AnnAssign: - iaa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(ibody) - if iaa.target is not None and iaa.target.kind() == ast.ASTKind.Attribute: - iat: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(iaa.target) - # 检查 target.value 是否为 Name("self") - if iat.value is not None and iat.value.kind() == ast.ASTKind.Name: - iavn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(iat.value) - if iavn.id is None or string.strcmp(iavn.id, "self") != 0: - ici += 1 - continue - pos = _PyiIndent(buf, buf_size, pos, indent_level + 1) - if iat.attr is not None: - pos = _PyiEmit(buf, buf_size, pos, iat.attr) - pos = _PyiEmit(buf, buf_size, pos, ": ") - pos = _PyiTypeStr(buf, buf_size, pos, iaa.annotation) - pos = _PyiEmit(buf, buf_size, pos, "\n") - has_member = 1 - ici += 1 - pos = _PyiFunction(buf, buf_size, pos, mfn, indent_level + 1, cls.name) - has_member = 1 - - # 带注解的属性 - elif sk == ast.ASTKind.AnnAssign: - aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) - if aa.target is not None and aa.target.kind() == ast.ASTKind.Name: - tn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) - pos = _PyiIndent(buf, buf_size, pos, indent_level + 1) - if tn.id is not None: - pos = _PyiEmit(buf, buf_size, pos, tn.id) - pos = _PyiEmit(buf, buf_size, pos, ": ") - pos = _PyiTypeStr(buf, buf_size, pos, aa.annotation) - pos = _PyiEmit(buf, buf_size, pos, "\n") - has_member = 1 - - # 嵌套类 - elif sk == ast.ASTKind.ClassDef: - ncls: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(stmt) - pos = _PyiClass(buf, buf_size, pos, ncls, indent_level + 1) - has_member = 1 - ci += 1 - - # 空类补 pass - if has_member == 0: - pos = _PyiIndent(buf, buf_size, pos, indent_level + 1) - pos = _PyiEmit(buf, buf_size, pos, "pass\n") - - pos = _PyiEmit(buf, buf_size, pos, "\n") - return pos - - -# ============================================================ -# _GeneratePyiFromAst - 从 AST 生成 .vpi 存根文件 -# -# 遍历 AST Module 节点,提取函数签名、类定义、变量声明、import 语句, -# 生成 Python 类型存根文件内容到 buf。 -# -# Args: -# mb: 内存池(保留以符合调用约定,实际未使用) -# tree: AST Module 根节点 -# rel_path: 相对路径(用于模块名,当前未使用) -# buf: 输出缓冲区 -# buf_size: 缓冲区大小 -# -# Returns: -# 写入的字节数(0 表示失败) -# ============================================================ -def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr, - rel_path: str, buf: bytes, - buf_size: t.CSizeT) -> t.CSizeT: - """从 AST 生成 .vpi 存根文件内容到 buf""" - if tree is None or buf is None or buf_size == 0: - return 0 - - pos: t.CSizeT = 0 - - # 预处理:按声明顺序注册本文件 CDefine 到 _g_pyi 缓存(供 BinOp 求值) - # vpi 生成(Phase1 L1614)早于翻译阶段的 CDefine 注册(L1629+),直接查 - # HandlesType 全局表为空 → BinOp 内 Name 引用退化为 0(ZDEFLATE_WINDOW_SIZE - # = 1<<0 = 1、MASK = 0-1 = -1 → 跨模块读回错误常量 → 索引越界崩溃根因)。 - # 必须 global 声明:TPV 语义下函数内对模块级变量赋值无 global 时创建局部 - # 变量(_lookup_cdefine_for_pyi 读到的仍是模块级 None → 缓存永不命中, - # 追加58 首版失效根因)。 - global _g_pyi_cdef_names - global _g_pyi_cdef_vals - global _g_pyi_cdef_count - if tree.children is not None: - pre_children: list[ast.AST | t.CPtr] | t.CPtr = tree.children - pcn: t.CSizeT = pre_children.__len__() - # 第一遍:数本文件 t.CDefine 声明数(C 数组需先定长分配) - _g_pyi_cdef_count = 0 - pci0: t.CSizeT = 0 - while pci0 < pcn: - stmt_pc0: ast.AST | t.CPtr = pre_children.get(pci0) - if stmt_pc0 is not None and stmt_pc0.kind() == ast.ASTKind.AnnAssign: - aa_pc0: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt_pc0) - if aa_pc0.target is not None and aa_pc0.target.kind() == ast.ASTKind.Name \ - and aa_pc0.annotation is not None: - tgt_pc0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa_pc0.target) - if tgt_pc0.id is not None and aa_pc0.annotation.kind() == ast.ASTKind.Attribute: - ann_pc0: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(aa_pc0.annotation) - if ann_pc0.attr is not None and string.strcmp(ann_pc0.attr, "CDefine") == 0: - _g_pyi_cdef_count += 1 - pci0 += 1 - if _g_pyi_cdef_count > 0: - _g_pyi_cdef_names = list[str](mb, t.CSizeT(_g_pyi_cdef_count)) - _g_pyi_cdef_vals = (t.CInt64T | t.CPtr)(mb.alloc(t.CSizeT(_g_pyi_cdef_count) * 8)) - # 第二遍:按声明顺序注册(BinOp 内 Name 引用依赖先前注册项) - pci: t.CSizeT = 0 - cdi: t.CInt = 0 - while pci < pcn: - stmt_pc: ast.AST | t.CPtr = pre_children.get(pci) - if stmt_pc is not None and stmt_pc.kind() == ast.ASTKind.AnnAssign: - aa_pc: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt_pc) - if aa_pc.target is not None and aa_pc.target.kind() == ast.ASTKind.Name \ - and aa_pc.annotation is not None: - tgt_pc: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa_pc.target) - if tgt_pc.id is not None and aa_pc.annotation.kind() == ast.ASTKind.Attribute: - ann_pc: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(aa_pc.annotation) - if ann_pc.attr is not None and string.strcmp(ann_pc.attr, "CDefine") == 0: - if _g_pyi_cdef_names is not None and _g_pyi_cdef_vals is not None: - _g_pyi_cdef_names.append(tgt_pc.id) - _g_pyi_cdef_vals[cdi] = _eval_cdefine_value_cache(aa_pc.value) - cdi += 1 - pci += 1 - - # 文件头 - pos = _PyiEmit(buf, buf_size, pos, "\"\"\"Auto-generated Python stub file\"\"\"\n\n") - - if tree.children is None: - if pos < buf_size: - buf[pos] = 0 - return pos - - tree_children: list[ast.AST | t.CPtr] | t.CPtr = tree.children - n: t.CSizeT = tree_children.__len__() - - # 第一遍扫描:检测 import t/c - has_import_t: int = 0 - has_import_c: int = 0 - i: t.CSizeT = 0 - while i < n: - stmt: ast.AST | t.CPtr = tree_children.get(i) - if stmt is not None and stmt.kind() == ast.ASTKind.Import: - imp: ast.Import | t.CPtr = (ast.Import | t.CPtr)(stmt) - if imp.names is not None: - imp_names: list[ast.AST | t.CPtr] | t.CPtr = imp.names - an: t.CSizeT = imp_names.__len__() - ai: t.CSizeT = 0 - while ai < an: - al: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(imp_names.get(ai)) - if al is not None and al.name is not None: - if string.strcmp(al.name, "t") == 0: - has_import_t = 1 - elif string.strcmp(al.name, "c") == 0: - has_import_c = 1 - ai += 1 - i += 1 - - # 补充缺失的 import t/c - if has_import_t == 0 and has_import_c == 0: - pos = _PyiEmit(buf, buf_size, pos, "import t, c\n\n") - elif has_import_t == 0: - pos = _PyiEmit(buf, buf_size, pos, "import t\n\n") - elif has_import_c == 0: - pos = _PyiEmit(buf, buf_size, pos, "import c\n\n") - else: - pos = _PyiEmit(buf, buf_size, pos, "\n") - - # 第二遍扫描:生成声明 - i = 0 - while i < n: - stmt = tree_children.get(i) - if stmt is not None: - k: int = stmt.kind() - - # Import 语句 - if k == ast.ASTKind.Import: - imp2: ast.Import | t.CPtr = (ast.Import | t.CPtr)(stmt) - pos = _PyiEmit(buf, buf_size, pos, "import ") - if imp2.names is not None: - imp2_names: list[ast.AST | t.CPtr] | t.CPtr = imp2.names - an2: t.CSizeT = imp2_names.__len__() - ai2: t.CSizeT = 0 - while ai2 < an2: - if ai2 > 0: - pos = _PyiEmit(buf, buf_size, pos, ", ") - al2: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(imp2_names.get(ai2)) - if al2 is not None and al2.name is not None: - pos = _PyiEmit(buf, buf_size, pos, al2.name) - if al2.asname is not None and string.strlen(al2.asname) > 0: - pos = _PyiEmit(buf, buf_size, pos, " as ") - pos = _PyiEmit(buf, buf_size, pos, al2.asname) - ai2 += 1 - pos = _PyiEmit(buf, buf_size, pos, "\n") - - # ImportFrom 语句 - elif k == ast.ASTKind.ImportFrom: - ifr: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(stmt) - pos = _PyiEmit(buf, buf_size, pos, "from ") - lvl: int = ifr.level - while lvl > 0: - pos = _PyiEmit(buf, buf_size, pos, ".") - lvl -= 1 - if ifr.module is not None: - pos = _PyiEmit(buf, buf_size, pos, ifr.module) - pos = _PyiEmit(buf, buf_size, pos, " import ") - if ifr.names is not None: - ifr_names: list[ast.AST | t.CPtr] | t.CPtr = ifr.names - an3: t.CSizeT = ifr_names.__len__() - ai3: t.CSizeT = 0 - while ai3 < an3: - if ai3 > 0: - pos = _PyiEmit(buf, buf_size, pos, ", ") - al3: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(ifr_names.get(ai3)) - if al3 is not None and al3.name is not None: - pos = _PyiEmit(buf, buf_size, pos, al3.name) - if al3.asname is not None and string.strlen(al3.asname) > 0: - pos = _PyiEmit(buf, buf_size, pos, " as ") - pos = _PyiEmit(buf, buf_size, pos, al3.asname) - ai3 += 1 - pos = _PyiEmit(buf, buf_size, pos, "\n") - - # 函数定义 - elif k == ast.ASTKind.FunctionDef: - fn: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) - pos = _PyiFunction(buf, buf_size, pos, fn, 0, "") - pos = _PyiEmit(buf, buf_size, pos, "\n") - - # 类定义 - elif k == ast.ASTKind.ClassDef: - cls: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(stmt) - pos = _PyiClass(buf, buf_size, pos, cls, 0) - - # 带注解的变量声明 - elif k == ast.ASTKind.AnnAssign: - aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) - if aa.target is not None and aa.target.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) - if nm.id is not None: - pos = _PyiEmit(buf, buf_size, pos, nm.id) - pos = _PyiEmit(buf, buf_size, pos, ": ") - pos = _PyiTypeStr(buf, buf_size, pos, aa.annotation) - # 如果有值(如 CDefine 常量),输出 = value - # CTypedef 特殊处理:值是类型表达式(如 VOIDPTR / t.CVoid | t.CPtr), - # 不是整数,用 _PyiTypeStr 输出类型字符串 - is_ctypedef_ann: int = 0 - if aa.annotation is not None and aa.annotation.kind() == ast.ASTKind.Attribute: - ctd_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(aa.annotation) - if ctd_at.attr is not None and string.strcmp(ctd_at.attr, "CTypedef") == 0: - if ctd_at.value is not None and ctd_at.value.kind() == ast.ASTKind.Name: - ctd_mod: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ctd_at.value) - if ctd_mod.id is not None and string.strcmp(ctd_mod.id, "t") == 0: - is_ctypedef_ann = 1 - if is_ctypedef_ann != 0 and aa.value is not None: - pos = _PyiEmit(buf, buf_size, pos, " = ") - pos = _PyiTypeStr(buf, buf_size, pos, aa.value) - elif aa.value is not None and aa.value.kind() == ast.ASTKind.Constant: - cv: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(aa.value) - num_buf: bytes = mb.alloc(32) - if cv.const_kind == ast.CONST_INT and num_buf is not None: - viperlib.snprintf(num_buf, 32, " = %lld", cv.int_val) - pos = _PyiEmit(buf, buf_size, pos, num_buf) - elif cv.const_kind == ast.CONST_FLOAT: - # 浮点 CDefine(numpy 的 pi/e 等):stub 必须输出值。 - # 否则读回端"vpi 中任一 CDefine 带值 → 不读源文件" - # 的启发式会被同模块 int CDefine(如 MAX_NDIM=4) - # 挡住,无值的 pi 解析不到 → 退化 @pi 全局指针 → - # float<->ptr 报错(NumpyTest 根因)。%.17g 保证 - # double 全精度往返(与读回端缓存格式一致)。 - fbuf_c: bytes = mb.alloc(64) - if fbuf_c is not None: - viperlib.snprintf(fbuf_c, 64, " = %.17g", cv.float_val) - pos = _PyiEmit(buf, buf_size, pos, fbuf_c) - elif cv.const_kind == ast.CONST_BOOL: - if cv.int_val != 0: - pos = _PyiEmit(buf, buf_size, pos, " = True") - else: - pos = _PyiEmit(buf, buf_size, pos, " = False") - elif cv.const_kind == ast.CONST_STR: - # 字符串 CDefine(pyzlib.ZLIB_VERSION = "1.3.2" 等): - # stub 必须输出值(同 CONST_FLOAT 追加44 教训——读回端 - # 按目标名判定会回退源文件可工作,但 stub 应自包含) - sbuf_c: bytes = mb.alloc(string.strlen(cv.str_val) + 6) - if sbuf_c is not None: - viperlib.snprintf(sbuf_c, string.strlen(cv.str_val) + 6, - " = \"%s\"", cv.str_val) - pos = _PyiEmit(buf, buf_size, pos, sbuf_c) - elif cv.const_kind == ast.CONST_NONE: - pos = _PyiEmit(buf, buf_size, pos, " = None") - elif aa.value is not None and aa.value.kind() == ast.ASTKind.UnaryOp: - # 处理负值常量(如 INVALID_HANDLE_VALUE = -1) - # UnaryOp(USub, Constant(1)) → -1 - uop_cv: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(aa.value) - num_buf_u: bytes = mb.alloc(32) - if uop_cv.op == ast.OpKind.USub and uop_cv.operand is not None \ - and uop_cv.operand.kind() == ast.ASTKind.Constant: - uop_const: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(uop_cv.operand) - if uop_const.const_kind == ast.CONST_INT and num_buf_u is not None: - neg_val: t.CInt64T = -uop_const.int_val - viperlib.snprintf(num_buf_u, 32, " = %lld", neg_val) - pos = _PyiEmit(buf, buf_size, pos, num_buf_u) - elif aa.value is not None and aa.value.kind() == ast.ASTKind.Call: - # 处理类型构造函数常量(如 t.CUnsignedLong(-11)) - # 提取第一个参数的整数值并输出 - call_cv: ast.Call | t.CPtr = (ast.Call | t.CPtr)(aa.value) - if call_cv.args is not None: - call_args_cv: list[ast.AST | t.CPtr] | t.CPtr = call_cv.args - if call_args_cv.__len__() > 0: - first_arg: ast.AST | t.CPtr = call_args_cv.get(0) - if first_arg is not None: - arg_kind: int = first_arg.kind() - if arg_kind == ast.ASTKind.Constant: - ca_cv: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(first_arg) - num_buf_c: bytes = mb.alloc(32) - if ca_cv.const_kind == ast.CONST_INT and num_buf_c is not None: - viperlib.snprintf(num_buf_c, 32, " = %lld", ca_cv.int_val) - pos = _PyiEmit(buf, buf_size, pos, num_buf_c) - elif arg_kind == ast.ASTKind.UnaryOp: - uop_ca: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(first_arg) - num_buf_cu: bytes = mb.alloc(32) - if uop_ca.op == ast.OpKind.USub and uop_ca.operand is not None \ - and uop_ca.operand.kind() == ast.ASTKind.Constant: - uoc: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(uop_ca.operand) - if uoc.const_kind == ast.CONST_INT and num_buf_cu is not None: - neg_c_val: t.CInt64T = -uoc.int_val - viperlib.snprintf(num_buf_cu, 32, " = %lld", neg_c_val) - pos = _PyiEmit(buf, buf_size, pos, num_buf_cu) - elif arg_kind == ast.ASTKind.BinOp: - # Call 内部的 BinOp(如 t.CUnsignedLong(A | B)) - # 递归计算 BinOp 值 - binop_val_bo: t.CInt64T = _eval_binop_int(first_arg) - num_buf_bo: bytes = mb.alloc(32) - if (binop_val_bo != 0 or _eval_binop_valid(first_arg) != 0) \ - and num_buf_bo is not None: - viperlib.snprintf(num_buf_bo, 32, " = %lld", binop_val_bo) - pos = _PyiEmit(buf, buf_size, pos, num_buf_bo) - elif aa.value is not None and aa.value.kind() == ast.ASTKind.BinOp: - # 处理 BinOp 常量(如 FOREGROUND_COMBO = FOREGROUND_RED | FOREGROUND_GREEN) - # 递归计算 BinOp 值并输出 - binop_val_av: t.CInt64T = _eval_binop_int(aa.value) - if binop_val_av != 0 or _eval_binop_valid(aa.value) != 0: - num_buf_b: bytes = mb.alloc(32) - if num_buf_b is not None: - viperlib.snprintf(num_buf_b, 32, " = %lld", binop_val_av) - pos = _PyiEmit(buf, buf_size, pos, num_buf_b) - elif aa.value is not None and aa.value.kind() == ast.ASTKind.Name: - # 处理 Name 引用常量(如 ALIAS = OTHER_CONST) - # 输出引用的名字,让消费方在本地查找 - name_val: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.value) - if name_val.id is not None: - pos = _PyiEmit(buf, buf_size, pos, " = ") - pos = _PyiEmit(buf, buf_size, pos, name_val.id) - pos = _PyiEmit(buf, buf_size, pos, "\n") - - # 全局赋值(无注解)— 从 Constant value 推断类型 - elif k == ast.ASTKind.Assign: - asg: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) - if asg.targets is not None and asg.value is not None: - asg_targets: list[ast.AST | t.CPtr] | t.CPtr = asg.targets - atn: t.CSizeT = asg_targets.__len__() - if atn == 1: - atg: ast.AST | t.CPtr = asg_targets.get(0) - if atg is not None and atg.kind() == ast.ASTKind.Name: - agn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(atg) - aval: ast.AST | t.CPtr = asg.value - avk: int = aval.kind() - inferred: int = 0 - if avk == ast.ASTKind.Constant: - acv: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(aval) - if acv.const_kind == ast.CONST_INT: - inferred = 1 - elif acv.const_kind == ast.CONST_FLOAT: - inferred = 2 - elif acv.const_kind == ast.CONST_STR: - inferred = 3 - elif acv.const_kind == ast.CONST_BOOL: - inferred = 4 - elif acv.const_kind == ast.CONST_NONE: - inferred = 5 - if inferred > 0 and agn.id is not None: - pos = _PyiEmit(buf, buf_size, pos, agn.id) - pos = _PyiEmit(buf, buf_size, pos, ": ") - if inferred == 1: - pos = _PyiEmit(buf, buf_size, pos, "t.CInt") - elif inferred == 2: - pos = _PyiEmit(buf, buf_size, pos, "t.CDouble") - elif inferred == 3: - pos = _PyiEmit(buf, buf_size, pos, "str") - elif inferred == 4: - pos = _PyiEmit(buf, buf_size, pos, "bool") - elif inferred == 5: - pos = _PyiEmit(buf, buf_size, pos, "None") - pos = _PyiEmit(buf, buf_size, pos, "\n") - - i += 1 - - # NUL 终止 - if pos < buf_size: - buf[pos] = 0 - else: - buf[buf_size - 1] = 0 - return pos +import lib.core.Gen.GenApi as GenApi +import t, c +from stdint import * +import ast +import string +import memhub +import viperlib +import stdlib + +# ============================================================ +# StubGen.Converter - vpi 存根文件生成器 +# +# 从 AST 直接生成 .vpi 存根文件,不依赖 CPython 的 PythonToStubConverter。 +# 遍历 Module 节点的 children,提取函数签名、类定义、变量声明、 +# import 语句,生成 Python 类型存根文件。 +# +# 本文件使用 Viper 语法实现,可被 TPC 编译为原生码。 +# ============================================================ + + +# ============================================================ +# _eval_binop_int / _eval_binop_valid - 递归计算 BinOp 常量值 +# +# 用于 .vpi 存根文件生成时计算 BinOp 表达式(如 A | B, A + B)的整数值。 +# 支持 BitOr/BitAnd/Add/Sub 以及嵌套的 Name(引用已注册的 CDefine 常量)。 +# ============================================================ +def _eval_binop_valid(node: ast.AST | t.CPtr) -> int: + """检查 BinOp 节点是否可计算(所有叶子节点都是常量或已注册的 CDefine)""" + if node is None: + return 0 + k: int = node.kind() + if k == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + if cn.const_kind == ast.CONST_INT: + return 1 + return 0 + if k == ast.ASTKind.UnaryOp: + uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + if uop.operand is not None: + return _eval_binop_valid(uop.operand) + return 0 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if bop.left is not None and bop.right is not None: + if _eval_binop_valid(bop.left) != 0: + if _eval_binop_valid(bop.right) != 0: + return 1 + return 0 + if k == ast.ASTKind.Name: + # Name 引用:检查是否是已注册的 CDefine 常量 + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is not None: + # 从本地 CDefine 表查找 + val: int = _lookup_cdefine_for_pyi(nm.id) + if _pyi_cdefine_found() != 0: + return 1 + return 0 + return 0 + + +def _eval_binop_int(node: ast.AST | t.CPtr) -> t.CInt64T: + """递归计算 BinOp 节点的整数值(64 位,避免大整数 CDefine 截断)""" + if node is None: + return 0 + k: int = node.kind() + if k == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + if cn.const_kind == ast.CONST_INT: + return cn.int_val + return 0 + if k == ast.ASTKind.UnaryOp: + uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + if uop.op == ast.OpKind.USub and uop.operand is not None: + return -_eval_binop_int(uop.operand) + if uop.op == ast.OpKind.UAdd and uop.operand is not None: + return _eval_binop_int(uop.operand) + if uop.op == ast.OpKind.Invert and uop.operand is not None: + return ~_eval_binop_int(uop.operand) + return 0 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if bop.left is None or bop.right is None: + return 0 + lv: t.CInt64T = _eval_binop_int(bop.left) + rv: t.CInt64T = _eval_binop_int(bop.right) + if bop.op == ast.OpKind.BitOr: + return lv | rv + if bop.op == ast.OpKind.BitAnd: + return lv & rv + if bop.op == ast.OpKind.BitXor: + return lv ^ rv + if bop.op == ast.OpKind.Add: + return lv + rv + if bop.op == ast.OpKind.Sub: + return lv - rv + if bop.op == ast.OpKind.Mult: + return lv * rv + if bop.op == ast.OpKind.Div: + return lv // rv + if bop.op == ast.OpKind.FloorDiv: + return lv // rv + if bop.op == ast.OpKind.Mod: + return lv % rv + if bop.op == ast.OpKind.LShift: + return lv << rv + if bop.op == ast.OpKind.RShift: + return lv >> rv + return 0 + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is not None: + return _lookup_cdefine_for_pyi(nm.id) + return 0 + return 0 + + +# CDefine 查找的前向声明(实际实现在 HandlesType) +# 避免循环依赖,使用弱引用 +_g_pyi_cdefine_found: int = 0 + +# 本文件 CDefine 值缓存(vpi 生成专用): +# Phase1 生成 .vpi(L1614)早于翻译阶段的 CDefine 注册(L1629+),此时 +# HandlesType 全局表为空 → BinOp 内 Name 引用查表失败退化为 0(ZDEFLATE +# WINDOW_SIZE = 1<<0 = 1、MASK = 0-1 = -1,跨模块读回错误常量根因)。 +# _GeneratePyiFromAst 开头按声明顺序注册到本缓存,Name 引用先查缓存。 +# 值缓存用 C 数组(t.CInt64T*)而非 list[int]:TPC 对 list[int].get 会误解析为 +# list[str].get(返回元素指针 i8*)→ ptrtoint 返回元素地址而非值 → MASK 变成 +# 20323785277439(地址-1)。C 数组索引 [i] 直接返回 i64 值,可靠。 +_g_pyi_cdef_names: list[str] | t.CPtr = None +_g_pyi_cdef_vals: t.CInt64T | t.CPtr = None +_g_pyi_cdef_count: t.CInt = 0 + + +def _lookup_cdefine_for_pyi(name: str) -> t.CInt64T: + """从本文件缓存 / 本地 CDefine 表查找常量值(用于 .vpi 生成时的 BinOp 计算)""" + global _g_pyi_cdefine_found + # 优先查本文件 CDefine 缓存(vpi 生成早于翻译阶段注册,全局表为空) + if _g_pyi_cdef_names is not None and _g_pyi_cdef_vals is not None: + # 循环上限用 _g_pyi_cdef_count 而非 len(_g_pyi_cdef_names): + # list[str] | t.CPtr 联合类型下 TPV 的 len() 回退 strlen(把 list 对象 + # 指针当字符串算长度 → 垃圾小值 → 靠后注册项查不到,ZDEFLATE_HASH_MASK + # = lookup(HASH_SIZE) 失败 = 0-1 = -1 根因;WINDOW_MASK 查位置 1 恰好 + # 在 strlen 结果内所以碰巧正确)。 + pn: t.CSizeT = t.CSizeT(_g_pyi_cdef_count) + pi: t.CSizeT + for pi in range(pn): + pnm: str = _g_pyi_cdef_names.get(pi) + if pnm is not None and string.strcmp(pnm, name) == 0: + _g_pyi_cdefine_found = 1 + return _g_pyi_cdef_vals[pi] + import lib.core.Handles.HandlesType as HandlesType + val: t.CInt64T = GenApi.lookup_cdefine_constant(name) + if GenApi.is_cdefine_found() != 0: + _g_pyi_cdefine_found = 1 + return val + _g_pyi_cdefine_found = 0 + return 0 + + +def _eval_cdefine_value_cache(node: ast.AST | t.CPtr) -> t.CInt64T: + """求值 CDefine 值(Constant/UnaryOp/BinOp/Call/Name),供 vpi 预处理注册缓存""" + if node is None: + return 0 + k: int = node.kind() + if k == ast.ASTKind.Constant: + cn_c: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + if cn_c.const_kind == ast.CONST_INT: + return cn_c.int_val + if cn_c.const_kind == ast.CONST_BOOL: + return cn_c.int_val + # STR/FLOAT/NONE 不参与整数 BinOp 引用(注册 0 无害) + return 0 + if k == ast.ASTKind.UnaryOp: + return _eval_binop_int(node) + if k == ast.ASTKind.BinOp: + return _eval_binop_int(node) + if k == ast.ASTKind.Call: + cl_c: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + if cl_c.args is not None and cl_c.args.__len__() > 0: + return _eval_cdefine_value_cache(cl_c.args.get(0)) + return 0 + if k == ast.ASTKind.Name: + nm_c: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm_c.id is not None: + return _lookup_cdefine_for_pyi(nm_c.id) + return 0 + return 0 + + +def _pyi_cdefine_found() -> int: + """返回上次 _lookup_cdefine_for_pyi 的查找结果状态""" + return _g_pyi_cdefine_found + + +# ============================================================ +# _PyiEmit - 追加字符串到缓冲区 +# +# 将 text 追加到 buf 的 pos 位置,返回新的 pos。 +# 自动处理缓冲区溢出(截断)。 +# ============================================================ +def _PyiEmit(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT, + text: str) -> t.CSizeT: + """追加 text 到 buf 的 pos 位置,返回新的 pos""" + if buf is None or text is None or pos >= buf_size: + return pos + tlen: t.CSizeT = string.strlen(text) + if tlen == 0: + return pos + remain: t.CSizeT = buf_size - pos + if tlen >= remain: + tlen = remain - 1 + if tlen > 0: + string.memcpy(buf + pos, text, tlen) + return pos + tlen + + +# ============================================================ +# _PyiIndent - 追加缩进空格 +# +# 追加 level*4 个空格到 buf 的 pos 位置。 +# ============================================================ +def _PyiIndent(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT, + level: int) -> t.CSizeT: + """追加 level*4 个空格到 buf,返回新的 pos""" + i: int = 0 + while i < level: + pos = _PyiEmit(buf, buf_size, pos, " ") + i += 1 + return pos + + +# ============================================================ +# _PyiTypeStr - 递归生成类型注解字符串 +# +# 将 AST 类型注解节点转换为字符串表示,写入 buf 的 pos 位置。 +# 支持: Name, Attribute, Subscript, BinOp(|), Constant(前向引用), Tuple +# ============================================================ +def _PyiTypeStr(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT, + annot: ast.AST | t.CPtr) -> t.CSizeT: + """递归生成类型注解字符串,返回新的 pos""" + if annot is None: + return _PyiEmit(buf, buf_size, pos, "t.CInt") + + k: int = annot.kind() + + # Name: 简单类型名 (如 int, str, MyClass) + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annot) + if nm.id is not None: + return _PyiEmit(buf, buf_size, pos, nm.id) + return _PyiEmit(buf, buf_size, pos, "t.CInt") + + # Attribute: 属性引用 (如 t.CInt, memhub.MemBuddy) + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot) + pos = _PyiTypeStr(buf, buf_size, pos, at.value) + pos = _PyiEmit(buf, buf_size, pos, ".") + if at.attr is not None: + pos = _PyiEmit(buf, buf_size, pos, at.attr) + return pos + + # Subscript: 下标类型 (如 list[int], t.CArray[elem, count]) + if k == ast.ASTKind.Subscript: + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot) + pos = _PyiTypeStr(buf, buf_size, pos, sub.value) + pos = _PyiEmit(buf, buf_size, pos, "[") + pos = _PyiTypeStr(buf, buf_size, pos, sub.slice) + pos = _PyiEmit(buf, buf_size, pos, "]") + return pos + + # BinOp: 联合类型 (如 int | str, File | t.CPtr) + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot) + pos = _PyiTypeStr(buf, buf_size, pos, bop.left) + pos = _PyiEmit(buf, buf_size, pos, " | ") + pos = _PyiTypeStr(buf, buf_size, pos, bop.right) + return pos + + # Constant: 字符串前向引用 (如 'MyClass')、None 或数字常量(CArray count) + if k == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(annot) + if cn.const_kind == ast.CONST_STR: + pos = _PyiEmit(buf, buf_size, pos, "'") + if cn.str_val is not None: + pos = _PyiEmit(buf, buf_size, pos, cn.str_val) + pos = _PyiEmit(buf, buf_size, pos, "'") + return pos + if cn.const_kind == ast.CONST_NONE: + return _PyiEmit(buf, buf_size, pos, "None") + # 数字常量(t.CArray[t.CUInt32T, 64] 的 count 等):输出数值本身, + # 而不是回退 t.CInt——否则 vpi 生成 "t.CArray[..., t.CInt]" 在加载 + # stub 时触发 TypeError(count 必须是整数常量、None、CDefine 常量名 + # 或常量表达式)。 + if cn.const_kind == ast.CONST_INT or cn.const_kind == ast.CONST_CHAR: + num_buf_ct: str = stdlib.malloc(24) + if num_buf_ct is not None: + viperlib.snprintf(num_buf_ct, 24, "%d", cn.int_val) + pos = _PyiEmit(buf, buf_size, pos, num_buf_ct) + stdlib.free(num_buf_ct) + return pos + return _PyiEmit(buf, buf_size, pos, "t.CInt") + + # Tuple: 多参数下标 (如 Dict[str, int]) + if k == ast.ASTKind.Tuple: + tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(annot) + if tup.elts is not None: + tup_elts: list[ast.AST | t.CPtr] | t.CPtr = tup.elts + tn: t.CSizeT = tup_elts.__len__() + ti: t.CSizeT = 0 + while ti < tn: + if ti > 0: + pos = _PyiEmit(buf, buf_size, pos, ", ") + el: ast.AST | t.CPtr = tup_elts.get(ti) + pos = _PyiTypeStr(buf, buf_size, pos, el) + ti += 1 + return pos + + # Call: 函数调用表达式 (用于装饰器如 @t.NoVTable()) + if k == ast.ASTKind.Call: + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(annot) + pos = _PyiTypeStr(buf, buf_size, pos, cl.func) + pos = _PyiEmit(buf, buf_size, pos, "(") + if cl.args is not None: + cl_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args + can: t.CSizeT = cl_args.__len__() + cai: t.CSizeT = 0 + while cai < can: + if cai > 0: + pos = _PyiEmit(buf, buf_size, pos, ", ") + ca: ast.AST | t.CPtr = cl_args.get(cai) + pos = _PyiTypeStr(buf, buf_size, pos, ca) + cai += 1 + pos = _PyiEmit(buf, buf_size, pos, ")") + return pos + + # 未知类型,回退到 t.CInt + return _PyiEmit(buf, buf_size, pos, "t.CInt") + + +# ============================================================ +# _PyiFunction - 生成函数签名 +# +# 格式: def name(param: Type, ...) -> ReturnType: pass +# ============================================================ +def _PyiFunction(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT, + fn: ast.FunctionDef | t.CPtr, + indent_level: int, class_name: str) -> t.CSizeT: + """生成函数签名到 buf,返回新的 pos""" + # 装饰器 + if fn.decorator_list is not None: + fn_decorator_list: list[ast.AST | t.CPtr] | t.CPtr = fn.decorator_list + dn: t.CSizeT = fn_decorator_list.__len__() + di: t.CSizeT = 0 + while di < dn: + dec: ast.AST | t.CPtr = fn_decorator_list.get(di) + if dec is not None: + pos = _PyiIndent(buf, buf_size, pos, indent_level) + pos = _PyiEmit(buf, buf_size, pos, "@") + pos = _PyiTypeStr(buf, buf_size, pos, dec) + pos = _PyiEmit(buf, buf_size, pos, "\n") + di += 1 + + pos = _PyiIndent(buf, buf_size, pos, indent_level) + pos = _PyiEmit(buf, buf_size, pos, "def ") + if fn.name is not None: + pos = _PyiEmit(buf, buf_size, pos, fn.name) + pos = _PyiEmit(buf, buf_size, pos, "(") + + # 参数列表 + args_node: ast.AST | t.CPtr = fn.args + if args_node is not None: + args: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + first: int = 1 + + # 位置参数 + if args.args is not None: + args_args: list[ast.AST | t.CPtr] | t.CPtr = args.args + an: t.CSizeT = args_args.__len__() + ai: t.CSizeT = 0 + while ai < an: + if first == 0: + pos = _PyiEmit(buf, buf_size, pos, ", ") + first = 0 + ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(args_args.get(ai)) + if ag.arg is not None: + pos = _PyiEmit(buf, buf_size, pos, ag.arg) + if ag.annotation is not None: + pos = _PyiEmit(buf, buf_size, pos, ": ") + pos = _PyiTypeStr(buf, buf_size, pos, ag.annotation) + ai += 1 + + # *args + if args.vararg is not None: + if first == 0: + pos = _PyiEmit(buf, buf_size, pos, ", ") + first = 0 + pos = _PyiEmit(buf, buf_size, pos, "*") + va: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(args.vararg) + if va.arg is not None: + pos = _PyiEmit(buf, buf_size, pos, va.arg) + + # **kwargs + if args.kwarg is not None: + if first == 0: + pos = _PyiEmit(buf, buf_size, pos, ", ") + first = 0 + pos = _PyiEmit(buf, buf_size, pos, "**") + kw: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(args.kwarg) + if kw.arg is not None: + pos = _PyiEmit(buf, buf_size, pos, kw.arg) + + pos = _PyiEmit(buf, buf_size, pos, ")") + + # 返回类型 + if fn.returns is not None: + pos = _PyiEmit(buf, buf_size, pos, " -> ") + pos = _PyiTypeStr(buf, buf_size, pos, fn.returns) + + pos = _PyiEmit(buf, buf_size, pos, ": pass\n") + return pos + + +# ============================================================ +# _PyiClass - 生成类定义 +# +# 格式: +# class Name(Base): +# field: Type +# def method(self: Name, ...) -> RetType: pass +# ============================================================ +def _PyiClass(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT, + cls: ast.ClassDef | t.CPtr, indent_level: int) -> t.CSizeT: + """生成类定义到 buf,返回新的 pos""" + # 装饰器 + if cls.decorator_list is not None: + cls_decorator_list: list[ast.AST | t.CPtr] | t.CPtr = cls.decorator_list + dcn: t.CSizeT = cls_decorator_list.__len__() + dci: t.CSizeT = 0 + while dci < dcn: + ddec: ast.AST | t.CPtr = cls_decorator_list.get(dci) + if ddec is not None: + pos = _PyiIndent(buf, buf_size, pos, indent_level) + pos = _PyiEmit(buf, buf_size, pos, "@") + pos = _PyiTypeStr(buf, buf_size, pos, ddec) + pos = _PyiEmit(buf, buf_size, pos, "\n") + dci += 1 + + pos = _PyiIndent(buf, buf_size, pos, indent_level) + pos = _PyiEmit(buf, buf_size, pos, "class ") + if cls.name is not None: + pos = _PyiEmit(buf, buf_size, pos, cls.name) + + # PEP 695 类型参数 (class Foo[T]:) + if cls.type_params is not None: + cls_type_params: list[ast.AST | t.CPtr] | t.CPtr = cls.type_params + tpn: t.CSizeT = cls_type_params.__len__() + if tpn > 0: + pos = _PyiEmit(buf, buf_size, pos, "[") + tpi: t.CSizeT = 0 + while tpi < tpn: + if tpi > 0: + pos = _PyiEmit(buf, buf_size, pos, ", ") + tpname: str = cls_type_params.get(tpi) + if tpname is not None: + pos = _PyiEmit(buf, buf_size, pos, tpname) + tpi += 1 + pos = _PyiEmit(buf, buf_size, pos, "]") + + # 基类 + if cls.bases is not None: + cls_bases: list[ast.AST | t.CPtr] | t.CPtr = cls.bases + bn: t.CSizeT = cls_bases.__len__() + if bn > 0: + pos = _PyiEmit(buf, buf_size, pos, "(") + bi: t.CSizeT = 0 + while bi < bn: + if bi > 0: + pos = _PyiEmit(buf, buf_size, pos, ", ") + base: ast.AST | t.CPtr = cls_bases.get(bi) + pos = _PyiTypeStr(buf, buf_size, pos, base) + bi += 1 + pos = _PyiEmit(buf, buf_size, pos, ")") + + pos = _PyiEmit(buf, buf_size, pos, ":\n") + + # 类成员 + has_member: int = 0 + + if cls.children is not None: + cls_children: list[ast.AST | t.CPtr] | t.CPtr = cls.children + cn: t.CSizeT = cls_children.__len__() + ci: t.CSizeT = 0 + while ci < cn: + stmt: ast.AST | t.CPtr = cls_children.get(ci) + if stmt is not None: + sk: int = stmt.kind() + + # 方法 + if sk == ast.ASTKind.FunctionDef: + mfn: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) + # __init__ 方法:先提取 self.x: Type 属性 + if mfn.name is not None and string.strcmp(mfn.name, "__init__") == 0: + if mfn.children is not None: + mfn_children: list[ast.AST | t.CPtr] | t.CPtr = mfn.children + icn: t.CSizeT = mfn_children.__len__() + ici: t.CSizeT = 0 + while ici < icn: + ibody: ast.AST | t.CPtr = mfn_children.get(ici) + if ibody is not None and ibody.kind() == ast.ASTKind.AnnAssign: + iaa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(ibody) + if iaa.target is not None and iaa.target.kind() == ast.ASTKind.Attribute: + iat: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(iaa.target) + # 检查 target.value 是否为 Name("self") + if iat.value is not None and iat.value.kind() == ast.ASTKind.Name: + iavn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(iat.value) + if iavn.id is None or string.strcmp(iavn.id, "self") != 0: + ici += 1 + continue + pos = _PyiIndent(buf, buf_size, pos, indent_level + 1) + if iat.attr is not None: + pos = _PyiEmit(buf, buf_size, pos, iat.attr) + pos = _PyiEmit(buf, buf_size, pos, ": ") + pos = _PyiTypeStr(buf, buf_size, pos, iaa.annotation) + pos = _PyiEmit(buf, buf_size, pos, "\n") + has_member = 1 + ici += 1 + pos = _PyiFunction(buf, buf_size, pos, mfn, indent_level + 1, cls.name) + has_member = 1 + + # 带注解的属性 + elif sk == ast.ASTKind.AnnAssign: + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) + if aa.target is not None and aa.target.kind() == ast.ASTKind.Name: + tn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) + pos = _PyiIndent(buf, buf_size, pos, indent_level + 1) + if tn.id is not None: + pos = _PyiEmit(buf, buf_size, pos, tn.id) + pos = _PyiEmit(buf, buf_size, pos, ": ") + pos = _PyiTypeStr(buf, buf_size, pos, aa.annotation) + pos = _PyiEmit(buf, buf_size, pos, "\n") + has_member = 1 + + # 嵌套类 + elif sk == ast.ASTKind.ClassDef: + ncls: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(stmt) + pos = _PyiClass(buf, buf_size, pos, ncls, indent_level + 1) + has_member = 1 + ci += 1 + + # 空类补 pass + if has_member == 0: + pos = _PyiIndent(buf, buf_size, pos, indent_level + 1) + pos = _PyiEmit(buf, buf_size, pos, "pass\n") + + pos = _PyiEmit(buf, buf_size, pos, "\n") + return pos + + +# ============================================================ +# _GeneratePyiFromAst - 从 AST 生成 .vpi 存根文件 +# +# 遍历 AST Module 节点,提取函数签名、类定义、变量声明、import 语句, +# 生成 Python 类型存根文件内容到 buf。 +# +# Args: +# mb: 内存池(保留以符合调用约定,实际未使用) +# tree: AST Module 根节点 +# rel_path: 相对路径(用于模块名,当前未使用) +# buf: 输出缓冲区 +# buf_size: 缓冲区大小 +# +# Returns: +# 写入的字节数(0 表示失败) +# ============================================================ +def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr, + rel_path: str, buf: bytes, + buf_size: t.CSizeT) -> t.CSizeT: + """从 AST 生成 .vpi 存根文件内容到 buf""" + if tree is None or buf is None or buf_size == 0: + return 0 + + pos: t.CSizeT = 0 + + # 预处理:按声明顺序注册本文件 CDefine 到 _g_pyi 缓存(供 BinOp 求值) + # vpi 生成(Phase1 L1614)早于翻译阶段的 CDefine 注册(L1629+),直接查 + # HandlesType 全局表为空 → BinOp 内 Name 引用退化为 0(ZDEFLATE_WINDOW_SIZE + # = 1<<0 = 1、MASK = 0-1 = -1 → 跨模块读回错误常量 → 索引越界崩溃根因)。 + # 必须 global 声明:TPV 语义下函数内对模块级变量赋值无 global 时创建局部 + # 变量(_lookup_cdefine_for_pyi 读到的仍是模块级 None → 缓存永不命中, + # 追加58 首版失效根因)。 + global _g_pyi_cdef_names + global _g_pyi_cdef_vals + global _g_pyi_cdef_count + if tree.children is not None: + pre_children: list[ast.AST | t.CPtr] | t.CPtr = tree.children + pcn: t.CSizeT = pre_children.__len__() + # 第一遍:数本文件 t.CDefine 声明数(C 数组需先定长分配) + _g_pyi_cdef_count = 0 + pci0: t.CSizeT = 0 + while pci0 < pcn: + stmt_pc0: ast.AST | t.CPtr = pre_children.get(pci0) + if stmt_pc0 is not None and stmt_pc0.kind() == ast.ASTKind.AnnAssign: + aa_pc0: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt_pc0) + if aa_pc0.target is not None and aa_pc0.target.kind() == ast.ASTKind.Name \ + and aa_pc0.annotation is not None: + tgt_pc0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa_pc0.target) + if tgt_pc0.id is not None and aa_pc0.annotation.kind() == ast.ASTKind.Attribute: + ann_pc0: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(aa_pc0.annotation) + if ann_pc0.attr is not None and string.strcmp(ann_pc0.attr, "CDefine") == 0: + _g_pyi_cdef_count += 1 + pci0 += 1 + if _g_pyi_cdef_count > 0: + _g_pyi_cdef_names = list[str](mb, t.CSizeT(_g_pyi_cdef_count)) + _g_pyi_cdef_vals = (t.CInt64T | t.CPtr)(mb.alloc(t.CSizeT(_g_pyi_cdef_count) * 8)) + # 第二遍:按声明顺序注册(BinOp 内 Name 引用依赖先前注册项) + pci: t.CSizeT = 0 + cdi: t.CInt = 0 + while pci < pcn: + stmt_pc: ast.AST | t.CPtr = pre_children.get(pci) + if stmt_pc is not None and stmt_pc.kind() == ast.ASTKind.AnnAssign: + aa_pc: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt_pc) + if aa_pc.target is not None and aa_pc.target.kind() == ast.ASTKind.Name \ + and aa_pc.annotation is not None: + tgt_pc: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa_pc.target) + if tgt_pc.id is not None and aa_pc.annotation.kind() == ast.ASTKind.Attribute: + ann_pc: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(aa_pc.annotation) + if ann_pc.attr is not None and string.strcmp(ann_pc.attr, "CDefine") == 0: + if _g_pyi_cdef_names is not None and _g_pyi_cdef_vals is not None: + _g_pyi_cdef_names.append(tgt_pc.id) + _g_pyi_cdef_vals[cdi] = _eval_cdefine_value_cache(aa_pc.value) + cdi += 1 + pci += 1 + + # 文件头 + pos = _PyiEmit(buf, buf_size, pos, "\"\"\"Auto-generated Python stub file\"\"\"\n\n") + + if tree.children is None: + if pos < buf_size: + buf[pos] = 0 + return pos + + tree_children: list[ast.AST | t.CPtr] | t.CPtr = tree.children + n: t.CSizeT = tree_children.__len__() + + # 第一遍扫描:检测 import t/c + has_import_t: int = 0 + has_import_c: int = 0 + i: t.CSizeT = 0 + while i < n: + stmt: ast.AST | t.CPtr = tree_children.get(i) + if stmt is not None and stmt.kind() == ast.ASTKind.Import: + imp: ast.Import | t.CPtr = (ast.Import | t.CPtr)(stmt) + if imp.names is not None: + imp_names: list[ast.AST | t.CPtr] | t.CPtr = imp.names + an: t.CSizeT = imp_names.__len__() + ai: t.CSizeT = 0 + while ai < an: + al: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(imp_names.get(ai)) + if al is not None and al.name is not None: + if string.strcmp(al.name, "t") == 0: + has_import_t = 1 + elif string.strcmp(al.name, "c") == 0: + has_import_c = 1 + ai += 1 + i += 1 + + # 补充缺失的 import t/c + if has_import_t == 0 and has_import_c == 0: + pos = _PyiEmit(buf, buf_size, pos, "import t, c\n\n") + elif has_import_t == 0: + pos = _PyiEmit(buf, buf_size, pos, "import t\n\n") + elif has_import_c == 0: + pos = _PyiEmit(buf, buf_size, pos, "import c\n\n") + else: + pos = _PyiEmit(buf, buf_size, pos, "\n") + + # 第二遍扫描:生成声明 + i = 0 + while i < n: + stmt = tree_children.get(i) + if stmt is not None: + k: int = stmt.kind() + + # Import 语句 + if k == ast.ASTKind.Import: + imp2: ast.Import | t.CPtr = (ast.Import | t.CPtr)(stmt) + pos = _PyiEmit(buf, buf_size, pos, "import ") + if imp2.names is not None: + imp2_names: list[ast.AST | t.CPtr] | t.CPtr = imp2.names + an2: t.CSizeT = imp2_names.__len__() + ai2: t.CSizeT = 0 + while ai2 < an2: + if ai2 > 0: + pos = _PyiEmit(buf, buf_size, pos, ", ") + al2: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(imp2_names.get(ai2)) + if al2 is not None and al2.name is not None: + pos = _PyiEmit(buf, buf_size, pos, al2.name) + if al2.asname is not None and string.strlen(al2.asname) > 0: + pos = _PyiEmit(buf, buf_size, pos, " as ") + pos = _PyiEmit(buf, buf_size, pos, al2.asname) + ai2 += 1 + pos = _PyiEmit(buf, buf_size, pos, "\n") + + # ImportFrom 语句 + elif k == ast.ASTKind.ImportFrom: + ifr: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(stmt) + pos = _PyiEmit(buf, buf_size, pos, "from ") + lvl: int = ifr.level + while lvl > 0: + pos = _PyiEmit(buf, buf_size, pos, ".") + lvl -= 1 + if ifr.module is not None: + pos = _PyiEmit(buf, buf_size, pos, ifr.module) + pos = _PyiEmit(buf, buf_size, pos, " import ") + if ifr.names is not None: + ifr_names: list[ast.AST | t.CPtr] | t.CPtr = ifr.names + an3: t.CSizeT = ifr_names.__len__() + ai3: t.CSizeT = 0 + while ai3 < an3: + if ai3 > 0: + pos = _PyiEmit(buf, buf_size, pos, ", ") + al3: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(ifr_names.get(ai3)) + if al3 is not None and al3.name is not None: + pos = _PyiEmit(buf, buf_size, pos, al3.name) + if al3.asname is not None and string.strlen(al3.asname) > 0: + pos = _PyiEmit(buf, buf_size, pos, " as ") + pos = _PyiEmit(buf, buf_size, pos, al3.asname) + ai3 += 1 + pos = _PyiEmit(buf, buf_size, pos, "\n") + + # 函数定义 + elif k == ast.ASTKind.FunctionDef: + fn: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) + pos = _PyiFunction(buf, buf_size, pos, fn, 0, "") + pos = _PyiEmit(buf, buf_size, pos, "\n") + + # 类定义 + elif k == ast.ASTKind.ClassDef: + cls: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(stmt) + pos = _PyiClass(buf, buf_size, pos, cls, 0) + + # 带注解的变量声明 + elif k == ast.ASTKind.AnnAssign: + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) + if aa.target is not None and aa.target.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) + if nm.id is not None: + pos = _PyiEmit(buf, buf_size, pos, nm.id) + pos = _PyiEmit(buf, buf_size, pos, ": ") + pos = _PyiTypeStr(buf, buf_size, pos, aa.annotation) + # 如果有值(如 CDefine 常量),输出 = value + # CTypedef 特殊处理:值是类型表达式(如 VOIDPTR / t.CVoid | t.CPtr), + # 不是整数,用 _PyiTypeStr 输出类型字符串 + is_ctypedef_ann: int = 0 + if aa.annotation is not None and aa.annotation.kind() == ast.ASTKind.Attribute: + ctd_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(aa.annotation) + if ctd_at.attr is not None and string.strcmp(ctd_at.attr, "CTypedef") == 0: + if ctd_at.value is not None and ctd_at.value.kind() == ast.ASTKind.Name: + ctd_mod: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ctd_at.value) + if ctd_mod.id is not None and string.strcmp(ctd_mod.id, "t") == 0: + is_ctypedef_ann = 1 + if is_ctypedef_ann != 0 and aa.value is not None: + pos = _PyiEmit(buf, buf_size, pos, " = ") + pos = _PyiTypeStr(buf, buf_size, pos, aa.value) + elif aa.value is not None and aa.value.kind() == ast.ASTKind.Constant: + cv: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(aa.value) + num_buf: bytes = mb.alloc(32) + if cv.const_kind == ast.CONST_INT and num_buf is not None: + viperlib.snprintf(num_buf, 32, " = %lld", cv.int_val) + pos = _PyiEmit(buf, buf_size, pos, num_buf) + elif cv.const_kind == ast.CONST_FLOAT: + # 浮点 CDefine(numpy 的 pi/e 等):stub 必须输出值。 + # 否则读回端"vpi 中任一 CDefine 带值 → 不读源文件" + # 的启发式会被同模块 int CDefine(如 MAX_NDIM=4) + # 挡住,无值的 pi 解析不到 → 退化 @pi 全局指针 → + # float<->ptr 报错(NumpyTest 根因)。%.17g 保证 + # double 全精度往返(与读回端缓存格式一致)。 + fbuf_c: bytes = mb.alloc(64) + if fbuf_c is not None: + viperlib.snprintf(fbuf_c, 64, " = %.17g", cv.float_val) + pos = _PyiEmit(buf, buf_size, pos, fbuf_c) + elif cv.const_kind == ast.CONST_BOOL: + if cv.int_val != 0: + pos = _PyiEmit(buf, buf_size, pos, " = True") + else: + pos = _PyiEmit(buf, buf_size, pos, " = False") + elif cv.const_kind == ast.CONST_STR: + # 字符串 CDefine(pyzlib.ZLIB_VERSION = "1.3.2" 等): + # stub 必须输出值(同 CONST_FLOAT 追加44 教训——读回端 + # 按目标名判定会回退源文件可工作,但 stub 应自包含) + sbuf_c: bytes = mb.alloc(string.strlen(cv.str_val) + 6) + if sbuf_c is not None: + viperlib.snprintf(sbuf_c, string.strlen(cv.str_val) + 6, + " = \"%s\"", cv.str_val) + pos = _PyiEmit(buf, buf_size, pos, sbuf_c) + elif cv.const_kind == ast.CONST_NONE: + pos = _PyiEmit(buf, buf_size, pos, " = None") + elif aa.value is not None and aa.value.kind() == ast.ASTKind.UnaryOp: + # 处理负值常量(如 INVALID_HANDLE_VALUE = -1) + # UnaryOp(USub, Constant(1)) → -1 + uop_cv: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(aa.value) + num_buf_u: bytes = mb.alloc(32) + if uop_cv.op == ast.OpKind.USub and uop_cv.operand is not None \ + and uop_cv.operand.kind() == ast.ASTKind.Constant: + uop_const: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(uop_cv.operand) + if uop_const.const_kind == ast.CONST_INT and num_buf_u is not None: + neg_val: t.CInt64T = -uop_const.int_val + viperlib.snprintf(num_buf_u, 32, " = %lld", neg_val) + pos = _PyiEmit(buf, buf_size, pos, num_buf_u) + elif aa.value is not None and aa.value.kind() == ast.ASTKind.Call: + # 处理类型构造函数常量(如 t.CUnsignedLong(-11)) + # 提取第一个参数的整数值并输出 + call_cv: ast.Call | t.CPtr = (ast.Call | t.CPtr)(aa.value) + if call_cv.args is not None: + call_args_cv: list[ast.AST | t.CPtr] | t.CPtr = call_cv.args + if call_args_cv.__len__() > 0: + first_arg: ast.AST | t.CPtr = call_args_cv.get(0) + if first_arg is not None: + arg_kind: int = first_arg.kind() + if arg_kind == ast.ASTKind.Constant: + ca_cv: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(first_arg) + num_buf_c: bytes = mb.alloc(32) + if ca_cv.const_kind == ast.CONST_INT and num_buf_c is not None: + viperlib.snprintf(num_buf_c, 32, " = %lld", ca_cv.int_val) + pos = _PyiEmit(buf, buf_size, pos, num_buf_c) + elif arg_kind == ast.ASTKind.UnaryOp: + uop_ca: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(first_arg) + num_buf_cu: bytes = mb.alloc(32) + if uop_ca.op == ast.OpKind.USub and uop_ca.operand is not None \ + and uop_ca.operand.kind() == ast.ASTKind.Constant: + uoc: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(uop_ca.operand) + if uoc.const_kind == ast.CONST_INT and num_buf_cu is not None: + neg_c_val: t.CInt64T = -uoc.int_val + viperlib.snprintf(num_buf_cu, 32, " = %lld", neg_c_val) + pos = _PyiEmit(buf, buf_size, pos, num_buf_cu) + elif arg_kind == ast.ASTKind.BinOp: + # Call 内部的 BinOp(如 t.CUnsignedLong(A | B)) + # 递归计算 BinOp 值 + binop_val_bo: t.CInt64T = _eval_binop_int(first_arg) + num_buf_bo: bytes = mb.alloc(32) + if (binop_val_bo != 0 or _eval_binop_valid(first_arg) != 0) \ + and num_buf_bo is not None: + viperlib.snprintf(num_buf_bo, 32, " = %lld", binop_val_bo) + pos = _PyiEmit(buf, buf_size, pos, num_buf_bo) + elif aa.value is not None and aa.value.kind() == ast.ASTKind.BinOp: + # 处理 BinOp 常量(如 FOREGROUND_COMBO = FOREGROUND_RED | FOREGROUND_GREEN) + # 递归计算 BinOp 值并输出 + binop_val_av: t.CInt64T = _eval_binop_int(aa.value) + if binop_val_av != 0 or _eval_binop_valid(aa.value) != 0: + num_buf_b: bytes = mb.alloc(32) + if num_buf_b is not None: + viperlib.snprintf(num_buf_b, 32, " = %lld", binop_val_av) + pos = _PyiEmit(buf, buf_size, pos, num_buf_b) + elif aa.value is not None and aa.value.kind() == ast.ASTKind.Name: + # 处理 Name 引用常量(如 ALIAS = OTHER_CONST) + # 输出引用的名字,让消费方在本地查找 + name_val: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.value) + if name_val.id is not None: + pos = _PyiEmit(buf, buf_size, pos, " = ") + pos = _PyiEmit(buf, buf_size, pos, name_val.id) + pos = _PyiEmit(buf, buf_size, pos, "\n") + + # 全局赋值(无注解)— 从 Constant value 推断类型 + elif k == ast.ASTKind.Assign: + asg: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) + if asg.targets is not None and asg.value is not None: + asg_targets: list[ast.AST | t.CPtr] | t.CPtr = asg.targets + atn: t.CSizeT = asg_targets.__len__() + if atn == 1: + atg: ast.AST | t.CPtr = asg_targets.get(0) + if atg is not None and atg.kind() == ast.ASTKind.Name: + agn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(atg) + aval: ast.AST | t.CPtr = asg.value + avk: int = aval.kind() + inferred: int = 0 + if avk == ast.ASTKind.Constant: + acv: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(aval) + if acv.const_kind == ast.CONST_INT: + inferred = 1 + elif acv.const_kind == ast.CONST_FLOAT: + inferred = 2 + elif acv.const_kind == ast.CONST_STR: + inferred = 3 + elif acv.const_kind == ast.CONST_BOOL: + inferred = 4 + elif acv.const_kind == ast.CONST_NONE: + inferred = 5 + if inferred > 0 and agn.id is not None: + pos = _PyiEmit(buf, buf_size, pos, agn.id) + pos = _PyiEmit(buf, buf_size, pos, ": ") + if inferred == 1: + pos = _PyiEmit(buf, buf_size, pos, "t.CInt") + elif inferred == 2: + pos = _PyiEmit(buf, buf_size, pos, "t.CDouble") + elif inferred == 3: + pos = _PyiEmit(buf, buf_size, pos, "str") + elif inferred == 4: + pos = _PyiEmit(buf, buf_size, pos, "bool") + elif inferred == 5: + pos = _PyiEmit(buf, buf_size, pos, "None") + pos = _PyiEmit(buf, buf_size, pos, "\n") + + i += 1 + + # NUL 终止 + if pos < buf_size: + buf[pos] = 0 + else: + buf[buf_size - 1] = 0 + return pos diff --git a/App/lib/StubGen/VpiReader.vp b/App/lib/StubGen/VpiReader.vp index 9a0f1dd..873f246 100644 --- a/App/lib/StubGen/VpiReader.vp +++ b/App/lib/StubGen/VpiReader.vp @@ -1,1363 +1,1361 @@ -import t, c -from stdint import * -import ast -import string -import stdio -import stdlib -import sys -import memhub -import llvmlite -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesFunctions as HandlesFunctions -import lib.core.Handles.HandlesTranslator as HT -import lib.core.StubMergerStore as StubMergerStore -import lib.core.Handles.ExprCallBase as ExprCallBase -import lib.core.Handles.ExprCallTable as ExprCallTable - - -# ============================================================ -# 方法返回注解缓存(stdlib 持久) -# -# 背景:vpi tree 在"解析后立即"有效,但遍历处理到后续类的方法时, -# 深层 AST 节点(如 parse_args 的 returns 注解)可能已被覆盖损坏 -# (kind() 读取异常),直接 resolve 得到垃圾类型(如 i8*)。 -# 因此采用文本提取方案:ParseVpiIntoModule 读 .vpi stub 时,从 -# vpi_buf 原始文本(在函数末尾才释放,始终有效)直接按行格式 -# 提取 "def m(...) -> Ret:" 的返回注解字符串缓存到 stdlib(持久, -# 不受 pool 状态影响)。HandlesExprCall._lookup_method_ret_ty_via_vpi -# 按 sha1.类名.方法名 查表并用 _resolve_vpi_ret_annot_str 纯字符串 -# 解析为 LLVMType,返回类型始终来自方法定义处,无白名单/无硬编码。 -# ============================================================ -VPI_RET_MAX: t.CDefine = 4096 -VPI_KEY_LEN: t.CDefine = 224 -VPI_RET_LEN: t.CDefine = 224 - -_g_vpi_ret_keys: bytes = None -_g_vpi_ret_strs: bytes = None -_g_vpi_ret_count: int = 0 -_g_vpi_ret_cap: int = 0 - - -# ============================================================ -# _cache_vpi_return_annots_text - 从 vpi_buf 文本直接提取方法返回注解 -# -# 完全不依赖 AST tree(tree 深层节点在后续处理中可能损坏), -# 直接按 vpi 生成文件的行格式提取: -# " def method(...) -> Ret: pass"(类内方法,缩进) -# "def method(...) -> Ret: pass"(模块级函数) -# "class X:"(跟踪当前类名) -# ============================================================ -def _cache_vpi_return_annots_text(vpi_buf: bytes, src_sha1: str) -> int: - """从 vpi_buf 文本提取方法返回注解字符串(stdlib 持久)""" - global _g_vpi_ret_keys, _g_vpi_ret_strs, _g_vpi_ret_count, _g_vpi_ret_cap - if vpi_buf is None or src_sha1 is None: - return 0 - if _g_vpi_ret_keys is None: - _g_vpi_ret_keys = stdlib.malloc(VPI_RET_MAX * VPI_KEY_LEN) - _g_vpi_ret_strs = stdlib.malloc(VPI_RET_MAX * VPI_RET_LEN) - if _g_vpi_ret_keys is None or _g_vpi_ret_strs is None: - return 0 - string.memset(_g_vpi_ret_keys, 0, VPI_RET_MAX * VPI_KEY_LEN) - string.memset(_g_vpi_ret_strs, 0, VPI_RET_MAX * VPI_RET_LEN) - _g_vpi_ret_cap = VPI_RET_MAX - sha1_len: t.CSizeT = string.strlen(src_sha1) - buf_len: t.CSizeT = string.strlen(vpi_buf) - cur_cls: bytes = None - pos: t.CSizeT = 0 - line_no: int = 0 - while pos < buf_len: - ls: t.CSizeT = pos - le: t.CSizeT = pos - while le < buf_len and vpi_buf[le] != '\n': - le += 1 - line_len: t.CSizeT = le - ls - # 跳过前导空格,检查 class/def - i: t.CSizeT = ls - while i < le and vpi_buf[i] == ' ': - i += 1 - if i < le: - # class X: - if line_len >= 6 and string.strncmp(vpi_buf + i, "class ", 6) == 0: - cstart: t.CSizeT = i + 6 - cend: t.CSizeT = cstart - # 类名提取:到 ':' / ' ' / '(' 前停止(继承基类括号不入类名, - # 如 "class MemBuddy(MemManager):" → "MemBuddy",与调用方短名一致) - while cend < le and vpi_buf[cend] != ':' and vpi_buf[cend] != ' ' and vpi_buf[cend] != '(': - cend += 1 - if cend > cstart: - if cur_cls is not None: - stdlib.free(cur_cls) - cur_cls = stdlib.malloc(cend - cstart + 1) - if cur_cls is not None: - string.strncpy(cur_cls, vpi_buf + cstart, cend - cstart) - cur_cls[cend - cstart] = '\0' - # def name(...) -> Ret: - elif line_len >= 4 and string.strncmp(vpi_buf + i, "def ", 4) == 0: - # 模块级函数(行首无缩进):清空类名上下文,避免类结束后残留 - # (如 json 的 null/int_val 等模块级函数被误存为 JsonValue.null) - if i == ls and cur_cls is not None: - stdlib.free(cur_cls) - cur_cls = None - dstart: t.CSizeT = i + 4 - dend: t.CSizeT = dstart - while dend < le and vpi_buf[dend] != '(': - dend += 1 - # 方法名 = [dstart, dend) - # 找 "->" - rpos: t.CSizeT = dstart - arrow_pos: t.CSizeT = le - while rpos < le - 1: - if vpi_buf[rpos] == '-' and vpi_buf[rpos + 1] == '>': - arrow_pos = rpos - break - rpos += 1 - if dend > dstart: - # 返回类型:有 "-> Ret" 提取注解;无注解的非特殊方法默认 "i32" - # (与 HandlesType.infer_return_type 无 return 语句时的默认行为一致, - # 如 json._append_child / __setitem__ 无注解实际编译为 i32)。 - ret_src: str = None - rtype_len: t.CSizeT = 0 - if arrow_pos < le: - # 返回类型 = arrow_pos+2 跳过空格 到 ':' 前 - rstart2: t.CSizeT = arrow_pos + 2 - while rstart2 < le and vpi_buf[rstart2] == ' ': - rstart2 += 1 - rend2: t.CSizeT = rstart2 - while rend2 < le and vpi_buf[rend2] != ':': - rend2 += 1 - if rend2 > rstart2: - rtype_len = rend2 - rstart2 - ret_src = vpi_buf + rstart2 - else: - # 无返回注解:默认 i32(特殊方法除外,见下方过滤) - rtype_len = 3 - ret_src = "i32" - if ret_src is not None: - # 构造 key 和 ret_str,存入缓存 - mname_len: t.CSizeT = dend - dstart - cls_len2: t.CSizeT = 0 - if cur_cls is not None: - cls_len2 = string.strlen(cur_cls) - key_len: t.CSizeT = sha1_len + 1 + cls_len2 + 1 + mname_len - if key_len < VPI_KEY_LEN and rtype_len < VPI_RET_LEN: - # 方法名复制到临时缓冲(vpi_buf+dstart 非 null 结尾,不能直接 snprintf) - mname_buf: bytes = stdlib.malloc(mname_len + 1) - if mname_buf is not None: - string.strncpy(mname_buf, vpi_buf + dstart, mname_len) - mname_buf[mname_len] = '\0' - # 无注解的特殊方法(构造/析构)跳过:它们有专门调用路径 - skip_def: int = 0 - if arrow_pos >= le and ( - string.strcmp(mname_buf, "__init__") == 0 or \ - string.strcmp(mname_buf, "__new__") == 0 or \ - string.strcmp(mname_buf, "__before_init__") == 0 or \ - string.strcmp(mname_buf, "__after_init__") == 0): - skip_def = 1 - if skip_def == 0: - key_buf: bytes = stdlib.malloc(key_len + 1) - if key_buf is not None: - if cur_cls is not None: - viperlib.snprintf(key_buf, key_len + 1, "%s.%s.%s", src_sha1, cur_cls, mname_buf) - else: - viperlib.snprintf(key_buf, key_len + 1, "%s.%s", src_sha1, mname_buf) - # 去重:同一 key 已存在则跳过(同文件可能被多次加载) - dup_key: int = 0 - dki: int - for dki in range(_g_vpi_ret_count): - if string.strcmp(_g_vpi_ret_keys + dki * VPI_KEY_LEN, key_buf) == 0: - dup_key = 1 - break - grow_ok: int = 1 - if dup_key == 0 and _g_vpi_ret_count >= _g_vpi_ret_cap: - grow_ok = _grow_vpi_ret_cache() - if dup_key == 0 and grow_ok != 0: - string.strcpy(_g_vpi_ret_keys + _g_vpi_ret_count * VPI_KEY_LEN, key_buf) - string.strncpy(_g_vpi_ret_strs + _g_vpi_ret_count * VPI_RET_LEN, - ret_src, rtype_len) - (_g_vpi_ret_strs + _g_vpi_ret_count * VPI_RET_LEN)[rtype_len] = '\0' - _g_vpi_ret_count += 1 - stdlib.free(key_buf) - stdlib.free(mname_buf) - pos = le + 1 - line_no += 1 - if cur_cls is not None: - stdlib.free(cur_cls) - return 1 - - -# ============================================================ -# _grow_vpi_ret_cache - 扩容方法返回注解缓存(容量翻倍) -# -# 背景:VPI_RET_MAX 初始 4096,但 includes 模块量大(~90 个 stub、 -# 每个几十个方法),缓存写满后条目被静默丢弃,导致已缓存模块的 -# 方法(如 JsonValue._pool_alloc)查不到而 fail-fast 误报。 -# 用 stdlib.realloc 翻倍扩容(上限 1M 条目,防御异常增长)。 -# ============================================================ -def _grow_vpi_ret_cache() -> int: - """扩容返回注解缓存(容量翻倍),返回 1=成功 / 0=失败""" - global _g_vpi_ret_keys, _g_vpi_ret_strs, _g_vpi_ret_cap - if _g_vpi_ret_keys is None or _g_vpi_ret_cap <= 0: - return 0 - new_cap: int = _g_vpi_ret_cap * 2 - if new_cap > 1048576: - return 0 - new_keys: bytes = stdlib.realloc(_g_vpi_ret_keys, new_cap * VPI_KEY_LEN) - if new_keys is None: - return 0 - new_strs: bytes = stdlib.realloc(_g_vpi_ret_strs, new_cap * VPI_RET_LEN) - if new_strs is None: - return 0 - _g_vpi_ret_keys = new_keys - _g_vpi_ret_strs = new_strs - _g_vpi_ret_cap = new_cap - return 1 - - -# ============================================================ -# _ensure_vpi_ret_annot_loaded - 按需加载模块的 vpi stub 返回注解缓存 -# -# 背景:_cache_vpi_return_annots_text 仅在 stub 注入(LoadDepVpiIntoModule, -# 即"当前模块 import 了该模块")时填充缓存。但模块自身翻译时,自己的 -# stub 尚未被任何依赖方读取,且自己的 text.ll 要翻译完成才落盘,导致 -# "同模块方法调用(定义在后)"(如 json.__setitem__ 调用后定义的 -# _pool_alloc)在 found_func/text.ll/vpi 缓存三类来源上全部未命中。 -# 此函数在缓存未命中时直接读 {temp_dir}/{sha1[0:2]}/{sha1}.vpi -# (Converter 在 deps 阶段已生成全部 stub 文件),填充缓存后即可命中。 -# 幂等:模块已缓存过则跳过,不重复读文件。 -# ============================================================ -def _ensure_vpi_ret_annot_loaded(src_sha1: str, temp_dir: str) -> int: - """按需加载模块 vpi stub 的返回注解缓存,返回 1=已就绪 / 0=失败""" - if src_sha1 is None or temp_dir is None: - return 0 - sha1_len: t.CSizeT = string.strlen(src_sha1) - if sha1_len < 2: - return 0 - # 该模块已有缓存条目 → 跳过(幂等) - if _g_vpi_ret_keys is not None and _g_vpi_ret_count > 0: - pre_i: int - for pre_i in range(_g_vpi_ret_count): - pre_key: bytes = _g_vpi_ret_keys + pre_i * VPI_KEY_LEN - if string.strncmp(pre_key, src_sha1, sha1_len) == 0 and pre_key[sha1_len] == '.': - return 1 - # 构造路径 {temp_dir}/{sha1[0:2]}/{sha1}.vpi(逐字符拼接,避免 %c 格式化问题) - td_len: t.CSizeT = string.strlen(temp_dir) - path_len: t.CSizeT = td_len + sha1_len + 12 - vpi_path: bytes = stdlib.malloc(path_len) - if vpi_path is None: - return 0 - string.strcpy(vpi_path, temp_dir) - vpi_path[td_len] = '/' - vpi_path[td_len + 1] = src_sha1[0] - vpi_path[td_len + 2] = src_sha1[1] - vpi_path[td_len + 3] = '/' - string.strcpy(vpi_path + td_len + 4, src_sha1) - string.strcpy(vpi_path + td_len + 4 + sha1_len, ".vpi") - f: fileio.File | t.CPtr = fileio.File(vpi_path, fileio.MODE.R) - if f.closed: - stdlib.free(vpi_path) - return 0 - vpi_buf: bytes = stdlib.malloc(VPI_READ_BUF_SIZE) - if vpi_buf is None: - f.close() - stdlib.free(vpi_path) - return 0 - bytes_read: LONG = f.read_all(vpi_buf, VPI_READ_BUF_SIZE) - f.close() - if bytes_read > 0: - if bytes_read < VPI_READ_BUF_SIZE: - vpi_buf[bytes_read] = 0 - else: - vpi_buf[VPI_READ_BUF_SIZE - 1] = 0 - _cache_vpi_return_annots_text(vpi_buf, src_sha1) - stdlib.free(vpi_buf) - stdlib.free(vpi_path) - return 1 - - -# ============================================================ -# _subst_template_arg - 替换注解字符串中独立的模板参数 token -# -# 泛型模板返回注解(如 list[T].get -> T)中的类型参数名(T) -# 需替换为实际特化实参(AST|t.CPtr)后才能解析。仅替换前后 -# 非字母数字下划线边界的独立 token(避免误替换 t.CSizeT 等)。 -# 返回 stdlib 新分配字符串(调用者负责 free);失败返回 None。 -# ============================================================ -def _subst_template_arg(annot: str, tparam: str, targ: str) -> str: - """替换 annot 中独立的 tparam token 为 targ""" - if annot is None or tparam is None or targ is None: - return None - alen: t.CSizeT = string.strlen(annot) - tplen: t.CSizeT = string.strlen(tparam) - tglen: t.CSizeT = string.strlen(targ) - if tplen == 0 or tplen > alen: - return annot - # 容量 = alen + tglen*8 + 16 只覆盖 ≤8 次替换;替换次数无上限时 - # opos 会越界写穿 stdlib 堆(哨兵盲区 → CRT 堆损坏后任意 malloc/free - # 静默段错误、崩溃点漂移)。按最坏上界分配:每替换消耗 tplen 写 tglen, - # 最坏全部被替换 → alen + (alen/tplen)*tglen + 1。 - max_sub: t.CSizeT = alen / tplen - if max_sub == 0: - max_sub = 1 - out_size: t.CSizeT = alen + max_sub * tglen + 1 - out: bytes = stdlib.malloc(out_size) - if out is None: - return None - opos: t.CSizeT = 0 - p: t.CSizeT = 0 - while p < alen: - # 防御:opos 超分配即 fail-fast 返回 None(绝不越界写) - if opos >= out_size: - stdlib.free(out) - return None - matched: int = 0 - if annot[p] == tparam[0] and p + tplen <= alen: - if string.strncmp(annot + p, tparam, tplen) == 0: - prev_ch: int = 0 - next_ch: int = 0 - if p > 0: - prev_ch = annot[p - 1] - if p + tplen < alen: - next_ch = annot[p + tplen] - prev_ok: int = 1 - if (prev_ch >= 'a' and prev_ch <= 'z') or (prev_ch >= 'A' and prev_ch <= 'Z') or \ - (prev_ch >= '0' and prev_ch <= '9') or prev_ch == '_': - prev_ok = 0 - next_ok: int = 1 - if (next_ch >= 'a' and next_ch <= 'z') or (next_ch >= 'A' and next_ch <= 'Z') or \ - (next_ch >= '0' and next_ch <= '9') or next_ch == '_': - next_ok = 0 - if prev_ok != 0 and next_ok != 0: - string.strncpy(out + opos, targ, tglen) - opos += tglen - p += tplen - matched = 1 - if matched == 0: - out[opos] = annot[p] - opos += 1 - p += 1 - out[opos] = '\0' - return out - - -# ============================================================ -# _lookup_vpi_ret_annot - 查找缓存的方法返回注解字符串 -# ============================================================ -def _lookup_vpi_ret_annot(src_sha1: str, cls_name: str, method_name: str) -> str: - """查找缓存的方法返回注解字符串,未找到返回 None""" - if _g_vpi_ret_keys is None or _g_vpi_ret_count == 0: - return None - if src_sha1 is None or method_name is None: - return None - sha1_len: t.CSizeT = string.strlen(src_sha1) - cl_len: t.CSizeT = 0 - if cls_name is not None: - cl_len = string.strlen(cls_name) - me_len: t.CSizeT = string.strlen(method_name) - key_len: t.CSizeT = sha1_len + 1 + cl_len + 1 + me_len - key_buf: bytes = stdlib.malloc(key_len + 1) - if key_buf is None: - return None - if cls_name is not None: - viperlib.snprintf(key_buf, key_len + 1, "%s.%s.%s", src_sha1, cls_name, method_name) - else: - viperlib.snprintf(key_buf, key_len + 1, "%s.%s", src_sha1, method_name) - i: int - for i in range(_g_vpi_ret_count): - if string.strcmp(_g_vpi_ret_keys + i * VPI_KEY_LEN, key_buf) == 0: - stdlib.free(key_buf) - return _g_vpi_ret_strs + i * VPI_RET_LEN - # 泛型特化归一化匹配:list[AST|t.CPtr].get → list[T].get 模板缓存。 - # 命中后把模板注解中的类型参数名(如 T)替换为实参(AST|t.CPtr)再返回。 - # 不依赖模板类已注册/特化已发生(base.vp 可能先于 list 模块翻译)。 - if cls_name is not None: - lbkt_v: str = string.strchr(cls_name, '[') - if lbkt_v is not None: - rbkt_v: str = string.strrchr(cls_name, ']') - if rbkt_v is not None and rbkt_v > lbkt_v: - base_len_v: t.CSizeT = t.CSizeT(t.CUInt64T(lbkt_v) - t.CUInt64T(cls_name)) - param_len_v: t.CSizeT = t.CSizeT(t.CUInt64T(rbkt_v) - t.CUInt64T(lbkt_v) - 1) - if base_len_v > 0 and param_len_v > 0: - base_v: str = stdlib.malloc(base_len_v + 1) - param_v: str = stdlib.malloc(param_len_v + 1) - if base_v is not None and param_v is not None: - string.strncpy(base_v, cls_name, base_len_v) - base_v[base_len_v] = '\0' - string.strncpy(param_v, lbkt_v + 1, param_len_v) - param_v[param_len_v] = '\0' - # 遍历缓存找 {sha1}.{base}[xxx].{method} - gi: int - for gi in range(_g_vpi_ret_count): - gk: bytes = _g_vpi_ret_keys + gi * VPI_KEY_LEN - if string.strncmp(gk, src_sha1, sha1_len) == 0 and \ - gk[sha1_len] == '.' and \ - string.strncmp(gk + sha1_len + 1, base_v, base_len_v) == 0 and \ - gk[sha1_len + 1 + base_len_v] == '[': - gklb: str = string.strchr(gk + sha1_len + 1 + base_len_v, ']') - if gklb is not None: - tparam_len_v: t.CSizeT = t.CSizeT( - t.CUInt64T(gklb) - t.CUInt64T(gk + sha1_len + 1 + base_len_v) - 1) - meth_start_v: str = gklb + 2 # 跳过 ']' 和 '.' - if tparam_len_v > 0 and string.strcmp(meth_start_v, method_name) == 0: - tparam_v: str = stdlib.malloc(tparam_len_v + 1) - if tparam_v is not None: - string.strncpy(tparam_v, gk + sha1_len + 1 + base_len_v + 1, tparam_len_v) - tparam_v[tparam_len_v] = '\0' - new_annot_v: str = _subst_template_arg( - _g_vpi_ret_strs + gi * VPI_RET_LEN, tparam_v, param_v) - stdlib.free(tparam_v) - stdlib.free(base_v) - stdlib.free(param_v) - stdlib.free(key_buf) - return new_annot_v - stdlib.free(base_v) - stdlib.free(param_v) - stdlib.free(key_buf) - return None - - -# ============================================================ -# _resolve_single_vpi_type_str - 解析单个类型段(无 CPtr/CVoid)为 LLVMType -# -# 纯字符串解析,不构造 AST 节点。 -# ============================================================ -def _resolve_single_vpi_type_str(pool: memhub.MemBuddy | t.CPtr, - seg: str) -> llvmlite.LLVMType | t.CPtr: - """解析单个类型段为 LLVMType,无法识别返回 None""" - if seg is None or pool is None: - return None - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - # 内置别名 - if string.strcmp(seg, "str") == 0 or string.strcmp(seg, "bytes") == 0: - return i8_ptr_ty - if string.strcmp(seg, "int") == 0: - return llvmlite.Int32(pool) - if string.strcmp(seg, "bool") == 0: - return llvmlite.Int1(pool) - # LLVM 类型串:vpi 缓存对无返回注解方法默认存 "i32" - # (见 _cache_vpi_return_annots_text;push 等无注解方法返回 i32)。 - # 之前缺分支导致解析返回 None → 泛型模板方法(Vector[int].push)调用 - # 走 fail-fast"方法返回类型无法精确获取",实际是约定不一致。 - if string.strcmp(seg, "i32") == 0: - return llvmlite.Int32(pool) - if string.strcmp(seg, "i64") == 0: - return llvmlite.Int64(pool) - if string.strcmp(seg, "i16") == 0: - return llvmlite.Int16(pool) - if string.strcmp(seg, "i8") == 0: - return i8_ty - if string.strcmp(seg, "i1") == 0: - return llvmlite.Int1(pool) - if string.strcmp(seg, "f32") == 0: - return llvmlite.Float(pool) - if string.strcmp(seg, "f64") == 0: - return llvmlite.Double(pool) - if string.strcmp(seg, "void") == 0: - return llvmlite.Void(pool) - # vpi 源文本中 `-> None` 被原样缓存为 "None"(_cache_vpi_return_annots_text - # 提取 arrow_pos 后到 ':' 前的内容)。此前无 "None" 分支 → 解析返回 None → - # `-> None` 的跨模块方法(如 AssignGenMixin._register_cdefine_from_value)vpi - # 缓存命中也解析不出 void → 方法返回类型 fail-fast 误报(追加80e 断点 B)。 - # None 与 void 同义,归一到 Void。 - if string.strcmp(seg, "None") == 0: - return llvmlite.Void(pool) - # t.XXX / c.XXX 内置类型映射 - if string.strncmp(seg, "t.", 2) == 0 or string.strncmp(seg, "c.", 2) == 0: - attr_nm: str = seg + 2 - mapped_ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, attr_nm) - if mapped_ty is not None: - return mapped_ty - return None - # 模块限定类名 "memhub.MemBuddy" → 取最后一段查 struct - last_dot: str = string.strrchr(seg, '.') - if last_dot is not None: - cls_nm2: str = last_dot + 1 - mod_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(cls_nm2) - if mod_struct_ty is not None: - return mod_struct_ty - return None - # 裸类名 → 全局 struct 注册表 - bare_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(seg) - if bare_struct_ty is not None: - return bare_struct_ty - # 裸 typedef 名(如 VOIDPTR) - mapped_bare: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, seg) - if mapped_bare is not None: - return mapped_bare - return None - - -# ============================================================ -# _resolve_vpi_ret_annot_str - 直接解析 vpi 返回注解字符串为 LLVMType -# -# 背景:_parse_type_string 跨模块构造 ast.Name/ast.BinOp 在 TPV 中可能 -# 退化为裸函数调用(__init__/vtable 未执行),节点 kind() 异常导致 -# resolve 得到垃圾类型(如 Ptr(i8))。此处纯字符串解析避免该问题。 -# -# 支持: "str"/"bytes" → i8*; "int" → i32; "bool" → i1; -# "t.CChar" 等 → map_t_type 映射; -# "X | t.CPtr" → Ptr(Struct X); "t.CVoid | t.CPtr" → i8*; -# "memhub.MemBuddy | t.CPtr" → Ptr(Struct MemBuddy)。 -# ============================================================ -def _resolve_vpi_ret_annot_str(pool: memhub.MemBuddy | t.CPtr, - ret_annot: str, - i32_ty: llvmlite.LLVMType | t.CPtr, - i8_ptr_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.LLVMType | t.CPtr: - """直接解析 vpi 返回注解字符串为 LLVMType(不构造 AST 节点)""" - if ret_annot is None or pool is None: - return None - - # tuple[T1, T2, ...] → 匿名结构体 {T1, T2, ...}(多返回值打包, - # 与 TypeGenMixin._resolve_generic_subscript_ty 的 tuple 分支一致)。 - # b2a_hqx -> tuple[str, t.CUnsignedShort] 之前按普通段解析失败 → 调用侧 - # 返回类型退化 i8* → tuple 解包失效(hqx 段崩溃根因)。 - if string.strncmp(ret_annot, "tuple[", 6) == 0: - inner_len_t: t.CSizeT = 0 - while ret_annot[6 + inner_len_t] != ']' and ret_annot[6 + inner_len_t] != '\0': - inner_len_t += 1 - if ret_annot[6 + inner_len_t] != ']' or inner_len_t == 0: - return None - tup_head_t: llvmlite.ParamNode | t.CPtr = None - tup_tail_t: llvmlite.ParamNode | t.CPtr = None - tup_count_t: int = 0 - p_t: t.CSizeT = 0 - while p_t < inner_len_t: - # 跳过前导空格/逗号 - while p_t < inner_len_t and (ret_annot[6 + p_t] == ' ' or ret_annot[6 + p_t] == ','): - p_t += 1 - seg_s_t: t.CSizeT = p_t - while p_t < inner_len_t and ret_annot[6 + p_t] != ',': - p_t += 1 - seg_e_t: t.CSizeT = p_t - while seg_e_t > seg_s_t and ret_annot[6 + seg_e_t - 1] == ' ': - seg_e_t -= 1 - if seg_e_t > seg_s_t: - seg_len_t: t.CSizeT = seg_e_t - seg_s_t - seg_buf_t: bytes = stdlib.malloc(seg_len_t + 1) - if seg_buf_t is None: - return None - string.strncpy(seg_buf_t, ret_annot + 6 + seg_s_t, seg_len_t) - seg_buf_t[seg_len_t] = '\0' - seg_ty_t: llvmlite.LLVMType | t.CPtr = _resolve_single_vpi_type_str(pool, seg_buf_t) - stdlib.free(seg_buf_t) - if seg_ty_t is None: - return None - tup_node_t: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, seg_ty_t) - if tup_node_t is None: - return None - if tup_head_t is None: - tup_head_t = tup_node_t - else: - llvmlite.paramnode_set_next(tup_tail_t, tup_node_t) - tup_tail_t = tup_node_t - tup_count_t += 1 - if tup_head_t is None: - return None - return llvmlite.Struct(pool, tup_head_t, tup_count_t, None) - - has_cptr: int = 0 - has_cvoid: int = 0 - first_ty: llvmlite.LLVMType | t.CPtr = None - - buf_len: t.CSizeT = string.strlen(ret_annot) - pos: t.CSizeT = 0 - while pos <= buf_len: - # 跳过前导空格 - while pos < buf_len and ret_annot[pos] == ' ': - pos += 1 - seg_start: t.CSizeT = pos - while pos < buf_len and ret_annot[pos] != '|': - pos += 1 - seg_end: t.CSizeT = pos - # trim 尾随空格 - while seg_end > seg_start and ret_annot[seg_end - 1] == ' ': - seg_end -= 1 - if seg_end > seg_start: - seg_len2: t.CSizeT = seg_end - seg_start - seg_buf: bytes = stdlib.malloc(seg_len2 + 1) - if seg_buf is None: - break - string.strncpy(seg_buf, ret_annot + seg_start, seg_len2) - seg_buf[seg_len2] = '\0' - if string.strcmp(seg_buf, "t.CPtr") == 0 or string.strcmp(seg_buf, "CPtr") == 0: - has_cptr = 1 - elif string.strcmp(seg_buf, "t.CVoid") == 0 or string.strcmp(seg_buf, "CVoid") == 0: - has_cvoid = 1 - else: - seg_ty: llvmlite.LLVMType | t.CPtr = _resolve_single_vpi_type_str(pool, seg_buf) - if seg_ty is not None and first_ty is None: - first_ty = seg_ty - stdlib.free(seg_buf) - pos += 1 # 跳过 '|' - - if has_cptr != 0: - if has_cvoid != 0: - return i8_ptr_ty - if first_ty is not None: - return llvmlite.Ptr(pool, first_ty) - return i8_ptr_ty - if has_cvoid != 0: - # t.CVoid | t.State:State 是装饰器标记(编译侧忽略),t.CVoid → void。 - # 此前缺此分支 → first_ty=None → 返回 None → 跨模块函数返回类型 - # fail-fast(CPythonTest Py_Initialize() -> t.CVoid | t.State 根因)。 - return llvmlite.Void(pool) - if first_ty is not None: - return first_ty - return None - - -# ============================================================ -# VpiReader - .vpi AST 解析器 -# -# 从 .vpi 存根文件读取函数签名和 CTypedef 定义,注入 declare -# 到当前模块。用于跨模块函数调用时补充缺失的函数声明。 -# -# .vpi 文件由 StubGen.Converter._GeneratePyiFromAst 生成, -# 包含函数签名(无函数体)、类定义、变量声明、import 语句。 -# VpiReader 解析 .vpi 为 AST,提取 FunctionDef 和 CTypedef -# AnnAssign,在当前模块创建对应的 declare 声明。 -# ============================================================ - -# .vpi 读取缓冲区大小(256KB,与 PYI_BUF_SIZE 一致) -VPI_READ_BUF_SIZE: t.CSizeT = 262144 - -# SHA1 字符串长度(16 hex 字符) -SHA1_LEN: t.CSizeT = 16 - - -# ============================================================ -# _extract_sha1_from_path - 从 .vpi 文件路径提取 SHA1 -# -# .vpi 文件名格式为 {sha1}.vpi,sha1 是 16 位十六进制字符。 -# 从路径中找到最后一个路径分隔符(/ 或 \),取后续文件名的前 -# 16 个字符作为 SHA1。分配新缓冲区存储 SHA1(调用者负责 free)。 -# -# Args: -# vpi_path: .vpi 文件路径 -# -# Returns: -# SHA1 字符串(stdlib.malloc 分配,需 stdlib.free),None 失败 -# ============================================================ -def _extract_sha1_from_path(vpi_path: str) -> str: - """从 .vpi 文件路径提取 SHA1(文件名前16字符,malloc 分配)""" - if vpi_path is None: - return None - # 查找最后一个路径分隔符 / 或 \ - total_len: t.CSizeT = string.strlen(vpi_path) - if total_len < SHA1_LEN + 4: # 至少需要 "xxxx.vpi" 的长度 - return None - # 从后向前查找最后一个 / 或 \ - sep_pos: t.CSizeT = total_len - while sep_pos > 0: - sep_pos -= 1 - ch: t.CChar = vpi_path[sep_pos] - if ch == '/' or ch == '\\': - sep_pos += 1 - break - if sep_pos + SHA1_LEN > total_len: - return None - # 分配缓冲区并复制 SHA1(16 字符 + null 终止符) - sha1_buf: str = stdlib.malloc(SHA1_LEN + 1) - if sha1_buf is None: - return None - string.strncpy(sha1_buf, vpi_path + sep_pos, SHA1_LEN) - sha1_buf[SHA1_LEN] = '\0' - return sha1_buf - - -# ============================================================ -# _stub_add_imported - 追加模块名到空格分隔列表(stub 上下文收集用) -# -# 与 HandlesImports.add_imported_module 逻辑一致,但内联在本模块, -# 避免 VpiReader → HandlesImports → StubMerger → VpiReader 循环依赖。 -# ============================================================ -def _stub_add_imported(pool: memhub.MemBuddy | t.CPtr, - cur: str, name: str) -> str: - """追加模块名到空格分隔列表(pool 分配),返回新列表""" - if name is None: - return cur - if cur is None: - nlen: t.CSizeT = string.strlen(name) - buf: str = pool.alloc(nlen + 1) - if buf is not None: - string.strcpy(buf, name) - return buf - old_len: t.CSizeT = string.strlen(cur) - name_len: t.CSizeT = string.strlen(name) - buf2: str = pool.alloc(old_len + 1 + name_len + 1) - if buf2 is not None: - string.strcpy(buf2, cur) - buf2[old_len] = ' ' - string.strcpy(buf2 + old_len + 1, name) - return buf2 - - -# ============================================================ -# _stub_add_from - 追加 from-import 映射("local:mod[:orig]" 空格分隔) -# ============================================================ -def _stub_add_from(pool: memhub.MemBuddy | t.CPtr, - cur: str, local: str, mod: str, orig: str) -> str: - """追加 from-import 映射(pool 分配),返回新列表""" - if local is None or mod is None: - return cur - entry: str = pool.alloc(256) - if entry is None: - return cur - if orig is not None and string.strcmp(orig, local) != 0: - viperlib.snprintf(entry, 256, "%s:%s:%s", local, mod, orig) - else: - viperlib.snprintf(entry, 256, "%s:%s", local, mod) - if cur is None: - return entry - old_len: t.CSizeT = string.strlen(cur) - entry_len: t.CSizeT = string.strlen(entry) - buf: str = pool.alloc(old_len + 1 + entry_len + 1) - if buf is not None: - string.strcpy(buf, cur) - buf[old_len] = ' ' - string.strcpy(buf + old_len + 1, entry) - return buf - - -# ============================================================ -# ParseVpiIntoModule - 解析 .vpi 文件,将函数声明注入到当前模块 -# -# 读取 .vpi 文件 → AST 解析 → 遍历顶层节点 → 创建 declare 声明。 -# 对每个 FunctionDef: -# 1. 提取函数名、参数、返回类型 -# 2. 检测 CExport/CExtern/State 标记(决定是否用裸名) -# 3. 用 find_func_in_module 去重(已存在则跳过) -# 4. 用 create_declare + add_param 创建 declare 声明 -# 5. 注册到函数表(用裸名,非 mangled_name) -# 对 AnnAssign with t.CTypedef:调用 register_ctypedef 注册 -# ClassDef/Import/ImportFrom:跳过 -# -# Args: -# pool: 内存池 -# mod: 当前 LLVM 模块 -# vpi_path: .vpi 文件路径 -# trans: 翻译器对象 -# -# Returns: -# 1=成功,0=失败 -# ============================================================ -def ParseVpiIntoModule(pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - vpi_path: str, - trans: HT.Translator | t.CPtr) -> int: - """解析 .vpi 文件,将函数声明注入到当前模块 - - 解析 stub 期间临时将错误归因切换到被读 stub 文件(.vpi): - 注解解析失败时 fatal_error 应指向 stub 及其行号(真实出错位置), - 而非当前编译模块(错误归因修复)。 - """ - if pool is None or mod is None or vpi_path is None or trans is None: - return 0 - saved_cur: str = HandlesType.get_current_file() - HandlesType.set_current_file(vpi_path) - ret: int = _ParseVpiIntoModuleImpl(pool, mod, vpi_path, trans) - HandlesType.set_current_file(saved_cur) - return ret - - -def _ParseVpiIntoModuleImpl(pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - vpi_path: str, - trans: HT.Translator | t.CPtr) -> int: - """解析 .vpi 文件,将函数声明注入到当前模块(ParseVpiIntoModule 实际实现)""" - if pool is None or mod is None or vpi_path is None or trans is None: - return 0 - - # 1. 读取 .vpi 文件 - f: fileio.File | t.CPtr = fileio.File(vpi_path, fileio.MODE.R) - if f.closed: - return 0 - vpi_buf: bytes = stdlib.malloc(VPI_READ_BUF_SIZE) - if vpi_buf is None: - f.close() - return 0 - bytes_read: LONG = f.read_all(vpi_buf, VPI_READ_BUF_SIZE) - f.close() - if bytes_read <= 0: - stdlib.free(vpi_buf) - return 0 - if bytes_read < VPI_READ_BUF_SIZE: - vpi_buf[bytes_read] = 0 - else: - vpi_buf[VPI_READ_BUF_SIZE - 1] = 0 - - # 2. 解析为 AST - lx: ast.Lexer | t.CPtr = ast.new_lexer(pool) - if lx is None: - stdlib.free(vpi_buf) - return 0 - ast._lexer_init(lx, vpi_buf, pool) - tokens: ast.Token | t.CPtr = ast.tokenize(lx) - tree: ast.AST | t.CPtr = ast.parse_tokens(pool, tokens) - # vpi_buf 延迟释放:AST 字符串字段可能引用 vpi_buf 内部(token 零拷贝), - # 提前 free 会导致 Name.id/Attribute.attr 等悬空 → 后续解析返回错误类型。 - # 在 ParseVpiIntoModule 末尾统一释放。 - if tree is None: - stdlib.free(vpi_buf) - return 0 - - # 提取源模块 SHA1(用于函数名混淆,在 AST 解析成功后提取避免提前返回时泄漏) - src_sha1: str = _extract_sha1_from_path(vpi_path) - - # 从 vpi_buf 文本直接提取方法返回注解字符串缓存到 stdlib - # (不依赖 AST tree:tree 深层节点在后续遍历处理时可能被覆盖损坏, - # 但 vpi_buf 原始文本在 ParseVpiIntoModule 末尾才释放,始终有效) - _cache_vpi_return_annots_text(vpi_buf, src_sha1) - - # 3. 遍历 AST 顶层节点 - ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children - if ch is None: - if src_sha1 is not None: - stdlib.free(src_sha1) - return 1 - n: t.CSizeT = ch.__len__() - - # 收集 stub 内被读模块自己的 import 语句,构建独立的注解解析上下文。 - # .vpi stub 顶部含被读模块的 import(Converter 已写入,如 string.vp 的 - # "import t, c"),用它替代当前模块的 imported_modules/from_imports 去 - # 解析注解——根治跨上下文误报(如 t.CArray[str] 需要 't' 已导入)。 - stub_imported_modules: str = None - stub_from_imports: str = None - si: t.CSizeT - for si in range(n): - schild: ast.AST | t.CPtr = ch.get(si) - if schild is None: - continue - sk: int = schild.kind() - if sk == ast.ASTKind.Import: - simp: ast.Import | t.CPtr = (ast.Import | t.CPtr)(schild) - if simp.names is not None: - sn_n: t.CSizeT = simp.names.__len__() - sni: t.CSizeT - for sni in range(sn_n): - sal: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(simp.names.get(sni)) - if sal is not None and sal.name is not None: - stub_imported_modules = _stub_add_imported( - pool, stub_imported_modules, sal.name) - if sal.asname is not None: - stub_imported_modules = _stub_add_imported( - pool, stub_imported_modules, sal.asname) - elif sk == ast.ASTKind.ImportFrom: - sifr: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(schild) - sifr_mod: str = sifr.module - if sifr_mod is not None: - stub_imported_modules = _stub_add_imported( - pool, stub_imported_modules, sifr_mod) - if sifr.names is not None: - sifr_nn: t.CSizeT = sifr.names.__len__() - sifri: t.CSizeT - for sifri in range(sifr_nn): - sial: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(sifr.names.get(sifri)) - if sial is not None and sial.name is not None: - # '*' star import 不建 from 映射(lookup 有 star 回退) - if string.strcmp(sial.name, "*") != 0: - slocal: str = sial.name - sorig: str = None - if sial.asname is not None: - slocal = sial.asname - sorig = sial.name - stub_from_imports = _stub_add_from( - pool, stub_from_imports, slocal, sifr_mod, sorig) - - # 用 stub 自己的 imports 替代当前模块的(stub 注解解析上下文正确性) - imported_modules: str = trans._imported_modules - from_imports: str = trans._from_imports - if stub_imported_modules is not None: - imported_modules = stub_imported_modules - if stub_from_imports is not None: - from_imports = stub_from_imports - # 把源模块自己加入 stub 注解上下文:stub 注解(如 __sha512 的 transform - # 参数 t.CArray[t.CUInt8T, SHA512_BLOCK_LEN])引用源模块自身的 CDefine, - # 但 stub 的 import 只含被 import 的模块(t/c/string),不含自己。 - # 不加则 _eval_const_int_expr 跨模块 CDefine 查找遍历不到源模块 - # (imported_modules 无 __sha512)→ t.CArray count 报"必须是整数常量"。 - # 示例:RelPath "hashlib/__sha512.vp" → 模块名 "hashlib.__sha512"。 - if src_sha1 is not None: - import lib.core.StubMerger as StubMerger - stub_rel_src: str = StubMergerStore.LookupSha1RelPath(src_sha1) - if stub_rel_src is not None: - sr_len_src: t.CSizeT = string.strlen(stub_rel_src) - if sr_len_src > 3 and string.strncmp(stub_rel_src + sr_len_src - 3, ".vp", 3) == 0: - sr_len_src -= 3 - elif sr_len_src > 3 and string.strncmp(stub_rel_src + sr_len_src - 3, ".py", 3) == 0: - sr_len_src -= 3 - if sr_len_src > 0: - src_mod_buf: str = stdlib.malloc(sr_len_src + 1) - if src_mod_buf is not None: - sri_src: t.CSizeT - for sri_src in range(sr_len_src): - ch_src: t.CChar = stub_rel_src[sri_src] - if ch_src == '/' or ch_src == '\\': - src_mod_buf[sri_src] = '.' - else: - src_mod_buf[sri_src] = ch_src - src_mod_buf[sr_len_src] = '\0' - imported_modules = _stub_add_imported(pool, imported_modules, src_mod_buf) - stdlib.free(src_mod_buf) - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - # 函数表信息 - funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs - max_funcs: int = 1024 - - i: t.CSizeT - for i in range(n): - child: ast.AST | t.CPtr = ch.get(i) - if child is None: - continue - kd: int = child.kind() - - # FunctionDef → 提取函数名、参数、返回类型 → 注入 declare - if kd == ast.ASTKind.FunctionDef: - fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child) - if fd is None or fd.name is None: - continue - _inject_function_declare(pool, mod, fd, trans, src_sha1, - imported_modules, from_imports, - i32_ty, i8_ptr_ty, - funcs_ptr, max_funcs) - continue - - # AnnAssign with t.CTypedef → 注册 CTypedef; - # 普通模块级全局变量(如 tokens._op_head)→ external global declare - if kd == ast.ASTKind.AnnAssign: - aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(child) - if aa is None: - continue - if HandlesType._is_ctypedef_annotation(aa.annotation) != 0: - _register_ctypedef_from_annassign(pool, aa) - else: - _inject_global_variable_declare(pool, mod, aa, trans, - stub_imported_modules, stub_from_imports, - i32_ty, i8_ptr_ty, src_sha1) - continue - - # ClassDef → 递归注入类内方法(如 MemBuddy.__init__/alloc) - # 方法 declare 使用 {sha1}.{ClassName}.{method} 混淆名, - # 参数类型从 vpi 注解解析(避免调用时 _ensure_method_declare 用实参类型 - # 创建错误 declare,如 size: t.CSizeT 被写成 i32 而非 i64) - if kd == ast.ASTKind.ClassDef: - class_cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child) - if class_cd is None or class_cd.name is None: - continue - cls_name_v: str = class_cd.name - # 泛型类(class X[T])跳过方法 declare 注入:stub 模板签名含类级 - # 类型参数 T(如 ndarray[T].__add__ 的返回 ndarray[T] | t.CPtr), - # 注入时 T 无法确定具体类型,直接解析会触发 - # _specialize_generic_class("ndarray", ["T"]) 错误特化 - # (Phase2 翻译 App 文件注入 numpy stub 时崩溃)。 - # 具体特化的方法 define 已在 Phase1 生成,跨模块调用按特化类名 - # (ndarray[t.CDouble].__add__)查找命中,无需 stub 模板 declare。 - tp_stub: list[str] | t.CPtr = class_cd.type_params - if tp_stub is not None and tp_stub.__len__() > 0: - continue - cls_children: list[ast.AST | t.CPtr] | t.CPtr = class_cd.children - if cls_children is not None: - cn2: t.CSizeT = cls_children.__len__() - for ci2 in range(cn2): - m_child: ast.AST | t.CPtr = cls_children.get(ci2) - if m_child is None: - continue - if m_child.kind() != ast.ASTKind.FunctionDef: - continue - m_fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(m_child) - if m_fd is None or m_fd.name is None: - continue - _inject_method_declare(pool, mod, m_fd, cls_name_v, trans, - src_sha1, imported_modules, from_imports, - i32_ty, i8_ptr_ty, funcs_ptr, max_funcs) - continue - - # Import/ImportFrom → 跳过 - # (import 不需要处理) - - # 释放 SHA1 缓冲区(_extract_sha1_from_path 用 stdlib.malloc 分配) - if src_sha1 is not None: - stdlib.free(src_sha1) - # vpi_buf 延迟到全部 tree 处理完成后释放(见解析处注释) - stdlib.free(vpi_buf) - return 1 - - -# ============================================================ -# _inject_global_variable_declare - 从 vpi AnnAssign 创建模块级全局变量 declare -# -# 背景:vpi 里模块级全局变量(如 tokens.vp 的 _op_head: OpEntry | t.CPtr = None) -# 需在当前模块创建 external global 声明(短名 @name,COFF 按名链接),否则 -# 跨模块 from-import 读取全局变量时 find_global_in_module 找不到 → -# "跨模块全局变量类型未知(stub 未注入)" 误杀(lexer.vp 读 tokens._op_head)。 -# ============================================================ -def _inject_global_variable_declare(pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - aa: ast.AnnAssign | t.CPtr, - trans: HT.Translator | t.CPtr, - imported_modules: str, - from_imports: str, - i32_ty: llvmlite.LLVMType | t.CPtr, - i8_ptr_ty: llvmlite.LLVMType | t.CPtr, - src_sha1: str) -> None: - """从 vpi AnnAssign 创建模块级全局变量 external declare(mangled 名 @.)""" - if pool is None or mod is None or aa is None or trans is None: - return - tgt_v: ast.AST | t.CPtr = aa.target - if tgt_v is None or tgt_v.kind() != ast.ASTKind.Name: - return - nm_v: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tgt_v) - if nm_v is None or nm_v.id is None: - return - gname_v: str = nm_v.id - if gname_v[0] == '\0': - return - # mangled 名:带源模块 SHA1 前缀(对齐定义端 5f7a873 的 @. - # 与查找端 from-import 精确查找三方一致;裸短名会退化为未定义)。 - # 注:a42923c 曾把此处写成未定义变量 gv_name_m(笔误,mangle 未实现), - # 导致注入空名 @ = external global → llc "expected top-level entity"。 - gv_name_m: str = gname_v - if src_sha1 is not None and src_sha1[0] != '\0': - ml_v: t.CSizeT = string.strlen(src_sha1) + 1 + string.strlen(gname_v) + 1 - gv_name_m = pool.alloc(ml_v) - if gv_name_m is not None: - viperlib.snprintf(gv_name_m, ml_v, "%s.%s", src_sha1, gname_v) - # 去重:遍历模块全局变量链表(mangled 名匹配) - cur_v: llvmlite.GlobalVariable | t.CPtr = mod.GlobalHead - while cur_v is not None: - if cur_v.Name is not None and string.strcmp(cur_v.Name, gv_name_m) == 0: - return - cur_v = cur_v.Next - # 解析注解类型(裸类 → Ptr(struct),CArray → 元素指针) - resolved_v: llvmlite.LLVMType | t.CPtr = None - if aa.annotation is not None: - resolved_v = HandlesType.resolve_annotation_type( - pool, aa.annotation, imported_modules, from_imports, trans) - if resolved_v is None: - return # 类型解析失败跳过:调用侧有 fail-fast 定位 - gv_ty_v: llvmlite.LLVMType | t.CPtr = resolved_v - match resolved_v: - case llvmlite.LLVMType.Struct(_, _, _): - gv_ty_v = llvmlite.Ptr(pool, resolved_v) - case llvmlite.LLVMType.Array(aelem_v, acount_v): - # 定长数组(CArray[T, N]):保留完整数组类型 [N x T],与定义端 - # handle_module_level_var 生成的 global [N x T] 一致——此前一律 - # 衰减为元素指针 i32*,链接后引用端 load 把数组前 8 字节当指针 - # 读 → 垃圾地址 → zdeflate_len_to_symbol 读 NULL/垃圾崩溃 - # (zdeflate_len_base 跨模块数组根因)。 - if acount_v > 0: - gv_ty_v = resolved_v - else: - # 不定长数组(CArray[T, None]):元素指针(C 数组衰减) - gv_ty_v = llvmlite.Ptr(pool, aelem_v) - case _: - gv_ty_v = resolved_v - gv_v: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, gv_name_m, gv_ty_v) - if gv_v is None: - return - llvmlite.module_add_global(mod, gv_v) - gv_v.Linkage = "external" - - -# ============================================================ -# _inject_function_declare - 为单个 FunctionDef 创建 declare 声明 -# -# 检测 CExport/CExtern/State 标记,计算 mangled name, -# 用 find_func_in_module 去重,创建 declare 并添加参数, -# 注册到函数表。 -# ============================================================ -def _inject_function_declare(pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - fd: ast.FunctionDef | t.CPtr, - trans: HT.Translator | t.CPtr, - src_sha1: str, - imported_modules: str, - from_imports: str, - i32_ty: llvmlite.LLVMType | t.CPtr, - i8_ptr_ty: llvmlite.LLVMType | t.CPtr, - funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr, - max_funcs: int) -> None: - """为 FunctionDef 创建 declare 声明并注入到模块""" - if fd.name is None: - return - - # 检测 CExtern/State/CExport 标记(从返回类型注解) - has_extern: int = 0 - has_state: int = 0 - has_export: int = 0 - if fd.returns is not None: - has_extern = HandlesType.has_decorator_marker(fd.returns, "CExtern") - has_state = HandlesType.has_decorator_marker(fd.returns, "State") - has_export = HandlesType.has_decorator_marker(fd.returns, "CExport") - - # 计算 mangled name - # CExport/CExtern/State/main 函数用裸名,其他函数用源模块 SHA1 前缀 - use_bare_name: int = 0 - if has_extern != 0 or has_state != 0 or has_export != 0 or string.strcmp(fd.name, "main") == 0: - mangled_name: str = fd.name - use_bare_name = 1 - else: - mangled_name = HandlesFunctions._mangle_name_with_sha1(src_sha1, fd.name) - - # 去重:如果函数已存在则跳过 - existing: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module(mod, mangled_name) - if existing is not None: - return - # 也检查裸名(非裸名模式时,CExport 函数可能已通过其他途径注册) - if use_bare_name == 0: - existing_bare: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module(mod, fd.name) - if existing_bare is not None: - return - - # 推断返回类型 - # 优先用缓存的返回注解字符串(tree 解析后立即提取,节点未损坏) - # 直接字符串解析(绕开 _parse_type_string 跨模块 AST 构造在 TPV 中的 - # __init__/vtable 未执行问题,节点 kind() 异常导致 resolve 得垃圾类型) - ret_ty: llvmlite.LLVMType | t.CPtr = None - ret_annot_fd: str = _lookup_vpi_ret_annot(src_sha1, None, fd.name) - if ret_annot_fd is not None: - ret_ty = _resolve_vpi_ret_annot_str(pool, ret_annot_fd, i32_ty, i8_ptr_ty) - if ret_ty is None and fd.returns is not None: - ret_ty = HandlesType.resolve_annotation_type( - pool, fd.returns, imported_modules, from_imports, trans) - # 如果返回类型是纯 t.State(无实际类型),用 Void - if ret_ty is None and fd.returns is not None: - if has_state != 0: - ret_ty = llvmlite.Void(pool) - # 默认返回 i32 - if ret_ty is None: - ret_ty = i32_ty - - # 创建 declare - func: llvmlite.Function | t.CPtr = llvmlite.create_declare( - pool, mod, mangled_name, ret_ty) - if func is None: - return - - # 提取参数并添加到 declare - param_count: int = 0 - if fd.args is not None: - args_node: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args) - if args_node.args is not None: - args_list: list[ast.AST | t.CPtr] | t.CPtr = args_node.args - param_count = args_list.__len__() - # 参数数上限哨兵(fail-fast):vpi tree 深层节点在遍历处理过程中 - # 可能被覆盖损坏(见本文件顶部注释),fd.args 悬空时 __len__() - # 返回垃圾大数 → for 循环 add_param 海量次 → Params 链超长, - # dump 时步数哨兵误报"链表成环"。超限立即报错定位。 - if param_count < 0 or param_count > 128: - stdio.printf( - "[VPIS] 参数数异常: 函数名=%s param_count=%d(fd.args=%llu,tree 可能被覆盖,终止)\n", - fd.name, param_count, t.CUInt64T(fd.args)) - stdlib.exit(1) - pi: t.CSizeT - for pi in range(param_count): - ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(args_list.get(pi)) - if ag is None: - continue - pname: str = ag.arg - if pname is None: - pname = "arg" - # 解析参数类型 - param_ty: llvmlite.LLVMType | t.CPtr = i8_ptr_ty - if ag.annotation is not None: - resolved_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, ag.annotation, imported_modules, from_imports, trans) - if resolved_ty is not None: - # 结构体按值参数 → i64:跨模块结构体在本模块是 opaque - # (未定义字段),LLVM 不允许 opaque struct 作为函数参数 - # (llc: invalid type for function argument)。Windows ABI - # 小结构体(≤8 字节,如 COORD)按整数寄存器传,映射 i64 兼容。 - # CArray 参数 → 元素指针 ty*(C 数组衰减,与编译侧一致)。 - match resolved_ty: - case llvmlite.LLVMType.Struct(_, _, _): - param_ty = llvmlite.Int64(pool) - case llvmlite.LLVMType.Array(aelem_ty, _): - param_ty = llvmlite.Ptr(pool, aelem_ty) - case _: - param_ty = resolved_ty - llvmlite.add_param(pool, func, param_ty, pname) - # *args 变长参数:标记 IsVarArg=1,使调用侧走 C ABI 参数提升 - # (i8/i16 → i32,float → double),避免 %d/%x 等格式因参数按 i64 - # 传递而读错(第二个 %x 读到第一个 i64 槽的高 4 字节)。 - if args_node.vararg is not None: - func.IsVarArg = 1 - - # 注册到函数表(用裸名 fd.name,不是 mangled_name) - if funcs_ptr is not None: - cur_count: int = trans._func_count - if ExprCallTable.add_func_to_table(funcs_ptr, cur_count, fd.name, func, max_funcs, - None, 0, param_count) == 0: - trans._func_count = cur_count + 1 - - -# ============================================================ -# _inject_method_declare - 为 ClassDef 内的方法创建 declare -# -# 方法混淆名: {src_sha1}.{ClassName}.{method} -# 参数类型从 vpi 注解解析(self 无注解时默认为 i8*)。 -# 注入正确签名避免调用时 _ensure_method_declare 用实参类型 -# 创建错误 declare(如 size: t.CSizeT 被写成 i32 而非 i64)。 -# ============================================================ -def _inject_method_declare(pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - m_fd: ast.FunctionDef | t.CPtr, - cls_name: str, - trans: HT.Translator | t.CPtr, - src_sha1: str, - imported_modules: str, - from_imports: str, - i32_ty: llvmlite.LLVMType | t.CPtr, - i8_ptr_ty: llvmlite.LLVMType | t.CPtr, - funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr, - max_funcs: int) -> None: - """为 ClassDef 内方法创建 declare 声明并注入到模块""" - if m_fd is None or m_fd.name is None or cls_name is None: - return - if src_sha1 is None: - return - - # 构造方法查找名: ClassName.method - lookup_name_len: t.CSizeT = string.strlen(cls_name) + 1 + string.strlen(m_fd.name) + 1 - lookup_name: str = pool.alloc(lookup_name_len) - if lookup_name is None: - return - viperlib.snprintf(lookup_name, lookup_name_len, "%s.%s", cls_name, m_fd.name) - - # mangled name: {src_sha1}.{ClassName}.{method} - mangled_len: t.CSizeT = string.strlen(src_sha1) + 1 + lookup_name_len - mangled_name: str = pool.alloc(mangled_len) - if mangled_name is None: - return - viperlib.snprintf(mangled_name, mangled_len, "%s.%s", src_sha1, lookup_name) - - # 去重:如果方法已存在则跳过 - existing: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module(mod, mangled_name) - if existing is not None: - return - - # 推断返回类型 - # 优先用缓存的返回注解字符串(tree 解析后立即提取,节点未损坏), - # 用 _parse_type_string 重新解析成新 AST(立即使用不被覆盖)。 - # 直接解析 m_fd.returns 可能因 vpi tree 深层节点被覆盖而得到垃圾类型。 - ret_ty: llvmlite.LLVMType | t.CPtr = None - ret_annot: str = _lookup_vpi_ret_annot(src_sha1, cls_name, m_fd.name) - if ret_annot is not None: - ret_ty = _resolve_vpi_ret_annot_str(pool, ret_annot, i32_ty, i8_ptr_ty) - if ret_ty is None and m_fd.returns is not None: - ret_ty = HandlesType.resolve_annotation_type( - pool, m_fd.returns, imported_modules, from_imports, trans) - # __new__ 无返回注解时推断为类指针(__new__ 返回 self 指针,默认 i32 会截断指针) - if ret_ty is None and string.strcmp(m_fd.name, "__new__") == 0: - cls_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(cls_name) - if cls_ty is not None: - ret_ty = llvmlite.Ptr(pool, cls_ty) - if ret_ty is None: - ret_ty = i32_ty - - # 创建 declare - func: llvmlite.Function | t.CPtr = llvmlite.create_declare( - pool, mod, mangled_name, ret_ty) - if func is None: - return - - # 提取参数并添加到 declare - param_count: int = 0 - if m_fd.args is not None: - args_node: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(m_fd.args) - if args_node.args is not None: - args_list: list[ast.AST | t.CPtr] | t.CPtr = args_node.args - param_count = args_list.__len__() - # 参数数上限哨兵(fail-fast):与 _inject_function_declare 同因 - # (vpi tree 深层节点被覆盖损坏时 __len__() 返回垃圾大数)。 - if param_count < 0 or param_count > 128: - stdio.printf( - "[VPIS] 参数数异常: 方法名=%s.%s param_count=%d(m_fd.args=%llu,tree 可能被覆盖,终止)\n", - cls_name, m_fd.name, param_count, t.CUInt64T(m_fd.args)) - stdlib.exit(1) - pi: t.CSizeT - for pi in range(param_count): - ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(args_list.get(pi)) - if ag is None: - continue - pname: str = ag.arg - if pname is None: - pname = "arg" - # 解析参数类型 - param_ty: llvmlite.LLVMType | t.CPtr = i8_ptr_ty - if ag.annotation is not None: - resolved_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, ag.annotation, imported_modules, from_imports, trans) - if resolved_ty is not None: - # 结构体按值参数 → i64:跨模块结构体在本模块是 opaque - # (未定义字段),LLVM 不允许 opaque struct 作为函数参数 - # (llc: invalid type for function argument)。Windows ABI - # 小结构体(≤8 字节,如 COORD)按整数寄存器传,映射 i64 兼容。 - # CArray 参数 → 元素指针 ty*(C 数组衰减,与编译侧一致)。 - match resolved_ty: - case llvmlite.LLVMType.Struct(_, _, _): - param_ty = llvmlite.Int64(pool) - case llvmlite.LLVMType.Array(aelem_ty, _): - param_ty = llvmlite.Ptr(pool, aelem_ty) - case _: - param_ty = resolved_ty - llvmlite.add_param(pool, func, param_ty, pname) - - # OOP iter 协议:__next__ 方法 stub 声明带隐藏 __stop_iter_flag__(i1*), - # 与 _translate_method 的 define 签名一致(对齐 TPC HandlesFunctions.py - # L703-705)。for x in obj 循环会以 2 个实参调用 __next__(self, flag)。 - if m_fd.name is not None and string.strcmp(m_fd.name, "__next__") == 0: - i1_ty_si: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - if i1_ty_si is not None: - i1_ptr_ty_si: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_si) - if i1_ptr_ty_si is not None: - llvmlite.add_param(pool, func, i1_ptr_ty_si, "__stop_iter_flag__") - - # 注册到函数表(用裸名 ClassName.method,与调用方 lookup_name 一致) - # ParamCount 不含 self(方法首参 self/cls 不计入,与 _translate_method 的 - # md_param_count = args.__len__() - 1 保持一致)——默认参数填充按非 self - # 参数计数,若含 self 会导致 mdf_param_count 虚高、填充逻辑错位/越界。 - if funcs_ptr is not None: - cur_count: int = trans._func_count - param_count_no_self: int = param_count - if param_count_no_self > 0: - param_count_no_self -= 1 - if ExprCallTable.add_func_to_table(funcs_ptr, cur_count, lookup_name, func, max_funcs, - None, 0, param_count_no_self) == 0: - trans._func_count = cur_count + 1 - - -# ============================================================ -# _register_ctypedef_from_annassign - 从 AnnAssign 节点注册 CTypedef -# -# 提取 NAME: t.CTypedef = Type 中的名称和类型表达式字符串, -# 调用 register_ctypedef 注册到动态 CTypedef 表。 -# ============================================================ -def _register_ctypedef_from_annassign(pool: memhub.MemBuddy | t.CPtr, - aa: ast.AnnAssign | t.CPtr) -> None: - """从 AnnAssign 节点提取并注册 CTypedef""" - if aa is None or pool is None: - return - # 提取目标名称(必须是 Name 节点) - if aa.target is None or aa.target.kind() != ast.ASTKind.Name: - return - tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) - if tgt.id is None: - return - # 提取类型表达式字符串(从 value AST 节点) - if aa.value is None: - return - type_str: str = HandlesType._get_type_name_from_annotation(pool, aa.value) - if type_str is None: - return - # 注册 CTypedef - HandlesType.register_ctypedef(pool, tgt.id, type_str) +import lib.core.Gen.GenApi as GenApi +import lib.core.Gen.GenTypes as GenTypes +import t, c +from stdint import * +import ast +import string +import stdio +import stdlib +import sys +import memhub +import llvmlite +import viperlib +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesTranslator as HT +import lib.core.StubMergerStore as StubMergerStore +import lib.core.Handles.ExprCallTable as ExprCallTable + + +# ============================================================ +# 方法返回注解缓存(stdlib 持久) +# +# 背景:vpi tree 在"解析后立即"有效,但遍历处理到后续类的方法时, +# 深层 AST 节点(如 parse_args 的 returns 注解)可能已被覆盖损坏 +# (kind() 读取异常),直接 resolve 得到垃圾类型(如 i8*)。 +# 因此采用文本提取方案:ParseVpiIntoModule 读 .vpi stub 时,从 +# vpi_buf 原始文本(在函数末尾才释放,始终有效)直接按行格式 +# 提取 "def m(...) -> Ret:" 的返回注解字符串缓存到 stdlib(持久, +# 不受 pool 状态影响)。HandlesExprCall._lookup_method_ret_ty_via_vpi +# 按 sha1.类名.方法名 查表并用 _resolve_vpi_ret_annot_str 纯字符串 +# 解析为 LLVMType,返回类型始终来自方法定义处,无白名单/无硬编码。 +# ============================================================ +VPI_RET_MAX: t.CDefine = 4096 +VPI_KEY_LEN: t.CDefine = 224 +VPI_RET_LEN: t.CDefine = 224 + +_g_vpi_ret_keys: bytes = None +_g_vpi_ret_strs: bytes = None +_g_vpi_ret_count: int = 0 +_g_vpi_ret_cap: int = 0 + + +# ============================================================ +# _cache_vpi_return_annots_text - 从 vpi_buf 文本直接提取方法返回注解 +# +# 完全不依赖 AST tree(tree 深层节点在后续处理中可能损坏), +# 直接按 vpi 生成文件的行格式提取: +# " def method(...) -> Ret: pass"(类内方法,缩进) +# "def method(...) -> Ret: pass"(模块级函数) +# "class X:"(跟踪当前类名) +# ============================================================ +def _cache_vpi_return_annots_text(vpi_buf: bytes, src_sha1: str) -> int: + """从 vpi_buf 文本提取方法返回注解字符串(stdlib 持久)""" + global _g_vpi_ret_keys, _g_vpi_ret_strs, _g_vpi_ret_count, _g_vpi_ret_cap + if vpi_buf is None or src_sha1 is None: + return 0 + if _g_vpi_ret_keys is None: + _g_vpi_ret_keys = stdlib.malloc(VPI_RET_MAX * VPI_KEY_LEN) + _g_vpi_ret_strs = stdlib.malloc(VPI_RET_MAX * VPI_RET_LEN) + if _g_vpi_ret_keys is None or _g_vpi_ret_strs is None: + return 0 + string.memset(_g_vpi_ret_keys, 0, VPI_RET_MAX * VPI_KEY_LEN) + string.memset(_g_vpi_ret_strs, 0, VPI_RET_MAX * VPI_RET_LEN) + _g_vpi_ret_cap = VPI_RET_MAX + sha1_len: t.CSizeT = string.strlen(src_sha1) + buf_len: t.CSizeT = string.strlen(vpi_buf) + cur_cls: bytes = None + pos: t.CSizeT = 0 + line_no: int = 0 + while pos < buf_len: + ls: t.CSizeT = pos + le: t.CSizeT = pos + while le < buf_len and vpi_buf[le] != '\n': + le += 1 + line_len: t.CSizeT = le - ls + # 跳过前导空格,检查 class/def + i: t.CSizeT = ls + while i < le and vpi_buf[i] == ' ': + i += 1 + if i < le: + # class X: + if line_len >= 6 and string.strncmp(vpi_buf + i, "class ", 6) == 0: + cstart: t.CSizeT = i + 6 + cend: t.CSizeT = cstart + # 类名提取:到 ':' / ' ' / '(' 前停止(继承基类括号不入类名, + # 如 "class MemBuddy(MemManager):" → "MemBuddy",与调用方短名一致) + while cend < le and vpi_buf[cend] != ':' and vpi_buf[cend] != ' ' and vpi_buf[cend] != '(': + cend += 1 + if cend > cstart: + if cur_cls is not None: + stdlib.free(cur_cls) + cur_cls = stdlib.malloc(cend - cstart + 1) + if cur_cls is not None: + string.strncpy(cur_cls, vpi_buf + cstart, cend - cstart) + cur_cls[cend - cstart] = '\0' + # def name(...) -> Ret: + elif line_len >= 4 and string.strncmp(vpi_buf + i, "def ", 4) == 0: + # 模块级函数(行首无缩进):清空类名上下文,避免类结束后残留 + # (如 json 的 null/int_val 等模块级函数被误存为 JsonValue.null) + if i == ls and cur_cls is not None: + stdlib.free(cur_cls) + cur_cls = None + dstart: t.CSizeT = i + 4 + dend: t.CSizeT = dstart + while dend < le and vpi_buf[dend] != '(': + dend += 1 + # 方法名 = [dstart, dend) + # 找 "->" + rpos: t.CSizeT = dstart + arrow_pos: t.CSizeT = le + while rpos < le - 1: + if vpi_buf[rpos] == '-' and vpi_buf[rpos + 1] == '>': + arrow_pos = rpos + break + rpos += 1 + if dend > dstart: + # 返回类型:有 "-> Ret" 提取注解;无注解的非特殊方法默认 "i32" + # (与 HandlesType.infer_return_type 无 return 语句时的默认行为一致, + # 如 json._append_child / __setitem__ 无注解实际编译为 i32)。 + ret_src: str = None + rtype_len: t.CSizeT = 0 + if arrow_pos < le: + # 返回类型 = arrow_pos+2 跳过空格 到 ':' 前 + rstart2: t.CSizeT = arrow_pos + 2 + while rstart2 < le and vpi_buf[rstart2] == ' ': + rstart2 += 1 + rend2: t.CSizeT = rstart2 + while rend2 < le and vpi_buf[rend2] != ':': + rend2 += 1 + if rend2 > rstart2: + rtype_len = rend2 - rstart2 + ret_src = vpi_buf + rstart2 + else: + # 无返回注解:默认 i32(特殊方法除外,见下方过滤) + rtype_len = 3 + ret_src = "i32" + if ret_src is not None: + # 构造 key 和 ret_str,存入缓存 + mname_len: t.CSizeT = dend - dstart + cls_len2: t.CSizeT = 0 + if cur_cls is not None: + cls_len2 = string.strlen(cur_cls) + key_len: t.CSizeT = sha1_len + 1 + cls_len2 + 1 + mname_len + if key_len < VPI_KEY_LEN and rtype_len < VPI_RET_LEN: + # 方法名复制到临时缓冲(vpi_buf+dstart 非 null 结尾,不能直接 snprintf) + mname_buf: bytes = stdlib.malloc(mname_len + 1) + if mname_buf is not None: + string.strncpy(mname_buf, vpi_buf + dstart, mname_len) + mname_buf[mname_len] = '\0' + # 无注解的特殊方法(构造/析构)跳过:它们有专门调用路径 + skip_def: int = 0 + if arrow_pos >= le and ( + string.strcmp(mname_buf, "__init__") == 0 or \ + string.strcmp(mname_buf, "__new__") == 0 or \ + string.strcmp(mname_buf, "__before_init__") == 0 or \ + string.strcmp(mname_buf, "__after_init__") == 0): + skip_def = 1 + if skip_def == 0: + key_buf: bytes = stdlib.malloc(key_len + 1) + if key_buf is not None: + if cur_cls is not None: + viperlib.snprintf(key_buf, key_len + 1, "%s.%s.%s", src_sha1, cur_cls, mname_buf) + else: + viperlib.snprintf(key_buf, key_len + 1, "%s.%s", src_sha1, mname_buf) + # 去重:同一 key 已存在则跳过(同文件可能被多次加载) + dup_key: int = 0 + dki: int + for dki in range(_g_vpi_ret_count): + if string.strcmp(_g_vpi_ret_keys + dki * VPI_KEY_LEN, key_buf) == 0: + dup_key = 1 + break + grow_ok: int = 1 + if dup_key == 0 and _g_vpi_ret_count >= _g_vpi_ret_cap: + grow_ok = _grow_vpi_ret_cache() + if dup_key == 0 and grow_ok != 0: + string.strcpy(_g_vpi_ret_keys + _g_vpi_ret_count * VPI_KEY_LEN, key_buf) + string.strncpy(_g_vpi_ret_strs + _g_vpi_ret_count * VPI_RET_LEN, + ret_src, rtype_len) + (_g_vpi_ret_strs + _g_vpi_ret_count * VPI_RET_LEN)[rtype_len] = '\0' + _g_vpi_ret_count += 1 + stdlib.free(key_buf) + stdlib.free(mname_buf) + pos = le + 1 + line_no += 1 + if cur_cls is not None: + stdlib.free(cur_cls) + return 1 + + +# ============================================================ +# _grow_vpi_ret_cache - 扩容方法返回注解缓存(容量翻倍) +# +# 背景:VPI_RET_MAX 初始 4096,但 includes 模块量大(~90 个 stub、 +# 每个几十个方法),缓存写满后条目被静默丢弃,导致已缓存模块的 +# 方法(如 JsonValue._pool_alloc)查不到而 fail-fast 误报。 +# 用 stdlib.realloc 翻倍扩容(上限 1M 条目,防御异常增长)。 +# ============================================================ +def _grow_vpi_ret_cache() -> int: + """扩容返回注解缓存(容量翻倍),返回 1=成功 / 0=失败""" + global _g_vpi_ret_keys, _g_vpi_ret_strs, _g_vpi_ret_cap + if _g_vpi_ret_keys is None or _g_vpi_ret_cap <= 0: + return 0 + new_cap: int = _g_vpi_ret_cap * 2 + if new_cap > 1048576: + return 0 + new_keys: bytes = stdlib.realloc(_g_vpi_ret_keys, new_cap * VPI_KEY_LEN) + if new_keys is None: + return 0 + new_strs: bytes = stdlib.realloc(_g_vpi_ret_strs, new_cap * VPI_RET_LEN) + if new_strs is None: + return 0 + _g_vpi_ret_keys = new_keys + _g_vpi_ret_strs = new_strs + _g_vpi_ret_cap = new_cap + return 1 + + +# ============================================================ +# _ensure_vpi_ret_annot_loaded - 按需加载模块的 vpi stub 返回注解缓存 +# +# 背景:_cache_vpi_return_annots_text 仅在 stub 注入(LoadDepVpiIntoModule, +# 即"当前模块 import 了该模块")时填充缓存。但模块自身翻译时,自己的 +# stub 尚未被任何依赖方读取,且自己的 text.ll 要翻译完成才落盘,导致 +# "同模块方法调用(定义在后)"(如 json.__setitem__ 调用后定义的 +# _pool_alloc)在 found_func/text.ll/vpi 缓存三类来源上全部未命中。 +# 此函数在缓存未命中时直接读 {temp_dir}/{sha1[0:2]}/{sha1}.vpi +# (Converter 在 deps 阶段已生成全部 stub 文件),填充缓存后即可命中。 +# 幂等:模块已缓存过则跳过,不重复读文件。 +# ============================================================ +def _ensure_vpi_ret_annot_loaded(src_sha1: str, temp_dir: str) -> int: + """按需加载模块 vpi stub 的返回注解缓存,返回 1=已就绪 / 0=失败""" + if src_sha1 is None or temp_dir is None: + return 0 + sha1_len: t.CSizeT = string.strlen(src_sha1) + if sha1_len < 2: + return 0 + # 该模块已有缓存条目 → 跳过(幂等) + if _g_vpi_ret_keys is not None and _g_vpi_ret_count > 0: + pre_i: int + for pre_i in range(_g_vpi_ret_count): + pre_key: bytes = _g_vpi_ret_keys + pre_i * VPI_KEY_LEN + if string.strncmp(pre_key, src_sha1, sha1_len) == 0 and pre_key[sha1_len] == '.': + return 1 + # 构造路径 {temp_dir}/{sha1[0:2]}/{sha1}.vpi(逐字符拼接,避免 %c 格式化问题) + td_len: t.CSizeT = string.strlen(temp_dir) + path_len: t.CSizeT = td_len + sha1_len + 12 + vpi_path: bytes = stdlib.malloc(path_len) + if vpi_path is None: + return 0 + string.strcpy(vpi_path, temp_dir) + vpi_path[td_len] = '/' + vpi_path[td_len + 1] = src_sha1[0] + vpi_path[td_len + 2] = src_sha1[1] + vpi_path[td_len + 3] = '/' + string.strcpy(vpi_path + td_len + 4, src_sha1) + string.strcpy(vpi_path + td_len + 4 + sha1_len, ".vpi") + f: fileio.File | t.CPtr = fileio.File(vpi_path, fileio.MODE.R) + if f.closed: + stdlib.free(vpi_path) + return 0 + vpi_buf: bytes = stdlib.malloc(VPI_READ_BUF_SIZE) + if vpi_buf is None: + f.close() + stdlib.free(vpi_path) + return 0 + bytes_read: LONG = f.read_all(vpi_buf, VPI_READ_BUF_SIZE) + f.close() + if bytes_read > 0: + if bytes_read < VPI_READ_BUF_SIZE: + vpi_buf[bytes_read] = 0 + else: + vpi_buf[VPI_READ_BUF_SIZE - 1] = 0 + _cache_vpi_return_annots_text(vpi_buf, src_sha1) + stdlib.free(vpi_buf) + stdlib.free(vpi_path) + return 1 + + +# ============================================================ +# _subst_template_arg - 替换注解字符串中独立的模板参数 token +# +# 泛型模板返回注解(如 list[T].get -> T)中的类型参数名(T) +# 需替换为实际特化实参(AST|t.CPtr)后才能解析。仅替换前后 +# 非字母数字下划线边界的独立 token(避免误替换 t.CSizeT 等)。 +# 返回 stdlib 新分配字符串(调用者负责 free);失败返回 None。 +# ============================================================ +def _subst_template_arg(annot: str, tparam: str, targ: str) -> str: + """替换 annot 中独立的 tparam token 为 targ""" + if annot is None or tparam is None or targ is None: + return None + alen: t.CSizeT = string.strlen(annot) + tplen: t.CSizeT = string.strlen(tparam) + tglen: t.CSizeT = string.strlen(targ) + if tplen == 0 or tplen > alen: + return annot + # 容量 = alen + tglen*8 + 16 只覆盖 ≤8 次替换;替换次数无上限时 + # opos 会越界写穿 stdlib 堆(哨兵盲区 → CRT 堆损坏后任意 malloc/free + # 静默段错误、崩溃点漂移)。按最坏上界分配:每替换消耗 tplen 写 tglen, + # 最坏全部被替换 → alen + (alen/tplen)*tglen + 1。 + max_sub: t.CSizeT = alen / tplen + if max_sub == 0: + max_sub = 1 + out_size: t.CSizeT = alen + max_sub * tglen + 1 + out: bytes = stdlib.malloc(out_size) + if out is None: + return None + opos: t.CSizeT = 0 + p: t.CSizeT = 0 + while p < alen: + # 防御:opos 超分配即 fail-fast 返回 None(绝不越界写) + if opos >= out_size: + stdlib.free(out) + return None + matched: int = 0 + if annot[p] == tparam[0] and p + tplen <= alen: + if string.strncmp(annot + p, tparam, tplen) == 0: + prev_ch: int = 0 + next_ch: int = 0 + if p > 0: + prev_ch = annot[p - 1] + if p + tplen < alen: + next_ch = annot[p + tplen] + prev_ok: int = 1 + if (prev_ch >= 'a' and prev_ch <= 'z') or (prev_ch >= 'A' and prev_ch <= 'Z') or \ + (prev_ch >= '0' and prev_ch <= '9') or prev_ch == '_': + prev_ok = 0 + next_ok: int = 1 + if (next_ch >= 'a' and next_ch <= 'z') or (next_ch >= 'A' and next_ch <= 'Z') or \ + (next_ch >= '0' and next_ch <= '9') or next_ch == '_': + next_ok = 0 + if prev_ok != 0 and next_ok != 0: + string.strncpy(out + opos, targ, tglen) + opos += tglen + p += tplen + matched = 1 + if matched == 0: + out[opos] = annot[p] + opos += 1 + p += 1 + out[opos] = '\0' + return out + + +# ============================================================ +# _lookup_vpi_ret_annot - 查找缓存的方法返回注解字符串 +# ============================================================ +def _lookup_vpi_ret_annot(src_sha1: str, cls_name: str, method_name: str) -> str: + """查找缓存的方法返回注解字符串,未找到返回 None""" + if _g_vpi_ret_keys is None or _g_vpi_ret_count == 0: + return None + if src_sha1 is None or method_name is None: + return None + sha1_len: t.CSizeT = string.strlen(src_sha1) + cl_len: t.CSizeT = 0 + if cls_name is not None: + cl_len = string.strlen(cls_name) + me_len: t.CSizeT = string.strlen(method_name) + key_len: t.CSizeT = sha1_len + 1 + cl_len + 1 + me_len + key_buf: bytes = stdlib.malloc(key_len + 1) + if key_buf is None: + return None + if cls_name is not None: + viperlib.snprintf(key_buf, key_len + 1, "%s.%s.%s", src_sha1, cls_name, method_name) + else: + viperlib.snprintf(key_buf, key_len + 1, "%s.%s", src_sha1, method_name) + i: int + for i in range(_g_vpi_ret_count): + if string.strcmp(_g_vpi_ret_keys + i * VPI_KEY_LEN, key_buf) == 0: + stdlib.free(key_buf) + return _g_vpi_ret_strs + i * VPI_RET_LEN + # 泛型特化归一化匹配:list[AST|t.CPtr].get → list[T].get 模板缓存。 + # 命中后把模板注解中的类型参数名(如 T)替换为实参(AST|t.CPtr)再返回。 + # 不依赖模板类已注册/特化已发生(base.vp 可能先于 list 模块翻译)。 + if cls_name is not None: + lbkt_v: str = string.strchr(cls_name, '[') + if lbkt_v is not None: + rbkt_v: str = string.strrchr(cls_name, ']') + if rbkt_v is not None and rbkt_v > lbkt_v: + base_len_v: t.CSizeT = t.CSizeT(t.CUInt64T(lbkt_v) - t.CUInt64T(cls_name)) + param_len_v: t.CSizeT = t.CSizeT(t.CUInt64T(rbkt_v) - t.CUInt64T(lbkt_v) - 1) + if base_len_v > 0 and param_len_v > 0: + base_v: str = stdlib.malloc(base_len_v + 1) + param_v: str = stdlib.malloc(param_len_v + 1) + if base_v is not None and param_v is not None: + string.strncpy(base_v, cls_name, base_len_v) + base_v[base_len_v] = '\0' + string.strncpy(param_v, lbkt_v + 1, param_len_v) + param_v[param_len_v] = '\0' + # 遍历缓存找 {sha1}.{base}[xxx].{method} + gi: int + for gi in range(_g_vpi_ret_count): + gk: bytes = _g_vpi_ret_keys + gi * VPI_KEY_LEN + if string.strncmp(gk, src_sha1, sha1_len) == 0 and \ + gk[sha1_len] == '.' and \ + string.strncmp(gk + sha1_len + 1, base_v, base_len_v) == 0 and \ + gk[sha1_len + 1 + base_len_v] == '[': + gklb: str = string.strchr(gk + sha1_len + 1 + base_len_v, ']') + if gklb is not None: + tparam_len_v: t.CSizeT = t.CSizeT( + t.CUInt64T(gklb) - t.CUInt64T(gk + sha1_len + 1 + base_len_v) - 1) + meth_start_v: str = gklb + 2 # 跳过 ']' 和 '.' + if tparam_len_v > 0 and string.strcmp(meth_start_v, method_name) == 0: + tparam_v: str = stdlib.malloc(tparam_len_v + 1) + if tparam_v is not None: + string.strncpy(tparam_v, gk + sha1_len + 1 + base_len_v + 1, tparam_len_v) + tparam_v[tparam_len_v] = '\0' + new_annot_v: str = _subst_template_arg( + _g_vpi_ret_strs + gi * VPI_RET_LEN, tparam_v, param_v) + stdlib.free(tparam_v) + stdlib.free(base_v) + stdlib.free(param_v) + stdlib.free(key_buf) + return new_annot_v + stdlib.free(base_v) + stdlib.free(param_v) + stdlib.free(key_buf) + return None + + +# ============================================================ +# _resolve_single_vpi_type_str - 解析单个类型段(无 CPtr/CVoid)为 LLVMType +# +# 纯字符串解析,不构造 AST 节点。 +# ============================================================ +def _resolve_single_vpi_type_str(pool: memhub.MemBuddy | t.CPtr, + seg: str) -> llvmlite.LLVMType | t.CPtr: + """解析单个类型段为 LLVMType,无法识别返回 None""" + if seg is None or pool is None: + return None + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + # 内置别名 + if string.strcmp(seg, "str") == 0 or string.strcmp(seg, "bytes") == 0: + return i8_ptr_ty + if string.strcmp(seg, "int") == 0: + return llvmlite.Int32(pool) + if string.strcmp(seg, "bool") == 0: + return llvmlite.Int1(pool) + # LLVM 类型串:vpi 缓存对无返回注解方法默认存 "i32" + # (见 _cache_vpi_return_annots_text;push 等无注解方法返回 i32)。 + # 之前缺分支导致解析返回 None → 泛型模板方法(Vector[int].push)调用 + # 走 fail-fast"方法返回类型无法精确获取",实际是约定不一致。 + if string.strcmp(seg, "i32") == 0: + return llvmlite.Int32(pool) + if string.strcmp(seg, "i64") == 0: + return llvmlite.Int64(pool) + if string.strcmp(seg, "i16") == 0: + return llvmlite.Int16(pool) + if string.strcmp(seg, "i8") == 0: + return i8_ty + if string.strcmp(seg, "i1") == 0: + return llvmlite.Int1(pool) + if string.strcmp(seg, "f32") == 0: + return llvmlite.Float(pool) + if string.strcmp(seg, "f64") == 0: + return llvmlite.Double(pool) + if string.strcmp(seg, "void") == 0: + return llvmlite.Void(pool) + # vpi 源文本中 `-> None` 被原样缓存为 "None"(_cache_vpi_return_annots_text + # 提取 arrow_pos 后到 ':' 前的内容)。此前无 "None" 分支 → 解析返回 None → + # `-> None` 的跨模块方法(如 AssignGenMixin._register_cdefine_from_value)vpi + # 缓存命中也解析不出 void → 方法返回类型 fail-fast 误报(追加80e 断点 B)。 + # None 与 void 同义,归一到 Void。 + if string.strcmp(seg, "None") == 0: + return llvmlite.Void(pool) + # t.XXX / c.XXX 内置类型映射 + if string.strncmp(seg, "t.", 2) == 0 or string.strncmp(seg, "c.", 2) == 0: + attr_nm: str = seg + 2 + mapped_ty: llvmlite.LLVMType | t.CPtr = GenApi.map_t_type(pool, attr_nm) + if mapped_ty is not None: + return mapped_ty + return None + # 模块限定类名 "memhub.MemBuddy" → 取最后一段查 struct + last_dot: str = string.strrchr(seg, '.') + if last_dot is not None: + cls_nm2: str = last_dot + 1 + mod_struct_ty: llvmlite.LLVMType | t.CPtr = GenApi.get_struct_type(cls_nm2) + if mod_struct_ty is not None: + return mod_struct_ty + return None + # 裸类名 → 全局 struct 注册表 + bare_struct_ty: llvmlite.LLVMType | t.CPtr = GenApi.get_struct_type(seg) + if bare_struct_ty is not None: + return bare_struct_ty + # 裸 typedef 名(如 VOIDPTR) + mapped_bare: llvmlite.LLVMType | t.CPtr = GenApi.map_t_type(pool, seg) + if mapped_bare is not None: + return mapped_bare + return None + + +# ============================================================ +# _resolve_vpi_ret_annot_str - 直接解析 vpi 返回注解字符串为 LLVMType +# +# 背景:_parse_type_string 跨模块构造 ast.Name/ast.BinOp 在 TPV 中可能 +# 退化为裸函数调用(__init__/vtable 未执行),节点 kind() 异常导致 +# resolve 得到垃圾类型(如 Ptr(i8))。此处纯字符串解析避免该问题。 +# +# 支持: "str"/"bytes" → i8*; "int" → i32; "bool" → i1; +# "t.CChar" 等 → map_t_type 映射; +# "X | t.CPtr" → Ptr(Struct X); "t.CVoid | t.CPtr" → i8*; +# "memhub.MemBuddy | t.CPtr" → Ptr(Struct MemBuddy)。 +# ============================================================ +def _resolve_vpi_ret_annot_str(pool: memhub.MemBuddy | t.CPtr, + ret_annot: str, + i32_ty: llvmlite.LLVMType | t.CPtr, + i8_ptr_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.LLVMType | t.CPtr: + """直接解析 vpi 返回注解字符串为 LLVMType(不构造 AST 节点)""" + if ret_annot is None or pool is None: + return None + + # tuple[T1, T2, ...] → 匿名结构体 {T1, T2, ...}(多返回值打包, + # 与 TypeGenMixin._resolve_generic_subscript_ty 的 tuple 分支一致)。 + # b2a_hqx -> tuple[str, t.CUnsignedShort] 之前按普通段解析失败 → 调用侧 + # 返回类型退化 i8* → tuple 解包失效(hqx 段崩溃根因)。 + if string.strncmp(ret_annot, "tuple[", 6) == 0: + inner_len_t: t.CSizeT = 0 + while ret_annot[6 + inner_len_t] != ']' and ret_annot[6 + inner_len_t] != '\0': + inner_len_t += 1 + if ret_annot[6 + inner_len_t] != ']' or inner_len_t == 0: + return None + tup_head_t: llvmlite.ParamNode | t.CPtr = None + tup_tail_t: llvmlite.ParamNode | t.CPtr = None + tup_count_t: int = 0 + p_t: t.CSizeT = 0 + while p_t < inner_len_t: + # 跳过前导空格/逗号 + while p_t < inner_len_t and (ret_annot[6 + p_t] == ' ' or ret_annot[6 + p_t] == ','): + p_t += 1 + seg_s_t: t.CSizeT = p_t + while p_t < inner_len_t and ret_annot[6 + p_t] != ',': + p_t += 1 + seg_e_t: t.CSizeT = p_t + while seg_e_t > seg_s_t and ret_annot[6 + seg_e_t - 1] == ' ': + seg_e_t -= 1 + if seg_e_t > seg_s_t: + seg_len_t: t.CSizeT = seg_e_t - seg_s_t + seg_buf_t: bytes = stdlib.malloc(seg_len_t + 1) + if seg_buf_t is None: + return None + string.strncpy(seg_buf_t, ret_annot + 6 + seg_s_t, seg_len_t) + seg_buf_t[seg_len_t] = '\0' + seg_ty_t: llvmlite.LLVMType | t.CPtr = _resolve_single_vpi_type_str(pool, seg_buf_t) + stdlib.free(seg_buf_t) + if seg_ty_t is None: + return None + tup_node_t: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, seg_ty_t) + if tup_node_t is None: + return None + if tup_head_t is None: + tup_head_t = tup_node_t + else: + llvmlite.paramnode_set_next(tup_tail_t, tup_node_t) + tup_tail_t = tup_node_t + tup_count_t += 1 + if tup_head_t is None: + return None + return llvmlite.Struct(pool, tup_head_t, tup_count_t, None) + + has_cptr: int = 0 + has_cvoid: int = 0 + first_ty: llvmlite.LLVMType | t.CPtr = None + + buf_len: t.CSizeT = string.strlen(ret_annot) + pos: t.CSizeT = 0 + while pos <= buf_len: + # 跳过前导空格 + while pos < buf_len and ret_annot[pos] == ' ': + pos += 1 + seg_start: t.CSizeT = pos + while pos < buf_len and ret_annot[pos] != '|': + pos += 1 + seg_end: t.CSizeT = pos + # trim 尾随空格 + while seg_end > seg_start and ret_annot[seg_end - 1] == ' ': + seg_end -= 1 + if seg_end > seg_start: + seg_len2: t.CSizeT = seg_end - seg_start + seg_buf: bytes = stdlib.malloc(seg_len2 + 1) + if seg_buf is None: + break + string.strncpy(seg_buf, ret_annot + seg_start, seg_len2) + seg_buf[seg_len2] = '\0' + if string.strcmp(seg_buf, "t.CPtr") == 0 or string.strcmp(seg_buf, "CPtr") == 0: + has_cptr = 1 + elif string.strcmp(seg_buf, "t.CVoid") == 0 or string.strcmp(seg_buf, "CVoid") == 0: + has_cvoid = 1 + else: + seg_ty: llvmlite.LLVMType | t.CPtr = _resolve_single_vpi_type_str(pool, seg_buf) + if seg_ty is not None and first_ty is None: + first_ty = seg_ty + stdlib.free(seg_buf) + pos += 1 # 跳过 '|' + + if has_cptr != 0: + if has_cvoid != 0: + return i8_ptr_ty + if first_ty is not None: + return llvmlite.Ptr(pool, first_ty) + return i8_ptr_ty + if has_cvoid != 0: + # t.CVoid | t.State:State 是装饰器标记(编译侧忽略),t.CVoid → void。 + # 此前缺此分支 → first_ty=None → 返回 None → 跨模块函数返回类型 + # fail-fast(CPythonTest Py_Initialize() -> t.CVoid | t.State 根因)。 + return llvmlite.Void(pool) + if first_ty is not None: + return first_ty + return None + + +# ============================================================ +# VpiReader - .vpi AST 解析器 +# +# 从 .vpi 存根文件读取函数签名和 CTypedef 定义,注入 declare +# 到当前模块。用于跨模块函数调用时补充缺失的函数声明。 +# +# .vpi 文件由 StubGen.Converter._GeneratePyiFromAst 生成, +# 包含函数签名(无函数体)、类定义、变量声明、import 语句。 +# VpiReader 解析 .vpi 为 AST,提取 FunctionDef 和 CTypedef +# AnnAssign,在当前模块创建对应的 declare 声明。 +# ============================================================ + +# .vpi 读取缓冲区大小(256KB,与 PYI_BUF_SIZE 一致) +VPI_READ_BUF_SIZE: t.CSizeT = 262144 + +# SHA1 字符串长度(16 hex 字符) +SHA1_LEN: t.CSizeT = 16 + + +# ============================================================ +# _extract_sha1_from_path - 从 .vpi 文件路径提取 SHA1 +# +# .vpi 文件名格式为 {sha1}.vpi,sha1 是 16 位十六进制字符。 +# 从路径中找到最后一个路径分隔符(/ 或 \),取后续文件名的前 +# 16 个字符作为 SHA1。分配新缓冲区存储 SHA1(调用者负责 free)。 +# +# Args: +# vpi_path: .vpi 文件路径 +# +# Returns: +# SHA1 字符串(stdlib.malloc 分配,需 stdlib.free),None 失败 +# ============================================================ +def _extract_sha1_from_path(vpi_path: str) -> str: + """从 .vpi 文件路径提取 SHA1(文件名前16字符,malloc 分配)""" + if vpi_path is None: + return None + # 查找最后一个路径分隔符 / 或 \ + total_len: t.CSizeT = string.strlen(vpi_path) + if total_len < SHA1_LEN + 4: # 至少需要 "xxxx.vpi" 的长度 + return None + # 从后向前查找最后一个 / 或 \ + sep_pos: t.CSizeT = total_len + while sep_pos > 0: + sep_pos -= 1 + ch: t.CChar = vpi_path[sep_pos] + if ch == '/' or ch == '\\': + sep_pos += 1 + break + if sep_pos + SHA1_LEN > total_len: + return None + # 分配缓冲区并复制 SHA1(16 字符 + null 终止符) + sha1_buf: str = stdlib.malloc(SHA1_LEN + 1) + if sha1_buf is None: + return None + string.strncpy(sha1_buf, vpi_path + sep_pos, SHA1_LEN) + sha1_buf[SHA1_LEN] = '\0' + return sha1_buf + + +# ============================================================ +# _stub_add_imported - 追加模块名到空格分隔列表(stub 上下文收集用) +# +# 与 HandlesImports.add_imported_module 逻辑一致,但内联在本模块, +# 避免 VpiReader → HandlesImports → StubMerger → VpiReader 循环依赖。 +# ============================================================ +def _stub_add_imported(pool: memhub.MemBuddy | t.CPtr, + cur: str, name: str) -> str: + """追加模块名到空格分隔列表(pool 分配),返回新列表""" + if name is None: + return cur + if cur is None: + nlen: t.CSizeT = string.strlen(name) + buf: str = pool.alloc(nlen + 1) + if buf is not None: + string.strcpy(buf, name) + return buf + old_len: t.CSizeT = string.strlen(cur) + name_len: t.CSizeT = string.strlen(name) + buf2: str = pool.alloc(old_len + 1 + name_len + 1) + if buf2 is not None: + string.strcpy(buf2, cur) + buf2[old_len] = ' ' + string.strcpy(buf2 + old_len + 1, name) + return buf2 + + +# ============================================================ +# _stub_add_from - 追加 from-import 映射("local:mod[:orig]" 空格分隔) +# ============================================================ +def _stub_add_from(pool: memhub.MemBuddy | t.CPtr, + cur: str, local: str, mod: str, orig: str) -> str: + """追加 from-import 映射(pool 分配),返回新列表""" + if local is None or mod is None: + return cur + entry: str = pool.alloc(256) + if entry is None: + return cur + if orig is not None and string.strcmp(orig, local) != 0: + viperlib.snprintf(entry, 256, "%s:%s:%s", local, mod, orig) + else: + viperlib.snprintf(entry, 256, "%s:%s", local, mod) + if cur is None: + return entry + old_len: t.CSizeT = string.strlen(cur) + entry_len: t.CSizeT = string.strlen(entry) + buf: str = pool.alloc(old_len + 1 + entry_len + 1) + if buf is not None: + string.strcpy(buf, cur) + buf[old_len] = ' ' + string.strcpy(buf + old_len + 1, entry) + return buf + + +# ============================================================ +# ParseVpiIntoModule - 解析 .vpi 文件,将函数声明注入到当前模块 +# +# 读取 .vpi 文件 → AST 解析 → 遍历顶层节点 → 创建 declare 声明。 +# 对每个 FunctionDef: +# 1. 提取函数名、参数、返回类型 +# 2. 检测 CExport/CExtern/State 标记(决定是否用裸名) +# 3. 用 find_func_in_module 去重(已存在则跳过) +# 4. 用 create_declare + add_param 创建 declare 声明 +# 5. 注册到函数表(用裸名,非 mangled_name) +# 对 AnnAssign with t.CTypedef:调用 register_ctypedef 注册 +# ClassDef/Import/ImportFrom:跳过 +# +# Args: +# pool: 内存池 +# mod: 当前 LLVM 模块 +# vpi_path: .vpi 文件路径 +# trans: 翻译器对象 +# +# Returns: +# 1=成功,0=失败 +# ============================================================ +def ParseVpiIntoModule(pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + vpi_path: str, + trans: HT.Translator | t.CPtr) -> int: + """解析 .vpi 文件,将函数声明注入到当前模块 + + 解析 stub 期间临时将错误归因切换到被读 stub 文件(.vpi): + 注解解析失败时 fatal_error 应指向 stub 及其行号(真实出错位置), + 而非当前编译模块(错误归因修复)。 + """ + if pool is None or mod is None or vpi_path is None or trans is None: + return 0 + saved_cur: str = GenApi.get_current_file() + GenApi.set_current_file_type(vpi_path) + ret: int = _ParseVpiIntoModuleImpl(pool, mod, vpi_path, trans) + GenApi.set_current_file_type(saved_cur) + return ret + + +def _ParseVpiIntoModuleImpl(pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + vpi_path: str, + trans: HT.Translator | t.CPtr) -> int: + """解析 .vpi 文件,将函数声明注入到当前模块(ParseVpiIntoModule 实际实现)""" + if pool is None or mod is None or vpi_path is None or trans is None: + return 0 + + # 1. 读取 .vpi 文件 + f: fileio.File | t.CPtr = fileio.File(vpi_path, fileio.MODE.R) + if f.closed: + return 0 + vpi_buf: bytes = stdlib.malloc(VPI_READ_BUF_SIZE) + if vpi_buf is None: + f.close() + return 0 + bytes_read: LONG = f.read_all(vpi_buf, VPI_READ_BUF_SIZE) + f.close() + if bytes_read <= 0: + stdlib.free(vpi_buf) + return 0 + if bytes_read < VPI_READ_BUF_SIZE: + vpi_buf[bytes_read] = 0 + else: + vpi_buf[VPI_READ_BUF_SIZE - 1] = 0 + + # 2. 解析为 AST + lx: ast.Lexer | t.CPtr = ast.new_lexer(pool) + if lx is None: + stdlib.free(vpi_buf) + return 0 + ast._lexer_init(lx, vpi_buf, pool) + tokens: ast.Token | t.CPtr = ast.tokenize(lx) + tree: ast.AST | t.CPtr = ast.parse_tokens(pool, tokens) + # vpi_buf 延迟释放:AST 字符串字段可能引用 vpi_buf 内部(token 零拷贝), + # 提前 free 会导致 Name.id/Attribute.attr 等悬空 → 后续解析返回错误类型。 + # 在 ParseVpiIntoModule 末尾统一释放。 + if tree is None: + stdlib.free(vpi_buf) + return 0 + + # 提取源模块 SHA1(用于函数名混淆,在 AST 解析成功后提取避免提前返回时泄漏) + src_sha1: str = _extract_sha1_from_path(vpi_path) + + # 从 vpi_buf 文本直接提取方法返回注解字符串缓存到 stdlib + # (不依赖 AST tree:tree 深层节点在后续遍历处理时可能被覆盖损坏, + # 但 vpi_buf 原始文本在 ParseVpiIntoModule 末尾才释放,始终有效) + _cache_vpi_return_annots_text(vpi_buf, src_sha1) + + # 3. 遍历 AST 顶层节点 + ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children + if ch is None: + if src_sha1 is not None: + stdlib.free(src_sha1) + return 1 + n: t.CSizeT = ch.__len__() + + # 收集 stub 内被读模块自己的 import 语句,构建独立的注解解析上下文。 + # .vpi stub 顶部含被读模块的 import(Converter 已写入,如 string.vp 的 + # "import t, c"),用它替代当前模块的 imported_modules/from_imports 去 + # 解析注解——根治跨上下文误报(如 t.CArray[str] 需要 't' 已导入)。 + stub_imported_modules: str = None + stub_from_imports: str = None + si: t.CSizeT + for si in range(n): + schild: ast.AST | t.CPtr = ch.get(si) + if schild is None: + continue + sk: int = schild.kind() + if sk == ast.ASTKind.Import: + simp: ast.Import | t.CPtr = (ast.Import | t.CPtr)(schild) + if simp.names is not None: + sn_n: t.CSizeT = simp.names.__len__() + sni: t.CSizeT + for sni in range(sn_n): + sal: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(simp.names.get(sni)) + if sal is not None and sal.name is not None: + stub_imported_modules = _stub_add_imported( + pool, stub_imported_modules, sal.name) + if sal.asname is not None: + stub_imported_modules = _stub_add_imported( + pool, stub_imported_modules, sal.asname) + elif sk == ast.ASTKind.ImportFrom: + sifr: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(schild) + sifr_mod: str = sifr.module + if sifr_mod is not None: + stub_imported_modules = _stub_add_imported( + pool, stub_imported_modules, sifr_mod) + if sifr.names is not None: + sifr_nn: t.CSizeT = sifr.names.__len__() + sifri: t.CSizeT + for sifri in range(sifr_nn): + sial: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(sifr.names.get(sifri)) + if sial is not None and sial.name is not None: + # '*' star import 不建 from 映射(lookup 有 star 回退) + if string.strcmp(sial.name, "*") != 0: + slocal: str = sial.name + sorig: str = None + if sial.asname is not None: + slocal = sial.asname + sorig = sial.name + stub_from_imports = _stub_add_from( + pool, stub_from_imports, slocal, sifr_mod, sorig) + + # 用 stub 自己的 imports 替代当前模块的(stub 注解解析上下文正确性) + imported_modules: str = trans._imported_modules + from_imports: str = trans._from_imports + if stub_imported_modules is not None: + imported_modules = stub_imported_modules + if stub_from_imports is not None: + from_imports = stub_from_imports + # 把源模块自己加入 stub 注解上下文:stub 注解(如 __sha512 的 transform + # 参数 t.CArray[t.CUInt8T, SHA512_BLOCK_LEN])引用源模块自身的 CDefine, + # 但 stub 的 import 只含被 import 的模块(t/c/string),不含自己。 + # 不加则 _eval_const_int_expr 跨模块 CDefine 查找遍历不到源模块 + # (imported_modules 无 __sha512)→ t.CArray count 报"必须是整数常量"。 + # 示例:RelPath "hashlib/__sha512.vp" → 模块名 "hashlib.__sha512"。 + if src_sha1 is not None: + import lib.core.StubMerger as StubMerger + stub_rel_src: str = StubMergerStore.LookupSha1RelPath(src_sha1) + if stub_rel_src is not None: + sr_len_src: t.CSizeT = string.strlen(stub_rel_src) + if sr_len_src > 3 and string.strncmp(stub_rel_src + sr_len_src - 3, ".vp", 3) == 0: + sr_len_src -= 3 + elif sr_len_src > 3 and string.strncmp(stub_rel_src + sr_len_src - 3, ".py", 3) == 0: + sr_len_src -= 3 + if sr_len_src > 0: + src_mod_buf: str = stdlib.malloc(sr_len_src + 1) + if src_mod_buf is not None: + sri_src: t.CSizeT + for sri_src in range(sr_len_src): + ch_src: t.CChar = stub_rel_src[sri_src] + if ch_src == '/' or ch_src == '\\': + src_mod_buf[sri_src] = '.' + else: + src_mod_buf[sri_src] = ch_src + src_mod_buf[sr_len_src] = '\0' + imported_modules = _stub_add_imported(pool, imported_modules, src_mod_buf) + stdlib.free(src_mod_buf) + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + # 函数表信息 + funcs_ptr: GenTypes.FuncEntry | t.CPtr = trans._funcs + max_funcs: int = 1024 + + i: t.CSizeT + for i in range(n): + child: ast.AST | t.CPtr = ch.get(i) + if child is None: + continue + kd: int = child.kind() + + # FunctionDef → 提取函数名、参数、返回类型 → 注入 declare + if kd == ast.ASTKind.FunctionDef: + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child) + if fd is None or fd.name is None: + continue + _inject_function_declare(pool, mod, fd, trans, src_sha1, + imported_modules, from_imports, + i32_ty, i8_ptr_ty, + funcs_ptr, max_funcs) + continue + + # AnnAssign with t.CTypedef → 注册 CTypedef; + # 普通模块级全局变量(如 tokens._op_head)→ external global declare + if kd == ast.ASTKind.AnnAssign: + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(child) + if aa is None: + continue + if GenApi._is_ctypedef_annotation(aa.annotation) != 0: + _register_ctypedef_from_annassign(pool, aa) + else: + _inject_global_variable_declare(pool, mod, aa, trans, + stub_imported_modules, stub_from_imports, + i32_ty, i8_ptr_ty, src_sha1) + continue + + # ClassDef → 递归注入类内方法(如 MemBuddy.__init__/alloc) + # 方法 declare 使用 {sha1}.{ClassName}.{method} 混淆名, + # 参数类型从 vpi 注解解析(避免调用时 _ensure_method_declare 用实参类型 + # 创建错误 declare,如 size: t.CSizeT 被写成 i32 而非 i64) + if kd == ast.ASTKind.ClassDef: + class_cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child) + if class_cd is None or class_cd.name is None: + continue + cls_name_v: str = class_cd.name + # 泛型类(class X[T])跳过方法 declare 注入:stub 模板签名含类级 + # 类型参数 T(如 ndarray[T].__add__ 的返回 ndarray[T] | t.CPtr), + # 注入时 T 无法确定具体类型,直接解析会触发 + # _specialize_generic_class("ndarray", ["T"]) 错误特化 + # (Phase2 翻译 App 文件注入 numpy stub 时崩溃)。 + # 具体特化的方法 define 已在 Phase1 生成,跨模块调用按特化类名 + # (ndarray[t.CDouble].__add__)查找命中,无需 stub 模板 declare。 + tp_stub: list[str] | t.CPtr = class_cd.type_params + if tp_stub is not None and tp_stub.__len__() > 0: + continue + cls_children: list[ast.AST | t.CPtr] | t.CPtr = class_cd.children + if cls_children is not None: + cn2: t.CSizeT = cls_children.__len__() + for ci2 in range(cn2): + m_child: ast.AST | t.CPtr = cls_children.get(ci2) + if m_child is None: + continue + if m_child.kind() != ast.ASTKind.FunctionDef: + continue + m_fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(m_child) + if m_fd is None or m_fd.name is None: + continue + _inject_method_declare(pool, mod, m_fd, cls_name_v, trans, + src_sha1, imported_modules, from_imports, + i32_ty, i8_ptr_ty, funcs_ptr, max_funcs) + continue + + # Import/ImportFrom → 跳过 + # (import 不需要处理) + + # 释放 SHA1 缓冲区(_extract_sha1_from_path 用 stdlib.malloc 分配) + if src_sha1 is not None: + stdlib.free(src_sha1) + # vpi_buf 延迟到全部 tree 处理完成后释放(见解析处注释) + stdlib.free(vpi_buf) + return 1 + + +# ============================================================ +# _inject_global_variable_declare - 从 vpi AnnAssign 创建模块级全局变量 declare +# +# 背景:vpi 里模块级全局变量(如 tokens.vp 的 _op_head: OpEntry | t.CPtr = None) +# 需在当前模块创建 external global 声明(短名 @name,COFF 按名链接),否则 +# 跨模块 from-import 读取全局变量时 find_global_in_module 找不到 → +# "跨模块全局变量类型未知(stub 未注入)" 误杀(lexer.vp 读 tokens._op_head)。 +# ============================================================ +def _inject_global_variable_declare(pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + aa: ast.AnnAssign | t.CPtr, + trans: HT.Translator | t.CPtr, + imported_modules: str, + from_imports: str, + i32_ty: llvmlite.LLVMType | t.CPtr, + i8_ptr_ty: llvmlite.LLVMType | t.CPtr, + src_sha1: str) -> None: + """从 vpi AnnAssign 创建模块级全局变量 external declare(mangled 名 @.)""" + if pool is None or mod is None or aa is None or trans is None: + return + tgt_v: ast.AST | t.CPtr = aa.target + if tgt_v is None or tgt_v.kind() != ast.ASTKind.Name: + return + nm_v: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tgt_v) + if nm_v is None or nm_v.id is None: + return + gname_v: str = nm_v.id + if gname_v[0] == '\0': + return + # mangled 名:带源模块 SHA1 前缀(对齐定义端 5f7a873 的 @. + # 与查找端 from-import 精确查找三方一致;裸短名会退化为未定义)。 + # 注:a42923c 曾把此处写成未定义变量 gv_name_m(笔误,mangle 未实现), + # 导致注入空名 @ = external global → llc "expected top-level entity"。 + gv_name_m: str = gname_v + if src_sha1 is not None and src_sha1[0] != '\0': + ml_v: t.CSizeT = string.strlen(src_sha1) + 1 + string.strlen(gname_v) + 1 + gv_name_m = pool.alloc(ml_v) + if gv_name_m is not None: + viperlib.snprintf(gv_name_m, ml_v, "%s.%s", src_sha1, gname_v) + # 去重:遍历模块全局变量链表(mangled 名匹配) + cur_v: llvmlite.GlobalVariable | t.CPtr = mod.GlobalHead + while cur_v is not None: + if cur_v.Name is not None and string.strcmp(cur_v.Name, gv_name_m) == 0: + return + cur_v = cur_v.Next + # 解析注解类型(裸类 → Ptr(struct),CArray → 元素指针) + resolved_v: llvmlite.LLVMType | t.CPtr = None + if aa.annotation is not None: + resolved_v = GenApi.resolve_annotation_type( + pool, aa.annotation, imported_modules, from_imports, trans) + if resolved_v is None: + return # 类型解析失败跳过:调用侧有 fail-fast 定位 + gv_ty_v: llvmlite.LLVMType | t.CPtr = resolved_v + match resolved_v: + case llvmlite.LLVMType.Struct(_, _, _): + gv_ty_v = llvmlite.Ptr(pool, resolved_v) + case llvmlite.LLVMType.Array(aelem_v, acount_v): + # 定长数组(CArray[T, N]):保留完整数组类型 [N x T],与定义端 + # handle_module_level_var 生成的 global [N x T] 一致——此前一律 + # 衰减为元素指针 i32*,链接后引用端 load 把数组前 8 字节当指针 + # 读 → 垃圾地址 → zdeflate_len_to_symbol 读 NULL/垃圾崩溃 + # (zdeflate_len_base 跨模块数组根因)。 + if acount_v > 0: + gv_ty_v = resolved_v + else: + # 不定长数组(CArray[T, None]):元素指针(C 数组衰减) + gv_ty_v = llvmlite.Ptr(pool, aelem_v) + case _: + gv_ty_v = resolved_v + gv_v: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, gv_name_m, gv_ty_v) + if gv_v is None: + return + llvmlite.module_add_global(mod, gv_v) + gv_v.Linkage = "external" + + +# ============================================================ +# _inject_function_declare - 为单个 FunctionDef 创建 declare 声明 +# +# 检测 CExport/CExtern/State 标记,计算 mangled name, +# 用 find_func_in_module 去重,创建 declare 并添加参数, +# 注册到函数表。 +# ============================================================ +def _inject_function_declare(pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + fd: ast.FunctionDef | t.CPtr, + trans: HT.Translator | t.CPtr, + src_sha1: str, + imported_modules: str, + from_imports: str, + i32_ty: llvmlite.LLVMType | t.CPtr, + i8_ptr_ty: llvmlite.LLVMType | t.CPtr, + funcs_ptr: GenTypes.FuncEntry | t.CPtr, + max_funcs: int) -> None: + """为 FunctionDef 创建 declare 声明并注入到模块""" + if fd.name is None: + return + + # 检测 CExtern/State/CExport 标记(从返回类型注解) + has_extern: int = 0 + has_state: int = 0 + has_export: int = 0 + if fd.returns is not None: + has_extern = GenApi.has_decorator_marker(fd.returns, "CExtern") + has_state = GenApi.has_decorator_marker(fd.returns, "State") + has_export = GenApi.has_decorator_marker(fd.returns, "CExport") + + # 计算 mangled name + # CExport/CExtern/State/main 函数用裸名,其他函数用源模块 SHA1 前缀 + use_bare_name: int = 0 + if has_extern != 0 or has_state != 0 or has_export != 0 or string.strcmp(fd.name, "main") == 0: + mangled_name: str = fd.name + use_bare_name = 1 + else: + mangled_name = GenApi._mangle_name_with_sha1(src_sha1, fd.name) + + # 去重:如果函数已存在则跳过 + existing: llvmlite.Function | t.CPtr = GenApi.find_func_in_module(mod, mangled_name) + if existing is not None: + return + # 也检查裸名(非裸名模式时,CExport 函数可能已通过其他途径注册) + if use_bare_name == 0: + existing_bare: llvmlite.Function | t.CPtr = GenApi.find_func_in_module(mod, fd.name) + if existing_bare is not None: + return + + # 推断返回类型 + # 优先用缓存的返回注解字符串(tree 解析后立即提取,节点未损坏) + # 直接字符串解析(绕开 _parse_type_string 跨模块 AST 构造在 TPV 中的 + # __init__/vtable 未执行问题,节点 kind() 异常导致 resolve 得垃圾类型) + ret_ty: llvmlite.LLVMType | t.CPtr = None + ret_annot_fd: str = _lookup_vpi_ret_annot(src_sha1, None, fd.name) + if ret_annot_fd is not None: + ret_ty = _resolve_vpi_ret_annot_str(pool, ret_annot_fd, i32_ty, i8_ptr_ty) + if ret_ty is None and fd.returns is not None: + ret_ty = GenApi.resolve_annotation_type( + pool, fd.returns, imported_modules, from_imports, trans) + # 如果返回类型是纯 t.State(无实际类型),用 Void + if ret_ty is None and fd.returns is not None: + if has_state != 0: + ret_ty = llvmlite.Void(pool) + # 默认返回 i32 + if ret_ty is None: + ret_ty = i32_ty + + # 创建 declare + func: llvmlite.Function | t.CPtr = llvmlite.create_declare( + pool, mod, mangled_name, ret_ty) + if func is None: + return + + # 提取参数并添加到 declare + param_count: int = 0 + if fd.args is not None: + args_node: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args) + if args_node.args is not None: + args_list: list[ast.AST | t.CPtr] | t.CPtr = args_node.args + param_count = args_list.__len__() + # 参数数上限哨兵(fail-fast):vpi tree 深层节点在遍历处理过程中 + # 可能被覆盖损坏(见本文件顶部注释),fd.args 悬空时 __len__() + # 返回垃圾大数 → for 循环 add_param 海量次 → Params 链超长, + # dump 时步数哨兵误报"链表成环"。超限立即报错定位。 + if param_count < 0 or param_count > 128: + stdio.printf( + "[VPIS] 参数数异常: 函数名=%s param_count=%d(fd.args=%llu,tree 可能被覆盖,终止)\n", + fd.name, param_count, t.CUInt64T(fd.args)) + stdlib.exit(1) + pi: t.CSizeT + for pi in range(param_count): + ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(args_list.get(pi)) + if ag is None: + continue + pname: str = ag.arg + if pname is None: + pname = "arg" + # 解析参数类型 + param_ty: llvmlite.LLVMType | t.CPtr = i8_ptr_ty + if ag.annotation is not None: + resolved_ty: llvmlite.LLVMType | t.CPtr = GenApi.resolve_annotation_type( + pool, ag.annotation, imported_modules, from_imports, trans) + if resolved_ty is not None: + # 结构体按值参数 → i64:跨模块结构体在本模块是 opaque + # (未定义字段),LLVM 不允许 opaque struct 作为函数参数 + # (llc: invalid type for function argument)。Windows ABI + # 小结构体(≤8 字节,如 COORD)按整数寄存器传,映射 i64 兼容。 + # CArray 参数 → 元素指针 ty*(C 数组衰减,与编译侧一致)。 + match resolved_ty: + case llvmlite.LLVMType.Struct(_, _, _): + param_ty = llvmlite.Int64(pool) + case llvmlite.LLVMType.Array(aelem_ty, _): + param_ty = llvmlite.Ptr(pool, aelem_ty) + case _: + param_ty = resolved_ty + llvmlite.add_param(pool, func, param_ty, pname) + # *args 变长参数:标记 IsVarArg=1,使调用侧走 C ABI 参数提升 + # (i8/i16 → i32,float → double),避免 %d/%x 等格式因参数按 i64 + # 传递而读错(第二个 %x 读到第一个 i64 槽的高 4 字节)。 + if args_node.vararg is not None: + func.IsVarArg = 1 + + # 注册到函数表(用裸名 fd.name,不是 mangled_name) + if funcs_ptr is not None: + cur_count: int = trans._func_count + if GenApi.add_func_to_table(funcs_ptr, cur_count, fd.name, func, max_funcs, + None, 0, param_count) == 0: + trans._func_count = cur_count + 1 + + +# ============================================================ +# _inject_method_declare - 为 ClassDef 内的方法创建 declare +# +# 方法混淆名: {src_sha1}.{ClassName}.{method} +# 参数类型从 vpi 注解解析(self 无注解时默认为 i8*)。 +# 注入正确签名避免调用时 _ensure_method_declare 用实参类型 +# 创建错误 declare(如 size: t.CSizeT 被写成 i32 而非 i64)。 +# ============================================================ +def _inject_method_declare(pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + m_fd: ast.FunctionDef | t.CPtr, + cls_name: str, + trans: HT.Translator | t.CPtr, + src_sha1: str, + imported_modules: str, + from_imports: str, + i32_ty: llvmlite.LLVMType | t.CPtr, + i8_ptr_ty: llvmlite.LLVMType | t.CPtr, + funcs_ptr: GenTypes.FuncEntry | t.CPtr, + max_funcs: int) -> None: + """为 ClassDef 内方法创建 declare 声明并注入到模块""" + if m_fd is None or m_fd.name is None or cls_name is None: + return + if src_sha1 is None: + return + + # 构造方法查找名: ClassName.method + lookup_name_len: t.CSizeT = string.strlen(cls_name) + 1 + string.strlen(m_fd.name) + 1 + lookup_name: str = pool.alloc(lookup_name_len) + if lookup_name is None: + return + viperlib.snprintf(lookup_name, lookup_name_len, "%s.%s", cls_name, m_fd.name) + + # mangled name: {src_sha1}.{ClassName}.{method} + mangled_len: t.CSizeT = string.strlen(src_sha1) + 1 + lookup_name_len + mangled_name: str = pool.alloc(mangled_len) + if mangled_name is None: + return + viperlib.snprintf(mangled_name, mangled_len, "%s.%s", src_sha1, lookup_name) + + # 去重:如果方法已存在则跳过 + existing: llvmlite.Function | t.CPtr = GenApi.find_func_in_module(mod, mangled_name) + if existing is not None: + return + + # 推断返回类型 + # 优先用缓存的返回注解字符串(tree 解析后立即提取,节点未损坏), + # 用 _parse_type_string 重新解析成新 AST(立即使用不被覆盖)。 + # 直接解析 m_fd.returns 可能因 vpi tree 深层节点被覆盖而得到垃圾类型。 + ret_ty: llvmlite.LLVMType | t.CPtr = None + ret_annot: str = _lookup_vpi_ret_annot(src_sha1, cls_name, m_fd.name) + if ret_annot is not None: + ret_ty = _resolve_vpi_ret_annot_str(pool, ret_annot, i32_ty, i8_ptr_ty) + if ret_ty is None and m_fd.returns is not None: + ret_ty = GenApi.resolve_annotation_type( + pool, m_fd.returns, imported_modules, from_imports, trans) + # __new__ 无返回注解时推断为类指针(__new__ 返回 self 指针,默认 i32 会截断指针) + if ret_ty is None and string.strcmp(m_fd.name, "__new__") == 0: + cls_ty: llvmlite.LLVMType | t.CPtr = GenApi.get_struct_type(cls_name) + if cls_ty is not None: + ret_ty = llvmlite.Ptr(pool, cls_ty) + if ret_ty is None: + ret_ty = i32_ty + + # 创建 declare + func: llvmlite.Function | t.CPtr = llvmlite.create_declare( + pool, mod, mangled_name, ret_ty) + if func is None: + return + + # 提取参数并添加到 declare + param_count: int = 0 + if m_fd.args is not None: + args_node: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(m_fd.args) + if args_node.args is not None: + args_list: list[ast.AST | t.CPtr] | t.CPtr = args_node.args + param_count = args_list.__len__() + # 参数数上限哨兵(fail-fast):与 _inject_function_declare 同因 + # (vpi tree 深层节点被覆盖损坏时 __len__() 返回垃圾大数)。 + if param_count < 0 or param_count > 128: + stdio.printf( + "[VPIS] 参数数异常: 方法名=%s.%s param_count=%d(m_fd.args=%llu,tree 可能被覆盖,终止)\n", + cls_name, m_fd.name, param_count, t.CUInt64T(m_fd.args)) + stdlib.exit(1) + pi: t.CSizeT + for pi in range(param_count): + ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(args_list.get(pi)) + if ag is None: + continue + pname: str = ag.arg + if pname is None: + pname = "arg" + # 解析参数类型 + param_ty: llvmlite.LLVMType | t.CPtr = i8_ptr_ty + if ag.annotation is not None: + resolved_ty: llvmlite.LLVMType | t.CPtr = GenApi.resolve_annotation_type( + pool, ag.annotation, imported_modules, from_imports, trans) + if resolved_ty is not None: + # 结构体按值参数 → i64:跨模块结构体在本模块是 opaque + # (未定义字段),LLVM 不允许 opaque struct 作为函数参数 + # (llc: invalid type for function argument)。Windows ABI + # 小结构体(≤8 字节,如 COORD)按整数寄存器传,映射 i64 兼容。 + # CArray 参数 → 元素指针 ty*(C 数组衰减,与编译侧一致)。 + match resolved_ty: + case llvmlite.LLVMType.Struct(_, _, _): + param_ty = llvmlite.Int64(pool) + case llvmlite.LLVMType.Array(aelem_ty, _): + param_ty = llvmlite.Ptr(pool, aelem_ty) + case _: + param_ty = resolved_ty + llvmlite.add_param(pool, func, param_ty, pname) + + # OOP iter 协议:__next__ 方法 stub 声明带隐藏 __stop_iter_flag__(i1*), + # 与 _translate_method 的 define 签名一致(对齐 TPC HandlesFunctions.py + # L703-705)。for x in obj 循环会以 2 个实参调用 __next__(self, flag)。 + if m_fd.name is not None and string.strcmp(m_fd.name, "__next__") == 0: + i1_ty_si: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + if i1_ty_si is not None: + i1_ptr_ty_si: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_si) + if i1_ptr_ty_si is not None: + llvmlite.add_param(pool, func, i1_ptr_ty_si, "__stop_iter_flag__") + + # 注册到函数表(用裸名 ClassName.method,与调用方 lookup_name 一致) + # ParamCount 不含 self(方法首参 self/cls 不计入,与 _translate_method 的 + # md_param_count = args.__len__() - 1 保持一致)——默认参数填充按非 self + # 参数计数,若含 self 会导致 mdf_param_count 虚高、填充逻辑错位/越界。 + if funcs_ptr is not None: + cur_count: int = trans._func_count + param_count_no_self: int = param_count + if param_count_no_self > 0: + param_count_no_self -= 1 + if GenApi.add_func_to_table(funcs_ptr, cur_count, lookup_name, func, max_funcs, + None, 0, param_count_no_self) == 0: + trans._func_count = cur_count + 1 + + +# ============================================================ +# _register_ctypedef_from_annassign - 从 AnnAssign 节点注册 CTypedef +# +# 提取 NAME: t.CTypedef = Type 中的名称和类型表达式字符串, +# 调用 register_ctypedef 注册到动态 CTypedef 表。 +# ============================================================ +def _register_ctypedef_from_annassign(pool: memhub.MemBuddy | t.CPtr, + aa: ast.AnnAssign | t.CPtr) -> None: + """从 AnnAssign 节点提取并注册 CTypedef""" + if aa is None or pool is None: + return + # 提取目标名称(必须是 Name 节点) + if aa.target is None or aa.target.kind() != ast.ASTKind.Name: + return + tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) + if tgt.id is None: + return + # 提取类型表达式字符串(从 value AST 节点) + if aa.value is None: + return + type_str: str = GenApi._get_type_name_from_annotation(pool, aa.value) + if type_str is None: + return + # 注册 CTypedef + GenApi.register_ctypedef(pool, tgt.id, type_str) diff --git a/App/lib/core/BuildPipeline.vp b/App/lib/core/BuildPipeline.vp index 522f874..e76b20c 100644 --- a/App/lib/core/BuildPipeline.vp +++ b/App/lib/core/BuildPipeline.vp @@ -1,978 +1,940 @@ -import t, c -from stdint import * -import stdio -import string -import stdlib -import memhub -import viperlib -import vthreading -import w32.fileio as fileio -import w32.win32file -import w32.win32base -import w32.win32process as win32process -import w32.win32sync as win32sync -import subprocess -import viperlib -import ast -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HandlesTranslator -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesType as HandlesType -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.HandlesFunctions as HandlesFunctions -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesBody as HandlesBody -import lib.core.Handles.HandlesIf as HandlesIf -import lib.core.Handles.HandlesWhile as HandlesWhile -import lib.core.Handles.HandlesFor as HandlesFor -import lib.core.Handles.HandlesReturn as HandlesReturn -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesMatch as HandlesMatch -import lib.core.Handles.HandlesEnum as HandlesEnum -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.Handles.HandlesAugAssign as HandlesAugAssign -import lib.core.Handles.HandlesAssign as HandlesAssign -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesMain as HandlesMain -import lib.core.StubMerger as StubMerger -import lib.StubGen.Converter as StubConverter -import lib.Projectrans.Config as Config -import lib.core.Gen.Generator as GenGenerator -import lib.core.StubMergerCollect as StubMergerCollect - -# ============================================================ -# BuildPipeline - 编译管线 -# -# 负责将 LLVM IR 编译为可执行文件: -# 1. 写 .ll 文件到 temp 目录 -# 2. 调用 llc 编译 .ll → .obj -# 3. 调用 clang++ 链接 .obj → .exe -# ============================================================ - -# 全局 mbuddy 指针 -_mbuddy: memhub.MemBuddy | t.CPtr - -# ASan 模式(--asan):对 .ll 先 opt -passes=asan 插桩,链接加 -fsanitize=address -_asan_mode: bool = 0 - -# 源代码缓冲区大小(1MB) -SRC_BUF_SIZE: t.CDefine = 1048576 # 2^20 = 1MB - -# .vpi 存根缓冲区大小(256KB,与 Phase1 一致) -PYI_BUF_SIZE: t.CSizeT = 262144 - -# ============================================================ -# TranslateFileGetTrans - 翻译单个文件,返回 Translator 对象 -# -# 读取文件 → AST 解析 → .vpi 生成 → LLVM IR 翻译,返回 Translator 对象供 -# 调用者 dump_ir。命名空间隔离:includes 文件宽松模式(全部可见), -# 用户文件严格模式(仅本地+import)。 -# -# Args: -# mb: 内存池 -# file_path: 源文件路径 -# sha1_val: 文件内容的 SHA1 前16字符(用于函数名混淆) -# current_package: 当前文件所属包名(用于解析相对导入),None 表示顶级模块 -# declare_only: 0=全量翻译(默认),1=仅注册 struct/enum/union(不翻译方法体) -# temp_dir: temp 目录路径(非 None 时在翻译前生成 .vpi 存根文件) -# -# Returns: -# Translator 对象(None 失败) -# ============================================================ -def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str, - sha1_val: str, - current_package: str = None, - declare_only: int = 0, - temp_dir: str = None) -> HandlesTranslator.Translator | t.CPtr: - """翻译文件,返回 Translator 对象(调用者负责 dump_ir),None 失败 - - current_package: 当前文件所属包名(用于解析相对导入),None 表示顶级模块 - declare_only: 0=全量翻译(默认),1=仅注册 struct/enum/union(不翻译方法体) - temp_dir: temp 目录路径(非 None 时在翻译前生成 .vpi 存根文件) - """ - if file_path is None: return None - f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R) - if f.closed: return None - src_buf: bytes = stdlib.malloc(SRC_BUF_SIZE) - if src_buf is None: - f.close() - return None - bytes_read: LONG = f.read_all(src_buf, SRC_BUF_SIZE) - f.close() - if bytes_read <= 0: - stdlib.free(src_buf) - return None - if bytes_read < SRC_BUF_SIZE: - src_buf[bytes_read] = 0 - else: - src_buf[SRC_BUF_SIZE - 1] = 0 - lx: ast.Lexer | t.CPtr = ast.new_lexer(mb) - ast._lexer_init(lx, src_buf, mb) - tokens: ast.Token | t.CPtr = ast.tokenize(lx) - tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens) - # parse 完成后 AST 树已独立,释放源代码缓冲区(避免 1MB/文件泄漏) - stdlib.free(src_buf) - if tree is None: - # fail-fast 定位:以 Python 风格输出解析错误 traceback(仿 fatal_error) - # Traceback (most recent call last): - # File "", line N - # - # SyntaxError: - HandlesType.dump_parse_traceback(file_path) - fb_parse: str = VLogger.fmt_buf() - if fb_parse is not None: - err_line: int = ast.get_parse_err_line() - err_col: int = ast.get_parse_err_col() - viperlib.snprintf(fb_parse, 1024, "解析失败: %s (line %d col %d)", file_path, err_line, err_col) - VLogger.error(fb_parse, "PARSE") - return None - # 生成 .vpi 存根文件(从 AST 直接生成,在 tr.translate 之前,与 Phase1 一致) - # .vpi 供其他模块跨模块查询函数签名和 CTypedef 定义 - if temp_dir is not None: - pyi_buf: bytes = stdlib.malloc(PYI_BUF_SIZE) - if pyi_buf is not None: - pyi_buf[0] = 0 - pyi_pos: t.CSizeT = StubConverter._GeneratePyiFromAst(mb, tree, None, pyi_buf, PYI_BUF_SIZE) - if pyi_pos > 0: - # 写入 {sha1}.vpi 到 temp_dir(切片路径) - td_len_vpi: t.CSizeT = len(temp_dir) - pyi_path: str = StubMergerCollect._sliced_path(temp_dir, td_len_vpi, sha1_val, "vpi") - if pyi_path is not None: - pf: fileio.File | t.CPtr = fileio.File(pyi_path, fileio.MODE.W) - if not pf.closed: - pf.write(pyi_buf, pyi_pos) - pf.close() - stdlib.free(pyi_path) - stdlib.free(pyi_buf) - tr: HandlesTranslator.Translator | t.CPtr = mb.alloc(HandlesTranslator.Translator.__sizeof__()) - tr.__before_init__() - tr.__init__() - tr.ModuleSha1 = sha1_val - tr.CurrentPackage = current_package - tr._declare_only = declare_only - # P2: 复用全局 gen 单例(App/main.vp 创建;HandlesType 等旧模块函数经 - # 延迟 import 委托到 gen 方法)。单例未注册时兜底创建(防御直接调用路径)。 - gen: GenGenerator.Generator | t.CPtr = GenGenerator._g_gen - if gen is None: - gen = mb.alloc(GenGenerator.Generator.__sizeof__()) - if gen is None: - VLogger.error("Generator alloc failed", "GEN") - return None - gen.__before_init__() - gen.__init__(mb) - GenGenerator._g_gen = gen - # P2-P5: 注入各 Handles 模块级单例(委托函数经本地 _g_gen 访问, - # 避免函数体 import 包模块与类/模块名歧义) - HandlesType._g_gen = gen - HandlesStruct._g_gen = gen - HandlesExpr._g_gen = gen - HandlesExprOps._g_gen = gen - HandlesExprCall._g_gen = gen - HandlesFunctions._g_gen = gen - HandlesClassDef._g_gen = gen - # P6: 注入语句/赋值/变量/导入/翻译驱动模块的单例 - HandlesImports._g_gen = gen - HandlesBody._g_gen = gen - HandlesIf._g_gen = gen - HandlesWhile._g_gen = gen - HandlesFor._g_gen = gen - HandlesReturn._g_gen = gen - HandlesNonlocal._g_gen = gen - HandlesMatch._g_gen = gen - HandlesEnum._g_gen = gen - HandlesAnnAssign._g_gen = gen - HandlesAugAssign._g_gen = gen - HandlesAssign._g_gen = gen - HandlesVar._g_gen = gen - HandlesTranslator._g_gen = gen - HandlesMain._g_gen = gen - # 设置当前文件名(供报错使用) - HandlesType.set_current_file(file_path) - # 同步到 HandlesImports(import 时 SHA1 检查报错需要当前文件名,循环依赖无法直接读 HandlesType) - HandlesImports.set_current_file(file_path) - # 清空调用栈(每个文件翻译开始前重置) - HandlesType.clear_trace() - # 模块切换:清空 CDefine 常量表,确保每个模块的 CDefine 常量正确隔离 - HandlesType.clear_cdefine_constants() - # 模块切换:清空 CTypedef 表,确保每个模块的 CTypedef 正确隔离 - HandlesType.clear_ctypedefs() - # 命名空间隔离:includes 文件宽松模式(全部可见),用户文件严格模式(仅本地+import) - strict_mode: int = 1 - if string.strstr(file_path, "includes") is not None: - strict_mode = 0 - HandlesStruct.reset_visible_structs(mb, strict_mode) - # 提取 docstring(预注册阶段所有 App/includes 文件都被翻译, - # 保证跨模块 __doc__ 在正式翻译前已登记;查重幂等) - # 注意:必须在 tr.translate 之前扫描——translate 期间 mb 池大量分配 - # IR 节点,AST 节点所在池块可能被复用覆盖(ASan 下遍历 tree 读 - # 0xffffffffffffffff 崩溃),docstring 提取与翻译状态无关,提前安全。 - if gen is not None: - gen.extract_module_docstrings(tree, sha1_val) - ret: int = tr.translate(tree) - if ret != 0: - fb_tf: str = VLogger.fmt_buf() - if fb_tf is not None: - viperlib.snprintf(fb_tf, 1024, "文件翻译失败: %s", file_path) - VLogger.error(fb_tf, "Translate") - return None - return tr - - -class BuildResult: - Success: t.CInt - OutputPath: str - ErrorMsg: str - - def __new__(self) -> t.CPtr: - return t.CPtr(_mbuddy.alloc(BuildResult.__sizeof__())) - - def __init__(self): - self.Success = 0 - self.OutputPath = None - self.ErrorMsg = None - - -def ensure_dir(path: str) -> int: - """递归创建目录(类似 mkdir -p),目录已存在视为成功 - - Args: - path: 目录路径(支持 / 或 \\ 分隔符) - - Returns: - 0 成功(包括目录已存在),非 0 失败 - """ - if path is None: - return 1 - - path_len: t.CSizeT = len(path) - if path_len == 0: - return 0 - - # 复制路径到可写缓冲区(逐级截断用) - buf: bytes = _mbuddy.alloc(path_len + 1) - if buf is None: - return 1 - string.strcpy(buf, path) - - # 遇到分隔符时临时截断,创建每一层目录 - # CreateDirectoryA 在目录已存在时返回 0(失败),忽略即可 - plen: int = path_len - for i in range(plen): - ch: int = buf[i] - if ch == 47 or ch == 92: # '/' = 47, '\\' = 92 - saved: int = ch - buf[i] = '\0' - w32.win32file.CreateDirectoryA(buf, None) - buf[i] = saved - - # 创建最终目录 - w32.win32file.CreateDirectoryA(buf, None) - return 0 - - -# ============================================================ -# build_sliced_path - 构建切片路径并确保目录存在 -# -# 根据 Config.Sha1SliceLevel 将文件分散到 SHA1 前缀子目录: -# level=0 → {base_dir}/{sha1}.{ext} -# level=1 → {base_dir}/b7/{sha1}.{ext} -# level=2 → {base_dir}/b7/90/{sha1}.{ext} -# -# 自动调用 ensure_dir 创建子目录。 -# -# Args: -# base_dir: 基础目录(如 temp_dir) -# sha1: SHA1 字符串 -# ext: 文件扩展名(如 "stub.ll") -# -# Returns: -# 完整文件路径(mbuddy 分配),None 失败 -# ============================================================ -def build_sliced_path(base_dir: str, sha1: str, ext: str) -> str: - """构建切片路径并确保目录存在""" - if base_dir is None or sha1 is None or ext is None: - return None - - subdir: str = Config.slice_subdir(sha1, Config.Sha1SliceLevel) - base_len: t.CSizeT = len(base_dir) - sha1_len: t.CSizeT = len(sha1) - ext_len: t.CSizeT = len(ext) - - if subdir is not None: - sub_len: t.CSizeT = len(subdir) - # ensure_dir({base_dir}/{subdir}) - dir_path: str = _mbuddy.alloc(base_len + sub_len + 2) - if dir_path is not None: - viperlib.snprintf(dir_path, base_len + sub_len + 2, "%s/%s", base_dir, subdir) - ensure_dir(dir_path) - # 文件路径: {base_dir}/{subdir}/{sha1}.{ext} - path_len: t.CSizeT = base_len + sub_len + sha1_len + ext_len + 4 - path: str = _mbuddy.alloc(path_len) - if path is None: return None - viperlib.snprintf(path, path_len, "%s/%s/%s.%s", base_dir, subdir, sha1, ext) - return path - else: - # 无切片: {base_dir}/{sha1}.{ext} - path_len = base_len + sha1_len + ext_len + 3 - path = _mbuddy.alloc(path_len) - if path is None: return None - viperlib.snprintf(path, path_len, "%s/%s.%s", base_dir, sha1, ext) - return path - - -def write_ir_to_file(ir_buf: bytes, ir_len: t.CSizeT, output_dir: str, module_name: str) -> int: - """将 IR 缓冲区写入 .ll 文件 - - Args: - ir_buf: IR 文本缓冲区 - ir_len: IR 文本长度 - output_dir: 输出目录(temp 或 output) - module_name: 模块名(SHA1) - - Returns: - 0 成功,非 0 失败 - """ - if ir_buf is None or output_dir is None or module_name is None: return 1 - - # 构造切片路径: output_dir/{sha1前缀}/{module_name}.ll - path: str = build_sliced_path(output_dir, module_name, "ll") - if path is None: return 1 - - # 打开文件写入 - f: fileio.File | t.CPtr = fileio.File(path, fileio.MODE.W) - if f.closed: return 1 - - written: t.CInt64T = f.write(ir_buf, ir_len) - f.close() - if written < 0: return 1 - return 0 - - -def compile_ll_to_obj(ir_path: str, output_dir: str, module_name: str, cc_cmd: str, cc_flags: str) -> int: - """调用 llc 将 .ll 编译为 .obj - - Args: - ir_path: .ll 文件路径 - output_dir: 输出目录 - module_name: 模块名(SHA1,用于生成 .obj 文件名) - cc_cmd: 编译器命令(如 "llc") - cc_flags: 编译器参数(如 "-filetype=obj -relocation-model=pic") - - Returns: - 0 成功,非 0 失败 - """ - if ir_path is None or cc_cmd is None or output_dir is None or module_name is None: - return 1 - - # 构造切片 .obj 路径: output_dir/{sha1前缀}/{module_name}.obj - obj_path: str = build_sliced_path(output_dir, module_name, "obj") - if obj_path is None: return 1 - - # ASan 模式(_asan_mode=1):先 opt -passes=asan 插桩再 llc。 - # -asan-globals=false 关闭全局插桩:TPV 对全局变量(如各模块 _g_gen) - # 用直接地址寻址,ASan 全局 redzone 重定位后引用错位会读到垃圾指针。 - compile_input: str = ir_path - if _asan_mode != 0: - asan_path: str = build_sliced_path(output_dir, module_name, "asan.ll") - if asan_path is None: - return 1 - opt_cmd_len: t.CSizeT = len(asan_path) + len(ir_path) + 192 - opt_cmd: bytes = _mbuddy.alloc(opt_cmd_len) - if opt_cmd is None: - return 1 - viperlib.snprintf(opt_cmd, opt_cmd_len, - "opt -passes=forceattrs,asan -force-attribute=sanitize_address -asan-globals=false -o %s %s", - asan_path, ir_path) - opt_ret: int = stdlib.system(opt_cmd) - if opt_ret != 0: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "opt ASan 插桩失败 (module=%s)", module_name) - VLogger.error(fb, "ASAN") - return 1 - compile_input = asan_path - - # 构造命令: llc -filetype=obj -o {obj_path} ir_path - cmd_len: t.CSizeT = len(cc_cmd) + len(cc_flags) + len(obj_path) + len(compile_input) + 64 - cmd: bytes = _mbuddy.alloc(cmd_len) - if cmd is None: - return 1 - viperlib.snprintf(cmd, cmd_len, "%s %s -o %s %s", cc_cmd, cc_flags, obj_path, compile_input) - - # 用 stdlib.system() 直接在控制台运行,输出直接显示 - # 避免 subprocess 管道捕获丢失输出 - sys_ret: int = stdlib.system(cmd) - if sys_ret != 0: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "编译失败 (module=%s, cmd=%s)", module_name, cmd) - VLogger.error(fb, "LLC") - return 1 - return 0 - - -# ============================================================ -# llc 并行编译(线程异步,Phase B 多模块同时跑 llc) -# -# 线程安全约束: -# - LlcTask 及命令串一律 stdlib.malloc:主池 mb 会被 reset_to(mark2) -# 回收,线程运行期间字符串悬空 → 概率崩溃 -# - worker 只调 stdlib.system(),不做任何池分配(MemBuddy 分配非线程安全) -# - 依赖 CRT system() 的多线程安全性(ThreadingTest 已验证) -# ============================================================ -# llc 并行最大线程数(参考 TPC Phase2Translator n_workers=os.cpu_count(),本机 16 核) -LLC_MAX_THREADS: t.CDefine = 16 - - -class LlcTask: - """llc 异步任务:命令串(stdlib.malloc)+ 模块 SHA1 + 结果""" - OptCmd: bytes # ASan 插桩命令(非 ASan 为 None) - LlcCmd: bytes # llc 命令 - ModuleSha1: bytes # 模块 SHA1(报错用) - Result: int # worker 写:0 成功,非 0 失败 - - -def init_llc_task(task: LlcTask | t.CPtr, ir_path: str, output_dir: str, - module_name: str, cc_cmd: str, cc_flags: str) -> int: - """填充 llc 任务(全部 stdlib.malloc,线程运行期不被回收),0 成功""" - if task is None or ir_path is None or output_dir is None or module_name is None: - return 1 - string.memset(task, 0, LlcTask.__sizeof__()) - task.Result = -1 - obj_path: str = build_sliced_path(output_dir, module_name, "obj") - if obj_path is None: - return 1 - # 模块 SHA1 - sl: t.CSizeT = len(module_name) - task.ModuleSha1 = stdlib.malloc(sl + 1) - if task.ModuleSha1 is None: - return 1 - string.strcpy(task.ModuleSha1, module_name) - # llc 命令 - cmd_len: t.CSizeT = len(cc_cmd) + len(cc_flags) \ - + len(obj_path) + len(ir_path) + 64 - task.LlcCmd = stdlib.malloc(cmd_len) - if task.LlcCmd is None: - return 1 - viperlib.snprintf(task.LlcCmd, cmd_len, "%s %s -o %s %s", - cc_cmd, cc_flags, obj_path, ir_path) - # ASan 模式:opt 插桩命令(worker 先跑,失败即置 Result) - if _asan_mode != 0: - asan_path: str = build_sliced_path(output_dir, module_name, "asan.ll") - if asan_path is None: - return 1 - opt_len: t.CSizeT = len(asan_path) + len(ir_path) + 192 - task.OptCmd = stdlib.malloc(opt_len) - if task.OptCmd is None: - return 1 - viperlib.snprintf(task.OptCmd, opt_len, - "opt -passes=forceattrs,asan -force-attribute=sanitize_address" - " -asan-globals=false -o %s %s", - asan_path, ir_path) - return 0 - - -def free_llc_task(task: LlcTask | t.CPtr): - """释放任务的命令串;记录本身是任务数组的连续槽(非独立 malloc), - 由调用方对数组整体 stdlib.free(此前对槽 free 导致 double-free)""" - if task is None: - return - if task.OptCmd is not None: - stdlib.free(task.OptCmd) - task.OptCmd = None - if task.LlcCmd is not None: - stdlib.free(task.LlcCmd) - task.LlcCmd = None - if task.ModuleSha1 is not None: - stdlib.free(task.ModuleSha1) - task.ModuleSha1 = None - - -def _run_cmd_wait(cmd: str) -> int: - """CreateProcessA 同步执行命令并等待退出,返回退出码。 - - 替代 stdlib.system:Windows asan 环境下 cmd /c 经 CreateProcess 受 - RTL allocator hook 干扰可能挂起(LLVM issue #111166 同类,ClassArrayTest - llc 固定卡死根因);CreateProcessA 直接执行目标程序并继承父进程控制台 - (stdout/stderr 直接显示,同 system 语义)。全 stdlib.malloc/栈分配, - worker 线程安全。 - """ - if cmd is None: - return -1 - cl_len: t.CSizeT = len(cmd) - cmd_line: bytes = stdlib.malloc(cl_len + 1) - if cmd_line is None: - return -1 - string.strcpy(cmd_line, cmd) - sa: w32.win32base.SECURITY_ATTRIBUTES = w32.win32base.SECURITY_ATTRIBUTES() - si: win32process.STARTUPINFOA = win32process.STARTUPINFOA() - pi: win32process.PROCESS_INFORMATION = win32process.PROCESS_INFORMATION() - # T() 构造仅 alloca 不 memset:STARTUPINFOA 未设字段(dwFlags 等)全为 - # 栈垃圾,多线程并发调用时垃圾随机 → dwFlags 垃圾位让 CreateProcessA - # 用垃圾句柄作子进程 stdio → 子进程行为不定/父进程线程崩溃(ClassArrayTest - # e5fb worker 崩溃、edd8 正常的原因)。si/sa/pi 全部显式清零。 - string.memset(t.CPtr(c.Addr(si)), 0, win32process.STARTUPINFOA.__sizeof__()) - string.memset(t.CPtr(c.Addr(sa)), 0, w32.win32base.SECURITY_ATTRIBUTES.__sizeof__()) - string.memset(t.CPtr(c.Addr(pi)), 0, win32process.PROCESS_INFORMATION.__sizeof__()) - sa.nLength = w32.win32base.SECURITY_ATTRIBUTES.__sizeof__() - sa.lpSecurityDescriptor = t.CPtr(0) - sa.bInheritHandle = 1 - si.cb = win32process.STARTUPINFOA.__sizeof__() - # create_flags=0:子进程继承父控制台(输出直接显示,同 system 语义) - ok: int = win32process.CreateProcessA( - t.CPtr(0), cmd_line, t.CPtr(0), t.CPtr(0), 1, 0, - t.CPtr(0), t.CPtr(0), t.CPtr(c.Addr(si)), t.CPtr(c.Addr(pi))) - stdlib.free(cmd_line) - if ok == 0: - return -1 - win32sync.WaitForSingleObject(pi.hProcess, w32.win32base.INFINITE) - exit_code: t.CUInt32T = 0 - win32process.GetExitCodeProcess(pi.hProcess, t.CPtr(c.Addr(exit_code))) - w32.win32base.CloseHandle(pi.hProcess) - w32.win32base.CloseHandle(pi.hThread) - return t.CInt(exit_code) - - -def _llc_task_worker(arg: t.CPtr) -> t.CPtr: - """llc 线程入口:只调 stdlib.system(),不做任何分配(线程安全) - Result 仅在命令链执行完后写入(初始 -1;join 超时保持 -1 → 报失败)""" - task: LlcTask | t.CPtr = (LlcTask | t.CPtr)(arg) - if task is None: - return t.CPtr(0) - if task.OptCmd is not None: - opt_rc: int = _run_cmd_wait(task.OptCmd) - if opt_rc != 0: - task.Result = 1 - return t.CPtr(0) - llc_rc: int = _run_cmd_wait(task.LlcCmd) - if llc_rc != 0: - task.Result = 1 - else: - task.Result = 0 - return t.CPtr(0) - - -def run_llc_parallel(tasks: bytes, task_count: int, max_threads: int) -> int: - """并行执行 llc:分批 max_threads 个线程,全部 join 后检查结果 - - tasks: LlcTask 记录连续数组(stdlib.malloc),每个记录由 init_llc_task 填充。 - Returns: 0 全部成功;非 0 有失败(已打印失败模块与命令) - """ - if tasks is None or task_count <= 0: - return 0 - if max_threads <= 0: - max_threads = 1 - # 线程句柄数组:list[str](str=bytes=i8*,elem_size=8 显式)存句柄值。 - # 此前 list[t.CPtr] 特化修复后 append 仍崩(pool 有效、elem=8 下读零页, - # list[ptr] append 的 store 与 t.CPtr 参数类型生成待查);list[str] 全库 - # 验证稳定(append/get 8 字节指针)。start() 后立即取 handle 存入, - # join/close 直接对句柄操作,不依赖 Thread 对象存续。 - handles: list[str] | t.CPtr = list[str](_mbuddy, 8) - if handles is None: - VLogger.error("run_llc_parallel: 线程句柄数组分配失败", "PhaseB") - return 1 - slot_size: t.CSizeT = LlcTask.__sizeof__() - ret: int = 0 - # 分批执行:batch_start 按 max_threads 步进(每批 spawn+join+close 一批句柄)。 - for batch_start in range(0, task_count, max_threads): - batch_n: int = max_threads - if batch_start + batch_n > task_count: - batch_n = task_count - batch_start - # 本批 spawn - for j in range(batch_n): - tsk: LlcTask | t.CPtr = (LlcTask | t.CPtr)(t.CVoid( - t.CUInt64T(tasks) + t.CSizeT(batch_start + j) * slot_size, t.CPtr)) - th: vthreading.Thread | t.CPtr = vthreading.Thread(_llc_task_worker, t.CPtr(tsk)) - th.start() - # start() 后立即取出句柄(Thread 对象栈地址可能被后续构造复用, - # join 时再读 self.handle 可能已被 close 清空/覆盖) - handles.append(t.CPtr(th.handle)) - for j in range(batch_n): - h_j: t.CPtr = t.CPtr(handles.get(batch_start + j)) - wr: t.CUInt32T = win32sync.WaitForSingleObject(h_j, 600000) - if wr != 0: - VLogger.error("llc 线程 join 超时/失败(600 秒未完成)", "PhaseB") - w32.win32base.CloseHandle(h_j) - # 本批结果检查 - for j in range(batch_n): - tsk2: LlcTask | t.CPtr = (LlcTask | t.CPtr)(t.CVoid( - t.CUInt64T(tasks) + t.CSizeT(batch_start + j) * slot_size, t.CPtr)) - if tsk2 is not None and tsk2.Result != 0: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "llc 编译失败: %s (cmd=%s)", - (tsk2.ModuleSha1 if tsk2.ModuleSha1 is not None else "?"), - (tsk2.LlcCmd if tsk2.LlcCmd is not None else "?")) - VLogger.error(fb, "LLC") - ret = 1 - return ret - - -def _CollectObjFilesImpl(base_dir: str, bd_len: t.CSizeT, - out_buf: bytes, out_pos: t.CSizeT, out_size: t.CSizeT) -> t.CSizeT: - """递归扫描 base_dir,收集 .obj 文件路径到 out_buf,返回新的 out_pos - - 支持切片子目录(如 dir/43/{sha1}.obj)。 - """ - find_data: w32.win32file.WIN32_FIND_DATAA | t.CPtr = _mbuddy.alloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__()) - if find_data is None: - VLogger.warning("_CollectObjFilesImpl 分配 find_data 失败,少收集 .obj", "collect") - return out_pos - string.memset(find_data, 0, w32.win32file.WIN32_FIND_DATAA.__sizeof__()) - - pattern: bytes = _mbuddy.alloc(bd_len + 8) - if pattern is None: - VLogger.warning("_CollectObjFilesImpl 分配 pattern 失败,少收集 .obj", "collect") - return out_pos - viperlib.snprintf(pattern, bd_len + 8, "%s/*", base_dir) - - handle: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(pattern, find_data) - _mbuddy.free(pattern) - if handle == w32.win32base.INVALID_HANDLE_VALUE: - VLogger.warning("_CollectObjFilesImpl 无法打开目录,少收集 .obj", "collect") - return out_pos - - while True: - fname: str = find_data.cFileName - if fname is not None: - fname_len: t.CSizeT = len(fname) - if fname_len > 0: - # 跳过 . 和 .. - is_dot: int = 0 - if fname_len == 1 and fname[0] == '.': - is_dot = 1 - elif fname_len == 2 and fname[0] == '.' and fname[1] == '.': - is_dot = 1 - if is_dot == 0: - attrs: ULONG = find_data.dwFileAttributes - is_dir: int = 0 - if (attrs & w32.win32file.FILE_ATTRIBUTE_DIRECTORY) != 0: - is_dir = 1 - if is_dir != 0: - # 递归扫描子目录 - sub_dir: bytes = _mbuddy.alloc(bd_len + fname_len + 2) - if sub_dir is not None: - viperlib.snprintf(sub_dir, bd_len + fname_len + 2, "%s/%s", base_dir, fname) - sub_len: t.CSizeT = len(sub_dir) - out_pos = _CollectObjFilesImpl(sub_dir, sub_len, out_buf, out_pos, out_size) - _mbuddy.free(sub_dir) - else: - # 检查是否是 .obj 文件 - if fname_len > 4 and fname[fname_len - 4] == '.' \ - and fname[fname_len - 3] == 'o' and fname[fname_len - 2] == 'b' \ - and fname[fname_len - 1] == 'j': - need: t.CSizeT = bd_len + 1 + fname_len + 2 - if out_pos + need >= out_size: - break - if out_pos > 0: - out_buf[out_pos] = ' ' - out_pos += 1 - viperlib.snprintf(out_buf + out_pos, need, "%s/%s", base_dir, fname) - out_pos += bd_len + 1 + fname_len - - if w32.win32file.FindNextFileA(handle, find_data) == 0: - break - - w32.win32file.FindClose(handle) - return out_pos - - -def collect_obj_files(includes_binary_dir: str, out_buf: bytes, out_size: t.CSizeT) -> t.CSizeT: - """递归扫描 includes_binary_dir 目录,收集所有 .obj 文件路径到 out_buf - - 支持切片子目录(如 includes_binary_dir/43/{sha1}.obj)。 - - Args: - includes_binary_dir: includes.binary 目录路径 - out_buf: 输出缓冲区(用于存放空格分隔的 .obj 文件路径) - out_size: 输出缓冲区大小 - - Returns: - 写入的字节数(不含 null 终止符),0 表示无文件或错误 - """ - if includes_binary_dir is None or out_buf is None or out_size == 0: - return 0 - - out_buf[0] = '\0' - dir_len: t.CSizeT = len(includes_binary_dir) - out_pos: t.CSizeT = _CollectObjFilesImpl(includes_binary_dir, dir_len, out_buf, 0, out_size) - out_buf[out_pos] = '\0' - return out_pos - - -def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_flags: str, linker_output: str, - includes_binary_dir: str) -> int: - """调用 clang++ 链接 .obj 为 .exe - - Args: - output_dir: 输出目录(包含 .obj 文件) - module_name: 模块名(SHA1) - linker_cmd: 链接器命令(如 "clang++") - linker_flags: 链接器参数 - linker_output: 输出文件名(如 "test.exe") - includes_binary_dir: includes.binary 目录路径(链接时附加预编译 .obj) - - Returns: - 0 成功,非 0 失败 - """ - if output_dir is None or linker_cmd is None or module_name is None: - return 1 - - # 构造切片 .obj 路径: output_dir/{sha1前缀}/{module_name}.obj - obj_path: str = build_sliced_path(output_dir, module_name, "obj") - if obj_path is None: - return 1 - - # 收集 includes.binary 的 .obj 文件路径 - EXTRA_BUF_SIZE: t.CSizeT = 32768 - extra_objs: bytes = _mbuddy.alloc(EXTRA_BUF_SIZE) - if extra_objs is None: - return 1 - extra_len: t.CSizeT = 0 - if includes_binary_dir is not None: - extra_len = collect_obj_files(includes_binary_dir, extra_objs, EXTRA_BUF_SIZE) - if extra_len > 0: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "附加 %d 字节的 includes.binary .obj 文件", extra_len) - VLogger.info(fb, "link") - else: - fb = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "includes.binary 无 .obj 文件: %s", includes_binary_dir) - VLogger.warning(fb, "link") - - # 构造命令: clang++ {obj_path} extra_objs -o {output_dir}/{linker_output} linker_flags - # 注意: .obj 文件必须在 -l 库标志之前,否则链接器无法解析符号依赖 - # ASan 模式:mingw64 clang 的 -fsanitize=address 在 mingw64/lib 下找不到 - # asan 运行库(实际在 clang64),改为显式链接 clang64 的 libclang_rt - # (DLL 版,运行时需 D:/msys64/clang64/bin 在 PATH) - use_flags: str = linker_flags - if _asan_mode != 0: - fl_len: t.CSizeT = len(linker_flags) + 256 - use_flags = _mbuddy.alloc(fl_len) - if use_flags is None: - return 1 - viperlib.snprintf(use_flags, fl_len, - "%s -L D:/msys64/clang64/lib/clang/22/lib/windows -l:libclang_rt.asan_dynamic-x86_64.dll.a -l:libclang_rt.asan_dynamic_runtime_thunk-x86_64.a", - linker_flags) - cmd_len: t.CSizeT = len(linker_cmd) + len(obj_path) + len(use_flags) + len(output_dir) + len(linker_output) + extra_len + 128 - cmd: bytes = _mbuddy.alloc(cmd_len) - if cmd is None: - return 1 - if extra_len > 0: - viperlib.snprintf(cmd, cmd_len, "%s %s %s -o %s/%s %s", - linker_cmd, obj_path, extra_objs, - output_dir, linker_output, use_flags) - else: - viperlib.snprintf(cmd, cmd_len, "%s %s -o %s/%s %s", - linker_cmd, obj_path, output_dir, linker_output, - use_flags) - - result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True) - if result is None: - VLogger.error("subprocess.run 返回 None", "link") - return 1 - if result.returncode != 0: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "链接失败,返回码: %d", result.returncode) - VLogger.error(fb, "link") - fb = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "命令: %s", cmd) - VLogger.error(fb, "link") - # 显示链接器错误输出 - # 注意: subprocess 在 Windows 下将 stderr 合并到 stdout,result.stderr 总是 None - if result.stdout is not None: - VLogger.error(result.stdout, "link") - else: - VLogger.error("无输出捕获", "link") - if result.stderr is not None: - VLogger.error(result.stderr, "link") - return 1 - return 0 - - -def compile_module_to_obj(ir_buf: bytes, ir_len: t.CSizeT, - temp_dir: str, output_dir: str, module_name: str, - cc_cmd: str, cc_flags: str) -> int: - """编译 IR 到 .obj(不链接) - - Args: - ir_buf: LLVM IR 文本缓冲区 - ir_len: IR 文本长度 - temp_dir: 临时目录 - output_dir: 输出目录 - module_name: 模块名(SHA1) - cc_cmd: 编译器命令 - cc_flags: 编译器参数 - - Returns: - 0 成功,非 0 失败 - """ - if ir_buf is None or temp_dir is None or output_dir is None or module_name is None: - return 1 - - # Step 1: 写 .ll 文件 - ret: int = write_ir_to_file(ir_buf, ir_len, temp_dir, module_name) - if ret != 0: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "写 .ll 失败: %s", module_name) - VLogger.error(fb, "compile") - return 1 - - # Step 2: 构造切片 .ll 路径并编译 → .obj - ir_path: str = build_sliced_path(temp_dir, module_name, "ll") - if ir_path is None: - return 1 - - ret = compile_ll_to_obj(ir_path, output_dir, module_name, cc_cmd, cc_flags) - if ret != 0: - fb = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "llc 编译失败: %s", module_name) - VLogger.error(fb, "compile") - return 1 - return 0 - - -def link_objs_to_exe(obj_paths: str, obj_paths_len: t.CSizeT, - linker_cmd: str, linker_flags: str, linker_output: str, - includes_binary_dir: str) -> int: - """链接多个 .obj 文件为 .exe - - Args: - obj_paths: 空格分隔的 .obj 文件完整路径字符串 - obj_paths_len: obj_paths 长度 - linker_cmd: 链接器命令(如 "clang++") - linker_flags: 链接器参数 - linker_output: 输出文件完整路径 - includes_binary_dir: includes.binary 目录路径(链接时附加预编译 .obj) - - Returns: - 0 成功,非 0 失败 - """ - if obj_paths is None or obj_paths_len == 0 or linker_cmd is None: - return 1 - - # 收集 includes.binary 的 .obj 文件路径 - EXTRA_BUF_SIZE: t.CSizeT = 32768 - extra_objs: bytes = _mbuddy.alloc(EXTRA_BUF_SIZE) - if extra_objs is None: - return 1 - extra_len: t.CSizeT = 0 - if includes_binary_dir is not None: - extra_len = collect_obj_files(includes_binary_dir, extra_objs, EXTRA_BUF_SIZE) - - # 构造命令: clang++ obj_paths extra_objs -o linker_output linker_flags - # ASan 模式:显式链接 clang64 的 libclang_rt(同 link_obj_to_exe) - use_flags: str = linker_flags - if _asan_mode != 0: - fl_len: t.CSizeT = len(linker_flags) + 256 - use_flags = _mbuddy.alloc(fl_len) - if use_flags is None: - return 1 - viperlib.snprintf(use_flags, fl_len, - "%s -L D:/msys64/clang64/lib/clang/22/lib/windows -l:libclang_rt.asan_dynamic-x86_64.dll.a -l:libclang_rt.asan_dynamic_runtime_thunk-x86_64.a", - linker_flags) - cmd_len: t.CSizeT = len(linker_cmd) + obj_paths_len + len(use_flags) + len(linker_output) + extra_len + 128 - cmd: bytes = _mbuddy.alloc(cmd_len) - if cmd is None: - return 1 - if extra_len > 0: - viperlib.snprintf(cmd, cmd_len, "%s %s %s -o %s %s", - linker_cmd, obj_paths, extra_objs, - linker_output, use_flags) - else: - viperlib.snprintf(cmd, cmd_len, "%s %s -o %s %s", - linker_cmd, obj_paths, linker_output, use_flags) - - # 用 subprocess.run 捕获 clang++ 的 stdout/stderr 输出 - # 之前用 stdlib.system() 无法捕获具体错误(undefined reference 等), - # 导致 1.txt 中只看到"链接失败,返回码: 1"而看不到未解析符号 - result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True) - if result is None: - VLogger.error("subprocess.run 返回 None", "link") - return 1 - if result.returncode != 0: - # 先用 stdio.printf 直接输出 clang++ 的完整错误输出(含 undefined reference) - # 必须在 VLogger.error 之前输出,因为 VLogger.error 会调用 sys.exit(1) 终止进程 - if result.stdout is not None: - stdio.printf("=== clang++ 链接错误输出 ===\n%s\n", result.stdout) - if result.stderr is not None: - stdio.printf("=== clang++ stderr ===\n%s\n", result.stderr) - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "链接失败,返回码: %d, 命令: %s", result.returncode, cmd) - VLogger.error(fb, "link") - return 1 - return 0 - - -def run_pipeline(ir_buf: bytes, ir_len: t.CSizeT, - temp_dir: str, output_dir: str, module_name: str, - cc_cmd: str, cc_flags: str, - linker_cmd: str, linker_flags: str, linker_output: str, - includes_binary_dir: str) -> BuildResult | t.CPtr: - """执行完整编译管线 - - Args: - ir_buf: LLVM IR 文本缓冲区 - ir_len: IR 文本长度 - temp_dir: 临时目录 - output_dir: 输出目录 - module_name: 模块名 - cc_cmd: 编译器命令 - cc_flags: 编译器参数 - linker_cmd: 链接器命令 - linker_flags: 链接器参数 - linker_output: 输出文件名 - includes_binary_dir: includes.binary 目录路径(链接时附加预编译 .obj) - - Returns: - BuildResult 对象 - """ - result: BuildResult | t.CPtr = BuildResult() - if result is None: - return None - - # Step 0: 确保 temp/output 目录存在(自动创建,避免写文件失败) - ensure_dir(temp_dir) - ensure_dir(output_dir) - - # Step 1: 写 .ll 文件 - ret: int = write_ir_to_file(ir_buf, ir_len, temp_dir, module_name) - if ret != 0: - result.Success = 0 - result.ErrorMsg = "写 .ll 文件失败" - return result - - # Step 2: llc 编译 .ll → .obj - # 构造切片 .ll 文件路径 - ir_path: str = build_sliced_path(temp_dir, module_name, "ll") - if ir_path is None: - result.Success = 0 - result.ErrorMsg = "内存分配失败" - return result - - ret = compile_ll_to_obj(ir_path, output_dir, module_name, cc_cmd, cc_flags) - if ret != 0: - result.Success = 0 - result.ErrorMsg = "llc 编译失败" - return result - - # Step 3: clang++ 链接 .obj → .exe(附加 includes.binary 预编译 .obj) - ret = link_obj_to_exe(output_dir, module_name, linker_cmd, linker_flags, linker_output, - includes_binary_dir) - if ret != 0: - result.Success = 0 - result.ErrorMsg = "链接失败" - return result - - result.Success = 1 +import lib.core.Gen.GenApi as GenApi +import t, c +from stdint import * +import stdio +import string +import stdlib +import memhub +import viperlib +import vthreading +import w32.fileio as fileio +import w32.win32file +import w32.win32base +import w32.win32process as win32process +import w32.win32sync as win32sync +import subprocess +import viperlib +import ast +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HandlesTranslator +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.StubMerger as StubMerger +import lib.StubGen.Converter as StubConverter +import lib.Projectrans.Config as Config +import lib.core.Gen.Generator as GenGenerator +import lib.core.Gen.ExprGenCls as ExprGenCls +import lib.core.StubMergerCollect as StubMergerCollect + +# ============================================================ +# BuildPipeline - 编译管线 +# +# 负责将 LLVM IR 编译为可执行文件: +# 1. 写 .ll 文件到 temp 目录 +# 2. 调用 llc 编译 .ll → .obj +# 3. 调用 clang++ 链接 .obj → .exe +# ============================================================ + +# 全局 mbuddy 指针 +_mbuddy: memhub.MemBuddy | t.CPtr + +# ASan 模式(--asan):对 .ll 先 opt -passes=asan 插桩,链接加 -fsanitize=address +_asan_mode: bool = 0 + +# 源代码缓冲区大小(1MB) +SRC_BUF_SIZE: t.CDefine = 1048576 # 2^20 = 1MB + +# .vpi 存根缓冲区大小(256KB,与 Phase1 一致) +PYI_BUF_SIZE: t.CSizeT = 262144 + +# ============================================================ +# TranslateFileGetTrans - 翻译单个文件,返回 Translator 对象 +# +# 读取文件 → AST 解析 → .vpi 生成 → LLVM IR 翻译,返回 Translator 对象供 +# 调用者 dump_ir。命名空间隔离:includes 文件宽松模式(全部可见), +# 用户文件严格模式(仅本地+import)。 +# +# Args: +# mb: 内存池 +# file_path: 源文件路径 +# sha1_val: 文件内容的 SHA1 前16字符(用于函数名混淆) +# current_package: 当前文件所属包名(用于解析相对导入),None 表示顶级模块 +# declare_only: 0=全量翻译(默认),1=仅注册 struct/enum/union(不翻译方法体) +# temp_dir: temp 目录路径(非 None 时在翻译前生成 .vpi 存根文件) +# +# Returns: +# Translator 对象(None 失败) +# ============================================================ +def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str, + sha1_val: str, + current_package: str = None, + declare_only: int = 0, + temp_dir: str = None) -> HandlesTranslator.Translator | t.CPtr: + """翻译文件,返回 Translator 对象(调用者负责 dump_ir),None 失败 + + current_package: 当前文件所属包名(用于解析相对导入),None 表示顶级模块 + declare_only: 0=全量翻译(默认),1=仅注册 struct/enum/union(不翻译方法体) + temp_dir: temp 目录路径(非 None 时在翻译前生成 .vpi 存根文件) + """ + if file_path is None: return None + f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R) + if f.closed: return None + src_buf: bytes = stdlib.malloc(SRC_BUF_SIZE) + if src_buf is None: + f.close() + return None + bytes_read: LONG = f.read_all(src_buf, SRC_BUF_SIZE) + f.close() + if bytes_read <= 0: + stdlib.free(src_buf) + return None + if bytes_read < SRC_BUF_SIZE: + src_buf[bytes_read] = 0 + else: + src_buf[SRC_BUF_SIZE - 1] = 0 + lx: ast.Lexer | t.CPtr = ast.new_lexer(mb) + ast._lexer_init(lx, src_buf, mb) + tokens: ast.Token | t.CPtr = ast.tokenize(lx) + tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens) + # parse 完成后 AST 树已独立,释放源代码缓冲区(避免 1MB/文件泄漏) + stdlib.free(src_buf) + if tree is None: + # fail-fast 定位:以 Python 风格输出解析错误 traceback(仿 fatal_error) + # Traceback (most recent call last): + # File "", line N + # + # SyntaxError: + GenApi.dump_parse_traceback(file_path) + fb_parse: str = VLogger.fmt_buf() + if fb_parse is not None: + err_line: int = ast.get_parse_err_line() + err_col: int = ast.get_parse_err_col() + viperlib.snprintf(fb_parse, 1024, "解析失败: %s (line %d col %d)", file_path, err_line, err_col) + VLogger.error(fb_parse, "PARSE") + return None + # 生成 .vpi 存根文件(从 AST 直接生成,在 tr.translate 之前,与 Phase1 一致) + # .vpi 供其他模块跨模块查询函数签名和 CTypedef 定义 + if temp_dir is not None: + pyi_buf: bytes = stdlib.malloc(PYI_BUF_SIZE) + if pyi_buf is not None: + pyi_buf[0] = 0 + pyi_pos: t.CSizeT = StubConverter._GeneratePyiFromAst(mb, tree, None, pyi_buf, PYI_BUF_SIZE) + if pyi_pos > 0: + # 写入 {sha1}.vpi 到 temp_dir(切片路径) + td_len_vpi: t.CSizeT = len(temp_dir) + pyi_path: str = StubMergerCollect._sliced_path(temp_dir, td_len_vpi, sha1_val, "vpi") + if pyi_path is not None: + pf: fileio.File | t.CPtr = fileio.File(pyi_path, fileio.MODE.W) + if not pf.closed: + pf.write(pyi_buf, pyi_pos) + pf.close() + stdlib.free(pyi_path) + stdlib.free(pyi_buf) + tr: HandlesTranslator.Translator | t.CPtr = mb.alloc(HandlesTranslator.Translator.__sizeof__()) + tr.__before_init__() + tr.__init__() + tr.ModuleSha1 = sha1_val + tr.CurrentPackage = current_package + tr._declare_only = declare_only + # P2: 复用全局 gen 单例(App/main.vp 创建;HandlesType 等旧模块函数经 + # 延迟 import 委托到 gen 方法)。单例未注册时兜底创建(防御直接调用路径)。 + gen: GenGenerator.Generator | t.CPtr = GenGenerator._g_gen + if gen is None: + gen = mb.alloc(GenGenerator.Generator.__sizeof__()) + if gen is None: + VLogger.error("Generator alloc failed", "GEN") + return None + gen.__before_init__() + gen.__init__(mb) + GenGenerator._g_gen = gen + # P2-P5: 注入各 Handles 模块级单例(委托函数经本地 _g_gen 访问, + # 避免函数体 import 包模块与类/模块名歧义) + GenApi._g_gen = gen + # P6: 注入语句/赋值/变量/导入/翻译驱动模块的单例 + # 设置当前文件名(供报错使用) + GenApi.set_current_file_type(file_path) + # 同步到 HandlesImports(import 时 SHA1 检查报错需要当前文件名,循环依赖无法直接读 HandlesType) + GenApi.set_current_file_imports(file_path) + # 清空调用栈(每个文件翻译开始前重置) + GenApi.clear_trace() + # 模块切换:清空 CDefine 常量表,确保每个模块的 CDefine 常量正确隔离 + GenApi.clear_cdefine_constants() + # 模块切换:清空 CTypedef 表,确保每个模块的 CTypedef 正确隔离 + GenApi.clear_ctypedefs() + # 命名空间隔离:includes 文件宽松模式(全部可见),用户文件严格模式(仅本地+import) + strict_mode: int = 1 + if string.strstr(file_path, "includes") is not None: + strict_mode = 0 + GenApi.reset_visible_structs(mb, strict_mode) + # 提取 docstring(预注册阶段所有 App/includes 文件都被翻译, + # 保证跨模块 __doc__ 在正式翻译前已登记;查重幂等) + # 注意:必须在 tr.translate 之前扫描——translate 期间 mb 池大量分配 + # IR 节点,AST 节点所在池块可能被复用覆盖(ASan 下遍历 tree 读 + # 0xffffffffffffffff 崩溃),docstring 提取与翻译状态无关,提前安全。 + if gen is not None: + gen.ExprGenCls.extract_module_docstrings(tree, sha1_val) + ret: int = tr.translate(tree) + if ret != 0: + fb_tf: str = VLogger.fmt_buf() + if fb_tf is not None: + viperlib.snprintf(fb_tf, 1024, "文件翻译失败: %s", file_path) + VLogger.error(fb_tf, "Translate") + return None + return tr + + +class BuildResult: + Success: t.CInt + OutputPath: str + ErrorMsg: str + + def __new__(self) -> t.CPtr: + return t.CPtr(_mbuddy.alloc(BuildResult.__sizeof__())) + + def __init__(self): + self.Success = 0 + self.OutputPath = None + self.ErrorMsg = None + + +def ensure_dir(path: str) -> int: + """递归创建目录(类似 mkdir -p),目录已存在视为成功 + + Args: + path: 目录路径(支持 / 或 \\ 分隔符) + + Returns: + 0 成功(包括目录已存在),非 0 失败 + """ + if path is None: + return 1 + + path_len: t.CSizeT = len(path) + if path_len == 0: + return 0 + + # 复制路径到可写缓冲区(逐级截断用) + buf: bytes = _mbuddy.alloc(path_len + 1) + if buf is None: + return 1 + string.strcpy(buf, path) + + # 遇到分隔符时临时截断,创建每一层目录 + # CreateDirectoryA 在目录已存在时返回 0(失败),忽略即可 + plen: int = path_len + for i in range(plen): + ch: int = buf[i] + if ch == 47 or ch == 92: # '/' = 47, '\\' = 92 + saved: int = ch + buf[i] = '\0' + w32.win32file.CreateDirectoryA(buf, None) + buf[i] = saved + + # 创建最终目录 + w32.win32file.CreateDirectoryA(buf, None) + return 0 + + +# ============================================================ +# build_sliced_path - 构建切片路径并确保目录存在 +# +# 根据 Config.Sha1SliceLevel 将文件分散到 SHA1 前缀子目录: +# level=0 → {base_dir}/{sha1}.{ext} +# level=1 → {base_dir}/b7/{sha1}.{ext} +# level=2 → {base_dir}/b7/90/{sha1}.{ext} +# +# 自动调用 ensure_dir 创建子目录。 +# +# Args: +# base_dir: 基础目录(如 temp_dir) +# sha1: SHA1 字符串 +# ext: 文件扩展名(如 "stub.ll") +# +# Returns: +# 完整文件路径(mbuddy 分配),None 失败 +# ============================================================ +def build_sliced_path(base_dir: str, sha1: str, ext: str) -> str: + """构建切片路径并确保目录存在""" + if base_dir is None or sha1 is None or ext is None: + return None + + subdir: str = Config.slice_subdir(sha1, Config.Sha1SliceLevel) + base_len: t.CSizeT = len(base_dir) + sha1_len: t.CSizeT = len(sha1) + ext_len: t.CSizeT = len(ext) + + if subdir is not None: + sub_len: t.CSizeT = len(subdir) + # ensure_dir({base_dir}/{subdir}) + dir_path: str = _mbuddy.alloc(base_len + sub_len + 2) + if dir_path is not None: + viperlib.snprintf(dir_path, base_len + sub_len + 2, "%s/%s", base_dir, subdir) + ensure_dir(dir_path) + # 文件路径: {base_dir}/{subdir}/{sha1}.{ext} + path_len: t.CSizeT = base_len + sub_len + sha1_len + ext_len + 4 + path: str = _mbuddy.alloc(path_len) + if path is None: return None + viperlib.snprintf(path, path_len, "%s/%s/%s.%s", base_dir, subdir, sha1, ext) + return path + else: + # 无切片: {base_dir}/{sha1}.{ext} + path_len = base_len + sha1_len + ext_len + 3 + path = _mbuddy.alloc(path_len) + if path is None: return None + viperlib.snprintf(path, path_len, "%s/%s.%s", base_dir, sha1, ext) + return path + + +def write_ir_to_file(ir_buf: bytes, ir_len: t.CSizeT, output_dir: str, module_name: str) -> int: + """将 IR 缓冲区写入 .ll 文件 + + Args: + ir_buf: IR 文本缓冲区 + ir_len: IR 文本长度 + output_dir: 输出目录(temp 或 output) + module_name: 模块名(SHA1) + + Returns: + 0 成功,非 0 失败 + """ + if ir_buf is None or output_dir is None or module_name is None: return 1 + + # 构造切片路径: output_dir/{sha1前缀}/{module_name}.ll + path: str = build_sliced_path(output_dir, module_name, "ll") + if path is None: return 1 + + # 打开文件写入 + f: fileio.File | t.CPtr = fileio.File(path, fileio.MODE.W) + if f.closed: return 1 + + written: t.CInt64T = f.write(ir_buf, ir_len) + f.close() + if written < 0: return 1 + return 0 + + +def compile_ll_to_obj(ir_path: str, output_dir: str, module_name: str, cc_cmd: str, cc_flags: str) -> int: + """调用 llc 将 .ll 编译为 .obj + + Args: + ir_path: .ll 文件路径 + output_dir: 输出目录 + module_name: 模块名(SHA1,用于生成 .obj 文件名) + cc_cmd: 编译器命令(如 "llc") + cc_flags: 编译器参数(如 "-filetype=obj -relocation-model=pic") + + Returns: + 0 成功,非 0 失败 + """ + if ir_path is None or cc_cmd is None or output_dir is None or module_name is None: + return 1 + + # 构造切片 .obj 路径: output_dir/{sha1前缀}/{module_name}.obj + obj_path: str = build_sliced_path(output_dir, module_name, "obj") + if obj_path is None: return 1 + + # ASan 模式(_asan_mode=1):先 opt -passes=asan 插桩再 llc。 + # -asan-globals=false 关闭全局插桩:TPV 对全局变量(如各模块 _g_gen) + # 用直接地址寻址,ASan 全局 redzone 重定位后引用错位会读到垃圾指针。 + compile_input: str = ir_path + if _asan_mode != 0: + asan_path: str = build_sliced_path(output_dir, module_name, "asan.ll") + if asan_path is None: + return 1 + opt_cmd_len: t.CSizeT = len(asan_path) + len(ir_path) + 192 + opt_cmd: bytes = _mbuddy.alloc(opt_cmd_len) + if opt_cmd is None: + return 1 + viperlib.snprintf(opt_cmd, opt_cmd_len, + "opt -passes=forceattrs,asan -force-attribute=sanitize_address -asan-globals=false -o %s %s", + asan_path, ir_path) + opt_ret: int = stdlib.system(opt_cmd) + if opt_ret != 0: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "opt ASan 插桩失败 (module=%s)", module_name) + VLogger.error(fb, "ASAN") + return 1 + compile_input = asan_path + + # 构造命令: llc -filetype=obj -o {obj_path} ir_path + cmd_len: t.CSizeT = len(cc_cmd) + len(cc_flags) + len(obj_path) + len(compile_input) + 64 + cmd: bytes = _mbuddy.alloc(cmd_len) + if cmd is None: + return 1 + viperlib.snprintf(cmd, cmd_len, "%s %s -o %s %s", cc_cmd, cc_flags, obj_path, compile_input) + + # 用 stdlib.system() 直接在控制台运行,输出直接显示 + # 避免 subprocess 管道捕获丢失输出 + sys_ret: int = stdlib.system(cmd) + if sys_ret != 0: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "编译失败 (module=%s, cmd=%s)", module_name, cmd) + VLogger.error(fb, "LLC") + return 1 + return 0 + + +# ============================================================ +# llc 并行编译(线程异步,Phase B 多模块同时跑 llc) +# +# 线程安全约束: +# - LlcTask 及命令串一律 stdlib.malloc:主池 mb 会被 reset_to(mark2) +# 回收,线程运行期间字符串悬空 → 概率崩溃 +# - worker 只调 stdlib.system(),不做任何池分配(MemBuddy 分配非线程安全) +# - 依赖 CRT system() 的多线程安全性(ThreadingTest 已验证) +# ============================================================ +# llc 并行最大线程数(参考 TPC Phase2Translator n_workers=os.cpu_count(),本机 16 核) +LLC_MAX_THREADS: t.CDefine = 16 + + +class LlcTask: + """llc 异步任务:命令串(stdlib.malloc)+ 模块 SHA1 + 结果""" + OptCmd: bytes # ASan 插桩命令(非 ASan 为 None) + LlcCmd: bytes # llc 命令 + ModuleSha1: bytes # 模块 SHA1(报错用) + Result: int # worker 写:0 成功,非 0 失败 + + +def init_llc_task(task: LlcTask | t.CPtr, ir_path: str, output_dir: str, + module_name: str, cc_cmd: str, cc_flags: str) -> int: + """填充 llc 任务(全部 stdlib.malloc,线程运行期不被回收),0 成功""" + if task is None or ir_path is None or output_dir is None or module_name is None: + return 1 + string.memset(task, 0, LlcTask.__sizeof__()) + task.Result = -1 + obj_path: str = build_sliced_path(output_dir, module_name, "obj") + if obj_path is None: + return 1 + # 模块 SHA1 + sl: t.CSizeT = len(module_name) + task.ModuleSha1 = stdlib.malloc(sl + 1) + if task.ModuleSha1 is None: + return 1 + string.strcpy(task.ModuleSha1, module_name) + # llc 命令 + cmd_len: t.CSizeT = len(cc_cmd) + len(cc_flags) \ + + len(obj_path) + len(ir_path) + 64 + task.LlcCmd = stdlib.malloc(cmd_len) + if task.LlcCmd is None: + return 1 + viperlib.snprintf(task.LlcCmd, cmd_len, "%s %s -o %s %s", + cc_cmd, cc_flags, obj_path, ir_path) + # ASan 模式:opt 插桩命令(worker 先跑,失败即置 Result) + if _asan_mode != 0: + asan_path: str = build_sliced_path(output_dir, module_name, "asan.ll") + if asan_path is None: + return 1 + opt_len: t.CSizeT = len(asan_path) + len(ir_path) + 192 + task.OptCmd = stdlib.malloc(opt_len) + if task.OptCmd is None: + return 1 + viperlib.snprintf(task.OptCmd, opt_len, + "opt -passes=forceattrs,asan -force-attribute=sanitize_address" + " -asan-globals=false -o %s %s", + asan_path, ir_path) + return 0 + + +def free_llc_task(task: LlcTask | t.CPtr): + """释放任务的命令串;记录本身是任务数组的连续槽(非独立 malloc), + 由调用方对数组整体 stdlib.free(此前对槽 free 导致 double-free)""" + if task is None: + return + if task.OptCmd is not None: + stdlib.free(task.OptCmd) + task.OptCmd = None + if task.LlcCmd is not None: + stdlib.free(task.LlcCmd) + task.LlcCmd = None + if task.ModuleSha1 is not None: + stdlib.free(task.ModuleSha1) + task.ModuleSha1 = None + + +def _run_cmd_wait(cmd: str) -> int: + """CreateProcessA 同步执行命令并等待退出,返回退出码。 + + 替代 stdlib.system:Windows asan 环境下 cmd /c 经 CreateProcess 受 + RTL allocator hook 干扰可能挂起(LLVM issue #111166 同类,ClassArrayTest + llc 固定卡死根因);CreateProcessA 直接执行目标程序并继承父进程控制台 + (stdout/stderr 直接显示,同 system 语义)。全 stdlib.malloc/栈分配, + worker 线程安全。 + """ + if cmd is None: + return -1 + cl_len: t.CSizeT = len(cmd) + cmd_line: bytes = stdlib.malloc(cl_len + 1) + if cmd_line is None: + return -1 + string.strcpy(cmd_line, cmd) + sa: w32.win32base.SECURITY_ATTRIBUTES = w32.win32base.SECURITY_ATTRIBUTES() + si: win32process.STARTUPINFOA = win32process.STARTUPINFOA() + pi: win32process.PROCESS_INFORMATION = win32process.PROCESS_INFORMATION() + # T() 构造仅 alloca 不 memset:STARTUPINFOA 未设字段(dwFlags 等)全为 + # 栈垃圾,多线程并发调用时垃圾随机 → dwFlags 垃圾位让 CreateProcessA + # 用垃圾句柄作子进程 stdio → 子进程行为不定/父进程线程崩溃(ClassArrayTest + # e5fb worker 崩溃、edd8 正常的原因)。si/sa/pi 全部显式清零。 + string.memset(t.CPtr(c.Addr(si)), 0, win32process.STARTUPINFOA.__sizeof__()) + string.memset(t.CPtr(c.Addr(sa)), 0, w32.win32base.SECURITY_ATTRIBUTES.__sizeof__()) + string.memset(t.CPtr(c.Addr(pi)), 0, win32process.PROCESS_INFORMATION.__sizeof__()) + sa.nLength = w32.win32base.SECURITY_ATTRIBUTES.__sizeof__() + sa.lpSecurityDescriptor = t.CPtr(0) + sa.bInheritHandle = 1 + si.cb = win32process.STARTUPINFOA.__sizeof__() + # create_flags=0:子进程继承父控制台(输出直接显示,同 system 语义) + ok: int = win32process.CreateProcessA( + t.CPtr(0), cmd_line, t.CPtr(0), t.CPtr(0), 1, 0, + t.CPtr(0), t.CPtr(0), t.CPtr(c.Addr(si)), t.CPtr(c.Addr(pi))) + stdlib.free(cmd_line) + if ok == 0: + return -1 + win32sync.WaitForSingleObject(pi.hProcess, w32.win32base.INFINITE) + exit_code: t.CUInt32T = 0 + win32process.GetExitCodeProcess(pi.hProcess, t.CPtr(c.Addr(exit_code))) + w32.win32base.CloseHandle(pi.hProcess) + w32.win32base.CloseHandle(pi.hThread) + return t.CInt(exit_code) + + +def _llc_task_worker(arg: t.CPtr) -> t.CPtr: + """llc 线程入口:只调 stdlib.system(),不做任何分配(线程安全) + Result 仅在命令链执行完后写入(初始 -1;join 超时保持 -1 → 报失败)""" + task: LlcTask | t.CPtr = (LlcTask | t.CPtr)(arg) + if task is None: + return t.CPtr(0) + if task.OptCmd is not None: + opt_rc: int = _run_cmd_wait(task.OptCmd) + if opt_rc != 0: + task.Result = 1 + return t.CPtr(0) + llc_rc: int = _run_cmd_wait(task.LlcCmd) + if llc_rc != 0: + task.Result = 1 + else: + task.Result = 0 + return t.CPtr(0) + + +def run_llc_parallel(tasks: bytes, task_count: int, max_threads: int) -> int: + """并行执行 llc:分批 max_threads 个线程,全部 join 后检查结果 + + tasks: LlcTask 记录连续数组(stdlib.malloc),每个记录由 init_llc_task 填充。 + Returns: 0 全部成功;非 0 有失败(已打印失败模块与命令) + """ + if tasks is None or task_count <= 0: + return 0 + if max_threads <= 0: + max_threads = 1 + # 线程句柄数组:list[str](str=bytes=i8*,elem_size=8 显式)存句柄值。 + # 此前 list[t.CPtr] 特化修复后 append 仍崩(pool 有效、elem=8 下读零页, + # list[ptr] append 的 store 与 t.CPtr 参数类型生成待查);list[str] 全库 + # 验证稳定(append/get 8 字节指针)。start() 后立即取 handle 存入, + # join/close 直接对句柄操作,不依赖 Thread 对象存续。 + handles: list[str] | t.CPtr = list[str](_mbuddy, 8) + if handles is None: + VLogger.error("run_llc_parallel: 线程句柄数组分配失败", "PhaseB") + return 1 + slot_size: t.CSizeT = LlcTask.__sizeof__() + ret: int = 0 + # 分批执行:batch_start 按 max_threads 步进(每批 spawn+join+close 一批句柄)。 + for batch_start in range(0, task_count, max_threads): + batch_n: int = max_threads + if batch_start + batch_n > task_count: + batch_n = task_count - batch_start + # 本批 spawn + for j in range(batch_n): + tsk: LlcTask | t.CPtr = (LlcTask | t.CPtr)(t.CVoid( + t.CUInt64T(tasks) + t.CSizeT(batch_start + j) * slot_size, t.CPtr)) + th: vthreading.Thread | t.CPtr = vthreading.Thread(_llc_task_worker, t.CPtr(tsk)) + th.start() + # start() 后立即取出句柄(Thread 对象栈地址可能被后续构造复用, + # join 时再读 self.handle 可能已被 close 清空/覆盖) + handles.append(t.CPtr(th.handle)) + for j in range(batch_n): + h_j: t.CPtr = t.CPtr(handles.get(batch_start + j)) + wr: t.CUInt32T = win32sync.WaitForSingleObject(h_j, 600000) + if wr != 0: + VLogger.error("llc 线程 join 超时/失败(600 秒未完成)", "PhaseB") + w32.win32base.CloseHandle(h_j) + # 本批结果检查 + for j in range(batch_n): + tsk2: LlcTask | t.CPtr = (LlcTask | t.CPtr)(t.CVoid( + t.CUInt64T(tasks) + t.CSizeT(batch_start + j) * slot_size, t.CPtr)) + if tsk2 is not None and tsk2.Result != 0: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "llc 编译失败: %s (cmd=%s)", + (tsk2.ModuleSha1 if tsk2.ModuleSha1 is not None else "?"), + (tsk2.LlcCmd if tsk2.LlcCmd is not None else "?")) + VLogger.error(fb, "LLC") + ret = 1 + return ret + + +def _CollectObjFilesImpl(base_dir: str, bd_len: t.CSizeT, + out_buf: bytes, out_pos: t.CSizeT, out_size: t.CSizeT) -> t.CSizeT: + """递归扫描 base_dir,收集 .obj 文件路径到 out_buf,返回新的 out_pos + + 支持切片子目录(如 dir/43/{sha1}.obj)。 + """ + find_data: w32.win32file.WIN32_FIND_DATAA | t.CPtr = _mbuddy.alloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__()) + if find_data is None: + VLogger.warning("_CollectObjFilesImpl 分配 find_data 失败,少收集 .obj", "collect") + return out_pos + string.memset(find_data, 0, w32.win32file.WIN32_FIND_DATAA.__sizeof__()) + + pattern: bytes = _mbuddy.alloc(bd_len + 8) + if pattern is None: + VLogger.warning("_CollectObjFilesImpl 分配 pattern 失败,少收集 .obj", "collect") + return out_pos + viperlib.snprintf(pattern, bd_len + 8, "%s/*", base_dir) + + handle: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(pattern, find_data) + _mbuddy.free(pattern) + if handle == w32.win32base.INVALID_HANDLE_VALUE: + VLogger.warning("_CollectObjFilesImpl 无法打开目录,少收集 .obj", "collect") + return out_pos + + while True: + fname: str = find_data.cFileName + if fname is not None: + fname_len: t.CSizeT = len(fname) + if fname_len > 0: + # 跳过 . 和 .. + is_dot: int = 0 + if fname_len == 1 and fname[0] == '.': + is_dot = 1 + elif fname_len == 2 and fname[0] == '.' and fname[1] == '.': + is_dot = 1 + if is_dot == 0: + attrs: ULONG = find_data.dwFileAttributes + is_dir: int = 0 + if (attrs & w32.win32file.FILE_ATTRIBUTE_DIRECTORY) != 0: + is_dir = 1 + if is_dir != 0: + # 递归扫描子目录 + sub_dir: bytes = _mbuddy.alloc(bd_len + fname_len + 2) + if sub_dir is not None: + viperlib.snprintf(sub_dir, bd_len + fname_len + 2, "%s/%s", base_dir, fname) + sub_len: t.CSizeT = len(sub_dir) + out_pos = _CollectObjFilesImpl(sub_dir, sub_len, out_buf, out_pos, out_size) + _mbuddy.free(sub_dir) + else: + # 检查是否是 .obj 文件 + if fname_len > 4 and fname[fname_len - 4] == '.' \ + and fname[fname_len - 3] == 'o' and fname[fname_len - 2] == 'b' \ + and fname[fname_len - 1] == 'j': + need: t.CSizeT = bd_len + 1 + fname_len + 2 + if out_pos + need >= out_size: + break + if out_pos > 0: + out_buf[out_pos] = ' ' + out_pos += 1 + viperlib.snprintf(out_buf + out_pos, need, "%s/%s", base_dir, fname) + out_pos += bd_len + 1 + fname_len + + if w32.win32file.FindNextFileA(handle, find_data) == 0: + break + + w32.win32file.FindClose(handle) + return out_pos + + +def collect_obj_files(includes_binary_dir: str, out_buf: bytes, out_size: t.CSizeT) -> t.CSizeT: + """递归扫描 includes_binary_dir 目录,收集所有 .obj 文件路径到 out_buf + + 支持切片子目录(如 includes_binary_dir/43/{sha1}.obj)。 + + Args: + includes_binary_dir: includes.binary 目录路径 + out_buf: 输出缓冲区(用于存放空格分隔的 .obj 文件路径) + out_size: 输出缓冲区大小 + + Returns: + 写入的字节数(不含 null 终止符),0 表示无文件或错误 + """ + if includes_binary_dir is None or out_buf is None or out_size == 0: + return 0 + + out_buf[0] = '\0' + dir_len: t.CSizeT = len(includes_binary_dir) + out_pos: t.CSizeT = _CollectObjFilesImpl(includes_binary_dir, dir_len, out_buf, 0, out_size) + out_buf[out_pos] = '\0' + return out_pos + + +def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_flags: str, linker_output: str, + includes_binary_dir: str) -> int: + """调用 clang++ 链接 .obj 为 .exe + + Args: + output_dir: 输出目录(包含 .obj 文件) + module_name: 模块名(SHA1) + linker_cmd: 链接器命令(如 "clang++") + linker_flags: 链接器参数 + linker_output: 输出文件名(如 "test.exe") + includes_binary_dir: includes.binary 目录路径(链接时附加预编译 .obj) + + Returns: + 0 成功,非 0 失败 + """ + if output_dir is None or linker_cmd is None or module_name is None: + return 1 + + # 构造切片 .obj 路径: output_dir/{sha1前缀}/{module_name}.obj + obj_path: str = build_sliced_path(output_dir, module_name, "obj") + if obj_path is None: + return 1 + + # 收集 includes.binary 的 .obj 文件路径 + EXTRA_BUF_SIZE: t.CSizeT = 32768 + extra_objs: bytes = _mbuddy.alloc(EXTRA_BUF_SIZE) + if extra_objs is None: + return 1 + extra_len: t.CSizeT = 0 + if includes_binary_dir is not None: + extra_len = collect_obj_files(includes_binary_dir, extra_objs, EXTRA_BUF_SIZE) + if extra_len > 0: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "附加 %d 字节的 includes.binary .obj 文件", extra_len) + VLogger.info(fb, "link") + else: + fb = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "includes.binary 无 .obj 文件: %s", includes_binary_dir) + VLogger.warning(fb, "link") + + # 构造命令: clang++ {obj_path} extra_objs -o {output_dir}/{linker_output} linker_flags + # 注意: .obj 文件必须在 -l 库标志之前,否则链接器无法解析符号依赖 + # ASan 模式:mingw64 clang 的 -fsanitize=address 在 mingw64/lib 下找不到 + # asan 运行库(实际在 clang64),改为显式链接 clang64 的 libclang_rt + # (DLL 版,运行时需 D:/msys64/clang64/bin 在 PATH) + use_flags: str = linker_flags + if _asan_mode != 0: + fl_len: t.CSizeT = len(linker_flags) + 256 + use_flags = _mbuddy.alloc(fl_len) + if use_flags is None: + return 1 + viperlib.snprintf(use_flags, fl_len, + "%s -L D:/msys64/clang64/lib/clang/22/lib/windows -l:libclang_rt.asan_dynamic-x86_64.dll.a -l:libclang_rt.asan_dynamic_runtime_thunk-x86_64.a", + linker_flags) + cmd_len: t.CSizeT = len(linker_cmd) + len(obj_path) + len(use_flags) + len(output_dir) + len(linker_output) + extra_len + 128 + cmd: bytes = _mbuddy.alloc(cmd_len) + if cmd is None: + return 1 + if extra_len > 0: + viperlib.snprintf(cmd, cmd_len, "%s %s %s -o %s/%s %s", + linker_cmd, obj_path, extra_objs, + output_dir, linker_output, use_flags) + else: + viperlib.snprintf(cmd, cmd_len, "%s %s -o %s/%s %s", + linker_cmd, obj_path, output_dir, linker_output, + use_flags) + + result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True) + if result is None: + VLogger.error("subprocess.run 返回 None", "link") + return 1 + if result.returncode != 0: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "链接失败,返回码: %d", result.returncode) + VLogger.error(fb, "link") + fb = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "命令: %s", cmd) + VLogger.error(fb, "link") + # 显示链接器错误输出 + # 注意: subprocess 在 Windows 下将 stderr 合并到 stdout,result.stderr 总是 None + if result.stdout is not None: + VLogger.error(result.stdout, "link") + else: + VLogger.error("无输出捕获", "link") + if result.stderr is not None: + VLogger.error(result.stderr, "link") + return 1 + return 0 + + +def compile_module_to_obj(ir_buf: bytes, ir_len: t.CSizeT, + temp_dir: str, output_dir: str, module_name: str, + cc_cmd: str, cc_flags: str) -> int: + """编译 IR 到 .obj(不链接) + + Args: + ir_buf: LLVM IR 文本缓冲区 + ir_len: IR 文本长度 + temp_dir: 临时目录 + output_dir: 输出目录 + module_name: 模块名(SHA1) + cc_cmd: 编译器命令 + cc_flags: 编译器参数 + + Returns: + 0 成功,非 0 失败 + """ + if ir_buf is None or temp_dir is None or output_dir is None or module_name is None: + return 1 + + # Step 1: 写 .ll 文件 + ret: int = write_ir_to_file(ir_buf, ir_len, temp_dir, module_name) + if ret != 0: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "写 .ll 失败: %s", module_name) + VLogger.error(fb, "compile") + return 1 + + # Step 2: 构造切片 .ll 路径并编译 → .obj + ir_path: str = build_sliced_path(temp_dir, module_name, "ll") + if ir_path is None: + return 1 + + ret = compile_ll_to_obj(ir_path, output_dir, module_name, cc_cmd, cc_flags) + if ret != 0: + fb = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "llc 编译失败: %s", module_name) + VLogger.error(fb, "compile") + return 1 + return 0 + + +def link_objs_to_exe(obj_paths: str, obj_paths_len: t.CSizeT, + linker_cmd: str, linker_flags: str, linker_output: str, + includes_binary_dir: str) -> int: + """链接多个 .obj 文件为 .exe + + Args: + obj_paths: 空格分隔的 .obj 文件完整路径字符串 + obj_paths_len: obj_paths 长度 + linker_cmd: 链接器命令(如 "clang++") + linker_flags: 链接器参数 + linker_output: 输出文件完整路径 + includes_binary_dir: includes.binary 目录路径(链接时附加预编译 .obj) + + Returns: + 0 成功,非 0 失败 + """ + if obj_paths is None or obj_paths_len == 0 or linker_cmd is None: + return 1 + + # 收集 includes.binary 的 .obj 文件路径 + EXTRA_BUF_SIZE: t.CSizeT = 32768 + extra_objs: bytes = _mbuddy.alloc(EXTRA_BUF_SIZE) + if extra_objs is None: + return 1 + extra_len: t.CSizeT = 0 + if includes_binary_dir is not None: + extra_len = collect_obj_files(includes_binary_dir, extra_objs, EXTRA_BUF_SIZE) + + # 构造命令: clang++ obj_paths extra_objs -o linker_output linker_flags + # ASan 模式:显式链接 clang64 的 libclang_rt(同 link_obj_to_exe) + use_flags: str = linker_flags + if _asan_mode != 0: + fl_len: t.CSizeT = len(linker_flags) + 256 + use_flags = _mbuddy.alloc(fl_len) + if use_flags is None: + return 1 + viperlib.snprintf(use_flags, fl_len, + "%s -L D:/msys64/clang64/lib/clang/22/lib/windows -l:libclang_rt.asan_dynamic-x86_64.dll.a -l:libclang_rt.asan_dynamic_runtime_thunk-x86_64.a", + linker_flags) + cmd_len: t.CSizeT = len(linker_cmd) + obj_paths_len + len(use_flags) + len(linker_output) + extra_len + 128 + cmd: bytes = _mbuddy.alloc(cmd_len) + if cmd is None: + return 1 + if extra_len > 0: + viperlib.snprintf(cmd, cmd_len, "%s %s %s -o %s %s", + linker_cmd, obj_paths, extra_objs, + linker_output, use_flags) + else: + viperlib.snprintf(cmd, cmd_len, "%s %s -o %s %s", + linker_cmd, obj_paths, linker_output, use_flags) + + # 用 subprocess.run 捕获 clang++ 的 stdout/stderr 输出 + # 之前用 stdlib.system() 无法捕获具体错误(undefined reference 等), + # 导致 1.txt 中只看到"链接失败,返回码: 1"而看不到未解析符号 + result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True) + if result is None: + VLogger.error("subprocess.run 返回 None", "link") + return 1 + if result.returncode != 0: + # 先用 stdio.printf 直接输出 clang++ 的完整错误输出(含 undefined reference) + # 必须在 VLogger.error 之前输出,因为 VLogger.error 会调用 sys.exit(1) 终止进程 + if result.stdout is not None: + stdio.printf("=== clang++ 链接错误输出 ===\n%s\n", result.stdout) + if result.stderr is not None: + stdio.printf("=== clang++ stderr ===\n%s\n", result.stderr) + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "链接失败,返回码: %d, 命令: %s", result.returncode, cmd) + VLogger.error(fb, "link") + return 1 + return 0 + + +def run_pipeline(ir_buf: bytes, ir_len: t.CSizeT, + temp_dir: str, output_dir: str, module_name: str, + cc_cmd: str, cc_flags: str, + linker_cmd: str, linker_flags: str, linker_output: str, + includes_binary_dir: str) -> BuildResult | t.CPtr: + """执行完整编译管线 + + Args: + ir_buf: LLVM IR 文本缓冲区 + ir_len: IR 文本长度 + temp_dir: 临时目录 + output_dir: 输出目录 + module_name: 模块名 + cc_cmd: 编译器命令 + cc_flags: 编译器参数 + linker_cmd: 链接器命令 + linker_flags: 链接器参数 + linker_output: 输出文件名 + includes_binary_dir: includes.binary 目录路径(链接时附加预编译 .obj) + + Returns: + BuildResult 对象 + """ + result: BuildResult | t.CPtr = BuildResult() + if result is None: + return None + + # Step 0: 确保 temp/output 目录存在(自动创建,避免写文件失败) + ensure_dir(temp_dir) + ensure_dir(output_dir) + + # Step 1: 写 .ll 文件 + ret: int = write_ir_to_file(ir_buf, ir_len, temp_dir, module_name) + if ret != 0: + result.Success = 0 + result.ErrorMsg = "写 .ll 文件失败" + return result + + # Step 2: llc 编译 .ll → .obj + # 构造切片 .ll 文件路径 + ir_path: str = build_sliced_path(temp_dir, module_name, "ll") + if ir_path is None: + result.Success = 0 + result.ErrorMsg = "内存分配失败" + return result + + ret = compile_ll_to_obj(ir_path, output_dir, module_name, cc_cmd, cc_flags) + if ret != 0: + result.Success = 0 + result.ErrorMsg = "llc 编译失败" + return result + + # Step 3: clang++ 链接 .obj → .exe(附加 includes.binary 预编译 .obj) + ret = link_obj_to_exe(output_dir, module_name, linker_cmd, linker_flags, linker_output, + includes_binary_dir) + if ret != 0: + result.Success = 0 + result.ErrorMsg = "链接失败" + return result + + result.Success = 1 return result \ No newline at end of file diff --git a/App/lib/core/Gen/AssignGenMixin.vp b/App/lib/core/Gen/AssignGenMixin.vp index 58a78a1..2d04f95 100644 --- a/App/lib/core/Gen/AssignGenMixin.vp +++ b/App/lib/core/Gen/AssignGenMixin.vp @@ -1,2233 +1,2221 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.ExprCallBase as ExprCallBase -import lib.core.Handles.ExprCallCall as ExprCallCall -import lib.core.Handles.ExprCallCtor as ExprCallCtor -import lib.core.StubMergerStore as StubMergerStore - - -# ============================================================ -# AssignGenMixin - 赋值翻译 Mixin(P6 方法化) -# -# 从 HandlesAssign/HandlesAnnAssign/HandlesAugAssign 迁移: -# 模块级无状态函数(trans/pool 首参)→ 类方法;全局状态 -# (HandlesAnnAssign._g_recover_found)→ 本类字段 RecoverFound。 -# -# 迁移原则(与 P1-P5 一致,行为零变化): -# 1. 方法保留原函数签名(含 trans/pool 首参),仅函数体内的 -# 本模块函数调用改为 self.xxx(...) -# 2. 外部模块调用(HandlesType.xxx/HandlesExpr.xxx 等)保留模块前缀 -# 3. 原 Handles 模块函数保留为"委托":本地模块级单例 _g_gen -# (BuildPipeline/main 注入)cast 成 Generator 类型 -# -# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 -# ============================================================ - - -@t.NoVTable -class AssignGenMixin: - """赋值翻译 Mixin(P6 方法化)""" - - # --- 原 HandlesAnnAssign._g_recover_found 模块级全局(迁移为实例字段) --- - RecoverFound: int - - # ============================================================ - # is_cdefine_annotation - 检测注解是否为 t.CDefine(模块级函数) - # - # 支持两种形式: - # 1. Attribute(Name('t'), 'CDefine') - # 2. BinOp(... | Attribute(Name('t'), 'CDefine'))(联合注解) - # ============================================================ - def is_cdefine_annotation(self, annot: ast.AST | t.CPtr) -> int: - """检测注解是否为 t.CDefine,返回 1 表示是,0 表示否""" - if annot is None: - return 0 - k: int = annot.kind() - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot) - if at.attr is not None and string.strcmp(at.attr, "CDefine") == 0: - return 1 - return 0 - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot) - if self.is_cdefine_annotation(bop.left) != 0: - return 1 - if self.is_cdefine_annotation(bop.right) != 0: - return 1 - return 0 - - # ============================================================ - # extract_cdefine_int_value - 从 AnnAssign.value 提取整数常量(模块级函数) - # - # 支持的表达式形式: - # 1. Constant(INT) — 如 0x0002, 42 - # 2. BinOp(BitOr/BitAnd) — 如 FOREGROUND_RED | FOREGROUND_GREEN - # 3. Name — 引用已注册的 CDefine 常量 - # 4. Call — 如 t.CUnsignedLong(-11) → 取第一个参数 - # 5. UnaryOp(USub/UAdd/Invert) — 如 -11 - # ============================================================ - def extract_cdefine_int_value(self, val_node: ast.AST | t.CPtr) -> t.CInt64T: - """从值节点提取整数常量(支持 Constant/BinOp/Name/Call/UnaryOp) - - 64 位返回:大整数 CDefine(如 sys.maxsize=9223372036854775807) - 必须全精度提取,否则 int(32 位) 截断成 -1(SysLibTest maxsize FAIL 根因)。 - """ - if val_node is None: - return 0 - k: int = val_node.kind() - - # Case 1: Constant(INT) — 如 0x0002 - if k == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(val_node) - # True/False 布尔常量 → 1/0(对齐 TPC:bool 在 CDefine 语境按整数处理, - # 如 SHADOW_ENABLED: t.CDefine = False) - if cn.const_kind == ast.CONST_BOOL: - return 1 if cn.int_val != 0 else 0 - if cn.const_kind != ast.CONST_INT: - # 非 INT 常量:直接报错终止(fail-fast) - HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError") - return cn.int_val - - # Case 2: BinOp — 如 FOREGROUND_RED | FOREGROUND_GREEN、(1 << ZDEFLATE_WINDOW_BITS) - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(val_node) - left_val: t.CInt64T = self.extract_cdefine_int_value(bop.left) - right_val: t.CInt64T = self.extract_cdefine_int_value(bop.right) - if bop.op == ast.OpKind.BitOr: - return left_val | right_val - if bop.op == ast.OpKind.BitAnd: - return left_val & right_val - if bop.op == ast.OpKind.BitXor: - return left_val ^ right_val - if bop.op == ast.OpKind.LShift: - return left_val << right_val - if bop.op == ast.OpKind.RShift: - return left_val >> right_val - if bop.op == ast.OpKind.Add: - return left_val + right_val - if bop.op == ast.OpKind.Sub: - return left_val - right_val - if bop.op == ast.OpKind.Mult: - return left_val * right_val - if bop.op == ast.OpKind.Div: - # 整数常量除法:与 FloorDiv 一致(对齐 TPC ConstEvaluator L354-355) - return left_val // right_val - if bop.op == ast.OpKind.FloorDiv: - return left_val // right_val - if bop.op == ast.OpKind.Mod: - return left_val % right_val - # 未知 BinOp 运算符:直接报错终止(fail-fast) - HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError") - - # Case 3: Name — 引用已注册的 CDefine 常量,或 True/False 布尔字面量 - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node) - if nm.id is not None: - # True/False 布尔字面量 → 1/0(对齐 TPC:bool 在 CDefine 语境按整数处理) - if string.strcmp(nm.id, "True") == 0: - return 1 - if string.strcmp(nm.id, "False") == 0: - return 0 - looked_up: t.CInt64T = HandlesType.lookup_cdefine_constant(nm.id) - if HandlesType.is_cdefine_found() != 0: - return looked_up - # 引用未注册:直接报错终止(fail-fast) - HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError") - - # Case 4: Call — 如 t.CUnsignedLong(-11) - if k == ast.ASTKind.Call: - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(val_node) - # 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(), - # 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错 - cl_args_list: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cl_args_list is not None and len(cl_args_list) > 0: - first_arg: ast.AST | t.CPtr = cl_args_list.get(0) - arg_val: t.CInt64T = self.extract_cdefine_int_value(first_arg) - return arg_val - # Call 无参数:直接报错终止(fail-fast) - HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError") - - # Case 5: UnaryOp — 如 -11 - if k == ast.ASTKind.UnaryOp: - uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(val_node) - operand_val: t.CInt64T = self.extract_cdefine_int_value(uop.operand) - if uop.op == ast.OpKind.USub: - return -operand_val - if uop.op == ast.OpKind.UAdd: - return operand_val - if uop.op == ast.OpKind.Invert: - return ~operand_val - # 未知 UnaryOp 运算符:直接报错终止(fail-fast) - HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError") - - # 未知节点类型:直接报错终止(fail-fast) - HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError") - # 追加89 块设计:fatal_error 调用后补显式 return(运行时不可达, - # 保证函数末尾块被正确 terminated,不做 noreturn 函数名白名单) - return 0 - - # ============================================================ - # _register_cdefine_from_value - 注册 CDefine 常量(浮点/整数自动识别) - # - # 浮点字面量(如 vipermath 的 U_M_PI: t.CDefine = 3.14159...)走 - # register_cdefine_double,否则 translate_value 查表得 0 生成 - # ret i32 0(llc 报错 "value doesn't match function result type")。 - # ============================================================ - def _register_cdefine_from_value(self, pool: memhub.MemBuddy | t.CPtr, - name: str, val_node: ast.AST | t.CPtr) -> None: - """注册 CDefine 常量(浮点字面量 → register_cdefine_double,否则整数)""" - if pool is None or name is None: - return - # Call 包装的常量:如 PI: t.CDefine = float(3.14159...) / - # t.CFloat64T(2.5) / t.CDouble(1.0)。取第一个参数作为真实值节点, - # 再按 Constant 分支处理(浮点 → register_cdefine_double)。 - if val_node is not None and val_node.kind() == ast.ASTKind.Call: - cl_cd: ast.Call | t.CPtr = (ast.Call | t.CPtr)(val_node) - if cl_cd is not None and cl_cd.args is not None: - cl_args_cd: list[ast.AST | t.CPtr] | t.CPtr = cl_cd.args - if cl_args_cd.__len__() > 0: - first_arg_cd: ast.AST | t.CPtr = cl_args_cd.get(0) - if first_arg_cd is not None and first_arg_cd.kind() == ast.ASTKind.Constant: - val_node = first_arg_cd - if val_node is not None and val_node.kind() == ast.ASTKind.Constant: - cn_fp: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(val_node) - if cn_fp.const_kind == ast.CONST_STR: - # 字符串 CDefine(如 ZLIB_VERSION: t.CDefine = "1.3.2"): - # 注册为字符串常量,读取端返回 global string(对齐 TPC)。 - HandlesType.register_cdefine_string(pool, name, cn_fp.str_val) - return - if cn_fp.const_kind == ast.CONST_FLOAT: - # 源文件重读恢复(最可靠:AST 节点 float_val 可能被 pool 操作覆写, - # 源文件文本不受影响;用输出参数绕开跨模块 double 返回值传递 bug) - use_val: double = cn_fp.float_val - rec_d: t.CDouble = 0.0 - if self._recover_cdefine_float(name, t.CPtr(c.Addr(rec_d))) != 0: - use_val = rec_d - else: - # 源文件恢复失败:直接报错终止(fail-fast),避免注册被 pool 覆写的错误浮点值 - HandlesType.fatal_error(val_node, "CDefine 浮点值源文件恢复失败", "InternalCompilerError") - return - HandlesType.register_cdefine_double(pool, name, use_val) - return - if val_node is None: - # CDefine 声明缺少值节点:直接报错终止(fail-fast) - HandlesType.fatal_error(None, f"CDefine 值提取失败:'{name}' 缺少初始值", "TypeError") - return - val_fp: t.CInt64T = self.extract_cdefine_int_value(val_node) - HandlesType.register_cdefine_constant(pool, name, val_fp) - - # ============================================================ - # 源文件重读恢复 CDefine 浮点值 - # - # 背景:AST 节点的 float_val/str_val 字段可能被 pool 分配操作覆写 - # (MemBuddy 内存冲突),导致注册的浮点 CDefine 值错误(llc ret i32 0)。 - # 本函数直接读源文件找 "NAME: t.CDefine = value" 行,atof 解析 value—— - # 源文件文本不受 pool 影响,是最可靠的恢复路径。 - # - # 原模块级 _g_recover_found 全局已迁移为实例字段 self.RecoverFound。 - # ============================================================ - - def _recover_found(self) -> int: - """检查最近一次 _recover_cdefine_float 是否成功""" - return self.RecoverFound - - def _recover_cdefine_float(self, name: str, out: t.CDouble | t.CPtr) -> int: - """从当前模块源文件恢复浮点 CDefine 值,写入 out[0],成功返回 1 - - 用输出参数传递 double,避免 TPV 跨模块 double 返回值传递 bug。 - """ - self.RecoverFound = 0 - fp: str = HandlesType.get_current_file() - if fp is None or name is None or out is None: - return 0 - f: fileio.File | t.CPtr = fileio.File(fp, fileio.MODE.R) - if f.closed: - return 0 - BUF_SZ: t.CSizeT = 1048576 - buf: bytes = stdlib.malloc(BUF_SZ) - if buf is None: - f.close() - return 0 - nrd: LONG = f.read_all(buf, BUF_SZ) - f.close() - if nrd <= 0: - stdlib.free(buf) - return 0 - if nrd < BUF_SZ: - buf[nrd] = 0 - else: - buf[BUF_SZ - 1] = 0 - - name_len: t.CSizeT = string.strlen(name) - total_len: t.CSizeT = string.strlen(buf) - pos: t.CSizeT = 0 - while pos < total_len: - line_start: t.CSizeT = pos - while pos < total_len and buf[pos] != '\n': - pos += 1 - line_len: t.CSizeT = pos - line_start - if pos < total_len: - pos += 1 - - # 匹配 "name:" - if line_len < name_len + 1: - continue - match_ok: int = 1 - ki: t.CSizeT - for ki in range(name_len): - if buf[line_start + ki] != name[ki]: - match_ok = 0 - break - if match_ok == 0: - continue - if buf[line_start + name_len] != ':': - continue - - # 行内包含 "t.CDefine" - has_cd: int = 0 - ci: t.CSizeT = line_start + name_len + 1 - while ci + 8 <= line_start + line_len: - if (buf[ci] == 't' and buf[ci + 1] == '.' and buf[ci + 2] == 'C' and - buf[ci + 3] == 'D' and buf[ci + 4] == 'e' and buf[ci + 5] == 'f' and - buf[ci + 6] == 'i' and buf[ci + 7] == 'n' and buf[ci + 8] == 'e'): - has_cd = 1 - break - ci += 1 - if has_cd == 0: - continue - - # 找 '=' - eq: t.CSizeT = line_start - while eq < line_start + line_len and buf[eq] != '=': - eq += 1 - if eq >= line_start + line_len: - continue - eq += 1 - while eq < line_start + line_len and buf[eq] == ' ': - eq += 1 - val_start: t.CSizeT = eq - while eq < line_start + line_len and buf[eq] != ' ' and buf[eq] != '\t' \ - and buf[eq] != '#' and buf[eq] != '\r' and buf[eq] != '\n': - eq += 1 - if eq == val_start: - continue - - val_txt: str = stdlib.malloc(eq - val_start + 1) - if val_txt is None: - stdlib.free(buf) - return 0 - vi: t.CSizeT - for vi in range(eq - val_start): - val_txt[vi] = buf[val_start + vi] - val_txt[eq - val_start] = 0 - stdlib.free(buf) - # 用 atof_out(输出参数)绕开跨模块 double 返回值传递 bug - if string.atof_out(val_txt, out) != 0: - self.RecoverFound = 1 - return 1 - return 0 - - stdlib.free(buf) - return 0 - - # ============================================================ - # _annotation_contains_name - 递归检查注解中是否包含指定名称 - # - # 支持 BinOp(BitOr) 递归,同时检查 Attribute.attr 和 Name.id。 - # ============================================================ - def _annotation_contains_name(self, annot: ast.AST | t.CPtr, name: str) -> int: - """递归检查注解中是否包含指定名称,返回 1=包含 / 0=不包含""" - if annot is None or name is None: - return 0 - k: int = annot.kind() - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot) - if at.attr is not None and string.strcmp(at.attr, name) == 0: - return 1 - return 0 - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annot) - if nm.id is not None and string.strcmp(nm.id, name) == 0: - return 1 - return 0 - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot) - if self._annotation_contains_name(bop.left, name) != 0: - return 1 - if self._annotation_contains_name(bop.right, name) != 0: - return 1 - return 0 - - # ============================================================ - # _is_ptr_element_annotation - 检查注解是否为 bytes|t.CPtr 或 str|t.CPtr - # - # 返回 1=是(下标按 8 字节步长, i8** 语义), 0=否(下标按 1 字节步长, i8* 语义) - # - # 规则: - # bytes|t.CPtr / str|t.CPtr → i8**(8 字节步长)→ 返回 1 - # t.CChar|t.CPtr / t.CInt8T|t.CPtr → i8*(1 字节步长)→ 返回 0 - # 纯 bytes / str → i8*(1 字节步长)→ 返回 0 - # - # 注: 注解中的 "|" 是"和"的意思(组合类型),非右值中的位或运算 - # ============================================================ - def _is_ptr_element_annotation(self, annot: ast.AST | t.CPtr) -> int: - """检查注解是否为 bytes|t.CPtr 或 str|t.CPtr 形式""" - if annot is None: - return 0 - k: int = annot.kind() - if k != ast.ASTKind.BinOp: - return 0 - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot) - if bop.op != ast.OpKind.BitOr: - return 0 - if self._annotation_contains_name(annot, "str") != 0: - return 1 - if self._annotation_contains_name(annot, "bytes") != 0: - return 1 - # 泛型类型参数/嵌套联合 | t.CPtr(如 _list.vp 的 elem_ptr: T | t.CPtr): - # 先经泛型上下文解析 T 的具体类型——纯标量(int/float 等 sizeof≠8)时 - # 元素按标量自身大小(list[int] elem_size=4 匹配 i32),不能按 8 字节 - # 指针槽(否则 8 字节写 / 4 字节步长互相覆盖,pop 读到 0); - # 指针/嵌套联合/64 位标量/double(sizeof==8)才按 8 字节。 - if self._is_generic_tp_or_nested(bop.left) != 0 or self._is_generic_tp_or_nested(bop.right) != 0: - gp_nm: str = None - if bop.left is not None and bop.left.kind() == ast.ASTKind.Name: - gp_left_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bop.left) - gp_nm = gp_left_nm.id - elif bop.right is not None and bop.right.kind() == ast.ASTKind.Name: - gp_right_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bop.right) - gp_nm = gp_right_nm.id - if gp_nm is not None: - # 经全局 gen 委托解析泛型参数(T → 具体类型名)。不能 self.GenericTpNames - # 直读(Mixin @t.NoVTable 静态绑定:字段声明在 TypeGenMixin,AssignGenMixin - # 访问会生成不存在的属性引用 → TPC fast-fail 编译崩溃) - gp_resolved: str = HandlesType.resolve_generic_type_name(gp_nm) - if gp_resolved is not None and string.strcmp(gp_resolved, gp_nm) != 0: - # 泛型参数解析为纯标量 → 元素按标量自身大小(非 8 字节指针槽) - if self._is_scalar_ty_name(gp_resolved) != 0: - return 0 - return 1 - # 64 位标量数值类型 | CPtr(如 CUInt64T | CPtr / CSizeT | CPtr): - # 联合解析后同样退化为指针表示,元素为 8 字节(i64 或指针)。 - # 下标必须按 8 字节步长读写——否则 GEP 步长 1 + trunc i8 截断, - # 指针存进数组只剩低 1 字节(BuddyTest OOM/fill 的 ptrs 数组全错位: - # store i8 trunc i64、读回 inttoptr i8 丢高 56 位,free 全部无效)。 - if self._is_64bit_scalar_ty(bop.left) != 0 or self._is_64bit_scalar_ty(bop.right) != 0: - return 1 - return 0 - - def _is_64bit_scalar_ty(self, node: ast.AST | t.CPtr) -> int: - """判断类型节点是否为 64 位标量数值类型(CUInt64T/CInt64T/CSizeT),元素 8 字节""" - if node is None: - return 0 - ty_nm: str = None - nk: int = node.kind() - if nk == ast.ASTKind.Name: - nm64: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - ty_nm = nm64.id - elif nk == ast.ASTKind.Attribute: - at64: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - ty_nm = at64.attr - if ty_nm is None: - return 0 - if string.strcmp(ty_nm, "CUInt64T") == 0: - return 1 - if string.strcmp(ty_nm, "CInt64T") == 0: - return 1 - if string.strcmp(ty_nm, "CSizeT") == 0: - return 1 - return 0 - - def _is_scalar_ty_name(self, ty_name: str) -> int: - """判断类型名是否为已知纯标量(整数/浮点/字符),白名单判定 - - 泛型 T | t.CPtr(如 _list.vp 的 elem_ptr)经 Fix A(TypeGenMixin 联合 - 解析保留泛型标量)后 alloca 变 Ptr(标量):T 为纯标量(int/float/double/ - i64 等)时下标按标量自身大小步长,不能再按 8 字节指针槽——否则 - Ptr(标量) alloca + IsPtrElement 路径(load 标量当指针)产生非法 IR。 - 指针/联合/str/bytes 才保持 8 字节指针槽语义。 - - 原实现"排除 Ptr/str/bytes/| 后默认返回 1"把**未知类名**(如泛型上下文 - 污染产生的 llvmlite.Value)误判为标量 → IsPtrElement=0 → elem_ptr[0] - 走通用路径生成 Value* → list[str].get 声明 i8* 与 ret Value* 不匹配 - (8fbba llc 报错根因)。改白名单:已知标量才 1,未知类名按 8 字节指针槽。 - """ - if ty_name is None: - return 0 - if string.strchr(ty_name, '|') is not None: - return 0 - if string.strchr(ty_name, '*') is not None: - return 0 - if string.strcmp(ty_name, "str") == 0: - return 0 - if string.strcmp(ty_name, "bytes") == 0: - return 0 - if string.strcmp(ty_name, "t.CPtr") == 0: - return 0 - if string.strcmp(ty_name, "CPtr") == 0: - return 0 - if string.strstr(ty_name, "Ptr") is not None: - return 0 - # === 白名单:已知纯标量(基础名 + stdint 大写别名) === - if string.strcmp(ty_name, "int") == 0: return 1 - if string.strcmp(ty_name, "CInt") == 0: return 1 - if string.strcmp(ty_name, "CChar") == 0: return 1 - if string.strcmp(ty_name, "CUnsignedChar") == 0: return 1 - if string.strcmp(ty_name, "CShort") == 0: return 1 - if string.strcmp(ty_name, "CUnsignedShort") == 0: return 1 - if string.strcmp(ty_name, "CLong") == 0: return 1 - if string.strcmp(ty_name, "CUnsignedLong") == 0: return 1 - if string.strcmp(ty_name, "CLongLong") == 0: return 1 - if string.strcmp(ty_name, "CUnsignedLongLong") == 0: return 1 - if string.strcmp(ty_name, "CSizeT") == 0: return 1 - if string.strcmp(ty_name, "BOOL") == 0: return 1 - if string.strcmp(ty_name, "BYTE") == 0: return 1 - if string.strcmp(ty_name, "UCHAR") == 0: return 1 - if string.strcmp(ty_name, "CHAR") == 0: return 1 - if string.strcmp(ty_name, "SHORT") == 0: return 1 - if string.strcmp(ty_name, "USHORT") == 0: return 1 - if string.strcmp(ty_name, "LONG") == 0: return 1 - if string.strcmp(ty_name, "ULONG") == 0: return 1 - if string.strcmp(ty_name, "LONGLONG") == 0: return 1 - if string.strcmp(ty_name, "ULONGLONG") == 0: return 1 - if string.strcmp(ty_name, "INT") == 0: return 1 - if string.strcmp(ty_name, "UINT") == 0: return 1 - if string.strcmp(ty_name, "WORD") == 0: return 1 - if string.strcmp(ty_name, "DWORD") == 0: return 1 - if string.strcmp(ty_name, "QWORD") == 0: return 1 - # 定长整数/浮点(C*T 形式与裸别名,strstr 前缀匹配) - if string.strstr(ty_name, "Int8") is not None: return 1 - if string.strstr(ty_name, "Int16") is not None: return 1 - if string.strstr(ty_name, "Int32") is not None: return 1 - if string.strstr(ty_name, "Int64") is not None: return 1 - if string.strstr(ty_name, "UInt8") is not None: return 1 - if string.strstr(ty_name, "UInt16") is not None: return 1 - if string.strstr(ty_name, "UInt32") is not None: return 1 - if string.strstr(ty_name, "UInt64") is not None: return 1 - if string.strstr(ty_name, "Float") is not None: return 1 - if string.strstr(ty_name, "FLOAT") is not None: return 1 - if string.strstr(ty_name, "Double") is not None: return 1 - if string.strstr(ty_name, "DOUBLE") is not None: return 1 - # 未知类名(结构体/类/污染类型)→ 非标量,按 8 字节指针槽 - return 0 - - def _is_generic_tp_or_nested(self, node: ast.AST | t.CPtr) -> int: - """判断注解节点是否为泛型类型参数名(单字母大写,如 T)或嵌套联合(BinOp)""" - if node is None: - return 0 - nk: int = node.kind() - if nk == ast.ASTKind.BinOp: - return 1 - if nk == ast.ASTKind.Name: - nm_tp: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm_tp.id is None: - return 0 - tp_len: t.CSizeT = string.strlen(nm_tp.id) - if tp_len == 1: - if nm_tp.id[0] >= 65 and nm_tp.id[0] <= 90: - return 1 - return 0 - - # ============================================================ - # _init_global_array_from_list — 从列表字面量初始化全局数组 - # - # 为每个元素生成 GEP + store 指令,将值存入全局数组的对应位置。 - # 适用于模块级 t.CArray[elem_ty, count] = [v0, v1, ...] 的初始化。 - # - # Args: - # builder: IRBuilder - # pool: 编译器内存池 - # mod: LLVMModule - # array_alloca: 全局数组变量的 Value 引用(类型为 [N x elem_ty]*) - # list_node: ast.List 节点 - # trans: Translator 对象 - # - # Returns: - # 0 成功,1 失败 - # ============================================================ - def _init_global_array_from_list(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - array_alloca: llvmlite.Value | t.CPtr, - list_node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr) -> int: - """从列表字面量初始化全局数组,为每个元素生成 GEP + store""" - if builder is None or array_alloca is None or list_node is None: - return 1 - - # 获取数组类型(Pointee of [N x elem_ty]*) - arr_ty: llvmlite.LLVMType | t.CPtr = None - if array_alloca.Ty is not None: - arr_ty = array_alloca.Ty.Pointee - if arr_ty is None: - return 1 - - # 匹配数组类型获取元素类型 - elem_ty: llvmlite.LLVMType | t.CPtr = None - match arr_ty: - case llvmlite.LLVMType.Array(et, _): - elem_ty = et - if elem_ty is None: - return 1 - - # 获取列表元素 - lst: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node) - if lst is None or lst.elts is None: - return 1 - elts: list[ast.AST | t.CPtr] | t.CPtr = lst.elts - elts_count: t.CSizeT = len(elts) - - # 为每个元素生成 GEP + store - i: t.CSizeT = 0 - while i < elts_count: - elem_node: ast.AST | t.CPtr = elts.get(i) - elem_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, elem_node, None, 0, trans) - if elem_val is None: - # 元素翻译失败:直接报错终止(fail-fast),暴露上游根因 - HandlesType.fatal_error(elem_node, "全局数组初始化元素翻译失败", "TypeError") - idx_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, i) - elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, arr_ty, elem_ty, array_alloca, idx_val) - if elem_ptr is not None: - # 类型转换(如 i32 → i8 截断) - store_val: llvmlite.Value | t.CPtr = elem_val - if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None: - store_val = HandlesExpr.coerce_to_type( - builder, elem_val, elem_ptr.Ty.Pointee, elem_node) - llvmlite.build_store(builder, store_val, elem_ptr) - i += 1 - - return 0 - - # ============================================================ - # _apply_aug_op - 应用增强赋值的二元运算 - # - # 支持浮点运算、指针算术: ptr += int / ptr -= int - # 整数运算自动类型提升 - # ============================================================ - def _apply_aug_op(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - op: int, - lhs: llvmlite.Value | t.CPtr, - rhs: llvmlite.Value | t.CPtr, - node: ast.AST | t.CPtr = None, - trans: HT.Translator | t.CPtr = None, - lhs_node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """应用增强赋值的二元运算(浮点 + 指针算术 + 整数运算)""" - lhs_bits: int = HandlesExpr.get_llvm_type_bits(lhs.Ty) - rhs_bits: int = HandlesExpr.get_llvm_type_bits(rhs.Ty) - lhs_fbits: int = HandlesExpr.get_llvm_float_bits(lhs.Ty) - rhs_fbits: int = HandlesExpr.get_llvm_float_bits(rhs.Ty) - - # 浮点运算: 任一操作数为浮点时,使用浮点指令(必须在指针算术之前检查, - # 因为 float 的 int bits 为 0,会被误认为指针) - if lhs_fbits != 0 or rhs_fbits != 0: - # 确定目标浮点类型(使用较大的位宽) - target_fbits: int = lhs_fbits - if rhs_fbits > target_fbits: - target_fbits = rhs_fbits - target_float_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) - if target_fbits == 32: - target_float_ty = llvmlite.Float(pool) - # 将两个操作数转换为目标浮点类型(int→float via si2fp, float→float via fpext/fptrunc) - lhs = HandlesExpr.coerce_to_type(builder, lhs, target_float_ty, node) - rhs = HandlesExpr.coerce_to_type(builder, rhs, target_float_ty, node) - if op == ast.OpKind.Add: - return llvmlite.build_fadd(builder, lhs, rhs) - if op == ast.OpKind.Sub: - return llvmlite.build_fsub(builder, lhs, rhs) - if op == ast.OpKind.Mult: - return llvmlite.build_fmul(builder, lhs, rhs) - if op == ast.OpKind.Div: - return llvmlite.build_fdiv(builder, lhs, rhs) - if op == ast.OpKind.Mod: - return llvmlite.build_frem(builder, lhs, rhs) - return None - - # 指针算术: ptr += int / ptr -= int → getelementptr(按元素大小缩放) - # 对齐 TPC HandlesAugAssign.py L140-149 / L170-180 - if lhs_bits == 0 and rhs_bits != 0: - if op == ast.OpKind.Add or op == ast.OpKind.Sub: - return HandlesExpr.translate_ptr_arith(pool, builder, lhs, rhs, op) - return None - - # 整数运算:类型提升 - if lhs_bits > rhs_bits and rhs_bits > 0: - rhs = HandlesExpr.coerce_to_type(builder, rhs, lhs.Ty, node) - elif rhs_bits > lhs_bits and lhs_bits > 0: - lhs = HandlesExpr.coerce_to_type(builder, lhs, rhs.Ty, node) - - if op == ast.OpKind.Add: - return llvmlite.build_add(builder, lhs, rhs) - elif op == ast.OpKind.Sub: - return llvmlite.build_sub(builder, lhs, rhs) - elif op == ast.OpKind.Mult: - return llvmlite.build_mul(builder, lhs, rhs) - elif op == ast.OpKind.Div: - return llvmlite.build_sdiv(builder, lhs, rhs) - elif op == ast.OpKind.FloorDiv: - return llvmlite.build_sdiv(builder, lhs, rhs) - elif op == ast.OpKind.Mod: - return llvmlite.build_srem(builder, lhs, rhs) - elif op == ast.OpKind.BitAnd: - return llvmlite.build_and(builder, lhs, rhs) - elif op == ast.OpKind.BitOr: - return llvmlite.build_or(builder, lhs, rhs) - elif op == ast.OpKind.BitXor: - return llvmlite.build_xor(builder, lhs, rhs) - elif op == ast.OpKind.LShift: - return llvmlite.build_shl(builder, lhs, rhs) - elif op == ast.OpKind.RShift: - # 无符号 >> → lshr(逻辑右移),有符号 >> → ashr(算术右移) - # 对齐 TPC ExprGen.emit_binary_op:i8/i16 默认无符号;其余查操作数无符号性 - if lhs_bits == 8 or lhs_bits == 16: - return llvmlite.build_lshr(builder, lhs, rhs) - if lhs_node is not None and trans is not None: - if HandlesExpr._node_type_unsigned(pool, lhs_node, trans) != 0: - return llvmlite.build_lshr(builder, lhs, rhs) - return llvmlite.build_ashr(builder, lhs, rhs) - return None - - # ============================================================ - # translate_augassign - 增强赋值语句翻译(迁移自 HandlesAugAssign.AugAssignHandle.Handle) - # - # 支持 += -= *= /= %= &= |= ^= <<= >>=,local/global/nonlocal 三种作用域 - # ============================================================ - def translate_augassign(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译增强赋值语句 (x += 1, y -= 2, etc.)""" - if node is None: - return 0 - - aug: ast.AugAssign | t.CPtr = (ast.AugAssign | t.CPtr)(node) - if aug is None: - return 0 - - target: ast.AST | t.CPtr = aug.target - if target is None: - return 0 - - tk: int = target.kind() - - # Attribute 目标: self.field += 1 - # 流程: get_attribute_ptr → load → binop → store - if tk == ast.ASTKind.Attribute: - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - - # 1. 获取字段指针 - field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( - builder, pool, mod, target, trans) - if field_ptr is None: - # fail-fast: 属性指针解析失败 - HandlesType.fatal_error(target, "attribute ptr is None", "TypeError") - - # 2. 确定字段类型并加载当前值 - target_ty: llvmlite.LLVMType | t.CPtr = None - if field_ptr.Ty is not None and field_ptr.Ty.Pointee is not None: - target_ty = field_ptr.Ty.Pointee - if target_ty is None: - # fail-fast: 字段类型信息缺失,禁止兜底 i32 - HandlesType.fatal_error(target, "字段类型信息缺失", "TypeError") - cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, target_ty, field_ptr) - if cur_val is None: - # fail-fast: 属性当前值加载失败 - HandlesType.fatal_error(target, "无法加载 attribute 当前值", "TypeError") - - # 3. 翻译 RHS 值 - rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, aug.value, None, 0, trans) - if rhs_val is None: - # fail-fast: RHS 翻译失败 - HandlesType.fatal_error(target, "rhs 翻译失败", "TypeError") - - # 4. 应用二元运算 - result: llvmlite.Value | t.CPtr = self._apply_aug_op( - pool, builder, aug.op, cur_val, rhs_val, node, trans, target) - if result is None: - # fail-fast: attribute 二元运算失败 - HandlesType.fatal_error(target, f"attribute 二元运算失败 op={aug.op}", "TypeError") - - # 5. 类型对齐并存储 - result = HandlesExpr.coerce_to_type(builder, result, target_ty, node) - if result is None: - # fail-fast: 类型对齐失败 - HandlesType.fatal_error(target, "类型对齐失败", "TypeError") - llvmlite.build_store(builder, result, field_ptr) - return 0 - - # Subscript 目标: self.state[i] += x / arr[i] += x - # 流程: get_subscript_ptr → load → binop → store - if tk == ast.ASTKind.Subscript: - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - - # 1. 获取元素指针 - elem_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_subscript_ptr( - builder, pool, mod, target, trans) - if elem_ptr is None: - # fail-fast: 下标指针解析失败 - HandlesType.fatal_error(target, "subscript ptr is None", "TypeError") - - # 2. 确定元素类型并加载当前值 - target_ty: llvmlite.LLVMType | t.CPtr = None - if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None: - target_ty = elem_ptr.Ty.Pointee - if target_ty is None: - # fail-fast: 元素类型信息缺失,禁止兜底 i32 - HandlesType.fatal_error(target, "元素类型信息缺失", "TypeError") - cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, target_ty, elem_ptr) - if cur_val is None: - # fail-fast: 元素当前值加载失败 - HandlesType.fatal_error(target, "无法加载 subscript 元素当前值", "TypeError") - - # 3. 翻译 RHS 值 - rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, aug.value, None, 0, trans) - if rhs_val is None: - # fail-fast: RHS 翻译失败 - HandlesType.fatal_error(target, "rhs 翻译失败", "TypeError") - - # 4. 应用二元运算 - result: llvmlite.Value | t.CPtr = self._apply_aug_op( - pool, builder, aug.op, cur_val, rhs_val, node, trans, target) - if result is None: - # fail-fast: subscript 二元运算失败 - HandlesType.fatal_error(target, f"subscript 二元运算失败 op={aug.op}", "TypeError") - - # 5. 类型对齐并存储 - result = HandlesExpr.coerce_to_type(builder, result, target_ty, node) - if result is None: - # fail-fast: 类型对齐失败 - HandlesType.fatal_error(target, "类型对齐失败", "TypeError") - llvmlite.build_store(builder, result, elem_ptr) - return 0 - - if tk != ast.ASTKind.Name: - # fail-fast: 不支持的 AugAssign 目标类型 - HandlesType.fatal_error( - target, "AugAssign 目标类型不支持,仅支持 Name/Attribute/Subscript", "TypeError") - - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) - if nm is None or nm.id is None: - return 0 - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - - # 1. 确定变量作用域类型: 0=local, 1=global, 2=nonlocal - scope_type: int = 0 - if HT.is_global_name(trans, nm.id) != 0: - scope_type = 1 - elif HT.is_nonlocal_name(trans, nm.id) != 0: - scope_type = 2 - - # 2. 加载当前值 - cur_val: llvmlite.Value | t.CPtr = None - target_alloca: llvmlite.Value | t.CPtr = None - target_ty: llvmlite.LLVMType | t.CPtr = None - - if scope_type == 1: - # global 变量 - target_alloca = HandlesVar.lookup_module_var( - trans.SymTab, nm.id) - if target_alloca is not None: - if target_alloca.Ty is None: - # fail-fast: 变量类型信息缺失,禁止兜底 i32 - HandlesType.fatal_error(target, "变量类型信息缺失", "TypeError") - target_ty = target_alloca.Ty.Pointee - cur_val = llvmlite.build_load(builder, target_ty, target_alloca) - elif scope_type == 2: - # nonlocal 变量(通过闭包 env) - cur_val = HandlesNonlocal.load_nonlocal_var(trans, nm.id) - if cur_val is not None: - target_ty = cur_val.Ty - else: - # 普通局部变量 - target_alloca = HandlesVar.lookup_var(trans.SymTab, nm.id) - if target_alloca is not None: - if target_alloca.Ty is None: - # fail-fast: 变量类型信息缺失,禁止兜底 i32 - HandlesType.fatal_error(target, "变量类型信息缺失", "TypeError") - target_ty = target_alloca.Ty.Pointee - cur_val = llvmlite.build_load(builder, target_ty, target_alloca) - - if cur_val is None: - # fail-fast: 目标变量当前值加载失败 - HandlesType.fatal_error( - target, - f"无法加载目标变量 '{nm.id}' 的当前值", - "TypeError") - - # 3. 翻译 RHS 值 - rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, aug.value, None, 0, trans) - if rhs_val is None: - # fail-fast: RHS 翻译失败 - HandlesType.fatal_error(target, "rhs 翻译失败", "TypeError") - - # 4. 类型对齐 + 应用二元运算 - # 注意: AugAssign 不走运算符重载(语义上需要 __iadd__ 而非 __add__) - result: llvmlite.Value | t.CPtr = self._apply_aug_op( - pool, builder, aug.op, cur_val, rhs_val, node, trans, target) - if result is None: - # fail-fast: 二元运算失败 - HandlesType.fatal_error( - target, - f"对变量 '{nm.id}' 应用二元运算失败 op={aug.op}", - "TypeError") - - # 5. 存储结果 - result = HandlesExpr.coerce_to_type(builder, result, target_ty, node) - if result is None: - # fail-fast: 类型对齐失败 - HandlesType.fatal_error(target, "类型对齐失败", "TypeError") - - if scope_type == 1: - # global 变量 - if target_alloca is not None: - llvmlite.build_store(builder, result, target_alloca) - elif scope_type == 2: - # nonlocal 变量 - nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr( - trans, nm.id) - if nl_ptr is not None: - llvmlite.build_store(builder, result, nl_ptr) - else: - # 普通局部变量 - if target_alloca is not None: - llvmlite.build_store(builder, result, target_alloca) - - return 0 - - # ============================================================ - # is_ctypedef_annotation - 检测注解是否为 t.CTypedef - # - # 迁移自 HandlesAnnAssign.is_ctypedef_annotation(模块级委托壳); - # 真实实现 TypeGenCType._is_ctypedef_annotation 在另一 Mixin,经 - # gen 单例(HandlesExpr._g_gen 镜像)跨链调用。 - # ============================================================ - def is_ctypedef_annotation(self, annot: ast.AST | t.CPtr) -> int: - """检测注解是否为 t.CTypedef,返回 1 表示是,0 表示否""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( - t.CVoid(HandlesExpr._g_gen, t.CPtr)) - if g is not None: - return g._is_ctypedef_annotation(annot) - return 0 - - # ============================================================ - # _is_single_param_carray_annot - 检查注解是否为单参 t.CArray[elem_ty] - # - # 单参形式(t.CArray[elem_ty])与 count=None 形式(t.CArray[elem_ty, None]) - # 都解析为 Ptr(elem_ty)。当 RHS 是列表字面量时,按 TPC 语义应推断为 - # 静态数组 [len x elem_ty](对齐 TPC ParseListAnnotation 的 is_pointer 分支: - # "单参数 list[type] → 指针,但如果有列表字面量初始化值则按数组 list[type, N] 处理")。 - # ============================================================ - def _is_single_param_carray_annot(self, annot: ast.AST | t.CPtr) -> int: - """检查注解是否为单参/None 长度 t.CArray[...],返回 1=是 0=否 - - 支持两种书写形式: - 1. 模块限定 t.CArray[...](Attribute value) - 2. 裸名 CArray[...](from t import * 后使用,如 Termination4K3 core.vp - 的 `__python_suffix__: CArray[str] = ["py", ...]`) - """ - if annot is None or annot.kind() != ast.ASTKind.Subscript: - return 0 - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot) - if sub.value is None or sub.slice is None: - return 0 - if sub.value.kind() == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sub.value) - if at.attr is None or string.strcmp(at.attr, "CArray") != 0: - return 0 - if at.value is None or at.value.kind() != ast.ASTKind.Name: - return 0 - mv: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if mv.id is None or string.strcmp(mv.id, "t") != 0: - return 0 - elif sub.value.kind() == ast.ASTKind.Name: - # 裸名 CArray(from t import *):与 t.CArray 等价 - bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) - if bn.id is None or string.strcmp(bn.id, "CArray") != 0: - return 0 - else: - return 0 - # 单参形式:slice 非 Tuple(如 t.CArray[u64] / CArray[str]) - if sub.slice.kind() != ast.ASTKind.Tuple: - return 1 - # 双参形式:count=None(t.CArray[u64, None])→ 等价单参 - tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice) - if tup.elts is None or len(tup.elts) < 2: - return 0 - cnt_node: ast.AST | t.CPtr = tup.elts.get(1) - if cnt_node is not None and cnt_node.kind() == ast.ASTKind.Constant: - cn0: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(cnt_node) - if cn0.const_kind == ast.CONST_NONE: - return 1 - return 0 - - # ============================================================ - # _infer_static_array_ty_from_literal - 单参 CArray + 列表字面量 → 静态数组 - # - # 单参 t.CArray[elem_ty] 解析为 Ptr(elem_ty),但当 RHS 是列表字面量时, - # 按 TPC 语义应推断为 [len x elem_ty](对齐 TPC ParseListAnnotation): - # 避免误走动态 list 构造(_find_pool_var 兜底引用外部 @_mbuddy → 链接期 - # undefined)。PreScan 与 Handle 都调用(PreScan 预创建 alloca 的类型必须 - # 与 Handle 一致,否则 get_or_create_sym 复用旧 alloca 使推断失效)。 - # ============================================================ - def _infer_static_array_ty_from_literal(self, pool: memhub.MemBuddy | t.CPtr, - annot: ast.AST | t.CPtr, - value: ast.AST | t.CPtr, - resolved_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.LLVMType | t.CPtr: - """单参 CArray + 列表字面量 → Array(elem_ty, len);否则返回原类型""" - if value is not None and value.kind() == ast.ASTKind.List and resolved_ty is not None: - if self._is_single_param_carray_annot(annot) != 0: - elem_ty_arr: llvmlite.LLVMType | t.CPtr = resolved_ty.Pointee - lst_arr: ast.List | t.CPtr = (ast.List | t.CPtr)(value) - cnt_arr: int = 0 - if lst_arr.elts is not None: - cnt_arr = len(lst_arr.elts) - if elem_ty_arr is not None and cnt_arr > 0: - return llvmlite.Array(pool, elem_ty_arr, cnt_arr) - return resolved_ty - - # ============================================================ - # translate_annassign_prescan - 预扫描 AnnAssign(迁移自 - # HandlesAnnAssign.AnnAssignHandle.PreScan) - # - # 为有类型注解的变量提前创建 alloca 到 entry block 顶部;返回新增的变量数 - # ============================================================ - def translate_annassign_prescan(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """预扫描 AnnAssign,提前创建 alloca 到 entry block 顶部""" - if node is None: - return 0 - k: int = node.kind() - if k != ast.ASTKind.AnnAssign: - return 0 - - aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) - if aa is None or aa.target is None: - return 0 - target: ast.AST | t.CPtr = aa.target - if target.kind() != ast.ASTKind.Name: - return 0 - - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) - if nm.id is None: - return 0 - - # CDefine 注解: 不创建 alloca,但注册常量到全局表 - # 供后续 t.CArray[elem_ty, NAME] 编译期解析使用 - # 浮点/整数自动识别(与 Handle/handle_module_level_var 路径一致) - if self.is_cdefine_annotation(aa.annotation) != 0: - pool_ps: memhub.MemBuddy | t.CPtr = trans.Pool - self._register_cdefine_from_value(pool_ps, nm.id, aa.value) - return 0 - - # CTypedef 注解: 类型别名(ScanCTypedefDeclarations 已注册到 CTypedef 表), - # 不创建全局/局部存储——否则 stdint.vp 的 float64_t: t.CTypedef = t.CFloat64T - # 等生成 @float64_t 符号,链接 duplicate symbol warning - if self.is_ctypedef_annotation(aa.annotation) != 0: - return 0 - - # global/nonlocal 变量不需要局部 alloca - if HT.is_global_name(trans, nm.id) != 0: - return 0 - if HT.is_nonlocal_name(trans, nm.id) != 0: - return 0 - - # 模块级全局变量已由 handle_module_level_var 注册到模块作用域。 - # Python 语义:仅模块级代码(Current == Root)时跳过局部 alloca; - # 函数内无 global 声明时应创建局部变量(不遮蔽全局)。 - if HandlesVar.is_module_scope(trans.SymTab) != 0: - if HandlesVar.lookup_module_var(trans.SymTab, nm.id) is not None: - return 0 - - # 检查是否已存在 - existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( - trans.SymTab, nm.id) - if existing is not None: - return 0 - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - - # 从 annotation 推断类型(修复:原硬编码 i32 导致 str 等类型错误) - var_ty: llvmlite.LLVMType | t.CPtr = None - annot: ast.AST | t.CPtr = aa.annotation - if annot is not None: - resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, annot, trans._imported_modules, trans._from_imports, trans) - if resolved is None: - # 尝试特化泛型类注解(如 list[str]) - # resolve_annotation_type 返回 None 可能是因为泛型类未特化 - if annot.kind() == ast.ASTKind.Subscript: - sub_annot: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot) - if sub_annot.value is not None and sub_annot.value.kind() == ast.ASTKind.Name: - sub_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_annot.value) - if sub_nm.id is not None: - template_cd: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(sub_nm.id) - spec_name_ps: str = None - if template_cd is not None: - type_args_ps: list[str] | t.CPtr = ExprCallCtor._extract_type_args_from_slice(pool, sub_annot.slice) - if type_args_ps is not None and len(type_args_ps) > 0: - spec_name_ps = HandlesClassDef._specialize_generic_class( - trans, sub_nm.id, type_args_ps) - if spec_name_ps is not None: - resolved = HandlesType.resolve_annotation_type( - pool, annot, trans._imported_modules, trans._from_imports, trans) - if resolved is not None: - var_ty = resolved - # 单参 t.CArray[elem_ty] + 列表字面量 → 静态数组(与 Handle 推断一致)。 - # PreScan 预创建的 alloca 类型必须与 Handle 期望一致,否则 Handle 的 - # get_or_create_sym 复用旧 alloca,数组推断失效仍走动态 list → _mbuddy。 - var_ty = self._infer_static_array_ty_from_literal(pool, annot, aa.value, var_ty) - else: - # fast-fail: 注解类型解析失败,Python traceback 立即终止(不静默回退 i32) - HandlesType.fatal_error( - aa, - f"变量类型注解解析失败,变量名: {nm.id}", - "TypeError") - else: - # fail-fast: AnnAssign 必须有 annotation,缺少时立即终止(禁止兜底 i32) - HandlesType.fatal_error( - aa, - f"AnnAssign 缺少类型注解,变量名: {nm.id}", - "SyntaxError") - - # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) - HandlesStruct.ensure_struct_def_in_module(pool, trans.Module, var_ty) - alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, var_ty) - if alloca is not None: - if HandlesVar.define_var( - trans.SymTab, nm.id, alloca) == 0: - # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) - # 传 pool:泛型 Subscript 返回 mangled name(GSList[BasicBlock] → 特化 - # struct 名),否则 pool=None 只返回裸类名(GSList → 泛型模板未注册 - # → 属性访问 lookup_field_by_class("GSList") 报"类未注册",LLVMLiteTest - # __function.vp blocks.Tail 根因;对齐 ClassGenMixin L3159 BUG 1 方案3) - if annot is not None: - cls_nm_ps: str = HandlesType.extract_class_name_from_annotation( - annot, trans._imported_modules, pool) - if cls_nm_ps is not None: - HandlesVar.set_var_annot_class_name( - trans.SymTab, nm.id, cls_nm_ps) - # 检查是否为 bytes|t.CPtr 或 str|t.CPtr(i8** 语义,8 字节步长) - if self._is_ptr_element_annotation(annot) != 0: - HandlesVar.set_var_ptr_element( - trans.SymTab, nm.id) - return 0 - return 0 - - # ============================================================ - # translate_annassign - 翻译 AnnAssign 语句(迁移自 - # HandlesAnnAssign.AnnAssignHandle.Handle) - # - # 返回新增的变量数 - # ============================================================ - def translate_annassign(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 AnnAssign(target=Name, annotation=..., value=expr)""" - aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) - if aa is None: - return 0 - - target: ast.AST | t.CPtr = aa.target - if target is None or target.kind() != ast.ASTKind.Name: - return 0 - - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) - if nm.id is None: - return 0 - - # CDefine 注解: 编译期常量,不生成运行时代码 - # 注册到全局 CDefine 表供 t.CArray[elem_ty, NAME] 解析 - # 注: PreScan 已注册过,此处保证即使跳过 PreScan 也能正确注册 - if self.is_cdefine_annotation(aa.annotation) != 0: - pool_cd: memhub.MemBuddy | t.CPtr = trans.Pool - self._register_cdefine_from_value(pool_cd, nm.id, aa.value) - return 0 - - # CTypedef 注解: 类型别名(mode_t: t.CTypedef = t.CUInt32T 等)。 - # 翻译期 CTypedef 表已被 clear_ctypedefs 清空(每文件隔离;表字符串 - # pool 分配,reset_to(mark1) 回收后悬空,不能跨文件累积),必须在此 - # 按需注册,否则 posix.vp S_ISREG(mode: mode_t) 等普通函数参数注解 - # 解析查表失败 → NameError: mode_t。仅登记类型表达式,不创建全局/ - # 局部存储——否则生成 @mode_t 符号,链接 duplicate symbol warning。 - if self.is_ctypedef_annotation(aa.annotation) != 0: - pool_ct: memhub.MemBuddy | t.CPtr = trans.Pool - ctd_str: str = HandlesType._get_type_name_from_annotation(pool_ct, aa.value) - if ctd_str is not None: - HandlesType.register_ctypedef(pool_ct, nm.id, ctd_str) - return 0 - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - - # 确定类型(从 annotation 推断) - var_ty: llvmlite.LLVMType | t.CPtr = None - annot: ast.AST | t.CPtr = aa.annotation - if annot is not None: - resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, annot, trans._imported_modules, trans._from_imports, trans) - if resolved is not None: - var_ty = resolved - else: - # fast-fail: 注解类型解析失败,Python traceback 立即终止(不静默回退 i32) - HandlesType.fatal_error( - aa, - f"变量类型注解解析失败,变量名: {nm.id}", - "TypeError") - else: - # fail-fast: AnnAssign 必须有 annotation,缺少时立即终止(禁止兜底 i32) - HandlesType.fatal_error( - aa, - f"AnnAssign 缺少类型注解,变量名: {nm.id}", - "SyntaxError") - - # t.Callable 函数指针:注册返回类型签名(供函数指针间接调用精确返回类型) - callable_ret: llvmlite.LLVMType | t.CPtr = HandlesType.try_extract_callable_ret( - pool, annot, trans._imported_modules, trans._from_imports, trans) - if callable_ret is not None: - ExprCallCall.register_func_ptr_sig(nm.id, callable_ret) - - # global 变量:写入模块作用域中的全局变量 - if HT.is_global_name(trans, nm.id) != 0: - mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( - trans.SymTab, nm.id) - if mod_alloca is not None and aa.value is not None: - rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, aa.value, - None, 0, trans) - if rhs_val is not None: - target_ty: llvmlite.LLVMType | t.CPtr = None - if mod_alloca.Ty is not None: - target_ty = mod_alloca.Ty.Pointee - if target_ty is not None: - rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty, node) - llvmlite.build_store(builder, rhs_val, mod_alloca) - return 0 - - # nonlocal 变量:通过闭包 env 写入 - if HT.is_nonlocal_name(trans, nm.id) != 0: - if aa.value is not None: - rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, aa.value, - None, 0, trans) - if rhs_val is not None: - nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr( - trans, nm.id) - if nl_ptr is not None: - # 从 nl_ptr 的类型推断 nonlocal 变量实际类型, - # 不再强制 i32(会截断指针/结构体/i64 导致闭包数据损坏) - nl_target_ty: llvmlite.LLVMType | t.CPtr = None - if nl_ptr.Ty is not None: - nl_target_ty = nl_ptr.Ty.Pointee - if nl_target_ty is None: - # fast-fail: nl_ptr 类型信息丢失,无法安全 store - VLogger.error( - f"nonlocal 变量类型信息丢失,无法写入: {nm.id}", - "HandlesAnnAssign") - return 0 - rhs_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( - builder, rhs_val, nl_target_ty, node) - llvmlite.build_store(builder, rhs_coerced, nl_ptr) - return 0 - - # 模块级全局变量(由 handle_module_level_var 注册到模块作用域) - # Python 语义:仅模块级代码(Current == Root)时修改全局变量; - # 函数内无 global 声明时应创建局部变量(走后面的 get_or_create_sym 路径)。 - if HandlesVar.is_module_scope(trans.SymTab) != 0: - mod_glob: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( - trans.SymTab, nm.id) - else: - mod_glob = None - if mod_glob is not None: - if aa.value is not None: - # 列表字面量 → 逐元素 GEP + store 初始化数组 - if aa.value.kind() == ast.ASTKind.List: - self._init_global_array_from_list( - builder, pool, mod, mod_glob, aa.value, trans) - else: - rhs_val_mg: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, aa.value, - None, 0, trans) - if rhs_val_mg is not None: - target_ty_mg: llvmlite.LLVMType | t.CPtr = None - if mod_glob.Ty is not None: - target_ty_mg = mod_glob.Ty.Pointee - if target_ty_mg is not None: - rhs_val_mg = HandlesExpr.coerce_to_type(builder, rhs_val_mg, target_ty_mg, node) - llvmlite.build_store(builder, rhs_val_mg, mod_glob) - return 0 - - # 单参 t.CArray[elem_ty] + 列表字面量 → 按静态数组处理(count 从字面量长度推断) - # 与 PreScan 推断一致:get_or_create_sym 复用 PreScan 创建的 alloca, - # 类型一致才能命中局部数组快路径,避免 _find_pool_var 兜底引用 @_mbuddy。 - var_ty = self._infer_static_array_ty_from_literal(pool, annot, aa.value, var_ty) - - # 普通局部变量 - # 创建 alloca - alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym( - trans.SymTab, pool, builder, nm.id, var_ty) - if alloca is None: - # fail-fast: 存储创建失败,立即终止(禁止静默跳过) - HandlesType.fatal_error( - aa, - f"无法为变量 {nm.id} 创建存储", - "TypeError") - # FakeDuck: str 变量创建影子结构体 {var}__meta__(per-instance 字段存储) - # 仅裸 str 注解(Name("str"))且 _str 已注册时创建;bytes / t.CChar|t.CPtr 不创建。 - # a 保持为 i8*(可 printf/len),a__meta__ 存 __data__/__mbuddy__ 等字段, - # 属性读写(fd3)与方法调用(fd5)均通过该影子解析。 - fd_str_ty: llvmlite.LLVMType | t.CPtr = None - fd_meta_alloca: llvmlite.Value | t.CPtr = None - fd_meta_name: str = None - if annot is not None and annot.kind() == ast.ASTKind.Name: - fd_annot: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annot) - if fd_annot is not None and fd_annot.id is not None: - if string.strcmp(fd_annot.id, "str") == 0: - fd_str_ty = HandlesStruct.get_struct_type("_str") - if fd_str_ty is not None: - # 确保 _str 完整类型定义在当前模块可用:跨模块结构体默认 opaque, - # 直接 alloca opaque 类型 → llc "Cannot allocate unsized type" - HandlesStruct.ensure_struct_def_in_module(pool, mod, fd_str_ty) - # 影子变量名必须用 pool 持久缓冲:f-string 生成栈缓冲,在 AnnAssign - # 返回后被覆盖,符号表注册的名字内容损坏 → 后续 lookup 找不到。 - fd_meta_name = pool.alloc(256) - if fd_meta_name is not None: - viperlib.snprintf(fd_meta_name, 256, "%s__meta__", nm.id) - fd_meta_alloca = HandlesVar.get_or_create_sym( - trans.SymTab, pool, builder, fd_meta_name, fd_str_ty) - if fd_meta_alloca is None: - # fail-fast: 影子存储创建失败,立即终止 - HandlesType.fatal_error( - aa, - f"无法为 str 影子变量 {fd_meta_name} 创建存储", - "TypeError") - # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) - # 传 pool:泛型 Subscript 返回 mangled name(对齐 L401 同根因修复) - if annot is not None: - cls_nm_hd: str = HandlesType.extract_class_name_from_annotation( - annot, trans._imported_modules, pool) - if cls_nm_hd is not None: - HandlesVar.set_var_annot_class_name( - trans.SymTab, nm.id, cls_nm_hd) - # 检查是否为 bytes|t.CPtr 或 str|t.CPtr(i8** 语义,8 字节步长) - if self._is_ptr_element_annotation(annot) != 0: - HandlesVar.set_var_ptr_element( - trans.SymTab, nm.id) - - new_vars: int = 0 - existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( - trans.SymTab, nm.id) - if existing is None: - new_vars = 1 - - # 如果有初始值,store - if aa.value is not None: - # 局部数组:列表字面量 → 逐元素 GEP + store 初始化 - # 修复:此前局部 CArray[...] = [x, y] 会走 translate_list_literal, - # 错误触发 list[T] 泛型特化(堆对象)导致崩溃(如 this.vp 的 - # t.CArray[t.CChar, 256] = [0])。局部 alloca 未零初始化, - # 先整体置零再写列表元素(与全局数组默认零初始化语义一致)。 - local_arr_ty: llvmlite.LLVMType | t.CPtr = None - if aa.value.kind() == ast.ASTKind.List and alloca.Ty is not None: - pt_l: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee - if HandlesExpr.is_array_type(pt_l) != 0: - local_arr_ty = pt_l - if local_arr_ty is not None: - zero_arr: llvmlite.Value | t.CPtr = llvmlite.ConstZero( - pool, local_arr_ty) - if zero_arr is not None: - llvmlite.build_store(builder, zero_arr, alloca) - self._init_global_array_from_list( - builder, pool, mod, alloca, aa.value, trans) - else: - # 供 c.Deref(i8*) 推断读取宽度:v: int = c.Deref(p) → 读 i32 - # CurAssignNode 记录 RHS 节点:translate_c_deref 据此判定 Deref - # 是否为赋值直接 RHS(对齐 TPC _infer_deref_target_type)。 - trans.CurAssignAnnot = aa.annotation - trans.CurAssignNode = aa.value - rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, aa.value, - None, 0, trans) - if rhs_val is not None: - # 注解退化修复(对齐 TPC 从构造结果推断类型): - # 无实参泛型模板类注解(如 vi: vector.Vector | CPtr,模板 - # 未注册 struct → resolve 退化)会让 alloca 类型退化为 - # Ptr(i8),但 rhs 构造返回精确结构体指针(如 Ptr(Vector[int] - # 结构))。此时按退化 alloca store 会丢失特化类型,后续 - # vi.push 方法调用按 Ptr(i8) 查不到类名 → AnnotClassName - # 回退到模板名(无实参)→ vpi 查不到返回类型 fail-fast。 - # 用 rhs 精确类型重建 alloca 并更新符号表注册,使方法调用 - # 按精确特化类名解析。旧退化 alloca 行残留为 entry block - # 死代码(文本 IR 即时生成,无法删除,无害)。 - precise_rhs_ty: llvmlite.LLVMType | t.CPtr = None - if rhs_val.Ty is not None: - match rhs_val.Ty: - case llvmlite.LLVMType.Ptr(inner_struct): - match inner_struct: - case llvmlite.LLVMType.Struct(_, _, _): - precise_rhs_ty = rhs_val.Ty - case _: - pass - case _: - pass - if precise_rhs_ty is not None and alloca.Ty is not None: - alloca_pt: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee - if alloca_pt is not None and \ - t.CUInt64T(alloca_pt) != t.CUInt64T(precise_rhs_ty): - new_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry( - builder, precise_rhs_ty) - if new_alloca is not None: - v_entry_rb: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm.id) - if v_entry_rb is not None: - v_entry_rb.Alloca = new_alloca - alloca = new_alloca - # 类型转换:将 rhs_val 转换为 alloca 的 pointee 类型 - # 修复:整数字面量是 i32,但变量可能是 i8/i16/i64,需 trunc/sext - target_ty: llvmlite.LLVMType | t.CPtr = None - if alloca.Ty is not None: - target_ty = alloca.Ty.Pointee - if target_ty is not None: - rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty, node) - llvmlite.build_store(builder, rhs_val, alloca) - # FakeDuck: 初始化影子结构体 __data__ 字段 = 初始字符串指针 - # (对齐 TPC HandlesAnnAssign.py: 仅当有初值时写入 __data__) - if fd_str_ty is not None and fd_meta_alloca is not None: - fd_data_fe: HandlesStruct.FieldEntry | t.CPtr = \ - HandlesStruct.lookup_field(fd_str_ty, "__data__") - if fd_data_fe is not None: - fd_data_ptr: llvmlite.Value | t.CPtr = \ - llvmlite.build_gep_struct( - builder, fd_str_ty, fd_data_fe.Ty, - fd_meta_alloca, fd_data_fe.Index) - if fd_data_ptr is not None: - llvmlite.build_store(builder, rhs_val, fd_data_ptr) - # 清除赋值上下文(防残留):CurAssignAnnot/CurAssignNode 只在该 - # AnnAssign 的 RHS 翻译期间有效,否则后续 while 条件/比较等处的 - # c.Deref 会被残留注解误判读取宽度(i8* 被 bitcast i32* 读 4 字节)。 - trans.CurAssignAnnot = None - trans.CurAssignNode = None - - # FakeDuck: __mbuddy__ 字段初始化为 NULL。 - # with 上下文提供的 __mbuddy__ 注入由 _inject_requires_fields(fd4)完成, - # 此处仅确保影子结构体初始为空指针(对齐 TPC HandlesAnnAssign.py L667-670)。 - if fd_str_ty is not None and fd_meta_alloca is not None: - fd_buddy_fe: HandlesStruct.FieldEntry | t.CPtr = \ - HandlesStruct.lookup_field(fd_str_ty, "__mbuddy__") - if fd_buddy_fe is not None and fd_buddy_fe.Ty is not None: - fd_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull( - pool, fd_buddy_fe.Ty, "null") - fd_buddy_ptr: llvmlite.Value | t.CPtr = \ - llvmlite.build_gep_struct( - builder, fd_str_ty, fd_buddy_fe.Ty, - fd_meta_alloca, fd_buddy_fe.Index) - if fd_buddy_ptr is not None and fd_null is not None: - llvmlite.build_store(builder, fd_null, fd_buddy_ptr) - # FakeDuck: with 上下文自动注入 requires 字段(如 __mbuddy__)。 - # 经全局 gen 单例委托 CallGenMixin._inject_requires_fields。 - import lib.core.Gen.Generator as Generator - g_fda: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( - t.CVoid(HandlesExpr._g_gen, t.CPtr)) - if g_fda is not None: - g_fda._inject_requires_fields( - trans, pool, builder, mod, fd_meta_alloca, "_str") - - return 0 - - # ============================================================ - # translate_assign - 处理 Assign 语句,返回新增变量数(0 或 1) - # - # 迁移自 HandlesAssign.AssignHandle.Handle(对应 TransPyC - # AssignHandle._HandleAssignLlvm)。共享状态从 trans 获取。 - # ============================================================ - def translate_assign(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 Assign 语句,返回新增变量数(0 或 1)""" - asgn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node) - if asgn is None: - VLogger.error("cast failed", "ASGN") - return 0 - - targets: list[ast.AST | t.CPtr] | t.CPtr = asgn.targets - if targets is None: - VLogger.error("targets is None", "ASGN") - return 0 - - # 从 trans 取共享状态(替代 11 个参数) - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - - # 翻译 RHS 值 - # 无注解赋值无目标类型可推断,清空 CurAssignAnnot/CurAssignNode - # (防残留误判 c.Deref 宽度) - trans.CurAssignAnnot = None - trans.CurAssignNode = None - rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, asgn.value, None, 0, trans) - if rhs_val is None: - # Phase A 依赖未就绪(_deps_pending=1):跨模块函数/方法因 text.ll - # 未生成返回类型退化为 void/None(CallGenMixin L4493 - # g_vta._resolve_attr_field_class 根因)。此时整文件不写盘、下遍重译 - # (Phase2.vp L590-599),跳过本语句不报错——否则 fatal 使多遍 - # 重试机制永远无法收敛(本语句只是"本遍保持默认类型"的退化结果, - # 下遍依赖已生成即可精确解析)。依赖就绪时 _deps_pending=0, - # 此处仍 fail-fast,不掩盖真实错误。 - if trans is not None and trans._deps_pending != 0: - return 0 - # 增强错误信息:包含文件名 + lineno + AST 节点详情,便于定位 - fb: str = VLogger.fmt_buf() - if fb is not None and asgn.value is not None: - sha1: str = trans.ModuleSha1 - val_kind: int = asgn.value.kind() - val_line: t.CInt = asgn.value.lineno - # 通过 sha1 查找文件名(人类可读) - rel_path: str = None - if sha1 is not None: - rel_path = StubMergerStore.LookupSha1RelPath(sha1) - # 根据 AST 节点类型提取详情 - if val_kind == ast.ASTKind.Attribute: - at_nv: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(asgn.value) - attr_nm: str = at_nv.attr - target_nm: str = "?" - if at_nv.value is not None: - if at_nv.value.kind() == ast.ASTKind.Name: - tn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_nv.value) - target_nm = tn_nm.id - if rel_path is not None: - viperlib.snprintf(fb, 1024, - "赋值右侧为 None: %s:%d '%s.%s' 属性访问失败", - rel_path, val_line, target_nm, attr_nm) - else: - viperlib.snprintf(fb, 1024, - "赋值右侧为 None: sha1=%s:%d '%s.%s' 属性访问失败", - sha1, val_line, target_nm, attr_nm) - elif val_kind == ast.ASTKind.Name: - nm_nv: ast.Name | t.CPtr = (ast.Name | t.CPtr)(asgn.value) - if rel_path is not None: - viperlib.snprintf(fb, 1024, - "赋值右侧为 None: %s:%d 变量 '%s' 未找到", - rel_path, val_line, nm_nv.id) - else: - viperlib.snprintf(fb, 1024, - "赋值右侧为 None: sha1=%s:%d 变量 '%s' 未找到", - sha1, val_line, nm_nv.id) - elif val_kind == ast.ASTKind.Call: - cl_nv: ast.Call | t.CPtr = (ast.Call | t.CPtr)(asgn.value) - func_nm: str = "?" - if cl_nv.func is not None: - if cl_nv.func.kind() == ast.ASTKind.Name: - fn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl_nv.func) - func_nm = fn_nm.id - if rel_path is not None: - viperlib.snprintf(fb, 1024, - "赋值右侧为 None: %s:%d 调用 '%s(...)' 返回 None", - rel_path, val_line, func_nm) - else: - viperlib.snprintf(fb, 1024, - "赋值右侧为 None: sha1=%s:%d 调用 '%s(...)' 返回 None", - sha1, val_line, func_nm) - else: - if rel_path is not None: - viperlib.snprintf(fb, 1024, - "赋值右侧为 None: %s:%d [kind=%d]", - rel_path, val_line, val_kind) - else: - viperlib.snprintf(fb, 1024, - "赋值右侧为 None: sha1=%s:%d [kind=%d]", - sha1, val_line, val_kind) - VLogger.error(fb, "ASGN") - else: - VLogger.error("赋值右侧为 None (asgn.value 为空)", "ASGN") - return 0 - - new_vars: int = 0 - tn: t.CSizeT = len(targets) - for ti in range(tn): - target: ast.AST | t.CPtr = targets.get(ti) - if target is None: - continue - - tk: int = target.kind() - - # Tuple 赋值: a, b = f() 多返回值解包 - # rhs_val 是匿名 struct 值(函数返回 tuple[T1,T2] 打包)→ alloca + - # store + GEP 逐字段 load → store 到各 Name 目标。 - if tk == ast.ASTKind.Tuple: - tgt_tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(target) - tgt_elts: list[ast.AST | t.CPtr] | t.CPtr = tgt_tup.elts - # 守卫:rhs 不是 struct(tuple 打包)时跳过本 target - if tgt_elts is None or rhs_val is None or rhs_val.Ty is None: - continue - match rhs_val.Ty: - case llvmlite.LLVMType.Struct(_, _, _): - tgt_n: t.CSizeT = len(tgt_elts) - tmp_s: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, rhs_val.Ty) - if tmp_s is not None: - llvmlite.build_store(builder, rhs_val, tmp_s) - fchain: llvmlite.ParamNode | t.CPtr = llvmlite.get_struct_fields(rhs_val.Ty) - fcur: llvmlite.ParamNode | t.CPtr = fchain - fti: t.CSizeT - for fti in range(tgt_n): - tgt_elt: ast.AST | t.CPtr = tgt_elts.get(fti) - if tgt_elt is None or fcur is None: - break - fty: llvmlite.LLVMType | t.CPtr = llvmlite.paramnode_get_ty(fcur) - fcur = llvmlite.paramnode_get_next(fcur) - if fty is None: - # fail-fast: 字段类型缺失,立即终止 - HandlesType.fatal_error(target, "元组解包字段类型缺失", "TypeError") - # 守卫:非 Name 元素无法解包,跳过 - if tgt_elt.kind() != ast.ASTKind.Name: - continue - tgt_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tgt_elt) - if tgt_nm2.id is None: - continue - fp2: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, rhs_val.Ty, fty, tmp_s, fti) - if fp2 is None: - continue - fv2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, fty, fp2) - tgt_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, tgt_nm2.id) - if tgt_alloca is None: - tgt_alloca = HandlesVar.get_or_create_sym( - trans.SymTab, pool, builder, tgt_nm2.id, fty) - if tgt_alloca is None: - continue - sval: llvmlite.Value | t.CPtr = fv2 - if tgt_alloca.Ty is not None and tgt_alloca.Ty.Pointee is not None: - sval = HandlesExpr.coerce_to_type( - builder, fv2, tgt_alloca.Ty.Pointee, node) - llvmlite.build_store(builder, sval, tgt_alloca) - case _: - pass - continue - - # Subscript 赋值: arr[i] = val / ptr[i] = val / list[i] = val - if tk == ast.ASTKind.Subscript: - # 检查是否是 list[T] 类型的 Subscript(泛型类不注册 struct) - # list 的 subscript 赋值走 __setitem__ 内联路径 - list_obj: llvmlite.Value | t.CPtr = HandlesExpr.is_list_subscript( - target, trans) - if list_obj is not None: - # list[T] 类型: 内联生成 __setitem__ 逻辑 - sub_node: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(target) - if sub_node is not None and sub_node.slice is not None: - list_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, sub_node.slice, None, 0, trans) - if list_idx_val is None: - # fail-fast: list 下标翻译失败,立即终止 - HandlesType.fatal_error(target, "list 下标翻译失败", "TypeError") - HandlesExpr.list_setitem_inline( - builder, pool, list_obj, list_idx_val, rhs_val, target) - continue - # 普通 Subscript 赋值 - elem_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_subscript_ptr( - builder, pool, mod, target, trans) - if elem_ptr is not None: - store_val: llvmlite.Value | t.CPtr = rhs_val - # 守卫短路:elem 类型完整才做类型转换 - if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None: - store_val = HandlesExpr.coerce_to_type( - builder, rhs_val, elem_ptr.Ty.Pointee, node) - llvmlite.build_store(builder, store_val, elem_ptr) - continue - # get_subscript_ptr 返回 None: 尝试 __setitem__ 运算符重载 - # 适用于自定义类(如 hashtable[key]=val → hashtable.__setitem__(key, val)) - sub_asgn: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(target) - setitem_done: int = 0 - if sub_asgn is not None and sub_asgn.value is not None: - if sub_asgn.value.kind() == ast.ASTKind.Name: - sub_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_asgn.value) - if sub_nm.id is not None: - sub_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, sub_nm.id) - if sub_alloca is not None and sub_alloca.Ty is not None \ - and sub_alloca.Ty.Pointee is not None \ - and HandlesExpr.is_ptr_type(sub_alloca.Ty) != 0: - sub_pointee: llvmlite.LLVMType | t.CPtr = sub_alloca.Ty.Pointee - cls_nm_set: str = HandlesStruct.get_class_name_by_type(pool, sub_pointee) - obj_val_set: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, sub_pointee, sub_alloca) - # 指针类型变量 (X|t.CPtr): sub_pointee 是 Ptr(Struct), - # 需 load 获取 Ptr(Struct) 再检查 inner struct - if cls_nm_set is None and obj_val_set is not None \ - and HandlesExpr.is_ptr_type(sub_pointee) != 0 \ - and sub_pointee.Pointee is not None: - cls_nm_set = HandlesStruct.get_class_name_by_type( - pool, sub_pointee.Pointee) - if cls_nm_set is not None and obj_val_set is not None: - key_val_set: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, sub_asgn.slice, None, 0, trans) - if key_val_set is not None: - arg_vals_set: t.CSizeT | t.CPtr = pool.alloc(16) - if arg_vals_set is not None: - arg_vals_set[0] = t.CSizeT(key_val_set) - arg_vals_set[1] = t.CSizeT(rhs_val) - ExprCallCtor._call_method_on_ptr( - pool, builder, mod, cls_nm_set, "__setitem__", - obj_val_set, arg_vals_set, 2, trans) - setitem_done = 1 - elif sub_asgn.value.kind() == ast.ASTKind.Attribute: - # self._ht[key] = val → self._ht.__setitem__(key, val) - # 通过 get_attribute_ptr 获取字段指针,再调用 __setitem__ - field_ptr_set: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( - builder, pool, mod, sub_asgn.value, trans) - if field_ptr_set is not None and field_ptr_set.Ty is not None \ - and field_ptr_set.Ty.Pointee is not None \ - and HandlesExpr.is_ptr_type(field_ptr_set.Ty) != 0: - field_pointee_set: llvmlite.LLVMType | t.CPtr = field_ptr_set.Ty.Pointee - cls_nm_attr: str = HandlesStruct.get_class_name_by_type(pool, field_pointee_set) - obj_val_attr: llvmlite.Value | t.CPtr = field_ptr_set - # field_ptr 是 Ptr(Ptr(Struct)) (X|t.CPtr 字段): - # load 解引用获取 Ptr(Struct) - if cls_nm_attr is None \ - and HandlesExpr.is_ptr_type(field_pointee_set) != 0 \ - and field_pointee_set.Pointee is not None: - cls_nm_attr = HandlesStruct.get_class_name_by_type( - pool, field_pointee_set.Pointee) - if cls_nm_attr is not None: - obj_val_attr = llvmlite.build_load( - builder, field_pointee_set, field_ptr_set) - if cls_nm_attr is not None and obj_val_attr is not None: - key_val_attr: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, sub_asgn.slice, None, 0, trans) - if key_val_attr is not None: - arg_vals_attr: t.CSizeT | t.CPtr = pool.alloc(16) - if arg_vals_attr is not None: - arg_vals_attr[0] = t.CSizeT(key_val_attr) - arg_vals_attr[1] = t.CSizeT(rhs_val) - ExprCallCtor._call_method_on_ptr( - pool, builder, mod, cls_nm_attr, "__setitem__", - obj_val_attr, arg_vals_attr, 2, trans) - setitem_done = 1 - if setitem_done == 0: - # 通用 fallback: 翻译 sub.value 并尝试 __setitem__ 或直接 GEP+store - # 处理 Name/Attribute 之外的节点以及 SymTab 查找失败的情况 - if sub_asgn is not None and sub_asgn.value is not None: - obj_val_gen: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, sub_asgn.value, None, 0, trans) - key_val_gen: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, sub_asgn.slice, None, 0, trans) - if obj_val_gen is not None and key_val_gen is not None \ - and obj_val_gen.Ty is not None: - # 内联 _get_custom_struct_cls_nm 逻辑(避免依赖新函数) - cls_nm_gen: str = HandlesStruct.get_class_name_by_type( - pool, obj_val_gen.Ty) - if cls_nm_gen is None and HandlesExpr.is_ptr_type(obj_val_gen.Ty) != 0 \ - and obj_val_gen.Ty.Pointee is not None: - cls_nm_gen = HandlesStruct.get_class_name_by_type( - pool, obj_val_gen.Ty.Pointee) - if cls_nm_gen is not None: - # 自定义结构体: 调用 __setitem__ - arg_vals_gen: t.CSizeT | t.CPtr = pool.alloc(16) - if arg_vals_gen is not None: - arg_vals_gen[0] = t.CSizeT(key_val_gen) - arg_vals_gen[1] = t.CSizeT(rhs_val) - ExprCallCtor._call_method_on_ptr( - pool, builder, mod, cls_nm_gen, "__setitem__", - obj_val_gen, arg_vals_gen, 2, trans) - setitem_done = 1 - elif HandlesExpr.is_ptr_type(obj_val_gen.Ty) != 0 \ - and obj_val_gen.Ty.Pointee is not None: - # 非自定义结构体: 直接 GEP + store - # 处理 get_subscript_ptr 因边界情况返回 None 的指针下标 - elem_gen: llvmlite.LLVMType | t.CPtr = obj_val_gen.Ty.Pointee - store_val_gen: llvmlite.Value | t.CPtr = rhs_val - elem_ptr_gen: llvmlite.Value | t.CPtr = None - match elem_gen: - case llvmlite.LLVMType.Array(arr_elem_gen, _): - elem_ptr_gen = llvmlite.build_gep_array( - builder, elem_gen, arr_elem_gen, - obj_val_gen, key_val_gen) - case _: - elem_ptr_gen = llvmlite.build_gep( - builder, elem_gen, obj_val_gen, key_val_gen) - if elem_ptr_gen is not None and elem_ptr_gen.Ty is not None: - if elem_ptr_gen.Ty.Pointee is not None: - store_val_gen = HandlesExpr.coerce_to_type( - builder, rhs_val, elem_ptr_gen.Ty.Pointee, node) - llvmlite.build_store(builder, store_val_gen, elem_ptr_gen) - setitem_done = 1 - if setitem_done == 0: - HandlesType.fatal_error(target, "subscript ptr is None") - continue - - # Attribute 赋值: obj.field = val - if tk == ast.ASTKind.Attribute: - # property setter 拦截: obj.attr = v 且 attr 是 @x.setter 方法时, - # 生成 call Class.attr$set(obj, v),跳过字段存储 - # 注意参数顺序:_try_property_setter(pool, builder, mod, ...)—— - # 旧代码传 (builder, pool, ...) 导致 pool/builder 错位,pool 参数 - # 实际是 IRBuilder 对象,pool.alloc 虚调用读 IRBuilder[0] 当 vtable - # 跳到垃圾地址崩溃(BuiltinDecoratorTest Phase A 崩溃根因)。 - if ExprCallCtor._try_property_setter( - pool, builder, mod, target, rhs_val, trans) == 1: - continue - # FakeDuck: 影子结构体属性写入 (str 变量的 per-instance 字段) - # a.__data__ = v → GEP {a}__meta__[field] 并 store - # 对齐 TPC HandlesAssign.py L67-76:对象是 Name 变量且存在 - # {var}__meta__ 影子(fd2 创建)时,属性写入改走影子结构体。 - fd_an: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(target) - if fd_an is not None and fd_an.value is not None and fd_an.attr is not None: - if fd_an.value.kind() == ast.ASTKind.Name: - fd_obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(fd_an.value) - if fd_obj_nm.id is not None: - # pool 持久缓冲(f-string 栈缓冲在函数返回后失效) - fd_meta_w: str = pool.alloc(256) - if fd_meta_w is not None: - viperlib.snprintf(fd_meta_w, 256, "%s__meta__", fd_obj_nm.id) - fd_meta_vw: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( - trans.SymTab, fd_meta_w) - if fd_meta_vw is not None: - fd_sty_w: llvmlite.LLVMType | t.CPtr = \ - HandlesStruct.get_struct_type("_str") - if fd_sty_w is not None: - fd_fe_w: HandlesStruct.FieldEntry | t.CPtr = \ - HandlesStruct.lookup_field(fd_sty_w, fd_an.attr) - if fd_fe_w is not None and fd_fe_w.Ty is not None: - fd_fp_w: llvmlite.Value | t.CPtr = \ - llvmlite.build_gep_struct( - builder, fd_sty_w, fd_fe_w.Ty, - fd_meta_vw, fd_fe_w.Index) - if fd_fp_w is not None: - sv_fd: llvmlite.Value | t.CPtr = \ - HandlesExpr.coerce_to_type( - builder, rhs_val, fd_fe_w.Ty, node) - llvmlite.build_store(builder, sv_fd, fd_fp_w) - continue - # VTABLE 直接写入:obj.method = func(serial0_file.open = serial0_open) - # vtable 方法不是数据字段(FieldEntry),get_attribute_ptr 查不到会 - # fatal_error;此处对齐 TPC HandlesAssign.py L905-949 的写时复制, - # 检测到 vtable 方法时直接生成槽位写入并跳过字段路径。 - import lib.core.Gen.Generator as Generator - g_vtw: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( - t.CVoid(HandlesExpr._g_gen, t.CPtr)) - if g_vtw is not None: - if g_vtw._write_vtable_attr( - builder, pool, mod, target, rhs_val, trans) == 1: - continue - field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( - builder, pool, mod, target, trans) - if field_ptr is not None: - # 获取字段类型,对 rhs_val 进行类型转换(如 i32 → i64) - store_val: llvmlite.Value | t.CPtr = rhs_val - if field_ptr.Ty is not None and field_ptr.Ty.Pointee is not None: - store_val = HandlesExpr.coerce_to_type( - builder, rhs_val, field_ptr.Ty.Pointee, node) - llvmlite.build_store(builder, store_val, field_ptr) - continue - # 守卫:field_ptr 为 None → 构造详细错误信息 - # Phase A 依赖未就绪(_deps_pending):get_attribute_ptr 已因 - # 父类/依赖类未注册跳过字段,此处同样跳过不报错,整文件下遍重译 - # (对齐 HandlesAssign L69-78 与 get_attribute_ptr 的 pending 容忍) - if trans is not None and trans._deps_pending != 0: - continue - attr_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(target) - attr_name: str = "(unknown)" - obj_name: str = "(unknown)" - if attr_node is not None: - attr_name = attr_node.attr - if attr_node.value is not None and attr_node.value.kind() == ast.ASTKind.Name: - obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(attr_node.value) - obj_name = obj_nm.id - err_buf: str = pool.alloc(256) - if err_buf is not None: - viperlib.snprintf(err_buf, 256, - "attribute ptr is None: %s.%s", - obj_name, attr_name) - HandlesType.fatal_error(target, err_buf) - else: - HandlesType.fatal_error(target, "attribute ptr is None") - continue - - # Name 赋值: var = val - if tk == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) - # 守卫:target 名缺失时跳过 - if nm.id is None: - continue - # global 变量:写入模块作用域中的全局变量 - if HT.is_global_name(trans, nm.id) != 0: - mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( - trans.SymTab, nm.id) - if mod_alloca is None: - # fail-fast: global 变量未注册,无法赋值 - HandlesType.fatal_error( - target, - f"global 变量 '{nm.id}' 未注册,无法赋值", - "NameError") - target_ty: llvmlite.LLVMType | t.CPtr = None - if mod_alloca.Ty is not None: - target_ty = mod_alloca.Ty.Pointee - if target_ty is not None: - rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty, node) - llvmlite.build_store(builder, rhs_val, mod_alloca) - continue - - # nonlocal 变量:通过闭包 env 写入 - if HT.is_nonlocal_name(trans, nm.id) != 0: - nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr( - trans, nm.id) - if nl_ptr is None: - # fail-fast: nonlocal 变量指针解析失败 - HandlesType.fatal_error( - target, - f"nonlocal 变量 '{nm.id}' 指针解析失败", - "NameError") - # 从 nl_ptr 的类型推断 nonlocal 变量实际类型, - # 不再强制 i32(会截断指针/结构体/i64 导致闭包数据损坏) - nl_target_ty: llvmlite.LLVMType | t.CPtr = None - if nl_ptr.Ty is not None: - nl_target_ty = nl_ptr.Ty.Pointee - if nl_target_ty is None: - # fail-fast: nl_ptr 类型信息丢失,无法安全 store - HandlesType.fatal_error( - target, - f"nonlocal 变量 '{nm.id}' 类型信息丢失,无法写入", - "TypeError") - rhs_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( - builder, rhs_val, nl_target_ty, node) - llvmlite.build_store(builder, rhs_coerced, nl_ptr) - continue - - # 拦截:函数内对模块级全局变量赋值但没 global 声明 - # 否则静默创建局部变量遮蔽全局,全局保持 null 导致运行时崩溃 - # (_mbuddy = mb 缺 global 声明即此类 bug:Int32 解引用 null 崩溃) - if HandlesVar.is_module_scope(trans.SymTab) == 0: - mod_gv: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( - trans.SymTab, nm.id) - if mod_gv is not None: - fb_g: str = VLogger.fmt_buf() - msg_g: str = "global 声明缺失" - if fb_g is not None: - viperlib.snprintf(fb_g, 1024, "变量 '%s' 是模块级全局变量,函数内赋值需用 global 声明(否则创建局部变量遮蔽全局,导致全局保持 null 崩溃)", nm.id) - msg_g = fb_g - HandlesType.fatal_error(target, msg_g, "SyntaxError") - - # 普通局部变量 - alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym( - trans.SymTab, pool, builder, nm.id, rhs_val.Ty) - if alloca is not None: - # 无注解赋值:从 RHS 表达式推断类名设置变量注解 - # (联合类型 X|t.CPtr 简化为 Ptr(i8),属性访问按需过滤需要 - # AnnotClassName 才能定位结构体字段) - cls_inf: str = self._infer_rhs_annot(pool, mod, asgn.value, trans, rhs_val) - if cls_inf is not None: - HandlesVar.set_var_annot_class_name( - trans.SymTab, nm.id, cls_inf) - # 按 alloca 类型对值进行转换(如 double → float) - store_val: llvmlite.Value | t.CPtr = rhs_val - if alloca.Ty is not None and alloca.Ty.Pointee is not None: - store_val = HandlesExpr.coerce_to_type( - builder, rhs_val, alloca.Ty.Pointee, node) - llvmlite.build_store(builder, store_val, alloca) - # lambda 表达式赋给变量:注册为闭包变量名, - # 调用分派(is_closure_name)才走闭包间接调用路径; - # 否则 i8** alloca 被 _is_func_ptr_alloca 误判为 - # 函数指针,无参 call 直接跳闭包数据崩溃 - if asgn.value is not None \ - and asgn.value.kind() == ast.ASTKind.Lambda: - ExprCallCall.register_closure_name(nm.id) - existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( - trans.SymTab, nm.id) - if existing is None: - new_vars += 1 - else: - # fail-fast: 变量存储创建失败,立即终止 - HandlesType.fatal_error( - target, - f"变量 '{nm.id}' 存储创建失败", - "TypeError") - - return new_vars - - # ============================================================ - # _infer_rhs_annot - 从 RHS 表达式推断变量注解类名 - # - # 无注解赋值(如 v = Vec2(...) / v3 = v1 + v2)时,变量 AnnotClassName - # 缺失会导致后续属性访问(.x)无法"按需过滤":联合类型 X|t.CPtr 在 LLVM - # 中简化为 Ptr(i8),不携带类名,无法定位结构体字段(字段未找到 → fast-fail)。 - # 此函数按 RHS 结构推断类名: - # Call → 类实例化(func 为已注册结构体名才采用,避免普通函数误标); - # func 为 Attribute 时是方法调用(a.cross()),obj 类名 + - # 方法存在 + rhs_val 为指针类型(联合对象)三条件判定 - # Name → 源变量的 AnnotClassName - # BinOp/UnaryOp → lhs 类名 + 该类存在对应 dunder 方法(运算符重载返回同类对象) - # Attribute → 字段注解类名(委托 Generator 单例 _resolve_attr_field_class) - # 仅当目标为已注册结构体时采用,与"按需过滤,找不到 fast-fail"原则一致。 - # ============================================================ - def _infer_rhs_annot(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr, - rhs_val: llvmlite.Value | t.CPtr = None) -> str: - """从 RHS 表达式推断类名,无法推断返回 None""" - if node is None or trans is None: - return None - k: int = node.kind() - # Call: 类实例化 / 方法调用 - if k == ast.ASTKind.Call: - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) - if cl is None or cl.func is None: - return None - if cl.func.kind() == ast.ASTKind.Name: - # 类实例化:func 为已注册结构体名才采用 - cand: str = ((ast.Name | t.CPtr)(cl.func)).id - if cand is None: - return None - se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(cand) - if se is not None: - return cand - return None - if cl.func.kind() == ast.ASTKind.Attribute: - # 方法调用 a.cross(b):从 vpi 返回注解缓存精确解析返回类名 - # (方法可返回非同类对象,如 Transform.world_position → 'Vec3', - # 启发式取 obj 类名会 GEP 错字段)。vpi 未命中时返回 None, - # 由后续属性访问 fast-fail 暴露 vpi 缺失根因(不静默回退)。 - ca: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if ca is None or ca.attr is None or ca.value is None: - return None - obj_cls: str = self._infer_rhs_annot(pool, mod, ca.value, trans) - if obj_cls is None: - # 模块级函数调用(requests.get):ca.value 是已导入模块名 - # 而非对象变量(模块名 lookup_var_entry 返回 None → 上面 - # 对象类名推断失败)。从该模块 vpi 的返回注解缓存解析返回 - # 类名(键 {sha1}.{func},cls_name=None 即模块级函数,与 - # CallGenMixin 跨模块返回类型解析一致)。 - # WebTest resp = requests.get(...) 根因:无注解赋值变量 - # AnnotClassName 推断失败(annot=None)→ 属性访问按需过滤 - # (依赖 AnnotClassName)失效 → "属性访问失败: .status_code"。 - if ca.value.kind() == ast.ASTKind.Name: - mod_nm_rhs: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ca.value) - if mod_nm_rhs.id is not None: - mod_sha1_rhs: str = ExprCallBase._lookup_module_sha1( - mod_nm_rhs.id) - if mod_sha1_rhs is not None: - import lib.StubGen.VpiReader as VpiReader - temp_dir_rhs: str = None - import lib.core.Gen.Generator as Generator - g_rhs: Generator.Generator | t.CPtr = ( - Generator.Generator | t.CPtr)( - t.CVoid(HandlesExpr._g_gen, t.CPtr)) - if g_rhs is not None and g_rhs.TempDir is not None: - temp_dir_rhs = g_rhs.TempDir - if temp_dir_rhs is not None: - VpiReader._ensure_vpi_ret_annot_loaded( - mod_sha1_rhs, temp_dir_rhs) - annot_rhs: str = VpiReader._lookup_vpi_ret_annot( - mod_sha1_rhs, None, ca.attr) - if annot_rhs is not None: - ret_cls_rhs: str = self._extract_annot_class_name( - pool, annot_rhs) - if ret_cls_rhs is not None: - return ret_cls_rhs - return None - if self._cls_has_dunder(pool, mod, obj_cls, ca.attr) == 0: - return None - # 方法定义所在模块 SHA1(优先 struct entry,回退当前模块 sha1) - cls_sha1: str = HandlesStruct.get_struct_sha1(obj_cls) - if cls_sha1 is None and trans.ModuleSha1 is not None: - cls_sha1 = trans.ModuleSha1 - ret_cls: str = None - if cls_sha1 is not None: - import lib.StubGen.VpiReader as VpiReader - temp_dir: str = None - import lib.core.Gen.Generator as Generator - g2: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( - t.CVoid(HandlesExpr._g_gen, t.CPtr)) - if g2 is not None and g2.TempDir is not None: - temp_dir = g2.TempDir - if temp_dir is not None: - VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, temp_dir) - annot_ret: str = VpiReader._lookup_vpi_ret_annot( - cls_sha1, obj_cls, ca.attr) - if annot_ret is not None: - ret_cls = self._extract_annot_class_name(pool, annot_ret) - return ret_cls - return None - # Name: 源变量注解 - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm is None or nm.id is None: - return None - ve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm.id) - if ve is None: - return None - return ve.AnnotClassName - # BinOp/UnaryOp: 运算符重载返回同类对象 - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - if bop is None or bop.left is None: - return None - dunder: str = self._op_to_dunder(bop.op) - if dunder is None: - return None - lhs_cls: str = self._infer_rhs_annot(pool, mod, bop.left, trans) - if lhs_cls is None or self._cls_has_dunder(pool, mod, lhs_cls, dunder) == 0: - return None - return lhs_cls - if k == ast.ASTKind.UnaryOp: - uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) - if uop is None or uop.operand is None: - return None - dunder: str = self._op_to_dunder(uop.op) - if dunder is None: - return None - opr_cls: str = self._infer_rhs_annot(pool, mod, uop.operand, trans) - if opr_cls is None or self._cls_has_dunder(pool, mod, opr_cls, dunder) == 0: - return None - return opr_cls - # Attribute: 字段注解类名(属性链递归,如 p = r.origin) - if k == ast.ASTKind.Attribute: - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( - t.CVoid(HandlesExpr._g_gen, t.CPtr)) - if g is not None: - return g._resolve_attr_field_class(pool, trans, node) - return None - return None - - # ============================================================ - # _extract_annot_class_name - 从返回注解文本提取结构体类名 - # - # vpi 返回注解文本(如 "'Vec3' | CPtr")按 '|' 分段,每段去除 - # 空格/引号后查结构体注册表:命中即类名(内置类型 str/int/ - # CFloat64T/t.CPtr 等均不注册 struct,天然过滤)。"A | B" 联合 - # 多候选时取首个命中段。 - # ============================================================ - def _extract_annot_class_name(self, pool: memhub.MemBuddy | t.CPtr, - annot: str) -> str: - """从返回注解文本提取已注册结构体类名,无命中返回 None""" - if pool is None or annot is None: - return None - alen: t.CSizeT = string.strlen(annot) - if alen == 0: - return None - seg: str = pool.alloc(256) - if seg is None: - return None - start: t.CSizeT = 0 - i: t.CSizeT - for i in range(alen): - if annot[i] == '|': - seglen: t.CSizeT = i - start - # 段 [start, i):去除首尾空格与引号后查注册表 - s: t.CSizeT = start - e: t.CSizeT = i - while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'): - s += 1 - while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'): - e -= 1 - seglen = e - s - if seglen > 0 and seglen < 256: - string.strncpy(seg, annot + s, seglen) - seg[seglen] = '\0' - se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(seg) - if se is not None: - return seg - start = i + 1 - # 最后一段(无 '|' 后缀) - s: t.CSizeT = start - e: t.CSizeT = alen - while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'): - s += 1 - while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'): - e -= 1 - seglen: t.CSizeT = e - s - if seglen > 0 and seglen < 256: - string.strncpy(seg, annot + s, seglen) - seg[seglen] = '\0' - se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(seg) - if se is not None: - return seg - return None - - # ============================================================ - # _op_to_dunder - 运算符 → dunder 方法名(本地副本,避免跨 Mixin 调用) - # ============================================================ - def _op_to_dunder(self, op: int) -> str: - """BinOp/UnaryOp 运算符 → dunder 方法名,无映射返回 None""" - if op == ast.OpKind.Add: return "__add__" - if op == ast.OpKind.Sub: return "__sub__" - if op == ast.OpKind.Mult: return "__mul__" - if op == ast.OpKind.Div: return "__truediv__" - if op == ast.OpKind.FloorDiv: return "__floordiv__" - if op == ast.OpKind.Mod: return "__mod__" - if op == ast.OpKind.Pow: return "__pow__" - if op == ast.OpKind.BitAnd: return "__and__" - if op == ast.OpKind.BitOr: return "__or__" - if op == ast.OpKind.BitXor: return "__xor__" - if op == ast.OpKind.LShift: return "__lshift__" - if op == ast.OpKind.RShift: return "__rshift__" - if op == ast.OpKind.USub: return "__neg__" - if op == ast.OpKind.UAdd: return "__pos__" - if op == ast.OpKind.Invert: return "__invert__" - return None - - # ============================================================ - # _cls_has_dunder - 检查类(含继承链)是否存在 dunder 方法 - # - # 与 ExprGenMixin.try_operator_overload 的查找一致:当前模块内定义 - # 或跨模块类有 SHA1(stub 中声明)即视为存在。仅在确实存在时 - # 才采用运算符重载推断的类名,避免把原生运算误标为类类型。 - # ============================================================ - def _cls_has_dunder(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, dunder: str) -> int: - """类及其 MRO 祖先链中是否存在 dunder 方法,存在返回 1""" - if class_name is None or dunder is None or mod is None: - return 0 - lookup_name: str = pool.alloc(128) - if lookup_name is None: - return 0 - viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder) - if ExprCallBase.find_func_in_module(mod, lookup_name) is not None: - return 1 - # 继承链祖先查找 - mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name) - mi: int = 1 - while mro_ptr is not None and mro_ptr[mi] != 0: - anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr)) - if anc is not None: - anc_lookup: str = pool.alloc(128) - if anc_lookup is not None: - viperlib.snprintf(anc_lookup, 128, "%s.%s", anc, dunder) - if ExprCallBase.find_func_in_module(mod, anc_lookup) is not None: - return 1 - mi += 1 - # 跨模块:类有 SHA1(stub 中声明该方法)视为存在 - if HandlesStruct.get_struct_sha1(class_name) is not None: - return 1 - return 0 +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.Generator as Generator + +import lib.core.Gen.TypeGenCType as TypeGenCType + +import lib.core.Gen.ExprGenAttr as ExprGenAttr + +import lib.core.Gen.CallGenBase as CallGenBase + +import lib.core.Gen.CallGenFd as CallGenFd + +import lib.core.Gen.CallGenVt as CallGenVt + +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.StubMergerStore as StubMergerStore + + +# ============================================================ +# AssignGenMixin - 赋值翻译 Mixin(P6 方法化) +# +# 从 HandlesAssign/HandlesAnnAssign/HandlesAugAssign 迁移: +# 模块级无状态函数(trans/pool 首参)→ 类方法;全局状态 +# (HandlesAnnAssign._g_recover_found)→ 本类字段 RecoverFound。 +# +# 迁移原则(与 P1-P5 一致,行为零变化): +# 1. 方法保留原函数签名(含 trans/pool 首参),仅函数体内的 +# 本模块函数调用改为 self.xxx(...) +# 2. 外部模块调用(HandlesType.xxx/HandlesExpr.xxx 等)保留模块前缀 +# 3. 原 Handles 模块函数保留为"委托":本地模块级单例 _g_gen +# (BuildPipeline/main 注入)cast 成 Generator 类型 +# +# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 +# ============================================================ + + +@t.NoVTable +class AssignGenMixin: + Gen: Generator.Generator | t.CPtr + """赋值翻译 Mixin(P6 方法化)""" + + # --- 原 HandlesAnnAssign._g_recover_found 模块级全局(迁移为实例字段) --- + RecoverFound: int + + # ============================================================ + # is_cdefine_annotation - 检测注解是否为 t.CDefine(模块级函数) + # + # 支持两种形式: + # 1. Attribute(Name('t'), 'CDefine') + # 2. BinOp(... | Attribute(Name('t'), 'CDefine'))(联合注解) + # ============================================================ + def is_cdefine_annotation(self, annot: ast.AST | t.CPtr) -> int: + """检测注解是否为 t.CDefine,返回 1 表示是,0 表示否""" + if annot is None: + return 0 + k: int = annot.kind() + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot) + if at.attr is not None and string.strcmp(at.attr, "CDefine") == 0: + return 1 + return 0 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot) + if self.is_cdefine_annotation(bop.left) != 0: + return 1 + if self.is_cdefine_annotation(bop.right) != 0: + return 1 + return 0 + + # ============================================================ + # extract_cdefine_int_value - 从 AnnAssign.value 提取整数常量(模块级函数) + # + # 支持的表达式形式: + # 1. Constant(INT) — 如 0x0002, 42 + # 2. BinOp(BitOr/BitAnd) — 如 FOREGROUND_RED | FOREGROUND_GREEN + # 3. Name — 引用已注册的 CDefine 常量 + # 4. Call — 如 t.CUnsignedLong(-11) → 取第一个参数 + # 5. UnaryOp(USub/UAdd/Invert) — 如 -11 + # ============================================================ + def extract_cdefine_int_value(self, val_node: ast.AST | t.CPtr) -> t.CInt64T: + """从值节点提取整数常量(支持 Constant/BinOp/Name/Call/UnaryOp) + + 64 位返回:大整数 CDefine(如 sys.maxsize=9223372036854775807) + 必须全精度提取,否则 int(32 位) 截断成 -1(SysLibTest maxsize FAIL 根因)。 + """ + if val_node is None: + return 0 + k: int = val_node.kind() + + # Case 1: Constant(INT) — 如 0x0002 + if k == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(val_node) + # True/False 布尔常量 → 1/0(对齐 TPC:bool 在 CDefine 语境按整数处理, + # 如 SHADOW_ENABLED: t.CDefine = False) + if cn.const_kind == ast.CONST_BOOL: + return 1 if cn.int_val != 0 else 0 + if cn.const_kind != ast.CONST_INT: + # 非 INT 常量:直接报错终止(fail-fast) + self.Gen.TypeGenErr.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError") + return cn.int_val + + # Case 2: BinOp — 如 FOREGROUND_RED | FOREGROUND_GREEN、(1 << ZDEFLATE_WINDOW_BITS) + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(val_node) + left_val: t.CInt64T = self.extract_cdefine_int_value(bop.left) + right_val: t.CInt64T = self.extract_cdefine_int_value(bop.right) + if bop.op == ast.OpKind.BitOr: + return left_val | right_val + if bop.op == ast.OpKind.BitAnd: + return left_val & right_val + if bop.op == ast.OpKind.BitXor: + return left_val ^ right_val + if bop.op == ast.OpKind.LShift: + return left_val << right_val + if bop.op == ast.OpKind.RShift: + return left_val >> right_val + if bop.op == ast.OpKind.Add: + return left_val + right_val + if bop.op == ast.OpKind.Sub: + return left_val - right_val + if bop.op == ast.OpKind.Mult: + return left_val * right_val + if bop.op == ast.OpKind.Div: + # 整数常量除法:与 FloorDiv 一致(对齐 TPC ConstEvaluator L354-355) + return left_val // right_val + if bop.op == ast.OpKind.FloorDiv: + return left_val // right_val + if bop.op == ast.OpKind.Mod: + return left_val % right_val + # 未知 BinOp 运算符:直接报错终止(fail-fast) + self.Gen.TypeGenErr.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError") + + # Case 3: Name — 引用已注册的 CDefine 常量,或 True/False 布尔字面量 + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node) + if nm.id is not None: + # True/False 布尔字面量 → 1/0(对齐 TPC:bool 在 CDefine 语境按整数处理) + if string.strcmp(nm.id, "True") == 0: + return 1 + if string.strcmp(nm.id, "False") == 0: + return 0 + looked_up: t.CInt64T = self.Gen.TypeGenCDef.lookup_cdefine_constant(nm.id) + if self.Gen.TypeGenCDef.is_cdefine_found() != 0: + return looked_up + # 引用未注册:直接报错终止(fail-fast) + self.Gen.TypeGenErr.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError") + + # Case 4: Call — 如 t.CUnsignedLong(-11) + if k == ast.ASTKind.Call: + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(val_node) + # 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(), + # 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错 + cl_args_list: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cl_args_list is not None and len(cl_args_list) > 0: + first_arg: ast.AST | t.CPtr = cl_args_list.get(0) + arg_val: t.CInt64T = self.extract_cdefine_int_value(first_arg) + return arg_val + # Call 无参数:直接报错终止(fail-fast) + self.Gen.TypeGenErr.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError") + + # Case 5: UnaryOp — 如 -11 + if k == ast.ASTKind.UnaryOp: + uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(val_node) + operand_val: t.CInt64T = self.extract_cdefine_int_value(uop.operand) + if uop.op == ast.OpKind.USub: + return -operand_val + if uop.op == ast.OpKind.UAdd: + return operand_val + if uop.op == ast.OpKind.Invert: + return ~operand_val + # 未知 UnaryOp 运算符:直接报错终止(fail-fast) + self.Gen.TypeGenErr.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError") + + # 未知节点类型:直接报错终止(fail-fast) + self.Gen.TypeGenErr.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError") + # 追加89 块设计:fatal_error 调用后补显式 return(运行时不可达, + # 保证函数末尾块被正确 terminated,不做 noreturn 函数名白名单) + return 0 + + # ============================================================ + # _register_cdefine_from_value - 注册 CDefine 常量(浮点/整数自动识别) + # + # 浮点字面量(如 vipermath 的 U_M_PI: t.CDefine = 3.14159...)走 + # register_cdefine_double,否则 translate_value 查表得 0 生成 + # ret i32 0(llc 报错 "value doesn't match function result type")。 + # ============================================================ + def _register_cdefine_from_value(self, pool: memhub.MemBuddy | t.CPtr, + name: str, val_node: ast.AST | t.CPtr) -> None: + """注册 CDefine 常量(浮点字面量 → register_cdefine_double,否则整数)""" + if pool is None or name is None: + return + # Call 包装的常量:如 PI: t.CDefine = float(3.14159...) / + # t.CFloat64T(2.5) / t.CDouble(1.0)。取第一个参数作为真实值节点, + # 再按 Constant 分支处理(浮点 → register_cdefine_double)。 + if val_node is not None and val_node.kind() == ast.ASTKind.Call: + cl_cd: ast.Call | t.CPtr = (ast.Call | t.CPtr)(val_node) + if cl_cd is not None and cl_cd.args is not None: + cl_args_cd: list[ast.AST | t.CPtr] | t.CPtr = cl_cd.args + if cl_args_cd.__len__() > 0: + first_arg_cd: ast.AST | t.CPtr = cl_args_cd.get(0) + if first_arg_cd is not None and first_arg_cd.kind() == ast.ASTKind.Constant: + val_node = first_arg_cd + if val_node is not None and val_node.kind() == ast.ASTKind.Constant: + cn_fp: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(val_node) + if cn_fp.const_kind == ast.CONST_STR: + # 字符串 CDefine(如 ZLIB_VERSION: t.CDefine = "1.3.2"): + # 注册为字符串常量,读取端返回 global string(对齐 TPC)。 + self.Gen.TypeGenCDef.register_cdefine_string(pool, name, cn_fp.str_val) + return + if cn_fp.const_kind == ast.CONST_FLOAT: + # 源文件重读恢复(最可靠:AST 节点 float_val 可能被 pool 操作覆写, + # 源文件文本不受影响;用输出参数绕开跨模块 double 返回值传递 bug) + use_val: double = cn_fp.float_val + rec_d: t.CDouble = 0.0 + if self._recover_cdefine_float(name, t.CPtr(c.Addr(rec_d))) != 0: + use_val = rec_d + else: + # 源文件恢复失败:直接报错终止(fail-fast),避免注册被 pool 覆写的错误浮点值 + self.Gen.TypeGenErr.fatal_error(val_node, "CDefine 浮点值源文件恢复失败", "InternalCompilerError") + return + self.Gen.TypeGenCDef.register_cdefine_double(pool, name, use_val) + return + if val_node is None: + # CDefine 声明缺少值节点:直接报错终止(fail-fast) + self.Gen.TypeGenErr.fatal_error(None, f"CDefine 值提取失败:'{name}' 缺少初始值", "TypeError") + return + val_fp: t.CInt64T = self.extract_cdefine_int_value(val_node) + self.Gen.TypeGenCDef.register_cdefine_constant(pool, name, val_fp) + + # ============================================================ + # 源文件重读恢复 CDefine 浮点值 + # + # 背景:AST 节点的 float_val/str_val 字段可能被 pool 分配操作覆写 + # (MemBuddy 内存冲突),导致注册的浮点 CDefine 值错误(llc ret i32 0)。 + # 本函数直接读源文件找 "NAME: t.CDefine = value" 行,atof 解析 value—— + # 源文件文本不受 pool 影响,是最可靠的恢复路径。 + # + # 原模块级 _g_recover_found 全局已迁移为实例字段 self.RecoverFound。 + # ============================================================ + + def _recover_found(self) -> int: + """检查最近一次 _recover_cdefine_float 是否成功""" + return self.RecoverFound + + def _recover_cdefine_float(self, name: str, out: t.CDouble | t.CPtr) -> int: + """从当前模块源文件恢复浮点 CDefine 值,写入 out[0],成功返回 1 + + 用输出参数传递 double,避免 TPV 跨模块 double 返回值传递 bug。 + """ + self.RecoverFound = 0 + fp: str = self.Gen.TypeGenResolve.get_current_file() + if fp is None or name is None or out is None: + return 0 + f: fileio.File | t.CPtr = fileio.File(fp, fileio.MODE.R) + if f.closed: + return 0 + BUF_SZ: t.CSizeT = 1048576 + buf: bytes = stdlib.malloc(BUF_SZ) + if buf is None: + f.close() + return 0 + nrd: LONG = f.read_all(buf, BUF_SZ) + f.close() + if nrd <= 0: + stdlib.free(buf) + return 0 + if nrd < BUF_SZ: + buf[nrd] = 0 + else: + buf[BUF_SZ - 1] = 0 + + name_len: t.CSizeT = string.strlen(name) + total_len: t.CSizeT = string.strlen(buf) + pos: t.CSizeT = 0 + while pos < total_len: + line_start: t.CSizeT = pos + while pos < total_len and buf[pos] != '\n': + pos += 1 + line_len: t.CSizeT = pos - line_start + if pos < total_len: + pos += 1 + + # 匹配 "name:" + if line_len < name_len + 1: + continue + match_ok: int = 1 + ki: t.CSizeT + for ki in range(name_len): + if buf[line_start + ki] != name[ki]: + match_ok = 0 + break + if match_ok == 0: + continue + if buf[line_start + name_len] != ':': + continue + + # 行内包含 "t.CDefine" + has_cd: int = 0 + ci: t.CSizeT = line_start + name_len + 1 + while ci + 8 <= line_start + line_len: + if (buf[ci] == 't' and buf[ci + 1] == '.' and buf[ci + 2] == 'C' and + buf[ci + 3] == 'D' and buf[ci + 4] == 'e' and buf[ci + 5] == 'f' and + buf[ci + 6] == 'i' and buf[ci + 7] == 'n' and buf[ci + 8] == 'e'): + has_cd = 1 + break + ci += 1 + if has_cd == 0: + continue + + # 找 '=' + eq: t.CSizeT = line_start + while eq < line_start + line_len and buf[eq] != '=': + eq += 1 + if eq >= line_start + line_len: + continue + eq += 1 + while eq < line_start + line_len and buf[eq] == ' ': + eq += 1 + val_start: t.CSizeT = eq + while eq < line_start + line_len and buf[eq] != ' ' and buf[eq] != '\t' \ + and buf[eq] != '#' and buf[eq] != '\r' and buf[eq] != '\n': + eq += 1 + if eq == val_start: + continue + + val_txt: str = stdlib.malloc(eq - val_start + 1) + if val_txt is None: + stdlib.free(buf) + return 0 + vi: t.CSizeT + for vi in range(eq - val_start): + val_txt[vi] = buf[val_start + vi] + val_txt[eq - val_start] = 0 + stdlib.free(buf) + # 用 atof_out(输出参数)绕开跨模块 double 返回值传递 bug + if string.atof_out(val_txt, out) != 0: + self.RecoverFound = 1 + return 1 + return 0 + + stdlib.free(buf) + return 0 + + # ============================================================ + # _annotation_contains_name - 递归检查注解中是否包含指定名称 + # + # 支持 BinOp(BitOr) 递归,同时检查 Attribute.attr 和 Name.id。 + # ============================================================ + def _annotation_contains_name(self, annot: ast.AST | t.CPtr, name: str) -> int: + """递归检查注解中是否包含指定名称,返回 1=包含 / 0=不包含""" + if annot is None or name is None: + return 0 + k: int = annot.kind() + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot) + if at.attr is not None and string.strcmp(at.attr, name) == 0: + return 1 + return 0 + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annot) + if nm.id is not None and string.strcmp(nm.id, name) == 0: + return 1 + return 0 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot) + if self._annotation_contains_name(bop.left, name) != 0: + return 1 + if self._annotation_contains_name(bop.right, name) != 0: + return 1 + return 0 + + # ============================================================ + # _is_ptr_element_annotation - 检查注解是否为 bytes|t.CPtr 或 str|t.CPtr + # + # 返回 1=是(下标按 8 字节步长, i8** 语义), 0=否(下标按 1 字节步长, i8* 语义) + # + # 规则: + # bytes|t.CPtr / str|t.CPtr → i8**(8 字节步长)→ 返回 1 + # t.CChar|t.CPtr / t.CInt8T|t.CPtr → i8*(1 字节步长)→ 返回 0 + # 纯 bytes / str → i8*(1 字节步长)→ 返回 0 + # + # 注: 注解中的 "|" 是"和"的意思(组合类型),非右值中的位或运算 + # ============================================================ + def _is_ptr_element_annotation(self, annot: ast.AST | t.CPtr) -> int: + """检查注解是否为 bytes|t.CPtr 或 str|t.CPtr 形式""" + if annot is None: + return 0 + k: int = annot.kind() + if k != ast.ASTKind.BinOp: + return 0 + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot) + if bop.op != ast.OpKind.BitOr: + return 0 + if self._annotation_contains_name(annot, "str") != 0: + return 1 + if self._annotation_contains_name(annot, "bytes") != 0: + return 1 + # 泛型类型参数/嵌套联合 | t.CPtr(如 _list.vp 的 elem_ptr: T | t.CPtr): + # 先经泛型上下文解析 T 的具体类型——纯标量(int/float 等 sizeof≠8)时 + # 元素按标量自身大小(list[int] elem_size=4 匹配 i32),不能按 8 字节 + # 指针槽(否则 8 字节写 / 4 字节步长互相覆盖,pop 读到 0); + # 指针/嵌套联合/64 位标量/double(sizeof==8)才按 8 字节。 + if self._is_generic_tp_or_nested(bop.left) != 0 or self._is_generic_tp_or_nested(bop.right) != 0: + gp_nm: str = None + if bop.left is not None and bop.left.kind() == ast.ASTKind.Name: + gp_left_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bop.left) + gp_nm = gp_left_nm.id + elif bop.right is not None and bop.right.kind() == ast.ASTKind.Name: + gp_right_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bop.right) + gp_nm = gp_right_nm.id + if gp_nm is not None: + # 经全局 gen 委托解析泛型参数(T → 具体类型名)。不能 self.GenericTpNames + # 直读(Mixin @t.NoVTable 静态绑定:字段声明在 TypeGenMixin,AssignGenMixin + # 访问会生成不存在的属性引用 → TPC fast-fail 编译崩溃) + gp_resolved: str = self.Gen.TypeGenBase.resolve_generic_type_name(gp_nm) + if gp_resolved is not None and string.strcmp(gp_resolved, gp_nm) != 0: + # 泛型参数解析为纯标量 → 元素按标量自身大小(非 8 字节指针槽) + if self._is_scalar_ty_name(gp_resolved) != 0: + return 0 + return 1 + # 64 位标量数值类型 | CPtr(如 CUInt64T | CPtr / CSizeT | CPtr): + # 联合解析后同样退化为指针表示,元素为 8 字节(i64 或指针)。 + # 下标必须按 8 字节步长读写——否则 GEP 步长 1 + trunc i8 截断, + # 指针存进数组只剩低 1 字节(BuddyTest OOM/fill 的 ptrs 数组全错位: + # store i8 trunc i64、读回 inttoptr i8 丢高 56 位,free 全部无效)。 + if self._is_64bit_scalar_ty(bop.left) != 0 or self._is_64bit_scalar_ty(bop.right) != 0: + return 1 + return 0 + + def _is_64bit_scalar_ty(self, node: ast.AST | t.CPtr) -> int: + """判断类型节点是否为 64 位标量数值类型(CUInt64T/CInt64T/CSizeT),元素 8 字节""" + if node is None: + return 0 + ty_nm: str = None + nk: int = node.kind() + if nk == ast.ASTKind.Name: + nm64: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + ty_nm = nm64.id + elif nk == ast.ASTKind.Attribute: + at64: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + ty_nm = at64.attr + if ty_nm is None: + return 0 + if string.strcmp(ty_nm, "CUInt64T") == 0: + return 1 + if string.strcmp(ty_nm, "CInt64T") == 0: + return 1 + if string.strcmp(ty_nm, "CSizeT") == 0: + return 1 + return 0 + + def _is_scalar_ty_name(self, ty_name: str) -> int: + """判断类型名是否为已知纯标量(整数/浮点/字符),白名单判定 + + 泛型 T | t.CPtr(如 _list.vp 的 elem_ptr)经 Fix A(TypeGenMixin 联合 + 解析保留泛型标量)后 alloca 变 Ptr(标量):T 为纯标量(int/float/double/ + i64 等)时下标按标量自身大小步长,不能再按 8 字节指针槽——否则 + Ptr(标量) alloca + IsPtrElement 路径(load 标量当指针)产生非法 IR。 + 指针/联合/str/bytes 才保持 8 字节指针槽语义。 + + 原实现"排除 Ptr/str/bytes/| 后默认返回 1"把**未知类名**(如泛型上下文 + 污染产生的 llvmlite.Value)误判为标量 → IsPtrElement=0 → elem_ptr[0] + 走通用路径生成 Value* → list[str].get 声明 i8* 与 ret Value* 不匹配 + (8fbba llc 报错根因)。改白名单:已知标量才 1,未知类名按 8 字节指针槽。 + """ + if ty_name is None: + return 0 + if string.strchr(ty_name, '|') is not None: + return 0 + if string.strchr(ty_name, '*') is not None: + return 0 + if string.strcmp(ty_name, "str") == 0: + return 0 + if string.strcmp(ty_name, "bytes") == 0: + return 0 + if string.strcmp(ty_name, "t.CPtr") == 0: + return 0 + if string.strcmp(ty_name, "CPtr") == 0: + return 0 + if string.strstr(ty_name, "Ptr") is not None: + return 0 + # === 白名单:已知纯标量(基础名 + stdint 大写别名) === + if string.strcmp(ty_name, "int") == 0: return 1 + if string.strcmp(ty_name, "CInt") == 0: return 1 + if string.strcmp(ty_name, "CChar") == 0: return 1 + if string.strcmp(ty_name, "CUnsignedChar") == 0: return 1 + if string.strcmp(ty_name, "CShort") == 0: return 1 + if string.strcmp(ty_name, "CUnsignedShort") == 0: return 1 + if string.strcmp(ty_name, "CLong") == 0: return 1 + if string.strcmp(ty_name, "CUnsignedLong") == 0: return 1 + if string.strcmp(ty_name, "CLongLong") == 0: return 1 + if string.strcmp(ty_name, "CUnsignedLongLong") == 0: return 1 + if string.strcmp(ty_name, "CSizeT") == 0: return 1 + if string.strcmp(ty_name, "BOOL") == 0: return 1 + if string.strcmp(ty_name, "BYTE") == 0: return 1 + if string.strcmp(ty_name, "UCHAR") == 0: return 1 + if string.strcmp(ty_name, "CHAR") == 0: return 1 + if string.strcmp(ty_name, "SHORT") == 0: return 1 + if string.strcmp(ty_name, "USHORT") == 0: return 1 + if string.strcmp(ty_name, "LONG") == 0: return 1 + if string.strcmp(ty_name, "ULONG") == 0: return 1 + if string.strcmp(ty_name, "LONGLONG") == 0: return 1 + if string.strcmp(ty_name, "ULONGLONG") == 0: return 1 + if string.strcmp(ty_name, "INT") == 0: return 1 + if string.strcmp(ty_name, "UINT") == 0: return 1 + if string.strcmp(ty_name, "WORD") == 0: return 1 + if string.strcmp(ty_name, "DWORD") == 0: return 1 + if string.strcmp(ty_name, "QWORD") == 0: return 1 + # 定长整数/浮点(C*T 形式与裸别名,strstr 前缀匹配) + if string.strstr(ty_name, "Int8") is not None: return 1 + if string.strstr(ty_name, "Int16") is not None: return 1 + if string.strstr(ty_name, "Int32") is not None: return 1 + if string.strstr(ty_name, "Int64") is not None: return 1 + if string.strstr(ty_name, "UInt8") is not None: return 1 + if string.strstr(ty_name, "UInt16") is not None: return 1 + if string.strstr(ty_name, "UInt32") is not None: return 1 + if string.strstr(ty_name, "UInt64") is not None: return 1 + if string.strstr(ty_name, "Float") is not None: return 1 + if string.strstr(ty_name, "FLOAT") is not None: return 1 + if string.strstr(ty_name, "Double") is not None: return 1 + if string.strstr(ty_name, "DOUBLE") is not None: return 1 + # 未知类名(结构体/类/污染类型)→ 非标量,按 8 字节指针槽 + return 0 + + def _is_generic_tp_or_nested(self, node: ast.AST | t.CPtr) -> int: + """判断注解节点是否为泛型类型参数名(单字母大写,如 T)或嵌套联合(BinOp)""" + if node is None: + return 0 + nk: int = node.kind() + if nk == ast.ASTKind.BinOp: + return 1 + if nk == ast.ASTKind.Name: + nm_tp: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm_tp.id is None: + return 0 + tp_len: t.CSizeT = string.strlen(nm_tp.id) + if tp_len == 1: + if nm_tp.id[0] >= 65 and nm_tp.id[0] <= 90: + return 1 + return 0 + + # ============================================================ + # _init_global_array_from_list — 从列表字面量初始化全局数组 + # + # 为每个元素生成 GEP + store 指令,将值存入全局数组的对应位置。 + # 适用于模块级 t.CArray[elem_ty, count] = [v0, v1, ...] 的初始化。 + # + # Args: + # builder: IRBuilder + # pool: 编译器内存池 + # mod: LLVMModule + # array_alloca: 全局数组变量的 Value 引用(类型为 [N x elem_ty]*) + # list_node: ast.List 节点 + # trans: Translator 对象 + # + # Returns: + # 0 成功,1 失败 + # ============================================================ + def _init_global_array_from_list(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + array_alloca: llvmlite.Value | t.CPtr, + list_node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr) -> int: + """从列表字面量初始化全局数组,为每个元素生成 GEP + store""" + if builder is None or array_alloca is None or list_node is None: + return 1 + + # 获取数组类型(Pointee of [N x elem_ty]*) + arr_ty: llvmlite.LLVMType | t.CPtr = None + if array_alloca.Ty is not None: + arr_ty = array_alloca.Ty.Pointee + if arr_ty is None: + return 1 + + # 匹配数组类型获取元素类型 + elem_ty: llvmlite.LLVMType | t.CPtr = None + match arr_ty: + case llvmlite.LLVMType.Array(et, _): + elem_ty = et + if elem_ty is None: + return 1 + + # 获取列表元素 + lst: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node) + if lst is None or lst.elts is None: + return 1 + elts: list[ast.AST | t.CPtr] | t.CPtr = lst.elts + elts_count: t.CSizeT = len(elts) + + # 为每个元素生成 GEP + store + i: t.CSizeT = 0 + while i < elts_count: + elem_node: ast.AST | t.CPtr = elts.get(i) + elem_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, elem_node, None, 0, trans) + if elem_val is None: + # 元素翻译失败:直接报错终止(fail-fast),暴露上游根因 + self.Gen.TypeGenErr.fatal_error(elem_node, "全局数组初始化元素翻译失败", "TypeError") + idx_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, i) + elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( + builder, arr_ty, elem_ty, array_alloca, idx_val) + if elem_ptr is not None: + # 类型转换(如 i32 → i8 截断) + store_val: llvmlite.Value | t.CPtr = elem_val + if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None: + store_val = self.Gen.ExprGenBase.coerce_to_type( + builder, elem_val, elem_ptr.Ty.Pointee, elem_node) + llvmlite.build_store(builder, store_val, elem_ptr) + i += 1 + + return 0 + + # ============================================================ + # _apply_aug_op - 应用增强赋值的二元运算 + # + # 支持浮点运算、指针算术: ptr += int / ptr -= int + # 整数运算自动类型提升 + # ============================================================ + def _apply_aug_op(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + op: int, + lhs: llvmlite.Value | t.CPtr, + rhs: llvmlite.Value | t.CPtr, + node: ast.AST | t.CPtr = None, + trans: HT.Translator | t.CPtr = None, + lhs_node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """应用增强赋值的二元运算(浮点 + 指针算术 + 整数运算)""" + lhs_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(lhs.Ty) + rhs_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(rhs.Ty) + lhs_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(lhs.Ty) + rhs_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(rhs.Ty) + + # 浮点运算: 任一操作数为浮点时,使用浮点指令(必须在指针算术之前检查, + # 因为 float 的 int bits 为 0,会被误认为指针) + if lhs_fbits != 0 or rhs_fbits != 0: + # 确定目标浮点类型(使用较大的位宽) + target_fbits: int = lhs_fbits + if rhs_fbits > target_fbits: + target_fbits = rhs_fbits + target_float_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) + if target_fbits == 32: + target_float_ty = llvmlite.Float(pool) + # 将两个操作数转换为目标浮点类型(int→float via si2fp, float→float via fpext/fptrunc) + lhs = self.Gen.ExprGenBase.coerce_to_type(builder, lhs, target_float_ty, node) + rhs = self.Gen.ExprGenBase.coerce_to_type(builder, rhs, target_float_ty, node) + if op == ast.OpKind.Add: + return llvmlite.build_fadd(builder, lhs, rhs) + if op == ast.OpKind.Sub: + return llvmlite.build_fsub(builder, lhs, rhs) + if op == ast.OpKind.Mult: + return llvmlite.build_fmul(builder, lhs, rhs) + if op == ast.OpKind.Div: + return llvmlite.build_fdiv(builder, lhs, rhs) + if op == ast.OpKind.Mod: + return llvmlite.build_frem(builder, lhs, rhs) + return None + + # 指针算术: ptr += int / ptr -= int → getelementptr(按元素大小缩放) + # 对齐 TPC HandlesAugAssign.py L140-149 / L170-180 + if lhs_bits == 0 and rhs_bits != 0: + if op == ast.OpKind.Add or op == ast.OpKind.Sub: + return self.Gen.ExprGenBase.translate_ptr_arith(pool, builder, lhs, rhs, op) + return None + + # 整数运算:类型提升 + if lhs_bits > rhs_bits and rhs_bits > 0: + rhs = self.Gen.ExprGenBase.coerce_to_type(builder, rhs, lhs.Ty, node) + elif rhs_bits > lhs_bits and lhs_bits > 0: + lhs = self.Gen.ExprGenBase.coerce_to_type(builder, lhs, rhs.Ty, node) + + if op == ast.OpKind.Add: + return llvmlite.build_add(builder, lhs, rhs) + elif op == ast.OpKind.Sub: + return llvmlite.build_sub(builder, lhs, rhs) + elif op == ast.OpKind.Mult: + return llvmlite.build_mul(builder, lhs, rhs) + elif op == ast.OpKind.Div: + return llvmlite.build_sdiv(builder, lhs, rhs) + elif op == ast.OpKind.FloorDiv: + return llvmlite.build_sdiv(builder, lhs, rhs) + elif op == ast.OpKind.Mod: + return llvmlite.build_srem(builder, lhs, rhs) + elif op == ast.OpKind.BitAnd: + return llvmlite.build_and(builder, lhs, rhs) + elif op == ast.OpKind.BitOr: + return llvmlite.build_or(builder, lhs, rhs) + elif op == ast.OpKind.BitXor: + return llvmlite.build_xor(builder, lhs, rhs) + elif op == ast.OpKind.LShift: + return llvmlite.build_shl(builder, lhs, rhs) + elif op == ast.OpKind.RShift: + # 无符号 >> → lshr(逻辑右移),有符号 >> → ashr(算术右移) + # 对齐 TPC ExprGen.emit_binary_op:i8/i16 默认无符号;其余查操作数无符号性 + if lhs_bits == 8 or lhs_bits == 16: + return llvmlite.build_lshr(builder, lhs, rhs) + if lhs_node is not None and trans is not None: + if self.Gen.ExprGenOps._node_type_unsigned(pool, lhs_node, trans) != 0: + return llvmlite.build_lshr(builder, lhs, rhs) + return llvmlite.build_ashr(builder, lhs, rhs) + return None + + # ============================================================ + # translate_augassign - 增强赋值语句翻译(迁移自 HandlesAugAssign.AugAssignHandle.Handle) + # + # 支持 += -= *= /= %= &= |= ^= <<= >>=,local/global/nonlocal 三种作用域 + # ============================================================ + def translate_augassign(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译增强赋值语句 (x += 1, y -= 2, etc.)""" + if node is None: + return 0 + + aug: ast.AugAssign | t.CPtr = (ast.AugAssign | t.CPtr)(node) + if aug is None: + return 0 + + target: ast.AST | t.CPtr = aug.target + if target is None: + return 0 + + tk: int = target.kind() + + # Attribute 目标: self.field += 1 + # 流程: get_attribute_ptr → load → binop → store + if tk == ast.ASTKind.Attribute: + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + + # 1. 获取字段指针 + field_ptr: llvmlite.Value | t.CPtr = self.Gen.ExprGenAttr.get_attribute_ptr( + builder, pool, mod, target, trans) + if field_ptr is None: + # fail-fast: 属性指针解析失败 + self.Gen.TypeGenErr.fatal_error(target, "attribute ptr is None", "TypeError") + + # 2. 确定字段类型并加载当前值 + target_ty: llvmlite.LLVMType | t.CPtr = None + if field_ptr.Ty is not None and field_ptr.Ty.Pointee is not None: + target_ty = field_ptr.Ty.Pointee + if target_ty is None: + # fail-fast: 字段类型信息缺失,禁止兜底 i32 + self.Gen.TypeGenErr.fatal_error(target, "字段类型信息缺失", "TypeError") + cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, target_ty, field_ptr) + if cur_val is None: + # fail-fast: 属性当前值加载失败 + self.Gen.TypeGenErr.fatal_error(target, "无法加载 attribute 当前值", "TypeError") + + # 3. 翻译 RHS 值 + rhs_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, aug.value, None, 0, trans) + if rhs_val is None: + # fail-fast: RHS 翻译失败 + self.Gen.TypeGenErr.fatal_error(target, "rhs 翻译失败", "TypeError") + + # 4. 应用二元运算 + result: llvmlite.Value | t.CPtr = self._apply_aug_op( + pool, builder, aug.op, cur_val, rhs_val, node, trans, target) + if result is None: + # fail-fast: attribute 二元运算失败 + self.Gen.TypeGenErr.fatal_error(target, f"attribute 二元运算失败 op={aug.op}", "TypeError") + + # 5. 类型对齐并存储 + result = self.Gen.ExprGenBase.coerce_to_type(builder, result, target_ty, node) + if result is None: + # fail-fast: 类型对齐失败 + self.Gen.TypeGenErr.fatal_error(target, "类型对齐失败", "TypeError") + llvmlite.build_store(builder, result, field_ptr) + return 0 + + # Subscript 目标: self.state[i] += x / arr[i] += x + # 流程: get_subscript_ptr → load → binop → store + if tk == ast.ASTKind.Subscript: + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + + # 1. 获取元素指针 + elem_ptr: llvmlite.Value | t.CPtr = self.Gen.ExprGenName.get_subscript_ptr( + builder, pool, mod, target, trans) + if elem_ptr is None: + # fail-fast: 下标指针解析失败 + self.Gen.TypeGenErr.fatal_error(target, "subscript ptr is None", "TypeError") + + # 2. 确定元素类型并加载当前值 + target_ty: llvmlite.LLVMType | t.CPtr = None + if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None: + target_ty = elem_ptr.Ty.Pointee + if target_ty is None: + # fail-fast: 元素类型信息缺失,禁止兜底 i32 + self.Gen.TypeGenErr.fatal_error(target, "元素类型信息缺失", "TypeError") + cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, target_ty, elem_ptr) + if cur_val is None: + # fail-fast: 元素当前值加载失败 + self.Gen.TypeGenErr.fatal_error(target, "无法加载 subscript 元素当前值", "TypeError") + + # 3. 翻译 RHS 值 + rhs_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, aug.value, None, 0, trans) + if rhs_val is None: + # fail-fast: RHS 翻译失败 + self.Gen.TypeGenErr.fatal_error(target, "rhs 翻译失败", "TypeError") + + # 4. 应用二元运算 + result: llvmlite.Value | t.CPtr = self._apply_aug_op( + pool, builder, aug.op, cur_val, rhs_val, node, trans, target) + if result is None: + # fail-fast: subscript 二元运算失败 + self.Gen.TypeGenErr.fatal_error(target, f"subscript 二元运算失败 op={aug.op}", "TypeError") + + # 5. 类型对齐并存储 + result = self.Gen.ExprGenBase.coerce_to_type(builder, result, target_ty, node) + if result is None: + # fail-fast: 类型对齐失败 + self.Gen.TypeGenErr.fatal_error(target, "类型对齐失败", "TypeError") + llvmlite.build_store(builder, result, elem_ptr) + return 0 + + if tk != ast.ASTKind.Name: + # fail-fast: 不支持的 AugAssign 目标类型 + self.Gen.TypeGenErr.fatal_error( + target, "AugAssign 目标类型不支持,仅支持 Name/Attribute/Subscript", "TypeError") + + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) + if nm is None or nm.id is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + + # 1. 确定变量作用域类型: 0=local, 1=global, 2=nonlocal + scope_type: int = 0 + if HT.is_global_name(trans, nm.id) != 0: + scope_type = 1 + elif HT.is_nonlocal_name(trans, nm.id) != 0: + scope_type = 2 + + # 2. 加载当前值 + cur_val: llvmlite.Value | t.CPtr = None + target_alloca: llvmlite.Value | t.CPtr = None + target_ty: llvmlite.LLVMType | t.CPtr = None + + if scope_type == 1: + # global 变量 + target_alloca = self.Gen.VarGen.lookup_module_var( + trans.SymTab, nm.id) + if target_alloca is not None: + if target_alloca.Ty is None: + # fail-fast: 变量类型信息缺失,禁止兜底 i32 + self.Gen.TypeGenErr.fatal_error(target, "变量类型信息缺失", "TypeError") + target_ty = target_alloca.Ty.Pointee + cur_val = llvmlite.build_load(builder, target_ty, target_alloca) + elif scope_type == 2: + # nonlocal 变量(通过闭包 env) + cur_val = self.Gen.StmtGenDecl.load_nonlocal_var(trans, nm.id) + if cur_val is not None: + target_ty = cur_val.Ty + else: + # 普通局部变量 + target_alloca = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id) + if target_alloca is not None: + if target_alloca.Ty is None: + # fail-fast: 变量类型信息缺失,禁止兜底 i32 + self.Gen.TypeGenErr.fatal_error(target, "变量类型信息缺失", "TypeError") + target_ty = target_alloca.Ty.Pointee + cur_val = llvmlite.build_load(builder, target_ty, target_alloca) + + if cur_val is None: + # fail-fast: 目标变量当前值加载失败 + self.Gen.TypeGenErr.fatal_error( + target, + f"无法加载目标变量 '{nm.id}' 的当前值", + "TypeError") + + # 3. 翻译 RHS 值 + rhs_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, aug.value, None, 0, trans) + if rhs_val is None: + # fail-fast: RHS 翻译失败 + self.Gen.TypeGenErr.fatal_error(target, "rhs 翻译失败", "TypeError") + + # 4. 类型对齐 + 应用二元运算 + # 注意: AugAssign 不走运算符重载(语义上需要 __iadd__ 而非 __add__) + result: llvmlite.Value | t.CPtr = self._apply_aug_op( + pool, builder, aug.op, cur_val, rhs_val, node, trans, target) + if result is None: + # fail-fast: 二元运算失败 + self.Gen.TypeGenErr.fatal_error( + target, + f"对变量 '{nm.id}' 应用二元运算失败 op={aug.op}", + "TypeError") + + # 5. 存储结果 + result = self.Gen.ExprGenBase.coerce_to_type(builder, result, target_ty, node) + if result is None: + # fail-fast: 类型对齐失败 + self.Gen.TypeGenErr.fatal_error(target, "类型对齐失败", "TypeError") + + if scope_type == 1: + # global 变量 + if target_alloca is not None: + llvmlite.build_store(builder, result, target_alloca) + elif scope_type == 2: + # nonlocal 变量 + nl_ptr: llvmlite.Value | t.CPtr = self.Gen.StmtGenDecl.get_nonlocal_var_ptr( + trans, nm.id) + if nl_ptr is not None: + llvmlite.build_store(builder, result, nl_ptr) + else: + # 普通局部变量 + if target_alloca is not None: + llvmlite.build_store(builder, result, target_alloca) + + return 0 + + # ============================================================ + # is_ctypedef_annotation - 检测注解是否为 t.CTypedef + # + # 迁移自 HandlesAnnAssign.is_ctypedef_annotation(模块级委托壳); + # 真实实现 TypeGenCType._is_ctypedef_annotation 在另一 Mixin,经 + # gen 单例(HandlesExpr._g_gen 镜像)跨链调用。 + # ============================================================ + def is_ctypedef_annotation(self, annot: ast.AST | t.CPtr) -> int: + """检测注解是否为 t.CTypedef,返回 1 表示是,0 表示否""" + return self.Gen.TypeGenCType._is_ctypedef_annotation(annot) + + # ============================================================ + # _is_single_param_carray_annot - 检查注解是否为单参 t.CArray[elem_ty] + # + # 单参形式(t.CArray[elem_ty])与 count=None 形式(t.CArray[elem_ty, None]) + # 都解析为 Ptr(elem_ty)。当 RHS 是列表字面量时,按 TPC 语义应推断为 + # 静态数组 [len x elem_ty](对齐 TPC ParseListAnnotation 的 is_pointer 分支: + # "单参数 list[type] → 指针,但如果有列表字面量初始化值则按数组 list[type, N] 处理")。 + # ============================================================ + def _is_single_param_carray_annot(self, annot: ast.AST | t.CPtr) -> int: + """检查注解是否为单参/None 长度 t.CArray[...],返回 1=是 0=否 + + 支持两种书写形式: + 1. 模块限定 t.CArray[...](Attribute value) + 2. 裸名 CArray[...](from t import * 后使用,如 Termination4K3 core.vp + 的 `__python_suffix__: CArray[str] = ["py", ...]`) + """ + if annot is None or annot.kind() != ast.ASTKind.Subscript: + return 0 + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot) + if sub.value is None or sub.slice is None: + return 0 + if sub.value.kind() == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sub.value) + if at.attr is None or string.strcmp(at.attr, "CArray") != 0: + return 0 + if at.value is None or at.value.kind() != ast.ASTKind.Name: + return 0 + mv: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if mv.id is None or string.strcmp(mv.id, "t") != 0: + return 0 + elif sub.value.kind() == ast.ASTKind.Name: + # 裸名 CArray(from t import *):与 t.CArray 等价 + bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) + if bn.id is None or string.strcmp(bn.id, "CArray") != 0: + return 0 + else: + return 0 + # 单参形式:slice 非 Tuple(如 t.CArray[u64] / CArray[str]) + if sub.slice.kind() != ast.ASTKind.Tuple: + return 1 + # 双参形式:count=None(t.CArray[u64, None])→ 等价单参 + tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice) + if tup.elts is None or len(tup.elts) < 2: + return 0 + cnt_node: ast.AST | t.CPtr = tup.elts.get(1) + if cnt_node is not None and cnt_node.kind() == ast.ASTKind.Constant: + cn0: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(cnt_node) + if cn0.const_kind == ast.CONST_NONE: + return 1 + return 0 + + # ============================================================ + # _infer_static_array_ty_from_literal - 单参 CArray + 列表字面量 → 静态数组 + # + # 单参 t.CArray[elem_ty] 解析为 Ptr(elem_ty),但当 RHS 是列表字面量时, + # 按 TPC 语义应推断为 [len x elem_ty](对齐 TPC ParseListAnnotation): + # 避免误走动态 list 构造(_find_pool_var 兜底引用外部 @_mbuddy → 链接期 + # undefined)。PreScan 与 Handle 都调用(PreScan 预创建 alloca 的类型必须 + # 与 Handle 一致,否则 get_or_create_sym 复用旧 alloca 使推断失效)。 + # ============================================================ + def _infer_static_array_ty_from_literal(self, pool: memhub.MemBuddy | t.CPtr, + annot: ast.AST | t.CPtr, + value: ast.AST | t.CPtr, + resolved_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.LLVMType | t.CPtr: + """单参 CArray + 列表字面量 → Array(elem_ty, len);否则返回原类型""" + if value is not None and value.kind() == ast.ASTKind.List and resolved_ty is not None: + if self._is_single_param_carray_annot(annot) != 0: + elem_ty_arr: llvmlite.LLVMType | t.CPtr = resolved_ty.Pointee + lst_arr: ast.List | t.CPtr = (ast.List | t.CPtr)(value) + cnt_arr: int = 0 + if lst_arr.elts is not None: + cnt_arr = len(lst_arr.elts) + if elem_ty_arr is not None and cnt_arr > 0: + return llvmlite.Array(pool, elem_ty_arr, cnt_arr) + return resolved_ty + + # ============================================================ + # translate_annassign_prescan - 预扫描 AnnAssign(迁移自 + # HandlesAnnAssign.AnnAssignHandle.PreScan) + # + # 为有类型注解的变量提前创建 alloca 到 entry block 顶部;返回新增的变量数 + # ============================================================ + def translate_annassign_prescan(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """预扫描 AnnAssign,提前创建 alloca 到 entry block 顶部""" + if node is None: + return 0 + k: int = node.kind() + if k != ast.ASTKind.AnnAssign: + return 0 + + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) + if aa is None or aa.target is None: + return 0 + target: ast.AST | t.CPtr = aa.target + if target.kind() != ast.ASTKind.Name: + return 0 + + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) + if nm.id is None: + return 0 + + # CDefine 注解: 不创建 alloca,但注册常量到全局表 + # 供后续 t.CArray[elem_ty, NAME] 编译期解析使用 + # 浮点/整数自动识别(与 Handle/handle_module_level_var 路径一致) + if self.is_cdefine_annotation(aa.annotation) != 0: + pool_ps: memhub.MemBuddy | t.CPtr = trans.Pool + self._register_cdefine_from_value(pool_ps, nm.id, aa.value) + return 0 + + # CTypedef 注解: 类型别名(ScanCTypedefDeclarations 已注册到 CTypedef 表), + # 不创建全局/局部存储——否则 stdint.vp 的 float64_t: t.CTypedef = t.CFloat64T + # 等生成 @float64_t 符号,链接 duplicate symbol warning + if self.is_ctypedef_annotation(aa.annotation) != 0: + return 0 + + # global/nonlocal 变量不需要局部 alloca + if HT.is_global_name(trans, nm.id) != 0: + return 0 + if HT.is_nonlocal_name(trans, nm.id) != 0: + return 0 + + # 模块级全局变量已由 handle_module_level_var 注册到模块作用域。 + # Python 语义:仅模块级代码(Current == Root)时跳过局部 alloca; + # 函数内无 global 声明时应创建局部变量(不遮蔽全局)。 + if self.Gen.VarGen.is_module_scope(trans.SymTab) != 0: + if self.Gen.VarGen.lookup_module_var(trans.SymTab, nm.id) is not None: + return 0 + + # 检查是否已存在 + existing: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_current( + trans.SymTab, nm.id) + if existing is not None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + + # 从 annotation 推断类型(修复:原硬编码 i32 导致 str 等类型错误) + var_ty: llvmlite.LLVMType | t.CPtr = None + annot: ast.AST | t.CPtr = aa.annotation + if annot is not None: + resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, annot, trans._imported_modules, trans._from_imports, trans) + if resolved is None: + # 尝试特化泛型类注解(如 list[str]) + # resolve_annotation_type 返回 None 可能是因为泛型类未特化 + if annot.kind() == ast.ASTKind.Subscript: + sub_annot: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot) + if sub_annot.value is not None and sub_annot.value.kind() == ast.ASTKind.Name: + sub_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_annot.value) + if sub_nm.id is not None: + template_cd: ast.ClassDef | t.CPtr = self.Gen.ClassGenGeneric._find_generic_template(sub_nm.id) + spec_name_ps: str = None + if template_cd is not None: + type_args_ps: list[str] | t.CPtr = self.Gen.CallGenCtor._extract_type_args_from_slice(pool, sub_annot.slice) + if type_args_ps is not None and len(type_args_ps) > 0: + spec_name_ps = self.Gen.ClassGenGeneric._specialize_generic_class( + trans, sub_nm.id, type_args_ps) + if spec_name_ps is not None: + resolved = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, annot, trans._imported_modules, trans._from_imports, trans) + if resolved is not None: + var_ty = resolved + # 单参 t.CArray[elem_ty] + 列表字面量 → 静态数组(与 Handle 推断一致)。 + # PreScan 预创建的 alloca 类型必须与 Handle 期望一致,否则 Handle 的 + # get_or_create_sym 复用旧 alloca,数组推断失效仍走动态 list → _mbuddy。 + var_ty = self._infer_static_array_ty_from_literal(pool, annot, aa.value, var_ty) + else: + # fast-fail: 注解类型解析失败,Python traceback 立即终止(不静默回退 i32) + self.Gen.TypeGenErr.fatal_error( + aa, + f"变量类型注解解析失败,变量名: {nm.id}", + "TypeError") + else: + # fail-fast: AnnAssign 必须有 annotation,缺少时立即终止(禁止兜底 i32) + self.Gen.TypeGenErr.fatal_error( + aa, + f"AnnAssign 缺少类型注解,变量名: {nm.id}", + "SyntaxError") + + # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) + self.Gen.StructGen.ensure_struct_def_in_module(pool, trans.Module, var_ty) + alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen._alloca_at_entry(builder, var_ty) + if alloca is not None: + if self.Gen.VarGen.define_var( + trans.SymTab, nm.id, alloca) == 0: + # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) + # 传 pool:泛型 Subscript 返回 mangled name(GSList[BasicBlock] → 特化 + # struct 名),否则 pool=None 只返回裸类名(GSList → 泛型模板未注册 + # → 属性访问 lookup_field_by_class("GSList") 报"类未注册",LLVMLiteTest + # __function.vp blocks.Tail 根因;对齐 ClassGenMixin L3159 BUG 1 方案3) + if annot is not None: + cls_nm_ps: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation( + annot, trans._imported_modules, pool) + if cls_nm_ps is not None: + self.Gen.VarGen.set_var_annot_class_name( + trans.SymTab, nm.id, cls_nm_ps) + # 检查是否为 bytes|t.CPtr 或 str|t.CPtr(i8** 语义,8 字节步长) + if self._is_ptr_element_annotation(annot) != 0: + self.Gen.VarGen.set_var_ptr_element( + trans.SymTab, nm.id) + return 0 + return 0 + + # ============================================================ + # translate_annassign - 翻译 AnnAssign 语句(迁移自 + # HandlesAnnAssign.AnnAssignHandle.Handle) + # + # 返回新增的变量数 + # ============================================================ + def translate_annassign(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 AnnAssign(target=Name, annotation=..., value=expr)""" + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) + if aa is None: + return 0 + + target: ast.AST | t.CPtr = aa.target + if target is None or target.kind() != ast.ASTKind.Name: + return 0 + + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) + if nm.id is None: + return 0 + + # CDefine 注解: 编译期常量,不生成运行时代码 + # 注册到全局 CDefine 表供 t.CArray[elem_ty, NAME] 解析 + # 注: PreScan 已注册过,此处保证即使跳过 PreScan 也能正确注册 + if self.is_cdefine_annotation(aa.annotation) != 0: + pool_cd: memhub.MemBuddy | t.CPtr = trans.Pool + self._register_cdefine_from_value(pool_cd, nm.id, aa.value) + return 0 + + # CTypedef 注解: 类型别名(mode_t: t.CTypedef = t.CUInt32T 等)。 + # 翻译期 CTypedef 表已被 clear_ctypedefs 清空(每文件隔离;表字符串 + # pool 分配,reset_to(mark1) 回收后悬空,不能跨文件累积),必须在此 + # 按需注册,否则 posix.vp S_ISREG(mode: mode_t) 等普通函数参数注解 + # 解析查表失败 → NameError: mode_t。仅登记类型表达式,不创建全局/ + # 局部存储——否则生成 @mode_t 符号,链接 duplicate symbol warning。 + if self.is_ctypedef_annotation(aa.annotation) != 0: + pool_ct: memhub.MemBuddy | t.CPtr = trans.Pool + ctd_str: str = self.Gen.TypeGenResolve._get_type_name_from_annotation(pool_ct, aa.value) + if ctd_str is not None: + self.Gen.TypeGenCType.register_ctypedef(pool_ct, nm.id, ctd_str) + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + + # 确定类型(从 annotation 推断) + var_ty: llvmlite.LLVMType | t.CPtr = None + annot: ast.AST | t.CPtr = aa.annotation + if annot is not None: + resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, annot, trans._imported_modules, trans._from_imports, trans) + if resolved is not None: + var_ty = resolved + else: + # fast-fail: 注解类型解析失败,Python traceback 立即终止(不静默回退 i32) + self.Gen.TypeGenErr.fatal_error( + aa, + f"变量类型注解解析失败,变量名: {nm.id}", + "TypeError") + else: + # fail-fast: AnnAssign 必须有 annotation,缺少时立即终止(禁止兜底 i32) + self.Gen.TypeGenErr.fatal_error( + aa, + f"AnnAssign 缺少类型注解,变量名: {nm.id}", + "SyntaxError") + + # t.Callable 函数指针:注册返回类型签名(供函数指针间接调用精确返回类型) + callable_ret: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenErr.try_extract_callable_ret( + pool, annot, trans._imported_modules, trans._from_imports, trans) + if callable_ret is not None: + self.Gen.CallGenLeafKit.register_func_ptr_sig(nm.id, callable_ret) + + # global 变量:写入模块作用域中的全局变量 + if HT.is_global_name(trans, nm.id) != 0: + mod_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_module_var( + trans.SymTab, nm.id) + if mod_alloca is not None and aa.value is not None: + rhs_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, aa.value, + None, 0, trans) + if rhs_val is not None: + target_ty: llvmlite.LLVMType | t.CPtr = None + if mod_alloca.Ty is not None: + target_ty = mod_alloca.Ty.Pointee + if target_ty is not None: + rhs_val = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, target_ty, node) + llvmlite.build_store(builder, rhs_val, mod_alloca) + return 0 + + # nonlocal 变量:通过闭包 env 写入 + if HT.is_nonlocal_name(trans, nm.id) != 0: + if aa.value is not None: + rhs_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, aa.value, + None, 0, trans) + if rhs_val is not None: + nl_ptr: llvmlite.Value | t.CPtr = self.Gen.StmtGenDecl.get_nonlocal_var_ptr( + trans, nm.id) + if nl_ptr is not None: + # 从 nl_ptr 的类型推断 nonlocal 变量实际类型, + # 不再强制 i32(会截断指针/结构体/i64 导致闭包数据损坏) + nl_target_ty: llvmlite.LLVMType | t.CPtr = None + if nl_ptr.Ty is not None: + nl_target_ty = nl_ptr.Ty.Pointee + if nl_target_ty is None: + # fast-fail: nl_ptr 类型信息丢失,无法安全 store + VLogger.error( + f"nonlocal 变量类型信息丢失,无法写入: {nm.id}", + "HandlesAnnAssign") + return 0 + rhs_coerced: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type( + builder, rhs_val, nl_target_ty, node) + llvmlite.build_store(builder, rhs_coerced, nl_ptr) + return 0 + + # 模块级全局变量(由 handle_module_level_var 注册到模块作用域) + # Python 语义:仅模块级代码(Current == Root)时修改全局变量; + # 函数内无 global 声明时应创建局部变量(走后面的 get_or_create_sym 路径)。 + if self.Gen.VarGen.is_module_scope(trans.SymTab) != 0: + mod_glob: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_module_var( + trans.SymTab, nm.id) + else: + mod_glob = None + if mod_glob is not None: + if aa.value is not None: + # 列表字面量 → 逐元素 GEP + store 初始化数组 + if aa.value.kind() == ast.ASTKind.List: + self._init_global_array_from_list( + builder, pool, mod, mod_glob, aa.value, trans) + else: + rhs_val_mg: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, aa.value, + None, 0, trans) + if rhs_val_mg is not None: + target_ty_mg: llvmlite.LLVMType | t.CPtr = None + if mod_glob.Ty is not None: + target_ty_mg = mod_glob.Ty.Pointee + if target_ty_mg is not None: + rhs_val_mg = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val_mg, target_ty_mg, node) + llvmlite.build_store(builder, rhs_val_mg, mod_glob) + return 0 + + # 单参 t.CArray[elem_ty] + 列表字面量 → 按静态数组处理(count 从字面量长度推断) + # 与 PreScan 推断一致:get_or_create_sym 复用 PreScan 创建的 alloca, + # 类型一致才能命中局部数组快路径,避免 _find_pool_var 兜底引用 @_mbuddy。 + var_ty = self._infer_static_array_ty_from_literal(pool, annot, aa.value, var_ty) + + # 普通局部变量 + # 创建 alloca + alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.get_or_create_sym( + trans.SymTab, pool, builder, nm.id, var_ty) + if alloca is None: + # fail-fast: 存储创建失败,立即终止(禁止静默跳过) + self.Gen.TypeGenErr.fatal_error( + aa, + f"无法为变量 {nm.id} 创建存储", + "TypeError") + # FakeDuck: str 变量创建影子结构体 {var}__meta__(per-instance 字段存储) + # 仅裸 str 注解(Name("str"))且 _str 已注册时创建;bytes / t.CChar|t.CPtr 不创建。 + # a 保持为 i8*(可 printf/len),a__meta__ 存 __data__/__mbuddy__ 等字段, + # 属性读写(fd3)与方法调用(fd5)均通过该影子解析。 + fd_str_ty: llvmlite.LLVMType | t.CPtr = None + fd_meta_alloca: llvmlite.Value | t.CPtr = None + fd_meta_name: str = None + if annot is not None and annot.kind() == ast.ASTKind.Name: + fd_annot: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annot) + if fd_annot is not None and fd_annot.id is not None: + if string.strcmp(fd_annot.id, "str") == 0: + fd_str_ty = self.Gen.StructGen.get_struct_type("_str") + if fd_str_ty is not None: + # 确保 _str 完整类型定义在当前模块可用:跨模块结构体默认 opaque, + # 直接 alloca opaque 类型 → llc "Cannot allocate unsized type" + self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, fd_str_ty) + # 影子变量名必须用 pool 持久缓冲:f-string 生成栈缓冲,在 AnnAssign + # 返回后被覆盖,符号表注册的名字内容损坏 → 后续 lookup 找不到。 + fd_meta_name = pool.alloc(256) + if fd_meta_name is not None: + viperlib.snprintf(fd_meta_name, 256, "%s__meta__", nm.id) + fd_meta_alloca = self.Gen.VarGen.get_or_create_sym( + trans.SymTab, pool, builder, fd_meta_name, fd_str_ty) + if fd_meta_alloca is None: + # fail-fast: 影子存储创建失败,立即终止 + self.Gen.TypeGenErr.fatal_error( + aa, + f"无法为 str 影子变量 {fd_meta_name} 创建存储", + "TypeError") + # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) + # 传 pool:泛型 Subscript 返回 mangled name(对齐 L401 同根因修复) + if annot is not None: + cls_nm_hd: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation( + annot, trans._imported_modules, pool) + if cls_nm_hd is not None: + self.Gen.VarGen.set_var_annot_class_name( + trans.SymTab, nm.id, cls_nm_hd) + # 检查是否为 bytes|t.CPtr 或 str|t.CPtr(i8** 语义,8 字节步长) + if self._is_ptr_element_annotation(annot) != 0: + self.Gen.VarGen.set_var_ptr_element( + trans.SymTab, nm.id) + + new_vars: int = 0 + existing: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_current( + trans.SymTab, nm.id) + if existing is None: + new_vars = 1 + + # 如果有初始值,store + if aa.value is not None: + # 局部数组:列表字面量 → 逐元素 GEP + store 初始化 + # 修复:此前局部 CArray[...] = [x, y] 会走 translate_list_literal, + # 错误触发 list[T] 泛型特化(堆对象)导致崩溃(如 this.vp 的 + # t.CArray[t.CChar, 256] = [0])。局部 alloca 未零初始化, + # 先整体置零再写列表元素(与全局数组默认零初始化语义一致)。 + local_arr_ty: llvmlite.LLVMType | t.CPtr = None + if aa.value.kind() == ast.ASTKind.List and alloca.Ty is not None: + pt_l: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if self.Gen.ExprGenBase.is_array_type(pt_l) != 0: + local_arr_ty = pt_l + if local_arr_ty is not None: + zero_arr: llvmlite.Value | t.CPtr = llvmlite.ConstZero( + pool, local_arr_ty) + if zero_arr is not None: + llvmlite.build_store(builder, zero_arr, alloca) + self._init_global_array_from_list( + builder, pool, mod, alloca, aa.value, trans) + else: + # 供 c.Deref(i8*) 推断读取宽度:v: int = c.Deref(p) → 读 i32 + # CurAssignNode 记录 RHS 节点:translate_c_deref 据此判定 Deref + # 是否为赋值直接 RHS(对齐 TPC _infer_deref_target_type)。 + trans.CurAssignAnnot = aa.annotation + trans.CurAssignNode = aa.value + rhs_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, aa.value, + None, 0, trans) + if rhs_val is not None: + # 注解退化修复(对齐 TPC 从构造结果推断类型): + # 无实参泛型模板类注解(如 vi: vector.Vector | CPtr,模板 + # 未注册 struct → resolve 退化)会让 alloca 类型退化为 + # Ptr(i8),但 rhs 构造返回精确结构体指针(如 Ptr(Vector[int] + # 结构))。此时按退化 alloca store 会丢失特化类型,后续 + # vi.push 方法调用按 Ptr(i8) 查不到类名 → AnnotClassName + # 回退到模板名(无实参)→ vpi 查不到返回类型 fail-fast。 + # 用 rhs 精确类型重建 alloca 并更新符号表注册,使方法调用 + # 按精确特化类名解析。旧退化 alloca 行残留为 entry block + # 死代码(文本 IR 即时生成,无法删除,无害)。 + precise_rhs_ty: llvmlite.LLVMType | t.CPtr = None + if rhs_val.Ty is not None: + match rhs_val.Ty: + case llvmlite.LLVMType.Ptr(inner_struct): + match inner_struct: + case llvmlite.LLVMType.Struct(_, _, _): + precise_rhs_ty = rhs_val.Ty + case _: + pass + case _: + pass + if precise_rhs_ty is not None and alloca.Ty is not None: + alloca_pt: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if alloca_pt is not None and \ + t.CUInt64T(alloca_pt) != t.CUInt64T(precise_rhs_ty): + new_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen._alloca_at_entry( + builder, precise_rhs_ty) + if new_alloca is not None: + v_entry_rb: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, nm.id) + if v_entry_rb is not None: + v_entry_rb.Alloca = new_alloca + alloca = new_alloca + # 类型转换:将 rhs_val 转换为 alloca 的 pointee 类型 + # 修复:整数字面量是 i32,但变量可能是 i8/i16/i64,需 trunc/sext + target_ty: llvmlite.LLVMType | t.CPtr = None + if alloca.Ty is not None: + target_ty = alloca.Ty.Pointee + if target_ty is not None: + rhs_val = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, target_ty, node) + llvmlite.build_store(builder, rhs_val, alloca) + # FakeDuck: 初始化影子结构体 __data__ 字段 = 初始字符串指针 + # (对齐 TPC HandlesAnnAssign.py: 仅当有初值时写入 __data__) + if fd_str_ty is not None and fd_meta_alloca is not None: + fd_data_fe: GenTypes.FieldEntry | t.CPtr = \ + self.Gen.StructGen.lookup_field(fd_str_ty, "__data__") + if fd_data_fe is not None: + fd_data_ptr: llvmlite.Value | t.CPtr = \ + llvmlite.build_gep_struct( + builder, fd_str_ty, fd_data_fe.Ty, + fd_meta_alloca, fd_data_fe.Index) + if fd_data_ptr is not None: + llvmlite.build_store(builder, rhs_val, fd_data_ptr) + # 清除赋值上下文(防残留):CurAssignAnnot/CurAssignNode 只在该 + # AnnAssign 的 RHS 翻译期间有效,否则后续 while 条件/比较等处的 + # c.Deref 会被残留注解误判读取宽度(i8* 被 bitcast i32* 读 4 字节)。 + trans.CurAssignAnnot = None + trans.CurAssignNode = None + + # FakeDuck: __mbuddy__ 字段初始化为 NULL。 + # with 上下文提供的 __mbuddy__ 注入由 _inject_requires_fields(fd4)完成, + # 此处仅确保影子结构体初始为空指针(对齐 TPC HandlesAnnAssign.py L667-670)。 + if fd_str_ty is not None and fd_meta_alloca is not None: + fd_buddy_fe: GenTypes.FieldEntry | t.CPtr = \ + self.Gen.StructGen.lookup_field(fd_str_ty, "__mbuddy__") + if fd_buddy_fe is not None and fd_buddy_fe.Ty is not None: + fd_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull( + pool, fd_buddy_fe.Ty, "null") + fd_buddy_ptr: llvmlite.Value | t.CPtr = \ + llvmlite.build_gep_struct( + builder, fd_str_ty, fd_buddy_fe.Ty, + fd_meta_alloca, fd_buddy_fe.Index) + if fd_buddy_ptr is not None and fd_null is not None: + llvmlite.build_store(builder, fd_null, fd_buddy_ptr) + # FakeDuck: with 上下文自动注入 requires 字段(如 __mbuddy__)。 + # 跨 Mixin 经 self.Gen 调用 CallGenFd._inject_requires_fields。 + self.Gen.CallGenFd._inject_requires_fields( + trans, pool, builder, mod, fd_meta_alloca, "_str") + + return 0 + + # ============================================================ + # translate_assign - 处理 Assign 语句,返回新增变量数(0 或 1) + # + # 迁移自 HandlesAssign.AssignHandle.Handle(对应 TransPyC + # AssignHandle._HandleAssignLlvm)。共享状态从 trans 获取。 + # ============================================================ + def translate_assign(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 Assign 语句,返回新增变量数(0 或 1)""" + asgn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node) + if asgn is None: + VLogger.error("cast failed", "ASGN") + return 0 + + targets: list[ast.AST | t.CPtr] | t.CPtr = asgn.targets + if targets is None: + VLogger.error("targets is None", "ASGN") + return 0 + + # 从 trans 取共享状态(替代 11 个参数) + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + + # 翻译 RHS 值 + # 无注解赋值无目标类型可推断,清空 CurAssignAnnot/CurAssignNode + # (防残留误判 c.Deref 宽度) + trans.CurAssignAnnot = None + trans.CurAssignNode = None + rhs_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, asgn.value, None, 0, trans) + if rhs_val is None: + # Phase A 依赖未就绪(_deps_pending=1):跨模块函数/方法因 text.ll + # 未生成返回类型退化为 void/None(CallGenMixin L4493 + # g_vta._resolve_attr_field_class 根因)。此时整文件不写盘、下遍重译 + # (Phase2.vp L590-599),跳过本语句不报错——否则 fatal 使多遍 + # 重试机制永远无法收敛(本语句只是"本遍保持默认类型"的退化结果, + # 下遍依赖已生成即可精确解析)。依赖就绪时 _deps_pending=0, + # 此处仍 fail-fast,不掩盖真实错误。 + if trans is not None and trans._deps_pending != 0: + return 0 + # 增强错误信息:包含文件名 + lineno + AST 节点详情,便于定位 + fb: str = VLogger.fmt_buf() + if fb is not None and asgn.value is not None: + sha1: str = trans.ModuleSha1 + val_kind: int = asgn.value.kind() + val_line: t.CInt = asgn.value.lineno + # 通过 sha1 查找文件名(人类可读) + rel_path: str = None + if sha1 is not None: + rel_path = StubMergerStore.LookupSha1RelPath(sha1) + # 根据 AST 节点类型提取详情 + if val_kind == ast.ASTKind.Attribute: + at_nv: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(asgn.value) + attr_nm: str = at_nv.attr + target_nm: str = "?" + if at_nv.value is not None: + if at_nv.value.kind() == ast.ASTKind.Name: + tn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_nv.value) + target_nm = tn_nm.id + if rel_path is not None: + viperlib.snprintf(fb, 1024, + "赋值右侧为 None: %s:%d '%s.%s' 属性访问失败", + rel_path, val_line, target_nm, attr_nm) + else: + viperlib.snprintf(fb, 1024, + "赋值右侧为 None: sha1=%s:%d '%s.%s' 属性访问失败", + sha1, val_line, target_nm, attr_nm) + elif val_kind == ast.ASTKind.Name: + nm_nv: ast.Name | t.CPtr = (ast.Name | t.CPtr)(asgn.value) + if rel_path is not None: + viperlib.snprintf(fb, 1024, + "赋值右侧为 None: %s:%d 变量 '%s' 未找到", + rel_path, val_line, nm_nv.id) + else: + viperlib.snprintf(fb, 1024, + "赋值右侧为 None: sha1=%s:%d 变量 '%s' 未找到", + sha1, val_line, nm_nv.id) + elif val_kind == ast.ASTKind.Call: + cl_nv: ast.Call | t.CPtr = (ast.Call | t.CPtr)(asgn.value) + func_nm: str = "?" + if cl_nv.func is not None: + if cl_nv.func.kind() == ast.ASTKind.Name: + fn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl_nv.func) + func_nm = fn_nm.id + if rel_path is not None: + viperlib.snprintf(fb, 1024, + "赋值右侧为 None: %s:%d 调用 '%s(...)' 返回 None", + rel_path, val_line, func_nm) + else: + viperlib.snprintf(fb, 1024, + "赋值右侧为 None: sha1=%s:%d 调用 '%s(...)' 返回 None", + sha1, val_line, func_nm) + else: + if rel_path is not None: + viperlib.snprintf(fb, 1024, + "赋值右侧为 None: %s:%d [kind=%d]", + rel_path, val_line, val_kind) + else: + viperlib.snprintf(fb, 1024, + "赋值右侧为 None: sha1=%s:%d [kind=%d]", + sha1, val_line, val_kind) + VLogger.error(fb, "ASGN") + else: + VLogger.error("赋值右侧为 None (asgn.value 为空)", "ASGN") + return 0 + + new_vars: int = 0 + tn: t.CSizeT = len(targets) + for ti in range(tn): + target: ast.AST | t.CPtr = targets.get(ti) + if target is None: + continue + + tk: int = target.kind() + + # Tuple 赋值: a, b = f() 多返回值解包 + # rhs_val 是匿名 struct 值(函数返回 tuple[T1,T2] 打包)→ alloca + + # store + GEP 逐字段 load → store 到各 Name 目标。 + if tk == ast.ASTKind.Tuple: + tgt_tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(target) + tgt_elts: list[ast.AST | t.CPtr] | t.CPtr = tgt_tup.elts + # 守卫:rhs 不是 struct(tuple 打包)时跳过本 target + if tgt_elts is None or rhs_val is None or rhs_val.Ty is None: + continue + match rhs_val.Ty: + case llvmlite.LLVMType.Struct(_, _, _): + tgt_n: t.CSizeT = len(tgt_elts) + tmp_s: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, rhs_val.Ty) + if tmp_s is not None: + llvmlite.build_store(builder, rhs_val, tmp_s) + fchain: llvmlite.ParamNode | t.CPtr = llvmlite.get_struct_fields(rhs_val.Ty) + fcur: llvmlite.ParamNode | t.CPtr = fchain + fti: t.CSizeT + for fti in range(tgt_n): + tgt_elt: ast.AST | t.CPtr = tgt_elts.get(fti) + if tgt_elt is None or fcur is None: + break + fty: llvmlite.LLVMType | t.CPtr = llvmlite.paramnode_get_ty(fcur) + fcur = llvmlite.paramnode_get_next(fcur) + if fty is None: + # fail-fast: 字段类型缺失,立即终止 + self.Gen.TypeGenErr.fatal_error(target, "元组解包字段类型缺失", "TypeError") + # 守卫:非 Name 元素无法解包,跳过 + if tgt_elt.kind() != ast.ASTKind.Name: + continue + tgt_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tgt_elt) + if tgt_nm2.id is None: + continue + fp2: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, rhs_val.Ty, fty, tmp_s, fti) + if fp2 is None: + continue + fv2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, fty, fp2) + tgt_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, tgt_nm2.id) + if tgt_alloca is None: + tgt_alloca = self.Gen.VarGen.get_or_create_sym( + trans.SymTab, pool, builder, tgt_nm2.id, fty) + if tgt_alloca is None: + continue + sval: llvmlite.Value | t.CPtr = fv2 + if tgt_alloca.Ty is not None and tgt_alloca.Ty.Pointee is not None: + sval = self.Gen.ExprGenBase.coerce_to_type( + builder, fv2, tgt_alloca.Ty.Pointee, node) + llvmlite.build_store(builder, sval, tgt_alloca) + case _: + pass + continue + + # Subscript 赋值: arr[i] = val / ptr[i] = val / list[i] = val + if tk == ast.ASTKind.Subscript: + # 检查是否是 list[T] 类型的 Subscript(泛型类不注册 struct) + # list 的 subscript 赋值走 __setitem__ 内联路径 + list_obj: llvmlite.Value | t.CPtr = self.Gen.ExprGenName.is_list_subscript( + target, trans) + if list_obj is not None: + # list[T] 类型: 内联生成 __setitem__ 逻辑 + sub_node: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(target) + if sub_node is not None and sub_node.slice is not None: + list_idx_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, sub_node.slice, None, 0, trans) + if list_idx_val is None: + # fail-fast: list 下标翻译失败,立即终止 + self.Gen.TypeGenErr.fatal_error(target, "list 下标翻译失败", "TypeError") + self.Gen.ExprGenName.list_setitem_inline( + builder, pool, list_obj, list_idx_val, rhs_val, target) + continue + # 普通 Subscript 赋值 + elem_ptr: llvmlite.Value | t.CPtr = self.Gen.ExprGenName.get_subscript_ptr( + builder, pool, mod, target, trans) + if elem_ptr is not None: + store_val: llvmlite.Value | t.CPtr = rhs_val + # 守卫短路:elem 类型完整才做类型转换 + if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None: + store_val = self.Gen.ExprGenBase.coerce_to_type( + builder, rhs_val, elem_ptr.Ty.Pointee, node) + llvmlite.build_store(builder, store_val, elem_ptr) + continue + # get_subscript_ptr 返回 None: 尝试 __setitem__ 运算符重载 + # 适用于自定义类(如 hashtable[key]=val → hashtable.__setitem__(key, val)) + sub_asgn: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(target) + setitem_done: int = 0 + if sub_asgn is not None and sub_asgn.value is not None: + if sub_asgn.value.kind() == ast.ASTKind.Name: + sub_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_asgn.value) + if sub_nm.id is not None: + sub_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, sub_nm.id) + if sub_alloca is not None and sub_alloca.Ty is not None \ + and sub_alloca.Ty.Pointee is not None \ + and self.Gen.ExprGenBase.is_ptr_type(sub_alloca.Ty) != 0: + sub_pointee: llvmlite.LLVMType | t.CPtr = sub_alloca.Ty.Pointee + cls_nm_set: str = self.Gen.StructGen.get_class_name_by_type(pool, sub_pointee) + obj_val_set: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, sub_pointee, sub_alloca) + # 指针类型变量 (X|t.CPtr): sub_pointee 是 Ptr(Struct), + # 需 load 获取 Ptr(Struct) 再检查 inner struct + if cls_nm_set is None and obj_val_set is not None \ + and self.Gen.ExprGenBase.is_ptr_type(sub_pointee) != 0 \ + and sub_pointee.Pointee is not None: + cls_nm_set = self.Gen.StructGen.get_class_name_by_type( + pool, sub_pointee.Pointee) + if cls_nm_set is not None and obj_val_set is not None: + key_val_set: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, sub_asgn.slice, None, 0, trans) + if key_val_set is not None: + arg_vals_set: t.CSizeT | t.CPtr = pool.alloc(16) + if arg_vals_set is not None: + arg_vals_set[0] = t.CSizeT(key_val_set) + arg_vals_set[1] = t.CSizeT(rhs_val) + self.Gen.CallGenCall._call_method_on_ptr( + pool, builder, mod, cls_nm_set, "__setitem__", + obj_val_set, arg_vals_set, 2, trans) + setitem_done = 1 + elif sub_asgn.value.kind() == ast.ASTKind.Attribute: + # self._ht[key] = val → self._ht.__setitem__(key, val) + # 通过 get_attribute_ptr 获取字段指针,再调用 __setitem__ + field_ptr_set: llvmlite.Value | t.CPtr = self.Gen.ExprGenAttr.get_attribute_ptr( + builder, pool, mod, sub_asgn.value, trans) + if field_ptr_set is not None and field_ptr_set.Ty is not None \ + and field_ptr_set.Ty.Pointee is not None \ + and self.Gen.ExprGenBase.is_ptr_type(field_ptr_set.Ty) != 0: + field_pointee_set: llvmlite.LLVMType | t.CPtr = field_ptr_set.Ty.Pointee + cls_nm_attr: str = self.Gen.StructGen.get_class_name_by_type(pool, field_pointee_set) + obj_val_attr: llvmlite.Value | t.CPtr = field_ptr_set + # field_ptr 是 Ptr(Ptr(Struct)) (X|t.CPtr 字段): + # load 解引用获取 Ptr(Struct) + if cls_nm_attr is None \ + and self.Gen.ExprGenBase.is_ptr_type(field_pointee_set) != 0 \ + and field_pointee_set.Pointee is not None: + cls_nm_attr = self.Gen.StructGen.get_class_name_by_type( + pool, field_pointee_set.Pointee) + if cls_nm_attr is not None: + obj_val_attr = llvmlite.build_load( + builder, field_pointee_set, field_ptr_set) + if cls_nm_attr is not None and obj_val_attr is not None: + key_val_attr: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, sub_asgn.slice, None, 0, trans) + if key_val_attr is not None: + arg_vals_attr: t.CSizeT | t.CPtr = pool.alloc(16) + if arg_vals_attr is not None: + arg_vals_attr[0] = t.CSizeT(key_val_attr) + arg_vals_attr[1] = t.CSizeT(rhs_val) + self.Gen.CallGenCall._call_method_on_ptr( + pool, builder, mod, cls_nm_attr, "__setitem__", + obj_val_attr, arg_vals_attr, 2, trans) + setitem_done = 1 + if setitem_done == 0: + # 通用 fallback: 翻译 sub.value 并尝试 __setitem__ 或直接 GEP+store + # 处理 Name/Attribute 之外的节点以及 SymTab 查找失败的情况 + if sub_asgn is not None and sub_asgn.value is not None: + obj_val_gen: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, sub_asgn.value, None, 0, trans) + key_val_gen: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, sub_asgn.slice, None, 0, trans) + if obj_val_gen is not None and key_val_gen is not None \ + and obj_val_gen.Ty is not None: + # 内联 _get_custom_struct_cls_nm 逻辑(避免依赖新函数) + cls_nm_gen: str = self.Gen.StructGen.get_class_name_by_type( + pool, obj_val_gen.Ty) + if cls_nm_gen is None and self.Gen.ExprGenBase.is_ptr_type(obj_val_gen.Ty) != 0 \ + and obj_val_gen.Ty.Pointee is not None: + cls_nm_gen = self.Gen.StructGen.get_class_name_by_type( + pool, obj_val_gen.Ty.Pointee) + if cls_nm_gen is not None: + # 自定义结构体: 调用 __setitem__ + arg_vals_gen: t.CSizeT | t.CPtr = pool.alloc(16) + if arg_vals_gen is not None: + arg_vals_gen[0] = t.CSizeT(key_val_gen) + arg_vals_gen[1] = t.CSizeT(rhs_val) + self.Gen.CallGenCall._call_method_on_ptr( + pool, builder, mod, cls_nm_gen, "__setitem__", + obj_val_gen, arg_vals_gen, 2, trans) + setitem_done = 1 + elif self.Gen.ExprGenBase.is_ptr_type(obj_val_gen.Ty) != 0 \ + and obj_val_gen.Ty.Pointee is not None: + # 非自定义结构体: 直接 GEP + store + # 处理 get_subscript_ptr 因边界情况返回 None 的指针下标 + elem_gen: llvmlite.LLVMType | t.CPtr = obj_val_gen.Ty.Pointee + store_val_gen: llvmlite.Value | t.CPtr = rhs_val + elem_ptr_gen: llvmlite.Value | t.CPtr = None + match elem_gen: + case llvmlite.LLVMType.Array(arr_elem_gen, _): + elem_ptr_gen = llvmlite.build_gep_array( + builder, elem_gen, arr_elem_gen, + obj_val_gen, key_val_gen) + case _: + elem_ptr_gen = llvmlite.build_gep( + builder, elem_gen, obj_val_gen, key_val_gen) + if elem_ptr_gen is not None and elem_ptr_gen.Ty is not None: + if elem_ptr_gen.Ty.Pointee is not None: + store_val_gen = self.Gen.ExprGenBase.coerce_to_type( + builder, rhs_val, elem_ptr_gen.Ty.Pointee, node) + llvmlite.build_store(builder, store_val_gen, elem_ptr_gen) + setitem_done = 1 + if setitem_done == 0: + self.Gen.TypeGenErr.fatal_error(target, "subscript ptr is None") + continue + + # Attribute 赋值: obj.field = val + if tk == ast.ASTKind.Attribute: + # property setter 拦截: obj.attr = v 且 attr 是 @x.setter 方法时, + # 生成 call Class.attr$set(obj, v),跳过字段存储 + # 注意参数顺序:_try_property_setter(pool, builder, mod, ...)—— + # 旧代码传 (builder, pool, ...) 导致 pool/builder 错位,pool 参数 + # 实际是 IRBuilder 对象,pool.alloc 虚调用读 IRBuilder[0] 当 vtable + # 跳到垃圾地址崩溃(BuiltinDecoratorTest Phase A 崩溃根因)。 + if self.Gen.CallGenProp._try_property_setter( + pool, builder, mod, target, rhs_val, trans) == 1: + continue + # FakeDuck: 影子结构体属性写入 (str 变量的 per-instance 字段) + # a.__data__ = v → GEP {a}__meta__[field] 并 store + # 对齐 TPC HandlesAssign.py L67-76:对象是 Name 变量且存在 + # {var}__meta__ 影子(fd2 创建)时,属性写入改走影子结构体。 + fd_an: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(target) + if fd_an is not None and fd_an.value is not None and fd_an.attr is not None: + if fd_an.value.kind() == ast.ASTKind.Name: + fd_obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(fd_an.value) + if fd_obj_nm.id is not None: + # pool 持久缓冲(f-string 栈缓冲在函数返回后失效) + fd_meta_w: str = pool.alloc(256) + if fd_meta_w is not None: + viperlib.snprintf(fd_meta_w, 256, "%s__meta__", fd_obj_nm.id) + fd_meta_vw: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_current( + trans.SymTab, fd_meta_w) + if fd_meta_vw is not None: + fd_sty_w: llvmlite.LLVMType | t.CPtr = \ + self.Gen.StructGen.get_struct_type("_str") + if fd_sty_w is not None: + fd_fe_w: GenTypes.FieldEntry | t.CPtr = \ + self.Gen.StructGen.lookup_field(fd_sty_w, fd_an.attr) + if fd_fe_w is not None and fd_fe_w.Ty is not None: + fd_fp_w: llvmlite.Value | t.CPtr = \ + llvmlite.build_gep_struct( + builder, fd_sty_w, fd_fe_w.Ty, + fd_meta_vw, fd_fe_w.Index) + if fd_fp_w is not None: + sv_fd: llvmlite.Value | t.CPtr = \ + self.Gen.ExprGenBase.coerce_to_type( + builder, rhs_val, fd_fe_w.Ty, node) + llvmlite.build_store(builder, sv_fd, fd_fp_w) + continue + # VTABLE 直接写入:obj.method = func(serial0_file.open = serial0_open) + # vtable 方法不是数据字段(FieldEntry),get_attribute_ptr 查不到会 + # fatal_error;此处对齐 TPC HandlesAssign.py L905-949 的写时复制, + # 检测到 vtable 方法时直接生成槽位写入并跳过字段路径。 + if self.Gen.CallGenVt._write_vtable_attr( + builder, pool, mod, target, rhs_val, trans) == 1: + continue + field_ptr: llvmlite.Value | t.CPtr = self.Gen.ExprGenAttr.get_attribute_ptr( + builder, pool, mod, target, trans) + if field_ptr is not None: + # 获取字段类型,对 rhs_val 进行类型转换(如 i32 → i64) + store_val: llvmlite.Value | t.CPtr = rhs_val + if field_ptr.Ty is not None and field_ptr.Ty.Pointee is not None: + store_val = self.Gen.ExprGenBase.coerce_to_type( + builder, rhs_val, field_ptr.Ty.Pointee, node) + llvmlite.build_store(builder, store_val, field_ptr) + continue + # 守卫:field_ptr 为 None → 构造详细错误信息 + # Phase A 依赖未就绪(_deps_pending):get_attribute_ptr 已因 + # 父类/依赖类未注册跳过字段,此处同样跳过不报错,整文件下遍重译 + # (对齐 HandlesAssign L69-78 与 get_attribute_ptr 的 pending 容忍) + if trans is not None and trans._deps_pending != 0: + continue + attr_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(target) + attr_name: str = "(unknown)" + obj_name: str = "(unknown)" + if attr_node is not None: + attr_name = attr_node.attr + if attr_node.value is not None and attr_node.value.kind() == ast.ASTKind.Name: + obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(attr_node.value) + obj_name = obj_nm.id + err_buf: str = pool.alloc(256) + if err_buf is not None: + viperlib.snprintf(err_buf, 256, + "attribute ptr is None: %s.%s", + obj_name, attr_name) + self.Gen.TypeGenErr.fatal_error(target, err_buf) + else: + self.Gen.TypeGenErr.fatal_error(target, "attribute ptr is None") + continue + + # Name 赋值: var = val + if tk == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) + # 守卫:target 名缺失时跳过 + if nm.id is None: + continue + # global 变量:写入模块作用域中的全局变量 + if HT.is_global_name(trans, nm.id) != 0: + mod_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_module_var( + trans.SymTab, nm.id) + if mod_alloca is None: + # fail-fast: global 变量未注册,无法赋值 + self.Gen.TypeGenErr.fatal_error( + target, + f"global 变量 '{nm.id}' 未注册,无法赋值", + "NameError") + target_ty: llvmlite.LLVMType | t.CPtr = None + if mod_alloca.Ty is not None: + target_ty = mod_alloca.Ty.Pointee + if target_ty is not None: + rhs_val = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, target_ty, node) + llvmlite.build_store(builder, rhs_val, mod_alloca) + continue + + # nonlocal 变量:通过闭包 env 写入 + if HT.is_nonlocal_name(trans, nm.id) != 0: + nl_ptr: llvmlite.Value | t.CPtr = self.Gen.StmtGenDecl.get_nonlocal_var_ptr( + trans, nm.id) + if nl_ptr is None: + # fail-fast: nonlocal 变量指针解析失败 + self.Gen.TypeGenErr.fatal_error( + target, + f"nonlocal 变量 '{nm.id}' 指针解析失败", + "NameError") + # 从 nl_ptr 的类型推断 nonlocal 变量实际类型, + # 不再强制 i32(会截断指针/结构体/i64 导致闭包数据损坏) + nl_target_ty: llvmlite.LLVMType | t.CPtr = None + if nl_ptr.Ty is not None: + nl_target_ty = nl_ptr.Ty.Pointee + if nl_target_ty is None: + # fail-fast: nl_ptr 类型信息丢失,无法安全 store + self.Gen.TypeGenErr.fatal_error( + target, + f"nonlocal 变量 '{nm.id}' 类型信息丢失,无法写入", + "TypeError") + rhs_coerced: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type( + builder, rhs_val, nl_target_ty, node) + llvmlite.build_store(builder, rhs_coerced, nl_ptr) + continue + + # 拦截:函数内对模块级全局变量赋值但没 global 声明 + # 否则静默创建局部变量遮蔽全局,全局保持 null 导致运行时崩溃 + # (_mbuddy = mb 缺 global 声明即此类 bug:Int32 解引用 null 崩溃) + if self.Gen.VarGen.is_module_scope(trans.SymTab) == 0: + mod_gv: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_module_var( + trans.SymTab, nm.id) + if mod_gv is not None: + fb_g: str = VLogger.fmt_buf() + msg_g: str = "global 声明缺失" + if fb_g is not None: + viperlib.snprintf(fb_g, 1024, "变量 '%s' 是模块级全局变量,函数内赋值需用 global 声明(否则创建局部变量遮蔽全局,导致全局保持 null 崩溃)", nm.id) + msg_g = fb_g + self.Gen.TypeGenErr.fatal_error(target, msg_g, "SyntaxError") + + # 普通局部变量 + alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.get_or_create_sym( + trans.SymTab, pool, builder, nm.id, rhs_val.Ty) + if alloca is not None: + # 无注解赋值:从 RHS 表达式推断类名设置变量注解 + # (联合类型 X|t.CPtr 简化为 Ptr(i8),属性访问按需过滤需要 + # AnnotClassName 才能定位结构体字段) + cls_inf: str = self._infer_rhs_annot(pool, mod, asgn.value, trans, rhs_val) + if cls_inf is not None: + self.Gen.VarGen.set_var_annot_class_name( + trans.SymTab, nm.id, cls_inf) + # 按 alloca 类型对值进行转换(如 double → float) + store_val: llvmlite.Value | t.CPtr = rhs_val + if alloca.Ty is not None and alloca.Ty.Pointee is not None: + store_val = self.Gen.ExprGenBase.coerce_to_type( + builder, rhs_val, alloca.Ty.Pointee, node) + llvmlite.build_store(builder, store_val, alloca) + # lambda 表达式赋给变量:注册为闭包变量名, + # 调用分派(is_closure_name)才走闭包间接调用路径; + # 否则 i8** alloca 被 _is_func_ptr_alloca 误判为 + # 函数指针,无参 call 直接跳闭包数据崩溃 + if asgn.value is not None \ + and asgn.value.kind() == ast.ASTKind.Lambda: + self.Gen.CallGenLeafKit.register_closure_name(nm.id) + existing: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_current( + trans.SymTab, nm.id) + if existing is None: + new_vars += 1 + else: + # fail-fast: 变量存储创建失败,立即终止 + self.Gen.TypeGenErr.fatal_error( + target, + f"变量 '{nm.id}' 存储创建失败", + "TypeError") + + return new_vars + + # ============================================================ + # _infer_rhs_annot - 从 RHS 表达式推断变量注解类名 + # + # 无注解赋值(如 v = Vec2(...) / v3 = v1 + v2)时,变量 AnnotClassName + # 缺失会导致后续属性访问(.x)无法"按需过滤":联合类型 X|t.CPtr 在 LLVM + # 中简化为 Ptr(i8),不携带类名,无法定位结构体字段(字段未找到 → fast-fail)。 + # 此函数按 RHS 结构推断类名: + # Call → 类实例化(func 为已注册结构体名才采用,避免普通函数误标); + # func 为 Attribute 时是方法调用(a.cross()),obj 类名 + + # 方法存在 + rhs_val 为指针类型(联合对象)三条件判定 + # Name → 源变量的 AnnotClassName + # BinOp/UnaryOp → lhs 类名 + 该类存在对应 dunder 方法(运算符重载返回同类对象) + # Attribute → 字段注解类名(委托 Generator 单例 _resolve_attr_field_class) + # 仅当目标为已注册结构体时采用,与"按需过滤,找不到 fast-fail"原则一致。 + # ============================================================ + def _infer_rhs_annot(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr, + rhs_val: llvmlite.Value | t.CPtr = None) -> str: + """从 RHS 表达式推断类名,无法推断返回 None""" + if node is None or trans is None: + return None + k: int = node.kind() + # Call: 类实例化 / 方法调用 + if k == ast.ASTKind.Call: + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + if cl is None or cl.func is None: + return None + if cl.func.kind() == ast.ASTKind.Name: + # 类实例化:func 为已注册结构体名才采用 + cand: str = ((ast.Name | t.CPtr)(cl.func)).id + if cand is None: + return None + se: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(cand) + if se is not None: + return cand + return None + if cl.func.kind() == ast.ASTKind.Attribute: + # 方法调用 a.cross(b):从 vpi 返回注解缓存精确解析返回类名 + # (方法可返回非同类对象,如 Transform.world_position → 'Vec3', + # 启发式取 obj 类名会 GEP 错字段)。vpi 未命中时返回 None, + # 由后续属性访问 fast-fail 暴露 vpi 缺失根因(不静默回退)。 + ca: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if ca is None or ca.attr is None or ca.value is None: + return None + obj_cls: str = self._infer_rhs_annot(pool, mod, ca.value, trans) + if obj_cls is None: + # 模块级函数调用(requests.get):ca.value 是已导入模块名 + # 而非对象变量(模块名 lookup_var_entry 返回 None → 上面 + # 对象类名推断失败)。从该模块 vpi 的返回注解缓存解析返回 + # 类名(键 {sha1}.{func},cls_name=None 即模块级函数,与 + # CallGenMixin 跨模块返回类型解析一致)。 + # WebTest resp = requests.get(...) 根因:无注解赋值变量 + # AnnotClassName 推断失败(annot=None)→ 属性访问按需过滤 + # (依赖 AnnotClassName)失效 → "属性访问失败: .status_code"。 + if ca.value.kind() == ast.ASTKind.Name: + mod_nm_rhs: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ca.value) + if mod_nm_rhs.id is not None: + mod_sha1_rhs: str = self.Gen.CallGenBase._lookup_module_sha1( + mod_nm_rhs.id) + if mod_sha1_rhs is not None: + import lib.StubGen.VpiReader as VpiReader + temp_dir_rhs: str = None + if self.Gen.CallGenBase.TempDir is not None: + temp_dir_rhs = self.Gen.CallGenBase.TempDir + if temp_dir_rhs is not None: + VpiReader._ensure_vpi_ret_annot_loaded( + mod_sha1_rhs, temp_dir_rhs) + annot_rhs: str = VpiReader._lookup_vpi_ret_annot( + mod_sha1_rhs, None, ca.attr) + if annot_rhs is not None: + ret_cls_rhs: str = self._extract_annot_class_name( + pool, annot_rhs) + if ret_cls_rhs is not None: + return ret_cls_rhs + return None + if self._cls_has_dunder(pool, mod, obj_cls, ca.attr) == 0: + return None + # 方法定义所在模块 SHA1(优先 struct entry,回退当前模块 sha1) + cls_sha1: str = self.Gen.StructGen.get_struct_sha1(obj_cls) + if cls_sha1 is None and trans.ModuleSha1 is not None: + cls_sha1 = trans.ModuleSha1 + ret_cls: str = None + if cls_sha1 is not None: + import lib.StubGen.VpiReader as VpiReader + temp_dir: str = None + if self.Gen.CallGenBase.TempDir is not None: + temp_dir = self.Gen.CallGenBase.TempDir + if temp_dir is not None: + VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, temp_dir) + annot_ret: str = VpiReader._lookup_vpi_ret_annot( + cls_sha1, obj_cls, ca.attr) + if annot_ret is not None: + ret_cls = self._extract_annot_class_name(pool, annot_ret) + return ret_cls + return None + # Name: 源变量注解 + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm is None or nm.id is None: + return None + ve: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, nm.id) + if ve is None: + return None + return ve.AnnotClassName + # BinOp/UnaryOp: 运算符重载返回同类对象 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if bop is None or bop.left is None: + return None + dunder: str = self._op_to_dunder(bop.op) + if dunder is None: + return None + lhs_cls: str = self._infer_rhs_annot(pool, mod, bop.left, trans) + if lhs_cls is None or self._cls_has_dunder(pool, mod, lhs_cls, dunder) == 0: + return None + return lhs_cls + if k == ast.ASTKind.UnaryOp: + uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + if uop is None or uop.operand is None: + return None + dunder: str = self._op_to_dunder(uop.op) + if dunder is None: + return None + opr_cls: str = self._infer_rhs_annot(pool, mod, uop.operand, trans) + if opr_cls is None or self._cls_has_dunder(pool, mod, opr_cls, dunder) == 0: + return None + return opr_cls + # Attribute: 字段注解类名(属性链递归,如 p = r.origin) + if k == ast.ASTKind.Attribute: + return self.Gen.ExprGenAttr._resolve_attr_field_class(pool, trans, node) + return None + + # ============================================================ + # _extract_annot_class_name - 从返回注解文本提取结构体类名 + # + # vpi 返回注解文本(如 "'Vec3' | CPtr")按 '|' 分段,每段去除 + # 空格/引号后查结构体注册表:命中即类名(内置类型 str/int/ + # CFloat64T/t.CPtr 等均不注册 struct,天然过滤)。"A | B" 联合 + # 多候选时取首个命中段。 + # ============================================================ + def _extract_annot_class_name(self, pool: memhub.MemBuddy | t.CPtr, + annot: str) -> str: + """从返回注解文本提取已注册结构体类名,无命中返回 None""" + if pool is None or annot is None: + return None + alen: t.CSizeT = string.strlen(annot) + if alen == 0: + return None + seg: str = pool.alloc(256) + if seg is None: + return None + start: t.CSizeT = 0 + i: t.CSizeT + for i in range(alen): + if annot[i] == '|': + seglen: t.CSizeT = i - start + # 段 [start, i):去除首尾空格与引号后查注册表 + s: t.CSizeT = start + e: t.CSizeT = i + while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'): + s += 1 + while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'): + e -= 1 + seglen = e - s + if seglen > 0 and seglen < 256: + string.strncpy(seg, annot + s, seglen) + seg[seglen] = '\0' + se: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(seg) + if se is not None: + return seg + start = i + 1 + # 最后一段(无 '|' 后缀) + s: t.CSizeT = start + e: t.CSizeT = alen + while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'): + s += 1 + while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'): + e -= 1 + seglen: t.CSizeT = e - s + if seglen > 0 and seglen < 256: + string.strncpy(seg, annot + s, seglen) + seg[seglen] = '\0' + se: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(seg) + if se is not None: + return seg + return None + + # ============================================================ + # _op_to_dunder - 运算符 → dunder 方法名(本地副本,避免跨 Mixin 调用) + # ============================================================ + def _op_to_dunder(self, op: int) -> str: + """BinOp/UnaryOp 运算符 → dunder 方法名,无映射返回 None""" + if op == ast.OpKind.Add: return "__add__" + if op == ast.OpKind.Sub: return "__sub__" + if op == ast.OpKind.Mult: return "__mul__" + if op == ast.OpKind.Div: return "__truediv__" + if op == ast.OpKind.FloorDiv: return "__floordiv__" + if op == ast.OpKind.Mod: return "__mod__" + if op == ast.OpKind.Pow: return "__pow__" + if op == ast.OpKind.BitAnd: return "__and__" + if op == ast.OpKind.BitOr: return "__or__" + if op == ast.OpKind.BitXor: return "__xor__" + if op == ast.OpKind.LShift: return "__lshift__" + if op == ast.OpKind.RShift: return "__rshift__" + if op == ast.OpKind.USub: return "__neg__" + if op == ast.OpKind.UAdd: return "__pos__" + if op == ast.OpKind.Invert: return "__invert__" + return None + + # ============================================================ + # _cls_has_dunder - 检查类(含继承链)是否存在 dunder 方法 + # + # 与 ExprGenMixin.try_operator_overload 的查找一致:当前模块内定义 + # 或跨模块类有 SHA1(stub 中声明)即视为存在。仅在确实存在时 + # 才采用运算符重载推断的类名,避免把原生运算误标为类类型。 + # ============================================================ + def _cls_has_dunder(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, dunder: str) -> int: + """类及其 MRO 祖先链中是否存在 dunder 方法,存在返回 1""" + if class_name is None or dunder is None or mod is None: + return 0 + lookup_name: str = pool.alloc(128) + if lookup_name is None: + return 0 + viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder) + if self.Gen.CallGenBase.find_func_in_module(mod, lookup_name) is not None: + return 1 + # 继承链祖先查找 + mro_ptr: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, class_name) + mi: int = 1 + while mro_ptr is not None and mro_ptr[mi] != 0: + anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr)) + if anc is not None: + anc_lookup: str = pool.alloc(128) + if anc_lookup is not None: + viperlib.snprintf(anc_lookup, 128, "%s.%s", anc, dunder) + if self.Gen.CallGenBase.find_func_in_module(mod, anc_lookup) is not None: + return 1 + mi += 1 + # 跨模块:类有 SHA1(stub 中声明该方法)视为存在 + if self.Gen.StructGen.get_struct_sha1(class_name) is not None: + return 1 + return 0 + + def InitAssignGen(self) -> int: + """初始化 AssignGen 字段(构造时由 Generator 调用)""" + if self is None: + return 1 + self.RecoverFound = 0 + return 0 diff --git a/App/lib/core/Gen/BaseGenMixin.vp b/App/lib/core/Gen/BaseGenMixin.vp index 139fa6e..817c698 100644 --- a/App/lib/core/Gen/BaseGenMixin.vp +++ b/App/lib/core/Gen/BaseGenMixin.vp @@ -1,58 +1,60 @@ -import t, c -from stdint import * -import memhub -import llvmlite -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesExprCall as HandlesExprCall - - -# ============================================================ -# BaseGenMixin - 生成器基座(状态容器) -# -# 对象化重构 P1(方案见 wiki/14-oo-refactor.md): -# 将 Translator/Handles 的共享状态集中于此。后续 Mixin -# (TypeGen/StructGen/ExprGen/CallGen/FuncGen/ClassGen/StmtGen/ -# ImportsGen)单继承本类,逐步把 Handles* 模块的函数迁移为 -# Generator 的方法,消除 (pool, builder, mod, node, ...) 六参连传。 -# -# 注意:@t.NoVTable(静态绑定,骨架无多态需求;若未来需要 -# 运行时多态再改 @t.CVTable,字段布局由编译器统一管理)。 -# ============================================================ -@t.NoVTable -class BaseGenMixin: - """生成器状态容器(基座)""" - - # 内存/IR 状态 - Pool: memhub.MemBuddy | t.CPtr # 内存池 - Module: llvmlite.LLVMModule | t.CPtr # 当前 LLVM 模块 - Builder: llvmlite.IRBuilder | t.CPtr # 当前 IRBuilder - # 符号表/函数表 - SymTab: HandlesVar.SymbolTable | t.CPtr - Funcs: HandlesExprCall.FuncEntry | t.CPtr - FuncCount: int - # 导入/模块信息 - ImportedModules: str - FromImports: str - ModuleSha1: str - # 当前翻译上下文 - CurFunc: llvmlite.Function | t.CPtr - CurBuilder: llvmlite.IRBuilder | t.CPtr - CurClassName: str - - def InitBaseGen(self, pool: memhub.MemBuddy | t.CPtr) -> int: - """初始化生成器状态(默认值;子类构造时调用)""" - if self is None: - return 1 - self.Pool = pool - self.Module = None - self.Builder = None - self.SymTab = None - self.Funcs = None - self.FuncCount = 0 - self.ImportedModules = None - self.FromImports = None - self.ModuleSha1 = None - self.CurFunc = None - self.CurBuilder = None - self.CurClassName = None - return 0 +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.Generator as Generator +import t, c +from stdint import * +import memhub +import llvmlite +import lib.core.Handles.HandlesExprCall as HandlesExprCall + + +# ============================================================ +# BaseGenMixin - 生成器基座(状态容器) +# +# 对象化重构 P1(方案见 wiki/14-oo-refactor.md): +# 将 Translator/Handles 的共享状态集中于此。后续 Mixin +# (TypeGen/StructGen/ExprGen/CallGen/FuncGen/ClassGen/StmtGen/ +# ImportsGen)单继承本类,逐步把 Handles* 模块的函数迁移为 +# Generator 的方法,消除 (pool, builder, mod, node, ...) 六参连传。 +# +# 注意:@t.NoVTable(静态绑定,骨架无多态需求;若未来需要 +# 运行时多态再改 @t.CVTable,字段布局由编译器统一管理)。 +# ============================================================ +@t.NoVTable +class BaseGenMixin: + """生成器状态容器(基座)""" + + # 内存/IR 状态 + Gen: Generator.Generator | t.CPtr + Pool: memhub.MemBuddy | t.CPtr # 内存池 + Module: llvmlite.LLVMModule | t.CPtr # 当前 LLVM 模块 + Builder: llvmlite.IRBuilder | t.CPtr # 当前 IRBuilder + # 符号表/函数表 + SymTab: GenTypes.SymbolTable | t.CPtr + Funcs: GenTypes.FuncEntry | t.CPtr + FuncCount: int + # 导入/模块信息 + ImportedModules: str + FromImports: str + ModuleSha1: str + # 当前翻译上下文 + CurFunc: llvmlite.Function | t.CPtr + CurBuilder: llvmlite.IRBuilder | t.CPtr + CurClassName: str + + def InitBaseGen(self, pool: memhub.MemBuddy | t.CPtr) -> int: + """初始化生成器状态(默认值;子类构造时调用)""" + if self is None: + return 1 + self.Pool = pool + self.Module = None + self.Builder = None + self.SymTab = None + self.Funcs = None + self.FuncCount = 0 + self.ImportedModules = None + self.FromImports = None + self.ModuleSha1 = None + self.CurFunc = None + self.CurBuilder = None + self.CurClassName = None + return 0 diff --git a/App/lib/core/Gen/CallGenBase.vp b/App/lib/core/Gen/CallGenBase.vp index c9733f9..51fd679 100644 --- a/App/lib/core/Gen/CallGenBase.vp +++ b/App/lib/core/Gen/CallGenBase.vp @@ -1,1018 +1,1015 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import sys -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesFunctions as HandlesFunctions -import lib.core.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.CompilerFactory as CompilerFactory -import lib.core.StubMergerCollect as StubMergerCollect -import lib.core.StubMergerStore as StubMergerStore - - - -# ============================================================ -# CallGenBase - CallGenMixin 拆分 1/9(最底层父类):模块符号查找 + -# 返回类型解析基础设施 -# -# 按功能域从 CallGenMixin.vp 拆出(500~1500 行/文件架构重构): -# 字段(15 个)+ InitCallGen + 模块符号查找(sha1/cexport/vpi/reexport/find_func_in_module) -# + 返回类型解析链(_ensure_method_declare/_LookupMethodRetTyFromTextLL/_dep_text_ll_exists 等) -# -# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 -# ============================================================ - - -# ============================================================ -# 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug) -# ============================================================ -GLOBAL_FUNC_MAX: t.CDefine = 8192 -GLOBAL_DEFAULTS_MAX: t.CDefine = 4096 -_CEXPORT_MAX: t.CDefine = 256 -ASM_MAX_OPERANDS: t.CDefine = 16 -ASM_TEXT_BUF_SIZE: t.CDefine = 2048 -ASM_CONST_BUF_SIZE: t.CDefine = 512 -ASM_ARGS_BUF_SIZE: t.CDefine = 512 -ASM_LINE_BUF_SIZE: t.CDefine = 4096 -LLVMIR_MAX_OPS: t.CDefine = 16 -LLVMIR_TEMPLATE_BUF: t.CDefine = 512 -# 闭包名表大小(原 HandlesExprCall 模块级常量) -MAX_CLOSURE_NAMES: t.CDefine = 128 -# 函数指针签名表大小(原 HandlesExprCall 模块级常量) -MAX_FUNC_PTR_SIGS: t.CDefine = 64 -# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32) -ISINSTANCE_CLASS_MAX: t.CDefine = 64 - - -# ============================================================ -# CallGenBase - 最底层父类(字段 + 模块查找 + 返回类型解析) -# ============================================================ -@t.NoVTable -class CallGenBase: - """调用分派最底层父类(字段 + 模块符号查找 + 返回类型解析基础设施)""" - - # --- c.cexport 注册表(原 _g_cexport_sha1_arr/_g_cexport_func_arr/_g_cexport_count) --- - CexportSha1Arr: bytes - CexportFuncArr: bytes - CexportCount: int - - # --- LLVMIR 寄存器序号(原 _g_llvmir_reg_seq) --- - LLVMIRRegSeq: int - - # --- temp 目录(原 _g_temp_dir/_g_temp_dir_len) --- - TempDir: str - TempDirLen: t.CSizeT - - # --- 闭包名表(原 _g_closure_names/_g_closure_count) --- - ClosureNames: str - ClosureCount: int - - # --- 函数指针签名表(原 _g_funcptr_names/_g_funcptr_rets/_g_funcptr_count) --- - FuncptrNames: str - FuncptrRets: t.CUInt64T | t.CPtr - FuncptrCount: int - - # --- 全局函数注册表(原 _global_funcs/_global_func_count) --- - GlobalFuncs: HandlesExprCall.FuncEntry | t.CPtr - GlobalFuncCount: int - - # --- 全局默认参数表(原 _global_defaults/_global_defaults_count) --- - GlobalDefaults: HandlesExprCall.FuncDefaultsEntry | t.CPtr - GlobalDefaultsCount: int - - def InitCallGen(self) -> int: - """初始化调用 Mixin 字段(子类构造时内联调用,规避 NoVTable 继承符号不转发)""" - if self is None: - return 1 - self.CexportSha1Arr = None - self.CexportFuncArr = None - self.CexportCount = 0 - self.LLVMIRRegSeq = 0 - self.TempDir = None - self.TempDirLen = 0 - self.ClosureNames = None - self.ClosureCount = 0 - self.FuncptrNames = None - self.FuncptrRets = None - self.FuncptrCount = 0 - self.GlobalFuncs = None - self.GlobalFuncCount = 0 - self.GlobalDefaults = None - self.GlobalDefaultsCount = 0 - return 0 - - # ============================================================ - # P4 簇 1+2 迁移方法(函数体来自 HandlesExprCall.vp: - # 模块 SHA1 查询/CExport 注册表/c.* 系列/内联汇编/LLVMIR) - # 本模块函数调用改 self.,外部模块调用保留模块前缀 - # ============================================================ - - - - def _lookup_module_sha1(self, mod_name: str) -> str: - """查找模块名对应的 SHA1,找不到返回 None - - 委托给 StubMerger.LookupSha1ByModName(精确匹配 + 包名回退)。 - """ - return StubMergerStore.LookupSha1ByModName(mod_name) - - - def _lookup_module_sha1_suffix(self, mod_suffix: str) -> str: - """后缀匹配查找模块 SHA1,如 mod_suffix="__types" 匹配 "llvmlite.__types" - - 用于 from .X import Y 的相对导入:impf.module 是 ".X"(带前导点), - 去掉前导点后为 "X",SHA1 映射表中键是 "pkg.X",需要后缀匹配。 - 委托给 StubMerger.LookupSha1ByModNameSuffix(精确 + 后缀 + 反向后缀)。 - """ - return StubMergerStore.LookupSha1ByModNameSuffix(mod_suffix) - - - def _module_package_from_sha1(self, pool: memhub.MemBuddy | t.CPtr, - mod_sha1: str) -> str: - """从 SHA1 存储器的 rel_path 计算模块所属包名(目录部分,'/' → '.')""" - if pool is None or mod_sha1 is None: - return None - rel_arr_ptr: bytes | t.CPtr = StubMergerStore.GetSha1StoreRelArrPtr() - sha1_arr_ptr: bytes | t.CPtr = StubMergerStore.GetSha1StoreArrPtr() - count: int = StubMergerStore.GetSha1StoreCount() - if rel_arr_ptr is None or sha1_arr_ptr is None or count <= 0: - return None - for i in range(count): - sidx: t.CSizeT = t.CSizeT(i) * 17 - if string.strcmp(sha1_arr_ptr + sidx, mod_sha1) != 0: - continue - ridx: t.CSizeT = t.CSizeT(i) * StubMerger.MAX_REL_PATH_LEN - rel: str = rel_arr_ptr + ridx - last_slash: str = string.strrchr(rel, 47) # 47 = ord('/') - if last_slash is None: - return None - pkg_len: t.CSizeT = t.CSizeT(t.CUInt64T(last_slash) - t.CUInt64T(rel)) - if pkg_len == 0: - return None - pkg_buf: str = pool.alloc(pkg_len + 1) - if pkg_buf is None: - return None - for pi in range(pkg_len): - if rel[pi] == '/': - pkg_buf[pi] = '.' - else: - pkg_buf[pi] = rel[pi] - pkg_buf[pkg_len] = '\0' - return pkg_buf - return None - - - def _lookup_reexport_from_vpi(self, pool: memhub.MemBuddy | t.CPtr, - mod_sha1: str, func_name: str) -> str: - """re-export 表未命中时,从模块 .vpi 按需解析 from-import 定位定义模块 - - includes 模块(如 llvmlite/__init__)的 stub/text 已存在时不会被按需 - 全量翻译(Phase2 3.5 仅在 stub/text 缺失时翻译),而 re-export 表只在 - declare_only=0 的全量翻译中注册(HandleImportFromNames),因此表可能为空。 - 本函数解析该模块 .vpi 的 "from .X import ... func_name ..." 语句, - 返回定义模块名(如 llvmlite/__init__ 的 .__builder → "llvmlite.__builder")。 - """ - if pool is None or mod_sha1 is None or func_name is None: - return None - temp_dir: str = HandlesType.get_temp_dir() - if temp_dir is None: - return None - td_len: t.CSizeT = string.strlen(temp_dir) - vpi_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, mod_sha1, "vpi") - if vpi_path is None: - return None - READ_SZ: t.CSizeT = 1048576 - buf: bytes = stdlib.malloc(READ_SZ) - if buf is None: - stdlib.free(vpi_path) - return None - vf: fileio.File | t.CPtr = fileio.File(vpi_path, fileio.MODE.R) - stdlib.free(vpi_path) - if vf.closed: - stdlib.free(buf) - return None - nrd: LONG = vf.read_all(buf, READ_SZ) - vf.close() - if nrd <= 0: - stdlib.free(buf) - return None - if nrd < READ_SZ: - buf[nrd] = 0 - else: - buf[READ_SZ - 1] = 0 - name_len: t.CSizeT = string.strlen(func_name) - total: t.CSizeT = string.strlen(buf) - pos: t.CSizeT = 0 - while pos < total: - ls: t.CSizeT = pos - while pos < total and buf[pos] != '\n': - pos += 1 - ll: t.CSizeT = pos - ls - if pos < total: - pos += 1 - # 行必须以 "from " 开头 - if ll < 6: - continue - if buf[ls] != 'f' or buf[ls + 1] != 'r' or buf[ls + 2] != 'o' or buf[ls + 3] != 'm' or buf[ls + 4] != ' ': - continue - # 找 " import " 分隔符 - imp_pos: t.CSizeT = ls + 5 - while imp_pos + 7 <= ls + ll: - if buf[imp_pos] == ' ' and buf[imp_pos + 1] == 'i' and buf[imp_pos + 2] == 'm' and \ - buf[imp_pos + 3] == 'p' and buf[imp_pos + 4] == 'o' and buf[imp_pos + 5] == 'r' and \ - buf[imp_pos + 6] == 't' and buf[imp_pos + 7] == ' ': - break - imp_pos += 1 - if imp_pos + 7 > ls + ll: - continue - mod_start: t.CSizeT = ls + 5 - mod_end: t.CSizeT = imp_pos - # 名称列表从 "import " 之后(逗号分隔,含 "A as B" 取原名 A) - nm_start: t.CSizeT = imp_pos + 8 - scan: t.CSizeT = nm_start - while scan < ls + ll: - while scan < ls + ll and (buf[scan] == ' ' or buf[scan] == ','): - scan += 1 - if scan >= ls + ll: - break - n_end: t.CSizeT = scan - while n_end < ls + ll and buf[n_end] != ',' and buf[n_end] != ' ': - n_end += 1 - cand_start: t.CSizeT = scan - cand_len: t.CSizeT = n_end - scan - as_pos: t.CSizeT = scan - while as_pos + 4 <= n_end: - if buf[as_pos] == ' ' and buf[as_pos + 1] == 'a' and buf[as_pos + 2] == 's' and buf[as_pos + 3] == ' ': - cand_start = as_pos + 4 - cand_len = n_end - cand_start - break - as_pos += 1 - if cand_len == name_len: - m_ok: int = 1 - for ki in range(name_len): - if buf[cand_start + ki] != func_name[ki]: - m_ok = 0 - break - if m_ok == 1: - # 命中:解析模块名(前导点 → 相对导入,补包前缀) - has_dot: int = 0 - if buf[mod_start] == '.': - has_dot = 1 - mod_buf: str = pool.alloc(mod_end - mod_start + 1) - if mod_buf is None: - stdlib.free(buf) - return None - mi: t.CSizeT = 0 - while mod_start + mi < mod_end: - mod_buf[mi] = buf[mod_start + mi] - mi += 1 - mod_buf[mi] = '\0' - while mod_buf[0] == '.': - mod_buf = mod_buf + 1 - if string.strlen(mod_buf) == 0: - stdlib.free(buf) - return None - if has_dot != 0: - pkg: str = self._module_package_from_sha1(pool, mod_sha1) - if pkg is None: - stdlib.free(buf) - return None - rl: t.CSizeT = string.strlen(pkg) + string.strlen(mod_buf) + 2 - res: str = pool.alloc(rl) - if res is None: - stdlib.free(buf) - return None - viperlib.snprintf(res, rl, "%s.%s", pkg, mod_buf) - stdlib.free(buf) - return res - stdlib.free(buf) - return mod_buf - scan = n_end - stdlib.free(buf) - return None - - - def register_cexport_func(self, sha1: str, func_name: str) -> int: - """注册 CExport 函数到全局表(sha1+func_name 二元组)""" - if sha1 is None or func_name is None: - return 0 - if self.CexportSha1Arr is None: - self.CexportSha1Arr = CompilerFactory.get_perm_pool().alloc(_CEXPORT_MAX * 17) - self.CexportFuncArr = CompilerFactory.get_perm_pool().alloc(_CEXPORT_MAX * 64) - if self.CexportSha1Arr is None or self.CexportFuncArr is None: - return 0 - string.memset(self.CexportSha1Arr, 0, _CEXPORT_MAX * 17) - string.memset(self.CexportFuncArr, 0, _CEXPORT_MAX * 64) - if self.CexportCount < _CEXPORT_MAX: - idx: t.CSizeT = t.CSizeT(self.CexportCount) * 17 - # 槽位定长 17/64 字节,strcpy 无界会越界写相邻槽(stdlib 堆区) - string.strncpy(self.CexportSha1Arr + idx, sha1, 16) - self.CexportSha1Arr[idx + 16] = '\0' - idx2: t.CSizeT = t.CSizeT(self.CexportCount) * 64 - string.strncpy(self.CexportFuncArr + idx2, func_name, 63) - self.CexportFuncArr[idx2 + 63] = '\0' - self.CexportCount += 1 - return 1 - return 0 - - - def is_cexport_func(self, sha1: str, func_name: str) -> int: - """检查 (sha1, func_name) 是否是 CExport 函数""" - if sha1 is None or func_name is None: - return 0 - if self.CexportSha1Arr is None: - return 0 - for i in range(self.CexportCount): - idx: t.CSizeT = t.CSizeT(i) * 17 - if string.strcmp(self.CexportSha1Arr + idx, sha1) == 0: - idx2: t.CSizeT = t.CSizeT(i) * 64 - if string.strcmp(self.CexportFuncArr + idx2, func_name) == 0: - return 1 - return 0 - - - def _is_state_func_from_vpi(self, pool: memhub.MemBuddy | t.CPtr, - sha1: str, func_name: str) -> int: - """vpi 返回注解含 t.State → 外部 C 函数(定义端用裸名,跨模块调用无 sha1 头) - - t.State(同 t.CExtern/t.CExport)是外部函数标记:定义端生成裸名 - @PyList_Size(链接外部库 libpython),跨模块调用若生成 @{sha1}.PyList_Size - → ld.lld undefined symbol(CPythonTest PyList_Size 根因)。CExport 走 - is_cexport_func 注册表,State 函数未注册 → 按需解析 vpi 返回注解判断。 - """ - if pool is None or sha1 is None or func_name is None: - return 0 - import lib.StubGen.VpiReader as VpiReader - if self.TempDir is not None and self.TempDirLen > 0: - VpiReader._ensure_vpi_ret_annot_loaded(sha1, self.TempDir) - state_annot: str = VpiReader._lookup_vpi_ret_annot(sha1, None, func_name) - if state_annot is None: - return 0 - # 返回注解含 "State"(如 "t.CSizeT | t.State")→ 外部 C 函数 - if string.strstr(state_annot, "State") is not None: - return 1 - return 0 - - - def _lookup_mod_sha1(self, pool: memhub.MemBuddy | t.CPtr, - from_imports: str, class_name: str, - allow_star_fallback: int = 1) -> str: - """从 from_imports 查找类所属模块的 SHA1,返回 None=未找到 - - allow_star_fallback: 传 0 禁用 star import 回退(用于明确模块名/函数名查找) - """ - mod_name_raw: str = HandlesImports.lookup_from_import( - from_imports, class_name, allow_star_fallback) - if mod_name_raw is None: - return None - return self._lookup_sha1_from_modname_raw(pool, mod_name_raw) - - - def _lookup_sha1_from_modname_raw(self, pool: memhub.MemBuddy | t.CPtr, - mod_name_raw: str) -> str: - """从原始模块名查找 SHA1,返回 None=未找到""" - # 手动找到模块名结束位置(空格、null、或 ':' 别名分隔符),复制到新缓冲区 - mod_len: t.CSizeT = 0 - while mod_name_raw[mod_len] != ' ' and mod_name_raw[mod_len] != '\0' and mod_name_raw[mod_len] != ':': - mod_len += 1 - mod_name_buf: str = pool.alloc(mod_len + 1) - if mod_name_buf is None: - return None - for mi in range(mod_len): - mod_name_buf[mi] = mod_name_raw[mi] - mod_name_buf[mod_len] = '\0' - # 去掉相对导入的前导点 - base_mod: str = mod_name_buf - while base_mod[0] == '.': - base_mod = base_mod + 1 - sha1: str = self._lookup_module_sha1(base_mod) - if sha1 is None: - sha1 = self._lookup_module_sha1_suffix(base_mod) - return sha1 - - - def find_func_in_module(self, mod: llvmlite.LLVMModule | t.CPtr, - name: str) -> llvmlite.Function | t.CPtr: - """在模块的函数链表中按名称查找函数 - - 查找策略: - 1. 精确匹配(如 "strlen" 匹配 @strlen,有 t.CExport 的函数) - 2. 后缀匹配(如 "atoi" 匹配 @"83210a72e829a086.atoi",无 t.CExport 的函数) - - 使用 llvmlite.function_get_name/next 访问器绕过 stub 类型限制 - (stub 类型字段不足且字段类型可能错误,直接字段访问会被静默跳过)。 - """ - if mod is None or name is None: - return None - name_len: t.CSizeT = string.strlen(name) - cur: llvmlite.Function | t.CPtr = mod.FuncHead - # 第一遍:精确匹配 - while cur is not None: - cur_name: str = llvmlite.function_get_name(cur) - if cur_name is not None: - if string.strcmp(cur_name, name) == 0: - return cur - cur = llvmlite.function_get_next(cur) - # 第二遍:后缀匹配(.name) - # 不跳过 declare:方法 stub 也是 declare,需要通过后缀匹配找到 - # 调用处(translate_call 等)负责判断 IsDeclared 并决定使用裸名还是 sha1 前缀名 - # - # 修复:本模块 define 优先于跨模块 stub declare。 - # 根因:跨模块同名函数(如 lexer.vp 的 _advance 与 parser.vp 的 _advance) - # 的 stub declare 在 stub 注入时排在 FuncHead 前面,裸名调用 _advance 后缀 - # 匹配按链表顺序先命中跨模块 declare → 参数按 Lexer* coerce → Parser* 被 - # bitcast 成 Lexer* → lexer 版 _advance 按 Lexer 布局操作 Parser 指针, - # cur 永不推进 → parse 无限循环。本模块同名 define 必须优先。 - cur = mod.FuncHead - while cur is not None: - cur_name2: str = llvmlite.function_get_name(cur) - if cur_name2 is not None: - cur_len: t.CSizeT = string.strlen(cur_name2) - if cur_len > name_len + 1: - suffix_start: t.CSizeT = cur_len - name_len - if cur_name2[suffix_start - 1] == '.': - match: int = 1 - for i in range(name_len): - if cur_name2[suffix_start + i] != name[i]: - match = 0 - break - if match == 1: - if cur.IsDeclared == 0: - return cur - cur = llvmlite.function_get_next(cur) - # 本模块无同名 define:回退到 stub declare(跨模块方法/函数调用) - cur = mod.FuncHead - while cur is not None: - cur_name3: str = llvmlite.function_get_name(cur) - if cur_name3 is not None: - cur_len3: t.CSizeT = string.strlen(cur_name3) - if cur_len3 > name_len + 1: - suffix_start3: t.CSizeT = cur_len3 - name_len - if cur_name3[suffix_start3 - 1] == '.': - match3: int = 1 - for i in range(name_len): - if cur_name3[suffix_start3 + i] != name[i]: - match3 = 0 - break - if match3 == 1: - return cur - cur = llvmlite.function_get_next(cur) - return None - - - # ============================================================ - # _ensure_method_declare - 为跨模块方法调用创建 declare 声明 - # - # 当 found_func 为 None(stub 未注入或跨模块调用)时, - # 在当前模块中创建函数声明,避免 llc 报 undefined value。 - # ============================================================ - def _ensure_method_declare(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - call_name: str, - ret_ty: llvmlite.LLVMType | t.CPtr, - param_head: llvmlite.ParamNode | t.CPtr, - param_count: int): - """为跨模块方法调用创建 declare 声明 - - 若模块中已存在同名 declare 且参数数量较少(例如 File.__init__ 的 - stub 仅 3 个参数,而实际调用传入 4 个),则向现有 declare 追加缺失 - 参数,避免 llc 报 `argument invalid for parameter type` 之类的错误。 - 已存在的 define 不修改(其参数由定义决定)。 - """ - if pool is None or mod is None or call_name is None: - return - # 链遍历哨兵(fail-fast):FuncHead/Params 的 Next 被越界写破坏成环时 - # 无上限遍历会死循环(builtins.vp dump 卡死根因排查),超限即报错终止。 - DECLARE_CHAIN_LIMIT: int = 100000 - # 检查模块中是否已有同名函数(declare 或 define) - existing: llvmlite.Function | t.CPtr = mod.FuncHead - existing_steps: int = 0 - while existing is not None: - existing_steps += 1 - if existing_steps > DECLARE_CHAIN_LIMIT: - stdio.printf("[CALLGEN] 链表异常: module funcs(call_name=%s,遍历超限,终止)\n", call_name) - stdlib.exit(1) - if existing.Name is not None: - if string.strcmp(existing.Name, call_name) == 0: - # 已存在:仅当是 declare 且参数数量不足时追加缺失参数 - if existing.IsDeclared == 1: - # 变长函数(*args,IsVarArg=1)不追加参数:多余实参由 - # 变参机制(...)承接,追加有类型参数会导致调用侧把变参 - # 强转为追加的类型(如 i8 → i64),%d/%x 等格式读错。 - if existing.IsVarArg == 1: - return - # 遍历现有参数链表计数(避免依赖 GSList.Count 字段的类型推断) - cur_count: int = 0 - cur_p: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(existing) - while cur_p is not None: - cur_count += 1 - if cur_count > DECLARE_CHAIN_LIMIT: - stdio.printf("[CALLGEN] 链表异常: func params(call_name=%s,参数链遍历超限,终止)\n", call_name) - stdlib.exit(1) - cur_p = cur_p.Next - # 只追加缺失的参数(cur_count < param_count 时) - if cur_count < param_count: - # 定位到 param_head 的第 cur_count 个节点开始追加 - pnode2: llvmlite.ParamNode | t.CPtr = param_head - pi2: int = 0 - # 跳过已有的 cur_count 个参数 - while pnode2 is not None and pi2 < cur_count: - pnode2 = pnode2.Next - pi2 += 1 - # 追加剩余参数 - while pnode2 is not None and pi2 < param_count: - if pnode2.Ty is not None: - param2: llvmlite.Param | t.CPtr = llvmlite.new_param(pool, pnode2.Ty, None) - if param2 is not None: - llvmlite.function_add_param(existing, param2) - pnode2 = pnode2.Next - pi2 += 1 - return - existing = existing.Next - # 创建函数声明 - func: llvmlite.Function | t.CPtr = llvmlite.new_function(pool, call_name, ret_ty) - if func is None: - return - func.IsDeclared = 1 - # 添加参数(declare 中参数名无意义,设为 None 只输出类型) - pnode: llvmlite.ParamNode | t.CPtr = param_head - pi: int = 0 - while pnode is not None and pi < param_count: - if pnode.Ty is not None: - param: llvmlite.Param | t.CPtr = llvmlite.new_param(pool, pnode.Ty, None) - if param is not None: - llvmlite.function_add_param(func, param) - pnode = pnode.Next - pi += 1 - llvmlite.module_add_function(mod, func) - - # ============================================================ - # _lookup_method_ret_ty_via_vpi - 从 vpi stub 返回注解缓存精确获取方法返回类型 - # - # 方法定义处(.vpi stub)的返回注解(如 json.JsonValue._pool_alloc → - # "str")在 stub 注入时由 VpiReader 缓存(_cache_vpi_return_annots_text)。 - # 此函数按 模块SHA1 + 类名 + 方法名 查缓存并纯字符串解析为 LLVMType。 - # 无需硬编码白名单——返回类型始终来自方法定义处。 - # ============================================================ - - # ============================================================ - def _lookup_method_ret_ty_via_vpi(self, pool: memhub.MemBuddy | t.CPtr, - cls_sha1: str, - cls_name: str, - method_name: str) -> llvmlite.LLVMType | t.CPtr: - """从 vpi stub 返回注解缓存获取方法返回类型,未命中返回 None""" - if pool is None or cls_sha1 is None or method_name is None: - return None - # 函数内懒 import:VpiReader imports HandlesExprCall,顶层 import 会成环 - import lib.StubGen.VpiReader as VpiReader - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - # 按需加载:缓存未命中时直接读 {temp_dir}/{sha1[0:2]}/{sha1}.vpi - # 覆盖"模块自身翻译时 stub 尚未注入"(同模块方法调用,定义在后)的场景 - if self.TempDir is not None and self.TempDirLen > 0: - VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, self.TempDir) - annot: str = VpiReader._lookup_vpi_ret_annot(cls_sha1, cls_name, method_name) - if annot is None: - return None - return VpiReader._resolve_vpi_ret_annot_str(pool, annot, i32_ty, i8_ptr_ty) - - # ============================================================ - # _special_method_ret_ty - 编译器内置特殊方法的固定返回类型 - # - # __before_init__ / __init__:编译器生成/约定返回 void - # __new__:返回 Ptr(StructTy)(存储空间指针) - # - # 这些方法不存在于源码(vpi stub 无条目),跨模块调用时 - # found_func/text.ll/vpi 缓存必然未命中,但返回类型是编译器 - # 确定性语义(与 HandlesClassDef._translate_method 3543-3548 一致), - # 在此直接固定,不触发 fail-fast 误报。非特殊方法返回 None。 - # ============================================================ - - # ============================================================ - def _special_method_ret_ty(self, pool: memhub.MemBuddy | t.CPtr, - class_name: str, - method_name: str) -> llvmlite.LLVMType | t.CPtr: - """编译器内置特殊方法的固定返回类型;非特殊返回 None""" - if pool is None or method_name is None: - return None - if string.strcmp(method_name, "__before_init__") == 0 or \ - string.strcmp(method_name, "__init__") == 0: - return llvmlite.Void(pool) - if string.strcmp(method_name, "__new__") == 0: - if class_name is not None: - sp_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(class_name) - if sp_struct_ty is not None: - return llvmlite.Ptr(pool, sp_struct_ty) - return None - return None - - # ============================================================ - # _fail_method_ret_ty - 方法返回类型无法精确获取时 fail-fast - # - # 返回类型来源(按序):当前模块函数 → text.ll define → vpi stub 返回注解缓存。 - # 全部未命中时立即 ERROR + 错误堆栈终止,绝不按名推断白名单/静默默认 i32。 - # - # node: 调用点 AST 节点(可选,用于 ERROR 堆栈定位) - # ============================================================ - - # ============================================================ - def _fail_method_ret_ty(self, method_name: str, - node: ast.AST | t.CPtr = None) -> llvmlite.LLVMType | t.CPtr: - """方法返回类型无法精确获取时 fail-fast(ERROR + 错误堆栈) - - 返回类型来源(按序):当前模块函数 → text.ll define → vpi stub 返回注解缓存。 - 全部未命中说明方法定义缺失或 stub 损坏,立即终止暴露,绝不静默默认 i32。 - """ - VLogger.error( - f"方法返回类型无法精确获取(函数/text.ll/vpi stub 均未命中): {method_name}", - "HandlesExprCall") - HandlesType.fatal_error( - node, - f"方法返回类型无法精确获取,默认 i32 会截断指针/i64: {method_name}", - "TypeError") - return None - - # ============================================================ - # SetTempDir - 设置 temp 目录路径 - # - # 在 Phase2.py 的 Phase A 翻译前调用,使 CallGenMixin - # 能够读取依赖模块的 text.ll 文件。 - # ============================================================ - - # ============================================================ - def SetTempDir(self, temp_dir: str): - """设置 temp 目录路径(供跨模块方法返回类型查找使用)""" - self.TempDir = temp_dir - if temp_dir is not None: - self.TempDirLen = string.strlen(temp_dir) - else: - self.TempDirLen = 0 - - # ============================================================ - # _ParseLLVMRetTyStr - 将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType - # - # 从 define 行中提取的返回类型字符串(define 与 @ 之间的内容), - # 转换为 llvmlite.LLVMType 对象。 - # - # 支持的类型: - # void → Void - # i8/i16/i32/i64 → Int8/Int16/Int32/Int64 - # double → Double, float → Float - # 任何含 * 的类型 → Ptr(Int8)(通用指针,保留 64 位地址) - # - # Args: - # pool: 内存池 - # buf: 包含类型字符串的缓冲区 - # start: 类型字符串起始位置 - # end: 类型字符串结束位置(不含) - # - # Returns: - # LLVM 类型对象,或 None(无法解析) - # ============================================================ - - # ============================================================ - def _ParseLLVMRetTyStr(self, pool: memhub.MemBuddy | t.CPtr, - buf: bytes, - start: t.CSizeT, - end: t.CSizeT) -> llvmlite.LLVMType | t.CPtr: - """将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType""" - if pool is None or buf is None or start >= end: - return None - - # 去除前导空白 - s: t.CSizeT = start - while s < end: - c: int = buf[s] - if c != ' ' and c != '\t': - break - s += 1 - # 去除尾部空白 - e: t.CSizeT = end - while e > s: - c2: int = buf[e - 1] - if c2 != ' ' and c2 != '\t': - break - e -= 1 - - ty_len: t.CSizeT = e - s - if ty_len == 0: - return None - - # struct 字面量 {T1, T2, ...}(tuple 打包返回类型,如 b2a_hqx -> - # tuple[str, t.CUnsignedShort] 编译为 {i8*, i16})。必须在 * 检查 - # 之前——否则 "{i8*, i16}" 内含 * 会被误判为 i8*(b2a_hqx 调用侧 - # 返回类型退化 i8* → HandlesAssign tuple 解包静默跳过 → free 未初始化 - # 指针崩溃,HashLibTest hqx 段)。 - if s < e and buf[s] == '{': - th_st: llvmlite.ParamNode | t.CPtr = None - tt_st: llvmlite.ParamNode | t.CPtr = None - tc_st: int = 0 - ps_st: t.CSizeT = s + 1 - while ps_st < e and buf[ps_st] != '}': - while ps_st < e and (buf[ps_st] == ' ' or buf[ps_st] == ','): - ps_st += 1 - if ps_st >= e or buf[ps_st] == '}': - break - es_st: t.CSizeT = ps_st - while ps_st < e and buf[ps_st] != ',' and buf[ps_st] != '}': - ps_st += 1 - ee_st: t.CSizeT = ps_st - if ee_st > es_st: - et_st: llvmlite.LLVMType | t.CPtr = self._ParseLLVMRetTyStr( - pool, buf, es_st, ee_st) - if et_st is None: - return None - en_st: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node( - pool, et_st) - if en_st is None: - return None - if th_st is None: - th_st = en_st - else: - llvmlite.paramnode_set_next(tt_st, en_st) - tt_st = en_st - tc_st += 1 - if th_st is None or tc_st == 0: - return None - st_ty_st: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, th_st, tc_st, None) - # 指针到 struct({i32, i8}*):返回 Ptr(Struct);纯 tuple 打包 - # ({i8*, i16})无尾部 *,返回 Struct 本身。 - if ps_st < e and buf[ps_st] == '*': - return llvmlite.Ptr(pool, st_ty_st) - return st_ty_st - - # 检查是否含 * (指针类型) → 返回 i8* (通用指针) - # 包括 i8*, i32*, %"name"*, { i32, i8 }* 等 - ci: t.CSizeT = s - while ci < e: - if buf[ci] == '*': - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - ci += 1 - - # void - if ty_len == 4 and string.strncmp(buf + s, "void", 4) == 0: - return llvmlite.Void(pool) - - # double - if ty_len == 6 and string.strncmp(buf + s, "double", 6) == 0: - return llvmlite.Double(pool) - - # float - if ty_len == 5 and string.strncmp(buf + s, "float", 5) == 0: - return llvmlite.Float(pool) - - # iN (i8, i16, i32, i64) - if ty_len >= 2 and buf[s] == 'i': - bits: int = 0 - di: t.CSizeT = s + 1 - valid: int = 1 - while di < e: - d: int = buf[di] - if d >= '0' and d <= '9': - bits = bits * 10 + (d - '0') - else: - valid = 0 - break - di += 1 - if valid != 0 and bits > 0: - if bits == 8: - return llvmlite.Int8(pool) - if bits == 16: - return llvmlite.Int16(pool) - if bits == 32: - return llvmlite.Int32(pool) - if bits == 64: - return llvmlite.Int64(pool) - - # 无法解析 - return None - - # ============================================================ - # _LookupMethodRetTyFromTextLL - 从依赖模块的 text.ll 查找方法返回类型 - # - # 读取 {temp_dir}/{sha1[0:2]}/{sha1}.text.ll (level=1),搜索 - # define 行中包含 "{sha1}.{class_name}.{method_name}" 的函数, - # 提取返回类型并转换为 llvmlite.LLVMType。 - # - # 解决问题: 旧实现 _infer_method_ret_ty(已移除)默认返回 i32,导致指针返回值 - # 被 inttoptr 截断为 32 位(coerce_to_type line 238-239)。 - # 本函数从 text.ll 获取实际返回类型,避免截断。 - # - # Args: - # pool: 内存池 - # class_sha1: 类所属模块的 SHA1 - # class_name: 类名 - # method_name: 方法名 - # - # Returns: - # LLVM 类型对象,或 None(未找到/text.ll 不存在) - # ============================================================ - - # ============================================================ - def _LookupMethodRetTyFromTextLL(self, pool: memhub.MemBuddy | t.CPtr, - class_sha1: str, - class_name: str, - method_name: str, - use_bare: int = 0) -> llvmlite.LLVMType | t.CPtr: - """从依赖模块的 text.ll 中查找方法返回类型 - - use_bare: 1=按模块级函数查找(搜索 "{sha1}.{method_name}" define, - 用于 new_lexer/tokenize 等模块函数;class_name 忽略)。 - """ - if pool is None or class_sha1 is None or method_name is None: - return None - if self.TempDir is None or self.TempDirLen == 0: - return None - - sha1_len: t.CSizeT = string.strlen(class_sha1) - if sha1_len < 2: - return None - - # 构造 text.ll 路径 (level=1): {temp_dir}/{sha1[0:2]}/{sha1}.text.ll - # 使用 subdir 缓冲区避免 %c 格式化问题(与 StubMerger._sliced_path 一致) - path_len: t.CSizeT = self.TempDirLen + sha1_len + 14 - path_buf: bytes = stdlib.malloc(path_len) - if path_buf is None: - return None - subdir_buf: bytes = stdlib.malloc(3) - if subdir_buf is None: - stdlib.free(path_buf) - return None - subdir_buf[0] = class_sha1[0] - subdir_buf[1] = class_sha1[1] - subdir_buf[2] = '\0' - viperlib.snprintf(path_buf, path_len, "%s/%s/%s.text.ll", - self.TempDir, subdir_buf, class_sha1) - stdlib.free(subdir_buf) - - # 读取 text.ll(按文件实际大小分配:固定 _TEXT_LL_READ_BUF_SIZE(256KB) - # 会截断大模块的 text.ll,末尾方法定义查不到 → 误报"方法返回类型无法 - # 精确获取"(追加80b 根因,同追加74 _read_source_line 截断)。64MB 上限 - # 防御异常超大文件整体读取。) - tf: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R) - if tf.closed: - stdlib.free(path_buf) - return None - tfsize: LONGLONG = tf.size() - if tfsize <= 0 or tfsize > 67108864: - tf.close() - stdlib.free(path_buf) - return None - read_size: t.CSizeT = t.CSizeT(tfsize) - read_buf: bytes = stdlib.malloc(read_size + 1) - if read_buf is None: - tf.close() - stdlib.free(path_buf) - return None - text_len: t.CInt64T = tf.read_all(read_buf, ULONG(read_size + 1)) - tf.close() - stdlib.free(path_buf) - - if text_len <= 0: - stdlib.free(read_buf) - return None - read_buf[text_len] = '\0' - - # 构造搜索模式: "{sha1}.{class_name}.{method_name}" 或 bare 模式 "{sha1}.{method_name}" - cls_len: t.CSizeT = 0 - if class_name is not None: - cls_len = string.strlen(class_name) - meth_len: t.CSizeT = string.strlen(method_name) - search_len: t.CSizeT = sha1_len + meth_len + 2 - if use_bare == 0: - search_len = sha1_len + cls_len + meth_len + 4 - search_buf: bytes = stdlib.malloc(search_len) - if search_buf is None: - stdlib.free(read_buf) - return None - if use_bare != 0: - viperlib.snprintf(search_buf, search_len, "%s.%s", - class_sha1, method_name) - else: - viperlib.snprintf(search_buf, search_len, "%s.%s.%s", - class_sha1, class_name, method_name) - search_str_len: t.CSizeT = string.strlen(search_buf) - - # 在 text.ll 中搜索 define 行包含 search_buf - buf_len: t.CSizeT = string.strlen(read_buf) - pos: t.CSizeT = 0 - result_ty: llvmlite.LLVMType | t.CPtr = None - - while pos < buf_len and result_ty is None: - ls: t.CSizeT = pos - le: t.CSizeT = pos - while le < buf_len: - if read_buf[le] == '\n': - break - le += 1 - ll: t.CSizeT = le - ls - - # 检查是否是 define 行 - if ll >= 7 and string.strncmp(read_buf + ls, "define ", 7) == 0: - # 找 @ 符号 - at_pos: t.CSizeT = ls + 7 - while at_pos < ls + ll: - if read_buf[at_pos] == '@': - break - at_pos += 1 - if at_pos < ls + ll: - # 跳过可选引号 - name_start: t.CSizeT = at_pos + 1 - if name_start < ls + ll and read_buf[name_start] == '"': - name_start += 1 - # 检查是否匹配 search_buf - if name_start + search_str_len <= ls + ll: - if string.strncmp(read_buf + name_start, search_buf, search_str_len) == 0: - # 函数名边界检查:search 后必须是 '"'(带引号名)、'('(参数表)或行尾, - # 否则 "sha1.func" 会误匹配 "sha1.func_helper" 等前缀同名函数 - name_end: t.CSizeT = name_start + search_str_len - end_ch: int = 0 - if name_end < ls + ll: - end_ch = read_buf[name_end] - if end_ch == 34 or end_ch == 40 or end_ch == 0: - # 匹配!提取返回类型: [ls+7, at_pos) - result_ty = self._ParseLLVMRetTyStr(pool, read_buf, ls + 7, at_pos) - - pos = le + 1 - - stdlib.free(search_buf) - stdlib.free(read_buf) - return result_ty - - # ============================================================ - # _dep_text_ll_exists - 探测依赖模块 text.ll 是否已生成 - # - # 用于区分跨模块返回类型精确解析失败的两种场景: - # 1. text.ll 存在但函数未命中 → 真错误(依赖已编译,函数缺失) - # 2. text.ll 不存在 → 依赖模块尚未翻译(Phase A 按文件顺序翻译, - # main.vp 先于其 import 的 mbuddytest.vp),标记重试待下遍 - # ============================================================ - - # ============================================================ - def _dep_text_ll_exists(self, pool: memhub.MemBuddy | t.CPtr, - sha1: str) -> int: - """探测 {temp_dir}/{sha1[0:2]}/{sha1}.text.ll 是否存在,1=存在""" - if self.TempDir is None or self.TempDirLen == 0 or sha1 is None: - return 0 - sha1_len: t.CSizeT = string.strlen(sha1) - if sha1_len < 2: - return 0 - path_len: t.CSizeT = self.TempDirLen + sha1_len + 14 - path_buf: bytes = stdlib.malloc(path_len) - subdir_buf: bytes = stdlib.malloc(3) - if path_buf is None or subdir_buf is None: - if path_buf is not None: - stdlib.free(path_buf) - if subdir_buf is not None: - stdlib.free(subdir_buf) - return 0 - subdir_buf[0] = sha1[0] - subdir_buf[1] = sha1[1] - subdir_buf[2] = '\0' - viperlib.snprintf(path_buf, path_len, "%s/%s/%s.text.ll", - self.TempDir, subdir_buf, sha1) - stdlib.free(subdir_buf) - tf: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R) - exists: int = 0 - if not tf.closed: - tf.close() - exists = 1 - stdlib.free(path_buf) - return exists - - # ============================================================ - # 属性方法(@property/@x.setter/@x.deleter)与静态/类方法调用辅助 - # - # 元数据表由 HandlesClassDef 在类翻译/预注册阶段填充, - # 这里负责把 obj.prop / obj.prop=v / del obj.prop / Class.method() - # 翻译为对应的 {sha1}.ClassName.prop 系列函数调用。 - # ============================================================ - - # ============================================================ - # _translate_property_call — 翻译属性方法调用 - # - # 与 _translate_method_call 的调用名/返回类型解析逻辑一致: - # 1. 优先用模块中已有的函数(精确/后缀匹配,来自 stub 注入) - # 2. 否则用类所属模块的 SHA1 构造 "{sha1}.ClassName.method" 调用名 - # 3. 返回类型:函数实类型 → text.ll 查找 → 按方法名推断(默认 i32) - # - # call_head/call_count: 已构建好的参数链表(如 getter 只有 obj 一个参数) - # ============================================================ +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.Generator as Generator +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import sys +import viperlib +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.CompilerFactory as CompilerFactory +import lib.core.StubMergerCollect as StubMergerCollect +import lib.core.StubMergerStore as StubMergerStore + + + +# ============================================================ +# CallGenBase - CallGenMixin 拆分 1/9(最底层父类):模块符号查找 + +# 返回类型解析基础设施 +# +# 按功能域从 CallGenMixin.vp 拆出(500~1500 行/文件架构重构): +# 字段(15 个)+ InitCallGen + 模块符号查找(sha1/cexport/vpi/reexport/find_func_in_module) +# + 返回类型解析链(_ensure_method_declare/_LookupMethodRetTyFromTextLL/_dep_text_ll_exists 等) +# +# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 +# ============================================================ + + +# ============================================================ +# 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug) +# ============================================================ +GLOBAL_FUNC_MAX: t.CDefine = 8192 +GLOBAL_DEFAULTS_MAX: t.CDefine = 4096 +_CEXPORT_MAX: t.CDefine = 256 +ASM_MAX_OPERANDS: t.CDefine = 16 +ASM_TEXT_BUF_SIZE: t.CDefine = 2048 +ASM_CONST_BUF_SIZE: t.CDefine = 512 +ASM_ARGS_BUF_SIZE: t.CDefine = 512 +ASM_LINE_BUF_SIZE: t.CDefine = 4096 +LLVMIR_MAX_OPS: t.CDefine = 16 +LLVMIR_TEMPLATE_BUF: t.CDefine = 512 +# 闭包名表大小(原 HandlesExprCall 模块级常量) +MAX_CLOSURE_NAMES: t.CDefine = 128 +# 函数指针签名表大小(原 HandlesExprCall 模块级常量) +MAX_FUNC_PTR_SIGS: t.CDefine = 64 +# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32) +ISINSTANCE_CLASS_MAX: t.CDefine = 64 + + +# ============================================================ +# CallGenBase - 最底层父类(字段 + 模块查找 + 返回类型解析) +# ============================================================ +@t.NoVTable +class CallGenBase: + """调用分派最底层父类(字段 + 模块符号查找 + 返回类型解析基础设施)""" + + # --- c.cexport 注册表(原 _g_cexport_sha1_arr/_g_cexport_func_arr/_g_cexport_count) --- + Gen: Generator.Generator | t.CPtr + CexportSha1Arr: bytes + CexportFuncArr: bytes + CexportCount: int + + # --- LLVMIR 寄存器序号(原 _g_llvmir_reg_seq) --- + LLVMIRRegSeq: int + + # --- temp 目录(原 _g_temp_dir/_g_temp_dir_len) --- + TempDir: str + TempDirLen: t.CSizeT + + # --- 闭包名表(原 _g_closure_names/_g_closure_count) --- + ClosureNames: str + ClosureCount: int + + # --- 函数指针签名表(原 _g_funcptr_names/_g_funcptr_rets/_g_funcptr_count) --- + FuncptrNames: str + FuncptrRets: t.CUInt64T | t.CPtr + FuncptrCount: int + + # --- 全局函数注册表(原 _global_funcs/_global_func_count) --- + GlobalFuncs: GenTypes.FuncEntry | t.CPtr + GlobalFuncCount: int + + # --- 全局默认参数表(原 _global_defaults/_global_defaults_count) --- + GlobalDefaults: GenTypes.FuncDefaultsEntry | t.CPtr + GlobalDefaultsCount: int + + def InitCallGen(self) -> int: + """初始化调用 Mixin 字段(子类构造时内联调用,规避 NoVTable 继承符号不转发)""" + if self is None: + return 1 + self.CexportSha1Arr = None + self.CexportFuncArr = None + self.CexportCount = 0 + self.LLVMIRRegSeq = 0 + self.TempDir = None + self.TempDirLen = 0 + self.ClosureNames = None + self.ClosureCount = 0 + self.FuncptrNames = None + self.FuncptrRets = None + self.FuncptrCount = 0 + self.GlobalFuncs = None + self.GlobalFuncCount = 0 + self.GlobalDefaults = None + self.GlobalDefaultsCount = 0 + return 0 + + # ============================================================ + # P4 簇 1+2 迁移方法(函数体来自 HandlesExprCall.vp: + # 模块 SHA1 查询/CExport 注册表/c.* 系列/内联汇编/LLVMIR) + # 本模块函数调用改 self.,外部模块调用保留模块前缀 + # ============================================================ + + + + def _lookup_module_sha1(self, mod_name: str) -> str: + """查找模块名对应的 SHA1,找不到返回 None + + 委托给 StubMerger.LookupSha1ByModName(精确匹配 + 包名回退)。 + """ + return StubMergerStore.LookupSha1ByModName(mod_name) + + + def _lookup_module_sha1_suffix(self, mod_suffix: str) -> str: + """后缀匹配查找模块 SHA1,如 mod_suffix="__types" 匹配 "llvmlite.__types" + + 用于 from .X import Y 的相对导入:impf.module 是 ".X"(带前导点), + 去掉前导点后为 "X",SHA1 映射表中键是 "pkg.X",需要后缀匹配。 + 委托给 StubMerger.LookupSha1ByModNameSuffix(精确 + 后缀 + 反向后缀)。 + """ + return StubMergerStore.LookupSha1ByModNameSuffix(mod_suffix) + + + def _module_package_from_sha1(self, pool: memhub.MemBuddy | t.CPtr, + mod_sha1: str) -> str: + """从 SHA1 存储器的 rel_path 计算模块所属包名(目录部分,'/' → '.')""" + if pool is None or mod_sha1 is None: + return None + rel_arr_ptr: bytes | t.CPtr = StubMergerStore.GetSha1StoreRelArrPtr() + sha1_arr_ptr: bytes | t.CPtr = StubMergerStore.GetSha1StoreArrPtr() + count: int = StubMergerStore.GetSha1StoreCount() + if rel_arr_ptr is None or sha1_arr_ptr is None or count <= 0: + return None + for i in range(count): + sidx: t.CSizeT = t.CSizeT(i) * 17 + if string.strcmp(sha1_arr_ptr + sidx, mod_sha1) != 0: + continue + ridx: t.CSizeT = t.CSizeT(i) * StubMerger.MAX_REL_PATH_LEN + rel: str = rel_arr_ptr + ridx + last_slash: str = string.strrchr(rel, 47) # 47 = ord('/') + if last_slash is None: + return None + pkg_len: t.CSizeT = t.CSizeT(t.CUInt64T(last_slash) - t.CUInt64T(rel)) + if pkg_len == 0: + return None + pkg_buf: str = pool.alloc(pkg_len + 1) + if pkg_buf is None: + return None + for pi in range(pkg_len): + if rel[pi] == '/': + pkg_buf[pi] = '.' + else: + pkg_buf[pi] = rel[pi] + pkg_buf[pkg_len] = '\0' + return pkg_buf + return None + + + def _lookup_reexport_from_vpi(self, pool: memhub.MemBuddy | t.CPtr, + mod_sha1: str, func_name: str) -> str: + """re-export 表未命中时,从模块 .vpi 按需解析 from-import 定位定义模块 + + includes 模块(如 llvmlite/__init__)的 stub/text 已存在时不会被按需 + 全量翻译(Phase2 3.5 仅在 stub/text 缺失时翻译),而 re-export 表只在 + declare_only=0 的全量翻译中注册(HandleImportFromNames),因此表可能为空。 + 本函数解析该模块 .vpi 的 "from .X import ... func_name ..." 语句, + 返回定义模块名(如 llvmlite/__init__ 的 .__builder → "llvmlite.__builder")。 + """ + if pool is None or mod_sha1 is None or func_name is None: + return None + temp_dir: str = self.Gen.TypeGenBase.get_temp_dir() + if temp_dir is None: + return None + td_len: t.CSizeT = string.strlen(temp_dir) + vpi_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, mod_sha1, "vpi") + if vpi_path is None: + return None + READ_SZ: t.CSizeT = 1048576 + buf: bytes = stdlib.malloc(READ_SZ) + if buf is None: + stdlib.free(vpi_path) + return None + vf: fileio.File | t.CPtr = fileio.File(vpi_path, fileio.MODE.R) + stdlib.free(vpi_path) + if vf.closed: + stdlib.free(buf) + return None + nrd: LONG = vf.read_all(buf, READ_SZ) + vf.close() + if nrd <= 0: + stdlib.free(buf) + return None + if nrd < READ_SZ: + buf[nrd] = 0 + else: + buf[READ_SZ - 1] = 0 + name_len: t.CSizeT = string.strlen(func_name) + total: t.CSizeT = string.strlen(buf) + pos: t.CSizeT = 0 + while pos < total: + ls: t.CSizeT = pos + while pos < total and buf[pos] != '\n': + pos += 1 + ll: t.CSizeT = pos - ls + if pos < total: + pos += 1 + # 行必须以 "from " 开头 + if ll < 6: + continue + if buf[ls] != 'f' or buf[ls + 1] != 'r' or buf[ls + 2] != 'o' or buf[ls + 3] != 'm' or buf[ls + 4] != ' ': + continue + # 找 " import " 分隔符 + imp_pos: t.CSizeT = ls + 5 + while imp_pos + 7 <= ls + ll: + if buf[imp_pos] == ' ' and buf[imp_pos + 1] == 'i' and buf[imp_pos + 2] == 'm' and \ + buf[imp_pos + 3] == 'p' and buf[imp_pos + 4] == 'o' and buf[imp_pos + 5] == 'r' and \ + buf[imp_pos + 6] == 't' and buf[imp_pos + 7] == ' ': + break + imp_pos += 1 + if imp_pos + 7 > ls + ll: + continue + mod_start: t.CSizeT = ls + 5 + mod_end: t.CSizeT = imp_pos + # 名称列表从 "import " 之后(逗号分隔,含 "A as B" 取原名 A) + nm_start: t.CSizeT = imp_pos + 8 + scan: t.CSizeT = nm_start + while scan < ls + ll: + while scan < ls + ll and (buf[scan] == ' ' or buf[scan] == ','): + scan += 1 + if scan >= ls + ll: + break + n_end: t.CSizeT = scan + while n_end < ls + ll and buf[n_end] != ',' and buf[n_end] != ' ': + n_end += 1 + cand_start: t.CSizeT = scan + cand_len: t.CSizeT = n_end - scan + as_pos: t.CSizeT = scan + while as_pos + 4 <= n_end: + if buf[as_pos] == ' ' and buf[as_pos + 1] == 'a' and buf[as_pos + 2] == 's' and buf[as_pos + 3] == ' ': + cand_start = as_pos + 4 + cand_len = n_end - cand_start + break + as_pos += 1 + if cand_len == name_len: + m_ok: int = 1 + for ki in range(name_len): + if buf[cand_start + ki] != func_name[ki]: + m_ok = 0 + break + if m_ok == 1: + # 命中:解析模块名(前导点 → 相对导入,补包前缀) + has_dot: int = 0 + if buf[mod_start] == '.': + has_dot = 1 + mod_buf: str = pool.alloc(mod_end - mod_start + 1) + if mod_buf is None: + stdlib.free(buf) + return None + mi: t.CSizeT = 0 + while mod_start + mi < mod_end: + mod_buf[mi] = buf[mod_start + mi] + mi += 1 + mod_buf[mi] = '\0' + while mod_buf[0] == '.': + mod_buf = mod_buf + 1 + if string.strlen(mod_buf) == 0: + stdlib.free(buf) + return None + if has_dot != 0: + pkg: str = self._module_package_from_sha1(pool, mod_sha1) + if pkg is None: + stdlib.free(buf) + return None + rl: t.CSizeT = string.strlen(pkg) + string.strlen(mod_buf) + 2 + res: str = pool.alloc(rl) + if res is None: + stdlib.free(buf) + return None + viperlib.snprintf(res, rl, "%s.%s", pkg, mod_buf) + stdlib.free(buf) + return res + stdlib.free(buf) + return mod_buf + scan = n_end + stdlib.free(buf) + return None + + + def register_cexport_func(self, sha1: str, func_name: str) -> int: + """注册 CExport 函数到全局表(统一写入 Gen.CallGenBase 真源,跨子对象共享)""" + if self.Gen is None or sha1 is None or func_name is None: + return 0 + if self.Gen.CallGenBase.CexportSha1Arr is None: + self.Gen.CallGenBase.CexportSha1Arr = CompilerFactory.get_perm_pool().alloc(_CEXPORT_MAX * 17) + self.Gen.CallGenBase.CexportFuncArr = CompilerFactory.get_perm_pool().alloc(_CEXPORT_MAX * 64) + if self.Gen.CallGenBase.CexportSha1Arr is None or self.Gen.CallGenBase.CexportFuncArr is None: + return 0 + string.memset(self.Gen.CallGenBase.CexportSha1Arr, 0, _CEXPORT_MAX * 17) + string.memset(self.Gen.CallGenBase.CexportFuncArr, 0, _CEXPORT_MAX * 64) + if self.Gen.CallGenBase.CexportCount < _CEXPORT_MAX: + idx: t.CSizeT = t.CSizeT(self.Gen.CallGenBase.CexportCount) * 17 + # 槽位定长 17/64 字节,strcpy 无界会越界写相邻槽(stdlib 堆区) + string.strncpy(self.Gen.CallGenBase.CexportSha1Arr + idx, sha1, 16) + self.Gen.CallGenBase.CexportSha1Arr[idx + 16] = '\0' + idx2: t.CSizeT = t.CSizeT(self.Gen.CallGenBase.CexportCount) * 64 + string.strncpy(self.Gen.CallGenBase.CexportFuncArr + idx2, func_name, 63) + self.Gen.CallGenBase.CexportFuncArr[idx2 + 63] = '\0' + self.Gen.CallGenBase.CexportCount += 1 + return 1 + return 0 + + + def is_cexport_func(self, sha1: str, func_name: str) -> int: + """检查 (sha1, func_name) 是否是 CExport 函数(统一读 Gen.CallGenBase 真源)""" + if self.Gen is None or sha1 is None or func_name is None: + return 0 + if self.Gen.CallGenBase.CexportSha1Arr is None: + return 0 + for i in range(self.Gen.CallGenBase.CexportCount): + idx: t.CSizeT = t.CSizeT(i) * 17 + if string.strcmp(self.Gen.CallGenBase.CexportSha1Arr + idx, sha1) == 0: + idx2: t.CSizeT = t.CSizeT(i) * 64 + if string.strcmp(self.Gen.CallGenBase.CexportFuncArr + idx2, func_name) == 0: + return 1 + return 0 + + + def _is_state_func_from_vpi(self, pool: memhub.MemBuddy | t.CPtr, + sha1: str, func_name: str) -> int: + """vpi 返回注解含 t.State → 外部 C 函数(定义端用裸名,跨模块调用无 sha1 头) + + t.State(同 t.CExtern/t.CExport)是外部函数标记:定义端生成裸名 + @PyList_Size(链接外部库 libpython),跨模块调用若生成 @{sha1}.PyList_Size + → ld.lld undefined symbol(CPythonTest PyList_Size 根因)。CExport 走 + is_cexport_func 注册表,State 函数未注册 → 按需解析 vpi 返回注解判断。 + """ + if pool is None or sha1 is None or func_name is None: + return 0 + import lib.StubGen.VpiReader as VpiReader + if self.Gen.CallGenBase.TempDir is not None and self.Gen.CallGenBase.TempDirLen > 0: + VpiReader._ensure_vpi_ret_annot_loaded(sha1, self.Gen.CallGenBase.TempDir) + state_annot: str = VpiReader._lookup_vpi_ret_annot(sha1, None, func_name) + if state_annot is None: + return 0 + # 返回注解含 "State"(如 "t.CSizeT | t.State")→ 外部 C 函数 + if string.strstr(state_annot, "State") is not None: + return 1 + return 0 + + + def _lookup_mod_sha1(self, pool: memhub.MemBuddy | t.CPtr, + from_imports: str, class_name: str, + allow_star_fallback: int = 1) -> str: + """从 from_imports 查找类所属模块的 SHA1,返回 None=未找到 + + allow_star_fallback: 传 0 禁用 star import 回退(用于明确模块名/函数名查找) + """ + mod_name_raw: str = self.Gen.ImportsGen.lookup_from_import( + from_imports, class_name, allow_star_fallback) + if mod_name_raw is None: + return None + return self._lookup_sha1_from_modname_raw(pool, mod_name_raw) + + + def _lookup_sha1_from_modname_raw(self, pool: memhub.MemBuddy | t.CPtr, + mod_name_raw: str) -> str: + """从原始模块名查找 SHA1,返回 None=未找到""" + # 手动找到模块名结束位置(空格、null、或 ':' 别名分隔符),复制到新缓冲区 + mod_len: t.CSizeT = 0 + while mod_name_raw[mod_len] != ' ' and mod_name_raw[mod_len] != '\0' and mod_name_raw[mod_len] != ':': + mod_len += 1 + mod_name_buf: str = pool.alloc(mod_len + 1) + if mod_name_buf is None: + return None + for mi in range(mod_len): + mod_name_buf[mi] = mod_name_raw[mi] + mod_name_buf[mod_len] = '\0' + # 去掉相对导入的前导点 + base_mod: str = mod_name_buf + while base_mod[0] == '.': + base_mod = base_mod + 1 + sha1: str = self._lookup_module_sha1(base_mod) + if sha1 is None: + sha1 = self._lookup_module_sha1_suffix(base_mod) + return sha1 + + + def find_func_in_module(self, mod: llvmlite.LLVMModule | t.CPtr, + name: str) -> llvmlite.Function | t.CPtr: + """在模块的函数链表中按名称查找函数 + + 查找策略: + 1. 精确匹配(如 "strlen" 匹配 @strlen,有 t.CExport 的函数) + 2. 后缀匹配(如 "atoi" 匹配 @"83210a72e829a086.atoi",无 t.CExport 的函数) + + 使用 llvmlite.function_get_name/next 访问器绕过 stub 类型限制 + (stub 类型字段不足且字段类型可能错误,直接字段访问会被静默跳过)。 + """ + if mod is None or name is None: + return None + name_len: t.CSizeT = string.strlen(name) + cur: llvmlite.Function | t.CPtr = mod.FuncHead + # 第一遍:精确匹配 + while cur is not None: + cur_name: str = llvmlite.function_get_name(cur) + if cur_name is not None: + if string.strcmp(cur_name, name) == 0: + return cur + cur = llvmlite.function_get_next(cur) + # 第二遍:后缀匹配(.name) + # 不跳过 declare:方法 stub 也是 declare,需要通过后缀匹配找到 + # 调用处(translate_call 等)负责判断 IsDeclared 并决定使用裸名还是 sha1 前缀名 + # + # 修复:本模块 define 优先于跨模块 stub declare。 + # 根因:跨模块同名函数(如 lexer.vp 的 _advance 与 parser.vp 的 _advance) + # 的 stub declare 在 stub 注入时排在 FuncHead 前面,裸名调用 _advance 后缀 + # 匹配按链表顺序先命中跨模块 declare → 参数按 Lexer* coerce → Parser* 被 + # bitcast 成 Lexer* → lexer 版 _advance 按 Lexer 布局操作 Parser 指针, + # cur 永不推进 → parse 无限循环。本模块同名 define 必须优先。 + cur = mod.FuncHead + while cur is not None: + cur_name2: str = llvmlite.function_get_name(cur) + if cur_name2 is not None: + cur_len: t.CSizeT = string.strlen(cur_name2) + if cur_len > name_len + 1: + suffix_start: t.CSizeT = cur_len - name_len + if cur_name2[suffix_start - 1] == '.': + match: int = 1 + for i in range(name_len): + if cur_name2[suffix_start + i] != name[i]: + match = 0 + break + if match == 1: + if cur.IsDeclared == 0: + return cur + cur = llvmlite.function_get_next(cur) + # 本模块无同名 define:回退到 stub declare(跨模块方法/函数调用) + cur = mod.FuncHead + while cur is not None: + cur_name3: str = llvmlite.function_get_name(cur) + if cur_name3 is not None: + cur_len3: t.CSizeT = string.strlen(cur_name3) + if cur_len3 > name_len + 1: + suffix_start3: t.CSizeT = cur_len3 - name_len + if cur_name3[suffix_start3 - 1] == '.': + match3: int = 1 + for i in range(name_len): + if cur_name3[suffix_start3 + i] != name[i]: + match3 = 0 + break + if match3 == 1: + return cur + cur = llvmlite.function_get_next(cur) + return None + + + # ============================================================ + # _ensure_method_declare - 为跨模块方法调用创建 declare 声明 + # + # 当 found_func 为 None(stub 未注入或跨模块调用)时, + # 在当前模块中创建函数声明,避免 llc 报 undefined value。 + # ============================================================ + def _ensure_method_declare(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + call_name: str, + ret_ty: llvmlite.LLVMType | t.CPtr, + param_head: llvmlite.ParamNode | t.CPtr, + param_count: int): + """为跨模块方法调用创建 declare 声明 + + 若模块中已存在同名 declare 且参数数量较少(例如 File.__init__ 的 + stub 仅 3 个参数,而实际调用传入 4 个),则向现有 declare 追加缺失 + 参数,避免 llc 报 `argument invalid for parameter type` 之类的错误。 + 已存在的 define 不修改(其参数由定义决定)。 + """ + if pool is None or mod is None or call_name is None: + return + # 链遍历哨兵(fail-fast):FuncHead/Params 的 Next 被越界写破坏成环时 + # 无上限遍历会死循环(builtins.vp dump 卡死根因排查),超限即报错终止。 + DECLARE_CHAIN_LIMIT: int = 100000 + # 检查模块中是否已有同名函数(declare 或 define) + existing: llvmlite.Function | t.CPtr = mod.FuncHead + existing_steps: int = 0 + while existing is not None: + existing_steps += 1 + if existing_steps > DECLARE_CHAIN_LIMIT: + stdio.printf("[CALLGEN] 链表异常: module funcs(call_name=%s,遍历超限,终止)\n", call_name) + stdlib.exit(1) + if existing.Name is not None: + if string.strcmp(existing.Name, call_name) == 0: + # 已存在:仅当是 declare 且参数数量不足时追加缺失参数 + if existing.IsDeclared == 1: + # 变长函数(*args,IsVarArg=1)不追加参数:多余实参由 + # 变参机制(...)承接,追加有类型参数会导致调用侧把变参 + # 强转为追加的类型(如 i8 → i64),%d/%x 等格式读错。 + if existing.IsVarArg == 1: + return + # 遍历现有参数链表计数(避免依赖 GSList.Count 字段的类型推断) + cur_count: int = 0 + cur_p: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(existing) + while cur_p is not None: + cur_count += 1 + if cur_count > DECLARE_CHAIN_LIMIT: + stdio.printf("[CALLGEN] 链表异常: func params(call_name=%s,参数链遍历超限,终止)\n", call_name) + stdlib.exit(1) + cur_p = cur_p.Next + # 只追加缺失的参数(cur_count < param_count 时) + if cur_count < param_count: + # 定位到 param_head 的第 cur_count 个节点开始追加 + pnode2: llvmlite.ParamNode | t.CPtr = param_head + pi2: int = 0 + # 跳过已有的 cur_count 个参数 + while pnode2 is not None and pi2 < cur_count: + pnode2 = pnode2.Next + pi2 += 1 + # 追加剩余参数 + while pnode2 is not None and pi2 < param_count: + if pnode2.Ty is not None: + param2: llvmlite.Param | t.CPtr = llvmlite.new_param(pool, pnode2.Ty, None) + if param2 is not None: + llvmlite.function_add_param(existing, param2) + pnode2 = pnode2.Next + pi2 += 1 + return + existing = existing.Next + # 创建函数声明 + func: llvmlite.Function | t.CPtr = llvmlite.new_function(pool, call_name, ret_ty) + if func is None: + return + func.IsDeclared = 1 + # 添加参数(declare 中参数名无意义,设为 None 只输出类型) + pnode: llvmlite.ParamNode | t.CPtr = param_head + pi: int = 0 + while pnode is not None and pi < param_count: + if pnode.Ty is not None: + param: llvmlite.Param | t.CPtr = llvmlite.new_param(pool, pnode.Ty, None) + if param is not None: + llvmlite.function_add_param(func, param) + pnode = pnode.Next + pi += 1 + llvmlite.module_add_function(mod, func) + + # ============================================================ + # _lookup_method_ret_ty_via_vpi - 从 vpi stub 返回注解缓存精确获取方法返回类型 + # + # 方法定义处(.vpi stub)的返回注解(如 json.JsonValue._pool_alloc → + # "str")在 stub 注入时由 VpiReader 缓存(_cache_vpi_return_annots_text)。 + # 此函数按 模块SHA1 + 类名 + 方法名 查缓存并纯字符串解析为 LLVMType。 + # 无需硬编码白名单——返回类型始终来自方法定义处。 + # ============================================================ + + # ============================================================ + def _lookup_method_ret_ty_via_vpi(self, pool: memhub.MemBuddy | t.CPtr, + cls_sha1: str, + cls_name: str, + method_name: str) -> llvmlite.LLVMType | t.CPtr: + """从 vpi stub 返回注解缓存获取方法返回类型,未命中返回 None""" + if pool is None or cls_sha1 is None or method_name is None: + return None + # 函数内懒 import:VpiReader imports HandlesExprCall,顶层 import 会成环 + import lib.StubGen.VpiReader as VpiReader + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + # 按需加载:缓存未命中时直接读 {temp_dir}/{sha1[0:2]}/{sha1}.vpi + # 覆盖"模块自身翻译时 stub 尚未注入"(同模块方法调用,定义在后)的场景 + if self.Gen.CallGenBase.TempDir is not None and self.Gen.CallGenBase.TempDirLen > 0: + VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, self.Gen.CallGenBase.TempDir) + annot: str = VpiReader._lookup_vpi_ret_annot(cls_sha1, cls_name, method_name) + if annot is None: + return None + return VpiReader._resolve_vpi_ret_annot_str(pool, annot, i32_ty, i8_ptr_ty) + + # ============================================================ + # _special_method_ret_ty - 编译器内置特殊方法的固定返回类型 + # + # __before_init__ / __init__:编译器生成/约定返回 void + # __new__:返回 Ptr(StructTy)(存储空间指针) + # + # 这些方法不存在于源码(vpi stub 无条目),跨模块调用时 + # found_func/text.ll/vpi 缓存必然未命中,但返回类型是编译器 + # 确定性语义(与 HandlesClassDef._translate_method 3543-3548 一致), + # 在此直接固定,不触发 fail-fast 误报。非特殊方法返回 None。 + # ============================================================ + + # ============================================================ + def _special_method_ret_ty(self, pool: memhub.MemBuddy | t.CPtr, + class_name: str, + method_name: str) -> llvmlite.LLVMType | t.CPtr: + """编译器内置特殊方法的固定返回类型;非特殊返回 None""" + if pool is None or method_name is None: + return None + if string.strcmp(method_name, "__before_init__") == 0 or \ + string.strcmp(method_name, "__init__") == 0: + return llvmlite.Void(pool) + if string.strcmp(method_name, "__new__") == 0: + if class_name is not None: + sp_struct_ty: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type(class_name) + if sp_struct_ty is not None: + return llvmlite.Ptr(pool, sp_struct_ty) + return None + return None + + # ============================================================ + # _fail_method_ret_ty - 方法返回类型无法精确获取时 fail-fast + # + # 返回类型来源(按序):当前模块函数 → text.ll define → vpi stub 返回注解缓存。 + # 全部未命中时立即 ERROR + 错误堆栈终止,绝不按名推断白名单/静默默认 i32。 + # + # node: 调用点 AST 节点(可选,用于 ERROR 堆栈定位) + # ============================================================ + + # ============================================================ + def _fail_method_ret_ty(self, method_name: str, + node: ast.AST | t.CPtr = None) -> llvmlite.LLVMType | t.CPtr: + """方法返回类型无法精确获取时 fail-fast(ERROR + 错误堆栈) + + 返回类型来源(按序):当前模块函数 → text.ll define → vpi stub 返回注解缓存。 + 全部未命中说明方法定义缺失或 stub 损坏,立即终止暴露,绝不静默默认 i32。 + """ + VLogger.error( + f"方法返回类型无法精确获取(函数/text.ll/vpi stub 均未命中): {method_name}", + "HandlesExprCall") + self.Gen.TypeGenErr.fatal_error( + node, + f"方法返回类型无法精确获取,默认 i32 会截断指针/i64: {method_name}", + "TypeError") + return None + + # ============================================================ + # SetTempDir - 设置 temp 目录路径 + # + # 在 Phase2.py 的 Phase A 翻译前调用,使 CallGenMixin + # 能够读取依赖模块的 text.ll 文件。 + # ============================================================ + + # ============================================================ + def SetTempDir(self, temp_dir: str): + """设置 temp 目录路径(统一写入 Gen.CallGenBase 真源,跨子对象共享)""" + if self.Gen is None: + return + self.Gen.CallGenBase.TempDir = temp_dir + if temp_dir is not None: + self.Gen.CallGenBase.TempDirLen = string.strlen(temp_dir) + else: + self.Gen.CallGenBase.TempDirLen = 0 + + # ============================================================ + # _ParseLLVMRetTyStr - 将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType + # + # 从 define 行中提取的返回类型字符串(define 与 @ 之间的内容), + # 转换为 llvmlite.LLVMType 对象。 + # + # 支持的类型: + # void → Void + # i8/i16/i32/i64 → Int8/Int16/Int32/Int64 + # double → Double, float → Float + # 任何含 * 的类型 → Ptr(Int8)(通用指针,保留 64 位地址) + # + # Args: + # pool: 内存池 + # buf: 包含类型字符串的缓冲区 + # start: 类型字符串起始位置 + # end: 类型字符串结束位置(不含) + # + # Returns: + # LLVM 类型对象,或 None(无法解析) + # ============================================================ + + # ============================================================ + def _ParseLLVMRetTyStr(self, pool: memhub.MemBuddy | t.CPtr, + buf: bytes, + start: t.CSizeT, + end: t.CSizeT) -> llvmlite.LLVMType | t.CPtr: + """将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType""" + if pool is None or buf is None or start >= end: + return None + + # 去除前导空白 + s: t.CSizeT = start + while s < end: + c: int = buf[s] + if c != ' ' and c != '\t': + break + s += 1 + # 去除尾部空白 + e: t.CSizeT = end + while e > s: + c2: int = buf[e - 1] + if c2 != ' ' and c2 != '\t': + break + e -= 1 + + ty_len: t.CSizeT = e - s + if ty_len == 0: + return None + + # struct 字面量 {T1, T2, ...}(tuple 打包返回类型,如 b2a_hqx -> + # tuple[str, t.CUnsignedShort] 编译为 {i8*, i16})。必须在 * 检查 + # 之前——否则 "{i8*, i16}" 内含 * 会被误判为 i8*(b2a_hqx 调用侧 + # 返回类型退化 i8* → HandlesAssign tuple 解包静默跳过 → free 未初始化 + # 指针崩溃,HashLibTest hqx 段)。 + if s < e and buf[s] == '{': + th_st: llvmlite.ParamNode | t.CPtr = None + tt_st: llvmlite.ParamNode | t.CPtr = None + tc_st: int = 0 + ps_st: t.CSizeT = s + 1 + while ps_st < e and buf[ps_st] != '}': + while ps_st < e and (buf[ps_st] == ' ' or buf[ps_st] == ','): + ps_st += 1 + if ps_st >= e or buf[ps_st] == '}': + break + es_st: t.CSizeT = ps_st + while ps_st < e and buf[ps_st] != ',' and buf[ps_st] != '}': + ps_st += 1 + ee_st: t.CSizeT = ps_st + if ee_st > es_st: + et_st: llvmlite.LLVMType | t.CPtr = self._ParseLLVMRetTyStr( + pool, buf, es_st, ee_st) + if et_st is None: + return None + en_st: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node( + pool, et_st) + if en_st is None: + return None + if th_st is None: + th_st = en_st + else: + llvmlite.paramnode_set_next(tt_st, en_st) + tt_st = en_st + tc_st += 1 + if th_st is None or tc_st == 0: + return None + st_ty_st: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, th_st, tc_st, None) + # 指针到 struct({i32, i8}*):返回 Ptr(Struct);纯 tuple 打包 + # ({i8*, i16})无尾部 *,返回 Struct 本身。 + if ps_st < e and buf[ps_st] == '*': + return llvmlite.Ptr(pool, st_ty_st) + return st_ty_st + + # 检查是否含 * (指针类型) → 返回 i8* (通用指针) + # 包括 i8*, i32*, %"name"*, { i32, i8 }* 等 + ci: t.CSizeT = s + while ci < e: + if buf[ci] == '*': + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + ci += 1 + + # void + if ty_len == 4 and string.strncmp(buf + s, "void", 4) == 0: + return llvmlite.Void(pool) + + # double + if ty_len == 6 and string.strncmp(buf + s, "double", 6) == 0: + return llvmlite.Double(pool) + + # float + if ty_len == 5 and string.strncmp(buf + s, "float", 5) == 0: + return llvmlite.Float(pool) + + # iN (i8, i16, i32, i64) + if ty_len >= 2 and buf[s] == 'i': + bits: int = 0 + di: t.CSizeT = s + 1 + valid: int = 1 + while di < e: + d: int = buf[di] + if d >= '0' and d <= '9': + bits = bits * 10 + (d - '0') + else: + valid = 0 + break + di += 1 + if valid != 0 and bits > 0: + if bits == 8: + return llvmlite.Int8(pool) + if bits == 16: + return llvmlite.Int16(pool) + if bits == 32: + return llvmlite.Int32(pool) + if bits == 64: + return llvmlite.Int64(pool) + + # 无法解析 + return None + + # ============================================================ + # _LookupMethodRetTyFromTextLL - 从依赖模块的 text.ll 查找方法返回类型 + # + # 读取 {temp_dir}/{sha1[0:2]}/{sha1}.text.ll (level=1),搜索 + # define 行中包含 "{sha1}.{class_name}.{method_name}" 的函数, + # 提取返回类型并转换为 llvmlite.LLVMType。 + # + # 解决问题: 旧实现 _infer_method_ret_ty(已移除)默认返回 i32,导致指针返回值 + # 被 inttoptr 截断为 32 位(coerce_to_type line 238-239)。 + # 本函数从 text.ll 获取实际返回类型,避免截断。 + # + # Args: + # pool: 内存池 + # class_sha1: 类所属模块的 SHA1 + # class_name: 类名 + # method_name: 方法名 + # + # Returns: + # LLVM 类型对象,或 None(未找到/text.ll 不存在) + # ============================================================ + + # ============================================================ + def _LookupMethodRetTyFromTextLL(self, pool: memhub.MemBuddy | t.CPtr, + class_sha1: str, + class_name: str, + method_name: str, + use_bare: int = 0) -> llvmlite.LLVMType | t.CPtr: + """从依赖模块的 text.ll 中查找方法返回类型 + + use_bare: 1=按模块级函数查找(搜索 "{sha1}.{method_name}" define, + 用于 new_lexer/tokenize 等模块函数;class_name 忽略)。 + """ + if pool is None or class_sha1 is None or method_name is None: + return None + if self.Gen.CallGenBase.TempDir is None or self.Gen.CallGenBase.TempDirLen == 0: + return None + + sha1_len: t.CSizeT = string.strlen(class_sha1) + if sha1_len < 2: + return None + + # 构造 text.ll 路径 (level=1): {temp_dir}/{sha1[0:2]}/{sha1}.text.ll + # 使用 subdir 缓冲区避免 %c 格式化问题(与 StubMerger._sliced_path 一致) + path_len: t.CSizeT = self.Gen.CallGenBase.TempDirLen + sha1_len + 14 + path_buf: bytes = stdlib.malloc(path_len) + if path_buf is None: + return None + subdir_buf: bytes = stdlib.malloc(3) + if subdir_buf is None: + stdlib.free(path_buf) + return None + subdir_buf[0] = class_sha1[0] + subdir_buf[1] = class_sha1[1] + subdir_buf[2] = '\0' + viperlib.snprintf(path_buf, path_len, "%s/%s/%s.text.ll", + self.Gen.CallGenBase.TempDir, subdir_buf, class_sha1) + stdlib.free(subdir_buf) + + # 读取 text.ll(按文件实际大小分配:固定 _TEXT_LL_READ_BUF_SIZE(256KB) + # 会截断大模块的 text.ll,末尾方法定义查不到 → 误报"方法返回类型无法 + # 精确获取"(追加80b 根因,同追加74 _read_source_line 截断)。64MB 上限 + # 防御异常超大文件整体读取。) + tf: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R) + if tf.closed: + stdlib.free(path_buf) + return None + tfsize: LONGLONG = tf.size() + if tfsize <= 0 or tfsize > 67108864: + tf.close() + stdlib.free(path_buf) + return None + read_size: t.CSizeT = t.CSizeT(tfsize) + read_buf: bytes = stdlib.malloc(read_size + 1) + if read_buf is None: + tf.close() + stdlib.free(path_buf) + return None + text_len: t.CInt64T = tf.read_all(read_buf, ULONG(read_size + 1)) + tf.close() + stdlib.free(path_buf) + + if text_len <= 0: + stdlib.free(read_buf) + return None + read_buf[text_len] = '\0' + + # 构造搜索模式: "{sha1}.{class_name}.{method_name}" 或 bare 模式 "{sha1}.{method_name}" + cls_len: t.CSizeT = 0 + if class_name is not None: + cls_len = string.strlen(class_name) + meth_len: t.CSizeT = string.strlen(method_name) + search_len: t.CSizeT = sha1_len + meth_len + 2 + if use_bare == 0: + search_len = sha1_len + cls_len + meth_len + 4 + search_buf: bytes = stdlib.malloc(search_len) + if search_buf is None: + stdlib.free(read_buf) + return None + if use_bare != 0: + viperlib.snprintf(search_buf, search_len, "%s.%s", + class_sha1, method_name) + else: + viperlib.snprintf(search_buf, search_len, "%s.%s.%s", + class_sha1, class_name, method_name) + search_str_len: t.CSizeT = string.strlen(search_buf) + + # 在 text.ll 中搜索 define 行包含 search_buf + buf_len: t.CSizeT = string.strlen(read_buf) + pos: t.CSizeT = 0 + result_ty: llvmlite.LLVMType | t.CPtr = None + + while pos < buf_len and result_ty is None: + ls: t.CSizeT = pos + le: t.CSizeT = pos + while le < buf_len: + if read_buf[le] == '\n': + break + le += 1 + ll: t.CSizeT = le - ls + + # 检查是否是 define 行 + if ll >= 7 and string.strncmp(read_buf + ls, "define ", 7) == 0: + # 找 @ 符号 + at_pos: t.CSizeT = ls + 7 + while at_pos < ls + ll: + if read_buf[at_pos] == '@': + break + at_pos += 1 + if at_pos < ls + ll: + # 跳过可选引号 + name_start: t.CSizeT = at_pos + 1 + if name_start < ls + ll and read_buf[name_start] == '"': + name_start += 1 + # 检查是否匹配 search_buf + if name_start + search_str_len <= ls + ll: + if string.strncmp(read_buf + name_start, search_buf, search_str_len) == 0: + # 函数名边界检查:search 后必须是 '"'(带引号名)、'('(参数表)或行尾, + # 否则 "sha1.func" 会误匹配 "sha1.func_helper" 等前缀同名函数 + name_end: t.CSizeT = name_start + search_str_len + end_ch: int = 0 + if name_end < ls + ll: + end_ch = read_buf[name_end] + if end_ch == 34 or end_ch == 40 or end_ch == 0: + # 匹配!提取返回类型: [ls+7, at_pos) + result_ty = self._ParseLLVMRetTyStr(pool, read_buf, ls + 7, at_pos) + + pos = le + 1 + + stdlib.free(search_buf) + stdlib.free(read_buf) + return result_ty + + # ============================================================ + # _dep_text_ll_exists - 探测依赖模块 text.ll 是否已生成 + # + # 用于区分跨模块返回类型精确解析失败的两种场景: + # 1. text.ll 存在但函数未命中 → 真错误(依赖已编译,函数缺失) + # 2. text.ll 不存在 → 依赖模块尚未翻译(Phase A 按文件顺序翻译, + # main.vp 先于其 import 的 mbuddytest.vp),标记重试待下遍 + # ============================================================ + + # ============================================================ + def _dep_text_ll_exists(self, pool: memhub.MemBuddy | t.CPtr, + sha1: str) -> int: + """探测 {temp_dir}/{sha1[0:2]}/{sha1}.text.ll 是否存在,1=存在""" + if self.Gen.CallGenBase.TempDir is None or self.Gen.CallGenBase.TempDirLen == 0 or sha1 is None: + return 0 + sha1_len: t.CSizeT = string.strlen(sha1) + if sha1_len < 2: + return 0 + path_len: t.CSizeT = self.Gen.CallGenBase.TempDirLen + sha1_len + 14 + path_buf: bytes = stdlib.malloc(path_len) + subdir_buf: bytes = stdlib.malloc(3) + if path_buf is None or subdir_buf is None: + if path_buf is not None: + stdlib.free(path_buf) + if subdir_buf is not None: + stdlib.free(subdir_buf) + return 0 + subdir_buf[0] = sha1[0] + subdir_buf[1] = sha1[1] + subdir_buf[2] = '\0' + viperlib.snprintf(path_buf, path_len, "%s/%s/%s.text.ll", + self.Gen.CallGenBase.TempDir, subdir_buf, sha1) + stdlib.free(subdir_buf) + tf: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R) + exists: int = 0 + if not tf.closed: + tf.close() + exists = 1 + stdlib.free(path_buf) + return exists + + # ============================================================ + # 属性方法(@property/@x.setter/@x.deleter)与静态/类方法调用辅助 + # + # 元数据表由 HandlesClassDef 在类翻译/预注册阶段填充, + # 这里负责把 obj.prop / obj.prop=v / del obj.prop / Class.method() + # 翻译为对应的 {sha1}.ClassName.prop 系列函数调用。 + # ============================================================ + + # ============================================================ + # _translate_property_call — 翻译属性方法调用 + # + # 与 _translate_method_call 的调用名/返回类型解析逻辑一致: + # 1. 优先用模块中已有的函数(精确/后缀匹配,来自 stub 注入) + # 2. 否则用类所属模块的 SHA1 构造 "{sha1}.ClassName.method" 调用名 + # 3. 返回类型:函数实类型 → text.ll 查找 → 按方法名推断(默认 i32) + # + # call_head/call_count: 已构建好的参数链表(如 getter 只有 obj 一个参数) + # ============================================================ diff --git a/App/lib/core/Gen/CallGenCBuiltin.vp b/App/lib/core/Gen/CallGenCBuiltin.vp index 1cbae0f..37e3285 100644 --- a/App/lib/core/Gen/CallGenCBuiltin.vp +++ b/App/lib/core/Gen/CallGenCBuiltin.vp @@ -1,1414 +1,1407 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import sys -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesFunctions as HandlesFunctions -import lib.core.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.CompilerFactory as CompilerFactory - - -import lib.core.Gen.CallGenBase as CallGenBase - - -# ============================================================ -# CallGenCBuiltin - CallGenMixin 拆分 2/9:c.* 内建 + asm + llvmir -# -# 按功能域从 CallGenMixin.vp 拆出(500~1500 行/文件架构重构): -# translate_c_deref/derefas/set/addr/load + c.Asm 全套 + c.LLVMIR。 -# 继承 CallGenBase。 -# -# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 -# ============================================================ - - -# ============================================================ -# _IsTypeExpr / _IsCastWrappingDeref - c.Deref 加载宽度推断的转换包裹判定 -# (镜像 TPC HandlesSpecialCall:转换链包裹 Deref 时允许从赋值注解推断 -# 加载宽度;ifexp/binop 包裹不放行,避免 i8* 错 bitcast 成其他位宽读) -# ============================================================ -def _IsTypeExpr(node: ast.AST | t.CPtr) -> int: - """节点是否为类型表达式(Name/Attribute/Subscript/BinOp|)""" - if node is None: - return 0 - k: int = node.kind() - if k == ast.ASTKind.Name or k == ast.ASTKind.Attribute or k == ast.ASTKind.Subscript: - return 1 - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - if bop.op == ast.OpKind.BitOr: - return 1 - return 0 - - -def _IsCastWrappingDeref(rhs: ast.AST | t.CPtr, deref_node: ast.AST | t.CPtr) -> int: - """rhs 是否为"类型转换链包裹 c.Deref"(如 (T | t.CPtr)(t.CPtr(c.Deref(p))))""" - if rhs is None: - return 0 - if t.CUInt64T(rhs) == t.CUInt64T(deref_node): - return 1 - if rhs.kind() == ast.ASTKind.Call: - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(rhs) - if cl.args is not None and len(cl.args) == 1 and _IsTypeExpr(cl.func) != 0: - return _IsCastWrappingDeref(cl.args.get(0), deref_node) - return 0 - - -# ============================================================ -# 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug) -# ============================================================ -GLOBAL_FUNC_MAX: t.CDefine = 8192 -GLOBAL_DEFAULTS_MAX: t.CDefine = 4096 -_CEXPORT_MAX: t.CDefine = 256 -ASM_MAX_OPERANDS: t.CDefine = 16 -ASM_TEXT_BUF_SIZE: t.CDefine = 2048 -ASM_CONST_BUF_SIZE: t.CDefine = 512 -ASM_ARGS_BUF_SIZE: t.CDefine = 512 -ASM_LINE_BUF_SIZE: t.CDefine = 4096 -LLVMIR_MAX_OPS: t.CDefine = 16 -LLVMIR_TEMPLATE_BUF: t.CDefine = 512 -# 闭包名表大小(原 HandlesExprCall 模块级常量) -MAX_CLOSURE_NAMES: t.CDefine = 128 -# 函数指针签名表大小(原 HandlesExprCall 模块级常量) -MAX_FUNC_PTR_SIGS: t.CDefine = 64 -# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32) -ISINSTANCE_CLASS_MAX: t.CDefine = 64 - - -# ============================================================ -# CallGenCBuiltin - c.*/asm/llvmir 内建 -# ============================================================ -@t.NoVTable -class CallGenCBuiltin(CallGenBase.CallGenBase): - """c.* 内建 + 内联汇编 + LLVMIR 翻译(继承 Base)""" - - - def translate_c_deref(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """c.Deref(ptr) → load 按 ptr 的 pointee 类型""" - if cl is None: - return None - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cargs is None or len(cargs) < 1: - return None - - ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(0), None, 0, trans) - if ptr_val is None: - return None - - # 按 pointee 类型读取;非指针参数默认按 i8(保持向后兼容) - if HandlesExpr.is_ptr_type(ptr_val.Ty) != 0: - pointee: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee - if pointee is not None: - # i8*(void*)时按赋值目标类型推断读取宽度(对齐 TPC - # HandlesSpecialCall._infer_deref_target_type): - # v: int = c.Deref(p) → bitcast i32* 后 load 4 字节。 - # 背景:DictTest d3[key5]=500 读出 -12——固定按 i8 读 1 字节 + - # sext 截断(0xF4 → 0xFFFFFFF4);Test 1 的小值(10)恰好正确 - # 掩盖了缺陷。 - match pointee: - case llvmlite.LLVMType.Int(pointee_width): - # 允许推断:c.Deref 是赋值语句直接 RHS(v: int = c.Deref(p)) - # 或处于类型转换链包裹中(如 vt: t.CVoid | t.CPtr = - # t.CVoid(c.Deref(p)))。嵌套在 while 条件/比较/binop/ - # 其他调用中(如 while c.Deref(p) != 0、total += - # t.CInt(c.Deref(p)))不推断,否则 i8* 会被残留 - # CurAssignAnnot 误判为 i32* 读 4 字节 → StringIterTest - # ASCII sum/manual strcmp 失败。 - allow_infer: int = 0 - if trans is not None and trans.CurAssignNode is not None: - if t.CUInt64T(cl) == t.CUInt64T(trans.CurAssignNode): - allow_infer = 1 - elif _IsCastWrappingDeref(trans.CurAssignNode, cl) != 0: - allow_infer = 1 - if pointee_width == 8 and allow_infer != 0 \ - and trans is not None and trans.CurAssignAnnot is not None: - dref_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - trans.Pool, trans.CurAssignAnnot, - trans._imported_modules, trans._from_imports, trans) - if dref_ty is not None: - dref_bits: int = HandlesExpr.get_llvm_type_bits(dref_ty) - dref_fbits: int = HandlesExpr.get_llvm_float_bits(dref_ty) - dref_is_ptr: int = HandlesExpr.is_ptr_type(dref_ty) - # 整数/浮点/指针目标均推断(指针 → bitcast 后 - # load 8 字节;struct 值目标不推断,保持 i8 读) - dref_ptr: llvmlite.Value | t.CPtr = None - if (dref_bits != 0 or dref_fbits != 0 or dref_is_ptr != 0) \ - and dref_bits != 8: - dref_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, dref_ty) - dref_ptr = llvmlite.build_bitcast( - builder, ptr_val, dref_ptr_ty) - if dref_ptr is not None: - return llvmlite.build_load(builder, dref_ty, dref_ptr) - case _: - pass - return llvmlite.build_load(builder, pointee, ptr_val) - # 非指针参数即类型推断退化:fail-fast,绝不按 i8 兜底读取(会读到垃圾宽度) - HandlesType.fatal_error(cl, "c.Deref 参数不是指针类型(类型推断退化)", "TypeError") - return None - - - def translate_c_derefas(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """c.DerefAs(ptr, val) → store val to ptr(bitcast 后 store)""" - if cl is None: - return None - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cargs is None or len(cargs) < 2: - return None - - ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(0), None, 0, trans) - val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(1), None, 0, trans) - if ptr_val is None or val is None: - return None - - # 两端均为指向同一结构体类型的指针时执行结构体拷贝(*ptr = *val), - # 而非存储指针值。这对 REnum 变体构造(c.DerefAs(ptr, LLVMType.Int(32)))至关重要: - # LLVMType.Int(32) 构造返回 alloca 指针(Ptr(LLVMType)),若直接 store 指针值, - # 只写入 8 字节指针(tag 字段仍是 0x0),导致运行时读 tag 错乱。 - # 对应 TPC HandlesExprCall.py:3696-3701 的 struct 拷贝逻辑。 - if HandlesExpr.is_ptr_type(ptr_val.Ty) != 0 and HandlesExpr.is_ptr_type(val.Ty) != 0: - ptr_pointee: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee - val_pointee: llvmlite.LLVMType | t.CPtr = val.Ty.Pointee - if ptr_pointee is not None and val_pointee is not None: - # ptr_pointee 是已注册结构体类型(用 find_struct_by_type 判断) - if HandlesStruct.find_struct_by_type(ptr_pointee) is not None: - if ptr_pointee is val_pointee: - # 同一结构体类型:load 值再 store(结构体拷贝) - loaded: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, val_pointee, val) - if loaded is not None: - # bitcast ptr 到结构体指针再 store - struct_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, ptr_pointee) - casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, ptr_val, struct_ptr_ty) - if casted_ptr is not None: - llvmlite.build_store(builder, loaded, casted_ptr) - return val - - # bitcast ptr 到 val.Ty* 再 store - val_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, val.Ty) - casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ptr_val, val_ptr_ty) - if casted_ptr is None: - return None - llvmlite.build_store(builder, val, casted_ptr) - return val - - - def translate_c_set(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """c.Set(a, b) → a = b(赋值语义,a 为左值)""" - if cl is None: - return None - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cargs is None or len(cargs) < 2: - return None - a_node: ast.AST | t.CPtr = cargs.get(0) - b_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(1), None, 0, trans) - if b_val is None: - return None - - # 形态 1: c.Set(c.Deref(ptr), b) → *ptr = b - if a_node is not None and a_node.kind() == ast.ASTKind.Call: - d_call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(a_node) - if d_call.func is not None and d_call.func.kind() == ast.ASTKind.Attribute: - d_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(d_call.func) - if d_at.attr is not None and string.strcmp(d_at.attr, "Deref") == 0: - d_args: list[ast.AST | t.CPtr] | t.CPtr = d_call.args - if d_args is not None and len(d_args) >= 1: - ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, d_args.get(0), None, 0, trans) - if ptr_val is not None: - val_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, b_val.Ty) - casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, ptr_val, val_ptr_ty) - if casted_ptr is not None: - llvmlite.build_store(builder, b_val, casted_ptr) - return b_val - # 其他 Call 形态不可作左值 - return b_val - - # 形态 2: Name 变量赋值 - if a_node is not None and a_node.kind() == ast.ASTKind.Name and trans is not None: - nm_set: ast.Name | t.CPtr = (ast.Name | t.CPtr)(a_node) - if nm_set.id is not None: - if HT.is_global_name(trans, nm_set.id) != 0: - mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( - trans.SymTab, nm_set.id) - if mod_alloca is not None: - tg_ty: llvmlite.LLVMType | t.CPtr = None - if mod_alloca.Ty is not None: - tg_ty = mod_alloca.Ty.Pointee - sv: llvmlite.Value | t.CPtr = b_val - if tg_ty is not None: - sv = HandlesExpr.coerce_to_type(builder, b_val, tg_ty, a_node) - llvmlite.build_store(builder, sv, mod_alloca) - return b_val - if HT.is_nonlocal_name(trans, nm_set.id) != 0: - nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr( - trans, nm_set.id) - if nl_ptr is not None: - nl_ty: llvmlite.LLVMType | t.CPtr = None - if nl_ptr.Ty is not None: - nl_ty = nl_ptr.Ty.Pointee - sv2: llvmlite.Value | t.CPtr = b_val - if nl_ty is not None: - sv2 = HandlesExpr.coerce_to_type(builder, b_val, nl_ty, a_node) - llvmlite.build_store(builder, sv2, nl_ptr) - return b_val - alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym( - trans.SymTab, pool, builder, nm_set.id, b_val.Ty) - if alloca is not None: - ac_ty: llvmlite.LLVMType | t.CPtr = None - if alloca.Ty is not None: - ac_ty = alloca.Ty.Pointee - sv3: llvmlite.Value | t.CPtr = b_val - if ac_ty is not None: - sv3 = HandlesExpr.coerce_to_type(builder, b_val, ac_ty, a_node) - llvmlite.build_store(builder, sv3, alloca) - return b_val - return b_val - - # 形态 3: Attribute 字段赋值 - if a_node is not None and a_node.kind() == ast.ASTKind.Attribute: - field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( - builder, pool, mod, a_node, trans) - if field_ptr is not None: - fd_ty: llvmlite.LLVMType | t.CPtr = None - if field_ptr.Ty is not None: - fd_ty = field_ptr.Ty.Pointee - sv4: llvmlite.Value | t.CPtr = b_val - if fd_ty is not None: - sv4 = HandlesExpr.coerce_to_type(builder, b_val, fd_ty, a_node) - llvmlite.build_store(builder, sv4, field_ptr) - return b_val - - return b_val - - - def translate_c_addr(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """c.Addr(var) → 返回变量的 alloca 指针(不 load)""" - if cl is None: - return None - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cargs is None or len(cargs) < 1: - return None - - arg0: ast.AST | t.CPtr = cargs.get(0) - if arg0 is None: - return None - - # Name 形式: c.Addr(var) → 返回变量的 alloca 指针(不 load) - if arg0.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0) - if nm.id is None: - return None - if trans is not None: - # self/cls 对象引用:c.Addr(self) 返回对象指针本身(Ptr(Struct)), - # 而非指针变量的地址(Ptr(Ptr(Struct)))。方法与 Attribute 分支 - # (c.Addr(self.field) 先 load self)语义一致,供 - # return t.CVoid(c.Addr(self), CPtr) 返回 this 使用。 - if string.strcmp(nm.id, "self") == 0 or string.strcmp(nm.id, "cls") == 0: - self_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm.id) - if self_entry is not None and self_entry.Alloca is not None and self_entry.Alloca.Ty is not None: - match self_entry.Alloca.Ty: - case llvmlite.LLVMType.Ptr(inner1): - match inner1: - case llvmlite.LLVMType.Ptr(inner2): - obj_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, inner2) - return llvmlite.build_load(builder, obj_ty, self_entry.Alloca) - case _: - pass - case _: - pass - return_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if return_var is not None and return_var.Ty is not None: - # 对象指针变量(如 lit_tree = zhuff.zhuff_tree(),alloca 是 - # Ptr(Ptr(Struct)),存对象指针):c.Addr(对象变量) 应返回对象 - # 指针本身(load 一次),对齐 self/cls 分支与 c.Addr(self.field) - # (GEP 后对象地址)。此前直接返回 &变量(Ptr(Ptr(Struct)))→ - # 调用端 bitcast 成 Ptr(Struct) 后 ht 指向指针变量存储 → 字段 - # 读到指针值/垃圾 → build_decode_tree 越界崩溃 - # (zinflate inflate_block_fixed 的 c.Addr(lit_tree) 根因)。 - match return_var.Ty: - case llvmlite.LLVMType.Ptr(addr_inner1): - match addr_inner1: - case llvmlite.LLVMType.Ptr(addr_inner2): - match addr_inner2: - case llvmlite.LLVMType.Struct(_, _, _): - addr_obj_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, addr_inner2) - return llvmlite.build_load(builder, addr_obj_ty, return_var) - case _: - pass - case _: - pass - case _: - pass - return return_var - - # Attribute 形式: c.Addr(self.field) → 取字段地址(GEP 到字段,不 load) - # 用于 atom.__atomic_test_and_set(c.Addr(self.lock_val), ...) 等锁操作 - if arg0.kind() == ast.ASTKind.Attribute: - if trans is None: - return None - at_addr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg0) - if at_addr is None or at_addr.attr is None or at_addr.value is None: - return None - # 解析 self(Name)→ 查找 alloca - if at_addr.value.kind() != ast.ASTKind.Name: - return None - self_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_addr.value) - if self_nm.id is None: - return None - self_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, self_nm.id) - if self_alloca is None or self_alloca.Ty is None: - return None - # 从 self 类型提取结构体类型(Ptr(Struct) 或 Ptr(Ptr(Struct))) - struct_ty: llvmlite.LLVMType | t.CPtr = None - self_is_ptr_ptr: int = 0 - match self_alloca.Ty: - case llvmlite.LLVMType.Ptr(inner1): - match inner1: - case llvmlite.LLVMType.Ptr(inner2): - struct_ty = inner2 - self_is_ptr_ptr = 1 - case _: - struct_ty = inner1 - case _: - return None - # 查找字段 - fe_addr: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( - struct_ty, at_addr.attr) - if fe_addr is None: - return None - # self_alloca 是 Ptr(Ptr(Struct)) 时先 load 成 Ptr(Struct) 对象指针 - obj_ptr: llvmlite.Value | t.CPtr = self_alloca - if self_is_ptr_ptr == 1: - self_obj_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) - obj_ptr = llvmlite.build_load(builder, self_obj_ty, self_alloca) - if obj_ptr is None: - return None - # GEP 到字段地址 - return llvmlite.build_gep_struct( - builder, struct_ty, fe_addr.Ty, obj_ptr, fe_addr.Index) - - # Subscript 形式: c.Addr(arr[i]) → 数组元素地址(GEP 数组,不 load) - # 用于 self.root_directory = c.Addr(directories[directory_count]) 等。 - # 此前只支持 Name/Attribute,Subscript 落到函数末尾返回 None → - # 赋值右侧为 None(devfs.vp:159 根因)。 - if arg0.kind() == ast.ASTKind.Subscript: - if trans is None: - return None - sub_addr: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(arg0) - if sub_addr is None or sub_addr.value is None or sub_addr.slice is None: - return None - arr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, sub_addr.value, None, 0, trans) - if arr_val is None or arr_val.Ty is None: - return None - idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, sub_addr.slice, None, 0, trans) - if idx_val is None: - return None - # 数组基址 pointee 是 Array(elem_ty, N) → GEP 得元素指针 - arr_pointee_ca: llvmlite.LLVMType | t.CPtr = None - if HandlesExpr.is_ptr_type(arr_val.Ty) != 0: - arr_pointee_ca = arr_val.Ty.Pointee - if arr_pointee_ca is not None: - match arr_pointee_ca: - case llvmlite.LLVMType.Array(arr_et_ca, _): - return llvmlite.build_gep_array( - builder, arr_pointee_ca, arr_et_ca, arr_val, idx_val) - case _: - pass - return None - - # 其他 arg0 形式(非 Name/Attribute/Subscript):真实掉出函数末尾, - # 补显式 return None(fail-fast 不允许流程掉出末尾) - return None - - - def translate_c_load(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """c.Load(a, b) → *a = *b(加载 b 的值,存储到 a)""" - if cl is None: - return None - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cargs is None or len(cargs) < 2: - return None - - dst_ptr: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(0), None, 0, trans) - src_ptr: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(1), None, 0, trans) - if dst_ptr is None or src_ptr is None: - return None - - # 确定 pointee 类型(优先用 src 的 pointee,回退到 dst 的 pointee) - pointee: llvmlite.LLVMType | t.CPtr = None - if src_ptr.Ty is not None: - pointee = src_ptr.Ty.Pointee - if pointee is None and dst_ptr.Ty is not None: - pointee = dst_ptr.Ty.Pointee - if pointee is None: - return None - - # bitcast src 到 pointee* 并 load - target_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, pointee) - src_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, src_ptr, target_ptr_ty) - if src_cast is None: - return None - loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, pointee, src_cast) - if loaded is None: - return None - - # bitcast dst 到 pointee* 并 store - dst_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, dst_ptr, target_ptr_ty) - if dst_cast is None: - return None - llvmlite.build_store(builder, loaded, dst_cast) - return loaded - - - def _asm_append_cstr(self, dst: str, dst_size: t.CSizeT, - src: str): - """将 C 字符串 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 - i: t.CSizeT = 0 - while i < slen and i + 1 < remain: - dst[dlen + i] = src[i] - i += 1 - dst[dlen + i] = '\0' - - - def _asm_escape_for_ir(self, pool: memhub.MemBuddy | t.CPtr, - src: str) -> str: - """转义汇编文本用于 LLVM IR 字符串字面量""" - if src is None: - return None - slen: t.CSizeT = string.strlen(src) - buf: str = pool.alloc(slen * 4 + 8) - if buf is None: - return None - pos: t.CSizeT = 0 - for ch in src: - if ch == '\n': - buf[pos] = '\\' - pos += 1 - buf[pos] = '0' - pos += 1 - buf[pos] = 'A' - pos += 1 - elif ch == '"': - buf[pos] = '\\' - pos += 1 - buf[pos] = '2' - pos += 1 - buf[pos] = '2' - pos += 1 - elif ch == '\\': - buf[pos] = '\\' - pos += 1 - buf[pos] = '5' - pos += 1 - buf[pos] = 'C' - pos += 1 - else: - buf[pos] = ch - pos += 1 - buf[pos] = '\0' - return buf - - - def _resolve_register(self, attr_name: str) -> str: - """将 t.ASM_DESCR.XXX 的属性名映射到约束字符串值""" - if attr_name is None: - return "" - - # Clobber 破坏描述符 - if string.strcmp(attr_name, "CLOBBER_MEMORY") == 0: return "memory" - if string.strcmp(attr_name, "CLOBBER_CC") == 0: return "cc" - if string.strcmp(attr_name, "CLOBBER_RAX") == 0: return "rax" - if string.strcmp(attr_name, "CLOBBER_RBX") == 0: return "rbx" - if string.strcmp(attr_name, "CLOBBER_RCX") == 0: return "rcx" - if string.strcmp(attr_name, "CLOBBER_RDX") == 0: return "rdx" - if string.strcmp(attr_name, "CLOBBER_RSI") == 0: return "rsi" - if string.strcmp(attr_name, "CLOBBER_RDI") == 0: return "rdi" - if string.strcmp(attr_name, "CLOBBER_RBP") == 0: return "rbp" - if string.strcmp(attr_name, "CLOBBER_RSP") == 0: return "rsp" - if string.strcmp(attr_name, "CLOBBER_R8") == 0: return "r8" - if string.strcmp(attr_name, "CLOBBER_R9") == 0: return "r9" - if string.strcmp(attr_name, "CLOBBER_R10") == 0: return "r10" - if string.strcmp(attr_name, "CLOBBER_R11") == 0: return "r11" - if string.strcmp(attr_name, "CLOBBER_R12") == 0: return "r12" - if string.strcmp(attr_name, "CLOBBER_R13") == 0: return "r13" - if string.strcmp(attr_name, "CLOBBER_R14") == 0: return "r14" - if string.strcmp(attr_name, "CLOBBER_R15") == 0: return "r15" - if string.strcmp(attr_name, "CLOBBER_EAX") == 0: return "eax" - if string.strcmp(attr_name, "CLOBBER_EBX") == 0: return "ebx" - if string.strcmp(attr_name, "CLOBBER_ECX") == 0: return "ecx" - if string.strcmp(attr_name, "CLOBBER_EDX") == 0: return "edx" - if string.strcmp(attr_name, "CLOBBER_ESI") == 0: return "esi" - if string.strcmp(attr_name, "CLOBBER_EDI") == 0: return "edi" - if string.strcmp(attr_name, "CLOBBER_DX") == 0: return "dx" - if string.strcmp(attr_name, "CLOBBER_AX") == 0: return "ax" - if string.strcmp(attr_name, "CLOBBER_CX") == 0: return "cx" - if string.strcmp(attr_name, "CLOBBER_SI") == 0: return "si" - if string.strcmp(attr_name, "CLOBBER_DI") == 0: return "di" - - # Output 输出约束 - if string.strcmp(attr_name, "OUTPUT_REG") == 0: return "=r" - if string.strcmp(attr_name, "OUTPUT_MEM") == 0: return "=m" - if string.strcmp(attr_name, "OUTPUT_EAX") == 0: return "=a" - if string.strcmp(attr_name, "OUTPUT_EBX") == 0: return "=b" - if string.strcmp(attr_name, "OUTPUT_ECX") == 0: return "=c" - if string.strcmp(attr_name, "OUTPUT_EDX") == 0: return "=d" - if string.strcmp(attr_name, "OUTPUT_ESI") == 0: return "=S" - if string.strcmp(attr_name, "OUTPUT_EDI") == 0: return "=D" - if string.strcmp(attr_name, "OUTPUT_RAX") == 0: return "=a" - if string.strcmp(attr_name, "OUTPUT_RBX") == 0: return "=b" - if string.strcmp(attr_name, "OUTPUT_RCX") == 0: return "=c" - if string.strcmp(attr_name, "OUTPUT_RDX") == 0: return "=d" - if string.strcmp(attr_name, "OUTPUT_RSI") == 0: return "=S" - if string.strcmp(attr_name, "OUTPUT_RDI") == 0: return "=D" - - # Input/Register 输入约束 - if string.strcmp(attr_name, "REG_ANY") == 0: return "r" - if string.strcmp(attr_name, "REG_EAX") == 0: return "a" - if string.strcmp(attr_name, "REG_EBX") == 0: return "b" - if string.strcmp(attr_name, "REG_ECX") == 0: return "c" - if string.strcmp(attr_name, "REG_EDX") == 0: return "d" - if string.strcmp(attr_name, "REG_ESI") == 0: return "S" - if string.strcmp(attr_name, "REG_EDI") == 0: return "D" - if string.strcmp(attr_name, "REG_RAX") == 0: return "a" - if string.strcmp(attr_name, "REG_RBX") == 0: return "b" - if string.strcmp(attr_name, "REG_RCX") == 0: return "c" - if string.strcmp(attr_name, "REG_RDX") == 0: return "d" - if string.strcmp(attr_name, "REG_RSI") == 0: return "S" - if string.strcmp(attr_name, "REG_RDI") == 0: return "D" - - if string.strcmp(attr_name, "INPUT_REG") == 0: return "r" - if string.strcmp(attr_name, "INPUT_MEM") == 0: return "m" - if string.strcmp(attr_name, "INPUT_EAX") == 0: return "a" - if string.strcmp(attr_name, "INPUT_EBX") == 0: return "b" - if string.strcmp(attr_name, "INPUT_ECX") == 0: return "c" - if string.strcmp(attr_name, "INPUT_EDX") == 0: return "d" - if string.strcmp(attr_name, "INPUT_ESI") == 0: return "S" - if string.strcmp(attr_name, "INPUT_EDI") == 0: return "D" - if string.strcmp(attr_name, "INPUT_RAX") == 0: return "a" - if string.strcmp(attr_name, "INPUT_RBX") == 0: return "b" - if string.strcmp(attr_name, "INPUT_RCX") == 0: return "c" - if string.strcmp(attr_name, "INPUT_RDX") == 0: return "d" - if string.strcmp(attr_name, "INPUT_RSI") == 0: return "S" - if string.strcmp(attr_name, "INPUT_RDI") == 0: return "D" - - return "" - - - def _resolve_asm_descr(self, pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr) -> str: - """递归解析约束表达式,返回约束字符串""" - if node is None: - return "" - - k: int = node.kind() - - # BinOp with BitOr: 拼接左右 - 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._resolve_asm_descr(pool, bop.left) - right_str: str = self._resolve_asm_descr(pool, bop.right) - llen: t.CSizeT = string.strlen(left_str) - rlen: t.CSizeT = string.strlen(right_str) - buf: str = pool.alloc(llen + rlen + 1) - if buf is None: - return "" - string.strcpy(buf, left_str) - for i in range(rlen): - buf[llen + i] = right_str[i] - buf[llen + rlen] = '\0' - return buf - return "" - - # Attribute: t.ASM_DESCR.XXX 或 t.XXX - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - # t.ASM_DESCR.XXX - if at.value is not None and at.value.kind() == ast.ASTKind.Attribute: - inner: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(at.value) - if inner.value is not None and inner.value.kind() == ast.ASTKind.Name: - mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner.value) - if mod_nm.id is not None and string.strcmp(mod_nm.id, "t") == 0: - if inner.attr is not None and string.strcmp(inner.attr, "ASM_DESCR") == 0: - return self._resolve_register(at.attr) - # t.XXX 简化形式 - if at.value is not None and at.value.kind() == ast.ASTKind.Name: - mod_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if mod_nm2.id is not None and string.strcmp(mod_nm2.id, "t") == 0: - return self._resolve_register(at.attr) - return "" - - # Constant: 字符串常量 - if k == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) - if cn.const_kind == ast.CONST_STR: - return cn.str_val - return "" - - return "" - - - def _asm_get_operand(self, base: HandlesExprCall.AsmOperand | t.CPtr, - idx: int) -> HandlesExprCall.AsmOperand | t.CPtr: - """获取操作数数组中第 idx 个元素的指针""" - entry_size: t.CSizeT = HandlesExprCall.AsmOperand.__sizeof__() - entry_addr: t.CUInt64T = t.CUInt64T(base) + idx * entry_size - return (HandlesExprCall.AsmOperand | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - - - def _asm_is_c_call(self, node: ast.Call | t.CPtr) -> str: - """检查 Call 节点是否是 c.XXX 调用,返回属性名或 None""" - if node is None or node.func is None: - return None - if node.func.kind() != ast.ASTKind.Attribute: - return None - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node.func) - if at.value is None or at.value.kind() != ast.ASTKind.Name: - return None - mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if mod_nm.id is None or string.strcmp(mod_nm.id, "c") != 0: - return None - return at.attr - - - def _asm_add_operand(self, operands: HandlesExprCall.AsmOperand | t.CPtr, - count: int, - val: llvmlite.Value | t.CPtr, - constraint: str, - is_output: int) -> int: - """添加操作数到数组,返回新计数(失败返回原计数) - - 去重:f-string 模板内嵌的 AsmOut/AsmInp 与 out=/inp= 声明指向 - 同一变量时会重复收集(如 vrandom.vp 的 c.Asm(f"...{AsmOut(v)}", - out=[AsmOut(v)])),同一 (Value, IsOutput) 只保留第一个, - 避免约束数多于 asm 返回元素数(llc: output constraints mismatch)。 - """ - if count >= ASM_MAX_OPERANDS: - return count - if val is not None: - for ei in range(count): - eop: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, ei) - if eop is not None and eop.Value == val and eop.IsOutput == is_output: - return count - op: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, count) - op.Value = val - op.Constraint = constraint - op.IsOutput = is_output - return count + 1 - - - def translate_c_asm(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译 c.Asm 内联汇编,返回结果 Value(无输出时返回 None)""" - if cl is None: - return None - - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cargs is None or len(cargs) < 1: - return None - - # 分配操作数数组 - operand_size: t.CSizeT = HandlesExprCall.AsmOperand.__sizeof__() - operands: HandlesExprCall.AsmOperand | t.CPtr = pool.alloc(operand_size * ASM_MAX_OPERANDS) - if operands is None: - return None - string.memset(operands, 0, operand_size * ASM_MAX_OPERANDS) - - # 分配 clobber 名数组 - clobbers: str | t.CPtr = pool.alloc(8 * ASM_MAX_OPERANDS) - if clobbers is None: - return None - string.memset(clobbers, 0, 8 * ASM_MAX_OPERANDS) - - # 分配 asm 文本缓冲区 - asm_text: str = pool.alloc(ASM_TEXT_BUF_SIZE) - if asm_text is None: - return None - asm_text[0] = '\0' - - operand_count: int = 0 - clobber_count: int = 0 - fv_count: int = 0 - - # 分配 fv 索引数组(记录每个 FormattedValue 对应的操作数原始索引) - fv_orig_indices: int | t.CPtr = pool.alloc(4 * ASM_MAX_OPERANDS) - if fv_orig_indices is None: - return None - string.memset(fv_orig_indices, 0, 4 * ASM_MAX_OPERANDS) - - # ============================================================ - # 1. 解析汇编模板(JoinedStr 或 Constant)— 第一遍:收集操作数 - # 不生成 asm 文本(占位符 $N 需在重排后才能确定编号) - # ============================================================ - tmpl_node: ast.AST | t.CPtr = cargs.get(0) - if tmpl_node is not None: - tk: int = tmpl_node.kind() - - if tk == ast.ASTKind.JoinedStr: - js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(tmpl_node) - jvalues: list[ast.AST | t.CPtr] | t.CPtr = js.values - if jvalues is not None: - jvlen: t.CSizeT = len(jvalues) - for vi in range(jvlen): - part: ast.AST | t.CPtr = jvalues.get(vi) - if part is None: - continue - pk: int = part.kind() - - if pk == ast.ASTKind.FormattedValue: - fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part) - fexpr: ast.AST | t.CPtr = fv.value - if fexpr is None or fexpr.kind() != ast.ASTKind.Call: - continue - fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr) - attr_nm: str = self._asm_is_c_call(fcall) - if attr_nm is None: - continue - - is_out: int = 0 - if string.strcmp(attr_nm, "AsmOut") == 0: - is_out = 1 - elif string.strcmp(attr_nm, "AsmInp") == 0: - is_out = 0 - else: - continue - - fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args - if fargs is None or len(fargs) < 1: - continue - - val_node: ast.AST | t.CPtr = fargs.get(0) - cons_str: str = "" - if len(fargs) >= 2: - cons_str = self._resolve_asm_descr(pool, fargs.get(1)) - - if is_out != 0: - # 输出:获取变量 alloca - if val_node is None or val_node.kind() != ast.ASTKind.Name: - continue - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node) - if nm.id is None: - continue - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is None: - continue - operand_count = self._asm_add_operand( - operands, operand_count, alloca, cons_str, 1) - else: - # 输入:翻译值 - ival: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, val_node, None, 0, trans) - if ival is None: - continue - operand_count = self._asm_add_operand( - operands, operand_count, ival, cons_str, 0) - - # 记录 fv 的原始操作数索引 - if fv_count < ASM_MAX_OPERANDS: - fv_orig_indices[fv_count] = operand_count - 1 - fv_count += 1 - - # ============================================================ - # 2. 解析关键字参数 out=/inp=/op=/clobber= - # ============================================================ - keywords: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords - if keywords is not None: - kwlen: t.CSizeT = len(keywords) - for ki in range(kwlen): - kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki)) - if kw is None or kw.arg is None or kw.value is None: - continue - kwk: int = kw.value.kind() - - if string.strcmp(kw.arg, "out") == 0: - # 输出操作数列表 - if kwk != ast.ASTKind.List: - continue - out_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value) - out_elts: list[ast.AST | t.CPtr] | t.CPtr = out_lst.elts - if out_elts is None: - continue - oelen: t.CSizeT = len(out_elts) - for oi in range(oelen): - oelt: ast.AST | t.CPtr = out_elts.get(oi) - if oelt is None or oelt.kind() != ast.ASTKind.Call: - continue - ocall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(oelt) - oattr: str = self._asm_is_c_call(ocall) - if oattr is None or string.strcmp(oattr, "AsmOut") != 0: - continue - oargs: list[ast.AST | t.CPtr] | t.CPtr = ocall.args - if oargs is None or len(oargs) < 1: - continue - oval_node: ast.AST | t.CPtr = oargs.get(0) - ocons: str = "" - if len(oargs) >= 2: - ocons = self._resolve_asm_descr(pool, oargs.get(1)) - if oval_node is None or oval_node.kind() != ast.ASTKind.Name: - continue - onm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(oval_node) - if onm.id is None: - continue - oalloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, onm.id) - if oalloca is None: - continue - operand_count = self._asm_add_operand( - operands, operand_count, oalloca, ocons, 1) - - elif string.strcmp(kw.arg, "inp") == 0 or string.strcmp(kw.arg, "inputs") == 0: - # 输入操作数列表 - if kwk != ast.ASTKind.List: - continue - in_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value) - in_elts: list[ast.AST | t.CPtr] | t.CPtr = in_lst.elts - if in_elts is None: - continue - ielen: t.CSizeT = len(in_elts) - for ii in range(ielen): - ielt: ast.AST | t.CPtr = in_elts.get(ii) - if ielt is None or ielt.kind() != ast.ASTKind.Call: - continue - icall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(ielt) - iattr: str = self._asm_is_c_call(icall) - if iattr is None or string.strcmp(iattr, "AsmInp") != 0: - continue - iargs: list[ast.AST | t.CPtr] | t.CPtr = icall.args - if iargs is None or len(iargs) < 1: - continue - ival_node: ast.AST | t.CPtr = iargs.get(0) - icons: str = "" - if len(iargs) >= 2: - icons = self._resolve_asm_descr(pool, iargs.get(1)) - ival2: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, ival_node, None, 0, trans) - if ival2 is None: - continue - operand_count = self._asm_add_operand( - operands, operand_count, ival2, icons, 0) - - elif string.strcmp(kw.arg, "op") == 0 or string.strcmp(kw.arg, "clobber") == 0: - # 破坏列表 - if kwk != ast.ASTKind.List: - continue - cl_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value) - cl_elts: list[ast.AST | t.CPtr] | t.CPtr = cl_lst.elts - if cl_elts is None: - continue - clen: t.CSizeT = len(cl_elts) - for ci in range(clen): - celt: ast.AST | t.CPtr = cl_elts.get(ci) - if celt is None: - continue - cstr: str = self._resolve_asm_descr(pool, celt) - if cstr is None or cstr[0] == '\0': - continue - if clobber_count < ASM_MAX_OPERANDS: - cl_addr: t.CUInt64T = t.CUInt64T(clobbers) + clobber_count * 8 - cl_ptr: str | t.CPtr = (str | t.CPtr)(t.CVoid(cl_addr, t.CPtr)) - cl_ptr[0] = cstr - clobber_count += 1 - - # ============================================================ - # 3. 解析第二个位置参数作为破坏列表 - # ============================================================ - if len(cargs) >= 2: - pos_node: ast.AST | t.CPtr = cargs.get(1) - if pos_node is not None and pos_node.kind() == ast.ASTKind.List: - pos_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(pos_node) - pos_elts: list[ast.AST | t.CPtr] | t.CPtr = pos_lst.elts - if pos_elts is not None: - plen: t.CSizeT = len(pos_elts) - for pi in range(plen): - pelt: ast.AST | t.CPtr = pos_elts.get(pi) - if pelt is None: - continue - pstr: str = self._resolve_asm_descr(pool, pelt) - if pstr is None or pstr[0] == '\0': - continue - if clobber_count < ASM_MAX_OPERANDS: - pcl_addr: t.CUInt64T = t.CUInt64T(clobbers) + clobber_count * 8 - pcl_ptr: str | t.CPtr = (str | t.CPtr)(t.CVoid(pcl_addr, t.CPtr)) - pcl_ptr[0] = pstr - clobber_count += 1 - - # ============================================================ - # 4. 统计输出/输入数量,确定返回类型 - # ============================================================ - output_count: int = 0 - input_count: int = 0 - first_output_idx: int = -1 - for oi2 in range(operand_count): - op2: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi2) - if op2.IsOutput != 0: - if first_output_idx < 0: - first_output_idx = oi2 - output_count += 1 - else: - input_count += 1 - - # 确定返回类型 - # 多输出(如 vrandom rdrand*_step 的 val+ok 两个 AsmOut)返回 - # 匿名 struct {ty1, ty2, ...},元素数 = 输出操作数(LLVM asm - # 要求输出约束数 = 返回 struct 元素数)。 - ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) - if output_count > 0 and first_output_idx >= 0: - if output_count > 1: - out_pn_head: llvmlite.ParamNode | t.CPtr = None - out_pn_last: llvmlite.ParamNode | t.CPtr = None - out_pn_n: int = 0 - for oi5 in range(operand_count): - op5: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi5) - if op5 is None or op5.IsOutput == 0: - continue - if op5.Value is not None and op5.Value.Ty is not None \ - and op5.Value.Ty.Pointee is not None: - pn5: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node( - pool, op5.Value.Ty.Pointee) - if pn5 is not None: - if out_pn_head is None: - out_pn_head = pn5 - else: - out_pn_last.Next = pn5 - out_pn_last = pn5 - out_pn_n += 1 - if out_pn_head is not None and out_pn_n > 0: - ret_ty = llvmlite.Struct(pool, out_pn_head, out_pn_n, None) - else: - HandlesType.fatal_error( - cl, "c.Asm 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError") - ret_ty = llvmlite.Int32(pool) - else: - out_op: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, first_output_idx) - if out_op.Value is not None and out_op.Value.Ty is not None: - # alloca 的类型是指针,Pointee 是目标类型 - if out_op.Value.Ty.Pointee is not None: - ret_ty = out_op.Value.Ty.Pointee - else: - HandlesType.fatal_error( - cl, "c.Asm 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError") - ret_ty = llvmlite.Int32(pool) - - # 判断 void — 直接基于 output_count 判断,避免 match 类型匹配问题 - is_void: int = 1 - if output_count > 0: - is_void = 0 - - # ============================================================ - # 4.5 重排操作数:输出在前,输入在后(LLVM IR 要求) - # - # new_order[new_idx] = orig_idx — 新位置对应原索引 - # orig_to_new[orig_idx] = new_idx — 原索引映射到新位置(用于占位符编号) - # ============================================================ - new_order: int | t.CPtr = pool.alloc(4 * (operand_count + 1)) - orig_to_new: int | t.CPtr = pool.alloc(4 * (operand_count + 1)) - if new_order is None or orig_to_new is None: - return None - - new_idx: int = 0 - # 先放输出 - for oi3 in range(operand_count): - op3: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi3) - if op3.IsOutput != 0: - new_order[new_idx] = oi3 - new_idx += 1 - # 再放输入 - for oi4 in range(operand_count): - op4: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi4) - if op4.IsOutput == 0: - new_order[new_idx] = oi4 - new_idx += 1 - # 建立映射 orig -> new - for ni2 in range(operand_count): - orig_to_new[new_order[ni2]] = ni2 - - # ============================================================ - # 4.6 生成汇编文本(第二遍遍历 f-string,用重排后的索引生成占位符) - # 项目约定使用 Intel 语法,通过 IR 的 inteldialect 关键字启用 - # ============================================================ - if tmpl_node is not None: - tk2: int = tmpl_node.kind() - if tk2 == ast.ASTKind.JoinedStr: - js2: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(tmpl_node) - jvalues2: list[ast.AST | t.CPtr] | t.CPtr = js2.values - if jvalues2 is not None: - jvlen2: t.CSizeT = len(jvalues2) - fv_fi: int = 0 - for vi2 in range(jvlen2): - part2: ast.AST | t.CPtr = jvalues2.get(vi2) - if part2 is None: - continue - pk2: int = part2.kind() - if pk2 == ast.ASTKind.Constant: - cn3: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part2) - if cn3.const_kind == ast.CONST_STR and cn3.str_val is not None: - self._asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, cn3.str_val) - elif pk2 == ast.ASTKind.FormattedValue: - if fv_fi < fv_count: - orig_idx2: int = fv_orig_indices[fv_fi] - new_idx2: int = orig_to_new[orig_idx2] - ph_buf2: str = pool.alloc(16) - if ph_buf2 is not None: - viperlib.snprintf(ph_buf2, 16, "$%d", new_idx2) - self._asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, ph_buf2) - fv_fi += 1 - elif tk2 == ast.ASTKind.Constant: - cn4: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(tmpl_node) - if cn4.const_kind == ast.CONST_STR and cn4.str_val is not None: - self._asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, cn4.str_val) - - # ============================================================ - # 5. 构建约束字符串(按重排后的顺序:输出在前,输入在后) - # ============================================================ - const_buf: str = pool.alloc(ASM_CONST_BUF_SIZE) - if const_buf is None: - return None - const_buf[0] = '\0' - - first_const: int = 1 - for ci2 in range(operand_count): - orig_i: int = new_order[ci2] - cop: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, orig_i) - cons_val: str = cop.Constraint - if cons_val is None: - cons_val = "r" - - if first_const == 0: - self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",") - first_const = 0 - - if cop.IsOutput != 0: - # 输出约束:确保以 = 开头 - if cons_val[0] != '=': - self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "=") - self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cons_val) - else: - self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cons_val) - - # 追加 clobber 约束 ~{name} - for cidx in range(clobber_count): - cl_addr2: t.CUInt64T = t.CUInt64T(clobbers) + cidx * 8 - cname: str = (str | t.CPtr)(t.CVoid(cl_addr2, t.CPtr))[0] - if cname is None or cname[0] == '\0': - continue - if first_const == 0: - self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",") - first_const = 0 - self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "~{") - self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cname) - self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "}") - - # ============================================================ - # 6. 构建参数列表文本(仅输入操作数) - # ============================================================ - args_buf: str = pool.alloc(ASM_ARGS_BUF_SIZE) - if args_buf is None: - return None - args_buf[0] = '\0' - - first_arg: int = 1 - for ai3 in range(operand_count): - orig_i2: int = new_order[ai3] - aop: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, orig_i2) - if aop.IsOutput != 0: - continue - aval: llvmlite.Value | t.CPtr = aop.Value - if aval is None or aval.Ty is None or aval.Name is None: - continue - - if first_arg == 0: - self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ", ") - first_arg = 0 - - # 类型文本 - ty_buf: str = pool.alloc(64) - if ty_buf is not None: - ty_buf[0] = '\0' - llvmlite.TypePrint(ty_buf, 64, aval.Ty, pool) - self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ty_buf) - self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, " ") - self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, aval.Name) - - # ============================================================ - # 7. 转义汇编文本 - # ============================================================ - escaped_asm: str = self._asm_escape_for_ir(pool, asm_text) - if escaped_asm is None: - return None - - # ============================================================ - # 8. 生成 IR 行并发射 - # ============================================================ - line: str = pool.alloc(ASM_LINE_BUF_SIZE) - if line is None: - return None - line[0] = '\0' - - ssa_name: str = None - if is_void == 0: - ssa_name = pool.alloc(16) - if ssa_name is not None: - viperlib.snprintf(ssa_name, 16, "%%%d", builder.Counter) - builder.Counter += 1 - - # 获取返回类型文本 - ret_ty_buf: str = pool.alloc(64) - if ret_ty_buf is not None: - ret_ty_buf[0] = '\0' - llvmlite.TypePrint(ret_ty_buf, 64, ret_ty, pool) - - if is_void == 1: - viperlib.snprintf(line, ASM_LINE_BUF_SIZE, - "call %s asm sideeffect inteldialect \"%s\", \"%s\"(%s)", - ret_ty_buf, escaped_asm, const_buf, args_buf) - else: - viperlib.snprintf(line, ASM_LINE_BUF_SIZE, - "%s = call %s asm sideeffect inteldialect \"%s\", \"%s\"(%s)", - ssa_name, ret_ty_buf, escaped_asm, const_buf, args_buf) - - # 发射 IR 到当前块 - llvmlite.block_append_text(pool, builder.CurBlock, line) - - # ============================================================ - # 9. 处理输出:存储结果到输出变量 - # ============================================================ - if is_void == 0 and first_output_idx >= 0: - result_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, ret_ty, ssa_name) - out_emit_idx: int = 0 - for oi_out in range(operand_count): - orig_o: int = new_order[oi_out] - oo: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, orig_o) - if oo is None or oo.IsOutput == 0: - continue - if output_count > 1: - # 多输出:extractvalue 取第 out_emit_idx 个元素后 store - if oo.Value is not None and oo.Value.Ty is not None \ - and oo.Value.Ty.Pointee is not None: - ev_name: str = pool.alloc(32) - ev_line: str = pool.alloc(ASM_LINE_BUF_SIZE) - if ev_name is not None and ev_line is not None: - # ssa_name 形如 "%N"(纯数字 ID),构造唯一名 - # "%asm.N.e{i}"(字母开头,避免 %N.e{i} 被解析为 - # 数字 ID + 非法后缀导致 "expected '=' after id") - viperlib.snprintf(ev_name, 32, "%%asm.%s.e%d", ssa_name + 1, out_emit_idx) - viperlib.snprintf(ev_line, ASM_LINE_BUF_SIZE, - "%s = extractvalue %s %s, %d", - ev_name, ret_ty_buf, ssa_name, out_emit_idx) - llvmlite.block_append_text(pool, builder.CurBlock, ev_line) - ev_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, oo.Value.Ty.Pointee, ev_name) - llvmlite.build_store(builder, ev_val, oo.Value) - else: - if oo.Value is not None: - llvmlite.build_store(builder, result_val, oo.Value) - out_emit_idx += 1 - return result_val - - return None - - - def translate_c_llvmir(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """c.LLVMIR 内联 LLVM IR:无返回值,直接嵌入原始 IR 文本 - - 不做指令解析,模板文本(c.LInp/c.LOut 替换后)用 block_append_text - 嵌入当前基本块。c.LOut 变量由唯一 SSA 寄存器 %llvmirN 接收结果, - 嵌入后自动追加 store 写回变量 alloca。返回 None(无返回值)。 - """ - if cl is None or builder is None or pool is None or trans is None: - return None - - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cargs is None or len(cargs) < 1: - HandlesType.fatal_error(cl, "c.LLVMIR 缺少模板参数", "TypeError") - - # LOut 写回记录(alloca 指针 + 寄存器名),最多 LLVMIR_MAX_OPS 个 - out_alloca: t.CSizeT | t.CPtr = pool.alloc(8 * LLVMIR_MAX_OPS) - out_regname: t.CSizeT | t.CPtr = pool.alloc(8 * LLVMIR_MAX_OPS) - if out_alloca is None or out_regname is None: - return None - string.memset(out_alloca, 0, 8 * LLVMIR_MAX_OPS) - string.memset(out_regname, 0, 8 * LLVMIR_MAX_OPS) - out_count: int = 0 - - # 模板文本缓冲区 - text: str = pool.alloc(LLVMIR_TEMPLATE_BUF) - if text is None: - return None - text[0] = '\0' - - # ============================================================ - # 1. 解析 IR 模板(JoinedStr 或 Constant)— 替换 LInp/LOut/表达式为值文本 - # ============================================================ - first_arg: ast.AST | t.CPtr = cargs.get(0) - if first_arg is None: - return None - - tk: int = first_arg.kind() - - if tk == ast.ASTKind.JoinedStr: - js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(first_arg) - jvalues: list[ast.AST | t.CPtr] | t.CPtr = js.values - if jvalues is not None: - jvlen: t.CSizeT = len(jvalues) - for vi in range(jvlen): - part: ast.AST | t.CPtr = jvalues.get(vi) - if part is None: - continue - pk: int = part.kind() - - if pk == ast.ASTKind.Constant: - # 字符串字面量片段 - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part) - if cn.str_val is not None: - self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, cn.str_val) - - elif pk == ast.ASTKind.FormattedValue: - fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part) - fexpr: ast.AST | t.CPtr = fv.value - if fexpr is None: - continue - # 检测 c.LInp / c.LOut - if fexpr.kind() == ast.ASTKind.Call: - fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr) - attr_nm: str = self._asm_is_c_call(fcall) - if attr_nm is not None: - fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args - if fargs is None or len(fargs) < 1: - continue - val_node: ast.AST | t.CPtr = fargs.get(0) - - if string.strcmp(attr_nm, "LInp") == 0: - # 输入操作数:翻译值,替换为 LLVM 值引用文本(%x 或常量文本) - inp_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, val_node, None, 0, trans) - if inp_val is not None and inp_val.Name is not None: - self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, inp_val.Name) - - elif string.strcmp(attr_nm, "LOut") == 0: - # 输出操作数:为变量分配唯一 SSA 寄存器 %llvmirN, - # 记录写回(模板嵌入后 store 到变量 alloca) - if val_node is not None and val_node.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node) - if nm.id is not None: - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, nm.id) - if alloca is None or out_count >= LLVMIR_MAX_OPS: - HandlesType.fatal_error( - fcall, - f"c.LOut 变量 '{nm.id}' 未定义或输出数超过 {LLVMIR_MAX_OPS}", - "TypeError") - self.LLVMIRRegSeq += 1 - reg_buf: str = pool.alloc(32) - if reg_buf is not None: - viperlib.snprintf(reg_buf, 32, "%%llvmir_%d", self.LLVMIRRegSeq) - self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, reg_buf) - out_alloca[out_count] = t.CSizeT(alloca) - out_regname[out_count] = t.CSizeT(reg_buf) - out_count += 1 - continue - # 非 c.LInp/c.LOut 的 f-string 表达式:翻译值并嵌入值文本 - ival: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, fexpr, None, 0, trans) - if ival is not None and ival.Name is not None: - self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, ival.Name) - - elif tk == ast.ASTKind.Constant: - cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(first_arg) - if cn2.str_val is not None: - # 裸 strcpy 无界:模板常量串 ≥ LLVMIR_TEMPLATE_BUF 会越界写 pool 块, - # 改用与 JoinedStr 分支一致的有界追加 - self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, cn2.str_val) - - # ============================================================ - # 2. 直接嵌入模板文本(不做指令解析)+ LOut 写回 - # ============================================================ - llvmlite.block_append_text(pool, builder.CurBlock, text) - - # LOut 写回: store %llvmirN, * %var - oi: int - for oi in range(out_count): - oa: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)(t.CVoid(out_alloca[oi], t.CPtr)) - rn: str = (str)(t.CVoid(out_regname[oi], t.CPtr)) - if oa is None or oa.Ty is None or oa.Ty.Pointee is None or rn is None: - continue - reg_val: llvmlite.Value | t.CPtr = llvmlite.new_value(pool) - if reg_val is None: - continue - reg_val.Ty = oa.Ty.Pointee - reg_val.Name = rn - reg_val.IsConst = 0 - llvmlite.build_store(builder, reg_val, oa) - - return None - - # ============================================================ - # _apply_struct_defaults — 应用结构体字段的默认值 - # - # 在 zeroinitializer 之后、显式参数之前调用 - # 遍历所有字段,对有默认值的字段翻译并 store - # 显式参数(位置/关键字)后续会覆盖默认值 - # ============================================================ +import lib.core.Gen.GenTypes as GenTypes +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import sys +import viperlib +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.CallGenBase as CallGenBase + + +# ============================================================ +# CallGenCBuiltin - CallGenMixin 拆分 2/9:c.* 内建 + asm + llvmir +# +# 按功能域从 CallGenMixin.vp 拆出(500~1500 行/文件架构重构): +# translate_c_deref/derefas/set/addr/load + c.Asm 全套 + c.LLVMIR。 +# 继承 CallGenBase。 +# +# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 +# ============================================================ + + +# ============================================================ +# _IsTypeExpr / _IsCastWrappingDeref - c.Deref 加载宽度推断的转换包裹判定 +# (镜像 TPC HandlesSpecialCall:转换链包裹 Deref 时允许从赋值注解推断 +# 加载宽度;ifexp/binop 包裹不放行,避免 i8* 错 bitcast 成其他位宽读) +# ============================================================ +def _IsTypeExpr(node: ast.AST | t.CPtr) -> int: + """节点是否为类型表达式(Name/Attribute/Subscript/BinOp|)""" + if node is None: + return 0 + k: int = node.kind() + if k == ast.ASTKind.Name or k == ast.ASTKind.Attribute or k == ast.ASTKind.Subscript: + return 1 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if bop.op == ast.OpKind.BitOr: + return 1 + return 0 + + +def _IsCastWrappingDeref(rhs: ast.AST | t.CPtr, deref_node: ast.AST | t.CPtr) -> int: + """rhs 是否为"类型转换链包裹 c.Deref"(如 (T | t.CPtr)(t.CPtr(c.Deref(p))))""" + if rhs is None: + return 0 + if t.CUInt64T(rhs) == t.CUInt64T(deref_node): + return 1 + if rhs.kind() == ast.ASTKind.Call: + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(rhs) + if cl.args is not None and len(cl.args) == 1 and _IsTypeExpr(cl.func) != 0: + return _IsCastWrappingDeref(cl.args.get(0), deref_node) + return 0 + + +# ============================================================ +# 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug) +# ============================================================ +GLOBAL_FUNC_MAX: t.CDefine = 8192 +GLOBAL_DEFAULTS_MAX: t.CDefine = 4096 +_CEXPORT_MAX: t.CDefine = 256 +ASM_MAX_OPERANDS: t.CDefine = 16 +ASM_TEXT_BUF_SIZE: t.CDefine = 2048 +ASM_CONST_BUF_SIZE: t.CDefine = 512 +ASM_ARGS_BUF_SIZE: t.CDefine = 512 +ASM_LINE_BUF_SIZE: t.CDefine = 4096 +LLVMIR_MAX_OPS: t.CDefine = 16 +LLVMIR_TEMPLATE_BUF: t.CDefine = 512 +# 闭包名表大小(原 HandlesExprCall 模块级常量) +MAX_CLOSURE_NAMES: t.CDefine = 128 +# 函数指针签名表大小(原 HandlesExprCall 模块级常量) +MAX_FUNC_PTR_SIGS: t.CDefine = 64 +# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32) +ISINSTANCE_CLASS_MAX: t.CDefine = 64 + + +# ============================================================ +# CallGenCBuiltin - c.*/asm/llvmir 内建 +# ============================================================ +@t.NoVTable +class CallGenCBuiltin(CallGenBase.CallGenBase): + """c.* 内建 + 内联汇编 + LLVMIR 翻译(继承 Base)""" + + + def translate_c_deref(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """c.Deref(ptr) → load 按 ptr 的 pointee 类型""" + if cl is None: + return None + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or len(cargs) < 1: + return None + + ptr_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cargs.get(0), None, 0, trans) + if ptr_val is None: + return None + + # 按 pointee 类型读取;非指针参数默认按 i8(保持向后兼容) + if self.Gen.ExprGenBase.is_ptr_type(ptr_val.Ty) != 0: + pointee: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee + if pointee is not None: + # i8*(void*)时按赋值目标类型推断读取宽度(对齐 TPC + # HandlesSpecialCall._infer_deref_target_type): + # v: int = c.Deref(p) → bitcast i32* 后 load 4 字节。 + # 背景:DictTest d3[key5]=500 读出 -12——固定按 i8 读 1 字节 + + # sext 截断(0xF4 → 0xFFFFFFF4);Test 1 的小值(10)恰好正确 + # 掩盖了缺陷。 + match pointee: + case llvmlite.LLVMType.Int(pointee_width): + # 允许推断:c.Deref 是赋值语句直接 RHS(v: int = c.Deref(p)) + # 或处于类型转换链包裹中(如 vt: t.CVoid | t.CPtr = + # t.CVoid(c.Deref(p)))。嵌套在 while 条件/比较/binop/ + # 其他调用中(如 while c.Deref(p) != 0、total += + # t.CInt(c.Deref(p)))不推断,否则 i8* 会被残留 + # CurAssignAnnot 误判为 i32* 读 4 字节 → StringIterTest + # ASCII sum/manual strcmp 失败。 + allow_infer: int = 0 + if trans is not None and trans.CurAssignNode is not None: + if t.CUInt64T(cl) == t.CUInt64T(trans.CurAssignNode): + allow_infer = 1 + elif _IsCastWrappingDeref(trans.CurAssignNode, cl) != 0: + allow_infer = 1 + if pointee_width == 8 and allow_infer != 0 \ + and trans is not None and trans.CurAssignAnnot is not None: + dref_ty: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( + trans.Pool, trans.CurAssignAnnot, + trans._imported_modules, trans._from_imports, trans) + if dref_ty is not None: + dref_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(dref_ty) + dref_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(dref_ty) + dref_is_ptr: int = self.Gen.ExprGenBase.is_ptr_type(dref_ty) + # 整数/浮点/指针目标均推断(指针 → bitcast 后 + # load 8 字节;struct 值目标不推断,保持 i8 读) + dref_ptr: llvmlite.Value | t.CPtr = None + if (dref_bits != 0 or dref_fbits != 0 or dref_is_ptr != 0) \ + and dref_bits != 8: + dref_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, dref_ty) + dref_ptr = llvmlite.build_bitcast( + builder, ptr_val, dref_ptr_ty) + if dref_ptr is not None: + return llvmlite.build_load(builder, dref_ty, dref_ptr) + case _: + pass + return llvmlite.build_load(builder, pointee, ptr_val) + # 非指针参数即类型推断退化:fail-fast,绝不按 i8 兜底读取(会读到垃圾宽度) + self.Gen.TypeGenErr.fatal_error(cl, "c.Deref 参数不是指针类型(类型推断退化)", "TypeError") + return None + + + def translate_c_derefas(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """c.DerefAs(ptr, val) → store val to ptr(bitcast 后 store)""" + if cl is None: + return None + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or len(cargs) < 2: + return None + + ptr_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cargs.get(0), None, 0, trans) + val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cargs.get(1), None, 0, trans) + if ptr_val is None or val is None: + return None + + # 两端均为指向同一结构体类型的指针时执行结构体拷贝(*ptr = *val), + # 而非存储指针值。这对 REnum 变体构造(c.DerefAs(ptr, LLVMType.Int(32)))至关重要: + # LLVMType.Int(32) 构造返回 alloca 指针(Ptr(LLVMType)),若直接 store 指针值, + # 只写入 8 字节指针(tag 字段仍是 0x0),导致运行时读 tag 错乱。 + # 对应 TPC HandlesExprCall.py:3696-3701 的 struct 拷贝逻辑。 + if self.Gen.ExprGenBase.is_ptr_type(ptr_val.Ty) != 0 and self.Gen.ExprGenBase.is_ptr_type(val.Ty) != 0: + ptr_pointee: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee + val_pointee: llvmlite.LLVMType | t.CPtr = val.Ty.Pointee + if ptr_pointee is not None and val_pointee is not None: + # ptr_pointee 是已注册结构体类型(用 find_struct_by_type 判断) + if self.Gen.StructGen.find_struct_by_type(ptr_pointee) is not None: + if ptr_pointee is val_pointee: + # 同一结构体类型:load 值再 store(结构体拷贝) + loaded: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, val_pointee, val) + if loaded is not None: + # bitcast ptr 到结构体指针再 store + struct_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, ptr_pointee) + casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, ptr_val, struct_ptr_ty) + if casted_ptr is not None: + llvmlite.build_store(builder, loaded, casted_ptr) + return val + + # bitcast ptr 到 val.Ty* 再 store + val_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, val.Ty) + casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ptr_val, val_ptr_ty) + if casted_ptr is None: + return None + llvmlite.build_store(builder, val, casted_ptr) + return val + + + def translate_c_set(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """c.Set(a, b) → a = b(赋值语义,a 为左值)""" + if cl is None: + return None + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or len(cargs) < 2: + return None + a_node: ast.AST | t.CPtr = cargs.get(0) + b_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cargs.get(1), None, 0, trans) + if b_val is None: + return None + + # 形态 1: c.Set(c.Deref(ptr), b) → *ptr = b + if a_node is not None and a_node.kind() == ast.ASTKind.Call: + d_call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(a_node) + if d_call.func is not None and d_call.func.kind() == ast.ASTKind.Attribute: + d_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(d_call.func) + if d_at.attr is not None and string.strcmp(d_at.attr, "Deref") == 0: + d_args: list[ast.AST | t.CPtr] | t.CPtr = d_call.args + if d_args is not None and len(d_args) >= 1: + ptr_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, d_args.get(0), None, 0, trans) + if ptr_val is not None: + val_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, b_val.Ty) + casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, ptr_val, val_ptr_ty) + if casted_ptr is not None: + llvmlite.build_store(builder, b_val, casted_ptr) + return b_val + # 其他 Call 形态不可作左值 + return b_val + + # 形态 2: Name 变量赋值 + if a_node is not None and a_node.kind() == ast.ASTKind.Name and trans is not None: + nm_set: ast.Name | t.CPtr = (ast.Name | t.CPtr)(a_node) + if nm_set.id is not None: + if HT.is_global_name(trans, nm_set.id) != 0: + mod_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_module_var( + trans.SymTab, nm_set.id) + if mod_alloca is not None: + tg_ty: llvmlite.LLVMType | t.CPtr = None + if mod_alloca.Ty is not None: + tg_ty = mod_alloca.Ty.Pointee + sv: llvmlite.Value | t.CPtr = b_val + if tg_ty is not None: + sv = self.Gen.ExprGenBase.coerce_to_type(builder, b_val, tg_ty, a_node) + llvmlite.build_store(builder, sv, mod_alloca) + return b_val + if HT.is_nonlocal_name(trans, nm_set.id) != 0: + nl_ptr: llvmlite.Value | t.CPtr = self.Gen.StmtGenDecl.get_nonlocal_var_ptr( + trans, nm_set.id) + if nl_ptr is not None: + nl_ty: llvmlite.LLVMType | t.CPtr = None + if nl_ptr.Ty is not None: + nl_ty = nl_ptr.Ty.Pointee + sv2: llvmlite.Value | t.CPtr = b_val + if nl_ty is not None: + sv2 = self.Gen.ExprGenBase.coerce_to_type(builder, b_val, nl_ty, a_node) + llvmlite.build_store(builder, sv2, nl_ptr) + return b_val + alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.get_or_create_sym( + trans.SymTab, pool, builder, nm_set.id, b_val.Ty) + if alloca is not None: + ac_ty: llvmlite.LLVMType | t.CPtr = None + if alloca.Ty is not None: + ac_ty = alloca.Ty.Pointee + sv3: llvmlite.Value | t.CPtr = b_val + if ac_ty is not None: + sv3 = self.Gen.ExprGenBase.coerce_to_type(builder, b_val, ac_ty, a_node) + llvmlite.build_store(builder, sv3, alloca) + return b_val + return b_val + + # 形态 3: Attribute 字段赋值 + if a_node is not None and a_node.kind() == ast.ASTKind.Attribute: + field_ptr: llvmlite.Value | t.CPtr = self.Gen.ExprGenAttr.get_attribute_ptr( + builder, pool, mod, a_node, trans) + if field_ptr is not None: + fd_ty: llvmlite.LLVMType | t.CPtr = None + if field_ptr.Ty is not None: + fd_ty = field_ptr.Ty.Pointee + sv4: llvmlite.Value | t.CPtr = b_val + if fd_ty is not None: + sv4 = self.Gen.ExprGenBase.coerce_to_type(builder, b_val, fd_ty, a_node) + llvmlite.build_store(builder, sv4, field_ptr) + return b_val + + return b_val + + + def translate_c_addr(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """c.Addr(var) → 返回变量的 alloca 指针(不 load)""" + if cl is None: + return None + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or len(cargs) < 1: + return None + + arg0: ast.AST | t.CPtr = cargs.get(0) + if arg0 is None: + return None + + # Name 形式: c.Addr(var) → 返回变量的 alloca 指针(不 load) + if arg0.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0) + if nm.id is None: + return None + if trans is not None: + # self/cls 对象引用:c.Addr(self) 返回对象指针本身(Ptr(Struct)), + # 而非指针变量的地址(Ptr(Ptr(Struct)))。方法与 Attribute 分支 + # (c.Addr(self.field) 先 load self)语义一致,供 + # return t.CVoid(c.Addr(self), CPtr) 返回 this 使用。 + if string.strcmp(nm.id, "self") == 0 or string.strcmp(nm.id, "cls") == 0: + self_entry: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, nm.id) + if self_entry is not None and self_entry.Alloca is not None and self_entry.Alloca.Ty is not None: + match self_entry.Alloca.Ty: + case llvmlite.LLVMType.Ptr(inner1): + match inner1: + case llvmlite.LLVMType.Ptr(inner2): + obj_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, inner2) + return llvmlite.build_load(builder, obj_ty, self_entry.Alloca) + case _: + pass + case _: + pass + return_var: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id) + if return_var is not None and return_var.Ty is not None: + # 对象指针变量(如 lit_tree = zhuff.zhuff_tree(),alloca 是 + # Ptr(Ptr(Struct)),存对象指针):c.Addr(对象变量) 应返回对象 + # 指针本身(load 一次),对齐 self/cls 分支与 c.Addr(self.field) + # (GEP 后对象地址)。此前直接返回 &变量(Ptr(Ptr(Struct)))→ + # 调用端 bitcast 成 Ptr(Struct) 后 ht 指向指针变量存储 → 字段 + # 读到指针值/垃圾 → build_decode_tree 越界崩溃 + # (zinflate inflate_block_fixed 的 c.Addr(lit_tree) 根因)。 + match return_var.Ty: + case llvmlite.LLVMType.Ptr(addr_inner1): + match addr_inner1: + case llvmlite.LLVMType.Ptr(addr_inner2): + match addr_inner2: + case llvmlite.LLVMType.Struct(_, _, _): + addr_obj_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, addr_inner2) + return llvmlite.build_load(builder, addr_obj_ty, return_var) + case _: + pass + case _: + pass + case _: + pass + return return_var + + # Attribute 形式: c.Addr(self.field) → 取字段地址(GEP 到字段,不 load) + # 用于 atom.__atomic_test_and_set(c.Addr(self.lock_val), ...) 等锁操作 + if arg0.kind() == ast.ASTKind.Attribute: + if trans is None: + return None + at_addr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg0) + if at_addr is None or at_addr.attr is None or at_addr.value is None: + return None + # 解析 self(Name)→ 查找 alloca + if at_addr.value.kind() != ast.ASTKind.Name: + return None + self_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_addr.value) + if self_nm.id is None: + return None + self_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, self_nm.id) + if self_alloca is None or self_alloca.Ty is None: + return None + # 从 self 类型提取结构体类型(Ptr(Struct) 或 Ptr(Ptr(Struct))) + struct_ty: llvmlite.LLVMType | t.CPtr = None + self_is_ptr_ptr: int = 0 + match self_alloca.Ty: + case llvmlite.LLVMType.Ptr(inner1): + match inner1: + case llvmlite.LLVMType.Ptr(inner2): + struct_ty = inner2 + self_is_ptr_ptr = 1 + case _: + struct_ty = inner1 + case _: + return None + # 查找字段 + fe_addr: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field( + struct_ty, at_addr.attr) + if fe_addr is None: + return None + # self_alloca 是 Ptr(Ptr(Struct)) 时先 load 成 Ptr(Struct) 对象指针 + obj_ptr: llvmlite.Value | t.CPtr = self_alloca + if self_is_ptr_ptr == 1: + self_obj_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) + obj_ptr = llvmlite.build_load(builder, self_obj_ty, self_alloca) + if obj_ptr is None: + return None + # GEP 到字段地址 + return llvmlite.build_gep_struct( + builder, struct_ty, fe_addr.Ty, obj_ptr, fe_addr.Index) + + # Subscript 形式: c.Addr(arr[i]) → 数组元素地址(GEP 数组,不 load) + # 用于 self.root_directory = c.Addr(directories[directory_count]) 等。 + # 此前只支持 Name/Attribute,Subscript 落到函数末尾返回 None → + # 赋值右侧为 None(devfs.vp:159 根因)。 + if arg0.kind() == ast.ASTKind.Subscript: + if trans is None: + return None + sub_addr: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(arg0) + if sub_addr is None or sub_addr.value is None or sub_addr.slice is None: + return None + arr_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, sub_addr.value, None, 0, trans) + if arr_val is None or arr_val.Ty is None: + return None + idx_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, sub_addr.slice, None, 0, trans) + if idx_val is None: + return None + # 数组基址 pointee 是 Array(elem_ty, N) → GEP 得元素指针 + arr_pointee_ca: llvmlite.LLVMType | t.CPtr = None + if self.Gen.ExprGenBase.is_ptr_type(arr_val.Ty) != 0: + arr_pointee_ca = arr_val.Ty.Pointee + if arr_pointee_ca is not None: + match arr_pointee_ca: + case llvmlite.LLVMType.Array(arr_et_ca, _): + return llvmlite.build_gep_array( + builder, arr_pointee_ca, arr_et_ca, arr_val, idx_val) + case _: + pass + return None + + # 其他 arg0 形式(非 Name/Attribute/Subscript):真实掉出函数末尾, + # 补显式 return None(fail-fast 不允许流程掉出末尾) + return None + + + def translate_c_load(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """c.Load(a, b) → *a = *b(加载 b 的值,存储到 a)""" + if cl is None: + return None + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or len(cargs) < 2: + return None + + dst_ptr: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cargs.get(0), None, 0, trans) + src_ptr: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cargs.get(1), None, 0, trans) + if dst_ptr is None or src_ptr is None: + return None + + # 确定 pointee 类型(优先用 src 的 pointee,回退到 dst 的 pointee) + pointee: llvmlite.LLVMType | t.CPtr = None + if src_ptr.Ty is not None: + pointee = src_ptr.Ty.Pointee + if pointee is None and dst_ptr.Ty is not None: + pointee = dst_ptr.Ty.Pointee + if pointee is None: + return None + + # bitcast src 到 pointee* 并 load + target_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, pointee) + src_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, src_ptr, target_ptr_ty) + if src_cast is None: + return None + loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, pointee, src_cast) + if loaded is None: + return None + + # bitcast dst 到 pointee* 并 store + dst_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, dst_ptr, target_ptr_ty) + if dst_cast is None: + return None + llvmlite.build_store(builder, loaded, dst_cast) + return loaded + + + def _asm_append_cstr(self, dst: str, dst_size: t.CSizeT, + src: str): + """将 C 字符串 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 + i: t.CSizeT = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' + + + def _asm_escape_for_ir(self, pool: memhub.MemBuddy | t.CPtr, + src: str) -> str: + """转义汇编文本用于 LLVM IR 字符串字面量""" + if src is None: + return None + slen: t.CSizeT = string.strlen(src) + buf: str = pool.alloc(slen * 4 + 8) + if buf is None: + return None + pos: t.CSizeT = 0 + for ch in src: + if ch == '\n': + buf[pos] = '\\' + pos += 1 + buf[pos] = '0' + pos += 1 + buf[pos] = 'A' + pos += 1 + elif ch == '"': + buf[pos] = '\\' + pos += 1 + buf[pos] = '2' + pos += 1 + buf[pos] = '2' + pos += 1 + elif ch == '\\': + buf[pos] = '\\' + pos += 1 + buf[pos] = '5' + pos += 1 + buf[pos] = 'C' + pos += 1 + else: + buf[pos] = ch + pos += 1 + buf[pos] = '\0' + return buf + + + def _resolve_register(self, attr_name: str) -> str: + """将 t.ASM_DESCR.XXX 的属性名映射到约束字符串值""" + if attr_name is None: + return "" + + # Clobber 破坏描述符 + if string.strcmp(attr_name, "CLOBBER_MEMORY") == 0: return "memory" + if string.strcmp(attr_name, "CLOBBER_CC") == 0: return "cc" + if string.strcmp(attr_name, "CLOBBER_RAX") == 0: return "rax" + if string.strcmp(attr_name, "CLOBBER_RBX") == 0: return "rbx" + if string.strcmp(attr_name, "CLOBBER_RCX") == 0: return "rcx" + if string.strcmp(attr_name, "CLOBBER_RDX") == 0: return "rdx" + if string.strcmp(attr_name, "CLOBBER_RSI") == 0: return "rsi" + if string.strcmp(attr_name, "CLOBBER_RDI") == 0: return "rdi" + if string.strcmp(attr_name, "CLOBBER_RBP") == 0: return "rbp" + if string.strcmp(attr_name, "CLOBBER_RSP") == 0: return "rsp" + if string.strcmp(attr_name, "CLOBBER_R8") == 0: return "r8" + if string.strcmp(attr_name, "CLOBBER_R9") == 0: return "r9" + if string.strcmp(attr_name, "CLOBBER_R10") == 0: return "r10" + if string.strcmp(attr_name, "CLOBBER_R11") == 0: return "r11" + if string.strcmp(attr_name, "CLOBBER_R12") == 0: return "r12" + if string.strcmp(attr_name, "CLOBBER_R13") == 0: return "r13" + if string.strcmp(attr_name, "CLOBBER_R14") == 0: return "r14" + if string.strcmp(attr_name, "CLOBBER_R15") == 0: return "r15" + if string.strcmp(attr_name, "CLOBBER_EAX") == 0: return "eax" + if string.strcmp(attr_name, "CLOBBER_EBX") == 0: return "ebx" + if string.strcmp(attr_name, "CLOBBER_ECX") == 0: return "ecx" + if string.strcmp(attr_name, "CLOBBER_EDX") == 0: return "edx" + if string.strcmp(attr_name, "CLOBBER_ESI") == 0: return "esi" + if string.strcmp(attr_name, "CLOBBER_EDI") == 0: return "edi" + if string.strcmp(attr_name, "CLOBBER_DX") == 0: return "dx" + if string.strcmp(attr_name, "CLOBBER_AX") == 0: return "ax" + if string.strcmp(attr_name, "CLOBBER_CX") == 0: return "cx" + if string.strcmp(attr_name, "CLOBBER_SI") == 0: return "si" + if string.strcmp(attr_name, "CLOBBER_DI") == 0: return "di" + + # Output 输出约束 + if string.strcmp(attr_name, "OUTPUT_REG") == 0: return "=r" + if string.strcmp(attr_name, "OUTPUT_MEM") == 0: return "=m" + if string.strcmp(attr_name, "OUTPUT_EAX") == 0: return "=a" + if string.strcmp(attr_name, "OUTPUT_EBX") == 0: return "=b" + if string.strcmp(attr_name, "OUTPUT_ECX") == 0: return "=c" + if string.strcmp(attr_name, "OUTPUT_EDX") == 0: return "=d" + if string.strcmp(attr_name, "OUTPUT_ESI") == 0: return "=S" + if string.strcmp(attr_name, "OUTPUT_EDI") == 0: return "=D" + if string.strcmp(attr_name, "OUTPUT_RAX") == 0: return "=a" + if string.strcmp(attr_name, "OUTPUT_RBX") == 0: return "=b" + if string.strcmp(attr_name, "OUTPUT_RCX") == 0: return "=c" + if string.strcmp(attr_name, "OUTPUT_RDX") == 0: return "=d" + if string.strcmp(attr_name, "OUTPUT_RSI") == 0: return "=S" + if string.strcmp(attr_name, "OUTPUT_RDI") == 0: return "=D" + + # Input/Register 输入约束 + if string.strcmp(attr_name, "REG_ANY") == 0: return "r" + if string.strcmp(attr_name, "REG_EAX") == 0: return "a" + if string.strcmp(attr_name, "REG_EBX") == 0: return "b" + if string.strcmp(attr_name, "REG_ECX") == 0: return "c" + if string.strcmp(attr_name, "REG_EDX") == 0: return "d" + if string.strcmp(attr_name, "REG_ESI") == 0: return "S" + if string.strcmp(attr_name, "REG_EDI") == 0: return "D" + if string.strcmp(attr_name, "REG_RAX") == 0: return "a" + if string.strcmp(attr_name, "REG_RBX") == 0: return "b" + if string.strcmp(attr_name, "REG_RCX") == 0: return "c" + if string.strcmp(attr_name, "REG_RDX") == 0: return "d" + if string.strcmp(attr_name, "REG_RSI") == 0: return "S" + if string.strcmp(attr_name, "REG_RDI") == 0: return "D" + + if string.strcmp(attr_name, "INPUT_REG") == 0: return "r" + if string.strcmp(attr_name, "INPUT_MEM") == 0: return "m" + if string.strcmp(attr_name, "INPUT_EAX") == 0: return "a" + if string.strcmp(attr_name, "INPUT_EBX") == 0: return "b" + if string.strcmp(attr_name, "INPUT_ECX") == 0: return "c" + if string.strcmp(attr_name, "INPUT_EDX") == 0: return "d" + if string.strcmp(attr_name, "INPUT_ESI") == 0: return "S" + if string.strcmp(attr_name, "INPUT_EDI") == 0: return "D" + if string.strcmp(attr_name, "INPUT_RAX") == 0: return "a" + if string.strcmp(attr_name, "INPUT_RBX") == 0: return "b" + if string.strcmp(attr_name, "INPUT_RCX") == 0: return "c" + if string.strcmp(attr_name, "INPUT_RDX") == 0: return "d" + if string.strcmp(attr_name, "INPUT_RSI") == 0: return "S" + if string.strcmp(attr_name, "INPUT_RDI") == 0: return "D" + + return "" + + + def _resolve_asm_descr(self, pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr) -> str: + """递归解析约束表达式,返回约束字符串""" + if node is None: + return "" + + k: int = node.kind() + + # BinOp with BitOr: 拼接左右 + 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._resolve_asm_descr(pool, bop.left) + right_str: str = self._resolve_asm_descr(pool, bop.right) + llen: t.CSizeT = string.strlen(left_str) + rlen: t.CSizeT = string.strlen(right_str) + buf: str = pool.alloc(llen + rlen + 1) + if buf is None: + return "" + string.strcpy(buf, left_str) + for i in range(rlen): + buf[llen + i] = right_str[i] + buf[llen + rlen] = '\0' + return buf + return "" + + # Attribute: t.ASM_DESCR.XXX 或 t.XXX + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + # t.ASM_DESCR.XXX + if at.value is not None and at.value.kind() == ast.ASTKind.Attribute: + inner: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(at.value) + if inner.value is not None and inner.value.kind() == ast.ASTKind.Name: + mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner.value) + if mod_nm.id is not None and string.strcmp(mod_nm.id, "t") == 0: + if inner.attr is not None and string.strcmp(inner.attr, "ASM_DESCR") == 0: + return self._resolve_register(at.attr) + # t.XXX 简化形式 + if at.value is not None and at.value.kind() == ast.ASTKind.Name: + mod_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if mod_nm2.id is not None and string.strcmp(mod_nm2.id, "t") == 0: + return self._resolve_register(at.attr) + return "" + + # Constant: 字符串常量 + if k == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + if cn.const_kind == ast.CONST_STR: + return cn.str_val + return "" + + return "" + + + def _asm_get_operand(self, base: GenTypes.AsmOperand | t.CPtr, + idx: int) -> GenTypes.AsmOperand | t.CPtr: + """获取操作数数组中第 idx 个元素的指针""" + entry_size: t.CSizeT = GenTypes.AsmOperand.__sizeof__() + entry_addr: t.CUInt64T = t.CUInt64T(base) + idx * entry_size + return (GenTypes.AsmOperand | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + + + def _asm_is_c_call(self, node: ast.Call | t.CPtr) -> str: + """检查 Call 节点是否是 c.XXX 调用,返回属性名或 None""" + if node is None or node.func is None: + return None + if node.func.kind() != ast.ASTKind.Attribute: + return None + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node.func) + if at.value is None or at.value.kind() != ast.ASTKind.Name: + return None + mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if mod_nm.id is None or string.strcmp(mod_nm.id, "c") != 0: + return None + return at.attr + + + def _asm_add_operand(self, operands: GenTypes.AsmOperand | t.CPtr, + count: int, + val: llvmlite.Value | t.CPtr, + constraint: str, + is_output: int) -> int: + """添加操作数到数组,返回新计数(失败返回原计数) + + 去重:f-string 模板内嵌的 AsmOut/AsmInp 与 out=/inp= 声明指向 + 同一变量时会重复收集(如 vrandom.vp 的 c.Asm(f"...{AsmOut(v)}", + out=[AsmOut(v)])),同一 (Value, IsOutput) 只保留第一个, + 避免约束数多于 asm 返回元素数(llc: output constraints mismatch)。 + """ + if count >= ASM_MAX_OPERANDS: + return count + if val is not None: + for ei in range(count): + eop: GenTypes.AsmOperand | t.CPtr = self._asm_get_operand(operands, ei) + if eop is not None and eop.Value == val and eop.IsOutput == is_output: + return count + op: GenTypes.AsmOperand | t.CPtr = self._asm_get_operand(operands, count) + op.Value = val + op.Constraint = constraint + op.IsOutput = is_output + return count + 1 + + + def translate_c_asm(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译 c.Asm 内联汇编,返回结果 Value(无输出时返回 None)""" + if cl is None: + return None + + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or len(cargs) < 1: + return None + + # 分配操作数数组 + operand_size: t.CSizeT = GenTypes.AsmOperand.__sizeof__() + operands: GenTypes.AsmOperand | t.CPtr = pool.alloc(operand_size * ASM_MAX_OPERANDS) + if operands is None: + return None + string.memset(operands, 0, operand_size * ASM_MAX_OPERANDS) + + # 分配 clobber 名数组 + clobbers: str | t.CPtr = pool.alloc(8 * ASM_MAX_OPERANDS) + if clobbers is None: + return None + string.memset(clobbers, 0, 8 * ASM_MAX_OPERANDS) + + # 分配 asm 文本缓冲区 + asm_text: str = pool.alloc(ASM_TEXT_BUF_SIZE) + if asm_text is None: + return None + asm_text[0] = '\0' + + operand_count: int = 0 + clobber_count: int = 0 + fv_count: int = 0 + + # 分配 fv 索引数组(记录每个 FormattedValue 对应的操作数原始索引) + fv_orig_indices: int | t.CPtr = pool.alloc(4 * ASM_MAX_OPERANDS) + if fv_orig_indices is None: + return None + string.memset(fv_orig_indices, 0, 4 * ASM_MAX_OPERANDS) + + # ============================================================ + # 1. 解析汇编模板(JoinedStr 或 Constant)— 第一遍:收集操作数 + # 不生成 asm 文本(占位符 $N 需在重排后才能确定编号) + # ============================================================ + tmpl_node: ast.AST | t.CPtr = cargs.get(0) + if tmpl_node is not None: + tk: int = tmpl_node.kind() + + if tk == ast.ASTKind.JoinedStr: + js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(tmpl_node) + jvalues: list[ast.AST | t.CPtr] | t.CPtr = js.values + if jvalues is not None: + jvlen: t.CSizeT = len(jvalues) + for vi in range(jvlen): + part: ast.AST | t.CPtr = jvalues.get(vi) + if part is None: + continue + pk: int = part.kind() + + if pk == ast.ASTKind.FormattedValue: + fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part) + fexpr: ast.AST | t.CPtr = fv.value + if fexpr is None or fexpr.kind() != ast.ASTKind.Call: + continue + fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr) + attr_nm: str = self._asm_is_c_call(fcall) + if attr_nm is None: + continue + + is_out: int = 0 + if string.strcmp(attr_nm, "AsmOut") == 0: + is_out = 1 + elif string.strcmp(attr_nm, "AsmInp") == 0: + is_out = 0 + else: + continue + + fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args + if fargs is None or len(fargs) < 1: + continue + + val_node: ast.AST | t.CPtr = fargs.get(0) + cons_str: str = "" + if len(fargs) >= 2: + cons_str = self._resolve_asm_descr(pool, fargs.get(1)) + + if is_out != 0: + # 输出:获取变量 alloca + if val_node is None or val_node.kind() != ast.ASTKind.Name: + continue + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node) + if nm.id is None: + continue + alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id) + if alloca is None: + continue + operand_count = self._asm_add_operand( + operands, operand_count, alloca, cons_str, 1) + else: + # 输入:翻译值 + ival: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, val_node, None, 0, trans) + if ival is None: + continue + operand_count = self._asm_add_operand( + operands, operand_count, ival, cons_str, 0) + + # 记录 fv 的原始操作数索引 + if fv_count < ASM_MAX_OPERANDS: + fv_orig_indices[fv_count] = operand_count - 1 + fv_count += 1 + + # ============================================================ + # 2. 解析关键字参数 out=/inp=/op=/clobber= + # ============================================================ + keywords: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords + if keywords is not None: + kwlen: t.CSizeT = len(keywords) + for ki in range(kwlen): + kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki)) + if kw is None or kw.arg is None or kw.value is None: + continue + kwk: int = kw.value.kind() + + if string.strcmp(kw.arg, "out") == 0: + # 输出操作数列表 + if kwk != ast.ASTKind.List: + continue + out_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value) + out_elts: list[ast.AST | t.CPtr] | t.CPtr = out_lst.elts + if out_elts is None: + continue + oelen: t.CSizeT = len(out_elts) + for oi in range(oelen): + oelt: ast.AST | t.CPtr = out_elts.get(oi) + if oelt is None or oelt.kind() != ast.ASTKind.Call: + continue + ocall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(oelt) + oattr: str = self._asm_is_c_call(ocall) + if oattr is None or string.strcmp(oattr, "AsmOut") != 0: + continue + oargs: list[ast.AST | t.CPtr] | t.CPtr = ocall.args + if oargs is None or len(oargs) < 1: + continue + oval_node: ast.AST | t.CPtr = oargs.get(0) + ocons: str = "" + if len(oargs) >= 2: + ocons = self._resolve_asm_descr(pool, oargs.get(1)) + if oval_node is None or oval_node.kind() != ast.ASTKind.Name: + continue + onm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(oval_node) + if onm.id is None: + continue + oalloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, onm.id) + if oalloca is None: + continue + operand_count = self._asm_add_operand( + operands, operand_count, oalloca, ocons, 1) + + elif string.strcmp(kw.arg, "inp") == 0 or string.strcmp(kw.arg, "inputs") == 0: + # 输入操作数列表 + if kwk != ast.ASTKind.List: + continue + in_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value) + in_elts: list[ast.AST | t.CPtr] | t.CPtr = in_lst.elts + if in_elts is None: + continue + ielen: t.CSizeT = len(in_elts) + for ii in range(ielen): + ielt: ast.AST | t.CPtr = in_elts.get(ii) + if ielt is None or ielt.kind() != ast.ASTKind.Call: + continue + icall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(ielt) + iattr: str = self._asm_is_c_call(icall) + if iattr is None or string.strcmp(iattr, "AsmInp") != 0: + continue + iargs: list[ast.AST | t.CPtr] | t.CPtr = icall.args + if iargs is None or len(iargs) < 1: + continue + ival_node: ast.AST | t.CPtr = iargs.get(0) + icons: str = "" + if len(iargs) >= 2: + icons = self._resolve_asm_descr(pool, iargs.get(1)) + ival2: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, ival_node, None, 0, trans) + if ival2 is None: + continue + operand_count = self._asm_add_operand( + operands, operand_count, ival2, icons, 0) + + elif string.strcmp(kw.arg, "op") == 0 or string.strcmp(kw.arg, "clobber") == 0: + # 破坏列表 + if kwk != ast.ASTKind.List: + continue + cl_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value) + cl_elts: list[ast.AST | t.CPtr] | t.CPtr = cl_lst.elts + if cl_elts is None: + continue + clen: t.CSizeT = len(cl_elts) + for ci in range(clen): + celt: ast.AST | t.CPtr = cl_elts.get(ci) + if celt is None: + continue + cstr: str = self._resolve_asm_descr(pool, celt) + if cstr is None or cstr[0] == '\0': + continue + if clobber_count < ASM_MAX_OPERANDS: + cl_addr: t.CUInt64T = t.CUInt64T(clobbers) + clobber_count * 8 + cl_ptr: str | t.CPtr = (str | t.CPtr)(t.CVoid(cl_addr, t.CPtr)) + cl_ptr[0] = cstr + clobber_count += 1 + + # ============================================================ + # 3. 解析第二个位置参数作为破坏列表 + # ============================================================ + if len(cargs) >= 2: + pos_node: ast.AST | t.CPtr = cargs.get(1) + if pos_node is not None and pos_node.kind() == ast.ASTKind.List: + pos_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(pos_node) + pos_elts: list[ast.AST | t.CPtr] | t.CPtr = pos_lst.elts + if pos_elts is not None: + plen: t.CSizeT = len(pos_elts) + for pi in range(plen): + pelt: ast.AST | t.CPtr = pos_elts.get(pi) + if pelt is None: + continue + pstr: str = self._resolve_asm_descr(pool, pelt) + if pstr is None or pstr[0] == '\0': + continue + if clobber_count < ASM_MAX_OPERANDS: + pcl_addr: t.CUInt64T = t.CUInt64T(clobbers) + clobber_count * 8 + pcl_ptr: str | t.CPtr = (str | t.CPtr)(t.CVoid(pcl_addr, t.CPtr)) + pcl_ptr[0] = pstr + clobber_count += 1 + + # ============================================================ + # 4. 统计输出/输入数量,确定返回类型 + # ============================================================ + output_count: int = 0 + input_count: int = 0 + first_output_idx: int = -1 + for oi2 in range(operand_count): + op2: GenTypes.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi2) + if op2.IsOutput != 0: + if first_output_idx < 0: + first_output_idx = oi2 + output_count += 1 + else: + input_count += 1 + + # 确定返回类型 + # 多输出(如 vrandom rdrand*_step 的 val+ok 两个 AsmOut)返回 + # 匿名 struct {ty1, ty2, ...},元素数 = 输出操作数(LLVM asm + # 要求输出约束数 = 返回 struct 元素数)。 + ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + if output_count > 0 and first_output_idx >= 0: + if output_count > 1: + out_pn_head: llvmlite.ParamNode | t.CPtr = None + out_pn_last: llvmlite.ParamNode | t.CPtr = None + out_pn_n: int = 0 + for oi5 in range(operand_count): + op5: GenTypes.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi5) + if op5 is None or op5.IsOutput == 0: + continue + if op5.Value is not None and op5.Value.Ty is not None \ + and op5.Value.Ty.Pointee is not None: + pn5: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node( + pool, op5.Value.Ty.Pointee) + if pn5 is not None: + if out_pn_head is None: + out_pn_head = pn5 + else: + out_pn_last.Next = pn5 + out_pn_last = pn5 + out_pn_n += 1 + if out_pn_head is not None and out_pn_n > 0: + ret_ty = llvmlite.Struct(pool, out_pn_head, out_pn_n, None) + else: + self.Gen.TypeGenErr.fatal_error( + cl, "c.Asm 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError") + ret_ty = llvmlite.Int32(pool) + else: + out_op: GenTypes.AsmOperand | t.CPtr = self._asm_get_operand(operands, first_output_idx) + if out_op.Value is not None and out_op.Value.Ty is not None: + # alloca 的类型是指针,Pointee 是目标类型 + if out_op.Value.Ty.Pointee is not None: + ret_ty = out_op.Value.Ty.Pointee + else: + self.Gen.TypeGenErr.fatal_error( + cl, "c.Asm 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError") + ret_ty = llvmlite.Int32(pool) + + # 判断 void — 直接基于 output_count 判断,避免 match 类型匹配问题 + is_void: int = 1 + if output_count > 0: + is_void = 0 + + # ============================================================ + # 4.5 重排操作数:输出在前,输入在后(LLVM IR 要求) + # + # new_order[new_idx] = orig_idx — 新位置对应原索引 + # orig_to_new[orig_idx] = new_idx — 原索引映射到新位置(用于占位符编号) + # ============================================================ + new_order: int | t.CPtr = pool.alloc(4 * (operand_count + 1)) + orig_to_new: int | t.CPtr = pool.alloc(4 * (operand_count + 1)) + if new_order is None or orig_to_new is None: + return None + + new_idx: int = 0 + # 先放输出 + for oi3 in range(operand_count): + op3: GenTypes.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi3) + if op3.IsOutput != 0: + new_order[new_idx] = oi3 + new_idx += 1 + # 再放输入 + for oi4 in range(operand_count): + op4: GenTypes.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi4) + if op4.IsOutput == 0: + new_order[new_idx] = oi4 + new_idx += 1 + # 建立映射 orig -> new + for ni2 in range(operand_count): + orig_to_new[new_order[ni2]] = ni2 + + # ============================================================ + # 4.6 生成汇编文本(第二遍遍历 f-string,用重排后的索引生成占位符) + # 项目约定使用 Intel 语法,通过 IR 的 inteldialect 关键字启用 + # ============================================================ + if tmpl_node is not None: + tk2: int = tmpl_node.kind() + if tk2 == ast.ASTKind.JoinedStr: + js2: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(tmpl_node) + jvalues2: list[ast.AST | t.CPtr] | t.CPtr = js2.values + if jvalues2 is not None: + jvlen2: t.CSizeT = len(jvalues2) + fv_fi: int = 0 + for vi2 in range(jvlen2): + part2: ast.AST | t.CPtr = jvalues2.get(vi2) + if part2 is None: + continue + pk2: int = part2.kind() + if pk2 == ast.ASTKind.Constant: + cn3: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part2) + if cn3.const_kind == ast.CONST_STR and cn3.str_val is not None: + self._asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, cn3.str_val) + elif pk2 == ast.ASTKind.FormattedValue: + if fv_fi < fv_count: + orig_idx2: int = fv_orig_indices[fv_fi] + new_idx2: int = orig_to_new[orig_idx2] + ph_buf2: str = pool.alloc(16) + if ph_buf2 is not None: + viperlib.snprintf(ph_buf2, 16, "$%d", new_idx2) + self._asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, ph_buf2) + fv_fi += 1 + elif tk2 == ast.ASTKind.Constant: + cn4: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(tmpl_node) + if cn4.const_kind == ast.CONST_STR and cn4.str_val is not None: + self._asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, cn4.str_val) + + # ============================================================ + # 5. 构建约束字符串(按重排后的顺序:输出在前,输入在后) + # ============================================================ + const_buf: str = pool.alloc(ASM_CONST_BUF_SIZE) + if const_buf is None: + return None + const_buf[0] = '\0' + + first_const: int = 1 + for ci2 in range(operand_count): + orig_i: int = new_order[ci2] + cop: GenTypes.AsmOperand | t.CPtr = self._asm_get_operand(operands, orig_i) + cons_val: str = cop.Constraint + if cons_val is None: + cons_val = "r" + + if first_const == 0: + self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",") + first_const = 0 + + if cop.IsOutput != 0: + # 输出约束:确保以 = 开头 + if cons_val[0] != '=': + self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "=") + self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cons_val) + else: + self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cons_val) + + # 追加 clobber 约束 ~{name} + for cidx in range(clobber_count): + cl_addr2: t.CUInt64T = t.CUInt64T(clobbers) + cidx * 8 + cname: str = (str | t.CPtr)(t.CVoid(cl_addr2, t.CPtr))[0] + if cname is None or cname[0] == '\0': + continue + if first_const == 0: + self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",") + first_const = 0 + self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "~{") + self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cname) + self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "}") + + # ============================================================ + # 6. 构建参数列表文本(仅输入操作数) + # ============================================================ + args_buf: str = pool.alloc(ASM_ARGS_BUF_SIZE) + if args_buf is None: + return None + args_buf[0] = '\0' + + first_arg: int = 1 + for ai3 in range(operand_count): + orig_i2: int = new_order[ai3] + aop: GenTypes.AsmOperand | t.CPtr = self._asm_get_operand(operands, orig_i2) + if aop.IsOutput != 0: + continue + aval: llvmlite.Value | t.CPtr = aop.Value + if aval is None or aval.Ty is None or aval.Name is None: + continue + + if first_arg == 0: + self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ", ") + first_arg = 0 + + # 类型文本 + ty_buf: str = pool.alloc(64) + if ty_buf is not None: + ty_buf[0] = '\0' + llvmlite.TypePrint(ty_buf, 64, aval.Ty, pool) + self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ty_buf) + self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, " ") + self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, aval.Name) + + # ============================================================ + # 7. 转义汇编文本 + # ============================================================ + escaped_asm: str = self._asm_escape_for_ir(pool, asm_text) + if escaped_asm is None: + return None + + # ============================================================ + # 8. 生成 IR 行并发射 + # ============================================================ + line: str = pool.alloc(ASM_LINE_BUF_SIZE) + if line is None: + return None + line[0] = '\0' + + ssa_name: str = None + if is_void == 0: + ssa_name = pool.alloc(16) + if ssa_name is not None: + viperlib.snprintf(ssa_name, 16, "%%%d", builder.Counter) + builder.Counter += 1 + + # 获取返回类型文本 + ret_ty_buf: str = pool.alloc(64) + if ret_ty_buf is not None: + ret_ty_buf[0] = '\0' + llvmlite.TypePrint(ret_ty_buf, 64, ret_ty, pool) + + if is_void == 1: + viperlib.snprintf(line, ASM_LINE_BUF_SIZE, + "call %s asm sideeffect inteldialect \"%s\", \"%s\"(%s)", + ret_ty_buf, escaped_asm, const_buf, args_buf) + else: + viperlib.snprintf(line, ASM_LINE_BUF_SIZE, + "%s = call %s asm sideeffect inteldialect \"%s\", \"%s\"(%s)", + ssa_name, ret_ty_buf, escaped_asm, const_buf, args_buf) + + # 发射 IR 到当前块 + llvmlite.block_append_text(pool, builder.CurBlock, line) + + # ============================================================ + # 9. 处理输出:存储结果到输出变量 + # ============================================================ + if is_void == 0 and first_output_idx >= 0: + result_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, ret_ty, ssa_name) + out_emit_idx: int = 0 + for oi_out in range(operand_count): + orig_o: int = new_order[oi_out] + oo: GenTypes.AsmOperand | t.CPtr = self._asm_get_operand(operands, orig_o) + if oo is None or oo.IsOutput == 0: + continue + if output_count > 1: + # 多输出:extractvalue 取第 out_emit_idx 个元素后 store + if oo.Value is not None and oo.Value.Ty is not None \ + and oo.Value.Ty.Pointee is not None: + ev_name: str = pool.alloc(32) + ev_line: str = pool.alloc(ASM_LINE_BUF_SIZE) + if ev_name is not None and ev_line is not None: + # ssa_name 形如 "%N"(纯数字 ID),构造唯一名 + # "%asm.N.e{i}"(字母开头,避免 %N.e{i} 被解析为 + # 数字 ID + 非法后缀导致 "expected '=' after id") + viperlib.snprintf(ev_name, 32, "%%asm.%s.e%d", ssa_name + 1, out_emit_idx) + viperlib.snprintf(ev_line, ASM_LINE_BUF_SIZE, + "%s = extractvalue %s %s, %d", + ev_name, ret_ty_buf, ssa_name, out_emit_idx) + llvmlite.block_append_text(pool, builder.CurBlock, ev_line) + ev_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, oo.Value.Ty.Pointee, ev_name) + llvmlite.build_store(builder, ev_val, oo.Value) + else: + if oo.Value is not None: + llvmlite.build_store(builder, result_val, oo.Value) + out_emit_idx += 1 + return result_val + + return None + + + def translate_c_llvmir(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """c.LLVMIR 内联 LLVM IR:无返回值,直接嵌入原始 IR 文本 + + 不做指令解析,模板文本(c.LInp/c.LOut 替换后)用 block_append_text + 嵌入当前基本块。c.LOut 变量由唯一 SSA 寄存器 %llvmirN 接收结果, + 嵌入后自动追加 store 写回变量 alloca。返回 None(无返回值)。 + """ + if cl is None or builder is None or pool is None or trans is None: + return None + + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or len(cargs) < 1: + self.Gen.TypeGenErr.fatal_error(cl, "c.LLVMIR 缺少模板参数", "TypeError") + + # LOut 写回记录(alloca 指针 + 寄存器名),最多 LLVMIR_MAX_OPS 个 + out_alloca: t.CSizeT | t.CPtr = pool.alloc(8 * LLVMIR_MAX_OPS) + out_regname: t.CSizeT | t.CPtr = pool.alloc(8 * LLVMIR_MAX_OPS) + if out_alloca is None or out_regname is None: + return None + string.memset(out_alloca, 0, 8 * LLVMIR_MAX_OPS) + string.memset(out_regname, 0, 8 * LLVMIR_MAX_OPS) + out_count: int = 0 + + # 模板文本缓冲区 + text: str = pool.alloc(LLVMIR_TEMPLATE_BUF) + if text is None: + return None + text[0] = '\0' + + # ============================================================ + # 1. 解析 IR 模板(JoinedStr 或 Constant)— 替换 LInp/LOut/表达式为值文本 + # ============================================================ + first_arg: ast.AST | t.CPtr = cargs.get(0) + if first_arg is None: + return None + + tk: int = first_arg.kind() + + if tk == ast.ASTKind.JoinedStr: + js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(first_arg) + jvalues: list[ast.AST | t.CPtr] | t.CPtr = js.values + if jvalues is not None: + jvlen: t.CSizeT = len(jvalues) + for vi in range(jvlen): + part: ast.AST | t.CPtr = jvalues.get(vi) + if part is None: + continue + pk: int = part.kind() + + if pk == ast.ASTKind.Constant: + # 字符串字面量片段 + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part) + if cn.str_val is not None: + self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, cn.str_val) + + elif pk == ast.ASTKind.FormattedValue: + fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part) + fexpr: ast.AST | t.CPtr = fv.value + if fexpr is None: + continue + # 检测 c.LInp / c.LOut + if fexpr.kind() == ast.ASTKind.Call: + fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr) + attr_nm: str = self._asm_is_c_call(fcall) + if attr_nm is not None: + fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args + if fargs is None or len(fargs) < 1: + continue + val_node: ast.AST | t.CPtr = fargs.get(0) + + if string.strcmp(attr_nm, "LInp") == 0: + # 输入操作数:翻译值,替换为 LLVM 值引用文本(%x 或常量文本) + inp_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, val_node, None, 0, trans) + if inp_val is not None and inp_val.Name is not None: + self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, inp_val.Name) + + elif string.strcmp(attr_nm, "LOut") == 0: + # 输出操作数:为变量分配唯一 SSA 寄存器 %llvmirN, + # 记录写回(模板嵌入后 store 到变量 alloca) + if val_node is not None and val_node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node) + if nm.id is not None: + alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, nm.id) + if alloca is None or out_count >= LLVMIR_MAX_OPS: + self.Gen.TypeGenErr.fatal_error( + fcall, + f"c.LOut 变量 '{nm.id}' 未定义或输出数超过 {LLVMIR_MAX_OPS}", + "TypeError") + self.Gen.CallGenBase.LLVMIRRegSeq += 1 + reg_buf: str = pool.alloc(32) + if reg_buf is not None: + viperlib.snprintf(reg_buf, 32, "%%llvmir_%d", self.Gen.CallGenBase.LLVMIRRegSeq) + self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, reg_buf) + out_alloca[out_count] = t.CSizeT(alloca) + out_regname[out_count] = t.CSizeT(reg_buf) + out_count += 1 + continue + # 非 c.LInp/c.LOut 的 f-string 表达式:翻译值并嵌入值文本 + ival: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, fexpr, None, 0, trans) + if ival is not None and ival.Name is not None: + self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, ival.Name) + + elif tk == ast.ASTKind.Constant: + cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(first_arg) + if cn2.str_val is not None: + # 裸 strcpy 无界:模板常量串 ≥ LLVMIR_TEMPLATE_BUF 会越界写 pool 块, + # 改用与 JoinedStr 分支一致的有界追加 + self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, cn2.str_val) + + # ============================================================ + # 2. 直接嵌入模板文本(不做指令解析)+ LOut 写回 + # ============================================================ + llvmlite.block_append_text(pool, builder.CurBlock, text) + + # LOut 写回: store %llvmirN, * %var + oi: int + for oi in range(out_count): + oa: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)(t.CVoid(out_alloca[oi], t.CPtr)) + rn: str = (str)(t.CVoid(out_regname[oi], t.CPtr)) + if oa is None or oa.Ty is None or oa.Ty.Pointee is None or rn is None: + continue + reg_val: llvmlite.Value | t.CPtr = llvmlite.new_value(pool) + if reg_val is None: + continue + reg_val.Ty = oa.Ty.Pointee + reg_val.Name = rn + reg_val.IsConst = 0 + llvmlite.build_store(builder, reg_val, oa) + + return None + + # ============================================================ + # _apply_struct_defaults — 应用结构体字段的默认值 + # + # 在 zeroinitializer 之后、显式参数之前调用 + # 遍历所有字段,对有默认值的字段翻译并 store + # 显式参数(位置/关键字)后续会覆盖默认值 + # ============================================================ diff --git a/App/lib/core/Gen/CallGenCall.vp b/App/lib/core/Gen/CallGenCall.vp index ac7ba9d..448c899 100644 --- a/App/lib/core/Gen/CallGenCall.vp +++ b/App/lib/core/Gen/CallGenCall.vp @@ -1,1576 +1,1567 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import sys -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesFunctions as HandlesFunctions -import lib.core.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.CompilerFactory as CompilerFactory - - -import lib.core.Gen.CallGenBase as CallGenBase -import lib.core.Handles.ExprCallCall as ExprCallCall -import lib.core.Handles.ExprCallHandle as ExprCallHandle -import lib.core.Handles.ExprCallTable as ExprCallTable - -# ============================================================ -# CallGenCall - CallGenMixin 拆分(阶段 B):方法调用分派(含 super / 虚调用 / kwargs 名匹配) -# -# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class CallGenCall(CallGenBase.CallGenBase): - """方法调用分派(含 super / 虚调用 / kwargs 名匹配)""" - - # ============================================================ - # _do_virtual_call — 通过虚表间接调用虚方法 - # - # IR 模式: - # %1 = getelementptr StructTy, StructTy* %self, i32 0, i32 0 ; i8** - # %2 = load i8*, i8** %1 ; i8* (vtable ptr) - # %3 = bitcast i8* %2 to {i8*, ...}* ; vtable typed ptr - # %4 = getelementptr {i8*, ...}, {i8*, ...}* %3, i32 0, i32 N ; i8** - # %5 = load i8*, i8** %4 ; i8* (func ptr) - # %6 = bitcast i8* %5 to RetTy(Params)* ; func typed ptr - # call RetTy %6(Params %self, ...) - # - # 参数: - # args_head — 已构建好的参数链表头(self_ptr 为首节点) - # args_count — 参数总数(含 self) - # found_func — 方法对应的 Function 对象(用于推断函数签名) - # ret_ty — 返回类型 - # ============================================================ - - # ============================================================ - def _do_virtual_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, - method_name: str, - self_ptr: llvmlite.Value | t.CPtr, - args_head: llvmlite.Value | t.CPtr, - args_count: int, - found_func: llvmlite.Function | t.CPtr, - ret_ty: llvmlite.LLVMType | t.CPtr, - vtable_base: llvmlite.Value | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """通过虚表间接调用虚方法,返回 call 结果(void 方法返回 None) - - vtable_base: 对象头指针(vtable 所在位置,即未调整的 obj_ptr)。 - 多继承 this 调整后 self_ptr 可能前移(如 obj+4 指向父类字段区), - 从调整后位置读 vtable 会读到字段值 → 垃圾指针崩溃。默认 None 时 - vtable_base = self_ptr(未调整场景,读对象头)。 - """ - if pool is None or builder is None or class_name is None or method_name is None: - return None - if self_ptr is None or args_head is None: - return None - if vtable_base is None: - vtable_base = self_ptr - - # 1. 获取结构体类型(用 find_struct_by_type 规避跨模块同名 find_struct 找错) - vc_entry: HandlesStruct.StructEntry | t.CPtr = None - struct_ty: llvmlite.LLVMType | t.CPtr = None - if self_ptr.Ty is not None: - vc_entry = HandlesStruct.get_struct_type_from_value(self_ptr) - if vc_entry is not None: - # vc_entry 是 struct_ty(LLVMType),需要找 StructEntry - vc_entry = HandlesStruct.find_struct_by_type(vc_entry) - if vc_entry is not None: - struct_ty = vc_entry.Ty - if struct_ty is None: - struct_ty = HandlesStruct.get_struct_type(class_name) - if struct_ty is None: - return None - - # 2. 获取方法在虚表中的索引(用 entry 直接查找) - method_index: int = -1 - if vc_entry is not None and vc_entry.VTableMethods is not None: - methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(vc_entry.VTableMethods, t.CPtr)) - for mi in range(vc_entry.VTableMethodCount): - mname_addr: t.CSizeT = methods_arr[mi] - if mname_addr == 0: - continue - mname: str = (str | t.CPtr)(t.CVoid(mname_addr, t.CPtr)) - if mname is not None and string.strcmp(mname, method_name) == 0: - method_index = mi - break - else: - method_index = HandlesStruct.get_vtable_method_index(class_name, method_name) - if method_index < 0: - return None - - # 3. 基础类型 - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty) - - # 4. bitcast 到 i8** 访问 __vtable__ 字段(索引 0) - # vtable 指针总是在对象第一个字段,无需 GEP,直接 bitcast 到 i8** 即可。 - # 这样即使 struct_ty 是 opaque(跨模块未加载完整定义)也能正常工作。 - # 注意用 vtable_base(对象头)而非 self_ptr:多继承 this 调整后 - # self_ptr 已前移,其头部不是 vtable 而是父类字段值。 - vtable_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, vtable_base, i8_ptr_ptr_ty) - if vtable_slot is None: - return None - - # 5. load vtable 指针 (i8*) - vtable_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, vtable_slot) - if vtable_ptr is None: - return None - - # 6. 构造 vtable 类型 {i8*, i8*, ...} - method_count: int = 0 - if vc_entry is not None: - method_count = vc_entry.VTableMethodCount - else: - method_count = HandlesStruct.get_vtable_method_count(class_name) - if method_count <= 0: - return None - - vt_first: llvmlite.ParamNode | t.CPtr = None - vt_prev: llvmlite.ParamNode | t.CPtr = None - for vi in range(method_count): - pn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) - if pn is None: - continue - if vt_first is None: - vt_first = pn - if vt_prev is not None: - llvmlite.paramnode_set_next(vt_prev, pn) - vt_prev = pn - - vtable_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, vt_first, method_count, None) - if vtable_ty is None: - return None - vtable_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, vtable_ty) - - # 7. bitcast i8* 到 vtable 类型指针 - vtable_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, vtable_ptr, vtable_ptr_ty) - if vtable_typed is None: - return None - - # 8. GEP 到方法槽位 - func_slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, vtable_ty, i8_ptr_ty, vtable_typed, method_index) - if func_slot is None: - return None - - # 9. load 函数指针 (i8*) - func_i8: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, func_slot) - if func_i8 is None: - return None - - # 10. 从 args_head 构造函数类型 RetTy(Param1, Param2, ...) - # 直接遍历 Value 链表提取参数类型,避免跨模块访问 found_func(stub 字段偏移问题) - fp_first: llvmlite.ParamNode | t.CPtr = None - fp_prev: llvmlite.ParamNode | t.CPtr = None - fp_count: int = 0 - cur_val: llvmlite.Value | t.CPtr = args_head - for vi in range(args_count): - if cur_val is None: - break - cur_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(cur_val) - fpn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, cur_ty) - if fpn is not None: - if fp_first is None: - fp_first = fpn - if fp_prev is not None: - llvmlite.paramnode_set_next(fp_prev, fpn) - fp_prev = fpn - cur_val = llvmlite.value_get_next(cur_val) - fp_count += 1 - - func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, ret_ty, fp_first, fp_count) - if func_ty is None: - return None - func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty) - - # 11. bitcast i8* 到函数指针类型 - func_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, func_i8, func_ptr_ty) - if func_ptr is None: - return None - - # 12. 间接调用 - return llvmlite.build_call_indirect(builder, func_ptr, args_head, args_count, ret_ty) - # ============================================================ - # _call_method_on_ptr — 在结构体指针上调用方法 - # - # 辅助函数:构造 ClassName.method_name 调用,self 指针为首个参数 - # 如果该方法在虚表中,则走虚方法分发路径(间接调用) - # ============================================================ - - # ============================================================ - def _call_method_on_ptr(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, - method_name: str, - self_ptr: llvmlite.Value | t.CPtr, - extra_args: t.CSizeT | t.CPtr, - extra_count: int, - trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """在结构体指针上调用方法,返回 call 结果(void 方法返回 None) - - node: 触发本次调用的 AST 节点(如 Subscript 下标节点),用于 fatal_error - 准确报告出错行号(传 None 时行号显示 0,不利于定位)。""" - if pool is None or builder is None or class_name is None or method_name is None: - return None - if self_ptr is None: - return None - - # 提前获取结构体 entry(用 find_struct_by_type 规避跨模块同名 find_struct 找错) - # 用于 SHA1 查找和虚表分派 - cmop_entry: HandlesStruct.StructEntry | t.CPtr = None - cmop_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(self_ptr) - if cmop_struct_ty is not None: - cmop_entry = HandlesStruct.find_struct_by_type(cmop_struct_ty) - if cmop_entry is None: - cmop_entry = HandlesStruct.find_struct(class_name) - # fallback: 若 cmop_struct_ty 为 None 但 entry 存在,从 entry 获取类型 - # 用于跨模块调用时 self_ptr 类型信息丢失的情况 - if cmop_struct_ty is None and cmop_entry is not None: - cmop_struct_ty = cmop_entry.Ty - - # 构造方法查找名: ClassName.method_name - lookup_name: str = pool.alloc(128) - if lookup_name is None: - return None - viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name) - - # 查找函数(支持 SHA1 后缀匹配) - found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, lookup_name) - - # 确定调用名 - call_name: str = lookup_name - if found_func is not None: - found_name: str = llvmlite.function_get_name(found_func) - if found_name is not None: - call_name = found_name - else: - # found_func 为 None(stub 未注入):用类所属模块的 SHA1 构造调用名 - # 优先从 entry 获取 SHA1(规避跨模块同名 find_struct 找错) - cls_sha1: str = None - if cmop_entry is not None: - cls_sha1 = cmop_entry.ModuleSha1 - else: - cls_sha1 = HandlesStruct.get_struct_sha1(class_name) - if cls_sha1 is None and trans is not None: - # fallback: 从 from_imports 查找类所属模块的 SHA1(含截断处理) - cls_sha1 = self._lookup_mod_sha1(pool, trans._from_imports, class_name) - if cls_sha1 is None: - err_msg: str = pool.alloc(256) - if err_msg is not None: - viperlib.snprintf(err_msg, 256, "类 '%s' 方法 '%s' 找不到模块 SHA1", class_name, method_name) - HandlesType.fatal_error(node, err_msg) - HandlesType.fatal_error(node, "找不到模块 SHA1") - mangled_len2: t.CSizeT = string.strlen(cls_sha1) + string.strlen(lookup_name) + 2 - mangled2: str = pool.alloc(mangled_len2) - if mangled2 is not None: - viperlib.snprintf(mangled2, mangled_len2, "%s.%s", cls_sha1, lookup_name) - call_name = mangled2 - - # 确定返回类型(__before_init__ 和 __init__ 返回 void) - void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) - call_ret_ty: llvmlite.LLVMType | t.CPtr = void_ty - if found_func is not None: - frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) - if frt is not None: - call_ret_ty = frt - elif string.strcmp(method_name, "__getitem__") == 0 or string.strcmp(method_name, "__new__") == 0: - # fail-fast:__getitem__/__new__ 必返回指针,返回类型缺失意味着 - # stub declare 损坏,静默推断会截断指针(32 位)崩溃,立即终止。 - err_cm1: str = pool.alloc(256) - if err_cm1 is not None: - viperlib.snprintf(err_cm1, 256, - "方法 '%s' 返回类型无法确定(stub declare 返回类型缺失)", method_name) - HandlesType.fatal_error(node, err_cm1) - HandlesType.fatal_error(node, "方法返回类型无法确定") - else: - # found_func 为 None(跨模块调用 stub 未注入):无法从 declare 获取返回类型。 - # __before_init__/__init__ 是编译器生成/约定方法(vpi stub 无条目): - # 恒返回 void(对齐 _special_method_ret_ty L3196-3198),直接固定, - # 否则走 text.ll/vpi 解析失败 → fail-fast 误报 - # (CPythonTest PyLongObj() 构造:类未定义 __init__/__before_init__ - # 但实例化仍生成调用 → "PyLongObj.__before_init__ 返回类型无法确定"根因)。 - if string.strcmp(method_name, "__before_init__") == 0 or \ - string.strcmp(method_name, "__init__") == 0: - call_ret_ty = void_ty - # __new__ 返回 Ptr(struct_ty)(构造函数返回自身指针,可推断)。 - # __getitem__ 返回类型无法从 self 推断(可返回 i8* 如 HashTable.__getitem__ - # -> t.CPtr,或 Ptr(JsonValue) 如 JsonValue.__getitem__)——推断 Ptr(cmop_struct_ty) - # 会与 define 返回类型不匹配,调用侧按错误类型读取返回值导致指针截断崩溃。 - # fail-fast:__getitem__ 无 stub declare 立即报错,暴露依赖模块 vpi 缺失或 - # 拓扑顺序错误(依赖模块未先翻译生成 vpi/text.ll)。 - elif string.strcmp(method_name, "__new__") == 0: - if cmop_struct_ty is not None: - call_ret_ty = llvmlite.Ptr(pool, cmop_struct_ty) - else: - err_cm2: str = pool.alloc(256) - if err_cm2 is not None: - viperlib.snprintf(err_cm2, 256, - "方法 '%s' 的 self 结构体类型未知(字段类型退化,依赖模块未预注册?)", method_name) - HandlesType.fatal_error(node, err_cm2) - HandlesType.fatal_error(node, "self 结构体类型未知") - elif string.strcmp(method_name, "__getitem__") == 0: - err_cm3: str = pool.alloc(256) - if err_cm3 is not None: - viperlib.snprintf(err_cm3, 256, - "方法 '%s.__getitem__' 的 stub declare 未注入(依赖模块 vpi 缺失或拓扑顺序错误),无法确定返回类型", - class_name) - HandlesType.fatal_error(node, err_cm3) - HandlesType.fatal_error(node, "__getitem__ stub declare 未注入") - else: - # 其它跨模块方法(泛型特化方法必然无 stub declare):旧实现静默 - # 保持 void → 幽灵 "call void @...__add__" + 调用方(如运算符 - # 重载 try_operator_overload)回退原生运算双重发射 → llc invalid - # operand type for instruction(NumpyTest a+b 根因)。用 text.ll - # → vpi 精确解析返回类型(对齐 _translate_method_call L4641); - # 都失败则 fail-fast,绝不静默 void。 - ret_cm: llvmlite.LLVMType | t.CPtr = None - if cls_sha1 is not None: - ret_cm = self._LookupMethodRetTyFromTextLL( - pool, cls_sha1, class_name, method_name) - if ret_cm is None and cls_sha1 is not None: - ret_cm = self._lookup_method_ret_ty_via_vpi( - pool, cls_sha1, class_name, method_name) - if ret_cm is not None: - call_ret_ty = ret_cm - else: - # Phase A 依赖 text.ll 未生成(方法定义模块尚未翻译)→ 标记重试, - # 保持默认类型继续(对齐 _translate_method_call L4760-4773 与跨模块 - # 函数路径 L8167-8195 的 _deps_pending 机制;本函数同样服务 Mixin - # 跨模块方法调用,如 BuildPipeline gen.extract_module_docstrings) - # cls_sha1 为 None 同样视为依赖未就绪(pass1 定义类/祖先未注册 - # 连 sha1 都取不到,对齐 _translate_method_call L4778-4785) - if cls_sha1 is None \ - or (cls_sha1 is not None - and self._dep_text_ll_exists(pool, cls_sha1) == 0): - if trans is not None: - trans._deps_pending = 1 - # 依赖未就绪:保持默认 i32(build_call(Void) 返回 None 会 - # 破坏表达式翻译;pending 文件本遍不写盘,下遍重译) - call_ret_ty = llvmlite.Int32(pool) - else: - err_cm4: str = pool.alloc(256) - if err_cm4 is not None: - viperlib.snprintf(err_cm4, 256, - "方法 '%s.%s' 返回类型无法确定(text.ll/vpi 均未命中,跨模块 stub 未注入)", - class_name, method_name) - HandlesType.fatal_error(node, err_cm4) - HandlesType.fatal_error(node, "方法返回类型无法确定") - - # 构建参数链表: self_ptr → extra_args... - llvmlite.value_set_next(self_ptr, None) - head: llvmlite.Value | t.CPtr = self_ptr - tail: llvmlite.Value | t.CPtr = self_ptr - - if extra_args is not None and extra_count > 0: - for ei in range(extra_count): - arg_addr: t.CSizeT = extra_args[ei] - if arg_addr == 0: - continue - av: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)(t.CVoid(arg_addr, t.CPtr)) - if av is not None: - llvmlite.value_set_next(av, None) - llvmlite.value_set_next(tail, av) - tail = av - - total_count: int = 1 + extra_count - - # 默认参数填充:如果调用点参数少于函数定义参数,用默认值填充缺失参数 - # 优先用函数定义的默认值,无默认值时用零值兜底 - # 查找函数的 defaults 信息 - mdf_defaults: t.CVoid | t.CPtr = None - mdf_default_count: int = 0 - mdf_param_count: int = 0 - if trans is not None and trans._funcs is not None: - mdf_entry: FuncEntry | t.CPtr = ExprCallTable.find_func_entry_in_table( - trans._funcs, trans._func_count, lookup_name) - if mdf_entry is not None: - mdf_defaults = mdf_entry.Defaults - mdf_default_count = mdf_entry.DefaultCount - mdf_param_count = mdf_entry.ParamCount - # 全局默认参数表查询无条件执行:mdf_entry 命中时(泛型特化方法注册进 - # 调用方函数表)Defaults 非 None 会短路跳过,但下方"用快照重建默认值" - # 分支依赖 mdf_gd(唯一持有 stdlib 常量快照处)——缺它必 fatal_error - # (ListTest list[int].__new__ 根因) - mdf_gd: FuncDefaultsEntry | t.CPtr = ExprCallTable.find_func_defaults(lookup_name) - if mdf_defaults is None and mdf_gd is not None: - mdf_defaults = mdf_gd.Defaults - mdf_default_count = mdf_gd.DefaultCount - mdf_param_count = mdf_gd.ParamCount - - # 计算需要填充的参数(不含 self) - # extra_count = 已提供的非 self 参数数量 - # mdf_param_count = 函数定义的非 self 参数数量 - if mdf_param_count > extra_count: - mdf_offset: int = mdf_param_count - mdf_default_count - mdf_pi: int = extra_count - while mdf_pi < mdf_param_count: - # 优先用默认值 - if mdf_defaults is not None and mdf_default_count > 0 and mdf_pi >= mdf_offset: - mdf_di: int = mdf_pi - mdf_offset - if mdf_di < mdf_default_count: - # 用 stdlib 常量快照重建(mdf_gd.Defaults 的 pool 内 AST 可能已被 reset 回收, - # 直接回退读 AST 会 use-after-free——快照失败时 fail-fast 暴露,绝不读悬空 AST) - mdf_val: llvmlite.Value | t.CPtr = None - if mdf_gd is not None: - mdf_val = ExprCallTable._build_const_from_snapshot( - pool, mod, mdf_gd, mdf_di, trans, builder) - if mdf_val is None: - # 用 node(本函数报错行号节点,如构造实参/源码 Call)而非 cl—— - # cl 在本函数未定义(无该参数),读取垃圾指针导致 fatal_error - # 显示 "line 0"(FileIoTest File.__init__ 报错行号丢失根因) - HandlesType.fatal_error( - node, - f"跨模块默认参数无法重建(快照缺失,默认值需为简单常量): {lookup_name}", - "TypeError") - continue - llvmlite.value_set_next(mdf_val, None) - llvmlite.value_set_next(tail, mdf_val) - tail = mdf_val - total_count += 1 - mdf_pi += 1 - continue - # 无默认值时用零值兜底(需要 found_func 获取参数类型)。 - # 默认参数表按裸名注册(如 "__init__"),跨模块 "ClassName.method" - # 查找常查不到——查不到 ≠ 无默认值(如 Buf.__init__(data, capacity) - # 缺的 length=0/owned=False 恰为零值),零值兜底语义一致。 - if found_func is not None: - param_node_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) - skip_z: int = 0 - while skip_z <= mdf_pi and param_node_z is not None: - param_node_z = llvmlite.param_get_next(param_node_z) - skip_z += 1 - if param_node_z is not None: - zero_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node_z) - zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, zero_ty) - if zero_val is not None: - llvmlite.value_set_next(zero_val, None) - llvmlite.value_set_next(tail, zero_val) - tail = zero_val - total_count += 1 - mdf_pi += 1 - elif found_func is not None: - # 无默认参数信息但有 found_func:用零值兜底填充缺失参数 - # (原逻辑;禁止 fail-fast 误杀——同上,查不到默认参数表 ≠ 无默认值) - param_node: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) - skip_idx: int = 0 - while skip_idx < total_count and param_node is not None: - param_node = llvmlite.param_get_next(param_node) - skip_idx += 1 - while param_node is not None: - missing_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node) - zero_val2: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, missing_ty) - if zero_val2 is not None: - llvmlite.value_set_next(zero_val2, None) - llvmlite.value_set_next(tail, zero_val2) - tail = zero_val2 - total_count += 1 - param_node = llvmlite.param_get_next(param_node) - - # 参数类型强制转换:按 found_func 的形参类型 coerce 每个实参(含 self)。 - # 修复: 构造器调用 __init__(ptr, base, 4096) 时 size 形参是 i64 (t.CSizeT), - # 但 4096 字面量按 i32 传递,未提升导致运行时 size 高 32 位垃圾, - # 破坏伙伴分配器的池大小元数据(如 total=2048)引发 calloc 失败/OOM。 - # self 在运算符重载路径 2(lhs 为 X|t.CPtr 联合简化的 Vec3** 对象指针)时 - # 与形参 Vec3* 不匹配,需 bitcast(coerce 指针→指针生成 bitcast), - # 否则 call 参数类型与声明不一致 llc 报错。 - if found_func is not None and head is not None: - pc_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) - pc_node: llvmlite.Value | t.CPtr = head - new_head_pc: llvmlite.Value | t.CPtr = head - prev_pc: llvmlite.Value | t.CPtr = None - while pc_node is not None: - pc_next_save: llvmlite.Value | t.CPtr = pc_node.Next - coerced_pc: llvmlite.Value | t.CPtr = pc_node - if pc_param is not None: - pty_pc: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pc_param) - if pty_pc is not None: - c_pc: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( - builder, pc_node, pty_pc, None) - if c_pc is not None: - coerced_pc = c_pc - pc_param = llvmlite.param_get_next(pc_param) - coerced_pc.Next = None - if prev_pc is None: - new_head_pc = coerced_pc - else: - prev_pc.Next = coerced_pc - prev_pc = coerced_pc - pc_node = pc_next_save - head = new_head_pc - - # 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用 - # 复用前面已获取的 cmop_entry(find_struct_by_type 规避跨模块同名找错) - if found_func is not None: - cmop_has_vt: int = 0 - cmop_method_idx: int = -1 - if cmop_entry is not None: - cmop_has_vt = cmop_entry.HasVTable - if cmop_has_vt == 1 and cmop_entry.VTableMethods is not None: - cmop_methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(cmop_entry.VTableMethods, t.CPtr)) - for cmop_mi in range(cmop_entry.VTableMethodCount): - cmop_mname_addr: t.CSizeT = cmop_methods_arr[cmop_mi] - if cmop_mname_addr == 0: - continue - cmop_mname: str = (str | t.CPtr)(t.CVoid(cmop_mname_addr, t.CPtr)) - if cmop_mname is not None and string.strcmp(cmop_mname, method_name) == 0: - cmop_method_idx = cmop_mi - break - if cmop_has_vt == 1 and cmop_method_idx >= 0: - return self._do_virtual_call(pool, builder, mod, class_name, method_name, - self_ptr, head, total_count, found_func, call_ret_ty) - # 防御:返回类型为 i0(0 位整数)时 fail-fast,绝不输出非法 IR。 - # 根因已修(gen_done 成功后不再读未初始化的 looked_up_ty,见 L3970); - # 此兜底防止未来任何路径产出零值 LLVMType 导致 llc - # "bitwidth for integer type out of range"。 - if call_ret_ty is not None: - cd_i0: int = 0 - match call_ret_ty: - case llvmlite.LLVMType.Int(bits): - if bits == 0: - cd_i0 = 1 - case _: - pass - if cd_i0 != 0: - call_ret_ty = self._fail_method_ret_ty(method_name, node) - # 跨模块调用(found_func 为 None):创建 declare 声明,避免 llc 报 undefined value - if found_func is None: - self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, total_count) - - return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, 0) - # ============================================================ - # _translate_method_call - 翻译方法调用 obj.method(args) - # - # 生成: call @SHA1.ClassName.method_name(Ptr(StructTy) %obj, args...) - # - # obj_ptr 是对象变量的 alloca(Ptr(StructTy)),作为 self 参数传入 - # ============================================================ - - # ============================================================ - def _translate_method_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, - method_name: str, - obj_ptr: llvmlite.Value | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """翻译方法调用,返回 call 结果 Value""" - if pool is None or builder is None or class_name is None or method_name is None: - return None - if obj_ptr is None or cl is None: - return None - - # 提前获取结构体 entry(用 find_struct_by_type 规避跨模块同名 find_struct 找错) - # 用于继承链遍历、SHA1 查找和虚表分派 - mc_entry: HandlesStruct.StructEntry | t.CPtr = None - mc_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(obj_ptr) - if mc_struct_ty is not None: - mc_entry = HandlesStruct.find_struct_by_type(mc_struct_ty) - if mc_entry is None: - mc_entry = HandlesStruct.find_struct(class_name) - - # 构造方法查找名: ClassName.method_name - lookup_name: str = pool.alloc(128) - if lookup_name is None: - return None - viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name) - - # 查找函数(支持 SHA1 后缀匹配) - found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, lookup_name) - - # 泛型模板类方法:特化函数名带类型参数({sha1}.list[int].get), - # "ClassName.method" 短名匹配不到。特化由触发方(通常即调用方)模块完成, - # 用对象实际特化名(mc_entry.Name)构造后缀匹配,获得精确返回类型。 - if found_func is None and mc_entry is not None and mc_entry.Name is not None: - if string.strcmp(mc_entry.Name, class_name) != 0: - spec_lookup: str = pool.alloc(160) - if spec_lookup is not None: - viperlib.snprintf(spec_lookup, 160, "%s.%s", mc_entry.Name, method_name) - found_func = self.find_func_in_module(mod, spec_lookup) - - # 沿 MRO 祖先链查找父类方法(子类未覆盖时回退到父类,先声明父类优先) - mc_anc: str = None # 方法实际定义类(多继承 this 调整用) - if found_func is None: - mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name) - mi: int = 1 - while mro_ptr is not None and mro_ptr[mi] != 0: - anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr)) - if anc is not None: - parent_lookup: str = pool.alloc(128) - if parent_lookup is not None: - viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, method_name) - parent_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, parent_lookup) - if parent_func is not None: - found_func = parent_func - mc_anc = anc - break - mi += 1 - - # 兄弟 Mixin 兜底(与 TPC HandlesExprCall 一致):方法不在本类 MRO 链 - # (如 BaseB 内 self.helper() 调兄弟 BaseA.helper,BaseB 无 BaseA 的 - # 继承信息)。遍历已注册 struct 表找定义类方法,this 由下方 - # _adjust_this_for_inherited_method 按组合布局前移 sizeof(定义类)。 - # 注意:仅对普通类名兜底——泛型特化类名(list[X] / dict[K,V])是 - # 模板生成的特殊容器,其特化函数(如 list[ASTptr].__getitem__)虽 - # 在模块中存在,但绝非"兄弟 Mixin"(NoVTableCrossMixinTest 的 - # BaseA/BaseB/Combined 场景)。若不过滤,JsonValue.__getitem__ 等 - # 普通方法调用在 found_func 未命中时会误绑定到 list 特化函数, - # this 按 list 布局前移 sizeof(list) → 运行期读 -1 崩溃 - # (Config.vp Load_project_config root.__getitem__ 根因)。 - if found_func is None: - sc_i: int = 0 - sc_n: int = HandlesStruct.get_struct_count() - while sc_i < sc_n and found_func is None: - cand_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct._get_struct_entry(sc_i) - if cand_entry is not None and cand_entry.Name is not None: - cand_name: str = cand_entry.Name - if string.strcmp(cand_name, class_name) != 0: - # 泛型特化类名含 '['(list[...]/dict[...]):跳过, - # 不是兄弟 Mixin 候选(见上方注释) - if string.strchr(cand_name, '[') is not None: - sc_i += 1 - continue - cand_lookup: str = pool.alloc(128) - if cand_lookup is not None: - viperlib.snprintf(cand_lookup, 128, "%s.%s", cand_name, method_name) - cand_func: llvmlite.Function | t.CPtr = self.find_func_in_module( - mod, cand_lookup) - if cand_func is not None: - found_func = cand_func - mc_anc = cand_name - sc_i += 1 - - # 确定调用名(默认 "ClassName.method";found_func 未命中时沿 MRO 用 - # 方法实际定义类的 SHA1 构造,如 Module.append → AST 定义的 append, - # 函数名为 {AST_sha1}.AST.append) - call_name: str = lookup_name - if found_func is not None: - found_name: str = llvmlite.function_get_name(found_func) - if found_name is not None: - call_name = found_name - - # 确定返回类型 - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - call_ret_ty: llvmlite.LLVMType | t.CPtr = i32_ty - if found_func is not None: - frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) - if frt is not None: - call_ret_ty = frt - else: - # found_func 为 None(stub 未注入):先处理编译器内置特殊方法 - sp_ty2: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty(pool, class_name, method_name) - if sp_ty2 is not None: - call_ret_ty = sp_ty2 - # 特殊方法(__before_init__ 等)跨模块调用同样需带 sha1 前缀: - # memhub.alloc_buf 显式调 buf.__before_init__(),buf 是 viperio.Buf*, - # 若用裸名 @Buf.__before_init__ 链接 undefined symbol。用 - # mc_entry.ModuleSha1 / get_struct_sha1 / 类型名提取 sha1 构造 - # {sha1}.Buf.__before_init__。 - sp_anc_name: str = class_name - sp_anc_sha1: str = None - if mc_entry is not None: - sp_anc_sha1 = mc_entry.ModuleSha1 - else: - sp_anc_sha1 = HandlesStruct.get_struct_sha1(class_name) - if sp_anc_sha1 is None and mc_struct_ty is not None: - match mc_struct_ty: - case llvmlite.LLVMType.Struct(_fs_sp, _fc_sp, type_name_sp): - if type_name_sp is not None and type_name_sp[0] != '\0': - tl_sp: t.CSizeT = string.strlen(type_name_sp) - if tl_sp >= 16: - sb_sp: str = pool.alloc(17) - if sb_sp is not None: - string.strncpy(sb_sp, type_name_sp, 16) - sb_sp[16] = '\0' - sp_anc_sha1 = sb_sp - case _: - pass - if sp_anc_sha1 is not None: - ml_sp: t.CSizeT = string.strlen(sp_anc_sha1) + string.strlen(sp_anc_name) \ - + string.strlen(method_name) + 3 - mangled_sp: str = pool.alloc(ml_sp) - if mangled_sp is not None: - viperlib.snprintf(mangled_sp, ml_sp, "%s.%s.%s", - sp_anc_sha1, sp_anc_name, method_name) - call_name = mangled_sp - else: - # 方法实际定义类(跨模块调用名/返回类型来源;Module.append 定义在 AST) - # 默认 class_name 自身,MRO fallback 命中祖先类时更新 - ret_anc_name: str = class_name - ret_anc_sha1: str = None - if mc_entry is not None: - ret_anc_sha1 = mc_entry.ModuleSha1 - else: - ret_anc_sha1 = HandlesStruct.get_struct_sha1(class_name) - if ret_anc_sha1 is None: - # 沿 MRO 找第一个有 SHA1 的类 - mro_s0: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name) - mi_s0: int = 1 - while mro_s0 is not None and mro_s0[mi_s0] != 0 and ret_anc_sha1 is None: - anc_s0: str = (str | t.CPtr)(t.CVoid(mro_s0[mi_s0], t.CPtr)) - if anc_s0 is not None: - ret_anc_sha1 = HandlesStruct.get_struct_sha1(anc_s0) - mi_s0 += 1 - - # 泛型特化方法调用:特化函数可能尚未注册(如 ast.base 用 - # list[AST|t.CPtr].get)。主动触发特化(幂等,MethodsEmitted 防重入), - # 特化后重新查找即可命中,返回类型来自特化函数定义(天然精确)。 - gen_done: int = 0 - # text.ll 查找结果提升为函数级并显式初始化:gen_done==1 成功时 - # 下方回退段不执行,若在此声明则读到未初始化的池内存垃圾(非 NULL), - # 把已正确解析的 call_ret_ty(特化 define 的 i32)覆盖成垃圾零值 - # LLVMType → build_call 输出 call i0(llc bitwidth out of range)。 - looked_up_ty: llvmlite.LLVMType | t.CPtr = None - if class_name is not None: - lbkt_g: str = string.strchr(class_name, '[') - if lbkt_g is not None: - rbkt_g: str = string.strrchr(class_name, ']') - if rbkt_g is not None and rbkt_g > lbkt_g: - base_len_g: t.CSizeT = t.CSizeT(t.CUInt64T(lbkt_g) - t.CUInt64T(class_name)) - arg_len_g: t.CSizeT = t.CSizeT(t.CUInt64T(rbkt_g) - t.CUInt64T(lbkt_g) - 1) - if base_len_g > 0 and arg_len_g > 0: - base_buf_g: str = pool.alloc(base_len_g + 1) - arg_buf_g: str = pool.alloc(arg_len_g + 1) - if base_buf_g is not None and arg_buf_g is not None: - string.strncpy(base_buf_g, class_name, base_len_g) - base_buf_g[base_len_g] = '\0' - string.strncpy(arg_buf_g, lbkt_g + 1, arg_len_g) - arg_buf_g[arg_len_g] = '\0' - ta_list_g: list[str] | t.CPtr = list[str](pool, 8) - if ta_list_g is not None: - # 逗号分隔多类型实参(list[X] / dict[K, V]) - cur_arg_g: str = arg_buf_g - while cur_arg_g is not None: - comma_g: str = string.strchr(cur_arg_g, ',') - if comma_g is None: - ta_list_g.append(cur_arg_g) - break - seg_len_g: t.CSizeT = t.CSizeT(t.CUInt64T(comma_g) - t.CUInt64T(cur_arg_g)) - seg_buf_g: str = pool.alloc(seg_len_g + 1) - if seg_buf_g is not None: - string.strncpy(seg_buf_g, cur_arg_g, seg_len_g) - seg_buf_g[seg_len_g] = '\0' - ta_list_g.append(seg_buf_g) - cur_arg_g = comma_g + 1 - spec_name_g: str = HandlesClassDef._specialize_generic_class( - trans, base_buf_g, ta_list_g) - if spec_name_g is not None: - # 特化后重新查找特化函数(特化名 = 调用点类名) - spec_lk_g: str = pool.alloc( - string.strlen(class_name) + string.strlen(method_name) + 2) - if spec_lk_g is not None: - viperlib.snprintf(spec_lk_g, - string.strlen(class_name) + string.strlen(method_name) + 2, - "%s.%s", class_name, method_name) - spec_found_g: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, spec_lk_g) - if spec_found_g is not None: - frt_g: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(spec_found_g) - if frt_g is not None: - call_ret_ty = frt_g - found_func = spec_found_g - gen_done = 1 - if gen_done == 0: - # 尝试从 text.ll 查找实际返回类型 - # 避免指针返回值被默认 i32 导致 inttoptr 截断 - looked_up_ty = self._LookupMethodRetTyFromTextLL( - pool, ret_anc_sha1, ret_anc_name, method_name) - # 沿 MRO 祖先链重试:方法可能定义在基类(如 Module.append → - # AST.append,函数名 {ast_sha1}.AST.append,且基类在另一模块文件 - # 如 ast/stmts.vp 的 Module vs ast/base.vp 的 AST),按调用类名 - # 及其 sha1 查不到,需用每个祖先类的类名 + 祖先类所属模块 sha1 - # 查 text.ll(NewAstTest mod.append 根因) - if looked_up_ty is None: - mro_t2: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name) - mi_t2: int = 1 - while mro_t2 is not None and mro_t2[mi_t2] != 0 and looked_up_ty is None: - anc_t2: str = (str | t.CPtr)(t.CVoid(mro_t2[mi_t2], t.CPtr)) - if anc_t2 is not None and string.strcmp(anc_t2, class_name) != 0: - anc_sha1_t2: str = HandlesStruct.get_struct_sha1(anc_t2) - looked_up_ty = self._LookupMethodRetTyFromTextLL( - pool, anc_sha1_t2, anc_t2, method_name) - if looked_up_ty is not None: - ret_anc_name = anc_t2 - ret_anc_sha1 = anc_sha1_t2 - mi_t2 += 1 - if gen_done == 0 and looked_up_ty is not None: - call_ret_ty = looked_up_ty - elif gen_done == 0: - # 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单) - vpi_ret_ty: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi( - pool, ret_anc_sha1, ret_anc_name, method_name) - # vpi 同样沿 MRO 祖先链重试(基类方法注解,用祖先类自身 sha1) - if vpi_ret_ty is None: - mro_v2: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name) - mi_v2: int = 1 - while mro_v2 is not None and mro_v2[mi_v2] != 0 and vpi_ret_ty is None: - anc_v2: str = (str | t.CPtr)(t.CVoid(mro_v2[mi_v2], t.CPtr)) - if anc_v2 is not None and string.strcmp(anc_v2, class_name) != 0: - anc_sha1_v2: str = HandlesStruct.get_struct_sha1(anc_v2) - vpi_ret_ty = self._lookup_method_ret_ty_via_vpi( - pool, anc_sha1_v2, anc_v2, method_name) - if vpi_ret_ty is not None: - ret_anc_name = anc_v2 - ret_anc_sha1 = anc_sha1_v2 - mi_v2 += 1 - if vpi_ret_ty is not None: - call_ret_ty = vpi_ret_ty - else: - # Phase A 依赖 text.ll 未生成(方法定义模块尚未翻译)→ 标记 - # 重试,保持默认类型继续(下遍依赖生成后可精确解析),对齐跨模块 - # 函数路径 L8167-8195 的 _deps_pending 机制。BuildPipeline.vp - # L216 gen.extract_module_docstrings 根因:方法定义在 - # ExprGenMixin(Mixin 模块),Phase A 顺序中 ExprGenMixin 的 - # text.ll 尚未生成 → MRO 链查找全部未命中 → fail-fast 误报。 - # ret_anc_sha1 为 None 同样视为依赖未就绪:pass1 中 Generator - # 及其 Mixin 全部 defer(依赖 Handles/* 未翻译)→ 结构体未注册 - # → get_struct_sha1/MRO 查找全空 → 连 sha1 都取不到 - # (g._register_cdefine_from_value 根因)。标记 _deps_pending - # 下遍重译,绝不 fail-fast 中断多遍收敛;真实错误由收敛检查兜底。 - if ret_anc_sha1 is None \ - or (ret_anc_sha1 is not None - and self._dep_text_ll_exists(pool, ret_anc_sha1) == 0): - if trans is not None: - trans._deps_pending = 1 - # 依赖未就绪:保持默认 i32 继续而非 Void——build_call(Void) - # 返回 None,方法调用结果喂进表达式(if 条件/比较)时 fatal - # "if 条件表达式翻译失败"(ExprGenAttr._get_cderef_attr_base - # 根因)。本遍不写盘、下遍重译精确解析,错误类型不会进入 - # 产物(对齐跨模块函数路径 L8167-8195"保持默认类型继续")。 - call_ret_ty = llvmlite.Int32(pool) - else: - # 追加80e 断点 A:方法可能定义在 MRO 祖先(Mixin)模块。 - # 此时 ret_anc_sha1 仍是调用类自身的 sha1(MRO 双路重试 - # 失败未更新),且调用类(如 Generator)已注册、自身 text.ll - # 存在 → 上方 guard 不成立 → 直接 fail-fast。但 MRO 重试 - # 落空可能只是"祖先定义模块未翻译"(AssignGenMixin.vp 的 - # text.ll 未生成),属依赖未就绪而非方法不存在。遍历祖先链: - # 任一祖先的 sha1 取不到或其 text.ll 未生成 → 结果不确定, - # 标记 pending 下遍重试(届时祖先 text.ll 生成,MRO 重试 - # 可精确解析);全部祖先就绪仍查不到才是真错误。 - mro_p2: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name) - mi_p2: int = 1 - anc_missing_p2: int = 0 - while mro_p2 is not None and mro_p2[mi_p2] != 0: - anc_p2: str = (str | t.CPtr)(t.CVoid(mro_p2[mi_p2], t.CPtr)) - if anc_p2 is not None: - anc_sha1_p2: str = HandlesStruct.get_struct_sha1(anc_p2) - if anc_sha1_p2 is None \ - or self._dep_text_ll_exists(pool, anc_sha1_p2) == 0: - anc_missing_p2 = 1 - break - mi_p2 += 1 - if anc_missing_p2 != 0: - if trans is not None: - trans._deps_pending = 1 - # 依赖未就绪:保持默认 i32(同上,build_call(Void) 返回 - # None 会破坏表达式翻译,pending 文件本遍不写盘) - call_ret_ty = llvmlite.Int32(pool) - else: - call_ret_ty = self._fail_method_ret_ty(method_name, cl) - - # found_func 未命中但返回类型已解析:用方法定义类构造跨模块调用名 - # (Module.append → {AST_sha1}.AST.append,避免链接 undefined reference) - if ret_anc_name is not None and ret_anc_sha1 is None: - # ret_anc_sha1 缺失(如 find_struct 未命中跨模块结构体)时, - # 从对象实际 LLVM 类型名提取 sha1 前缀:类型名形如 - # "2c175afd85852faf.Buf"({sha1}.{ClassName}),前 16 字符即模块 sha1。 - # 例:memhub.alloc_buf 里 buf.__before_init__(),buf 是 viperio.Buf*, - # 其类型名含 viperio 模块 sha1,借此构造 {sha1}.Buf.__before_init__, - # 避免静默生成裸名 @Buf.__before_init__(链接 undefined symbol)。 - if mc_struct_ty is not None: - match mc_struct_ty: - case llvmlite.LLVMType.Struct(_fields_st, _fcount_st, type_name_st): - if type_name_st is not None and type_name_st[0] != '\0': - type_len_st: t.CSizeT = string.strlen(type_name_st) - if type_len_st >= 16: - sha1_from_ty: str = pool.alloc(17) - if sha1_from_ty is not None: - string.strncpy(sha1_from_ty, type_name_st, 16) - sha1_from_ty[16] = '\0' - ret_anc_sha1 = sha1_from_ty - case _: - pass - if ret_anc_name is not None and ret_anc_sha1 is not None: - ml_anc: t.CSizeT = string.strlen(ret_anc_sha1) + string.strlen(ret_anc_name) \ - + string.strlen(method_name) + 3 - mangled_anc: str = pool.alloc(ml_anc) - if mangled_anc is not None: - viperlib.snprintf(mangled_anc, ml_anc, "%s.%s.%s", - ret_anc_sha1, ret_anc_name, method_name) - call_name = mangled_anc - # 类型名提取的 sha1 无法保证为真实模块 sha1(跨模块 stub 类型名 - # 带前缀但 find_struct 未注册时仍可用),此处不校验格式 - elif ret_anc_name is not None and ret_anc_sha1 is None: - # fail-fast:方法所属类既查不到 SHA1 又从类型名提取失败, - # 禁止静默裸名(否则链接期 undefined symbol 难以定位) - HandlesType.fatal_error( - cl, - f"方法 '{method_name}' 所属类 '{ret_anc_name}' 无法解析模块 SHA1" - f"(text.ll/vpi/类型名均未命中),跨模块调用名构造失败", - "TypeError") - - # 翻译调用参数 - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - can: t.CSizeT = 0 - if cargs is not None: - can = len(cargs) - kw_calls: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords - kwc: t.CSizeT = 0 - if kw_calls is not None: - kwc = len(kw_calls) - - # 多继承 this 调整(字节偏移法,2026-08-10,与 TPC HandlesExprCall._adjust_this_for_inherited_method 一致): - # 继承方法体按"定义类自身布局"读 self 字段(如 B.get_b 内 GEP(self_B, [0,1]) - # 的字节偏移是 B 布局中 b 的 offset 12)。父类字段区在子类中的字节偏移可能 - # 不同(如 AB={vtable,a@8,b@12} 中 b 偏移 16),self 需按字节差前移,使父类 - # 方法内二次 GEP 恰好落到子类字段。 - # delta = 字段在子类中字节偏移 − 字段在父类自身布局中字节偏移 - # delta==0(第一父类,字段区前缀对齐)无需调整;delta>0 时按字节 GEP 到 - # 父类字段区在子类中的等效基址,再 bitcast 成父类指针。 - # 原实现仅覆盖"无 vtable 的父类"(其首字段偏移 0,GEP 到首字段即父类起点), - # 且用 GEP 字段法——对 vtable 父类(首字段偏移非 0,如 B)被直接跳过不调整 - # → AB 场景 B.get_b 按 B 布局读 self.b@12 落到 a → AB 字段/方法 FAILED。 - self_arg: llvmlite.Value | t.CPtr = obj_ptr - if mc_anc is not None and string.strcmp(mc_anc, class_name) != 0: - # 判断 mc_anc 是否为 class_name 的第一父类:第一父类字段区前缀对齐 - # (delta==0)无需调整;非第一父类必须调整 self,任何一步失败都 - # fail-fast——绝不静默用未调整的 obj_ptr 当 self,否则方法按自身 - # 布局读字段读到垃圾(lookup_reexport strcmp 概率崩溃根因候选)。 - is_first_parent_th: int = 0 - mro_fp_th: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name) - if mro_fp_th is not None and mro_fp_th[1] != 0: - first_parent_th: str = (str | t.CPtr)(t.CVoid(mro_fp_th[1], t.CPtr)) - if first_parent_th is not None and string.strcmp(first_parent_th, mc_anc) == 0: - is_first_parent_th = 1 - anc_entry_th: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(mc_anc) - # 无字段父类(FieldCount==0,如多继承中的纯方法类 Vec2Extra): - # 继承方法体按"定义类字段"读 self,定义类无字段则方法体不读 - # self 布局 → this 无需字节调整,原样传入即可(对齐 TPC - # _adjust_this_for_inherited_method:anc_members 为空直接返回 ObjVal)。 - if anc_entry_th is not None and anc_entry_th.FieldCount > 0: - anc_first_name_th: str = None - afi_th: int = 0 - while afi_th < anc_entry_th.FieldCount: - afe_th: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( - anc_entry_th, afi_th) - if afe_th is not None: - afn_th: str = HandlesStruct.get_field_name_ptr(afe_th) - if afn_th is not None and string.strcmp(afn_th, "__vtable__") != 0: - anc_first_name_th = afn_th - break - afi_th += 1 - if anc_first_name_th is not None: - sub_entry_th: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct( - class_name) - if sub_entry_th is not None: - anc_field_th: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( - anc_entry_th.Ty, anc_first_name_th) - sub_field_th: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( - sub_entry_th.Ty, anc_first_name_th) - if anc_field_th is not None and sub_field_th is not None: - anc_off_th: int = self._field_byte_offset( - pool, anc_entry_th, anc_field_th.Index) - sub_off_th: int = self._field_byte_offset( - pool, sub_entry_th, sub_field_th.Index) - delta_th: int = sub_off_th - anc_off_th - if delta_th > 0: - i8_ty_th: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_th: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_th) - obj_i8_th: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, obj_ptr, i8_ptr_th) - delta_val_th: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, delta_th) - adj_th: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i8_ty_th, obj_i8_th, delta_val_th) - if adj_th is not None: - anc_ptr_ty_th: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, anc_entry_th.Ty) - # 跨模块基类(如 Generator → ClassGenBase)的完整定义不在本模块, - # bitcast 引用 %"sha1.ClassGenBase" 前必须确保 opaque 声明存在, - # 否则 llc 报 "use of undefined type"(PrintModule 只扫函数签名, - # 函数体内的 bitcast 类型不会被自动声明)。 - llvmlite.module_ensure_opaque_for_type(mod, pool, anc_ptr_ty_th) - self_arg = llvmlite.build_bitcast(builder, adj_th, anc_ptr_ty_th) - elif sub_field_th is None and anc_field_th is not None: - # 兄弟 Mixin 场景(对齐 TPC _adjust_this_for_inherited_method): - # 调用类(class_name=BaseB)不含定义类(mc_anc=BaseA)字段—— - # BaseA 在组合类 MRO 中位于 BaseB 之前(如 Combined(BaseA, BaseB), - # BaseB 内 self.helper() 调 BaseA.helper)。BaseB.this 指向组合类中 - # BaseB 字段区起点,BaseA 区在它前面,this 前移 sizeof(定义类)。 - # 若无此分支,sub_field_th 查找失败 → 下方 fail-fast,兄弟 Mixin - # 调用永远编译不过(NoVTableCrossMixinTest BaseB.caller 根因)。 - anc_size_th: int = HandlesClassDef._get_type_size(anc_entry_th.Ty) - if anc_size_th > 0: - i8_ty_th2: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_th2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_th2) - obj_i8_th2: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, obj_ptr, i8_ptr_th2) - sib_delta_th: llvmlite.Value | t.CPtr = llvmlite.const_int32( - pool, 0 - anc_size_th) - adj_th2: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i8_ty_th2, obj_i8_th2, sib_delta_th) - if adj_th2 is not None: - anc_ptr_ty_th2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, anc_entry_th.Ty) - llvmlite.module_ensure_opaque_for_type( - mod, pool, anc_ptr_ty_th2) - self_arg = llvmlite.build_bitcast( - builder, adj_th2, anc_ptr_ty_th2) - else: - # 定义类 struct 大小不可得(opaque/未加载):fail-fast - HandlesType.fatal_error( - cl, - f"this-adjust 兄弟 Mixin 定义类大小未知: 方法'{method_name}'" - f"定义类'{mc_anc}'的 struct 大小计算失败", - "InternalCompilerError") - elif is_first_parent_th == 0: - HandlesType.fatal_error( - cl, - f"this-adjust 字段查找失败: 方法'{method_name}'定义类'{mc_anc}'" - f"首字段'{anc_first_name_th}'在类'{class_name}'/'{mc_anc}'布局中未找到", - "InternalCompilerError") - elif is_first_parent_th == 0: - HandlesType.fatal_error( - cl, - f"this-adjust 子类结构体未注册: 方法'{method_name}'定义类'{mc_anc}'," - f"接收类'{class_name}'的 struct 未找到", - "InternalCompilerError") - else: - # 父类仅 __vtable__ 字段(无字段 CVTable 类):方法体不读 - # 布局字段,无需调整(对齐 TPC:first_field_name None → ObjVal) - pass - elif anc_entry_th is not None and anc_entry_th.FieldCount == 0: - # 无字段父类:this 无需字节调整(见上方注释) - pass - elif is_first_parent_th == 0: - # 父类 struct 未注册:fail-fast,绝不静默用未调整的 obj_ptr - # 当 self(否则方法按自身布局读字段读到垃圾) - HandlesType.fatal_error( - cl, - f"this-adjust 父类结构体未注册: 方法'{method_name}'定义类'{mc_anc}'的 struct 未找到", - "InternalCompilerError") - # 构建参数链表: self → arg1 → arg2 → ... - llvmlite.value_set_next(self_arg, None) - head: llvmlite.Value | t.CPtr = self_arg - tail: llvmlite.Value | t.CPtr = self_arg - arg_count_eff: int = 0 - - if kwc > 0 and found_func is not None: - # 关键字参数:遍历函数定义参数(跳过 self),位置参数优先,其余按名匹配 - # 缺失参数用零值兜底,保持 call 参数数量与 define 一致 - cur_param_k: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) - if cur_param_k is not None: - cur_param_k = llvmlite.param_get_next(cur_param_k) # 跳过 self - pi_k: int = 0 - while cur_param_k is not None: - arg_node_k: ast.AST | t.CPtr = None - if pi_k < can: - arg_node_k = cargs.get(pi_k) - else: - pname_k: str = llvmlite.param_get_name(cur_param_k) - if pname_k is not None: - ki_k: int - for ki_k in range(kwc): - kw_k: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(kw_calls.get(ki_k)) - if kw_k is None or kw_k.arg is None or kw_k.value is None: - continue - if self._kwarg_name_matches(kw_k.arg, pname_k) == 1: - arg_node_k = kw_k.value - break - arg_val_k: llvmlite.Value | t.CPtr = None - if arg_node_k is not None: - arg_val_k = HandlesExpr.translate_value( - builder, pool, mod, arg_node_k, None, 0, trans) - if arg_val_k is None: - # 缺失参数:零值兜底(保持参数数量匹配)。 - # kw 省略的形参可能有默认值(查不到默认表 ≠ 无默认值), - # 零值兜底与原逻辑一致,禁止 fail-fast 误杀。 - pty_k: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k) - if pty_k is not None: - arg_val_k = llvmlite.ConstZero(pool, pty_k) - if arg_val_k is not None: - pty_k2: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k) - if pty_k2 is not None: - arg_val_k = HandlesExpr.coerce_to_type( - builder, arg_val_k, pty_k2, arg_node_k) - llvmlite.value_set_next(arg_val_k, None) - llvmlite.value_set_next(tail, arg_val_k) - tail = arg_val_k - arg_count_eff += 1 - pi_k += 1 - cur_param_k = llvmlite.param_get_next(cur_param_k) - else: - # 位置参数(原逻辑) - for ai in range(can): - arg_node: ast.AST | t.CPtr = cargs.get(ai) - if arg_node is None: - continue - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg_node, None, 0, trans) - if arg_val is None: - continue - # 按形参类型 coerce(self 是形参 0,第 ai 个实参对应形参 ai+1) - # 修复: CDefine/i32 常量传给 i64 形参(如 MemBuddy.__init__ 的 size: t.CSizeT) - # 未提升导致 call(i32) 与 define(i64) 不匹配,运行时读到垃圾高 32 位崩溃 - if found_func is not None: - pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) - pi: int = 0 - while pp is not None and pi < ai + 1: - if pi == ai + 1: - break - pp = llvmlite.param_get_next(pp) - pi += 1 - if pp is not None: - pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pp) - if pty is not None: - arg_val = HandlesExpr.coerce_to_type( - builder, arg_val, pty, arg_node) - else: - # found_func=None(跨模块 stub 未注入):数组实参按 C 语义 - # 衰减为元素指针(对齐 TPC _decay_array_to_ptr)。否则 - # _ensure_method_declare 用 [N x ty]* 实参类型建 declare, - # 与定义侧元素指针(如 md5.final 的 i8*)类型不匹配。 - if arg_val.Ty is not None and HandlesExpr.is_ptr_type(arg_val.Ty) != 0: - arr_pointee_ma: llvmlite.LLVMType | t.CPtr = arg_val.Ty.Pointee - if arr_pointee_ma is not None: - match arr_pointee_ma: - case llvmlite.LLVMType.Array(arr_et_ma, _): - decayed_ma: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, arr_pointee_ma, arr_et_ma, arg_val, - llvmlite.const_int32(pool, 0)) - if decayed_ma is not None: - arg_val = decayed_ma - case _: - pass - llvmlite.value_set_next(arg_val, None) - llvmlite.value_set_next(tail, arg_val) - tail = arg_val - arg_count_eff += 1 - - total_count: int = 1 + arg_count_eff - - # 默认参数填充:如果调用点参数少于函数定义参数,用默认值填充缺失参数 - # 查找函数的 defaults 信息 - mdf_defaults: t.CVoid | t.CPtr = None - mdf_default_count: int = 0 - mdf_param_count: int = 0 - if trans is not None and trans._funcs is not None: - mdf_entry: FuncEntry | t.CPtr = ExprCallTable.find_func_entry_in_table( - trans._funcs, trans._func_count, lookup_name) - if mdf_entry is not None: - mdf_defaults = mdf_entry.Defaults - mdf_default_count = mdf_entry.DefaultCount - mdf_param_count = mdf_entry.ParamCount - # 全局默认参数表查询无条件执行:mdf_entry 命中时(泛型特化方法注册进 - # 调用方函数表)Defaults 非 None 会短路跳过,但下方"用快照重建默认值" - # 分支依赖 mdf_gd(唯一持有 stdlib 常量快照处)——缺它必 fatal_error - # (ListTest list[int].__new__ 根因) - mdf_gd: FuncDefaultsEntry | t.CPtr = ExprCallTable.find_func_defaults(lookup_name) - if mdf_defaults is None and mdf_gd is not None: - mdf_defaults = mdf_gd.Defaults - mdf_default_count = mdf_gd.DefaultCount - mdf_param_count = mdf_gd.ParamCount - - # 计算需要填充的参数(不含 self) - # arg_count_eff = 已提供的非 self 参数数量(含关键字模式完整构建) - # mdf_param_count = 函数定义的非 self 参数数量 - if mdf_param_count > arg_count_eff: - mdf_offset: int = mdf_param_count - mdf_default_count - mdf_pi: int = arg_count_eff - while mdf_pi < mdf_param_count: - # 优先用默认值 - if mdf_defaults is not None and mdf_default_count > 0 and mdf_pi >= mdf_offset: - mdf_di: int = mdf_pi - mdf_offset - if mdf_di < mdf_default_count: - # 用 stdlib 常量快照重建(mdf_gd.Defaults 的 pool 内 AST 可能已被 reset 回收, - # 直接回退读 AST 会 use-after-free——快照失败时 fail-fast 暴露,绝不读悬空 AST) - mdf_val: llvmlite.Value | t.CPtr = None - if mdf_gd is not None: - mdf_val = ExprCallTable._build_const_from_snapshot( - pool, mod, mdf_gd, mdf_di, trans, builder) - if mdf_val is None: - HandlesType.fatal_error( - cl, - f"跨模块默认参数无法重建(快照缺失,默认值需为简单常量): {lookup_name}", - "TypeError") - continue - llvmlite.value_set_next(mdf_val, None) - llvmlite.value_set_next(tail, mdf_val) - tail = mdf_val - total_count += 1 - mdf_pi += 1 - continue - # 无默认值时用零值兜底(需要 found_func 获取参数类型)。 - # 默认参数表按裸名注册(如 "__init__"),跨模块 "ClassName.method" - # 查找常查不到——查不到 ≠ 无默认值(如 Buf.__init__(data, capacity) - # 缺的 length=0/owned=False 恰为零值),零值兜底语义一致。 - if found_func is not None: - param_node_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) - skip_z: int = 0 - while skip_z <= mdf_pi and param_node_z is not None: - param_node_z = llvmlite.param_get_next(param_node_z) - skip_z += 1 - if param_node_z is not None: - zero_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node_z) - zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, zero_ty) - if zero_val is not None: - llvmlite.value_set_next(zero_val, None) - llvmlite.value_set_next(tail, zero_val) - tail = zero_val - total_count += 1 - mdf_pi += 1 - - # 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用 - # (不依赖 found_func — 继承的虚方法可能没有子类实现) - # 复用前面已获取的 mc_entry(find_struct_by_type 规避跨模块同名找错) - mc_has_vt: int = 0 - mc_method_idx: int = -1 - if mc_entry is not None: - mc_has_vt = mc_entry.HasVTable - if mc_has_vt == 1 and mc_entry.VTableMethods is not None: - mc_methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(mc_entry.VTableMethods, t.CPtr)) - for mc_mi in range(mc_entry.VTableMethodCount): - mc_mname_addr: t.CSizeT = mc_methods_arr[mc_mi] - if mc_mname_addr == 0: - continue - mc_mname: str = (str | t.CPtr)(t.CVoid(mc_mname_addr, t.CPtr)) - if mc_mname is not None and string.strcmp(mc_mname, method_name) == 0: - mc_method_idx = mc_mi - break - if mc_has_vt == 1 and mc_method_idx >= 0: - # 虚分派 self 必须用调整后的 self_arg(多继承 this 调整), - # 否则 B.get_b 收到未调整的 AB*,方法体内按 B 布局读字段错位。 - # vtable 读取必须用对象头 obj_ptr(调整后 self 头部是父类字段值)。 - return self._do_virtual_call(pool, builder, mod, class_name, method_name, - self_arg, head, total_count, found_func, call_ret_ty, - obj_ptr) - - # 跨模块调用:创建 declare 声明,避免 llc 报 undefined value - self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, total_count) - # 检查变长函数 + C ABI 提升(cargs 是实参 AST,self_offset=1 跳过 self) - is_variadic_3441: int = ExprCallCall._check_and_promote_variadic_call( - pool, builder, mod, call_name, head, total_count, cargs, 1, trans) - # try-except:方法含 raise(EH 输出参数)时追加输出实参 + 调用后检测 - return ExprCallHandle._emit_eh_guarded_call( - builder, pool, mod, trans, found_func, call_name, head, total_count, - call_ret_ty, is_variadic_3441) - # ============================================================ - # _translate_super_call — super().method(args) → 静态调用父类方法 - # - # Python super 语义(2026-08-10 实现): - # - 当前类来自 self.CurClassName(_translate_method 翻译方法体时设置) - # - 父类查找:沿 get_mro_chain(CurClassName) 跳过自身,找第一个定义 method 的祖先 - # - self 指针:符号表 self 变量 alloca load(对象头,复用 c.Addr(self) 模式) - # - this_adjust:父类字段区在子类中字节偏移 delta>0 时 GEP i8* + delta - # (复用 _field_byte_offset 字节偏移法,与 _translate_method_call 一致) - # - 静态调用父类实现:不虚分派(super() 不触发子类 override) - # ============================================================ - - # ============================================================ - def _translate_super_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - method_name: str, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """super().method(args) → 父类方法静态调用,返回 call 结果 Value""" - if pool is None or builder is None or cl is None or method_name is None: - return None - if trans is None: - return None - # 1. 当前方法所属类:从 self 变量的注解类名获取(_translate_method - # 注册 self 时 set_var_annot_class_name(SymTab, "self", class_name))。 - # 不用 Mixin 字段:TPV Mixin 字段按声明类独立布局(Generator 多继承 - # 去重只保留首个声明),ClassGenMixin 写的 CurClassName 与 CallGenMixin - # 读的位置偏移不一致 → 运行时读到空 → super() 误报"只能在类方法内使用"。 - self_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, "self") - if self_entry is None: - self_entry = HandlesVar.lookup_var_entry(trans.SymTab, "cls") - if self_entry is None: - HandlesType.fatal_error(cl, "super(): 当前作用域无 self 变量(静态方法内不可用)", "TypeError") - return None - cur_class: str = self_entry.AnnotClassName - if cur_class is None: - HandlesType.fatal_error(cl, "super() 只能在类方法内使用(self 无注解类名)") - return None - # 2. 沿 MRO 跳过自身,找第一个定义 method 的祖先类 - anc: str = None - mro_sp: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, cur_class) - mi_sp: int = 1 - while mro_sp is not None and mro_sp[mi_sp] != 0: - anc_sp: str = (str | t.CPtr)(t.CVoid(mro_sp[mi_sp], t.CPtr)) - if anc_sp is not None: - probe_sp: str = pool.alloc(160) - if probe_sp is not None: - viperlib.snprintf(probe_sp, 160, "%s.%s", anc_sp, method_name) - if ExprCallTable.find_func_global(probe_sp) is not None: - anc = anc_sp - break - mi_sp += 1 - if anc is None: - err_sp: str = pool.alloc(256) - if err_sp is not None: - viperlib.snprintf(err_sp, 256, "super(): 当前类 %s 的父类链未定义方法 %s", - cur_class, method_name) - HandlesType.fatal_error(cl, err_sp, "TypeError") - HandlesType.fatal_error(cl, "super(): 父类链未定义方法", "TypeError") - return None - # 3. self 指针(self 变量 alloca load,复用 c.Addr(self) 模式) - if self_entry.Alloca is None or self_entry.Alloca.Ty is None: - HandlesType.fatal_error(cl, "super(): 当前作用域无 self 变量(静态方法内不可用)", "TypeError") - return None - self_ptr: llvmlite.Value | t.CPtr = None - match self_entry.Alloca.Ty: - case llvmlite.LLVMType.Ptr(inner1): - match inner1: - case llvmlite.LLVMType.Ptr(inner2): - obj_ty_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, inner2) - self_ptr = llvmlite.build_load(builder, obj_ty_sp, self_entry.Alloca) - case _: - self_ptr = llvmlite.build_load(builder, self_entry.Alloca.Ty, self_entry.Alloca) - case _: - self_ptr = self_entry.Alloca - if self_ptr is None: - return None - # 3. this_adjust(字节偏移法:父类字段区在子类中的偏移差) - self_arg: llvmlite.Value | t.CPtr = self_ptr - if string.strcmp(anc, cur_class) != 0: - anc_entry_sp: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(anc) - if anc_entry_sp is not None and anc_entry_sp.FieldCount > 0: - first_name_sp: str = None - afi_sp: int = 0 - while afi_sp < anc_entry_sp.FieldCount: - afe_sp: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( - anc_entry_sp, afi_sp) - if afe_sp is not None: - afn_sp: str = HandlesStruct.get_field_name_ptr(afe_sp) - if afn_sp is not None and string.strcmp(afn_sp, "__vtable__") != 0: - first_name_sp = afn_sp - break - afi_sp += 1 - if first_name_sp is not None: - sub_entry_sp: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct( - cur_class) - if sub_entry_sp is not None: - anc_field_sp: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( - anc_entry_sp.Ty, first_name_sp) - sub_field_sp: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( - sub_entry_sp.Ty, first_name_sp) - if anc_field_sp is not None and sub_field_sp is not None: - anc_off_sp: int = self._field_byte_offset( - pool, anc_entry_sp, anc_field_sp.Index) - sub_off_sp: int = self._field_byte_offset( - pool, sub_entry_sp, sub_field_sp.Index) - delta_sp: int = sub_off_sp - anc_off_sp - if delta_sp > 0: - i8_ty_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_sp) - obj_i8_sp: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, self_ptr, i8_ptr_sp) - dval_sp: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, delta_sp) - adj_sp: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i8_ty_sp, obj_i8_sp, dval_sp) - if adj_sp is not None: - anc_ptr_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, anc_entry_sp.Ty) - # 同上:跨模块祖先类型 bitcast 前确保 opaque 声明, - # 否则 llc 报 "use of undefined type" - llvmlite.module_ensure_opaque_for_type(mod, pool, anc_ptr_sp) - self_arg = llvmlite.build_bitcast(builder, adj_sp, anc_ptr_sp) - # 4. 查找父类方法函数 + 构造调用名(SHA1 mangled) - anc_lookup: str = pool.alloc(160) - if anc_lookup is None: - return None - viperlib.snprintf(anc_lookup, 160, "%s.%s", anc, method_name) - found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, anc_lookup) - call_name: str = anc_lookup - anc_sha1_sp: str = HandlesStruct.get_struct_sha1(anc) - if anc_sha1_sp is None: - anc_sha1_sp = trans.ModuleSha1 - if found_func is not None: - fname_sp: str = llvmlite.function_get_name(found_func) - if fname_sp is not None: - call_name = fname_sp - else: - if anc_sha1_sp is not None: - mangled_sp: str = HandlesFunctions._mangle_name_with_sha1(anc_sha1_sp, anc_lookup) - if mangled_sp is not None: - call_name = mangled_sp - # 5. 翻译参数 + 按形参 coerce(self 是形参 0,第 ai 个实参对应形参 ai+1) - cargs_sp: list[ast.AST | t.CPtr] | t.CPtr = cl.args - can_sp: t.CSizeT = 0 - if cargs_sp is not None: - can_sp = len(cargs_sp) - llvmlite.value_set_next(self_arg, None) - head: llvmlite.Value | t.CPtr = self_arg - tail: llvmlite.Value | t.CPtr = self_arg - arg_count_sp: int = 1 - for ai_sp in range(can_sp): - arg_node_sp: ast.AST | t.CPtr = cargs_sp.get(ai_sp) - if arg_node_sp is None: - continue - arg_val_sp: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg_node_sp, None, 0, trans) - if arg_val_sp is None: - continue - if found_func is not None: - pp_sp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) - pi_sp: int = 0 - while pp_sp is not None and pi_sp < ai_sp + 1: - if pi_sp == ai_sp + 1: - break - pp_sp = llvmlite.param_get_next(pp_sp) - pi_sp += 1 - if pp_sp is not None: - pty_sp: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pp_sp) - if pty_sp is not None: - arg_val_sp = HandlesExpr.coerce_to_type( - builder, arg_val_sp, pty_sp, arg_node_sp) - else: - # found_func=None:数组实参按 C 语义衰减为元素指针 - # (与 _translate_method_call 一致,避免 declare 类型不匹配) - if arg_val_sp.Ty is not None and HandlesExpr.is_ptr_type(arg_val_sp.Ty) != 0: - arr_pointee_sp: llvmlite.LLVMType | t.CPtr = arg_val_sp.Ty.Pointee - if arr_pointee_sp is not None: - match arr_pointee_sp: - case llvmlite.LLVMType.Array(arr_et_sp, _): - decayed_sp: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, arr_pointee_sp, arr_et_sp, arg_val_sp, - llvmlite.const_int32(pool, 0)) - if decayed_sp is not None: - arg_val_sp = decayed_sp - case _: - pass - llvmlite.value_set_next(arg_val_sp, None) - llvmlite.value_set_next(tail, arg_val_sp) - tail = arg_val_sp - arg_count_sp += 1 - # 6. 返回类型:found_func → 特殊方法 → text.ll/vpi - ret_ty_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if found_func is not None: - frt_sp: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) - if frt_sp is not None: - ret_ty_sp = frt_sp - else: - sp_ty_sp: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty(pool, anc, method_name) - if sp_ty_sp is not None: - ret_ty_sp = sp_ty_sp - else: - looked_sp: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL( - pool, anc_sha1_sp, anc, method_name) - if looked_sp is not None: - ret_ty_sp = looked_sp - else: - vpi_ret_sp: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi( - pool, anc_sha1_sp, anc, method_name) - if vpi_ret_sp is not None: - ret_ty_sp = vpi_ret_sp - else: - # 查找链(函数/text.ll/vpi stub)全部未命中:fail-fast, - # 绝不静默保持默认 i32(会截断指针/i64 返回值) - # Phase A 依赖未就绪(anc_sha1_sp None / 定义模块 text.ll - # 未生成):标记 pending 下遍重译(对齐 L4783-4790), - # 绝不 fail-fast 中断多遍收敛;真实错误由收敛检查兜底。 - if anc_sha1_sp is None \ - or self._dep_text_ll_exists(pool, anc_sha1_sp) == 0: - if trans is not None: - trans._deps_pending = 1 - # 依赖未就绪:保持默认 i32(build_call(Void) 返回 None - # 会破坏表达式翻译;pending 文件本遍不写盘,下遍重译) - ret_ty_sp = llvmlite.Int32(pool) - else: - self._fail_method_ret_ty(method_name, cl) - # 7. 跨模块:创建 declare;生成 call - if found_func is None: - self._ensure_method_declare(pool, mod, call_name, ret_ty_sp, head, arg_count_sp) - is_variadic_sp: int = ExprCallCall._check_and_promote_variadic_call( - pool, builder, mod, call_name, head, arg_count_sp, cargs_sp, 1, trans) - return llvmlite.build_call(builder, call_name, head, arg_count_sp, ret_ty_sp, is_variadic_sp) - # ============================================================ - # _field_byte_offset — 计算字段在结构体布局中的字节偏移 - # - # 按 LLVM 布局遍历 struct elements 带对齐累加(与 ClassGenMixin._get_type_size - # 的 padding 规则一致)。field_index 是 FieldEntry.Index(OOP 类 __vtable__ 占 0)。 - # 供多继承 this 调整(字节偏移法)计算 delta。 - # ============================================================ - - # ============================================================ - def _field_byte_offset(self, pool: memhub.MemBuddy | t.CPtr, - entry: HandlesStruct.StructEntry | t.CPtr, - field_index: int) -> int: - """计算字段在结构体中的字节偏移(含对齐 padding),无法计算返回 0""" - if pool is None or entry is None or entry.Ty is None or field_index < 0: - return 0 - match entry.Ty: - case llvmlite.LLVMType.Struct(fields, fcount, name): - offset_fb: int = 0 - cur_fb: llvmlite.ParamNode | t.CPtr = fields - i_fb: int = 0 - while cur_fb is not None and i_fb < field_index: - if cur_fb.Ty is not None: - fty_fb: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(cur_fb.Ty) - fsize_fb: int = HandlesClassDef._get_type_size(fty_fb) - falign_fb: int = HandlesClassDef._get_type_align(fty_fb) - if falign_fb > 1: - rem_fb: int = offset_fb % falign_fb - if rem_fb != 0: - offset_fb += falign_fb - rem_fb - offset_fb += fsize_fb - cur_fb = cur_fb.Next - i_fb += 1 - # 字段自身对齐 - if cur_fb is not None and cur_fb.Ty is not None: - fty2_fb: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(cur_fb.Ty) - falign2_fb: int = HandlesClassDef._get_type_align(fty2_fb) - if falign2_fb > 1: - rem2_fb: int = offset_fb % falign2_fb - if rem2_fb != 0: - offset_fb += falign2_fb - rem2_fb - return offset_fb - case _: - return 0 - # ============================================================ - # _kwarg_name_matches — 检查关键字参数名是否匹配函数参数名 - # - # 函数参数名在 LLVM IR 中带 % 前缀(如 "%a"),关键字参数名无前缀(如 "a") - # 跳过 % 前缀后逐字符比较 - # ============================================================ - def _kwarg_name_matches(self, kw_arg: str, - param_name: str) -> int: - """检查关键字参数名 kw_arg 是否匹配参数名 param_name(跳过 % 前缀)""" - if kw_arg is None or param_name is None: - return 0 - start: t.CSizeT = 0 - if param_name[0] == '%': - start = 1 - for i, ch in enumerate(kw_arg): - c: t.CChar = param_name[start + i] - if c == '\0' or c != ch: - return 0 - if param_name[start + i + 1] != '\0': - return 0 +import lib.core.Gen.GenTypes as GenTypes +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import sys +import viperlib +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.CallGenBase as CallGenBase +import lib.core.Handles.ExprCallTable as ExprCallTable + +# ============================================================ +# CallGenCall - CallGenMixin 拆分(阶段 B):方法调用分派(含 super / 虚调用 / kwargs 名匹配) +# +# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class CallGenCall(CallGenBase.CallGenBase): + """方法调用分派(含 super / 虚调用 / kwargs 名匹配)""" + + # ============================================================ + # _do_virtual_call — 通过虚表间接调用虚方法 + # + # IR 模式: + # %1 = getelementptr StructTy, StructTy* %self, i32 0, i32 0 ; i8** + # %2 = load i8*, i8** %1 ; i8* (vtable ptr) + # %3 = bitcast i8* %2 to {i8*, ...}* ; vtable typed ptr + # %4 = getelementptr {i8*, ...}, {i8*, ...}* %3, i32 0, i32 N ; i8** + # %5 = load i8*, i8** %4 ; i8* (func ptr) + # %6 = bitcast i8* %5 to RetTy(Params)* ; func typed ptr + # call RetTy %6(Params %self, ...) + # + # 参数: + # args_head — 已构建好的参数链表头(self_ptr 为首节点) + # args_count — 参数总数(含 self) + # found_func — 方法对应的 Function 对象(用于推断函数签名) + # ret_ty — 返回类型 + # ============================================================ + + # ============================================================ + def _do_virtual_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, + method_name: str, + self_ptr: llvmlite.Value | t.CPtr, + args_head: llvmlite.Value | t.CPtr, + args_count: int, + found_func: llvmlite.Function | t.CPtr, + ret_ty: llvmlite.LLVMType | t.CPtr, + vtable_base: llvmlite.Value | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """通过虚表间接调用虚方法,返回 call 结果(void 方法返回 None) + + vtable_base: 对象头指针(vtable 所在位置,即未调整的 obj_ptr)。 + 多继承 this 调整后 self_ptr 可能前移(如 obj+4 指向父类字段区), + 从调整后位置读 vtable 会读到字段值 → 垃圾指针崩溃。默认 None 时 + vtable_base = self_ptr(未调整场景,读对象头)。 + """ + if pool is None or builder is None or class_name is None or method_name is None: + return None + if self_ptr is None or args_head is None: + return None + if vtable_base is None: + vtable_base = self_ptr + + # 1. 获取结构体类型(用 find_struct_by_type 规避跨模块同名 find_struct 找错) + vc_entry: GenTypes.StructEntry | t.CPtr = None + struct_ty: llvmlite.LLVMType | t.CPtr = None + if self_ptr.Ty is not None: + vc_entry = self.Gen.StructGen.get_struct_type_from_value(self_ptr) + if vc_entry is not None: + # vc_entry 是 struct_ty(LLVMType),需要找 StructEntry + vc_entry = self.Gen.StructGen.find_struct_by_type(vc_entry) + if vc_entry is not None: + struct_ty = vc_entry.Ty + if struct_ty is None: + struct_ty = self.Gen.StructGen.get_struct_type(class_name) + if struct_ty is None: + return None + + # 2. 获取方法在虚表中的索引(用 entry 直接查找) + method_index: int = -1 + if vc_entry is not None and vc_entry.VTableMethods is not None: + methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(vc_entry.VTableMethods, t.CPtr)) + for mi in range(vc_entry.VTableMethodCount): + mname_addr: t.CSizeT = methods_arr[mi] + if mname_addr == 0: + continue + mname: str = (str | t.CPtr)(t.CVoid(mname_addr, t.CPtr)) + if mname is not None and string.strcmp(mname, method_name) == 0: + method_index = mi + break + else: + method_index = self.Gen.StructGen.get_vtable_method_index(class_name, method_name) + if method_index < 0: + return None + + # 3. 基础类型 + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty) + + # 4. bitcast 到 i8** 访问 __vtable__ 字段(索引 0) + # vtable 指针总是在对象第一个字段,无需 GEP,直接 bitcast 到 i8** 即可。 + # 这样即使 struct_ty 是 opaque(跨模块未加载完整定义)也能正常工作。 + # 注意用 vtable_base(对象头)而非 self_ptr:多继承 this 调整后 + # self_ptr 已前移,其头部不是 vtable 而是父类字段值。 + vtable_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, vtable_base, i8_ptr_ptr_ty) + if vtable_slot is None: + return None + + # 5. load vtable 指针 (i8*) + vtable_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, vtable_slot) + if vtable_ptr is None: + return None + + # 6. 构造 vtable 类型 {i8*, i8*, ...} + method_count: int = 0 + if vc_entry is not None: + method_count = vc_entry.VTableMethodCount + else: + method_count = self.Gen.StructGen.get_vtable_method_count(class_name) + if method_count <= 0: + return None + + vt_first: llvmlite.ParamNode | t.CPtr = None + vt_prev: llvmlite.ParamNode | t.CPtr = None + for vi in range(method_count): + pn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) + if pn is None: + continue + if vt_first is None: + vt_first = pn + if vt_prev is not None: + llvmlite.paramnode_set_next(vt_prev, pn) + vt_prev = pn + + vtable_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, vt_first, method_count, None) + if vtable_ty is None: + return None + vtable_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, vtable_ty) + + # 7. bitcast i8* 到 vtable 类型指针 + vtable_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, vtable_ptr, vtable_ptr_ty) + if vtable_typed is None: + return None + + # 8. GEP 到方法槽位 + func_slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, vtable_ty, i8_ptr_ty, vtable_typed, method_index) + if func_slot is None: + return None + + # 9. load 函数指针 (i8*) + func_i8: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, func_slot) + if func_i8 is None: + return None + + # 10. 从 args_head 构造函数类型 RetTy(Param1, Param2, ...) + # 直接遍历 Value 链表提取参数类型,避免跨模块访问 found_func(stub 字段偏移问题) + fp_first: llvmlite.ParamNode | t.CPtr = None + fp_prev: llvmlite.ParamNode | t.CPtr = None + fp_count: int = 0 + cur_val: llvmlite.Value | t.CPtr = args_head + for vi in range(args_count): + if cur_val is None: + break + cur_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(cur_val) + fpn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, cur_ty) + if fpn is not None: + if fp_first is None: + fp_first = fpn + if fp_prev is not None: + llvmlite.paramnode_set_next(fp_prev, fpn) + fp_prev = fpn + cur_val = llvmlite.value_get_next(cur_val) + fp_count += 1 + + func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, ret_ty, fp_first, fp_count) + if func_ty is None: + return None + func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty) + + # 11. bitcast i8* 到函数指针类型 + func_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, func_i8, func_ptr_ty) + if func_ptr is None: + return None + + # 12. 间接调用 + return llvmlite.build_call_indirect(builder, func_ptr, args_head, args_count, ret_ty) + # ============================================================ + # _call_method_on_ptr — 在结构体指针上调用方法 + # + # 辅助函数:构造 ClassName.method_name 调用,self 指针为首个参数 + # 如果该方法在虚表中,则走虚方法分发路径(间接调用) + # ============================================================ + + # ============================================================ + def _call_method_on_ptr(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, + method_name: str, + self_ptr: llvmlite.Value | t.CPtr, + extra_args: t.CSizeT | t.CPtr, + extra_count: int, + trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """在结构体指针上调用方法,返回 call 结果(void 方法返回 None) + + node: 触发本次调用的 AST 节点(如 Subscript 下标节点),用于 fatal_error + 准确报告出错行号(传 None 时行号显示 0,不利于定位)。""" + if pool is None or builder is None or class_name is None or method_name is None: + return None + if self_ptr is None: + return None + + # 提前获取结构体 entry(用 find_struct_by_type 规避跨模块同名 find_struct 找错) + # 用于 SHA1 查找和虚表分派 + cmop_entry: GenTypes.StructEntry | t.CPtr = None + cmop_struct_ty: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type_from_value(self_ptr) + if cmop_struct_ty is not None: + cmop_entry = self.Gen.StructGen.find_struct_by_type(cmop_struct_ty) + if cmop_entry is None: + cmop_entry = self.Gen.StructGen.find_struct(class_name) + # fallback: 若 cmop_struct_ty 为 None 但 entry 存在,从 entry 获取类型 + # 用于跨模块调用时 self_ptr 类型信息丢失的情况 + if cmop_struct_ty is None and cmop_entry is not None: + cmop_struct_ty = cmop_entry.Ty + + # 构造方法查找名: ClassName.method_name + lookup_name: str = pool.alloc(128) + if lookup_name is None: + return None + viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name) + + # 查找函数(支持 SHA1 后缀匹配) + found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, lookup_name) + + # 确定调用名 + call_name: str = lookup_name + if found_func is not None: + found_name: str = llvmlite.function_get_name(found_func) + if found_name is not None: + call_name = found_name + else: + # found_func 为 None(stub 未注入):用类所属模块的 SHA1 构造调用名 + # 优先从 entry 获取 SHA1(规避跨模块同名 find_struct 找错) + cls_sha1: str = None + if cmop_entry is not None: + cls_sha1 = cmop_entry.ModuleSha1 + else: + cls_sha1 = self.Gen.StructGen.get_struct_sha1(class_name) + if cls_sha1 is None and trans is not None: + # fallback: 从 from_imports 查找类所属模块的 SHA1(含截断处理) + cls_sha1 = self._lookup_mod_sha1(pool, trans._from_imports, class_name) + if cls_sha1 is None: + err_msg: str = pool.alloc(256) + if err_msg is not None: + viperlib.snprintf(err_msg, 256, "类 '%s' 方法 '%s' 找不到模块 SHA1", class_name, method_name) + self.Gen.TypeGenErr.fatal_error(node, err_msg) + self.Gen.TypeGenErr.fatal_error(node, "找不到模块 SHA1") + mangled_len2: t.CSizeT = string.strlen(cls_sha1) + string.strlen(lookup_name) + 2 + mangled2: str = pool.alloc(mangled_len2) + if mangled2 is not None: + viperlib.snprintf(mangled2, mangled_len2, "%s.%s", cls_sha1, lookup_name) + call_name = mangled2 + + # 确定返回类型(__before_init__ 和 __init__ 返回 void) + void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + call_ret_ty: llvmlite.LLVMType | t.CPtr = void_ty + if found_func is not None: + frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) + if frt is not None: + call_ret_ty = frt + elif string.strcmp(method_name, "__getitem__") == 0 or string.strcmp(method_name, "__new__") == 0: + # fail-fast:__getitem__/__new__ 必返回指针,返回类型缺失意味着 + # stub declare 损坏,静默推断会截断指针(32 位)崩溃,立即终止。 + err_cm1: str = pool.alloc(256) + if err_cm1 is not None: + viperlib.snprintf(err_cm1, 256, + "方法 '%s' 返回类型无法确定(stub declare 返回类型缺失)", method_name) + self.Gen.TypeGenErr.fatal_error(node, err_cm1) + self.Gen.TypeGenErr.fatal_error(node, "方法返回类型无法确定") + else: + # found_func 为 None(跨模块调用 stub 未注入):无法从 declare 获取返回类型。 + # __before_init__/__init__ 是编译器生成/约定方法(vpi stub 无条目): + # 恒返回 void(对齐 _special_method_ret_ty L3196-3198),直接固定, + # 否则走 text.ll/vpi 解析失败 → fail-fast 误报 + # (CPythonTest PyLongObj() 构造:类未定义 __init__/__before_init__ + # 但实例化仍生成调用 → "PyLongObj.__before_init__ 返回类型无法确定"根因)。 + if string.strcmp(method_name, "__before_init__") == 0 or \ + string.strcmp(method_name, "__init__") == 0: + call_ret_ty = void_ty + # __new__ 返回 Ptr(struct_ty)(构造函数返回自身指针,可推断)。 + # __getitem__ 返回类型无法从 self 推断(可返回 i8* 如 HashTable.__getitem__ + # -> t.CPtr,或 Ptr(JsonValue) 如 JsonValue.__getitem__)——推断 Ptr(cmop_struct_ty) + # 会与 define 返回类型不匹配,调用侧按错误类型读取返回值导致指针截断崩溃。 + # fail-fast:__getitem__ 无 stub declare 立即报错,暴露依赖模块 vpi 缺失或 + # 拓扑顺序错误(依赖模块未先翻译生成 vpi/text.ll)。 + elif string.strcmp(method_name, "__new__") == 0: + if cmop_struct_ty is not None: + call_ret_ty = llvmlite.Ptr(pool, cmop_struct_ty) + else: + err_cm2: str = pool.alloc(256) + if err_cm2 is not None: + viperlib.snprintf(err_cm2, 256, + "方法 '%s' 的 self 结构体类型未知(字段类型退化,依赖模块未预注册?)", method_name) + self.Gen.TypeGenErr.fatal_error(node, err_cm2) + self.Gen.TypeGenErr.fatal_error(node, "self 结构体类型未知") + elif string.strcmp(method_name, "__getitem__") == 0: + err_cm3: str = pool.alloc(256) + if err_cm3 is not None: + viperlib.snprintf(err_cm3, 256, + "方法 '%s.__getitem__' 的 stub declare 未注入(依赖模块 vpi 缺失或拓扑顺序错误),无法确定返回类型", + class_name) + self.Gen.TypeGenErr.fatal_error(node, err_cm3) + self.Gen.TypeGenErr.fatal_error(node, "__getitem__ stub declare 未注入") + else: + # 其它跨模块方法(泛型特化方法必然无 stub declare):旧实现静默 + # 保持 void → 幽灵 "call void @...__add__" + 调用方(如运算符 + # 重载 try_operator_overload)回退原生运算双重发射 → llc invalid + # operand type for instruction(NumpyTest a+b 根因)。用 text.ll + # → vpi 精确解析返回类型(对齐 _translate_method_call L4641); + # 都失败则 fail-fast,绝不静默 void。 + ret_cm: llvmlite.LLVMType | t.CPtr = None + if cls_sha1 is not None: + ret_cm = self._LookupMethodRetTyFromTextLL( + pool, cls_sha1, class_name, method_name) + if ret_cm is None and cls_sha1 is not None: + ret_cm = self._lookup_method_ret_ty_via_vpi( + pool, cls_sha1, class_name, method_name) + if ret_cm is not None: + call_ret_ty = ret_cm + else: + # Phase A 依赖 text.ll 未生成(方法定义模块尚未翻译)→ 标记重试, + # 保持默认类型继续(对齐 _translate_method_call L4760-4773 与跨模块 + # 函数路径 L8167-8195 的 _deps_pending 机制;本函数同样服务 Mixin + # 跨模块方法调用,如 BuildPipeline gen.extract_module_docstrings) + # cls_sha1 为 None 同样视为依赖未就绪(pass1 定义类/祖先未注册 + # 连 sha1 都取不到,对齐 _translate_method_call L4778-4785) + if cls_sha1 is None \ + or (cls_sha1 is not None + and self._dep_text_ll_exists(pool, cls_sha1) == 0): + if trans is not None: + trans._deps_pending = 1 + # 依赖未就绪:保持默认 i32(build_call(Void) 返回 None 会 + # 破坏表达式翻译;pending 文件本遍不写盘,下遍重译) + call_ret_ty = llvmlite.Int32(pool) + else: + err_cm4: str = pool.alloc(256) + if err_cm4 is not None: + viperlib.snprintf(err_cm4, 256, + "方法 '%s.%s' 返回类型无法确定(text.ll/vpi 均未命中,跨模块 stub 未注入)", + class_name, method_name) + self.Gen.TypeGenErr.fatal_error(node, err_cm4) + self.Gen.TypeGenErr.fatal_error(node, "方法返回类型无法确定") + + # 构建参数链表: self_ptr → extra_args... + llvmlite.value_set_next(self_ptr, None) + head: llvmlite.Value | t.CPtr = self_ptr + tail: llvmlite.Value | t.CPtr = self_ptr + + if extra_args is not None and extra_count > 0: + for ei in range(extra_count): + arg_addr: t.CSizeT = extra_args[ei] + if arg_addr == 0: + continue + av: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)(t.CVoid(arg_addr, t.CPtr)) + if av is not None: + llvmlite.value_set_next(av, None) + llvmlite.value_set_next(tail, av) + tail = av + + total_count: int = 1 + extra_count + + # 默认参数填充:如果调用点参数少于函数定义参数,用默认值填充缺失参数 + # 优先用函数定义的默认值,无默认值时用零值兜底 + # 查找函数的 defaults 信息 + mdf_defaults: t.CVoid | t.CPtr = None + mdf_default_count: int = 0 + mdf_param_count: int = 0 + if trans is not None and trans._funcs is not None: + mdf_entry: FuncEntry | t.CPtr = ExprCallTable.find_func_entry_in_table( + trans._funcs, trans._func_count, lookup_name) + if mdf_entry is not None: + mdf_defaults = mdf_entry.Defaults + mdf_default_count = mdf_entry.DefaultCount + mdf_param_count = mdf_entry.ParamCount + # 全局默认参数表查询无条件执行:mdf_entry 命中时(泛型特化方法注册进 + # 调用方函数表)Defaults 非 None 会短路跳过,但下方"用快照重建默认值" + # 分支依赖 mdf_gd(唯一持有 stdlib 常量快照处)——缺它必 fatal_error + # (ListTest list[int].__new__ 根因) + mdf_gd: FuncDefaultsEntry | t.CPtr = self.Gen.CallGenLeafKit.find_func_defaults(lookup_name) + if mdf_defaults is None and mdf_gd is not None: + mdf_defaults = mdf_gd.Defaults + mdf_default_count = mdf_gd.DefaultCount + mdf_param_count = mdf_gd.ParamCount + + # 计算需要填充的参数(不含 self) + # extra_count = 已提供的非 self 参数数量 + # mdf_param_count = 函数定义的非 self 参数数量 + if mdf_param_count > extra_count: + mdf_offset: int = mdf_param_count - mdf_default_count + mdf_pi: int = extra_count + while mdf_pi < mdf_param_count: + # 优先用默认值 + if mdf_defaults is not None and mdf_default_count > 0 and mdf_pi >= mdf_offset: + mdf_di: int = mdf_pi - mdf_offset + if mdf_di < mdf_default_count: + # 用 stdlib 常量快照重建(mdf_gd.Defaults 的 pool 内 AST 可能已被 reset 回收, + # 直接回退读 AST 会 use-after-free——快照失败时 fail-fast 暴露,绝不读悬空 AST) + mdf_val: llvmlite.Value | t.CPtr = None + if mdf_gd is not None: + mdf_val = self.Gen.CallGenLeafKit._build_const_from_snapshot( + pool, mod, mdf_gd, mdf_di, trans, builder) + if mdf_val is None: + # 用 node(本函数报错行号节点,如构造实参/源码 Call)而非 cl—— + # cl 在本函数未定义(无该参数),读取垃圾指针导致 fatal_error + # 显示 "line 0"(FileIoTest File.__init__ 报错行号丢失根因) + self.Gen.TypeGenErr.fatal_error( + node, + f"跨模块默认参数无法重建(快照缺失,默认值需为简单常量): {lookup_name}", + "TypeError") + continue + llvmlite.value_set_next(mdf_val, None) + llvmlite.value_set_next(tail, mdf_val) + tail = mdf_val + total_count += 1 + mdf_pi += 1 + continue + # 无默认值时用零值兜底(需要 found_func 获取参数类型)。 + # 默认参数表按裸名注册(如 "__init__"),跨模块 "ClassName.method" + # 查找常查不到——查不到 ≠ 无默认值(如 Buf.__init__(data, capacity) + # 缺的 length=0/owned=False 恰为零值),零值兜底语义一致。 + if found_func is not None: + param_node_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + skip_z: int = 0 + while skip_z <= mdf_pi and param_node_z is not None: + param_node_z = llvmlite.param_get_next(param_node_z) + skip_z += 1 + if param_node_z is not None: + zero_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node_z) + zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, zero_ty) + if zero_val is not None: + llvmlite.value_set_next(zero_val, None) + llvmlite.value_set_next(tail, zero_val) + tail = zero_val + total_count += 1 + mdf_pi += 1 + elif found_func is not None: + # 无默认参数信息但有 found_func:用零值兜底填充缺失参数 + # (原逻辑;禁止 fail-fast 误杀——同上,查不到默认参数表 ≠ 无默认值) + param_node: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + skip_idx: int = 0 + while skip_idx < total_count and param_node is not None: + param_node = llvmlite.param_get_next(param_node) + skip_idx += 1 + while param_node is not None: + missing_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node) + zero_val2: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, missing_ty) + if zero_val2 is not None: + llvmlite.value_set_next(zero_val2, None) + llvmlite.value_set_next(tail, zero_val2) + tail = zero_val2 + total_count += 1 + param_node = llvmlite.param_get_next(param_node) + + # 参数类型强制转换:按 found_func 的形参类型 coerce 每个实参(含 self)。 + # 修复: 构造器调用 __init__(ptr, base, 4096) 时 size 形参是 i64 (t.CSizeT), + # 但 4096 字面量按 i32 传递,未提升导致运行时 size 高 32 位垃圾, + # 破坏伙伴分配器的池大小元数据(如 total=2048)引发 calloc 失败/OOM。 + # self 在运算符重载路径 2(lhs 为 X|t.CPtr 联合简化的 Vec3** 对象指针)时 + # 与形参 Vec3* 不匹配,需 bitcast(coerce 指针→指针生成 bitcast), + # 否则 call 参数类型与声明不一致 llc 报错。 + if found_func is not None and head is not None: + pc_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + pc_node: llvmlite.Value | t.CPtr = head + new_head_pc: llvmlite.Value | t.CPtr = head + prev_pc: llvmlite.Value | t.CPtr = None + while pc_node is not None: + pc_next_save: llvmlite.Value | t.CPtr = pc_node.Next + coerced_pc: llvmlite.Value | t.CPtr = pc_node + if pc_param is not None: + pty_pc: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pc_param) + if pty_pc is not None: + c_pc: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type( + builder, pc_node, pty_pc, None) + if c_pc is not None: + coerced_pc = c_pc + pc_param = llvmlite.param_get_next(pc_param) + coerced_pc.Next = None + if prev_pc is None: + new_head_pc = coerced_pc + else: + prev_pc.Next = coerced_pc + prev_pc = coerced_pc + pc_node = pc_next_save + head = new_head_pc + + # 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用 + # 复用前面已获取的 cmop_entry(find_struct_by_type 规避跨模块同名找错) + if found_func is not None: + cmop_has_vt: int = 0 + cmop_method_idx: int = -1 + if cmop_entry is not None: + cmop_has_vt = cmop_entry.HasVTable + if cmop_has_vt == 1 and cmop_entry.VTableMethods is not None: + cmop_methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(cmop_entry.VTableMethods, t.CPtr)) + for cmop_mi in range(cmop_entry.VTableMethodCount): + cmop_mname_addr: t.CSizeT = cmop_methods_arr[cmop_mi] + if cmop_mname_addr == 0: + continue + cmop_mname: str = (str | t.CPtr)(t.CVoid(cmop_mname_addr, t.CPtr)) + if cmop_mname is not None and string.strcmp(cmop_mname, method_name) == 0: + cmop_method_idx = cmop_mi + break + if cmop_has_vt == 1 and cmop_method_idx >= 0: + return self._do_virtual_call(pool, builder, mod, class_name, method_name, + self_ptr, head, total_count, found_func, call_ret_ty) + # 防御:返回类型为 i0(0 位整数)时 fail-fast,绝不输出非法 IR。 + # 根因已修(gen_done 成功后不再读未初始化的 looked_up_ty,见 L3970); + # 此兜底防止未来任何路径产出零值 LLVMType 导致 llc + # "bitwidth for integer type out of range"。 + if call_ret_ty is not None: + cd_i0: int = 0 + match call_ret_ty: + case llvmlite.LLVMType.Int(bits): + if bits == 0: + cd_i0 = 1 + case _: + pass + if cd_i0 != 0: + call_ret_ty = self._fail_method_ret_ty(method_name, node) + # 跨模块调用(found_func 为 None):创建 declare 声明,避免 llc 报 undefined value + if found_func is None: + self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, total_count) + + return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, 0) + # ============================================================ + # _translate_method_call - 翻译方法调用 obj.method(args) + # + # 生成: call @SHA1.ClassName.method_name(Ptr(StructTy) %obj, args...) + # + # obj_ptr 是对象变量的 alloca(Ptr(StructTy)),作为 self 参数传入 + # ============================================================ + + # ============================================================ + def _translate_method_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, + method_name: str, + obj_ptr: llvmlite.Value | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """翻译方法调用,返回 call 结果 Value""" + if pool is None or builder is None or class_name is None or method_name is None: + return None + if obj_ptr is None or cl is None: + return None + + # 提前获取结构体 entry(用 find_struct_by_type 规避跨模块同名 find_struct 找错) + # 用于继承链遍历、SHA1 查找和虚表分派 + mc_entry: GenTypes.StructEntry | t.CPtr = None + mc_struct_ty: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type_from_value(obj_ptr) + if mc_struct_ty is not None: + mc_entry = self.Gen.StructGen.find_struct_by_type(mc_struct_ty) + if mc_entry is None: + mc_entry = self.Gen.StructGen.find_struct(class_name) + + # 构造方法查找名: ClassName.method_name + lookup_name: str = pool.alloc(128) + if lookup_name is None: + return None + viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name) + + # 查找函数(支持 SHA1 后缀匹配) + found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, lookup_name) + + # 泛型模板类方法:特化函数名带类型参数({sha1}.list[int].get), + # "ClassName.method" 短名匹配不到。特化由触发方(通常即调用方)模块完成, + # 用对象实际特化名(mc_entry.Name)构造后缀匹配,获得精确返回类型。 + if found_func is None and mc_entry is not None and mc_entry.Name is not None: + if string.strcmp(mc_entry.Name, class_name) != 0: + spec_lookup: str = pool.alloc(160) + if spec_lookup is not None: + viperlib.snprintf(spec_lookup, 160, "%s.%s", mc_entry.Name, method_name) + found_func = self.find_func_in_module(mod, spec_lookup) + + # 沿 MRO 祖先链查找父类方法(子类未覆盖时回退到父类,先声明父类优先) + mc_anc: str = None # 方法实际定义类(多继承 this 调整用) + if found_func is None: + mro_ptr: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, class_name) + mi: int = 1 + while mro_ptr is not None and mro_ptr[mi] != 0: + anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr)) + if anc is not None: + parent_lookup: str = pool.alloc(128) + if parent_lookup is not None: + viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, method_name) + parent_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, parent_lookup) + if parent_func is not None: + found_func = parent_func + mc_anc = anc + break + mi += 1 + + # 兄弟 Mixin 兜底(与 TPC HandlesExprCall 一致):方法不在本类 MRO 链 + # (如 BaseB 内 self.helper() 调兄弟 BaseA.helper,BaseB 无 BaseA 的 + # 继承信息)。遍历已注册 struct 表找定义类方法,this 由下方 + # _adjust_this_for_inherited_method 按组合布局前移 sizeof(定义类)。 + # 注意:仅对普通类名兜底——泛型特化类名(list[X] / dict[K,V])是 + # 模板生成的特殊容器,其特化函数(如 list[ASTptr].__getitem__)虽 + # 在模块中存在,但绝非"兄弟 Mixin"(NoVTableCrossMixinTest 的 + # BaseA/BaseB/Combined 场景)。若不过滤,JsonValue.__getitem__ 等 + # 普通方法调用在 found_func 未命中时会误绑定到 list 特化函数, + # this 按 list 布局前移 sizeof(list) → 运行期读 -1 崩溃 + # (Config.vp Load_project_config root.__getitem__ 根因)。 + if found_func is None: + sc_i: int = 0 + sc_n: int = self.Gen.StructGen.get_struct_count() + while sc_i < sc_n and found_func is None: + cand_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen._get_struct_entry(sc_i) + if cand_entry is not None and cand_entry.Name is not None: + cand_name: str = cand_entry.Name + if string.strcmp(cand_name, class_name) != 0: + # 泛型特化类名含 '['(list[...]/dict[...]):跳过, + # 不是兄弟 Mixin 候选(见上方注释) + if string.strchr(cand_name, '[') is not None: + sc_i += 1 + continue + cand_lookup: str = pool.alloc(128) + if cand_lookup is not None: + viperlib.snprintf(cand_lookup, 128, "%s.%s", cand_name, method_name) + cand_func: llvmlite.Function | t.CPtr = self.find_func_in_module( + mod, cand_lookup) + if cand_func is not None: + found_func = cand_func + mc_anc = cand_name + sc_i += 1 + + # 确定调用名(默认 "ClassName.method";found_func 未命中时沿 MRO 用 + # 方法实际定义类的 SHA1 构造,如 Module.append → AST 定义的 append, + # 函数名为 {AST_sha1}.AST.append) + call_name: str = lookup_name + if found_func is not None: + found_name: str = llvmlite.function_get_name(found_func) + if found_name is not None: + call_name = found_name + + # 确定返回类型 + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + call_ret_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if found_func is not None: + frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) + if frt is not None: + call_ret_ty = frt + else: + # found_func 为 None(stub 未注入):先处理编译器内置特殊方法 + sp_ty2: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty(pool, class_name, method_name) + if sp_ty2 is not None: + call_ret_ty = sp_ty2 + # 特殊方法(__before_init__ 等)跨模块调用同样需带 sha1 前缀: + # memhub.alloc_buf 显式调 buf.__before_init__(),buf 是 viperio.Buf*, + # 若用裸名 @Buf.__before_init__ 链接 undefined symbol。用 + # mc_entry.ModuleSha1 / get_struct_sha1 / 类型名提取 sha1 构造 + # {sha1}.Buf.__before_init__。 + sp_anc_name: str = class_name + sp_anc_sha1: str = None + if mc_entry is not None: + sp_anc_sha1 = mc_entry.ModuleSha1 + else: + sp_anc_sha1 = self.Gen.StructGen.get_struct_sha1(class_name) + if sp_anc_sha1 is None and mc_struct_ty is not None: + match mc_struct_ty: + case llvmlite.LLVMType.Struct(_fs_sp, _fc_sp, type_name_sp): + if type_name_sp is not None and type_name_sp[0] != '\0': + tl_sp: t.CSizeT = string.strlen(type_name_sp) + if tl_sp >= 16: + sb_sp: str = pool.alloc(17) + if sb_sp is not None: + string.strncpy(sb_sp, type_name_sp, 16) + sb_sp[16] = '\0' + sp_anc_sha1 = sb_sp + case _: + pass + if sp_anc_sha1 is not None: + ml_sp: t.CSizeT = string.strlen(sp_anc_sha1) + string.strlen(sp_anc_name) \ + + string.strlen(method_name) + 3 + mangled_sp: str = pool.alloc(ml_sp) + if mangled_sp is not None: + viperlib.snprintf(mangled_sp, ml_sp, "%s.%s.%s", + sp_anc_sha1, sp_anc_name, method_name) + call_name = mangled_sp + else: + # 方法实际定义类(跨模块调用名/返回类型来源;Module.append 定义在 AST) + # 默认 class_name 自身,MRO fallback 命中祖先类时更新 + ret_anc_name: str = class_name + ret_anc_sha1: str = None + if mc_entry is not None: + ret_anc_sha1 = mc_entry.ModuleSha1 + else: + ret_anc_sha1 = self.Gen.StructGen.get_struct_sha1(class_name) + if ret_anc_sha1 is None: + # 沿 MRO 找第一个有 SHA1 的类 + mro_s0: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, class_name) + mi_s0: int = 1 + while mro_s0 is not None and mro_s0[mi_s0] != 0 and ret_anc_sha1 is None: + anc_s0: str = (str | t.CPtr)(t.CVoid(mro_s0[mi_s0], t.CPtr)) + if anc_s0 is not None: + ret_anc_sha1 = self.Gen.StructGen.get_struct_sha1(anc_s0) + mi_s0 += 1 + + # 泛型特化方法调用:特化函数可能尚未注册(如 ast.base 用 + # list[AST|t.CPtr].get)。主动触发特化(幂等,MethodsEmitted 防重入), + # 特化后重新查找即可命中,返回类型来自特化函数定义(天然精确)。 + gen_done: int = 0 + # text.ll 查找结果提升为函数级并显式初始化:gen_done==1 成功时 + # 下方回退段不执行,若在此声明则读到未初始化的池内存垃圾(非 NULL), + # 把已正确解析的 call_ret_ty(特化 define 的 i32)覆盖成垃圾零值 + # LLVMType → build_call 输出 call i0(llc bitwidth out of range)。 + looked_up_ty: llvmlite.LLVMType | t.CPtr = None + if class_name is not None: + lbkt_g: str = string.strchr(class_name, '[') + if lbkt_g is not None: + rbkt_g: str = string.strrchr(class_name, ']') + if rbkt_g is not None and rbkt_g > lbkt_g: + base_len_g: t.CSizeT = t.CSizeT(t.CUInt64T(lbkt_g) - t.CUInt64T(class_name)) + arg_len_g: t.CSizeT = t.CSizeT(t.CUInt64T(rbkt_g) - t.CUInt64T(lbkt_g) - 1) + if base_len_g > 0 and arg_len_g > 0: + base_buf_g: str = pool.alloc(base_len_g + 1) + arg_buf_g: str = pool.alloc(arg_len_g + 1) + if base_buf_g is not None and arg_buf_g is not None: + string.strncpy(base_buf_g, class_name, base_len_g) + base_buf_g[base_len_g] = '\0' + string.strncpy(arg_buf_g, lbkt_g + 1, arg_len_g) + arg_buf_g[arg_len_g] = '\0' + ta_list_g: list[str] | t.CPtr = list[str](pool, 8) + if ta_list_g is not None: + # 逗号分隔多类型实参(list[X] / dict[K, V]) + cur_arg_g: str = arg_buf_g + while cur_arg_g is not None: + comma_g: str = string.strchr(cur_arg_g, ',') + if comma_g is None: + ta_list_g.append(cur_arg_g) + break + seg_len_g: t.CSizeT = t.CSizeT(t.CUInt64T(comma_g) - t.CUInt64T(cur_arg_g)) + seg_buf_g: str = pool.alloc(seg_len_g + 1) + if seg_buf_g is not None: + string.strncpy(seg_buf_g, cur_arg_g, seg_len_g) + seg_buf_g[seg_len_g] = '\0' + ta_list_g.append(seg_buf_g) + cur_arg_g = comma_g + 1 + spec_name_g: str = self.Gen.ClassGenGeneric._specialize_generic_class( + trans, base_buf_g, ta_list_g) + if spec_name_g is not None: + # 特化后重新查找特化函数(特化名 = 调用点类名) + spec_lk_g: str = pool.alloc( + string.strlen(class_name) + string.strlen(method_name) + 2) + if spec_lk_g is not None: + viperlib.snprintf(spec_lk_g, + string.strlen(class_name) + string.strlen(method_name) + 2, + "%s.%s", class_name, method_name) + spec_found_g: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, spec_lk_g) + if spec_found_g is not None: + frt_g: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(spec_found_g) + if frt_g is not None: + call_ret_ty = frt_g + found_func = spec_found_g + gen_done = 1 + if gen_done == 0: + # 尝试从 text.ll 查找实际返回类型 + # 避免指针返回值被默认 i32 导致 inttoptr 截断 + looked_up_ty = self._LookupMethodRetTyFromTextLL( + pool, ret_anc_sha1, ret_anc_name, method_name) + # 沿 MRO 祖先链重试:方法可能定义在基类(如 Module.append → + # AST.append,函数名 {ast_sha1}.AST.append,且基类在另一模块文件 + # 如 ast/stmts.vp 的 Module vs ast/base.vp 的 AST),按调用类名 + # 及其 sha1 查不到,需用每个祖先类的类名 + 祖先类所属模块 sha1 + # 查 text.ll(NewAstTest mod.append 根因) + if looked_up_ty is None: + mro_t2: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, class_name) + mi_t2: int = 1 + while mro_t2 is not None and mro_t2[mi_t2] != 0 and looked_up_ty is None: + anc_t2: str = (str | t.CPtr)(t.CVoid(mro_t2[mi_t2], t.CPtr)) + if anc_t2 is not None and string.strcmp(anc_t2, class_name) != 0: + anc_sha1_t2: str = self.Gen.StructGen.get_struct_sha1(anc_t2) + looked_up_ty = self._LookupMethodRetTyFromTextLL( + pool, anc_sha1_t2, anc_t2, method_name) + if looked_up_ty is not None: + ret_anc_name = anc_t2 + ret_anc_sha1 = anc_sha1_t2 + mi_t2 += 1 + if gen_done == 0 and looked_up_ty is not None: + call_ret_ty = looked_up_ty + elif gen_done == 0: + # 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单) + vpi_ret_ty: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi( + pool, ret_anc_sha1, ret_anc_name, method_name) + # vpi 同样沿 MRO 祖先链重试(基类方法注解,用祖先类自身 sha1) + if vpi_ret_ty is None: + mro_v2: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, class_name) + mi_v2: int = 1 + while mro_v2 is not None and mro_v2[mi_v2] != 0 and vpi_ret_ty is None: + anc_v2: str = (str | t.CPtr)(t.CVoid(mro_v2[mi_v2], t.CPtr)) + if anc_v2 is not None and string.strcmp(anc_v2, class_name) != 0: + anc_sha1_v2: str = self.Gen.StructGen.get_struct_sha1(anc_v2) + vpi_ret_ty = self._lookup_method_ret_ty_via_vpi( + pool, anc_sha1_v2, anc_v2, method_name) + if vpi_ret_ty is not None: + ret_anc_name = anc_v2 + ret_anc_sha1 = anc_sha1_v2 + mi_v2 += 1 + if vpi_ret_ty is not None: + call_ret_ty = vpi_ret_ty + else: + # Phase A 依赖 text.ll 未生成(方法定义模块尚未翻译)→ 标记 + # 重试,保持默认类型继续(下遍依赖生成后可精确解析),对齐跨模块 + # 函数路径 L8167-8195 的 _deps_pending 机制。BuildPipeline.vp + # L216 gen.extract_module_docstrings 根因:方法定义在 + # ExprGenMixin(Mixin 模块),Phase A 顺序中 ExprGenMixin 的 + # text.ll 尚未生成 → MRO 链查找全部未命中 → fail-fast 误报。 + # ret_anc_sha1 为 None 同样视为依赖未就绪:pass1 中 Generator + # 及其 Mixin 全部 defer(依赖 Handles/* 未翻译)→ 结构体未注册 + # → get_struct_sha1/MRO 查找全空 → 连 sha1 都取不到 + # (g._register_cdefine_from_value 根因)。标记 _deps_pending + # 下遍重译,绝不 fail-fast 中断多遍收敛;真实错误由收敛检查兜底。 + if ret_anc_sha1 is None \ + or (ret_anc_sha1 is not None + and self._dep_text_ll_exists(pool, ret_anc_sha1) == 0): + if trans is not None: + trans._deps_pending = 1 + # 依赖未就绪:保持默认 i32 继续而非 Void——build_call(Void) + # 返回 None,方法调用结果喂进表达式(if 条件/比较)时 fatal + # "if 条件表达式翻译失败"(ExprGenAttr._get_cderef_attr_base + # 根因)。本遍不写盘、下遍重译精确解析,错误类型不会进入 + # 产物(对齐跨模块函数路径 L8167-8195"保持默认类型继续")。 + call_ret_ty = llvmlite.Int32(pool) + else: + # 追加80e 断点 A:方法可能定义在 MRO 祖先(Mixin)模块。 + # 此时 ret_anc_sha1 仍是调用类自身的 sha1(MRO 双路重试 + # 失败未更新),且调用类(如 Generator)已注册、自身 text.ll + # 存在 → 上方 guard 不成立 → 直接 fail-fast。但 MRO 重试 + # 落空可能只是"祖先定义模块未翻译"(AssignGenMixin.vp 的 + # text.ll 未生成),属依赖未就绪而非方法不存在。遍历祖先链: + # 任一祖先的 sha1 取不到或其 text.ll 未生成 → 结果不确定, + # 标记 pending 下遍重试(届时祖先 text.ll 生成,MRO 重试 + # 可精确解析);全部祖先就绪仍查不到才是真错误。 + mro_p2: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, class_name) + mi_p2: int = 1 + anc_missing_p2: int = 0 + while mro_p2 is not None and mro_p2[mi_p2] != 0: + anc_p2: str = (str | t.CPtr)(t.CVoid(mro_p2[mi_p2], t.CPtr)) + if anc_p2 is not None: + anc_sha1_p2: str = self.Gen.StructGen.get_struct_sha1(anc_p2) + if anc_sha1_p2 is None \ + or self._dep_text_ll_exists(pool, anc_sha1_p2) == 0: + anc_missing_p2 = 1 + break + mi_p2 += 1 + if anc_missing_p2 != 0: + if trans is not None: + trans._deps_pending = 1 + # 依赖未就绪:保持默认 i32(同上,build_call(Void) 返回 + # None 会破坏表达式翻译,pending 文件本遍不写盘) + call_ret_ty = llvmlite.Int32(pool) + else: + call_ret_ty = self._fail_method_ret_ty(method_name, cl) + + # found_func 未命中但返回类型已解析:用方法定义类构造跨模块调用名 + # (Module.append → {AST_sha1}.AST.append,避免链接 undefined reference) + if ret_anc_name is not None and ret_anc_sha1 is None: + # ret_anc_sha1 缺失(如 find_struct 未命中跨模块结构体)时, + # 从对象实际 LLVM 类型名提取 sha1 前缀:类型名形如 + # "2c175afd85852faf.Buf"({sha1}.{ClassName}),前 16 字符即模块 sha1。 + # 例:memhub.alloc_buf 里 buf.__before_init__(),buf 是 viperio.Buf*, + # 其类型名含 viperio 模块 sha1,借此构造 {sha1}.Buf.__before_init__, + # 避免静默生成裸名 @Buf.__before_init__(链接 undefined symbol)。 + if mc_struct_ty is not None: + match mc_struct_ty: + case llvmlite.LLVMType.Struct(_fields_st, _fcount_st, type_name_st): + if type_name_st is not None and type_name_st[0] != '\0': + type_len_st: t.CSizeT = string.strlen(type_name_st) + if type_len_st >= 16: + sha1_from_ty: str = pool.alloc(17) + if sha1_from_ty is not None: + string.strncpy(sha1_from_ty, type_name_st, 16) + sha1_from_ty[16] = '\0' + ret_anc_sha1 = sha1_from_ty + case _: + pass + if ret_anc_name is not None and ret_anc_sha1 is not None: + ml_anc: t.CSizeT = string.strlen(ret_anc_sha1) + string.strlen(ret_anc_name) \ + + string.strlen(method_name) + 3 + mangled_anc: str = pool.alloc(ml_anc) + if mangled_anc is not None: + viperlib.snprintf(mangled_anc, ml_anc, "%s.%s.%s", + ret_anc_sha1, ret_anc_name, method_name) + call_name = mangled_anc + # 类型名提取的 sha1 无法保证为真实模块 sha1(跨模块 stub 类型名 + # 带前缀但 find_struct 未注册时仍可用),此处不校验格式 + elif ret_anc_name is not None and ret_anc_sha1 is None: + # fail-fast:方法所属类既查不到 SHA1 又从类型名提取失败, + # 禁止静默裸名(否则链接期 undefined symbol 难以定位) + self.Gen.TypeGenErr.fatal_error( + cl, + f"方法 '{method_name}' 所属类 '{ret_anc_name}' 无法解析模块 SHA1" + f"(text.ll/vpi/类型名均未命中),跨模块调用名构造失败", + "TypeError") + + # 翻译调用参数 + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + can: t.CSizeT = 0 + if cargs is not None: + can = len(cargs) + kw_calls: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords + kwc: t.CSizeT = 0 + if kw_calls is not None: + kwc = len(kw_calls) + + # 多继承 this 调整(字节偏移法,2026-08-10,与 TPC HandlesExprCall._adjust_this_for_inherited_method 一致): + # 继承方法体按"定义类自身布局"读 self 字段(如 B.get_b 内 GEP(self_B, [0,1]) + # 的字节偏移是 B 布局中 b 的 offset 12)。父类字段区在子类中的字节偏移可能 + # 不同(如 AB={vtable,a@8,b@12} 中 b 偏移 16),self 需按字节差前移,使父类 + # 方法内二次 GEP 恰好落到子类字段。 + # delta = 字段在子类中字节偏移 − 字段在父类自身布局中字节偏移 + # delta==0(第一父类,字段区前缀对齐)无需调整;delta>0 时按字节 GEP 到 + # 父类字段区在子类中的等效基址,再 bitcast 成父类指针。 + # 原实现仅覆盖"无 vtable 的父类"(其首字段偏移 0,GEP 到首字段即父类起点), + # 且用 GEP 字段法——对 vtable 父类(首字段偏移非 0,如 B)被直接跳过不调整 + # → AB 场景 B.get_b 按 B 布局读 self.b@12 落到 a → AB 字段/方法 FAILED。 + self_arg: llvmlite.Value | t.CPtr = obj_ptr + if mc_anc is not None and string.strcmp(mc_anc, class_name) != 0: + # 判断 mc_anc 是否为 class_name 的第一父类:第一父类字段区前缀对齐 + # (delta==0)无需调整;非第一父类必须调整 self,任何一步失败都 + # fail-fast——绝不静默用未调整的 obj_ptr 当 self,否则方法按自身 + # 布局读字段读到垃圾(lookup_reexport strcmp 概率崩溃根因候选)。 + is_first_parent_th: int = 0 + mro_fp_th: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, class_name) + if mro_fp_th is not None and mro_fp_th[1] != 0: + first_parent_th: str = (str | t.CPtr)(t.CVoid(mro_fp_th[1], t.CPtr)) + if first_parent_th is not None and string.strcmp(first_parent_th, mc_anc) == 0: + is_first_parent_th = 1 + anc_entry_th: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(mc_anc) + # 无字段父类(FieldCount==0,如多继承中的纯方法类 Vec2Extra): + # 继承方法体按"定义类字段"读 self,定义类无字段则方法体不读 + # self 布局 → this 无需字节调整,原样传入即可(对齐 TPC + # _adjust_this_for_inherited_method:anc_members 为空直接返回 ObjVal)。 + if anc_entry_th is not None and anc_entry_th.FieldCount > 0: + anc_first_name_th: str = None + afi_th: int = 0 + while afi_th < anc_entry_th.FieldCount: + afe_th: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry( + anc_entry_th, afi_th) + if afe_th is not None: + afn_th: str = self.Gen.StructGen.get_field_name_ptr(afe_th) + if afn_th is not None and string.strcmp(afn_th, "__vtable__") != 0: + anc_first_name_th = afn_th + break + afi_th += 1 + if anc_first_name_th is not None: + sub_entry_th: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct( + class_name) + if sub_entry_th is not None: + anc_field_th: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field( + anc_entry_th.Ty, anc_first_name_th) + sub_field_th: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field( + sub_entry_th.Ty, anc_first_name_th) + if anc_field_th is not None and sub_field_th is not None: + anc_off_th: int = self._field_byte_offset( + pool, anc_entry_th, anc_field_th.Index) + sub_off_th: int = self._field_byte_offset( + pool, sub_entry_th, sub_field_th.Index) + delta_th: int = sub_off_th - anc_off_th + if delta_th > 0: + i8_ty_th: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_th: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_th) + obj_i8_th: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, obj_ptr, i8_ptr_th) + delta_val_th: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, delta_th) + adj_th: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i8_ty_th, obj_i8_th, delta_val_th) + if adj_th is not None: + anc_ptr_ty_th: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, anc_entry_th.Ty) + # 跨模块基类(如 Generator → ClassGenBase)的完整定义不在本模块, + # bitcast 引用 %"sha1.ClassGenBase" 前必须确保 opaque 声明存在, + # 否则 llc 报 "use of undefined type"(PrintModule 只扫函数签名, + # 函数体内的 bitcast 类型不会被自动声明)。 + llvmlite.module_ensure_opaque_for_type(mod, pool, anc_ptr_ty_th) + self_arg = llvmlite.build_bitcast(builder, adj_th, anc_ptr_ty_th) + elif sub_field_th is None and anc_field_th is not None: + # 兄弟 Mixin 场景(对齐 TPC _adjust_this_for_inherited_method): + # 调用类(class_name=BaseB)不含定义类(mc_anc=BaseA)字段—— + # BaseA 在组合类 MRO 中位于 BaseB 之前(如 Combined(BaseA, BaseB), + # BaseB 内 self.helper() 调 BaseA.helper)。BaseB.this 指向组合类中 + # BaseB 字段区起点,BaseA 区在它前面,this 前移 sizeof(定义类)。 + # 若无此分支,sub_field_th 查找失败 → 下方 fail-fast,兄弟 Mixin + # 调用永远编译不过(NoVTableCrossMixinTest BaseB.caller 根因)。 + anc_size_th: int = self.Gen.ClassGenEnum._get_type_size(anc_entry_th.Ty) + if anc_size_th > 0: + i8_ty_th2: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_th2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_th2) + obj_i8_th2: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, obj_ptr, i8_ptr_th2) + sib_delta_th: llvmlite.Value | t.CPtr = llvmlite.const_int32( + pool, 0 - anc_size_th) + adj_th2: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i8_ty_th2, obj_i8_th2, sib_delta_th) + if adj_th2 is not None: + anc_ptr_ty_th2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, anc_entry_th.Ty) + llvmlite.module_ensure_opaque_for_type( + mod, pool, anc_ptr_ty_th2) + self_arg = llvmlite.build_bitcast( + builder, adj_th2, anc_ptr_ty_th2) + else: + # 定义类 struct 大小不可得(opaque/未加载):fail-fast + self.Gen.TypeGenErr.fatal_error( + cl, + f"this-adjust 兄弟 Mixin 定义类大小未知: 方法'{method_name}'" + f"定义类'{mc_anc}'的 struct 大小计算失败", + "InternalCompilerError") + elif is_first_parent_th == 0: + self.Gen.TypeGenErr.fatal_error( + cl, + f"this-adjust 字段查找失败: 方法'{method_name}'定义类'{mc_anc}'" + f"首字段'{anc_first_name_th}'在类'{class_name}'/'{mc_anc}'布局中未找到", + "InternalCompilerError") + elif is_first_parent_th == 0: + self.Gen.TypeGenErr.fatal_error( + cl, + f"this-adjust 子类结构体未注册: 方法'{method_name}'定义类'{mc_anc}'," + f"接收类'{class_name}'的 struct 未找到", + "InternalCompilerError") + else: + # 父类仅 __vtable__ 字段(无字段 CVTable 类):方法体不读 + # 布局字段,无需调整(对齐 TPC:first_field_name None → ObjVal) + pass + elif anc_entry_th is not None and anc_entry_th.FieldCount == 0: + # 无字段父类:this 无需字节调整(见上方注释) + pass + elif is_first_parent_th == 0: + # 父类 struct 未注册:fail-fast,绝不静默用未调整的 obj_ptr + # 当 self(否则方法按自身布局读字段读到垃圾) + self.Gen.TypeGenErr.fatal_error( + cl, + f"this-adjust 父类结构体未注册: 方法'{method_name}'定义类'{mc_anc}'的 struct 未找到", + "InternalCompilerError") + # 构建参数链表: self → arg1 → arg2 → ... + llvmlite.value_set_next(self_arg, None) + head: llvmlite.Value | t.CPtr = self_arg + tail: llvmlite.Value | t.CPtr = self_arg + arg_count_eff: int = 0 + + if kwc > 0 and found_func is not None: + # 关键字参数:遍历函数定义参数(跳过 self),位置参数优先,其余按名匹配 + # 缺失参数用零值兜底,保持 call 参数数量与 define 一致 + cur_param_k: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + if cur_param_k is not None: + cur_param_k = llvmlite.param_get_next(cur_param_k) # 跳过 self + pi_k: int = 0 + while cur_param_k is not None: + arg_node_k: ast.AST | t.CPtr = None + if pi_k < can: + arg_node_k = cargs.get(pi_k) + else: + pname_k: str = llvmlite.param_get_name(cur_param_k) + if pname_k is not None: + ki_k: int + for ki_k in range(kwc): + kw_k: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(kw_calls.get(ki_k)) + if kw_k is None or kw_k.arg is None or kw_k.value is None: + continue + if self._kwarg_name_matches(kw_k.arg, pname_k) == 1: + arg_node_k = kw_k.value + break + arg_val_k: llvmlite.Value | t.CPtr = None + if arg_node_k is not None: + arg_val_k = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg_node_k, None, 0, trans) + if arg_val_k is None: + # 缺失参数:零值兜底(保持参数数量匹配)。 + # kw 省略的形参可能有默认值(查不到默认表 ≠ 无默认值), + # 零值兜底与原逻辑一致,禁止 fail-fast 误杀。 + pty_k: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k) + if pty_k is not None: + arg_val_k = llvmlite.ConstZero(pool, pty_k) + if arg_val_k is not None: + pty_k2: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k) + if pty_k2 is not None: + arg_val_k = self.Gen.ExprGenBase.coerce_to_type( + builder, arg_val_k, pty_k2, arg_node_k) + llvmlite.value_set_next(arg_val_k, None) + llvmlite.value_set_next(tail, arg_val_k) + tail = arg_val_k + arg_count_eff += 1 + pi_k += 1 + cur_param_k = llvmlite.param_get_next(cur_param_k) + else: + # 位置参数(原逻辑) + for ai in range(can): + arg_node: ast.AST | t.CPtr = cargs.get(ai) + if arg_node is None: + continue + arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg_node, None, 0, trans) + if arg_val is None: + continue + # 按形参类型 coerce(self 是形参 0,第 ai 个实参对应形参 ai+1) + # 修复: CDefine/i32 常量传给 i64 形参(如 MemBuddy.__init__ 的 size: t.CSizeT) + # 未提升导致 call(i32) 与 define(i64) 不匹配,运行时读到垃圾高 32 位崩溃 + if found_func is not None: + pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + pi: int = 0 + while pp is not None and pi < ai + 1: + if pi == ai + 1: + break + pp = llvmlite.param_get_next(pp) + pi += 1 + if pp is not None: + pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pp) + if pty is not None: + arg_val = self.Gen.ExprGenBase.coerce_to_type( + builder, arg_val, pty, arg_node) + else: + # found_func=None(跨模块 stub 未注入):数组实参按 C 语义 + # 衰减为元素指针(对齐 TPC _decay_array_to_ptr)。否则 + # _ensure_method_declare 用 [N x ty]* 实参类型建 declare, + # 与定义侧元素指针(如 md5.final 的 i8*)类型不匹配。 + if arg_val.Ty is not None and self.Gen.ExprGenBase.is_ptr_type(arg_val.Ty) != 0: + arr_pointee_ma: llvmlite.LLVMType | t.CPtr = arg_val.Ty.Pointee + if arr_pointee_ma is not None: + match arr_pointee_ma: + case llvmlite.LLVMType.Array(arr_et_ma, _): + decayed_ma: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( + builder, arr_pointee_ma, arr_et_ma, arg_val, + llvmlite.const_int32(pool, 0)) + if decayed_ma is not None: + arg_val = decayed_ma + case _: + pass + llvmlite.value_set_next(arg_val, None) + llvmlite.value_set_next(tail, arg_val) + tail = arg_val + arg_count_eff += 1 + + total_count: int = 1 + arg_count_eff + + # 默认参数填充:如果调用点参数少于函数定义参数,用默认值填充缺失参数 + # 查找函数的 defaults 信息 + mdf_defaults: t.CVoid | t.CPtr = None + mdf_default_count: int = 0 + mdf_param_count: int = 0 + if trans is not None and trans._funcs is not None: + mdf_entry: FuncEntry | t.CPtr = ExprCallTable.find_func_entry_in_table( + trans._funcs, trans._func_count, lookup_name) + if mdf_entry is not None: + mdf_defaults = mdf_entry.Defaults + mdf_default_count = mdf_entry.DefaultCount + mdf_param_count = mdf_entry.ParamCount + # 全局默认参数表查询无条件执行:mdf_entry 命中时(泛型特化方法注册进 + # 调用方函数表)Defaults 非 None 会短路跳过,但下方"用快照重建默认值" + # 分支依赖 mdf_gd(唯一持有 stdlib 常量快照处)——缺它必 fatal_error + # (ListTest list[int].__new__ 根因) + mdf_gd: FuncDefaultsEntry | t.CPtr = self.Gen.CallGenLeafKit.find_func_defaults(lookup_name) + if mdf_defaults is None and mdf_gd is not None: + mdf_defaults = mdf_gd.Defaults + mdf_default_count = mdf_gd.DefaultCount + mdf_param_count = mdf_gd.ParamCount + + # 计算需要填充的参数(不含 self) + # arg_count_eff = 已提供的非 self 参数数量(含关键字模式完整构建) + # mdf_param_count = 函数定义的非 self 参数数量 + if mdf_param_count > arg_count_eff: + mdf_offset: int = mdf_param_count - mdf_default_count + mdf_pi: int = arg_count_eff + while mdf_pi < mdf_param_count: + # 优先用默认值 + if mdf_defaults is not None and mdf_default_count > 0 and mdf_pi >= mdf_offset: + mdf_di: int = mdf_pi - mdf_offset + if mdf_di < mdf_default_count: + # 用 stdlib 常量快照重建(mdf_gd.Defaults 的 pool 内 AST 可能已被 reset 回收, + # 直接回退读 AST 会 use-after-free——快照失败时 fail-fast 暴露,绝不读悬空 AST) + mdf_val: llvmlite.Value | t.CPtr = None + if mdf_gd is not None: + mdf_val = self.Gen.CallGenLeafKit._build_const_from_snapshot( + pool, mod, mdf_gd, mdf_di, trans, builder) + if mdf_val is None: + self.Gen.TypeGenErr.fatal_error( + cl, + f"跨模块默认参数无法重建(快照缺失,默认值需为简单常量): {lookup_name}", + "TypeError") + continue + llvmlite.value_set_next(mdf_val, None) + llvmlite.value_set_next(tail, mdf_val) + tail = mdf_val + total_count += 1 + mdf_pi += 1 + continue + # 无默认值时用零值兜底(需要 found_func 获取参数类型)。 + # 默认参数表按裸名注册(如 "__init__"),跨模块 "ClassName.method" + # 查找常查不到——查不到 ≠ 无默认值(如 Buf.__init__(data, capacity) + # 缺的 length=0/owned=False 恰为零值),零值兜底语义一致。 + if found_func is not None: + param_node_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + skip_z: int = 0 + while skip_z <= mdf_pi and param_node_z is not None: + param_node_z = llvmlite.param_get_next(param_node_z) + skip_z += 1 + if param_node_z is not None: + zero_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node_z) + zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, zero_ty) + if zero_val is not None: + llvmlite.value_set_next(zero_val, None) + llvmlite.value_set_next(tail, zero_val) + tail = zero_val + total_count += 1 + mdf_pi += 1 + + # 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用 + # (不依赖 found_func — 继承的虚方法可能没有子类实现) + # 复用前面已获取的 mc_entry(find_struct_by_type 规避跨模块同名找错) + mc_has_vt: int = 0 + mc_method_idx: int = -1 + if mc_entry is not None: + mc_has_vt = mc_entry.HasVTable + if mc_has_vt == 1 and mc_entry.VTableMethods is not None: + mc_methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(mc_entry.VTableMethods, t.CPtr)) + for mc_mi in range(mc_entry.VTableMethodCount): + mc_mname_addr: t.CSizeT = mc_methods_arr[mc_mi] + if mc_mname_addr == 0: + continue + mc_mname: str = (str | t.CPtr)(t.CVoid(mc_mname_addr, t.CPtr)) + if mc_mname is not None and string.strcmp(mc_mname, method_name) == 0: + mc_method_idx = mc_mi + break + if mc_has_vt == 1 and mc_method_idx >= 0: + # 虚分派 self 必须用调整后的 self_arg(多继承 this 调整), + # 否则 B.get_b 收到未调整的 AB*,方法体内按 B 布局读字段错位。 + # vtable 读取必须用对象头 obj_ptr(调整后 self 头部是父类字段值)。 + return self._do_virtual_call(pool, builder, mod, class_name, method_name, + self_arg, head, total_count, found_func, call_ret_ty, + obj_ptr) + + # 跨模块调用:创建 declare 声明,避免 llc 报 undefined value + self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, total_count) + # 检查变长函数 + C ABI 提升(cargs 是实参 AST,self_offset=1 跳过 self) + is_variadic_3441: int = self.Gen.CallGenVa._check_and_promote_variadic_call( + pool, builder, mod, call_name, head, total_count, cargs, 1, trans) + # try-except:方法含 raise(EH 输出参数)时追加输出实参 + 调用后检测 + return self.Gen.CallGenLeafKit._emit_eh_guarded_call( + builder, pool, mod, trans, found_func, call_name, head, total_count, + call_ret_ty, is_variadic_3441) + # ============================================================ + # _translate_super_call — super().method(args) → 静态调用父类方法 + # + # Python super 语义(2026-08-10 实现): + # - 当前类来自 self.CurClassName(_translate_method 翻译方法体时设置) + # - 父类查找:沿 get_mro_chain(CurClassName) 跳过自身,找第一个定义 method 的祖先 + # - self 指针:符号表 self 变量 alloca load(对象头,复用 c.Addr(self) 模式) + # - this_adjust:父类字段区在子类中字节偏移 delta>0 时 GEP i8* + delta + # (复用 _field_byte_offset 字节偏移法,与 _translate_method_call 一致) + # - 静态调用父类实现:不虚分派(super() 不触发子类 override) + # ============================================================ + + # ============================================================ + def _translate_super_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + method_name: str, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """super().method(args) → 父类方法静态调用,返回 call 结果 Value""" + if pool is None or builder is None or cl is None or method_name is None: + return None + if trans is None: + return None + # 1. 当前方法所属类:从 self 变量的注解类名获取(_translate_method + # 注册 self 时 set_var_annot_class_name(SymTab, "self", class_name))。 + # 不用 Mixin 字段:TPV Mixin 字段按声明类独立布局(Generator 多继承 + # 去重只保留首个声明),ClassGenMixin 写的 CurClassName 与 CallGenMixin + # 读的位置偏移不一致 → 运行时读到空 → super() 误报"只能在类方法内使用"。 + self_entry: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, "self") + if self_entry is None: + self_entry = self.Gen.VarGen.lookup_var_entry(trans.SymTab, "cls") + if self_entry is None: + self.Gen.TypeGenErr.fatal_error(cl, "super(): 当前作用域无 self 变量(静态方法内不可用)", "TypeError") + return None + cur_class: str = self_entry.AnnotClassName + if cur_class is None: + self.Gen.TypeGenErr.fatal_error(cl, "super() 只能在类方法内使用(self 无注解类名)") + return None + # 2. 沿 MRO 跳过自身,找第一个定义 method 的祖先类 + anc: str = None + mro_sp: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, cur_class) + mi_sp: int = 1 + while mro_sp is not None and mro_sp[mi_sp] != 0: + anc_sp: str = (str | t.CPtr)(t.CVoid(mro_sp[mi_sp], t.CPtr)) + if anc_sp is not None: + probe_sp: str = pool.alloc(160) + if probe_sp is not None: + viperlib.snprintf(probe_sp, 160, "%s.%s", anc_sp, method_name) + if self.Gen.CallGenLeafKit.find_func_global(probe_sp) is not None: + anc = anc_sp + break + mi_sp += 1 + if anc is None: + err_sp: str = pool.alloc(256) + if err_sp is not None: + viperlib.snprintf(err_sp, 256, "super(): 当前类 %s 的父类链未定义方法 %s", + cur_class, method_name) + self.Gen.TypeGenErr.fatal_error(cl, err_sp, "TypeError") + self.Gen.TypeGenErr.fatal_error(cl, "super(): 父类链未定义方法", "TypeError") + return None + # 3. self 指针(self 变量 alloca load,复用 c.Addr(self) 模式) + if self_entry.Alloca is None or self_entry.Alloca.Ty is None: + self.Gen.TypeGenErr.fatal_error(cl, "super(): 当前作用域无 self 变量(静态方法内不可用)", "TypeError") + return None + self_ptr: llvmlite.Value | t.CPtr = None + match self_entry.Alloca.Ty: + case llvmlite.LLVMType.Ptr(inner1): + match inner1: + case llvmlite.LLVMType.Ptr(inner2): + obj_ty_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, inner2) + self_ptr = llvmlite.build_load(builder, obj_ty_sp, self_entry.Alloca) + case _: + self_ptr = llvmlite.build_load(builder, self_entry.Alloca.Ty, self_entry.Alloca) + case _: + self_ptr = self_entry.Alloca + if self_ptr is None: + return None + # 3. this_adjust(字节偏移法:父类字段区在子类中的偏移差) + self_arg: llvmlite.Value | t.CPtr = self_ptr + if string.strcmp(anc, cur_class) != 0: + anc_entry_sp: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(anc) + if anc_entry_sp is not None and anc_entry_sp.FieldCount > 0: + first_name_sp: str = None + afi_sp: int = 0 + while afi_sp < anc_entry_sp.FieldCount: + afe_sp: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry( + anc_entry_sp, afi_sp) + if afe_sp is not None: + afn_sp: str = self.Gen.StructGen.get_field_name_ptr(afe_sp) + if afn_sp is not None and string.strcmp(afn_sp, "__vtable__") != 0: + first_name_sp = afn_sp + break + afi_sp += 1 + if first_name_sp is not None: + sub_entry_sp: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct( + cur_class) + if sub_entry_sp is not None: + anc_field_sp: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field( + anc_entry_sp.Ty, first_name_sp) + sub_field_sp: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field( + sub_entry_sp.Ty, first_name_sp) + if anc_field_sp is not None and sub_field_sp is not None: + anc_off_sp: int = self._field_byte_offset( + pool, anc_entry_sp, anc_field_sp.Index) + sub_off_sp: int = self._field_byte_offset( + pool, sub_entry_sp, sub_field_sp.Index) + delta_sp: int = sub_off_sp - anc_off_sp + if delta_sp > 0: + i8_ty_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_sp) + obj_i8_sp: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, self_ptr, i8_ptr_sp) + dval_sp: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, delta_sp) + adj_sp: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i8_ty_sp, obj_i8_sp, dval_sp) + if adj_sp is not None: + anc_ptr_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, anc_entry_sp.Ty) + # 同上:跨模块祖先类型 bitcast 前确保 opaque 声明, + # 否则 llc 报 "use of undefined type" + llvmlite.module_ensure_opaque_for_type(mod, pool, anc_ptr_sp) + self_arg = llvmlite.build_bitcast(builder, adj_sp, anc_ptr_sp) + # 4. 查找父类方法函数 + 构造调用名(SHA1 mangled) + anc_lookup: str = pool.alloc(160) + if anc_lookup is None: + return None + viperlib.snprintf(anc_lookup, 160, "%s.%s", anc, method_name) + found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, anc_lookup) + call_name: str = anc_lookup + anc_sha1_sp: str = self.Gen.StructGen.get_struct_sha1(anc) + if anc_sha1_sp is None: + anc_sha1_sp = trans.ModuleSha1 + if found_func is not None: + fname_sp: str = llvmlite.function_get_name(found_func) + if fname_sp is not None: + call_name = fname_sp + else: + if anc_sha1_sp is not None: + mangled_sp: str = self.Gen.FuncGenBase._mangle_name_with_sha1(anc_sha1_sp, anc_lookup) + if mangled_sp is not None: + call_name = mangled_sp + # 5. 翻译参数 + 按形参 coerce(self 是形参 0,第 ai 个实参对应形参 ai+1) + cargs_sp: list[ast.AST | t.CPtr] | t.CPtr = cl.args + can_sp: t.CSizeT = 0 + if cargs_sp is not None: + can_sp = len(cargs_sp) + llvmlite.value_set_next(self_arg, None) + head: llvmlite.Value | t.CPtr = self_arg + tail: llvmlite.Value | t.CPtr = self_arg + arg_count_sp: int = 1 + for ai_sp in range(can_sp): + arg_node_sp: ast.AST | t.CPtr = cargs_sp.get(ai_sp) + if arg_node_sp is None: + continue + arg_val_sp: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg_node_sp, None, 0, trans) + if arg_val_sp is None: + continue + if found_func is not None: + pp_sp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + pi_sp: int = 0 + while pp_sp is not None and pi_sp < ai_sp + 1: + if pi_sp == ai_sp + 1: + break + pp_sp = llvmlite.param_get_next(pp_sp) + pi_sp += 1 + if pp_sp is not None: + pty_sp: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pp_sp) + if pty_sp is not None: + arg_val_sp = self.Gen.ExprGenBase.coerce_to_type( + builder, arg_val_sp, pty_sp, arg_node_sp) + else: + # found_func=None:数组实参按 C 语义衰减为元素指针 + # (与 _translate_method_call 一致,避免 declare 类型不匹配) + if arg_val_sp.Ty is not None and self.Gen.ExprGenBase.is_ptr_type(arg_val_sp.Ty) != 0: + arr_pointee_sp: llvmlite.LLVMType | t.CPtr = arg_val_sp.Ty.Pointee + if arr_pointee_sp is not None: + match arr_pointee_sp: + case llvmlite.LLVMType.Array(arr_et_sp, _): + decayed_sp: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( + builder, arr_pointee_sp, arr_et_sp, arg_val_sp, + llvmlite.const_int32(pool, 0)) + if decayed_sp is not None: + arg_val_sp = decayed_sp + case _: + pass + llvmlite.value_set_next(arg_val_sp, None) + llvmlite.value_set_next(tail, arg_val_sp) + tail = arg_val_sp + arg_count_sp += 1 + # 6. 返回类型:found_func → 特殊方法 → text.ll/vpi + ret_ty_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if found_func is not None: + frt_sp: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) + if frt_sp is not None: + ret_ty_sp = frt_sp + else: + sp_ty_sp: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty(pool, anc, method_name) + if sp_ty_sp is not None: + ret_ty_sp = sp_ty_sp + else: + looked_sp: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL( + pool, anc_sha1_sp, anc, method_name) + if looked_sp is not None: + ret_ty_sp = looked_sp + else: + vpi_ret_sp: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi( + pool, anc_sha1_sp, anc, method_name) + if vpi_ret_sp is not None: + ret_ty_sp = vpi_ret_sp + else: + # 查找链(函数/text.ll/vpi stub)全部未命中:fail-fast, + # 绝不静默保持默认 i32(会截断指针/i64 返回值) + # Phase A 依赖未就绪(anc_sha1_sp None / 定义模块 text.ll + # 未生成):标记 pending 下遍重译(对齐 L4783-4790), + # 绝不 fail-fast 中断多遍收敛;真实错误由收敛检查兜底。 + if anc_sha1_sp is None \ + or self._dep_text_ll_exists(pool, anc_sha1_sp) == 0: + if trans is not None: + trans._deps_pending = 1 + # 依赖未就绪:保持默认 i32(build_call(Void) 返回 None + # 会破坏表达式翻译;pending 文件本遍不写盘,下遍重译) + ret_ty_sp = llvmlite.Int32(pool) + else: + self._fail_method_ret_ty(method_name, cl) + # 7. 跨模块:创建 declare;生成 call + if found_func is None: + self._ensure_method_declare(pool, mod, call_name, ret_ty_sp, head, arg_count_sp) + is_variadic_sp: int = self.Gen.CallGenVa._check_and_promote_variadic_call( + pool, builder, mod, call_name, head, arg_count_sp, cargs_sp, 1, trans) + return llvmlite.build_call(builder, call_name, head, arg_count_sp, ret_ty_sp, is_variadic_sp) + # ============================================================ + # _field_byte_offset — 计算字段在结构体布局中的字节偏移 + # + # 按 LLVM 布局遍历 struct elements 带对齐累加(与 ClassGenMixin._get_type_size + # 的 padding 规则一致)。field_index 是 FieldEntry.Index(OOP 类 __vtable__ 占 0)。 + # 供多继承 this 调整(字节偏移法)计算 delta。 + # ============================================================ + + # ============================================================ + def _field_byte_offset(self, pool: memhub.MemBuddy | t.CPtr, + entry: GenTypes.StructEntry | t.CPtr, + field_index: int) -> int: + """计算字段在结构体中的字节偏移(含对齐 padding),无法计算返回 0""" + if pool is None or entry is None or entry.Ty is None or field_index < 0: + return 0 + match entry.Ty: + case llvmlite.LLVMType.Struct(fields, fcount, name): + offset_fb: int = 0 + cur_fb: llvmlite.ParamNode | t.CPtr = fields + i_fb: int = 0 + while cur_fb is not None and i_fb < field_index: + if cur_fb.Ty is not None: + fty_fb: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(cur_fb.Ty) + fsize_fb: int = self.Gen.ClassGenEnum._get_type_size(fty_fb) + falign_fb: int = self.Gen.ClassGenEnum._get_type_align(fty_fb) + if falign_fb > 1: + rem_fb: int = offset_fb % falign_fb + if rem_fb != 0: + offset_fb += falign_fb - rem_fb + offset_fb += fsize_fb + cur_fb = cur_fb.Next + i_fb += 1 + # 字段自身对齐 + if cur_fb is not None and cur_fb.Ty is not None: + fty2_fb: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(cur_fb.Ty) + falign2_fb: int = self.Gen.ClassGenEnum._get_type_align(fty2_fb) + if falign2_fb > 1: + rem2_fb: int = offset_fb % falign2_fb + if rem2_fb != 0: + offset_fb += falign2_fb - rem2_fb + return offset_fb + case _: + return 0 + # ============================================================ + # _kwarg_name_matches — 检查关键字参数名是否匹配函数参数名 + # + # 函数参数名在 LLVM IR 中带 % 前缀(如 "%a"),关键字参数名无前缀(如 "a") + # 跳过 % 前缀后逐字符比较 + # ============================================================ + def _kwarg_name_matches(self, kw_arg: str, + param_name: str) -> int: + """检查关键字参数名 kw_arg 是否匹配参数名 param_name(跳过 % 前缀)""" + if kw_arg is None or param_name is None: + return 0 + start: t.CSizeT = 0 + if param_name[0] == '%': + start = 1 + for i, ch in enumerate(kw_arg): + c: t.CChar = param_name[start + i] + if c == '\0' or c != ch: + return 0 + if param_name[start + i + 1] != '\0': + return 0 return 1 \ No newline at end of file diff --git a/App/lib/core/Gen/CallGenCtor.vp b/App/lib/core/Gen/CallGenCtor.vp index 5640472..02d3bd8 100644 --- a/App/lib/core/Gen/CallGenCtor.vp +++ b/App/lib/core/Gen/CallGenCtor.vp @@ -1,989 +1,981 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import sys -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesFunctions as HandlesFunctions -import lib.core.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.CompilerFactory as CompilerFactory - - -import lib.core.Gen.CallGenBase as CallGenBase -import lib.core.Handles.ExprCallCtor as ExprCallCtor -import lib.core.Handles.ExprCallTable as ExprCallTable - -# ============================================================ -# CallGenCtor - CallGenMixin 拆分(阶段 B):结构体构造 / 枚举构造 / 泛型构造 / 类型转换 -# -# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class CallGenCtor(CallGenBase.CallGenBase): - """结构体构造 / 枚举构造 / 泛型构造 / 类型转换""" - - # ============================================================ - # _apply_struct_defaults — 应用结构体字段的默认值 - # - # 在 zeroinitializer 之后、显式参数之前调用 - # 遍历所有字段,对有默认值的字段翻译并 store - # 显式参数(位置/关键字)后续会覆盖默认值 - # ============================================================ - def _apply_struct_defaults(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - struct_ty: llvmlite.LLVMType | t.CPtr, - class_name: str, - tmp: llvmlite.Value | t.CPtr, - trans: HT.Translator | t.CPtr): - """应用结构体字段的默认值""" - # 用类型指针定位 entry,规避跨模块同名 find_struct 找错 - entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) - if entry is None: - # fast-fail: 结构体类型未注册,静默 return 会导致字段未初始化 - VLogger.error( - f"结构体类型未注册,无法应用默认值: {class_name}", - "HandlesExprCall") - return - for fi in range(entry.FieldCount): - fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( - entry, fi) - if fe is None: - # fast-fail: 字段索引越界(entry.FieldCount 与实际不一致) - VLogger.error( - f"字段索引越界,无法获取字段 entry: {class_name}", - "HandlesExprCall") - continue - if fe.DefaultVal is None: - continue # 合理跳过:无默认值的字段 - # 静态数组字段 + 列表字面量默认值 → 整体置零 + 逐元素 GEP+store - # (与 _generate_before_init 一致;translate_value 会把列表字面量 - # 误译成动态 list 对象指针,coerce 到 [N x elem] 会失败)。 - # Mixin 静态绑定:跨 Mixin 方法必须走 HandlesAnnAssign 模块级委托。 - if fe.Ty is not None and HandlesExpr.is_array_type(fe.Ty) != 0 \ - and fe.DefaultVal.kind() == ast.ASTKind.List: - field_ptr_arr2: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, struct_ty, fe.Ty, tmp, fe.Index) - if field_ptr_arr2 is not None: - zero_arr2: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, fe.Ty) - if zero_arr2 is not None: - llvmlite.build_store(builder, zero_arr2, field_ptr_arr2) - HandlesAnnAssign._init_global_array_from_list( - builder, pool, mod, field_ptr_arr2, fe.DefaultVal, trans) - continue - default_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, fe.DefaultVal, None, 0, trans) - if default_val is None: - # fast-fail: 默认值翻译失败(如引用了未定义符号) - VLogger.error( - f"字段默认值翻译失败: {class_name}", - "HandlesExprCall") - continue - field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, struct_ty, fe.Ty, tmp, fe.Index) - if field_ptr is None: - # fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配) - VLogger.error( - f"字段 GEP 失败,类型不匹配: {class_name}", - "HandlesExprCall") - continue - default_val = HandlesExpr.coerce_to_type(builder, default_val, fe.Ty, fe.DefaultVal) - llvmlite.build_store(builder, default_val, field_ptr) - # ============================================================ - # _translate_struct_ctor — 结构体构造函数 Point(10, 20) - # - # 生成: - # %tmp = alloca {i32, i32} - # store {i32, i32} zeroinitializer, {i32, i32}* %tmp - # %f0 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 0 - # store i32 10, i32* %f0 - # %f1 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 1 - # store i32 20, i32* %f1 - # %result = load {i32, i32}, {i32, i32}* %tmp - # ============================================================ - - # ============================================================ - def _translate_struct_ctor(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - struct_ty: llvmlite.LLVMType | t.CPtr, - class_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """结构体构造函数:按字段顺序 store 参数值,返回结构体值 - - OOP 结构体:alloca → call __before_init__(ptr) → call __init__(ptr, args) 或 store 参数 → load - 普通结构体:alloca → zero + defaults → store 参数 → load - """ - # 创建临时 alloca - # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) - HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) - tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) - if tmp is None: - return llvmlite.ConstZero(pool, struct_ty) - # 诊断节点:取第一个构造实参(有行号),供 _call_method_on_ptr 的 - # fatal_error 显示构造调用行号(本函数无 cl 参数,实参节点最接近调用点) - diag_node_ct: ast.AST | t.CPtr = None - if cargs is not None and len(cargs) > 0: - diag_node_ct = cargs.get(0) - - # 检查是否为 OOP 结构体(用类型指针定位 entry,规避跨模块同名 find_struct 找错) - ctor_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) - is_oop: int = 0 - if ctor_entry is not None: - is_oop = ctor_entry.IsOOP - - # 跨模块 OOP 类推断:IsOOP 可能未设置(Phase1 缓存跳过 _translate_oop_methods) - # 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入) - # 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠) - if is_oop == 0 and class_name is not None: - init_lookup_name: str = pool.alloc(128) - if init_lookup_name is not None: - viperlib.snprintf(init_lookup_name, 128, "%s.__init__", class_name) - # 方案1: 检查当前模块的函数声明 - init_found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, init_lookup_name) - if init_found_func is not None: - is_oop = 1 - if ctor_entry is not None: - ctor_entry.IsOOP = 1 - ctor_entry.HasInit = 1 - else: - # 方案2: 检查全局默认参数表(翻译时填充,不依赖 stub 注入) - init_defaults_entry: FuncDefaultsEntry | t.CPtr = ExprCallTable.find_func_defaults(init_lookup_name) - if init_defaults_entry is not None: - is_oop = 1 - if ctor_entry is not None: - ctor_entry.IsOOP = 1 - ctor_entry.HasInit = 1 - - if is_oop != 0: - # 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针 - storage_ptr: llvmlite.Value | t.CPtr = tmp - - # 如果有 __new__,调用 __new__(tmp, args...) 获取实际存储指针 - # __new__ 签名与 __init__ 一样(self + args),返回 Ptr(struct_ty) - has_new_flag: int = 0 - if ctor_entry is not None: - has_new_flag = ctor_entry.HasNew - # 注意: __new__ 是可选的,不推断 HasNew(仅 __init__ 是 OOP 类标准方法) - if has_new_flag != 0: - new_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if new_arg_vals is not None: - string.memset(new_arg_vals, 0, 8 * 32) - new_arg_count: int = 0 - for nai in range(can): - new_arg_node: ast.AST | t.CPtr = cargs.get(nai) - if new_arg_node is None: - continue - new_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, new_arg_node, None, 0, trans) - if new_av is not None: - if new_arg_count < 32: - new_arg_vals[new_arg_count] = t.CSizeT(new_av) - new_arg_count += 1 - - new_ptr: llvmlite.Value | t.CPtr = ExprCallCtor._call_method_on_ptr( - pool, builder, mod, class_name, - "__new__", tmp, new_arg_vals, new_arg_count, trans, diag_node_ct) - if new_ptr is not None: - storage_ptr = new_ptr - # __new__ 只保证返回"实例存储指针",声明类型通常是 - # `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。 - # 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的 - # obj.method(如 parser.add_argument)get_class_name_by_type - # 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。 - # bitcast 只改类型层视图,运行时零开销(指针位不变)。 - if new_ptr.Ty is not None: - nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) - if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty): - nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty) - if nw_bc is not None: - storage_ptr = nw_bc - - # OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值 - ExprCallCtor._call_method_on_ptr(pool, builder, mod, class_name, - "__before_init__", storage_ptr, None, 0, trans, diag_node_ct) - - # 如果有 __init__,调用 __init__(ptr, args...) - # 注意: 仅依据 ctor_entry.HasInit 判断,不强制推断 - # (JsonValue 等类有 __new__ 但无 __init__,强制推断会导致 undefined reference) - has_init_flag: int = 0 - if ctor_entry is not None: - has_init_flag = ctor_entry.HasInit - if has_init_flag != 0: - # 翻译构造函数参数 - arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if arg_vals is not None: - string.memset(arg_vals, 0, 8 * 32) - real_arg_count: int = 0 - for ai in range(can): - arg_node: ast.AST | t.CPtr = cargs.get(ai) - if arg_node is None: - continue - av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg_node, None, 0, trans) - if av is not None: - if real_arg_count < 32: - arg_vals[real_arg_count] = t.CSizeT(av) - real_arg_count += 1 - - ExprCallCtor._call_method_on_ptr(pool, builder, mod, class_name, - "__init__", storage_ptr, arg_vals, real_arg_count, trans, diag_node_ct) - elif has_new_flag == 0: - # 无 __init__ 且无 __new__:逐字段 store 参数值 - # (有 __new__ 时参数已由 __new__ 消费,不应存入字段) - for ai in range(can): - arg: ast.AST | t.CPtr = cargs.get(ai) - if arg is None: - continue - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg, None, 0, trans) - if arg_val is None: - # fast-fail: 参数翻译失败 - VLogger.error( - f"构造函数参数翻译失败: {class_name}", - "HandlesExprCall") - continue - fe: HandlesStruct.FieldEntry | t.CPtr = None - if ctor_entry is not None: - # OOP 结构体字段表第 0 个字段是 __vtable__(vtable 指针占位), - # 构造参数按"用户字段顺序"存储:必须跳过 __vtable__ 字段, - # 否则参数会覆盖 vtable 槽(对象头读到垃圾指针, - # isinstance 的 icmp 全部不匹配 + 方法分派错乱)。 - # 原实现直接 _get_field_entry(ctor_entry, ai) 取到 __vtable__ - # → GEP Index 0 → 覆盖 vtable(Dog("dog") 场景崩溃漂移根因)。 - target_idx: int = 0 - for fi in range(ctor_entry.FieldCount): - cand_fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( - ctor_entry, fi) - if cand_fe is None: - continue - cand_name: str = HandlesStruct.get_field_name_ptr(cand_fe) - if cand_name is not None and string.strcmp(cand_name, "__vtable__") == 0: - continue - if target_idx == ai: - fe = cand_fe - break - target_idx += 1 - else: - fe = HandlesStruct.get_field_by_index(class_name, ai) - if fe is None: - # fast-fail: 字段索引越界(用户传了多余参数) - VLogger.error( - f"构造函数参数过多,字段索引越界: {class_name}", - "HandlesExprCall") - continue - field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, struct_ty, fe.Ty, storage_ptr, fe.Index) - if field_ptr is None: - # fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配) - VLogger.error( - f"构造函数字段 GEP 失败: {class_name}", - "HandlesExprCall") - continue - arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty, arg) - llvmlite.build_store(builder, arg_val, field_ptr) - - # 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load - return storage_ptr - - # 普通结构体:先 store zeroinitializer 清零(确保未赋值字段为零) - zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) - llvmlite.build_store(builder, zero, tmp) - - # 应用默认值(显式参数会覆盖默认值) - self._apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans) - - # 逐字段 store 参数值(覆盖默认值) - for ai in range(can): - arg: ast.AST | t.CPtr = cargs.get(ai) - if arg is None: - continue - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg, None, 0, trans) - if arg_val is None: - # fast-fail: 参数翻译失败 - VLogger.error( - f"构造函数参数翻译失败: {class_name}", - "HandlesExprCall") - continue - # 获取字段信息(用 ctor_entry 规避跨模块同名 find_struct 找错) - fe: HandlesStruct.FieldEntry | t.CPtr = None - if ctor_entry is not None: - fe = HandlesStruct._get_field_entry(ctor_entry, ai) - else: - fe = HandlesStruct.get_field_by_index(class_name, ai) - if fe is None: - # fast-fail: 字段索引越界(用户传了多余参数) - VLogger.error( - f"构造函数参数过多,字段索引越界: {class_name}", - "HandlesExprCall") - continue - # GEP 到字段 ai - field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, struct_ty, fe.Ty, tmp, fe.Index) - if field_ptr is None: - # fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配) - VLogger.error( - f"构造函数字段 GEP 失败: {class_name}", - "HandlesExprCall") - continue - # 类型转换并 store - arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty, arg) - llvmlite.build_store(builder, arg_val, field_ptr) - - # 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load - return tmp - # ============================================================ - # _translate_renum_construct — REnum 变体构造函数 - # - # 语法: ClassName.VariantName(args...) - # 如 LLVMType.Int(1) → 构造 LLVMType 的 Int 变体,__tag=0,_p1=1 - # - # 生成 IR: - # %tmp = alloca {i32, i32, ...} ; REnum 类型 - # store zeroinitializer, %tmp ; 清零 - # %tag_ptr = gep %tmp, 0, 0 ; __tag 字段 - # store i32 , %tag_ptr ; 写入 tag - # %p1_ptr = gep %tmp, 0, 1 ; _p1 字段 - # store , %p1_ptr ; 写入 payload[0] - # ... (更多 payload 字段) - # return %tmp ; 返回指针 - # - # 对应 TPC 的 _HandleREnumConstructLlvm - # ============================================================ - - # ============================================================ - def _translate_renum_construct(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, - variant_name: str, - tag_value: int, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """构造 REnum 变体实例,返回指向 alloca 的指针 - - class_name: REnum 类名(如 "LLVMType") - variant_name: 变体名(如 "Int") - tag_value: 变体的 tag 值(变体在类中的索引) - cargs: 参数 AST 列表 - can: 参数数量 - """ - if pool is None or builder is None or class_name is None: - return None - - # 查找 REnum 结构体类型(用 find_struct_by_module 规避跨模块同名) - renum_entry: HandlesStruct.StructEntry | t.CPtr = None - if trans is not None: - renum_entry = HandlesStruct.find_struct_by_module(class_name, trans.ModuleSha1) - if renum_entry is None: - renum_entry = HandlesStruct.find_struct(class_name) - if renum_entry is None: - fb_re: str = VLogger.fmt_buf() - if fb_re is not None: - viperlib.snprintf(fb_re, 1024, "REnum construct: type %s not registered", class_name) - VLogger.error(fb_re, "RENUM") - return None - - renum_ty: llvmlite.LLVMType | t.CPtr = renum_entry.Ty - if renum_ty is None: - return None - - # alloca REnum 类型 - # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) - HandlesStruct.ensure_struct_def_in_module(pool, mod, renum_ty) - tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, renum_ty) - if tmp is None: - return llvmlite.ConstZero(pool, renum_ty) - - # 清零(确保未赋值的 payload 位置为零) - zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, renum_ty) - llvmlite.build_store(builder, zero, tmp) - - # 写入 __tag 字段(索引 0) - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - tag_name_buf: str = pool.alloc(32) - if tag_name_buf is not None: - viperlib.snprintf(tag_name_buf, 32, "%d", tag_value) - tag_const: llvmlite.Value | t.CPtr = llvmlite.ConstInt( - pool, i32_ty, tag_value, - tag_name_buf if tag_name_buf is not None else "0") - tag_field: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(renum_entry, 0) - tag_field_ty: llvmlite.LLVMType | t.CPtr = i32_ty - if tag_field is not None and tag_field.Ty is not None: - tag_field_ty = tag_field.Ty - tag_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, renum_ty, tag_field_ty, tmp, 0) - if tag_ptr is not None: - llvmlite.build_store(builder, tag_const, tag_ptr) - - # 写入 payload 字段(索引 1, 2, ... 对应 _p1, _p2, ...) - # 参数按位置顺序填充 payload,跳过 __tag(索引 0) - for ai in range(can): - arg: ast.AST | t.CPtr = cargs.get(ai) - if arg is None: - continue - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg, None, 0, trans) - if arg_val is None: - continue - # payload 字段索引 = ai + 1(跳过 __tag) - payload_idx: int = ai + 1 - if payload_idx >= renum_entry.FieldCount: - break - pfe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( - renum_entry, payload_idx) - if pfe is None: - continue - payload_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, renum_ty, pfe.Ty, tmp, payload_idx) - if payload_ptr is None: - continue - # 类型转换并 store(payload 位置可能是 i32 或 i64,按字段类型 coerce) - arg_val = HandlesExpr.coerce_to_type(builder, arg_val, pfe.Ty, arg) - llvmlite.build_store(builder, arg_val, payload_ptr) - - # 返回指针(与 _translate_struct_ctor 一致,赋值时由 coerce_to_type 决定是否 load) - return tmp - # ============================================================ - # _translate_struct_ctor_kw — 结构体构造函数(关键字参数) - # - # 支持两种语法: - # Point(x=10, y=20) — 全关键字 - # Point(10, y=20) — 混合(位置 + 关键字) - # - # 位置参数按字段索引赋值,关键字参数按字段名查找赋值 - # ============================================================ - - # ============================================================ - def _translate_struct_ctor_kw(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - struct_ty: llvmlite.LLVMType | t.CPtr, - class_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - keywords: list[ast.AST | t.CPtr] | t.CPtr, - kw_count: t.CSizeT, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """结构体构造函数(关键字参数版本)""" - # 创建临时 alloca - # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) - HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) - tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) - if tmp is None: - return llvmlite.ConstZero(pool, struct_ty) - # 诊断节点:取第一个构造实参(有行号),供 _call_method_on_ptr 的 - # fatal_error 显示构造调用行号(本函数无 cl 参数,实参节点最接近调用点) - diag_node_ct: ast.AST | t.CPtr = None - if cargs is not None and len(cargs) > 0: - diag_node_ct = cargs.get(0) - - # OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值 - # 用 find_struct_by_type 规避跨模块同名 find_struct 找错 - kw_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) - is_oop: int = 0 - if kw_entry is not None: - is_oop = kw_entry.IsOOP - - # 跨模块 OOP 类推断:IsOOP 可能未设置(Phase1 缓存跳过 _translate_oop_methods) - # 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入) - # 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠) - if is_oop == 0 and class_name is not None: - kw_init_lookup: str = pool.alloc(128) - if kw_init_lookup is not None: - viperlib.snprintf(kw_init_lookup, 128, "%s.__init__", class_name) - # 方案1: 检查当前模块的函数声明 - kw_init_found: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, kw_init_lookup) - if kw_init_found is not None: - is_oop = 1 - if kw_entry is not None: - kw_entry.IsOOP = 1 - kw_entry.HasInit = 1 - else: - # 方案2: 检查全局默认参数表(翻译时填充,不依赖 stub 注入) - kw_init_defaults: FuncDefaultsEntry | t.CPtr = ExprCallTable.find_func_defaults(kw_init_lookup) - if kw_init_defaults is not None: - is_oop = 1 - if kw_entry is not None: - kw_entry.IsOOP = 1 - kw_entry.HasInit = 1 - - if is_oop != 0: - ExprCallCtor._call_method_on_ptr(pool, builder, mod, class_name, - "__before_init__", tmp, None, 0, trans) - else: - # 普通结构体:store zeroinitializer + 应用默认值 - zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) - llvmlite.build_store(builder, zero, tmp) - self._apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans) - - # OOP 结构体且有 __init__:调用 __init__ 而非逐字段 store - # 关键字构造调用此前总是逐字段 store,导致 __init__ 方法体不执行 - # (如 self._args = mb.alloc(...) 不执行 → self._args 为 NULL → add_argument 崩溃) - has_init_flag: int = 0 - has_new_flag: int = 0 - if kw_entry is not None: - has_init_flag = kw_entry.HasInit - has_new_flag = kw_entry.HasNew - - # 跨模块 OOP 类: HasInit 可能未设置(_translate_oop_methods 未被调用) - # 但 IsOOP=1 说明类有方法,推断 HasInit=1(__init__ 在目标模块中存在) - # 注意: __new__ 是可选的,不推断 HasNew(仅 __init__ 是 OOP 类标准方法) - if is_oop != 0 and has_init_flag == 0: - has_init_flag = 1 - - if is_oop != 0 and has_init_flag != 0: - # 有 __init__:构建参数数组并调用 __init__ - storage_ptr: llvmlite.Value | t.CPtr = tmp - - # 如果有 __new__,调用 __new__ 获取实际存储指针 - if has_new_flag != 0: - new_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if new_arg_vals is not None: - string.memset(new_arg_vals, 0, 8 * 32) - new_arg_count: int = 0 - for nai in range(can): - new_arg_node: ast.AST | t.CPtr = cargs.get(nai) - if new_arg_node is None: - continue - new_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, new_arg_node, None, 0, trans) - if new_av is not None: - if new_arg_count < 32: - new_arg_vals[new_arg_count] = t.CSizeT(new_av) - new_arg_count += 1 - # 关键字参数也传递给 __new__ - for nki in range(kw_count): - nkw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(nki)) - if nkw is None or nkw.value is None: - continue - nkw_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, nkw.value, None, 0, trans) - if nkw_av is not None: - if new_arg_count < 32: - new_arg_vals[new_arg_count] = t.CSizeT(nkw_av) - new_arg_count += 1 - new_ptr: llvmlite.Value | t.CPtr = ExprCallCtor._call_method_on_ptr( - pool, builder, mod, class_name, - "__new__", tmp, new_arg_vals, new_arg_count, trans, diag_node_ct) - if new_ptr is not None: - storage_ptr = new_ptr - # __new__ 只保证返回"实例存储指针",声明类型通常是 - # `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。 - # 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的 - # obj.method(如 parser.add_argument)get_class_name_by_type - # 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。 - # bitcast 只改类型层视图,运行时零开销(指针位不变)。 - if new_ptr.Ty is not None: - nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) - if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty): - nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty) - if nw_bc is not None: - storage_ptr = nw_bc - - # 构建 __init__ 参数数组:位置参数按顺序 + 关键字参数追加 - init_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if init_arg_vals is not None: - string.memset(init_arg_vals, 0, 8 * 32) - init_arg_count: int = 0 - # 位置参数 - for ai_init in range(can): - arg_node_init: ast.AST | t.CPtr = cargs.get(ai_init) - if arg_node_init is None: - continue - av_init: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg_node_init, None, 0, trans) - if av_init is not None: - if init_arg_count < 32: - init_arg_vals[init_arg_count] = t.CSizeT(av_init) - init_arg_count += 1 - # 关键字参数(追加到末尾,按出现顺序) - for ki_init in range(kw_count): - kw_init: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki_init)) - if kw_init is None or kw_init.value is None: - continue - kw_av_init: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, kw_init.value, None, 0, trans) - if kw_av_init is not None: - if init_arg_count < 32: - init_arg_vals[init_arg_count] = t.CSizeT(kw_av_init) - init_arg_count += 1 - - # 调用 __init__(storage_ptr, *args) - ExprCallCtor._call_method_on_ptr(pool, builder, mod, class_name, - "__init__", storage_ptr, init_arg_vals, init_arg_count, trans, diag_node_ct) - - # 返回指针 - return storage_ptr - - # 无 __init__(或非 OOP):逐字段 store 参数值 - # 先处理位置参数(按字段索引,覆盖默认值) - for ai in range(can): - arg: ast.AST | t.CPtr = cargs.get(ai) - if arg is None: - continue - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg, None, 0, trans) - if arg_val is None: - continue - fe: HandlesStruct.FieldEntry | t.CPtr = None - if kw_entry is not None: - fe = HandlesStruct._get_field_entry(kw_entry, ai) - else: - fe = HandlesStruct.get_field_by_index(class_name, ai) - if fe is None: - # 位置参数越界(字段表无对应项):fail-fast,绝不静默跳过 - HandlesType.fatal_error( - arg, f"结构体 '{class_name}' 位置参数越界(无对应字段)", "TypeError") - continue - field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, struct_ty, fe.Ty, tmp, fe.Index) - if field_ptr is None: - continue - arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty, arg) - llvmlite.build_store(builder, arg_val, field_ptr) - - # 处理关键字参数(按字段名查找) - # SHA1 从 kw_entry 获取(规避跨模块同名 find_struct 找错) - kw_sha1: str = None - if kw_entry is not None: - kw_sha1 = kw_entry.ModuleSha1 - for ki in range(kw_count): - kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki)) - if kw is None or kw.arg is None or kw.value is None: - continue - fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field_by_class( - class_name, kw.arg, kw_sha1) - if fe is None: - # 关键字字段不存在:fail-fast(AttributeError),绝不静默跳过 - HandlesType.fatal_error( - kw, f"结构体 '{class_name}' 无字段 '{kw.arg}'", "AttributeError") - continue - kw_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, kw.value, None, 0, trans) - if kw_val is None: - continue - field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, struct_ty, fe.Ty, tmp, fe.Index) - if field_ptr is None: - continue - kw_val = HandlesExpr.coerce_to_type(builder, kw_val, fe.Ty, kw.value) - llvmlite.build_store(builder, kw_val, field_ptr) - - # 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load - return tmp - # ============================================================ - # _translate_t_type_cast - 翻译 t.XXX(value) 类型转换 - # - # 当 func 是 t.XXX 形式且 XXX 是已知类型名(map_t_type 能映射)时, - # 将 value 转换为目标类型: - # - 指针 → 整数: ptrtoint (如 t.CUInt64T(ptr) → i64) - # - 整数 → 指针: inttoptr (如 t.CPtr(int_val) → i8*) - # - 整数 → 整数: trunc/zext (如 t.CInt8T(i32_val) → i8) - # - 指针 → 指针: bitcast (如 t.CPtr(ptr_val) → i8*) - # - 整数 → 浮点: sitofp (如 t.CDouble(i32_val) → double) - # - 浮点 → 整数: fptosi (如 t.CInt(double_val) → i32) - # - 浮点 → 浮点: fpext/fptrunc (如 t.CFloat(double_val) → float) - # ============================================================ - - # ============================================================ - def _translate_t_type_cast(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - val: llvmlite.Value | t.CPtr, - target_ty: llvmlite.LLVMType | t.CPtr, - target_name: str = None, - src_node: ast.AST | t.CPtr = None, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """类型转换:根据参数类型和目标类型选择转换方式 - - 整数 → 整数拓宽时(对齐 TPC _HandleTypeCastLlvm L1723-1737): - 源 i1(bool)→ zext - 目标类型无符号(target_name 命中 CUIntXXT 等)→ zext - 源表达式无符号(t.CUIntXXT(x) 强转 / 无符号注解变量)→ zext - 否则 → sext(有符号整数拓宽保持数值,如 i8 -50 → 0xFFFFFFCE) - """ - if val is None or target_ty is None: - return None - - val_bits: int = HandlesExpr.get_llvm_type_bits(val.Ty) - target_bits: int = HandlesExpr.get_llvm_type_bits(target_ty) - val_fbits: int = HandlesExpr.get_llvm_float_bits(val.Ty) - target_fbits: int = HandlesExpr.get_llvm_float_bits(target_ty) - - # 整数 → 整数: trunc/zext/sext - if val_bits != 0 and target_bits != 0: - if val_bits == target_bits: - return val - elif val_bits < target_bits: - if val_bits == 1: - # i1 是布尔值(来自 icmp/fcmp),无符号语义,必须 zext - return llvmlite.build_zext(builder, val, target_ty) - # 目标类型名已知且为有符号 → 按源符号性 sext/zext(对齐 TPC L1723-1737); - # 目标名未知(int()/联合类型强转等)保持默认 zext(旧行为) - need_sext: int = 0 - if target_name is not None and HandlesExpr._type_name_unsigned(target_name) == 0: - if src_node is None or HandlesExpr._node_type_unsigned(pool, src_node, trans) == 0: - need_sext = 1 - if need_sext != 0: - return llvmlite.build_sext(builder, val, target_ty) - return llvmlite.build_zext(builder, val, target_ty) - else: - return llvmlite.build_trunc(builder, val, target_ty) - - # 整数 → 浮点: sitofp - if val_bits != 0 and target_fbits != 0: - return llvmlite.build_si2fp(builder, val, target_ty) - - # 浮点 → 整数: fptosi - if val_fbits != 0 and target_bits != 0: - return llvmlite.build_fp2si(builder, val, target_ty) - - # 浮点 → 浮点: fpext/fptrunc - if val_fbits != 0 and target_fbits != 0: - if val_fbits == target_fbits: - return val - elif val_fbits < target_fbits: - return llvmlite.build_fpext(builder, val, target_ty) - else: - return llvmlite.build_fptrunc(builder, val, target_ty) - - # 指针 → 整数: ptrtoint - if val_bits == 0 and val_fbits == 0 and target_bits != 0: - return llvmlite.build_ptrtoint(builder, val, target_ty) - - # 整数 → 指针: inttoptr(必须排除浮点 target,浮点 target_bits 也是 0) - if val_bits != 0 and target_bits == 0 and target_fbits == 0: - return llvmlite.build_inttoptr(builder, val, target_ty) - - # 指针 → 指针: bitcast - return llvmlite.build_bitcast(builder, val, target_ty) - # ============================================================ - # 泛型实例化辅助:从 Subscript slice 提取类型实参名 - # ============================================================ - # _get_type_name_from_annotation 已移至 HandlesType.py(支持 BinOp/Attribute) - # HandlesExprCall 通过 HandlesType._get_type_name_from_annotation 调用 - - - # ============================================================ - # 泛型实例化辅助:从 Subscript slice 提取类型实参名 - # ============================================================ - # _get_type_name_from_annotation 已移至 HandlesType.py(支持 BinOp/Attribute) - # HandlesExprCall 通过 HandlesType._get_type_name_from_annotation 调用 - - def _extract_type_args_from_slice(self, pool: memhub.MemBuddy | t.CPtr, - slice_node: ast.AST | t.CPtr) -> list[str] | t.CPtr: - """从 Subscript.slice 提取类型实参名列表 - - list[int] -> ["int"] - dict[str, int] -> ["str", "int"] - list[AST | t.CPtr] -> ["AST|t.CPtr"] - """ - if slice_node is None or pool is None: - return None - # elem_size=8:str 是 i8* 指针(8 字节),若用 4 则双元素时 append 写 8 字节 - # 但步长按 4 计算,第 2 个元素覆盖第 1 个元素高 4 字节 → get 读出垃圾指针崩溃 - result: list[str] | t.CPtr = list[str](pool, 8) - k: int = slice_node.kind() - if k == ast.ASTKind.Tuple: - tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(slice_node) - elts: list[ast.AST | t.CPtr] | t.CPtr = tp.elts - if elts is not None: - n: t.CSizeT = len(elts) - i: t.CSizeT - for i in range(n): - elt: ast.AST | t.CPtr = elts.get(i) - tn: str = HandlesType._get_type_name_from_annotation(pool, elt) - if tn is not None: - result.append(tn) - else: - tn: str = HandlesType._get_type_name_from_annotation(pool, slice_node) - if tn is not None: - result.append(tn) - return result - # ============================================================ - # 泛型类构造调用辅助: list[str](pool, 8) → __new__ + __before_init__ + __init__ - # - # 复用 translate_list_literal 的构造逻辑: - # 1. alloca tmp(特化类临时空间,作为 __new__ 的 self) - # 2. 翻译 cl.args 为参数指针数组 - # 3. call __new__(tmp, *args) → storage_ptr - # 4. call __before_init__(storage_ptr) - # 5. call __init__(storage_ptr, *args) - # 6. return storage_ptr - # - # 必须独立于 translate_call 的普通函数路径:spec_name 是类名不是函数名, - # 走裸名路径会被 _lookup_mod_sha1 的 star import 回退误导,用错误的 SHA1 - # 且缺少 __new__ 方法名后缀,导致链接报 undefined reference。 - # ============================================================ - - # ============================================================ - def _infer_generic_ctor_type_arg(self, pool: memhub.MemBuddy | t.CPtr, - arg_node: ast.AST | t.CPtr, - class_name: str) -> str: - """从构造实参 AST 推断泛型类型实参名;无法推断时 fail-fast(绝不默认 "int") - - 裸名泛型类构造(Box(42) → Box[int])需要从实参推断类型实参。 - 对应 TPC _HandleGenericClassNewLlvm 的推断逻辑(常量/类型转换调用)。 - 注意:本函数仅做 AST 静态推断,不发射 IR(避免重复翻译实参)。 - """ - if pool is None or arg_node is None: - HandlesType.fatal_error( - None, - f"无法从实参推断泛型类 '{class_name}' 的类型实参,请显式标注如 {class_name}[类型](...)", - "TypeError") - return "int" - k: int = arg_node.kind() - # 常量: 42→int, 3.14→double, "abc"→str - if k == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg_node) - if cn.const_kind == ast.CONST_FLOAT: - return "double" - if cn.const_kind == ast.CONST_STR: - return "str" - return "int" - # 类型转换调用: int(...)/float(...)/t.CInt(...)/t.CDouble(...) - if k == ast.ASTKind.Call: - cl_f: ast.Call | t.CPtr = (ast.Call | t.CPtr)(arg_node) - if cl_f.func is not None: - if cl_f.func.kind() == ast.ASTKind.Name: - fn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl_f.func) - if fn_nm.id is not None: - # 与下方 Attribute 分支的 strstr 匹配一致:from t import CInt - # 后 `CInt(0)` 的 func 是 Name("CInt"),仅精确匹配 int/float - # 会漏判 → fail-fast 误杀(VectorGenericTest 隐式泛型推断)。 - if string.strcmp(fn_nm.id, "float") == 0 or string.strcmp(fn_nm.id, "double") == 0 \ - or string.strstr(fn_nm.id, "Float") is not None or string.strstr(fn_nm.id, "Double") is not None: - return "double" - if string.strcmp(fn_nm.id, "int") == 0 \ - or string.strstr(fn_nm.id, "Int") is not None or string.strstr(fn_nm.id, "UInt") is not None \ - or string.strstr(fn_nm.id, "Char") is not None or string.strstr(fn_nm.id, "Short") is not None \ - or string.strstr(fn_nm.id, "Long") is not None: - return "int" - elif cl_f.func.kind() == ast.ASTKind.Attribute: - fn_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl_f.func) - if fn_at.attr is not None: - if string.strstr(fn_at.attr, "Float") is not None or string.strstr(fn_at.attr, "Double") is not None: - return "double" - if string.strstr(fn_at.attr, "Int") is not None or string.strstr(fn_at.attr, "UInt") is not None or string.strstr(fn_at.attr, "Char") is not None or string.strstr(fn_at.attr, "Short") is not None or string.strstr(fn_at.attr, "Long") is not None: - return "int" - # 类型转换调用(Call)但函数名无法识别:明确的类型意图却无法解析, - # fail-fast(区别于普通变量 Name——那是非 T 参数,默认 int 被过滤)。 - HandlesType.fatal_error( - arg_node, - f"无法从实参推断泛型类 '{class_name}' 的类型实参,请显式标注如 {class_name}[类型](...)", - "TypeError") - return "int" - # 非类型转换节点(普通变量 Name/Attribute 等,如 Vector(pool, 8, ...) - # 的 pool 参数):不是 T 类型提示,返回默认 "int"(调用方"过滤纯 int" - # 逻辑将其排除,只保留 float/str 等区分性提示)。 - return "int" - def _translate_generic_ctor_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - spec_name: str, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """泛型类构造调用: list[str](pool, 8) → __new__ + __before_init__ + __init__""" - if pool is None or builder is None or mod is None or spec_name is None or cl is None: - return None - - # 查找 struct entry 获取类型 - struct_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name) - if struct_entry is None: - HandlesType.fatal_error(cl, "泛型类构造调用: 特化类未注册") - return None - struct_ty: llvmlite.LLVMType | t.CPtr = struct_entry.Ty - if struct_ty is None: - return None - - # 确保结构体定义在当前模块中可用(供 alloca 分配空间) - HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) - - # alloca tmp(self 指针) - tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) - if tmp is None: - return None - - # 翻译 cl.args 为参数指针数组(extra_args[i] = Value 指针) - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - can: t.CSizeT = 0 - if cargs is not None: - can = len(cargs) - - extra_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if extra_args is None: - return None - string.memset(extra_args, 0, 8 * 32) - - ai: t.CSizeT = 0 - while ai < can: - if ai >= 32: - # 定长 8*32 槽:超过 32 个实参继续写会越界污染 pool 相邻块,fail-fast - HandlesType.fatal_error( - cl, "泛型构造实参超过 32 个上限", "TypeError") - break - arg_node: ast.AST | t.CPtr = cargs.get(ai) - if arg_node is not None: - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg_node, None, 0, trans) - if arg_val is not None: - extra_args[ai] = t.CSizeT(arg_val) - ai += 1 - - # 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针 - # __new__ 是可选的,仅当泛型类模板定义了 __new__ 方法时才调用 - # (与 _translate_struct_ctor 保持一致,避免为无 __new__ 的类生成过度声明) - storage_ptr: llvmlite.Value | t.CPtr = tmp - has_new_flag: int = 0 - if struct_entry is not None: - has_new_flag = struct_entry.HasNew - if has_new_flag != 0: - new_ptr: llvmlite.Value | t.CPtr = ExprCallCtor._call_method_on_ptr( - pool, builder, mod, spec_name, "__new__", tmp, extra_args, can, trans) - if new_ptr is not None: - storage_ptr = new_ptr - # __new__ 只保证返回"实例存储指针",声明类型通常是 - # `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。 - # 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的 - # obj.method(如 parser.add_argument)get_class_name_by_type - # 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。 - # bitcast 只改类型层视图,运行时零开销(指针位不变)。 - if new_ptr.Ty is not None: - nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) - if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty): - nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty) - if nw_bc is not None: - storage_ptr = nw_bc - - # call __before_init__(storage_ptr)(TransPyV 自动生成,零值填充) - ExprCallCtor._call_method_on_ptr( - pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans) - - # call __init__(storage_ptr, *args) - ExprCallCtor._call_method_on_ptr( - pool, builder, mod, spec_name, "__init__", storage_ptr, extra_args, can, trans) - +import lib.core.Gen.GenTypes as GenTypes +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import sys +import viperlib +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.CallGenBase as CallGenBase +import lib.core.Handles.ExprCallTable as ExprCallTable + +# ============================================================ +# CallGenCtor - CallGenMixin 拆分(阶段 B):结构体构造 / 枚举构造 / 泛型构造 / 类型转换 +# +# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class CallGenCtor(CallGenBase.CallGenBase): + """结构体构造 / 枚举构造 / 泛型构造 / 类型转换""" + + # ============================================================ + # _apply_struct_defaults — 应用结构体字段的默认值 + # + # 在 zeroinitializer 之后、显式参数之前调用 + # 遍历所有字段,对有默认值的字段翻译并 store + # 显式参数(位置/关键字)后续会覆盖默认值 + # ============================================================ + def _apply_struct_defaults(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr, + class_name: str, + tmp: llvmlite.Value | t.CPtr, + trans: HT.Translator | t.CPtr): + """应用结构体字段的默认值""" + # 用类型指针定位 entry,规避跨模块同名 find_struct 找错 + entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_type(struct_ty) + if entry is None: + # fast-fail: 结构体类型未注册,静默 return 会导致字段未初始化 + VLogger.error( + f"结构体类型未注册,无法应用默认值: {class_name}", + "HandlesExprCall") + return + for fi in range(entry.FieldCount): + fe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry( + entry, fi) + if fe is None: + # fast-fail: 字段索引越界(entry.FieldCount 与实际不一致) + VLogger.error( + f"字段索引越界,无法获取字段 entry: {class_name}", + "HandlesExprCall") + continue + if fe.DefaultVal is None: + continue # 合理跳过:无默认值的字段 + # 静态数组字段 + 列表字面量默认值 → 整体置零 + 逐元素 GEP+store + # (与 _generate_before_init 一致;translate_value 会把列表字面量 + # 误译成动态 list 对象指针,coerce 到 [N x elem] 会失败)。 + # Mixin 静态绑定:跨 Mixin 方法必须走 HandlesAnnAssign 模块级委托。 + if fe.Ty is not None and self.Gen.ExprGenBase.is_array_type(fe.Ty) != 0 \ + and fe.DefaultVal.kind() == ast.ASTKind.List: + field_ptr_arr2: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, fe.Ty, tmp, fe.Index) + if field_ptr_arr2 is not None: + zero_arr2: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, fe.Ty) + if zero_arr2 is not None: + llvmlite.build_store(builder, zero_arr2, field_ptr_arr2) + self.Gen.AssignGen._init_global_array_from_list( + builder, pool, mod, field_ptr_arr2, fe.DefaultVal, trans) + continue + default_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, fe.DefaultVal, None, 0, trans) + if default_val is None: + # fast-fail: 默认值翻译失败(如引用了未定义符号) + VLogger.error( + f"字段默认值翻译失败: {class_name}", + "HandlesExprCall") + continue + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, fe.Ty, tmp, fe.Index) + if field_ptr is None: + # fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配) + VLogger.error( + f"字段 GEP 失败,类型不匹配: {class_name}", + "HandlesExprCall") + continue + default_val = self.Gen.ExprGenBase.coerce_to_type(builder, default_val, fe.Ty, fe.DefaultVal) + llvmlite.build_store(builder, default_val, field_ptr) + # ============================================================ + # _translate_struct_ctor — 结构体构造函数 Point(10, 20) + # + # 生成: + # %tmp = alloca {i32, i32} + # store {i32, i32} zeroinitializer, {i32, i32}* %tmp + # %f0 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 0 + # store i32 10, i32* %f0 + # %f1 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 1 + # store i32 20, i32* %f1 + # %result = load {i32, i32}, {i32, i32}* %tmp + # ============================================================ + + # ============================================================ + def _translate_struct_ctor(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr, + class_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """结构体构造函数:按字段顺序 store 参数值,返回结构体值 + + OOP 结构体:alloca → call __before_init__(ptr) → call __init__(ptr, args) 或 store 参数 → load + 普通结构体:alloca → zero + defaults → store 参数 → load + """ + # 创建临时 alloca + # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) + self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, struct_ty) + tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) + if tmp is None: + return llvmlite.ConstZero(pool, struct_ty) + # 诊断节点:取第一个构造实参(有行号),供 _call_method_on_ptr 的 + # fatal_error 显示构造调用行号(本函数无 cl 参数,实参节点最接近调用点) + diag_node_ct: ast.AST | t.CPtr = None + if cargs is not None and len(cargs) > 0: + diag_node_ct = cargs.get(0) + + # 检查是否为 OOP 结构体(用类型指针定位 entry,规避跨模块同名 find_struct 找错) + ctor_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_type(struct_ty) + is_oop: int = 0 + if ctor_entry is not None: + is_oop = ctor_entry.IsOOP + + # 跨模块 OOP 类推断:IsOOP 可能未设置(Phase1 缓存跳过 _translate_oop_methods) + # 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入) + # 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠) + if is_oop == 0 and class_name is not None: + init_lookup_name: str = pool.alloc(128) + if init_lookup_name is not None: + viperlib.snprintf(init_lookup_name, 128, "%s.__init__", class_name) + # 方案1: 检查当前模块的函数声明 + init_found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, init_lookup_name) + if init_found_func is not None: + is_oop = 1 + if ctor_entry is not None: + ctor_entry.IsOOP = 1 + ctor_entry.HasInit = 1 + else: + # 方案2: 检查全局默认参数表(翻译时填充,不依赖 stub 注入) + init_defaults_entry: FuncDefaultsEntry | t.CPtr = self.Gen.CallGenLeafKit.find_func_defaults(init_lookup_name) + if init_defaults_entry is not None: + is_oop = 1 + if ctor_entry is not None: + ctor_entry.IsOOP = 1 + ctor_entry.HasInit = 1 + + if is_oop != 0: + # 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针 + storage_ptr: llvmlite.Value | t.CPtr = tmp + + # 如果有 __new__,调用 __new__(tmp, args...) 获取实际存储指针 + # __new__ 签名与 __init__ 一样(self + args),返回 Ptr(struct_ty) + has_new_flag: int = 0 + if ctor_entry is not None: + has_new_flag = ctor_entry.HasNew + # 注意: __new__ 是可选的,不推断 HasNew(仅 __init__ 是 OOP 类标准方法) + if has_new_flag != 0: + new_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if new_arg_vals is not None: + string.memset(new_arg_vals, 0, 8 * 32) + new_arg_count: int = 0 + for nai in range(can): + new_arg_node: ast.AST | t.CPtr = cargs.get(nai) + if new_arg_node is None: + continue + new_av: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, new_arg_node, None, 0, trans) + if new_av is not None: + if new_arg_count < 32: + new_arg_vals[new_arg_count] = t.CSizeT(new_av) + new_arg_count += 1 + + new_ptr: llvmlite.Value | t.CPtr = self.Gen.CallGenCall._call_method_on_ptr( + pool, builder, mod, class_name, + "__new__", tmp, new_arg_vals, new_arg_count, trans, diag_node_ct) + if new_ptr is not None: + storage_ptr = new_ptr + # __new__ 只保证返回"实例存储指针",声明类型通常是 + # `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。 + # 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的 + # obj.method(如 parser.add_argument)get_class_name_by_type + # 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。 + # bitcast 只改类型层视图,运行时零开销(指针位不变)。 + if new_ptr.Ty is not None: + nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) + if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty): + nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty) + if nw_bc is not None: + storage_ptr = nw_bc + + # OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值 + self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, class_name, + "__before_init__", storage_ptr, None, 0, trans, diag_node_ct) + + # 如果有 __init__,调用 __init__(ptr, args...) + # 注意: 仅依据 ctor_entry.HasInit 判断,不强制推断 + # (JsonValue 等类有 __new__ 但无 __init__,强制推断会导致 undefined reference) + has_init_flag: int = 0 + if ctor_entry is not None: + has_init_flag = ctor_entry.HasInit + if has_init_flag != 0: + # 翻译构造函数参数 + arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if arg_vals is not None: + string.memset(arg_vals, 0, 8 * 32) + real_arg_count: int = 0 + for ai in range(can): + arg_node: ast.AST | t.CPtr = cargs.get(ai) + if arg_node is None: + continue + av: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg_node, None, 0, trans) + if av is not None: + if real_arg_count < 32: + arg_vals[real_arg_count] = t.CSizeT(av) + real_arg_count += 1 + + self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, class_name, + "__init__", storage_ptr, arg_vals, real_arg_count, trans, diag_node_ct) + elif has_new_flag == 0: + # 无 __init__ 且无 __new__:逐字段 store 参数值 + # (有 __new__ 时参数已由 __new__ 消费,不应存入字段) + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is None: + continue + arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is None: + # fast-fail: 参数翻译失败 + VLogger.error( + f"构造函数参数翻译失败: {class_name}", + "HandlesExprCall") + continue + fe: GenTypes.FieldEntry | t.CPtr = None + if ctor_entry is not None: + # OOP 结构体字段表第 0 个字段是 __vtable__(vtable 指针占位), + # 构造参数按"用户字段顺序"存储:必须跳过 __vtable__ 字段, + # 否则参数会覆盖 vtable 槽(对象头读到垃圾指针, + # isinstance 的 icmp 全部不匹配 + 方法分派错乱)。 + # 原实现直接 _get_field_entry(ctor_entry, ai) 取到 __vtable__ + # → GEP Index 0 → 覆盖 vtable(Dog("dog") 场景崩溃漂移根因)。 + target_idx: int = 0 + for fi in range(ctor_entry.FieldCount): + cand_fe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry( + ctor_entry, fi) + if cand_fe is None: + continue + cand_name: str = self.Gen.StructGen.get_field_name_ptr(cand_fe) + if cand_name is not None and string.strcmp(cand_name, "__vtable__") == 0: + continue + if target_idx == ai: + fe = cand_fe + break + target_idx += 1 + else: + fe = self.Gen.StructGen.get_field_by_index(class_name, ai) + if fe is None: + # fast-fail: 字段索引越界(用户传了多余参数) + VLogger.error( + f"构造函数参数过多,字段索引越界: {class_name}", + "HandlesExprCall") + continue + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, fe.Ty, storage_ptr, fe.Index) + if field_ptr is None: + # fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配) + VLogger.error( + f"构造函数字段 GEP 失败: {class_name}", + "HandlesExprCall") + continue + arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, fe.Ty, arg) + llvmlite.build_store(builder, arg_val, field_ptr) + + # 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load + return storage_ptr + + # 普通结构体:先 store zeroinitializer 清零(确保未赋值字段为零) + zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) + llvmlite.build_store(builder, zero, tmp) + + # 应用默认值(显式参数会覆盖默认值) + self._apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans) + + # 逐字段 store 参数值(覆盖默认值) + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is None: + continue + arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is None: + # fast-fail: 参数翻译失败 + VLogger.error( + f"构造函数参数翻译失败: {class_name}", + "HandlesExprCall") + continue + # 获取字段信息(用 ctor_entry 规避跨模块同名 find_struct 找错) + fe: GenTypes.FieldEntry | t.CPtr = None + if ctor_entry is not None: + fe = self.Gen.StructGen._get_field_entry(ctor_entry, ai) + else: + fe = self.Gen.StructGen.get_field_by_index(class_name, ai) + if fe is None: + # fast-fail: 字段索引越界(用户传了多余参数) + VLogger.error( + f"构造函数参数过多,字段索引越界: {class_name}", + "HandlesExprCall") + continue + # GEP 到字段 ai + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, fe.Ty, tmp, fe.Index) + if field_ptr is None: + # fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配) + VLogger.error( + f"构造函数字段 GEP 失败: {class_name}", + "HandlesExprCall") + continue + # 类型转换并 store + arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, fe.Ty, arg) + llvmlite.build_store(builder, arg_val, field_ptr) + + # 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load + return tmp + # ============================================================ + # _translate_renum_construct — REnum 变体构造函数 + # + # 语法: ClassName.VariantName(args...) + # 如 LLVMType.Int(1) → 构造 LLVMType 的 Int 变体,__tag=0,_p1=1 + # + # 生成 IR: + # %tmp = alloca {i32, i32, ...} ; REnum 类型 + # store zeroinitializer, %tmp ; 清零 + # %tag_ptr = gep %tmp, 0, 0 ; __tag 字段 + # store i32 , %tag_ptr ; 写入 tag + # %p1_ptr = gep %tmp, 0, 1 ; _p1 字段 + # store , %p1_ptr ; 写入 payload[0] + # ... (更多 payload 字段) + # return %tmp ; 返回指针 + # + # 对应 TPC 的 _HandleREnumConstructLlvm + # ============================================================ + + # ============================================================ + def _translate_renum_construct(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, + variant_name: str, + tag_value: int, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """构造 REnum 变体实例,返回指向 alloca 的指针 + + class_name: REnum 类名(如 "LLVMType") + variant_name: 变体名(如 "Int") + tag_value: 变体的 tag 值(变体在类中的索引) + cargs: 参数 AST 列表 + can: 参数数量 + """ + if pool is None or builder is None or class_name is None: + return None + + # 查找 REnum 结构体类型(用 find_struct_by_module 规避跨模块同名) + renum_entry: GenTypes.StructEntry | t.CPtr = None + if trans is not None: + renum_entry = self.Gen.StructGen.find_struct_by_module(class_name, trans.ModuleSha1) + if renum_entry is None: + renum_entry = self.Gen.StructGen.find_struct(class_name) + if renum_entry is None: + fb_re: str = VLogger.fmt_buf() + if fb_re is not None: + viperlib.snprintf(fb_re, 1024, "REnum construct: type %s not registered", class_name) + VLogger.error(fb_re, "RENUM") + return None + + renum_ty: llvmlite.LLVMType | t.CPtr = renum_entry.Ty + if renum_ty is None: + return None + + # alloca REnum 类型 + # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) + self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, renum_ty) + tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, renum_ty) + if tmp is None: + return llvmlite.ConstZero(pool, renum_ty) + + # 清零(确保未赋值的 payload 位置为零) + zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, renum_ty) + llvmlite.build_store(builder, zero, tmp) + + # 写入 __tag 字段(索引 0) + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + tag_name_buf: str = pool.alloc(32) + if tag_name_buf is not None: + viperlib.snprintf(tag_name_buf, 32, "%d", tag_value) + tag_const: llvmlite.Value | t.CPtr = llvmlite.ConstInt( + pool, i32_ty, tag_value, + tag_name_buf if tag_name_buf is not None else "0") + tag_field: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry(renum_entry, 0) + tag_field_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if tag_field is not None and tag_field.Ty is not None: + tag_field_ty = tag_field.Ty + tag_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, renum_ty, tag_field_ty, tmp, 0) + if tag_ptr is not None: + llvmlite.build_store(builder, tag_const, tag_ptr) + + # 写入 payload 字段(索引 1, 2, ... 对应 _p1, _p2, ...) + # 参数按位置顺序填充 payload,跳过 __tag(索引 0) + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is None: + continue + arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is None: + continue + # payload 字段索引 = ai + 1(跳过 __tag) + payload_idx: int = ai + 1 + if payload_idx >= renum_entry.FieldCount: + break + pfe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry( + renum_entry, payload_idx) + if pfe is None: + continue + payload_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, renum_ty, pfe.Ty, tmp, payload_idx) + if payload_ptr is None: + continue + # 类型转换并 store(payload 位置可能是 i32 或 i64,按字段类型 coerce) + arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, pfe.Ty, arg) + llvmlite.build_store(builder, arg_val, payload_ptr) + + # 返回指针(与 _translate_struct_ctor 一致,赋值时由 coerce_to_type 决定是否 load) + return tmp + # ============================================================ + # _translate_struct_ctor_kw — 结构体构造函数(关键字参数) + # + # 支持两种语法: + # Point(x=10, y=20) — 全关键字 + # Point(10, y=20) — 混合(位置 + 关键字) + # + # 位置参数按字段索引赋值,关键字参数按字段名查找赋值 + # ============================================================ + + # ============================================================ + def _translate_struct_ctor_kw(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr, + class_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + keywords: list[ast.AST | t.CPtr] | t.CPtr, + kw_count: t.CSizeT, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """结构体构造函数(关键字参数版本)""" + # 创建临时 alloca + # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) + self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, struct_ty) + tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) + if tmp is None: + return llvmlite.ConstZero(pool, struct_ty) + # 诊断节点:取第一个构造实参(有行号),供 _call_method_on_ptr 的 + # fatal_error 显示构造调用行号(本函数无 cl 参数,实参节点最接近调用点) + diag_node_ct: ast.AST | t.CPtr = None + if cargs is not None and len(cargs) > 0: + diag_node_ct = cargs.get(0) + + # OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值 + # 用 find_struct_by_type 规避跨模块同名 find_struct 找错 + kw_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_type(struct_ty) + is_oop: int = 0 + if kw_entry is not None: + is_oop = kw_entry.IsOOP + + # 跨模块 OOP 类推断:IsOOP 可能未设置(Phase1 缓存跳过 _translate_oop_methods) + # 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入) + # 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠) + if is_oop == 0 and class_name is not None: + kw_init_lookup: str = pool.alloc(128) + if kw_init_lookup is not None: + viperlib.snprintf(kw_init_lookup, 128, "%s.__init__", class_name) + # 方案1: 检查当前模块的函数声明 + kw_init_found: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, kw_init_lookup) + if kw_init_found is not None: + is_oop = 1 + if kw_entry is not None: + kw_entry.IsOOP = 1 + kw_entry.HasInit = 1 + else: + # 方案2: 检查全局默认参数表(翻译时填充,不依赖 stub 注入) + kw_init_defaults: FuncDefaultsEntry | t.CPtr = self.Gen.CallGenLeafKit.find_func_defaults(kw_init_lookup) + if kw_init_defaults is not None: + is_oop = 1 + if kw_entry is not None: + kw_entry.IsOOP = 1 + kw_entry.HasInit = 1 + + if is_oop != 0: + self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, class_name, + "__before_init__", tmp, None, 0, trans) + else: + # 普通结构体:store zeroinitializer + 应用默认值 + zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) + llvmlite.build_store(builder, zero, tmp) + self._apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans) + + # OOP 结构体且有 __init__:调用 __init__ 而非逐字段 store + # 关键字构造调用此前总是逐字段 store,导致 __init__ 方法体不执行 + # (如 self._args = mb.alloc(...) 不执行 → self._args 为 NULL → add_argument 崩溃) + has_init_flag: int = 0 + has_new_flag: int = 0 + if kw_entry is not None: + has_init_flag = kw_entry.HasInit + has_new_flag = kw_entry.HasNew + + # 跨模块 OOP 类: HasInit 可能未设置(_translate_oop_methods 未被调用) + # 但 IsOOP=1 说明类有方法,推断 HasInit=1(__init__ 在目标模块中存在) + # 注意: __new__ 是可选的,不推断 HasNew(仅 __init__ 是 OOP 类标准方法) + if is_oop != 0 and has_init_flag == 0: + has_init_flag = 1 + + if is_oop != 0 and has_init_flag != 0: + # 有 __init__:构建参数数组并调用 __init__ + storage_ptr: llvmlite.Value | t.CPtr = tmp + + # 如果有 __new__,调用 __new__ 获取实际存储指针 + if has_new_flag != 0: + new_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if new_arg_vals is not None: + string.memset(new_arg_vals, 0, 8 * 32) + new_arg_count: int = 0 + for nai in range(can): + new_arg_node: ast.AST | t.CPtr = cargs.get(nai) + if new_arg_node is None: + continue + new_av: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, new_arg_node, None, 0, trans) + if new_av is not None: + if new_arg_count < 32: + new_arg_vals[new_arg_count] = t.CSizeT(new_av) + new_arg_count += 1 + # 关键字参数也传递给 __new__ + for nki in range(kw_count): + nkw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(nki)) + if nkw is None or nkw.value is None: + continue + nkw_av: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, nkw.value, None, 0, trans) + if nkw_av is not None: + if new_arg_count < 32: + new_arg_vals[new_arg_count] = t.CSizeT(nkw_av) + new_arg_count += 1 + new_ptr: llvmlite.Value | t.CPtr = self.Gen.CallGenCall._call_method_on_ptr( + pool, builder, mod, class_name, + "__new__", tmp, new_arg_vals, new_arg_count, trans, diag_node_ct) + if new_ptr is not None: + storage_ptr = new_ptr + # __new__ 只保证返回"实例存储指针",声明类型通常是 + # `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。 + # 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的 + # obj.method(如 parser.add_argument)get_class_name_by_type + # 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。 + # bitcast 只改类型层视图,运行时零开销(指针位不变)。 + if new_ptr.Ty is not None: + nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) + if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty): + nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty) + if nw_bc is not None: + storage_ptr = nw_bc + + # 构建 __init__ 参数数组:位置参数按顺序 + 关键字参数追加 + init_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if init_arg_vals is not None: + string.memset(init_arg_vals, 0, 8 * 32) + init_arg_count: int = 0 + # 位置参数 + for ai_init in range(can): + arg_node_init: ast.AST | t.CPtr = cargs.get(ai_init) + if arg_node_init is None: + continue + av_init: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg_node_init, None, 0, trans) + if av_init is not None: + if init_arg_count < 32: + init_arg_vals[init_arg_count] = t.CSizeT(av_init) + init_arg_count += 1 + # 关键字参数(追加到末尾,按出现顺序) + for ki_init in range(kw_count): + kw_init: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki_init)) + if kw_init is None or kw_init.value is None: + continue + kw_av_init: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, kw_init.value, None, 0, trans) + if kw_av_init is not None: + if init_arg_count < 32: + init_arg_vals[init_arg_count] = t.CSizeT(kw_av_init) + init_arg_count += 1 + + # 调用 __init__(storage_ptr, *args) + self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, class_name, + "__init__", storage_ptr, init_arg_vals, init_arg_count, trans, diag_node_ct) + + # 返回指针 + return storage_ptr + + # 无 __init__(或非 OOP):逐字段 store 参数值 + # 先处理位置参数(按字段索引,覆盖默认值) + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is None: + continue + arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is None: + continue + fe: GenTypes.FieldEntry | t.CPtr = None + if kw_entry is not None: + fe = self.Gen.StructGen._get_field_entry(kw_entry, ai) + else: + fe = self.Gen.StructGen.get_field_by_index(class_name, ai) + if fe is None: + # 位置参数越界(字段表无对应项):fail-fast,绝不静默跳过 + self.Gen.TypeGenErr.fatal_error( + arg, f"结构体 '{class_name}' 位置参数越界(无对应字段)", "TypeError") + continue + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, fe.Ty, tmp, fe.Index) + if field_ptr is None: + continue + arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, fe.Ty, arg) + llvmlite.build_store(builder, arg_val, field_ptr) + + # 处理关键字参数(按字段名查找) + # SHA1 从 kw_entry 获取(规避跨模块同名 find_struct 找错) + kw_sha1: str = None + if kw_entry is not None: + kw_sha1 = kw_entry.ModuleSha1 + for ki in range(kw_count): + kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki)) + if kw is None or kw.arg is None or kw.value is None: + continue + fe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field_by_class( + class_name, kw.arg, kw_sha1) + if fe is None: + # 关键字字段不存在:fail-fast(AttributeError),绝不静默跳过 + self.Gen.TypeGenErr.fatal_error( + kw, f"结构体 '{class_name}' 无字段 '{kw.arg}'", "AttributeError") + continue + kw_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, kw.value, None, 0, trans) + if kw_val is None: + continue + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, fe.Ty, tmp, fe.Index) + if field_ptr is None: + continue + kw_val = self.Gen.ExprGenBase.coerce_to_type(builder, kw_val, fe.Ty, kw.value) + llvmlite.build_store(builder, kw_val, field_ptr) + + # 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load + return tmp + # ============================================================ + # _translate_t_type_cast - 翻译 t.XXX(value) 类型转换 + # + # 当 func 是 t.XXX 形式且 XXX 是已知类型名(map_t_type 能映射)时, + # 将 value 转换为目标类型: + # - 指针 → 整数: ptrtoint (如 t.CUInt64T(ptr) → i64) + # - 整数 → 指针: inttoptr (如 t.CPtr(int_val) → i8*) + # - 整数 → 整数: trunc/zext (如 t.CInt8T(i32_val) → i8) + # - 指针 → 指针: bitcast (如 t.CPtr(ptr_val) → i8*) + # - 整数 → 浮点: sitofp (如 t.CDouble(i32_val) → double) + # - 浮点 → 整数: fptosi (如 t.CInt(double_val) → i32) + # - 浮点 → 浮点: fpext/fptrunc (如 t.CFloat(double_val) → float) + # ============================================================ + + # ============================================================ + def _translate_t_type_cast(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + val: llvmlite.Value | t.CPtr, + target_ty: llvmlite.LLVMType | t.CPtr, + target_name: str = None, + src_node: ast.AST | t.CPtr = None, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """类型转换:根据参数类型和目标类型选择转换方式 + + 整数 → 整数拓宽时(对齐 TPC _HandleTypeCastLlvm L1723-1737): + 源 i1(bool)→ zext + 目标类型无符号(target_name 命中 CUIntXXT 等)→ zext + 源表达式无符号(t.CUIntXXT(x) 强转 / 无符号注解变量)→ zext + 否则 → sext(有符号整数拓宽保持数值,如 i8 -50 → 0xFFFFFFCE) + """ + if val is None or target_ty is None: + return None + + val_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(val.Ty) + target_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(target_ty) + val_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(val.Ty) + target_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(target_ty) + + # 整数 → 整数: trunc/zext/sext + if val_bits != 0 and target_bits != 0: + if val_bits == target_bits: + return val + elif val_bits < target_bits: + if val_bits == 1: + # i1 是布尔值(来自 icmp/fcmp),无符号语义,必须 zext + return llvmlite.build_zext(builder, val, target_ty) + # 目标类型名已知且为有符号 → 按源符号性 sext/zext(对齐 TPC L1723-1737); + # 目标名未知(int()/联合类型强转等)保持默认 zext(旧行为) + need_sext: int = 0 + if target_name is not None and self.Gen.ExprGenOps._type_name_unsigned(target_name) == 0: + if src_node is None or self.Gen.ExprGenOps._node_type_unsigned(pool, src_node, trans) == 0: + need_sext = 1 + if need_sext != 0: + return llvmlite.build_sext(builder, val, target_ty) + return llvmlite.build_zext(builder, val, target_ty) + else: + return llvmlite.build_trunc(builder, val, target_ty) + + # 整数 → 浮点: sitofp + if val_bits != 0 and target_fbits != 0: + return llvmlite.build_si2fp(builder, val, target_ty) + + # 浮点 → 整数: fptosi + if val_fbits != 0 and target_bits != 0: + return llvmlite.build_fp2si(builder, val, target_ty) + + # 浮点 → 浮点: fpext/fptrunc + if val_fbits != 0 and target_fbits != 0: + if val_fbits == target_fbits: + return val + elif val_fbits < target_fbits: + return llvmlite.build_fpext(builder, val, target_ty) + else: + return llvmlite.build_fptrunc(builder, val, target_ty) + + # 指针 → 整数: ptrtoint + if val_bits == 0 and val_fbits == 0 and target_bits != 0: + return llvmlite.build_ptrtoint(builder, val, target_ty) + + # 整数 → 指针: inttoptr(必须排除浮点 target,浮点 target_bits 也是 0) + if val_bits != 0 and target_bits == 0 and target_fbits == 0: + return llvmlite.build_inttoptr(builder, val, target_ty) + + # 指针 → 指针: bitcast + return llvmlite.build_bitcast(builder, val, target_ty) + # ============================================================ + # 泛型实例化辅助:从 Subscript slice 提取类型实参名 + # ============================================================ + # _get_type_name_from_annotation 已移至 HandlesType.py(支持 BinOp/Attribute) + # HandlesExprCall 通过 HandlesType._get_type_name_from_annotation 调用 + + + # ============================================================ + # 泛型实例化辅助:从 Subscript slice 提取类型实参名 + # ============================================================ + # _get_type_name_from_annotation 已移至 HandlesType.py(支持 BinOp/Attribute) + # HandlesExprCall 通过 HandlesType._get_type_name_from_annotation 调用 + + def _extract_type_args_from_slice(self, pool: memhub.MemBuddy | t.CPtr, + slice_node: ast.AST | t.CPtr) -> list[str] | t.CPtr: + """从 Subscript.slice 提取类型实参名列表 + + list[int] -> ["int"] + dict[str, int] -> ["str", "int"] + list[AST | t.CPtr] -> ["AST|t.CPtr"] + """ + if slice_node is None or pool is None: + return None + # elem_size=8:str 是 i8* 指针(8 字节),若用 4 则双元素时 append 写 8 字节 + # 但步长按 4 计算,第 2 个元素覆盖第 1 个元素高 4 字节 → get 读出垃圾指针崩溃 + result: list[str] | t.CPtr = list[str](pool, 8) + k: int = slice_node.kind() + if k == ast.ASTKind.Tuple: + tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(slice_node) + elts: list[ast.AST | t.CPtr] | t.CPtr = tp.elts + if elts is not None: + n: t.CSizeT = len(elts) + i: t.CSizeT + for i in range(n): + elt: ast.AST | t.CPtr = elts.get(i) + tn: str = self.Gen.TypeGenResolve._get_type_name_from_annotation(pool, elt) + if tn is not None: + result.append(tn) + else: + tn: str = self.Gen.TypeGenResolve._get_type_name_from_annotation(pool, slice_node) + if tn is not None: + result.append(tn) + return result + # ============================================================ + # 泛型类构造调用辅助: list[str](pool, 8) → __new__ + __before_init__ + __init__ + # + # 复用 translate_list_literal 的构造逻辑: + # 1. alloca tmp(特化类临时空间,作为 __new__ 的 self) + # 2. 翻译 cl.args 为参数指针数组 + # 3. call __new__(tmp, *args) → storage_ptr + # 4. call __before_init__(storage_ptr) + # 5. call __init__(storage_ptr, *args) + # 6. return storage_ptr + # + # 必须独立于 translate_call 的普通函数路径:spec_name 是类名不是函数名, + # 走裸名路径会被 _lookup_mod_sha1 的 star import 回退误导,用错误的 SHA1 + # 且缺少 __new__ 方法名后缀,导致链接报 undefined reference。 + # ============================================================ + + # ============================================================ + def _infer_generic_ctor_type_arg(self, pool: memhub.MemBuddy | t.CPtr, + arg_node: ast.AST | t.CPtr, + class_name: str) -> str: + """从构造实参 AST 推断泛型类型实参名;无法推断时 fail-fast(绝不默认 "int") + + 裸名泛型类构造(Box(42) → Box[int])需要从实参推断类型实参。 + 对应 TPC _HandleGenericClassNewLlvm 的推断逻辑(常量/类型转换调用)。 + 注意:本函数仅做 AST 静态推断,不发射 IR(避免重复翻译实参)。 + """ + if pool is None or arg_node is None: + self.Gen.TypeGenErr.fatal_error( + None, + f"无法从实参推断泛型类 '{class_name}' 的类型实参,请显式标注如 {class_name}[类型](...)", + "TypeError") + return "int" + k: int = arg_node.kind() + # 常量: 42→int, 3.14→double, "abc"→str + if k == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg_node) + if cn.const_kind == ast.CONST_FLOAT: + return "double" + if cn.const_kind == ast.CONST_STR: + return "str" + return "int" + # 类型转换调用: int(...)/float(...)/t.CInt(...)/t.CDouble(...) + if k == ast.ASTKind.Call: + cl_f: ast.Call | t.CPtr = (ast.Call | t.CPtr)(arg_node) + if cl_f.func is not None: + if cl_f.func.kind() == ast.ASTKind.Name: + fn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl_f.func) + if fn_nm.id is not None: + # 与下方 Attribute 分支的 strstr 匹配一致:from t import CInt + # 后 `CInt(0)` 的 func 是 Name("CInt"),仅精确匹配 int/float + # 会漏判 → fail-fast 误杀(VectorGenericTest 隐式泛型推断)。 + if string.strcmp(fn_nm.id, "float") == 0 or string.strcmp(fn_nm.id, "double") == 0 \ + or string.strstr(fn_nm.id, "Float") is not None or string.strstr(fn_nm.id, "Double") is not None: + return "double" + if string.strcmp(fn_nm.id, "int") == 0 \ + or string.strstr(fn_nm.id, "Int") is not None or string.strstr(fn_nm.id, "UInt") is not None \ + or string.strstr(fn_nm.id, "Char") is not None or string.strstr(fn_nm.id, "Short") is not None \ + or string.strstr(fn_nm.id, "Long") is not None: + return "int" + elif cl_f.func.kind() == ast.ASTKind.Attribute: + fn_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl_f.func) + if fn_at.attr is not None: + if string.strstr(fn_at.attr, "Float") is not None or string.strstr(fn_at.attr, "Double") is not None: + return "double" + if string.strstr(fn_at.attr, "Int") is not None or string.strstr(fn_at.attr, "UInt") is not None or string.strstr(fn_at.attr, "Char") is not None or string.strstr(fn_at.attr, "Short") is not None or string.strstr(fn_at.attr, "Long") is not None: + return "int" + # 类型转换调用(Call)但函数名无法识别:明确的类型意图却无法解析, + # fail-fast(区别于普通变量 Name——那是非 T 参数,默认 int 被过滤)。 + self.Gen.TypeGenErr.fatal_error( + arg_node, + f"无法从实参推断泛型类 '{class_name}' 的类型实参,请显式标注如 {class_name}[类型](...)", + "TypeError") + return "int" + # 非类型转换节点(普通变量 Name/Attribute 等,如 Vector(pool, 8, ...) + # 的 pool 参数):不是 T 类型提示,返回默认 "int"(调用方"过滤纯 int" + # 逻辑将其排除,只保留 float/str 等区分性提示)。 + return "int" + def _translate_generic_ctor_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + spec_name: str, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """泛型类构造调用: list[str](pool, 8) → __new__ + __before_init__ + __init__""" + if pool is None or builder is None or mod is None or spec_name is None or cl is None: + return None + + # 查找 struct entry 获取类型 + struct_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(spec_name) + if struct_entry is None: + self.Gen.TypeGenErr.fatal_error(cl, "泛型类构造调用: 特化类未注册") + return None + struct_ty: llvmlite.LLVMType | t.CPtr = struct_entry.Ty + if struct_ty is None: + return None + + # 确保结构体定义在当前模块中可用(供 alloca 分配空间) + self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, struct_ty) + + # alloca tmp(self 指针) + tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) + if tmp is None: + return None + + # 翻译 cl.args 为参数指针数组(extra_args[i] = Value 指针) + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + can: t.CSizeT = 0 + if cargs is not None: + can = len(cargs) + + extra_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if extra_args is None: + return None + string.memset(extra_args, 0, 8 * 32) + + ai: t.CSizeT = 0 + while ai < can: + if ai >= 32: + # 定长 8*32 槽:超过 32 个实参继续写会越界污染 pool 相邻块,fail-fast + self.Gen.TypeGenErr.fatal_error( + cl, "泛型构造实参超过 32 个上限", "TypeError") + break + arg_node: ast.AST | t.CPtr = cargs.get(ai) + if arg_node is not None: + arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg_node, None, 0, trans) + if arg_val is not None: + extra_args[ai] = t.CSizeT(arg_val) + ai += 1 + + # 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针 + # __new__ 是可选的,仅当泛型类模板定义了 __new__ 方法时才调用 + # (与 _translate_struct_ctor 保持一致,避免为无 __new__ 的类生成过度声明) + storage_ptr: llvmlite.Value | t.CPtr = tmp + has_new_flag: int = 0 + if struct_entry is not None: + has_new_flag = struct_entry.HasNew + if has_new_flag != 0: + new_ptr: llvmlite.Value | t.CPtr = self.Gen.CallGenCall._call_method_on_ptr( + pool, builder, mod, spec_name, "__new__", tmp, extra_args, can, trans) + if new_ptr is not None: + storage_ptr = new_ptr + # __new__ 只保证返回"实例存储指针",声明类型通常是 + # `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。 + # 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的 + # obj.method(如 parser.add_argument)get_class_name_by_type + # 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。 + # bitcast 只改类型层视图,运行时零开销(指针位不变)。 + if new_ptr.Ty is not None: + nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) + if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty): + nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty) + if nw_bc is not None: + storage_ptr = nw_bc + + # call __before_init__(storage_ptr)(TransPyV 自动生成,零值填充) + self.Gen.CallGenCall._call_method_on_ptr( + pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans) + + # call __init__(storage_ptr, *args) + self.Gen.CallGenCall._call_method_on_ptr( + pool, builder, mod, spec_name, "__init__", storage_ptr, extra_args, can, trans) + return storage_ptr \ No newline at end of file diff --git a/App/lib/core/Gen/CallGenDispatch.vp b/App/lib/core/Gen/CallGenDispatch.vp index 7a41679..25c882f 100644 --- a/App/lib/core/Gen/CallGenDispatch.vp +++ b/App/lib/core/Gen/CallGenDispatch.vp @@ -1,1527 +1,1510 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import sys -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesFunctions as HandlesFunctions -import lib.core.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.CompilerFactory as CompilerFactory - - -import lib.core.Gen.CallGenBase as CallGenBase -import lib.core.Handles.ExprCallCall as ExprCallCall -import lib.core.Handles.ExprCallCtor as ExprCallCtor -import lib.core.Handles.ExprCallDeref as ExprCallDeref -import lib.core.Handles.ExprCallHandle as ExprCallHandle - -# ============================================================ -# CallGenDispatch - CallGenMixin 拆分(阶段 C):translate_call 检测段 -# -# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 每个 helper 返回 Value|CPtr,None = 未命中(translate_call 继续)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class CallGenDispatch(CallGenBase.CallGenBase): - """translate_call 前置检测 helper(继承 Base)""" - - def _tc_h1_super_ctraits(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr, - func_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - hit_box: t.CPtr = None) -> llvmlite.Value | t.CPtr: - """super()/ctraits 编译期检测(未命中返回 None) - - hit_box: 命中标志字节([0]=1 表示被本 helper 拦截处理)。 - super().method() 命中后 _translate_super_call 对 void 方法(如 - __init__)经 build_call 返回 None 属预期(void call 无 SSA 值), - 必须用 hit_box 与"未命中"区分,否则 translate_call 会误判继续 - 主路径 → 把内层 Call(super) 当裸名调用报"super 未定义"。 - """ - # super() 语义(2026-08-10):super().method(args) → 静态调用父类方法 - # 形态: Call(func=Attribute(value=Call(func=Name('super')), attr=method)) - # 必须在 Attribute 分派前拦截——否则 value 的 Call(super) 被 translate_value - # 当作普通函数调用报错,且走普通属性调用会命中自身/虚分派而非父类实现。 - if func_name is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - sup_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if sup_at.value is not None and sup_at.value.kind() == ast.ASTKind.Call: - sup_cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(sup_at.value) - if sup_cl.func is not None and sup_cl.func.kind() == ast.ASTKind.Name: - sup_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sup_cl.func) - if sup_nm.id is not None and string.strcmp(sup_nm.id, "super") == 0: - if hit_box is not None: - hit_box[0] = 1 - return ExprCallHandle._translate_super_call( - pool, builder, mod, cl, func_name, trans) - - # ctraits 宏库编译期谓词:ctraits.isptr(x) 不生成运行时调用, - # 直接按变量存储类型返回编译期常量(CIf 求值失败回退或非 CIf 上下文时兜底, - # 避免生成跨模块调用 ctraits.isptr 触发"模块未注册 SHA1"误导性报错) - if func_name is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - ct_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if ct_at.value is not None and ct_at.value.kind() == ast.ASTKind.Name: - ct_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ct_at.value) - if ct_nm.id is not None and string.strcmp(ct_nm.id, "ctraits") == 0 \ - and string.strcmp(func_name, "isptr") == 0: - ct_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if ct_args is not None and len(ct_args) >= 1: - ct_arg0: ast.AST | t.CPtr = ct_args.get(0) - if ct_arg0 is not None and ct_arg0.kind() == ast.ASTKind.Name: - ct_nm0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ct_arg0) - if ct_nm0.id is not None and trans is not None: - ct_r: int = HandlesType.eval_ctraits_isptr(trans.SymTab, ct_nm0.id) - if ct_r > 0: - return llvmlite.const_int32(pool, 1) - return llvmlite.const_int32(pool, 0) - return None - - def _tc_h2_c_special(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr, - func_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - hit_box: t.CPtr = None) -> llvmlite.Value | t.CPtr: - """c.Deref/Asm/LLVMIR 等特殊调用(未命中返回 None) - - hit_box: 命中标记(t.CPtr,[0]=1 表示已识别为 c.* 特殊调用)。 - 仅对 c.Asm/c.LLVMIR 等返回 None(void,无返回值)的调用置位—— - translate_c_asm/translate_c_llvmir 成功处理 void 时返回 None, - 若不加 hit_box 会被 translate_call 误判为"未命中"继续走外部函数路径。 - """ - # 检测 c.Deref / c.DerefAs / c.Addr 等特殊调用(内联 IR,不生成 call) - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - at_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if at_node.value is not None and at_node.value.kind() == ast.ASTKind.Name: - mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_node.value) - if mod_nm.id is not None and string.strcmp(mod_nm.id, "c") == 0: - if string.strcmp(func_name, "Deref") == 0: - return ExprCallDeref.translate_c_deref(pool, builder, mod, cl, trans) - elif string.strcmp(func_name, "DerefAs") == 0: - return ExprCallDeref.translate_c_derefas(pool, builder, mod, cl, trans) - elif string.strcmp(func_name, "Addr") == 0: - return ExprCallDeref.translate_c_addr(pool, builder, mod, cl, trans) - elif string.strcmp(func_name, "Set") == 0: - # c.Set(a, b) = a = b(赋值语义,非指针解引用)。 - # 若当普通函数调用会生成 @Set 引用导致链接失败(undefined reference to `Set')。 - return ExprCallDeref.translate_c_set(pool, builder, mod, cl, trans) - elif string.strcmp(func_name, "Load") == 0: - return ExprCallDeref.translate_c_load(pool, builder, mod, cl, trans) - elif string.strcmp(func_name, "Asm") == 0: - # c.Asm 无输出(void)时 translate_c_asm 返回 None: - # 置命中标记,避免 translate_call 误判未命中继续走外部函数 - if hit_box is not None: - hit_box[0] = 1 - return ExprCallDeref.translate_c_asm(pool, builder, mod, cl, trans) - elif string.strcmp(func_name, "LLVMIR") == 0: - # c.LLVMIR 总是无返回值(返回 None):置命中标记 - if hit_box is not None: - hit_box[0] = 1 - return ExprCallDeref.translate_c_llvmir(pool, builder, mod, cl, trans) - elif string.strcmp(func_name, "LInp") == 0 or string.strcmp(func_name, "LOut") == 0: - # c.LInp/c.LOut 独立调用时返回 0(仅在 c.LLVMIR 的 f-string 内有意义) - return llvmlite.ConstInt(pool, llvmlite.Int32(pool), 0, "0") - elif string.strcmp(func_name, "CIf") == 0: - # 运行时 c.CIf(expr)(编译期求值失败回退):expr 与 0 比较得到 i1 - # 对齐 TPC HandlesExprCall.py L2434-2444 - cif_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cif_args is not None and len(cif_args) >= 1: - cif_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cif_args.get(0), funcs_ptr, func_count, trans) - if cif_arg_val is not None: - cif_bits: int = HandlesExpr.get_llvm_type_bits(cif_arg_val.Ty) - if cif_bits == 1: - return cif_arg_val - if HandlesExpr.is_ptr_type(cif_arg_val.Ty) != 0: - cif_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull( - pool, cif_arg_val.Ty, "null") - return llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, cif_arg_val, cif_null) - cif_zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - return llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, cif_arg_val, cif_zero) - return llvmlite.ConstInt(pool, llvmlite.Int1(pool), 0, "0") - elif string.strcmp(func_name, "CIfdef") == 0 or string.strcmp(func_name, "CIfndef") == 0: - # 运行时 c.CIfdef/c.CIfndef(编译期求值失败回退):恒真 - # 对齐 TPC HandlesExprCall.py L2445-2446 - return llvmlite.ConstInt(pool, llvmlite.Int1(pool), 1, "1") - return None - - def _tc_h3_stdarg_cast(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr, - func_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT) -> llvmlite.Value | t.CPtr: - """stdarg 糖 + str/int/bool 内置强转(未命中返回 None)""" - # stdarg 糖函数处理: va_arg / arg / va_start / va_end - # 这些函数在 stdarg.vp 中声明为 pass 体,由编译器在翻译期处理: - # va_arg(ap, type) → %N = va_arg , (LLVM 指令) - # va_arg(ap) → 同上,类型从赋值上下文推断(默认 i32) - # arg(type) → 同上,使用当前函数的隐式 va_list (trans._va_list_ptr) - # va_start(ap, _) → call void @llvm.va_start(i8* %ap) (LLVM intrinsic) - # va_end(ap) → call void @llvm.va_end(i8* %ap) (LLVM intrinsic) - # ============================================================ - if func_name is not None and trans is not None: - if string.strcmp(func_name, "va_arg") == 0: - return ExprCallCall._translate_va_arg_sugar(pool, builder, mod, cl, cargs, can, - funcs_ptr, func_count, trans) - elif string.strcmp(func_name, "arg") == 0: - return ExprCallCall._translate_arg_sugar(pool, builder, mod, cl, cargs, can, - funcs_ptr, func_count, trans) - elif string.strcmp(func_name, "va_start") == 0: - return ExprCallCall._translate_va_start_sugar(pool, builder, mod, cargs, can, - funcs_ptr, func_count, trans) - elif string.strcmp(func_name, "va_end") == 0: - return ExprCallCall._translate_va_end_sugar(pool, builder, mod, cargs, can, - funcs_ptr, func_count, trans) - - # 内置强转函数: str(x)/bytes(x) → i8*, int(x) → i32 - # 等价于 (str)(x) / (t.CInt32T)(x) - # 单参数:str(val) → bitcast val to i8* - # int(val) → trunc/sext val to i32 - # 泛型类型参数: 类特化/泛型函数上下文中的 T(x) 先解析 T 为具体类型名 - # (如 "int")再按内建强转处理(Box[int].__init__ 的 self.value = T(v)、 - # combine[T1,T2] 的 T1(b) 依赖此路径) - if func_name is not None and can == 1: - cast_fn_name: str = HandlesType.resolve_generic_type_name(func_name) - if string.strcmp(cast_fn_name, "str") == 0 or string.strcmp(cast_fn_name, "bytes") == 0: - # str(x) / bytes(x) → i8* (bitcast) - cast_arg: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) - if cast_arg is not None: - i8_ptr_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - return ExprCallCtor._translate_t_type_cast(pool, builder, cast_arg, i8_ptr_ty_builtin) - return None - elif string.strcmp(cast_fn_name, "int") == 0: - # int(x) → i32 - cast_arg_int: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) - if cast_arg_int is not None: - i32_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - return ExprCallCtor._translate_t_type_cast(pool, builder, cast_arg_int, i32_ty_builtin) - return None - elif string.strcmp(cast_fn_name, "bool") == 0: - # bool(x) → i1(严格 != 0 归一化) - # 整数: icmp ne x, 0 → i1 - # 浮点: fcmp one x, 0.0 → i1 - # 指针: icmp ne x, null → i1 - cast_arg_bool: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) - if cast_arg_bool is not None: - arg_bits: int = HandlesExpr.get_llvm_type_bits(cast_arg_bool.Ty) - arg_fbits: int = HandlesExpr.get_llvm_float_bits(cast_arg_bool.Ty) - # 整数: icmp ne x, 0 - if arg_bits != 0: - zero_int: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, arg_bits, 0) - if zero_int is not None: - return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cast_arg_bool, zero_int) - return None - # 浮点: fcmp one x, 0.0 - if arg_fbits != 0: - zero_ty: llvmlite.LLVMType | t.CPtr = cast_arg_bool.Ty - zero_flt: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, zero_ty, 0.0) - if zero_flt is not None: - return llvmlite.build_fcmp(builder, llvmlite.FCMP_ONE, cast_arg_bool, zero_flt) - return None - # 指针: icmp ne x, null - ptr_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cast_arg_bool.Ty, "null") - if ptr_null is not None: - return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cast_arg_bool, ptr_null) - return None - return None - return None - - def _tc_h4_type_casts(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr, - func_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT) -> llvmlite.Value | t.CPtr: - """t.XXX / typedef 类型转换(未命中返回 None)""" - # 检测 t.XXX 类型转换: t.CUInt64T(ptr), t.CPtr(val), t.CInt(val) 等 - # 当 func 是 t.XXX 形式且 XXX 是已知类型名时,当作类型转换处理(而非函数调用) - # 支持: - # 单参数: t.CInt(val) → 目标类型 = map_t_type(func_name) - # 双参数: t.CInt(val, t.CPtr) → 目标类型 = Ptr(map_t_type(func_name)) - # t 是内部库,一旦确认为类型转换,绝不跌落到跨模块调用 FATAL 路径 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - tc_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if tc_at.value is not None and tc_at.value.kind() == ast.ASTKind.Name: - tc_mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_at.value) - if tc_mod_nm.id is not None and string.strcmp(tc_mod_nm.id, "t") == 0: - target_ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, func_name) - if target_ty is not None: - tc_effective_can: t.CSizeT = can - # 双参数形式: t.CInt(val, t.CPtr) → Ptr(target_ty) - # 注意: void* 在 LLVM 中非法,CVoid* 应表示为 i8* - if can == 2: - tc_arg2_node: ast.AST | t.CPtr = cargs.get(1) - tc_arg2_is_cptr: int = 0 - if tc_arg2_node is not None: - # 形式 1: t.CPtr(Attribute 形式) - if tc_arg2_node.kind() == ast.ASTKind.Attribute: - tc_arg2_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(tc_arg2_node) - if tc_arg2_at.attr is not None and string.strcmp(tc_arg2_at.attr, "CPtr") == 0: - if tc_arg2_at.value is not None and tc_arg2_at.value.kind() == ast.ASTKind.Name: - tc_arg2_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_arg2_at.value) - if tc_arg2_nm.id is not None and string.strcmp(tc_arg2_nm.id, "t") == 0: - tc_arg2_is_cptr = 1 - # 形式 2: 裸名 CPtr(from t import CPtr 后直接使用,如 t.CVoid(x, CPtr)) - elif tc_arg2_node.kind() == ast.ASTKind.Name: - tc_arg2_bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_arg2_node) - if tc_arg2_bn.id is not None and string.strcmp(tc_arg2_bn.id, "CPtr") == 0: - tc_arg2_is_cptr = 1 - if tc_arg2_is_cptr != 0: - # CVoid* → i8*(LLVM 中 void* 表示为 i8*) - match target_ty: - case llvmlite.LLVMType.Void(): - target_ty = llvmlite.Int8(pool) - case _: - pass - target_ty = llvmlite.Ptr(pool, target_ty) - tc_effective_can = 1 - if tc_effective_can == 1: - tc_arg_node: ast.AST | t.CPtr = cargs.get(0) - if tc_arg_node is not None: - tc_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, tc_arg_node, None, 0, trans) - if tc_arg_val is not None: - return ExprCallCtor._translate_t_type_cast( - pool, builder, tc_arg_val, target_ty, - func_name, tc_arg_node, trans) - # t.XXX 类型转换已确认但不满足参数条件:返回 None,不跌落到跨模块 FATAL - return None - - # 模块限定 typedef 转换: posix.mode_t(mode), w32.win32base.HANDLE(v) 等 - # func = Attribute(value=Name(模块), attr=typedef名),此前被误当跨模块函数调用 - # → "跨模块函数 'sha1.mode_t' 返回类型无法精确获取"(SysLibTest os/_posix.vp - # L130 posix.mode_t(mode) 根因)。typedef 名做类型转换(与裸名 BYTEPTR(x) - # 对齐);非 typedef 名继续走模块函数调用。 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - mt_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if mt_at.value is not None and mt_at.value.kind() == ast.ASTKind.Name: - mt_mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(mt_at.value) - if mt_mod_nm.id is not None and string.strcmp(mt_mod_nm.id, "t") != 0 \ - and string.strcmp(mt_mod_nm.id, "c") != 0: - mod_td_ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type( - pool, func_name) - if mod_td_ty is None: - mod_td_str: str = HandlesType.lookup_ctypedef(func_name) - if mod_td_str is not None and HandlesType.is_ctypedef_found() != 0: - mod_td_ast: ast.AST | t.CPtr = HandlesType._parse_type_string( - pool, mod_td_str, 0) - if mod_td_ast is not None: - mod_imp_td: str = None - mod_fi_td: str = None - if trans is not None: - mod_imp_td = trans._imported_modules - mod_fi_td = trans._from_imports - mod_td_ty = HandlesType.resolve_annotation_type( - pool, mod_td_ast, mod_imp_td, mod_fi_td, trans) - if mod_td_ty is not None and can == 1: - mt_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) - if mt_arg_val is not None: - return ExprCallCtor._translate_t_type_cast( - pool, builder, mt_arg_val, mod_td_ty, - func_name, cargs.get(0), trans) - - # 裸名 typedef 调用: BYTEPTR(ptr1), HANDLE(val), CHARPTR(str) 等 - # 用户通过 `from stdint import *` 导入 typedef 后,可直接用裸名做类型转换 - # map_t_type 包含所有内置 typedef 名称(BYTEPTR/HANDLE/LPCSTR/size_t 等) - # 泛型类型参数转换: 泛型上下文(类特化/泛型函数)中 T(x) → 先解析 T 为具体 - # 类型名(如 "int")再走 map_t_type(Box[int].__init__ 的 self.value = T(v)、 - # combine[T1,T2] 的 T1(b) 依赖此路径) - if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: - bare_fn_name: str = HandlesType.resolve_generic_type_name(func_name) - bare_ty: llvmlite.LLVMType | t.CPtr = None - # 泛型上下文解析出的内建名(如 T→"double"/"float"):map_t_type 只认 t.CDouble, - # 且 float 必须映射 t.CFloat(f32)而非 f64(与注解语义一致) - if string.strcmp(bare_fn_name, "double") == 0: - bare_ty = llvmlite.Double(pool) - elif string.strcmp(bare_fn_name, "float") == 0: - bare_ty = llvmlite.Float(pool) - else: - bare_ty = HandlesType.map_t_type(pool, bare_fn_name) - # 泛型上下文替换出的类型名(如 T→"t.CInt")map_t_type 不识别(只认无前缀名), - # 回退用 resolve_annotation_type 解析(支持 t.CXxx / 结构体类名 / 别名等)。 - # GenericTest4 Box[t.CInt].__init__ 的 self.value = T(v) 依赖此路径。 - if bare_ty is None and string.strcmp(bare_fn_name, func_name) != 0: - gp_ast: ast.AST | t.CPtr = HandlesType._parse_type_string(pool, bare_fn_name, 0) - if gp_ast is not None: - imp_gp: str = None - fi_gp: str = None - if trans is not None: - imp_gp = trans._imported_modules - fi_gp = trans._from_imports - bare_ty = HandlesType.resolve_annotation_type( - pool, gp_ast, imp_gp, fi_gp, trans) - # 泛型类型参数双参数形式: T(val, t.CPtr) → Ptr(T) - # (与 t.CInt(val, t.CPtr) → Ptr(i32) 对齐;vector.vp get() 的 - # typed_ptr = T(offset, t.CPtr) 依赖此路径,否则双参数不进 - # can==1 单参数分支 → 跌落到"裸名调用未定义"误报) - if bare_ty is not None and can == 2: - bare_arg2_node: ast.AST | t.CPtr = cargs.get(1) - bare_arg2_is_cptr: int = 0 - if bare_arg2_node is not None: - # 形式 1: t.CPtr(Attribute 形式) - if bare_arg2_node.kind() == ast.ASTKind.Attribute: - bare_arg2_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(bare_arg2_node) - if bare_arg2_at.attr is not None and string.strcmp(bare_arg2_at.attr, "CPtr") == 0: - if bare_arg2_at.value is not None and bare_arg2_at.value.kind() == ast.ASTKind.Name: - bare_arg2_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bare_arg2_at.value) - if bare_arg2_nm.id is not None and string.strcmp(bare_arg2_nm.id, "t") == 0: - bare_arg2_is_cptr = 1 - # 形式 2: 裸名 CPtr(from t import CPtr 后直接使用) - elif bare_arg2_node.kind() == ast.ASTKind.Name: - bare_arg2_bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bare_arg2_node) - if bare_arg2_bn.id is not None and string.strcmp(bare_arg2_bn.id, "CPtr") == 0: - bare_arg2_is_cptr = 1 - if bare_arg2_is_cptr != 0: - # CVoid* → i8*(LLVM 中 void* 表示为 i8*) - match bare_ty: - case llvmlite.LLVMType.Void(): - bare_ty = llvmlite.Int8(pool) - case _: - pass - bare_ty = llvmlite.Ptr(pool, bare_ty) - bare_arg_node: ast.AST | t.CPtr = cargs.get(0) - if bare_arg_node is not None: - bare_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, bare_arg_node, None, 0, trans) - if bare_arg_val is not None: - return ExprCallCtor._translate_t_type_cast( - pool, builder, bare_arg_val, bare_ty, - bare_fn_name, bare_arg_node, trans) - if bare_ty is not None and can == 1: - bare_arg_node: ast.AST | t.CPtr = cargs.get(0) - if bare_arg_node is not None: - bare_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, bare_arg_node, None, 0, trans) - if bare_arg_val is not None: - return ExprCallCtor._translate_t_type_cast( - pool, builder, bare_arg_val, bare_ty, - bare_fn_name, bare_arg_node, trans) - - return None - - def _tc_h5_sizeof_len_isinst(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr, - func_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT) -> llvmlite.Value | t.CPtr: - """__sizeof__/len/isinstance 内置(未命中返回 None)""" - # 检测 ClassName.__sizeof__() — 返回结构体大小常量(i64) - # __sizeof__ 是内置方法,不走跨模块调用路径 - # 支持: Argument.__sizeof__() 和 w32.win32file.WIN32_FIND_DATAA.__sizeof__() - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - sz_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if sz_at.attr is not None and string.strcmp(sz_at.attr, "__sizeof__") == 0: - if sz_at.value is not None and can == 0: - sz_cls_name: str = None - sz_vk: int = sz_at.value.kind() - if sz_vk == ast.ASTKind.Name: - sz_cls_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sz_at.value) - sz_cls_name = sz_cls_nm2.id - elif sz_vk == ast.ASTKind.Attribute: - sz_inner_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sz_at.value) - sz_cls_name = sz_inner_at.attr - # 最终解析出的结构体类型:类型名命中 → 泛型特化(Stack[T])→ 实例接收者类型(self/obj) - sz_resolved_ty: llvmlite.LLVMType | t.CPtr = None - sz_resolved_name: str = sz_cls_name - if sz_cls_name is not None: - # 泛型类型参数 T 替换: T.__sizeof__() → int.__sizeof__() - sz_cls_name = HandlesType.resolve_generic_type_name(sz_cls_name) - sz_resolved_name = sz_cls_name - # 去除模块前缀: Viper 解析器将 t.CInt 解析为 Name(id="t.CInt") - # 而非 Attribute(value=Name("t"), attr="CInt"),需要手动提取最后的类名分量 - # "t.CInt" → "CInt", "w32.win32file.WIN32_FIND_DATAA" → "WIN32_FIND_DATAA" - dot_pos: str = string.strrchr(sz_cls_name, '.') - if dot_pos is not None: - sz_cls_name = dot_pos + 1 - # 联合类型(如 AST|t.CPtr)按指针大小处理(8 字节) - # 联合类型在 TPV 中表示指针,可以指向多种类型 - # 对应 TPC 中对 BinOp/BitOr 联合类型的特殊处理 - if string.strstr(sz_cls_name, "|") is not None: - return llvmlite.const_int64(pool, 8) - # 内置类型 sizeof(int=4, str/bytes=8 指针, double=8 等) - sz_builtin: int = -1 - if string.strcmp(sz_cls_name, "int") == 0: - sz_builtin = 4 - elif string.strcmp(sz_cls_name, "str") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "bytes") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "CInt") == 0: - sz_builtin = 4 - elif string.strcmp(sz_cls_name, "CInt8T") == 0: - sz_builtin = 1 - elif string.strcmp(sz_cls_name, "CInt16T") == 0: - sz_builtin = 2 - elif string.strcmp(sz_cls_name, "CInt32T") == 0: - sz_builtin = 4 - elif string.strcmp(sz_cls_name, "CInt64T") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "CChar") == 0: - sz_builtin = 1 - elif string.strcmp(sz_cls_name, "CDouble") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "CFloat") == 0: - sz_builtin = 4 - elif string.strcmp(sz_cls_name, "CPtr") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "CSizeT") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "CBool") == 0: - sz_builtin = 1 - elif string.strcmp(sz_cls_name, "bool") == 0: - sz_builtin = 1 - # 泛型 T 解析出的裸内建名(resolve_generic_type_name 返回 - # _infer_generic_ctor_type_arg 的输出,如 T→"double"/"float"): - # 缺省会让 sz_builtin=-1 → 落到"回退 2"把 Name(T) 当值翻译 → - # NameError(VectorGenericTest Vector[double].__init__ 回归根因) - elif string.strcmp(sz_cls_name, "double") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "float") == 0: - sz_builtin = 4 - elif string.strcmp(sz_cls_name, "char") == 0: - sz_builtin = 1 - if sz_builtin >= 0: - # 注意: 必须用 const_int64 而非 ConstInt(...,"0") - # ConstInt 的 name 参数是 IR 文本表示,ValuePrint 输出时使用 Name 而非 IntVal - # 硬编码 "0" 会导致 IR 输出 i64 0 而非实际值 - return llvmlite.const_int64(pool, sz_builtin) - sz_resolved_ty = HandlesStruct.get_struct_type(sz_cls_name) - # 回退 1: 泛型类引用接收者 Stack[T].__sizeof__() — Subscript → 特化后计算大小 - # (GenericTest2 Stack.type_size 依赖此路径) - if sz_resolved_ty is None and trans is not None and sz_vk == ast.ASTKind.Subscript: - sub_sz: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sz_at.value) - if sub_sz.value is not None and sub_sz.value.kind() == ast.ASTKind.Name: - gen_nm_sz: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_sz.value) - if gen_nm_sz.id is not None: - gen_args_sz: list[str] | t.CPtr = ExprCallCtor._extract_type_args_from_slice(pool, sub_sz.slice) - if gen_args_sz is not None and len(gen_args_sz) > 0: - gargs_resolved: list[str] | t.CPtr = list[str](pool, 8) - if gargs_resolved is not None: - gai_sz: t.CSizeT = len(gen_args_sz) - gai2_sz: t.CSizeT = 0 - for gai2_sz in range(gai_sz): - gres_sz: str = HandlesType.resolve_generic_type_name( - gen_args_sz.get(gai2_sz)) - gargs_resolved.append(gres_sz) - spec_sz: str = HandlesClassDef._specialize_generic_class( - trans, gen_nm_sz.id, gargs_resolved) - if spec_sz is not None: - sz_resolved_name = spec_sz - sz_resolved_ty = HandlesStruct.get_struct_type(spec_sz) - # 回退 2: 实例接收者 self.__sizeof__() / obj.__sizeof__() — 用接收者值的实际类型 - # (GenericTest2 Stack.size_of 依赖此路径;self 在方法内是 Ptr(Stack[int])) - # 数组变量接收者 bl_count.__sizeof__()(t.CArray[T, N] 变量)→ alloca - # 指针 Ptr([N x T]),算 N*elem_size(TPC _HandleSizeofLlvm 数组分支; - # zhuff.vp memset(bl_count, 0, bl_count.__sizeof__()) 依赖) - if sz_resolved_ty is None: - inst_sz_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, sz_at.value, None, 0, trans) - if inst_sz_val is not None and inst_sz_val.Ty is not None: - match inst_sz_val.Ty: - case llvmlite.LLVMType.Ptr(inst_inner_sz): - match inst_inner_sz: - case llvmlite.LLVMType.Struct(_, _, _): - sz_resolved_ty = inst_inner_sz - case llvmlite.LLVMType.Array(_, _): - sz_resolved_ty = inst_inner_sz - case _: - pass - case llvmlite.LLVMType.Struct(_, _, _): - sz_resolved_ty = inst_sz_val.Ty - case llvmlite.LLVMType.Array(_, _): - # 全局数组变量(模块级 t.CArray[T,N])translate_value - # 返回数组值 [N x T](非指针);局部数组返回 alloca - # 指针 Ptr([N x T]) 走上方 Ptr(Array) 分支。 - # pyzlib_error_msg.__sizeof__() 依赖(全局字符缓冲)。 - sz_resolved_ty = inst_sz_val.Ty - case _: - pass - if sz_resolved_ty is not None: - sz_val: int = HandlesClassDef._get_type_size(sz_resolved_ty) - if sz_val > 0: - return llvmlite.const_int64(pool, sz_val) - # 类型已注册但大小为 0(opaque struct 或字段链表未填充):Python 风格报错终止 - HandlesType.fatal_error( - sz_at, f"类型 '{sz_resolved_name}' 已注册但大小为 0(字段链表未填充),无法计算大小", - "TypeError") - # 类型未注册:Python 风格报错终止,不静默返回 0(会导致 malloc(0)/alloc(0) 堆溢出) - if sz_resolved_name is None: - sz_resolved_name = "(unknown)" - HandlesType.fatal_error( - sz_at, f"类型 '{sz_resolved_name}' 未在结构体表中注册,无法计算大小", - "TypeError") - - # 检测 len(obj) — 返回 list 对象的 __count__ 字段(偏移 8,i64) - # __len__ 是 list[T] 的内置方法,list 是泛型类不注册 struct - # 注意: 必须用 translate_value 而非 translate_name_value,因为 len_at.value - # 可能是 Attribute 节点(如 md_ags.args),translate_name_value 只处理 Name 节点, - # 对 Attribute 会错误返回 i32 0,导致 GEP base 不是指针(base of getelementptr must be a pointer) - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - len_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if len_at.attr is not None and string.strcmp(len_at.attr, "__len__") == 0: - if len_at.value is not None and can == 0: - obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, len_at.value, funcs_ptr, func_count, trans) - if obj_val is not None and obj_val.Ty is not None: - # 防御性类型检查: obj_val 必须是指针类型才能做 GEP - # 如果 translate_value 返回 i32 (如 CDefine 常量被误解析、 - # 模块属性前向引用回退为 i32),GEP base 会是 i32 而非指针, - # 导致 llc 报错 "base of getelementptr must be a pointer" - if HandlesExpr.is_ptr_type(obj_val.Ty) == 0: - # 类型推断失败(非指针/结构体):fail-fast,绝不返回 0 掩盖错误 - HandlesType.fatal_error( - len_at.value, "len() 参数类型推断失败(非指针/结构体)", "TypeError") - i64_ty_len: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - # 注意: 必须用 const_int64 而非 ConstInt(...,"0") - # ConstInt 的 name 参数 "0" 会被当作 IR 文本值输出 i64 0 - # 导致 GEP 索引为 0(访问 __data__)而非 1(访问 __count__) - idx_one: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) - count_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i64_ty_len, obj_val, idx_one) - if count_ptr is not None: - return llvmlite.build_load(builder, i64_ty_len, count_ptr) - - # 检测 len() 内置函数调用 — 结构体对象走 __len__ 方法,字符串走 strlen - # len(s) 对 str 类型调用 strlen,返回 i64 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: - if func_name is not None and string.strcmp(func_name, "len") == 0: - if can == 1: - len_arg_node: ast.AST | t.CPtr = cargs.get(0) - if len_arg_node is not None: - len_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, len_arg_node, None, 0, trans) - if len_val is not None: - # len(数组):t.CArray[T, N] → 常量 N(对齐 TPC - # _HandleLenLlvm 的 ArrayType.count 分支)。数组变量 - # translate_value 可能返回 Ptr([N x T])(alloca 指针) - # 或 [N x T] 值,两种都识别;否则会误走 strlen 把 - # 数组首元素当字符串读 → 垃圾长度。 - len_is_arr: int = 0 - len_arr_n: int = 0 - if len_val.Ty is not None: - if HandlesExpr.is_ptr_type(len_val.Ty) != 0: - len_ap: llvmlite.LLVMType | t.CPtr = len_val.Ty.Pointee - if len_ap is not None: - match len_ap: - case llvmlite.LLVMType.Array(_, len_arr_cnt): - len_is_arr = 1 - len_arr_n = len_arr_cnt - case _: - pass - else: - match len_val.Ty: - case llvmlite.LLVMType.Array(_, len_arr_cnt): - len_is_arr = 1 - len_arr_n = len_arr_cnt - case _: - pass - if len_is_arr != 0: - return llvmlite.const_int64(pool, len_arr_n) - # len(对象):有 __len__ 就调用,没有就编译期报错 - # (用户要求 2026-08-15,不再静默 strlen 读对象首字段): - # - list 泛型内置容器:__len__ 由 list 内置分支内联 - # (读 __count__,偏移 1),不生成方法函数 - # (_is_list_builtin_method,通用判断非特判) - # - 普通类:调用 {Class}.__len__ 函数 - # - 都没有:fatal_error - # str(Ptr(Int8))保持 strlen(内建语义)。 - len_struct_ty: llvmlite.LLVMType | t.CPtr = \ - HandlesStruct.get_struct_type_from_value(len_val) - if len_struct_ty is not None: - len_cls_nm: str = HandlesStruct.get_class_name_by_type( - pool, len_struct_ty) - if len_cls_nm is None: - HandlesType.fatal_error( - len_arg_node, "len() 参数类型推断失败(结构体类名未知)", - "TypeError") - # list 内置 __len__:读 __count__(GEP 偏移 1,i64) - if ExprCallHandle._is_list_builtin_method(len_cls_nm, "__len__") != 0: - i64_ty_lb: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - idx_one_lb: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) - cnt_ptr_lb: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i64_ty_lb, len_val, idx_one_lb) - if cnt_ptr_lb is not None: - return llvmlite.build_load(builder, i64_ty_lb, cnt_ptr_lb) - len_lookup: str = pool.alloc(128) - if len_lookup is not None: - viperlib.snprintf(len_lookup, 128, "%s.__len__", len_cls_nm) - len_fn2: llvmlite.Function | t.CPtr = self.find_func_in_module( - mod, len_lookup) - if len_fn2 is not None: - len_ret_ty2: llvmlite.LLVMType | t.CPtr = \ - llvmlite.function_get_ret_ty(len_fn2) - len_fn_name2: str = \ - llvmlite.function_get_name(len_fn2) - if len_ret_ty2 is not None and len_fn_name2 is not None: - # self 参数类型对齐(按方法首个形参 bitcast) - len_self_arg2: llvmlite.Value | t.CPtr = len_val - len_first_param2: llvmlite.Param | t.CPtr = \ - llvmlite.function_get_param_head(len_fn2) - if len_first_param2 is not None: - len_self_ty2: llvmlite.LLVMType | t.CPtr = \ - llvmlite.param_get_ty(len_first_param2) - if len_self_ty2 is not None and len_val.Ty is not None: - len_self_arg2 = llvmlite.build_bitcast( - builder, len_val, len_self_ty2) - len_self_arg2.Next = None - return llvmlite.build_call( - builder, len_fn_name2, len_self_arg2, - 1, len_ret_ty2, 0) - # len_fn2 未命中(跨模块方法):如 ndarray[t.CDouble].__len__ - # 定义在 numpy——泛型特化方法无 stub declare,find_func_in_module - # 后缀匹配查不到。用结构体所属模块 sha1 构造 - # {sha1}.{cls}.__len__ 精确调用名(对齐 _translate_method_call - # 跨模块调用名构造),返回类型从 text.ll/vpi 精确解析, - # _ensure_method_declare 建 declare 后调用。 - len_cls_sha1_x: str = HandlesStruct.get_struct_sha1(len_cls_nm) - if len_cls_sha1_x is not None: - # 缓冲区需容纳 "{sha1}.{cls}.__len__": - # 2 个点 + "__len__"(7) + NUL = 10;+8 会截断 - # 末两位 → 符号变 ".__len" 链接 undefined - # (NumpyTest test_len 链接错误根因) - len_ml_x: t.CSizeT = string.strlen(len_cls_sha1_x) \ - + string.strlen(len_cls_nm) + 10 - len_mangled_x: str = pool.alloc(len_ml_x) - if len_mangled_x is not None: - viperlib.snprintf(len_mangled_x, len_ml_x, - "%s.%s.__len__", len_cls_sha1_x, len_cls_nm) - len_ret_x: llvmlite.LLVMType | t.CPtr = \ - self._LookupMethodRetTyFromTextLL( - pool, len_cls_sha1_x, len_cls_nm, "__len__") - if len_ret_x is None: - len_ret_x = self._lookup_method_ret_ty_via_vpi( - pool, len_cls_sha1_x, len_cls_nm, "__len__") - if len_ret_x is not None: - # self 参数按对象实际类型 Ptr(len_struct_ty)(与定义侧 - # 同名类型链接匹配);len_val 已是 load 后的对象指针。 - # Value 链直接作 param_head(同跨模块调用模式)。 - len_self_x: llvmlite.Value | t.CPtr = len_val - len_self_x.Next = None - self._ensure_method_declare( - pool, mod, len_mangled_x, len_ret_x, - len_self_x, 1) - return llvmlite.build_call( - builder, len_mangled_x, len_self_x, - 1, len_ret_x, 0) - # fail-fast:类没有 __len__(用户要求编译期报错) - HandlesType.fatal_error( - len_arg_node, - f"len() 参数类型 '{len_cls_nm}' 没有 __len__ 方法", - "TypeError") - # 非结构体:str(Ptr(Int8))走 strlen;其它类型 fail-fast - len_arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(len_val) - len_is_str: int = 0 - if len_arg_ty is not None and HandlesExpr.is_ptr_type(len_arg_ty) != 0: - match len_arg_ty: - case llvmlite.LLVMType.Ptr(len_pt_ty): - if len_pt_ty is not None: - match len_pt_ty: - case llvmlite.LLVMType.Int(len_pt_bits): - if len_pt_bits == 8: - len_is_str = 1 - case _: - pass - case _: - pass - if len_is_str != 0: - # 确保 strlen 在模块中有声明 - strlen_fn: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, "strlen") - if strlen_fn is None: - i64_ty_ln: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i8_ptr_ty_ln: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - strlen_fn = llvmlite.create_declare(pool, mod, "strlen", i64_ty_ln) - if strlen_fn is not None: - llvmlite.add_param(pool, strlen_fn, i8_ptr_ty_ln, "s") - # 参数类型转换为 i8* - i8_ptr_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - len_coerced: llvmlite.Value | t.CPtr = len_val - if HandlesExpr.is_ptr_type(len_arg_ty) != 0: - len_coerced = llvmlite.build_bitcast(builder, len_val, i8_ptr_ty_ln2) - # 构建单参数链表并调用 strlen - len_coerced.Next = None - i64_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - return llvmlite.build_call(builder, "strlen", len_coerced, 1, i64_ty_ln2, 0) - # fail-fast:非字符串/数组/对象,无法求长度 - HandlesType.fatal_error( - len_arg_node, "len() 参数类型不支持(非字符串/数组/对象)", - "TypeError") - - # 检测 isinstance() 内置函数调用 — 运行时 vtable 子类集合比较 - # isinstance(obj, Cls):obj 头部 vtable 指针 ∈ {Cls 及全部子类 vtable}; - # NoVTable 目标类回退编译时静态判断(详见 _translate_isinstance)。 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: - if func_name is not None and string.strcmp(func_name, "isinstance") == 0: - if can >= 2: - is_res: llvmlite.Value | t.CPtr = ExprCallHandle._translate_isinstance( - pool, builder, mod, cargs.get(0), cargs.get(1), trans) - if is_res is not None: - return is_res - - return None - - def _tc_h6_method_dispatch(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr, - func_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - hit_box: t.CPtr = None) -> llvmlite.Value | t.CPtr: - """静态类/方法调用/表达式接收者/self.field/list 内置(未命中返回 None) - - hit_box: 命中标记(t.CPtr,[0]=1 表示已识别为方法调用路径)。 - 编译器生成方法(如 __before_init__/__init__)恒返回 void, - _translate_method_call 处理后返回 None(无返回值)——若不标记, - translate_call 会误判"未命中"继续走跨模块函数路径(把对象名 - 当模块名查 SHA1 → "跨模块调用 'buf.__before_init__' 找不到模块 SHA1")。 - """ - # 检测类名静态/类方法调用: ClassName.method(args) - # 当 cl.func 是 Attribute、value 是已注册结构体类名(非普通变量)时, - # 且方法带 @staticmethod/@classmethod 元数据,走静态调用路径 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - st_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if st_at is not None and st_at.value is not None and trans is not None: - if st_at.value.kind() == ast.ASTKind.Name: - st_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(st_at.value) - if st_nm.id is not None: - # 仅当该名称不是普通变量且是已注册结构体类名时尝试静态/类方法 - # 追加"非导入模块"条件:st_nm.id 是模块名(import X as Y 把别名 - # Y 加入 _imported_modules,HandlesImports L344-347)时,X.Y(...) - # 是模块限定调用(Module.Class 构造 / Module.func 函数),不是 - # ClassName.method(obj,args)。模块名与类名同名时(CompilerFactory. - # CompilerFactory(...) 构造 / .set_factory(...) 函数,main.vp - # 追加84/84b 根因)get_struct_type(st_nm.id) 会误判为类名 → - # 把首实参当 self 传 _call_method_on_ptr → 返回类型查 "X.Y" 永远 - # 落空 → fail-fast。模块限定调用由尾部 ctor 检测(L7441 模块限定 - # 构造)与跨模块函数路径正确路由。 - st_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, st_nm.id) - if st_var is None and HandlesStruct.get_struct_type(st_nm.id) is not None \ - and HandlesImports.is_module_imported( - trans._imported_modules, st_nm.id) == 0: - # REnum 变体构造优先于静态/类方法调用: - # ClassName.VariantName(args)(如 Option.Some(42))若被当 - # "实例方法经类名调用"处理,会把首实参 42 当 self 传 - # _call_method_on_ptr → 查 "Option.Some" 方法返回类型 → - # 跨模块 stub 未命中 → fail-fast(EnumTest "方法 - # 'Option.Some' 返回类型无法确定" 根因)。REnum 变体 - # 构造检测原在 translate_call 尾部(L7493),被本分支 - # 拦截先执行不到,此处提前检测。 - if HandlesClassDef._is_renum_class_name(st_nm.id) != 0: - rc_tag_sc: int = HandlesClassDef._lookup_renum_variant_in_class( - st_nm.id, func_name) - if rc_tag_sc >= 0: - return ExprCallCtor._translate_renum_construct( - pool, builder, mod, st_nm.id, func_name, - rc_tag_sc, cargs, can, trans) - st_res: llvmlite.Value | t.CPtr = ExprCallCtor._translate_static_class_call( - pool, builder, mod, st_nm.id, func_name, cl, trans) - if st_res is not None: - return st_res - # 实例方法经类名调用: ClassName.method(obj, args) → obj.method(args) - # (Python 语义,首参是 self 对象;zdeflate.vp - # zdeflate_stream.find_match(s, data, ...) 根因:_translate_ - # static_class_call 对非静态方法返回 None 后,ClassName 被 - # 通用路径当模块名 → "跨模块调用找不到模块 SHA1") - # st_nm.id == func_name(类名==方法名,如 CompilerFactory. - # CompilerFactory(...))不是实例方法调用而是构造调用: - # 模块名与类名同名时本分支把模块限定类构造误判为 - # ClassName.method(obj,args),首实参当 self 传 → - # _call_method_on_ptr 查 "X.X" 返回类型永远落空 → - # fail-fast(main.vp CompilerFactory 追加84 根因)。 - # 跳过本分支,落到 translate_call 尾部的 ctor 检测 - # (L7426 模块限定类构造 find_struct_by_module 正确路由)。 - if can >= 1 and cargs is not None \ - and string.strcmp(st_nm.id, func_name) != 0: - im_self: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(0), None, 0, trans) - if im_self is not None: - im_rem: t.CSizeT | t.CPtr = None - if can >= 2: - im_rem = pool.alloc(t.CSizeT(can - 1) * 8) - if im_rem is not None: - ri_im: t.CSizeT - for ri_im in range(can - 1): - im_rv: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(ri_im + 1), None, 0, trans) - if im_rv is not None: - im_rem[ri_im] = t.CSizeT(im_rv) - im_res: llvmlite.Value | t.CPtr = ExprCallCtor._call_method_on_ptr( - pool, builder, mod, st_nm.id, func_name, - im_self, im_rem, can - 1, trans) - if im_res is not None: - return im_res - elif st_at.value.kind() == ast.ASTKind.Attribute: - # 模块限定静态调用: module.ClassName.static_method(args) - # cl.func = Attribute(value=Attribute(value=Name(module), - # attr=ClassName), attr=method_name) - # 此前未检测 → 走通用路径把 method_name 当裸函数解析, - # 生成 call i32 @from_long(无类名/SHA1 前缀)→ 链接 - # undefined reference(CPythonTest PyLongObj.from_long 根因) - st_at2: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(st_at.value) - if st_at2 is not None and st_at2.attr is not None and st_at2.value is not None: - if st_at2.value.kind() == ast.ASTKind.Name: - # ClassName 是已注册结构体类名时尝试静态/类方法 - if HandlesStruct.get_struct_type(st_at2.attr) is not None: - st_res2: llvmlite.Value | t.CPtr = ExprCallCtor._translate_static_class_call( - pool, builder, mod, st_at2.attr, func_name, cl, trans) - if st_res2 is not None: - return st_res2 - - # 检测方法调用: obj.method(args) - # 当 cl.func 是 Attribute 且 obj 是已注册的结构体变量时,翻译为方法调用 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if method_at is not None and method_at.value is not None: - if method_at.value.kind() == ast.ASTKind.Name and trans is not None: - method_obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(method_at.value) - if method_obj_nm.id is not None: - # 查找对象变量 - obj_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, method_obj_nm.id) - if obj_var is not None and obj_var.Ty is not None: - # 检查是否为 Ptr(Struct(...))(结构体值变量) - # 或 Ptr(Ptr(Struct(...)))(指针变量,需 load) - match obj_var.Ty: - case llvmlite.LLVMType.Ptr(obj_struct_ty): - class_nm: str = HandlesStruct.get_class_name_by_type( - pool, obj_struct_ty) - if class_nm is not None: - # list 泛型内置容器方法(append/get/set/pop/clear/__iter__/ - # __len__/__getitem__/__setitem__)由下方 list 内置分支 - # (L5848 起)内联 GEP 处理,不注册方法函数;若走 - # _translate_method_call 会查 append 返回类型(函数/text.ll/ - # vpi stub 均未命中)→ fail-fast。检测到 list 方法时 - # 跳过 method_call,落到内置分支(NewAstTest body.append 根因)。 - if ExprCallHandle._is_list_builtin_method(class_nm, func_name) == 0: - if hit_box is not None: - hit_box[0] = 1 - return ExprCallCtor._translate_method_call( - pool, builder, mod, class_nm, func_name, - obj_var, cl, trans) - # 指针变量: alloca 类型是 Ptr(Ptr(Struct)) - # load 获取实际指针 Ptr(Struct) 后再查找 - match obj_struct_ty: - case llvmlite.LLVMType.Ptr(inner_struct_ty): - inner_nm: str = HandlesStruct.get_class_name_by_type( - pool, inner_struct_ty) - if inner_nm is not None: - # list 内置方法同样跳过(同 Ptr(Struct) 分支) - if ExprCallHandle._is_list_builtin_method(inner_nm, func_name) == 0: - obj_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, obj_struct_ty, obj_var) - if obj_ptr is not None: - if hit_box is not None: - hit_box[0] = 1 - return ExprCallCtor._translate_method_call( - pool, builder, mod, inner_nm, func_name, - obj_ptr, cl, trans) - # FakeDuck: str/bytes 变量(Ptr(i8),AnnotClassName 为空) - # 方法调用 → 扩展类 _Type/_str(a.type_id() / a.upper())。 - # 前置拦截:常规结构体方法分支全落空时,尝试扩展类方法 - # (find_func_in_module 未命中返回 None,不影响正常路径)。 - fd_name_res: llvmlite.Value | t.CPtr = ExprCallHandle._translate_fakeduck_call( - pool, builder, mod, None, func_name, cl, trans) - if fd_name_res is not None: - return fd_name_res - # AnnotClassName 回退:联合类型简化为 Ptr(i8) 时, - # 通过原始类型注解的类名查找结构体 - var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, method_obj_nm.id) - if var_entry is not None and var_entry.AnnotClassName is not None: - annot_val: str = var_entry.AnnotClassName - # 解析模块限定名 "memhub.MemBuddy" → mod_nm="memhub", cls_nm="MemBuddy" - dot_ptr: str = string.strrchr(annot_val, '.') - cls_nm2: str = annot_val - mod_nm2: str = None - if dot_ptr is not None: - cls_nm2 = dot_ptr + 1 - total_len_av: t.CSizeT = string.strlen(annot_val) - cls_len_av: t.CSizeT = string.strlen(cls_nm2) - mod_len2: t.CSizeT = total_len_av - cls_len_av - 1 - mod_nm2 = pool.alloc(mod_len2 + 1) - if mod_nm2 is not None: - string.strncpy(mod_nm2, annot_val, mod_len2) - mod_nm2[mod_len2] = '\0' - # 检查结构体是否已注册 - if HandlesStruct.get_struct_type(cls_nm2) is not None: - # list 内置方法跳过 method_call(同 Ptr(Struct) 分支), - # 落到下方 list 内置分支 - if ExprCallHandle._is_list_builtin_method(cls_nm2, func_name) == 0: - # 结构体已注册:load obj_ptr 走方法调用 - i8_ptr_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - obj_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i8_ptr_ty2, obj_var) - if obj_ptr2 is not None: - if hit_box is not None: - hit_box[0] = 1 - return ExprCallCtor._translate_method_call( - pool, builder, mod, cls_nm2, func_name, - obj_ptr2, cl, trans) - else: - # list 内置方法跳过(结构体未注册路径同样不能 - # 构造 {sha1}.{cls}.append 调用名——list 方法无此函数) - if ExprCallHandle._is_list_builtin_method(cls_nm2, func_name) == 0: - # FakeDuck: str 变量方法调用 → 扩展类 _Type/_str - # a.type_id() / a.upper() / " ".isspace() 等 - # AnnotClassName=="str" 且对象是 char* 时触发, - # self 用影子结构体 {a}__meta__(或临时影子)。 - fd_res: llvmlite.Value | t.CPtr = ExprCallHandle._translate_fakeduck_call( - pool, builder, mod, cls_nm2, func_name, cl, trans) - if fd_res is not None: - return fd_res - # 结构体未注册(跨模块依赖未翻译): - # 用模块名查 SHA1 构造方法调用名 - sha1_fc: str = None - if mod_nm2 is not None: - sha1_fc = self._lookup_module_sha1(mod_nm2) - if sha1_fc is not None: - # 构造 "{sha1}.{cls_nm2}.{func_name}" 调用名 - mlen3: t.CSizeT = string.strlen(sha1_fc) + string.strlen(cls_nm2) + string.strlen(func_name) + 3 - mangled3: str = pool.alloc(mlen3) - if mangled3 is not None: - viperlib.snprintf(mangled3, mlen3, "%s.%s.%s", sha1_fc, cls_nm2, func_name) - # load obj_ptr (self) - i8_ptr_ty3: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - obj_ptr3: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i8_ptr_ty3, obj_var) - if obj_ptr3 is not None: - # 构建参数链表: obj_ptr3 (self) → 其他参数 - llvmlite.value_set_next(obj_ptr3, None) - head3: llvmlite.Value | t.CPtr = obj_ptr3 - tail3: llvmlite.Value | t.CPtr = obj_ptr3 - for ai3 in range(can): - arg3: ast.AST | t.CPtr = cargs.get(ai3) - if arg3 is not None: - arg_val3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg3, None, 0, trans) - if arg_val3 is not None: - llvmlite.value_set_next(arg_val3, None) - llvmlite.value_set_next(tail3, arg_val3) - tail3 = arg_val3 - total3: int = 1 + can - ret_ty3: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty( - pool, cls_nm2, func_name) - if ret_ty3 is None: - ret_ty3 = self._LookupMethodRetTyFromTextLL( - pool, sha1_fc, cls_nm2, func_name) - if ret_ty3 is None: - # 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单) - ret_ty3 = self._lookup_method_ret_ty_via_vpi( - pool, sha1_fc, cls_nm2, func_name) - if ret_ty3 is None: - # 本分支仅在"注解类结构体未注册"时到达(L6932 else): - # 类未注册 → 无法沿 MRO 解析 Mixin 方法定义模块。 - # 例如 g 注解 Generator.Generator,但 _register_cdefine_from_value - # 定义在 AssignGenMixin.vp——其 text.ll 的 define 名是 - # {AssignGenMixin_sha1}.AssignGenMixin.xxx,查 - # {Generator_sha1}.Generator.xxx 永远落空(追加80d 根因; - # sha1_fc 存在 + text.ll 存在仍查不到,固定 256KB 截断 - # 只是次要因素)。必须标记 pending:等 Generator 注册后 - # 下遍走 L6919 已注册分支 → _translate_method_call 沿 - # MRO 链找到 AssignGenMixin → 精确解析。真正不存在的 - # 类/方法由 Phase A 收敛检查兜底,绝不在此 fail-fast - # 中断多遍收敛(对齐追加77/77b 类 defer 原则)。 - if trans is not None: - trans._deps_pending = 1 - # 依赖未就绪:保持默认 i32(build_call(Void) - # 返回 None 破坏表达式翻译;本遍不写盘) - ret_ty3 = llvmlite.Int32(pool) - self._ensure_method_declare(pool, mod, mangled3, ret_ty3, head3, total3) - return llvmlite.build_call(builder, mangled3, head3, total3, ret_ty3, 0) - else: - # 编译器生成特殊方法放行(__before_init__/__init__ 等): - # 结构体未注册 + 模块 SHA1 均不可查(Phase A 依赖未就绪)时, - # 方法返回类型由编译器确定性定义(_special_method_ret_ty), - # 不依赖结构体注册即可精确解析。走 _translate_method_call 处理 - # (内部含 _special_method_ret_ty + mc_entry/类型名 SHA1 提取), - # 绝不掉出返回 None 让 translate_call 把对象名当模块名 - # 报"跨模块调用 'buf.__before_init__' 找不到模块 SHA1" - # (memhub.alloc_buf buf.__before_init__() 根因)。 - sp_ty4: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty( - pool, cls_nm2, func_name) - if sp_ty4 is not None: - i8_ptr_ty4: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - obj_ptr4: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i8_ptr_ty4, obj_var) - if obj_ptr4 is not None: - if trans is not None: - trans._deps_pending = 1 - if hit_box is not None: - hit_box[0] = 1 - return ExprCallCtor._translate_method_call( - pool, builder, mod, cls_nm2, func_name, - obj_ptr4, cl, trans) - - # ============================================================ - # 检测表达式接收者方法调用: (expr).method(args) - # - # 当 method_at.value 是 BinOp/Subscript/Call 等非 Name/Attribute 表达式时 - # (如 (a + b).dot(c)、(v1 + v2) * 3.0),先 translate_value 求值接收者, - # 再从值的 LLVM 类型(Ptr(Struct))解析类名,走方法调用路径。 - # ============================================================ - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - expr_method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if expr_method_at is not None and expr_method_at.value is not None and trans is not None: - evk: int = expr_method_at.value.kind() - # Attribute 接收者区分两种形态: - # 1. 模块限定路径(os._win32.exists / w32.fileio.fn)——根名是已导入 - # 模块或 t/c,留给下方跨模块限定路径处理 - # 2. 字段链表达式接收者(self.writer.write_bits / self.pool.alloc) - # ——根名是对象(self/局部变量),必须走本方法调用路径; - # 否则被模块限定路径误判 xmod_path="self.writer" → "找不到模块 - # SHA1"(zdeflate.vp write_fixed_block 根因) - is_mod_path_expr: int = 0 - if evk == ast.ASTKind.Attribute: - expr_root: ast.AST | t.CPtr = expr_method_at.value - while expr_root is not None and expr_root.kind() == ast.ASTKind.Attribute: - expr_root = (ast.Attribute | t.CPtr)(expr_root).value - if expr_root is not None and expr_root.kind() == ast.ASTKind.Name: - expr_root_nm: str = (ast.Name | t.CPtr)(expr_root).id - if expr_root_nm is not None: - if string.strcmp(expr_root_nm, "t") == 0 or \ - string.strcmp(expr_root_nm, "c") == 0: - is_mod_path_expr = 1 - elif trans._imported_modules is not None: - if HandlesImports.is_module_imported( - trans._imported_modules, expr_root_nm) != 0: - is_mod_path_expr = 1 - if evk != ast.ASTKind.Name and is_mod_path_expr == 0: - # 翻译接收者表达式(求值结果应为 Ptr(Struct)) - expr_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, expr_method_at.value, funcs_ptr, func_count, trans) - if expr_obj is not None and expr_obj.Ty is not None: - expr_cls_nm: str = None - # 递归解 Ptr:识别 X|t.CPtr 联合简化的 Ptr(Ptr(Struct)) - # (如 (a*2.0 - b) 中 __mul__ 返回 Vec3**),否则方法 - # 调用被当裸函数 @dot 解析 → 链接 undefined symbol - expr_struct_ty: llvmlite.LLVMType | t.CPtr = \ - HandlesStruct.get_struct_type_from_value(expr_obj) - if expr_struct_ty is not None: - expr_cls_nm = HandlesStruct.get_class_name_by_type( - pool, expr_struct_ty) - # 回退:LLVM 类型为 Ptr(i8)(方法返回 X|t.CPtr 无类型信息)时, - # 从接收者表达式结构推断类名(链式调用 c2.scale(2.0).move(...) - # 的 scale 返回 Ptr(i8),经 infer_expr_class → vpi 返回注解) - # 跨 Mixin 不能 self 调用 ExprGenMixin 方法,经全局单例 - if expr_cls_nm is None: - import lib.core.Gen.Generator as Generator - g3: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( - t.CVoid(HandlesExpr._g_gen, t.CPtr)) - if g3 is not None: - expr_cls_nm = g3.infer_expr_class( - pool, mod, expr_method_at.value, trans) - if expr_cls_nm is not None: - # 值类型接收者(内嵌 struct 字段,如 zdeflate s.writer 值字段): - # 方法调用 self 必须传字段地址(GEP)而非 load 出的结构体值, - # 否则结构体值(40B)塞进 zbit_writer* 参数 → ABI 错配 → - # 被调方把值当 this 指针解引用 → GEP 0x18 崩溃 - # (s.writer.write_zlib_header 运行时 access-violation 根因; - # 本路径 evk=Attribute 先于 self.field.method() 分支命中)。 - expr_is_ptr: int = 0 - match expr_obj.Ty: - case llvmlite.LLVMType.Ptr(expr_ptr_inner): - expr_is_ptr = 1 - case _: - expr_is_ptr = 0 - if expr_is_ptr == 0: - expr_addr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( - builder, pool, mod, expr_method_at.value, trans) - if expr_addr is not None: - expr_obj = expr_addr - if hit_box is not None: - hit_box[0] = 1 - return ExprCallCtor._translate_method_call( - pool, builder, mod, expr_cls_nm, func_name, - expr_obj, cl, trans) - # FakeDuck: 表达式接收者解析失败且对象是 char* 时 - # (如 " ".isspace()),尝试扩展类 _Type/_str 方法 - # (self 用临时影子,对齐 TPC L2858-2873) - fd_expr_res: llvmlite.Value | t.CPtr = ExprCallHandle._translate_fakeduck_call( - pool, builder, mod, None, func_name, cl, trans) - if fd_expr_res is not None: - return fd_expr_res - - # ============================================================ - # 检测 self.field.method() 调用 - # - # 当 method_at.value 是 Attribute(字段访问,如 self.__pool__)时, - # 翻译字段值获取对象指针,然后走方法调用路径。 - # - # 路径1: 从字段值的 LLVM 类型获取类名(字段类型为 Ptr(Struct("MemManager"))) - # 路径2: 从字段的 AnnotClassName 回退查找(字段类型被简化为 Ptr(i8) 时) - # ============================================================ - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - attr_method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if attr_method_at is not None and attr_method_at.value is not None: - if attr_method_at.value.kind() == ast.ASTKind.Attribute and trans is not None: - inner_attr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(attr_method_at.value) - if inner_attr is not None and inner_attr.attr is not None: - # 翻译 self.__pool__ 获取字段值(已 load 的对象指针) - field_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, attr_method_at.value, funcs_ptr, func_count, trans) - if field_obj is not None and field_obj.Ty is not None: - field_cls_nm: str = None - # 路径1: 从字段值的 LLVM 类型获取类名 - match field_obj.Ty: - case llvmlite.LLVMType.Ptr(field_struct_ty): - field_cls_nm = HandlesStruct.get_class_name_by_type( - pool, field_struct_ty) - # 路径2: 从字段注解类名回退查找 - if field_cls_nm is None: - if inner_attr.value is not None and inner_attr.value.kind() == ast.ASTKind.Name: - inner_name_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner_attr.value) - if inner_name_node is not None and inner_name_node.id is not None: - inner_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, inner_name_node.id) - if inner_var is not None and inner_var.Ty is not None: - match inner_var.Ty: - case llvmlite.LLVMType.Ptr(field_owner_struct_ty): - field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( - field_owner_struct_ty, inner_attr.attr) - if field_info is not None: - field_annot: str = HandlesStruct.get_field_annot_class_name(field_info) - if field_annot is not None: - dot_p: str = string.strrchr(field_annot, 46) - if dot_p is not None: - field_cls_nm = dot_p + 1 - else: - field_cls_nm = field_annot - if field_cls_nm is not None: - # 值类型字段(内嵌 struct,如 zdeflate_stream.writer: zbit_writer) - # 方法调用 self 必须传字段地址(GEP),而非 load 出的结构体值: - # 传值给 stub 声明/define 的 zbit_writer* 参数 → ABI 错配, - # 被调方把结构体值前 8 字节当 this 指针解引用 → GEP 0x18 崩溃 - # (zdeflate s.writer.write_zlib_header 运行时 access-violation 根因)。 - is_val_field: int = 0 - match field_obj.Ty: - case llvmlite.LLVMType.Ptr(field_ptr_inner): - is_val_field = 0 - case _: - is_val_field = 1 - if is_val_field != 0: - field_addr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( - builder, pool, mod, attr_method_at.value, trans) - if field_addr is not None: - field_obj = field_addr - if hit_box is not None: - hit_box[0] = 1 - return ExprCallCtor._translate_method_call( - pool, builder, mod, field_cls_nm, func_name, - field_obj, cl, trans) - - # ============================================================ - # 检测 list 内置方法调用: lst.get(i), lst.set(i,v), lst.pop(), lst.clear(), lst.__iter__() - # list[T] 是泛型类不注册 struct,方法调用处理器(上方)无法处理, - # 需要在此特殊处理。 - # list 结构布局 (6 字段 × 8 字节): - # __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40) - # ============================================================ - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - lm_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if lm_at is not None and lm_at.attr is not None and lm_at.value is not None: - lm_name: str = lm_at.attr - # 判断是否是 list 方法名 - lm_is_list: int = 0 - if string.strcmp(lm_name, "get") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "__getitem__") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "set") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "__setitem__") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "pop") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "clear") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "__iter__") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "append") == 0: lm_is_list = 1 - - if lm_is_list == 1 and trans is not None: - # 翻译 list 对象 - lm_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, lm_at.value, funcs_ptr, func_count, trans) - if lm_obj is not None: - # 防御性类型检查: lm_obj 必须是指针类型才能做 GEP - # translate_value 对某些 Attribute 节点(如 ast.Arguments 的属性) - # 可能返回 i32 0 (非指针),直接 GEP 会导致 - # "base of getelementptr must be a pointer" 错误 - if lm_obj.Ty is None or HandlesExpr.is_ptr_type(lm_obj.Ty) == 0: - # translate_value 类型推断失败(目标对象非指针): - # fail-fast,绝不 VLogger.critical 后 return None 静默吞掉 - HandlesType.fatal_error( - lm_at.value, f"list 方法 '{lm_name}' 目标对象非指针", "TypeError") - # list 对象类型确认(额外搜索路径):list 内置分支仅按方法名 - # 判断(get/set/__getitem__ 等非 list 专有),须确认对象确实 - # 是 list——从对象结构体名匹配 "list"。明确非 list(如 dict / - # 普通类未注册场景)跳过本分支,避免按 list 布局 GEP 生成 - # 错误 IR(dict 的 get 被当 list.get 按 __data__/__elem_size__ - # 偏移读写垃圾)。 - lm_conf_ty: llvmlite.LLVMType | t.CPtr = \ - HandlesStruct.get_struct_type_from_value(lm_obj) - lm_conf_nm: str = None - if lm_conf_ty is not None: - lm_conf_nm = llvmlite.get_struct_name(lm_conf_ty) - if lm_conf_nm is not None and \ - string.strstr(lm_conf_nm, "list") is None: - return None - # list 内置分支命中标记:void 方法(set/clear)成功处理后返回 - # None,必须置位 hit_box 区分"已识别为 list 方法路径",否则 - # translate_call 误判未命中继续走跨模块函数路径,把对象名当 - # 模块名查 SHA1 → "跨模块调用 'nums.set' 找不到模块 SHA1" - # (ListTest main.vp nums.set(1,99) 根因;对齐 _translate_method_call - # 调用点的 hit_box 置位模式)。 - if hit_box is not None: - hit_box[0] = 1 - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - # 元素类型 T:从 list 特化类型名解析(list[int]→i32、 - # list[str]→i8*、未知/指针元素→i8*)。此前 get/set/pop - # 固定 i8*(8 字节)读写:set 的 8 字节 store 覆盖相邻元素 - # (inttoptr 值,如 set(1,99) 把 data[8..11] 的 30 清 0), - # pop 读回 0 → ListTest "pop FAILED expect 30" 根因。 - # subscript 路径(list_getitem_inline 调用方)已用 - # _list_elem_type_from_name 修正,方法调用路径漏改。 - lm_esty: llvmlite.LLVMType | t.CPtr = \ - HandlesStruct.get_struct_type_from_value(lm_obj) - lm_ename: str = None - if lm_esty is not None: - lm_ename = llvmlite.get_struct_name(lm_esty) - lm_elem_ty: llvmlite.LLVMType | t.CPtr = None - if lm_ename is not None: - import lib.core.Gen.Generator as Generator - g_le: Generator.Generator | t.CPtr = ( - Generator.Generator | t.CPtr)( - t.CVoid(HandlesExpr._g_gen, t.CPtr)) - if g_le is not None: - lm_elem_ty = g_le._list_elem_type_from_name( - pool, lm_ename) - if lm_elem_ty is None: - lm_elem_ty = i8_ptr_ty - - # get / __getitem__: 返回 index 处的元素 - if string.strcmp(lm_name, "get") == 0 or string.strcmp(lm_name, "__getitem__") == 0: - if can >= 1: - # 加载 __data__ (偏移 0) - g_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) - g_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0) - g_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, g_dpp) - # 加载 __elem_size__ (偏移 32, index 4) - g_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) - g_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4) - g_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, g_epp) - # 翻译 index - g_idx_node: ast.AST | t.CPtr = cargs.get(0) - g_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, g_idx_node, None, 0, trans) - if g_data is not None and g_esize is not None and g_idx_val is not None: - g_idx_i64: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( - builder, g_idx_val, i64_ty, g_idx_node) - g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize) - g_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, g_data, g_offset) - if g_addr is not None: - g_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, g_addr, llvmlite.Ptr(pool, lm_elem_ty)) - if g_ep is not None: - return llvmlite.build_load(builder, lm_elem_ty, g_ep) - - # set / __setitem__: 设置 index 处的元素 - elif string.strcmp(lm_name, "set") == 0 or string.strcmp(lm_name, "__setitem__") == 0: - if can >= 2: - s_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) - s_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0) - s_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, s_dpp) - s_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) - s_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4) - s_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, s_epp) - s_idx_node: ast.AST | t.CPtr = cargs.get(0) - s_val_node: ast.AST | t.CPtr = cargs.get(1) - s_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, s_idx_node, None, 0, trans) - s_val_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, s_val_node, None, 0, trans) - if s_data is not None and s_esize is not None and s_idx_val is not None and s_val_val is not None: - s_idx_i64: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( - builder, s_idx_val, i64_ty, s_idx_node) - s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize) - s_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s_data, s_offset) - if s_addr is not None: - s_val_elem: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( - builder, s_val_val, lm_elem_ty, s_val_node) - s_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, s_addr, llvmlite.Ptr(pool, lm_elem_ty)) - if s_ep is not None: - llvmlite.build_store(builder, s_val_elem, s_ep) - return None - - # pop: 返回最后一个元素,count-- - elif string.strcmp(lm_name, "pop") == 0: - p_idx1: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) - p_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx1) - p_count: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_cpp) - p_nc: llvmlite.Value | t.CPtr = llvmlite.build_sub( - builder, p_count, llvmlite.const_int64(pool, 1)) - llvmlite.build_store(builder, p_nc, p_cpp) - p_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) - p_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx0) - p_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, p_dpp) - p_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) - p_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx4) - p_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_epp) - if p_data is not None and p_esize is not None and p_nc is not None: - p_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, p_nc, p_esize) - p_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, p_data, p_offset) - if p_addr is not None: - p_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, p_addr, llvmlite.Ptr(pool, lm_elem_ty)) - if p_ep is not None: - return llvmlite.build_load(builder, lm_elem_ty, p_ep) - - # clear: count = 0 - elif string.strcmp(lm_name, "clear") == 0: - c_idx1: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) - c_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, c_idx1) - llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), c_cpp) - return None - - # __iter__: iter_index = 0, return self - elif string.strcmp(lm_name, "__iter__") == 0: - it_idx5: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 5) - it_ipp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, it_idx5) - llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), it_ipp) - return lm_obj - - # append: 直接调用 list.append(self, item) - # append 需要容量检查和内存重分配,逻辑复杂,直接调用 _list.py 中的实现 - elif string.strcmp(lm_name, "append") == 0: - if can >= 1: - ap_sha1: str = self._lookup_module_sha1("_list") - if ap_sha1 is None: - # 依赖模块未编译(_list 未预加入编译链):fail-fast, - # 绝不静默跳过 append(元素永远不会被加入列表) - HandlesType.fatal_error( - cl, "list.append: 找不到 _list 模块 SHA1(依赖模块未编译)", - "InternalCompilerError") - if ap_sha1 is not None: - # 特化类名提取:list.append 的符号名是 - # {sha1}.list[AST|CPtr].append(带类型参数特化名), - # 而非 {sha1}.list.append。lm_obj 类型即特化结构体 - # Ptr(list[AST|CPtr]),从类型解析特化类名拼接调用名, - # 否则 ld.lld undefined symbol(定义端是特化名)。 - ap_spec_nm: str = None - ap_struct_ty: llvmlite.LLVMType | t.CPtr = \ - HandlesStruct.get_struct_type_from_value(lm_obj) - if ap_struct_ty is not None: - ap_spec_nm = HandlesStruct.get_class_name_by_type( - pool, ap_struct_ty) - if ap_spec_nm is None: - ap_spec_nm = "list" - # 触发泛型特化翻译(幂等,MethodsEmitted 防重入): - # list[AST|CPtr].append 的 define 方法体在特化类翻译时 - # 生成。仅构造调用名不触发特化会导致定义缺失 - # (ld.lld undefined symbol: list[AST|CPtr].append)。 - if trans is not None and ap_spec_nm is not None: - lbkt_ap: str = string.strchr(ap_spec_nm, '[') - if lbkt_ap is not None: - rbkt_ap: str = string.strrchr(ap_spec_nm, ']') - if rbkt_ap is not None and rbkt_ap > lbkt_ap: - base_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(lbkt_ap) - t.CUInt64T(ap_spec_nm)) - arg_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(rbkt_ap) - t.CUInt64T(lbkt_ap) - 1) - if base_len_ap > 0 and arg_len_ap > 0: - base_buf_ap: str = pool.alloc(base_len_ap + 1) - arg_buf_ap: str = pool.alloc(arg_len_ap + 1) - if base_buf_ap is not None and arg_buf_ap is not None: - string.strncpy(base_buf_ap, ap_spec_nm, base_len_ap) - base_buf_ap[base_len_ap] = '\0' - string.strncpy(arg_buf_ap, lbkt_ap + 1, arg_len_ap) - arg_buf_ap[arg_len_ap] = '\0' - args_ap: list[str] | t.CPtr = list[str](pool, 8) - if args_ap is not None: - # 逗号分隔多类型实参(list[X] / dict[K, V]) - cur_ap: str = arg_buf_ap - while cur_ap is not None: - comma_ap: str = string.strchr(cur_ap, ',') - if comma_ap is None: - args_ap.append(cur_ap) - break - seg_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(comma_ap) - t.CUInt64T(cur_ap)) - seg_buf_ap: str = pool.alloc(seg_len_ap + 1) - if seg_buf_ap is not None: - string.strncpy(seg_buf_ap, cur_ap, seg_len_ap) - seg_buf_ap[seg_len_ap] = '\0' - args_ap.append(seg_buf_ap) - cur_ap = comma_ap + 1 - HandlesClassDef._specialize_generic_class( - trans, base_buf_ap, args_ap) - # 调用名 "{sha1}.{spec}.append": - # sha1(16) + '.'(1) + spec + '.append'(7) + NUL(1) = spec + 25。 - # 此前 +8 少 1 字节,snprintf 截断末尾 'd' → - # undefined symbol: ...list[AST|CPtr].appen(缺 d)。 - ap_mlen: t.CSizeT = string.strlen(ap_sha1) + \ - string.strlen(ap_spec_nm) + 26 - ap_mangled: str = pool.alloc(ap_mlen) - if ap_mangled is not None: - viperlib.snprintf(ap_mangled, ap_mlen, "%s.%s.append", - ap_sha1, ap_spec_nm) - ap_item_node: ast.AST | t.CPtr = cargs.get(0) - ap_item_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, ap_item_node, None, 0, trans) - if ap_item_val is not None: - llvmlite.value_set_next(lm_obj, None) - llvmlite.value_set_next(ap_item_val, None) - llvmlite.value_set_next(lm_obj, ap_item_val) - ap_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - self._ensure_method_declare(pool, mod, ap_mangled, ap_ret_ty, lm_obj, 2) - return llvmlite.build_call(builder, ap_mangled, lm_obj, 2, ap_ret_ty, 0) - +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.Generator as Generator +import lib.core.Gen.ExprGenCls as ExprGenCls +import lib.core.Gen.ExprGenName as ExprGenName +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import sys +import viperlib +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.CallGenBase as CallGenBase + +# ============================================================ +# CallGenDispatch - CallGenMixin 拆分(阶段 C):translate_call 检测段 +# +# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 每个 helper 返回 Value|CPtr,None = 未命中(translate_call 继续)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class CallGenDispatch(CallGenBase.CallGenBase): + """translate_call 前置检测 helper(继承 Base)""" + + def _tc_h1_super_ctraits(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + hit_box: t.CPtr = None) -> llvmlite.Value | t.CPtr: + """super()/ctraits 编译期检测(未命中返回 None) + + hit_box: 命中标志字节([0]=1 表示被本 helper 拦截处理)。 + super().method() 命中后 _translate_super_call 对 void 方法(如 + __init__)经 build_call 返回 None 属预期(void call 无 SSA 值), + 必须用 hit_box 与"未命中"区分,否则 translate_call 会误判继续 + 主路径 → 把内层 Call(super) 当裸名调用报"super 未定义"。 + """ + # super() 语义(2026-08-10):super().method(args) → 静态调用父类方法 + # 形态: Call(func=Attribute(value=Call(func=Name('super')), attr=method)) + # 必须在 Attribute 分派前拦截——否则 value 的 Call(super) 被 translate_value + # 当作普通函数调用报错,且走普通属性调用会命中自身/虚分派而非父类实现。 + if func_name is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + sup_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if sup_at.value is not None and sup_at.value.kind() == ast.ASTKind.Call: + sup_cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(sup_at.value) + if sup_cl.func is not None and sup_cl.func.kind() == ast.ASTKind.Name: + sup_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sup_cl.func) + if sup_nm.id is not None and string.strcmp(sup_nm.id, "super") == 0: + if hit_box is not None: + hit_box[0] = 1 + return self.Gen.CallGenCall._translate_super_call( + pool, builder, mod, cl, func_name, trans) + + # ctraits 宏库编译期谓词:ctraits.isptr(x) 不生成运行时调用, + # 直接按变量存储类型返回编译期常量(CIf 求值失败回退或非 CIf 上下文时兜底, + # 避免生成跨模块调用 ctraits.isptr 触发"模块未注册 SHA1"误导性报错) + if func_name is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + ct_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if ct_at.value is not None and ct_at.value.kind() == ast.ASTKind.Name: + ct_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ct_at.value) + if ct_nm.id is not None and string.strcmp(ct_nm.id, "ctraits") == 0 \ + and string.strcmp(func_name, "isptr") == 0: + ct_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if ct_args is not None and len(ct_args) >= 1: + ct_arg0: ast.AST | t.CPtr = ct_args.get(0) + if ct_arg0 is not None and ct_arg0.kind() == ast.ASTKind.Name: + ct_nm0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ct_arg0) + if ct_nm0.id is not None and trans is not None: + ct_r: int = self.Gen.StmtGenCif._eval_ctraits_isptr(trans.SymTab, ct_nm0.id) + if ct_r > 0: + return llvmlite.const_int32(pool, 1) + return llvmlite.const_int32(pool, 0) + return None + + def _tc_h2_c_special(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + hit_box: t.CPtr = None) -> llvmlite.Value | t.CPtr: + """c.Deref/Asm/LLVMIR 等特殊调用(未命中返回 None) + + hit_box: 命中标记(t.CPtr,[0]=1 表示已识别为 c.* 特殊调用)。 + 仅对 c.Asm/c.LLVMIR 等返回 None(void,无返回值)的调用置位—— + translate_c_asm/translate_c_llvmir 成功处理 void 时返回 None, + 若不加 hit_box 会被 translate_call 误判为"未命中"继续走外部函数路径。 + """ + # 检测 c.Deref / c.DerefAs / c.Addr 等特殊调用(内联 IR,不生成 call) + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + at_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if at_node.value is not None and at_node.value.kind() == ast.ASTKind.Name: + mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_node.value) + if mod_nm.id is not None and string.strcmp(mod_nm.id, "c") == 0: + if string.strcmp(func_name, "Deref") == 0: + return self.Gen.CallGenCBuiltin.translate_c_deref(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "DerefAs") == 0: + return self.Gen.CallGenCBuiltin.translate_c_derefas(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "Addr") == 0: + return self.Gen.CallGenCBuiltin.translate_c_addr(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "Set") == 0: + # c.Set(a, b) = a = b(赋值语义,非指针解引用)。 + # 若当普通函数调用会生成 @Set 引用导致链接失败(undefined reference to `Set')。 + return self.Gen.CallGenCBuiltin.translate_c_set(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "Load") == 0: + return self.Gen.CallGenCBuiltin.translate_c_load(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "Asm") == 0: + # c.Asm 无输出(void)时 translate_c_asm 返回 None: + # 置命中标记,避免 translate_call 误判未命中继续走外部函数 + if hit_box is not None: + hit_box[0] = 1 + return self.Gen.CallGenCBuiltin.translate_c_asm(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "LLVMIR") == 0: + # c.LLVMIR 总是无返回值(返回 None):置命中标记 + if hit_box is not None: + hit_box[0] = 1 + return self.Gen.CallGenCBuiltin.translate_c_llvmir(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "LInp") == 0 or string.strcmp(func_name, "LOut") == 0: + # c.LInp/c.LOut 独立调用时返回 0(仅在 c.LLVMIR 的 f-string 内有意义) + return llvmlite.ConstInt(pool, llvmlite.Int32(pool), 0, "0") + elif string.strcmp(func_name, "CIf") == 0: + # 运行时 c.CIf(expr)(编译期求值失败回退):expr 与 0 比较得到 i1 + # 对齐 TPC HandlesExprCall.py L2434-2444 + cif_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cif_args is not None and len(cif_args) >= 1: + cif_arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cif_args.get(0), funcs_ptr, func_count, trans) + if cif_arg_val is not None: + cif_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(cif_arg_val.Ty) + if cif_bits == 1: + return cif_arg_val + if self.Gen.ExprGenBase.is_ptr_type(cif_arg_val.Ty) != 0: + cif_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull( + pool, cif_arg_val.Ty, "null") + return llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, cif_arg_val, cif_null) + cif_zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + return llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, cif_arg_val, cif_zero) + return llvmlite.ConstInt(pool, llvmlite.Int1(pool), 0, "0") + elif string.strcmp(func_name, "CIfdef") == 0 or string.strcmp(func_name, "CIfndef") == 0: + # 运行时 c.CIfdef/c.CIfndef(编译期求值失败回退):恒真 + # 对齐 TPC HandlesExprCall.py L2445-2446 + return llvmlite.ConstInt(pool, llvmlite.Int1(pool), 1, "1") + return None + + def _tc_h3_stdarg_cast(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT) -> llvmlite.Value | t.CPtr: + """stdarg 糖 + str/int/bool 内置强转(未命中返回 None)""" + # stdarg 糖函数处理: va_arg / arg / va_start / va_end + # 这些函数在 stdarg.vp 中声明为 pass 体,由编译器在翻译期处理: + # va_arg(ap, type) → %N = va_arg , (LLVM 指令) + # va_arg(ap) → 同上,类型从赋值上下文推断(默认 i32) + # arg(type) → 同上,使用当前函数的隐式 va_list (trans._va_list_ptr) + # va_start(ap, _) → call void @llvm.va_start(i8* %ap) (LLVM intrinsic) + # va_end(ap) → call void @llvm.va_end(i8* %ap) (LLVM intrinsic) + # ============================================================ + if func_name is not None and trans is not None: + if string.strcmp(func_name, "va_arg") == 0: + return self.Gen.CallGenVa._translate_va_arg_sugar(pool, builder, mod, cl, cargs, can, + funcs_ptr, func_count, trans) + elif string.strcmp(func_name, "arg") == 0: + return self.Gen.CallGenVa._translate_arg_sugar(pool, builder, mod, cl, cargs, can, + funcs_ptr, func_count, trans) + elif string.strcmp(func_name, "va_start") == 0: + return self.Gen.CallGenVa._translate_va_start_sugar(pool, builder, mod, cargs, can, + funcs_ptr, func_count, trans) + elif string.strcmp(func_name, "va_end") == 0: + return self.Gen.CallGenVa._translate_va_end_sugar(pool, builder, mod, cargs, can, + funcs_ptr, func_count, trans) + + # 内置强转函数: str(x)/bytes(x) → i8*, int(x) → i32 + # 等价于 (str)(x) / (t.CInt32T)(x) + # 单参数:str(val) → bitcast val to i8* + # int(val) → trunc/sext val to i32 + # 泛型类型参数: 类特化/泛型函数上下文中的 T(x) 先解析 T 为具体类型名 + # (如 "int")再按内建强转处理(Box[int].__init__ 的 self.value = T(v)、 + # combine[T1,T2] 的 T1(b) 依赖此路径) + if func_name is not None and can == 1: + cast_fn_name: str = self.Gen.TypeGenBase.resolve_generic_type_name(func_name) + if string.strcmp(cast_fn_name, "str") == 0 or string.strcmp(cast_fn_name, "bytes") == 0: + # str(x) / bytes(x) → i8* (bitcast) + cast_arg: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) + if cast_arg is not None: + i8_ptr_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, cast_arg, i8_ptr_ty_builtin) + return None + elif string.strcmp(cast_fn_name, "int") == 0: + # int(x) → i32 + cast_arg_int: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) + if cast_arg_int is not None: + i32_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, cast_arg_int, i32_ty_builtin) + return None + elif string.strcmp(cast_fn_name, "bool") == 0: + # bool(x) → i1(严格 != 0 归一化) + # 整数: icmp ne x, 0 → i1 + # 浮点: fcmp one x, 0.0 → i1 + # 指针: icmp ne x, null → i1 + cast_arg_bool: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) + if cast_arg_bool is not None: + arg_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(cast_arg_bool.Ty) + arg_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(cast_arg_bool.Ty) + # 整数: icmp ne x, 0 + if arg_bits != 0: + zero_int: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, arg_bits, 0) + if zero_int is not None: + return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cast_arg_bool, zero_int) + return None + # 浮点: fcmp one x, 0.0 + if arg_fbits != 0: + zero_ty: llvmlite.LLVMType | t.CPtr = cast_arg_bool.Ty + zero_flt: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, zero_ty, 0.0) + if zero_flt is not None: + return llvmlite.build_fcmp(builder, llvmlite.FCMP_ONE, cast_arg_bool, zero_flt) + return None + # 指针: icmp ne x, null + ptr_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cast_arg_bool.Ty, "null") + if ptr_null is not None: + return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cast_arg_bool, ptr_null) + return None + return None + return None + + def _tc_h4_type_casts(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT) -> llvmlite.Value | t.CPtr: + """t.XXX / typedef 类型转换(未命中返回 None)""" + # 检测 t.XXX 类型转换: t.CUInt64T(ptr), t.CPtr(val), t.CInt(val) 等 + # 当 func 是 t.XXX 形式且 XXX 是已知类型名时,当作类型转换处理(而非函数调用) + # 支持: + # 单参数: t.CInt(val) → 目标类型 = map_t_type(func_name) + # 双参数: t.CInt(val, t.CPtr) → 目标类型 = Ptr(map_t_type(func_name)) + # t 是内部库,一旦确认为类型转换,绝不跌落到跨模块调用 FATAL 路径 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + tc_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if tc_at.value is not None and tc_at.value.kind() == ast.ASTKind.Name: + tc_mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_at.value) + if tc_mod_nm.id is not None and string.strcmp(tc_mod_nm.id, "t") == 0: + target_ty: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.map_t_type(pool, func_name) + if target_ty is not None: + tc_effective_can: t.CSizeT = can + # 双参数形式: t.CInt(val, t.CPtr) → Ptr(target_ty) + # 注意: void* 在 LLVM 中非法,CVoid* 应表示为 i8* + if can == 2: + tc_arg2_node: ast.AST | t.CPtr = cargs.get(1) + tc_arg2_is_cptr: int = 0 + if tc_arg2_node is not None: + # 形式 1: t.CPtr(Attribute 形式) + if tc_arg2_node.kind() == ast.ASTKind.Attribute: + tc_arg2_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(tc_arg2_node) + if tc_arg2_at.attr is not None and string.strcmp(tc_arg2_at.attr, "CPtr") == 0: + if tc_arg2_at.value is not None and tc_arg2_at.value.kind() == ast.ASTKind.Name: + tc_arg2_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_arg2_at.value) + if tc_arg2_nm.id is not None and string.strcmp(tc_arg2_nm.id, "t") == 0: + tc_arg2_is_cptr = 1 + # 形式 2: 裸名 CPtr(from t import CPtr 后直接使用,如 t.CVoid(x, CPtr)) + elif tc_arg2_node.kind() == ast.ASTKind.Name: + tc_arg2_bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_arg2_node) + if tc_arg2_bn.id is not None and string.strcmp(tc_arg2_bn.id, "CPtr") == 0: + tc_arg2_is_cptr = 1 + if tc_arg2_is_cptr != 0: + # CVoid* → i8*(LLVM 中 void* 表示为 i8*) + match target_ty: + case llvmlite.LLVMType.Void(): + target_ty = llvmlite.Int8(pool) + case _: + pass + target_ty = llvmlite.Ptr(pool, target_ty) + tc_effective_can = 1 + if tc_effective_can == 1: + tc_arg_node: ast.AST | t.CPtr = cargs.get(0) + if tc_arg_node is not None: + tc_arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, tc_arg_node, None, 0, trans) + if tc_arg_val is not None: + return self.Gen.CallGenCtor._translate_t_type_cast( + pool, builder, tc_arg_val, target_ty, + func_name, tc_arg_node, trans) + # t.XXX 类型转换已确认但不满足参数条件:返回 None,不跌落到跨模块 FATAL + return None + + # 模块限定 typedef 转换: posix.mode_t(mode), w32.win32base.HANDLE(v) 等 + # func = Attribute(value=Name(模块), attr=typedef名),此前被误当跨模块函数调用 + # → "跨模块函数 'sha1.mode_t' 返回类型无法精确获取"(SysLibTest os/_posix.vp + # L130 posix.mode_t(mode) 根因)。typedef 名做类型转换(与裸名 BYTEPTR(x) + # 对齐);非 typedef 名继续走模块函数调用。 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + mt_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if mt_at.value is not None and mt_at.value.kind() == ast.ASTKind.Name: + mt_mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(mt_at.value) + if mt_mod_nm.id is not None and string.strcmp(mt_mod_nm.id, "t") != 0 \ + and string.strcmp(mt_mod_nm.id, "c") != 0: + mod_td_ty: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.map_t_type( + pool, func_name) + if mod_td_ty is None: + mod_td_str: str = self.Gen.TypeGenCType.lookup_ctypedef(func_name) + if mod_td_str is not None and self.Gen.TypeGenCType.is_ctypedef_found() != 0: + mod_td_ast: ast.AST | t.CPtr = self.Gen.TypeGenResolve._parse_type_string( + pool, mod_td_str, 0) + if mod_td_ast is not None: + mod_imp_td: str = None + mod_fi_td: str = None + if trans is not None: + mod_imp_td = trans._imported_modules + mod_fi_td = trans._from_imports + mod_td_ty = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, mod_td_ast, mod_imp_td, mod_fi_td, trans) + if mod_td_ty is not None and can == 1: + mt_arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) + if mt_arg_val is not None: + return self.Gen.CallGenCtor._translate_t_type_cast( + pool, builder, mt_arg_val, mod_td_ty, + func_name, cargs.get(0), trans) + + # 裸名 typedef 调用: BYTEPTR(ptr1), HANDLE(val), CHARPTR(str) 等 + # 用户通过 `from stdint import *` 导入 typedef 后,可直接用裸名做类型转换 + # map_t_type 包含所有内置 typedef 名称(BYTEPTR/HANDLE/LPCSTR/size_t 等) + # 泛型类型参数转换: 泛型上下文(类特化/泛型函数)中 T(x) → 先解析 T 为具体 + # 类型名(如 "int")再走 map_t_type(Box[int].__init__ 的 self.value = T(v)、 + # combine[T1,T2] 的 T1(b) 依赖此路径) + if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: + bare_fn_name: str = self.Gen.TypeGenBase.resolve_generic_type_name(func_name) + bare_ty: llvmlite.LLVMType | t.CPtr = None + # 泛型上下文解析出的内建名(如 T→"double"/"float"):map_t_type 只认 t.CDouble, + # 且 float 必须映射 t.CFloat(f32)而非 f64(与注解语义一致) + if string.strcmp(bare_fn_name, "double") == 0: + bare_ty = llvmlite.Double(pool) + elif string.strcmp(bare_fn_name, "float") == 0: + bare_ty = llvmlite.Float(pool) + else: + bare_ty = self.Gen.TypeGenResolve.map_t_type(pool, bare_fn_name) + # 泛型上下文替换出的类型名(如 T→"t.CInt")map_t_type 不识别(只认无前缀名), + # 回退用 resolve_annotation_type 解析(支持 t.CXxx / 结构体类名 / 别名等)。 + # GenericTest4 Box[t.CInt].__init__ 的 self.value = T(v) 依赖此路径。 + if bare_ty is None and string.strcmp(bare_fn_name, func_name) != 0: + gp_ast: ast.AST | t.CPtr = self.Gen.TypeGenResolve._parse_type_string(pool, bare_fn_name, 0) + if gp_ast is not None: + imp_gp: str = None + fi_gp: str = None + if trans is not None: + imp_gp = trans._imported_modules + fi_gp = trans._from_imports + bare_ty = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, gp_ast, imp_gp, fi_gp, trans) + # 泛型类型参数双参数形式: T(val, t.CPtr) → Ptr(T) + # (与 t.CInt(val, t.CPtr) → Ptr(i32) 对齐;vector.vp get() 的 + # typed_ptr = T(offset, t.CPtr) 依赖此路径,否则双参数不进 + # can==1 单参数分支 → 跌落到"裸名调用未定义"误报) + if bare_ty is not None and can == 2: + bare_arg2_node: ast.AST | t.CPtr = cargs.get(1) + bare_arg2_is_cptr: int = 0 + if bare_arg2_node is not None: + # 形式 1: t.CPtr(Attribute 形式) + if bare_arg2_node.kind() == ast.ASTKind.Attribute: + bare_arg2_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(bare_arg2_node) + if bare_arg2_at.attr is not None and string.strcmp(bare_arg2_at.attr, "CPtr") == 0: + if bare_arg2_at.value is not None and bare_arg2_at.value.kind() == ast.ASTKind.Name: + bare_arg2_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bare_arg2_at.value) + if bare_arg2_nm.id is not None and string.strcmp(bare_arg2_nm.id, "t") == 0: + bare_arg2_is_cptr = 1 + # 形式 2: 裸名 CPtr(from t import CPtr 后直接使用) + elif bare_arg2_node.kind() == ast.ASTKind.Name: + bare_arg2_bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bare_arg2_node) + if bare_arg2_bn.id is not None and string.strcmp(bare_arg2_bn.id, "CPtr") == 0: + bare_arg2_is_cptr = 1 + if bare_arg2_is_cptr != 0: + # CVoid* → i8*(LLVM 中 void* 表示为 i8*) + match bare_ty: + case llvmlite.LLVMType.Void(): + bare_ty = llvmlite.Int8(pool) + case _: + pass + bare_ty = llvmlite.Ptr(pool, bare_ty) + bare_arg_node: ast.AST | t.CPtr = cargs.get(0) + if bare_arg_node is not None: + bare_arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, bare_arg_node, None, 0, trans) + if bare_arg_val is not None: + return self.Gen.CallGenCtor._translate_t_type_cast( + pool, builder, bare_arg_val, bare_ty, + bare_fn_name, bare_arg_node, trans) + if bare_ty is not None and can == 1: + bare_arg_node: ast.AST | t.CPtr = cargs.get(0) + if bare_arg_node is not None: + bare_arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, bare_arg_node, None, 0, trans) + if bare_arg_val is not None: + return self.Gen.CallGenCtor._translate_t_type_cast( + pool, builder, bare_arg_val, bare_ty, + bare_fn_name, bare_arg_node, trans) + + return None + + def _tc_h5_sizeof_len_isinst(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT) -> llvmlite.Value | t.CPtr: + """__sizeof__/len/isinstance 内置(未命中返回 None)""" + # 检测 ClassName.__sizeof__() — 返回结构体大小常量(i64) + # __sizeof__ 是内置方法,不走跨模块调用路径 + # 支持: Argument.__sizeof__() 和 w32.win32file.WIN32_FIND_DATAA.__sizeof__() + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + sz_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if sz_at.attr is not None and string.strcmp(sz_at.attr, "__sizeof__") == 0: + if sz_at.value is not None and can == 0: + sz_cls_name: str = None + sz_vk: int = sz_at.value.kind() + if sz_vk == ast.ASTKind.Name: + sz_cls_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sz_at.value) + sz_cls_name = sz_cls_nm2.id + elif sz_vk == ast.ASTKind.Attribute: + sz_inner_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sz_at.value) + sz_cls_name = sz_inner_at.attr + # 最终解析出的结构体类型:类型名命中 → 泛型特化(Stack[T])→ 实例接收者类型(self/obj) + sz_resolved_ty: llvmlite.LLVMType | t.CPtr = None + sz_resolved_name: str = sz_cls_name + if sz_cls_name is not None: + # 泛型类型参数 T 替换: T.__sizeof__() → int.__sizeof__() + sz_cls_name = self.Gen.TypeGenBase.resolve_generic_type_name(sz_cls_name) + sz_resolved_name = sz_cls_name + # 去除模块前缀: Viper 解析器将 t.CInt 解析为 Name(id="t.CInt") + # 而非 Attribute(value=Name("t"), attr="CInt"),需要手动提取最后的类名分量 + # "t.CInt" → "CInt", "w32.win32file.WIN32_FIND_DATAA" → "WIN32_FIND_DATAA" + dot_pos: str = string.strrchr(sz_cls_name, '.') + if dot_pos is not None: + sz_cls_name = dot_pos + 1 + # 联合类型(如 AST|t.CPtr)按指针大小处理(8 字节) + # 联合类型在 TPV 中表示指针,可以指向多种类型 + # 对应 TPC 中对 BinOp/BitOr 联合类型的特殊处理 + if string.strstr(sz_cls_name, "|") is not None: + return llvmlite.const_int64(pool, 8) + # 内置类型 sizeof(int=4, str/bytes=8 指针, double=8 等) + sz_builtin: int = -1 + if string.strcmp(sz_cls_name, "int") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "str") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "bytes") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CInt") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "CInt8T") == 0: + sz_builtin = 1 + elif string.strcmp(sz_cls_name, "CInt16T") == 0: + sz_builtin = 2 + elif string.strcmp(sz_cls_name, "CInt32T") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "CInt64T") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CChar") == 0: + sz_builtin = 1 + elif string.strcmp(sz_cls_name, "CDouble") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CFloat") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "CPtr") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CSizeT") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CBool") == 0: + sz_builtin = 1 + elif string.strcmp(sz_cls_name, "bool") == 0: + sz_builtin = 1 + # 泛型 T 解析出的裸内建名(resolve_generic_type_name 返回 + # _infer_generic_ctor_type_arg 的输出,如 T→"double"/"float"): + # 缺省会让 sz_builtin=-1 → 落到"回退 2"把 Name(T) 当值翻译 → + # NameError(VectorGenericTest Vector[double].__init__ 回归根因) + elif string.strcmp(sz_cls_name, "double") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "float") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "char") == 0: + sz_builtin = 1 + if sz_builtin >= 0: + # 注意: 必须用 const_int64 而非 ConstInt(...,"0") + # ConstInt 的 name 参数是 IR 文本表示,ValuePrint 输出时使用 Name 而非 IntVal + # 硬编码 "0" 会导致 IR 输出 i64 0 而非实际值 + return llvmlite.const_int64(pool, sz_builtin) + sz_resolved_ty = self.Gen.StructGen.get_struct_type(sz_cls_name) + # 回退 1: 泛型类引用接收者 Stack[T].__sizeof__() — Subscript → 特化后计算大小 + # (GenericTest2 Stack.type_size 依赖此路径) + if sz_resolved_ty is None and trans is not None and sz_vk == ast.ASTKind.Subscript: + sub_sz: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sz_at.value) + if sub_sz.value is not None and sub_sz.value.kind() == ast.ASTKind.Name: + gen_nm_sz: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_sz.value) + if gen_nm_sz.id is not None: + gen_args_sz: list[str] | t.CPtr = self.Gen.CallGenCtor._extract_type_args_from_slice(pool, sub_sz.slice) + if gen_args_sz is not None and len(gen_args_sz) > 0: + gargs_resolved: list[str] | t.CPtr = list[str](pool, 8) + if gargs_resolved is not None: + gai_sz: t.CSizeT = len(gen_args_sz) + gai2_sz: t.CSizeT = 0 + for gai2_sz in range(gai_sz): + gres_sz: str = self.Gen.TypeGenBase.resolve_generic_type_name( + gen_args_sz.get(gai2_sz)) + gargs_resolved.append(gres_sz) + spec_sz: str = self.Gen.ClassGenGeneric._specialize_generic_class( + trans, gen_nm_sz.id, gargs_resolved) + if spec_sz is not None: + sz_resolved_name = spec_sz + sz_resolved_ty = self.Gen.StructGen.get_struct_type(spec_sz) + # 回退 2: 实例接收者 self.__sizeof__() / obj.__sizeof__() — 用接收者值的实际类型 + # (GenericTest2 Stack.size_of 依赖此路径;self 在方法内是 Ptr(Stack[int])) + # 数组变量接收者 bl_count.__sizeof__()(t.CArray[T, N] 变量)→ alloca + # 指针 Ptr([N x T]),算 N*elem_size(TPC _HandleSizeofLlvm 数组分支; + # zhuff.vp memset(bl_count, 0, bl_count.__sizeof__()) 依赖) + if sz_resolved_ty is None: + inst_sz_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, sz_at.value, None, 0, trans) + if inst_sz_val is not None and inst_sz_val.Ty is not None: + match inst_sz_val.Ty: + case llvmlite.LLVMType.Ptr(inst_inner_sz): + match inst_inner_sz: + case llvmlite.LLVMType.Struct(_, _, _): + sz_resolved_ty = inst_inner_sz + case llvmlite.LLVMType.Array(_, _): + sz_resolved_ty = inst_inner_sz + case _: + pass + case llvmlite.LLVMType.Struct(_, _, _): + sz_resolved_ty = inst_sz_val.Ty + case llvmlite.LLVMType.Array(_, _): + # 全局数组变量(模块级 t.CArray[T,N])translate_value + # 返回数组值 [N x T](非指针);局部数组返回 alloca + # 指针 Ptr([N x T]) 走上方 Ptr(Array) 分支。 + # pyzlib_error_msg.__sizeof__() 依赖(全局字符缓冲)。 + sz_resolved_ty = inst_sz_val.Ty + case _: + pass + if sz_resolved_ty is not None: + sz_val: int = self.Gen.ClassGenEnum._get_type_size(sz_resolved_ty) + if sz_val > 0: + return llvmlite.const_int64(pool, sz_val) + # 类型已注册但大小为 0(opaque struct 或字段链表未填充):Python 风格报错终止 + self.Gen.TypeGenErr.fatal_error( + sz_at, f"类型 '{sz_resolved_name}' 已注册但大小为 0(字段链表未填充),无法计算大小", + "TypeError") + # 类型未注册:Python 风格报错终止,不静默返回 0(会导致 malloc(0)/alloc(0) 堆溢出) + if sz_resolved_name is None: + sz_resolved_name = "(unknown)" + self.Gen.TypeGenErr.fatal_error( + sz_at, f"类型 '{sz_resolved_name}' 未在结构体表中注册,无法计算大小", + "TypeError") + + # 检测 len(obj) — 返回 list 对象的 __count__ 字段(偏移 8,i64) + # __len__ 是 list[T] 的内置方法,list 是泛型类不注册 struct + # 注意: 必须用 translate_value 而非 translate_name_value,因为 len_at.value + # 可能是 Attribute 节点(如 md_ags.args),translate_name_value 只处理 Name 节点, + # 对 Attribute 会错误返回 i32 0,导致 GEP base 不是指针(base of getelementptr must be a pointer) + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + len_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if len_at.attr is not None and string.strcmp(len_at.attr, "__len__") == 0: + if len_at.value is not None and can == 0: + obj_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, len_at.value, funcs_ptr, func_count, trans) + if obj_val is not None and obj_val.Ty is not None: + # 防御性类型检查: obj_val 必须是指针类型才能做 GEP + # 如果 translate_value 返回 i32 (如 CDefine 常量被误解析、 + # 模块属性前向引用回退为 i32),GEP base 会是 i32 而非指针, + # 导致 llc 报错 "base of getelementptr must be a pointer" + if self.Gen.ExprGenBase.is_ptr_type(obj_val.Ty) == 0: + # 类型推断失败(非指针/结构体):fail-fast,绝不返回 0 掩盖错误 + self.Gen.TypeGenErr.fatal_error( + len_at.value, "len() 参数类型推断失败(非指针/结构体)", "TypeError") + i64_ty_len: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + # 注意: 必须用 const_int64 而非 ConstInt(...,"0") + # ConstInt 的 name 参数 "0" 会被当作 IR 文本值输出 i64 0 + # 导致 GEP 索引为 0(访问 __data__)而非 1(访问 __count__) + idx_one: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) + count_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i64_ty_len, obj_val, idx_one) + if count_ptr is not None: + return llvmlite.build_load(builder, i64_ty_len, count_ptr) + + # 检测 len() 内置函数调用 — 结构体对象走 __len__ 方法,字符串走 strlen + # len(s) 对 str 类型调用 strlen,返回 i64 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: + if func_name is not None and string.strcmp(func_name, "len") == 0: + if can == 1: + len_arg_node: ast.AST | t.CPtr = cargs.get(0) + if len_arg_node is not None: + len_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, len_arg_node, None, 0, trans) + if len_val is not None: + # len(数组):t.CArray[T, N] → 常量 N(对齐 TPC + # _HandleLenLlvm 的 ArrayType.count 分支)。数组变量 + # translate_value 可能返回 Ptr([N x T])(alloca 指针) + # 或 [N x T] 值,两种都识别;否则会误走 strlen 把 + # 数组首元素当字符串读 → 垃圾长度。 + len_is_arr: int = 0 + len_arr_n: int = 0 + if len_val.Ty is not None: + if self.Gen.ExprGenBase.is_ptr_type(len_val.Ty) != 0: + len_ap: llvmlite.LLVMType | t.CPtr = len_val.Ty.Pointee + if len_ap is not None: + match len_ap: + case llvmlite.LLVMType.Array(_, len_arr_cnt): + len_is_arr = 1 + len_arr_n = len_arr_cnt + case _: + pass + else: + match len_val.Ty: + case llvmlite.LLVMType.Array(_, len_arr_cnt): + len_is_arr = 1 + len_arr_n = len_arr_cnt + case _: + pass + if len_is_arr != 0: + return llvmlite.const_int64(pool, len_arr_n) + # len(对象):有 __len__ 就调用,没有就编译期报错 + # (用户要求 2026-08-15,不再静默 strlen 读对象首字段): + # - list 泛型内置容器:__len__ 由 list 内置分支内联 + # (读 __count__,偏移 1),不生成方法函数 + # (_is_list_builtin_method,通用判断非特判) + # - 普通类:调用 {Class}.__len__ 函数 + # - 都没有:fatal_error + # str(Ptr(Int8))保持 strlen(内建语义)。 + len_struct_ty: llvmlite.LLVMType | t.CPtr = \ + self.Gen.StructGen.get_struct_type_from_value(len_val) + if len_struct_ty is not None: + len_cls_nm: str = self.Gen.StructGen.get_class_name_by_type( + pool, len_struct_ty) + if len_cls_nm is None: + self.Gen.TypeGenErr.fatal_error( + len_arg_node, "len() 参数类型推断失败(结构体类名未知)", + "TypeError") + # list 内置 __len__:读 __count__(GEP 偏移 1,i64) + if self.Gen.CallGenProp._is_list_builtin_method(len_cls_nm, "__len__") != 0: + i64_ty_lb: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + idx_one_lb: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) + cnt_ptr_lb: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i64_ty_lb, len_val, idx_one_lb) + if cnt_ptr_lb is not None: + return llvmlite.build_load(builder, i64_ty_lb, cnt_ptr_lb) + len_lookup: str = pool.alloc(128) + if len_lookup is not None: + viperlib.snprintf(len_lookup, 128, "%s.__len__", len_cls_nm) + len_fn2: llvmlite.Function | t.CPtr = self.find_func_in_module( + mod, len_lookup) + if len_fn2 is not None: + len_ret_ty2: llvmlite.LLVMType | t.CPtr = \ + llvmlite.function_get_ret_ty(len_fn2) + len_fn_name2: str = \ + llvmlite.function_get_name(len_fn2) + if len_ret_ty2 is not None and len_fn_name2 is not None: + # self 参数类型对齐(按方法首个形参 bitcast) + len_self_arg2: llvmlite.Value | t.CPtr = len_val + len_first_param2: llvmlite.Param | t.CPtr = \ + llvmlite.function_get_param_head(len_fn2) + if len_first_param2 is not None: + len_self_ty2: llvmlite.LLVMType | t.CPtr = \ + llvmlite.param_get_ty(len_first_param2) + if len_self_ty2 is not None and len_val.Ty is not None: + len_self_arg2 = llvmlite.build_bitcast( + builder, len_val, len_self_ty2) + len_self_arg2.Next = None + return llvmlite.build_call( + builder, len_fn_name2, len_self_arg2, + 1, len_ret_ty2, 0) + # len_fn2 未命中(跨模块方法):如 ndarray[t.CDouble].__len__ + # 定义在 numpy——泛型特化方法无 stub declare,find_func_in_module + # 后缀匹配查不到。用结构体所属模块 sha1 构造 + # {sha1}.{cls}.__len__ 精确调用名(对齐 _translate_method_call + # 跨模块调用名构造),返回类型从 text.ll/vpi 精确解析, + # _ensure_method_declare 建 declare 后调用。 + len_cls_sha1_x: str = self.Gen.StructGen.get_struct_sha1(len_cls_nm) + if len_cls_sha1_x is not None: + # 缓冲区需容纳 "{sha1}.{cls}.__len__": + # 2 个点 + "__len__"(7) + NUL = 10;+8 会截断 + # 末两位 → 符号变 ".__len" 链接 undefined + # (NumpyTest test_len 链接错误根因) + len_ml_x: t.CSizeT = string.strlen(len_cls_sha1_x) \ + + string.strlen(len_cls_nm) + 10 + len_mangled_x: str = pool.alloc(len_ml_x) + if len_mangled_x is not None: + viperlib.snprintf(len_mangled_x, len_ml_x, + "%s.%s.__len__", len_cls_sha1_x, len_cls_nm) + len_ret_x: llvmlite.LLVMType | t.CPtr = \ + self._LookupMethodRetTyFromTextLL( + pool, len_cls_sha1_x, len_cls_nm, "__len__") + if len_ret_x is None: + len_ret_x = self._lookup_method_ret_ty_via_vpi( + pool, len_cls_sha1_x, len_cls_nm, "__len__") + if len_ret_x is not None: + # self 参数按对象实际类型 Ptr(len_struct_ty)(与定义侧 + # 同名类型链接匹配);len_val 已是 load 后的对象指针。 + # Value 链直接作 param_head(同跨模块调用模式)。 + len_self_x: llvmlite.Value | t.CPtr = len_val + len_self_x.Next = None + self._ensure_method_declare( + pool, mod, len_mangled_x, len_ret_x, + len_self_x, 1) + return llvmlite.build_call( + builder, len_mangled_x, len_self_x, + 1, len_ret_x, 0) + # fail-fast:类没有 __len__(用户要求编译期报错) + self.Gen.TypeGenErr.fatal_error( + len_arg_node, + f"len() 参数类型 '{len_cls_nm}' 没有 __len__ 方法", + "TypeError") + # 非结构体:str(Ptr(Int8))走 strlen;其它类型 fail-fast + len_arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(len_val) + len_is_str: int = 0 + if len_arg_ty is not None and self.Gen.ExprGenBase.is_ptr_type(len_arg_ty) != 0: + match len_arg_ty: + case llvmlite.LLVMType.Ptr(len_pt_ty): + if len_pt_ty is not None: + match len_pt_ty: + case llvmlite.LLVMType.Int(len_pt_bits): + if len_pt_bits == 8: + len_is_str = 1 + case _: + pass + case _: + pass + if len_is_str != 0: + # 确保 strlen 在模块中有声明 + strlen_fn: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, "strlen") + if strlen_fn is None: + i64_ty_ln: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i8_ptr_ty_ln: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + strlen_fn = llvmlite.create_declare(pool, mod, "strlen", i64_ty_ln) + if strlen_fn is not None: + llvmlite.add_param(pool, strlen_fn, i8_ptr_ty_ln, "s") + # 参数类型转换为 i8* + i8_ptr_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + len_coerced: llvmlite.Value | t.CPtr = len_val + if self.Gen.ExprGenBase.is_ptr_type(len_arg_ty) != 0: + len_coerced = llvmlite.build_bitcast(builder, len_val, i8_ptr_ty_ln2) + # 构建单参数链表并调用 strlen + len_coerced.Next = None + i64_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + return llvmlite.build_call(builder, "strlen", len_coerced, 1, i64_ty_ln2, 0) + # fail-fast:非字符串/数组/对象,无法求长度 + self.Gen.TypeGenErr.fatal_error( + len_arg_node, "len() 参数类型不支持(非字符串/数组/对象)", + "TypeError") + + # 检测 isinstance() 内置函数调用 — 运行时 vtable 子类集合比较 + # isinstance(obj, Cls):obj 头部 vtable 指针 ∈ {Cls 及全部子类 vtable}; + # NoVTable 目标类回退编译时静态判断(详见 _translate_isinstance)。 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: + if func_name is not None and string.strcmp(func_name, "isinstance") == 0: + if can >= 2: + is_res: llvmlite.Value | t.CPtr = self.Gen.CallGenLeafKit._translate_isinstance( + pool, builder, mod, cargs.get(0), cargs.get(1), trans) + if is_res is not None: + return is_res + + return None + + def _tc_h6_method_dispatch(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + hit_box: t.CPtr = None) -> llvmlite.Value | t.CPtr: + """静态类/方法调用/表达式接收者/self.field/list 内置(未命中返回 None) + + hit_box: 命中标记(t.CPtr,[0]=1 表示已识别为方法调用路径)。 + 编译器生成方法(如 __before_init__/__init__)恒返回 void, + _translate_method_call 处理后返回 None(无返回值)——若不标记, + translate_call 会误判"未命中"继续走跨模块函数路径(把对象名 + 当模块名查 SHA1 → "跨模块调用 'buf.__before_init__' 找不到模块 SHA1")。 + """ + # 检测类名静态/类方法调用: ClassName.method(args) + # 当 cl.func 是 Attribute、value 是已注册结构体类名(非普通变量)时, + # 且方法带 @staticmethod/@classmethod 元数据,走静态调用路径 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + st_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if st_at is not None and st_at.value is not None and trans is not None: + if st_at.value.kind() == ast.ASTKind.Name: + st_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(st_at.value) + if st_nm.id is not None: + # 仅当该名称不是普通变量且是已注册结构体类名时尝试静态/类方法 + # 追加"非导入模块"条件:st_nm.id 是模块名(import X as Y 把别名 + # Y 加入 _imported_modules,HandlesImports L344-347)时,X.Y(...) + # 是模块限定调用(Module.Class 构造 / Module.func 函数),不是 + # ClassName.method(obj,args)。模块名与类名同名时(CompilerFactory. + # CompilerFactory(...) 构造 / .set_factory(...) 函数,main.vp + # 追加84/84b 根因)get_struct_type(st_nm.id) 会误判为类名 → + # 把首实参当 self 传 _call_method_on_ptr → 返回类型查 "X.Y" 永远 + # 落空 → fail-fast。模块限定调用由尾部 ctor 检测(L7441 模块限定 + # 构造)与跨模块函数路径正确路由。 + st_var: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, st_nm.id) + if st_var is None and self.Gen.StructGen.get_struct_type(st_nm.id) is not None \ + and self.Gen.ImportsGen.is_module_imported( + trans._imported_modules, st_nm.id) == 0: + # REnum 变体构造优先于静态/类方法调用: + # ClassName.VariantName(args)(如 Option.Some(42))若被当 + # "实例方法经类名调用"处理,会把首实参 42 当 self 传 + # _call_method_on_ptr → 查 "Option.Some" 方法返回类型 → + # 跨模块 stub 未命中 → fail-fast(EnumTest "方法 + # 'Option.Some' 返回类型无法确定" 根因)。REnum 变体 + # 构造检测原在 translate_call 尾部(L7493),被本分支 + # 拦截先执行不到,此处提前检测。 + if self.Gen.ClassGenEnum._is_renum_class_name(st_nm.id) != 0: + rc_tag_sc: int = self.Gen.ClassGenEnum._lookup_renum_variant_in_class( + st_nm.id, func_name) + if rc_tag_sc >= 0: + return self.Gen.CallGenCtor._translate_renum_construct( + pool, builder, mod, st_nm.id, func_name, + rc_tag_sc, cargs, can, trans) + st_res: llvmlite.Value | t.CPtr = self.Gen.CallGenProp._translate_static_class_call( + pool, builder, mod, st_nm.id, func_name, cl, trans) + if st_res is not None: + return st_res + # 实例方法经类名调用: ClassName.method(obj, args) → obj.method(args) + # (Python 语义,首参是 self 对象;zdeflate.vp + # zdeflate_stream.find_match(s, data, ...) 根因:_translate_ + # static_class_call 对非静态方法返回 None 后,ClassName 被 + # 通用路径当模块名 → "跨模块调用找不到模块 SHA1") + # st_nm.id == func_name(类名==方法名,如 CompilerFactory. + # CompilerFactory(...))不是实例方法调用而是构造调用: + # 模块名与类名同名时本分支把模块限定类构造误判为 + # ClassName.method(obj,args),首实参当 self 传 → + # _call_method_on_ptr 查 "X.X" 返回类型永远落空 → + # fail-fast(main.vp CompilerFactory 追加84 根因)。 + # 跳过本分支,落到 translate_call 尾部的 ctor 检测 + # (L7426 模块限定类构造 find_struct_by_module 正确路由)。 + if can >= 1 and cargs is not None \ + and string.strcmp(st_nm.id, func_name) != 0: + im_self: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cargs.get(0), None, 0, trans) + if im_self is not None: + im_rem: t.CSizeT | t.CPtr = None + if can >= 2: + im_rem = pool.alloc(t.CSizeT(can - 1) * 8) + if im_rem is not None: + ri_im: t.CSizeT + for ri_im in range(can - 1): + im_rv: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cargs.get(ri_im + 1), None, 0, trans) + if im_rv is not None: + im_rem[ri_im] = t.CSizeT(im_rv) + im_res: llvmlite.Value | t.CPtr = self.Gen.CallGenCall._call_method_on_ptr( + pool, builder, mod, st_nm.id, func_name, + im_self, im_rem, can - 1, trans) + if im_res is not None: + return im_res + elif st_at.value.kind() == ast.ASTKind.Attribute: + # 模块限定静态调用: module.ClassName.static_method(args) + # cl.func = Attribute(value=Attribute(value=Name(module), + # attr=ClassName), attr=method_name) + # 此前未检测 → 走通用路径把 method_name 当裸函数解析, + # 生成 call i32 @from_long(无类名/SHA1 前缀)→ 链接 + # undefined reference(CPythonTest PyLongObj.from_long 根因) + st_at2: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(st_at.value) + if st_at2 is not None and st_at2.attr is not None and st_at2.value is not None: + if st_at2.value.kind() == ast.ASTKind.Name: + # ClassName 是已注册结构体类名时尝试静态/类方法 + if self.Gen.StructGen.get_struct_type(st_at2.attr) is not None: + st_res2: llvmlite.Value | t.CPtr = self.Gen.CallGenProp._translate_static_class_call( + pool, builder, mod, st_at2.attr, func_name, cl, trans) + if st_res2 is not None: + return st_res2 + + # 检测方法调用: obj.method(args) + # 当 cl.func 是 Attribute 且 obj 是已注册的结构体变量时,翻译为方法调用 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if method_at is not None and method_at.value is not None: + if method_at.value.kind() == ast.ASTKind.Name and trans is not None: + method_obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(method_at.value) + if method_obj_nm.id is not None: + # 查找对象变量 + obj_var: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, method_obj_nm.id) + if obj_var is not None and obj_var.Ty is not None: + # 检查是否为 Ptr(Struct(...))(结构体值变量) + # 或 Ptr(Ptr(Struct(...)))(指针变量,需 load) + match obj_var.Ty: + case llvmlite.LLVMType.Ptr(obj_struct_ty): + class_nm: str = self.Gen.StructGen.get_class_name_by_type( + pool, obj_struct_ty) + if class_nm is not None: + # list 泛型内置容器方法(append/get/set/pop/clear/__iter__/ + # __len__/__getitem__/__setitem__)由下方 list 内置分支 + # (L5848 起)内联 GEP 处理,不注册方法函数;若走 + # _translate_method_call 会查 append 返回类型(函数/text.ll/ + # vpi stub 均未命中)→ fail-fast。检测到 list 方法时 + # 跳过 method_call,落到内置分支(NewAstTest body.append 根因)。 + if self.Gen.CallGenProp._is_list_builtin_method(class_nm, func_name) == 0: + if hit_box is not None: + hit_box[0] = 1 + return self.Gen.CallGenCall._translate_method_call( + pool, builder, mod, class_nm, func_name, + obj_var, cl, trans) + # 指针变量: alloca 类型是 Ptr(Ptr(Struct)) + # load 获取实际指针 Ptr(Struct) 后再查找 + match obj_struct_ty: + case llvmlite.LLVMType.Ptr(inner_struct_ty): + inner_nm: str = self.Gen.StructGen.get_class_name_by_type( + pool, inner_struct_ty) + if inner_nm is not None: + # list 内置方法同样跳过(同 Ptr(Struct) 分支) + if self.Gen.CallGenProp._is_list_builtin_method(inner_nm, func_name) == 0: + obj_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, obj_struct_ty, obj_var) + if obj_ptr is not None: + if hit_box is not None: + hit_box[0] = 1 + return self.Gen.CallGenCall._translate_method_call( + pool, builder, mod, inner_nm, func_name, + obj_ptr, cl, trans) + # FakeDuck: str/bytes 变量(Ptr(i8),AnnotClassName 为空) + # 方法调用 → 扩展类 _Type/_str(a.type_id() / a.upper())。 + # 前置拦截:常规结构体方法分支全落空时,尝试扩展类方法 + # (find_func_in_module 未命中返回 None,不影响正常路径)。 + fd_name_res: llvmlite.Value | t.CPtr = self.Gen.CallGenFd._translate_fakeduck_call( + pool, builder, mod, None, func_name, cl, trans) + if fd_name_res is not None: + return fd_name_res + # AnnotClassName 回退:联合类型简化为 Ptr(i8) 时, + # 通过原始类型注解的类名查找结构体 + var_entry: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, method_obj_nm.id) + if var_entry is not None and var_entry.AnnotClassName is not None: + annot_val: str = var_entry.AnnotClassName + # 解析模块限定名 "memhub.MemBuddy" → mod_nm="memhub", cls_nm="MemBuddy" + dot_ptr: str = string.strrchr(annot_val, '.') + cls_nm2: str = annot_val + mod_nm2: str = None + if dot_ptr is not None: + cls_nm2 = dot_ptr + 1 + total_len_av: t.CSizeT = string.strlen(annot_val) + cls_len_av: t.CSizeT = string.strlen(cls_nm2) + mod_len2: t.CSizeT = total_len_av - cls_len_av - 1 + mod_nm2 = pool.alloc(mod_len2 + 1) + if mod_nm2 is not None: + string.strncpy(mod_nm2, annot_val, mod_len2) + mod_nm2[mod_len2] = '\0' + # 检查结构体是否已注册 + if self.Gen.StructGen.get_struct_type(cls_nm2) is not None: + # list 内置方法跳过 method_call(同 Ptr(Struct) 分支), + # 落到下方 list 内置分支 + if self.Gen.CallGenProp._is_list_builtin_method(cls_nm2, func_name) == 0: + # 结构体已注册:load obj_ptr 走方法调用 + i8_ptr_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + obj_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i8_ptr_ty2, obj_var) + if obj_ptr2 is not None: + if hit_box is not None: + hit_box[0] = 1 + return self.Gen.CallGenCall._translate_method_call( + pool, builder, mod, cls_nm2, func_name, + obj_ptr2, cl, trans) + else: + # list 内置方法跳过(结构体未注册路径同样不能 + # 构造 {sha1}.{cls}.append 调用名——list 方法无此函数) + if self.Gen.CallGenProp._is_list_builtin_method(cls_nm2, func_name) == 0: + # FakeDuck: str 变量方法调用 → 扩展类 _Type/_str + # a.type_id() / a.upper() / " ".isspace() 等 + # AnnotClassName=="str" 且对象是 char* 时触发, + # self 用影子结构体 {a}__meta__(或临时影子)。 + fd_res: llvmlite.Value | t.CPtr = self.Gen.CallGenFd._translate_fakeduck_call( + pool, builder, mod, cls_nm2, func_name, cl, trans) + if fd_res is not None: + return fd_res + # 结构体未注册(跨模块依赖未翻译): + # 用模块名查 SHA1 构造方法调用名 + sha1_fc: str = None + if mod_nm2 is not None: + sha1_fc = self._lookup_module_sha1(mod_nm2) + if sha1_fc is not None: + # 构造 "{sha1}.{cls_nm2}.{func_name}" 调用名 + mlen3: t.CSizeT = string.strlen(sha1_fc) + string.strlen(cls_nm2) + string.strlen(func_name) + 3 + mangled3: str = pool.alloc(mlen3) + if mangled3 is not None: + viperlib.snprintf(mangled3, mlen3, "%s.%s.%s", sha1_fc, cls_nm2, func_name) + # load obj_ptr (self) + i8_ptr_ty3: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + obj_ptr3: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i8_ptr_ty3, obj_var) + if obj_ptr3 is not None: + # 构建参数链表: obj_ptr3 (self) → 其他参数 + llvmlite.value_set_next(obj_ptr3, None) + head3: llvmlite.Value | t.CPtr = obj_ptr3 + tail3: llvmlite.Value | t.CPtr = obj_ptr3 + for ai3 in range(can): + arg3: ast.AST | t.CPtr = cargs.get(ai3) + if arg3 is not None: + arg_val3: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg3, None, 0, trans) + if arg_val3 is not None: + llvmlite.value_set_next(arg_val3, None) + llvmlite.value_set_next(tail3, arg_val3) + tail3 = arg_val3 + total3: int = 1 + can + ret_ty3: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty( + pool, cls_nm2, func_name) + if ret_ty3 is None: + ret_ty3 = self._LookupMethodRetTyFromTextLL( + pool, sha1_fc, cls_nm2, func_name) + if ret_ty3 is None: + # 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单) + ret_ty3 = self._lookup_method_ret_ty_via_vpi( + pool, sha1_fc, cls_nm2, func_name) + if ret_ty3 is None: + # 本分支仅在"注解类结构体未注册"时到达(L6932 else): + # 类未注册 → 无法沿 MRO 解析 Mixin 方法定义模块。 + # 例如 g 注解 Generator.Generator,但 _register_cdefine_from_value + # 定义在 AssignGenMixin.vp——其 text.ll 的 define 名是 + # {AssignGenMixin_sha1}.AssignGenMixin.xxx,查 + # {Generator_sha1}.Generator.xxx 永远落空(追加80d 根因; + # sha1_fc 存在 + text.ll 存在仍查不到,固定 256KB 截断 + # 只是次要因素)。必须标记 pending:等 Generator 注册后 + # 下遍走 L6919 已注册分支 → _translate_method_call 沿 + # MRO 链找到 AssignGenMixin → 精确解析。真正不存在的 + # 类/方法由 Phase A 收敛检查兜底,绝不在此 fail-fast + # 中断多遍收敛(对齐追加77/77b 类 defer 原则)。 + if trans is not None: + trans._deps_pending = 1 + # 依赖未就绪:保持默认 i32(build_call(Void) + # 返回 None 破坏表达式翻译;本遍不写盘) + ret_ty3 = llvmlite.Int32(pool) + self._ensure_method_declare(pool, mod, mangled3, ret_ty3, head3, total3) + return llvmlite.build_call(builder, mangled3, head3, total3, ret_ty3, 0) + else: + # 编译器生成特殊方法放行(__before_init__/__init__ 等): + # 结构体未注册 + 模块 SHA1 均不可查(Phase A 依赖未就绪)时, + # 方法返回类型由编译器确定性定义(_special_method_ret_ty), + # 不依赖结构体注册即可精确解析。走 _translate_method_call 处理 + # (内部含 _special_method_ret_ty + mc_entry/类型名 SHA1 提取), + # 绝不掉出返回 None 让 translate_call 把对象名当模块名 + # 报"跨模块调用 'buf.__before_init__' 找不到模块 SHA1" + # (memhub.alloc_buf buf.__before_init__() 根因)。 + sp_ty4: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty( + pool, cls_nm2, func_name) + if sp_ty4 is not None: + i8_ptr_ty4: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + obj_ptr4: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i8_ptr_ty4, obj_var) + if obj_ptr4 is not None: + if trans is not None: + trans._deps_pending = 1 + if hit_box is not None: + hit_box[0] = 1 + return self.Gen.CallGenCall._translate_method_call( + pool, builder, mod, cls_nm2, func_name, + obj_ptr4, cl, trans) + + # ============================================================ + # 检测表达式接收者方法调用: (expr).method(args) + # + # 当 method_at.value 是 BinOp/Subscript/Call 等非 Name/Attribute 表达式时 + # (如 (a + b).dot(c)、(v1 + v2) * 3.0),先 translate_value 求值接收者, + # 再从值的 LLVM 类型(Ptr(Struct))解析类名,走方法调用路径。 + # ============================================================ + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + expr_method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if expr_method_at is not None and expr_method_at.value is not None and trans is not None: + evk: int = expr_method_at.value.kind() + # Attribute 接收者区分两种形态: + # 1. 模块限定路径(os._win32.exists / w32.fileio.fn)——根名是已导入 + # 模块或 t/c,留给下方跨模块限定路径处理 + # 2. 字段链表达式接收者(self.writer.write_bits / self.pool.alloc) + # ——根名是对象(self/局部变量),必须走本方法调用路径; + # 否则被模块限定路径误判 xmod_path="self.writer" → "找不到模块 + # SHA1"(zdeflate.vp write_fixed_block 根因) + is_mod_path_expr: int = 0 + if evk == ast.ASTKind.Attribute: + expr_root: ast.AST | t.CPtr = expr_method_at.value + while expr_root is not None and expr_root.kind() == ast.ASTKind.Attribute: + expr_root = (ast.Attribute | t.CPtr)(expr_root).value + if expr_root is not None and expr_root.kind() == ast.ASTKind.Name: + expr_root_nm: str = (ast.Name | t.CPtr)(expr_root).id + if expr_root_nm is not None: + if string.strcmp(expr_root_nm, "t") == 0 or \ + string.strcmp(expr_root_nm, "c") == 0: + is_mod_path_expr = 1 + elif trans._imported_modules is not None: + if self.Gen.ImportsGen.is_module_imported( + trans._imported_modules, expr_root_nm) != 0: + is_mod_path_expr = 1 + if evk != ast.ASTKind.Name and is_mod_path_expr == 0: + # 翻译接收者表达式(求值结果应为 Ptr(Struct)) + expr_obj: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, expr_method_at.value, funcs_ptr, func_count, trans) + if expr_obj is not None and expr_obj.Ty is not None: + expr_cls_nm: str = None + # 递归解 Ptr:识别 X|t.CPtr 联合简化的 Ptr(Ptr(Struct)) + # (如 (a*2.0 - b) 中 __mul__ 返回 Vec3**),否则方法 + # 调用被当裸函数 @dot 解析 → 链接 undefined symbol + expr_struct_ty: llvmlite.LLVMType | t.CPtr = \ + self.Gen.StructGen.get_struct_type_from_value(expr_obj) + if expr_struct_ty is not None: + expr_cls_nm = self.Gen.StructGen.get_class_name_by_type( + pool, expr_struct_ty) + # 回退:LLVM 类型为 Ptr(i8)(方法返回 X|t.CPtr 无类型信息)时, + # 从接收者表达式结构推断类名(链式调用 c2.scale(2.0).move(...) + # 的 scale 返回 Ptr(i8),经 infer_expr_class → vpi 返回注解) + # 跨 Mixin 不能 self 调用 ExprGenMixin 方法,经全局单例 + if expr_cls_nm is None: + expr_cls_nm = self.Gen.ExprGenCls.infer_expr_class( + pool, mod, expr_method_at.value, trans) + if expr_cls_nm is not None: + # 值类型接收者(内嵌 struct 字段,如 zdeflate s.writer 值字段): + # 方法调用 self 必须传字段地址(GEP)而非 load 出的结构体值, + # 否则结构体值(40B)塞进 zbit_writer* 参数 → ABI 错配 → + # 被调方把值当 this 指针解引用 → GEP 0x18 崩溃 + # (s.writer.write_zlib_header 运行时 access-violation 根因; + # 本路径 evk=Attribute 先于 self.field.method() 分支命中)。 + expr_is_ptr: int = 0 + match expr_obj.Ty: + case llvmlite.LLVMType.Ptr(expr_ptr_inner): + expr_is_ptr = 1 + case _: + expr_is_ptr = 0 + if expr_is_ptr == 0: + expr_addr: llvmlite.Value | t.CPtr = self.Gen.ExprGenAttr.get_attribute_ptr( + builder, pool, mod, expr_method_at.value, trans) + if expr_addr is not None: + expr_obj = expr_addr + if hit_box is not None: + hit_box[0] = 1 + return self.Gen.CallGenCall._translate_method_call( + pool, builder, mod, expr_cls_nm, func_name, + expr_obj, cl, trans) + # FakeDuck: 表达式接收者解析失败且对象是 char* 时 + # (如 " ".isspace()),尝试扩展类 _Type/_str 方法 + # (self 用临时影子,对齐 TPC L2858-2873) + fd_expr_res: llvmlite.Value | t.CPtr = self.Gen.CallGenFd._translate_fakeduck_call( + pool, builder, mod, None, func_name, cl, trans) + if fd_expr_res is not None: + return fd_expr_res + + # ============================================================ + # 检测 self.field.method() 调用 + # + # 当 method_at.value 是 Attribute(字段访问,如 self.__pool__)时, + # 翻译字段值获取对象指针,然后走方法调用路径。 + # + # 路径1: 从字段值的 LLVM 类型获取类名(字段类型为 Ptr(Struct("MemManager"))) + # 路径2: 从字段的 AnnotClassName 回退查找(字段类型被简化为 Ptr(i8) 时) + # ============================================================ + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + attr_method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if attr_method_at is not None and attr_method_at.value is not None: + if attr_method_at.value.kind() == ast.ASTKind.Attribute and trans is not None: + inner_attr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(attr_method_at.value) + if inner_attr is not None and inner_attr.attr is not None: + # 翻译 self.__pool__ 获取字段值(已 load 的对象指针) + field_obj: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, attr_method_at.value, funcs_ptr, func_count, trans) + if field_obj is not None and field_obj.Ty is not None: + field_cls_nm: str = None + # 路径1: 从字段值的 LLVM 类型获取类名 + match field_obj.Ty: + case llvmlite.LLVMType.Ptr(field_struct_ty): + field_cls_nm = self.Gen.StructGen.get_class_name_by_type( + pool, field_struct_ty) + # 路径2: 从字段注解类名回退查找 + if field_cls_nm is None: + if inner_attr.value is not None and inner_attr.value.kind() == ast.ASTKind.Name: + inner_name_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner_attr.value) + if inner_name_node is not None and inner_name_node.id is not None: + inner_var: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, inner_name_node.id) + if inner_var is not None and inner_var.Ty is not None: + match inner_var.Ty: + case llvmlite.LLVMType.Ptr(field_owner_struct_ty): + field_info: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field( + field_owner_struct_ty, inner_attr.attr) + if field_info is not None: + field_annot: str = self.Gen.StructGen.get_field_annot_class_name(field_info) + if field_annot is not None: + dot_p: str = string.strrchr(field_annot, 46) + if dot_p is not None: + field_cls_nm = dot_p + 1 + else: + field_cls_nm = field_annot + if field_cls_nm is not None: + # 值类型字段(内嵌 struct,如 zdeflate_stream.writer: zbit_writer) + # 方法调用 self 必须传字段地址(GEP),而非 load 出的结构体值: + # 传值给 stub 声明/define 的 zbit_writer* 参数 → ABI 错配, + # 被调方把结构体值前 8 字节当 this 指针解引用 → GEP 0x18 崩溃 + # (zdeflate s.writer.write_zlib_header 运行时 access-violation 根因)。 + is_val_field: int = 0 + match field_obj.Ty: + case llvmlite.LLVMType.Ptr(field_ptr_inner): + is_val_field = 0 + case _: + is_val_field = 1 + if is_val_field != 0: + field_addr: llvmlite.Value | t.CPtr = self.Gen.ExprGenAttr.get_attribute_ptr( + builder, pool, mod, attr_method_at.value, trans) + if field_addr is not None: + field_obj = field_addr + if hit_box is not None: + hit_box[0] = 1 + return self.Gen.CallGenCall._translate_method_call( + pool, builder, mod, field_cls_nm, func_name, + field_obj, cl, trans) + + # ============================================================ + # 检测 list 内置方法调用: lst.get(i), lst.set(i,v), lst.pop(), lst.clear(), lst.__iter__() + # list[T] 是泛型类不注册 struct,方法调用处理器(上方)无法处理, + # 需要在此特殊处理。 + # list 结构布局 (6 字段 × 8 字节): + # __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40) + # ============================================================ + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + lm_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if lm_at is not None and lm_at.attr is not None and lm_at.value is not None: + lm_name: str = lm_at.attr + # 判断是否是 list 方法名 + lm_is_list: int = 0 + if string.strcmp(lm_name, "get") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "__getitem__") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "set") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "__setitem__") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "pop") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "clear") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "__iter__") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "append") == 0: lm_is_list = 1 + + if lm_is_list == 1 and trans is not None: + # 翻译 list 对象 + lm_obj: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, lm_at.value, funcs_ptr, func_count, trans) + if lm_obj is not None: + # 防御性类型检查: lm_obj 必须是指针类型才能做 GEP + # translate_value 对某些 Attribute 节点(如 ast.Arguments 的属性) + # 可能返回 i32 0 (非指针),直接 GEP 会导致 + # "base of getelementptr must be a pointer" 错误 + if lm_obj.Ty is None or self.Gen.ExprGenBase.is_ptr_type(lm_obj.Ty) == 0: + # translate_value 类型推断失败(目标对象非指针): + # fail-fast,绝不 VLogger.critical 后 return None 静默吞掉 + self.Gen.TypeGenErr.fatal_error( + lm_at.value, f"list 方法 '{lm_name}' 目标对象非指针", "TypeError") + # list 对象类型确认(额外搜索路径):list 内置分支仅按方法名 + # 判断(get/set/__getitem__ 等非 list 专有),须确认对象确实 + # 是 list——从对象结构体名匹配 "list"。明确非 list(如 dict / + # 普通类未注册场景)跳过本分支,避免按 list 布局 GEP 生成 + # 错误 IR(dict 的 get 被当 list.get 按 __data__/__elem_size__ + # 偏移读写垃圾)。 + lm_conf_ty: llvmlite.LLVMType | t.CPtr = \ + self.Gen.StructGen.get_struct_type_from_value(lm_obj) + lm_conf_nm: str = None + if lm_conf_ty is not None: + lm_conf_nm = llvmlite.get_struct_name(lm_conf_ty) + if lm_conf_nm is not None and \ + string.strstr(lm_conf_nm, "list") is None: + return None + # list 内置分支命中标记:void 方法(set/clear)成功处理后返回 + # None,必须置位 hit_box 区分"已识别为 list 方法路径",否则 + # translate_call 误判未命中继续走跨模块函数路径,把对象名当 + # 模块名查 SHA1 → "跨模块调用 'nums.set' 找不到模块 SHA1" + # (ListTest main.vp nums.set(1,99) 根因;对齐 _translate_method_call + # 调用点的 hit_box 置位模式)。 + if hit_box is not None: + hit_box[0] = 1 + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + # 元素类型 T:从 list 特化类型名解析(list[int]→i32、 + # list[str]→i8*、未知/指针元素→i8*)。此前 get/set/pop + # 固定 i8*(8 字节)读写:set 的 8 字节 store 覆盖相邻元素 + # (inttoptr 值,如 set(1,99) 把 data[8..11] 的 30 清 0), + # pop 读回 0 → ListTest "pop FAILED expect 30" 根因。 + # subscript 路径(list_getitem_inline 调用方)已用 + # _list_elem_type_from_name 修正,方法调用路径漏改。 + lm_esty: llvmlite.LLVMType | t.CPtr = \ + self.Gen.StructGen.get_struct_type_from_value(lm_obj) + lm_ename: str = None + if lm_esty is not None: + lm_ename = llvmlite.get_struct_name(lm_esty) + lm_elem_ty: llvmlite.LLVMType | t.CPtr = None + if lm_ename is not None: + lm_elem_ty = self.Gen.ExprGenName._list_elem_type_from_name( + pool, lm_ename) + if lm_elem_ty is None: + lm_elem_ty = i8_ptr_ty + + # get / __getitem__: 返回 index 处的元素 + if string.strcmp(lm_name, "get") == 0 or string.strcmp(lm_name, "__getitem__") == 0: + if can >= 1: + # 加载 __data__ (偏移 0) + g_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + g_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0) + g_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, g_dpp) + # 加载 __elem_size__ (偏移 32, index 4) + g_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) + g_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4) + g_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, g_epp) + # 翻译 index + g_idx_node: ast.AST | t.CPtr = cargs.get(0) + g_idx_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, g_idx_node, None, 0, trans) + if g_data is not None and g_esize is not None and g_idx_val is not None: + g_idx_i64: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type( + builder, g_idx_val, i64_ty, g_idx_node) + g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize) + g_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, g_data, g_offset) + if g_addr is not None: + g_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, g_addr, llvmlite.Ptr(pool, lm_elem_ty)) + if g_ep is not None: + return llvmlite.build_load(builder, lm_elem_ty, g_ep) + + # set / __setitem__: 设置 index 处的元素 + elif string.strcmp(lm_name, "set") == 0 or string.strcmp(lm_name, "__setitem__") == 0: + if can >= 2: + s_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + s_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0) + s_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, s_dpp) + s_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) + s_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4) + s_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, s_epp) + s_idx_node: ast.AST | t.CPtr = cargs.get(0) + s_val_node: ast.AST | t.CPtr = cargs.get(1) + s_idx_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, s_idx_node, None, 0, trans) + s_val_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, s_val_node, None, 0, trans) + if s_data is not None and s_esize is not None and s_idx_val is not None and s_val_val is not None: + s_idx_i64: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type( + builder, s_idx_val, i64_ty, s_idx_node) + s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize) + s_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s_data, s_offset) + if s_addr is not None: + s_val_elem: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type( + builder, s_val_val, lm_elem_ty, s_val_node) + s_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, s_addr, llvmlite.Ptr(pool, lm_elem_ty)) + if s_ep is not None: + llvmlite.build_store(builder, s_val_elem, s_ep) + return None + + # pop: 返回最后一个元素,count-- + elif string.strcmp(lm_name, "pop") == 0: + p_idx1: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) + p_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx1) + p_count: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_cpp) + p_nc: llvmlite.Value | t.CPtr = llvmlite.build_sub( + builder, p_count, llvmlite.const_int64(pool, 1)) + llvmlite.build_store(builder, p_nc, p_cpp) + p_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + p_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx0) + p_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, p_dpp) + p_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) + p_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx4) + p_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_epp) + if p_data is not None and p_esize is not None and p_nc is not None: + p_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, p_nc, p_esize) + p_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, p_data, p_offset) + if p_addr is not None: + p_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, p_addr, llvmlite.Ptr(pool, lm_elem_ty)) + if p_ep is not None: + return llvmlite.build_load(builder, lm_elem_ty, p_ep) + + # clear: count = 0 + elif string.strcmp(lm_name, "clear") == 0: + c_idx1: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) + c_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, c_idx1) + llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), c_cpp) + return None + + # __iter__: iter_index = 0, return self + elif string.strcmp(lm_name, "__iter__") == 0: + it_idx5: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 5) + it_ipp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, it_idx5) + llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), it_ipp) + return lm_obj + + # append: 直接调用 list.append(self, item) + # append 需要容量检查和内存重分配,逻辑复杂,直接调用 _list.py 中的实现 + elif string.strcmp(lm_name, "append") == 0: + if can >= 1: + ap_sha1: str = self._lookup_module_sha1("_list") + if ap_sha1 is None: + # 依赖模块未编译(_list 未预加入编译链):fail-fast, + # 绝不静默跳过 append(元素永远不会被加入列表) + self.Gen.TypeGenErr.fatal_error( + cl, "list.append: 找不到 _list 模块 SHA1(依赖模块未编译)", + "InternalCompilerError") + if ap_sha1 is not None: + # 特化类名提取:list.append 的符号名是 + # {sha1}.list[AST|CPtr].append(带类型参数特化名), + # 而非 {sha1}.list.append。lm_obj 类型即特化结构体 + # Ptr(list[AST|CPtr]),从类型解析特化类名拼接调用名, + # 否则 ld.lld undefined symbol(定义端是特化名)。 + ap_spec_nm: str = None + ap_struct_ty: llvmlite.LLVMType | t.CPtr = \ + self.Gen.StructGen.get_struct_type_from_value(lm_obj) + if ap_struct_ty is not None: + ap_spec_nm = self.Gen.StructGen.get_class_name_by_type( + pool, ap_struct_ty) + if ap_spec_nm is None: + ap_spec_nm = "list" + # 触发泛型特化翻译(幂等,MethodsEmitted 防重入): + # list[AST|CPtr].append 的 define 方法体在特化类翻译时 + # 生成。仅构造调用名不触发特化会导致定义缺失 + # (ld.lld undefined symbol: list[AST|CPtr].append)。 + if trans is not None and ap_spec_nm is not None: + lbkt_ap: str = string.strchr(ap_spec_nm, '[') + if lbkt_ap is not None: + rbkt_ap: str = string.strrchr(ap_spec_nm, ']') + if rbkt_ap is not None and rbkt_ap > lbkt_ap: + base_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(lbkt_ap) - t.CUInt64T(ap_spec_nm)) + arg_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(rbkt_ap) - t.CUInt64T(lbkt_ap) - 1) + if base_len_ap > 0 and arg_len_ap > 0: + base_buf_ap: str = pool.alloc(base_len_ap + 1) + arg_buf_ap: str = pool.alloc(arg_len_ap + 1) + if base_buf_ap is not None and arg_buf_ap is not None: + string.strncpy(base_buf_ap, ap_spec_nm, base_len_ap) + base_buf_ap[base_len_ap] = '\0' + string.strncpy(arg_buf_ap, lbkt_ap + 1, arg_len_ap) + arg_buf_ap[arg_len_ap] = '\0' + args_ap: list[str] | t.CPtr = list[str](pool, 8) + if args_ap is not None: + # 逗号分隔多类型实参(list[X] / dict[K, V]) + cur_ap: str = arg_buf_ap + while cur_ap is not None: + comma_ap: str = string.strchr(cur_ap, ',') + if comma_ap is None: + args_ap.append(cur_ap) + break + seg_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(comma_ap) - t.CUInt64T(cur_ap)) + seg_buf_ap: str = pool.alloc(seg_len_ap + 1) + if seg_buf_ap is not None: + string.strncpy(seg_buf_ap, cur_ap, seg_len_ap) + seg_buf_ap[seg_len_ap] = '\0' + args_ap.append(seg_buf_ap) + cur_ap = comma_ap + 1 + self.Gen.ClassGenGeneric._specialize_generic_class( + trans, base_buf_ap, args_ap) + # 调用名 "{sha1}.{spec}.append": + # sha1(16) + '.'(1) + spec + '.append'(7) + NUL(1) = spec + 25。 + # 此前 +8 少 1 字节,snprintf 截断末尾 'd' → + # undefined symbol: ...list[AST|CPtr].appen(缺 d)。 + ap_mlen: t.CSizeT = string.strlen(ap_sha1) + \ + string.strlen(ap_spec_nm) + 26 + ap_mangled: str = pool.alloc(ap_mlen) + if ap_mangled is not None: + viperlib.snprintf(ap_mangled, ap_mlen, "%s.%s.append", + ap_sha1, ap_spec_nm) + ap_item_node: ast.AST | t.CPtr = cargs.get(0) + ap_item_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, ap_item_node, None, 0, trans) + if ap_item_val is not None: + llvmlite.value_set_next(lm_obj, None) + llvmlite.value_set_next(ap_item_val, None) + llvmlite.value_set_next(lm_obj, ap_item_val) + ap_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + self._ensure_method_declare(pool, mod, ap_mangled, ap_ret_ty, lm_obj, 2) + return llvmlite.build_call(builder, ap_mangled, lm_obj, 2, ap_ret_ty, 0) + return None \ No newline at end of file diff --git a/App/lib/core/Gen/CallGenFd.vp b/App/lib/core/Gen/CallGenFd.vp index 8c702fd..42dedf8 100644 --- a/App/lib/core/Gen/CallGenFd.vp +++ b/App/lib/core/Gen/CallGenFd.vp @@ -1,411 +1,404 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import sys -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesFunctions as HandlesFunctions -import lib.core.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.CompilerFactory as CompilerFactory - - -import lib.core.Gen.CallGenBase as CallGenBase - -# ============================================================ -# CallGenFd - CallGenMixin 拆分(阶段 B):FakeDuck / requires 字段注入 / provider 栈 -# -# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class CallGenFd(CallGenBase.CallGenBase): - """FakeDuck / requires 字段注入 / provider 栈""" - - # ============================================================ - # _translate_fakeduck_call - FakeDuck: str 变量方法调用 → 扩展类 _Type/_str - # - # 对齐 TPC HandlesExprCall.py L2841-2880: - # ClassName 常规解析失败且对象是 char*(i8*)时,遍历扩展类查找 - # {CN}.{method} 函数。对象是 Name 变量且有影子({var}__meta__,fd2 - # 创建)时 self=影子;否则(字符串字面量/匿名 str)在入口创建临时 - # 影子,写 __data__=obj 值、__mbuddy__=NULL 后作 self,避免 - # bitcast i8* → _str* 读取垃圾指针导致 ACCESS_VIOLATION。 - # ============================================================ - - # ============================================================ - def _translate_fakeduck_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cls_name: str, - method_name: str, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """FakeDuck: str 变量方法调用解析到扩展类 _Type/_str,返回 call 结果或 None""" - if pool is None or builder is None or cl is None or trans is None: - return None - if method_name is None: - return None - # 仅对 str 类型触发(AnnotClassName == "str",对象是 char*); - # cls_name 为 None(表达式接收者解析失败)时也尝试 - if cls_name is not None and string.strcmp(cls_name, "str") != 0: - return None - if cl.func is None or cl.func.kind() != ast.ASTKind.Attribute: - return None - fd_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if fd_at is None or fd_at.value is None or fd_at.attr is None: - return None - if string.strcmp(fd_at.attr, method_name) != 0: - return None - # 候选扩展类:先 _Type(a.type_id())后 _str(a.upper() 等) - fd_func: llvmlite.Function | t.CPtr = None - fd_cls: str = None - fd_key: str = pool.alloc(160) - if fd_key is not None: - for fd_ci in range(2): - fd_cn: str = "_Type" - if fd_ci == 1: - fd_cn = "_str" - viperlib.snprintf(fd_key, 160, "%s.%s", fd_cn, method_name) - fd_func = self.find_func_in_module(mod, fd_key) - if fd_func is not None: - fd_cls = fd_cn - break - if fd_func is None or fd_cls is None: - return None - # 扩展类结构体必须已注册(GEP/临时影子需要类型) - fd_sty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(fd_cls) - if fd_sty is None: - return None - # 扩展类字段数:有字段(_str)时 self 用影子结构体指针; - # 无字段(_Type)时 self 用对象值 bitcast 到扩展类指针(对齐 TPC L2856-2876) - fd_entry_fd: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(fd_sty) - fd_has_fields: int = 0 - if fd_entry_fd is not None and fd_entry_fd.FieldCount > 0: - fd_has_fields = 1 - # self 参数:优先使用已有影子 {var}__meta__(fd2 创建,仅当扩展类有字段时) - fd_self: llvmlite.Value | t.CPtr = None - if fd_at.value.kind() == ast.ASTKind.Name: - fd_onm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(fd_at.value) - if fd_onm.id is not None: - # pool 持久缓冲(f-string 栈缓冲在函数返回后失效) - fd_mn: str = pool.alloc(256) - if fd_mn is not None: - viperlib.snprintf(fd_mn, 256, "%s__meta__", fd_onm.id) - fd_meta: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( - trans.SymTab, fd_mn) - if fd_meta is not None and fd_has_fields != 0: - fd_self = fd_meta - if fd_self is None: - if fd_has_fields != 0: - # 有字段扩展类且无影子(字符串字面量等):入口创建临时影子并初始化 - # 先确保 _str 完整定义(跨模块结构体默认 opaque,alloca 报 unsized) - HandlesStruct.ensure_struct_def_in_module(pool, mod, fd_sty) - fd_self = HandlesVar._alloca_at_entry(builder, fd_sty) - if fd_self is None: - return None - fd_obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, fd_at.value, None, 0, trans) - if fd_obj_val is not None: - fd_dfe: HandlesStruct.FieldEntry | t.CPtr = \ - HandlesStruct.lookup_field(fd_sty, "__data__") - if fd_dfe is not None and fd_dfe.Ty is not None: - fd_dp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, fd_sty, fd_dfe.Ty, fd_self, fd_dfe.Index) - if fd_dp is not None: - llvmlite.build_store(builder, fd_obj_val, fd_dp) - fd_bfe: HandlesStruct.FieldEntry | t.CPtr = \ - HandlesStruct.lookup_field(fd_sty, "__mbuddy__") - if fd_bfe is not None and fd_bfe.Ty is not None: - fd_bp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, fd_sty, fd_bfe.Ty, fd_self, fd_bfe.Index) - fd_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull( - pool, fd_bfe.Ty, "null") - if fd_bp is not None and fd_null is not None: - llvmlite.build_store(builder, fd_null, fd_bp) - # FakeDuck: with 上下文自动注入 requires 字段(如 __mbuddy__) - self._inject_requires_fields( - trans, pool, builder, mod, fd_self, fd_cls) - else: - # 无字段扩展类(_Type):对象值 bitcast 到扩展类指针 - fd_obj_v: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, fd_at.value, None, 0, trans) - if fd_obj_v is None: - return None - fd_self = llvmlite.build_bitcast( - builder, fd_obj_v, llvmlite.Ptr(pool, fd_sty)) - if fd_self is None: - return None - # 构建参数链表: self → 其余参数 - llvmlite.value_set_next(fd_self, None) - fd_head: llvmlite.Value | t.CPtr = fd_self - fd_tail: llvmlite.Value | t.CPtr = fd_self - fd_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args - fd_can: int = 0 - if fd_args is not None: - fd_can = len(fd_args) - for fd_ai in range(fd_can): - fd_arg: ast.AST | t.CPtr = fd_args.get(fd_ai) - if fd_arg is not None: - fd_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, fd_arg, None, 0, trans) - # char 常量参数 → 单字符字符串(char 隐式转 str, - # 如 s1.split(','):',' 是 i32 值 44,传给 str 参数须先字符串化, - # 否则运行时 strlen/strncmp 解引用 44 崩溃) - if fd_arg.kind() == ast.ASTKind.Constant: - fd_ac: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(fd_arg) - if fd_ac.const_kind == ast.CONST_CHAR: - ch_buf: str = pool.alloc(2) - if ch_buf is not None: - ch_buf[0] = t.CChar(fd_ac.int_val) - ch_buf[1] = '\0' - fd_av = HandlesExpr.create_global_string( - builder, pool, mod, ch_buf, trans) - if fd_av is not None: - llvmlite.value_set_next(fd_av, None) - llvmlite.value_set_next(fd_tail, fd_av) - fd_tail = fd_av - # 返回类型与调用名(来自 find_func_in_module 命中的函数定义) - fd_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(fd_func) - if fd_ret_ty is None: - fd_ret_ty = llvmlite.Int32(pool) - fd_fname: str = llvmlite.function_get_name(fd_func) - if fd_fname is None: - return None - # 返回类型精确化:跨模块 declare 的 list[T] 特化返回类型可能被简化 - # 为 Ptr(i8),调用方变量 alloca 类型随之退化 → parts[0] 走字符下标 - # 路径而非 list 内联 __getitem__(printf %s 解引用字符值崩溃)。 - # 从定义模块 text.ll 读取精确返回类型(对齐普通方法调用 _translate_method_call)。 - fd_sha1: str = pool.alloc(17) - if fd_sha1 is not None: - string.strncpy(fd_sha1, fd_fname, 16) - fd_sha1[16] = '\0' - fd_exact: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL( - pool, fd_sha1, fd_cls, method_name) - if fd_exact is not None: - fd_ret_ty = fd_exact - fd_total: int = 1 + fd_can - return llvmlite.build_call(builder, fd_fname, fd_head, fd_total, fd_ret_ty, 0) - # ============================================================ - # _inject_requires_fields - FakeDuck: with 上下文注入 requires 字段 - # - # 对齐 TPC HandlesExprCall.py L4021-4079: - # 对类 __requires__ 元数据(fd1 注册)中的每个字段,运行时调用 - # _find_provider(field) 查找 with 上下文提供的指针;非 NULL 时 - # bitcast 到字段类型写入 meta_ptr 对应槽位(条件注入,避免覆盖 - # 用户已手动设置的值)。_find_provider 未注册(未 import - # _withcontent)时跳过注入,不影响非 with 场景。 - # ============================================================ - - # ============================================================ - def _inject_requires_fields(self, trans: HT.Translator | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - meta_ptr: llvmlite.Value | t.CPtr, - class_name: str) -> int: - """在 with 上下文注入 requires 字段,返回注入字段数""" - if trans is None or pool is None or builder is None or mod is None: - return 0 - if meta_ptr is None or class_name is None: - return 0 - # _withcontent._find_provider(跨模块):仅当本模块可见(_withcontent - # 被 import,vpi stub declare 已注入)时才注入。对齐 TPC L4048-4050 - # (Gen.functions.get('_find_provider') 不存在则跳过)——否则非 with - # 项目(如 HashTableTest 未 import _withcontent)也会为每个 _str(...) - # 构造发射 {sha1}._find_provider 调用 → ld.lld undefined symbol。 - fd_fn_probe: llvmlite.Function | t.CPtr = self.find_func_in_module( - mod, "_find_provider") - if fd_fn_probe is None: - return 0 - fd_fname: str = llvmlite.function_get_name(fd_fn_probe) - if fd_fname is None: - return 0 - cnt: int = HandlesType.class_meta_count( - HandlesType.CLASS_META_REQUIRES, class_name) - if cnt <= 0: - return 0 - sty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(class_name) - if sty is None: - return 0 - i8_ty_j: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - if i8_ty_j is None: - return 0 - i8_ptr_ty_j: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_j) - if i8_ptr_ty_j is None: - return 0 - cur_func: llvmlite.Function | t.CPtr = trans._cur_func - if cur_func is None: - return 0 - injected: int = 0 - for ji in range(cnt): - fname: str = HandlesType.class_meta_field_at( - HandlesType.CLASS_META_REQUIRES, class_name, ji) - if fname is None: - continue - fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( - sty, fname) - if fe is None or fe.Ty is None: - continue - # 参数:字段名字符串(i8*) - fd_fstr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string( - builder, pool, mod, fname, trans) - if fd_fstr is None: - continue - llvmlite.value_set_next(fd_fstr, None) - self._ensure_method_declare( - pool, mod, fd_fname, i8_ptr_ty_j, fd_fstr, 1) - fd_ptr: llvmlite.Value | t.CPtr = llvmlite.build_call( - builder, fd_fname, fd_fstr, 1, i8_ptr_ty_j, 0) - if fd_ptr is None: - continue - # 条件注入:ptr != NULL 才写入(保留用户手动设置的值) - fd_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull( - pool, i8_ptr_ty_j, "null") - if fd_null is None: - continue - fd_cmp: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, fd_ptr, fd_null) - if fd_cmp is None: - continue - # 块名唯一化(create_block 不自动编号,同名 label 在文本 IR 中 - # 冲突 → llc "Terminator found in the middle of a basic block") - vtc2: int = trans._label_counter - trans._label_counter = vtc2 + 1 - fd_bb_buf2: str = pool.alloc(64) - if fd_bb_buf2 is None: - continue - viperlib.snprintf(fd_bb_buf2, 64, "fd.skip.%d", vtc2) - fd_skip_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, cur_func, fd_bb_buf2) - viperlib.snprintf(fd_bb_buf2, 64, "fd.inject.%d", vtc2) - fd_inject_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, cur_func, fd_bb_buf2) - if fd_skip_bb is None or fd_inject_bb is None: - continue - llvmlite.build_cond_br(builder, fd_cmp, fd_inject_bb, fd_skip_bb) - # inject 块:bitcast + GEP + store,跳回 skip - llvmlite.position_at_end(builder, fd_inject_bb) - fd_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, fd_ptr, fe.Ty) - if fd_cast is not None: - fd_fp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, sty, fe.Ty, meta_ptr, fe.Index) - if fd_fp is not None: - llvmlite.build_store(builder, fd_cast, fd_fp) - llvmlite.build_br(builder, fd_skip_bb) - # skip 块:恢复 CurBlock,继续后续代码生成 - llvmlite.position_at_end(builder, fd_skip_bb) - injected += 1 - return injected - # ============================================================ - # _emit_provider_push / _emit_provider_pop - FakeDuck: with 上下文 - # provider push/pop(__provides__ 元数据,fd1 注册) - # - # 对齐 TPC HandlesWith.py L138-174: - # with 进入时对每个提供字段生成 _push_provider(field_str, ctx_i8); - # 退出时生成等量 _pop_provider()。运行时 _withcontent 模块负责 - # 维护 TLS provider 栈,供 _inject_requires_fields 查找。 - # ============================================================ - - # ============================================================ - def _emit_provider_push(self, trans: HT.Translator | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cls_name: str, - ctx_val: llvmlite.Value | t.CPtr) -> int: - """生成 _push_provider(field, ctx_i8) 调用(每提供字段一次),返回字段数""" - if trans is None or pool is None or builder is None or mod is None: - return 0 - if cls_name is None or ctx_val is None: - return 0 - fd_pc: int = HandlesType.class_meta_count( - HandlesType.CLASS_META_PROVIDES, cls_name) - if fd_pc <= 0: - return 0 - # _withcontent._push_provider(跨模块,同 _find_provider 的可见性守卫: - # 本模块未 import _withcontent 时跳过,避免 undefined symbol) - fd_pfn_probe: llvmlite.Function | t.CPtr = self.find_func_in_module( - mod, "_push_provider") - if fd_pfn_probe is None: - return 0 - fd_pfn: str = llvmlite.function_get_name(fd_pfn_probe) - if fd_pfn is None: - return 0 - i8_ty_p: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - if i8_ty_p is None: - return 0 - i8_ptr_ty_p: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_p) - if i8_ptr_ty_p is None: - return 0 - ret_i32_p: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if ret_i32_p is None: - return 0 - # ctx 值 bitcast 到 i8*(provider 栈存 void*) - fd_ctx_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, ctx_val, i8_ptr_ty_p) - if fd_ctx_i8 is None: - return 0 - for pi in range(fd_pc): - fname: str = HandlesType.class_meta_field_at( - HandlesType.CLASS_META_PROVIDES, cls_name, pi) - if fname is None: - continue - fd_fstr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string( - builder, pool, mod, fname, trans) - if fd_fstr is None: - continue - llvmlite.value_set_next(fd_fstr, fd_ctx_i8) - llvmlite.value_set_next(fd_ctx_i8, None) - self._ensure_method_declare( - pool, mod, fd_pfn, ret_i32_p, fd_fstr, 2) - llvmlite.build_call(builder, fd_pfn, fd_fstr, 2, ret_i32_p, 0) - return fd_pc - def _emit_provider_pop(self, trans: HT.Translator | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cls_name: str) -> int: - """生成 _pop_provider() 调用(每提供字段一次),返回字段数""" - if trans is None or pool is None or builder is None or mod is None: - return 0 - if cls_name is None: - return 0 - fd_pc: int = HandlesType.class_meta_count( - HandlesType.CLASS_META_PROVIDES, cls_name) - if fd_pc <= 0: - return 0 - # _withcontent._pop_provider(跨模块,同 _find_provider 的可见性守卫: - # 本模块未 import _withcontent 时跳过,避免 undefined symbol) - fd_pon_probe: llvmlite.Function | t.CPtr = self.find_func_in_module( - mod, "_pop_provider") - if fd_pon_probe is None: - return 0 - fd_pon: str = llvmlite.function_get_name(fd_pon_probe) - if fd_pon is None: - return 0 - ret_i32_q: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if ret_i32_q is None: - return 0 - self._ensure_method_declare(pool, mod, fd_pon, ret_i32_q, None, 0) - for _pi in range(fd_pc): - llvmlite.build_call(builder, fd_pon, None, 0, ret_i32_q, 0) +import lib.core.Gen.GenTypes as GenTypes +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import sys +import viperlib +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.CallGenBase as CallGenBase + +# ============================================================ +# CallGenFd - CallGenMixin 拆分(阶段 B):FakeDuck / requires 字段注入 / provider 栈 +# +# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class CallGenFd(CallGenBase.CallGenBase): + """FakeDuck / requires 字段注入 / provider 栈""" + + # ============================================================ + # _translate_fakeduck_call - FakeDuck: str 变量方法调用 → 扩展类 _Type/_str + # + # 对齐 TPC HandlesExprCall.py L2841-2880: + # ClassName 常规解析失败且对象是 char*(i8*)时,遍历扩展类查找 + # {CN}.{method} 函数。对象是 Name 变量且有影子({var}__meta__,fd2 + # 创建)时 self=影子;否则(字符串字面量/匿名 str)在入口创建临时 + # 影子,写 __data__=obj 值、__mbuddy__=NULL 后作 self,避免 + # bitcast i8* → _str* 读取垃圾指针导致 ACCESS_VIOLATION。 + # ============================================================ + + # ============================================================ + def _translate_fakeduck_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cls_name: str, + method_name: str, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """FakeDuck: str 变量方法调用解析到扩展类 _Type/_str,返回 call 结果或 None""" + if pool is None or builder is None or cl is None or trans is None: + return None + if method_name is None: + return None + # 仅对 str 类型触发(AnnotClassName == "str",对象是 char*); + # cls_name 为 None(表达式接收者解析失败)时也尝试 + if cls_name is not None and string.strcmp(cls_name, "str") != 0: + return None + if cl.func is None or cl.func.kind() != ast.ASTKind.Attribute: + return None + fd_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if fd_at is None or fd_at.value is None or fd_at.attr is None: + return None + if string.strcmp(fd_at.attr, method_name) != 0: + return None + # 候选扩展类:先 _Type(a.type_id())后 _str(a.upper() 等) + fd_func: llvmlite.Function | t.CPtr = None + fd_cls: str = None + fd_key: str = pool.alloc(160) + if fd_key is not None: + for fd_ci in range(2): + fd_cn: str = "_Type" + if fd_ci == 1: + fd_cn = "_str" + viperlib.snprintf(fd_key, 160, "%s.%s", fd_cn, method_name) + fd_func = self.find_func_in_module(mod, fd_key) + if fd_func is not None: + fd_cls = fd_cn + break + if fd_func is None or fd_cls is None: + return None + # 扩展类结构体必须已注册(GEP/临时影子需要类型) + fd_sty: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type(fd_cls) + if fd_sty is None: + return None + # 扩展类字段数:有字段(_str)时 self 用影子结构体指针; + # 无字段(_Type)时 self 用对象值 bitcast 到扩展类指针(对齐 TPC L2856-2876) + fd_entry_fd: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_type(fd_sty) + fd_has_fields: int = 0 + if fd_entry_fd is not None and fd_entry_fd.FieldCount > 0: + fd_has_fields = 1 + # self 参数:优先使用已有影子 {var}__meta__(fd2 创建,仅当扩展类有字段时) + fd_self: llvmlite.Value | t.CPtr = None + if fd_at.value.kind() == ast.ASTKind.Name: + fd_onm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(fd_at.value) + if fd_onm.id is not None: + # pool 持久缓冲(f-string 栈缓冲在函数返回后失效) + fd_mn: str = pool.alloc(256) + if fd_mn is not None: + viperlib.snprintf(fd_mn, 256, "%s__meta__", fd_onm.id) + fd_meta: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_current( + trans.SymTab, fd_mn) + if fd_meta is not None and fd_has_fields != 0: + fd_self = fd_meta + if fd_self is None: + if fd_has_fields != 0: + # 有字段扩展类且无影子(字符串字面量等):入口创建临时影子并初始化 + # 先确保 _str 完整定义(跨模块结构体默认 opaque,alloca 报 unsized) + self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, fd_sty) + fd_self = self.Gen.VarGen._alloca_at_entry(builder, fd_sty) + if fd_self is None: + return None + fd_obj_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, fd_at.value, None, 0, trans) + if fd_obj_val is not None: + fd_dfe: GenTypes.FieldEntry | t.CPtr = \ + self.Gen.StructGen.lookup_field(fd_sty, "__data__") + if fd_dfe is not None and fd_dfe.Ty is not None: + fd_dp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, fd_sty, fd_dfe.Ty, fd_self, fd_dfe.Index) + if fd_dp is not None: + llvmlite.build_store(builder, fd_obj_val, fd_dp) + fd_bfe: GenTypes.FieldEntry | t.CPtr = \ + self.Gen.StructGen.lookup_field(fd_sty, "__mbuddy__") + if fd_bfe is not None and fd_bfe.Ty is not None: + fd_bp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, fd_sty, fd_bfe.Ty, fd_self, fd_bfe.Index) + fd_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull( + pool, fd_bfe.Ty, "null") + if fd_bp is not None and fd_null is not None: + llvmlite.build_store(builder, fd_null, fd_bp) + # FakeDuck: with 上下文自动注入 requires 字段(如 __mbuddy__) + self._inject_requires_fields( + trans, pool, builder, mod, fd_self, fd_cls) + else: + # 无字段扩展类(_Type):对象值 bitcast 到扩展类指针 + fd_obj_v: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, fd_at.value, None, 0, trans) + if fd_obj_v is None: + return None + fd_self = llvmlite.build_bitcast( + builder, fd_obj_v, llvmlite.Ptr(pool, fd_sty)) + if fd_self is None: + return None + # 构建参数链表: self → 其余参数 + llvmlite.value_set_next(fd_self, None) + fd_head: llvmlite.Value | t.CPtr = fd_self + fd_tail: llvmlite.Value | t.CPtr = fd_self + fd_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args + fd_can: int = 0 + if fd_args is not None: + fd_can = len(fd_args) + for fd_ai in range(fd_can): + fd_arg: ast.AST | t.CPtr = fd_args.get(fd_ai) + if fd_arg is not None: + fd_av: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, fd_arg, None, 0, trans) + # char 常量参数 → 单字符字符串(char 隐式转 str, + # 如 s1.split(','):',' 是 i32 值 44,传给 str 参数须先字符串化, + # 否则运行时 strlen/strncmp 解引用 44 崩溃) + if fd_arg.kind() == ast.ASTKind.Constant: + fd_ac: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(fd_arg) + if fd_ac.const_kind == ast.CONST_CHAR: + ch_buf: str = pool.alloc(2) + if ch_buf is not None: + ch_buf[0] = t.CChar(fd_ac.int_val) + ch_buf[1] = '\0' + fd_av = self.Gen.ExprGenConst.create_global_string( + builder, pool, mod, ch_buf, trans) + if fd_av is not None: + llvmlite.value_set_next(fd_av, None) + llvmlite.value_set_next(fd_tail, fd_av) + fd_tail = fd_av + # 返回类型与调用名(来自 find_func_in_module 命中的函数定义) + fd_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(fd_func) + if fd_ret_ty is None: + fd_ret_ty = llvmlite.Int32(pool) + fd_fname: str = llvmlite.function_get_name(fd_func) + if fd_fname is None: + return None + # 返回类型精确化:跨模块 declare 的 list[T] 特化返回类型可能被简化 + # 为 Ptr(i8),调用方变量 alloca 类型随之退化 → parts[0] 走字符下标 + # 路径而非 list 内联 __getitem__(printf %s 解引用字符值崩溃)。 + # 从定义模块 text.ll 读取精确返回类型(对齐普通方法调用 _translate_method_call)。 + fd_sha1: str = pool.alloc(17) + if fd_sha1 is not None: + string.strncpy(fd_sha1, fd_fname, 16) + fd_sha1[16] = '\0' + fd_exact: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL( + pool, fd_sha1, fd_cls, method_name) + if fd_exact is not None: + fd_ret_ty = fd_exact + fd_total: int = 1 + fd_can + return llvmlite.build_call(builder, fd_fname, fd_head, fd_total, fd_ret_ty, 0) + # ============================================================ + # _inject_requires_fields - FakeDuck: with 上下文注入 requires 字段 + # + # 对齐 TPC HandlesExprCall.py L4021-4079: + # 对类 __requires__ 元数据(fd1 注册)中的每个字段,运行时调用 + # _find_provider(field) 查找 with 上下文提供的指针;非 NULL 时 + # bitcast 到字段类型写入 meta_ptr 对应槽位(条件注入,避免覆盖 + # 用户已手动设置的值)。_find_provider 未注册(未 import + # _withcontent)时跳过注入,不影响非 with 场景。 + # ============================================================ + + # ============================================================ + def _inject_requires_fields(self, trans: HT.Translator | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + meta_ptr: llvmlite.Value | t.CPtr, + class_name: str) -> int: + """在 with 上下文注入 requires 字段,返回注入字段数""" + if trans is None or pool is None or builder is None or mod is None: + return 0 + if meta_ptr is None or class_name is None: + return 0 + # _withcontent._find_provider(跨模块):仅当本模块可见(_withcontent + # 被 import,vpi stub declare 已注入)时才注入。对齐 TPC L4048-4050 + # (Gen.functions.get('_find_provider') 不存在则跳过)——否则非 with + # 项目(如 HashTableTest 未 import _withcontent)也会为每个 _str(...) + # 构造发射 {sha1}._find_provider 调用 → ld.lld undefined symbol。 + fd_fn_probe: llvmlite.Function | t.CPtr = self.find_func_in_module( + mod, "_find_provider") + if fd_fn_probe is None: + return 0 + fd_fname: str = llvmlite.function_get_name(fd_fn_probe) + if fd_fname is None: + return 0 + cnt: int = self.Gen.ClassGenBase.class_meta_count( + GenTypes.CLASS_META_REQUIRES, class_name) + if cnt <= 0: + return 0 + sty: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type(class_name) + if sty is None: + return 0 + i8_ty_j: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + if i8_ty_j is None: + return 0 + i8_ptr_ty_j: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_j) + if i8_ptr_ty_j is None: + return 0 + cur_func: llvmlite.Function | t.CPtr = trans._cur_func + if cur_func is None: + return 0 + injected: int = 0 + for ji in range(cnt): + fname: str = self.Gen.ClassGenBase.class_meta_field_at( + GenTypes.CLASS_META_REQUIRES, class_name, ji) + if fname is None: + continue + fe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field( + sty, fname) + if fe is None or fe.Ty is None: + continue + # 参数:字段名字符串(i8*) + fd_fstr: llvmlite.Value | t.CPtr = self.Gen.ExprGenConst.create_global_string( + builder, pool, mod, fname, trans) + if fd_fstr is None: + continue + llvmlite.value_set_next(fd_fstr, None) + self._ensure_method_declare( + pool, mod, fd_fname, i8_ptr_ty_j, fd_fstr, 1) + fd_ptr: llvmlite.Value | t.CPtr = llvmlite.build_call( + builder, fd_fname, fd_fstr, 1, i8_ptr_ty_j, 0) + if fd_ptr is None: + continue + # 条件注入:ptr != NULL 才写入(保留用户手动设置的值) + fd_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull( + pool, i8_ptr_ty_j, "null") + if fd_null is None: + continue + fd_cmp: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, fd_ptr, fd_null) + if fd_cmp is None: + continue + # 块名唯一化(create_block 不自动编号,同名 label 在文本 IR 中 + # 冲突 → llc "Terminator found in the middle of a basic block") + vtc2: int = trans._label_counter + trans._label_counter = vtc2 + 1 + fd_bb_buf2: str = pool.alloc(64) + if fd_bb_buf2 is None: + continue + viperlib.snprintf(fd_bb_buf2, 64, "fd.skip.%d", vtc2) + fd_skip_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, cur_func, fd_bb_buf2) + viperlib.snprintf(fd_bb_buf2, 64, "fd.inject.%d", vtc2) + fd_inject_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, cur_func, fd_bb_buf2) + if fd_skip_bb is None or fd_inject_bb is None: + continue + llvmlite.build_cond_br(builder, fd_cmp, fd_inject_bb, fd_skip_bb) + # inject 块:bitcast + GEP + store,跳回 skip + llvmlite.position_at_end(builder, fd_inject_bb) + fd_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, fd_ptr, fe.Ty) + if fd_cast is not None: + fd_fp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, sty, fe.Ty, meta_ptr, fe.Index) + if fd_fp is not None: + llvmlite.build_store(builder, fd_cast, fd_fp) + llvmlite.build_br(builder, fd_skip_bb) + # skip 块:恢复 CurBlock,继续后续代码生成 + llvmlite.position_at_end(builder, fd_skip_bb) + injected += 1 + return injected + # ============================================================ + # _emit_provider_push / _emit_provider_pop - FakeDuck: with 上下文 + # provider push/pop(__provides__ 元数据,fd1 注册) + # + # 对齐 TPC HandlesWith.py L138-174: + # with 进入时对每个提供字段生成 _push_provider(field_str, ctx_i8); + # 退出时生成等量 _pop_provider()。运行时 _withcontent 模块负责 + # 维护 TLS provider 栈,供 _inject_requires_fields 查找。 + # ============================================================ + + # ============================================================ + def _emit_provider_push(self, trans: HT.Translator | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cls_name: str, + ctx_val: llvmlite.Value | t.CPtr) -> int: + """生成 _push_provider(field, ctx_i8) 调用(每提供字段一次),返回字段数""" + if trans is None or pool is None or builder is None or mod is None: + return 0 + if cls_name is None or ctx_val is None: + return 0 + fd_pc: int = self.Gen.ClassGenBase.class_meta_count( + GenTypes.CLASS_META_PROVIDES, cls_name) + if fd_pc <= 0: + return 0 + # _withcontent._push_provider(跨模块,同 _find_provider 的可见性守卫: + # 本模块未 import _withcontent 时跳过,避免 undefined symbol) + fd_pfn_probe: llvmlite.Function | t.CPtr = self.find_func_in_module( + mod, "_push_provider") + if fd_pfn_probe is None: + return 0 + fd_pfn: str = llvmlite.function_get_name(fd_pfn_probe) + if fd_pfn is None: + return 0 + i8_ty_p: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + if i8_ty_p is None: + return 0 + i8_ptr_ty_p: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_p) + if i8_ptr_ty_p is None: + return 0 + ret_i32_p: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if ret_i32_p is None: + return 0 + # ctx 值 bitcast 到 i8*(provider 栈存 void*) + fd_ctx_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, ctx_val, i8_ptr_ty_p) + if fd_ctx_i8 is None: + return 0 + for pi in range(fd_pc): + fname: str = self.Gen.ClassGenBase.class_meta_field_at( + GenTypes.CLASS_META_PROVIDES, cls_name, pi) + if fname is None: + continue + fd_fstr: llvmlite.Value | t.CPtr = self.Gen.ExprGenConst.create_global_string( + builder, pool, mod, fname, trans) + if fd_fstr is None: + continue + llvmlite.value_set_next(fd_fstr, fd_ctx_i8) + llvmlite.value_set_next(fd_ctx_i8, None) + self._ensure_method_declare( + pool, mod, fd_pfn, ret_i32_p, fd_fstr, 2) + llvmlite.build_call(builder, fd_pfn, fd_fstr, 2, ret_i32_p, 0) + return fd_pc + def _emit_provider_pop(self, trans: HT.Translator | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cls_name: str) -> int: + """生成 _pop_provider() 调用(每提供字段一次),返回字段数""" + if trans is None or pool is None or builder is None or mod is None: + return 0 + if cls_name is None: + return 0 + fd_pc: int = self.Gen.ClassGenBase.class_meta_count( + GenTypes.CLASS_META_PROVIDES, cls_name) + if fd_pc <= 0: + return 0 + # _withcontent._pop_provider(跨模块,同 _find_provider 的可见性守卫: + # 本模块未 import _withcontent 时跳过,避免 undefined symbol) + fd_pon_probe: llvmlite.Function | t.CPtr = self.find_func_in_module( + mod, "_pop_provider") + if fd_pon_probe is None: + return 0 + fd_pon: str = llvmlite.function_get_name(fd_pon_probe) + if fd_pon is None: + return 0 + ret_i32_q: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if ret_i32_q is None: + return 0 + self._ensure_method_declare(pool, mod, fd_pon, ret_i32_q, None, 0) + for _pi in range(fd_pc): + llvmlite.build_call(builder, fd_pon, None, 0, ret_i32_q, 0) return fd_pc \ No newline at end of file diff --git a/App/lib/core/Gen/CallGenLeafKit.vp b/App/lib/core/Gen/CallGenLeafKit.vp index 2ab63c9..f2c8c27 100644 --- a/App/lib/core/Gen/CallGenLeafKit.vp +++ b/App/lib/core/Gen/CallGenLeafKit.vp @@ -1,1312 +1,1305 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import sys -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesFunctions as HandlesFunctions -import lib.core.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.CompilerFactory as CompilerFactory - - -import lib.core.Gen.CallGenCBuiltin as CallGenCBuiltin - - -# ============================================================ -# CallGenLeafKit - CallGenMixin 拆分 3/9:EH/isinstance/闭包/print/函数表 -# -# 按功能域从 CallGenMixin.vp 拆出(500~1500 行/文件架构重构): -# EH 防护 + isinstance + 闭包/函数指针 + printf/print + 全局函数表/默认参数表。 -# 继承 CallGenCBuiltin。 -# -# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 -# ============================================================ - - -# ============================================================ -# 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug) -# ============================================================ -GLOBAL_FUNC_MAX: t.CDefine = 8192 -GLOBAL_DEFAULTS_MAX: t.CDefine = 4096 -_CEXPORT_MAX: t.CDefine = 256 -ASM_MAX_OPERANDS: t.CDefine = 16 -ASM_TEXT_BUF_SIZE: t.CDefine = 2048 -ASM_CONST_BUF_SIZE: t.CDefine = 512 -ASM_ARGS_BUF_SIZE: t.CDefine = 512 -ASM_LINE_BUF_SIZE: t.CDefine = 4096 -LLVMIR_MAX_OPS: t.CDefine = 16 -LLVMIR_TEMPLATE_BUF: t.CDefine = 512 -# 闭包名表大小(原 HandlesExprCall 模块级常量) -MAX_CLOSURE_NAMES: t.CDefine = 128 -# 函数指针签名表大小(原 HandlesExprCall 模块级常量) -MAX_FUNC_PTR_SIGS: t.CDefine = 64 -# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32) -ISINSTANCE_CLASS_MAX: t.CDefine = 64 - - -# ============================================================ -# CallGenLeafKit - EH/isinstance/闭包/print/函数表 -# ============================================================ -@t.NoVTable -class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin): - """EH 防护 + isinstance + 闭包 + print + 全局函数表(继承 CBuiltin)""" - - - # ============================================================ - # _func_has_eh_params - 被调函数签名是否含 try-except EH 输出参数 - # - # EH 参数(%__eh_msg_out__/__eh_code_out__)由 translate_function_def/ - # _translate_method 在含 raise 的函数签名末尾注入(main 除外)。 - # ============================================================ - def _func_has_eh_params(self, func: llvmlite.Function | t.CPtr) -> int: - """返回 1=函数带 EH 输出参数 / 0=不带""" - if func is None: - return 0 - cur_p: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) - while cur_p is not None: - pn: str = llvmlite.param_get_name(cur_p) - if pn is not None and string.strcmp(pn, "%__eh_msg_out__") == 0: - return 1 - cur_p = llvmlite.param_get_next(cur_p) - return 0 - - # ============================================================ - # _emit_eh_guarded_call - 调用侧 try-except EH 检测(对齐 TPC - # HandlesExprCall._append_eh_msg_out_arg + _check_eh_return) - # - # 被调函数带 EH 输出参数时: - # 1. 确定 msg/code 输出指针: - # - 当前在 try(trans._eh_dispatch_bb 非空):复用 try 的 - # eh_message/exception_code alloca——被调函数直接写入,检查 - # 路径读同一 alloca 即得异常,无需搬运 - # - 当前函数有 EH 输出参数:复用本函数 out 参数(异常直接写进 - # 本函数输出,检查命中后仅返回,由调用方接管传播) - # - 两者皆无:局部 null alloca(异常被吞) - # 2. 调用前清零输出指针(复用 alloca 必须复位,防上次残留误判) - # 3. 追加 msg/code 两个实参(count+2) - # 4. 调用后检查 msg != null:命中 → err 块(try 内分支 DispatchBB; - # 否则仅返回默认值);未命中 → ok 块继续 - # ============================================================ - - # ============================================================ - def _emit_eh_guarded_call(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - trans: HT.Translator | t.CPtr, - func: llvmlite.Function | t.CPtr, - call_name: str, - head: llvmlite.Value | t.CPtr, - count: int, - ret_ty: llvmlite.LLVMType | t.CPtr, - is_variadic: int) -> llvmlite.Value | t.CPtr: - """带 try-except EH 检测的函数调用,返回 call 结果(检查后位于 ok 块)""" - if trans is None or self._func_has_eh_params(func) == 0: - return llvmlite.build_call(builder, call_name, head, count, ret_ty, is_variadic) - # ---- 1. 确定输出指针 ---- - i8_ty_g: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty_g: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_g) - i32_ty_g: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if i8_ty_g is None or i8_ptr_ty_g is None or i32_ty_g is None: - return llvmlite.build_call(builder, call_name, head, count, ret_ty, is_variadic) - msg_ptr: llvmlite.Value | t.CPtr = None - code_ptr: llvmlite.Value | t.CPtr = None - if trans._eh_msg_ptr is not None and trans._eh_code_ptr is not None: - msg_ptr = trans._eh_msg_ptr - code_ptr = trans._eh_code_ptr - elif trans._cur_func_has_eh != 0 and trans._eh_msg_out_param is not None \ - and trans._eh_code_out_param is not None: - msg_ptr = trans._eh_msg_out_param - code_ptr = trans._eh_code_out_param - if msg_ptr is None: - msg_ptr = llvmlite.build_alloca(builder, i8_ptr_ty_g) - code_ptr = llvmlite.build_alloca(builder, i32_ty_g) - # ---- 2. 调用前清零 ---- - null_msg_g: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty_g, "null") - zero_code_g: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - if null_msg_g is not None: - llvmlite.build_store(builder, null_msg_g, msg_ptr) - if zero_code_g is not None: - llvmlite.build_store(builder, zero_code_g, code_ptr) - # ---- 3. 追加实参(链表末尾 + count+2)---- - msg_ptr.Next = code_ptr - code_ptr.Next = None - if head is None: - head = msg_ptr - else: - tail_g: llvmlite.Value | t.CPtr = head - while tail_g.Next is not None: - tail_g = tail_g.Next - tail_g.Next = msg_ptr - count = count + 2 - # ---- 4. 调用 + 检查 ---- - result: llvmlite.Value | t.CPtr = llvmlite.build_call( - builder, call_name, head, count, ret_ty, is_variadic) - cur_func_g: llvmlite.Function | t.CPtr = trans._cur_func - if cur_func_g is None or null_msg_g is None: - return result - msg_val_g: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i8_ptr_ty_g, msg_ptr) - if msg_val_g is None: - return result - is_err_g: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, msg_val_g, null_msg_g) - if is_err_g is None: - return result - lc_g: int = trans._label_counter - trans._label_counter = lc_g + 1 - bb_buf_g: str = pool.alloc(64) - if bb_buf_g is None: - return result - viperlib.snprintf(bb_buf_g, 64, "eh.err.%d", lc_g) - err_bb_g: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, cur_func_g, bb_buf_g) - viperlib.snprintf(bb_buf_g, 64, "eh.ok.%d", lc_g) - ok_bb_g: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, cur_func_g, bb_buf_g) - if err_bb_g is None or ok_bb_g is None: - return result - llvmlite.build_cond_br(builder, is_err_g, err_bb_g, ok_bb_g) - # err 块 - llvmlite.position_at_end(builder, err_bb_g) - if trans._eh_dispatch_bb is not None: - # try 内:异常已写入 try 的 alloca(code_ptr 即 try 的 alloca), - # 分支 DispatchBB 交给 except 链 - llvmlite.build_br(builder, trans._eh_dispatch_bb) - else: - # 非 try:异常已写入本函数 out 参数(复用)或局部 alloca(吞掉), - # 仅返回默认值,由调用方检测本函数 out 参数 - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - ret_ty_g2: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty( - cur_func_g) - if ret_ty_g2 is not None: - match ret_ty_g2: - case llvmlite.LLVMType.Void(): - llvmlite.build_ret_void(builder) - case llvmlite.LLVMType.Ptr(_pg): - nv_g: llvmlite.Value | t.CPtr = llvmlite.ConstNull( - pool, ret_ty_g2, "null") - if nv_g is not None: - llvmlite.build_ret(builder, nv_g) - case llvmlite.LLVMType.Float(_fg): - zf_g: llvmlite.Value | t.CPtr = llvmlite.ConstFloat( - pool, ret_ty_g2, 0.0) - if zf_g is not None: - llvmlite.build_ret(builder, zf_g) - case _: - zv_g: llvmlite.Value | t.CPtr = llvmlite.ConstZero( - pool, ret_ty_g2) - if zv_g is not None: - llvmlite.build_ret(builder, zv_g) - # ok 块:继续 - llvmlite.position_at_end(builder, ok_bb_g) - return result - - # ============================================================ - # isinstance - 运行时 vtable 子类集合比较(2026-08-10) - # - # CVTable 对象头部 vtable 指针唯一标识对象实际类。isinstance(obj, Cls) - # 语义 = Cls 是实际类的祖先(实际类 == Cls 或继承自 Cls)。运行时只能 - # 拿到实际类 vtable 地址,无法向上推导祖先链,因此在编译期沿 - # StructEntry.ParentNames 反向 BFS 枚举 Cls 的全部已知子类(含自身), - # 运行时比较 obj->vtable ∈ {Cls 子类 vtable 地址集合}。 - # NoVTable / 未知类回退编译时静态判断(obj 静态类型 MRO 判断)。 - # ============================================================ - - - - def _translate_isinstance(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - obj_node: ast.AST | t.CPtr, - cls_node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """isinstance(obj, Cls):运行时 vtable 子类集合比较,返回 i1""" - if obj_node is None or cls_node is None: - # 参数缺失即调用错误:fail-fast,绝不返回 True 掩盖 - HandlesType.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError") - obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, obj_node, None, 0, trans) - if obj_val is None or obj_val.Ty is None: - # obj 类型推断失败:fail-fast,绝不返回 True 掩盖 - HandlesType.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError") - # 对象指针规整:二级指针(变量 alloca / 联合 Class|t.CPtr)先 load - obj_ptr: llvmlite.Value | t.CPtr = obj_val - match obj_val.Ty: - case llvmlite.LLVMType.Ptr(inner_ty): - match inner_ty: - case llvmlite.LLVMType.Ptr(_): - loaded: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, inner_ty, obj_val) - if loaded is not None: - obj_ptr = loaded - case _: - pass - obj_is_ptr: int = HandlesExpr.is_ptr_type(obj_ptr.Ty) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty) - # 对象 vtable 指针惰性读取(首个 CVTable 类比较时执行一次) - vtable_ptr: llvmlite.Value | t.CPtr = None - vtable_ready: int = 0 - res: llvmlite.Value | t.CPtr = None - cls_names: t.CSizeT | t.CPtr = self._extract_isinstance_class_names(pool, cls_node) - if cls_names is None: - # 类名提取失败:fail-fast,绝不返回 True 掩盖 - HandlesType.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError") - ci: int = 0 - while cls_names[ci] != 0: - cn: str = (str | t.CPtr)(t.CVoid(cls_names[ci], t.CPtr)) - if cn is not None: - if HandlesStruct.is_novtable_by_name(cn) != 0 \ - or HandlesStruct.has_vtable_by_name(cn) == 0: - # NoVTable / 未知类 → 编译时静态判断(obj 静态类型 MRO) - st: int = self._isinstance_compile_time(pool, obj_ptr, cn) - c1: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, 1, 1 if st > 0 else 0) - if res is None: - res = c1 - else: - res = llvmlite.build_or(builder, res, c1) - elif obj_is_ptr != 0: - # CVTable → 运行时 vtable 比较(读对象头部 vtable 指针) - if vtable_ready == 0: - vtable_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, obj_ptr, i8_ptr_ptr_ty) - if vtable_slot is not None: - vtable_ptr = llvmlite.build_load(builder, i8_ptr_ty, vtable_slot) - vtable_ready = 1 - if vtable_ptr is not None: - subs: t.CSizeT | t.CPtr = self._collect_subclass_vtable_classes(pool, cn) - if subs is not None: - k: int = 0 - while subs[k] != 0: - scn: str = (str | t.CPtr)(t.CVoid(subs[k], t.CPtr)) - if scn is not None: - sub_i8: llvmlite.Value | t.CPtr = self._make_vtable_ref_i8( - pool, builder, mod, scn, trans) - if sub_i8 is not None: - cmp: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_EQ, vtable_ptr, sub_i8) - if cmp is not None: - if res is None: - res = cmp - else: - res = llvmlite.build_or(builder, res, cmp) - k += 1 - ci += 1 - if res is None: - # 未产生任何比较结果(obj 非指针且类全部为 CVTable):推断失败,fail-fast - HandlesType.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError") - return res - - - def _extract_isinstance_class_names(self, pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr) -> t.CSizeT | t.CPtr: - """从 isinstance 第二参数提取类名数组(Name→id / Attribute→attr / Tuple→遍历)""" - arr: t.CSizeT | t.CPtr = pool.alloc(8 * 16) - if arr is None: - return None - # 全数组清零:pool 分配内存非零时,未初始化槽位会被 while cls_names[ci]!=0 - # 误当类名指针解引用 → 段错误 - string.memset(arr, 0, 8 * 16) - arr[0] = 0 - if node is None: - return arr - count: int = 0 - k: int = node.kind() - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm.id is not None: - arr[0] = t.CSizeT(nm.id) - elif k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at.attr is not None: - arr[0] = t.CSizeT(at.attr) - elif k == ast.ASTKind.Tuple: - tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(node) - elts: list[ast.AST | t.CPtr] | t.CPtr = tp.elts - if elts is not None: - n: t.CSizeT = len(elts) - for i in range(n): - if count >= 15: - break - elt: ast.AST | t.CPtr = elts.get(i) - if elt is None: - continue - ek: int = elt.kind() - if ek == ast.ASTKind.Name: - enm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(elt) - if enm.id is not None: - arr[count] = t.CSizeT(enm.id) - count += 1 - elif ek == ast.ASTKind.Attribute: - eat: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(elt) - if eat.attr is not None: - arr[count] = t.CSizeT(eat.attr) - count += 1 - arr[count] = 0 - return arr - - - def _collect_subclass_vtable_classes(self, pool: memhub.MemBuddy | t.CPtr, - class_name: str) -> t.CSizeT | t.CPtr: - """反向 BFS 收集目标类及全部子类(含自身,仅 HasVTable==1),返回 0 结尾数组""" - if class_name is None: - return None - names: t.CSizeT | t.CPtr = pool.alloc(8 * (ISINSTANCE_CLASS_MAX + 1)) - queue: t.CSizeT | t.CPtr = pool.alloc(8 * ISINSTANCE_CLASS_MAX) - visited: t.CSizeT | t.CPtr = pool.alloc(8 * ISINSTANCE_CLASS_MAX) - if names is None or queue is None or visited is None: - return None - string.memset(names, 0, 8 * (ISINSTANCE_CLASS_MAX + 1)) - string.memset(queue, 0, 8 * ISINSTANCE_CLASS_MAX) - string.memset(visited, 0, 8 * ISINSTANCE_CLASS_MAX) - qcount: int = 0 - outcount: int = 0 - vcount: int = 0 - queue[0] = t.CSizeT(class_name) - qcount = 1 - while qcount > 0: - qcount -= 1 - cur_addr: t.CSizeT = queue[qcount] - cur: str = (str | t.CPtr)(t.CVoid(cur_addr, t.CPtr)) - if cur is None: - continue - dup: int = 0 - for vi in range(vcount): - va: t.CSizeT = visited[vi] - if va != 0: - vn: str = (str | t.CPtr)(t.CVoid(va, t.CPtr)) - if vn is not None and string.strcmp(vn, cur) == 0: - dup = 1 - break - if dup != 0: - continue - if vcount < ISINSTANCE_CLASS_MAX: - visited[vcount] = t.CSizeT(cur) - vcount += 1 - centry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(cur) - if centry is not None and centry.HasVTable != 0: - if outcount < ISINSTANCE_CLASS_MAX: - names[outcount] = t.CSizeT(cur) - outcount += 1 - # 子类入队:遍历全部已注册 struct,ParentNames 含 cur 者 - scnt: int = HandlesStruct.get_struct_count() - for i in range(scnt): - e2: HandlesStruct.StructEntry | t.CPtr = HandlesStruct._get_struct_entry(i) - if e2 is None or e2.Name is None: - continue - if e2.ParentCount > 0 and e2.ParentNames is not None: - parr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(e2.ParentNames, t.CPtr)) - for j in range(e2.ParentCount): - pa: t.CSizeT = parr[j] - if pa != 0: - pn: str = (str | t.CPtr)(t.CVoid(pa, t.CPtr)) - if pn is not None and string.strcmp(pn, cur) == 0: - if qcount < ISINSTANCE_CLASS_MAX: - queue[qcount] = t.CSizeT(e2.Name) - qcount += 1 - break - names[outcount] = 0 - return names - - - def _make_vtable_ref_i8(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """构造类 vtable 地址引用(i8*):本模块已定义直接引用,跨模块声明 external""" - if class_name is None: - return None - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - buf: str = pool.alloc(256) - if buf is None: - return None - viperlib.snprintf(buf, 256, "%s.vtable", class_name) - vn: str = (str | t.CPtr)(buf) - sha1: str = HandlesStruct.get_struct_sha1(class_name) - if sha1 is None: - if trans is None: - return None - sha1 = trans.ModuleSha1 - if sha1 is None: - return None - mangled: str = HandlesFunctions._mangle_name_with_sha1(sha1, vn) - ref_name: str = pool.alloc(256) - if ref_name is None: - return None - # vtable 名含 sha1 点号前缀,一律 @"..." 引号形式 - viperlib.snprintf(ref_name, 256, "@\"%s\"", mangled) - gv: llvmlite.GlobalVariable | t.CPtr = HandlesExpr.find_global_in_module(mod, mangled) - ref_ty: llvmlite.LLVMType | t.CPtr = None - if gv is not None: - # 本模块已定义 vtable(constant {i8* x N})→ 引用类型 Ptr(struct) - ref_ty = llvmlite.Ptr(pool, gv.Ty) - else: - # 跨模块:声明 @mangled = external global i8*,引用类型 i8** - gv2: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable( - pool, mangled, i8_ptr_ty) - if gv2 is None: - return None - llvmlite.module_add_global(mod, gv2) - ref_ty = llvmlite.Ptr(pool, i8_ptr_ty) - ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, ref_ty, ref_name) - if ref is None: - return None - return llvmlite.build_bitcast(builder, ref, i8_ptr_ty) - - - def _isinstance_compile_time(self, pool: memhub.MemBuddy | t.CPtr, - obj_ptr: llvmlite.Value | t.CPtr, - class_name: str) -> int: - """编译时静态判断:obj 静态类型 == class_name 或 class_name 在其 MRO 中""" - if obj_ptr is None or obj_ptr.Ty is None or class_name is None: - return 0 - match obj_ptr.Ty: - case llvmlite.LLVMType.Ptr(obj_struct_ty): - sname: str = HandlesStruct.get_class_name_by_type(pool, obj_struct_ty) - if sname is not None: - if string.strcmp(sname, class_name) == 0: - return 1 - mro: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, sname) - if mro is not None: - k: int = 0 - while mro[k] != 0: - mn: str = (str | t.CPtr)(t.CVoid(mro[k], t.CPtr)) - if mn is not None and string.strcmp(mn, class_name) == 0: - return 1 - k += 1 - case _: - pass - return 0 - - # ============================================================ - # P4 簇 5+6 迁移方法(函数体来自 HandlesExprCall.vp: - # 闭包调用/函数指针/printf/print/stdarg 糖/变长参数提升/函数表/全局注册表) - # 本模块函数调用改 self.,外部模块调用保留模块前缀,全局变量改 self 字段 - # ============================================================ - - - - def translate_closure_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - closure_alloca: llvmlite.Value | t.CPtr, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """通过闭包指针间接调用(支持带参 lambda:i32(i8*, args...))""" - if builder is None or closure_alloca is None: - return None - - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - - # 1. 加载闭包指针 (i8*) - closure_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, closure_alloca) - if closure_ptr is None: - return None - - # 2. 加载 fn_ptr (offset 0): bitcast to i8**, load i8* - fn_ptr_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, closure_ptr, llvmlite.Ptr(pool, i8_ptr_ty)) - if fn_ptr_addr is None: - return None - fn_raw: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, fn_ptr_addr) - if fn_raw is None: - return None - - # 3. 加载 env_ptr (offset 8): GEP i8, closure, 8; load i8* - eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 8) - env_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, closure_ptr, eight_val) - if env_addr is None: - return None - env_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, env_addr) - if env_ptr is None: - return None - - # 4. 构建参数:env 头 + 实参尾(带参 lambda 时翻译实参) - total_args: int = 1 - arg_head: llvmlite.Value | t.CPtr = env_ptr - arg_tail: llvmlite.Value | t.CPtr = env_ptr - param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) - pn_tail: llvmlite.ParamNode | t.CPtr = param_node - if can > 0 and cargs is not None and trans is not None: - for ai in range(can): - arg: ast.AST | t.CPtr = cargs.get(ai) - if arg is None: - continue - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg, None, 0, trans) - if arg_val is None or arg_val.Ty is None: - continue - arg_val.Next = None - if arg_tail is not None: - arg_tail.Next = arg_val - arg_tail = arg_val - pn_new: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, arg_val.Ty) - if pn_new is not None: - pn_tail.Next = pn_new - pn_tail = pn_new - total_args += 1 - if total_args == 1: - env_ptr.Next = None - - # 5. bitcast fn_raw 到函数指针类型 i32(i8*, [args...])* - func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, param_node, total_args) - func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty) - fn_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, fn_raw, func_ptr_ty) - if fn_typed is None: - return None - - # 6. 间接调用: call i32 %fn_typed(env, args...) - return llvmlite.build_call_indirect(builder, fn_typed, arg_head, total_args, i32_ty) - - - def _is_func_ptr_alloca(self, alloca: llvmlite.Value | t.CPtr) -> int: - """判断 alloca 是否为函数指针变量(类型 Ptr(Ptr(i8))),1=是 / 0=否""" - if alloca is None or alloca.Ty is None: - return 0 - if HandlesExpr.is_ptr_type(alloca.Ty) == 0: - return 0 - pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee - if pointee is None or HandlesExpr.is_ptr_type(pointee) == 0: - return 0 - inner: llvmlite.LLVMType | t.CPtr = pointee.Pointee - if inner is None or HandlesExpr.is_ptr_type(inner) != 0: - return 0 - return 1 - - - def _ensure_closure_names(self) -> int: - """确保闭包名表已分配,0 失败""" - if self.ClosureNames is not None: - return 1 - self.ClosureNames = CompilerFactory.get_perm_pool().alloc(64 * MAX_CLOSURE_NAMES) - if self.ClosureNames is None: - return 0 - string.memset(self.ClosureNames, 0, 64 * MAX_CLOSURE_NAMES) - return 1 - - - def register_closure_name(self, name: str) -> int: - """注册嵌套函数(闭包变量)名,0 成功""" - if name is None: - return 1 - if self._ensure_closure_names() == 0: - return 1 - if self.ClosureCount >= MAX_CLOSURE_NAMES: - return 1 - idx: t.CSizeT = t.CSizeT(self.ClosureCount) * 64 - string.strncpy(self.ClosureNames + idx, name, 63) - self.ClosureCount += 1 - return 0 - - - def is_closure_name(self, name: str) -> int: - """检查 name 是否已注册为闭包变量名,1=是 / 0=否""" - if name is None or self.ClosureNames is None: - return 0 - i: t.CSizeT - for i in range(self.ClosureCount): - if string.strcmp(self.ClosureNames + i * 64, name) == 0: - return 1 - return 0 - - - def _ensure_funcptr_sigs(self) -> int: - """确保函数指针签名表已分配(stdlib.malloc,懒初始化)""" - if self.FuncptrNames is not None: - return 1 - self.FuncptrNames = CompilerFactory.get_perm_pool().alloc(64 * MAX_FUNC_PTR_SIGS) - self.FuncptrRets = CompilerFactory.get_perm_pool().alloc(8 * MAX_FUNC_PTR_SIGS) - if self.FuncptrNames is None or self.FuncptrRets is None: - return 0 - string.memset(self.FuncptrNames, 0, 64 * MAX_FUNC_PTR_SIGS) - return 1 - - - def register_func_ptr_sig(self, name: str, - ret_ty: llvmlite.LLVMType | t.CPtr) -> int: - """注册函数指针变量的返回类型签名,0 成功""" - if name is None or ret_ty is None: - return 1 - if self._ensure_funcptr_sigs() == 0: - return 1 - if self.FuncptrCount >= MAX_FUNC_PTR_SIGS: - return 1 - idx: t.CSizeT = t.CSizeT(self.FuncptrCount) * 64 - # 槽位定长 64 字节,与 register_closure_name 一致用 strncpy 钳制防越界 - string.strncpy(self.FuncptrNames + idx, name, 63) - # ret_ty 是调用方 pool 分配的裸 LLVMType,1a 每文件 reset 后悬空; - # 深拷贝到 perm_pool(lookup_func_ptr_ret 跨文件读取) - ret_copy_fp: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( - CompilerFactory.get_perm_pool(), ret_ty) - if ret_copy_fp is not None: - self.FuncptrRets[self.FuncptrCount] = t.CUInt64T(ret_copy_fp) - else: - self.FuncptrRets[self.FuncptrCount] = t.CUInt64T(ret_ty) - self.FuncptrCount += 1 - return 0 - - - def lookup_func_ptr_ret(self, name: str) -> llvmlite.LLVMType | t.CPtr: - """查函数指针变量的返回类型,None=未注册(调用时默认 i32)""" - if name is None or self.FuncptrNames is None: - return None - for i in range(self.FuncptrCount): - idx: t.CSizeT = t.CSizeT(i) * 64 - if string.strcmp(self.FuncptrNames + idx, name) == 0: - return (llvmlite.LLVMType | t.CPtr)( - t.CVoid(self.FuncptrRets[i], t.CPtr)) - return None - - - def _translate_func_ptr_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - fp_alloca: llvmlite.Value | t.CPtr, - func_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """函数指针变量间接调用,返回结果 Value""" - if builder is None or fp_alloca is None: - return None - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - - # 1. load 函数地址 (i8*) - fn_i8: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, fp_alloca) - if fn_i8 is None: - return None - - # 2. 翻译实参并链接为 Value 链表 - head: llvmlite.Value | t.CPtr = None - tail: llvmlite.Value | t.CPtr = None - arg_count: int = 0 - ai: t.CSizeT - for ai in range(can): - arg: ast.AST | t.CPtr = cargs.get(ai) - if arg is not None: - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg, None, 0, trans) - if arg_val is not None: - arg_val.Next = None - if head is None: - head = arg_val - else: - tail.Next = arg_val - tail = arg_val - arg_count += 1 - - # 3. 按实参类型 + 注册的返回类型构造签名(未注册即 t.Callable 注解缺失,fail-fast) - ret_ty: llvmlite.LLVMType | t.CPtr = self.lookup_func_ptr_ret(func_name) - if ret_ty is None: - HandlesType.fatal_error( - None, - f"函数指针变量 '{func_name}' 的返回类型未注册(t.Callable 注解缺失)", - "TypeError") - ret_ty = i32_ty - fp_first: llvmlite.ParamNode | t.CPtr = None - fp_prev: llvmlite.ParamNode | t.CPtr = None - cur_v: llvmlite.Value | t.CPtr = head - for pi in range(arg_count): - if cur_v is None: - break - cur_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(cur_v) - pn2: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, cur_ty) - if pn2 is not None: - if fp_first is None: - fp_first = pn2 - if fp_prev is not None: - llvmlite.paramnode_set_next(fp_prev, pn2) - fp_prev = pn2 - cur_v = llvmlite.value_get_next(cur_v) - - func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, ret_ty, fp_first, arg_count) - if func_ty is None: - return None - func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty) - - # 4. bitcast i8* → 函数指针类型,间接调用 - fn_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, fn_i8, func_ptr_ty) - if fn_typed is None: - return None - return llvmlite.build_call_indirect(builder, fn_typed, head, arg_count, ret_ty) - - - def translate_printf_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None): - """翻译 printf 调用(特殊处理格式字符串)""" - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cargs is None: - return - can: t.CSizeT = len(cargs) - if can == 0: - return - - arg0: ast.AST | t.CPtr = cargs.get(0) - if arg0 is None: - return - - fmt_str: str = None - arg0_kind: int = arg0.kind() - if arg0_kind == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg0) - if cn.const_kind == ast.CONST_STR: - fmt_str = cn.str_val - - if fmt_str is None: - return - - fmt_ptr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string( - builder, pool, mod, fmt_str, trans) - if fmt_ptr is None: - return - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - - # 翻译额外参数并链接 - prev: llvmlite.Value | t.CPtr = fmt_ptr - for ai in range(1, can): - arg: ast.AST | t.CPtr = cargs.get(ai) - if arg is not None: - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg, None, 0, trans) - if arg_val is not None: - # C ABI integer promotion: i8/i16 → i32(printf 变参函数要求) - arg_bits: int = HandlesExpr.get_llvm_type_bits(arg_val.Ty) - if arg_bits != 0 and arg_bits < 32: - arg_val = HandlesExpr.coerce_to_type(builder, arg_val, i32_ty, arg) - # C ABI float promotion: float → double(printf 变参函数要求) - arg_fbits: int = HandlesExpr.get_llvm_float_bits(arg_val.Ty) - if arg_fbits != 0 and arg_fbits < 64: - double_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) - arg_val = HandlesExpr.coerce_to_type(builder, arg_val, double_ty, arg) - arg_val.Next = None - prev.Next = arg_val - prev = arg_val - prev.Next = None - - # is_variadic=1: 生成带显式函数类型签名的 call(如 call i32 (i8*, ...) @printf), - # 让 llc 识别为 variadic 调用,生成正确的 Win64 ABI 代码(浮点参数同时传 XMM 和整数寄存器) - llvmlite.build_call(builder, "printf", fmt_ptr, can, i32_ty, 1) - - - def translate_print_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None): - """翻译 print 调用(类型感知格式化 + 默认换行)""" - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cargs is None: - return - - FMT_BUF_SIZE: t.CSizeT = 256 - fmt_buf: bytes = stdlib.malloc(FMT_BUF_SIZE) - if fmt_buf is None: - return - fmt_buf[0] = '\0' - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - dbl_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) - - can: t.CSizeT = len(cargs) - arg_head: llvmlite.Value | t.CPtr = None - arg_tail: llvmlite.Value | t.CPtr = None - arg_count: int = 1 # 格式串本身是第 1 个 printf 参数 - - for ai in range(can): - arg: ast.AST | t.CPtr = cargs.get(ai) - if arg is None: - continue - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg, None, 0, trans) - if arg_val is None or arg_val.Ty is None: - # fail-fast:print 参数翻译失败必须终止编译,绝不在格式串写 - # 误导为数据问题而非编译器 bug。 - fb_pp: str = VLogger.fmt_buf() - if fb_pp is not None: - viperlib.snprintf(fb_pp, 1024, "print 参数翻译失败(表达式返回 None): [arg=%d]", ai) - VLogger.error(fb_pp, "PRINT") - HandlesType.fatal_error(arg, "print 参数翻译失败(表达式返回 None)", "TypeError") - return - - # 数组名(如 print(l),l: t.CArray[t.CChar, N]): - # translate_value 会 load 出数组值([N x T]),print 无法格式化; - # 按数组退化语义取数组 alloca 地址——字符数组 → %s(打印字符串内容), - # 其他元素类型 → 0x%llx(打印数组地址)。 - array_ptr: llvmlite.Value | t.CPtr = None - array_elem_bits: int = 0 - if arg.kind() == ast.ASTKind.Name and trans is not None: - anm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg) - if anm.id is not None: - arr_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, anm.id) - if arr_alloca is not None and arr_alloca.Ty is not None \ - and HandlesExpr.is_ptr_type(arr_alloca.Ty) != 0: - arr_pointee: llvmlite.LLVMType | t.CPtr = arr_alloca.Ty.Pointee - if arr_pointee is not None: - match arr_pointee: - case llvmlite.LLVMType.Array(arr_et, arr_n): - array_ptr = arr_alloca - array_elem_bits = HandlesExpr.get_llvm_type_bits(arr_et) - case _: - pass - - token: str = None - chain_arg: int = 1 # 1=该 token 消耗一个参数,0=纯文本 - arg_bits: int = HandlesExpr.get_llvm_type_bits(arg_val.Ty) - arg_fbits: int = HandlesExpr.get_llvm_float_bits(arg_val.Ty) - - if array_ptr is not None: - # 数组退化:字符数组 → %s(bitcast [N x i8]* 到 i8*);其他 → 0x%llx - if array_elem_bits == 8: - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - token = "%s" - arg_val = llvmlite.build_bitcast(builder, array_ptr, i8_ptr_ty) - else: - token = "0x%llx" - arg_val = llvmlite.build_ptrtoint(builder, array_ptr, i64_ty) - elif HandlesExpr.is_ptr_type(arg_val.Ty) != 0: - # i8*(str/bytes)→ %s;其他指针 → 0x%llx - pointee: llvmlite.LLVMType | t.CPtr = arg_val.Ty.Pointee - if pointee is not None and HandlesExpr.get_llvm_type_bits(pointee) == 8: - token = "%s" - else: - token = "0x%llx" - arg_val = llvmlite.build_ptrtoint(builder, arg_val, i64_ty) - elif arg_bits != 0: - if arg_bits == 1: - token = "%d" - arg_val = llvmlite.build_zext(builder, arg_val, i32_ty) - elif arg_bits == 8: - token = "%d" - arg_val = llvmlite.build_sext(builder, arg_val, i32_ty) - elif arg_bits == 16: - token = "%d" - arg_val = llvmlite.build_sext(builder, arg_val, i32_ty) - elif arg_bits == 32: - token = "%d" - else: - token = "%lld" - elif arg_fbits != 0: - token = "%f" - if arg_fbits < 64: - arg_val = llvmlite.build_fpext(builder, arg_val, dbl_ty) - else: - # 结构体值/数组/函数等 → "(unknown)",不传参 - token = "(unknown)" - chain_arg = 0 - - # 追加格式 token - if string.strlen(fmt_buf) < FMT_BUF_SIZE - 16: - viperlib.snprintf(fmt_buf + string.strlen(fmt_buf), 16, "%s", token) - # 链接参数 - if chain_arg != 0: - arg_val.Next = None - if arg_tail is None: - arg_head = arg_val - else: - arg_tail.Next = arg_val - arg_tail = arg_val - arg_count += 1 - - # 追加默认换行(Python print 默认 end="\n") - if string.strlen(fmt_buf) < FMT_BUF_SIZE - 2: - viperlib.snprintf(fmt_buf + string.strlen(fmt_buf), 2, "\n") - - fmt_ptr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string( - builder, pool, mod, fmt_buf, trans) - stdlib.free(fmt_buf) - if fmt_ptr is None: - return - fmt_ptr.Next = arg_head - # is_variadic=1: 带显式函数类型签名(C ABI 变参调用) - llvmlite.build_call(builder, "printf", fmt_ptr, arg_count, i32_ty, 1) - - - def init_func_table(self, pool: memhub.MemBuddy | t.CPtr, - max_count: int) -> HandlesExprCall.FuncEntry | t.CPtr: - """分配并清零函数表数组""" - size: t.CSizeT = max_count * HandlesExprCall.FuncEntry.__sizeof__() - funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = pool.alloc(size) - if funcs_ptr is not None: - string.memset(funcs_ptr, 0, size) - return funcs_ptr - - - def find_func_in_table(self, funcs: HandlesExprCall.FuncEntry | t.CPtr, - func_count: int, - name: str) -> llvmlite.Function | t.CPtr: - """在函数表中按名称查找,返回 Function 指针或 None""" - if name is None or funcs is None: - return None - entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__() - for i in range(func_count): - entry_addr: t.CUInt64T = t.CUInt64T(funcs) + i * entry_size - entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - if entry.Name is not None: - if string.strcmp(entry.Name, name) == 0: - return entry.Func - return None - - - def add_func_to_table(self, funcs: HandlesExprCall.FuncEntry | t.CPtr, - func_count: int, - name: str, - func: llvmlite.Function | t.CPtr, - max_count: int, - defaults: t.CVoid | t.CPtr = None, - default_count: int = 0, - param_count: int = 0, - pool: memhub.MemBuddy | t.CPtr = None) -> int: - """添加函数到函数表,返回 0 成功 - - Args: - defaults: ast.Arguments.defaults 列表节点指针,None=无默认值 - default_count: 默认值数量(len(defaults)) - param_count: 形参数量(不含 self,len(args.args)) - pool: 内存池(用于生成 TypeStr;None 时 TypeStr 为空,vtable 回退读 Func 对象) - """ - if name is None or func is None or funcs is None: - return 1 - if func_count >= max_count: - return 1 - entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__() - entry_addr: t.CUInt64T = t.CUInt64T(funcs) + func_count * entry_size - entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - entry.Name = name - entry.Func = func - entry.Defaults = defaults - entry.DefaultCount = default_count - entry.ParamCount = param_count - # 同时注册到全局函数表(供跨模块 vtable 初始化查找) - self._register_global_func(name, func, pool) - # 同时注册到全局默认参数表(供跨模块调用时填充默认值) - if default_count > 0: - self._register_global_defaults(name, defaults, default_count, param_count) - return 0 - - - def _init_global_func_table(self) -> int: - """初始化全局函数表(用 stdlib.malloc 分配,生命周期=整个程序)""" - if self.GlobalFuncs is not None: - return 1 - size: t.CSizeT = GLOBAL_FUNC_MAX * HandlesExprCall.FuncEntry.__sizeof__() - self.GlobalFuncs = CompilerFactory.get_perm_pool().alloc(size) - if self.GlobalFuncs is None: - return 0 - string.memset(self.GlobalFuncs, 0, size) - self.GlobalFuncCount = 0 - return 1 - - - def _build_func_type_str(self, pool: memhub.MemBuddy | t.CPtr, - func: llvmlite.Function | t.CPtr) -> str: - """生成函数类型文本(stdlib 分配)""" - if func is None: - return None - # 类型文本可能较长(SHA1 限定命名结构体 + 多参数),用 1024 缓冲 - ty_buf: str = pool.alloc(1024) - if ty_buf is None: - return None - ty_buf[0] = '\0' - - # 返回类型 - ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(func) - ret_part: str = pool.alloc(512) - if ret_part is not None and ret_ty is not None: - ret_part[0] = '\0' - llvmlite.TypePrint(ret_part, 512, ret_ty, pool) - self._asm_append_cstr(ty_buf, 1024, ret_part) - self._asm_append_cstr(ty_buf, 1024, " (") - - # 参数类型(全部经 _asm_append_cstr 有界追加,防止 strcat 无界写穿 1024 缓冲) - cur: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) - first: int = 1 - param_part: str = pool.alloc(512) - while cur is not None: - if first == 0: - self._asm_append_cstr(ty_buf, 1024, ", ") - if param_part is not None: - param_part[0] = '\0' - param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur) - if param_ty is not None: - llvmlite.TypePrint(param_part, 512, param_ty, pool) - self._asm_append_cstr(ty_buf, 1024, param_part) - cur = llvmlite.param_get_next(cur) - first = 0 - self._asm_append_cstr(ty_buf, 1024, ")") - - # 深拷贝到 stdlib 区(TypeStr 跨文件永久存活) - ts_len: t.CSizeT = string.strlen(ty_buf) - ts_copy: str = CompilerFactory.get_perm_pool().alloc(ts_len + 1) - if ts_copy is None: - return None - string.strcpy(ts_copy, ty_buf) - return ts_copy - - - def _register_global_func(self, name: str, func: llvmlite.Function | t.CPtr, - pool: memhub.MemBuddy | t.CPtr = None) -> int: - """注册函数到全局表(已存在则跳过),返回 0 成功 - - 直接操作全局表,不调用 add_func_to_table,避免递归。 - pool 用于生成 TypeStr(None 时 TypeStr 为空)。 - """ - if name is None or func is None: - return 1 - if self._init_global_func_table() == 0: - return 1 - # 已存在则跳过(避免重复) - if self.find_func_in_table(self.GlobalFuncs, self.GlobalFuncCount, name) is not None: - return 0 - if self.GlobalFuncCount >= GLOBAL_FUNC_MAX: - return 1 - # 直接写入全局表(不调用 add_func_to_table,避免递归) - entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__() - entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalFuncs) + self.GlobalFuncCount * entry_size - entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - # Name 深拷贝到 stdlib 区:全局表跨文件永久存活,pool 内名字会被 1b 每文件 - # reset_to(mark1) 回收导致悬空(vtable 生成 find_func_global 后 strcmp 崩溃) - name_len: t.CSizeT = string.strlen(name) - name_copy: str = CompilerFactory.get_perm_pool().alloc(name_len + 1) - if name_copy is None: - return 1 - string.strcpy(name_copy, name) - entry.Name = name_copy - entry.Func = func - # TypeStr 不在此生成:函数参数在 add_func_to_table 之后才添加, - # 需由调用方在参数添加完成后调用 update_global_func_typestr 补全。 - self.GlobalFuncCount += 1 - return 0 - - - def update_global_func_typestr(self, pool: memhub.MemBuddy | t.CPtr, - name: str, - func: llvmlite.Function | t.CPtr) -> int: - """更新全局函数表的 TypeStr(在函数参数全部添加完成后调用) - - 调用时机:add_func_to_table 注册后、llvmlite.add_param 全部执行完。 - 生成 ret_ty (param1_ty, ...) 类型文本(stdlib 深拷贝), - 供 vtable 生成在 func 被 1b reset 后使用。 - """ - if name is None or func is None: - return 1 - entry: HandlesExprCall.FuncEntry | t.CPtr = self.find_func_entry_global(name) - if entry is None: - return 1 - entry.TypeStr = self._build_func_type_str(pool, func) - return 0 - - - def find_func_global(self, name: str) -> llvmlite.Function | t.CPtr: - """在全局函数表中按名称查找,返回 Function 指针或 None""" - if name is None or self.GlobalFuncs is None: - return None - return self.find_func_in_table(self.GlobalFuncs, self.GlobalFuncCount, name) - - - def find_func_entry_global(self, name: str) -> HandlesExprCall.FuncEntry | t.CPtr: - """在全局函数表中按名称查找,返回完整 FuncEntry(含 TypeStr)或 None""" - if name is None or self.GlobalFuncs is None: - return None - entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__() - for i in range(self.GlobalFuncCount): - entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalFuncs) + i * entry_size - entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - if entry.Name is not None: - if string.strcmp(entry.Name, name) == 0: - return entry - return None - - - def _init_global_defaults_table(self) -> int: - """初始化全局默认参数表""" - if self.GlobalDefaults is not None: - return 1 - size: t.CSizeT = GLOBAL_DEFAULTS_MAX * HandlesExprCall.FuncDefaultsEntry.__sizeof__() - self.GlobalDefaults = CompilerFactory.get_perm_pool().alloc(size) - if self.GlobalDefaults is None: - return 0 - string.memset(self.GlobalDefaults, 0, size) - self.GlobalDefaultsCount = 0 - return 1 - - - def _register_global_defaults(self, name: str, - defaults: t.CVoid | t.CPtr, - default_count: int, - param_count: int) -> int: - """注册函数默认参数到全局表,返回 0 成功 - - 注册时提取每个默认值 Constant 的常量快照到 stdlib(ConstKinds/ConstInts/ConstStrs), - 跨模块调用时优先用快照重建常量 IR,避免读取被 reset 回收的 pool 内 AST。 - """ - if name is None or defaults is None: - return 1 - if self._init_global_defaults_table() == 0: - return 1 - # 已存在则跳过 - if self.find_func_defaults(name) is not None: - return 0 - if self.GlobalDefaultsCount >= GLOBAL_DEFAULTS_MAX: - return 1 - entry_size: t.CSizeT = HandlesExprCall.FuncDefaultsEntry.__sizeof__() - entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalDefaults) + self.GlobalDefaultsCount * entry_size - entry: HandlesExprCall.FuncDefaultsEntry | t.CPtr = (HandlesExprCall.FuncDefaultsEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - # Name 深拷贝到 stdlib(全局表跨文件永久存活) - nm_len: t.CSizeT = string.strlen(name) - nm_copy: str = CompilerFactory.get_perm_pool().alloc(nm_len + 1) - if nm_copy is None: - return 1 - string.strcpy(nm_copy, name) - entry.Name = nm_copy - entry.Defaults = defaults - entry.DefaultCount = default_count - entry.ParamCount = param_count - # 提取常量快照到 stdlib - if default_count > 0: - kinds: t.CInt | t.CPtr = CompilerFactory.get_perm_pool().alloc(default_count * 4) - ints: t.CInt64T | t.CPtr = CompilerFactory.get_perm_pool().alloc(default_count * 8) - strs: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(default_count * 8) - if kinds is not None and ints is not None and strs is not None: - string.memset(kinds, 0, default_count * 4) - string.memset(ints, 0, default_count * 8) - string.memset(strs, 0, default_count * 8) - dl: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(defaults), t.CPtr)) - di: int - for di in range(default_count): - dnode: ast.AST | t.CPtr = dl.get(di) - if dnode is not None and dnode.kind() == ast.ASTKind.Constant: - dcn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(dnode) - kinds[di] = dcn.const_kind - ints[di] = dcn.int_val - if dcn.const_kind == ast.CONST_STR and dcn.str_val is not None: - slen: t.CSizeT = string.strlen(dcn.str_val) - scopy: str = CompilerFactory.get_perm_pool().alloc(slen + 1) - if scopy is not None: - string.strcpy(scopy, dcn.str_val) - strs[di] = t.CSizeT(scopy) - elif dnode is not None and dnode.kind() == ast.ASTKind.Name: - # CDefine Name 引用默认值(如 share: ULONG = SHARE_READ): - # 注册时求值 CDefine 存快照——否则跨模块重建时快照为空 - # → "跨模块默认参数无法重建"(FileIoTest File.__init__ 根因)。 - # 仅支持已注册的整型 CDefine;未注册保持 kinds=0(重建时 - # 仍 fail-fast,绝不静默回退)。 - dnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(dnode) - if dnm.id is not None: - cdef_v: int = HandlesType.lookup_cdefine_constant(dnm.id) - if HandlesType.is_cdefine_found() != 0: - kinds[di] = ast.CONST_INT - ints[di] = cdef_v - entry.ConstKinds = kinds - entry.ConstInts = ints - entry.ConstStrs = strs - self.GlobalDefaultsCount += 1 - return 0 - - - def find_func_defaults(self, name: str) -> HandlesExprCall.FuncDefaultsEntry | t.CPtr: - """按函数名查找默认参数信息,返回 FuncDefaultsEntry 或 None""" - if name is None or self.GlobalDefaults is None: - return None - entry_size: t.CSizeT = HandlesExprCall.FuncDefaultsEntry.__sizeof__() - i: int = 0 - while i < self.GlobalDefaultsCount: - entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalDefaults) + i * entry_size - entry: HandlesExprCall.FuncDefaultsEntry | t.CPtr = (HandlesExprCall.FuncDefaultsEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - if entry.Name is not None: - if string.strcmp(entry.Name, name) == 0: - return entry - i += 1 - return None - - - def _build_const_from_snapshot(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - gd_entry: HandlesExprCall.FuncDefaultsEntry | t.CPtr, - di: int, - trans: HT.Translator | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr) -> llvmlite.Value | t.CPtr: - """从快照重建第 di 个默认值常量 IR""" - if gd_entry is None or gd_entry.ConstKinds is None or gd_entry.ConstInts is None: - return None - if di < 0 or di >= gd_entry.DefaultCount: - return None - kind: t.CInt = gd_entry.ConstKinds[di] - ival: t.CInt64T = gd_entry.ConstInts[di] - if kind == ast.CONST_INT: - if ival > 2147483647 or ival < -2147483648: - return llvmlite.const_int64(pool, ival) - return llvmlite.const_int32(pool, ival) - elif kind == ast.CONST_BOOL: - if ival != 0: - return llvmlite.const_int32(pool, 1) - return llvmlite.const_int32(pool, 0) - elif kind == ast.CONST_NONE: - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - return llvmlite.ConstNull(pool, i8_ptr_ty, "null") - elif kind == ast.CONST_STR: - if gd_entry.ConstStrs is not None and gd_entry.ConstStrs[di] != 0: - sv: str = (str | t.CPtr)(t.CVoid(gd_entry.ConstStrs[di], t.CPtr)) - return HandlesExpr.create_global_string(builder, pool, mod, sv, trans) - # 无法重建的(如 CONST_FLOAT/复杂表达式)返回 None,调用方回退到 AST - return None - - - def find_func_entry_in_table(self, funcs: HandlesExprCall.FuncEntry | t.CPtr, - func_count: int, - name: str) -> HandlesExprCall.FuncEntry | t.CPtr: - """在函数表中按名称查找,返回完整 FuncEntry 或 None""" - if name is None or funcs is None: - return None - entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__() - i: int = 0 - while i < func_count: - entry_addr: t.CUInt64T = t.CUInt64T(funcs) + i * entry_size - entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - if entry.Name is not None: - if string.strcmp(entry.Name, name) == 0: - return entry - i += 1 - return None - - - def NewExprCallHandle(self, pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr) -> HandlesExprCall.ExprCallHandle | t.CPtr: - h: HandlesExprCall.ExprCallHandle | t.CPtr = pool.alloc(HandlesExprCall.ExprCallHandle.__sizeof__()) - if h is None: - return None - string.memset(h, 0, HandlesExprCall.ExprCallHandle.__sizeof__()) - h.Trans = trans - return h - +import lib.core.Gen.GenTypes as GenTypes +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import sys +import viperlib +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.CallGenCBuiltin as CallGenCBuiltin + + +# ============================================================ +# CallGenLeafKit - CallGenMixin 拆分 3/9:EH/isinstance/闭包/print/函数表 +# +# 按功能域从 CallGenMixin.vp 拆出(500~1500 行/文件架构重构): +# EH 防护 + isinstance + 闭包/函数指针 + printf/print + 全局函数表/默认参数表。 +# 继承 CallGenCBuiltin。 +# +# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 +# ============================================================ + + +# ============================================================ +# 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug) +# ============================================================ +GLOBAL_FUNC_MAX: t.CDefine = 8192 +GLOBAL_DEFAULTS_MAX: t.CDefine = 4096 +_CEXPORT_MAX: t.CDefine = 256 +ASM_MAX_OPERANDS: t.CDefine = 16 +ASM_TEXT_BUF_SIZE: t.CDefine = 2048 +ASM_CONST_BUF_SIZE: t.CDefine = 512 +ASM_ARGS_BUF_SIZE: t.CDefine = 512 +ASM_LINE_BUF_SIZE: t.CDefine = 4096 +LLVMIR_MAX_OPS: t.CDefine = 16 +LLVMIR_TEMPLATE_BUF: t.CDefine = 512 +# 闭包名表大小(原 HandlesExprCall 模块级常量) +MAX_CLOSURE_NAMES: t.CDefine = 128 +# 函数指针签名表大小(原 HandlesExprCall 模块级常量) +MAX_FUNC_PTR_SIGS: t.CDefine = 64 +# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32) +ISINSTANCE_CLASS_MAX: t.CDefine = 64 + + +# ============================================================ +# CallGenLeafKit - EH/isinstance/闭包/print/函数表 +# ============================================================ +@t.NoVTable +class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin): + """EH 防护 + isinstance + 闭包 + print + 全局函数表(继承 CBuiltin)""" + + + # ============================================================ + # _func_has_eh_params - 被调函数签名是否含 try-except EH 输出参数 + # + # EH 参数(%__eh_msg_out__/__eh_code_out__)由 translate_function_def/ + # _translate_method 在含 raise 的函数签名末尾注入(main 除外)。 + # ============================================================ + def _func_has_eh_params(self, func: llvmlite.Function | t.CPtr) -> int: + """返回 1=函数带 EH 输出参数 / 0=不带""" + if func is None: + return 0 + cur_p: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) + while cur_p is not None: + pn: str = llvmlite.param_get_name(cur_p) + if pn is not None and string.strcmp(pn, "%__eh_msg_out__") == 0: + return 1 + cur_p = llvmlite.param_get_next(cur_p) + return 0 + + # ============================================================ + # _emit_eh_guarded_call - 调用侧 try-except EH 检测(对齐 TPC + # HandlesExprCall._append_eh_msg_out_arg + _check_eh_return) + # + # 被调函数带 EH 输出参数时: + # 1. 确定 msg/code 输出指针: + # - 当前在 try(trans._eh_dispatch_bb 非空):复用 try 的 + # eh_message/exception_code alloca——被调函数直接写入,检查 + # 路径读同一 alloca 即得异常,无需搬运 + # - 当前函数有 EH 输出参数:复用本函数 out 参数(异常直接写进 + # 本函数输出,检查命中后仅返回,由调用方接管传播) + # - 两者皆无:局部 null alloca(异常被吞) + # 2. 调用前清零输出指针(复用 alloca 必须复位,防上次残留误判) + # 3. 追加 msg/code 两个实参(count+2) + # 4. 调用后检查 msg != null:命中 → err 块(try 内分支 DispatchBB; + # 否则仅返回默认值);未命中 → ok 块继续 + # ============================================================ + + # ============================================================ + def _emit_eh_guarded_call(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + trans: HT.Translator | t.CPtr, + func: llvmlite.Function | t.CPtr, + call_name: str, + head: llvmlite.Value | t.CPtr, + count: int, + ret_ty: llvmlite.LLVMType | t.CPtr, + is_variadic: int) -> llvmlite.Value | t.CPtr: + """带 try-except EH 检测的函数调用,返回 call 结果(检查后位于 ok 块)""" + if trans is None or self._func_has_eh_params(func) == 0: + return llvmlite.build_call(builder, call_name, head, count, ret_ty, is_variadic) + # ---- 1. 确定输出指针 ---- + i8_ty_g: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty_g: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_g) + i32_ty_g: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if i8_ty_g is None or i8_ptr_ty_g is None or i32_ty_g is None: + return llvmlite.build_call(builder, call_name, head, count, ret_ty, is_variadic) + msg_ptr: llvmlite.Value | t.CPtr = None + code_ptr: llvmlite.Value | t.CPtr = None + if trans._eh_msg_ptr is not None and trans._eh_code_ptr is not None: + msg_ptr = trans._eh_msg_ptr + code_ptr = trans._eh_code_ptr + elif trans._cur_func_has_eh != 0 and trans._eh_msg_out_param is not None \ + and trans._eh_code_out_param is not None: + msg_ptr = trans._eh_msg_out_param + code_ptr = trans._eh_code_out_param + if msg_ptr is None: + msg_ptr = llvmlite.build_alloca(builder, i8_ptr_ty_g) + code_ptr = llvmlite.build_alloca(builder, i32_ty_g) + # ---- 2. 调用前清零 ---- + null_msg_g: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty_g, "null") + zero_code_g: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + if null_msg_g is not None: + llvmlite.build_store(builder, null_msg_g, msg_ptr) + if zero_code_g is not None: + llvmlite.build_store(builder, zero_code_g, code_ptr) + # ---- 3. 追加实参(链表末尾 + count+2)---- + msg_ptr.Next = code_ptr + code_ptr.Next = None + if head is None: + head = msg_ptr + else: + tail_g: llvmlite.Value | t.CPtr = head + while tail_g.Next is not None: + tail_g = tail_g.Next + tail_g.Next = msg_ptr + count = count + 2 + # ---- 4. 调用 + 检查 ---- + result: llvmlite.Value | t.CPtr = llvmlite.build_call( + builder, call_name, head, count, ret_ty, is_variadic) + cur_func_g: llvmlite.Function | t.CPtr = trans._cur_func + if cur_func_g is None or null_msg_g is None: + return result + msg_val_g: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i8_ptr_ty_g, msg_ptr) + if msg_val_g is None: + return result + is_err_g: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, msg_val_g, null_msg_g) + if is_err_g is None: + return result + lc_g: int = trans._label_counter + trans._label_counter = lc_g + 1 + bb_buf_g: str = pool.alloc(64) + if bb_buf_g is None: + return result + viperlib.snprintf(bb_buf_g, 64, "eh.err.%d", lc_g) + err_bb_g: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, cur_func_g, bb_buf_g) + viperlib.snprintf(bb_buf_g, 64, "eh.ok.%d", lc_g) + ok_bb_g: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, cur_func_g, bb_buf_g) + if err_bb_g is None or ok_bb_g is None: + return result + llvmlite.build_cond_br(builder, is_err_g, err_bb_g, ok_bb_g) + # err 块 + llvmlite.position_at_end(builder, err_bb_g) + if trans._eh_dispatch_bb is not None: + # try 内:异常已写入 try 的 alloca(code_ptr 即 try 的 alloca), + # 分支 DispatchBB 交给 except 链 + llvmlite.build_br(builder, trans._eh_dispatch_bb) + else: + # 非 try:异常已写入本函数 out 参数(复用)或局部 alloca(吞掉), + # 仅返回默认值,由调用方检测本函数 out 参数 + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + ret_ty_g2: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty( + cur_func_g) + if ret_ty_g2 is not None: + match ret_ty_g2: + case llvmlite.LLVMType.Void(): + llvmlite.build_ret_void(builder) + case llvmlite.LLVMType.Ptr(_pg): + nv_g: llvmlite.Value | t.CPtr = llvmlite.ConstNull( + pool, ret_ty_g2, "null") + if nv_g is not None: + llvmlite.build_ret(builder, nv_g) + case llvmlite.LLVMType.Float(_fg): + zf_g: llvmlite.Value | t.CPtr = llvmlite.ConstFloat( + pool, ret_ty_g2, 0.0) + if zf_g is not None: + llvmlite.build_ret(builder, zf_g) + case _: + zv_g: llvmlite.Value | t.CPtr = llvmlite.ConstZero( + pool, ret_ty_g2) + if zv_g is not None: + llvmlite.build_ret(builder, zv_g) + # ok 块:继续 + llvmlite.position_at_end(builder, ok_bb_g) + return result + + # ============================================================ + # isinstance - 运行时 vtable 子类集合比较(2026-08-10) + # + # CVTable 对象头部 vtable 指针唯一标识对象实际类。isinstance(obj, Cls) + # 语义 = Cls 是实际类的祖先(实际类 == Cls 或继承自 Cls)。运行时只能 + # 拿到实际类 vtable 地址,无法向上推导祖先链,因此在编译期沿 + # StructEntry.ParentNames 反向 BFS 枚举 Cls 的全部已知子类(含自身), + # 运行时比较 obj->vtable ∈ {Cls 子类 vtable 地址集合}。 + # NoVTable / 未知类回退编译时静态判断(obj 静态类型 MRO 判断)。 + # ============================================================ + + + + def _translate_isinstance(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + obj_node: ast.AST | t.CPtr, + cls_node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """isinstance(obj, Cls):运行时 vtable 子类集合比较,返回 i1""" + if obj_node is None or cls_node is None: + # 参数缺失即调用错误:fail-fast,绝不返回 True 掩盖 + self.Gen.TypeGenErr.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError") + obj_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, obj_node, None, 0, trans) + if obj_val is None or obj_val.Ty is None: + # obj 类型推断失败:fail-fast,绝不返回 True 掩盖 + self.Gen.TypeGenErr.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError") + # 对象指针规整:二级指针(变量 alloca / 联合 Class|t.CPtr)先 load + obj_ptr: llvmlite.Value | t.CPtr = obj_val + match obj_val.Ty: + case llvmlite.LLVMType.Ptr(inner_ty): + match inner_ty: + case llvmlite.LLVMType.Ptr(_): + loaded: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, inner_ty, obj_val) + if loaded is not None: + obj_ptr = loaded + case _: + pass + obj_is_ptr: int = self.Gen.ExprGenBase.is_ptr_type(obj_ptr.Ty) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty) + # 对象 vtable 指针惰性读取(首个 CVTable 类比较时执行一次) + vtable_ptr: llvmlite.Value | t.CPtr = None + vtable_ready: int = 0 + res: llvmlite.Value | t.CPtr = None + cls_names: t.CSizeT | t.CPtr = self._extract_isinstance_class_names(pool, cls_node) + if cls_names is None: + # 类名提取失败:fail-fast,绝不返回 True 掩盖 + self.Gen.TypeGenErr.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError") + ci: int = 0 + while cls_names[ci] != 0: + cn: str = (str | t.CPtr)(t.CVoid(cls_names[ci], t.CPtr)) + if cn is not None: + if self.Gen.StructGen.is_novtable_by_name(cn) != 0 \ + or self.Gen.StructGen.has_vtable_by_name(cn) == 0: + # NoVTable / 未知类 → 编译时静态判断(obj 静态类型 MRO) + st: int = self._isinstance_compile_time(pool, obj_ptr, cn) + c1: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, 1, 1 if st > 0 else 0) + if res is None: + res = c1 + else: + res = llvmlite.build_or(builder, res, c1) + elif obj_is_ptr != 0: + # CVTable → 运行时 vtable 比较(读对象头部 vtable 指针) + if vtable_ready == 0: + vtable_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, obj_ptr, i8_ptr_ptr_ty) + if vtable_slot is not None: + vtable_ptr = llvmlite.build_load(builder, i8_ptr_ty, vtable_slot) + vtable_ready = 1 + if vtable_ptr is not None: + subs: t.CSizeT | t.CPtr = self._collect_subclass_vtable_classes(pool, cn) + if subs is not None: + k: int = 0 + while subs[k] != 0: + scn: str = (str | t.CPtr)(t.CVoid(subs[k], t.CPtr)) + if scn is not None: + sub_i8: llvmlite.Value | t.CPtr = self._make_vtable_ref_i8( + pool, builder, mod, scn, trans) + if sub_i8 is not None: + cmp: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_EQ, vtable_ptr, sub_i8) + if cmp is not None: + if res is None: + res = cmp + else: + res = llvmlite.build_or(builder, res, cmp) + k += 1 + ci += 1 + if res is None: + # 未产生任何比较结果(obj 非指针且类全部为 CVTable):推断失败,fail-fast + self.Gen.TypeGenErr.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError") + return res + + + def _extract_isinstance_class_names(self, pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr) -> t.CSizeT | t.CPtr: + """从 isinstance 第二参数提取类名数组(Name→id / Attribute→attr / Tuple→遍历)""" + arr: t.CSizeT | t.CPtr = pool.alloc(8 * 16) + if arr is None: + return None + # 全数组清零:pool 分配内存非零时,未初始化槽位会被 while cls_names[ci]!=0 + # 误当类名指针解引用 → 段错误 + string.memset(arr, 0, 8 * 16) + arr[0] = 0 + if node is None: + return arr + count: int = 0 + k: int = node.kind() + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is not None: + arr[0] = t.CSizeT(nm.id) + elif k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at.attr is not None: + arr[0] = t.CSizeT(at.attr) + elif k == ast.ASTKind.Tuple: + tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(node) + elts: list[ast.AST | t.CPtr] | t.CPtr = tp.elts + if elts is not None: + n: t.CSizeT = len(elts) + for i in range(n): + if count >= 15: + break + elt: ast.AST | t.CPtr = elts.get(i) + if elt is None: + continue + ek: int = elt.kind() + if ek == ast.ASTKind.Name: + enm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(elt) + if enm.id is not None: + arr[count] = t.CSizeT(enm.id) + count += 1 + elif ek == ast.ASTKind.Attribute: + eat: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(elt) + if eat.attr is not None: + arr[count] = t.CSizeT(eat.attr) + count += 1 + arr[count] = 0 + return arr + + + def _collect_subclass_vtable_classes(self, pool: memhub.MemBuddy | t.CPtr, + class_name: str) -> t.CSizeT | t.CPtr: + """反向 BFS 收集目标类及全部子类(含自身,仅 HasVTable==1),返回 0 结尾数组""" + if class_name is None: + return None + names: t.CSizeT | t.CPtr = pool.alloc(8 * (ISINSTANCE_CLASS_MAX + 1)) + queue: t.CSizeT | t.CPtr = pool.alloc(8 * ISINSTANCE_CLASS_MAX) + visited: t.CSizeT | t.CPtr = pool.alloc(8 * ISINSTANCE_CLASS_MAX) + if names is None or queue is None or visited is None: + return None + string.memset(names, 0, 8 * (ISINSTANCE_CLASS_MAX + 1)) + string.memset(queue, 0, 8 * ISINSTANCE_CLASS_MAX) + string.memset(visited, 0, 8 * ISINSTANCE_CLASS_MAX) + qcount: int = 0 + outcount: int = 0 + vcount: int = 0 + queue[0] = t.CSizeT(class_name) + qcount = 1 + while qcount > 0: + qcount -= 1 + cur_addr: t.CSizeT = queue[qcount] + cur: str = (str | t.CPtr)(t.CVoid(cur_addr, t.CPtr)) + if cur is None: + continue + dup: int = 0 + for vi in range(vcount): + va: t.CSizeT = visited[vi] + if va != 0: + vn: str = (str | t.CPtr)(t.CVoid(va, t.CPtr)) + if vn is not None and string.strcmp(vn, cur) == 0: + dup = 1 + break + if dup != 0: + continue + if vcount < ISINSTANCE_CLASS_MAX: + visited[vcount] = t.CSizeT(cur) + vcount += 1 + centry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(cur) + if centry is not None and centry.HasVTable != 0: + if outcount < ISINSTANCE_CLASS_MAX: + names[outcount] = t.CSizeT(cur) + outcount += 1 + # 子类入队:遍历全部已注册 struct,ParentNames 含 cur 者 + scnt: int = self.Gen.StructGen.get_struct_count() + for i in range(scnt): + e2: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen._get_struct_entry(i) + if e2 is None or e2.Name is None: + continue + if e2.ParentCount > 0 and e2.ParentNames is not None: + parr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(e2.ParentNames, t.CPtr)) + for j in range(e2.ParentCount): + pa: t.CSizeT = parr[j] + if pa != 0: + pn: str = (str | t.CPtr)(t.CVoid(pa, t.CPtr)) + if pn is not None and string.strcmp(pn, cur) == 0: + if qcount < ISINSTANCE_CLASS_MAX: + queue[qcount] = t.CSizeT(e2.Name) + qcount += 1 + break + names[outcount] = 0 + return names + + + def _make_vtable_ref_i8(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """构造类 vtable 地址引用(i8*):本模块已定义直接引用,跨模块声明 external""" + if class_name is None: + return None + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + buf: str = pool.alloc(256) + if buf is None: + return None + viperlib.snprintf(buf, 256, "%s.vtable", class_name) + vn: str = (str | t.CPtr)(buf) + sha1: str = self.Gen.StructGen.get_struct_sha1(class_name) + if sha1 is None: + if trans is None: + return None + sha1 = trans.ModuleSha1 + if sha1 is None: + return None + mangled: str = self.Gen.FuncGenBase._mangle_name_with_sha1(sha1, vn) + ref_name: str = pool.alloc(256) + if ref_name is None: + return None + # vtable 名含 sha1 点号前缀,一律 @"..." 引号形式 + viperlib.snprintf(ref_name, 256, "@\"%s\"", mangled) + gv: llvmlite.GlobalVariable | t.CPtr = self.Gen.ExprGenAttr.find_global_in_module(mod, mangled) + ref_ty: llvmlite.LLVMType | t.CPtr = None + if gv is not None: + # 本模块已定义 vtable(constant {i8* x N})→ 引用类型 Ptr(struct) + ref_ty = llvmlite.Ptr(pool, gv.Ty) + else: + # 跨模块:声明 @mangled = external global i8*,引用类型 i8** + gv2: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable( + pool, mangled, i8_ptr_ty) + if gv2 is None: + return None + llvmlite.module_add_global(mod, gv2) + ref_ty = llvmlite.Ptr(pool, i8_ptr_ty) + ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, ref_ty, ref_name) + if ref is None: + return None + return llvmlite.build_bitcast(builder, ref, i8_ptr_ty) + + + def _isinstance_compile_time(self, pool: memhub.MemBuddy | t.CPtr, + obj_ptr: llvmlite.Value | t.CPtr, + class_name: str) -> int: + """编译时静态判断:obj 静态类型 == class_name 或 class_name 在其 MRO 中""" + if obj_ptr is None or obj_ptr.Ty is None or class_name is None: + return 0 + match obj_ptr.Ty: + case llvmlite.LLVMType.Ptr(obj_struct_ty): + sname: str = self.Gen.StructGen.get_class_name_by_type(pool, obj_struct_ty) + if sname is not None: + if string.strcmp(sname, class_name) == 0: + return 1 + mro: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, sname) + if mro is not None: + k: int = 0 + while mro[k] != 0: + mn: str = (str | t.CPtr)(t.CVoid(mro[k], t.CPtr)) + if mn is not None and string.strcmp(mn, class_name) == 0: + return 1 + k += 1 + case _: + pass + return 0 + + # ============================================================ + # P4 簇 5+6 迁移方法(函数体来自 HandlesExprCall.vp: + # 闭包调用/函数指针/printf/print/stdarg 糖/变长参数提升/函数表/全局注册表) + # 本模块函数调用改 self.,外部模块调用保留模块前缀,全局变量改 self 字段 + # ============================================================ + + + + def translate_closure_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + closure_alloca: llvmlite.Value | t.CPtr, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """通过闭包指针间接调用(支持带参 lambda:i32(i8*, args...))""" + if builder is None or closure_alloca is None: + return None + + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + + # 1. 加载闭包指针 (i8*) + closure_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, closure_alloca) + if closure_ptr is None: + return None + + # 2. 加载 fn_ptr (offset 0): bitcast to i8**, load i8* + fn_ptr_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, closure_ptr, llvmlite.Ptr(pool, i8_ptr_ty)) + if fn_ptr_addr is None: + return None + fn_raw: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, fn_ptr_addr) + if fn_raw is None: + return None + + # 3. 加载 env_ptr (offset 8): GEP i8, closure, 8; load i8* + eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 8) + env_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, closure_ptr, eight_val) + if env_addr is None: + return None + env_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, env_addr) + if env_ptr is None: + return None + + # 4. 构建参数:env 头 + 实参尾(带参 lambda 时翻译实参) + total_args: int = 1 + arg_head: llvmlite.Value | t.CPtr = env_ptr + arg_tail: llvmlite.Value | t.CPtr = env_ptr + param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) + pn_tail: llvmlite.ParamNode | t.CPtr = param_node + if can > 0 and cargs is not None and trans is not None: + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is None: + continue + arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is None or arg_val.Ty is None: + continue + arg_val.Next = None + if arg_tail is not None: + arg_tail.Next = arg_val + arg_tail = arg_val + pn_new: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, arg_val.Ty) + if pn_new is not None: + pn_tail.Next = pn_new + pn_tail = pn_new + total_args += 1 + if total_args == 1: + env_ptr.Next = None + + # 5. bitcast fn_raw 到函数指针类型 i32(i8*, [args...])* + func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, param_node, total_args) + func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty) + fn_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, fn_raw, func_ptr_ty) + if fn_typed is None: + return None + + # 6. 间接调用: call i32 %fn_typed(env, args...) + return llvmlite.build_call_indirect(builder, fn_typed, arg_head, total_args, i32_ty) + + + def _is_func_ptr_alloca(self, alloca: llvmlite.Value | t.CPtr) -> int: + """判断 alloca 是否为函数指针变量(类型 Ptr(Ptr(i8))),1=是 / 0=否""" + if alloca is None or alloca.Ty is None: + return 0 + if self.Gen.ExprGenBase.is_ptr_type(alloca.Ty) == 0: + return 0 + pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if pointee is None or self.Gen.ExprGenBase.is_ptr_type(pointee) == 0: + return 0 + inner: llvmlite.LLVMType | t.CPtr = pointee.Pointee + if inner is None or self.Gen.ExprGenBase.is_ptr_type(inner) != 0: + return 0 + return 1 + + + def _ensure_closure_names(self) -> int: + """确保闭包名表已分配,0 失败""" + if self.ClosureNames is not None: + return 1 + self.ClosureNames = CompilerFactory.get_perm_pool().alloc(64 * MAX_CLOSURE_NAMES) + if self.ClosureNames is None: + return 0 + string.memset(self.ClosureNames, 0, 64 * MAX_CLOSURE_NAMES) + return 1 + + + def register_closure_name(self, name: str) -> int: + """注册嵌套函数(闭包变量)名,0 成功""" + if name is None: + return 1 + if self._ensure_closure_names() == 0: + return 1 + if self.ClosureCount >= MAX_CLOSURE_NAMES: + return 1 + idx: t.CSizeT = t.CSizeT(self.ClosureCount) * 64 + string.strncpy(self.ClosureNames + idx, name, 63) + self.ClosureCount += 1 + return 0 + + + def is_closure_name(self, name: str) -> int: + """检查 name 是否已注册为闭包变量名,1=是 / 0=否""" + if name is None or self.ClosureNames is None: + return 0 + i: t.CSizeT + for i in range(self.ClosureCount): + if string.strcmp(self.ClosureNames + i * 64, name) == 0: + return 1 + return 0 + + + def _ensure_funcptr_sigs(self) -> int: + """确保函数指针签名表已分配(stdlib.malloc,懒初始化)""" + if self.FuncptrNames is not None: + return 1 + self.FuncptrNames = CompilerFactory.get_perm_pool().alloc(64 * MAX_FUNC_PTR_SIGS) + self.FuncptrRets = CompilerFactory.get_perm_pool().alloc(8 * MAX_FUNC_PTR_SIGS) + if self.FuncptrNames is None or self.FuncptrRets is None: + return 0 + string.memset(self.FuncptrNames, 0, 64 * MAX_FUNC_PTR_SIGS) + return 1 + + + def register_func_ptr_sig(self, name: str, + ret_ty: llvmlite.LLVMType | t.CPtr) -> int: + """注册函数指针变量的返回类型签名,0 成功""" + if name is None or ret_ty is None: + return 1 + if self._ensure_funcptr_sigs() == 0: + return 1 + if self.FuncptrCount >= MAX_FUNC_PTR_SIGS: + return 1 + idx: t.CSizeT = t.CSizeT(self.FuncptrCount) * 64 + # 槽位定长 64 字节,与 register_closure_name 一致用 strncpy 钳制防越界 + string.strncpy(self.FuncptrNames + idx, name, 63) + # ret_ty 是调用方 pool 分配的裸 LLVMType,1a 每文件 reset 后悬空; + # 深拷贝到 perm_pool(lookup_func_ptr_ret 跨文件读取) + ret_copy_fp: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( + CompilerFactory.get_perm_pool(), ret_ty) + if ret_copy_fp is not None: + self.FuncptrRets[self.FuncptrCount] = t.CUInt64T(ret_copy_fp) + else: + self.FuncptrRets[self.FuncptrCount] = t.CUInt64T(ret_ty) + self.FuncptrCount += 1 + return 0 + + + def lookup_func_ptr_ret(self, name: str) -> llvmlite.LLVMType | t.CPtr: + """查函数指针变量的返回类型,None=未注册(调用时默认 i32)""" + if name is None or self.FuncptrNames is None: + return None + for i in range(self.FuncptrCount): + idx: t.CSizeT = t.CSizeT(i) * 64 + if string.strcmp(self.FuncptrNames + idx, name) == 0: + return (llvmlite.LLVMType | t.CPtr)( + t.CVoid(self.FuncptrRets[i], t.CPtr)) + return None + + + def _translate_func_ptr_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + fp_alloca: llvmlite.Value | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """函数指针变量间接调用,返回结果 Value""" + if builder is None or fp_alloca is None: + return None + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + + # 1. load 函数地址 (i8*) + fn_i8: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, fp_alloca) + if fn_i8 is None: + return None + + # 2. 翻译实参并链接为 Value 链表 + head: llvmlite.Value | t.CPtr = None + tail: llvmlite.Value | t.CPtr = None + arg_count: int = 0 + ai: t.CSizeT + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is not None: + arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is not None: + arg_val.Next = None + if head is None: + head = arg_val + else: + tail.Next = arg_val + tail = arg_val + arg_count += 1 + + # 3. 按实参类型 + 注册的返回类型构造签名(未注册即 t.Callable 注解缺失,fail-fast) + ret_ty: llvmlite.LLVMType | t.CPtr = self.lookup_func_ptr_ret(func_name) + if ret_ty is None: + self.Gen.TypeGenErr.fatal_error( + None, + f"函数指针变量 '{func_name}' 的返回类型未注册(t.Callable 注解缺失)", + "TypeError") + ret_ty = i32_ty + fp_first: llvmlite.ParamNode | t.CPtr = None + fp_prev: llvmlite.ParamNode | t.CPtr = None + cur_v: llvmlite.Value | t.CPtr = head + for pi in range(arg_count): + if cur_v is None: + break + cur_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(cur_v) + pn2: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, cur_ty) + if pn2 is not None: + if fp_first is None: + fp_first = pn2 + if fp_prev is not None: + llvmlite.paramnode_set_next(fp_prev, pn2) + fp_prev = pn2 + cur_v = llvmlite.value_get_next(cur_v) + + func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, ret_ty, fp_first, arg_count) + if func_ty is None: + return None + func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty) + + # 4. bitcast i8* → 函数指针类型,间接调用 + fn_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, fn_i8, func_ptr_ty) + if fn_typed is None: + return None + return llvmlite.build_call_indirect(builder, fn_typed, head, arg_count, ret_ty) + + + def translate_printf_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None): + """翻译 printf 调用(特殊处理格式字符串)""" + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None: + return + can: t.CSizeT = len(cargs) + if can == 0: + return + + arg0: ast.AST | t.CPtr = cargs.get(0) + if arg0 is None: + return + + fmt_str: str = None + arg0_kind: int = arg0.kind() + if arg0_kind == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg0) + if cn.const_kind == ast.CONST_STR: + fmt_str = cn.str_val + + if fmt_str is None: + return + + fmt_ptr: llvmlite.Value | t.CPtr = self.Gen.ExprGenConst.create_global_string( + builder, pool, mod, fmt_str, trans) + if fmt_ptr is None: + return + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + + # 翻译额外参数并链接 + prev: llvmlite.Value | t.CPtr = fmt_ptr + for ai in range(1, can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is not None: + arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is not None: + # C ABI integer promotion: i8/i16 → i32(printf 变参函数要求) + arg_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(arg_val.Ty) + if arg_bits != 0 and arg_bits < 32: + arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, i32_ty, arg) + # C ABI float promotion: float → double(printf 变参函数要求) + arg_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(arg_val.Ty) + if arg_fbits != 0 and arg_fbits < 64: + double_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) + arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, double_ty, arg) + arg_val.Next = None + prev.Next = arg_val + prev = arg_val + prev.Next = None + + # is_variadic=1: 生成带显式函数类型签名的 call(如 call i32 (i8*, ...) @printf), + # 让 llc 识别为 variadic 调用,生成正确的 Win64 ABI 代码(浮点参数同时传 XMM 和整数寄存器) + llvmlite.build_call(builder, "printf", fmt_ptr, can, i32_ty, 1) + + + def translate_print_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None): + """翻译 print 调用(类型感知格式化 + 默认换行)""" + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None: + return + + FMT_BUF_SIZE: t.CSizeT = 256 + fmt_buf: bytes = stdlib.malloc(FMT_BUF_SIZE) + if fmt_buf is None: + return + fmt_buf[0] = '\0' + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + dbl_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) + + can: t.CSizeT = len(cargs) + arg_head: llvmlite.Value | t.CPtr = None + arg_tail: llvmlite.Value | t.CPtr = None + arg_count: int = 1 # 格式串本身是第 1 个 printf 参数 + + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is None: + continue + arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is None or arg_val.Ty is None: + # fail-fast:print 参数翻译失败必须终止编译,绝不在格式串写 + # 误导为数据问题而非编译器 bug。 + fb_pp: str = VLogger.fmt_buf() + if fb_pp is not None: + viperlib.snprintf(fb_pp, 1024, "print 参数翻译失败(表达式返回 None): [arg=%d]", ai) + VLogger.error(fb_pp, "PRINT") + self.Gen.TypeGenErr.fatal_error(arg, "print 参数翻译失败(表达式返回 None)", "TypeError") + return + + # 数组名(如 print(l),l: t.CArray[t.CChar, N]): + # translate_value 会 load 出数组值([N x T]),print 无法格式化; + # 按数组退化语义取数组 alloca 地址——字符数组 → %s(打印字符串内容), + # 其他元素类型 → 0x%llx(打印数组地址)。 + array_ptr: llvmlite.Value | t.CPtr = None + array_elem_bits: int = 0 + if arg.kind() == ast.ASTKind.Name and trans is not None: + anm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg) + if anm.id is not None: + arr_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, anm.id) + if arr_alloca is not None and arr_alloca.Ty is not None \ + and self.Gen.ExprGenBase.is_ptr_type(arr_alloca.Ty) != 0: + arr_pointee: llvmlite.LLVMType | t.CPtr = arr_alloca.Ty.Pointee + if arr_pointee is not None: + match arr_pointee: + case llvmlite.LLVMType.Array(arr_et, arr_n): + array_ptr = arr_alloca + array_elem_bits = self.Gen.ExprGenBase.get_llvm_type_bits(arr_et) + case _: + pass + + token: str = None + chain_arg: int = 1 # 1=该 token 消耗一个参数,0=纯文本 + arg_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(arg_val.Ty) + arg_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(arg_val.Ty) + + if array_ptr is not None: + # 数组退化:字符数组 → %s(bitcast [N x i8]* 到 i8*);其他 → 0x%llx + if array_elem_bits == 8: + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + token = "%s" + arg_val = llvmlite.build_bitcast(builder, array_ptr, i8_ptr_ty) + else: + token = "0x%llx" + arg_val = llvmlite.build_ptrtoint(builder, array_ptr, i64_ty) + elif self.Gen.ExprGenBase.is_ptr_type(arg_val.Ty) != 0: + # i8*(str/bytes)→ %s;其他指针 → 0x%llx + pointee: llvmlite.LLVMType | t.CPtr = arg_val.Ty.Pointee + if pointee is not None and self.Gen.ExprGenBase.get_llvm_type_bits(pointee) == 8: + token = "%s" + else: + token = "0x%llx" + arg_val = llvmlite.build_ptrtoint(builder, arg_val, i64_ty) + elif arg_bits != 0: + if arg_bits == 1: + token = "%d" + arg_val = llvmlite.build_zext(builder, arg_val, i32_ty) + elif arg_bits == 8: + token = "%d" + arg_val = llvmlite.build_sext(builder, arg_val, i32_ty) + elif arg_bits == 16: + token = "%d" + arg_val = llvmlite.build_sext(builder, arg_val, i32_ty) + elif arg_bits == 32: + token = "%d" + else: + token = "%lld" + elif arg_fbits != 0: + token = "%f" + if arg_fbits < 64: + arg_val = llvmlite.build_fpext(builder, arg_val, dbl_ty) + else: + # 结构体值/数组/函数等 → "(unknown)",不传参 + token = "(unknown)" + chain_arg = 0 + + # 追加格式 token + if string.strlen(fmt_buf) < FMT_BUF_SIZE - 16: + viperlib.snprintf(fmt_buf + string.strlen(fmt_buf), 16, "%s", token) + # 链接参数 + if chain_arg != 0: + arg_val.Next = None + if arg_tail is None: + arg_head = arg_val + else: + arg_tail.Next = arg_val + arg_tail = arg_val + arg_count += 1 + + # 追加默认换行(Python print 默认 end="\n") + if string.strlen(fmt_buf) < FMT_BUF_SIZE - 2: + viperlib.snprintf(fmt_buf + string.strlen(fmt_buf), 2, "\n") + + fmt_ptr: llvmlite.Value | t.CPtr = self.Gen.ExprGenConst.create_global_string( + builder, pool, mod, fmt_buf, trans) + stdlib.free(fmt_buf) + if fmt_ptr is None: + return + fmt_ptr.Next = arg_head + # is_variadic=1: 带显式函数类型签名(C ABI 变参调用) + llvmlite.build_call(builder, "printf", fmt_ptr, arg_count, i32_ty, 1) + + + def init_func_table(self, pool: memhub.MemBuddy | t.CPtr, + max_count: int) -> GenTypes.FuncEntry | t.CPtr: + """分配并清零函数表数组""" + size: t.CSizeT = max_count * GenTypes.FuncEntry.__sizeof__() + funcs_ptr: GenTypes.FuncEntry | t.CPtr = pool.alloc(size) + if funcs_ptr is not None: + string.memset(funcs_ptr, 0, size) + return funcs_ptr + + + def find_func_in_table(self, funcs: GenTypes.FuncEntry | t.CPtr, + func_count: int, + name: str) -> llvmlite.Function | t.CPtr: + """在函数表中按名称查找,返回 Function 指针或 None""" + if name is None or funcs is None: + return None + entry_size: t.CSizeT = GenTypes.FuncEntry.__sizeof__() + for i in range(func_count): + entry_addr: t.CUInt64T = t.CUInt64T(funcs) + i * entry_size + entry: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + if entry.Name is not None: + if string.strcmp(entry.Name, name) == 0: + return entry.Func + return None + + + def add_func_to_table(self, funcs: GenTypes.FuncEntry | t.CPtr, + func_count: int, + name: str, + func: llvmlite.Function | t.CPtr, + max_count: int, + defaults: t.CVoid | t.CPtr = None, + default_count: int = 0, + param_count: int = 0, + pool: memhub.MemBuddy | t.CPtr = None) -> int: + """添加函数到函数表,返回 0 成功 + + Args: + defaults: ast.Arguments.defaults 列表节点指针,None=无默认值 + default_count: 默认值数量(len(defaults)) + param_count: 形参数量(不含 self,len(args.args)) + pool: 内存池(用于生成 TypeStr;None 时 TypeStr 为空,vtable 回退读 Func 对象) + """ + if name is None or func is None or funcs is None: + return 1 + if func_count >= max_count: + return 1 + entry_size: t.CSizeT = GenTypes.FuncEntry.__sizeof__() + entry_addr: t.CUInt64T = t.CUInt64T(funcs) + func_count * entry_size + entry: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + entry.Name = name + entry.Func = func + entry.Defaults = defaults + entry.DefaultCount = default_count + entry.ParamCount = param_count + # 同时注册到全局函数表(供跨模块 vtable 初始化查找) + self._register_global_func(name, func, pool) + # 同时注册到全局默认参数表(供跨模块调用时填充默认值) + if default_count > 0: + self._register_global_defaults(name, defaults, default_count, param_count) + return 0 + + + def _init_global_func_table(self) -> int: + """初始化全局函数表(用 stdlib.malloc 分配,生命周期=整个程序)""" + if self.GlobalFuncs is not None: + return 1 + size: t.CSizeT = GLOBAL_FUNC_MAX * GenTypes.FuncEntry.__sizeof__() + self.GlobalFuncs = CompilerFactory.get_perm_pool().alloc(size) + if self.GlobalFuncs is None: + return 0 + string.memset(self.GlobalFuncs, 0, size) + self.GlobalFuncCount = 0 + return 1 + + + def _build_func_type_str(self, pool: memhub.MemBuddy | t.CPtr, + func: llvmlite.Function | t.CPtr) -> str: + """生成函数类型文本(stdlib 分配)""" + if func is None: + return None + # 类型文本可能较长(SHA1 限定命名结构体 + 多参数),用 1024 缓冲 + ty_buf: str = pool.alloc(1024) + if ty_buf is None: + return None + ty_buf[0] = '\0' + + # 返回类型 + ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(func) + ret_part: str = pool.alloc(512) + if ret_part is not None and ret_ty is not None: + ret_part[0] = '\0' + llvmlite.TypePrint(ret_part, 512, ret_ty, pool) + self._asm_append_cstr(ty_buf, 1024, ret_part) + self._asm_append_cstr(ty_buf, 1024, " (") + + # 参数类型(全部经 _asm_append_cstr 有界追加,防止 strcat 无界写穿 1024 缓冲) + cur: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) + first: int = 1 + param_part: str = pool.alloc(512) + while cur is not None: + if first == 0: + self._asm_append_cstr(ty_buf, 1024, ", ") + if param_part is not None: + param_part[0] = '\0' + param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur) + if param_ty is not None: + llvmlite.TypePrint(param_part, 512, param_ty, pool) + self._asm_append_cstr(ty_buf, 1024, param_part) + cur = llvmlite.param_get_next(cur) + first = 0 + self._asm_append_cstr(ty_buf, 1024, ")") + + # 深拷贝到 stdlib 区(TypeStr 跨文件永久存活) + ts_len: t.CSizeT = string.strlen(ty_buf) + ts_copy: str = CompilerFactory.get_perm_pool().alloc(ts_len + 1) + if ts_copy is None: + return None + string.strcpy(ts_copy, ty_buf) + return ts_copy + + + def _register_global_func(self, name: str, func: llvmlite.Function | t.CPtr, + pool: memhub.MemBuddy | t.CPtr = None) -> int: + """注册函数到全局表(已存在则跳过),返回 0 成功 + + 直接操作全局表,不调用 add_func_to_table,避免递归。 + pool 用于生成 TypeStr(None 时 TypeStr 为空)。 + """ + if name is None or func is None: + return 1 + if self._init_global_func_table() == 0: + return 1 + # 已存在则跳过(避免重复) + if self.find_func_in_table(self.GlobalFuncs, self.GlobalFuncCount, name) is not None: + return 0 + if self.GlobalFuncCount >= GLOBAL_FUNC_MAX: + return 1 + # 直接写入全局表(不调用 add_func_to_table,避免递归) + entry_size: t.CSizeT = GenTypes.FuncEntry.__sizeof__() + entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalFuncs) + self.GlobalFuncCount * entry_size + entry: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + # Name 深拷贝到 stdlib 区:全局表跨文件永久存活,pool 内名字会被 1b 每文件 + # reset_to(mark1) 回收导致悬空(vtable 生成 find_func_global 后 strcmp 崩溃) + name_len: t.CSizeT = string.strlen(name) + name_copy: str = CompilerFactory.get_perm_pool().alloc(name_len + 1) + if name_copy is None: + return 1 + string.strcpy(name_copy, name) + entry.Name = name_copy + entry.Func = func + # TypeStr 不在此生成:函数参数在 add_func_to_table 之后才添加, + # 需由调用方在参数添加完成后调用 update_global_func_typestr 补全。 + self.GlobalFuncCount += 1 + return 0 + + + def update_global_func_typestr(self, pool: memhub.MemBuddy | t.CPtr, + name: str, + func: llvmlite.Function | t.CPtr) -> int: + """更新全局函数表的 TypeStr(在函数参数全部添加完成后调用) + + 调用时机:add_func_to_table 注册后、llvmlite.add_param 全部执行完。 + 生成 ret_ty (param1_ty, ...) 类型文本(stdlib 深拷贝), + 供 vtable 生成在 func 被 1b reset 后使用。 + """ + if name is None or func is None: + return 1 + entry: GenTypes.FuncEntry | t.CPtr = self.find_func_entry_global(name) + if entry is None: + return 1 + entry.TypeStr = self._build_func_type_str(pool, func) + return 0 + + + def find_func_global(self, name: str) -> llvmlite.Function | t.CPtr: + """在全局函数表中按名称查找,返回 Function 指针或 None""" + if name is None or self.GlobalFuncs is None: + return None + return self.find_func_in_table(self.GlobalFuncs, self.GlobalFuncCount, name) + + + def find_func_entry_global(self, name: str) -> GenTypes.FuncEntry | t.CPtr: + """在全局函数表中按名称查找,返回完整 FuncEntry(含 TypeStr)或 None""" + if name is None or self.GlobalFuncs is None: + return None + entry_size: t.CSizeT = GenTypes.FuncEntry.__sizeof__() + for i in range(self.GlobalFuncCount): + entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalFuncs) + i * entry_size + entry: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + if entry.Name is not None: + if string.strcmp(entry.Name, name) == 0: + return entry + return None + + + def _init_global_defaults_table(self) -> int: + """初始化全局默认参数表""" + if self.GlobalDefaults is not None: + return 1 + size: t.CSizeT = GLOBAL_DEFAULTS_MAX * GenTypes.FuncDefaultsEntry.__sizeof__() + self.GlobalDefaults = CompilerFactory.get_perm_pool().alloc(size) + if self.GlobalDefaults is None: + return 0 + string.memset(self.GlobalDefaults, 0, size) + self.GlobalDefaultsCount = 0 + return 1 + + + def _register_global_defaults(self, name: str, + defaults: t.CVoid | t.CPtr, + default_count: int, + param_count: int) -> int: + """注册函数默认参数到全局表,返回 0 成功 + + 注册时提取每个默认值 Constant 的常量快照到 stdlib(ConstKinds/ConstInts/ConstStrs), + 跨模块调用时优先用快照重建常量 IR,避免读取被 reset 回收的 pool 内 AST。 + """ + if name is None or defaults is None: + return 1 + if self._init_global_defaults_table() == 0: + return 1 + # 已存在则跳过 + if self.find_func_defaults(name) is not None: + return 0 + if self.GlobalDefaultsCount >= GLOBAL_DEFAULTS_MAX: + return 1 + entry_size: t.CSizeT = GenTypes.FuncDefaultsEntry.__sizeof__() + entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalDefaults) + self.GlobalDefaultsCount * entry_size + entry: GenTypes.FuncDefaultsEntry | t.CPtr = (GenTypes.FuncDefaultsEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + # Name 深拷贝到 stdlib(全局表跨文件永久存活) + nm_len: t.CSizeT = string.strlen(name) + nm_copy: str = CompilerFactory.get_perm_pool().alloc(nm_len + 1) + if nm_copy is None: + return 1 + string.strcpy(nm_copy, name) + entry.Name = nm_copy + entry.Defaults = defaults + entry.DefaultCount = default_count + entry.ParamCount = param_count + # 提取常量快照到 stdlib + if default_count > 0: + kinds: t.CInt | t.CPtr = CompilerFactory.get_perm_pool().alloc(default_count * 4) + ints: t.CInt64T | t.CPtr = CompilerFactory.get_perm_pool().alloc(default_count * 8) + strs: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(default_count * 8) + if kinds is not None and ints is not None and strs is not None: + string.memset(kinds, 0, default_count * 4) + string.memset(ints, 0, default_count * 8) + string.memset(strs, 0, default_count * 8) + dl: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(defaults), t.CPtr)) + di: int + for di in range(default_count): + dnode: ast.AST | t.CPtr = dl.get(di) + if dnode is not None and dnode.kind() == ast.ASTKind.Constant: + dcn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(dnode) + kinds[di] = dcn.const_kind + ints[di] = dcn.int_val + if dcn.const_kind == ast.CONST_STR and dcn.str_val is not None: + slen: t.CSizeT = string.strlen(dcn.str_val) + scopy: str = CompilerFactory.get_perm_pool().alloc(slen + 1) + if scopy is not None: + string.strcpy(scopy, dcn.str_val) + strs[di] = t.CSizeT(scopy) + elif dnode is not None and dnode.kind() == ast.ASTKind.Name: + # CDefine Name 引用默认值(如 share: ULONG = SHARE_READ): + # 注册时求值 CDefine 存快照——否则跨模块重建时快照为空 + # → "跨模块默认参数无法重建"(FileIoTest File.__init__ 根因)。 + # 仅支持已注册的整型 CDefine;未注册保持 kinds=0(重建时 + # 仍 fail-fast,绝不静默回退)。 + dnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(dnode) + if dnm.id is not None: + cdef_v: int = self.Gen.TypeGenCDef.lookup_cdefine_constant(dnm.id) + if self.Gen.TypeGenCDef.is_cdefine_found() != 0: + kinds[di] = ast.CONST_INT + ints[di] = cdef_v + entry.ConstKinds = kinds + entry.ConstInts = ints + entry.ConstStrs = strs + self.GlobalDefaultsCount += 1 + return 0 + + + def find_func_defaults(self, name: str) -> GenTypes.FuncDefaultsEntry | t.CPtr: + """按函数名查找默认参数信息,返回 FuncDefaultsEntry 或 None""" + if name is None or self.GlobalDefaults is None: + return None + entry_size: t.CSizeT = GenTypes.FuncDefaultsEntry.__sizeof__() + i: int = 0 + while i < self.GlobalDefaultsCount: + entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalDefaults) + i * entry_size + entry: GenTypes.FuncDefaultsEntry | t.CPtr = (GenTypes.FuncDefaultsEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + if entry.Name is not None: + if string.strcmp(entry.Name, name) == 0: + return entry + i += 1 + return None + + + def _build_const_from_snapshot(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + gd_entry: GenTypes.FuncDefaultsEntry | t.CPtr, + di: int, + trans: HT.Translator | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr) -> llvmlite.Value | t.CPtr: + """从快照重建第 di 个默认值常量 IR""" + if gd_entry is None or gd_entry.ConstKinds is None or gd_entry.ConstInts is None: + return None + if di < 0 or di >= gd_entry.DefaultCount: + return None + kind: t.CInt = gd_entry.ConstKinds[di] + ival: t.CInt64T = gd_entry.ConstInts[di] + if kind == ast.CONST_INT: + if ival > 2147483647 or ival < -2147483648: + return llvmlite.const_int64(pool, ival) + return llvmlite.const_int32(pool, ival) + elif kind == ast.CONST_BOOL: + if ival != 0: + return llvmlite.const_int32(pool, 1) + return llvmlite.const_int32(pool, 0) + elif kind == ast.CONST_NONE: + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + return llvmlite.ConstNull(pool, i8_ptr_ty, "null") + elif kind == ast.CONST_STR: + if gd_entry.ConstStrs is not None and gd_entry.ConstStrs[di] != 0: + sv: str = (str | t.CPtr)(t.CVoid(gd_entry.ConstStrs[di], t.CPtr)) + return self.Gen.ExprGenConst.create_global_string(builder, pool, mod, sv, trans) + # 无法重建的(如 CONST_FLOAT/复杂表达式)返回 None,调用方回退到 AST + return None + + + def find_func_entry_in_table(self, funcs: GenTypes.FuncEntry | t.CPtr, + func_count: int, + name: str) -> GenTypes.FuncEntry | t.CPtr: + """在函数表中按名称查找,返回完整 FuncEntry 或 None""" + if name is None or funcs is None: + return None + entry_size: t.CSizeT = GenTypes.FuncEntry.__sizeof__() + i: int = 0 + while i < func_count: + entry_addr: t.CUInt64T = t.CUInt64T(funcs) + i * entry_size + entry: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + if entry.Name is not None: + if string.strcmp(entry.Name, name) == 0: + return entry + i += 1 + return None + + + def NewExprCallHandle(self, pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr) -> HandlesExprCall.ExprCallHandle | t.CPtr: + h: HandlesExprCall.ExprCallHandle | t.CPtr = pool.alloc(HandlesExprCall.ExprCallHandle.__sizeof__()) + if h is None: + return None + string.memset(h, 0, HandlesExprCall.ExprCallHandle.__sizeof__()) + h.Trans = trans + return h + diff --git a/App/lib/core/Gen/CallGenLib.vp b/App/lib/core/Gen/CallGenLib.vp index c432acf..e26291b 100644 --- a/App/lib/core/Gen/CallGenLib.vp +++ b/App/lib/core/Gen/CallGenLib.vp @@ -1,568 +1,559 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import sys -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesFunctions as HandlesFunctions -import lib.core.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.CompilerFactory as CompilerFactory - - -import lib.core.Gen.CallGenBase as CallGenBase -import lib.core.Handles.ExprCallCtor as ExprCallCtor - -# ============================================================ -# CallGenLib - CallGenMixin 拆分(阶段 C):C 库声明 / 返回类型推断 / -# 变长参数 / memcpy / kwargs 调用辅助方法 -# -# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class CallGenLib(CallGenBase.CallGenBase): - """C 库声明 / 返回类型推断 / kwargs 调用辅助(继承 Base)""" - - def _ensure_c_lib_declare(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - name: str) -> llvmlite.Function | t.CPtr: - """为已知的 C 库函数创建 declare 声明""" - if pool is None or mod is None or name is None: - return None - - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - ret_ty: llvmlite.LLVMType | t.CPtr = None - params: int = 0 # 参数数量 - - if string.strcmp(name, "strlen") == 0 or string.strcmp(name, "strlength") == 0: - ret_ty = i64_ty - params = 1 - elif string.strcmp(name, "memset") == 0: - ret_ty = i8_ptr_ty - params = 3 - elif string.strcmp(name, "memcpy") == 0: - ret_ty = i8_ptr_ty - params = 3 - elif string.strcmp(name, "memmove") == 0: - ret_ty = i8_ptr_ty - params = 3 - elif string.strcmp(name, "memcmp") == 0: - ret_ty = i32_ty - params = 3 - elif string.strcmp(name, "strcmp") == 0: - ret_ty = i32_ty - params = 2 - elif string.strcmp(name, "strncmp") == 0: - ret_ty = i32_ty - params = 3 - elif string.strcmp(name, "strcpy") == 0: - ret_ty = i8_ptr_ty - params = 2 - elif string.strcmp(name, "strncpy") == 0: - ret_ty = i8_ptr_ty - params = 3 - elif string.strcmp(name, "strcat") == 0: - ret_ty = i8_ptr_ty - params = 2 - elif string.strcmp(name, "puts") == 0: - ret_ty = i32_ty - params = 1 - elif string.strcmp(name, "atoi") == 0: - ret_ty = i32_ty - params = 1 - elif string.strcmp(name, "atol") == 0: - ret_ty = i64_ty - params = 1 - elif string.strcmp(name, "abs") == 0: - ret_ty = i32_ty - params = 1 - elif string.strcmp(name, "labs") == 0: - ret_ty = i64_ty - params = 1 - else: - return None - - # 创建 declare - fn: llvmlite.Function | t.CPtr = llvmlite.create_declare(pool, mod, name, ret_ty) - if fn is None: - return None - # 添加参数 - if params == 1: - if string.strcmp(name, "abs") == 0: - llvmlite.add_param(pool, fn, i32_ty, "n") - elif string.strcmp(name, "labs") == 0: - llvmlite.add_param(pool, fn, i64_ty, "n") - else: - llvmlite.add_param(pool, fn, i8_ptr_ty, "s") - elif params == 2: - llvmlite.add_param(pool, fn, i8_ptr_ty, "dst") - llvmlite.add_param(pool, fn, i8_ptr_ty, "src") - elif params == 3: - if string.strcmp(name, "memset") == 0: - llvmlite.add_param(pool, fn, i8_ptr_ty, "dst") - llvmlite.add_param(pool, fn, i32_ty, "c") - llvmlite.add_param(pool, fn, i64_ty, "n") - else: - llvmlite.add_param(pool, fn, i8_ptr_ty, "dst") - llvmlite.add_param(pool, fn, i8_ptr_ty, "src") - llvmlite.add_param(pool, fn, i64_ty, "n") - return fn - def _infer_external_func_ret_ty(self, pool: memhub.MemBuddy | t.CPtr, - func_name: str) -> llvmlite.LLVMType | t.CPtr: - """根据函数名推断外部 includes 函数的返回类型 - - 支持三种函数名形式: - 1. 裸名: "parse", "strlen" - 2. 别名: "json_parse"(from X import parse as json_parse) - 3. 带 SHA1 前缀: "240a9a4157959a9f.parse"(跨模块调用 mangled name) - """ - if pool is None or func_name is None: - return llvmlite.Int32(pool) - - # 提取裸函数名:去掉 SHA1 前缀(如 "240a9a4157959a9f.parse" → "parse") - # SHA1 前缀是 16 位十六进制 + '.',检查是否有 '.' 分隔 - bare_name: str = func_name - dot_pos: str = string.strrchr(func_name, 46) # 46 = ord('.') - if dot_pos is not None: - # '.' 后的部分是裸函数名 - bare_name = dot_pos + 1 - - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - - # 返回 i8* 的函数(指针返回值,截断会导致错误) - if string.strcmp(bare_name, "strchr") == 0 or string.strcmp(func_name, "strchr") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "strrchr") == 0 or string.strcmp(func_name, "strrchr") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "strstr") == 0 or string.strcmp(func_name, "strstr") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "strcpy") == 0 or string.strcmp(func_name, "strcpy") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "strncpy") == 0 or string.strcmp(func_name, "strncpy") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "memset") == 0 or string.strcmp(func_name, "memset") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "memset32") == 0 or string.strcmp(func_name, "memset32") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "memcpy") == 0 or string.strcmp(func_name, "memcpy") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "memmove") == 0 or string.strcmp(func_name, "memmove") == 0: - return i8_ptr_ty - # JSON 解析函数返回 JsonValue*(指针) - # from json.__parser import parse as json_parse → 别名 json_parse 也需覆盖 - if string.strcmp(bare_name, "parse") == 0 or string.strcmp(func_name, "parse") == 0 or string.strcmp(func_name, "json_parse") == 0: - return i8_ptr_ty - # MemBuddy 方法(当类型信息丢失时可能走外部函数路径) - if string.strcmp(func_name, "alloc") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - if string.strcmp(func_name, "calloc") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - if string.strcmp(func_name, "realloc") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - if string.strcmp(func_name, "alloc_buf") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - # VLogger 模块函数(跨模块调用时 stub 未注入,返回指针被截断为 i32 导致崩溃) - if string.strcmp(func_name, "get_logger") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - if string.strcmp(func_name, "fmt_buf") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - # Config 模块函数(跨模块调用时 stub 未注入,返回 i8* 被 inttoptr i32 截断导致路径损坏) - if string.strcmp(func_name, "get_includes_binary_dir") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - # HandlesType 模块函数(返回 ast.AST|t.CPtr 联合类型,跨模块推断为 i32 导致指针截断) - if string.strcmp(bare_name, "_parse_type_string") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - - # 返回 i64 的函数 - if string.strcmp(func_name, "strlen") == 0: - return llvmlite.Int64(pool) - if string.strcmp(func_name, "atoll") == 0: - return llvmlite.Int64(pool) - - # 返回 double 的函数 - if string.strcmp(func_name, "atof") == 0: - return llvmlite.Double(pool) - - # 返回 i8 的函数 - if string.strcmp(func_name, "samestr") == 0: - return llvmlite.Int8(pool) - - # Win32 API 返回指针(VOIDPTR/HANDLE)的函数 - # stubs 翻译时未注入,需推断返回 i8* 避免指针被截断为 i32 导致解引用崩溃 - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - if string.strcmp(func_name, "VirtualAlloc") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "HeapAlloc") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "HeapReAlloc") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "HeapCreate") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GetProcessHeap") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GlobalAlloc") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GlobalFree") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GlobalLock") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "LocalAlloc") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "LocalFree") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GetProcAddress") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GetModuleHandleA") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GetModuleHandleW") == 0: - return i8_ptr_ty - # GetCommandLineA/W 返回 LPSTR(i8*):缺则 64 位指针被截成 i32 → - # inttoptr 后 strlen 读到无效地址(SysLibTest argv 段 ASAN 崩溃, - # 非 ASAN 环境随机表现:IDE 0xC0000005 / 部分环境侥幸可读)。 - if string.strcmp(func_name, "GetCommandLineA") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GetCommandLineW") == 0: - return i8_ptr_ty - # gethostbyname 返回 hostent*(i8*) - if string.strcmp(func_name, "gethostbyname") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "LoadLibraryA") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "LoadLibraryW") == 0: - return i8_ptr_ty - # Win32 Handle 返回函数(HANDLE = void* = i8*) - if string.strcmp(func_name, "GetStdHandle") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "CreateFileA") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "CreateFileW") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "FindFirstFileA") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "FindFirstFileW") == 0: - return i8_ptr_ty - - # Win32 API 返回 i64 (SIZE_T) 的函数 - if string.strcmp(func_name, "VirtualQuery") == 0: - return llvmlite.Int64(pool) - if string.strcmp(func_name, "HeapSize") == 0: - return llvmlite.Int64(pool) - if string.strcmp(func_name, "HeapCompact") == 0: - return llvmlite.Int64(pool) - if string.strcmp(func_name, "GlobalSize") == 0: - return llvmlite.Int64(pool) - - # llvmlite build_* 函数返回类型推断 - # stubs 翻译时未注入,需推断返回类型避免指针被截断为 i32 - # 大多数 build_* 函数返回 Value*(指针),少数终止指令返回 void - if string.strncmp(func_name, "build_", 6) == 0: - # 返回 void 的 build_* 函数(终止指令和无返回值指令) - if string.strcmp(func_name, "build_ret") == 0 or string.strcmp(func_name, "build_ret_void") == 0 or \ - string.strcmp(func_name, "build_store") == 0 or string.strcmp(func_name, "build_br") == 0 or \ - string.strcmp(func_name, "build_cond_br") == 0 or string.strcmp(func_name, "build_unreachable") == 0 or \ - string.strcmp(func_name, "build_switch") == 0: - return llvmlite.Void(pool) - # 其他 build_* 函数返回 Value*(指针) - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - - # llvmlite 类型工厂函数返回 LLVMType*(指针) - # Int1/Int8/Int16/Int32/Int64/Ptr/Func/Array/Struct/Void/Half/Float/Double/FP128/Label - # new_param_node/new_phi_incoming 返回 ParamNode*/PhiIncoming*(指针) - # const_int32/const_int64/ConstFloat/ConstZero/ConstNull/ConstInt 返回 Value*(指针) - # function_get_name/param_get_ty 等访问器返回指针 - if string.strcmp(func_name, "Int1") == 0 or string.strcmp(func_name, "Int8") == 0 or string.strcmp(func_name, "Int16") == 0 or \ - string.strcmp(func_name, "Int32") == 0 or string.strcmp(func_name, "Int64") == 0 or string.strcmp(func_name, "Ptr") == 0 or \ - string.strcmp(func_name, "Func") == 0 or string.strcmp(func_name, "Array") == 0 or string.strcmp(func_name, "Struct") == 0 or \ - string.strcmp(func_name, "Void") == 0 or string.strcmp(func_name, "Half") == 0 or string.strcmp(func_name, "Float") == 0 or \ - string.strcmp(func_name, "Double") == 0 or string.strcmp(func_name, "FP128") == 0 or string.strcmp(func_name, "Label") == 0 or \ - string.strcmp(func_name, "new_param_node") == 0 or string.strcmp(func_name, "new_phi_incoming") == 0 or \ - string.strcmp(func_name, "const_int32") == 0 or string.strcmp(func_name, "const_int64") == 0 or \ - string.strcmp(func_name, "ConstFloat") == 0 or string.strcmp(func_name, "ConstZero") == 0 or \ - string.strcmp(func_name, "ConstNull") == 0 or string.strcmp(func_name, "ConstInt") == 0 or \ - string.strcmp(func_name, "function_get_name") == 0 or string.strcmp(func_name, "param_get_ty") == 0 or \ - string.strcmp(func_name, "value_get_ty") == 0 or string.strcmp(func_name, "value_get_next") == 0 or \ - string.strcmp(func_name, "function_get_ret_ty") == 0 or string.strcmp(func_name, "function_get_params") == 0 or \ - string.strcmp(func_name, "function_get_param_head") == 0 or string.strcmp(func_name, "param_get_next") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - - # 默认 i32(整数):与本模块函数定义的默认返回类型一致(HandlesFunctions.py line 324) - # 已知返回指针的函数在上方显式列出(返回 i8*),已知返回 i64 的函数也显式列出 - # 避免使用 i64 导致 stub 声明(declare i64)与实际定义(define i32)类型不匹配 - # x86-64 ABI 中 i32 返回值在 rax 低 32 位,与 define i32 完全一致 - # WARNING: 未登记的外部函数返回类型默认推断为 i32,若实际返回指针/i64 会被截断 - # --nowarn-register 可抑制此 WARN(自举编译中大量出现,刷屏影响日志收敛) - if VLogger.nowarn_register() == 0: - VLogger.warning( - f"外部函数返回类型未登记,默认推断为 i32(可能截断指针/i64): {func_name}", - "HandlesExprCall") - return llvmlite.Int32(pool) - def _get_external_func_param_ty(self, pool: memhub.MemBuddy | t.CPtr, - func_name: str, - param_idx: int) -> llvmlite.LLVMType | t.CPtr: - """获取外部函数第 param_idx 个参数的期望类型,None 表示用字面量原类型 - - 对 Win32 API 函数的所有非指针参数返回 i64,匹配 declare 中 - ULONG/SIZE_T 被统一翻译为 i64 的情况。 - """ - if pool is None or func_name is None: - return None - - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - - # Win32 API 函数列表:所有非指针参数在 declare 中都是 i64 - # (因为 ULONG/DWORD/SIZE_T 在 LLVM stubs 翻译时都被映射为 i64) - win32_apis: list[str] | t.CPtr = [ - "VirtualAlloc", "VirtualFree", "VirtualProtect", "VirtualQuery", - "VirtualLock", "VirtualUnlock", - "HeapCreate", "HeapDestroy", "HeapAlloc", "HeapReAlloc", - "HeapFree", "HeapSize", "HeapValidate", "HeapCompact", - "GlobalAlloc", "GlobalFree", "GlobalLock", "GlobalUnlock", "GlobalSize", - "LocalAlloc", "LocalFree", - "GetLastError", "SetLastError", - "Sleep", "SleepEx", - "GetTickCount", "GetProcessHeap" - ] - - # list 迭代不支持,用 range + get 替代 - api_count: t.CSizeT = len(win32_apis) - for ai in range(api_count): - api_name: str = win32_apis.get(ai) - if string.strcmp(api_name, func_name) == 0: - return i64_ty - - return None - def _is_sha1_mangled_call(self, call_name: str) -> int: - """判断 call_name 是否为跨模块 Viper 函数("{16位hex}.func" 形式) - - C 库函数(strlen 等裸名)和 Win32 API(VirtualAlloc 等裸名)返回 0, - 不参与精确返回类型解析(走 _infer_external_func_ret_ty 白名单)。 - """ - if call_name is None: - return 0 - first_dot: str = string.strchr(call_name, '.') - if first_dot is None: - return 0 - pre_len: t.CSizeT = t.CSizeT(t.CUInt64T(first_dot) - t.CUInt64T(call_name)) - if pre_len != 16: - return 0 - for hx in range(16): - ch: int = call_name[hx] - if ch < 48 or ch > 57: - if ch < 97 or ch > 102: - if ch < 65 or ch > 70: - return 0 - return 1 - def _emit_llvm_memcpy_intrinsic(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - dst_val: llvmlite.Value | t.CPtr, - src_val: llvmlite.Value | t.CPtr, - num_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: - """将 memcpy 调用映射到 @llvm.memcpy 内联函数 - - 直接接收三个 Value 参数,避免通过 Next 链表遍历(共享 alloca 对象的 - Next 字段可能被其他操作污染,导致链表断裂)。 - """ - if pool is None or builder is None or mod is None: - return None - if dst_val is None or src_val is None or num_val is None: - return None - - # 在函数顶部声明 void_ty,避免后续遮蔽 - void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) - - # 声明 @llvm.memcpy(如未声明) - memcpy_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, "llvm.memcpy") - if memcpy_func is None: - memcpy_func = llvmlite.create_declare(pool, mod, "llvm.memcpy", void_ty) - if memcpy_func is not None: - i8_ptr_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - i64_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i1_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - llvmlite.add_param(pool, memcpy_func, i8_ptr_ty_d, "dst") - llvmlite.add_param(pool, memcpy_func, i8_ptr_ty_d, "src") - llvmlite.add_param(pool, memcpy_func, i64_ty_d, "len") - llvmlite.add_param(pool, memcpy_func, i1_ty_d, "isvolatile") - - # 类型转换: dst, src → i8*; num → i64 - # 注意: 使用 value_get_ty 访问器获取 Ty,避免本地 Value 类型字段索引偏移 - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - - # dst → i8* - dst_coerced: llvmlite.Value | t.CPtr = dst_val - dst_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(dst_val) - if HandlesExpr.is_ptr_type(dst_ty) != 0: - dst_coerced = llvmlite.build_bitcast(builder, dst_val, i8_ptr_ty) - else: - dst_bits: int = HandlesExpr.get_llvm_type_bits(dst_ty) - if dst_bits != 0: - if dst_bits < 64: - dst_coerced = llvmlite.build_zext(builder, dst_val, i64_ty) - dst_coerced = llvmlite.build_inttoptr(builder, dst_coerced, i8_ptr_ty) - - # src → i8* - src_coerced: llvmlite.Value | t.CPtr = src_val - src_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(src_val) - if HandlesExpr.is_ptr_type(src_ty) != 0: - src_coerced = llvmlite.build_bitcast(builder, src_val, i8_ptr_ty) - else: - src_bits: int = HandlesExpr.get_llvm_type_bits(src_ty) - if src_bits != 0: - if src_bits < 64: - src_coerced = llvmlite.build_zext(builder, src_val, i64_ty) - src_coerced = llvmlite.build_inttoptr(builder, src_coerced, i8_ptr_ty) - - # num → i64 - num_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, num_val, i64_ty) - - if dst_coerced is None or src_coerced is None or num_coerced is None: - return None - - # 添加 i1 false 参数(isvolatile)— llvm.memcpy 需要 4 个参数 - false_val: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, llvmlite.Int1(pool), 0, "false") - - # 使用 includes 中的访问器函数构建参数链表,避免本地 Value 类型字段索引偏移 - # (f26cd4c78b4d554c.Value 缺少 GSListNode 的 Next 字段,直接访问 .Next 会修改 .Ty) - llvmlite.value_set_next(dst_coerced, src_coerced) - llvmlite.value_set_next(src_coerced, num_coerced) - if false_val is not None: - llvmlite.value_set_next(num_coerced, false_val) - llvmlite.value_set_next(false_val, None) - else: - llvmlite.value_set_next(num_coerced, None) - - # 使用 build_call 发射 call 指令(内部用 includes Value 类型访问字段,索引正确) - # _ll_name_needs_quote 已对 llvm. 前缀豁免引号 - result: llvmlite.Value | t.CPtr = llvmlite.build_call(builder, "llvm.memcpy", dst_coerced, 4, void_ty, 0) - - # 返回 dst(匹配 C memcpy 语义: 返回 dest 指针) - return dst_coerced - # ============================================================ - # _translate_call_with_kwargs — 带关键字参数的函数调用 - # - # 支持两种语法: - # add(b=4, a=3) — 全关键字乱序 - # greet("Hello", name="World") — 位置 + 关键字混合 - # - # 策略: 遍历 found_func.Params 链表,对每个参数: - # 1. 若位置参数仍有剩余(param_idx < can),取位置参数 - # 2. 否则按参数名匹配关键字参数 - # 3. 按参数顺序构建调用参数链表 - # ============================================================ - - # ============================================================ - def _translate_call_with_kwargs(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - func_name: str, - found_func: llvmlite.Function | t.CPtr, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - keywords: list[ast.AST | t.CPtr] | t.CPtr, - kw_count: t.CSizeT, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """带关键字参数的函数调用,按参数顺序构建调用链表 - - 使用 llvmlite 访问器函数绕过 stub 类型限制: - found_func.Params/RetTy/Name 和 cur_param.Name/Ty/Next 在 stub - 类型中字段不足,直接访问会被 TransPyC 静默跳过。 - """ - head: llvmlite.Value | t.CPtr = None - tail: llvmlite.Value | t.CPtr = None - actual_count: t.CSizeT = 0 - # memcpy 专用: 收集前三个 Value 的独立引用(避免共享 alloca 对象的 Next 被污染) - mc_dst1: llvmlite.Value | t.CPtr = None - mc_src1: llvmlite.Value | t.CPtr = None - mc_num1: llvmlite.Value | t.CPtr = None - - # 遍历函数参数链表(使用访问器获取 Head) - param_idx: t.CSizeT = 0 - cur_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) - - while cur_param is not None: - arg_val: llvmlite.Value | t.CPtr = None - if param_idx < can: - # 优先使用位置参数 - arg: ast.AST | t.CPtr = cargs.get(param_idx) - if arg is not None: - arg_val = HandlesExpr.translate_value( - builder, pool, mod, arg, None, 0, trans) - else: - # 查找匹配的关键字参数 - param_name: str = llvmlite.param_get_name(cur_param) - if param_name is not None: - for ki in range(kw_count): - kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki)) - if kw is None or kw.arg is None or kw.value is None: - continue - if ExprCallCtor._kwarg_name_matches(kw.arg, param_name) == 1: - arg_val = HandlesExpr.translate_value( - builder, pool, mod, kw.value, None, 0, trans) - break - - if arg_val is not None: - # 类型转换(按参数类型,使用访问器) - param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param) - if param_ty is not None: - arg_val = HandlesExpr.coerce_to_type(builder, arg_val, param_ty) - arg_val.Next = None - if head is None: - head = arg_val - else: - tail.Next = arg_val - tail = arg_val - # memcpy 专用: 保存前三个参数的独立引用 - if actual_count == 0: - mc_dst1 = arg_val - elif actual_count == 1: - mc_src1 = arg_val - elif actual_count == 2: - mc_num1 = arg_val - actual_count += 1 - - param_idx += 1 - cur_param = llvmlite.param_get_next(cur_param) - - # 使用模块中的实际函数名(可能带 SHA1 前缀,使用访问器) - # declare 和 define 统一用 found_func.Name: - # - 普通函数的 declare/define 都带 SHA1 前缀(forward_declare_functions 和 stub 注入都用 mangled_name) - # - t.CExtern/t.State/t.CExport 函数的 declare/define 都用裸名 - # 旧逻辑(IsDeclared==1 时用 func_name 裸名)是错误的:stub 注入的 declare Name 已带 SHA1 前缀, - # 用裸名会导致 call @_PathToModuleName 而 define 是 @"sha1._PathToModuleName",链接报 undefined reference - call_name: str = func_name - found_name: str = llvmlite.function_get_name(found_func) - if found_name is not None: - call_name = found_name - - # 返回类型(使用访问器) - call_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) - if call_ret_ty is None: - call_ret_ty = self._infer_external_func_ret_ty(pool, func_name) - - # memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失) - if string.strcmp(func_name, "memcpy") == 0 and actual_count >= 3: - return self._emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst1, mc_src1, mc_num1) +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import sys +import viperlib +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.CallGenBase as CallGenBase + +# ============================================================ +# CallGenLib - CallGenMixin 拆分(阶段 C):C 库声明 / 返回类型推断 / +# 变长参数 / memcpy / kwargs 调用辅助方法 +# +# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class CallGenLib(CallGenBase.CallGenBase): + """C 库声明 / 返回类型推断 / kwargs 调用辅助(继承 Base)""" + + def _ensure_c_lib_declare(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + name: str) -> llvmlite.Function | t.CPtr: + """为已知的 C 库函数创建 declare 声明""" + if pool is None or mod is None or name is None: + return None + + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + ret_ty: llvmlite.LLVMType | t.CPtr = None + params: int = 0 # 参数数量 + + if string.strcmp(name, "strlen") == 0 or string.strcmp(name, "strlength") == 0: + ret_ty = i64_ty + params = 1 + elif string.strcmp(name, "memset") == 0: + ret_ty = i8_ptr_ty + params = 3 + elif string.strcmp(name, "memcpy") == 0: + ret_ty = i8_ptr_ty + params = 3 + elif string.strcmp(name, "memmove") == 0: + ret_ty = i8_ptr_ty + params = 3 + elif string.strcmp(name, "memcmp") == 0: + ret_ty = i32_ty + params = 3 + elif string.strcmp(name, "strcmp") == 0: + ret_ty = i32_ty + params = 2 + elif string.strcmp(name, "strncmp") == 0: + ret_ty = i32_ty + params = 3 + elif string.strcmp(name, "strcpy") == 0: + ret_ty = i8_ptr_ty + params = 2 + elif string.strcmp(name, "strncpy") == 0: + ret_ty = i8_ptr_ty + params = 3 + elif string.strcmp(name, "strcat") == 0: + ret_ty = i8_ptr_ty + params = 2 + elif string.strcmp(name, "puts") == 0: + ret_ty = i32_ty + params = 1 + elif string.strcmp(name, "atoi") == 0: + ret_ty = i32_ty + params = 1 + elif string.strcmp(name, "atol") == 0: + ret_ty = i64_ty + params = 1 + elif string.strcmp(name, "abs") == 0: + ret_ty = i32_ty + params = 1 + elif string.strcmp(name, "labs") == 0: + ret_ty = i64_ty + params = 1 + else: + return None + + # 创建 declare + fn: llvmlite.Function | t.CPtr = llvmlite.create_declare(pool, mod, name, ret_ty) + if fn is None: + return None + # 添加参数 + if params == 1: + if string.strcmp(name, "abs") == 0: + llvmlite.add_param(pool, fn, i32_ty, "n") + elif string.strcmp(name, "labs") == 0: + llvmlite.add_param(pool, fn, i64_ty, "n") + else: + llvmlite.add_param(pool, fn, i8_ptr_ty, "s") + elif params == 2: + llvmlite.add_param(pool, fn, i8_ptr_ty, "dst") + llvmlite.add_param(pool, fn, i8_ptr_ty, "src") + elif params == 3: + if string.strcmp(name, "memset") == 0: + llvmlite.add_param(pool, fn, i8_ptr_ty, "dst") + llvmlite.add_param(pool, fn, i32_ty, "c") + llvmlite.add_param(pool, fn, i64_ty, "n") + else: + llvmlite.add_param(pool, fn, i8_ptr_ty, "dst") + llvmlite.add_param(pool, fn, i8_ptr_ty, "src") + llvmlite.add_param(pool, fn, i64_ty, "n") + return fn + def _infer_external_func_ret_ty(self, pool: memhub.MemBuddy | t.CPtr, + func_name: str) -> llvmlite.LLVMType | t.CPtr: + """根据函数名推断外部 includes 函数的返回类型 + + 支持三种函数名形式: + 1. 裸名: "parse", "strlen" + 2. 别名: "json_parse"(from X import parse as json_parse) + 3. 带 SHA1 前缀: "240a9a4157959a9f.parse"(跨模块调用 mangled name) + """ + if pool is None or func_name is None: + return llvmlite.Int32(pool) + + # 提取裸函数名:去掉 SHA1 前缀(如 "240a9a4157959a9f.parse" → "parse") + # SHA1 前缀是 16 位十六进制 + '.',检查是否有 '.' 分隔 + bare_name: str = func_name + dot_pos: str = string.strrchr(func_name, 46) # 46 = ord('.') + if dot_pos is not None: + # '.' 后的部分是裸函数名 + bare_name = dot_pos + 1 + + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + + # 返回 i8* 的函数(指针返回值,截断会导致错误) + if string.strcmp(bare_name, "strchr") == 0 or string.strcmp(func_name, "strchr") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "strrchr") == 0 or string.strcmp(func_name, "strrchr") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "strstr") == 0 or string.strcmp(func_name, "strstr") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "strcpy") == 0 or string.strcmp(func_name, "strcpy") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "strncpy") == 0 or string.strcmp(func_name, "strncpy") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "memset") == 0 or string.strcmp(func_name, "memset") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "memset32") == 0 or string.strcmp(func_name, "memset32") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "memcpy") == 0 or string.strcmp(func_name, "memcpy") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "memmove") == 0 or string.strcmp(func_name, "memmove") == 0: + return i8_ptr_ty + # JSON 解析函数返回 JsonValue*(指针) + # from json.__parser import parse as json_parse → 别名 json_parse 也需覆盖 + if string.strcmp(bare_name, "parse") == 0 or string.strcmp(func_name, "parse") == 0 or string.strcmp(func_name, "json_parse") == 0: + return i8_ptr_ty + # MemBuddy 方法(当类型信息丢失时可能走外部函数路径) + if string.strcmp(func_name, "alloc") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if string.strcmp(func_name, "calloc") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if string.strcmp(func_name, "realloc") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if string.strcmp(func_name, "alloc_buf") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + # VLogger 模块函数(跨模块调用时 stub 未注入,返回指针被截断为 i32 导致崩溃) + if string.strcmp(func_name, "get_logger") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if string.strcmp(func_name, "fmt_buf") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + # Config 模块函数(跨模块调用时 stub 未注入,返回 i8* 被 inttoptr i32 截断导致路径损坏) + if string.strcmp(func_name, "get_includes_binary_dir") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + # HandlesType 模块函数(返回 ast.AST|t.CPtr 联合类型,跨模块推断为 i32 导致指针截断) + if string.strcmp(bare_name, "_parse_type_string") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + + # 返回 i64 的函数 + if string.strcmp(func_name, "strlen") == 0: + return llvmlite.Int64(pool) + if string.strcmp(func_name, "atoll") == 0: + return llvmlite.Int64(pool) + + # 返回 double 的函数 + if string.strcmp(func_name, "atof") == 0: + return llvmlite.Double(pool) + + # 返回 i8 的函数 + if string.strcmp(func_name, "samestr") == 0: + return llvmlite.Int8(pool) + + # Win32 API 返回指针(VOIDPTR/HANDLE)的函数 + # stubs 翻译时未注入,需推断返回 i8* 避免指针被截断为 i32 导致解引用崩溃 + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if string.strcmp(func_name, "VirtualAlloc") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "HeapAlloc") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "HeapReAlloc") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "HeapCreate") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GetProcessHeap") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GlobalAlloc") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GlobalFree") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GlobalLock") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "LocalAlloc") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "LocalFree") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GetProcAddress") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GetModuleHandleA") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GetModuleHandleW") == 0: + return i8_ptr_ty + # GetCommandLineA/W 返回 LPSTR(i8*):缺则 64 位指针被截成 i32 → + # inttoptr 后 strlen 读到无效地址(SysLibTest argv 段 ASAN 崩溃, + # 非 ASAN 环境随机表现:IDE 0xC0000005 / 部分环境侥幸可读)。 + if string.strcmp(func_name, "GetCommandLineA") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GetCommandLineW") == 0: + return i8_ptr_ty + # gethostbyname 返回 hostent*(i8*) + if string.strcmp(func_name, "gethostbyname") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "LoadLibraryA") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "LoadLibraryW") == 0: + return i8_ptr_ty + # Win32 Handle 返回函数(HANDLE = void* = i8*) + if string.strcmp(func_name, "GetStdHandle") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "CreateFileA") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "CreateFileW") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "FindFirstFileA") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "FindFirstFileW") == 0: + return i8_ptr_ty + + # Win32 API 返回 i64 (SIZE_T) 的函数 + if string.strcmp(func_name, "VirtualQuery") == 0: + return llvmlite.Int64(pool) + if string.strcmp(func_name, "HeapSize") == 0: + return llvmlite.Int64(pool) + if string.strcmp(func_name, "HeapCompact") == 0: + return llvmlite.Int64(pool) + if string.strcmp(func_name, "GlobalSize") == 0: + return llvmlite.Int64(pool) + + # llvmlite build_* 函数返回类型推断 + # stubs 翻译时未注入,需推断返回类型避免指针被截断为 i32 + # 大多数 build_* 函数返回 Value*(指针),少数终止指令返回 void + if string.strncmp(func_name, "build_", 6) == 0: + # 返回 void 的 build_* 函数(终止指令和无返回值指令) + if string.strcmp(func_name, "build_ret") == 0 or string.strcmp(func_name, "build_ret_void") == 0 or \ + string.strcmp(func_name, "build_store") == 0 or string.strcmp(func_name, "build_br") == 0 or \ + string.strcmp(func_name, "build_cond_br") == 0 or string.strcmp(func_name, "build_unreachable") == 0 or \ + string.strcmp(func_name, "build_switch") == 0: + return llvmlite.Void(pool) + # 其他 build_* 函数返回 Value*(指针) + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + + # llvmlite 类型工厂函数返回 LLVMType*(指针) + # Int1/Int8/Int16/Int32/Int64/Ptr/Func/Array/Struct/Void/Half/Float/Double/FP128/Label + # new_param_node/new_phi_incoming 返回 ParamNode*/PhiIncoming*(指针) + # const_int32/const_int64/ConstFloat/ConstZero/ConstNull/ConstInt 返回 Value*(指针) + # function_get_name/param_get_ty 等访问器返回指针 + if string.strcmp(func_name, "Int1") == 0 or string.strcmp(func_name, "Int8") == 0 or string.strcmp(func_name, "Int16") == 0 or \ + string.strcmp(func_name, "Int32") == 0 or string.strcmp(func_name, "Int64") == 0 or string.strcmp(func_name, "Ptr") == 0 or \ + string.strcmp(func_name, "Func") == 0 or string.strcmp(func_name, "Array") == 0 or string.strcmp(func_name, "Struct") == 0 or \ + string.strcmp(func_name, "Void") == 0 or string.strcmp(func_name, "Half") == 0 or string.strcmp(func_name, "Float") == 0 or \ + string.strcmp(func_name, "Double") == 0 or string.strcmp(func_name, "FP128") == 0 or string.strcmp(func_name, "Label") == 0 or \ + string.strcmp(func_name, "new_param_node") == 0 or string.strcmp(func_name, "new_phi_incoming") == 0 or \ + string.strcmp(func_name, "const_int32") == 0 or string.strcmp(func_name, "const_int64") == 0 or \ + string.strcmp(func_name, "ConstFloat") == 0 or string.strcmp(func_name, "ConstZero") == 0 or \ + string.strcmp(func_name, "ConstNull") == 0 or string.strcmp(func_name, "ConstInt") == 0 or \ + string.strcmp(func_name, "function_get_name") == 0 or string.strcmp(func_name, "param_get_ty") == 0 or \ + string.strcmp(func_name, "value_get_ty") == 0 or string.strcmp(func_name, "value_get_next") == 0 or \ + string.strcmp(func_name, "function_get_ret_ty") == 0 or string.strcmp(func_name, "function_get_params") == 0 or \ + string.strcmp(func_name, "function_get_param_head") == 0 or string.strcmp(func_name, "param_get_next") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + + # 默认 i32(整数):与本模块函数定义的默认返回类型一致(HandlesFunctions.py line 324) + # 已知返回指针的函数在上方显式列出(返回 i8*),已知返回 i64 的函数也显式列出 + # 避免使用 i64 导致 stub 声明(declare i64)与实际定义(define i32)类型不匹配 + # x86-64 ABI 中 i32 返回值在 rax 低 32 位,与 define i32 完全一致 + # WARNING: 未登记的外部函数返回类型默认推断为 i32,若实际返回指针/i64 会被截断 + # --nowarn-register 可抑制此 WARN(自举编译中大量出现,刷屏影响日志收敛) + if VLogger.nowarn_register() == 0: + VLogger.warning( + f"外部函数返回类型未登记,默认推断为 i32(可能截断指针/i64): {func_name}", + "HandlesExprCall") + return llvmlite.Int32(pool) + def _get_external_func_param_ty(self, pool: memhub.MemBuddy | t.CPtr, + func_name: str, + param_idx: int) -> llvmlite.LLVMType | t.CPtr: + """获取外部函数第 param_idx 个参数的期望类型,None 表示用字面量原类型 + + 对 Win32 API 函数的所有非指针参数返回 i64,匹配 declare 中 + ULONG/SIZE_T 被统一翻译为 i64 的情况。 + """ + if pool is None or func_name is None: + return None + + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + + # Win32 API 函数列表:所有非指针参数在 declare 中都是 i64 + # (因为 ULONG/DWORD/SIZE_T 在 LLVM stubs 翻译时都被映射为 i64) + win32_apis: list[str] | t.CPtr = [ + "VirtualAlloc", "VirtualFree", "VirtualProtect", "VirtualQuery", + "VirtualLock", "VirtualUnlock", + "HeapCreate", "HeapDestroy", "HeapAlloc", "HeapReAlloc", + "HeapFree", "HeapSize", "HeapValidate", "HeapCompact", + "GlobalAlloc", "GlobalFree", "GlobalLock", "GlobalUnlock", "GlobalSize", + "LocalAlloc", "LocalFree", + "GetLastError", "SetLastError", + "Sleep", "SleepEx", + "GetTickCount", "GetProcessHeap" + ] + + # list 迭代不支持,用 range + get 替代 + api_count: t.CSizeT = len(win32_apis) + for ai in range(api_count): + api_name: str = win32_apis.get(ai) + if string.strcmp(api_name, func_name) == 0: + return i64_ty + + return None + def _is_sha1_mangled_call(self, call_name: str) -> int: + """判断 call_name 是否为跨模块 Viper 函数("{16位hex}.func" 形式) + + C 库函数(strlen 等裸名)和 Win32 API(VirtualAlloc 等裸名)返回 0, + 不参与精确返回类型解析(走 _infer_external_func_ret_ty 白名单)。 + """ + if call_name is None: + return 0 + first_dot: str = string.strchr(call_name, '.') + if first_dot is None: + return 0 + pre_len: t.CSizeT = t.CSizeT(t.CUInt64T(first_dot) - t.CUInt64T(call_name)) + if pre_len != 16: + return 0 + for hx in range(16): + ch: int = call_name[hx] + if ch < 48 or ch > 57: + if ch < 97 or ch > 102: + if ch < 65 or ch > 70: + return 0 + return 1 + def _emit_llvm_memcpy_intrinsic(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + dst_val: llvmlite.Value | t.CPtr, + src_val: llvmlite.Value | t.CPtr, + num_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: + """将 memcpy 调用映射到 @llvm.memcpy 内联函数 + + 直接接收三个 Value 参数,避免通过 Next 链表遍历(共享 alloca 对象的 + Next 字段可能被其他操作污染,导致链表断裂)。 + """ + if pool is None or builder is None or mod is None: + return None + if dst_val is None or src_val is None or num_val is None: + return None + + # 在函数顶部声明 void_ty,避免后续遮蔽 + void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + + # 声明 @llvm.memcpy(如未声明) + memcpy_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, "llvm.memcpy") + if memcpy_func is None: + memcpy_func = llvmlite.create_declare(pool, mod, "llvm.memcpy", void_ty) + if memcpy_func is not None: + i8_ptr_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + i64_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i1_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + llvmlite.add_param(pool, memcpy_func, i8_ptr_ty_d, "dst") + llvmlite.add_param(pool, memcpy_func, i8_ptr_ty_d, "src") + llvmlite.add_param(pool, memcpy_func, i64_ty_d, "len") + llvmlite.add_param(pool, memcpy_func, i1_ty_d, "isvolatile") + + # 类型转换: dst, src → i8*; num → i64 + # 注意: 使用 value_get_ty 访问器获取 Ty,避免本地 Value 类型字段索引偏移 + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + + # dst → i8* + dst_coerced: llvmlite.Value | t.CPtr = dst_val + dst_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(dst_val) + if self.Gen.ExprGenBase.is_ptr_type(dst_ty) != 0: + dst_coerced = llvmlite.build_bitcast(builder, dst_val, i8_ptr_ty) + else: + dst_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(dst_ty) + if dst_bits != 0: + if dst_bits < 64: + dst_coerced = llvmlite.build_zext(builder, dst_val, i64_ty) + dst_coerced = llvmlite.build_inttoptr(builder, dst_coerced, i8_ptr_ty) + + # src → i8* + src_coerced: llvmlite.Value | t.CPtr = src_val + src_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(src_val) + if self.Gen.ExprGenBase.is_ptr_type(src_ty) != 0: + src_coerced = llvmlite.build_bitcast(builder, src_val, i8_ptr_ty) + else: + src_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(src_ty) + if src_bits != 0: + if src_bits < 64: + src_coerced = llvmlite.build_zext(builder, src_val, i64_ty) + src_coerced = llvmlite.build_inttoptr(builder, src_coerced, i8_ptr_ty) + + # num → i64 + num_coerced: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type(builder, num_val, i64_ty) + + if dst_coerced is None or src_coerced is None or num_coerced is None: + return None + + # 添加 i1 false 参数(isvolatile)— llvm.memcpy 需要 4 个参数 + false_val: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, llvmlite.Int1(pool), 0, "false") + + # 使用 includes 中的访问器函数构建参数链表,避免本地 Value 类型字段索引偏移 + # (f26cd4c78b4d554c.Value 缺少 GSListNode 的 Next 字段,直接访问 .Next 会修改 .Ty) + llvmlite.value_set_next(dst_coerced, src_coerced) + llvmlite.value_set_next(src_coerced, num_coerced) + if false_val is not None: + llvmlite.value_set_next(num_coerced, false_val) + llvmlite.value_set_next(false_val, None) + else: + llvmlite.value_set_next(num_coerced, None) + + # 使用 build_call 发射 call 指令(内部用 includes Value 类型访问字段,索引正确) + # _ll_name_needs_quote 已对 llvm. 前缀豁免引号 + result: llvmlite.Value | t.CPtr = llvmlite.build_call(builder, "llvm.memcpy", dst_coerced, 4, void_ty, 0) + + # 返回 dst(匹配 C memcpy 语义: 返回 dest 指针) + return dst_coerced + # ============================================================ + # _translate_call_with_kwargs — 带关键字参数的函数调用 + # + # 支持两种语法: + # add(b=4, a=3) — 全关键字乱序 + # greet("Hello", name="World") — 位置 + 关键字混合 + # + # 策略: 遍历 found_func.Params 链表,对每个参数: + # 1. 若位置参数仍有剩余(param_idx < can),取位置参数 + # 2. 否则按参数名匹配关键字参数 + # 3. 按参数顺序构建调用参数链表 + # ============================================================ + + # ============================================================ + def _translate_call_with_kwargs(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + func_name: str, + found_func: llvmlite.Function | t.CPtr, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + keywords: list[ast.AST | t.CPtr] | t.CPtr, + kw_count: t.CSizeT, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """带关键字参数的函数调用,按参数顺序构建调用链表 + + 使用 llvmlite 访问器函数绕过 stub 类型限制: + found_func.Params/RetTy/Name 和 cur_param.Name/Ty/Next 在 stub + 类型中字段不足,直接访问会被 TransPyC 静默跳过。 + """ + head: llvmlite.Value | t.CPtr = None + tail: llvmlite.Value | t.CPtr = None + actual_count: t.CSizeT = 0 + # memcpy 专用: 收集前三个 Value 的独立引用(避免共享 alloca 对象的 Next 被污染) + mc_dst1: llvmlite.Value | t.CPtr = None + mc_src1: llvmlite.Value | t.CPtr = None + mc_num1: llvmlite.Value | t.CPtr = None + + # 遍历函数参数链表(使用访问器获取 Head) + param_idx: t.CSizeT = 0 + cur_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + + while cur_param is not None: + arg_val: llvmlite.Value | t.CPtr = None + if param_idx < can: + # 优先使用位置参数 + arg: ast.AST | t.CPtr = cargs.get(param_idx) + if arg is not None: + arg_val = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg, None, 0, trans) + else: + # 查找匹配的关键字参数 + param_name: str = llvmlite.param_get_name(cur_param) + if param_name is not None: + for ki in range(kw_count): + kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki)) + if kw is None or kw.arg is None or kw.value is None: + continue + if self.Gen.CallGenCall._kwarg_name_matches(kw.arg, param_name) == 1: + arg_val = self.Gen.ExprGen.translate_value( + builder, pool, mod, kw.value, None, 0, trans) + break + + if arg_val is not None: + # 类型转换(按参数类型,使用访问器) + param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param) + if param_ty is not None: + arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, param_ty) + arg_val.Next = None + if head is None: + head = arg_val + else: + tail.Next = arg_val + tail = arg_val + # memcpy 专用: 保存前三个参数的独立引用 + if actual_count == 0: + mc_dst1 = arg_val + elif actual_count == 1: + mc_src1 = arg_val + elif actual_count == 2: + mc_num1 = arg_val + actual_count += 1 + + param_idx += 1 + cur_param = llvmlite.param_get_next(cur_param) + + # 使用模块中的实际函数名(可能带 SHA1 前缀,使用访问器) + # declare 和 define 统一用 found_func.Name: + # - 普通函数的 declare/define 都带 SHA1 前缀(forward_declare_functions 和 stub 注入都用 mangled_name) + # - t.CExtern/t.State/t.CExport 函数的 declare/define 都用裸名 + # 旧逻辑(IsDeclared==1 时用 func_name 裸名)是错误的:stub 注入的 declare Name 已带 SHA1 前缀, + # 用裸名会导致 call @_PathToModuleName 而 define 是 @"sha1._PathToModuleName",链接报 undefined reference + call_name: str = func_name + found_name: str = llvmlite.function_get_name(found_func) + if found_name is not None: + call_name = found_name + + # 返回类型(使用访问器) + call_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) + if call_ret_ty is None: + call_ret_ty = self._infer_external_func_ret_ty(pool, func_name) + + # memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失) + if string.strcmp(func_name, "memcpy") == 0 and actual_count >= 3: + return self._emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst1, mc_src1, mc_num1) return llvmlite.build_call(builder, call_name, head, actual_count, call_ret_ty, 0) \ No newline at end of file diff --git a/App/lib/core/Gen/CallGenMixin.vp b/App/lib/core/Gen/CallGenMixin.vp index 61a3445..5ddc48e 100644 --- a/App/lib/core/Gen/CallGenMixin.vp +++ b/App/lib/core/Gen/CallGenMixin.vp @@ -1,1162 +1,1151 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import sys -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesFunctions as HandlesFunctions -import lib.core.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.CompilerFactory as CompilerFactory - - -import lib.core.Gen.CallGenBase as CallGenBase -import lib.core.Handles.ExprCallBase as ExprCallBase -import lib.core.Handles.ExprCallCall as ExprCallCall -import lib.core.Handles.ExprCallCtor as ExprCallCtor -import lib.core.Handles.ExprCallHandle as ExprCallHandle -import lib.core.Handles.ExprCallTable as ExprCallTable - - -# ============================================================ -# CallGenMixin - 调用分派 Mixin(拆分后顶层,阶段 A:底层已拆至 -# CallGenBase/CallGenCBuiltin/CallGenLeafKit) -# -# 500~1500 行/文件架构重构阶段 A:底层自包含组(模块查找/返回类型解析/ -# c.*/asm/llvmir/EH/isinstance/闭包/print/函数表)已拆出,本文件保留 -# 调用分派中枢(translate_call 等)。继承链 CallGenMixin → LeafKit → -# CBuiltin → Base,@t.NoVTable 静态绑定沿 MRO 解析 self 调用。 -# -# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 -# ============================================================ - - -# ============================================================ -# 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug) -# ============================================================ -GLOBAL_FUNC_MAX: t.CDefine = 8192 -GLOBAL_DEFAULTS_MAX: t.CDefine = 4096 -_CEXPORT_MAX: t.CDefine = 256 -ASM_MAX_OPERANDS: t.CDefine = 16 -ASM_TEXT_BUF_SIZE: t.CDefine = 2048 -ASM_CONST_BUF_SIZE: t.CDefine = 512 -ASM_ARGS_BUF_SIZE: t.CDefine = 512 -ASM_LINE_BUF_SIZE: t.CDefine = 4096 -LLVMIR_MAX_OPS: t.CDefine = 16 -LLVMIR_TEMPLATE_BUF: t.CDefine = 512 -# 闭包名表大小(原 HandlesExprCall 模块级常量) -MAX_CLOSURE_NAMES: t.CDefine = 128 -# 函数指针签名表大小(原 HandlesExprCall 模块级常量) -MAX_FUNC_PTR_SIGS: t.CDefine = 64 -# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32) -ISINSTANCE_CLASS_MAX: t.CDefine = 64 - - -# ============================================================ -# CallGenMixin - 调用分派中枢(顶层,继承 LeafKit) -# ============================================================ -@t.NoVTable -class CallGenMixin(CallGenBase.CallGenBase): - """调用分派 Mixin(拆分后顶层,直接继承 CallGenBase——TPV self 调用仅支持 1 级父类)""" - - # ============================================================ - # 翻译函数调用 Call(func, args) — 模块级版本 - # ============================================================ - def translate_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译函数调用,返回 call 结果 Value""" - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) - if cl is None: - return None - - func_name: str = HandlesExpr.get_func_name(cl.func) - - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - can: t.CSizeT = 0 - if cargs is not None: - can = len(cargs) - - # super()/ctraits 检测:void 方法(如 __init__)命中后 build_call 返回 - # None 属预期(void call 无 SSA 值),必须用 hit_box 区分"命中已处理" - # 与"未命中",否则 None 被误判继续主路径 → 内层 Call(super) 当裸名 - # 调用报"super 未定义且未导入"(SuperTest 根因)。 - h1_hit: t.CPtr = stdlib.malloc(4) - if h1_hit is not None: - h1_hit[0] = 0 - _tc_h1_super_ctraits_res: llvmlite.Value | t.CPtr = ExprCallHandle._tc_h1_super_ctraits( - pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can, h1_hit) - h1_hit_val: int = 0 - if h1_hit is not None: - h1_hit_val = h1_hit[0] - stdlib.free(h1_hit) - if _tc_h1_super_ctraits_res is not None: - return _tc_h1_super_ctraits_res - if h1_hit_val != 0: - # 命中 super()/ctraits 但无返回值(void 方法/宏调用):视为已处理 - return None - - # ---- func_name is None:泛型实例化 + 类型转换 ---- - if func_name is None: - # 检查是否是 list[int](pool) 形式的泛型实例化调用 - # Subscript 节点作为 Call func: 泛型类构造函数 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Subscript and trans is not None: - sub_node: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(cl.func) - if sub_node.value is not None and sub_node.value.kind() == ast.ASTKind.Name: - gen_nm_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_node.value) - gen_class_name: str = gen_nm_node.id - # 检查是否是泛型类模板 - template_cd: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(gen_class_name) - if template_cd is not None: - # 提取类型实参 - gen_type_args: list[str] | t.CPtr = ExprCallCtor._extract_type_args_from_slice(pool, sub_node.slice) - if gen_type_args is not None and len(gen_type_args) > 0: - # 特化泛型类,返回特化类名 - spec_name: str = HandlesClassDef._specialize_generic_class( - trans, gen_class_name, gen_type_args) - if spec_name is not None: - # 泛型类构造调用: list[str](pool, 8) → __new__ + __before_init__ + __init__ - # 不能直接用 spec_name 作为 func_name(会走裸名调用路径, - # 被 star import 回退误导用错误的 SHA1,且缺少 __new__ 方法名后缀) - return ExprCallCtor._translate_generic_ctor_call( - pool, builder, mod, spec_name, cl, trans) - else: - # 泛型类模板未找到:可能是泛型函数手动传类型参数调用 xxx[T](x) - # (对应 TPC _HandleGenericCallExplicitLlvm;TPV 无泛型函数特化, - # 泛型函数按普通函数编译,类型参数 [T] 仅在函数定义处消费)。 - # 检查当前模块是否已定义同名函数(def double[T] 编译后即普通函数 - # double),若是则丢弃 [t.CInt] 显式类型参数,退回普通函数调用。 - if self.find_func_in_module(mod, gen_class_name) is not None: - func_name = gen_class_name - else: - # 泛型类模板未找到:可能未 import 定义模块 - gt_err: str = pool.alloc(256) - if gt_err is not None: - viperlib.snprintf(gt_err, 256, "泛型类 '%s' 未找到模板,可能未 import 定义模块", gen_class_name) - HandlesType.fatal_error(gen_nm_node, gt_err) - HandlesType.fatal_error(gen_nm_node, "泛型类模板未找到") - if func_name is None: - # 检查是否是 (A | t.CPtr)(value) 形式的类型转换 - # BinOp 节点作为 Call func: 联合类型注解用作类型转换 - if cl.func is not None and cl.func.kind() == ast.ASTKind.BinOp and trans is not None: - binop_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, cl.func, trans._imported_modules, trans._from_imports, trans) - if binop_ty is not None: - binop_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if binop_args is not None and len(binop_args) == 1: - binop_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, binop_args.get(0), funcs_ptr, func_count, trans) - if binop_arg_val is not None: - return ExprCallCtor._translate_t_type_cast(pool, builder, binop_arg_val, binop_ty) - return None - - # c.Asm/c.LLVMIR 等特殊调用:void(无输出)时 translate_c_asm/llvmir - # 返回 None 表示"已处理无返回值",需用 hit_box 区分"未命中", - # 否则会误判未命中继续走外部函数路径(外部函数返回类型未登记 Asm + - # t.ASM_DESCR 被当 CDefine 常量赋值) - h2_hit: t.CPtr = stdlib.malloc(4) - if h2_hit is not None: - h2_hit[0] = 0 - _tc_h2_c_special_res: llvmlite.Value | t.CPtr = ExprCallHandle._tc_h2_c_special( - pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can, h2_hit) - h2_hit_val: int = 0 - if h2_hit is not None: - h2_hit_val = h2_hit[0] - stdlib.free(h2_hit) - if _tc_h2_c_special_res is not None: - return _tc_h2_c_special_res - if h2_hit_val != 0: - # 命中 c.Asm/c.LLVMIR 但无返回值(void):视为已处理 - return None - - _tc_h3_stdarg_cast_res: llvmlite.Value | t.CPtr = ExprCallHandle._tc_h3_stdarg_cast( - pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) - if _tc_h3_stdarg_cast_res is not None: - return _tc_h3_stdarg_cast_res - - _tc_h4_type_casts_res: llvmlite.Value | t.CPtr = ExprCallHandle._tc_h4_type_casts( - pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) - if _tc_h4_type_casts_res is not None: - return _tc_h4_type_casts_res - - _tc_h5_sizeof_len_isinst_res: llvmlite.Value | t.CPtr = ExprCallHandle._tc_h5_sizeof_len_isinst( - pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) - if _tc_h5_sizeof_len_isinst_res is not None: - return _tc_h5_sizeof_len_isinst_res - - # c.Asm/c.LLVMIR 等方法调用分派:方法调用识别成功但返回 None - # (如编译器生成方法 __before_init__/__init__ 恒返回 void,_translate_ - # method_call 或 _emit_eh_guarded_call 处理后可能返回 None)时,须用 - # hit_box 区分"已识别为方法调用"与"未命中",否则 translate_call 误判 - # 未命中继续走跨模块函数路径,把对象名当模块名查 SHA1 → - # "跨模块调用 'buf.__before_init__' 找不到模块 SHA1"(memhub.alloc_buf 根因)。 - h6_hit: t.CPtr = stdlib.malloc(4) - if h6_hit is not None: - h6_hit[0] = 0 - _tc_h6_method_dispatch_res: llvmlite.Value | t.CPtr = ExprCallHandle._tc_h6_method_dispatch( - pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can, h6_hit) - h6_hit_val: int = 0 - if h6_hit is not None: - h6_hit_val = h6_hit[0] - stdlib.free(h6_hit) - if _tc_h6_method_dispatch_res is not None: - return _tc_h6_method_dispatch_res - if h6_hit_val != 0: - # 命中方法调用路径但无返回值(编译器生成方法等 void 语义):视为已处理 - return None - - # 获取关键字参数 - keywords: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords - kw_count: t.CSizeT = 0 - if keywords is not None: - kw_count = len(keywords) - - # 检查是否是结构体构造函数: Point() / Point(10, 20) / Point(x=10, y=20) - # 命名空间隔离:严格模式下检查结构体可见性 - # - 裸名 Class(): 需要 from X import Class 或本地定义 - # - 模块限定 Module.Class(): 需要 import Module - # 用 find_struct_by_module 规避跨模块同名 find_struct 找错 - struct_ty: llvmlite.LLVMType | t.CPtr = None - gen_ctor_entry: HandlesStruct.StructEntry | t.CPtr = None - vis: int = HandlesStruct.is_struct_visible(func_name) - if vis != 0: - if trans is not None: - gen_ctor_entry = HandlesStruct.find_struct_by_module(func_name, trans.ModuleSha1) - if gen_ctor_entry is None: - gen_ctor_entry = HandlesStruct.find_struct(func_name) - if gen_ctor_entry is not None: - struct_ty = gen_ctor_entry.Ty - elif trans is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - at_qc: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if at_qc.value is not None and at_qc.value.kind() == ast.ASTKind.Name: - mod_nm_qc: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_qc.value) - imp_ok: int = HandlesImports.is_module_imported(trans._imported_modules, mod_nm_qc.id) - if imp_ok != 0: - if trans is not None: - gen_ctor_entry = HandlesStruct.find_struct_by_module(func_name, trans.ModuleSha1) - if gen_ctor_entry is None: - gen_ctor_entry = HandlesStruct.find_struct(func_name) - if gen_ctor_entry is not None: - struct_ty = gen_ctor_entry.Ty - elif at_qc.value is not None and at_qc.value.kind() == ast.ASTKind.Attribute: - # 多层模块路径类构造: w32.fileio.File(...)(value 是嵌套 Attribute)。 - # 仅两层(fileio.File)支持时,三层会被跳过 → 退化走跨模块普通函数 - # 调用生成 @File 裸名 → 链接 undefined symbol: File(SysLibTest 根因)。 - # 模块路径经 attr_module_path_str 递归拼接("w32.fileio"), - # import 检查用完整路径(import w32.fileio 注册 "w32.fileio"), - # 结构体查找用该模块自身 SHA1 精确命中(find_struct_by_module)。 - # 注:经 HandlesExpr 委托调用(跨 mixin 不能 self. 直接调, - # @t.NoVTable 静态绑定会 mangle 成 CallGenMixin. 前缀 → undefined reference)。 - mod_path_qc: str = HandlesExpr.attr_module_path_str(pool, at_qc.value) - if mod_path_qc is not None: - imp_ok_qc: int = HandlesImports.is_module_imported( - trans._imported_modules, mod_path_qc) - if imp_ok_qc != 0: - mod_sha1_qc: str = self._lookup_module_sha1(mod_path_qc) - if mod_sha1_qc is not None: - gen_ctor_entry = HandlesStruct.find_struct_by_module( - func_name, mod_sha1_qc) - if gen_ctor_entry is None: - gen_ctor_entry = HandlesStruct.find_struct(func_name) - if gen_ctor_entry is not None: - struct_ty = gen_ctor_entry.Ty - # 别名导入的类构造: from X import Class as Alias → Alias(args) - # 可见性列表按别名注册(HandleImportFromNames 用 local_name=asname),但结构体 - # 按原名注册(如 Keyword as KwNode → 可见 "KwNode"、注册名 "Keyword")。 - # 直接按别名 find_struct 查不到 → 误走普通函数路径生成 @sha1.Keyword 调用 - # (该函数不存在)→ 链接期 undefined reference。此处解析别名→原名再查结构体。 - if gen_ctor_entry is None and trans is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Name: - if trans._from_imports is not None: - ctor_sha1: str = self._lookup_mod_sha1(pool, trans._from_imports, func_name, 0) - if ctor_sha1 is not None: - ctor_orig: str = HandlesImports.lookup_from_import_original( - trans._from_imports, func_name) - if ctor_orig is not None: - # 复制到独立 null 终止缓冲区(from_imports 内部缓冲未终止) - co_len: t.CSizeT = 0 - while ctor_orig[co_len] != ' ' and ctor_orig[co_len] != '\0': - co_len += 1 - co_buf: str = pool.alloc(co_len + 1) - if co_buf is not None: - for co_i in range(co_len): - co_buf[co_i] = ctor_orig[co_i] - co_buf[co_len] = '\0' - # 原名结构体查找(可见性已由别名保证,原名无需再查) - gen_ctor_entry = HandlesStruct.find_struct_by_module(co_buf, ctor_sha1) - if gen_ctor_entry is None: - gen_ctor_entry = HandlesStruct.find_struct(co_buf) - if gen_ctor_entry is not None: - struct_ty = gen_ctor_entry.Ty - func_name = co_buf - if struct_ty is not None: - if can == 0 and kw_count == 0: - # OOP 结构体:即使无参数也调用 __before_init__ - # 用 gen_ctor_entry 规避跨模块同名 find_struct 找错 - ctor_is_oop: int = 0 - if gen_ctor_entry is not None: - ctor_is_oop = gen_ctor_entry.IsOOP - if ctor_is_oop != 0: - return ExprCallCtor._translate_struct_ctor( - pool, builder, mod, struct_ty, func_name, cargs, 0, trans) - # @t.NoVTable 类(无方法、类语义/指针对象):无参构造也应分配内存 - # 返回指针。否则按值结构体返回 ConstZero(struct_ty),LHS 联合注解 - # (如 Plain|CPtr)存 0 指针 → p.v 解引用 NULL 段错误 - # (TpvIsinstanceTest Plain 场景崩溃根因)。 - ctor_is_novt: int = 0 - if gen_ctor_entry is not None: - ctor_is_novt = gen_ctor_entry.IsNoVTable - if ctor_is_novt != 0: - return ExprCallCtor._translate_struct_ctor( - pool, builder, mod, struct_ty, func_name, cargs, 0, trans) - # 普通结构体:检查是否有默认值(用 entry 直接访问) - gen_has_defaults: int = 0 - if gen_ctor_entry is not None: - for gdi in range(gen_ctor_entry.FieldCount): - gdf: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( - gen_ctor_entry, gdi) - if gdf is not None and gdf.DefaultVal is not None: - gen_has_defaults = 1 - break - else: - gen_has_defaults = HandlesStruct.struct_has_defaults(func_name) - if gen_has_defaults == 1: - # 有默认值:走构造函数路径应用默认值 - return ExprCallCtor._translate_struct_ctor( - pool, builder, mod, struct_ty, func_name, cargs, 0, trans) - # 无默认值:返回 zeroinitializer - ret: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) - return ret - if kw_count > 0: - # 有关键字参数:按字段名赋值 - return ExprCallCtor._translate_struct_ctor_kw( - pool, builder, mod, struct_ty, func_name, cargs, can, - keywords, kw_count, trans) - # 仅位置参数:按字段顺序构建 - return ExprCallCtor._translate_struct_ctor( - pool, builder, mod, struct_ty, func_name, cargs, can, trans) - - # 裸名泛型类模板构造: Box(42) → 从实参推断类型实参 → 特化 → 构造 - # (TPC 参考: _HandleGenericClassNewLlvm;GenericTest Test4 Box(42)/Test5 - # Pair(10,20)/Test10 Counter(0) 依赖此路径。显式类型实参 list[int](mb) - # 走 translate_call 上方的 Subscript 分支,此处处理裸名 + 推断。) - # 支持模块限定调用(vector.Vector(...)):func_name 是 attr("Vector"), - # 需确认模块已导入(模板查找兜底——普通函数如 stdlib.free 的 attr 找 - # 不到模板 → 回落普通调用)。 - if struct_ty is None and gen_ctor_entry is None and trans is not None: - is_gen_bare: int = 0 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: - is_gen_bare = 1 - elif cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - at_gb: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if at_gb.value is not None and at_gb.value.kind() == ast.ASTKind.Name: - am_gb: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_gb.value) - if am_gb.id is not None: - if HandlesImports.is_module_imported(trans._imported_modules, am_gb.id) != 0: - is_gen_bare = 1 - if is_gen_bare != 0: - template_cd_bare: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(func_name) - if template_cd_bare is not None and template_cd_bare.type_params is not None: - tp_bare: list[str] | t.CPtr = template_cd_bare.type_params - tp_count_bare: t.CSizeT = len(tp_bare) - if tp_count_bare > 0: - inferred_args_bare: list[str] | t.CPtr = list[str](pool, 8) - if inferred_args_bare is not None: - # 对齐 TPC _HandleGenericClassNewLlvm:先收集全部实参 - # 推断类型,过滤纯 int(排除 pool 等非 T 参数), - # hint_types 优先填充(Vector(pool,8,CFloat64T(0.0)) - # → Vector[double];Vector(pool,10,CInt(0)) → Vector[int]) - hint_bare: list[str] | t.CPtr = list[str](pool, 8) - if hint_bare is not None: - hi_bare: t.CSizeT - for hi_bare in range(can): - hty_bare: str = ExprCallCtor._infer_generic_ctor_type_arg(pool, cargs.get(hi_bare), func_name) - if string.strcmp(hty_bare, "int") != 0: - hint_bare.append(hty_bare) - tpi_bare: t.CSizeT = 0 - for tpi_bare in range(tp_count_bare): - ta_bare: str = "int" - if tpi_bare < len(hint_bare): - ta_bare = hint_bare.get(tpi_bare) - elif tpi_bare < can: - ta_bare = ExprCallCtor._infer_generic_ctor_type_arg(pool, cargs.get(tpi_bare), func_name) - inferred_args_bare.append(ta_bare) - spec_name_bare: str = HandlesClassDef._specialize_generic_class( - trans, func_name, inferred_args_bare) - if spec_name_bare is not None: - return ExprCallCtor._translate_generic_ctor_call( - pool, builder, mod, spec_name_bare, cl, trans) - - # REnum 变体构造检测: ClassName.VariantName(args...) - # 如 LLVMType.Int(1) → 构造 LLVMType 的 Int 变体 - # 必须在跨模块调用查找之前,否则 ClassName 会被误判为模块名 - # 对应 TPC HandlesExprCall.py:585-644 的三条检测路径之一 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - rc_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if rc_at.value is not None and rc_at.value.kind() == ast.ASTKind.Name: - rc_cls_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rc_at.value) - if rc_cls_node.id is not None: - rc_cls_name: str = rc_cls_node.id - # 检查 ClassName 是否是已注册的 REnum 类 - if HandlesClassDef._is_renum_class_name(rc_cls_name) != 0: - # 在该 REnum 类中查找变体名 func_name - rc_tag: int = HandlesClassDef._lookup_renum_variant_in_class( - rc_cls_name, func_name) - if rc_tag >= 0: - return ExprCallCtor._translate_renum_construct( - pool, builder, mod, rc_cls_name, func_name, - rc_tag, cargs, can, trans) - elif rc_at.value is not None and rc_at.value.kind() == ast.ASTKind.Attribute: - # 模块限定 REnum 变体构造: mod.Class.Variant(args...) - # 如 llvmlite.LLVMType.Struct(...) → 构造 llvmlite 模块 LLVMType 的 Struct 变体。 - # 根因:此前只支持单层 Name(ClassName.Variant),嵌套属性漏检 → 误走跨模块 - # 函数路径 → _lookup_module_sha1("llvmlite.LLVMType") 查无 → 报"跨模块调用 - # 'llvmlite.LLVMType.Struct' 找不到模块 SHA1"。跨模块任意同名可接受(REnum - # 表按类名全局注册):仅要求最左模块已导入 + 末段类名在全局 REnum 表中命中, - # 不做"类必须属于该模块"校验(未命中则按后续函数路径 fast-fail)。 - rc_mq_path: str = HandlesExpr.attr_module_path_str(pool, rc_at.value) - if rc_mq_path is not None: - rc_mq_dot: str = string.strrchr(rc_mq_path, 46) # 46 = ord('.') - if rc_mq_dot is not None and rc_mq_dot[1] != '\0': - # 模块路径 = 末段之前(支持多级: w32.fileio.Class.Variant)。 - # 注意:不能用 rc_mq_dot - rc_mq_path 指针减法(TPC 直接发 - # sub i8*, i8* 非法 IR),用 strlen 整数差扣除末段与分隔点。 - rc_mq_len: t.CSizeT = string.strlen(rc_mq_path) - string.strlen(rc_mq_dot + 1) - 1 - rc_mq_mod: str = pool.alloc(rc_mq_len + 1) - if rc_mq_mod is not None: - string.memcpy(rc_mq_mod, rc_mq_path, rc_mq_len) - rc_mq_mod[rc_mq_len] = '\0' - rc_mq_imp: int = 1 - if trans is not None and trans._imported_modules is not None: - rc_mq_imp = HandlesImports.is_module_imported( - trans._imported_modules, rc_mq_mod) - if rc_mq_imp != 0: - rc_mq_cls: str = rc_mq_dot + 1 - # 检查类名是否是已注册的 REnum 类 - if HandlesClassDef._is_renum_class_name(rc_mq_cls) != 0: - rc_mq_tag: int = HandlesClassDef._lookup_renum_variant_in_class( - rc_mq_cls, func_name) - if rc_mq_tag >= 0: - return ExprCallCtor._translate_renum_construct( - pool, builder, mod, rc_mq_cls, func_name, - rc_mq_tag, cargs, can, trans) - - # 查找函数:优先从函数表按裸名精确匹配(同模块函数), - # 再从模块函数链表按后缀匹配(SHA1 前缀名)。 - # 注意:模块限定/属性调用(如 stdlib.free)不能做后缀匹配—— - # "free" 会误命中 viperio.Buf.free 等方法,导致普通 malloc 指针被 - # 当作 Buf 对象释放(Buf.free 读 self 字段/写 self.data), - # 传入句柄数组等指针时把句柄值当地址写入直接崩溃。 - # 后缀匹配仅用于裸名调用(cl.func 是 Name,如 _thread_alloc_free)。 - # stubs 在翻译后才注入,翻译时跨模块函数 found_func 通常为 None, - # 此时根据函数名推断 includes 库函数的返回类型(如 strchr 返回 i8*) - # 如果调用方未传 funcs_ptr/func_count(如 AnnAssign 路径),从 trans 获取 - actual_funcs: HandlesExprCall.FuncEntry | t.CPtr = funcs_ptr - actual_func_count: int = func_count - if actual_funcs is None and trans is not None: - actual_funcs = trans._funcs - actual_func_count = trans._func_count - found_func: llvmlite.Function | t.CPtr = None - if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: - # 裸名调用:允许精确 + 后缀匹配 - # 自定义装饰器 wrapper 重写:原函数名 → __decor_wrap_{name} - # (对齐 TPC DecoratorPass.run 的 _redirect_calls;wrapper 在函数 - # 翻译末尾生成,同 pass 内 main 调用点晚于被装饰函数定义,可达) - decor_wrap_nm: str = HandlesClassDef.lookup_decor_wrapper(func_name) - if decor_wrap_nm is not None: - found_func = self.find_func_in_module(mod, decor_wrap_nm) - else: - found_func = self.find_func_in_module(mod, func_name) - # 治本修复(对齐 Attribute 路径 L6579-6613):后缀匹配误命中类方法 - # (SHA1.Class.method,第 2 段是已注册结构体类)必须拒绝——否则方法体内 - # 与 from-import 模块函数同名的裸名调用(如 LLVMModuleCore.SSAValue 内 - # 的 SSAValue(self.Pool, ...))绑定到本类方法 define → 无限递归 - # (栈溢出 0xC0000005)。裸名调用应优先解析为模块级函数 - # (同模块函数表 / from_imports),方法调用需显式 obj.method。 - if found_func is not None: - bn_name: str = llvmlite.function_get_name(found_func) - if bn_name is not None: - bn_dots: int = 0 - bni2: t.CSizeT = 0 - while bn_name[bni2] != '\0': - if bn_name[bni2] == '.': - bn_dots += 1 - bni2 += 1 - if bn_dots >= 2: - # 提取第 2 段(SHA1.Class.method → Class;SHA1.submod.func → submod) - bn_seg2: str = pool.alloc(64) - if bn_seg2 is not None: - bn_seg2[0] = '\0' - bsi2: t.CSizeT = 0 - while bn_name[bsi2] != '\0' and bsi2 < 17: - bsi2 += 1 - bse2: t.CSizeT = bsi2 - while bn_name[bse2] != '\0' and bn_name[bse2] != '.': - bse2 += 1 - bsl2: t.CSizeT = bse2 - bsi2 - if bsl2 > 0 and bsl2 < 63: - string.strncpy(bn_seg2, bn_name + bsi2, bsl2) - bn_seg2[bsl2] = '\0' - # 第 2 段是已注册结构体类 → 是方法,拒绝(走模块 SHA1 路径) - if HandlesStruct.get_struct_type(bn_seg2) is not None: - found_func = None - else: - # 模块限定/属性调用:精确匹配优先,后缀匹配仅接受模块函数。 - # 后缀匹配命中的"方法"(SHA1.Class.method,Class 是已注册类)必须拒绝—— - # 短方法名(free/reset/close 等)会误命中其他模块的方法 - # (如 stdlib.free 命中 viperio.Buf.free,普通指针被当 Buf 释放崩溃; - # 且 atom.__atomic_test_and_set 若被误拒,返回类型从 i1 推断成 i32, - # 调用按 i32 读 i1 返回值读到垃圾高位,spinlock 恒非 0 卡死)。 - # 模块函数(SHA1.func)或子模块函数(SHA1.submod.func)的后缀匹配保留。 - found_func = self.find_func_in_module(mod, func_name) - if found_func is not None: - # 模块限定调用(mod.func,value 是已导入模块名):校验 found_func - # 的 SHA1 前缀必须等于该模块。否则 find_func_in_module 第 3 遍对 - # stub declare 的后缀匹配会误命中其他模块的同名函数(如 main 模块 - # 里 subprocess 的 declare 先注入,syslibtest_impl.run() 后缀匹配 - # 误命中 subprocess.run → call 到错误符号 → 参数错位解引用崩溃, - # SysLibTest 0xC0000005 根因)。误命中时拒绝(found_func=None), - # 落到下方跨模块模块限定解析用模块自身 SHA1 构造正确符号。 - xm_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if xm_at is not None and xm_at.value is not None and trans is not None \ - and trans._imported_modules is not None: - # 模块路径:单层 Name(syslibtest_impl.run)或嵌套 Attribute - # (os._win32.exists)。后者此前不校验 → os/__init__.vp 内部 - # 调 os._win32.exists 后缀匹配命中本模块同名 define → - # 无限递归栈溢出(SysLibTest 0xC00000FD 根因)。 - xm_mod_path: str = None - if xm_at.value.kind() == ast.ASTKind.Name: - xm_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(xm_at.value) - if xm_nm.id is not None: - xm_mod_path = xm_nm.id - elif xm_at.value.kind() == ast.ASTKind.Attribute: - xm_mod_path = HandlesExpr.attr_module_path_str( - pool, xm_at.value) - if xm_mod_path is not None: - if HandlesImports.is_module_imported( - trans._imported_modules, xm_mod_path) != 0: - mod_sha1_chk: str = self._lookup_module_sha1(xm_mod_path) - if mod_sha1_chk is not None: - ff_nm2: str = llvmlite.function_get_name(found_func) - if ff_nm2 is not None: - if string.strncmp(ff_nm2, mod_sha1_chk, 16) != 0: - found_func = None - ff_name: str = llvmlite.function_get_name(found_func) - if ff_name is not None: - ff_dots: int = 0 - ffi2: t.CSizeT = 0 - while ff_name[ffi2] != '\0': - if ff_name[ffi2] == '.': - ff_dots += 1 - ffi2 += 1 - if ff_dots >= 2: - # 提取第 2 段(SHA1.Class.method → Class;SHA1.submod.func → submod) - seg2: str = pool.alloc(64) - if seg2 is not None: - seg2[0] = '\0' - si: t.CSizeT = 0 - while ff_name[si] != '\0' and si < 17: - si += 1 - seg_start: t.CSizeT = si - seg_end: t.CSizeT = si - while ff_name[seg_end] != '\0' and ff_name[seg_end] != '.': - seg_end += 1 - seg_len: t.CSizeT = seg_end - seg_start - if seg_len > 0 and seg_len < 63: - string.strncpy(seg2, ff_name + seg_start, seg_len) - seg2[seg_len] = '\0' - # 第 2 段是已注册结构体类 → 是方法,拒绝(走模块 SHA1 路径) - if HandlesStruct.get_struct_type(seg2) is not None: - found_func = None - # C 库函数裸名调用支持:若模块中找不到且是已知 C 库函数,自动创建 declare - # 对应 TPC 的 _C_LIB_FUNCS 机制,支持 memset/memmove/memcmp/strcmp 等裸名调用 - if found_func is None and cl.func is not None and cl.func.kind() == ast.ASTKind.Name: - found_func = ExprCallBase._ensure_c_lib_declare(pool, mod, func_name) - # builtins 自动关联:C 库未命中时,自动关联 builtins 模块的内置函数(ord/chr 等)。 - # builtins 已由编译链预加入(StubMerger 预加入列表)。PhaseA 期 builtins 尚未编译, - # 因此按约定签名创建 {builtins_sha1}.{name} 的 mangled declare(链接时解析到 - # builtins.vp 的真实定义);签名与 builtins.vp 保持一致:ord(i8)->i32, chr(i32)->i8。 - if found_func is None: - bi_sha1: str = self._lookup_module_sha1("builtins") - if bi_sha1 is not None: - bi_ret: llvmlite.LLVMType | t.CPtr = None - bi_p1: llvmlite.LLVMType | t.CPtr = None - if string.strcmp(func_name, "ord") == 0: - bi_ret = llvmlite.Int32(pool) - bi_p1 = llvmlite.Int8(pool) - elif string.strcmp(func_name, "chr") == 0: - bi_ret = llvmlite.Int8(pool) - bi_p1 = llvmlite.Int32(pool) - if bi_ret is not None: - bi_sym: str = func_name - if self.is_cexport_func(bi_sha1, func_name) == 0: - bi_sym_len: t.CSizeT = string.strlen(bi_sha1) + string.strlen(func_name) + 2 - bi_sym_buf: str = pool.alloc(bi_sym_len) - if bi_sym_buf is not None: - viperlib.snprintf(bi_sym_buf, bi_sym_len, "%s.%s", bi_sha1, func_name) - bi_sym = bi_sym_buf - bi_decl: llvmlite.Function | t.CPtr = llvmlite.create_declare( - pool, mod, bi_sym, bi_ret) - if bi_decl is not None: - llvmlite.add_param(pool, bi_decl, bi_p1, "v") - found_func = bi_decl - # 使用访问器绕过 stub 类型限制 - found_ret_ty: llvmlite.LLVMType | t.CPtr = None - found_params: t.CPtr = None - if found_func is not None: - found_ret_ty = llvmlite.function_get_ret_ty(found_func) - found_params = llvmlite.function_get_params(found_func) - if found_ret_ty is not None: - call_ret_ty: llvmlite.LLVMType | t.CPtr = found_ret_ty - else: - # found_func=None(跨模块 stub 未注入):先从 vpi stub 返回注解 - # 缓存精确获取返回类型(含 tuple[T1,T2] → 匿名结构体,如 - # b2a_hqx -> tuple[str, t.CUnsignedShort] → {i8*, i16}), - # 未命中才回退 _infer_external_func_ret_ty 白名单推断。 - # 根因:_infer 白名单无 tuple 概念,未知函数默认 i32 会截断 - # 指针/i64;b2a_hqx 被推断为单值 i8*/i32 后调用侧返回值类型 - # 与定义侧 {i8*, i16} 不匹配 → HandlesAssign 的 tuple 解包 - # (依赖 rhs_val.Ty 是 Struct)静默跳过 → 目标变量从未赋值 → - # free 未初始化栈垃圾指针崩溃(HashLibTest hqx 段)。 - vpi_ret_ty: llvmlite.LLVMType | t.CPtr = None - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - at_ret: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if at_ret.value is not None and at_ret.value.kind() == ast.ASTKind.Name: - mod_ret_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_ret.value) - if mod_ret_nm.id is not None: - mod_ret_sha1: str = self._lookup_module_sha1(mod_ret_nm.id) - if mod_ret_sha1 is not None: - # 函数内懒 import:VpiReader imports HandlesExprCall, - # 顶层 import 会成环(与 _lookup_method_ret_ty_via_vpi 一致) - import lib.StubGen.VpiReader as VpiReader - VpiReader._ensure_vpi_ret_annot_loaded(mod_ret_sha1, self.TempDir) - ret_annot_fc: str = VpiReader._lookup_vpi_ret_annot( - mod_ret_sha1, None, func_name) - if ret_annot_fc is not None: - vpi_ret_ty = VpiReader._resolve_vpi_ret_annot_str( - pool, ret_annot_fc, - llvmlite.Int32(pool), - llvmlite.Ptr(pool, llvmlite.Int8(pool))) - if vpi_ret_ty is not None: - call_ret_ty = vpi_ret_ty - else: - call_ret_ty = ExprCallBase._infer_external_func_ret_ty(pool, func_name) - - # 如果模块中找不到函数,仅裸名调用(Name)才回退查局部变量(函数指针/ - # 闭包调用);模块属性调用(VLogger.fmt_buf())的目标是模块符号,绝不 - # 回退局部变量——跨模块任意同名可接受(CallGenLeafKit 局部 fmt_buf - # 曾劫持 VLogger.fmt_buf → 误走函数指针调用报 t.Callable 缺失), - # 仅 from-import 的裸名 yyy 与局部重名才可能冲突(该场景 func 是 Name)。 - if found_func is None: - fp_alloca: llvmlite.Value | t.CPtr = None - if cl.func is None or cl.func.kind() == ast.ASTKind.Name: - fp_alloca = HandlesVar.lookup_var(trans.SymTab, func_name) - if fp_alloca is not None: - # 闭包变量(嵌套函数提升,已注册到闭包名集合):提取 fn_ptr/env_ptr 间接调用 - if ExprCallCall.is_closure_name(func_name) != 0: - return ExprCallCall.translate_closure_call(pool, builder, mod, fp_alloca, - cargs, can, trans) - # 函数指针变量(t.Callable 注解 → i8** alloca):按实参构造签名间接调用 - if ExprCallCall._is_func_ptr_alloca(fp_alloca) != 0: - # 区分 t.Callable(真函数指针)vs t.CPtr(闭包指针): - # t.CPtr 变量(如 f: t.CPtr = make_counter())存的是闭包结构 - # {fn_ptr, env_ptr},调用必须提取 env 传参;若按函数指针直接 - # call,跳转到闭包结构数据地址崩溃(ClosureCallTest 运行时崩溃)。 - ve_fp: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, func_name) - is_cptr_annot_fp: int = 0 - if ve_fp is not None and ve_fp.AnnotClassName is not None: - if string.strstr(ve_fp.AnnotClassName, "CPtr") is not None: - is_cptr_annot_fp = 1 - if is_cptr_annot_fp == 0: - return ExprCallCall._translate_func_ptr_call(pool, builder, mod, fp_alloca, - func_name, cargs, can, trans) - return ExprCallCall.translate_closure_call(pool, builder, mod, fp_alloca, - cargs, can, trans) - # 其他 i8* 变量按闭包调用路径处理 - return ExprCallCall.translate_closure_call(pool, builder, mod, fp_alloca, - cargs, can, trans) - - # 翻译参数并链接 - # 有关键字参数且找到函数定义时,按参数名匹配 - if kw_count > 0 and found_func is not None and found_params is not None: - return ExprCallCtor._translate_call_with_kwargs( - pool, builder, mod, func_name, found_func, - cargs, can, keywords, kw_count, trans) - - head: llvmlite.Value | t.CPtr = None - tail: llvmlite.Value | t.CPtr = None - # memcpy 专用: 收集前三个 Value 的独立引用(避免共享 alloca 对象的 Next 被污染) - mc_dst2: llvmlite.Value | t.CPtr = None - mc_src2: llvmlite.Value | t.CPtr = None - mc_num2: llvmlite.Value | t.CPtr = None - for ai in range(can): - arg: ast.AST | t.CPtr = cargs.get(ai) - if arg is not None: - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg, None, 0, trans) - if arg_val is not None: - # 参数类型提升:当 found_func 为 None(stub 未注入)时, - # 根据外部函数签名推断期望类型,提升字面量(如 i32→i64) - # 避免 declare(i64) 与 call(i32) 类型不匹配 - if found_func is None and arg_val.Ty is not None: - # 数组实参按 C 语义衰减为元素指针(对齐 TPC - # _decay_array_to_ptr),与 _translate_method_call 一致。 - if HandlesExpr.is_ptr_type(arg_val.Ty) != 0: - arr_pointee_fc: llvmlite.LLVMType | t.CPtr = arg_val.Ty.Pointee - if arr_pointee_fc is not None: - match arr_pointee_fc: - case llvmlite.LLVMType.Array(arr_et_fc, _): - decayed_fc: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, arr_pointee_fc, arr_et_fc, arg_val, - llvmlite.const_int32(pool, 0)) - if decayed_fc is not None: - arg_val = decayed_fc - case _: - pass - ext_param_ty: llvmlite.LLVMType | t.CPtr = ExprCallBase._get_external_func_param_ty( - pool, func_name, ai) - if ext_param_ty is not None: - val_bits_ap: int = HandlesExpr.get_llvm_type_bits(arg_val.Ty) - tgt_bits_ap: int = HandlesExpr.get_llvm_type_bits(ext_param_ty) - if val_bits_ap != 0 and tgt_bits_ap != 0 and val_bits_ap != tgt_bits_ap: - if val_bits_ap == 1 and val_bits_ap < tgt_bits_ap: - arg_val = llvmlite.build_zext(builder, arg_val, ext_param_ty) - else: - arg_val = HandlesExpr.coerce_to_type(builder, arg_val, ext_param_ty, arg) - elif found_func is not None: - # found_func 存在:按形参类型 coerce(如 stdlib.malloc(size: t.CSizeT)) - # 修复: CDefine/i32 常量传给 i64 形参未提升,导致 call(i32) 与 define(i64) 不匹配 - fp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) - fpi: int = 0 - while fp is not None and fpi < ai: - fp = llvmlite.param_get_next(fp) - fpi += 1 - if fp is not None: - fpty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(fp) - if fpty is not None: - arg_val = HandlesExpr.coerce_to_type( - builder, arg_val, fpty, arg) - elif found_func.IsVarArg == 1: - # Win64 变参 8 字节槽位:<64 位整数按 i64 传(sext 符号扩展), - # f32 提升为 f64。若按原窄类型传,调用点只写 4 字节进 8 字节槽, - # 高 4 字节残留旧栈数据,va_arg(i64) 读到垃圾(如 DefineTest - # PAGE=%d 读到 0x400921FB00001000,高位是 PI 残留)。 - # 对齐 TPC FuncGen/Python-llvmlite 的 ABI 自动提升。 - ab_va: int = HandlesExpr.get_llvm_type_bits(arg_val.Ty) - af_va: int = HandlesExpr.get_llvm_float_bits(arg_val.Ty) - i64_va: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - if ab_va != 0 and ab_va < 64: - arg_val = llvmlite.build_sext(builder, arg_val, i64_va) - elif af_va == 32: - arg_val = llvmlite.build_fpext( - builder, arg_val, llvmlite.Double(pool)) - arg_val.Next = None - if head is None: - head = arg_val - else: - tail.Next = arg_val - tail = arg_val - # memcpy 专用: 保存前三个参数的独立引用 - if ai == 0: - mc_dst2 = arg_val - elif ai == 1: - mc_src2 = arg_val - elif ai == 2: - mc_num2 = arg_val - - # 默认参数填充:当实参数量 < 形参数量时,用默认值填充缺失参数 - # defaults 数组右对齐到 args:defaults[0] 对应 args[offset],offset = param_count - default_count - if can > 0 or (can == 0 and cargs is not None): - df_defaults: t.CVoid | t.CPtr = None - df_default_count: int = 0 - df_param_count: int = 0 - # 先从当前模块函数表查找 FuncEntry - if trans is not None and trans._funcs is not None: - df_entry: FuncEntry | t.CPtr = ExprCallTable.find_func_entry_in_table( - trans._funcs, trans._func_count, func_name) - if df_entry is not None: - df_defaults = df_entry.Defaults - df_default_count = df_entry.DefaultCount - df_param_count = df_entry.ParamCount - # 无条件查询全局默认参数表(跨模块/同模块都要用 stdlib 常量快照 - # 重建默认值:模块表 Defaults 指向 pool 内 AST,跨 1b reset 后悬空; - # 快照才是跨文件永久存活。同模块命中时 gd_entry 也必须已赋值, - # 否则下方 _build_const_from_snapshot 读到未初始化栈垃圾指针崩溃。 - # 与 _translate_method_call 的 mdf_gd 无条件查询(L2677)保持一致。 - gd_entry: FuncDefaultsEntry | t.CPtr = ExprCallTable.find_func_defaults(func_name) - if df_defaults is None and gd_entry is not None: - df_defaults = gd_entry.Defaults - df_default_count = gd_entry.DefaultCount - df_param_count = gd_entry.ParamCount - # 填充缺失参数 - if df_defaults is not None and df_default_count > 0 and can < df_param_count: - df_offset: int = df_param_count - df_default_count - df_di: int = 0 - while df_di < df_default_count: - df_param_idx: int = df_offset + df_di - if df_param_idx >= can: - # 优先用 stdlib 常量快照重建(gd_entry.Defaults 的 pool 内 AST 可能已被 reset 回收) - df_arg_val: llvmlite.Value | t.CPtr = None - if gd_entry is not None: - df_arg_val = ExprCallTable._build_const_from_snapshot( - pool, mod, gd_entry, df_di, trans, builder) - if df_arg_val is None: - df_defaults_list: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(df_defaults), t.CPtr)) - df_default_node: ast.AST | t.CPtr = df_defaults_list.get(df_di) - if df_default_node is not None: - df_arg_val = HandlesExpr.translate_value( - builder, pool, mod, df_default_node, None, 0, trans) - if df_arg_val is not None: - df_arg_val.Next = None - if head is None: - head = df_arg_val - else: - tail.Next = df_arg_val - tail = df_arg_val - df_di += 1 - - # 使用模块中的实际函数名(可能带 SHA1 前缀,如 "83210a72e829a086.atoi") - # t.CExtern/t.State/t.CExport 函数不加 SHA1 前缀,使用裸名 - # declare 和 define 统一用 found_func.Name: - # - 普通函数的 declare/define 都带 SHA1 前缀(forward_declare_functions 和 stub 注入都用 mangled_name) - # - t.CExtern/t.State/t.CExport 函数的 declare/define 都用裸名 - # 旧逻辑(IsDeclared==1 时用 func_name 裸名)是错误的:stub 注入的 declare Name 已带 SHA1 前缀, - # 用裸名会导致 call @_PathToModuleName 而 define 是 @"sha1._PathToModuleName",链接报 undefined reference - call_name: str = func_name - # 原始函数名(别名导入时记录,如 from X import parse as json_parse → orig_func_name="parse") - # 用于在别名处理后重新推断返回类型,避免 _infer_external_func_ret_ty 用别名匹配失败 - orig_func_name: str = None - if found_func is not None: - found_name: str = llvmlite.function_get_name(found_func) - if found_name is not None: - call_name = found_name - else: - # 跨模块函数调用:found_func 为 None 时,检查是否是模块限定调用 - # 如 string.strchr(...) → @{sha1_of_string}.strchr - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - xmod_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if xmod_at.value is not None and (xmod_at.value.kind() == ast.ASTKind.Name - or xmod_at.value.kind() == ast.ASTKind.Attribute): - # 模块路径:单层 Name(string.strchr)或嵌套 Attribute - # (os._win32.exists)。嵌套路径此前不支持 → os/__init__.vp - # 内部调 os._win32.exists 只能被 find_func_in_module 后缀匹配 - # 命中本模块同名 define(无限递归),或找不到模块路径而走 - # 错误 fallback;此处用完整模块路径解析正确 SHA1(与校验段 - # L7344 对齐,SysLibTest 0xC00000FD 根因)。 - xmod_path: str = None - if xmod_at.value.kind() == ast.ASTKind.Name: - xmod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(xmod_at.value) - if xmod_nm.id is not None: - xmod_path = xmod_nm.id - else: - xmod_path = HandlesExpr.attr_module_path_str(pool, xmod_at.value) - if xmod_path is not None: - mod_sha1: str = self._lookup_module_sha1(xmod_path) - if mod_sha1 is not None: - # fast-fail: 模块限定调用要求模块已被当前文件 import。 - # 全局 SHA1 存储包含所有被扫描的 includes,未导入的模块 - # (如 this.this() 但 import this 被注释)也会命中存储, - # 静默生成 @{sha1}.func 调用而非报错——违反"找不到 fast-fail"原则。 - is_xmod_imported: int = 1 - if trans is not None and trans._imported_modules is not None: - is_xmod_imported = HandlesImports.is_module_imported( - trans._imported_modules, xmod_path) - if is_xmod_imported == 0: - err_ni: str = pool.alloc(256) - if err_ni is not None: - viperlib.snprintf(err_ni, 256, - "跨模块调用 '%s.%s':模块 '%s' 未导入(请先 import %s)", - xmod_path, func_name, xmod_path, xmod_path) - HandlesType.fatal_error(xmod_at, err_ni) - HandlesType.fatal_error(xmod_at, "跨模块调用:模块未导入") - # 检查是否是 re-export 函数(如 ast._lexer_init 实际定义在 ast.lexer) - reexport_src: str = HandlesImports.lookup_reexport(mod_sha1, func_name) - if reexport_src is None: - # re-export 表未命中(includes 模块 stub/text 已存在时 - # 不被按需全量翻译,表只在 declare_only=0 时注册,可能为空): - # 按需解析该模块 .vpi 的 from-import 定位定义模块 - reexport_src = self._lookup_reexport_from_vpi(pool, mod_sha1, func_name) - if reexport_src is not None: - reexport_sha1: str = self._lookup_module_sha1(reexport_src) - if reexport_sha1 is not None: - mod_sha1 = reexport_sha1 - # CExport 函数定义用裸名(@strlen),跨模块调用需用裸名而非 @{sha1}.func - if self.is_cexport_func(mod_sha1, func_name) != 0: - call_name = func_name - elif self._is_state_func_from_vpi(pool, mod_sha1, func_name) != 0: - # t.State 标记的外部 C 函数(如 CPython PyList_Size): - # 定义端用裸名 @PyList_Size(链接外部库),跨模块调用 - # 必须用裸名——带 sha1 前缀 → ld.lld undefined symbol - call_name = func_name - else: - mangled_len: t.CSizeT = string.strlen(mod_sha1) + string.strlen(func_name) + 2 - mangled: str = pool.alloc(mangled_len) - if mangled is not None: - viperlib.snprintf(mangled, mangled_len, "%s.%s", mod_sha1, func_name) - call_name = mangled - else: - # t 和 c 是内部库,豁免 SHA1 查找:使用裸名调用 - if string.strcmp(xmod_path, "t") == 0 or string.strcmp(xmod_path, "c") == 0: - call_name = func_name - else: - # Bug 修复: 先检查是否是已导入的模块名(如 BuildPipeline.run_pipeline) - # 如果是已导入模块但 SHA1 未注册,说明该模块未被编译(如 Phase2 未扫描到), - # 应该立即报错,而不是错误地走 from_imports 查找(会被 star import 回退误导) - is_imported_mod: int = 0 - if trans is not None and trans._imported_modules is not None: - is_imported_mod = HandlesImports.is_module_imported( - trans._imported_modules, xmod_path) - if is_imported_mod != 0: - # 别名导入(import X as Y):Y 在 _imported_modules 中, - # 但 _lookup_module_sha1("Y") 精确匹配失败(mod_arr 只存文件名)。 - # 先尝试 from_imports 查找别名→完整模块名→后缀匹配 SHA1。 - # allow_star_fallback=0 避免被 star import 回退误导。 - alias_sha1: str = None - if trans is not None and trans._from_imports is not None: - alias_sha1 = self._lookup_mod_sha1(pool, trans._from_imports, xmod_path, 0) - if alias_sha1 is not None: - if self.is_cexport_func(alias_sha1, func_name) != 0: - call_name = func_name - elif self._is_state_func_from_vpi(pool, alias_sha1, func_name) != 0: - # t.State 外部 C 函数:裸名(同主路径 L7918) - call_name = func_name - else: - AliasMangledLen: t.CSizeT = string.strlen(alias_sha1) + string.strlen(func_name) + 2 - alias_mangled: str = pool.alloc(AliasMangledLen) - if alias_mangled is not None: - viperlib.snprintf(alias_mangled, AliasMangledLen, "%s.%s", alias_sha1, func_name) - call_name = alias_mangled - else: - # 已导入模块但 SHA1 未注册:该模块未被编译,立即报错 - err_msg_imp: str = pool.alloc(256) - if err_msg_imp is not None: - viperlib.snprintf(err_msg_imp, 256, "模块 '%s' 已导入但 SHA1 未注册(该模块未被编译)", xmod_path) - HandlesType.fatal_error(xmod_at, err_msg_imp) - HandlesType.fatal_error(xmod_at, "已导入模块 SHA1 未注册") - else: - # 检查是否是通过 from import 导入的名称(如 from .__types import LLVMType) - # LLVMType.Ptr(ty) 中 LLVMType 是类名不是模块名, - # 但 Ptr 是 __types 模块的模块级函数 - # 禁用 star import 回退:xmod_path 是明确名称,不应回退到 star import 模块 - from_sha1: str = None - if trans is not None and trans._from_imports is not None: - from_sha1 = self._lookup_mod_sha1(pool, trans._from_imports, xmod_path, 0) - if from_sha1 is not None: - # CExport 函数定义用裸名,跨模块调用需用裸名 - if self.is_cexport_func(from_sha1, func_name) != 0: - call_name = func_name - else: - fmangled_len: t.CSizeT = string.strlen(from_sha1) + string.strlen(func_name) + 2 - fmangled: str = pool.alloc(fmangled_len) - if fmangled is not None: - viperlib.snprintf(fmangled, fmangled_len, "%s.%s", from_sha1, func_name) - call_name = fmangled - else: - err_msg2: str = pool.alloc(256) - if err_msg2 is not None: - viperlib.snprintf(err_msg2, 256, "跨模块调用 '%s.%s' 找不到模块 SHA1", xmod_path, func_name) - HandlesType.fatal_error(xmod_at, err_msg2) - HandlesType.fatal_error(xmod_at, "跨模块调用找不到模块 SHA1") - else: - # 裸名调用(非 Attribute):检查 from_imports - # 治本修复:函数调用禁用 star import 回退(allow_star_fallback=0)。 - # star import(from stdint import *)本意是导入类型/常量(如 BYTEPTR),而非函数; - # 函数应显式 from import。漏导函数若走 star 回退会被错归到 star 模块,生成错误 SHA1 符号 - # (如 block_insert_text_before_terminator 漏导后被错归 stdint,生成 - # f5522571bcce7bcb.block_insert... 而非 874bac141c97bae9.block_insert...)。 - # 禁用回退后,漏导函数编译期即报"未定义且未导入"(fast-fail),优于链接期 undefined reference。 - if trans is not None and trans._from_imports is not None: - bare_sha1: str = self._lookup_mod_sha1(pool, trans._from_imports, func_name, 0) - if bare_sha1 is not None: - # 别名处理: from X import Y as Z → 调用 Z 时需用 Y 作为源模块函数名 - # 例如 from json.__parser import parse as json_parse → 修饰为 SHA1.parse 而非 SHA1.json_parse - bare_orig: str = HandlesImports.lookup_from_import_original( - trans._from_imports, func_name) - bare_func_name: str = func_name - if bare_orig is not None: - # bare_orig 指向 from_imports 内部缓冲区,未 null 终止 - # 需复制到独立缓冲区(截断于空格或 null) - bo_len: t.CSizeT = 0 - while bare_orig[bo_len] != ' ' and bare_orig[bo_len] != '\0': - bo_len += 1 - bo_buf: str = pool.alloc(bo_len + 1) - if bo_buf is not None: - for bo_i in range(bo_len): - bo_buf[bo_i] = bare_orig[bo_i] - bo_buf[bo_len] = '\0' - bare_func_name = bo_buf - # 记录原始函数名,供后续重新推断返回类型 - # 例如 from json.__parser import parse as json_parse - # func_name="json_parse", bare_func_name="parse" - # _infer_external_func_ret_ty 用 "parse" 能正确匹配,用 "json_parse" 则返回默认 i32 - orig_func_name = bare_func_name - # re-export 解析(对齐模块限定路径 L6598): - # 裸名 from import 的函数可能实际定义在子模块(re-export)。 - # 例:from ast import dump → dump 定义在 ast.base(sha1=71b2), - # ast/__init__(sha1=876e)只是 re-export。若沿用包 sha1 构造 - # call_name="876e.dump",text.ll/vpi 返回类型解析均未命中, - # fail-fast 报"返回类型无法精确获取";需重定向到定义模块 SHA1。 - reexport_src2: str = HandlesImports.lookup_reexport(bare_sha1, bare_func_name) - if reexport_src2 is None: - # re-export 表未命中:按需解析该模块 .vpi 的 from-import - reexport_src2 = self._lookup_reexport_from_vpi(pool, bare_sha1, bare_func_name) - if reexport_src2 is not None: - reexport_sha1_2: str = self._lookup_module_sha1(reexport_src2) - if reexport_sha1_2 is not None: - bare_sha1 = reexport_sha1_2 - if self.is_cexport_func(bare_sha1, bare_func_name) != 0: - call_name = bare_func_name - else: - bare_mangled_len: t.CSizeT = string.strlen(bare_sha1) + string.strlen(bare_func_name) + 2 - bare_mangled: str = pool.alloc(bare_mangled_len) - if bare_mangled is not None: - viperlib.snprintf(bare_mangled, bare_mangled_len, "%s.%s", bare_sha1, bare_func_name) - call_name = bare_mangled - else: - err_msg3: str = pool.alloc(256) - if err_msg3 is not None: - viperlib.snprintf(err_msg3, 256, "裸名调用 '%s' 未定义且未导入", func_name) - HandlesType.fatal_error(node, err_msg3) - HandlesType.fatal_error(node, "裸名调用未定义且未导入") - else: - err_msg4: str = pool.alloc(256) - if err_msg4 is not None: - viperlib.snprintf(err_msg4, 256, "裸名调用 '%s' 未定义且未导入", func_name) - HandlesType.fatal_error(node, err_msg4) - HandlesType.fatal_error(node, "裸名调用未定义且未导入") - - # 直接调用 - # memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失) - if string.strcmp(func_name, "memcpy") == 0 and can >= 3: - return ExprCallBase._emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst2, mc_src2, mc_num2) - # 别名导入重新推断返回类型: - # from X import parse as json_parse → func_name="json_parse" 时 _infer_external_func_ret_ty 返回默认 i32 - # 用 orig_func_name="parse" 重新推断,能正确匹配返回 i8*(JsonValue*) - # 避免指针被截断为 i32 后 inttoptr 丢失高 32 位导致崩溃 - if orig_func_name is not None and orig_func_name != func_name: - re_inferred_ty: llvmlite.LLVMType | t.CPtr = ExprCallBase._infer_external_func_ret_ty(pool, orig_func_name) - if re_inferred_ty is not None: - call_ret_ty = re_inferred_ty - # ============================================================ - # 跨模块 Viper 函数返回类型精确解析(对齐方法路径,fail-fast) - # 根因:_infer_external_func_ret_ty 白名单未覆盖返回指针的模块函数 - # (new_lexer→Lexer* / tokenize→Token* / parse_tokens→AST*),兜底 i32 - # 导致 64 位指针被截断高 32 位 → inttoptr 无效指针 → 解引用崩溃 - # (AstTest 的 _lexer_init 崩溃链)。declare 也可能是错误 i32(_ensure_method_declare - # 曾用兜底类型创建),因此不信任 found_func 的 declare 返回类型。 - # 权威来源:text.ll define;次选:vpi stub 返回注解;均未命中立即终止。 - # 仅对 mangled("{16位hex}.func")调用生效;C 库/Win32 裸名走原白名单。 - # Phase 1a(declare_only)期间依赖 text.ll 未生成,保持原白名单行为不 fail-fast。 - # ============================================================ - if ExprCallHandle._is_sha1_mangled_call(call_name) != 0: - if trans is None or trans._declare_only == 0: - cf_dot: str = string.strchr(call_name, '.') - cf_last: str = string.strrchr(call_name, '.') - if cf_dot is not None and cf_last is not None: - cf_sha1: str = stdlib.malloc(17) - cf_bare_len: t.CSizeT = string.strlen(call_name) - \ - (t.CSizeT(t.CUInt64T(cf_last) - t.CUInt64T(call_name))) - 1 - cf_bare: str = stdlib.malloc(cf_bare_len + 1) - if cf_sha1 is not None and cf_bare is not None: - string.strncpy(cf_sha1, call_name, 16) - cf_sha1[16] = '\0' - string.strcpy(cf_bare, cf_last + 1) - # 本模块自身函数(泛型特化等):从当前 IR 已声明的函数 - # 取返回类型;不走跨模块 text.ll 查找——自己的 text.ll - # 在 Phase A 翻译中尚未生成,直接查会误报"依赖未生成" - # 并保持默认类型(GenericTest 泛型 add/combine 等警告 - # 根因)。未命中(特化尚未声明)保持默认推断。 - is_local_mod: int = 0 - if trans is not None and trans.ModuleSha1 is not None: - if string.strncmp(cf_sha1, trans.ModuleSha1, 16) == 0: - is_local_mod = 1 - if is_local_mod != 0: - local_fn: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, call_name) - if local_fn is not None and local_fn.RetTy is not None: - call_ret_ty = local_fn.RetTy - else: - cf_ret: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL( - pool, cf_sha1, None, cf_bare, 1) - if cf_ret is not None: - call_ret_ty = cf_ret - else: - cf_vpi: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi( - pool, cf_sha1, None, cf_bare) - if cf_vpi is not None: - call_ret_ty = cf_vpi - else: - # 区分两种失败场景: - # 1. 依赖模块 text.ll 存在但函数未命中 → 真错误,fail-fast - # 2. 依赖模块 text.ll 不存在(模块尚未翻译)→ Phase A 按 - # 文件顺序翻译,main.vp 先于其 import 的 mbuddytest.vp - # (同项目多源文件)。此时标记 trans._deps_pending=1, - # 保持白名单类型继续,Phase A 多遍循环下遍重译—— - # 届时依赖已生成 text.ll,可精确解析(治本:依赖先翻译)。 - if self._dep_text_ll_exists(pool, cf_sha1) != 0: - cf_err: str = VLogger.fmt_buf() - if cf_err is not None: - viperlib.snprintf( - cf_err, 1024, - "跨模块函数 '%s' 返回类型无法精确获取(text.ll/vpi 均未命中)," - "默认 i32 会截断指针/i64,请检查依赖模块是否已编译/注册", call_name) - VLogger.error(cf_err, "HandlesExprCall") - HandlesType.fatal_error( - node, - f"跨模块函数返回类型无法精确获取(text.ll/vpi 均未命中),默认 i32 会截断指针: {call_name}", - "TypeError") - else: - if trans is not None: - trans._deps_pending = 1 - cf_dbg: str = VLogger.fmt_buf() - if cf_dbg is not None: - viperlib.snprintf( - cf_dbg, 1024, - "跨模块函数 '%s' 依赖模块 text.ll 尚未生成(Phase A 顺序)," - "标记重试,本遍保持默认类型", call_name) - if VLogger.nowarn_register() == 0: - VLogger.warning(cf_dbg, "HandlesExprCall") - stdlib.free(cf_sha1) - stdlib.free(cf_bare) - # 跨模块调用:创建 declare 声明,避免 llc 报 undefined value - self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, can) - # 检查被调用函数是否为变长函数(*args),若是则对变长参数进行 C ABI 提升 - # (cargs 为本函数参数 AST 链表,self_offset=0 普通函数调用) - is_variadic_call: int = ExprCallCall._check_and_promote_variadic_call( - pool, builder, mod, call_name, head, can, cargs, 0, trans) - # try-except:被调函数带 EH 输出参数时,追加输出实参 + 调用后检测异常 - return ExprCallHandle._emit_eh_guarded_call( - builder, pool, mod, trans, found_func, call_name, head, can, - call_ret_ty, is_variadic_call) - - - - - - - - - - - - - +import lib.core.Gen.GenTypes as GenTypes +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import sys +import viperlib +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.CallGenBase as CallGenBase +import lib.core.Handles.ExprCallTable as ExprCallTable + + +# ============================================================ +# CallGenMixin - 调用分派 Mixin(拆分后顶层,阶段 A:底层已拆至 +# CallGenBase/CallGenCBuiltin/CallGenLeafKit) +# +# 500~1500 行/文件架构重构阶段 A:底层自包含组(模块查找/返回类型解析/ +# c.*/asm/llvmir/EH/isinstance/闭包/print/函数表)已拆出,本文件保留 +# 调用分派中枢(translate_call 等)。继承链 CallGenMixin → LeafKit → +# CBuiltin → Base,@t.NoVTable 静态绑定沿 MRO 解析 self 调用。 +# +# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 +# ============================================================ + + +# ============================================================ +# 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug) +# ============================================================ +GLOBAL_FUNC_MAX: t.CDefine = 8192 +GLOBAL_DEFAULTS_MAX: t.CDefine = 4096 +_CEXPORT_MAX: t.CDefine = 256 +ASM_MAX_OPERANDS: t.CDefine = 16 +ASM_TEXT_BUF_SIZE: t.CDefine = 2048 +ASM_CONST_BUF_SIZE: t.CDefine = 512 +ASM_ARGS_BUF_SIZE: t.CDefine = 512 +ASM_LINE_BUF_SIZE: t.CDefine = 4096 +LLVMIR_MAX_OPS: t.CDefine = 16 +LLVMIR_TEMPLATE_BUF: t.CDefine = 512 +# 闭包名表大小(原 HandlesExprCall 模块级常量) +MAX_CLOSURE_NAMES: t.CDefine = 128 +# 函数指针签名表大小(原 HandlesExprCall 模块级常量) +MAX_FUNC_PTR_SIGS: t.CDefine = 64 +# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32) +ISINSTANCE_CLASS_MAX: t.CDefine = 64 + + +# ============================================================ +# CallGenMixin - 调用分派中枢(顶层,继承 LeafKit) +# ============================================================ +@t.NoVTable +class CallGenMixin(CallGenBase.CallGenBase): + """调用分派 Mixin(拆分后顶层,直接继承 CallGenBase——TPV self 调用仅支持 1 级父类)""" + + # ============================================================ + # 翻译函数调用 Call(func, args) — 模块级版本 + # ============================================================ + def translate_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译函数调用,返回 call 结果 Value""" + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + if cl is None: + return None + + func_name: str = self.Gen.ExprGenBase.get_func_name(cl.func) + + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + can: t.CSizeT = 0 + if cargs is not None: + can = len(cargs) + + # super()/ctraits 检测:void 方法(如 __init__)命中后 build_call 返回 + # None 属预期(void call 无 SSA 值),必须用 hit_box 区分"命中已处理" + # 与"未命中",否则 None 被误判继续主路径 → 内层 Call(super) 当裸名 + # 调用报"super 未定义且未导入"(SuperTest 根因)。 + h1_hit: t.CPtr = stdlib.malloc(4) + if h1_hit is not None: + h1_hit[0] = 0 + _tc_h1_super_ctraits_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._tc_h1_super_ctraits( + pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can, h1_hit) + h1_hit_val: int = 0 + if h1_hit is not None: + h1_hit_val = h1_hit[0] + stdlib.free(h1_hit) + if _tc_h1_super_ctraits_res is not None: + return _tc_h1_super_ctraits_res + if h1_hit_val != 0: + # 命中 super()/ctraits 但无返回值(void 方法/宏调用):视为已处理 + return None + + # ---- func_name is None:泛型实例化 + 类型转换 ---- + if func_name is None: + # 检查是否是 list[int](pool) 形式的泛型实例化调用 + # Subscript 节点作为 Call func: 泛型类构造函数 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Subscript and trans is not None: + sub_node: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(cl.func) + if sub_node.value is not None and sub_node.value.kind() == ast.ASTKind.Name: + gen_nm_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_node.value) + gen_class_name: str = gen_nm_node.id + # 检查是否是泛型类模板 + template_cd: ast.ClassDef | t.CPtr = self.Gen.ClassGenGeneric._find_generic_template(gen_class_name) + if template_cd is not None: + # 提取类型实参 + gen_type_args: list[str] | t.CPtr = self.Gen.CallGenCtor._extract_type_args_from_slice(pool, sub_node.slice) + if gen_type_args is not None and len(gen_type_args) > 0: + # 特化泛型类,返回特化类名 + spec_name: str = self.Gen.ClassGenGeneric._specialize_generic_class( + trans, gen_class_name, gen_type_args) + if spec_name is not None: + # 泛型类构造调用: list[str](pool, 8) → __new__ + __before_init__ + __init__ + # 不能直接用 spec_name 作为 func_name(会走裸名调用路径, + # 被 star import 回退误导用错误的 SHA1,且缺少 __new__ 方法名后缀) + return self.Gen.CallGenCtor._translate_generic_ctor_call( + pool, builder, mod, spec_name, cl, trans) + else: + # 泛型类模板未找到:可能是泛型函数手动传类型参数调用 xxx[T](x) + # (对应 TPC _HandleGenericCallExplicitLlvm;TPV 无泛型函数特化, + # 泛型函数按普通函数编译,类型参数 [T] 仅在函数定义处消费)。 + # 检查当前模块是否已定义同名函数(def double[T] 编译后即普通函数 + # double),若是则丢弃 [t.CInt] 显式类型参数,退回普通函数调用。 + if self.find_func_in_module(mod, gen_class_name) is not None: + func_name = gen_class_name + else: + # 泛型类模板未找到:可能未 import 定义模块 + gt_err: str = pool.alloc(256) + if gt_err is not None: + viperlib.snprintf(gt_err, 256, "泛型类 '%s' 未找到模板,可能未 import 定义模块", gen_class_name) + self.Gen.TypeGenErr.fatal_error(gen_nm_node, gt_err) + self.Gen.TypeGenErr.fatal_error(gen_nm_node, "泛型类模板未找到") + if func_name is None: + # 检查是否是 (A | t.CPtr)(value) 形式的类型转换 + # BinOp 节点作为 Call func: 联合类型注解用作类型转换 + if cl.func is not None and cl.func.kind() == ast.ASTKind.BinOp and trans is not None: + binop_ty: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, cl.func, trans._imported_modules, trans._from_imports, trans) + if binop_ty is not None: + binop_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if binop_args is not None and len(binop_args) == 1: + binop_arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, binop_args.get(0), funcs_ptr, func_count, trans) + if binop_arg_val is not None: + return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, binop_arg_val, binop_ty) + return None + + # c.Asm/c.LLVMIR 等特殊调用:void(无输出)时 translate_c_asm/llvmir + # 返回 None 表示"已处理无返回值",需用 hit_box 区分"未命中", + # 否则会误判未命中继续走外部函数路径(外部函数返回类型未登记 Asm + + # t.ASM_DESCR 被当 CDefine 常量赋值) + h2_hit: t.CPtr = stdlib.malloc(4) + if h2_hit is not None: + h2_hit[0] = 0 + _tc_h2_c_special_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._tc_h2_c_special( + pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can, h2_hit) + h2_hit_val: int = 0 + if h2_hit is not None: + h2_hit_val = h2_hit[0] + stdlib.free(h2_hit) + if _tc_h2_c_special_res is not None: + return _tc_h2_c_special_res + if h2_hit_val != 0: + # 命中 c.Asm/c.LLVMIR 但无返回值(void):视为已处理 + return None + + _tc_h3_stdarg_cast_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._tc_h3_stdarg_cast( + pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) + if _tc_h3_stdarg_cast_res is not None: + return _tc_h3_stdarg_cast_res + + _tc_h4_type_casts_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._tc_h4_type_casts( + pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) + if _tc_h4_type_casts_res is not None: + return _tc_h4_type_casts_res + + _tc_h5_sizeof_len_isinst_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._tc_h5_sizeof_len_isinst( + pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) + if _tc_h5_sizeof_len_isinst_res is not None: + return _tc_h5_sizeof_len_isinst_res + + # c.Asm/c.LLVMIR 等方法调用分派:方法调用识别成功但返回 None + # (如编译器生成方法 __before_init__/__init__ 恒返回 void,_translate_ + # method_call 或 _emit_eh_guarded_call 处理后可能返回 None)时,须用 + # hit_box 区分"已识别为方法调用"与"未命中",否则 translate_call 误判 + # 未命中继续走跨模块函数路径,把对象名当模块名查 SHA1 → + # "跨模块调用 'buf.__before_init__' 找不到模块 SHA1"(memhub.alloc_buf 根因)。 + h6_hit: t.CPtr = stdlib.malloc(4) + if h6_hit is not None: + h6_hit[0] = 0 + _tc_h6_method_dispatch_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._tc_h6_method_dispatch( + pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can, h6_hit) + h6_hit_val: int = 0 + if h6_hit is not None: + h6_hit_val = h6_hit[0] + stdlib.free(h6_hit) + if _tc_h6_method_dispatch_res is not None: + return _tc_h6_method_dispatch_res + if h6_hit_val != 0: + # 命中方法调用路径但无返回值(编译器生成方法等 void 语义):视为已处理 + return None + + # 获取关键字参数 + keywords: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords + kw_count: t.CSizeT = 0 + if keywords is not None: + kw_count = len(keywords) + + # 检查是否是结构体构造函数: Point() / Point(10, 20) / Point(x=10, y=20) + # 命名空间隔离:严格模式下检查结构体可见性 + # - 裸名 Class(): 需要 from X import Class 或本地定义 + # - 模块限定 Module.Class(): 需要 import Module + # 用 find_struct_by_module 规避跨模块同名 find_struct 找错 + struct_ty: llvmlite.LLVMType | t.CPtr = None + gen_ctor_entry: GenTypes.StructEntry | t.CPtr = None + vis: int = self.Gen.StructGen.is_struct_visible(func_name) + if vis != 0: + if trans is not None: + gen_ctor_entry = self.Gen.StructGen.find_struct_by_module(func_name, trans.ModuleSha1) + if gen_ctor_entry is None: + gen_ctor_entry = self.Gen.StructGen.find_struct(func_name) + if gen_ctor_entry is not None: + struct_ty = gen_ctor_entry.Ty + elif trans is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + at_qc: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if at_qc.value is not None and at_qc.value.kind() == ast.ASTKind.Name: + mod_nm_qc: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_qc.value) + imp_ok: int = self.Gen.ImportsGen.is_module_imported(trans._imported_modules, mod_nm_qc.id) + if imp_ok != 0: + if trans is not None: + gen_ctor_entry = self.Gen.StructGen.find_struct_by_module(func_name, trans.ModuleSha1) + if gen_ctor_entry is None: + gen_ctor_entry = self.Gen.StructGen.find_struct(func_name) + if gen_ctor_entry is not None: + struct_ty = gen_ctor_entry.Ty + elif at_qc.value is not None and at_qc.value.kind() == ast.ASTKind.Attribute: + # 多层模块路径类构造: w32.fileio.File(...)(value 是嵌套 Attribute)。 + # 仅两层(fileio.File)支持时,三层会被跳过 → 退化走跨模块普通函数 + # 调用生成 @File 裸名 → 链接 undefined symbol: File(SysLibTest 根因)。 + # 模块路径经 attr_module_path_str 递归拼接("w32.fileio"), + # import 检查用完整路径(import w32.fileio 注册 "w32.fileio"), + # 结构体查找用该模块自身 SHA1 精确命中(find_struct_by_module)。 + # 注:经 HandlesExpr 委托调用(跨 mixin 不能 self. 直接调, + # @t.NoVTable 静态绑定会 mangle 成 CallGenMixin. 前缀 → undefined reference)。 + mod_path_qc: str = self.Gen.ExprGenAttr._attr_module_path_str(pool, at_qc.value) + if mod_path_qc is not None: + imp_ok_qc: int = self.Gen.ImportsGen.is_module_imported( + trans._imported_modules, mod_path_qc) + if imp_ok_qc != 0: + mod_sha1_qc: str = self._lookup_module_sha1(mod_path_qc) + if mod_sha1_qc is not None: + gen_ctor_entry = self.Gen.StructGen.find_struct_by_module( + func_name, mod_sha1_qc) + if gen_ctor_entry is None: + gen_ctor_entry = self.Gen.StructGen.find_struct(func_name) + if gen_ctor_entry is not None: + struct_ty = gen_ctor_entry.Ty + # 别名导入的类构造: from X import Class as Alias → Alias(args) + # 可见性列表按别名注册(HandleImportFromNames 用 local_name=asname),但结构体 + # 按原名注册(如 Keyword as KwNode → 可见 "KwNode"、注册名 "Keyword")。 + # 直接按别名 find_struct 查不到 → 误走普通函数路径生成 @sha1.Keyword 调用 + # (该函数不存在)→ 链接期 undefined reference。此处解析别名→原名再查结构体。 + if gen_ctor_entry is None and trans is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Name: + if trans._from_imports is not None: + ctor_sha1: str = self._lookup_mod_sha1(pool, trans._from_imports, func_name, 0) + if ctor_sha1 is not None: + ctor_orig: str = self.Gen.ImportsGen.lookup_from_import_original( + trans._from_imports, func_name) + if ctor_orig is not None: + # 复制到独立 null 终止缓冲区(from_imports 内部缓冲未终止) + co_len: t.CSizeT = 0 + while ctor_orig[co_len] != ' ' and ctor_orig[co_len] != '\0': + co_len += 1 + co_buf: str = pool.alloc(co_len + 1) + if co_buf is not None: + for co_i in range(co_len): + co_buf[co_i] = ctor_orig[co_i] + co_buf[co_len] = '\0' + # 原名结构体查找(可见性已由别名保证,原名无需再查) + gen_ctor_entry = self.Gen.StructGen.find_struct_by_module(co_buf, ctor_sha1) + if gen_ctor_entry is None: + gen_ctor_entry = self.Gen.StructGen.find_struct(co_buf) + if gen_ctor_entry is not None: + struct_ty = gen_ctor_entry.Ty + func_name = co_buf + if struct_ty is not None: + if can == 0 and kw_count == 0: + # OOP 结构体:即使无参数也调用 __before_init__ + # 用 gen_ctor_entry 规避跨模块同名 find_struct 找错 + ctor_is_oop: int = 0 + if gen_ctor_entry is not None: + ctor_is_oop = gen_ctor_entry.IsOOP + if ctor_is_oop != 0: + return self.Gen.CallGenCtor._translate_struct_ctor( + pool, builder, mod, struct_ty, func_name, cargs, 0, trans) + # @t.NoVTable 类(无方法、类语义/指针对象):无参构造也应分配内存 + # 返回指针。否则按值结构体返回 ConstZero(struct_ty),LHS 联合注解 + # (如 Plain|CPtr)存 0 指针 → p.v 解引用 NULL 段错误 + # (TpvIsinstanceTest Plain 场景崩溃根因)。 + ctor_is_novt: int = 0 + if gen_ctor_entry is not None: + ctor_is_novt = gen_ctor_entry.IsNoVTable + if ctor_is_novt != 0: + return self.Gen.CallGenCtor._translate_struct_ctor( + pool, builder, mod, struct_ty, func_name, cargs, 0, trans) + # 普通结构体:检查是否有默认值(用 entry 直接访问) + gen_has_defaults: int = 0 + if gen_ctor_entry is not None: + for gdi in range(gen_ctor_entry.FieldCount): + gdf: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry( + gen_ctor_entry, gdi) + if gdf is not None and gdf.DefaultVal is not None: + gen_has_defaults = 1 + break + else: + gen_has_defaults = self.Gen.StructGen.struct_has_defaults(func_name) + if gen_has_defaults == 1: + # 有默认值:走构造函数路径应用默认值 + return self.Gen.CallGenCtor._translate_struct_ctor( + pool, builder, mod, struct_ty, func_name, cargs, 0, trans) + # 无默认值:返回 zeroinitializer + ret: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) + return ret + if kw_count > 0: + # 有关键字参数:按字段名赋值 + return self.Gen.CallGenCtor._translate_struct_ctor_kw( + pool, builder, mod, struct_ty, func_name, cargs, can, + keywords, kw_count, trans) + # 仅位置参数:按字段顺序构建 + return self.Gen.CallGenCtor._translate_struct_ctor( + pool, builder, mod, struct_ty, func_name, cargs, can, trans) + + # 裸名泛型类模板构造: Box(42) → 从实参推断类型实参 → 特化 → 构造 + # (TPC 参考: _HandleGenericClassNewLlvm;GenericTest Test4 Box(42)/Test5 + # Pair(10,20)/Test10 Counter(0) 依赖此路径。显式类型实参 list[int](mb) + # 走 translate_call 上方的 Subscript 分支,此处处理裸名 + 推断。) + # 支持模块限定调用(vector.Vector(...)):func_name 是 attr("Vector"), + # 需确认模块已导入(模板查找兜底——普通函数如 stdlib.free 的 attr 找 + # 不到模板 → 回落普通调用)。 + if struct_ty is None and gen_ctor_entry is None and trans is not None: + is_gen_bare: int = 0 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: + is_gen_bare = 1 + elif cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + at_gb: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if at_gb.value is not None and at_gb.value.kind() == ast.ASTKind.Name: + am_gb: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_gb.value) + if am_gb.id is not None: + if self.Gen.ImportsGen.is_module_imported(trans._imported_modules, am_gb.id) != 0: + is_gen_bare = 1 + if is_gen_bare != 0: + template_cd_bare: ast.ClassDef | t.CPtr = self.Gen.ClassGenGeneric._find_generic_template(func_name) + if template_cd_bare is not None and template_cd_bare.type_params is not None: + tp_bare: list[str] | t.CPtr = template_cd_bare.type_params + tp_count_bare: t.CSizeT = len(tp_bare) + if tp_count_bare > 0: + inferred_args_bare: list[str] | t.CPtr = list[str](pool, 8) + if inferred_args_bare is not None: + # 对齐 TPC _HandleGenericClassNewLlvm:先收集全部实参 + # 推断类型,过滤纯 int(排除 pool 等非 T 参数), + # hint_types 优先填充(Vector(pool,8,CFloat64T(0.0)) + # → Vector[double];Vector(pool,10,CInt(0)) → Vector[int]) + hint_bare: list[str] | t.CPtr = list[str](pool, 8) + if hint_bare is not None: + hi_bare: t.CSizeT + for hi_bare in range(can): + hty_bare: str = self.Gen.CallGenCtor._infer_generic_ctor_type_arg(pool, cargs.get(hi_bare), func_name) + if string.strcmp(hty_bare, "int") != 0: + hint_bare.append(hty_bare) + tpi_bare: t.CSizeT = 0 + for tpi_bare in range(tp_count_bare): + ta_bare: str = "int" + if tpi_bare < len(hint_bare): + ta_bare = hint_bare.get(tpi_bare) + elif tpi_bare < can: + ta_bare = self.Gen.CallGenCtor._infer_generic_ctor_type_arg(pool, cargs.get(tpi_bare), func_name) + inferred_args_bare.append(ta_bare) + spec_name_bare: str = self.Gen.ClassGenGeneric._specialize_generic_class( + trans, func_name, inferred_args_bare) + if spec_name_bare is not None: + return self.Gen.CallGenCtor._translate_generic_ctor_call( + pool, builder, mod, spec_name_bare, cl, trans) + + # REnum 变体构造检测: ClassName.VariantName(args...) + # 如 LLVMType.Int(1) → 构造 LLVMType 的 Int 变体 + # 必须在跨模块调用查找之前,否则 ClassName 会被误判为模块名 + # 对应 TPC HandlesExprCall.py:585-644 的三条检测路径之一 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + rc_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if rc_at.value is not None and rc_at.value.kind() == ast.ASTKind.Name: + rc_cls_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rc_at.value) + if rc_cls_node.id is not None: + rc_cls_name: str = rc_cls_node.id + # 检查 ClassName 是否是已注册的 REnum 类 + if self.Gen.ClassGenEnum._is_renum_class_name(rc_cls_name) != 0: + # 在该 REnum 类中查找变体名 func_name + rc_tag: int = self.Gen.ClassGenEnum._lookup_renum_variant_in_class( + rc_cls_name, func_name) + if rc_tag >= 0: + return self.Gen.CallGenCtor._translate_renum_construct( + pool, builder, mod, rc_cls_name, func_name, + rc_tag, cargs, can, trans) + elif rc_at.value is not None and rc_at.value.kind() == ast.ASTKind.Attribute: + # 模块限定 REnum 变体构造: mod.Class.Variant(args...) + # 如 llvmlite.LLVMType.Struct(...) → 构造 llvmlite 模块 LLVMType 的 Struct 变体。 + # 根因:此前只支持单层 Name(ClassName.Variant),嵌套属性漏检 → 误走跨模块 + # 函数路径 → _lookup_module_sha1("llvmlite.LLVMType") 查无 → 报"跨模块调用 + # 'llvmlite.LLVMType.Struct' 找不到模块 SHA1"。跨模块任意同名可接受(REnum + # 表按类名全局注册):仅要求最左模块已导入 + 末段类名在全局 REnum 表中命中, + # 不做"类必须属于该模块"校验(未命中则按后续函数路径 fast-fail)。 + rc_mq_path: str = self.Gen.ExprGenAttr._attr_module_path_str(pool, rc_at.value) + if rc_mq_path is not None: + rc_mq_dot: str = string.strrchr(rc_mq_path, 46) # 46 = ord('.') + if rc_mq_dot is not None and rc_mq_dot[1] != '\0': + # 模块路径 = 末段之前(支持多级: w32.fileio.Class.Variant)。 + # 注意:不能用 rc_mq_dot - rc_mq_path 指针减法(TPC 直接发 + # sub i8*, i8* 非法 IR),用 strlen 整数差扣除末段与分隔点。 + rc_mq_len: t.CSizeT = string.strlen(rc_mq_path) - string.strlen(rc_mq_dot + 1) - 1 + rc_mq_mod: str = pool.alloc(rc_mq_len + 1) + if rc_mq_mod is not None: + string.memcpy(rc_mq_mod, rc_mq_path, rc_mq_len) + rc_mq_mod[rc_mq_len] = '\0' + rc_mq_imp: int = 1 + if trans is not None and trans._imported_modules is not None: + rc_mq_imp = self.Gen.ImportsGen.is_module_imported( + trans._imported_modules, rc_mq_mod) + if rc_mq_imp != 0: + rc_mq_cls: str = rc_mq_dot + 1 + # 检查类名是否是已注册的 REnum 类 + if self.Gen.ClassGenEnum._is_renum_class_name(rc_mq_cls) != 0: + rc_mq_tag: int = self.Gen.ClassGenEnum._lookup_renum_variant_in_class( + rc_mq_cls, func_name) + if rc_mq_tag >= 0: + return self.Gen.CallGenCtor._translate_renum_construct( + pool, builder, mod, rc_mq_cls, func_name, + rc_mq_tag, cargs, can, trans) + + # 查找函数:优先从函数表按裸名精确匹配(同模块函数), + # 再从模块函数链表按后缀匹配(SHA1 前缀名)。 + # 注意:模块限定/属性调用(如 stdlib.free)不能做后缀匹配—— + # "free" 会误命中 viperio.Buf.free 等方法,导致普通 malloc 指针被 + # 当作 Buf 对象释放(Buf.free 读 self 字段/写 self.data), + # 传入句柄数组等指针时把句柄值当地址写入直接崩溃。 + # 后缀匹配仅用于裸名调用(cl.func 是 Name,如 _thread_alloc_free)。 + # stubs 在翻译后才注入,翻译时跨模块函数 found_func 通常为 None, + # 此时根据函数名推断 includes 库函数的返回类型(如 strchr 返回 i8*) + # 如果调用方未传 funcs_ptr/func_count(如 AnnAssign 路径),从 trans 获取 + actual_funcs: GenTypes.FuncEntry | t.CPtr = funcs_ptr + actual_func_count: int = func_count + if actual_funcs is None and trans is not None: + actual_funcs = trans._funcs + actual_func_count = trans._func_count + found_func: llvmlite.Function | t.CPtr = None + if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: + # 裸名调用:允许精确 + 后缀匹配 + # 自定义装饰器 wrapper 重写:原函数名 → __decor_wrap_{name} + # (对齐 TPC DecoratorPass.run 的 _redirect_calls;wrapper 在函数 + # 翻译末尾生成,同 pass 内 main 调用点晚于被装饰函数定义,可达) + decor_wrap_nm: str = self.Gen.ClassGenBase.lookup_decor_wrapper(func_name) + if decor_wrap_nm is not None: + found_func = self.find_func_in_module(mod, decor_wrap_nm) + else: + found_func = self.find_func_in_module(mod, func_name) + # 治本修复(对齐 Attribute 路径 L6579-6613):后缀匹配误命中类方法 + # (SHA1.Class.method,第 2 段是已注册结构体类)必须拒绝——否则方法体内 + # 与 from-import 模块函数同名的裸名调用(如 LLVMModuleCore.SSAValue 内 + # 的 SSAValue(self.Pool, ...))绑定到本类方法 define → 无限递归 + # (栈溢出 0xC0000005)。裸名调用应优先解析为模块级函数 + # (同模块函数表 / from_imports),方法调用需显式 obj.method。 + if found_func is not None: + bn_name: str = llvmlite.function_get_name(found_func) + if bn_name is not None: + bn_dots: int = 0 + bni2: t.CSizeT = 0 + while bn_name[bni2] != '\0': + if bn_name[bni2] == '.': + bn_dots += 1 + bni2 += 1 + if bn_dots >= 2: + # 提取第 2 段(SHA1.Class.method → Class;SHA1.submod.func → submod) + bn_seg2: str = pool.alloc(64) + if bn_seg2 is not None: + bn_seg2[0] = '\0' + bsi2: t.CSizeT = 0 + while bn_name[bsi2] != '\0' and bsi2 < 17: + bsi2 += 1 + bse2: t.CSizeT = bsi2 + while bn_name[bse2] != '\0' and bn_name[bse2] != '.': + bse2 += 1 + bsl2: t.CSizeT = bse2 - bsi2 + if bsl2 > 0 and bsl2 < 63: + string.strncpy(bn_seg2, bn_name + bsi2, bsl2) + bn_seg2[bsl2] = '\0' + # 第 2 段是已注册结构体类 → 是方法,拒绝(走模块 SHA1 路径) + if self.Gen.StructGen.get_struct_type(bn_seg2) is not None: + found_func = None + else: + # 模块限定/属性调用:精确匹配优先,后缀匹配仅接受模块函数。 + # 后缀匹配命中的"方法"(SHA1.Class.method,Class 是已注册类)必须拒绝—— + # 短方法名(free/reset/close 等)会误命中其他模块的方法 + # (如 stdlib.free 命中 viperio.Buf.free,普通指针被当 Buf 释放崩溃; + # 且 atom.__atomic_test_and_set 若被误拒,返回类型从 i1 推断成 i32, + # 调用按 i32 读 i1 返回值读到垃圾高位,spinlock 恒非 0 卡死)。 + # 模块函数(SHA1.func)或子模块函数(SHA1.submod.func)的后缀匹配保留。 + found_func = self.find_func_in_module(mod, func_name) + if found_func is not None: + # 模块限定调用(mod.func,value 是已导入模块名):校验 found_func + # 的 SHA1 前缀必须等于该模块。否则 find_func_in_module 第 3 遍对 + # stub declare 的后缀匹配会误命中其他模块的同名函数(如 main 模块 + # 里 subprocess 的 declare 先注入,syslibtest_impl.run() 后缀匹配 + # 误命中 subprocess.run → call 到错误符号 → 参数错位解引用崩溃, + # SysLibTest 0xC0000005 根因)。误命中时拒绝(found_func=None), + # 落到下方跨模块模块限定解析用模块自身 SHA1 构造正确符号。 + xm_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if xm_at is not None and xm_at.value is not None and trans is not None \ + and trans._imported_modules is not None: + # 模块路径:单层 Name(syslibtest_impl.run)或嵌套 Attribute + # (os._win32.exists)。后者此前不校验 → os/__init__.vp 内部 + # 调 os._win32.exists 后缀匹配命中本模块同名 define → + # 无限递归栈溢出(SysLibTest 0xC00000FD 根因)。 + xm_mod_path: str = None + if xm_at.value.kind() == ast.ASTKind.Name: + xm_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(xm_at.value) + if xm_nm.id is not None: + xm_mod_path = xm_nm.id + elif xm_at.value.kind() == ast.ASTKind.Attribute: + xm_mod_path = self.Gen.ExprGenAttr._attr_module_path_str( + pool, xm_at.value) + if xm_mod_path is not None: + if self.Gen.ImportsGen.is_module_imported( + trans._imported_modules, xm_mod_path) != 0: + mod_sha1_chk: str = self._lookup_module_sha1(xm_mod_path) + if mod_sha1_chk is not None: + ff_nm2: str = llvmlite.function_get_name(found_func) + if ff_nm2 is not None: + if string.strncmp(ff_nm2, mod_sha1_chk, 16) != 0: + found_func = None + ff_name: str = llvmlite.function_get_name(found_func) + if ff_name is not None: + ff_dots: int = 0 + ffi2: t.CSizeT = 0 + while ff_name[ffi2] != '\0': + if ff_name[ffi2] == '.': + ff_dots += 1 + ffi2 += 1 + if ff_dots >= 2: + # 提取第 2 段(SHA1.Class.method → Class;SHA1.submod.func → submod) + seg2: str = pool.alloc(64) + if seg2 is not None: + seg2[0] = '\0' + si: t.CSizeT = 0 + while ff_name[si] != '\0' and si < 17: + si += 1 + seg_start: t.CSizeT = si + seg_end: t.CSizeT = si + while ff_name[seg_end] != '\0' and ff_name[seg_end] != '.': + seg_end += 1 + seg_len: t.CSizeT = seg_end - seg_start + if seg_len > 0 and seg_len < 63: + string.strncpy(seg2, ff_name + seg_start, seg_len) + seg2[seg_len] = '\0' + # 第 2 段是已注册结构体类 → 是方法,拒绝(走模块 SHA1 路径) + if self.Gen.StructGen.get_struct_type(seg2) is not None: + found_func = None + # C 库函数裸名调用支持:若模块中找不到且是已知 C 库函数,自动创建 declare + # 对应 TPC 的 _C_LIB_FUNCS 机制,支持 memset/memmove/memcmp/strcmp 等裸名调用 + if found_func is None and cl.func is not None and cl.func.kind() == ast.ASTKind.Name: + found_func = self.Gen.CallGenLib._ensure_c_lib_declare(pool, mod, func_name) + # builtins 自动关联:C 库未命中时,自动关联 builtins 模块的内置函数(ord/chr 等)。 + # builtins 已由编译链预加入(StubMerger 预加入列表)。PhaseA 期 builtins 尚未编译, + # 因此按约定签名创建 {builtins_sha1}.{name} 的 mangled declare(链接时解析到 + # builtins.vp 的真实定义);签名与 builtins.vp 保持一致:ord(i8)->i32, chr(i32)->i8。 + if found_func is None: + bi_sha1: str = self._lookup_module_sha1("builtins") + if bi_sha1 is not None: + bi_ret: llvmlite.LLVMType | t.CPtr = None + bi_p1: llvmlite.LLVMType | t.CPtr = None + if string.strcmp(func_name, "ord") == 0: + bi_ret = llvmlite.Int32(pool) + bi_p1 = llvmlite.Int8(pool) + elif string.strcmp(func_name, "chr") == 0: + bi_ret = llvmlite.Int8(pool) + bi_p1 = llvmlite.Int32(pool) + if bi_ret is not None: + bi_sym: str = func_name + if self.Gen.CallGenBase.is_cexport_func(bi_sha1, func_name) == 0: + bi_sym_len: t.CSizeT = string.strlen(bi_sha1) + string.strlen(func_name) + 2 + bi_sym_buf: str = pool.alloc(bi_sym_len) + if bi_sym_buf is not None: + viperlib.snprintf(bi_sym_buf, bi_sym_len, "%s.%s", bi_sha1, func_name) + bi_sym = bi_sym_buf + bi_decl: llvmlite.Function | t.CPtr = llvmlite.create_declare( + pool, mod, bi_sym, bi_ret) + if bi_decl is not None: + llvmlite.add_param(pool, bi_decl, bi_p1, "v") + found_func = bi_decl + # 使用访问器绕过 stub 类型限制 + found_ret_ty: llvmlite.LLVMType | t.CPtr = None + found_params: t.CPtr = None + if found_func is not None: + found_ret_ty = llvmlite.function_get_ret_ty(found_func) + found_params = llvmlite.function_get_params(found_func) + if found_ret_ty is not None: + call_ret_ty: llvmlite.LLVMType | t.CPtr = found_ret_ty + else: + # found_func=None(跨模块 stub 未注入):先从 vpi stub 返回注解 + # 缓存精确获取返回类型(含 tuple[T1,T2] → 匿名结构体,如 + # b2a_hqx -> tuple[str, t.CUnsignedShort] → {i8*, i16}), + # 未命中才回退 _infer_external_func_ret_ty 白名单推断。 + # 根因:_infer 白名单无 tuple 概念,未知函数默认 i32 会截断 + # 指针/i64;b2a_hqx 被推断为单值 i8*/i32 后调用侧返回值类型 + # 与定义侧 {i8*, i16} 不匹配 → HandlesAssign 的 tuple 解包 + # (依赖 rhs_val.Ty 是 Struct)静默跳过 → 目标变量从未赋值 → + # free 未初始化栈垃圾指针崩溃(HashLibTest hqx 段)。 + vpi_ret_ty: llvmlite.LLVMType | t.CPtr = None + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + at_ret: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if at_ret.value is not None and at_ret.value.kind() == ast.ASTKind.Name: + mod_ret_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_ret.value) + if mod_ret_nm.id is not None: + mod_ret_sha1: str = self._lookup_module_sha1(mod_ret_nm.id) + if mod_ret_sha1 is not None: + # 函数内懒 import:VpiReader imports HandlesExprCall, + # 顶层 import 会成环(与 _lookup_method_ret_ty_via_vpi 一致) + import lib.StubGen.VpiReader as VpiReader + VpiReader._ensure_vpi_ret_annot_loaded(mod_ret_sha1, self.Gen.CallGenBase.TempDir) + ret_annot_fc: str = VpiReader._lookup_vpi_ret_annot( + mod_ret_sha1, None, func_name) + if ret_annot_fc is not None: + vpi_ret_ty = VpiReader._resolve_vpi_ret_annot_str( + pool, ret_annot_fc, + llvmlite.Int32(pool), + llvmlite.Ptr(pool, llvmlite.Int8(pool))) + if vpi_ret_ty is not None: + call_ret_ty = vpi_ret_ty + else: + call_ret_ty = self.Gen.CallGenLib._infer_external_func_ret_ty(pool, func_name) + + # 如果模块中找不到函数,仅裸名调用(Name)才回退查局部变量(函数指针/ + # 闭包调用);模块属性调用(VLogger.fmt_buf())的目标是模块符号,绝不 + # 回退局部变量——跨模块任意同名可接受(CallGenLeafKit 局部 fmt_buf + # 曾劫持 VLogger.fmt_buf → 误走函数指针调用报 t.Callable 缺失), + # 仅 from-import 的裸名 yyy 与局部重名才可能冲突(该场景 func 是 Name)。 + if found_func is None: + fp_alloca: llvmlite.Value | t.CPtr = None + if cl.func is None or cl.func.kind() == ast.ASTKind.Name: + fp_alloca = self.Gen.VarGen.lookup_var(trans.SymTab, func_name) + if fp_alloca is not None: + # 闭包变量(嵌套函数提升,已注册到闭包名集合):提取 fn_ptr/env_ptr 间接调用 + if self.Gen.CallGenLeafKit.is_closure_name(func_name) != 0: + return self.Gen.CallGenLeafKit.translate_closure_call(pool, builder, mod, fp_alloca, + cargs, can, trans) + # 函数指针变量(t.Callable 注解 → i8** alloca):按实参构造签名间接调用 + if self.Gen.CallGenLeafKit._is_func_ptr_alloca(fp_alloca) != 0: + # 区分 t.Callable(真函数指针)vs t.CPtr(闭包指针): + # t.CPtr 变量(如 f: t.CPtr = make_counter())存的是闭包结构 + # {fn_ptr, env_ptr},调用必须提取 env 传参;若按函数指针直接 + # call,跳转到闭包结构数据地址崩溃(ClosureCallTest 运行时崩溃)。 + ve_fp: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, func_name) + is_cptr_annot_fp: int = 0 + if ve_fp is not None and ve_fp.AnnotClassName is not None: + if string.strstr(ve_fp.AnnotClassName, "CPtr") is not None: + is_cptr_annot_fp = 1 + if is_cptr_annot_fp == 0: + return self.Gen.CallGenLeafKit._translate_func_ptr_call(pool, builder, mod, fp_alloca, + func_name, cargs, can, trans) + return self.Gen.CallGenLeafKit.translate_closure_call(pool, builder, mod, fp_alloca, + cargs, can, trans) + # 其他 i8* 变量按闭包调用路径处理 + return self.Gen.CallGenLeafKit.translate_closure_call(pool, builder, mod, fp_alloca, + cargs, can, trans) + + # 翻译参数并链接 + # 有关键字参数且找到函数定义时,按参数名匹配 + if kw_count > 0 and found_func is not None and found_params is not None: + return self.Gen.CallGenLib._translate_call_with_kwargs( + pool, builder, mod, func_name, found_func, + cargs, can, keywords, kw_count, trans) + + head: llvmlite.Value | t.CPtr = None + tail: llvmlite.Value | t.CPtr = None + # memcpy 专用: 收集前三个 Value 的独立引用(避免共享 alloca 对象的 Next 被污染) + mc_dst2: llvmlite.Value | t.CPtr = None + mc_src2: llvmlite.Value | t.CPtr = None + mc_num2: llvmlite.Value | t.CPtr = None + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is not None: + arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is not None: + # 参数类型提升:当 found_func 为 None(stub 未注入)时, + # 根据外部函数签名推断期望类型,提升字面量(如 i32→i64) + # 避免 declare(i64) 与 call(i32) 类型不匹配 + if found_func is None and arg_val.Ty is not None: + # 数组实参按 C 语义衰减为元素指针(对齐 TPC + # _decay_array_to_ptr),与 _translate_method_call 一致。 + if self.Gen.ExprGenBase.is_ptr_type(arg_val.Ty) != 0: + arr_pointee_fc: llvmlite.LLVMType | t.CPtr = arg_val.Ty.Pointee + if arr_pointee_fc is not None: + match arr_pointee_fc: + case llvmlite.LLVMType.Array(arr_et_fc, _): + decayed_fc: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( + builder, arr_pointee_fc, arr_et_fc, arg_val, + llvmlite.const_int32(pool, 0)) + if decayed_fc is not None: + arg_val = decayed_fc + case _: + pass + ext_param_ty: llvmlite.LLVMType | t.CPtr = self.Gen.CallGenLib._get_external_func_param_ty( + pool, func_name, ai) + if ext_param_ty is not None: + val_bits_ap: int = self.Gen.ExprGenBase.get_llvm_type_bits(arg_val.Ty) + tgt_bits_ap: int = self.Gen.ExprGenBase.get_llvm_type_bits(ext_param_ty) + if val_bits_ap != 0 and tgt_bits_ap != 0 and val_bits_ap != tgt_bits_ap: + if val_bits_ap == 1 and val_bits_ap < tgt_bits_ap: + arg_val = llvmlite.build_zext(builder, arg_val, ext_param_ty) + else: + arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, ext_param_ty, arg) + elif found_func is not None: + # found_func 存在:按形参类型 coerce(如 stdlib.malloc(size: t.CSizeT)) + # 修复: CDefine/i32 常量传给 i64 形参未提升,导致 call(i32) 与 define(i64) 不匹配 + fp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + fpi: int = 0 + while fp is not None and fpi < ai: + fp = llvmlite.param_get_next(fp) + fpi += 1 + if fp is not None: + fpty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(fp) + if fpty is not None: + arg_val = self.Gen.ExprGenBase.coerce_to_type( + builder, arg_val, fpty, arg) + elif found_func.IsVarArg == 1: + # Win64 变参 8 字节槽位:<64 位整数按 i64 传(sext 符号扩展), + # f32 提升为 f64。若按原窄类型传,调用点只写 4 字节进 8 字节槽, + # 高 4 字节残留旧栈数据,va_arg(i64) 读到垃圾(如 DefineTest + # PAGE=%d 读到 0x400921FB00001000,高位是 PI 残留)。 + # 对齐 TPC FuncGen/Python-llvmlite 的 ABI 自动提升。 + ab_va: int = self.Gen.ExprGenBase.get_llvm_type_bits(arg_val.Ty) + af_va: int = self.Gen.ExprGenBase.get_llvm_float_bits(arg_val.Ty) + i64_va: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + if ab_va != 0 and ab_va < 64: + arg_val = llvmlite.build_sext(builder, arg_val, i64_va) + elif af_va == 32: + arg_val = llvmlite.build_fpext( + builder, arg_val, llvmlite.Double(pool)) + arg_val.Next = None + if head is None: + head = arg_val + else: + tail.Next = arg_val + tail = arg_val + # memcpy 专用: 保存前三个参数的独立引用 + if ai == 0: + mc_dst2 = arg_val + elif ai == 1: + mc_src2 = arg_val + elif ai == 2: + mc_num2 = arg_val + + # 默认参数填充:当实参数量 < 形参数量时,用默认值填充缺失参数 + # defaults 数组右对齐到 args:defaults[0] 对应 args[offset],offset = param_count - default_count + if can > 0 or (can == 0 and cargs is not None): + df_defaults: t.CVoid | t.CPtr = None + df_default_count: int = 0 + df_param_count: int = 0 + # 先从当前模块函数表查找 FuncEntry + if trans is not None and trans._funcs is not None: + df_entry: FuncEntry | t.CPtr = ExprCallTable.find_func_entry_in_table( + trans._funcs, trans._func_count, func_name) + if df_entry is not None: + df_defaults = df_entry.Defaults + df_default_count = df_entry.DefaultCount + df_param_count = df_entry.ParamCount + # 无条件查询全局默认参数表(跨模块/同模块都要用 stdlib 常量快照 + # 重建默认值:模块表 Defaults 指向 pool 内 AST,跨 1b reset 后悬空; + # 快照才是跨文件永久存活。同模块命中时 gd_entry 也必须已赋值, + # 否则下方 _build_const_from_snapshot 读到未初始化栈垃圾指针崩溃。 + # 与 _translate_method_call 的 mdf_gd 无条件查询(L2677)保持一致。 + gd_entry: FuncDefaultsEntry | t.CPtr = self.Gen.CallGenLeafKit.find_func_defaults(func_name) + if df_defaults is None and gd_entry is not None: + df_defaults = gd_entry.Defaults + df_default_count = gd_entry.DefaultCount + df_param_count = gd_entry.ParamCount + # 填充缺失参数 + if df_defaults is not None and df_default_count > 0 and can < df_param_count: + df_offset: int = df_param_count - df_default_count + df_di: int = 0 + while df_di < df_default_count: + df_param_idx: int = df_offset + df_di + if df_param_idx >= can: + # 优先用 stdlib 常量快照重建(gd_entry.Defaults 的 pool 内 AST 可能已被 reset 回收) + df_arg_val: llvmlite.Value | t.CPtr = None + if gd_entry is not None: + df_arg_val = self.Gen.CallGenLeafKit._build_const_from_snapshot( + pool, mod, gd_entry, df_di, trans, builder) + if df_arg_val is None: + df_defaults_list: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(df_defaults), t.CPtr)) + df_default_node: ast.AST | t.CPtr = df_defaults_list.get(df_di) + if df_default_node is not None: + df_arg_val = self.Gen.ExprGen.translate_value( + builder, pool, mod, df_default_node, None, 0, trans) + if df_arg_val is not None: + df_arg_val.Next = None + if head is None: + head = df_arg_val + else: + tail.Next = df_arg_val + tail = df_arg_val + df_di += 1 + + # 使用模块中的实际函数名(可能带 SHA1 前缀,如 "83210a72e829a086.atoi") + # t.CExtern/t.State/t.CExport 函数不加 SHA1 前缀,使用裸名 + # declare 和 define 统一用 found_func.Name: + # - 普通函数的 declare/define 都带 SHA1 前缀(forward_declare_functions 和 stub 注入都用 mangled_name) + # - t.CExtern/t.State/t.CExport 函数的 declare/define 都用裸名 + # 旧逻辑(IsDeclared==1 时用 func_name 裸名)是错误的:stub 注入的 declare Name 已带 SHA1 前缀, + # 用裸名会导致 call @_PathToModuleName 而 define 是 @"sha1._PathToModuleName",链接报 undefined reference + call_name: str = func_name + # 原始函数名(别名导入时记录,如 from X import parse as json_parse → orig_func_name="parse") + # 用于在别名处理后重新推断返回类型,避免 _infer_external_func_ret_ty 用别名匹配失败 + orig_func_name: str = None + if found_func is not None: + found_name: str = llvmlite.function_get_name(found_func) + if found_name is not None: + call_name = found_name + else: + # 跨模块函数调用:found_func 为 None 时,检查是否是模块限定调用 + # 如 string.strchr(...) → @{sha1_of_string}.strchr + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + xmod_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if xmod_at.value is not None and (xmod_at.value.kind() == ast.ASTKind.Name + or xmod_at.value.kind() == ast.ASTKind.Attribute): + # 模块路径:单层 Name(string.strchr)或嵌套 Attribute + # (os._win32.exists)。嵌套路径此前不支持 → os/__init__.vp + # 内部调 os._win32.exists 只能被 find_func_in_module 后缀匹配 + # 命中本模块同名 define(无限递归),或找不到模块路径而走 + # 错误 fallback;此处用完整模块路径解析正确 SHA1(与校验段 + # L7344 对齐,SysLibTest 0xC00000FD 根因)。 + xmod_path: str = None + if xmod_at.value.kind() == ast.ASTKind.Name: + xmod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(xmod_at.value) + if xmod_nm.id is not None: + xmod_path = xmod_nm.id + else: + xmod_path = self.Gen.ExprGenAttr._attr_module_path_str(pool, xmod_at.value) + if xmod_path is not None: + mod_sha1: str = self._lookup_module_sha1(xmod_path) + if mod_sha1 is not None: + # fast-fail: 模块限定调用要求模块已被当前文件 import。 + # 全局 SHA1 存储包含所有被扫描的 includes,未导入的模块 + # (如 this.this() 但 import this 被注释)也会命中存储, + # 静默生成 @{sha1}.func 调用而非报错——违反"找不到 fast-fail"原则。 + is_xmod_imported: int = 1 + if trans is not None and trans._imported_modules is not None: + is_xmod_imported = self.Gen.ImportsGen.is_module_imported( + trans._imported_modules, xmod_path) + if is_xmod_imported == 0: + err_ni: str = pool.alloc(256) + if err_ni is not None: + viperlib.snprintf(err_ni, 256, + "跨模块调用 '%s.%s':模块 '%s' 未导入(请先 import %s)", + xmod_path, func_name, xmod_path, xmod_path) + self.Gen.TypeGenErr.fatal_error(xmod_at, err_ni) + self.Gen.TypeGenErr.fatal_error(xmod_at, "跨模块调用:模块未导入") + # 检查是否是 re-export 函数(如 ast._lexer_init 实际定义在 ast.lexer) + reexport_src: str = self.Gen.ImportsGen.lookup_reexport(mod_sha1, func_name) + if reexport_src is None: + # re-export 表未命中(includes 模块 stub/text 已存在时 + # 不被按需全量翻译,表只在 declare_only=0 时注册,可能为空): + # 按需解析该模块 .vpi 的 from-import 定位定义模块 + reexport_src = self._lookup_reexport_from_vpi(pool, mod_sha1, func_name) + if reexport_src is not None: + reexport_sha1: str = self._lookup_module_sha1(reexport_src) + if reexport_sha1 is not None: + mod_sha1 = reexport_sha1 + # CExport 函数定义用裸名(@strlen),跨模块调用需用裸名而非 @{sha1}.func + if self.Gen.CallGenBase.is_cexport_func(mod_sha1, func_name) != 0: + call_name = func_name + elif self._is_state_func_from_vpi(pool, mod_sha1, func_name) != 0: + # t.State 标记的外部 C 函数(如 CPython PyList_Size): + # 定义端用裸名 @PyList_Size(链接外部库),跨模块调用 + # 必须用裸名——带 sha1 前缀 → ld.lld undefined symbol + call_name = func_name + else: + mangled_len: t.CSizeT = string.strlen(mod_sha1) + string.strlen(func_name) + 2 + mangled: str = pool.alloc(mangled_len) + if mangled is not None: + viperlib.snprintf(mangled, mangled_len, "%s.%s", mod_sha1, func_name) + call_name = mangled + else: + # t 和 c 是内部库,豁免 SHA1 查找:使用裸名调用 + if string.strcmp(xmod_path, "t") == 0 or string.strcmp(xmod_path, "c") == 0: + call_name = func_name + else: + # Bug 修复: 先检查是否是已导入的模块名(如 BuildPipeline.run_pipeline) + # 如果是已导入模块但 SHA1 未注册,说明该模块未被编译(如 Phase2 未扫描到), + # 应该立即报错,而不是错误地走 from_imports 查找(会被 star import 回退误导) + is_imported_mod: int = 0 + if trans is not None and trans._imported_modules is not None: + is_imported_mod = self.Gen.ImportsGen.is_module_imported( + trans._imported_modules, xmod_path) + if is_imported_mod != 0: + # 别名导入(import X as Y):Y 在 _imported_modules 中, + # 但 _lookup_module_sha1("Y") 精确匹配失败(mod_arr 只存文件名)。 + # 先尝试 from_imports 查找别名→完整模块名→后缀匹配 SHA1。 + # allow_star_fallback=0 避免被 star import 回退误导。 + alias_sha1: str = None + if trans is not None and trans._from_imports is not None: + alias_sha1 = self._lookup_mod_sha1(pool, trans._from_imports, xmod_path, 0) + if alias_sha1 is not None: + if self.Gen.CallGenBase.is_cexport_func(alias_sha1, func_name) != 0: + call_name = func_name + elif self._is_state_func_from_vpi(pool, alias_sha1, func_name) != 0: + # t.State 外部 C 函数:裸名(同主路径 L7918) + call_name = func_name + else: + AliasMangledLen: t.CSizeT = string.strlen(alias_sha1) + string.strlen(func_name) + 2 + alias_mangled: str = pool.alloc(AliasMangledLen) + if alias_mangled is not None: + viperlib.snprintf(alias_mangled, AliasMangledLen, "%s.%s", alias_sha1, func_name) + call_name = alias_mangled + else: + # 已导入模块但 SHA1 未注册:该模块未被编译,立即报错 + err_msg_imp: str = pool.alloc(256) + if err_msg_imp is not None: + viperlib.snprintf(err_msg_imp, 256, "模块 '%s' 已导入但 SHA1 未注册(该模块未被编译)", xmod_path) + self.Gen.TypeGenErr.fatal_error(xmod_at, err_msg_imp) + self.Gen.TypeGenErr.fatal_error(xmod_at, "已导入模块 SHA1 未注册") + else: + # 检查是否是通过 from import 导入的名称(如 from .__types import LLVMType) + # LLVMType.Ptr(ty) 中 LLVMType 是类名不是模块名, + # 但 Ptr 是 __types 模块的模块级函数 + # 禁用 star import 回退:xmod_path 是明确名称,不应回退到 star import 模块 + from_sha1: str = None + if trans is not None and trans._from_imports is not None: + from_sha1 = self._lookup_mod_sha1(pool, trans._from_imports, xmod_path, 0) + if from_sha1 is not None: + # CExport 函数定义用裸名,跨模块调用需用裸名 + if self.Gen.CallGenBase.is_cexport_func(from_sha1, func_name) != 0: + call_name = func_name + else: + fmangled_len: t.CSizeT = string.strlen(from_sha1) + string.strlen(func_name) + 2 + fmangled: str = pool.alloc(fmangled_len) + if fmangled is not None: + viperlib.snprintf(fmangled, fmangled_len, "%s.%s", from_sha1, func_name) + call_name = fmangled + else: + err_msg2: str = pool.alloc(256) + if err_msg2 is not None: + viperlib.snprintf(err_msg2, 256, "跨模块调用 '%s.%s' 找不到模块 SHA1", xmod_path, func_name) + self.Gen.TypeGenErr.fatal_error(xmod_at, err_msg2) + self.Gen.TypeGenErr.fatal_error(xmod_at, "跨模块调用找不到模块 SHA1") + else: + # 裸名调用(非 Attribute):检查 from_imports + # 治本修复:函数调用禁用 star import 回退(allow_star_fallback=0)。 + # star import(from stdint import *)本意是导入类型/常量(如 BYTEPTR),而非函数; + # 函数应显式 from import。漏导函数若走 star 回退会被错归到 star 模块,生成错误 SHA1 符号 + # (如 block_insert_text_before_terminator 漏导后被错归 stdint,生成 + # f5522571bcce7bcb.block_insert... 而非 874bac141c97bae9.block_insert...)。 + # 禁用回退后,漏导函数编译期即报"未定义且未导入"(fast-fail),优于链接期 undefined reference。 + if trans is not None and trans._from_imports is not None: + bare_sha1: str = self._lookup_mod_sha1(pool, trans._from_imports, func_name, 0) + if bare_sha1 is not None: + # 别名处理: from X import Y as Z → 调用 Z 时需用 Y 作为源模块函数名 + # 例如 from json.__parser import parse as json_parse → 修饰为 SHA1.parse 而非 SHA1.json_parse + bare_orig: str = self.Gen.ImportsGen.lookup_from_import_original( + trans._from_imports, func_name) + bare_func_name: str = func_name + if bare_orig is not None: + # bare_orig 指向 from_imports 内部缓冲区,未 null 终止 + # 需复制到独立缓冲区(截断于空格或 null) + bo_len: t.CSizeT = 0 + while bare_orig[bo_len] != ' ' and bare_orig[bo_len] != '\0': + bo_len += 1 + bo_buf: str = pool.alloc(bo_len + 1) + if bo_buf is not None: + for bo_i in range(bo_len): + bo_buf[bo_i] = bare_orig[bo_i] + bo_buf[bo_len] = '\0' + bare_func_name = bo_buf + # 记录原始函数名,供后续重新推断返回类型 + # 例如 from json.__parser import parse as json_parse + # func_name="json_parse", bare_func_name="parse" + # _infer_external_func_ret_ty 用 "parse" 能正确匹配,用 "json_parse" 则返回默认 i32 + orig_func_name = bare_func_name + # re-export 解析(对齐模块限定路径 L6598): + # 裸名 from import 的函数可能实际定义在子模块(re-export)。 + # 例:from ast import dump → dump 定义在 ast.base(sha1=71b2), + # ast/__init__(sha1=876e)只是 re-export。若沿用包 sha1 构造 + # call_name="876e.dump",text.ll/vpi 返回类型解析均未命中, + # fail-fast 报"返回类型无法精确获取";需重定向到定义模块 SHA1。 + reexport_src2: str = self.Gen.ImportsGen.lookup_reexport(bare_sha1, bare_func_name) + if reexport_src2 is None: + # re-export 表未命中:按需解析该模块 .vpi 的 from-import + reexport_src2 = self._lookup_reexport_from_vpi(pool, bare_sha1, bare_func_name) + if reexport_src2 is not None: + reexport_sha1_2: str = self._lookup_module_sha1(reexport_src2) + if reexport_sha1_2 is not None: + bare_sha1 = reexport_sha1_2 + if self.Gen.CallGenBase.is_cexport_func(bare_sha1, bare_func_name) != 0: + call_name = bare_func_name + else: + bare_mangled_len: t.CSizeT = string.strlen(bare_sha1) + string.strlen(bare_func_name) + 2 + bare_mangled: str = pool.alloc(bare_mangled_len) + if bare_mangled is not None: + viperlib.snprintf(bare_mangled, bare_mangled_len, "%s.%s", bare_sha1, bare_func_name) + call_name = bare_mangled + else: + err_msg3: str = pool.alloc(256) + if err_msg3 is not None: + viperlib.snprintf(err_msg3, 256, "裸名调用 '%s' 未定义且未导入", func_name) + self.Gen.TypeGenErr.fatal_error(node, err_msg3) + self.Gen.TypeGenErr.fatal_error(node, "裸名调用未定义且未导入") + else: + err_msg4: str = pool.alloc(256) + if err_msg4 is not None: + viperlib.snprintf(err_msg4, 256, "裸名调用 '%s' 未定义且未导入", func_name) + self.Gen.TypeGenErr.fatal_error(node, err_msg4) + self.Gen.TypeGenErr.fatal_error(node, "裸名调用未定义且未导入") + + # 直接调用 + # memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失) + if string.strcmp(func_name, "memcpy") == 0 and can >= 3: + return self.Gen.CallGenLib._emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst2, mc_src2, mc_num2) + # 别名导入重新推断返回类型: + # from X import parse as json_parse → func_name="json_parse" 时 _infer_external_func_ret_ty 返回默认 i32 + # 用 orig_func_name="parse" 重新推断,能正确匹配返回 i8*(JsonValue*) + # 避免指针被截断为 i32 后 inttoptr 丢失高 32 位导致崩溃 + if orig_func_name is not None and orig_func_name != func_name: + re_inferred_ty: llvmlite.LLVMType | t.CPtr = self.Gen.CallGenLib._infer_external_func_ret_ty(pool, orig_func_name) + if re_inferred_ty is not None: + call_ret_ty = re_inferred_ty + # ============================================================ + # 跨模块 Viper 函数返回类型精确解析(对齐方法路径,fail-fast) + # 根因:_infer_external_func_ret_ty 白名单未覆盖返回指针的模块函数 + # (new_lexer→Lexer* / tokenize→Token* / parse_tokens→AST*),兜底 i32 + # 导致 64 位指针被截断高 32 位 → inttoptr 无效指针 → 解引用崩溃 + # (AstTest 的 _lexer_init 崩溃链)。declare 也可能是错误 i32(_ensure_method_declare + # 曾用兜底类型创建),因此不信任 found_func 的 declare 返回类型。 + # 权威来源:text.ll define;次选:vpi stub 返回注解;均未命中立即终止。 + # 仅对 mangled("{16位hex}.func")调用生效;C 库/Win32 裸名走原白名单。 + # Phase 1a(declare_only)期间依赖 text.ll 未生成,保持原白名单行为不 fail-fast。 + # ============================================================ + if self.Gen.CallGenLib._is_sha1_mangled_call(call_name) != 0: + if trans is None or trans._declare_only == 0: + cf_dot: str = string.strchr(call_name, '.') + cf_last: str = string.strrchr(call_name, '.') + if cf_dot is not None and cf_last is not None: + cf_sha1: str = stdlib.malloc(17) + cf_bare_len: t.CSizeT = string.strlen(call_name) - \ + (t.CSizeT(t.CUInt64T(cf_last) - t.CUInt64T(call_name))) - 1 + cf_bare: str = stdlib.malloc(cf_bare_len + 1) + if cf_sha1 is not None and cf_bare is not None: + string.strncpy(cf_sha1, call_name, 16) + cf_sha1[16] = '\0' + string.strcpy(cf_bare, cf_last + 1) + # 本模块自身函数(泛型特化等):从当前 IR 已声明的函数 + # 取返回类型;不走跨模块 text.ll 查找——自己的 text.ll + # 在 Phase A 翻译中尚未生成,直接查会误报"依赖未生成" + # 并保持默认类型(GenericTest 泛型 add/combine 等警告 + # 根因)。未命中(特化尚未声明)保持默认推断。 + is_local_mod: int = 0 + if trans is not None and trans.ModuleSha1 is not None: + if string.strncmp(cf_sha1, trans.ModuleSha1, 16) == 0: + is_local_mod = 1 + if is_local_mod != 0: + local_fn: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, call_name) + if local_fn is not None and local_fn.RetTy is not None: + call_ret_ty = local_fn.RetTy + else: + cf_ret: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL( + pool, cf_sha1, None, cf_bare, 1) + if cf_ret is not None: + call_ret_ty = cf_ret + else: + cf_vpi: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi( + pool, cf_sha1, None, cf_bare) + if cf_vpi is not None: + call_ret_ty = cf_vpi + else: + # 区分两种失败场景: + # 1. 依赖模块 text.ll 存在但函数未命中 → 真错误,fail-fast + # 2. 依赖模块 text.ll 不存在(模块尚未翻译)→ Phase A 按 + # 文件顺序翻译,main.vp 先于其 import 的 mbuddytest.vp + # (同项目多源文件)。此时标记 trans._deps_pending=1, + # 保持白名单类型继续,Phase A 多遍循环下遍重译—— + # 届时依赖已生成 text.ll,可精确解析(治本:依赖先翻译)。 + if self._dep_text_ll_exists(pool, cf_sha1) != 0: + cf_err: str = VLogger.fmt_buf() + if cf_err is not None: + viperlib.snprintf( + cf_err, 1024, + "跨模块函数 '%s' 返回类型无法精确获取(text.ll/vpi 均未命中)," + "默认 i32 会截断指针/i64,请检查依赖模块是否已编译/注册", call_name) + VLogger.error(cf_err, "HandlesExprCall") + self.Gen.TypeGenErr.fatal_error( + node, + f"跨模块函数返回类型无法精确获取(text.ll/vpi 均未命中),默认 i32 会截断指针: {call_name}", + "TypeError") + else: + if trans is not None: + trans._deps_pending = 1 + cf_dbg: str = VLogger.fmt_buf() + if cf_dbg is not None: + viperlib.snprintf( + cf_dbg, 1024, + "跨模块函数 '%s' 依赖模块 text.ll 尚未生成(Phase A 顺序)," + "标记重试,本遍保持默认类型", call_name) + if VLogger.nowarn_register() == 0: + VLogger.warning(cf_dbg, "HandlesExprCall") + stdlib.free(cf_sha1) + stdlib.free(cf_bare) + # 跨模块调用:创建 declare 声明,避免 llc 报 undefined value + self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, can) + # 检查被调用函数是否为变长函数(*args),若是则对变长参数进行 C ABI 提升 + # (cargs 为本函数参数 AST 链表,self_offset=0 普通函数调用) + is_variadic_call: int = self.Gen.CallGenVa._check_and_promote_variadic_call( + pool, builder, mod, call_name, head, can, cargs, 0, trans) + # try-except:被调函数带 EH 输出参数时,追加输出实参 + 调用后检测异常 + return self.Gen.CallGenLeafKit._emit_eh_guarded_call( + builder, pool, mod, trans, found_func, call_name, head, can, + call_ret_ty, is_variadic_call) + + + + + + + + + + + + + diff --git a/App/lib/core/Gen/CallGenProp.vp b/App/lib/core/Gen/CallGenProp.vp index ab5096b..a08a5fd 100644 --- a/App/lib/core/Gen/CallGenProp.vp +++ b/App/lib/core/Gen/CallGenProp.vp @@ -1,420 +1,413 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import sys -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesFunctions as HandlesFunctions -import lib.core.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.CompilerFactory as CompilerFactory - - -import lib.core.Gen.CallGenBase as CallGenBase - -# ============================================================ -# CallGenProp - CallGenMixin 拆分(阶段 B):属性访问(getter/setter/deleter / 静态类调用 / list 内置方法) -# -# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class CallGenProp(CallGenBase.CallGenBase): - """属性访问(getter/setter/deleter / 静态类调用 / list 内置方法)""" - - # ============================================================ - # _ensure_method_declare - 为跨模块方法调用创建 declare 声明 - # - # 当 found_func 为 None(stub 未注入或跨模块调用)时, - # 在当前模块中创建函数声明,避免 llc 报 undefined value。 - # ============================================================ - - # ============================================================ - # 属性方法(@property/@x.setter/@x.deleter)与静态/类方法调用辅助 - # - # 元数据表由 HandlesClassDef 在类翻译/预注册阶段填充, - # 这里负责把 obj.prop / obj.prop=v / del obj.prop / Class.method() - # 翻译为对应的 {sha1}.ClassName.prop 系列函数调用。 - # ============================================================ - - # ============================================================ - # _translate_property_call — 翻译属性方法调用 - # - # 与 _translate_method_call 的调用名/返回类型解析逻辑一致: - # 1. 优先用模块中已有的函数(精确/后缀匹配,来自 stub 注入) - # 2. 否则用类所属模块的 SHA1 构造 "{sha1}.ClassName.method" 调用名 - # 3. 返回类型:函数实类型 → text.ll 查找 → 按方法名推断(默认 i32) - # - # call_head/call_count: 已构建好的参数链表(如 getter 只有 obj 一个参数) - # ============================================================ - def _translate_property_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, - method_name: str, - call_head: llvmlite.Value | t.CPtr, - call_count: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """翻译属性/静态方法调用,返回 call 结果 Value""" - if pool is None or builder is None or class_name is None or method_name is None: - return None - - # 构造查找名: ClassName.method_name - lookup_name: str = pool.alloc(128) - if lookup_name is None: - return None - viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name) - - # 查找函数(精确/后缀匹配) - found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, lookup_name) - - # 确定调用名 - call_name: str = lookup_name - if found_func is not None: - found_name: str = llvmlite.function_get_name(found_func) - if found_name is not None: - call_name = found_name - else: - # 未找到:用类所属模块的 SHA1 构造调用名 - cls_sha1_pc: str = HandlesStruct.get_struct_sha1(class_name) - if cls_sha1_pc is not None: - mlen_pc: t.CSizeT = string.strlen(cls_sha1_pc) + string.strlen(lookup_name) + 2 - mangled_pc: str = pool.alloc(mlen_pc) - if mangled_pc is not None: - viperlib.snprintf(mangled_pc, mlen_pc, "%s.%s", cls_sha1_pc, lookup_name) - call_name = mangled_pc - - # 确定返回类型 - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - call_ret_ty: llvmlite.LLVMType | t.CPtr = i32_ty - if found_func is not None: - frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) - if frt is not None: - call_ret_ty = frt - else: - sp_ty1: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty(pool, class_name, method_name) - if sp_ty1 is not None: - call_ret_ty = sp_ty1 - else: - cls_sha1_rt: str = HandlesStruct.get_struct_sha1(class_name) - looked_up_ty: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL( - pool, cls_sha1_rt, class_name, method_name) - if looked_up_ty is not None: - call_ret_ty = looked_up_ty - else: - # 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单) - vpi_ret_ty: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi( - pool, cls_sha1_rt, class_name, method_name) - if vpi_ret_ty is not None: - call_ret_ty = vpi_ret_ty - else: - # Phase A 依赖未就绪(cls_sha1_rt None / 定义模块 text.ll 未生成): - # 标记 pending 下遍重译(对齐 _translate_method_call L4783-4790), - # 绝不 fail-fast 中断多遍收敛;真实错误由收敛检查兜底。 - if cls_sha1_rt is None \ - or self._dep_text_ll_exists(pool, cls_sha1_rt) == 0: - if trans is not None: - trans._deps_pending = 1 - # 依赖未就绪:保持默认 i32(build_call(Void) 返回 None - # 会破坏表达式翻译;pending 文件本遍不写盘,下遍重译) - call_ret_ty = llvmlite.Int32(pool) - else: - call_ret_ty = self._fail_method_ret_ty(method_name) - - # 参数类型对齐:按目标函数声明的参数类型转换实参(与 _translate_method_call - # 一致)。例如 from_long(10) 的 i32 字面量 → i64 形参(v: t.CLong), - # 不转换则 call(i32) 与 declare(i64) 不匹配,llc 报参数类型错误。 - # 目标函数优先用已找到的 found_func,否则按 mangled 调用名查模块 declare。 - tgt_func_pc: llvmlite.Function | t.CPtr = found_func - if tgt_func_pc is None: - tgt_func_pc = self.find_func_in_module(mod, call_name) - if tgt_func_pc is not None: - prev_pc: llvmlite.Value | t.CPtr = None - cur_arg_pc: llvmlite.Value | t.CPtr = call_head - cur_param_pc: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(tgt_func_pc) - while cur_arg_pc is not None and cur_param_pc is not None: - param_ty_pc: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_pc) - if param_ty_pc is not None and cur_arg_pc.Ty is not None: - coerced_pc: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( - builder, cur_arg_pc, param_ty_pc) - if coerced_pc is not None and coerced_pc != cur_arg_pc: - # 保持链表完整性:新 Value 继承原节点的 Next,前驱指向新节点 - llvmlite.value_set_next(coerced_pc, cur_arg_pc.Next) - if prev_pc is None: - call_head = coerced_pc - else: - llvmlite.value_set_next(prev_pc, coerced_pc) - cur_arg_pc = coerced_pc - prev_pc = cur_arg_pc - cur_arg_pc = cur_arg_pc.Next - cur_param_pc = llvmlite.param_get_next(cur_param_pc) - - # 确保 declare 存在,然后调用 - self._ensure_method_declare(pool, mod, call_name, call_ret_ty, call_head, call_count) - return llvmlite.build_call(builder, call_name, call_head, call_count, call_ret_ty, 0) - # ============================================================ - # _resolve_obj_class_name — 解析对象表达式的类名(短名) - # - # 优先从变量注解(AnnotClassName)解析(如 "memhub.MemBuddy" → "MemBuddy"), - # 失败时从 LLVM 类型解析(Ptr(Struct) → 类名)。 - # 供属性访问/赋值/删除识别 property 时使用。 - # ============================================================ - - # ============================================================ - def _resolve_obj_class_name(self, pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - obj_node: ast.AST | t.CPtr) -> str: - """解析对象表达式的类名(短名),失败返回 None""" - if pool is None or trans is None or obj_node is None: - return None - if obj_node.kind() == ast.ASTKind.Name: - obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(obj_node) - if obj_nm.id is not None: - var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, obj_nm.id) - if var_entry is not None and var_entry.AnnotClassName is not None: - annot_val: str = var_entry.AnnotClassName - dot_ptr: str = string.strrchr(annot_val, '.') - if dot_ptr is not None: - return dot_ptr + 1 - return annot_val - return None - # ============================================================ - # _try_property_getter_attr — 尝试将 obj.attr 翻译为 property getter 调用 - # - # 检查 obj 的类是否有 @property/@x.getter 的 attr 方法; - # 若有则生成 call Class.attr(obj) 并返回调用结果 Value;否则返回 None。 - # ============================================================ - - # ============================================================ - def _try_property_getter_attr(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - at_node: ast.Attribute | t.CPtr, - obj_ptr: llvmlite.Value | t.CPtr, - trans: HT.Translator | t.CPtr, - fallback_class_name: str = None) -> llvmlite.Value | t.CPtr: - """尝试 property getter 属性访问,返回调用结果 Value;非 getter 返回 None - - fallback_class_name: 对象表达式非 Name 时从 LLVM 类型解析出的类名兜底。 - """ - if at_node is None or at_node.attr is None or obj_ptr is None or trans is None: - return None - class_name: str = self._resolve_obj_class_name(pool, trans, at_node.value) - if class_name is None: - class_name = fallback_class_name - if class_name is None: - return None - meta: int = HandlesClassDef.lookup_method_meta(class_name, at_node.attr) - if meta & HandlesClassDef.META_PROP_GETTER == 0: - return None - # 单参数调用: obj → getter - llvmlite.value_set_next(obj_ptr, None) - return self._translate_property_call( - pool, builder, mod, class_name, at_node.attr, obj_ptr, 1, trans) - # ============================================================ - # _try_property_setter — 尝试将 obj.attr = v 翻译为 property setter 调用 - # - # 检查 obj 的类是否有 @x.setter 的 attr 方法; - # 若有则生成 call Class.attr$set(obj, v),返回 1;否则返回 0。 - # ============================================================ - - # ============================================================ - def _try_property_setter(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - target_attr: ast.Attribute | t.CPtr, - rhs_val: llvmlite.Value | t.CPtr, - trans: HT.Translator | t.CPtr) -> int: - """尝试 property setter 赋值,返回 1=已处理(生成调用)""" - if pool is None or builder is None or mod is None or trans is None: - return 0 - if target_attr is None or target_attr.attr is None or rhs_val is None: - return 0 - class_name: str = self._resolve_obj_class_name(pool, trans, target_attr.value) - if class_name is None: - return 0 - meta: int = HandlesClassDef.lookup_method_meta(class_name, target_attr.attr) - if meta & HandlesClassDef.META_PROP_SETTER == 0: - return 0 - # 翻译对象值(self 参数) - obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, target_attr.value, None, 0, trans) - if obj_val is None: - return 0 - # 构建参数链表: obj → rhs - llvmlite.value_set_next(obj_val, None) - llvmlite.value_set_next(rhs_val, None) - llvmlite.value_set_next(obj_val, rhs_val) - # setter 函数名带 $set 后缀 - setter_name_buf: str = pool.alloc(128) - if setter_name_buf is None: - return 0 - viperlib.snprintf(setter_name_buf, 128, "%s$set", target_attr.attr) - self._translate_property_call(pool, builder, mod, class_name, - setter_name_buf, obj_val, 2, trans) - return 1 - # ============================================================ - # _try_property_deleter — 尝试将 del obj.attr 翻译为 property deleter 调用 - # - # 检查 obj 的类是否有 @x.deleter 的 attr 方法; - # 若有则生成 call Class.attr$del(obj),返回 1;否则返回 0。 - # ============================================================ - - # ============================================================ - def _try_property_deleter(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - target_attr: ast.Attribute | t.CPtr, - trans: HT.Translator | t.CPtr) -> int: - """尝试 property deleter 删除,返回 1=已处理(生成调用)""" - if pool is None or builder is None or mod is None or trans is None: - return 0 - if target_attr is None or target_attr.attr is None: - return 0 - class_name: str = self._resolve_obj_class_name(pool, trans, target_attr.value) - if class_name is None: - return 0 - meta: int = HandlesClassDef.lookup_method_meta(class_name, target_attr.attr) - if meta & HandlesClassDef.META_PROP_DELETER == 0: - return 0 - # 翻译对象值(self 参数) - obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, target_attr.value, None, 0, trans) - if obj_val is None: - return 0 - llvmlite.value_set_next(obj_val, None) - # deleter 函数名带 $del 后缀 - del_name_buf: str = pool.alloc(128) - if del_name_buf is None: - return 0 - viperlib.snprintf(del_name_buf, 128, "%s$del", target_attr.attr) - self._translate_property_call(pool, builder, mod, class_name, - del_name_buf, obj_val, 1, trans) - return 1 - # ============================================================ - # _translate_static_class_call — 翻译 ClassName.method(args) 静态/类方法调用 - # - # @staticmethod: 直接 call Class.method(args...),无 self - # @classmethod: 在参数前插入栈上分配的类实例指针(与 TPC 一致) - # ============================================================ - - # ============================================================ - def _translate_static_class_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, - method_name: str, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """翻译类名静态/类方法调用,返回 call 结果 Value;非静态/类方法返回 None""" - if pool is None or builder is None or mod is None or trans is None: - return None - if class_name is None or method_name is None or cl is None: - return None - meta: int = HandlesClassDef.lookup_method_meta(class_name, method_name) - is_static: int = 0 - is_class: int = 0 - if meta & HandlesClassDef.META_STATIC != 0: - is_static = 1 - if meta & HandlesClassDef.META_CLASS != 0: - is_class = 1 - if is_static == 0 and is_class == 0: - return None - - # 构建参数链表 - head: llvmlite.Value | t.CPtr = None - total_count: int = 0 - - # @classmethod: 插入栈上分配的类实例指针作为 cls 参数 - if is_class != 0: - struct_ty_cc: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(class_name) - if struct_ty_cc is None: - return None - cls_ptr: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty_cc) - if cls_ptr is None: - return None - llvmlite.value_set_next(cls_ptr, None) - head = cls_ptr - total_count = 1 - - # 翻译调用参数 - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - can: t.CSizeT = 0 - if cargs is not None: - can = len(cargs) - tail: llvmlite.Value | t.CPtr = head - for ai in range(can): - arg_node: ast.AST | t.CPtr = cargs.get(ai) - if arg_node is None: - continue - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg_node, None, 0, trans) - if arg_val is None: - continue - llvmlite.value_set_next(arg_val, None) - if head is None: - head = arg_val - tail = arg_val - else: - llvmlite.value_set_next(tail, arg_val) - tail = arg_val - total_count += 1 - - # 零参 @staticmethod(如 PyListObj.new()):head 保持 None 是合法的 - # 无参调用,照常走 _translate_property_call(SHA1 前缀名 + 精确返回类型)。 - # 若此处 return None,调用方回退通用路径把方法名当裸函数解析,生成 - # call i32 @new() → 链接 undefined reference(CPythonTest 根因)。 - # @classmethod 恒有 cls_ptr(head 非 None),不受影响。 - return self._translate_property_call(pool, builder, mod, class_name, - method_name, head, total_count, trans) - # ============================================================ - # _is_list_builtin_method - 判断是否是 list 泛型内置容器方法 - # - # list[T] 是内置泛型容器(_list.vp),其方法(append/get/set/pop/clear/ - # __iter__/__len__/__getitem__/__setitem__)由 translate_call 的 list - # 内置分支内联 GEP 处理,不注册为方法函数。若 obj.method() 检测把 - # list 特化 struct(如 list[AST | CPtr])误当普通结构体走 - # _translate_method_call,会查不到 append 返回类型 → fail-fast - # (NewAstTest body.append 根因)。此判断用于跳过 method_call 路径。 - # - # 返回: 1=list 内置方法(应落到 list 内置分支),0=普通方法 - # ============================================================ - - # ============================================================ - def _is_list_builtin_method(self, class_name: str, - method_name: str) -> int: - """判断 (class_name, method_name) 是否是 list 泛型内置方法""" - if class_name is None or method_name is None: - return 0 - # 类名必须以 "list" 开头(list / list[AST | CPtr] 特化名) - if string.strncmp(class_name, "list", 4) != 0: - return 0 - # 方法名必须是 list 内置方法集合 - if string.strcmp(method_name, "append") == 0: return 1 - if string.strcmp(method_name, "get") == 0: return 1 - if string.strcmp(method_name, "set") == 0: return 1 - if string.strcmp(method_name, "pop") == 0: return 1 - if string.strcmp(method_name, "clear") == 0: return 1 - if string.strcmp(method_name, "__iter__") == 0: return 1 - if string.strcmp(method_name, "__len__") == 0: return 1 - if string.strcmp(method_name, "__getitem__") == 0: return 1 - if string.strcmp(method_name, "__setitem__") == 0: return 1 +import lib.core.Gen.GenTypes as GenTypes +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import sys +import viperlib +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.CallGenBase as CallGenBase + +# ============================================================ +# CallGenProp - CallGenMixin 拆分(阶段 B):属性访问(getter/setter/deleter / 静态类调用 / list 内置方法) +# +# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class CallGenProp(CallGenBase.CallGenBase): + """属性访问(getter/setter/deleter / 静态类调用 / list 内置方法)""" + + # ============================================================ + # _ensure_method_declare - 为跨模块方法调用创建 declare 声明 + # + # 当 found_func 为 None(stub 未注入或跨模块调用)时, + # 在当前模块中创建函数声明,避免 llc 报 undefined value。 + # ============================================================ + + # ============================================================ + # 属性方法(@property/@x.setter/@x.deleter)与静态/类方法调用辅助 + # + # 元数据表由 HandlesClassDef 在类翻译/预注册阶段填充, + # 这里负责把 obj.prop / obj.prop=v / del obj.prop / Class.method() + # 翻译为对应的 {sha1}.ClassName.prop 系列函数调用。 + # ============================================================ + + # ============================================================ + # _translate_property_call — 翻译属性方法调用 + # + # 与 _translate_method_call 的调用名/返回类型解析逻辑一致: + # 1. 优先用模块中已有的函数(精确/后缀匹配,来自 stub 注入) + # 2. 否则用类所属模块的 SHA1 构造 "{sha1}.ClassName.method" 调用名 + # 3. 返回类型:函数实类型 → text.ll 查找 → 按方法名推断(默认 i32) + # + # call_head/call_count: 已构建好的参数链表(如 getter 只有 obj 一个参数) + # ============================================================ + def _translate_property_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, + method_name: str, + call_head: llvmlite.Value | t.CPtr, + call_count: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """翻译属性/静态方法调用,返回 call 结果 Value""" + if pool is None or builder is None or class_name is None or method_name is None: + return None + + # 构造查找名: ClassName.method_name + lookup_name: str = pool.alloc(128) + if lookup_name is None: + return None + viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name) + + # 查找函数(精确/后缀匹配) + found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, lookup_name) + + # 确定调用名 + call_name: str = lookup_name + if found_func is not None: + found_name: str = llvmlite.function_get_name(found_func) + if found_name is not None: + call_name = found_name + else: + # 未找到:用类所属模块的 SHA1 构造调用名 + cls_sha1_pc: str = self.Gen.StructGen.get_struct_sha1(class_name) + if cls_sha1_pc is not None: + mlen_pc: t.CSizeT = string.strlen(cls_sha1_pc) + string.strlen(lookup_name) + 2 + mangled_pc: str = pool.alloc(mlen_pc) + if mangled_pc is not None: + viperlib.snprintf(mangled_pc, mlen_pc, "%s.%s", cls_sha1_pc, lookup_name) + call_name = mangled_pc + + # 确定返回类型 + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + call_ret_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if found_func is not None: + frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) + if frt is not None: + call_ret_ty = frt + else: + sp_ty1: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty(pool, class_name, method_name) + if sp_ty1 is not None: + call_ret_ty = sp_ty1 + else: + cls_sha1_rt: str = self.Gen.StructGen.get_struct_sha1(class_name) + looked_up_ty: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL( + pool, cls_sha1_rt, class_name, method_name) + if looked_up_ty is not None: + call_ret_ty = looked_up_ty + else: + # 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单) + vpi_ret_ty: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi( + pool, cls_sha1_rt, class_name, method_name) + if vpi_ret_ty is not None: + call_ret_ty = vpi_ret_ty + else: + # Phase A 依赖未就绪(cls_sha1_rt None / 定义模块 text.ll 未生成): + # 标记 pending 下遍重译(对齐 _translate_method_call L4783-4790), + # 绝不 fail-fast 中断多遍收敛;真实错误由收敛检查兜底。 + if cls_sha1_rt is None \ + or self._dep_text_ll_exists(pool, cls_sha1_rt) == 0: + if trans is not None: + trans._deps_pending = 1 + # 依赖未就绪:保持默认 i32(build_call(Void) 返回 None + # 会破坏表达式翻译;pending 文件本遍不写盘,下遍重译) + call_ret_ty = llvmlite.Int32(pool) + else: + call_ret_ty = self._fail_method_ret_ty(method_name) + + # 参数类型对齐:按目标函数声明的参数类型转换实参(与 _translate_method_call + # 一致)。例如 from_long(10) 的 i32 字面量 → i64 形参(v: t.CLong), + # 不转换则 call(i32) 与 declare(i64) 不匹配,llc 报参数类型错误。 + # 目标函数优先用已找到的 found_func,否则按 mangled 调用名查模块 declare。 + tgt_func_pc: llvmlite.Function | t.CPtr = found_func + if tgt_func_pc is None: + tgt_func_pc = self.find_func_in_module(mod, call_name) + if tgt_func_pc is not None: + prev_pc: llvmlite.Value | t.CPtr = None + cur_arg_pc: llvmlite.Value | t.CPtr = call_head + cur_param_pc: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(tgt_func_pc) + while cur_arg_pc is not None and cur_param_pc is not None: + param_ty_pc: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_pc) + if param_ty_pc is not None and cur_arg_pc.Ty is not None: + coerced_pc: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type( + builder, cur_arg_pc, param_ty_pc) + if coerced_pc is not None and coerced_pc != cur_arg_pc: + # 保持链表完整性:新 Value 继承原节点的 Next,前驱指向新节点 + llvmlite.value_set_next(coerced_pc, cur_arg_pc.Next) + if prev_pc is None: + call_head = coerced_pc + else: + llvmlite.value_set_next(prev_pc, coerced_pc) + cur_arg_pc = coerced_pc + prev_pc = cur_arg_pc + cur_arg_pc = cur_arg_pc.Next + cur_param_pc = llvmlite.param_get_next(cur_param_pc) + + # 确保 declare 存在,然后调用 + self._ensure_method_declare(pool, mod, call_name, call_ret_ty, call_head, call_count) + return llvmlite.build_call(builder, call_name, call_head, call_count, call_ret_ty, 0) + # ============================================================ + # _resolve_obj_class_name — 解析对象表达式的类名(短名) + # + # 优先从变量注解(AnnotClassName)解析(如 "memhub.MemBuddy" → "MemBuddy"), + # 失败时从 LLVM 类型解析(Ptr(Struct) → 类名)。 + # 供属性访问/赋值/删除识别 property 时使用。 + # ============================================================ + + # ============================================================ + def _resolve_obj_class_name(self, pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr, + obj_node: ast.AST | t.CPtr) -> str: + """解析对象表达式的类名(短名),失败返回 None""" + if pool is None or trans is None or obj_node is None: + return None + if obj_node.kind() == ast.ASTKind.Name: + obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(obj_node) + if obj_nm.id is not None: + var_entry: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, obj_nm.id) + if var_entry is not None and var_entry.AnnotClassName is not None: + annot_val: str = var_entry.AnnotClassName + dot_ptr: str = string.strrchr(annot_val, '.') + if dot_ptr is not None: + return dot_ptr + 1 + return annot_val + return None + # ============================================================ + # _try_property_getter_attr — 尝试将 obj.attr 翻译为 property getter 调用 + # + # 检查 obj 的类是否有 @property/@x.getter 的 attr 方法; + # 若有则生成 call Class.attr(obj) 并返回调用结果 Value;否则返回 None。 + # ============================================================ + + # ============================================================ + def _try_property_getter_attr(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + at_node: ast.Attribute | t.CPtr, + obj_ptr: llvmlite.Value | t.CPtr, + trans: HT.Translator | t.CPtr, + fallback_class_name: str = None) -> llvmlite.Value | t.CPtr: + """尝试 property getter 属性访问,返回调用结果 Value;非 getter 返回 None + + fallback_class_name: 对象表达式非 Name 时从 LLVM 类型解析出的类名兜底。 + """ + if at_node is None or at_node.attr is None or obj_ptr is None or trans is None: + return None + class_name: str = self._resolve_obj_class_name(pool, trans, at_node.value) + if class_name is None: + class_name = fallback_class_name + if class_name is None: + return None + meta: int = self.Gen.ClassGenBase.lookup_method_meta(class_name, at_node.attr) + if meta & GenTypes.META_PROP_GETTER == 0: + return None + # 单参数调用: obj → getter + llvmlite.value_set_next(obj_ptr, None) + return self._translate_property_call( + pool, builder, mod, class_name, at_node.attr, obj_ptr, 1, trans) + # ============================================================ + # _try_property_setter — 尝试将 obj.attr = v 翻译为 property setter 调用 + # + # 检查 obj 的类是否有 @x.setter 的 attr 方法; + # 若有则生成 call Class.attr$set(obj, v),返回 1;否则返回 0。 + # ============================================================ + + # ============================================================ + def _try_property_setter(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + target_attr: ast.Attribute | t.CPtr, + rhs_val: llvmlite.Value | t.CPtr, + trans: HT.Translator | t.CPtr) -> int: + """尝试 property setter 赋值,返回 1=已处理(生成调用)""" + if pool is None or builder is None or mod is None or trans is None: + return 0 + if target_attr is None or target_attr.attr is None or rhs_val is None: + return 0 + class_name: str = self._resolve_obj_class_name(pool, trans, target_attr.value) + if class_name is None: + return 0 + meta: int = self.Gen.ClassGenBase.lookup_method_meta(class_name, target_attr.attr) + if meta & GenTypes.META_PROP_SETTER == 0: + return 0 + # 翻译对象值(self 参数) + obj_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, target_attr.value, None, 0, trans) + if obj_val is None: + return 0 + # 构建参数链表: obj → rhs + llvmlite.value_set_next(obj_val, None) + llvmlite.value_set_next(rhs_val, None) + llvmlite.value_set_next(obj_val, rhs_val) + # setter 函数名带 $set 后缀 + setter_name_buf: str = pool.alloc(128) + if setter_name_buf is None: + return 0 + viperlib.snprintf(setter_name_buf, 128, "%s$set", target_attr.attr) + self._translate_property_call(pool, builder, mod, class_name, + setter_name_buf, obj_val, 2, trans) + return 1 + # ============================================================ + # _try_property_deleter — 尝试将 del obj.attr 翻译为 property deleter 调用 + # + # 检查 obj 的类是否有 @x.deleter 的 attr 方法; + # 若有则生成 call Class.attr$del(obj),返回 1;否则返回 0。 + # ============================================================ + + # ============================================================ + def _try_property_deleter(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + target_attr: ast.Attribute | t.CPtr, + trans: HT.Translator | t.CPtr) -> int: + """尝试 property deleter 删除,返回 1=已处理(生成调用)""" + if pool is None or builder is None or mod is None or trans is None: + return 0 + if target_attr is None or target_attr.attr is None: + return 0 + class_name: str = self._resolve_obj_class_name(pool, trans, target_attr.value) + if class_name is None: + return 0 + meta: int = self.Gen.ClassGenBase.lookup_method_meta(class_name, target_attr.attr) + if meta & GenTypes.META_PROP_DELETER == 0: + return 0 + # 翻译对象值(self 参数) + obj_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, target_attr.value, None, 0, trans) + if obj_val is None: + return 0 + llvmlite.value_set_next(obj_val, None) + # deleter 函数名带 $del 后缀 + del_name_buf: str = pool.alloc(128) + if del_name_buf is None: + return 0 + viperlib.snprintf(del_name_buf, 128, "%s$del", target_attr.attr) + self._translate_property_call(pool, builder, mod, class_name, + del_name_buf, obj_val, 1, trans) + return 1 + # ============================================================ + # _translate_static_class_call — 翻译 ClassName.method(args) 静态/类方法调用 + # + # @staticmethod: 直接 call Class.method(args...),无 self + # @classmethod: 在参数前插入栈上分配的类实例指针(与 TPC 一致) + # ============================================================ + + # ============================================================ + def _translate_static_class_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, + method_name: str, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """翻译类名静态/类方法调用,返回 call 结果 Value;非静态/类方法返回 None""" + if pool is None or builder is None or mod is None or trans is None: + return None + if class_name is None or method_name is None or cl is None: + return None + meta: int = self.Gen.ClassGenBase.lookup_method_meta(class_name, method_name) + is_static: int = 0 + is_class: int = 0 + if meta & GenTypes.META_STATIC != 0: + is_static = 1 + if meta & GenTypes.META_CLASS != 0: + is_class = 1 + if is_static == 0 and is_class == 0: + return None + + # 构建参数链表 + head: llvmlite.Value | t.CPtr = None + total_count: int = 0 + + # @classmethod: 插入栈上分配的类实例指针作为 cls 参数 + if is_class != 0: + struct_ty_cc: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type(class_name) + if struct_ty_cc is None: + return None + cls_ptr: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty_cc) + if cls_ptr is None: + return None + llvmlite.value_set_next(cls_ptr, None) + head = cls_ptr + total_count = 1 + + # 翻译调用参数 + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + can: t.CSizeT = 0 + if cargs is not None: + can = len(cargs) + tail: llvmlite.Value | t.CPtr = head + for ai in range(can): + arg_node: ast.AST | t.CPtr = cargs.get(ai) + if arg_node is None: + continue + arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg_node, None, 0, trans) + if arg_val is None: + continue + llvmlite.value_set_next(arg_val, None) + if head is None: + head = arg_val + tail = arg_val + else: + llvmlite.value_set_next(tail, arg_val) + tail = arg_val + total_count += 1 + + # 零参 @staticmethod(如 PyListObj.new()):head 保持 None 是合法的 + # 无参调用,照常走 _translate_property_call(SHA1 前缀名 + 精确返回类型)。 + # 若此处 return None,调用方回退通用路径把方法名当裸函数解析,生成 + # call i32 @new() → 链接 undefined reference(CPythonTest 根因)。 + # @classmethod 恒有 cls_ptr(head 非 None),不受影响。 + return self._translate_property_call(pool, builder, mod, class_name, + method_name, head, total_count, trans) + # ============================================================ + # _is_list_builtin_method - 判断是否是 list 泛型内置容器方法 + # + # list[T] 是内置泛型容器(_list.vp),其方法(append/get/set/pop/clear/ + # __iter__/__len__/__getitem__/__setitem__)由 translate_call 的 list + # 内置分支内联 GEP 处理,不注册为方法函数。若 obj.method() 检测把 + # list 特化 struct(如 list[AST | CPtr])误当普通结构体走 + # _translate_method_call,会查不到 append 返回类型 → fail-fast + # (NewAstTest body.append 根因)。此判断用于跳过 method_call 路径。 + # + # 返回: 1=list 内置方法(应落到 list 内置分支),0=普通方法 + # ============================================================ + + # ============================================================ + def _is_list_builtin_method(self, class_name: str, + method_name: str) -> int: + """判断 (class_name, method_name) 是否是 list 泛型内置方法""" + if class_name is None or method_name is None: + return 0 + # 类名必须以 "list" 开头(list / list[AST | CPtr] 特化名) + if string.strncmp(class_name, "list", 4) != 0: + return 0 + # 方法名必须是 list 内置方法集合 + if string.strcmp(method_name, "append") == 0: return 1 + if string.strcmp(method_name, "get") == 0: return 1 + if string.strcmp(method_name, "set") == 0: return 1 + if string.strcmp(method_name, "pop") == 0: return 1 + if string.strcmp(method_name, "clear") == 0: return 1 + if string.strcmp(method_name, "__iter__") == 0: return 1 + if string.strcmp(method_name, "__len__") == 0: return 1 + if string.strcmp(method_name, "__getitem__") == 0: return 1 + if string.strcmp(method_name, "__setitem__") == 0: return 1 return 0 \ No newline at end of file diff --git a/App/lib/core/Gen/CallGenVa.vp b/App/lib/core/Gen/CallGenVa.vp index e80e0cd..5b66a5f 100644 --- a/App/lib/core/Gen/CallGenVa.vp +++ b/App/lib/core/Gen/CallGenVa.vp @@ -1,334 +1,326 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import sys -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesFunctions as HandlesFunctions -import lib.core.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.CompilerFactory as CompilerFactory - - -import lib.core.Gen.CallGenBase as CallGenBase - -# ============================================================ -# CallGenVa - CallGenMixin 拆分(阶段 B):va_arg 变长参数(start/arg/end / 变长调用提升) -# -# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class CallGenVa(CallGenBase.CallGenBase): - """va_arg 变长参数(start/arg/end / 变长调用提升)""" - - # ============================================================ - # _func_has_eh_params - 被调函数签名是否含 try-except EH 输出参数 - # - # EH 参数(%__eh_msg_out__/__eh_code_out__)由 translate_function_def/ - # _translate_method 在含 raise 的函数签名末尾注入(main 除外)。 - # ============================================================ - - def _va_arg_get_alloca_ptr(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - arg_node: ast.AST | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """获取 va_list 变量的 alloca 指针(不 load) - - va_arg/va_start/va_end 需要的是 va_list 对象的地址(alloca 指针), - 而非 va_list 的值。若 arg_node 是 Name,查符号表获取 alloca; - 否则用 translate_value 翻译(调用者负责确保传入的是指针)。 - """ - if arg_node is None: - return None - # Name 节点:直接查符号表获取 alloca 指针(不 load) - if arg_node.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg_node) - if nm.id is not None: - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is not None: - return alloca - # 回退:translate_value(可能返回 load 后的值,仅适用于已是指针的情况) - return HandlesExpr.translate_value(builder, pool, mod, arg_node, funcs_ptr, func_count, trans) - def _resolve_va_arg_type(self, pool: memhub.MemBuddy | t.CPtr, - type_node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.LLVMType | t.CPtr: - """解析 va_arg/arg 的类型参数为 LLVMType - - 支持的类型表达式: - t.CInt / t.CInt32T → i32 - t.CInt64T → i64 - t.CDouble → double - t.CPtr / str → i8* - str / bytes → i8* - 无类型参数时默认 i32(vsnprintf 中 va_arg(ap) 常用于读取 i32) - """ - if type_node is None: - return llvmlite.Int32(pool) - # 使用 HandlesType.resolve_annotation_type 解析类型表达式 - resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, type_node, trans._imported_modules, trans._from_imports, trans) - if resolved is not None: - return resolved - # 类型节点存在但解析失败:fail-fast,绝不回退 i32(会按错宽度读变参槽位) - HandlesType.fatal_error(type_node, "va_arg 类型解析失败", "TypeError") - return llvmlite.Int32(pool) - def _translate_va_arg_sugar(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """va_arg(ap, type) / va_arg(ap) → %N = va_arg , - - 生成 LLVM va_arg 指令,从 va_list 读取下一个变长参数。 - """ - if can == 0 or cargs is None: - return llvmlite.const_int32(pool, 0) - - # 第一个参数:va_list(求值为 i8* 地址值,对齐 TPC _HandleVaArgLlvm) - # 当前函数 *args:translate_value 经 vararg 名映射直接返回 va_list 缓冲区地址; - # 转发场景(sprintf → vsnprintf 的 ap 参数):translate_value load 参数得到地址值。 - ap_node: ast.AST | t.CPtr = cargs.get(0) - ap_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, ap_node, None, 0, trans) - if ap_val is None: - return llvmlite.const_int32(pool, 0) - ap_ptr: llvmlite.Value | t.CPtr = ap_val - - # 第二个参数:目标类型(可选,默认 i32) - arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if can >= 2: - type_node: ast.AST | t.CPtr = cargs.get(1) - arg_ty = self._resolve_va_arg_type(pool, type_node, trans) - - # Win64 变参槽位为 8 字节:<64 位整数按 i64 读取(对齐 TPC emit_va_arg L72-73) - read_ty: llvmlite.LLVMType | t.CPtr = arg_ty - abits_va: int = HandlesExpr.get_llvm_type_bits(arg_ty) - if abits_va != 0 and abits_va < 64: - read_ty = llvmlite.Int64(pool) - - # 生成 va_arg 指令 - return llvmlite.build_va_arg(builder, ap_ptr, read_ty) - def _translate_arg_sugar(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """arg(type) → %N = va_arg , - - 使用当前函数的隐式 va_list(trans._va_list_ptr), - 简化 *args 函数体内的 va_arg 调用。 - """ - if trans._va_list_ptr is None: - return llvmlite.const_int32(pool, 0) - - # 第一个参数:目标类型(可选,默认 i32) - arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if can >= 1 and cargs is not None: - type_node: ast.AST | t.CPtr = cargs.get(0) - arg_ty = self._resolve_va_arg_type(pool, type_node, trans) - - # Win64 变参槽位为 8 字节:<64 位整数按 i64 读取(与 _translate_va_arg_sugar 一致) - read_ty: llvmlite.LLVMType | t.CPtr = arg_ty - abits_arg: int = HandlesExpr.get_llvm_type_bits(arg_ty) - if abits_arg != 0 and abits_arg < 64: - read_ty = llvmlite.Int64(pool) - - # 生成 va_arg 指令(使用 trans._va_list_ptr 作为 va_list 地址) - return llvmlite.build_va_arg(builder, trans._va_list_ptr, read_ty) - def _translate_va_start_sugar(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """va_start(ap, last_arg) → call void @llvm.va_start(i8* %ap) - - 初始化 va_list。第二个参数 last_arg 在 LLVM intrinsic 中不使用(C 宏兼容)。 - """ - if can == 0 or cargs is None: - return llvmlite.const_int32(pool, 0) - - # 第一个参数:va_list 指针(获取 alloca,不 load) - ap_node: ast.AST | t.CPtr = cargs.get(0) - ap_ptr: llvmlite.Value | t.CPtr = self._va_arg_get_alloca_ptr( - pool, builder, mod, ap_node, funcs_ptr, func_count, trans) - if ap_ptr is None: - return llvmlite.const_int32(pool, 0) - - # bitcast 到 i8*(@llvm.va_start 接受 i8*) - i8_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_vs) - ap_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_vs) - if ap_i8 is None: - return llvmlite.const_int32(pool, 0) - - void_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) - llvmlite.build_call(builder, "llvm.va_start", ap_i8, 1, void_ty_vs, 0) - return llvmlite.const_int32(pool, 0) - def _translate_va_end_sugar(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """va_end(ap) → call void @llvm.va_end(i8* %ap) - - 清理 va_list。在大多数平台上是 no-op,但调用它是良好的 C ABI 习惯。 - """ - if can == 0 or cargs is None: - return llvmlite.const_int32(pool, 0) - - # 第一个参数:va_list 指针(获取 alloca,不 load) - ap_node: ast.AST | t.CPtr = cargs.get(0) - ap_ptr: llvmlite.Value | t.CPtr = self._va_arg_get_alloca_ptr( - pool, builder, mod, ap_node, funcs_ptr, func_count, trans) - if ap_ptr is None: - return llvmlite.const_int32(pool, 0) - - # bitcast 到 i8*(@llvm.va_end 接受 i8*) - i8_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_ve) - ap_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_ve) - if ap_i8 is None: - return llvmlite.const_int32(pool, 0) - - void_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) - llvmlite.build_call(builder, "llvm.va_end", ap_i8, 1, void_ty_ve, 0) - return llvmlite.const_int32(pool, 0) - def _get_func_fixed_param_count(self, func: llvmlite.Function | t.CPtr) -> int: - """获取函数的固定参数数量(遍历 Params 链表)""" - if func is None: - return 0 - count: int = 0 - param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) - while param is not None: - count += 1 - param = llvmlite.param_get_next(param) - return count - def _check_and_promote_variadic_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - call_name: str, - head: llvmlite.Value | t.CPtr, - can: t.CSizeT, - arg_nodes: list[ast.AST | t.CPtr] | t.CPtr = None, - self_offset: int = 0, - trans: HT.Translator | t.CPtr = None) -> int: - """检查被调用函数是否为变长函数,若是则对变长参数进行 C ABI 提升 - - 返回: is_variadic (1=变长调用, 0=普通调用) - 副作用: 修改 head 链表中超过固定参数数量的节点(C ABI 提升) - - arg_nodes: 实参 AST 链表(不含 self),用于 i8/i16 提升的无符号性判断 - self_offset: Value 链中 self 占用的偏移(方法调用=1,普通函数=0) - trans: 供 _node_type_unsigned 查询变量注解 - """ - if mod is None or call_name is None or head is None: - return 0 - # 查找函数对象 - func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, call_name) - if func is None: - return 0 - if func.IsVarArg != 1: - return 0 - - # 获取固定参数数量 - fixed_count: int = self._get_func_fixed_param_count(func) - - # 无变长参数(实参数量 <= 固定参数数量),仍需 is_variadic=1 - if can <= fixed_count: - return 1 - - # 遍历到第 fixed_count 个节点(固定参数的最后一个) - cur: llvmlite.Value | t.CPtr = head - prev: llvmlite.Value | t.CPtr = None - idx: int = 0 - while cur is not None and idx < fixed_count: - prev = cur - cur = cur.Next - idx += 1 - - # cur 指向第 fixed_count+1 个节点(第一个变长参数) - # 对变长参数进行 C ABI 提升 - i32_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - double_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) - v_idx: int = fixed_count - while cur is not None: - next_node: llvmlite.Value | t.CPtr = cur.Next - promoted: llvmlite.Value | t.CPtr = cur - # C ABI integer promotion: i8/i16 → i32 - arg_bits: int = HandlesExpr.get_llvm_type_bits(cur.Ty) - if arg_bits != 0 and arg_bits < 32: - # 无符号整型(t.CUInt8T/CUInt16T 等)→ zext;有符号/未知 → sext。 - # 修复: printf("%02x", buf[i]) 中 buf[i] 是 CUInt8T,sext 得 - # 0xFFFFFFF3 打印 fffffff3(哈希摘要输出垃圾),应 zext 得 0xF3。 - is_u_va: int = 0 - if arg_nodes is not None and trans is not None: - ast_idx_va: int = v_idx - self_offset - if ast_idx_va >= 0 and ast_idx_va < len(arg_nodes): - an_va: ast.AST | t.CPtr = arg_nodes.get(ast_idx_va) - if an_va is not None: - if HandlesExpr._node_type_unsigned(pool, an_va, trans) != 0: - is_u_va = 1 - if is_u_va != 0: - promoted = llvmlite.build_zext(builder, cur, i32_ty_promote) - else: - # is_u_va 判断失败(arg_nodes/trans 缺失或变量注解查不到)时, - # i8 按系统编程惯例默认 zext(对齐 should_zext_widen 的 - # "i8 → zext(系统编程中 i8 几乎总是无符号字节)"策略), - # 否则 printf("%02x", buf[i]) 中 uint8 字节被 sext 成 - # 0xFFFFFFF3,哈希摘要输出 ffffffXX 垃圾。 - if HandlesExpr.get_llvm_type_bits(cur.Ty) == 8: - promoted = llvmlite.build_zext(builder, cur, i32_ty_promote) - else: - promoted = HandlesExpr.coerce_to_type(builder, cur, i32_ty_promote, None) - if promoted is not None: - promoted.Next = next_node - if prev is not None: - prev.Next = promoted - # C ABI float promotion: float → double - arg_fbits: int = HandlesExpr.get_llvm_float_bits(promoted.Ty) - if arg_fbits != 0 and arg_fbits < 64: - promoted = HandlesExpr.coerce_to_type(builder, promoted, double_ty_promote, None) - if promoted is not None: - promoted.Next = next_node - if prev is not None: - prev.Next = promoted - prev = promoted - cur = next_node - v_idx += 1 - +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import sys +import viperlib +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.CallGenBase as CallGenBase + +# ============================================================ +# CallGenVa - CallGenMixin 拆分(阶段 B):va_arg 变长参数(start/arg/end / 变长调用提升) +# +# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class CallGenVa(CallGenBase.CallGenBase): + """va_arg 变长参数(start/arg/end / 变长调用提升)""" + + # ============================================================ + # _func_has_eh_params - 被调函数签名是否含 try-except EH 输出参数 + # + # EH 参数(%__eh_msg_out__/__eh_code_out__)由 translate_function_def/ + # _translate_method 在含 raise 的函数签名末尾注入(main 除外)。 + # ============================================================ + + def _va_arg_get_alloca_ptr(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + arg_node: ast.AST | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """获取 va_list 变量的 alloca 指针(不 load) + + va_arg/va_start/va_end 需要的是 va_list 对象的地址(alloca 指针), + 而非 va_list 的值。若 arg_node 是 Name,查符号表获取 alloca; + 否则用 translate_value 翻译(调用者负责确保传入的是指针)。 + """ + if arg_node is None: + return None + # Name 节点:直接查符号表获取 alloca 指针(不 load) + if arg_node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg_node) + if nm.id is not None: + alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id) + if alloca is not None: + return alloca + # 回退:translate_value(可能返回 load 后的值,仅适用于已是指针的情况) + return self.Gen.ExprGen.translate_value(builder, pool, mod, arg_node, funcs_ptr, func_count, trans) + def _resolve_va_arg_type(self, pool: memhub.MemBuddy | t.CPtr, + type_node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.LLVMType | t.CPtr: + """解析 va_arg/arg 的类型参数为 LLVMType + + 支持的类型表达式: + t.CInt / t.CInt32T → i32 + t.CInt64T → i64 + t.CDouble → double + t.CPtr / str → i8* + str / bytes → i8* + 无类型参数时默认 i32(vsnprintf 中 va_arg(ap) 常用于读取 i32) + """ + if type_node is None: + return llvmlite.Int32(pool) + # 使用 HandlesType.resolve_annotation_type 解析类型表达式 + resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, type_node, trans._imported_modules, trans._from_imports, trans) + if resolved is not None: + return resolved + # 类型节点存在但解析失败:fail-fast,绝不回退 i32(会按错宽度读变参槽位) + self.Gen.TypeGenErr.fatal_error(type_node, "va_arg 类型解析失败", "TypeError") + return llvmlite.Int32(pool) + def _translate_va_arg_sugar(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """va_arg(ap, type) / va_arg(ap) → %N = va_arg , + + 生成 LLVM va_arg 指令,从 va_list 读取下一个变长参数。 + """ + if can == 0 or cargs is None: + return llvmlite.const_int32(pool, 0) + + # 第一个参数:va_list(求值为 i8* 地址值,对齐 TPC _HandleVaArgLlvm) + # 当前函数 *args:translate_value 经 vararg 名映射直接返回 va_list 缓冲区地址; + # 转发场景(sprintf → vsnprintf 的 ap 参数):translate_value load 参数得到地址值。 + ap_node: ast.AST | t.CPtr = cargs.get(0) + ap_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, ap_node, None, 0, trans) + if ap_val is None: + return llvmlite.const_int32(pool, 0) + ap_ptr: llvmlite.Value | t.CPtr = ap_val + + # 第二个参数:目标类型(可选,默认 i32) + arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if can >= 2: + type_node: ast.AST | t.CPtr = cargs.get(1) + arg_ty = self._resolve_va_arg_type(pool, type_node, trans) + + # Win64 变参槽位为 8 字节:<64 位整数按 i64 读取(对齐 TPC emit_va_arg L72-73) + read_ty: llvmlite.LLVMType | t.CPtr = arg_ty + abits_va: int = self.Gen.ExprGenBase.get_llvm_type_bits(arg_ty) + if abits_va != 0 and abits_va < 64: + read_ty = llvmlite.Int64(pool) + + # 生成 va_arg 指令 + return llvmlite.build_va_arg(builder, ap_ptr, read_ty) + def _translate_arg_sugar(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """arg(type) → %N = va_arg , + + 使用当前函数的隐式 va_list(trans._va_list_ptr), + 简化 *args 函数体内的 va_arg 调用。 + """ + if trans._va_list_ptr is None: + return llvmlite.const_int32(pool, 0) + + # 第一个参数:目标类型(可选,默认 i32) + arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if can >= 1 and cargs is not None: + type_node: ast.AST | t.CPtr = cargs.get(0) + arg_ty = self._resolve_va_arg_type(pool, type_node, trans) + + # Win64 变参槽位为 8 字节:<64 位整数按 i64 读取(与 _translate_va_arg_sugar 一致) + read_ty: llvmlite.LLVMType | t.CPtr = arg_ty + abits_arg: int = self.Gen.ExprGenBase.get_llvm_type_bits(arg_ty) + if abits_arg != 0 and abits_arg < 64: + read_ty = llvmlite.Int64(pool) + + # 生成 va_arg 指令(使用 trans._va_list_ptr 作为 va_list 地址) + return llvmlite.build_va_arg(builder, trans._va_list_ptr, read_ty) + def _translate_va_start_sugar(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """va_start(ap, last_arg) → call void @llvm.va_start(i8* %ap) + + 初始化 va_list。第二个参数 last_arg 在 LLVM intrinsic 中不使用(C 宏兼容)。 + """ + if can == 0 or cargs is None: + return llvmlite.const_int32(pool, 0) + + # 第一个参数:va_list 指针(获取 alloca,不 load) + ap_node: ast.AST | t.CPtr = cargs.get(0) + ap_ptr: llvmlite.Value | t.CPtr = self._va_arg_get_alloca_ptr( + pool, builder, mod, ap_node, funcs_ptr, func_count, trans) + if ap_ptr is None: + return llvmlite.const_int32(pool, 0) + + # bitcast 到 i8*(@llvm.va_start 接受 i8*) + i8_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_vs) + ap_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_vs) + if ap_i8 is None: + return llvmlite.const_int32(pool, 0) + + void_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + llvmlite.build_call(builder, "llvm.va_start", ap_i8, 1, void_ty_vs, 0) + return llvmlite.const_int32(pool, 0) + def _translate_va_end_sugar(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """va_end(ap) → call void @llvm.va_end(i8* %ap) + + 清理 va_list。在大多数平台上是 no-op,但调用它是良好的 C ABI 习惯。 + """ + if can == 0 or cargs is None: + return llvmlite.const_int32(pool, 0) + + # 第一个参数:va_list 指针(获取 alloca,不 load) + ap_node: ast.AST | t.CPtr = cargs.get(0) + ap_ptr: llvmlite.Value | t.CPtr = self._va_arg_get_alloca_ptr( + pool, builder, mod, ap_node, funcs_ptr, func_count, trans) + if ap_ptr is None: + return llvmlite.const_int32(pool, 0) + + # bitcast 到 i8*(@llvm.va_end 接受 i8*) + i8_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_ve) + ap_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_ve) + if ap_i8 is None: + return llvmlite.const_int32(pool, 0) + + void_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + llvmlite.build_call(builder, "llvm.va_end", ap_i8, 1, void_ty_ve, 0) + return llvmlite.const_int32(pool, 0) + def _get_func_fixed_param_count(self, func: llvmlite.Function | t.CPtr) -> int: + """获取函数的固定参数数量(遍历 Params 链表)""" + if func is None: + return 0 + count: int = 0 + param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) + while param is not None: + count += 1 + param = llvmlite.param_get_next(param) + return count + def _check_and_promote_variadic_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + call_name: str, + head: llvmlite.Value | t.CPtr, + can: t.CSizeT, + arg_nodes: list[ast.AST | t.CPtr] | t.CPtr = None, + self_offset: int = 0, + trans: HT.Translator | t.CPtr = None) -> int: + """检查被调用函数是否为变长函数,若是则对变长参数进行 C ABI 提升 + + 返回: is_variadic (1=变长调用, 0=普通调用) + 副作用: 修改 head 链表中超过固定参数数量的节点(C ABI 提升) + + arg_nodes: 实参 AST 链表(不含 self),用于 i8/i16 提升的无符号性判断 + self_offset: Value 链中 self 占用的偏移(方法调用=1,普通函数=0) + trans: 供 _node_type_unsigned 查询变量注解 + """ + if mod is None or call_name is None or head is None: + return 0 + # 查找函数对象 + func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, call_name) + if func is None: + return 0 + if func.IsVarArg != 1: + return 0 + + # 获取固定参数数量 + fixed_count: int = self._get_func_fixed_param_count(func) + + # 无变长参数(实参数量 <= 固定参数数量),仍需 is_variadic=1 + if can <= fixed_count: + return 1 + + # 遍历到第 fixed_count 个节点(固定参数的最后一个) + cur: llvmlite.Value | t.CPtr = head + prev: llvmlite.Value | t.CPtr = None + idx: int = 0 + while cur is not None and idx < fixed_count: + prev = cur + cur = cur.Next + idx += 1 + + # cur 指向第 fixed_count+1 个节点(第一个变长参数) + # 对变长参数进行 C ABI 提升 + i32_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + double_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) + v_idx: int = fixed_count + while cur is not None: + next_node: llvmlite.Value | t.CPtr = cur.Next + promoted: llvmlite.Value | t.CPtr = cur + # C ABI integer promotion: i8/i16 → i32 + arg_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(cur.Ty) + if arg_bits != 0 and arg_bits < 32: + # 无符号整型(t.CUInt8T/CUInt16T 等)→ zext;有符号/未知 → sext。 + # 修复: printf("%02x", buf[i]) 中 buf[i] 是 CUInt8T,sext 得 + # 0xFFFFFFF3 打印 fffffff3(哈希摘要输出垃圾),应 zext 得 0xF3。 + is_u_va: int = 0 + if arg_nodes is not None and trans is not None: + ast_idx_va: int = v_idx - self_offset + if ast_idx_va >= 0 and ast_idx_va < len(arg_nodes): + an_va: ast.AST | t.CPtr = arg_nodes.get(ast_idx_va) + if an_va is not None: + if self.Gen.ExprGenOps._node_type_unsigned(pool, an_va, trans) != 0: + is_u_va = 1 + if is_u_va != 0: + promoted = llvmlite.build_zext(builder, cur, i32_ty_promote) + else: + # is_u_va 判断失败(arg_nodes/trans 缺失或变量注解查不到)时, + # i8 按系统编程惯例默认 zext(对齐 should_zext_widen 的 + # "i8 → zext(系统编程中 i8 几乎总是无符号字节)"策略), + # 否则 printf("%02x", buf[i]) 中 uint8 字节被 sext 成 + # 0xFFFFFFF3,哈希摘要输出 ffffffXX 垃圾。 + if self.Gen.ExprGenBase.get_llvm_type_bits(cur.Ty) == 8: + promoted = llvmlite.build_zext(builder, cur, i32_ty_promote) + else: + promoted = self.Gen.ExprGenBase.coerce_to_type(builder, cur, i32_ty_promote, None) + if promoted is not None: + promoted.Next = next_node + if prev is not None: + prev.Next = promoted + # C ABI float promotion: float → double + arg_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(promoted.Ty) + if arg_fbits != 0 and arg_fbits < 64: + promoted = self.Gen.ExprGenBase.coerce_to_type(builder, promoted, double_ty_promote, None) + if promoted is not None: + promoted.Next = next_node + if prev is not None: + prev.Next = promoted + prev = promoted + cur = next_node + v_idx += 1 + return 1 \ No newline at end of file diff --git a/App/lib/core/Gen/CallGenVt.vp b/App/lib/core/Gen/CallGenVt.vp index c8feb73..69b91b1 100644 --- a/App/lib/core/Gen/CallGenVt.vp +++ b/App/lib/core/Gen/CallGenVt.vp @@ -1,242 +1,231 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import sys -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesFunctions as HandlesFunctions -import lib.core.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.CompilerFactory as CompilerFactory - - -import lib.core.Gen.CallGenBase as CallGenBase -import lib.core.Handles.ExprCallBase as ExprCallBase -import lib.core.Handles.ExprCallHandle as ExprCallHandle - -# ============================================================ -# CallGenVt - CallGenMixin 拆分(阶段 B):vtable 槽位写入 -# -# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class CallGenVt(CallGenBase.CallGenBase): - """vtable 槽位写入""" - - # ============================================================ - # _write_vtable_slot / _write_vtable_attr — vtable 方法槽位直接写入 - # - # serial0_file.open = serial0_open(devfs 驱动注册模式):把模块级函数 - # 指针写入对象 vtable 的方法槽位。vtable 方法不是数据字段(FieldEntry), - # get_attribute_ptr 查不到 → 此前 fatal_error "属性写入失败"。 - # 对齐 TPC HandlesAssign.py L905-949 的写时复制: - # 对象 vtable 仍指向类默认 vtable 时,先复制一份(internal 全局 + - # llvm.memcpy)并让对象指向副本,再 GEP method_index 槽位 store - # 函数指针(i8*)。多次写入互不覆盖(第二次起 vtable 已非默认, - # 跳过复制直接写槽位)。 - # ============================================================ - - # ============================================================ - def _write_vtable_slot(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - obj_ptr: llvmlite.Value | t.CPtr, - class_name: str, - method_index: int, - func_val: llvmlite.Value | t.CPtr, - trans: HT.Translator | t.CPtr) -> int: - """生成 vtable 槽位写入(写时复制),成功返回 1""" - if pool is None or builder is None or mod is None or trans is None: - return 0 - if obj_ptr is None or class_name is None or func_val is None: - return 0 - if method_index < 0 or trans._cur_func is None: - return 0 - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - if i8_ty is None: - return 0 - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - if i8_ptr_ty is None: - return 0 - i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty) - if i8_ptr_ptr_ty is None: - return 0 - method_count: int = HandlesStruct.get_vtable_method_count(class_name) - if method_count <= 0: - return 0 - # 构造 vtable 类型 { i8*, i8*, ... } - vt_first: llvmlite.ParamNode | t.CPtr = None - vt_prev: llvmlite.ParamNode | t.CPtr = None - for vi in range(method_count): - pn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) - if pn is None: - continue - if vt_first is None: - vt_first = pn - if vt_prev is not None: - llvmlite.paramnode_set_next(vt_prev, pn) - vt_prev = pn - vtable_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, vt_first, method_count, None) - if vtable_ty is None: - return 0 - # 对象 vtable 槽位(对象头 → i8**,vtable 指针总是第一个字段) - vtable_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, obj_ptr, i8_ptr_ptr_ty) - if vtable_slot is None: - return 0 - vtable_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i8_ptr_ty, vtable_slot) - if vtable_ptr is None: - return 0 - # 类默认 vtable 地址(比较用) - class_vt: llvmlite.Value | t.CPtr = ExprCallHandle._make_vtable_ref_i8( - pool, builder, mod, class_name, trans) - if class_vt is None: - return 0 - cmp_vt: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_EQ, vtable_ptr, class_vt) - if cmp_vt is None: - return 0 - # 块名唯一化(create_block 不自动编号;同函数多次 vtable 写入(如 - # devfs open/close/read/write 连续赋值)同名 label 冲突) - vtc3: int = trans._label_counter - trans._label_counter = vtc3 + 1 - vt_bb_buf3: str = pool.alloc(64) - if vt_bb_buf3 is None: - return 0 - viperlib.snprintf(vt_bb_buf3, 64, "vt.copy.%d", vtc3) - vt_copy_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, trans._cur_func, vt_bb_buf3) - viperlib.snprintf(vt_bb_buf3, 64, "vt.skip.%d", vtc3) - vt_skip_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, trans._cur_func, vt_bb_buf3) - if vt_copy_bb is None or vt_skip_bb is None: - return 0 - llvmlite.build_cond_br(builder, cmp_vt, vt_copy_bb, vt_skip_bb) - # copy 块:创建 internal 副本全局(zeroinit)+ memcpy + 对象指向副本 - llvmlite.position_at_end(builder, vt_copy_bb) - vtc: int = trans._label_counter - trans._label_counter = vtc + 1 - vcopy_buf: str = pool.alloc(256) - if vcopy_buf is not None: - viperlib.snprintf(vcopy_buf, 256, "%s.vtable.copy.%d", class_name, vtc) - vcopy_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable( - pool, vcopy_buf, vtable_ty) - if vcopy_gv is not None: - llvmlite.module_add_global(mod, vcopy_gv) - vcopy_gv.Linkage = None - vcopy_gv.Initializer = "zeroinitializer" - vcopy_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, llvmlite.Ptr(pool, vtable_ty), vcopy_buf) - if vcopy_ref is not None: - vcopy_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, vcopy_ref, i8_ptr_ty) - if vcopy_i8 is not None: - vt_size: llvmlite.Value | t.CPtr = llvmlite.ConstInt( - pool, llvmlite.Int64(pool), method_count * 8, "vtsz") - if vt_size is not None: - ExprCallBase._emit_llvm_memcpy_intrinsic( - pool, builder, mod, vcopy_i8, class_vt, vt_size) - llvmlite.build_store(builder, vcopy_i8, vtable_slot) - llvmlite.build_br(builder, vt_skip_bb) - # skip 块:reload vtable → GEP 槽位 → store 函数指针(i8*) - llvmlite.position_at_end(builder, vt_skip_bb) - vt_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i8_ptr_ty, vtable_slot) - if vt_ptr2 is None: - return 0 - vt_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, vt_ptr2, llvmlite.Ptr(pool, vtable_ty)) - if vt_typed is None: - return 0 - vt_slotp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, vtable_ty, i8_ptr_ty, vt_typed, method_index) - if vt_slotp is None: - return 0 - fptr_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, func_val, i8_ptr_ty) - if fptr_i8 is not None: - llvmlite.build_store(builder, fptr_i8, vt_slotp) - return 1 - def _write_vtable_attr(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - rhs_val: llvmlite.Value | t.CPtr, - trans: HT.Translator | t.CPtr) -> int: - """属性写入 obj.method = func:检测 vtable 方法并生成槽位写入(成功返回 1)""" - if node is None or builder is None or pool is None or mod is None: - return 0 - if rhs_val is None or trans is None: - return 0 - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at is None or at.value is None or at.attr is None: - return 0 - # 解析类名(AnnotClassName;去模块前缀) - class_nm_v: str = None - if at.value.kind() == ast.ASTKind.Name: - nm_v: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm_v.id is not None: - ve_v: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm_v.id) - if ve_v is not None: - class_nm_v = ve_v.AnnotClassName - elif at.value.kind() == ast.ASTKind.Attribute: - # 跨 Mixin:_resolve_attr_field_class 定义在 ExprGenMixin,经 gen 单例调用 - import lib.core.Gen.Generator as Generator - g_vta: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( - t.CVoid(HandlesExpr._g_gen, t.CPtr)) - if g_vta is not None: - class_nm_v = g_vta._resolve_attr_field_class(pool, trans, at.value) - if class_nm_v is None: - return 0 - fd_dot_v: str = string.strrchr(class_nm_v, '.') - if fd_dot_v is not None: - class_nm_v = fd_dot_v + 1 - if HandlesStruct.get_struct_type(class_nm_v) is None: - return 0 - vm_idx_v: int = HandlesStruct.get_vtable_method_index(class_nm_v, at.attr) - if vm_idx_v < 0: - return 0 - # 解析 obj_ptr(对齐 get_attribute_ptr 前半段:Name 直接查 alloca) - obj_ptr_v: llvmlite.Value | t.CPtr = None - if at.value.kind() == ast.ASTKind.Name: - obj_ptr_v = HandlesVar.lookup_var( - trans.SymTab, ((ast.Name | t.CPtr)(at.value)).id) - else: - obj_ptr_v = HandlesExpr.translate_value( - builder, pool, mod, at.value, None, 0, trans) - if obj_ptr_v is None or obj_ptr_v.Ty is None: - return 0 - # X|t.CPtr 变量(Ptr(Ptr))load 解引用取对象指针 - match obj_ptr_v.Ty: - case llvmlite.LLVMType.Ptr(inner_v): - match inner_v: - case llvmlite.LLVMType.Ptr(_): - obj_ptr_v = llvmlite.build_load(builder, inner_v, obj_ptr_v) - case _: - pass - case _: - pass - if obj_ptr_v is None: - return 0 - return self._write_vtable_slot( +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.Generator as Generator +import lib.core.Gen.ExprGenAttr as ExprGenAttr +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import sys +import viperlib +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.CallGenBase as CallGenBase + +# ============================================================ +# CallGenVt - CallGenMixin 拆分(阶段 B):vtable 槽位写入 +# +# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class CallGenVt(CallGenBase.CallGenBase): + """vtable 槽位写入""" + + # ============================================================ + # _write_vtable_slot / _write_vtable_attr — vtable 方法槽位直接写入 + # + # serial0_file.open = serial0_open(devfs 驱动注册模式):把模块级函数 + # 指针写入对象 vtable 的方法槽位。vtable 方法不是数据字段(FieldEntry), + # get_attribute_ptr 查不到 → 此前 fatal_error "属性写入失败"。 + # 对齐 TPC HandlesAssign.py L905-949 的写时复制: + # 对象 vtable 仍指向类默认 vtable 时,先复制一份(internal 全局 + + # llvm.memcpy)并让对象指向副本,再 GEP method_index 槽位 store + # 函数指针(i8*)。多次写入互不覆盖(第二次起 vtable 已非默认, + # 跳过复制直接写槽位)。 + # ============================================================ + + # ============================================================ + def _write_vtable_slot(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + obj_ptr: llvmlite.Value | t.CPtr, + class_name: str, + method_index: int, + func_val: llvmlite.Value | t.CPtr, + trans: HT.Translator | t.CPtr) -> int: + """生成 vtable 槽位写入(写时复制),成功返回 1""" + if pool is None or builder is None or mod is None or trans is None: + return 0 + if obj_ptr is None or class_name is None or func_val is None: + return 0 + if method_index < 0 or trans._cur_func is None: + return 0 + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + if i8_ty is None: + return 0 + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + if i8_ptr_ty is None: + return 0 + i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty) + if i8_ptr_ptr_ty is None: + return 0 + method_count: int = self.Gen.StructGen.get_vtable_method_count(class_name) + if method_count <= 0: + return 0 + # 构造 vtable 类型 { i8*, i8*, ... } + vt_first: llvmlite.ParamNode | t.CPtr = None + vt_prev: llvmlite.ParamNode | t.CPtr = None + for vi in range(method_count): + pn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) + if pn is None: + continue + if vt_first is None: + vt_first = pn + if vt_prev is not None: + llvmlite.paramnode_set_next(vt_prev, pn) + vt_prev = pn + vtable_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, vt_first, method_count, None) + if vtable_ty is None: + return 0 + # 对象 vtable 槽位(对象头 → i8**,vtable 指针总是第一个字段) + vtable_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, obj_ptr, i8_ptr_ptr_ty) + if vtable_slot is None: + return 0 + vtable_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i8_ptr_ty, vtable_slot) + if vtable_ptr is None: + return 0 + # 类默认 vtable 地址(比较用) + class_vt: llvmlite.Value | t.CPtr = self.Gen.CallGenLeafKit._make_vtable_ref_i8( + pool, builder, mod, class_name, trans) + if class_vt is None: + return 0 + cmp_vt: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_EQ, vtable_ptr, class_vt) + if cmp_vt is None: + return 0 + # 块名唯一化(create_block 不自动编号;同函数多次 vtable 写入(如 + # devfs open/close/read/write 连续赋值)同名 label 冲突) + vtc3: int = trans._label_counter + trans._label_counter = vtc3 + 1 + vt_bb_buf3: str = pool.alloc(64) + if vt_bb_buf3 is None: + return 0 + viperlib.snprintf(vt_bb_buf3, 64, "vt.copy.%d", vtc3) + vt_copy_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, trans._cur_func, vt_bb_buf3) + viperlib.snprintf(vt_bb_buf3, 64, "vt.skip.%d", vtc3) + vt_skip_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, trans._cur_func, vt_bb_buf3) + if vt_copy_bb is None or vt_skip_bb is None: + return 0 + llvmlite.build_cond_br(builder, cmp_vt, vt_copy_bb, vt_skip_bb) + # copy 块:创建 internal 副本全局(zeroinit)+ memcpy + 对象指向副本 + llvmlite.position_at_end(builder, vt_copy_bb) + vtc: int = trans._label_counter + trans._label_counter = vtc + 1 + vcopy_buf: str = pool.alloc(256) + if vcopy_buf is not None: + viperlib.snprintf(vcopy_buf, 256, "%s.vtable.copy.%d", class_name, vtc) + vcopy_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable( + pool, vcopy_buf, vtable_ty) + if vcopy_gv is not None: + llvmlite.module_add_global(mod, vcopy_gv) + vcopy_gv.Linkage = None + vcopy_gv.Initializer = "zeroinitializer" + vcopy_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, llvmlite.Ptr(pool, vtable_ty), vcopy_buf) + if vcopy_ref is not None: + vcopy_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, vcopy_ref, i8_ptr_ty) + if vcopy_i8 is not None: + vt_size: llvmlite.Value | t.CPtr = llvmlite.ConstInt( + pool, llvmlite.Int64(pool), method_count * 8, "vtsz") + if vt_size is not None: + self.Gen.CallGenLib._emit_llvm_memcpy_intrinsic( + pool, builder, mod, vcopy_i8, class_vt, vt_size) + llvmlite.build_store(builder, vcopy_i8, vtable_slot) + llvmlite.build_br(builder, vt_skip_bb) + # skip 块:reload vtable → GEP 槽位 → store 函数指针(i8*) + llvmlite.position_at_end(builder, vt_skip_bb) + vt_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i8_ptr_ty, vtable_slot) + if vt_ptr2 is None: + return 0 + vt_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, vt_ptr2, llvmlite.Ptr(pool, vtable_ty)) + if vt_typed is None: + return 0 + vt_slotp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, vtable_ty, i8_ptr_ty, vt_typed, method_index) + if vt_slotp is None: + return 0 + fptr_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, func_val, i8_ptr_ty) + if fptr_i8 is not None: + llvmlite.build_store(builder, fptr_i8, vt_slotp) + return 1 + def _write_vtable_attr(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + rhs_val: llvmlite.Value | t.CPtr, + trans: HT.Translator | t.CPtr) -> int: + """属性写入 obj.method = func:检测 vtable 方法并生成槽位写入(成功返回 1)""" + if node is None or builder is None or pool is None or mod is None: + return 0 + if rhs_val is None or trans is None: + return 0 + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at is None or at.value is None or at.attr is None: + return 0 + # 解析类名(AnnotClassName;去模块前缀) + class_nm_v: str = None + if at.value.kind() == ast.ASTKind.Name: + nm_v: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm_v.id is not None: + ve_v: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, nm_v.id) + if ve_v is not None: + class_nm_v = ve_v.AnnotClassName + elif at.value.kind() == ast.ASTKind.Attribute: + # 跨 Mixin:_resolve_attr_field_class 定义在 ExprGenAttr,经 self.Gen 调用 + class_nm_v = self.Gen.ExprGenAttr._resolve_attr_field_class(pool, trans, at.value) + if class_nm_v is None: + return 0 + fd_dot_v: str = string.strrchr(class_nm_v, '.') + if fd_dot_v is not None: + class_nm_v = fd_dot_v + 1 + if self.Gen.StructGen.get_struct_type(class_nm_v) is None: + return 0 + vm_idx_v: int = self.Gen.StructGen.get_vtable_method_index(class_nm_v, at.attr) + if vm_idx_v < 0: + return 0 + # 解析 obj_ptr(对齐 get_attribute_ptr 前半段:Name 直接查 alloca) + obj_ptr_v: llvmlite.Value | t.CPtr = None + if at.value.kind() == ast.ASTKind.Name: + obj_ptr_v = self.Gen.VarGen.lookup_var( + trans.SymTab, ((ast.Name | t.CPtr)(at.value)).id) + else: + obj_ptr_v = self.Gen.ExprGen.translate_value( + builder, pool, mod, at.value, None, 0, trans) + if obj_ptr_v is None or obj_ptr_v.Ty is None: + return 0 + # X|t.CPtr 变量(Ptr(Ptr))load 解引用取对象指针 + match obj_ptr_v.Ty: + case llvmlite.LLVMType.Ptr(inner_v): + match inner_v: + case llvmlite.LLVMType.Ptr(_): + obj_ptr_v = llvmlite.build_load(builder, inner_v, obj_ptr_v) + case _: + pass + case _: + pass + if obj_ptr_v is None: + return 0 + return self._write_vtable_slot( pool, builder, mod, obj_ptr_v, class_nm_v, vm_idx_v, rhs_val, trans) \ No newline at end of file diff --git a/App/lib/core/Gen/ClassGenBase.vp b/App/lib/core/Gen/ClassGenBase.vp index dc88c95..78599bf 100644 --- a/App/lib/core/Gen/ClassGenBase.vp +++ b/App/lib/core/Gen/ClassGenBase.vp @@ -1,1119 +1,1161 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import viperlib -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesEnum as HandlesEnum -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.StubMerger as StubMerger -import lib.core.CompilerFactory as CompilerFactory - - -# ============================================================ -# 本地常量(阶段 D 拆分时从 ClassGenMixin 顶层遗漏,补回: -# 方法元数据/类元数据/装饰器/异常表容量与编码;本地副本避免跨模块 CDefine 查找) -# ============================================================ -# 方法元数据 flag 位(对齐 TPC HandlesBase _METHOD_META_*) -META_TLS: t.CDefine = 32 -# 类编译期元数据表容量上限(__provides__/__requires__/__require_must__) -CLASS_META_MAX: t.CDefine = 256 -# 自定义装饰器 wrapper 表容量上限(带 @decor 的函数数) -DECOR_FUNC_MAX: t.CDefine = 64 -# 装饰器表槽内函数名/wrapper 名长度(含 NUL) -DECOR_NAME_LEN: t.CDefine = 128 -# 异常类注册表容量上限(class X(Exception) 自定义异常类) -EXCEPTION_MAX: t.CDefine = 64 -# 异常类表槽内类名/父类名长度(含 NUL) -EXCEPTION_NAME_LEN: t.CDefine = 128 -# 内置异常编码(对齐 TPC HandlesBase.py EXCEPTION_CODE_MAP); -# KeyError=6 IOError=7 OSError=8 AssertionError=9 Exception=99;用户类从 100 起 -BUILTIN_EH_VALUE_ERROR: t.CDefine = 1 -BUILTIN_EH_RUNTIME_ERROR: t.CDefine = 3 -BUILTIN_EH_EXCEPTION: t.CDefine = 99 -EH_USER_CODE_START: t.CDefine = 100 - - -# ============================================================ -# ClassGenBase - ClassGenMixin 拆分(阶段 D):字段 + 方法元数据/异常/继承检测/装饰器(Meta) -# -# 继承 ClassGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesClassDef 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class ClassGenBase: - """字段 + 方法元数据/异常/继承检测/装饰器(Meta)""" - - # --- 方法元数据表(原 _g_method_meta_keys/_g_method_meta_flags/_g_method_meta_count) --- - MethodMetaKeys: bytes - MethodMetaFlags: bytes - MethodMetaCount: int - - # --- REnum 变体表(原 _renum_class_names/_renum_class_variant_counts/ - # _renum_variant_names/_renum_variant_tags/_renum_class_count) --- - RenumClassNames: t.CSizeT | t.CPtr - RenumClassVariantCounts: t.CSizeT | t.CPtr - RenumVariantNames: t.CSizeT | t.CPtr - RenumVariantTags: t.CSizeT | t.CPtr - RenumClassCount: int - - # --- REnum 字段别名表(原 _renum_alias_class/_renum_alias_field/ - # _renum_alias_index/_renum_alias_count) --- - RenumAliasClass: t.CSizeT | t.CPtr - RenumAliasField: t.CSizeT | t.CPtr - RenumAliasIndex: t.CSizeT | t.CPtr - # 变体成员实际 LLVM 类型(对齐 TPC class_members):注册时按注解解析, - # perm_pool 深拷贝持久化。match 绑定用真实成员类型 bitcast 槽位地址 - # (Struct.Name: i8*,否则按槽位 i64 读 → is/subscript/strlen 失败)。 - RenumAliasTy: t.CSizeT | t.CPtr - # 别名所属变体名(perm_pool 拷贝):同一 payload 位置跨变体类型不同 - # (Int.Bits=i32 vs Struct.Fields=Ptr),match 绑定按 (class, 变体, 位置) - # 唯一定位成员类型。 - RenumAliasVariant: t.CSizeT | t.CPtr - RenumAliasCount: int - - # --- 泛型特化缓存(原 _spec_keys/_spec_names/_spec_count) --- - SpecKeys: t.CSizeT | t.CPtr - SpecNames: t.CSizeT | t.CPtr - SpecCount: int - - # --- 类编译期元数据表(__provides__/__requires__/__require_must__) --- - # perm_pool 分配(跨 mark/reset 存活):每槽 kind(4B) + cls(64B) + field(64B) - # FakeDuck:_str.__requires__=['__mbuddy__'] 等(FakeDuck 移植点 1) - ClassMetaKinds: t.CInt | t.CPtr - ClassMetaClss: bytes - ClassMetaFields: bytes - ClassMetaCount: int - - # --- 自定义装饰器 wrapper 表(@log/@skip/@repeat 等 → __decor_wrap_{name}) --- - # perm_pool 分配(跨 mark/reset 存活):每槽函数名(128B) + wrapper 名(128B) - # 对齐 TPC HandlesFunctions.py L1621-1631 的 _decorated_funcs + - # DecoratorPass.py 的 wrapper 生成。调用点重写经 - # lookup_decor_wrapper(translate_call 拦截原函数名 → wrapper 名)。 - DecoratorFuncCount: int - DecoratorFuncNames: bytes - DecoratorWrapNames: bytes - # 装饰器首个常量参数(@repeat(3) 的 3),无参数为 0(每槽 8B,i64) - DecoratorArgs: t.CInt64T | t.CPtr - - # --- 异常类注册表(try-except,对齐 TPC HandlesClassDef.py L47-61) --- - # perm_pool 分配(跨 mark/reset 存活):每槽类名(128B) + 父类名(128B) + 编码(4B) - # 用户异常类编码从 100 递增;内置编码(ValueError=1 等)不在此表 - # (_lookup_exception_code 走内置硬编码)。异常类不生成 struct。 - ExceptionCount: int - ExceptionNames: bytes - ExceptionParents: bytes - ExceptionCodes: t.CInt | t.CPtr - # 下一个待分配的异常编码(用户类,从 100 起) - NextExceptionCode: int - # 递归收集子孙编码用的临时计数(collect_descendant_codes 返回后无效)。 - # 必须与其它字段一起声明在类顶:方法中间的字段注解可能被编译器 - # 当作局部声明处理,破坏 Mixin 布局/this_adjust 对齐。 - _exception_codes_tmp_count: int - - # --- 泛型特化递归深度(泛型循环套用防护) --- - # _specialize_generic_class 进入时 +1、退出时 -1;超过上限立即报错终止 - # (防止 F-bounded 等循环特化把编译变成死循环) - GenericSpecDepth: int - - # --- 泛型模板表(原 HandlesClassDef._generic_class_names/ - # _generic_class_nodes/_generic_class_sha1s) --- - GenericClassNames: list[str] | t.CPtr - GenericClassNodes: list[ast.ClassDef | t.CPtr] | t.CPtr - GenericClassSha1s: list[str] | t.CPtr - # 泛型模板来源文件路径(与上面三表同序)。特化翻译模板方法体时 - # node.lineno 是模板文件行号,若 CurrentFile 仍是调用方文件, - # fatal_error 会把模板行号套到调用方文件上显示错位(如 vector.vp - # 的 T(...) 错报成 vectortest.vp 的 return 0)。此表用于特化期间 - # 临时切换 CurrentFile 到模板文件,翻译完恢复。 - GenericClassFiles: list[str] | t.CPtr - # 泛型模板类型参数名表(与 GenericClassNames 同序,stdlib 深拷贝)。 - # 模板节点 type_params 是 Phase 1 pool 分配的 list,跨 Phase 引用时内容 - # 可能失效(VectorGenericTest 特化 Vector[int].__init__ 的 T.__sizeof__() - # NameError 根因方向);注册时展平深拷贝到 stdlib,特化时从本表恢复。 - # 每槽指向一个空格分隔、NUL 结尾的 stdlib 缓冲区(如 "T" 或 "T K")。 - GenericClassTpParams: t.CSizeT | t.CPtr - - # --- vtable 方法收集表(原 _g_vt_full_names/_g_vt_method_names/ - # _g_vt_parent_sha1s/_g_vt_method_count) --- - VtFullNames: t.CSizeT | t.CPtr - VtMethodNames: t.CSizeT | t.CPtr - VtParentSha1s: t.CSizeT | t.CPtr - VtMethodCount: int - # ============================================================ - # 以下方法由 P5-2 分簇迁移填充(函数体来自 HandlesClassDef.vp, - # 本模块函数调用改 self.,外部模块调用保留模块前缀) - # ============================================================ - - def _is_cenum_base(self, base_node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> int: - """检查 base 节点是否为 t.CEnum,返回 1=是 / 0=否""" - if base_node is None: - return 0 - k: int = base_node.kind() - # Name('CEnum') 形式(from t import CEnum) - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node) - if nm.id is None: - return 0 - if string.strcmp(nm.id, "CEnum") == 0: - return 1 - # 别名形式: from t import CEnum as en; class Color(en) - # 解析别名原始名(en → CEnum)再比较 - if trans is not None and trans._from_imports is not None: - alias_orig: str = HandlesImports.lookup_from_import_original( - trans._from_imports, nm.id) - if alias_orig is not None: - og_len_ce: t.CSizeT = 0 - while alias_orig[og_len_ce] != ' ' and alias_orig[og_len_ce] != '\0': - og_len_ce += 1 - if og_len_ce == 5 and string.strncmp(alias_orig, "CEnum", 5) == 0: - return 1 - return 0 - # Attribute(t.CEnum) 形式 - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_node) - if at.attr is not None and string.strcmp(at.attr, "CEnum") == 0: - return 1 - return 0 - return 0 - def _is_enum_class(self, cd: ast.ClassDef | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> int: - """检查 ClassDef 是否为 CEnum:继承自 t.CEnum 或 @t.CEnum 装饰器形式""" - if cd is None: - return 0 - # 装饰器形式: @t.CEnum class Color:(无基类,等价 class Color(t.CEnum):) - if cd.decorator_list is not None: - if self._has_decorator(cd.decorator_list, "CEnum") == 1: - return 1 - if cd.bases is None: - return 0 - bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases - bn: t.CSizeT = len(bases) - if bn == 0: - return 0 - for bi in range(bn): - base_node: ast.AST | t.CPtr = bases.get(bi) - if base_node is None: - continue - if self._is_cenum_base(base_node, trans) == 1: - return 1 - return 0 - def _is_cunion_base(self, base_node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> int: - """检查 base 节点是否为 t.CUnion,返回 1=是 / 0=否""" - if base_node is None: - return 0 - k: int = base_node.kind() - # Name('CUnion') 形式(from t import CUnion) - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node) - if nm.id is None: - return 0 - if string.strcmp(nm.id, "CUnion") == 0: - return 1 - # 别名形式: from t import CUnion as un; class Data(un) - if trans is not None and trans._from_imports is not None: - alias_orig: str = HandlesImports.lookup_from_import_original( - trans._from_imports, nm.id) - if alias_orig is not None: - og_len_cu: t.CSizeT = 0 - while alias_orig[og_len_cu] != ' ' and alias_orig[og_len_cu] != '\0': - og_len_cu += 1 - if og_len_cu == 6 and string.strncmp(alias_orig, "CUnion", 6) == 0: - return 1 - return 0 - # Attribute(t.CUnion) 形式 - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_node) - if at.attr is not None and string.strcmp(at.attr, "CUnion") == 0: - return 1 - return 0 - return 0 - def _is_union_class(self, cd: ast.ClassDef | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> int: - """检查 ClassDef 是否为 CUnion:继承自 t.CUnion 或 @t.CUnion 装饰器形式""" - if cd is None: - return 0 - # 装饰器形式: @t.CUnion class Data: - if cd.decorator_list is not None: - if self._has_decorator(cd.decorator_list, "CUnion") == 1: - return 1 - if cd.bases is None: - return 0 - bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases - bn: t.CSizeT = len(bases) - if bn == 0: - return 0 - for bi in range(bn): - base_node: ast.AST | t.CPtr = bases.get(bi) - if base_node is None: - continue - if self._is_cunion_base(base_node, trans) == 1: - return 1 - return 0 - def _is_crenum_base(self, base_node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> int: - """检查 base 节点是否为 t.REnum,返回 1=是 / 0=否""" - if base_node is None: - return 0 - k: int = base_node.kind() - # Name('REnum') 形式(from t import REnum) - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node) - if nm.id is None: - return 0 - if string.strcmp(nm.id, "REnum") == 0: - return 1 - # 别名形式: from t import REnum as ren; class Opt(ren) - if trans is not None and trans._from_imports is not None: - alias_orig: str = HandlesImports.lookup_from_import_original( - trans._from_imports, nm.id) - if alias_orig is not None: - og_len_cr: t.CSizeT = 0 - while alias_orig[og_len_cr] != ' ' and alias_orig[og_len_cr] != '\0': - og_len_cr += 1 - if og_len_cr == 5 and string.strncmp(alias_orig, "REnum", 5) == 0: - return 1 - return 0 - # Attribute(t.REnum) 形式 - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_node) - if at.attr is not None and string.strcmp(at.attr, "REnum") == 0: - return 1 - return 0 - return 0 - def _is_renum_class(self, cd: ast.ClassDef | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> int: - """检查 ClassDef 是否为 REnum:继承自 t.REnum 或 @t.REnum 装饰器形式""" - if cd is None: - return 0 - # 装饰器形式: @t.REnum class X: - if cd.decorator_list is not None: - if self._has_decorator(cd.decorator_list, "REnum") == 1: - return 1 - if cd.bases is None: - return 0 - bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases - bn: t.CSizeT = len(bases) - if bn == 0: - return 0 - for bi in range(bn): - base_node: ast.AST | t.CPtr = bases.get(bi) - if base_node is None: - continue - if self._is_crenum_base(base_node, trans) == 1: - return 1 - return 0 - def _has_decorator(self, decorator_list: list[ast.AST | t.CPtr] | t.CPtr, - deco_name: str) -> int: - """检查 decorator_list 中是否有指定装饰器名""" - if decorator_list is None: - return 0 - dn: t.CSizeT = len(decorator_list) - if dn == 0: - return 0 - for di in range(dn): - deco: ast.AST | t.CPtr = decorator_list.get(di) - if deco is None: - continue - k: int = deco.kind() - # @t.NoVTable 形式(Attribute) - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(deco) - if at.attr is not None and string.strcmp(at.attr, deco_name) == 0: - # 检查 value 是 Name('t') - if at.value is not None and at.value.kind() == ast.ASTKind.Name: - vn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if vn.id is not None and string.strcmp(vn.id, "t") == 0: - return 1 - return 0 - # @NoVTable 形式(Name,from t import NoVTable) - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(deco) - if nm.id is not None and string.strcmp(nm.id, deco_name) == 0: - return 1 - return 0 - def _extract_func_meta(self, decorator_list: list[ast.AST | t.CPtr] | t.CPtr) -> int: - """从装饰器列表提取元数据位掩码,返回 0=无装饰器元数据""" - meta: int = 0 - if decorator_list is None: - return meta - dn: t.CSizeT = len(decorator_list) - if dn == 0: - return meta - for di in range(dn): - deco: ast.AST | t.CPtr = decorator_list.get(di) - if deco is None: - continue - k: int = deco.kind() - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(deco) - if nm.id is not None: - if string.strcmp(nm.id, "staticmethod") == 0: - meta |= META_STATIC - elif string.strcmp(nm.id, "property") == 0: - meta |= META_PROP_GETTER - elif string.strcmp(nm.id, "classmethod") == 0: - meta |= META_CLASS - elif string.strcmp(nm.id, "TLS") == 0: - meta |= META_TLS - elif k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(deco) - if at.attr is not None and at.value is not None: - if at.value.kind() == ast.ASTKind.Name: - vn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - is_prop_name: int = 0 - if vn.id is not None and string.strcmp(vn.id, "property") == 0: - is_prop_name = 1 - # @t.TLS 一次性初始化标记(对齐 TPC HandlesFunctions.py - # L1223-1231:value 必须为 Name('t');@TLS 裸名走上面 Name 分支) - if vn.id is not None and string.strcmp(vn.id, "t") == 0 \ - and string.strcmp(at.attr, "TLS") == 0: - meta |= META_TLS - # @property.setter 或 @x.setter/getter/deleter 都识别 - if is_prop_name != 0 or string.strcmp(at.attr, "setter") == 0 \ - or string.strcmp(at.attr, "getter") == 0 or string.strcmp(at.attr, "deleter") == 0: - if string.strcmp(at.attr, "setter") == 0: - meta |= META_PROP_SETTER - elif string.strcmp(at.attr, "getter") == 0: - meta |= META_PROP_GETTER - elif string.strcmp(at.attr, "deleter") == 0: - meta |= META_PROP_DELETER - return meta - def register_class_meta(self, pool: memhub.MemBuddy | t.CPtr, - kind: int, cls: str, field: str) -> int: - """注册类编译期元数据字段(__provides__/__requires__/__require_must__,幂等)""" - if pool is None or cls is None or field is None: - return -1 - if self.ClassMetaKinds is None: - self.ClassMetaKinds = CompilerFactory.get_perm_pool().alloc(CLASS_META_MAX * 4) - self.ClassMetaClss = CompilerFactory.get_perm_pool().alloc(CLASS_META_MAX * 64) - self.ClassMetaFields = CompilerFactory.get_perm_pool().alloc(CLASS_META_MAX * 64) - if self.ClassMetaKinds is None or self.ClassMetaClss is None or self.ClassMetaFields is None: - return -1 - string.memset(self.ClassMetaKinds, 0, CLASS_META_MAX * 4) - string.memset(self.ClassMetaClss, 0, CLASS_META_MAX * 64) - string.memset(self.ClassMetaFields, 0, CLASS_META_MAX * 64) - self.ClassMetaCount = 0 - if self.ClassMetaCount >= CLASS_META_MAX: - return -1 - # 幂等:同 (kind, cls, field) 跳过 - for i in range(self.ClassMetaCount): - if self.ClassMetaKinds[i] == kind: - if string.strcmp(self.ClassMetaClss + i * 64, cls) == 0: - if string.strcmp(self.ClassMetaFields + i * 64, field) == 0: - return 0 - idx_cm: t.CSizeT = t.CSizeT(self.ClassMetaCount) * 64 - self.ClassMetaKinds[self.ClassMetaCount] = kind - string.strncpy(self.ClassMetaClss + idx_cm, cls, 63) - self.ClassMetaClss[idx_cm + 63] = '\0' - string.strncpy(self.ClassMetaFields + idx_cm, field, 63) - self.ClassMetaFields[idx_cm + 63] = '\0' - self.ClassMetaCount += 1 - return 0 - def class_meta_count(self, kind: int, cls: str) -> int: - """返回某类某元数据类型的字段数""" - if self.ClassMetaKinds is None or cls is None: - return 0 - n_cm: int = 0 - for i in range(self.ClassMetaCount): - if self.ClassMetaKinds[i] == kind: - if string.strcmp(self.ClassMetaClss + i * 64, cls) == 0: - n_cm += 1 - return n_cm - def class_meta_field_at(self, kind: int, cls: str, idx: int) -> str: - """返回某类某元数据类型的第 idx 个字段名""" - if self.ClassMetaKinds is None or cls is None: - return None - n_cm2: int = 0 - for i in range(self.ClassMetaCount): - if self.ClassMetaKinds[i] == kind: - if string.strcmp(self.ClassMetaClss + i * 64, cls) == 0: - if n_cm2 == idx: - return self.ClassMetaFields + i * 64 - n_cm2 += 1 - return None - def register_decorator(self, pool: memhub.MemBuddy | t.CPtr, - func_name: str, wrapper_name: str, - arg0: t.CInt64T) -> int: - """注册自定义装饰器函数(@log/@skip/@repeat(3) → __decor_wrap_{name}) - - 对齐 TPC HandlesFunctions.py L1621-1631 的 _decorated_funcs 注册。 - arg0 为装饰器首个常量参数(@repeat(3) 的 3),无参数为 0。 - """ - if pool is None or func_name is None or wrapper_name is None: - return -1 - if self.DecoratorFuncNames is None: - self.DecoratorFuncNames = CompilerFactory.get_perm_pool().alloc( - DECOR_FUNC_MAX * DECOR_NAME_LEN) - self.DecoratorWrapNames = CompilerFactory.get_perm_pool().alloc( - DECOR_FUNC_MAX * DECOR_NAME_LEN) - self.DecoratorArgs = CompilerFactory.get_perm_pool().alloc( - DECOR_FUNC_MAX * 8) - if self.DecoratorFuncNames is None or self.DecoratorWrapNames is None \ - or self.DecoratorArgs is None: - return -1 - string.memset(self.DecoratorFuncNames, 0, DECOR_FUNC_MAX * DECOR_NAME_LEN) - string.memset(self.DecoratorWrapNames, 0, DECOR_FUNC_MAX * DECOR_NAME_LEN) - string.memset(self.DecoratorArgs, 0, DECOR_FUNC_MAX * 8) - self.DecoratorFuncCount = 0 - if self.DecoratorFuncCount >= DECOR_FUNC_MAX: - return -1 - # 幂等:同名函数已注册则跳过(多遍扫描) - for i in range(self.DecoratorFuncCount): - if string.strcmp(self.DecoratorFuncNames + i * DECOR_NAME_LEN, func_name) == 0: - return 0 - idx_dc: t.CSizeT = t.CSizeT(self.DecoratorFuncCount) * DECOR_NAME_LEN - string.strncpy(self.DecoratorFuncNames + idx_dc, func_name, DECOR_NAME_LEN - 1) - self.DecoratorFuncNames[idx_dc + DECOR_NAME_LEN - 1] = '\0' - string.strncpy(self.DecoratorWrapNames + idx_dc, wrapper_name, DECOR_NAME_LEN - 1) - self.DecoratorWrapNames[idx_dc + DECOR_NAME_LEN - 1] = '\0' - self.DecoratorArgs[self.DecoratorFuncCount] = arg0 - self.DecoratorFuncCount += 1 - return 0 - def lookup_decor_wrapper(self, func_name: str) -> str: - """按原函数名查 wrapper 名,未注册返回 None""" - if self.DecoratorFuncNames is None or func_name is None: - return None - for i in range(self.DecoratorFuncCount): - if string.strcmp(self.DecoratorFuncNames + i * DECOR_NAME_LEN, func_name) == 0: - return self.DecoratorWrapNames + i * DECOR_NAME_LEN - return None - def lookup_decor_arg0(self, func_name: str) -> t.CInt64T: - """按原函数名查装饰器首个常量参数(无参数为 0)""" - if self.DecoratorFuncNames is None or func_name is None: - return 0 - for i in range(self.DecoratorFuncCount): - if string.strcmp(self.DecoratorFuncNames + i * DECOR_NAME_LEN, func_name) == 0: - return self.DecoratorArgs[i] - return 0 - # ============================================================ - # 异常类注册表(try-except,对齐 TPC HandlesClassDef.py L47-61) - # ============================================================ - def _ensure_exception_tables(self) -> int: - """懒初始化异常表(perm_pool),返回 0 成功""" - if self.ExceptionNames is not None: - return 0 - pp_e: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool() - if pp_e is None: - return -1 - self.ExceptionNames = pp_e.alloc(EXCEPTION_MAX * EXCEPTION_NAME_LEN) - self.ExceptionParents = pp_e.alloc(EXCEPTION_MAX * EXCEPTION_NAME_LEN) - self.ExceptionCodes = pp_e.alloc(EXCEPTION_MAX * 4) - if self.ExceptionNames is None or self.ExceptionParents is None \ - or self.ExceptionCodes is None: - return -1 - string.memset(self.ExceptionNames, 0, EXCEPTION_MAX * EXCEPTION_NAME_LEN) - string.memset(self.ExceptionParents, 0, EXCEPTION_MAX * EXCEPTION_NAME_LEN) - string.memset(self.ExceptionCodes, 0, EXCEPTION_MAX * 4) - self.ExceptionCount = 0 - self.NextExceptionCode = EH_USER_CODE_START - return 0 - def register_exception(self, class_name: str, parent_name: str) -> int: - """注册用户异常类并分配编码(幂等:同名跳过)。返回编码或 -1""" - if class_name is None: - return -1 - if self._ensure_exception_tables() != 0: - return -1 - # 幂等:已注册则返回既有编码(多遍扫描) - for i in range(self.ExceptionCount): - if string.strcmp(self.ExceptionNames + i * EXCEPTION_NAME_LEN, class_name) == 0: - return self.ExceptionCodes[i] - if self.ExceptionCount >= EXCEPTION_MAX: - return -1 - idx_e: t.CSizeT = t.CSizeT(self.ExceptionCount) * EXCEPTION_NAME_LEN - string.strncpy(self.ExceptionNames + idx_e, class_name, EXCEPTION_NAME_LEN - 1) - self.ExceptionNames[idx_e + EXCEPTION_NAME_LEN - 1] = '\0' - if parent_name is not None: - string.strncpy(self.ExceptionParents + idx_e, parent_name, EXCEPTION_NAME_LEN - 1) - self.ExceptionParents[idx_e + EXCEPTION_NAME_LEN - 1] = '\0' - code_e: int = self.NextExceptionCode - self.NextExceptionCode += 1 - self.ExceptionCodes[self.ExceptionCount] = code_e - self.ExceptionCount += 1 - return code_e - def _builtin_exception_code(self, name: str) -> int: - """内置异常编码(对齐 TPC HandlesBase.py EXCEPTION_CODE_MAP),非内置返回 0""" - if name is None: - return 0 - if string.strcmp(name, "ValueError") == 0: return 1 - if string.strcmp(name, "TypeError") == 0: return 2 - if string.strcmp(name, "RuntimeError") == 0: return 3 - if string.strcmp(name, "ZeroDivisionError") == 0: return 4 - if string.strcmp(name, "IndexError") == 0: return 5 - if string.strcmp(name, "KeyError") == 0: return 6 - if string.strcmp(name, "IOError") == 0: return 7 - if string.strcmp(name, "OSError") == 0: return 8 - if string.strcmp(name, "AssertionError") == 0: return 9 - if string.strcmp(name, "Exception") == 0: return 99 - return 0 - def lookup_exception_code(self, name: str) -> int: - """查异常编码:内置表优先,其次用户异常表,都未命中返回 0""" - if name is None: - return 0 - bi: int = self._builtin_exception_code(name) - if bi != 0: - return bi - if self.ExceptionNames is None: - return 0 - for i in range(self.ExceptionCount): - if string.strcmp(self.ExceptionNames + i * EXCEPTION_NAME_LEN, name) == 0: - return self.ExceptionCodes[i] - return 0 - def lookup_exception_parent(self, name: str) -> str: - """查用户异常类的父类名,非用户异常返回 None""" - if name is None or self.ExceptionNames is None: - return None - for i in range(self.ExceptionCount): - if string.strcmp(self.ExceptionNames + i * EXCEPTION_NAME_LEN, name) == 0: - p_e: str = self.ExceptionParents + i * EXCEPTION_NAME_LEN - if p_e is not None and p_e[0] != '\0': - return p_e - return None - return None - def is_exception_name(self, name: str) -> int: - """name 是否是内置或用户异常类名(1=是 / 0=否)""" - if name is None: - return 0 - if self._builtin_exception_code(name) != 0: - return 1 - if self.ExceptionNames is None: - return 0 - for i in range(self.ExceptionCount): - if string.strcmp(self.ExceptionNames + i * EXCEPTION_NAME_LEN, name) == 0: - return 1 - return 0 - def collect_descendant_codes(self, name: str, out_codes: t.CInt | t.CPtr, - max_codes: int) -> int: - """把 name 及其所有子孙异常类的编码收集到 out_codes,返回数量 - (对齐 TPC HandlesTry.py _get_all_match_codes/_collect_descendant_codes: - 编译期静态展开继承树,except X 匹配 X 及全部子孙)。""" - if name is None or out_codes is None: - return 0 - self._exception_codes_tmp_count = 0 - self._collect_desc_codes_rec(name, out_codes, max_codes, 0) - return self._exception_codes_tmp_count - def _collect_desc_codes_rec(self, name: str, out_codes: t.CInt | t.CPtr, - max_codes: int, depth: int) -> None: - """递归收集 name 编码 + 全部子孙编码(BFS 语义对齐 TPC)""" - if depth > 32: - return - code_e: int = self.lookup_exception_code(name) - if code_e != 0 and self._exception_codes_tmp_count < max_codes: - # 去重(继承环防护) - dup: int = 0 - for i in range(self._exception_codes_tmp_count): - if out_codes[i] == code_e: - dup = 1 - break - if dup == 0: - out_codes[self._exception_codes_tmp_count] = code_e - self._exception_codes_tmp_count += 1 - # 遍历全部用户异常,找以 name 为父类的子类递归收集 - if self.ExceptionNames is None: - return - for i in range(self.ExceptionCount): - cname_e: str = self.ExceptionNames + i * EXCEPTION_NAME_LEN - pname_e: str = self.ExceptionParents + i * EXCEPTION_NAME_LEN - if pname_e is not None and pname_e[0] != '\0': - if string.strcmp(pname_e, name) == 0: - self._collect_desc_codes_rec(cname_e, out_codes, max_codes, depth + 1) - def _is_exception_class_def(self, cd: ast.ClassDef | t.CPtr) -> int: - """类定义是否是异常类:基类是 Exception 或已注册异常类(1=是)""" - if cd is None or cd.bases is None: - return 0 - bases_e: list[ast.AST | t.CPtr] | t.CPtr = cd.bases - bn_e: t.CSizeT = len(bases_e) - for bi_e in range(bn_e): - base_e: ast.AST | t.CPtr = bases_e.get(bi_e) - if base_e is None: - continue - base_name_e: str = None - if base_e.kind() == ast.ASTKind.Name: - base_name_e = ((ast.Name | t.CPtr)(base_e)).id - elif base_e.kind() == ast.ASTKind.Attribute: - base_at_e: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_e) - if base_at_e.attr is not None: - base_name_e = base_at_e.attr - if base_name_e is None: - continue - if string.strcmp(base_name_e, "Exception") == 0: - return 1 - if self.is_exception_name(base_name_e) != 0: - return 1 - return 0 - def _get_exception_parent_name(self, cd: ast.ClassDef | t.CPtr) -> str: - """返回异常类定义的真实父类名(第一个非 Exception 的已注册异常类),无则 None""" - if cd is None or cd.bases is None: - return None - bases_e2: list[ast.AST | t.CPtr] | t.CPtr = cd.bases - bn_e2: t.CSizeT = len(bases_e2) - for bi_e2 in range(bn_e2): - base_e2: ast.AST | t.CPtr = bases_e2.get(bi_e2) - if base_e2 is None: - continue - base_name_e2: str = None - if base_e2.kind() == ast.ASTKind.Name: - base_name_e2 = ((ast.Name | t.CPtr)(base_e2)).id - elif base_e2.kind() == ast.ASTKind.Attribute: - base_at_e2: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_e2) - if base_at_e2.attr is not None: - base_name_e2 = base_at_e2.attr - if base_name_e2 is None: - continue - if string.strcmp(base_name_e2, "Exception") != 0 \ - and self.is_exception_name(base_name_e2) != 0: - return base_name_e2 - return None - def _register_exception_class_def(self, trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr) -> int: - """注册异常类(分配编码 + 记录父类),不生成 struct,返回 0""" - if cd is None or cd.name is None: - return 0 - parent_e: str = self._get_exception_parent_name(cd) - self.register_exception(cd.name, parent_e) - return 0 - def _register_class_meta_list(self, pool: memhub.MemBuddy | t.CPtr, - kind: int, cls: str, value_node: ast.AST | t.CPtr) -> None: - """解析类体 __provides__/__requires__ 的 list[str] 字面量并注册""" - if value_node is None or cls is None: - return - if value_node.kind() != ast.ASTKind.List: - return - lst_rcm: ast.List | t.CPtr = (ast.List | t.CPtr)(value_node) - if lst_rcm.elts is None: - return - elts_rcm: list[ast.AST | t.CPtr] | t.CPtr = lst_rcm.elts - en_rcm: t.CSizeT = len(elts_rcm) - for ei_rcm in range(en_rcm): - el_rcm: ast.AST | t.CPtr = elts_rcm.get(ei_rcm) - if el_rcm is None or el_rcm.kind() != ast.ASTKind.Constant: - continue - ec_rcm: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(el_rcm) - if ec_rcm.str_val is not None: - self.register_class_meta(pool, kind, cls, ec_rcm.str_val) - def register_method_meta(self, class_name: str, method_name: str, - meta: int) -> None: - """注册方法元数据(幂等)""" - if class_name is None or method_name is None or meta == 0: - return - # 懒初始化 - if self.MethodMetaKeys is None: - self.MethodMetaKeys = CompilerFactory.get_perm_pool().alloc(META_MAX * META_KEY_LEN) - self.MethodMetaFlags = CompilerFactory.get_perm_pool().alloc(META_MAX * 4) - if self.MethodMetaKeys is None or self.MethodMetaFlags is None: - return - string.memset(self.MethodMetaKeys, 0, META_MAX * META_KEY_LEN) - string.memset(self.MethodMetaFlags, 0, META_MAX * 4) - # 构造 key "ClassName.method" - cl_len: t.CSizeT = string.strlen(class_name) - mn_len: t.CSizeT = string.strlen(method_name) - key_buf: bytes = stdlib.malloc(cl_len + mn_len + 2) - if key_buf is None: - return - viperlib.snprintf(key_buf, cl_len + mn_len + 2, "%s.%s", class_name, method_name) - # 去重更新 - i: int - for i in range(self.MethodMetaCount): - if string.strcmp(self.MethodMetaKeys + i * META_KEY_LEN, key_buf) == 0: - flags_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid( - t.CUInt64T(self.MethodMetaFlags) + i * 4, t.CPtr)) - # 按位或合并:同一属性名先 @property(getter=4) 再 @x.setter(8)/ - # @x.deleter(16) 会多次注册(如 Config.value / Counter.value)。 - # 若整值替换,后注册的位会覆盖 GETTER 位 → _try_property_getter_attr - # 不再拦截 obj.prop → 落入字段查找失败返回 None → 上游 llvmlite - # 收到 NULL Value → 编译器进程段错误(BuiltinDecoratorTest Phase A 崩溃)。 - flags_ptr[0] = flags_ptr[0] | meta - stdlib.free(key_buf) - return - if self.MethodMetaCount < META_MAX: - # 槽位定长 META_KEY_LEN=128 字节,key 超长时 strncpy 钳制防越界写相邻槽 - string.strncpy(self.MethodMetaKeys + self.MethodMetaCount * META_KEY_LEN, - key_buf, META_KEY_LEN - 1) - flags_ptr2: t.CPtr = (t.CInt | t.CPtr)(t.CVoid( - t.CUInt64T(self.MethodMetaFlags) + self.MethodMetaCount * 4, t.CPtr)) - flags_ptr2[0] = meta - self.MethodMetaCount += 1 - stdlib.free(key_buf) - def lookup_method_meta(self, class_name: str, method_name: str) -> int: - """查找方法元数据位掩码,返回 0=未注册或非装饰器方法""" - if class_name is None or method_name is None: - return 0 - if self.MethodMetaKeys is None or self.MethodMetaCount <= 0: - return 0 - cl_len: t.CSizeT = string.strlen(class_name) - mn_len: t.CSizeT = string.strlen(method_name) - key_buf: bytes = stdlib.malloc(cl_len + mn_len + 2) - if key_buf is None: - return 0 - viperlib.snprintf(key_buf, cl_len + mn_len + 2, "%s.%s", class_name, method_name) - found: int = 0 - i: int - for i in range(self.MethodMetaCount): - if string.strcmp(self.MethodMetaKeys + i * META_KEY_LEN, key_buf) == 0: - flags_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid( - t.CUInt64T(self.MethodMetaFlags) + i * 4, t.CPtr)) - found = flags_ptr[0] - break - stdlib.free(key_buf) - return found - def _is_marker_base(self, base_name: str) -> int: - """检查基类名是否为标记基类,返回 1=是 / 0=否 - - 含 t.Struct:t.py 未定义 Struct 类(不被编译),`class X(t.Struct)` - 的 Struct 只是"普通结构体"标记。若不当成标记基类,会被误判为真实父类: - - 自动启用虚表 → 结构体多出 i8* 槽位(与 TPC 的 {i32,i32} 布局不符) - - Phase A-pre(declare_only=1)父类延迟检查找不到 "Struct" → 类被延迟注册 - → forward_declare 时类型未注册 → 裸类形参退化为 i32 → 函数签名与 - 函数体 alloca(Ptr(struct))不一致 → llc 报 "'%p' defined with type - 'i32' but expected 'ptr'"。 - 与 TPC(_resolve_base_kind 对 t.Struct 返回 None → 无父类)保持一致。 - """ - if base_name is None: - return 0 - if string.strcmp(base_name, "Object") == 0: - return 1 - if string.strcmp(base_name, "CVTable") == 0: - return 1 - if string.strcmp(base_name, "Exception") == 0: - return 1 - if string.strcmp(base_name, "CEnum") == 0: - return 1 - if string.strcmp(base_name, "Enum") == 0: - return 1 - if string.strcmp(base_name, "CStruct") == 0: - return 1 - if string.strcmp(base_name, "Struct") == 0: - return 1 - if string.strcmp(base_name, "CUnion") == 0: - return 1 - if string.strcmp(base_name, "REnum") == 0: - return 1 - return 0 - def _get_base_name(self, base_node: ast.AST | t.CPtr, - pool: memhub.MemBuddy | t.CPtr = None) -> str: - """从 base AST 节点提取基类名,返回 None=失败 - - 对于 Subscript 节点,需要 pool 分配内存拼接特化名; - pool=None 时降级返回基类名(不含类型实参) - """ - if base_node is None: - return None - k: int = base_node.kind() - # Name(id) 形式 - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node) - return nm.id - # Attribute(attr) 形式 - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_node) - return at.attr - # Subscript(value, slice) 形式 — 如 GSListNode[Value] - if k == ast.ASTKind.Subscript: - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(base_node) - if sub is None or sub.value is None or sub.slice is None: - return None - # 提取基类名(如 "GSListNode") - base_nm: str = self._get_base_name(sub.value, pool) - if base_nm is None: - return None - # 提取类型实参名(如 "Value") - slice_k: int = sub.slice.kind() - arg_nm: str = None - if slice_k == ast.ASTKind.Name: - sl_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.slice) - arg_nm = sl_nm.id - # 如果无法提取类型实参,返回基类名(降级) - if arg_nm is None: - return base_nm - # 无 pool 时返回基类名(降级,无法拼接特化名) - if pool is None: - return base_nm - # 拼接特化名 "GSListNode[Value]" - base_len: t.CSizeT = string.strlen(base_nm) - arg_len: t.CSizeT = string.strlen(arg_nm) - total_len: t.CSizeT = base_len + arg_len + 3 # "[" + arg + "]" + NUL - mangled: str = pool.alloc(total_len) - if mangled is None: - return base_nm # 降级 - mangled[0] = '\0' - string.strcat(mangled, base_nm) - string.strcat(mangled, "[") - string.strcat(mangled, arg_nm) - string.strcat(mangled, "]") - return mangled - return None - def _get_parent_class(self, cd: ast.ClassDef | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> str: - """获取 ClassDef 的真实父类名,返回 None=无真实父类""" - if cd is None or cd.bases is None: - return None - pool: memhub.MemBuddy | t.CPtr = None - if trans is not None: - pool = trans.Pool - bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases - bn: t.CSizeT = len(bases) - if bn == 0: - return None - for bi in range(bn): - base_node: ast.AST | t.CPtr = bases.get(bi) - if base_node is None: - continue - bname: str = self._get_base_name(base_node, pool) - if bname is not None: - # 基类别名解析(from t import CStruct as cs → cs 实际是 CStruct)。 - # ClassGen 拆分(47ac2dd)时丢失,EdgeCaseTest Test12 class - # CsPoint(cs) 回归根因:'cs' 被当真实父类 → find_struct("cs") - # 失败 → 类 defer 永不注册 → 变量注解解析失败。 - bname = self._resolve_base_alias(bname, trans) - if self._is_marker_base(bname) == 0: - return bname - return None - def _resolve_base_alias(self, base_name: str, - trans: HT.Translator | t.CPtr = None) -> str: - """解析基类别名:from t import CStruct as cs → 基类 cs 实际是 CStruct。 - - 别名不解析时 "cs" 会被当作真实父类名 → find_struct("cs") 失败 → - PhaseA 预注册把整类 defer(永不注册)→ 变量注解 X 解析失败 - (EdgeCaseTest Test12 class CsPoint(cs): 根因)。 - """ - if base_name is None or trans is None or trans._from_imports is None: - return base_name - orig: str = HandlesImports.lookup_from_import_original( - trans._from_imports, base_name) - if orig is not None: - # lookup_from_import_original 返回 from_imports 内部指针且未 NUL 结尾 - # (如 "CStruct myint:t:CInt CChar:t CPtr:t" 整串直到真正的 NUL)。 - # 复制到独立缓冲并按空格截断出干净原始名——否则 _is_marker_base 的 - # strcmp 对整串比较失败 → 别名基类(CStruct as cs)被当真实父类 → - # find_struct 失败 → 整类 defer 永不注册 → 变量注解解析失败。 - og_len: t.CSizeT = 0 - while orig[og_len] != ' ' and orig[og_len] != '\0': - og_len += 1 - if og_len > 0: - og_buf: str = CompilerFactory.get_perm_pool().alloc(og_len + 1) - if og_buf is not None: - string.strncpy(og_buf, orig, og_len) - og_buf[og_len] = '\0' - return og_buf - return base_name - def _collect_parents(self, pool: memhub.MemBuddy | t.CPtr, - cd: ast.ClassDef | t.CPtr, - parents_buf: t.CSizeT | t.CPtr, - max_parents: int, - trans: HT.Translator | t.CPtr = None) -> int: - """收集所有非 marker 父类名到 parents_buf,返回数量""" - if pool is None or cd is None or cd.bases is None or parents_buf is None: - return 0 - bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases - bn: t.CSizeT = len(bases) - count: int = 0 - for bi in range(bn): - if count >= max_parents: - break - base_node: ast.AST | t.CPtr = bases.get(bi) - if base_node is None: - continue - bname: str = self._get_base_name(base_node, pool) - if bname is not None: - # 基类别名解析(同 _get_parent_class,见 _resolve_base_alias) - bname = self._resolve_base_alias(bname, trans) - if self._is_marker_base(bname) == 0: - parents_buf[count] = t.CSizeT(bname) - count += 1 - return count - def _field_name_exists(self, names_buf: t.CSizeT | t.CPtr, - count: int, name: str) -> int: - """检查字段名是否已在 names_buf 中(先声明父类优先,重复跳过)""" - if names_buf is None or name is None: - return 0 - for fi in range(count): - addr: t.CSizeT = names_buf[fi] - if addr != 0: - existing: str = (str | t.CPtr)(t.CVoid(addr, t.CPtr)) - if existing is not None and string.strcmp(existing, name) == 0: - return 1 - return 0 - def _class_body_has_field(self, cd: ast.ClassDef | t.CPtr) -> int: - """检查类体是否声明了字段(AnnAssign),0=纯方法/无字段类""" - if cd is None or cd.children is None: - return 0 - cn: t.CSizeT = len(cd.children) - for ci in range(cn): - stmt: ast.AST | t.CPtr = cd.children.get(ci) - if stmt is None: - continue - if stmt.kind() == ast.ASTKind.AnnAssign: - return 1 - return 0 - def _trigger_base_specialization(self, trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr): - """触发 base 中 Subscript 的泛型特化(如 GSListNode[Value])""" - if trans is None or cd is None or cd.bases is None: - return - pool: memhub.MemBuddy | t.CPtr = trans.Pool - bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases - bn: t.CSizeT = len(bases) - if bn == 0: - return - for bi in range(bn): - base_node: ast.AST | t.CPtr = bases.get(bi) - if base_node is None: - continue - bk: int = base_node.kind() - if bk != ast.ASTKind.Subscript: - continue - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(base_node) - if sub is None or sub.value is None or sub.slice is None: - continue - # 提取泛型类名(如 "GSListNode") - gen_class_name: str = self._get_base_name(sub.value, pool) - if gen_class_name is None: - continue - # 跳过标记基类 - if self._is_marker_base(gen_class_name) == 1: - continue - # 提取类型实参名(如 "Value") - slice_k: int = sub.slice.kind() - arg_nm: str = None - if slice_k == ast.ASTKind.Name: - sl_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.slice) - arg_nm = sl_nm.id - if arg_nm is None: - continue - # 构建 type_args 列表(elem_size=8:str 是指针,1 会导致双元素重叠损坏) - type_args: list[str] | t.CPtr = list[str](pool, 8) - if type_args is None: - continue - type_args.append(arg_nm) - # 触发特化(_specialize_generic_class 有缓存,重复调用安全) - HandlesClassDef._specialize_generic_class(trans, gen_class_name, type_args) - def _has_any_func_cvtable(self, cd: ast.ClassDef | t.CPtr) -> int: - """检查类中是否有任何函数标记了 @t.CVTable,返回 1=有 / 0=无""" - if cd is None or cd.children is None: - return 0 - children: list[ast.AST | t.CPtr] | t.CPtr = cd.children - cn: t.CSizeT = len(children) - for ci in range(cn): - stmt: ast.AST | t.CPtr = children.get(ci) - if stmt is None: - continue - if stmt.kind() != ast.ASTKind.FunctionDef: - continue - fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) - if fd is None or fd.name is None: - continue - # 跳过构造函数 - if string.strcmp(fd.name, "__init__") == 0: - continue - if string.strcmp(fd.name, "__before_init__") == 0: - continue - if string.strcmp(fd.name, "__new__") == 0: - continue - if fd.decorator_list is not None: - if self._has_decorator(fd.decorator_list, "CVTable") == 1: - return 1 - return 0 - def _should_method_be_virtual(self, cd: ast.ClassDef | t.CPtr, - fd: ast.FunctionDef | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> int: - """判断方法是否应该进入虚表,返回 1=包含 / 0=排除""" - if fd is None: - return 0 - # 1. 检查函数级 @t.NoVTable(最高优先级,排除) - if fd.decorator_list is not None: - if self._has_decorator(fd.decorator_list, "NoVTable") == 1: - return 0 - # 2. 检查函数级 @t.CVTable(明确包含) - if self._has_decorator(fd.decorator_list, "CVTable") == 1: - return 1 - - # 3. 检查类级别 @t.CVTable - if cd is not None and cd.decorator_list is not None: - if self._has_decorator(cd.decorator_list, "CVTable") == 1: - return 1 - - # 4. 检查继承关系 - parent_name: str = self._get_parent_class(cd, trans) - if parent_name is not None: - # 用 SHA1 感知查找父类,规避跨模块同名找错 - is_nvt: int = 0 - if trans is not None: - p_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( - parent_name, trans.ModuleSha1) - if p_entry is None: - # 跨模块父类回退全局查找(父类注册在父模块 SHA1 下,如 linkedlist.LinkedNode), - # 与字段展平(1.5 节)的回退保持一致,否则父类 NoVTable 被误判为有虚表 → 子类插 vptr - # 导致子类布局比父类多一个指针,父类方法按无 vptr 布局操作错位 - p_entry = HandlesStruct.find_struct(parent_name) - if p_entry is not None: - is_nvt = p_entry.IsNoVTable - else: - is_nvt = HandlesStruct.is_novtable_by_name(parent_name) - if is_nvt != 1: - # 继承链统一虚表:父类有虚表 → 方法进虚表;父类无虚表 → 静态方法。 - # 与 _detect_vtable_status 规则一致,避免父类无 vptr 布局/子类有 vptr 的错位。 - if p_entry is None: - return 1 # 父类信息未知,保守进虚表 - if p_entry.HasVTable == 1: - return 1 - return 0 - - # 5. 默认排除 - return 0 - def _detect_vtable_status(self, cd: ast.ClassDef | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> int: - """检测类是否应该启用虚表""" - if cd is None: - return 0 - - # 检查类装饰器 - if cd.decorator_list is not None: - # @t.CVTable 优先级最高,直接启用 - if self._has_decorator(cd.decorator_list, "CVTable") == 1: - return 1 - # @t.NoVTable:类级别禁用,但检查函数级 @t.CVTable - if self._has_decorator(cd.decorator_list, "NoVTable") == 1: - return self._has_any_func_cvtable(cd) - - # 检查是否有真实父类(继承自动启用 CVTable) - parent_name: str = self._get_parent_class(cd, trans) - if parent_name is not None: - # 用 SHA1 感知查找父类,规避跨模块同名找错 - is_nvt: int = 0 - if trans is not None: - p_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( - parent_name, trans.ModuleSha1) - if p_entry is None: - # 跨模块父类回退全局查找(同 _detect_vtable_status 的回退) - p_entry = HandlesStruct.find_struct(parent_name) - if p_entry is not None: - is_nvt = p_entry.IsNoVTable - else: - is_nvt = HandlesStruct.is_novtable_by_name(parent_name) - if is_nvt == 1: - # 父类是 NoVTable,检查函数级 @t.CVTable - return self._has_any_func_cvtable(cd) - # 继承链统一虚表:父类有虚表 → 子类启用;父类无虚表 → 子类静态。 - # 若父类无 vtable 而子类有,父类方法按无 vptr 布局(self.field@0)操作 - # 子类实例(有 vptr@0)会字段错位 → 运行时错误(父类方法读 vptr 当字段)。 - if p_entry is None: - return 1 # 父类信息未知(跨模块/未注册),保守启用虚表 - if p_entry.HasVTable == 1: - return 1 - return 0 - - # 默认(无装饰器无继承),检查函数级 @t.CVTable - return self._has_any_func_cvtable(cd) \ No newline at end of file +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.Generator as Generator +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HT +import lib.core.StubMerger as StubMerger +import lib.core.CompilerFactory as CompilerFactory + + +# ============================================================ +# 本地常量(阶段 D 拆分时从 ClassGenMixin 顶层遗漏,补回: +# 方法元数据/类元数据/装饰器/异常表容量与编码;本地副本避免跨模块 CDefine 查找) +# ============================================================ +# 方法元数据 flag 位(对齐 TPC HandlesBase _METHOD_META_*) +META_TLS: t.CDefine = 32 +# 类编译期元数据表容量上限(__provides__/__requires__/__require_must__) +CLASS_META_MAX: t.CDefine = 256 +# 自定义装饰器 wrapper 表容量上限(带 @decor 的函数数) +DECOR_FUNC_MAX: t.CDefine = 64 +# 装饰器表槽内函数名/wrapper 名长度(含 NUL) +DECOR_NAME_LEN: t.CDefine = 128 +# 异常类注册表容量上限(class X(Exception) 自定义异常类) +EXCEPTION_MAX: t.CDefine = 64 +# 异常类表槽内类名/父类名长度(含 NUL) +EXCEPTION_NAME_LEN: t.CDefine = 128 +# 内置异常编码(对齐 TPC HandlesBase.py EXCEPTION_CODE_MAP); +# KeyError=6 IOError=7 OSError=8 AssertionError=9 Exception=99;用户类从 100 起 +BUILTIN_EH_VALUE_ERROR: t.CDefine = 1 +BUILTIN_EH_RUNTIME_ERROR: t.CDefine = 3 +BUILTIN_EH_EXCEPTION: t.CDefine = 99 +EH_USER_CODE_START: t.CDefine = 100 + + +# ============================================================ +# ClassGenBase - ClassGenMixin 拆分(阶段 D):字段 + 方法元数据/异常/继承检测/装饰器(Meta) +# +# 继承 ClassGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesClassDef 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class ClassGenBase: + """字段 + 方法元数据/异常/继承检测/装饰器(Meta)""" + + # --- 方法元数据表(原 _g_method_meta_keys/_g_method_meta_flags/_g_method_meta_count) --- + Gen: Generator.Generator | t.CPtr + MethodMetaKeys: bytes + MethodMetaFlags: bytes + MethodMetaCount: int + + # --- REnum 变体表(原 _renum_class_names/_renum_class_variant_counts/ + # _renum_variant_names/_renum_variant_tags/_renum_class_count) --- + RenumClassNames: t.CSizeT | t.CPtr + RenumClassVariantCounts: t.CSizeT | t.CPtr + RenumVariantNames: t.CSizeT | t.CPtr + RenumVariantTags: t.CSizeT | t.CPtr + RenumClassCount: int + + # --- REnum 字段别名表(原 _renum_alias_class/_renum_alias_field/ + # _renum_alias_index/_renum_alias_count) --- + RenumAliasClass: t.CSizeT | t.CPtr + RenumAliasField: t.CSizeT | t.CPtr + RenumAliasIndex: t.CSizeT | t.CPtr + # 变体成员实际 LLVM 类型(对齐 TPC class_members):注册时按注解解析, + # perm_pool 深拷贝持久化。match 绑定用真实成员类型 bitcast 槽位地址 + # (Struct.Name: i8*,否则按槽位 i64 读 → is/subscript/strlen 失败)。 + RenumAliasTy: t.CSizeT | t.CPtr + # 别名所属变体名(perm_pool 拷贝):同一 payload 位置跨变体类型不同 + # (Int.Bits=i32 vs Struct.Fields=Ptr),match 绑定按 (class, 变体, 位置) + # 唯一定位成员类型。 + RenumAliasVariant: t.CSizeT | t.CPtr + RenumAliasCount: int + + # --- 泛型特化缓存(原 _spec_keys/_spec_names/_spec_count) --- + SpecKeys: t.CSizeT | t.CPtr + SpecNames: t.CSizeT | t.CPtr + SpecCount: int + + # --- 类编译期元数据表(__provides__/__requires__/__require_must__) --- + # perm_pool 分配(跨 mark/reset 存活):每槽 kind(4B) + cls(64B) + field(64B) + # FakeDuck:_str.__requires__=['__mbuddy__'] 等(FakeDuck 移植点 1) + ClassMetaKinds: t.CInt | t.CPtr + ClassMetaClss: bytes + ClassMetaFields: bytes + ClassMetaCount: int + + # --- 自定义装饰器 wrapper 表(@log/@skip/@repeat 等 → __decor_wrap_{name}) --- + # perm_pool 分配(跨 mark/reset 存活):每槽函数名(128B) + wrapper 名(128B) + # 对齐 TPC HandlesFunctions.py L1621-1631 的 _decorated_funcs + + # DecoratorPass.py 的 wrapper 生成。调用点重写经 + # lookup_decor_wrapper(translate_call 拦截原函数名 → wrapper 名)。 + DecoratorFuncCount: int + DecoratorFuncNames: bytes + DecoratorWrapNames: bytes + # 装饰器首个常量参数(@repeat(3) 的 3),无参数为 0(每槽 8B,i64) + DecoratorArgs: t.CInt64T | t.CPtr + + # --- 异常类注册表(try-except,对齐 TPC HandlesClassDef.py L47-61) --- + # perm_pool 分配(跨 mark/reset 存活):每槽类名(128B) + 父类名(128B) + 编码(4B) + # 用户异常类编码从 100 递增;内置编码(ValueError=1 等)不在此表 + # (_lookup_exception_code 走内置硬编码)。异常类不生成 struct。 + ExceptionCount: int + ExceptionNames: bytes + ExceptionParents: bytes + ExceptionCodes: t.CInt | t.CPtr + # 下一个待分配的异常编码(用户类,从 100 起) + NextExceptionCode: int + # 递归收集子孙编码用的临时计数(collect_descendant_codes 返回后无效)。 + # 必须与其它字段一起声明在类顶:方法中间的字段注解可能被编译器 + # 当作局部声明处理,破坏 Mixin 布局/this_adjust 对齐。 + _exception_codes_tmp_count: int + + # --- 泛型特化递归深度(泛型循环套用防护) --- + # _specialize_generic_class 进入时 +1、退出时 -1;超过上限立即报错终止 + # (防止 F-bounded 等循环特化把编译变成死循环) + GenericSpecDepth: int + + # --- 泛型模板表(原 HandlesClassDef._generic_class_names/ + # _generic_class_nodes/_generic_class_sha1s) --- + GenericClassNames: list[str] | t.CPtr + GenericClassNodes: list[ast.ClassDef | t.CPtr] | t.CPtr + GenericClassSha1s: list[str] | t.CPtr + # 泛型模板来源文件路径(与上面三表同序)。特化翻译模板方法体时 + # node.lineno 是模板文件行号,若 CurrentFile 仍是调用方文件, + # fatal_error 会把模板行号套到调用方文件上显示错位(如 vector.vp + # 的 T(...) 错报成 vectortest.vp 的 return 0)。此表用于特化期间 + # 临时切换 CurrentFile 到模板文件,翻译完恢复。 + GenericClassFiles: list[str] | t.CPtr + # 泛型模板类型参数名表(与 GenericClassNames 同序,stdlib 深拷贝)。 + # 模板节点 type_params 是 Phase 1 pool 分配的 list,跨 Phase 引用时内容 + # 可能失效(VectorGenericTest 特化 Vector[int].__init__ 的 T.__sizeof__() + # NameError 根因方向);注册时展平深拷贝到 stdlib,特化时从本表恢复。 + # 每槽指向一个空格分隔、NUL 结尾的 stdlib 缓冲区(如 "T" 或 "T K")。 + GenericClassTpParams: t.CSizeT | t.CPtr + + # --- vtable 方法收集表(原 _g_vt_full_names/_g_vt_method_names/ + # _g_vt_parent_sha1s/_g_vt_method_count) --- + VtFullNames: t.CSizeT | t.CPtr + VtMethodNames: t.CSizeT | t.CPtr + VtParentSha1s: t.CSizeT | t.CPtr + VtMethodCount: int + # ============================================================ + # 以下方法由 P5-2 分簇迁移填充(函数体来自 HandlesClassDef.vp, + # 本模块函数调用改 self.,外部模块调用保留模块前缀) + # ============================================================ + + def _is_cenum_base(self, base_node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> int: + """检查 base 节点是否为 t.CEnum,返回 1=是 / 0=否""" + if base_node is None: + return 0 + k: int = base_node.kind() + # Name('CEnum') 形式(from t import CEnum) + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node) + if nm.id is None: + return 0 + if string.strcmp(nm.id, "CEnum") == 0: + return 1 + # 别名形式: from t import CEnum as en; class Color(en) + # 解析别名原始名(en → CEnum)再比较 + if trans is not None and trans._from_imports is not None: + alias_orig: str = self.Gen.ImportsGen.lookup_from_import_original( + trans._from_imports, nm.id) + if alias_orig is not None: + og_len_ce: t.CSizeT = 0 + while alias_orig[og_len_ce] != ' ' and alias_orig[og_len_ce] != '\0': + og_len_ce += 1 + if og_len_ce == 5 and string.strncmp(alias_orig, "CEnum", 5) == 0: + return 1 + return 0 + # Attribute(t.CEnum) 形式 + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_node) + if at.attr is not None and string.strcmp(at.attr, "CEnum") == 0: + return 1 + return 0 + return 0 + def _is_enum_class(self, cd: ast.ClassDef | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> int: + """检查 ClassDef 是否为 CEnum:继承自 t.CEnum 或 @t.CEnum 装饰器形式""" + if cd is None: + return 0 + # 装饰器形式: @t.CEnum class Color:(无基类,等价 class Color(t.CEnum):) + if cd.decorator_list is not None: + if self._has_decorator(cd.decorator_list, "CEnum") == 1: + return 1 + if cd.bases is None: + return 0 + bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases + bn: t.CSizeT = len(bases) + if bn == 0: + return 0 + for bi in range(bn): + base_node: ast.AST | t.CPtr = bases.get(bi) + if base_node is None: + continue + if self._is_cenum_base(base_node, trans) == 1: + return 1 + return 0 + def _is_cunion_base(self, base_node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> int: + """检查 base 节点是否为 t.CUnion,返回 1=是 / 0=否""" + if base_node is None: + return 0 + k: int = base_node.kind() + # Name('CUnion') 形式(from t import CUnion) + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node) + if nm.id is None: + return 0 + if string.strcmp(nm.id, "CUnion") == 0: + return 1 + # 别名形式: from t import CUnion as un; class Data(un) + if trans is not None and trans._from_imports is not None: + alias_orig: str = self.Gen.ImportsGen.lookup_from_import_original( + trans._from_imports, nm.id) + if alias_orig is not None: + og_len_cu: t.CSizeT = 0 + while alias_orig[og_len_cu] != ' ' and alias_orig[og_len_cu] != '\0': + og_len_cu += 1 + if og_len_cu == 6 and string.strncmp(alias_orig, "CUnion", 6) == 0: + return 1 + return 0 + # Attribute(t.CUnion) 形式 + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_node) + if at.attr is not None and string.strcmp(at.attr, "CUnion") == 0: + return 1 + return 0 + return 0 + def _is_union_class(self, cd: ast.ClassDef | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> int: + """检查 ClassDef 是否为 CUnion:继承自 t.CUnion 或 @t.CUnion 装饰器形式""" + if cd is None: + return 0 + # 装饰器形式: @t.CUnion class Data: + if cd.decorator_list is not None: + if self._has_decorator(cd.decorator_list, "CUnion") == 1: + return 1 + if cd.bases is None: + return 0 + bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases + bn: t.CSizeT = len(bases) + if bn == 0: + return 0 + for bi in range(bn): + base_node: ast.AST | t.CPtr = bases.get(bi) + if base_node is None: + continue + if self._is_cunion_base(base_node, trans) == 1: + return 1 + return 0 + def _is_crenum_base(self, base_node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> int: + """检查 base 节点是否为 t.REnum,返回 1=是 / 0=否""" + if base_node is None: + return 0 + k: int = base_node.kind() + # Name('REnum') 形式(from t import REnum) + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node) + if nm.id is None: + return 0 + if string.strcmp(nm.id, "REnum") == 0: + return 1 + # 别名形式: from t import REnum as ren; class Opt(ren) + if trans is not None and trans._from_imports is not None: + alias_orig: str = self.Gen.ImportsGen.lookup_from_import_original( + trans._from_imports, nm.id) + if alias_orig is not None: + og_len_cr: t.CSizeT = 0 + while alias_orig[og_len_cr] != ' ' and alias_orig[og_len_cr] != '\0': + og_len_cr += 1 + if og_len_cr == 5 and string.strncmp(alias_orig, "REnum", 5) == 0: + return 1 + return 0 + # Attribute(t.REnum) 形式 + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_node) + if at.attr is not None and string.strcmp(at.attr, "REnum") == 0: + return 1 + return 0 + return 0 + def _is_renum_class(self, cd: ast.ClassDef | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> int: + """检查 ClassDef 是否为 REnum:继承自 t.REnum 或 @t.REnum 装饰器形式""" + if cd is None: + return 0 + # 装饰器形式: @t.REnum class X: + if cd.decorator_list is not None: + if self._has_decorator(cd.decorator_list, "REnum") == 1: + return 1 + if cd.bases is None: + return 0 + bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases + bn: t.CSizeT = len(bases) + if bn == 0: + return 0 + for bi in range(bn): + base_node: ast.AST | t.CPtr = bases.get(bi) + if base_node is None: + continue + if self._is_crenum_base(base_node, trans) == 1: + return 1 + return 0 + def _has_decorator(self, decorator_list: list[ast.AST | t.CPtr] | t.CPtr, + deco_name: str) -> int: + """检查 decorator_list 中是否有指定装饰器名""" + if decorator_list is None: + return 0 + dn: t.CSizeT = len(decorator_list) + if dn == 0: + return 0 + for di in range(dn): + deco: ast.AST | t.CPtr = decorator_list.get(di) + if deco is None: + continue + k: int = deco.kind() + # @t.NoVTable 形式(Attribute) + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(deco) + if at.attr is not None and string.strcmp(at.attr, deco_name) == 0: + # 检查 value 是 Name('t') + if at.value is not None and at.value.kind() == ast.ASTKind.Name: + vn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if vn.id is not None and string.strcmp(vn.id, "t") == 0: + return 1 + return 0 + # @NoVTable 形式(Name,from t import NoVTable) + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(deco) + if nm.id is not None and string.strcmp(nm.id, deco_name) == 0: + return 1 + return 0 + def _extract_func_meta(self, decorator_list: list[ast.AST | t.CPtr] | t.CPtr) -> int: + """从装饰器列表提取元数据位掩码,返回 0=无装饰器元数据""" + meta: int = 0 + if decorator_list is None: + return meta + dn: t.CSizeT = len(decorator_list) + if dn == 0: + return meta + for di in range(dn): + deco: ast.AST | t.CPtr = decorator_list.get(di) + if deco is None: + continue + k: int = deco.kind() + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(deco) + if nm.id is not None: + if string.strcmp(nm.id, "staticmethod") == 0: + meta |= META_STATIC + elif string.strcmp(nm.id, "property") == 0: + meta |= META_PROP_GETTER + elif string.strcmp(nm.id, "classmethod") == 0: + meta |= META_CLASS + elif string.strcmp(nm.id, "TLS") == 0: + meta |= META_TLS + elif k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(deco) + if at.attr is not None and at.value is not None: + if at.value.kind() == ast.ASTKind.Name: + vn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + is_prop_name: int = 0 + if vn.id is not None and string.strcmp(vn.id, "property") == 0: + is_prop_name = 1 + # @t.TLS 一次性初始化标记(对齐 TPC HandlesFunctions.py + # L1223-1231:value 必须为 Name('t');@TLS 裸名走上面 Name 分支) + if vn.id is not None and string.strcmp(vn.id, "t") == 0 \ + and string.strcmp(at.attr, "TLS") == 0: + meta |= META_TLS + # @property.setter 或 @x.setter/getter/deleter 都识别 + if is_prop_name != 0 or string.strcmp(at.attr, "setter") == 0 \ + or string.strcmp(at.attr, "getter") == 0 or string.strcmp(at.attr, "deleter") == 0: + if string.strcmp(at.attr, "setter") == 0: + meta |= META_PROP_SETTER + elif string.strcmp(at.attr, "getter") == 0: + meta |= META_PROP_GETTER + elif string.strcmp(at.attr, "deleter") == 0: + meta |= META_PROP_DELETER + return meta + def register_class_meta(self, pool: memhub.MemBuddy | t.CPtr, + kind: int, cls: str, field: str) -> int: + """注册类编译期元数据字段(__provides__/__requires__/__require_must__,幂等)""" + if pool is None or cls is None or field is None: + return -1 + if self.ClassMetaKinds is None: + self.ClassMetaKinds = CompilerFactory.get_perm_pool().alloc(CLASS_META_MAX * 4) + self.ClassMetaClss = CompilerFactory.get_perm_pool().alloc(CLASS_META_MAX * 64) + self.ClassMetaFields = CompilerFactory.get_perm_pool().alloc(CLASS_META_MAX * 64) + if self.ClassMetaKinds is None or self.ClassMetaClss is None or self.ClassMetaFields is None: + return -1 + string.memset(self.ClassMetaKinds, 0, CLASS_META_MAX * 4) + string.memset(self.ClassMetaClss, 0, CLASS_META_MAX * 64) + string.memset(self.ClassMetaFields, 0, CLASS_META_MAX * 64) + self.ClassMetaCount = 0 + if self.ClassMetaCount >= CLASS_META_MAX: + return -1 + # 幂等:同 (kind, cls, field) 跳过 + for i in range(self.ClassMetaCount): + if self.ClassMetaKinds[i] == kind: + if string.strcmp(self.ClassMetaClss + i * 64, cls) == 0: + if string.strcmp(self.ClassMetaFields + i * 64, field) == 0: + return 0 + idx_cm: t.CSizeT = t.CSizeT(self.ClassMetaCount) * 64 + self.ClassMetaKinds[self.ClassMetaCount] = kind + string.strncpy(self.ClassMetaClss + idx_cm, cls, 63) + self.ClassMetaClss[idx_cm + 63] = '\0' + string.strncpy(self.ClassMetaFields + idx_cm, field, 63) + self.ClassMetaFields[idx_cm + 63] = '\0' + self.ClassMetaCount += 1 + return 0 + def class_meta_count(self, kind: int, cls: str) -> int: + """返回某类某元数据类型的字段数""" + if self.ClassMetaKinds is None or cls is None: + return 0 + n_cm: int = 0 + for i in range(self.ClassMetaCount): + if self.ClassMetaKinds[i] == kind: + if string.strcmp(self.ClassMetaClss + i * 64, cls) == 0: + n_cm += 1 + return n_cm + def class_meta_field_at(self, kind: int, cls: str, idx: int) -> str: + """返回某类某元数据类型的第 idx 个字段名""" + if self.ClassMetaKinds is None or cls is None: + return None + n_cm2: int = 0 + for i in range(self.ClassMetaCount): + if self.ClassMetaKinds[i] == kind: + if string.strcmp(self.ClassMetaClss + i * 64, cls) == 0: + if n_cm2 == idx: + return self.ClassMetaFields + i * 64 + n_cm2 += 1 + return None + def register_decorator(self, pool: memhub.MemBuddy | t.CPtr, + func_name: str, wrapper_name: str, + arg0: t.CInt64T) -> int: + """注册自定义装饰器函数(@log/@skip/@repeat(3) → __decor_wrap_{name}) + + 对齐 TPC HandlesFunctions.py L1621-1631 的 _decorated_funcs 注册。 + arg0 为装饰器首个常量参数(@repeat(3) 的 3),无参数为 0。 + """ + if pool is None or func_name is None or wrapper_name is None: + return -1 + if self.DecoratorFuncNames is None: + self.DecoratorFuncNames = CompilerFactory.get_perm_pool().alloc( + DECOR_FUNC_MAX * DECOR_NAME_LEN) + self.DecoratorWrapNames = CompilerFactory.get_perm_pool().alloc( + DECOR_FUNC_MAX * DECOR_NAME_LEN) + self.DecoratorArgs = CompilerFactory.get_perm_pool().alloc( + DECOR_FUNC_MAX * 8) + if self.DecoratorFuncNames is None or self.DecoratorWrapNames is None \ + or self.DecoratorArgs is None: + return -1 + string.memset(self.DecoratorFuncNames, 0, DECOR_FUNC_MAX * DECOR_NAME_LEN) + string.memset(self.DecoratorWrapNames, 0, DECOR_FUNC_MAX * DECOR_NAME_LEN) + string.memset(self.DecoratorArgs, 0, DECOR_FUNC_MAX * 8) + self.DecoratorFuncCount = 0 + if self.DecoratorFuncCount >= DECOR_FUNC_MAX: + return -1 + # 幂等:同名函数已注册则跳过(多遍扫描) + for i in range(self.DecoratorFuncCount): + if string.strcmp(self.DecoratorFuncNames + i * DECOR_NAME_LEN, func_name) == 0: + return 0 + idx_dc: t.CSizeT = t.CSizeT(self.DecoratorFuncCount) * DECOR_NAME_LEN + string.strncpy(self.DecoratorFuncNames + idx_dc, func_name, DECOR_NAME_LEN - 1) + self.DecoratorFuncNames[idx_dc + DECOR_NAME_LEN - 1] = '\0' + string.strncpy(self.DecoratorWrapNames + idx_dc, wrapper_name, DECOR_NAME_LEN - 1) + self.DecoratorWrapNames[idx_dc + DECOR_NAME_LEN - 1] = '\0' + self.DecoratorArgs[self.DecoratorFuncCount] = arg0 + self.DecoratorFuncCount += 1 + return 0 + def lookup_decor_wrapper(self, func_name: str) -> str: + """按原函数名查 wrapper 名,未注册返回 None""" + if self.DecoratorFuncNames is None or func_name is None: + return None + for i in range(self.DecoratorFuncCount): + if string.strcmp(self.DecoratorFuncNames + i * DECOR_NAME_LEN, func_name) == 0: + return self.DecoratorWrapNames + i * DECOR_NAME_LEN + return None + def lookup_decor_arg0(self, func_name: str) -> t.CInt64T: + """按原函数名查装饰器首个常量参数(无参数为 0)""" + if self.DecoratorFuncNames is None or func_name is None: + return 0 + for i in range(self.DecoratorFuncCount): + if string.strcmp(self.DecoratorFuncNames + i * DECOR_NAME_LEN, func_name) == 0: + return self.DecoratorArgs[i] + return 0 + # ============================================================ + # 异常类注册表(try-except,对齐 TPC HandlesClassDef.py L47-61) + # ============================================================ + def _ensure_exception_tables(self) -> int: + """懒初始化异常表(perm_pool),返回 0 成功""" + if self.ExceptionNames is not None: + return 0 + pp_e: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool() + if pp_e is None: + return -1 + self.ExceptionNames = pp_e.alloc(EXCEPTION_MAX * EXCEPTION_NAME_LEN) + self.ExceptionParents = pp_e.alloc(EXCEPTION_MAX * EXCEPTION_NAME_LEN) + self.ExceptionCodes = pp_e.alloc(EXCEPTION_MAX * 4) + if self.ExceptionNames is None or self.ExceptionParents is None \ + or self.ExceptionCodes is None: + return -1 + string.memset(self.ExceptionNames, 0, EXCEPTION_MAX * EXCEPTION_NAME_LEN) + string.memset(self.ExceptionParents, 0, EXCEPTION_MAX * EXCEPTION_NAME_LEN) + string.memset(self.ExceptionCodes, 0, EXCEPTION_MAX * 4) + self.ExceptionCount = 0 + self.NextExceptionCode = EH_USER_CODE_START + return 0 + def register_exception(self, class_name: str, parent_name: str) -> int: + """注册用户异常类并分配编码(幂等:同名跳过)。返回编码或 -1""" + if class_name is None: + return -1 + if self._ensure_exception_tables() != 0: + return -1 + # 幂等:已注册则返回既有编码(多遍扫描) + for i in range(self.ExceptionCount): + if string.strcmp(self.ExceptionNames + i * EXCEPTION_NAME_LEN, class_name) == 0: + return self.ExceptionCodes[i] + if self.ExceptionCount >= EXCEPTION_MAX: + return -1 + idx_e: t.CSizeT = t.CSizeT(self.ExceptionCount) * EXCEPTION_NAME_LEN + string.strncpy(self.ExceptionNames + idx_e, class_name, EXCEPTION_NAME_LEN - 1) + self.ExceptionNames[idx_e + EXCEPTION_NAME_LEN - 1] = '\0' + if parent_name is not None: + string.strncpy(self.ExceptionParents + idx_e, parent_name, EXCEPTION_NAME_LEN - 1) + self.ExceptionParents[idx_e + EXCEPTION_NAME_LEN - 1] = '\0' + code_e: int = self.NextExceptionCode + self.NextExceptionCode += 1 + self.ExceptionCodes[self.ExceptionCount] = code_e + self.ExceptionCount += 1 + return code_e + def _builtin_exception_code(self, name: str) -> int: + """内置异常编码(对齐 TPC HandlesBase.py EXCEPTION_CODE_MAP),非内置返回 0""" + if name is None: + return 0 + if string.strcmp(name, "ValueError") == 0: return 1 + if string.strcmp(name, "TypeError") == 0: return 2 + if string.strcmp(name, "RuntimeError") == 0: return 3 + if string.strcmp(name, "ZeroDivisionError") == 0: return 4 + if string.strcmp(name, "IndexError") == 0: return 5 + if string.strcmp(name, "KeyError") == 0: return 6 + if string.strcmp(name, "IOError") == 0: return 7 + if string.strcmp(name, "OSError") == 0: return 8 + if string.strcmp(name, "AssertionError") == 0: return 9 + if string.strcmp(name, "Exception") == 0: return 99 + return 0 + def lookup_exception_code(self, name: str) -> int: + """查异常编码:内置表优先,其次用户异常表,都未命中返回 0""" + if name is None: + return 0 + bi: int = self._builtin_exception_code(name) + if bi != 0: + return bi + if self.ExceptionNames is None: + return 0 + for i in range(self.ExceptionCount): + if string.strcmp(self.ExceptionNames + i * EXCEPTION_NAME_LEN, name) == 0: + return self.ExceptionCodes[i] + return 0 + def lookup_exception_parent(self, name: str) -> str: + """查用户异常类的父类名,非用户异常返回 None""" + if name is None or self.ExceptionNames is None: + return None + for i in range(self.ExceptionCount): + if string.strcmp(self.ExceptionNames + i * EXCEPTION_NAME_LEN, name) == 0: + p_e: str = self.ExceptionParents + i * EXCEPTION_NAME_LEN + if p_e is not None and p_e[0] != '\0': + return p_e + return None + return None + def is_exception_name(self, name: str) -> int: + """name 是否是内置或用户异常类名(1=是 / 0=否)""" + if name is None: + return 0 + if self._builtin_exception_code(name) != 0: + return 1 + if self.ExceptionNames is None: + return 0 + for i in range(self.ExceptionCount): + if string.strcmp(self.ExceptionNames + i * EXCEPTION_NAME_LEN, name) == 0: + return 1 + return 0 + def collect_descendant_codes(self, name: str, out_codes: t.CInt | t.CPtr, + max_codes: int) -> int: + """把 name 及其所有子孙异常类的编码收集到 out_codes,返回数量 + (对齐 TPC HandlesTry.py _get_all_match_codes/_collect_descendant_codes: + 编译期静态展开继承树,except X 匹配 X 及全部子孙)。""" + if name is None or out_codes is None: + return 0 + self._exception_codes_tmp_count = 0 + self._collect_desc_codes_rec(name, out_codes, max_codes, 0) + return self._exception_codes_tmp_count + def _collect_desc_codes_rec(self, name: str, out_codes: t.CInt | t.CPtr, + max_codes: int, depth: int) -> None: + """递归收集 name 编码 + 全部子孙编码(BFS 语义对齐 TPC)""" + if depth > 32: + return + code_e: int = self.lookup_exception_code(name) + if code_e != 0 and self._exception_codes_tmp_count < max_codes: + # 去重(继承环防护) + dup: int = 0 + for i in range(self._exception_codes_tmp_count): + if out_codes[i] == code_e: + dup = 1 + break + if dup == 0: + out_codes[self._exception_codes_tmp_count] = code_e + self._exception_codes_tmp_count += 1 + # 遍历全部用户异常,找以 name 为父类的子类递归收集 + if self.ExceptionNames is None: + return + for i in range(self.ExceptionCount): + cname_e: str = self.ExceptionNames + i * EXCEPTION_NAME_LEN + pname_e: str = self.ExceptionParents + i * EXCEPTION_NAME_LEN + if pname_e is not None and pname_e[0] != '\0': + if string.strcmp(pname_e, name) == 0: + self._collect_desc_codes_rec(cname_e, out_codes, max_codes, depth + 1) + def _is_exception_class_def(self, cd: ast.ClassDef | t.CPtr) -> int: + """类定义是否是异常类:基类是 Exception 或已注册异常类(1=是)""" + if cd is None or cd.bases is None: + return 0 + bases_e: list[ast.AST | t.CPtr] | t.CPtr = cd.bases + bn_e: t.CSizeT = len(bases_e) + for bi_e in range(bn_e): + base_e: ast.AST | t.CPtr = bases_e.get(bi_e) + if base_e is None: + continue + base_name_e: str = None + if base_e.kind() == ast.ASTKind.Name: + base_name_e = ((ast.Name | t.CPtr)(base_e)).id + elif base_e.kind() == ast.ASTKind.Attribute: + base_at_e: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_e) + if base_at_e.attr is not None: + base_name_e = base_at_e.attr + if base_name_e is None: + continue + if string.strcmp(base_name_e, "Exception") == 0: + return 1 + if self.is_exception_name(base_name_e) != 0: + return 1 + return 0 + def _get_exception_parent_name(self, cd: ast.ClassDef | t.CPtr) -> str: + """返回异常类定义的真实父类名(第一个非 Exception 的已注册异常类),无则 None""" + if cd is None or cd.bases is None: + return None + bases_e2: list[ast.AST | t.CPtr] | t.CPtr = cd.bases + bn_e2: t.CSizeT = len(bases_e2) + for bi_e2 in range(bn_e2): + base_e2: ast.AST | t.CPtr = bases_e2.get(bi_e2) + if base_e2 is None: + continue + base_name_e2: str = None + if base_e2.kind() == ast.ASTKind.Name: + base_name_e2 = ((ast.Name | t.CPtr)(base_e2)).id + elif base_e2.kind() == ast.ASTKind.Attribute: + base_at_e2: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_e2) + if base_at_e2.attr is not None: + base_name_e2 = base_at_e2.attr + if base_name_e2 is None: + continue + if string.strcmp(base_name_e2, "Exception") != 0 \ + and self.is_exception_name(base_name_e2) != 0: + return base_name_e2 + return None + def _register_exception_class_def(self, trans: HT.Translator | t.CPtr, + cd: ast.ClassDef | t.CPtr) -> int: + """注册异常类(分配编码 + 记录父类),不生成 struct,返回 0""" + if cd is None or cd.name is None: + return 0 + parent_e: str = self._get_exception_parent_name(cd) + self.register_exception(cd.name, parent_e) + return 0 + def _register_class_meta_list(self, pool: memhub.MemBuddy | t.CPtr, + kind: int, cls: str, value_node: ast.AST | t.CPtr) -> None: + """解析类体 __provides__/__requires__ 的 list[str] 字面量并注册""" + if value_node is None or cls is None: + return + if value_node.kind() != ast.ASTKind.List: + return + lst_rcm: ast.List | t.CPtr = (ast.List | t.CPtr)(value_node) + if lst_rcm.elts is None: + return + elts_rcm: list[ast.AST | t.CPtr] | t.CPtr = lst_rcm.elts + en_rcm: t.CSizeT = len(elts_rcm) + for ei_rcm in range(en_rcm): + el_rcm: ast.AST | t.CPtr = elts_rcm.get(ei_rcm) + if el_rcm is None or el_rcm.kind() != ast.ASTKind.Constant: + continue + ec_rcm: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(el_rcm) + if ec_rcm.str_val is not None: + self.register_class_meta(pool, kind, cls, ec_rcm.str_val) + def register_method_meta(self, class_name: str, method_name: str, + meta: int) -> None: + """注册方法元数据(幂等)""" + if class_name is None or method_name is None or meta == 0: + return + # 懒初始化 + if self.MethodMetaKeys is None: + self.MethodMetaKeys = CompilerFactory.get_perm_pool().alloc(META_MAX * META_KEY_LEN) + self.MethodMetaFlags = CompilerFactory.get_perm_pool().alloc(META_MAX * 4) + if self.MethodMetaKeys is None or self.MethodMetaFlags is None: + return + string.memset(self.MethodMetaKeys, 0, META_MAX * META_KEY_LEN) + string.memset(self.MethodMetaFlags, 0, META_MAX * 4) + # 构造 key "ClassName.method" + cl_len: t.CSizeT = string.strlen(class_name) + mn_len: t.CSizeT = string.strlen(method_name) + key_buf: bytes = stdlib.malloc(cl_len + mn_len + 2) + if key_buf is None: + return + viperlib.snprintf(key_buf, cl_len + mn_len + 2, "%s.%s", class_name, method_name) + # 去重更新 + i: int + for i in range(self.MethodMetaCount): + if string.strcmp(self.MethodMetaKeys + i * META_KEY_LEN, key_buf) == 0: + flags_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid( + t.CUInt64T(self.MethodMetaFlags) + i * 4, t.CPtr)) + # 按位或合并:同一属性名先 @property(getter=4) 再 @x.setter(8)/ + # @x.deleter(16) 会多次注册(如 Config.value / Counter.value)。 + # 若整值替换,后注册的位会覆盖 GETTER 位 → _try_property_getter_attr + # 不再拦截 obj.prop → 落入字段查找失败返回 None → 上游 llvmlite + # 收到 NULL Value → 编译器进程段错误(BuiltinDecoratorTest Phase A 崩溃)。 + flags_ptr[0] = flags_ptr[0] | meta + stdlib.free(key_buf) + return + if self.MethodMetaCount < META_MAX: + # 槽位定长 META_KEY_LEN=128 字节,key 超长时 strncpy 钳制防越界写相邻槽 + string.strncpy(self.MethodMetaKeys + self.MethodMetaCount * META_KEY_LEN, + key_buf, META_KEY_LEN - 1) + flags_ptr2: t.CPtr = (t.CInt | t.CPtr)(t.CVoid( + t.CUInt64T(self.MethodMetaFlags) + self.MethodMetaCount * 4, t.CPtr)) + flags_ptr2[0] = meta + self.MethodMetaCount += 1 + stdlib.free(key_buf) + def lookup_method_meta(self, class_name: str, method_name: str) -> int: + """查找方法元数据位掩码,返回 0=未注册或非装饰器方法""" + if class_name is None or method_name is None: + return 0 + if self.MethodMetaKeys is None or self.MethodMetaCount <= 0: + return 0 + cl_len: t.CSizeT = string.strlen(class_name) + mn_len: t.CSizeT = string.strlen(method_name) + key_buf: bytes = stdlib.malloc(cl_len + mn_len + 2) + if key_buf is None: + return 0 + viperlib.snprintf(key_buf, cl_len + mn_len + 2, "%s.%s", class_name, method_name) + found: int = 0 + i: int + for i in range(self.MethodMetaCount): + if string.strcmp(self.MethodMetaKeys + i * META_KEY_LEN, key_buf) == 0: + flags_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid( + t.CUInt64T(self.MethodMetaFlags) + i * 4, t.CPtr)) + found = flags_ptr[0] + break + stdlib.free(key_buf) + return found + def _is_marker_base(self, base_name: str) -> int: + """检查基类名是否为标记基类,返回 1=是 / 0=否 + + 含 t.Struct:t.py 未定义 Struct 类(不被编译),`class X(t.Struct)` + 的 Struct 只是"普通结构体"标记。若不当成标记基类,会被误判为真实父类: + - 自动启用虚表 → 结构体多出 i8* 槽位(与 TPC 的 {i32,i32} 布局不符) + - Phase A-pre(declare_only=1)父类延迟检查找不到 "Struct" → 类被延迟注册 + → forward_declare 时类型未注册 → 裸类形参退化为 i32 → 函数签名与 + 函数体 alloca(Ptr(struct))不一致 → llc 报 "'%p' defined with type + 'i32' but expected 'ptr'"。 + 与 TPC(_resolve_base_kind 对 t.Struct 返回 None → 无父类)保持一致。 + """ + if base_name is None: + return 0 + if string.strcmp(base_name, "Object") == 0: + return 1 + if string.strcmp(base_name, "CVTable") == 0: + return 1 + if string.strcmp(base_name, "Exception") == 0: + return 1 + if string.strcmp(base_name, "CEnum") == 0: + return 1 + if string.strcmp(base_name, "Enum") == 0: + return 1 + if string.strcmp(base_name, "CStruct") == 0: + return 1 + if string.strcmp(base_name, "Struct") == 0: + return 1 + if string.strcmp(base_name, "CUnion") == 0: + return 1 + if string.strcmp(base_name, "REnum") == 0: + return 1 + return 0 + def _get_base_name(self, base_node: ast.AST | t.CPtr, + pool: memhub.MemBuddy | t.CPtr = None) -> str: + """从 base AST 节点提取基类名,返回 None=失败 + + 对于 Subscript 节点,需要 pool 分配内存拼接特化名; + pool=None 时降级返回基类名(不含类型实参) + """ + if base_node is None: + return None + k: int = base_node.kind() + # Name(id) 形式 + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node) + return nm.id + # Attribute(attr) 形式 + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_node) + return at.attr + # Subscript(value, slice) 形式 — 如 GSListNode[Value] + if k == ast.ASTKind.Subscript: + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(base_node) + if sub is None or sub.value is None or sub.slice is None: + return None + # 提取基类名(如 "GSListNode") + base_nm: str = self._get_base_name(sub.value, pool) + if base_nm is None: + return None + # 提取类型实参名(如 "Value") + slice_k: int = sub.slice.kind() + arg_nm: str = None + if slice_k == ast.ASTKind.Name: + sl_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.slice) + arg_nm = sl_nm.id + # 如果无法提取类型实参,返回基类名(降级) + if arg_nm is None: + return base_nm + # 无 pool 时返回基类名(降级,无法拼接特化名) + if pool is None: + return base_nm + # 拼接特化名 "GSListNode[Value]" + base_len: t.CSizeT = string.strlen(base_nm) + arg_len: t.CSizeT = string.strlen(arg_nm) + total_len: t.CSizeT = base_len + arg_len + 3 # "[" + arg + "]" + NUL + mangled: str = pool.alloc(total_len) + if mangled is None: + return base_nm # 降级 + mangled[0] = '\0' + string.strcat(mangled, base_nm) + string.strcat(mangled, "[") + string.strcat(mangled, arg_nm) + string.strcat(mangled, "]") + return mangled + return None + def _get_parent_class(self, cd: ast.ClassDef | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> str: + """获取 ClassDef 的真实父类名,返回 None=无真实父类""" + if cd is None or cd.bases is None: + return None + pool: memhub.MemBuddy | t.CPtr = None + if trans is not None: + pool = trans.Pool + bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases + bn: t.CSizeT = len(bases) + if bn == 0: + return None + for bi in range(bn): + base_node: ast.AST | t.CPtr = bases.get(bi) + if base_node is None: + continue + bname: str = self._get_base_name(base_node, pool) + if bname is not None: + # 基类别名解析(from t import CStruct as cs → cs 实际是 CStruct)。 + # ClassGen 拆分(47ac2dd)时丢失,EdgeCaseTest Test12 class + # CsPoint(cs) 回归根因:'cs' 被当真实父类 → find_struct("cs") + # 失败 → 类 defer 永不注册 → 变量注解解析失败。 + bname = self._resolve_base_alias(bname, trans) + if self._is_marker_base(bname) == 0: + return bname + return None + def _resolve_base_alias(self, base_name: str, + trans: HT.Translator | t.CPtr = None) -> str: + """解析基类别名:from t import CStruct as cs → 基类 cs 实际是 CStruct。 + + 别名不解析时 "cs" 会被当作真实父类名 → find_struct("cs") 失败 → + PhaseA 预注册把整类 defer(永不注册)→ 变量注解 X 解析失败 + (EdgeCaseTest Test12 class CsPoint(cs): 根因)。 + """ + if base_name is None or trans is None or trans._from_imports is None: + return base_name + orig: str = self.Gen.ImportsGen.lookup_from_import_original( + trans._from_imports, base_name) + if orig is not None: + # lookup_from_import_original 返回 from_imports 内部指针且未 NUL 结尾 + # (如 "CStruct myint:t:CInt CChar:t CPtr:t" 整串直到真正的 NUL)。 + # 复制到独立缓冲并按空格截断出干净原始名——否则 _is_marker_base 的 + # strcmp 对整串比较失败 → 别名基类(CStruct as cs)被当真实父类 → + # find_struct 失败 → 整类 defer 永不注册 → 变量注解解析失败。 + og_len: t.CSizeT = 0 + while orig[og_len] != ' ' and orig[og_len] != '\0': + og_len += 1 + if og_len > 0: + og_buf: str = CompilerFactory.get_perm_pool().alloc(og_len + 1) + if og_buf is not None: + string.strncpy(og_buf, orig, og_len) + og_buf[og_len] = '\0' + return og_buf + return base_name + def _collect_parents(self, pool: memhub.MemBuddy | t.CPtr, + cd: ast.ClassDef | t.CPtr, + parents_buf: t.CSizeT | t.CPtr, + max_parents: int, + trans: HT.Translator | t.CPtr = None) -> int: + """收集所有非 marker 父类名到 parents_buf,返回数量""" + if pool is None or cd is None or cd.bases is None or parents_buf is None: + return 0 + bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases + bn: t.CSizeT = len(bases) + count: int = 0 + for bi in range(bn): + if count >= max_parents: + break + base_node: ast.AST | t.CPtr = bases.get(bi) + if base_node is None: + continue + bname: str = self._get_base_name(base_node, pool) + if bname is not None: + # 基类别名解析(同 _get_parent_class,见 _resolve_base_alias) + bname = self._resolve_base_alias(bname, trans) + if self._is_marker_base(bname) == 0: + parents_buf[count] = t.CSizeT(bname) + count += 1 + return count + def _field_name_exists(self, names_buf: t.CSizeT | t.CPtr, + count: int, name: str) -> int: + """检查字段名是否已在 names_buf 中(先声明父类优先,重复跳过)""" + if names_buf is None or name is None: + return 0 + for fi in range(count): + addr: t.CSizeT = names_buf[fi] + if addr != 0: + existing: str = (str | t.CPtr)(t.CVoid(addr, t.CPtr)) + if existing is not None and string.strcmp(existing, name) == 0: + return 1 + return 0 + def _class_body_has_field(self, cd: ast.ClassDef | t.CPtr) -> int: + """检查类体是否声明了字段(AnnAssign),0=纯方法/无字段类""" + if cd is None or cd.children is None: + return 0 + cn: t.CSizeT = len(cd.children) + for ci in range(cn): + stmt: ast.AST | t.CPtr = cd.children.get(ci) + if stmt is None: + continue + if stmt.kind() == ast.ASTKind.AnnAssign: + return 1 + return 0 + def _trigger_base_specialization(self, trans: HT.Translator | t.CPtr, + cd: ast.ClassDef | t.CPtr): + """触发 base 中 Subscript 的泛型特化(如 GSListNode[Value])""" + if trans is None or cd is None or cd.bases is None: + return + pool: memhub.MemBuddy | t.CPtr = trans.Pool + bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases + bn: t.CSizeT = len(bases) + if bn == 0: + return + for bi in range(bn): + base_node: ast.AST | t.CPtr = bases.get(bi) + if base_node is None: + continue + bk: int = base_node.kind() + if bk != ast.ASTKind.Subscript: + continue + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(base_node) + if sub is None or sub.value is None or sub.slice is None: + continue + # 提取泛型类名(如 "GSListNode") + gen_class_name: str = self._get_base_name(sub.value, pool) + if gen_class_name is None: + continue + # 跳过标记基类 + if self._is_marker_base(gen_class_name) == 1: + continue + # 提取类型实参名(如 "Value") + slice_k: int = sub.slice.kind() + arg_nm: str = None + if slice_k == ast.ASTKind.Name: + sl_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.slice) + arg_nm = sl_nm.id + if arg_nm is None: + continue + # 构建 type_args 列表(elem_size=8:str 是指针,1 会导致双元素重叠损坏) + type_args: list[str] | t.CPtr = list[str](pool, 8) + if type_args is None: + continue + type_args.append(arg_nm) + # 触发特化(_specialize_generic_class 有缓存,重复调用安全) + self.Gen.ClassGenGeneric._specialize_generic_class(trans, gen_class_name, type_args) + def _has_any_func_cvtable(self, cd: ast.ClassDef | t.CPtr) -> int: + """检查类中是否有任何函数标记了 @t.CVTable,返回 1=有 / 0=无""" + if cd is None or cd.children is None: + return 0 + children: list[ast.AST | t.CPtr] | t.CPtr = cd.children + cn: t.CSizeT = len(children) + for ci in range(cn): + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + if stmt.kind() != ast.ASTKind.FunctionDef: + continue + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) + if fd is None or fd.name is None: + continue + # 跳过构造函数 + if string.strcmp(fd.name, "__init__") == 0: + continue + if string.strcmp(fd.name, "__before_init__") == 0: + continue + if string.strcmp(fd.name, "__new__") == 0: + continue + if fd.decorator_list is not None: + if self._has_decorator(fd.decorator_list, "CVTable") == 1: + return 1 + return 0 + def _should_method_be_virtual(self, cd: ast.ClassDef | t.CPtr, + fd: ast.FunctionDef | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> int: + """判断方法是否应该进入虚表,返回 1=包含 / 0=排除""" + if fd is None: + return 0 + # 1. 检查函数级 @t.NoVTable(最高优先级,排除) + if fd.decorator_list is not None: + if self._has_decorator(fd.decorator_list, "NoVTable") == 1: + return 0 + # 2. 检查函数级 @t.CVTable(明确包含) + if self._has_decorator(fd.decorator_list, "CVTable") == 1: + return 1 + + # 3. 检查类级别 @t.CVTable + if cd is not None and cd.decorator_list is not None: + if self._has_decorator(cd.decorator_list, "CVTable") == 1: + return 1 + + # 4. 检查继承关系 + parent_name: str = self._get_parent_class(cd, trans) + if parent_name is not None: + # 用 SHA1 感知查找父类,规避跨模块同名找错 + is_nvt: int = 0 + if trans is not None: + p_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module( + parent_name, trans.ModuleSha1) + if p_entry is None: + # 跨模块父类回退全局查找(父类注册在父模块 SHA1 下,如 linkedlist.LinkedNode), + # 与字段展平(1.5 节)的回退保持一致,否则父类 NoVTable 被误判为有虚表 → 子类插 vptr + # 导致子类布局比父类多一个指针,父类方法按无 vptr 布局操作错位 + p_entry = self.Gen.StructGen.find_struct(parent_name) + if p_entry is not None: + is_nvt = p_entry.IsNoVTable + else: + is_nvt = self.Gen.StructGen.is_novtable_by_name(parent_name) + if is_nvt != 1: + # 继承链统一虚表:父类有虚表 → 方法进虚表;父类无虚表 → 静态方法。 + # 与 _detect_vtable_status 规则一致,避免父类无 vptr 布局/子类有 vptr 的错位。 + if p_entry is None: + return 1 # 父类信息未知,保守进虚表 + if p_entry.HasVTable == 1: + return 1 + return 0 + + # 5. 默认排除 + return 0 + def _detect_vtable_status(self, cd: ast.ClassDef | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> int: + """检测类是否应该启用虚表""" + if cd is None: + return 0 + + # 检查类装饰器 + if cd.decorator_list is not None: + # @t.CVTable 优先级最高,直接启用 + if self._has_decorator(cd.decorator_list, "CVTable") == 1: + return 1 + # @t.NoVTable:类级别禁用,但检查函数级 @t.CVTable + if self._has_decorator(cd.decorator_list, "NoVTable") == 1: + return self._has_any_func_cvtable(cd) + + # 检查是否有真实父类(继承自动启用 CVTable) + parent_name: str = self._get_parent_class(cd, trans) + if parent_name is not None: + # 用 SHA1 感知查找父类,规避跨模块同名找错 + is_nvt: int = 0 + if trans is not None: + p_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module( + parent_name, trans.ModuleSha1) + if p_entry is None: + # 跨模块父类回退全局查找(同 _detect_vtable_status 的回退) + p_entry = self.Gen.StructGen.find_struct(parent_name) + if p_entry is not None: + is_nvt = p_entry.IsNoVTable + else: + is_nvt = self.Gen.StructGen.is_novtable_by_name(parent_name) + if is_nvt == 1: + # 父类是 NoVTable,检查函数级 @t.CVTable + return self._has_any_func_cvtable(cd) + # 继承链统一虚表:父类有虚表 → 子类启用;父类无虚表 → 子类静态。 + # 若父类无 vtable 而子类有,父类方法按无 vptr 布局(self.field@0)操作 + # 子类实例(有 vptr@0)会字段错位 → 运行时错误(父类方法读 vptr 当字段)。 + if p_entry is None: + return 1 # 父类信息未知(跨模块/未注册),保守启用虚表 + if p_entry.HasVTable == 1: + return 1 + return 0 + + # 默认(无装饰器无继承),检查函数级 @t.CVTable + return self._has_any_func_cvtable(cd) + def InitClassGen(self) -> int: + """初始化 ClassGen 族字段(构造时由 Generator 调用)""" + if self is None: + return 1 + self.MethodMetaKeys = None + self.MethodMetaFlags = None + self.MethodMetaCount = 0 + self.RenumClassNames = None + self.RenumClassVariantCounts = None + self.RenumVariantNames = None + self.RenumVariantTags = None + self.RenumClassCount = 0 + self.RenumAliasClass = None + self.RenumAliasField = None + self.RenumAliasIndex = None + self.RenumAliasCount = 0 + self.SpecKeys = None + self.SpecNames = None + self.SpecCount = 0 + self.GenericClassNames = None + self.GenericClassNodes = None + self.GenericClassSha1s = None + self.GenericClassFiles = None + self.GenericClassTpParams = None + self.VtFullNames = None + self.VtMethodNames = None + self.VtParentSha1s = None + self.VtMethodCount = 0 + self.RenumAliasTy = None + self.RenumAliasVariant = None + self.ClassMetaKinds = None + self.ClassMetaClss = None + self.ClassMetaFields = None + self.ClassMetaCount = 0 + self.DecoratorFuncCount = 0 + self.DecoratorFuncNames = None + self.DecoratorWrapNames = None + self.DecoratorArgs = None + self.ExceptionCount = 0 + self.ExceptionNames = None + self.ExceptionParents = None + self.ExceptionCodes = None + self.NextExceptionCode = 0 + self._exception_codes_tmp_count = 0 + self.GenericSpecDepth = 0 + return 0 diff --git a/App/lib/core/Gen/ClassGenDef.vp b/App/lib/core/Gen/ClassGenDef.vp index db5de5e..b3b5325 100644 --- a/App/lib/core/Gen/ClassGenDef.vp +++ b/App/lib/core/Gen/ClassGenDef.vp @@ -1,577 +1,571 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import viperlib -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesEnum as HandlesEnum -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.StubMerger as StubMerger -import lib.core.CompilerFactory as CompilerFactory - - -import lib.core.Gen.ClassGenBase as ClassGenBase - -# ============================================================ -# ClassGenDef - ClassGenMixin 拆分(阶段 D):translate_class_def 主入口 -# -# 继承 ClassGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesClassDef 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class ClassGenDef(ClassGenBase.ClassGenBase): - """translate_class_def 主入口""" - - # ============================================================ - # translate_class_def — 翻译 class 定义(簇 D) - # ============================================================ - def translate_class_def(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 class 定义,返回 0""" - if node is None or trans is None: - return 0 - - cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(node) - if cd is None or cd.name is None: - return 0 - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - class_name: str = cd.name - - if trans.ModuleSha1 is None: - # fail-fast:翻译类时模块 SHA1 缺失(命名空间隔离依赖它)—— - VLogger.error("翻译类时 ModuleSha1 缺失", "CLASS") - HandlesType.fatal_error(cd, "翻译类时 ModuleSha1 缺失", "TypeError") - - # 命名空间隔离:标记为当前文件可见(必须在 existing 检查之前, - # 因为 Phase B 时结构体已注册会提前 return,否则永远无法标记本地类) - HandlesStruct.add_visible_struct(pool, class_name) - - # 枚举类:交给 HandlesEnum 处理 - if HandlesClassDef._is_enum_class(cd, trans) == 1: - return HandlesClassDef._translate_enum_def(trans, cd) - - # 联合体类:交给联合体处理 - if HandlesClassDef._is_union_class(cd, trans) == 1: - return HandlesClassDef._translate_union_def(trans, cd) - - # REnum 类:交给 REnum 处理({i32 tag, max_payload} 布局) - if HandlesClassDef._is_renum_class(cd, trans) == 1: - return HandlesClassDef._translate_renum_def(trans, cd) - - # 泛型类:存储为模板,不发射 IR(等实例化时特化) - # 用局部变量接收 cd.type_params,触发类型推断 - tp_val: list[str] | t.CPtr = cd.type_params - if HandlesClassDef._is_generic_class(tp_val) == 1: - HandlesClassDef._register_generic_template(pool, cd, trans.ModuleSha1) - return 0 - - # 异常类(try-except):注册编码+继承树,不生成 struct - # (对齐 TPC HandlesClassDef.py L509-511:_is_exception_class → - # _RegisterExceptionClass → return,异常类不编译为结构体) - if HandlesClassDef._is_exception_class_def(cd) == 1: - return HandlesClassDef._register_exception_class_def(trans, cd) - - # 检查是否已注册(用 SHA1 区分跨模块同名类) - existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( - class_name, trans.ModuleSha1) - if existing is not None: - # BUG 5 方案1修改点2:existing 时字段完整性检查 - # 结构体已注册,但需验证字段信息是否完整(防止 i32 回退残留或注册不完整) - # 注意:无字段类(接口/标记类,类体无 AnnAssign)合法(空 struct + 方法), - # 仅当"类体声明了字段但 FieldCount==0"才算注册不完整(Phase A-pre 漏注册)。 - if existing.FieldCount == 0 and trans._declare_only == 0: - if HandlesClassDef._class_body_has_field(cd) != 0: - # Phase B 时字段数为 0 说明注册不完整(Phase A-pre 可能漏注册) - HandlesType.fatal_error( - node, - f"结构体已注册但字段数为0,类: {class_name},可能注册不完整", - "InternalCompilerError") - # 结构体已注册(Phase A-pre 多遍扫描或 Phase B 重新翻译),但仍需在当前模块中翻译方法 - if existing.Ty is not None: - # Phase 1b(declare_only=0):existing.Ty 是 Phase 1a 注册的 struct_ty, - # 其 Name(如 "sha1.ClassName")指向 Phase 1a 的 pool 内存。虽然 mark1 - # 之前分配不被 reset 回收,但 struct_ty 会被后续文件翻译引用(vtable/ - # self 参数类型打印),部分实现下 pool 块被复用导致 Name 悬空崩溃。 - # 保险起见:深拷贝 Name 到 stdlib,确保跨文件永久存活。 - if trans._declare_only == 0: - # 深拷贝整个 existing.Ty 到 stdlib:1a pool Ty 跨 1b reset 悬空, - # _ensure_field_types_in_module 遍历悬空字段 ParamNode 链表 - # 读悬空挂起(G3 LinkedNode.prepend 挂起根因)。DeepCopyType - # 递归深拷贝字段链表/子类型/Name 到 stdlib(深度上限+链守卫)。 - ty_deep: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( - CompilerFactory.get_perm_pool(), existing.Ty) - if ty_deep is not None: - existing.Ty = ty_deep - old_name: str = llvmlite.get_struct_name(existing.Ty) - if old_name is not None: - on_len: t.CSizeT = string.strlen(old_name) - on_copy: str = CompilerFactory.get_perm_pool().alloc(on_len + 1) - if on_copy is not None: - string.strcpy(on_copy, old_name) - c.DerefAs(existing.Ty, llvmlite.LLVMType.Struct( - llvmlite.get_struct_fields(existing.Ty), - llvmlite.get_struct_fcount(existing.Ty), - on_copy)) - # Phase B: 将已存在的命名结构体注册到当前模块(输出类型定义行) - llvmlite.module_add_named_type(trans.Module, pool, existing.Ty) - # Phase A-pre(declare_only=1)多遍扫描时,类已注册但不应翻译方法体 - # Phase B(declare_only=0)时全量翻译方法体 - if trans._declare_only == 1: - HandlesClassDef._translate_oop_methods(trans, cd, existing.Ty, class_name, 1) - else: - HandlesClassDef._translate_oop_methods(trans, cd, existing.Ty, class_name) - # SHA1 已在 register_struct 时设置,无需再补 - return 0 - - # ============================================================ - # 触发 base 中 Subscript 的泛型特化(如 GSListNode[Value]) - # 必须在 _detect_vtable_status 和父类字段继承之前调用, - # 否则 find_struct_by_module("GSListNode[Value]") 返回 None - # ============================================================ - HandlesClassDef._trigger_base_specialization(trans, cd) - - # ============================================================ - # VTable 检测:判断是否启用虚表 - # ============================================================ - has_vtable: int = HandlesClassDef._detect_vtable_status(cd, trans) - parent_name: str = HandlesClassDef._get_parent_class(cd, trans) - # 多继承:收集所有真实父类名(跳过 marker base),供字段展平/vtable/MRO 使用 - parents_buf: t.CSizeT | t.CPtr = pool.alloc(8 * HandlesStruct.PARENT_MAX) - parents_count: int = 0 - if parents_buf is not None: - parents_count = HandlesClassDef._collect_parents(pool, cd, parents_buf, HandlesStruct.PARENT_MAX, trans) - is_novtable_deco: int = 0 - if cd.decorator_list is not None: - if HandlesClassDef._has_decorator(cd.decorator_list, "NoVTable") == 1: - is_novtable_deco = 1 - - # ============================================================ - # PhaseA 预注册延迟检查:父类未注册时延迟注册当前类 - # - # 根因:AssignHandle(HandlesBase.Mixin) 有自己的字段 _CurrentClass, - # 当 Mixin 未注册时(字母序:HandlesAssign.py 在 HandlesBase.py 之前), - # field_count=1(不是0),field_count==0 静默返回不触发, - # AssignHandle 被注册为只有 _CurrentClass 字段(缺 Trans)。 - # 后续遍 existing is not None,不补字段 → attribute ptr is None: self.Trans - # - # 修复:declare_only==1 且父类未注册时,延迟注册到下一遍。 - # 多遍 PhaseA-pre 会在后续遍中重试(父类已注册后完整注册)。 - # Phase B(declare_only==0)不延迟,避免死锁。 - # ============================================================ - if trans._declare_only == 1 and parent_name is not None: - parent_check: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( - parent_name, trans.ModuleSha1) - if parent_check is None: - parent_check = HandlesStruct.find_struct(parent_name) - if parent_check is None: - return 0 - - # ============================================================ - # 1. 遍历 class body,收集字段信息 - # ============================================================ - # 用 CSizeT 数组存储指针值(64 位系统上 8 字节) - field_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * HandlesStruct.FIELD_MAX) - field_types_buf: t.CSizeT | t.CPtr = pool.alloc(8 * HandlesStruct.FIELD_MAX) - field_defaults_buf: t.CSizeT | t.CPtr = pool.alloc(8 * HandlesStruct.FIELD_MAX) - field_annot_buf: t.CSizeT | t.CPtr = pool.alloc(8 * HandlesStruct.FIELD_MAX) - if field_names_buf is None or field_types_buf is None or field_defaults_buf is None: - return 0 - if field_annot_buf is None: - return 0 - string.memset(field_names_buf, 0, 8 * HandlesStruct.FIELD_MAX) - string.memset(field_types_buf, 0, 8 * HandlesStruct.FIELD_MAX) - string.memset(field_defaults_buf, 0, 8 * HandlesStruct.FIELD_MAX) - string.memset(field_annot_buf, 0, 8 * HandlesStruct.FIELD_MAX) - - field_count: int = 0 - - # ============================================================ - # 1.5 继承父类字段(字段展平) - # ============================================================ - # - # 父类字段排在子类字段之前,结构体布局: - # [vtable_ptr?, parent_field1, ..., child_field1, ...] - # 跳过父类的 __vtable__ 字段(子类会有自己的 vtable 指针) - # ============================================================ - # 多继承字段展平:遍历所有父类(声明顺序),字段名去重(先声明优先) - if parents_count > 0 and parents_buf is not None: - for pi in range(parents_count): - pname_addr: t.CSizeT = parents_buf[pi] - if pname_addr == 0: - continue - pname: str = (str | t.CPtr)(t.CVoid(pname_addr, t.CPtr)) - if pname is None: - continue - # 用 SHA1 感知查找父类,规避跨模块同名找错 - parent_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( - pname, trans.ModuleSha1) - if parent_entry is None: - # 父类可能定义在另一个模块(不同 SHA1,如 HandlesBase.Mixin), - # find_struct_by_module 不回退全局查找,此处手动回退到 find_struct, - # 否则子类无法继承父类字段 → field_count==0 → __sizeof__ 失败 - parent_entry = HandlesStruct.find_struct(pname) - if parent_entry is None: - # 父类尚未注册(依赖模块未翻译:Phase A 按文件序,子类模块可能 - # 先于父类模块,如 Generator.vp G < TypeGenMixin.vp T)。此时 - # **不能**继续注册——StructTable 在 StdlibAlloc=1 时用 perm_pool - # 分配(init_struct_table L136-140),残缺条目跨 pass 存活, - # 后续 pass 的 existing 早退(L2995-3006)永远无法修复 → 子类 - # __init__ 写父类字段(self.TraceFrames)每遍永久失败。 - # 整类 defer(不注册)+ 标记 _deps_pending 下遍重译;模块级 - # 变量/函数参数解析失败静默降级 i32(handle_module_level_var - # L422-426 / FuncGenMixin L482-483),不致命,本遍文件不写盘。 - if trans is not None: - trans._deps_pending = 1 - return 0 - pfc: int = parent_entry.FieldCount - for pfi in range(pfc): - pfe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( - parent_entry, pfi) - if pfe is None: - continue - pfn: str = HandlesStruct.get_field_name_ptr(pfe) - if pfn is None: - continue - # 跳过父类的 vtable 指针字段 - if string.strcmp(pfn, "__vtable__") == 0: - continue - # 多继承去重:字段名已存在跳过(先声明父类优先) - if HandlesClassDef._field_name_exists(field_names_buf, field_count, pfn) != 0: - continue - if field_count < HandlesStruct.FIELD_MAX: - pft: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_field_type_ptr(pfe) - pfd: ast.AST | t.CPtr = HandlesStruct.get_field_default_ptr(pfe) - pfa: str = HandlesStruct.get_field_annot_class_name(pfe) - field_names_buf[field_count] = t.CSizeT(pfn) - field_types_buf[field_count] = t.CSizeT(pft) - if pfd is not None: - field_defaults_buf[field_count] = t.CSizeT(pfd) - else: - field_defaults_buf[field_count] = 0 - if pfa is not None: - stored_val: t.CSizeT = t.CSizeT(pfa) - field_annot_buf[field_count] = stored_val - else: - field_annot_buf[field_count] = 0 - field_count += 1 - - children: list[ast.AST | t.CPtr] | t.CPtr = cd.children - if children is None: - return 0 - - cn: t.CSizeT = len(children) - for ci in range(cn): - stmt: ast.AST | t.CPtr = children.get(ci) - if stmt is None: - continue - sk: int = stmt.kind() - - if sk != ast.ASTKind.AnnAssign: continue - - # AnnAssign(target=Name(id), annotation=type, value=...) - aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) - if aa is None or aa.target is None: - continue - - # 获取字段名 - if aa.target.kind() != ast.ASTKind.Name: - continue - tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) - if tgt.id is None: - continue - - # 类体 CDefine 常量(任意位置,2026-08-10):注册到全局 CDefine 表。 - # 方法内裸名(如 ISINSTANCE_CLASS_MAX)经 translate_name_value 查 - # CDefine 表解析为常量值;类体开头的常量(MRO_MAX 等)由早期预注册 - # 路径注册,但方法之后的 AnnAssign 不经过那些路径 → 此处统一兜底注册。 - if HandlesAnnAssign.is_cdefine_annotation(aa.annotation) != 0: - if aa.value is not None: - HandlesAnnAssign._register_cdefine_from_value(pool, tgt.id, aa.value) - # CDefine 字段类型固定 i32,直接收集后跳过通用注解解析: - # resolve_annotation_type 不识别 "CDefine"(map_t_type/CTypedef - # 表均无此名),类体尾部常量(ISINSTANCE_CLASS_MAX 是首个触发 - # 该路径的实例)Phase B 会 NameError: 't.CDefine' is not defined。 - # 与类头常量(MRO_MAX 等)的 i32 字段语义保持一致。 - if field_count < HandlesStruct.FIELD_MAX: - cdef_ty_l: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if cdef_ty_l is not None: - field_names_buf[field_count] = t.CSizeT(tgt.id) - field_types_buf[field_count] = t.CSizeT(cdef_ty_l) - if aa.value is not None: - field_defaults_buf[field_count] = t.CSizeT(aa.value) - else: - field_defaults_buf[field_count] = 0 - field_count += 1 - continue - - # 跳过编译期元数据字段(__provides__/__requires__/__require_must__) - # 这些字段只用于 with 上下文的静态可达性检查,不生成运行时代码 - # (FakeDuck:_str.__requires__=['__mbuddy__'])。此处解析 list[str] - # 字面量注册到持久元数据表,供 requires 注入 / with provider 查询。 - if string.strcmp(tgt.id, "__provides__") == 0: - HandlesClassDef._register_class_meta_list(pool, HandlesType.CLASS_META_PROVIDES, class_name, aa.value) - continue - if string.strcmp(tgt.id, "__requires__") == 0: - HandlesClassDef._register_class_meta_list(pool, HandlesType.CLASS_META_REQUIRES, class_name, aa.value) - continue - if string.strcmp(tgt.id, "__require_must__") == 0: - HandlesClassDef._register_class_meta_list(pool, HandlesType.CLASS_META_REQUIRE_MUST, class_name, aa.value) - continue - - # 解析字段类型 - field_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, aa.annotation, trans._imported_modules, trans._from_imports, trans) - # 单参 t.CArray[elem] + 列表字面量 → 静态数组 [N x elem] - # (与局部 AnnAssign 路径一致,对齐 TPC ParseListAnnotation 语义): - # 否则字段保持 Ptr(elem)(如 t.CArray[str] → i8**), - # for x in self.field 会误走指针迭代(元素非整数 → null 终止符 - # 检查失败报错)。推断为静态数组后走数组迭代(按长度 N)。 - if field_ty is not None: - field_ty = HandlesAnnAssign._infer_static_array_ty_from_literal( - pool, aa.annotation, aa.value, field_ty) - if field_ty is None: - # BUG 5 方案1修改点1:消除 i32 静默回退 - # Phase A-pre(declare_only=1):依赖的类可能尚未注册,延迟到下一遍 - # Phase B(declare_only=0):真正的类型解析错误,fast-fail 终止该类翻译 - # 不再用 i32 回退(会导致结构体布局错误 + GEP 索引错乱) - # 例外:泛型 Subscript(如 list[AST|t.CPtr])未特化时回退为 Ptr(i8), - # 因为泛型特化可能延迟到构造调用时。AnnotClassName 会携带 mangled name - # 供 translate_attribute 做后续 bitcast。 - is_generic_sub: int = 0 - if aa.annotation is not None and aa.annotation.kind() == ast.ASTKind.Subscript: - is_generic_sub = 1 - if is_generic_sub != 0: - # 泛型未特化:回退为 Ptr(i8),依赖 AnnotClassName 做后续类型恢复 - field_ty = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - else: - # Phase A-pre(declare_only=1):依赖的类可能尚未注册, - # 静默 return 0 让多遍收敛机制生效(下一遍依赖类已注册即可成功) - if trans._declare_only == 1: - return 0 - # Phase A(declare_only=0,Phase2.vp L573 多遍):依赖模块按 - # 文件序可能晚于本模块翻译(如 TypeGenMixin.vp G < HandlesType.vp - # H,TraceFrames 注解的 HandlesType.TraceFrame 未注册)→ 标记 - # _deps_pending 下遍重译,不在本遍以残缺字段注册结构体。 - # 真正的类型错误由 Phase A 收敛检查暴露("Phase A 无法完成 - # 翻译: ,请检查依赖模块是否已编译/注册"),不静默掩盖。 - if trans is not None: - trans._deps_pending = 1 - return 0 - # 旧行为:fast-fail NameError(已移除——Phase A 依赖未就绪时 - # 误报真实错误,中断多遍收敛;真实错误交给收敛检查兜底) - - # 存储到数组(指针转 CSizeT) - if field_count < HandlesStruct.FIELD_MAX: - diag_name_val: t.CSizeT = t.CSizeT(tgt.id) - field_names_buf[field_count] = diag_name_val - field_types_buf[field_count] = t.CSizeT(field_ty) - # 存储默认值 AST 指针(None=无默认值) - if aa.value is not None: - field_defaults_buf[field_count] = t.CSizeT(aa.value) - else: - field_defaults_buf[field_count] = 0 - # 提取原始类型注解的类名(联合类型简化为 Ptr(i8) 时回退查找结构体) - # BUG 1 方案3:传 pool 使泛型 Subscript 返回 mangled name(如 "list[ast.AST|t.CPtr]") - if aa.annotation is not None: - annot_cn: str = HandlesType.extract_class_name_from_annotation( - aa.annotation, trans._imported_modules, pool) - if annot_cn is not None: - diag_cn_val: t.CSizeT = t.CSizeT(annot_cn) - field_annot_buf[field_count] = diag_cn_val - else: - field_annot_buf[field_count] = 0 - else: - field_annot_buf[field_count] = 0 - field_count += 1 - - if field_count == 0: - # PhaseA 预注册时,父类可能尚未注册(字母序单遍扫描), - # 导致子类无法继承父类字段 → field_count==0。 - # 静默返回,Phase2.py 的多遍 PhaseA-pre 会在后续遍中重试。 - if trans._declare_only == 1 and parent_name is not None: - return 0 - # 无字段类(接口/标记类):不能整体跳过——类可能只有方法 - # (如多继承中的 ShapeM/Vec2Extra),需注册类并翻译方法。 - # 空 struct 在 LLVM 中合法({});@t.CVTable 类由下方补 vtable 指针字段。 - - # ============================================================ - # 2. 创建 LLVM StructType - # ============================================================ - # 构建 ParamNode 链表 - first_node: llvmlite.ParamNode | t.CPtr = None - prev_node: llvmlite.ParamNode | t.CPtr = None - total_field_count: int = field_count - - # 如果有虚表,首字段添加 i8* vtable 指针 - if has_vtable == 1: - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - vtable_node: llvmlite.ParamNode | t.CPtr = pool.alloc(llvmlite.ParamNode.__sizeof__()) - if vtable_node is None: - fb_vn: str = VLogger.fmt_buf() - if fb_vn is not None: - viperlib.snprintf(fb_vn, 1024, "failed to alloc vtable node for %s", class_name) - VLogger.error(fb_vn, "CLASS") - return 0 - string.memset(vtable_node, 0, llvmlite.ParamNode.__sizeof__()) - vtable_node.Ty = i8_ptr_ty - first_node = vtable_node - prev_node = vtable_node - total_field_count = field_count + 1 - - for fi in range(field_count): - fty_addr: t.CSizeT = field_types_buf[fi] - if fty_addr == 0: - continue - fty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(t.CVoid(fty_addr, t.CPtr)) - - # 创建 ParamNode - pnode: llvmlite.ParamNode | t.CPtr = pool.alloc(llvmlite.ParamNode.__sizeof__()) - if pnode is None: - continue - string.memset(pnode, 0, llvmlite.ParamNode.__sizeof__()) - pnode.Ty = fty - - if first_node is None: - first_node = pnode - if prev_node is not None: - prev_node.Next = pnode - prev_node = pnode - - # 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName" - # 注意: Phase 1b(declare_only=0)时 struct_ty 会注册到全局表并被后续 - # 文件翻译引用(vtable/self 参数类型打印),其 Name 必须跨 1b 每文件 - # reset_to(mark1) 存活 → 用 stdlib 深拷贝;Phase 1a 仍用 pool(无需跨文件)。 - type_name: str = class_name - if trans.ModuleSha1 is not None: - name_buf: str = pool.alloc(64) - if name_buf is not None: - viperlib.snprintf(name_buf, 64, "%s.%s", trans.ModuleSha1, class_name) - type_name = name_buf - if trans._declare_only == 0 and type_name is not None: - tn_len: t.CSizeT = string.strlen(type_name) - tn_copy: str = CompilerFactory.get_perm_pool().alloc(tn_len + 1) - if tn_copy is not None: - string.strcpy(tn_copy, type_name) - type_name = tn_copy - - # 创建 StructType(命名结构体) - struct_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, first_node, total_field_count, type_name) - if struct_ty is None: - fb_st: str = VLogger.fmt_buf() - if fb_st is not None: - viperlib.snprintf(fb_st, 1024, "failed to create StructType for %s", class_name) - VLogger.error(fb_st, "CLASS") - return 0 - - # Phase 1b(declare_only=0)新注册的 struct_ty 会被注册到全局表并被后续文件 - # 翻译引用(vtable/self 参数类型打印/find_struct_by_type 指针匹配)。LLVMType - # 对象和 Fields 链是 pool 分配的,本文件 reset_to(mark1) 后悬空。深拷贝整棵树 - # 到 stdlib,并替换 struct_ty 指针,保证 entry.Ty 与调用方持有的 struct_ty - # 指向同一个 stdlib 拷贝(指针匹配不失效)且跨文件永久存活。 - # StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:Phase A-pre-inc(declare_only=1) - # 预注册 includes 时若仍用 pool struct_ty,reset_to(mark2) 后 entry.Ty 悬空 → - # 后续文件字段类型引用(resolve → Ptr(entry.Ty))→ opaque 扫描遍历悬空 fields - # 崩溃(LoopTest _scan_type_for_cross_module_refs 0xFFFF 根因)。 - if trans._declare_only == 0 or HandlesStruct.get_stdlib_alloc() != 0: - st_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( - CompilerFactory.get_perm_pool(), struct_ty) - if st_copy is not None: - struct_ty = st_copy - type_name = llvmlite.get_struct_name(struct_ty) - - # 注册命名结构体到模块(输出 %"name" = type { ... } 定义行) - llvmlite.module_add_named_type(trans.Module, pool, struct_ty) - - # 扫描字段类型,为跨模块结构体引用添加 opaque 声明 - # 例如 list[int].__pool__ 引用 memhub.MemManager,需要在当前模块添加 %"sha1.MemManager" = type opaque - for fi in range(field_count): - fty_addr_op: t.CSizeT = field_types_buf[fi] - if fty_addr_op == 0: - continue - fty_op: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(t.CVoid(fty_addr_op, t.CPtr)) - llvmlite.module_ensure_opaque_for_type(trans.Module, pool, fty_op) - - # ============================================================ - # 3. 注册到 HandlesStruct - # ============================================================ - entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.register_struct( - pool, class_name, struct_ty, trans.ModuleSha1) - if entry is None: - fb_re: str = VLogger.fmt_buf() - if fb_re is not None: - viperlib.snprintf(fb_re, 1024, "failed to register %s", class_name) - VLogger.error(fb_re, "CLASS") - return 0 - - # 标记 VTable 状态(直接用 entry,规避跨模块同名 find_struct 找错) - if has_vtable == 1: - entry.HasVTable = 1 - if is_novtable_deco == 1: - entry.IsNoVTable = 1 - if parent_name is not None: - # 1b 阶段父类名是 pool 字符串(本文件 AST/1a 预存),reset 后悬空; - # _translate_oop_methods/_detect_vtable_status 会在后续文件 - # find_struct(ParentName) strcmp 解引用 → 用 stdlib 拷贝保证跨文件存活 - if HandlesStruct.get_stdlib_alloc() != 0: - pn_len: t.CSizeT = string.strlen(parent_name) - pn_buf: str = CompilerFactory.get_perm_pool().alloc(pn_len + 1) - if pn_buf is not None: - string.strcpy(pn_buf, parent_name) - entry.ParentName = pn_buf - else: - entry.ParentName = parent_name - # 多继承:设置父类数组(供 MRO/字段/vtable 查询,stdlib 深拷贝跨文件存活) - if parents_count > 0 and parents_buf is not None: - HandlesStruct.set_parent_names(pool, class_name, parents_buf, parents_count) - - # 添加字段信息 - # 如果有虚表,先添加 __vtable__ 字段占位(索引 0),用户字段从索引 1 开始 - if has_vtable == 1: - i8_ptr_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - HandlesStruct.add_field(pool, entry, "__vtable__", i8_ptr_ty2, None, None) - - for fi in range(field_count): - fname_addr: t.CSizeT = field_names_buf[fi] - if fname_addr == 0: - continue - fname: str = (str | t.CPtr)(t.CVoid(fname_addr, t.CPtr)) - fty_addr2: t.CSizeT = field_types_buf[fi] - if fty_addr2 == 0: - continue - fty2: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(t.CVoid(fty_addr2, t.CPtr)) - # 恢复默认值 AST 指针 - fdef_addr: t.CSizeT = field_defaults_buf[fi] - fdef: ast.AST | t.CPtr = None - if fdef_addr != 0: - fdef = (ast.AST | t.CPtr)(t.CVoid(fdef_addr, t.CPtr)) - # 恢复注解类名指针 - fannot_addr: t.CSizeT = field_annot_buf[fi] - fannot: str = None - if fannot_addr != 0: - fannot = (str)(t.CVoid(fannot_addr, t.CPtr)) - if fname is not None and fty2 is not None: - HandlesStruct.add_field(pool, entry, fname, fty2, fdef, fannot) - - # Phase 1a 声明模式:只注册 struct + 设置 OOP 标志,不翻译方法体 - if trans._declare_only == 1: - HandlesClassDef._translate_oop_methods(trans, cd, struct_ty, class_name, 1) - return 0 - - # ============================================================ - # 4. OOP 方法处理:扫描 FunctionDef,标记 OOP,翻译方法,生成 __before_init__ - # ============================================================ - HandlesClassDef._translate_oop_methods(trans, cd, struct_ty, class_name) - +import lib.core.Gen.GenTypes as GenTypes +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HT +import lib.core.StubMerger as StubMerger +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.ClassGenBase as ClassGenBase + +# ============================================================ +# ClassGenDef - ClassGenMixin 拆分(阶段 D):translate_class_def 主入口 +# +# 继承 ClassGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesClassDef 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class ClassGenDef(ClassGenBase.ClassGenBase): + """translate_class_def 主入口""" + + # ============================================================ + # translate_class_def — 翻译 class 定义(簇 D) + # ============================================================ + def translate_class_def(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 class 定义,返回 0""" + if node is None or trans is None: + return 0 + + cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(node) + if cd is None or cd.name is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + class_name: str = cd.name + + if trans.ModuleSha1 is None: + # fail-fast:翻译类时模块 SHA1 缺失(命名空间隔离依赖它)—— + VLogger.error("翻译类时 ModuleSha1 缺失", "CLASS") + self.Gen.TypeGenErr.fatal_error(cd, "翻译类时 ModuleSha1 缺失", "TypeError") + + # 命名空间隔离:标记为当前文件可见(必须在 existing 检查之前, + # 因为 Phase B 时结构体已注册会提前 return,否则永远无法标记本地类) + self.Gen.StructGen.add_visible_struct(pool, class_name) + + # 枚举类:交给 HandlesEnum 处理 + if self.Gen.ClassGenBase._is_enum_class(cd, trans) == 1: + return self.Gen.ClassGenEnum._translate_enum_def(trans, cd) + + # 联合体类:交给联合体处理 + if self.Gen.ClassGenBase._is_union_class(cd, trans) == 1: + return self.Gen.ClassGenEnum._translate_union_def(trans, cd) + + # REnum 类:交给 REnum 处理({i32 tag, max_payload} 布局) + if self.Gen.ClassGenBase._is_renum_class(cd, trans) == 1: + return self.Gen.ClassGenEnum._translate_renum_def(trans, cd) + + # 泛型类:存储为模板,不发射 IR(等实例化时特化) + # 用局部变量接收 cd.type_params,触发类型推断 + tp_val: list[str] | t.CPtr = cd.type_params + if self.Gen.ClassGenGeneric._is_generic_class(tp_val) == 1: + self.Gen.ClassGenGeneric._register_generic_template(pool, cd, trans.ModuleSha1) + return 0 + + # 异常类(try-except):注册编码+继承树,不生成 struct + # (对齐 TPC HandlesClassDef.py L509-511:_is_exception_class → + # _RegisterExceptionClass → return,异常类不编译为结构体) + if self.Gen.ClassGenBase._is_exception_class_def(cd) == 1: + return self.Gen.ClassGenBase._register_exception_class_def(trans, cd) + + # 检查是否已注册(用 SHA1 区分跨模块同名类) + existing: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module( + class_name, trans.ModuleSha1) + if existing is not None: + # BUG 5 方案1修改点2:existing 时字段完整性检查 + # 结构体已注册,但需验证字段信息是否完整(防止 i32 回退残留或注册不完整) + # 注意:无字段类(接口/标记类,类体无 AnnAssign)合法(空 struct + 方法), + # 仅当"类体声明了字段但 FieldCount==0"才算注册不完整(Phase A-pre 漏注册)。 + if existing.FieldCount == 0 and trans._declare_only == 0: + if self.Gen.ClassGenBase._class_body_has_field(cd) != 0: + # Phase B 时字段数为 0 说明注册不完整(Phase A-pre 可能漏注册) + self.Gen.TypeGenErr.fatal_error( + node, + f"结构体已注册但字段数为0,类: {class_name},可能注册不完整", + "InternalCompilerError") + # 结构体已注册(Phase A-pre 多遍扫描或 Phase B 重新翻译),但仍需在当前模块中翻译方法 + if existing.Ty is not None: + # Phase 1b(declare_only=0):existing.Ty 是 Phase 1a 注册的 struct_ty, + # 其 Name(如 "sha1.ClassName")指向 Phase 1a 的 pool 内存。虽然 mark1 + # 之前分配不被 reset 回收,但 struct_ty 会被后续文件翻译引用(vtable/ + # self 参数类型打印),部分实现下 pool 块被复用导致 Name 悬空崩溃。 + # 保险起见:深拷贝 Name 到 stdlib,确保跨文件永久存活。 + if trans._declare_only == 0: + # 深拷贝整个 existing.Ty 到 stdlib:1a pool Ty 跨 1b reset 悬空, + # _ensure_field_types_in_module 遍历悬空字段 ParamNode 链表 + # 读悬空挂起(G3 LinkedNode.prepend 挂起根因)。DeepCopyType + # 递归深拷贝字段链表/子类型/Name 到 stdlib(深度上限+链守卫)。 + ty_deep: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( + CompilerFactory.get_perm_pool(), existing.Ty) + if ty_deep is not None: + existing.Ty = ty_deep + old_name: str = llvmlite.get_struct_name(existing.Ty) + if old_name is not None: + on_len: t.CSizeT = string.strlen(old_name) + on_copy: str = CompilerFactory.get_perm_pool().alloc(on_len + 1) + if on_copy is not None: + string.strcpy(on_copy, old_name) + c.DerefAs(existing.Ty, llvmlite.LLVMType.Struct( + llvmlite.get_struct_fields(existing.Ty), + llvmlite.get_struct_fcount(existing.Ty), + on_copy)) + # Phase B: 将已存在的命名结构体注册到当前模块(输出类型定义行) + llvmlite.module_add_named_type(trans.Module, pool, existing.Ty) + # Phase A-pre(declare_only=1)多遍扫描时,类已注册但不应翻译方法体 + # Phase B(declare_only=0)时全量翻译方法体 + if trans._declare_only == 1: + self.Gen.ClassGenVTable._translate_oop_methods(trans, cd, existing.Ty, class_name, 1) + else: + self.Gen.ClassGenVTable._translate_oop_methods(trans, cd, existing.Ty, class_name) + # SHA1 已在 register_struct 时设置,无需再补 + return 0 + + # ============================================================ + # 触发 base 中 Subscript 的泛型特化(如 GSListNode[Value]) + # 必须在 _detect_vtable_status 和父类字段继承之前调用, + # 否则 find_struct_by_module("GSListNode[Value]") 返回 None + # ============================================================ + self.Gen.ClassGenBase._trigger_base_specialization(trans, cd) + + # ============================================================ + # VTable 检测:判断是否启用虚表 + # ============================================================ + has_vtable: int = self.Gen.ClassGenBase._detect_vtable_status(cd, trans) + parent_name: str = self.Gen.ClassGenBase._get_parent_class(cd, trans) + # 多继承:收集所有真实父类名(跳过 marker base),供字段展平/vtable/MRO 使用 + parents_buf: t.CSizeT | t.CPtr = pool.alloc(8 * GenTypes.PARENT_MAX) + parents_count: int = 0 + if parents_buf is not None: + parents_count = self.Gen.ClassGenBase._collect_parents(pool, cd, parents_buf, GenTypes.PARENT_MAX, trans) + is_novtable_deco: int = 0 + if cd.decorator_list is not None: + if self.Gen.ClassGenBase._has_decorator(cd.decorator_list, "NoVTable") == 1: + is_novtable_deco = 1 + + # ============================================================ + # PhaseA 预注册延迟检查:父类未注册时延迟注册当前类 + # + # 根因:AssignHandle(HandlesBase.Mixin) 有自己的字段 _CurrentClass, + # 当 Mixin 未注册时(字母序:HandlesAssign.py 在 HandlesBase.py 之前), + # field_count=1(不是0),field_count==0 静默返回不触发, + # AssignHandle 被注册为只有 _CurrentClass 字段(缺 Trans)。 + # 后续遍 existing is not None,不补字段 → attribute ptr is None: self.Trans + # + # 修复:declare_only==1 且父类未注册时,延迟注册到下一遍。 + # 多遍 PhaseA-pre 会在后续遍中重试(父类已注册后完整注册)。 + # Phase B(declare_only==0)不延迟,避免死锁。 + # ============================================================ + if trans._declare_only == 1 and parent_name is not None: + parent_check: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module( + parent_name, trans.ModuleSha1) + if parent_check is None: + parent_check = self.Gen.StructGen.find_struct(parent_name) + if parent_check is None: + return 0 + + # ============================================================ + # 1. 遍历 class body,收集字段信息 + # ============================================================ + # 用 CSizeT 数组存储指针值(64 位系统上 8 字节) + field_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX) + field_types_buf: t.CSizeT | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX) + field_defaults_buf: t.CSizeT | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX) + field_annot_buf: t.CSizeT | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX) + if field_names_buf is None or field_types_buf is None or field_defaults_buf is None: + return 0 + if field_annot_buf is None: + return 0 + string.memset(field_names_buf, 0, 8 * GenTypes.FIELD_MAX) + string.memset(field_types_buf, 0, 8 * GenTypes.FIELD_MAX) + string.memset(field_defaults_buf, 0, 8 * GenTypes.FIELD_MAX) + string.memset(field_annot_buf, 0, 8 * GenTypes.FIELD_MAX) + + field_count: int = 0 + + # ============================================================ + # 1.5 继承父类字段(字段展平) + # ============================================================ + # + # 父类字段排在子类字段之前,结构体布局: + # [vtable_ptr?, parent_field1, ..., child_field1, ...] + # 跳过父类的 __vtable__ 字段(子类会有自己的 vtable 指针) + # ============================================================ + # 多继承字段展平:遍历所有父类(声明顺序),字段名去重(先声明优先) + if parents_count > 0 and parents_buf is not None: + for pi in range(parents_count): + pname_addr: t.CSizeT = parents_buf[pi] + if pname_addr == 0: + continue + pname: str = (str | t.CPtr)(t.CVoid(pname_addr, t.CPtr)) + if pname is None: + continue + # 用 SHA1 感知查找父类,规避跨模块同名找错 + parent_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module( + pname, trans.ModuleSha1) + if parent_entry is None: + # 父类可能定义在另一个模块(不同 SHA1,如 HandlesBase.Mixin), + # find_struct_by_module 不回退全局查找,此处手动回退到 find_struct, + # 否则子类无法继承父类字段 → field_count==0 → __sizeof__ 失败 + parent_entry = self.Gen.StructGen.find_struct(pname) + if parent_entry is None: + # 父类尚未注册(依赖模块未翻译:Phase A 按文件序,子类模块可能 + # 先于父类模块,如 Generator.vp G < TypeGenMixin.vp T)。此时 + # **不能**继续注册——StructTable 在 StdlibAlloc=1 时用 perm_pool + # 分配(init_struct_table L136-140),残缺条目跨 pass 存活, + # 后续 pass 的 existing 早退(L2995-3006)永远无法修复 → 子类 + # __init__ 写父类字段(self.TraceFrames)每遍永久失败。 + # 整类 defer(不注册)+ 标记 _deps_pending 下遍重译;模块级 + # 变量/函数参数解析失败静默降级 i32(handle_module_level_var + # L422-426 / FuncGenMixin L482-483),不致命,本遍文件不写盘。 + if trans is not None: + trans._deps_pending = 1 + return 0 + pfc: int = parent_entry.FieldCount + for pfi in range(pfc): + pfe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry( + parent_entry, pfi) + if pfe is None: + continue + pfn: str = self.Gen.StructGen.get_field_name_ptr(pfe) + if pfn is None: + continue + # 跳过父类的 vtable 指针字段 + if string.strcmp(pfn, "__vtable__") == 0: + continue + # 多继承去重:字段名已存在跳过(先声明父类优先) + if self.Gen.ClassGenBase._field_name_exists(field_names_buf, field_count, pfn) != 0: + continue + if field_count < GenTypes.FIELD_MAX: + pft: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_field_type_ptr(pfe) + pfd: ast.AST | t.CPtr = self.Gen.StructGen.get_field_default_ptr(pfe) + pfa: str = self.Gen.StructGen.get_field_annot_class_name(pfe) + field_names_buf[field_count] = t.CSizeT(pfn) + field_types_buf[field_count] = t.CSizeT(pft) + if pfd is not None: + field_defaults_buf[field_count] = t.CSizeT(pfd) + else: + field_defaults_buf[field_count] = 0 + if pfa is not None: + stored_val: t.CSizeT = t.CSizeT(pfa) + field_annot_buf[field_count] = stored_val + else: + field_annot_buf[field_count] = 0 + field_count += 1 + + children: list[ast.AST | t.CPtr] | t.CPtr = cd.children + if children is None: + return 0 + + cn: t.CSizeT = len(children) + for ci in range(cn): + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + sk: int = stmt.kind() + + if sk != ast.ASTKind.AnnAssign: continue + + # AnnAssign(target=Name(id), annotation=type, value=...) + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) + if aa is None or aa.target is None: + continue + + # 获取字段名 + if aa.target.kind() != ast.ASTKind.Name: + continue + tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) + if tgt.id is None: + continue + + # 类体 CDefine 常量(任意位置,2026-08-10):注册到全局 CDefine 表。 + # 方法内裸名(如 ISINSTANCE_CLASS_MAX)经 translate_name_value 查 + # CDefine 表解析为常量值;类体开头的常量(MRO_MAX 等)由早期预注册 + # 路径注册,但方法之后的 AnnAssign 不经过那些路径 → 此处统一兜底注册。 + if self.Gen.AssignGen.is_cdefine_annotation(aa.annotation) != 0: + if aa.value is not None: + self.Gen.AssignGen._register_cdefine_from_value(pool, tgt.id, aa.value) + # CDefine 字段类型固定 i32,直接收集后跳过通用注解解析: + # resolve_annotation_type 不识别 "CDefine"(map_t_type/CTypedef + # 表均无此名),类体尾部常量(ISINSTANCE_CLASS_MAX 是首个触发 + # 该路径的实例)Phase B 会 NameError: 't.CDefine' is not defined。 + # 与类头常量(MRO_MAX 等)的 i32 字段语义保持一致。 + if field_count < GenTypes.FIELD_MAX: + cdef_ty_l: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if cdef_ty_l is not None: + field_names_buf[field_count] = t.CSizeT(tgt.id) + field_types_buf[field_count] = t.CSizeT(cdef_ty_l) + if aa.value is not None: + field_defaults_buf[field_count] = t.CSizeT(aa.value) + else: + field_defaults_buf[field_count] = 0 + field_count += 1 + continue + + # 跳过编译期元数据字段(__provides__/__requires__/__require_must__) + # 这些字段只用于 with 上下文的静态可达性检查,不生成运行时代码 + # (FakeDuck:_str.__requires__=['__mbuddy__'])。此处解析 list[str] + # 字面量注册到持久元数据表,供 requires 注入 / with provider 查询。 + if string.strcmp(tgt.id, "__provides__") == 0: + self.Gen.ClassGenBase._register_class_meta_list(pool, GenTypes.CLASS_META_PROVIDES, class_name, aa.value) + continue + if string.strcmp(tgt.id, "__requires__") == 0: + self.Gen.ClassGenBase._register_class_meta_list(pool, GenTypes.CLASS_META_REQUIRES, class_name, aa.value) + continue + if string.strcmp(tgt.id, "__require_must__") == 0: + self.Gen.ClassGenBase._register_class_meta_list(pool, GenTypes.CLASS_META_REQUIRE_MUST, class_name, aa.value) + continue + + # 解析字段类型 + field_ty: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, aa.annotation, trans._imported_modules, trans._from_imports, trans) + # 单参 t.CArray[elem] + 列表字面量 → 静态数组 [N x elem] + # (与局部 AnnAssign 路径一致,对齐 TPC ParseListAnnotation 语义): + # 否则字段保持 Ptr(elem)(如 t.CArray[str] → i8**), + # for x in self.field 会误走指针迭代(元素非整数 → null 终止符 + # 检查失败报错)。推断为静态数组后走数组迭代(按长度 N)。 + if field_ty is not None: + field_ty = self.Gen.AssignGen._infer_static_array_ty_from_literal( + pool, aa.annotation, aa.value, field_ty) + if field_ty is None: + # BUG 5 方案1修改点1:消除 i32 静默回退 + # Phase A-pre(declare_only=1):依赖的类可能尚未注册,延迟到下一遍 + # Phase B(declare_only=0):真正的类型解析错误,fast-fail 终止该类翻译 + # 不再用 i32 回退(会导致结构体布局错误 + GEP 索引错乱) + # 例外:泛型 Subscript(如 list[AST|t.CPtr])未特化时回退为 Ptr(i8), + # 因为泛型特化可能延迟到构造调用时。AnnotClassName 会携带 mangled name + # 供 translate_attribute 做后续 bitcast。 + is_generic_sub: int = 0 + if aa.annotation is not None and aa.annotation.kind() == ast.ASTKind.Subscript: + is_generic_sub = 1 + if is_generic_sub != 0: + # 泛型未特化:回退为 Ptr(i8),依赖 AnnotClassName 做后续类型恢复 + field_ty = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + else: + # Phase A-pre(declare_only=1):依赖的类可能尚未注册, + # 静默 return 0 让多遍收敛机制生效(下一遍依赖类已注册即可成功) + if trans._declare_only == 1: + return 0 + # Phase A(declare_only=0,Phase2.vp L573 多遍):依赖模块按 + # 文件序可能晚于本模块翻译(如 TypeGenMixin.vp G < HandlesType.vp + # H,TraceFrames 注解的 HandlesType.TraceFrame 未注册)→ 标记 + # _deps_pending 下遍重译,不在本遍以残缺字段注册结构体。 + # 真正的类型错误由 Phase A 收敛检查暴露("Phase A 无法完成 + # 翻译: ,请检查依赖模块是否已编译/注册"),不静默掩盖。 + if trans is not None: + trans._deps_pending = 1 + return 0 + # 旧行为:fast-fail NameError(已移除——Phase A 依赖未就绪时 + # 误报真实错误,中断多遍收敛;真实错误交给收敛检查兜底) + + # 存储到数组(指针转 CSizeT) + if field_count < GenTypes.FIELD_MAX: + diag_name_val: t.CSizeT = t.CSizeT(tgt.id) + field_names_buf[field_count] = diag_name_val + field_types_buf[field_count] = t.CSizeT(field_ty) + # 存储默认值 AST 指针(None=无默认值) + if aa.value is not None: + field_defaults_buf[field_count] = t.CSizeT(aa.value) + else: + field_defaults_buf[field_count] = 0 + # 提取原始类型注解的类名(联合类型简化为 Ptr(i8) 时回退查找结构体) + # BUG 1 方案3:传 pool 使泛型 Subscript 返回 mangled name(如 "list[ast.AST|t.CPtr]") + if aa.annotation is not None: + annot_cn: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation( + aa.annotation, trans._imported_modules, pool) + if annot_cn is not None: + diag_cn_val: t.CSizeT = t.CSizeT(annot_cn) + field_annot_buf[field_count] = diag_cn_val + else: + field_annot_buf[field_count] = 0 + else: + field_annot_buf[field_count] = 0 + field_count += 1 + + if field_count == 0: + # PhaseA 预注册时,父类可能尚未注册(字母序单遍扫描), + # 导致子类无法继承父类字段 → field_count==0。 + # 静默返回,Phase2.py 的多遍 PhaseA-pre 会在后续遍中重试。 + if trans._declare_only == 1 and parent_name is not None: + return 0 + # 无字段类(接口/标记类):不能整体跳过——类可能只有方法 + # (如多继承中的 ShapeM/Vec2Extra),需注册类并翻译方法。 + # 空 struct 在 LLVM 中合法({});@t.CVTable 类由下方补 vtable 指针字段。 + + # ============================================================ + # 2. 创建 LLVM StructType + # ============================================================ + # 构建 ParamNode 链表 + first_node: llvmlite.ParamNode | t.CPtr = None + prev_node: llvmlite.ParamNode | t.CPtr = None + total_field_count: int = field_count + + # 如果有虚表,首字段添加 i8* vtable 指针 + if has_vtable == 1: + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + vtable_node: llvmlite.ParamNode | t.CPtr = pool.alloc(llvmlite.ParamNode.__sizeof__()) + if vtable_node is None: + fb_vn: str = VLogger.fmt_buf() + if fb_vn is not None: + viperlib.snprintf(fb_vn, 1024, "failed to alloc vtable node for %s", class_name) + VLogger.error(fb_vn, "CLASS") + return 0 + string.memset(vtable_node, 0, llvmlite.ParamNode.__sizeof__()) + vtable_node.Ty = i8_ptr_ty + first_node = vtable_node + prev_node = vtable_node + total_field_count = field_count + 1 + + for fi in range(field_count): + fty_addr: t.CSizeT = field_types_buf[fi] + if fty_addr == 0: + continue + fty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(t.CVoid(fty_addr, t.CPtr)) + + # 创建 ParamNode + pnode: llvmlite.ParamNode | t.CPtr = pool.alloc(llvmlite.ParamNode.__sizeof__()) + if pnode is None: + continue + string.memset(pnode, 0, llvmlite.ParamNode.__sizeof__()) + pnode.Ty = fty + + if first_node is None: + first_node = pnode + if prev_node is not None: + prev_node.Next = pnode + prev_node = pnode + + # 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName" + # 注意: Phase 1b(declare_only=0)时 struct_ty 会注册到全局表并被后续 + # 文件翻译引用(vtable/self 参数类型打印),其 Name 必须跨 1b 每文件 + # reset_to(mark1) 存活 → 用 stdlib 深拷贝;Phase 1a 仍用 pool(无需跨文件)。 + type_name: str = class_name + if trans.ModuleSha1 is not None: + name_buf: str = pool.alloc(64) + if name_buf is not None: + viperlib.snprintf(name_buf, 64, "%s.%s", trans.ModuleSha1, class_name) + type_name = name_buf + if trans._declare_only == 0 and type_name is not None: + tn_len: t.CSizeT = string.strlen(type_name) + tn_copy: str = CompilerFactory.get_perm_pool().alloc(tn_len + 1) + if tn_copy is not None: + string.strcpy(tn_copy, type_name) + type_name = tn_copy + + # 创建 StructType(命名结构体) + struct_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, first_node, total_field_count, type_name) + if struct_ty is None: + fb_st: str = VLogger.fmt_buf() + if fb_st is not None: + viperlib.snprintf(fb_st, 1024, "failed to create StructType for %s", class_name) + VLogger.error(fb_st, "CLASS") + return 0 + + # Phase 1b(declare_only=0)新注册的 struct_ty 会被注册到全局表并被后续文件 + # 翻译引用(vtable/self 参数类型打印/find_struct_by_type 指针匹配)。LLVMType + # 对象和 Fields 链是 pool 分配的,本文件 reset_to(mark1) 后悬空。深拷贝整棵树 + # 到 stdlib,并替换 struct_ty 指针,保证 entry.Ty 与调用方持有的 struct_ty + # 指向同一个 stdlib 拷贝(指针匹配不失效)且跨文件永久存活。 + # StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:Phase A-pre-inc(declare_only=1) + # 预注册 includes 时若仍用 pool struct_ty,reset_to(mark2) 后 entry.Ty 悬空 → + # 后续文件字段类型引用(resolve → Ptr(entry.Ty))→ opaque 扫描遍历悬空 fields + # 崩溃(LoopTest _scan_type_for_cross_module_refs 0xFFFF 根因)。 + if trans._declare_only == 0 or self.Gen.StructGen.get_stdlib_alloc() != 0: + st_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( + CompilerFactory.get_perm_pool(), struct_ty) + if st_copy is not None: + struct_ty = st_copy + type_name = llvmlite.get_struct_name(struct_ty) + + # 注册命名结构体到模块(输出 %"name" = type { ... } 定义行) + llvmlite.module_add_named_type(trans.Module, pool, struct_ty) + + # 扫描字段类型,为跨模块结构体引用添加 opaque 声明 + # 例如 list[int].__pool__ 引用 memhub.MemManager,需要在当前模块添加 %"sha1.MemManager" = type opaque + for fi in range(field_count): + fty_addr_op: t.CSizeT = field_types_buf[fi] + if fty_addr_op == 0: + continue + fty_op: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(t.CVoid(fty_addr_op, t.CPtr)) + llvmlite.module_ensure_opaque_for_type(trans.Module, pool, fty_op) + + # ============================================================ + # 3. 注册到 HandlesStruct + # ============================================================ + entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.register_struct( + pool, class_name, struct_ty, trans.ModuleSha1) + if entry is None: + fb_re: str = VLogger.fmt_buf() + if fb_re is not None: + viperlib.snprintf(fb_re, 1024, "failed to register %s", class_name) + VLogger.error(fb_re, "CLASS") + return 0 + + # 标记 VTable 状态(直接用 entry,规避跨模块同名 find_struct 找错) + if has_vtable == 1: + entry.HasVTable = 1 + if is_novtable_deco == 1: + entry.IsNoVTable = 1 + if parent_name is not None: + # 1b 阶段父类名是 pool 字符串(本文件 AST/1a 预存),reset 后悬空; + # _translate_oop_methods/_detect_vtable_status 会在后续文件 + # find_struct(ParentName) strcmp 解引用 → 用 stdlib 拷贝保证跨文件存活 + if self.Gen.StructGen.get_stdlib_alloc() != 0: + pn_len: t.CSizeT = string.strlen(parent_name) + pn_buf: str = CompilerFactory.get_perm_pool().alloc(pn_len + 1) + if pn_buf is not None: + string.strcpy(pn_buf, parent_name) + entry.ParentName = pn_buf + else: + entry.ParentName = parent_name + # 多继承:设置父类数组(供 MRO/字段/vtable 查询,stdlib 深拷贝跨文件存活) + if parents_count > 0 and parents_buf is not None: + self.Gen.StructGen.set_parent_names(pool, class_name, parents_buf, parents_count) + + # 添加字段信息 + # 如果有虚表,先添加 __vtable__ 字段占位(索引 0),用户字段从索引 1 开始 + if has_vtable == 1: + i8_ptr_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + self.Gen.StructGen.add_field(pool, entry, "__vtable__", i8_ptr_ty2, None, None) + + for fi in range(field_count): + fname_addr: t.CSizeT = field_names_buf[fi] + if fname_addr == 0: + continue + fname: str = (str | t.CPtr)(t.CVoid(fname_addr, t.CPtr)) + fty_addr2: t.CSizeT = field_types_buf[fi] + if fty_addr2 == 0: + continue + fty2: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(t.CVoid(fty_addr2, t.CPtr)) + # 恢复默认值 AST 指针 + fdef_addr: t.CSizeT = field_defaults_buf[fi] + fdef: ast.AST | t.CPtr = None + if fdef_addr != 0: + fdef = (ast.AST | t.CPtr)(t.CVoid(fdef_addr, t.CPtr)) + # 恢复注解类名指针 + fannot_addr: t.CSizeT = field_annot_buf[fi] + fannot: str = None + if fannot_addr != 0: + fannot = (str)(t.CVoid(fannot_addr, t.CPtr)) + if fname is not None and fty2 is not None: + self.Gen.StructGen.add_field(pool, entry, fname, fty2, fdef, fannot) + + # Phase 1a 声明模式:只注册 struct + 设置 OOP 标志,不翻译方法体 + if trans._declare_only == 1: + self.Gen.ClassGenVTable._translate_oop_methods(trans, cd, struct_ty, class_name, 1) + return 0 + + # ============================================================ + # 4. OOP 方法处理:扫描 FunctionDef,标记 OOP,翻译方法,生成 __before_init__ + # ============================================================ + self.Gen.ClassGenVTable._translate_oop_methods(trans, cd, struct_ty, class_name) + return 0 \ No newline at end of file diff --git a/App/lib/core/Gen/ClassGenEnum.vp b/App/lib/core/Gen/ClassGenEnum.vp index 8b27243..2877a70 100644 --- a/App/lib/core/Gen/ClassGenEnum.vp +++ b/App/lib/core/Gen/ClassGenEnum.vp @@ -1,1162 +1,1156 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import viperlib -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesEnum as HandlesEnum -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.StubMerger as StubMerger -import lib.core.CompilerFactory as CompilerFactory - - -import lib.core.Gen.ClassGenBase as ClassGenBase - -# ============================================================ -# ClassGenEnum - ClassGenMixin 拆分(阶段 D):enum/union/renum 定义与变体表 -# -# 继承 ClassGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesClassDef 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class ClassGenEnum(ClassGenBase.ClassGenBase): - """enum/union/renum 定义与变体表""" - - def _resolve_enum_member_type(self, pool: memhub.MemBuddy | t.CPtr, - ann_node: ast.AST | t.CPtr, - imported_modules: str, - from_imports: str) -> llvmlite.LLVMType | t.CPtr: - """解析枚举成员的类型注解为 LLVM 整数类型""" - if ann_node is None: - return llvmlite.Int32(pool) - - k: int = ann_node.kind() - - # Attribute 节点: t.State / int / t.CInt8T 等 - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(ann_node) - if at.attr is None: - return llvmlite.Int32(pool) - # t.State → 默认 i32 - if string.strcmp(at.attr, "State") == 0: - return llvmlite.Int32(pool) - # 其他 t.CXxx 类型 - ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, at.attr) - if ty is not None: - return ty - return llvmlite.Int32(pool) - - # Name 节点: from-import 形式(State / CInt) - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ann_node) - if nm.id is None: - return llvmlite.Int32(pool) - if string.strcmp(nm.id, "State") == 0: - return llvmlite.Int32(pool) - ty2: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, nm.id) - if ty2 is not None: - return ty2 - return llvmlite.Int32(pool) - - # BinOp 节点: t.State | t.CInt8T(递归查找实际类型) - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(ann_node) - if bop.op == ast.OpKind.BitOr: - left_ty: llvmlite.LLVMType | t.CPtr = self._resolve_enum_member_type( - pool, bop.left, imported_modules, from_imports) - # 跳过 t.State(i32 默认),优先返回具体类型 - left_bits: int = HandlesType.get_llvm_type_bits(left_ty) - if left_bits != 0 and not self._is_state_annotation(bop.left): - return left_ty - right_ty: llvmlite.LLVMType | t.CPtr = self._resolve_enum_member_type( - pool, bop.right, imported_modules, from_imports) - if right_ty is not None and not self._is_state_annotation(bop.right): - return right_ty - # 两边都是 State 或无法确定,返回较宽的 - right_bits: int = HandlesType.get_llvm_type_bits(right_ty) - if left_bits >= right_bits: - return left_ty - return right_ty - # fail-fast:BinOp 但非 BitOr(未知联合运算),不再静默回退 i32 - HandlesType.fatal_error( - ann_node, f"枚举成员类型注解解析失败: {HandlesType.annotation_to_str(ann_node)}", "TypeError") - return llvmlite.Int32(pool) # 不可达(fatal_error 已退出) - - # fail-fast:未知注解节点 kind,不再静默回退 i32 - HandlesType.fatal_error( - ann_node, f"枚举成员类型注解解析失败: {HandlesType.annotation_to_str(ann_node)}", "TypeError") - return llvmlite.Int32(pool) # 不可达(fatal_error 已退出) - def _is_state_annotation(self, node: ast.AST | t.CPtr) -> int: - """检查注解节点是否为 t.State,返回 1=是 / 0=否""" - if node is None: - return 0 - k: int = node.kind() - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at.attr is not None and string.strcmp(at.attr, "State") == 0: - return 1 - return 0 - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm.id is not None and string.strcmp(nm.id, "State") == 0: - return 1 - return 0 - return 0 - def _extract_int_value(self, node: ast.AST | t.CPtr) -> t.CInt64T: - """从 AST 节点提取整数值,失败返回 0""" - if node is None: - return 0 - k: int = node.kind() - if k == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) - if cn.const_kind == ast.CONST_INT: - return cn.int_val - return 0 - if k == ast.ASTKind.UnaryOp: - uo: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) - if uo.op == ast.OpKind.USub: - inner: t.CInt64T = self._extract_int_value(uo.operand) - return -inner - return 0 - return 0 - def _translate_enum_def(self, trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr) -> int: - """翻译枚举类定义,返回 0""" - if cd is None or cd.name is None or trans is None: - return 0 - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - class_name: str = cd.name - - # 不按全局同名跳过:跨模块可能同名枚举(includes/w32/fileio.vp 的 - # FRESULT 与 fat32_types.vp 的 FRESULT),跳过会导致后注册模块的 - # 成员缺失(FR_OK 找不到)。register_enum 幂等返回已有 entry, - # add_enum_member 成员名去重,重复处理安全合并。 - - children: list[ast.AST | t.CPtr] | t.CPtr = cd.children - if children is None: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "%s has no body", class_name) - VLogger.warning(fb, "ENUM") - return 0 - - cn: t.CSizeT = len(children) - - # 临时数组存储成员信息 - member_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL) - member_types_buf: t.CSizeT | t.CPtr = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL) - member_values_buf: t.CInt64T | t.CPtr = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL) - if member_names_buf is None or member_types_buf is None or member_values_buf is None: - return 0 - string.memset(member_names_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL) - string.memset(member_types_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL) - string.memset(member_values_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL) - - member_count: int = 0 - next_val: t.CInt64T = 0 - - for ci in range(cn): - stmt: ast.AST | t.CPtr = children.get(ci) - if stmt is None: - continue - sk: int = stmt.kind() - - if sk == ast.ASTKind.AnnAssign: - aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) - if aa is None or aa.target is None: - continue - - # 获取成员名 - if aa.target.kind() != ast.ASTKind.Name: - continue - tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) - if tgt.id is None: - continue - - # 解析成员类型 - member_ty: llvmlite.LLVMType | t.CPtr = self._resolve_enum_member_type( - pool, aa.annotation, trans._imported_modules, trans._from_imports) - - # 解析成员值 - has_value: int = 0 - cur_val: t.CInt64T = 0 - if aa.value is not None: - cur_val = self._extract_int_value(aa.value) - has_value = 1 - else: - cur_val = next_val - - # 下一个自动值 - next_val = cur_val + 1 - - # 存储 - if member_count < ENUM_MEMBER_MAX_LOCAL: - member_names_buf[member_count] = t.CSizeT(tgt.id) - member_types_buf[member_count] = t.CSizeT(member_ty) - member_values_buf[member_count] = cur_val - member_count += 1 - - elif sk == ast.ASTKind.Assign: - # 处理 Assign 形式的枚举成员: DEBUG = 0, INFO = 1 等 - # CEnum 子类中无类型注释的赋值也视为枚举成员 - ag: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) - if ag is None or ag.targets is None: - continue - tgts: list[ast.AST | t.CPtr] | t.CPtr = ag.targets - tn: t.CSizeT = len(tgts) - if tn == 0: - continue - # 取第一个 target 作为成员名 - t0: ast.AST | t.CPtr = tgts.get(0) - if t0 is None or t0.kind() != ast.ASTKind.Name: - continue - tgt_a: ast.Name | t.CPtr = (ast.Name | t.CPtr)(t0) - if tgt_a.id is None: - continue - - # Assign 无类型注释,默认使用 i32 - member_ty_a: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - - # 解析成员值 - cur_val_a: t.CInt64T = 0 - if ag.value is not None: - cur_val_a = self._extract_int_value(ag.value) - else: - cur_val_a = next_val - - # 下一个自动值 - next_val = cur_val_a + 1 - - # 存储 - if member_count < ENUM_MEMBER_MAX_LOCAL: - member_names_buf[member_count] = t.CSizeT(tgt_a.id) - member_types_buf[member_count] = t.CSizeT(member_ty_a) - member_values_buf[member_count] = cur_val_a - member_count += 1 - - if member_count == 0: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "%s has no members", class_name) - VLogger.warning(fb, "ENUM") - return 0 - - # 确定基准类型:所有成员类型中 Bits 最大的 - base_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - max_bits: int = 0 - for mi in range(member_count): - ty_addr: t.CSizeT = member_types_buf[mi] - if ty_addr == 0: - continue - mty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)( - t.CVoid(ty_addr, t.CPtr)) - bits: int = HandlesType.get_llvm_type_bits(mty) - if bits > max_bits: - max_bits = bits - base_ty = mty - - # 注册枚举 - entry: HandlesEnum.EnumEntry | t.CPtr = HandlesEnum.register_enum( - pool, class_name, base_ty) - if entry is None: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "failed to register %s", class_name) - VLogger.error(fb, "ENUM") - return 0 - - # 添加成员 - for mi in range(member_count): - fname_addr: t.CSizeT = member_names_buf[mi] - if fname_addr == 0: - continue - mname: str = (str | t.CPtr)(t.CVoid(fname_addr, t.CPtr)) - fty_addr2: t.CSizeT = member_types_buf[mi] - if fty_addr2 == 0: - continue - mty2: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)( - t.CVoid(fty_addr2, t.CPtr)) - mval: t.CInt64T = member_values_buf[mi] - if mname is not None and mty2 is not None: - HandlesEnum.add_enum_member(pool, entry, mname, mval, mty2) - - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "registered %s with %d members, base_bits=%d", - class_name, member_count, max_bits) - VLogger.info(fb, "ENUM") - return 0 - def _get_type_size(self, ty: llvmlite.LLVMType | t.CPtr) -> int: - """计算 LLVM 类型的字节大小(含对齐 padding)""" - if ty is None: - return 0 - match ty: - case llvmlite.LLVMType.Int(bits): - return (bits + 7) // 8 - case llvmlite.LLVMType.Float(bits): - return bits // 8 - case llvmlite.LLVMType.Ptr(pointee): - return 8 - case llvmlite.LLVMType.Array(elem_ty, count): - return self._get_type_size(elem_ty) * count - case llvmlite.LLVMType.Struct(fields, fcount, name): - # 计算结构体大小,考虑字段对齐 padding - # 规则: 每个字段的对齐 = 该字段类型的自然对齐 - # 指针/i64 → 8, i32 → 4, i16 → 2, i8 → 1 - # 结构体总大小需对齐到最大字段对齐的倍数 - total: int = 0 - max_align: int = 1 - cur: llvmlite.ParamNode | t.CPtr = fields - i: int = 0 - while cur is not None and i < fcount: - if cur.Ty is not None: - fty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(cur.Ty) - fsize: int = self._get_type_size(fty) - falign: int = self._get_type_align(fty) - # 对齐当前偏移到字段对齐边界 - if falign > 0: - rem: int = total % falign - if rem != 0: - total += falign - rem - total += fsize - if falign > max_align: - max_align = falign - cur = cur.Next - i += 1 - # 结构体总大小对齐到最大字段对齐的倍数 - rem2: int = total % max_align - if rem2 != 0: - total += max_align - rem2 - return total - case _: - return 8 - def _get_type_align(self, ty: llvmlite.LLVMType | t.CPtr) -> int: - """返回类型的自然对齐(字节)""" - if ty is None: - return 1 - match ty: - case llvmlite.LLVMType.Int(bits): - if bits <= 8: - return 1 - elif bits <= 16: - return 2 - elif bits <= 32: - return 4 - else: - return 8 - case llvmlite.LLVMType.Float(bits): - if bits <= 32: - return 4 - else: - return 8 - case llvmlite.LLVMType.Ptr(pointee): - return 8 - case llvmlite.LLVMType.Array(elem_ty, count): - return self._get_type_align(elem_ty) - case llvmlite.LLVMType.Struct(fields, fcount, name): - # 结构体的对齐 = 最大字段对齐 - max_align: int = 1 - cur: llvmlite.ParamNode | t.CPtr = fields - i: int = 0 - while cur is not None and i < fcount: - if cur.Ty is not None: - fty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(cur.Ty) - fa: int = self._get_type_align(fty) - if fa > max_align: - max_align = fa - cur = cur.Next - i += 1 - return max_align - case _: - return 8 - def _translate_union_def(self, trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr) -> int: - """翻译联合体定义,返回 0""" - if cd is None or cd.name is None or trans is None: - return 0 - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - class_name: str = cd.name - - # 命名空间隔离:标记为当前文件可见(必须在 existing 检查之前) - HandlesStruct.add_visible_struct(pool, class_name) - - # 检查是否已注册(用 SHA1 区分跨模块同名类) - existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( - class_name, trans.ModuleSha1) - if existing is not None: - # Phase B: 将已存在的命名结构体注册到当前模块 - if existing.Ty is not None: - llvmlite.module_add_named_type(trans.Module, pool, existing.Ty) - # SHA1 已在 register_struct 时设置,无需再补 - return 0 - - children: list[ast.AST | t.CPtr] | t.CPtr = cd.children - if children is None: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "%s has no body", class_name) - VLogger.warning(fb, "UNION") - return 0 - - cn: t.CSizeT = len(children) - - # 临时数组存储字段信息 - field_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * HandlesStruct.FIELD_MAX) - field_types_buf: t.CSizeT | t.CPtr = pool.alloc(8 * HandlesStruct.FIELD_MAX) - if field_names_buf is None or field_types_buf is None: - return 0 - string.memset(field_names_buf, 0, 8 * HandlesStruct.FIELD_MAX) - string.memset(field_types_buf, 0, 8 * HandlesStruct.FIELD_MAX) - - field_count: int = 0 - max_size: int = 0 - - for ci in range(cn): - stmt: ast.AST | t.CPtr = children.get(ci) - if stmt is None: - continue - sk: int = stmt.kind() - - if sk == ast.ASTKind.AnnAssign: - aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) - if aa is None or aa.target is None: - continue - - # 获取字段名 - if aa.target.kind() != ast.ASTKind.Name: - continue - tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) - if tgt.id is None: - continue - - # 解析字段类型 - field_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, aa.annotation, trans._imported_modules, trans._from_imports, trans) - if field_ty is None: - # Phase A-pre(declare_only=1):依赖的类可能尚未注册, - # 静默 return 1 让多遍收敛机制生效(renum 返回 1=跳过该类) - if trans._declare_only == 1: - return 1 - # Phase B(declare_only=0):真正的类型解析错误,fast-fail 终止 - type_name: str = HandlesType.annotation_to_str(aa.annotation) - HandlesType.fatal_error( - aa, - f"'{type_name}' is not defined", - "NameError") - field_ty = llvmlite.Int32(pool) - - # 计算字段大小,更新 max_size - fsize: int = self._get_type_size(field_ty) - if fsize > max_size: - max_size = fsize - - # 存储到数组 - if field_count < HandlesStruct.FIELD_MAX: - field_names_buf[field_count] = t.CSizeT(tgt.id) - field_types_buf[field_count] = t.CSizeT(field_ty) - field_count += 1 - - if field_count == 0: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "%s has no fields", class_name) - VLogger.warning(fb, "UNION") - return 0 - - if max_size < 1: - max_size = 1 - - # 创建联合体的 LLVM 类型: Struct([Array(Int8, max_size)]) - # 即 { [max_size x i8] } - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - array_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, max_size) - - # 构建 ParamNode 链表(单字段:字节数组) - pnode: llvmlite.ParamNode | t.CPtr = pool.alloc(llvmlite.ParamNode.__sizeof__()) - if pnode is None: - return 0 - string.memset(pnode, 0, llvmlite.ParamNode.__sizeof__()) - pnode.Ty = array_ty - - # 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName" - union_type_name: str = class_name - if trans.ModuleSha1 is not None: - union_name_buf: str = pool.alloc(64) - if union_name_buf is not None: - viperlib.snprintf(union_name_buf, 64, "%s.%s", trans.ModuleSha1, class_name) - union_type_name = union_name_buf - - union_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, pnode, 1, union_type_name) - if union_ty is None: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "failed to create type for %s", class_name) - VLogger.error(fb, "UNION") - return 0 - - # Phase 1b 新注册的 union struct_ty 深拷贝到 stdlib(跨文件 reset 存活) - # StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:Phase A-pre-inc 预注册 - # includes 时 declare_only=1,若仍用 pool struct_ty,reset_to(mark2) 后 - # entry.Ty 悬空 → 后续文件 opaque 扫描跨模块引用遍历悬空 fields 崩溃 - # (LoopTest _scan_type_for_cross_module_refs 0xFFFF 根因)。 - if trans._declare_only == 0 or HandlesStruct.get_stdlib_alloc() != 0: - union_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( - CompilerFactory.get_perm_pool(), union_ty) - if union_copy is not None: - union_ty = union_copy - - # 注册命名结构体到模块 - llvmlite.module_add_named_type(trans.Module, pool, union_ty) - - # 注册到 HandlesStruct(传递 SHA1 在注册时直接设置,避免跨模块同名找错 entry) - entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.register_struct( - pool, class_name, union_ty, trans.ModuleSha1) - if entry is None: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "failed to register %s", class_name) - VLogger.error(fb, "UNION") - return 0 - - # 标记为当前文件可见(命名空间隔离) - HandlesStruct.add_visible_struct(pool, class_name) - - # 标记为联合体(直接用 entry,规避跨模块同名 find_struct 找错) - entry.IsUnion = 1 - - # 添加字段信息(所有字段 Index=0,因为共享偏移 0) - for fi in range(field_count): - fname_addr: t.CSizeT = field_names_buf[fi] - if fname_addr == 0: - continue - fname: str = (str | t.CPtr)(t.CVoid(fname_addr, t.CPtr)) - fty_addr2: t.CSizeT = field_types_buf[fi] - if fty_addr2 == 0: - continue - fty2: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)( - t.CVoid(fty_addr2, t.CPtr)) - if fname is not None and fty2 is not None: - HandlesStruct.add_field(pool, entry, fname, fty2, None, None) - - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "registered %s with %d fields, max_size=%d", - class_name, field_count, max_size) - VLogger.info(fb, "UNION") - return 0 - def _get_annotation_field_size(self, annotation: ast.AST | t.CPtr) -> int: - """计算注解类型的字节大小,用于 REnum 布局计算""" - if annotation is None: - return 8 - k: int = annotation.kind() - # 联合类型 A | B → 指针大小 8 - if k == ast.ASTKind.BinOp: - return 8 - # Name(id) 或 Attribute(attr) → 解析类型名 - type_name: str = None - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annotation) - if nm is not None: - type_name = nm.id - elif k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annotation) - if at is not None: - type_name = at.attr - if type_name is None: - return 8 - # 内置类型 - if string.strcmp(type_name, "int") == 0: - return 4 - if string.strcmp(type_name, "CInt") == 0: - return 4 - if string.strcmp(type_name, "CInt8T") == 0: - return 1 - if string.strcmp(type_name, "CInt16T") == 0: - return 2 - if string.strcmp(type_name, "CInt32T") == 0: - return 4 - if string.strcmp(type_name, "CInt64T") == 0: - return 8 - if string.strcmp(type_name, "CChar") == 0: - return 1 - if string.strcmp(type_name, "CDouble") == 0: - return 8 - if string.strcmp(type_name, "CFloat") == 0: - return 4 - if string.strcmp(type_name, "CPtr") == 0: - return 8 - if string.strcmp(type_name, "CSizeT") == 0: - return 8 - if string.strcmp(type_name, "str") == 0: - return 8 - if string.strcmp(type_name, "bytes") == 0: - return 8 - if string.strcmp(type_name, "bool") == 0: - # bool = t.CBool = i8(1 字节) - return 1 - # 已注册的结构体类型 - struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(type_name) - if struct_ty is not None: - sz: int = self._get_type_size(struct_ty) - if sz > 0: - return sz - # 未注册类型 → 默认指针大小 8(可能是自引用或前向引用) - return 8 - def _translate_renum_def(self, trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr) -> int: - """翻译 REnum 类定义,返回 0""" - if cd is None or cd.name is None or trans is None: - return 0 - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - class_name: str = cd.name - - # 命名空间隔离:标记为当前文件可见 - HandlesStruct.add_visible_struct(pool, class_name) - - # 检查是否已注册(用 SHA1 区分跨模块同名类) - existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( - class_name, trans.ModuleSha1) - if existing is not None: - if existing.Ty is not None: - llvmlite.module_add_named_type(trans.Module, pool, existing.Ty) - return 0 - - children: list[ast.AST | t.CPtr] | t.CPtr = cd.children - if children is None: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "%s has no body", class_name) - VLogger.warning(fb, "RENUM") - return 0 - - cn: t.CSizeT = len(children) - - # 变体最多 32 个,每个变体最多 16 个字段 - # variant_field_sizes[i][j] = 变体 i 的第 j 个字段大小 - variant_field_sizes: t.CSizeT | t.CPtr = pool.alloc(8 * 64 * 16) - if variant_field_sizes is None: - return 0 - string.memset(variant_field_sizes, 0, 8 * 64 * 16) - - variant_count: int = 0 - max_field_count: int = 0 # 所有变体中最大字段数 - - for ci in range(cn): - stmt: ast.AST | t.CPtr = children.get(ci) - if stmt is None: - continue - sk: int = stmt.kind() - - if sk == ast.ASTKind.ClassDef: - # 嵌套变体类 - variant_cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(stmt) - if variant_cd is None or variant_cd.children is None: - variant_count += 1 - continue - variant_children: list[ast.AST | t.CPtr] | t.CPtr = variant_cd.children - vcn: t.CSizeT = len(variant_children) - field_idx: int = 0 - for vi in range(vcn): - vstmt: ast.AST | t.CPtr = variant_children.get(vi) - if vstmt is None: - continue - vk: int = vstmt.kind() - if vk != ast.ASTKind.AnnAssign: - continue - vaa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(vstmt) - if vaa is None or vaa.target is None or vaa.annotation is None: - continue - if vaa.target.kind() != ast.ASTKind.Name: - continue - # 提取字段名 - vnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(vaa.target) - # 计算字段大小 - fsize: int = self._get_annotation_field_size(vaa.annotation) - if variant_count < 32 and field_idx < 16: - # variant_field_sizes[variant_count][field_idx] = fsize - offset: t.CSizeT = variant_count * 16 + field_idx - variant_field_sizes[offset] = t.CSizeT(fsize) - # 直接注册变体字段名别名(避免 CSizeT→str 转换问题) - # 同时解析成员实际类型(对齐 TPC class_members,供 match - # 绑定 bitcast 槽位地址用)。自引用注解(如 - # LLVMType|t.CPtr 引用自身类)此时解析失败返回 None → - # 不存类型,绑定回退槽位类型。variant_cd.name 在 1a reset - # 后悬空,注册内部会 strcpy 到 perm_pool。 - if vnm is not None and vnm.id is not None: - mem_ty_l: llvmlite.LLVMType | t.CPtr = None - if trans is not None: - mem_ty_l = HandlesType.resolve_annotation_type( - pool, vaa.annotation, - trans._imported_modules, - trans._from_imports, trans) - self._register_renum_field_alias( - pool, class_name, vnm.id, field_idx + 1, - mem_ty_l, variant_cd.name) - field_idx += 1 - if field_idx > max_field_count: - max_field_count = field_idx - variant_count += 1 - - if variant_count == 0: - fb2: str = VLogger.fmt_buf() - if fb2 is not None: - viperlib.snprintf(fb2, 1024, "%s has no variants", class_name) - VLogger.warning(fb2, "RENUM") - return 0 - - # 计算每个位置的最大字段大小 - # 位置 0 = __tag (i32, 4 字节) - # 位置 1+ = 变体字段 - total_positions: int = max_field_count + 1 # +1 for tag - if total_positions < 2: - total_positions = 2 # 至少 {i32, i32} - - position_max_sizes: t.CSizeT | t.CPtr = pool.alloc(8 * total_positions) - if position_max_sizes is None: - return 0 - string.memset(position_max_sizes, 0, 8 * total_positions) - - # 位置 0 = tag = 4 字节 - position_max_sizes[0] = t.CSizeT(4) - - # 位置 1+ = 每个位置取所有变体的最大字段大小 - for pos in range(1, total_positions): - pos_max: int = 0 - for vi in range(variant_count): - if vi >= 64: - break # variant_field_sizes 64 类槽上限,防读越界 - field_pos: int = pos - 1 # 变体字段从位置 0 开始 - if field_pos >= 16: - continue # 超出每变体 16 字段槽位:未写入(memset 为 0),跳过 - offset2: t.CSizeT = vi * 16 + field_pos - fsize_val: t.CSizeT = variant_field_sizes[offset2] - if fsize_val > pos_max: - pos_max = fsize_val - position_max_sizes[pos] = t.CSizeT(pos_max) - - # 构建 ParamNode 链表 - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - - first_node: llvmlite.ParamNode | t.CPtr = None - tail_node: llvmlite.ParamNode | t.CPtr = None - - for pos in range(total_positions): - psize: int = position_max_sizes[pos] - field_ty: llvmlite.LLVMType | t.CPtr = i32_ty - if psize > 4: - field_ty = i64_ty - pnode: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, field_ty) - if pnode is None: - continue - tail_node = llvmlite.param_list_append(first_node, tail_node, pnode) - if first_node is None: - first_node = tail_node - - if first_node is None: - fb3: str = VLogger.fmt_buf() - if fb3 is not None: - viperlib.snprintf(fb3, 1024, "failed to build field list for %s", class_name) - VLogger.error(fb3, "RENUM") - return 0 - - # 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName" - renum_type_name: str = class_name - if trans.ModuleSha1 is not None: - renum_name_buf: str = pool.alloc(64) - if renum_name_buf is not None: - viperlib.snprintf(renum_name_buf, 64, "%s.%s", trans.ModuleSha1, class_name) - renum_type_name = renum_name_buf - - renum_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct( - pool, first_node, total_positions, renum_type_name) - if renum_ty is None: - fb4: str = VLogger.fmt_buf() - if fb4 is not None: - viperlib.snprintf(fb4, 1024, "failed to create type for %s", class_name) - VLogger.error(fb4, "RENUM") - return 0 - - # Phase 1b 新注册的 REnum struct_ty 深拷贝到 stdlib(跨文件 reset 存活, - # 与 entry.Ty 保持同一指针,find_struct_by_type 匹配不失效) - # StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:同 union 的悬空根因。 - if trans._declare_only == 0 or HandlesStruct.get_stdlib_alloc() != 0: - renum_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( - CompilerFactory.get_perm_pool(), renum_ty) - if renum_copy is not None: - renum_ty = renum_copy - - # 注册命名结构体到模块 - llvmlite.module_add_named_type(trans.Module, pool, renum_ty) - - # 注册到 HandlesStruct - entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.register_struct( - pool, class_name, renum_ty, trans.ModuleSha1) - if entry is None: - fb5: str = VLogger.fmt_buf() - if fb5 is not None: - viperlib.snprintf(fb5, 1024, "failed to register %s", class_name) - VLogger.error(fb5, "RENUM") - return 0 - - # 修复 class_name 指针不匹配: - # 别名注册时用 class_name(= cd.name,AST 原始指针), - # 但查找时用 entry.Name(register_struct 通过 pool.alloc+strcpy 复制的副本指针)。 - # 两者是不同指针,CSizeT 指针值比较会失败。 - # 调用辅助函数将已注册别名的 class_name 统一更新为 entry.Name。 - if entry.Name is not None: - self._update_renum_alias_class_ptr(t.CSizeT(class_name), t.CSizeT(entry.Name)) - - # 添加 __tag 字段(位置 0,i32) - HandlesStruct.add_field(pool, entry, "__tag", i32_ty, None, None) - - # 添加 payload 字段(位置 1+,i32 或 i64) - for pos in range(1, total_positions): - psize2: int = position_max_sizes[pos] - payload_ty: llvmlite.LLVMType | t.CPtr = i32_ty - if psize2 > 4: - payload_ty = i64_ty - field_name_buf: str = pool.alloc(16) - if field_name_buf is not None: - viperlib.snprintf(field_name_buf, 16, "_p%d", pos) - HandlesStruct.add_field(pool, entry, field_name_buf, payload_ty, None, None) - - # 注册变体名到全局变体表(供 translate_call 检测 REnum 变体构造) - self._register_renum_variants(pool, class_name, cd, variant_count) - - # 注册变体字段名别名已在变体遍历时直接完成(避免 CSizeT→str 转换问题) - - fb6: str = VLogger.fmt_buf() - if fb6 is not None: - viperlib.snprintf(fb6, 1024, "registered %s with %d variants, %d positions", - class_name, variant_count, total_positions) - VLogger.info(fb6, "RENUM") - return 0 - def _register_renum_variants(self, pool: memhub.MemBuddy | t.CPtr, - class_name: str, - cd: ast.ClassDef | t.CPtr, - variant_count: int): - """注册 REnum 类的变体名和 tag 值到全局变体表""" - if pool is None or class_name is None or cd is None: - return - if variant_count == 0: - return - children: list[ast.AST | t.CPtr] | t.CPtr = cd.children - if children is None: - return - - # 懒初始化表(首次注册时分配) - # 注意: 必须用 stdlib 分配——这些表在 1b 阶段(mark1 之后)首次分配, - # 若用 pool 会被 reset_to(mark1) 回收导致悬空(LLVMType 的 match 在 - # parser.vp 等后续文件翻译时访问已回收的表 → 崩溃)。 - if self.RenumClassNames is None: - self.RenumClassNames = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX) - self.RenumClassVariantCounts = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX) - self.RenumVariantNames = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS) - self.RenumVariantTags = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS) - if (self.RenumClassNames is None or self.RenumClassVariantCounts is None - or self.RenumVariantNames is None or self.RenumVariantTags is None): - self.RenumClassNames = None - return - string.memset(self.RenumClassNames, 0, 8 * RENUM_CLASS_MAX) - string.memset(self.RenumClassVariantCounts, 0, 8 * RENUM_CLASS_MAX) - string.memset(self.RenumVariantNames, 0, 8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS) - string.memset(self.RenumVariantTags, 0, 8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS) - self.RenumClassCount = 0 - - # ============ 临时诊断(0xb0 崩溃定位,定位后移除) ============ - # lazy init 后 RenumClassNames 必非空;此时若 RCV 异常(null/小值) - # 说明字段被越界覆盖或 __init__ 未生效,fail-fast 暴露崩溃现场。 - fb_diag: str = VLogger.fmt_buf() - if fb_diag is not None: - viperlib.snprintf(fb_diag, 1024, - "[RENUM-DIAG] self=%llu RN=%llu RCV=%llu RVN=%llu RVT=%llu RCount=%d class=%s", - t.CUInt64T(self), t.CUInt64T(self.RenumClassNames), - t.CUInt64T(self.RenumClassVariantCounts), - t.CUInt64T(self.RenumVariantNames), - t.CUInt64T(self.RenumVariantTags), - self.RenumClassCount, class_name) - VLogger.info(fb_diag, "RENUM") - rcv_chk: t.CUInt64T = t.CUInt64T(self.RenumClassVariantCounts) - if rcv_chk == 0 or rcv_chk < 4096: - fb_fail: str = VLogger.fmt_buf() - if fb_fail is not None: - viperlib.snprintf(fb_fail, 1024, - "[RENUM-FAIL] RCV=%llu 异常(lazy init 后应为 perm_pool 地址),RenumClassCount=%d class=%s", - t.CUInt64T(self.RenumClassVariantCounts), - self.RenumClassCount, class_name) - VLogger.error(fb_fail, "RENUM") - stdlib.exit(1) - # ============ 临时诊断结束 ============ - - # 检查是否已注册(避免重复注册) - for i in range(self.RenumClassCount): - existing: str = self.RenumClassNames[i] - if existing is not None and string.strcmp(existing, class_name) == 0: - return - - # 表已满 - if self.RenumClassCount >= RENUM_CLASS_MAX: - return - - # 注册类名(strcpy 到 perm_pool:1a 每文件 reset 后 AST 裸指针悬空, - # _lookup_renum_variant/_is_renum_class_name 的 strcmp 会读毒化内存) - idx: int = self.RenumClassCount - cn_len_rv: t.CSizeT = string.strlen(class_name) - cn_buf_rv: str = CompilerFactory.get_perm_pool().alloc(cn_len_rv + 1) - if cn_buf_rv is None: - return - string.strcpy(cn_buf_rv, class_name) - self.RenumClassNames[idx] = t.CSizeT(cn_buf_rv) - self.RenumClassVariantCounts[idx] = variant_count - - # 遍历 children,提取嵌套变体类名并注册 - cn: t.CSizeT = len(children) - tag: int = 0 - for ci in range(cn): - if tag >= variant_count: - break - if tag >= RENUM_VARIANT_PER_CLASS: - # 每类固定 32 槽:变体超过上限继续写会越界污染相邻类槽,fail-fast 报错 - fb_rv: str = VLogger.fmt_buf() - if fb_rv is not None: - viperlib.snprintf(fb_rv, 1024, - "REnum 变体数超过上限 %d: %s", RENUM_VARIANT_PER_CLASS, class_name) - VLogger.error(fb_rv, "RENUM") - break - stmt: ast.AST | t.CPtr = children.get(ci) - if stmt is None: - continue - if stmt.kind() != ast.ASTKind.ClassDef: - continue - vcd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(stmt) - if vcd is None or vcd.name is None: - continue - name_offset: t.CSizeT = idx * RENUM_VARIANT_PER_CLASS + tag - # 变体名同样 strcpy 到 perm_pool(1a 每文件 reset 后 vcd.name 悬空) - vn_len_rv: t.CSizeT = string.strlen(vcd.name) - vn_buf_rv: str = CompilerFactory.get_perm_pool().alloc(vn_len_rv + 1) - if vn_buf_rv is None: - break - string.strcpy(vn_buf_rv, vcd.name) - self.RenumVariantNames[name_offset] = t.CSizeT(vn_buf_rv) - self.RenumVariantTags[name_offset] = tag - tag += 1 - - self.RenumClassCount = idx + 1 - def _lookup_renum_variant(self, variant_name: str) -> str: - """查找变体名所属的 REnum 类名 - - 返回: class_name (str),或 None - """ - if variant_name is None or self.RenumClassNames is None: - return None - - for i in range(self.RenumClassCount): - vcount: int = self.RenumClassVariantCounts[i] - for j in range(vcount): - name_offset: t.CSizeT = i * RENUM_VARIANT_PER_CLASS + j - vname: str = self.RenumVariantNames[name_offset] - if vname is not None and string.strcmp(vname, variant_name) == 0: - cls_nm: str = self.RenumClassNames[i] - return cls_nm - return None - def _is_renum_class_name(self, class_name: str) -> int: - """检查名称是否是已注册的 REnum 类名,返回 1=是 / 0=否""" - if class_name is None or self.RenumClassNames is None: - return 0 - for i in range(self.RenumClassCount): - existing: str = self.RenumClassNames[i] - if existing is not None and string.strcmp(existing, class_name) == 0: - return 1 - return 0 - def _lookup_renum_variant_in_class(self, class_name: str, variant_name: str) -> int: - """在指定 REnum 类中查找变体,返回 tag 值或 -1""" - if class_name is None or variant_name is None or self.RenumClassNames is None: - return -1 - for i in range(self.RenumClassCount): - existing: str = self.RenumClassNames[i] - if existing is None or string.strcmp(existing, class_name) != 0: - continue - vcount: int = self.RenumClassVariantCounts[i] - for j in range(vcount): - name_offset: t.CSizeT = i * RENUM_VARIANT_PER_CLASS + j - vname: str = self.RenumVariantNames[name_offset] - if vname is not None and string.strcmp(vname, variant_name) == 0: - return self.RenumVariantTags[name_offset] - return -1 - return -1 - def _register_renum_field_alias(self, pool: memhub.MemBuddy | t.CPtr, - class_name: str, - field_name: str, - payload_idx: int, - field_ty: llvmlite.LLVMType | t.CPtr = None, - variant_name: str = None): - """注册 REnum 变体字段名别名到全局表 - - field_ty: 变体成员的实际 LLVM 类型(可选;自引用类型如 - LLVMType|t.CPtr 在注册期解析失败时为 None,match 绑定回退槽位类型)。 - variant_name: 所属变体名(可选;match 绑定按 (class, 变体, 位置) 定位成员) - """ - if pool is None or class_name is None or field_name is None: - return - if payload_idx < 1: - return - - # 懒初始化表(perm_pool:1a 每文件 reset 后表本体不被回收) - if self.RenumAliasClass is None: - alias_pool_rfa: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool() - self.RenumAliasClass = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX) - self.RenumAliasField = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX) - self.RenumAliasIndex = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX) - self.RenumAliasTy = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX) - self.RenumAliasVariant = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX) - if (self.RenumAliasClass is None or self.RenumAliasField is None - or self.RenumAliasIndex is None or self.RenumAliasTy is None - or self.RenumAliasVariant is None): - self.RenumAliasClass = None - return - string.memset(self.RenumAliasClass, 0, 8 * RENUM_ALIAS_MAX) - string.memset(self.RenumAliasField, 0, 8 * RENUM_ALIAS_MAX) - string.memset(self.RenumAliasIndex, 0, 8 * RENUM_ALIAS_MAX) - string.memset(self.RenumAliasTy, 0, 8 * RENUM_ALIAS_MAX) - string.memset(self.RenumAliasVariant, 0, 8 * RENUM_ALIAS_MAX) - self.RenumAliasCount = 0 - - if self.RenumAliasCount >= RENUM_ALIAS_MAX: - return - - # 检查是否已注册(避免重复)— class 用 CSizeT 指针值比较(契约不变), - # field 槽位是 perm_pool 拷贝、key 是原指针,指针比较恒不相等 → 改 strcmp - cls_key: t.CSizeT = t.CSizeT(class_name) - for i in range(self.RenumAliasCount): - cls_existing: t.CSizeT = self.RenumAliasClass[i] - if cls_existing == cls_key: - fld_existing_ptr: str = (str | t.CPtr)( - t.CVoid(self.RenumAliasField[i], t.CPtr)) - if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0: - return - - idx: int = self.RenumAliasCount - self.RenumAliasClass[idx] = cls_key - # field_name 存 AST 裸指针,1a 每文件 reset 后悬空;_lookup_renum_field_alias - # 用 strcmp 内容比较 → strcpy 到 perm_pool 不影响查找。 - # class_name 槽位保持原指针:_update_renum_alias_class_ptr 会统一为 - # entry.Name(perm_pool 拷贝),指针值比较契约不变。 - fn_len_rfa: t.CSizeT = string.strlen(field_name) - fn_buf_rfa: str = CompilerFactory.get_perm_pool().alloc(fn_len_rfa + 1) - if fn_buf_rfa is None: - return - string.strcpy(fn_buf_rfa, field_name) - self.RenumAliasField[idx] = t.CSizeT(fn_buf_rfa) - self.RenumAliasIndex[idx] = t.CSizeT(payload_idx) - # 成员类型深拷贝到 perm_pool(1a 每文件 reset 后 pool 类型悬空; - # 未解析成功(自引用等)存 0,绑定回退槽位类型) - self.RenumAliasTy[idx] = 0 - if field_ty is not None: - ty_copy_rfa: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( - CompilerFactory.get_perm_pool(), field_ty) - if ty_copy_rfa is not None: - self.RenumAliasTy[idx] = t.CSizeT(ty_copy_rfa) - # 变体名同样 strcpy 到 perm_pool(1a reset 后 variant_cd.name 悬空) - self.RenumAliasVariant[idx] = 0 - if variant_name is not None: - vn_len_rfa: t.CSizeT = string.strlen(variant_name) - vn_buf_rfa: str = CompilerFactory.get_perm_pool().alloc(vn_len_rfa + 1) - if vn_buf_rfa is not None: - string.strcpy(vn_buf_rfa, variant_name) - self.RenumAliasVariant[idx] = t.CSizeT(vn_buf_rfa) - self.RenumAliasCount = idx + 1 - def _update_renum_alias_class_ptr(self, old_ptr: t.CSizeT, new_ptr: t.CSizeT): - """更新别名表中的 class_name 指针,从 old_ptr 更新为 new_ptr""" - if old_ptr == new_ptr: - return - if self.RenumAliasClass is None: - return - for i in range(self.RenumAliasCount): - if self.RenumAliasClass[i] == old_ptr: - self.RenumAliasClass[i] = new_ptr - def _lookup_renum_field_alias(self, class_name: str, field_name: str) -> int: - """查找 REnum 变体字段名的 payload 索引,返回索引或 -1 - - class_name: 用 CSizeT 指针值比较(_update_renum_alias_class_ptr 已统一指针) - field_name: 用 strcmp 内容比较(注册时 vnm.id 与查找时 at.attr 是不同指针) - """ - if class_name is None or field_name is None or self.RenumAliasClass is None: - return -1 - cls_key: t.CSizeT = t.CSizeT(class_name) - for i in range(self.RenumAliasCount): - cls_existing: t.CSizeT = self.RenumAliasClass[i] - if cls_existing == cls_key: - # field_name 用 strcmp 内容比较(指针不同但内容相同) - fld_existing_ptr: str = (str | t.CPtr)( - t.CVoid(self.RenumAliasField[i], t.CPtr)) - if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0: - return self.RenumAliasIndex[i] - return -1 - def _lookup_renum_field_alias_ty(self, class_name: str, - field_name: str) -> llvmlite.LLVMType | t.CPtr: - """查找 REnum 变体成员的实际 LLVM 类型,返回类型或 None - - 与 _lookup_renum_field_alias 同表同键(class 指针值比较 + field strcmp)。 - 注册期未解析成功(自引用类型等)槽位为 0 → 返回 None,绑定回退槽位类型。 - """ - if class_name is None or field_name is None or self.RenumAliasTy is None: - return None - cls_key: t.CSizeT = t.CSizeT(class_name) - for i in range(self.RenumAliasCount): - cls_existing: t.CSizeT = self.RenumAliasClass[i] - if cls_existing == cls_key: - fld_existing_ptr: str = (str | t.CPtr)( - t.CVoid(self.RenumAliasField[i], t.CPtr)) - if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0: - if self.RenumAliasTy[i] == 0: - return None - return (llvmlite.LLVMType | t.CPtr)( - t.CVoid(self.RenumAliasTy[i], t.CPtr)) - return None - def _lookup_renum_member_ty(self, class_name: str, - variant_name: str, - payload_idx: int) -> llvmlite.LLVMType | t.CPtr: - """按 (class, 变体名, payload 位置) 查找变体成员的实际 LLVM 类型 - - match 绑定用:同一 payload 位置跨变体类型不同(Int.Bits=i32 vs - Struct.Fields=Ptr),必须带变体名定位。class 指针值比较 + 变体/位置 - 内容比较。返回类型或 None(未注册/未解析成功 → 绑定回退槽位类型)。 - """ - if class_name is None or variant_name is None or self.RenumAliasVariant is None: - return None - if payload_idx < 1: - return None - cls_key: t.CSizeT = t.CSizeT(class_name) - for i in range(self.RenumAliasCount): - cls_existing: t.CSizeT = self.RenumAliasClass[i] - if cls_existing != cls_key: - continue - if self.RenumAliasVariant[i] == 0: - continue - vnt_ptr: str = (str | t.CPtr)( - t.CVoid(self.RenumAliasVariant[i], t.CPtr)) - if vnt_ptr is None or string.strcmp(vnt_ptr, variant_name) != 0: - continue - if self.RenumAliasIndex[i] != payload_idx: - continue - if self.RenumAliasTy[i] == 0: - return None - return (llvmlite.LLVMType | t.CPtr)( - t.CVoid(self.RenumAliasTy[i], t.CPtr)) +import lib.core.Gen.GenTypes as GenTypes +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HT +import lib.core.StubMerger as StubMerger +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.ClassGenBase as ClassGenBase + +# ============================================================ +# ClassGenEnum - ClassGenMixin 拆分(阶段 D):enum/union/renum 定义与变体表 +# +# 继承 ClassGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesClassDef 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class ClassGenEnum(ClassGenBase.ClassGenBase): + """enum/union/renum 定义与变体表""" + + def _resolve_enum_member_type(self, pool: memhub.MemBuddy | t.CPtr, + ann_node: ast.AST | t.CPtr, + imported_modules: str, + from_imports: str) -> llvmlite.LLVMType | t.CPtr: + """解析枚举成员的类型注解为 LLVM 整数类型""" + if ann_node is None: + return llvmlite.Int32(pool) + + k: int = ann_node.kind() + + # Attribute 节点: t.State / int / t.CInt8T 等 + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(ann_node) + if at.attr is None: + return llvmlite.Int32(pool) + # t.State → 默认 i32 + if string.strcmp(at.attr, "State") == 0: + return llvmlite.Int32(pool) + # 其他 t.CXxx 类型 + ty: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.map_t_type(pool, at.attr) + if ty is not None: + return ty + return llvmlite.Int32(pool) + + # Name 节点: from-import 形式(State / CInt) + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ann_node) + if nm.id is None: + return llvmlite.Int32(pool) + if string.strcmp(nm.id, "State") == 0: + return llvmlite.Int32(pool) + ty2: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.map_t_type(pool, nm.id) + if ty2 is not None: + return ty2 + return llvmlite.Int32(pool) + + # BinOp 节点: t.State | t.CInt8T(递归查找实际类型) + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(ann_node) + if bop.op == ast.OpKind.BitOr: + left_ty: llvmlite.LLVMType | t.CPtr = self._resolve_enum_member_type( + pool, bop.left, imported_modules, from_imports) + # 跳过 t.State(i32 默认),优先返回具体类型 + left_bits: int = self.Gen.TypeGenErr.get_llvm_type_bits(left_ty) + if left_bits != 0 and not self._is_state_annotation(bop.left): + return left_ty + right_ty: llvmlite.LLVMType | t.CPtr = self._resolve_enum_member_type( + pool, bop.right, imported_modules, from_imports) + if right_ty is not None and not self._is_state_annotation(bop.right): + return right_ty + # 两边都是 State 或无法确定,返回较宽的 + right_bits: int = self.Gen.TypeGenErr.get_llvm_type_bits(right_ty) + if left_bits >= right_bits: + return left_ty + return right_ty + # fail-fast:BinOp 但非 BitOr(未知联合运算),不再静默回退 i32 + self.Gen.TypeGenErr.fatal_error( + ann_node, f"枚举成员类型注解解析失败: {self.Gen.TypeGenResolve.annotation_to_str(ann_node)}", "TypeError") + return llvmlite.Int32(pool) # 不可达(fatal_error 已退出) + + # fail-fast:未知注解节点 kind,不再静默回退 i32 + self.Gen.TypeGenErr.fatal_error( + ann_node, f"枚举成员类型注解解析失败: {self.Gen.TypeGenResolve.annotation_to_str(ann_node)}", "TypeError") + return llvmlite.Int32(pool) # 不可达(fatal_error 已退出) + def _is_state_annotation(self, node: ast.AST | t.CPtr) -> int: + """检查注解节点是否为 t.State,返回 1=是 / 0=否""" + if node is None: + return 0 + k: int = node.kind() + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at.attr is not None and string.strcmp(at.attr, "State") == 0: + return 1 + return 0 + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is not None and string.strcmp(nm.id, "State") == 0: + return 1 + return 0 + return 0 + def _extract_int_value(self, node: ast.AST | t.CPtr) -> t.CInt64T: + """从 AST 节点提取整数值,失败返回 0""" + if node is None: + return 0 + k: int = node.kind() + if k == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + if cn.const_kind == ast.CONST_INT: + return cn.int_val + return 0 + if k == ast.ASTKind.UnaryOp: + uo: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + if uo.op == ast.OpKind.USub: + inner: t.CInt64T = self._extract_int_value(uo.operand) + return -inner + return 0 + return 0 + def _translate_enum_def(self, trans: HT.Translator | t.CPtr, + cd: ast.ClassDef | t.CPtr) -> int: + """翻译枚举类定义,返回 0""" + if cd is None or cd.name is None or trans is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + class_name: str = cd.name + + # 不按全局同名跳过:跨模块可能同名枚举(includes/w32/fileio.vp 的 + # FRESULT 与 fat32_types.vp 的 FRESULT),跳过会导致后注册模块的 + # 成员缺失(FR_OK 找不到)。register_enum 幂等返回已有 entry, + # add_enum_member 成员名去重,重复处理安全合并。 + + children: list[ast.AST | t.CPtr] | t.CPtr = cd.children + if children is None: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "%s has no body", class_name) + VLogger.warning(fb, "ENUM") + return 0 + + cn: t.CSizeT = len(children) + + # 临时数组存储成员信息 + member_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL) + member_types_buf: t.CSizeT | t.CPtr = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL) + member_values_buf: t.CInt64T | t.CPtr = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL) + if member_names_buf is None or member_types_buf is None or member_values_buf is None: + return 0 + string.memset(member_names_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL) + string.memset(member_types_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL) + string.memset(member_values_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL) + + member_count: int = 0 + next_val: t.CInt64T = 0 + + for ci in range(cn): + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + sk: int = stmt.kind() + + if sk == ast.ASTKind.AnnAssign: + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) + if aa is None or aa.target is None: + continue + + # 获取成员名 + if aa.target.kind() != ast.ASTKind.Name: + continue + tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) + if tgt.id is None: + continue + + # 解析成员类型 + member_ty: llvmlite.LLVMType | t.CPtr = self._resolve_enum_member_type( + pool, aa.annotation, trans._imported_modules, trans._from_imports) + + # 解析成员值 + has_value: int = 0 + cur_val: t.CInt64T = 0 + if aa.value is not None: + cur_val = self._extract_int_value(aa.value) + has_value = 1 + else: + cur_val = next_val + + # 下一个自动值 + next_val = cur_val + 1 + + # 存储 + if member_count < ENUM_MEMBER_MAX_LOCAL: + member_names_buf[member_count] = t.CSizeT(tgt.id) + member_types_buf[member_count] = t.CSizeT(member_ty) + member_values_buf[member_count] = cur_val + member_count += 1 + + elif sk == ast.ASTKind.Assign: + # 处理 Assign 形式的枚举成员: DEBUG = 0, INFO = 1 等 + # CEnum 子类中无类型注释的赋值也视为枚举成员 + ag: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) + if ag is None or ag.targets is None: + continue + tgts: list[ast.AST | t.CPtr] | t.CPtr = ag.targets + tn: t.CSizeT = len(tgts) + if tn == 0: + continue + # 取第一个 target 作为成员名 + t0: ast.AST | t.CPtr = tgts.get(0) + if t0 is None or t0.kind() != ast.ASTKind.Name: + continue + tgt_a: ast.Name | t.CPtr = (ast.Name | t.CPtr)(t0) + if tgt_a.id is None: + continue + + # Assign 无类型注释,默认使用 i32 + member_ty_a: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + + # 解析成员值 + cur_val_a: t.CInt64T = 0 + if ag.value is not None: + cur_val_a = self._extract_int_value(ag.value) + else: + cur_val_a = next_val + + # 下一个自动值 + next_val = cur_val_a + 1 + + # 存储 + if member_count < ENUM_MEMBER_MAX_LOCAL: + member_names_buf[member_count] = t.CSizeT(tgt_a.id) + member_types_buf[member_count] = t.CSizeT(member_ty_a) + member_values_buf[member_count] = cur_val_a + member_count += 1 + + if member_count == 0: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "%s has no members", class_name) + VLogger.warning(fb, "ENUM") + return 0 + + # 确定基准类型:所有成员类型中 Bits 最大的 + base_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + max_bits: int = 0 + for mi in range(member_count): + ty_addr: t.CSizeT = member_types_buf[mi] + if ty_addr == 0: + continue + mty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)( + t.CVoid(ty_addr, t.CPtr)) + bits: int = self.Gen.TypeGenErr.get_llvm_type_bits(mty) + if bits > max_bits: + max_bits = bits + base_ty = mty + + # 注册枚举 + entry: GenTypes.EnumEntry | t.CPtr = self.Gen.StmtGenDecl.register_enum( + pool, class_name, base_ty) + if entry is None: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "failed to register %s", class_name) + VLogger.error(fb, "ENUM") + return 0 + + # 添加成员 + for mi in range(member_count): + fname_addr: t.CSizeT = member_names_buf[mi] + if fname_addr == 0: + continue + mname: str = (str | t.CPtr)(t.CVoid(fname_addr, t.CPtr)) + fty_addr2: t.CSizeT = member_types_buf[mi] + if fty_addr2 == 0: + continue + mty2: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)( + t.CVoid(fty_addr2, t.CPtr)) + mval: t.CInt64T = member_values_buf[mi] + if mname is not None and mty2 is not None: + self.Gen.StmtGenDecl.add_enum_member(pool, entry, mname, mval, mty2) + + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "registered %s with %d members, base_bits=%d", + class_name, member_count, max_bits) + VLogger.info(fb, "ENUM") + return 0 + def _get_type_size(self, ty: llvmlite.LLVMType | t.CPtr) -> int: + """计算 LLVM 类型的字节大小(含对齐 padding)""" + if ty is None: + return 0 + match ty: + case llvmlite.LLVMType.Int(bits): + return (bits + 7) // 8 + case llvmlite.LLVMType.Float(bits): + return bits // 8 + case llvmlite.LLVMType.Ptr(pointee): + return 8 + case llvmlite.LLVMType.Array(elem_ty, count): + return self._get_type_size(elem_ty) * count + case llvmlite.LLVMType.Struct(fields, fcount, name): + # 计算结构体大小,考虑字段对齐 padding + # 规则: 每个字段的对齐 = 该字段类型的自然对齐 + # 指针/i64 → 8, i32 → 4, i16 → 2, i8 → 1 + # 结构体总大小需对齐到最大字段对齐的倍数 + total: int = 0 + max_align: int = 1 + cur: llvmlite.ParamNode | t.CPtr = fields + i: int = 0 + while cur is not None and i < fcount: + if cur.Ty is not None: + fty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(cur.Ty) + fsize: int = self._get_type_size(fty) + falign: int = self._get_type_align(fty) + # 对齐当前偏移到字段对齐边界 + if falign > 0: + rem: int = total % falign + if rem != 0: + total += falign - rem + total += fsize + if falign > max_align: + max_align = falign + cur = cur.Next + i += 1 + # 结构体总大小对齐到最大字段对齐的倍数 + rem2: int = total % max_align + if rem2 != 0: + total += max_align - rem2 + return total + case _: + return 8 + def _get_type_align(self, ty: llvmlite.LLVMType | t.CPtr) -> int: + """返回类型的自然对齐(字节)""" + if ty is None: + return 1 + match ty: + case llvmlite.LLVMType.Int(bits): + if bits <= 8: + return 1 + elif bits <= 16: + return 2 + elif bits <= 32: + return 4 + else: + return 8 + case llvmlite.LLVMType.Float(bits): + if bits <= 32: + return 4 + else: + return 8 + case llvmlite.LLVMType.Ptr(pointee): + return 8 + case llvmlite.LLVMType.Array(elem_ty, count): + return self._get_type_align(elem_ty) + case llvmlite.LLVMType.Struct(fields, fcount, name): + # 结构体的对齐 = 最大字段对齐 + max_align: int = 1 + cur: llvmlite.ParamNode | t.CPtr = fields + i: int = 0 + while cur is not None and i < fcount: + if cur.Ty is not None: + fty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(cur.Ty) + fa: int = self._get_type_align(fty) + if fa > max_align: + max_align = fa + cur = cur.Next + i += 1 + return max_align + case _: + return 8 + def _translate_union_def(self, trans: HT.Translator | t.CPtr, + cd: ast.ClassDef | t.CPtr) -> int: + """翻译联合体定义,返回 0""" + if cd is None or cd.name is None or trans is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + class_name: str = cd.name + + # 命名空间隔离:标记为当前文件可见(必须在 existing 检查之前) + self.Gen.StructGen.add_visible_struct(pool, class_name) + + # 检查是否已注册(用 SHA1 区分跨模块同名类) + existing: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module( + class_name, trans.ModuleSha1) + if existing is not None: + # Phase B: 将已存在的命名结构体注册到当前模块 + if existing.Ty is not None: + llvmlite.module_add_named_type(trans.Module, pool, existing.Ty) + # SHA1 已在 register_struct 时设置,无需再补 + return 0 + + children: list[ast.AST | t.CPtr] | t.CPtr = cd.children + if children is None: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "%s has no body", class_name) + VLogger.warning(fb, "UNION") + return 0 + + cn: t.CSizeT = len(children) + + # 临时数组存储字段信息 + field_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX) + field_types_buf: t.CSizeT | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX) + if field_names_buf is None or field_types_buf is None: + return 0 + string.memset(field_names_buf, 0, 8 * GenTypes.FIELD_MAX) + string.memset(field_types_buf, 0, 8 * GenTypes.FIELD_MAX) + + field_count: int = 0 + max_size: int = 0 + + for ci in range(cn): + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + sk: int = stmt.kind() + + if sk == ast.ASTKind.AnnAssign: + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) + if aa is None or aa.target is None: + continue + + # 获取字段名 + if aa.target.kind() != ast.ASTKind.Name: + continue + tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) + if tgt.id is None: + continue + + # 解析字段类型 + field_ty: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, aa.annotation, trans._imported_modules, trans._from_imports, trans) + if field_ty is None: + # Phase A-pre(declare_only=1):依赖的类可能尚未注册, + # 静默 return 1 让多遍收敛机制生效(renum 返回 1=跳过该类) + if trans._declare_only == 1: + return 1 + # Phase B(declare_only=0):真正的类型解析错误,fast-fail 终止 + type_name: str = self.Gen.TypeGenResolve.annotation_to_str(aa.annotation) + self.Gen.TypeGenErr.fatal_error( + aa, + f"'{type_name}' is not defined", + "NameError") + field_ty = llvmlite.Int32(pool) + + # 计算字段大小,更新 max_size + fsize: int = self._get_type_size(field_ty) + if fsize > max_size: + max_size = fsize + + # 存储到数组 + if field_count < GenTypes.FIELD_MAX: + field_names_buf[field_count] = t.CSizeT(tgt.id) + field_types_buf[field_count] = t.CSizeT(field_ty) + field_count += 1 + + if field_count == 0: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "%s has no fields", class_name) + VLogger.warning(fb, "UNION") + return 0 + + if max_size < 1: + max_size = 1 + + # 创建联合体的 LLVM 类型: Struct([Array(Int8, max_size)]) + # 即 { [max_size x i8] } + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + array_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, max_size) + + # 构建 ParamNode 链表(单字段:字节数组) + pnode: llvmlite.ParamNode | t.CPtr = pool.alloc(llvmlite.ParamNode.__sizeof__()) + if pnode is None: + return 0 + string.memset(pnode, 0, llvmlite.ParamNode.__sizeof__()) + pnode.Ty = array_ty + + # 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName" + union_type_name: str = class_name + if trans.ModuleSha1 is not None: + union_name_buf: str = pool.alloc(64) + if union_name_buf is not None: + viperlib.snprintf(union_name_buf, 64, "%s.%s", trans.ModuleSha1, class_name) + union_type_name = union_name_buf + + union_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, pnode, 1, union_type_name) + if union_ty is None: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "failed to create type for %s", class_name) + VLogger.error(fb, "UNION") + return 0 + + # Phase 1b 新注册的 union struct_ty 深拷贝到 stdlib(跨文件 reset 存活) + # StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:Phase A-pre-inc 预注册 + # includes 时 declare_only=1,若仍用 pool struct_ty,reset_to(mark2) 后 + # entry.Ty 悬空 → 后续文件 opaque 扫描跨模块引用遍历悬空 fields 崩溃 + # (LoopTest _scan_type_for_cross_module_refs 0xFFFF 根因)。 + if trans._declare_only == 0 or self.Gen.StructGen.get_stdlib_alloc() != 0: + union_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( + CompilerFactory.get_perm_pool(), union_ty) + if union_copy is not None: + union_ty = union_copy + + # 注册命名结构体到模块 + llvmlite.module_add_named_type(trans.Module, pool, union_ty) + + # 注册到 HandlesStruct(传递 SHA1 在注册时直接设置,避免跨模块同名找错 entry) + entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.register_struct( + pool, class_name, union_ty, trans.ModuleSha1) + if entry is None: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "failed to register %s", class_name) + VLogger.error(fb, "UNION") + return 0 + + # 标记为当前文件可见(命名空间隔离) + self.Gen.StructGen.add_visible_struct(pool, class_name) + + # 标记为联合体(直接用 entry,规避跨模块同名 find_struct 找错) + entry.IsUnion = 1 + + # 添加字段信息(所有字段 Index=0,因为共享偏移 0) + for fi in range(field_count): + fname_addr: t.CSizeT = field_names_buf[fi] + if fname_addr == 0: + continue + fname: str = (str | t.CPtr)(t.CVoid(fname_addr, t.CPtr)) + fty_addr2: t.CSizeT = field_types_buf[fi] + if fty_addr2 == 0: + continue + fty2: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)( + t.CVoid(fty_addr2, t.CPtr)) + if fname is not None and fty2 is not None: + self.Gen.StructGen.add_field(pool, entry, fname, fty2, None, None) + + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "registered %s with %d fields, max_size=%d", + class_name, field_count, max_size) + VLogger.info(fb, "UNION") + return 0 + def _get_annotation_field_size(self, annotation: ast.AST | t.CPtr) -> int: + """计算注解类型的字节大小,用于 REnum 布局计算""" + if annotation is None: + return 8 + k: int = annotation.kind() + # 联合类型 A | B → 指针大小 8 + if k == ast.ASTKind.BinOp: + return 8 + # Name(id) 或 Attribute(attr) → 解析类型名 + type_name: str = None + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annotation) + if nm is not None: + type_name = nm.id + elif k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annotation) + if at is not None: + type_name = at.attr + if type_name is None: + return 8 + # 内置类型 + if string.strcmp(type_name, "int") == 0: + return 4 + if string.strcmp(type_name, "CInt") == 0: + return 4 + if string.strcmp(type_name, "CInt8T") == 0: + return 1 + if string.strcmp(type_name, "CInt16T") == 0: + return 2 + if string.strcmp(type_name, "CInt32T") == 0: + return 4 + if string.strcmp(type_name, "CInt64T") == 0: + return 8 + if string.strcmp(type_name, "CChar") == 0: + return 1 + if string.strcmp(type_name, "CDouble") == 0: + return 8 + if string.strcmp(type_name, "CFloat") == 0: + return 4 + if string.strcmp(type_name, "CPtr") == 0: + return 8 + if string.strcmp(type_name, "CSizeT") == 0: + return 8 + if string.strcmp(type_name, "str") == 0: + return 8 + if string.strcmp(type_name, "bytes") == 0: + return 8 + if string.strcmp(type_name, "bool") == 0: + # bool = t.CBool = i8(1 字节) + return 1 + # 已注册的结构体类型 + struct_ty: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type(type_name) + if struct_ty is not None: + sz: int = self._get_type_size(struct_ty) + if sz > 0: + return sz + # 未注册类型 → 默认指针大小 8(可能是自引用或前向引用) + return 8 + def _translate_renum_def(self, trans: HT.Translator | t.CPtr, + cd: ast.ClassDef | t.CPtr) -> int: + """翻译 REnum 类定义,返回 0""" + if cd is None or cd.name is None or trans is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + class_name: str = cd.name + + # 命名空间隔离:标记为当前文件可见 + self.Gen.StructGen.add_visible_struct(pool, class_name) + + # 检查是否已注册(用 SHA1 区分跨模块同名类) + existing: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module( + class_name, trans.ModuleSha1) + if existing is not None: + if existing.Ty is not None: + llvmlite.module_add_named_type(trans.Module, pool, existing.Ty) + return 0 + + children: list[ast.AST | t.CPtr] | t.CPtr = cd.children + if children is None: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "%s has no body", class_name) + VLogger.warning(fb, "RENUM") + return 0 + + cn: t.CSizeT = len(children) + + # 变体最多 32 个,每个变体最多 16 个字段 + # variant_field_sizes[i][j] = 变体 i 的第 j 个字段大小 + variant_field_sizes: t.CSizeT | t.CPtr = pool.alloc(8 * 64 * 16) + if variant_field_sizes is None: + return 0 + string.memset(variant_field_sizes, 0, 8 * 64 * 16) + + variant_count: int = 0 + max_field_count: int = 0 # 所有变体中最大字段数 + + for ci in range(cn): + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + sk: int = stmt.kind() + + if sk == ast.ASTKind.ClassDef: + # 嵌套变体类 + variant_cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(stmt) + if variant_cd is None or variant_cd.children is None: + variant_count += 1 + continue + variant_children: list[ast.AST | t.CPtr] | t.CPtr = variant_cd.children + vcn: t.CSizeT = len(variant_children) + field_idx: int = 0 + for vi in range(vcn): + vstmt: ast.AST | t.CPtr = variant_children.get(vi) + if vstmt is None: + continue + vk: int = vstmt.kind() + if vk != ast.ASTKind.AnnAssign: + continue + vaa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(vstmt) + if vaa is None or vaa.target is None or vaa.annotation is None: + continue + if vaa.target.kind() != ast.ASTKind.Name: + continue + # 提取字段名 + vnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(vaa.target) + # 计算字段大小 + fsize: int = self._get_annotation_field_size(vaa.annotation) + if variant_count < 32 and field_idx < 16: + # variant_field_sizes[variant_count][field_idx] = fsize + offset: t.CSizeT = variant_count * 16 + field_idx + variant_field_sizes[offset] = t.CSizeT(fsize) + # 直接注册变体字段名别名(避免 CSizeT→str 转换问题) + # 同时解析成员实际类型(对齐 TPC class_members,供 match + # 绑定 bitcast 槽位地址用)。自引用注解(如 + # LLVMType|t.CPtr 引用自身类)此时解析失败返回 None → + # 不存类型,绑定回退槽位类型。variant_cd.name 在 1a reset + # 后悬空,注册内部会 strcpy 到 perm_pool。 + if vnm is not None and vnm.id is not None: + mem_ty_l: llvmlite.LLVMType | t.CPtr = None + if trans is not None: + mem_ty_l = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, vaa.annotation, + trans._imported_modules, + trans._from_imports, trans) + self._register_renum_field_alias( + pool, class_name, vnm.id, field_idx + 1, + mem_ty_l, variant_cd.name) + field_idx += 1 + if field_idx > max_field_count: + max_field_count = field_idx + variant_count += 1 + + if variant_count == 0: + fb2: str = VLogger.fmt_buf() + if fb2 is not None: + viperlib.snprintf(fb2, 1024, "%s has no variants", class_name) + VLogger.warning(fb2, "RENUM") + return 0 + + # 计算每个位置的最大字段大小 + # 位置 0 = __tag (i32, 4 字节) + # 位置 1+ = 变体字段 + total_positions: int = max_field_count + 1 # +1 for tag + if total_positions < 2: + total_positions = 2 # 至少 {i32, i32} + + position_max_sizes: t.CSizeT | t.CPtr = pool.alloc(8 * total_positions) + if position_max_sizes is None: + return 0 + string.memset(position_max_sizes, 0, 8 * total_positions) + + # 位置 0 = tag = 4 字节 + position_max_sizes[0] = t.CSizeT(4) + + # 位置 1+ = 每个位置取所有变体的最大字段大小 + for pos in range(1, total_positions): + pos_max: int = 0 + for vi in range(variant_count): + if vi >= 64: + break # variant_field_sizes 64 类槽上限,防读越界 + field_pos: int = pos - 1 # 变体字段从位置 0 开始 + if field_pos >= 16: + continue # 超出每变体 16 字段槽位:未写入(memset 为 0),跳过 + offset2: t.CSizeT = vi * 16 + field_pos + fsize_val: t.CSizeT = variant_field_sizes[offset2] + if fsize_val > pos_max: + pos_max = fsize_val + position_max_sizes[pos] = t.CSizeT(pos_max) + + # 构建 ParamNode 链表 + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + + first_node: llvmlite.ParamNode | t.CPtr = None + tail_node: llvmlite.ParamNode | t.CPtr = None + + for pos in range(total_positions): + psize: int = position_max_sizes[pos] + field_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if psize > 4: + field_ty = i64_ty + pnode: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, field_ty) + if pnode is None: + continue + tail_node = llvmlite.param_list_append(first_node, tail_node, pnode) + if first_node is None: + first_node = tail_node + + if first_node is None: + fb3: str = VLogger.fmt_buf() + if fb3 is not None: + viperlib.snprintf(fb3, 1024, "failed to build field list for %s", class_name) + VLogger.error(fb3, "RENUM") + return 0 + + # 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName" + renum_type_name: str = class_name + if trans.ModuleSha1 is not None: + renum_name_buf: str = pool.alloc(64) + if renum_name_buf is not None: + viperlib.snprintf(renum_name_buf, 64, "%s.%s", trans.ModuleSha1, class_name) + renum_type_name = renum_name_buf + + renum_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct( + pool, first_node, total_positions, renum_type_name) + if renum_ty is None: + fb4: str = VLogger.fmt_buf() + if fb4 is not None: + viperlib.snprintf(fb4, 1024, "failed to create type for %s", class_name) + VLogger.error(fb4, "RENUM") + return 0 + + # Phase 1b 新注册的 REnum struct_ty 深拷贝到 stdlib(跨文件 reset 存活, + # 与 entry.Ty 保持同一指针,find_struct_by_type 匹配不失效) + # StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:同 union 的悬空根因。 + if trans._declare_only == 0 or self.Gen.StructGen.get_stdlib_alloc() != 0: + renum_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( + CompilerFactory.get_perm_pool(), renum_ty) + if renum_copy is not None: + renum_ty = renum_copy + + # 注册命名结构体到模块 + llvmlite.module_add_named_type(trans.Module, pool, renum_ty) + + # 注册到 HandlesStruct + entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.register_struct( + pool, class_name, renum_ty, trans.ModuleSha1) + if entry is None: + fb5: str = VLogger.fmt_buf() + if fb5 is not None: + viperlib.snprintf(fb5, 1024, "failed to register %s", class_name) + VLogger.error(fb5, "RENUM") + return 0 + + # 修复 class_name 指针不匹配: + # 别名注册时用 class_name(= cd.name,AST 原始指针), + # 但查找时用 entry.Name(register_struct 通过 pool.alloc+strcpy 复制的副本指针)。 + # 两者是不同指针,CSizeT 指针值比较会失败。 + # 调用辅助函数将已注册别名的 class_name 统一更新为 entry.Name。 + if entry.Name is not None: + self._update_renum_alias_class_ptr(t.CSizeT(class_name), t.CSizeT(entry.Name)) + + # 添加 __tag 字段(位置 0,i32) + self.Gen.StructGen.add_field(pool, entry, "__tag", i32_ty, None, None) + + # 添加 payload 字段(位置 1+,i32 或 i64) + for pos in range(1, total_positions): + psize2: int = position_max_sizes[pos] + payload_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if psize2 > 4: + payload_ty = i64_ty + field_name_buf: str = pool.alloc(16) + if field_name_buf is not None: + viperlib.snprintf(field_name_buf, 16, "_p%d", pos) + self.Gen.StructGen.add_field(pool, entry, field_name_buf, payload_ty, None, None) + + # 注册变体名到全局变体表(供 translate_call 检测 REnum 变体构造) + self._register_renum_variants(pool, class_name, cd, variant_count) + + # 注册变体字段名别名已在变体遍历时直接完成(避免 CSizeT→str 转换问题) + + fb6: str = VLogger.fmt_buf() + if fb6 is not None: + viperlib.snprintf(fb6, 1024, "registered %s with %d variants, %d positions", + class_name, variant_count, total_positions) + VLogger.info(fb6, "RENUM") + return 0 + def _register_renum_variants(self, pool: memhub.MemBuddy | t.CPtr, + class_name: str, + cd: ast.ClassDef | t.CPtr, + variant_count: int): + """注册 REnum 类的变体名和 tag 值到全局变体表""" + if pool is None or class_name is None or cd is None: + return + if variant_count == 0: + return + children: list[ast.AST | t.CPtr] | t.CPtr = cd.children + if children is None: + return + + # 懒初始化表(首次注册时分配) + # 注意: 必须用 stdlib 分配——这些表在 1b 阶段(mark1 之后)首次分配, + # 若用 pool 会被 reset_to(mark1) 回收导致悬空(LLVMType 的 match 在 + # parser.vp 等后续文件翻译时访问已回收的表 → 崩溃)。 + if self.RenumClassNames is None: + self.RenumClassNames = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX) + self.RenumClassVariantCounts = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX) + self.RenumVariantNames = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS) + self.RenumVariantTags = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS) + if (self.RenumClassNames is None or self.RenumClassVariantCounts is None + or self.RenumVariantNames is None or self.RenumVariantTags is None): + self.RenumClassNames = None + return + string.memset(self.RenumClassNames, 0, 8 * RENUM_CLASS_MAX) + string.memset(self.RenumClassVariantCounts, 0, 8 * RENUM_CLASS_MAX) + string.memset(self.RenumVariantNames, 0, 8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS) + string.memset(self.RenumVariantTags, 0, 8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS) + self.RenumClassCount = 0 + + # ============ 临时诊断(0xb0 崩溃定位,定位后移除) ============ + # lazy init 后 RenumClassNames 必非空;此时若 RCV 异常(null/小值) + # 说明字段被越界覆盖或 __init__ 未生效,fail-fast 暴露崩溃现场。 + fb_diag: str = VLogger.fmt_buf() + if fb_diag is not None: + viperlib.snprintf(fb_diag, 1024, + "[RENUM-DIAG] self=%llu RN=%llu RCV=%llu RVN=%llu RVT=%llu RCount=%d class=%s", + t.CUInt64T(self), t.CUInt64T(self.RenumClassNames), + t.CUInt64T(self.RenumClassVariantCounts), + t.CUInt64T(self.RenumVariantNames), + t.CUInt64T(self.RenumVariantTags), + self.RenumClassCount, class_name) + VLogger.info(fb_diag, "RENUM") + rcv_chk: t.CUInt64T = t.CUInt64T(self.RenumClassVariantCounts) + if rcv_chk == 0 or rcv_chk < 4096: + fb_fail: str = VLogger.fmt_buf() + if fb_fail is not None: + viperlib.snprintf(fb_fail, 1024, + "[RENUM-FAIL] RCV=%llu 异常(lazy init 后应为 perm_pool 地址),RenumClassCount=%d class=%s", + t.CUInt64T(self.RenumClassVariantCounts), + self.RenumClassCount, class_name) + VLogger.error(fb_fail, "RENUM") + stdlib.exit(1) + # ============ 临时诊断结束 ============ + + # 检查是否已注册(避免重复注册) + for i in range(self.RenumClassCount): + existing: str = self.RenumClassNames[i] + if existing is not None and string.strcmp(existing, class_name) == 0: + return + + # 表已满 + if self.RenumClassCount >= RENUM_CLASS_MAX: + return + + # 注册类名(strcpy 到 perm_pool:1a 每文件 reset 后 AST 裸指针悬空, + # _lookup_renum_variant/_is_renum_class_name 的 strcmp 会读毒化内存) + idx: int = self.RenumClassCount + cn_len_rv: t.CSizeT = string.strlen(class_name) + cn_buf_rv: str = CompilerFactory.get_perm_pool().alloc(cn_len_rv + 1) + if cn_buf_rv is None: + return + string.strcpy(cn_buf_rv, class_name) + self.RenumClassNames[idx] = t.CSizeT(cn_buf_rv) + self.RenumClassVariantCounts[idx] = variant_count + + # 遍历 children,提取嵌套变体类名并注册 + cn: t.CSizeT = len(children) + tag: int = 0 + for ci in range(cn): + if tag >= variant_count: + break + if tag >= RENUM_VARIANT_PER_CLASS: + # 每类固定 32 槽:变体超过上限继续写会越界污染相邻类槽,fail-fast 报错 + fb_rv: str = VLogger.fmt_buf() + if fb_rv is not None: + viperlib.snprintf(fb_rv, 1024, + "REnum 变体数超过上限 %d: %s", RENUM_VARIANT_PER_CLASS, class_name) + VLogger.error(fb_rv, "RENUM") + break + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + if stmt.kind() != ast.ASTKind.ClassDef: + continue + vcd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(stmt) + if vcd is None or vcd.name is None: + continue + name_offset: t.CSizeT = idx * RENUM_VARIANT_PER_CLASS + tag + # 变体名同样 strcpy 到 perm_pool(1a 每文件 reset 后 vcd.name 悬空) + vn_len_rv: t.CSizeT = string.strlen(vcd.name) + vn_buf_rv: str = CompilerFactory.get_perm_pool().alloc(vn_len_rv + 1) + if vn_buf_rv is None: + break + string.strcpy(vn_buf_rv, vcd.name) + self.RenumVariantNames[name_offset] = t.CSizeT(vn_buf_rv) + self.RenumVariantTags[name_offset] = tag + tag += 1 + + self.RenumClassCount = idx + 1 + def _lookup_renum_variant(self, variant_name: str) -> str: + """查找变体名所属的 REnum 类名 + + 返回: class_name (str),或 None + """ + if variant_name is None or self.RenumClassNames is None: + return None + + for i in range(self.RenumClassCount): + vcount: int = self.RenumClassVariantCounts[i] + for j in range(vcount): + name_offset: t.CSizeT = i * RENUM_VARIANT_PER_CLASS + j + vname: str = self.RenumVariantNames[name_offset] + if vname is not None and string.strcmp(vname, variant_name) == 0: + cls_nm: str = self.RenumClassNames[i] + return cls_nm + return None + def _is_renum_class_name(self, class_name: str) -> int: + """检查名称是否是已注册的 REnum 类名,返回 1=是 / 0=否""" + if class_name is None or self.RenumClassNames is None: + return 0 + for i in range(self.RenumClassCount): + existing: str = self.RenumClassNames[i] + if existing is not None and string.strcmp(existing, class_name) == 0: + return 1 + return 0 + def _lookup_renum_variant_in_class(self, class_name: str, variant_name: str) -> int: + """在指定 REnum 类中查找变体,返回 tag 值或 -1""" + if class_name is None or variant_name is None or self.RenumClassNames is None: + return -1 + for i in range(self.RenumClassCount): + existing: str = self.RenumClassNames[i] + if existing is None or string.strcmp(existing, class_name) != 0: + continue + vcount: int = self.RenumClassVariantCounts[i] + for j in range(vcount): + name_offset: t.CSizeT = i * RENUM_VARIANT_PER_CLASS + j + vname: str = self.RenumVariantNames[name_offset] + if vname is not None and string.strcmp(vname, variant_name) == 0: + return self.RenumVariantTags[name_offset] + return -1 + return -1 + def _register_renum_field_alias(self, pool: memhub.MemBuddy | t.CPtr, + class_name: str, + field_name: str, + payload_idx: int, + field_ty: llvmlite.LLVMType | t.CPtr = None, + variant_name: str = None): + """注册 REnum 变体字段名别名到全局表 + + field_ty: 变体成员的实际 LLVM 类型(可选;自引用类型如 + LLVMType|t.CPtr 在注册期解析失败时为 None,match 绑定回退槽位类型)。 + variant_name: 所属变体名(可选;match 绑定按 (class, 变体, 位置) 定位成员) + """ + if pool is None or class_name is None or field_name is None: + return + if payload_idx < 1: + return + + # 懒初始化表(perm_pool:1a 每文件 reset 后表本体不被回收) + if self.RenumAliasClass is None: + alias_pool_rfa: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool() + self.RenumAliasClass = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX) + self.RenumAliasField = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX) + self.RenumAliasIndex = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX) + self.RenumAliasTy = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX) + self.RenumAliasVariant = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX) + if (self.RenumAliasClass is None or self.RenumAliasField is None + or self.RenumAliasIndex is None or self.RenumAliasTy is None + or self.RenumAliasVariant is None): + self.RenumAliasClass = None + return + string.memset(self.RenumAliasClass, 0, 8 * RENUM_ALIAS_MAX) + string.memset(self.RenumAliasField, 0, 8 * RENUM_ALIAS_MAX) + string.memset(self.RenumAliasIndex, 0, 8 * RENUM_ALIAS_MAX) + string.memset(self.RenumAliasTy, 0, 8 * RENUM_ALIAS_MAX) + string.memset(self.RenumAliasVariant, 0, 8 * RENUM_ALIAS_MAX) + self.RenumAliasCount = 0 + + if self.RenumAliasCount >= RENUM_ALIAS_MAX: + return + + # 检查是否已注册(避免重复)— class 用 CSizeT 指针值比较(契约不变), + # field 槽位是 perm_pool 拷贝、key 是原指针,指针比较恒不相等 → 改 strcmp + cls_key: t.CSizeT = t.CSizeT(class_name) + for i in range(self.RenumAliasCount): + cls_existing: t.CSizeT = self.RenumAliasClass[i] + if cls_existing == cls_key: + fld_existing_ptr: str = (str | t.CPtr)( + t.CVoid(self.RenumAliasField[i], t.CPtr)) + if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0: + return + + idx: int = self.RenumAliasCount + self.RenumAliasClass[idx] = cls_key + # field_name 存 AST 裸指针,1a 每文件 reset 后悬空;_lookup_renum_field_alias + # 用 strcmp 内容比较 → strcpy 到 perm_pool 不影响查找。 + # class_name 槽位保持原指针:_update_renum_alias_class_ptr 会统一为 + # entry.Name(perm_pool 拷贝),指针值比较契约不变。 + fn_len_rfa: t.CSizeT = string.strlen(field_name) + fn_buf_rfa: str = CompilerFactory.get_perm_pool().alloc(fn_len_rfa + 1) + if fn_buf_rfa is None: + return + string.strcpy(fn_buf_rfa, field_name) + self.RenumAliasField[idx] = t.CSizeT(fn_buf_rfa) + self.RenumAliasIndex[idx] = t.CSizeT(payload_idx) + # 成员类型深拷贝到 perm_pool(1a 每文件 reset 后 pool 类型悬空; + # 未解析成功(自引用等)存 0,绑定回退槽位类型) + self.RenumAliasTy[idx] = 0 + if field_ty is not None: + ty_copy_rfa: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( + CompilerFactory.get_perm_pool(), field_ty) + if ty_copy_rfa is not None: + self.RenumAliasTy[idx] = t.CSizeT(ty_copy_rfa) + # 变体名同样 strcpy 到 perm_pool(1a reset 后 variant_cd.name 悬空) + self.RenumAliasVariant[idx] = 0 + if variant_name is not None: + vn_len_rfa: t.CSizeT = string.strlen(variant_name) + vn_buf_rfa: str = CompilerFactory.get_perm_pool().alloc(vn_len_rfa + 1) + if vn_buf_rfa is not None: + string.strcpy(vn_buf_rfa, variant_name) + self.RenumAliasVariant[idx] = t.CSizeT(vn_buf_rfa) + self.RenumAliasCount = idx + 1 + def _update_renum_alias_class_ptr(self, old_ptr: t.CSizeT, new_ptr: t.CSizeT): + """更新别名表中的 class_name 指针,从 old_ptr 更新为 new_ptr""" + if old_ptr == new_ptr: + return + if self.RenumAliasClass is None: + return + for i in range(self.RenumAliasCount): + if self.RenumAliasClass[i] == old_ptr: + self.RenumAliasClass[i] = new_ptr + def _lookup_renum_field_alias(self, class_name: str, field_name: str) -> int: + """查找 REnum 变体字段名的 payload 索引,返回索引或 -1 + + class_name: 用 CSizeT 指针值比较(_update_renum_alias_class_ptr 已统一指针) + field_name: 用 strcmp 内容比较(注册时 vnm.id 与查找时 at.attr 是不同指针) + """ + if class_name is None or field_name is None or self.RenumAliasClass is None: + return -1 + cls_key: t.CSizeT = t.CSizeT(class_name) + for i in range(self.RenumAliasCount): + cls_existing: t.CSizeT = self.RenumAliasClass[i] + if cls_existing == cls_key: + # field_name 用 strcmp 内容比较(指针不同但内容相同) + fld_existing_ptr: str = (str | t.CPtr)( + t.CVoid(self.RenumAliasField[i], t.CPtr)) + if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0: + return self.RenumAliasIndex[i] + return -1 + def _lookup_renum_field_alias_ty(self, class_name: str, + field_name: str) -> llvmlite.LLVMType | t.CPtr: + """查找 REnum 变体成员的实际 LLVM 类型,返回类型或 None + + 与 _lookup_renum_field_alias 同表同键(class 指针值比较 + field strcmp)。 + 注册期未解析成功(自引用类型等)槽位为 0 → 返回 None,绑定回退槽位类型。 + """ + if class_name is None or field_name is None or self.RenumAliasTy is None: + return None + cls_key: t.CSizeT = t.CSizeT(class_name) + for i in range(self.RenumAliasCount): + cls_existing: t.CSizeT = self.RenumAliasClass[i] + if cls_existing == cls_key: + fld_existing_ptr: str = (str | t.CPtr)( + t.CVoid(self.RenumAliasField[i], t.CPtr)) + if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0: + if self.RenumAliasTy[i] == 0: + return None + return (llvmlite.LLVMType | t.CPtr)( + t.CVoid(self.RenumAliasTy[i], t.CPtr)) + return None + def _lookup_renum_member_ty(self, class_name: str, + variant_name: str, + payload_idx: int) -> llvmlite.LLVMType | t.CPtr: + """按 (class, 变体名, payload 位置) 查找变体成员的实际 LLVM 类型 + + match 绑定用:同一 payload 位置跨变体类型不同(Int.Bits=i32 vs + Struct.Fields=Ptr),必须带变体名定位。class 指针值比较 + 变体/位置 + 内容比较。返回类型或 None(未注册/未解析成功 → 绑定回退槽位类型)。 + """ + if class_name is None or variant_name is None or self.RenumAliasVariant is None: + return None + if payload_idx < 1: + return None + cls_key: t.CSizeT = t.CSizeT(class_name) + for i in range(self.RenumAliasCount): + cls_existing: t.CSizeT = self.RenumAliasClass[i] + if cls_existing != cls_key: + continue + if self.RenumAliasVariant[i] == 0: + continue + vnt_ptr: str = (str | t.CPtr)( + t.CVoid(self.RenumAliasVariant[i], t.CPtr)) + if vnt_ptr is None or string.strcmp(vnt_ptr, variant_name) != 0: + continue + if self.RenumAliasIndex[i] != payload_idx: + continue + if self.RenumAliasTy[i] == 0: + return None + return (llvmlite.LLVMType | t.CPtr)( + t.CVoid(self.RenumAliasTy[i], t.CPtr)) return None \ No newline at end of file diff --git a/App/lib/core/Gen/ClassGenGeneric.vp b/App/lib/core/Gen/ClassGenGeneric.vp index 87ea390..3210b68 100644 --- a/App/lib/core/Gen/ClassGenGeneric.vp +++ b/App/lib/core/Gen/ClassGenGeneric.vp @@ -1,715 +1,709 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import viperlib -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesEnum as HandlesEnum -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.StubMerger as StubMerger -import lib.core.CompilerFactory as CompilerFactory - - -import lib.core.Gen.ClassGenBase as ClassGenBase -import lib.core.StubMergerStore as StubMergerStore - - -# 泛型特化递归深度上限(泛型循环套用防护) -# 正常嵌套特化深度 ≤ 3(如 list[list[str]]);64 远超合理值,命中即循环。 -# (原 HandlesClassDef/ClassGenMixin 顶层常量,阶段 D 拆分时遗漏,补回) -GENERIC_SPEC_MAX_DEPTH: t.CDefine = 64 -# 泛型模板表容量上限(与 GenericClassNames 等 pool 表可容纳的模板数对齐; -# 原 ClassGenMixin 顶层常量,阶段 D 拆分时遗漏,补回) -GENERIC_TEMPLATE_MAX: t.CDefine = 512 - -# ============================================================ -# ClassGenGeneric - ClassGenMixin 拆分(阶段 D):泛型模板注册/特化/克隆 -# -# 继承 ClassGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesClassDef 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class ClassGenGeneric(ClassGenBase.ClassGenBase): - """泛型模板注册/特化/克隆""" - - # ============================================================ - # 簇 C:泛型模板注册/特化(P5-2 第三阶段迁移,函数体来自 - # HandlesClassDef.vp,逻辑零改动) - # - # 说明: - # - _generic_class_* 全局表已迁入 self.GenericClassNames/ - # GenericClassNodes/GenericClassSha1s(P5-2 收尾) - # - _spec_* 全局缓存迁移为 self.SpecKeys/SpecNames/SpecCount - # ============================================================ - - def _is_generic_class(self, tp: list[str] | t.CPtr) -> int: - """检查 ClassDef 是否有类型参数(泛型类),返回 1=是 / 0=否 - - 接收 type_params 而非 cd,避免 cd.type_params 属性访问 - 因跨模块类型推断失败返回 None。 - """ - if tp is None: - return 0 - return 1 - def _register_generic_template(self, pool: memhub.MemBuddy | t.CPtr, - cd: ast.ClassDef | t.CPtr, - module_sha1: str): - """注册泛型类模板(类名 + ClassDef 节点 + 来源模块 SHA1)""" - if self.GenericClassNames is None: - self.GenericClassNames = list[str](pool, 8) - self.GenericClassNodes = list[ast.ClassDef | t.CPtr](pool, 8) - self.GenericClassSha1s = list[str](pool, 8) - self.GenericClassFiles = list[str](pool, 8) - if self.GenericClassTpParams is None: - self.GenericClassTpParams = CompilerFactory.get_perm_pool().alloc(GENERIC_TEMPLATE_MAX * 8) - if self.GenericClassTpParams is None: - return - string.memset(self.GenericClassTpParams, 0, GENERIC_TEMPLATE_MAX * 8) - # 用局部变量接收 list,触发类型推断(避免字段 __len__ 失败) - names_local: list[str] | t.CPtr = self.GenericClassNames - cn: t.CSizeT = len(names_local) - i: t.CSizeT - for i in range(cn): - nm: str = names_local.get(i) - if nm is not None and string.strcmp(nm, cd.name) == 0: - return - # type_params stdlib 深拷贝:模板节点的 type_params 是 pool 分配的 - tp_names_buf: str = self._copy_type_params_stdlib(cd.type_params) - self.GenericClassNames.append(cd.name) - self.GenericClassNodes.append(cd) - self.GenericClassSha1s.append(module_sha1) - # 同时保存模板来源文件路径(错误定位用,见字段注释) - self.GenericClassFiles.append(HandlesType.get_current_file()) - if tp_names_buf is not None and cn < GENERIC_TEMPLATE_MAX: - self.GenericClassTpParams[cn] = t.CSizeT(tp_names_buf) - def _copy_type_params_stdlib(self, tp: list[str] | t.CPtr) -> str: - """将模板 type_params 深拷贝为空格分隔、NUL 结尾的 stdlib 缓冲区 - - TPC Python 参考实现:type_params = [tp.name for tp in Node.type_params] - (Python 字符串不可变天然跨阶段存活);Viper 的 type_params 是 pool - 分配 list,跨 Phase 内容可能被复用污染,必须注册时拷贝到 stdlib。 - 返回缓冲区指针;tp 为 None(非泛型)或分配失败返回 None。 - """ - if tp is None: - return None - tp_n: t.CSizeT = len(tp) - if tp_n == 0: - return None - # 计算总长:各名字长度 + (n-1) 个空格 + NUL - total: t.CSizeT = 1 - ti: t.CSizeT - for ti in range(tp_n): - tp_name: str = tp.get(ti) - if tp_name is not None: - total += string.strlen(tp_name) + 1 - buf: str = CompilerFactory.get_perm_pool().alloc(total) - if buf is None: - return None - buf[0] = '\0' - for ti in range(tp_n): - tp_name = tp.get(ti) - if tp_name is None: - continue - if ti > 0 and buf[0] != '\0': - string.strcat(buf, " ") - string.strcat(buf, tp_name) - return buf - def _find_generic_template_tp_params(self, pool: memhub.MemBuddy | t.CPtr, - class_name: str) -> list[str] | t.CPtr: - """查找泛型类模板的类型参数名列表,未找到返回 None - - 从注册时深拷贝的 stdlib 缓冲区重建当前 pool 的 list[str] - (特化期间 pool 有效,方法与体翻译共用)。与 GenericClassNames 同序。 - """ - if self.GenericClassNames is None or class_name is None \ - or self.GenericClassTpParams is None: - return None - names_local: list[str] | t.CPtr = self.GenericClassNames - cn: t.CSizeT = len(names_local) - i: t.CSizeT - for i in range(cn): - nm: str = names_local.get(i) - if nm is not None and string.strcmp(nm, class_name) == 0: - if i >= GENERIC_TEMPLATE_MAX: - return None - buf_addr: t.CSizeT = self.GenericClassTpParams[i] - if buf_addr == 0: - return None - buf_tp: str = (str | t.CPtr)(t.CVoid(buf_addr, t.CPtr)) - # 空格分隔 → list[str] - # 注意:list[str](pool, 8) 第二个参数是 elem_size(指针 8 字节), - # 不是容量!传 4 会导致 get(i) 偏移算错、append 相互覆盖 - # (Pair[T1,T2] 的 seg1 写 data+4 覆盖 seg0 高 4 字节 → strcmp - # 收到 0x15B78D5015B78CB0 混合垃圾崩溃,GenericTest 回归根因) - tp_list: list[str] | t.CPtr = list[str](pool, 8) - if tp_list is None: - return None - seg_start: t.CSizeT = 0 - pos: t.CSizeT = 0 - blen: t.CSizeT = string.strlen(buf_tp) - while pos <= blen: - if buf_tp[pos] == ' ' or buf_tp[pos] == '\0': - seg_len: t.CSizeT = pos - seg_start - if seg_len > 0: - seg: str = pool.alloc(seg_len + 1) - if seg is not None: - string.strncpy(seg, buf_tp + seg_start, seg_len) - seg[seg_len] = '\0' - tp_list.append(seg) - seg_start = pos + 1 - pos += 1 - return tp_list - return None - def _find_generic_template(self, class_name: str) -> ast.ClassDef | t.CPtr: - """查找泛型类模板,返回 ClassDef 节点或 None""" - if self.GenericClassNames is None or class_name is None: - return None - # 用局部变量接收 list,触发类型推断(避免字段 __len__ 失败) - names_local: list[str] | t.CPtr = self.GenericClassNames - nodes_local: list[ast.ClassDef | t.CPtr] | t.CPtr = self.GenericClassNodes - cn: t.CSizeT = len(names_local) - i: t.CSizeT - for i in range(cn): - nm: str = names_local.get(i) - if nm is not None and string.strcmp(nm, class_name) == 0: - node: ast.ClassDef | t.CPtr = nodes_local.get(i) - return node - return None - def _find_generic_template_sha1(self, class_name: str) -> str: - """查找泛型类模板的来源模块 SHA1,未找到返回 None""" - if self.GenericClassNames is None or class_name is None: - return None - # 用局部变量接收 list,触发类型推断 - names_local: list[str] | t.CPtr = self.GenericClassNames - sha1s_local: list[str] | t.CPtr = self.GenericClassSha1s - cn: t.CSizeT = len(names_local) - i: t.CSizeT - for i in range(cn): - nm: str = names_local.get(i) - if nm is not None and string.strcmp(nm, class_name) == 0: - sha1_val: str = sha1s_local.get(i) - return sha1_val - return None - def _find_generic_template_file(self, class_name: str) -> str: - """查找泛型类模板的来源文件路径,未找到返回 None - - 与 _find_generic_template_sha1 同表同序;供特化翻译模板方法体时 - 临时切换 CurrentFile(错误定位:模板 node.lineno 需配模板文件路径)。 - """ - if self.GenericClassNames is None or class_name is None: - return None - names_local: list[str] | t.CPtr = self.GenericClassNames - files_local: list[str] | t.CPtr = self.GenericClassFiles - cn: t.CSizeT = len(names_local) - i: t.CSizeT - for i in range(cn): - nm: str = names_local.get(i) - if nm is not None and string.strcmp(nm, class_name) == 0: - f_val: str = files_local.get(i) - return f_val - return None - def _mangle_generic_class_name(self, pool: memhub.MemBuddy | t.CPtr, - class_name: str, - type_args: list[str] | t.CPtr) -> str: - """生成特化类名: list + [int] -> list[int] - - 分配新缓冲区拼接,避免原地 strcat 导致缓冲区溢出 - """ - if class_name is None or type_args is None or pool is None: - return class_name - n: t.CSizeT = len(type_args) - if n == 0: - return class_name - # 计算总长度: class_name + "[" + arg0 + "," + arg1 + ... + "]" + NUL - total_len: t.CSizeT = string.strlen(class_name) + 2 # "[" 和 "]" - i: t.CSizeT - for i in range(n): - if i > 0: - total_len += 1 # "," - ta: str = type_args.get(i) - if ta is not None: - total_len += string.strlen(ta) - total_len += 1 # NUL - # 分配新缓冲区 - mangled: str = pool.alloc(total_len) - if mangled is None: - return class_name - mangled[0] = '\0' - string.strcat(mangled, class_name) - string.strcat(mangled, "[") - for i in range(n): - if i > 0: - string.strcat(mangled, ",") - ta: str = type_args.get(i) - if ta is not None: - string.strcat(mangled, ta) - string.strcat(mangled, "]") - return mangled - def _clone_annotation(self, pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr, - tp_names: list[str] | t.CPtr, - type_args: list[str] | t.CPtr) -> ast.AST | t.CPtr: - """拷贝类型注解表达式,替换类型参数 T 为具体类型名 - - tp_names: 类型参数名列表 ['T'] - type_args: 类型实参名列表 ['int'] - """ - if node is None: - return None - k: int = node.kind() - - # Name: 可能是类型参数 T - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm.id is not None: - n: t.CSizeT = len(tp_names) if tp_names is not None else 0 - i: t.CSizeT - for i in range(n): - tpn: str = tp_names.get(i) - if tpn is not None and string.strcmp(nm.id, tpn) == 0: - ta: str = type_args.get(i) - # 类型实参可能是复合类型(如 "AST|t.CPtr"),用 _parse_type_string 解析 - parsed_node: ast.AST | t.CPtr = HandlesType._parse_type_string(pool, ta, nm.ctx) - return parsed_node - return ast.Name(pool, nm.id, nm.ctx) - return None - - # Attribute: t.CPtr 等 - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - new_value: ast.AST | t.CPtr = self._clone_annotation(pool, at.value, tp_names, type_args) - return ast.Attribute(pool, new_value, at.attr, at.ctx) - - # BinOp: T | t.CPtr 等 - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - new_left: ast.AST | t.CPtr = self._clone_annotation(pool, bop.left, tp_names, type_args) - new_right: ast.AST | t.CPtr = self._clone_annotation(pool, bop.right, tp_names, type_args) - return ast.BinOp(pool, new_left, bop.op, new_right) - - # Subscript: list[int] 等 - if k == ast.ASTKind.Subscript: - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - new_value2: ast.AST | t.CPtr = self._clone_annotation(pool, sub.value, tp_names, type_args) - new_slice: ast.AST | t.CPtr = self._clone_annotation(pool, sub.slice, tp_names, type_args) - return ast.Subscript(pool, new_value2, new_slice, sub.ctx) - - # Tuple: (T, int) 等 - if k == ast.ASTKind.Tuple: - tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(node) - new_elts: list[ast.AST | t.CPtr] | t.CPtr = list[ast.AST | t.CPtr](pool, 8) - if tup.elts is not None: - tup_elts: list[ast.AST | t.CPtr] | t.CPtr = tup.elts - en: t.CSizeT = len(tup_elts) - ei: t.CSizeT - for ei in range(en): - el: ast.AST | t.CPtr = tup_elts.get(ei) - new_el: ast.AST | t.CPtr = self._clone_annotation(pool, el, tp_names, type_args) - if new_el is not None: - new_elts.append(new_el) - return ast.Tuple(pool, new_elts, tup.ctx) - - # Constant: 默认值等 - if k == ast.ASTKind.Constant: - cnst: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) - return ast.Constant(pool, cnst.const_kind, cnst.int_val, cnst.float_val, - cnst.str_val, cnst.lineno, cnst.col_offset) - - # 其他: 直接引用(不拷贝) - return node - def _clone_arguments(self, pool: memhub.MemBuddy | t.CPtr, - args: ast.AST | t.CPtr, - tp_names: list[str] | t.CPtr, - type_args: list[str] | t.CPtr) -> ast.AST | t.CPtr: - """拷贝 Arguments 节点,替换 arg annotation 中的 T""" - if args is None: - return None - if args.kind() != ast.ASTKind.Arguments: - return args - old_args: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args) - # 拷贝 args 列表,替换每个 Arg 的 annotation - new_arg_list: list[ast.AST | t.CPtr] | t.CPtr = list[ast.AST | t.CPtr](pool, 8) - if old_args.args is not None: - old_arg_list: list[ast.AST | t.CPtr] | t.CPtr = old_args.args - an: t.CSizeT = len(old_arg_list) - ai: t.CSizeT - for ai in range(an): - arg_node: ast.AST | t.CPtr = old_arg_list.get(ai) - if arg_node is None: - continue - if arg_node.kind() == ast.ASTKind.Arg: - ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(arg_node) - new_anno: ast.AST | t.CPtr = self._clone_annotation(pool, ag.annotation, tp_names, type_args) - new_arg: ast.Arg | t.CPtr = ast.Arg(pool, ag.arg, new_anno) - new_arg_list.append(new_arg) - else: - new_arg_list.append(arg_node) - return ast.Arguments(pool, new_arg_list, old_args.vararg, old_args.kwarg, - old_args.defaults, old_args.kw_defaults) - def _clone_classdef_for_spec(self, pool: memhub.MemBuddy | t.CPtr, - cd: ast.ClassDef | t.CPtr, - spec_name: str, - tp_names: list[str] | t.CPtr, - type_args: list[str] | t.CPtr) -> ast.ClassDef | t.CPtr: - """拷贝 ClassDef 节点用于泛型特化 - - - 替换类名为 spec_name - - 清除 type_params(特化后不是泛型类) - - 拷贝 children 中的 AnnAssign 和 FunctionDef,替换类型注解中的 T - - 方法体直接引用原始节点(通过 type_map 上下文处理 T) - """ - # 创建新 ClassDef(type_params=None 表示非泛型) - new_cd: ast.ClassDef | t.CPtr = ast.ClassDef(pool, spec_name, cd.bases, cd.keywords, - cd.decorator_list, None) - # 拷贝 children - if cd.children is not None: - cd_children: list[ast.AST | t.CPtr] | t.CPtr = cd.children - cn: t.CSizeT = len(cd_children) - ci: t.CSizeT - for ci in range(cn): - child: ast.AST | t.CPtr = cd_children.get(ci) - if child is None: - continue - ck: int = child.kind() - - if ck == ast.ASTKind.AnnAssign: - aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(child) - new_target: ast.AST | t.CPtr = aa.target - new_anno2: ast.AST | t.CPtr = self._clone_annotation(pool, aa.annotation, tp_names, type_args) - new_value3: ast.AST | t.CPtr = aa.value - new_aa: ast.AnnAssign | t.CPtr = ast.AnnAssign(pool, new_target, new_anno2, new_value3, aa.simple) - new_cd.append(new_aa) - - elif ck == ast.ASTKind.FunctionDef: - fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child) - new_args2: ast.AST | t.CPtr = self._clone_arguments(pool, fd.args, tp_names, type_args) - new_returns2: ast.AST | t.CPtr = self._clone_annotation(pool, fd.returns, tp_names, type_args) - new_fd: ast.FunctionDef | t.CPtr = ast.FunctionDef(pool, fd.name, new_args2, - fd.decorator_list, new_returns2, 0) - # 方法体直接引用原始节点 - if fd.children is not None: - fd_children: list[ast.AST | t.CPtr] | t.CPtr = fd.children - bcn: t.CSizeT = len(fd_children) - bci: t.CSizeT - for bci in range(bcn): - body_stmt: ast.AST | t.CPtr = fd_children.get(bci) - if body_stmt is not None: - new_fd.append(body_stmt) - new_cd.append(new_fd) - - else: - new_cd.append(child) - - return new_cd - def _find_cached_spec(self, spec_key: str) -> str: - """查找已缓存的特化名,未找到返回 None""" - if self.SpecKeys is None or spec_key is None: - return None - i: int - for i in range(self.SpecCount): - key_addr: t.CSizeT = self.SpecKeys[i] - if key_addr != 0: - k: str = (str | t.CPtr)(t.CVoid(key_addr, t.CPtr)) - if k is not None and string.strcmp(k, spec_key) == 0: - name_addr: t.CSizeT = self.SpecNames[i] - if name_addr != 0: - return (str | t.CPtr)(t.CVoid(name_addr, t.CPtr)) - return None - def _cache_spec(self, pool: memhub.MemBuddy | t.CPtr, spec_key: str, spec_name: str): - """缓存特化结果(stdlib 深拷贝存储,跨文件安全)""" - if spec_key is None or spec_name is None: - return - if self.SpecKeys is None: - self.SpecKeys = CompilerFactory.get_perm_pool().alloc(SPEC_CACHE_MAX * 8) - self.SpecNames = CompilerFactory.get_perm_pool().alloc(SPEC_CACHE_MAX * 8) - if self.SpecKeys is None or self.SpecNames is None: - return - string.memset(self.SpecKeys, 0, SPEC_CACHE_MAX * 8) - string.memset(self.SpecNames, 0, SPEC_CACHE_MAX * 8) - self.SpecCount = 0 - if self.SpecCount >= SPEC_CACHE_MAX: - return - # 深拷贝字符串到 stdlib 区 - key_len: t.CSizeT = string.strlen(spec_key) - name_len: t.CSizeT = string.strlen(spec_name) - key_copy: str = CompilerFactory.get_perm_pool().alloc(key_len + 1) - name_copy: str = CompilerFactory.get_perm_pool().alloc(name_len + 1) - if key_copy is None or name_copy is None: - return - string.strcpy(key_copy, spec_key) - string.strcpy(name_copy, spec_name) - self.SpecKeys[self.SpecCount] = t.CSizeT(key_copy) - self.SpecNames[self.SpecCount] = t.CSizeT(name_copy) - self.SpecCount += 1 - def _merge_template_imports(self, trans: HT.Translator | t.CPtr, - template_sha1: str) -> None: - """将模板模块的 imports 并入 trans._imported_modules(空格分隔)""" - if trans is None or template_sha1 is None: - return - tdeps: str = StubMergerStore.LookupIncludesDeps(template_sha1) - if tdeps is None or tdeps[0] == '\0': - return - cur: str = trans._imported_modules - if cur is None or cur[0] == '\0': - trans._imported_modules = tdeps - return - cur_len: t.CSizeT = string.strlen(cur) - td_len: t.CSizeT = string.strlen(tdeps) - merged: str = trans.Pool.alloc(cur_len + td_len + 2) - if merged is None: - return - string.strcpy(merged, cur) - merged[cur_len] = ' ' - string.strcpy(merged + cur_len + 1, tdeps) - trans._imported_modules = merged - def _record_spec_trigger(self, pool: memhub.MemBuddy | t.CPtr, - spec_name: str, trigger_sha1: str) -> int: - """记录泛型特化类的触发文件 sha1(StructEntry.SpecTriggerSha1) - - 特化类 ModuleSha1=模板 sha1(方法名带模板前缀),Phase A _deps_pending - 作废重译时 reset_module_methods_emitted 按当前文件 sha1 匹配不到 → - 特化方法体 MethodsEmitted 残留 1 → 下遍不补译 → 链接 undefined symbol。 - 记录触发文件 sha1 后按此精确重置(见 StructGenMixin.reset_module_methods_emitted)。 - """ - if spec_name is None or trigger_sha1 is None: - return 0 - entry_rt: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name) - if entry_rt is None: - return 0 - if string.strcmp(entry_rt.Name, spec_name) != 0: - return 0 - ts_len_r: t.CSizeT = string.strlen(trigger_sha1) - ts_buf_r: str = CompilerFactory.get_perm_pool().alloc(ts_len_r + 1) - if ts_buf_r is None: - return 0 - string.strcpy(ts_buf_r, trigger_sha1) - entry_rt.SpecTriggerSha1 = ts_buf_r - return 1 - def _specialize_generic_class(self, trans: HT.Translator | t.CPtr, - class_name: str, - type_args: list[str] | t.CPtr) -> str: - """特化泛型类,返回特化类名 - - 1. 查找泛型模板 - 2. 生成特化名 - 3. 检查缓存 - 4. 拷贝 ClassDef 节点(替换类型注解中的 T) - 5. 设置 type_map 上下文(用于方法体中的 T 替换) - 6. 调用 translate_class_def 翻译特化类 - 7. 返回特化名 - """ - if trans is None or class_name is None or type_args is None: - return None - # 泛型循环套用防护:递归深度 +1,超过上限立即报错终止(防 F-bounded - # 等循环特化把编译变死循环)。所有返回路径都必须 -1(见各 return 前)。 - self.GenericSpecDepth += 1 - # 特化触发文件 sha1:进入函数时 trans.ModuleSha1 是触发方文件, - # 翻译特化类时会被切换为模板 sha1(见下方),作废重译时按此重置 - # 特化类 MethodsEmitted(见 _record_spec_trigger / reset_module_methods_emitted) - spec_trigger_sha1: str = trans.ModuleSha1 - if self.GenericSpecDepth > GENERIC_SPEC_MAX_DEPTH: - err_spec: str = trans.Pool.alloc(256) - if err_spec is not None: - viperlib.snprintf(err_spec, 256, - "泛型特化递归过深(疑似泛型循环套用),类: %s 深度=%d", - class_name, self.GenericSpecDepth) - HandlesType.fatal_error(None, err_spec, "InternalCompilerError") - HandlesType.fatal_error(None, "泛型特化递归过深(疑似泛型循环套用)", "InternalCompilerError") - # 防御:泛型上下文内收集的 type_args 若残留未替换的类型参数名(如 "T"), - # 统一替换为具体类型名,避免 ndarray[T] 二次递归特化崩溃。 - # 调用方传入的 type_args 均为临时新建列表,就地替换无共享副作用。 - ta_cnt_g: t.CSizeT = len(type_args) - ta_i_g: t.CSizeT - for ta_i_g in range(ta_cnt_g): - ta_raw_g: str = type_args.get(ta_i_g) - if ta_raw_g is not None: - ta_rsv_g: str = HandlesType.resolve_generic_type_name(ta_raw_g) - if ta_rsv_g is not None and string.strcmp(ta_raw_g, ta_rsv_g) != 0: - type_args.set(ta_i_g, ta_rsv_g) - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - - # 1. 查找泛型模板 - template_cd: ast.ClassDef | t.CPtr = self._find_generic_template(class_name) - if template_cd is None: - self.GenericSpecDepth -= 1 - return None - - # 2. 生成特化名 - spec_name: str = self._mangle_generic_class_name(pool, class_name, type_args) - if spec_name is None: - self.GenericSpecDepth -= 1 - return None - - # 治本修复:Phase B 补译泛型特化类方法体(统一入口,在 cache/existing 检查之前) - # Phase 1a(declare_only==1)特化时只注册结构体不译方法体(MethodsEmitted==0), - # Phase B(declare_only==0)重复进入时若方法体未译,补译方法体生成 define, - # 避免 GSList[Line].append 等符号只有 declare 无 define → 链接失败。 - # 首次 Phase B 特化(Phase 1a 未特化)find_struct 返回 None,不补译,走下方正常全量翻译。 - if trans._declare_only == 0: - pre_existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name) - if pre_existing is not None and pre_existing.MethodsEmitted == 0: - # 防重入:先标记 MethodsEmitted=1,避免补译过程中方法体/返回类型注解 - # 再次触发 _specialize_generic_class(如 __iter__ 返回 list[T]|t.CPtr) - # 导致无限递归补译 → OOM。补译完成后已设置,无需恢复。 - # 注意:此处提前置位后调用 _translate_oop_methods 必须传 reemit=1 - # (补译模式),否则其 MethodsEmitted==1 防重复检查会拦截补译, - # 方法体永不发射 → 特化方法只有 call 无 define → 链接 undefined symbol。 - pre_existing.MethodsEmitted = 1 - # 从 stdlib 深拷贝表取 type_params(模板节点 pool list 跨 Phase 可能失效) - tp_names_pre: list[str] | t.CPtr = self._find_generic_template_tp_params( - pool, class_name) - if tp_names_pre is None: - tp_names_pre = template_cd.type_params - spec_cd_pre: ast.ClassDef | t.CPtr = self._clone_classdef_for_spec( - pool, template_cd, spec_name, tp_names_pre, type_args) - if spec_cd_pre is not None: - trans.GenericTypeParamNames = tp_names_pre - trans.GenericTypeArgs = type_args - HandlesType.set_generic_context(tp_names_pre, type_args) - saved_ms_pre: str = trans.ModuleSha1 - saved_imp_pre: str = trans._imported_modules - template_sha1_pre: str = self._find_generic_template_sha1(class_name) - if template_sha1_pre is not None: - trans.ModuleSha1 = template_sha1_pre - self._merge_template_imports(trans, template_sha1_pre) - # 错误定位上下文:补译的是模板方法体(spec_cd_pre 克隆自模板, - # node.lineno 是模板文件行号)。切换 CurrentFile 到模板文件并压入 - # trace 帧,使 fatal_error 正确显示模板文件位置(翻译完恢复)。 - saved_cur_pre: str = HandlesType.get_current_file() - tpl_file_pre: str = self._find_generic_template_file(class_name) - if tpl_file_pre is not None: - HandlesType.set_current_file(tpl_file_pre) - HandlesType.push_trace(tpl_file_pre, template_cd.lineno) - HandlesClassDef._translate_oop_methods(trans, spec_cd_pre, pre_existing.Ty, spec_name, 0, 1) - if tpl_file_pre is not None: - HandlesType.pop_trace() - HandlesType.set_current_file(saved_cur_pre) - trans.ModuleSha1 = saved_ms_pre - trans._imported_modules = saved_imp_pre - trans.GenericTypeParamNames = None - trans.GenericTypeArgs = None - HandlesType.clear_generic_context() - - # 3. 检查缓存(spec_key 包含所有类型实参,避免多参数泛型缓存冲突) - # 分配新缓冲区避免原地 strcat 溢出 - sk_n: t.CSizeT = len(type_args) - sk_total: t.CSizeT = string.strlen(class_name) + 2 # "<" 和 ">" - sk_i: t.CSizeT - for sk_i in range(sk_n): - if sk_i > 0: - sk_total += 1 # "," - sk_ta: str = type_args.get(sk_i) - if sk_ta is not None: - sk_total += string.strlen(sk_ta) - sk_total += 1 # NUL - spec_key: str = pool.alloc(sk_total) - if spec_key is None: - self.GenericSpecDepth -= 1 - return None - spec_key[0] = '\0' - string.strcat(spec_key, class_name) - string.strcat(spec_key, "<") - for sk_i in range(sk_n): - if sk_i > 0: - string.strcat(spec_key, ",") - sk_ta: str = type_args.get(sk_i) - if sk_ta is not None: - string.strcat(spec_key, sk_ta) - string.strcat(spec_key, ">") - cached: str = self._find_cached_spec(spec_key) - if cached is not None: - self._record_spec_trigger(pool, spec_name, spec_trigger_sha1) - self.GenericSpecDepth -= 1 - return cached - - # 4. 检查是否已注册(Phase B 重复特化) - existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name) - if existing is not None: - self._cache_spec(pool, spec_key, spec_name) - self._record_spec_trigger(pool, spec_name, spec_trigger_sha1) - self.GenericSpecDepth -= 1 - return spec_name - - # 预注册缓存(防止递归) - self._cache_spec(pool, spec_key, spec_name) - - # 5. 拷贝 ClassDef 节点 - # 从 stdlib 深拷贝表取 type_params(模板节点 pool list 跨 Phase 可能失效) - tp_names: list[str] | t.CPtr = self._find_generic_template_tp_params( - pool, class_name) - if tp_names is None: - tp_names = template_cd.type_params - spec_cd: ast.ClassDef | t.CPtr = self._clone_classdef_for_spec( - pool, template_cd, spec_name, tp_names, type_args) - if spec_cd is None: - self.GenericSpecDepth -= 1 - return None - - # 6. 设置 type_map 上下文(用于方法体中的 T 替换) - trans.GenericTypeParamNames = tp_names - trans.GenericTypeArgs = type_args - HandlesType.set_generic_context(tp_names, type_args) - - # 7. 翻译特化类 - # 切换 trans.ModuleSha1 为泛型模板定义模块的 SHA1, - # 使结构体类型名和方法定义名都用定义模块的 SHA1 前缀, - # 与调用端 get_struct_sha1(class_name) 查到的 SHA1 一致。 - # 同时并入模板模块的 imports(见 _merge_template_imports 注释), - # 避免模板方法体内的跨模块调用被误报"模块未导入"。 - saved_module_sha1: str = trans.ModuleSha1 - saved_imported: str = trans._imported_modules - template_sha1: str = self._find_generic_template_sha1(class_name) - if template_sha1 is not None: - trans.ModuleSha1 = template_sha1 - self._merge_template_imports(trans, template_sha1) - # 错误定位上下文:spec_cd 克隆自模板,方法体的 node.lineno 是模板文件 - # 行号,而 CurrentFile 仍是调用方文件 → 错误显示错位。切换 CurrentFile - # 到模板文件并压入 trace 帧(翻译完恢复),使 fatal_error 正确溯源。 - saved_cur_full: str = HandlesType.get_current_file() - tpl_file_full: str = self._find_generic_template_file(class_name) - if tpl_file_full is not None: - HandlesType.set_current_file(tpl_file_full) - HandlesType.push_trace(tpl_file_full, template_cd.lineno) - HandlesClassDef.translate_class_def(trans, spec_cd) - if tpl_file_full is not None: - HandlesType.pop_trace() - HandlesType.set_current_file(saved_cur_full) - # 恢复原始 ModuleSha1 与 imports - trans.ModuleSha1 = saved_module_sha1 - trans._imported_modules = saved_imported - - # 8. 清除 type_map 上下文 - trans.GenericTypeParamNames = None - trans.GenericTypeArgs = None - HandlesType.clear_generic_context() - - # 特化结果字段名完整性检查(fail-fast:字段名缺失 = 字段表损坏, - # 静默继续会让后续 GEP 按错索引访问) - if string.strcmp(class_name, "GSListNode") == 0: - result_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name) - if result_entry is not None: - ri: int - for ri in range(result_entry.FieldCount): - rfe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( - result_entry, ri) - if rfe is not None: - rfn: str = HandlesStruct.get_field_name_ptr(rfe) - if rfn is None: - VLogger.error("SPEC 字段名缺失(字段表损坏)", "SPEC") - HandlesType.fatal_error(None, "SPEC 字段名缺失(字段表损坏)", "TypeError") - - self._record_spec_trigger(pool, spec_name, spec_trigger_sha1) - self.GenericSpecDepth -= 1 +import lib.core.Gen.GenTypes as GenTypes +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HT +import lib.core.StubMerger as StubMerger +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.ClassGenBase as ClassGenBase +import lib.core.StubMergerStore as StubMergerStore + + +# 泛型特化递归深度上限(泛型循环套用防护) +# 正常嵌套特化深度 ≤ 3(如 list[list[str]]);64 远超合理值,命中即循环。 +# (原 HandlesClassDef/ClassGenMixin 顶层常量,阶段 D 拆分时遗漏,补回) +GENERIC_SPEC_MAX_DEPTH: t.CDefine = 64 +# 泛型模板表容量上限(与 GenericClassNames 等 pool 表可容纳的模板数对齐; +# 原 ClassGenMixin 顶层常量,阶段 D 拆分时遗漏,补回) +GENERIC_TEMPLATE_MAX: t.CDefine = 512 + +# ============================================================ +# ClassGenGeneric - ClassGenMixin 拆分(阶段 D):泛型模板注册/特化/克隆 +# +# 继承 ClassGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesClassDef 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class ClassGenGeneric(ClassGenBase.ClassGenBase): + """泛型模板注册/特化/克隆""" + + # ============================================================ + # 簇 C:泛型模板注册/特化(P5-2 第三阶段迁移,函数体来自 + # HandlesClassDef.vp,逻辑零改动) + # + # 说明: + # - _generic_class_* 全局表已迁入 self.GenericClassNames/ + # GenericClassNodes/GenericClassSha1s(P5-2 收尾) + # - _spec_* 全局缓存迁移为 self.SpecKeys/SpecNames/SpecCount + # ============================================================ + + def _is_generic_class(self, tp: list[str] | t.CPtr) -> int: + """检查 ClassDef 是否有类型参数(泛型类),返回 1=是 / 0=否 + + 接收 type_params 而非 cd,避免 cd.type_params 属性访问 + 因跨模块类型推断失败返回 None。 + """ + if tp is None: + return 0 + return 1 + def _register_generic_template(self, pool: memhub.MemBuddy | t.CPtr, + cd: ast.ClassDef | t.CPtr, + module_sha1: str): + """注册泛型类模板(类名 + ClassDef 节点 + 来源模块 SHA1)""" + if self.GenericClassNames is None: + self.GenericClassNames = list[str](pool, 8) + self.GenericClassNodes = list[ast.ClassDef | t.CPtr](pool, 8) + self.GenericClassSha1s = list[str](pool, 8) + self.GenericClassFiles = list[str](pool, 8) + if self.GenericClassTpParams is None: + self.GenericClassTpParams = CompilerFactory.get_perm_pool().alloc(GENERIC_TEMPLATE_MAX * 8) + if self.GenericClassTpParams is None: + return + string.memset(self.GenericClassTpParams, 0, GENERIC_TEMPLATE_MAX * 8) + # 用局部变量接收 list,触发类型推断(避免字段 __len__ 失败) + names_local: list[str] | t.CPtr = self.GenericClassNames + cn: t.CSizeT = len(names_local) + i: t.CSizeT + for i in range(cn): + nm: str = names_local.get(i) + if nm is not None and string.strcmp(nm, cd.name) == 0: + return + # type_params stdlib 深拷贝:模板节点的 type_params 是 pool 分配的 + tp_names_buf: str = self._copy_type_params_stdlib(cd.type_params) + self.GenericClassNames.append(cd.name) + self.GenericClassNodes.append(cd) + self.GenericClassSha1s.append(module_sha1) + # 同时保存模板来源文件路径(错误定位用,见字段注释) + self.GenericClassFiles.append(self.Gen.TypeGenResolve.get_current_file()) + if tp_names_buf is not None and cn < GENERIC_TEMPLATE_MAX: + self.GenericClassTpParams[cn] = t.CSizeT(tp_names_buf) + def _copy_type_params_stdlib(self, tp: list[str] | t.CPtr) -> str: + """将模板 type_params 深拷贝为空格分隔、NUL 结尾的 stdlib 缓冲区 + + TPC Python 参考实现:type_params = [tp.name for tp in Node.type_params] + (Python 字符串不可变天然跨阶段存活);Viper 的 type_params 是 pool + 分配 list,跨 Phase 内容可能被复用污染,必须注册时拷贝到 stdlib。 + 返回缓冲区指针;tp 为 None(非泛型)或分配失败返回 None。 + """ + if tp is None: + return None + tp_n: t.CSizeT = len(tp) + if tp_n == 0: + return None + # 计算总长:各名字长度 + (n-1) 个空格 + NUL + total: t.CSizeT = 1 + ti: t.CSizeT + for ti in range(tp_n): + tp_name: str = tp.get(ti) + if tp_name is not None: + total += string.strlen(tp_name) + 1 + buf: str = CompilerFactory.get_perm_pool().alloc(total) + if buf is None: + return None + buf[0] = '\0' + for ti in range(tp_n): + tp_name = tp.get(ti) + if tp_name is None: + continue + if ti > 0 and buf[0] != '\0': + string.strcat(buf, " ") + string.strcat(buf, tp_name) + return buf + def _find_generic_template_tp_params(self, pool: memhub.MemBuddy | t.CPtr, + class_name: str) -> list[str] | t.CPtr: + """查找泛型类模板的类型参数名列表,未找到返回 None + + 从注册时深拷贝的 stdlib 缓冲区重建当前 pool 的 list[str] + (特化期间 pool 有效,方法与体翻译共用)。与 GenericClassNames 同序。 + """ + if self.GenericClassNames is None or class_name is None \ + or self.GenericClassTpParams is None: + return None + names_local: list[str] | t.CPtr = self.GenericClassNames + cn: t.CSizeT = len(names_local) + i: t.CSizeT + for i in range(cn): + nm: str = names_local.get(i) + if nm is not None and string.strcmp(nm, class_name) == 0: + if i >= GENERIC_TEMPLATE_MAX: + return None + buf_addr: t.CSizeT = self.GenericClassTpParams[i] + if buf_addr == 0: + return None + buf_tp: str = (str | t.CPtr)(t.CVoid(buf_addr, t.CPtr)) + # 空格分隔 → list[str] + # 注意:list[str](pool, 8) 第二个参数是 elem_size(指针 8 字节), + # 不是容量!传 4 会导致 get(i) 偏移算错、append 相互覆盖 + # (Pair[T1,T2] 的 seg1 写 data+4 覆盖 seg0 高 4 字节 → strcmp + # 收到 0x15B78D5015B78CB0 混合垃圾崩溃,GenericTest 回归根因) + tp_list: list[str] | t.CPtr = list[str](pool, 8) + if tp_list is None: + return None + seg_start: t.CSizeT = 0 + pos: t.CSizeT = 0 + blen: t.CSizeT = string.strlen(buf_tp) + while pos <= blen: + if buf_tp[pos] == ' ' or buf_tp[pos] == '\0': + seg_len: t.CSizeT = pos - seg_start + if seg_len > 0: + seg: str = pool.alloc(seg_len + 1) + if seg is not None: + string.strncpy(seg, buf_tp + seg_start, seg_len) + seg[seg_len] = '\0' + tp_list.append(seg) + seg_start = pos + 1 + pos += 1 + return tp_list + return None + def _find_generic_template(self, class_name: str) -> ast.ClassDef | t.CPtr: + """查找泛型类模板,返回 ClassDef 节点或 None""" + if self.GenericClassNames is None or class_name is None: + return None + # 用局部变量接收 list,触发类型推断(避免字段 __len__ 失败) + names_local: list[str] | t.CPtr = self.GenericClassNames + nodes_local: list[ast.ClassDef | t.CPtr] | t.CPtr = self.GenericClassNodes + cn: t.CSizeT = len(names_local) + i: t.CSizeT + for i in range(cn): + nm: str = names_local.get(i) + if nm is not None and string.strcmp(nm, class_name) == 0: + node: ast.ClassDef | t.CPtr = nodes_local.get(i) + return node + return None + def _find_generic_template_sha1(self, class_name: str) -> str: + """查找泛型类模板的来源模块 SHA1,未找到返回 None""" + if self.GenericClassNames is None or class_name is None: + return None + # 用局部变量接收 list,触发类型推断 + names_local: list[str] | t.CPtr = self.GenericClassNames + sha1s_local: list[str] | t.CPtr = self.GenericClassSha1s + cn: t.CSizeT = len(names_local) + i: t.CSizeT + for i in range(cn): + nm: str = names_local.get(i) + if nm is not None and string.strcmp(nm, class_name) == 0: + sha1_val: str = sha1s_local.get(i) + return sha1_val + return None + def _find_generic_template_file(self, class_name: str) -> str: + """查找泛型类模板的来源文件路径,未找到返回 None + + 与 _find_generic_template_sha1 同表同序;供特化翻译模板方法体时 + 临时切换 CurrentFile(错误定位:模板 node.lineno 需配模板文件路径)。 + """ + if self.GenericClassNames is None or class_name is None: + return None + names_local: list[str] | t.CPtr = self.GenericClassNames + files_local: list[str] | t.CPtr = self.GenericClassFiles + cn: t.CSizeT = len(names_local) + i: t.CSizeT + for i in range(cn): + nm: str = names_local.get(i) + if nm is not None and string.strcmp(nm, class_name) == 0: + f_val: str = files_local.get(i) + return f_val + return None + def _mangle_generic_class_name(self, pool: memhub.MemBuddy | t.CPtr, + class_name: str, + type_args: list[str] | t.CPtr) -> str: + """生成特化类名: list + [int] -> list[int] + + 分配新缓冲区拼接,避免原地 strcat 导致缓冲区溢出 + """ + if class_name is None or type_args is None or pool is None: + return class_name + n: t.CSizeT = len(type_args) + if n == 0: + return class_name + # 计算总长度: class_name + "[" + arg0 + "," + arg1 + ... + "]" + NUL + total_len: t.CSizeT = string.strlen(class_name) + 2 # "[" 和 "]" + i: t.CSizeT + for i in range(n): + if i > 0: + total_len += 1 # "," + ta: str = type_args.get(i) + if ta is not None: + total_len += string.strlen(ta) + total_len += 1 # NUL + # 分配新缓冲区 + mangled: str = pool.alloc(total_len) + if mangled is None: + return class_name + mangled[0] = '\0' + string.strcat(mangled, class_name) + string.strcat(mangled, "[") + for i in range(n): + if i > 0: + string.strcat(mangled, ",") + ta: str = type_args.get(i) + if ta is not None: + string.strcat(mangled, ta) + string.strcat(mangled, "]") + return mangled + def _clone_annotation(self, pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr, + tp_names: list[str] | t.CPtr, + type_args: list[str] | t.CPtr) -> ast.AST | t.CPtr: + """拷贝类型注解表达式,替换类型参数 T 为具体类型名 + + tp_names: 类型参数名列表 ['T'] + type_args: 类型实参名列表 ['int'] + """ + if node is None: + return None + k: int = node.kind() + + # Name: 可能是类型参数 T + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is not None: + n: t.CSizeT = len(tp_names) if tp_names is not None else 0 + i: t.CSizeT + for i in range(n): + tpn: str = tp_names.get(i) + if tpn is not None and string.strcmp(nm.id, tpn) == 0: + ta: str = type_args.get(i) + # 类型实参可能是复合类型(如 "AST|t.CPtr"),用 _parse_type_string 解析 + parsed_node: ast.AST | t.CPtr = self.Gen.TypeGenResolve._parse_type_string(pool, ta, nm.ctx) + return parsed_node + return ast.Name(pool, nm.id, nm.ctx) + return None + + # Attribute: t.CPtr 等 + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + new_value: ast.AST | t.CPtr = self._clone_annotation(pool, at.value, tp_names, type_args) + return ast.Attribute(pool, new_value, at.attr, at.ctx) + + # BinOp: T | t.CPtr 等 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + new_left: ast.AST | t.CPtr = self._clone_annotation(pool, bop.left, tp_names, type_args) + new_right: ast.AST | t.CPtr = self._clone_annotation(pool, bop.right, tp_names, type_args) + return ast.BinOp(pool, new_left, bop.op, new_right) + + # Subscript: list[int] 等 + if k == ast.ASTKind.Subscript: + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + new_value2: ast.AST | t.CPtr = self._clone_annotation(pool, sub.value, tp_names, type_args) + new_slice: ast.AST | t.CPtr = self._clone_annotation(pool, sub.slice, tp_names, type_args) + return ast.Subscript(pool, new_value2, new_slice, sub.ctx) + + # Tuple: (T, int) 等 + if k == ast.ASTKind.Tuple: + tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(node) + new_elts: list[ast.AST | t.CPtr] | t.CPtr = list[ast.AST | t.CPtr](pool, 8) + if tup.elts is not None: + tup_elts: list[ast.AST | t.CPtr] | t.CPtr = tup.elts + en: t.CSizeT = len(tup_elts) + ei: t.CSizeT + for ei in range(en): + el: ast.AST | t.CPtr = tup_elts.get(ei) + new_el: ast.AST | t.CPtr = self._clone_annotation(pool, el, tp_names, type_args) + if new_el is not None: + new_elts.append(new_el) + return ast.Tuple(pool, new_elts, tup.ctx) + + # Constant: 默认值等 + if k == ast.ASTKind.Constant: + cnst: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + return ast.Constant(pool, cnst.const_kind, cnst.int_val, cnst.float_val, + cnst.str_val, cnst.lineno, cnst.col_offset) + + # 其他: 直接引用(不拷贝) + return node + def _clone_arguments(self, pool: memhub.MemBuddy | t.CPtr, + args: ast.AST | t.CPtr, + tp_names: list[str] | t.CPtr, + type_args: list[str] | t.CPtr) -> ast.AST | t.CPtr: + """拷贝 Arguments 节点,替换 arg annotation 中的 T""" + if args is None: + return None + if args.kind() != ast.ASTKind.Arguments: + return args + old_args: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args) + # 拷贝 args 列表,替换每个 Arg 的 annotation + new_arg_list: list[ast.AST | t.CPtr] | t.CPtr = list[ast.AST | t.CPtr](pool, 8) + if old_args.args is not None: + old_arg_list: list[ast.AST | t.CPtr] | t.CPtr = old_args.args + an: t.CSizeT = len(old_arg_list) + ai: t.CSizeT + for ai in range(an): + arg_node: ast.AST | t.CPtr = old_arg_list.get(ai) + if arg_node is None: + continue + if arg_node.kind() == ast.ASTKind.Arg: + ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(arg_node) + new_anno: ast.AST | t.CPtr = self._clone_annotation(pool, ag.annotation, tp_names, type_args) + new_arg: ast.Arg | t.CPtr = ast.Arg(pool, ag.arg, new_anno) + new_arg_list.append(new_arg) + else: + new_arg_list.append(arg_node) + return ast.Arguments(pool, new_arg_list, old_args.vararg, old_args.kwarg, + old_args.defaults, old_args.kw_defaults) + def _clone_classdef_for_spec(self, pool: memhub.MemBuddy | t.CPtr, + cd: ast.ClassDef | t.CPtr, + spec_name: str, + tp_names: list[str] | t.CPtr, + type_args: list[str] | t.CPtr) -> ast.ClassDef | t.CPtr: + """拷贝 ClassDef 节点用于泛型特化 + + - 替换类名为 spec_name + - 清除 type_params(特化后不是泛型类) + - 拷贝 children 中的 AnnAssign 和 FunctionDef,替换类型注解中的 T + - 方法体直接引用原始节点(通过 type_map 上下文处理 T) + """ + # 创建新 ClassDef(type_params=None 表示非泛型) + new_cd: ast.ClassDef | t.CPtr = ast.ClassDef(pool, spec_name, cd.bases, cd.keywords, + cd.decorator_list, None) + # 拷贝 children + if cd.children is not None: + cd_children: list[ast.AST | t.CPtr] | t.CPtr = cd.children + cn: t.CSizeT = len(cd_children) + ci: t.CSizeT + for ci in range(cn): + child: ast.AST | t.CPtr = cd_children.get(ci) + if child is None: + continue + ck: int = child.kind() + + if ck == ast.ASTKind.AnnAssign: + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(child) + new_target: ast.AST | t.CPtr = aa.target + new_anno2: ast.AST | t.CPtr = self._clone_annotation(pool, aa.annotation, tp_names, type_args) + new_value3: ast.AST | t.CPtr = aa.value + new_aa: ast.AnnAssign | t.CPtr = ast.AnnAssign(pool, new_target, new_anno2, new_value3, aa.simple) + new_cd.append(new_aa) + + elif ck == ast.ASTKind.FunctionDef: + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child) + new_args2: ast.AST | t.CPtr = self._clone_arguments(pool, fd.args, tp_names, type_args) + new_returns2: ast.AST | t.CPtr = self._clone_annotation(pool, fd.returns, tp_names, type_args) + new_fd: ast.FunctionDef | t.CPtr = ast.FunctionDef(pool, fd.name, new_args2, + fd.decorator_list, new_returns2, 0) + # 方法体直接引用原始节点 + if fd.children is not None: + fd_children: list[ast.AST | t.CPtr] | t.CPtr = fd.children + bcn: t.CSizeT = len(fd_children) + bci: t.CSizeT + for bci in range(bcn): + body_stmt: ast.AST | t.CPtr = fd_children.get(bci) + if body_stmt is not None: + new_fd.append(body_stmt) + new_cd.append(new_fd) + + else: + new_cd.append(child) + + return new_cd + def _find_cached_spec(self, spec_key: str) -> str: + """查找已缓存的特化名,未找到返回 None""" + if self.SpecKeys is None or spec_key is None: + return None + i: int + for i in range(self.SpecCount): + key_addr: t.CSizeT = self.SpecKeys[i] + if key_addr != 0: + k: str = (str | t.CPtr)(t.CVoid(key_addr, t.CPtr)) + if k is not None and string.strcmp(k, spec_key) == 0: + name_addr: t.CSizeT = self.SpecNames[i] + if name_addr != 0: + return (str | t.CPtr)(t.CVoid(name_addr, t.CPtr)) + return None + def _cache_spec(self, pool: memhub.MemBuddy | t.CPtr, spec_key: str, spec_name: str): + """缓存特化结果(stdlib 深拷贝存储,跨文件安全)""" + if spec_key is None or spec_name is None: + return + if self.SpecKeys is None: + self.SpecKeys = CompilerFactory.get_perm_pool().alloc(SPEC_CACHE_MAX * 8) + self.SpecNames = CompilerFactory.get_perm_pool().alloc(SPEC_CACHE_MAX * 8) + if self.SpecKeys is None or self.SpecNames is None: + return + string.memset(self.SpecKeys, 0, SPEC_CACHE_MAX * 8) + string.memset(self.SpecNames, 0, SPEC_CACHE_MAX * 8) + self.SpecCount = 0 + if self.SpecCount >= SPEC_CACHE_MAX: + return + # 深拷贝字符串到 stdlib 区 + key_len: t.CSizeT = string.strlen(spec_key) + name_len: t.CSizeT = string.strlen(spec_name) + key_copy: str = CompilerFactory.get_perm_pool().alloc(key_len + 1) + name_copy: str = CompilerFactory.get_perm_pool().alloc(name_len + 1) + if key_copy is None or name_copy is None: + return + string.strcpy(key_copy, spec_key) + string.strcpy(name_copy, spec_name) + self.SpecKeys[self.SpecCount] = t.CSizeT(key_copy) + self.SpecNames[self.SpecCount] = t.CSizeT(name_copy) + self.SpecCount += 1 + def _merge_template_imports(self, trans: HT.Translator | t.CPtr, + template_sha1: str) -> None: + """将模板模块的 imports 并入 trans._imported_modules(空格分隔)""" + if trans is None or template_sha1 is None: + return + tdeps: str = StubMergerStore.LookupIncludesDeps(template_sha1) + if tdeps is None or tdeps[0] == '\0': + return + cur: str = trans._imported_modules + if cur is None or cur[0] == '\0': + trans._imported_modules = tdeps + return + cur_len: t.CSizeT = string.strlen(cur) + td_len: t.CSizeT = string.strlen(tdeps) + merged: str = trans.Pool.alloc(cur_len + td_len + 2) + if merged is None: + return + string.strcpy(merged, cur) + merged[cur_len] = ' ' + string.strcpy(merged + cur_len + 1, tdeps) + trans._imported_modules = merged + def _record_spec_trigger(self, pool: memhub.MemBuddy | t.CPtr, + spec_name: str, trigger_sha1: str) -> int: + """记录泛型特化类的触发文件 sha1(StructEntry.SpecTriggerSha1) + + 特化类 ModuleSha1=模板 sha1(方法名带模板前缀),Phase A _deps_pending + 作废重译时 reset_module_methods_emitted 按当前文件 sha1 匹配不到 → + 特化方法体 MethodsEmitted 残留 1 → 下遍不补译 → 链接 undefined symbol。 + 记录触发文件 sha1 后按此精确重置(见 StructGenMixin.reset_module_methods_emitted)。 + """ + if spec_name is None or trigger_sha1 is None: + return 0 + entry_rt: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(spec_name) + if entry_rt is None: + return 0 + if string.strcmp(entry_rt.Name, spec_name) != 0: + return 0 + ts_len_r: t.CSizeT = string.strlen(trigger_sha1) + ts_buf_r: str = CompilerFactory.get_perm_pool().alloc(ts_len_r + 1) + if ts_buf_r is None: + return 0 + string.strcpy(ts_buf_r, trigger_sha1) + entry_rt.SpecTriggerSha1 = ts_buf_r + return 1 + def _specialize_generic_class(self, trans: HT.Translator | t.CPtr, + class_name: str, + type_args: list[str] | t.CPtr) -> str: + """特化泛型类,返回特化类名 + + 1. 查找泛型模板 + 2. 生成特化名 + 3. 检查缓存 + 4. 拷贝 ClassDef 节点(替换类型注解中的 T) + 5. 设置 type_map 上下文(用于方法体中的 T 替换) + 6. 调用 translate_class_def 翻译特化类 + 7. 返回特化名 + """ + if trans is None or class_name is None or type_args is None: + return None + # 泛型循环套用防护:递归深度 +1,超过上限立即报错终止(防 F-bounded + # 等循环特化把编译变死循环)。所有返回路径都必须 -1(见各 return 前)。 + self.GenericSpecDepth += 1 + # 特化触发文件 sha1:进入函数时 trans.ModuleSha1 是触发方文件, + # 翻译特化类时会被切换为模板 sha1(见下方),作废重译时按此重置 + # 特化类 MethodsEmitted(见 _record_spec_trigger / reset_module_methods_emitted) + spec_trigger_sha1: str = trans.ModuleSha1 + if self.GenericSpecDepth > GENERIC_SPEC_MAX_DEPTH: + err_spec: str = trans.Pool.alloc(256) + if err_spec is not None: + viperlib.snprintf(err_spec, 256, + "泛型特化递归过深(疑似泛型循环套用),类: %s 深度=%d", + class_name, self.GenericSpecDepth) + self.Gen.TypeGenErr.fatal_error(None, err_spec, "InternalCompilerError") + self.Gen.TypeGenErr.fatal_error(None, "泛型特化递归过深(疑似泛型循环套用)", "InternalCompilerError") + # 防御:泛型上下文内收集的 type_args 若残留未替换的类型参数名(如 "T"), + # 统一替换为具体类型名,避免 ndarray[T] 二次递归特化崩溃。 + # 调用方传入的 type_args 均为临时新建列表,就地替换无共享副作用。 + ta_cnt_g: t.CSizeT = len(type_args) + ta_i_g: t.CSizeT + for ta_i_g in range(ta_cnt_g): + ta_raw_g: str = type_args.get(ta_i_g) + if ta_raw_g is not None: + ta_rsv_g: str = self.Gen.TypeGenBase.resolve_generic_type_name(ta_raw_g) + if ta_rsv_g is not None and string.strcmp(ta_raw_g, ta_rsv_g) != 0: + type_args.set(ta_i_g, ta_rsv_g) + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + + # 1. 查找泛型模板 + template_cd: ast.ClassDef | t.CPtr = self._find_generic_template(class_name) + if template_cd is None: + self.GenericSpecDepth -= 1 + return None + + # 2. 生成特化名 + spec_name: str = self._mangle_generic_class_name(pool, class_name, type_args) + if spec_name is None: + self.GenericSpecDepth -= 1 + return None + + # 治本修复:Phase B 补译泛型特化类方法体(统一入口,在 cache/existing 检查之前) + # Phase 1a(declare_only==1)特化时只注册结构体不译方法体(MethodsEmitted==0), + # Phase B(declare_only==0)重复进入时若方法体未译,补译方法体生成 define, + # 避免 GSList[Line].append 等符号只有 declare 无 define → 链接失败。 + # 首次 Phase B 特化(Phase 1a 未特化)find_struct 返回 None,不补译,走下方正常全量翻译。 + if trans._declare_only == 0: + pre_existing: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(spec_name) + if pre_existing is not None and pre_existing.MethodsEmitted == 0: + # 防重入:先标记 MethodsEmitted=1,避免补译过程中方法体/返回类型注解 + # 再次触发 _specialize_generic_class(如 __iter__ 返回 list[T]|t.CPtr) + # 导致无限递归补译 → OOM。补译完成后已设置,无需恢复。 + # 注意:此处提前置位后调用 _translate_oop_methods 必须传 reemit=1 + # (补译模式),否则其 MethodsEmitted==1 防重复检查会拦截补译, + # 方法体永不发射 → 特化方法只有 call 无 define → 链接 undefined symbol。 + pre_existing.MethodsEmitted = 1 + # 从 stdlib 深拷贝表取 type_params(模板节点 pool list 跨 Phase 可能失效) + tp_names_pre: list[str] | t.CPtr = self._find_generic_template_tp_params( + pool, class_name) + if tp_names_pre is None: + tp_names_pre = template_cd.type_params + spec_cd_pre: ast.ClassDef | t.CPtr = self._clone_classdef_for_spec( + pool, template_cd, spec_name, tp_names_pre, type_args) + if spec_cd_pre is not None: + trans.GenericTypeParamNames = tp_names_pre + trans.GenericTypeArgs = type_args + self.Gen.TypeGenBase.set_generic_context(tp_names_pre, type_args) + saved_ms_pre: str = trans.ModuleSha1 + saved_imp_pre: str = trans._imported_modules + template_sha1_pre: str = self._find_generic_template_sha1(class_name) + if template_sha1_pre is not None: + trans.ModuleSha1 = template_sha1_pre + self._merge_template_imports(trans, template_sha1_pre) + # 错误定位上下文:补译的是模板方法体(spec_cd_pre 克隆自模板, + # node.lineno 是模板文件行号)。切换 CurrentFile 到模板文件并压入 + # trace 帧,使 fatal_error 正确显示模板文件位置(翻译完恢复)。 + saved_cur_pre: str = self.Gen.TypeGenResolve.get_current_file() + tpl_file_pre: str = self._find_generic_template_file(class_name) + if tpl_file_pre is not None: + self.Gen.TypeGenResolve.set_current_file(tpl_file_pre) + self.Gen.TypeGenBase.push_trace(tpl_file_pre, template_cd.lineno) + self.Gen.ClassGenVTable._translate_oop_methods(trans, spec_cd_pre, pre_existing.Ty, spec_name, 0, 1) + if tpl_file_pre is not None: + self.Gen.TypeGenBase.pop_trace() + self.Gen.TypeGenResolve.set_current_file(saved_cur_pre) + trans.ModuleSha1 = saved_ms_pre + trans._imported_modules = saved_imp_pre + trans.GenericTypeParamNames = None + trans.GenericTypeArgs = None + self.Gen.TypeGenBase.clear_generic_context() + + # 3. 检查缓存(spec_key 包含所有类型实参,避免多参数泛型缓存冲突) + # 分配新缓冲区避免原地 strcat 溢出 + sk_n: t.CSizeT = len(type_args) + sk_total: t.CSizeT = string.strlen(class_name) + 2 # "<" 和 ">" + sk_i: t.CSizeT + for sk_i in range(sk_n): + if sk_i > 0: + sk_total += 1 # "," + sk_ta: str = type_args.get(sk_i) + if sk_ta is not None: + sk_total += string.strlen(sk_ta) + sk_total += 1 # NUL + spec_key: str = pool.alloc(sk_total) + if spec_key is None: + self.GenericSpecDepth -= 1 + return None + spec_key[0] = '\0' + string.strcat(spec_key, class_name) + string.strcat(spec_key, "<") + for sk_i in range(sk_n): + if sk_i > 0: + string.strcat(spec_key, ",") + sk_ta: str = type_args.get(sk_i) + if sk_ta is not None: + string.strcat(spec_key, sk_ta) + string.strcat(spec_key, ">") + cached: str = self._find_cached_spec(spec_key) + if cached is not None: + self._record_spec_trigger(pool, spec_name, spec_trigger_sha1) + self.GenericSpecDepth -= 1 + return cached + + # 4. 检查是否已注册(Phase B 重复特化) + existing: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(spec_name) + if existing is not None: + self._cache_spec(pool, spec_key, spec_name) + self._record_spec_trigger(pool, spec_name, spec_trigger_sha1) + self.GenericSpecDepth -= 1 + return spec_name + + # 预注册缓存(防止递归) + self._cache_spec(pool, spec_key, spec_name) + + # 5. 拷贝 ClassDef 节点 + # 从 stdlib 深拷贝表取 type_params(模板节点 pool list 跨 Phase 可能失效) + tp_names: list[str] | t.CPtr = self._find_generic_template_tp_params( + pool, class_name) + if tp_names is None: + tp_names = template_cd.type_params + spec_cd: ast.ClassDef | t.CPtr = self._clone_classdef_for_spec( + pool, template_cd, spec_name, tp_names, type_args) + if spec_cd is None: + self.GenericSpecDepth -= 1 + return None + + # 6. 设置 type_map 上下文(用于方法体中的 T 替换) + trans.GenericTypeParamNames = tp_names + trans.GenericTypeArgs = type_args + self.Gen.TypeGenBase.set_generic_context(tp_names, type_args) + + # 7. 翻译特化类 + # 切换 trans.ModuleSha1 为泛型模板定义模块的 SHA1, + # 使结构体类型名和方法定义名都用定义模块的 SHA1 前缀, + # 与调用端 get_struct_sha1(class_name) 查到的 SHA1 一致。 + # 同时并入模板模块的 imports(见 _merge_template_imports 注释), + # 避免模板方法体内的跨模块调用被误报"模块未导入"。 + saved_module_sha1: str = trans.ModuleSha1 + saved_imported: str = trans._imported_modules + template_sha1: str = self._find_generic_template_sha1(class_name) + if template_sha1 is not None: + trans.ModuleSha1 = template_sha1 + self._merge_template_imports(trans, template_sha1) + # 错误定位上下文:spec_cd 克隆自模板,方法体的 node.lineno 是模板文件 + # 行号,而 CurrentFile 仍是调用方文件 → 错误显示错位。切换 CurrentFile + # 到模板文件并压入 trace 帧(翻译完恢复),使 fatal_error 正确溯源。 + saved_cur_full: str = self.Gen.TypeGenResolve.get_current_file() + tpl_file_full: str = self._find_generic_template_file(class_name) + if tpl_file_full is not None: + self.Gen.TypeGenResolve.set_current_file(tpl_file_full) + self.Gen.TypeGenBase.push_trace(tpl_file_full, template_cd.lineno) + self.Gen.ClassGenDef.translate_class_def(trans, spec_cd) + if tpl_file_full is not None: + self.Gen.TypeGenBase.pop_trace() + self.Gen.TypeGenResolve.set_current_file(saved_cur_full) + # 恢复原始 ModuleSha1 与 imports + trans.ModuleSha1 = saved_module_sha1 + trans._imported_modules = saved_imported + + # 8. 清除 type_map 上下文 + trans.GenericTypeParamNames = None + trans.GenericTypeArgs = None + self.Gen.TypeGenBase.clear_generic_context() + + # 特化结果字段名完整性检查(fail-fast:字段名缺失 = 字段表损坏, + # 静默继续会让后续 GEP 按错索引访问) + if string.strcmp(class_name, "GSListNode") == 0: + result_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(spec_name) + if result_entry is not None: + ri: int + for ri in range(result_entry.FieldCount): + rfe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry( + result_entry, ri) + if rfe is not None: + rfn: str = self.Gen.StructGen.get_field_name_ptr(rfe) + if rfn is None: + VLogger.error("SPEC 字段名缺失(字段表损坏)", "SPEC") + self.Gen.TypeGenErr.fatal_error(None, "SPEC 字段名缺失(字段表损坏)", "TypeError") + + self._record_spec_trigger(pool, spec_name, spec_trigger_sha1) + self.GenericSpecDepth -= 1 return spec_name \ No newline at end of file diff --git a/App/lib/core/Gen/ClassGenMixin.vp b/App/lib/core/Gen/ClassGenMixin.vp index 3f39cee..1b362c1 100644 --- a/App/lib/core/Gen/ClassGenMixin.vp +++ b/App/lib/core/Gen/ClassGenMixin.vp @@ -1,32 +1,25 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import viperlib -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesEnum as HandlesEnum -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.StubMerger as StubMerger -import lib.core.CompilerFactory as CompilerFactory -import lib.core.Gen.ClassGenBase as ClassGenBase - -# ============================================================ -# ClassGenMixin - 类定义/继承/泛型/vtable/enum/union/renum -# -# 500~1500 行/文件架构重构阶段 D:全部方法已拆至 -# ClassGenBase/Enum/Generic/VTable/Def,本文件保留类声明。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class ClassGenMixin(ClassGenBase.ClassGenBase): - """类定义处理 Mixin(阶段 D 拆分后顶层,方法全部在子 Mixin)""" +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HT +import lib.core.StubMerger as StubMerger +import lib.core.CompilerFactory as CompilerFactory +import lib.core.Gen.ClassGenBase as ClassGenBase + +# ============================================================ +# ClassGenMixin - 类定义/继承/泛型/vtable/enum/union/renum +# +# 500~1500 行/文件架构重构阶段 D:全部方法已拆至 +# ClassGenBase/Enum/Generic/VTable/Def,本文件保留类声明。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class ClassGenMixin(ClassGenBase.ClassGenBase): + """类定义处理 Mixin(阶段 D 拆分后顶层,方法全部在子 Mixin)""" diff --git a/App/lib/core/Gen/ClassGenVTable.vp b/App/lib/core/Gen/ClassGenVTable.vp index 62660e5..21f769c 100644 --- a/App/lib/core/Gen/ClassGenVTable.vp +++ b/App/lib/core/Gen/ClassGenVTable.vp @@ -1,1315 +1,1309 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import viperlib -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesEnum as HandlesEnum -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.StubMerger as StubMerger -import lib.core.CompilerFactory as CompilerFactory - - -import lib.core.Gen.ClassGenBase as ClassGenBase -import lib.core.Handles.ExprCallTable as ExprCallTable - - -# 方法元数据 flag:TLS(@t.TLS 装饰器,对齐 ClassGenBase 本地常量;本地副本避免跨模块 CDefine 查找) -META_TLS: t.CDefine = 32 - -# ============================================================ -# ClassGenVTable - ClassGenMixin 拆分(阶段 D):vtable 收集/生成/方法翻译 -# -# 继承 ClassGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesClassDef 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class ClassGenVTable(ClassGenBase.ClassGenBase): - """vtable 收集/生成/方法翻译""" - - # ============================================================ - # _vtable_strcat — 将 src 追加到 dst 末尾 - # ============================================================ - def _vtable_strcat(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 - i: t.CSizeT = 0 - while i < slen and i + 1 < remain: - dst[dlen + i] = src[i] - i += 1 - dst[dlen + i] = '\0' - # ============================================================ - # _vtable_name_needs_quote — 检查 LLVM 标识符是否需要引号 - # ============================================================ - def _vtable_name_needs_quote(self, name: str) -> int: - """检查 LLVM 标识符是否需要引号(以数字开头或含 '.')""" - if name is None: - return 0 - if '0' <= name[0] <= '9': - return 1 - for i in name: - if i == '.': - return 1 - return 0 - # ============================================================ - # _format_func_type_str — 从 Function 对象生成函数类型字符串 - # - # 格式: ret_ty (param1_ty, param2_ty, ...) - # 例如: void ({i32, i32}*, i32) - # ============================================================ - def _format_func_type_str(self, pool: memhub.MemBuddy | t.CPtr, - buf: str, buf_size: t.CSizeT, - func: llvmlite.Function | t.CPtr) -> int: - """从 Function 对象生成函数类型字符串""" - if buf is None or func is None or buf_size == 0: - return 0 - buf[0] = '\0' - # 打印返回类型(使用访问器函数避免跨模块直接字段访问) - ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(func) - ret_buf: str = pool.alloc(128) - if ret_buf is not None and ret_ty is not None: - ret_buf[0] = '\0' - llvmlite.TypePrint(ret_buf, 128, ret_ty, pool) - self._vtable_strcat(buf, buf_size, ret_buf) - self._vtable_strcat(buf, buf_size, " (") - - # 遍历参数(使用访问器函数避免跨模块直接字段访问) - cur: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) - first: int = 1 - param_buf: str = pool.alloc(128) - _pc: int = 0 - while cur is not None: - _pc += 1 - if _pc > 100: - break - if first == 0: - self._vtable_strcat(buf, buf_size, ", ") - if param_buf is not None: - param_buf[0] = '\0' - param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur) - if param_ty is not None: - llvmlite.TypePrint(param_buf, 128, param_ty, pool) - self._vtable_strcat(buf, buf_size, param_buf) - cur = llvmlite.param_get_next(cur) - first = 0 - self._vtable_strcat(buf, buf_size, ")") - return 1 - # ============================================================ - # _collect_vtable_methods — 收集类的虚方法信息 - # - # 1. 继承父类虚方法(父类方法排在子类方法之前,保持槽位顺序一致) - # 2. 收集当前类虚方法(跳过已继承的) - # - # 结果存入 self.VtFullNames/VtMethodNames/VtParentSha1s/VtMethodCount - # (原模块级 _g_vt_*),并设置 entry.VTableMethodCount / - # VTableMethods(stdlib 分配,供虚分派跨模块查询)。 - # - # 返回 1=有虚方法 / 0=无方法或失败 - # ============================================================ - def _collect_vtable_methods(self, trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr, - class_name: str) -> int: - """收集虚方法信息,设置 entry.VTableMethods/VTableMethodCount""" - if trans is None or cd is None or class_name is None: - return 0 - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - # 懒导入(find_func_global 探测方法实际定义类用) - import lib.core.Handles.HandlesExprCall as HandlesExprCall - - children: list[ast.AST | t.CPtr] | t.CPtr = cd.children - if children is None: - return 0 - cn: t.CSizeT = len(children) - - # 1. 收集虚方法信息 - # stdlib 分配:method_names_buf 存到 StructEntry.VTableMethods(跨文件永久存活), - # 必须迁出 mb 池 reset 区间,否则 1b 每文件 reset_to(mark1) 会回收导致悬空。 - full_names_buf: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(8 * VTBL_METHOD_MAX) - method_names_buf: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(8 * VTBL_METHOD_MAX) - # 记录每个方法的父类 SHA1(非 0=继承方法用父模块 SHA1 mangling,0=当前类方法) - method_parent_sha1s: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(8 * VTBL_METHOD_MAX) - if full_names_buf is None or method_names_buf is None or method_parent_sha1s is None: - return 0 - string.memset(full_names_buf, 0, 8 * VTBL_METHOD_MAX) - string.memset(method_names_buf, 0, 8 * VTBL_METHOD_MAX) - string.memset(method_parent_sha1s, 0, 8 * VTBL_METHOD_MAX) - - method_count: int = 0 - - # ============================================================ - # 1.5 继承父类虚方法 - # - # 父类虚方法排在子类虚方法之前,保持 vtable 槽位顺序一致。 - # 如果子类覆盖了方法,full_name 用子类的;否则用父类的。 - # 用 SHA1 感知查找,规避跨模块同名 find_struct 找错 - # ============================================================ - vt_self_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( - class_name, trans.ModuleSha1) - # 多继承:遍历所有父类(声明顺序),vtable 方法合并(短名去重,先声明父类优先) - parent_count: int = HandlesStruct.get_parent_count(class_name) - if parent_count > 0: - for pi in range(parent_count): - pname: str = HandlesStruct.get_parent_name_at(class_name, pi) - if pname is None: - continue - # 查找父类 entry(优先同模块 SHA1 匹配) - vt_parent_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( - pname, trans.ModuleSha1) - if vt_parent_entry is None: - # 跨模块继承: 父类在不同模块定义(SHA1 不同),回退到按类名查找 - vt_parent_entry = HandlesStruct.find_struct(pname) - parent_vt_count: int = 0 - if vt_parent_entry is not None: - parent_vt_count = vt_parent_entry.VTableMethodCount - if parent_vt_count > 0: - for pvi in range(parent_vt_count): - if method_count >= VTBL_METHOD_MAX: - break - pmethod_name: str = None - if vt_parent_entry is not None: - pmethod_name = HandlesStruct.get_vtable_method_name(pname, pvi) - if pmethod_name is None: - continue - # 多继承 vtable 去重:方法短名已存在跳过(先声明父类优先) - if HandlesClassDef._field_name_exists(method_names_buf, method_count, pmethod_name) != 0: - continue - # 检查子类是否覆盖了该方法,以及是否标记 @t.NoVTable - child_overrides: int = 0 - child_nvt: int = 0 - for ci2 in range(cn): - stmt2: ast.AST | t.CPtr = children.get(ci2) - if stmt2 is None: - continue - if stmt2.kind() != ast.ASTKind.FunctionDef: - continue - fd2: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt2) - if fd2 is not None and fd2.name is not None: - if string.strcmp(fd2.name, pmethod_name) == 0: - child_overrides = 1 - # 检查子类覆盖方法是否标记 @t.NoVTable - if fd2.decorator_list is not None: - if HandlesClassDef._has_decorator(fd2.decorator_list, "NoVTable") == 1: - child_nvt = 1 - break - # 构造 full_name - # 子类覆盖且未标记 NoVTable → 用子类实现 - # 子类未覆盖 或 子类覆盖但标记 NoVTable → 用实际定义类实现(保持 vtable 槽位) - # - # 多层继承修复: 直接父类可能只是继承而非定义该方法 - # (如 ElectricCar 继承 Car 的 is_running 实际定义在 Vehicle), - # 沿父类链向上用 find_func_global("类名.方法名") 探测实际定义类, - # 避免生成 "Car.is_running" 这类找不到函数的 full_name → vtable 槽变 null。 - def_class: str = class_name - if child_overrides == 1 and child_nvt == 0: - def_class = class_name - else: - def_class = pname - # 多继承:沿 pname 的 MRO 祖先链探测实际定义类(跳过自身,先声明父类优先) - mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, pname) - mro_i: int = 1 - while mro_ptr is not None and mro_ptr[mro_i] != 0: - anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mro_i], t.CPtr)) - if anc is not None: - probe_buf: str = pool.alloc(128) - if probe_buf is not None: - viperlib.snprintf(probe_buf, 128, "%s.%s", anc, pmethod_name) - if ExprCallTable.find_func_global(probe_buf) is not None: - def_class = anc - break - mro_i += 1 - pfname_buf: str = CompilerFactory.get_perm_pool().alloc(128) - if pfname_buf is not None: - viperlib.snprintf(pfname_buf, 128, "%s.%s", def_class, pmethod_name) - full_names_buf[method_count] = t.CSizeT(pfname_buf) - # 复制方法名(短名) - pmname_len: t.CSizeT = string.strlen(pmethod_name) - pmname_buf: str = CompilerFactory.get_perm_pool().alloc(pmname_len + 1) - if pmname_buf is not None: - string.strcpy(pmname_buf, pmethod_name) - method_names_buf[method_count] = t.CSizeT(pmname_buf) - # 记录 mangling 用的 SHA1(继承未覆盖的方法用实际定义类的模块 SHA1) - if child_overrides == 1 and child_nvt == 0: - # 子类覆盖: 用当前模块 SHA1(保持 0) - method_parent_sha1s[method_count] = 0 - else: - # 继承未覆盖: 用实际定义类的模块 SHA1(跨模块继承时 mangling 正确) - def_entry2: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct( - def_class) - if def_entry2 is not None and def_entry2.ModuleSha1 is not None: - method_parent_sha1s[method_count] = t.CSizeT(def_entry2.ModuleSha1) - else: - method_parent_sha1s[method_count] = 0 - method_count += 1 - - # 2. 收集当前类的虚方法(跳过已从父类继承的) - for ci in range(cn): - stmt: ast.AST | t.CPtr = children.get(ci) - if stmt is None: - continue - if stmt.kind() != ast.ASTKind.FunctionDef: - continue - fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) - if fd is None or fd.name is None: - continue - if method_count >= VTBL_METHOD_MAX: - break - - mname: str = fd.name - # 跳过构造函数和特殊方法(不应放入虚表) - if string.strcmp(mname, "__init__") == 0: - continue - if string.strcmp(mname, "__before_init__") == 0: - continue - if string.strcmp(mname, "__new__") == 0: - continue - # 函数级装饰器过滤:判断方法是否应该进入虚表 - if HandlesClassDef._should_method_be_virtual(cd, fd, trans) == 0: - continue - # 检查是否已从父类继承(避免重复) - already_in_vt: int = 0 - for mi in range(method_count): - exist_addr: t.CSizeT = method_names_buf[mi] - if exist_addr != 0: - exist_name: str = (str | t.CPtr)(t.CVoid(exist_addr, t.CPtr)) - if exist_name is not None and string.strcmp(exist_name, mname) == 0: - already_in_vt = 1 - break - if already_in_vt == 1: - continue - # 构造 full_name = "ClassName.method_name" - # 内容必须落在 perm_pool:1a(mark_only=1)收集的 VTableMethods 被 - # Phase 1b 依赖模块翻译跨文件读取,1a 每文件 reset 后 pool 裸字符串悬空 - fname_buf: str = CompilerFactory.get_perm_pool().alloc(128) - if fname_buf is not None: - viperlib.snprintf(fname_buf, 128, "%s.%s", class_name, mname) - full_names_buf[method_count] = t.CSizeT(fname_buf) - - # 复制方法名 - mname_len: t.CSizeT = string.strlen(mname) - mname_buf: str = CompilerFactory.get_perm_pool().alloc(mname_len + 1) - if mname_buf is not None: - string.strcpy(mname_buf, mname) - method_names_buf[method_count] = t.CSizeT(mname_buf) - - method_count += 1 - - # 暂存结果(_generate_vtable 复用) - self.VtFullNames = full_names_buf - self.VtMethodNames = method_names_buf - self.VtParentSha1s = method_parent_sha1s - self.VtMethodCount = method_count - - # 设置 entry 元数据(虚分派查询用;必须在本类方法体翻译前就绪, - # 否则方法体内 self.虚方法 调用无法虚分派) - if vt_self_entry is not None and method_count > 0: - vt_self_entry.VTableMethodCount = method_count - vt_self_entry.VTableMethods = method_names_buf - - if method_count == 0: - return 0 - return 1 - # ============================================================ - # _generate_vtable — 生成 VTable 全局变量 - # - # 1. 收集 class body 中所有 FunctionDef 作为虚方法 - # 2. 构造 VTable 类型 { i8*, i8*, ... } - # 3. 构造初始化字符串 { i8* bitcast (...), ... } - # 4. 创建全局变量 @"SHA1.ClassName.vtable" - # 5. 存储虚方法名列表到 StructEntry - # ============================================================ - def _generate_vtable(self, trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr, - class_name: str) -> int: - """生成 VTable 全局变量""" - if trans is None or cd is None or class_name is None: - return 0 - - # 懒导入 - import lib.core.Handles.HandlesFunctions as HandlesFunctions - import lib.core.Handles.HandlesExprCall as HandlesExprCall - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - - # 收集虚方法信息(继承父类 + 自身,结果存 self.VtFullNames 等暂存区) - # 同时设置 entry.VTableMethodCount/VTableMethods(虚分派查询用) - if self._collect_vtable_methods(trans, cd, class_name) == 0: - return 0 - full_names_buf: t.CSizeT | t.CPtr = self.VtFullNames - method_names_buf: t.CSizeT | t.CPtr = self.VtMethodNames - method_parent_sha1s: t.CSizeT | t.CPtr = self.VtParentSha1s - method_count: int = self.VtMethodCount - # 重新获取 entry(后续存储 VTableMethods 用) - vt_self_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( - class_name, trans.ModuleSha1) - - # 2. 构造 VTable 类型: { i8*, i8*, ..., i8* } - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - first_node: llvmlite.ParamNode | t.CPtr = None - tail_node: llvmlite.ParamNode | t.CPtr = None - for i in range(method_count): - pnode: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) - if pnode is None: - continue - tail_node = llvmlite.param_list_append(first_node, tail_node, pnode) - if first_node is None: - first_node = tail_node - - vtable_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, first_node, method_count, None) - if vtable_ty is None: - return 0 - - # 3. 构造初始化字符串 - # 大 vtable(如 MemBuddy 28+ 方法)每个方法 bitcast 约 100+ 字节, - # 4096 可能写满导致截断/strlen 越界,用 16384 预留足够空间。 - init_buf: str = pool.alloc(16384) - if init_buf is None: - return 0 - init_buf[0] = '\0' - self._vtable_strcat(init_buf, 16384, "{ ") - - for i in range(method_count): - if i > 0: - self._vtable_strcat(init_buf, 16384, ", ") - - full_name_addr: t.CSizeT = full_names_buf[i] - if full_name_addr == 0: - self._vtable_strcat(init_buf, 16384, "i8* null") - continue - - full_name: str = (str | t.CPtr)(t.CVoid(full_name_addr, t.CPtr)) - - # 检查是否是继承方法(method_parent_sha1s 非 0 表示用父模块 SHA1 mangling) - parent_sha1_addr: t.CSizeT = method_parent_sha1s[i] - if parent_sha1_addr != 0: - # 继承方法: 用父类模块 SHA1 做 mangling - parent_sha1: str = (str | t.CPtr)(t.CVoid(parent_sha1_addr, t.CPtr)) - mangled_name: str = HandlesFunctions._mangle_name_with_sha1(parent_sha1, full_name) - # 从全局函数表查找(跨模块函数不在当前模块表中) - func: llvmlite.Function | t.CPtr = ExprCallTable.find_func_global(full_name) - else: - # 当前类方法: 用当前模块 SHA1 - mangled_name: str = HandlesFunctions._mangle_name(trans, full_name) - func: llvmlite.Function | t.CPtr = ExprCallTable.find_func_in_table( - trans._funcs, trans._func_count, full_name) - # 当前模块表找不到时,回退到全局表 - if func is None: - func = ExprCallTable.find_func_global(full_name) - - # func 可能已被 1b reset_to(mark1) 回收(跨模块继承方法在定义文件翻译后被 reset)。 - # 悬空指针非 NULL 但内容已被复用,_format_func_type_str 解引用会沿垃圾 Next 链 - # 指针追逐导致无限分配(TypePrint 每次 pool.alloc(512) → 单文件暴涨 900MB OOM)。 - # 因此 func 非 NULL 时也须用 _is_valid_ptr 校验,失败回退到 TypeStr。 - func_valid: int = 0 - if func is not None: - if trans.Pool is not None: - # 继承方法(parent_sha1_addr != 0):func 来自其他模块,该模块 1b 翻译 - # 后已被 reset_to(mark1) 回收,_is_valid_ptr 存在假阳性(块头复用后仍 - # 看似有效),直接判定无效走 TypeStr 回退,避免解引用悬空 func 崩溃。 - if parent_sha1_addr != 0: - func_valid = 0 - elif trans.Pool._is_valid_ptr(func) != 0: - func_valid = 1 - if func_valid == 0: - # 回退到全局表完整 entry 的 TypeStr(stdlib 深拷贝,跨文件永久存活)。 - ge: HandlesExprCall.FuncEntry | t.CPtr = ExprCallTable.find_func_entry_global(full_name) - if ge is not None and ge.TypeStr is not None: - self._vtable_strcat(init_buf, 16384, "i8* bitcast (") - self._vtable_strcat(init_buf, 16384, ge.TypeStr) - self._vtable_strcat(init_buf, 16384, "* @") - if self._vtable_name_needs_quote(mangled_name) != 0: - self._vtable_strcat(init_buf, 16384, "\"") - self._vtable_strcat(init_buf, 16384, mangled_name) - self._vtable_strcat(init_buf, 16384, "\"") - else: - self._vtable_strcat(init_buf, 16384, mangled_name) - self._vtable_strcat(init_buf, 16384, " to i8*)") - continue - # fail-fast:func 无效且全局表 TypeStr 回退也失败, - # 不再写 "i8* null" 静默掩盖缺失实现。 - HandlesType.fatal_error( - cd, f"vtable 方法 '{full_name}' 找不到函数实现", "InternalCompilerError") - continue - - # 构造函数类型字符串 - func_ty_buf: str = pool.alloc(512) - if func_ty_buf is None: - self._vtable_strcat(init_buf, 16384, "i8* null") - continue - self._format_func_type_str(pool, func_ty_buf, 512, func) - - # 构造 bitcast 字符串: i8* bitcast (func_ty* @mangled to i8*) - self._vtable_strcat(init_buf, 16384, "i8* bitcast (") - self._vtable_strcat(init_buf, 16384, func_ty_buf) - self._vtable_strcat(init_buf, 16384, "* @") - - if self._vtable_name_needs_quote(mangled_name) != 0: - self._vtable_strcat(init_buf, 16384, "\"") - self._vtable_strcat(init_buf, 16384, mangled_name) - self._vtable_strcat(init_buf, 16384, "\"") - else: - self._vtable_strcat(init_buf, 16384, mangled_name) - self._vtable_strcat(init_buf, 16384, " to i8*)") - - self._vtable_strcat(init_buf, 16384, " }") - - # 4. 构造 VTable 全局变量名 - vtable_name_buf: str = pool.alloc(128) - if vtable_name_buf is None: - return 0 - viperlib.snprintf(vtable_name_buf, 128, "%s.vtable", class_name) - vtable_mangled: str = HandlesFunctions._mangle_name(trans, vtable_name_buf) - - # 5. 创建全局变量 - gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable( - pool, vtable_mangled, vtable_ty) - if gv is None: - return 0 - gv.Initializer = init_buf - gv.IsConstant = 1 - # 默认 linkage(external,2026-08-10):isinstance 内建函数需要跨模块 - # 引用其他模块类的 vtable 符号({模块sha1}.Class.vtable),internal 不对外 - # 导出会导致链接失败。vtable 名含模块 sha1 前缀全局唯一,外部可见不冲突。 - # llvmlite 打印规则:Initializer 非空 + external 时不打印 external 关键字, - # 输出 @name = constant {...}(合法外部强定义)。 - - # 添加到模块 - llvmlite.module_add_global(mod, gv) - - # 6. 存储虚方法名列表到 StructEntry(直接用 entry,规避跨模块同名 find_struct 找错) - if vt_self_entry is not None: - vt_self_entry.VTableMethods = method_names_buf - vt_self_entry.VTableMethodCount = method_count - - return 0 - # ============================================================ - # _translate_oop_methods — 扫描 class body 中的方法并翻译 - # - # 遍历 ClassDef.children,对每个 FunctionDef: - # - 标记 OOP(mark_as_oop) - # - 如果是 __init__,标记 has_init - # - 翻译方法(生成 SHA1.ClassName.method_name 函数) - # 翻译完所有方法后,生成 __before_init__ 函数 - # ============================================================ - def _translate_oop_methods(self, trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr, - struct_ty: llvmlite.LLVMType | t.CPtr, - class_name: str, - mark_only: int = 0, - reemit: int = 0) -> int: - """扫描 class body 中的方法并翻译,生成 __before_init__ - - mark_only: 0=全量翻译(默认),1=只设置 IsOOP/HasNew/HasInit 标志(不翻译方法体) - reemit: 1=补译模式(_specialize_generic_class Phase B 补译分支调用)。 - 补译分支为防重入已提前置 MethodsEmitted=1,但方法体尚未发射, - 必须跳过下方 MethodsEmitted==1 的防重复检查强制发射,否则补译 - 被自身拦截 → 特化方法只有 call 无 define → 链接 undefined symbol。 - """ - if trans is None or cd is None or struct_ty is None or class_name is None: - return 0 - - children: list[ast.AST | t.CPtr] | t.CPtr = cd.children - if children is None: - return 0 - - cn: t.CSizeT = len(children) - has_method: int = 0 - has_init: int = 0 - has_new: int = 0 - - # 提前用类型指针定位 entry(规避跨模块同名类 find_struct 找错) - oop_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) - - # 第一遍:检测是否有方法,标记 OOP,并注册装饰器元数据 - for ci in range(cn): - stmt: ast.AST | t.CPtr = children.get(ci) - if stmt is None: - continue - if stmt.kind() == ast.ASTKind.FunctionDef: - has_method = 1 - fd_check: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) - if fd_check is not None and fd_check.name is not None: - if string.strcmp(fd_check.name, "__init__") == 0: - has_init = 1 - if string.strcmp(fd_check.name, "__new__") == 0: - has_new = 1 - # 注册装饰器元数据(@property/@staticmethod/@classmethod/@x.setter 等)。 - # 此处(含 mark_only=1 的 struct 预注册阶段)注册, - # 确保其他模块在 App 文件翻译时能识别属性访问。 - fd_meta: int = HandlesClassDef._extract_func_meta(fd_check.decorator_list) - if fd_meta != 0: - HandlesClassDef.register_method_meta(class_name, fd_check.name, fd_meta) - - if has_method == 0: - # 子类没有自己的方法,但可能继承了父类的虚方法 - # 用 oop_entry 直接获取 ParentName,规避 find_struct 按名查找找错 - parent_name: str = None - if oop_entry is not None: - parent_name = oop_entry.ParentName - if parent_name is not None: - parent_vt_count: int = HandlesStruct.get_vtable_method_count(parent_name) - if parent_vt_count > 0: - has_method = 1 # 标记为有方法(继承的虚方法) - if has_method == 0: - return 0 - - # 标记为 OOP 结构体 - if oop_entry is not None: - oop_entry.IsOOP = 1 - if has_init != 0: - oop_entry.HasInit = 1 - if has_new != 0: - oop_entry.HasNew = 1 - - # mark_only 模式:只设置标志,不翻译方法体 - if mark_only != 0: - # Phase 1a 预注册也收集 vtable 元数据(VTableMethods/VTableMethodCount)。 - # 根因:Phase 1b 中依赖模块可能先于其依赖类全量翻译(如 tokens.vp 先于 - # memhub 生成 text.ll),此时调用方查到 entry 有 HasVTable=1 但 - # VTableMethods=None → _translate_method_call 虚分派条件 - # (VTableMethods is not None)不成立 → pool.alloc 被静态绑定到 - # MemManager.alloc(默认返回 None)→ KwEntry.__new__ 返回 null → - # __before_init__ 写 null 崩溃。 - # 短名顺序与 Phase 1b 全量收集一致(父类方法在前 + 本类方法,确定性), - # 多遍扫描重复收集时用新缓冲区覆盖(stdlib 泄漏可忽略,Phase 1b 重译幂等)。 - mk_has_vt: int = 0 - if oop_entry is not None: - mk_has_vt = oop_entry.HasVTable - if mk_has_vt == 1: - self._collect_vtable_methods(trans, cd, class_name) - return 0 - - # 防重复生成:MethodsEmitted==1 说明方法体/__before_init__ 已生成过。 - # 场景:_specialize_generic_class 的 Phase B 补译分支(MethodsEmitted==0 - # 时补译方法体并置 1)之后,同一特化类又经 translate_class_def 全量 - # 翻译进入本方法 → 重复生成 __before_init__ → ld.lld duplicate symbol。 - # 已生成过则直接跳过(方法+__before_init__ 都产出过,跳过安全)。 - # reemit=1(补译模式)时跳过本检查:补译分支为防重入已提前置 - # MethodsEmitted=1,但方法体尚未发射,必须强制发射。 - if oop_entry is not None and oop_entry.MethodsEmitted == 1 and reemit == 0: - return 0 - - # 防重入:方法体翻译前先标记 MethodsEmitted=1。 - # 根因:若等全部方法译完再标记,翻译 __iter__(返回 list[T]|t.CPtr)时, - # 返回类型注解会再次触发 _specialize_generic_class,此时 MethodsEmitted - # 仍为 0,走补译分支把同一特化类方法全部重发 → invalid redefinition。 - if oop_entry is not None: - oop_entry.MethodsEmitted = 1 - - # 第二遍:翻译每个方法 - # 翻译方法体前先预注册 vtable 元数据(VTableMethods/VTableMethodCount)。 - # 根因:方法体翻译先于 _generate_vtable,若不预注册,方法体内的 - # self.虚方法 调用(如 MemManager.calloc 里的 self.alloc)读不到 - # VTableMethods,虚分派失败,被静态绑定到本类实现(基类 alloc 返回 - # None),导致 calloc 永远返回 NULL。 - oop_has_vt_pre: int = 0 - if oop_entry is not None: - oop_has_vt_pre = oop_entry.HasVTable - if oop_has_vt_pre == 1: - self._collect_vtable_methods(trans, cd, class_name) - for ci in range(cn): - stmt: ast.AST | t.CPtr = children.get(ci) - if stmt is None: - continue - if stmt.kind() == ast.ASTKind.FunctionDef: - fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) - if fd is not None and fd.name is not None: - self._translate_method(trans, fd, struct_ty, class_name) - - # 如果有虚表,先生成 VTable 全局变量(设置 VTableMethodCount) - # 必须在 __before_init__ 之前,否则 __before_init__ 读不到 VTableMethodCount - # 用 oop_entry 直接检查,规避跨模块同名 find_struct 找错 - has_vt_flag: int = 0 - if oop_entry is not None: - has_vt_flag = oop_entry.HasVTable - if has_vt_flag == 1: - self._generate_vtable(trans, cd, class_name) - - # 生成 __before_init__ 函数(零值填充 + 默认值赋值 + vtable 指针设置) - self._generate_before_init(trans, struct_ty, class_name) - - return 0 - # ============================================================ - # _translate_method — 翻译单个方法 - # - # 生成: define @SHA1.ClassName.method_name(Ptr(StructTy) %self, ...) - # - # self 参数处理: - # - 类型 Ptr(struct_ty),直接注册为 SSA 值(不创建 alloca) - # - 使 self.field 能通过 GEP 直接访问原始结构体 - # ============================================================ - def _translate_method(self, trans: HT.Translator | t.CPtr, - fd: ast.FunctionDef | t.CPtr, - struct_ty: llvmlite.LLVMType | t.CPtr, - class_name: str) -> int: - """翻译单个方法,返回 0""" - if trans is None or fd is None or struct_ty is None or class_name is None: - return 0 - - # 懒导入 - import lib.core.Handles.HandlesFunctions as HandlesFunctions - import lib.core.Handles.HandlesVar as HandlesVar - import lib.core.Handles.HandlesBody as HandlesBody - import lib.core.Handles.HandlesType as HandlesType - import lib.core.Handles.HandlesExprCall as HandlesExprCall - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - imported_modules: str = trans._imported_modules - from_imports: str = trans._from_imports - funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs - func_count: int = trans._func_count - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - self_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) - - method_name: str = fd.name - if method_name is None: - # fail-fast:方法名缺失(解析器不可能产出无名 def)——静默打印 - VLogger.error("方法名缺失(fd.name is None)", "OOP") - HandlesType.fatal_error(fd, "方法名缺失(fd.name is None)", "TypeError") - - # 提取装饰器元数据(@property/@staticmethod/@classmethod/@x.setter/@x.deleter) - func_meta: int = HandlesClassDef._extract_func_meta(fd.decorator_list) - # property setter/deleter 函数名带 $set/$del 后缀,避免与 getter 冲突 - method_name_buf: str = pool.alloc(128) - if method_name_buf is None: - return 0 - viperlib.snprintf(method_name_buf, 128, "%s", fd.name) - if func_meta & META_PROP_SETTER != 0: - # 128 字节缓冲:追加 "$set" 前检查剩余容量,防 strcat 无界写穿 - mn_len2: t.CSizeT = string.strlen(method_name_buf) - if mn_len2 + 5 < 128: - string.strcat(method_name_buf, "$set") - elif func_meta & META_PROP_DELETER != 0: - mn_len2: t.CSizeT = string.strlen(method_name_buf) - if mn_len2 + 5 < 128: - string.strcat(method_name_buf, "$del") - method_name = method_name_buf - - is_static_m: int = 0 - is_class_m: int = 0 - is_tls_m: int = 0 - if func_meta & META_STATIC != 0: - is_static_m = 1 - if func_meta & META_CLASS != 0: - is_class_m = 1 - if func_meta & META_TLS != 0: - is_tls_m = 1 - - # 构建方法全名: ClassName.method_name - full_name_buf: str = pool.alloc(128) - if full_name_buf is None: - return 0 - viperlib.snprintf(full_name_buf, 128, "%s.%s", class_name, method_name) - full_name: str = full_name_buf - - # SHA1 命名空间混淆 - mangled_name: str = HandlesFunctions._mangle_name(trans, full_name) - - # 推断返回类型 - ret_ty: llvmlite.LLVMType | t.CPtr = None - if fd.returns is not None: - ret_ty = HandlesType.resolve_annotation_type( - pool, fd.returns, imported_modules, from_imports, trans) - if ret_ty is None and fd.returns is not None: - if HandlesType.has_decorator_marker(fd.returns, "State") != 0: - ret_ty = llvmlite.Void(pool) - if ret_ty is None: - # __init__ 和 __before_init__ 返回 void - if string.strcmp(method_name, "__init__") == 0: - ret_ty = llvmlite.Void(pool) - # __new__ 返回 Ptr(struct_ty)(结构体指针作为存储空间) - elif string.strcmp(method_name, "__new__") == 0: - ret_ty = llvmlite.Ptr(pool, struct_ty) - else: - param_types_str: str = HandlesType.build_param_types_str(pool, fd.args) - ret_ty = HandlesType.infer_return_type( - pool, fd.children, param_types_str) - - # 创建 LLVM 函数 - func: llvmlite.Function | t.CPtr = llvmlite.create_function( - pool, mod, mangled_name, ret_ty) - if func is None: - return 0 - - # 提取默认参数信息(普通方法 args[0] 是 self,不含在 param_count 中; - # @staticmethod 无 self,param_count 为完整参数数) - # 注意: 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(), - # 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错 - md_defaults: t.CVoid | t.CPtr = None - md_default_count: int = 0 - md_param_count: int = 0 - md_args_node: ast.Arguments | t.CPtr = fd.args - if md_args_node is not None: - md_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(md_args_node) - if md_ags.args is not None: - md_alist: list[ast.AST | t.CPtr] | t.CPtr = md_ags.args - if is_static_m != 0: - md_param_count = len(md_alist) - else: - md_param_count = len(md_alist) - 1 - if md_ags.defaults is not None: - md_dlist: list[ast.AST | t.CPtr] | t.CPtr = md_ags.defaults - md_defaults = md_dlist - md_default_count = len(md_dlist) - - # 注册到函数表(用 ClassName.method_name 作为查找名,支持后缀匹配) - max_funcs: int = 1024 - if ExprCallTable.add_func_to_table(funcs_ptr, func_count, full_name, func, max_funcs, - md_defaults, md_default_count, md_param_count, - pool) == 0: - trans._func_count = func_count + 1 - - # 添加 self/cls 参数(Ptr(struct_ty));@staticmethod 无 self,跳过 - # @classmethod 的 cls 也用 Ptr(struct_ty),首参名取 args[0](如 cls) - if is_static_m == 0: - first_pname: str = "self" - if is_class_m != 0 and fd.args is not None: - fd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args) - if fd_ags.args is not None and len(fd_ags.args) > 0: - fd_first_arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(fd_ags.args.get(0)) - if fd_first_arg is not None and fd_first_arg.arg is not None: - first_pname = fd_first_arg.arg - first_pname_buf: str = pool.alloc(32) - if first_pname_buf is not None: - viperlib.snprintf(first_pname_buf, 32, "%%%s", first_pname) - llvmlite.add_param(pool, func, self_ptr_ty, first_pname_buf) - - # 添加其他参数(支持类型注解;@staticmethod 从索引 0 开始,其余跳过索引 0 的 self/cls) - args_node: ast.Arguments | t.CPtr = fd.args - if args_node is not None: - ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) - if ags.args is not None: - alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args - an: t.CSizeT = len(alist) - start_idx: int = 0 - if is_static_m == 0: - start_idx = 1 - for ai in range(start_idx, 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: - resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, arg.annotation, imported_modules, from_imports, trans) - if resolved is not None: - # 裸类形参 → Ptr(struct):按"对象即指针"引用传参。 - # 若按 struct 值传参,self.Head = node 会取局部拷贝地址 - # (append 返回后悬垂,G5 Test4 head.Value 读到垃圾)。 - # CArray 形参 → 元素指针 ty*(数组衰减,C 语义,与函数形参一致)。 - match resolved: - case llvmlite.LLVMType.Struct(_, _, _): - param_ty = llvmlite.Ptr(pool, resolved) - case llvmlite.LLVMType.Array(aelem_ty, _): - param_ty = llvmlite.Ptr(pool, aelem_ty) - case _: - param_ty = resolved - pname: str = pool.alloc(32) - if pname is not None: - viperlib.snprintf(pname, 32, "%%%s", arg.arg) - llvmlite.add_param(pool, func, param_ty, pname) - - # OOP iter 协议:__next__ 方法注入隐藏参数 __stop_iter_flag__(i1*)。 - # raise StopIteration 时置 1(对齐 TPC HandlesFunctions.py L703-705)。 - # 该参数不计入 md_param_count(逻辑参数),调用侧(for 循环)显式传。 - if string.strcmp(method_name, "__next__") == 0: - i1_ty_si: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - if i1_ty_si is not None: - i1_ptr_ty_si: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_si) - if i1_ptr_ty_si is not None: - llvmlite.add_param(pool, func, i1_ptr_ty_si, "%__stop_iter_flag__") - - # 参数添加完成,补全全局函数表的 TypeStr(供 vtable 在 func 被 reset 后使用) - ExprCallTable.update_global_func_typestr(pool, full_name, func) - - # 创建 entry 块 - entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") - if entry_blk is None: - return 0 - - # 创建方法专属 builder - func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) - if func_builder is None: - return 0 - llvmlite.position_at_end(func_builder, entry_blk) - - # @t.TLS 一次性初始化守卫(对齐 TPC HandlesFunctions.py L1763-1792; - # 与 FuncGenMixin.translate_function_def 同一实现,类方法同样支持) - if is_tls_m != 0: - tls_m_flag_name: str = pool.alloc(128) - if tls_m_flag_name is not None: - viperlib.snprintf(tls_m_flag_name, 128, "__tls_init_done_%s", method_name) - tls_m_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.create_global_int( - pool, mod, tls_m_flag_name, 1, 0) - if tls_m_gv is not None: - i1_ty_m: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - if i1_ty_m is not None: - # GlobalVariable 非 Value 子类:构造 Value 视图后再 load/store - tls_m_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_m) - tls_m_rn: str = pool.alloc(64) - if tls_m_rn is not None: - viperlib.snprintf(tls_m_rn, 64, "@%s", tls_m_flag_name) - tls_m_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, tls_m_ptr_ty, tls_m_rn) - if tls_m_ref is not None: - tls_m_ld: llvmlite.Value | t.CPtr = llvmlite.build_load( - func_builder, i1_ty_m, tls_m_ref) - lc_m: int = trans._label_counter - trans._label_counter = lc_m + 1 - tls_m_buf: str = pool.alloc(64) - if tls_m_buf is not None: - viperlib.snprintf(tls_m_buf, 64, "tls.skip.%d", lc_m) - tls_m_skip: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, tls_m_buf) - viperlib.snprintf(tls_m_buf, 64, "tls.cont.%d", lc_m) - tls_m_cont: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, tls_m_buf) - if tls_m_skip is not None and tls_m_cont is not None: - llvmlite.build_cond_br( - func_builder, tls_m_ld, tls_m_skip, tls_m_cont) - llvmlite.position_at_end(func_builder, tls_m_skip) - match ret_ty: - case llvmlite.LLVMType.Void(): - llvmlite.build_ret_void(func_builder) - case llvmlite.LLVMType.Int(_): - tlm0: llvmlite.Value | t.CPtr = llvmlite.ConstInt( - pool, ret_ty, 0, "0") - if tlm0 is not None: - llvmlite.build_ret(func_builder, tlm0) - case llvmlite.LLVMType.Float(_): - tlmf: llvmlite.Value | t.CPtr = llvmlite.ConstFloat( - pool, ret_ty, 0.0) - if tlmf is not None: - llvmlite.build_ret(func_builder, tlmf) - case _: - tlmn: llvmlite.Value | t.CPtr = llvmlite.ConstNull( - pool, ret_ty, "null") - if tlmn is not None: - llvmlite.build_ret(func_builder, tlmn) - llvmlite.position_at_end(func_builder, tls_m_cont) - tlmo: llvmlite.Value | t.CPtr = llvmlite.ConstInt( - pool, i1_ty_m, 1, "1") - if tlmo is not None: - llvmlite.build_store(func_builder, tlmo, tls_m_ref) - - # 进入函数作用域 - HandlesVar.enter_scope(trans.SymTab, SCOPE_FUNCTION) - - # 为 self/cls 创建 alloca 并 store(与其他参数一致);@staticmethod 无 self,跳过 - # 修复: 之前 self 注册为 SSA 值导致 translate_name_value 错误地 load 一次 - # 将 Ptr(struct_ty) 变成 struct 值,引发变参函数 ABI 不匹配崩溃 - if is_static_m == 0: - self_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, self_ptr_ty) - if self_alloca is not None: - self_var_name: str = "self" - self_ssa_name: str = "%self" - if is_class_m != 0 and args_node is not None: - cags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) - if cags.args is not None and len(cags.args) > 0: - cfirst: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(cags.args.get(0)) - if cfirst is not None and cfirst.arg is not None: - self_var_name = cfirst.arg - self_ssa_name_buf: str = pool.alloc(32) - if self_ssa_name_buf is not None: - viperlib.snprintf(self_ssa_name_buf, 32, "%%%s", cfirst.arg) - self_ssa_name = self_ssa_name_buf - HandlesVar.define_var(trans.SymTab, self_var_name, self_alloca) - # 设置 self/cls 的类型注解类名(属性访问 lookup_field 回退查找用) - HandlesVar.set_var_annot_class_name(trans.SymTab, self_var_name, class_name) - self_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, self_ptr_ty, self_ssa_name) - llvmlite.build_store(func_builder, self_val, self_alloca) - - # 为其他参数创建 alloca 并 store(与普通函数一致; - # @staticmethod 从索引 0 开始,其余跳过索引 0 的 self/cls 参数) - if args_node is not None: - ags2: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) - if ags2.args is not None: - alist2: list[ast.AST | t.CPtr] | t.CPtr = ags2.args - an2: t.CSizeT = len(alist2) - start_idx2: int = 0 - if is_static_m == 0: - start_idx2 = 1 - for ai2 in range(start_idx2, an2): - arg2: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist2.get(ai2)) - if arg2 is not None and arg2.arg is not None: - param_ty2: llvmlite.LLVMType | t.CPtr = i32_ty - if arg2.annotation is not None: - resolved2: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, arg2.annotation, imported_modules, from_imports, trans) - if resolved2 is None: - # fail-fast:参数有注解但类型解析失败,不再静默保持 i32 - HandlesType.fatal_error( - arg2, f"方法 '{class_name}.{method_name}' 参数 '{arg2.arg}' 类型解析失败", - "NameError") - resolved2 = i32_ty # 不可达(fatal_error 已退出) - if resolved2 is not None: - # 与 add_param 保持一致:裸类形参 → Ptr(struct)(对象即指针) - # CArray 形参 → 元素指针 ty*(数组衰减,与 add_param 一致) - match resolved2: - case llvmlite.LLVMType.Struct(_, _, _): - param_ty2 = llvmlite.Ptr(pool, resolved2) - case llvmlite.LLVMType.Array(aelem_ty2, _): - param_ty2 = llvmlite.Ptr(pool, aelem_ty2) - case _: - param_ty2 = resolved2 - alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, param_ty2) - if alloca is not None: - HandlesVar.define_var(trans.SymTab, arg2.arg, alloca) - # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) - # 传 pool:泛型 Subscript 返回 mangled name(对齐 HandlesAnnAssign 修复) - if arg2.annotation is not None: - cls_nm_oc: str = HandlesType.extract_class_name_from_annotation( - arg2.annotation, imported_modules, pool) - if cls_nm_oc is not None: - HandlesVar.set_var_annot_class_name( - trans.SymTab, arg2.arg, cls_nm_oc) - pname2: str = pool.alloc(32) - if pname2 is not None: - viperlib.snprintf(pname2, 32, "%%%s", arg2.arg) - param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, param_ty2, pname2) - llvmlite.build_store(func_builder, param_val, alloca) - - # OOP iter 协议:__next__ 的 stop-flag 参数初始化(store 0)并保存 - # 指针到 trans,供 translate_raise 的 raise StopIteration 写 1。 - # 参数名必须与上面 add_param 的 "%__stop_iter_flag__" 一致。 - if string.strcmp(method_name, "__next__") == 0: - i1_ty_sf: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - if i1_ty_sf is not None: - i1_ptr_ty_sf: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_sf) - if i1_ptr_ty_sf is not None: - flag_ref_sf: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, i1_ptr_ty_sf, "%__stop_iter_flag__") - if flag_ref_sf is not None: - trans._stop_iter_flag_ptr = flag_ref_sf - zero_i1_sf: llvmlite.Value | t.CPtr = llvmlite.ConstInt( - pool, i1_ty_sf, 0, "0") - if zero_i1_sf is not None: - llvmlite.build_store(func_builder, zero_i1_sf, flag_ref_sf) - - # 保存模块级作用域状态 - old_func: llvmlite.Function | t.CPtr = trans._cur_func - old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - old_global_count: int = trans._global_name_count - old_nonlocal_count: int = trans._nonlocal_name_count - old_env_count: int = trans._closure_env_count - old_stop_iter_flag: llvmlite.Value | t.CPtr = trans._stop_iter_flag_ptr - - trans._cur_func = func - trans._cur_builder = func_builder - HT.clear_scope_names(trans) - - # 预扫描方法体:为局部变量提前创建 alloca - body: list[ast.AST | t.CPtr] | t.CPtr = fd.children - if body is not None: - bn: t.CSizeT = len(body) - for bi in range(bn): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.pre_scan_allocas(trans, stmt) - - # 翻译方法体 - if body is not None: - bn2: t.CSizeT = len(body) - for bi2 in range(bn2): - stmt2: ast.AST | t.CPtr = body.get(bi2) - if stmt2 is not None: - HandlesBody.translate_stmt(trans, stmt2) - - # 追加89:方法末尾收尾与模块级函数(FuncGenMixin.translate_function_def) - # 同语义——编译器不替代码发明返回值,三种合法收尾: - # ① void 方法掉出末尾 → ret void(无值可发明,Python 语义) - # ② 末句是控制流语句(match/if 全分支 return)→ merge 块结构性 - # 不可达 → build_unreachable(不可能抵达,GCC/Clang fall-through - # 视为 UB 同语义) - # ③ 无返回类型注解的方法 → 视为无返回值过程,ConstZero 兜底 - # 有 -> 注解且末句普通语句掉出末尾 → fail-fast。 - # 不做 noreturn 函数名白名单:错误终止路径(fatal_error 等)也必须在 - # 源码层面保证块收尾(如显式 return 样板),每个函数都符合块设计。 - # 原实现 L4529 const_int32 硬编码 ret i32 0,对 i64 返回方法报 llc - # "value doesn't match function result type 'i64'"(追加88 只修了 - # FuncGenMixin 模块级函数路径,方法路径此处追加89 一并同步) - last_is_return: int = 0 - # 追加89:bn3 提前初始化,避免 body is None 时下方引用未定义变量 - bn3: t.CSizeT = 0 - if body is not None: - bn3 = len(body) - if bn3 > 0: - last_stmt_m: ast.AST | t.CPtr = body.get(bn3 - 1) - if last_stmt_m is not None and last_stmt_m.kind() == ast.ASTKind.Return: - last_is_return = 1 - if last_is_return == 0: - if llvmlite.builder_cur_block_is_terminated(func_builder) == 0: - last_is_ctrl: int = 0 - if bn3 > 0: - last_stmt3_m: ast.AST | t.CPtr = body.get(bn3 - 1) - if last_stmt3_m is not None: - k3m: int = last_stmt3_m.kind() - if k3m == ast.ASTKind.If or k3m == ast.ASTKind.While or \ - k3m == ast.ASTKind.For or k3m == ast.ASTKind.Try or \ - k3m == ast.ASTKind.With or k3m == ast.ASTKind.Match: - last_is_ctrl = 1 - _is_void: int = 0 - if ret_ty is not None: - match ret_ty: - case llvmlite.LLVMType.Void(): - _is_void = 1 - case _: - pass - if _is_void != 0: - llvmlite.build_ret_void(func_builder) - elif last_is_ctrl != 0 and trans._ctrl_merge_reachable == 0: - # 追加90(与 FuncGenMixin 同步):非 void 方法末句是控制流 - # 且 merge 块结构性不可达(全分支 return,无 br 到 merge) - # → LLVM 语义 unreachable。merge 可达(分支 br 到 merge)时 - # 不是结构性不可达,需正常收尾(下方 ConstZero / fail-fast)。 - # 原无条件 unreachable 使 llc O2 优化 br-to-unreachable 为 - # fall-through → 双分支执行崩溃(FuncTest check) - llvmlite.build_unreachable(func_builder) - elif fd.returns is None: - # 无返回类型注解 → 无返回值过程方法,默认零值返回 - if ret_ty is not None: - _m_zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, ret_ty) - if _m_zero_val is not None: - llvmlite.build_ret(func_builder, _m_zero_val) - else: - HandlesType.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") - else: - HandlesType.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") - else: - # fail-fast:有 -> 注解但流程真实掉出末尾(traceback 风格) - if ret_ty is not None: - rt_name_m: str = pool.alloc(64) - if rt_name_m is not None: - llvmlite.TypePrint(rt_name_m, 64, ret_ty, pool) - if rt_name_m[0] == '\0': - rt_name_m = "?" - err_fn_m: str = pool.alloc(256) - if err_fn_m is not None: - viperlib.snprintf( - err_fn_m, 256, - "方法 '%s' 流程掉出末尾但未显式 return(返回类型 %s)," - "请补显式 return(如 return 0 / return null)", method_name, rt_name_m) - HandlesType.fatal_error(fd, err_fn_m, "TypeError") - HandlesType.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") - else: - HandlesType.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") - - # 恢复模块级作用域 - HandlesVar.exit_scope(trans.SymTab) - trans._cur_func = old_func - trans._cur_builder = old_builder - trans._global_name_count = old_global_count - trans._nonlocal_name_count = old_nonlocal_count - trans._closure_env_count = old_env_count - trans._stop_iter_flag_ptr = old_stop_iter_flag - - return 0 - # ============================================================ - # _generate_before_init — 生成 __before_init__ 函数 - # - # 生成: define void @SHA1.ClassName.__before_init__(Ptr(StructTy) %self) - # - # 执行: - # 1. store zeroinitializer 到 %self(零值填充) - # 2. 逐字段 store 默认值(如有) - # 3. ret void - # ============================================================ - def _generate_before_init(self, trans: HT.Translator | t.CPtr, - struct_ty: llvmlite.LLVMType | t.CPtr, - class_name: str) -> int: - """生成 __before_init__ 函数,返回 0""" - if trans is None or struct_ty is None or class_name is None: - return 0 - - import lib.core.Handles.HandlesFunctions as HandlesFunctions - import lib.core.Handles.HandlesVar as HandlesVar - import lib.core.Handles.HandlesExpr as HandlesExpr - import lib.core.Handles.HandlesExprCall as HandlesExprCall - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs - func_count: int = trans._func_count - - self_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) - void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) - - # 构建函数名: ClassName.__before_init__ - full_name_buf: str = pool.alloc(128) - if full_name_buf is None: - return 0 - viperlib.snprintf(full_name_buf, 128, "%s.__before_init__", class_name) - full_name: str = full_name_buf - - mangled_name: str = HandlesFunctions._mangle_name(trans, full_name) - - # 创建函数 - func: llvmlite.Function | t.CPtr = llvmlite.create_function( - pool, mod, mangled_name, void_ty) - if func is None: - return 0 - - # 注册到函数表 - max_funcs: int = 1024 - rc_add: int = ExprCallTable.add_func_to_table(funcs_ptr, func_count, full_name, func, max_funcs, None, 0, 0, pool) - if rc_add == 0: - trans._func_count = func_count + 1 - - # 添加 self 参数 - llvmlite.add_param(pool, func, self_ptr_ty, "%self") - - # 参数添加完成,补全全局函数表的 TypeStr - rc_ut: int = ExprCallTable.update_global_func_typestr(pool, full_name, func) - - # 创建 entry 块 + builder - entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") - if entry_blk is None: - return 0 - func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) - if func_builder is None: - return 0 - llvmlite.position_at_end(func_builder, entry_blk) - - # 注册 self 为 SSA 值 - self_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, self_ptr_ty, "%self") - - # 1. 零值填充: store zeroinitializer, Ptr(struct_ty)* %self - # 空 struct({})在 LLVM 中不允许 zeroinitializer(invalid type for null constant), - # 无字段类(接口/标记类,如多继承的 Vec2Extra)跳过零值填充; - # @t.CVTable 类必有 vtable 指针字段(非空),不受影响。 - struct_fcount_zi: int = llvmlite.get_struct_fcount(struct_ty) - if struct_fcount_zi > 0: - zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) - if zero is not None: - llvmlite.build_store(func_builder, zero, self_val) - - # 1.5 如果有虚表,store vtable 全局地址到 __vtable__ 字段(索引 0) - # 用 find_struct_by_type 定位 entry,规避跨模块同名 find_struct 找错 - bi_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) - bi_has_vt: int = 0 - if bi_entry is not None: - bi_has_vt = bi_entry.HasVTable - if bi_has_vt == 1: - vt_method_count: int = 0 - if bi_entry is not None: - vt_method_count = bi_entry.VTableMethodCount - if vt_method_count > 0: - # 构造 vtable 类型 { i8*, i8*, ..., i8* } - vt_i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - vt_i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, vt_i8_ty) - - vt_first_node: llvmlite.ParamNode | t.CPtr = None - vt_prev_node: llvmlite.ParamNode | t.CPtr = None - for vti in range(vt_method_count): - vtnode: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, vt_i8_ptr_ty) - if vtnode is None: - continue - if vt_first_node is None: - vt_first_node = vtnode - if vt_prev_node is not None: - llvmlite.paramnode_set_next(vt_prev_node, vtnode) - vt_prev_node = vtnode - - vt_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, vt_first_node, vt_method_count, None) - vt_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, vt_ty) - - # 构造 vtable 全局变量名 - vt_name_buf: str = pool.alloc(128) - if vt_name_buf is not None: - viperlib.snprintf(vt_name_buf, 128, "%s.vtable", class_name) - vt_full_name: str = vt_name_buf - vt_mangled: str = HandlesFunctions._mangle_name(trans, vt_full_name) - - # GEP 到 __vtable__ 字段(索引 0) - vt_slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - func_builder, struct_ty, vt_i8_ptr_ty, self_val, 0) - if vt_slot is not None: - # 创建全局变量引用 Value - vt_ref: llvmlite.Value | t.CPtr = llvmlite.new_value(pool) - if vt_ref is not None: - llvmlite.value_set_ty(vt_ref, vt_ptr_ty) - llvmlite.value_set_isconst(vt_ref, 1) - # Name 格式: @"mangled" 或 @mangled - vt_ref_name: str = pool.alloc(256) - if vt_ref_name is not None: - vt_ref_name[0] = '\0' - if self._vtable_name_needs_quote(vt_mangled) != 0: - viperlib.snprintf(vt_ref_name, 256, "@\"%s\"", vt_mangled) - else: - viperlib.snprintf(vt_ref_name, 256, "@%s", vt_mangled) - llvmlite.value_set_name(vt_ref, vt_ref_name) - - # bitcast 到 i8* - vt_as_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - func_builder, vt_ref, vt_i8_ptr_ty) - if vt_as_i8 is not None: - llvmlite.build_store(func_builder, vt_as_i8, vt_slot) - - # 2. 逐字段 store 默认值(用 bi_entry 直接访问,规避跨模块同名 find_struct 找错) - if bi_entry is not None: - for fi in range(bi_entry.FieldCount): - fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( - bi_entry, fi) - if fe is None or fe.DefaultVal is None: - continue - # 静态数组字段 + 列表字面量默认值 → 整体置零 + 逐元素 GEP+store - # (与局部 AnnAssign 数组初始化一致;translate_value 会把列表字面量 - # 误译成动态 list 对象指针,coerce 到 [N x elem] 会失败)。 - # 单参 CArray 字段(如 t.CArray[str] = ["py", ...])经类体字段收集 - # 推断为静态数组,此处保证 __before_init__ 填充真实字符串指针。 - if fe.Ty is not None and HandlesExpr.is_array_type(fe.Ty) != 0 \ - and fe.DefaultVal.kind() == ast.ASTKind.List: - field_ptr_arr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - func_builder, struct_ty, fe.Ty, self_val, fe.Index) - if field_ptr_arr is not None: - zero_arr_f: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, fe.Ty) - if zero_arr_f is not None: - llvmlite.build_store(func_builder, zero_arr_f, field_ptr_arr) - # Mixin 静态绑定:self._xxx 只沿本类查找,跨 Mixin 方法 - # (AssignGenMixin._init_global_array_from_list)会生成不存在 - # 符号 → 必须走 HandlesAnnAssign 模块级委托(延迟 import Gen)。 - HandlesAnnAssign._init_global_array_from_list( - func_builder, pool, mod, field_ptr_arr, fe.DefaultVal, trans) - continue - # 翻译默认值表达式 - default_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - func_builder, pool, mod, fe.DefaultVal, None, 0, trans) - if default_val is None: - continue - # GEP 到字段 - field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - func_builder, struct_ty, fe.Ty, self_val, fe.Index) - if field_ptr is None: - continue - # 类型转换并 store - default_val = HandlesExpr.coerce_to_type(func_builder, default_val, fe.Ty, fe.DefaultVal) - llvmlite.build_store(func_builder, default_val, field_ptr) - - # 3. ret void - llvmlite.build_ret_void(func_builder) - +import lib.core.Gen.GenTypes as GenTypes +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HT +import lib.core.StubMerger as StubMerger +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.ClassGenBase as ClassGenBase +import lib.core.Handles.ExprCallTable as ExprCallTable + + +# 方法元数据 flag:TLS(@t.TLS 装饰器,对齐 ClassGenBase 本地常量;本地副本避免跨模块 CDefine 查找) +META_TLS: t.CDefine = 32 + +# ============================================================ +# ClassGenVTable - ClassGenMixin 拆分(阶段 D):vtable 收集/生成/方法翻译 +# +# 继承 ClassGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesClassDef 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class ClassGenVTable(ClassGenBase.ClassGenBase): + """vtable 收集/生成/方法翻译""" + + # ============================================================ + # _vtable_strcat — 将 src 追加到 dst 末尾 + # ============================================================ + def _vtable_strcat(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 + i: t.CSizeT = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' + # ============================================================ + # _vtable_name_needs_quote — 检查 LLVM 标识符是否需要引号 + # ============================================================ + def _vtable_name_needs_quote(self, name: str) -> int: + """检查 LLVM 标识符是否需要引号(以数字开头或含 '.')""" + if name is None: + return 0 + if '0' <= name[0] <= '9': + return 1 + for i in name: + if i == '.': + return 1 + return 0 + # ============================================================ + # _format_func_type_str — 从 Function 对象生成函数类型字符串 + # + # 格式: ret_ty (param1_ty, param2_ty, ...) + # 例如: void ({i32, i32}*, i32) + # ============================================================ + def _format_func_type_str(self, pool: memhub.MemBuddy | t.CPtr, + buf: str, buf_size: t.CSizeT, + func: llvmlite.Function | t.CPtr) -> int: + """从 Function 对象生成函数类型字符串""" + if buf is None or func is None or buf_size == 0: + return 0 + buf[0] = '\0' + # 打印返回类型(使用访问器函数避免跨模块直接字段访问) + ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(func) + ret_buf: str = pool.alloc(128) + if ret_buf is not None and ret_ty is not None: + ret_buf[0] = '\0' + llvmlite.TypePrint(ret_buf, 128, ret_ty, pool) + self._vtable_strcat(buf, buf_size, ret_buf) + self._vtable_strcat(buf, buf_size, " (") + + # 遍历参数(使用访问器函数避免跨模块直接字段访问) + cur: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) + first: int = 1 + param_buf: str = pool.alloc(128) + _pc: int = 0 + while cur is not None: + _pc += 1 + if _pc > 100: + break + if first == 0: + self._vtable_strcat(buf, buf_size, ", ") + if param_buf is not None: + param_buf[0] = '\0' + param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur) + if param_ty is not None: + llvmlite.TypePrint(param_buf, 128, param_ty, pool) + self._vtable_strcat(buf, buf_size, param_buf) + cur = llvmlite.param_get_next(cur) + first = 0 + self._vtable_strcat(buf, buf_size, ")") + return 1 + # ============================================================ + # _collect_vtable_methods — 收集类的虚方法信息 + # + # 1. 继承父类虚方法(父类方法排在子类方法之前,保持槽位顺序一致) + # 2. 收集当前类虚方法(跳过已继承的) + # + # 结果存入 self.VtFullNames/VtMethodNames/VtParentSha1s/VtMethodCount + # (原模块级 _g_vt_*),并设置 entry.VTableMethodCount / + # VTableMethods(stdlib 分配,供虚分派跨模块查询)。 + # + # 返回 1=有虚方法 / 0=无方法或失败 + # ============================================================ + def _collect_vtable_methods(self, trans: HT.Translator | t.CPtr, + cd: ast.ClassDef | t.CPtr, + class_name: str) -> int: + """收集虚方法信息,设置 entry.VTableMethods/VTableMethodCount""" + if trans is None or cd is None or class_name is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + # 懒导入(find_func_global 探测方法实际定义类用) + import lib.core.Handles.HandlesExprCall as HandlesExprCall + + children: list[ast.AST | t.CPtr] | t.CPtr = cd.children + if children is None: + return 0 + cn: t.CSizeT = len(children) + + # 1. 收集虚方法信息 + # stdlib 分配:method_names_buf 存到 StructEntry.VTableMethods(跨文件永久存活), + # 必须迁出 mb 池 reset 区间,否则 1b 每文件 reset_to(mark1) 会回收导致悬空。 + full_names_buf: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(8 * VTBL_METHOD_MAX) + method_names_buf: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(8 * VTBL_METHOD_MAX) + # 记录每个方法的父类 SHA1(非 0=继承方法用父模块 SHA1 mangling,0=当前类方法) + method_parent_sha1s: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(8 * VTBL_METHOD_MAX) + if full_names_buf is None or method_names_buf is None or method_parent_sha1s is None: + return 0 + string.memset(full_names_buf, 0, 8 * VTBL_METHOD_MAX) + string.memset(method_names_buf, 0, 8 * VTBL_METHOD_MAX) + string.memset(method_parent_sha1s, 0, 8 * VTBL_METHOD_MAX) + + method_count: int = 0 + + # ============================================================ + # 1.5 继承父类虚方法 + # + # 父类虚方法排在子类虚方法之前,保持 vtable 槽位顺序一致。 + # 如果子类覆盖了方法,full_name 用子类的;否则用父类的。 + # 用 SHA1 感知查找,规避跨模块同名 find_struct 找错 + # ============================================================ + vt_self_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module( + class_name, trans.ModuleSha1) + # 多继承:遍历所有父类(声明顺序),vtable 方法合并(短名去重,先声明父类优先) + parent_count: int = self.Gen.StructGen.get_parent_count(class_name) + if parent_count > 0: + for pi in range(parent_count): + pname: str = self.Gen.StructGen.get_parent_name_at(class_name, pi) + if pname is None: + continue + # 查找父类 entry(优先同模块 SHA1 匹配) + vt_parent_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module( + pname, trans.ModuleSha1) + if vt_parent_entry is None: + # 跨模块继承: 父类在不同模块定义(SHA1 不同),回退到按类名查找 + vt_parent_entry = self.Gen.StructGen.find_struct(pname) + parent_vt_count: int = 0 + if vt_parent_entry is not None: + parent_vt_count = vt_parent_entry.VTableMethodCount + if parent_vt_count > 0: + for pvi in range(parent_vt_count): + if method_count >= VTBL_METHOD_MAX: + break + pmethod_name: str = None + if vt_parent_entry is not None: + pmethod_name = self.Gen.StructGen.get_vtable_method_name(pname, pvi) + if pmethod_name is None: + continue + # 多继承 vtable 去重:方法短名已存在跳过(先声明父类优先) + if self.Gen.ClassGenBase._field_name_exists(method_names_buf, method_count, pmethod_name) != 0: + continue + # 检查子类是否覆盖了该方法,以及是否标记 @t.NoVTable + child_overrides: int = 0 + child_nvt: int = 0 + for ci2 in range(cn): + stmt2: ast.AST | t.CPtr = children.get(ci2) + if stmt2 is None: + continue + if stmt2.kind() != ast.ASTKind.FunctionDef: + continue + fd2: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt2) + if fd2 is not None and fd2.name is not None: + if string.strcmp(fd2.name, pmethod_name) == 0: + child_overrides = 1 + # 检查子类覆盖方法是否标记 @t.NoVTable + if fd2.decorator_list is not None: + if self.Gen.ClassGenBase._has_decorator(fd2.decorator_list, "NoVTable") == 1: + child_nvt = 1 + break + # 构造 full_name + # 子类覆盖且未标记 NoVTable → 用子类实现 + # 子类未覆盖 或 子类覆盖但标记 NoVTable → 用实际定义类实现(保持 vtable 槽位) + # + # 多层继承修复: 直接父类可能只是继承而非定义该方法 + # (如 ElectricCar 继承 Car 的 is_running 实际定义在 Vehicle), + # 沿父类链向上用 find_func_global("类名.方法名") 探测实际定义类, + # 避免生成 "Car.is_running" 这类找不到函数的 full_name → vtable 槽变 null。 + def_class: str = class_name + if child_overrides == 1 and child_nvt == 0: + def_class = class_name + else: + def_class = pname + # 多继承:沿 pname 的 MRO 祖先链探测实际定义类(跳过自身,先声明父类优先) + mro_ptr: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, pname) + mro_i: int = 1 + while mro_ptr is not None and mro_ptr[mro_i] != 0: + anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mro_i], t.CPtr)) + if anc is not None: + probe_buf: str = pool.alloc(128) + if probe_buf is not None: + viperlib.snprintf(probe_buf, 128, "%s.%s", anc, pmethod_name) + if self.Gen.CallGenLeafKit.find_func_global(probe_buf) is not None: + def_class = anc + break + mro_i += 1 + pfname_buf: str = CompilerFactory.get_perm_pool().alloc(128) + if pfname_buf is not None: + viperlib.snprintf(pfname_buf, 128, "%s.%s", def_class, pmethod_name) + full_names_buf[method_count] = t.CSizeT(pfname_buf) + # 复制方法名(短名) + pmname_len: t.CSizeT = string.strlen(pmethod_name) + pmname_buf: str = CompilerFactory.get_perm_pool().alloc(pmname_len + 1) + if pmname_buf is not None: + string.strcpy(pmname_buf, pmethod_name) + method_names_buf[method_count] = t.CSizeT(pmname_buf) + # 记录 mangling 用的 SHA1(继承未覆盖的方法用实际定义类的模块 SHA1) + if child_overrides == 1 and child_nvt == 0: + # 子类覆盖: 用当前模块 SHA1(保持 0) + method_parent_sha1s[method_count] = 0 + else: + # 继承未覆盖: 用实际定义类的模块 SHA1(跨模块继承时 mangling 正确) + def_entry2: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct( + def_class) + if def_entry2 is not None and def_entry2.ModuleSha1 is not None: + method_parent_sha1s[method_count] = t.CSizeT(def_entry2.ModuleSha1) + else: + method_parent_sha1s[method_count] = 0 + method_count += 1 + + # 2. 收集当前类的虚方法(跳过已从父类继承的) + for ci in range(cn): + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + if stmt.kind() != ast.ASTKind.FunctionDef: + continue + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) + if fd is None or fd.name is None: + continue + if method_count >= VTBL_METHOD_MAX: + break + + mname: str = fd.name + # 跳过构造函数和特殊方法(不应放入虚表) + if string.strcmp(mname, "__init__") == 0: + continue + if string.strcmp(mname, "__before_init__") == 0: + continue + if string.strcmp(mname, "__new__") == 0: + continue + # 函数级装饰器过滤:判断方法是否应该进入虚表 + if self.Gen.ClassGenBase._should_method_be_virtual(cd, fd, trans) == 0: + continue + # 检查是否已从父类继承(避免重复) + already_in_vt: int = 0 + for mi in range(method_count): + exist_addr: t.CSizeT = method_names_buf[mi] + if exist_addr != 0: + exist_name: str = (str | t.CPtr)(t.CVoid(exist_addr, t.CPtr)) + if exist_name is not None and string.strcmp(exist_name, mname) == 0: + already_in_vt = 1 + break + if already_in_vt == 1: + continue + # 构造 full_name = "ClassName.method_name" + # 内容必须落在 perm_pool:1a(mark_only=1)收集的 VTableMethods 被 + # Phase 1b 依赖模块翻译跨文件读取,1a 每文件 reset 后 pool 裸字符串悬空 + fname_buf: str = CompilerFactory.get_perm_pool().alloc(128) + if fname_buf is not None: + viperlib.snprintf(fname_buf, 128, "%s.%s", class_name, mname) + full_names_buf[method_count] = t.CSizeT(fname_buf) + + # 复制方法名 + mname_len: t.CSizeT = string.strlen(mname) + mname_buf: str = CompilerFactory.get_perm_pool().alloc(mname_len + 1) + if mname_buf is not None: + string.strcpy(mname_buf, mname) + method_names_buf[method_count] = t.CSizeT(mname_buf) + + method_count += 1 + + # 暂存结果(_generate_vtable 复用) + self.VtFullNames = full_names_buf + self.VtMethodNames = method_names_buf + self.VtParentSha1s = method_parent_sha1s + self.VtMethodCount = method_count + + # 设置 entry 元数据(虚分派查询用;必须在本类方法体翻译前就绪, + # 否则方法体内 self.虚方法 调用无法虚分派) + if vt_self_entry is not None and method_count > 0: + vt_self_entry.VTableMethodCount = method_count + vt_self_entry.VTableMethods = method_names_buf + + if method_count == 0: + return 0 + return 1 + # ============================================================ + # _generate_vtable — 生成 VTable 全局变量 + # + # 1. 收集 class body 中所有 FunctionDef 作为虚方法 + # 2. 构造 VTable 类型 { i8*, i8*, ... } + # 3. 构造初始化字符串 { i8* bitcast (...), ... } + # 4. 创建全局变量 @"SHA1.ClassName.vtable" + # 5. 存储虚方法名列表到 StructEntry + # ============================================================ + def _generate_vtable(self, trans: HT.Translator | t.CPtr, + cd: ast.ClassDef | t.CPtr, + class_name: str) -> int: + """生成 VTable 全局变量""" + if trans is None or cd is None or class_name is None: + return 0 + + # 懒导入 + import lib.core.Handles.HandlesFunctions as HandlesFunctions + import lib.core.Handles.HandlesExprCall as HandlesExprCall + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + + # 收集虚方法信息(继承父类 + 自身,结果存 self.VtFullNames 等暂存区) + # 同时设置 entry.VTableMethodCount/VTableMethods(虚分派查询用) + if self._collect_vtable_methods(trans, cd, class_name) == 0: + return 0 + full_names_buf: t.CSizeT | t.CPtr = self.VtFullNames + method_names_buf: t.CSizeT | t.CPtr = self.VtMethodNames + method_parent_sha1s: t.CSizeT | t.CPtr = self.VtParentSha1s + method_count: int = self.VtMethodCount + # 重新获取 entry(后续存储 VTableMethods 用) + vt_self_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module( + class_name, trans.ModuleSha1) + + # 2. 构造 VTable 类型: { i8*, i8*, ..., i8* } + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + first_node: llvmlite.ParamNode | t.CPtr = None + tail_node: llvmlite.ParamNode | t.CPtr = None + for i in range(method_count): + pnode: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) + if pnode is None: + continue + tail_node = llvmlite.param_list_append(first_node, tail_node, pnode) + if first_node is None: + first_node = tail_node + + vtable_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, first_node, method_count, None) + if vtable_ty is None: + return 0 + + # 3. 构造初始化字符串 + # 大 vtable(如 MemBuddy 28+ 方法)每个方法 bitcast 约 100+ 字节, + # 4096 可能写满导致截断/strlen 越界,用 16384 预留足够空间。 + init_buf: str = pool.alloc(16384) + if init_buf is None: + return 0 + init_buf[0] = '\0' + self._vtable_strcat(init_buf, 16384, "{ ") + + for i in range(method_count): + if i > 0: + self._vtable_strcat(init_buf, 16384, ", ") + + full_name_addr: t.CSizeT = full_names_buf[i] + if full_name_addr == 0: + self._vtable_strcat(init_buf, 16384, "i8* null") + continue + + full_name: str = (str | t.CPtr)(t.CVoid(full_name_addr, t.CPtr)) + + # 检查是否是继承方法(method_parent_sha1s 非 0 表示用父模块 SHA1 mangling) + parent_sha1_addr: t.CSizeT = method_parent_sha1s[i] + if parent_sha1_addr != 0: + # 继承方法: 用父类模块 SHA1 做 mangling + parent_sha1: str = (str | t.CPtr)(t.CVoid(parent_sha1_addr, t.CPtr)) + mangled_name: str = self.Gen.FuncGenBase._mangle_name_with_sha1(parent_sha1, full_name) + # 从全局函数表查找(跨模块函数不在当前模块表中) + func: llvmlite.Function | t.CPtr = self.Gen.CallGenLeafKit.find_func_global(full_name) + else: + # 当前类方法: 用当前模块 SHA1 + mangled_name: str = self.Gen.FuncGenBase._mangle_name(trans, full_name) + func: llvmlite.Function | t.CPtr = self.Gen.CallGenLeafKit.find_func_in_table( + trans._funcs, trans._func_count, full_name) + # 当前模块表找不到时,回退到全局表 + if func is None: + func = self.Gen.CallGenLeafKit.find_func_global(full_name) + + # func 可能已被 1b reset_to(mark1) 回收(跨模块继承方法在定义文件翻译后被 reset)。 + # 悬空指针非 NULL 但内容已被复用,_format_func_type_str 解引用会沿垃圾 Next 链 + # 指针追逐导致无限分配(TypePrint 每次 pool.alloc(512) → 单文件暴涨 900MB OOM)。 + # 因此 func 非 NULL 时也须用 _is_valid_ptr 校验,失败回退到 TypeStr。 + func_valid: int = 0 + if func is not None: + if trans.Pool is not None: + # 继承方法(parent_sha1_addr != 0):func 来自其他模块,该模块 1b 翻译 + # 后已被 reset_to(mark1) 回收,_is_valid_ptr 存在假阳性(块头复用后仍 + # 看似有效),直接判定无效走 TypeStr 回退,避免解引用悬空 func 崩溃。 + if parent_sha1_addr != 0: + func_valid = 0 + elif trans.Pool._is_valid_ptr(func) != 0: + func_valid = 1 + if func_valid == 0: + # 回退到全局表完整 entry 的 TypeStr(stdlib 深拷贝,跨文件永久存活)。 + ge: GenTypes.FuncEntry | t.CPtr = self.Gen.CallGenLeafKit.find_func_entry_global(full_name) + if ge is not None and ge.TypeStr is not None: + self._vtable_strcat(init_buf, 16384, "i8* bitcast (") + self._vtable_strcat(init_buf, 16384, ge.TypeStr) + self._vtable_strcat(init_buf, 16384, "* @") + if self._vtable_name_needs_quote(mangled_name) != 0: + self._vtable_strcat(init_buf, 16384, "\"") + self._vtable_strcat(init_buf, 16384, mangled_name) + self._vtable_strcat(init_buf, 16384, "\"") + else: + self._vtable_strcat(init_buf, 16384, mangled_name) + self._vtable_strcat(init_buf, 16384, " to i8*)") + continue + # fail-fast:func 无效且全局表 TypeStr 回退也失败, + # 不再写 "i8* null" 静默掩盖缺失实现。 + self.Gen.TypeGenErr.fatal_error( + cd, f"vtable 方法 '{full_name}' 找不到函数实现", "InternalCompilerError") + continue + + # 构造函数类型字符串 + func_ty_buf: str = pool.alloc(512) + if func_ty_buf is None: + self._vtable_strcat(init_buf, 16384, "i8* null") + continue + self._format_func_type_str(pool, func_ty_buf, 512, func) + + # 构造 bitcast 字符串: i8* bitcast (func_ty* @mangled to i8*) + self._vtable_strcat(init_buf, 16384, "i8* bitcast (") + self._vtable_strcat(init_buf, 16384, func_ty_buf) + self._vtable_strcat(init_buf, 16384, "* @") + + if self._vtable_name_needs_quote(mangled_name) != 0: + self._vtable_strcat(init_buf, 16384, "\"") + self._vtable_strcat(init_buf, 16384, mangled_name) + self._vtable_strcat(init_buf, 16384, "\"") + else: + self._vtable_strcat(init_buf, 16384, mangled_name) + self._vtable_strcat(init_buf, 16384, " to i8*)") + + self._vtable_strcat(init_buf, 16384, " }") + + # 4. 构造 VTable 全局变量名 + vtable_name_buf: str = pool.alloc(128) + if vtable_name_buf is None: + return 0 + viperlib.snprintf(vtable_name_buf, 128, "%s.vtable", class_name) + vtable_mangled: str = self.Gen.FuncGenBase._mangle_name(trans, vtable_name_buf) + + # 5. 创建全局变量 + gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable( + pool, vtable_mangled, vtable_ty) + if gv is None: + return 0 + gv.Initializer = init_buf + gv.IsConstant = 1 + # 默认 linkage(external,2026-08-10):isinstance 内建函数需要跨模块 + # 引用其他模块类的 vtable 符号({模块sha1}.Class.vtable),internal 不对外 + # 导出会导致链接失败。vtable 名含模块 sha1 前缀全局唯一,外部可见不冲突。 + # llvmlite 打印规则:Initializer 非空 + external 时不打印 external 关键字, + # 输出 @name = constant {...}(合法外部强定义)。 + + # 添加到模块 + llvmlite.module_add_global(mod, gv) + + # 6. 存储虚方法名列表到 StructEntry(直接用 entry,规避跨模块同名 find_struct 找错) + if vt_self_entry is not None: + vt_self_entry.VTableMethods = method_names_buf + vt_self_entry.VTableMethodCount = method_count + + return 0 + # ============================================================ + # _translate_oop_methods — 扫描 class body 中的方法并翻译 + # + # 遍历 ClassDef.children,对每个 FunctionDef: + # - 标记 OOP(mark_as_oop) + # - 如果是 __init__,标记 has_init + # - 翻译方法(生成 SHA1.ClassName.method_name 函数) + # 翻译完所有方法后,生成 __before_init__ 函数 + # ============================================================ + def _translate_oop_methods(self, trans: HT.Translator | t.CPtr, + cd: ast.ClassDef | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr, + class_name: str, + mark_only: int = 0, + reemit: int = 0) -> int: + """扫描 class body 中的方法并翻译,生成 __before_init__ + + mark_only: 0=全量翻译(默认),1=只设置 IsOOP/HasNew/HasInit 标志(不翻译方法体) + reemit: 1=补译模式(_specialize_generic_class Phase B 补译分支调用)。 + 补译分支为防重入已提前置 MethodsEmitted=1,但方法体尚未发射, + 必须跳过下方 MethodsEmitted==1 的防重复检查强制发射,否则补译 + 被自身拦截 → 特化方法只有 call 无 define → 链接 undefined symbol。 + """ + if trans is None or cd is None or struct_ty is None or class_name is None: + return 0 + + children: list[ast.AST | t.CPtr] | t.CPtr = cd.children + if children is None: + return 0 + + cn: t.CSizeT = len(children) + has_method: int = 0 + has_init: int = 0 + has_new: int = 0 + + # 提前用类型指针定位 entry(规避跨模块同名类 find_struct 找错) + oop_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_type(struct_ty) + + # 第一遍:检测是否有方法,标记 OOP,并注册装饰器元数据 + for ci in range(cn): + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + if stmt.kind() == ast.ASTKind.FunctionDef: + has_method = 1 + fd_check: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) + if fd_check is not None and fd_check.name is not None: + if string.strcmp(fd_check.name, "__init__") == 0: + has_init = 1 + if string.strcmp(fd_check.name, "__new__") == 0: + has_new = 1 + # 注册装饰器元数据(@property/@staticmethod/@classmethod/@x.setter 等)。 + # 此处(含 mark_only=1 的 struct 预注册阶段)注册, + # 确保其他模块在 App 文件翻译时能识别属性访问。 + fd_meta: int = self.Gen.ClassGenBase._extract_func_meta(fd_check.decorator_list) + if fd_meta != 0: + self.Gen.ClassGenBase.register_method_meta(class_name, fd_check.name, fd_meta) + + if has_method == 0: + # 子类没有自己的方法,但可能继承了父类的虚方法 + # 用 oop_entry 直接获取 ParentName,规避 find_struct 按名查找找错 + parent_name: str = None + if oop_entry is not None: + parent_name = oop_entry.ParentName + if parent_name is not None: + parent_vt_count: int = self.Gen.StructGen.get_vtable_method_count(parent_name) + if parent_vt_count > 0: + has_method = 1 # 标记为有方法(继承的虚方法) + if has_method == 0: + return 0 + + # 标记为 OOP 结构体 + if oop_entry is not None: + oop_entry.IsOOP = 1 + if has_init != 0: + oop_entry.HasInit = 1 + if has_new != 0: + oop_entry.HasNew = 1 + + # mark_only 模式:只设置标志,不翻译方法体 + if mark_only != 0: + # Phase 1a 预注册也收集 vtable 元数据(VTableMethods/VTableMethodCount)。 + # 根因:Phase 1b 中依赖模块可能先于其依赖类全量翻译(如 tokens.vp 先于 + # memhub 生成 text.ll),此时调用方查到 entry 有 HasVTable=1 但 + # VTableMethods=None → _translate_method_call 虚分派条件 + # (VTableMethods is not None)不成立 → pool.alloc 被静态绑定到 + # MemManager.alloc(默认返回 None)→ KwEntry.__new__ 返回 null → + # __before_init__ 写 null 崩溃。 + # 短名顺序与 Phase 1b 全量收集一致(父类方法在前 + 本类方法,确定性), + # 多遍扫描重复收集时用新缓冲区覆盖(stdlib 泄漏可忽略,Phase 1b 重译幂等)。 + mk_has_vt: int = 0 + if oop_entry is not None: + mk_has_vt = oop_entry.HasVTable + if mk_has_vt == 1: + self._collect_vtable_methods(trans, cd, class_name) + return 0 + + # 防重复生成:MethodsEmitted==1 说明方法体/__before_init__ 已生成过。 + # 场景:_specialize_generic_class 的 Phase B 补译分支(MethodsEmitted==0 + # 时补译方法体并置 1)之后,同一特化类又经 translate_class_def 全量 + # 翻译进入本方法 → 重复生成 __before_init__ → ld.lld duplicate symbol。 + # 已生成过则直接跳过(方法+__before_init__ 都产出过,跳过安全)。 + # reemit=1(补译模式)时跳过本检查:补译分支为防重入已提前置 + # MethodsEmitted=1,但方法体尚未发射,必须强制发射。 + if oop_entry is not None and oop_entry.MethodsEmitted == 1 and reemit == 0: + return 0 + + # 防重入:方法体翻译前先标记 MethodsEmitted=1。 + # 根因:若等全部方法译完再标记,翻译 __iter__(返回 list[T]|t.CPtr)时, + # 返回类型注解会再次触发 _specialize_generic_class,此时 MethodsEmitted + # 仍为 0,走补译分支把同一特化类方法全部重发 → invalid redefinition。 + if oop_entry is not None: + oop_entry.MethodsEmitted = 1 + + # 第二遍:翻译每个方法 + # 翻译方法体前先预注册 vtable 元数据(VTableMethods/VTableMethodCount)。 + # 根因:方法体翻译先于 _generate_vtable,若不预注册,方法体内的 + # self.虚方法 调用(如 MemManager.calloc 里的 self.alloc)读不到 + # VTableMethods,虚分派失败,被静态绑定到本类实现(基类 alloc 返回 + # None),导致 calloc 永远返回 NULL。 + oop_has_vt_pre: int = 0 + if oop_entry is not None: + oop_has_vt_pre = oop_entry.HasVTable + if oop_has_vt_pre == 1: + self._collect_vtable_methods(trans, cd, class_name) + for ci in range(cn): + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + if stmt.kind() == ast.ASTKind.FunctionDef: + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) + if fd is not None and fd.name is not None: + self._translate_method(trans, fd, struct_ty, class_name) + + # 如果有虚表,先生成 VTable 全局变量(设置 VTableMethodCount) + # 必须在 __before_init__ 之前,否则 __before_init__ 读不到 VTableMethodCount + # 用 oop_entry 直接检查,规避跨模块同名 find_struct 找错 + has_vt_flag: int = 0 + if oop_entry is not None: + has_vt_flag = oop_entry.HasVTable + if has_vt_flag == 1: + self._generate_vtable(trans, cd, class_name) + + # 生成 __before_init__ 函数(零值填充 + 默认值赋值 + vtable 指针设置) + self._generate_before_init(trans, struct_ty, class_name) + + return 0 + # ============================================================ + # _translate_method — 翻译单个方法 + # + # 生成: define @SHA1.ClassName.method_name(Ptr(StructTy) %self, ...) + # + # self 参数处理: + # - 类型 Ptr(struct_ty),直接注册为 SSA 值(不创建 alloca) + # - 使 self.field 能通过 GEP 直接访问原始结构体 + # ============================================================ + def _translate_method(self, trans: HT.Translator | t.CPtr, + fd: ast.FunctionDef | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr, + class_name: str) -> int: + """翻译单个方法,返回 0""" + if trans is None or fd is None or struct_ty is None or class_name is None: + return 0 + + # 懒导入 + import lib.core.Handles.HandlesFunctions as HandlesFunctions + import lib.core.Handles.HandlesVar as HandlesVar + import lib.core.Handles.HandlesBody as HandlesBody + import lib.core.Handles.HandlesType as HandlesType + import lib.core.Handles.HandlesExprCall as HandlesExprCall + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + imported_modules: str = trans._imported_modules + from_imports: str = trans._from_imports + funcs_ptr: GenTypes.FuncEntry | t.CPtr = trans._funcs + func_count: int = trans._func_count + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + self_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) + + method_name: str = fd.name + if method_name is None: + # fail-fast:方法名缺失(解析器不可能产出无名 def)——静默打印 + VLogger.error("方法名缺失(fd.name is None)", "OOP") + self.Gen.TypeGenErr.fatal_error(fd, "方法名缺失(fd.name is None)", "TypeError") + + # 提取装饰器元数据(@property/@staticmethod/@classmethod/@x.setter/@x.deleter) + func_meta: int = self.Gen.ClassGenBase._extract_func_meta(fd.decorator_list) + # property setter/deleter 函数名带 $set/$del 后缀,避免与 getter 冲突 + method_name_buf: str = pool.alloc(128) + if method_name_buf is None: + return 0 + viperlib.snprintf(method_name_buf, 128, "%s", fd.name) + if func_meta & META_PROP_SETTER != 0: + # 128 字节缓冲:追加 "$set" 前检查剩余容量,防 strcat 无界写穿 + mn_len2: t.CSizeT = string.strlen(method_name_buf) + if mn_len2 + 5 < 128: + string.strcat(method_name_buf, "$set") + elif func_meta & META_PROP_DELETER != 0: + mn_len2: t.CSizeT = string.strlen(method_name_buf) + if mn_len2 + 5 < 128: + string.strcat(method_name_buf, "$del") + method_name = method_name_buf + + is_static_m: int = 0 + is_class_m: int = 0 + is_tls_m: int = 0 + if func_meta & META_STATIC != 0: + is_static_m = 1 + if func_meta & META_CLASS != 0: + is_class_m = 1 + if func_meta & META_TLS != 0: + is_tls_m = 1 + + # 构建方法全名: ClassName.method_name + full_name_buf: str = pool.alloc(128) + if full_name_buf is None: + return 0 + viperlib.snprintf(full_name_buf, 128, "%s.%s", class_name, method_name) + full_name: str = full_name_buf + + # SHA1 命名空间混淆 + mangled_name: str = self.Gen.FuncGenBase._mangle_name(trans, full_name) + + # 推断返回类型 + ret_ty: llvmlite.LLVMType | t.CPtr = None + if fd.returns is not None: + ret_ty = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, fd.returns, imported_modules, from_imports, trans) + if ret_ty is None and fd.returns is not None: + if self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "State") != 0: + ret_ty = llvmlite.Void(pool) + if ret_ty is None: + # __init__ 和 __before_init__ 返回 void + if string.strcmp(method_name, "__init__") == 0: + ret_ty = llvmlite.Void(pool) + # __new__ 返回 Ptr(struct_ty)(结构体指针作为存储空间) + elif string.strcmp(method_name, "__new__") == 0: + ret_ty = llvmlite.Ptr(pool, struct_ty) + else: + param_types_str: str = self.Gen.TypeGenErr.build_param_types_str(pool, fd.args) + ret_ty = self.Gen.TypeGenErr.infer_return_type( + pool, fd.children, param_types_str) + + # 创建 LLVM 函数 + func: llvmlite.Function | t.CPtr = llvmlite.create_function( + pool, mod, mangled_name, ret_ty) + if func is None: + return 0 + + # 提取默认参数信息(普通方法 args[0] 是 self,不含在 param_count 中; + # @staticmethod 无 self,param_count 为完整参数数) + # 注意: 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(), + # 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错 + md_defaults: t.CVoid | t.CPtr = None + md_default_count: int = 0 + md_param_count: int = 0 + md_args_node: ast.Arguments | t.CPtr = fd.args + if md_args_node is not None: + md_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(md_args_node) + if md_ags.args is not None: + md_alist: list[ast.AST | t.CPtr] | t.CPtr = md_ags.args + if is_static_m != 0: + md_param_count = len(md_alist) + else: + md_param_count = len(md_alist) - 1 + if md_ags.defaults is not None: + md_dlist: list[ast.AST | t.CPtr] | t.CPtr = md_ags.defaults + md_defaults = md_dlist + md_default_count = len(md_dlist) + + # 注册到函数表(用 ClassName.method_name 作为查找名,支持后缀匹配) + max_funcs: int = 1024 + if self.Gen.CallGenLeafKit.add_func_to_table(funcs_ptr, func_count, full_name, func, max_funcs, + md_defaults, md_default_count, md_param_count, + pool) == 0: + trans._func_count = func_count + 1 + + # 添加 self/cls 参数(Ptr(struct_ty));@staticmethod 无 self,跳过 + # @classmethod 的 cls 也用 Ptr(struct_ty),首参名取 args[0](如 cls) + if is_static_m == 0: + first_pname: str = "self" + if is_class_m != 0 and fd.args is not None: + fd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args) + if fd_ags.args is not None and len(fd_ags.args) > 0: + fd_first_arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(fd_ags.args.get(0)) + if fd_first_arg is not None and fd_first_arg.arg is not None: + first_pname = fd_first_arg.arg + first_pname_buf: str = pool.alloc(32) + if first_pname_buf is not None: + viperlib.snprintf(first_pname_buf, 32, "%%%s", first_pname) + llvmlite.add_param(pool, func, self_ptr_ty, first_pname_buf) + + # 添加其他参数(支持类型注解;@staticmethod 从索引 0 开始,其余跳过索引 0 的 self/cls) + args_node: ast.Arguments | t.CPtr = fd.args + if args_node is not None: + ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if ags.args is not None: + alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args + an: t.CSizeT = len(alist) + start_idx: int = 0 + if is_static_m == 0: + start_idx = 1 + for ai in range(start_idx, 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: + resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, arg.annotation, imported_modules, from_imports, trans) + if resolved is not None: + # 裸类形参 → Ptr(struct):按"对象即指针"引用传参。 + # 若按 struct 值传参,self.Head = node 会取局部拷贝地址 + # (append 返回后悬垂,G5 Test4 head.Value 读到垃圾)。 + # CArray 形参 → 元素指针 ty*(数组衰减,C 语义,与函数形参一致)。 + match resolved: + case llvmlite.LLVMType.Struct(_, _, _): + param_ty = llvmlite.Ptr(pool, resolved) + case llvmlite.LLVMType.Array(aelem_ty, _): + param_ty = llvmlite.Ptr(pool, aelem_ty) + case _: + param_ty = resolved + pname: str = pool.alloc(32) + if pname is not None: + viperlib.snprintf(pname, 32, "%%%s", arg.arg) + llvmlite.add_param(pool, func, param_ty, pname) + + # OOP iter 协议:__next__ 方法注入隐藏参数 __stop_iter_flag__(i1*)。 + # raise StopIteration 时置 1(对齐 TPC HandlesFunctions.py L703-705)。 + # 该参数不计入 md_param_count(逻辑参数),调用侧(for 循环)显式传。 + if string.strcmp(method_name, "__next__") == 0: + i1_ty_si: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + if i1_ty_si is not None: + i1_ptr_ty_si: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_si) + if i1_ptr_ty_si is not None: + llvmlite.add_param(pool, func, i1_ptr_ty_si, "%__stop_iter_flag__") + + # 参数添加完成,补全全局函数表的 TypeStr(供 vtable 在 func 被 reset 后使用) + self.Gen.CallGenLeafKit.update_global_func_typestr(pool, full_name, func) + + # 创建 entry 块 + entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") + if entry_blk is None: + return 0 + + # 创建方法专属 builder + func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) + if func_builder is None: + return 0 + llvmlite.position_at_end(func_builder, entry_blk) + + # @t.TLS 一次性初始化守卫(对齐 TPC HandlesFunctions.py L1763-1792; + # 与 FuncGenMixin.translate_function_def 同一实现,类方法同样支持) + if is_tls_m != 0: + tls_m_flag_name: str = pool.alloc(128) + if tls_m_flag_name is not None: + viperlib.snprintf(tls_m_flag_name, 128, "__tls_init_done_%s", method_name) + tls_m_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.create_global_int( + pool, mod, tls_m_flag_name, 1, 0) + if tls_m_gv is not None: + i1_ty_m: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + if i1_ty_m is not None: + # GlobalVariable 非 Value 子类:构造 Value 视图后再 load/store + tls_m_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_m) + tls_m_rn: str = pool.alloc(64) + if tls_m_rn is not None: + viperlib.snprintf(tls_m_rn, 64, "@%s", tls_m_flag_name) + tls_m_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, tls_m_ptr_ty, tls_m_rn) + if tls_m_ref is not None: + tls_m_ld: llvmlite.Value | t.CPtr = llvmlite.build_load( + func_builder, i1_ty_m, tls_m_ref) + lc_m: int = trans._label_counter + trans._label_counter = lc_m + 1 + tls_m_buf: str = pool.alloc(64) + if tls_m_buf is not None: + viperlib.snprintf(tls_m_buf, 64, "tls.skip.%d", lc_m) + tls_m_skip: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, tls_m_buf) + viperlib.snprintf(tls_m_buf, 64, "tls.cont.%d", lc_m) + tls_m_cont: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, tls_m_buf) + if tls_m_skip is not None and tls_m_cont is not None: + llvmlite.build_cond_br( + func_builder, tls_m_ld, tls_m_skip, tls_m_cont) + llvmlite.position_at_end(func_builder, tls_m_skip) + match ret_ty: + case llvmlite.LLVMType.Void(): + llvmlite.build_ret_void(func_builder) + case llvmlite.LLVMType.Int(_): + tlm0: llvmlite.Value | t.CPtr = llvmlite.ConstInt( + pool, ret_ty, 0, "0") + if tlm0 is not None: + llvmlite.build_ret(func_builder, tlm0) + case llvmlite.LLVMType.Float(_): + tlmf: llvmlite.Value | t.CPtr = llvmlite.ConstFloat( + pool, ret_ty, 0.0) + if tlmf is not None: + llvmlite.build_ret(func_builder, tlmf) + case _: + tlmn: llvmlite.Value | t.CPtr = llvmlite.ConstNull( + pool, ret_ty, "null") + if tlmn is not None: + llvmlite.build_ret(func_builder, tlmn) + llvmlite.position_at_end(func_builder, tls_m_cont) + tlmo: llvmlite.Value | t.CPtr = llvmlite.ConstInt( + pool, i1_ty_m, 1, "1") + if tlmo is not None: + llvmlite.build_store(func_builder, tlmo, tls_m_ref) + + # 进入函数作用域 + self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_FUNCTION) + + # 为 self/cls 创建 alloca 并 store(与其他参数一致);@staticmethod 无 self,跳过 + # 修复: 之前 self 注册为 SSA 值导致 translate_name_value 错误地 load 一次 + # 将 Ptr(struct_ty) 变成 struct 值,引发变参函数 ABI 不匹配崩溃 + if is_static_m == 0: + self_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, self_ptr_ty) + if self_alloca is not None: + self_var_name: str = "self" + self_ssa_name: str = "%self" + if is_class_m != 0 and args_node is not None: + cags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if cags.args is not None and len(cags.args) > 0: + cfirst: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(cags.args.get(0)) + if cfirst is not None and cfirst.arg is not None: + self_var_name = cfirst.arg + self_ssa_name_buf: str = pool.alloc(32) + if self_ssa_name_buf is not None: + viperlib.snprintf(self_ssa_name_buf, 32, "%%%s", cfirst.arg) + self_ssa_name = self_ssa_name_buf + self.Gen.VarGen.define_var(trans.SymTab, self_var_name, self_alloca) + # 设置 self/cls 的类型注解类名(属性访问 lookup_field 回退查找用) + self.Gen.VarGen.set_var_annot_class_name(trans.SymTab, self_var_name, class_name) + self_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, self_ptr_ty, self_ssa_name) + llvmlite.build_store(func_builder, self_val, self_alloca) + + # 为其他参数创建 alloca 并 store(与普通函数一致; + # @staticmethod 从索引 0 开始,其余跳过索引 0 的 self/cls 参数) + if args_node is not None: + ags2: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if ags2.args is not None: + alist2: list[ast.AST | t.CPtr] | t.CPtr = ags2.args + an2: t.CSizeT = len(alist2) + start_idx2: int = 0 + if is_static_m == 0: + start_idx2 = 1 + for ai2 in range(start_idx2, an2): + arg2: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist2.get(ai2)) + if arg2 is not None and arg2.arg is not None: + param_ty2: llvmlite.LLVMType | t.CPtr = i32_ty + if arg2.annotation is not None: + resolved2: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, arg2.annotation, imported_modules, from_imports, trans) + if resolved2 is None: + # fail-fast:参数有注解但类型解析失败,不再静默保持 i32 + self.Gen.TypeGenErr.fatal_error( + arg2, f"方法 '{class_name}.{method_name}' 参数 '{arg2.arg}' 类型解析失败", + "NameError") + resolved2 = i32_ty # 不可达(fatal_error 已退出) + if resolved2 is not None: + # 与 add_param 保持一致:裸类形参 → Ptr(struct)(对象即指针) + # CArray 形参 → 元素指针 ty*(数组衰减,与 add_param 一致) + match resolved2: + case llvmlite.LLVMType.Struct(_, _, _): + param_ty2 = llvmlite.Ptr(pool, resolved2) + case llvmlite.LLVMType.Array(aelem_ty2, _): + param_ty2 = llvmlite.Ptr(pool, aelem_ty2) + case _: + param_ty2 = resolved2 + alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, param_ty2) + if alloca is not None: + self.Gen.VarGen.define_var(trans.SymTab, arg2.arg, alloca) + # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) + # 传 pool:泛型 Subscript 返回 mangled name(对齐 HandlesAnnAssign 修复) + if arg2.annotation is not None: + cls_nm_oc: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation( + arg2.annotation, imported_modules, pool) + if cls_nm_oc is not None: + self.Gen.VarGen.set_var_annot_class_name( + trans.SymTab, arg2.arg, cls_nm_oc) + pname2: str = pool.alloc(32) + if pname2 is not None: + viperlib.snprintf(pname2, 32, "%%%s", arg2.arg) + param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, param_ty2, pname2) + llvmlite.build_store(func_builder, param_val, alloca) + + # OOP iter 协议:__next__ 的 stop-flag 参数初始化(store 0)并保存 + # 指针到 trans,供 translate_raise 的 raise StopIteration 写 1。 + # 参数名必须与上面 add_param 的 "%__stop_iter_flag__" 一致。 + if string.strcmp(method_name, "__next__") == 0: + i1_ty_sf: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + if i1_ty_sf is not None: + i1_ptr_ty_sf: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_sf) + if i1_ptr_ty_sf is not None: + flag_ref_sf: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, i1_ptr_ty_sf, "%__stop_iter_flag__") + if flag_ref_sf is not None: + trans._stop_iter_flag_ptr = flag_ref_sf + zero_i1_sf: llvmlite.Value | t.CPtr = llvmlite.ConstInt( + pool, i1_ty_sf, 0, "0") + if zero_i1_sf is not None: + llvmlite.build_store(func_builder, zero_i1_sf, flag_ref_sf) + + # 保存模块级作用域状态 + old_func: llvmlite.Function | t.CPtr = trans._cur_func + old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + old_global_count: int = trans._global_name_count + old_nonlocal_count: int = trans._nonlocal_name_count + old_env_count: int = trans._closure_env_count + old_stop_iter_flag: llvmlite.Value | t.CPtr = trans._stop_iter_flag_ptr + + trans._cur_func = func + trans._cur_builder = func_builder + HT.clear_scope_names(trans) + + # 预扫描方法体:为局部变量提前创建 alloca + body: list[ast.AST | t.CPtr] | t.CPtr = fd.children + if body is not None: + bn: t.CSizeT = len(body) + for bi in range(bn): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + self.Gen.StmtGenDecl.pre_scan_allocas(trans, stmt) + + # 翻译方法体 + if body is not None: + bn2: t.CSizeT = len(body) + for bi2 in range(bn2): + stmt2: ast.AST | t.CPtr = body.get(bi2) + if stmt2 is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt2) + + # 追加89:方法末尾收尾与模块级函数(FuncGenMixin.translate_function_def) + # 同语义——编译器不替代码发明返回值,三种合法收尾: + # ① void 方法掉出末尾 → ret void(无值可发明,Python 语义) + # ② 末句是控制流语句(match/if 全分支 return)→ merge 块结构性 + # 不可达 → build_unreachable(不可能抵达,GCC/Clang fall-through + # 视为 UB 同语义) + # ③ 无返回类型注解的方法 → 视为无返回值过程,ConstZero 兜底 + # 有 -> 注解且末句普通语句掉出末尾 → fail-fast。 + # 不做 noreturn 函数名白名单:错误终止路径(fatal_error 等)也必须在 + # 源码层面保证块收尾(如显式 return 样板),每个函数都符合块设计。 + # 原实现 L4529 const_int32 硬编码 ret i32 0,对 i64 返回方法报 llc + # "value doesn't match function result type 'i64'"(追加88 只修了 + # FuncGenMixin 模块级函数路径,方法路径此处追加89 一并同步) + last_is_return: int = 0 + # 追加89:bn3 提前初始化,避免 body is None 时下方引用未定义变量 + bn3: t.CSizeT = 0 + if body is not None: + bn3 = len(body) + if bn3 > 0: + last_stmt_m: ast.AST | t.CPtr = body.get(bn3 - 1) + if last_stmt_m is not None and last_stmt_m.kind() == ast.ASTKind.Return: + last_is_return = 1 + if last_is_return == 0: + if llvmlite.builder_cur_block_is_terminated(func_builder) == 0: + last_is_ctrl: int = 0 + if bn3 > 0: + last_stmt3_m: ast.AST | t.CPtr = body.get(bn3 - 1) + if last_stmt3_m is not None: + k3m: int = last_stmt3_m.kind() + if k3m == ast.ASTKind.If or k3m == ast.ASTKind.While or \ + k3m == ast.ASTKind.For or k3m == ast.ASTKind.Try or \ + k3m == ast.ASTKind.With or k3m == ast.ASTKind.Match: + last_is_ctrl = 1 + _is_void: int = 0 + if ret_ty is not None: + match ret_ty: + case llvmlite.LLVMType.Void(): + _is_void = 1 + case _: + pass + if _is_void != 0: + llvmlite.build_ret_void(func_builder) + elif last_is_ctrl != 0 and trans._ctrl_merge_reachable == 0: + # 追加90(与 FuncGenMixin 同步):非 void 方法末句是控制流 + # 且 merge 块结构性不可达(全分支 return,无 br 到 merge) + # → LLVM 语义 unreachable。merge 可达(分支 br 到 merge)时 + # 不是结构性不可达,需正常收尾(下方 ConstZero / fail-fast)。 + # 原无条件 unreachable 使 llc O2 优化 br-to-unreachable 为 + # fall-through → 双分支执行崩溃(FuncTest check) + llvmlite.build_unreachable(func_builder) + elif fd.returns is None: + # 无返回类型注解 → 无返回值过程方法,默认零值返回 + if ret_ty is not None: + _m_zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, ret_ty) + if _m_zero_val is not None: + llvmlite.build_ret(func_builder, _m_zero_val) + else: + self.Gen.TypeGenErr.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") + else: + self.Gen.TypeGenErr.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") + else: + # fail-fast:有 -> 注解但流程真实掉出末尾(traceback 风格) + if ret_ty is not None: + rt_name_m: str = pool.alloc(64) + if rt_name_m is not None: + llvmlite.TypePrint(rt_name_m, 64, ret_ty, pool) + if rt_name_m[0] == '\0': + rt_name_m = "?" + err_fn_m: str = pool.alloc(256) + if err_fn_m is not None: + viperlib.snprintf( + err_fn_m, 256, + "方法 '%s' 流程掉出末尾但未显式 return(返回类型 %s)," + "请补显式 return(如 return 0 / return null)", method_name, rt_name_m) + self.Gen.TypeGenErr.fatal_error(fd, err_fn_m, "TypeError") + self.Gen.TypeGenErr.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") + else: + self.Gen.TypeGenErr.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") + + # 恢复模块级作用域 + self.Gen.VarGen.exit_scope(trans.SymTab) + trans._cur_func = old_func + trans._cur_builder = old_builder + trans._global_name_count = old_global_count + trans._nonlocal_name_count = old_nonlocal_count + trans._closure_env_count = old_env_count + trans._stop_iter_flag_ptr = old_stop_iter_flag + + return 0 + # ============================================================ + # _generate_before_init — 生成 __before_init__ 函数 + # + # 生成: define void @SHA1.ClassName.__before_init__(Ptr(StructTy) %self) + # + # 执行: + # 1. store zeroinitializer 到 %self(零值填充) + # 2. 逐字段 store 默认值(如有) + # 3. ret void + # ============================================================ + def _generate_before_init(self, trans: HT.Translator | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr, + class_name: str) -> int: + """生成 __before_init__ 函数,返回 0""" + if trans is None or struct_ty is None or class_name is None: + return 0 + + import lib.core.Handles.HandlesFunctions as HandlesFunctions + import lib.core.Handles.HandlesVar as HandlesVar + import lib.core.Handles.HandlesExpr as HandlesExpr + import lib.core.Handles.HandlesExprCall as HandlesExprCall + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + funcs_ptr: GenTypes.FuncEntry | t.CPtr = trans._funcs + func_count: int = trans._func_count + + self_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) + void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + + # 构建函数名: ClassName.__before_init__ + full_name_buf: str = pool.alloc(128) + if full_name_buf is None: + return 0 + viperlib.snprintf(full_name_buf, 128, "%s.__before_init__", class_name) + full_name: str = full_name_buf + + mangled_name: str = self.Gen.FuncGenBase._mangle_name(trans, full_name) + + # 创建函数 + func: llvmlite.Function | t.CPtr = llvmlite.create_function( + pool, mod, mangled_name, void_ty) + if func is None: + return 0 + + # 注册到函数表 + max_funcs: int = 1024 + rc_add: int = self.Gen.CallGenLeafKit.add_func_to_table(funcs_ptr, func_count, full_name, func, max_funcs, None, 0, 0, pool) + if rc_add == 0: + trans._func_count = func_count + 1 + + # 添加 self 参数 + llvmlite.add_param(pool, func, self_ptr_ty, "%self") + + # 参数添加完成,补全全局函数表的 TypeStr + rc_ut: int = self.Gen.CallGenLeafKit.update_global_func_typestr(pool, full_name, func) + + # 创建 entry 块 + builder + entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") + if entry_blk is None: + return 0 + func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) + if func_builder is None: + return 0 + llvmlite.position_at_end(func_builder, entry_blk) + + # 注册 self 为 SSA 值 + self_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, self_ptr_ty, "%self") + + # 1. 零值填充: store zeroinitializer, Ptr(struct_ty)* %self + # 空 struct({})在 LLVM 中不允许 zeroinitializer(invalid type for null constant), + # 无字段类(接口/标记类,如多继承的 Vec2Extra)跳过零值填充; + # @t.CVTable 类必有 vtable 指针字段(非空),不受影响。 + struct_fcount_zi: int = llvmlite.get_struct_fcount(struct_ty) + if struct_fcount_zi > 0: + zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) + if zero is not None: + llvmlite.build_store(func_builder, zero, self_val) + + # 1.5 如果有虚表,store vtable 全局地址到 __vtable__ 字段(索引 0) + # 用 find_struct_by_type 定位 entry,规避跨模块同名 find_struct 找错 + bi_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_type(struct_ty) + bi_has_vt: int = 0 + if bi_entry is not None: + bi_has_vt = bi_entry.HasVTable + if bi_has_vt == 1: + vt_method_count: int = 0 + if bi_entry is not None: + vt_method_count = bi_entry.VTableMethodCount + if vt_method_count > 0: + # 构造 vtable 类型 { i8*, i8*, ..., i8* } + vt_i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + vt_i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, vt_i8_ty) + + vt_first_node: llvmlite.ParamNode | t.CPtr = None + vt_prev_node: llvmlite.ParamNode | t.CPtr = None + for vti in range(vt_method_count): + vtnode: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, vt_i8_ptr_ty) + if vtnode is None: + continue + if vt_first_node is None: + vt_first_node = vtnode + if vt_prev_node is not None: + llvmlite.paramnode_set_next(vt_prev_node, vtnode) + vt_prev_node = vtnode + + vt_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, vt_first_node, vt_method_count, None) + vt_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, vt_ty) + + # 构造 vtable 全局变量名 + vt_name_buf: str = pool.alloc(128) + if vt_name_buf is not None: + viperlib.snprintf(vt_name_buf, 128, "%s.vtable", class_name) + vt_full_name: str = vt_name_buf + vt_mangled: str = self.Gen.FuncGenBase._mangle_name(trans, vt_full_name) + + # GEP 到 __vtable__ 字段(索引 0) + vt_slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + func_builder, struct_ty, vt_i8_ptr_ty, self_val, 0) + if vt_slot is not None: + # 创建全局变量引用 Value + vt_ref: llvmlite.Value | t.CPtr = llvmlite.new_value(pool) + if vt_ref is not None: + llvmlite.value_set_ty(vt_ref, vt_ptr_ty) + llvmlite.value_set_isconst(vt_ref, 1) + # Name 格式: @"mangled" 或 @mangled + vt_ref_name: str = pool.alloc(256) + if vt_ref_name is not None: + vt_ref_name[0] = '\0' + if self._vtable_name_needs_quote(vt_mangled) != 0: + viperlib.snprintf(vt_ref_name, 256, "@\"%s\"", vt_mangled) + else: + viperlib.snprintf(vt_ref_name, 256, "@%s", vt_mangled) + llvmlite.value_set_name(vt_ref, vt_ref_name) + + # bitcast 到 i8* + vt_as_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + func_builder, vt_ref, vt_i8_ptr_ty) + if vt_as_i8 is not None: + llvmlite.build_store(func_builder, vt_as_i8, vt_slot) + + # 2. 逐字段 store 默认值(用 bi_entry 直接访问,规避跨模块同名 find_struct 找错) + if bi_entry is not None: + for fi in range(bi_entry.FieldCount): + fe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry( + bi_entry, fi) + if fe is None or fe.DefaultVal is None: + continue + # 静态数组字段 + 列表字面量默认值 → 整体置零 + 逐元素 GEP+store + # (与局部 AnnAssign 数组初始化一致;translate_value 会把列表字面量 + # 误译成动态 list 对象指针,coerce 到 [N x elem] 会失败)。 + # 单参 CArray 字段(如 t.CArray[str] = ["py", ...])经类体字段收集 + # 推断为静态数组,此处保证 __before_init__ 填充真实字符串指针。 + if fe.Ty is not None and self.Gen.ExprGenBase.is_array_type(fe.Ty) != 0 \ + and fe.DefaultVal.kind() == ast.ASTKind.List: + field_ptr_arr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + func_builder, struct_ty, fe.Ty, self_val, fe.Index) + if field_ptr_arr is not None: + zero_arr_f: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, fe.Ty) + if zero_arr_f is not None: + llvmlite.build_store(func_builder, zero_arr_f, field_ptr_arr) + # Mixin 静态绑定:self._xxx 只沿本类查找,跨 Mixin 方法 + # (AssignGenMixin._init_global_array_from_list)会生成不存在 + # 符号 → 必须走 HandlesAnnAssign 模块级委托(延迟 import Gen)。 + self.Gen.AssignGen._init_global_array_from_list( + func_builder, pool, mod, field_ptr_arr, fe.DefaultVal, trans) + continue + # 翻译默认值表达式 + default_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + func_builder, pool, mod, fe.DefaultVal, None, 0, trans) + if default_val is None: + continue + # GEP 到字段 + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + func_builder, struct_ty, fe.Ty, self_val, fe.Index) + if field_ptr is None: + continue + # 类型转换并 store + default_val = self.Gen.ExprGenBase.coerce_to_type(func_builder, default_val, fe.Ty, fe.DefaultVal) + llvmlite.build_store(func_builder, default_val, field_ptr) + + # 3. ret void + llvmlite.build_ret_void(func_builder) + return 0 \ No newline at end of file diff --git a/App/lib/core/Gen/ExprGenAttr.vp b/App/lib/core/Gen/ExprGenAttr.vp index 6490b79..d2e1561 100644 --- a/App/lib/core/Gen/ExprGenAttr.vp +++ b/App/lib/core/Gen/ExprGenAttr.vp @@ -1,1204 +1,1195 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import viperlib -import w32.fileio as fileio -import lib.core.CompilerFactory as CompilerFactory -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.Handles.HandlesFunctions as HandlesFunctions -import lib.core.StubMerger as StubMerger -import lib.core.StubMergerStore as StubMergerStore -import lib.core.VLogger as VLogger -import lib.Projectrans.Config as Config -import lib.Projectrans.Utils as Utils - - -import lib.core.Gen.ExprGenBase as ExprGenBase -import lib.core.Handles.ExprCallCtor as ExprCallCtor - -# ============================================================ -# ExprGenAttr - ExprGenMixin 拆分(阶段 D):Attribute/属性访问/全局引用 -# -# 继承 ExprGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class ExprGenAttr(ExprGenBase.ExprGenBase): - """Attribute/属性访问/全局引用""" - - # ============================================================ - # find_global_in_module - 在模块全局变量链表中按名称查找 - # - # 查找策略: - # 1. 精确匹配 (如 "_mbuddy" 匹配 @_mbuddy) - # 2. 后缀匹配 (如 "_mbuddy" 匹配 @"sha1._mbuddy") - # ============================================================ - def find_global_in_module(self, mod: llvmlite.LLVMModule | t.CPtr, - name: str) -> llvmlite.GlobalVariable | t.CPtr: - """在模块全局变量链表中按名称查找全局变量""" - if mod is None or name is None: - return None - name_len: t.CSizeT = string.strlen(name) - cur: llvmlite.GlobalVariable | t.CPtr = mod.GlobalHead - # 第一遍: 精确匹配 - while cur is not None: - if cur.Name is not None: - if string.strcmp(cur.Name, name) == 0: - return cur - cur = cur.Next - # 第二遍: 后缀匹配 (.name) - cur = mod.GlobalHead - while cur is not None: - if cur.Name is not None: - cur_len: t.CSizeT = string.strlen(cur.Name) - if cur_len > name_len + 1: - suffix_start: t.CSizeT = cur_len - name_len - if cur.Name[suffix_start - 1] == '.': - match: int = 1 - for i in range(name_len): - if cur.Name[suffix_start + i] != name[i]: - match = 0 - break - if match == 1: - return cur - cur = cur.Next - return None - # ============================================================ - # make_global_ref - 创建全局变量引用 (@name,类型为 ty*) - # - # 用于跨模块全局变量访问: stub 未注入时,翻译阶段生成 @name 引用, - # 链接时由 stub 提供 external global 声明。 - # ============================================================ - def make_global_ref(self, pool: memhub.MemBuddy | t.CPtr, - name: str, - ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: - """创建全局变量引用 (类型为 ty*,名称为 @name)""" - if name is None or ty is None: - return None - ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, ty) - ref_name: str = pool.alloc(96) - if ref_name is None: - return None - # LLVM 无引号标识符不能以数字开头:带 SHA1 前缀的全局名("sha1.name") - # 必命中 needs_quote(数字开头 + '.'),引用必须加引号 @\"sha1.name\", - # 否则 llc "expected instruction opcode"。对齐函数引用路径 - # (ExprGenName L252-255 的 needs_quote 判断)。 - if HandlesClassDef._vtable_name_needs_quote(name) != 0: - viperlib.snprintf(ref_name, 96, "@\"%s\"", name) - else: - viperlib.snprintf(ref_name, 96, "@%s", name) - return llvmlite.SSAValue(pool, ptr_ty, ref_name) - # ============================================================ - # _resolve_module_attribute_global - 解析模块属性访问的全局变量引用 - # - # 当 obj 是已导入模块名 (如 sys._mbuddy) 时: - # 1. 在当前模块全局变量链表中查找 (stub 已注入的情况) - # 2. 未找到则创建前向引用 (@attr_name, 类型为 ty 参数) - # - # 参数: - # ty_hint: 类型提示 (写路径用 rhs 类型, 读路径用 i8* 回退) - # 返回: Value 指针 (类型为 ty*),未识别为模块属性返回 None - # ============================================================ - def _is_t_type_object_name(self, name: str) -> int: - """检查 name 是否是 t.py 中的类型对象名(CPtr/CInt/CDouble 等) - - 这些类型对象在运行时作为全局变量 @CPtr/@CInt 等被引用, - 但 t.py 不被编译,需要在使用处生成带 null 初值的定义。 - """ - if name is None: - return 0 - # t.py 中的类型对象名(PascalCase,首字母大写) - if string.strcmp(name, "CPtr") == 0: - return 1 - if string.strcmp(name, "CInt") == 0: - return 1 - if string.strcmp(name, "CChar") == 0: - return 1 - if string.strcmp(name, "CShort") == 0: - return 1 - if string.strcmp(name, "CLong") == 0: - return 1 - if string.strcmp(name, "CLongLong") == 0: - return 1 - if string.strcmp(name, "CDouble") == 0: - return 1 - if string.strcmp(name, "CFloat") == 0: - return 1 - if string.strcmp(name, "CBool") == 0: - return 1 - if string.strcmp(name, "CVoid") == 0: - return 1 - if string.strcmp(name, "CInt8T") == 0: - return 1 - if string.strcmp(name, "CInt16T") == 0: - return 1 - if string.strcmp(name, "CInt32T") == 0: - return 1 - if string.strcmp(name, "CInt64T") == 0: - return 1 - if string.strcmp(name, "CUInt8T") == 0: - return 1 - if string.strcmp(name, "CUInt16T") == 0: - return 1 - if string.strcmp(name, "CUInt32T") == 0: - return 1 - if string.strcmp(name, "CUInt64T") == 0: - return 1 - if string.strcmp(name, "CUnsigned") == 0: - return 1 - if string.strcmp(name, "CUnsignedInt") == 0: - return 1 - if string.strcmp(name, "CUnsignedChar") == 0: - return 1 - if string.strcmp(name, "CUnsignedShort") == 0: - return 1 - if string.strcmp(name, "CUnsignedLong") == 0: - return 1 - if string.strcmp(name, "CUnsignedLongLong") == 0: - return 1 - if string.strcmp(name, "CSizeT") == 0: - return 1 - if string.strcmp(name, "CIntPtrT") == 0: - return 1 - if string.strcmp(name, "CUIntPtrT") == 0: - return 1 - if string.strcmp(name, "CPtrDiffT") == 0: - return 1 - if string.strcmp(name, "CType") == 0: - return 1 - if string.strcmp(name, "CDefine") == 0: - return 1 - if string.strcmp(name, "CStatic") == 0: - return 1 - if string.strcmp(name, "CExport") == 0: - return 1 - if string.strcmp(name, "CArray") == 0: - return 1 - if string.strcmp(name, "CTypedef") == 0: - return 1 - if string.strcmp(name, "CNoVTable") == 0: - return 1 - if string.strcmp(name, "CNeedPtr") == 0: - return 1 - if string.strcmp(name, "CAutoPtr") == 0: - return 1 - return 0 - def _attr_module_path_str(self, pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr) -> str: - """把模块引用 AST 转成模块路径字符串(递归拼接 Attribute 链): - Name('sys') → "sys";Attribute(Attribute(Name('os'),'_win32')) → "os._win32"。 - 非模块引用形态(Call/Subscript 等)返回 None。""" - if node is None: - return None - k: int = node.kind() - if k == ast.ASTKind.Name: - nm_m: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm_m.id is not None: - return nm_m.id - return None - if k == ast.ASTKind.Attribute: - at_m: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at_m.attr is None: - return None - base_m: str = self._attr_module_path_str(pool, at_m.value) - if base_m is None: - return None - blen: t.CSizeT = string.strlen(base_m) - alen: t.CSizeT = string.strlen(at_m.attr) - buf_m: str = pool.alloc(blen + alen + 2) - if buf_m is None: - return None - viperlib.snprintf(buf_m, blen + alen + 2, "%s.%s", base_m, at_m.attr) - return buf_m - return None - def _resolve_module_attribute_global(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - trans: HT.Translator | t.CPtr, - at: ast.Attribute | t.CPtr, - ty_hint: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: - """解析模块属性访问,返回全局变量引用 (用于跨模块 global 访问)""" - if at is None or at.value is None or at.attr is None: - return None - if trans is None or trans._imported_modules is None: - return None - # 提取模块路径名:Name → "sys";嵌套 Attribute → "os._win32" - # (此前只支持 Name 模块;SysLibTest main.vp L32 `os._win32._mbuddy = v` - # 的 at.value 是 Attribute → 被跳过 → "属性写入失败" 根因) - mod_path_w: str = self._attr_module_path_str(pool, at.value) - if mod_path_w is None: - return None - # 别名解析:import lib.core.Gen.Generator as GenGenerator → 查 from_imports - # 得原始模块名。否则 _lookup_module_sha1("GenGenerator") 查不到(Sha1Store - # 用原始模块名)→ 退化裸名 → 全局带 SHA1 前缀后 undefined symbol。 - # 别名属性访问(GenGenerator._g_gen = gen)依赖此解析才能命中目标模块定义。 - # 注意:lookup_from_import 返回指针非 NUL 结尾,须截断到空格/冒号/NUL - # 再查 SHA1(否则整串 "lib.core.Gen.Generator Config:lib... " 查不到)。 - if trans._from_imports is not None: - orig_mw: str = HandlesImports.lookup_from_import( - trans._from_imports, mod_path_w, 0) - if orig_mw is not None: - oml_a: t.CSizeT = 0 - while orig_mw[oml_a] != ' ' and orig_mw[oml_a] != '\0' and orig_mw[oml_a] != ':': - oml_a += 1 - if oml_a > 0: - om_buf_a: str = pool.alloc(oml_a + 1) - if om_buf_a is not None: - string.strncpy(om_buf_a, orig_mw, oml_a) - om_buf_a[oml_a] = '\0' - mod_path_w = om_buf_a - # 检查是否是已导入模块 - if HandlesImports.is_module_imported(trans._imported_modules, mod_path_w) == 0: - return None - # 在当前模块查找全局变量:优先按"目标模块 SHA1 前缀 + 属性名"精确匹配, - # 避免多模块同名全局(@._mbuddy / @._mbuddy 同时注入)时裸名后缀 - # 匹配返回错误模块的全局(串扰)。目标 sha1 未知时退化裸名(后缀匹配兜底) - gv_q: str = HandlesFunctions._mangle_name_with_sha1( - self._lookup_module_sha1(mod_path_w), at.attr) - gv: llvmlite.GlobalVariable | t.CPtr = self.find_global_in_module(mod, gv_q) - if gv is not None and gv.Ty is not None: - # 用 gv.Name(完整名,带 SHA1 前缀时与定义端一致)构造引用, - # 避免裸名 @_mbuddy 在多模块各自带前缀定义下 undefined symbol - return self.make_global_ref(pool, gv.Name, gv.Ty) - # 未找到: 创建 external global 声明并添加到模块 - # 否则只生成 @_argc 引用而无声明,LLVM 报 "use of undefined value '@_argc'" - use_ty: llvmlite.LLVMType | t.CPtr = ty_hint - if use_ty is None: - use_ty = llvmlite.Int8(pool) - # 确保 use_ty 中的跨模块结构体类型有 opaque 声明 - llvmlite.module_ensure_opaque_for_type(mod, pool, use_ty) - # 特殊处理: t.py 中的类型对象(CPtr/CInt/CDouble 等) - # t.py 不被编译,但这些类型对象在运行时被引用(如 va_arg(ap, t.CPtr))。 - # 创建带 null 初值的 linkonce_odr 全局变量定义,避免链接时 undefined reference。 - # LLVM 22+ 不允许 external linkage 全局变量带初值,使用 linkonce_odr 替代。 - is_t_type_obj: int = 0 - if string.strcmp(mod_path_w, "t") == 0: - is_t_type_obj = self._is_t_type_object_name(at.attr) - # 兜底声明名:t 类型对象(t.py 不编译、无 sha1)保持裸名 linkonce_odr; - # 其他模块属性带目标模块 SHA1 前缀(对齐定义端 mangling,跨模块同名 - # 全局独立命名,消除 duplicate symbol / 串扰) - gv_name_ba: str = at.attr - if is_t_type_obj == 0: - gv_name_ba = HandlesFunctions._mangle_name_with_sha1( - self._lookup_module_sha1(mod_path_w), at.attr) - ext_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, gv_name_ba, use_ty) - if ext_gv is not None: - if is_t_type_obj != 0: - # t.CPtr 等类型对象: 创建带 null 初值的定义(linkonce_odr) - ext_gv.Linkage = "linkonce_odr" - # i8* null 的初值文本 - null_init: bytes = pool.alloc(8) - if null_init is not None: - null_init[0] = 'n' - null_init[1] = 'u' - null_init[2] = 'l' - null_init[3] = 'l' - null_init[4] = '\0' - ext_gv.Initializer = null_init - else: - ext_gv.Initializer = None - else: - # 普通模块属性: external 声明(由其他模块提供定义) - ext_gv.Linkage = "external" - ext_gv.Initializer = None - llvmlite.module_add_global(mod, ext_gv) - return self.make_global_ref(pool, gv_name_ba, use_ty) - def _lookup_module_sha1(self, mod_name: str) -> str: - """查找模块名对应的 SHA1(委托 StubMergerStore,支持包名回退; - None=未找到,调用方退化为裸名)""" - return StubMergerStore.LookupSha1ByModName(mod_name) - # ============================================================ - # 翻译属性访问 Attribute(value, attr, ctx) — obj.field - # - # 优先级: - # 1. 枚举成员访问 (State.Idle → 常量值) - # 2. 模块属性访问 (sys._mbuddy → 加载全局变量) - # 3. 结构体字段访问 (obj.field → GEP + load) - # - # 对于 Name 类型的 obj,直接使用 alloca 指针(不 load 结构体) - # ============================================================ - - - # ============================================================ - # _get_cderef_attr_base - c.Deref(ptr).attr 属性访问的 base 指针 - # - # c.Deref(ptr) 作为属性访问 base 时(如 c.Deref(p).a),需要 ptr - # 指针本身而非 load 后的结构体值(*p.a → p->a),与 TPC - # _handle_attr_call_result 语义一致。否则 c.Deref 返回结构体值, - # 后续 GEP 在非指针上做属性访问会误报"base=非指针类型"。 - # - # 返回: - # ptr 指针值(Ptr(Struct) 或 Ptr(Ptr(Struct)),交由 _deref_if_ptr_ptr 解层级) - # 非 c.Deref 模式返回 None - # ============================================================ - def _get_cderef_attr_base(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - at_value: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """检测 at.value 是否为 c.Deref(ptr) 调用,返回 ptr 指针(不做 load)""" - if at_value is None or at_value.kind() != ast.ASTKind.Call: - return None - cl_cd: ast.Call | t.CPtr = (ast.Call | t.CPtr)(at_value) - if cl_cd.func is None or cl_cd.func.kind() != ast.ASTKind.Attribute: - return None - f_cd: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl_cd.func) - if f_cd.attr is None or string.strcmp(f_cd.attr, "Deref") != 0: - return None - if f_cd.value is None or f_cd.value.kind() != ast.ASTKind.Name: - return None - nm_cd: ast.Name | t.CPtr = (ast.Name | t.CPtr)(f_cd.value) - if nm_cd.id is None or string.strcmp(nm_cd.id, "c") != 0: - return None - if cl_cd.args is None or len(cl_cd.args) < 1: - return None - inner_cd: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cl_cd.args.get(0), None, 0, trans) - if inner_cd is not None and self.is_ptr_type(inner_cd.Ty) != 0: - return inner_cd - return None - def translate_attribute(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译属性访问,返回加载的字段值""" - if node is None or builder is None: - return None - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at is None or at.value is None or at.attr is None: - # fast-fail: AST 节点字段缺失属解析器 bug,应报告具体缺失字段 - diag_buf_an: bytes = stdlib.malloc(256) - if diag_buf_an is not None: - missing_an: str = "?" - if at is not None: - if at.value is None: - missing_an = "value" - elif at.attr is None: - missing_an = "attr" - viperlib.snprintf(diag_buf_an, 256, - "属性访问失败: AST 节点字段缺失 (%s sha1=%s:%d)", - missing_an, - trans.ModuleSha1 if trans is not None and trans.ModuleSha1 is not None else "?", - at.lineno if at is not None and at.lineno is not None else 0) - VLogger.error(diag_buf_an, "ATTR") - return None - - # 魔法属性 __doc__:查询 docstring 登记表(预注册阶段从 AST 提取), - # 命中则当前模块内联生成字符串常量返回;未命中(无 docstring 的 - # 函数/类/方法)返回 null 指针(i8*)。支持本模块与跨模块符号: - # local_func / LocalClass / LocalClass.method / remote.remote_func / - # remote.RemoteClass / remote.RemoteClass.remote_method - if string.strcmp(at.attr, "__doc__") == 0: - doc_mod_buf: bytes = pool.alloc(64) - doc_sym_buf: bytes = pool.alloc(256) - if doc_mod_buf is None or doc_sym_buf is None: - return None - doc_mod_buf[0] = '\0' - doc_sym_buf[0] = '\0' - if at.value is not None and at.value.kind() == ast.ASTKind.Name: - nm_doc: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm_doc.id is not None: - HandlesExpr._resolve_doc_symbol_name(trans, nm_doc.id, doc_mod_buf, doc_sym_buf) - elif at.value is not None and at.value.kind() == ast.ASTKind.Attribute: - HandlesExpr._resolve_doc_symbol_attr(trans, (ast.Attribute | t.CPtr)(at.value), doc_mod_buf, doc_sym_buf) - doc_val: str = None - if doc_mod_buf[0] != '\0' and doc_sym_buf[0] != '\0': - doc_val = HandlesExpr.lookup_docstring(doc_mod_buf, doc_sym_buf) - if doc_val is None: - i8_ty_doc: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - if i8_ty_doc is None: - return None - i8_ptr_ty_doc: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_doc) - if i8_ptr_ty_doc is None: - return None - return llvmlite.ConstNull(pool, i8_ptr_ty_doc, "null") - return HandlesExpr.create_global_string(builder, pool, mod, doc_val, trans) - - # 枚举成员访问: EnumName.MemberName → 常量值 - # 当 value 是 Name 且 Name.id 是已注册枚举时,查找成员并返回常量 - if at.value.kind() == ast.ASTKind.Name: - enum_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if enum_nm.id is not None: - if HandlesEnum.is_enum_class(enum_nm.id) == 1: - member: HandlesEnum.EnumMember | t.CPtr = HandlesEnum.lookup_enum_member( - enum_nm.id, at.attr) - if member is not None: - base_ty: llvmlite.LLVMType | t.CPtr = HandlesEnum.get_enum_base_type( - enum_nm.id) - if base_ty is not None: - # 生成数字字符串作为常量名(LLVM IR 要求常量输出数字值) - name_buf: str = pool.alloc(32) - if name_buf is not None: - viperlib.snprintf(name_buf, 32, "%lld", member.Value) - return llvmlite.ConstInt(pool, base_ty, member.Value, name_buf) - return llvmlite.const_int32(pool, member.Value) - # fast-fail: 枚举成员未找到 - VLogger.error( - f"枚举成员未找到: {enum_nm.id}.{at.attr}", - "ATTR") - return None - - # 嵌套枚举成员访问: Module.EnumName.MemberName → 常量值 - # 当 value 是 Attribute(如 fileio.MODE / w32.fileio.MODE,含三级以上 - # 模块路径)且 attr 部分是已注册枚举时。此前限制 inner_at_e.value 必须是 - # Name(仅支持两层 Module.EnumName),w32.fileio.MODE.W(三层,value 是 - # Attribute)被跳过 → "属性访问失败: .W"(SysLibTest L190 根因)。 - # 枚举类名只取最内层 attr(MODE),模块路径形态不影响。 - if at.value.kind() == ast.ASTKind.Attribute: - inner_at_e: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(at.value) - if inner_at_e.attr is not None: - if HandlesEnum.is_enum_class(inner_at_e.attr) == 1: - member_e: HandlesEnum.EnumMember | t.CPtr = HandlesEnum.lookup_enum_member( - inner_at_e.attr, at.attr) - if member_e is not None: - base_ty_e: llvmlite.LLVMType | t.CPtr = HandlesEnum.get_enum_base_type( - inner_at_e.attr) - if base_ty_e is not None: - name_buf_e: str = pool.alloc(32) - if name_buf_e is not None: - viperlib.snprintf(name_buf_e, 32, "%lld", member_e.Value) - return llvmlite.ConstInt(pool, base_ty_e, member_e.Value, name_buf_e) - return llvmlite.const_int32(pool, member_e.Value) - # fast-fail: 嵌套枚举成员未找到 - dbg_ee: HandlesEnum.EnumEntry | t.CPtr = HandlesEnum.find_enum( - inner_at_e.attr) - dbg_mc: int = -1 - if dbg_ee is not None: - dbg_mc = dbg_ee.MemberCount - VLogger.error( - f"嵌套枚举成员未找到: {inner_at_e.attr}.{at.attr} " - f"(enum_members={dbg_mc})", "ATTR") - return None - - # FakeDuck: 影子结构体属性读取 (str 变量的 per-instance 字段) - # a.__data__ / a.__mbuddy__ → GEP {a}__meta__[field] 并加载 - # 对齐 TPC HandlesExprAttr.py L433-442:对象是 Name 变量且存在 - # {var}__meta__ 影子(fd2 创建)时,属性访问改走影子结构体。 - if at.value.kind() == ast.ASTKind.Name and trans is not None: - fd_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if fd_nm.id is not None: - # pool 持久缓冲(f-string 栈缓冲在函数返回后失效) - fd_meta_buf: str = pool.alloc(256) - if fd_meta_buf is not None: - viperlib.snprintf(fd_meta_buf, 256, "%s__meta__", fd_nm.id) - fd_meta_v: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( - trans.SymTab, fd_meta_buf) - if fd_meta_v is not None: - fd_sty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type( - "_str") - if fd_sty is not None: - fd_fe: HandlesStruct.FieldEntry | t.CPtr = \ - HandlesStruct.lookup_field(fd_sty, at.attr) - if fd_fe is not None and fd_fe.Ty is not None: - fd_fp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, fd_sty, fd_fe.Ty, fd_meta_v, fd_fe.Index) - if fd_fp is not None: - return llvmlite.build_load(builder, fd_fe.Ty, fd_fp) - - # 模块属性访问 (读路径): sys._mbuddy → 加载全局变量 @_mbuddy - # 当 obj 是已导入模块名且不是普通变量时,查找/创建全局变量引用并加载 - if at.value.kind() == ast.ASTKind.Name and trans is not None: - nm_ma: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm_ma.id is not None: - # 先检查是否是普通变量 (优先级高于模块属性) - ma_is_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, nm_ma.id) - if ma_is_var is None: - # 先检查是否是 CDefine 编译期常量 (如 ast.CONST_INT / win32base.INVALID_HANDLE_VALUE) - # 模块属性访问的 CDefine 常量需要跨模块查找源 .vp / .vpi 文件 - cdef_ma_val: t.CInt64T = HandlesType.lookup_cdefine_constant(at.attr) - cd_local: int = HandlesType.is_cdefine_found() - if cd_local == 0: - # 确定真实模块名:优先从 _from_imports 解析别名 - # from_imports 中条目格式 "local_name:real_module" - # 如 win32base:w32.win32base → 别名 win32base 真实模块 w32.win32base - real_mod_name: str = nm_ma.id - if trans._from_imports is not None: - resolved_mod: str = HandlesImports.lookup_from_import( - trans._from_imports, nm_ma.id, 0) - if resolved_mod is not None: - # 复制模块名到新缓冲区(截断于空格、null、或 ':') - rm_len: t.CSizeT = 0 - while resolved_mod[rm_len] != ' ' and resolved_mod[rm_len] != '\0' and resolved_mod[rm_len] != ':': - rm_len += 1 - rm_buf: str = pool.alloc(rm_len + 1) - if rm_buf is not None: - for rm_i in range(rm_len): - rm_buf[rm_i] = resolved_mod[rm_i] - rm_buf[rm_len] = '\0' - real_mod_name = rm_buf - # 即使 _from_imports 为 None(如纯 `import ast` 无 from-import), - # 也必须尝试跨模块 CDefine 查找,否则 ast.CONST_INT 会被 - # 误解析为全局变量引用 @CONST_INT(未定义符号)。 - # 构建临时 from_imports "{attr}:{real_module}" 用于跨模块查找 - if real_mod_name is not None: - ma_fi_len: t.CSizeT = string.strlen(at.attr) + string.strlen(real_mod_name) + 2 - ma_fi: str = pool.alloc(ma_fi_len) - if ma_fi is not None: - viperlib.snprintf(ma_fi, ma_fi_len, "%s:%s", at.attr, real_mod_name) - cdef_ma_val = HandlesExpr._lookup_cross_module_cdefine(pool, at.attr, ma_fi) - if HandlesType.is_cdefine_found() != 0: - # 跨模块字符串 CDefine(如 pyzlib.ZLIB_VERSION = "1.3.2")→ - # 字符串全局常量(test_pyzlib.vp L49 ver = pyzlib.ZLIB_VERSION) - if HandlesType.is_cdefine_str() != 0: - cdef_str_v: str = HandlesType.lookup_cdefine_string(at.attr) - if cdef_str_v is not None: - return HandlesExpr.create_global_string( - builder, pool, mod, cdef_str_v, trans) - # 跨模块浮点 CDefine(如 vipermath.U_M_PI)→ 浮点常量 - dchk_ma: double = HandlesType.lookup_cdefine_double(at.attr) - if HandlesType.is_cdefine_double() != 0: - return llvmlite.ConstFloat(pool, llvmlite.Double(pool), dchk_ma) - return HandlesExpr._const_int_for_cdefine(pool, cdef_ma_val) - # 检查 nm_ma.id.at.attr 是否是已导入子模块 (如 w32.win32file) - # 如果是子模块,不应创建全局变量,让嵌套属性访问路径处理 - is_submod: int = 0 - if trans._imported_modules is not None: - submod_len: t.CSizeT = string.strlen(nm_ma.id) + string.strlen(at.attr) + 2 - submod_buf: str = pool.alloc(submod_len) - if submod_buf is not None: - viperlib.snprintf(submod_buf, submod_len, "%s.%s", nm_ma.id, at.attr) - if HandlesImports.is_module_imported(trans._imported_modules, submod_buf) == 1: - is_submod = 1 - # also check from_imports: at.attr 别名对应真实模块 w32.win32file - if is_submod == 0 and trans._from_imports is not None: - fi_mod_raw: str = HandlesImports.lookup_from_import( - trans._from_imports, at.attr, 0) - if fi_mod_raw is not None: - # 复制模块名到新缓冲区(截断于空格、null、或 ':') - fm_len: t.CSizeT = 0 - while fi_mod_raw[fm_len] != ' ' and fi_mod_raw[fm_len] != '\0' and fi_mod_raw[fm_len] != ':': - fm_len += 1 - fi_mod: str = pool.alloc(fm_len + 1) - if fi_mod is not None: - for fm_i in range(fm_len): - fi_mod[fm_i] = fi_mod_raw[fm_i] - fi_mod[fm_len] = '\0' - # 检查 fi_mod 是否以 "nm_ma.id." 开头 (如 w32.win32file 以 w32. 开头) - prefix_len: t.CSizeT = string.strlen(nm_ma.id) - fi_mod_len: t.CSizeT = string.strlen(fi_mod) - if fi_mod_len > prefix_len + 1: - match_prefix: int = 1 - for pi in range(prefix_len): - if fi_mod[pi] != nm_ma.id[pi]: - match_prefix = 0 - break - if match_prefix == 1 and fi_mod[prefix_len] == '.': - is_submod = 1 - if is_submod != 0: - return None # 是子模块,交给嵌套属性访问路径 - # 特殊处理: t.ASM_DESCR 不是 CDefine,是内联汇编约束命名空间 - # t.ASM_DESCR.XXX 由 HandlesExprCall 的 _asm_resolve_constraint 处理 - # 此处返回 None,让上层嵌套属性访问路径处理 - if string.strcmp(nm_ma.id, "t") == 0 and string.strcmp(at.attr, "ASM_DESCR") == 0: - return None - # ALL_CAPS 模块属性但非 CDefine:先检查模块是否定义了同名全局 - # 变量(如 Phase1.PYI_BUF_SIZE: t.CSizeT = 262144 是 i64 全局、 - # 非宏,语义同 C 的 extern size_t PYI_BUF_SIZE)→ 按跨模块全局 - # 引用加载。仅当全局变量也不存在时才 fail-fast(防 llc - # "use of undefined value")。 - if HandlesExpr._is_cdefine_name_pattern(at.attr) != 0: - if self.find_global_in_module(mod, at.attr) is None: - HandlesType.fatal_error( - at, - f"跨模块 CDefine 未找到: '{nm_ma.id}.{at.attr}'(CDefine cross-module lookup failed)", - "TypeError") - # 命中跨模块全局 → 落到下方跨模块全局加载路径 - # 非 CDefine: 使用 i8* 作为类型提示 (模块级变量通常存储指针) - i8_ptr_hint: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - mod_gv_ref: llvmlite.Value | t.CPtr = self._resolve_module_attribute_global( - pool, mod, trans, at, i8_ptr_hint) - if mod_gv_ref is not None and mod_gv_ref.Ty is not None: - load_ty_mod: llvmlite.LLVMType | t.CPtr = mod_gv_ref.Ty.Pointee - if load_ty_mod is not None: - # 模块级全局数组(如 zdef.zdeflate_len_base: CArray[T, N]): - # 按 C 语义衰减为基址返回(对齐 translate_name_value 局部 - # 数组分支 L3383-3388),load [N x T] 数组值无法作 GEP 基址。 - match load_ty_mod: - case llvmlite.LLVMType.Array(_, _): - return mod_gv_ref - case _: - pass - return llvmlite.build_load(builder, load_ty_mod, mod_gv_ref) - - # 嵌套模块属性访问 (w32.win32file.GENERIC_READ → 查找全局 @GENERIC_READ) - # 当 at.value 是 Attribute 且解析为已导入子模块时,查找 at.attr 作为全局常量 - if at.value.kind() == ast.ASTKind.Attribute and trans is not None: - inner_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(at.value) - if inner_at.value is not None and inner_at.value.kind() == ast.ASTKind.Name: - inner_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner_at.value) - if inner_nm.id is not None and inner_at.attr is not None: - if HandlesVar.lookup_var(trans.SymTab, inner_nm.id) is None: - # 构建限定模块名: "w32.win32file" - qual_len: t.CSizeT = string.strlen(inner_nm.id) + string.strlen(inner_at.attr) + 2 - qual_buf: str = pool.alloc(qual_len) - if qual_buf is not None: - viperlib.snprintf(qual_buf, qual_len, "%s.%s", inner_nm.id, inner_at.attr) - if HandlesImports.is_module_imported(trans._imported_modules, qual_buf) == 1: - # 查找全局变量 at.attr(带限定模块 SHA1 前缀精确匹配, - # 避免多模块同名全局后缀匹配串扰;sha1 未知退化裸名) - gv_nested_q: str = HandlesFunctions._mangle_name_with_sha1( - self._lookup_module_sha1(qual_buf), at.attr) - gv_nested: llvmlite.GlobalVariable | t.CPtr = self.find_global_in_module(mod, gv_nested_q) - if gv_nested is not None and gv_nested.Ty is not None: - gv_ref_nested: llvmlite.Value | t.CPtr = self.make_global_ref( - pool, gv_nested.Name, gv_nested.Ty) - if gv_ref_nested is not None and gv_ref_nested.Ty is not None: - load_ty_nested: llvmlite.LLVMType | t.CPtr = gv_ref_nested.Ty.Pointee - if load_ty_nested is not None: - return llvmlite.build_load(builder, load_ty_nested, gv_ref_nested) - # 未找到全局: 尝试 CDefine 常量查找 - # 对于 w32.win32base.INVALID_HANDLE_VALUE 等嵌套模块属性访问, - # 先从限定模块的 .vpi 文件中查找 CDefine 常量值并内联 - cdef_val_nested: t.CInt64T = HandlesType.lookup_cdefine_constant(at.attr) - if HandlesType.is_cdefine_found() == 0: - # 构建临时 from_imports "attr:module" 用于跨模块查找 - tmp_fi_len: t.CSizeT = string.strlen(at.attr) + string.strlen(qual_buf) + 2 - tmp_fi: str = pool.alloc(tmp_fi_len) - if tmp_fi is not None: - viperlib.snprintf(tmp_fi, tmp_fi_len, "%s:%s", at.attr, qual_buf) - cdef_val_nested = HandlesExpr._lookup_cross_module_cdefine(pool, at.attr, tmp_fi) - if HandlesType.is_cdefine_found() != 0: - # 跨模块浮点 CDefine → 浮点常量 - dchk_nst: double = HandlesType.lookup_cdefine_double(at.attr) - if HandlesType.is_cdefine_double() != 0: - return llvmlite.ConstFloat(pool, llvmlite.Double(pool), dchk_nst) - return HandlesExpr._const_int_for_cdefine(pool, cdef_val_nested) - # CDefine 未找到: fail-fast 终止编译(不再创建未定义的全局变量引用) - # 之前此处创建 @INVALID_HANDLE_VALUE 等前向引用,但全局未定义, - # 导致 llc 报 "use of undefined value" 错误。 - # 正确做法是报错终止,让开发者修复跨模块 CDefine 查找失败的根本原因。 - if HandlesExpr._is_cdefine_name_pattern(at.attr) != 0: - HandlesType.fatal_error( - at, - f"嵌套属性跨模块 CDefine 未找到: '{qual_buf}.{at.attr}'(CDefine cross-module lookup failed)", - "TypeError") - return None - - # 对于 Name 类型的 obj,直接查找 alloca(不 load 结构体); - # nonlocal 变量(提升函数内)从 env 读共享堆值,避免 lookup_var - # 跨函数引用外层 alloca(SSA 编号跨函数错乱崩溃) - obj_ptr: llvmlite.Value | t.CPtr = None - if at.value.kind() == ast.ASTKind.Name and trans is not None: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm.id is not None: - if HT.is_nonlocal_name(trans, nm.id) != 0: - raw_nl_a: llvmlite.Value | t.CPtr = HandlesNonlocal._load_raw_var_ptr( - trans, nm.id) - if raw_nl_a is not None: - nl_ty_a: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type( - trans, nm.id) - if nl_ty_a is not None: - # 对象即指针:Struct/Array 类型直接用堆地址(bitcast 后 - # 作为对象指针,不 load);指针类型(如 Ptr(Point))堆里 - # 存对象指针,需 load 出对象指针 - match nl_ty_a: - case llvmlite.LLVMType.Struct(_, _, _): - obj_ptr = llvmlite.build_bitcast( - builder, raw_nl_a, llvmlite.Ptr(pool, nl_ty_a)) - case llvmlite.LLVMType.Array(_, _): - obj_ptr = llvmlite.build_bitcast( - builder, raw_nl_a, llvmlite.Ptr(pool, nl_ty_a)) - case _: - nl_val_ptr_a: llvmlite.Value | t.CPtr = \ - llvmlite.build_bitcast( - builder, raw_nl_a, llvmlite.Ptr(pool, nl_ty_a)) - if nl_val_ptr_a is not None: - obj_ptr = llvmlite.build_load( - builder, nl_ty_a, nl_val_ptr_a) - else: - obj_ptr = HandlesVar.lookup_var(trans.SymTab, nm.id) - - # 非 Name 路径:翻译对象值(会 load) - if obj_ptr is None: - # c.Deref(ptr).attr: 属性访问 base 取指针本身而非 load 后的结构体值 - # (如 c.Deref(p).a 语义是 (*p).a,直接对 p 做 GEP) - cd_base_rd: llvmlite.Value | t.CPtr = self._get_cderef_attr_base( - builder, pool, mod, at.value, trans) - if cd_base_rd is not None: - obj_ptr = cd_base_rd - elif at.value.kind() == ast.ASTKind.Subscript: - # 下标基座属性访问(如 pts[0].x):list[T]/OOP __getitem__ 类走 - # translate_value(返回元素值/地址);普通结构体指针数组走 - # get_subscript_ptr(GEP 元素地址,避免结构体值 base=非指针 报错) - if self._sub_base_uses_getitem(pool, mod, trans, at.value) != 0: - obj_ptr = HandlesExpr.translate_value(builder, pool, mod, at.value, None, 0, trans) - else: - obj_ptr = HandlesExpr.get_subscript_ptr(builder, pool, mod, at.value, trans) - elif at.value.kind() == ast.ASTKind.Attribute: - # 嵌套属性基座(如 r.origin.x):取内层字段地址(get_attribute_ptr 递归, - # 地址语义),指针字段(X|t.CPtr)由 _deref_if_ptr_ptr load 解引用 - obj_ptr = self.get_attribute_ptr(builder, pool, mod, at.value, trans) - if obj_ptr is None: - obj_ptr = HandlesExpr.translate_value(builder, pool, mod, at.value, None, 0, trans) - else: - obj_ptr = HandlesExpr.translate_value(builder, pool, mod, at.value, None, 0, trans) - - if obj_ptr is None or obj_ptr.Ty is None: - return None - - # 如果 obj_ptr 是 Ptr(Ptr(Struct))(X|t.CPtr 变量的 alloca), - # load 解引用获取 Ptr(Struct) - obj_ptr = self._deref_if_ptr_ptr(builder, obj_ptr) - - # 查找结构体类型信息 - # obj_ptr 类型应该是 Ptr(Struct(...)) - match obj_ptr.Ty: - case llvmlite.LLVMType.Ptr(struct_ty): - # 确保跨模块结构体的完整定义在当前模块中可用(供 getelementptr 访问字段) - HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) - # 查找字段索引和类型 - field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( - struct_ty, at.attr) - # REnum 变体字段查找: lookup_field 失败时,尝试 REnum 别名 - # REnum 结构体字段名是 _p1/_p2/...,但源码用变体字段名访问(如 ty.Pointee) - if field_info is None: - renum_se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type( - struct_ty) - if renum_se is not None and renum_se.Name is not None: - is_rn: int = HandlesClassDef._is_renum_class_name(renum_se.Name) - if is_rn == 1: - alias_idx: int = HandlesClassDef._lookup_renum_field_alias( - renum_se.Name, at.attr) - if alias_idx >= 1: - alias_fe: HandlesStruct.FieldEntry | t.CPtr = \ - HandlesStruct._get_field_entry(renum_se, alias_idx) - if alias_fe is not None and alias_fe.Ty is not None: - alias_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, struct_ty, alias_fe.Ty, obj_ptr, alias_idx) - if alias_ptr is not None: - return llvmlite.build_load(builder, alias_fe.Ty, alias_ptr) - # property getter 回退: obj.attr 是 @property/@x.getter 方法时生成调用 - # (字段未找到时先尝试,避免报误导性的"字段未找到"错误) - if field_info is None and at.value is not None and trans is not None: - prop_cls_fb: str = HandlesStruct.get_class_name_by_type(pool, struct_ty) - prop_val: llvmlite.Value | t.CPtr = ExprCallCtor._try_property_getter_attr( - pool, builder, mod, at, obj_ptr, trans, prop_cls_fb) - if prop_val is not None: - return prop_val - # 按需过滤: struct_ty 为 i8(简化联合类型)时,通过 AnnotClassName 按类名查找 - # 传递 SHA1 以区分跨模块同名类 - # base 注解类名提取:Name → 变量注解类名;Attribute → 属性链递归字段注解类名 - if field_info is None: - base_class: str = None - if at.value.kind() == ast.ASTKind.Name and trans is not None: - nm_fb: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm_fb.id is not None: - var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm_fb.id) - if var_entry is not None: - base_class = var_entry.AnnotClassName - elif at.value.kind() == ast.ASTKind.Attribute: - base_class = self._resolve_attr_field_class(pool, trans, at.value) - if base_class is not None: - cur_sha1: str = trans.ModuleSha1 - field_info = HandlesStruct.lookup_field_by_class( - base_class, at.attr, cur_sha1) - # REnum 变体字段别名回退:base_class 是 REnum 类时,变体 - # 字段名(如 LLVMType.Pointee → _p2 槽位)不是普通字段, - # lookup_field_by_class 查不到(LLVMType"字段 Pointee 未找到" - # 根因;主路径 L4989-5004 的 REnum 别名查找因 struct_ty 简化 - # 为 i8、find_struct_by_type 失败被跳过) - if field_info is None \ - and HandlesClassDef._is_renum_class_name(base_class) != 0: - rn_alias: int = HandlesClassDef._lookup_renum_field_alias( - base_class, at.attr) - if rn_alias >= 1: - rn_se: HandlesStruct.StructEntry | t.CPtr = \ - HandlesStruct.find_struct(base_class) - if rn_se is not None: - rn_fe: HandlesStruct.FieldEntry | t.CPtr = \ - HandlesStruct._get_field_entry(rn_se, rn_alias) - if rn_fe is not None and rn_fe.Ty is not None: - field_info = rn_fe - # 按需过滤成功:bitcast obj_ptr 到 AnnotClassName 对应的结构体类型 - # 原始 struct_ty 可能是 i8(X|t.CPtr 简化为 Ptr(i8)), - # 需用实际结构体类型做 GEP,否则 GEP i8 失败 - if field_info is not None: - annot_se: HandlesStruct.StructEntry | t.CPtr = \ - HandlesStruct.find_struct(base_class) - if annot_se is not None and annot_se.Ty is not None: - annot_ptr_ty: llvmlite.LLVMType | t.CPtr = \ - llvmlite.Ptr(pool, annot_se.Ty) - casted_ptr: llvmlite.Value | t.CPtr = \ - llvmlite.build_bitcast(builder, obj_ptr, annot_ptr_ty) - if casted_ptr is not None: - obj_ptr = casted_ptr - struct_ty = annot_se.Ty - # 按需过滤更新 struct_ty 后,需重新确保 - # 注解类型结构体定义在当前模块可用 - # (原始 struct_ty 可能是 i8,ensure 无效) - HandlesStruct.ensure_struct_def_in_module( - pool, mod, annot_se.Ty) - if field_info is not None: - field_ty: llvmlite.LLVMType | t.CPtr = field_info.Ty - # 联合体:bitcast obj_ptr 到 field_ty* 后 load - if HandlesStruct.is_union_by_type(struct_ty) == 1: - field_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, field_ty) - casted: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, obj_ptr, field_ptr_ty) - if casted is not None: - return llvmlite.build_load(builder, field_ty, casted) - return None - # 普通结构体:GEP + load - field_idx: int = field_info.Index - field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, struct_ty, field_ty, obj_ptr, field_idx) - if field_ptr is not None: - # 数组类型字段不能 load 为 SSA value,直接返回字段指针 - # 用于后续下标访问: self.state[0] → GEP state 字段 → GEP 数组元素 - if self.is_array_type(field_ty) != 0: - return field_ptr - loaded_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, field_ty, field_ptr) - # 联合类型字段(如 Token | t.CPtr)被编译为 i8*, - # 若 AnnotClassName 指示了具体结构体类型,bitcast 为正确的结构体指针。 - # 注意:仅当字段类型本身是指针时才 bitcast(指针→指针); - # 内嵌结构体字段(field_ty=Struct)load 出的是结构体值, - # bitcast 值→指针是非法 IR(llc: invalid cast opcode)。 - if loaded_val is not None and field_info.AnnotClassName is not None \ - and self.is_ptr_type(field_ty) != 0: - annot_struct: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct( - field_info.AnnotClassName) - if annot_struct is not None and annot_struct.Ty is not None: - annot_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, annot_struct.Ty) - return llvmlite.build_bitcast(builder, loaded_val, annot_ptr_ty) - return loaded_val - # fast-fail: 字段未找到,立即终止编译(不再打印诊断后返回 None) - # Phase A 依赖未就绪(_deps_pending,父类/依赖类未注册致字段缺失): - # 跳过本属性访问交给下遍重译(对齐 get_attribute_ptr L5541-5547), - # 避免 fail-fast 中断多遍收敛;依赖就绪后仍缺失则走下方真实报错。 - if trans is not None and trans._deps_pending != 0: - return None - if trans is not None: - diag_annot: str = None - diag_var_nm: str = None - if at.value is not None and at.value.kind() == ast.ASTKind.Name: - dnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - diag_var_nm = dnm.id - if dnm.id is not None: - dve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, dnm.id) - if dve is not None: - diag_annot = dve.AnnotClassName - diag_var_txt: str = "?" - if diag_var_nm is not None: - diag_var_txt = diag_var_nm - diag_annot_txt: str = "None" - if diag_annot is not None: - diag_annot_txt = diag_annot - sha1_attr: str = "?" - if trans.ModuleSha1 is not None: - sha1_attr = trans.ModuleSha1 - HandlesType.fatal_error( - at, - f"属性访问失败: .{at.attr} (var={diag_var_txt} annot={diag_annot_txt} sha1={sha1_attr})", - "TypeError") - return None - case _: - # fast-fail: 对非指针类型做属性访问(如 i32.x), - # Python traceback 立即终止,不静默返回 None(否则下游 "store to None" 崩溃,丢失错误现场) - attr_nm_ap: str = "?" - if at is not None and at.attr is not None: - attr_nm_ap = at.attr - sha1_ap: str = "?" - if trans is not None and trans.ModuleSha1 is not None: - sha1_ap = trans.ModuleSha1 - ln_ap: int = 0 - if at is not None and at.lineno is not None: - ln_ap = at.lineno - HandlesType.fatal_error( - at, - f"属性访问失败: .{attr_nm_ap} (base=非指针类型,无法做属性访问 sha1={sha1_ap}:{ln_ap})", - "TypeError") - # fatal_error 后补显式 return 样板:match 末 arm 块必须 terminated, - # 否则掉出末尾被函数收尾 fail-fast 误判(块设计约定) - return None - # ============================================================ - # 获取属性访问的字段指针(不加载值,用于赋值) - # 对于 Name 类型的 obj,直接使用 alloca 指针(不 load 结构体) - # ============================================================ - def _resolve_attr_field_class(self, pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - attr_node: ast.AST | t.CPtr) -> str: - """解析属性链(a.b.c)中 c 字段的注解类名。 - - 联合类型字段(X | t.CPtr)被简化为 Ptr(i8),属性链写入时 - (如 lx.tokens_tail.next = tok)obj_ptr.Ty 是 Ptr(i8), - lookup_field(i8, ...) 必然失败。此函数沿属性链递归解析 - 最终字段的 AnnotClassName(如 tokens_tail → 'Token'), - 供按需过滤分支 bitcast 回真实结构体类型后 GEP。 - """ - if attr_node is None or trans is None: - return None - k: int = attr_node.kind() - if k != ast.ASTKind.Attribute: - return None - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(attr_node) - if at is None or at.attr is None or at.value is None: - return None - # 递归解析基座的注解类名(Name → 变量注解;Attribute → 字段注解) - parent_class: str = None - if at.value.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm.id is None: - return None - var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm.id) - if var_entry is None: - return None - parent_class = var_entry.AnnotClassName - elif at.value.kind() == ast.ASTKind.Attribute: - parent_class = self._resolve_attr_field_class(pool, trans, at.value) - else: - return None - if parent_class is None: - return None - # 在父类中查 at.attr 字段,返回其注解类名 - cur_sha1: str = None - if trans is not None: - cur_sha1 = trans.ModuleSha1 - fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field_by_class( - parent_class, at.attr, cur_sha1) - if fe is None: - return None - return HandlesStruct.get_field_annot_class_name(fe) - def get_attribute_ptr(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """获取属性访问的字段指针(用于赋值 lhs)""" - if node is None or builder is None: - return None - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at is None or at.value is None or at.attr is None: - return None - - # 对于 Name 类型的 obj,直接查找 alloca(不 load 结构体); - # nonlocal 变量(提升函数内)从 env 读共享堆值,避免 lookup_var - # 跨函数引用外层 alloca(SSA 编号跨函数错乱崩溃) - obj_ptr: llvmlite.Value | t.CPtr = None - if at.value.kind() == ast.ASTKind.Name and trans is not None: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm.id is not None: - if HT.is_nonlocal_name(trans, nm.id) != 0: - raw_nl_a: llvmlite.Value | t.CPtr = HandlesNonlocal._load_raw_var_ptr( - trans, nm.id) - if raw_nl_a is not None: - nl_ty_a: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type( - trans, nm.id) - if nl_ty_a is not None: - # 对象即指针:Struct/Array 类型直接用堆地址(bitcast 后 - # 作为对象指针,不 load);指针类型(如 Ptr(Point))堆里 - # 存对象指针,需 load 出对象指针 - match nl_ty_a: - case llvmlite.LLVMType.Struct(_, _, _): - obj_ptr = llvmlite.build_bitcast( - builder, raw_nl_a, llvmlite.Ptr(pool, nl_ty_a)) - case llvmlite.LLVMType.Array(_, _): - obj_ptr = llvmlite.build_bitcast( - builder, raw_nl_a, llvmlite.Ptr(pool, nl_ty_a)) - case _: - nl_val_ptr_a: llvmlite.Value | t.CPtr = \ - llvmlite.build_bitcast( - builder, raw_nl_a, llvmlite.Ptr(pool, nl_ty_a)) - if nl_val_ptr_a is not None: - obj_ptr = llvmlite.build_load( - builder, nl_ty_a, nl_val_ptr_a) - else: - obj_ptr = HandlesVar.lookup_var(trans.SymTab, nm.id) - - # 模块属性访问 (写路径): sys._mbuddy = mb / os._win32._mbuddy = v - # → store 到模块全局变量。当 obj 是已导入模块名(Name 或嵌套 Attribute - # 模块路径)且不是普通变量时,查找/创建全局变量引用。 - if obj_ptr is None and trans is not None: - mod_path_c: str = self._attr_module_path_str(pool, at.value) - if mod_path_c is not None: - # CDefine 常量不可写: 报 FATAL 错误,不创建未定义全局 - # (仅单层 Name 模块可精确判 CDefine) - if at.value.kind() == ast.ASTKind.Name: - nm_wma: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm_wma.id is not None: - if HandlesExpr._is_cdefine_name_pattern(at.attr) != 0: - err_buf_wma: str = pool.alloc(256) - if err_buf_wma is not None: - viperlib.snprintf(err_buf_wma, 256, - "[CD] FATAL: Cannot assign to CDefine constant '%s.%s'\n", - nm_wma.id, at.attr) - VLogger.error(err_buf_wma, "CD") - return None - # 使用 i8* 作为类型提示 (模块级变量通常存储指针) - i8_ptr_w: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - wma_ref: llvmlite.Value | t.CPtr = self._resolve_module_attribute_global( - pool, mod, trans, at, i8_ptr_w) - if wma_ref is not None: - return wma_ref - - # 非 Name 路径:翻译对象值(会 load) - if obj_ptr is None: - # c.Deref(ptr).attr: 属性写入 base 取指针本身而非 load 后的结构体值 - # (如 c.Deref(p).a = val 语义是 (*p).a = val,直接对 p 做 GEP) - cd_base_wr: llvmlite.Value | t.CPtr = self._get_cderef_attr_base( - builder, pool, mod, at.value, trans) - if cd_base_wr is not None: - obj_ptr = cd_base_wr - elif at.value.kind() == ast.ASTKind.Subscript: - # 下标基座属性写入(如 pts[0].x = val):list[T]/OOP __getitem__ 类走 - # translate_value(返回元素值/地址);普通结构体指针数组走 - # get_subscript_ptr(GEP 元素地址,避免结构体值 base=非指针 报错) - if self._sub_base_uses_getitem(pool, mod, trans, at.value) != 0: - obj_ptr = HandlesExpr.translate_value(builder, pool, mod, at.value, None, 0, trans) - else: - obj_ptr = HandlesExpr.get_subscript_ptr(builder, pool, mod, at.value, trans) - elif at.value.kind() == ast.ASTKind.Attribute: - # 嵌套属性基座写入(如 r.origin.x = val):取内层字段地址 - # (get_attribute_ptr 递归,地址语义),指针字段由 _deref_if_ptr_ptr 解引用 - obj_ptr = self.get_attribute_ptr(builder, pool, mod, at.value, trans) - if obj_ptr is None: - obj_ptr = HandlesExpr.translate_value(builder, pool, mod, at.value, None, 0, trans) - else: - obj_ptr = HandlesExpr.translate_value(builder, pool, mod, at.value, None, 0, trans) - - if obj_ptr is None or obj_ptr.Ty is None: - return None - - # 如果 obj_ptr 是 Ptr(Ptr(Struct))(X|t.CPtr 变量的 alloca), - # load 解引用获取 Ptr(Struct) - obj_ptr = self._deref_if_ptr_ptr(builder, obj_ptr) - - match obj_ptr.Ty: - case llvmlite.LLVMType.Ptr(struct_ty): - # 确保跨模块结构体的完整定义在当前模块中可用(供 getelementptr 访问字段) - # 与 translate_attribute 一致,避免 opaque 类型导致 GEP 报错 - HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) - field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( - struct_ty, at.attr) - # 按需过滤: struct_ty 为 i8(简化联合类型)时,通过 AnnotClassName 按类名查找 - # 传递 SHA1 以区分跨模块同名类 - # base 注解类名提取:Name → 变量注解类名;Attribute → 属性链递归字段注解类名 - # (如 lx.tokens_tail.next = tok:lx 的注解 Lexer → tokens_tail 字段注解 Token) - if field_info is None: - base_class: str = None - if at.value.kind() == ast.ASTKind.Name and trans is not None: - nm_fb: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm_fb.id is not None: - var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm_fb.id) - if var_entry is not None: - base_class = var_entry.AnnotClassName - elif at.value.kind() == ast.ASTKind.Attribute: - base_class = self._resolve_attr_field_class(pool, trans, at.value) - if base_class is not None: - cur_sha1: str = None - if trans is not None: - cur_sha1 = trans.ModuleSha1 - field_info = HandlesStruct.lookup_field_by_class( - base_class, at.attr, cur_sha1) - # REnum 变体字段别名回退(同 translate_attribute L5046-5062): - # get_attribute_ptr 赋值路径的按需过滤同样需要——struct_ty 简化 - # i8 时主路径 REnum 别名查找被跳过(LLVMType.Pointee 报错根因) - if field_info is None \ - and HandlesClassDef._is_renum_class_name(base_class) != 0: - rn_alias_g: int = HandlesClassDef._lookup_renum_field_alias( - base_class, at.attr) - if rn_alias_g >= 1: - rn_se_g: HandlesStruct.StructEntry | t.CPtr = \ - HandlesStruct.find_struct(base_class) - if rn_se_g is not None: - rn_fe_g: HandlesStruct.FieldEntry | t.CPtr = \ - HandlesStruct._get_field_entry(rn_se_g, rn_alias_g) - if rn_fe_g is not None and rn_fe_g.Ty is not None: - field_info = rn_fe_g - # 按需过滤成功:bitcast obj_ptr 到 AnnotClassName 对应的结构体类型 - # 原始 struct_ty 可能是 i8(X|t.CPtr 简化为 Ptr(i8)), - # 需用实际结构体类型做 GEP,否则 GEP i8 失败 - if field_info is not None: - annot_se: HandlesStruct.StructEntry | t.CPtr = \ - HandlesStruct.find_struct(base_class) - if annot_se is not None and annot_se.Ty is not None: - annot_ptr_ty: llvmlite.LLVMType | t.CPtr = \ - llvmlite.Ptr(pool, annot_se.Ty) - casted_ptr: llvmlite.Value | t.CPtr = \ - llvmlite.build_bitcast(builder, obj_ptr, annot_ptr_ty) - if casted_ptr is not None: - obj_ptr = casted_ptr - struct_ty = annot_se.Ty - # 按需过滤更新 struct_ty 后,需重新确保 - # 注解类型结构体定义在当前模块可用 - HandlesStruct.ensure_struct_def_in_module( - pool, mod, annot_se.Ty) - if field_info is not None: - # 联合体:bitcast obj_ptr 到 field_ty*(字段指针用于 store) - if HandlesStruct.is_union_by_type(struct_ty) == 1: - field_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, field_info.Ty) - return llvmlite.build_bitcast(builder, obj_ptr, field_ptr_ty) - # 普通结构体:GEP 获取字段指针 - return llvmlite.build_gep_struct( - builder, struct_ty, field_info.Ty, obj_ptr, field_info.Index) - # fast-fail: 字段未找到,立即终止编译(不再打印诊断后返回 None) - # Phase A 依赖未就绪(_deps_pending,父类/依赖类未注册致字段缺失, - # 如 Generator.vp 先于 TypeGenMixin.vp 编译时 self.TraceFrames): - # 跳过本属性写入交给下遍重译(对齐 HandlesAssign L69-78), - # 避免 fail-fast 中断多遍收敛;依赖就绪后仍缺失则走下方真实报错。 - if trans is not None and trans._deps_pending != 0: - return None - if trans is not None: - diag_annot_g: str = None - diag_var_nm_g: str = None - if at.value is not None and at.value.kind() == ast.ASTKind.Name: - dnm_g: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - diag_var_nm_g = dnm_g.id - if dnm_g.id is not None: - dve_g: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, dnm_g.id) - if dve_g is not None: - diag_annot_g = dve_g.AnnotClassName - diag_var_txt_g: str = "?" - if diag_var_nm_g is not None: - diag_var_txt_g = diag_var_nm_g - diag_annot_txt_g: str = "None" - if diag_annot_g is not None: - diag_annot_txt_g = diag_annot_g - sha1_attr_g: str = "?" - if trans.ModuleSha1 is not None: - sha1_attr_g = trans.ModuleSha1 - HandlesType.fatal_error( - at, - f"属性写入失败: .{at.attr} (var={diag_var_txt_g} annot={diag_annot_txt_g} sha1={sha1_attr_g})", - "TypeError") - return None - case _: - # fast-fail: 对非指针类型做属性写入(如 i32.x = ...), - # Python traceback 立即终止,不静默返回 None(否则下游 "store to None" 崩溃) - attr_nm_gp: str = "?" - if at is not None and at.attr is not None: - attr_nm_gp = at.attr - sha1_gp: str = "?" - if trans is not None and trans.ModuleSha1 is not None: - sha1_gp = trans.ModuleSha1 - ln_gp: int = 0 - if at is not None and at.lineno is not None: - ln_gp = at.lineno - HandlesType.fatal_error( - at, - f"属性写入失败: .{attr_nm_gp} (base=非指针类型,无法做属性写入 sha1={sha1_gp}:{ln_gp})", - "TypeError") - # fatal_error 后补显式 return 样板:match 末 arm 块必须 terminated +import lib.core.Gen.GenTypes as GenTypes +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import w32.fileio as fileio +import lib.core.CompilerFactory as CompilerFactory +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.StubMerger as StubMerger +import lib.core.StubMergerStore as StubMergerStore +import lib.core.VLogger as VLogger +import lib.Projectrans.Config as Config +import lib.Projectrans.Utils as Utils + + +import lib.core.Gen.ExprGenBase as ExprGenBase + +# ============================================================ +# ExprGenAttr - ExprGenMixin 拆分(阶段 D):Attribute/属性访问/全局引用 +# +# 继承 ExprGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class ExprGenAttr(ExprGenBase.ExprGenBase): + """Attribute/属性访问/全局引用""" + + # ============================================================ + # find_global_in_module - 在模块全局变量链表中按名称查找 + # + # 查找策略: + # 1. 精确匹配 (如 "_mbuddy" 匹配 @_mbuddy) + # 2. 后缀匹配 (如 "_mbuddy" 匹配 @"sha1._mbuddy") + # ============================================================ + def find_global_in_module(self, mod: llvmlite.LLVMModule | t.CPtr, + name: str) -> llvmlite.GlobalVariable | t.CPtr: + """在模块全局变量链表中按名称查找全局变量""" + if mod is None or name is None: + return None + name_len: t.CSizeT = string.strlen(name) + cur: llvmlite.GlobalVariable | t.CPtr = mod.GlobalHead + # 第一遍: 精确匹配 + while cur is not None: + if cur.Name is not None: + if string.strcmp(cur.Name, name) == 0: + return cur + cur = cur.Next + # 第二遍: 后缀匹配 (.name) + cur = mod.GlobalHead + while cur is not None: + if cur.Name is not None: + cur_len: t.CSizeT = string.strlen(cur.Name) + if cur_len > name_len + 1: + suffix_start: t.CSizeT = cur_len - name_len + if cur.Name[suffix_start - 1] == '.': + match: int = 1 + for i in range(name_len): + if cur.Name[suffix_start + i] != name[i]: + match = 0 + break + if match == 1: + return cur + cur = cur.Next + return None + # ============================================================ + # make_global_ref - 创建全局变量引用 (@name,类型为 ty*) + # + # 用于跨模块全局变量访问: stub 未注入时,翻译阶段生成 @name 引用, + # 链接时由 stub 提供 external global 声明。 + # ============================================================ + def make_global_ref(self, pool: memhub.MemBuddy | t.CPtr, + name: str, + ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: + """创建全局变量引用 (类型为 ty*,名称为 @name)""" + if name is None or ty is None: + return None + ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, ty) + ref_name: str = pool.alloc(96) + if ref_name is None: + return None + # LLVM 无引号标识符不能以数字开头:带 SHA1 前缀的全局名("sha1.name") + # 必命中 needs_quote(数字开头 + '.'),引用必须加引号 @\"sha1.name\", + # 否则 llc "expected instruction opcode"。对齐函数引用路径 + # (ExprGenName L252-255 的 needs_quote 判断)。 + if self.Gen.ClassGenVTable._vtable_name_needs_quote(name) != 0: + viperlib.snprintf(ref_name, 96, "@\"%s\"", name) + else: + viperlib.snprintf(ref_name, 96, "@%s", name) + return llvmlite.SSAValue(pool, ptr_ty, ref_name) + # ============================================================ + # _resolve_module_attribute_global - 解析模块属性访问的全局变量引用 + # + # 当 obj 是已导入模块名 (如 sys._mbuddy) 时: + # 1. 在当前模块全局变量链表中查找 (stub 已注入的情况) + # 2. 未找到则创建前向引用 (@attr_name, 类型为 ty 参数) + # + # 参数: + # ty_hint: 类型提示 (写路径用 rhs 类型, 读路径用 i8* 回退) + # 返回: Value 指针 (类型为 ty*),未识别为模块属性返回 None + # ============================================================ + def _is_t_type_object_name(self, name: str) -> int: + """检查 name 是否是 t.py 中的类型对象名(CPtr/CInt/CDouble 等) + + 这些类型对象在运行时作为全局变量 @CPtr/@CInt 等被引用, + 但 t.py 不被编译,需要在使用处生成带 null 初值的定义。 + """ + if name is None: + return 0 + # t.py 中的类型对象名(PascalCase,首字母大写) + if string.strcmp(name, "CPtr") == 0: + return 1 + if string.strcmp(name, "CInt") == 0: + return 1 + if string.strcmp(name, "CChar") == 0: + return 1 + if string.strcmp(name, "CShort") == 0: + return 1 + if string.strcmp(name, "CLong") == 0: + return 1 + if string.strcmp(name, "CLongLong") == 0: + return 1 + if string.strcmp(name, "CDouble") == 0: + return 1 + if string.strcmp(name, "CFloat") == 0: + return 1 + if string.strcmp(name, "CBool") == 0: + return 1 + if string.strcmp(name, "CVoid") == 0: + return 1 + if string.strcmp(name, "CInt8T") == 0: + return 1 + if string.strcmp(name, "CInt16T") == 0: + return 1 + if string.strcmp(name, "CInt32T") == 0: + return 1 + if string.strcmp(name, "CInt64T") == 0: + return 1 + if string.strcmp(name, "CUInt8T") == 0: + return 1 + if string.strcmp(name, "CUInt16T") == 0: + return 1 + if string.strcmp(name, "CUInt32T") == 0: + return 1 + if string.strcmp(name, "CUInt64T") == 0: + return 1 + if string.strcmp(name, "CUnsigned") == 0: + return 1 + if string.strcmp(name, "CUnsignedInt") == 0: + return 1 + if string.strcmp(name, "CUnsignedChar") == 0: + return 1 + if string.strcmp(name, "CUnsignedShort") == 0: + return 1 + if string.strcmp(name, "CUnsignedLong") == 0: + return 1 + if string.strcmp(name, "CUnsignedLongLong") == 0: + return 1 + if string.strcmp(name, "CSizeT") == 0: + return 1 + if string.strcmp(name, "CIntPtrT") == 0: + return 1 + if string.strcmp(name, "CUIntPtrT") == 0: + return 1 + if string.strcmp(name, "CPtrDiffT") == 0: + return 1 + if string.strcmp(name, "CType") == 0: + return 1 + if string.strcmp(name, "CDefine") == 0: + return 1 + if string.strcmp(name, "CStatic") == 0: + return 1 + if string.strcmp(name, "CExport") == 0: + return 1 + if string.strcmp(name, "CArray") == 0: + return 1 + if string.strcmp(name, "CTypedef") == 0: + return 1 + if string.strcmp(name, "CNoVTable") == 0: + return 1 + if string.strcmp(name, "CNeedPtr") == 0: + return 1 + if string.strcmp(name, "CAutoPtr") == 0: + return 1 + return 0 + def _attr_module_path_str(self, pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr) -> str: + """把模块引用 AST 转成模块路径字符串(递归拼接 Attribute 链): + Name('sys') → "sys";Attribute(Attribute(Name('os'),'_win32')) → "os._win32"。 + 非模块引用形态(Call/Subscript 等)返回 None。""" + if node is None: + return None + k: int = node.kind() + if k == ast.ASTKind.Name: + nm_m: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm_m.id is not None: + return nm_m.id + return None + if k == ast.ASTKind.Attribute: + at_m: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at_m.attr is None: + return None + base_m: str = self._attr_module_path_str(pool, at_m.value) + if base_m is None: + return None + blen: t.CSizeT = string.strlen(base_m) + alen: t.CSizeT = string.strlen(at_m.attr) + buf_m: str = pool.alloc(blen + alen + 2) + if buf_m is None: + return None + viperlib.snprintf(buf_m, blen + alen + 2, "%s.%s", base_m, at_m.attr) + return buf_m + return None + def _resolve_module_attribute_global(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + trans: HT.Translator | t.CPtr, + at: ast.Attribute | t.CPtr, + ty_hint: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: + """解析模块属性访问,返回全局变量引用 (用于跨模块 global 访问)""" + if at is None or at.value is None or at.attr is None: + return None + if trans is None or trans._imported_modules is None: + return None + # 提取模块路径名:Name → "sys";嵌套 Attribute → "os._win32" + # (此前只支持 Name 模块;SysLibTest main.vp L32 `os._win32._mbuddy = v` + # 的 at.value 是 Attribute → 被跳过 → "属性写入失败" 根因) + mod_path_w: str = self._attr_module_path_str(pool, at.value) + if mod_path_w is None: + return None + # 别名解析:import lib.core.Gen.Generator as GenGenerator → 查 from_imports + # 得原始模块名。否则 _lookup_module_sha1("GenGenerator") 查不到(Sha1Store + # 用原始模块名)→ 退化裸名 → 全局带 SHA1 前缀后 undefined symbol。 + # 别名属性访问(GenGenerator._g_gen = gen)依赖此解析才能命中目标模块定义。 + # 注意:lookup_from_import 返回指针非 NUL 结尾,须截断到空格/冒号/NUL + # 再查 SHA1(否则整串 "lib.core.Gen.Generator Config:lib... " 查不到)。 + if trans._from_imports is not None: + orig_mw: str = self.Gen.ImportsGen.lookup_from_import( + trans._from_imports, mod_path_w, 0) + if orig_mw is not None: + oml_a: t.CSizeT = 0 + while orig_mw[oml_a] != ' ' and orig_mw[oml_a] != '\0' and orig_mw[oml_a] != ':': + oml_a += 1 + if oml_a > 0: + om_buf_a: str = pool.alloc(oml_a + 1) + if om_buf_a is not None: + string.strncpy(om_buf_a, orig_mw, oml_a) + om_buf_a[oml_a] = '\0' + mod_path_w = om_buf_a + # 检查是否是已导入模块 + if self.Gen.ImportsGen.is_module_imported(trans._imported_modules, mod_path_w) == 0: + return None + # 在当前模块查找全局变量:优先按"目标模块 SHA1 前缀 + 属性名"精确匹配, + # 避免多模块同名全局(@._mbuddy / @._mbuddy 同时注入)时裸名后缀 + # 匹配返回错误模块的全局(串扰)。目标 sha1 未知时退化裸名(后缀匹配兜底) + gv_q: str = self.Gen.FuncGenBase._mangle_name_with_sha1( + self._lookup_module_sha1(mod_path_w), at.attr) + gv: llvmlite.GlobalVariable | t.CPtr = self.find_global_in_module(mod, gv_q) + if gv is not None and gv.Ty is not None: + # 用 gv.Name(完整名,带 SHA1 前缀时与定义端一致)构造引用, + # 避免裸名 @_mbuddy 在多模块各自带前缀定义下 undefined symbol + return self.make_global_ref(pool, gv.Name, gv.Ty) + # 未找到: 创建 external global 声明并添加到模块 + # 否则只生成 @_argc 引用而无声明,LLVM 报 "use of undefined value '@_argc'" + use_ty: llvmlite.LLVMType | t.CPtr = ty_hint + if use_ty is None: + use_ty = llvmlite.Int8(pool) + # 确保 use_ty 中的跨模块结构体类型有 opaque 声明 + llvmlite.module_ensure_opaque_for_type(mod, pool, use_ty) + # 特殊处理: t.py 中的类型对象(CPtr/CInt/CDouble 等) + # t.py 不被编译,但这些类型对象在运行时被引用(如 va_arg(ap, t.CPtr))。 + # 创建带 null 初值的 linkonce_odr 全局变量定义,避免链接时 undefined reference。 + # LLVM 22+ 不允许 external linkage 全局变量带初值,使用 linkonce_odr 替代。 + is_t_type_obj: int = 0 + if string.strcmp(mod_path_w, "t") == 0: + is_t_type_obj = self._is_t_type_object_name(at.attr) + # 兜底声明名:t 类型对象(t.py 不编译、无 sha1)保持裸名 linkonce_odr; + # 其他模块属性带目标模块 SHA1 前缀(对齐定义端 mangling,跨模块同名 + # 全局独立命名,消除 duplicate symbol / 串扰) + gv_name_ba: str = at.attr + if is_t_type_obj == 0: + gv_name_ba = self.Gen.FuncGenBase._mangle_name_with_sha1( + self._lookup_module_sha1(mod_path_w), at.attr) + ext_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, gv_name_ba, use_ty) + if ext_gv is not None: + if is_t_type_obj != 0: + # t.CPtr 等类型对象: 创建带 null 初值的定义(linkonce_odr) + ext_gv.Linkage = "linkonce_odr" + # i8* null 的初值文本 + null_init: bytes = pool.alloc(8) + if null_init is not None: + null_init[0] = 'n' + null_init[1] = 'u' + null_init[2] = 'l' + null_init[3] = 'l' + null_init[4] = '\0' + ext_gv.Initializer = null_init + else: + ext_gv.Initializer = None + else: + # 普通模块属性: external 声明(由其他模块提供定义) + ext_gv.Linkage = "external" + ext_gv.Initializer = None + llvmlite.module_add_global(mod, ext_gv) + return self.make_global_ref(pool, gv_name_ba, use_ty) + def _lookup_module_sha1(self, mod_name: str) -> str: + """查找模块名对应的 SHA1(委托 StubMergerStore,支持包名回退; + None=未找到,调用方退化为裸名)""" + return StubMergerStore.LookupSha1ByModName(mod_name) + # ============================================================ + # 翻译属性访问 Attribute(value, attr, ctx) — obj.field + # + # 优先级: + # 1. 枚举成员访问 (State.Idle → 常量值) + # 2. 模块属性访问 (sys._mbuddy → 加载全局变量) + # 3. 结构体字段访问 (obj.field → GEP + load) + # + # 对于 Name 类型的 obj,直接使用 alloca 指针(不 load 结构体) + # ============================================================ + + + # ============================================================ + # _get_cderef_attr_base - c.Deref(ptr).attr 属性访问的 base 指针 + # + # c.Deref(ptr) 作为属性访问 base 时(如 c.Deref(p).a),需要 ptr + # 指针本身而非 load 后的结构体值(*p.a → p->a),与 TPC + # _handle_attr_call_result 语义一致。否则 c.Deref 返回结构体值, + # 后续 GEP 在非指针上做属性访问会误报"base=非指针类型"。 + # + # 返回: + # ptr 指针值(Ptr(Struct) 或 Ptr(Ptr(Struct)),交由 _deref_if_ptr_ptr 解层级) + # 非 c.Deref 模式返回 None + # ============================================================ + def _get_cderef_attr_base(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + at_value: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """检测 at.value 是否为 c.Deref(ptr) 调用,返回 ptr 指针(不做 load)""" + if at_value is None or at_value.kind() != ast.ASTKind.Call: + return None + cl_cd: ast.Call | t.CPtr = (ast.Call | t.CPtr)(at_value) + if cl_cd.func is None or cl_cd.func.kind() != ast.ASTKind.Attribute: + return None + f_cd: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl_cd.func) + if f_cd.attr is None or string.strcmp(f_cd.attr, "Deref") != 0: + return None + if f_cd.value is None or f_cd.value.kind() != ast.ASTKind.Name: + return None + nm_cd: ast.Name | t.CPtr = (ast.Name | t.CPtr)(f_cd.value) + if nm_cd.id is None or string.strcmp(nm_cd.id, "c") != 0: + return None + if cl_cd.args is None or len(cl_cd.args) < 1: + return None + inner_cd: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cl_cd.args.get(0), None, 0, trans) + if inner_cd is not None and self.is_ptr_type(inner_cd.Ty) != 0: + return inner_cd + return None + def translate_attribute(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译属性访问,返回加载的字段值""" + if node is None or builder is None: + return None + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at is None or at.value is None or at.attr is None: + # fast-fail: AST 节点字段缺失属解析器 bug,应报告具体缺失字段 + diag_buf_an: bytes = stdlib.malloc(256) + if diag_buf_an is not None: + missing_an: str = "?" + if at is not None: + if at.value is None: + missing_an = "value" + elif at.attr is None: + missing_an = "attr" + viperlib.snprintf(diag_buf_an, 256, + "属性访问失败: AST 节点字段缺失 (%s sha1=%s:%d)", + missing_an, + trans.ModuleSha1 if trans is not None and trans.ModuleSha1 is not None else "?", + at.lineno if at is not None and at.lineno is not None else 0) + VLogger.error(diag_buf_an, "ATTR") + return None + + # 魔法属性 __doc__:查询 docstring 登记表(预注册阶段从 AST 提取), + # 命中则当前模块内联生成字符串常量返回;未命中(无 docstring 的 + # 函数/类/方法)返回 null 指针(i8*)。支持本模块与跨模块符号: + # local_func / LocalClass / LocalClass.method / remote.remote_func / + # remote.RemoteClass / remote.RemoteClass.remote_method + if string.strcmp(at.attr, "__doc__") == 0: + doc_mod_buf: bytes = pool.alloc(64) + doc_sym_buf: bytes = pool.alloc(256) + if doc_mod_buf is None or doc_sym_buf is None: + return None + doc_mod_buf[0] = '\0' + doc_sym_buf[0] = '\0' + if at.value is not None and at.value.kind() == ast.ASTKind.Name: + nm_doc: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm_doc.id is not None: + self.Gen.ExprGenCls._resolve_doc_symbol_name(trans, nm_doc.id, doc_mod_buf, doc_sym_buf) + elif at.value is not None and at.value.kind() == ast.ASTKind.Attribute: + self.Gen.ExprGenCls._resolve_doc_symbol_attr(trans, (ast.Attribute | t.CPtr)(at.value), doc_mod_buf, doc_sym_buf) + doc_val: str = None + if doc_mod_buf[0] != '\0' and doc_sym_buf[0] != '\0': + doc_val = self.Gen.ExprGenCls.lookup_docstring(doc_mod_buf, doc_sym_buf) + if doc_val is None: + i8_ty_doc: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + if i8_ty_doc is None: + return None + i8_ptr_ty_doc: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_doc) + if i8_ptr_ty_doc is None: + return None + return llvmlite.ConstNull(pool, i8_ptr_ty_doc, "null") + return self.Gen.ExprGenConst.create_global_string(builder, pool, mod, doc_val, trans) + + # 枚举成员访问: EnumName.MemberName → 常量值 + # 当 value 是 Name 且 Name.id 是已注册枚举时,查找成员并返回常量 + if at.value.kind() == ast.ASTKind.Name: + enum_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if enum_nm.id is not None: + if self.Gen.StmtGenDecl.is_enum_class(enum_nm.id) == 1: + member: GenTypes.EnumMember | t.CPtr = self.Gen.StmtGenDecl.lookup_enum_member( + enum_nm.id, at.attr) + if member is not None: + base_ty: llvmlite.LLVMType | t.CPtr = self.Gen.StmtGenDecl.get_enum_base_type( + enum_nm.id) + if base_ty is not None: + # 生成数字字符串作为常量名(LLVM IR 要求常量输出数字值) + name_buf: str = pool.alloc(32) + if name_buf is not None: + viperlib.snprintf(name_buf, 32, "%lld", member.Value) + return llvmlite.ConstInt(pool, base_ty, member.Value, name_buf) + return llvmlite.const_int32(pool, member.Value) + # fast-fail: 枚举成员未找到 + VLogger.error( + f"枚举成员未找到: {enum_nm.id}.{at.attr}", + "ATTR") + return None + + # 嵌套枚举成员访问: Module.EnumName.MemberName → 常量值 + # 当 value 是 Attribute(如 fileio.MODE / w32.fileio.MODE,含三级以上 + # 模块路径)且 attr 部分是已注册枚举时。此前限制 inner_at_e.value 必须是 + # Name(仅支持两层 Module.EnumName),w32.fileio.MODE.W(三层,value 是 + # Attribute)被跳过 → "属性访问失败: .W"(SysLibTest L190 根因)。 + # 枚举类名只取最内层 attr(MODE),模块路径形态不影响。 + if at.value.kind() == ast.ASTKind.Attribute: + inner_at_e: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(at.value) + if inner_at_e.attr is not None: + if self.Gen.StmtGenDecl.is_enum_class(inner_at_e.attr) == 1: + member_e: GenTypes.EnumMember | t.CPtr = self.Gen.StmtGenDecl.lookup_enum_member( + inner_at_e.attr, at.attr) + if member_e is not None: + base_ty_e: llvmlite.LLVMType | t.CPtr = self.Gen.StmtGenDecl.get_enum_base_type( + inner_at_e.attr) + if base_ty_e is not None: + name_buf_e: str = pool.alloc(32) + if name_buf_e is not None: + viperlib.snprintf(name_buf_e, 32, "%lld", member_e.Value) + return llvmlite.ConstInt(pool, base_ty_e, member_e.Value, name_buf_e) + return llvmlite.const_int32(pool, member_e.Value) + # fast-fail: 嵌套枚举成员未找到 + dbg_ee: GenTypes.EnumEntry | t.CPtr = self.Gen.StmtGenDecl.find_enum( + inner_at_e.attr) + dbg_mc: int = -1 + if dbg_ee is not None: + dbg_mc = dbg_ee.MemberCount + VLogger.error( + f"嵌套枚举成员未找到: {inner_at_e.attr}.{at.attr} " + f"(enum_members={dbg_mc})", "ATTR") + return None + + # FakeDuck: 影子结构体属性读取 (str 变量的 per-instance 字段) + # a.__data__ / a.__mbuddy__ → GEP {a}__meta__[field] 并加载 + # 对齐 TPC HandlesExprAttr.py L433-442:对象是 Name 变量且存在 + # {var}__meta__ 影子(fd2 创建)时,属性访问改走影子结构体。 + if at.value.kind() == ast.ASTKind.Name and trans is not None: + fd_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if fd_nm.id is not None: + # pool 持久缓冲(f-string 栈缓冲在函数返回后失效) + fd_meta_buf: str = pool.alloc(256) + if fd_meta_buf is not None: + viperlib.snprintf(fd_meta_buf, 256, "%s__meta__", fd_nm.id) + fd_meta_v: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_current( + trans.SymTab, fd_meta_buf) + if fd_meta_v is not None: + fd_sty: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type( + "_str") + if fd_sty is not None: + fd_fe: GenTypes.FieldEntry | t.CPtr = \ + self.Gen.StructGen.lookup_field(fd_sty, at.attr) + if fd_fe is not None and fd_fe.Ty is not None: + fd_fp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, fd_sty, fd_fe.Ty, fd_meta_v, fd_fe.Index) + if fd_fp is not None: + return llvmlite.build_load(builder, fd_fe.Ty, fd_fp) + + # 模块属性访问 (读路径): sys._mbuddy → 加载全局变量 @_mbuddy + # 当 obj 是已导入模块名且不是普通变量时,查找/创建全局变量引用并加载 + if at.value.kind() == ast.ASTKind.Name and trans is not None: + nm_ma: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm_ma.id is not None: + # 先检查是否是普通变量 (优先级高于模块属性) + ma_is_var: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, nm_ma.id) + if ma_is_var is None: + # 先检查是否是 CDefine 编译期常量 (如 ast.CONST_INT / win32base.INVALID_HANDLE_VALUE) + # 模块属性访问的 CDefine 常量需要跨模块查找源 .vp / .vpi 文件 + cdef_ma_val: t.CInt64T = self.Gen.TypeGenCDef.lookup_cdefine_constant(at.attr) + cd_local: int = self.Gen.TypeGenCDef.is_cdefine_found() + if cd_local == 0: + # 确定真实模块名:优先从 _from_imports 解析别名 + # from_imports 中条目格式 "local_name:real_module" + # 如 win32base:w32.win32base → 别名 win32base 真实模块 w32.win32base + real_mod_name: str = nm_ma.id + if trans._from_imports is not None: + resolved_mod: str = self.Gen.ImportsGen.lookup_from_import( + trans._from_imports, nm_ma.id, 0) + if resolved_mod is not None: + # 复制模块名到新缓冲区(截断于空格、null、或 ':') + rm_len: t.CSizeT = 0 + while resolved_mod[rm_len] != ' ' and resolved_mod[rm_len] != '\0' and resolved_mod[rm_len] != ':': + rm_len += 1 + rm_buf: str = pool.alloc(rm_len + 1) + if rm_buf is not None: + for rm_i in range(rm_len): + rm_buf[rm_i] = resolved_mod[rm_i] + rm_buf[rm_len] = '\0' + real_mod_name = rm_buf + # 即使 _from_imports 为 None(如纯 `import ast` 无 from-import), + # 也必须尝试跨模块 CDefine 查找,否则 ast.CONST_INT 会被 + # 误解析为全局变量引用 @CONST_INT(未定义符号)。 + # 构建临时 from_imports "{attr}:{real_module}" 用于跨模块查找 + if real_mod_name is not None: + ma_fi_len: t.CSizeT = string.strlen(at.attr) + string.strlen(real_mod_name) + 2 + ma_fi: str = pool.alloc(ma_fi_len) + if ma_fi is not None: + viperlib.snprintf(ma_fi, ma_fi_len, "%s:%s", at.attr, real_mod_name) + cdef_ma_val = self.Gen.ExprGenCdef._lookup_cross_module_cdefine(pool, at.attr, ma_fi) + if self.Gen.TypeGenCDef.is_cdefine_found() != 0: + # 跨模块字符串 CDefine(如 pyzlib.ZLIB_VERSION = "1.3.2")→ + # 字符串全局常量(test_pyzlib.vp L49 ver = pyzlib.ZLIB_VERSION) + if self.Gen.TypeGenCDef.is_cdefine_str() != 0: + cdef_str_v: str = self.Gen.TypeGenCDef.lookup_cdefine_string(at.attr) + if cdef_str_v is not None: + return self.Gen.ExprGenConst.create_global_string( + builder, pool, mod, cdef_str_v, trans) + # 跨模块浮点 CDefine(如 vipermath.U_M_PI)→ 浮点常量 + dchk_ma: double = self.Gen.TypeGenCDef.lookup_cdefine_double(at.attr) + if self.Gen.TypeGenCDef.is_cdefine_double() != 0: + return llvmlite.ConstFloat(pool, llvmlite.Double(pool), dchk_ma) + return self.Gen.ExprGenCdef._const_int_for_cdefine(pool, cdef_ma_val) + # 检查 nm_ma.id.at.attr 是否是已导入子模块 (如 w32.win32file) + # 如果是子模块,不应创建全局变量,让嵌套属性访问路径处理 + is_submod: int = 0 + if trans._imported_modules is not None: + submod_len: t.CSizeT = string.strlen(nm_ma.id) + string.strlen(at.attr) + 2 + submod_buf: str = pool.alloc(submod_len) + if submod_buf is not None: + viperlib.snprintf(submod_buf, submod_len, "%s.%s", nm_ma.id, at.attr) + if self.Gen.ImportsGen.is_module_imported(trans._imported_modules, submod_buf) == 1: + is_submod = 1 + # also check from_imports: at.attr 别名对应真实模块 w32.win32file + if is_submod == 0 and trans._from_imports is not None: + fi_mod_raw: str = self.Gen.ImportsGen.lookup_from_import( + trans._from_imports, at.attr, 0) + if fi_mod_raw is not None: + # 复制模块名到新缓冲区(截断于空格、null、或 ':') + fm_len: t.CSizeT = 0 + while fi_mod_raw[fm_len] != ' ' and fi_mod_raw[fm_len] != '\0' and fi_mod_raw[fm_len] != ':': + fm_len += 1 + fi_mod: str = pool.alloc(fm_len + 1) + if fi_mod is not None: + for fm_i in range(fm_len): + fi_mod[fm_i] = fi_mod_raw[fm_i] + fi_mod[fm_len] = '\0' + # 检查 fi_mod 是否以 "nm_ma.id." 开头 (如 w32.win32file 以 w32. 开头) + prefix_len: t.CSizeT = string.strlen(nm_ma.id) + fi_mod_len: t.CSizeT = string.strlen(fi_mod) + if fi_mod_len > prefix_len + 1: + match_prefix: int = 1 + for pi in range(prefix_len): + if fi_mod[pi] != nm_ma.id[pi]: + match_prefix = 0 + break + if match_prefix == 1 and fi_mod[prefix_len] == '.': + is_submod = 1 + if is_submod != 0: + return None # 是子模块,交给嵌套属性访问路径 + # 特殊处理: t.ASM_DESCR 不是 CDefine,是内联汇编约束命名空间 + # t.ASM_DESCR.XXX 由 HandlesExprCall 的 _asm_resolve_constraint 处理 + # 此处返回 None,让上层嵌套属性访问路径处理 + if string.strcmp(nm_ma.id, "t") == 0 and string.strcmp(at.attr, "ASM_DESCR") == 0: + return None + # ALL_CAPS 模块属性但非 CDefine:先检查模块是否定义了同名全局 + # 变量(如 Phase1.PYI_BUF_SIZE: t.CSizeT = 262144 是 i64 全局、 + # 非宏,语义同 C 的 extern size_t PYI_BUF_SIZE)→ 按跨模块全局 + # 引用加载。仅当全局变量也不存在时才 fail-fast(防 llc + # "use of undefined value")。 + if self.Gen.ExprGenCdef._is_cdefine_name_pattern(at.attr) != 0: + if self.find_global_in_module(mod, at.attr) is None: + self.Gen.TypeGenErr.fatal_error( + at, + f"跨模块 CDefine 未找到: '{nm_ma.id}.{at.attr}'(CDefine cross-module lookup failed)", + "TypeError") + # 命中跨模块全局 → 落到下方跨模块全局加载路径 + # 非 CDefine: 使用 i8* 作为类型提示 (模块级变量通常存储指针) + i8_ptr_hint: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + mod_gv_ref: llvmlite.Value | t.CPtr = self._resolve_module_attribute_global( + pool, mod, trans, at, i8_ptr_hint) + if mod_gv_ref is not None and mod_gv_ref.Ty is not None: + load_ty_mod: llvmlite.LLVMType | t.CPtr = mod_gv_ref.Ty.Pointee + if load_ty_mod is not None: + # 模块级全局数组(如 zdef.zdeflate_len_base: CArray[T, N]): + # 按 C 语义衰减为基址返回(对齐 translate_name_value 局部 + # 数组分支 L3383-3388),load [N x T] 数组值无法作 GEP 基址。 + match load_ty_mod: + case llvmlite.LLVMType.Array(_, _): + return mod_gv_ref + case _: + pass + return llvmlite.build_load(builder, load_ty_mod, mod_gv_ref) + + # 嵌套模块属性访问 (w32.win32file.GENERIC_READ → 查找全局 @GENERIC_READ) + # 当 at.value 是 Attribute 且解析为已导入子模块时,查找 at.attr 作为全局常量 + if at.value.kind() == ast.ASTKind.Attribute and trans is not None: + inner_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(at.value) + if inner_at.value is not None and inner_at.value.kind() == ast.ASTKind.Name: + inner_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner_at.value) + if inner_nm.id is not None and inner_at.attr is not None: + if self.Gen.VarGen.lookup_var(trans.SymTab, inner_nm.id) is None: + # 构建限定模块名: "w32.win32file" + qual_len: t.CSizeT = string.strlen(inner_nm.id) + string.strlen(inner_at.attr) + 2 + qual_buf: str = pool.alloc(qual_len) + if qual_buf is not None: + viperlib.snprintf(qual_buf, qual_len, "%s.%s", inner_nm.id, inner_at.attr) + if self.Gen.ImportsGen.is_module_imported(trans._imported_modules, qual_buf) == 1: + # 查找全局变量 at.attr(带限定模块 SHA1 前缀精确匹配, + # 避免多模块同名全局后缀匹配串扰;sha1 未知退化裸名) + gv_nested_q: str = self.Gen.FuncGenBase._mangle_name_with_sha1( + self._lookup_module_sha1(qual_buf), at.attr) + gv_nested: llvmlite.GlobalVariable | t.CPtr = self.find_global_in_module(mod, gv_nested_q) + if gv_nested is not None and gv_nested.Ty is not None: + gv_ref_nested: llvmlite.Value | t.CPtr = self.make_global_ref( + pool, gv_nested.Name, gv_nested.Ty) + if gv_ref_nested is not None and gv_ref_nested.Ty is not None: + load_ty_nested: llvmlite.LLVMType | t.CPtr = gv_ref_nested.Ty.Pointee + if load_ty_nested is not None: + return llvmlite.build_load(builder, load_ty_nested, gv_ref_nested) + # 未找到全局: 尝试 CDefine 常量查找 + # 对于 w32.win32base.INVALID_HANDLE_VALUE 等嵌套模块属性访问, + # 先从限定模块的 .vpi 文件中查找 CDefine 常量值并内联 + cdef_val_nested: t.CInt64T = self.Gen.TypeGenCDef.lookup_cdefine_constant(at.attr) + if self.Gen.TypeGenCDef.is_cdefine_found() == 0: + # 构建临时 from_imports "attr:module" 用于跨模块查找 + tmp_fi_len: t.CSizeT = string.strlen(at.attr) + string.strlen(qual_buf) + 2 + tmp_fi: str = pool.alloc(tmp_fi_len) + if tmp_fi is not None: + viperlib.snprintf(tmp_fi, tmp_fi_len, "%s:%s", at.attr, qual_buf) + cdef_val_nested = self.Gen.ExprGenCdef._lookup_cross_module_cdefine(pool, at.attr, tmp_fi) + if self.Gen.TypeGenCDef.is_cdefine_found() != 0: + # 跨模块浮点 CDefine → 浮点常量 + dchk_nst: double = self.Gen.TypeGenCDef.lookup_cdefine_double(at.attr) + if self.Gen.TypeGenCDef.is_cdefine_double() != 0: + return llvmlite.ConstFloat(pool, llvmlite.Double(pool), dchk_nst) + return self.Gen.ExprGenCdef._const_int_for_cdefine(pool, cdef_val_nested) + # CDefine 未找到: fail-fast 终止编译(不再创建未定义的全局变量引用) + # 之前此处创建 @INVALID_HANDLE_VALUE 等前向引用,但全局未定义, + # 导致 llc 报 "use of undefined value" 错误。 + # 正确做法是报错终止,让开发者修复跨模块 CDefine 查找失败的根本原因。 + if self.Gen.ExprGenCdef._is_cdefine_name_pattern(at.attr) != 0: + self.Gen.TypeGenErr.fatal_error( + at, + f"嵌套属性跨模块 CDefine 未找到: '{qual_buf}.{at.attr}'(CDefine cross-module lookup failed)", + "TypeError") + return None + + # 对于 Name 类型的 obj,直接查找 alloca(不 load 结构体); + # nonlocal 变量(提升函数内)从 env 读共享堆值,避免 lookup_var + # 跨函数引用外层 alloca(SSA 编号跨函数错乱崩溃) + obj_ptr: llvmlite.Value | t.CPtr = None + if at.value.kind() == ast.ASTKind.Name and trans is not None: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm.id is not None: + if HT.is_nonlocal_name(trans, nm.id) != 0: + raw_nl_a: llvmlite.Value | t.CPtr = self.Gen.StmtGenDecl._load_raw_var_ptr( + trans, nm.id) + if raw_nl_a is not None: + nl_ty_a: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type( + trans, nm.id) + if nl_ty_a is not None: + # 对象即指针:Struct/Array 类型直接用堆地址(bitcast 后 + # 作为对象指针,不 load);指针类型(如 Ptr(Point))堆里 + # 存对象指针,需 load 出对象指针 + match nl_ty_a: + case llvmlite.LLVMType.Struct(_, _, _): + obj_ptr = llvmlite.build_bitcast( + builder, raw_nl_a, llvmlite.Ptr(pool, nl_ty_a)) + case llvmlite.LLVMType.Array(_, _): + obj_ptr = llvmlite.build_bitcast( + builder, raw_nl_a, llvmlite.Ptr(pool, nl_ty_a)) + case _: + nl_val_ptr_a: llvmlite.Value | t.CPtr = \ + llvmlite.build_bitcast( + builder, raw_nl_a, llvmlite.Ptr(pool, nl_ty_a)) + if nl_val_ptr_a is not None: + obj_ptr = llvmlite.build_load( + builder, nl_ty_a, nl_val_ptr_a) + else: + obj_ptr = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id) + + # 非 Name 路径:翻译对象值(会 load) + if obj_ptr is None: + # c.Deref(ptr).attr: 属性访问 base 取指针本身而非 load 后的结构体值 + # (如 c.Deref(p).a 语义是 (*p).a,直接对 p 做 GEP) + cd_base_rd: llvmlite.Value | t.CPtr = self._get_cderef_attr_base( + builder, pool, mod, at.value, trans) + if cd_base_rd is not None: + obj_ptr = cd_base_rd + elif at.value.kind() == ast.ASTKind.Subscript: + # 下标基座属性访问(如 pts[0].x):list[T]/OOP __getitem__ 类走 + # translate_value(返回元素值/地址);普通结构体指针数组走 + # get_subscript_ptr(GEP 元素地址,避免结构体值 base=非指针 报错) + if self._sub_base_uses_getitem(pool, mod, trans, at.value) != 0: + obj_ptr = self.Gen.ExprGen.translate_value(builder, pool, mod, at.value, None, 0, trans) + else: + obj_ptr = self.Gen.ExprGenName.get_subscript_ptr(builder, pool, mod, at.value, trans) + elif at.value.kind() == ast.ASTKind.Attribute: + # 嵌套属性基座(如 r.origin.x):取内层字段地址(get_attribute_ptr 递归, + # 地址语义),指针字段(X|t.CPtr)由 _deref_if_ptr_ptr load 解引用 + obj_ptr = self.get_attribute_ptr(builder, pool, mod, at.value, trans) + if obj_ptr is None: + obj_ptr = self.Gen.ExprGen.translate_value(builder, pool, mod, at.value, None, 0, trans) + else: + obj_ptr = self.Gen.ExprGen.translate_value(builder, pool, mod, at.value, None, 0, trans) + + if obj_ptr is None or obj_ptr.Ty is None: + return None + + # 如果 obj_ptr 是 Ptr(Ptr(Struct))(X|t.CPtr 变量的 alloca), + # load 解引用获取 Ptr(Struct) + obj_ptr = self._deref_if_ptr_ptr(builder, obj_ptr) + + # 查找结构体类型信息 + # obj_ptr 类型应该是 Ptr(Struct(...)) + match obj_ptr.Ty: + case llvmlite.LLVMType.Ptr(struct_ty): + # 确保跨模块结构体的完整定义在当前模块中可用(供 getelementptr 访问字段) + self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, struct_ty) + # 查找字段索引和类型 + field_info: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field( + struct_ty, at.attr) + # REnum 变体字段查找: lookup_field 失败时,尝试 REnum 别名 + # REnum 结构体字段名是 _p1/_p2/...,但源码用变体字段名访问(如 ty.Pointee) + if field_info is None: + renum_se: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_type( + struct_ty) + if renum_se is not None and renum_se.Name is not None: + is_rn: int = self.Gen.ClassGenEnum._is_renum_class_name(renum_se.Name) + if is_rn == 1: + alias_idx: int = self.Gen.ClassGenEnum._lookup_renum_field_alias( + renum_se.Name, at.attr) + if alias_idx >= 1: + alias_fe: GenTypes.FieldEntry | t.CPtr = \ + self.Gen.StructGen._get_field_entry(renum_se, alias_idx) + if alias_fe is not None and alias_fe.Ty is not None: + alias_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, alias_fe.Ty, obj_ptr, alias_idx) + if alias_ptr is not None: + return llvmlite.build_load(builder, alias_fe.Ty, alias_ptr) + # property getter 回退: obj.attr 是 @property/@x.getter 方法时生成调用 + # (字段未找到时先尝试,避免报误导性的"字段未找到"错误) + if field_info is None and at.value is not None and trans is not None: + prop_cls_fb: str = self.Gen.StructGen.get_class_name_by_type(pool, struct_ty) + prop_val: llvmlite.Value | t.CPtr = self.Gen.CallGenProp._try_property_getter_attr( + pool, builder, mod, at, obj_ptr, trans, prop_cls_fb) + if prop_val is not None: + return prop_val + # 按需过滤: struct_ty 为 i8(简化联合类型)时,通过 AnnotClassName 按类名查找 + # 传递 SHA1 以区分跨模块同名类 + # base 注解类名提取:Name → 变量注解类名;Attribute → 属性链递归字段注解类名 + if field_info is None: + base_class: str = None + if at.value.kind() == ast.ASTKind.Name and trans is not None: + nm_fb: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm_fb.id is not None: + var_entry: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, nm_fb.id) + if var_entry is not None: + base_class = var_entry.AnnotClassName + elif at.value.kind() == ast.ASTKind.Attribute: + base_class = self._resolve_attr_field_class(pool, trans, at.value) + if base_class is not None: + cur_sha1: str = trans.ModuleSha1 + field_info = self.Gen.StructGen.lookup_field_by_class( + base_class, at.attr, cur_sha1) + # REnum 变体字段别名回退:base_class 是 REnum 类时,变体 + # 字段名(如 LLVMType.Pointee → _p2 槽位)不是普通字段, + # lookup_field_by_class 查不到(LLVMType"字段 Pointee 未找到" + # 根因;主路径 L4989-5004 的 REnum 别名查找因 struct_ty 简化 + # 为 i8、find_struct_by_type 失败被跳过) + if field_info is None \ + and self.Gen.ClassGenEnum._is_renum_class_name(base_class) != 0: + rn_alias: int = self.Gen.ClassGenEnum._lookup_renum_field_alias( + base_class, at.attr) + if rn_alias >= 1: + rn_se: GenTypes.StructEntry | t.CPtr = \ + self.Gen.StructGen.find_struct(base_class) + if rn_se is not None: + rn_fe: GenTypes.FieldEntry | t.CPtr = \ + self.Gen.StructGen._get_field_entry(rn_se, rn_alias) + if rn_fe is not None and rn_fe.Ty is not None: + field_info = rn_fe + # 按需过滤成功:bitcast obj_ptr 到 AnnotClassName 对应的结构体类型 + # 原始 struct_ty 可能是 i8(X|t.CPtr 简化为 Ptr(i8)), + # 需用实际结构体类型做 GEP,否则 GEP i8 失败 + if field_info is not None: + annot_se: GenTypes.StructEntry | t.CPtr = \ + self.Gen.StructGen.find_struct(base_class) + if annot_se is not None and annot_se.Ty is not None: + annot_ptr_ty: llvmlite.LLVMType | t.CPtr = \ + llvmlite.Ptr(pool, annot_se.Ty) + casted_ptr: llvmlite.Value | t.CPtr = \ + llvmlite.build_bitcast(builder, obj_ptr, annot_ptr_ty) + if casted_ptr is not None: + obj_ptr = casted_ptr + struct_ty = annot_se.Ty + # 按需过滤更新 struct_ty 后,需重新确保 + # 注解类型结构体定义在当前模块可用 + # (原始 struct_ty 可能是 i8,ensure 无效) + self.Gen.StructGen.ensure_struct_def_in_module( + pool, mod, annot_se.Ty) + if field_info is not None: + field_ty: llvmlite.LLVMType | t.CPtr = field_info.Ty + # 联合体:bitcast obj_ptr 到 field_ty* 后 load + if self.Gen.StructGen.is_union_by_type(struct_ty) == 1: + field_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, field_ty) + casted: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, obj_ptr, field_ptr_ty) + if casted is not None: + return llvmlite.build_load(builder, field_ty, casted) + return None + # 普通结构体:GEP + load + field_idx: int = field_info.Index + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, field_ty, obj_ptr, field_idx) + if field_ptr is not None: + # 数组类型字段不能 load 为 SSA value,直接返回字段指针 + # 用于后续下标访问: self.state[0] → GEP state 字段 → GEP 数组元素 + if self.is_array_type(field_ty) != 0: + return field_ptr + loaded_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, field_ty, field_ptr) + # 联合类型字段(如 Token | t.CPtr)被编译为 i8*, + # 若 AnnotClassName 指示了具体结构体类型,bitcast 为正确的结构体指针。 + # 注意:仅当字段类型本身是指针时才 bitcast(指针→指针); + # 内嵌结构体字段(field_ty=Struct)load 出的是结构体值, + # bitcast 值→指针是非法 IR(llc: invalid cast opcode)。 + if loaded_val is not None and field_info.AnnotClassName is not None \ + and self.is_ptr_type(field_ty) != 0: + annot_struct: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct( + field_info.AnnotClassName) + if annot_struct is not None and annot_struct.Ty is not None: + annot_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, annot_struct.Ty) + return llvmlite.build_bitcast(builder, loaded_val, annot_ptr_ty) + return loaded_val + # fast-fail: 字段未找到,立即终止编译(不再打印诊断后返回 None) + # Phase A 依赖未就绪(_deps_pending,父类/依赖类未注册致字段缺失): + # 跳过本属性访问交给下遍重译(对齐 get_attribute_ptr L5541-5547), + # 避免 fail-fast 中断多遍收敛;依赖就绪后仍缺失则走下方真实报错。 + if trans is not None and trans._deps_pending != 0: + return None + if trans is not None: + diag_annot: str = None + diag_var_nm: str = None + if at.value is not None and at.value.kind() == ast.ASTKind.Name: + dnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + diag_var_nm = dnm.id + if dnm.id is not None: + dve: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, dnm.id) + if dve is not None: + diag_annot = dve.AnnotClassName + diag_var_txt: str = "?" + if diag_var_nm is not None: + diag_var_txt = diag_var_nm + diag_annot_txt: str = "None" + if diag_annot is not None: + diag_annot_txt = diag_annot + sha1_attr: str = "?" + if trans.ModuleSha1 is not None: + sha1_attr = trans.ModuleSha1 + self.Gen.TypeGenErr.fatal_error( + at, + f"属性访问失败: .{at.attr} (var={diag_var_txt} annot={diag_annot_txt} sha1={sha1_attr})", + "TypeError") + return None + case _: + # fast-fail: 对非指针类型做属性访问(如 i32.x), + # Python traceback 立即终止,不静默返回 None(否则下游 "store to None" 崩溃,丢失错误现场) + attr_nm_ap: str = "?" + if at is not None and at.attr is not None: + attr_nm_ap = at.attr + sha1_ap: str = "?" + if trans is not None and trans.ModuleSha1 is not None: + sha1_ap = trans.ModuleSha1 + ln_ap: int = 0 + if at is not None and at.lineno is not None: + ln_ap = at.lineno + self.Gen.TypeGenErr.fatal_error( + at, + f"属性访问失败: .{attr_nm_ap} (base=非指针类型,无法做属性访问 sha1={sha1_ap}:{ln_ap})", + "TypeError") + # fatal_error 后补显式 return 样板:match 末 arm 块必须 terminated, + # 否则掉出末尾被函数收尾 fail-fast 误判(块设计约定) + return None + # ============================================================ + # 获取属性访问的字段指针(不加载值,用于赋值) + # 对于 Name 类型的 obj,直接使用 alloca 指针(不 load 结构体) + # ============================================================ + def _resolve_attr_field_class(self, pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr, + attr_node: ast.AST | t.CPtr) -> str: + """解析属性链(a.b.c)中 c 字段的注解类名。 + + 联合类型字段(X | t.CPtr)被简化为 Ptr(i8),属性链写入时 + (如 lx.tokens_tail.next = tok)obj_ptr.Ty 是 Ptr(i8), + lookup_field(i8, ...) 必然失败。此函数沿属性链递归解析 + 最终字段的 AnnotClassName(如 tokens_tail → 'Token'), + 供按需过滤分支 bitcast 回真实结构体类型后 GEP。 + """ + if attr_node is None or trans is None: + return None + k: int = attr_node.kind() + if k != ast.ASTKind.Attribute: + return None + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(attr_node) + if at is None or at.attr is None or at.value is None: + return None + # 递归解析基座的注解类名(Name → 变量注解;Attribute → 字段注解) + parent_class: str = None + if at.value.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm.id is None: + return None + var_entry: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, nm.id) + if var_entry is None: + return None + parent_class = var_entry.AnnotClassName + elif at.value.kind() == ast.ASTKind.Attribute: + parent_class = self._resolve_attr_field_class(pool, trans, at.value) + else: + return None + if parent_class is None: + return None + # 在父类中查 at.attr 字段,返回其注解类名 + cur_sha1: str = None + if trans is not None: + cur_sha1 = trans.ModuleSha1 + fe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field_by_class( + parent_class, at.attr, cur_sha1) + if fe is None: + return None + return self.Gen.StructGen.get_field_annot_class_name(fe) + def get_attribute_ptr(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """获取属性访问的字段指针(用于赋值 lhs)""" + if node is None or builder is None: + return None + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at is None or at.value is None or at.attr is None: + return None + + # 对于 Name 类型的 obj,直接查找 alloca(不 load 结构体); + # nonlocal 变量(提升函数内)从 env 读共享堆值,避免 lookup_var + # 跨函数引用外层 alloca(SSA 编号跨函数错乱崩溃) + obj_ptr: llvmlite.Value | t.CPtr = None + if at.value.kind() == ast.ASTKind.Name and trans is not None: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm.id is not None: + if HT.is_nonlocal_name(trans, nm.id) != 0: + raw_nl_a: llvmlite.Value | t.CPtr = self.Gen.StmtGenDecl._load_raw_var_ptr( + trans, nm.id) + if raw_nl_a is not None: + nl_ty_a: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type( + trans, nm.id) + if nl_ty_a is not None: + # 对象即指针:Struct/Array 类型直接用堆地址(bitcast 后 + # 作为对象指针,不 load);指针类型(如 Ptr(Point))堆里 + # 存对象指针,需 load 出对象指针 + match nl_ty_a: + case llvmlite.LLVMType.Struct(_, _, _): + obj_ptr = llvmlite.build_bitcast( + builder, raw_nl_a, llvmlite.Ptr(pool, nl_ty_a)) + case llvmlite.LLVMType.Array(_, _): + obj_ptr = llvmlite.build_bitcast( + builder, raw_nl_a, llvmlite.Ptr(pool, nl_ty_a)) + case _: + nl_val_ptr_a: llvmlite.Value | t.CPtr = \ + llvmlite.build_bitcast( + builder, raw_nl_a, llvmlite.Ptr(pool, nl_ty_a)) + if nl_val_ptr_a is not None: + obj_ptr = llvmlite.build_load( + builder, nl_ty_a, nl_val_ptr_a) + else: + obj_ptr = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id) + + # 模块属性访问 (写路径): sys._mbuddy = mb / os._win32._mbuddy = v + # → store 到模块全局变量。当 obj 是已导入模块名(Name 或嵌套 Attribute + # 模块路径)且不是普通变量时,查找/创建全局变量引用。 + if obj_ptr is None and trans is not None: + mod_path_c: str = self._attr_module_path_str(pool, at.value) + if mod_path_c is not None: + # CDefine 常量不可写: 报 FATAL 错误,不创建未定义全局 + # (仅单层 Name 模块可精确判 CDefine) + if at.value.kind() == ast.ASTKind.Name: + nm_wma: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm_wma.id is not None: + if self.Gen.ExprGenCdef._is_cdefine_name_pattern(at.attr) != 0: + err_buf_wma: str = pool.alloc(256) + if err_buf_wma is not None: + viperlib.snprintf(err_buf_wma, 256, + "[CD] FATAL: Cannot assign to CDefine constant '%s.%s'\n", + nm_wma.id, at.attr) + VLogger.error(err_buf_wma, "CD") + return None + # 使用 i8* 作为类型提示 (模块级变量通常存储指针) + i8_ptr_w: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + wma_ref: llvmlite.Value | t.CPtr = self._resolve_module_attribute_global( + pool, mod, trans, at, i8_ptr_w) + if wma_ref is not None: + return wma_ref + + # 非 Name 路径:翻译对象值(会 load) + if obj_ptr is None: + # c.Deref(ptr).attr: 属性写入 base 取指针本身而非 load 后的结构体值 + # (如 c.Deref(p).a = val 语义是 (*p).a = val,直接对 p 做 GEP) + cd_base_wr: llvmlite.Value | t.CPtr = self._get_cderef_attr_base( + builder, pool, mod, at.value, trans) + if cd_base_wr is not None: + obj_ptr = cd_base_wr + elif at.value.kind() == ast.ASTKind.Subscript: + # 下标基座属性写入(如 pts[0].x = val):list[T]/OOP __getitem__ 类走 + # translate_value(返回元素值/地址);普通结构体指针数组走 + # get_subscript_ptr(GEP 元素地址,避免结构体值 base=非指针 报错) + if self._sub_base_uses_getitem(pool, mod, trans, at.value) != 0: + obj_ptr = self.Gen.ExprGen.translate_value(builder, pool, mod, at.value, None, 0, trans) + else: + obj_ptr = self.Gen.ExprGenName.get_subscript_ptr(builder, pool, mod, at.value, trans) + elif at.value.kind() == ast.ASTKind.Attribute: + # 嵌套属性基座写入(如 r.origin.x = val):取内层字段地址 + # (get_attribute_ptr 递归,地址语义),指针字段由 _deref_if_ptr_ptr 解引用 + obj_ptr = self.get_attribute_ptr(builder, pool, mod, at.value, trans) + if obj_ptr is None: + obj_ptr = self.Gen.ExprGen.translate_value(builder, pool, mod, at.value, None, 0, trans) + else: + obj_ptr = self.Gen.ExprGen.translate_value(builder, pool, mod, at.value, None, 0, trans) + + if obj_ptr is None or obj_ptr.Ty is None: + return None + + # 如果 obj_ptr 是 Ptr(Ptr(Struct))(X|t.CPtr 变量的 alloca), + # load 解引用获取 Ptr(Struct) + obj_ptr = self._deref_if_ptr_ptr(builder, obj_ptr) + + match obj_ptr.Ty: + case llvmlite.LLVMType.Ptr(struct_ty): + # 确保跨模块结构体的完整定义在当前模块中可用(供 getelementptr 访问字段) + # 与 translate_attribute 一致,避免 opaque 类型导致 GEP 报错 + self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, struct_ty) + field_info: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field( + struct_ty, at.attr) + # 按需过滤: struct_ty 为 i8(简化联合类型)时,通过 AnnotClassName 按类名查找 + # 传递 SHA1 以区分跨模块同名类 + # base 注解类名提取:Name → 变量注解类名;Attribute → 属性链递归字段注解类名 + # (如 lx.tokens_tail.next = tok:lx 的注解 Lexer → tokens_tail 字段注解 Token) + if field_info is None: + base_class: str = None + if at.value.kind() == ast.ASTKind.Name and trans is not None: + nm_fb: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm_fb.id is not None: + var_entry: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, nm_fb.id) + if var_entry is not None: + base_class = var_entry.AnnotClassName + elif at.value.kind() == ast.ASTKind.Attribute: + base_class = self._resolve_attr_field_class(pool, trans, at.value) + if base_class is not None: + cur_sha1: str = None + if trans is not None: + cur_sha1 = trans.ModuleSha1 + field_info = self.Gen.StructGen.lookup_field_by_class( + base_class, at.attr, cur_sha1) + # REnum 变体字段别名回退(同 translate_attribute L5046-5062): + # get_attribute_ptr 赋值路径的按需过滤同样需要——struct_ty 简化 + # i8 时主路径 REnum 别名查找被跳过(LLVMType.Pointee 报错根因) + if field_info is None \ + and self.Gen.ClassGenEnum._is_renum_class_name(base_class) != 0: + rn_alias_g: int = self.Gen.ClassGenEnum._lookup_renum_field_alias( + base_class, at.attr) + if rn_alias_g >= 1: + rn_se_g: GenTypes.StructEntry | t.CPtr = \ + self.Gen.StructGen.find_struct(base_class) + if rn_se_g is not None: + rn_fe_g: GenTypes.FieldEntry | t.CPtr = \ + self.Gen.StructGen._get_field_entry(rn_se_g, rn_alias_g) + if rn_fe_g is not None and rn_fe_g.Ty is not None: + field_info = rn_fe_g + # 按需过滤成功:bitcast obj_ptr 到 AnnotClassName 对应的结构体类型 + # 原始 struct_ty 可能是 i8(X|t.CPtr 简化为 Ptr(i8)), + # 需用实际结构体类型做 GEP,否则 GEP i8 失败 + if field_info is not None: + annot_se: GenTypes.StructEntry | t.CPtr = \ + self.Gen.StructGen.find_struct(base_class) + if annot_se is not None and annot_se.Ty is not None: + annot_ptr_ty: llvmlite.LLVMType | t.CPtr = \ + llvmlite.Ptr(pool, annot_se.Ty) + casted_ptr: llvmlite.Value | t.CPtr = \ + llvmlite.build_bitcast(builder, obj_ptr, annot_ptr_ty) + if casted_ptr is not None: + obj_ptr = casted_ptr + struct_ty = annot_se.Ty + # 按需过滤更新 struct_ty 后,需重新确保 + # 注解类型结构体定义在当前模块可用 + self.Gen.StructGen.ensure_struct_def_in_module( + pool, mod, annot_se.Ty) + if field_info is not None: + # 联合体:bitcast obj_ptr 到 field_ty*(字段指针用于 store) + if self.Gen.StructGen.is_union_by_type(struct_ty) == 1: + field_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, field_info.Ty) + return llvmlite.build_bitcast(builder, obj_ptr, field_ptr_ty) + # 普通结构体:GEP 获取字段指针 + return llvmlite.build_gep_struct( + builder, struct_ty, field_info.Ty, obj_ptr, field_info.Index) + # fast-fail: 字段未找到,立即终止编译(不再打印诊断后返回 None) + # Phase A 依赖未就绪(_deps_pending,父类/依赖类未注册致字段缺失, + # 如 Generator.vp 先于 TypeGenMixin.vp 编译时 self.TraceFrames): + # 跳过本属性写入交给下遍重译(对齐 HandlesAssign L69-78), + # 避免 fail-fast 中断多遍收敛;依赖就绪后仍缺失则走下方真实报错。 + if trans is not None and trans._deps_pending != 0: + return None + if trans is not None: + diag_annot_g: str = None + diag_var_nm_g: str = None + if at.value is not None and at.value.kind() == ast.ASTKind.Name: + dnm_g: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + diag_var_nm_g = dnm_g.id + if dnm_g.id is not None: + dve_g: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, dnm_g.id) + if dve_g is not None: + diag_annot_g = dve_g.AnnotClassName + diag_var_txt_g: str = "?" + if diag_var_nm_g is not None: + diag_var_txt_g = diag_var_nm_g + diag_annot_txt_g: str = "None" + if diag_annot_g is not None: + diag_annot_txt_g = diag_annot_g + sha1_attr_g: str = "?" + if trans.ModuleSha1 is not None: + sha1_attr_g = trans.ModuleSha1 + self.Gen.TypeGenErr.fatal_error( + at, + f"属性写入失败: .{at.attr} (var={diag_var_txt_g} annot={diag_annot_txt_g} sha1={sha1_attr_g})", + "TypeError") + return None + case _: + # fast-fail: 对非指针类型做属性写入(如 i32.x = ...), + # Python traceback 立即终止,不静默返回 None(否则下游 "store to None" 崩溃) + attr_nm_gp: str = "?" + if at is not None and at.attr is not None: + attr_nm_gp = at.attr + sha1_gp: str = "?" + if trans is not None and trans.ModuleSha1 is not None: + sha1_gp = trans.ModuleSha1 + ln_gp: int = 0 + if at is not None and at.lineno is not None: + ln_gp = at.lineno + self.Gen.TypeGenErr.fatal_error( + at, + f"属性写入失败: .{attr_nm_gp} (base=非指针类型,无法做属性写入 sha1={sha1_gp}:{ln_gp})", + "TypeError") + # fatal_error 后补显式 return 样板:match 末 arm 块必须 terminated return None \ No newline at end of file diff --git a/App/lib/core/Gen/ExprGenBase.vp b/App/lib/core/Gen/ExprGenBase.vp index c3b11fb..a0a02ee 100644 --- a/App/lib/core/Gen/ExprGenBase.vp +++ b/App/lib/core/Gen/ExprGenBase.vp @@ -1,513 +1,517 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import viperlib -import w32.fileio as fileio -import lib.core.CompilerFactory as CompilerFactory -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.VLogger as VLogger -import lib.Projectrans.Config as Config -import lib.Projectrans.Utils as Utils -import lib.core.Handles.ExprCallBase as ExprCallBase - - -# ============================================================ -# ExprGenBase - ExprGenMixin 拆分(阶段 D):表达式基础工具(类型判断/指针层级/coerce) -# -# 最底层 Base(ExprGenMixin/Const/Fstr/Ops/Cdef/Name/Attr/Cls 均 1 级继承本类)。 -# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class ExprGenBase: - """表达式基础工具(类型判断/指针层级/coerce)""" - - # --- docstring 登记表字段(__doc__ 魔法属性支持)--- - DocKeys: bytes - DocValues: bytes - DocCount: int - - # --- OOM 诊断:跨模块 CDefine 查找调用计数(CONST_INT 参数翻译疑似循环查找) --- - DiagCDefineCount: int - # --- OOM 诊断:translate_name_value 调用计数(顶层 CDefine 查找 14593 次来源) --- - DiagNameValueCount: int - # --- OOM 诊断:translate_value 调用计数(CONST_INT 循环调用源定位) --- - DiagTranslateValueCount: int - # ============================================================ - # P3 迁移方法(函数体来自 HandlesExpr.vp 模块级函数, - # 本模块函数调用改 self.,外部模块调用保留模块前缀) - # ============================================================ - - # ============================================================ - # 从 AST 节点提取函数名 - # ============================================================ - def get_func_name(self, func_node: ast.AST | t.CPtr) -> str: - """从函数节点提取函数名""" - if func_node is None: - return None - k: int = func_node.kind() - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(func_node) - return nm.id - elif k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(func_node) - return at.attr - return None - # ============================================================ - # 转义 LLVM IR 字符串字面量 - # ============================================================ - def escape_llvm_string(self, pool: memhub.MemBuddy | t.CPtr, - src: str) -> str: - """将字符串转换为 LLVM IR 字符串字面量 c"...\\00" """ - if src is None: - return None - slen: t.CSizeT = string.strlen(src) - alloc_size: t.CSizeT = 4 * slen + 8 - buf: str = pool.alloc(alloc_size) - if buf is None: - return None - pos: t.CSizeT = 0 - buf[pos] = 'c' - pos += 1 - buf[pos] = '"' - pos += 1 - for i in range(slen): - ch: t.CChar = src[i] - if ch == '\0': - break - if ch == '\"' or ch == '\\' or ch < 0x20: - buf[pos] = '\\' - pos += 1 - hi: int = (ch >> 4) & 0xF - lo: int = ch & 0xF - buf[pos] = Utils.nibble_to_hex_char(hi, 1) - pos += 1 - buf[pos] = Utils.nibble_to_hex_char(lo, 1) - pos += 1 - else: - buf[pos] = ch - pos += 1 - buf[pos] = '\\' - pos += 1 - buf[pos] = '0' - pos += 1 - buf[pos] = '0' - pos += 1 - buf[pos] = '"' - pos += 1 - buf[pos] = '\0' - return buf - # ============================================================ - # 获取 LLVM 整数类型的位宽 - # ============================================================ - 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 - # ============================================================ - # 获取 LLVM 浮点类型的位宽 - # ============================================================ - def get_llvm_float_bits(self, ty: llvmlite.LLVMType | t.CPtr) -> int: - """获取 LLVM 浮点类型的位宽,非浮点类型返回 0""" - if ty is None: - return 0 - match ty: - case llvmlite.LLVMType.Float(bits): - return bits - case _: - return 0 - # ============================================================ - # is_ptr_type - 检查类型是否为 Ptr - # - # 返回 1=是, 0=否。作为类型检查工具函数被广泛使用(50+ 处调用)。 - # ============================================================ - def is_ptr_type(self, ty: llvmlite.LLVMType | t.CPtr) -> int: - """检查 ty 是否是 Ptr 类型,返回 1=是, 0=否""" - if ty is None: - return 0 - match ty: - case llvmlite.LLVMType.Ptr(pointee): - return 1 - case _: - return 0 - # ============================================================ - # get_ptr_level - 计算指针层级 - # - # 返回值: - # 0 = 非指针(数值/结构体等) - # 1 = 一级指针(如 i8*, Struct*) - # 2 = 二级指针(如 i8**, Struct**) - # 3+ = 更高级指针 - # - # 用于比较运算的类型安全检查: - # - 数值(0) vs 数值(0) → 允许 - # - 一级指针(1) vs 一级指针(1) → 允许 - # - 数值(0) vs 指针(1+) → 禁止(fast-fail) - # - 不同级指针(1 vs 2) → 禁止(fast-fail) - # ============================================================ - def get_ptr_level(self, ty: llvmlite.LLVMType | t.CPtr) -> int: - """计算指针层级,0=非指针, 1=一级指针, 2=二级指针...""" - if ty is None: - return 0 - level: int = 0 - cur: llvmlite.LLVMType | t.CPtr = ty - while cur is not None: - match cur: - case llvmlite.LLVMType.Ptr(pointee): - level += 1 - cur = pointee - case _: - break - return level - # ============================================================ - # _is_zero_int_literal - 判断 AST 节点是否为整数字面量 0 - # - # 用于指针判空比较(ptr != 0 / ptr == 0):指针与字面量 0 比较时 - # 0 视为 NULL,允许并转成 null 指针(比较类型检查的例外)。 - # ============================================================ - def _is_zero_int_literal(self, node: ast.AST | t.CPtr) -> int: - """判断节点是否为整数字面量 0,返回 1=是 / 0=否""" - if node is None: - return 0 - if node.kind() != ast.ASTKind.Constant: - return 0 - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) - if cn is None or cn.const_kind != ast.CONST_INT: - return 0 - if cn.int_val == 0: - return 1 - return 0 - # ============================================================ - # is_array_type - 检查类型是否为 Array - # - # 返回 1=是, 0=否。类型检查工具函数。 - # ============================================================ - def is_array_type(self, ty: llvmlite.LLVMType | t.CPtr) -> int: - """检查 ty 是否是 Array 类型,返回 1=是, 0=否""" - if ty is None: - return 0 - match ty: - case llvmlite.LLVMType.Array(_, _): - return 1 - case _: - return 0 - # ============================================================ - # _zext_index_to_i32 - 数组下标索引零扩展 - # - # LLVM GEP 对窄整数索引默认符号扩展:i8 0xE2(226) 会被当成 -30, - # 导致数组下标越界读(字节 >= 128 的乱码根因)。 - # 数组下标语义为非负,<32 位整数索引一律 zext 到 i32。 - # 仅用于数组 GEP;指针负偏移(p[-1])不经过此路径,不受影响。 - # ============================================================ - def _zext_index_to_i32(self, builder: llvmlite.IRBuilder | t.CPtr, - idx_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: - """将 <32 位整数下标零扩展到 i32(数组下标非负语义)""" - if idx_val is None or idx_val.Ty is None or builder is None: - return idx_val - idx_bits: int = self.get_llvm_type_bits(idx_val.Ty) - if idx_bits != 0 and idx_bits < 32: - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(builder.Pool) - return llvmlite.build_zext(builder, idx_val, i32_ty) - return idx_val - # ============================================================ - # _get_custom_struct_cls_nm - 检查类型是否为已注册的自定义结构体 - # - # 处理两种情况: - # - ty 直接是 Struct → 检查是否注册 - # - ty 是 Ptr(Struct) → 检查 pointee 是否注册 - # - # 返回类名字符串或 None。用于 subscript 操作中判断是否需要 - # 转发到 __getitem__/__setitem__ 而非生成 GEP。 - # ============================================================ - def _get_custom_struct_cls_nm(self, pool: memhub.MemBuddy | t.CPtr, - ty: llvmlite.LLVMType | t.CPtr) -> str: - """检查 ty 或 ty 的 pointee 是否是已注册的自定义结构体,返回类名或 None""" - if ty is None: - return None - # 直接检查 ty 是否是注册的结构体 - cls_nm_direct: str = HandlesStruct.get_class_name_by_type(pool, ty) - if cls_nm_direct is not None: - return cls_nm_direct - # 如果 ty 是 Ptr,检查 pointee - if self.is_ptr_type(ty) != 0: - pointee_cs: llvmlite.LLVMType | t.CPtr = ty.Pointee - if pointee_cs is not None: - return HandlesStruct.get_class_name_by_type(pool, pointee_cs) - return None - # ============================================================ - # _is_list_subscript_base - 判断下标基座是否为 list[T] 变量 - # - # 属性访问的 Subscript 基座(如 lst[i].x)需要区分: - # - list[T] 变量:translate_subscript 走 __getitem__ 内联返回元素地址 - # - 普通结构体指针数组(如 pts: Point | t.CPtr):get_subscript_ptr 返回元素地址 - # 路由错误会让 list[T] 被当作结构体数组 GEP,访问错位崩溃。 - # ============================================================ - def _is_list_subscript_base(self, pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - sub_node: ast.AST | t.CPtr) -> int: - """判断下标基座是否为 list[T] 变量(1=是)""" - if sub_node is None or trans is None: - return 0 - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sub_node) - if sub is None or sub.value is None or sub.value.kind() != ast.ASTKind.Name: - return 0 - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) - if nm.id is None: - return 0 - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is None or alloca.Ty is None: - return 0 - if self.is_ptr_type(alloca.Ty) == 0: - return 0 - pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee - if pointee is None: - return 0 - match pointee: - case llvmlite.LLVMType.Ptr(inner_ty): - lsn_ls: str = None - match inner_ty: - case llvmlite.LLVMType.Struct(_, _, lsn3): - lsn_ls = lsn3 - case _: - pass - if lsn_ls is not None and string.strstr(lsn_ls, "list[") is not None: - return 1 - case _: - pass - return 0 - # ============================================================ - # _sub_base_class_name - 解析下标基座变量的结构体类名 - # ============================================================ - def _sub_base_class_name(self, pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - sub_node: ast.AST | t.CPtr) -> str: - """解析下标基座变量的结构体类名(无则 None)""" - if sub_node is None or trans is None: - return None - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sub_node) - if sub is None or sub.value is None or sub.value.kind() != ast.ASTKind.Name: - return None - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) - if nm.id is None: - return None - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is None or alloca.Ty is None: - return None - if self.is_ptr_type(alloca.Ty) == 0: - return None - pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee - if pointee is None: - return None - if self.is_ptr_type(pointee) != 0: - inner: llvmlite.LLVMType | t.CPtr = pointee.Pointee - if inner is not None: - return HandlesStruct.get_class_name_by_type(pool, inner) - return HandlesStruct.get_class_name_by_type(pool, pointee) - # ============================================================ - # _sub_base_uses_getitem - 下标基座是否应走 __getitem__ 语义 - # - # 属性访问的 Subscript 基座路由依据: - # - list[T] / OOP 定义 __getitem__ 的类(如 dict[key])→ translate_value - # (translate_subscript 走 __getitem__ 内联/方法调用返回元素值或地址) - # - 普通结构体指针数组(如 pts: Point | t.CPtr)→ get_subscript_ptr - # (GEP 元素地址,避免结构体值 base=非指针 报错) - # ============================================================ - def _sub_base_uses_getitem(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - trans: HT.Translator | t.CPtr, - sub_node: ast.AST | t.CPtr) -> int: - """下标基座应走 __getitem__ 语义时返回 1,否则 0(应走 GEP 地址语义)""" - if self._is_list_subscript_base(pool, trans, sub_node) != 0: - return 1 - cls_ugi: str = self._sub_base_class_name(pool, trans, sub_node) - if cls_ugi is None: - return 0 - lookup_ugi: str = pool.alloc(128) - if lookup_ugi is None: - return 0 - viperlib.snprintf(lookup_ugi, 128, "%s.__getitem__", cls_ugi) - if ExprCallBase.find_func_in_module(mod, lookup_ugi) is not None: - return 1 - return 0 - # ============================================================ - # _deref_if_ptr_ptr - 如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用 - # - # 用于支持 X|t.CPtr 类型变量的属性访问: - # - 值类型变量 (cnt: Counter): alloca 类型是 Ptr(Struct) → 不解引用 - # - 指针类型变量 (r: Vec2|t.CPtr): alloca 类型是 Ptr(Ptr(Struct)) → load 解引用 - # ============================================================ - def _deref_if_ptr_ptr(self, builder: llvmlite.IRBuilder | t.CPtr, - obj_ptr: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: - """如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用获取内层指针""" - if obj_ptr is None or obj_ptr.Ty is None: - return obj_ptr - if self.is_ptr_type(obj_ptr.Ty) == 0: - return obj_ptr - pointee: llvmlite.LLVMType | t.CPtr = obj_ptr.Ty.Pointee - if pointee is None: - return obj_ptr - if self.is_ptr_type(pointee) == 0: - return obj_ptr - # obj_ptr 是 Ptr(Ptr(...)),load 解引用 - loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, pointee, obj_ptr) - if loaded is None: - return obj_ptr - return loaded - # ============================================================ - # 类型强制转换:整数 sext/trunc,浮点 fpext/fptrunc,int↔float si2fp/fp2si - # ============================================================ - def coerce_to_type(self, builder: llvmlite.IRBuilder | t.CPtr, - val: llvmlite.Value | t.CPtr, - target_ty: llvmlite.LLVMType | t.CPtr, - node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """将 val 强制转换为 target_ty - - 整数: sext(扩展)/ trunc(截断) - 浮点: fpext(扩展)/ fptrunc(截断) - int→float: sitofp - float→int: fptosi - - node: AST 节点(用于错误定位),可为 None - """ - if val is None or target_ty is None: - return val - # 函数 → 指针: bitcast(如 CreateThread(..., _thread_alloc_free, ...) 传函数指针) - # 函数 Value 的 Ty 是 Func,既不是整数也不是指针,需在整数/浮点转换之前处理 - match val.Ty: - case llvmlite.LLVMType.Func(_, _, _): - if self.is_ptr_type(target_ty) != 0: - return llvmlite.build_bitcast(builder, val, target_ty) - return val - case _: - pass - # 整数转换 - val_bits: int = self.get_llvm_type_bits(val.Ty) - target_bits: int = self.get_llvm_type_bits(target_ty) - # 整数 → 指针: inttoptr(必须在纯整数转换之前检查,因为 ptr 的 bits 非零会误入 sext/trunc 路径) - # 适用于: 跨模块方法返回 i64/i32(默认推断),目标变量是指针类型 - if val_bits != 0 and self.is_ptr_type(target_ty) != 0: - return llvmlite.build_inttoptr(builder, val, target_ty) - # 指针 → 整数: ptrtoint(当目标明确是整数而非指针时) - # 注意: target_bits == 8 时跳过 ptrtoint,走后面的 build_load 解引用首字符 - # 修复: buf[idx] = '\0' 中 '\0' 是 CONST_STR → i8* 指针, - # ptrtoint 会截断地址低 8 位(非 0),应 load 解引用取首字符 0 - if self.is_ptr_type(val.Ty) != 0 and target_bits != 0 and target_bits != 8 and self.is_ptr_type(target_ty) == 0: - return llvmlite.build_ptrtoint(builder, val, target_ty) - if val_bits != 0 and target_bits != 0: - if val_bits == target_bits: - return val - if val_bits < target_bits: - # i1 (bool) → 更宽整数用 zext(bool 语义:1 保持 1,而非 sext 的 0xFF...) - # 与 HandlesReturn 中 return 语句的 i1 扩展规则保持一致 - if val_bits == 1: - return llvmlite.build_zext(builder, val, target_ty) - return llvmlite.build_sext(builder, val, target_ty) - return llvmlite.build_trunc(builder, val, target_ty) - # 浮点转换 - val_fbits: int = self.get_llvm_float_bits(val.Ty) - target_fbits: int = self.get_llvm_float_bits(target_ty) - # float ↔ ptr: 禁止(无意义的转换,fast-fail 防止误走入 build_load 路径) - if (val_fbits != 0 and self.is_ptr_type(target_ty) != 0) or \ - (self.is_ptr_type(val.Ty) != 0 and target_fbits != 0): - HandlesType.fatal_error(node, "unsupported type conversion: float <-> ptr", "CastError") - return val - if val_fbits != 0 and target_fbits != 0: - if val_fbits == target_fbits: - return val - if val_fbits < target_fbits: - return llvmlite.build_fpext(builder, val, target_ty) - return llvmlite.build_fptrunc(builder, val, target_ty) - # int → float - if val_bits != 0 and target_fbits != 0: - return llvmlite.build_si2fp(builder, val, target_ty) - # float → int - if val_fbits != 0 and target_bits != 0: - return llvmlite.build_fp2si(builder, val, target_ty) - # 指针 → 非指针值: build_load 解引用 - # 适用于: 指针 → 整数 (如 i8* → i8), 指针 → 结构体值 - # 当构造器返回 Ptr(Struct) 但目标变量是 Struct 值类型时,需要 load - if self.is_ptr_type(val.Ty) != 0 and self.is_ptr_type(target_ty) == 0: - return llvmlite.build_load(builder, target_ty, val) - # 指针 → 指针: bitcast (如 i8* → i8** 当目标是全局变量存储指针) - if self.is_ptr_type(val.Ty) != 0 and self.is_ptr_type(target_ty) != 0: - return llvmlite.build_bitcast(builder, val, target_ty) - return val - # ============================================================ - # translate_ptr_arith - 指针算术: ptr + int / ptr - int - # - # 用 getelementptr(按 pointee 元素大小缩放索引),对齐 TPC - # ExprGen.emit_binary_op / HandlesAugAssign.py。 - # 旧实现用 ptrtoint + add + inttoptr(按字节加):i8* 元素大小 1 - # 恰好正确,但 i32*/struct* 等指针 `p + 3` 只前进 3 字节(应 12), - # 导致 StringIterTest Test 4/8 失败(指针偏移/指针算术)。 - # - # 数组 pointee([N x ty]*)先 decay 为元素指针(GEP 0,0), - # 避免以整个数组为步长(对齐 TPC ExprGen L53-55)。 - # ============================================================ - def translate_ptr_arith(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - ptr_val: llvmlite.Value | t.CPtr, - int_val: llvmlite.Value | t.CPtr, - op: int) -> llvmlite.Value | t.CPtr: - """指针算术: ptr + int / ptr - int → GEP(按元素大小缩放索引)""" - if ptr_val is None or int_val is None or ptr_val.Ty is None: - return None - # 提取 pointee 类型(非指针 → 不处理返回 None) - elem_ty: llvmlite.LLVMType | t.CPtr = None - match ptr_val.Ty: - case llvmlite.LLVMType.Ptr(pointee): - elem_ty = pointee - case _: - return None - if elem_ty is None: - return None - # 索引统一到 i64(对齐 TPC zext 到 i64) - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - idx: llvmlite.Value | t.CPtr = self.coerce_to_type(builder, int_val, i64_ty, None) - if idx is None: - return None - # ptr - int → 负索引(LLVM GEP 索引为加法语义) - if op == ast.OpKind.Sub: - neg_idx: llvmlite.Value | t.CPtr = llvmlite.build_sub( - builder, llvmlite.const_int64(pool, 0), idx) - if neg_idx is None: - return None - idx = neg_idx - # 数组 pointee → 先 decay 为元素指针(getelementptr [N x ty], [N x ty]* %p, i32 0, i32 0) - if self.is_array_type(elem_ty) != 0: - inner_ty: llvmlite.LLVMType | t.CPtr = None - match elem_ty: - case llvmlite.LLVMType.Array(inner, _): - inner_ty = inner - case _: - return None - if inner_ty is None: - return None - decayed: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, elem_ty, inner_ty, ptr_val, llvmlite.const_int64(pool, 0)) - if decayed is None: - return None - return llvmlite.build_gep(builder, inner_ty, decayed, idx) - return llvmlite.build_gep(builder, elem_ty, ptr_val, idx) \ No newline at end of file +import lib.core.Gen.Generator as Generator +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import w32.fileio as fileio +import lib.core.CompilerFactory as CompilerFactory +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.StubMerger as StubMerger +import lib.core.VLogger as VLogger +import lib.Projectrans.Config as Config +import lib.Projectrans.Utils as Utils + + +# ============================================================ +# ExprGenBase - ExprGenMixin 拆分(阶段 D):表达式基础工具(类型判断/指针层级/coerce) +# +# 最底层 Base(ExprGenMixin/Const/Fstr/Ops/Cdef/Name/Attr/Cls 均 1 级继承本类)。 +# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class ExprGenBase: + """表达式基础工具(类型判断/指针层级/coerce)""" + + # --- docstring 登记表字段(__doc__ 魔法属性支持)--- + Gen: Generator.Generator | t.CPtr + DocKeys: bytes + DocValues: bytes + DocCount: int + + # --- OOM 诊断:跨模块 CDefine 查找调用计数(CONST_INT 参数翻译疑似循环查找) --- + DiagCDefineCount: int + # --- OOM 诊断:translate_name_value 调用计数(顶层 CDefine 查找 14593 次来源) --- + DiagNameValueCount: int + # --- OOM 诊断:translate_value 调用计数(CONST_INT 循环调用源定位) --- + DiagTranslateValueCount: int + # ============================================================ + # P3 迁移方法(函数体来自 HandlesExpr.vp 模块级函数, + # 本模块函数调用改 self.,外部模块调用保留模块前缀) + # ============================================================ + + # ============================================================ + # 从 AST 节点提取函数名 + # ============================================================ + def get_func_name(self, func_node: ast.AST | t.CPtr) -> str: + """从函数节点提取函数名""" + if func_node is None: + return None + k: int = func_node.kind() + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(func_node) + return nm.id + elif k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(func_node) + return at.attr + return None + # ============================================================ + # 转义 LLVM IR 字符串字面量 + # ============================================================ + def escape_llvm_string(self, pool: memhub.MemBuddy | t.CPtr, + src: str) -> str: + """将字符串转换为 LLVM IR 字符串字面量 c"...\\00" """ + if src is None: + return None + slen: t.CSizeT = string.strlen(src) + alloc_size: t.CSizeT = 4 * slen + 8 + buf: str = pool.alloc(alloc_size) + if buf is None: + return None + pos: t.CSizeT = 0 + buf[pos] = 'c' + pos += 1 + buf[pos] = '"' + pos += 1 + for i in range(slen): + ch: t.CChar = src[i] + if ch == '\0': + break + if ch == '\"' or ch == '\\' or ch < 0x20: + buf[pos] = '\\' + pos += 1 + hi: int = (ch >> 4) & 0xF + lo: int = ch & 0xF + buf[pos] = Utils.nibble_to_hex_char(hi, 1) + pos += 1 + buf[pos] = Utils.nibble_to_hex_char(lo, 1) + pos += 1 + else: + buf[pos] = ch + pos += 1 + buf[pos] = '\\' + pos += 1 + buf[pos] = '0' + pos += 1 + buf[pos] = '0' + pos += 1 + buf[pos] = '"' + pos += 1 + buf[pos] = '\0' + return buf + # ============================================================ + # 获取 LLVM 整数类型的位宽 + # ============================================================ + 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 + # ============================================================ + # 获取 LLVM 浮点类型的位宽 + # ============================================================ + def get_llvm_float_bits(self, ty: llvmlite.LLVMType | t.CPtr) -> int: + """获取 LLVM 浮点类型的位宽,非浮点类型返回 0""" + if ty is None: + return 0 + match ty: + case llvmlite.LLVMType.Float(bits): + return bits + case _: + return 0 + # ============================================================ + # is_ptr_type - 检查类型是否为 Ptr + # + # 返回 1=是, 0=否。作为类型检查工具函数被广泛使用(50+ 处调用)。 + # ============================================================ + def is_ptr_type(self, ty: llvmlite.LLVMType | t.CPtr) -> int: + """检查 ty 是否是 Ptr 类型,返回 1=是, 0=否""" + if ty is None: + return 0 + match ty: + case llvmlite.LLVMType.Ptr(pointee): + return 1 + case _: + return 0 + # ============================================================ + # get_ptr_level - 计算指针层级 + # + # 返回值: + # 0 = 非指针(数值/结构体等) + # 1 = 一级指针(如 i8*, Struct*) + # 2 = 二级指针(如 i8**, Struct**) + # 3+ = 更高级指针 + # + # 用于比较运算的类型安全检查: + # - 数值(0) vs 数值(0) → 允许 + # - 一级指针(1) vs 一级指针(1) → 允许 + # - 数值(0) vs 指针(1+) → 禁止(fast-fail) + # - 不同级指针(1 vs 2) → 禁止(fast-fail) + # ============================================================ + def get_ptr_level(self, ty: llvmlite.LLVMType | t.CPtr) -> int: + """计算指针层级,0=非指针, 1=一级指针, 2=二级指针...""" + if ty is None: + return 0 + level: int = 0 + cur: llvmlite.LLVMType | t.CPtr = ty + while cur is not None: + match cur: + case llvmlite.LLVMType.Ptr(pointee): + level += 1 + cur = pointee + case _: + break + return level + # ============================================================ + # _is_zero_int_literal - 判断 AST 节点是否为整数字面量 0 + # + # 用于指针判空比较(ptr != 0 / ptr == 0):指针与字面量 0 比较时 + # 0 视为 NULL,允许并转成 null 指针(比较类型检查的例外)。 + # ============================================================ + def _is_zero_int_literal(self, node: ast.AST | t.CPtr) -> int: + """判断节点是否为整数字面量 0,返回 1=是 / 0=否""" + if node is None: + return 0 + if node.kind() != ast.ASTKind.Constant: + return 0 + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + if cn is None or cn.const_kind != ast.CONST_INT: + return 0 + if cn.int_val == 0: + return 1 + return 0 + # ============================================================ + # is_array_type - 检查类型是否为 Array + # + # 返回 1=是, 0=否。类型检查工具函数。 + # ============================================================ + def is_array_type(self, ty: llvmlite.LLVMType | t.CPtr) -> int: + """检查 ty 是否是 Array 类型,返回 1=是, 0=否""" + if ty is None: + return 0 + match ty: + case llvmlite.LLVMType.Array(_, _): + return 1 + case _: + return 0 + # ============================================================ + # _zext_index_to_i32 - 数组下标索引零扩展 + # + # LLVM GEP 对窄整数索引默认符号扩展:i8 0xE2(226) 会被当成 -30, + # 导致数组下标越界读(字节 >= 128 的乱码根因)。 + # 数组下标语义为非负,<32 位整数索引一律 zext 到 i32。 + # 仅用于数组 GEP;指针负偏移(p[-1])不经过此路径,不受影响。 + # ============================================================ + def _zext_index_to_i32(self, builder: llvmlite.IRBuilder | t.CPtr, + idx_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: + """将 <32 位整数下标零扩展到 i32(数组下标非负语义)""" + if idx_val is None or idx_val.Ty is None or builder is None: + return idx_val + idx_bits: int = self.get_llvm_type_bits(idx_val.Ty) + if idx_bits != 0 and idx_bits < 32: + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(builder.Pool) + return llvmlite.build_zext(builder, idx_val, i32_ty) + return idx_val + # ============================================================ + # _get_custom_struct_cls_nm - 检查类型是否为已注册的自定义结构体 + # + # 处理两种情况: + # - ty 直接是 Struct → 检查是否注册 + # - ty 是 Ptr(Struct) → 检查 pointee 是否注册 + # + # 返回类名字符串或 None。用于 subscript 操作中判断是否需要 + # 转发到 __getitem__/__setitem__ 而非生成 GEP。 + # ============================================================ + def _get_custom_struct_cls_nm(self, pool: memhub.MemBuddy | t.CPtr, + ty: llvmlite.LLVMType | t.CPtr) -> str: + """检查 ty 或 ty 的 pointee 是否是已注册的自定义结构体,返回类名或 None""" + if ty is None: + return None + # 直接检查 ty 是否是注册的结构体 + cls_nm_direct: str = self.Gen.StructGen.get_class_name_by_type(pool, ty) + if cls_nm_direct is not None: + return cls_nm_direct + # 如果 ty 是 Ptr,检查 pointee + if self.is_ptr_type(ty) != 0: + pointee_cs: llvmlite.LLVMType | t.CPtr = ty.Pointee + if pointee_cs is not None: + return self.Gen.StructGen.get_class_name_by_type(pool, pointee_cs) + return None + # ============================================================ + # _is_list_subscript_base - 判断下标基座是否为 list[T] 变量 + # + # 属性访问的 Subscript 基座(如 lst[i].x)需要区分: + # - list[T] 变量:translate_subscript 走 __getitem__ 内联返回元素地址 + # - 普通结构体指针数组(如 pts: Point | t.CPtr):get_subscript_ptr 返回元素地址 + # 路由错误会让 list[T] 被当作结构体数组 GEP,访问错位崩溃。 + # ============================================================ + def _is_list_subscript_base(self, pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr, + sub_node: ast.AST | t.CPtr) -> int: + """判断下标基座是否为 list[T] 变量(1=是)""" + if sub_node is None or trans is None: + return 0 + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sub_node) + if sub is None or sub.value is None or sub.value.kind() != ast.ASTKind.Name: + return 0 + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) + if nm.id is None: + return 0 + alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id) + if alloca is None or alloca.Ty is None: + return 0 + if self.is_ptr_type(alloca.Ty) == 0: + return 0 + pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if pointee is None: + return 0 + match pointee: + case llvmlite.LLVMType.Ptr(inner_ty): + lsn_ls: str = None + match inner_ty: + case llvmlite.LLVMType.Struct(_, _, lsn3): + lsn_ls = lsn3 + case _: + pass + if lsn_ls is not None and string.strstr(lsn_ls, "list[") is not None: + return 1 + case _: + pass + return 0 + # ============================================================ + # _sub_base_class_name - 解析下标基座变量的结构体类名 + # ============================================================ + def _sub_base_class_name(self, pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr, + sub_node: ast.AST | t.CPtr) -> str: + """解析下标基座变量的结构体类名(无则 None)""" + if sub_node is None or trans is None: + return None + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sub_node) + if sub is None or sub.value is None or sub.value.kind() != ast.ASTKind.Name: + return None + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) + if nm.id is None: + return None + alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id) + if alloca is None or alloca.Ty is None: + return None + if self.is_ptr_type(alloca.Ty) == 0: + return None + pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if pointee is None: + return None + if self.is_ptr_type(pointee) != 0: + inner: llvmlite.LLVMType | t.CPtr = pointee.Pointee + if inner is not None: + return self.Gen.StructGen.get_class_name_by_type(pool, inner) + return self.Gen.StructGen.get_class_name_by_type(pool, pointee) + # ============================================================ + # _sub_base_uses_getitem - 下标基座是否应走 __getitem__ 语义 + # + # 属性访问的 Subscript 基座路由依据: + # - list[T] / OOP 定义 __getitem__ 的类(如 dict[key])→ translate_value + # (translate_subscript 走 __getitem__ 内联/方法调用返回元素值或地址) + # - 普通结构体指针数组(如 pts: Point | t.CPtr)→ get_subscript_ptr + # (GEP 元素地址,避免结构体值 base=非指针 报错) + # ============================================================ + def _sub_base_uses_getitem(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + trans: HT.Translator | t.CPtr, + sub_node: ast.AST | t.CPtr) -> int: + """下标基座应走 __getitem__ 语义时返回 1,否则 0(应走 GEP 地址语义)""" + if self._is_list_subscript_base(pool, trans, sub_node) != 0: + return 1 + cls_ugi: str = self._sub_base_class_name(pool, trans, sub_node) + if cls_ugi is None: + return 0 + lookup_ugi: str = pool.alloc(128) + if lookup_ugi is None: + return 0 + viperlib.snprintf(lookup_ugi, 128, "%s.__getitem__", cls_ugi) + if self.Gen.CallGenBase.find_func_in_module(mod, lookup_ugi) is not None: + return 1 + return 0 + # ============================================================ + # _deref_if_ptr_ptr - 如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用 + # + # 用于支持 X|t.CPtr 类型变量的属性访问: + # - 值类型变量 (cnt: Counter): alloca 类型是 Ptr(Struct) → 不解引用 + # - 指针类型变量 (r: Vec2|t.CPtr): alloca 类型是 Ptr(Ptr(Struct)) → load 解引用 + # ============================================================ + def _deref_if_ptr_ptr(self, builder: llvmlite.IRBuilder | t.CPtr, + obj_ptr: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: + """如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用获取内层指针""" + if obj_ptr is None or obj_ptr.Ty is None: + return obj_ptr + if self.is_ptr_type(obj_ptr.Ty) == 0: + return obj_ptr + pointee: llvmlite.LLVMType | t.CPtr = obj_ptr.Ty.Pointee + if pointee is None: + return obj_ptr + if self.is_ptr_type(pointee) == 0: + return obj_ptr + # obj_ptr 是 Ptr(Ptr(...)),load 解引用 + loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, pointee, obj_ptr) + if loaded is None: + return obj_ptr + return loaded + # ============================================================ + # 类型强制转换:整数 sext/trunc,浮点 fpext/fptrunc,int↔float si2fp/fp2si + # ============================================================ + def coerce_to_type(self, builder: llvmlite.IRBuilder | t.CPtr, + val: llvmlite.Value | t.CPtr, + target_ty: llvmlite.LLVMType | t.CPtr, + node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """将 val 强制转换为 target_ty + + 整数: sext(扩展)/ trunc(截断) + 浮点: fpext(扩展)/ fptrunc(截断) + int→float: sitofp + float→int: fptosi + + node: AST 节点(用于错误定位),可为 None + """ + if val is None or target_ty is None: + return val + # 函数 → 指针: bitcast(如 CreateThread(..., _thread_alloc_free, ...) 传函数指针) + # 函数 Value 的 Ty 是 Func,既不是整数也不是指针,需在整数/浮点转换之前处理 + match val.Ty: + case llvmlite.LLVMType.Func(_, _, _): + if self.is_ptr_type(target_ty) != 0: + return llvmlite.build_bitcast(builder, val, target_ty) + return val + case _: + pass + # 整数转换 + val_bits: int = self.get_llvm_type_bits(val.Ty) + target_bits: int = self.get_llvm_type_bits(target_ty) + # 整数 → 指针: inttoptr(必须在纯整数转换之前检查,因为 ptr 的 bits 非零会误入 sext/trunc 路径) + # 适用于: 跨模块方法返回 i64/i32(默认推断),目标变量是指针类型 + if val_bits != 0 and self.is_ptr_type(target_ty) != 0: + return llvmlite.build_inttoptr(builder, val, target_ty) + # 指针 → 整数: ptrtoint(当目标明确是整数而非指针时) + # 注意: target_bits == 8 时跳过 ptrtoint,走后面的 build_load 解引用首字符 + # 修复: buf[idx] = '\0' 中 '\0' 是 CONST_STR → i8* 指针, + # ptrtoint 会截断地址低 8 位(非 0),应 load 解引用取首字符 0 + if self.is_ptr_type(val.Ty) != 0 and target_bits != 0 and target_bits != 8 and self.is_ptr_type(target_ty) == 0: + return llvmlite.build_ptrtoint(builder, val, target_ty) + if val_bits != 0 and target_bits != 0: + if val_bits == target_bits: + return val + if val_bits < target_bits: + # i1 (bool) → 更宽整数用 zext(bool 语义:1 保持 1,而非 sext 的 0xFF...) + # 与 HandlesReturn 中 return 语句的 i1 扩展规则保持一致 + if val_bits == 1: + return llvmlite.build_zext(builder, val, target_ty) + return llvmlite.build_sext(builder, val, target_ty) + return llvmlite.build_trunc(builder, val, target_ty) + # 浮点转换 + val_fbits: int = self.get_llvm_float_bits(val.Ty) + target_fbits: int = self.get_llvm_float_bits(target_ty) + # float ↔ ptr: 禁止(无意义的转换,fast-fail 防止误走入 build_load 路径) + if (val_fbits != 0 and self.is_ptr_type(target_ty) != 0) or \ + (self.is_ptr_type(val.Ty) != 0 and target_fbits != 0): + self.Gen.TypeGenErr.fatal_error(node, "unsupported type conversion: float <-> ptr", "CastError") + return val + if val_fbits != 0 and target_fbits != 0: + if val_fbits == target_fbits: + return val + if val_fbits < target_fbits: + return llvmlite.build_fpext(builder, val, target_ty) + return llvmlite.build_fptrunc(builder, val, target_ty) + # int → float + if val_bits != 0 and target_fbits != 0: + return llvmlite.build_si2fp(builder, val, target_ty) + # float → int + if val_fbits != 0 and target_bits != 0: + return llvmlite.build_fp2si(builder, val, target_ty) + # 指针 → 非指针值: build_load 解引用 + # 适用于: 指针 → 整数 (如 i8* → i8), 指针 → 结构体值 + # 当构造器返回 Ptr(Struct) 但目标变量是 Struct 值类型时,需要 load + if self.is_ptr_type(val.Ty) != 0 and self.is_ptr_type(target_ty) == 0: + return llvmlite.build_load(builder, target_ty, val) + # 指针 → 指针: bitcast (如 i8* → i8** 当目标是全局变量存储指针) + if self.is_ptr_type(val.Ty) != 0 and self.is_ptr_type(target_ty) != 0: + return llvmlite.build_bitcast(builder, val, target_ty) + return val + # ============================================================ + # translate_ptr_arith - 指针算术: ptr + int / ptr - int + # + # 用 getelementptr(按 pointee 元素大小缩放索引),对齐 TPC + # ExprGen.emit_binary_op / HandlesAugAssign.py。 + # 旧实现用 ptrtoint + add + inttoptr(按字节加):i8* 元素大小 1 + # 恰好正确,但 i32*/struct* 等指针 `p + 3` 只前进 3 字节(应 12), + # 导致 StringIterTest Test 4/8 失败(指针偏移/指针算术)。 + # + # 数组 pointee([N x ty]*)先 decay 为元素指针(GEP 0,0), + # 避免以整个数组为步长(对齐 TPC ExprGen L53-55)。 + # ============================================================ + def translate_ptr_arith(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + ptr_val: llvmlite.Value | t.CPtr, + int_val: llvmlite.Value | t.CPtr, + op: int) -> llvmlite.Value | t.CPtr: + """指针算术: ptr + int / ptr - int → GEP(按元素大小缩放索引)""" + if ptr_val is None or int_val is None or ptr_val.Ty is None: + return None + # 提取 pointee 类型(非指针 → 不处理返回 None) + elem_ty: llvmlite.LLVMType | t.CPtr = None + match ptr_val.Ty: + case llvmlite.LLVMType.Ptr(pointee): + elem_ty = pointee + case _: + return None + if elem_ty is None: + return None + # 索引统一到 i64(对齐 TPC zext 到 i64) + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + idx: llvmlite.Value | t.CPtr = self.coerce_to_type(builder, int_val, i64_ty, None) + if idx is None: + return None + # ptr - int → 负索引(LLVM GEP 索引为加法语义) + if op == ast.OpKind.Sub: + neg_idx: llvmlite.Value | t.CPtr = llvmlite.build_sub( + builder, llvmlite.const_int64(pool, 0), idx) + if neg_idx is None: + return None + idx = neg_idx + # 数组 pointee → 先 decay 为元素指针(getelementptr [N x ty], [N x ty]* %p, i32 0, i32 0) + if self.is_array_type(elem_ty) != 0: + inner_ty: llvmlite.LLVMType | t.CPtr = None + match elem_ty: + case llvmlite.LLVMType.Array(inner, _): + inner_ty = inner + case _: + return None + if inner_ty is None: + return None + decayed: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( + builder, elem_ty, inner_ty, ptr_val, llvmlite.const_int64(pool, 0)) + if decayed is None: + return None + return llvmlite.build_gep(builder, inner_ty, decayed, idx) + return llvmlite.build_gep(builder, elem_ty, ptr_val, idx) + def InitExprGen(self) -> int: + """初始化 ExprGen 族字段(构造时由 Generator 调用)""" + if self is None: + return 1 + self.DocKeys = None + self.DocValues = None + self.DocCount = 0 + self.DiagCDefineCount = 0 + self.DiagNameValueCount = 0 + self.DiagTranslateValueCount = 0 + return 0 diff --git a/App/lib/core/Gen/ExprGenCdef.vp b/App/lib/core/Gen/ExprGenCdef.vp index 84b4fdc..741b74b 100644 --- a/App/lib/core/Gen/ExprGenCdef.vp +++ b/App/lib/core/Gen/ExprGenCdef.vp @@ -1,1089 +1,1080 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import viperlib -import w32.fileio as fileio -import lib.core.CompilerFactory as CompilerFactory -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.VLogger as VLogger -import lib.Projectrans.Config as Config -import lib.Projectrans.Utils as Utils - - -import lib.core.Gen.ExprGenBase as ExprGenBase -import lib.core.StubMergerCollect as StubMergerCollect -import lib.core.StubMergerStore as StubMergerStore -import lib.core.Handles.ExprCallBase as ExprCallBase - -# ============================================================ -# ExprGenCdef - ExprGenMixin 拆分(阶段 D):跨模块 CDefine 查找 -# -# 继承 ExprGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class ExprGenCdef(ExprGenBase.ExprGenBase): - """跨模块 CDefine 查找""" - - # ============================================================ - # _build_source_path_from_sha1 - 通过 SHA1 从存储器构建源 .vp/.py 文件路径 - # - # .vpi 文件可能未生成(Phase1 未输出 vpi),此时回退读取源 .py 文件。 - # 从 StubMerger 全局存储器查找 SHA1 对应的相对路径, - # 根据 rel_path 前缀选择基础目录: - # - rel_path 以 "lib/" 开头 → App 源文件,用 {Config.SourceDir}/{rel_path} - # - 其他 → includes 文件,用 {Config.IncludesDir}/{rel_path} - # - # Returns: - # stdlib.malloc 分配的路径字符串(调用者负责 free),None 失败 - # ============================================================ - def _build_source_path_from_sha1(self, sha1: str) -> str: - """通过 SHA1 从全局存储器构建源 .py 文件路径""" - if sha1 is None: - return None - if Config.IncludesDir is None: - return None - # 从 StubMerger 全局存储器获取相对路径数组 - rel_arr_ptr: bytes | t.CPtr = StubMergerStore.GetSha1StoreRelArrPtr() - count: int = StubMergerStore.GetSha1StoreCount() - if rel_arr_ptr is None or count <= 0: - return None - sha1_arr_ptr: bytes | t.CPtr = StubMergerStore.GetSha1StoreArrPtr() - if sha1_arr_ptr is None: - return None - # 遍历查找匹配的 SHA1 - idx_s: int = -1 - for i in range(count): - sidx: t.CSizeT = t.CSizeT(i) * 17 - cur_sha1: str = sha1_arr_ptr + sidx - if cur_sha1[0] == '\0': - continue - if string.strcmp(cur_sha1, sha1) == 0: - idx_s = i - break - if idx_s < 0: - return None - # 获取相对路径(MAX_REL_PATH_LEN=256,避免跨模块 CDefine 解析问题) - MAX_RPL: t.CSizeT = 256 - ridx: t.CSizeT = t.CSizeT(idx_s) * MAX_RPL - rel_path: str = rel_arr_ptr + ridx - if rel_path[0] == '\0': - return None - # 选择基础目录:rel_path 以 "lib/" 开头 → App 源文件(SourceDir); - # 以 "includes/" 开头 → includes 文件(去掉 "includes/" 前缀)。 - # 其他 rel_path(如 VKernel 的 "drivers/core/cpu/cpu.vp")无前缀, - # 无法从 rel_path 判断归属:先试 SourceDir(App 文件),文件不存在 - # 再试 IncludesDir(includes 文件的 RelPath 同样无前缀存储)。 - # 避免路径构建错误导致跨模块 CDefine 查找静默失败。 - base_dir: str = None - rel_used: str = rel_path - if string.strlen(rel_path) >= 4: - if (rel_path[0] == 'l' and rel_path[1] == 'i' and - rel_path[2] == 'b' and rel_path[3] == '/'): - base_dir = Config.SourceDir if Config.SourceDir is not None else Config.IncludesDir - if base_dir is None and string.strlen(rel_path) >= 9: - if (rel_path[0] == 'i' and rel_path[1] == 'n' and - rel_path[2] == 'c' and rel_path[3] == 'l' and - rel_path[4] == 'u' and rel_path[5] == 'd' and - rel_path[6] == 'e' and rel_path[7] == 's' and - rel_path[8] == '/'): - rel_used = rel_path + 9 - base_dir = Config.IncludesDir - if base_dir is None: - base_dir = Config.SourceDir if Config.SourceDir is not None else Config.IncludesDir - # 构建完整路径: {base_dir}/{rel_used} - base_len: t.CSizeT = string.strlen(base_dir) - rel_len: t.CSizeT = string.strlen(rel_used) - path_len: t.CSizeT = base_len + rel_len + 2 - buf: str = stdlib.malloc(path_len) - if buf is None: - return None - viperlib.snprintf(buf, path_len, "%s/%s", base_dir, rel_used) - # 存在性检查:SourceDir 下不存在且 IncludesDir 不同 → 重试 IncludesDir - pf_chk: fileio.File | t.CPtr = fileio.File(buf, fileio.MODE.R) - if pf_chk.closed: - pf_chk.close() - if Config.IncludesDir is not None and base_dir != Config.IncludesDir: - stdlib.free(buf) - base_len2: t.CSizeT = string.strlen(Config.IncludesDir) - path_len2: t.CSizeT = base_len2 + rel_len + 2 - buf = stdlib.malloc(path_len2) - if buf is None: - return None - viperlib.snprintf(buf, path_len2, "%s/%s", Config.IncludesDir, rel_used) - pf_chk2: fileio.File | t.CPtr = fileio.File(buf, fileio.MODE.R) - if pf_chk2.closed: - pf_chk2.close() - stdlib.free(buf) - return None - pf_chk2.close() - else: - stdlib.free(buf) - return None - else: - pf_chk.close() - return buf - # ============================================================ - # _lookup_cross_module_cdefine - 跨模块查找 CDefine 常量 - # - # 当当前模块的 CDefine 表中找不到某个 Name 时,从 from_imports - # 解析出源模块,再从该模块的 pyi 文件中解析 CDefine 常量值。 - # 找到后缓存到当前模块的 CDefine 表中,避免重复查找。 - # - # pyi 文件格式: "NAME: t.CDefine = value" - # ============================================================ - def _lookup_cross_module_cdefine(self, pool: memhub.MemBuddy | t.CPtr, - name: str, - from_imports: str, - imported_modules: str = None, - depth: int = 0, - node: ast.AST | t.CPtr = None) -> t.CInt64T: - """跨模块查找 CDefine 常量,返回值(64 位)或 -1(未找到) - - 查找顺序: - 1. from_imports 精确匹配(from X import NAME) - 2. from_imports star 回退(from X import *) - 3. imported_modules 遍历(import X):当通过 import X 导入模块时, - 模块中定义的 CDefine 常量可通过此路径找到(如方法签名默认参数引用) - - depth: 递归深度(子模块递归/imported_modules 遍历的内部调用递增)。 - node: 触发查找的 AST 节点(递归内传 None,line 0;顶层调用点传实际节点)。 - """ - # 递归深度守卫:子模块递归(from .X import NAME re-export 链)与 - # imported_modules 遍历组合可能形成循环(模块间互相 from import), - # 无上限时无限递归 → 每次递归 pool.alloc 缓冲(rc_sub_buf/rc_full_mod/ - # rc_fi/im_buf/sub_fi)→ O(n²) 累积 → 主池 1.5GB OOM - # (NewAstTest CONST_INT 单次查找 14593 次调用,fi 恒为 CONST_INT:ast)。 - # 正常跨模块 CDefine 查找深度 < 8(如 ast → ast.base),32 上限 fail-fast - # 暴露循环 import 链(而非静默 OOM)。报错带 node 行号 + 当前递归模块链。 - if depth > 32: - err_buf: str = pool.alloc(256) - if err_buf is not None: - viperlib.snprintf(err_buf, 256, - "跨模块 CDefine 查找递归过深(疑似模块循环 import/re-export): %s (depth=%d fi=%s)", - name, depth, - from_imports if from_imports is not None else "(nil)") - HandlesType.fatal_error(node, err_buf, "InternalCompilerError") - HandlesType.fatal_error(node, - "跨模块 CDefine 查找递归过深(疑似模块循环 import/re-export)", "InternalCompilerError") - # 入口处清零标志,确保所有早退路径(return -1)都返回"未找到"状态 - # 避免递归调用时前一次成功的标志残留导致误判 - HandlesType.set_cdefine_found(0) - if name is None: - return -1 - if from_imports is None: - from_imports = "" - - # 1. 从 from_imports 查找名称对应的模块名 - # 先尝试精确匹配(allow_star_fallback=0),避免 CDefine 常量被 star import 误导 - mod_name_raw: str = HandlesImports.lookup_from_import(from_imports, name, 0) - if mod_name_raw is None: - # 精确匹配失败:尝试 star import 回退 - mod_name_raw = HandlesImports.lookup_from_import(from_imports, name, 1) - - # 截断模块名到 NUL 结尾:lookup_from_import 返回指向 from_imports 内部的 - # 指针(非 NUL 结尾,后随空格分隔的其他条目,如 "ast CONST_STR:ast ...")。 - # 不截断会污染 base_mod:strlen 读到整个 from_imports 末尾 → rc_full_mod - # 每层累积整个列表 + ".base"(dump:ast.base.base.base 无限递归根因), - # 且缓存 key 错乱("CONST_INT@ast CONST_STR:ast ...")无法命中。 - # 与 _lookup_sha1_from_modname_raw 的截断逻辑一致(空格/冒号/NUL 分隔)。 - base_mod: str = None - if mod_name_raw is not None: - mbl: t.CSizeT = 0 - while mod_name_raw[mbl] != ' ' and mod_name_raw[mbl] != '\0' \ - and mod_name_raw[mbl] != ':': - mbl += 1 - mb_buf: str = pool.alloc(mbl + 1) - if mb_buf is not None: - mi2: t.CSizeT - for mi2 in range(mbl): - mb_buf[mi2] = mod_name_raw[mi2] - mb_buf[mbl] = '\0' - base_mod = mb_buf - while base_mod is not None and base_mod[0] == '.': - base_mod = base_mod + 1 - - # 跨模块 CDefine 查找缓存(perm_pool 永久,跨文件复用): - # 首次查找成功后结果缓存,后续文件(含 reset_to(mark2)/模块切换)直接命中, - # 避免 CONST_INT 跨模块递归查找反复触发(NewAstTest OOM 根因—— - # 14593 次调用全部重复递归 ast → ast.base → ...)。 - # key = "name@源模块"(源模块维度,用去点后的 base_mod 保证一致), - # 保持模块隔离:不同源模块的同名 CDefine 值不同时不串值。 - # 仅 ALL_CAPS 全局唯一宏名才进入本函数(_is_cdefine_name_pattern 已过滤)。 - xkey_buf: str = None - if base_mod is not None: - xk_len: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2 - xkey_buf = pool.alloc(xk_len) - if xkey_buf is not None: - viperlib.snprintf(xkey_buf, xk_len, "%s@%s", name, base_mod) - xval: str = HandlesType.lookup_xmod_cdefine(xkey_buf) - if HandlesType.is_cdefine_found() != 0: - if HandlesType.is_cdefine_str() != 0: - HandlesType.register_cdefine_string(pool, name, xval) - elif HandlesType.is_cdefine_double() != 0: - xd_v: double = string.atof(xval) - HandlesType.register_cdefine_double(pool, name, xd_v) - else: - xv_i: t.CInt64T = string.atoll(xval) - HandlesType.register_cdefine_constant(pool, name, xv_i) - return string.atoll(xval) - - # 2. from_imports 查找失败:直接回退到 imported_modules 遍历(步骤 9.6) - # 注意:star fallback 可能返回错误模块(如 stdint),常量实际不在其中, - # 步骤 9.6 会在该模块查找失败后继续遍历 imported_modules - if mod_name_raw is None: - # from_imports 完全没有匹配(精确和 star 都失败) - # 直接进入 imported_modules 遍历(步骤 9.6) - if imported_modules is None: - return -1 - # 跳过 from_imports 模块读取,直接走步骤 9.6 的 imported_modules 遍历 - # 设置 result_found=0 跳过步骤 3-9,直接到 9.6 - HandlesType.set_cdefine_found(0) - # 直接遍历 imported_modules - im_len: t.CSizeT = string.strlen(imported_modules) - im_ci: t.CSizeT = 0 - while im_ci < im_len: - while im_ci < im_len and imported_modules[im_ci] == ' ': - im_ci += 1 - if im_ci >= im_len: - break - im_start: t.CSizeT = im_ci - while im_ci < im_len and imported_modules[im_ci] != ' ': - im_ci += 1 - im_end: t.CSizeT = im_ci - im_nlen: t.CSizeT = im_end - im_start - if im_nlen > 0 and im_nlen < 256: - im_buf: str = pool.alloc(im_nlen + 1) - if im_buf is not None: - mk: t.CSizeT = 0 - while mk < im_nlen: - im_buf[mk] = imported_modules[im_start + mk] - mk += 1 - im_buf[im_nlen] = '\0' - sub_fi: str = pool.alloc(im_nlen + 3) - if sub_fi is not None: - sub_fi[0] = '*' - sub_fi[1] = ':' - mk2: t.CSizeT = 0 - while mk2 < im_nlen: - sub_fi[2 + mk2] = im_buf[mk2] - mk2 += 1 - sub_fi[2 + im_nlen] = '\0' - sub_val: t.CInt64T = self._lookup_cross_module_cdefine(pool, name, sub_fi, None, depth + 1, node) - if HandlesType.is_cdefine_found() != 0: - return sub_val - return -1 - - # 2. 截断模块名 → 去前导点 → 精确+后缀查找 SHA1(复用 HandlesExprCall 公共逻辑) - sha1: str = ExprCallBase._lookup_sha1_from_modname_raw(pool, mod_name_raw) - if sha1 is None: - return -1 - - # 5. 获取 temp_dir - temp_dir: str = HandlesType.get_temp_dir() - if temp_dir is None: - return -1 - - # 6. 构建 vpi 文件路径 - td_len: t.CSizeT = string.strlen(temp_dir) - pyi_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, sha1, "vpi") - if pyi_path is None: - return -1 - - # 7. 读取 vpi 文件;若不存在或内容过短(空 stub)则回退读取源 .vp/.py 文件 - PYI_READ_BUF_SIZE: t.CSizeT = 65536 - pyi_buf: bytes = stdlib.malloc(PYI_READ_BUF_SIZE) - if pyi_buf is None: - stdlib.free(pyi_path) - return -1 - pf: fileio.File | t.CPtr = fileio.File(pyi_path, fileio.MODE.R) - need_py_fallback: int = 0 - bytes_read: LONG = 0 - if pf.closed: - # .vpi 文件不存在:回退读取源 .vp/.py 文件 - need_py_fallback = 1 - else: - bytes_read = pf.read_all(pyi_buf, PYI_READ_BUF_SIZE) - pf.close() - # vpi 内容过短(< 10 字节)视为空 stub,回退 .py - if bytes_read < 10: - need_py_fallback = 1 - else: - if bytes_read < PYI_READ_BUF_SIZE: - pyi_buf[bytes_read] = 0 - else: - pyi_buf[PYI_READ_BUF_SIZE - 1] = 0 - # vpi(存根签名文件)中的 CDefine 声明可能只带名字不带值 - # (Converter 旧版只对 CONST_INT/BOOL 等输出 "= value",CONST_FLOAT - # 等不输出 → numpy 的 pi/e 在 stub 中无值),真正的值在源 - # .vp/.py 文件中。旧启发式"vpi 中任一 CDefine 带值 → 不读源"是错的: - # 模块同时含 int CDefine(带值,如 numpy.MAX_NDIM=4)与 float - # CDefine(无值,如 pi)时,int 行让 cd_sig=1 而漏回退源 → pi - # 解析失败 → 退化 @pi 全局指针 → float<->ptr 报错(NumpyTest 根因)。 - # 改为按目标名判定:仅当 vpi 中 name 的 CDefine 行带值时才信任 - # vpi,否则(name 行无值 / name 不在 vpi / 整个 vpi 无带值 CDefine) - # 一律回退读源文件。 - cd_sig: int = 0 - name_has_val: int = 0 - cs_name_len: t.CSizeT = string.strlen(name) - cs_total: t.CSizeT = string.strlen(pyi_buf) - cs_i: t.CSizeT = 0 - while cs_i + 9 < cs_total: - if (pyi_buf[cs_i] == 't' and pyi_buf[cs_i + 1] == '.' and - pyi_buf[cs_i + 2] == 'C' and pyi_buf[cs_i + 3] == 'D' and - pyi_buf[cs_i + 4] == 'e' and pyi_buf[cs_i + 5] == 'f' and - pyi_buf[cs_i + 6] == 'i' and pyi_buf[cs_i + 7] == 'n' and - pyi_buf[cs_i + 8] == 'e'): - # 检查该行剩余部分是否有 '='(带值声明才在 vpi 中匹配) - cd_eq: int = 0 - cs_j: t.CSizeT = cs_i + 9 - while cs_j < cs_total and pyi_buf[cs_j] != '\n': - if pyi_buf[cs_j] == '=': - cd_eq = 1 - break - cs_j += 1 - if cd_eq != 0: - cd_sig = 1 - # 定位该行行首,检查是否以 "name:" 开头(目标名带值) - cs_line_start: t.CSizeT = cs_i - while cs_line_start > 0 and pyi_buf[cs_line_start - 1] != '\n': - cs_line_start -= 1 - if cs_i - cs_line_start >= cs_name_len + 1: - nm_ok: int = 1 - for ki2 in range(cs_name_len): - if pyi_buf[cs_line_start + ki2] != name[ki2]: - nm_ok = 0 - break - if nm_ok == 1 and pyi_buf[cs_line_start + cs_name_len] == ':': - name_has_val = 1 - cs_i += 1 - if cd_sig == 0 or name_has_val == 0: - need_py_fallback = 1 - stdlib.free(pyi_path) - - if need_py_fallback != 0: - # 从 SHA1 存储器查找相对路径,构建 {base_dir}/{rel_path} - src_path: str = self._build_source_path_from_sha1(sha1) - if src_path is None: - # 存储器中找不到 SHA1 = 编译器 bug(Phase1/Phase2 未填充存储器) - # 报错终止,不静默返回 -1(避免后续生成错误的 @UNDEFINED 全局变量引用) - err_buf: str = pool.alloc(512) - if err_buf is not None: - viperlib.snprintf(err_buf, 512, - "跨模块 CDefine 查找失败:SHA1 %s 不在存储器中(base_mod=%s name=%s)。" - "Phase1/Phase2 未正确填充 PopulateSha1MapStore/AppendToSha1MapStore", - sha1, base_mod, name) - VLogger.error(err_buf, "XMOD-CD") - stdlib.free(pyi_buf) - return -1 - pf = fileio.File(src_path, fileio.MODE.R) - stdlib.free(src_path) - if pf.closed: - stdlib.free(pyi_buf) - return -1 - bytes_read = pf.read_all(pyi_buf, PYI_READ_BUF_SIZE) - pf.close() - if bytes_read <= 0: - stdlib.free(pyi_buf) - return -1 - if bytes_read < PYI_READ_BUF_SIZE: - pyi_buf[bytes_read] = 0 - else: - pyi_buf[PYI_READ_BUF_SIZE - 1] = 0 - - # 8. 在 pyi_buf 中查找 "name: t.CDefine = value" 行 - # 格式: NAME: t.CDefine = value - name_len: t.CSizeT = string.strlen(name) - total_len: t.CSizeT = string.strlen(pyi_buf) - pos: t.CSizeT = 0 - result_val: t.CInt64T = 0 - result_found: int = 0 - res_is_double: int = 0 - res_is_str: int = 0 - while pos < total_len: - # 找到行首 - line_start: t.CSizeT = pos - # 找到行尾 - while pos < total_len and pyi_buf[pos] != '\n': - pos += 1 - line_len: t.CSizeT = pos - line_start - if pos < total_len: - pos += 1 # 跳过 '\n' - - # 检查行是否以 "name:" 开头 - if line_len < name_len + 1: - continue - match_ok: int = 1 - for ki in range(name_len): - if pyi_buf[line_start + ki] != name[ki]: - match_ok = 0 - break - if match_ok == 0: - continue - if pyi_buf[line_start + name_len] != ':': - continue - - # 检查行是否包含 "t.CDefine" - # 在行中查找 "t.CDefine" - has_cdefine: int = 0 - ci: t.CSizeT = line_start + name_len + 1 - while ci + 8 <= line_start + line_len: - if (pyi_buf[ci] == 't' and pyi_buf[ci + 1] == '.' and - pyi_buf[ci + 2] == 'C' and pyi_buf[ci + 3] == 'D' and - pyi_buf[ci + 4] == 'e' and pyi_buf[ci + 5] == 'f' and - pyi_buf[ci + 6] == 'i' and pyi_buf[ci + 7] == 'n' and - pyi_buf[ci + 8] == 'e'): - has_cdefine = 1 - break - ci += 1 - if has_cdefine == 0: - continue - - # 找到 "=" 后面的值 - eq_pos: t.CSizeT = line_start + name_len + 1 - while eq_pos < line_start + line_len and pyi_buf[eq_pos] != '=': - eq_pos += 1 - if eq_pos >= line_start + line_len: - continue - eq_pos += 1 # 跳过 '=' - - # 跳过空格 - while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': - eq_pos += 1 - - # 检查是否是 t.CUnsignedLong(...) / t.CLong(...) / t.CInt(...) 等类型构造函数 - # 格式: t.CUnsignedLong(-11) / t.CUnsignedLong(0xFFFFFFFF) - # 如果是,跳过 "t.CXxx(" 前缀,解析括号内的值,忽略结尾 ')' - is_type_ctor: int = 0 - if eq_pos + 2 < line_start + line_len: - if pyi_buf[eq_pos] == 't' and pyi_buf[eq_pos + 1] == '.': - # 找到 '(' 的位置 - paren_pos: t.CSizeT = eq_pos + 2 - while paren_pos < line_start + line_len and pyi_buf[paren_pos] != '(': - paren_pos += 1 - if paren_pos < line_start + line_len and pyi_buf[paren_pos] == '(': - is_type_ctor = 1 - eq_pos = paren_pos + 1 # 跳过 '(' - # 跳过括号内可能的前导空格 - while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': - eq_pos += 1 - - # 括号包裹标记:(1 << 23) / (512) / (A | B) - is_paren_expr: int = 0 - if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '(': - is_paren_expr = 1 - eq_pos += 1 - while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': - eq_pos += 1 - - # === 解析左操作数 token(数字 / hex / 负号 / 名称) === - # 负号标记 - is_neg: int = 0 - if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '-': - is_neg = 1 - eq_pos += 1 - val_str_start: t.CSizeT = eq_pos - val_str_len: t.CSizeT = 0 - is_hex: int = 0 - is_float_val: int = 0 - is_name_val: int = 0 - is_str_val: int = 0 - # 字符串值(如 ZLIB_VERSION: t.CDefine = "1.3.2"):读引号内内容。 - # 跨模块读回此前不支持引号 → val_str_len=0 被跳过 → "跨模块 CDefine - # 未找到"(test_pyzlib.vp pyzlib.ZLIB_VERSION 根因) - if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '"': - is_str_val = 1 - eq_pos += 1 # 跳过开引号 - val_str_start = eq_pos - while eq_pos < line_start + line_len and pyi_buf[eq_pos] != '"': - val_str_len += 1 - eq_pos += 1 - if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '"': - eq_pos += 1 # 跳过闭引号 - if eq_pos + 1 < line_start + line_len: - if pyi_buf[eq_pos] == '0' and (pyi_buf[eq_pos + 1] == 'x' or pyi_buf[eq_pos + 1] == 'X'): - is_hex = 1 - val_str_len = 2 - eq_pos += 2 - elif (pyi_buf[eq_pos] >= 'A' and pyi_buf[eq_pos] <= 'Z') or \ - (pyi_buf[eq_pos] >= 'a' and pyi_buf[eq_pos] <= 'z') or \ - pyi_buf[eq_pos] == '_': - is_name_val = 1 - while eq_pos < line_start + line_len: - c_tk: t.CChar = pyi_buf[eq_pos] - if (c_tk >= 'A' and c_tk <= 'Z') or (c_tk >= 'a' and c_tk <= 'z') or \ - (c_tk >= '0' and c_tk <= '9') or c_tk == '_': - val_str_len += 1 - eq_pos += 1 - else: - break - # 数字/hex 字符续读(字符串值已整体读取,跳过) - while eq_pos < line_start + line_len and is_name_val == 0 and is_str_val == 0: - ch: t.CChar = pyi_buf[eq_pos] - if is_hex == 1: - if ((ch >= '0' and ch <= '9') or - (ch >= 'a' and ch <= 'f') or - (ch >= 'A' and ch <= 'F')): - val_str_len += 1 - eq_pos += 1 - else: - break - else: - if ch >= '0' and ch <= '9': - val_str_len += 1 - eq_pos += 1 - elif ch == '.' and is_float_val == 0: - # 浮点值:'3.14159'('.' 只允许一次) - is_float_val = 1 - val_str_len += 1 - eq_pos += 1 - else: - break - - if val_str_len == 0 and is_str_val == 0: - continue - - # 复制左 token 到缓冲区 - val_buf: str = pool.alloc(val_str_len + 1) - if val_buf is None: - continue - for vi in range(val_str_len): - val_buf[vi] = pyi_buf[val_str_start + vi] - val_buf[val_str_len] = '\0' - - # 左 token 求值 - lval: t.CInt64T = 0 - l_is_double: int = 0 - ldbl: double = 0.0 - if is_str_val != 0: - # 字符串 CDefine(如 ZLIB_VERSION = "1.3.2"):注册字符串值 - # (含空串 ""),result_found 标记 + res_is_str 供尾部跳过整数 - # 注册/缓存(否则 register_cdefine_constant 把字符串当 0 整数) - HandlesType.register_cdefine_string(pool, name, val_buf) - result_val = 0 - result_found = 1 - res_is_str = 1 - elif is_name_val != 0: - # True/False 布尔字面量 → 1/0(对齐 TPC:bool 在 CDefine 语境按整数处理) - if string.strcmp(val_buf, "True") == 0: - lval = 1 - elif string.strcmp(val_buf, "False") == 0: - lval = 0 - else: - # 名称引用:查当前 CDefine 表(如 FOREGROUND_COMBO = FOREGROUND_RED) - lval = HandlesType.lookup_cdefine_constant(val_buf) - if HandlesType.is_cdefine_found() == 0: - # 名称未注册:该行无法求值,跳过 - continue - elif is_hex == 1: - # 手动解析十六进制(跳过 0x 前缀)——64 位累加, - # 0xFFFFFFFF=4294967295 保持全精度(常量生成端 i32 截断回 -1) - hex_result: t.CInt64T = 0 - hex_buf: str = val_buf + 2 # 跳过 "0x" - for hi in range(val_str_len - 2): - hc: t.CChar = hex_buf[hi] - hd: int = 0 - if hc >= '0' and hc <= '9': - hd = hc - '0' - elif hc >= 'a' and hc <= 'f': - hd = hc - 'a' + 10 - elif hc >= 'A' and hc <= 'F': - hd = hc - 'A' + 10 - else: - break - hex_result = hex_result * 16 + hd - lval = hex_result - elif is_float_val != 0: - l_is_double = 1 - ldbl = string.atof(val_buf) - lval = string.atoll(val_buf) - else: - lval = string.atoll(val_buf) - if is_neg != 0: - lval = -lval - if l_is_double != 0: - ldbl = -ldbl - - # 跳过空格,检查是否有二元运算符 - while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': - eq_pos += 1 - - # 解析运算符(<< >> | & ^ + - * /) - cd_op: int = 0 - if eq_pos + 1 < line_start + line_len: - if pyi_buf[eq_pos] == '<' and pyi_buf[eq_pos + 1] == '<': - cd_op = 1 # LShift - eq_pos += 2 - elif pyi_buf[eq_pos] == '>' and pyi_buf[eq_pos + 1] == '>': - cd_op = 2 # RShift - eq_pos += 2 - if cd_op == 0 and eq_pos < line_start + line_len: - if pyi_buf[eq_pos] == '|': - cd_op = 3 # BitOr - eq_pos += 1 - elif pyi_buf[eq_pos] == '&': - cd_op = 4 # BitAnd - eq_pos += 1 - elif pyi_buf[eq_pos] == '^': - cd_op = 5 # BitXor - eq_pos += 1 - elif pyi_buf[eq_pos] == '+': - cd_op = 6 # Add - eq_pos += 1 - elif pyi_buf[eq_pos] == '-': - cd_op = 7 # Sub - eq_pos += 1 - elif pyi_buf[eq_pos] == '*': - cd_op = 8 # Mult - eq_pos += 1 - elif pyi_buf[eq_pos] == '/': - cd_op = 9 # Div - eq_pos += 1 - - if cd_op != 0: - # === 解析右操作数 token === - while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': - eq_pos += 1 - r_neg: int = 0 - if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '-': - r_neg = 1 - eq_pos += 1 - r_start: t.CSizeT = eq_pos - r_len: t.CSizeT = 0 - r_hex: int = 0 - r_name: int = 0 - if eq_pos + 1 < line_start + line_len: - if pyi_buf[eq_pos] == '0' and (pyi_buf[eq_pos + 1] == 'x' or pyi_buf[eq_pos + 1] == 'X'): - r_hex = 1 - r_len = 2 - eq_pos += 2 - elif (pyi_buf[eq_pos] >= 'A' and pyi_buf[eq_pos] <= 'Z') or \ - (pyi_buf[eq_pos] >= 'a' and pyi_buf[eq_pos] <= 'z') or \ - pyi_buf[eq_pos] == '_': - r_name = 1 - while eq_pos < line_start + line_len: - c_r: t.CChar = pyi_buf[eq_pos] - if (c_r >= 'A' and c_r <= 'Z') or (c_r >= 'a' and c_r <= 'z') or \ - (c_r >= '0' and c_r <= '9') or c_r == '_': - r_len += 1 - eq_pos += 1 - else: - break - while eq_pos < line_start + line_len and r_name == 0: - c_r2: t.CChar = pyi_buf[eq_pos] - if r_hex == 1: - if ((c_r2 >= '0' and c_r2 <= '9') or - (c_r2 >= 'a' and c_r2 <= 'f') or - (c_r2 >= 'A' and c_r2 <= 'F')): - r_len += 1 - eq_pos += 1 - else: - break - else: - if c_r2 >= '0' and c_r2 <= '9': - r_len += 1 - eq_pos += 1 - else: - break - if r_len == 0: - # 运算符后无右操作数:无法求值,跳过该行 - continue - r_buf: str = pool.alloc(r_len + 1) - if r_buf is None: - continue - for r_i in range(r_len): - r_buf[r_i] = pyi_buf[r_start + r_i] - r_buf[r_len] = '\0' - rval: t.CInt64T = 0 - if r_name != 0: - # True/False 布尔字面量 → 1/0 - if string.strcmp(r_buf, "True") == 0: - rval = 1 - elif string.strcmp(r_buf, "False") == 0: - rval = 0 - else: - rval = HandlesType.lookup_cdefine_constant(r_buf) - if HandlesType.is_cdefine_found() == 0: - # 名称未注册:无法求值,跳过该行 - continue - elif r_hex != 0: - rhex_v: t.CInt64T = 0 - rh_buf: str = r_buf + 2 - for rh_i in range(r_len - 2): - rc: t.CChar = rh_buf[rh_i] - rd: int = 0 - if rc >= '0' and rc <= '9': - rd = rc - '0' - elif rc >= 'a' and rc <= 'f': - rd = rc - 'a' + 10 - elif rc >= 'A' and rc <= 'F': - rd = rc - 'A' + 10 - else: - break - rhex_v = rhex_v * 16 + rd - rval = rhex_v - else: - rval = string.atoll(r_buf) - if r_neg != 0: - rval = -rval - # 计算二元表达式结果(对齐 TPC ConstEvaluator) - if cd_op == 1: - result_val = lval << rval - elif cd_op == 2: - result_val = lval >> rval - elif cd_op == 3: - result_val = lval | rval - elif cd_op == 4: - result_val = lval & rval - elif cd_op == 5: - result_val = lval ^ rval - elif cd_op == 6: - result_val = lval + rval - elif cd_op == 7: - result_val = lval - rval - elif cd_op == 8: - result_val = lval * rval - else: - if rval == 0: - continue - result_val = lval // rval - result_found = 1 - break - else: - # 单值(无运算符):括号内单值如 (512) / (-11) 也走这里 - if is_paren_expr != 0: - while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': - eq_pos += 1 - if eq_pos < line_start + line_len and pyi_buf[eq_pos] == ')': - eq_pos += 1 - if is_float_val != 0: - # 浮点 CDefine(如 U_M_PI = 3.14159...): - # 值缓存为 double(register_cdefine_double),供调用处生成 - # double 常量;整数部分供 int 路径使用(is_cdefine_double 标志)。 - HandlesType.register_cdefine_double(pool, name, ldbl) - result_val = lval - result_found = 1 - res_is_double = 1 - else: - result_val = lval - result_found = 1 - break - - # 9.5 如果当前模块文件中没找到,递归查找子模块 - # 处理 from .X import NAME 和 from .X import * 的情况 - # 例如 ast.__init__.vp 中 from .base import CONST_INT, ... - # 需要递归查找 ast.base 子模块中的 CONST_INT: t.CDefine = 1 - if result_found == 0: - # base_mod 已在函数开头计算(mod_name_raw 去前导点), - # 供子模块递归构建 "base_mod.X" 全名。 - name_len_rc: t.CSizeT = string.strlen(name) - rc_pos: t.CSizeT = 0 - while rc_pos < total_len and result_found == 0: - # 找到行首 - rc_line_start: t.CSizeT = rc_pos - # 找到行尾 - while rc_pos < total_len and pyi_buf[rc_pos] != '\n': - rc_pos += 1 - rc_line_len: t.CSizeT = rc_pos - rc_line_start - if rc_pos < total_len: - rc_pos += 1 - - # 检查行是否以 "from ." 开头(相对导入子模块) - if rc_line_len < 12: - continue - if pyi_buf[rc_line_start] != 'f' or pyi_buf[rc_line_start+1] != 'r' or \ - pyi_buf[rc_line_start+2] != 'o' or pyi_buf[rc_line_start+3] != 'm' or \ - pyi_buf[rc_line_start+4] != ' ' or pyi_buf[rc_line_start+5] != '.': - continue - - # 提取子模块名(从 rc_line_start+6 开始,到空格/tab 为止) - rc_sub_start: t.CSizeT = rc_line_start + 6 - rc_sub_end: t.CSizeT = rc_sub_start - while rc_sub_end < rc_line_start + rc_line_len and \ - pyi_buf[rc_sub_end] != ' ' and pyi_buf[rc_sub_end] != '\t': - rc_sub_end += 1 - rc_sub_len: t.CSizeT = rc_sub_end - rc_sub_start - if rc_sub_len == 0: - continue - - # 检查行是否包含 "import" - rc_has_import: int = 0 - rc_ipos: t.CSizeT = rc_sub_end - while rc_ipos + 6 <= rc_line_start + rc_line_len: - if pyi_buf[rc_ipos] == 'i' and pyi_buf[rc_ipos+1] == 'm' and \ - pyi_buf[rc_ipos+2] == 'p' and pyi_buf[rc_ipos+3] == 'o' and \ - pyi_buf[rc_ipos+4] == 'r' and pyi_buf[rc_ipos+5] == 't': - rc_has_import = 1 - break - rc_ipos += 1 - if rc_has_import == 0: - continue - - # 检查 NAME 是否在导入列表中,或导入是 * - # 处理多行导入:from .X import (... NAME, ...) - # 从 "import" 之后扫描,如果有 "(" 则扫描到 ")" 为止 - rc_imp_start: t.CSizeT = rc_ipos + 6 - rc_star: int = 0 - rc_name_match: int = 0 - - # 确定扫描范围:单行或跨行(括号内) - rc_scan_end: t.CSizeT = rc_line_start + rc_line_len - rc_has_paren: int = 0 - rc_pp: t.CSizeT = rc_imp_start - while rc_pp < rc_line_start + rc_line_len: - if pyi_buf[rc_pp] == '(': - rc_has_paren = 1 - break - if pyi_buf[rc_pp] == '*': - rc_star = 1 - rc_pp += 1 - if rc_has_paren != 0: - # 多行导入:从 "(" 之后扫描到 ")" 为止 - rc_scan_end = rc_pp + 1 - rc_paren_closed: int = 0 - rc_sp: t.CSizeT = rc_pp + 1 - while rc_sp < total_len and rc_paren_closed == 0: - if pyi_buf[rc_sp] == ')': - rc_paren_closed = 1 - rc_scan_end = rc_sp - break - rc_sp += 1 - if rc_paren_closed == 0: - rc_scan_end = total_len - - # 在 rc_imp_start 到 rc_scan_end 范围内查找 NAME 和 * - rc_cpos: t.CSizeT = rc_imp_start - while rc_cpos < rc_scan_end: - rc_ch: t.CChar = pyi_buf[rc_cpos] - if rc_ch == '*': - rc_star = 1 - # 检查 NAME 是否匹配(作为完整单词) - if rc_cpos + name_len_rc <= rc_scan_end: - rc_match: int = 1 - rc_ki: t.CSizeT - for rc_ki in range(name_len_rc): - if pyi_buf[rc_cpos + rc_ki] != name[rc_ki]: - rc_match = 0 - break - if rc_match == 1: - # 检查前字符是否是非标识符字符 - rc_before_ok: int = 0 - if rc_cpos == rc_imp_start: - rc_before_ok = 1 - else: - rc_before_ch: t.CChar = pyi_buf[rc_cpos - 1] - if rc_before_ch == ' ' or rc_before_ch == '\t' or \ - rc_before_ch == '(' or rc_before_ch == ',' or \ - rc_before_ch == '\n' or rc_before_ch == '\r': - rc_before_ok = 1 - # 检查后字符是否是非标识符字符 - rc_after_ok: int = 0 - rc_after_pos: t.CSizeT = rc_cpos + name_len_rc - if rc_after_pos >= rc_scan_end: - rc_after_ok = 1 - else: - rc_after_ch: t.CChar = pyi_buf[rc_after_pos] - if rc_after_ch == ' ' or rc_after_ch == '\t' or \ - rc_after_ch == ')' or rc_after_ch == ',' or \ - rc_after_ch == '\r' or rc_after_ch == '\n': - rc_after_ok = 1 - if rc_before_ok == 1 and rc_after_ok == 1: - rc_name_match = 1 - rc_cpos += 1 - - if rc_star == 0 and rc_name_match == 0: - continue - - # 复制子模块名到新缓冲区(pyi_buf + rc_sub_start 不是 NUL 结尾) - rc_sub_buf: str = pool.alloc(rc_sub_len + 1) - if rc_sub_buf is None: - continue - rc_si: t.CSizeT - for rc_si in range(rc_sub_len): - rc_sub_buf[rc_si] = pyi_buf[rc_sub_start + rc_si] - rc_sub_buf[rc_sub_len] = '\0' - - # 构建完整子模块名 base_mod.X - rc_full_len: t.CSizeT = string.strlen(base_mod) + 1 + rc_sub_len + 1 - rc_full_mod: str = pool.alloc(rc_full_len) - if rc_full_mod is None: - continue - viperlib.snprintf(rc_full_mod, rc_full_len, "%s.%s", base_mod, rc_sub_buf) - - # 防循环:若 base_mod 已以 "."+rc_sub_buf 结尾(如 ast.base 再拼 - # .base → ast.base.base),说明子模块递归在重复追加同一模块段 - # (模块间循环 re-export / 后缀匹配容错命中自身),跳过该次递归 - # (NewAstTest CONST_INT 查找 dump:ast.base.base.base 无限增长根因)。 - rc_blen: t.CSizeT = string.strlen(base_mod) - if rc_blen > rc_sub_len + 1: - rc_tail: str = base_mod + (rc_blen - rc_sub_len) - if rc_tail[0] == '.' and \ - string.strncmp(rc_tail + 1, rc_sub_buf, rc_sub_len) == 0: - continue - - # 构建临时 from_imports "name:full_mod" - rc_fi_len: t.CSizeT = name_len_rc + 1 + string.strlen(rc_full_mod) + 1 - rc_fi: str = pool.alloc(rc_fi_len) - if rc_fi is None: - continue - viperlib.snprintf(rc_fi, rc_fi_len, "%s:%s", name, rc_full_mod) - - # 递归调用查找子模块 - rc_sub_val: int = self._lookup_cross_module_cdefine(pool, name, rc_fi, None, depth + 1, node) - if HandlesType.is_cdefine_found() != 0: - result_val = rc_sub_val - result_found = 1 - - stdlib.free(pyi_buf) - - # 9.6 from_imports star fallback 模块中未找到:回退到 imported_modules 遍历 - # 当 `from stdint import *` 导致 star fallback 返回 stdint,但目标常量 - # (如 SHARE_READ)实际在 `import w32.fileio` 导入的模块中时, - # 需要遍历 imported_modules 逐个查找 - if result_found == 0 and imported_modules is not None: - im2_len: t.CSizeT = string.strlen(imported_modules) - im2_ci: t.CSizeT = 0 - while im2_ci < im2_len and result_found == 0: - while im2_ci < im2_len and imported_modules[im2_ci] == ' ': - im2_ci += 1 - if im2_ci >= im2_len: - break - im2_start: t.CSizeT = im2_ci - while im2_ci < im2_len and imported_modules[im2_ci] != ' ': - im2_ci += 1 - im2_end: t.CSizeT = im2_ci - im2_nlen: t.CSizeT = im2_end - im2_start - if im2_nlen > 0 and im2_nlen < 256: - im2_buf: str = pool.alloc(im2_nlen + 1) - if im2_buf is not None: - mk3: t.CSizeT = 0 - while mk3 < im2_nlen: - im2_buf[mk3] = imported_modules[im2_start + mk3] - mk3 += 1 - im2_buf[im2_nlen] = '\0' - sub_fi2: str = pool.alloc(im2_nlen + 3) - if sub_fi2 is not None: - sub_fi2[0] = '*' - sub_fi2[1] = ':' - mk4: t.CSizeT = 0 - while mk4 < im2_nlen: - sub_fi2[2 + mk4] = im2_buf[mk4] - mk4 += 1 - sub_fi2[2 + im2_nlen] = '\0' - sub_val2: t.CInt64T = self._lookup_cross_module_cdefine(pool, name, sub_fi2, None, depth + 1, node) - if HandlesType.is_cdefine_found() != 0: - result_val = sub_val2 - result_found = 1 - - # 10. 缓存到当前模块的 CDefine 表中,并写入跨模块 perm_pool 缓存 - # 浮点 CDefine 已在匹配循环中 register_cdefine_double 缓存 - # (res_is_double=1),此处只缓存整数 CDefine,避免覆盖 double。 - if result_found != 0: - if res_is_str != 0: - # 字符串 CDefine:值已在匹配循环 register_cdefine_string(val_buf - # 是命中行的字符串内容,pool 分配跨函数有效),此处只写跨模块缓存 - if base_mod is not None: - ck_len_s: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2 - ckey_s: str = pool.alloc(ck_len_s) - if ckey_s is not None: - viperlib.snprintf(ckey_s, ck_len_s, "%s@%s", name, base_mod) - HandlesType.register_xmod_cdefine(ckey_s, val_buf, 0, 1) - elif res_is_double == 0: - HandlesType.register_cdefine_constant(pool, name, result_val) - # 跨模块查找缓存(perm_pool 永久,跨文件复用):整数 - # key 与入口查询一致:"name@源模块"(用截断后的 base_mod, - # 与 mod_name_raw 一致——两者都是去点后的模块名,保证 key 匹配) - if base_mod is not None: - ck_len: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2 - ckey_buf: str = pool.alloc(ck_len) - if ckey_buf is not None: - viperlib.snprintf(ckey_buf, ck_len, "%s@%s", name, base_mod) - cbuf_i: str = pool.alloc(32) - if cbuf_i is not None: - viperlib.snprintf(cbuf_i, 32, "%lld", result_val) - HandlesType.register_xmod_cdefine(ckey_buf, cbuf_i, 0, 0) - else: - # 浮点:从本地表取回 %.17g 文本,写入跨模块缓存(保精度) - if base_mod is not None: - ck_len2: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2 - ckey2: str = pool.alloc(ck_len2) - if ckey2 is not None: - viperlib.snprintf(ckey2, ck_len2, "%s@%s", name, base_mod) - dval_cc: double = HandlesType.lookup_cdefine_double(name) - if HandlesType.is_cdefine_double() != 0: - cbuf_d: str = pool.alloc(64) - if cbuf_d is not None: - stdio.snprintf(cbuf_d, 64, "%.17g", dval_cc) - HandlesType.register_xmod_cdefine(ckey2, cbuf_d, 1, 0) - HandlesType.set_cdefine_found(1) - else: - HandlesType.set_cdefine_found(0) - - return result_val - # ============================================================ - # _is_cdefine_name_pattern - 检查名字是否符合 CDefine 命名约定 - # - # CDefine 常量(如 FOREGROUND_GREEN, STD_OUTPUT_HANDLE, SCOPE_MODULE) - # 都遵循 ALL_CAPS 约定:仅含大写字母 A-Z、数字 0-9、下划线 _, - # 且至少含一个大写字母。 - # - # Python 关键字(match, if, for)和变量名(self, pool, builder) - # 都含小写字母,不会匹配,从而避免 fail-fast 误报。 - # - # 返回: 1=符合 CDefine 命名约定, 0=不符合 - # ============================================================ - def _is_cdefine_name_pattern(self, name: str) -> int: - """检查名字是否符合 CDefine 命名约定(全大写+下划线+数字)""" - if name is None: - return 0 - has_upper: int = 0 - i: t.CSizeT = 0 - while name[i] != '\0': - c: t.CChar = name[i] - if c >= 'a' and c <= 'z': - return 0 - if c >= 'A' and c <= 'Z': - has_upper = 1 - i += 1 - return has_upper - # ============================================================ - # 翻译变量引用(Name 节点)→ load - # ============================================================ - def _const_int_for_cdefine(self, pool: memhub.MemBuddy | t.CPtr, - value: t.CInt64T) -> llvmlite.Value | t.CPtr: - """CDefine 整数常量 → LLVM 常量(对齐 TPC TypeConvert 的 64 位升级) - - 规则(与 translate_constant 的 i32 溢出升级一致,但保留 0xFFFFFFFF 语义): - 值超 32 位无符号范围(> 0xFFFFFFFF)→ i64 全精度常量 - (如 sys.maxsize = 9223372036854775807); - 否则 → i32 常量,内部 t.CInt 截断(0xFFFFFFFF → -1,保持既有 - INVALID_HANDLE_VALUE / WAIT_FAILED = -1 语义不变,避免 i32 4294967295 - 生成非法 LLVM IR 文本 "i32 4294967295")。 - - 注意:不能用 `value > 4294967295` 直接比较——TPV 编译自身源码时大数字面量 - (> 0x7FFFFFFF)在字面量层回绕成 i32(sext 后等于 -1),阈值恒成立导致所有 - 正数 CDefine 都被升 i64(INVALID_FILE_ATTRIBUTES 0xFFFFFFFF 从 i32 -1 变 - i64 4294967295 → 与 _get_attrs 的 sext(-1) 比较失败,SysLibTest exists FAIL 根因)。 - 改用截断回比较:t.CUInt32T(value) 回绕后还原,与 value 不等即超 u32 范围。 - """ - if value >= 0 and t.CUInt64T(t.CUInt32T(value)) != value: - return llvmlite.const_int64(pool, value) +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import w32.fileio as fileio +import lib.core.CompilerFactory as CompilerFactory +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.StubMerger as StubMerger +import lib.core.VLogger as VLogger +import lib.Projectrans.Config as Config +import lib.Projectrans.Utils as Utils + + +import lib.core.Gen.ExprGenBase as ExprGenBase +import lib.core.StubMergerCollect as StubMergerCollect +import lib.core.StubMergerStore as StubMergerStore + +# ============================================================ +# ExprGenCdef - ExprGenMixin 拆分(阶段 D):跨模块 CDefine 查找 +# +# 继承 ExprGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class ExprGenCdef(ExprGenBase.ExprGenBase): + """跨模块 CDefine 查找""" + + # ============================================================ + # _build_source_path_from_sha1 - 通过 SHA1 从存储器构建源 .vp/.py 文件路径 + # + # .vpi 文件可能未生成(Phase1 未输出 vpi),此时回退读取源 .py 文件。 + # 从 StubMerger 全局存储器查找 SHA1 对应的相对路径, + # 根据 rel_path 前缀选择基础目录: + # - rel_path 以 "lib/" 开头 → App 源文件,用 {Config.SourceDir}/{rel_path} + # - 其他 → includes 文件,用 {Config.IncludesDir}/{rel_path} + # + # Returns: + # stdlib.malloc 分配的路径字符串(调用者负责 free),None 失败 + # ============================================================ + def _build_source_path_from_sha1(self, sha1: str) -> str: + """通过 SHA1 从全局存储器构建源 .py 文件路径""" + if sha1 is None: + return None + if Config.IncludesDir is None: + return None + # 从 StubMerger 全局存储器获取相对路径数组 + rel_arr_ptr: bytes | t.CPtr = StubMergerStore.GetSha1StoreRelArrPtr() + count: int = StubMergerStore.GetSha1StoreCount() + if rel_arr_ptr is None or count <= 0: + return None + sha1_arr_ptr: bytes | t.CPtr = StubMergerStore.GetSha1StoreArrPtr() + if sha1_arr_ptr is None: + return None + # 遍历查找匹配的 SHA1 + idx_s: int = -1 + for i in range(count): + sidx: t.CSizeT = t.CSizeT(i) * 17 + cur_sha1: str = sha1_arr_ptr + sidx + if cur_sha1[0] == '\0': + continue + if string.strcmp(cur_sha1, sha1) == 0: + idx_s = i + break + if idx_s < 0: + return None + # 获取相对路径(MAX_REL_PATH_LEN=256,避免跨模块 CDefine 解析问题) + MAX_RPL: t.CSizeT = 256 + ridx: t.CSizeT = t.CSizeT(idx_s) * MAX_RPL + rel_path: str = rel_arr_ptr + ridx + if rel_path[0] == '\0': + return None + # 选择基础目录:rel_path 以 "lib/" 开头 → App 源文件(SourceDir); + # 以 "includes/" 开头 → includes 文件(去掉 "includes/" 前缀)。 + # 其他 rel_path(如 VKernel 的 "drivers/core/cpu/cpu.vp")无前缀, + # 无法从 rel_path 判断归属:先试 SourceDir(App 文件),文件不存在 + # 再试 IncludesDir(includes 文件的 RelPath 同样无前缀存储)。 + # 避免路径构建错误导致跨模块 CDefine 查找静默失败。 + base_dir: str = None + rel_used: str = rel_path + if string.strlen(rel_path) >= 4: + if (rel_path[0] == 'l' and rel_path[1] == 'i' and + rel_path[2] == 'b' and rel_path[3] == '/'): + base_dir = Config.SourceDir if Config.SourceDir is not None else Config.IncludesDir + if base_dir is None and string.strlen(rel_path) >= 9: + if (rel_path[0] == 'i' and rel_path[1] == 'n' and + rel_path[2] == 'c' and rel_path[3] == 'l' and + rel_path[4] == 'u' and rel_path[5] == 'd' and + rel_path[6] == 'e' and rel_path[7] == 's' and + rel_path[8] == '/'): + rel_used = rel_path + 9 + base_dir = Config.IncludesDir + if base_dir is None: + base_dir = Config.SourceDir if Config.SourceDir is not None else Config.IncludesDir + # 构建完整路径: {base_dir}/{rel_used} + base_len: t.CSizeT = string.strlen(base_dir) + rel_len: t.CSizeT = string.strlen(rel_used) + path_len: t.CSizeT = base_len + rel_len + 2 + buf: str = stdlib.malloc(path_len) + if buf is None: + return None + viperlib.snprintf(buf, path_len, "%s/%s", base_dir, rel_used) + # 存在性检查:SourceDir 下不存在且 IncludesDir 不同 → 重试 IncludesDir + pf_chk: fileio.File | t.CPtr = fileio.File(buf, fileio.MODE.R) + if pf_chk.closed: + pf_chk.close() + if Config.IncludesDir is not None and base_dir != Config.IncludesDir: + stdlib.free(buf) + base_len2: t.CSizeT = string.strlen(Config.IncludesDir) + path_len2: t.CSizeT = base_len2 + rel_len + 2 + buf = stdlib.malloc(path_len2) + if buf is None: + return None + viperlib.snprintf(buf, path_len2, "%s/%s", Config.IncludesDir, rel_used) + pf_chk2: fileio.File | t.CPtr = fileio.File(buf, fileio.MODE.R) + if pf_chk2.closed: + pf_chk2.close() + stdlib.free(buf) + return None + pf_chk2.close() + else: + stdlib.free(buf) + return None + else: + pf_chk.close() + return buf + # ============================================================ + # _lookup_cross_module_cdefine - 跨模块查找 CDefine 常量 + # + # 当当前模块的 CDefine 表中找不到某个 Name 时,从 from_imports + # 解析出源模块,再从该模块的 pyi 文件中解析 CDefine 常量值。 + # 找到后缓存到当前模块的 CDefine 表中,避免重复查找。 + # + # pyi 文件格式: "NAME: t.CDefine = value" + # ============================================================ + def _lookup_cross_module_cdefine(self, pool: memhub.MemBuddy | t.CPtr, + name: str, + from_imports: str, + imported_modules: str = None, + depth: int = 0, + node: ast.AST | t.CPtr = None) -> t.CInt64T: + """跨模块查找 CDefine 常量,返回值(64 位)或 -1(未找到) + + 查找顺序: + 1. from_imports 精确匹配(from X import NAME) + 2. from_imports star 回退(from X import *) + 3. imported_modules 遍历(import X):当通过 import X 导入模块时, + 模块中定义的 CDefine 常量可通过此路径找到(如方法签名默认参数引用) + + depth: 递归深度(子模块递归/imported_modules 遍历的内部调用递增)。 + node: 触发查找的 AST 节点(递归内传 None,line 0;顶层调用点传实际节点)。 + """ + # 递归深度守卫:子模块递归(from .X import NAME re-export 链)与 + # imported_modules 遍历组合可能形成循环(模块间互相 from import), + # 无上限时无限递归 → 每次递归 pool.alloc 缓冲(rc_sub_buf/rc_full_mod/ + # rc_fi/im_buf/sub_fi)→ O(n²) 累积 → 主池 1.5GB OOM + # (NewAstTest CONST_INT 单次查找 14593 次调用,fi 恒为 CONST_INT:ast)。 + # 正常跨模块 CDefine 查找深度 < 8(如 ast → ast.base),32 上限 fail-fast + # 暴露循环 import 链(而非静默 OOM)。报错带 node 行号 + 当前递归模块链。 + if depth > 32: + err_buf: str = pool.alloc(256) + if err_buf is not None: + viperlib.snprintf(err_buf, 256, + "跨模块 CDefine 查找递归过深(疑似模块循环 import/re-export): %s (depth=%d fi=%s)", + name, depth, + from_imports if from_imports is not None else "(nil)") + self.Gen.TypeGenErr.fatal_error(node, err_buf, "InternalCompilerError") + self.Gen.TypeGenErr.fatal_error(node, + "跨模块 CDefine 查找递归过深(疑似模块循环 import/re-export)", "InternalCompilerError") + # 入口处清零标志,确保所有早退路径(return -1)都返回"未找到"状态 + # 避免递归调用时前一次成功的标志残留导致误判 + self.Gen.TypeGenCDef.set_cdefine_found(0) + if name is None: + return -1 + if from_imports is None: + from_imports = "" + + # 1. 从 from_imports 查找名称对应的模块名 + # 先尝试精确匹配(allow_star_fallback=0),避免 CDefine 常量被 star import 误导 + mod_name_raw: str = self.Gen.ImportsGen.lookup_from_import(from_imports, name, 0) + if mod_name_raw is None: + # 精确匹配失败:尝试 star import 回退 + mod_name_raw = self.Gen.ImportsGen.lookup_from_import(from_imports, name, 1) + + # 截断模块名到 NUL 结尾:lookup_from_import 返回指向 from_imports 内部的 + # 指针(非 NUL 结尾,后随空格分隔的其他条目,如 "ast CONST_STR:ast ...")。 + # 不截断会污染 base_mod:strlen 读到整个 from_imports 末尾 → rc_full_mod + # 每层累积整个列表 + ".base"(dump:ast.base.base.base 无限递归根因), + # 且缓存 key 错乱("CONST_INT@ast CONST_STR:ast ...")无法命中。 + # 与 _lookup_sha1_from_modname_raw 的截断逻辑一致(空格/冒号/NUL 分隔)。 + base_mod: str = None + if mod_name_raw is not None: + mbl: t.CSizeT = 0 + while mod_name_raw[mbl] != ' ' and mod_name_raw[mbl] != '\0' \ + and mod_name_raw[mbl] != ':': + mbl += 1 + mb_buf: str = pool.alloc(mbl + 1) + if mb_buf is not None: + mi2: t.CSizeT + for mi2 in range(mbl): + mb_buf[mi2] = mod_name_raw[mi2] + mb_buf[mbl] = '\0' + base_mod = mb_buf + while base_mod is not None and base_mod[0] == '.': + base_mod = base_mod + 1 + + # 跨模块 CDefine 查找缓存(perm_pool 永久,跨文件复用): + # 首次查找成功后结果缓存,后续文件(含 reset_to(mark2)/模块切换)直接命中, + # 避免 CONST_INT 跨模块递归查找反复触发(NewAstTest OOM 根因—— + # 14593 次调用全部重复递归 ast → ast.base → ...)。 + # key = "name@源模块"(源模块维度,用去点后的 base_mod 保证一致), + # 保持模块隔离:不同源模块的同名 CDefine 值不同时不串值。 + # 仅 ALL_CAPS 全局唯一宏名才进入本函数(_is_cdefine_name_pattern 已过滤)。 + xkey_buf: str = None + if base_mod is not None: + xk_len: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2 + xkey_buf = pool.alloc(xk_len) + if xkey_buf is not None: + viperlib.snprintf(xkey_buf, xk_len, "%s@%s", name, base_mod) + xval: str = self.Gen.TypeGenCDef.lookup_xmod_cdefine(xkey_buf) + if self.Gen.TypeGenCDef.is_cdefine_found() != 0: + if self.Gen.TypeGenCDef.is_cdefine_str() != 0: + self.Gen.TypeGenCDef.register_cdefine_string(pool, name, xval) + elif self.Gen.TypeGenCDef.is_cdefine_double() != 0: + xd_v: double = string.atof(xval) + self.Gen.TypeGenCDef.register_cdefine_double(pool, name, xd_v) + else: + xv_i: t.CInt64T = string.atoll(xval) + self.Gen.TypeGenCDef.register_cdefine_constant(pool, name, xv_i) + return string.atoll(xval) + + # 2. from_imports 查找失败:直接回退到 imported_modules 遍历(步骤 9.6) + # 注意:star fallback 可能返回错误模块(如 stdint),常量实际不在其中, + # 步骤 9.6 会在该模块查找失败后继续遍历 imported_modules + if mod_name_raw is None: + # from_imports 完全没有匹配(精确和 star 都失败) + # 直接进入 imported_modules 遍历(步骤 9.6) + if imported_modules is None: + return -1 + # 跳过 from_imports 模块读取,直接走步骤 9.6 的 imported_modules 遍历 + # 设置 result_found=0 跳过步骤 3-9,直接到 9.6 + self.Gen.TypeGenCDef.set_cdefine_found(0) + # 直接遍历 imported_modules + im_len: t.CSizeT = string.strlen(imported_modules) + im_ci: t.CSizeT = 0 + while im_ci < im_len: + while im_ci < im_len and imported_modules[im_ci] == ' ': + im_ci += 1 + if im_ci >= im_len: + break + im_start: t.CSizeT = im_ci + while im_ci < im_len and imported_modules[im_ci] != ' ': + im_ci += 1 + im_end: t.CSizeT = im_ci + im_nlen: t.CSizeT = im_end - im_start + if im_nlen > 0 and im_nlen < 256: + im_buf: str = pool.alloc(im_nlen + 1) + if im_buf is not None: + mk: t.CSizeT = 0 + while mk < im_nlen: + im_buf[mk] = imported_modules[im_start + mk] + mk += 1 + im_buf[im_nlen] = '\0' + sub_fi: str = pool.alloc(im_nlen + 3) + if sub_fi is not None: + sub_fi[0] = '*' + sub_fi[1] = ':' + mk2: t.CSizeT = 0 + while mk2 < im_nlen: + sub_fi[2 + mk2] = im_buf[mk2] + mk2 += 1 + sub_fi[2 + im_nlen] = '\0' + sub_val: t.CInt64T = self._lookup_cross_module_cdefine(pool, name, sub_fi, None, depth + 1, node) + if self.Gen.TypeGenCDef.is_cdefine_found() != 0: + return sub_val + return -1 + + # 2. 截断模块名 → 去前导点 → 精确+后缀查找 SHA1(复用 HandlesExprCall 公共逻辑) + sha1: str = self.Gen.CallGenBase._lookup_sha1_from_modname_raw(pool, mod_name_raw) + if sha1 is None: + return -1 + + # 5. 获取 temp_dir + temp_dir: str = self.Gen.TypeGenBase.get_temp_dir() + if temp_dir is None: + return -1 + + # 6. 构建 vpi 文件路径 + td_len: t.CSizeT = string.strlen(temp_dir) + pyi_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, sha1, "vpi") + if pyi_path is None: + return -1 + + # 7. 读取 vpi 文件;若不存在或内容过短(空 stub)则回退读取源 .vp/.py 文件 + PYI_READ_BUF_SIZE: t.CSizeT = 65536 + pyi_buf: bytes = stdlib.malloc(PYI_READ_BUF_SIZE) + if pyi_buf is None: + stdlib.free(pyi_path) + return -1 + pf: fileio.File | t.CPtr = fileio.File(pyi_path, fileio.MODE.R) + need_py_fallback: int = 0 + bytes_read: LONG = 0 + if pf.closed: + # .vpi 文件不存在:回退读取源 .vp/.py 文件 + need_py_fallback = 1 + else: + bytes_read = pf.read_all(pyi_buf, PYI_READ_BUF_SIZE) + pf.close() + # vpi 内容过短(< 10 字节)视为空 stub,回退 .py + if bytes_read < 10: + need_py_fallback = 1 + else: + if bytes_read < PYI_READ_BUF_SIZE: + pyi_buf[bytes_read] = 0 + else: + pyi_buf[PYI_READ_BUF_SIZE - 1] = 0 + # vpi(存根签名文件)中的 CDefine 声明可能只带名字不带值 + # (Converter 旧版只对 CONST_INT/BOOL 等输出 "= value",CONST_FLOAT + # 等不输出 → numpy 的 pi/e 在 stub 中无值),真正的值在源 + # .vp/.py 文件中。旧启发式"vpi 中任一 CDefine 带值 → 不读源"是错的: + # 模块同时含 int CDefine(带值,如 numpy.MAX_NDIM=4)与 float + # CDefine(无值,如 pi)时,int 行让 cd_sig=1 而漏回退源 → pi + # 解析失败 → 退化 @pi 全局指针 → float<->ptr 报错(NumpyTest 根因)。 + # 改为按目标名判定:仅当 vpi 中 name 的 CDefine 行带值时才信任 + # vpi,否则(name 行无值 / name 不在 vpi / 整个 vpi 无带值 CDefine) + # 一律回退读源文件。 + cd_sig: int = 0 + name_has_val: int = 0 + cs_name_len: t.CSizeT = string.strlen(name) + cs_total: t.CSizeT = string.strlen(pyi_buf) + cs_i: t.CSizeT = 0 + while cs_i + 9 < cs_total: + if (pyi_buf[cs_i] == 't' and pyi_buf[cs_i + 1] == '.' and + pyi_buf[cs_i + 2] == 'C' and pyi_buf[cs_i + 3] == 'D' and + pyi_buf[cs_i + 4] == 'e' and pyi_buf[cs_i + 5] == 'f' and + pyi_buf[cs_i + 6] == 'i' and pyi_buf[cs_i + 7] == 'n' and + pyi_buf[cs_i + 8] == 'e'): + # 检查该行剩余部分是否有 '='(带值声明才在 vpi 中匹配) + cd_eq: int = 0 + cs_j: t.CSizeT = cs_i + 9 + while cs_j < cs_total and pyi_buf[cs_j] != '\n': + if pyi_buf[cs_j] == '=': + cd_eq = 1 + break + cs_j += 1 + if cd_eq != 0: + cd_sig = 1 + # 定位该行行首,检查是否以 "name:" 开头(目标名带值) + cs_line_start: t.CSizeT = cs_i + while cs_line_start > 0 and pyi_buf[cs_line_start - 1] != '\n': + cs_line_start -= 1 + if cs_i - cs_line_start >= cs_name_len + 1: + nm_ok: int = 1 + for ki2 in range(cs_name_len): + if pyi_buf[cs_line_start + ki2] != name[ki2]: + nm_ok = 0 + break + if nm_ok == 1 and pyi_buf[cs_line_start + cs_name_len] == ':': + name_has_val = 1 + cs_i += 1 + if cd_sig == 0 or name_has_val == 0: + need_py_fallback = 1 + stdlib.free(pyi_path) + + if need_py_fallback != 0: + # 从 SHA1 存储器查找相对路径,构建 {base_dir}/{rel_path} + src_path: str = self._build_source_path_from_sha1(sha1) + if src_path is None: + # 存储器中找不到 SHA1 = 编译器 bug(Phase1/Phase2 未填充存储器) + # 报错终止,不静默返回 -1(避免后续生成错误的 @UNDEFINED 全局变量引用) + err_buf: str = pool.alloc(512) + if err_buf is not None: + viperlib.snprintf(err_buf, 512, + "跨模块 CDefine 查找失败:SHA1 %s 不在存储器中(base_mod=%s name=%s)。" + "Phase1/Phase2 未正确填充 PopulateSha1MapStore/AppendToSha1MapStore", + sha1, base_mod, name) + VLogger.error(err_buf, "XMOD-CD") + stdlib.free(pyi_buf) + return -1 + pf = fileio.File(src_path, fileio.MODE.R) + stdlib.free(src_path) + if pf.closed: + stdlib.free(pyi_buf) + return -1 + bytes_read = pf.read_all(pyi_buf, PYI_READ_BUF_SIZE) + pf.close() + if bytes_read <= 0: + stdlib.free(pyi_buf) + return -1 + if bytes_read < PYI_READ_BUF_SIZE: + pyi_buf[bytes_read] = 0 + else: + pyi_buf[PYI_READ_BUF_SIZE - 1] = 0 + + # 8. 在 pyi_buf 中查找 "name: t.CDefine = value" 行 + # 格式: NAME: t.CDefine = value + name_len: t.CSizeT = string.strlen(name) + total_len: t.CSizeT = string.strlen(pyi_buf) + pos: t.CSizeT = 0 + result_val: t.CInt64T = 0 + result_found: int = 0 + res_is_double: int = 0 + res_is_str: int = 0 + while pos < total_len: + # 找到行首 + line_start: t.CSizeT = pos + # 找到行尾 + while pos < total_len and pyi_buf[pos] != '\n': + pos += 1 + line_len: t.CSizeT = pos - line_start + if pos < total_len: + pos += 1 # 跳过 '\n' + + # 检查行是否以 "name:" 开头 + if line_len < name_len + 1: + continue + match_ok: int = 1 + for ki in range(name_len): + if pyi_buf[line_start + ki] != name[ki]: + match_ok = 0 + break + if match_ok == 0: + continue + if pyi_buf[line_start + name_len] != ':': + continue + + # 检查行是否包含 "t.CDefine" + # 在行中查找 "t.CDefine" + has_cdefine: int = 0 + ci: t.CSizeT = line_start + name_len + 1 + while ci + 8 <= line_start + line_len: + if (pyi_buf[ci] == 't' and pyi_buf[ci + 1] == '.' and + pyi_buf[ci + 2] == 'C' and pyi_buf[ci + 3] == 'D' and + pyi_buf[ci + 4] == 'e' and pyi_buf[ci + 5] == 'f' and + pyi_buf[ci + 6] == 'i' and pyi_buf[ci + 7] == 'n' and + pyi_buf[ci + 8] == 'e'): + has_cdefine = 1 + break + ci += 1 + if has_cdefine == 0: + continue + + # 找到 "=" 后面的值 + eq_pos: t.CSizeT = line_start + name_len + 1 + while eq_pos < line_start + line_len and pyi_buf[eq_pos] != '=': + eq_pos += 1 + if eq_pos >= line_start + line_len: + continue + eq_pos += 1 # 跳过 '=' + + # 跳过空格 + while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': + eq_pos += 1 + + # 检查是否是 t.CUnsignedLong(...) / t.CLong(...) / t.CInt(...) 等类型构造函数 + # 格式: t.CUnsignedLong(-11) / t.CUnsignedLong(0xFFFFFFFF) + # 如果是,跳过 "t.CXxx(" 前缀,解析括号内的值,忽略结尾 ')' + is_type_ctor: int = 0 + if eq_pos + 2 < line_start + line_len: + if pyi_buf[eq_pos] == 't' and pyi_buf[eq_pos + 1] == '.': + # 找到 '(' 的位置 + paren_pos: t.CSizeT = eq_pos + 2 + while paren_pos < line_start + line_len and pyi_buf[paren_pos] != '(': + paren_pos += 1 + if paren_pos < line_start + line_len and pyi_buf[paren_pos] == '(': + is_type_ctor = 1 + eq_pos = paren_pos + 1 # 跳过 '(' + # 跳过括号内可能的前导空格 + while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': + eq_pos += 1 + + # 括号包裹标记:(1 << 23) / (512) / (A | B) + is_paren_expr: int = 0 + if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '(': + is_paren_expr = 1 + eq_pos += 1 + while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': + eq_pos += 1 + + # === 解析左操作数 token(数字 / hex / 负号 / 名称) === + # 负号标记 + is_neg: int = 0 + if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '-': + is_neg = 1 + eq_pos += 1 + val_str_start: t.CSizeT = eq_pos + val_str_len: t.CSizeT = 0 + is_hex: int = 0 + is_float_val: int = 0 + is_name_val: int = 0 + is_str_val: int = 0 + # 字符串值(如 ZLIB_VERSION: t.CDefine = "1.3.2"):读引号内内容。 + # 跨模块读回此前不支持引号 → val_str_len=0 被跳过 → "跨模块 CDefine + # 未找到"(test_pyzlib.vp pyzlib.ZLIB_VERSION 根因) + if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '"': + is_str_val = 1 + eq_pos += 1 # 跳过开引号 + val_str_start = eq_pos + while eq_pos < line_start + line_len and pyi_buf[eq_pos] != '"': + val_str_len += 1 + eq_pos += 1 + if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '"': + eq_pos += 1 # 跳过闭引号 + if eq_pos + 1 < line_start + line_len: + if pyi_buf[eq_pos] == '0' and (pyi_buf[eq_pos + 1] == 'x' or pyi_buf[eq_pos + 1] == 'X'): + is_hex = 1 + val_str_len = 2 + eq_pos += 2 + elif (pyi_buf[eq_pos] >= 'A' and pyi_buf[eq_pos] <= 'Z') or \ + (pyi_buf[eq_pos] >= 'a' and pyi_buf[eq_pos] <= 'z') or \ + pyi_buf[eq_pos] == '_': + is_name_val = 1 + while eq_pos < line_start + line_len: + c_tk: t.CChar = pyi_buf[eq_pos] + if (c_tk >= 'A' and c_tk <= 'Z') or (c_tk >= 'a' and c_tk <= 'z') or \ + (c_tk >= '0' and c_tk <= '9') or c_tk == '_': + val_str_len += 1 + eq_pos += 1 + else: + break + # 数字/hex 字符续读(字符串值已整体读取,跳过) + while eq_pos < line_start + line_len and is_name_val == 0 and is_str_val == 0: + ch: t.CChar = pyi_buf[eq_pos] + if is_hex == 1: + if ((ch >= '0' and ch <= '9') or + (ch >= 'a' and ch <= 'f') or + (ch >= 'A' and ch <= 'F')): + val_str_len += 1 + eq_pos += 1 + else: + break + else: + if ch >= '0' and ch <= '9': + val_str_len += 1 + eq_pos += 1 + elif ch == '.' and is_float_val == 0: + # 浮点值:'3.14159'('.' 只允许一次) + is_float_val = 1 + val_str_len += 1 + eq_pos += 1 + else: + break + + if val_str_len == 0 and is_str_val == 0: + continue + + # 复制左 token 到缓冲区 + val_buf: str = pool.alloc(val_str_len + 1) + if val_buf is None: + continue + for vi in range(val_str_len): + val_buf[vi] = pyi_buf[val_str_start + vi] + val_buf[val_str_len] = '\0' + + # 左 token 求值 + lval: t.CInt64T = 0 + l_is_double: int = 0 + ldbl: double = 0.0 + if is_str_val != 0: + # 字符串 CDefine(如 ZLIB_VERSION = "1.3.2"):注册字符串值 + # (含空串 ""),result_found 标记 + res_is_str 供尾部跳过整数 + # 注册/缓存(否则 register_cdefine_constant 把字符串当 0 整数) + self.Gen.TypeGenCDef.register_cdefine_string(pool, name, val_buf) + result_val = 0 + result_found = 1 + res_is_str = 1 + elif is_name_val != 0: + # True/False 布尔字面量 → 1/0(对齐 TPC:bool 在 CDefine 语境按整数处理) + if string.strcmp(val_buf, "True") == 0: + lval = 1 + elif string.strcmp(val_buf, "False") == 0: + lval = 0 + else: + # 名称引用:查当前 CDefine 表(如 FOREGROUND_COMBO = FOREGROUND_RED) + lval = self.Gen.TypeGenCDef.lookup_cdefine_constant(val_buf) + if self.Gen.TypeGenCDef.is_cdefine_found() == 0: + # 名称未注册:该行无法求值,跳过 + continue + elif is_hex == 1: + # 手动解析十六进制(跳过 0x 前缀)——64 位累加, + # 0xFFFFFFFF=4294967295 保持全精度(常量生成端 i32 截断回 -1) + hex_result: t.CInt64T = 0 + hex_buf: str = val_buf + 2 # 跳过 "0x" + for hi in range(val_str_len - 2): + hc: t.CChar = hex_buf[hi] + hd: int = 0 + if hc >= '0' and hc <= '9': + hd = hc - '0' + elif hc >= 'a' and hc <= 'f': + hd = hc - 'a' + 10 + elif hc >= 'A' and hc <= 'F': + hd = hc - 'A' + 10 + else: + break + hex_result = hex_result * 16 + hd + lval = hex_result + elif is_float_val != 0: + l_is_double = 1 + ldbl = string.atof(val_buf) + lval = string.atoll(val_buf) + else: + lval = string.atoll(val_buf) + if is_neg != 0: + lval = -lval + if l_is_double != 0: + ldbl = -ldbl + + # 跳过空格,检查是否有二元运算符 + while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': + eq_pos += 1 + + # 解析运算符(<< >> | & ^ + - * /) + cd_op: int = 0 + if eq_pos + 1 < line_start + line_len: + if pyi_buf[eq_pos] == '<' and pyi_buf[eq_pos + 1] == '<': + cd_op = 1 # LShift + eq_pos += 2 + elif pyi_buf[eq_pos] == '>' and pyi_buf[eq_pos + 1] == '>': + cd_op = 2 # RShift + eq_pos += 2 + if cd_op == 0 and eq_pos < line_start + line_len: + if pyi_buf[eq_pos] == '|': + cd_op = 3 # BitOr + eq_pos += 1 + elif pyi_buf[eq_pos] == '&': + cd_op = 4 # BitAnd + eq_pos += 1 + elif pyi_buf[eq_pos] == '^': + cd_op = 5 # BitXor + eq_pos += 1 + elif pyi_buf[eq_pos] == '+': + cd_op = 6 # Add + eq_pos += 1 + elif pyi_buf[eq_pos] == '-': + cd_op = 7 # Sub + eq_pos += 1 + elif pyi_buf[eq_pos] == '*': + cd_op = 8 # Mult + eq_pos += 1 + elif pyi_buf[eq_pos] == '/': + cd_op = 9 # Div + eq_pos += 1 + + if cd_op != 0: + # === 解析右操作数 token === + while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': + eq_pos += 1 + r_neg: int = 0 + if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '-': + r_neg = 1 + eq_pos += 1 + r_start: t.CSizeT = eq_pos + r_len: t.CSizeT = 0 + r_hex: int = 0 + r_name: int = 0 + if eq_pos + 1 < line_start + line_len: + if pyi_buf[eq_pos] == '0' and (pyi_buf[eq_pos + 1] == 'x' or pyi_buf[eq_pos + 1] == 'X'): + r_hex = 1 + r_len = 2 + eq_pos += 2 + elif (pyi_buf[eq_pos] >= 'A' and pyi_buf[eq_pos] <= 'Z') or \ + (pyi_buf[eq_pos] >= 'a' and pyi_buf[eq_pos] <= 'z') or \ + pyi_buf[eq_pos] == '_': + r_name = 1 + while eq_pos < line_start + line_len: + c_r: t.CChar = pyi_buf[eq_pos] + if (c_r >= 'A' and c_r <= 'Z') or (c_r >= 'a' and c_r <= 'z') or \ + (c_r >= '0' and c_r <= '9') or c_r == '_': + r_len += 1 + eq_pos += 1 + else: + break + while eq_pos < line_start + line_len and r_name == 0: + c_r2: t.CChar = pyi_buf[eq_pos] + if r_hex == 1: + if ((c_r2 >= '0' and c_r2 <= '9') or + (c_r2 >= 'a' and c_r2 <= 'f') or + (c_r2 >= 'A' and c_r2 <= 'F')): + r_len += 1 + eq_pos += 1 + else: + break + else: + if c_r2 >= '0' and c_r2 <= '9': + r_len += 1 + eq_pos += 1 + else: + break + if r_len == 0: + # 运算符后无右操作数:无法求值,跳过该行 + continue + r_buf: str = pool.alloc(r_len + 1) + if r_buf is None: + continue + for r_i in range(r_len): + r_buf[r_i] = pyi_buf[r_start + r_i] + r_buf[r_len] = '\0' + rval: t.CInt64T = 0 + if r_name != 0: + # True/False 布尔字面量 → 1/0 + if string.strcmp(r_buf, "True") == 0: + rval = 1 + elif string.strcmp(r_buf, "False") == 0: + rval = 0 + else: + rval = self.Gen.TypeGenCDef.lookup_cdefine_constant(r_buf) + if self.Gen.TypeGenCDef.is_cdefine_found() == 0: + # 名称未注册:无法求值,跳过该行 + continue + elif r_hex != 0: + rhex_v: t.CInt64T = 0 + rh_buf: str = r_buf + 2 + for rh_i in range(r_len - 2): + rc: t.CChar = rh_buf[rh_i] + rd: int = 0 + if rc >= '0' and rc <= '9': + rd = rc - '0' + elif rc >= 'a' and rc <= 'f': + rd = rc - 'a' + 10 + elif rc >= 'A' and rc <= 'F': + rd = rc - 'A' + 10 + else: + break + rhex_v = rhex_v * 16 + rd + rval = rhex_v + else: + rval = string.atoll(r_buf) + if r_neg != 0: + rval = -rval + # 计算二元表达式结果(对齐 TPC ConstEvaluator) + if cd_op == 1: + result_val = lval << rval + elif cd_op == 2: + result_val = lval >> rval + elif cd_op == 3: + result_val = lval | rval + elif cd_op == 4: + result_val = lval & rval + elif cd_op == 5: + result_val = lval ^ rval + elif cd_op == 6: + result_val = lval + rval + elif cd_op == 7: + result_val = lval - rval + elif cd_op == 8: + result_val = lval * rval + else: + if rval == 0: + continue + result_val = lval // rval + result_found = 1 + break + else: + # 单值(无运算符):括号内单值如 (512) / (-11) 也走这里 + if is_paren_expr != 0: + while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': + eq_pos += 1 + if eq_pos < line_start + line_len and pyi_buf[eq_pos] == ')': + eq_pos += 1 + if is_float_val != 0: + # 浮点 CDefine(如 U_M_PI = 3.14159...): + # 值缓存为 double(register_cdefine_double),供调用处生成 + # double 常量;整数部分供 int 路径使用(is_cdefine_double 标志)。 + self.Gen.TypeGenCDef.register_cdefine_double(pool, name, ldbl) + result_val = lval + result_found = 1 + res_is_double = 1 + else: + result_val = lval + result_found = 1 + break + + # 9.5 如果当前模块文件中没找到,递归查找子模块 + # 处理 from .X import NAME 和 from .X import * 的情况 + # 例如 ast.__init__.vp 中 from .base import CONST_INT, ... + # 需要递归查找 ast.base 子模块中的 CONST_INT: t.CDefine = 1 + if result_found == 0: + # base_mod 已在函数开头计算(mod_name_raw 去前导点), + # 供子模块递归构建 "base_mod.X" 全名。 + name_len_rc: t.CSizeT = string.strlen(name) + rc_pos: t.CSizeT = 0 + while rc_pos < total_len and result_found == 0: + # 找到行首 + rc_line_start: t.CSizeT = rc_pos + # 找到行尾 + while rc_pos < total_len and pyi_buf[rc_pos] != '\n': + rc_pos += 1 + rc_line_len: t.CSizeT = rc_pos - rc_line_start + if rc_pos < total_len: + rc_pos += 1 + + # 检查行是否以 "from ." 开头(相对导入子模块) + if rc_line_len < 12: + continue + if pyi_buf[rc_line_start] != 'f' or pyi_buf[rc_line_start+1] != 'r' or \ + pyi_buf[rc_line_start+2] != 'o' or pyi_buf[rc_line_start+3] != 'm' or \ + pyi_buf[rc_line_start+4] != ' ' or pyi_buf[rc_line_start+5] != '.': + continue + + # 提取子模块名(从 rc_line_start+6 开始,到空格/tab 为止) + rc_sub_start: t.CSizeT = rc_line_start + 6 + rc_sub_end: t.CSizeT = rc_sub_start + while rc_sub_end < rc_line_start + rc_line_len and \ + pyi_buf[rc_sub_end] != ' ' and pyi_buf[rc_sub_end] != '\t': + rc_sub_end += 1 + rc_sub_len: t.CSizeT = rc_sub_end - rc_sub_start + if rc_sub_len == 0: + continue + + # 检查行是否包含 "import" + rc_has_import: int = 0 + rc_ipos: t.CSizeT = rc_sub_end + while rc_ipos + 6 <= rc_line_start + rc_line_len: + if pyi_buf[rc_ipos] == 'i' and pyi_buf[rc_ipos+1] == 'm' and \ + pyi_buf[rc_ipos+2] == 'p' and pyi_buf[rc_ipos+3] == 'o' and \ + pyi_buf[rc_ipos+4] == 'r' and pyi_buf[rc_ipos+5] == 't': + rc_has_import = 1 + break + rc_ipos += 1 + if rc_has_import == 0: + continue + + # 检查 NAME 是否在导入列表中,或导入是 * + # 处理多行导入:from .X import (... NAME, ...) + # 从 "import" 之后扫描,如果有 "(" 则扫描到 ")" 为止 + rc_imp_start: t.CSizeT = rc_ipos + 6 + rc_star: int = 0 + rc_name_match: int = 0 + + # 确定扫描范围:单行或跨行(括号内) + rc_scan_end: t.CSizeT = rc_line_start + rc_line_len + rc_has_paren: int = 0 + rc_pp: t.CSizeT = rc_imp_start + while rc_pp < rc_line_start + rc_line_len: + if pyi_buf[rc_pp] == '(': + rc_has_paren = 1 + break + if pyi_buf[rc_pp] == '*': + rc_star = 1 + rc_pp += 1 + if rc_has_paren != 0: + # 多行导入:从 "(" 之后扫描到 ")" 为止 + rc_scan_end = rc_pp + 1 + rc_paren_closed: int = 0 + rc_sp: t.CSizeT = rc_pp + 1 + while rc_sp < total_len and rc_paren_closed == 0: + if pyi_buf[rc_sp] == ')': + rc_paren_closed = 1 + rc_scan_end = rc_sp + break + rc_sp += 1 + if rc_paren_closed == 0: + rc_scan_end = total_len + + # 在 rc_imp_start 到 rc_scan_end 范围内查找 NAME 和 * + rc_cpos: t.CSizeT = rc_imp_start + while rc_cpos < rc_scan_end: + rc_ch: t.CChar = pyi_buf[rc_cpos] + if rc_ch == '*': + rc_star = 1 + # 检查 NAME 是否匹配(作为完整单词) + if rc_cpos + name_len_rc <= rc_scan_end: + rc_match: int = 1 + rc_ki: t.CSizeT + for rc_ki in range(name_len_rc): + if pyi_buf[rc_cpos + rc_ki] != name[rc_ki]: + rc_match = 0 + break + if rc_match == 1: + # 检查前字符是否是非标识符字符 + rc_before_ok: int = 0 + if rc_cpos == rc_imp_start: + rc_before_ok = 1 + else: + rc_before_ch: t.CChar = pyi_buf[rc_cpos - 1] + if rc_before_ch == ' ' or rc_before_ch == '\t' or \ + rc_before_ch == '(' or rc_before_ch == ',' or \ + rc_before_ch == '\n' or rc_before_ch == '\r': + rc_before_ok = 1 + # 检查后字符是否是非标识符字符 + rc_after_ok: int = 0 + rc_after_pos: t.CSizeT = rc_cpos + name_len_rc + if rc_after_pos >= rc_scan_end: + rc_after_ok = 1 + else: + rc_after_ch: t.CChar = pyi_buf[rc_after_pos] + if rc_after_ch == ' ' or rc_after_ch == '\t' or \ + rc_after_ch == ')' or rc_after_ch == ',' or \ + rc_after_ch == '\r' or rc_after_ch == '\n': + rc_after_ok = 1 + if rc_before_ok == 1 and rc_after_ok == 1: + rc_name_match = 1 + rc_cpos += 1 + + if rc_star == 0 and rc_name_match == 0: + continue + + # 复制子模块名到新缓冲区(pyi_buf + rc_sub_start 不是 NUL 结尾) + rc_sub_buf: str = pool.alloc(rc_sub_len + 1) + if rc_sub_buf is None: + continue + rc_si: t.CSizeT + for rc_si in range(rc_sub_len): + rc_sub_buf[rc_si] = pyi_buf[rc_sub_start + rc_si] + rc_sub_buf[rc_sub_len] = '\0' + + # 构建完整子模块名 base_mod.X + rc_full_len: t.CSizeT = string.strlen(base_mod) + 1 + rc_sub_len + 1 + rc_full_mod: str = pool.alloc(rc_full_len) + if rc_full_mod is None: + continue + viperlib.snprintf(rc_full_mod, rc_full_len, "%s.%s", base_mod, rc_sub_buf) + + # 防循环:若 base_mod 已以 "."+rc_sub_buf 结尾(如 ast.base 再拼 + # .base → ast.base.base),说明子模块递归在重复追加同一模块段 + # (模块间循环 re-export / 后缀匹配容错命中自身),跳过该次递归 + # (NewAstTest CONST_INT 查找 dump:ast.base.base.base 无限增长根因)。 + rc_blen: t.CSizeT = string.strlen(base_mod) + if rc_blen > rc_sub_len + 1: + rc_tail: str = base_mod + (rc_blen - rc_sub_len) + if rc_tail[0] == '.' and \ + string.strncmp(rc_tail + 1, rc_sub_buf, rc_sub_len) == 0: + continue + + # 构建临时 from_imports "name:full_mod" + rc_fi_len: t.CSizeT = name_len_rc + 1 + string.strlen(rc_full_mod) + 1 + rc_fi: str = pool.alloc(rc_fi_len) + if rc_fi is None: + continue + viperlib.snprintf(rc_fi, rc_fi_len, "%s:%s", name, rc_full_mod) + + # 递归调用查找子模块 + rc_sub_val: int = self._lookup_cross_module_cdefine(pool, name, rc_fi, None, depth + 1, node) + if self.Gen.TypeGenCDef.is_cdefine_found() != 0: + result_val = rc_sub_val + result_found = 1 + + stdlib.free(pyi_buf) + + # 9.6 from_imports star fallback 模块中未找到:回退到 imported_modules 遍历 + # 当 `from stdint import *` 导致 star fallback 返回 stdint,但目标常量 + # (如 SHARE_READ)实际在 `import w32.fileio` 导入的模块中时, + # 需要遍历 imported_modules 逐个查找 + if result_found == 0 and imported_modules is not None: + im2_len: t.CSizeT = string.strlen(imported_modules) + im2_ci: t.CSizeT = 0 + while im2_ci < im2_len and result_found == 0: + while im2_ci < im2_len and imported_modules[im2_ci] == ' ': + im2_ci += 1 + if im2_ci >= im2_len: + break + im2_start: t.CSizeT = im2_ci + while im2_ci < im2_len and imported_modules[im2_ci] != ' ': + im2_ci += 1 + im2_end: t.CSizeT = im2_ci + im2_nlen: t.CSizeT = im2_end - im2_start + if im2_nlen > 0 and im2_nlen < 256: + im2_buf: str = pool.alloc(im2_nlen + 1) + if im2_buf is not None: + mk3: t.CSizeT = 0 + while mk3 < im2_nlen: + im2_buf[mk3] = imported_modules[im2_start + mk3] + mk3 += 1 + im2_buf[im2_nlen] = '\0' + sub_fi2: str = pool.alloc(im2_nlen + 3) + if sub_fi2 is not None: + sub_fi2[0] = '*' + sub_fi2[1] = ':' + mk4: t.CSizeT = 0 + while mk4 < im2_nlen: + sub_fi2[2 + mk4] = im2_buf[mk4] + mk4 += 1 + sub_fi2[2 + im2_nlen] = '\0' + sub_val2: t.CInt64T = self._lookup_cross_module_cdefine(pool, name, sub_fi2, None, depth + 1, node) + if self.Gen.TypeGenCDef.is_cdefine_found() != 0: + result_val = sub_val2 + result_found = 1 + + # 10. 缓存到当前模块的 CDefine 表中,并写入跨模块 perm_pool 缓存 + # 浮点 CDefine 已在匹配循环中 register_cdefine_double 缓存 + # (res_is_double=1),此处只缓存整数 CDefine,避免覆盖 double。 + if result_found != 0: + if res_is_str != 0: + # 字符串 CDefine:值已在匹配循环 register_cdefine_string(val_buf + # 是命中行的字符串内容,pool 分配跨函数有效),此处只写跨模块缓存 + if base_mod is not None: + ck_len_s: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2 + ckey_s: str = pool.alloc(ck_len_s) + if ckey_s is not None: + viperlib.snprintf(ckey_s, ck_len_s, "%s@%s", name, base_mod) + self.Gen.TypeGenCDef.register_xmod_cdefine(ckey_s, val_buf, 0, 1) + elif res_is_double == 0: + self.Gen.TypeGenCDef.register_cdefine_constant(pool, name, result_val) + # 跨模块查找缓存(perm_pool 永久,跨文件复用):整数 + # key 与入口查询一致:"name@源模块"(用截断后的 base_mod, + # 与 mod_name_raw 一致——两者都是去点后的模块名,保证 key 匹配) + if base_mod is not None: + ck_len: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2 + ckey_buf: str = pool.alloc(ck_len) + if ckey_buf is not None: + viperlib.snprintf(ckey_buf, ck_len, "%s@%s", name, base_mod) + cbuf_i: str = pool.alloc(32) + if cbuf_i is not None: + viperlib.snprintf(cbuf_i, 32, "%lld", result_val) + self.Gen.TypeGenCDef.register_xmod_cdefine(ckey_buf, cbuf_i, 0, 0) + else: + # 浮点:从本地表取回 %.17g 文本,写入跨模块缓存(保精度) + if base_mod is not None: + ck_len2: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2 + ckey2: str = pool.alloc(ck_len2) + if ckey2 is not None: + viperlib.snprintf(ckey2, ck_len2, "%s@%s", name, base_mod) + dval_cc: double = self.Gen.TypeGenCDef.lookup_cdefine_double(name) + if self.Gen.TypeGenCDef.is_cdefine_double() != 0: + cbuf_d: str = pool.alloc(64) + if cbuf_d is not None: + stdio.snprintf(cbuf_d, 64, "%.17g", dval_cc) + self.Gen.TypeGenCDef.register_xmod_cdefine(ckey2, cbuf_d, 1, 0) + self.Gen.TypeGenCDef.set_cdefine_found(1) + else: + self.Gen.TypeGenCDef.set_cdefine_found(0) + + return result_val + # ============================================================ + # _is_cdefine_name_pattern - 检查名字是否符合 CDefine 命名约定 + # + # CDefine 常量(如 FOREGROUND_GREEN, STD_OUTPUT_HANDLE, SCOPE_MODULE) + # 都遵循 ALL_CAPS 约定:仅含大写字母 A-Z、数字 0-9、下划线 _, + # 且至少含一个大写字母。 + # + # Python 关键字(match, if, for)和变量名(self, pool, builder) + # 都含小写字母,不会匹配,从而避免 fail-fast 误报。 + # + # 返回: 1=符合 CDefine 命名约定, 0=不符合 + # ============================================================ + def _is_cdefine_name_pattern(self, name: str) -> int: + """检查名字是否符合 CDefine 命名约定(全大写+下划线+数字)""" + if name is None: + return 0 + has_upper: int = 0 + i: t.CSizeT = 0 + while name[i] != '\0': + c: t.CChar = name[i] + if c >= 'a' and c <= 'z': + return 0 + if c >= 'A' and c <= 'Z': + has_upper = 1 + i += 1 + return has_upper + # ============================================================ + # 翻译变量引用(Name 节点)→ load + # ============================================================ + def _const_int_for_cdefine(self, pool: memhub.MemBuddy | t.CPtr, + value: t.CInt64T) -> llvmlite.Value | t.CPtr: + """CDefine 整数常量 → LLVM 常量(对齐 TPC TypeConvert 的 64 位升级) + + 规则(与 translate_constant 的 i32 溢出升级一致,但保留 0xFFFFFFFF 语义): + 值超 32 位无符号范围(> 0xFFFFFFFF)→ i64 全精度常量 + (如 sys.maxsize = 9223372036854775807); + 否则 → i32 常量,内部 t.CInt 截断(0xFFFFFFFF → -1,保持既有 + INVALID_HANDLE_VALUE / WAIT_FAILED = -1 语义不变,避免 i32 4294967295 + 生成非法 LLVM IR 文本 "i32 4294967295")。 + + 注意:不能用 `value > 4294967295` 直接比较——TPV 编译自身源码时大数字面量 + (> 0x7FFFFFFF)在字面量层回绕成 i32(sext 后等于 -1),阈值恒成立导致所有 + 正数 CDefine 都被升 i64(INVALID_FILE_ATTRIBUTES 0xFFFFFFFF 从 i32 -1 变 + i64 4294967295 → 与 _get_attrs 的 sext(-1) 比较失败,SysLibTest exists FAIL 根因)。 + 改用截断回比较:t.CUInt32T(value) 回绕后还原,与 value 不等即超 u32 范围。 + """ + if value >= 0 and t.CUInt64T(t.CUInt32T(value)) != value: + return llvmlite.const_int64(pool, value) return llvmlite.const_int32(pool, t.CInt(value)) \ No newline at end of file diff --git a/App/lib/core/Gen/ExprGenCls.vp b/App/lib/core/Gen/ExprGenCls.vp index da8c255..7758285 100644 --- a/App/lib/core/Gen/ExprGenCls.vp +++ b/App/lib/core/Gen/ExprGenCls.vp @@ -1,503 +1,493 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import viperlib -import w32.fileio as fileio -import lib.core.CompilerFactory as CompilerFactory -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.VLogger as VLogger -import lib.Projectrans.Config as Config -import lib.Projectrans.Utils as Utils - - -import lib.core.Gen.ExprGenBase as ExprGenBase -import lib.core.StubMergerStore as StubMergerStore -import lib.core.Handles.ExprCallBase as ExprCallBase - -# ============================================================ -# docstring 登记表容量常量(与 ExprGenMixin 保持一致,本地副本避免 -# 跨模块 CDefine 查找 bug:ExprGenCls(C) 在 ExprGenMixin(M) 之前按 -# 文件序编译时,跨模块 CDefine 全局表未注册 → NameError 未定义) -# ============================================================ -DOC_MAX: t.CDefine = 512 -DOC_KEY_SZ: t.CDefine = 192 -DOC_VAL_SZ: t.CDefine = 4096 - - -# ============================================================ -# ExprGenCls - ExprGenMixin 拆分(阶段 D):类名推断/docstring 登记 -# -# 继承 ExprGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class ExprGenCls(ExprGenBase.ExprGenBase): - """类名推断/docstring 登记""" - - # ============================================================ - # docstring 提取/登记/查找(__doc__ 魔法属性支持) - # - # 预注册阶段(BuildPipeline.TranslateFileGetTrans)扫描所有 - # App/includes 文件的 AST,提取函数/类/方法的 docstring 内容 - # 登记到全局表(key = "{module_sha1}.{symbol}");__doc__ 属性 - # 访问时查表,命中则当前模块内联生成字符串常量(无跨模块 IR - # 符号依赖),未命中返回 null。幂等查重,多遍翻译安全。 - # ============================================================ - - def _extract_docstring_from_body(self, body: list[ast.AST | t.CPtr] | t.CPtr) -> str: - """从函数/类体提取 docstring:body[0] 为 Expr(Constant str) 时返回内容""" - if body is None or len(body) == 0: - return None - first: ast.AST | t.CPtr = body.get(0) - if first is None or first.kind() != ast.ASTKind.Expr: - return None - ex: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(first) - if ex is None or ex.value is None or ex.value.kind() != ast.ASTKind.Constant: - return None - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(ex.value) - if cn is None or cn.const_kind != ast.CONST_STR: - return None - return cn.str_val - def register_docstring(self, module_sha1: str, symbol: str, doc: str) -> None: - """登记 docstring(key="{module_sha1}.{symbol}"),查重幂等""" - if module_sha1 is None or symbol is None or doc is None: - return - if string.strlen(doc) == 0: - return - if self.DocKeys is None: - self.DocKeys = CompilerFactory.get_perm_pool().alloc(DOC_MAX * DOC_KEY_SZ) - self.DocValues = CompilerFactory.get_perm_pool().alloc(DOC_MAX * DOC_VAL_SZ) - if self.DocKeys is None or self.DocValues is None: - return - string.memset(self.DocKeys, 0, DOC_MAX * DOC_KEY_SZ) - string.memset(self.DocValues, 0, DOC_MAX * DOC_VAL_SZ) - if self.DocCount >= DOC_MAX: - return - ml: t.CSizeT = string.strlen(module_sha1) - sl: t.CSizeT = string.strlen(symbol) - key_buf: bytes = stdlib.malloc(ml + sl + 2) - if key_buf is None: - return - viperlib.snprintf(key_buf, ml + sl + 2, "%s.%s", module_sha1, symbol) - i: int - for i in range(self.DocCount): - if string.strcmp(self.DocKeys + i * DOC_KEY_SZ, key_buf) == 0: - stdlib.free(key_buf) - return - string.strcpy(self.DocKeys + self.DocCount * DOC_KEY_SZ, key_buf) - string.strcpy(self.DocValues + self.DocCount * DOC_VAL_SZ, doc) - self.DocCount += 1 - stdlib.free(key_buf) - def lookup_docstring(self, module_sha1: str, symbol: str) -> str: - """查找 docstring 内容(key="{module_sha1}.{symbol}"),未找到返回 None""" - if self.DocKeys is None or module_sha1 is None or symbol is None: - return None - ml: t.CSizeT = string.strlen(module_sha1) - sl: t.CSizeT = string.strlen(symbol) - key_buf: bytes = stdlib.malloc(ml + sl + 2) - if key_buf is None: - return None - viperlib.snprintf(key_buf, ml + sl + 2, "%s.%s", module_sha1, symbol) - i: int - for i in range(self.DocCount): - if string.strcmp(self.DocKeys + i * DOC_KEY_SZ, key_buf) == 0: - stdlib.free(key_buf) - return self.DocValues + i * DOC_VAL_SZ - stdlib.free(key_buf) - return None - def extract_module_docstrings(self, tree: ast.AST | t.CPtr, module_sha1: str) -> None: - """扫描模块 AST:登记模块级函数/类/方法的 docstring(幂等)""" - if tree is None or module_sha1 is None: - return - ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children - if ch is None: - return - cn: t.CSizeT = len(ch) - for ci in range(cn): - child: ast.AST | t.CPtr = ch.get(ci) - if child is None: - continue - kd: int = child.kind() - if kd == ast.ASTKind.FunctionDef: - fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child) - if fd is not None and fd.name is not None: - fd_body: list[ast.AST | t.CPtr] | t.CPtr = fd.children - fdoc: str = self._extract_docstring_from_body(fd_body) - if fdoc is not None: - self.register_docstring(module_sha1, fd.name, fdoc) - elif kd == ast.ASTKind.ClassDef: - cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child) - if cd is None or cd.name is None: - continue - cd_body0: list[ast.AST | t.CPtr] | t.CPtr = cd.children - cdoc: str = self._extract_docstring_from_body(cd_body0) - if cdoc is not None: - self.register_docstring(module_sha1, cd.name, cdoc) - # 类方法 docstring(key="{ClassName}.{method}") - cd_body: list[ast.AST | t.CPtr] | t.CPtr = cd.children - if cd_body is not None: - cbn: t.CSizeT = len(cd_body) - for mi in range(cbn): - m: ast.AST | t.CPtr = cd_body.get(mi) - if m is None or m.kind() != ast.ASTKind.FunctionDef: - continue - mfd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(m) - if mfd is None or mfd.name is None: - continue - mdoc: str = self._extract_docstring_from_body(mfd.children) - if mdoc is not None: - cl_nl: t.CSizeT = string.strlen(cd.name) - mt_nl: t.CSizeT = string.strlen(mfd.name) - sym_buf: bytes = stdlib.malloc(cl_nl + mt_nl + 2) - if sym_buf is not None: - viperlib.snprintf(sym_buf, cl_nl + mt_nl + 2, "%s.%s", cd.name, mfd.name) - self.register_docstring(module_sha1, sym_buf, mdoc) - stdlib.free(sym_buf) - def _resolve_doc_symbol_name(self, trans: HT.Translator | t.CPtr, name_id: str, - out_mod: str | t.CPtr, out_sym: str | t.CPtr) -> int: - """解析 Name 符号的 docstring 归属,写入 out_mod/out_sym,成功返回 1 - - 判定顺序:本地变量(函数变量)→ 结构体类(含跨模块预注册)→ 模块名。 - """ - if trans is None or name_id is None or out_mod is None or out_sym is None: - return 0 - if trans.ModuleSha1 is None: - return 0 - # 1. 本地变量(函数变量/全局变量) - if HandlesVar.lookup_var(trans.SymTab, name_id) is not None: - string.strcpy(out_mod, trans.ModuleSha1) - string.strcpy(out_sym, name_id) - return 1 - # 2. 结构体类(entry.ModuleSha1 区分跨模块预注册的类) - se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(name_id) - if se is not None: - if se.ModuleSha1 is not None: - string.strcpy(out_mod, se.ModuleSha1) - else: - string.strcpy(out_mod, trans.ModuleSha1) - string.strcpy(out_sym, name_id) - return 1 - # 3. 模块名(模块本身,少见);用 StubMerger 模块级函数(避免 - # 跨 Mixin self 调用生成不存在符号) - mod_sha1: str = StubMergerStore.LookupSha1ByModName(name_id) - if mod_sha1 is None: - mod_sha1 = StubMergerStore.LookupSha1ByModNameSuffix(name_id) - if mod_sha1 is not None: - string.strcpy(out_mod, mod_sha1) - string.strcpy(out_sym, name_id) - return 1 - # 4. 兜底当前模块 - string.strcpy(out_mod, trans.ModuleSha1) - string.strcpy(out_sym, name_id) - return 1 - def _resolve_doc_symbol_attr(self, trans: HT.Translator | t.CPtr, - at: ast.Attribute | t.CPtr, - out_mod: str | t.CPtr, out_sym: str | t.CPtr) -> int: - """解析嵌套 Attribute 链的 docstring 归属,写入 out_mod/out_sym - - 支持形态:remote.remote_func / remote.RemoteClass / - remote.RemoteClass.remote_method / LocalClass.local_method 等。 - 最左 Name 判定:模块名 → 该模块 sha1;变量/类 → 类所属模块 sha1。 - """ - if trans is None or at is None or out_mod is None or out_sym is None: - return 0 - if trans.ModuleSha1 is None: - return 0 - # 收集 Attribute 链(最外层 attr 在前) - DOC_CHAIN_MAX: t.CInt = 8 - items: bytes = stdlib.malloc(DOC_CHAIN_MAX * 128) - if items is None: - return 0 - n_items: int = 0 - cur: ast.AST | t.CPtr = (ast.AST | t.CPtr)(at) - while cur is not None and cur.kind() == ast.ASTKind.Attribute and n_items < DOC_CHAIN_MAX: - cat: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cur) - if cat.attr is None: - break - string.strcpy(items + n_items * 128, cat.attr) - n_items += 1 - cur = cat.value - # 最左应为 Name - head_id: str = None - if cur is not None and cur.kind() == ast.ASTKind.Name: - hnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cur) - head_id = hnm.id - if head_id is None: - stdlib.free(items) - return 0 - # head 判定:模块名 or 变量/类 - is_mod: int = 0 - mod_sha1: str = None - if HandlesVar.lookup_var(trans.SymTab, head_id) is None: - mod_sha1 = StubMergerStore.LookupSha1ByModName(head_id) - if mod_sha1 is None: - mod_sha1 = StubMergerStore.LookupSha1ByModNameSuffix(head_id) - if mod_sha1 is not None: - is_mod = 1 - if is_mod != 0: - # 模块限定:symbol = items 反转(不含 head_id) - if n_items == 0: - string.strcpy(out_mod, mod_sha1) - string.strcpy(out_sym, head_id) - stdlib.free(items) - return 1 - total: t.CSizeT = 0 - j: int - for j in range(n_items): - total += string.strlen(items + j * 128) + 1 - sym_buf: bytes = stdlib.malloc(total + 1) - if sym_buf is None: - stdlib.free(items) - return 0 - sym_buf[0] = '\0' - for j in range(n_items): - if j > 0: - string.strcat(sym_buf, ".") - string.strcat(sym_buf, items + (n_items - 1 - j) * 128) - string.strcpy(out_mod, mod_sha1) - string.strcpy(out_sym, sym_buf) - stdlib.free(sym_buf) - stdlib.free(items) - return 1 - # 变量/类:symbol = head_id + '.' + items 反转 - total2: t.CSizeT = string.strlen(head_id) - for j in range(n_items): - total2 += string.strlen(items + j * 128) + 1 - sym2: bytes = stdlib.malloc(total2 + 1) - if sym2 is None: - stdlib.free(items) - return 0 - sym2[0] = '\0' - string.strcat(sym2, head_id) - for j in range(n_items): - string.strcat(sym2, ".") - string.strcat(sym2, items + (n_items - 1 - j) * 128) - se2: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(head_id) - if se2 is not None and se2.ModuleSha1 is not None: - string.strcpy(out_mod, se2.ModuleSha1) - else: - string.strcpy(out_mod, trans.ModuleSha1) - string.strcpy(out_sym, sym2) - stdlib.free(sym2) - stdlib.free(items) - return 1 - # ============================================================ - # P3 迁移方法(来自 HandlesExprOps.vp:运算符重载 + 二元运算) - # ============================================================ - - # ============================================================ - # infer_expr_class - 从表达式推断结构体类名(共享推断) - # - # 无注解赋值(HandlesAssign)与方法调用分派(CallGenMixin)共用: - # 联合类型 X|t.CPtr 简化为 Ptr(i8),不含类名,需按表达式结构推断: - # Call → 类实例化(func 为已注册结构体名);func 为 Attribute - # 时是方法调用,经 vpi 返回注解缓存解析返回类名 - # Name → 源变量的 AnnotClassName - # BinOp/UnaryOp → lhs 类名 + 存在对应 dunder 方法(返回同类对象) - # Attribute → 字段注解类名(_resolve_attr_field_class) - # 仅采用已注册结构体;无法精确推断返回 None(fail-fast 由调用方暴露)。 - # ============================================================ - def infer_expr_class(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr) -> str: - """从表达式推断结构体类名,无法推断返回 None""" - if node is None or trans is None: - return None - k: int = node.kind() - # Call: 类实例化 / 方法调用 - if k == ast.ASTKind.Call: - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) - if cl is None or cl.func is None: - return None - if cl.func.kind() == ast.ASTKind.Name: - cand: str = ((ast.Name | t.CPtr)(cl.func)).id - if cand is None: - return None - if HandlesStruct.find_struct(cand) is not None: - return cand - return None - if cl.func.kind() == ast.ASTKind.Attribute: - # 方法调用 a.cross(b):vpi 返回注解缓存精确解析返回类名 - # (方法可返回非同类对象,如 Transform.world_position → 'Vec3')。 - ca: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if ca is None or ca.attr is None or ca.value is None: - return None - obj_cls: str = self.infer_expr_class(pool, mod, ca.value, trans) - if obj_cls is None: - return None - if self._cls_has_dunder(pool, mod, obj_cls, ca.attr) == 0: - return None - cls_sha1: str = HandlesStruct.get_struct_sha1(obj_cls) - if cls_sha1 is None and trans.ModuleSha1 is not None: - cls_sha1 = trans.ModuleSha1 - ret_cls: str = None - if cls_sha1 is not None: - import lib.StubGen.VpiReader as VpiReader - temp_dir: str = None - # 跨 Mixin 不能 self 访问 Generator 的 TempDir 字段(字段按 - # 声明类隔离),经全局单例获取(同 HandlesAssign 模式) - import lib.core.Gen.Generator as Generator - g2: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( - t.CVoid(HandlesExpr._g_gen, t.CPtr)) - if g2 is not None and g2.TempDir is not None: - temp_dir = g2.TempDir - if temp_dir is not None: - VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, temp_dir) - annot_ret: str = VpiReader._lookup_vpi_ret_annot( - cls_sha1, obj_cls, ca.attr) - if annot_ret is not None: - ret_cls = self._extract_annot_class_name(pool, annot_ret) - return ret_cls - return None - # Name: 源变量注解 - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm is None or nm.id is None: - return None - ve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm.id) - if ve is None: - return None - acn_n: str = ve.AnnotClassName - if acn_n is None: - return None - # 去模块前缀:json.JsonValue → JsonValue。AnnotClassName 可能带 - # 模块限定(extract_class_name_from_annotation 的 Attribute 分支返回 - # "memhub.MemBuddy" 形式),而 find_struct/_cls_has_dunder/ - # get_struct_sha1 查找都用裸类名(struct 注册名)。泛型名 - # (list[str] 含 '[')不截断(方括号内可能有点号)。 - acn_dot_n: str = string.strrchr(acn_n, 46) - if acn_dot_n is not None and string.strchr(acn_n, 91) is None: - acn_n = acn_dot_n + 1 - return acn_n - # BinOp/UnaryOp: 运算符重载返回同类对象 - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - if bop is None or bop.left is None: - return None - dunder: str = HandlesExpr._binop_to_dunder(bop.op) - if dunder is None: - return None - lhs_cls: str = self.infer_expr_class(pool, mod, bop.left, trans) - if lhs_cls is None or self._cls_has_dunder(pool, mod, lhs_cls, dunder) == 0: - return None - return lhs_cls - if k == ast.ASTKind.UnaryOp: - uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) - if uop is None or uop.operand is None: - return None - dunder: str = HandlesExpr._unaryop_to_dunder(uop.op) - if dunder is None: - return None - opr_cls: str = self.infer_expr_class(pool, mod, uop.operand, trans) - if opr_cls is None or self._cls_has_dunder(pool, mod, opr_cls, dunder) == 0: - return None - return opr_cls - # Attribute: 字段注解类名(属性链递归,如 p = r.origin) - if k == ast.ASTKind.Attribute: - return HandlesExpr._resolve_attr_field_class(pool, trans, node) - return None - # ============================================================ - # _cls_has_dunder - 检查类(含继承链)是否存在 dunder/方法 - # - # 与 try_operator_overload 的查找一致:当前模块内定义或跨模块类有 - # SHA1(stub 中声明)即视为存在。仅在确实存在时采用推断类名, - # 避免把原生运算误标为类类型。 - # ============================================================ - def _cls_has_dunder(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, dunder: str) -> int: - """类及其 MRO 祖先链中是否存在 dunder 方法,存在返回 1""" - if class_name is None or dunder is None or mod is None: - return 0 - lookup_name: str = pool.alloc(128) - if lookup_name is None: - return 0 - viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder) - if ExprCallBase.find_func_in_module(mod, lookup_name) is not None: - return 1 - # 继承链祖先查找 - mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name) - mi: int = 1 - while mro_ptr is not None and mro_ptr[mi] != 0: - anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr)) - if anc is not None: - anc_lookup: str = pool.alloc(128) - if anc_lookup is not None: - viperlib.snprintf(anc_lookup, 128, "%s.%s", anc, dunder) - if ExprCallBase.find_func_in_module(mod, anc_lookup) is not None: - return 1 - mi += 1 - # 跨模块:类有 SHA1(stub 中声明该方法)视为存在 - if HandlesStruct.get_struct_sha1(class_name) is not None: - return 1 - return 0 - # ============================================================ - # _extract_annot_class_name - 从返回注解文本提取结构体类名 - # - # vpi 返回注解文本(如 "'Vec3' | CPtr")按 '|' 分段,每段去除 - # 空格/引号后查结构体注册表:命中即类名(内置类型 str/int/ - # CFloat64T/t.CPtr 等均不注册 struct,天然过滤)。"A | B" 联合 - # 多候选时取首个命中段。 - # ============================================================ - def _extract_annot_class_name(self, pool: memhub.MemBuddy | t.CPtr, - annot: str) -> str: - """从返回注解文本提取已注册结构体类名,无命中返回 None""" - if pool is None or annot is None: - return None - alen: t.CSizeT = string.strlen(annot) - if alen == 0: - return None - seg: str = pool.alloc(256) - if seg is None: - return None - start: t.CSizeT = 0 - i: t.CSizeT - for i in range(alen): - if annot[i] == '|': - s: t.CSizeT = start - e: t.CSizeT = i - while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'): - s += 1 - while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'): - e -= 1 - seglen: t.CSizeT = e - s - if seglen > 0 and seglen < 256: - string.strncpy(seg, annot + s, seglen) - seg[seglen] = '\0' - if HandlesStruct.find_struct(seg) is not None: - return seg - start = i + 1 - # 最后一段(无 '|' 后缀) - s: t.CSizeT = start - e: t.CSizeT = alen - while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'): - s += 1 - while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'): - e -= 1 - seglen: t.CSizeT = e - s - if seglen > 0 and seglen < 256: - string.strncpy(seg, annot + s, seglen) - seg[seglen] = '\0' - if HandlesStruct.find_struct(seg) is not None: - return seg +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.Generator as Generator +import lib.core.Gen.CallGenBase as CallGenBase +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import w32.fileio as fileio +import lib.core.CompilerFactory as CompilerFactory +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.StubMerger as StubMerger +import lib.core.VLogger as VLogger +import lib.Projectrans.Config as Config +import lib.Projectrans.Utils as Utils + + +import lib.core.Gen.ExprGenBase as ExprGenBase +import lib.core.StubMergerStore as StubMergerStore + +# ============================================================ +# docstring 登记表容量常量(与 ExprGenMixin 保持一致,本地副本避免 +# 跨模块 CDefine 查找 bug:ExprGenCls(C) 在 ExprGenMixin(M) 之前按 +# 文件序编译时,跨模块 CDefine 全局表未注册 → NameError 未定义) +# ============================================================ +DOC_MAX: t.CDefine = 512 +DOC_KEY_SZ: t.CDefine = 192 +DOC_VAL_SZ: t.CDefine = 4096 + + +# ============================================================ +# ExprGenCls - ExprGenMixin 拆分(阶段 D):类名推断/docstring 登记 +# +# 继承 ExprGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class ExprGenCls(ExprGenBase.ExprGenBase): + """类名推断/docstring 登记""" + + # ============================================================ + # docstring 提取/登记/查找(__doc__ 魔法属性支持) + # + # 预注册阶段(BuildPipeline.TranslateFileGetTrans)扫描所有 + # App/includes 文件的 AST,提取函数/类/方法的 docstring 内容 + # 登记到全局表(key = "{module_sha1}.{symbol}");__doc__ 属性 + # 访问时查表,命中则当前模块内联生成字符串常量(无跨模块 IR + # 符号依赖),未命中返回 null。幂等查重,多遍翻译安全。 + # ============================================================ + + def _extract_docstring_from_body(self, body: list[ast.AST | t.CPtr] | t.CPtr) -> str: + """从函数/类体提取 docstring:body[0] 为 Expr(Constant str) 时返回内容""" + if body is None or len(body) == 0: + return None + first: ast.AST | t.CPtr = body.get(0) + if first is None or first.kind() != ast.ASTKind.Expr: + return None + ex: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(first) + if ex is None or ex.value is None or ex.value.kind() != ast.ASTKind.Constant: + return None + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(ex.value) + if cn is None or cn.const_kind != ast.CONST_STR: + return None + return cn.str_val + def register_docstring(self, module_sha1: str, symbol: str, doc: str) -> None: + """登记 docstring(key="{module_sha1}.{symbol}"),查重幂等""" + if module_sha1 is None or symbol is None or doc is None: + return + if string.strlen(doc) == 0: + return + if self.DocKeys is None: + self.DocKeys = CompilerFactory.get_perm_pool().alloc(DOC_MAX * DOC_KEY_SZ) + self.DocValues = CompilerFactory.get_perm_pool().alloc(DOC_MAX * DOC_VAL_SZ) + if self.DocKeys is None or self.DocValues is None: + return + string.memset(self.DocKeys, 0, DOC_MAX * DOC_KEY_SZ) + string.memset(self.DocValues, 0, DOC_MAX * DOC_VAL_SZ) + if self.DocCount >= DOC_MAX: + return + ml: t.CSizeT = string.strlen(module_sha1) + sl: t.CSizeT = string.strlen(symbol) + key_buf: bytes = stdlib.malloc(ml + sl + 2) + if key_buf is None: + return + viperlib.snprintf(key_buf, ml + sl + 2, "%s.%s", module_sha1, symbol) + i: int + for i in range(self.DocCount): + if string.strcmp(self.DocKeys + i * DOC_KEY_SZ, key_buf) == 0: + stdlib.free(key_buf) + return + string.strcpy(self.DocKeys + self.DocCount * DOC_KEY_SZ, key_buf) + string.strcpy(self.DocValues + self.DocCount * DOC_VAL_SZ, doc) + self.DocCount += 1 + stdlib.free(key_buf) + def lookup_docstring(self, module_sha1: str, symbol: str) -> str: + """查找 docstring 内容(key="{module_sha1}.{symbol}"),未找到返回 None""" + if self.DocKeys is None or module_sha1 is None or symbol is None: + return None + ml: t.CSizeT = string.strlen(module_sha1) + sl: t.CSizeT = string.strlen(symbol) + key_buf: bytes = stdlib.malloc(ml + sl + 2) + if key_buf is None: + return None + viperlib.snprintf(key_buf, ml + sl + 2, "%s.%s", module_sha1, symbol) + i: int + for i in range(self.DocCount): + if string.strcmp(self.DocKeys + i * DOC_KEY_SZ, key_buf) == 0: + stdlib.free(key_buf) + return self.DocValues + i * DOC_VAL_SZ + stdlib.free(key_buf) + return None + def extract_module_docstrings(self, tree: ast.AST | t.CPtr, module_sha1: str) -> None: + """扫描模块 AST:登记模块级函数/类/方法的 docstring(幂等)""" + if tree is None or module_sha1 is None: + return + ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children + if ch is None: + return + cn: t.CSizeT = len(ch) + for ci in range(cn): + child: ast.AST | t.CPtr = ch.get(ci) + if child is None: + continue + kd: int = child.kind() + if kd == ast.ASTKind.FunctionDef: + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child) + if fd is not None and fd.name is not None: + fd_body: list[ast.AST | t.CPtr] | t.CPtr = fd.children + fdoc: str = self._extract_docstring_from_body(fd_body) + if fdoc is not None: + self.register_docstring(module_sha1, fd.name, fdoc) + elif kd == ast.ASTKind.ClassDef: + cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child) + if cd is None or cd.name is None: + continue + cd_body0: list[ast.AST | t.CPtr] | t.CPtr = cd.children + cdoc: str = self._extract_docstring_from_body(cd_body0) + if cdoc is not None: + self.register_docstring(module_sha1, cd.name, cdoc) + # 类方法 docstring(key="{ClassName}.{method}") + cd_body: list[ast.AST | t.CPtr] | t.CPtr = cd.children + if cd_body is not None: + cbn: t.CSizeT = len(cd_body) + for mi in range(cbn): + m: ast.AST | t.CPtr = cd_body.get(mi) + if m is None or m.kind() != ast.ASTKind.FunctionDef: + continue + mfd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(m) + if mfd is None or mfd.name is None: + continue + mdoc: str = self._extract_docstring_from_body(mfd.children) + if mdoc is not None: + cl_nl: t.CSizeT = string.strlen(cd.name) + mt_nl: t.CSizeT = string.strlen(mfd.name) + sym_buf: bytes = stdlib.malloc(cl_nl + mt_nl + 2) + if sym_buf is not None: + viperlib.snprintf(sym_buf, cl_nl + mt_nl + 2, "%s.%s", cd.name, mfd.name) + self.register_docstring(module_sha1, sym_buf, mdoc) + stdlib.free(sym_buf) + def _resolve_doc_symbol_name(self, trans: HT.Translator | t.CPtr, name_id: str, + out_mod: str | t.CPtr, out_sym: str | t.CPtr) -> int: + """解析 Name 符号的 docstring 归属,写入 out_mod/out_sym,成功返回 1 + + 判定顺序:本地变量(函数变量)→ 结构体类(含跨模块预注册)→ 模块名。 + """ + if trans is None or name_id is None or out_mod is None or out_sym is None: + return 0 + if trans.ModuleSha1 is None: + return 0 + # 1. 本地变量(函数变量/全局变量) + if self.Gen.VarGen.lookup_var(trans.SymTab, name_id) is not None: + string.strcpy(out_mod, trans.ModuleSha1) + string.strcpy(out_sym, name_id) + return 1 + # 2. 结构体类(entry.ModuleSha1 区分跨模块预注册的类) + se: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(name_id) + if se is not None: + if se.ModuleSha1 is not None: + string.strcpy(out_mod, se.ModuleSha1) + else: + string.strcpy(out_mod, trans.ModuleSha1) + string.strcpy(out_sym, name_id) + return 1 + # 3. 模块名(模块本身,少见);用 StubMerger 模块级函数(避免 + # 跨 Mixin self 调用生成不存在符号) + mod_sha1: str = StubMergerStore.LookupSha1ByModName(name_id) + if mod_sha1 is None: + mod_sha1 = StubMergerStore.LookupSha1ByModNameSuffix(name_id) + if mod_sha1 is not None: + string.strcpy(out_mod, mod_sha1) + string.strcpy(out_sym, name_id) + return 1 + # 4. 兜底当前模块 + string.strcpy(out_mod, trans.ModuleSha1) + string.strcpy(out_sym, name_id) + return 1 + def _resolve_doc_symbol_attr(self, trans: HT.Translator | t.CPtr, + at: ast.Attribute | t.CPtr, + out_mod: str | t.CPtr, out_sym: str | t.CPtr) -> int: + """解析嵌套 Attribute 链的 docstring 归属,写入 out_mod/out_sym + + 支持形态:remote.remote_func / remote.RemoteClass / + remote.RemoteClass.remote_method / LocalClass.local_method 等。 + 最左 Name 判定:模块名 → 该模块 sha1;变量/类 → 类所属模块 sha1。 + """ + if trans is None or at is None or out_mod is None or out_sym is None: + return 0 + if trans.ModuleSha1 is None: + return 0 + # 收集 Attribute 链(最外层 attr 在前) + DOC_CHAIN_MAX: t.CInt = 8 + items: bytes = stdlib.malloc(DOC_CHAIN_MAX * 128) + if items is None: + return 0 + n_items: int = 0 + cur: ast.AST | t.CPtr = (ast.AST | t.CPtr)(at) + while cur is not None and cur.kind() == ast.ASTKind.Attribute and n_items < DOC_CHAIN_MAX: + cat: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cur) + if cat.attr is None: + break + string.strcpy(items + n_items * 128, cat.attr) + n_items += 1 + cur = cat.value + # 最左应为 Name + head_id: str = None + if cur is not None and cur.kind() == ast.ASTKind.Name: + hnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cur) + head_id = hnm.id + if head_id is None: + stdlib.free(items) + return 0 + # head 判定:模块名 or 变量/类 + is_mod: int = 0 + mod_sha1: str = None + if self.Gen.VarGen.lookup_var(trans.SymTab, head_id) is None: + mod_sha1 = StubMergerStore.LookupSha1ByModName(head_id) + if mod_sha1 is None: + mod_sha1 = StubMergerStore.LookupSha1ByModNameSuffix(head_id) + if mod_sha1 is not None: + is_mod = 1 + if is_mod != 0: + # 模块限定:symbol = items 反转(不含 head_id) + if n_items == 0: + string.strcpy(out_mod, mod_sha1) + string.strcpy(out_sym, head_id) + stdlib.free(items) + return 1 + total: t.CSizeT = 0 + j: int + for j in range(n_items): + total += string.strlen(items + j * 128) + 1 + sym_buf: bytes = stdlib.malloc(total + 1) + if sym_buf is None: + stdlib.free(items) + return 0 + sym_buf[0] = '\0' + for j in range(n_items): + if j > 0: + string.strcat(sym_buf, ".") + string.strcat(sym_buf, items + (n_items - 1 - j) * 128) + string.strcpy(out_mod, mod_sha1) + string.strcpy(out_sym, sym_buf) + stdlib.free(sym_buf) + stdlib.free(items) + return 1 + # 变量/类:symbol = head_id + '.' + items 反转 + total2: t.CSizeT = string.strlen(head_id) + for j in range(n_items): + total2 += string.strlen(items + j * 128) + 1 + sym2: bytes = stdlib.malloc(total2 + 1) + if sym2 is None: + stdlib.free(items) + return 0 + sym2[0] = '\0' + string.strcat(sym2, head_id) + for j in range(n_items): + string.strcat(sym2, ".") + string.strcat(sym2, items + (n_items - 1 - j) * 128) + se2: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(head_id) + if se2 is not None and se2.ModuleSha1 is not None: + string.strcpy(out_mod, se2.ModuleSha1) + else: + string.strcpy(out_mod, trans.ModuleSha1) + string.strcpy(out_sym, sym2) + stdlib.free(sym2) + stdlib.free(items) + return 1 + # ============================================================ + # P3 迁移方法(来自 HandlesExprOps.vp:运算符重载 + 二元运算) + # ============================================================ + + # ============================================================ + # infer_expr_class - 从表达式推断结构体类名(共享推断) + # + # 无注解赋值(HandlesAssign)与方法调用分派(CallGenMixin)共用: + # 联合类型 X|t.CPtr 简化为 Ptr(i8),不含类名,需按表达式结构推断: + # Call → 类实例化(func 为已注册结构体名);func 为 Attribute + # 时是方法调用,经 vpi 返回注解缓存解析返回类名 + # Name → 源变量的 AnnotClassName + # BinOp/UnaryOp → lhs 类名 + 存在对应 dunder 方法(返回同类对象) + # Attribute → 字段注解类名(_resolve_attr_field_class) + # 仅采用已注册结构体;无法精确推断返回 None(fail-fast 由调用方暴露)。 + # ============================================================ + def infer_expr_class(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr) -> str: + """从表达式推断结构体类名,无法推断返回 None""" + if node is None or trans is None: + return None + k: int = node.kind() + # Call: 类实例化 / 方法调用 + if k == ast.ASTKind.Call: + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + if cl is None or cl.func is None: + return None + if cl.func.kind() == ast.ASTKind.Name: + cand: str = ((ast.Name | t.CPtr)(cl.func)).id + if cand is None: + return None + if self.Gen.StructGen.find_struct(cand) is not None: + return cand + return None + if cl.func.kind() == ast.ASTKind.Attribute: + # 方法调用 a.cross(b):vpi 返回注解缓存精确解析返回类名 + # (方法可返回非同类对象,如 Transform.world_position → 'Vec3')。 + ca: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if ca is None or ca.attr is None or ca.value is None: + return None + obj_cls: str = self.infer_expr_class(pool, mod, ca.value, trans) + if obj_cls is None: + return None + if self._cls_has_dunder(pool, mod, obj_cls, ca.attr) == 0: + return None + cls_sha1: str = self.Gen.StructGen.get_struct_sha1(obj_cls) + if cls_sha1 is None and trans.ModuleSha1 is not None: + cls_sha1 = trans.ModuleSha1 + ret_cls: str = None + if cls_sha1 is not None: + import lib.StubGen.VpiReader as VpiReader + temp_dir: str = None + # 跨子对象访问经 self.Gen 取 CallGenBase.TempDir(双向引用) + if self.Gen.CallGenBase.TempDir is not None: + temp_dir = self.Gen.CallGenBase.TempDir + if temp_dir is not None: + VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, temp_dir) + annot_ret: str = VpiReader._lookup_vpi_ret_annot( + cls_sha1, obj_cls, ca.attr) + if annot_ret is not None: + ret_cls = self._extract_annot_class_name(pool, annot_ret) + return ret_cls + return None + # Name: 源变量注解 + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm is None or nm.id is None: + return None + ve: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, nm.id) + if ve is None: + return None + acn_n: str = ve.AnnotClassName + if acn_n is None: + return None + # 去模块前缀:json.JsonValue → JsonValue。AnnotClassName 可能带 + # 模块限定(extract_class_name_from_annotation 的 Attribute 分支返回 + # "memhub.MemBuddy" 形式),而 find_struct/_cls_has_dunder/ + # get_struct_sha1 查找都用裸类名(struct 注册名)。泛型名 + # (list[str] 含 '[')不截断(方括号内可能有点号)。 + acn_dot_n: str = string.strrchr(acn_n, 46) + if acn_dot_n is not None and string.strchr(acn_n, 91) is None: + acn_n = acn_dot_n + 1 + return acn_n + # BinOp/UnaryOp: 运算符重载返回同类对象 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if bop is None or bop.left is None: + return None + dunder: str = self.Gen.ExprGenOps._binop_to_dunder(bop.op) + if dunder is None: + return None + lhs_cls: str = self.infer_expr_class(pool, mod, bop.left, trans) + if lhs_cls is None or self._cls_has_dunder(pool, mod, lhs_cls, dunder) == 0: + return None + return lhs_cls + if k == ast.ASTKind.UnaryOp: + uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + if uop is None or uop.operand is None: + return None + dunder: str = self.Gen.ExprGenOps._unaryop_to_dunder(uop.op) + if dunder is None: + return None + opr_cls: str = self.infer_expr_class(pool, mod, uop.operand, trans) + if opr_cls is None or self._cls_has_dunder(pool, mod, opr_cls, dunder) == 0: + return None + return opr_cls + # Attribute: 字段注解类名(属性链递归,如 p = r.origin) + if k == ast.ASTKind.Attribute: + return self.Gen.ExprGenAttr._resolve_attr_field_class(pool, trans, node) + return None + # ============================================================ + # _cls_has_dunder - 检查类(含继承链)是否存在 dunder/方法 + # + # 与 try_operator_overload 的查找一致:当前模块内定义或跨模块类有 + # SHA1(stub 中声明)即视为存在。仅在确实存在时采用推断类名, + # 避免把原生运算误标为类类型。 + # ============================================================ + def _cls_has_dunder(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, dunder: str) -> int: + """类及其 MRO 祖先链中是否存在 dunder 方法,存在返回 1""" + if class_name is None or dunder is None or mod is None: + return 0 + lookup_name: str = pool.alloc(128) + if lookup_name is None: + return 0 + viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder) + if self.Gen.CallGenBase.find_func_in_module(mod, lookup_name) is not None: + return 1 + # 继承链祖先查找 + mro_ptr: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, class_name) + mi: int = 1 + while mro_ptr is not None and mro_ptr[mi] != 0: + anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr)) + if anc is not None: + anc_lookup: str = pool.alloc(128) + if anc_lookup is not None: + viperlib.snprintf(anc_lookup, 128, "%s.%s", anc, dunder) + if self.Gen.CallGenBase.find_func_in_module(mod, anc_lookup) is not None: + return 1 + mi += 1 + # 跨模块:类有 SHA1(stub 中声明该方法)视为存在 + if self.Gen.StructGen.get_struct_sha1(class_name) is not None: + return 1 + return 0 + # ============================================================ + # _extract_annot_class_name - 从返回注解文本提取结构体类名 + # + # vpi 返回注解文本(如 "'Vec3' | CPtr")按 '|' 分段,每段去除 + # 空格/引号后查结构体注册表:命中即类名(内置类型 str/int/ + # CFloat64T/t.CPtr 等均不注册 struct,天然过滤)。"A | B" 联合 + # 多候选时取首个命中段。 + # ============================================================ + def _extract_annot_class_name(self, pool: memhub.MemBuddy | t.CPtr, + annot: str) -> str: + """从返回注解文本提取已注册结构体类名,无命中返回 None""" + if pool is None or annot is None: + return None + alen: t.CSizeT = string.strlen(annot) + if alen == 0: + return None + seg: str = pool.alloc(256) + if seg is None: + return None + start: t.CSizeT = 0 + i: t.CSizeT + for i in range(alen): + if annot[i] == '|': + s: t.CSizeT = start + e: t.CSizeT = i + while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'): + s += 1 + while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'): + e -= 1 + seglen: t.CSizeT = e - s + if seglen > 0 and seglen < 256: + string.strncpy(seg, annot + s, seglen) + seg[seglen] = '\0' + if self.Gen.StructGen.find_struct(seg) is not None: + return seg + start = i + 1 + # 最后一段(无 '|' 后缀) + s: t.CSizeT = start + e: t.CSizeT = alen + while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'): + s += 1 + while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'): + e -= 1 + seglen: t.CSizeT = e - s + if seglen > 0 and seglen < 256: + string.strncpy(seg, annot + s, seglen) + seg[seglen] = '\0' + if self.Gen.StructGen.find_struct(seg) is not None: + return seg return None \ No newline at end of file diff --git a/App/lib/core/Gen/ExprGenConst.vp b/App/lib/core/Gen/ExprGenConst.vp index 0ad8066..deb78a4 100644 --- a/App/lib/core/Gen/ExprGenConst.vp +++ b/App/lib/core/Gen/ExprGenConst.vp @@ -1,399 +1,390 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import viperlib -import w32.fileio as fileio -import lib.core.CompilerFactory as CompilerFactory -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.Handles.HandlesFunctions as HandlesFunctions -import lib.core.StubMerger as StubMerger -import lib.core.VLogger as VLogger -import lib.Projectrans.Config as Config -import lib.Projectrans.Utils as Utils - - -import lib.core.Gen.ExprGenBase as ExprGenBase -import lib.core.Handles.ExprCallCtor as ExprCallCtor - -# ============================================================ -# ExprGenConst - ExprGenMixin 拆分(阶段 D):常量/全局字符串/list 字面量翻译 -# -# 继承 ExprGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class ExprGenConst(ExprGenBase.ExprGenBase): - """常量/全局字符串/list 字面量翻译""" - - # ============================================================ - # 创建全局字符串常量 - # ============================================================ - def create_global_string(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - str_val: str, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """创建全局字符串常量并返回 i8* bitcast""" - escaped: str = self.escape_llvm_string(pool, str_val) - if escaped is None: - return None - - slen: t.CSizeT = string.strlen(str_val) - count: int = slen + 1 - - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - arr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, count) - - # 使用模块级计数器(trans._label_counter)避免跨函数命名冲突 - str_idx: int = trans._label_counter - trans._label_counter += 1 - - # 字符串名加 SHA1 前缀,和函数导出规则一致,避免跨模块重名 - gv_name: str = pool.alloc(48) - if gv_name is None: - return None - if trans.ModuleSha1 is not None: - viperlib.snprintf(gv_name, 48, ".str.%s.%d", trans.ModuleSha1, str_idx) - else: - viperlib.snprintf(gv_name, 48, ".str.%d", str_idx) - - gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, gv_name, arr_ty) - if gv is None: - return None - llvmlite.module_add_global(mod, gv) - - # 去掉 private 链接,和函数一致:stub 中 declare,text 中 define - llvmlite.global_set_unnamed_addr(gv, 1) - llvmlite.global_set_constant(gv, 1) - # LLVM 22+ 不允许 external linkage 全局变量带初始值,设为 internal - gv.Linkage = "internal" - gv.Initializer = escaped - - arr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, arr_ty) - gv_ref_name: str = pool.alloc(64) - if gv_ref_name is None: - return None - viperlib.snprintf(gv_ref_name, 64, "@%s", gv.Name) - gv_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, arr_ptr_ty, gv_ref_name) - - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, gv_ref, i8_ptr_ty) - return bc - # ============================================================ - # 翻译常量表达式 - # ============================================================ - def translate_constant(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译常量(int/str/bool)""" - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) - if cn is None: - return None - ck: int = cn.const_kind - if cn.const_kind == ast.CONST_INT: - # 超出 i32 范围则用 i64(避免常量创建时被截断) - iv: t.CInt64T = cn.int_val - if iv > 2147483647 or iv < -2147483648: - return llvmlite.const_int64(pool, iv) - return llvmlite.const_int32(pool, iv) - elif cn.const_kind == ast.CONST_FLOAT: - # 浮点常量默认创建为 double(64 位),赋值时由 coerce_to_type 自动 fptrunc - double_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) - return llvmlite.ConstFloat(pool, double_ty, cn.float_val) - elif cn.const_kind == ast.CONST_CHAR: - # 单引号单字符 → i32 值(字符 ASCII 码),coerce_to_type 会 trunc 为 i8 - cv: t.CInt64T = cn.int_val - return llvmlite.const_int32(pool, cv) - elif cn.const_kind == ast.CONST_STR: - sv: str = cn.str_val - if sv is None: - return None - r: llvmlite.Value | t.CPtr = self.create_global_string(builder, pool, mod, sv, trans) - return r - elif cn.const_kind == ast.CONST_BOOL: - if cn.int_val != 0: - return llvmlite.const_int32(pool, 1) - return llvmlite.const_int32(pool, 0) - elif cn.const_kind == ast.CONST_NONE: - # None → i8* null(空指针常量),用于 `p is None` / `p is not None` 比较 - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - if i8_ty is None: - return None - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - if i8_ptr_ty is None: - return None - rv_none: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty, "null") - return rv_none - return None - # ============================================================ - # _infer_elem_type_from_value — 从 LLVM Value 推断 list 元素类型名 - # - # 用于 list 字面量 [a, b, c] 的元素类型推断 - # ============================================================ - def _infer_elem_type_from_value(self, pool: memhub.MemBuddy | t.CPtr, - value: llvmlite.Value | t.CPtr) -> str: - """从 LLVM Value 的类型推断 list 元素类型名 - - fail-fast:值类型缺失/无法映射时返回 None(调用方携带节点报错终止), - 绝不静默回退 "str"(掩盖上游 Value 类型缺失根因)。 - """ - if value is None or value.Ty is None: - return None - ty: llvmlite.LLVMType | t.CPtr = value.Ty - bits: int = self.get_llvm_type_bits(ty) - if bits != 0: - if bits == 32: - return "int" - if bits == 64: - return "CSizeT" - if bits == 8: - return "CInt8T" - if bits == 16: - return "CInt16T" - return None - if self.is_ptr_type(ty) != 0: - return "str" - fbits: int = self.get_llvm_float_bits(ty) - if fbits != 0: - if fbits == 64: - return "CDouble" - if fbits == 32: - return "CFloat" - return None - # ============================================================ - # _find_pool_var — 查找上下文中的 pool 变量 - # - # 依次尝试 "pool", "_mbuddy", "mbuddy", "mb" - # ============================================================ - def _find_pool_var(self, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """查找上下文中的 pool 变量,返回 alloca 或 None - - 查找顺序: pool → _mbuddy → mbuddy → mb - 兜底: 若都未找到,注册外部全局 @_mbuddy (i8*) 供函数内动态 list 创建使用。 - 注意: 模块级 t.CArray 初始化不走此路径(由 _init_global_array_from_list 处理), - 此兜底仅用于函数内的动态 list 字面量(如 op=[...])。 - @_mbuddy 由入口模块(如 Phase2.py)定义并初始化,其他模块以 external 引用。 - """ - if trans is None: - return None - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, "pool") - if alloca is not None: - return alloca - alloca = HandlesVar.lookup_var(trans.SymTab, "_mbuddy") - if alloca is not None: - return alloca - alloca = HandlesVar.lookup_var(trans.SymTab, "mbuddy") - if alloca is not None: - return alloca - alloca = HandlesVar.lookup_var(trans.SymTab, "mb") - if alloca is not None: - return alloca - # 兜底: 创建当前模块 mangled 的 @_mbuddy 定义(linkonce_odr + zeroinitializer) - # 对齐模块级全局带 SHA1 前缀命名:裸名 @_mbuddy 依赖链接合并共享 - # (--allow-multiple-definition),带前缀后每模块独立。linkonce_odr 允许 - # 链接器合并同模板重复特化定义,zeroinitializer 保证编译链接通过。 - # 运行时若该模块未在入口 main 赋值 _mbuddy(null pool 上动态建 list), - # 由真实崩溃暴露(fail-fast 哲学,不掩盖上游未初始化)。 - pool: memhub.MemBuddy | t.CPtr = trans.Pool - if pool is None or trans.Module is None or trans.SymTab is None: - return None - # 先检查是否已注册到模块作用域(避免重复创建全局变量) - existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(trans.SymTab, "_mbuddy") - if existing is not None: - return existing - # 创建 i8* 类型(t.CVoid | t.CPtr = i8*) - i8_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_fb) - # 当前模块 mangled 名(@<模块sha1>._mbuddy) - mb_name_fb: str = HandlesFunctions._mangle_name(trans, "_mbuddy") - # 创建 linkonce_odr 定义(可被链接器合并,自给自足保证链接通过) - gv_ext: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, mb_name_fb, i8_ptr_ty_fb) - if gv_ext is not None: - gv_ext.Linkage = "linkonce_odr" - gv_ext.Initializer = "zeroinitializer" - llvmlite.module_add_global(trans.Module, gv_ext) - # 创建 Value 引用(@<模块sha1>._mbuddy, 类型为 i8**) - i8_ptr_ptr_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty_fb) - ref_name_fb: str = pool.alloc(96) - if ref_name_fb is not None: - # mangled 名带 SHA1 前缀(数字开头),引用必须加引号(见 make_global_ref) - if HandlesClassDef._vtable_name_needs_quote(mb_name_fb) != 0: - viperlib.snprintf(ref_name_fb, 96, "@\"%s\"", mb_name_fb) - else: - viperlib.snprintf(ref_name_fb, 96, "@%s", mb_name_fb) - gv_ref_fb: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ptr_ty_fb, ref_name_fb) - # 注册到模块作用域,避免重复创建 - HandlesVar.define_module_var(trans.SymTab, "_mbuddy", gv_ref_fb) - return gv_ref_fb - # ============================================================ - # translate_list_literal — 翻译 list 字面量 [a, b, c] - # - # 将 list 字面量翻译为 list[T](pool) 构造 + append 调用序列 - # - # Args: - # builder: IRBuilder - # pool: 编译器内存池(MemBuddy) - # mod: LLVMModule - # node: ast.List 节点 - # elem_type_name: 元素类型名(如 "str", "int"),None 表示从元素推断 - # trans: Translator 对象 - # - # Returns: - # list 对象指针(Ptr(list[T] struct)),None 失败 - # ============================================================ - def translate_list_literal(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - elem_type_name: str, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """翻译 list 字面量 [a, b, c] → list[T](pool) + append 序列""" - if node is None or trans is None: - return None - - list_node: ast.List | t.CPtr = (ast.List | t.CPtr)(node) - if list_node is None: - return None - - elts: list[ast.AST | t.CPtr] | t.CPtr = list_node.elts - elts_count: t.CSizeT = 0 - if elts is not None: - elts_count = len(elts) - - # 推断元素类型 - inferred_type_name: str = elem_type_name - first_elem_val: llvmlite.Value | t.CPtr = None - if inferred_type_name is None: - if elts_count > 0: - first_elem_node: ast.AST | t.CPtr = elts.get(0) - first_elem_val = HandlesExpr.translate_value(builder, pool, mod, first_elem_node, None, 0, trans) - if first_elem_val is None or first_elem_val.Ty is None: - # fail-fast:首元素翻译失败/Value 类型缺失,立即终止编译(暴露上游根因) - HandlesType.fatal_error( - first_elem_node, "list 字面量元素类型推断失败(Value 类型缺失)", "TypeError") - inferred_type_name = self._infer_elem_type_from_value(pool, first_elem_val) - if inferred_type_name is None: - # fail-fast:首元素 Value 类型无法映射为 list 元素类型,立即终止编译 - HandlesType.fatal_error( - first_elem_node, "list 字面量元素类型推断失败(Value 类型缺失)", "TypeError") - else: - # 空 list 无元素可推断,保持默认 str(list[str]) - inferred_type_name = "str" - - # 查找 pool 变量 - pool_alloca: llvmlite.Value | t.CPtr = self._find_pool_var(trans) - if pool_alloca is None: - HandlesType.fatal_error(node, "list literal requires pool variable in context") - return None - - # load pool 变量值(i8*) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - pool_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, pool_alloca) - if pool_val is None: - return None - - # 特化 list[T] 类(elem_size=8:str 是指针,4 会导致双元素重叠损坏) - type_args: list[str] | t.CPtr = list[str](pool, 8) - type_args.append(inferred_type_name) - spec_name: str = HandlesClassDef._specialize_generic_class(trans, "list", type_args) - if spec_name is None: - HandlesType.fatal_error(node, "list literal generic specialization failed") - return None - - # 查找 struct entry - struct_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name) - if struct_entry is None: - HandlesType.fatal_error(node, "list literal specialized class not registered") - return None - struct_ty: llvmlite.LLVMType | t.CPtr = struct_entry.Ty - if struct_ty is None: - return None - - # alloca 临时 list 空间 - # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) - HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) - tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) - if tmp is None: - return None - - # 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针 - # __new__ 是可选的,仅当泛型类模板定义了 __new__ 方法时才调用 - # (与 _translate_struct_ctor/_translate_generic_ctor_call 保持一致, - # 避免为无 __new__ 的类生成过度声明) - storage_ptr: llvmlite.Value | t.CPtr = tmp - has_new_flag: int = 0 - if struct_entry is not None: - has_new_flag = struct_entry.HasNew - if has_new_flag != 0: - new_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if new_args is None: - return None - string.memset(new_args, 0, 8 * 32) - new_args[0] = t.CSizeT(pool_val) - new_ptr: llvmlite.Value | t.CPtr = ExprCallCtor._call_method_on_ptr( - pool, builder, mod, spec_name, "__new__", tmp, new_args, 1, trans) - if new_ptr is not None: - storage_ptr = new_ptr - - # 调用 __before_init__(storage_ptr) - ExprCallCtor._call_method_on_ptr( - pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans) - - # 调用 __init__(storage_ptr, pool_val, elem_size=0) - init_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if init_args is None: - return None - string.memset(init_args, 0, 8 * 32) - init_args[0] = t.CSizeT(pool_val) - elem_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) - init_args[1] = t.CSizeT(elem_size_val) - ExprCallCtor._call_method_on_ptr( - pool, builder, mod, spec_name, "__init__", storage_ptr, init_args, 2, trans) - - # 对每个元素调用 append(storage_ptr, elem_val) - if elts_count > 0: - # 第一个元素可能已经翻译过 - if first_elem_val is not None: - append_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if append_args is not None: - string.memset(append_args, 0, 8 * 32) - append_args[0] = t.CSizeT(first_elem_val) - ExprCallCtor._call_method_on_ptr( - pool, builder, mod, spec_name, "append", storage_ptr, append_args, 1, trans) - - # 翻译剩余元素 - i: t.CSizeT = 1 - while i < elts_count: - elem_node_i: ast.AST | t.CPtr = elts.get(i) - elem_val_i: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(builder, pool, mod, elem_node_i, None, 0, trans) - if elem_val_i is not None: - ap_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if ap_args is not None: - string.memset(ap_args, 0, 8 * 32) - ap_args[0] = t.CSizeT(elem_val_i) - ExprCallCtor._call_method_on_ptr( - pool, builder, mod, spec_name, "append", storage_ptr, ap_args, 1, trans) - i += 1 - +import lib.core.Gen.GenTypes as GenTypes +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import w32.fileio as fileio +import lib.core.CompilerFactory as CompilerFactory +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.StubMerger as StubMerger +import lib.core.VLogger as VLogger +import lib.Projectrans.Config as Config +import lib.Projectrans.Utils as Utils + + +import lib.core.Gen.ExprGenBase as ExprGenBase + +# ============================================================ +# ExprGenConst - ExprGenMixin 拆分(阶段 D):常量/全局字符串/list 字面量翻译 +# +# 继承 ExprGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class ExprGenConst(ExprGenBase.ExprGenBase): + """常量/全局字符串/list 字面量翻译""" + + # ============================================================ + # 创建全局字符串常量 + # ============================================================ + def create_global_string(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + str_val: str, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """创建全局字符串常量并返回 i8* bitcast""" + escaped: str = self.escape_llvm_string(pool, str_val) + if escaped is None: + return None + + slen: t.CSizeT = string.strlen(str_val) + count: int = slen + 1 + + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + arr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, count) + + # 使用模块级计数器(trans._label_counter)避免跨函数命名冲突 + str_idx: int = trans._label_counter + trans._label_counter += 1 + + # 字符串名加 SHA1 前缀,和函数导出规则一致,避免跨模块重名 + gv_name: str = pool.alloc(48) + if gv_name is None: + return None + if trans.ModuleSha1 is not None: + viperlib.snprintf(gv_name, 48, ".str.%s.%d", trans.ModuleSha1, str_idx) + else: + viperlib.snprintf(gv_name, 48, ".str.%d", str_idx) + + gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, gv_name, arr_ty) + if gv is None: + return None + llvmlite.module_add_global(mod, gv) + + # 去掉 private 链接,和函数一致:stub 中 declare,text 中 define + llvmlite.global_set_unnamed_addr(gv, 1) + llvmlite.global_set_constant(gv, 1) + # LLVM 22+ 不允许 external linkage 全局变量带初始值,设为 internal + gv.Linkage = "internal" + gv.Initializer = escaped + + arr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, arr_ty) + gv_ref_name: str = pool.alloc(64) + if gv_ref_name is None: + return None + viperlib.snprintf(gv_ref_name, 64, "@%s", gv.Name) + gv_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, arr_ptr_ty, gv_ref_name) + + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, gv_ref, i8_ptr_ty) + return bc + # ============================================================ + # 翻译常量表达式 + # ============================================================ + def translate_constant(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译常量(int/str/bool)""" + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + if cn is None: + return None + ck: int = cn.const_kind + if cn.const_kind == ast.CONST_INT: + # 超出 i32 范围则用 i64(避免常量创建时被截断) + iv: t.CInt64T = cn.int_val + if iv > 2147483647 or iv < -2147483648: + return llvmlite.const_int64(pool, iv) + return llvmlite.const_int32(pool, iv) + elif cn.const_kind == ast.CONST_FLOAT: + # 浮点常量默认创建为 double(64 位),赋值时由 coerce_to_type 自动 fptrunc + double_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) + return llvmlite.ConstFloat(pool, double_ty, cn.float_val) + elif cn.const_kind == ast.CONST_CHAR: + # 单引号单字符 → i32 值(字符 ASCII 码),coerce_to_type 会 trunc 为 i8 + cv: t.CInt64T = cn.int_val + return llvmlite.const_int32(pool, cv) + elif cn.const_kind == ast.CONST_STR: + sv: str = cn.str_val + if sv is None: + return None + r: llvmlite.Value | t.CPtr = self.create_global_string(builder, pool, mod, sv, trans) + return r + elif cn.const_kind == ast.CONST_BOOL: + if cn.int_val != 0: + return llvmlite.const_int32(pool, 1) + return llvmlite.const_int32(pool, 0) + elif cn.const_kind == ast.CONST_NONE: + # None → i8* null(空指针常量),用于 `p is None` / `p is not None` 比较 + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + if i8_ty is None: + return None + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + if i8_ptr_ty is None: + return None + rv_none: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty, "null") + return rv_none + return None + # ============================================================ + # _infer_elem_type_from_value — 从 LLVM Value 推断 list 元素类型名 + # + # 用于 list 字面量 [a, b, c] 的元素类型推断 + # ============================================================ + def _infer_elem_type_from_value(self, pool: memhub.MemBuddy | t.CPtr, + value: llvmlite.Value | t.CPtr) -> str: + """从 LLVM Value 的类型推断 list 元素类型名 + + fail-fast:值类型缺失/无法映射时返回 None(调用方携带节点报错终止), + 绝不静默回退 "str"(掩盖上游 Value 类型缺失根因)。 + """ + if value is None or value.Ty is None: + return None + ty: llvmlite.LLVMType | t.CPtr = value.Ty + bits: int = self.get_llvm_type_bits(ty) + if bits != 0: + if bits == 32: + return "int" + if bits == 64: + return "CSizeT" + if bits == 8: + return "CInt8T" + if bits == 16: + return "CInt16T" + return None + if self.is_ptr_type(ty) != 0: + return "str" + fbits: int = self.get_llvm_float_bits(ty) + if fbits != 0: + if fbits == 64: + return "CDouble" + if fbits == 32: + return "CFloat" + return None + # ============================================================ + # _find_pool_var — 查找上下文中的 pool 变量 + # + # 依次尝试 "pool", "_mbuddy", "mbuddy", "mb" + # ============================================================ + def _find_pool_var(self, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """查找上下文中的 pool 变量,返回 alloca 或 None + + 查找顺序: pool → _mbuddy → mbuddy → mb + 兜底: 若都未找到,注册外部全局 @_mbuddy (i8*) 供函数内动态 list 创建使用。 + 注意: 模块级 t.CArray 初始化不走此路径(由 _init_global_array_from_list 处理), + 此兜底仅用于函数内的动态 list 字面量(如 op=[...])。 + @_mbuddy 由入口模块(如 Phase2.py)定义并初始化,其他模块以 external 引用。 + """ + if trans is None: + return None + alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, "pool") + if alloca is not None: + return alloca + alloca = self.Gen.VarGen.lookup_var(trans.SymTab, "_mbuddy") + if alloca is not None: + return alloca + alloca = self.Gen.VarGen.lookup_var(trans.SymTab, "mbuddy") + if alloca is not None: + return alloca + alloca = self.Gen.VarGen.lookup_var(trans.SymTab, "mb") + if alloca is not None: + return alloca + # 兜底: 创建当前模块 mangled 的 @_mbuddy 定义(linkonce_odr + zeroinitializer) + # 对齐模块级全局带 SHA1 前缀命名:裸名 @_mbuddy 依赖链接合并共享 + # (--allow-multiple-definition),带前缀后每模块独立。linkonce_odr 允许 + # 链接器合并同模板重复特化定义,zeroinitializer 保证编译链接通过。 + # 运行时若该模块未在入口 main 赋值 _mbuddy(null pool 上动态建 list), + # 由真实崩溃暴露(fail-fast 哲学,不掩盖上游未初始化)。 + pool: memhub.MemBuddy | t.CPtr = trans.Pool + if pool is None or trans.Module is None or trans.SymTab is None: + return None + # 先检查是否已注册到模块作用域(避免重复创建全局变量) + existing: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_module_var(trans.SymTab, "_mbuddy") + if existing is not None: + return existing + # 创建 i8* 类型(t.CVoid | t.CPtr = i8*) + i8_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_fb) + # 当前模块 mangled 名(@<模块sha1>._mbuddy) + mb_name_fb: str = self.Gen.FuncGenBase._mangle_name(trans, "_mbuddy") + # 创建 linkonce_odr 定义(可被链接器合并,自给自足保证链接通过) + gv_ext: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, mb_name_fb, i8_ptr_ty_fb) + if gv_ext is not None: + gv_ext.Linkage = "linkonce_odr" + gv_ext.Initializer = "zeroinitializer" + llvmlite.module_add_global(trans.Module, gv_ext) + # 创建 Value 引用(@<模块sha1>._mbuddy, 类型为 i8**) + i8_ptr_ptr_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty_fb) + ref_name_fb: str = pool.alloc(96) + if ref_name_fb is not None: + # mangled 名带 SHA1 前缀(数字开头),引用必须加引号(见 make_global_ref) + if self.Gen.ClassGenVTable._vtable_name_needs_quote(mb_name_fb) != 0: + viperlib.snprintf(ref_name_fb, 96, "@\"%s\"", mb_name_fb) + else: + viperlib.snprintf(ref_name_fb, 96, "@%s", mb_name_fb) + gv_ref_fb: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ptr_ty_fb, ref_name_fb) + # 注册到模块作用域,避免重复创建 + self.Gen.VarGen.define_module_var(trans.SymTab, "_mbuddy", gv_ref_fb) + return gv_ref_fb + # ============================================================ + # translate_list_literal — 翻译 list 字面量 [a, b, c] + # + # 将 list 字面量翻译为 list[T](pool) 构造 + append 调用序列 + # + # Args: + # builder: IRBuilder + # pool: 编译器内存池(MemBuddy) + # mod: LLVMModule + # node: ast.List 节点 + # elem_type_name: 元素类型名(如 "str", "int"),None 表示从元素推断 + # trans: Translator 对象 + # + # Returns: + # list 对象指针(Ptr(list[T] struct)),None 失败 + # ============================================================ + def translate_list_literal(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + elem_type_name: str, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """翻译 list 字面量 [a, b, c] → list[T](pool) + append 序列""" + if node is None or trans is None: + return None + + list_node: ast.List | t.CPtr = (ast.List | t.CPtr)(node) + if list_node is None: + return None + + elts: list[ast.AST | t.CPtr] | t.CPtr = list_node.elts + elts_count: t.CSizeT = 0 + if elts is not None: + elts_count = len(elts) + + # 推断元素类型 + inferred_type_name: str = elem_type_name + first_elem_val: llvmlite.Value | t.CPtr = None + if inferred_type_name is None: + if elts_count > 0: + first_elem_node: ast.AST | t.CPtr = elts.get(0) + first_elem_val = self.Gen.ExprGen.translate_value(builder, pool, mod, first_elem_node, None, 0, trans) + if first_elem_val is None or first_elem_val.Ty is None: + # fail-fast:首元素翻译失败/Value 类型缺失,立即终止编译(暴露上游根因) + self.Gen.TypeGenErr.fatal_error( + first_elem_node, "list 字面量元素类型推断失败(Value 类型缺失)", "TypeError") + inferred_type_name = self._infer_elem_type_from_value(pool, first_elem_val) + if inferred_type_name is None: + # fail-fast:首元素 Value 类型无法映射为 list 元素类型,立即终止编译 + self.Gen.TypeGenErr.fatal_error( + first_elem_node, "list 字面量元素类型推断失败(Value 类型缺失)", "TypeError") + else: + # 空 list 无元素可推断,保持默认 str(list[str]) + inferred_type_name = "str" + + # 查找 pool 变量 + pool_alloca: llvmlite.Value | t.CPtr = self._find_pool_var(trans) + if pool_alloca is None: + self.Gen.TypeGenErr.fatal_error(node, "list literal requires pool variable in context") + return None + + # load pool 变量值(i8*) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + pool_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, pool_alloca) + if pool_val is None: + return None + + # 特化 list[T] 类(elem_size=8:str 是指针,4 会导致双元素重叠损坏) + type_args: list[str] | t.CPtr = list[str](pool, 8) + type_args.append(inferred_type_name) + spec_name: str = self.Gen.ClassGenGeneric._specialize_generic_class(trans, "list", type_args) + if spec_name is None: + self.Gen.TypeGenErr.fatal_error(node, "list literal generic specialization failed") + return None + + # 查找 struct entry + struct_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(spec_name) + if struct_entry is None: + self.Gen.TypeGenErr.fatal_error(node, "list literal specialized class not registered") + return None + struct_ty: llvmlite.LLVMType | t.CPtr = struct_entry.Ty + if struct_ty is None: + return None + + # alloca 临时 list 空间 + # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) + self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, struct_ty) + tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) + if tmp is None: + return None + + # 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针 + # __new__ 是可选的,仅当泛型类模板定义了 __new__ 方法时才调用 + # (与 _translate_struct_ctor/_translate_generic_ctor_call 保持一致, + # 避免为无 __new__ 的类生成过度声明) + storage_ptr: llvmlite.Value | t.CPtr = tmp + has_new_flag: int = 0 + if struct_entry is not None: + has_new_flag = struct_entry.HasNew + if has_new_flag != 0: + new_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if new_args is None: + return None + string.memset(new_args, 0, 8 * 32) + new_args[0] = t.CSizeT(pool_val) + new_ptr: llvmlite.Value | t.CPtr = self.Gen.CallGenCall._call_method_on_ptr( + pool, builder, mod, spec_name, "__new__", tmp, new_args, 1, trans) + if new_ptr is not None: + storage_ptr = new_ptr + + # 调用 __before_init__(storage_ptr) + self.Gen.CallGenCall._call_method_on_ptr( + pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans) + + # 调用 __init__(storage_ptr, pool_val, elem_size=0) + init_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if init_args is None: + return None + string.memset(init_args, 0, 8 * 32) + init_args[0] = t.CSizeT(pool_val) + elem_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + init_args[1] = t.CSizeT(elem_size_val) + self.Gen.CallGenCall._call_method_on_ptr( + pool, builder, mod, spec_name, "__init__", storage_ptr, init_args, 2, trans) + + # 对每个元素调用 append(storage_ptr, elem_val) + if elts_count > 0: + # 第一个元素可能已经翻译过 + if first_elem_val is not None: + append_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if append_args is not None: + string.memset(append_args, 0, 8 * 32) + append_args[0] = t.CSizeT(first_elem_val) + self.Gen.CallGenCall._call_method_on_ptr( + pool, builder, mod, spec_name, "append", storage_ptr, append_args, 1, trans) + + # 翻译剩余元素 + i: t.CSizeT = 1 + while i < elts_count: + elem_node_i: ast.AST | t.CPtr = elts.get(i) + elem_val_i: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(builder, pool, mod, elem_node_i, None, 0, trans) + if elem_val_i is not None: + ap_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if ap_args is not None: + string.memset(ap_args, 0, 8 * 32) + ap_args[0] = t.CSizeT(elem_val_i) + self.Gen.CallGenCall._call_method_on_ptr( + pool, builder, mod, spec_name, "append", storage_ptr, ap_args, 1, trans) + i += 1 + return storage_ptr \ No newline at end of file diff --git a/App/lib/core/Gen/ExprGenFstr.vp b/App/lib/core/Gen/ExprGenFstr.vp index 8ad9520..a006806 100644 --- a/App/lib/core/Gen/ExprGenFstr.vp +++ b/App/lib/core/Gen/ExprGenFstr.vp @@ -1,510 +1,502 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import viperlib -import w32.fileio as fileio -import lib.core.CompilerFactory as CompilerFactory -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.VLogger as VLogger -import lib.Projectrans.Config as Config -import lib.Projectrans.Utils as Utils - - -import lib.core.Gen.ExprGenBase as ExprGenBase - -# ============================================================ -# f-string 翻译常量(与 ExprGenMixin 保持一致,本地副本避免跨模块 -# CDefine 查找 bug:ExprGenFstr(F) 在 ExprGenMixin(M) 之前按文件序 -# 编译时,跨模块 CDefine 全局表未注册 → NameError 未定义) -# ============================================================ -FSTR_BUF_SIZE: t.CDefine = 1024 -FSTR_SPEC_MAX: t.CDefine = 64 -FSTR_FMT_MAX: t.CDefine = 64 - -# ============================================================ -# ExprGenFstr - ExprGenMixin 拆分(阶段 D):f-string/格式化值翻译 -# -# 继承 ExprGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class ExprGenFstr(ExprGenBase.ExprGenBase): - """f-string/格式化值翻译""" - - # ============================================================ - # translate_joined_str - f-string 翻译(对齐 TPC _HandleJoinedStrLlvm) - # - # f"..."(JoinedStr)→ 拼接字面量与格式说明符 → snprintf 生成 i8* - # 栈缓冲。之前 f-string 未翻译导致 print/赋值拿到 NULL 指针 - # ("(null)"输出 + printf("%s", 垃圾) 崩溃 0xC0000005)。 - # ============================================================ - def translate_joined_str(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """f-string → snprintf 生成 i8* 栈缓冲""" - if node is None or builder is None or trans is None: - return None - js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(node) - if js is None or js.values is None: - return None - - # 编译期格式串缓冲(pool 分配) - fmt_buf: str = pool.alloc(FSTR_BUF_SIZE) - if fmt_buf is None: - return None - fmt_buf[0] = '\0' - - # 运行时参数链表(Value.Next 链接,与 printf 调用一致) - arg_head: llvmlite.Value | t.CPtr = None - arg_tail: llvmlite.Value | t.CPtr = None - arg_count: int = 0 - - parts: list[ast.AST | t.CPtr] | t.CPtr = js.values - pn: t.CSizeT = len(parts) - for pi in range(pn): - part: ast.AST | t.CPtr = parts.get(pi) - if part is None: - continue - if part.kind() == ast.ASTKind.Constant: - pcn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part) - if pcn.const_kind == ast.CONST_STR and pcn.str_val is not None: - self._fstr_append_literal(fmt_buf, pcn.str_val) - continue - if part.kind() != ast.ASTKind.FormattedValue: - continue - fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part) - if fv.value is None: - continue - val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, fv.value, None, 0, trans) - if val is None: - # fail-fast:f-string 格式化值翻译失败必须终止编译,绝不在 - HandlesType.fatal_error( - fv.value, "f-string 格式化值翻译失败(表达式返回 None)", "TypeError") - continue - # 确定 C 格式说明符(format_spec 优先,否则按值类型推断) - c_fmt: str = None - if fv.format_spec is not None: - c_fmt = self._fstr_parse_format_spec(pool, fv.format_spec, val, fv.value) - if c_fmt is None: - c_fmt = self._fstr_infer_c_fmt(pool, val, fv.value, trans) - if c_fmt is None: - # fail-fast:f-string 格式无法推断(值类型缺失),立即终止编译 - HandlesType.fatal_error(fv.value, "f-string 格式无法推断(值类型缺失)", "TypeError") - # 追加格式说明符 - if string.strlen(fmt_buf) + string.strlen(c_fmt) < FSTR_BUF_SIZE - 1: - string.strcat(fmt_buf, c_fmt) - # 转换参数类型(i8/i16→i32、bool→i32、f32→f64) - cast_val: llvmlite.Value | t.CPtr = self._fstr_cast_value( - builder, pool, val, c_fmt, fv.value, trans) - if cast_val is None: - cast_val = val - cast_val.Next = None - if arg_head is None: - arg_head = cast_val - else: - arg_tail.Next = cast_val - arg_tail = cast_val - arg_count += 1 - - return self._fstr_finalize(builder, pool, mod, fmt_buf, arg_head, arg_tail, arg_count, trans) - def translate_formatted_value(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译裸 FormattedValue(f"{expr:spec}" 无字面量时解析器返回 FormattedValue 而非 JoinedStr)""" - if node is None or builder is None or trans is None: - return None - fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(node) - if fv is None or fv.value is None: - return None - fmt_buf: str = pool.alloc(FSTR_BUF_SIZE) - if fmt_buf is None: - return None - fmt_buf[0] = '\0' - arg_head: llvmlite.Value | t.CPtr = None - arg_tail: llvmlite.Value | t.CPtr = None - arg_count: int = 0 - val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, fv.value, None, 0, trans) - if val is None: - # fail-fast:裸 FormattedValue 翻译失败必须终止编译,绝不在 - HandlesType.fatal_error( - fv.value, "f-string 格式化值翻译失败(表达式返回 None)", "TypeError") - else: - c_fmt: str = None - if fv.format_spec is not None: - c_fmt = self._fstr_parse_format_spec(pool, fv.format_spec, val, fv.value) - if c_fmt is None: - c_fmt = self._fstr_infer_c_fmt(pool, val, fv.value, trans) - if c_fmt is None: - # fail-fast:f-string 格式无法推断(值类型缺失),立即终止编译 - HandlesType.fatal_error(fv.value, "f-string 格式无法推断(值类型缺失)", "TypeError") - if string.strlen(fmt_buf) + string.strlen(c_fmt) < FSTR_BUF_SIZE - 1: - string.strcat(fmt_buf, c_fmt) - cast_val: llvmlite.Value | t.CPtr = self._fstr_cast_value( - builder, pool, val, c_fmt, fv.value, trans) - if cast_val is None: - cast_val = val - cast_val.Next = None - arg_head = cast_val - arg_tail = cast_val - arg_count = 1 - return self._fstr_finalize(builder, pool, mod, fmt_buf, arg_head, arg_tail, arg_count, trans) - def _fstr_finalize(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - fmt_buf: str, - arg_head: llvmlite.Value | t.CPtr, - arg_tail: llvmlite.Value | t.CPtr, - arg_count: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """f-string 尾部:全局格式串 + 固定栈缓冲 + snprintf,返回 i8*""" - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - if fmt_buf is None or fmt_buf[0] == '\0': - # 空 f-string(f"")→ 空字符串常量 - return HandlesExpr.create_global_string(builder, pool, mod, "", trans) - # 格式串 → 全局字符串常量(i8*) - fmt_ptr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string( - builder, pool, mod, fmt_buf, trans) - if fmt_ptr is None: - return None - # 固定栈缓冲 [FSTR_BUF_SIZE x i8],GEP(0,0) 取 i8* - buf_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, FSTR_BUF_SIZE) - buf_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, buf_ty) - if buf_alloca is None: - return None - zero_i32: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - buf_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, buf_ty, i8_ty, buf_alloca, zero_i32) - if buf_ptr is None: - return None - # snprintf(buf, FSTR_BUF_SIZE, fmt, args...) - size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, FSTR_BUF_SIZE) - buf_ptr.Next = size_val - size_val.Next = fmt_ptr - fmt_ptr.Next = arg_head - if arg_tail is not None: - arg_tail.Next = None - llvmlite.build_call(builder, "snprintf", buf_ptr, 3 + arg_count, i32_ty, 1) - return buf_ptr - def _fstr_append_literal(self, fmt_buf: str, - lit: str) -> None: - """追加字面量到格式串(% 转义为 %%)""" - if fmt_buf is None or lit is None: - return - cur_len: t.CSizeT = string.strlen(fmt_buf) - rem: t.CSizeT = FSTR_BUF_SIZE - 1 - cur_len - if rem == 0: - return - src_len: t.CSizeT = string.strlen(lit) - si: t.CSizeT = 0 - while si < src_len and rem > 0: - ch: t.CChar = lit[si] - if ch == '%': - if rem < 2: - break - fmt_buf[cur_len] = '%' - fmt_buf[cur_len + 1] = '%' - cur_len += 2 - rem -= 2 - else: - fmt_buf[cur_len] = ch - cur_len += 1 - rem -= 1 - si += 1 - fmt_buf[cur_len] = '\0' - def _fstr_append_raw(self, fmt_buf: str, s: str) -> None: - """追加原始字符串(不做 % 转义)""" - if fmt_buf is None or s is None: - return - cur_len: t.CSizeT = string.strlen(fmt_buf) - src_len: t.CSizeT = string.strlen(s) - if cur_len + src_len < FSTR_BUF_SIZE: - string.strcpy(fmt_buf + cur_len, s) - def _fstr_parse_format_spec(self, pool: memhub.MemBuddy | t.CPtr, - spec_node: ast.AST | t.CPtr, - val: llvmlite.Value | t.CPtr, - arg_node: ast.AST | t.CPtr) -> str: - """Python format_spec → C printf 格式串(pool 分配),无法解析返回 None""" - if spec_node is None or pool is None or val is None: - return None - # 1. 提取 spec 字符串(JoinedStr 仅常量拼接) - spec: str = pool.alloc(FSTR_SPEC_MAX) - if spec is None: - return None - spec[0] = '\0' - sk: int = spec_node.kind() - if sk == ast.ASTKind.JoinedStr: - jss: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(spec_node) - if jss.values is None: - return None - vn: t.CSizeT = len(jss.values) - for vi in range(vn): - vpart: ast.AST | t.CPtr = jss.values.get(vi) - if vpart is None: - continue - if vpart.kind() != ast.ASTKind.Constant: - return None - vcn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(vpart) - if vcn.const_kind != ast.CONST_STR or vcn.str_val is None: - return None - if string.strlen(spec) + string.strlen(vcn.str_val) < FSTR_SPEC_MAX - 1: - string.strcat(spec, vcn.str_val) - elif sk == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(spec_node) - if cn.const_kind != ast.CONST_STR or cn.str_val is None: - return None - string.strncpy(spec, cn.str_val, FSTR_SPEC_MAX - 1) - else: - return None - slen: t.CSizeT = string.strlen(spec) - if slen == 0: - return None - - # 2. 逐段解析: [fill]align / sign / # / 0 / width / , / .precision / type - pos: t.CSizeT = 0 - align_char: t.CChar = 0 - if pos < slen: - ch0: t.CChar = spec[pos] - if ch0 == '<' or ch0 == '>' or ch0 == '^' or ch0 == '=': - align_char = ch0 - pos += 1 - elif pos + 1 < slen: - ch1: t.CChar = spec[pos + 1] - if ch1 == '<' or ch1 == '>' or ch1 == '^' or ch1 == '=': - align_char = ch1 - pos += 2 - c_flags: str = pool.alloc(FSTR_FMT_MAX) - c_width: str = pool.alloc(32) - c_prec: str = pool.alloc(32) - if c_flags is None or c_width is None or c_prec is None: - return None - c_flags[0] = '\0' - c_width[0] = '\0' - c_prec[0] = '\0' - # sign - if pos < slen and (spec[pos] == '+' or spec[pos] == '-' or spec[pos] == ' '): - if spec[pos] == '+': - string.strcat(c_flags, "+") - elif spec[pos] == ' ': - string.strcat(c_flags, " ") - pos += 1 - # alt '#' - if pos < slen and spec[pos] == '#': - string.strcat(c_flags, "#") - pos += 1 - # zero '0' - if pos < slen and spec[pos] == '0': - string.strcat(c_flags, "0") - pos += 1 - # 左对齐 '<'/'^' → '-'(与 0 同时存在时 C 语义 '-' 优先) - if align_char == '<' or align_char == '^': - string.strcat(c_flags, "-") - # width digits - while pos < slen and spec[pos] >= '0' and spec[pos] <= '9': - wl: t.CSizeT = string.strlen(c_width) - if wl < 30: - c_width[wl] = spec[pos] - c_width[wl + 1] = '\0' - pos += 1 - # comma ',' → C printf 不支持千分位,忽略 - if pos < slen and spec[pos] == ',': - pos += 1 - # .precision - if pos < slen and spec[pos] == '.': - string.strcat(c_prec, ".") - pos += 1 - while pos < slen and spec[pos] >= '0' and spec[pos] <= '9': - pl: t.CSizeT = string.strlen(c_prec) - if pl < 30: - c_prec[pl] = spec[pos] - c_prec[pl + 1] = '\0' - pos += 1 - if string.strlen(c_prec) == 1: - return None # 只有 '.' 无效 - # type char - fmt_type: t.CChar = 0 - if pos < slen: - fmt_type = spec[pos] - pos += 1 - if pos != slen: - return None # 多余字符无法解析 - - # 3. 长度修饰(按值类型位宽) - len_mod: str = pool.alloc(4) - if len_mod is None: - return None - len_mod[0] = '\0' - ibits: int = HandlesExpr.get_llvm_type_bits(val.Ty) - if ibits == 64: - string.strcpy(len_mod, "ll") - elif ibits == 32: - string.strcpy(len_mod, "l") - elif ibits == 16: - string.strcpy(len_mod, "h") - elif ibits == 8: - string.strcpy(len_mod, "hh") - - # 4. 组装 C 格式串 - out: str = pool.alloc(FSTR_FMT_MAX) - if out is None: - return None - out[0] = '\0' - string.strcat(out, "%") - string.strcat(out, c_flags) - string.strcat(out, c_width) - string.strcat(out, c_prec) - if fmt_type == 0: - # 无 type:按值类型推断 - fbits2: int = HandlesExpr.get_llvm_float_bits(val.Ty) - if ibits != 0: - if ibits == 8: - string.strcat(out, "c") - elif ibits == 1: - string.strcat(out, "d") - else: - string.strcat(out, len_mod) - string.strcat(out, "d") - elif fbits2 != 0: - string.strcat(out, "f") - elif HandlesExpr.is_ptr_type(val.Ty) != 0: - string.strcat(out, "s") - else: - string.strcat(out, "d") - elif fmt_type == 'c': - string.strcat(out, "c") - elif fmt_type == 'f' or fmt_type == 'F': - string.strcat(out, "f") - elif fmt_type == 'e' or fmt_type == 'E' or fmt_type == 'g' or fmt_type == 'G': - tmp_ch: str = pool.alloc(2) - if tmp_ch is None: - return None - tmp_ch[0] = fmt_type - tmp_ch[1] = '\0' - string.strcat(out, tmp_ch) - elif fmt_type == 's': - string.strcat(out, "s") - elif fmt_type == '%': - string.strcat(out, "%") - elif fmt_type == 'b': - return None # 二进制不支持 - elif fmt_type == 'd' or fmt_type == 'i': - string.strcat(out, len_mod) - string.strcat(out, "d") - elif fmt_type == 'x' or fmt_type == 'X' or fmt_type == 'o' or fmt_type == 'u': - string.strcat(out, len_mod) - tmp_ch2: str = pool.alloc(2) - if tmp_ch2 is None: - return None - tmp_ch2[0] = fmt_type - tmp_ch2[1] = '\0' - string.strcat(out, tmp_ch2) - else: - return None - return out - def _fstr_infer_c_fmt(self, pool: memhub.MemBuddy | t.CPtr, - val: llvmlite.Value | t.CPtr, - arg_node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr) -> str: - """无 format_spec 时按值类型推断 C printf 格式(对齐 TPC 无 spec 分支,带 % 前缀)""" - if val is None or pool is None: - return None - out: str = pool.alloc(16) - if out is None: - return None - out[0] = '\0' - ibits: int = HandlesExpr.get_llvm_type_bits(val.Ty) - fbits: int = HandlesExpr.get_llvm_float_bits(val.Ty) - if ibits == 1: - return "%d" # bool - if ibits == 8: - return "%c" # 字符 - if ibits != 0: - if HandlesExpr._node_type_unsigned(pool, arg_node, trans) != 0: - if ibits == 64: - string.strcpy(out, "%llu") - else: - string.strcpy(out, "%u") - else: - if ibits == 64: - string.strcpy(out, "%lld") - else: - string.strcpy(out, "%d") - return out - if fbits != 0: - return "%f" - if HandlesExpr.is_ptr_type(val.Ty) != 0: - return "%s" - # fail-fast:值类型缺失(非整数/浮点/指针),无法推断 C 格式,立即终止编译 - HandlesType.fatal_error(arg_node, "f-string 格式无法推断(值类型缺失)", "TypeError") - return None - def _fstr_cast_value(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - val: llvmlite.Value | t.CPtr, - c_fmt: str, - arg_node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """按 C 格式转换值类型(i8/i16→i32、bool→i32、f32→f64)""" - if val is None or c_fmt is None: - return None - # 找格式类型字符(最后一个字母,忽略 l/h 长度修饰) - fmt_char: t.CChar = 0 - flen: t.CSizeT = string.strlen(c_fmt) - fi: t.CSizeT = flen - while fi > 0: - fi -= 1 - ch: t.CChar = c_fmt[fi] - if ch == '%': - break - if (ch >= 'a' and ch <= 'z') or (ch >= 'A' and ch <= 'Z'): - if ch != 'l' and ch != 'h': - fmt_char = ch - break - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if fmt_char == 's': - return val - if fmt_char == 'c': - ibits: int = HandlesExpr.get_llvm_type_bits(val.Ty) - if ibits != 0 and ibits < 32: - return llvmlite.build_zext(builder, val, i32_ty) - return val - if fmt_char == 'd' or fmt_char == 'i' or fmt_char == 'x' \ - or fmt_char == 'X' or fmt_char == 'o' or fmt_char == 'u': - ibits = HandlesExpr.get_llvm_type_bits(val.Ty) - if ibits == 1: - return llvmlite.build_zext(builder, val, i32_ty) - if ibits == 8 or ibits == 16: - if HandlesExpr._node_type_unsigned(pool, arg_node, trans) != 0: - return llvmlite.build_zext(builder, val, i32_ty) - return llvmlite.build_sext(builder, val, i32_ty) - return val - if fmt_char == 'f' or fmt_char == 'e' or fmt_char == 'E' \ - or fmt_char == 'g' or fmt_char == 'G': - fbits: int = HandlesExpr.get_llvm_float_bits(val.Ty) - if fbits == 32: - return llvmlite.build_fpext(builder, val, llvmlite.Double(pool)) - return val +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import w32.fileio as fileio +import lib.core.CompilerFactory as CompilerFactory +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.StubMerger as StubMerger +import lib.core.VLogger as VLogger +import lib.Projectrans.Config as Config +import lib.Projectrans.Utils as Utils + + +import lib.core.Gen.ExprGenBase as ExprGenBase + +# ============================================================ +# f-string 翻译常量(与 ExprGenMixin 保持一致,本地副本避免跨模块 +# CDefine 查找 bug:ExprGenFstr(F) 在 ExprGenMixin(M) 之前按文件序 +# 编译时,跨模块 CDefine 全局表未注册 → NameError 未定义) +# ============================================================ +FSTR_BUF_SIZE: t.CDefine = 1024 +FSTR_SPEC_MAX: t.CDefine = 64 +FSTR_FMT_MAX: t.CDefine = 64 + +# ============================================================ +# ExprGenFstr - ExprGenMixin 拆分(阶段 D):f-string/格式化值翻译 +# +# 继承 ExprGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class ExprGenFstr(ExprGenBase.ExprGenBase): + """f-string/格式化值翻译""" + + # ============================================================ + # translate_joined_str - f-string 翻译(对齐 TPC _HandleJoinedStrLlvm) + # + # f"..."(JoinedStr)→ 拼接字面量与格式说明符 → snprintf 生成 i8* + # 栈缓冲。之前 f-string 未翻译导致 print/赋值拿到 NULL 指针 + # ("(null)"输出 + printf("%s", 垃圾) 崩溃 0xC0000005)。 + # ============================================================ + def translate_joined_str(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """f-string → snprintf 生成 i8* 栈缓冲""" + if node is None or builder is None or trans is None: + return None + js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(node) + if js is None or js.values is None: + return None + + # 编译期格式串缓冲(pool 分配) + fmt_buf: str = pool.alloc(FSTR_BUF_SIZE) + if fmt_buf is None: + return None + fmt_buf[0] = '\0' + + # 运行时参数链表(Value.Next 链接,与 printf 调用一致) + arg_head: llvmlite.Value | t.CPtr = None + arg_tail: llvmlite.Value | t.CPtr = None + arg_count: int = 0 + + parts: list[ast.AST | t.CPtr] | t.CPtr = js.values + pn: t.CSizeT = len(parts) + for pi in range(pn): + part: ast.AST | t.CPtr = parts.get(pi) + if part is None: + continue + if part.kind() == ast.ASTKind.Constant: + pcn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part) + if pcn.const_kind == ast.CONST_STR and pcn.str_val is not None: + self._fstr_append_literal(fmt_buf, pcn.str_val) + continue + if part.kind() != ast.ASTKind.FormattedValue: + continue + fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part) + if fv.value is None: + continue + val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, fv.value, None, 0, trans) + if val is None: + # fail-fast:f-string 格式化值翻译失败必须终止编译,绝不在 + self.Gen.TypeGenErr.fatal_error( + fv.value, "f-string 格式化值翻译失败(表达式返回 None)", "TypeError") + continue + # 确定 C 格式说明符(format_spec 优先,否则按值类型推断) + c_fmt: str = None + if fv.format_spec is not None: + c_fmt = self._fstr_parse_format_spec(pool, fv.format_spec, val, fv.value) + if c_fmt is None: + c_fmt = self._fstr_infer_c_fmt(pool, val, fv.value, trans) + if c_fmt is None: + # fail-fast:f-string 格式无法推断(值类型缺失),立即终止编译 + self.Gen.TypeGenErr.fatal_error(fv.value, "f-string 格式无法推断(值类型缺失)", "TypeError") + # 追加格式说明符 + if string.strlen(fmt_buf) + string.strlen(c_fmt) < FSTR_BUF_SIZE - 1: + string.strcat(fmt_buf, c_fmt) + # 转换参数类型(i8/i16→i32、bool→i32、f32→f64) + cast_val: llvmlite.Value | t.CPtr = self._fstr_cast_value( + builder, pool, val, c_fmt, fv.value, trans) + if cast_val is None: + cast_val = val + cast_val.Next = None + if arg_head is None: + arg_head = cast_val + else: + arg_tail.Next = cast_val + arg_tail = cast_val + arg_count += 1 + + return self._fstr_finalize(builder, pool, mod, fmt_buf, arg_head, arg_tail, arg_count, trans) + def translate_formatted_value(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译裸 FormattedValue(f"{expr:spec}" 无字面量时解析器返回 FormattedValue 而非 JoinedStr)""" + if node is None or builder is None or trans is None: + return None + fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(node) + if fv is None or fv.value is None: + return None + fmt_buf: str = pool.alloc(FSTR_BUF_SIZE) + if fmt_buf is None: + return None + fmt_buf[0] = '\0' + arg_head: llvmlite.Value | t.CPtr = None + arg_tail: llvmlite.Value | t.CPtr = None + arg_count: int = 0 + val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, fv.value, None, 0, trans) + if val is None: + # fail-fast:裸 FormattedValue 翻译失败必须终止编译,绝不在 + self.Gen.TypeGenErr.fatal_error( + fv.value, "f-string 格式化值翻译失败(表达式返回 None)", "TypeError") + else: + c_fmt: str = None + if fv.format_spec is not None: + c_fmt = self._fstr_parse_format_spec(pool, fv.format_spec, val, fv.value) + if c_fmt is None: + c_fmt = self._fstr_infer_c_fmt(pool, val, fv.value, trans) + if c_fmt is None: + # fail-fast:f-string 格式无法推断(值类型缺失),立即终止编译 + self.Gen.TypeGenErr.fatal_error(fv.value, "f-string 格式无法推断(值类型缺失)", "TypeError") + if string.strlen(fmt_buf) + string.strlen(c_fmt) < FSTR_BUF_SIZE - 1: + string.strcat(fmt_buf, c_fmt) + cast_val: llvmlite.Value | t.CPtr = self._fstr_cast_value( + builder, pool, val, c_fmt, fv.value, trans) + if cast_val is None: + cast_val = val + cast_val.Next = None + arg_head = cast_val + arg_tail = cast_val + arg_count = 1 + return self._fstr_finalize(builder, pool, mod, fmt_buf, arg_head, arg_tail, arg_count, trans) + def _fstr_finalize(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + fmt_buf: str, + arg_head: llvmlite.Value | t.CPtr, + arg_tail: llvmlite.Value | t.CPtr, + arg_count: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """f-string 尾部:全局格式串 + 固定栈缓冲 + snprintf,返回 i8*""" + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + if fmt_buf is None or fmt_buf[0] == '\0': + # 空 f-string(f"")→ 空字符串常量 + return self.Gen.ExprGenConst.create_global_string(builder, pool, mod, "", trans) + # 格式串 → 全局字符串常量(i8*) + fmt_ptr: llvmlite.Value | t.CPtr = self.Gen.ExprGenConst.create_global_string( + builder, pool, mod, fmt_buf, trans) + if fmt_ptr is None: + return None + # 固定栈缓冲 [FSTR_BUF_SIZE x i8],GEP(0,0) 取 i8* + buf_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, FSTR_BUF_SIZE) + buf_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, buf_ty) + if buf_alloca is None: + return None + zero_i32: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + buf_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( + builder, buf_ty, i8_ty, buf_alloca, zero_i32) + if buf_ptr is None: + return None + # snprintf(buf, FSTR_BUF_SIZE, fmt, args...) + size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, FSTR_BUF_SIZE) + buf_ptr.Next = size_val + size_val.Next = fmt_ptr + fmt_ptr.Next = arg_head + if arg_tail is not None: + arg_tail.Next = None + llvmlite.build_call(builder, "snprintf", buf_ptr, 3 + arg_count, i32_ty, 1) + return buf_ptr + def _fstr_append_literal(self, fmt_buf: str, + lit: str) -> None: + """追加字面量到格式串(% 转义为 %%)""" + if fmt_buf is None or lit is None: + return + cur_len: t.CSizeT = string.strlen(fmt_buf) + rem: t.CSizeT = FSTR_BUF_SIZE - 1 - cur_len + if rem == 0: + return + src_len: t.CSizeT = string.strlen(lit) + si: t.CSizeT = 0 + while si < src_len and rem > 0: + ch: t.CChar = lit[si] + if ch == '%': + if rem < 2: + break + fmt_buf[cur_len] = '%' + fmt_buf[cur_len + 1] = '%' + cur_len += 2 + rem -= 2 + else: + fmt_buf[cur_len] = ch + cur_len += 1 + rem -= 1 + si += 1 + fmt_buf[cur_len] = '\0' + def _fstr_append_raw(self, fmt_buf: str, s: str) -> None: + """追加原始字符串(不做 % 转义)""" + if fmt_buf is None or s is None: + return + cur_len: t.CSizeT = string.strlen(fmt_buf) + src_len: t.CSizeT = string.strlen(s) + if cur_len + src_len < FSTR_BUF_SIZE: + string.strcpy(fmt_buf + cur_len, s) + def _fstr_parse_format_spec(self, pool: memhub.MemBuddy | t.CPtr, + spec_node: ast.AST | t.CPtr, + val: llvmlite.Value | t.CPtr, + arg_node: ast.AST | t.CPtr) -> str: + """Python format_spec → C printf 格式串(pool 分配),无法解析返回 None""" + if spec_node is None or pool is None or val is None: + return None + # 1. 提取 spec 字符串(JoinedStr 仅常量拼接) + spec: str = pool.alloc(FSTR_SPEC_MAX) + if spec is None: + return None + spec[0] = '\0' + sk: int = spec_node.kind() + if sk == ast.ASTKind.JoinedStr: + jss: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(spec_node) + if jss.values is None: + return None + vn: t.CSizeT = len(jss.values) + for vi in range(vn): + vpart: ast.AST | t.CPtr = jss.values.get(vi) + if vpart is None: + continue + if vpart.kind() != ast.ASTKind.Constant: + return None + vcn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(vpart) + if vcn.const_kind != ast.CONST_STR or vcn.str_val is None: + return None + if string.strlen(spec) + string.strlen(vcn.str_val) < FSTR_SPEC_MAX - 1: + string.strcat(spec, vcn.str_val) + elif sk == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(spec_node) + if cn.const_kind != ast.CONST_STR or cn.str_val is None: + return None + string.strncpy(spec, cn.str_val, FSTR_SPEC_MAX - 1) + else: + return None + slen: t.CSizeT = string.strlen(spec) + if slen == 0: + return None + + # 2. 逐段解析: [fill]align / sign / # / 0 / width / , / .precision / type + pos: t.CSizeT = 0 + align_char: t.CChar = 0 + if pos < slen: + ch0: t.CChar = spec[pos] + if ch0 == '<' or ch0 == '>' or ch0 == '^' or ch0 == '=': + align_char = ch0 + pos += 1 + elif pos + 1 < slen: + ch1: t.CChar = spec[pos + 1] + if ch1 == '<' or ch1 == '>' or ch1 == '^' or ch1 == '=': + align_char = ch1 + pos += 2 + c_flags: str = pool.alloc(FSTR_FMT_MAX) + c_width: str = pool.alloc(32) + c_prec: str = pool.alloc(32) + if c_flags is None or c_width is None or c_prec is None: + return None + c_flags[0] = '\0' + c_width[0] = '\0' + c_prec[0] = '\0' + # sign + if pos < slen and (spec[pos] == '+' or spec[pos] == '-' or spec[pos] == ' '): + if spec[pos] == '+': + string.strcat(c_flags, "+") + elif spec[pos] == ' ': + string.strcat(c_flags, " ") + pos += 1 + # alt '#' + if pos < slen and spec[pos] == '#': + string.strcat(c_flags, "#") + pos += 1 + # zero '0' + if pos < slen and spec[pos] == '0': + string.strcat(c_flags, "0") + pos += 1 + # 左对齐 '<'/'^' → '-'(与 0 同时存在时 C 语义 '-' 优先) + if align_char == '<' or align_char == '^': + string.strcat(c_flags, "-") + # width digits + while pos < slen and spec[pos] >= '0' and spec[pos] <= '9': + wl: t.CSizeT = string.strlen(c_width) + if wl < 30: + c_width[wl] = spec[pos] + c_width[wl + 1] = '\0' + pos += 1 + # comma ',' → C printf 不支持千分位,忽略 + if pos < slen and spec[pos] == ',': + pos += 1 + # .precision + if pos < slen and spec[pos] == '.': + string.strcat(c_prec, ".") + pos += 1 + while pos < slen and spec[pos] >= '0' and spec[pos] <= '9': + pl: t.CSizeT = string.strlen(c_prec) + if pl < 30: + c_prec[pl] = spec[pos] + c_prec[pl + 1] = '\0' + pos += 1 + if string.strlen(c_prec) == 1: + return None # 只有 '.' 无效 + # type char + fmt_type: t.CChar = 0 + if pos < slen: + fmt_type = spec[pos] + pos += 1 + if pos != slen: + return None # 多余字符无法解析 + + # 3. 长度修饰(按值类型位宽) + len_mod: str = pool.alloc(4) + if len_mod is None: + return None + len_mod[0] = '\0' + ibits: int = self.Gen.ExprGenBase.get_llvm_type_bits(val.Ty) + if ibits == 64: + string.strcpy(len_mod, "ll") + elif ibits == 32: + string.strcpy(len_mod, "l") + elif ibits == 16: + string.strcpy(len_mod, "h") + elif ibits == 8: + string.strcpy(len_mod, "hh") + + # 4. 组装 C 格式串 + out: str = pool.alloc(FSTR_FMT_MAX) + if out is None: + return None + out[0] = '\0' + string.strcat(out, "%") + string.strcat(out, c_flags) + string.strcat(out, c_width) + string.strcat(out, c_prec) + if fmt_type == 0: + # 无 type:按值类型推断 + fbits2: int = self.Gen.ExprGenBase.get_llvm_float_bits(val.Ty) + if ibits != 0: + if ibits == 8: + string.strcat(out, "c") + elif ibits == 1: + string.strcat(out, "d") + else: + string.strcat(out, len_mod) + string.strcat(out, "d") + elif fbits2 != 0: + string.strcat(out, "f") + elif self.Gen.ExprGenBase.is_ptr_type(val.Ty) != 0: + string.strcat(out, "s") + else: + string.strcat(out, "d") + elif fmt_type == 'c': + string.strcat(out, "c") + elif fmt_type == 'f' or fmt_type == 'F': + string.strcat(out, "f") + elif fmt_type == 'e' or fmt_type == 'E' or fmt_type == 'g' or fmt_type == 'G': + tmp_ch: str = pool.alloc(2) + if tmp_ch is None: + return None + tmp_ch[0] = fmt_type + tmp_ch[1] = '\0' + string.strcat(out, tmp_ch) + elif fmt_type == 's': + string.strcat(out, "s") + elif fmt_type == '%': + string.strcat(out, "%") + elif fmt_type == 'b': + return None # 二进制不支持 + elif fmt_type == 'd' or fmt_type == 'i': + string.strcat(out, len_mod) + string.strcat(out, "d") + elif fmt_type == 'x' or fmt_type == 'X' or fmt_type == 'o' or fmt_type == 'u': + string.strcat(out, len_mod) + tmp_ch2: str = pool.alloc(2) + if tmp_ch2 is None: + return None + tmp_ch2[0] = fmt_type + tmp_ch2[1] = '\0' + string.strcat(out, tmp_ch2) + else: + return None + return out + def _fstr_infer_c_fmt(self, pool: memhub.MemBuddy | t.CPtr, + val: llvmlite.Value | t.CPtr, + arg_node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr) -> str: + """无 format_spec 时按值类型推断 C printf 格式(对齐 TPC 无 spec 分支,带 % 前缀)""" + if val is None or pool is None: + return None + out: str = pool.alloc(16) + if out is None: + return None + out[0] = '\0' + ibits: int = self.Gen.ExprGenBase.get_llvm_type_bits(val.Ty) + fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(val.Ty) + if ibits == 1: + return "%d" # bool + if ibits == 8: + return "%c" # 字符 + if ibits != 0: + if self.Gen.ExprGenOps._node_type_unsigned(pool, arg_node, trans) != 0: + if ibits == 64: + string.strcpy(out, "%llu") + else: + string.strcpy(out, "%u") + else: + if ibits == 64: + string.strcpy(out, "%lld") + else: + string.strcpy(out, "%d") + return out + if fbits != 0: + return "%f" + if self.Gen.ExprGenBase.is_ptr_type(val.Ty) != 0: + return "%s" + # fail-fast:值类型缺失(非整数/浮点/指针),无法推断 C 格式,立即终止编译 + self.Gen.TypeGenErr.fatal_error(arg_node, "f-string 格式无法推断(值类型缺失)", "TypeError") + return None + def _fstr_cast_value(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + val: llvmlite.Value | t.CPtr, + c_fmt: str, + arg_node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """按 C 格式转换值类型(i8/i16→i32、bool→i32、f32→f64)""" + if val is None or c_fmt is None: + return None + # 找格式类型字符(最后一个字母,忽略 l/h 长度修饰) + fmt_char: t.CChar = 0 + flen: t.CSizeT = string.strlen(c_fmt) + fi: t.CSizeT = flen + while fi > 0: + fi -= 1 + ch: t.CChar = c_fmt[fi] + if ch == '%': + break + if (ch >= 'a' and ch <= 'z') or (ch >= 'A' and ch <= 'Z'): + if ch != 'l' and ch != 'h': + fmt_char = ch + break + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if fmt_char == 's': + return val + if fmt_char == 'c': + ibits: int = self.Gen.ExprGenBase.get_llvm_type_bits(val.Ty) + if ibits != 0 and ibits < 32: + return llvmlite.build_zext(builder, val, i32_ty) + return val + if fmt_char == 'd' or fmt_char == 'i' or fmt_char == 'x' \ + or fmt_char == 'X' or fmt_char == 'o' or fmt_char == 'u': + ibits = self.Gen.ExprGenBase.get_llvm_type_bits(val.Ty) + if ibits == 1: + return llvmlite.build_zext(builder, val, i32_ty) + if ibits == 8 or ibits == 16: + if self.Gen.ExprGenOps._node_type_unsigned(pool, arg_node, trans) != 0: + return llvmlite.build_zext(builder, val, i32_ty) + return llvmlite.build_sext(builder, val, i32_ty) + return val + if fmt_char == 'f' or fmt_char == 'e' or fmt_char == 'E' \ + or fmt_char == 'g' or fmt_char == 'G': + fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(val.Ty) + if fbits == 32: + return llvmlite.build_fpext(builder, val, llvmlite.Double(pool)) + return val return val \ No newline at end of file diff --git a/App/lib/core/Gen/ExprGenMixin.vp b/App/lib/core/Gen/ExprGenMixin.vp index 1cc15ac..03cf488 100644 --- a/App/lib/core/Gen/ExprGenMixin.vp +++ b/App/lib/core/Gen/ExprGenMixin.vp @@ -1,130 +1,121 @@ -import t, c -from stdint import * -import ast -import memhub -import string -import llvmlite -import stdlib -import stdio -import viperlib -import w32.fileio as fileio -import lib.core.CompilerFactory as CompilerFactory -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.VLogger as VLogger -import lib.Projectrans.Config as Config -import lib.Projectrans.Utils as Utils -import lib.core.Gen.ExprGenBase as ExprGenBase -import lib.core.Handles.ExprCallCall as ExprCallCall - -# ============================================================ -# docstring 登记表容量(__doc__ 魔法属性支持) -# -# DOC_MAX: 登记条目上限(预注册阶段所有 App/includes 文件的 -# 函数/类/方法 docstring,幂等查重) -# DOC_KEY_SZ: key "{module_sha1}.{symbol}" 缓冲宽度 -# DOC_VAL_SZ: docstring 内容缓冲宽度 -# ============================================================ -DOC_MAX: t.CDefine = 512 -DOC_KEY_SZ: t.CDefine = 192 -DOC_VAL_SZ: t.CDefine = 4096 - -# ============================================================ -# f-string 翻译常量(对齐 TPC HandlesExprFormat) -# -# FSTR_BUF_SIZE: 运行时栈缓冲大小(snprintf 结果缓冲) -# FSTR_SPEC_MAX: 编译期 format_spec 解析缓冲宽度 -# FSTR_FMT_MAX: 编译期 C printf 格式串缓冲宽度 -# ============================================================ -FSTR_BUF_SIZE: t.CDefine = 1024 -FSTR_SPEC_MAX: t.CDefine = 64 -FSTR_FMT_MAX: t.CDefine = 64 - - -# ============================================================ -# ExprGenMixin - 表达式处理 Mixin(对象化 P3,wiki/14-oo-refactor.md) -# -# 从 HandlesExpr.vp(48 函数,无全局状态)与 HandlesExprOps.vp -# 迁移:模块级纯函数 → 类方法(self 替代,参数保留含 builder/pool)。 -# -# 迁移原则(与 P2 一致,行为零变化): -# 1. 方法保留原函数签名(含 builder/pool 首参),仅函数体内 -# 本模块函数调用改为 self.xxx(...) -# 2. 外部模块调用(HandlesExprCall.xxx / HandlesType.xxx 等)保留模块前缀 -# 3. HandlesExpr.vp / HandlesExprOps.vp 原函数保留为"委托":本地 -# 模块级单例 _g_gen(BuildPipeline/main 注入)cast 成 Generator 类型 -# 4. ExprHandle 类保留在 HandlesExpr.vp(translator handler 模式) -# -# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 -# ============================================================ - - -# ============================================================ -# ExprGenMixin - 表达式/常量/下标/属性访问/运算符 -# ============================================================ -@t.NoVTable -class ExprGenMixin(ExprGenBase.ExprGenBase): - """表达式处理 Mixin(纯方法化迁移,无状态字段)""" - - - # ============================================================ - # 翻译值表达式(RHS 分派)— 模块级版本 - # ============================================================ - def translate_value(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - funcs_ptr: t.CPtr = None, - func_count: int = 0, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译值表达式为 LLVM Value""" - if node is None: - return None - k: int = node.kind() - if k == ast.ASTKind.Constant: - rv: llvmlite.Value | t.CPtr = HandlesExpr.translate_constant(builder, pool, mod, node, trans) - return rv - elif k == ast.ASTKind.Name: - return HandlesExpr.translate_name_value(builder, pool, node, trans) - elif k == ast.ASTKind.BinOp: - return HandlesExpr.translate_binop(pool, builder, mod, node, trans) - elif k == ast.ASTKind.Call: - return ExprCallCall.translate_call(pool, builder, mod, node, - funcs_ptr, func_count, trans) - elif k == ast.ASTKind.Compare: - return HandlesExpr.translate_compare(builder, pool, mod, node, trans) - elif k == ast.ASTKind.UnaryOp: - return HandlesExpr.translate_unaryop(builder, pool, mod, node, trans) - elif k == ast.ASTKind.BoolOp: - return HandlesExpr.translate_boolop(builder, pool, mod, node, - funcs_ptr, func_count, trans) - elif k == ast.ASTKind.Subscript: - return HandlesExpr.translate_subscript(builder, pool, mod, node, trans) - elif k == ast.ASTKind.Attribute: - return HandlesExpr.translate_attribute(builder, pool, mod, node, trans) - elif k == ast.ASTKind.List: - return HandlesExpr.translate_list_literal(builder, pool, mod, node, None, trans) - elif k == ast.ASTKind.IfExp: - return HandlesExpr.translate_ifexp(builder, pool, mod, node, trans) - elif k == ast.ASTKind.Lambda: - # 模块级委托:translate_lambda 定义在 FuncGenMixin(跨 Mixin - # 方法不能 self. 直接调用,见 HandlesExpr.translate_lambda) - return HandlesExpr.translate_lambda(builder, pool, mod, node, trans) - elif k == ast.ASTKind.JoinedStr: - return HandlesExpr.translate_joined_str(builder, pool, mod, node, trans) - elif k == ast.ASTKind.FormattedValue: - # 解析器对 f"{expr:spec}"(单 FormattedValue 无字面量)返回裸 FormattedValue - # 而非 JoinedStr(见 ast/parser.vp _parse_fstring),需单独翻译 - return HandlesExpr.translate_formatted_value(builder, pool, mod, node, trans) - return None +import t, c +from stdint import * +import ast +import memhub +import string +import llvmlite +import stdlib +import stdio +import viperlib +import w32.fileio as fileio +import lib.core.CompilerFactory as CompilerFactory +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.StubMerger as StubMerger +import lib.core.VLogger as VLogger +import lib.Projectrans.Config as Config +import lib.Projectrans.Utils as Utils +import lib.core.Gen.ExprGenBase as ExprGenBase + +# ============================================================ +# docstring 登记表容量(__doc__ 魔法属性支持) +# +# DOC_MAX: 登记条目上限(预注册阶段所有 App/includes 文件的 +# 函数/类/方法 docstring,幂等查重) +# DOC_KEY_SZ: key "{module_sha1}.{symbol}" 缓冲宽度 +# DOC_VAL_SZ: docstring 内容缓冲宽度 +# ============================================================ +DOC_MAX: t.CDefine = 512 +DOC_KEY_SZ: t.CDefine = 192 +DOC_VAL_SZ: t.CDefine = 4096 + +# ============================================================ +# f-string 翻译常量(对齐 TPC HandlesExprFormat) +# +# FSTR_BUF_SIZE: 运行时栈缓冲大小(snprintf 结果缓冲) +# FSTR_SPEC_MAX: 编译期 format_spec 解析缓冲宽度 +# FSTR_FMT_MAX: 编译期 C printf 格式串缓冲宽度 +# ============================================================ +FSTR_BUF_SIZE: t.CDefine = 1024 +FSTR_SPEC_MAX: t.CDefine = 64 +FSTR_FMT_MAX: t.CDefine = 64 + + +# ============================================================ +# ExprGenMixin - 表达式处理 Mixin(对象化 P3,wiki/14-oo-refactor.md) +# +# 从 HandlesExpr.vp(48 函数,无全局状态)与 HandlesExprOps.vp +# 迁移:模块级纯函数 → 类方法(self 替代,参数保留含 builder/pool)。 +# +# 迁移原则(与 P2 一致,行为零变化): +# 1. 方法保留原函数签名(含 builder/pool 首参),仅函数体内 +# 本模块函数调用改为 self.xxx(...) +# 2. 外部模块调用(HandlesExprCall.xxx / HandlesType.xxx 等)保留模块前缀 +# 3. HandlesExpr.vp / HandlesExprOps.vp 原函数保留为"委托":本地 +# 模块级单例 _g_gen(BuildPipeline/main 注入)cast 成 Generator 类型 +# 4. ExprHandle 类保留在 HandlesExpr.vp(translator handler 模式) +# +# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 +# ============================================================ + + +# ============================================================ +# ExprGenMixin - 表达式/常量/下标/属性访问/运算符 +# ============================================================ +@t.NoVTable +class ExprGenMixin(ExprGenBase.ExprGenBase): + """表达式处理 Mixin(纯方法化迁移,无状态字段)""" + + + # ============================================================ + # 翻译值表达式(RHS 分派)— 模块级版本 + # ============================================================ + def translate_value(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + funcs_ptr: t.CPtr = None, + func_count: int = 0, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译值表达式为 LLVM Value""" + if node is None: + return None + k: int = node.kind() + if k == ast.ASTKind.Constant: + rv: llvmlite.Value | t.CPtr = self.Gen.ExprGenConst.translate_constant(builder, pool, mod, node, trans) + return rv + elif k == ast.ASTKind.Name: + return self.Gen.ExprGenName.translate_name_value(builder, pool, node, trans) + elif k == ast.ASTKind.BinOp: + return self.Gen.ExprGenOps.translate_binop(pool, builder, mod, node, trans) + elif k == ast.ASTKind.Call: + return self.Gen.CallGen.translate_call(pool, builder, mod, node, + funcs_ptr, func_count, trans) + elif k == ast.ASTKind.Compare: + return self.Gen.ExprGenOps.translate_compare(builder, pool, mod, node, trans) + elif k == ast.ASTKind.UnaryOp: + return self.Gen.ExprGenOps.translate_unaryop(builder, pool, mod, node, trans) + elif k == ast.ASTKind.BoolOp: + return self.Gen.ExprGenOps.translate_boolop(builder, pool, mod, node, + funcs_ptr, func_count, trans) + elif k == ast.ASTKind.Subscript: + return self.Gen.ExprGenName.translate_subscript(builder, pool, mod, node, trans) + elif k == ast.ASTKind.Attribute: + return self.Gen.ExprGenAttr.translate_attribute(builder, pool, mod, node, trans) + elif k == ast.ASTKind.List: + return self.Gen.ExprGenConst.translate_list_literal(builder, pool, mod, node, None, trans) + elif k == ast.ASTKind.IfExp: + return self.Gen.ExprGenOps.translate_ifexp(builder, pool, mod, node, trans) + elif k == ast.ASTKind.Lambda: + # 模块级委托:translate_lambda 定义在 FuncGenMixin(跨 Mixin + # 方法不能 self. 直接调用,见 HandlesExpr.translate_lambda) + return self.Gen.FuncGen.translate_lambda(builder, pool, mod, node, trans) + elif k == ast.ASTKind.JoinedStr: + return self.Gen.ExprGenFstr.translate_joined_str(builder, pool, mod, node, trans) + elif k == ast.ASTKind.FormattedValue: + # 解析器对 f"{expr:spec}"(单 FormattedValue 无字面量)返回裸 FormattedValue + # 而非 JoinedStr(见 ast/parser.vp _parse_fstring),需单独翻译 + return self.Gen.ExprGenFstr.translate_formatted_value(builder, pool, mod, node, trans) + return None diff --git a/App/lib/core/Gen/ExprGenName.vp b/App/lib/core/Gen/ExprGenName.vp index c5c58c4..ae8f3e9 100644 --- a/App/lib/core/Gen/ExprGenName.vp +++ b/App/lib/core/Gen/ExprGenName.vp @@ -1,1057 +1,1047 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import viperlib -import w32.fileio as fileio -import lib.core.CompilerFactory as CompilerFactory -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.StubMergerStore as StubMergerStore -import lib.core.Handles.HandlesFunctions as HandlesFunctions -import lib.core.VLogger as VLogger -import lib.Projectrans.Config as Config -import lib.Projectrans.Utils as Utils - - -import lib.core.Gen.ExprGenBase as ExprGenBase -import lib.core.Handles.ExprCallBase as ExprCallBase -import lib.core.Handles.ExprCallCtor as ExprCallCtor - -# ============================================================ -# ExprGenName - ExprGenMixin 拆分(阶段 D):Name/Subscript/下标访问 -# -# 继承 ExprGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class ExprGenName(ExprGenBase.ExprGenBase): - """Name/Subscript/下标访问""" - - def _cut_from_import_mod(self, pool: memhub.MemBuddy | t.CPtr, - raw: str) -> str: - """截断 lookup_from_import 返回的模块名到独立缓冲 - - lookup_from_import 返回指向 from_imports 内部的指针(非 NUL 结尾, - 后随空格分隔的其他条目,如 "ast.tokens TokenType:ast.tokens ...")。 - 不截断则 LookupSha1ByModName 收到整串查不到 → mangle 退化裸名 → - 全局引用不带 SHA1 前缀 → 链接 undefined symbol(_op_head 根因, - 对齐 ExprGenCdef._lookup_cross_module_cdefine 的截断逻辑)。 - 截断到空格/冒号/NUL;raw 无效返回 None。 - """ - if raw is None: - return None - mbl_c: t.CSizeT = 0 - while raw[mbl_c] != ' ' and raw[mbl_c] != '\0' and raw[mbl_c] != ':': - mbl_c += 1 - if mbl_c == 0: - return None - buf_c: str = pool.alloc(mbl_c + 1) - if buf_c is None: - return None - string.strncpy(buf_c, raw, mbl_c) - buf_c[mbl_c] = '\0' - return buf_c - - def translate_name_value(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译变量引用(Name 节点)→ load""" - # mod 必须取自 trans.Module:函数签名无 mod 参数,若用裸名 mod 会被 - # 解析为 None → create_global_string 的 module_add_global(None, gv) 被 - # add_global 的 `if self is None: return` 静默丢弃 → 字符串 CDefine 的 - # global 定义丢失但 _label_counter/IR 引用已生成 → llc 报 - # "use of undefined value '@.str.{sha1}.N'(SysLibTest _cleanup 根因)" - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm is None: - return None - nm_id: str = nm.id - if nm_id is None: - return None - # CDefine 编译期常量: 返回常量值(浮点 CDefine → double 常量,整数 → i32) - # NAME: t.CDefine = value 形式定义的常量在编译期已注册到本地表 - # 浮点 CDefine(如 vipermath 的 U_M_PI=3.14...)必须返回浮点常量, - # 否则在 double 函数里 return 生成 ret i32 0(llc 报错)。 - cdef_val_d: double = HandlesType.lookup_cdefine_double(nm_id) - if HandlesType.is_cdefine_found() != 0: - if HandlesType.is_cdefine_str() != 0: - # 字符串 CDefine(如 ZLIB_VERSION: t.CDefine = "1.3.2"): - # 返回 global string(i8*),供 return ZLIB_VERSION 等使用。 - cdef_sv: str = HandlesType.lookup_cdefine_string(nm_id) - if cdef_sv is not None: - return HandlesExpr.create_global_string(builder, pool, mod, cdef_sv, trans) - HandlesType.fatal_error(node, f"CDefine 字符串值缺失: {nm_id}", "InternalCompilerError") - if HandlesType.is_cdefine_double() != 0: - return llvmlite.ConstFloat(pool, llvmlite.Double(pool), cdef_val_d) - # 整数 CDefine:重新查表取 64 位全精度值(double 往返会丢精度, - # 9223372036854775807 → 9.223372036854776e18 舍入错位,生成错常量) - cdef_val_c: t.CInt64T = HandlesType.lookup_cdefine_constant(nm_id) - return HandlesExpr._const_int_for_cdefine(pool, cdef_val_c) - - # 本地表未找到:尝试跨模块 .vpi 查找(保证多模块查表存表一致) - # 仅对符合 CDefine 命名约定(ALL_CAPS)的名字触发跨模块查找, - # 避免对普通变量名(mb/name/ptr/pool/self 等)误触发,造成严重性能损耗 - if HandlesExpr._is_cdefine_name_pattern(nm_id) != 0: - if trans is not None: - cdef_val: t.CInt64T = HandlesExpr._lookup_cross_module_cdefine( - pool, nm_id, trans._from_imports, trans._imported_modules, 0, node) - if HandlesType.is_cdefine_found() != 0: - if HandlesType.is_cdefine_str() != 0: - cdef_sv2: str = HandlesType.lookup_cdefine_string(nm_id) - if cdef_sv2 is not None: - return HandlesExpr.create_global_string(builder, pool, mod, cdef_sv2, trans) - HandlesType.fatal_error(node, f"CDefine 字符串值缺失: {nm_id}", "InternalCompilerError") - # 跨模块浮点 CDefine 已缓存为 double(is_cdefine_double), - # 需返回浮点常量而非截断的整数 - dchk_nm: double = HandlesType.lookup_cdefine_double(nm_id) - if HandlesType.is_cdefine_double() != 0: - return llvmlite.ConstFloat(pool, llvmlite.Double(pool), dchk_nm) - return HandlesExpr._const_int_for_cdefine(pool, cdef_val) - - # CDefine 查找失败:from-import 的模块级全局变量(如 - # from Phase1 import PYI_BUF_SIZE;PYI_BUF_SIZE: t.CSizeT = 262144 是 - # i64 全局、非宏,语义同 C 的 extern size_t PYI_BUF_SIZE)。from-import - # 确认名称确实来自某模块后,按后缀匹配查找该全局并加载。 - if trans is not None and trans._from_imports is not None: - fi_mod_raw: str = HandlesImports.lookup_from_import( - trans._from_imports, nm_id, 0) - if fi_mod_raw is not None: - # 带源模块 SHA1 前缀精确查找,避免多模块同名全局后缀匹配串扰。 - # fi_mod_raw 非 NUL 结尾,先截断再查 SHA1(否则整串查不到退化裸名) - fi_mod_cut: str = self._cut_from_import_mod(pool, fi_mod_raw) - if fi_mod_cut is None: - fi_mod_cut = fi_mod_raw - fi_gv_q: str = HandlesFunctions._mangle_name_with_sha1( - StubMergerStore.LookupSha1ByModName(fi_mod_cut), nm_id) - fi_gv: llvmlite.GlobalVariable | t.CPtr = HandlesExpr.find_global_in_module( - trans.Module, fi_gv_q) - if fi_gv is not None and fi_gv.Ty is not None: - fi_ref: llvmlite.Value | t.CPtr = HandlesExpr.make_global_ref( - pool, fi_gv.Name, fi_gv.Ty) - if fi_ref is not None and fi_ref.Ty is not None: - fi_pty: llvmlite.LLVMType | t.CPtr = fi_ref.Ty.Pointee - if fi_pty is not None: - match fi_pty: - case llvmlite.LLVMType.Array(_, _): - # 数组全局按 C 语义退化为基址(对齐 L3383-3388) - return fi_ref - case _: - pass - return llvmlite.build_load(builder, fi_pty, fi_ref) - - # global 变量:从模块作用域查找(global 声明优先级最高) - if trans is not None: - if HT.is_global_name(trans, nm_id) != 0: - mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( - trans.SymTab, nm_id) - if mod_alloca is not None: - load_ty: llvmlite.LLVMType | t.CPtr = None - if mod_alloca.Ty is not None: - load_ty = mod_alloca.Ty.Pointee - if load_ty is None: - # fail-fast:global 变量存储类型缺失,立即终止编译(暴露上游根因) - HandlesType.fatal_error( - node, f"变量 '{nm_id}' 存储类型缺失", "TypeError") - # 全局数组(如 pyzlib.pyzlib_error_msg: CArray[t.CChar, 512]): - # 按 C 语义衰减为基址返回(对齐下方局部数组分支 L3383-3388)。 - # 否则 load [512 x i8] 数组值当 i8* 传 → set_error 的 strncpy - # dest 是数组值(栈拷贝)而非数组基址 → 写入丢失 → get_error - # 为空(test_pyzlib "error message is empty" 根因)。 - match load_ty: - case llvmlite.LLVMType.Array(_, _): - return mod_alloca - case _: - pass - return llvmlite.build_load(builder, load_ty, mod_alloca) - - # nonlocal 变量:通过闭包 env 访问 - if HT.is_nonlocal_name(trans, nm_id) != 0: - return HandlesNonlocal.load_nonlocal_var(trans, nm_id) - - # *args va_list:变量名直接解析为指向 24 字节 va_list 缓冲区的 i8* 地址 - # (对齐 TPC _direct_values[vararg_name] = va_list_ptr;不 load 缓冲区内容, - # 转发时按值传该地址即可,如 sprintf → vsnprintf(..., args)) - if trans is not None and trans._vararg_name is not None: - if nm_id is not None and string.strcmp(nm_id, trans._vararg_name) == 0: - if trans._va_list_ptr is not None: - return trans._va_list_ptr - - # 局部变量查找(必须先于模块别名检查) - # 否则与模块同名的局部变量(如 `import t, c` 后的局部变量 c)会被误判为模块别名, - # 导致 SymTab 已注册的局部变量查找不到(rhs_val is None bug 根因) - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm_id) - if alloca is not None: - load_ty: llvmlite.LLVMType | t.CPtr = None - if alloca.Ty is not None: - load_ty = alloca.Ty.Pointee - if load_ty is None: - # fail-fast:局部变量存储类型缺失,立即终止编译(暴露上游根因) - HandlesType.fatal_error( - node, f"变量 '{nm_id}' 存储类型缺失", "TypeError") - # 结构体值变量(alloca 类型为 Struct,如 `x: Cls | t.CPtr`): - # 按"对象即指针"语义返回其地址(alloca 指针),而非加载结构体值。 - # 结构体值无法参与 ptrtoint/方法调用等地址相关操作,加载值会导致 - # `ptrtoint %Struct ... to i64` 无效指令(llc invalid cast opcode)。 - match load_ty: - case llvmlite.LLVMType.Struct(_, _, _): - return alloca - case llvmlite.LLVMType.Array(_, _): - # 数组变量按 C 语义退化为指针(返回数组基址),而非整体 - # load 数组值——如 printf("%s", str_arr) 应传数组首地址, - # load [N x i8] 值传给 %s 会读到错误数据崩溃 - # (ClassArrayTest TestCharArray 运行时崩溃根因)。 - return alloca - return llvmlite.build_load(builder, load_ty, alloca) - - # 模块别名检查:SymTab 查找失败后才检查 - # 如果 nm_id 是已导入模块名(如 win32file, fileio)且未被声明为局部变量, - # 返回 None 让上层处理(用于属性访问 win32file.CreateFileA) - if trans is not None and trans._imported_modules is not None: - if HandlesImports.is_module_imported(trans._imported_modules, nm_id) != 0: - return None - - # 模块级函数引用:函数名作为值传递(如 CreateThread(..., _thread_alloc_free, ...))。 - # 之前缺失此查找导致函数名参数翻译返回 None 被跳过,后续参数整体前移 - # (lpStartAddress 变成对象地址,线程从数据区执行直接崩溃)。 - # 注意:不能直接返回 Function 对象,也不能直接 build_bitcast(Function)—— - # Function 布局是 {Next, Name, RetTy, Params, ...},value_get_ty 会错位读到 - # Name 字段,TypePrint 输出 "void",生成 `bitcast void ... to i8*` 非法 IR; - # 且 Function.Next 是模块函数链表指针,参数链表构建对其赋值会截断函数链表, - # 最终打印出 `declare void @()` 空名函数。正确做法:按 Function 的 - # RetTy/Params 构造真实函数类型,用 new_value 包装成普通 Value 再 bitcast。 - if trans is not None and trans.Module is not None: - fn_ref: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module( - trans.Module, nm_id) - if fn_ref is not None: - fn_name: str = llvmlite.function_get_name(fn_ref) - if fn_name is None: - return None - # 构造函数类型:ret_ty + 参数 ParamNode 链表 - fn_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(fn_ref) - if fn_ret_ty is None: - # fail-fast:函数返回类型缺失,无法构造函数指针(暴露上游根因) - HandlesType.fatal_error( - node, f"函数 '{nm_id}' 返回类型缺失,无法构造函数指针", "TypeError") - fn_pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(fn_ref) - fn_first_node: llvmlite.ParamNode | t.CPtr = None - fn_prev_node: llvmlite.ParamNode | t.CPtr = None - fn_pcount: int = 0 - while fn_pp is not None: - fn_pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(fn_pp) - fn_pn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, fn_pty) - if fn_pn is not None: - if fn_first_node is None: - fn_first_node = fn_pn - if fn_prev_node is not None: - llvmlite.paramnode_set_next(fn_prev_node, fn_pn) - fn_prev_node = fn_pn - fn_pcount += 1 - fn_pp = llvmlite.param_get_next(fn_pp) - fn_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func( - pool, fn_ret_ty, fn_first_node, fn_pcount) - if fn_ty is None: - return None - # 构造函数指针 Value(new_value 包装,避免触碰 Function.Next) - fn_ref_v: llvmlite.Value | t.CPtr = llvmlite.new_value(pool) - if fn_ref_v is None: - return None - llvmlite.value_set_ty(fn_ref_v, llvmlite.Ptr(pool, fn_ty)) - llvmlite.value_set_isconst(fn_ref_v, 1) - fn_ref_name: str = pool.alloc(256) - if fn_ref_name is not None: - fn_ref_name[0] = '\0' - if HandlesClassDef._vtable_name_needs_quote(fn_name) != 0: - viperlib.snprintf(fn_ref_name, 256, "@\"%s\"", fn_name) - else: - viperlib.snprintf(fn_ref_name, 256, "@%s", fn_name) - llvmlite.value_set_name(fn_ref_v, fn_ref_name) - fn_i8ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - return llvmlite.build_bitcast(builder, fn_ref_v, fn_i8ptr_ty) - - # ============================================================ - # 跨模块 from-import 全局变量读取(如 from .tokens import _op_head) - # 根因:模块级全局(非 CDefine/非函数)from-import 后无本模块 SymTab - # 条目,所有查找路径未命中 → translate_name_value 返回 None → 赋值被 - # 静默跳过 → 变量未初始化 → 垃圾指针解引用崩溃(AstTest 的 - # _read_operator 里 `cur = _op_head` 丢失导致 while 循环读未初始化 %6)。 - # 语义对齐模块属性全局(sys._mbuddy):external @{全局名} 引用 + load, - # 定义由源模块提供(COFF 按名链接)。别名导入用源模块内真实名。 - # ============================================================ - if trans is not None and trans._from_imports is not None: - if trans.Module is not None: - # 是 from-import 名称(禁用 star 回退,避免误归 star 模块) - fi_mod: str = HandlesImports.lookup_from_import( - trans._from_imports, nm_id, 0) - if fi_mod is not None: - # 排除已注册类名/枚举名:这些是类型,不作为全局变量值读取 - fi_is_class: int = 0 - if HandlesStruct.get_struct_type(nm_id) is not None: - fi_is_class = 1 - # 排除 ALL_CAPS CDefine(上方已处理本地+跨模块查找) - if HandlesExpr._is_cdefine_name_pattern(nm_id) != 0: - fi_is_class = 1 - if fi_is_class == 0: - fi_gname: str = nm_id - fi_orig: str = HandlesImports.lookup_from_import_original( - trans._from_imports, nm_id) - if fi_orig is not None: - og_len_fi: t.CSizeT = 0 - while fi_orig[og_len_fi] != ' ' and fi_orig[og_len_fi] != '\0': - og_len_fi += 1 - if og_len_fi > 0: - og_buf_fi: str = pool.alloc(og_len_fi + 1) - if og_buf_fi is not None: - string.strncpy(og_buf_fi, fi_orig, og_len_fi) - og_buf_fi[og_len_fi] = '\0' - fi_gname = og_buf_fi - # stub 已注入全局(精确类型)→ 直接引用;未注入 → fail-fast - # (不再创建 external i8* 声明,否则 llc 报 "use of undefined value", - # 静默回退掩盖 stub 未注入的上游根因) - # 带源模块 SHA1 前缀精确查找(避免多模块同名全局后缀匹配串扰); - # fi_mod 非 NUL 结尾,先截断再查 SHA1(否则退化裸名 → undefined) - fi_mod_cut2: str = self._cut_from_import_mod(pool, fi_mod) - if fi_mod_cut2 is None: - fi_mod_cut2 = fi_mod - gv_fi_q: str = HandlesFunctions._mangle_name_with_sha1( - StubMergerStore.LookupSha1ByModName(fi_mod_cut2), fi_gname) - gv_fi: llvmlite.GlobalVariable | t.CPtr = HandlesExpr.find_global_in_module( - trans.Module, gv_fi_q) - ref_fi: llvmlite.Value | t.CPtr = None - if gv_fi is not None and gv_fi.Ty is not None: - ref_fi = HandlesExpr.make_global_ref(pool, gv_fi.Name, gv_fi.Ty) - else: - # 依赖模块 vpi/stub 未注入:Phase A 按文件序翻译时依赖模块 - # (如 lexer 先于 ast.tokens)可能晚于本文件,其 .vpi 尚未生成 - # (LoadDepVpiIntoModule 无从注入)→ 标记 _deps_pending 下遍 - # 重试(对齐 CallGenMixin 跨模块依赖未就绪处理)。真实错误由 - # Phase A 收敛检查暴露,不在此 fail-fast——否则清缓存后 - # lexer 先于 tokens 翻译必然误报 "stub 未注入"。 - if trans is not None: - trans._deps_pending = 1 - return None - if ref_fi is not None and ref_fi.Ty is not None: - lty_fi: llvmlite.LLVMType | t.CPtr = ref_fi.Ty.Pointee - if lty_fi is not None: - return llvmlite.build_load(builder, lty_fi, ref_fi) - return ref_fi - - # 所有查找路径均失败 - # fail-fast:未定义名称立即终止编译(NameError,暴露上游根因), - # 不再静默返回 None(否则下游 store/call 到 None 崩溃,掩盖名称查找失败)。 - # 豁免:关键字/内建名(self/pool/true/false/None/match 上下文关键字、_、 - # CIf 系等特殊名字)——这些名字不注册 SymTab 属正常,调用方有合法语义 - # 处理路径(如 CIf 未定义名特判走 else),保持返回 None 不报错。 - if nm_id is None: - return None - if string.strcmp(nm_id, "self") == 0 or string.strcmp(nm_id, "pool") == 0 \ - or string.strcmp(nm_id, "true") == 0 or string.strcmp(nm_id, "false") == 0 \ - or string.strcmp(nm_id, "None") == 0 or string.strcmp(nm_id, "match") == 0 \ - or string.strcmp(nm_id, "_") == 0 \ - or string.strcmp(nm_id, "CIf") == 0 or string.strcmp(nm_id, "CIfdef") == 0 \ - or string.strcmp(nm_id, "CIfndef") == 0: - return None - HandlesType.fatal_error(node, f"未定义名称 '{nm_id}'", "NameError") - return None - # ============================================================ - # list_getitem_inline — 内联生成 list[T] __getitem__ 逻辑 - # - # list 结构布局 (6 字段 × 8 字节): - # __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40) - # 返回元素地址 (i8*),调用方根据元素类型 load 正确的值 - # ============================================================ - def list_getitem_inline(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - lm_obj: llvmlite.Value | t.CPtr, - idx_val: llvmlite.Value | t.CPtr, - node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """内联生成 list __getitem__ 逻辑,返回元素地址 (i8*)""" - if builder is None or pool is None or lm_obj is None or idx_val is None: - return None - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - # 加载 __data__ (偏移 0, index 0) - g_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) - g_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0) - if g_dpp is None: - return None - g_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, g_dpp) - # 加载 __elem_size__ (偏移 32, index 4) - g_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) - g_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4) - if g_epp is None: - return None - g_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, g_epp) - if g_data is None or g_esize is None: - return None - g_idx_i64: llvmlite.Value | t.CPtr = self.coerce_to_type(builder, idx_val, i64_ty, node) - if g_idx_i64 is None: - return None - g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize) - if g_offset is None: - return None - # 返回元素地址 (i8*),不 load - return llvmlite.build_gep(builder, i8_ty, g_data, g_offset) - # ============================================================ - # _list_elem_type_from_name — 从 list 类型名提取元素 LLVM 类型 - # - # 类型名格式: .list[] - # 用 strstr 检查完整模式,避免子串提取 - # 支持: list[int]→i32, list[str]/list[bytes]→i8*, list[CInt]→i32 等 - # 默认: i32 - # ============================================================ - def _list_elem_type_from_name(self, pool: memhub.MemBuddy | t.CPtr, - struct_name: str) -> llvmlite.LLVMType | t.CPtr: - """从 list 类型名提取元素 LLVM 类型""" - if pool is None or struct_name is None: - return None - # 用 strstr 检查完整模式 - if string.strstr(struct_name, "list[int]") is not None: - return llvmlite.Int32(pool) - if string.strstr(struct_name, "list[CInt]") is not None: - return llvmlite.Int32(pool) - if string.strstr(struct_name, "list[CInt8T]") is not None: - return llvmlite.Int8(pool) - if string.strstr(struct_name, "list[CInt16T]") is not None: - return llvmlite.Int16(pool) - if string.strstr(struct_name, "list[CInt32T]") is not None: - return llvmlite.Int32(pool) - if string.strstr(struct_name, "list[CInt64T]") is not None: - return llvmlite.Int64(pool) - if string.strstr(struct_name, "list[CSizeT]") is not None: - return llvmlite.Int64(pool) - if string.strstr(struct_name, "list[CDouble]") is not None: - return llvmlite.Double(pool) - if string.strstr(struct_name, "list[CFloat]") is not None: - return llvmlite.Float(pool) - if string.strstr(struct_name, "list[CChar]") is not None: - return llvmlite.Int8(pool) - # str/bytes/CPtr 等已知指针元素类型 → i8*(元素存储为 8 字节地址) - i8_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - if string.strstr(struct_name, "list[str]") is not None: - return llvmlite.Ptr(pool, i8_ty_d) - if string.strstr(struct_name, "list[bytes]") is not None: - return llvmlite.Ptr(pool, i8_ty_d) - if string.strstr(struct_name, "list[CPtr]") is not None: - return llvmlite.Ptr(pool, i8_ty_d) - # 未知 list[T] 元素类型(如 list[Foo]、list[AST|t.CPtr]):元素存储为 - # 8 字节槽(指针或 8 字节整数),回退 Ptr(i8) 位宽一致(load 8 字节), - # 由 AnnotClassName/特化恢复机制保证语义。禁止 fail-fast(误杀合法 - # 自定义类元素列表的下标访问)。 - return llvmlite.Ptr(pool, i8_ty_d) - # ============================================================ - # list_setitem_inline — 内联生成 list[T] __setitem__ 逻辑 - # - # 直接存储 rhs_val 到元素地址 (coerce 为 i8* 后 store) - # ============================================================ - def list_setitem_inline(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - lm_obj: llvmlite.Value | t.CPtr, - idx_val: llvmlite.Value | t.CPtr, - rhs_val: llvmlite.Value | t.CPtr, - node: ast.AST | t.CPtr = None) -> int: - """内联生成 list __setitem__ 逻辑,返回 0""" - if builder is None or pool is None or lm_obj is None or idx_val is None or rhs_val is None: - return 0 - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - # 加载 __data__ (偏移 0, index 0) - s_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) - s_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0) - if s_dpp is None: - return 0 - s_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, s_dpp) - # 加载 __elem_size__ (偏移 32, index 4) - s_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) - s_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4) - if s_epp is None: - return 0 - s_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, s_epp) - if s_data is None or s_esize is None: - return 0 - s_idx_i64: llvmlite.Value | t.CPtr = self.coerce_to_type(builder, idx_val, i64_ty, node) - if s_idx_i64 is None: - return 0 - s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize) - if s_offset is None: - return 0 - s_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s_data, s_offset) - if s_addr is None: - return 0 - # 元素类型 T:从 list 特化类型名解析(list[int]→i32、list[str]→i8*)。 - # 此前固定 i8*(8 字节)store(inttoptr 值)覆盖相邻元素——与 - # CallGenMixin list 内置分支同根因(ListTest pop FAILED expect 30)。 - s_sty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(lm_obj) - s_name: str = None - if s_sty is not None: - s_name = llvmlite.get_struct_name(s_sty) - s_elem_ty: llvmlite.LLVMType | t.CPtr = None - if s_name is not None: - s_elem_ty = self._list_elem_type_from_name(pool, s_name) - if s_elem_ty is None: - s_elem_ty = i8_ptr_ty - s_val_ptr: llvmlite.Value | t.CPtr = self.coerce_to_type(builder, rhs_val, s_elem_ty, node) - if s_val_ptr is None: - return 0 - s_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, s_addr, llvmlite.Ptr(pool, s_elem_ty)) - if s_ep is not None: - llvmlite.build_store(builder, s_val_ptr, s_ep) - return 0 - # ============================================================ - # is_list_subscript — 检查 Subscript 节点是否是 list[T] 类型 - # - # 返回 list 对象指针 (Ptr(list[T])) 或 None - # ============================================================ - def is_list_subscript(self, node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """检查 Subscript 节点是否是 list[T] 类型,返回 list 对象指针或 None""" - if node is None or trans is None: - return None - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - if sub is None or sub.value is None: - return None - if sub.value.kind() != ast.ASTKind.Name: - return None - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) - if nm is None or nm.id is None: - return None - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is None or alloca.Ty is None: - return None - if self.is_ptr_type(alloca.Ty) == 0: - return None - pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee - if pointee is None: - return None - # 检查 pointee 是否是 Ptr(Struct) - inner_ty: llvmlite.LLVMType | t.CPtr = None - match pointee: - case llvmlite.LLVMType.Ptr(it): - inner_ty = it - case _: - return None - if inner_ty is None: - return None - # 检查 inner_ty 是否是 Struct 且名称包含 "list[" - struct_name: str = None - match inner_ty: - case llvmlite.LLVMType.Struct(_, _, sname): - struct_name = sname - case _: - return None - if struct_name is None: - return None - if string.strstr(struct_name, "list[") is None: - return None - # 是 list 类型: load 出 list 对象指针 - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - return llvmlite.build_load(builder, pointee, alloca) - # ============================================================ - # _nonlocal_subscript_ptr - nonlocal 数组/指针的下标元素指针 - # - # 嵌套函数(提升函数)体内访问 nonlocal 变量时,变量的实际存储是 - # 运行时共享堆(env[ni] 存的堆地址),不能 lookup_var 找外层函数 - # alloca(其 SSA 编号属于外层函数,当前函数引用错乱崩溃—— - # ClosureTest2 Test 4 fill() 内 arr[i] 崩溃根因)。 - # 正确路径:从 env 读堆地址(_load_raw_var_ptr)→ bitcast → GEP。 - # ============================================================ - def _nonlocal_subscript_ptr(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - nm_id: str, - idx_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: - """nonlocal 数组/指针下标:从 env 读堆地址 → bitcast → GEP,返回元素指针""" - if trans is None or nm_id is None or idx_val is None: - return None - nl_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, nm_id) - if nl_ty is None: - return None - raw_nl: llvmlite.Value | t.CPtr = HandlesNonlocal._load_raw_var_ptr(trans, nm_id) - if raw_nl is None: - return None - match nl_ty: - case llvmlite.LLVMType.Array(elem_ty_nl, _cnt_nl): - arr_ptr_nl: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, raw_nl, llvmlite.Ptr(pool, nl_ty)) - if arr_ptr_nl is None: - return None - return llvmlite.build_gep_array( - builder, nl_ty, elem_ty_nl, arr_ptr_nl, - self._zext_index_to_i32(builder, idx_val)) - case llvmlite.LLVMType.Ptr(inner_nl): - arr_ptr_nl2: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, raw_nl, llvmlite.Ptr(pool, nl_ty)) - if arr_ptr_nl2 is None: - return None - return llvmlite.build_gep(builder, inner_nl, arr_ptr_nl2, idx_val) - case _: - arr_ptr_nl3: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, raw_nl, llvmlite.Ptr(pool, nl_ty)) - if arr_ptr_nl3 is None: - return None - return llvmlite.build_gep(builder, nl_ty, arr_ptr_nl3, idx_val) - return None - # ============================================================ - # 翻译下标表达式 Subscript(value, slice, ctx) — ptr[i] / arr[i] - # - # 指针遍历: ptr 是指针变量,load 出指针值后 GEP + load - # 数组遍历: arr 是数组变量,用 alloca 指针做双索引 GEP [0, i] + load - # list[T]: 泛型类不注册 struct,subscript 走 __getitem__ 内联路径 - # ============================================================ - def translate_subscript(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译下标表达式,返回加载的元素值""" - if node is None or builder is None: - return None - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - if sub is None: - return None - - # 翻译索引 - idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, sub.slice, None, 0, trans) - if idx_val is None: - return None - - # 如果 value 是 Name,尝试从 alloca 类型推断 - if sub.value is not None and sub.value.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) - if nm.id is not None and trans is not None: - # nonlocal 数组/指针:从 env 读共享堆地址(提升函数内不能 - # lookup_var 外层 alloca——SSA 编号跨函数错乱崩溃) - # 读路径:元素指针 load 出元素值 - if HT.is_nonlocal_name(trans, nm.id) != 0: - nl_ptr_r: llvmlite.Value | t.CPtr = self._nonlocal_subscript_ptr( - builder, pool, trans, nm.id, idx_val) - if nl_ptr_r is not None and nl_ptr_r.Ty is not None: - nl_elem_ty: llvmlite.LLVMType | t.CPtr = nl_ptr_r.Ty.Pointee - if nl_elem_ty is not None: - return llvmlite.build_load(builder, nl_elem_ty, nl_ptr_r) - return None - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is not None and alloca.Ty is not None: - if self.is_ptr_type(alloca.Ty) != 0: - pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee - if pointee is not None: - # 不调用 pointee.kind() 避免跨模块引用 LLVMType.kind 符号 - # 用 match 检查 pointee 类型 - match pointee: - case llvmlite.LLVMType.Array(elem_ty, count): - # 数组遍历: getelementptr [N x elem_ty], ... , i32 0, i32 %idx - elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, pointee, elem_ty, alloca, - self._zext_index_to_i32(builder, idx_val)) - if elem_ptr is not None: - return llvmlite.build_load(builder, elem_ty, elem_ptr) - return None - case llvmlite.LLVMType.Struct(_fs_v, _fc_v, lsn_v): - # list[T] 值变量(无注解赋值 rhs 返回 list 值, - # 如 parts = s1.split(','):split 的 define 返回 - # %list[str] 结构体值,alloca 直接存 list 对象)。 - # alloca 即 list*,直接走 list 内联 __getitem__ - #(对齐 Ptr(Ptr(list)) 变量路径,修复 parts[0] 崩溃) - if lsn_v is not None: - if string.strstr(lsn_v, "list[") is not None: - elem_addr_v: llvmlite.Value | t.CPtr = \ - self.list_getitem_inline( - builder, pool, alloca, idx_val, node) - if elem_addr_v is not None: - elem_ty_v: llvmlite.LLVMType | t.CPtr = \ - self._list_elem_type_from_name(pool, lsn_v) - if elem_ty_v is not None: - elem_ptr_ty_v: llvmlite.LLVMType | t.CPtr = \ - llvmlite.Ptr(pool, elem_ty_v) - casted_v: llvmlite.Value | t.CPtr = \ - llvmlite.build_bitcast( - builder, elem_addr_v, elem_ptr_ty_v) - if casted_v is not None: - return llvmlite.build_load( - builder, elem_ty_v, casted_v) - return None - case llvmlite.LLVMType.Ptr(inner_ty): - # 检查 inner_ty 是否是 list[T] 类型(泛型类不注册 struct) - # list 的 subscript 应该走 __getitem__ 内联路径,而非指针遍历 - list_struct_name: str = None - match inner_ty: - case llvmlite.LLVMType.Struct(_, _, lsn): - list_struct_name = lsn - case _: - pass - if list_struct_name is not None: - if string.strstr(list_struct_name, "list[") is not None: - # list[T] 类型: 内联生成 __getitem__ 逻辑 - ptr_val_list: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val_list is not None: - elem_addr_list: llvmlite.Value | t.CPtr = self.list_getitem_inline( - builder, pool, ptr_val_list, idx_val, node) - if elem_addr_list is not None: - # 根据类型名提取元素类型,bitcast 后 load - elem_ty_list: llvmlite.LLVMType | t.CPtr = self._list_elem_type_from_name( - pool, list_struct_name) - if elem_ty_list is not None: - elem_ptr_ty_list: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, elem_ty_list) - casted_addr_list: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, elem_addr_list, elem_ptr_ty_list) - if casted_addr_list is not None: - return llvmlite.build_load( - builder, elem_ty_list, casted_addr_list) - return None - # inner_ty 是 Ptr 说明 alloca.Ty 是三重指针 Ptr(Ptr(Ptr(...))), - # 即 X|t.CPtr 当 X 本身是指针类型 (如 T=AST|t.CPtr, T|t.CPtr=AST**)。 - # 此时 [i] 应该是指针解引用 (步长 sizeof(ptr)=8), 而非调用 - # 结构体的 __getitem__ 方法 (会错误生成 AST.__getitem__ 调用)。 - # 对比 HashTable|t.CPtr: alloca.Ty=HashTable**, inner_ty=Struct(HashTable) - # (非 Ptr), 仍走下面的方法调用转发路径。 - if self.is_ptr_type(inner_ty) != 0: - ptr_val_pp: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val_pp is not None: - elem_ptr_pp: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, inner_ty, ptr_val_pp, idx_val) - if elem_ptr_pp is not None: - return llvmlite.build_load(builder, inner_ty, elem_ptr_pp) - return None - # 自定义结构体 (如 HashTable|t.CPtr, JsonValue|t.CPtr): - # 仅当类定义了 __getitem__(当前模块定义或跨模块 stub declare 注入) - # 才转发方法调用;否则普通结构体指针按下标做 GEP 数组访问 - # (对齐 TPC _HandleSubscriptLlvm: if ClassName and has_function(__getitem__)) - cls_nm_rd_ptr: str = self._get_custom_struct_cls_nm(pool, inner_ty) - if not (cls_nm_rd_ptr is None): - gi_lookup_rd: str = pool.alloc(128) - if gi_lookup_rd is not None: - viperlib.snprintf(gi_lookup_rd, 128, "%s.__getitem__", cls_nm_rd_ptr) - if ExprCallBase.find_func_in_module(mod, gi_lookup_rd) is not None: - obj_ptr_rd: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if not (obj_ptr_rd is None): - arg_vals_rd_p: t.CSizeT | t.CPtr = pool.alloc(8) - if not (arg_vals_rd_p is None): - arg_vals_rd_p[0] = t.CSizeT(idx_val) - ret_rd_p: llvmlite.Value | t.CPtr = ExprCallCtor._call_method_on_ptr( - pool, builder, mod, cls_nm_rd_ptr, "__getitem__", - obj_ptr_rd, arg_vals_rd_p, 1, trans, sub) - if not (ret_rd_p is None): - return ret_rd_p - # 无 __getitem__:结构体指针数组访问(GEP + load) - ptr_val_rd_g: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val_rd_g is not None: - elem_rd_g: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, inner_ty, ptr_val_rd_g, idx_val) - if elem_rd_g is not None: - return llvmlite.build_load(builder, inner_ty, elem_rd_g) - return None - # bytes|t.CPtr / str|t.CPtr: alloca 是 i8**, - # 直接 GEP 按 i8* 步长(8 字节),load i8* - # 仅当 inner_ty 不是自定义结构体时才走指针遍历 - if trans is not None: - ve_pe_ts: HandlesVar.VarEntry | t.CPtr = \ - HandlesVar.lookup_var_entry(trans.SymTab, nm.id) - if ve_pe_ts is not None and ve_pe_ts.IsPtrElement == 1: - # bytes|t.CPtr / str|t.CPtr / T|t.CPtr:变量存指针值(i8*), - # elem[i] 语义 = load [指针值 + i*8](8 字节指针元素)。 - # 必须先 load alloca 得指针值,再 GEP i8*(步长 8)—— - # 否则 GEP base 用 alloca(&elem_ptr)读到栈变量而非数据区, - # list.get 返回"元素地址"而非"元素值"(dump 虚调用读错 vtable)。 - ptr_val_pe_ts: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val_pe_ts is not None: - elem_ptr_ts: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, pointee, ptr_val_pe_ts, idx_val) - if elem_ptr_ts is not None: - return llvmlite.build_load(builder, pointee, elem_ptr_ts) - return None - # 普通指针遍历: 先 load 指针值,再 GEP - ptr_val: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val is not None: - elem_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, inner_ty, ptr_val, idx_val) - if elem_ptr2 is not None: - return llvmlite.build_load(builder, inner_ty, elem_ptr2) - return None - case _: - # 联合类型变量(IsPtrElement=1,如 _list.vp 的 - # elem_ptr: T | t.CPtr 退化为 i8*):pointee=i8 但 - # 元素是 8 字节指针,须按 i8* 步长 GEP + load i8*—— - # 否则 list.get 只读 1 字节,指针截断 inttoptr 崩溃。 - if trans is not None: - ve_pe_rd: HandlesVar.VarEntry | t.CPtr = \ - HandlesVar.lookup_var_entry(trans.SymTab, nm.id) - if ve_pe_rd is not None and ve_pe_rd.IsPtrElement == 1: - match pointee: - case llvmlite.LLVMType.Int8(): - i8_ptr_rd: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - elem_ptr_rd: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i8_ptr_rd, alloca, idx_val) - if elem_ptr_rd is not None: - return llvmlite.build_load( - builder, i8_ptr_rd, elem_ptr_rd) - case _: - pass - # 自定义类(结构体类型): 仅当类定义了 __getitem__ - # (当前模块定义或跨模块 stub declare 注入)才转发方法调用; - # 否则普通结构体指针按下标做 GEP 数组访问 - cls_nm_sub: str = HandlesStruct.get_class_name_by_type(pool, pointee) - if not (cls_nm_sub is None): - gi_lookup_sub: str = pool.alloc(128) - if gi_lookup_sub is not None: - viperlib.snprintf(gi_lookup_sub, 128, "%s.__getitem__", cls_nm_sub) - if ExprCallBase.find_func_in_module(mod, gi_lookup_sub) is not None: - obj_val_sub: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if not (obj_val_sub is None): - arg_vals_sub: t.CSizeT | t.CPtr = pool.alloc(8) - if not (arg_vals_sub is None): - arg_vals_sub[0] = t.CSizeT(idx_val) - ret_sub: llvmlite.Value | t.CPtr = ExprCallCtor._call_method_on_ptr( - pool, builder, mod, cls_nm_sub, "__getitem__", - obj_val_sub, arg_vals_sub, 1, trans, sub) - if not (ret_sub is None): - return ret_sub - # 无 __getitem__:结构体指针数组访问(GEP + load) - ptr_val_sub_g: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val_sub_g is not None: - elem_sub_g: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, pointee, ptr_val_sub_g, idx_val) - if elem_sub_g is not None: - return llvmlite.build_load(builder, pointee, elem_sub_g) - return None - pass - - # 通用路径:翻译 value 获取指针 - ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, sub.value, None, 0, trans) - if ptr_val is None or ptr_val.Ty is None: - return None - - # 检查是否是指针类型 - if self.is_ptr_type(ptr_val.Ty) != 0: - elem_ty2: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee - if elem_ty2 is not None: - # 数组类型: 双索引 GEP + load 元素 - match elem_ty2: - case llvmlite.LLVMType.Array(arr_elem_ty2, arr_count2): - elem_ptr3: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, elem_ty2, arr_elem_ty2, ptr_val, - self._zext_index_to_i32(builder, idx_val)) - if elem_ptr3 is not None: - return llvmlite.build_load(builder, arr_elem_ty2, elem_ptr3) - return None - case _: - pass - # 自定义结构体 (如 self._ht[key]): 仅当类定义了 __getitem__ 才转发方法调用; - # 否则普通结构体指针按下标做 GEP 数组访问 - cls_nm_rd_gen: str = self._get_custom_struct_cls_nm(pool, elem_ty2) - if not (cls_nm_rd_gen is None): - gi_lookup_gen: str = pool.alloc(128) - if gi_lookup_gen is not None: - viperlib.snprintf(gi_lookup_gen, 128, "%s.__getitem__", cls_nm_rd_gen) - if ExprCallBase.find_func_in_module(mod, gi_lookup_gen) is not None: - arg_vals_rd_g: t.CSizeT | t.CPtr = pool.alloc(8) - if not (arg_vals_rd_g is None): - arg_vals_rd_g[0] = t.CSizeT(idx_val) - ret_rd_g: llvmlite.Value | t.CPtr = ExprCallCtor._call_method_on_ptr( - pool, builder, mod, cls_nm_rd_gen, "__getitem__", - ptr_val, arg_vals_rd_g, 1, trans, sub) - if not (ret_rd_g is None): - return ret_rd_g - # 无 __getitem__:结构体指针数组访问(GEP + load) - elem_ptr_gen: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, elem_ty2, ptr_val, idx_val) - if elem_ptr_gen is not None: - return llvmlite.build_load(builder, elem_ty2, elem_ptr_gen) - return None - # 指针类型: 单索引 GEP + load - elem_ptr4: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, elem_ty2, ptr_val, idx_val) - if elem_ptr4 is not None: - return llvmlite.build_load(builder, elem_ty2, elem_ptr4) - return None - # ============================================================ - # 获取下标表达式的元素指针(不加载值,用于赋值) - # ============================================================ - def get_subscript_ptr(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """获取下标表达式的元素指针(用于赋值 lhs)""" - if node is None or builder is None: - return None - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - if sub is None: - return None - - # 翻译索引 - idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, sub.slice, None, 0, trans) - if idx_val is None: - return None - - # 如果 value 是 Name,尝试从 alloca 类型推断 - if sub.value is not None and sub.value.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) - if nm.id is not None and trans is not None: - # nonlocal 数组/指针:从 env 读共享堆地址(提升函数内不能 - # lookup_var 外层 alloca——SSA 编号跨函数错乱崩溃) - if HT.is_nonlocal_name(trans, nm.id) != 0: - return self._nonlocal_subscript_ptr( - builder, pool, trans, nm.id, idx_val) - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is not None and alloca.Ty is not None: - if self.is_ptr_type(alloca.Ty) != 0: - pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee - if pointee is not None: - # 用 match 检查 pointee 类型 - match pointee: - case llvmlite.LLVMType.Array(elem_ty, count): - # 数组遍历 - return llvmlite.build_gep_array( - builder, pointee, elem_ty, alloca, - self._zext_index_to_i32(builder, idx_val)) - case llvmlite.LLVMType.Ptr(inner_ty): - # inner_ty 是 Ptr 说明 alloca.Ty 是三重指针, - # 即 X|t.CPtr 当 X 本身是指针类型 (如 T=AST|t.CPtr, T|t.CPtr=AST**)。 - # 此时 [i]=val 应该是指针解引用赋值, 而非调用 __setitem__。 - if self.is_ptr_type(inner_ty) != 0: - ptr_val_gsp: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val_gsp is not None: - return llvmlite.build_gep( - builder, inner_ty, ptr_val_gsp, idx_val) - return None - # 自定义结构体 (如 HashTable|t.CPtr, JsonValue|t.CPtr): - # 仅当类定义了 __setitem__(当前模块定义或跨模块 stub declare 注入) - # 才返回 None 触发 __setitem__ 重载;否则普通结构体指针按下标 - # 做 GEP 数组访问(走下方指针遍历路径) - cls_nm_ptr_chk: str = self._get_custom_struct_cls_nm(pool, inner_ty) - if not (cls_nm_ptr_chk is None): - si_lookup_gsp: str = pool.alloc(128) - if si_lookup_gsp is not None: - viperlib.snprintf(si_lookup_gsp, 128, "%s.__setitem__", cls_nm_ptr_chk) - if ExprCallBase.find_func_in_module(mod, si_lookup_gsp) is not None: - return None - # bytes|t.CPtr / str|t.CPtr: alloca 是 i8**, - # 直接 GEP 按 i8* 步长(8 字节),不 load - # 仅当 inner_ty 不是自定义结构体时才走指针遍历 - if trans is not None: - ve_pe: HandlesVar.VarEntry | t.CPtr = \ - HandlesVar.lookup_var_entry(trans.SymTab, nm.id) - if ve_pe is not None and ve_pe.IsPtrElement == 1: - # bytes|t.CPtr / str|t.CPtr / T|t.CPtr:变量存指针值, - # 下标语义 = [指针值 + i*8](8 字节指针元素)。必须先 load - # alloca 得指针值,再 GEP——否则 GEP base 用 alloca(&elem_ptr) - # 读到栈变量而非数据区,赋值写不进 list 数据 - # (data 全 0xbaadf00d,dump 虚调用读错 vtable 崩溃)。 - ptr_val_pe: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val_pe is not None: - match pointee: - case llvmlite.LLVMType.Int8(): - i8_ptr_pe: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - return llvmlite.build_gep( - builder, i8_ptr_pe, ptr_val_pe, idx_val) - case _: - pass - return llvmlite.build_gep( - builder, pointee, ptr_val_pe, idx_val) - return None - # 普通指针遍历: 先 load 指针值,再 GEP - ptr_val: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val is None: - return None - gep_r: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, inner_ty, ptr_val, idx_val) - return gep_r - case _: - # pointee 是普通标量类型 (如 i64, i32, i8): - # alloca 是 Ptr(标量), 直接 GEP 获取第 idx 个元素指针 - # 支持 arg_vals[i] = val 这类参数数组下标赋值 - # 联合类型变量(IsPtrElement=1,如 _list.vp 的 - # elem_ptr: T | t.CPtr 退化为 i8*):pointee=i8 但 - # 元素是 8 字节指针,须按 i8* 步长 GEP(防只写 1 字节截断) - if trans is not None: - ve_pe_cs: HandlesVar.VarEntry | t.CPtr = \ - HandlesVar.lookup_var_entry(trans.SymTab, nm.id) - if ve_pe_cs is not None and ve_pe_cs.IsPtrElement == 1: - # T|t.CPtr(退化为 i8*,如 _list.vp 的 elem_ptr)变量 - # 存数据区指针,元素为 8 字节指针:必须先 load alloca - # 得指针值,再按 i8* 步长 GEP——否则 GEP base 用 alloca - # (&elem_ptr)算到栈地址,赋值写不进 list 数据区 - # (append 只增 count、data 全 0xbaadf00d)。 - ptr_val_cs: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val_cs is not None: - match pointee: - case llvmlite.LLVMType.Int8(): - i8_ptr_cs: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - return llvmlite.build_gep( - builder, i8_ptr_cs, ptr_val_cs, idx_val) - case _: - pass - return llvmlite.build_gep( - builder, pointee, ptr_val_cs, idx_val) - return None - return llvmlite.build_gep(builder, pointee, alloca, idx_val) - - # 通用路径 - ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, sub.value, None, 0, trans) - if ptr_val is None or ptr_val.Ty is None: - return None - if self.is_ptr_type(ptr_val.Ty) != 0: - elem_ty2: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee - if elem_ty2 is not None: - # 数组类型: 双索引 GEP (getelementptr [N x ty], ptr, i32 0, i32 idx) - match elem_ty2: - case llvmlite.LLVMType.Array(arr_elem_ty, arr_count): - return llvmlite.build_gep_array( - builder, elem_ty2, arr_elem_ty, ptr_val, - self._zext_index_to_i32(builder, idx_val)) - case _: - pass - # 自定义结构体 (如 self._ht[key]): 仅当类定义了 __setitem__ - # 才返回 None 触发 HandlesAssign 的 __setitem__ 重载; - # 否则普通结构体指针按下标做 GEP 数组访问 - cls_nm_gen: str = self._get_custom_struct_cls_nm(pool, elem_ty2) - if not (cls_nm_gen is None): - si_lookup_gen: str = pool.alloc(128) - if si_lookup_gen is not None: - viperlib.snprintf(si_lookup_gen, 128, "%s.__setitem__", cls_nm_gen) - if ExprCallBase.find_func_in_module(mod, si_lookup_gen) is not None: - return None - # 指针类型: 单索引 GEP (getelementptr ty, ptr, idx) - return llvmlite.build_gep(builder, elem_ty2, ptr_val, idx_val) +import lib.core.Gen.GenTypes as GenTypes +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import w32.fileio as fileio +import lib.core.CompilerFactory as CompilerFactory +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.StubMerger as StubMerger +import lib.core.StubMergerStore as StubMergerStore +import lib.core.VLogger as VLogger +import lib.Projectrans.Config as Config +import lib.Projectrans.Utils as Utils + + +import lib.core.Gen.ExprGenBase as ExprGenBase + +# ============================================================ +# ExprGenName - ExprGenMixin 拆分(阶段 D):Name/Subscript/下标访问 +# +# 继承 ExprGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class ExprGenName(ExprGenBase.ExprGenBase): + """Name/Subscript/下标访问""" + + def _cut_from_import_mod(self, pool: memhub.MemBuddy | t.CPtr, + raw: str) -> str: + """截断 lookup_from_import 返回的模块名到独立缓冲 + + lookup_from_import 返回指向 from_imports 内部的指针(非 NUL 结尾, + 后随空格分隔的其他条目,如 "ast.tokens TokenType:ast.tokens ...")。 + 不截断则 LookupSha1ByModName 收到整串查不到 → mangle 退化裸名 → + 全局引用不带 SHA1 前缀 → 链接 undefined symbol(_op_head 根因, + 对齐 ExprGenCdef._lookup_cross_module_cdefine 的截断逻辑)。 + 截断到空格/冒号/NUL;raw 无效返回 None。 + """ + if raw is None: + return None + mbl_c: t.CSizeT = 0 + while raw[mbl_c] != ' ' and raw[mbl_c] != '\0' and raw[mbl_c] != ':': + mbl_c += 1 + if mbl_c == 0: + return None + buf_c: str = pool.alloc(mbl_c + 1) + if buf_c is None: + return None + string.strncpy(buf_c, raw, mbl_c) + buf_c[mbl_c] = '\0' + return buf_c + + def translate_name_value(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译变量引用(Name 节点)→ load""" + # mod 必须取自 trans.Module:函数签名无 mod 参数,若用裸名 mod 会被 + # 解析为 None → create_global_string 的 module_add_global(None, gv) 被 + # add_global 的 `if self is None: return` 静默丢弃 → 字符串 CDefine 的 + # global 定义丢失但 _label_counter/IR 引用已生成 → llc 报 + # "use of undefined value '@.str.{sha1}.N'(SysLibTest _cleanup 根因)" + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm is None: + return None + nm_id: str = nm.id + if nm_id is None: + return None + # CDefine 编译期常量: 返回常量值(浮点 CDefine → double 常量,整数 → i32) + # NAME: t.CDefine = value 形式定义的常量在编译期已注册到本地表 + # 浮点 CDefine(如 vipermath 的 U_M_PI=3.14...)必须返回浮点常量, + # 否则在 double 函数里 return 生成 ret i32 0(llc 报错)。 + cdef_val_d: double = self.Gen.TypeGenCDef.lookup_cdefine_double(nm_id) + if self.Gen.TypeGenCDef.is_cdefine_found() != 0: + if self.Gen.TypeGenCDef.is_cdefine_str() != 0: + # 字符串 CDefine(如 ZLIB_VERSION: t.CDefine = "1.3.2"): + # 返回 global string(i8*),供 return ZLIB_VERSION 等使用。 + cdef_sv: str = self.Gen.TypeGenCDef.lookup_cdefine_string(nm_id) + if cdef_sv is not None: + return self.Gen.ExprGenConst.create_global_string(builder, pool, mod, cdef_sv, trans) + self.Gen.TypeGenErr.fatal_error(node, f"CDefine 字符串值缺失: {nm_id}", "InternalCompilerError") + if self.Gen.TypeGenCDef.is_cdefine_double() != 0: + return llvmlite.ConstFloat(pool, llvmlite.Double(pool), cdef_val_d) + # 整数 CDefine:重新查表取 64 位全精度值(double 往返会丢精度, + # 9223372036854775807 → 9.223372036854776e18 舍入错位,生成错常量) + cdef_val_c: t.CInt64T = self.Gen.TypeGenCDef.lookup_cdefine_constant(nm_id) + return self.Gen.ExprGenCdef._const_int_for_cdefine(pool, cdef_val_c) + + # 本地表未找到:尝试跨模块 .vpi 查找(保证多模块查表存表一致) + # 仅对符合 CDefine 命名约定(ALL_CAPS)的名字触发跨模块查找, + # 避免对普通变量名(mb/name/ptr/pool/self 等)误触发,造成严重性能损耗 + if self.Gen.ExprGenCdef._is_cdefine_name_pattern(nm_id) != 0: + if trans is not None: + cdef_val: t.CInt64T = self.Gen.ExprGenCdef._lookup_cross_module_cdefine( + pool, nm_id, trans._from_imports, trans._imported_modules, 0, node) + if self.Gen.TypeGenCDef.is_cdefine_found() != 0: + if self.Gen.TypeGenCDef.is_cdefine_str() != 0: + cdef_sv2: str = self.Gen.TypeGenCDef.lookup_cdefine_string(nm_id) + if cdef_sv2 is not None: + return self.Gen.ExprGenConst.create_global_string(builder, pool, mod, cdef_sv2, trans) + self.Gen.TypeGenErr.fatal_error(node, f"CDefine 字符串值缺失: {nm_id}", "InternalCompilerError") + # 跨模块浮点 CDefine 已缓存为 double(is_cdefine_double), + # 需返回浮点常量而非截断的整数 + dchk_nm: double = self.Gen.TypeGenCDef.lookup_cdefine_double(nm_id) + if self.Gen.TypeGenCDef.is_cdefine_double() != 0: + return llvmlite.ConstFloat(pool, llvmlite.Double(pool), dchk_nm) + return self.Gen.ExprGenCdef._const_int_for_cdefine(pool, cdef_val) + + # CDefine 查找失败:from-import 的模块级全局变量(如 + # from Phase1 import PYI_BUF_SIZE;PYI_BUF_SIZE: t.CSizeT = 262144 是 + # i64 全局、非宏,语义同 C 的 extern size_t PYI_BUF_SIZE)。from-import + # 确认名称确实来自某模块后,按后缀匹配查找该全局并加载。 + if trans is not None and trans._from_imports is not None: + fi_mod_raw: str = self.Gen.ImportsGen.lookup_from_import( + trans._from_imports, nm_id, 0) + if fi_mod_raw is not None: + # 带源模块 SHA1 前缀精确查找,避免多模块同名全局后缀匹配串扰。 + # fi_mod_raw 非 NUL 结尾,先截断再查 SHA1(否则整串查不到退化裸名) + fi_mod_cut: str = self._cut_from_import_mod(pool, fi_mod_raw) + if fi_mod_cut is None: + fi_mod_cut = fi_mod_raw + fi_gv_q: str = self.Gen.FuncGenBase._mangle_name_with_sha1( + StubMergerStore.LookupSha1ByModName(fi_mod_cut), nm_id) + fi_gv: llvmlite.GlobalVariable | t.CPtr = self.Gen.ExprGenAttr.find_global_in_module( + trans.Module, fi_gv_q) + if fi_gv is not None and fi_gv.Ty is not None: + fi_ref: llvmlite.Value | t.CPtr = self.Gen.ExprGenAttr.make_global_ref( + pool, fi_gv.Name, fi_gv.Ty) + if fi_ref is not None and fi_ref.Ty is not None: + fi_pty: llvmlite.LLVMType | t.CPtr = fi_ref.Ty.Pointee + if fi_pty is not None: + match fi_pty: + case llvmlite.LLVMType.Array(_, _): + # 数组全局按 C 语义退化为基址(对齐 L3383-3388) + return fi_ref + case _: + pass + return llvmlite.build_load(builder, fi_pty, fi_ref) + + # global 变量:从模块作用域查找(global 声明优先级最高) + if trans is not None: + if HT.is_global_name(trans, nm_id) != 0: + mod_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_module_var( + trans.SymTab, nm_id) + if mod_alloca is not None: + load_ty: llvmlite.LLVMType | t.CPtr = None + if mod_alloca.Ty is not None: + load_ty = mod_alloca.Ty.Pointee + if load_ty is None: + # fail-fast:global 变量存储类型缺失,立即终止编译(暴露上游根因) + self.Gen.TypeGenErr.fatal_error( + node, f"变量 '{nm_id}' 存储类型缺失", "TypeError") + # 全局数组(如 pyzlib.pyzlib_error_msg: CArray[t.CChar, 512]): + # 按 C 语义衰减为基址返回(对齐下方局部数组分支 L3383-3388)。 + # 否则 load [512 x i8] 数组值当 i8* 传 → set_error 的 strncpy + # dest 是数组值(栈拷贝)而非数组基址 → 写入丢失 → get_error + # 为空(test_pyzlib "error message is empty" 根因)。 + match load_ty: + case llvmlite.LLVMType.Array(_, _): + return mod_alloca + case _: + pass + return llvmlite.build_load(builder, load_ty, mod_alloca) + + # nonlocal 变量:通过闭包 env 访问 + if HT.is_nonlocal_name(trans, nm_id) != 0: + return self.Gen.StmtGenDecl.load_nonlocal_var(trans, nm_id) + + # *args va_list:变量名直接解析为指向 24 字节 va_list 缓冲区的 i8* 地址 + # (对齐 TPC _direct_values[vararg_name] = va_list_ptr;不 load 缓冲区内容, + # 转发时按值传该地址即可,如 sprintf → vsnprintf(..., args)) + if trans is not None and trans._vararg_name is not None: + if nm_id is not None and string.strcmp(nm_id, trans._vararg_name) == 0: + if trans._va_list_ptr is not None: + return trans._va_list_ptr + + # 局部变量查找(必须先于模块别名检查) + # 否则与模块同名的局部变量(如 `import t, c` 后的局部变量 c)会被误判为模块别名, + # 导致 SymTab 已注册的局部变量查找不到(rhs_val is None bug 根因) + alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, nm_id) + if alloca is not None: + load_ty: llvmlite.LLVMType | t.CPtr = None + if alloca.Ty is not None: + load_ty = alloca.Ty.Pointee + if load_ty is None: + # fail-fast:局部变量存储类型缺失,立即终止编译(暴露上游根因) + self.Gen.TypeGenErr.fatal_error( + node, f"变量 '{nm_id}' 存储类型缺失", "TypeError") + # 结构体值变量(alloca 类型为 Struct,如 `x: Cls | t.CPtr`): + # 按"对象即指针"语义返回其地址(alloca 指针),而非加载结构体值。 + # 结构体值无法参与 ptrtoint/方法调用等地址相关操作,加载值会导致 + # `ptrtoint %Struct ... to i64` 无效指令(llc invalid cast opcode)。 + match load_ty: + case llvmlite.LLVMType.Struct(_, _, _): + return alloca + case llvmlite.LLVMType.Array(_, _): + # 数组变量按 C 语义退化为指针(返回数组基址),而非整体 + # load 数组值——如 printf("%s", str_arr) 应传数组首地址, + # load [N x i8] 值传给 %s 会读到错误数据崩溃 + # (ClassArrayTest TestCharArray 运行时崩溃根因)。 + return alloca + return llvmlite.build_load(builder, load_ty, alloca) + + # 模块别名检查:SymTab 查找失败后才检查 + # 如果 nm_id 是已导入模块名(如 win32file, fileio)且未被声明为局部变量, + # 返回 None 让上层处理(用于属性访问 win32file.CreateFileA) + if trans is not None and trans._imported_modules is not None: + if self.Gen.ImportsGen.is_module_imported(trans._imported_modules, nm_id) != 0: + return None + + # 模块级函数引用:函数名作为值传递(如 CreateThread(..., _thread_alloc_free, ...))。 + # 之前缺失此查找导致函数名参数翻译返回 None 被跳过,后续参数整体前移 + # (lpStartAddress 变成对象地址,线程从数据区执行直接崩溃)。 + # 注意:不能直接返回 Function 对象,也不能直接 build_bitcast(Function)—— + # Function 布局是 {Next, Name, RetTy, Params, ...},value_get_ty 会错位读到 + # Name 字段,TypePrint 输出 "void",生成 `bitcast void ... to i8*` 非法 IR; + # 且 Function.Next 是模块函数链表指针,参数链表构建对其赋值会截断函数链表, + # 最终打印出 `declare void @()` 空名函数。正确做法:按 Function 的 + # RetTy/Params 构造真实函数类型,用 new_value 包装成普通 Value 再 bitcast。 + if trans is not None and trans.Module is not None: + fn_ref: llvmlite.Function | t.CPtr = self.Gen.CallGenBase.find_func_in_module( + trans.Module, nm_id) + if fn_ref is not None: + fn_name: str = llvmlite.function_get_name(fn_ref) + if fn_name is None: + return None + # 构造函数类型:ret_ty + 参数 ParamNode 链表 + fn_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(fn_ref) + if fn_ret_ty is None: + # fail-fast:函数返回类型缺失,无法构造函数指针(暴露上游根因) + self.Gen.TypeGenErr.fatal_error( + node, f"函数 '{nm_id}' 返回类型缺失,无法构造函数指针", "TypeError") + fn_pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(fn_ref) + fn_first_node: llvmlite.ParamNode | t.CPtr = None + fn_prev_node: llvmlite.ParamNode | t.CPtr = None + fn_pcount: int = 0 + while fn_pp is not None: + fn_pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(fn_pp) + fn_pn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, fn_pty) + if fn_pn is not None: + if fn_first_node is None: + fn_first_node = fn_pn + if fn_prev_node is not None: + llvmlite.paramnode_set_next(fn_prev_node, fn_pn) + fn_prev_node = fn_pn + fn_pcount += 1 + fn_pp = llvmlite.param_get_next(fn_pp) + fn_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func( + pool, fn_ret_ty, fn_first_node, fn_pcount) + if fn_ty is None: + return None + # 构造函数指针 Value(new_value 包装,避免触碰 Function.Next) + fn_ref_v: llvmlite.Value | t.CPtr = llvmlite.new_value(pool) + if fn_ref_v is None: + return None + llvmlite.value_set_ty(fn_ref_v, llvmlite.Ptr(pool, fn_ty)) + llvmlite.value_set_isconst(fn_ref_v, 1) + fn_ref_name: str = pool.alloc(256) + if fn_ref_name is not None: + fn_ref_name[0] = '\0' + if self.Gen.ClassGenVTable._vtable_name_needs_quote(fn_name) != 0: + viperlib.snprintf(fn_ref_name, 256, "@\"%s\"", fn_name) + else: + viperlib.snprintf(fn_ref_name, 256, "@%s", fn_name) + llvmlite.value_set_name(fn_ref_v, fn_ref_name) + fn_i8ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + return llvmlite.build_bitcast(builder, fn_ref_v, fn_i8ptr_ty) + + # ============================================================ + # 跨模块 from-import 全局变量读取(如 from .tokens import _op_head) + # 根因:模块级全局(非 CDefine/非函数)from-import 后无本模块 SymTab + # 条目,所有查找路径未命中 → translate_name_value 返回 None → 赋值被 + # 静默跳过 → 变量未初始化 → 垃圾指针解引用崩溃(AstTest 的 + # _read_operator 里 `cur = _op_head` 丢失导致 while 循环读未初始化 %6)。 + # 语义对齐模块属性全局(sys._mbuddy):external @{全局名} 引用 + load, + # 定义由源模块提供(COFF 按名链接)。别名导入用源模块内真实名。 + # ============================================================ + if trans is not None and trans._from_imports is not None: + if trans.Module is not None: + # 是 from-import 名称(禁用 star 回退,避免误归 star 模块) + fi_mod: str = self.Gen.ImportsGen.lookup_from_import( + trans._from_imports, nm_id, 0) + if fi_mod is not None: + # 排除已注册类名/枚举名:这些是类型,不作为全局变量值读取 + fi_is_class: int = 0 + if self.Gen.StructGen.get_struct_type(nm_id) is not None: + fi_is_class = 1 + # 排除 ALL_CAPS CDefine(上方已处理本地+跨模块查找) + if self.Gen.ExprGenCdef._is_cdefine_name_pattern(nm_id) != 0: + fi_is_class = 1 + if fi_is_class == 0: + fi_gname: str = nm_id + fi_orig: str = self.Gen.ImportsGen.lookup_from_import_original( + trans._from_imports, nm_id) + if fi_orig is not None: + og_len_fi: t.CSizeT = 0 + while fi_orig[og_len_fi] != ' ' and fi_orig[og_len_fi] != '\0': + og_len_fi += 1 + if og_len_fi > 0: + og_buf_fi: str = pool.alloc(og_len_fi + 1) + if og_buf_fi is not None: + string.strncpy(og_buf_fi, fi_orig, og_len_fi) + og_buf_fi[og_len_fi] = '\0' + fi_gname = og_buf_fi + # stub 已注入全局(精确类型)→ 直接引用;未注入 → fail-fast + # (不再创建 external i8* 声明,否则 llc 报 "use of undefined value", + # 静默回退掩盖 stub 未注入的上游根因) + # 带源模块 SHA1 前缀精确查找(避免多模块同名全局后缀匹配串扰); + # fi_mod 非 NUL 结尾,先截断再查 SHA1(否则退化裸名 → undefined) + fi_mod_cut2: str = self._cut_from_import_mod(pool, fi_mod) + if fi_mod_cut2 is None: + fi_mod_cut2 = fi_mod + gv_fi_q: str = self.Gen.FuncGenBase._mangle_name_with_sha1( + StubMergerStore.LookupSha1ByModName(fi_mod_cut2), fi_gname) + gv_fi: llvmlite.GlobalVariable | t.CPtr = self.Gen.ExprGenAttr.find_global_in_module( + trans.Module, gv_fi_q) + ref_fi: llvmlite.Value | t.CPtr = None + if gv_fi is not None and gv_fi.Ty is not None: + ref_fi = self.Gen.ExprGenAttr.make_global_ref(pool, gv_fi.Name, gv_fi.Ty) + else: + # 依赖模块 vpi/stub 未注入:Phase A 按文件序翻译时依赖模块 + # (如 lexer 先于 ast.tokens)可能晚于本文件,其 .vpi 尚未生成 + # (LoadDepVpiIntoModule 无从注入)→ 标记 _deps_pending 下遍 + # 重试(对齐 CallGenMixin 跨模块依赖未就绪处理)。真实错误由 + # Phase A 收敛检查暴露,不在此 fail-fast——否则清缓存后 + # lexer 先于 tokens 翻译必然误报 "stub 未注入"。 + if trans is not None: + trans._deps_pending = 1 + return None + if ref_fi is not None and ref_fi.Ty is not None: + lty_fi: llvmlite.LLVMType | t.CPtr = ref_fi.Ty.Pointee + if lty_fi is not None: + return llvmlite.build_load(builder, lty_fi, ref_fi) + return ref_fi + + # 所有查找路径均失败 + # fail-fast:未定义名称立即终止编译(NameError,暴露上游根因), + # 不再静默返回 None(否则下游 store/call 到 None 崩溃,掩盖名称查找失败)。 + # 豁免:关键字/内建名(self/pool/true/false/None/match 上下文关键字、_、 + # CIf 系等特殊名字)——这些名字不注册 SymTab 属正常,调用方有合法语义 + # 处理路径(如 CIf 未定义名特判走 else),保持返回 None 不报错。 + if nm_id is None: + return None + if string.strcmp(nm_id, "self") == 0 or string.strcmp(nm_id, "pool") == 0 \ + or string.strcmp(nm_id, "true") == 0 or string.strcmp(nm_id, "false") == 0 \ + or string.strcmp(nm_id, "None") == 0 or string.strcmp(nm_id, "match") == 0 \ + or string.strcmp(nm_id, "_") == 0 \ + or string.strcmp(nm_id, "CIf") == 0 or string.strcmp(nm_id, "CIfdef") == 0 \ + or string.strcmp(nm_id, "CIfndef") == 0: + return None + self.Gen.TypeGenErr.fatal_error(node, f"未定义名称 '{nm_id}'", "NameError") + return None + # ============================================================ + # list_getitem_inline — 内联生成 list[T] __getitem__ 逻辑 + # + # list 结构布局 (6 字段 × 8 字节): + # __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40) + # 返回元素地址 (i8*),调用方根据元素类型 load 正确的值 + # ============================================================ + def list_getitem_inline(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + lm_obj: llvmlite.Value | t.CPtr, + idx_val: llvmlite.Value | t.CPtr, + node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """内联生成 list __getitem__ 逻辑,返回元素地址 (i8*)""" + if builder is None or pool is None or lm_obj is None or idx_val is None: + return None + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + # 加载 __data__ (偏移 0, index 0) + g_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + g_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0) + if g_dpp is None: + return None + g_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, g_dpp) + # 加载 __elem_size__ (偏移 32, index 4) + g_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) + g_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4) + if g_epp is None: + return None + g_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, g_epp) + if g_data is None or g_esize is None: + return None + g_idx_i64: llvmlite.Value | t.CPtr = self.coerce_to_type(builder, idx_val, i64_ty, node) + if g_idx_i64 is None: + return None + g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize) + if g_offset is None: + return None + # 返回元素地址 (i8*),不 load + return llvmlite.build_gep(builder, i8_ty, g_data, g_offset) + # ============================================================ + # _list_elem_type_from_name — 从 list 类型名提取元素 LLVM 类型 + # + # 类型名格式: .list[] + # 用 strstr 检查完整模式,避免子串提取 + # 支持: list[int]→i32, list[str]/list[bytes]→i8*, list[CInt]→i32 等 + # 默认: i32 + # ============================================================ + def _list_elem_type_from_name(self, pool: memhub.MemBuddy | t.CPtr, + struct_name: str) -> llvmlite.LLVMType | t.CPtr: + """从 list 类型名提取元素 LLVM 类型""" + if pool is None or struct_name is None: + return None + # 用 strstr 检查完整模式 + if string.strstr(struct_name, "list[int]") is not None: + return llvmlite.Int32(pool) + if string.strstr(struct_name, "list[CInt]") is not None: + return llvmlite.Int32(pool) + if string.strstr(struct_name, "list[CInt8T]") is not None: + return llvmlite.Int8(pool) + if string.strstr(struct_name, "list[CInt16T]") is not None: + return llvmlite.Int16(pool) + if string.strstr(struct_name, "list[CInt32T]") is not None: + return llvmlite.Int32(pool) + if string.strstr(struct_name, "list[CInt64T]") is not None: + return llvmlite.Int64(pool) + if string.strstr(struct_name, "list[CSizeT]") is not None: + return llvmlite.Int64(pool) + if string.strstr(struct_name, "list[CDouble]") is not None: + return llvmlite.Double(pool) + if string.strstr(struct_name, "list[CFloat]") is not None: + return llvmlite.Float(pool) + if string.strstr(struct_name, "list[CChar]") is not None: + return llvmlite.Int8(pool) + # str/bytes/CPtr 等已知指针元素类型 → i8*(元素存储为 8 字节地址) + i8_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + if string.strstr(struct_name, "list[str]") is not None: + return llvmlite.Ptr(pool, i8_ty_d) + if string.strstr(struct_name, "list[bytes]") is not None: + return llvmlite.Ptr(pool, i8_ty_d) + if string.strstr(struct_name, "list[CPtr]") is not None: + return llvmlite.Ptr(pool, i8_ty_d) + # 未知 list[T] 元素类型(如 list[Foo]、list[AST|t.CPtr]):元素存储为 + # 8 字节槽(指针或 8 字节整数),回退 Ptr(i8) 位宽一致(load 8 字节), + # 由 AnnotClassName/特化恢复机制保证语义。禁止 fail-fast(误杀合法 + # 自定义类元素列表的下标访问)。 + return llvmlite.Ptr(pool, i8_ty_d) + # ============================================================ + # list_setitem_inline — 内联生成 list[T] __setitem__ 逻辑 + # + # 直接存储 rhs_val 到元素地址 (coerce 为 i8* 后 store) + # ============================================================ + def list_setitem_inline(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + lm_obj: llvmlite.Value | t.CPtr, + idx_val: llvmlite.Value | t.CPtr, + rhs_val: llvmlite.Value | t.CPtr, + node: ast.AST | t.CPtr = None) -> int: + """内联生成 list __setitem__ 逻辑,返回 0""" + if builder is None or pool is None or lm_obj is None or idx_val is None or rhs_val is None: + return 0 + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + # 加载 __data__ (偏移 0, index 0) + s_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + s_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0) + if s_dpp is None: + return 0 + s_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, s_dpp) + # 加载 __elem_size__ (偏移 32, index 4) + s_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) + s_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4) + if s_epp is None: + return 0 + s_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, s_epp) + if s_data is None or s_esize is None: + return 0 + s_idx_i64: llvmlite.Value | t.CPtr = self.coerce_to_type(builder, idx_val, i64_ty, node) + if s_idx_i64 is None: + return 0 + s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize) + if s_offset is None: + return 0 + s_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s_data, s_offset) + if s_addr is None: + return 0 + # 元素类型 T:从 list 特化类型名解析(list[int]→i32、list[str]→i8*)。 + # 此前固定 i8*(8 字节)store(inttoptr 值)覆盖相邻元素——与 + # CallGenMixin list 内置分支同根因(ListTest pop FAILED expect 30)。 + s_sty: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type_from_value(lm_obj) + s_name: str = None + if s_sty is not None: + s_name = llvmlite.get_struct_name(s_sty) + s_elem_ty: llvmlite.LLVMType | t.CPtr = None + if s_name is not None: + s_elem_ty = self._list_elem_type_from_name(pool, s_name) + if s_elem_ty is None: + s_elem_ty = i8_ptr_ty + s_val_ptr: llvmlite.Value | t.CPtr = self.coerce_to_type(builder, rhs_val, s_elem_ty, node) + if s_val_ptr is None: + return 0 + s_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, s_addr, llvmlite.Ptr(pool, s_elem_ty)) + if s_ep is not None: + llvmlite.build_store(builder, s_val_ptr, s_ep) + return 0 + # ============================================================ + # is_list_subscript — 检查 Subscript 节点是否是 list[T] 类型 + # + # 返回 list 对象指针 (Ptr(list[T])) 或 None + # ============================================================ + def is_list_subscript(self, node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """检查 Subscript 节点是否是 list[T] 类型,返回 list 对象指针或 None""" + if node is None or trans is None: + return None + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + if sub is None or sub.value is None: + return None + if sub.value.kind() != ast.ASTKind.Name: + return None + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) + if nm is None or nm.id is None: + return None + alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id) + if alloca is None or alloca.Ty is None: + return None + if self.is_ptr_type(alloca.Ty) == 0: + return None + pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if pointee is None: + return None + # 检查 pointee 是否是 Ptr(Struct) + inner_ty: llvmlite.LLVMType | t.CPtr = None + match pointee: + case llvmlite.LLVMType.Ptr(it): + inner_ty = it + case _: + return None + if inner_ty is None: + return None + # 检查 inner_ty 是否是 Struct 且名称包含 "list[" + struct_name: str = None + match inner_ty: + case llvmlite.LLVMType.Struct(_, _, sname): + struct_name = sname + case _: + return None + if struct_name is None: + return None + if string.strstr(struct_name, "list[") is None: + return None + # 是 list 类型: load 出 list 对象指针 + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + return llvmlite.build_load(builder, pointee, alloca) + # ============================================================ + # _nonlocal_subscript_ptr - nonlocal 数组/指针的下标元素指针 + # + # 嵌套函数(提升函数)体内访问 nonlocal 变量时,变量的实际存储是 + # 运行时共享堆(env[ni] 存的堆地址),不能 lookup_var 找外层函数 + # alloca(其 SSA 编号属于外层函数,当前函数引用错乱崩溃—— + # ClosureTest2 Test 4 fill() 内 arr[i] 崩溃根因)。 + # 正确路径:从 env 读堆地址(_load_raw_var_ptr)→ bitcast → GEP。 + # ============================================================ + def _nonlocal_subscript_ptr(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr, + nm_id: str, + idx_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: + """nonlocal 数组/指针下标:从 env 读堆地址 → bitcast → GEP,返回元素指针""" + if trans is None or nm_id is None or idx_val is None: + return None + nl_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, nm_id) + if nl_ty is None: + return None + raw_nl: llvmlite.Value | t.CPtr = self.Gen.StmtGenDecl._load_raw_var_ptr(trans, nm_id) + if raw_nl is None: + return None + match nl_ty: + case llvmlite.LLVMType.Array(elem_ty_nl, _cnt_nl): + arr_ptr_nl: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, raw_nl, llvmlite.Ptr(pool, nl_ty)) + if arr_ptr_nl is None: + return None + return llvmlite.build_gep_array( + builder, nl_ty, elem_ty_nl, arr_ptr_nl, + self._zext_index_to_i32(builder, idx_val)) + case llvmlite.LLVMType.Ptr(inner_nl): + arr_ptr_nl2: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, raw_nl, llvmlite.Ptr(pool, nl_ty)) + if arr_ptr_nl2 is None: + return None + return llvmlite.build_gep(builder, inner_nl, arr_ptr_nl2, idx_val) + case _: + arr_ptr_nl3: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, raw_nl, llvmlite.Ptr(pool, nl_ty)) + if arr_ptr_nl3 is None: + return None + return llvmlite.build_gep(builder, nl_ty, arr_ptr_nl3, idx_val) + return None + # ============================================================ + # 翻译下标表达式 Subscript(value, slice, ctx) — ptr[i] / arr[i] + # + # 指针遍历: ptr 是指针变量,load 出指针值后 GEP + load + # 数组遍历: arr 是数组变量,用 alloca 指针做双索引 GEP [0, i] + load + # list[T]: 泛型类不注册 struct,subscript 走 __getitem__ 内联路径 + # ============================================================ + def translate_subscript(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译下标表达式,返回加载的元素值""" + if node is None or builder is None: + return None + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + if sub is None: + return None + + # 翻译索引 + idx_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, sub.slice, None, 0, trans) + if idx_val is None: + return None + + # 如果 value 是 Name,尝试从 alloca 类型推断 + if sub.value is not None and sub.value.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) + if nm.id is not None and trans is not None: + # nonlocal 数组/指针:从 env 读共享堆地址(提升函数内不能 + # lookup_var 外层 alloca——SSA 编号跨函数错乱崩溃) + # 读路径:元素指针 load 出元素值 + if HT.is_nonlocal_name(trans, nm.id) != 0: + nl_ptr_r: llvmlite.Value | t.CPtr = self._nonlocal_subscript_ptr( + builder, pool, trans, nm.id, idx_val) + if nl_ptr_r is not None and nl_ptr_r.Ty is not None: + nl_elem_ty: llvmlite.LLVMType | t.CPtr = nl_ptr_r.Ty.Pointee + if nl_elem_ty is not None: + return llvmlite.build_load(builder, nl_elem_ty, nl_ptr_r) + return None + alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id) + if alloca is not None and alloca.Ty is not None: + if self.is_ptr_type(alloca.Ty) != 0: + pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if pointee is not None: + # 不调用 pointee.kind() 避免跨模块引用 LLVMType.kind 符号 + # 用 match 检查 pointee 类型 + match pointee: + case llvmlite.LLVMType.Array(elem_ty, count): + # 数组遍历: getelementptr [N x elem_ty], ... , i32 0, i32 %idx + elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( + builder, pointee, elem_ty, alloca, + self._zext_index_to_i32(builder, idx_val)) + if elem_ptr is not None: + return llvmlite.build_load(builder, elem_ty, elem_ptr) + return None + case llvmlite.LLVMType.Struct(_fs_v, _fc_v, lsn_v): + # list[T] 值变量(无注解赋值 rhs 返回 list 值, + # 如 parts = s1.split(','):split 的 define 返回 + # %list[str] 结构体值,alloca 直接存 list 对象)。 + # alloca 即 list*,直接走 list 内联 __getitem__ + #(对齐 Ptr(Ptr(list)) 变量路径,修复 parts[0] 崩溃) + if lsn_v is not None: + if string.strstr(lsn_v, "list[") is not None: + elem_addr_v: llvmlite.Value | t.CPtr = \ + self.list_getitem_inline( + builder, pool, alloca, idx_val, node) + if elem_addr_v is not None: + elem_ty_v: llvmlite.LLVMType | t.CPtr = \ + self._list_elem_type_from_name(pool, lsn_v) + if elem_ty_v is not None: + elem_ptr_ty_v: llvmlite.LLVMType | t.CPtr = \ + llvmlite.Ptr(pool, elem_ty_v) + casted_v: llvmlite.Value | t.CPtr = \ + llvmlite.build_bitcast( + builder, elem_addr_v, elem_ptr_ty_v) + if casted_v is not None: + return llvmlite.build_load( + builder, elem_ty_v, casted_v) + return None + case llvmlite.LLVMType.Ptr(inner_ty): + # 检查 inner_ty 是否是 list[T] 类型(泛型类不注册 struct) + # list 的 subscript 应该走 __getitem__ 内联路径,而非指针遍历 + list_struct_name: str = None + match inner_ty: + case llvmlite.LLVMType.Struct(_, _, lsn): + list_struct_name = lsn + case _: + pass + if list_struct_name is not None: + if string.strstr(list_struct_name, "list[") is not None: + # list[T] 类型: 内联生成 __getitem__ 逻辑 + ptr_val_list: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if ptr_val_list is not None: + elem_addr_list: llvmlite.Value | t.CPtr = self.list_getitem_inline( + builder, pool, ptr_val_list, idx_val, node) + if elem_addr_list is not None: + # 根据类型名提取元素类型,bitcast 后 load + elem_ty_list: llvmlite.LLVMType | t.CPtr = self._list_elem_type_from_name( + pool, list_struct_name) + if elem_ty_list is not None: + elem_ptr_ty_list: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, elem_ty_list) + casted_addr_list: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, elem_addr_list, elem_ptr_ty_list) + if casted_addr_list is not None: + return llvmlite.build_load( + builder, elem_ty_list, casted_addr_list) + return None + # inner_ty 是 Ptr 说明 alloca.Ty 是三重指针 Ptr(Ptr(Ptr(...))), + # 即 X|t.CPtr 当 X 本身是指针类型 (如 T=AST|t.CPtr, T|t.CPtr=AST**)。 + # 此时 [i] 应该是指针解引用 (步长 sizeof(ptr)=8), 而非调用 + # 结构体的 __getitem__ 方法 (会错误生成 AST.__getitem__ 调用)。 + # 对比 HashTable|t.CPtr: alloca.Ty=HashTable**, inner_ty=Struct(HashTable) + # (非 Ptr), 仍走下面的方法调用转发路径。 + if self.is_ptr_type(inner_ty) != 0: + ptr_val_pp: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if ptr_val_pp is not None: + elem_ptr_pp: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, inner_ty, ptr_val_pp, idx_val) + if elem_ptr_pp is not None: + return llvmlite.build_load(builder, inner_ty, elem_ptr_pp) + return None + # 自定义结构体 (如 HashTable|t.CPtr, JsonValue|t.CPtr): + # 仅当类定义了 __getitem__(当前模块定义或跨模块 stub declare 注入) + # 才转发方法调用;否则普通结构体指针按下标做 GEP 数组访问 + # (对齐 TPC _HandleSubscriptLlvm: if ClassName and has_function(__getitem__)) + cls_nm_rd_ptr: str = self._get_custom_struct_cls_nm(pool, inner_ty) + if not (cls_nm_rd_ptr is None): + gi_lookup_rd: str = pool.alloc(128) + if gi_lookup_rd is not None: + viperlib.snprintf(gi_lookup_rd, 128, "%s.__getitem__", cls_nm_rd_ptr) + if self.Gen.CallGenBase.find_func_in_module(mod, gi_lookup_rd) is not None: + obj_ptr_rd: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if not (obj_ptr_rd is None): + arg_vals_rd_p: t.CSizeT | t.CPtr = pool.alloc(8) + if not (arg_vals_rd_p is None): + arg_vals_rd_p[0] = t.CSizeT(idx_val) + ret_rd_p: llvmlite.Value | t.CPtr = self.Gen.CallGenCall._call_method_on_ptr( + pool, builder, mod, cls_nm_rd_ptr, "__getitem__", + obj_ptr_rd, arg_vals_rd_p, 1, trans, sub) + if not (ret_rd_p is None): + return ret_rd_p + # 无 __getitem__:结构体指针数组访问(GEP + load) + ptr_val_rd_g: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if ptr_val_rd_g is not None: + elem_rd_g: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, inner_ty, ptr_val_rd_g, idx_val) + if elem_rd_g is not None: + return llvmlite.build_load(builder, inner_ty, elem_rd_g) + return None + # bytes|t.CPtr / str|t.CPtr: alloca 是 i8**, + # 直接 GEP 按 i8* 步长(8 字节),load i8* + # 仅当 inner_ty 不是自定义结构体时才走指针遍历 + if trans is not None: + ve_pe_ts: GenTypes.VarEntry | t.CPtr = \ + self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id) + if ve_pe_ts is not None and ve_pe_ts.IsPtrElement == 1: + # bytes|t.CPtr / str|t.CPtr / T|t.CPtr:变量存指针值(i8*), + # elem[i] 语义 = load [指针值 + i*8](8 字节指针元素)。 + # 必须先 load alloca 得指针值,再 GEP i8*(步长 8)—— + # 否则 GEP base 用 alloca(&elem_ptr)读到栈变量而非数据区, + # list.get 返回"元素地址"而非"元素值"(dump 虚调用读错 vtable)。 + ptr_val_pe_ts: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if ptr_val_pe_ts is not None: + elem_ptr_ts: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, pointee, ptr_val_pe_ts, idx_val) + if elem_ptr_ts is not None: + return llvmlite.build_load(builder, pointee, elem_ptr_ts) + return None + # 普通指针遍历: 先 load 指针值,再 GEP + ptr_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if ptr_val is not None: + elem_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, inner_ty, ptr_val, idx_val) + if elem_ptr2 is not None: + return llvmlite.build_load(builder, inner_ty, elem_ptr2) + return None + case _: + # 联合类型变量(IsPtrElement=1,如 _list.vp 的 + # elem_ptr: T | t.CPtr 退化为 i8*):pointee=i8 但 + # 元素是 8 字节指针,须按 i8* 步长 GEP + load i8*—— + # 否则 list.get 只读 1 字节,指针截断 inttoptr 崩溃。 + if trans is not None: + ve_pe_rd: GenTypes.VarEntry | t.CPtr = \ + self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id) + if ve_pe_rd is not None and ve_pe_rd.IsPtrElement == 1: + match pointee: + case llvmlite.LLVMType.Int8(): + i8_ptr_rd: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + elem_ptr_rd: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i8_ptr_rd, alloca, idx_val) + if elem_ptr_rd is not None: + return llvmlite.build_load( + builder, i8_ptr_rd, elem_ptr_rd) + case _: + pass + # 自定义类(结构体类型): 仅当类定义了 __getitem__ + # (当前模块定义或跨模块 stub declare 注入)才转发方法调用; + # 否则普通结构体指针按下标做 GEP 数组访问 + cls_nm_sub: str = self.Gen.StructGen.get_class_name_by_type(pool, pointee) + if not (cls_nm_sub is None): + gi_lookup_sub: str = pool.alloc(128) + if gi_lookup_sub is not None: + viperlib.snprintf(gi_lookup_sub, 128, "%s.__getitem__", cls_nm_sub) + if self.Gen.CallGenBase.find_func_in_module(mod, gi_lookup_sub) is not None: + obj_val_sub: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if not (obj_val_sub is None): + arg_vals_sub: t.CSizeT | t.CPtr = pool.alloc(8) + if not (arg_vals_sub is None): + arg_vals_sub[0] = t.CSizeT(idx_val) + ret_sub: llvmlite.Value | t.CPtr = self.Gen.CallGenCall._call_method_on_ptr( + pool, builder, mod, cls_nm_sub, "__getitem__", + obj_val_sub, arg_vals_sub, 1, trans, sub) + if not (ret_sub is None): + return ret_sub + # 无 __getitem__:结构体指针数组访问(GEP + load) + ptr_val_sub_g: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if ptr_val_sub_g is not None: + elem_sub_g: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, pointee, ptr_val_sub_g, idx_val) + if elem_sub_g is not None: + return llvmlite.build_load(builder, pointee, elem_sub_g) + return None + pass + + # 通用路径:翻译 value 获取指针 + ptr_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, sub.value, None, 0, trans) + if ptr_val is None or ptr_val.Ty is None: + return None + + # 检查是否是指针类型 + if self.is_ptr_type(ptr_val.Ty) != 0: + elem_ty2: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee + if elem_ty2 is not None: + # 数组类型: 双索引 GEP + load 元素 + match elem_ty2: + case llvmlite.LLVMType.Array(arr_elem_ty2, arr_count2): + elem_ptr3: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( + builder, elem_ty2, arr_elem_ty2, ptr_val, + self._zext_index_to_i32(builder, idx_val)) + if elem_ptr3 is not None: + return llvmlite.build_load(builder, arr_elem_ty2, elem_ptr3) + return None + case _: + pass + # 自定义结构体 (如 self._ht[key]): 仅当类定义了 __getitem__ 才转发方法调用; + # 否则普通结构体指针按下标做 GEP 数组访问 + cls_nm_rd_gen: str = self._get_custom_struct_cls_nm(pool, elem_ty2) + if not (cls_nm_rd_gen is None): + gi_lookup_gen: str = pool.alloc(128) + if gi_lookup_gen is not None: + viperlib.snprintf(gi_lookup_gen, 128, "%s.__getitem__", cls_nm_rd_gen) + if self.Gen.CallGenBase.find_func_in_module(mod, gi_lookup_gen) is not None: + arg_vals_rd_g: t.CSizeT | t.CPtr = pool.alloc(8) + if not (arg_vals_rd_g is None): + arg_vals_rd_g[0] = t.CSizeT(idx_val) + ret_rd_g: llvmlite.Value | t.CPtr = self.Gen.CallGenCall._call_method_on_ptr( + pool, builder, mod, cls_nm_rd_gen, "__getitem__", + ptr_val, arg_vals_rd_g, 1, trans, sub) + if not (ret_rd_g is None): + return ret_rd_g + # 无 __getitem__:结构体指针数组访问(GEP + load) + elem_ptr_gen: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, elem_ty2, ptr_val, idx_val) + if elem_ptr_gen is not None: + return llvmlite.build_load(builder, elem_ty2, elem_ptr_gen) + return None + # 指针类型: 单索引 GEP + load + elem_ptr4: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, elem_ty2, ptr_val, idx_val) + if elem_ptr4 is not None: + return llvmlite.build_load(builder, elem_ty2, elem_ptr4) + return None + # ============================================================ + # 获取下标表达式的元素指针(不加载值,用于赋值) + # ============================================================ + def get_subscript_ptr(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """获取下标表达式的元素指针(用于赋值 lhs)""" + if node is None or builder is None: + return None + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + if sub is None: + return None + + # 翻译索引 + idx_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, sub.slice, None, 0, trans) + if idx_val is None: + return None + + # 如果 value 是 Name,尝试从 alloca 类型推断 + if sub.value is not None and sub.value.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) + if nm.id is not None and trans is not None: + # nonlocal 数组/指针:从 env 读共享堆地址(提升函数内不能 + # lookup_var 外层 alloca——SSA 编号跨函数错乱崩溃) + if HT.is_nonlocal_name(trans, nm.id) != 0: + return self._nonlocal_subscript_ptr( + builder, pool, trans, nm.id, idx_val) + alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id) + if alloca is not None and alloca.Ty is not None: + if self.is_ptr_type(alloca.Ty) != 0: + pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if pointee is not None: + # 用 match 检查 pointee 类型 + match pointee: + case llvmlite.LLVMType.Array(elem_ty, count): + # 数组遍历 + return llvmlite.build_gep_array( + builder, pointee, elem_ty, alloca, + self._zext_index_to_i32(builder, idx_val)) + case llvmlite.LLVMType.Ptr(inner_ty): + # inner_ty 是 Ptr 说明 alloca.Ty 是三重指针, + # 即 X|t.CPtr 当 X 本身是指针类型 (如 T=AST|t.CPtr, T|t.CPtr=AST**)。 + # 此时 [i]=val 应该是指针解引用赋值, 而非调用 __setitem__。 + if self.is_ptr_type(inner_ty) != 0: + ptr_val_gsp: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if ptr_val_gsp is not None: + return llvmlite.build_gep( + builder, inner_ty, ptr_val_gsp, idx_val) + return None + # 自定义结构体 (如 HashTable|t.CPtr, JsonValue|t.CPtr): + # 仅当类定义了 __setitem__(当前模块定义或跨模块 stub declare 注入) + # 才返回 None 触发 __setitem__ 重载;否则普通结构体指针按下标 + # 做 GEP 数组访问(走下方指针遍历路径) + cls_nm_ptr_chk: str = self._get_custom_struct_cls_nm(pool, inner_ty) + if not (cls_nm_ptr_chk is None): + si_lookup_gsp: str = pool.alloc(128) + if si_lookup_gsp is not None: + viperlib.snprintf(si_lookup_gsp, 128, "%s.__setitem__", cls_nm_ptr_chk) + if self.Gen.CallGenBase.find_func_in_module(mod, si_lookup_gsp) is not None: + return None + # bytes|t.CPtr / str|t.CPtr: alloca 是 i8**, + # 直接 GEP 按 i8* 步长(8 字节),不 load + # 仅当 inner_ty 不是自定义结构体时才走指针遍历 + if trans is not None: + ve_pe: GenTypes.VarEntry | t.CPtr = \ + self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id) + if ve_pe is not None and ve_pe.IsPtrElement == 1: + # bytes|t.CPtr / str|t.CPtr / T|t.CPtr:变量存指针值, + # 下标语义 = [指针值 + i*8](8 字节指针元素)。必须先 load + # alloca 得指针值,再 GEP——否则 GEP base 用 alloca(&elem_ptr) + # 读到栈变量而非数据区,赋值写不进 list 数据 + # (data 全 0xbaadf00d,dump 虚调用读错 vtable 崩溃)。 + ptr_val_pe: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if ptr_val_pe is not None: + match pointee: + case llvmlite.LLVMType.Int8(): + i8_ptr_pe: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + return llvmlite.build_gep( + builder, i8_ptr_pe, ptr_val_pe, idx_val) + case _: + pass + return llvmlite.build_gep( + builder, pointee, ptr_val_pe, idx_val) + return None + # 普通指针遍历: 先 load 指针值,再 GEP + ptr_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if ptr_val is None: + return None + gep_r: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, inner_ty, ptr_val, idx_val) + return gep_r + case _: + # pointee 是普通标量类型 (如 i64, i32, i8): + # alloca 是 Ptr(标量), 直接 GEP 获取第 idx 个元素指针 + # 支持 arg_vals[i] = val 这类参数数组下标赋值 + # 联合类型变量(IsPtrElement=1,如 _list.vp 的 + # elem_ptr: T | t.CPtr 退化为 i8*):pointee=i8 但 + # 元素是 8 字节指针,须按 i8* 步长 GEP(防只写 1 字节截断) + if trans is not None: + ve_pe_cs: GenTypes.VarEntry | t.CPtr = \ + self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id) + if ve_pe_cs is not None and ve_pe_cs.IsPtrElement == 1: + # T|t.CPtr(退化为 i8*,如 _list.vp 的 elem_ptr)变量 + # 存数据区指针,元素为 8 字节指针:必须先 load alloca + # 得指针值,再按 i8* 步长 GEP——否则 GEP base 用 alloca + # (&elem_ptr)算到栈地址,赋值写不进 list 数据区 + # (append 只增 count、data 全 0xbaadf00d)。 + ptr_val_cs: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if ptr_val_cs is not None: + match pointee: + case llvmlite.LLVMType.Int8(): + i8_ptr_cs: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + return llvmlite.build_gep( + builder, i8_ptr_cs, ptr_val_cs, idx_val) + case _: + pass + return llvmlite.build_gep( + builder, pointee, ptr_val_cs, idx_val) + return None + return llvmlite.build_gep(builder, pointee, alloca, idx_val) + + # 通用路径 + ptr_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, sub.value, None, 0, trans) + if ptr_val is None or ptr_val.Ty is None: + return None + if self.is_ptr_type(ptr_val.Ty) != 0: + elem_ty2: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee + if elem_ty2 is not None: + # 数组类型: 双索引 GEP (getelementptr [N x ty], ptr, i32 0, i32 idx) + match elem_ty2: + case llvmlite.LLVMType.Array(arr_elem_ty, arr_count): + return llvmlite.build_gep_array( + builder, elem_ty2, arr_elem_ty, ptr_val, + self._zext_index_to_i32(builder, idx_val)) + case _: + pass + # 自定义结构体 (如 self._ht[key]): 仅当类定义了 __setitem__ + # 才返回 None 触发 HandlesAssign 的 __setitem__ 重载; + # 否则普通结构体指针按下标做 GEP 数组访问 + cls_nm_gen: str = self._get_custom_struct_cls_nm(pool, elem_ty2) + if not (cls_nm_gen is None): + si_lookup_gen: str = pool.alloc(128) + if si_lookup_gen is not None: + viperlib.snprintf(si_lookup_gen, 128, "%s.__setitem__", cls_nm_gen) + if self.Gen.CallGenBase.find_func_in_module(mod, si_lookup_gen) is not None: + return None + # 指针类型: 单索引 GEP (getelementptr ty, ptr, idx) + return llvmlite.build_gep(builder, elem_ty2, ptr_val, idx_val) return None \ No newline at end of file diff --git a/App/lib/core/Gen/ExprGenOps.vp b/App/lib/core/Gen/ExprGenOps.vp index b5a0666..98e6e7b 100644 --- a/App/lib/core/Gen/ExprGenOps.vp +++ b/App/lib/core/Gen/ExprGenOps.vp @@ -1,1232 +1,1223 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import viperlib -import w32.fileio as fileio -import lib.core.CompilerFactory as CompilerFactory -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.VLogger as VLogger -import lib.Projectrans.Config as Config -import lib.Projectrans.Utils as Utils - - -import lib.core.Gen.ExprGenBase as ExprGenBase -import lib.core.Handles.ExprCallBase as ExprCallBase -import lib.core.Handles.ExprCallCtor as ExprCallCtor - -# ============================================================ -# ExprGenOps - ExprGenMixin 拆分(阶段 D):比较/一元/布尔/binop 运算 -# -# 继承 ExprGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class ExprGenOps(ExprGenBase.ExprGenBase): - """比较/一元/布尔/binop 运算""" - - # ============================================================ - # 翻译三元表达式 IfExp(test, body, orelse) - # - # 生成: cond ? body : orelse - # then_blk: 翻译 body → br merge - # else_blk: 翻译 orelse → br merge - # merge_blk: phi [body_val, then_blk], [orelse_val, else_blk] - # ============================================================ - def translate_ifexp(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译三元表达式 (body if test else orelse),返回 phi 结果 Value""" - if node is None or builder is None or trans is None: - return None - ie: ast.IfExp | t.CPtr = (ast.IfExp | t.CPtr)(node) - if ie is None: - return None - - func: llvmlite.Function | t.CPtr = trans._cur_func - if func is None: - return None - - # 1. 求值条件 - cond_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, ie.test, None, 0, trans) - if cond_val is None: - return None - # 转换为 i1 - cond_bits: int = self.get_llvm_type_bits(cond_val.Ty) - if cond_bits == 1: - cond_i1: llvmlite.Value | t.CPtr = cond_val - else: - if self.is_ptr_type(cond_val.Ty) != 0: - # 指针类型:与 null 比较 - null_cond: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cond_val.Ty, "null") - cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, null_cond) - else: - zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, zero) - - # 2. 创建三个基本块 - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - name_buf: str = pool.alloc(32) - if name_buf is None: - return None - viperlib.snprintf(name_buf, 32, "ifexp.then.%d", cnt) - then_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - viperlib.snprintf(name_buf, 32, "ifexp.else.%d", cnt) - else_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - viperlib.snprintf(name_buf, 32, "ifexp.merge.%d", cnt) - merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - if then_bb is None or else_bb is None or merge_bb is None: - return None - - # 3. 条件跳转 - llvmlite.build_cond_br(builder, cond_i1, then_bb, else_bb) - - # 4. then 分支 - llvmlite.position_at_end(builder, then_bb) - body_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, ie.body, None, 0, trans) - then_blk_for_phi: llvmlite.BasicBlock | t.CPtr = trans._cur_builder.CurBlock - if body_val is None: - # fail-fast:三元表达式 then 分支翻译失败,立即终止编译(暴露上游根因) - HandlesType.fatal_error(ie.body, "三元表达式分支翻译失败", "TypeError") - # 暂不 br,等类型对齐后再 br - - # 5. else 分支 - llvmlite.position_at_end(builder, else_bb) - orelse_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, ie.orelse, None, 0, trans) - else_blk_for_phi: llvmlite.BasicBlock | t.CPtr = trans._cur_builder.CurBlock - if orelse_val is None: - # fail-fast:三元表达式 else 分支翻译失败,立即终止编译(暴露上游根因) - HandlesType.fatal_error(ie.orelse, "三元表达式分支翻译失败", "TypeError") - # 暂不 br,等类型对齐后再 br - - # 类型对齐 (两分支类型可能不同) - # 必须在各自分支中执行 coerce_to_type,确保 merge 块中 PHI 是第一条指令 - # (否则 coerce_to_type 生成的 sext/zext/ptrtoint/inttoptr 指令在 PHI 之前,违反 LLVM 规则) - body_bits: int = self.get_llvm_type_bits(body_val.Ty) - orelse_bits: int = self.get_llvm_type_bits(orelse_val.Ty) - body_is_ptr: int = self.is_ptr_type(body_val.Ty) - orelse_is_ptr: int = self.is_ptr_type(orelse_val.Ty) - # 情况0: 一侧是指针,另一侧是整数(如 i64 vs i8* null) - # 必须优先处理,因为 Ptr 的 bits=0 会导致下面三个分支全部跳过 - # 选择 body_val.Ty 作为 phi_ty(then 分支优先),orelse_val 对齐到它 - # coerce_to_type 内部会调用 ptrtoint(指针→整数)或 inttoptr(整数→指针) - if body_is_ptr != orelse_is_ptr: - llvmlite.position_at_end(builder, else_blk_for_phi) - orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node) - elif body_bits > orelse_bits and orelse_bits > 0: - # 在 else 块中转换 orelse_val - llvmlite.position_at_end(builder, else_blk_for_phi) - orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node) - elif orelse_bits > body_bits and body_bits > 0: - # 回到 then 块转换 body_val - llvmlite.position_at_end(builder, then_blk_for_phi) - body_val = self.coerce_to_type(builder, body_val, orelse_val.Ty, node) - elif body_bits == orelse_bits and body_bits > 0: - # bits 相同但类型不同(如 i64 vs Ptr):null 不能用于 i64 PHI - # 此分支理论上不会触发(已被情况0覆盖),保留作为防御 - if self.is_ptr_type(body_val.Ty) != self.is_ptr_type(orelse_val.Ty): - llvmlite.position_at_end(builder, else_blk_for_phi) - orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node) - - # 现在分别在 then/else 块中 br 到 merge(在类型转换之后) - llvmlite.position_at_end(builder, then_blk_for_phi) - llvmlite.build_br(builder, merge_bb) - llvmlite.position_at_end(builder, else_blk_for_phi) - llvmlite.build_br(builder, merge_bb) - - # 6. merge 块: phi(PHI 是 merge 块的第一条指令) - llvmlite.position_at_end(builder, merge_bb) - - phi_ty: llvmlite.LLVMType | t.CPtr = body_val.Ty - if phi_ty is None: - # fail-fast:三元表达式分支类型缺失,立即终止编译(暴露上游根因) - HandlesType.fatal_error(node, "三元表达式分支类型缺失", "TypeError") - - inc1: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming( - pool, body_val, then_blk_for_phi) - inc2: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming( - pool, orelse_val, else_blk_for_phi) - if inc1 is None or inc2 is None: - return None - # 链表顺序: inc1 (head) -> inc2 (tail) - # 之前错误写成 inc2.Next = inc1,导致 build_phi 从 inc1 遍历时 - # inc1.Next 为 None,只输出一个 phi 条目,引发 LLVM 验证错误: - # "PHINode should have one entry for each predecessor" - inc1.Next = inc2 - return llvmlite.build_phi(builder, phi_ty, inc1, 2) - # ============================================================ - # 翻译比较表达式 Compare(left, ops, comparators) - # ============================================================ - def should_zext_widen(self, pool: memhub.MemBuddy | t.CPtr, - narrow_val: llvmlite.Value | t.CPtr, - wide_val: llvmlite.Value | t.CPtr, - narrow_node: ast.AST | t.CPtr = None) -> int: - """判断整数拓宽方向:1=zext(无符号语义),0=sext - - 对齐 TPC 的 _check_node_unsigned / HandlesExprOps 拓宽规则: - 1. i1 (bool) → zext(1 保持 1,而非 sext 的 0xFF...) - 2. i8 → zext(系统编程中 i8 几乎总是无符号字节) - 3. 宽侧是常量且其值超出窄侧位宽的有符号范围 → zext - (常量"想要"无符号解释,如 0xAABBCCDD > INT32_MAX 与 - t.CUInt32T 值比较,sext 会把 0xAABBCCDD 变成 - 0xFFFFFFFFAABBCCDD 导致恒不等) - """ - if narrow_val is None or narrow_val.Ty is None: - return 0 - narrow_bits: int = self.get_llvm_type_bits(narrow_val.Ty) - if narrow_bits == 1: - return 1 - if narrow_bits == 8: - return 1 - # 宽侧常量启发式 - if wide_val is not None and wide_val.IsConst == 1: - wide_bits: int = self.get_llvm_type_bits(wide_val.Ty) - if wide_bits > narrow_bits and narrow_bits < 64: - signed_max: t.CInt64T = (t.CInt64T(1) << (narrow_bits - 1)) - 1 - if wide_val.IntVal > signed_max: - return 1 - # 窄侧 AST 节点解析为无符号类型(如 t.CUIntXXT 字面量/强转) - if narrow_node is not None: - if self._node_type_unsigned(pool, narrow_node) != 0: - return 1 - return 0 - def _node_type_unsigned(self, pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> int: - """轻量判断 AST 节点是否解析为无符号整数类型(1=是,0=否/未知) - - 覆盖常见形态(对齐 TPC _check_node_unsigned 的 Call/Subscript 分支): - - t.CUInt8T/CUInt16T/CUInt32T/CUInt64T/CUnsigned* 等显式无符号类型强转调用 - - 无符号类型名的 Name 引用(如 UInt32T 别名) - - 变量名(trans 可用时):查询 SymTab 中变量的 AnnotClassName(如 v: t.CUInt32T) - """ - if node is None: - return 0 - k: int = node.kind() - if k == ast.ASTKind.Call: - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - 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 and string.strcmp(mod_nm.id, "t") == 0 \ - and at.attr is not None: - if self._type_name_unsigned(at.attr) != 0: - return 1 - return 0 - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm.id is not None: - # 1) 名字本身是无符号类型名(如 UInt32T 别名) - if self._type_name_unsigned(nm.id) != 0: - return 1 - # 2) 变量注解类型为无符号类型(trans 可用时查 SymTab) - if trans is not None: - ve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm.id) - if ve is not None and ve.AnnotClassName is not None: - if self._type_name_unsigned(ve.AnnotClassName) != 0: - return 1 - return 0 - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - if self._node_type_unsigned(pool, bop.left, trans) != 0: - return 1 - if self._node_type_unsigned(pool, bop.right, trans) != 0: - return 1 - return 0 - if k == ast.ASTKind.UnaryOp: - uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) - if self._node_type_unsigned(pool, uop.operand, trans) != 0: - return 1 - return 0 - if k == ast.ASTKind.Subscript: - # 数组/指针下标: md5_buf[i](t.CArray[t.CUInt8T, N])或 buf[i] - # (形参 t.CUInt8T | t.CPtr)元素是无符号整型 → printf("%02x", ...) zext。 - sub_su: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - if sub_su.value is not None and sub_su.value.kind() == ast.ASTKind.Name: - snm_su: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_su.value) - if snm_su.id is not None and trans is not None: - ve_su: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, snm_su.id) - if ve_su is not None and ve_su.AnnotClassName is not None: - if self._annot_str_unsigned(ve_su.AnnotClassName) != 0: - return 1 - return 0 - return 0 - def _type_name_unsigned(self, type_name: str) -> int: - """类型名是否为无符号整数类型(精确匹配,避免子串误伤如 nUIntCount)""" - if type_name is None: - return 0 - # t.CUIntXXT 形式 - if string.strcmp(type_name, "CUInt8T") == 0: return 1 - if string.strcmp(type_name, "CUInt16T") == 0: return 1 - if string.strcmp(type_name, "CUInt32T") == 0: return 1 - if string.strcmp(type_name, "CUInt64T") == 0: return 1 - # stdint 裸别名(from stdint import *) - if string.strcmp(type_name, "UInt8T") == 0: return 1 - if string.strcmp(type_name, "UInt16T") == 0: return 1 - if string.strcmp(type_name, "UInt32T") == 0: return 1 - if string.strcmp(type_name, "UInt64T") == 0: return 1 - # CUnsigned* 形式 - if string.strcmp(type_name, "CUnsignedChar") == 0: return 1 - if string.strcmp(type_name, "CUnsignedShort") == 0: return 1 - if string.strcmp(type_name, "CUnsignedInt") == 0: return 1 - if string.strcmp(type_name, "CUnsignedLong") == 0: return 1 - if string.strcmp(type_name, "CUnsignedLongLong") == 0: return 1 - # 常见无符号别名 - if string.strcmp(type_name, "BYTE") == 0: return 1 - if string.strcmp(type_name, "UCHAR") == 0: return 1 - if string.strcmp(type_name, "USHORT") == 0: return 1 - if string.strcmp(type_name, "UINT") == 0: return 1 - if string.strcmp(type_name, "ULONG") == 0: return 1 - return 0 - def _annot_str_unsigned(self, annot: str) -> int: - """检查类型注解字符串是否引用无符号整型(子串扫描) - - 用于复合注解(t.CArray[t.CUInt8T, 16] / t.CUInt8T | t.CPtr), - _type_name_unsigned 的精确匹配对这类串不适用。 - """ - if annot is None: - return 0 - if string.strstr(annot, "CUInt8T") is not None: return 1 - if string.strstr(annot, "CUInt16T") is not None: return 1 - if string.strstr(annot, "CUInt32T") is not None: return 1 - if string.strstr(annot, "CUInt64T") is not None: return 1 - if string.strstr(annot, "CUnsigned") is not None: return 1 - if string.strstr(annot, "BYTE") is not None: return 1 - if string.strstr(annot, "UCHAR") is not None: return 1 - if string.strstr(annot, "USHORT") is not None: return 1 - if string.strstr(annot, "UINT") is not None: return 1 - if string.strstr(annot, "ULONG") is not None: return 1 - return 0 - def translate_compare(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译比较表达式,返回 i1 结果""" - cmp: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) - if cmp is None: - return None - - ops_list: list[t.CInt] | t.CPtr = (list[t.CInt] | t.CPtr)(cmp.ops) - if ops_list is None or len(ops_list) == 0: - return None - op: int = ops_list.get(0) - - comparators: list[ast.AST | t.CPtr] | t.CPtr = cmp.comparators - if comparators is None or len(comparators) == 0: - return None - rhs_node: ast.AST | t.CPtr = comparators.get(0) - rhs: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, rhs_node, None, 0, trans) - if rhs is None: - return None - - # === None 比较优化: x == None / x != None 走身份比较(icmp eq/ne null)=== - # 避免对结构体指针生成无效的 __eq__/__ne__ 调用(方法未定义但类有 SHA1 时 - # try_operator_overload 会误生成 call void @...__eq__(...) 导致链接错误) - # 语义依据: Python 中 == None / != None 默认走身份比较,不调用 __eq__/__ne__ - lhs_node: ast.AST | t.CPtr = cmp.left - cmp_with_none: int = 0 - if op == ast.OpKind.Eq or op == ast.OpKind.Ne or op == ast.OpKind.Is or op == ast.OpKind.IsNot: - if rhs_node is not None and rhs_node.kind() == ast.ASTKind.Constant: - rhs_cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(rhs_node) - if rhs_cn is not None and rhs_cn.const_kind == ast.CONST_NONE: - cmp_with_none = 1 - if cmp_with_none == 0 and lhs_node is not None and lhs_node.kind() == ast.ASTKind.Constant: - lhs_cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(lhs_node) - if lhs_cn is not None and lhs_cn.const_kind == ast.CONST_NONE: - cmp_with_none = 1 - - # === 指针判空模式: ptr != 0 / ptr == 0 === - # 跳过运算符重载走身份比较(icmp null)。跨模块类(如 cpython.PyObject) - # 未定义 __eq__/__ne__ 时,try_operator_overload 无法判定方法不存在 - # (类在依赖模块,cls_sha1 != trans.ModuleSha1),会误发幽灵 - # `call void @...__ne__` → 链接 undefined reference(CPythonTest main.vp - # `py_num != 0` 根因)。C 语义:指针与字面量 0 比较 = 判空。 - cmp_zero: int = 0 - if op == ast.OpKind.Eq or op == ast.OpKind.Ne: - if rhs_node is not None and self._is_zero_int_literal(rhs_node) != 0: - cmp_zero = 1 - if cmp_zero == 0 and lhs_node is not None and self._is_zero_int_literal(lhs_node) != 0: - cmp_zero = 1 - - # === 比较运算符重载路径 1: lhs 是 Name 且对应结构体变量 === - # 对于值类型变量(如 cnt: Counter),用 alloca 指针尝试重载 - # None 比较跳过重载(走身份比较) - if cmp_with_none == 0 and lhs_node is not None and lhs_node.kind() == ast.ASTKind.Name and trans is not None: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(lhs_node) - if nm is not None and nm.id is not None: - lhs_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, nm.id) - if lhs_alloca is not None: - if cmp_zero == 0 or self.get_ptr_level(lhs_alloca.Ty) == 0: - ovl_self1: llvmlite.Value | t.CPtr = lhs_alloca - # Ptr(Ptr(Struct)) 对象存储槽:load 出对象指针作 self - # (与 translate_binop 路径 1 一致,避免槽地址当对象地址) - if lhs_alloca.Ty is not None and lhs_alloca.Ty.Pointee is not None \ - and HandlesExpr.is_ptr_type(lhs_alloca.Ty.Pointee) != 0: - load_self1: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, lhs_alloca.Ty.Pointee, lhs_alloca) - if load_self1 is not None: - ovl_self1 = load_self1 - ovl_result: llvmlite.Value | t.CPtr = self.try_operator_overload( - pool, builder, mod, ovl_self1, rhs, op, trans, 1) - if ovl_result is not None: - return ovl_result - - # 正常翻译 lhs - lhs: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cmp.left, None, 0, trans) - if lhs is None: - return None - - # === in / not in:容器右操作数调用 __contains__(对齐 TPC - # HandlesExprOps.py L261-281)。x in y → y.__contains__(x); - # x not in y → !y.__contains__(x)。容器无 __contains__ → - # 返回 i1 0(TPC 同:恒 False)。 - if op == ast.OpKind.In or op == ast.OpKind.NotIn: - cn_st: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(rhs) - if cn_st is not None: - cn_cls: str = HandlesStruct.get_class_name_by_type(pool, cn_st) - if cn_cls is not None: - cn_lookup: str = pool.alloc(128) - if cn_lookup is not None: - viperlib.snprintf(cn_lookup, 128, "%s.__contains__", cn_cls) - cn_fn: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module( - mod, cn_lookup) - if cn_fn is not None: - cn_ret: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(cn_fn) - cn_fn_name: str = llvmlite.function_get_name(cn_fn) - if cn_ret is not None and cn_fn_name is not None: - # self 参数(容器)按 __contains__ 首参类型对齐 - cn_self: llvmlite.Value | t.CPtr = rhs - cn_first: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(cn_fn) - if cn_first is not None: - cn_self_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cn_first) - if cn_self_ty is not None: - cn_self = llvmlite.build_bitcast(builder, rhs, cn_self_ty) - if cn_self is not None: - # 参数链表: self → key(独立 null 结尾) - cn_self.Next = lhs - lhs.Next = None - cn_res: llvmlite.Value | t.CPtr = llvmlite.build_call( - builder, cn_fn_name, cn_self, 2, cn_ret, 0) - if cn_res is not None: - # 归一化到 i1(__contains__ 返回 t.CInt/i32 等) - cn_i1: llvmlite.Value | t.CPtr = cn_res - match cn_ret: - case llvmlite.LLVMType.Int(cn_bits): - if cn_bits > 1: - cn_zero: llvmlite.Value | t.CPtr = llvmlite.ConstInt( - pool, cn_ret, 0, "0") - if cn_zero is not None: - cn_i1 = llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, cn_res, cn_zero) - case _: - pass - if op == ast.OpKind.NotIn: - i1_ty_ni: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - if i1_ty_ni is not None and cn_i1 is not None: - one_i1_ni: llvmlite.Value | t.CPtr = llvmlite.ConstInt( - pool, i1_ty_ni, 1, "1") - if one_i1_ni is not None: - cn_i1 = llvmlite.build_xor(builder, cn_i1, one_i1_ni) - if cn_i1 is not None: - return cn_i1 - # 容器无 __contains__:TPC 语义恒 False(i1 0) - i1_ty_in: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - if i1_ty_in is not None: - return llvmlite.ConstInt(pool, i1_ty_in, 0, "0") - return None - - # === 比较运算符重载路径 2: lhs 是 Ptr(Struct) === - # Is/IsNot 不在 _cmpop_to_dunder 映射中,会自动返回 None 回退原生比较 - # None 比较跳过重载(走身份比较);指针判空(cmp_zero + 指针)同样跳过 - if cmp_with_none == 0 and (cmp_zero == 0 or self.get_ptr_level(lhs.Ty) == 0): - ovl_result2: llvmlite.Value | t.CPtr = self.try_operator_overload( - pool, builder, mod, lhs, rhs, op, trans, 1) - if ovl_result2 is not None: - return ovl_result2 - - predicate: int = llvmlite.ICMP_SLT - if op == ast.OpKind.Lt: - predicate = llvmlite.ICMP_SLT - elif op == ast.OpKind.Le: - predicate = llvmlite.ICMP_SLE - elif op == ast.OpKind.Gt: - predicate = llvmlite.ICMP_SGT - elif op == ast.OpKind.Ge: - predicate = llvmlite.ICMP_SGE - elif op == ast.OpKind.Eq: - predicate = llvmlite.ICMP_EQ - elif op == ast.OpKind.Ne: - predicate = llvmlite.ICMP_NE - elif op == ast.OpKind.Is: - # `x is y` → 指针/值相等比较 - predicate = llvmlite.ICMP_EQ - elif op == ast.OpKind.IsNot: - # `x is not y` → 指针/值不等比较 - predicate = llvmlite.ICMP_NE - - # === 类型安全检查(BUG2 修复)=== - # 规则: - # - 数值(0) vs 数值(0) → 允许(无关类型,按位宽 sext 对齐) - # - 一级指针(1) vs 一级指针(1) → 允许(无关 pointee 类型,地址比较) - # - 数值(0) vs 指针(1+) → 禁止(fast-fail,除 None 比较外) - # - 不同级指针(1 vs 2 等) → 禁止(fast-fail) - # - # None 比较跳过此检查(None 被翻译为 null 指针或 0,与任意指针/数值比较合法) - if cmp_with_none == 0: - lhs_ptr_level: int = self.get_ptr_level(lhs.Ty) - rhs_ptr_level: int = self.get_ptr_level(rhs.Ty) - if lhs_ptr_level != rhs_ptr_level: - # 指针 vs 整数字面量 0(判空模式 ptr != 0 / ptr == 0): - # 0 视为 NULL,转成与指针侧同类型的 null 指针(icmp 需要同类型), - # 不报类型不匹配(ClassArrayTest 的 if ptr != 0 等常见模式)。 - zero_is_rhs: int = 0 - zero_is_lhs: int = 0 - if rhs_ptr_level == 0 and self._is_zero_int_literal(rhs_node) != 0: - zero_is_rhs = 1 - if lhs_ptr_level == 0 and self._is_zero_int_literal(lhs_node) != 0: - zero_is_lhs = 1 - if zero_is_rhs != 0 or zero_is_lhs != 0: - if zero_is_rhs != 0: - rhs = llvmlite.ConstNull(pool, lhs.Ty, "null") - else: - lhs = llvmlite.ConstNull(pool, rhs.Ty, "null") - else: - # 指针 vs 非零整数(C 哨兵值模式,如 w32.win32base.INVALID_HANDLE_VALUE = -1): - # 对齐 TPC HandlesExprOps.py L388-398 —— 指针 ptrtoint 成整数做地址值比较。 - # (指针 vs 整数字面量 0 已在上方转 null 处理;此处处理非零整数哨兵) - if lhs_ptr_level != 0 and rhs_ptr_level == 0: - lhs = llvmlite.build_ptrtoint(builder, lhs, rhs.Ty) - elif rhs_ptr_level != 0 and lhs_ptr_level == 0: - rhs = llvmlite.build_ptrtoint(builder, rhs, lhs.Ty) - else: - # 不同级指针(1 vs 2 等)→ 禁止(fast-fail) - HandlesType.fatal_error( - cmp, - f"比较类型不匹配: 不同级指针比较 (lhs 层级={lhs_ptr_level}, rhs 层级={rhs_ptr_level})", - "TypeError") - else: - # None 比较: None 被翻译为 i8* null(一级指针) - # 如果 lhs 是指针,将 rhs (i8* null) bitcast 为 lhs 的指针类型 - # 如果 lhs 是数值,将 rhs 转为数值 0(走正常整数比较) - # 如果 lhs 是结构体值类型,结构体永远不等于 None,返回常量 i1 - lhs_ptr_level_none: int = self.get_ptr_level(lhs.Ty) - rhs_ptr_level_none: int = self.get_ptr_level(rhs.Ty) - if lhs_ptr_level_none != 0 and rhs_ptr_level_none != 0: - # 两边都是指针,类型可能不同(如 lhs=Struct*, rhs=i8* null) - # 由下方 bitcast 对齐处理,此处不处理 - pass - elif lhs_ptr_level_none != 0 and rhs_ptr_level_none == 0: - # lhs 是指针, rhs 是数值 → 将 rhs 转为同层级 null 指针 - rhs = llvmlite.ConstNull(pool, lhs.Ty, "null") - elif rhs_ptr_level_none != 0 and lhs_ptr_level_none == 0: - # 检查 lhs 是否是结构体值类型(非指针的 Struct) - lhs_is_struct_none: int = 0 - match lhs.Ty: - case llvmlite.LLVMType.Struct(_, _, _): - lhs_is_struct_none = 1 - case _: - lhs_is_struct_none = 0 - if lhs_is_struct_none != 0: - # 结构体值永远不等于 None:==/is 返回 false,!=/is not 返回 true - if op == ast.OpKind.Eq or op == ast.OpKind.Is: - return llvmlite.const_int(pool, 1, 0) - else: # Ne, IsNot - return llvmlite.const_int(pool, 1, 1) - # lhs 是数值, rhs 是 i8* null → 将 rhs 转为数值 0(保持 lhs 不变) - rhs = llvmlite.const_int32(pool, 0) - - # 类型对齐:icmp 要求两边类型相同 - # 仅对数值类型做对齐(指针类型无需对齐,LLVM 允许同层级指针直接 icmp) - # i1 (bool) 侧用 zext 对齐(1 保持 1,而非 sext 的 0xFF...) - lhs_bits: int = self.get_llvm_type_bits(lhs.Ty) - rhs_bits: int = self.get_llvm_type_bits(rhs.Ty) - if lhs_bits != 0 and rhs_bits != 0 and lhs_bits != rhs_bits: - if lhs_bits < rhs_bits: - if self.should_zext_widen(pool, lhs, rhs, cmp.left) != 0: - lhs = llvmlite.build_zext(builder, lhs, rhs.Ty) - else: - lhs = llvmlite.build_sext(builder, lhs, rhs.Ty) - else: - if self.should_zext_widen(pool, rhs, lhs, rhs_node) != 0: - rhs = llvmlite.build_zext(builder, rhs, lhs.Ty) - else: - rhs = llvmlite.build_sext(builder, rhs, lhs.Ty) - - # 指针类型对齐:同层级但不同 pointee 类型的指针需要 bitcast 统一类型 - # 例如 i8* vs Struct* → 将 rhs bitcast 为 lhs 的类型 - if lhs_bits == 0 and rhs_bits == 0: - lhs_is_ptr_now: int = self.is_ptr_type(lhs.Ty) - rhs_is_ptr_now: int = self.is_ptr_type(rhs.Ty) - if lhs_is_ptr_now != 0 and rhs_is_ptr_now != 0: - # 两边都是指针,用 TypePrint 比较类型字符串 - lhs_ty_buf: str = pool.alloc(128) - rhs_ty_buf: str = pool.alloc(128) - if lhs_ty_buf is not None and rhs_ty_buf is not None: - llvmlite.TypePrint(lhs_ty_buf, 128, lhs.Ty, pool) - llvmlite.TypePrint(rhs_ty_buf, 128, rhs.Ty, pool) - if string.strcmp(lhs_ty_buf, rhs_ty_buf) != 0: - rhs = llvmlite.build_bitcast(builder, rhs, lhs.Ty) - - # 浮点比较:任一操作数为浮点类型时使用 fcmp 而非 icmp - lhs_fbits: int = self.get_llvm_float_bits(lhs.Ty) - rhs_fbits: int = self.get_llvm_float_bits(rhs.Ty) - if lhs_fbits != 0 or rhs_fbits != 0: - # 浮点类型对齐(fpext/fptrunc) - if lhs_fbits != 0 and rhs_fbits != 0 and lhs_fbits != rhs_fbits: - if lhs_fbits < rhs_fbits: - lhs = llvmlite.build_fpext(builder, lhs, rhs.Ty) - else: - rhs = llvmlite.build_fptrunc(builder, rhs, lhs.Ty) - elif lhs_fbits != 0 and rhs_fbits == 0: - # int → float - rhs = llvmlite.build_si2fp(builder, rhs, lhs.Ty) - elif rhs_fbits != 0 and lhs_fbits == 0: - lhs = llvmlite.build_si2fp(builder, lhs, rhs.Ty) - # 映射比较谓词到 fcmp - fpredicate: int = llvmlite.FCMP_OEQ - if op == ast.OpKind.Eq or op == ast.OpKind.Is: - fpredicate = llvmlite.FCMP_OEQ - elif op == ast.OpKind.Ne or op == ast.OpKind.IsNot: - fpredicate = llvmlite.FCMP_ONE - elif op == ast.OpKind.Lt: - fpredicate = llvmlite.FCMP_OLT - elif op == ast.OpKind.Le: - fpredicate = llvmlite.FCMP_OLE - elif op == ast.OpKind.Gt: - fpredicate = llvmlite.FCMP_OGT - elif op == ast.OpKind.Ge: - fpredicate = llvmlite.FCMP_OGE - return llvmlite.build_fcmp(builder, fpredicate, lhs, rhs) - - return llvmlite.build_icmp(builder, predicate, lhs, rhs) - # ============================================================ - # 翻译一元运算表达式 UnaryOp(op, operand) - # ============================================================ - def translate_unaryop(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译一元运算(-x, +x, not x, ~x)""" - uo: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) - if uo is None: - return None - - operand: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, uo.operand, None, 0, trans) - if operand is None: - return None - - # === 一元运算符重载: -obj/+obj/~obj 调用 __neg__/__pos__/__invert__ === - # 仅 USub/UAdd/Invert 有重载语义(not 无 dunder 方法) - if uo.op == ast.OpKind.USub or uo.op == ast.OpKind.UAdd or uo.op == ast.OpKind.Invert: - ovl_u: llvmlite.Value | t.CPtr = self.try_unary_operator_overload( - pool, builder, mod, operand, uo.op, trans) - if ovl_u is not None: - return ovl_u - - if uo.op == ast.OpKind.USub: - # -x - # 浮点类型用 fneg(直接生成 fneg 指令,避免 0.0 - x 的类型不匹配) - operand_fbits: int = self.get_llvm_float_bits(operand.Ty) - if operand_fbits > 0: - return llvmlite.build_fneg(builder, operand) - # 整数类型:-x = 0 - x,根据位宽选择零值常量(避免 i32 与 i64 类型不匹配) - operand_bits: int = self.get_llvm_type_bits(operand.Ty) - zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - if operand_bits == 64: - zero = llvmlite.const_int64(pool, 0) - elif operand_bits > 0 and operand_bits != 32: - # 其他位宽(i8/i16 等):用 i32 零值,operand 会被 coerce - zero = llvmlite.const_int32(pool, 0) - return llvmlite.build_sub(builder, zero, operand) - elif uo.op == ast.OpKind.UAdd: - # +x = x - return operand - elif uo.op == ast.OpKind.Not: - # not x = (x == 0/null),返回 i1 - if self.is_ptr_type(operand.Ty) != 0: - # 指针类型:与 null 比较 - null_op: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, operand.Ty, "null") - return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, operand, null_op) - # 结构体值类型:永远为真(非空),not 返回 false - operand_is_struct_not: int = 0 - match operand.Ty: - case llvmlite.LLVMType.Struct(_, _, _): - operand_is_struct_not = 1 - case _: - operand_is_struct_not = 0 - if operand_is_struct_not != 0: - return llvmlite.const_int(pool, 1, 0) - operand_bits_not: int = self.get_llvm_type_bits(operand.Ty) - zero = llvmlite.const_int32(pool, 0) - if operand_bits_not == 64: - zero = llvmlite.const_int64(pool, 0) - return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, operand, zero) - elif uo.op == ast.OpKind.Invert: - # ~x = x ^ -1 - operand_bits_inv: int = self.get_llvm_type_bits(operand.Ty) - neg1: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, -1) - if operand_bits_inv == 64: - neg1 = llvmlite.const_int64(pool, -1) - return llvmlite.build_xor(builder, operand, neg1) - return operand - # ============================================================ - # 翻译布尔运算 BoolOp(op, values) — 短路求值,返回 i1 - # - # and: a and b and c → 若 a 为假短路到 merge(返回 a 的 i1),否则求 b, - # 最后一个值直接求值并跳 merge - # or: a or b or c → 若 a 为真短路到 merge(返回 a 的 i1),否则求 b, - # 最后一个值直接求值并跳 merge - # merge 块用 phi 合并所有入边的 i1 - # ============================================================ - def translate_boolop(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - funcs_ptr: t.CPtr = None, - func_count: int = 0, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译布尔运算(and/or)的短路求值,返回 i1""" - bo: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) - if bo is None: - return None - - op: int = bo.op - values: list[ast.AST | t.CPtr] | t.CPtr = bo.values - if values is None: - return None - count: t.CSizeT = len(values) - if count == 0: - return None - if count == 1: - return HandlesExpr.translate_value(builder, pool, mod, values.get(0), - funcs_ptr, func_count, trans) - - func: llvmlite.Function | t.CPtr = builder.Func - if func is None: - return None - - # 创建 merge BB(用 builder.Counter 生成唯一标签名,position_at_end 的 - # move_to_end 保证 BB 文本顺序与控制流顺序一致,标签名用 counter 安全) - cnt: int = builder.Counter - builder.Counter = cnt + 1 - name_buf: str = pool.alloc(32) - if name_buf is None: - return None - viperlib.snprintf(name_buf, 32, "bool.merge.%d", cnt) - merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - # phi 入边链表头/尾 - phi_head: llvmlite.PhiIncoming | t.CPtr = None - phi_tail: llvmlite.PhiIncoming | t.CPtr = None - phi_count: int = count - 1 # 循环次数 - - # 对每个值(除最后一个)求值并短路 - for i in range(count - 1): - val_node: ast.AST | t.CPtr = values.get(i) - val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, val_node, - funcs_ptr, func_count, trans) - if val is None: - return None - - # 转为 i1(已经是 i1 的直接用,否则与 0/null 比较) - val_bits: int = self.get_llvm_type_bits(val.Ty) - val_i1: llvmlite.Value | t.CPtr = val - if val_bits != 1: - if self.is_ptr_type(val.Ty) != 0: - # 指针类型:与 null 比较(避免 i8* 与 i32 类型不匹配) - null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, val.Ty, "null") - val_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, val, null_val) - else: - zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - val_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, val, zero) - - # 创建 next BB(求值下一个值) - cnt = builder.Counter - builder.Counter = cnt + 1 - viperlib.snprintf(name_buf, 32, "bool.next.%d", cnt) - next_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - # and: 短路假→merge,真→next;or: 短路真→merge,假→next - if op == ast.OpKind.And: - llvmlite.build_cond_br(builder, val_i1, next_bb, merge_bb) - else: - llvmlite.build_cond_br(builder, val_i1, merge_bb, next_bb) - - # 添加 phi 入边:(val_i1, cond_br 所在 BB) - cur_bb: llvmlite.BasicBlock | t.CPtr = builder.CurBlock - inc: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming(pool, val_i1, cur_bb) - if phi_head is None: - phi_head = inc - phi_tail = inc - else: - phi_tail.Next = inc - phi_tail = inc - - # 定位到 next BB,求值下一个值 - llvmlite.position_at_end(builder, next_bb) - - # 最后一个值:求值后直接跳 merge - last_node: ast.AST | t.CPtr = values.get(count - 1) - last_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, last_node, - funcs_ptr, func_count, trans) - if last_val is None: - return None - last_bits: int = self.get_llvm_type_bits(last_val.Ty) - last_i1: llvmlite.Value | t.CPtr = last_val - if last_bits != 1: - if self.is_ptr_type(last_val.Ty) != 0: - # 指针类型:与 null 比较(避免 i8* 与 i32 类型不匹配) - null_val2: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, last_val.Ty, "null") - last_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, last_val, null_val2) - else: - zero = llvmlite.const_int32(pool, 0) - last_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, last_val, zero) - - llvmlite.build_br(builder, merge_bb) - - cur_bb = builder.CurBlock - inc = llvmlite.new_phi_incoming(pool, last_i1, cur_bb) - if phi_head is None: - phi_head = inc - else: - phi_tail.Next = inc - phi_count += 1 - - # 定位到 merge,创建 phi 合并所有入边 - llvmlite.position_at_end(builder, merge_bb) - i1_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - return llvmlite.build_phi(builder, i1_ty, phi_head, phi_count) - # ============================================================ - # BinOp 运算符 → dunder 方法名 - # ============================================================ - def _binop_to_dunder(self, op: int) -> str: - """将 BinOp 运算符映射到 dunder 方法名,无映射时返回 None - - Python 3 语义:/ 映射 __truediv__(Python 2 的 __div__ 已废弃)。 - """ - if op == ast.OpKind.Add: return "__add__" - if op == ast.OpKind.Sub: return "__sub__" - if op == ast.OpKind.Mult: return "__mul__" - if op == ast.OpKind.Div: return "__truediv__" - if op == ast.OpKind.Mod: return "__mod__" - if op == ast.OpKind.BitAnd: return "__and__" - if op == ast.OpKind.BitOr: return "__or__" - if op == ast.OpKind.BitXor: return "__xor__" - if op == ast.OpKind.LShift: return "__lshift__" - if op == ast.OpKind.RShift: return "__rshift__" - if op == ast.OpKind.FloorDiv: return "__floordiv__" - return None - # ============================================================ - # Compare 运算符 → dunder 方法名 - # ============================================================ - def _cmpop_to_dunder(self, op: int) -> str: - """将 Compare 运算符映射到 dunder 方法名,无映射时返回 None""" - if op == ast.OpKind.Eq: return "__eq__" - if op == ast.OpKind.Ne: return "__ne__" - if op == ast.OpKind.Lt: return "__lt__" - if op == ast.OpKind.Le: return "__le__" - if op == ast.OpKind.Gt: return "__gt__" - if op == ast.OpKind.Ge: return "__ge__" - return None - # ============================================================ - # UnaryOp 运算符 → dunder 方法名 - # ============================================================ - def _unaryop_to_dunder(self, op: int) -> str: - """将 UnaryOp 运算符映射到 dunder 方法名,无映射时返回 None""" - if op == ast.OpKind.USub: return "__neg__" - if op == ast.OpKind.UAdd: return "__pos__" - if op == ast.OpKind.Invert: return "__invert__" - return None - # ============================================================ - # try_operator_overload - 尝试运算符重载 - # - # 检查 lhs 是否为结构体指针,并在该类(含继承链)中查找对应的 - # dunder 方法。找到则生成方法调用 lhs.__dunder__(rhs),返回 - # 调用结果;未找到返回 None,调用方回退到原生运算。 - # ============================================================ - def try_operator_overload(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - lhs: llvmlite.Value | t.CPtr, - rhs: llvmlite.Value | t.CPtr, - op: int, - trans: HT.Translator | t.CPtr, - is_compare: int) -> llvmlite.Value | t.CPtr: - """尝试运算符重载:lhs 是结构体指针时调用 dunder 方法,否则返回 None""" - if lhs is None or rhs is None: - return None - - # 延迟导入避免循环依赖 - import lib.core.Handles.HandlesStruct as HandlesStruct - import lib.core.Handles.HandlesExprCall as HandlesExprCall - - # 映射运算符到 dunder 方法名 - dunder: str = None - if is_compare != 0: - dunder = self._cmpop_to_dunder(op) - else: - dunder = self._binop_to_dunder(op) - if dunder is None: - return None - - # 检查 lhs 是否为结构体指针 - struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(lhs) - if struct_ty is None: - return None - - # 获取类名 - class_name: str = HandlesStruct.get_class_name_by_type(pool, struct_ty) - if class_name is None: - return None - - # 在继承链中查找 dunder 方法 - lookup_name: str = pool.alloc(128) - if lookup_name is None: - return None - viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder) - found_func: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module(mod, lookup_name) - - search_class: str = class_name - if found_func is None: - # 多继承:沿 MRO 祖先链查找(先声明父类优先) - mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name) - mi: int = 1 - while mro_ptr is not None and mro_ptr[mi] != 0: - anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr)) - if anc is not None: - parent_lookup: str = pool.alloc(128) - if parent_lookup is not None: - viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, dunder) - parent_func: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module(mod, parent_lookup) - if parent_func is not None: - found_func = parent_func - search_class = anc - break - mi += 1 - - # 方法不在当前模块中时,检查类(含父类)是否有 SHA1(stub 可能未注入) - # 优先用类型指针定位 entry 获取 SHA1(规避跨模块同名 find_struct 找错) - cls_sha1: str = None - op_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) - if op_entry is not None: - cls_sha1 = op_entry.ModuleSha1 - if cls_sha1 is None: - cls_sha1 = HandlesStruct.get_struct_sha1(search_class) - if cls_sha1 is None: - mro_p: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, search_class) - mj: int = 1 - while mro_p is not None and mro_p[mj] != 0 and cls_sha1 is None: - anc_p: str = (str | t.CPtr)(t.CVoid(mro_p[mj], t.CPtr)) - if anc_p is not None: - cls_sha1 = HandlesStruct.get_struct_sha1(anc_p) - mj += 1 - - # 既无函数定义也无 SHA1 → 该类没有此 dunder 方法,返回 None 回退原生运算 - if found_func is None and cls_sha1 is None: - return None - - # 方法在"定义它的模块"中确实不存在(同模块类但模块内无此 dunder): - # 返回 None 回退原生运算,绝不发出幽灵 call——否则 IR 残留 - # `call void @...__div__`(副作用)且调用方回退原生 sdiv 双重发射, - # llc 报 invalid operand type for instruction(CPythonTest PyFloatObj 根因) - if found_func is None and trans is not None and trans.ModuleSha1 is not None: - if cls_sha1 is not None and string.strcmp(cls_sha1, trans.ModuleSha1) == 0: - return None - # 跨模块类:stub 可能未注入,方法存在性以依赖模块 vpi stub 为准。 - # vpi 未命中(依赖模块确实无此 dunder)→ 回退原生比较(icmp), - # 绝不发幽灵 call——`call @{cls_sha1}.{Class}.{dunder}` 链接 undefined - # (MemBuddy 无 __eq__ 时 os._mbuddy == sys._mbuddy,SysLibTest 根因)。 - vpi_dup: llvmlite.LLVMType | t.CPtr = ExprCallCtor._lookup_method_ret_ty_via_vpi( - pool, cls_sha1, search_class, dunder) - if vpi_dup is None: - return None - - # 构建 extra_args 数组(仅含 rhs 一个参数) - extra_args: t.CSizeT | t.CPtr = pool.alloc(8) - if extra_args is None: - return None - extra_args[0] = t.CSizeT(rhs) - - # 调用方法: lhs.__dunder__(rhs) - return ExprCallCtor._call_method_on_ptr( - pool, builder, mod, search_class, dunder, - lhs, extra_args, 1, trans) - # ============================================================ - # try_unary_operator_overload - 尝试一元运算符重载 - # - # 检查 operand 是否为结构体指针,并在该类(含继承链)中查找对应的 - # dunder 方法(__neg__/__pos__/__invert__)。找到则生成方法调用 - # operand.__dunder__(),返回调用结果;未找到返回 None,调用方回退到原生运算。 - # ============================================================ - def try_unary_operator_overload(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - operand: llvmlite.Value | t.CPtr, - op: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """尝试一元运算符重载:operand 是结构体指针时调用 dunder 方法,否则返回 None""" - if operand is None: - return None - - # 延迟导入避免循环依赖 - import lib.core.Handles.HandlesStruct as HandlesStruct - import lib.core.Handles.HandlesExprCall as HandlesExprCall - - dunder: str = self._unaryop_to_dunder(op) - if dunder is None: - return None - - # 检查 operand 是否为结构体指针 - struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(operand) - if struct_ty is None: - return None - - # 获取类名 - class_name: str = HandlesStruct.get_class_name_by_type(pool, struct_ty) - if class_name is None: - return None - - # 在继承链中查找 dunder 方法 - lookup_name: str = pool.alloc(128) - if lookup_name is None: - return None - viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder) - found_func: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module(mod, lookup_name) - - search_class: str = class_name - if found_func is None: - # 多继承:沿 MRO 祖先链查找(先声明父类优先) - mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name) - mi: int = 1 - while mro_ptr is not None and mro_ptr[mi] != 0: - anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr)) - if anc is not None: - parent_lookup: str = pool.alloc(128) - if parent_lookup is not None: - viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, dunder) - parent_func: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module(mod, parent_lookup) - if parent_func is not None: - found_func = parent_func - search_class = anc - break - mi += 1 - - # 方法不在当前模块中时,检查类(含父类)是否有 SHA1(stub 可能未注入) - cls_sha1: str = None - uop_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) - if uop_entry is not None: - cls_sha1 = uop_entry.ModuleSha1 - if cls_sha1 is None: - cls_sha1 = HandlesStruct.get_struct_sha1(search_class) - if cls_sha1 is None: - mro_p: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, search_class) - mj: int = 1 - while mro_p is not None and mro_p[mj] != 0 and cls_sha1 is None: - anc_p: str = (str | t.CPtr)(t.CVoid(mro_p[mj], t.CPtr)) - if anc_p is not None: - cls_sha1 = HandlesStruct.get_struct_sha1(anc_p) - mj += 1 - - # 既无函数定义也无 SHA1 → 该类没有此 dunder 方法,返回 None 回退原生运算 - if found_func is None and cls_sha1 is None: - return None - - # 同模块类但模块内无此 dunder → 返回 None 回退原生运算,不发幽灵 call - # (与 try_operator_overload 一致,防 IR 残留 call void @...__neg__) - if found_func is None and trans is not None and trans.ModuleSha1 is not None: - if cls_sha1 is not None and string.strcmp(cls_sha1, trans.ModuleSha1) == 0: - return None - - # 一元方法无额外参数(extra_args 为空) - return ExprCallCtor._call_method_on_ptr( - pool, builder, mod, search_class, dunder, - operand, None, 0, trans) - # ============================================================ - # 翻译二元运算(自动类型提升) - # ============================================================ - def translate_binop(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译二元运算(自动类型提升)""" - binop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - if binop is None: - return None - - lhs_node: ast.AST | t.CPtr = binop.left - rhs_node: ast.AST | t.CPtr = binop.right - op: int = binop.op - - # 先翻译 rhs(只翻译一次,避免副作用重复) - rhs: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, rhs_node, None, 0, trans) - if rhs is None: - return None - - # === 运算符重载路径 1: lhs 是 Name 且对应结构体变量 === - # 对于值类型变量(如 cnt: Counter),translate_value 会 load 返回 Struct 值, - # 但 dunder 方法需要 Ptr(Struct) 作为 self。直接用 alloca 指针尝试重载。 - if lhs_node is not None and lhs_node.kind() == ast.ASTKind.Name and trans is not None: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(lhs_node) - if nm is not None and nm.id is not None: - lhs_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, nm.id) - if lhs_alloca is not None: - ovl_self1: llvmlite.Value | t.CPtr = lhs_alloca - # alloca 是 Ptr(Ptr(Struct))(X|t.CPtr 对象存储槽)时, - # load 出对象指针作为 self——若把槽地址当 self,dunder 内 - # load 槽内容(对象指针值)当字段读 → 垃圾(MultiInheritTest - # Vec2Both __add__ 输出 (1.0,2.0) 根因;get_struct_type_from_value - # 递归解指针后路径 1 能识别 alloca,需同步修正 self 语义) - if lhs_alloca.Ty is not None and lhs_alloca.Ty.Pointee is not None \ - and HandlesExpr.is_ptr_type(lhs_alloca.Ty.Pointee) != 0: - load_self1: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, lhs_alloca.Ty.Pointee, lhs_alloca) - if load_self1 is not None: - ovl_self1 = load_self1 - ovl_result: llvmlite.Value | t.CPtr = self.try_operator_overload( - pool, builder, mod, ovl_self1, rhs, op, trans, 0) - if ovl_result is not None: - return ovl_result - - # 正常翻译 lhs - lhs: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, lhs_node, None, 0, trans) - if lhs is None: - return None - - # === 运算符重载路径 2: lhs 是 Ptr(Struct)(如 Counter|t.CPtr 变量 load 后)=== - ovl_result2: llvmlite.Value | t.CPtr = self.try_operator_overload( - pool, builder, mod, lhs, rhs, op, trans, 0) - if ovl_result2 is not None: - return ovl_result2 - - # 获取操作数类型信息 - lhs_bits: int = self.get_llvm_type_bits(lhs.Ty) - rhs_bits: int = self.get_llvm_type_bits(rhs.Ty) - lhs_fbits: int = self.get_llvm_float_bits(lhs.Ty) - rhs_fbits: int = self.get_llvm_float_bits(rhs.Ty) - - # 浮点运算: 任一操作数为浮点时,使用浮点指令(必须在指针算术之前检查, - # 因为 float 的 int bits 为 0,会被误认为指针) - if lhs_fbits != 0 or rhs_fbits != 0: - # 确定目标浮点类型(使用较大的位宽) - target_fbits: int = lhs_fbits - if rhs_fbits > target_fbits: - target_fbits = rhs_fbits - target_float_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) - if target_fbits == 32: - target_float_ty = llvmlite.Float(pool) - # 将两个操作数转换为目标浮点类型(int→float via si2fp, float→float via fpext/fptrunc) - lhs = self.coerce_to_type(builder, lhs, target_float_ty, node) - rhs = self.coerce_to_type(builder, rhs, target_float_ty, node) - if op == ast.OpKind.Add: - return llvmlite.build_fadd(builder, lhs, rhs) - if op == ast.OpKind.Sub: - return llvmlite.build_fsub(builder, lhs, rhs) - if op == ast.OpKind.Mult: - return llvmlite.build_fmul(builder, lhs, rhs) - if op == ast.OpKind.Div: - return llvmlite.build_fdiv(builder, lhs, rhs) - if op == ast.OpKind.Mod: - return llvmlite.build_frem(builder, lhs, rhs) - return None - - # 指针算术: ptr + int / ptr - int / int + ptr → getelementptr(按元素大小缩放) - # 对齐 TPC ExprGen.emit_binary_op L50-67;int - ptr 无 GEP 形式(C 语义非法) - if (lhs_bits == 0 and rhs_bits != 0) or (lhs_bits != 0 and rhs_bits == 0): - if op == ast.OpKind.Add: - if lhs_bits == 0: - return self.translate_ptr_arith(pool, builder, lhs, rhs, op) - # int + ptr(交换) - return self.translate_ptr_arith(pool, builder, rhs, lhs, op) - if op == ast.OpKind.Sub and lhs_bits == 0: - return self.translate_ptr_arith(pool, builder, lhs, rhs, op) - - if lhs_bits > rhs_bits: - if self.should_zext_widen(pool, rhs, lhs, rhs_node) != 0: - rhs = llvmlite.build_zext(builder, rhs, lhs.Ty) - else: - rhs = self.coerce_to_type(builder, rhs, lhs.Ty, node) - elif rhs_bits > lhs_bits: - if self.should_zext_widen(pool, lhs, rhs, lhs_node) != 0: - lhs = llvmlite.build_zext(builder, lhs, rhs.Ty) - else: - lhs = self.coerce_to_type(builder, lhs, rhs.Ty, node) - - # 位运算类型安全检查:两边都是指针(lhs_bits==0 and rhs_bits==0)时, - # 位运算(BitOr/BitAnd/BitXor/LShift/RShift)非法,LLVM 要求整数操作数。 - # 常见触发场景:CDefine 常量查找失败返回指针 null,与另一指针做 `|`。 - if lhs_bits == 0 and rhs_bits == 0: - if op == ast.OpKind.BitOr or op == ast.OpKind.BitAnd or op == ast.OpKind.BitXor or op == ast.OpKind.LShift or op == ast.OpKind.RShift: - # fail-fast:位运算操作数类型非法,立即终止编译(暴露上游根因) - HandlesType.fatal_error( - node, - "位运算操作数类型非法: lhs/rhs 均为非整数类型(指针或结构体),无法执行位运算", - "TypeError") - - if op == ast.OpKind.Add: - return llvmlite.build_add(builder, lhs, rhs) - elif op == ast.OpKind.Sub: - return llvmlite.build_sub(builder, lhs, rhs) - elif op == ast.OpKind.Mult: - return llvmlite.build_mul(builder, lhs, rhs) - elif op == ast.OpKind.Div: - return llvmlite.build_sdiv(builder, lhs, rhs) - elif op == ast.OpKind.FloorDiv: - return llvmlite.build_sdiv(builder, lhs, rhs) - elif op == ast.OpKind.Mod: - return llvmlite.build_srem(builder, lhs, rhs) - elif op == ast.OpKind.BitAnd: - return llvmlite.build_and(builder, lhs, rhs) - elif op == ast.OpKind.BitOr: - return llvmlite.build_or(builder, lhs, rhs) - elif op == ast.OpKind.BitXor: - return llvmlite.build_xor(builder, lhs, rhs) - elif op == ast.OpKind.LShift: - return llvmlite.build_shl(builder, lhs, rhs) - elif op == ast.OpKind.RShift: - # 无符号 >> → lshr(逻辑右移),有符号 >> → ashr(算术右移) - # 对齐 TPC ExprGen.emit_binary_op:i8/i16 默认无符号;其余查操作数无符号性 - if lhs_bits == 8 or lhs_bits == 16: - return llvmlite.build_lshr(builder, lhs, rhs) - if self._node_type_unsigned(pool, lhs_node, trans) != 0: - return llvmlite.build_lshr(builder, lhs, rhs) - return llvmlite.build_ashr(builder, lhs, rhs) +import lib.core.Gen.GenTypes as GenTypes +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import w32.fileio as fileio +import lib.core.CompilerFactory as CompilerFactory +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.StubMerger as StubMerger +import lib.core.VLogger as VLogger +import lib.Projectrans.Config as Config +import lib.Projectrans.Utils as Utils + + +import lib.core.Gen.ExprGenBase as ExprGenBase + +# ============================================================ +# ExprGenOps - ExprGenMixin 拆分(阶段 D):比较/一元/布尔/binop 运算 +# +# 继承 ExprGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class ExprGenOps(ExprGenBase.ExprGenBase): + """比较/一元/布尔/binop 运算""" + + # ============================================================ + # 翻译三元表达式 IfExp(test, body, orelse) + # + # 生成: cond ? body : orelse + # then_blk: 翻译 body → br merge + # else_blk: 翻译 orelse → br merge + # merge_blk: phi [body_val, then_blk], [orelse_val, else_blk] + # ============================================================ + def translate_ifexp(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译三元表达式 (body if test else orelse),返回 phi 结果 Value""" + if node is None or builder is None or trans is None: + return None + ie: ast.IfExp | t.CPtr = (ast.IfExp | t.CPtr)(node) + if ie is None: + return None + + func: llvmlite.Function | t.CPtr = trans._cur_func + if func is None: + return None + + # 1. 求值条件 + cond_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, ie.test, None, 0, trans) + if cond_val is None: + return None + # 转换为 i1 + cond_bits: int = self.get_llvm_type_bits(cond_val.Ty) + if cond_bits == 1: + cond_i1: llvmlite.Value | t.CPtr = cond_val + else: + if self.is_ptr_type(cond_val.Ty) != 0: + # 指针类型:与 null 比较 + null_cond: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cond_val.Ty, "null") + cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, null_cond) + else: + zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, zero) + + # 2. 创建三个基本块 + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + name_buf: str = pool.alloc(32) + if name_buf is None: + return None + viperlib.snprintf(name_buf, 32, "ifexp.then.%d", cnt) + then_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + viperlib.snprintf(name_buf, 32, "ifexp.else.%d", cnt) + else_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + viperlib.snprintf(name_buf, 32, "ifexp.merge.%d", cnt) + merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + if then_bb is None or else_bb is None or merge_bb is None: + return None + + # 3. 条件跳转 + llvmlite.build_cond_br(builder, cond_i1, then_bb, else_bb) + + # 4. then 分支 + llvmlite.position_at_end(builder, then_bb) + body_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, ie.body, None, 0, trans) + then_blk_for_phi: llvmlite.BasicBlock | t.CPtr = trans._cur_builder.CurBlock + if body_val is None: + # fail-fast:三元表达式 then 分支翻译失败,立即终止编译(暴露上游根因) + self.Gen.TypeGenErr.fatal_error(ie.body, "三元表达式分支翻译失败", "TypeError") + # 暂不 br,等类型对齐后再 br + + # 5. else 分支 + llvmlite.position_at_end(builder, else_bb) + orelse_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, ie.orelse, None, 0, trans) + else_blk_for_phi: llvmlite.BasicBlock | t.CPtr = trans._cur_builder.CurBlock + if orelse_val is None: + # fail-fast:三元表达式 else 分支翻译失败,立即终止编译(暴露上游根因) + self.Gen.TypeGenErr.fatal_error(ie.orelse, "三元表达式分支翻译失败", "TypeError") + # 暂不 br,等类型对齐后再 br + + # 类型对齐 (两分支类型可能不同) + # 必须在各自分支中执行 coerce_to_type,确保 merge 块中 PHI 是第一条指令 + # (否则 coerce_to_type 生成的 sext/zext/ptrtoint/inttoptr 指令在 PHI 之前,违反 LLVM 规则) + body_bits: int = self.get_llvm_type_bits(body_val.Ty) + orelse_bits: int = self.get_llvm_type_bits(orelse_val.Ty) + body_is_ptr: int = self.is_ptr_type(body_val.Ty) + orelse_is_ptr: int = self.is_ptr_type(orelse_val.Ty) + # 情况0: 一侧是指针,另一侧是整数(如 i64 vs i8* null) + # 必须优先处理,因为 Ptr 的 bits=0 会导致下面三个分支全部跳过 + # 选择 body_val.Ty 作为 phi_ty(then 分支优先),orelse_val 对齐到它 + # coerce_to_type 内部会调用 ptrtoint(指针→整数)或 inttoptr(整数→指针) + if body_is_ptr != orelse_is_ptr: + llvmlite.position_at_end(builder, else_blk_for_phi) + orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node) + elif body_bits > orelse_bits and orelse_bits > 0: + # 在 else 块中转换 orelse_val + llvmlite.position_at_end(builder, else_blk_for_phi) + orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node) + elif orelse_bits > body_bits and body_bits > 0: + # 回到 then 块转换 body_val + llvmlite.position_at_end(builder, then_blk_for_phi) + body_val = self.coerce_to_type(builder, body_val, orelse_val.Ty, node) + elif body_bits == orelse_bits and body_bits > 0: + # bits 相同但类型不同(如 i64 vs Ptr):null 不能用于 i64 PHI + # 此分支理论上不会触发(已被情况0覆盖),保留作为防御 + if self.is_ptr_type(body_val.Ty) != self.is_ptr_type(orelse_val.Ty): + llvmlite.position_at_end(builder, else_blk_for_phi) + orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node) + + # 现在分别在 then/else 块中 br 到 merge(在类型转换之后) + llvmlite.position_at_end(builder, then_blk_for_phi) + llvmlite.build_br(builder, merge_bb) + llvmlite.position_at_end(builder, else_blk_for_phi) + llvmlite.build_br(builder, merge_bb) + + # 6. merge 块: phi(PHI 是 merge 块的第一条指令) + llvmlite.position_at_end(builder, merge_bb) + + phi_ty: llvmlite.LLVMType | t.CPtr = body_val.Ty + if phi_ty is None: + # fail-fast:三元表达式分支类型缺失,立即终止编译(暴露上游根因) + self.Gen.TypeGenErr.fatal_error(node, "三元表达式分支类型缺失", "TypeError") + + inc1: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming( + pool, body_val, then_blk_for_phi) + inc2: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming( + pool, orelse_val, else_blk_for_phi) + if inc1 is None or inc2 is None: + return None + # 链表顺序: inc1 (head) -> inc2 (tail) + # 之前错误写成 inc2.Next = inc1,导致 build_phi 从 inc1 遍历时 + # inc1.Next 为 None,只输出一个 phi 条目,引发 LLVM 验证错误: + # "PHINode should have one entry for each predecessor" + inc1.Next = inc2 + return llvmlite.build_phi(builder, phi_ty, inc1, 2) + # ============================================================ + # 翻译比较表达式 Compare(left, ops, comparators) + # ============================================================ + def should_zext_widen(self, pool: memhub.MemBuddy | t.CPtr, + narrow_val: llvmlite.Value | t.CPtr, + wide_val: llvmlite.Value | t.CPtr, + narrow_node: ast.AST | t.CPtr = None) -> int: + """判断整数拓宽方向:1=zext(无符号语义),0=sext + + 对齐 TPC 的 _check_node_unsigned / HandlesExprOps 拓宽规则: + 1. i1 (bool) → zext(1 保持 1,而非 sext 的 0xFF...) + 2. i8 → zext(系统编程中 i8 几乎总是无符号字节) + 3. 宽侧是常量且其值超出窄侧位宽的有符号范围 → zext + (常量"想要"无符号解释,如 0xAABBCCDD > INT32_MAX 与 + t.CUInt32T 值比较,sext 会把 0xAABBCCDD 变成 + 0xFFFFFFFFAABBCCDD 导致恒不等) + """ + if narrow_val is None or narrow_val.Ty is None: + return 0 + narrow_bits: int = self.get_llvm_type_bits(narrow_val.Ty) + if narrow_bits == 1: + return 1 + if narrow_bits == 8: + return 1 + # 宽侧常量启发式 + if wide_val is not None and wide_val.IsConst == 1: + wide_bits: int = self.get_llvm_type_bits(wide_val.Ty) + if wide_bits > narrow_bits and narrow_bits < 64: + signed_max: t.CInt64T = (t.CInt64T(1) << (narrow_bits - 1)) - 1 + if wide_val.IntVal > signed_max: + return 1 + # 窄侧 AST 节点解析为无符号类型(如 t.CUIntXXT 字面量/强转) + if narrow_node is not None: + if self._node_type_unsigned(pool, narrow_node) != 0: + return 1 + return 0 + def _node_type_unsigned(self, pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> int: + """轻量判断 AST 节点是否解析为无符号整数类型(1=是,0=否/未知) + + 覆盖常见形态(对齐 TPC _check_node_unsigned 的 Call/Subscript 分支): + - t.CUInt8T/CUInt16T/CUInt32T/CUInt64T/CUnsigned* 等显式无符号类型强转调用 + - 无符号类型名的 Name 引用(如 UInt32T 别名) + - 变量名(trans 可用时):查询 SymTab 中变量的 AnnotClassName(如 v: t.CUInt32T) + """ + if node is None: + return 0 + k: int = node.kind() + if k == ast.ASTKind.Call: + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + 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 and string.strcmp(mod_nm.id, "t") == 0 \ + and at.attr is not None: + if self._type_name_unsigned(at.attr) != 0: + return 1 + return 0 + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is not None: + # 1) 名字本身是无符号类型名(如 UInt32T 别名) + if self._type_name_unsigned(nm.id) != 0: + return 1 + # 2) 变量注解类型为无符号类型(trans 可用时查 SymTab) + if trans is not None: + ve: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, nm.id) + if ve is not None and ve.AnnotClassName is not None: + if self._type_name_unsigned(ve.AnnotClassName) != 0: + return 1 + return 0 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if self._node_type_unsigned(pool, bop.left, trans) != 0: + return 1 + if self._node_type_unsigned(pool, bop.right, trans) != 0: + return 1 + return 0 + if k == ast.ASTKind.UnaryOp: + uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + if self._node_type_unsigned(pool, uop.operand, trans) != 0: + return 1 + return 0 + if k == ast.ASTKind.Subscript: + # 数组/指针下标: md5_buf[i](t.CArray[t.CUInt8T, N])或 buf[i] + # (形参 t.CUInt8T | t.CPtr)元素是无符号整型 → printf("%02x", ...) zext。 + sub_su: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + if sub_su.value is not None and sub_su.value.kind() == ast.ASTKind.Name: + snm_su: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_su.value) + if snm_su.id is not None and trans is not None: + ve_su: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, snm_su.id) + if ve_su is not None and ve_su.AnnotClassName is not None: + if self._annot_str_unsigned(ve_su.AnnotClassName) != 0: + return 1 + return 0 + return 0 + def _type_name_unsigned(self, type_name: str) -> int: + """类型名是否为无符号整数类型(精确匹配,避免子串误伤如 nUIntCount)""" + if type_name is None: + return 0 + # t.CUIntXXT 形式 + if string.strcmp(type_name, "CUInt8T") == 0: return 1 + if string.strcmp(type_name, "CUInt16T") == 0: return 1 + if string.strcmp(type_name, "CUInt32T") == 0: return 1 + if string.strcmp(type_name, "CUInt64T") == 0: return 1 + # stdint 裸别名(from stdint import *) + if string.strcmp(type_name, "UInt8T") == 0: return 1 + if string.strcmp(type_name, "UInt16T") == 0: return 1 + if string.strcmp(type_name, "UInt32T") == 0: return 1 + if string.strcmp(type_name, "UInt64T") == 0: return 1 + # CUnsigned* 形式 + if string.strcmp(type_name, "CUnsignedChar") == 0: return 1 + if string.strcmp(type_name, "CUnsignedShort") == 0: return 1 + if string.strcmp(type_name, "CUnsignedInt") == 0: return 1 + if string.strcmp(type_name, "CUnsignedLong") == 0: return 1 + if string.strcmp(type_name, "CUnsignedLongLong") == 0: return 1 + # 常见无符号别名 + if string.strcmp(type_name, "BYTE") == 0: return 1 + if string.strcmp(type_name, "UCHAR") == 0: return 1 + if string.strcmp(type_name, "USHORT") == 0: return 1 + if string.strcmp(type_name, "UINT") == 0: return 1 + if string.strcmp(type_name, "ULONG") == 0: return 1 + return 0 + def _annot_str_unsigned(self, annot: str) -> int: + """检查类型注解字符串是否引用无符号整型(子串扫描) + + 用于复合注解(t.CArray[t.CUInt8T, 16] / t.CUInt8T | t.CPtr), + _type_name_unsigned 的精确匹配对这类串不适用。 + """ + if annot is None: + return 0 + if string.strstr(annot, "CUInt8T") is not None: return 1 + if string.strstr(annot, "CUInt16T") is not None: return 1 + if string.strstr(annot, "CUInt32T") is not None: return 1 + if string.strstr(annot, "CUInt64T") is not None: return 1 + if string.strstr(annot, "CUnsigned") is not None: return 1 + if string.strstr(annot, "BYTE") is not None: return 1 + if string.strstr(annot, "UCHAR") is not None: return 1 + if string.strstr(annot, "USHORT") is not None: return 1 + if string.strstr(annot, "UINT") is not None: return 1 + if string.strstr(annot, "ULONG") is not None: return 1 + return 0 + def translate_compare(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译比较表达式,返回 i1 结果""" + cmp: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) + if cmp is None: + return None + + ops_list: list[t.CInt] | t.CPtr = (list[t.CInt] | t.CPtr)(cmp.ops) + if ops_list is None or len(ops_list) == 0: + return None + op: int = ops_list.get(0) + + comparators: list[ast.AST | t.CPtr] | t.CPtr = cmp.comparators + if comparators is None or len(comparators) == 0: + return None + rhs_node: ast.AST | t.CPtr = comparators.get(0) + rhs: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, rhs_node, None, 0, trans) + if rhs is None: + return None + + # === None 比较优化: x == None / x != None 走身份比较(icmp eq/ne null)=== + # 避免对结构体指针生成无效的 __eq__/__ne__ 调用(方法未定义但类有 SHA1 时 + # try_operator_overload 会误生成 call void @...__eq__(...) 导致链接错误) + # 语义依据: Python 中 == None / != None 默认走身份比较,不调用 __eq__/__ne__ + lhs_node: ast.AST | t.CPtr = cmp.left + cmp_with_none: int = 0 + if op == ast.OpKind.Eq or op == ast.OpKind.Ne or op == ast.OpKind.Is or op == ast.OpKind.IsNot: + if rhs_node is not None and rhs_node.kind() == ast.ASTKind.Constant: + rhs_cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(rhs_node) + if rhs_cn is not None and rhs_cn.const_kind == ast.CONST_NONE: + cmp_with_none = 1 + if cmp_with_none == 0 and lhs_node is not None and lhs_node.kind() == ast.ASTKind.Constant: + lhs_cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(lhs_node) + if lhs_cn is not None and lhs_cn.const_kind == ast.CONST_NONE: + cmp_with_none = 1 + + # === 指针判空模式: ptr != 0 / ptr == 0 === + # 跳过运算符重载走身份比较(icmp null)。跨模块类(如 cpython.PyObject) + # 未定义 __eq__/__ne__ 时,try_operator_overload 无法判定方法不存在 + # (类在依赖模块,cls_sha1 != trans.ModuleSha1),会误发幽灵 + # `call void @...__ne__` → 链接 undefined reference(CPythonTest main.vp + # `py_num != 0` 根因)。C 语义:指针与字面量 0 比较 = 判空。 + cmp_zero: int = 0 + if op == ast.OpKind.Eq or op == ast.OpKind.Ne: + if rhs_node is not None and self._is_zero_int_literal(rhs_node) != 0: + cmp_zero = 1 + if cmp_zero == 0 and lhs_node is not None and self._is_zero_int_literal(lhs_node) != 0: + cmp_zero = 1 + + # === 比较运算符重载路径 1: lhs 是 Name 且对应结构体变量 === + # 对于值类型变量(如 cnt: Counter),用 alloca 指针尝试重载 + # None 比较跳过重载(走身份比较) + if cmp_with_none == 0 and lhs_node is not None and lhs_node.kind() == ast.ASTKind.Name and trans is not None: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(lhs_node) + if nm is not None and nm.id is not None: + lhs_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, nm.id) + if lhs_alloca is not None: + if cmp_zero == 0 or self.get_ptr_level(lhs_alloca.Ty) == 0: + ovl_self1: llvmlite.Value | t.CPtr = lhs_alloca + # Ptr(Ptr(Struct)) 对象存储槽:load 出对象指针作 self + # (与 translate_binop 路径 1 一致,避免槽地址当对象地址) + if lhs_alloca.Ty is not None and lhs_alloca.Ty.Pointee is not None \ + and self.Gen.ExprGenBase.is_ptr_type(lhs_alloca.Ty.Pointee) != 0: + load_self1: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, lhs_alloca.Ty.Pointee, lhs_alloca) + if load_self1 is not None: + ovl_self1 = load_self1 + ovl_result: llvmlite.Value | t.CPtr = self.try_operator_overload( + pool, builder, mod, ovl_self1, rhs, op, trans, 1) + if ovl_result is not None: + return ovl_result + + # 正常翻译 lhs + lhs: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cmp.left, None, 0, trans) + if lhs is None: + return None + + # === in / not in:容器右操作数调用 __contains__(对齐 TPC + # HandlesExprOps.py L261-281)。x in y → y.__contains__(x); + # x not in y → !y.__contains__(x)。容器无 __contains__ → + # 返回 i1 0(TPC 同:恒 False)。 + if op == ast.OpKind.In or op == ast.OpKind.NotIn: + cn_st: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type_from_value(rhs) + if cn_st is not None: + cn_cls: str = self.Gen.StructGen.get_class_name_by_type(pool, cn_st) + if cn_cls is not None: + cn_lookup: str = pool.alloc(128) + if cn_lookup is not None: + viperlib.snprintf(cn_lookup, 128, "%s.__contains__", cn_cls) + cn_fn: llvmlite.Function | t.CPtr = self.Gen.CallGenBase.find_func_in_module( + mod, cn_lookup) + if cn_fn is not None: + cn_ret: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(cn_fn) + cn_fn_name: str = llvmlite.function_get_name(cn_fn) + if cn_ret is not None and cn_fn_name is not None: + # self 参数(容器)按 __contains__ 首参类型对齐 + cn_self: llvmlite.Value | t.CPtr = rhs + cn_first: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(cn_fn) + if cn_first is not None: + cn_self_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cn_first) + if cn_self_ty is not None: + cn_self = llvmlite.build_bitcast(builder, rhs, cn_self_ty) + if cn_self is not None: + # 参数链表: self → key(独立 null 结尾) + cn_self.Next = lhs + lhs.Next = None + cn_res: llvmlite.Value | t.CPtr = llvmlite.build_call( + builder, cn_fn_name, cn_self, 2, cn_ret, 0) + if cn_res is not None: + # 归一化到 i1(__contains__ 返回 t.CInt/i32 等) + cn_i1: llvmlite.Value | t.CPtr = cn_res + match cn_ret: + case llvmlite.LLVMType.Int(cn_bits): + if cn_bits > 1: + cn_zero: llvmlite.Value | t.CPtr = llvmlite.ConstInt( + pool, cn_ret, 0, "0") + if cn_zero is not None: + cn_i1 = llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, cn_res, cn_zero) + case _: + pass + if op == ast.OpKind.NotIn: + i1_ty_ni: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + if i1_ty_ni is not None and cn_i1 is not None: + one_i1_ni: llvmlite.Value | t.CPtr = llvmlite.ConstInt( + pool, i1_ty_ni, 1, "1") + if one_i1_ni is not None: + cn_i1 = llvmlite.build_xor(builder, cn_i1, one_i1_ni) + if cn_i1 is not None: + return cn_i1 + # 容器无 __contains__:TPC 语义恒 False(i1 0) + i1_ty_in: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + if i1_ty_in is not None: + return llvmlite.ConstInt(pool, i1_ty_in, 0, "0") + return None + + # === 比较运算符重载路径 2: lhs 是 Ptr(Struct) === + # Is/IsNot 不在 _cmpop_to_dunder 映射中,会自动返回 None 回退原生比较 + # None 比较跳过重载(走身份比较);指针判空(cmp_zero + 指针)同样跳过 + if cmp_with_none == 0 and (cmp_zero == 0 or self.get_ptr_level(lhs.Ty) == 0): + ovl_result2: llvmlite.Value | t.CPtr = self.try_operator_overload( + pool, builder, mod, lhs, rhs, op, trans, 1) + if ovl_result2 is not None: + return ovl_result2 + + predicate: int = llvmlite.ICMP_SLT + if op == ast.OpKind.Lt: + predicate = llvmlite.ICMP_SLT + elif op == ast.OpKind.Le: + predicate = llvmlite.ICMP_SLE + elif op == ast.OpKind.Gt: + predicate = llvmlite.ICMP_SGT + elif op == ast.OpKind.Ge: + predicate = llvmlite.ICMP_SGE + elif op == ast.OpKind.Eq: + predicate = llvmlite.ICMP_EQ + elif op == ast.OpKind.Ne: + predicate = llvmlite.ICMP_NE + elif op == ast.OpKind.Is: + # `x is y` → 指针/值相等比较 + predicate = llvmlite.ICMP_EQ + elif op == ast.OpKind.IsNot: + # `x is not y` → 指针/值不等比较 + predicate = llvmlite.ICMP_NE + + # === 类型安全检查(BUG2 修复)=== + # 规则: + # - 数值(0) vs 数值(0) → 允许(无关类型,按位宽 sext 对齐) + # - 一级指针(1) vs 一级指针(1) → 允许(无关 pointee 类型,地址比较) + # - 数值(0) vs 指针(1+) → 禁止(fast-fail,除 None 比较外) + # - 不同级指针(1 vs 2 等) → 禁止(fast-fail) + # + # None 比较跳过此检查(None 被翻译为 null 指针或 0,与任意指针/数值比较合法) + if cmp_with_none == 0: + lhs_ptr_level: int = self.get_ptr_level(lhs.Ty) + rhs_ptr_level: int = self.get_ptr_level(rhs.Ty) + if lhs_ptr_level != rhs_ptr_level: + # 指针 vs 整数字面量 0(判空模式 ptr != 0 / ptr == 0): + # 0 视为 NULL,转成与指针侧同类型的 null 指针(icmp 需要同类型), + # 不报类型不匹配(ClassArrayTest 的 if ptr != 0 等常见模式)。 + zero_is_rhs: int = 0 + zero_is_lhs: int = 0 + if rhs_ptr_level == 0 and self._is_zero_int_literal(rhs_node) != 0: + zero_is_rhs = 1 + if lhs_ptr_level == 0 and self._is_zero_int_literal(lhs_node) != 0: + zero_is_lhs = 1 + if zero_is_rhs != 0 or zero_is_lhs != 0: + if zero_is_rhs != 0: + rhs = llvmlite.ConstNull(pool, lhs.Ty, "null") + else: + lhs = llvmlite.ConstNull(pool, rhs.Ty, "null") + else: + # 指针 vs 非零整数(C 哨兵值模式,如 w32.win32base.INVALID_HANDLE_VALUE = -1): + # 对齐 TPC HandlesExprOps.py L388-398 —— 指针 ptrtoint 成整数做地址值比较。 + # (指针 vs 整数字面量 0 已在上方转 null 处理;此处处理非零整数哨兵) + if lhs_ptr_level != 0 and rhs_ptr_level == 0: + lhs = llvmlite.build_ptrtoint(builder, lhs, rhs.Ty) + elif rhs_ptr_level != 0 and lhs_ptr_level == 0: + rhs = llvmlite.build_ptrtoint(builder, rhs, lhs.Ty) + else: + # 不同级指针(1 vs 2 等)→ 禁止(fast-fail) + self.Gen.TypeGenErr.fatal_error( + cmp, + f"比较类型不匹配: 不同级指针比较 (lhs 层级={lhs_ptr_level}, rhs 层级={rhs_ptr_level})", + "TypeError") + else: + # None 比较: None 被翻译为 i8* null(一级指针) + # 如果 lhs 是指针,将 rhs (i8* null) bitcast 为 lhs 的指针类型 + # 如果 lhs 是数值,将 rhs 转为数值 0(走正常整数比较) + # 如果 lhs 是结构体值类型,结构体永远不等于 None,返回常量 i1 + lhs_ptr_level_none: int = self.get_ptr_level(lhs.Ty) + rhs_ptr_level_none: int = self.get_ptr_level(rhs.Ty) + if lhs_ptr_level_none != 0 and rhs_ptr_level_none != 0: + # 两边都是指针,类型可能不同(如 lhs=Struct*, rhs=i8* null) + # 由下方 bitcast 对齐处理,此处不处理 + pass + elif lhs_ptr_level_none != 0 and rhs_ptr_level_none == 0: + # lhs 是指针, rhs 是数值 → 将 rhs 转为同层级 null 指针 + rhs = llvmlite.ConstNull(pool, lhs.Ty, "null") + elif rhs_ptr_level_none != 0 and lhs_ptr_level_none == 0: + # 检查 lhs 是否是结构体值类型(非指针的 Struct) + lhs_is_struct_none: int = 0 + match lhs.Ty: + case llvmlite.LLVMType.Struct(_, _, _): + lhs_is_struct_none = 1 + case _: + lhs_is_struct_none = 0 + if lhs_is_struct_none != 0: + # 结构体值永远不等于 None:==/is 返回 false,!=/is not 返回 true + if op == ast.OpKind.Eq or op == ast.OpKind.Is: + return llvmlite.const_int(pool, 1, 0) + else: # Ne, IsNot + return llvmlite.const_int(pool, 1, 1) + # lhs 是数值, rhs 是 i8* null → 将 rhs 转为数值 0(保持 lhs 不变) + rhs = llvmlite.const_int32(pool, 0) + + # 类型对齐:icmp 要求两边类型相同 + # 仅对数值类型做对齐(指针类型无需对齐,LLVM 允许同层级指针直接 icmp) + # i1 (bool) 侧用 zext 对齐(1 保持 1,而非 sext 的 0xFF...) + lhs_bits: int = self.get_llvm_type_bits(lhs.Ty) + rhs_bits: int = self.get_llvm_type_bits(rhs.Ty) + if lhs_bits != 0 and rhs_bits != 0 and lhs_bits != rhs_bits: + if lhs_bits < rhs_bits: + if self.should_zext_widen(pool, lhs, rhs, cmp.left) != 0: + lhs = llvmlite.build_zext(builder, lhs, rhs.Ty) + else: + lhs = llvmlite.build_sext(builder, lhs, rhs.Ty) + else: + if self.should_zext_widen(pool, rhs, lhs, rhs_node) != 0: + rhs = llvmlite.build_zext(builder, rhs, lhs.Ty) + else: + rhs = llvmlite.build_sext(builder, rhs, lhs.Ty) + + # 指针类型对齐:同层级但不同 pointee 类型的指针需要 bitcast 统一类型 + # 例如 i8* vs Struct* → 将 rhs bitcast 为 lhs 的类型 + if lhs_bits == 0 and rhs_bits == 0: + lhs_is_ptr_now: int = self.is_ptr_type(lhs.Ty) + rhs_is_ptr_now: int = self.is_ptr_type(rhs.Ty) + if lhs_is_ptr_now != 0 and rhs_is_ptr_now != 0: + # 两边都是指针,用 TypePrint 比较类型字符串 + lhs_ty_buf: str = pool.alloc(128) + rhs_ty_buf: str = pool.alloc(128) + if lhs_ty_buf is not None and rhs_ty_buf is not None: + llvmlite.TypePrint(lhs_ty_buf, 128, lhs.Ty, pool) + llvmlite.TypePrint(rhs_ty_buf, 128, rhs.Ty, pool) + if string.strcmp(lhs_ty_buf, rhs_ty_buf) != 0: + rhs = llvmlite.build_bitcast(builder, rhs, lhs.Ty) + + # 浮点比较:任一操作数为浮点类型时使用 fcmp 而非 icmp + lhs_fbits: int = self.get_llvm_float_bits(lhs.Ty) + rhs_fbits: int = self.get_llvm_float_bits(rhs.Ty) + if lhs_fbits != 0 or rhs_fbits != 0: + # 浮点类型对齐(fpext/fptrunc) + if lhs_fbits != 0 and rhs_fbits != 0 and lhs_fbits != rhs_fbits: + if lhs_fbits < rhs_fbits: + lhs = llvmlite.build_fpext(builder, lhs, rhs.Ty) + else: + rhs = llvmlite.build_fptrunc(builder, rhs, lhs.Ty) + elif lhs_fbits != 0 and rhs_fbits == 0: + # int → float + rhs = llvmlite.build_si2fp(builder, rhs, lhs.Ty) + elif rhs_fbits != 0 and lhs_fbits == 0: + lhs = llvmlite.build_si2fp(builder, lhs, rhs.Ty) + # 映射比较谓词到 fcmp + fpredicate: int = llvmlite.FCMP_OEQ + if op == ast.OpKind.Eq or op == ast.OpKind.Is: + fpredicate = llvmlite.FCMP_OEQ + elif op == ast.OpKind.Ne or op == ast.OpKind.IsNot: + fpredicate = llvmlite.FCMP_ONE + elif op == ast.OpKind.Lt: + fpredicate = llvmlite.FCMP_OLT + elif op == ast.OpKind.Le: + fpredicate = llvmlite.FCMP_OLE + elif op == ast.OpKind.Gt: + fpredicate = llvmlite.FCMP_OGT + elif op == ast.OpKind.Ge: + fpredicate = llvmlite.FCMP_OGE + return llvmlite.build_fcmp(builder, fpredicate, lhs, rhs) + + return llvmlite.build_icmp(builder, predicate, lhs, rhs) + # ============================================================ + # 翻译一元运算表达式 UnaryOp(op, operand) + # ============================================================ + def translate_unaryop(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译一元运算(-x, +x, not x, ~x)""" + uo: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + if uo is None: + return None + + operand: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, uo.operand, None, 0, trans) + if operand is None: + return None + + # === 一元运算符重载: -obj/+obj/~obj 调用 __neg__/__pos__/__invert__ === + # 仅 USub/UAdd/Invert 有重载语义(not 无 dunder 方法) + if uo.op == ast.OpKind.USub or uo.op == ast.OpKind.UAdd or uo.op == ast.OpKind.Invert: + ovl_u: llvmlite.Value | t.CPtr = self.try_unary_operator_overload( + pool, builder, mod, operand, uo.op, trans) + if ovl_u is not None: + return ovl_u + + if uo.op == ast.OpKind.USub: + # -x + # 浮点类型用 fneg(直接生成 fneg 指令,避免 0.0 - x 的类型不匹配) + operand_fbits: int = self.get_llvm_float_bits(operand.Ty) + if operand_fbits > 0: + return llvmlite.build_fneg(builder, operand) + # 整数类型:-x = 0 - x,根据位宽选择零值常量(避免 i32 与 i64 类型不匹配) + operand_bits: int = self.get_llvm_type_bits(operand.Ty) + zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + if operand_bits == 64: + zero = llvmlite.const_int64(pool, 0) + elif operand_bits > 0 and operand_bits != 32: + # 其他位宽(i8/i16 等):用 i32 零值,operand 会被 coerce + zero = llvmlite.const_int32(pool, 0) + return llvmlite.build_sub(builder, zero, operand) + elif uo.op == ast.OpKind.UAdd: + # +x = x + return operand + elif uo.op == ast.OpKind.Not: + # not x = (x == 0/null),返回 i1 + if self.is_ptr_type(operand.Ty) != 0: + # 指针类型:与 null 比较 + null_op: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, operand.Ty, "null") + return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, operand, null_op) + # 结构体值类型:永远为真(非空),not 返回 false + operand_is_struct_not: int = 0 + match operand.Ty: + case llvmlite.LLVMType.Struct(_, _, _): + operand_is_struct_not = 1 + case _: + operand_is_struct_not = 0 + if operand_is_struct_not != 0: + return llvmlite.const_int(pool, 1, 0) + operand_bits_not: int = self.get_llvm_type_bits(operand.Ty) + zero = llvmlite.const_int32(pool, 0) + if operand_bits_not == 64: + zero = llvmlite.const_int64(pool, 0) + return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, operand, zero) + elif uo.op == ast.OpKind.Invert: + # ~x = x ^ -1 + operand_bits_inv: int = self.get_llvm_type_bits(operand.Ty) + neg1: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, -1) + if operand_bits_inv == 64: + neg1 = llvmlite.const_int64(pool, -1) + return llvmlite.build_xor(builder, operand, neg1) + return operand + # ============================================================ + # 翻译布尔运算 BoolOp(op, values) — 短路求值,返回 i1 + # + # and: a and b and c → 若 a 为假短路到 merge(返回 a 的 i1),否则求 b, + # 最后一个值直接求值并跳 merge + # or: a or b or c → 若 a 为真短路到 merge(返回 a 的 i1),否则求 b, + # 最后一个值直接求值并跳 merge + # merge 块用 phi 合并所有入边的 i1 + # ============================================================ + def translate_boolop(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + funcs_ptr: t.CPtr = None, + func_count: int = 0, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译布尔运算(and/or)的短路求值,返回 i1""" + bo: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) + if bo is None: + return None + + op: int = bo.op + values: list[ast.AST | t.CPtr] | t.CPtr = bo.values + if values is None: + return None + count: t.CSizeT = len(values) + if count == 0: + return None + if count == 1: + return self.Gen.ExprGen.translate_value(builder, pool, mod, values.get(0), + funcs_ptr, func_count, trans) + + func: llvmlite.Function | t.CPtr = builder.Func + if func is None: + return None + + # 创建 merge BB(用 builder.Counter 生成唯一标签名,position_at_end 的 + # move_to_end 保证 BB 文本顺序与控制流顺序一致,标签名用 counter 安全) + cnt: int = builder.Counter + builder.Counter = cnt + 1 + name_buf: str = pool.alloc(32) + if name_buf is None: + return None + viperlib.snprintf(name_buf, 32, "bool.merge.%d", cnt) + merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + # phi 入边链表头/尾 + phi_head: llvmlite.PhiIncoming | t.CPtr = None + phi_tail: llvmlite.PhiIncoming | t.CPtr = None + phi_count: int = count - 1 # 循环次数 + + # 对每个值(除最后一个)求值并短路 + for i in range(count - 1): + val_node: ast.AST | t.CPtr = values.get(i) + val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, val_node, + funcs_ptr, func_count, trans) + if val is None: + return None + + # 转为 i1(已经是 i1 的直接用,否则与 0/null 比较) + val_bits: int = self.get_llvm_type_bits(val.Ty) + val_i1: llvmlite.Value | t.CPtr = val + if val_bits != 1: + if self.is_ptr_type(val.Ty) != 0: + # 指针类型:与 null 比较(避免 i8* 与 i32 类型不匹配) + null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, val.Ty, "null") + val_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, val, null_val) + else: + zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + val_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, val, zero) + + # 创建 next BB(求值下一个值) + cnt = builder.Counter + builder.Counter = cnt + 1 + viperlib.snprintf(name_buf, 32, "bool.next.%d", cnt) + next_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + # and: 短路假→merge,真→next;or: 短路真→merge,假→next + if op == ast.OpKind.And: + llvmlite.build_cond_br(builder, val_i1, next_bb, merge_bb) + else: + llvmlite.build_cond_br(builder, val_i1, merge_bb, next_bb) + + # 添加 phi 入边:(val_i1, cond_br 所在 BB) + cur_bb: llvmlite.BasicBlock | t.CPtr = builder.CurBlock + inc: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming(pool, val_i1, cur_bb) + if phi_head is None: + phi_head = inc + phi_tail = inc + else: + phi_tail.Next = inc + phi_tail = inc + + # 定位到 next BB,求值下一个值 + llvmlite.position_at_end(builder, next_bb) + + # 最后一个值:求值后直接跳 merge + last_node: ast.AST | t.CPtr = values.get(count - 1) + last_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, last_node, + funcs_ptr, func_count, trans) + if last_val is None: + return None + last_bits: int = self.get_llvm_type_bits(last_val.Ty) + last_i1: llvmlite.Value | t.CPtr = last_val + if last_bits != 1: + if self.is_ptr_type(last_val.Ty) != 0: + # 指针类型:与 null 比较(避免 i8* 与 i32 类型不匹配) + null_val2: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, last_val.Ty, "null") + last_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, last_val, null_val2) + else: + zero = llvmlite.const_int32(pool, 0) + last_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, last_val, zero) + + llvmlite.build_br(builder, merge_bb) + + cur_bb = builder.CurBlock + inc = llvmlite.new_phi_incoming(pool, last_i1, cur_bb) + if phi_head is None: + phi_head = inc + else: + phi_tail.Next = inc + phi_count += 1 + + # 定位到 merge,创建 phi 合并所有入边 + llvmlite.position_at_end(builder, merge_bb) + i1_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + return llvmlite.build_phi(builder, i1_ty, phi_head, phi_count) + # ============================================================ + # BinOp 运算符 → dunder 方法名 + # ============================================================ + def _binop_to_dunder(self, op: int) -> str: + """将 BinOp 运算符映射到 dunder 方法名,无映射时返回 None + + Python 3 语义:/ 映射 __truediv__(Python 2 的 __div__ 已废弃)。 + """ + if op == ast.OpKind.Add: return "__add__" + if op == ast.OpKind.Sub: return "__sub__" + if op == ast.OpKind.Mult: return "__mul__" + if op == ast.OpKind.Div: return "__truediv__" + if op == ast.OpKind.Mod: return "__mod__" + if op == ast.OpKind.BitAnd: return "__and__" + if op == ast.OpKind.BitOr: return "__or__" + if op == ast.OpKind.BitXor: return "__xor__" + if op == ast.OpKind.LShift: return "__lshift__" + if op == ast.OpKind.RShift: return "__rshift__" + if op == ast.OpKind.FloorDiv: return "__floordiv__" + return None + # ============================================================ + # Compare 运算符 → dunder 方法名 + # ============================================================ + def _cmpop_to_dunder(self, op: int) -> str: + """将 Compare 运算符映射到 dunder 方法名,无映射时返回 None""" + if op == ast.OpKind.Eq: return "__eq__" + if op == ast.OpKind.Ne: return "__ne__" + if op == ast.OpKind.Lt: return "__lt__" + if op == ast.OpKind.Le: return "__le__" + if op == ast.OpKind.Gt: return "__gt__" + if op == ast.OpKind.Ge: return "__ge__" + return None + # ============================================================ + # UnaryOp 运算符 → dunder 方法名 + # ============================================================ + def _unaryop_to_dunder(self, op: int) -> str: + """将 UnaryOp 运算符映射到 dunder 方法名,无映射时返回 None""" + if op == ast.OpKind.USub: return "__neg__" + if op == ast.OpKind.UAdd: return "__pos__" + if op == ast.OpKind.Invert: return "__invert__" + return None + # ============================================================ + # try_operator_overload - 尝试运算符重载 + # + # 检查 lhs 是否为结构体指针,并在该类(含继承链)中查找对应的 + # dunder 方法。找到则生成方法调用 lhs.__dunder__(rhs),返回 + # 调用结果;未找到返回 None,调用方回退到原生运算。 + # ============================================================ + def try_operator_overload(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + lhs: llvmlite.Value | t.CPtr, + rhs: llvmlite.Value | t.CPtr, + op: int, + trans: HT.Translator | t.CPtr, + is_compare: int) -> llvmlite.Value | t.CPtr: + """尝试运算符重载:lhs 是结构体指针时调用 dunder 方法,否则返回 None""" + if lhs is None or rhs is None: + return None + + # 延迟导入避免循环依赖 + import lib.core.Handles.HandlesStruct as HandlesStruct + import lib.core.Handles.HandlesExprCall as HandlesExprCall + + # 映射运算符到 dunder 方法名 + dunder: str = None + if is_compare != 0: + dunder = self._cmpop_to_dunder(op) + else: + dunder = self._binop_to_dunder(op) + if dunder is None: + return None + + # 检查 lhs 是否为结构体指针 + struct_ty: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type_from_value(lhs) + if struct_ty is None: + return None + + # 获取类名 + class_name: str = self.Gen.StructGen.get_class_name_by_type(pool, struct_ty) + if class_name is None: + return None + + # 在继承链中查找 dunder 方法 + lookup_name: str = pool.alloc(128) + if lookup_name is None: + return None + viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder) + found_func: llvmlite.Function | t.CPtr = self.Gen.CallGenBase.find_func_in_module(mod, lookup_name) + + search_class: str = class_name + if found_func is None: + # 多继承:沿 MRO 祖先链查找(先声明父类优先) + mro_ptr: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, class_name) + mi: int = 1 + while mro_ptr is not None and mro_ptr[mi] != 0: + anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr)) + if anc is not None: + parent_lookup: str = pool.alloc(128) + if parent_lookup is not None: + viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, dunder) + parent_func: llvmlite.Function | t.CPtr = self.Gen.CallGenBase.find_func_in_module(mod, parent_lookup) + if parent_func is not None: + found_func = parent_func + search_class = anc + break + mi += 1 + + # 方法不在当前模块中时,检查类(含父类)是否有 SHA1(stub 可能未注入) + # 优先用类型指针定位 entry 获取 SHA1(规避跨模块同名 find_struct 找错) + cls_sha1: str = None + op_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_type(struct_ty) + if op_entry is not None: + cls_sha1 = op_entry.ModuleSha1 + if cls_sha1 is None: + cls_sha1 = self.Gen.StructGen.get_struct_sha1(search_class) + if cls_sha1 is None: + mro_p: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, search_class) + mj: int = 1 + while mro_p is not None and mro_p[mj] != 0 and cls_sha1 is None: + anc_p: str = (str | t.CPtr)(t.CVoid(mro_p[mj], t.CPtr)) + if anc_p is not None: + cls_sha1 = self.Gen.StructGen.get_struct_sha1(anc_p) + mj += 1 + + # 既无函数定义也无 SHA1 → 该类没有此 dunder 方法,返回 None 回退原生运算 + if found_func is None and cls_sha1 is None: + return None + + # 方法在"定义它的模块"中确实不存在(同模块类但模块内无此 dunder): + # 返回 None 回退原生运算,绝不发出幽灵 call——否则 IR 残留 + # `call void @...__div__`(副作用)且调用方回退原生 sdiv 双重发射, + # llc 报 invalid operand type for instruction(CPythonTest PyFloatObj 根因) + if found_func is None and trans is not None and trans.ModuleSha1 is not None: + if cls_sha1 is not None and string.strcmp(cls_sha1, trans.ModuleSha1) == 0: + return None + # 跨模块类:stub 可能未注入,方法存在性以依赖模块 vpi stub 为准。 + # vpi 未命中(依赖模块确实无此 dunder)→ 回退原生比较(icmp), + # 绝不发幽灵 call——`call @{cls_sha1}.{Class}.{dunder}` 链接 undefined + # (MemBuddy 无 __eq__ 时 os._mbuddy == sys._mbuddy,SysLibTest 根因)。 + vpi_dup: llvmlite.LLVMType | t.CPtr = self.Gen.CallGenBase._lookup_method_ret_ty_via_vpi( + pool, cls_sha1, search_class, dunder) + if vpi_dup is None: + return None + + # 构建 extra_args 数组(仅含 rhs 一个参数) + extra_args: t.CSizeT | t.CPtr = pool.alloc(8) + if extra_args is None: + return None + extra_args[0] = t.CSizeT(rhs) + + # 调用方法: lhs.__dunder__(rhs) + return self.Gen.CallGenCall._call_method_on_ptr( + pool, builder, mod, search_class, dunder, + lhs, extra_args, 1, trans) + # ============================================================ + # try_unary_operator_overload - 尝试一元运算符重载 + # + # 检查 operand 是否为结构体指针,并在该类(含继承链)中查找对应的 + # dunder 方法(__neg__/__pos__/__invert__)。找到则生成方法调用 + # operand.__dunder__(),返回调用结果;未找到返回 None,调用方回退到原生运算。 + # ============================================================ + def try_unary_operator_overload(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + operand: llvmlite.Value | t.CPtr, + op: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """尝试一元运算符重载:operand 是结构体指针时调用 dunder 方法,否则返回 None""" + if operand is None: + return None + + # 延迟导入避免循环依赖 + import lib.core.Handles.HandlesStruct as HandlesStruct + import lib.core.Handles.HandlesExprCall as HandlesExprCall + + dunder: str = self._unaryop_to_dunder(op) + if dunder is None: + return None + + # 检查 operand 是否为结构体指针 + struct_ty: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type_from_value(operand) + if struct_ty is None: + return None + + # 获取类名 + class_name: str = self.Gen.StructGen.get_class_name_by_type(pool, struct_ty) + if class_name is None: + return None + + # 在继承链中查找 dunder 方法 + lookup_name: str = pool.alloc(128) + if lookup_name is None: + return None + viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder) + found_func: llvmlite.Function | t.CPtr = self.Gen.CallGenBase.find_func_in_module(mod, lookup_name) + + search_class: str = class_name + if found_func is None: + # 多继承:沿 MRO 祖先链查找(先声明父类优先) + mro_ptr: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, class_name) + mi: int = 1 + while mro_ptr is not None and mro_ptr[mi] != 0: + anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr)) + if anc is not None: + parent_lookup: str = pool.alloc(128) + if parent_lookup is not None: + viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, dunder) + parent_func: llvmlite.Function | t.CPtr = self.Gen.CallGenBase.find_func_in_module(mod, parent_lookup) + if parent_func is not None: + found_func = parent_func + search_class = anc + break + mi += 1 + + # 方法不在当前模块中时,检查类(含父类)是否有 SHA1(stub 可能未注入) + cls_sha1: str = None + uop_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_type(struct_ty) + if uop_entry is not None: + cls_sha1 = uop_entry.ModuleSha1 + if cls_sha1 is None: + cls_sha1 = self.Gen.StructGen.get_struct_sha1(search_class) + if cls_sha1 is None: + mro_p: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, search_class) + mj: int = 1 + while mro_p is not None and mro_p[mj] != 0 and cls_sha1 is None: + anc_p: str = (str | t.CPtr)(t.CVoid(mro_p[mj], t.CPtr)) + if anc_p is not None: + cls_sha1 = self.Gen.StructGen.get_struct_sha1(anc_p) + mj += 1 + + # 既无函数定义也无 SHA1 → 该类没有此 dunder 方法,返回 None 回退原生运算 + if found_func is None and cls_sha1 is None: + return None + + # 同模块类但模块内无此 dunder → 返回 None 回退原生运算,不发幽灵 call + # (与 try_operator_overload 一致,防 IR 残留 call void @...__neg__) + if found_func is None and trans is not None and trans.ModuleSha1 is not None: + if cls_sha1 is not None and string.strcmp(cls_sha1, trans.ModuleSha1) == 0: + return None + + # 一元方法无额外参数(extra_args 为空) + return self.Gen.CallGenCall._call_method_on_ptr( + pool, builder, mod, search_class, dunder, + operand, None, 0, trans) + # ============================================================ + # 翻译二元运算(自动类型提升) + # ============================================================ + def translate_binop(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译二元运算(自动类型提升)""" + binop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if binop is None: + return None + + lhs_node: ast.AST | t.CPtr = binop.left + rhs_node: ast.AST | t.CPtr = binop.right + op: int = binop.op + + # 先翻译 rhs(只翻译一次,避免副作用重复) + rhs: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, rhs_node, None, 0, trans) + if rhs is None: + return None + + # === 运算符重载路径 1: lhs 是 Name 且对应结构体变量 === + # 对于值类型变量(如 cnt: Counter),translate_value 会 load 返回 Struct 值, + # 但 dunder 方法需要 Ptr(Struct) 作为 self。直接用 alloca 指针尝试重载。 + if lhs_node is not None and lhs_node.kind() == ast.ASTKind.Name and trans is not None: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(lhs_node) + if nm is not None and nm.id is not None: + lhs_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, nm.id) + if lhs_alloca is not None: + ovl_self1: llvmlite.Value | t.CPtr = lhs_alloca + # alloca 是 Ptr(Ptr(Struct))(X|t.CPtr 对象存储槽)时, + # load 出对象指针作为 self——若把槽地址当 self,dunder 内 + # load 槽内容(对象指针值)当字段读 → 垃圾(MultiInheritTest + # Vec2Both __add__ 输出 (1.0,2.0) 根因;get_struct_type_from_value + # 递归解指针后路径 1 能识别 alloca,需同步修正 self 语义) + if lhs_alloca.Ty is not None and lhs_alloca.Ty.Pointee is not None \ + and self.Gen.ExprGenBase.is_ptr_type(lhs_alloca.Ty.Pointee) != 0: + load_self1: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, lhs_alloca.Ty.Pointee, lhs_alloca) + if load_self1 is not None: + ovl_self1 = load_self1 + ovl_result: llvmlite.Value | t.CPtr = self.try_operator_overload( + pool, builder, mod, ovl_self1, rhs, op, trans, 0) + if ovl_result is not None: + return ovl_result + + # 正常翻译 lhs + lhs: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, lhs_node, None, 0, trans) + if lhs is None: + return None + + # === 运算符重载路径 2: lhs 是 Ptr(Struct)(如 Counter|t.CPtr 变量 load 后)=== + ovl_result2: llvmlite.Value | t.CPtr = self.try_operator_overload( + pool, builder, mod, lhs, rhs, op, trans, 0) + if ovl_result2 is not None: + return ovl_result2 + + # 获取操作数类型信息 + lhs_bits: int = self.get_llvm_type_bits(lhs.Ty) + rhs_bits: int = self.get_llvm_type_bits(rhs.Ty) + lhs_fbits: int = self.get_llvm_float_bits(lhs.Ty) + rhs_fbits: int = self.get_llvm_float_bits(rhs.Ty) + + # 浮点运算: 任一操作数为浮点时,使用浮点指令(必须在指针算术之前检查, + # 因为 float 的 int bits 为 0,会被误认为指针) + if lhs_fbits != 0 or rhs_fbits != 0: + # 确定目标浮点类型(使用较大的位宽) + target_fbits: int = lhs_fbits + if rhs_fbits > target_fbits: + target_fbits = rhs_fbits + target_float_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) + if target_fbits == 32: + target_float_ty = llvmlite.Float(pool) + # 将两个操作数转换为目标浮点类型(int→float via si2fp, float→float via fpext/fptrunc) + lhs = self.coerce_to_type(builder, lhs, target_float_ty, node) + rhs = self.coerce_to_type(builder, rhs, target_float_ty, node) + if op == ast.OpKind.Add: + return llvmlite.build_fadd(builder, lhs, rhs) + if op == ast.OpKind.Sub: + return llvmlite.build_fsub(builder, lhs, rhs) + if op == ast.OpKind.Mult: + return llvmlite.build_fmul(builder, lhs, rhs) + if op == ast.OpKind.Div: + return llvmlite.build_fdiv(builder, lhs, rhs) + if op == ast.OpKind.Mod: + return llvmlite.build_frem(builder, lhs, rhs) + return None + + # 指针算术: ptr + int / ptr - int / int + ptr → getelementptr(按元素大小缩放) + # 对齐 TPC ExprGen.emit_binary_op L50-67;int - ptr 无 GEP 形式(C 语义非法) + if (lhs_bits == 0 and rhs_bits != 0) or (lhs_bits != 0 and rhs_bits == 0): + if op == ast.OpKind.Add: + if lhs_bits == 0: + return self.translate_ptr_arith(pool, builder, lhs, rhs, op) + # int + ptr(交换) + return self.translate_ptr_arith(pool, builder, rhs, lhs, op) + if op == ast.OpKind.Sub and lhs_bits == 0: + return self.translate_ptr_arith(pool, builder, lhs, rhs, op) + + if lhs_bits > rhs_bits: + if self.should_zext_widen(pool, rhs, lhs, rhs_node) != 0: + rhs = llvmlite.build_zext(builder, rhs, lhs.Ty) + else: + rhs = self.coerce_to_type(builder, rhs, lhs.Ty, node) + elif rhs_bits > lhs_bits: + if self.should_zext_widen(pool, lhs, rhs, lhs_node) != 0: + lhs = llvmlite.build_zext(builder, lhs, rhs.Ty) + else: + lhs = self.coerce_to_type(builder, lhs, rhs.Ty, node) + + # 位运算类型安全检查:两边都是指针(lhs_bits==0 and rhs_bits==0)时, + # 位运算(BitOr/BitAnd/BitXor/LShift/RShift)非法,LLVM 要求整数操作数。 + # 常见触发场景:CDefine 常量查找失败返回指针 null,与另一指针做 `|`。 + if lhs_bits == 0 and rhs_bits == 0: + if op == ast.OpKind.BitOr or op == ast.OpKind.BitAnd or op == ast.OpKind.BitXor or op == ast.OpKind.LShift or op == ast.OpKind.RShift: + # fail-fast:位运算操作数类型非法,立即终止编译(暴露上游根因) + self.Gen.TypeGenErr.fatal_error( + node, + "位运算操作数类型非法: lhs/rhs 均为非整数类型(指针或结构体),无法执行位运算", + "TypeError") + + if op == ast.OpKind.Add: + return llvmlite.build_add(builder, lhs, rhs) + elif op == ast.OpKind.Sub: + return llvmlite.build_sub(builder, lhs, rhs) + elif op == ast.OpKind.Mult: + return llvmlite.build_mul(builder, lhs, rhs) + elif op == ast.OpKind.Div: + return llvmlite.build_sdiv(builder, lhs, rhs) + elif op == ast.OpKind.FloorDiv: + return llvmlite.build_sdiv(builder, lhs, rhs) + elif op == ast.OpKind.Mod: + return llvmlite.build_srem(builder, lhs, rhs) + elif op == ast.OpKind.BitAnd: + return llvmlite.build_and(builder, lhs, rhs) + elif op == ast.OpKind.BitOr: + return llvmlite.build_or(builder, lhs, rhs) + elif op == ast.OpKind.BitXor: + return llvmlite.build_xor(builder, lhs, rhs) + elif op == ast.OpKind.LShift: + return llvmlite.build_shl(builder, lhs, rhs) + elif op == ast.OpKind.RShift: + # 无符号 >> → lshr(逻辑右移),有符号 >> → ashr(算术右移) + # 对齐 TPC ExprGen.emit_binary_op:i8/i16 默认无符号;其余查操作数无符号性 + if lhs_bits == 8 or lhs_bits == 16: + return llvmlite.build_lshr(builder, lhs, rhs) + if self._node_type_unsigned(pool, lhs_node, trans) != 0: + return llvmlite.build_lshr(builder, lhs, rhs) + return llvmlite.build_ashr(builder, lhs, rhs) return None \ No newline at end of file diff --git a/App/lib/core/Gen/FuncGenBase.vp b/App/lib/core/Gen/FuncGenBase.vp index 8b2e4a6..3c331e7 100644 --- a/App/lib/core/Gen/FuncGenBase.vp +++ b/App/lib/core/Gen/FuncGenBase.vp @@ -1,333 +1,327 @@ -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.HandlesTranslator as HT -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesExpr as HandlesExpr -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.HandlesBody as HandlesBody -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef - - -# ============================================================ -# FuncGenBase - FuncGenMixin 拆分(阶段 D):函数属性 / 命名 / mangle / create_function 基础工具 -# -# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class FuncGenBase(CallGenBase.CallGenBase): - """函数属性 / 命名 / mangle / create_function 基础工具""" - - # ============================================================ - # extract_func_attrs - 从 decorator_list 提取 c.Attribute 属性 - # - # 支持 @c.Attribute(t.attr.xxx()) 和 @c.Attribute(t.attr.xxx) 形式 - # 也支持 @c.Attribute(t.attr.llvm.xxx) 形式 - # - # 返回 LLVM IR 属性字符串(如 "alwaysinline nounwind"),无属性返回 None - # ============================================================ - def extract_func_attrs(self, pool: memhub.MemBuddy | t.CPtr, - decorator_list: list[ast.AST | t.CPtr] | t.CPtr, - imported_modules: str) -> str: - """从 decorator_list 提取 c.Attribute 属性,返回 LLVM IR 属性字符串""" - if decorator_list is None: - return None - dn: t.CSizeT = len(decorator_list) - if dn == 0: - return None - - attrs_buf: str = pool.alloc(256) - if attrs_buf is None: - return None - attrs_buf[0] = '\0' - found_any: int = 0 - - for di in range(dn): - deco: ast.AST | t.CPtr = decorator_list.get(di) - if deco is None or deco.kind() != ast.ASTKind.Call: - continue - call_node: ast.Call | t.CPtr = (ast.Call | t.CPtr)(deco) - if call_node.func is None or call_node.func.kind() != ast.ASTKind.Attribute: - continue - - # 检测 c.Attribute - func_attr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(call_node.func) - if func_attr.attr is None or string.strcmp(func_attr.attr, "Attribute") != 0: - continue - if func_attr.value is None or func_attr.value.kind() != ast.ASTKind.Name: - continue - c_name: ast.Name | t.CPtr = (ast.Name | t.CPtr)(func_attr.value) - if c_name.id is None or string.strcmp(c_name.id, "c") != 0: - continue - if HandlesImports.is_module_imported(imported_modules, "c") == 0: - continue - - # 遍历参数提取属性 - if call_node.args is None: - continue - args_list: list[ast.AST | t.CPtr] | t.CPtr = call_node.args - an: t.CSizeT = len(args_list) - for ai in range(an): - arg_node: ast.AST | t.CPtr = args_list.get(ai) - if arg_node is None: - continue - - # 提取属性名(t.attr.xxx / t.attr.xxx() / t.attr.llvm.xxx) - attr_name: str = self._get_attr_name_from_node(arg_node) - if attr_name is None: - continue - - # 映射到 LLVM 属性名并追加 - if self._append_llvm_attr(attrs_buf, attr_name) != 0: - found_any = 1 - # 追加成功后,如果不是最后一个属性,添加空格分隔 - # 在下一次追加前由 _append_str 处理 - - if found_any == 0: - return None - return attrs_buf - def _get_attr_name_from_node(self, node: ast.AST | t.CPtr) -> str: - """从 AST 节点提取属性名 - - 支持: - - Call(func=Attribute(...)): t.attr.always_inline() -> "always_inline" - - Attribute: t.attr.packed -> "packed" - - Attribute(t.attr.llvm.xxx): t.attr.llvm.nounwind -> "nounwind" - """ - if node is None: - return None - k: int = node.kind() - - # Call 节点: t.attr.always_inline() - if k == ast.ASTKind.Call: - call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) - if call.func is None or call.func.kind() != ast.ASTKind.Attribute: - return None - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(call.func) - return at.attr - - # Attribute 节点: t.attr.packed 或 t.attr.llvm.nounwind - if k == ast.ASTKind.Attribute: - at2: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - return at2.attr - - return None - def _append_llvm_attr(self, attrs_buf: str, attr_name: str) -> int: - """将属性名映射到 LLVM 属性名并追加到缓冲区 - - 返回 1 表示已追加,0 表示不支持该属性 - """ - if attrs_buf is None or attr_name is None: - return 0 - - # 先确定映射的 LLVM 属性名 - llvm_name: str = None - if string.strcmp(attr_name, "always_inline") == 0: - llvm_name = "alwaysinline" - elif string.strcmp(attr_name, "noinline") == 0: - llvm_name = "noinline" - elif string.strcmp(attr_name, "noreturn") == 0: - llvm_name = "noreturn" - elif string.strcmp(attr_name, "pure") == 0: - llvm_name = "readonly" - elif string.strcmp(attr_name, "const") == 0: - llvm_name = "readnone" - elif string.strcmp(attr_name, "nounwind") == 0: - llvm_name = "nounwind" - elif string.strcmp(attr_name, "noredzone") == 0: - llvm_name = "noredzone" - elif string.strcmp(attr_name, "willreturn") == 0: - llvm_name = "willreturn" - elif string.strcmp(attr_name, "mustprogress") == 0: - llvm_name = "mustprogress" - else: - # packed/aligned/section/visibility/weak 等不支持作为函数内联属性 - return 0 - - # 支持的属性:如果缓冲区非空,先追加空格分隔 - if attrs_buf[0] != '\0': - self._append_str(attrs_buf, " ") - self._append_str(attrs_buf, llvm_name) - return 1 - def _append_str(self, buf: str, s: str, - max_len: t.CSizeT = 256) -> None: - """将字符串追加到 buf 末尾(有界,防 strcpy 越界写穿定长缓冲)""" - if buf is None or s is None: - return - cur_len: t.CSizeT = string.strlen(buf) - s_len: t.CSizeT = string.strlen(s) - if cur_len + s_len + 1 > max_len: - return # 无剩余容量:丢弃本次追加,避免越界写 - string.strcpy(buf + cur_len, s) - # ============================================================ - # _mangle_name - 为名称添加 SHA1 前缀 - # - # 返回 "sha1.name" 格式的混淆名。若 ModuleSha1 为 None 或名称已带 - # SHA1 前缀(16 hex + '.'),则原样返回。 - # ============================================================ - def _mangle_name(self, trans: HT.Translator | t.CPtr, name: str) -> str: - """为任意名称添加 SHA1 前缀(不做 main/export 检查)""" - if trans is None or name is None: - return name - if trans.ModuleSha1 is None: - return name - name_len: t.CSizeT = string.strlen(name) - # 已带 SHA1 前缀(16 hex + '.')则跳过 - if name_len > 17: - is_sha1: int = 1 - for i in range(16): - c: t.CChar = name[i] - if not (('0' <= c <= '9') or ('a' <= c <= 'f')): - is_sha1 = 0 - break - if is_sha1 != 0 and name[16] == '.': - return name - sha1: str = trans.ModuleSha1 - sha1_len: t.CSizeT = string.strlen(sha1) - mangled: str = stdlib.malloc(sha1_len + name_len + 2) - if mangled is None: - return name - string.strcpy(mangled, sha1) - mangled[sha1_len] = '.' - string.strcpy(mangled + sha1_len + 1, name) - return mangled - # ============================================================ - # _mangle_name_with_sha1 — 用指定 SHA1 为名称添加前缀 - # - # 用于跨模块 vtable 继承: 继承方法需要用父模块的 SHA1 做 mangling, - # 而非当前模块的 SHA1。 - # ============================================================ - def _mangle_name_with_sha1(self, sha1: str, name: str) -> str: - """用指定 SHA1 为名称添加前缀(不做 main/export 检查)""" - if sha1 is None or name is None: - return name - name_len: t.CSizeT = string.strlen(name) - # 已带 SHA1 前缀(16 hex + '.')则跳过 - if name_len > 17: - is_sha1: int = 1 - for i in range(16): - c2: t.CChar = name[i] - if not (('0' <= c2 <= '9') or ('a' <= c2 <= 'f')): - is_sha1 = 0 - break - if is_sha1 != 0 and name[16] == '.': - return name - sha1_len: t.CSizeT = string.strlen(sha1) - mangled: str = stdlib.malloc(sha1_len + name_len + 2) - if mangled is None: - return name - string.strcpy(mangled, sha1) - mangled[sha1_len] = '.' - string.strcpy(mangled + sha1_len + 1, name) - return mangled - # ============================================================ - # _mangle_func_name - 为函数名添加 SHA1 前缀(含 main/export 检查) - # - # 规则: - # - main 函数不加前缀(程序入口点) - # - has_export 非 0 时不加前缀(t.CExport 导出函数) - # - 已带 SHA1 前缀的不再加 - # - ModuleSha1 为 None 时不加前缀 - # ============================================================ - def _mangle_func_name(self, trans: HT.Translator | t.CPtr, name: str, - has_export: int) -> str: - """为函数名添加 SHA1 前缀(检查 main/export)""" - if trans is None or name is None: - return name - if has_export != 0: - return name - if string.strcmp(name, "main") == 0: - return name - return self._mangle_name(trans, name) - # ============================================================ - # _body_has_raise - 函数体是否含 raise(非 StopIteration) - # - # 对齐 TPC HandlesFunctions.py L216-243 _body_contains_raise:函数签名 - # 追加 __eh_msg_out__/__eh_code_out__ 输出参数的条件。v1 只扫函数体 - # 顶层 raise(嵌套 if/for/try 内的 raise 未覆盖,后续扩展)。 - # ============================================================ - def _body_has_raise(self, fd: ast.FunctionDef | t.CPtr) -> int: - """函数体顶层是否含 raise(非 StopIteration),1=是 / 0=否""" - if fd is None or fd.children is None: - return 0 - body_f: list[ast.AST | t.CPtr] | t.CPtr = fd.children - bn_f: t.CSizeT = len(body_f) - for bi_f in range(bn_f): - stmt_f: ast.AST | t.CPtr = body_f.get(bi_f) - if stmt_f is None: - continue - if stmt_f.kind() != ast.ASTKind.Raise: - continue - rn_f: ast.Raise | t.CPtr = (ast.Raise | t.CPtr)(stmt_f) - if rn_f is None or rn_f.exc is None: - continue - ek_f: int = rn_f.exc.kind() - is_stop_f: int = 0 - if ek_f == ast.ASTKind.Name: - enm_f: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rn_f.exc) - if enm_f.id is not None and string.strcmp(enm_f.id, "StopIteration") == 0: - is_stop_f = 1 - elif ek_f == ast.ASTKind.Call: - ecl_f: ast.Call | t.CPtr = (ast.Call | t.CPtr)(rn_f.exc) - if ecl_f.func is not None and ecl_f.func.kind() == ast.ASTKind.Name: - ecn_f: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ecl_f.func) - if ecn_f.id is not None and string.strcmp(ecn_f.id, "StopIteration") == 0: - is_stop_f = 1 - if is_stop_f == 0: - return 1 - return 0 - # ============================================================ - # 创建 LLVM 函数(简单版本,仅声明) - # ============================================================ - def create_function(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - name: str, - args_node: ast.AST | t.CPtr, - ret_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Function | t.CPtr: - """创建 LLVM 函数并添加参数""" - if name is None or mod is None: - return None - - func: llvmlite.Function | t.CPtr = llvmlite.create_function(pool, mod, name, ret_ty) - if func is None: - return None - - if args_node is not None: - ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) - if ags.args is not None: - alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args - an: t.CSizeT = len(alist) - 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: - # t.CVoid 表示空参:跳过 - if arg.annotation is not None: - if arg.annotation.kind() == ast.ASTKind.Attribute: - at_cf: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg.annotation) - if at_cf.attr is not None and string.strcmp(at_cf.attr, "CVoid") == 0: - continue - param_ty: llvmlite.LLVMType | t.CPtr = i32_ty - if arg.annotation is not None: - resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, arg.annotation, None, None, None) - if resolved is not None: - param_ty = resolved - pname: str = pool.alloc(32) - if pname is not None: - viperlib.snprintf(pname, 32, "%%%s", arg.arg) - llvmlite.add_param(pool, func, param_ty, pname) - +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.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall + + +# ============================================================ +# FuncGenBase - FuncGenMixin 拆分(阶段 D):函数属性 / 命名 / mangle / create_function 基础工具 +# +# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class FuncGenBase(CallGenBase.CallGenBase): + """函数属性 / 命名 / mangle / create_function 基础工具""" + + # ============================================================ + # extract_func_attrs - 从 decorator_list 提取 c.Attribute 属性 + # + # 支持 @c.Attribute(t.attr.xxx()) 和 @c.Attribute(t.attr.xxx) 形式 + # 也支持 @c.Attribute(t.attr.llvm.xxx) 形式 + # + # 返回 LLVM IR 属性字符串(如 "alwaysinline nounwind"),无属性返回 None + # ============================================================ + def extract_func_attrs(self, pool: memhub.MemBuddy | t.CPtr, + decorator_list: list[ast.AST | t.CPtr] | t.CPtr, + imported_modules: str) -> str: + """从 decorator_list 提取 c.Attribute 属性,返回 LLVM IR 属性字符串""" + if decorator_list is None: + return None + dn: t.CSizeT = len(decorator_list) + if dn == 0: + return None + + attrs_buf: str = pool.alloc(256) + if attrs_buf is None: + return None + attrs_buf[0] = '\0' + found_any: int = 0 + + for di in range(dn): + deco: ast.AST | t.CPtr = decorator_list.get(di) + if deco is None or deco.kind() != ast.ASTKind.Call: + continue + call_node: ast.Call | t.CPtr = (ast.Call | t.CPtr)(deco) + if call_node.func is None or call_node.func.kind() != ast.ASTKind.Attribute: + continue + + # 检测 c.Attribute + func_attr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(call_node.func) + if func_attr.attr is None or string.strcmp(func_attr.attr, "Attribute") != 0: + continue + if func_attr.value is None or func_attr.value.kind() != ast.ASTKind.Name: + continue + c_name: ast.Name | t.CPtr = (ast.Name | t.CPtr)(func_attr.value) + if c_name.id is None or string.strcmp(c_name.id, "c") != 0: + continue + if self.Gen.ImportsGen.is_module_imported(imported_modules, "c") == 0: + continue + + # 遍历参数提取属性 + if call_node.args is None: + continue + args_list: list[ast.AST | t.CPtr] | t.CPtr = call_node.args + an: t.CSizeT = len(args_list) + for ai in range(an): + arg_node: ast.AST | t.CPtr = args_list.get(ai) + if arg_node is None: + continue + + # 提取属性名(t.attr.xxx / t.attr.xxx() / t.attr.llvm.xxx) + attr_name: str = self._get_attr_name_from_node(arg_node) + if attr_name is None: + continue + + # 映射到 LLVM 属性名并追加 + if self._append_llvm_attr(attrs_buf, attr_name) != 0: + found_any = 1 + # 追加成功后,如果不是最后一个属性,添加空格分隔 + # 在下一次追加前由 _append_str 处理 + + if found_any == 0: + return None + return attrs_buf + def _get_attr_name_from_node(self, node: ast.AST | t.CPtr) -> str: + """从 AST 节点提取属性名 + + 支持: + - Call(func=Attribute(...)): t.attr.always_inline() -> "always_inline" + - Attribute: t.attr.packed -> "packed" + - Attribute(t.attr.llvm.xxx): t.attr.llvm.nounwind -> "nounwind" + """ + if node is None: + return None + k: int = node.kind() + + # Call 节点: t.attr.always_inline() + if k == ast.ASTKind.Call: + call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + if call.func is None or call.func.kind() != ast.ASTKind.Attribute: + return None + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(call.func) + return at.attr + + # Attribute 节点: t.attr.packed 或 t.attr.llvm.nounwind + if k == ast.ASTKind.Attribute: + at2: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + return at2.attr + + return None + def _append_llvm_attr(self, attrs_buf: str, attr_name: str) -> int: + """将属性名映射到 LLVM 属性名并追加到缓冲区 + + 返回 1 表示已追加,0 表示不支持该属性 + """ + if attrs_buf is None or attr_name is None: + return 0 + + # 先确定映射的 LLVM 属性名 + llvm_name: str = None + if string.strcmp(attr_name, "always_inline") == 0: + llvm_name = "alwaysinline" + elif string.strcmp(attr_name, "noinline") == 0: + llvm_name = "noinline" + elif string.strcmp(attr_name, "noreturn") == 0: + llvm_name = "noreturn" + elif string.strcmp(attr_name, "pure") == 0: + llvm_name = "readonly" + elif string.strcmp(attr_name, "const") == 0: + llvm_name = "readnone" + elif string.strcmp(attr_name, "nounwind") == 0: + llvm_name = "nounwind" + elif string.strcmp(attr_name, "noredzone") == 0: + llvm_name = "noredzone" + elif string.strcmp(attr_name, "willreturn") == 0: + llvm_name = "willreturn" + elif string.strcmp(attr_name, "mustprogress") == 0: + llvm_name = "mustprogress" + else: + # packed/aligned/section/visibility/weak 等不支持作为函数内联属性 + return 0 + + # 支持的属性:如果缓冲区非空,先追加空格分隔 + if attrs_buf[0] != '\0': + self._append_str(attrs_buf, " ") + self._append_str(attrs_buf, llvm_name) + return 1 + def _append_str(self, buf: str, s: str, + max_len: t.CSizeT = 256) -> None: + """将字符串追加到 buf 末尾(有界,防 strcpy 越界写穿定长缓冲)""" + if buf is None or s is None: + return + cur_len: t.CSizeT = string.strlen(buf) + s_len: t.CSizeT = string.strlen(s) + if cur_len + s_len + 1 > max_len: + return # 无剩余容量:丢弃本次追加,避免越界写 + string.strcpy(buf + cur_len, s) + # ============================================================ + # _mangle_name - 为名称添加 SHA1 前缀 + # + # 返回 "sha1.name" 格式的混淆名。若 ModuleSha1 为 None 或名称已带 + # SHA1 前缀(16 hex + '.'),则原样返回。 + # ============================================================ + def _mangle_name(self, trans: HT.Translator | t.CPtr, name: str) -> str: + """为任意名称添加 SHA1 前缀(不做 main/export 检查)""" + if trans is None or name is None: + return name + if trans.ModuleSha1 is None: + return name + name_len: t.CSizeT = string.strlen(name) + # 已带 SHA1 前缀(16 hex + '.')则跳过 + if name_len > 17: + is_sha1: int = 1 + for i in range(16): + c: t.CChar = name[i] + if not (('0' <= c <= '9') or ('a' <= c <= 'f')): + is_sha1 = 0 + break + if is_sha1 != 0 and name[16] == '.': + return name + sha1: str = trans.ModuleSha1 + sha1_len: t.CSizeT = string.strlen(sha1) + mangled: str = stdlib.malloc(sha1_len + name_len + 2) + if mangled is None: + return name + string.strcpy(mangled, sha1) + mangled[sha1_len] = '.' + string.strcpy(mangled + sha1_len + 1, name) + return mangled + # ============================================================ + # _mangle_name_with_sha1 — 用指定 SHA1 为名称添加前缀 + # + # 用于跨模块 vtable 继承: 继承方法需要用父模块的 SHA1 做 mangling, + # 而非当前模块的 SHA1。 + # ============================================================ + def _mangle_name_with_sha1(self, sha1: str, name: str) -> str: + """用指定 SHA1 为名称添加前缀(不做 main/export 检查)""" + if sha1 is None or name is None: + return name + name_len: t.CSizeT = string.strlen(name) + # 已带 SHA1 前缀(16 hex + '.')则跳过 + if name_len > 17: + is_sha1: int = 1 + for i in range(16): + c2: t.CChar = name[i] + if not (('0' <= c2 <= '9') or ('a' <= c2 <= 'f')): + is_sha1 = 0 + break + if is_sha1 != 0 and name[16] == '.': + return name + sha1_len: t.CSizeT = string.strlen(sha1) + mangled: str = stdlib.malloc(sha1_len + name_len + 2) + if mangled is None: + return name + string.strcpy(mangled, sha1) + mangled[sha1_len] = '.' + string.strcpy(mangled + sha1_len + 1, name) + return mangled + # ============================================================ + # _mangle_func_name - 为函数名添加 SHA1 前缀(含 main/export 检查) + # + # 规则: + # - main 函数不加前缀(程序入口点) + # - has_export 非 0 时不加前缀(t.CExport 导出函数) + # - 已带 SHA1 前缀的不再加 + # - ModuleSha1 为 None 时不加前缀 + # ============================================================ + def _mangle_func_name(self, trans: HT.Translator | t.CPtr, name: str, + has_export: int) -> str: + """为函数名添加 SHA1 前缀(检查 main/export)""" + if trans is None or name is None: + return name + if has_export != 0: + return name + if string.strcmp(name, "main") == 0: + return name + return self._mangle_name(trans, name) + # ============================================================ + # _body_has_raise - 函数体是否含 raise(非 StopIteration) + # + # 对齐 TPC HandlesFunctions.py L216-243 _body_contains_raise:函数签名 + # 追加 __eh_msg_out__/__eh_code_out__ 输出参数的条件。v1 只扫函数体 + # 顶层 raise(嵌套 if/for/try 内的 raise 未覆盖,后续扩展)。 + # ============================================================ + def _body_has_raise(self, fd: ast.FunctionDef | t.CPtr) -> int: + """函数体顶层是否含 raise(非 StopIteration),1=是 / 0=否""" + if fd is None or fd.children is None: + return 0 + body_f: list[ast.AST | t.CPtr] | t.CPtr = fd.children + bn_f: t.CSizeT = len(body_f) + for bi_f in range(bn_f): + stmt_f: ast.AST | t.CPtr = body_f.get(bi_f) + if stmt_f is None: + continue + if stmt_f.kind() != ast.ASTKind.Raise: + continue + rn_f: ast.Raise | t.CPtr = (ast.Raise | t.CPtr)(stmt_f) + if rn_f is None or rn_f.exc is None: + continue + ek_f: int = rn_f.exc.kind() + is_stop_f: int = 0 + if ek_f == ast.ASTKind.Name: + enm_f: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rn_f.exc) + if enm_f.id is not None and string.strcmp(enm_f.id, "StopIteration") == 0: + is_stop_f = 1 + elif ek_f == ast.ASTKind.Call: + ecl_f: ast.Call | t.CPtr = (ast.Call | t.CPtr)(rn_f.exc) + if ecl_f.func is not None and ecl_f.func.kind() == ast.ASTKind.Name: + ecn_f: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ecl_f.func) + if ecn_f.id is not None and string.strcmp(ecn_f.id, "StopIteration") == 0: + is_stop_f = 1 + if is_stop_f == 0: + return 1 + return 0 + # ============================================================ + # 创建 LLVM 函数(简单版本,仅声明) + # ============================================================ + def create_function(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + name: str, + args_node: ast.AST | t.CPtr, + ret_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Function | t.CPtr: + """创建 LLVM 函数并添加参数""" + if name is None or mod is None: + return None + + func: llvmlite.Function | t.CPtr = llvmlite.create_function(pool, mod, name, ret_ty) + if func is None: + return None + + if args_node is not None: + ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if ags.args is not None: + alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args + an: t.CSizeT = len(alist) + 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: + # t.CVoid 表示空参:跳过 + if arg.annotation is not None: + if arg.annotation.kind() == ast.ASTKind.Attribute: + at_cf: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg.annotation) + if at_cf.attr is not None and string.strcmp(at_cf.attr, "CVoid") == 0: + continue + param_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if arg.annotation is not None: + resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, arg.annotation, None, None, None) + if resolved is not None: + param_ty = resolved + pname: str = pool.alloc(32) + if pname is not None: + viperlib.snprintf(pname, 32, "%%%s", arg.arg) + llvmlite.add_param(pool, func, param_ty, pname) + return func \ No newline at end of file diff --git a/App/lib/core/Gen/FuncGenDef.vp b/App/lib/core/Gen/FuncGenDef.vp index 5062afe..2099482 100644 --- a/App/lib/core/Gen/FuncGenDef.vp +++ b/App/lib/core/Gen/FuncGenDef.vp @@ -1,1239 +1,1232 @@ -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.HandlesTranslator as HT -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesExpr as HandlesExpr -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.HandlesBody as HandlesBody -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.ExprCallBase as ExprCallBase -import lib.core.Handles.ExprCallHandle as ExprCallHandle -import lib.core.Handles.ExprCallTable as ExprCallTable - - -# ============================================================ -# FuncGenDef - FuncGenMixin 拆分(阶段 D):函数声明 / translate_function_def / decorator wrapper -# -# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class FuncGenDef(CallGenBase.CallGenBase): - """函数声明 / translate_function_def / decorator wrapper""" - - # ============================================================ - # forward_declare_functions - 预扫描所有顶层 FunctionDef,创建前向声明 - # - # 解决同模块内前向引用问题:如 viperlib.py 中 sprintf(行15) 调用 - # vsnprintf(行41),但 vsnprintf 定义在后面。 - # - # 对每个顶层 FunctionDef: - # 1. 推断返回类型和参数类型 - # 2. 计算 mangled name(含 SHA1 前缀) - # 3. 创建 declare(IsDeclared=1) - # 4. 添加参数 - # 5. 注册到函数表 - # - # 后续 translate_function_def 会通过 find_func_in_module 找到已有的 declare, - # 复用之(清除 IsDeclared,跳过参数创建,直接添加函数体)。 - # ============================================================ - def forward_declare_functions(self, trans: HT.Translator | t.CPtr, - tree: ast.AST | t.CPtr) -> int: - """预扫描所有顶层 FunctionDef,创建前向声明""" - if trans is None or tree is None: - return 0 - pool: memhub.MemBuddy | t.CPtr = trans.Pool - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - if pool is None or mod is None: - return 0 - - imported_modules: str = trans._imported_modules - from_imports: str = trans._from_imports - funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children - if ch is None: - return 0 - - # 解析函数签名期间临时切换到"仅声明"模式: - # 签名里的泛型类注解(如 _empty_like(a: ndarray[t.CDouble]))会触发泛型特化, - # 若此时特化立即翻译方法体,方法体前向引用同模块后续函数(如 _empty_like 自身) - # 会因 declare 尚未创建而报"裸名调用未定义且未导入"。 - # 临时 declare_only=1 使特化只注册结构体(mark_only 不译方法体), - # 方法体由后续 resolve_annotation_type 命中已注册结构体时补译 - # (_specialize_generic_class 的 Phase B 补译分支)。 - saved_declare_only: int = trans._declare_only - trans._declare_only = 1 - cn_count: t.CSizeT = len(ch) - - for ci in range(cn_count): - child: ast.AST | t.CPtr = ch.get(ci) - if child is None: - continue - if child.kind() != ast.ASTKind.FunctionDef: - continue - fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child) - if fd is None or fd.name is None: - continue - - # 推断返回类型 - ret_ty: llvmlite.LLVMType | t.CPtr = None - if fd.returns is not None: - ret_ty = HandlesType.resolve_annotation_type( - pool, fd.returns, imported_modules, from_imports, trans) - if ret_ty is None and fd.returns is not None: - if HandlesType.has_decorator_marker(fd.returns, "State") != 0: - ret_ty = llvmlite.Void(pool) - if ret_ty is None: - ret_ty = i32_ty - - # 检测 CExtern/State/CExport - has_extern: int = 0 - has_state: int = 0 - has_export: int = 0 - if fd.returns is not None: - has_extern = HandlesType.has_decorator_marker(fd.returns, "CExtern") - has_state = HandlesType.has_decorator_marker(fd.returns, "State") - has_export = HandlesType.has_decorator_marker(fd.returns, "CExport") - # 装饰器形式存储类标记(@t.CExport/@t.CExtern/@t.State/@t.CStatic) - # 对齐 TPC HandlesFunctions._extract_decorator_storage_flags; - # CExport/CExtern/State 影响函数名(导出裸名),CStatic 仅标记。 - # 注意: 用 HandlesClassDef._has_decorator 委托而非 self._has_decorator - # (Mixin 是 @t.NoVTable 静态绑定,跨 Mixin 方法经 MRO 调用会生成 - # 不存在的 FuncGenMixin._has_decorator → 链接 undefined symbol) - if fd.decorator_list is not None: - if has_extern == 0 and HandlesClassDef._has_decorator(fd.decorator_list, "CExtern") == 1: - has_extern = 1 - if has_state == 0 and HandlesClassDef._has_decorator(fd.decorator_list, "State") == 1: - has_state = 1 - if has_export == 0 and HandlesClassDef._has_decorator(fd.decorator_list, "CExport") == 1: - has_export = 1 - is_extern_decl: int = 0 - if has_extern != 0 or has_state != 0: - is_extern_decl = 1 - - # 计算 mangled name - if has_extern != 0 or has_state != 0 or has_export != 0 or string.strcmp(fd.name, "main") == 0: - mangled_name: str = fd.name - else: - mangled_name = ExprCallHandle._mangle_func_name(trans, fd.name, 0) - - # 如果函数已存在(如重复定义),跳过 - existing: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module(mod, mangled_name) - if existing is not None: - continue - - # 创建 declare - func: llvmlite.Function | t.CPtr = llvmlite.create_declare( - pool, mod, mangled_name, ret_ty) - if func is None: - continue - - # 提取默认参数信息 - # 注意: 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(), - # 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错 - fd_args_node: ast.Arguments | t.CPtr = fd.args - fd_defaults: t.CVoid | t.CPtr = None - fd_default_count: int = 0 - fd_param_count: int = 0 - if fd_args_node is not None: - fd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd_args_node) - if fd_ags.args is not None: - fd_alist: list[ast.AST | t.CPtr] | t.CPtr = fd_ags.args - fd_param_count = len(fd_alist) - if fd_ags.defaults is not None: - fd_dlist: list[ast.AST | t.CPtr] | t.CPtr = fd_ags.defaults - fd_defaults = fd_dlist - fd_default_count = len(fd_dlist) - - # 注册到函数表(用裸名 fd.name,不是 mangled_name) - max_funcs: int = 1024 - cur_count: int = trans._func_count - if ExprCallTable.add_func_to_table(funcs_ptr, cur_count, fd.name, func, max_funcs, - fd_defaults, fd_default_count, fd_param_count, - trans.Pool) == 0: - trans._func_count = cur_count + 1 - - # 注册 CExport 函数到全局表 - if (has_export != 0 or has_state != 0) and trans.ModuleSha1 is not None: - ExprCallBase.register_cexport_func(trans.ModuleSha1, fd.name) - - # 添加参数 - args_node: ast.Arguments | t.CPtr = fd.args - if args_node is not None: - ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) - if ags.args is not None: - alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args - an: t.CSizeT = len(alist) - for ai in range(an): - arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) - if arg is None or arg.arg is None: - continue - # t.CVoid 表示空参:跳过 - if arg.annotation is not None: - if HandlesType._is_t_attr(arg.annotation, "CVoid", imported_modules) != 0: - continue - param_ty: llvmlite.LLVMType | t.CPtr = i32_ty - if arg.annotation is not None: - resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, arg.annotation, imported_modules, from_imports, trans) - if resolved is not None: - # 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致) - # CArray 形参 → 元素指针 ty*(C 数组衰减,与 add_param 一致) - match resolved: - case llvmlite.LLVMType.Struct(_, _, _): - param_ty = llvmlite.Ptr(pool, resolved) - case llvmlite.LLVMType.Array(aelem_ty, _): - param_ty = llvmlite.Ptr(pool, aelem_ty) - case _: - param_ty = resolved - pname: str = pool.alloc(32) - if pname is not None: - viperlib.snprintf(pname, 32, "%%%s", arg.arg) - llvmlite.add_param(pool, func, param_ty, pname) - - # *args 变长参数:设置 IsVarArg=1,生成 ... 后缀 - if ags.vararg is not None: - func.IsVarArg = 1 - - # 参数添加完成,补全全局函数表的 TypeStr(供 vtable 在 func 被 reset 后使用) - ExprCallTable.update_global_func_typestr(trans.Pool, fd.name, func) - - # 恢复原始声明模式 - trans._declare_only = saved_declare_only - return 0 - # ============================================================ - # 翻译函数定义 FunctionDef(name, args, body, ...) - # - # trans 单参模式:所有共享状态从 trans 获取 - # 函数局部作用域通过 enter_scope/exit_scope 管理 - # ============================================================ - def translate_function_def(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译函数定义,返回新增的变量数(通常为 0,函数定义不增加当前作用域变量)""" - fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node) - if fd is None or fd.name is None: - return 0 - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - imported_modules: str = trans._imported_modules - from_imports: str = trans._from_imports - funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs - func_count: int = trans._func_count - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - - # 推断返回类型:优先使用返回类型注解 - ret_ty: llvmlite.LLVMType | t.CPtr = None - if fd.returns is not None: - ret_ty = HandlesType.resolve_annotation_type( - pool, fd.returns, imported_modules, from_imports, trans) - - # 如果返回类型注解纯装饰器标记(如 t.State,无实际类型),使用 void - # 注意:必须在 infer_return_type 之前检测,因为 infer_return_type 至少返回 i32 - if ret_ty is None and fd.returns is not None: - if HandlesType.has_decorator_marker(fd.returns, "State") != 0: - ret_ty = llvmlite.Void(pool) - - # 如果仍然为 None,扫描 return 语句推断(至少返回 i32) - if ret_ty is None: - param_types_str: str = HandlesType.build_param_types_str(pool, fd.args) - ret_ty = HandlesType.infer_return_type( - pool, fd.children, param_types_str) - # 检测是否为外部声明函数(t.CExtern 或 t.State) - # 语义:t.CExtern 忽略 body 体,仅生成 declare(由链接器解析符号) - # t.State = t.CExtern + t.CExport(既是声明又是导出) - # t.CExport 导出函数不加 SHA1 前缀 - # t.CExtern/t.State/t.CExport 都不加 SHA1 前缀,直接映射到 C 标准库函数名 - is_extern_decl: int = 0 - has_export: int = 0 - has_extern: int = 0 - has_state: int = 0 - if fd.returns is not None: - has_extern = HandlesType.has_decorator_marker(fd.returns, "CExtern") - has_state = HandlesType.has_decorator_marker(fd.returns, "State") - has_export = HandlesType.has_decorator_marker(fd.returns, "CExport") - # t.CExtern/t.State 忽略 body 体,仅声明(无论 body 是否为 pass) - if has_extern != 0 or has_state != 0: - is_extern_decl = 1 - # 装饰器形式存储类标记(@t.CExport/@t.CExtern/@t.State/@t.CStatic), - # 对齐 TPC HandlesFunctions._extract_decorator_storage_flags(与 - # forward_declare_functions 一致,保证 declare 与 define 同名同语义)。 - # 用 HandlesClassDef._has_decorator 委托(Mixin 静态绑定不能 self. 跨类调) - if fd.decorator_list is not None: - if has_extern == 0 and HandlesClassDef._has_decorator(fd.decorator_list, "CExtern") == 1: - has_extern = 1 - if has_state == 0 and HandlesClassDef._has_decorator(fd.decorator_list, "State") == 1: - has_state = 1 - if has_export == 0 and HandlesClassDef._has_decorator(fd.decorator_list, "CExport") == 1: - has_export = 1 - if (has_extern != 0 or has_state != 0) and is_extern_decl == 0: - is_extern_decl = 1 - # @t.TLS 一次性初始化标记(对齐 TPC HandlesFunctions.py L1223-1231) - has_tls: int = 0 - if fd.decorator_list is not None: - has_tls = HandlesClassDef._has_decorator(fd.decorator_list, "TLS") - - # 自定义行为装饰器检测(@log/@skip/@repeat(3) 等):非 t 存储标记、 - # 非内置(staticmethod/property/classmethod)的 Name/Name(args) 装饰器。 - # 对齐 TPC HandlesFunctions.py L1161-1189 + DecoratorPass.py。首版取 - # decorator_list 中第一个自定义装饰器(Python 最外层),链式嵌套后续扩展。 - has_custom_decor: int = 0 - decor_handler: str = None - decor_arg0: t.CInt64T = 0 - if fd.decorator_list is not None: - ddn: t.CSizeT = len(fd.decorator_list) - for ddi in range(ddn): - deco: ast.AST | t.CPtr = fd.decorator_list.get(ddi) - if deco is None: - continue - dk: int = deco.kind() - dname: str = None - if dk == ast.ASTKind.Name: - dnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(deco) - dname = dnm.id - elif dk == ast.ASTKind.Call: - dcl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(deco) - if dcl.func is not None and dcl.func.kind() == ast.ASTKind.Name: - dnm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(dcl.func) - dname = dnm2.id - # @repeat(3):取首个常量 int 参数(对齐 TPC L1182-1184) - if dcl.args is not None and len(dcl.args) >= 1: - da0: ast.AST | t.CPtr = dcl.args.get(0) - if da0 is not None and da0.kind() == ast.ASTKind.Constant: - dc0: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(da0) - if dc0.const_kind == ast.CONST_INT: - decor_arg0 = dc0.int_val - if dname is None: - continue - # 跳过内置装饰器 - if string.strcmp(dname, "staticmethod") == 0 \ - or string.strcmp(dname, "property") == 0 \ - or string.strcmp(dname, "classmethod") == 0: - continue - # 跳过 t 模块存储类标记(@t.CExport/@t.CExtern/@t.State/@t.TLS/ - # @t.CStatic/@t.CInline/@t.CVTable/@t.NoVTable/@t.Object/@t.CEnum - # /@t.CUnion/@t.REnum/@t.CDefine 等裸名形式——Attribute 形式 - # @t.xxx 的 kind 是 Attribute,不进入本检测) - if string.strcmp(dname, "CExport") == 0 \ - or string.strcmp(dname, "CExtern") == 0 \ - or string.strcmp(dname, "State") == 0 \ - or string.strcmp(dname, "TLS") == 0 \ - or string.strcmp(dname, "CStatic") == 0 \ - or string.strcmp(dname, "CInline") == 0 \ - or string.strcmp(dname, "CVTable") == 0 \ - or string.strcmp(dname, "NoVTable") == 0 \ - or string.strcmp(dname, "Object") == 0 \ - or string.strcmp(dname, "CEnum") == 0 \ - or string.strcmp(dname, "CUnion") == 0 \ - or string.strcmp(dname, "REnum") == 0 \ - or string.strcmp(dname, "CDefine") == 0: - continue - has_custom_decor = 1 - decor_handler = dname - break - - # SHA1 命名空间:t.CExtern/t.State/t.CExport 不加前缀,直接用裸名 - # (裸名映射到 C 标准库符号,带 sha1 前缀会导致 undefined reference) - # main 函数也不加前缀(程序入口点) - if has_extern != 0 or has_state != 0 or has_export != 0 or string.strcmp(fd.name, "main") == 0: - mangled_name: str = fd.name - else: - mangled_name: str = ExprCallHandle._mangle_func_name(trans, fd.name, 0) - - # 注册 CExport 函数到全局表(供跨模块调用查表) - # t.CExport 函数定义用裸名(@strlen),跨模块调用需查表确认用裸名而非 @{sha1}.func - if (has_export != 0 or has_state != 0) and trans.ModuleSha1 is not None: - ExprCallBase.register_cexport_func(trans.ModuleSha1, fd.name) - - if is_extern_decl != 0: - # 外部声明函数:生成 declare(仅声明,不定义) - # 先检查是否已由 forward_declare_functions 创建,避免重复 declare - existing_extern: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module(mod, mangled_name) - if existing_extern is not None: - # 已存在前向声明,复用之,不再重复创建 - return 0 - - func: llvmlite.Function | t.CPtr = llvmlite.create_declare( - pool, mod, mangled_name, ret_ty) - if func is None: - return 0 - - # 注册到函数表 - max_funcs_extern: int = 256 - if ExprCallTable.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs_extern, None, 0, 0, pool) == 0: - trans._func_count = func_count + 1 - - # 添加参数(支持类型注解) - args_node_extern: ast.Arguments | t.CPtr = fd.args - if args_node_extern is not None: - ags_e: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node_extern) - if ags_e.args is not None: - alist_e: list[ast.AST | t.CPtr] | t.CPtr = ags_e.args - an_e: t.CSizeT = len(alist_e) - for ai_e in range(an_e): - arg_e: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist_e.get(ai_e)) - if arg_e is not None and arg_e.arg is not None: - # t.CVoid 表示空参:跳过,不添加到函数签名 - if arg_e.annotation is not None \ - and HandlesType._is_t_attr(arg_e.annotation, "CVoid", imported_modules) != 0: - continue - param_ty_e: llvmlite.LLVMType | t.CPtr = i32_ty - if arg_e.annotation is not None: - resolved_e: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, arg_e.annotation, imported_modules, from_imports, trans) - if resolved_e is None: - # fail-fast:外部声明函数参数有注解但类型解析失败, - # 不再静默保持 i32(声明签名错误会在 ABI 层暴露) - HandlesType.fatal_error( - arg_e, f"参数 '{arg_e.arg}' 类型解析失败: {HandlesType.annotation_to_str(arg_e.annotation)}", - "NameError") - resolved_e = i32_ty # 不可达(fatal_error 已退出) - if resolved_e is not None: - # 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致) - # CArray 形参 → 元素指针 ty*(C 数组衰减) - match resolved_e: - case llvmlite.LLVMType.Struct(_, _, _): - param_ty_e = llvmlite.Ptr(pool, resolved_e) - case llvmlite.LLVMType.Array(aelem_ty_e, _): - param_ty_e = llvmlite.Ptr(pool, aelem_ty_e) - case _: - param_ty_e = resolved_e - pname_e: str = pool.alloc(32) - if pname_e is not None: - viperlib.snprintf(pname_e, 32, "%%%s", arg_e.arg) - llvmlite.add_param(pool, func, param_ty_e, pname_e) - - # 提取 @c.Attribute 装饰器属性并设置到函数 - func_attrs_e: str = ExprCallHandle.extract_func_attrs(pool, fd.decorator_list, imported_modules) - if func_attrs_e is not None: - llvmlite.function_set_attrs(func, func_attrs_e) - - # 参数添加完成,补全全局函数表的 TypeStr - ExprCallTable.update_global_func_typestr(pool, fd.name, func) - - return 0 - - # args_node 用于后续 alloca 创建,提前赋值 - args_node: ast.Arguments | t.CPtr = fd.args - - # 检查是否已有前向声明(由 forward_declare_functions 创建) - func: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module(mod, mangled_name) - if func is not None and llvmlite.function_is_declared(func) != 0: - # 复用前向声明:清除 IsDeclared 标记,转为 define - func.IsDeclared = 0 - # 装饰器属性设置(前向声明时未设置) - func_attrs_reuse: str = ExprCallHandle.extract_func_attrs(pool, fd.decorator_list, imported_modules) - if func_attrs_reuse is not None: - llvmlite.function_set_attrs(func, func_attrs_reuse) - else: - # 创建新的 LLVM 函数(使用 SHA1 混淆名) - func = llvmlite.create_function(pool, mod, mangled_name, ret_ty) - if func is None: - fb_cf: str = VLogger.fmt_buf() - if fb_cf is not None: - viperlib.snprintf(fb_cf, 1024, "create_function %s failed", fd.name) - VLogger.error(fb_cf, "FUNC") - return 0 - - # 提取 @c.Attribute 装饰器属性并设置到函数 - func_attrs: str = ExprCallHandle.extract_func_attrs(pool, fd.decorator_list, imported_modules) - if func_attrs is not None: - llvmlite.function_set_attrs(func, func_attrs) - - # 提取默认参数信息 - tfd_defaults: t.CVoid | t.CPtr = None - tfd_default_count: int = 0 - tfd_param_count: int = 0 - if args_node is not None: - tfd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) - if tfd_ags.args is not None: - tfd_alist: list[ast.AST | t.CPtr] | t.CPtr = tfd_ags.args - tfd_param_count = len(tfd_alist) - if tfd_ags.defaults is not None: - tfd_dlist: list[ast.AST | t.CPtr] | t.CPtr = tfd_ags.defaults - tfd_defaults = tfd_dlist - tfd_default_count = len(tfd_dlist) - - # 注册到函数表 - max_funcs: int = 1024 - if ExprCallTable.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs, - tfd_defaults, tfd_default_count, tfd_param_count, - trans.Pool) == 0: - trans._func_count = func_count + 1 - - # 添加参数(支持类型注解) - if args_node is not None: - ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) - if ags.args is not None: - alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args - an: t.CSizeT = len(alist) - 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: - # t.CVoid 表示空参:跳过,不添加到函数签名 - if arg.annotation is not None \ - and HandlesType._is_t_attr(arg.annotation, "CVoid", imported_modules) != 0: - continue - param_ty: llvmlite.LLVMType | t.CPtr = i32_ty - if arg.annotation is not None: - resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, arg.annotation, imported_modules, from_imports, trans) - if resolved is not None: - # 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致) - # CArray 形参 → 元素指针 ty*(C 数组衰减:final(out: t.CArray[..., N]) - # 的 out 指向调用方数组首元素;传 Ptr(数组) 会使 out[i] 的 - # GEP 以整个数组为步长错位,摘要垃圾根因) - match resolved: - case llvmlite.LLVMType.Struct(_, _, _): - param_ty = llvmlite.Ptr(pool, resolved) - case llvmlite.LLVMType.Array(aelem_ty, _): - param_ty = llvmlite.Ptr(pool, aelem_ty) - case _: - param_ty = resolved - pname: str = pool.alloc(32) - if pname is not None: - viperlib.snprintf(pname, 32, "%%%s", arg.arg) - llvmlite.add_param(pool, func, param_ty, pname) - - # *args 变长参数:设置 IsVarArg=1,生成 ... 后缀 - if ags.vararg is not None: - func.IsVarArg = 1 - - # try-except:函数体含 raise → 追加 __eh_msg_out__(i8**)/ - # __eh_code_out__(i32*)输出参数(对齐 TPC HandlesFunctions.py - # L706-711;main 除外)。被调函数把异常编码/消息写入调用方传入 - # 的指针,调用方 _check_eh_return 检测。 - # 注意:必须在参数添加块(if args_node is not None:)外——无参函数 - # (def f())的 args_node 为 None,若放在其内会被跳过,导致函数体 - # store %__eh_code_out__ 但签名无此参数(llc: use of undefined value)。 - if string.strcmp(fd.name, "main") != 0: - if ExprCallHandle._body_has_raise(fd) != 0: - i8_ty_eh: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty_eh: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_eh) - i8_ptr_ptr_ty_eh: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty_eh) - i32_ty_eh: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i32_ptr_ty_eh: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty_eh) - if i8_ptr_ptr_ty_eh is not None and i32_ptr_ty_eh is not None: - llvmlite.add_param(pool, func, i8_ptr_ptr_ty_eh, "%__eh_msg_out__") - llvmlite.add_param(pool, func, i32_ptr_ty_eh, "%__eh_code_out__") - - # 参数添加完成,补全全局函数表的 TypeStr - ExprCallTable.update_global_func_typestr(trans.Pool, fd.name, func) - - # 创建 entry 块 - entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") - if entry_blk is None: - return 0 - - # 创建函数专属 builder - func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) - if func_builder is None: - return 0 - llvmlite.position_at_end(func_builder, entry_blk) - - # @t.TLS 一次性初始化守卫(对齐 TPC HandlesFunctions.py L1763-1792): - # 首次调用执行函数体并置全局标志 __tls_init_done_{name}=1,后续调用 - # 直接返回默认值。TPV 此前未实现 @t.TLS,_init_tls 每次 TlsAlloc 导致 - # provider 栈跨调用丢失(FakeDuckTest Test 9 注入失败根因)。 - if has_tls != 0: - tls_flag_name: str = pool.alloc(128) - if tls_flag_name is not None: - viperlib.snprintf(tls_flag_name, 128, "__tls_init_done_%s", fd.name) - tls_flag_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.create_global_int( - pool, mod, tls_flag_name, 1, 0) - if tls_flag_gv is not None: - i1_ty_t: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - if i1_ty_t is not None: - # GlobalVariable 不是 Value 子类(字段布局不同),build_load/store - # 按 Value 读 ptr.Ty/ptr.Name 会错位(Ty 读到 Name → void,Name 为空)。 - # 与 create_global_string 一致:构造 Value 视图(Ty=Ptr(i1), Name="@name")。 - tls_gv_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_t) - tls_ref_name: str = pool.alloc(64) - if tls_ref_name is not None: - viperlib.snprintf(tls_ref_name, 64, "@%s", tls_flag_name) - tls_flag_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, tls_gv_ptr_ty, tls_ref_name) - if tls_flag_ref is not None: - tls_flag_ld: llvmlite.Value | t.CPtr = llvmlite.build_load( - func_builder, i1_ty_t, tls_flag_ref) - # 块名唯一化(create_block 不自动编号,同函数同名 label 冲突) - lc_t: int = trans._label_counter - trans._label_counter = lc_t + 1 - tls_bb_buf: str = pool.alloc(64) - if tls_bb_buf is not None: - viperlib.snprintf(tls_bb_buf, 64, "tls.skip.%d", lc_t) - tls_skip_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, tls_bb_buf) - viperlib.snprintf(tls_bb_buf, 64, "tls.cont.%d", lc_t) - tls_cont_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, tls_bb_buf) - if tls_skip_bb is not None and tls_cont_bb is not None: - llvmlite.build_cond_br( - func_builder, tls_flag_ld, tls_skip_bb, tls_cont_bb) - # skip 块:按返回类型生成默认值直接返回 - llvmlite.position_at_end(func_builder, tls_skip_bb) - match ret_ty: - case llvmlite.LLVMType.Void(): - llvmlite.build_ret_void(func_builder) - case llvmlite.LLVMType.Int(_): - tlz0: llvmlite.Value | t.CPtr = llvmlite.ConstInt( - pool, ret_ty, 0, "0") - if tlz0 is not None: - llvmlite.build_ret(func_builder, tlz0) - case llvmlite.LLVMType.Float(_): - tlf0: llvmlite.Value | t.CPtr = llvmlite.ConstFloat( - pool, ret_ty, 0.0) - if tlf0 is not None: - llvmlite.build_ret(func_builder, tlf0) - case _: - tln0: llvmlite.Value | t.CPtr = llvmlite.ConstNull( - pool, ret_ty, "null") - if tln0 is not None: - llvmlite.build_ret(func_builder, tln0) - # cont 块:置标志=1,继续函数体 - llvmlite.position_at_end(func_builder, tls_cont_bb) - tlone: llvmlite.Value | t.CPtr = llvmlite.ConstInt( - pool, i1_ty_t, 1, "1") - if tlone is not None: - llvmlite.build_store(func_builder, tlone, tls_flag_ref) - - # 进入函数作用域(嵌套符号表) - HandlesVar.enter_scope(trans.SymTab, SCOPE_FUNCTION) - - # PEP 695 泛型函数: def f[T](...) — 设置泛型上下文,类型参数映射到 "int" 兜底。 - # TPV 无泛型函数特化机制(类泛型走 _specialize_generic_class),泛型函数按普通 - # 函数编译;设置上下文使参数注解 T / 方法体中的 T(x) 转换可解析为 int。 - # (注意与类特化的 set_generic_context 一样是全局状态,需在退出作用域前清除。) - tp_names_fn: list[str] | t.CPtr = None - if fd.type_params is not None: - tp_names_fn = fd.type_params - tp_args_fn: list[str] | t.CPtr = list[str](pool, 8) - if tp_args_fn is not None: - tpn_fn: t.CSizeT = len(fd.type_params) - tpi_fn: t.CSizeT = 0 - for tpi_fn in range(tpn_fn): - tp_args_fn.append("int") - HandlesType.set_generic_context(tp_names_fn, tp_args_fn) - - # 为参数创建 alloca - if args_node is not None: - ags2: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) - if ags2.args is not None: - alist2: list[ast.AST | t.CPtr] | t.CPtr = ags2.args - an2: t.CSizeT = len(alist2) - for ai2 in range(an2): - arg2: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist2.get(ai2)) - if arg2 is not None and arg2.arg is not None: - # t.CVoid 表示空参:跳过,不创建 alloca - if arg2.annotation is not None: - if HandlesType._is_t_attr(arg2.annotation, "CVoid", imported_modules) != 0: - continue - param_ty2: llvmlite.LLVMType | t.CPtr = i32_ty - if arg2.annotation is not None: - resolved2: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, arg2.annotation, imported_modules, from_imports, trans) - if resolved2 is None: - # fail-fast:参数有注解但类型解析失败,不再静默保持 i32 - HandlesType.fatal_error( - arg2, f"参数 '{arg2.arg}' 类型解析失败: {HandlesType.annotation_to_str(arg2.annotation)}", - "NameError") - resolved2 = i32_ty # 不可达(fatal_error 已退出) - if resolved2 is not None: - # 与 add_param 保持一致:裸类形参 → Ptr(struct)(对象即指针); - # CArray 形参 → 元素指针 ty*(数组衰减,alloca 类型须与形参一致, - # 否则 store ty* 到 [N x ty]* 容器类型不匹配) - match resolved2: - case llvmlite.LLVMType.Struct(_, _, _): - param_ty2 = llvmlite.Ptr(pool, resolved2) - case llvmlite.LLVMType.Array(aelem_ty2, _): - param_ty2 = llvmlite.Ptr(pool, aelem_ty2) - case _: - param_ty2 = resolved2 - alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, param_ty2) - if alloca is not None: - HandlesVar.define_var(trans.SymTab, arg2.arg, alloca) - # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) - # 传 pool:泛型 Subscript 返回 mangled name(对齐 HandlesAnnAssign 修复) - cls_nm: str = None - if arg2.annotation is not None: - cls_nm = HandlesType.extract_class_name_from_annotation( - arg2.annotation, imported_modules, pool) - if cls_nm is not None: - HandlesVar.set_var_annot_class_name( - trans.SymTab, arg2.arg, cls_nm) - pname2: str = pool.alloc(32) - if pname2 is not None: - viperlib.snprintf(pname2, 32, "%%%s", arg2.arg) - param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, param_ty2, pname2) - llvmlite.build_store(func_builder, param_val, alloca) - - # *args 变长参数:创建 va_list 缓冲区 + 调用 va_start + 注册到符号表 - # 生成 IR: - # %args_va = alloca [24 x i8], align 16 ; va_list 缓冲区(Win64 __va_list_tag) - # %args = bitcast [24 x i8]* %args_va to i8* - # call void @llvm.va_start(i8* %args) ; 初始化 va_list - # 用户函数体内可通过 args 名字读取 va_list 地址(i8*),或用 arg(type) 糖函数 - # 注意:必须在参数 alloca 段(if args_node is not None:)内但 EH 块外—— - # 无 raise 的函数(viperlib.sprintf 等)同样有 *args,若放在 EH 块内 - # 会被跳过,args 未注册到符号表 → NameError: 未定义名称 'args'。 - if ags2.vararg is not None: - vararg_node: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(ags2.vararg) - if vararg_node is not None and vararg_node.arg is not None: - vararg_name_str: str = vararg_node.arg - # va_list 缓冲区 24 字节(Win64 的 __va_list_tag = {i32,i32,i8*,i8*})+ 16 对齐 - # (对齐 TPC HandlesFunctions.py:1739-1741) - i8_ty_va: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty_va: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_va) - va_buf_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty_va, 24) - va_list_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca_aligned( - func_builder, va_buf_ty, 16) - if va_list_alloca is not None: - # i8* 地址(指向 24 字节 va_list 缓冲区)——vararg 名的值语义 - va_list_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - func_builder, va_list_alloca, i8_ptr_ty_va) - if va_list_addr is not None: - # 注册到符号表(translate_name_value 对 vararg 名特殊处理返回地址) - HandlesVar.define_var(trans.SymTab, vararg_name_str, va_list_alloca) - # 调用 @llvm.va_start(i8* %va_list_addr) - void_ty_va: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) - llvmlite.build_call(func_builder, "llvm.va_start", - va_list_addr, 1, void_ty_va, 0) - # 保存到 trans 供 arg(type) 糖函数与 vararg 名翻译使用 - trans._va_list_ptr = va_list_addr - trans._vararg_name = vararg_name_str - - # try-except:新函数作用域 EH 状态从零开始。必须先保存外层函数 - # (调用方/包围函数)的 EH 输出参数,翻译完本函数后再恢复——否则 - # 下方设置本函数 EH 参数会覆盖外层值,恢复时 old_eh_* 拿到的是 - # 本函数自身参数(嵌套函数/多函数链 EH 状态错乱)。 - old_eh_msg_out: llvmlite.Value | t.CPtr = trans._eh_msg_out_param - old_eh_code_out: llvmlite.Value | t.CPtr = trans._eh_code_out_param - old_cur_func_has_eh: int = trans._cur_func_has_eh - trans._eh_msg_out_param = None - trans._eh_code_out_param = None - trans._cur_func_has_eh = 0 - - # try-except:保存当前函数的 EH 输出参数(__eh_msg_out__/__eh_code_out__) - # 供 translate_raise / UnhandledBB 写入并向上传播。无 EH 参数的函数置空。 - if string.strcmp(fd.name, "main") != 0 and ExprCallHandle._body_has_raise(fd) != 0: - i8_ty_eh2: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty_eh2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_eh2) - i8_ptr_ptr_ty_eh2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty_eh2) - i32_ty_eh2: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i32_ptr_ty_eh2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty_eh2) - if i8_ptr_ptr_ty_eh2 is not None and i32_ptr_ty_eh2 is not None: - msg_out_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, i8_ptr_ptr_ty_eh2, "%__eh_msg_out__") - code_out_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, i32_ptr_ty_eh2, "%__eh_code_out__") - trans._eh_msg_out_param = msg_out_ref - trans._eh_code_out_param = code_out_ref - trans._cur_func_has_eh = 1 - - # 保存模块级作用域状态(仅非变量表相关) - old_func: llvmlite.Function | t.CPtr = trans._cur_func - old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - old_global_count: int = trans._global_name_count - old_nonlocal_count: int = trans._nonlocal_name_count - old_env_count: int = trans._closure_env_count - old_va_list_ptr: llvmlite.Value | t.CPtr = trans._va_list_ptr - old_vararg_name: str = trans._vararg_name - - trans._cur_func = func - trans._cur_builder = func_builder - # 清空 global/nonlocal 名称集合(新函数作用域) - HT.clear_scope_names(trans) - # 重置链内 nonlocal 堆预建标志(每函数只建一次;多嵌套函数定义 - # 共享同一堆,防重复 malloc + 二次重定向 VarEntry) - trans._nl_chain_done = 0 - - # 预扫描函数体: - # 1. 先预扫描 Global/Nonlocal 声明(Python 语义:global/nonlocal - # 对整个函数作用域生效,与声明位置无关,故须在任何赋值前注册) - # 2. 再预扫描 AnnAssign 为局部变量提前创建 alloca - body: list[ast.AST | t.CPtr] | t.CPtr = fd.children - if body is not None: - bn: t.CSizeT = len(body) - for bi in range(bn): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.pre_scan_scope_decls(trans, stmt) - for bi in range(bn): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.pre_scan_allocas(trans, stmt) - - # 翻译函数体 - if body is not None: - bn2: t.CSizeT = len(body) - for bi2 in range(bn2): - stmt2: ast.AST | t.CPtr = body.get(bi2) - if stmt2 is not None: - # 嵌套函数定义前:预扫描其链内 nonlocal 并建堆 - # (不同层捕获不同变量的场景,见 _prepare_chain_nonlocals) - if stmt2.kind() == ast.ASTKind.FunctionDef: - ExprCallHandle._prepare_chain_nonlocals( - trans, stmt2, pool, func_builder, mod, - llvmlite.Int8(pool), llvmlite.Ptr(pool, llvmlite.Int8(pool))) - HandlesBody.translate_stmt(trans, stmt2) - - # 如果函数体最后一条语句不是 Return,添加隐式 ret - last_is_return: int = 0 - # 追加89:bn3 提前初始化,避免 body is None 时下方 fail-fast 分支 - # 引用未定义的 bn3(追加81 同款 NameError 风险) - bn3: t.CSizeT = 0 - if body is not None: - bn3 = len(body) - if bn3 > 0: - last_stmt: ast.AST | t.CPtr = body.get(bn3 - 1) - if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return: - last_is_return = 1 - if last_is_return == 0: - if llvmlite.builder_cur_block_is_terminated(func_builder) == 0: - # 追加89:编译器不替代码发明返回值——函数流程真实掉出末尾而 - # 未显式 return 时 fail-fast(要求补 return,Python traceback - # 风格定位到函数)。三种合法收尾: - # ① void 函数掉出末尾 → ret void(无值可发明,Python 语义) - # ② 末句是控制流语句(match/if 全分支 return)且当前块 - # 未 terminated → merge 块结构性不可达 → unreachable - # ③ 无返回类型注解的函数(fd.returns is None,如 - # ast/base.vp _set_pos 过程风格赋值函数)→ 视为无返回值 - # 函数,默认生成零值返回(用户决策:没有返回值默认不用 - # return;ConstZero 按推断出的 ret_ty 构造,类型匹配) - # 有 -> 注解且末句是普通语句掉出末尾 → fail-fast(不得替代码 - # 发明返回值,也不做 noreturn 函数名白名单——错误终止路径 - # 也必须在源码层面保证块收尾,如显式 return 样板) - # 末句是否为控制流语句(If/Match/While/For/Try/With): - # 控制流语句翻译后当前块未 terminated 表示 merge 块结构性 - # 不可达(所有分支均已 return/terminated)——对非 void 函数 - # 生成 unreachable 而非 fail-fast(GCC/Clang 对 fall-through - # 视为 UB 同语义;追加89 修正 get_struct_name 全 case return - # 被错判"不可能抵达") - last_is_ctrl: int = 0 - if bn3 > 0: - last_stmt3: ast.AST | t.CPtr = body.get(bn3 - 1) - if last_stmt3 is not None: - k3: int = last_stmt3.kind() - if k3 == ast.ASTKind.If or k3 == ast.ASTKind.While or \ - k3 == ast.ASTKind.For or k3 == ast.ASTKind.Try or \ - k3 == ast.ASTKind.With or k3 == ast.ASTKind.Match: - last_is_ctrl = 1 - _is_void: int = 0 - if ret_ty is not None: - match ret_ty: - case llvmlite.LLVMType.Void(): - _is_void = 1 - case _: - pass - if _is_void != 0: - llvmlite.build_ret_void(func_builder) - elif last_is_ctrl != 0 and trans._ctrl_merge_reachable == 0: - # 追加90:非 void 函数末句是控制流且 merge 块结构性不可达 - # (全分支 return,无 br 到 merge)→ LLVM 语义 unreachable。 - # 注意:merge 可达(分支 br 到 merge,如 testcheck.check 的 - # if/else 无 return)时不是结构性不可达,需正常收尾(下方 - # ConstZero / fail-fast)。原实现无条件 unreachable 使 llc - # O2 把 br-to-unreachable 优化为 fall-through → 双分支执行 - # 崩溃(FuncTest check PASS+FAIL 双打印) - llvmlite.build_unreachable(func_builder) - elif fd.returns is None: - # 无返回类型注解 → 无返回值过程函数,默认零值返回 - if ret_ty is not None: - zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, ret_ty) - if zero_val is not None: - llvmlite.build_ret(func_builder, zero_val) - else: - HandlesType.fatal_error(node, "函数流程掉出末尾但未显式 return", "TypeError") - else: - HandlesType.fatal_error(node, "函数流程掉出末尾但未显式 return", "TypeError") - else: - # fail-fast:有 -> 注解但流程真实掉出末尾(定位到函数定义 - # 节点,fatal_error 输出 traceback 风格错误) - if ret_ty is not None: - # llvmlite 无 type_get_name API,类型序列化用真实接口 - # TypePrint(buf, size, ty, pool)(追加89 修正) - rt_name: str = pool.alloc(64) - if rt_name is not None: - llvmlite.TypePrint(rt_name, 64, ret_ty, pool) - if rt_name[0] == '\0': - rt_name = "?" - err_fn: str = pool.alloc(256) - if err_fn is not None: - viperlib.snprintf( - err_fn, 256, - "函数 '%s' 流程掉出函数末尾但未显式 return(返回类型 %s)," - "请补显式 return(如 return 0 / return null)", fd.name, rt_name) - HandlesType.fatal_error(node, err_fn, "TypeError") - HandlesType.fatal_error(node, "函数流程掉出末尾但未显式 return", "TypeError") - else: - HandlesType.fatal_error(node, "函数流程掉出末尾但未显式 return", "TypeError") - - # 恢复模块级作用域(退出函数作用域) - if tp_names_fn is not None: - HandlesType.clear_generic_context() - HandlesVar.exit_scope(trans.SymTab) - trans._cur_func = old_func - trans._cur_builder = old_builder - trans._global_name_count = old_global_count - trans._nonlocal_name_count = old_nonlocal_count - trans._closure_env_count = old_env_count - trans._va_list_ptr = old_va_list_ptr - trans._vararg_name = old_vararg_name - # 恢复外层函数(调用方)的 EH 输出参数——本函数体内的 raise 传播 - # 使用本函数参数,翻译结束必须交还外层作用域,否则嵌套函数/链式 - # 调用后 EH 状态残留导致 raise 写入错误的 out 指针。 - trans._eh_msg_out_param = old_eh_msg_out - trans._eh_code_out_param = old_eh_code_out - trans._cur_func_has_eh = old_cur_func_has_eh - - # 自定义装饰器:注册 + 生成 wrapper(对齐 TPC DecoratorPass.run)。 - # 仅模块级函数(fd 是顶层定义);wrapper 名 __decor_wrap_{裸函数名}。 - # 调用点重写经 lookup_decor_wrapper(translate_call 拦截原函数名)。 - if has_custom_decor != 0: - wb_name: str = pool.alloc(128) - if wb_name is not None: - viperlib.snprintf(wb_name, 128, "__decor_wrap_%s", fd.name) - HandlesClassDef.register_decorator(pool, fd.name, wb_name, decor_arg0) - self._gen_decor_wrapper( - trans, pool, mod, func, fd.name, wb_name, - decor_handler, decor_arg0) - - return 0 - # ============================================================ - # _gen_decor_wrapper - 生成装饰器 wrapper 函数(对齐 TPC DecoratorPass.py - # _generate_single_wrapper v4) - # - # v4 Wrapper 结构(最外层含递归保护): - # entry → 递归保护检查(最外层) - # recursive_call → 递归时直接调用原函数,跳过所有装饰 - # decorated_entry → 置递归标志,分配 ctx/args/ret,调用 handler 前置 - # loop_header → 计数器 i < n_calls(TPV 用 alloca 计数器替代 phi) - # loop.body → 从 args_struct 读回参数,调用原函数 - # post → 调用 handler 后置,清递归标志,返回结果 - # - # handler 调用约定:i32 decor(i8* ctx, i8* func_name, i32 phase, - # i8* args_ptr, i8* ret_ptr, i8* decor_args_ptr) - # 前置返回:0=跳过原函数,1=调用一次,N=循环 N 次 - # ============================================================ - def _gen_decor_wrapper(self, trans: HT.Translator | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - func: llvmlite.Function | t.CPtr, - func_name: str, - wrapper_name: str, - handler_name: str, - decor_arg0: t.CInt64T) -> llvmlite.Function | t.CPtr: - """生成装饰器 wrapper 函数,返回 wrapper 或 None""" - if trans is None or pool is None or mod is None or func is None: - return None - if func_name is None or wrapper_name is None or handler_name is None: - return None - ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(func) - if ret_ty is None: - return None - orig_call_name: str = llvmlite.function_get_name(func) - if orig_call_name is None: - return None - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - # ---- 收集原函数参数类型(按位置,最多 16 个)---- - n_params: int = 0 - param_tys: t.CSizeT | t.CPtr = pool.alloc(16 * 8) - if param_tys is None: - return None - string.memset(param_tys, 0, 16 * 8) - pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) - while pp is not None: - pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pp) - if pty is not None and n_params < 16: - param_tys[n_params] = t.CSizeT(pty) - n_params += 1 - pp = llvmlite.param_get_next(pp) - - # ---- 创建 wrapper 函数并添加参数(名字 %a0..%aN)---- - wrapper: llvmlite.Function | t.CPtr = llvmlite.create_function( - pool, mod, wrapper_name, ret_ty) - if wrapper is None: - return None - pi: int = 0 - for pi in range(n_params): - pname_w: str = pool.alloc(16) - if pname_w is not None: - viperlib.snprintf(pname_w, 16, "%%a%d", pi) - llvmlite.add_param(pool, wrapper, (llvmlite.LLVMType | t.CPtr)( - t.CVoid(param_tys[pi], t.CPtr)), pname_w) - - # ---- 创建块 ---- - entry_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "entry") - loop_h_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "loop.header") - loop_b_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "loop.body") - post_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "post") - if entry_bb is None or loop_h_bb is None or loop_b_bb is None or post_bb is None: - return None - - # 递归保护标志(最外层):@__decor_rec_{wrapper} = global i8 0 - rec_flag_ref: llvmlite.Value | t.CPtr = None - rec_flag_name: str = pool.alloc(128) - if rec_flag_name is not None: - viperlib.snprintf(rec_flag_name, 128, "__decor_rec_%s", wrapper_name) - llvmlite.create_global_int(pool, mod, rec_flag_name, 8, 0) - rec_ref_nm: str = pool.alloc(96) - if rec_ref_nm is not None: - viperlib.snprintf(rec_ref_nm, 96, "@%s", rec_flag_name) - rec_flag_ref = llvmlite.SSAValue(pool, llvmlite.Ptr(pool, i8_ty), rec_ref_nm) - - wb: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, wrapper) - if wb is None: - return None - - # 返回类型分类 - ret_is_void: int = 0 - match ret_ty: - case llvmlite.LLVMType.Void(): - ret_is_void = 1 - case _: - pass - - # ---- entry:递归保护检查(最外层)---- - llvmlite.position_at_end(wb, entry_bb) - loop_pred_bb: llvmlite.BasicBlock | t.CPtr = entry_bb - if rec_flag_ref is not None: - rec_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "recursive_call") - dec_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "decorated_entry") - if rec_bb is None or dec_bb is None: - return None - rec_val: llvmlite.Value | t.CPtr = llvmlite.build_load(wb, i8_ty, rec_flag_ref) - rec_zero: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i8_ty, 0, "0") - rec_is: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - wb, llvmlite.ICMP_NE, rec_val, rec_zero) - llvmlite.build_cond_br(wb, rec_is, rec_bb, dec_bb) - # recursive_call:直接调用原函数返回(跳过所有装饰逻辑) - llvmlite.position_at_end(wb, rec_bb) - rec_args: llvmlite.Value | t.CPtr = None - ri: int = 0 - for ri in range(n_params): - an_r: str = pool.alloc(16) - if an_r is None: - continue - viperlib.snprintf(an_r, 16, "%%a%d", ri) - av_r: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, (llvmlite.LLVMType | t.CPtr)(t.CVoid(param_tys[ri], t.CPtr)), an_r) - if av_r is not None: - llvmlite.value_set_next(av_r, None) - if rec_args is None: - rec_args = av_r - else: - # 链尾追加 - rt: llvmlite.Value | t.CPtr = rec_args - while rt.Next is not None: - rt = rt.Next - llvmlite.value_set_next(rt, av_r) - if ret_is_void != 0: - llvmlite.build_call(wb, orig_call_name, rec_args, n_params, ret_ty, 0) - llvmlite.build_ret_void(wb) - else: - rc_res: llvmlite.Value | t.CPtr = llvmlite.build_call( - wb, orig_call_name, rec_args, n_params, ret_ty, 0) - if rc_res is not None: - llvmlite.build_ret(wb, rc_res) - else: - llvmlite.build_ret_void(wb) - # decorated_entry:置递归标志,继续装饰路径 - llvmlite.position_at_end(wb, dec_bb) - rec_one: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i8_ty, 1, "1") - if rec_one is not None: - llvmlite.build_store(wb, rec_one, rec_flag_ref) - loop_pred_bb = dec_bb - - # ---- 公共装饰路径(entry 或 decorated_entry)---- - # 1. ctx = alloca [32 x i8]; ctx_ptr = bitcast i8* - ctx_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, 32) - ctx_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(wb, ctx_ty) - ctx_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(wb, ctx_alloca, i8_ptr_ty) - - # 2. 打包函数参数到结构体 {param_types}(装饰器可读写 args_ptr) - args_alloca: llvmlite.Value | t.CPtr = None - args_ptr: llvmlite.Value | t.CPtr = None - if n_params > 0: - fields_head: llvmlite.ParamNode | t.CPtr = None - fk: int = 0 - for fk in range(n_params - 1, -1, -1): - pn_n: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node( - pool, (llvmlite.LLVMType | t.CPtr)(t.CVoid(param_tys[fk], t.CPtr))) - if pn_n is not None: - pn_n.Next = fields_head - fields_head = pn_n - args_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct( - pool, fields_head, n_params, None) - if args_ty is not None: - args_alloca = llvmlite.build_alloca(wb, args_ty) - fi2: int = 0 - for fi2 in range(n_params): - fld_ty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)( - t.CVoid(param_tys[fi2], t.CPtr)) - fld_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - wb, args_ty, fld_ty, args_alloca, fi2) - if fld_ptr is not None: - fld_nm: str = pool.alloc(16) - if fld_nm is not None: - viperlib.snprintf(fld_nm, 16, "%%a%d", fi2) - fld_v: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, fld_ty, fld_nm) - if fld_v is not None: - llvmlite.build_store(wb, fld_v, fld_ptr) - args_ptr = llvmlite.build_bitcast(wb, args_alloca, i8_ptr_ty) - else: - args_ptr = llvmlite.ConstNull(pool, i8_ptr_ty, "null") - - # 3. 返回值存储(零初始化;跳过原函数时返回安全默认值) - ret_alloca: llvmlite.Value | t.CPtr = None - if ret_is_void == 0: - ret_alloca = llvmlite.build_alloca(wb, ret_ty) - ret_zero: llvmlite.Value | t.CPtr = None - match ret_ty: - case llvmlite.LLVMType.Int(_): - ret_zero = llvmlite.ConstInt(pool, ret_ty, 0, "0") - case llvmlite.LLVMType.Float(_): - ret_zero = llvmlite.ConstFloat(pool, ret_ty, 0.0) - case _: - ret_zero = llvmlite.ConstNull(pool, ret_ty, "null") - if ret_zero is not None and ret_alloca is not None: - llvmlite.build_store(wb, ret_zero, ret_alloca) - - # 4. 函数名字符串常量 - fn_str: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string( - wb, pool, mod, func_name, trans) - if fn_str is None: - fn_str = llvmlite.ConstNull(pool, i8_ptr_ty, "null") - - # 5. handler 声明(未翻译时 declare,固定签名 i32 (i8*,i8*,i32,i8*,i8*,i8*)) - if ExprCallBase.find_func_in_module(mod, handler_name) is None: - handler_d: llvmlite.Function | t.CPtr = llvmlite.create_declare( - pool, mod, handler_name, i32_ty) - if handler_d is not None: - llvmlite.add_param(pool, handler_d, i8_ptr_ty, "ctx") - llvmlite.add_param(pool, handler_d, i8_ptr_ty, "func_name") - llvmlite.add_param(pool, handler_d, i32_ty, "phase") - llvmlite.add_param(pool, handler_d, i8_ptr_ty, "args_ptr") - llvmlite.add_param(pool, handler_d, i8_ptr_ty, "ret_ptr") - llvmlite.add_param(pool, handler_d, i8_ptr_ty, "decor_args_ptr") - - # 6. 前置阶段:handler 返回调用次数 n_calls - ph0: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i32_ty, 0, "0") - null_ret: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty, "null") - null_dec: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty, "null") - # 参数链表(6 个独立值):ctx_ptr → fn_str → 0 → args_ptr → null → null - # 注意:不能 self 链接(null.Next = null 会让 build_call 遍历死循环) - if ctx_ptr is not None: - llvmlite.value_set_next(ctx_ptr, fn_str) - if fn_str is not None: - llvmlite.value_set_next(fn_str, ph0) - if ph0 is not None: - llvmlite.value_set_next(ph0, args_ptr) - if args_ptr is not None: - llvmlite.value_set_next(args_ptr, null_ret) - if null_ret is not None: - llvmlite.value_set_next(null_ret, null_dec) - n_calls: llvmlite.Value | t.CPtr = llvmlite.build_call( - wb, handler_name, ctx_ptr, 6, i32_ty, 0) - - # 7. 计数器 alloca(TPV 用 alloca 计数器替代 phi) - cnt_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(wb, i32_ty) - cnt_zero: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i32_ty, 0, "0") - if cnt_alloca is not None and cnt_zero is not None: - llvmlite.build_store(wb, cnt_zero, cnt_alloca) - llvmlite.build_br(wb, loop_h_bb) - - # 8. loop.header:cur = load cnt; cur < n_calls → body / post - llvmlite.position_at_end(wb, loop_h_bb) - cur_i: llvmlite.Value | t.CPtr = llvmlite.build_load(wb, i32_ty, cnt_alloca) - loop_cond: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - wb, llvmlite.ICMP_SLT, cur_i, n_calls) - llvmlite.build_cond_br(wb, loop_cond, loop_b_bb, post_bb) - - # 9. loop.body:读回参数(装饰器可能已修改)→ 调用原函数 → store ret - llvmlite.position_at_end(wb, loop_b_bb) - call_args: llvmlite.Value | t.CPtr = None - if n_params > 0: - k: int = 0 - for k in range(n_params): - fld_ty_k: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)( - t.CVoid(param_tys[k], t.CPtr)) - fld_pk: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - wb, args_ty, fld_ty_k, args_alloca, k) - if fld_pk is None: - continue - fld_vk: llvmlite.Value | t.CPtr = llvmlite.build_load(wb, fld_ty_k, fld_pk) - if fld_vk is not None: - llvmlite.value_set_next(fld_vk, None) - if call_args is None: - call_args = fld_vk - else: - ct: llvmlite.Value | t.CPtr = call_args - while ct.Next is not None: - ct = ct.Next - llvmlite.value_set_next(ct, fld_vk) - res_v: llvmlite.Value | t.CPtr = llvmlite.build_call( - wb, orig_call_name, call_args, n_params, ret_ty, 0) - if ret_alloca is not None and res_v is not None: - llvmlite.build_store(wb, res_v, ret_alloca) - nxt_i: llvmlite.Value | t.CPtr = llvmlite.build_add( - wb, cur_i, llvmlite.ConstInt(pool, i32_ty, 1, "1")) - if nxt_i is not None and cnt_alloca is not None: - llvmlite.build_store(wb, nxt_i, cnt_alloca) - llvmlite.build_br(wb, loop_h_bb) - - # 10. post:handler 后置 → 清递归标志 → 返回结果 - llvmlite.position_at_end(wb, post_bb) - ret_ptr: llvmlite.Value | t.CPtr = null_ret - if ret_alloca is not None: - ret_ptr = llvmlite.build_bitcast(wb, ret_alloca, i8_ptr_ty) - ph1: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i32_ty, 1, "1") - # 后置参数链:ctx_ptr → fn_str → 1 → args_ptr → ret_ptr → null - if ctx_ptr is not None: - llvmlite.value_set_next(ctx_ptr, fn_str) - if fn_str is not None: - llvmlite.value_set_next(fn_str, ph1) - if ph1 is not None: - llvmlite.value_set_next(ph1, args_ptr) - if args_ptr is not None: - llvmlite.value_set_next(args_ptr, ret_ptr) - if ret_ptr is not None: - llvmlite.value_set_next(ret_ptr, null_dec) - llvmlite.build_call(wb, handler_name, ctx_ptr, 6, i32_ty, 0) - if rec_flag_ref is not None: - rec_zero2: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i8_ty, 0, "0") - if rec_zero2 is not None: - llvmlite.build_store(wb, rec_zero2, rec_flag_ref) - if ret_is_void != 0: - llvmlite.build_ret_void(wb) - else: - final_v: llvmlite.Value | t.CPtr = llvmlite.build_load(wb, ret_ty, ret_alloca) - if final_v is not None: - llvmlite.build_ret(wb, final_v) - else: - llvmlite.build_ret_void(wb) - +import lib.core.Gen.GenTypes as GenTypes +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.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.ExprCallTable as ExprCallTable + + +# ============================================================ +# FuncGenDef - FuncGenMixin 拆分(阶段 D):函数声明 / translate_function_def / decorator wrapper +# +# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class FuncGenDef(CallGenBase.CallGenBase): + """函数声明 / translate_function_def / decorator wrapper""" + + # ============================================================ + # forward_declare_functions - 预扫描所有顶层 FunctionDef,创建前向声明 + # + # 解决同模块内前向引用问题:如 viperlib.py 中 sprintf(行15) 调用 + # vsnprintf(行41),但 vsnprintf 定义在后面。 + # + # 对每个顶层 FunctionDef: + # 1. 推断返回类型和参数类型 + # 2. 计算 mangled name(含 SHA1 前缀) + # 3. 创建 declare(IsDeclared=1) + # 4. 添加参数 + # 5. 注册到函数表 + # + # 后续 translate_function_def 会通过 find_func_in_module 找到已有的 declare, + # 复用之(清除 IsDeclared,跳过参数创建,直接添加函数体)。 + # ============================================================ + def forward_declare_functions(self, trans: HT.Translator | t.CPtr, + tree: ast.AST | t.CPtr) -> int: + """预扫描所有顶层 FunctionDef,创建前向声明""" + if trans is None or tree is None: + return 0 + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + if pool is None or mod is None: + return 0 + + imported_modules: str = trans._imported_modules + from_imports: str = trans._from_imports + funcs_ptr: GenTypes.FuncEntry | t.CPtr = trans._funcs + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children + if ch is None: + return 0 + + # 解析函数签名期间临时切换到"仅声明"模式: + # 签名里的泛型类注解(如 _empty_like(a: ndarray[t.CDouble]))会触发泛型特化, + # 若此时特化立即翻译方法体,方法体前向引用同模块后续函数(如 _empty_like 自身) + # 会因 declare 尚未创建而报"裸名调用未定义且未导入"。 + # 临时 declare_only=1 使特化只注册结构体(mark_only 不译方法体), + # 方法体由后续 resolve_annotation_type 命中已注册结构体时补译 + # (_specialize_generic_class 的 Phase B 补译分支)。 + saved_declare_only: int = trans._declare_only + trans._declare_only = 1 + cn_count: t.CSizeT = len(ch) + + for ci in range(cn_count): + child: ast.AST | t.CPtr = ch.get(ci) + if child is None: + continue + if child.kind() != ast.ASTKind.FunctionDef: + continue + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child) + if fd is None or fd.name is None: + continue + + # 推断返回类型 + ret_ty: llvmlite.LLVMType | t.CPtr = None + if fd.returns is not None: + ret_ty = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, fd.returns, imported_modules, from_imports, trans) + if ret_ty is None and fd.returns is not None: + if self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "State") != 0: + ret_ty = llvmlite.Void(pool) + if ret_ty is None: + ret_ty = i32_ty + + # 检测 CExtern/State/CExport + has_extern: int = 0 + has_state: int = 0 + has_export: int = 0 + if fd.returns is not None: + has_extern = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "CExtern") + has_state = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "State") + has_export = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "CExport") + # 装饰器形式存储类标记(@t.CExport/@t.CExtern/@t.State/@t.CStatic) + # 对齐 TPC HandlesFunctions._extract_decorator_storage_flags; + # CExport/CExtern/State 影响函数名(导出裸名),CStatic 仅标记。 + # 注意: 用 HandlesClassDef._has_decorator 委托而非 self._has_decorator + # (Mixin 是 @t.NoVTable 静态绑定,跨 Mixin 方法经 MRO 调用会生成 + # 不存在的 FuncGenMixin._has_decorator → 链接 undefined symbol) + if fd.decorator_list is not None: + if has_extern == 0 and self.Gen.ClassGenBase._has_decorator(fd.decorator_list, "CExtern") == 1: + has_extern = 1 + if has_state == 0 and self.Gen.ClassGenBase._has_decorator(fd.decorator_list, "State") == 1: + has_state = 1 + if has_export == 0 and self.Gen.ClassGenBase._has_decorator(fd.decorator_list, "CExport") == 1: + has_export = 1 + is_extern_decl: int = 0 + if has_extern != 0 or has_state != 0: + is_extern_decl = 1 + + # 计算 mangled name + if has_extern != 0 or has_state != 0 or has_export != 0 or string.strcmp(fd.name, "main") == 0: + mangled_name: str = fd.name + else: + mangled_name = self.Gen.FuncGenBase._mangle_func_name(trans, fd.name, 0) + + # 如果函数已存在(如重复定义),跳过 + existing: llvmlite.Function | t.CPtr = self.Gen.CallGenBase.find_func_in_module(mod, mangled_name) + if existing is not None: + continue + + # 创建 declare + func: llvmlite.Function | t.CPtr = llvmlite.create_declare( + pool, mod, mangled_name, ret_ty) + if func is None: + continue + + # 提取默认参数信息 + # 注意: 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(), + # 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错 + fd_args_node: ast.Arguments | t.CPtr = fd.args + fd_defaults: t.CVoid | t.CPtr = None + fd_default_count: int = 0 + fd_param_count: int = 0 + if fd_args_node is not None: + fd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd_args_node) + if fd_ags.args is not None: + fd_alist: list[ast.AST | t.CPtr] | t.CPtr = fd_ags.args + fd_param_count = len(fd_alist) + if fd_ags.defaults is not None: + fd_dlist: list[ast.AST | t.CPtr] | t.CPtr = fd_ags.defaults + fd_defaults = fd_dlist + fd_default_count = len(fd_dlist) + + # 注册到函数表(用裸名 fd.name,不是 mangled_name) + max_funcs: int = 1024 + cur_count: int = trans._func_count + if self.Gen.CallGenLeafKit.add_func_to_table(funcs_ptr, cur_count, fd.name, func, max_funcs, + fd_defaults, fd_default_count, fd_param_count, + trans.Pool) == 0: + trans._func_count = cur_count + 1 + + # 注册 CExport 函数到全局表 + if (has_export != 0 or has_state != 0) and trans.ModuleSha1 is not None: + self.Gen.CallGenBase.register_cexport_func(trans.ModuleSha1, fd.name) + + # 添加参数 + args_node: ast.Arguments | t.CPtr = fd.args + if args_node is not None: + ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if ags.args is not None: + alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args + an: t.CSizeT = len(alist) + for ai in range(an): + arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) + if arg is None or arg.arg is None: + continue + # t.CVoid 表示空参:跳过 + if arg.annotation is not None: + if self.Gen.TypeGenResolve._is_t_attr(arg.annotation, "CVoid", imported_modules) != 0: + continue + param_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if arg.annotation is not None: + resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, arg.annotation, imported_modules, from_imports, trans) + if resolved is not None: + # 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致) + # CArray 形参 → 元素指针 ty*(C 数组衰减,与 add_param 一致) + match resolved: + case llvmlite.LLVMType.Struct(_, _, _): + param_ty = llvmlite.Ptr(pool, resolved) + case llvmlite.LLVMType.Array(aelem_ty, _): + param_ty = llvmlite.Ptr(pool, aelem_ty) + case _: + param_ty = resolved + pname: str = pool.alloc(32) + if pname is not None: + viperlib.snprintf(pname, 32, "%%%s", arg.arg) + llvmlite.add_param(pool, func, param_ty, pname) + + # *args 变长参数:设置 IsVarArg=1,生成 ... 后缀 + if ags.vararg is not None: + func.IsVarArg = 1 + + # 参数添加完成,补全全局函数表的 TypeStr(供 vtable 在 func 被 reset 后使用) + self.Gen.CallGenLeafKit.update_global_func_typestr(trans.Pool, fd.name, func) + + # 恢复原始声明模式 + trans._declare_only = saved_declare_only + return 0 + # ============================================================ + # 翻译函数定义 FunctionDef(name, args, body, ...) + # + # trans 单参模式:所有共享状态从 trans 获取 + # 函数局部作用域通过 enter_scope/exit_scope 管理 + # ============================================================ + def translate_function_def(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译函数定义,返回新增的变量数(通常为 0,函数定义不增加当前作用域变量)""" + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node) + if fd is None or fd.name is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + imported_modules: str = trans._imported_modules + from_imports: str = trans._from_imports + funcs_ptr: GenTypes.FuncEntry | t.CPtr = trans._funcs + func_count: int = trans._func_count + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + + # 推断返回类型:优先使用返回类型注解 + ret_ty: llvmlite.LLVMType | t.CPtr = None + if fd.returns is not None: + ret_ty = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, fd.returns, imported_modules, from_imports, trans) + + # 如果返回类型注解纯装饰器标记(如 t.State,无实际类型),使用 void + # 注意:必须在 infer_return_type 之前检测,因为 infer_return_type 至少返回 i32 + if ret_ty is None and fd.returns is not None: + if self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "State") != 0: + ret_ty = llvmlite.Void(pool) + + # 如果仍然为 None,扫描 return 语句推断(至少返回 i32) + if ret_ty is None: + param_types_str: str = self.Gen.TypeGenErr.build_param_types_str(pool, fd.args) + ret_ty = self.Gen.TypeGenErr.infer_return_type( + pool, fd.children, param_types_str) + # 检测是否为外部声明函数(t.CExtern 或 t.State) + # 语义:t.CExtern 忽略 body 体,仅生成 declare(由链接器解析符号) + # t.State = t.CExtern + t.CExport(既是声明又是导出) + # t.CExport 导出函数不加 SHA1 前缀 + # t.CExtern/t.State/t.CExport 都不加 SHA1 前缀,直接映射到 C 标准库函数名 + is_extern_decl: int = 0 + has_export: int = 0 + has_extern: int = 0 + has_state: int = 0 + if fd.returns is not None: + has_extern = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "CExtern") + has_state = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "State") + has_export = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "CExport") + # t.CExtern/t.State 忽略 body 体,仅声明(无论 body 是否为 pass) + if has_extern != 0 or has_state != 0: + is_extern_decl = 1 + # 装饰器形式存储类标记(@t.CExport/@t.CExtern/@t.State/@t.CStatic), + # 对齐 TPC HandlesFunctions._extract_decorator_storage_flags(与 + # forward_declare_functions 一致,保证 declare 与 define 同名同语义)。 + # 用 HandlesClassDef._has_decorator 委托(Mixin 静态绑定不能 self. 跨类调) + if fd.decorator_list is not None: + if has_extern == 0 and self.Gen.ClassGenBase._has_decorator(fd.decorator_list, "CExtern") == 1: + has_extern = 1 + if has_state == 0 and self.Gen.ClassGenBase._has_decorator(fd.decorator_list, "State") == 1: + has_state = 1 + if has_export == 0 and self.Gen.ClassGenBase._has_decorator(fd.decorator_list, "CExport") == 1: + has_export = 1 + if (has_extern != 0 or has_state != 0) and is_extern_decl == 0: + is_extern_decl = 1 + # @t.TLS 一次性初始化标记(对齐 TPC HandlesFunctions.py L1223-1231) + has_tls: int = 0 + if fd.decorator_list is not None: + has_tls = self.Gen.ClassGenBase._has_decorator(fd.decorator_list, "TLS") + + # 自定义行为装饰器检测(@log/@skip/@repeat(3) 等):非 t 存储标记、 + # 非内置(staticmethod/property/classmethod)的 Name/Name(args) 装饰器。 + # 对齐 TPC HandlesFunctions.py L1161-1189 + DecoratorPass.py。首版取 + # decorator_list 中第一个自定义装饰器(Python 最外层),链式嵌套后续扩展。 + has_custom_decor: int = 0 + decor_handler: str = None + decor_arg0: t.CInt64T = 0 + if fd.decorator_list is not None: + ddn: t.CSizeT = len(fd.decorator_list) + for ddi in range(ddn): + deco: ast.AST | t.CPtr = fd.decorator_list.get(ddi) + if deco is None: + continue + dk: int = deco.kind() + dname: str = None + if dk == ast.ASTKind.Name: + dnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(deco) + dname = dnm.id + elif dk == ast.ASTKind.Call: + dcl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(deco) + if dcl.func is not None and dcl.func.kind() == ast.ASTKind.Name: + dnm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(dcl.func) + dname = dnm2.id + # @repeat(3):取首个常量 int 参数(对齐 TPC L1182-1184) + if dcl.args is not None and len(dcl.args) >= 1: + da0: ast.AST | t.CPtr = dcl.args.get(0) + if da0 is not None and da0.kind() == ast.ASTKind.Constant: + dc0: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(da0) + if dc0.const_kind == ast.CONST_INT: + decor_arg0 = dc0.int_val + if dname is None: + continue + # 跳过内置装饰器 + if string.strcmp(dname, "staticmethod") == 0 \ + or string.strcmp(dname, "property") == 0 \ + or string.strcmp(dname, "classmethod") == 0: + continue + # 跳过 t 模块存储类标记(@t.CExport/@t.CExtern/@t.State/@t.TLS/ + # @t.CStatic/@t.CInline/@t.CVTable/@t.NoVTable/@t.Object/@t.CEnum + # /@t.CUnion/@t.REnum/@t.CDefine 等裸名形式——Attribute 形式 + # @t.xxx 的 kind 是 Attribute,不进入本检测) + if string.strcmp(dname, "CExport") == 0 \ + or string.strcmp(dname, "CExtern") == 0 \ + or string.strcmp(dname, "State") == 0 \ + or string.strcmp(dname, "TLS") == 0 \ + or string.strcmp(dname, "CStatic") == 0 \ + or string.strcmp(dname, "CInline") == 0 \ + or string.strcmp(dname, "CVTable") == 0 \ + or string.strcmp(dname, "NoVTable") == 0 \ + or string.strcmp(dname, "Object") == 0 \ + or string.strcmp(dname, "CEnum") == 0 \ + or string.strcmp(dname, "CUnion") == 0 \ + or string.strcmp(dname, "REnum") == 0 \ + or string.strcmp(dname, "CDefine") == 0: + continue + has_custom_decor = 1 + decor_handler = dname + break + + # SHA1 命名空间:t.CExtern/t.State/t.CExport 不加前缀,直接用裸名 + # (裸名映射到 C 标准库符号,带 sha1 前缀会导致 undefined reference) + # main 函数也不加前缀(程序入口点) + if has_extern != 0 or has_state != 0 or has_export != 0 or string.strcmp(fd.name, "main") == 0: + mangled_name: str = fd.name + else: + mangled_name: str = self.Gen.FuncGenBase._mangle_func_name(trans, fd.name, 0) + + # 注册 CExport 函数到全局表(供跨模块调用查表) + # t.CExport 函数定义用裸名(@strlen),跨模块调用需查表确认用裸名而非 @{sha1}.func + if (has_export != 0 or has_state != 0) and trans.ModuleSha1 is not None: + self.Gen.CallGenBase.register_cexport_func(trans.ModuleSha1, fd.name) + + if is_extern_decl != 0: + # 外部声明函数:生成 declare(仅声明,不定义) + # 先检查是否已由 forward_declare_functions 创建,避免重复 declare + existing_extern: llvmlite.Function | t.CPtr = self.Gen.CallGenBase.find_func_in_module(mod, mangled_name) + if existing_extern is not None: + # 已存在前向声明,复用之,不再重复创建 + return 0 + + func: llvmlite.Function | t.CPtr = llvmlite.create_declare( + pool, mod, mangled_name, ret_ty) + if func is None: + return 0 + + # 注册到函数表 + max_funcs_extern: int = 256 + if self.Gen.CallGenLeafKit.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs_extern, None, 0, 0, pool) == 0: + trans._func_count = func_count + 1 + + # 添加参数(支持类型注解) + args_node_extern: ast.Arguments | t.CPtr = fd.args + if args_node_extern is not None: + ags_e: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node_extern) + if ags_e.args is not None: + alist_e: list[ast.AST | t.CPtr] | t.CPtr = ags_e.args + an_e: t.CSizeT = len(alist_e) + for ai_e in range(an_e): + arg_e: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist_e.get(ai_e)) + if arg_e is not None and arg_e.arg is not None: + # t.CVoid 表示空参:跳过,不添加到函数签名 + if arg_e.annotation is not None \ + and self.Gen.TypeGenResolve._is_t_attr(arg_e.annotation, "CVoid", imported_modules) != 0: + continue + param_ty_e: llvmlite.LLVMType | t.CPtr = i32_ty + if arg_e.annotation is not None: + resolved_e: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, arg_e.annotation, imported_modules, from_imports, trans) + if resolved_e is None: + # fail-fast:外部声明函数参数有注解但类型解析失败, + # 不再静默保持 i32(声明签名错误会在 ABI 层暴露) + self.Gen.TypeGenErr.fatal_error( + arg_e, f"参数 '{arg_e.arg}' 类型解析失败: {self.Gen.TypeGenResolve.annotation_to_str(arg_e.annotation)}", + "NameError") + resolved_e = i32_ty # 不可达(fatal_error 已退出) + if resolved_e is not None: + # 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致) + # CArray 形参 → 元素指针 ty*(C 数组衰减) + match resolved_e: + case llvmlite.LLVMType.Struct(_, _, _): + param_ty_e = llvmlite.Ptr(pool, resolved_e) + case llvmlite.LLVMType.Array(aelem_ty_e, _): + param_ty_e = llvmlite.Ptr(pool, aelem_ty_e) + case _: + param_ty_e = resolved_e + pname_e: str = pool.alloc(32) + if pname_e is not None: + viperlib.snprintf(pname_e, 32, "%%%s", arg_e.arg) + llvmlite.add_param(pool, func, param_ty_e, pname_e) + + # 提取 @c.Attribute 装饰器属性并设置到函数 + func_attrs_e: str = self.Gen.FuncGenBase.extract_func_attrs(pool, fd.decorator_list, imported_modules) + if func_attrs_e is not None: + llvmlite.function_set_attrs(func, func_attrs_e) + + # 参数添加完成,补全全局函数表的 TypeStr + self.Gen.CallGenLeafKit.update_global_func_typestr(pool, fd.name, func) + + return 0 + + # args_node 用于后续 alloca 创建,提前赋值 + args_node: ast.Arguments | t.CPtr = fd.args + + # 检查是否已有前向声明(由 forward_declare_functions 创建) + func: llvmlite.Function | t.CPtr = self.Gen.CallGenBase.find_func_in_module(mod, mangled_name) + if func is not None and llvmlite.function_is_declared(func) != 0: + # 复用前向声明:清除 IsDeclared 标记,转为 define + func.IsDeclared = 0 + # 装饰器属性设置(前向声明时未设置) + func_attrs_reuse: str = self.Gen.FuncGenBase.extract_func_attrs(pool, fd.decorator_list, imported_modules) + if func_attrs_reuse is not None: + llvmlite.function_set_attrs(func, func_attrs_reuse) + else: + # 创建新的 LLVM 函数(使用 SHA1 混淆名) + func = llvmlite.create_function(pool, mod, mangled_name, ret_ty) + if func is None: + fb_cf: str = VLogger.fmt_buf() + if fb_cf is not None: + viperlib.snprintf(fb_cf, 1024, "create_function %s failed", fd.name) + VLogger.error(fb_cf, "FUNC") + return 0 + + # 提取 @c.Attribute 装饰器属性并设置到函数 + func_attrs: str = self.Gen.FuncGenBase.extract_func_attrs(pool, fd.decorator_list, imported_modules) + if func_attrs is not None: + llvmlite.function_set_attrs(func, func_attrs) + + # 提取默认参数信息 + tfd_defaults: t.CVoid | t.CPtr = None + tfd_default_count: int = 0 + tfd_param_count: int = 0 + if args_node is not None: + tfd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if tfd_ags.args is not None: + tfd_alist: list[ast.AST | t.CPtr] | t.CPtr = tfd_ags.args + tfd_param_count = len(tfd_alist) + if tfd_ags.defaults is not None: + tfd_dlist: list[ast.AST | t.CPtr] | t.CPtr = tfd_ags.defaults + tfd_defaults = tfd_dlist + tfd_default_count = len(tfd_dlist) + + # 注册到函数表 + max_funcs: int = 1024 + if self.Gen.CallGenLeafKit.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs, + tfd_defaults, tfd_default_count, tfd_param_count, + trans.Pool) == 0: + trans._func_count = func_count + 1 + + # 添加参数(支持类型注解) + if args_node is not None: + ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if ags.args is not None: + alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args + an: t.CSizeT = len(alist) + 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: + # t.CVoid 表示空参:跳过,不添加到函数签名 + if arg.annotation is not None \ + and self.Gen.TypeGenResolve._is_t_attr(arg.annotation, "CVoid", imported_modules) != 0: + continue + param_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if arg.annotation is not None: + resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, arg.annotation, imported_modules, from_imports, trans) + if resolved is not None: + # 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致) + # CArray 形参 → 元素指针 ty*(C 数组衰减:final(out: t.CArray[..., N]) + # 的 out 指向调用方数组首元素;传 Ptr(数组) 会使 out[i] 的 + # GEP 以整个数组为步长错位,摘要垃圾根因) + match resolved: + case llvmlite.LLVMType.Struct(_, _, _): + param_ty = llvmlite.Ptr(pool, resolved) + case llvmlite.LLVMType.Array(aelem_ty, _): + param_ty = llvmlite.Ptr(pool, aelem_ty) + case _: + param_ty = resolved + pname: str = pool.alloc(32) + if pname is not None: + viperlib.snprintf(pname, 32, "%%%s", arg.arg) + llvmlite.add_param(pool, func, param_ty, pname) + + # *args 变长参数:设置 IsVarArg=1,生成 ... 后缀 + if ags.vararg is not None: + func.IsVarArg = 1 + + # try-except:函数体含 raise → 追加 __eh_msg_out__(i8**)/ + # __eh_code_out__(i32*)输出参数(对齐 TPC HandlesFunctions.py + # L706-711;main 除外)。被调函数把异常编码/消息写入调用方传入 + # 的指针,调用方 _check_eh_return 检测。 + # 注意:必须在参数添加块(if args_node is not None:)外——无参函数 + # (def f())的 args_node 为 None,若放在其内会被跳过,导致函数体 + # store %__eh_code_out__ 但签名无此参数(llc: use of undefined value)。 + if string.strcmp(fd.name, "main") != 0: + if self.Gen.FuncGenBase._body_has_raise(fd) != 0: + i8_ty_eh: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty_eh: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_eh) + i8_ptr_ptr_ty_eh: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty_eh) + i32_ty_eh: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i32_ptr_ty_eh: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty_eh) + if i8_ptr_ptr_ty_eh is not None and i32_ptr_ty_eh is not None: + llvmlite.add_param(pool, func, i8_ptr_ptr_ty_eh, "%__eh_msg_out__") + llvmlite.add_param(pool, func, i32_ptr_ty_eh, "%__eh_code_out__") + + # 参数添加完成,补全全局函数表的 TypeStr + self.Gen.CallGenLeafKit.update_global_func_typestr(trans.Pool, fd.name, func) + + # 创建 entry 块 + entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") + if entry_blk is None: + return 0 + + # 创建函数专属 builder + func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) + if func_builder is None: + return 0 + llvmlite.position_at_end(func_builder, entry_blk) + + # @t.TLS 一次性初始化守卫(对齐 TPC HandlesFunctions.py L1763-1792): + # 首次调用执行函数体并置全局标志 __tls_init_done_{name}=1,后续调用 + # 直接返回默认值。TPV 此前未实现 @t.TLS,_init_tls 每次 TlsAlloc 导致 + # provider 栈跨调用丢失(FakeDuckTest Test 9 注入失败根因)。 + if has_tls != 0: + tls_flag_name: str = pool.alloc(128) + if tls_flag_name is not None: + viperlib.snprintf(tls_flag_name, 128, "__tls_init_done_%s", fd.name) + tls_flag_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.create_global_int( + pool, mod, tls_flag_name, 1, 0) + if tls_flag_gv is not None: + i1_ty_t: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + if i1_ty_t is not None: + # GlobalVariable 不是 Value 子类(字段布局不同),build_load/store + # 按 Value 读 ptr.Ty/ptr.Name 会错位(Ty 读到 Name → void,Name 为空)。 + # 与 create_global_string 一致:构造 Value 视图(Ty=Ptr(i1), Name="@name")。 + tls_gv_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_t) + tls_ref_name: str = pool.alloc(64) + if tls_ref_name is not None: + viperlib.snprintf(tls_ref_name, 64, "@%s", tls_flag_name) + tls_flag_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, tls_gv_ptr_ty, tls_ref_name) + if tls_flag_ref is not None: + tls_flag_ld: llvmlite.Value | t.CPtr = llvmlite.build_load( + func_builder, i1_ty_t, tls_flag_ref) + # 块名唯一化(create_block 不自动编号,同函数同名 label 冲突) + lc_t: int = trans._label_counter + trans._label_counter = lc_t + 1 + tls_bb_buf: str = pool.alloc(64) + if tls_bb_buf is not None: + viperlib.snprintf(tls_bb_buf, 64, "tls.skip.%d", lc_t) + tls_skip_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, tls_bb_buf) + viperlib.snprintf(tls_bb_buf, 64, "tls.cont.%d", lc_t) + tls_cont_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, tls_bb_buf) + if tls_skip_bb is not None and tls_cont_bb is not None: + llvmlite.build_cond_br( + func_builder, tls_flag_ld, tls_skip_bb, tls_cont_bb) + # skip 块:按返回类型生成默认值直接返回 + llvmlite.position_at_end(func_builder, tls_skip_bb) + match ret_ty: + case llvmlite.LLVMType.Void(): + llvmlite.build_ret_void(func_builder) + case llvmlite.LLVMType.Int(_): + tlz0: llvmlite.Value | t.CPtr = llvmlite.ConstInt( + pool, ret_ty, 0, "0") + if tlz0 is not None: + llvmlite.build_ret(func_builder, tlz0) + case llvmlite.LLVMType.Float(_): + tlf0: llvmlite.Value | t.CPtr = llvmlite.ConstFloat( + pool, ret_ty, 0.0) + if tlf0 is not None: + llvmlite.build_ret(func_builder, tlf0) + case _: + tln0: llvmlite.Value | t.CPtr = llvmlite.ConstNull( + pool, ret_ty, "null") + if tln0 is not None: + llvmlite.build_ret(func_builder, tln0) + # cont 块:置标志=1,继续函数体 + llvmlite.position_at_end(func_builder, tls_cont_bb) + tlone: llvmlite.Value | t.CPtr = llvmlite.ConstInt( + pool, i1_ty_t, 1, "1") + if tlone is not None: + llvmlite.build_store(func_builder, tlone, tls_flag_ref) + + # 进入函数作用域(嵌套符号表) + self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_FUNCTION) + + # PEP 695 泛型函数: def f[T](...) — 设置泛型上下文,类型参数映射到 "int" 兜底。 + # TPV 无泛型函数特化机制(类泛型走 _specialize_generic_class),泛型函数按普通 + # 函数编译;设置上下文使参数注解 T / 方法体中的 T(x) 转换可解析为 int。 + # (注意与类特化的 set_generic_context 一样是全局状态,需在退出作用域前清除。) + tp_names_fn: list[str] | t.CPtr = None + if fd.type_params is not None: + tp_names_fn = fd.type_params + tp_args_fn: list[str] | t.CPtr = list[str](pool, 8) + if tp_args_fn is not None: + tpn_fn: t.CSizeT = len(fd.type_params) + tpi_fn: t.CSizeT = 0 + for tpi_fn in range(tpn_fn): + tp_args_fn.append("int") + self.Gen.TypeGenBase.set_generic_context(tp_names_fn, tp_args_fn) + + # 为参数创建 alloca + if args_node is not None: + ags2: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if ags2.args is not None: + alist2: list[ast.AST | t.CPtr] | t.CPtr = ags2.args + an2: t.CSizeT = len(alist2) + for ai2 in range(an2): + arg2: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist2.get(ai2)) + if arg2 is not None and arg2.arg is not None: + # t.CVoid 表示空参:跳过,不创建 alloca + if arg2.annotation is not None: + if self.Gen.TypeGenResolve._is_t_attr(arg2.annotation, "CVoid", imported_modules) != 0: + continue + param_ty2: llvmlite.LLVMType | t.CPtr = i32_ty + if arg2.annotation is not None: + resolved2: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, arg2.annotation, imported_modules, from_imports, trans) + if resolved2 is None: + # fail-fast:参数有注解但类型解析失败,不再静默保持 i32 + self.Gen.TypeGenErr.fatal_error( + arg2, f"参数 '{arg2.arg}' 类型解析失败: {self.Gen.TypeGenResolve.annotation_to_str(arg2.annotation)}", + "NameError") + resolved2 = i32_ty # 不可达(fatal_error 已退出) + if resolved2 is not None: + # 与 add_param 保持一致:裸类形参 → Ptr(struct)(对象即指针); + # CArray 形参 → 元素指针 ty*(数组衰减,alloca 类型须与形参一致, + # 否则 store ty* 到 [N x ty]* 容器类型不匹配) + match resolved2: + case llvmlite.LLVMType.Struct(_, _, _): + param_ty2 = llvmlite.Ptr(pool, resolved2) + case llvmlite.LLVMType.Array(aelem_ty2, _): + param_ty2 = llvmlite.Ptr(pool, aelem_ty2) + case _: + param_ty2 = resolved2 + alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, param_ty2) + if alloca is not None: + self.Gen.VarGen.define_var(trans.SymTab, arg2.arg, alloca) + # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) + # 传 pool:泛型 Subscript 返回 mangled name(对齐 HandlesAnnAssign 修复) + cls_nm: str = None + if arg2.annotation is not None: + cls_nm = self.Gen.TypeGenResolve.extract_class_name_from_annotation( + arg2.annotation, imported_modules, pool) + if cls_nm is not None: + self.Gen.VarGen.set_var_annot_class_name( + trans.SymTab, arg2.arg, cls_nm) + pname2: str = pool.alloc(32) + if pname2 is not None: + viperlib.snprintf(pname2, 32, "%%%s", arg2.arg) + param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, param_ty2, pname2) + llvmlite.build_store(func_builder, param_val, alloca) + + # *args 变长参数:创建 va_list 缓冲区 + 调用 va_start + 注册到符号表 + # 生成 IR: + # %args_va = alloca [24 x i8], align 16 ; va_list 缓冲区(Win64 __va_list_tag) + # %args = bitcast [24 x i8]* %args_va to i8* + # call void @llvm.va_start(i8* %args) ; 初始化 va_list + # 用户函数体内可通过 args 名字读取 va_list 地址(i8*),或用 arg(type) 糖函数 + # 注意:必须在参数 alloca 段(if args_node is not None:)内但 EH 块外—— + # 无 raise 的函数(viperlib.sprintf 等)同样有 *args,若放在 EH 块内 + # 会被跳过,args 未注册到符号表 → NameError: 未定义名称 'args'。 + if ags2.vararg is not None: + vararg_node: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(ags2.vararg) + if vararg_node is not None and vararg_node.arg is not None: + vararg_name_str: str = vararg_node.arg + # va_list 缓冲区 24 字节(Win64 的 __va_list_tag = {i32,i32,i8*,i8*})+ 16 对齐 + # (对齐 TPC HandlesFunctions.py:1739-1741) + i8_ty_va: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty_va: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_va) + va_buf_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty_va, 24) + va_list_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca_aligned( + func_builder, va_buf_ty, 16) + if va_list_alloca is not None: + # i8* 地址(指向 24 字节 va_list 缓冲区)——vararg 名的值语义 + va_list_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + func_builder, va_list_alloca, i8_ptr_ty_va) + if va_list_addr is not None: + # 注册到符号表(translate_name_value 对 vararg 名特殊处理返回地址) + self.Gen.VarGen.define_var(trans.SymTab, vararg_name_str, va_list_alloca) + # 调用 @llvm.va_start(i8* %va_list_addr) + void_ty_va: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + llvmlite.build_call(func_builder, "llvm.va_start", + va_list_addr, 1, void_ty_va, 0) + # 保存到 trans 供 arg(type) 糖函数与 vararg 名翻译使用 + trans._va_list_ptr = va_list_addr + trans._vararg_name = vararg_name_str + + # try-except:新函数作用域 EH 状态从零开始。必须先保存外层函数 + # (调用方/包围函数)的 EH 输出参数,翻译完本函数后再恢复——否则 + # 下方设置本函数 EH 参数会覆盖外层值,恢复时 old_eh_* 拿到的是 + # 本函数自身参数(嵌套函数/多函数链 EH 状态错乱)。 + old_eh_msg_out: llvmlite.Value | t.CPtr = trans._eh_msg_out_param + old_eh_code_out: llvmlite.Value | t.CPtr = trans._eh_code_out_param + old_cur_func_has_eh: int = trans._cur_func_has_eh + trans._eh_msg_out_param = None + trans._eh_code_out_param = None + trans._cur_func_has_eh = 0 + + # try-except:保存当前函数的 EH 输出参数(__eh_msg_out__/__eh_code_out__) + # 供 translate_raise / UnhandledBB 写入并向上传播。无 EH 参数的函数置空。 + if string.strcmp(fd.name, "main") != 0 and self.Gen.FuncGenBase._body_has_raise(fd) != 0: + i8_ty_eh2: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty_eh2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_eh2) + i8_ptr_ptr_ty_eh2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty_eh2) + i32_ty_eh2: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i32_ptr_ty_eh2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty_eh2) + if i8_ptr_ptr_ty_eh2 is not None and i32_ptr_ty_eh2 is not None: + msg_out_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, i8_ptr_ptr_ty_eh2, "%__eh_msg_out__") + code_out_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, i32_ptr_ty_eh2, "%__eh_code_out__") + trans._eh_msg_out_param = msg_out_ref + trans._eh_code_out_param = code_out_ref + trans._cur_func_has_eh = 1 + + # 保存模块级作用域状态(仅非变量表相关) + old_func: llvmlite.Function | t.CPtr = trans._cur_func + old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + old_global_count: int = trans._global_name_count + old_nonlocal_count: int = trans._nonlocal_name_count + old_env_count: int = trans._closure_env_count + old_va_list_ptr: llvmlite.Value | t.CPtr = trans._va_list_ptr + old_vararg_name: str = trans._vararg_name + + trans._cur_func = func + trans._cur_builder = func_builder + # 清空 global/nonlocal 名称集合(新函数作用域) + HT.clear_scope_names(trans) + # 重置链内 nonlocal 堆预建标志(每函数只建一次;多嵌套函数定义 + # 共享同一堆,防重复 malloc + 二次重定向 VarEntry) + trans._nl_chain_done = 0 + + # 预扫描函数体: + # 1. 先预扫描 Global/Nonlocal 声明(Python 语义:global/nonlocal + # 对整个函数作用域生效,与声明位置无关,故须在任何赋值前注册) + # 2. 再预扫描 AnnAssign 为局部变量提前创建 alloca + body: list[ast.AST | t.CPtr] | t.CPtr = fd.children + if body is not None: + bn: t.CSizeT = len(body) + for bi in range(bn): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + self.Gen.StmtGenDecl.pre_scan_scope_decls(trans, stmt) + for bi in range(bn): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + self.Gen.StmtGenDecl.pre_scan_allocas(trans, stmt) + + # 翻译函数体 + if body is not None: + bn2: t.CSizeT = len(body) + for bi2 in range(bn2): + stmt2: ast.AST | t.CPtr = body.get(bi2) + if stmt2 is not None: + # 嵌套函数定义前:预扫描其链内 nonlocal 并建堆 + # (不同层捕获不同变量的场景,见 _prepare_chain_nonlocals) + if stmt2.kind() == ast.ASTKind.FunctionDef: + self.Gen.FuncGen._prepare_chain_nonlocals( + trans, stmt2, pool, func_builder, mod, + llvmlite.Int8(pool), llvmlite.Ptr(pool, llvmlite.Int8(pool))) + self.Gen.StmtGen.translate_stmt(trans, stmt2) + + # 如果函数体最后一条语句不是 Return,添加隐式 ret + last_is_return: int = 0 + # 追加89:bn3 提前初始化,避免 body is None 时下方 fail-fast 分支 + # 引用未定义的 bn3(追加81 同款 NameError 风险) + bn3: t.CSizeT = 0 + if body is not None: + bn3 = len(body) + if bn3 > 0: + last_stmt: ast.AST | t.CPtr = body.get(bn3 - 1) + if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return: + last_is_return = 1 + if last_is_return == 0: + if llvmlite.builder_cur_block_is_terminated(func_builder) == 0: + # 追加89:编译器不替代码发明返回值——函数流程真实掉出末尾而 + # 未显式 return 时 fail-fast(要求补 return,Python traceback + # 风格定位到函数)。三种合法收尾: + # ① void 函数掉出末尾 → ret void(无值可发明,Python 语义) + # ② 末句是控制流语句(match/if 全分支 return)且当前块 + # 未 terminated → merge 块结构性不可达 → unreachable + # ③ 无返回类型注解的函数(fd.returns is None,如 + # ast/base.vp _set_pos 过程风格赋值函数)→ 视为无返回值 + # 函数,默认生成零值返回(用户决策:没有返回值默认不用 + # return;ConstZero 按推断出的 ret_ty 构造,类型匹配) + # 有 -> 注解且末句是普通语句掉出末尾 → fail-fast(不得替代码 + # 发明返回值,也不做 noreturn 函数名白名单——错误终止路径 + # 也必须在源码层面保证块收尾,如显式 return 样板) + # 末句是否为控制流语句(If/Match/While/For/Try/With): + # 控制流语句翻译后当前块未 terminated 表示 merge 块结构性 + # 不可达(所有分支均已 return/terminated)——对非 void 函数 + # 生成 unreachable 而非 fail-fast(GCC/Clang 对 fall-through + # 视为 UB 同语义;追加89 修正 get_struct_name 全 case return + # 被错判"不可能抵达") + last_is_ctrl: int = 0 + if bn3 > 0: + last_stmt3: ast.AST | t.CPtr = body.get(bn3 - 1) + if last_stmt3 is not None: + k3: int = last_stmt3.kind() + if k3 == ast.ASTKind.If or k3 == ast.ASTKind.While or \ + k3 == ast.ASTKind.For or k3 == ast.ASTKind.Try or \ + k3 == ast.ASTKind.With or k3 == ast.ASTKind.Match: + last_is_ctrl = 1 + _is_void: int = 0 + if ret_ty is not None: + match ret_ty: + case llvmlite.LLVMType.Void(): + _is_void = 1 + case _: + pass + if _is_void != 0: + llvmlite.build_ret_void(func_builder) + elif last_is_ctrl != 0 and trans._ctrl_merge_reachable == 0: + # 追加90:非 void 函数末句是控制流且 merge 块结构性不可达 + # (全分支 return,无 br 到 merge)→ LLVM 语义 unreachable。 + # 注意:merge 可达(分支 br 到 merge,如 testcheck.check 的 + # if/else 无 return)时不是结构性不可达,需正常收尾(下方 + # ConstZero / fail-fast)。原实现无条件 unreachable 使 llc + # O2 把 br-to-unreachable 优化为 fall-through → 双分支执行 + # 崩溃(FuncTest check PASS+FAIL 双打印) + llvmlite.build_unreachable(func_builder) + elif fd.returns is None: + # 无返回类型注解 → 无返回值过程函数,默认零值返回 + if ret_ty is not None: + zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, ret_ty) + if zero_val is not None: + llvmlite.build_ret(func_builder, zero_val) + else: + self.Gen.TypeGenErr.fatal_error(node, "函数流程掉出末尾但未显式 return", "TypeError") + else: + self.Gen.TypeGenErr.fatal_error(node, "函数流程掉出末尾但未显式 return", "TypeError") + else: + # fail-fast:有 -> 注解但流程真实掉出末尾(定位到函数定义 + # 节点,fatal_error 输出 traceback 风格错误) + if ret_ty is not None: + # llvmlite 无 type_get_name API,类型序列化用真实接口 + # TypePrint(buf, size, ty, pool)(追加89 修正) + rt_name: str = pool.alloc(64) + if rt_name is not None: + llvmlite.TypePrint(rt_name, 64, ret_ty, pool) + if rt_name[0] == '\0': + rt_name = "?" + err_fn: str = pool.alloc(256) + if err_fn is not None: + viperlib.snprintf( + err_fn, 256, + "函数 '%s' 流程掉出函数末尾但未显式 return(返回类型 %s)," + "请补显式 return(如 return 0 / return null)", fd.name, rt_name) + self.Gen.TypeGenErr.fatal_error(node, err_fn, "TypeError") + self.Gen.TypeGenErr.fatal_error(node, "函数流程掉出末尾但未显式 return", "TypeError") + else: + self.Gen.TypeGenErr.fatal_error(node, "函数流程掉出末尾但未显式 return", "TypeError") + + # 恢复模块级作用域(退出函数作用域) + if tp_names_fn is not None: + self.Gen.TypeGenBase.clear_generic_context() + self.Gen.VarGen.exit_scope(trans.SymTab) + trans._cur_func = old_func + trans._cur_builder = old_builder + trans._global_name_count = old_global_count + trans._nonlocal_name_count = old_nonlocal_count + trans._closure_env_count = old_env_count + trans._va_list_ptr = old_va_list_ptr + trans._vararg_name = old_vararg_name + # 恢复外层函数(调用方)的 EH 输出参数——本函数体内的 raise 传播 + # 使用本函数参数,翻译结束必须交还外层作用域,否则嵌套函数/链式 + # 调用后 EH 状态残留导致 raise 写入错误的 out 指针。 + trans._eh_msg_out_param = old_eh_msg_out + trans._eh_code_out_param = old_eh_code_out + trans._cur_func_has_eh = old_cur_func_has_eh + + # 自定义装饰器:注册 + 生成 wrapper(对齐 TPC DecoratorPass.run)。 + # 仅模块级函数(fd 是顶层定义);wrapper 名 __decor_wrap_{裸函数名}。 + # 调用点重写经 lookup_decor_wrapper(translate_call 拦截原函数名)。 + if has_custom_decor != 0: + wb_name: str = pool.alloc(128) + if wb_name is not None: + viperlib.snprintf(wb_name, 128, "__decor_wrap_%s", fd.name) + self.Gen.ClassGenBase.register_decorator(pool, fd.name, wb_name, decor_arg0) + self._gen_decor_wrapper( + trans, pool, mod, func, fd.name, wb_name, + decor_handler, decor_arg0) + + return 0 + # ============================================================ + # _gen_decor_wrapper - 生成装饰器 wrapper 函数(对齐 TPC DecoratorPass.py + # _generate_single_wrapper v4) + # + # v4 Wrapper 结构(最外层含递归保护): + # entry → 递归保护检查(最外层) + # recursive_call → 递归时直接调用原函数,跳过所有装饰 + # decorated_entry → 置递归标志,分配 ctx/args/ret,调用 handler 前置 + # loop_header → 计数器 i < n_calls(TPV 用 alloca 计数器替代 phi) + # loop.body → 从 args_struct 读回参数,调用原函数 + # post → 调用 handler 后置,清递归标志,返回结果 + # + # handler 调用约定:i32 decor(i8* ctx, i8* func_name, i32 phase, + # i8* args_ptr, i8* ret_ptr, i8* decor_args_ptr) + # 前置返回:0=跳过原函数,1=调用一次,N=循环 N 次 + # ============================================================ + def _gen_decor_wrapper(self, trans: HT.Translator | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + func: llvmlite.Function | t.CPtr, + func_name: str, + wrapper_name: str, + handler_name: str, + decor_arg0: t.CInt64T) -> llvmlite.Function | t.CPtr: + """生成装饰器 wrapper 函数,返回 wrapper 或 None""" + if trans is None or pool is None or mod is None or func is None: + return None + if func_name is None or wrapper_name is None or handler_name is None: + return None + ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(func) + if ret_ty is None: + return None + orig_call_name: str = llvmlite.function_get_name(func) + if orig_call_name is None: + return None + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + # ---- 收集原函数参数类型(按位置,最多 16 个)---- + n_params: int = 0 + param_tys: t.CSizeT | t.CPtr = pool.alloc(16 * 8) + if param_tys is None: + return None + string.memset(param_tys, 0, 16 * 8) + pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) + while pp is not None: + pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pp) + if pty is not None and n_params < 16: + param_tys[n_params] = t.CSizeT(pty) + n_params += 1 + pp = llvmlite.param_get_next(pp) + + # ---- 创建 wrapper 函数并添加参数(名字 %a0..%aN)---- + wrapper: llvmlite.Function | t.CPtr = llvmlite.create_function( + pool, mod, wrapper_name, ret_ty) + if wrapper is None: + return None + pi: int = 0 + for pi in range(n_params): + pname_w: str = pool.alloc(16) + if pname_w is not None: + viperlib.snprintf(pname_w, 16, "%%a%d", pi) + llvmlite.add_param(pool, wrapper, (llvmlite.LLVMType | t.CPtr)( + t.CVoid(param_tys[pi], t.CPtr)), pname_w) + + # ---- 创建块 ---- + entry_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "entry") + loop_h_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "loop.header") + loop_b_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "loop.body") + post_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "post") + if entry_bb is None or loop_h_bb is None or loop_b_bb is None or post_bb is None: + return None + + # 递归保护标志(最外层):@__decor_rec_{wrapper} = global i8 0 + rec_flag_ref: llvmlite.Value | t.CPtr = None + rec_flag_name: str = pool.alloc(128) + if rec_flag_name is not None: + viperlib.snprintf(rec_flag_name, 128, "__decor_rec_%s", wrapper_name) + llvmlite.create_global_int(pool, mod, rec_flag_name, 8, 0) + rec_ref_nm: str = pool.alloc(96) + if rec_ref_nm is not None: + viperlib.snprintf(rec_ref_nm, 96, "@%s", rec_flag_name) + rec_flag_ref = llvmlite.SSAValue(pool, llvmlite.Ptr(pool, i8_ty), rec_ref_nm) + + wb: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, wrapper) + if wb is None: + return None + + # 返回类型分类 + ret_is_void: int = 0 + match ret_ty: + case llvmlite.LLVMType.Void(): + ret_is_void = 1 + case _: + pass + + # ---- entry:递归保护检查(最外层)---- + llvmlite.position_at_end(wb, entry_bb) + loop_pred_bb: llvmlite.BasicBlock | t.CPtr = entry_bb + if rec_flag_ref is not None: + rec_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "recursive_call") + dec_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "decorated_entry") + if rec_bb is None or dec_bb is None: + return None + rec_val: llvmlite.Value | t.CPtr = llvmlite.build_load(wb, i8_ty, rec_flag_ref) + rec_zero: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i8_ty, 0, "0") + rec_is: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + wb, llvmlite.ICMP_NE, rec_val, rec_zero) + llvmlite.build_cond_br(wb, rec_is, rec_bb, dec_bb) + # recursive_call:直接调用原函数返回(跳过所有装饰逻辑) + llvmlite.position_at_end(wb, rec_bb) + rec_args: llvmlite.Value | t.CPtr = None + ri: int = 0 + for ri in range(n_params): + an_r: str = pool.alloc(16) + if an_r is None: + continue + viperlib.snprintf(an_r, 16, "%%a%d", ri) + av_r: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, (llvmlite.LLVMType | t.CPtr)(t.CVoid(param_tys[ri], t.CPtr)), an_r) + if av_r is not None: + llvmlite.value_set_next(av_r, None) + if rec_args is None: + rec_args = av_r + else: + # 链尾追加 + rt: llvmlite.Value | t.CPtr = rec_args + while rt.Next is not None: + rt = rt.Next + llvmlite.value_set_next(rt, av_r) + if ret_is_void != 0: + llvmlite.build_call(wb, orig_call_name, rec_args, n_params, ret_ty, 0) + llvmlite.build_ret_void(wb) + else: + rc_res: llvmlite.Value | t.CPtr = llvmlite.build_call( + wb, orig_call_name, rec_args, n_params, ret_ty, 0) + if rc_res is not None: + llvmlite.build_ret(wb, rc_res) + else: + llvmlite.build_ret_void(wb) + # decorated_entry:置递归标志,继续装饰路径 + llvmlite.position_at_end(wb, dec_bb) + rec_one: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i8_ty, 1, "1") + if rec_one is not None: + llvmlite.build_store(wb, rec_one, rec_flag_ref) + loop_pred_bb = dec_bb + + # ---- 公共装饰路径(entry 或 decorated_entry)---- + # 1. ctx = alloca [32 x i8]; ctx_ptr = bitcast i8* + ctx_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, 32) + ctx_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(wb, ctx_ty) + ctx_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(wb, ctx_alloca, i8_ptr_ty) + + # 2. 打包函数参数到结构体 {param_types}(装饰器可读写 args_ptr) + args_alloca: llvmlite.Value | t.CPtr = None + args_ptr: llvmlite.Value | t.CPtr = None + if n_params > 0: + fields_head: llvmlite.ParamNode | t.CPtr = None + fk: int = 0 + for fk in range(n_params - 1, -1, -1): + pn_n: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node( + pool, (llvmlite.LLVMType | t.CPtr)(t.CVoid(param_tys[fk], t.CPtr))) + if pn_n is not None: + pn_n.Next = fields_head + fields_head = pn_n + args_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct( + pool, fields_head, n_params, None) + if args_ty is not None: + args_alloca = llvmlite.build_alloca(wb, args_ty) + fi2: int = 0 + for fi2 in range(n_params): + fld_ty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)( + t.CVoid(param_tys[fi2], t.CPtr)) + fld_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + wb, args_ty, fld_ty, args_alloca, fi2) + if fld_ptr is not None: + fld_nm: str = pool.alloc(16) + if fld_nm is not None: + viperlib.snprintf(fld_nm, 16, "%%a%d", fi2) + fld_v: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, fld_ty, fld_nm) + if fld_v is not None: + llvmlite.build_store(wb, fld_v, fld_ptr) + args_ptr = llvmlite.build_bitcast(wb, args_alloca, i8_ptr_ty) + else: + args_ptr = llvmlite.ConstNull(pool, i8_ptr_ty, "null") + + # 3. 返回值存储(零初始化;跳过原函数时返回安全默认值) + ret_alloca: llvmlite.Value | t.CPtr = None + if ret_is_void == 0: + ret_alloca = llvmlite.build_alloca(wb, ret_ty) + ret_zero: llvmlite.Value | t.CPtr = None + match ret_ty: + case llvmlite.LLVMType.Int(_): + ret_zero = llvmlite.ConstInt(pool, ret_ty, 0, "0") + case llvmlite.LLVMType.Float(_): + ret_zero = llvmlite.ConstFloat(pool, ret_ty, 0.0) + case _: + ret_zero = llvmlite.ConstNull(pool, ret_ty, "null") + if ret_zero is not None and ret_alloca is not None: + llvmlite.build_store(wb, ret_zero, ret_alloca) + + # 4. 函数名字符串常量 + fn_str: llvmlite.Value | t.CPtr = self.Gen.ExprGenConst.create_global_string( + wb, pool, mod, func_name, trans) + if fn_str is None: + fn_str = llvmlite.ConstNull(pool, i8_ptr_ty, "null") + + # 5. handler 声明(未翻译时 declare,固定签名 i32 (i8*,i8*,i32,i8*,i8*,i8*)) + if self.Gen.CallGenBase.find_func_in_module(mod, handler_name) is None: + handler_d: llvmlite.Function | t.CPtr = llvmlite.create_declare( + pool, mod, handler_name, i32_ty) + if handler_d is not None: + llvmlite.add_param(pool, handler_d, i8_ptr_ty, "ctx") + llvmlite.add_param(pool, handler_d, i8_ptr_ty, "func_name") + llvmlite.add_param(pool, handler_d, i32_ty, "phase") + llvmlite.add_param(pool, handler_d, i8_ptr_ty, "args_ptr") + llvmlite.add_param(pool, handler_d, i8_ptr_ty, "ret_ptr") + llvmlite.add_param(pool, handler_d, i8_ptr_ty, "decor_args_ptr") + + # 6. 前置阶段:handler 返回调用次数 n_calls + ph0: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i32_ty, 0, "0") + null_ret: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty, "null") + null_dec: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty, "null") + # 参数链表(6 个独立值):ctx_ptr → fn_str → 0 → args_ptr → null → null + # 注意:不能 self 链接(null.Next = null 会让 build_call 遍历死循环) + if ctx_ptr is not None: + llvmlite.value_set_next(ctx_ptr, fn_str) + if fn_str is not None: + llvmlite.value_set_next(fn_str, ph0) + if ph0 is not None: + llvmlite.value_set_next(ph0, args_ptr) + if args_ptr is not None: + llvmlite.value_set_next(args_ptr, null_ret) + if null_ret is not None: + llvmlite.value_set_next(null_ret, null_dec) + n_calls: llvmlite.Value | t.CPtr = llvmlite.build_call( + wb, handler_name, ctx_ptr, 6, i32_ty, 0) + + # 7. 计数器 alloca(TPV 用 alloca 计数器替代 phi) + cnt_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(wb, i32_ty) + cnt_zero: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i32_ty, 0, "0") + if cnt_alloca is not None and cnt_zero is not None: + llvmlite.build_store(wb, cnt_zero, cnt_alloca) + llvmlite.build_br(wb, loop_h_bb) + + # 8. loop.header:cur = load cnt; cur < n_calls → body / post + llvmlite.position_at_end(wb, loop_h_bb) + cur_i: llvmlite.Value | t.CPtr = llvmlite.build_load(wb, i32_ty, cnt_alloca) + loop_cond: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + wb, llvmlite.ICMP_SLT, cur_i, n_calls) + llvmlite.build_cond_br(wb, loop_cond, loop_b_bb, post_bb) + + # 9. loop.body:读回参数(装饰器可能已修改)→ 调用原函数 → store ret + llvmlite.position_at_end(wb, loop_b_bb) + call_args: llvmlite.Value | t.CPtr = None + if n_params > 0: + k: int = 0 + for k in range(n_params): + fld_ty_k: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)( + t.CVoid(param_tys[k], t.CPtr)) + fld_pk: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + wb, args_ty, fld_ty_k, args_alloca, k) + if fld_pk is None: + continue + fld_vk: llvmlite.Value | t.CPtr = llvmlite.build_load(wb, fld_ty_k, fld_pk) + if fld_vk is not None: + llvmlite.value_set_next(fld_vk, None) + if call_args is None: + call_args = fld_vk + else: + ct: llvmlite.Value | t.CPtr = call_args + while ct.Next is not None: + ct = ct.Next + llvmlite.value_set_next(ct, fld_vk) + res_v: llvmlite.Value | t.CPtr = llvmlite.build_call( + wb, orig_call_name, call_args, n_params, ret_ty, 0) + if ret_alloca is not None and res_v is not None: + llvmlite.build_store(wb, res_v, ret_alloca) + nxt_i: llvmlite.Value | t.CPtr = llvmlite.build_add( + wb, cur_i, llvmlite.ConstInt(pool, i32_ty, 1, "1")) + if nxt_i is not None and cnt_alloca is not None: + llvmlite.build_store(wb, nxt_i, cnt_alloca) + llvmlite.build_br(wb, loop_h_bb) + + # 10. post:handler 后置 → 清递归标志 → 返回结果 + llvmlite.position_at_end(wb, post_bb) + ret_ptr: llvmlite.Value | t.CPtr = null_ret + if ret_alloca is not None: + ret_ptr = llvmlite.build_bitcast(wb, ret_alloca, i8_ptr_ty) + ph1: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i32_ty, 1, "1") + # 后置参数链:ctx_ptr → fn_str → 1 → args_ptr → ret_ptr → null + if ctx_ptr is not None: + llvmlite.value_set_next(ctx_ptr, fn_str) + if fn_str is not None: + llvmlite.value_set_next(fn_str, ph1) + if ph1 is not None: + llvmlite.value_set_next(ph1, args_ptr) + if args_ptr is not None: + llvmlite.value_set_next(args_ptr, ret_ptr) + if ret_ptr is not None: + llvmlite.value_set_next(ret_ptr, null_dec) + llvmlite.build_call(wb, handler_name, ctx_ptr, 6, i32_ty, 0) + if rec_flag_ref is not None: + rec_zero2: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i8_ty, 0, "0") + if rec_zero2 is not None: + llvmlite.build_store(wb, rec_zero2, rec_flag_ref) + if ret_is_void != 0: + llvmlite.build_ret_void(wb) + else: + final_v: llvmlite.Value | t.CPtr = llvmlite.build_load(wb, ret_ty, ret_alloca) + if final_v is not None: + llvmlite.build_ret(wb, final_v) + else: + llvmlite.build_ret_void(wb) + return wrapper \ No newline at end of file diff --git a/App/lib/core/Gen/FuncGenMixin.vp b/App/lib/core/Gen/FuncGenMixin.vp index 4fad5cd..6b3cb83 100644 --- a/App/lib/core/Gen/FuncGenMixin.vp +++ b/App/lib/core/Gen/FuncGenMixin.vp @@ -1,1180 +1,1173 @@ -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.HandlesTranslator as HT -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesExpr as HandlesExpr -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.HandlesBody as HandlesBody -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Gen.CallGenBase as CallGenBase -import lib.core.Handles.ExprCallCall as ExprCallCall -import lib.core.Handles.ExprCallHandle as ExprCallHandle - - -# ============================================================ -# FuncGenMixin - 函数/方法声明与翻译 Mixin(对象化 P5-1,wiki/14-oo-refactor.md) -# -# 从 HandlesFunctions.vp 迁移:模块级纯函数(trans 首参,无全局状态) -# → 类方法(self 替代,trans 参数保留)。 -# -# 迁移原则(与 P2/P3/P4 一致,行为零变化): -# 1. 方法保留原函数签名(含 trans 首参),仅函数体内的 -# 本模块函数调用改为 self.xxx(...) -# 2. 外部模块调用(HandlesExprCall.xxx/HandlesType.xxx 等)保留模块前缀 -# 3. HandlesFunctions.vp 原函数保留为"委托":本地模块级单例 _g_gen -# (BuildPipeline/main 注入)cast 成 Generator 类型 -# -# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 -# ============================================================ - - -# ============================================================ -# HandlesFunctions - 函数定义处理(trans 单参模式) -# -# 参考 Python 版 TransPyC FunctionHandle -# -# 函数有自己的局部作用域,通过 HandlesVar.enter_scope/exit_scope -# 管理嵌套作用域链,翻译函数体前进入函数作用域,翻译完退出。 -# ============================================================ - - -# 作用域类型常量(本地副本,与 HandlesFunctions.vp 保持一致) -SCOPE_FUNCTION: t.CDefine = 1 - - -# ============================================================ -# FuncGenMixin - 函数属性/命名/声明/翻译 -# ============================================================ -@t.NoVTable -class FuncGenMixin(CallGenBase.CallGenBase): - """函数/方法翻译 Mixin(纯方法化迁移,无状态字段)""" - - - - - - - - - - - - - - # ============================================================ - # translate_nested_function_def - 嵌套函数提升 + 闭包创建 - # - # 将嵌套函数提升为顶层函数 @__closure_{name}(i8* %env) -> i32, - # 在父函数中创建闭包对象 {i8* fn_ptr, i8* env_ptr} 并存储到 - # 以函数名命名的局部变量中。 - # - # 闭包结构: {i8* fn_ptr, i8* env_ptr} (16 字节, malloc 分配) - # Env 结构: {i8* ptr0, i8* ptr1, ...} (每个 nonlocal 变量 8 字节,指向父函数 alloca) - # ============================================================ - def translate_nested_function_def(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译嵌套函数定义:提升为顶层函数 + 创建闭包""" - fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node) - if fd is None or fd.name is None: - return 0 - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - func_name: str = fd.name - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - # 1. 构建提升后的函数名: __closure_{name}(加 SHA1 前缀避免跨模块冲突) - promoted_name: str = pool.alloc(64) - if promoted_name is not None: - viperlib.snprintf(promoted_name, 64, "__closure_%s", func_name) - mangled_promoted: str = ExprCallHandle._mangle_name(trans, promoted_name) - - # 2. 创建提升后的函数: define i32 @__closure_{name}(i8* %env, args...) - func: llvmlite.Function | t.CPtr = llvmlite.create_function( - pool, mod, mangled_promoted, i32_ty) - if func is None: - return 0 - llvmlite.add_param(pool, func, i8_ptr_ty, "%env") - - # 2a. 嵌套函数参数:加入提升函数签名(i8* %env, 参数...), - # 类型存入 param_tys 缓冲(CVoid 跳过,与 alloca 创建索引对齐) - imported_modules: str = trans._imported_modules - from_imports: str = trans._from_imports - param_tys: t.CVoid | t.CPtr = pool.alloc(8 * 64) - if param_tys is not None: - string.memset(param_tys, 0, 8 * 64) - param_count: int = 0 - if fd.args is not None: - ags_n: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args) - if ags_n.args is not None: - alist_n: list[ast.AST | t.CPtr] | t.CPtr = ags_n.args - an_n: t.CSizeT = len(alist_n) - for ai_n in range(an_n): - arg_n: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist_n.get(ai_n)) - if arg_n is None or arg_n.arg is None: - continue - if arg_n.annotation is not None: - if HandlesType._is_t_attr(arg_n.annotation, "CVoid", imported_modules) != 0: - continue - pty_n: llvmlite.LLVMType | t.CPtr = i32_ty - if arg_n.annotation is not None: - resolved_n: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, arg_n.annotation, imported_modules, from_imports, trans) - if resolved_n is not None: - match resolved_n: - case llvmlite.LLVMType.Struct(_, _, _): - pty_n = llvmlite.Ptr(pool, resolved_n) - case llvmlite.LLVMType.Array(aelem_ty_n, _): - pty_n = llvmlite.Ptr(pool, aelem_ty_n) - case _: - pty_n = resolved_n - if param_count < 64 and param_tys is not None: - pty_slot_n: str | t.CPtr = (t.CVoid | t.CPtr)( - t.CUInt64T(param_tys) + param_count * 8) - pty_slot_n[0] = pty_n - pname_n: str = pool.alloc(32) - if pname_n is not None: - viperlib.snprintf(pname_n, 32, "%%%s", arg_n.arg) - llvmlite.add_param(pool, func, pty_n, pname_n) - param_count += 1 - - # 3. 创建 entry 块 + builder - entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") - if entry_blk is None: - return 0 - func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) - if func_builder is None: - return 0 - llvmlite.position_at_end(func_builder, entry_blk) - - # 4. 进入嵌套函数作用域(嵌套符号表) - HandlesVar.enter_scope(trans.SymTab, SCOPE_FUNCTION) - - # 5. 创建 _env_ptr alloca 并存储 %env 参数 - env_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, i8_ptr_ty) - if env_alloca is not None: - HandlesVar.define_var(trans.SymTab, "_env_ptr", env_alloca) - env_param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "%env") - llvmlite.build_store(func_builder, env_param_val, env_alloca) - - # 5a. 创建嵌套函数参数 alloca(函数体内参数名可引用,如 - # accumulate(n) 内 for i in range(n)、set_result(val) 内 result = val) - if fd.args is not None: - ags_p: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args) - if ags_p.args is not None: - alist_p: list[ast.AST | t.CPtr] | t.CPtr = ags_p.args - idx_p: int = 0 - apn: t.CSizeT = len(alist_p) - for api in range(apn): - arg_p: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist_p.get(api)) - if arg_p is None or arg_p.arg is None: - continue - if arg_p.annotation is not None: - if HandlesType._is_t_attr(arg_p.annotation, "CVoid", imported_modules) != 0: - continue - if idx_p >= param_count: - break - pty2_n: llvmlite.LLVMType | t.CPtr = i32_ty - if param_tys is not None: - ty_addr_n: t.CUInt64T = t.CUInt64T(param_tys) + idx_p * 8 - ty_slot_n: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr_n) - pty2_n = (llvmlite.LLVMType | t.CPtr)(ty_slot_n[0]) - if pty2_n is None: - pty2_n = i32_ty - p_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, pty2_n) - if p_alloca is not None: - HandlesVar.define_var(trans.SymTab, arg_p.arg, p_alloca) - if arg_p.annotation is not None: - cls_nm_p: str = HandlesType.extract_class_name_from_annotation( - arg_p.annotation, imported_modules, pool) - if cls_nm_p is not None: - HandlesVar.set_var_annot_class_name( - trans.SymTab, arg_p.arg, cls_nm_p) - pname2_n: str = pool.alloc(32) - if pname2_n is not None: - viperlib.snprintf(pname2_n, 32, "%%%s", arg_p.arg) - p_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, pty2_n, pname2_n) - llvmlite.build_store(func_builder, p_val, p_alloca) - idx_p += 1 - - # 6. 保存父函数作用域状态(仅非变量表相关) - old_func: llvmlite.Function | t.CPtr = trans._cur_func - old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - old_func_name: str = trans._cur_func_name - old_global_count: int = trans._global_name_count - old_nonlocal_count: int = trans._nonlocal_name_count - old_env_count: int = trans._closure_env_count - # nonlocal 集合独立缓冲:嵌套函数注册 nonlocal 写入共享缓冲 [0] 会 - # 覆盖父函数集合(ClosureTest2 Test 7 不同变量场景:level2 的 b 覆盖 - # level1 的 a → level1 env[0] 存错)。嵌套函数用独立缓冲,翻译完恢复。 - saved_nl_names: t.CVoid | t.CPtr = trans._nonlocal_names - saved_nl_types: t.CVoid | t.CPtr = trans._nonlocal_types - - # 7. 切换到嵌套函数作用域 + 清空 scope names - trans._cur_func = func - trans._cur_builder = func_builder - trans._cur_func_name = func_name - HT.clear_scope_names(trans) - # 嵌套函数独立 nonlocal 缓冲(避免覆盖父函数集合) - trans._nonlocal_names = stdlib.malloc(HT.MAX_GLOBAL_NAMES * 8) - trans._nonlocal_types = stdlib.malloc(HT.MAX_GLOBAL_NAMES * 8) - if trans._nonlocal_names is not None: - string.memset(trans._nonlocal_names, 0, HT.MAX_GLOBAL_NAMES * 8) - if trans._nonlocal_types is not None: - string.memset(trans._nonlocal_types, 0, HT.MAX_GLOBAL_NAMES * 8) - - # 8. 预扫描函数体: - # a. 先预扫描 Global/Nonlocal 声明(Python 语义:对整个函数作用域生效) - # b. 再预扫描 AnnAssign 为局部变量提前创建 alloca - body: list[ast.AST | t.CPtr] | t.CPtr = fd.children - if body is not None: - bn: t.CSizeT = len(body) - for bi in range(bn): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.pre_scan_scope_decls(trans, stmt) - for bi in range(bn): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.pre_scan_allocas(trans, stmt) - - # 9. 翻译函数体(Nonlocal 语句会填充 _nonlocal_names) - if body is not None: - bn2: t.CSizeT = len(body) - for bi2 in range(bn2): - stmt2: ast.AST | t.CPtr = body.get(bi2) - if stmt2 is not None: - HandlesBody.translate_stmt(trans, stmt2) - - # 10. 隐式 ret - last_is_return: int = 0 - if body is not None: - bn3: t.CSizeT = len(body) - if bn3 > 0: - last_stmt: ast.AST | t.CPtr = body.get(bn3 - 1) - if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return: - last_is_return = 1 - if last_is_return == 0: - zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - llvmlite.build_ret(func_builder, zero_val) - - # 11. 保存嵌套函数的 nonlocal 信息 - nested_nonlocal_count: int = trans._nonlocal_name_count - - # 12. 退出嵌套函数作用域,回到父函数作用域(保留 _nonlocal_names 用于 env 创建) - HandlesVar.exit_scope(trans.SymTab) - trans._cur_func = old_func - trans._cur_builder = old_builder - # NOTE: _nonlocal_names 和 _nonlocal_name_count 仍为嵌套函数的值 - - # 13. 在父函数中创建闭包对象 - parent_builder: llvmlite.IRBuilder | t.CPtr = old_builder - if parent_builder is None: - # 无 builder(模块级嵌套函数?)→ 无法创建闭包,仅恢复状态 - trans._cur_func_name = old_func_name - trans._global_name_count = old_global_count - trans._nonlocal_name_count = old_nonlocal_count - trans._closure_env_count = old_env_count - trans._nonlocal_names = saved_nl_names - trans._nonlocal_types = saved_nl_types - return 0 - - # 13a. 创建 env: malloc(8 * nested_nonlocal_count) — env 存储指针数组 - # 每个 nonlocal 变量占 8 字节(i8*),指向父函数的 alloca(共享存储) - env_ptr: llvmlite.Value | t.CPtr = None - if nested_nonlocal_count > 0: - env_size: t.CInt64T = nested_nonlocal_count * 8 - env_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, env_size) - if env_size_val is not None: - env_size_val.Next = None - env_ptr = llvmlite.build_call( - parent_builder, "malloc", env_size_val, 1, i8_ptr_ty, 0) - - # 为每个 nonlocal 变量建立堆存储并注册到 env: - # 运行时 env 链式共享(无需编译期映射——映射存编译期 Value 对象 - # 地址会被 inttoptr 当运行时堆地址解引用崩溃;存整型也拿不到 - # 运行时 malloc 结果): - # - 变量是父函数局部(lookup_current 在当前作用域找到 alloca) - # → 新建堆(malloc + 拷贝当前值),并把父函数 VarEntry.Alloca - # 重定向到堆——父函数后续读写走共享堆 - # - 变量是父函数的 nonlocal(多层嵌套,当前作用域无 alloca) - # → 从父函数 env 读该变量的堆地址(_load_raw_var_ptr), - # env[ni] = 同一堆地址(运行时链式共享,各层写同一堆) - if env_ptr is not None: - i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty) - for ni in range(nested_nonlocal_count): - # 从 _nonlocal_names 缓冲区读取名称 - name_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + ni * 8 - nl_slot: str | t.CPtr = (t.CVoid | t.CPtr)(name_addr) - nl_name: str = nl_slot[0] - if nl_name is None: - continue - heap_store: llvmlite.Value | t.CPtr = None - # 1. 优先查全局堆地址映射(_prepare_chain_nonlocals 已为 - # 链内 nonlocal 建堆并 store 到 @nlheap.*;不同层捕获 - # 不同变量时(ClosureTest2 Test 7)level2 的 b 经此共享) - gname_ck: str = self._nl_heap_global_name( - pool, trans, nl_name) - if gname_ck is not None \ - and self._nl_heap_global_exists(mod, gname_ck) != 0: - gv_ref0: llvmlite.Value | t.CPtr = self._nl_heap_global_ref( - pool, trans, nl_name) - if gv_ref0 is not None: - heap_store = llvmlite.build_load( - parent_builder, i8_ptr_ty, gv_ref0) - if heap_store is None: - local_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( - trans.SymTab, nl_name) - if local_alloca is not None and local_alloca.Ty is not None: - # 父函数局部变量:新建堆存储 + 拷贝当前值 + 重定向 - nl_load_ty: llvmlite.LLVMType | t.CPtr = local_alloca.Ty.Pointee - if nl_load_ty is not None: - cur_val_nl: llvmlite.Value | t.CPtr = llvmlite.build_load( - parent_builder, nl_load_ty, local_alloca) - # 堆存储大小按类型字节数:数组(如 [4 x i32]=16 字节) - # 不能固定 8 字节(越界写崩溃);指针/标量 ≥ 8 字节 - st_size: t.CInt = self._type_byte_size(pool, nl_load_ty) - st_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64( - pool, st_size) - if st_size_val is not None: - st_size_val.Next = None - var_storage: llvmlite.Value | t.CPtr = llvmlite.build_call( - parent_builder, "malloc", st_size_val, 1, i8_ptr_ty, 0) - if var_storage is not None: - # 拷贝当前值到堆存储 - st_slot_nl: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - parent_builder, var_storage, llvmlite.Ptr(pool, nl_load_ty)) - if st_slot_nl is not None and cur_val_nl is not None: - llvmlite.build_store(parent_builder, cur_val_nl, st_slot_nl) - # 父函数 VarEntry.Alloca 重定向到堆(父函数读写走共享堆) - ve_nl: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nl_name) - heap_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - parent_builder, var_storage, llvmlite.Ptr(pool, nl_load_ty)) - if ve_nl is not None and heap_typed is not None: - ve_nl.Alloca = heap_typed - # 记录到全局映射(后续层/父函数可见) - gv_ref_new: llvmlite.Value | t.CPtr = None - if gname_ck is not None \ - and self._nl_heap_global_exists(mod, gname_ck) == 0: - gv_new: llvmlite.GlobalVariable | t.CPtr = \ - llvmlite.new_global_variable(pool, gname_ck, i8_ptr_ty) - if gv_new is not None: - # 清除 external linkage + 零初始化(防 undefined reference) - gv_new.Linkage = None - gv_new.Initializer = "null" - llvmlite.module_add_global(mod, gv_new) - gv_ref_new = self._nl_heap_global_ref(pool, trans, nl_name) - if gv_ref_new is not None: - llvmlite.build_store( - parent_builder, var_storage, gv_ref_new) - heap_store = var_storage - else: - # 父函数中该变量是 nonlocal(多层嵌套):从父函数 env - # 读堆地址(运行时链式共享同一堆),不新建 - heap_store = HandlesNonlocal._load_raw_var_ptr(trans, nl_name) - if heap_store is None: - continue - # env[ni] = 堆存储地址(共享) - offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, ni * 8) - slot: llvmlite.Value | t.CPtr = llvmlite.build_gep( - parent_builder, i8_ty, env_ptr, offset_val) - if slot is not None: - slot_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - parent_builder, slot, i8_ptr_ptr_ty) - if slot_typed is not None: - llvmlite.build_store(parent_builder, heap_store, slot_typed) - - # 13b. 创建闭包结构: malloc(16) - closure_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 16) - if closure_size_val is not None: - closure_size_val.Next = None - closure_ptr: llvmlite.Value | t.CPtr = llvmlite.build_call( - parent_builder, "malloc", closure_size_val, 1, i8_ptr_ty, 0) - if closure_ptr is None: - # malloc 失败,恢复状态 - trans._cur_func_name = old_func_name - trans._global_name_count = old_global_count - trans._nonlocal_name_count = old_nonlocal_count - trans._closure_env_count = old_env_count - trans._nonlocal_names = saved_nl_names - trans._nonlocal_types = saved_nl_types - return 0 - - # 13c. 存储 fn_ptr 到 offset 0 - # 创建函数指针类型 i32(i8*)* - fn_param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) - fn_func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, fn_param_node, 1) - fn_func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, fn_func_ty) - - # 创建函数引用 Value(类型为 i32(i8*)*,使用 SHA1 混淆名) - fn_ptr_name: str = pool.alloc(64) - if fn_ptr_name is not None: - # SHA1 前缀名含 '.' 需要加引号(如 @"sha1.__closure_func") - if string.strchr(mangled_promoted, '.') is not None: - viperlib.snprintf(fn_ptr_name, 64, "@\"%s\"", mangled_promoted) - else: - viperlib.snprintf(fn_ptr_name, 64, "@%s", mangled_promoted) - fn_ptr_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, fn_func_ptr_ty, fn_ptr_name) - - # bitcast 函数指针到 i8*(闭包存储 i8* 类型) - fn_as_i8ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - parent_builder, fn_ptr_val, i8_ptr_ty) - fn_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - parent_builder, closure_ptr, llvmlite.Ptr(pool, i8_ptr_ty)) - if fn_slot is not None and fn_as_i8ptr is not None: - llvmlite.build_store(parent_builder, fn_as_i8ptr, fn_slot) - - # 13d. 存储 env_ptr 到 offset 8 - eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 8) - env_slot_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep( - parent_builder, i8_ty, closure_ptr, eight_val) - if env_slot_addr is not None: - env_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - parent_builder, env_slot_addr, llvmlite.Ptr(pool, i8_ptr_ty)) - if env_slot is not None: - if env_ptr is not None: - llvmlite.build_store(parent_builder, env_ptr, env_slot) - else: - # 无 nonlocal 变量,存储 null - null_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "null") - llvmlite.build_store(parent_builder, null_val, env_slot) - - # 13e. 将闭包指针存储到父函数的局部变量 {func_name} - closure_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(parent_builder, i8_ptr_ty) - if closure_alloca is not None: - llvmlite.build_store(parent_builder, closure_ptr, closure_alloca) - HandlesVar.define_var(trans.SymTab, func_name, closure_alloca) - # 注册闭包变量名(供调用时区分闭包 vs 函数指针变量, - # 两者 alloca 类型同为 i8**,_is_func_ptr_alloca 无法区分) - ExprCallCall.register_closure_name(func_name) - - # 14. 恢复 scope names(含 nonlocal 集合指针) - trans._cur_func_name = old_func_name - trans._global_name_count = old_global_count - trans._nonlocal_name_count = old_nonlocal_count - trans._closure_env_count = old_env_count - trans._nonlocal_names = saved_nl_names - trans._nonlocal_types = saved_nl_types - - return 1 - - # ============================================================ - # _type_byte_size - 计算 LLVM 类型占用的字节大小(递归) - # - # 用于 nonlocal 共享堆存储分配:数组(如 [4 x i32]=16 字节)不能 - # 用固定 8 字节(越界写破坏 canary/邻块 → 运行时崩溃, - # ClosureTest2 Test 4 非local 数组崩溃根因)。未知类型保守返回 8。 - # ============================================================ - def _type_byte_size(self, pool: memhub.MemBuddy | t.CPtr, - ty: llvmlite.LLVMType | t.CPtr) -> t.CInt: - """计算 LLVM 类型占用的字节大小(递归),未知类型返回 8""" - if ty is None: - return 8 - match ty: - case llvmlite.LLVMType.Int(bits): - sz_i: t.CInt = (bits + 7) // 8 - if sz_i < 8: - sz_i = 8 - return sz_i - case llvmlite.LLVMType.Ptr(_pe): - return 8 - case llvmlite.LLVMType.Float(fb): - if fb == 64: - return 8 - if fb >= 128: - return 16 - return 4 - case llvmlite.LLVMType.Array(et, cnt): - esz: t.CInt = self._type_byte_size(pool, et) - return esz * cnt - case _: - return 8 - - # ============================================================ - # _nl_heap_global_name - nonlocal 堆地址全局映射变量名 - # - # 变量名: nlheap_{sha1}.{name}(全局变量,跨函数可见;SSA 编号是函数 - # 局部的,跨函数传递堆地址只能经全局变量/模块级映射)。 - # ============================================================ - def _nl_heap_global_name(self, pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - name: str) -> str: - """构造 nonlocal 堆地址全局映射变量名 nlheap_{sha1}.{name}""" - if pool is None or trans is None or name is None: - return None - mangled: str = ExprCallHandle._mangle_name(trans, name) - buf: str = pool.alloc(160) - if buf is not None: - viperlib.snprintf(buf, 160, "nlheap_%s", mangled) - return buf - - # ============================================================ - # _nl_heap_global_ref - 全局映射变量引用 Value(i8**) - # ============================================================ - def _nl_heap_global_ref(self, pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - name: str) -> llvmlite.Value | t.CPtr: - """获取 nonlocal 堆地址全局映射变量的引用(@"..." 引号包裹)""" - if pool is None or trans is None or name is None: - return None - gname: str = self._nl_heap_global_name(pool, trans, name) - if gname is None: - return None - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - ref_buf: str = pool.alloc(176) - if ref_buf is None: - return None - viperlib.snprintf(ref_buf, 176, "@\"%s\"", gname) - return llvmlite.SSAValue(pool, llvmlite.Ptr(pool, i8_ptr_ty), ref_buf) - - # ============================================================ - # _nl_heap_global_exists - 检查 nonlocal 堆地址全局映射变量是否存在 - # ============================================================ - def _nl_heap_global_exists(self, mod: llvmlite.LLVMModule | t.CPtr, - gname: str) -> int: - """检查全局映射变量 gname 是否已在模块中,1=存在""" - if mod is None or gname is None: - return 0 - gcur: llvmlite.GlobalVariable | t.CPtr = mod.GlobalHead - while gcur is not None: - if gcur.Name is not None and string.strcmp(gcur.Name, gname) == 0: - return 1 - gcur = gcur.Next - return 0 - - # ============================================================ - # _collect_chain_nonlocals - 递归收集嵌套函数链内 nonlocal 声明 - # - # 遍历 node(FunctionDef)的 children:遇嵌套 FunctionDef 递归, - # 遇 Nonlocal 语句收集变量名(去重)。返回更新后的计数。 - # ============================================================ - def _collect_chain_nonlocals(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr, - names: t.CVoid | t.CPtr, - count: int) -> int: - """递归收集 node(FunctionDef)链内所有 nonlocal 声明名(去重)""" - if node is None or names is None: - return count - fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node) - if fd is None or fd.children is None: - return count - ch: list[ast.AST | t.CPtr] | t.CPtr = fd.children - cn: t.CSizeT = len(ch) - for ci in range(cn): - st: ast.AST | t.CPtr = ch.get(ci) - if st is None: - continue - k: int = st.kind() - if k == ast.ASTKind.FunctionDef: - count = self._collect_chain_nonlocals(trans, st, names, count) - elif k == ast.ASTKind.Nonlocal: - nl_node: ast.Nonlocal | t.CPtr = (ast.Nonlocal | t.CPtr)(st) - if nl_node is not None and nl_node.names is not None: - nl_list: list[ast.AST | t.CPtr] | t.CPtr = nl_node.names - nn: t.CSizeT = len(nl_list) - for ni in range(nn): - nm_node: ast.AST | t.CPtr = nl_list.get(ni) - if nm_node is None: - continue - nm_x: ast.Name | t.CPtr = (ast.Name | t.CPtr)(nm_node) - if nm_x is None or nm_x.id is None: - continue - dup: int = 0 - for di in range(count): - if string.strcmp((str)( - t.CUInt64T(names) + di * 8), nm_x.id) == 0: - dup = 1 - break - if dup == 0 and count < 64: - nm_slot: str | t.CPtr = (t.CVoid | t.CPtr)( - t.CUInt64T(names) + count * 8) - nm_slot[0] = nm_x.id - count += 1 - return count - - # ============================================================ - # _prepare_chain_nonlocals - 预扫描嵌套函数链内 nonlocal 并建堆 - # - # 在翻译嵌套函数定义(translate_nested_function_def)之前调用。 - # 场景(ClosureTest2 Test 7):level1→a、level2→b、level3→c_val 各自 - # nonlocal 不同变量,都定义在最外层函数——level1 env 无 b 槽,level2 - # 无法经 env 链获取 b 的堆。此处在最外层函数中为链内所有 nonlocal - # 建堆 + 重定向 VarEntry + 把堆地址 store 到模块级映射 - # @nlheap.{sha1}.{name}(全局变量跨函数可见),内层闭包创建时从映射 load。 - # ============================================================ - def _prepare_chain_nonlocals(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - i8_ty: llvmlite.LLVMType | t.CPtr, - i8_ptr_ty: llvmlite.LLVMType | t.CPtr) -> int: - """预收集嵌套函数链内 nonlocal 并建堆,1 成功""" - if node is None or trans is None or builder is None or mod is None: - return 0 - # 每函数只预建一次:多个嵌套函数定义共享同一堆(防重复 malloc + - # 二次重定向 VarEntry.Alloca 导致兄弟闭包各持一堆,计数不同步) - if trans._nl_chain_done != 0: - return 1 - if trans._nl_chain_names is None: - trans._nl_chain_names = pool.alloc(8 * 64) - if trans._nl_chain_names is not None: - string.memset(trans._nl_chain_names, 0, 8 * 64) - if trans._nl_chain_names is None: - return 0 - trans._nl_chain_count = self._collect_chain_nonlocals( - trans, node, trans._nl_chain_names, 0) - trans._nl_chain_done = 1 - for ci in range(trans._nl_chain_count): - nm_slot: str | t.CPtr = (t.CVoid | t.CPtr)( - t.CUInt64T(trans._nl_chain_names) + ci * 8) - nl_name: str = nm_slot[0] - if nl_name is None: - continue - # 只在"定义它的函数"(当前顶层作用域有 alloca)中建堆 - local_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( - trans.SymTab, nl_name) - if local_alloca is None or local_alloca.Ty is None: - continue - nl_ty: llvmlite.LLVMType | t.CPtr = local_alloca.Ty.Pointee - if nl_ty is None: - continue - gname: str = self._nl_heap_global_name(pool, trans, nl_name) - if gname is None: - continue - # 建堆(按类型字节大小)并拷贝当前值——每次本函数执行都新建共享堆, - # 并 store 到模块级映射(跨函数可见)。注意:不能因映射变量已存在 - # 就跳过(前一个测试函数已把 @nlheap.* 加入模块——若跳过,本函数 - # 运行时 @nlheap.* 保持上一函数的堆地址,env 读到错堆。 - # ClosureTest2 Test 7 根因)。映射变量仅首次 add(模块去重), - # store 指令每次照发。 - st_size: t.CInt = self._type_byte_size(pool, nl_ty) - st_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, st_size) - if st_size_val is not None: - st_size_val.Next = None - var_storage: llvmlite.Value | t.CPtr = llvmlite.build_call( - builder, "malloc", st_size_val, 1, i8_ptr_ty, 0) - if var_storage is None: - continue - cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, nl_ty, local_alloca) - st_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, var_storage, llvmlite.Ptr(pool, nl_ty)) - if st_slot is not None and cur_val is not None: - llvmlite.build_store(builder, cur_val, st_slot) - # 重定向 VarEntry(父函数读写走共享堆) - ve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nl_name) - if ve is not None: - heap_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, var_storage, llvmlite.Ptr(pool, nl_ty)) - if heap_typed is not None: - ve.Alloca = heap_typed - # 创建/复用全局映射变量并 store 堆地址(跨函数可见) - gv_found: llvmlite.GlobalVariable | t.CPtr = None - gcur: llvmlite.GlobalVariable | t.CPtr = mod.GlobalHead - while gcur is not None: - if gcur.Name is not None and string.strcmp(gcur.Name, gname) == 0: - gv_found = gcur - break - gcur = gcur.Next - if gv_found is None: - gv_found = llvmlite.new_global_variable(pool, gname, i8_ptr_ty) - if gv_found is not None: - # 清除 external linkage 并给零初始化,否则打印为 external - # 声明、store 引用无定义体 → 链接 undefined reference - gv_found.Linkage = None - gv_found.Initializer = "null" - llvmlite.module_add_global(mod, gv_found) - if gv_found is not None: - gv_ref: llvmlite.Value | t.CPtr = self._nl_heap_global_ref( - pool, trans, nl_name) - if gv_ref is not None: - llvmlite.build_store(builder, var_storage, gv_ref) - return 1 - - # ============================================================ - # translate_lambda - 翻译 lambda 表达式 - # - # 与 translate_nested_function_def 同架构(TPV 闭包 {i8* fn_ptr, - # i8* env_ptr},16 字节): - # 1. 提升函数 __lambda_{id}(i8* %env, [args...]) — 恒返回 i32 - # 2. 捕获变量按值拷贝到堆存储(env[i] = 堆地址),避免闭包返回 - # 后父栈帧销毁导致悬垂 - # 3. 创建闭包 {fn_ptr, env_ptr},返回 i8* 闭包指针 - # 赋值语句据此创建 i8** alloca,调用走 translate_closure_call - # ============================================================ - def translate_lambda(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译 lambda 表达式,返回闭包指针(i8*)""" - if node is None or trans is None or builder is None: - return None - lam: ast.Lambda | t.CPtr = (ast.Lambda | t.CPtr)(node) - if lam is None: - return None - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty) - - # 1. lambda id + 提升函数名 - # 注意:计数器放 trans(_lambda_count)而非 self——Mixin 类自身无字段, - # self.新字段在 TPC 编译 Mixin 时查 class_members 失败触发未完成的 - # _PreRegisterClassMembers fallback 崩溃(FuncGen.py L437) - lambda_id: int = trans._lambda_count - trans._lambda_count += 1 - pname_buf: str = pool.alloc(64) - if pname_buf is None: - return None - viperlib.snprintf(pname_buf, 64, "__lambda_%d", lambda_id) - mangled_promoted: str = ExprCallHandle._mangle_name(trans, pname_buf) - - # 2. 解析参数(名称 + 类型,类型默认 i32,有注解则解析) - param_names: str = pool.alloc(32 * 64) # 64 参数 × 32 字节名 - if param_names is None: - return None - string.memset(param_names, 0, 32 * 64) - param_tys: t.CVoid | t.CPtr = pool.alloc(8 * 64) # LLVMType 指针槽 - if param_tys is None: - return None - string.memset(param_tys, 0, 8 * 64) - param_count: int = 0 - if lam.args is not None: - ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(lam.args) - if ags.args is not None: - alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args - pn: t.CSizeT = len(alist) - for pi in range(pn): - if param_count >= 64: - break - arg_n: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(pi)) - if arg_n is None or arg_n.arg is None: - continue - string.strncpy(param_names + param_count * 32, arg_n.arg, 31) - p_ty: llvmlite.LLVMType | t.CPtr = i32_ty - if arg_n.annotation is not None: - resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, arg_n.annotation, trans._imported_modules, trans._from_imports, trans) - if resolved is None: - # fail-fast:lambda 参数有注解但类型解析失败,不再静默保持 i32 - HandlesType.fatal_error( - arg_n, f"参数 '{arg_n.arg}' 类型解析失败: {HandlesType.annotation_to_str(arg_n.annotation)}", - "NameError") - resolved = i32_ty # 不可达(fatal_error 已退出) - if resolved is not None: - match resolved: - case llvmlite.LLVMType.Struct(_, _, _): - p_ty = llvmlite.Ptr(pool, resolved) - case llvmlite.LLVMType.Array(aelem_ty_l, _): - p_ty = llvmlite.Ptr(pool, aelem_ty_l) - case _: - p_ty = resolved - ty_slot_p: str | t.CPtr = (t.CVoid | t.CPtr)( - t.CUInt64T(param_tys) + param_count * 8) - ty_slot_p[0] = p_ty - param_count += 1 - - # 3. 收集捕获变量(body 中的外部 Name 引用) - cap_names: str = pool.alloc(64 * 64) # 64 捕获 × 64 字节名 - if cap_names is None: - return None - string.memset(cap_names, 0, 64 * 64) - cap_allocas: t.CVoid | t.CPtr = pool.alloc(8 * 64) # 父函数 alloca 指针槽 - if cap_allocas is None: - return None - string.memset(cap_allocas, 0, 8 * 64) - cap_tys: t.CVoid | t.CPtr = pool.alloc(8 * 64) # 捕获变量类型槽 - if cap_tys is None: - return None - string.memset(cap_tys, 0, 8 * 64) - cap_count: int = self._lambda_scan_body( - trans, lam.body, param_names, param_count, - cap_names, cap_allocas, cap_tys, 0) - - # 4. 创建提升函数 __lambda_{id}(i8* %env, [args...]) - func: llvmlite.Function | t.CPtr = llvmlite.create_function( - pool, mod, mangled_promoted, i32_ty) - if func is None: - return None - llvmlite.add_param(pool, func, i8_ptr_ty, "%env") - for pi2 in range(param_count): - ty_addr2: t.CUInt64T = t.CUInt64T(param_tys) + pi2 * 8 - ty_slot2: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr2) - p_ty2: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(ty_slot2[0]) - if p_ty2 is None: - p_ty2 = i32_ty - pname_l: str = pool.alloc(32) - if pname_l is not None: - viperlib.snprintf(pname_l, 32, "%%%s", param_names + pi2 * 32) - llvmlite.add_param(pool, func, p_ty2, pname_l) - - # 5. entry 块 + builder - entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") - if entry_blk is None: - return None - func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) - if func_builder is None: - return None - llvmlite.position_at_end(func_builder, entry_blk) - - # 6. 进入 lambda 作用域 - HandlesVar.enter_scope(trans.SymTab, SCOPE_FUNCTION) - - # 7. _env_ptr alloca(存储 %env 参数) - env_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, i8_ptr_ty) - if env_alloca is not None: - HandlesVar.define_var(trans.SymTab, "_env_ptr", env_alloca) - env_param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "%env") - llvmlite.build_store(func_builder, env_param_val, env_alloca) - - # 8. 保存父函数状态并切换到提升函数 - old_func: llvmlite.Function | t.CPtr = trans._cur_func - old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - old_func_name: str = trans._cur_func_name - old_global_count: int = trans._global_name_count - old_nonlocal_count: int = trans._nonlocal_name_count - old_env_count: int = trans._closure_env_count - trans._cur_func = func - trans._cur_builder = func_builder - trans._cur_func_name = mangled_promoted - HT.clear_scope_names(trans) - - # 9. 捕获变量:从 env 堆槽加载值到局部 alloca - for ci in range(cap_count): - # 直接 str 指针偏移取捕获名(与 param_names + pi*32 一致)。 - # 注意:不能用 (str)(cap_addr) 整数转换——TPV 将其编译为 itoa(整数转字符串), - # 会把 cap_slot 变成数字串,define_var 键名错乱,lambda body lookup 无法命中。 - cap_slot: str = cap_names + ci * 64 - if cap_slot[0] == '\0': - continue - ty_addr3: t.CUInt64T = t.CUInt64T(cap_tys) + ci * 8 - ty_slot3: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr3) - cap_ty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(ty_slot3[0]) - if cap_ty is None: - continue - off_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, ci * 8) - slot_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep( - func_builder, i8_ty, env_param_val, off_val) - if slot_addr is None: - continue - storage_addr: llvmlite.Value | t.CPtr = llvmlite.build_load( - func_builder, i8_ptr_ty, slot_addr) - if storage_addr is None: - continue - st_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - func_builder, storage_addr, llvmlite.Ptr(pool, cap_ty)) - if st_typed is None: - continue - cap_val: llvmlite.Value | t.CPtr = llvmlite.build_load( - func_builder, cap_ty, st_typed) - if cap_val is None: - continue - var_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, cap_ty) - if var_alloca is not None: - llvmlite.build_store(func_builder, cap_val, var_alloca) - HandlesVar.define_var(trans.SymTab, cap_slot, var_alloca) - - # 10. 参数 alloca - for pi3 in range(param_count): - ty_addr4: t.CUInt64T = t.CUInt64T(param_tys) + pi3 * 8 - ty_slot4: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr4) - p_ty3: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(ty_slot4[0]) - if p_ty3 is None: - # fail-fast:lambda 参数类型槽缺失(内部状态不一致),不再静默保持 i32 - HandlesType.fatal_error( - lam, f"lambda 参数 '{param_names + pi3 * 32}' 类型信息缺失", "InternalCompilerError") - p_ty3 = i32_ty # 不可达(fatal_error 已退出) - pname_ref: str = pool.alloc(32) - if pname_ref is not None: - viperlib.snprintf(pname_ref, 32, "%%%s", param_names + pi3 * 32) - param_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, p_ty3, pname_ref) - arg_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, p_ty3) - if arg_alloca is not None: - llvmlite.build_store(func_builder, param_ref, arg_alloca) - HandlesVar.define_var(trans.SymTab, param_names + pi3 * 32, arg_alloca) - - # 11. 翻译 body 表达式,coerce 到 i32 后 ret - body_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - func_builder, pool, mod, lam.body, None, 0, trans) - if body_val is not None and body_val.Ty is not None: - if HandlesExpr.get_llvm_type_bits(body_val.Ty) == 32 \ - and HandlesExpr.is_ptr_type(body_val.Ty) == 0: - llvmlite.build_ret(func_builder, body_val) - else: - ret_val: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( - func_builder, body_val, i32_ty, lam.body) - if ret_val is not None: - llvmlite.build_ret(func_builder, ret_val) - else: - # fail-fast:lambda 体类型转换失败,不再静默 ret 0 - HandlesType.fatal_error(lam.body, "lambda 体表达式翻译失败", "TypeError") - else: - # fail-fast:lambda 体翻译失败,不再静默 ret 0 - HandlesType.fatal_error(lam.body, "lambda 体表达式翻译失败", "TypeError") - - # 12. 退出 lambda 作用域,恢复父函数状态 - HandlesVar.exit_scope(trans.SymTab) - trans._cur_func = old_func - trans._cur_builder = old_builder - trans._cur_func_name = old_func_name - trans._global_name_count = old_global_count - trans._nonlocal_name_count = old_nonlocal_count - trans._closure_env_count = old_env_count - - # 13. 在父函数中创建 env(每个捕获变量 8 字节堆存储,env[i] = 堆地址) - env_ptr: llvmlite.Value | t.CPtr = None - if cap_count > 0: - env_size: t.CInt64T = cap_count * 8 - env_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, env_size) - if env_size_val is not None: - env_size_val.Next = None - env_ptr = llvmlite.build_call( - builder, "malloc", env_size_val, 1, i8_ptr_ty, 0) - if env_ptr is not None: - for ci3 in range(cap_count): - # 与步骤 9 一致:str 指针偏移判空,避免整数转换 itoa 语义 - cap_slot3: str = cap_names + ci3 * 64 - if cap_slot3[0] == '\0': - continue - al_addr: t.CUInt64T = t.CUInt64T(cap_allocas) + ci3 * 8 - al_slot: str | t.CPtr = (t.CVoid | t.CPtr)(al_addr) - var_alloca2: llvmlite.Value | t.CPtr = ( - llvmlite.Value | t.CPtr)(al_slot[0]) - if var_alloca2 is None: - continue - ty_addr5: t.CUInt64T = t.CUInt64T(cap_tys) + ci3 * 8 - ty_slot5: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr5) - cap_ty2: llvmlite.LLVMType | t.CPtr = ( - llvmlite.LLVMType | t.CPtr)(ty_slot5[0]) - if cap_ty2 is None: - continue - # 堆存储大小:位宽/8,至少 8 字节(容纳指针/标量) - ty_bits: int = HandlesExpr.get_llvm_type_bits(cap_ty2) - st_size: int = 8 - if ty_bits > 64: - st_size = ty_bits // 8 - st_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, st_size) - if st_size_val is not None: - st_size_val.Next = None - var_storage: llvmlite.Value | t.CPtr = llvmlite.build_call( - builder, "malloc", st_size_val, 1, i8_ptr_ty, 0) - if var_storage is not None: - cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, cap_ty2, var_alloca2) - if cur_val is not None: - st_slot5: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, var_storage, llvmlite.Ptr(pool, cap_ty2)) - if st_slot5 is not None: - llvmlite.build_store(builder, cur_val, st_slot5) - off_val2: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, ci3 * 8) - slot2: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i8_ty, env_ptr, off_val2) - if slot2 is not None: - slot_typed2: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, slot2, i8_ptr_ptr_ty) - if slot_typed2 is not None: - llvmlite.build_store(builder, var_storage, slot_typed2) - - # 14. 在父函数中创建闭包 malloc(16) - closure_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 16) - if closure_size_val is not None: - closure_size_val.Next = None - closure_ptr: llvmlite.Value | t.CPtr = llvmlite.build_call( - builder, "malloc", closure_size_val, 1, i8_ptr_ty, 0) - if closure_ptr is None: - return None - - # 15. [0] = fn_ptr(函数引用 bitcast 到 i8*) - fn_param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) - fn_func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, fn_param_node, 1) - fn_func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, fn_func_ty) - fn_ptr_name: str = pool.alloc(64) - if fn_ptr_name is not None: - if string.strchr(mangled_promoted, '.') is not None: - viperlib.snprintf(fn_ptr_name, 64, "@\"%s\"", mangled_promoted) - else: - viperlib.snprintf(fn_ptr_name, 64, "@%s", mangled_promoted) - fn_ptr_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, fn_func_ptr_ty, fn_ptr_name) - fn_as_i8ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, fn_ptr_val, i8_ptr_ty) - fn_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, closure_ptr, llvmlite.Ptr(pool, i8_ptr_ty)) - if fn_slot is not None and fn_as_i8ptr is not None: - llvmlite.build_store(builder, fn_as_i8ptr, fn_slot) - - # 16. [8] = env_ptr(无捕获存 null) - eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 8) - env_slot_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i8_ty, closure_ptr, eight_val) - if env_slot_addr is not None: - env_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, env_slot_addr, llvmlite.Ptr(pool, i8_ptr_ty)) - if env_slot is not None: - if env_ptr is not None: - llvmlite.build_store(builder, env_ptr, env_slot) - else: - null_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "null") - llvmlite.build_store(builder, null_val, env_slot) - - # 17. 返回闭包指针(i8*) - return closure_ptr - - # ============================================================ - # _lambda_scan_body - 递归扫描 lambda body 中的 Name 引用 - # - # 收集外部变量(排除 lambda 参数、模块级全局、已捕获项), - # 记录到 cap_names/cap_allocas/cap_tys 三个并行缓冲。 - # 返回更新后的捕获数量(递归调用逐层累加)。 - # ============================================================ - def _lambda_scan_body(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr, - param_names: str, - param_count: int, - cap_names: str, - cap_allocas: t.CVoid | t.CPtr, - cap_tys: t.CVoid | t.CPtr, - cap_count: int) -> int: - """递归扫描 lambda body 中的 Name 引用,收集捕获变量""" - if node is None or trans is None: - return cap_count - k: int = node.kind() - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm.id is None: - return cap_count - # 排除 lambda 参数 - for pi in range(param_count): - if string.strcmp(param_names + pi * 32, nm.id) == 0: - return cap_count - # 已捕获跳过 - for ci in range(cap_count): - if string.strcmp(cap_names + ci * 64, nm.id) == 0: - return cap_count - # 查当前作用域链 - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is None or alloca.Ty is None: - return cap_count - pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee - if pointee is None: - return cap_count - # 跳过模块级全局(body 直接解析全局,无需 env 捕获) - mod_gv: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(trans.SymTab, nm.id) - if mod_gv is not None: - if t.CUInt64T(mod_gv) == t.CUInt64T(alloca): - return cap_count - if cap_count >= 64: - return cap_count - string.strncpy(cap_names + cap_count * 64, nm.id, 63) - al_slot: str | t.CPtr = (t.CVoid | t.CPtr)( - t.CUInt64T(cap_allocas) + cap_count * 8) - al_slot[0] = alloca - ty_slot: str | t.CPtr = (t.CVoid | t.CPtr)( - t.CUInt64T(cap_tys) + cap_count * 8) - ty_slot[0] = pointee - return cap_count + 1 - # 递归遍历常见表达式子节点 - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - cc1: int = self._lambda_scan_body(trans, bop.left, param_names, param_count, - cap_names, cap_allocas, cap_tys, cap_count) - return self._lambda_scan_body(trans, bop.right, param_names, param_count, - cap_names, cap_allocas, cap_tys, cc1) - if k == ast.ASTKind.UnaryOp: - uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) - return self._lambda_scan_body(trans, uop.operand, param_names, param_count, - cap_names, cap_allocas, cap_tys, cap_count) - if k == ast.ASTKind.BoolOp: - bop2: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) - cc2: int = cap_count - if bop2.values is not None: - vs: list[ast.AST | t.CPtr] | t.CPtr = bop2.values - vn: t.CSizeT = len(vs) - for vi in range(vn): - cc2 = self._lambda_scan_body(trans, vs.get(vi), param_names, param_count, - cap_names, cap_allocas, cap_tys, cc2) - return cc2 - if k == ast.ASTKind.Compare: - cmp: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) - cc3: int = self._lambda_scan_body(trans, cmp.left, param_names, param_count, - cap_names, cap_allocas, cap_tys, cap_count) - if cmp.comparators is not None: - cl: list[ast.AST | t.CPtr] | t.CPtr = cmp.comparators - cn: t.CSizeT = len(cl) - for cvi in range(cn): - cc3 = self._lambda_scan_body(trans, cl.get(cvi), param_names, param_count, - cap_names, cap_allocas, cap_tys, cc3) - return cc3 - if k == ast.ASTKind.Call: - cal: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) - cc4: int = self._lambda_scan_body(trans, cal.func, param_names, param_count, - cap_names, cap_allocas, cap_tys, cap_count) - if cal.args is not None: - als: list[ast.AST | t.CPtr] | t.CPtr = cal.args - an: t.CSizeT = len(als) - for ai in range(an): - cc4 = self._lambda_scan_body(trans, als.get(ai), param_names, param_count, - cap_names, cap_allocas, cap_tys, cc4) - if cal.keywords is not None: - kws: list[ast.AST | t.CPtr] | t.CPtr = cal.keywords - kn: t.CSizeT = len(kws) - for ki in range(kn): - kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(kws.get(ki)) - if kw is not None and kw.value is not None: - cc4 = self._lambda_scan_body(trans, kw.value, param_names, param_count, - cap_names, cap_allocas, cap_tys, cc4) - return cc4 - if k == ast.ASTKind.Subscript: - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - cc5: int = self._lambda_scan_body(trans, sub.value, param_names, param_count, - cap_names, cap_allocas, cap_tys, cap_count) - if sub.slice is not None: - cc5 = self._lambda_scan_body(trans, sub.slice, param_names, param_count, - cap_names, cap_allocas, cap_tys, cc5) - return cc5 - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - return self._lambda_scan_body(trans, at.value, param_names, param_count, - cap_names, cap_allocas, cap_tys, cap_count) - if k == ast.ASTKind.IfExp: - ie: ast.IfExp | t.CPtr = (ast.IfExp | t.CPtr)(node) - cc6: int = self._lambda_scan_body(trans, ie.test, param_names, param_count, - cap_names, cap_allocas, cap_tys, cap_count) - cc6 = self._lambda_scan_body(trans, ie.body, param_names, param_count, - cap_names, cap_allocas, cap_tys, cc6) - return self._lambda_scan_body(trans, ie.orelse, param_names, param_count, - cap_names, cap_allocas, cap_tys, cc6) - if k == ast.ASTKind.List: - ls: ast.List | t.CPtr = (ast.List | t.CPtr)(node) - cc7: int = cap_count - if ls.elts is not None: - es: list[ast.AST | t.CPtr] | t.CPtr = ls.elts - en: t.CSizeT = len(es) - for ei in range(en): - cc7 = self._lambda_scan_body(trans, es.get(ei), param_names, param_count, - cap_names, cap_allocas, cap_tys, cc7) - return cc7 - if k == ast.ASTKind.Lambda: - lam2: ast.Lambda | t.CPtr = (ast.Lambda | t.CPtr)(node) - return self._lambda_scan_body(trans, lam2.body, param_names, param_count, - cap_names, cap_allocas, cap_tys, cap_count) - return cap_count +import lib.core.Gen.GenTypes as GenTypes +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.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Gen.CallGenBase as CallGenBase + + +# ============================================================ +# FuncGenMixin - 函数/方法声明与翻译 Mixin(对象化 P5-1,wiki/14-oo-refactor.md) +# +# 从 HandlesFunctions.vp 迁移:模块级纯函数(trans 首参,无全局状态) +# → 类方法(self 替代,trans 参数保留)。 +# +# 迁移原则(与 P2/P3/P4 一致,行为零变化): +# 1. 方法保留原函数签名(含 trans 首参),仅函数体内的 +# 本模块函数调用改为 self.xxx(...) +# 2. 外部模块调用(HandlesExprCall.xxx/HandlesType.xxx 等)保留模块前缀 +# 3. HandlesFunctions.vp 原函数保留为"委托":本地模块级单例 _g_gen +# (BuildPipeline/main 注入)cast 成 Generator 类型 +# +# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 +# ============================================================ + + +# ============================================================ +# HandlesFunctions - 函数定义处理(trans 单参模式) +# +# 参考 Python 版 TransPyC FunctionHandle +# +# 函数有自己的局部作用域,通过 HandlesVar.enter_scope/exit_scope +# 管理嵌套作用域链,翻译函数体前进入函数作用域,翻译完退出。 +# ============================================================ + + +# 作用域类型常量(本地副本,与 HandlesFunctions.vp 保持一致) +SCOPE_FUNCTION: t.CDefine = 1 + + +# ============================================================ +# FuncGenMixin - 函数属性/命名/声明/翻译 +# ============================================================ +@t.NoVTable +class FuncGenMixin(CallGenBase.CallGenBase): + """函数/方法翻译 Mixin(纯方法化迁移,无状态字段)""" + + + + + + + + + + + + + + # ============================================================ + # translate_nested_function_def - 嵌套函数提升 + 闭包创建 + # + # 将嵌套函数提升为顶层函数 @__closure_{name}(i8* %env) -> i32, + # 在父函数中创建闭包对象 {i8* fn_ptr, i8* env_ptr} 并存储到 + # 以函数名命名的局部变量中。 + # + # 闭包结构: {i8* fn_ptr, i8* env_ptr} (16 字节, malloc 分配) + # Env 结构: {i8* ptr0, i8* ptr1, ...} (每个 nonlocal 变量 8 字节,指向父函数 alloca) + # ============================================================ + def translate_nested_function_def(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译嵌套函数定义:提升为顶层函数 + 创建闭包""" + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node) + if fd is None or fd.name is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + func_name: str = fd.name + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + # 1. 构建提升后的函数名: __closure_{name}(加 SHA1 前缀避免跨模块冲突) + promoted_name: str = pool.alloc(64) + if promoted_name is not None: + viperlib.snprintf(promoted_name, 64, "__closure_%s", func_name) + mangled_promoted: str = self.Gen.FuncGenBase._mangle_name(trans, promoted_name) + + # 2. 创建提升后的函数: define i32 @__closure_{name}(i8* %env, args...) + func: llvmlite.Function | t.CPtr = llvmlite.create_function( + pool, mod, mangled_promoted, i32_ty) + if func is None: + return 0 + llvmlite.add_param(pool, func, i8_ptr_ty, "%env") + + # 2a. 嵌套函数参数:加入提升函数签名(i8* %env, 参数...), + # 类型存入 param_tys 缓冲(CVoid 跳过,与 alloca 创建索引对齐) + imported_modules: str = trans._imported_modules + from_imports: str = trans._from_imports + param_tys: t.CVoid | t.CPtr = pool.alloc(8 * 64) + if param_tys is not None: + string.memset(param_tys, 0, 8 * 64) + param_count: int = 0 + if fd.args is not None: + ags_n: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args) + if ags_n.args is not None: + alist_n: list[ast.AST | t.CPtr] | t.CPtr = ags_n.args + an_n: t.CSizeT = len(alist_n) + for ai_n in range(an_n): + arg_n: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist_n.get(ai_n)) + if arg_n is None or arg_n.arg is None: + continue + if arg_n.annotation is not None: + if self.Gen.TypeGenResolve._is_t_attr(arg_n.annotation, "CVoid", imported_modules) != 0: + continue + pty_n: llvmlite.LLVMType | t.CPtr = i32_ty + if arg_n.annotation is not None: + resolved_n: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, arg_n.annotation, imported_modules, from_imports, trans) + if resolved_n is not None: + match resolved_n: + case llvmlite.LLVMType.Struct(_, _, _): + pty_n = llvmlite.Ptr(pool, resolved_n) + case llvmlite.LLVMType.Array(aelem_ty_n, _): + pty_n = llvmlite.Ptr(pool, aelem_ty_n) + case _: + pty_n = resolved_n + if param_count < 64 and param_tys is not None: + pty_slot_n: str | t.CPtr = (t.CVoid | t.CPtr)( + t.CUInt64T(param_tys) + param_count * 8) + pty_slot_n[0] = pty_n + pname_n: str = pool.alloc(32) + if pname_n is not None: + viperlib.snprintf(pname_n, 32, "%%%s", arg_n.arg) + llvmlite.add_param(pool, func, pty_n, pname_n) + param_count += 1 + + # 3. 创建 entry 块 + builder + entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") + if entry_blk is None: + return 0 + func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) + if func_builder is None: + return 0 + llvmlite.position_at_end(func_builder, entry_blk) + + # 4. 进入嵌套函数作用域(嵌套符号表) + self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_FUNCTION) + + # 5. 创建 _env_ptr alloca 并存储 %env 参数 + env_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, i8_ptr_ty) + if env_alloca is not None: + self.Gen.VarGen.define_var(trans.SymTab, "_env_ptr", env_alloca) + env_param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "%env") + llvmlite.build_store(func_builder, env_param_val, env_alloca) + + # 5a. 创建嵌套函数参数 alloca(函数体内参数名可引用,如 + # accumulate(n) 内 for i in range(n)、set_result(val) 内 result = val) + if fd.args is not None: + ags_p: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args) + if ags_p.args is not None: + alist_p: list[ast.AST | t.CPtr] | t.CPtr = ags_p.args + idx_p: int = 0 + apn: t.CSizeT = len(alist_p) + for api in range(apn): + arg_p: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist_p.get(api)) + if arg_p is None or arg_p.arg is None: + continue + if arg_p.annotation is not None: + if self.Gen.TypeGenResolve._is_t_attr(arg_p.annotation, "CVoid", imported_modules) != 0: + continue + if idx_p >= param_count: + break + pty2_n: llvmlite.LLVMType | t.CPtr = i32_ty + if param_tys is not None: + ty_addr_n: t.CUInt64T = t.CUInt64T(param_tys) + idx_p * 8 + ty_slot_n: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr_n) + pty2_n = (llvmlite.LLVMType | t.CPtr)(ty_slot_n[0]) + if pty2_n is None: + pty2_n = i32_ty + p_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, pty2_n) + if p_alloca is not None: + self.Gen.VarGen.define_var(trans.SymTab, arg_p.arg, p_alloca) + if arg_p.annotation is not None: + cls_nm_p: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation( + arg_p.annotation, imported_modules, pool) + if cls_nm_p is not None: + self.Gen.VarGen.set_var_annot_class_name( + trans.SymTab, arg_p.arg, cls_nm_p) + pname2_n: str = pool.alloc(32) + if pname2_n is not None: + viperlib.snprintf(pname2_n, 32, "%%%s", arg_p.arg) + p_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, pty2_n, pname2_n) + llvmlite.build_store(func_builder, p_val, p_alloca) + idx_p += 1 + + # 6. 保存父函数作用域状态(仅非变量表相关) + old_func: llvmlite.Function | t.CPtr = trans._cur_func + old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + old_func_name: str = trans._cur_func_name + old_global_count: int = trans._global_name_count + old_nonlocal_count: int = trans._nonlocal_name_count + old_env_count: int = trans._closure_env_count + # nonlocal 集合独立缓冲:嵌套函数注册 nonlocal 写入共享缓冲 [0] 会 + # 覆盖父函数集合(ClosureTest2 Test 7 不同变量场景:level2 的 b 覆盖 + # level1 的 a → level1 env[0] 存错)。嵌套函数用独立缓冲,翻译完恢复。 + saved_nl_names: t.CVoid | t.CPtr = trans._nonlocal_names + saved_nl_types: t.CVoid | t.CPtr = trans._nonlocal_types + + # 7. 切换到嵌套函数作用域 + 清空 scope names + trans._cur_func = func + trans._cur_builder = func_builder + trans._cur_func_name = func_name + HT.clear_scope_names(trans) + # 嵌套函数独立 nonlocal 缓冲(避免覆盖父函数集合) + trans._nonlocal_names = stdlib.malloc(HT.MAX_GLOBAL_NAMES * 8) + trans._nonlocal_types = stdlib.malloc(HT.MAX_GLOBAL_NAMES * 8) + if trans._nonlocal_names is not None: + string.memset(trans._nonlocal_names, 0, HT.MAX_GLOBAL_NAMES * 8) + if trans._nonlocal_types is not None: + string.memset(trans._nonlocal_types, 0, HT.MAX_GLOBAL_NAMES * 8) + + # 8. 预扫描函数体: + # a. 先预扫描 Global/Nonlocal 声明(Python 语义:对整个函数作用域生效) + # b. 再预扫描 AnnAssign 为局部变量提前创建 alloca + body: list[ast.AST | t.CPtr] | t.CPtr = fd.children + if body is not None: + bn: t.CSizeT = len(body) + for bi in range(bn): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + self.Gen.StmtGenDecl.pre_scan_scope_decls(trans, stmt) + for bi in range(bn): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + self.Gen.StmtGenDecl.pre_scan_allocas(trans, stmt) + + # 9. 翻译函数体(Nonlocal 语句会填充 _nonlocal_names) + if body is not None: + bn2: t.CSizeT = len(body) + for bi2 in range(bn2): + stmt2: ast.AST | t.CPtr = body.get(bi2) + if stmt2 is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt2) + + # 10. 隐式 ret + last_is_return: int = 0 + if body is not None: + bn3: t.CSizeT = len(body) + if bn3 > 0: + last_stmt: ast.AST | t.CPtr = body.get(bn3 - 1) + if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return: + last_is_return = 1 + if last_is_return == 0: + zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + llvmlite.build_ret(func_builder, zero_val) + + # 11. 保存嵌套函数的 nonlocal 信息 + nested_nonlocal_count: int = trans._nonlocal_name_count + + # 12. 退出嵌套函数作用域,回到父函数作用域(保留 _nonlocal_names 用于 env 创建) + self.Gen.VarGen.exit_scope(trans.SymTab) + trans._cur_func = old_func + trans._cur_builder = old_builder + # NOTE: _nonlocal_names 和 _nonlocal_name_count 仍为嵌套函数的值 + + # 13. 在父函数中创建闭包对象 + parent_builder: llvmlite.IRBuilder | t.CPtr = old_builder + if parent_builder is None: + # 无 builder(模块级嵌套函数?)→ 无法创建闭包,仅恢复状态 + trans._cur_func_name = old_func_name + trans._global_name_count = old_global_count + trans._nonlocal_name_count = old_nonlocal_count + trans._closure_env_count = old_env_count + trans._nonlocal_names = saved_nl_names + trans._nonlocal_types = saved_nl_types + return 0 + + # 13a. 创建 env: malloc(8 * nested_nonlocal_count) — env 存储指针数组 + # 每个 nonlocal 变量占 8 字节(i8*),指向父函数的 alloca(共享存储) + env_ptr: llvmlite.Value | t.CPtr = None + if nested_nonlocal_count > 0: + env_size: t.CInt64T = nested_nonlocal_count * 8 + env_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, env_size) + if env_size_val is not None: + env_size_val.Next = None + env_ptr = llvmlite.build_call( + parent_builder, "malloc", env_size_val, 1, i8_ptr_ty, 0) + + # 为每个 nonlocal 变量建立堆存储并注册到 env: + # 运行时 env 链式共享(无需编译期映射——映射存编译期 Value 对象 + # 地址会被 inttoptr 当运行时堆地址解引用崩溃;存整型也拿不到 + # 运行时 malloc 结果): + # - 变量是父函数局部(lookup_current 在当前作用域找到 alloca) + # → 新建堆(malloc + 拷贝当前值),并把父函数 VarEntry.Alloca + # 重定向到堆——父函数后续读写走共享堆 + # - 变量是父函数的 nonlocal(多层嵌套,当前作用域无 alloca) + # → 从父函数 env 读该变量的堆地址(_load_raw_var_ptr), + # env[ni] = 同一堆地址(运行时链式共享,各层写同一堆) + if env_ptr is not None: + i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty) + for ni in range(nested_nonlocal_count): + # 从 _nonlocal_names 缓冲区读取名称 + name_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + ni * 8 + nl_slot: str | t.CPtr = (t.CVoid | t.CPtr)(name_addr) + nl_name: str = nl_slot[0] + if nl_name is None: + continue + heap_store: llvmlite.Value | t.CPtr = None + # 1. 优先查全局堆地址映射(_prepare_chain_nonlocals 已为 + # 链内 nonlocal 建堆并 store 到 @nlheap.*;不同层捕获 + # 不同变量时(ClosureTest2 Test 7)level2 的 b 经此共享) + gname_ck: str = self._nl_heap_global_name( + pool, trans, nl_name) + if gname_ck is not None \ + and self._nl_heap_global_exists(mod, gname_ck) != 0: + gv_ref0: llvmlite.Value | t.CPtr = self._nl_heap_global_ref( + pool, trans, nl_name) + if gv_ref0 is not None: + heap_store = llvmlite.build_load( + parent_builder, i8_ptr_ty, gv_ref0) + if heap_store is None: + local_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_current( + trans.SymTab, nl_name) + if local_alloca is not None and local_alloca.Ty is not None: + # 父函数局部变量:新建堆存储 + 拷贝当前值 + 重定向 + nl_load_ty: llvmlite.LLVMType | t.CPtr = local_alloca.Ty.Pointee + if nl_load_ty is not None: + cur_val_nl: llvmlite.Value | t.CPtr = llvmlite.build_load( + parent_builder, nl_load_ty, local_alloca) + # 堆存储大小按类型字节数:数组(如 [4 x i32]=16 字节) + # 不能固定 8 字节(越界写崩溃);指针/标量 ≥ 8 字节 + st_size: t.CInt = self._type_byte_size(pool, nl_load_ty) + st_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64( + pool, st_size) + if st_size_val is not None: + st_size_val.Next = None + var_storage: llvmlite.Value | t.CPtr = llvmlite.build_call( + parent_builder, "malloc", st_size_val, 1, i8_ptr_ty, 0) + if var_storage is not None: + # 拷贝当前值到堆存储 + st_slot_nl: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + parent_builder, var_storage, llvmlite.Ptr(pool, nl_load_ty)) + if st_slot_nl is not None and cur_val_nl is not None: + llvmlite.build_store(parent_builder, cur_val_nl, st_slot_nl) + # 父函数 VarEntry.Alloca 重定向到堆(父函数读写走共享堆) + ve_nl: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, nl_name) + heap_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + parent_builder, var_storage, llvmlite.Ptr(pool, nl_load_ty)) + if ve_nl is not None and heap_typed is not None: + ve_nl.Alloca = heap_typed + # 记录到全局映射(后续层/父函数可见) + gv_ref_new: llvmlite.Value | t.CPtr = None + if gname_ck is not None \ + and self._nl_heap_global_exists(mod, gname_ck) == 0: + gv_new: llvmlite.GlobalVariable | t.CPtr = \ + llvmlite.new_global_variable(pool, gname_ck, i8_ptr_ty) + if gv_new is not None: + # 清除 external linkage + 零初始化(防 undefined reference) + gv_new.Linkage = None + gv_new.Initializer = "null" + llvmlite.module_add_global(mod, gv_new) + gv_ref_new = self._nl_heap_global_ref(pool, trans, nl_name) + if gv_ref_new is not None: + llvmlite.build_store( + parent_builder, var_storage, gv_ref_new) + heap_store = var_storage + else: + # 父函数中该变量是 nonlocal(多层嵌套):从父函数 env + # 读堆地址(运行时链式共享同一堆),不新建 + heap_store = self.Gen.StmtGenDecl._load_raw_var_ptr(trans, nl_name) + if heap_store is None: + continue + # env[ni] = 堆存储地址(共享) + offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, ni * 8) + slot: llvmlite.Value | t.CPtr = llvmlite.build_gep( + parent_builder, i8_ty, env_ptr, offset_val) + if slot is not None: + slot_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + parent_builder, slot, i8_ptr_ptr_ty) + if slot_typed is not None: + llvmlite.build_store(parent_builder, heap_store, slot_typed) + + # 13b. 创建闭包结构: malloc(16) + closure_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 16) + if closure_size_val is not None: + closure_size_val.Next = None + closure_ptr: llvmlite.Value | t.CPtr = llvmlite.build_call( + parent_builder, "malloc", closure_size_val, 1, i8_ptr_ty, 0) + if closure_ptr is None: + # malloc 失败,恢复状态 + trans._cur_func_name = old_func_name + trans._global_name_count = old_global_count + trans._nonlocal_name_count = old_nonlocal_count + trans._closure_env_count = old_env_count + trans._nonlocal_names = saved_nl_names + trans._nonlocal_types = saved_nl_types + return 0 + + # 13c. 存储 fn_ptr 到 offset 0 + # 创建函数指针类型 i32(i8*)* + fn_param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) + fn_func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, fn_param_node, 1) + fn_func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, fn_func_ty) + + # 创建函数引用 Value(类型为 i32(i8*)*,使用 SHA1 混淆名) + fn_ptr_name: str = pool.alloc(64) + if fn_ptr_name is not None: + # SHA1 前缀名含 '.' 需要加引号(如 @"sha1.__closure_func") + if string.strchr(mangled_promoted, '.') is not None: + viperlib.snprintf(fn_ptr_name, 64, "@\"%s\"", mangled_promoted) + else: + viperlib.snprintf(fn_ptr_name, 64, "@%s", mangled_promoted) + fn_ptr_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, fn_func_ptr_ty, fn_ptr_name) + + # bitcast 函数指针到 i8*(闭包存储 i8* 类型) + fn_as_i8ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + parent_builder, fn_ptr_val, i8_ptr_ty) + fn_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + parent_builder, closure_ptr, llvmlite.Ptr(pool, i8_ptr_ty)) + if fn_slot is not None and fn_as_i8ptr is not None: + llvmlite.build_store(parent_builder, fn_as_i8ptr, fn_slot) + + # 13d. 存储 env_ptr 到 offset 8 + eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 8) + env_slot_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + parent_builder, i8_ty, closure_ptr, eight_val) + if env_slot_addr is not None: + env_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + parent_builder, env_slot_addr, llvmlite.Ptr(pool, i8_ptr_ty)) + if env_slot is not None: + if env_ptr is not None: + llvmlite.build_store(parent_builder, env_ptr, env_slot) + else: + # 无 nonlocal 变量,存储 null + null_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "null") + llvmlite.build_store(parent_builder, null_val, env_slot) + + # 13e. 将闭包指针存储到父函数的局部变量 {func_name} + closure_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(parent_builder, i8_ptr_ty) + if closure_alloca is not None: + llvmlite.build_store(parent_builder, closure_ptr, closure_alloca) + self.Gen.VarGen.define_var(trans.SymTab, func_name, closure_alloca) + # 注册闭包变量名(供调用时区分闭包 vs 函数指针变量, + # 两者 alloca 类型同为 i8**,_is_func_ptr_alloca 无法区分) + self.Gen.CallGenLeafKit.register_closure_name(func_name) + + # 14. 恢复 scope names(含 nonlocal 集合指针) + trans._cur_func_name = old_func_name + trans._global_name_count = old_global_count + trans._nonlocal_name_count = old_nonlocal_count + trans._closure_env_count = old_env_count + trans._nonlocal_names = saved_nl_names + trans._nonlocal_types = saved_nl_types + + return 1 + + # ============================================================ + # _type_byte_size - 计算 LLVM 类型占用的字节大小(递归) + # + # 用于 nonlocal 共享堆存储分配:数组(如 [4 x i32]=16 字节)不能 + # 用固定 8 字节(越界写破坏 canary/邻块 → 运行时崩溃, + # ClosureTest2 Test 4 非local 数组崩溃根因)。未知类型保守返回 8。 + # ============================================================ + def _type_byte_size(self, pool: memhub.MemBuddy | t.CPtr, + ty: llvmlite.LLVMType | t.CPtr) -> t.CInt: + """计算 LLVM 类型占用的字节大小(递归),未知类型返回 8""" + if ty is None: + return 8 + match ty: + case llvmlite.LLVMType.Int(bits): + sz_i: t.CInt = (bits + 7) // 8 + if sz_i < 8: + sz_i = 8 + return sz_i + case llvmlite.LLVMType.Ptr(_pe): + return 8 + case llvmlite.LLVMType.Float(fb): + if fb == 64: + return 8 + if fb >= 128: + return 16 + return 4 + case llvmlite.LLVMType.Array(et, cnt): + esz: t.CInt = self._type_byte_size(pool, et) + return esz * cnt + case _: + return 8 + + # ============================================================ + # _nl_heap_global_name - nonlocal 堆地址全局映射变量名 + # + # 变量名: nlheap_{sha1}.{name}(全局变量,跨函数可见;SSA 编号是函数 + # 局部的,跨函数传递堆地址只能经全局变量/模块级映射)。 + # ============================================================ + def _nl_heap_global_name(self, pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr, + name: str) -> str: + """构造 nonlocal 堆地址全局映射变量名 nlheap_{sha1}.{name}""" + if pool is None or trans is None or name is None: + return None + mangled: str = self.Gen.FuncGenBase._mangle_name(trans, name) + buf: str = pool.alloc(160) + if buf is not None: + viperlib.snprintf(buf, 160, "nlheap_%s", mangled) + return buf + + # ============================================================ + # _nl_heap_global_ref - 全局映射变量引用 Value(i8**) + # ============================================================ + def _nl_heap_global_ref(self, pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr, + name: str) -> llvmlite.Value | t.CPtr: + """获取 nonlocal 堆地址全局映射变量的引用(@"..." 引号包裹)""" + if pool is None or trans is None or name is None: + return None + gname: str = self._nl_heap_global_name(pool, trans, name) + if gname is None: + return None + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + ref_buf: str = pool.alloc(176) + if ref_buf is None: + return None + viperlib.snprintf(ref_buf, 176, "@\"%s\"", gname) + return llvmlite.SSAValue(pool, llvmlite.Ptr(pool, i8_ptr_ty), ref_buf) + + # ============================================================ + # _nl_heap_global_exists - 检查 nonlocal 堆地址全局映射变量是否存在 + # ============================================================ + def _nl_heap_global_exists(self, mod: llvmlite.LLVMModule | t.CPtr, + gname: str) -> int: + """检查全局映射变量 gname 是否已在模块中,1=存在""" + if mod is None or gname is None: + return 0 + gcur: llvmlite.GlobalVariable | t.CPtr = mod.GlobalHead + while gcur is not None: + if gcur.Name is not None and string.strcmp(gcur.Name, gname) == 0: + return 1 + gcur = gcur.Next + return 0 + + # ============================================================ + # _collect_chain_nonlocals - 递归收集嵌套函数链内 nonlocal 声明 + # + # 遍历 node(FunctionDef)的 children:遇嵌套 FunctionDef 递归, + # 遇 Nonlocal 语句收集变量名(去重)。返回更新后的计数。 + # ============================================================ + def _collect_chain_nonlocals(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr, + names: t.CVoid | t.CPtr, + count: int) -> int: + """递归收集 node(FunctionDef)链内所有 nonlocal 声明名(去重)""" + if node is None or names is None: + return count + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node) + if fd is None or fd.children is None: + return count + ch: list[ast.AST | t.CPtr] | t.CPtr = fd.children + cn: t.CSizeT = len(ch) + for ci in range(cn): + st: ast.AST | t.CPtr = ch.get(ci) + if st is None: + continue + k: int = st.kind() + if k == ast.ASTKind.FunctionDef: + count = self._collect_chain_nonlocals(trans, st, names, count) + elif k == ast.ASTKind.Nonlocal: + nl_node: ast.Nonlocal | t.CPtr = (ast.Nonlocal | t.CPtr)(st) + if nl_node is not None and nl_node.names is not None: + nl_list: list[ast.AST | t.CPtr] | t.CPtr = nl_node.names + nn: t.CSizeT = len(nl_list) + for ni in range(nn): + nm_node: ast.AST | t.CPtr = nl_list.get(ni) + if nm_node is None: + continue + nm_x: ast.Name | t.CPtr = (ast.Name | t.CPtr)(nm_node) + if nm_x is None or nm_x.id is None: + continue + dup: int = 0 + for di in range(count): + if string.strcmp((str)( + t.CUInt64T(names) + di * 8), nm_x.id) == 0: + dup = 1 + break + if dup == 0 and count < 64: + nm_slot: str | t.CPtr = (t.CVoid | t.CPtr)( + t.CUInt64T(names) + count * 8) + nm_slot[0] = nm_x.id + count += 1 + return count + + # ============================================================ + # _prepare_chain_nonlocals - 预扫描嵌套函数链内 nonlocal 并建堆 + # + # 在翻译嵌套函数定义(translate_nested_function_def)之前调用。 + # 场景(ClosureTest2 Test 7):level1→a、level2→b、level3→c_val 各自 + # nonlocal 不同变量,都定义在最外层函数——level1 env 无 b 槽,level2 + # 无法经 env 链获取 b 的堆。此处在最外层函数中为链内所有 nonlocal + # 建堆 + 重定向 VarEntry + 把堆地址 store 到模块级映射 + # @nlheap.{sha1}.{name}(全局变量跨函数可见),内层闭包创建时从映射 load。 + # ============================================================ + def _prepare_chain_nonlocals(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + i8_ty: llvmlite.LLVMType | t.CPtr, + i8_ptr_ty: llvmlite.LLVMType | t.CPtr) -> int: + """预收集嵌套函数链内 nonlocal 并建堆,1 成功""" + if node is None or trans is None or builder is None or mod is None: + return 0 + # 每函数只预建一次:多个嵌套函数定义共享同一堆(防重复 malloc + + # 二次重定向 VarEntry.Alloca 导致兄弟闭包各持一堆,计数不同步) + if trans._nl_chain_done != 0: + return 1 + if trans._nl_chain_names is None: + trans._nl_chain_names = pool.alloc(8 * 64) + if trans._nl_chain_names is not None: + string.memset(trans._nl_chain_names, 0, 8 * 64) + if trans._nl_chain_names is None: + return 0 + trans._nl_chain_count = self._collect_chain_nonlocals( + trans, node, trans._nl_chain_names, 0) + trans._nl_chain_done = 1 + for ci in range(trans._nl_chain_count): + nm_slot: str | t.CPtr = (t.CVoid | t.CPtr)( + t.CUInt64T(trans._nl_chain_names) + ci * 8) + nl_name: str = nm_slot[0] + if nl_name is None: + continue + # 只在"定义它的函数"(当前顶层作用域有 alloca)中建堆 + local_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_current( + trans.SymTab, nl_name) + if local_alloca is None or local_alloca.Ty is None: + continue + nl_ty: llvmlite.LLVMType | t.CPtr = local_alloca.Ty.Pointee + if nl_ty is None: + continue + gname: str = self._nl_heap_global_name(pool, trans, nl_name) + if gname is None: + continue + # 建堆(按类型字节大小)并拷贝当前值——每次本函数执行都新建共享堆, + # 并 store 到模块级映射(跨函数可见)。注意:不能因映射变量已存在 + # 就跳过(前一个测试函数已把 @nlheap.* 加入模块——若跳过,本函数 + # 运行时 @nlheap.* 保持上一函数的堆地址,env 读到错堆。 + # ClosureTest2 Test 7 根因)。映射变量仅首次 add(模块去重), + # store 指令每次照发。 + st_size: t.CInt = self._type_byte_size(pool, nl_ty) + st_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, st_size) + if st_size_val is not None: + st_size_val.Next = None + var_storage: llvmlite.Value | t.CPtr = llvmlite.build_call( + builder, "malloc", st_size_val, 1, i8_ptr_ty, 0) + if var_storage is None: + continue + cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, nl_ty, local_alloca) + st_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, var_storage, llvmlite.Ptr(pool, nl_ty)) + if st_slot is not None and cur_val is not None: + llvmlite.build_store(builder, cur_val, st_slot) + # 重定向 VarEntry(父函数读写走共享堆) + ve: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, nl_name) + if ve is not None: + heap_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, var_storage, llvmlite.Ptr(pool, nl_ty)) + if heap_typed is not None: + ve.Alloca = heap_typed + # 创建/复用全局映射变量并 store 堆地址(跨函数可见) + gv_found: llvmlite.GlobalVariable | t.CPtr = None + gcur: llvmlite.GlobalVariable | t.CPtr = mod.GlobalHead + while gcur is not None: + if gcur.Name is not None and string.strcmp(gcur.Name, gname) == 0: + gv_found = gcur + break + gcur = gcur.Next + if gv_found is None: + gv_found = llvmlite.new_global_variable(pool, gname, i8_ptr_ty) + if gv_found is not None: + # 清除 external linkage 并给零初始化,否则打印为 external + # 声明、store 引用无定义体 → 链接 undefined reference + gv_found.Linkage = None + gv_found.Initializer = "null" + llvmlite.module_add_global(mod, gv_found) + if gv_found is not None: + gv_ref: llvmlite.Value | t.CPtr = self._nl_heap_global_ref( + pool, trans, nl_name) + if gv_ref is not None: + llvmlite.build_store(builder, var_storage, gv_ref) + return 1 + + # ============================================================ + # translate_lambda - 翻译 lambda 表达式 + # + # 与 translate_nested_function_def 同架构(TPV 闭包 {i8* fn_ptr, + # i8* env_ptr},16 字节): + # 1. 提升函数 __lambda_{id}(i8* %env, [args...]) — 恒返回 i32 + # 2. 捕获变量按值拷贝到堆存储(env[i] = 堆地址),避免闭包返回 + # 后父栈帧销毁导致悬垂 + # 3. 创建闭包 {fn_ptr, env_ptr},返回 i8* 闭包指针 + # 赋值语句据此创建 i8** alloca,调用走 translate_closure_call + # ============================================================ + def translate_lambda(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译 lambda 表达式,返回闭包指针(i8*)""" + if node is None or trans is None or builder is None: + return None + lam: ast.Lambda | t.CPtr = (ast.Lambda | t.CPtr)(node) + if lam is None: + return None + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty) + + # 1. lambda id + 提升函数名 + # 注意:计数器放 trans(_lambda_count)而非 self——Mixin 类自身无字段, + # self.新字段在 TPC 编译 Mixin 时查 class_members 失败触发未完成的 + # _PreRegisterClassMembers fallback 崩溃(FuncGen.py L437) + lambda_id: int = trans._lambda_count + trans._lambda_count += 1 + pname_buf: str = pool.alloc(64) + if pname_buf is None: + return None + viperlib.snprintf(pname_buf, 64, "__lambda_%d", lambda_id) + mangled_promoted: str = self.Gen.FuncGenBase._mangle_name(trans, pname_buf) + + # 2. 解析参数(名称 + 类型,类型默认 i32,有注解则解析) + param_names: str = pool.alloc(32 * 64) # 64 参数 × 32 字节名 + if param_names is None: + return None + string.memset(param_names, 0, 32 * 64) + param_tys: t.CVoid | t.CPtr = pool.alloc(8 * 64) # LLVMType 指针槽 + if param_tys is None: + return None + string.memset(param_tys, 0, 8 * 64) + param_count: int = 0 + if lam.args is not None: + ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(lam.args) + if ags.args is not None: + alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args + pn: t.CSizeT = len(alist) + for pi in range(pn): + if param_count >= 64: + break + arg_n: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(pi)) + if arg_n is None or arg_n.arg is None: + continue + string.strncpy(param_names + param_count * 32, arg_n.arg, 31) + p_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if arg_n.annotation is not None: + resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, arg_n.annotation, trans._imported_modules, trans._from_imports, trans) + if resolved is None: + # fail-fast:lambda 参数有注解但类型解析失败,不再静默保持 i32 + self.Gen.TypeGenErr.fatal_error( + arg_n, f"参数 '{arg_n.arg}' 类型解析失败: {self.Gen.TypeGenResolve.annotation_to_str(arg_n.annotation)}", + "NameError") + resolved = i32_ty # 不可达(fatal_error 已退出) + if resolved is not None: + match resolved: + case llvmlite.LLVMType.Struct(_, _, _): + p_ty = llvmlite.Ptr(pool, resolved) + case llvmlite.LLVMType.Array(aelem_ty_l, _): + p_ty = llvmlite.Ptr(pool, aelem_ty_l) + case _: + p_ty = resolved + ty_slot_p: str | t.CPtr = (t.CVoid | t.CPtr)( + t.CUInt64T(param_tys) + param_count * 8) + ty_slot_p[0] = p_ty + param_count += 1 + + # 3. 收集捕获变量(body 中的外部 Name 引用) + cap_names: str = pool.alloc(64 * 64) # 64 捕获 × 64 字节名 + if cap_names is None: + return None + string.memset(cap_names, 0, 64 * 64) + cap_allocas: t.CVoid | t.CPtr = pool.alloc(8 * 64) # 父函数 alloca 指针槽 + if cap_allocas is None: + return None + string.memset(cap_allocas, 0, 8 * 64) + cap_tys: t.CVoid | t.CPtr = pool.alloc(8 * 64) # 捕获变量类型槽 + if cap_tys is None: + return None + string.memset(cap_tys, 0, 8 * 64) + cap_count: int = self._lambda_scan_body( + trans, lam.body, param_names, param_count, + cap_names, cap_allocas, cap_tys, 0) + + # 4. 创建提升函数 __lambda_{id}(i8* %env, [args...]) + func: llvmlite.Function | t.CPtr = llvmlite.create_function( + pool, mod, mangled_promoted, i32_ty) + if func is None: + return None + llvmlite.add_param(pool, func, i8_ptr_ty, "%env") + for pi2 in range(param_count): + ty_addr2: t.CUInt64T = t.CUInt64T(param_tys) + pi2 * 8 + ty_slot2: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr2) + p_ty2: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(ty_slot2[0]) + if p_ty2 is None: + p_ty2 = i32_ty + pname_l: str = pool.alloc(32) + if pname_l is not None: + viperlib.snprintf(pname_l, 32, "%%%s", param_names + pi2 * 32) + llvmlite.add_param(pool, func, p_ty2, pname_l) + + # 5. entry 块 + builder + entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") + if entry_blk is None: + return None + func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) + if func_builder is None: + return None + llvmlite.position_at_end(func_builder, entry_blk) + + # 6. 进入 lambda 作用域 + self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_FUNCTION) + + # 7. _env_ptr alloca(存储 %env 参数) + env_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, i8_ptr_ty) + if env_alloca is not None: + self.Gen.VarGen.define_var(trans.SymTab, "_env_ptr", env_alloca) + env_param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "%env") + llvmlite.build_store(func_builder, env_param_val, env_alloca) + + # 8. 保存父函数状态并切换到提升函数 + old_func: llvmlite.Function | t.CPtr = trans._cur_func + old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + old_func_name: str = trans._cur_func_name + old_global_count: int = trans._global_name_count + old_nonlocal_count: int = trans._nonlocal_name_count + old_env_count: int = trans._closure_env_count + trans._cur_func = func + trans._cur_builder = func_builder + trans._cur_func_name = mangled_promoted + HT.clear_scope_names(trans) + + # 9. 捕获变量:从 env 堆槽加载值到局部 alloca + for ci in range(cap_count): + # 直接 str 指针偏移取捕获名(与 param_names + pi*32 一致)。 + # 注意:不能用 (str)(cap_addr) 整数转换——TPV 将其编译为 itoa(整数转字符串), + # 会把 cap_slot 变成数字串,define_var 键名错乱,lambda body lookup 无法命中。 + cap_slot: str = cap_names + ci * 64 + if cap_slot[0] == '\0': + continue + ty_addr3: t.CUInt64T = t.CUInt64T(cap_tys) + ci * 8 + ty_slot3: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr3) + cap_ty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(ty_slot3[0]) + if cap_ty is None: + continue + off_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, ci * 8) + slot_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + func_builder, i8_ty, env_param_val, off_val) + if slot_addr is None: + continue + storage_addr: llvmlite.Value | t.CPtr = llvmlite.build_load( + func_builder, i8_ptr_ty, slot_addr) + if storage_addr is None: + continue + st_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + func_builder, storage_addr, llvmlite.Ptr(pool, cap_ty)) + if st_typed is None: + continue + cap_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + func_builder, cap_ty, st_typed) + if cap_val is None: + continue + var_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, cap_ty) + if var_alloca is not None: + llvmlite.build_store(func_builder, cap_val, var_alloca) + self.Gen.VarGen.define_var(trans.SymTab, cap_slot, var_alloca) + + # 10. 参数 alloca + for pi3 in range(param_count): + ty_addr4: t.CUInt64T = t.CUInt64T(param_tys) + pi3 * 8 + ty_slot4: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr4) + p_ty3: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(ty_slot4[0]) + if p_ty3 is None: + # fail-fast:lambda 参数类型槽缺失(内部状态不一致),不再静默保持 i32 + self.Gen.TypeGenErr.fatal_error( + lam, f"lambda 参数 '{param_names + pi3 * 32}' 类型信息缺失", "InternalCompilerError") + p_ty3 = i32_ty # 不可达(fatal_error 已退出) + pname_ref: str = pool.alloc(32) + if pname_ref is not None: + viperlib.snprintf(pname_ref, 32, "%%%s", param_names + pi3 * 32) + param_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, p_ty3, pname_ref) + arg_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, p_ty3) + if arg_alloca is not None: + llvmlite.build_store(func_builder, param_ref, arg_alloca) + self.Gen.VarGen.define_var(trans.SymTab, param_names + pi3 * 32, arg_alloca) + + # 11. 翻译 body 表达式,coerce 到 i32 后 ret + body_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + func_builder, pool, mod, lam.body, None, 0, trans) + if body_val is not None and body_val.Ty is not None: + if self.Gen.ExprGenBase.get_llvm_type_bits(body_val.Ty) == 32 \ + and self.Gen.ExprGenBase.is_ptr_type(body_val.Ty) == 0: + llvmlite.build_ret(func_builder, body_val) + else: + ret_val: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type( + func_builder, body_val, i32_ty, lam.body) + if ret_val is not None: + llvmlite.build_ret(func_builder, ret_val) + else: + # fail-fast:lambda 体类型转换失败,不再静默 ret 0 + self.Gen.TypeGenErr.fatal_error(lam.body, "lambda 体表达式翻译失败", "TypeError") + else: + # fail-fast:lambda 体翻译失败,不再静默 ret 0 + self.Gen.TypeGenErr.fatal_error(lam.body, "lambda 体表达式翻译失败", "TypeError") + + # 12. 退出 lambda 作用域,恢复父函数状态 + self.Gen.VarGen.exit_scope(trans.SymTab) + trans._cur_func = old_func + trans._cur_builder = old_builder + trans._cur_func_name = old_func_name + trans._global_name_count = old_global_count + trans._nonlocal_name_count = old_nonlocal_count + trans._closure_env_count = old_env_count + + # 13. 在父函数中创建 env(每个捕获变量 8 字节堆存储,env[i] = 堆地址) + env_ptr: llvmlite.Value | t.CPtr = None + if cap_count > 0: + env_size: t.CInt64T = cap_count * 8 + env_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, env_size) + if env_size_val is not None: + env_size_val.Next = None + env_ptr = llvmlite.build_call( + builder, "malloc", env_size_val, 1, i8_ptr_ty, 0) + if env_ptr is not None: + for ci3 in range(cap_count): + # 与步骤 9 一致:str 指针偏移判空,避免整数转换 itoa 语义 + cap_slot3: str = cap_names + ci3 * 64 + if cap_slot3[0] == '\0': + continue + al_addr: t.CUInt64T = t.CUInt64T(cap_allocas) + ci3 * 8 + al_slot: str | t.CPtr = (t.CVoid | t.CPtr)(al_addr) + var_alloca2: llvmlite.Value | t.CPtr = ( + llvmlite.Value | t.CPtr)(al_slot[0]) + if var_alloca2 is None: + continue + ty_addr5: t.CUInt64T = t.CUInt64T(cap_tys) + ci3 * 8 + ty_slot5: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr5) + cap_ty2: llvmlite.LLVMType | t.CPtr = ( + llvmlite.LLVMType | t.CPtr)(ty_slot5[0]) + if cap_ty2 is None: + continue + # 堆存储大小:位宽/8,至少 8 字节(容纳指针/标量) + ty_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(cap_ty2) + st_size: int = 8 + if ty_bits > 64: + st_size = ty_bits // 8 + st_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, st_size) + if st_size_val is not None: + st_size_val.Next = None + var_storage: llvmlite.Value | t.CPtr = llvmlite.build_call( + builder, "malloc", st_size_val, 1, i8_ptr_ty, 0) + if var_storage is not None: + cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, cap_ty2, var_alloca2) + if cur_val is not None: + st_slot5: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, var_storage, llvmlite.Ptr(pool, cap_ty2)) + if st_slot5 is not None: + llvmlite.build_store(builder, cur_val, st_slot5) + off_val2: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, ci3 * 8) + slot2: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i8_ty, env_ptr, off_val2) + if slot2 is not None: + slot_typed2: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, slot2, i8_ptr_ptr_ty) + if slot_typed2 is not None: + llvmlite.build_store(builder, var_storage, slot_typed2) + + # 14. 在父函数中创建闭包 malloc(16) + closure_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 16) + if closure_size_val is not None: + closure_size_val.Next = None + closure_ptr: llvmlite.Value | t.CPtr = llvmlite.build_call( + builder, "malloc", closure_size_val, 1, i8_ptr_ty, 0) + if closure_ptr is None: + return None + + # 15. [0] = fn_ptr(函数引用 bitcast 到 i8*) + fn_param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) + fn_func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, fn_param_node, 1) + fn_func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, fn_func_ty) + fn_ptr_name: str = pool.alloc(64) + if fn_ptr_name is not None: + if string.strchr(mangled_promoted, '.') is not None: + viperlib.snprintf(fn_ptr_name, 64, "@\"%s\"", mangled_promoted) + else: + viperlib.snprintf(fn_ptr_name, 64, "@%s", mangled_promoted) + fn_ptr_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, fn_func_ptr_ty, fn_ptr_name) + fn_as_i8ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, fn_ptr_val, i8_ptr_ty) + fn_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, closure_ptr, llvmlite.Ptr(pool, i8_ptr_ty)) + if fn_slot is not None and fn_as_i8ptr is not None: + llvmlite.build_store(builder, fn_as_i8ptr, fn_slot) + + # 16. [8] = env_ptr(无捕获存 null) + eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 8) + env_slot_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i8_ty, closure_ptr, eight_val) + if env_slot_addr is not None: + env_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, env_slot_addr, llvmlite.Ptr(pool, i8_ptr_ty)) + if env_slot is not None: + if env_ptr is not None: + llvmlite.build_store(builder, env_ptr, env_slot) + else: + null_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "null") + llvmlite.build_store(builder, null_val, env_slot) + + # 17. 返回闭包指针(i8*) + return closure_ptr + + # ============================================================ + # _lambda_scan_body - 递归扫描 lambda body 中的 Name 引用 + # + # 收集外部变量(排除 lambda 参数、模块级全局、已捕获项), + # 记录到 cap_names/cap_allocas/cap_tys 三个并行缓冲。 + # 返回更新后的捕获数量(递归调用逐层累加)。 + # ============================================================ + def _lambda_scan_body(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr, + param_names: str, + param_count: int, + cap_names: str, + cap_allocas: t.CVoid | t.CPtr, + cap_tys: t.CVoid | t.CPtr, + cap_count: int) -> int: + """递归扫描 lambda body 中的 Name 引用,收集捕获变量""" + if node is None or trans is None: + return cap_count + k: int = node.kind() + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is None: + return cap_count + # 排除 lambda 参数 + for pi in range(param_count): + if string.strcmp(param_names + pi * 32, nm.id) == 0: + return cap_count + # 已捕获跳过 + for ci in range(cap_count): + if string.strcmp(cap_names + ci * 64, nm.id) == 0: + return cap_count + # 查当前作用域链 + alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id) + if alloca is None or alloca.Ty is None: + return cap_count + pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if pointee is None: + return cap_count + # 跳过模块级全局(body 直接解析全局,无需 env 捕获) + mod_gv: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_module_var(trans.SymTab, nm.id) + if mod_gv is not None: + if t.CUInt64T(mod_gv) == t.CUInt64T(alloca): + return cap_count + if cap_count >= 64: + return cap_count + string.strncpy(cap_names + cap_count * 64, nm.id, 63) + al_slot: str | t.CPtr = (t.CVoid | t.CPtr)( + t.CUInt64T(cap_allocas) + cap_count * 8) + al_slot[0] = alloca + ty_slot: str | t.CPtr = (t.CVoid | t.CPtr)( + t.CUInt64T(cap_tys) + cap_count * 8) + ty_slot[0] = pointee + return cap_count + 1 + # 递归遍历常见表达式子节点 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + cc1: int = self._lambda_scan_body(trans, bop.left, param_names, param_count, + cap_names, cap_allocas, cap_tys, cap_count) + return self._lambda_scan_body(trans, bop.right, param_names, param_count, + cap_names, cap_allocas, cap_tys, cc1) + if k == ast.ASTKind.UnaryOp: + uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + return self._lambda_scan_body(trans, uop.operand, param_names, param_count, + cap_names, cap_allocas, cap_tys, cap_count) + if k == ast.ASTKind.BoolOp: + bop2: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) + cc2: int = cap_count + if bop2.values is not None: + vs: list[ast.AST | t.CPtr] | t.CPtr = bop2.values + vn: t.CSizeT = len(vs) + for vi in range(vn): + cc2 = self._lambda_scan_body(trans, vs.get(vi), param_names, param_count, + cap_names, cap_allocas, cap_tys, cc2) + return cc2 + if k == ast.ASTKind.Compare: + cmp: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) + cc3: int = self._lambda_scan_body(trans, cmp.left, param_names, param_count, + cap_names, cap_allocas, cap_tys, cap_count) + if cmp.comparators is not None: + cl: list[ast.AST | t.CPtr] | t.CPtr = cmp.comparators + cn: t.CSizeT = len(cl) + for cvi in range(cn): + cc3 = self._lambda_scan_body(trans, cl.get(cvi), param_names, param_count, + cap_names, cap_allocas, cap_tys, cc3) + return cc3 + if k == ast.ASTKind.Call: + cal: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + cc4: int = self._lambda_scan_body(trans, cal.func, param_names, param_count, + cap_names, cap_allocas, cap_tys, cap_count) + if cal.args is not None: + als: list[ast.AST | t.CPtr] | t.CPtr = cal.args + an: t.CSizeT = len(als) + for ai in range(an): + cc4 = self._lambda_scan_body(trans, als.get(ai), param_names, param_count, + cap_names, cap_allocas, cap_tys, cc4) + if cal.keywords is not None: + kws: list[ast.AST | t.CPtr] | t.CPtr = cal.keywords + kn: t.CSizeT = len(kws) + for ki in range(kn): + kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(kws.get(ki)) + if kw is not None and kw.value is not None: + cc4 = self._lambda_scan_body(trans, kw.value, param_names, param_count, + cap_names, cap_allocas, cap_tys, cc4) + return cc4 + if k == ast.ASTKind.Subscript: + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + cc5: int = self._lambda_scan_body(trans, sub.value, param_names, param_count, + cap_names, cap_allocas, cap_tys, cap_count) + if sub.slice is not None: + cc5 = self._lambda_scan_body(trans, sub.slice, param_names, param_count, + cap_names, cap_allocas, cap_tys, cc5) + return cc5 + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + return self._lambda_scan_body(trans, at.value, param_names, param_count, + cap_names, cap_allocas, cap_tys, cap_count) + if k == ast.ASTKind.IfExp: + ie: ast.IfExp | t.CPtr = (ast.IfExp | t.CPtr)(node) + cc6: int = self._lambda_scan_body(trans, ie.test, param_names, param_count, + cap_names, cap_allocas, cap_tys, cap_count) + cc6 = self._lambda_scan_body(trans, ie.body, param_names, param_count, + cap_names, cap_allocas, cap_tys, cc6) + return self._lambda_scan_body(trans, ie.orelse, param_names, param_count, + cap_names, cap_allocas, cap_tys, cc6) + if k == ast.ASTKind.List: + ls: ast.List | t.CPtr = (ast.List | t.CPtr)(node) + cc7: int = cap_count + if ls.elts is not None: + es: list[ast.AST | t.CPtr] | t.CPtr = ls.elts + en: t.CSizeT = len(es) + for ei in range(en): + cc7 = self._lambda_scan_body(trans, es.get(ei), param_names, param_count, + cap_names, cap_allocas, cap_tys, cc7) + return cc7 + if k == ast.ASTKind.Lambda: + lam2: ast.Lambda | t.CPtr = (ast.Lambda | t.CPtr)(node) + return self._lambda_scan_body(trans, lam2.body, param_names, param_count, + cap_names, cap_allocas, cap_tys, cap_count) + return cap_count diff --git a/App/lib/core/Gen/GenApi.vp b/App/lib/core/Gen/GenApi.vp new file mode 100644 index 0000000..da5b0f9 --- /dev/null +++ b/App/lib/core/Gen/GenApi.vp @@ -0,0 +1,491 @@ +import t, c +from stdint import * +import ast +import lib.Projectrans.Config as Config +import lib.Projectrans.Utils as Utils +import lib.core.StubMerger as StubMerger +import lib.core.VLogger as VLogger +import llvmlite +import memhub +import stdio +import stdlib +import string +import viperlib +import w32.fileio as fileio +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.Generator as Generator +import lib.core.Handles.HandlesTranslator as HT + + +# ============================================================ +# GenApi - 管线/保留文件访问 Gen 的模块级委托入口(去除 Handles 层) +# +# 由脚本从 Gen 子对象同名方法自动生成:签名取真源方法(含参数类型注解), +# 函数体经 _g_gen 单例调用 gen 子对象。main/BuildPipeline 注入 _g_gen。 +# ============================================================ + + +# 全局 gen 单例(main/BuildPipeline 创建 gen 后注入) +_g_gen: Generator.Generator | t.CPtr = None + + +# ---------------- set_temp_dir(委托 TypeGenBase.set_temp_dir) ---------------- +def set_temp_dir(temp_dir: str) -> None: + """委托到 gen.set_temp_dir(原 Handles 壳)""" + 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.TypeGenBase.set_temp_dir(temp_dir) + + +# ---------------- set_current_file_imports(委托 ImportsGenMixin.set_current_file) ---------------- +def set_current_file_imports(file_path: str) -> None: + """委托到 gen.set_current_file(原 Handles 壳)""" + 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.ImportsGen.set_current_file(file_path) + + +# ---------------- set_current_file_type(委托 TypeGenResolve.set_current_file) ---------------- +def set_current_file_type(file_path: str) -> None: + """委托到 gen.set_current_file(原 Handles 壳)""" + 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.TypeGenResolve.set_current_file(file_path) + + +# ---------------- set_current_module_sha1(委托 TypeGenBase.set_current_module_sha1) ---------------- +def set_current_module_sha1(sha1: str) -> None: + """委托到 gen.set_current_module_sha1(原 Handles 壳)""" + 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.TypeGenBase.set_current_module_sha1(sha1) + + +# ---------------- clear_trace(委托 TypeGenBase.clear_trace) ---------------- +def clear_trace() -> None: + """委托到 gen.clear_trace(原 Handles 壳)""" + 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.TypeGenBase.clear_trace() + + +# ---------------- clear_cdefine_constants(委托 TypeGenCDef.clear_cdefine_constants) ---------------- +def clear_cdefine_constants() -> None: + """委托到 gen.clear_cdefine_constants(原 Handles 壳)""" + 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.TypeGenCDef.clear_cdefine_constants() + + +# ---------------- clear_ctypedefs(委托 TypeGenCType.clear_ctypedefs) ---------------- +def clear_ctypedefs() -> None: + """委托到 gen.clear_ctypedefs(原 Handles 壳)""" + 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.TypeGenCType.clear_ctypedefs() + + +# ---------------- RegisterCTypedefFromSource(委托 TypeGenCType.register_ctypedef_from_source) ---------------- +def RegisterCTypedefFromSource(pool: memhub.MemBuddy | t.CPtr, src: str) -> int: + """委托到 gen.register_ctypedef_from_source(原 Handles 壳)""" + 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.TypeGenCType.register_ctypedef_from_source(pool, src) + return 0 + + +# ---------------- dump_parse_traceback(委托 TypeGenErr.dump_parse_traceback) ---------------- +def dump_parse_traceback(file_path: str) -> None: + """委托到 gen.dump_parse_traceback(原 Handles 壳)""" + 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.TypeGenErr.dump_parse_traceback(file_path) + + +# ---------------- map_t_type(委托 TypeGenResolve.map_t_type) ---------------- +def map_t_type(pool: memhub.MemBuddy | t.CPtr, type_name: str) -> llvmlite.LLVMType | t.CPtr: + """委托到 gen.map_t_type(原 Handles 壳)""" + 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.TypeGenResolve.map_t_type(pool, type_name) + return None + + +# ---------------- get_current_file(委托 TypeGenResolve.get_current_file) ---------------- +def get_current_file() -> str: + """委托到 gen.get_current_file(原 Handles 壳)""" + 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.TypeGenResolve.get_current_file() + return None + + +# ---------------- _is_ctypedef_annotation(委托 TypeGenCType._is_ctypedef_annotation) ---------------- +def _is_ctypedef_annotation(annotation: ast.AST | t.CPtr) -> int: + """委托到 gen._is_ctypedef_annotation(原 Handles 壳)""" + 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.TypeGenCType._is_ctypedef_annotation(annotation) + return 0 + + +# ---------------- resolve_annotation_type(委托 TypeGenResolve.resolve_annotation_type) ---------------- +def resolve_annotation_type(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: + """委托到 gen.resolve_annotation_type(原 Handles 壳)""" + 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.TypeGenResolve.resolve_annotation_type(pool, node, imported_modules, from_imports, trans) + return None + + +# ---------------- has_decorator_marker(委托 TypeGenErr.has_decorator_marker) ---------------- +def has_decorator_marker(node: ast.AST | t.CPtr, marker_name: str) -> int: + """委托到 gen.has_decorator_marker(原 Handles 壳)""" + 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.TypeGenErr.has_decorator_marker(node, marker_name) + return 0 + + +# ---------------- _get_type_name_from_annotation(委托 TypeGenResolve._get_type_name_from_annotation) ---------------- +def _get_type_name_from_annotation(pool: memhub.MemBuddy | t.CPtr, node: ast.AST | t.CPtr) -> str: + """委托到 gen._get_type_name_from_annotation(原 Handles 壳)""" + 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.TypeGenResolve._get_type_name_from_annotation(pool, node) + return None + + +# ---------------- register_ctypedef(委托 TypeGenCType.register_ctypedef) ---------------- +def register_ctypedef(pool: memhub.MemBuddy | t.CPtr, name: str, type_str: str) -> None: + """委托到 gen.register_ctypedef(原 Handles 壳)""" + 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.TypeGenCType.register_ctypedef(pool, name, type_str) + + +# ---------------- lookup_cdefine_constant(委托 TypeGenCDef.lookup_cdefine_constant) ---------------- +def lookup_cdefine_constant(name: str) -> t.CInt64T: + """委托到 gen.lookup_cdefine_constant(原 Handles 壳)""" + 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.TypeGenCDef.lookup_cdefine_constant(name) + return 0 + + +# ---------------- is_cdefine_found(委托 TypeGenCDef.is_cdefine_found) ---------------- +def is_cdefine_found() -> int: + """委托到 gen.is_cdefine_found(原 Handles 壳)""" + 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.TypeGenCDef.is_cdefine_found() + return 0 + + +# ---------------- push_trace(委托 TypeGenBase.push_trace) ---------------- +def push_trace(file_name: str, lineno: int, col_start: int = 0, col_end: int = 0) -> None: + """委托到 gen.push_trace(原 Handles 壳)""" + 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.TypeGenBase.push_trace(file_name, lineno, col_start, col_end) + + +# ---------------- pop_trace(委托 TypeGenBase.pop_trace) ---------------- +def pop_trace() -> None: + """委托到 gen.pop_trace(原 Handles 壳)""" + 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.TypeGenBase.pop_trace() + + +# ---------------- get_temp_dir(委托 TypeGenBase.get_temp_dir) ---------------- +def get_temp_dir() -> str: + """委托到 gen.get_temp_dir(原 Handles 壳)""" + 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.TypeGenBase.get_temp_dir() + return None + + +# ---------------- reset_visible_structs(委托 StructGenMixin.reset_visible_structs) ---------------- +def reset_visible_structs(pool: memhub.MemBuddy | t.CPtr, strict: int) -> None: + """委托到 gen.reset_visible_structs(原 Handles 壳)""" + 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.StructGen.reset_visible_structs(pool, strict) + + +# ---------------- set_stdlib_alloc(委托 StructGenMixin.set_stdlib_alloc) ---------------- +def set_stdlib_alloc(flag: int) -> None: + """委托到 gen.set_stdlib_alloc(原 Handles 壳)""" + 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.StructGen.set_stdlib_alloc(flag) + + +# ---------------- get_struct_count(委托 StructGenMixin.get_struct_count) ---------------- +def get_struct_count() -> int: + """委托到 gen.get_struct_count(原 Handles 壳)""" + 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.StructGen.get_struct_count() + return 0 + + +# ---------------- reset_module_methods_emitted(委托 StructGenMixin.reset_module_methods_emitted) ---------------- +def reset_module_methods_emitted(sha1: str) -> int: + """委托到 gen.reset_module_methods_emitted(原 Handles 壳)""" + 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.StructGen.reset_module_methods_emitted(sha1) + return 0 + + +# ---------------- get_struct_type(委托 StructGenMixin.get_struct_type) ---------------- +def get_struct_type(class_name: str) -> llvmlite.LLVMType | t.CPtr: + """委托到 gen.get_struct_type(原 Handles 壳)""" + 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.StructGen.get_struct_type(class_name) + return None + + +# ---------------- add_visible_struct(委托 StructGenMixin.add_visible_struct) ---------------- +def add_visible_struct(pool: memhub.MemBuddy | t.CPtr, name: str) -> None: + """委托到 gen.add_visible_struct(原 Handles 壳)""" + 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.StructGen.add_visible_struct(pool, name) + + +# ---------------- compute_package_from_relpath(委托 ImportsGenMixin.compute_package_from_relpath) ---------------- +def compute_package_from_relpath(pool: memhub.MemBuddy | t.CPtr, rel_path: str) -> str: + """委托到 gen.compute_package_from_relpath(原 Handles 壳)""" + 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.ImportsGen.compute_package_from_relpath(pool, rel_path) + return None + + +# ---------------- is_module_imported(委托 ImportsGenMixin.is_module_imported) ---------------- +def is_module_imported(imported_modules: str, name: str) -> int: + """委托到 gen.is_module_imported(原 Handles 壳)""" + 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.ImportsGen.is_module_imported(imported_modules, name) + return 0 + + +# ---------------- add_imported_module(委托 ImportsGenMixin.add_imported_module) ---------------- +def add_imported_module(pool: memhub.MemBuddy | t.CPtr, imported_modules: str, name: str) -> str: + """委托到 gen.add_imported_module(原 Handles 壳)""" + 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.ImportsGen.add_imported_module(pool, imported_modules, name) + return None + + +# ---------------- translate_import(委托 ImportsGenMixin.translate_import) ---------------- +def translate_import(trans: HT.Translator | t.CPtr, node: ast.AST | t.CPtr) -> int: + """委托到 gen.translate_import(原 Handles 壳)""" + 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.ImportsGen.translate_import(trans, node) + return 0 + + +# ---------------- translate_import_from_module(委托 ImportsGenMixin.translate_import_from_module) ---------------- +def translate_import_from_module(trans: HT.Translator | t.CPtr, node: ast.AST | t.CPtr) -> int: + """委托到 gen.translate_import_from_module(原 Handles 壳)""" + 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.ImportsGen.translate_import_from_module(trans, node) + return 0 + + +# ---------------- translate_import_from_names(委托 ImportsGenMixin.translate_import_from_names) ---------------- +def translate_import_from_names(trans: HT.Translator | t.CPtr, node: ast.AST | t.CPtr) -> int: + """委托到 gen.translate_import_from_names(原 Handles 壳)""" + 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.ImportsGen.translate_import_from_names(trans, node) + return 0 + + +# ---------------- _get_parent_class(委托 ClassGenBase._get_parent_class) ---------------- +def _get_parent_class(cd: ast.ClassDef | t.CPtr, trans: HT.Translator | t.CPtr = None) -> str: + """委托到 gen._get_parent_class(原 Handles 壳)""" + 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.ClassGenBase._get_parent_class(cd, trans) + return None + + +# ---------------- _register_generic_template(委托 ClassGenGeneric._register_generic_template) ---------------- +def _register_generic_template(pool: memhub.MemBuddy | t.CPtr, cd: ast.ClassDef | t.CPtr, module_sha1: str) -> None: + """委托到 gen._register_generic_template(原 Handles 壳)""" + 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.ClassGenGeneric._register_generic_template(pool, cd, module_sha1) + + +# ---------------- _mangle_name_with_sha1(委托 FuncGenBase._mangle_name_with_sha1) ---------------- +def _mangle_name_with_sha1(sha1: str, name: str) -> str: + """委托到 gen._mangle_name_with_sha1(原 Handles 壳)""" + 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.FuncGenBase._mangle_name_with_sha1(sha1, name) + return None + + +# ---------------- forward_declare_functions(委托 FuncGenDef.forward_declare_functions) ---------------- +def forward_declare_functions(trans: HT.Translator | t.CPtr, tree: ast.AST | t.CPtr) -> int: + """委托到 gen.forward_declare_functions(原 Handles 壳)""" + 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.FuncGenDef.forward_declare_functions(trans, tree) + return 0 + + +# ---------------- create_wrapper_main(委托 TranslatorGenMixin.create_wrapper_main) ---------------- +def create_wrapper_main(trans: HT.Translator | t.CPtr, tree: ast.AST | t.CPtr, i32_ty: llvmlite.LLVMType | t.CPtr) -> int: + """委托到 gen.create_wrapper_main(原 Handles 壳)""" + 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.TranslatorGen.create_wrapper_main(trans, tree, i32_ty) + return 0 + + +# ---------------- handle_module_level_var(委托 TranslatorGenMixin.handle_module_level_var) ---------------- +def handle_module_level_var(trans: HT.Translator | t.CPtr, node: ast.AST | t.CPtr) -> int: + """委托到 gen.handle_module_level_var(原 Handles 壳)""" + 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.TranslatorGen.handle_module_level_var(trans, node) + return 0 + + +# ---------------- translate_children(委托 TranslatorGenMixin.translate_children) ---------------- +def translate_children(trans: HT.Translator | t.CPtr, tree: ast.AST | t.CPtr) -> int: + """委托到 gen.translate_children(原 Handles 壳)""" + 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.TranslatorGen.translate_children(trans, tree) + return 0 + + +# ---------------- init_symbol_table(委托 VarGenMixin.init_symbol_table) ---------------- +def init_symbol_table(pool: memhub.MemBuddy | t.CPtr) -> GenTypes.SymbolTable | t.CPtr: + """委托到 gen.init_symbol_table(原 Handles 壳)""" + 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.VarGen.init_symbol_table(pool) + return None + + +# ---------------- SetTempDir(委托 CallGenBase.SetTempDir) ---------------- +def SetTempDir(temp_dir: str) -> None: + """委托到 gen.SetTempDir(原 Handles 壳)""" + 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.CallGenBase.SetTempDir(temp_dir) + + +# ---------------- find_func_in_module(委托 CallGenBase.find_func_in_module) ---------------- +def find_func_in_module(mod: llvmlite.LLVMModule | t.CPtr, name: str) -> llvmlite.Function | t.CPtr: + """委托到 gen.find_func_in_module(原 Handles 壳)""" + 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.CallGenBase.find_func_in_module(mod, name) + return None + + +# ---------------- add_func_to_table(委托 CallGenLeafKit.add_func_to_table) ---------------- +def add_func_to_table(funcs: GenTypes.FuncEntry | t.CPtr, func_count: int, name: str, func: llvmlite.Function | t.CPtr, max_count: int, defaults: t.CVoid | t.CPtr = None, default_count: int = 0, param_count: int = 0, pool: memhub.MemBuddy | t.CPtr = None) -> int: + """委托到 gen.add_func_to_table(原 Handles 壳)""" + 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.CallGenLeafKit.add_func_to_table(funcs, func_count, name, func, max_count, defaults, default_count, param_count, pool) + return 0 + + +# ---------------- init_func_table(委托 CallGenLeafKit.init_func_table) ---------------- +def init_func_table(pool: memhub.MemBuddy | t.CPtr, max_count: int) -> GenTypes.FuncEntry | t.CPtr: + """委托到 gen.init_func_table(原 Handles 壳)""" + 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.CallGenLeafKit.init_func_table(pool, max_count) + return None + + +# ---------------- translate_call(委托 CallGenMixin.translate_call) ---------------- +def translate_call(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, node: ast.AST | t.CPtr, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """委托到 gen.translate_call(原 Handles 壳)""" + 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.CallGen.translate_call(pool, builder, mod, node, funcs_ptr, func_count, trans) + return None + + +# ---------------- translate_printf_call(委托 CallGenLeafKit.translate_printf_call) ---------------- +def translate_printf_call(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, cl: ast.Call | t.CPtr, trans: HT.Translator | t.CPtr = None) -> None: + """委托到 gen.translate_printf_call(原 Handles 壳)""" + 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.CallGenLeafKit.translate_printf_call(pool, builder, mod, cl, trans) + + +# ---------------- translate_print_call(委托 CallGenLeafKit.translate_print_call) ---------------- +def translate_print_call(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, cl: ast.Call | t.CPtr, trans: HT.Translator | t.CPtr = None) -> None: + """委托到 gen.translate_print_call(原 Handles 壳)""" + 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.CallGenLeafKit.translate_print_call(pool, builder, mod, cl, trans) diff --git a/App/lib/core/Gen/GenTypes.vp b/App/lib/core/Gen/GenTypes.vp new file mode 100644 index 0000000..9f64eed --- /dev/null +++ b/App/lib/core/Gen/GenTypes.vp @@ -0,0 +1,193 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub + + +# ============================================================ +# GenTypes - Gen 侧共享数据类型与常量(去除 Handles 层迁移目标) +# +# 原分布于 Handles 目录的数据类与常量集中于此,供 Gen 子对象、 +# 管线与保留实体文件引用。删除 Handles 目录后统一经本模块访问。 +# ============================================================ + +# ============================================================ +# 类编译期元数据(原 HandlesType.CLASS_META_*) +# ============================================================ +CLASS_META_PROVIDES: t.CDefine = 1 +CLASS_META_REQUIRES: t.CDefine = 2 +CLASS_META_REQUIRE_MUST: t.CDefine = 3 + +# ============================================================ +# 属性/静态/类方法元数据(原 HandlesClassDef.META_*) +# ============================================================ +META_STATIC: t.CDefine = 1 +META_CLASS: t.CDefine = 2 +META_PROP_GETTER: t.CDefine = 4 +META_PROP_SETTER: t.CDefine = 8 +META_PROP_DELETER: t.CDefine = 16 + +# ============================================================ +# 结构体容量(原 HandlesStruct.FIELD_MAX/FIELD_NAME_MAX/PARENT_MAX/MRO_MAX) +# ============================================================ +FIELD_MAX: t.CDefine = 256 +FIELD_NAME_MAX: t.CDefine = 64 +PARENT_MAX: t.CDefine = 64 +MRO_MAX: t.CDefine = 64 + +# ============================================================ +# for 迭代序列种类(原 HandlesFor.SEQ_KIND_*) +# ============================================================ +SEQ_KIND_RANGE: t.CDefine = 1 +SEQ_KIND_STR: t.CDefine = 2 +SEQ_KIND_LIST: t.CDefine = 3 + +# ============================================================ +# TraceFrame - 仿 Python Traceback 调用栈帧(原 HandlesType.TraceFrame) +# ============================================================ +class TraceFrame: + """仿 Python Traceback 调用栈帧(push_trace/pop_trace 使用)""" + file_name: str + lineno: int + col_start: int + col_end: int + + +# ============================================================ +# VarEntry - 变量表条目(原 HandlesVar.VarEntry) +# ============================================================ +class VarEntry: + """变量表条目""" + Name: str + Alloca: llvmlite.Value | t.CPtr + Used: t.CInt + AnnotClassName: str # 原始类型注解的类名(str 别名在结构体字段中触发编译器 bug,改用显式联合类型) + IsPtrElement: t.CInt # 标志: 1=注解为 bytes|t.CPtr 或 str|t.CPtr, 下标按 8 字节步长 + + +# ============================================================ +# Scope - 作用域节点(原 HandlesVar.Scope) +# ============================================================ +@t.NoVTable +class Scope: + """作用域节点""" + Parent: Scope | t.CPtr + Vars: VarEntry | t.CPtr + VarCount: t.CInt + Kind: t.CInt + + +# ============================================================ +# SymbolTable - 嵌套作用域符号表(原 HandlesVar.SymbolTable) +# ============================================================ +@t.NoVTable +class SymbolTable: + """嵌套作用域符号表""" + Pool: memhub.MemBuddy | t.CPtr + Root: Scope | t.CPtr + Current: Scope | t.CPtr + + +# ============================================================ +# FieldEntry - 字段信息条目(原 HandlesStruct.FieldEntry) +# ============================================================ +class FieldEntry: + Name: str # 字段名(字符串) + Index: int # 字段在结构体中的索引 + Ty: llvmlite.LLVMType | t.CPtr # 字段的 LLVM 类型 + DefaultVal: ast.AST | t.CPtr # 默认值 AST 节点(None=无默认值) + AnnotClassName: str # 原始类型注解的类名(str 别名在结构体字段中触发编译器 bug,改用显式联合类型) + + +# ============================================================ +# StructEntry - 结构体注册条目(原 HandlesStruct.StructEntry) +# ============================================================ +@t.NoVTable +class StructEntry: + Name: str # 类名 + Ty: llvmlite.LLVMType | t.CPtr # LLVM StructType + FieldCount: int # 字段数量 + Fields: FieldEntry | t.CPtr # 字段数组(FIELD_MAX 个槽位) + IsUnion: int # 1=联合体 / 0=普通结构体 + IsOOP: int # 1=OOP结构体(有方法) / 0=纯内存结构体 + HasInit: int # 1=有__init__方法 / 0=无 + HasNew: int # 1=有__new__方法 / 0=无 + HasVTable: int # 1=有虚表 / 0=无虚表 + IsNoVTable: int # 1=明确标记 @t.NoVTable / 0=未标记 + ParentName: str # 父类名(None=无父类,多继承时为第一个父类,兼容旧调用) + ParentNames: t.CSizeT | t.CPtr # 多继承父类名数组(每元素 str 指针,ParentCount 个;stdlib 深拷贝) + ParentCount: t.CInt # 父类数量(0=无父类,1=单继承,>1=多继承) + VTableMethodCount: int # 虚表中的方法数量 + VTableMethods: str # 虚表方法名数组(每个方法名 str,VTableMethodCount 个) + ModuleSha1: str # 定义该类的模块 SHA1(None=无 SHA1) + MethodsEmitted: int # 1=方法体已翻译 / 0=未译(Phase 1a mark_only 未译,Phase B 据此补译) + SpecTriggerSha1: str # 泛型特化类的触发文件 SHA1(None=非特化类)。特化类 ModuleSha1=模板 + # sha1(方法名带模板前缀),作废重译时 reset_module_methods_emitted + # 按触发文件 sha1 精确重置 MethodsEmitted,防特化方法体残留 1 不补译 + # → 链接 undefined symbol(list[ast.ClassDef|t.CPtr].* 根因) + + +# ============================================================ +# EnumMember - 枚举成员(原 HandlesEnum.EnumMember) +# ============================================================ +class EnumMember: + Name: str # 成员名(字符串) + Value: t.CInt64T # 成员的整数值 + Ty: llvmlite.LLVMType | t.CPtr # 成员的 LLVM 类型(用于混用类型场景) + + +# ============================================================ +# EnumEntry - 枚举类型条目(原 HandlesEnum.EnumEntry) +# ============================================================ +@t.NoVTable +class EnumEntry: + Name: str # 枚举类名 + BaseTy: llvmlite.LLVMType | t.CPtr # 基准类型(所有成员类型中最大的) + MemberCount: int # 成员数量 + Members: EnumMember | t.CPtr # 成员数组(ENUM_MEMBER_MAX 个槽位) + + +# ============================================================ +# AsmOperand - 内联汇编操作数条目(原 HandlesExprCall.AsmOperand) +# ============================================================ +class AsmOperand: + """内联汇编操作数条目""" + Value: llvmlite.Value | t.CPtr # 输入值或输出 alloca + Constraint: str # 约束字符串 (如 "r", "=r") + IsOutput: int # 1=输出, 0=输入 + + +# ============================================================ +# FuncEntry - 函数表条目(原 HandlesExprCall.FuncEntry) +# ============================================================ +@t.NoVTable +class FuncEntry: + """函数表条目""" + Name: str + Func: llvmlite.Function | t.CPtr + Defaults: t.CVoid | t.CPtr # defaults 列表节点指针 (list[AST | CPtr]),None=无默认值 + DefaultCount: int # 默认值数量 + ParamCount: int # 形参数量(不含 self) + # TypeStr: 函数类型文本(stdlib 深拷贝,跨文件安全) + # 1b 每文件 reset_to(mark1) 回收 pool 内 Function 对象后, + # vtable 生成 find_func_global 读类型改用此文本,避免悬空。 + TypeStr: str + + +# ============================================================ +# FuncDefaultsEntry - 默认参数表条目(原 HandlesExprCall.FuncDefaultsEntry) +# ============================================================ +@t.NoVTable +class FuncDefaultsEntry: + """默认参数表条目""" + Name: str + Defaults: t.CVoid | t.CPtr # defaults 列表节点指针 (list[AST | CPtr])(pool 内,可能被 reset) + DefaultCount: int + ParamCount: int # 形参数量(不含 self) + # 常量快照(stdlib 分配,跨文件永久存活): + # 注册时提取每个默认值 Constant 的值,跨模块调用时优先用快照重建常量 IR, + # 避免读取已被 1b reset_to(mark1) 回收的 pool 内 AST。 + ConstKinds: t.CInt | t.CPtr # const_kind 数组(DefaultCount 个 i32) + ConstInts: t.CInt64T | t.CPtr # int_val 数组(DefaultCount 个 i64) + ConstStrs: t.CSizeT | t.CPtr # str_val 指针数组(DefaultCount 个 i8*) diff --git a/App/lib/core/Gen/Generator.vp b/App/lib/core/Gen/Generator.vp index 61b5b79..10600d7 100644 --- a/App/lib/core/Gen/Generator.vp +++ b/App/lib/core/Gen/Generator.vp @@ -1,17 +1,21 @@ +import string +import lib.core.CompilerFactory as CompilerFactory import t, c from stdint import * +import stdio +import stdlib 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.TypeGenMixin as TypeGenMixin 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.ExprGenBase as ExprGenBase +import lib.core.Gen.ExprGenMixin as ExprGenMixin import lib.core.Gen.ExprGenConst as ExprGenConst import lib.core.Gen.ExprGenFstr as ExprGenFstr import lib.core.Gen.ExprGenOps as ExprGenOps @@ -19,215 +23,437 @@ import lib.core.Gen.ExprGenCdef as ExprGenCdef import lib.core.Gen.ExprGenName as ExprGenName import lib.core.Gen.ExprGenAttr as ExprGenAttr import lib.core.Gen.ExprGenCls as ExprGenCls -import lib.core.Gen.CallGenMixin as CallGenMixin import lib.core.Gen.CallGenBase as CallGenBase -import lib.core.Gen.CallGenLeafKit as CallGenLeafKit import lib.core.Gen.CallGenCBuiltin as CallGenCBuiltin +import lib.core.Gen.CallGenLeafKit as CallGenLeafKit import lib.core.Gen.CallGenCtor as CallGenCtor import lib.core.Gen.CallGenCall as CallGenCall -import lib.core.Gen.CallGenProp as CallGenProp -import lib.core.Gen.CallGenFd as CallGenFd +import lib.core.Gen.CallGenMixin as CallGenMixin +import lib.core.Gen.CallGenDispatch as CallGenDispatch +import lib.core.Gen.CallGenLib as CallGenLib import lib.core.Gen.CallGenVt as CallGenVt import lib.core.Gen.CallGenVa as CallGenVa -import lib.core.Gen.CallGenLib as CallGenLib -import lib.core.Gen.CallGenDispatch as CallGenDispatch +import lib.core.Gen.CallGenProp as CallGenProp +import lib.core.Gen.CallGenFd as CallGenFd import lib.core.Gen.FuncGenBase as FuncGenBase import lib.core.Gen.FuncGenDef as FuncGenDef import lib.core.Gen.FuncGenMixin as FuncGenMixin -import lib.core.Gen.ClassGenMixin as ClassGenMixin import lib.core.Gen.ClassGenBase as ClassGenBase +import lib.core.Gen.ClassGenMixin as ClassGenMixin import lib.core.Gen.ClassGenEnum as ClassGenEnum import lib.core.Gen.ClassGenGeneric as ClassGenGeneric import lib.core.Gen.ClassGenVTable as ClassGenVTable import lib.core.Gen.ClassGenDef as ClassGenDef import lib.core.Gen.ImportsGenMixin as ImportsGenMixin +import lib.core.Gen.StmtGenCifMixin as StmtGenCifMixin +import lib.core.Gen.StmtGenDeclMixin as StmtGenDeclMixin import lib.core.Gen.StmtGenMixin as StmtGenMixin import lib.core.Gen.MatchGenMixin as MatchGenMixin import lib.core.Gen.AssignGenMixin as AssignGenMixin import lib.core.Gen.VarGenMixin as VarGenMixin import lib.core.Gen.TranslatorGenMixin as TranslatorGenMixin -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesExprCall as HandlesExprCall # ============================================================ -# Generator - 生成器(P1 骨架 + P2 多继承 Mixin 组合) +# Generator - 生成器(双向引用组合架构) # -# 对象化重构宿主(wiki/14-oo-refactor.md): -# @t.NoVTable + 多继承(BaseGen 状态 + TypeGen 类型映射),方法沿 -# MRO 直接调用(Viper 多继承已支持,M1-M4)。后续 P3-P6 追加 -# StructGen/ExprGen/CallGen/FuncGen/ClassGen/StmtGen/ImportsGen Mixin。 -# -# 注意:Viper NoVTable 继承只合并字段、不转发父类方法符号(子类调 -# 父类方法 mangle 成子类名 → undefined reference),因此字段初始化 -# 全部内联,不调用父类 Init* 方法。 +# 不再 46 路多继承 Mixin;改为组合:Generator 持所有 GenMixin +# 子对象指针(永久池分配,全生命周期),每个 Mixin 持 Gen 回指。 +# 跨子对象访问 = self.Gen..<字段/方法>(链式有风险, +# 统一用中间变量取子对象再访问)。高亮可推导(显式类型注解)。 # ============================================================ @t.NoVTable -class Generator(BaseGenMixin.BaseGenMixin, TypeGenMixin.TypeGenMixin, - TypeGenBase.TypeGenBase, TypeGenCDef.TypeGenCDef, - TypeGenCType.TypeGenCType, TypeGenResolve.TypeGenResolve, - TypeGenErr.TypeGenErr, - StructGenMixin.StructGenMixin, ExprGenMixin.ExprGenMixin, - ExprGenBase.ExprGenBase, ExprGenConst.ExprGenConst, - ExprGenFstr.ExprGenFstr, ExprGenOps.ExprGenOps, - ExprGenCdef.ExprGenCdef, ExprGenName.ExprGenName, - ExprGenAttr.ExprGenAttr, ExprGenCls.ExprGenCls, - CallGenMixin.CallGenMixin, CallGenBase.CallGenBase, - CallGenLeafKit.CallGenLeafKit, CallGenCBuiltin.CallGenCBuiltin, - CallGenCtor.CallGenCtor, CallGenCall.CallGenCall, - CallGenProp.CallGenProp, CallGenFd.CallGenFd, - CallGenVt.CallGenVt, CallGenVa.CallGenVa, - CallGenLib.CallGenLib, CallGenDispatch.CallGenDispatch, - FuncGenBase.FuncGenBase, FuncGenDef.FuncGenDef, - FuncGenMixin.FuncGenMixin, - ClassGenMixin.ClassGenMixin, ClassGenBase.ClassGenBase, - ClassGenEnum.ClassGenEnum, ClassGenGeneric.ClassGenGeneric, - ClassGenVTable.ClassGenVTable, ClassGenDef.ClassGenDef, - ImportsGenMixin.ImportsGenMixin, - StmtGenMixin.StmtGenMixin, MatchGenMixin.MatchGenMixin, - AssignGenMixin.AssignGenMixin, - VarGenMixin.VarGenMixin, TranslatorGenMixin.TranslatorGenMixin): - """生成器:多继承 Mixin 组合(对象化迁移宿主)""" +class Generator: + """生成器:持所有 GenMixin 子对象指针(双向引用组合)""" + + # ---- 子对象指针(46 个,永久池) ---- + BaseGen: BaseGenMixin.BaseGenMixin | t.CPtr + TypeGenBase: TypeGenBase.TypeGenBase | t.CPtr + TypeGen: TypeGenMixin.TypeGenMixin | t.CPtr + TypeGenCDef: TypeGenCDef.TypeGenCDef | t.CPtr + TypeGenCType: TypeGenCType.TypeGenCType | t.CPtr + TypeGenResolve: TypeGenResolve.TypeGenResolve | t.CPtr + TypeGenErr: TypeGenErr.TypeGenErr | t.CPtr + StructGen: StructGenMixin.StructGenMixin | t.CPtr + ExprGenBase: ExprGenBase.ExprGenBase | t.CPtr + ExprGen: ExprGenMixin.ExprGenMixin | t.CPtr + ExprGenConst: ExprGenConst.ExprGenConst | t.CPtr + ExprGenFstr: ExprGenFstr.ExprGenFstr | t.CPtr + ExprGenOps: ExprGenOps.ExprGenOps | t.CPtr + ExprGenCdef: ExprGenCdef.ExprGenCdef | t.CPtr + ExprGenName: ExprGenName.ExprGenName | t.CPtr + ExprGenAttr: ExprGenAttr.ExprGenAttr | t.CPtr + ExprGenCls: ExprGenCls.ExprGenCls | t.CPtr + CallGenBase: CallGenBase.CallGenBase | t.CPtr + CallGenCBuiltin: CallGenCBuiltin.CallGenCBuiltin | t.CPtr + CallGenLeafKit: CallGenLeafKit.CallGenLeafKit | t.CPtr + CallGenCtor: CallGenCtor.CallGenCtor | t.CPtr + CallGenCall: CallGenCall.CallGenCall | t.CPtr + CallGen: CallGenMixin.CallGenMixin | t.CPtr + CallGenDispatch: CallGenDispatch.CallGenDispatch | t.CPtr + CallGenLib: CallGenLib.CallGenLib | t.CPtr + CallGenVt: CallGenVt.CallGenVt | t.CPtr + CallGenVa: CallGenVa.CallGenVa | t.CPtr + CallGenProp: CallGenProp.CallGenProp | t.CPtr + CallGenFd: CallGenFd.CallGenFd | t.CPtr + FuncGenBase: FuncGenBase.FuncGenBase | t.CPtr + FuncGenDef: FuncGenDef.FuncGenDef | t.CPtr + FuncGen: FuncGenMixin.FuncGenMixin | t.CPtr + ClassGenBase: ClassGenBase.ClassGenBase | t.CPtr + ClassGen: ClassGenMixin.ClassGenMixin | t.CPtr + ClassGenEnum: ClassGenEnum.ClassGenEnum | t.CPtr + ClassGenGeneric: ClassGenGeneric.ClassGenGeneric | t.CPtr + ClassGenVTable: ClassGenVTable.ClassGenVTable | t.CPtr + ClassGenDef: ClassGenDef.ClassGenDef | t.CPtr + ImportsGen: ImportsGenMixin.ImportsGenMixin | t.CPtr + StmtGenCif: StmtGenCifMixin.StmtGenCifMixin | t.CPtr + StmtGenDecl: StmtGenDeclMixin.StmtGenDeclMixin | t.CPtr + StmtGen: StmtGenMixin.StmtGenMixin | t.CPtr + MatchGen: MatchGenMixin.MatchGenMixin | t.CPtr + AssignGen: AssignGenMixin.AssignGenMixin | t.CPtr + VarGen: VarGenMixin.VarGenMixin | t.CPtr + TranslatorGen: TranslatorGenMixin.TranslatorGenMixin | t.CPtr def __init__(self, pool: memhub.MemBuddy | t.CPtr): if self is None: return - # ---- BaseGenMixin 字段 ---- - self.Pool = pool - self.Module = None - self.Builder = None - self.SymTab = None - self.Funcs = None - self.FuncCount = 0 - self.ImportedModules = None - self.FromImports = None - self.ModuleSha1 = None - self.CurFunc = None - self.CurBuilder = None - self.CurClassName = None - # ---- TypeGenMixin 字段 ---- - 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 - # 跨模块 CDefine 查找缓存(perm_pool 永久,跨文件复用) - 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.CurrentFile = None - self.ConstEvalOk = 0 - # ---- StructGenMixin 字段 ---- - self.StructTable = None - self.StructCount = 0 - self.StdlibAlloc = 0 - self.VisibleStructs = None - self.StrictVisibility = 0 - # OOM 语句级诊断:translate_stmt 限频打印 used(定位单文件翻译暴涨起点) - self.DiagStmtCount = 0 - # ---- CallGenMixin 字段 ---- - self.CexportSha1Arr = None - self.CexportFuncArr = None - self.CexportCount = 0 - self.LLVMIRRegSeq = 0 - self.TempDir = None - self.TempDirLen = 0 - self.ClosureNames = None - self.ClosureCount = 0 - self.FuncptrNames = None - self.FuncptrRets = None - self.FuncptrCount = 0 - self.GlobalFuncs = None - self.GlobalFuncCount = 0 - self.GlobalDefaults = None - self.GlobalDefaultsCount = 0 - # ---- ClassGenMixin 字段 ---- - self.MethodMetaKeys = None - self.MethodMetaFlags = None - self.MethodMetaCount = 0 - self.RenumClassNames = None - self.RenumClassVariantCounts = None - self.RenumVariantNames = None - self.RenumVariantTags = None - self.RenumClassCount = 0 - self.RenumAliasClass = None - self.RenumAliasField = None - self.RenumAliasIndex = None - self.RenumAliasCount = 0 - self.SpecKeys = None - self.SpecNames = None - self.SpecCount = 0 - self.GenericClassNames = None - self.GenericClassNodes = None - self.GenericClassSha1s = None - self.GenericClassFiles = None - self.GenericClassTpParams = None - self.VtFullNames = None - self.VtMethodNames = None - self.VtParentSha1s = None - self.VtMethodCount = 0 - # ---- ClassGenBase 补漏字段(阶段 D 拆分新增,此前未初始化: - # 结构体是 malloc 分配,未初始化字段是内存垃圾——非 null 垃圾 - # 指针能通过 `is not None` 检查,导致 is_exception_name 等查询 - # 直接 strcmp 越界崩溃;int 垃圾则导致循环次数失控) ---- - self.RenumAliasTy = None - self.RenumAliasVariant = None - self.ClassMetaKinds = None - self.ClassMetaClss = None - self.ClassMetaFields = None - self.ClassMetaCount = 0 - self.DecoratorFuncCount = 0 - self.DecoratorFuncNames = None - self.DecoratorWrapNames = None - self.DecoratorArgs = None - # 异常类注册表(_ensure_exception_tables 仍保留懒分配,但 - # ExceptionNames 必须初始化为 null——否则 `is not None` 误判垃圾 - # 指针为已初始化,跳过分配直接查表 → strcmp 越界) - self.ExceptionCount = 0 - self.ExceptionNames = None - self.ExceptionParents = None - self.ExceptionCodes = None - self.NextExceptionCode = 0 - self._exception_codes_tmp_count = 0 - self.GenericSpecDepth = 0 - # ---- ImportsGenMixin 字段 ---- - self.ReexportSha1s = None - self.ReexportFuncs = None - self.ReexportSrcs = None - self.ReexportCount = 0 - # ---- StmtGenMixin 字段 ---- - self.CifEvalOk = 0 - self.EnumTable = None - self.EnumCount = 0 - # ---- AssignGenMixin 字段 ---- - self.RecoverFound = 0 - # ---- ExprGenMixin docstring 字段(__doc__ 魔法属性支持)---- - self.DocKeys = None - self.DocValues = None - self.DocCount = 0 - # OOM 诊断计数:跨模块 CDefine 查找调用次数 - self.DiagCDefineCount = 0 - self.DiagNameValueCount = 0 - self.DiagTranslateValueCount = 0 + # ---- alloc 46 个子对象 + 回指(永久池,fail-fast) ---- + SubBaseGen: BaseGenMixin.BaseGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(BaseGenMixin.BaseGenMixin.__sizeof__()) + if SubBaseGen is None: + stdio.printf("FAIL: BaseGenMixin alloc failed\n") + stdlib.exit(1) + string.memset(SubBaseGen, 0, BaseGenMixin.BaseGenMixin.__sizeof__()) + SubBaseGen.Gen = self + self.BaseGen = SubBaseGen + SubTypeGenBase: TypeGenBase.TypeGenBase | t.CPtr = CompilerFactory.get_perm_pool().alloc(TypeGenBase.TypeGenBase.__sizeof__()) + if SubTypeGenBase is None: + stdio.printf("FAIL: TypeGenBase alloc failed\n") + stdlib.exit(1) + string.memset(SubTypeGenBase, 0, TypeGenBase.TypeGenBase.__sizeof__()) + SubTypeGenBase.Gen = self + self.TypeGenBase = SubTypeGenBase + SubTypeGen: TypeGenMixin.TypeGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(TypeGenMixin.TypeGenMixin.__sizeof__()) + if SubTypeGen is None: + stdio.printf("FAIL: TypeGenMixin alloc failed\n") + stdlib.exit(1) + string.memset(SubTypeGen, 0, TypeGenMixin.TypeGenMixin.__sizeof__()) + SubTypeGen.Gen = self + self.TypeGen = SubTypeGen + SubTypeGenCDef: TypeGenCDef.TypeGenCDef | t.CPtr = CompilerFactory.get_perm_pool().alloc(TypeGenCDef.TypeGenCDef.__sizeof__()) + if SubTypeGenCDef is None: + stdio.printf("FAIL: TypeGenCDef alloc failed\n") + stdlib.exit(1) + string.memset(SubTypeGenCDef, 0, TypeGenCDef.TypeGenCDef.__sizeof__()) + SubTypeGenCDef.Gen = self + self.TypeGenCDef = SubTypeGenCDef + SubTypeGenCType: TypeGenCType.TypeGenCType | t.CPtr = CompilerFactory.get_perm_pool().alloc(TypeGenCType.TypeGenCType.__sizeof__()) + if SubTypeGenCType is None: + stdio.printf("FAIL: TypeGenCType alloc failed\n") + stdlib.exit(1) + string.memset(SubTypeGenCType, 0, TypeGenCType.TypeGenCType.__sizeof__()) + SubTypeGenCType.Gen = self + self.TypeGenCType = SubTypeGenCType + SubTypeGenResolve: TypeGenResolve.TypeGenResolve | t.CPtr = CompilerFactory.get_perm_pool().alloc(TypeGenResolve.TypeGenResolve.__sizeof__()) + if SubTypeGenResolve is None: + stdio.printf("FAIL: TypeGenResolve alloc failed\n") + stdlib.exit(1) + string.memset(SubTypeGenResolve, 0, TypeGenResolve.TypeGenResolve.__sizeof__()) + SubTypeGenResolve.Gen = self + self.TypeGenResolve = SubTypeGenResolve + SubTypeGenErr: TypeGenErr.TypeGenErr | t.CPtr = CompilerFactory.get_perm_pool().alloc(TypeGenErr.TypeGenErr.__sizeof__()) + if SubTypeGenErr is None: + stdio.printf("FAIL: TypeGenErr alloc failed\n") + stdlib.exit(1) + string.memset(SubTypeGenErr, 0, TypeGenErr.TypeGenErr.__sizeof__()) + SubTypeGenErr.Gen = self + self.TypeGenErr = SubTypeGenErr + SubStructGen: StructGenMixin.StructGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(StructGenMixin.StructGenMixin.__sizeof__()) + if SubStructGen is None: + stdio.printf("FAIL: StructGenMixin alloc failed\n") + stdlib.exit(1) + string.memset(SubStructGen, 0, StructGenMixin.StructGenMixin.__sizeof__()) + SubStructGen.Gen = self + self.StructGen = SubStructGen + SubExprGenBase: ExprGenBase.ExprGenBase | t.CPtr = CompilerFactory.get_perm_pool().alloc(ExprGenBase.ExprGenBase.__sizeof__()) + if SubExprGenBase is None: + stdio.printf("FAIL: ExprGenBase alloc failed\n") + stdlib.exit(1) + string.memset(SubExprGenBase, 0, ExprGenBase.ExprGenBase.__sizeof__()) + SubExprGenBase.Gen = self + self.ExprGenBase = SubExprGenBase + SubExprGen: ExprGenMixin.ExprGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(ExprGenMixin.ExprGenMixin.__sizeof__()) + if SubExprGen is None: + stdio.printf("FAIL: ExprGenMixin alloc failed\n") + stdlib.exit(1) + string.memset(SubExprGen, 0, ExprGenMixin.ExprGenMixin.__sizeof__()) + SubExprGen.Gen = self + self.ExprGen = SubExprGen + SubExprGenConst: ExprGenConst.ExprGenConst | t.CPtr = CompilerFactory.get_perm_pool().alloc(ExprGenConst.ExprGenConst.__sizeof__()) + if SubExprGenConst is None: + stdio.printf("FAIL: ExprGenConst alloc failed\n") + stdlib.exit(1) + string.memset(SubExprGenConst, 0, ExprGenConst.ExprGenConst.__sizeof__()) + SubExprGenConst.Gen = self + self.ExprGenConst = SubExprGenConst + SubExprGenFstr: ExprGenFstr.ExprGenFstr | t.CPtr = CompilerFactory.get_perm_pool().alloc(ExprGenFstr.ExprGenFstr.__sizeof__()) + if SubExprGenFstr is None: + stdio.printf("FAIL: ExprGenFstr alloc failed\n") + stdlib.exit(1) + string.memset(SubExprGenFstr, 0, ExprGenFstr.ExprGenFstr.__sizeof__()) + SubExprGenFstr.Gen = self + self.ExprGenFstr = SubExprGenFstr + SubExprGenOps: ExprGenOps.ExprGenOps | t.CPtr = CompilerFactory.get_perm_pool().alloc(ExprGenOps.ExprGenOps.__sizeof__()) + if SubExprGenOps is None: + stdio.printf("FAIL: ExprGenOps alloc failed\n") + stdlib.exit(1) + string.memset(SubExprGenOps, 0, ExprGenOps.ExprGenOps.__sizeof__()) + SubExprGenOps.Gen = self + self.ExprGenOps = SubExprGenOps + SubExprGenCdef: ExprGenCdef.ExprGenCdef | t.CPtr = CompilerFactory.get_perm_pool().alloc(ExprGenCdef.ExprGenCdef.__sizeof__()) + if SubExprGenCdef is None: + stdio.printf("FAIL: ExprGenCdef alloc failed\n") + stdlib.exit(1) + string.memset(SubExprGenCdef, 0, ExprGenCdef.ExprGenCdef.__sizeof__()) + SubExprGenCdef.Gen = self + self.ExprGenCdef = SubExprGenCdef + SubExprGenName: ExprGenName.ExprGenName | t.CPtr = CompilerFactory.get_perm_pool().alloc(ExprGenName.ExprGenName.__sizeof__()) + if SubExprGenName is None: + stdio.printf("FAIL: ExprGenName alloc failed\n") + stdlib.exit(1) + string.memset(SubExprGenName, 0, ExprGenName.ExprGenName.__sizeof__()) + SubExprGenName.Gen = self + self.ExprGenName = SubExprGenName + SubExprGenAttr: ExprGenAttr.ExprGenAttr | t.CPtr = CompilerFactory.get_perm_pool().alloc(ExprGenAttr.ExprGenAttr.__sizeof__()) + if SubExprGenAttr is None: + stdio.printf("FAIL: ExprGenAttr alloc failed\n") + stdlib.exit(1) + string.memset(SubExprGenAttr, 0, ExprGenAttr.ExprGenAttr.__sizeof__()) + SubExprGenAttr.Gen = self + self.ExprGenAttr = SubExprGenAttr + SubExprGenCls: ExprGenCls.ExprGenCls | t.CPtr = CompilerFactory.get_perm_pool().alloc(ExprGenCls.ExprGenCls.__sizeof__()) + if SubExprGenCls is None: + stdio.printf("FAIL: ExprGenCls alloc failed\n") + stdlib.exit(1) + string.memset(SubExprGenCls, 0, ExprGenCls.ExprGenCls.__sizeof__()) + SubExprGenCls.Gen = self + self.ExprGenCls = SubExprGenCls + SubCallGenBase: CallGenBase.CallGenBase | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenBase.CallGenBase.__sizeof__()) + if SubCallGenBase is None: + stdio.printf("FAIL: CallGenBase alloc failed\n") + stdlib.exit(1) + string.memset(SubCallGenBase, 0, CallGenBase.CallGenBase.__sizeof__()) + SubCallGenBase.Gen = self + self.CallGenBase = SubCallGenBase + SubCallGenCBuiltin: CallGenCBuiltin.CallGenCBuiltin | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenCBuiltin.CallGenCBuiltin.__sizeof__()) + if SubCallGenCBuiltin is None: + stdio.printf("FAIL: CallGenCBuiltin alloc failed\n") + stdlib.exit(1) + string.memset(SubCallGenCBuiltin, 0, CallGenCBuiltin.CallGenCBuiltin.__sizeof__()) + SubCallGenCBuiltin.Gen = self + self.CallGenCBuiltin = SubCallGenCBuiltin + SubCallGenLeafKit: CallGenLeafKit.CallGenLeafKit | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenLeafKit.CallGenLeafKit.__sizeof__()) + if SubCallGenLeafKit is None: + stdio.printf("FAIL: CallGenLeafKit alloc failed\n") + stdlib.exit(1) + string.memset(SubCallGenLeafKit, 0, CallGenLeafKit.CallGenLeafKit.__sizeof__()) + SubCallGenLeafKit.Gen = self + self.CallGenLeafKit = SubCallGenLeafKit + SubCallGenCtor: CallGenCtor.CallGenCtor | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenCtor.CallGenCtor.__sizeof__()) + if SubCallGenCtor is None: + stdio.printf("FAIL: CallGenCtor alloc failed\n") + stdlib.exit(1) + string.memset(SubCallGenCtor, 0, CallGenCtor.CallGenCtor.__sizeof__()) + SubCallGenCtor.Gen = self + self.CallGenCtor = SubCallGenCtor + SubCallGenCall: CallGenCall.CallGenCall | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenCall.CallGenCall.__sizeof__()) + if SubCallGenCall is None: + stdio.printf("FAIL: CallGenCall alloc failed\n") + stdlib.exit(1) + string.memset(SubCallGenCall, 0, CallGenCall.CallGenCall.__sizeof__()) + SubCallGenCall.Gen = self + self.CallGenCall = SubCallGenCall + SubCallGen: CallGenMixin.CallGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenMixin.CallGenMixin.__sizeof__()) + if SubCallGen is None: + stdio.printf("FAIL: CallGenMixin alloc failed\n") + stdlib.exit(1) + string.memset(SubCallGen, 0, CallGenMixin.CallGenMixin.__sizeof__()) + SubCallGen.Gen = self + self.CallGen = SubCallGen + SubCallGenDispatch: CallGenDispatch.CallGenDispatch | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenDispatch.CallGenDispatch.__sizeof__()) + if SubCallGenDispatch is None: + stdio.printf("FAIL: CallGenDispatch alloc failed\n") + stdlib.exit(1) + string.memset(SubCallGenDispatch, 0, CallGenDispatch.CallGenDispatch.__sizeof__()) + SubCallGenDispatch.Gen = self + self.CallGenDispatch = SubCallGenDispatch + SubCallGenLib: CallGenLib.CallGenLib | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenLib.CallGenLib.__sizeof__()) + if SubCallGenLib is None: + stdio.printf("FAIL: CallGenLib alloc failed\n") + stdlib.exit(1) + string.memset(SubCallGenLib, 0, CallGenLib.CallGenLib.__sizeof__()) + SubCallGenLib.Gen = self + self.CallGenLib = SubCallGenLib + SubCallGenVt: CallGenVt.CallGenVt | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenVt.CallGenVt.__sizeof__()) + if SubCallGenVt is None: + stdio.printf("FAIL: CallGenVt alloc failed\n") + stdlib.exit(1) + string.memset(SubCallGenVt, 0, CallGenVt.CallGenVt.__sizeof__()) + SubCallGenVt.Gen = self + self.CallGenVt = SubCallGenVt + SubCallGenVa: CallGenVa.CallGenVa | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenVa.CallGenVa.__sizeof__()) + if SubCallGenVa is None: + stdio.printf("FAIL: CallGenVa alloc failed\n") + stdlib.exit(1) + string.memset(SubCallGenVa, 0, CallGenVa.CallGenVa.__sizeof__()) + SubCallGenVa.Gen = self + self.CallGenVa = SubCallGenVa + SubCallGenProp: CallGenProp.CallGenProp | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenProp.CallGenProp.__sizeof__()) + if SubCallGenProp is None: + stdio.printf("FAIL: CallGenProp alloc failed\n") + stdlib.exit(1) + string.memset(SubCallGenProp, 0, CallGenProp.CallGenProp.__sizeof__()) + SubCallGenProp.Gen = self + self.CallGenProp = SubCallGenProp + SubCallGenFd: CallGenFd.CallGenFd | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenFd.CallGenFd.__sizeof__()) + if SubCallGenFd is None: + stdio.printf("FAIL: CallGenFd alloc failed\n") + stdlib.exit(1) + string.memset(SubCallGenFd, 0, CallGenFd.CallGenFd.__sizeof__()) + SubCallGenFd.Gen = self + self.CallGenFd = SubCallGenFd + SubFuncGenBase: FuncGenBase.FuncGenBase | t.CPtr = CompilerFactory.get_perm_pool().alloc(FuncGenBase.FuncGenBase.__sizeof__()) + if SubFuncGenBase is None: + stdio.printf("FAIL: FuncGenBase alloc failed\n") + stdlib.exit(1) + string.memset(SubFuncGenBase, 0, FuncGenBase.FuncGenBase.__sizeof__()) + SubFuncGenBase.Gen = self + self.FuncGenBase = SubFuncGenBase + SubFuncGenDef: FuncGenDef.FuncGenDef | t.CPtr = CompilerFactory.get_perm_pool().alloc(FuncGenDef.FuncGenDef.__sizeof__()) + if SubFuncGenDef is None: + stdio.printf("FAIL: FuncGenDef alloc failed\n") + stdlib.exit(1) + string.memset(SubFuncGenDef, 0, FuncGenDef.FuncGenDef.__sizeof__()) + SubFuncGenDef.Gen = self + self.FuncGenDef = SubFuncGenDef + SubFuncGen: FuncGenMixin.FuncGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(FuncGenMixin.FuncGenMixin.__sizeof__()) + if SubFuncGen is None: + stdio.printf("FAIL: FuncGenMixin alloc failed\n") + stdlib.exit(1) + string.memset(SubFuncGen, 0, FuncGenMixin.FuncGenMixin.__sizeof__()) + SubFuncGen.Gen = self + self.FuncGen = SubFuncGen + SubClassGenBase: ClassGenBase.ClassGenBase | t.CPtr = CompilerFactory.get_perm_pool().alloc(ClassGenBase.ClassGenBase.__sizeof__()) + if SubClassGenBase is None: + stdio.printf("FAIL: ClassGenBase alloc failed\n") + stdlib.exit(1) + string.memset(SubClassGenBase, 0, ClassGenBase.ClassGenBase.__sizeof__()) + SubClassGenBase.Gen = self + self.ClassGenBase = SubClassGenBase + SubClassGen: ClassGenMixin.ClassGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(ClassGenMixin.ClassGenMixin.__sizeof__()) + if SubClassGen is None: + stdio.printf("FAIL: ClassGenMixin alloc failed\n") + stdlib.exit(1) + string.memset(SubClassGen, 0, ClassGenMixin.ClassGenMixin.__sizeof__()) + SubClassGen.Gen = self + self.ClassGen = SubClassGen + SubClassGenEnum: ClassGenEnum.ClassGenEnum | t.CPtr = CompilerFactory.get_perm_pool().alloc(ClassGenEnum.ClassGenEnum.__sizeof__()) + if SubClassGenEnum is None: + stdio.printf("FAIL: ClassGenEnum alloc failed\n") + stdlib.exit(1) + string.memset(SubClassGenEnum, 0, ClassGenEnum.ClassGenEnum.__sizeof__()) + SubClassGenEnum.Gen = self + self.ClassGenEnum = SubClassGenEnum + SubClassGenGeneric: ClassGenGeneric.ClassGenGeneric | t.CPtr = CompilerFactory.get_perm_pool().alloc(ClassGenGeneric.ClassGenGeneric.__sizeof__()) + if SubClassGenGeneric is None: + stdio.printf("FAIL: ClassGenGeneric alloc failed\n") + stdlib.exit(1) + string.memset(SubClassGenGeneric, 0, ClassGenGeneric.ClassGenGeneric.__sizeof__()) + SubClassGenGeneric.Gen = self + self.ClassGenGeneric = SubClassGenGeneric + SubClassGenVTable: ClassGenVTable.ClassGenVTable | t.CPtr = CompilerFactory.get_perm_pool().alloc(ClassGenVTable.ClassGenVTable.__sizeof__()) + if SubClassGenVTable is None: + stdio.printf("FAIL: ClassGenVTable alloc failed\n") + stdlib.exit(1) + string.memset(SubClassGenVTable, 0, ClassGenVTable.ClassGenVTable.__sizeof__()) + SubClassGenVTable.Gen = self + self.ClassGenVTable = SubClassGenVTable + SubClassGenDef: ClassGenDef.ClassGenDef | t.CPtr = CompilerFactory.get_perm_pool().alloc(ClassGenDef.ClassGenDef.__sizeof__()) + if SubClassGenDef is None: + stdio.printf("FAIL: ClassGenDef alloc failed\n") + stdlib.exit(1) + string.memset(SubClassGenDef, 0, ClassGenDef.ClassGenDef.__sizeof__()) + SubClassGenDef.Gen = self + self.ClassGenDef = SubClassGenDef + SubImportsGen: ImportsGenMixin.ImportsGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(ImportsGenMixin.ImportsGenMixin.__sizeof__()) + if SubImportsGen is None: + stdio.printf("FAIL: ImportsGenMixin alloc failed\n") + stdlib.exit(1) + string.memset(SubImportsGen, 0, ImportsGenMixin.ImportsGenMixin.__sizeof__()) + SubImportsGen.Gen = self + self.ImportsGen = SubImportsGen + SubStmtGenCif: StmtGenCifMixin.StmtGenCifMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(StmtGenCifMixin.StmtGenCifMixin.__sizeof__()) + if SubStmtGenCif is None: + stdio.printf("FAIL: StmtGenCifMixin alloc failed\n") + stdlib.exit(1) + string.memset(SubStmtGenCif, 0, StmtGenCifMixin.StmtGenCifMixin.__sizeof__()) + SubStmtGenCif.Gen = self + self.StmtGenCif = SubStmtGenCif + SubStmtGenDecl: StmtGenDeclMixin.StmtGenDeclMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(StmtGenDeclMixin.StmtGenDeclMixin.__sizeof__()) + if SubStmtGenDecl is None: + stdio.printf("FAIL: StmtGenDeclMixin alloc failed\n") + stdlib.exit(1) + string.memset(SubStmtGenDecl, 0, StmtGenDeclMixin.StmtGenDeclMixin.__sizeof__()) + SubStmtGenDecl.Gen = self + self.StmtGenDecl = SubStmtGenDecl + SubStmtGen: StmtGenMixin.StmtGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(StmtGenMixin.StmtGenMixin.__sizeof__()) + if SubStmtGen is None: + stdio.printf("FAIL: StmtGenMixin alloc failed\n") + stdlib.exit(1) + string.memset(SubStmtGen, 0, StmtGenMixin.StmtGenMixin.__sizeof__()) + SubStmtGen.Gen = self + self.StmtGen = SubStmtGen + SubMatchGen: MatchGenMixin.MatchGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(MatchGenMixin.MatchGenMixin.__sizeof__()) + if SubMatchGen is None: + stdio.printf("FAIL: MatchGenMixin alloc failed\n") + stdlib.exit(1) + string.memset(SubMatchGen, 0, MatchGenMixin.MatchGenMixin.__sizeof__()) + SubMatchGen.Gen = self + self.MatchGen = SubMatchGen + SubAssignGen: AssignGenMixin.AssignGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(AssignGenMixin.AssignGenMixin.__sizeof__()) + if SubAssignGen is None: + stdio.printf("FAIL: AssignGenMixin alloc failed\n") + stdlib.exit(1) + string.memset(SubAssignGen, 0, AssignGenMixin.AssignGenMixin.__sizeof__()) + SubAssignGen.Gen = self + self.AssignGen = SubAssignGen + SubVarGen: VarGenMixin.VarGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(VarGenMixin.VarGenMixin.__sizeof__()) + if SubVarGen is None: + stdio.printf("FAIL: VarGenMixin alloc failed\n") + stdlib.exit(1) + string.memset(SubVarGen, 0, VarGenMixin.VarGenMixin.__sizeof__()) + SubVarGen.Gen = self + self.VarGen = SubVarGen + SubTranslatorGen: TranslatorGenMixin.TranslatorGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(TranslatorGenMixin.TranslatorGenMixin.__sizeof__()) + if SubTranslatorGen is None: + stdio.printf("FAIL: TranslatorGenMixin alloc failed\n") + stdlib.exit(1) + string.memset(SubTranslatorGen, 0, TranslatorGenMixin.TranslatorGenMixin.__sizeof__()) + SubTranslatorGen.Gen = self + self.TranslatorGen = SubTranslatorGen + + # ---- 初始化各子对象字段(Init* 方法内联调用) ---- + SubBaseGen.InitBaseGen(pool) + SubTypeGenBase.InitTypeGen() + SubCallGenBase.InitCallGen() + SubStructGen.InitStructGen() + SubClassGenBase.InitClassGen() + SubExprGenBase.InitExprGen() + SubImportsGen.InitImportsGen() + SubStmtGenCif.InitStmtGen() + SubAssignGen.InitAssignGen() # ============================================================ -# 全局生成器单例(对象化 P2 兼容层) +# 全局生成器单例(组合架构兼容层) # ============================================================ _g_gen: Generator | t.CPtr = None diff --git a/App/lib/core/Gen/ImportsGenMixin.vp b/App/lib/core/Gen/ImportsGenMixin.vp index ed3cc58..1d4c41a 100644 --- a/App/lib/core/Gen/ImportsGenMixin.vp +++ b/App/lib/core/Gen/ImportsGenMixin.vp @@ -1,752 +1,762 @@ -import t, c -from stdint import * -import ast -import memhub -import string -import stdlib -import viperlib -import stdio -import sys -import w32.fileio as fileio -import lib.core.StubMerger as StubMerger -import lib.core.CompilerFactory as CompilerFactory -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.StubMergerStore as StubMergerStore - - -# ============================================================ -# ImportsGenMixin - 导入处理 Mixin(对象化 P6-D,wiki/14-oo-refactor.md) -# -# 从 HandlesImports.vp 迁移: -# 全局状态(_g_reexport_sha1s/_g_reexport_funcs/_g_reexport_srcs/ -# _g_reexport_count/_g_current_file)→ 本类字段 -# 模块级函数(add_imported_module/is_module_imported/...)→ 本类方法 -# -# 迁移原则(与 P1-P5 Mixin 一致,行为零变化): -# 1. 方法保留原函数签名(含 pool 首参),仅函数体内的全局变量改为 self.字段 -# 2. 本模块内部函数调用改为 self.方法;跨模块调用(StubMerger 等)保留模块前缀 -# 3. HandlesImports.vp 原函数保留为"委托":本地模块级单例 _g_gen -# (BuildPipeline/main 注入)cast 成 Generator 类型后调本类方法 -# -# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整,无 vtable 开销)。 -# ============================================================ - - -# ============================================================ -# 常量(与 HandlesImports 保持一致) -# ============================================================ -MAX_REEXPORT: t.CDefine = 512 - - -# ============================================================ -# ImportsGenMixin - 导入处理 -# ============================================================ -@t.NoVTable -class ImportsGenMixin: - """导入处理 Mixin(P6 方法化)""" - - # --- 全局 re-export 映射表(原 _g_reexport_sha1s/_g_reexport_funcs/ - # _g_reexport_srcs/_g_reexport_count) --- - ReexportSha1s: bytes - ReexportFuncs: bytes - ReexportSrcs: bytes - ReexportCount: int - - # 注意:不声明 CurrentFile 字段——TypeGenMixin 已声明(Generator 展平块 - # 只有一份,跨父类不去重规则下重复声明会导致字段错位)。本 Mixin 的 - # set_current_file 与 CurrentFile 读取统一经 HandlesType 委托(延迟 import - # 规避 HandlesType↔HandlesImports 循环依赖)。 - - # ============================================================ - # 添加已导入模块名 - # ============================================================ - def add_imported_module(self, pool: memhub.MemBuddy | t.CPtr, - imported_modules: str, - name: str) -> str: - """记录已导入的模块名,返回新的 imported_modules 字符串指针""" - if name is None: - return imported_modules - if imported_modules is None: - nlen: t.CSizeT = string.strlen(name) - buf: str = pool.alloc(nlen + 1) - if buf is not None: - string.strcpy(buf, name) - return buf - return None - else: - old_len: t.CSizeT = string.strlen(imported_modules) - name_len: t.CSizeT = string.strlen(name) - new_len: t.CSizeT = old_len + 1 + name_len - buf2: str = pool.alloc(new_len + 1) - if buf2 is not None: - string.strcpy(buf2, imported_modules) - buf2[old_len] = ' ' - string.strcpy(buf2 + old_len + 1, name) - return buf2 - return imported_modules - - # ============================================================ - # 检查模块是否已导入 - # ============================================================ - def is_module_imported(self, imported_modules: str, name: str) -> int: - """检查模块是否已导入(词边界精确匹配,避免子串误匹配)""" - if name is None or imported_modules is None: - return 0 - name_len: t.CSizeT = string.strlen(name) - cur: str = imported_modules - total_len: t.CSizeT = string.strlen(imported_modules) - ci: t.CSizeT = 0 - while ci < total_len: - while ci < total_len and cur[ci] == ' ': - ci += 1 - if ci >= total_len: - break - word_start: t.CSizeT = ci - while ci < total_len and cur[ci] != ' ': - ci += 1 - word_len: t.CSizeT = ci - word_start - if word_len == name_len: - match: int = 1 - for ei in range(name_len): - if cur[word_start + ei] != name[ei]: - match = 0 - break - if match == 1: - return 1 - return 0 - - # ============================================================ - # 添加 from-import 名称映射 - # ============================================================ - def add_from_import(self, pool: memhub.MemBuddy | t.CPtr, - from_imports: str, - local_name: str, - module_name: str, - original_name: str = None) -> str: - """添加 from-import 映射,返回新的 from_imports 字符串 - - 格式: - 无别名: "local_name:module_name" - 有别名: "local_name:module_name:original_name" - (original_name 为源模块中的真实函数名,用于跨模块 SHA1 修饰) - """ - if local_name is None or module_name is None: - return from_imports - entry: str = pool.alloc(256) - if entry is None: - return from_imports - if original_name is not None and string.strcmp(original_name, local_name) != 0: - viperlib.snprintf(entry, 256, "%s:%s:%s", local_name, module_name, original_name) - else: - viperlib.snprintf(entry, 256, "%s:%s", local_name, module_name) - if from_imports is None: - return entry - else: - old_len: t.CSizeT = string.strlen(from_imports) - entry_len: t.CSizeT = string.strlen(entry) - new_len: t.CSizeT = old_len + 1 + entry_len - buf: str = pool.alloc(new_len + 1) - if buf is not None: - string.strcpy(buf, from_imports) - buf[old_len] = ' ' - string.strcpy(buf + old_len + 1, entry) - return buf - return from_imports - - # ============================================================ - # 查找 from-import 名称 → 返回原始函数名(别名场景) - # - # 对于 from X import Y as Z,返回 Y(源模块中的真实函数名)。 - # 无别名时返回 None(local_name 即为原始名)。 - # ============================================================ - def lookup_from_import_original(self, from_imports: str, - local_name: str) -> str: - """查找 from-import 别名对应的原始函数名,返回 None=无别名或未找到""" - if local_name is None or from_imports is None: - return None - name_len: t.CSizeT = string.strlen(local_name) - cur: str = from_imports - ci: t.CSizeT = 0 - total_len: t.CSizeT = string.strlen(from_imports) - while ci < total_len: - # 跳过前导空格 - while ci < total_len and cur[ci] == ' ': - ci += 1 - if ci >= total_len: - break - # 找到第一个 ':' 的位置 - colon1: t.CSizeT = ci - while colon1 < total_len and cur[colon1] != ':' and cur[colon1] != ' ': - colon1 += 1 - if colon1 >= total_len or cur[colon1] != ':': - break - entry_name_len: t.CSizeT = colon1 - ci - # 跳过 star import - if entry_name_len == 1 and cur[ci] == '*': - ci = colon1 - while ci < total_len and cur[ci] != ' ': - ci += 1 - continue - # 比较名称 - if entry_name_len == name_len: - match: int = 1 - ei: t.CSizeT = 0 - while ei < name_len: - if cur[ci + ei] != local_name[ei]: - match = 0 - break - ei += 1 - if match == 1: - # 找到匹配,检查是否有第三个字段(原始名) - pos: t.CSizeT = colon1 + 1 - # 跳过模块名 - while pos < total_len and cur[pos] != ':' and cur[pos] != ' ' and cur[pos] != '\0': - pos += 1 - if pos < total_len and cur[pos] == ':': - # 有第三个字段: original_name - orig_start: t.CSizeT = pos + 1 - orig_end: t.CSizeT = orig_start - while orig_end < total_len and cur[orig_end] != ' ' and cur[orig_end] != '\0': - orig_end += 1 - orig_len: t.CSizeT = orig_end - orig_start - if orig_len > 0: - orig_buf: str = cur + orig_start - # 返回指向内部的指针(调用方需在使用期内保持 from_imports 有效) - return orig_buf - return None - return None - # 跳到下一个条目 - ci = colon1 - while ci < total_len and cur[ci] != ' ': - ci += 1 - return None - - # ============================================================ - # 查找 from-import 名称 → 返回模块名或 None - # - # allow_star_fallback: 是否允许 star import 回退(默认 1=允许)。 - # 当查询明确模块名(如 "BuildPipeline")时,应传 0 禁用回退, - # 避免被 star import 模块名误导(如 from stdint import * 后 - # 查询 "BuildPipeline" 错误回退到 "stdint")。 - # ============================================================ - def lookup_from_import(self, from_imports: str, name: str, - allow_star_fallback: int = 1) -> str: - """查找 from-import 名称,返回模块名或 None - - 支持 star import: 如果 from_imports 中有 "*:module" 条目, - 且未找到精确名称匹配,且 allow_star_fallback != 0,则返回 star import 的模块名。 - """ - if name is None or from_imports is None: - return None - name_len: t.CSizeT = string.strlen(name) - cur: str = from_imports - ci: t.CSizeT = 0 - total_len: t.CSizeT = string.strlen(from_imports) - star_mod: str = None - while ci < total_len: - # 跳过前导空格 - while ci < total_len and cur[ci] == ' ': - ci += 1 - if ci >= total_len: - break - # 找到 ':' 的位置 - colon_pos: t.CSizeT = ci - while colon_pos < total_len and cur[colon_pos] != ':' and cur[colon_pos] != ' ': - colon_pos += 1 - if colon_pos >= total_len or cur[colon_pos] != ':': - break - entry_name_len: t.CSizeT = colon_pos - ci - # 检测 star import ("*:module") - if entry_name_len == 1 and cur[ci] == '*': - mod_start: t.CSizeT = colon_pos + 1 - mod_end: t.CSizeT = mod_start - while mod_end < total_len and cur[mod_end] != ' ' and cur[mod_end] != '\0' and cur[mod_end] != ':': - mod_end += 1 - star_mod = cur + mod_start - # 比较名称 - elif entry_name_len == name_len: - match: int = 1 - ei: t.CSizeT = 0 - while ei < name_len: - if cur[ci + ei] != name[ei]: - match = 0 - break - ei += 1 - if match == 1: - mod_start2: t.CSizeT = colon_pos + 1 - mod_end2: t.CSizeT = mod_start2 - # 模块名结束于: 空格、null、或第二个':'(别名格式的分隔符) - while mod_end2 < total_len and cur[mod_end2] != ' ' and cur[mod_end2] != '\0' and cur[mod_end2] != ':': - mod_end2 += 1 - return cur + mod_start2 - # 跳到下一个条目 - ci = colon_pos - while ci < total_len and cur[ci] != ' ': - ci += 1 - # 未找到精确匹配,仅在允许时回退到 star import - if allow_star_fallback == 0: - return None - return star_mod - - # ============================================================ - # register_reexport - 注册 re-export 映射 - # - # 在 HandleImportFromNames 中调用:当处理 from .X import Y 时, - # 记录当前模块(通过 ModuleSha1)re-export 了函数 Y,源模块为 X。 - # - # 幂等:重复注册相同映射不会增加条目。 - # 内存用 stdlib.malloc 分配(全局存储器,跨 Phase 持久化)。 - # ============================================================ - def register_reexport(self, mod_sha1: str, func_name: str, source_module: str) -> int: - """注册 re-export 映射(幂等),返回 0 成功,-1 失败""" - if mod_sha1 is None or func_name is None or source_module is None: - return -1 - # 懒初始化 - if self.ReexportSha1s is None: - self.ReexportSha1s = CompilerFactory.get_perm_pool().alloc(MAX_REEXPORT * 17) - self.ReexportFuncs = CompilerFactory.get_perm_pool().alloc(MAX_REEXPORT * 64) - self.ReexportSrcs = CompilerFactory.get_perm_pool().alloc(MAX_REEXPORT * 64) - if self.ReexportSha1s is None or self.ReexportFuncs is None or self.ReexportSrcs is None: - return -1 - string.memset(self.ReexportSha1s, 0, MAX_REEXPORT * 17) - string.memset(self.ReexportFuncs, 0, MAX_REEXPORT * 64) - string.memset(self.ReexportSrcs, 0, MAX_REEXPORT * 64) - if self.ReexportCount >= MAX_REEXPORT: - return -1 - # 幂等检查:查找是否已存在相同映射 - for i in range(self.ReexportCount): - sidx: t.CSizeT = t.CSizeT(i) * 17 - fidx: t.CSizeT = t.CSizeT(i) * 64 - if string.strcmp(self.ReexportSha1s + sidx, mod_sha1) == 0: - if string.strcmp(self.ReexportFuncs + fidx, func_name) == 0: - # 已存在,更新 source_module(以防变化;64 字节槽,strncpy 钳制) - string.strncpy(self.ReexportSrcs + fidx, source_module, 63) - self.ReexportSrcs[fidx + 63] = '\0' - return 0 - # 添加新条目(槽位定长 17/64 字节,strcpy 无界会越界写相邻槽,全部 strncpy 钳制) - idx2: t.CSizeT = t.CSizeT(self.ReexportCount) * 17 - fidx2: t.CSizeT = t.CSizeT(self.ReexportCount) * 64 - string.strncpy(self.ReexportSha1s + idx2, mod_sha1, 16) - self.ReexportSha1s[idx2 + 16] = '\0' - string.strncpy(self.ReexportFuncs + fidx2, func_name, 63) - self.ReexportFuncs[fidx2 + 63] = '\0' - string.strncpy(self.ReexportSrcs + fidx2, source_module, 63) - self.ReexportSrcs[fidx2 + 63] = '\0' - self.ReexportCount += 1 - return 0 - - # ============================================================ - # lookup_reexport - 查找 re-export 映射 - # - # 给定模块 SHA1 和函数名,返回源模块名(如 "ast.lexer")或 None。 - # 调用方通过 _lookup_module_sha1(source_module) 获取源模块的 SHA1。 - # ============================================================ - def lookup_reexport(self, mod_sha1: str, func_name: str) -> str: - """查找 re-export 映射,返回源模块名或 None""" - if mod_sha1 is None or func_name is None: - return None - if self.ReexportSha1s is None or self.ReexportCount <= 0: - return None - for i in range(self.ReexportCount): - sidx: t.CSizeT = t.CSizeT(i) * 17 - fidx: t.CSizeT = t.CSizeT(i) * 64 - if string.strcmp(self.ReexportSha1s + sidx, mod_sha1) == 0: - if string.strcmp(self.ReexportFuncs + fidx, func_name) == 0: - return self.ReexportSrcs + fidx - return None - - # ============================================================ - # _resolve_relative_module - 解析相对导入为完整模块名 - # - # 对于 from .X import Y(level=1, module="X")在包 pkg 中: - # 解析为 "pkg.X" - # 对于 from . import Y(level=1, module=None)在包 pkg 中: - # 解析为 "pkg" - # 对于 from ..X import Y(level=2, module="X")在包 pkg.sub 中: - # 解析为 "pkg.X"(先从 pkg.sub 上溯一级到 pkg,再追加 .X) - # - # Args: - # pool: 内存池 - # current_package: 当前文件所属包名(如 "llvmlite"),None 表示无包 - # level: 相对导入级别(0=绝对,1=., 2=..) - # module: ImportFrom 的 module 字段(可能为 None) - # - # Returns: - # 解析后的完整模块名;绝对导入(level<=0)直接返回 module; - # 无法解析时返回 module(回退到原始值) - # ============================================================ - def _resolve_relative_module(self, pool: memhub.MemBuddy | t.CPtr, - current_package: str, - level: t.CInt, - module: str) -> str: - """解析相对导入为完整模块名""" - if level <= 0: - return module - if current_package is None: - # 无包上下文(includes 顶级文件 / App 顶层文件): - # `from .X import Y` 的语义 = "同目录/根目录的 X 模块" - # (如 includes/viperstring.vp 的 `from .string import *`)。 - # 直接返回 module 是正确解析,不是降级——禁止 fail-fast。 - return module - - # 从 current_package 开始,上溯 (level-1) 级 - pkg: str = current_package - up: t.CInt = level - 1 - while up > 0: - pkg_len: t.CSizeT = string.strlen(pkg) - last_dot: t.CSizeT = 0 - found: int = 0 - i: t.CSizeT = 0 - while i < pkg_len: - if pkg[i] == '.': - last_dot = i - found = 1 - i += 1 - if found == 0: - # 无更多父级(相对导入级别超过包深度,上溯到根目录): - # 回退到 module 原始值(根目录模块语义),后续查找失败 - # 由 import SHA1 检查明确报"模块未找到",此处不误杀。 - pkg = None - break - # 截断到最后一个 '.' 处 - new_pkg: str = pool.alloc(last_dot + 1) - if new_pkg is None: - HandlesType.fatal_error(None, f"相对导入解析失败:level={level} module='{module}'", "ImportError") - return module - string.strncpy(new_pkg, pkg, last_dot) - new_pkg[last_dot] = '\0' - pkg = new_pkg - up -= 1 - - if module is None: - # from . import Y → 模块就是包本身 - return pkg - if pkg is None: - # 包已上溯到空(相对导入越界):回退到 module 原始值 - return module - # 拼接 pkg + "." + module - pkg_len2: t.CSizeT = string.strlen(pkg) - mod_len: t.CSizeT = string.strlen(module) - buf: str = pool.alloc(pkg_len2 + 1 + mod_len + 1) - if buf is None: - HandlesType.fatal_error(None, f"相对导入解析失败:level={level} module='{module}'", "ImportError") - return module - string.strcpy(buf, pkg) - buf[pkg_len2] = '.' - string.strcpy(buf + pkg_len2 + 1, module) - return buf - - # ============================================================ - # compute_package_from_relpath - 从相对路径计算包名 - # - # 包名 = 文件所在目录路径,将 / 和 \ 替换为 . - # 对于顶级文件(无目录分隔符),返回 None - # - # 示例: - # "llvmlite/__init__.vp" → "llvmlite" - # "llvmlite/__types.vp" → "llvmlite" - # "ast/parser.vp" → "ast" - # "ast.vp" → None(顶级文件) - # ============================================================ - def compute_package_from_relpath(self, pool: memhub.MemBuddy | t.CPtr, - rel_path: str) -> str: - """从相对路径计算包名(目录部分,分隔符替换为 .)""" - if rel_path is None: - return None - rlen: t.CSizeT = string.strlen(rel_path) - # 找最后一个 / 或 \ - last_sep: t.CSizeT = 0 - found: int = 0 - i: t.CSizeT = 0 - while i < rlen: - ch: t.CChar = rel_path[i] - if ch == '/' or ch == '\\': - last_sep = i - found = 1 - i += 1 - if found == 0: - # 无目录分隔符 → 顶级文件,无包 - return None - # 复制目录部分,将 / 和 \ 替换为 . - dir_len: t.CSizeT = last_sep - buf: str = pool.alloc(dir_len + 1) - if buf is None: - return None - j: t.CSizeT = 0 - while j < dir_len: - ch2: t.CChar = rel_path[j] - if ch2 == '/' or ch2 == '\\': - buf[j] = '.' - else: - buf[j] = ch2 - j += 1 - buf[dir_len] = '\0' - return buf - - # ============================================================ - # set_current_file - 设置当前编译的文件名 - # - # 与 TypeGenMixin.set_current_file 行为一致(写 CurrentFile 字段), - # BuildPipeline/Phase1 通过 HandlesImports.set_current_file 委托调用。 - # 经 HandlesType 委托(延迟 import 规避循环依赖),字段由 TypeGenMixin 持有。 - # ============================================================ - def set_current_file(self, file_path: str) -> None: - """设置当前正在编译的文件名(与 HandlesType.set_current_file 同步调用)""" - import lib.core.Handles.HandlesType as HandlesType - HandlesType.set_current_file(file_path) - - # ============================================================ - # _report_import_error - 本地实现 Python 风格报错(避免循环依赖) - # - # 无法访问 HandlesType.fatal_error(HandlesType import 了本模块, - # 若本模块再 import HandlesType 会形成循环依赖),这里用简化格式: - # Traceback (most recent call last): - # File "<当前文件>", line - # ImportError: - # ============================================================ - def _report_import_error(self, node: ast.AST | t.CPtr, msg: str) -> None: - """以 Python 风格报错并退出(本地实现,避免循环依赖)""" - import lib.core.Handles.HandlesType as HandlesType - stdio.printf("Traceback (most recent call last):\n") - lineno: int = 0 - if node is not None: - lineno = node.lineno - file_name: str = HandlesType.get_current_file() - if file_name is None: - file_name = "" - stdio.printf(' File "%s", line %d\n', file_name, lineno) - # 显示行内内容(读源文件第 lineno 行的实际代码,便于快速定位) - if lineno > 0 and file_name is not None: - f_err: fileio.File | t.CPtr = fileio.File(file_name, fileio.MODE.R) - if not f_err.closed: - line_buf_err: bytes = stdlib.malloc(512) - if line_buf_err is not None: - cur_ln: int = 0 - while cur_ln < lineno: - r_err: LONG = f_err.readline(line_buf_err, 511) - if r_err <= 0: - break - cur_ln += 1 - if cur_ln == lineno: - ll_err: t.CSizeT = string.strlen(line_buf_err) - while ll_err > 0 and (line_buf_err[ll_err - 1] == '\n' or line_buf_err[ll_err - 1] == '\r'): - ll_err -= 1 - line_buf_err[ll_err] = '\0' - stdio.printf(" %s\n", line_buf_err) - break - stdlib.free(line_buf_err) - f_err.close() - stdio.printf("ImportError: %s\n", msg) - sys.exit(1) - - # ============================================================ - # _is_local_module_file - 当前文件同目录存在 {mod_name}.vp/.py - # - # 多文件项目(如 Test/G4/App 的 caller1.vp import g4node)的兄弟模块 - # 不在 includes 扫描存储器中(SHA1 在项目源文件列表),检查应豁免。 - # ============================================================ - def _is_local_module_file(self, mod_name: str) -> int: - """当前文件同目录存在 {mod_name}.vp/.py → 项目内兄弟模块""" - import lib.core.Handles.HandlesType as HandlesType - cur: str = HandlesType.get_current_file() - if cur is None or mod_name is None: - return 0 - cur_len: t.CSizeT = string.strlen(cur) - if cur_len == 0: - return 0 - sep_pos: t.CSizeT = cur_len - while sep_pos > 0: - sep_pos -= 1 - ch: t.CChar = cur[sep_pos] - if ch == '/' or ch == '\\': - sep_pos += 1 - break - mod_len: t.CSizeT = string.strlen(mod_name) - path_len: t.CSizeT = sep_pos + mod_len + 5 - path_buf: bytes = stdlib.malloc(path_len + 1) - if path_buf is None: - return 0 - # .vp 文件 - string.strncpy(path_buf, cur, sep_pos) - path_buf[sep_pos] = '\0' - string.strcat(path_buf, mod_name) - string.strcat(path_buf, ".vp") - fex: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R) - if not fex.closed: - fex.close() - stdlib.free(path_buf) - return 1 - # .py 文件(Python 模块可能无 .vp) - string.strncpy(path_buf, cur, sep_pos) - path_buf[sep_pos] = '\0' - string.strcat(path_buf, mod_name) - string.strcat(path_buf, ".py") - fex2: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R) - if not fex2.closed: - fex2.close() - stdlib.free(path_buf) - return 1 - stdlib.free(path_buf) - return 0 - - # ============================================================ - # _check_import_sha1 - 导入时校验模块 SHA1 是否已注册(fast-fail) - # - # 背景:若 includes 路径配置错误(如 project.json 指向不存在的 - # ./includes),includes 扫描结果为 0,模块不会注册 SHA1。此前 - # 错误延迟到实际调用 module.func() 时才报误导性的 - # "跨模块调用 'bd.alloc' 找不到模块 SHA1"。 - # 现在在 import 语句处立即检测并报错,快速定位配置问题。 - # - # t/c 是内部库,不参与 includes 扫描,豁免检查。 - # ============================================================ - def _check_import_sha1(self, node: ast.AST | t.CPtr, mod_name: str) -> int: - """导入时校验模块 SHA1 是否已注册,未注册则立即报错退出 - - Args: - node: Import/ImportFrom AST 节点(提供行号) - mod_name: 导入的模块名(如 "memhub"、"w32.fileio") - - Returns: - 1=检查通过;模块未注册时直接报错退出(不会返回 0) - """ - if mod_name is None: - return 1 - # t/c 是内部库,不参与 includes 扫描,豁免检查 - # ctraits 是纯编译期宏库(.vpi 后缀,IncludesScanner 不扫描 .vpi),豁免检查 - if string.strcmp(mod_name, "t") == 0 or string.strcmp(mod_name, "c") == 0 or string.strcmp(mod_name, "ctraits") == 0: - return 1 - mod_sha1: str = StubMergerStore.LookupSha1ByModName(mod_name) - if mod_sha1 is None: - # App 兄弟模块豁免:当前文件同目录存在 {mod_name}.vp/.py - # (如 Test/G4/App/caller1.vp import g4node——同项目源文件, - # SHA1 在项目文件列表而非 includes 扫描存储器,不应报错) - if self._is_local_module_file(mod_name) != 0: - return 1 - err_buf: str = stdlib.malloc(256) - if err_buf is not None: - viperlib.snprintf(err_buf, 256, - "模块 '%s' 未注册 SHA1(includes 扫描未找到该模块,请检查 project.json 的 includes 路径配置)", - mod_name) - self._report_import_error(node, err_buf) - else: - self._report_import_error(node, "导入模块 SHA1 未注册(includes 扫描未找到该模块)") - return 1 - - # ============================================================ - # translate_import - 处理 import 语句,更新 trans._imported_modules - # (迁移自 HandlesImports.ImportsHandle.HandleImport) - # ============================================================ - def translate_import(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """处理 import 语句,返回 0""" - imp: ast.Import | t.CPtr = (ast.Import | t.CPtr)(node) - if imp is None: - return 0 - names: list[ast.AST | t.CPtr] | t.CPtr = imp.names - if names is None: - return 0 - nn: t.CSizeT = len(names) - for ni in range(nn): - alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni)) - if alias is not None and alias.name is not None: - # 导入时立即校验模块 SHA1 是否注册(fast-fail,仅全量翻译时检查) - # declare_only=1/2 是 struct 预注册/import 扫描阶段:此时 SHA1 表 - # 尚未包含后续才追加的模块(如 App 源文件),检查会造成误报 - if trans._declare_only == 0: - self._check_import_sha1(node, alias.name) - pool_val: memhub.MemBuddy | t.CPtr = trans.Pool - im_val: str = trans._imported_modules - trans._imported_modules = self.add_imported_module( - pool_val, im_val, alias.name) - # 别名也加入导入模块列表(用于模块限定构造器检查 Module.Class()) - if alias.asname is not None: - trans._imported_modules = self.add_imported_module( - pool_val, trans._imported_modules, alias.asname) - # 别名也加入 from_imports(asname:fullname), - # 使 HT.func() 跨模块调用能通过 from_imports 查找别名→完整模块名→SHA1 - # 否则 _lookup_module_sha1("HT") 找不到(mod_arr 只存文件名 HandlesTranslator) - trans._from_imports = self.add_from_import( - pool_val, trans._from_imports, alias.asname, alias.name) - else: - # 无别名时(import a.b.c),将顶层包名 "a" 也加入 _imported_modules, - # 使 a.b.c 作为属性访问的 base 被翻译时能通过 is_module_imported("a") 检查 - dot_ptr: str = string.strstr(alias.name, '.') - if dot_ptr is not None: - pkg_len: t.CSizeT = t.CSizeT(t.CUInt64T(dot_ptr) - t.CUInt64T(alias.name)) - if pkg_len > 0 and pkg_len < 256: - pkg_buf: bytes = pool_val.alloc(pkg_len + 1) - if pkg_buf is not None: - string.strncpy(pkg_buf, alias.name, pkg_len) - pkg_buf[pkg_len] = '\0' - trans._imported_modules = self.add_imported_module( - pool_val, trans._imported_modules, pkg_buf) - return 0 - - # ============================================================ - # translate_import_from_module - 处理 from X import Y 的模块部分 - # (迁移自 HandlesImports.ImportsHandle.HandleImportFromModule) - # - # 对相对导入(level > 0),使用 trans.CurrentPackage 解析为 - # 完整模块名(如 __types → llvmlite.__types),确保 .deps.txt - # 记录的模块名与 SHA1 映射表一致。 - # ============================================================ - def translate_import_from_module(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """处理 from X import Y 的模块部分,更新 trans._imported_modules""" - impf: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(node) - if impf is None: - return 0 - # 解析模块名:相对导入需补充包前缀 - resolved: str = self._resolve_relative_module( - trans.Pool, trans.CurrentPackage, - impf.level, impf.module) - if resolved is not None: - # 导入时立即校验模块 SHA1 是否注册(fast-fail,仅全量翻译时检查) - if trans._declare_only == 0: - self._check_import_sha1(node, resolved) - trans._imported_modules = self.add_imported_module( - trans.Pool, trans._imported_modules, resolved) - return 0 - - # ============================================================ - # translate_import_from_names - 处理 from X import Y 的名称部分 - # (迁移自 HandlesImports.ImportsHandle.HandleImportFromNames) - # - # 同样使用解析后的完整模块名,确保 from-import 映射 - # (如 LLVMType:llvmlite.__types)能正确查到 SHA1。 - # ============================================================ - def translate_import_from_names(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """处理 from X import Y 的名称部分,更新 trans._from_imports""" - impf: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(node) - if impf is None: - return 0 - # 解析模块名:相对导入需补充包前缀 - resolved: str = self._resolve_relative_module( - trans.Pool, trans.CurrentPackage, - impf.level, impf.module) - if resolved is not None: - names: list[ast.AST | t.CPtr] | t.CPtr = impf.names - if names is not None: - nn: t.CSizeT = len(names) - for ni in range(nn): - alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni)) - if alias is not None and alias.name is not None: - local_name: str = alias.name - orig_name: str = None - if alias.asname is not None: - local_name = alias.asname - orig_name = alias.name - trans._from_imports = self.add_from_import( - trans.Pool, trans._from_imports, - local_name, resolved, orig_name) - # 命名空间隔离:from-import 的名称标记为可见结构体 - HandlesStruct.add_visible_struct(trans.Pool, local_name) - # 注册 re-export 映射:当前模块 re-export 了 local_name,源模块为 resolved - # 使跨模块调用 module.func() 能解析到正确的源模块 SHA1 - if trans.ModuleSha1 is not None: - self.register_reexport(trans.ModuleSha1, local_name, resolved) - return 0 +import lib.core.Gen.Generator as Generator +import t, c +from stdint import * +import ast +import memhub +import string +import stdlib +import viperlib +import stdio +import sys +import w32.fileio as fileio +import lib.core.StubMerger as StubMerger +import lib.core.CompilerFactory as CompilerFactory +import lib.core.Handles.HandlesTranslator as HT +import lib.core.StubMergerStore as StubMergerStore + + +# ============================================================ +# ImportsGenMixin - 导入处理 Mixin(对象化 P6-D,wiki/14-oo-refactor.md) +# +# 从 HandlesImports.vp 迁移: +# 全局状态(_g_reexport_sha1s/_g_reexport_funcs/_g_reexport_srcs/ +# _g_reexport_count/_g_current_file)→ 本类字段 +# 模块级函数(add_imported_module/is_module_imported/...)→ 本类方法 +# +# 迁移原则(与 P1-P5 Mixin 一致,行为零变化): +# 1. 方法保留原函数签名(含 pool 首参),仅函数体内的全局变量改为 self.字段 +# 2. 本模块内部函数调用改为 self.方法;跨模块调用(StubMerger 等)保留模块前缀 +# 3. HandlesImports.vp 原函数保留为"委托":本地模块级单例 _g_gen +# (BuildPipeline/main 注入)cast 成 Generator 类型后调本类方法 +# +# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整,无 vtable 开销)。 +# ============================================================ + + +# ============================================================ +# 常量(与 HandlesImports 保持一致) +# ============================================================ +MAX_REEXPORT: t.CDefine = 512 + + +# ============================================================ +# ImportsGenMixin - 导入处理 +# ============================================================ +@t.NoVTable +class ImportsGenMixin: + """导入处理 Mixin(P6 方法化)""" + + # --- 全局 re-export 映射表(原 _g_reexport_sha1s/_g_reexport_funcs/ + # _g_reexport_srcs/_g_reexport_count) --- + Gen: Generator.Generator | t.CPtr + ReexportSha1s: bytes + ReexportFuncs: bytes + ReexportSrcs: bytes + ReexportCount: int + + # 注意:不声明 CurrentFile 字段——TypeGenMixin 已声明(Generator 展平块 + # 只有一份,跨父类不去重规则下重复声明会导致字段错位)。本 Mixin 的 + # set_current_file 与 CurrentFile 读取统一经 HandlesType 委托(延迟 import + # 规避 HandlesType↔HandlesImports 循环依赖)。 + + # ============================================================ + # 添加已导入模块名 + # ============================================================ + def add_imported_module(self, pool: memhub.MemBuddy | t.CPtr, + imported_modules: str, + name: str) -> str: + """记录已导入的模块名,返回新的 imported_modules 字符串指针""" + if name is None: + return imported_modules + if imported_modules is None: + nlen: t.CSizeT = string.strlen(name) + buf: str = pool.alloc(nlen + 1) + if buf is not None: + string.strcpy(buf, name) + return buf + return None + else: + old_len: t.CSizeT = string.strlen(imported_modules) + name_len: t.CSizeT = string.strlen(name) + new_len: t.CSizeT = old_len + 1 + name_len + buf2: str = pool.alloc(new_len + 1) + if buf2 is not None: + string.strcpy(buf2, imported_modules) + buf2[old_len] = ' ' + string.strcpy(buf2 + old_len + 1, name) + return buf2 + return imported_modules + + # ============================================================ + # 检查模块是否已导入 + # ============================================================ + def is_module_imported(self, imported_modules: str, name: str) -> int: + """检查模块是否已导入(词边界精确匹配,避免子串误匹配)""" + if name is None or imported_modules is None: + return 0 + name_len: t.CSizeT = string.strlen(name) + cur: str = imported_modules + total_len: t.CSizeT = string.strlen(imported_modules) + ci: t.CSizeT = 0 + while ci < total_len: + while ci < total_len and cur[ci] == ' ': + ci += 1 + if ci >= total_len: + break + word_start: t.CSizeT = ci + while ci < total_len and cur[ci] != ' ': + ci += 1 + word_len: t.CSizeT = ci - word_start + if word_len == name_len: + match: int = 1 + for ei in range(name_len): + if cur[word_start + ei] != name[ei]: + match = 0 + break + if match == 1: + return 1 + return 0 + + # ============================================================ + # 添加 from-import 名称映射 + # ============================================================ + def add_from_import(self, pool: memhub.MemBuddy | t.CPtr, + from_imports: str, + local_name: str, + module_name: str, + original_name: str = None) -> str: + """添加 from-import 映射,返回新的 from_imports 字符串 + + 格式: + 无别名: "local_name:module_name" + 有别名: "local_name:module_name:original_name" + (original_name 为源模块中的真实函数名,用于跨模块 SHA1 修饰) + """ + if local_name is None or module_name is None: + return from_imports + entry: str = pool.alloc(256) + if entry is None: + return from_imports + if original_name is not None and string.strcmp(original_name, local_name) != 0: + viperlib.snprintf(entry, 256, "%s:%s:%s", local_name, module_name, original_name) + else: + viperlib.snprintf(entry, 256, "%s:%s", local_name, module_name) + if from_imports is None: + return entry + else: + old_len: t.CSizeT = string.strlen(from_imports) + entry_len: t.CSizeT = string.strlen(entry) + new_len: t.CSizeT = old_len + 1 + entry_len + buf: str = pool.alloc(new_len + 1) + if buf is not None: + string.strcpy(buf, from_imports) + buf[old_len] = ' ' + string.strcpy(buf + old_len + 1, entry) + return buf + return from_imports + + # ============================================================ + # 查找 from-import 名称 → 返回原始函数名(别名场景) + # + # 对于 from X import Y as Z,返回 Y(源模块中的真实函数名)。 + # 无别名时返回 None(local_name 即为原始名)。 + # ============================================================ + def lookup_from_import_original(self, from_imports: str, + local_name: str) -> str: + """查找 from-import 别名对应的原始函数名,返回 None=无别名或未找到""" + if local_name is None or from_imports is None: + return None + name_len: t.CSizeT = string.strlen(local_name) + cur: str = from_imports + ci: t.CSizeT = 0 + total_len: t.CSizeT = string.strlen(from_imports) + while ci < total_len: + # 跳过前导空格 + while ci < total_len and cur[ci] == ' ': + ci += 1 + if ci >= total_len: + break + # 找到第一个 ':' 的位置 + colon1: t.CSizeT = ci + while colon1 < total_len and cur[colon1] != ':' and cur[colon1] != ' ': + colon1 += 1 + if colon1 >= total_len or cur[colon1] != ':': + break + entry_name_len: t.CSizeT = colon1 - ci + # 跳过 star import + if entry_name_len == 1 and cur[ci] == '*': + ci = colon1 + while ci < total_len and cur[ci] != ' ': + ci += 1 + continue + # 比较名称 + if entry_name_len == name_len: + match: int = 1 + ei: t.CSizeT = 0 + while ei < name_len: + if cur[ci + ei] != local_name[ei]: + match = 0 + break + ei += 1 + if match == 1: + # 找到匹配,检查是否有第三个字段(原始名) + pos: t.CSizeT = colon1 + 1 + # 跳过模块名 + while pos < total_len and cur[pos] != ':' and cur[pos] != ' ' and cur[pos] != '\0': + pos += 1 + if pos < total_len and cur[pos] == ':': + # 有第三个字段: original_name + orig_start: t.CSizeT = pos + 1 + orig_end: t.CSizeT = orig_start + while orig_end < total_len and cur[orig_end] != ' ' and cur[orig_end] != '\0': + orig_end += 1 + orig_len: t.CSizeT = orig_end - orig_start + if orig_len > 0: + orig_buf: str = cur + orig_start + # 返回指向内部的指针(调用方需在使用期内保持 from_imports 有效) + return orig_buf + return None + return None + # 跳到下一个条目 + ci = colon1 + while ci < total_len and cur[ci] != ' ': + ci += 1 + return None + + # ============================================================ + # 查找 from-import 名称 → 返回模块名或 None + # + # allow_star_fallback: 是否允许 star import 回退(默认 1=允许)。 + # 当查询明确模块名(如 "BuildPipeline")时,应传 0 禁用回退, + # 避免被 star import 模块名误导(如 from stdint import * 后 + # 查询 "BuildPipeline" 错误回退到 "stdint")。 + # ============================================================ + def lookup_from_import(self, from_imports: str, name: str, + allow_star_fallback: int = 1) -> str: + """查找 from-import 名称,返回模块名或 None + + 支持 star import: 如果 from_imports 中有 "*:module" 条目, + 且未找到精确名称匹配,且 allow_star_fallback != 0,则返回 star import 的模块名。 + """ + if name is None or from_imports is None: + return None + name_len: t.CSizeT = string.strlen(name) + cur: str = from_imports + ci: t.CSizeT = 0 + total_len: t.CSizeT = string.strlen(from_imports) + star_mod: str = None + while ci < total_len: + # 跳过前导空格 + while ci < total_len and cur[ci] == ' ': + ci += 1 + if ci >= total_len: + break + # 找到 ':' 的位置 + colon_pos: t.CSizeT = ci + while colon_pos < total_len and cur[colon_pos] != ':' and cur[colon_pos] != ' ': + colon_pos += 1 + if colon_pos >= total_len or cur[colon_pos] != ':': + break + entry_name_len: t.CSizeT = colon_pos - ci + # 检测 star import ("*:module") + if entry_name_len == 1 and cur[ci] == '*': + mod_start: t.CSizeT = colon_pos + 1 + mod_end: t.CSizeT = mod_start + while mod_end < total_len and cur[mod_end] != ' ' and cur[mod_end] != '\0' and cur[mod_end] != ':': + mod_end += 1 + star_mod = cur + mod_start + # 比较名称 + elif entry_name_len == name_len: + match: int = 1 + ei: t.CSizeT = 0 + while ei < name_len: + if cur[ci + ei] != name[ei]: + match = 0 + break + ei += 1 + if match == 1: + mod_start2: t.CSizeT = colon_pos + 1 + mod_end2: t.CSizeT = mod_start2 + # 模块名结束于: 空格、null、或第二个':'(别名格式的分隔符) + while mod_end2 < total_len and cur[mod_end2] != ' ' and cur[mod_end2] != '\0' and cur[mod_end2] != ':': + mod_end2 += 1 + return cur + mod_start2 + # 跳到下一个条目 + ci = colon_pos + while ci < total_len and cur[ci] != ' ': + ci += 1 + # 未找到精确匹配,仅在允许时回退到 star import + if allow_star_fallback == 0: + return None + return star_mod + + # ============================================================ + # register_reexport - 注册 re-export 映射 + # + # 在 HandleImportFromNames 中调用:当处理 from .X import Y 时, + # 记录当前模块(通过 ModuleSha1)re-export 了函数 Y,源模块为 X。 + # + # 幂等:重复注册相同映射不会增加条目。 + # 内存用 stdlib.malloc 分配(全局存储器,跨 Phase 持久化)。 + # ============================================================ + def register_reexport(self, mod_sha1: str, func_name: str, source_module: str) -> int: + """注册 re-export 映射(幂等),返回 0 成功,-1 失败""" + if mod_sha1 is None or func_name is None or source_module is None: + return -1 + # 懒初始化 + if self.ReexportSha1s is None: + self.ReexportSha1s = CompilerFactory.get_perm_pool().alloc(MAX_REEXPORT * 17) + self.ReexportFuncs = CompilerFactory.get_perm_pool().alloc(MAX_REEXPORT * 64) + self.ReexportSrcs = CompilerFactory.get_perm_pool().alloc(MAX_REEXPORT * 64) + if self.ReexportSha1s is None or self.ReexportFuncs is None or self.ReexportSrcs is None: + return -1 + string.memset(self.ReexportSha1s, 0, MAX_REEXPORT * 17) + string.memset(self.ReexportFuncs, 0, MAX_REEXPORT * 64) + string.memset(self.ReexportSrcs, 0, MAX_REEXPORT * 64) + if self.ReexportCount >= MAX_REEXPORT: + return -1 + # 幂等检查:查找是否已存在相同映射 + for i in range(self.ReexportCount): + sidx: t.CSizeT = t.CSizeT(i) * 17 + fidx: t.CSizeT = t.CSizeT(i) * 64 + if string.strcmp(self.ReexportSha1s + sidx, mod_sha1) == 0: + if string.strcmp(self.ReexportFuncs + fidx, func_name) == 0: + # 已存在,更新 source_module(以防变化;64 字节槽,strncpy 钳制) + string.strncpy(self.ReexportSrcs + fidx, source_module, 63) + self.ReexportSrcs[fidx + 63] = '\0' + return 0 + # 添加新条目(槽位定长 17/64 字节,strcpy 无界会越界写相邻槽,全部 strncpy 钳制) + idx2: t.CSizeT = t.CSizeT(self.ReexportCount) * 17 + fidx2: t.CSizeT = t.CSizeT(self.ReexportCount) * 64 + string.strncpy(self.ReexportSha1s + idx2, mod_sha1, 16) + self.ReexportSha1s[idx2 + 16] = '\0' + string.strncpy(self.ReexportFuncs + fidx2, func_name, 63) + self.ReexportFuncs[fidx2 + 63] = '\0' + string.strncpy(self.ReexportSrcs + fidx2, source_module, 63) + self.ReexportSrcs[fidx2 + 63] = '\0' + self.ReexportCount += 1 + return 0 + + # ============================================================ + # lookup_reexport - 查找 re-export 映射 + # + # 给定模块 SHA1 和函数名,返回源模块名(如 "ast.lexer")或 None。 + # 调用方通过 _lookup_module_sha1(source_module) 获取源模块的 SHA1。 + # ============================================================ + def lookup_reexport(self, mod_sha1: str, func_name: str) -> str: + """查找 re-export 映射,返回源模块名或 None""" + if mod_sha1 is None or func_name is None: + return None + if self.ReexportSha1s is None or self.ReexportCount <= 0: + return None + for i in range(self.ReexportCount): + sidx: t.CSizeT = t.CSizeT(i) * 17 + fidx: t.CSizeT = t.CSizeT(i) * 64 + if string.strcmp(self.ReexportSha1s + sidx, mod_sha1) == 0: + if string.strcmp(self.ReexportFuncs + fidx, func_name) == 0: + return self.ReexportSrcs + fidx + return None + + # ============================================================ + # _resolve_relative_module - 解析相对导入为完整模块名 + # + # 对于 from .X import Y(level=1, module="X")在包 pkg 中: + # 解析为 "pkg.X" + # 对于 from . import Y(level=1, module=None)在包 pkg 中: + # 解析为 "pkg" + # 对于 from ..X import Y(level=2, module="X")在包 pkg.sub 中: + # 解析为 "pkg.X"(先从 pkg.sub 上溯一级到 pkg,再追加 .X) + # + # Args: + # pool: 内存池 + # current_package: 当前文件所属包名(如 "llvmlite"),None 表示无包 + # level: 相对导入级别(0=绝对,1=., 2=..) + # module: ImportFrom 的 module 字段(可能为 None) + # + # Returns: + # 解析后的完整模块名;绝对导入(level<=0)直接返回 module; + # 无法解析时返回 module(回退到原始值) + # ============================================================ + def _resolve_relative_module(self, pool: memhub.MemBuddy | t.CPtr, + current_package: str, + level: t.CInt, + module: str) -> str: + """解析相对导入为完整模块名""" + if level <= 0: + return module + if current_package is None: + # 无包上下文(includes 顶级文件 / App 顶层文件): + # `from .X import Y` 的语义 = "同目录/根目录的 X 模块" + # (如 includes/viperstring.vp 的 `from .string import *`)。 + # 直接返回 module 是正确解析,不是降级——禁止 fail-fast。 + return module + + # 从 current_package 开始,上溯 (level-1) 级 + pkg: str = current_package + up: t.CInt = level - 1 + while up > 0: + pkg_len: t.CSizeT = string.strlen(pkg) + last_dot: t.CSizeT = 0 + found: int = 0 + i: t.CSizeT = 0 + while i < pkg_len: + if pkg[i] == '.': + last_dot = i + found = 1 + i += 1 + if found == 0: + # 无更多父级(相对导入级别超过包深度,上溯到根目录): + # 回退到 module 原始值(根目录模块语义),后续查找失败 + # 由 import SHA1 检查明确报"模块未找到",此处不误杀。 + pkg = None + break + # 截断到最后一个 '.' 处 + new_pkg: str = pool.alloc(last_dot + 1) + if new_pkg is None: + self.Gen.TypeGenErr.fatal_error(None, f"相对导入解析失败:level={level} module='{module}'", "ImportError") + return module + string.strncpy(new_pkg, pkg, last_dot) + new_pkg[last_dot] = '\0' + pkg = new_pkg + up -= 1 + + if module is None: + # from . import Y → 模块就是包本身 + return pkg + if pkg is None: + # 包已上溯到空(相对导入越界):回退到 module 原始值 + return module + # 拼接 pkg + "." + module + pkg_len2: t.CSizeT = string.strlen(pkg) + mod_len: t.CSizeT = string.strlen(module) + buf: str = pool.alloc(pkg_len2 + 1 + mod_len + 1) + if buf is None: + self.Gen.TypeGenErr.fatal_error(None, f"相对导入解析失败:level={level} module='{module}'", "ImportError") + return module + string.strcpy(buf, pkg) + buf[pkg_len2] = '.' + string.strcpy(buf + pkg_len2 + 1, module) + return buf + + # ============================================================ + # compute_package_from_relpath - 从相对路径计算包名 + # + # 包名 = 文件所在目录路径,将 / 和 \ 替换为 . + # 对于顶级文件(无目录分隔符),返回 None + # + # 示例: + # "llvmlite/__init__.vp" → "llvmlite" + # "llvmlite/__types.vp" → "llvmlite" + # "ast/parser.vp" → "ast" + # "ast.vp" → None(顶级文件) + # ============================================================ + def compute_package_from_relpath(self, pool: memhub.MemBuddy | t.CPtr, + rel_path: str) -> str: + """从相对路径计算包名(目录部分,分隔符替换为 .)""" + if rel_path is None: + return None + rlen: t.CSizeT = string.strlen(rel_path) + # 找最后一个 / 或 \ + last_sep: t.CSizeT = 0 + found: int = 0 + i: t.CSizeT = 0 + while i < rlen: + ch: t.CChar = rel_path[i] + if ch == '/' or ch == '\\': + last_sep = i + found = 1 + i += 1 + if found == 0: + # 无目录分隔符 → 顶级文件,无包 + return None + # 复制目录部分,将 / 和 \ 替换为 . + dir_len: t.CSizeT = last_sep + buf: str = pool.alloc(dir_len + 1) + if buf is None: + return None + j: t.CSizeT = 0 + while j < dir_len: + ch2: t.CChar = rel_path[j] + if ch2 == '/' or ch2 == '\\': + buf[j] = '.' + else: + buf[j] = ch2 + j += 1 + buf[dir_len] = '\0' + return buf + + # ============================================================ + # set_current_file - 设置当前编译的文件名 + # + # 与 TypeGenMixin.set_current_file 行为一致(写 CurrentFile 字段), + # BuildPipeline/Phase1 通过 HandlesImports.set_current_file 委托调用。 + # 经 HandlesType 委托(延迟 import 规避循环依赖),字段由 TypeGenMixin 持有。 + # ============================================================ + def set_current_file(self, file_path: str) -> None: + """设置当前正在编译的文件名(与 HandlesType.set_current_file 同步调用)""" + import lib.core.Handles.HandlesType as HandlesType + self.Gen.TypeGenResolve.set_current_file(file_path) + + # ============================================================ + # _report_import_error - 本地实现 Python 风格报错(避免循环依赖) + # + # 无法访问 HandlesType.fatal_error(HandlesType import 了本模块, + # 若本模块再 import HandlesType 会形成循环依赖),这里用简化格式: + # Traceback (most recent call last): + # File "<当前文件>", line + # ImportError: + # ============================================================ + def _report_import_error(self, node: ast.AST | t.CPtr, msg: str) -> None: + """以 Python 风格报错并退出(本地实现,避免循环依赖)""" + import lib.core.Handles.HandlesType as HandlesType + stdio.printf("Traceback (most recent call last):\n") + lineno: int = 0 + if node is not None: + lineno = node.lineno + file_name: str = self.Gen.TypeGenResolve.get_current_file() + if file_name is None: + file_name = "" + stdio.printf(' File "%s", line %d\n', file_name, lineno) + # 显示行内内容(读源文件第 lineno 行的实际代码,便于快速定位) + if lineno > 0 and file_name is not None: + f_err: fileio.File | t.CPtr = fileio.File(file_name, fileio.MODE.R) + if not f_err.closed: + line_buf_err: bytes = stdlib.malloc(512) + if line_buf_err is not None: + cur_ln: int = 0 + while cur_ln < lineno: + r_err: LONG = f_err.readline(line_buf_err, 511) + if r_err <= 0: + break + cur_ln += 1 + if cur_ln == lineno: + ll_err: t.CSizeT = string.strlen(line_buf_err) + while ll_err > 0 and (line_buf_err[ll_err - 1] == '\n' or line_buf_err[ll_err - 1] == '\r'): + ll_err -= 1 + line_buf_err[ll_err] = '\0' + stdio.printf(" %s\n", line_buf_err) + break + stdlib.free(line_buf_err) + f_err.close() + stdio.printf("ImportError: %s\n", msg) + sys.exit(1) + + # ============================================================ + # _is_local_module_file - 当前文件同目录存在 {mod_name}.vp/.py + # + # 多文件项目(如 Test/G4/App 的 caller1.vp import g4node)的兄弟模块 + # 不在 includes 扫描存储器中(SHA1 在项目源文件列表),检查应豁免。 + # ============================================================ + def _is_local_module_file(self, mod_name: str) -> int: + """当前文件同目录存在 {mod_name}.vp/.py → 项目内兄弟模块""" + import lib.core.Handles.HandlesType as HandlesType + cur: str = self.Gen.TypeGenResolve.get_current_file() + if cur is None or mod_name is None: + return 0 + cur_len: t.CSizeT = string.strlen(cur) + if cur_len == 0: + return 0 + sep_pos: t.CSizeT = cur_len + while sep_pos > 0: + sep_pos -= 1 + ch: t.CChar = cur[sep_pos] + if ch == '/' or ch == '\\': + sep_pos += 1 + break + mod_len: t.CSizeT = string.strlen(mod_name) + path_len: t.CSizeT = sep_pos + mod_len + 5 + path_buf: bytes = stdlib.malloc(path_len + 1) + if path_buf is None: + return 0 + # .vp 文件 + string.strncpy(path_buf, cur, sep_pos) + path_buf[sep_pos] = '\0' + string.strcat(path_buf, mod_name) + string.strcat(path_buf, ".vp") + fex: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R) + if not fex.closed: + fex.close() + stdlib.free(path_buf) + return 1 + # .py 文件(Python 模块可能无 .vp) + string.strncpy(path_buf, cur, sep_pos) + path_buf[sep_pos] = '\0' + string.strcat(path_buf, mod_name) + string.strcat(path_buf, ".py") + fex2: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R) + if not fex2.closed: + fex2.close() + stdlib.free(path_buf) + return 1 + stdlib.free(path_buf) + return 0 + + # ============================================================ + # _check_import_sha1 - 导入时校验模块 SHA1 是否已注册(fast-fail) + # + # 背景:若 includes 路径配置错误(如 project.json 指向不存在的 + # ./includes),includes 扫描结果为 0,模块不会注册 SHA1。此前 + # 错误延迟到实际调用 module.func() 时才报误导性的 + # "跨模块调用 'bd.alloc' 找不到模块 SHA1"。 + # 现在在 import 语句处立即检测并报错,快速定位配置问题。 + # + # t/c 是内部库,不参与 includes 扫描,豁免检查。 + # ============================================================ + def _check_import_sha1(self, node: ast.AST | t.CPtr, mod_name: str) -> int: + """导入时校验模块 SHA1 是否已注册,未注册则立即报错退出 + + Args: + node: Import/ImportFrom AST 节点(提供行号) + mod_name: 导入的模块名(如 "memhub"、"w32.fileio") + + Returns: + 1=检查通过;模块未注册时直接报错退出(不会返回 0) + """ + if mod_name is None: + return 1 + # t/c 是内部库,不参与 includes 扫描,豁免检查 + # ctraits 是纯编译期宏库(.vpi 后缀,IncludesScanner 不扫描 .vpi),豁免检查 + if string.strcmp(mod_name, "t") == 0 or string.strcmp(mod_name, "c") == 0 or string.strcmp(mod_name, "ctraits") == 0: + return 1 + mod_sha1: str = StubMergerStore.LookupSha1ByModName(mod_name) + if mod_sha1 is None: + # App 兄弟模块豁免:当前文件同目录存在 {mod_name}.vp/.py + # (如 Test/G4/App/caller1.vp import g4node——同项目源文件, + # SHA1 在项目文件列表而非 includes 扫描存储器,不应报错) + if self._is_local_module_file(mod_name) != 0: + return 1 + err_buf: str = stdlib.malloc(256) + if err_buf is not None: + viperlib.snprintf(err_buf, 256, + "模块 '%s' 未注册 SHA1(includes 扫描未找到该模块,请检查 project.json 的 includes 路径配置)", + mod_name) + self._report_import_error(node, err_buf) + else: + self._report_import_error(node, "导入模块 SHA1 未注册(includes 扫描未找到该模块)") + return 1 + + # ============================================================ + # translate_import - 处理 import 语句,更新 trans._imported_modules + # (迁移自 HandlesImports.ImportsHandle.HandleImport) + # ============================================================ + def translate_import(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """处理 import 语句,返回 0""" + imp: ast.Import | t.CPtr = (ast.Import | t.CPtr)(node) + if imp is None: + return 0 + names: list[ast.AST | t.CPtr] | t.CPtr = imp.names + if names is None: + return 0 + nn: t.CSizeT = len(names) + for ni in range(nn): + alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni)) + if alias is not None and alias.name is not None: + # 导入时立即校验模块 SHA1 是否注册(fast-fail,仅全量翻译时检查) + # declare_only=1/2 是 struct 预注册/import 扫描阶段:此时 SHA1 表 + # 尚未包含后续才追加的模块(如 App 源文件),检查会造成误报 + if trans._declare_only == 0: + self._check_import_sha1(node, alias.name) + pool_val: memhub.MemBuddy | t.CPtr = trans.Pool + im_val: str = trans._imported_modules + trans._imported_modules = self.add_imported_module( + pool_val, im_val, alias.name) + # 别名也加入导入模块列表(用于模块限定构造器检查 Module.Class()) + if alias.asname is not None: + trans._imported_modules = self.add_imported_module( + pool_val, trans._imported_modules, alias.asname) + # 别名也加入 from_imports(asname:fullname), + # 使 HT.func() 跨模块调用能通过 from_imports 查找别名→完整模块名→SHA1 + # 否则 _lookup_module_sha1("HT") 找不到(mod_arr 只存文件名 HandlesTranslator) + trans._from_imports = self.add_from_import( + pool_val, trans._from_imports, alias.asname, alias.name) + else: + # 无别名时(import a.b.c),将顶层包名 "a" 也加入 _imported_modules, + # 使 a.b.c 作为属性访问的 base 被翻译时能通过 is_module_imported("a") 检查 + dot_ptr: str = string.strstr(alias.name, '.') + if dot_ptr is not None: + pkg_len: t.CSizeT = t.CSizeT(t.CUInt64T(dot_ptr) - t.CUInt64T(alias.name)) + if pkg_len > 0 and pkg_len < 256: + pkg_buf: bytes = pool_val.alloc(pkg_len + 1) + if pkg_buf is not None: + string.strncpy(pkg_buf, alias.name, pkg_len) + pkg_buf[pkg_len] = '\0' + trans._imported_modules = self.add_imported_module( + pool_val, trans._imported_modules, pkg_buf) + return 0 + + # ============================================================ + # translate_import_from_module - 处理 from X import Y 的模块部分 + # (迁移自 HandlesImports.ImportsHandle.HandleImportFromModule) + # + # 对相对导入(level > 0),使用 trans.CurrentPackage 解析为 + # 完整模块名(如 __types → llvmlite.__types),确保 .deps.txt + # 记录的模块名与 SHA1 映射表一致。 + # ============================================================ + def translate_import_from_module(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """处理 from X import Y 的模块部分,更新 trans._imported_modules""" + impf: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(node) + if impf is None: + return 0 + # 解析模块名:相对导入需补充包前缀 + resolved: str = self._resolve_relative_module( + trans.Pool, trans.CurrentPackage, + impf.level, impf.module) + if resolved is not None: + # 导入时立即校验模块 SHA1 是否注册(fast-fail,仅全量翻译时检查) + if trans._declare_only == 0: + self._check_import_sha1(node, resolved) + trans._imported_modules = self.add_imported_module( + trans.Pool, trans._imported_modules, resolved) + return 0 + + # ============================================================ + # translate_import_from_names - 处理 from X import Y 的名称部分 + # (迁移自 HandlesImports.ImportsHandle.HandleImportFromNames) + # + # 同样使用解析后的完整模块名,确保 from-import 映射 + # (如 LLVMType:llvmlite.__types)能正确查到 SHA1。 + # ============================================================ + def translate_import_from_names(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """处理 from X import Y 的名称部分,更新 trans._from_imports""" + impf: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(node) + if impf is None: + return 0 + # 解析模块名:相对导入需补充包前缀 + resolved: str = self._resolve_relative_module( + trans.Pool, trans.CurrentPackage, + impf.level, impf.module) + if resolved is not None: + names: list[ast.AST | t.CPtr] | t.CPtr = impf.names + if names is not None: + nn: t.CSizeT = len(names) + for ni in range(nn): + alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni)) + if alias is not None and alias.name is not None: + local_name: str = alias.name + orig_name: str = None + if alias.asname is not None: + local_name = alias.asname + orig_name = alias.name + trans._from_imports = self.add_from_import( + trans.Pool, trans._from_imports, + local_name, resolved, orig_name) + # 命名空间隔离:from-import 的名称标记为可见结构体 + self.Gen.StructGen.add_visible_struct(trans.Pool, local_name) + # 注册 re-export 映射:当前模块 re-export 了 local_name,源模块为 resolved + # 使跨模块调用 module.func() 能解析到正确的源模块 SHA1 + if trans.ModuleSha1 is not None: + self.register_reexport(trans.ModuleSha1, local_name, resolved) + return 0 + + def InitImportsGen(self) -> int: + """初始化 ImportsGen 字段(构造时由 Generator 调用)""" + if self is None: + return 1 + self.ReexportSha1s = None + self.ReexportFuncs = None + self.ReexportSrcs = None + self.ReexportCount = 0 + return 0 diff --git a/App/lib/core/Gen/MatchGenMixin.vp b/App/lib/core/Gen/MatchGenMixin.vp index 29cf6f9..d33bc31 100644 --- a/App/lib/core/Gen/MatchGenMixin.vp +++ b/App/lib/core/Gen/MatchGenMixin.vp @@ -1,1306 +1,1304 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import viperlib -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesBody as HandlesBody -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesType as HandlesType - - -# ============================================================ -# MatchGenMixin - match 语句翻译 Mixin(P6 方法化) -# -# 从 HandlesMatch.vp 的 MatchHandle 类迁移(纯移动,逻辑零改动): -# Handle → translate_match(签名加 trans 首参,方法体 self.Trans → trans) -# 类内辅助方法 self._xxx → 保持 self.xxx,一并搬入成方法 -# 模块级辅助函数 _case_tail_unreachable → 搬入成方法 -# (原 HandlesMatch 模块级常量 MAX_MATCH_CASES/SCOPE_MATCH 一并复制) -# -# 迁移原则(与 P1-P6 一致,行为零变化): -# 1. 方法保留原逻辑,仅函数体内的 self.Trans 改为 trans 首参 -# 2. 外部模块调用(HandlesExpr.xxx/HandlesBody.xxx 等)保留模块前缀 -# 3. 原 HandlesMatch.translate_match 保留为"委托":本地模块级单例 _g_gen -# (BuildPipeline/main 注入)cast 成 Generator 类型 -# -# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 -# ============================================================ - - -# match case 数量上限(原 HandlesMatch.MAX_MATCH_CASES) -MAX_MATCH_CASES: t.CDefine = 32 - -# 作用域种类常量(与 HandlesVar 的 Scope.Kind 区分,原 HandlesMatch.SCOPE_MATCH) -SCOPE_MATCH: t.CDefine = 6 - - -@t.NoVTable -class MatchGenMixin: - """match 语句翻译 Mixin(P6 方法化)""" - - # ============================================================ - # _case_tail_unreachable - case 体末尾结构性不可达判定 - # - # case 体翻译后当前块若未终止,且末句是控制流语句(If/While/For/Match) - # 且其 merge 结构性不可达(全分支 return,如 case Int(bits): if ... return) - # 时,当前块是控制流的 merge(无 terminator),与 HandlesIf L309-315/ - # ClassGenVTable L1084 同语义补 unreachable。返回 1= 已补 unreachable - # (调用方不应 br end_bb);0= 正常收尾(应 br end_bb)。 - # - # 根因(ClassGenEnum._get_type_align):case 体末句 If 全 return 时,If - # 处理器把 builder 停在无 terminator 的 merge 块,case 循环的 - # is_terminated 检查误判"未终止" → 补 br end_bb → rm_merge_reach=1 → - # 全 case return 的 match 被误判 merge 可达 → 函数收尾 fail-fast - # "流程掉出末尾"。不含 Try/With:其处理器不维护 _ctrl_merge_reachable, - # 避免残留值误判。 - # ============================================================ - def _case_tail_unreachable(self, trans: HT.Translator | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - body_list: list[ast.AST | t.CPtr] | t.CPtr) -> int: - if trans is None or builder is None: - return 0 - if llvmlite.builder_cur_block_is_terminated(builder) != 0: - return 0 - if body_list is None or len(body_list) == 0: - return 0 - lst: ast.AST | t.CPtr = body_list.get(len(body_list) - 1) - if lst is None: - return 0 - lk: int = lst.kind() - if lk != ast.ASTKind.If and lk != ast.ASTKind.While \ - and lk != ast.ASTKind.For and lk != ast.ASTKind.Match: - return 0 - if trans._ctrl_merge_reachable != 0: - return 0 - llvmlite.build_unreachable(builder) - return 1 - - # ============================================================ - # translate_match - match 语句主入口,返回 0 - # (迁移自 HandlesMatch.MatchHandle.Handle) - # ============================================================ - def translate_match(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - if node is None: - return 0 - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - func: llvmlite.Function | t.CPtr = trans._cur_func - if builder is None or func is None: - return 0 - - # 追加90:match merge 可达性重置(分派前初始化为 0;各处理函数 - # renum/sequence/simple 内部用各自的局部标志记录 br end_bb 并在 - # 收尾覆盖,见 _handle_renum_match/_handle_sequence_match/ - # _handle_simple_match——切勿把标志声明在 Handle 这里(分派函数), - # 否则子函数引用的同名变量会退化为隐式全局,跨 match 互相污染)。 - trans._ctrl_merge_reachable = 0 - - m_node: ast.Match | t.CPtr = (ast.Match | t.CPtr)(node) - - # 1. 求值 subject - subject_node: ast.AST | t.CPtr = m_node.subject - if subject_node is None: - return 0 - # 序列匹配(match (a, b): case (x, y): ...)走独立路径: - # Tuple/List subject 无法用 translate_value 求值(会返回 None), - # 提前分派到 _handle_sequence_match,避免 fail-fast 误报。 - sk_seq: int = subject_node.kind() - if sk_seq == ast.ASTKind.Tuple or sk_seq == ast.ASTKind.List: - return self._handle_sequence_match(trans, m_node, subject_node) - subject_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, subject_node, - trans._funcs, trans._func_count, trans) - if subject_val is None: - # fail-fast: match subject 翻译失败 - HandlesType.fatal_error(subject_node, "match subject 翻译失败", "TypeError") - - # 2. 检测是否 REnum match - is_renum: int = 0 - renum_name: str = None - subject_ptr: llvmlite.Value | t.CPtr = None - - # 2a. 若 subject 是 Name,查变量注解类名 - if subject_node.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(subject_node) - if nm.id is not None: - entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm.id) - if entry is not None and entry.AnnotClassName is not None \ - and HandlesClassDef._is_renum_class_name( - entry.AnnotClassName) != 0: - is_renum = 1 - renum_name = entry.AnnotClassName - subject_ptr = HandlesVar.lookup_var(trans.SymTab, nm.id) - - # 2b. 若未确定,遍历 cases 查 MatchClass 变体 - if is_renum == 0: - cases_list: list[ast.AST | t.CPtr] | t.CPtr = m_node.cases - if cases_list is not None: - cn: t.CSizeT = len(cases_list) - ci: int = 0 - while ci < cn and is_renum == 0: - case_node: ast.AST | t.CPtr = cases_list.get(ci) - if case_node is not None \ - and case_node.kind() == ast.ASTKind.MatchCase: - mc: ast.MatchCase | t.CPtr = ( - ast.MatchCase | t.CPtr)(case_node) - pat: ast.AST | t.CPtr = mc.pattern - if pat is not None \ - and pat.kind() == ast.ASTKind.MatchClass: - rnm: str = self._extract_renum_name_from_cls(pat) - if rnm is not None \ - and HandlesClassDef._is_renum_class_name(rnm) != 0: - is_renum = 1 - renum_name = rnm - if subject_ptr is None: - subject_ptr = subject_val - ci = ci + 1 - - # 3. 分派 - if is_renum != 0 and subject_ptr is not None: - return self._handle_renum_match(trans, m_node, renum_name, subject_ptr) - return self._handle_simple_match(trans, m_node, subject_val) - - # ============================================================ - # _extract_renum_name_from_cls - 从 MatchClass.cls 提取 REnum 类名 - # - # LLVMType.Ptr -> Attribute(value=Name('LLVMType'), attr='Ptr') -> 'LLVMType' - # llvmlite.LLVMType.Ptr -> Attribute(Attribute(Name('llvmlite'),'LLVMType'),'Ptr') -> 'LLVMType' - # Ptr -> Name('Ptr') -> 遍历查找 - # ============================================================ - def _extract_renum_name_from_cls(self, - pattern: ast.AST | t.CPtr) -> str: - if pattern is None: - return None - mc: ast.MatchClass | t.CPtr = (ast.MatchClass | t.CPtr)(pattern) - cls_node: ast.AST | t.CPtr = mc.cls - if cls_node is None: - return None - # Attribute 形式 - if cls_node.kind() == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cls_node) - if at.value is not None: - if at.value.kind() == ast.ASTKind.Name: - inner_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - return inner_nm.id - if at.value.kind() == ast.ASTKind.Attribute: - inner_at: ast.Attribute | t.CPtr = ( - ast.Attribute | t.CPtr)(at.value) - return inner_at.attr - # Name 形式:遍历所有 REnum 类反查 - if cls_node.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cls_node) - return self._find_renum_class_for_variant(nm.id) - return None - - # ============================================================ - # _extract_variant_name_from_cls - 从 MatchClass.cls 提取变体名 - # ============================================================ - def _extract_variant_name_from_cls(self, - pattern: ast.AST | t.CPtr) -> str: - if pattern is None: - return None - mc: ast.MatchClass | t.CPtr = (ast.MatchClass | t.CPtr)(pattern) - cls_node: ast.AST | t.CPtr = mc.cls - if cls_node is None: - return None - if cls_node.kind() == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cls_node) - return at.attr - if cls_node.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cls_node) - return nm.id - return None - - # ============================================================ - # _find_renum_class_for_variant - 从变体名反查 REnum 类名 - # - # P5-2 后 REnum 变体表迁入 gen 字段(RenumClassNames/RenumClassCount), - # 模块级 _renum_class_* 已失效,统一委托到 gen._lookup_renum_variant。 - # ============================================================ - def _find_renum_class_for_variant(self, variant_name: str) -> str: - if variant_name is None: - return None - return HandlesClassDef._lookup_renum_variant(variant_name) - - # ============================================================ - # _has_no_break - 检测 case body 是否含 c.NoBreak() 调用 - # - # 遍历 case body 顶层语句,查找 Expr(Call(Attribute(Name('c'), 'NoBreak'))) - # ============================================================ - def _has_no_break(self, body_list: list[ast.AST | t.CPtr] | t.CPtr) -> int: - if body_list is None: - return 0 - n: t.CSizeT = len(body_list) - i: int = 0 - while i < n: - stmt: ast.AST | t.CPtr = body_list.get(i) - if stmt is not None and stmt.kind() == ast.ASTKind.Expr: - expr_node: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(stmt) - val: ast.AST | t.CPtr = expr_node.value - if val is not None and val.kind() == ast.ASTKind.Call: - call_node: ast.Call | t.CPtr = (ast.Call | t.CPtr)(val) - fn: ast.AST | t.CPtr = call_node.func - if fn is not None and fn.kind() == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = ( - ast.Attribute | t.CPtr)(fn) - if at.value is not None \ - and at.value.kind() == ast.ASTKind.Name: - base_nm: ast.Name | t.CPtr = ( - ast.Name | t.CPtr)(at.value) - if base_nm.id is not None \ - and string.strcmp(base_nm.id, "c") == 0 \ - and at.attr is not None \ - and string.strcmp(at.attr, "NoBreak") == 0: - return 1 - i = i + 1 - return 0 - - # ============================================================ - # _handle_renum_match - REnum 路径 - # - # 1. bitcast subject 到 i32* 读 __tag - # 2. 收集 case 值 + 创建 BB + 构建 SwitchCase 链表 - # 3. 发射 build_switch - # 4. 翻译每个 case body(含作用域隔离 + 变体字段绑定) - # ============================================================ - def _handle_renum_match(self, trans: HT.Translator | t.CPtr, - node: ast.Match | t.CPtr, - renum_name: str, - subject_ptr: llvmlite.Value | t.CPtr) -> int: - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - func: llvmlite.Function | t.CPtr = trans._cur_func - # 局部记录本 renum match 是否有 br 进入 end_bb,收尾时覆盖 - # _ctrl_merge_reachable(case 体内嵌套 If 无 else + return 会把全局 - # 标志置 1,全 case return 的 match 被误判 merge 可达 → 函数收尾 - # fail-fast "流程掉出末尾"。声明必须在本函数内——放 Handle 分派 - # 函数里会使本函数引用退化为隐式全局,跨 match 污染)。 - rm_merge_reach: int = 0 - - # 0. subject 归一化:确保 subject_ptr 是指向 REnum 结构体的指针 - # (对齐 TPC HandlesMatch.py:238-259 的 _HandleRenumMatchLlvm) - # 情况1: subject_ptr 是 T**(变量 alloca)→ load 一次得 T* - # 情况2: subject_ptr 不是指针(值型,如 REnum payload 槽位 load 出的 i64) - # → alloca REnum 结构体 + store 值 + 用 alloca 指针 - # 情况3: 指针但 pointee 不是结构体 → bitcast 到 REnum 结构体指针 - subj_ty: llvmlite.LLVMType | t.CPtr = subject_ptr.Ty - if subj_ty is not None and HandlesExpr.is_ptr_type(subj_ty) != 0 \ - and subj_ty.Pointee is not None \ - and HandlesExpr.is_ptr_type(subj_ty.Pointee) != 0: - # 情况1: T** → load 一次得 T* - loaded_sub: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, subj_ty.Pointee, subject_ptr) - if loaded_sub is not None: - subject_ptr = loaded_sub - # 情况2: 值型 subject(非指针)→ inttoptr 转回指针 - # 值型 subject 来自 REnum payload 槽位 load(槽位类型 i64,存的是指针), - # 所以直接 inttoptr 到 renum_sty* 即可,无需 alloca+store - if subject_ptr.Ty is None or HandlesExpr.is_ptr_type(subject_ptr.Ty) == 0: - renum_se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct( - renum_name) - renum_sty: llvmlite.LLVMType | t.CPtr = None - if renum_se is not None: - renum_sty = renum_se.Ty - if renum_sty is None: - # fail-fast: REnum 结构体未注册,无法构造 - HandlesType.fatal_error( - node, - f"REnum 结构体 '{renum_name}' 未注册", - "NameError") - i64_ty0: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - int_val: llvmlite.Value | t.CPtr = subject_ptr - # 非 i64 整数值先扩展/截断到 i64(inttoptr 要求同宽) - # 仅当 subj_ty 是已知整数类型时转换;类型未知时保持原值 - if subj_ty is not None and HandlesExpr.get_llvm_type_bits(subj_ty) != 64 \ - and HandlesExpr.is_ptr_type(subj_ty) == 0: - if HandlesExpr.get_llvm_type_bits(subj_ty) > 64: - int_val = llvmlite.build_trunc(builder, subject_ptr, i64_ty0) - else: - int_val = llvmlite.build_zext(builder, subject_ptr, i64_ty0) - renum_ptr_ty0: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, renum_sty) - subj_ptr0: llvmlite.Value | t.CPtr = llvmlite.build_inttoptr( - builder, int_val, renum_ptr_ty0) - if subj_ptr0 is not None: - subject_ptr = subj_ptr0 - - # 1. bitcast subject 到 i32* 读 __tag - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i32_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty) - tag_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, subject_ptr, i32_ptr_ty) - if tag_ptr is None: - # fail-fast: REnum tag 指针转换失败 - HandlesType.fatal_error(node, "REnum tag 指针转换失败", "TypeError") - tag_val: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i32_ty, tag_ptr) - if tag_val is None: - # fail-fast: REnum tag 读取失败 - HandlesType.fatal_error(node, "REnum tag 读取失败", "TypeError") - - # 2. 创建 default/end BB - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - name_buf: str = pool.alloc(32) - if name_buf is None: - # fail-fast: 标签缓冲区分配失败 - HandlesType.fatal_error(node, "标签缓冲区分配失败", "TypeError") - viperlib.snprintf(name_buf, 32, "match.default.%d", cnt) - default_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, name_buf) - viperlib.snprintf(name_buf, 32, "match.end.%d", cnt) - end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, name_buf) - - # 3. 准备收集数组(用 CSizeT 数组存指针) - cases_list: list[ast.AST | t.CPtr] | t.CPtr = node.cases - if cases_list is None: - # fail-fast: match cases 缺失 - HandlesType.fatal_error(node, "match cases 缺失", "TypeError") - case_count: t.CSizeT = len(cases_list) - - # BB 指针数组、case 值指针数组、default 标记数组、nobreak 标记数组 - bb_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) - cv_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) - def_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) - nb_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) - if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None: - # fail-fast: match 分派数组分配失败 - HandlesType.fatal_error(node, "match 分派数组分配失败", "TypeError") - - collected: int = 0 - has_default: int = 0 - - # SwitchCase 链表 - sw_head: llvmlite.SwitchCase | t.CPtr = None - sw_tail: llvmlite.SwitchCase | t.CPtr = None - sw_count: int = 0 - - # 4. 第一遍:收集 case 信息 + 创建 BB + 构建链表 - i: int = 0 - while i < case_count: - case_node: ast.AST | t.CPtr = cases_list.get(i) - if case_node is None: - i = i + 1 - continue - if case_node.kind() != ast.ASTKind.MatchCase: - i = i + 1 - continue - mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node) - pat: ast.AST | t.CPtr = mc.pattern - - is_def: int = 0 - cv: llvmlite.Value | t.CPtr = None - - if pat is not None: - pk: int = pat.kind() - if pk == ast.ASTKind.MatchClass: - vnm: str = self._extract_variant_name_from_cls(pat) - if vnm is not None: - tag: int = HandlesClassDef._lookup_renum_variant_in_class( - renum_name, vnm) - if tag >= 0: - tag_buf: str = pool.alloc(32) - if tag_buf is not None: - viperlib.snprintf(tag_buf, 32, "%d", tag) - cv = llvmlite.ConstInt(pool, i32_ty, tag, - tag_buf if tag_buf is not None else "0") - elif pk == ast.ASTKind.MatchAs: - ma: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(pat) - if ma.pattern is None: - is_def = 1 - has_default = 1 - elif pk == ast.ASTKind.MatchValue: - mv: ast.MatchValue | t.CPtr = (ast.MatchValue | t.CPtr)(pat) - cv = HandlesExpr.translate_value( - builder, pool, trans.Module, mv.value, - trans._funcs, trans._func_count, trans) - elif pk == ast.ASTKind.MatchOr: - # MatchOr: 多个值共享一个 BB(取第一个值做 case) - mo: ast.MatchOr | t.CPtr = (ast.MatchOr | t.CPtr)(pat) - pats: list[ast.AST | t.CPtr] | t.CPtr = mo.patterns - if pats is not None and len(pats) > 0: - first_pat: ast.AST | t.CPtr = pats.get(0) - if first_pat is not None \ - and first_pat.kind() == ast.ASTKind.MatchValue: - mv2: ast.MatchValue | t.CPtr = ( - ast.MatchValue | t.CPtr)(first_pat) - cv = HandlesExpr.translate_value( - builder, pool, trans.Module, mv2.value, - trans._funcs, trans._func_count, trans) - - # 创建 case BB - if is_def == 0: - if collected >= MAX_MATCH_CASES: - break - viperlib.snprintf(name_buf, 32, "match.case.%d.%d", cnt, i) - bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, name_buf) - else: - bb = default_bb - - # 检测 NoBreak - body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children - nb: int = self._has_no_break(body_list) - - # 存入数组 - if collected < MAX_MATCH_CASES: - bb_arr[collected] = t.CSizeT(bb) - cv_arr[collected] = t.CSizeT(cv) - def_arr[collected] = is_def - nb_arr[collected] = nb - collected = collected + 1 - - # 构建 SwitchCase 链表(非 default case 且有值) - if is_def == 0 and cv is not None: - sc: llvmlite.SwitchCase | t.CPtr = llvmlite.new_switch_case( - pool, cv, bb) - if sc is not None: - if sw_head is None: - sw_head = sc - sw_tail = sc - else: - sw_tail.Next = sc - sw_tail = sc - sw_count = sw_count + 1 - - i = i + 1 - - # 5. 发射 switch 指令 - llvmlite.build_switch(builder, tag_val, default_bb, sw_head, sw_count) - - # 6. 查找 REnum 结构体类型(用于变体字段绑定的 GEP) - renum_entry: HandlesStruct.StructEntry | t.CPtr = None - renum_ty: llvmlite.LLVMType | t.CPtr = None - se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(renum_name) - if se is not None: - renum_entry = se - renum_ty = se.Ty - - # 7. 第二遍:翻译每个 case body - i = 0 - while i < collected: - case_node: ast.AST | t.CPtr = cases_list.get(i) - if case_node is None: - i = i + 1 - continue - mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node) - pat: ast.AST | t.CPtr = mc.pattern - - # 取 BB - bb_addr: t.CSizeT = bb_arr[i] - case_bb: llvmlite.BasicBlock | t.CPtr = ( - llvmlite.BasicBlock | t.CPtr)(t.CVoid(bb_addr, t.CPtr)) - is_def: int = def_arr[i] - nb: int = nb_arr[i] - - # default case 的 body 在 step 8 单独翻译,这里跳过避免重复 - if is_def == 1: - i = i + 1 - continue - - # 定位到 case BB - llvmlite.position_at_end(builder, case_bb) - - # 进入 case 作用域(变体字段绑定隔离) - HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH) - - # 变体字段绑定(MatchClass) - if pat is not None and pat.kind() == ast.ASTKind.MatchClass \ - and renum_entry is not None and renum_ty is not None: - self._bind_variant_fields( - pat, renum_name, renum_entry, renum_ty, - subject_ptr, trans, pool, builder) - - # 翻译 case body - body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children - if body_list is not None: - bc: t.CSizeT = len(body_list) - bi: int = 0 - while bi < bc: - stmt: ast.AST | t.CPtr = body_list.get(bi) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - bi = bi + 1 - - # 退出 case 作用域 - HandlesVar.exit_scope(trans.SymTab) - - # 若未终止且无 NoBreak,跳到 end - # 末句控制流全 return(结构性不可达)时补 unreachable,不 br end_bb - if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ - and nb == 0 \ - and self._case_tail_unreachable(trans, builder, body_list) == 0: - llvmlite.build_br(builder, end_bb) - trans._ctrl_merge_reachable = 1 - rm_merge_reach = 1 - - i = i + 1 - - # 8. 处理 default 块 - llvmlite.position_at_end(builder, default_bb) - if has_default == 0: - # 无显式 default:default 直接跳 end - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, end_bb) - trans._ctrl_merge_reachable = 1 - rm_merge_reach = 1 - else: - # 有显式 default:翻译 default case body(找到 is_def==1 的 case) - dbody: list[ast.AST | t.CPtr] | t.CPtr = None - di: int = 0 - while di < collected: - if def_arr[di] == 1: - dcase: ast.AST | t.CPtr = cases_list.get(di) - if dcase is not None: - dmc: ast.MatchCase | t.CPtr = ( - ast.MatchCase | t.CPtr)(dcase) - HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH) - dbody = dmc.children - if dbody is not None: - dn: t.CSizeT = len(dbody) - dj: int = 0 - while dj < dn: - stmt: ast.AST | t.CPtr = dbody.get(dj) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - dj = dj + 1 - HandlesVar.exit_scope(trans.SymTab) - break - di = di + 1 - # 末句控制流全 return → 补 unreachable(不 br end_bb) - if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ - and self._case_tail_unreachable(trans, builder, dbody) == 0: - llvmlite.build_br(builder, end_bb) - trans._ctrl_merge_reachable = 1 - rm_merge_reach = 1 - - # 9. 定位到 end 块 - llvmlite.position_at_end(builder, end_bb) - # 用本 match 自身的 br 记录覆盖,消除 case 体内嵌套控制流对 - # _ctrl_merge_reachable 的污染(全 case return 时应为不可达) - trans._ctrl_merge_reachable = rm_merge_reach - return 0 - - # ============================================================ - # _bind_variant_fields - 绑定 MatchClass 的变体字段 - # - # case LLVMType.Ptr(pointee) 中的 pointee 绑定到 subject 的 payload 字段 - # ============================================================ - def _bind_variant_fields(self, pat: ast.AST | t.CPtr, - renum_name: str, - renum_entry: HandlesStruct.StructEntry | t.CPtr, - renum_ty: llvmlite.LLVMType | t.CPtr, - subject_ptr: llvmlite.Value | t.CPtr, - trans: HT.Translator | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr): - if pat is None or renum_entry is None or renum_ty is None: - return - mc: ast.MatchClass | t.CPtr = (ast.MatchClass | t.CPtr)(pat) - pats: list[ast.AST | t.CPtr] | t.CPtr = mc.patterns - if pats is None: - return - # bitcast subject_ptr 到 renum_ptr_ty(确保 GEP 类型匹配) - renum_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, renum_ty) - casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, subject_ptr, renum_ptr_ty) - if casted_ptr is None: - casted_ptr = subject_ptr - pn: t.CSizeT = len(pats) - j: int = 0 - while j < pn: - sub_pat: ast.AST | t.CPtr = pats.get(j) - if sub_pat is not None and sub_pat.kind() == ast.ASTKind.MatchAs: - ma: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(sub_pat) - bind_name: str = ma.name - if bind_name is not None: - # 按位置绑定:MatchClass 第 j 个参数 → payload 索引 j+1 - # 对应 TPC HandlesMatch.py:305-306(不依赖字段名大小写匹配) - payload_idx: int = j + 1 - # 字段名查找作为回退(若字段名与 MatchAs 名一致可直接命中) - if payload_idx >= renum_entry.FieldCount: - # class_name 用 CSizeT 指针值比较:必须传 renum_entry.Name - # (注册时 _update_renum_alias_class_ptr 统一后的 perm_pool - # 指针);renum_name(AnnotClassName 等)是不同指针恒不匹配 - # → 恒 -1 → fail-fast 误报(追加73d 同款指针陷阱) - alt_idx: int = HandlesClassDef._lookup_renum_field_alias( - renum_entry.Name, bind_name) - if alt_idx >= 1: - payload_idx = alt_idx - else: - # fail-fast: payload 越界且别名查找失败 - # (node 在本函数不存在——参数是 pat/sub_pat,用 sub_pat - # 定位到具体 MatchAs 模式;TPC Python 语义下未定义名只在 - # 运行时求值才报错,TPV 惰性编译方法体时即 NameError) - HandlesType.fatal_error( - sub_pat, - f"REnum 变体字段 '{bind_name}' 在结构体 '{renum_name}' 中越界且别名查找失败", - "TypeError") - # 获取字段类型 - fe: HandlesStruct.FieldEntry | t.CPtr = ( - HandlesStruct._get_field_entry( - renum_entry, payload_idx)) - field_ty: llvmlite.LLVMType | t.CPtr = None - if fe is not None: - field_ty = fe.Ty - if field_ty is None: - # fail-fast: 变体字段类型缺失,禁止兜底 i8 - HandlesType.fatal_error( - sub_pat, - f"REnum 变体字段类型缺失: {bind_name}", - "TypeError") - # GEP 取字段地址 - elem_ptr: llvmlite.Value | t.CPtr = ( - llvmlite.build_gep_struct( - builder, renum_ty, field_ty, - casted_ptr, payload_idx)) - if elem_ptr is None: - # fail-fast: 变体字段地址计算失败 - HandlesType.fatal_error( - sub_pat, - f"REnum 变体字段 '{bind_name}' 地址计算失败", - "TypeError") - # 变体成员实际类型(对齐 TPC class_members L300-307/L376-382): - # 注册时别名表存了成员注解解析出的类型(perm_pool 深拷贝)。 - # 用它把槽位地址 bitcast 成 Ptr(成员类型),使绑定变量按成员 - # 类型读 payload——Struct.Name: t.CChar|t.CPtr = i8*,否则按 - # 槽位 i64 读 → is 比较/下标/strlen 等字符串操作翻译失败 - # (CallGenMixin L4631 type_name_sp is not None 根因)。 - # 注意:必须按 (class, 变体名, 位置) 定位——MatchAs 名是局部 - # 变量名(type_name_sp),不是变体字段名(Name),按字段名 - # 查恒不匹配(追加76 第一次修复失效根因);同一 payload 位置 - # 跨变体类型也不同(Int.Bits=i32 vs Struct.Fields=Ptr)。 - # 自引用类型(如 Pointee: LLVMType|t.CPtr)注册期解析失败 → - # 查不到类型 → 回退槽位类型(原始位宽在嵌套 match 中经 - # subject bitcast 仍可用)。 - mem_ty_m: llvmlite.LLVMType | t.CPtr = None - vnt_m: str = self._extract_variant_name_from_cls(pat) - if vnt_m is not None and renum_entry is not None \ - and renum_entry.Name is not None: - mem_ty_m = HandlesClassDef._lookup_renum_member_ty( - renum_entry.Name, vnt_m, payload_idx) - if mem_ty_m is not None: - mem_ptr_m: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, mem_ty_m) - if mem_ptr_m is not None: - cast_m: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, elem_ptr, mem_ptr_m) - if cast_m is not None: - elem_ptr = cast_m - HandlesVar.define_var( - trans.SymTab, bind_name, elem_ptr) - j = j + 1 - - # ============================================================ - # _seq_cmp_eq - 序列匹配元素相等比较 - # - # 对齐 lhs/rhs(指针统一 ptrtoint i64,整数位宽统一到较宽者)后 - # 生成 icmp eq,返回 i1 条件。 - # ============================================================ - def _seq_cmp_eq(self, trans: HT.Translator | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - lhs: llvmlite.Value | t.CPtr, - rhs: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: - """对齐 lhs/rhs 后生成 icmp eq(指针统一 ptrtoint i64)""" - if lhs is None or rhs is None or builder is None: - return None - pool: memhub.MemBuddy | t.CPtr = trans.Pool - if HandlesExpr.is_ptr_type(lhs.Ty) != 0 \ - or HandlesExpr.is_ptr_type(rhs.Ty) != 0: - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - if HandlesExpr.is_ptr_type(lhs.Ty) != 0: - lhs = llvmlite.build_ptrtoint(builder, lhs, i64_ty) - if HandlesExpr.is_ptr_type(rhs.Ty) != 0: - rhs = llvmlite.build_ptrtoint(builder, rhs, i64_ty) - lb: int = HandlesExpr.get_llvm_type_bits(lhs.Ty) - rb: int = HandlesExpr.get_llvm_type_bits(rhs.Ty) - if lb != rb and lb != 0 and rb != 0: - if lb < rb: - if lb == 1: - lhs = llvmlite.build_zext(builder, lhs, rhs.Ty) - else: - lhs = llvmlite.build_sext(builder, lhs, rhs.Ty) - else: - if rb == 1: - rhs = llvmlite.build_zext(builder, rhs, lhs.Ty) - else: - rhs = llvmlite.build_sext(builder, rhs, lhs.Ty) - return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, lhs, rhs) - - # ============================================================ - # _handle_sequence_match - 序列匹配(match (a, b): case (x, y): ...) - # - # subject 是 Tuple/List、case 是 MatchSequence 时走此路径(对齐 Python - # 语义,按声明顺序取首个全部元素匹配且 guard 为真的 case 执行): - # 元素 pattern: - # MatchValue v → subject[i] == v - # MatchAs(pattern=None) → _ 通配(恒真) - # MatchStar → 剩余元素通配(恒真) - # IR 结构(check/body 链): - # entry → check0 - # check_i: 匹配条件 → body_i(不满足 → check_{i+1}) - # body_i: → end(c.NoBreak 时 fallthrough 到下一 case body) - # 全不匹配 → default → end - # ============================================================ - def _handle_sequence_match(self, trans: HT.Translator | t.CPtr, - node: ast.Match | t.CPtr, - subject_node: ast.AST | t.CPtr) -> int: - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - func: llvmlite.Function | t.CPtr = trans._cur_func - if builder is None or func is None: - return 0 - # 同主路径:局部记录本 sequence match 的 br end_bb,收尾覆盖 - # _ctrl_merge_reachable,消除 case 体内嵌套控制流污染 - sq_merge_reach: int = 0 - - # 1. 求值 subject 各元素 - elts: list[ast.AST | t.CPtr] | t.CPtr = None - if subject_node.kind() == ast.ASTKind.Tuple: - st: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(subject_node) - if st is not None: - elts = st.elts - elif subject_node.kind() == ast.ASTKind.List: - sl2: ast.List | t.CPtr = (ast.List | t.CPtr)(subject_node) - if sl2 is not None: - elts = sl2.elts - if elts is None: - return 0 - ecount: t.CSizeT = len(elts) - if ecount == 0: - return 0 - subj_vals: t.CSizeT | t.CPtr = pool.alloc(8 * ecount) - if subj_vals is None: - return 0 - for ei in range(ecount): - elt: ast.AST | t.CPtr = elts.get(ei) - sv: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, elt, - trans._funcs, trans._func_count, trans) - if sv is None: - HandlesType.fatal_error( - elt, f"match 序列元素 {ei} 翻译失败", "TypeError") - subj_vals[ei] = t.CSizeT(sv) - - # 2. 创建 default/end BB - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - name_buf: str = pool.alloc(32) - if name_buf is None: - return 0 - viperlib.snprintf(name_buf, 32, "match.seq.default.%d", cnt) - default_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, name_buf) - viperlib.snprintf(name_buf, 32, "match.seq.end.%d", cnt) - end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, name_buf) - - # 3. 第一遍:收集 case 信息(check/body BB、default 标记、nobreak、guard) - cases_list: list[ast.AST | t.CPtr] | t.CPtr = node.cases - if cases_list is None: - return 0 - case_count: t.CSizeT = len(cases_list) - check_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) - body_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) - def_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) - nb_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) - guard_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) - if check_arr is None or body_arr is None or def_arr is None \ - or nb_arr is None or guard_arr is None: - return 0 - collected: int = 0 - has_default: int = 0 - first_check: int = -1 - i: int = 0 - while i < case_count: - case_node: ast.AST | t.CPtr = cases_list.get(i) - if case_node is None or case_node.kind() != ast.ASTKind.MatchCase: - i = i + 1 - continue - mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node) - pat: ast.AST | t.CPtr = mc.pattern - is_def: int = 0 - if pat is not None: - pk: int = pat.kind() - if pk == ast.ASTKind.MatchAs: - ma0: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(pat) - if ma0.pattern is None: - is_def = 1 - elif pk != ast.ASTKind.MatchSequence: - # fail-fast:序列匹配只接受 MatchSequence / 顶层 _ 通配 - HandlesType.fatal_error( - pat, "序列匹配 case 只支持 (元素) 或 _ 模式", "TypeError") - if is_def == 1: - has_default = 1 - check_arr[collected] = 0 - body_arr[collected] = t.CSizeT(default_bb) - else: - if collected >= MAX_MATCH_CASES: - break - viperlib.snprintf(name_buf, 32, "match.seq.check.%d.%d", cnt, i) - cbb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, name_buf) - viperlib.snprintf(name_buf, 32, "match.seq.body.%d.%d", cnt, i) - bbb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, name_buf) - check_arr[collected] = t.CSizeT(cbb) - body_arr[collected] = t.CSizeT(bbb) - if first_check < 0: - first_check = collected - body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children - nb: int = self._has_no_break(body_list) - def_arr[collected] = is_def - nb_arr[collected] = nb - guard_arr[collected] = t.CSizeT(mc.guard) - collected = collected + 1 - i = i + 1 - - # 4. 入口 → 第一个 check(或 default/end) - if first_check >= 0: - head_bb: llvmlite.BasicBlock | t.CPtr = ( - llvmlite.BasicBlock | t.CPtr)( - t.CVoid(check_arr[first_check], t.CPtr)) - llvmlite.build_br(builder, head_bb) - elif has_default == 1: - llvmlite.build_br(builder, default_bb) - else: - llvmlite.build_br(builder, end_bb) - - # 5. 发射 check 链 - ci: int = 0 - while ci < collected: - if def_arr[ci] == 1: - ci = ci + 1 - continue - cbb2: llvmlite.BasicBlock | t.CPtr = ( - llvmlite.BasicBlock | t.CPtr)( - t.CVoid(check_arr[ci], t.CPtr)) - bbb2: llvmlite.BasicBlock | t.CPtr = ( - llvmlite.BasicBlock | t.CPtr)( - t.CVoid(body_arr[ci], t.CPtr)) - llvmlite.position_at_end(builder, cbb2) - - # 计算匹配条件(元素比较 && guard) - cond: llvmlite.Value | t.CPtr = None - cnode: ast.AST | t.CPtr = cases_list.get(ci) - mc2: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(cnode) - ms: ast.MatchSequence | t.CPtr = ( - ast.MatchSequence | t.CPtr)(mc2.pattern) - pats: list[ast.AST | t.CPtr] | t.CPtr = None - if ms is not None: - pats = ms.patterns - pcount: t.CSizeT = 0 - if pats is not None: - pcount = len(pats) - if pcount != ecount: - # 元素数量不匹配 → 恒假(对齐 Python 语义) - cond = llvmlite.const_int(pool, 1, 0) - else: - for pi in range(ecount): - pat1: ast.AST | t.CPtr = pats.get(pi) - if pat1 is None: - continue - pk1: int = pat1.kind() - if pk1 == ast.ASTKind.MatchValue: - mv: ast.MatchValue | t.CPtr = ( - ast.MatchValue | t.CPtr)(pat1) - pv: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, mv.value, - trans._funcs, trans._func_count, trans) - if pv is None: - HandlesType.fatal_error( - pat1, f"序列模式元素 {pi} 翻译失败", "TypeError") - sv1: llvmlite.Value | t.CPtr = ( - llvmlite.Value | t.CPtr)( - t.CVoid(subj_vals[pi], t.CPtr)) - c1: llvmlite.Value | t.CPtr = self._seq_cmp_eq( - trans, builder, sv1, pv) - if c1 is None: - HandlesType.fatal_error( - pat1, "序列模式元素比较失败", "TypeError") - if cond is None: - cond = c1 - else: - cond = llvmlite.build_and(builder, cond, c1) - elif pk1 == ast.ASTKind.MatchAs: - ma2: ast.MatchAs | t.CPtr = ( - ast.MatchAs | t.CPtr)(pat1) - if ma2.pattern is None: - continue # _ 通配:恒真 - if ma2.name is not None: - # fail-fast:序列模式变量绑定暂不支持 - HandlesType.fatal_error( - pat1, "序列模式变量绑定暂不支持", "NotImplementedError") - elif pk1 == ast.ASTKind.MatchStar: - continue # 剩余元素通配:恒真 - else: - HandlesType.fatal_error( - pat1, "序列模式不支持的 pattern 类型", "TypeError") - # guard(若有):匹配成立且 guard 非零 - g_addr: t.CSizeT = guard_arr[ci] - if g_addr != 0: - gnode: ast.AST | t.CPtr = ( - ast.AST | t.CPtr)(t.CVoid(g_addr, t.CPtr)) - gv: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, gnode, - trans._funcs, trans._func_count, trans) - if gv is None: - HandlesType.fatal_error( - gnode, "match guard 翻译失败", "TypeError") - gbits: int = HandlesExpr.get_llvm_type_bits(gv.Ty) - if gbits == 1: - g1: llvmlite.Value | t.CPtr = gv - else: - gzero: llvmlite.Value | t.CPtr = llvmlite.const_int( - pool, gbits if gbits > 0 else 32, 0) - g1 = llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, gv, gzero) - if cond is None: - cond = g1 - else: - cond = llvmlite.build_and(builder, cond, g1) - if cond is None: - cond = llvmlite.const_int(pool, 1, 1) - - # 下一个 check(或 default/end) - nxt: llvmlite.BasicBlock | t.CPtr = None - nj: int = ci + 1 - while nj < collected and def_arr[nj] == 1: - nj = nj + 1 - if nj < collected: - nxt = (llvmlite.BasicBlock | t.CPtr)( - t.CVoid(check_arr[nj], t.CPtr)) - elif has_default == 1: - nxt = default_bb - else: - nxt = end_bb - llvmlite.build_cond_br(builder, cond, bbb2, nxt) - ci = ci + 1 - - # 6. 翻译 case body - ci = 0 - while ci < collected: - if def_arr[ci] == 1: - ci = ci + 1 - continue - bbb3: llvmlite.BasicBlock | t.CPtr = ( - llvmlite.BasicBlock | t.CPtr)( - t.CVoid(body_arr[ci], t.CPtr)) - llvmlite.position_at_end(builder, bbb3) - cnode2: ast.AST | t.CPtr = cases_list.get(ci) - mc3: ast.MatchCase | t.CPtr = ( - ast.MatchCase | t.CPtr)(cnode2) - HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH) - body_list2: list[ast.AST | t.CPtr] | t.CPtr = mc3.children - if body_list2 is not None: - bc: t.CSizeT = len(body_list2) - bi: int = 0 - while bi < bc: - stmt: ast.AST | t.CPtr = body_list2.get(bi) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - bi = bi + 1 - HandlesVar.exit_scope(trans.SymTab) - # 末句控制流全 return → 补 unreachable(不 br end,无 fallthrough) - if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ - and self._case_tail_unreachable(trans, builder, body_list2) == 0: - if nb_arr[ci] == 0: - llvmlite.build_br(builder, end_bb) - else: - # c.NoBreak:fallthrough 到下一个 case body(跳过模式检查) - nj2: int = ci + 1 - while nj2 < collected and def_arr[nj2] == 1: - nj2 = nj2 + 1 - if nj2 < collected: - nbb: llvmlite.BasicBlock | t.CPtr = ( - llvmlite.BasicBlock | t.CPtr)( - t.CVoid(body_arr[nj2], t.CPtr)) - llvmlite.build_br(builder, nbb) - elif has_default == 1: - llvmlite.build_br(builder, default_bb) - else: - llvmlite.build_br(builder, end_bb) - trans._ctrl_merge_reachable = 1 - sq_merge_reach = 1 - ci = ci + 1 - - # 7. default 块 - llvmlite.position_at_end(builder, default_bb) - dbody: list[ast.AST | t.CPtr] | t.CPtr = None - if has_default == 1: - di: int = 0 - while di < collected: - if def_arr[di] == 1: - dnode: ast.AST | t.CPtr = cases_list.get(di) - if dnode is not None: - dmc: ast.MatchCase | t.CPtr = ( - ast.MatchCase | t.CPtr)(dnode) - HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH) - dbody = dmc.children - if dbody is not None: - dn: t.CSizeT = len(dbody) - dj: int = 0 - while dj < dn: - stmt: ast.AST | t.CPtr = dbody.get(dj) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - dj = dj + 1 - HandlesVar.exit_scope(trans.SymTab) - break - di = di + 1 - # 末句控制流全 return → 补 unreachable(不 br end_bb) - if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ - and self._case_tail_unreachable(trans, builder, dbody) == 0: - llvmlite.build_br(builder, end_bb) - sq_merge_reach = 1 - - # 8. 定位到 end - llvmlite.position_at_end(builder, end_bb) - # 覆盖嵌套控制流污染(同主路径) - trans._ctrl_merge_reachable = sq_merge_reach - return 0 - - # ============================================================ - # _handle_simple_match - 非 REnum 路径 - # - # subject ptrtoint 到 i32 + switch 分派 - # ============================================================ - def _handle_simple_match(self, trans: HT.Translator | t.CPtr, - node: ast.Match | t.CPtr, - subject_val: llvmlite.Value | t.CPtr) -> int: - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - func: llvmlite.Function | t.CPtr = trans._cur_func - # 同主路径:局部记录本 simple match 的 br end_bb,收尾覆盖 - # _ctrl_merge_reachable,消除 case 体内嵌套控制流污染 - sm_merge_reach: int = 0 - - # 1. subject 转 i32(若已 i32 直接用,否则 ptrtoint) - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - subj_bits: int = HandlesExpr.get_llvm_type_bits(subject_val.Ty) - subj_val: llvmlite.Value | t.CPtr = subject_val - if subj_bits != 32: - if HandlesExpr.is_ptr_type(subject_val.Ty) != 0: - subj_val = llvmlite.build_ptrtoint(builder, subject_val, i32_ty) - elif subj_bits > 32: - # trunc 到 i32 - subj_val = llvmlite.build_trunc(builder, subject_val, i32_ty) - elif subj_bits == 0: - # 未知类型,尝试 ptrtoint - subj_val = llvmlite.build_ptrtoint(builder, subject_val, i32_ty) - if subj_val is None: - # fail-fast: subject 转 i32 失败 - HandlesType.fatal_error(node, "match subject 转换为 i32 失败", "TypeError") - - # 2. 创建 default/end BB - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - name_buf: str = pool.alloc(32) - if name_buf is None: - # fail-fast: 标签缓冲区分配失败 - HandlesType.fatal_error(node, "标签缓冲区分配失败", "TypeError") - viperlib.snprintf(name_buf, 32, "match.default.%d", cnt) - default_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, name_buf) - viperlib.snprintf(name_buf, 32, "match.end.%d", cnt) - end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, name_buf) - - # 3. 收集 case 信息 - cases_list: list[ast.AST | t.CPtr] | t.CPtr = node.cases - if cases_list is None: - # fail-fast: match cases 缺失 - HandlesType.fatal_error(node, "match cases 缺失", "TypeError") - case_count: t.CSizeT = len(cases_list) - - bb_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) - cv_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) - def_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) - nb_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) - if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None: - # fail-fast: match 分派数组分配失败 - HandlesType.fatal_error(node, "match 分派数组分配失败", "TypeError") - - collected: int = 0 - has_default: int = 0 - sw_head: llvmlite.SwitchCase | t.CPtr = None - sw_tail: llvmlite.SwitchCase | t.CPtr = None - sw_count: int = 0 - - # 4. 第一遍:收集 + 创建 BB + 构建链表 - i: int = 0 - while i < case_count: - case_node: ast.AST | t.CPtr = cases_list.get(i) - if case_node is None: - i = i + 1 - continue - if case_node.kind() != ast.ASTKind.MatchCase: - i = i + 1 - continue - mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node) - pat: ast.AST | t.CPtr = mc.pattern - - is_def: int = 0 - cv: llvmlite.Value | t.CPtr = None - - if pat is not None: - pk: int = pat.kind() - if pk == ast.ASTKind.MatchValue: - mv: ast.MatchValue | t.CPtr = (ast.MatchValue | t.CPtr)(pat) - cv = HandlesExpr.translate_value( - builder, pool, trans.Module, mv.value, - trans._funcs, trans._func_count, trans) - elif pk == ast.ASTKind.MatchSingleton: - ms: ast.MatchSingleton | t.CPtr = ( - ast.MatchSingleton | t.CPtr)(pat) - # None -> 0 - cv = llvmlite.const_int32(pool, 0) - elif pk == ast.ASTKind.MatchAs: - ma: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(pat) - if ma.pattern is None: - is_def = 1 - has_default = 1 - elif pk == ast.ASTKind.MatchOr: - mo: ast.MatchOr | t.CPtr = (ast.MatchOr | t.CPtr)(pat) - pats: list[ast.AST | t.CPtr] | t.CPtr = mo.patterns - if pats is not None and len(pats) > 0: - first_pat: ast.AST | t.CPtr = pats.get(0) - if first_pat is not None \ - and first_pat.kind() == ast.ASTKind.MatchValue: - mv2: ast.MatchValue | t.CPtr = ( - ast.MatchValue | t.CPtr)(first_pat) - cv = HandlesExpr.translate_value( - builder, pool, trans.Module, mv2.value, - trans._funcs, trans._func_count, trans) - - if is_def == 0: - if collected >= MAX_MATCH_CASES: - break - viperlib.snprintf(name_buf, 32, "match.case.%d.%d", cnt, i) - bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, name_buf) - else: - bb = default_bb - - body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children - nb: int = self._has_no_break(body_list) - - if collected < MAX_MATCH_CASES: - bb_arr[collected] = t.CSizeT(bb) - cv_arr[collected] = t.CSizeT(cv) - def_arr[collected] = is_def - nb_arr[collected] = nb - collected = collected + 1 - - if is_def == 0 and cv is not None: - sc: llvmlite.SwitchCase | t.CPtr = llvmlite.new_switch_case( - pool, cv, bb) - if sc is not None: - if sw_head is None: - sw_head = sc - sw_tail = sc - else: - sw_tail.Next = sc - sw_tail = sc - sw_count = sw_count + 1 - - i = i + 1 - - # 5. 发射 switch - llvmlite.build_switch(builder, subj_val, default_bb, sw_head, sw_count) - - # 6. 第二遍:翻译 case body - i = 0 - while i < collected: - case_node: ast.AST | t.CPtr = cases_list.get(i) - if case_node is None: - i = i + 1 - continue - mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node) - - bb_addr: t.CSizeT = bb_arr[i] - case_bb: llvmlite.BasicBlock | t.CPtr = ( - llvmlite.BasicBlock | t.CPtr)(t.CVoid(bb_addr, t.CPtr)) - is_def: int = def_arr[i] - nb: int = nb_arr[i] - - # default case 的 body 在 step 7 单独翻译,这里跳过避免重复 - if is_def == 1: - i = i + 1 - continue - - llvmlite.position_at_end(builder, case_bb) - - HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH) - - body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children - if body_list is not None: - bc: t.CSizeT = len(body_list) - bi: int = 0 - while bi < bc: - stmt: ast.AST | t.CPtr = body_list.get(bi) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - bi = bi + 1 - - HandlesVar.exit_scope(trans.SymTab) - - # 末句控制流全 return → 补 unreachable(不 br end_bb) - if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ - and nb == 0 \ - and self._case_tail_unreachable(trans, builder, body_list) == 0: - llvmlite.build_br(builder, end_bb) - trans._ctrl_merge_reachable = 1 - sm_merge_reach = 1 - - i = i + 1 - - # 7. default 块 - llvmlite.position_at_end(builder, default_bb) - if has_default == 0: - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, end_bb) - trans._ctrl_merge_reachable = 1 - sm_merge_reach = 1 - else: - dbody: list[ast.AST | t.CPtr] | t.CPtr = None - di: int = 0 - while di < collected: - if def_arr[di] == 1: - dcase: ast.AST | t.CPtr = cases_list.get(di) - if dcase is not None: - dmc: ast.MatchCase | t.CPtr = ( - ast.MatchCase | t.CPtr)(dcase) - HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH) - dbody = dmc.children - if dbody is not None: - dn: t.CSizeT = len(dbody) - dj: int = 0 - while dj < dn: - stmt: ast.AST | t.CPtr = dbody.get(dj) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - dj = dj + 1 - HandlesVar.exit_scope(trans.SymTab) - break - di = di + 1 - # 末句控制流全 return → 补 unreachable(不 br end_bb) - if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ - and self._case_tail_unreachable(trans, builder, dbody) == 0: - llvmlite.build_br(builder, end_bb) - trans._ctrl_merge_reachable = 1 - sm_merge_reach = 1 - - # 8. 定位到 end - llvmlite.position_at_end(builder, end_bb) - # 覆盖嵌套控制流污染(同主路径) - trans._ctrl_merge_reachable = sm_merge_reach - return 0 +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.Generator as Generator +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import viperlib +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr + + +# ============================================================ +# MatchGenMixin - match 语句翻译 Mixin(P6 方法化) +# +# 从 HandlesMatch.vp 的 MatchHandle 类迁移(纯移动,逻辑零改动): +# Handle → translate_match(签名加 trans 首参,方法体 self.Trans → trans) +# 类内辅助方法 self._xxx → 保持 self.xxx,一并搬入成方法 +# 模块级辅助函数 _case_tail_unreachable → 搬入成方法 +# (原 HandlesMatch 模块级常量 MAX_MATCH_CASES/SCOPE_MATCH 一并复制) +# +# 迁移原则(与 P1-P6 一致,行为零变化): +# 1. 方法保留原逻辑,仅函数体内的 self.Trans 改为 trans 首参 +# 2. 外部模块调用(HandlesExpr.xxx/HandlesBody.xxx 等)保留模块前缀 +# 3. 原 HandlesMatch.translate_match 保留为"委托":本地模块级单例 _g_gen +# (BuildPipeline/main 注入)cast 成 Generator 类型 +# +# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 +# ============================================================ + + +# match case 数量上限(原 HandlesMatch.MAX_MATCH_CASES) +MAX_MATCH_CASES: t.CDefine = 32 + +# 作用域种类常量(与 HandlesVar 的 Scope.Kind 区分,原 HandlesMatch.SCOPE_MATCH) +SCOPE_MATCH: t.CDefine = 6 + + +@t.NoVTable +class MatchGenMixin: + """match 语句翻译 Mixin(P6 方法化)""" + + # ============================================================ + # _case_tail_unreachable - case 体末尾结构性不可达判定 + # + # case 体翻译后当前块若未终止,且末句是控制流语句(If/While/For/Match) + # 且其 merge 结构性不可达(全分支 return,如 case Int(bits): if ... return) + # 时,当前块是控制流的 merge(无 terminator),与 HandlesIf L309-315/ + # ClassGenVTable L1084 同语义补 unreachable。返回 1= 已补 unreachable + # (调用方不应 br end_bb);0= 正常收尾(应 br end_bb)。 + # + # 根因(ClassGenEnum._get_type_align):case 体末句 If 全 return 时,If + # 处理器把 builder 停在无 terminator 的 merge 块,case 循环的 + # is_terminated 检查误判"未终止" → 补 br end_bb → rm_merge_reach=1 → + # 全 case return 的 match 被误判 merge 可达 → 函数收尾 fail-fast + # "流程掉出末尾"。不含 Try/With:其处理器不维护 _ctrl_merge_reachable, + # 避免残留值误判。 + # ============================================================ + Gen: Generator.Generator | t.CPtr + def _case_tail_unreachable(self, trans: HT.Translator | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + body_list: list[ast.AST | t.CPtr] | t.CPtr) -> int: + if trans is None or builder is None: + return 0 + if llvmlite.builder_cur_block_is_terminated(builder) != 0: + return 0 + if body_list is None or len(body_list) == 0: + return 0 + lst: ast.AST | t.CPtr = body_list.get(len(body_list) - 1) + if lst is None: + return 0 + lk: int = lst.kind() + if lk != ast.ASTKind.If and lk != ast.ASTKind.While \ + and lk != ast.ASTKind.For and lk != ast.ASTKind.Match: + return 0 + if trans._ctrl_merge_reachable != 0: + return 0 + llvmlite.build_unreachable(builder) + return 1 + + # ============================================================ + # translate_match - match 语句主入口,返回 0 + # (迁移自 HandlesMatch.MatchHandle.Handle) + # ============================================================ + def translate_match(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + if node is None: + return 0 + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + if builder is None or func is None: + return 0 + + # 追加90:match merge 可达性重置(分派前初始化为 0;各处理函数 + # renum/sequence/simple 内部用各自的局部标志记录 br end_bb 并在 + # 收尾覆盖,见 _handle_renum_match/_handle_sequence_match/ + # _handle_simple_match——切勿把标志声明在 Handle 这里(分派函数), + # 否则子函数引用的同名变量会退化为隐式全局,跨 match 互相污染)。 + trans._ctrl_merge_reachable = 0 + + m_node: ast.Match | t.CPtr = (ast.Match | t.CPtr)(node) + + # 1. 求值 subject + subject_node: ast.AST | t.CPtr = m_node.subject + if subject_node is None: + return 0 + # 序列匹配(match (a, b): case (x, y): ...)走独立路径: + # Tuple/List subject 无法用 translate_value 求值(会返回 None), + # 提前分派到 _handle_sequence_match,避免 fail-fast 误报。 + sk_seq: int = subject_node.kind() + if sk_seq == ast.ASTKind.Tuple or sk_seq == ast.ASTKind.List: + return self._handle_sequence_match(trans, m_node, subject_node) + subject_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, subject_node, + trans._funcs, trans._func_count, trans) + if subject_val is None: + # fail-fast: match subject 翻译失败 + self.Gen.TypeGenErr.fatal_error(subject_node, "match subject 翻译失败", "TypeError") + + # 2. 检测是否 REnum match + is_renum: int = 0 + renum_name: str = None + subject_ptr: llvmlite.Value | t.CPtr = None + + # 2a. 若 subject 是 Name,查变量注解类名 + if subject_node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(subject_node) + if nm.id is not None: + entry: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, nm.id) + if entry is not None and entry.AnnotClassName is not None \ + and self.Gen.ClassGenEnum._is_renum_class_name( + entry.AnnotClassName) != 0: + is_renum = 1 + renum_name = entry.AnnotClassName + subject_ptr = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id) + + # 2b. 若未确定,遍历 cases 查 MatchClass 变体 + if is_renum == 0: + cases_list: list[ast.AST | t.CPtr] | t.CPtr = m_node.cases + if cases_list is not None: + cn: t.CSizeT = len(cases_list) + ci: int = 0 + while ci < cn and is_renum == 0: + case_node: ast.AST | t.CPtr = cases_list.get(ci) + if case_node is not None \ + and case_node.kind() == ast.ASTKind.MatchCase: + mc: ast.MatchCase | t.CPtr = ( + ast.MatchCase | t.CPtr)(case_node) + pat: ast.AST | t.CPtr = mc.pattern + if pat is not None \ + and pat.kind() == ast.ASTKind.MatchClass: + rnm: str = self._extract_renum_name_from_cls(pat) + if rnm is not None \ + and self.Gen.ClassGenEnum._is_renum_class_name(rnm) != 0: + is_renum = 1 + renum_name = rnm + if subject_ptr is None: + subject_ptr = subject_val + ci = ci + 1 + + # 3. 分派 + if is_renum != 0 and subject_ptr is not None: + return self._handle_renum_match(trans, m_node, renum_name, subject_ptr) + return self._handle_simple_match(trans, m_node, subject_val) + + # ============================================================ + # _extract_renum_name_from_cls - 从 MatchClass.cls 提取 REnum 类名 + # + # LLVMType.Ptr -> Attribute(value=Name('LLVMType'), attr='Ptr') -> 'LLVMType' + # llvmlite.LLVMType.Ptr -> Attribute(Attribute(Name('llvmlite'),'LLVMType'),'Ptr') -> 'LLVMType' + # Ptr -> Name('Ptr') -> 遍历查找 + # ============================================================ + def _extract_renum_name_from_cls(self, + pattern: ast.AST | t.CPtr) -> str: + if pattern is None: + return None + mc: ast.MatchClass | t.CPtr = (ast.MatchClass | t.CPtr)(pattern) + cls_node: ast.AST | t.CPtr = mc.cls + if cls_node is None: + return None + # Attribute 形式 + if cls_node.kind() == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cls_node) + if at.value is not None: + if at.value.kind() == ast.ASTKind.Name: + inner_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + return inner_nm.id + if at.value.kind() == ast.ASTKind.Attribute: + inner_at: ast.Attribute | t.CPtr = ( + ast.Attribute | t.CPtr)(at.value) + return inner_at.attr + # Name 形式:遍历所有 REnum 类反查 + if cls_node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cls_node) + return self._find_renum_class_for_variant(nm.id) + return None + + # ============================================================ + # _extract_variant_name_from_cls - 从 MatchClass.cls 提取变体名 + # ============================================================ + def _extract_variant_name_from_cls(self, + pattern: ast.AST | t.CPtr) -> str: + if pattern is None: + return None + mc: ast.MatchClass | t.CPtr = (ast.MatchClass | t.CPtr)(pattern) + cls_node: ast.AST | t.CPtr = mc.cls + if cls_node is None: + return None + if cls_node.kind() == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cls_node) + return at.attr + if cls_node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cls_node) + return nm.id + return None + + # ============================================================ + # _find_renum_class_for_variant - 从变体名反查 REnum 类名 + # + # P5-2 后 REnum 变体表迁入 gen 字段(RenumClassNames/RenumClassCount), + # 模块级 _renum_class_* 已失效,统一委托到 gen._lookup_renum_variant。 + # ============================================================ + def _find_renum_class_for_variant(self, variant_name: str) -> str: + if variant_name is None: + return None + return self.Gen.ClassGenEnum._lookup_renum_variant(variant_name) + + # ============================================================ + # _has_no_break - 检测 case body 是否含 c.NoBreak() 调用 + # + # 遍历 case body 顶层语句,查找 Expr(Call(Attribute(Name('c'), 'NoBreak'))) + # ============================================================ + def _has_no_break(self, body_list: list[ast.AST | t.CPtr] | t.CPtr) -> int: + if body_list is None: + return 0 + n: t.CSizeT = len(body_list) + i: int = 0 + while i < n: + stmt: ast.AST | t.CPtr = body_list.get(i) + if stmt is not None and stmt.kind() == ast.ASTKind.Expr: + expr_node: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(stmt) + val: ast.AST | t.CPtr = expr_node.value + if val is not None and val.kind() == ast.ASTKind.Call: + call_node: ast.Call | t.CPtr = (ast.Call | t.CPtr)(val) + fn: ast.AST | t.CPtr = call_node.func + if fn is not None and fn.kind() == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = ( + ast.Attribute | t.CPtr)(fn) + if at.value is not None \ + and at.value.kind() == ast.ASTKind.Name: + base_nm: ast.Name | t.CPtr = ( + ast.Name | t.CPtr)(at.value) + if base_nm.id is not None \ + and string.strcmp(base_nm.id, "c") == 0 \ + and at.attr is not None \ + and string.strcmp(at.attr, "NoBreak") == 0: + return 1 + i = i + 1 + return 0 + + # ============================================================ + # _handle_renum_match - REnum 路径 + # + # 1. bitcast subject 到 i32* 读 __tag + # 2. 收集 case 值 + 创建 BB + 构建 SwitchCase 链表 + # 3. 发射 build_switch + # 4. 翻译每个 case body(含作用域隔离 + 变体字段绑定) + # ============================================================ + def _handle_renum_match(self, trans: HT.Translator | t.CPtr, + node: ast.Match | t.CPtr, + renum_name: str, + subject_ptr: llvmlite.Value | t.CPtr) -> int: + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + # 局部记录本 renum match 是否有 br 进入 end_bb,收尾时覆盖 + # _ctrl_merge_reachable(case 体内嵌套 If 无 else + return 会把全局 + # 标志置 1,全 case return 的 match 被误判 merge 可达 → 函数收尾 + # fail-fast "流程掉出末尾"。声明必须在本函数内——放 Handle 分派 + # 函数里会使本函数引用退化为隐式全局,跨 match 污染)。 + rm_merge_reach: int = 0 + + # 0. subject 归一化:确保 subject_ptr 是指向 REnum 结构体的指针 + # (对齐 TPC HandlesMatch.py:238-259 的 _HandleRenumMatchLlvm) + # 情况1: subject_ptr 是 T**(变量 alloca)→ load 一次得 T* + # 情况2: subject_ptr 不是指针(值型,如 REnum payload 槽位 load 出的 i64) + # → alloca REnum 结构体 + store 值 + 用 alloca 指针 + # 情况3: 指针但 pointee 不是结构体 → bitcast 到 REnum 结构体指针 + subj_ty: llvmlite.LLVMType | t.CPtr = subject_ptr.Ty + if subj_ty is not None and self.Gen.ExprGenBase.is_ptr_type(subj_ty) != 0 \ + and subj_ty.Pointee is not None \ + and self.Gen.ExprGenBase.is_ptr_type(subj_ty.Pointee) != 0: + # 情况1: T** → load 一次得 T* + loaded_sub: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, subj_ty.Pointee, subject_ptr) + if loaded_sub is not None: + subject_ptr = loaded_sub + # 情况2: 值型 subject(非指针)→ inttoptr 转回指针 + # 值型 subject 来自 REnum payload 槽位 load(槽位类型 i64,存的是指针), + # 所以直接 inttoptr 到 renum_sty* 即可,无需 alloca+store + if subject_ptr.Ty is None or self.Gen.ExprGenBase.is_ptr_type(subject_ptr.Ty) == 0: + renum_se: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct( + renum_name) + renum_sty: llvmlite.LLVMType | t.CPtr = None + if renum_se is not None: + renum_sty = renum_se.Ty + if renum_sty is None: + # fail-fast: REnum 结构体未注册,无法构造 + self.Gen.TypeGenErr.fatal_error( + node, + f"REnum 结构体 '{renum_name}' 未注册", + "NameError") + i64_ty0: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + int_val: llvmlite.Value | t.CPtr = subject_ptr + # 非 i64 整数值先扩展/截断到 i64(inttoptr 要求同宽) + # 仅当 subj_ty 是已知整数类型时转换;类型未知时保持原值 + if subj_ty is not None and self.Gen.ExprGenBase.get_llvm_type_bits(subj_ty) != 64 \ + and self.Gen.ExprGenBase.is_ptr_type(subj_ty) == 0: + if self.Gen.ExprGenBase.get_llvm_type_bits(subj_ty) > 64: + int_val = llvmlite.build_trunc(builder, subject_ptr, i64_ty0) + else: + int_val = llvmlite.build_zext(builder, subject_ptr, i64_ty0) + renum_ptr_ty0: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, renum_sty) + subj_ptr0: llvmlite.Value | t.CPtr = llvmlite.build_inttoptr( + builder, int_val, renum_ptr_ty0) + if subj_ptr0 is not None: + subject_ptr = subj_ptr0 + + # 1. bitcast subject 到 i32* 读 __tag + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i32_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty) + tag_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, subject_ptr, i32_ptr_ty) + if tag_ptr is None: + # fail-fast: REnum tag 指针转换失败 + self.Gen.TypeGenErr.fatal_error(node, "REnum tag 指针转换失败", "TypeError") + tag_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i32_ty, tag_ptr) + if tag_val is None: + # fail-fast: REnum tag 读取失败 + self.Gen.TypeGenErr.fatal_error(node, "REnum tag 读取失败", "TypeError") + + # 2. 创建 default/end BB + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + name_buf: str = pool.alloc(32) + if name_buf is None: + # fail-fast: 标签缓冲区分配失败 + self.Gen.TypeGenErr.fatal_error(node, "标签缓冲区分配失败", "TypeError") + viperlib.snprintf(name_buf, 32, "match.default.%d", cnt) + default_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, name_buf) + viperlib.snprintf(name_buf, 32, "match.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, name_buf) + + # 3. 准备收集数组(用 CSizeT 数组存指针) + cases_list: list[ast.AST | t.CPtr] | t.CPtr = node.cases + if cases_list is None: + # fail-fast: match cases 缺失 + self.Gen.TypeGenErr.fatal_error(node, "match cases 缺失", "TypeError") + case_count: t.CSizeT = len(cases_list) + + # BB 指针数组、case 值指针数组、default 标记数组、nobreak 标记数组 + bb_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) + cv_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) + def_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) + nb_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) + if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None: + # fail-fast: match 分派数组分配失败 + self.Gen.TypeGenErr.fatal_error(node, "match 分派数组分配失败", "TypeError") + + collected: int = 0 + has_default: int = 0 + + # SwitchCase 链表 + sw_head: llvmlite.SwitchCase | t.CPtr = None + sw_tail: llvmlite.SwitchCase | t.CPtr = None + sw_count: int = 0 + + # 4. 第一遍:收集 case 信息 + 创建 BB + 构建链表 + i: int = 0 + while i < case_count: + case_node: ast.AST | t.CPtr = cases_list.get(i) + if case_node is None: + i = i + 1 + continue + if case_node.kind() != ast.ASTKind.MatchCase: + i = i + 1 + continue + mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node) + pat: ast.AST | t.CPtr = mc.pattern + + is_def: int = 0 + cv: llvmlite.Value | t.CPtr = None + + if pat is not None: + pk: int = pat.kind() + if pk == ast.ASTKind.MatchClass: + vnm: str = self._extract_variant_name_from_cls(pat) + if vnm is not None: + tag: int = self.Gen.ClassGenEnum._lookup_renum_variant_in_class( + renum_name, vnm) + if tag >= 0: + tag_buf: str = pool.alloc(32) + if tag_buf is not None: + viperlib.snprintf(tag_buf, 32, "%d", tag) + cv = llvmlite.ConstInt(pool, i32_ty, tag, + tag_buf if tag_buf is not None else "0") + elif pk == ast.ASTKind.MatchAs: + ma: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(pat) + if ma.pattern is None: + is_def = 1 + has_default = 1 + elif pk == ast.ASTKind.MatchValue: + mv: ast.MatchValue | t.CPtr = (ast.MatchValue | t.CPtr)(pat) + cv = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, mv.value, + trans._funcs, trans._func_count, trans) + elif pk == ast.ASTKind.MatchOr: + # MatchOr: 多个值共享一个 BB(取第一个值做 case) + mo: ast.MatchOr | t.CPtr = (ast.MatchOr | t.CPtr)(pat) + pats: list[ast.AST | t.CPtr] | t.CPtr = mo.patterns + if pats is not None and len(pats) > 0: + first_pat: ast.AST | t.CPtr = pats.get(0) + if first_pat is not None \ + and first_pat.kind() == ast.ASTKind.MatchValue: + mv2: ast.MatchValue | t.CPtr = ( + ast.MatchValue | t.CPtr)(first_pat) + cv = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, mv2.value, + trans._funcs, trans._func_count, trans) + + # 创建 case BB + if is_def == 0: + if collected >= MAX_MATCH_CASES: + break + viperlib.snprintf(name_buf, 32, "match.case.%d.%d", cnt, i) + bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, name_buf) + else: + bb = default_bb + + # 检测 NoBreak + body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children + nb: int = self._has_no_break(body_list) + + # 存入数组 + if collected < MAX_MATCH_CASES: + bb_arr[collected] = t.CSizeT(bb) + cv_arr[collected] = t.CSizeT(cv) + def_arr[collected] = is_def + nb_arr[collected] = nb + collected = collected + 1 + + # 构建 SwitchCase 链表(非 default case 且有值) + if is_def == 0 and cv is not None: + sc: llvmlite.SwitchCase | t.CPtr = llvmlite.new_switch_case( + pool, cv, bb) + if sc is not None: + if sw_head is None: + sw_head = sc + sw_tail = sc + else: + sw_tail.Next = sc + sw_tail = sc + sw_count = sw_count + 1 + + i = i + 1 + + # 5. 发射 switch 指令 + llvmlite.build_switch(builder, tag_val, default_bb, sw_head, sw_count) + + # 6. 查找 REnum 结构体类型(用于变体字段绑定的 GEP) + renum_entry: GenTypes.StructEntry | t.CPtr = None + renum_ty: llvmlite.LLVMType | t.CPtr = None + se: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(renum_name) + if se is not None: + renum_entry = se + renum_ty = se.Ty + + # 7. 第二遍:翻译每个 case body + i = 0 + while i < collected: + case_node: ast.AST | t.CPtr = cases_list.get(i) + if case_node is None: + i = i + 1 + continue + mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node) + pat: ast.AST | t.CPtr = mc.pattern + + # 取 BB + bb_addr: t.CSizeT = bb_arr[i] + case_bb: llvmlite.BasicBlock | t.CPtr = ( + llvmlite.BasicBlock | t.CPtr)(t.CVoid(bb_addr, t.CPtr)) + is_def: int = def_arr[i] + nb: int = nb_arr[i] + + # default case 的 body 在 step 8 单独翻译,这里跳过避免重复 + if is_def == 1: + i = i + 1 + continue + + # 定位到 case BB + llvmlite.position_at_end(builder, case_bb) + + # 进入 case 作用域(变体字段绑定隔离) + self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH) + + # 变体字段绑定(MatchClass) + if pat is not None and pat.kind() == ast.ASTKind.MatchClass \ + and renum_entry is not None and renum_ty is not None: + self._bind_variant_fields( + pat, renum_name, renum_entry, renum_ty, + subject_ptr, trans, pool, builder) + + # 翻译 case body + body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children + if body_list is not None: + bc: t.CSizeT = len(body_list) + bi: int = 0 + while bi < bc: + stmt: ast.AST | t.CPtr = body_list.get(bi) + if stmt is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt) + bi = bi + 1 + + # 退出 case 作用域 + self.Gen.VarGen.exit_scope(trans.SymTab) + + # 若未终止且无 NoBreak,跳到 end + # 末句控制流全 return(结构性不可达)时补 unreachable,不 br end_bb + if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ + and nb == 0 \ + and self._case_tail_unreachable(trans, builder, body_list) == 0: + llvmlite.build_br(builder, end_bb) + trans._ctrl_merge_reachable = 1 + rm_merge_reach = 1 + + i = i + 1 + + # 8. 处理 default 块 + llvmlite.position_at_end(builder, default_bb) + if has_default == 0: + # 无显式 default:default 直接跳 end + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, end_bb) + trans._ctrl_merge_reachable = 1 + rm_merge_reach = 1 + else: + # 有显式 default:翻译 default case body(找到 is_def==1 的 case) + dbody: list[ast.AST | t.CPtr] | t.CPtr = None + di: int = 0 + while di < collected: + if def_arr[di] == 1: + dcase: ast.AST | t.CPtr = cases_list.get(di) + if dcase is not None: + dmc: ast.MatchCase | t.CPtr = ( + ast.MatchCase | t.CPtr)(dcase) + self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH) + dbody = dmc.children + if dbody is not None: + dn: t.CSizeT = len(dbody) + dj: int = 0 + while dj < dn: + stmt: ast.AST | t.CPtr = dbody.get(dj) + if stmt is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt) + dj = dj + 1 + self.Gen.VarGen.exit_scope(trans.SymTab) + break + di = di + 1 + # 末句控制流全 return → 补 unreachable(不 br end_bb) + if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ + and self._case_tail_unreachable(trans, builder, dbody) == 0: + llvmlite.build_br(builder, end_bb) + trans._ctrl_merge_reachable = 1 + rm_merge_reach = 1 + + # 9. 定位到 end 块 + llvmlite.position_at_end(builder, end_bb) + # 用本 match 自身的 br 记录覆盖,消除 case 体内嵌套控制流对 + # _ctrl_merge_reachable 的污染(全 case return 时应为不可达) + trans._ctrl_merge_reachable = rm_merge_reach + return 0 + + # ============================================================ + # _bind_variant_fields - 绑定 MatchClass 的变体字段 + # + # case LLVMType.Ptr(pointee) 中的 pointee 绑定到 subject 的 payload 字段 + # ============================================================ + def _bind_variant_fields(self, pat: ast.AST | t.CPtr, + renum_name: str, + renum_entry: GenTypes.StructEntry | t.CPtr, + renum_ty: llvmlite.LLVMType | t.CPtr, + subject_ptr: llvmlite.Value | t.CPtr, + trans: HT.Translator | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr): + if pat is None or renum_entry is None or renum_ty is None: + return + mc: ast.MatchClass | t.CPtr = (ast.MatchClass | t.CPtr)(pat) + pats: list[ast.AST | t.CPtr] | t.CPtr = mc.patterns + if pats is None: + return + # bitcast subject_ptr 到 renum_ptr_ty(确保 GEP 类型匹配) + renum_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, renum_ty) + casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, subject_ptr, renum_ptr_ty) + if casted_ptr is None: + casted_ptr = subject_ptr + pn: t.CSizeT = len(pats) + j: int = 0 + while j < pn: + sub_pat: ast.AST | t.CPtr = pats.get(j) + if sub_pat is not None and sub_pat.kind() == ast.ASTKind.MatchAs: + ma: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(sub_pat) + bind_name: str = ma.name + if bind_name is not None: + # 按位置绑定:MatchClass 第 j 个参数 → payload 索引 j+1 + # 对应 TPC HandlesMatch.py:305-306(不依赖字段名大小写匹配) + payload_idx: int = j + 1 + # 字段名查找作为回退(若字段名与 MatchAs 名一致可直接命中) + if payload_idx >= renum_entry.FieldCount: + # class_name 用 CSizeT 指针值比较:必须传 renum_entry.Name + # (注册时 _update_renum_alias_class_ptr 统一后的 perm_pool + # 指针);renum_name(AnnotClassName 等)是不同指针恒不匹配 + # → 恒 -1 → fail-fast 误报(追加73d 同款指针陷阱) + alt_idx: int = self.Gen.ClassGenEnum._lookup_renum_field_alias( + renum_entry.Name, bind_name) + if alt_idx >= 1: + payload_idx = alt_idx + else: + # fail-fast: payload 越界且别名查找失败 + # (node 在本函数不存在——参数是 pat/sub_pat,用 sub_pat + # 定位到具体 MatchAs 模式;TPC Python 语义下未定义名只在 + # 运行时求值才报错,TPV 惰性编译方法体时即 NameError) + self.Gen.TypeGenErr.fatal_error( + sub_pat, + f"REnum 变体字段 '{bind_name}' 在结构体 '{renum_name}' 中越界且别名查找失败", + "TypeError") + # 获取字段类型 + fe: GenTypes.FieldEntry | t.CPtr = ( + self.Gen.StructGen._get_field_entry( + renum_entry, payload_idx)) + field_ty: llvmlite.LLVMType | t.CPtr = None + if fe is not None: + field_ty = fe.Ty + if field_ty is None: + # fail-fast: 变体字段类型缺失,禁止兜底 i8 + self.Gen.TypeGenErr.fatal_error( + sub_pat, + f"REnum 变体字段类型缺失: {bind_name}", + "TypeError") + # GEP 取字段地址 + elem_ptr: llvmlite.Value | t.CPtr = ( + llvmlite.build_gep_struct( + builder, renum_ty, field_ty, + casted_ptr, payload_idx)) + if elem_ptr is None: + # fail-fast: 变体字段地址计算失败 + self.Gen.TypeGenErr.fatal_error( + sub_pat, + f"REnum 变体字段 '{bind_name}' 地址计算失败", + "TypeError") + # 变体成员实际类型(对齐 TPC class_members L300-307/L376-382): + # 注册时别名表存了成员注解解析出的类型(perm_pool 深拷贝)。 + # 用它把槽位地址 bitcast 成 Ptr(成员类型),使绑定变量按成员 + # 类型读 payload——Struct.Name: t.CChar|t.CPtr = i8*,否则按 + # 槽位 i64 读 → is 比较/下标/strlen 等字符串操作翻译失败 + # (CallGenMixin L4631 type_name_sp is not None 根因)。 + # 注意:必须按 (class, 变体名, 位置) 定位——MatchAs 名是局部 + # 变量名(type_name_sp),不是变体字段名(Name),按字段名 + # 查恒不匹配(追加76 第一次修复失效根因);同一 payload 位置 + # 跨变体类型也不同(Int.Bits=i32 vs Struct.Fields=Ptr)。 + # 自引用类型(如 Pointee: LLVMType|t.CPtr)注册期解析失败 → + # 查不到类型 → 回退槽位类型(原始位宽在嵌套 match 中经 + # subject bitcast 仍可用)。 + mem_ty_m: llvmlite.LLVMType | t.CPtr = None + vnt_m: str = self._extract_variant_name_from_cls(pat) + if vnt_m is not None and renum_entry is not None \ + and renum_entry.Name is not None: + mem_ty_m = self.Gen.ClassGenEnum._lookup_renum_member_ty( + renum_entry.Name, vnt_m, payload_idx) + if mem_ty_m is not None: + mem_ptr_m: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, mem_ty_m) + if mem_ptr_m is not None: + cast_m: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, elem_ptr, mem_ptr_m) + if cast_m is not None: + elem_ptr = cast_m + self.Gen.VarGen.define_var( + trans.SymTab, bind_name, elem_ptr) + j = j + 1 + + # ============================================================ + # _seq_cmp_eq - 序列匹配元素相等比较 + # + # 对齐 lhs/rhs(指针统一 ptrtoint i64,整数位宽统一到较宽者)后 + # 生成 icmp eq,返回 i1 条件。 + # ============================================================ + def _seq_cmp_eq(self, trans: HT.Translator | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + lhs: llvmlite.Value | t.CPtr, + rhs: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: + """对齐 lhs/rhs 后生成 icmp eq(指针统一 ptrtoint i64)""" + if lhs is None or rhs is None or builder is None: + return None + pool: memhub.MemBuddy | t.CPtr = trans.Pool + if self.Gen.ExprGenBase.is_ptr_type(lhs.Ty) != 0 \ + or self.Gen.ExprGenBase.is_ptr_type(rhs.Ty) != 0: + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + if self.Gen.ExprGenBase.is_ptr_type(lhs.Ty) != 0: + lhs = llvmlite.build_ptrtoint(builder, lhs, i64_ty) + if self.Gen.ExprGenBase.is_ptr_type(rhs.Ty) != 0: + rhs = llvmlite.build_ptrtoint(builder, rhs, i64_ty) + lb: int = self.Gen.ExprGenBase.get_llvm_type_bits(lhs.Ty) + rb: int = self.Gen.ExprGenBase.get_llvm_type_bits(rhs.Ty) + if lb != rb and lb != 0 and rb != 0: + if lb < rb: + if lb == 1: + lhs = llvmlite.build_zext(builder, lhs, rhs.Ty) + else: + lhs = llvmlite.build_sext(builder, lhs, rhs.Ty) + else: + if rb == 1: + rhs = llvmlite.build_zext(builder, rhs, lhs.Ty) + else: + rhs = llvmlite.build_sext(builder, rhs, lhs.Ty) + return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, lhs, rhs) + + # ============================================================ + # _handle_sequence_match - 序列匹配(match (a, b): case (x, y): ...) + # + # subject 是 Tuple/List、case 是 MatchSequence 时走此路径(对齐 Python + # 语义,按声明顺序取首个全部元素匹配且 guard 为真的 case 执行): + # 元素 pattern: + # MatchValue v → subject[i] == v + # MatchAs(pattern=None) → _ 通配(恒真) + # MatchStar → 剩余元素通配(恒真) + # IR 结构(check/body 链): + # entry → check0 + # check_i: 匹配条件 → body_i(不满足 → check_{i+1}) + # body_i: → end(c.NoBreak 时 fallthrough 到下一 case body) + # 全不匹配 → default → end + # ============================================================ + def _handle_sequence_match(self, trans: HT.Translator | t.CPtr, + node: ast.Match | t.CPtr, + subject_node: ast.AST | t.CPtr) -> int: + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + if builder is None or func is None: + return 0 + # 同主路径:局部记录本 sequence match 的 br end_bb,收尾覆盖 + # _ctrl_merge_reachable,消除 case 体内嵌套控制流污染 + sq_merge_reach: int = 0 + + # 1. 求值 subject 各元素 + elts: list[ast.AST | t.CPtr] | t.CPtr = None + if subject_node.kind() == ast.ASTKind.Tuple: + st: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(subject_node) + if st is not None: + elts = st.elts + elif subject_node.kind() == ast.ASTKind.List: + sl2: ast.List | t.CPtr = (ast.List | t.CPtr)(subject_node) + if sl2 is not None: + elts = sl2.elts + if elts is None: + return 0 + ecount: t.CSizeT = len(elts) + if ecount == 0: + return 0 + subj_vals: t.CSizeT | t.CPtr = pool.alloc(8 * ecount) + if subj_vals is None: + return 0 + for ei in range(ecount): + elt: ast.AST | t.CPtr = elts.get(ei) + sv: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, elt, + trans._funcs, trans._func_count, trans) + if sv is None: + self.Gen.TypeGenErr.fatal_error( + elt, f"match 序列元素 {ei} 翻译失败", "TypeError") + subj_vals[ei] = t.CSizeT(sv) + + # 2. 创建 default/end BB + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + name_buf: str = pool.alloc(32) + if name_buf is None: + return 0 + viperlib.snprintf(name_buf, 32, "match.seq.default.%d", cnt) + default_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, name_buf) + viperlib.snprintf(name_buf, 32, "match.seq.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, name_buf) + + # 3. 第一遍:收集 case 信息(check/body BB、default 标记、nobreak、guard) + cases_list: list[ast.AST | t.CPtr] | t.CPtr = node.cases + if cases_list is None: + return 0 + case_count: t.CSizeT = len(cases_list) + check_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) + body_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) + def_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) + nb_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) + guard_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) + if check_arr is None or body_arr is None or def_arr is None \ + or nb_arr is None or guard_arr is None: + return 0 + collected: int = 0 + has_default: int = 0 + first_check: int = -1 + i: int = 0 + while i < case_count: + case_node: ast.AST | t.CPtr = cases_list.get(i) + if case_node is None or case_node.kind() != ast.ASTKind.MatchCase: + i = i + 1 + continue + mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node) + pat: ast.AST | t.CPtr = mc.pattern + is_def: int = 0 + if pat is not None: + pk: int = pat.kind() + if pk == ast.ASTKind.MatchAs: + ma0: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(pat) + if ma0.pattern is None: + is_def = 1 + elif pk != ast.ASTKind.MatchSequence: + # fail-fast:序列匹配只接受 MatchSequence / 顶层 _ 通配 + self.Gen.TypeGenErr.fatal_error( + pat, "序列匹配 case 只支持 (元素) 或 _ 模式", "TypeError") + if is_def == 1: + has_default = 1 + check_arr[collected] = 0 + body_arr[collected] = t.CSizeT(default_bb) + else: + if collected >= MAX_MATCH_CASES: + break + viperlib.snprintf(name_buf, 32, "match.seq.check.%d.%d", cnt, i) + cbb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, name_buf) + viperlib.snprintf(name_buf, 32, "match.seq.body.%d.%d", cnt, i) + bbb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, name_buf) + check_arr[collected] = t.CSizeT(cbb) + body_arr[collected] = t.CSizeT(bbb) + if first_check < 0: + first_check = collected + body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children + nb: int = self._has_no_break(body_list) + def_arr[collected] = is_def + nb_arr[collected] = nb + guard_arr[collected] = t.CSizeT(mc.guard) + collected = collected + 1 + i = i + 1 + + # 4. 入口 → 第一个 check(或 default/end) + if first_check >= 0: + head_bb: llvmlite.BasicBlock | t.CPtr = ( + llvmlite.BasicBlock | t.CPtr)( + t.CVoid(check_arr[first_check], t.CPtr)) + llvmlite.build_br(builder, head_bb) + elif has_default == 1: + llvmlite.build_br(builder, default_bb) + else: + llvmlite.build_br(builder, end_bb) + + # 5. 发射 check 链 + ci: int = 0 + while ci < collected: + if def_arr[ci] == 1: + ci = ci + 1 + continue + cbb2: llvmlite.BasicBlock | t.CPtr = ( + llvmlite.BasicBlock | t.CPtr)( + t.CVoid(check_arr[ci], t.CPtr)) + bbb2: llvmlite.BasicBlock | t.CPtr = ( + llvmlite.BasicBlock | t.CPtr)( + t.CVoid(body_arr[ci], t.CPtr)) + llvmlite.position_at_end(builder, cbb2) + + # 计算匹配条件(元素比较 && guard) + cond: llvmlite.Value | t.CPtr = None + cnode: ast.AST | t.CPtr = cases_list.get(ci) + mc2: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(cnode) + ms: ast.MatchSequence | t.CPtr = ( + ast.MatchSequence | t.CPtr)(mc2.pattern) + pats: list[ast.AST | t.CPtr] | t.CPtr = None + if ms is not None: + pats = ms.patterns + pcount: t.CSizeT = 0 + if pats is not None: + pcount = len(pats) + if pcount != ecount: + # 元素数量不匹配 → 恒假(对齐 Python 语义) + cond = llvmlite.const_int(pool, 1, 0) + else: + for pi in range(ecount): + pat1: ast.AST | t.CPtr = pats.get(pi) + if pat1 is None: + continue + pk1: int = pat1.kind() + if pk1 == ast.ASTKind.MatchValue: + mv: ast.MatchValue | t.CPtr = ( + ast.MatchValue | t.CPtr)(pat1) + pv: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, mv.value, + trans._funcs, trans._func_count, trans) + if pv is None: + self.Gen.TypeGenErr.fatal_error( + pat1, f"序列模式元素 {pi} 翻译失败", "TypeError") + sv1: llvmlite.Value | t.CPtr = ( + llvmlite.Value | t.CPtr)( + t.CVoid(subj_vals[pi], t.CPtr)) + c1: llvmlite.Value | t.CPtr = self._seq_cmp_eq( + trans, builder, sv1, pv) + if c1 is None: + self.Gen.TypeGenErr.fatal_error( + pat1, "序列模式元素比较失败", "TypeError") + if cond is None: + cond = c1 + else: + cond = llvmlite.build_and(builder, cond, c1) + elif pk1 == ast.ASTKind.MatchAs: + ma2: ast.MatchAs | t.CPtr = ( + ast.MatchAs | t.CPtr)(pat1) + if ma2.pattern is None: + continue # _ 通配:恒真 + if ma2.name is not None: + # fail-fast:序列模式变量绑定暂不支持 + self.Gen.TypeGenErr.fatal_error( + pat1, "序列模式变量绑定暂不支持", "NotImplementedError") + elif pk1 == ast.ASTKind.MatchStar: + continue # 剩余元素通配:恒真 + else: + self.Gen.TypeGenErr.fatal_error( + pat1, "序列模式不支持的 pattern 类型", "TypeError") + # guard(若有):匹配成立且 guard 非零 + g_addr: t.CSizeT = guard_arr[ci] + if g_addr != 0: + gnode: ast.AST | t.CPtr = ( + ast.AST | t.CPtr)(t.CVoid(g_addr, t.CPtr)) + gv: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, gnode, + trans._funcs, trans._func_count, trans) + if gv is None: + self.Gen.TypeGenErr.fatal_error( + gnode, "match guard 翻译失败", "TypeError") + gbits: int = self.Gen.ExprGenBase.get_llvm_type_bits(gv.Ty) + if gbits == 1: + g1: llvmlite.Value | t.CPtr = gv + else: + gzero: llvmlite.Value | t.CPtr = llvmlite.const_int( + pool, gbits if gbits > 0 else 32, 0) + g1 = llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, gv, gzero) + if cond is None: + cond = g1 + else: + cond = llvmlite.build_and(builder, cond, g1) + if cond is None: + cond = llvmlite.const_int(pool, 1, 1) + + # 下一个 check(或 default/end) + nxt: llvmlite.BasicBlock | t.CPtr = None + nj: int = ci + 1 + while nj < collected and def_arr[nj] == 1: + nj = nj + 1 + if nj < collected: + nxt = (llvmlite.BasicBlock | t.CPtr)( + t.CVoid(check_arr[nj], t.CPtr)) + elif has_default == 1: + nxt = default_bb + else: + nxt = end_bb + llvmlite.build_cond_br(builder, cond, bbb2, nxt) + ci = ci + 1 + + # 6. 翻译 case body + ci = 0 + while ci < collected: + if def_arr[ci] == 1: + ci = ci + 1 + continue + bbb3: llvmlite.BasicBlock | t.CPtr = ( + llvmlite.BasicBlock | t.CPtr)( + t.CVoid(body_arr[ci], t.CPtr)) + llvmlite.position_at_end(builder, bbb3) + cnode2: ast.AST | t.CPtr = cases_list.get(ci) + mc3: ast.MatchCase | t.CPtr = ( + ast.MatchCase | t.CPtr)(cnode2) + self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH) + body_list2: list[ast.AST | t.CPtr] | t.CPtr = mc3.children + if body_list2 is not None: + bc: t.CSizeT = len(body_list2) + bi: int = 0 + while bi < bc: + stmt: ast.AST | t.CPtr = body_list2.get(bi) + if stmt is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt) + bi = bi + 1 + self.Gen.VarGen.exit_scope(trans.SymTab) + # 末句控制流全 return → 补 unreachable(不 br end,无 fallthrough) + if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ + and self._case_tail_unreachable(trans, builder, body_list2) == 0: + if nb_arr[ci] == 0: + llvmlite.build_br(builder, end_bb) + else: + # c.NoBreak:fallthrough 到下一个 case body(跳过模式检查) + nj2: int = ci + 1 + while nj2 < collected and def_arr[nj2] == 1: + nj2 = nj2 + 1 + if nj2 < collected: + nbb: llvmlite.BasicBlock | t.CPtr = ( + llvmlite.BasicBlock | t.CPtr)( + t.CVoid(body_arr[nj2], t.CPtr)) + llvmlite.build_br(builder, nbb) + elif has_default == 1: + llvmlite.build_br(builder, default_bb) + else: + llvmlite.build_br(builder, end_bb) + trans._ctrl_merge_reachable = 1 + sq_merge_reach = 1 + ci = ci + 1 + + # 7. default 块 + llvmlite.position_at_end(builder, default_bb) + dbody: list[ast.AST | t.CPtr] | t.CPtr = None + if has_default == 1: + di: int = 0 + while di < collected: + if def_arr[di] == 1: + dnode: ast.AST | t.CPtr = cases_list.get(di) + if dnode is not None: + dmc: ast.MatchCase | t.CPtr = ( + ast.MatchCase | t.CPtr)(dnode) + self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH) + dbody = dmc.children + if dbody is not None: + dn: t.CSizeT = len(dbody) + dj: int = 0 + while dj < dn: + stmt: ast.AST | t.CPtr = dbody.get(dj) + if stmt is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt) + dj = dj + 1 + self.Gen.VarGen.exit_scope(trans.SymTab) + break + di = di + 1 + # 末句控制流全 return → 补 unreachable(不 br end_bb) + if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ + and self._case_tail_unreachable(trans, builder, dbody) == 0: + llvmlite.build_br(builder, end_bb) + sq_merge_reach = 1 + + # 8. 定位到 end + llvmlite.position_at_end(builder, end_bb) + # 覆盖嵌套控制流污染(同主路径) + trans._ctrl_merge_reachable = sq_merge_reach + return 0 + + # ============================================================ + # _handle_simple_match - 非 REnum 路径 + # + # subject ptrtoint 到 i32 + switch 分派 + # ============================================================ + def _handle_simple_match(self, trans: HT.Translator | t.CPtr, + node: ast.Match | t.CPtr, + subject_val: llvmlite.Value | t.CPtr) -> int: + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + # 同主路径:局部记录本 simple match 的 br end_bb,收尾覆盖 + # _ctrl_merge_reachable,消除 case 体内嵌套控制流污染 + sm_merge_reach: int = 0 + + # 1. subject 转 i32(若已 i32 直接用,否则 ptrtoint) + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + subj_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(subject_val.Ty) + subj_val: llvmlite.Value | t.CPtr = subject_val + if subj_bits != 32: + if self.Gen.ExprGenBase.is_ptr_type(subject_val.Ty) != 0: + subj_val = llvmlite.build_ptrtoint(builder, subject_val, i32_ty) + elif subj_bits > 32: + # trunc 到 i32 + subj_val = llvmlite.build_trunc(builder, subject_val, i32_ty) + elif subj_bits == 0: + # 未知类型,尝试 ptrtoint + subj_val = llvmlite.build_ptrtoint(builder, subject_val, i32_ty) + if subj_val is None: + # fail-fast: subject 转 i32 失败 + self.Gen.TypeGenErr.fatal_error(node, "match subject 转换为 i32 失败", "TypeError") + + # 2. 创建 default/end BB + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + name_buf: str = pool.alloc(32) + if name_buf is None: + # fail-fast: 标签缓冲区分配失败 + self.Gen.TypeGenErr.fatal_error(node, "标签缓冲区分配失败", "TypeError") + viperlib.snprintf(name_buf, 32, "match.default.%d", cnt) + default_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, name_buf) + viperlib.snprintf(name_buf, 32, "match.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, name_buf) + + # 3. 收集 case 信息 + cases_list: list[ast.AST | t.CPtr] | t.CPtr = node.cases + if cases_list is None: + # fail-fast: match cases 缺失 + self.Gen.TypeGenErr.fatal_error(node, "match cases 缺失", "TypeError") + case_count: t.CSizeT = len(cases_list) + + bb_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) + cv_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) + def_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) + nb_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) + if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None: + # fail-fast: match 分派数组分配失败 + self.Gen.TypeGenErr.fatal_error(node, "match 分派数组分配失败", "TypeError") + + collected: int = 0 + has_default: int = 0 + sw_head: llvmlite.SwitchCase | t.CPtr = None + sw_tail: llvmlite.SwitchCase | t.CPtr = None + sw_count: int = 0 + + # 4. 第一遍:收集 + 创建 BB + 构建链表 + i: int = 0 + while i < case_count: + case_node: ast.AST | t.CPtr = cases_list.get(i) + if case_node is None: + i = i + 1 + continue + if case_node.kind() != ast.ASTKind.MatchCase: + i = i + 1 + continue + mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node) + pat: ast.AST | t.CPtr = mc.pattern + + is_def: int = 0 + cv: llvmlite.Value | t.CPtr = None + + if pat is not None: + pk: int = pat.kind() + if pk == ast.ASTKind.MatchValue: + mv: ast.MatchValue | t.CPtr = (ast.MatchValue | t.CPtr)(pat) + cv = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, mv.value, + trans._funcs, trans._func_count, trans) + elif pk == ast.ASTKind.MatchSingleton: + ms: ast.MatchSingleton | t.CPtr = ( + ast.MatchSingleton | t.CPtr)(pat) + # None -> 0 + cv = llvmlite.const_int32(pool, 0) + elif pk == ast.ASTKind.MatchAs: + ma: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(pat) + if ma.pattern is None: + is_def = 1 + has_default = 1 + elif pk == ast.ASTKind.MatchOr: + mo: ast.MatchOr | t.CPtr = (ast.MatchOr | t.CPtr)(pat) + pats: list[ast.AST | t.CPtr] | t.CPtr = mo.patterns + if pats is not None and len(pats) > 0: + first_pat: ast.AST | t.CPtr = pats.get(0) + if first_pat is not None \ + and first_pat.kind() == ast.ASTKind.MatchValue: + mv2: ast.MatchValue | t.CPtr = ( + ast.MatchValue | t.CPtr)(first_pat) + cv = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, mv2.value, + trans._funcs, trans._func_count, trans) + + if is_def == 0: + if collected >= MAX_MATCH_CASES: + break + viperlib.snprintf(name_buf, 32, "match.case.%d.%d", cnt, i) + bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, name_buf) + else: + bb = default_bb + + body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children + nb: int = self._has_no_break(body_list) + + if collected < MAX_MATCH_CASES: + bb_arr[collected] = t.CSizeT(bb) + cv_arr[collected] = t.CSizeT(cv) + def_arr[collected] = is_def + nb_arr[collected] = nb + collected = collected + 1 + + if is_def == 0 and cv is not None: + sc: llvmlite.SwitchCase | t.CPtr = llvmlite.new_switch_case( + pool, cv, bb) + if sc is not None: + if sw_head is None: + sw_head = sc + sw_tail = sc + else: + sw_tail.Next = sc + sw_tail = sc + sw_count = sw_count + 1 + + i = i + 1 + + # 5. 发射 switch + llvmlite.build_switch(builder, subj_val, default_bb, sw_head, sw_count) + + # 6. 第二遍:翻译 case body + i = 0 + while i < collected: + case_node: ast.AST | t.CPtr = cases_list.get(i) + if case_node is None: + i = i + 1 + continue + mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node) + + bb_addr: t.CSizeT = bb_arr[i] + case_bb: llvmlite.BasicBlock | t.CPtr = ( + llvmlite.BasicBlock | t.CPtr)(t.CVoid(bb_addr, t.CPtr)) + is_def: int = def_arr[i] + nb: int = nb_arr[i] + + # default case 的 body 在 step 7 单独翻译,这里跳过避免重复 + if is_def == 1: + i = i + 1 + continue + + llvmlite.position_at_end(builder, case_bb) + + self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH) + + body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children + if body_list is not None: + bc: t.CSizeT = len(body_list) + bi: int = 0 + while bi < bc: + stmt: ast.AST | t.CPtr = body_list.get(bi) + if stmt is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt) + bi = bi + 1 + + self.Gen.VarGen.exit_scope(trans.SymTab) + + # 末句控制流全 return → 补 unreachable(不 br end_bb) + if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ + and nb == 0 \ + and self._case_tail_unreachable(trans, builder, body_list) == 0: + llvmlite.build_br(builder, end_bb) + trans._ctrl_merge_reachable = 1 + sm_merge_reach = 1 + + i = i + 1 + + # 7. default 块 + llvmlite.position_at_end(builder, default_bb) + if has_default == 0: + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, end_bb) + trans._ctrl_merge_reachable = 1 + sm_merge_reach = 1 + else: + dbody: list[ast.AST | t.CPtr] | t.CPtr = None + di: int = 0 + while di < collected: + if def_arr[di] == 1: + dcase: ast.AST | t.CPtr = cases_list.get(di) + if dcase is not None: + dmc: ast.MatchCase | t.CPtr = ( + ast.MatchCase | t.CPtr)(dcase) + self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH) + dbody = dmc.children + if dbody is not None: + dn: t.CSizeT = len(dbody) + dj: int = 0 + while dj < dn: + stmt: ast.AST | t.CPtr = dbody.get(dj) + if stmt is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt) + dj = dj + 1 + self.Gen.VarGen.exit_scope(trans.SymTab) + break + di = di + 1 + # 末句控制流全 return → 补 unreachable(不 br end_bb) + if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ + and self._case_tail_unreachable(trans, builder, dbody) == 0: + llvmlite.build_br(builder, end_bb) + trans._ctrl_merge_reachable = 1 + sm_merge_reach = 1 + + # 8. 定位到 end + llvmlite.position_at_end(builder, end_bb) + # 覆盖嵌套控制流污染(同主路径) + trans._ctrl_merge_reachable = sm_merge_reach + return 0 diff --git a/App/lib/core/Gen/StmtGenCifMixin.vp b/App/lib/core/Gen/StmtGenCifMixin.vp index f6aed3b..3e64e00 100644 --- a/App/lib/core/Gen/StmtGenCifMixin.vp +++ b/App/lib/core/Gen/StmtGenCifMixin.vp @@ -1,2517 +1,2515 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdlib -import stdio -import viperlib -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesFunctions as HandlesFunctions -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesBody as HandlesBody -import lib.core.Handles.ExprCallBase as ExprCallBase -import lib.core.Handles.HandlesIf as HandlesIf -import lib.core.Handles.HandlesWhile as HandlesWhile -import lib.core.Handles.HandlesFor as HandlesFor -import lib.core.Handles.HandlesReturn as HandlesReturn -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesMatch as HandlesMatch -import lib.core.Handles.HandlesEnum as HandlesEnum -import lib.core.CompilerFactory as CompilerFactory -import lib.Projectrans.Config as Config -# ============================================================ -# StmtGenCifMixin - StmtGen 拆分 1/3:CIf 编译期求值 + NewXxxHandle 工厂 -# -# 按功能域从 StmtGenMixin.vp 拆出(500~1500 行/文件架构重构,试点): -# 簇 B(CIf 宏求值)+ NewIfHandle/NewWhileHandle/NewForHandle/ -# NewReturnHandle/NewMatchHandle 工厂。 -# 全部字段保留在本最底层父类(顺序 CifEvalOk->EnumTable->EnumCount-> -# DiagStmtCount 与 Generator 组合布局一致,见下方字段注释)。 -# -# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 -# ============================================================ - - -# ============================================================ -# StmtGenCifMixin - CIf 求值 + 工厂(最底层父类) -# ============================================================ -@t.NoVTable -class StmtGenCifMixin: - """CIf 编译期求值 + NewXxxHandle 工厂(StmtGen 拆分 1/3,最底层)""" - - # --- 编译期 CIf 求值状态(原 HandlesIf._g_cif_eval_ok) --- - # 用 8 字节类型:Mixin 独立布局与 Generator 组合布局的字段对齐必须一致 - # (i32 首字段在组合布局中导致 EnumTable 相对偏移 4 vs 独立布局 8 的错位, - # this_adjust 无法同时修正,枚举表错位到相邻字段被覆盖——ASTCtx 丢失根因)。 - CifEvalOk: t.CSizeT - - # --- 枚举注册表(原 HandlesEnum._enum_table/_enum_count) --- - EnumTable: HandlesEnum.EnumEntry | t.CPtr - EnumCount: int - - # --- OOM 语句级诊断计数(translate_stmt 限频打印 used) --- - DiagStmtCount: int - - # ============================================================ - # 簇 B:编译期 CIf 宏求值(迁移自 HandlesIf.vp 模块级函数) - # ============================================================ - - def _is_cif_attr(self, attr: str) -> int: - """检查方法名是否为 CIf 系(CIf/CIfdef/CIfndef)""" - if attr is None: - return 0 - if string.strcmp(attr, "CIf") == 0: return 1 - if string.strcmp(attr, "CIfdef") == 0: return 1 - if string.strcmp(attr, "CIfndef") == 0: return 1 - return 0 - - def _is_cif_call(self, node: ast.AST | t.CPtr) -> int: - """检查 test 是否为 c.CIf(...)/c.CIfdef(...)/c.CIfndef(...)(或裸 CIf 系)调用""" - if node is None or node.kind() != ast.ASTKind.Call: - return 0 - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) - if cl.func is None: - return 0 - fk: int = cl.func.kind() - if fk == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if at.attr is None: - return 0 - if at.value is not None and at.value.kind() == ast.ASTKind.Name: - vn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if vn.id is not None and string.strcmp(vn.id, "c") == 0: - return self._is_cif_attr(at.attr) - return 0 - if fk == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl.func) - if nm.id is not None and self._is_cif_attr(nm.id) != 0: - return 1 - return 0 - - def _get_platform_macro_value(self, name: str) -> int: - """平台内置宏值(从目标三元组推导,对齐 TPC HandlesIf._get_platform_macros)。 - - 命中置 self.CifEvalOk=1;未命中置 0 返回 0。 - """ - self.CifEvalOk = 0 - if name is None: - return 0 - triple: str = Config.TargetTriple - if triple is None: - triple = "x86_64-pc-windows-gnu" - is_win: int = 0 - is_linux: int = 0 - is_x64: int = 0 - if string.strstr(triple, "windows") is not None \ - or string.strstr(triple, "win32") is not None \ - or string.strstr(triple, "mingw") is not None \ - or string.strstr(triple, "msvc") is not None: - is_win = 1 - if string.strstr(triple, "linux") is not None: - is_linux = 1 - if string.strstr(triple, "x86_64") is not None: - is_x64 = 1 - # 简化:本编译目标为 x86_64 Windows(_WIN64/WIN64 恒与 is_win 一致) - if string.strcmp(name, "_WIN32") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0 - if string.strcmp(name, "WIN32") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0 - if string.strcmp(name, "_WIN64") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0 - if string.strcmp(name, "WIN64") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0 - if string.strcmp(name, "__linux__") == 0: self.CifEvalOk = is_linux; return 1 if is_linux else 0 - if string.strcmp(name, "__x86_64__") == 0: self.CifEvalOk = is_x64; return 1 if is_x64 else 0 - if string.strcmp(name, "__x86_64") == 0: self.CifEvalOk = is_x64; return 1 if is_x64 else 0 - if string.strcmp(name, "_M_X64") == 0: self.CifEvalOk = is_x64; return 1 if is_x64 else 0 - if string.strcmp(name, "SIZEOF_VOID_P") == 0: self.CifEvalOk = 1; return 8 if is_x64 else 4 - if string.strcmp(name, "__SIZEOF_POINTER__") == 0: self.CifEvalOk = 1; return 8 if is_x64 else 4 - if string.strcmp(name, "NDEBUG") == 0: self.CifEvalOk = 1; return 0 - return 0 - - def _cif_name_value(self, pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - name: str) -> int: - """查宏名值: 本地 CDefine → 跨模块 CDefine → 平台宏。 - - 命中置 self.CifEvalOk=1(值 0 也算命中,如 DISABLED=0);未命中置 0。 - """ - self.CifEvalOk = 0 - if name is None or trans is None: - return 0 - v: int = HandlesType.lookup_cdefine_constant(name) - if HandlesType.is_cdefine_found() != 0: - self.CifEvalOk = 1 - return v - v2: int = HandlesExpr._lookup_cross_module_cdefine( - pool, name, trans._from_imports, trans._imported_modules) - if HandlesType.is_cdefine_found() != 0: - self.CifEvalOk = 1 - return v2 - pv: int = self._get_platform_macro_value(name) - if self.CifEvalOk != 0: - return pv - return 0 - - def _cif_attr_value(self, pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - at: ast.Attribute | t.CPtr) -> int: - """Attribute 宏值: platmacro.IS_WINDOWS → 本地 CDefine(attr) → 跨模块 CDefine。 - - 命中置 self.CifEvalOk=1;未命中置 0。 - """ - self.CifEvalOk = 0 - if at is None or at.attr is None or at.value is None or trans is None: - return 0 - if at.value.kind() != ast.ASTKind.Name: - return 0 - vn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if vn.id is None: - return 0 - v: int = HandlesType.lookup_cdefine_constant(at.attr) - if HandlesType.is_cdefine_found() != 0: - self.CifEvalOk = 1 - return v - # 跨模块: 确定真实模块名(解析 from_imports 别名) - real_mod: str = vn.id - if trans._from_imports is not None: - resolved: str = HandlesImports.lookup_from_import( - trans._from_imports, vn.id, 0) - if resolved is not None: - rm_len: t.CSizeT = 0 - while resolved[rm_len] != ' ' and resolved[rm_len] != '\0' and resolved[rm_len] != ':': - rm_len += 1 - rm_buf: str = pool.alloc(rm_len + 1) - if rm_buf is not None: - for rm_i in range(rm_len): - rm_buf[rm_i] = resolved[rm_i] - rm_buf[rm_len] = '\0' - real_mod = rm_buf - fi_len: t.CSizeT = string.strlen(at.attr) + string.strlen(real_mod) + 2 - fi: str = pool.alloc(fi_len) - if fi is None: - return 0 - viperlib.snprintf(fi, fi_len, "%s:%s", at.attr, real_mod) - v2: int = HandlesExpr._lookup_cross_module_cdefine(pool, at.attr, fi) - if HandlesType.is_cdefine_found() != 0: - self.CifEvalOk = 1 - return v2 - return 0 - - def _cif_eval_node(self, pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """递归常量求值 CIf 表达式。 - - 支持: Constant(int) / Name(CDefine/跨模块/平台宏) / Attribute(跨模块 CDefine) - / BinOp(+ - * // % & | ^ << >>) / Compare(== != < > <= >=) - / BoolOp(and/or) / UnaryOp(not - + ~)。 - 成功置 self.CifEvalOk=1;失败(含运行时变量)置 0 返回 0。 - """ - if node is None: - self.CifEvalOk = 0 - return 0 - k: int = node.kind() - if k == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) - if cn.const_kind == ast.CONST_INT: - self.CifEvalOk = 1 - return cn.int_val - self.CifEvalOk = 0 - return 0 - if k == ast.ASTKind.Call: - return self._cif_eval_call(pool, trans, node) - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm.id is None: - self.CifEvalOk = 0 - return 0 - return self._cif_name_value(pool, trans, nm.id) - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - return self._cif_attr_value(pool, trans, at) - if k == ast.ASTKind.UnaryOp: - uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) - if uop.operand is None: - self.CifEvalOk = 0 - return 0 - ov: int = self._cif_eval_node(pool, trans, uop.operand) - if self.CifEvalOk == 0: - return 0 - if uop.op == ast.OpKind.Not: return 1 if ov == 0 else 0 - if uop.op == ast.OpKind.USub: return -ov - if uop.op == ast.OpKind.UAdd: return ov - if uop.op == ast.OpKind.Invert: return ~ov - self.CifEvalOk = 0 - return 0 - if k == ast.ASTKind.BoolOp: - bo: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) - vals: list[ast.AST | t.CPtr] | t.CPtr = bo.values - if vals is None: - self.CifEvalOk = 0 - return 0 - bn: t.CSizeT = len(vals) - if bo.op == ast.OpKind.And: - for bi in range(bn): - rv: int = self._cif_eval_node(pool, trans, vals.get(bi)) - if self.CifEvalOk == 0: - return 0 - if rv == 0: - return 0 - return 1 - if bo.op == ast.OpKind.Or: - for bi in range(bn): - rv: int = self._cif_eval_node(pool, trans, vals.get(bi)) - if self.CifEvalOk == 0: - return 0 - if rv != 0: - return 1 - return 0 - self.CifEvalOk = 0 - return 0 - if k == ast.ASTKind.Compare: - cmp: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) - lv: int = self._cif_eval_node(pool, trans, cmp.left) - if self.CifEvalOk == 0: - return 0 - ops_list: list[t.CInt] | t.CPtr = (list[t.CInt] | t.CPtr)(cmp.ops) - comps: list[ast.AST | t.CPtr] | t.CPtr = cmp.comparators - if ops_list is None or comps is None: - self.CifEvalOk = 0 - return 0 - cc: t.CSizeT = len(comps) - ci: t.CSizeT - for ci in range(cc): - rv: int = self._cif_eval_node(pool, trans, comps.get(ci)) - if self.CifEvalOk == 0: - return 0 - op_id: int = ops_list.get(ci) - ok_cmp: int = 0 - if op_id == ast.OpKind.Eq: ok_cmp = 1 if lv == rv else 0 - elif op_id == ast.OpKind.Ne: ok_cmp = 1 if lv != rv else 0 - elif op_id == ast.OpKind.Lt: ok_cmp = 1 if lv < rv else 0 - elif op_id == ast.OpKind.Le: ok_cmp = 1 if lv <= rv else 0 - elif op_id == ast.OpKind.Gt: ok_cmp = 1 if lv > rv else 0 - elif op_id == ast.OpKind.Ge: ok_cmp = 1 if lv >= rv else 0 - else: - self.CifEvalOk = 0 - return 0 - if ok_cmp == 0: - return 0 - lv = rv - return 1 - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - lv: int = self._cif_eval_node(pool, trans, bop.left) - if self.CifEvalOk == 0: - return 0 - rv: int = self._cif_eval_node(pool, trans, bop.right) - if self.CifEvalOk == 0: - return 0 - if bop.op == ast.OpKind.Add: return lv + rv - if bop.op == ast.OpKind.Sub: return lv - rv - if bop.op == ast.OpKind.Mult: return lv * rv - if bop.op == ast.OpKind.Div: - # 整数常量除法:与 FloorDiv 一致(对齐 TPC ConstEvaluator L354-355) - if rv == 0: - self.CifEvalOk = 0 - return 0 - return lv // rv - if bop.op == ast.OpKind.FloorDiv: - if rv == 0: - self.CifEvalOk = 0 - return 0 - return lv // rv - if bop.op == ast.OpKind.Mod: - if rv == 0: - self.CifEvalOk = 0 - return 0 - return lv % rv - if bop.op == ast.OpKind.BitAnd: return lv & rv - if bop.op == ast.OpKind.BitOr: return lv | rv - if bop.op == ast.OpKind.BitXor: return lv ^ rv - if bop.op == ast.OpKind.LShift: return lv << rv - if bop.op == ast.OpKind.RShift: return lv >> rv - self.CifEvalOk = 0 - return 0 - self.CifEvalOk = 0 - return 0 - - def _eval_ctraits_isptr(self, symtab: HandlesVar.SymbolTable | t.CPtr, - name: str) -> int: - """ctraits.isptr(name) 编译期求值。 - - 按变量实际存储类型判断是否指针:alloca 的 pointee 为 Ptr 即指针 - (与 TPC ConstEvaluator._eval_compile_time_call 的 LLVM 类型判断一致)。 - 返回: 1=指针 0=非指针 -1=无法求值(变量不存在/无类型信息)。 - """ - if name is None or symtab is None: - return -1 - v: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(symtab, name) - if v is None or v.Ty is None: - return -1 - pointee: llvmlite.LLVMType | t.CPtr = v.Ty.Pointee - if pointee is not None and HandlesExpr.is_ptr_type(pointee) != 0: - return 1 - return 0 - - def _cif_eval_call(self, pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """编译期函数调用求值:ctraits.isptr(x)。 - - 命中置 self.CifEvalOk=1 返回 1/0;未识别调用置 0 返回 0。 - """ - self.CifEvalOk = 0 - if node is None or trans is None: - return 0 - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) - if cl is None or cl.func is None: - return 0 - fk: int = cl.func.kind() - if fk != ast.ASTKind.Attribute: - return 0 - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if at.value is None or at.attr is None: - return 0 - if at.value.kind() != ast.ASTKind.Name: - return 0 - vn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if vn.id is None: - return 0 - if string.strcmp(vn.id, "ctraits") != 0 or string.strcmp(at.attr, "isptr") != 0: - return 0 - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cargs is None or len(cargs) < 1: - self.CifEvalOk = 0 - return 0 - arg0: ast.AST | t.CPtr = cargs.get(0) - if arg0 is None or arg0.kind() != ast.ASTKind.Name: - self.CifEvalOk = 0 - return 0 - nm0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0) - if nm0.id is None: - self.CifEvalOk = 0 - return 0 - r: int = self._eval_ctraits_isptr(trans.SymTab, nm0.id) - if r < 0: - self.CifEvalOk = 0 - return 0 - self.CifEvalOk = 1 - return r - - def _evaluate_cif_test(self, pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - test: ast.AST | t.CPtr) -> int: - """求值 CIf 调用(test 必须是 c.CIf 系调用)。 - - 成功: 置 self.CifEvalOk=1,返回条件值(0/1) - 失败(运行时变量/未知结构): 置 self.CifEvalOk=0,返回 0 - """ - self.CifEvalOk = 0 - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(test) - if cl is None or cl.func is None: - return 0 - kind: str = None - fk: int = cl.func.kind() - if fk == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - kind = at.attr - elif fk == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl.func) - kind = nm.id - if kind is None: - return 0 - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cargs is None or len(cargs) < 1: - return 0 - arg0: ast.AST | t.CPtr = cargs.get(0) - if string.strcmp(kind, "CIf") == 0: - v: int = self._cif_eval_node(pool, trans, arg0) - if self.CifEvalOk == 0: - return 0 - return 1 if v != 0 else 0 - # CIfdef / CIfndef: 判定宏名是否已定义 - defined: int = 0 - if arg0 is not None and arg0.kind() == ast.ASTKind.Name: - nm0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0) - if nm0.id is None: - return 0 - self._cif_name_value(pool, trans, nm0.id) - defined = self.CifEvalOk - elif arg0 is not None and arg0.kind() == ast.ASTKind.Constant: - cn0: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg0) - if cn0.const_kind == ast.CONST_STR and cn0.str_val is not None: - self._cif_name_value(pool, trans, cn0.str_val) - defined = self.CifEvalOk - else: - return 0 - elif arg0 is not None and arg0.kind() == ast.ASTKind.Attribute: - at0: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg0) - self._cif_attr_value(pool, trans, at0) - defined = self.CifEvalOk - else: - return 0 - # 定义判定本身成功(未定义名特判:不报错,defined=0 走 else) - self.CifEvalOk = 1 - if string.strcmp(kind, "CIfdef") == 0: - return 1 if defined != 0 else 0 - # CIfndef - return 0 if defined != 0 else 1 - - # ============================================================ - # translate_return - Return 语句翻译(迁移自 HandlesReturn.ReturnHandle.Handle) - # - # 翻译返回值(若有)并生成 ret 指令;裸 return 按函数返回类型生成 - # 默认零值(void→ret void,ptr→null,float→0.0,其余→零值)。 - # ============================================================ - def translate_return(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 Return 语句""" - rt: ast.Return | t.CPtr = (ast.Return | t.CPtr)(node) - if rt is None: - return 0 - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - - val: llvmlite.Value | t.CPtr = None - if rt.value is not None: - # return a, b → 打包匿名 struct 值(多返回值,函数返回类型 tuple[T1,T2]) - if rt.value.kind() == ast.ASTKind.Tuple: - rtp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(rt.value) - rtp_elts: list[ast.AST | t.CPtr] | t.CPtr = rtp.elts - rt_n: t.CSizeT = 0 - if rtp_elts is not None: - rt_n = len(rtp_elts) - if rt_n > 0 and rt_n <= 16: - rt_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 16) - if rt_vals is not None: - rt_val_ok: int = 1 - rt_head: llvmlite.ParamNode | t.CPtr = None - rt_tail: llvmlite.ParamNode | t.CPtr = None - rvi: t.CSizeT - for rvi in range(rt_n): - ev_i: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, rtp_elts.get(rvi), - trans._funcs, trans._func_count, trans) - if ev_i is None: - rt_val_ok = 0 - break - rt_vals[rvi] = t.CSizeT(ev_i) - if rt_val_ok != 0: - # 构建匿名 struct 类型(字段类型 = 元素值类型) - rvi2: t.CSizeT - for rvi2 in range(rt_n): - rv_i: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)( - t.CVoid(rt_vals[rvi2], t.CPtr)) - if rv_i is None or rv_i.Ty is None: - rt_val_ok = 0 - break - rn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, rv_i.Ty) - if rn is None: - rt_val_ok = 0 - break - if rt_head is None: - rt_head = rn - else: - llvmlite.paramnode_set_next(rt_tail, rn) - rt_tail = rn - rt_struct_ty: llvmlite.LLVMType | t.CPtr = None - if rt_val_ok != 0 and rt_head is not None: - rt_struct_ty = llvmlite.Struct(pool, rt_head, rt_n, None) - rt_tmp: llvmlite.Value | t.CPtr = None - if rt_struct_ty is not None: - rt_tmp = llvmlite.build_alloca(builder, rt_struct_ty) - if rt_tmp is not None: - rvi3: t.CSizeT - for rvi3 in range(rt_n): - rv3: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)( - t.CVoid(rt_vals[rvi3], t.CPtr)) - rfp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, rt_struct_ty, rv3.Ty, rt_tmp, rvi3) - if rfp is None: - rt_val_ok = 0 - break - llvmlite.build_store(builder, rv3, rfp) - if rt_val_ok != 0: - val = llvmlite.build_load(builder, rt_struct_ty, rt_tmp) - # return self: 返回 self 指针本身(Ptr(StructTy)),而非结构体值 - # translate_value 会 load 得到结构体值,但 return self 需要指针 - # 注意: lookup_var 返回的是存储 self 的 alloca (Ptr(Ptr(StructTy))) - # 需要 load 得到实际的 self 指针 (Ptr(StructTy)) - if rt.value.kind() == ast.ASTKind.Name: - ret_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rt.value) - if ret_nm is not None and ret_nm.id is not None \ - and string.strcmp(ret_nm.id, "self") == 0: - self_ptr: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, "self") - if self_ptr is not None: - # 检查 self_ptr 是否是 Ptr(Ptr(...))(alloca 存储指针) - self_pointee_ty: llvmlite.LLVMType | t.CPtr = None - match self_ptr.Ty: - case llvmlite.LLVMType.Ptr(inner_ty): - self_pointee_ty = inner_ty - if self_pointee_ty is not None and HandlesExpr.is_ptr_type(self_pointee_ty) != 0: - # Ptr(Ptr(StructTy)) → load 得到 Ptr(StructTy) - val = llvmlite.build_load(builder, self_pointee_ty, self_ptr) - else: - val = self_ptr - if val is None: - val = HandlesExpr.translate_value( - builder, pool, mod, rt.value, - trans._funcs, trans._func_count, trans) - - # val 为 None 时(裸 return):检查当前函数返回类型 - # void 函数(如 __init__/__before_init__)生成 ret void, - # ptr 函数生成 ret ptr null,浮点函数生成 ConstFloat(0.0), - # 否则 ret i32 0(浮点漏处理会报 llc: value doesn't match function result type) - if val is None: - cur_func: llvmlite.Function | t.CPtr = trans._cur_func - is_void_ret: int = 0 - is_ptr_ret: int = 0 - is_float_ret: int = 0 - ret_ty: llvmlite.LLVMType | t.CPtr = None - if cur_func is not None: - ret_ty = llvmlite.function_get_ret_ty(cur_func) - if ret_ty is not None: - match ret_ty: - case llvmlite.LLVMType.Void(): - is_void_ret = 1 - case llvmlite.LLVMType.Ptr(_pe): - is_ptr_ret = 1 - case llvmlite.LLVMType.Float(_fb): - is_float_ret = 1 - if is_void_ret != 0: - llvmlite.build_ret_void(builder) - return 0 - if is_ptr_ret != 0: - null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, ret_ty, "null") - llvmlite.build_ret(builder, null_val) - return 0 - if is_float_ret != 0: - zero_f: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, ret_ty, 0.0) - llvmlite.build_ret(builder, zero_f) - return 0 - if ret_ty is None: - # fail-fast: 裸 return 无法确定函数返回类型,禁止硬编码 i32 零值兜底 - HandlesType.fatal_error(rt, "函数返回类型无法确定", "TypeError") - val = llvmlite.ConstZero(pool, ret_ty) - if val is None: - # fail-fast: 无法按返回类型构造零值 - HandlesType.fatal_error(rt, "函数返回类型无法确定", "TypeError") - - # 类型转换:确保 val 类型与函数返回类型匹配 - # 处理 i1(bool 比较结果)→ i8(t.CBool)等情况 - # i1 → 更宽整数用 zext(bool 语义:1 保持 1,而非 sext 的 0xFF) - # 注意:当 val 是整数而 ret_ty 是 ptr 时(即使 bits 相同,如 i64 vs ptr), - # 也必须 inttoptr 转换,否则 llc 报 "value doesn't match function result type" - cur_func_rt: llvmlite.Function | t.CPtr = trans._cur_func - ret_ty_rt: llvmlite.LLVMType | t.CPtr = None - if cur_func_rt is not None and val is not None and val.Ty is not None: - ret_ty_rt = llvmlite.function_get_ret_ty(cur_func_rt) - if ret_ty_rt is not None: - val_bits: int = HandlesExpr.get_llvm_type_bits(val.Ty) - ret_bits: int = HandlesExpr.get_llvm_type_bits(ret_ty_rt) - val_is_ptr: int = HandlesExpr.is_ptr_type(val.Ty) - ret_is_ptr: int = HandlesExpr.is_ptr_type(ret_ty_rt) - # ptr 类型不一致性:val 是整数但 ret 是 ptr(或反之),必须转换 - if val_is_ptr != ret_is_ptr: - val = HandlesExpr.coerce_to_type(builder, val, ret_ty_rt, node) - elif val_is_ptr != 0 and ret_is_ptr != 0: - # 指针 → 指针且元素类型不同(如 t.CVoid(x, CPtr) 得到 i8*, - # 函数返回类型是类指针 Circle* 时)需 bitcast 回, - # 否则 llc 报 "value doesn't match function result type"。 - val_pointee: llvmlite.LLVMType | t.CPtr = None - ret_pointee: llvmlite.LLVMType | t.CPtr = None - match val.Ty: - case llvmlite.LLVMType.Ptr(v_inner): - val_pointee = v_inner - match ret_ty_rt: - case llvmlite.LLVMType.Ptr(r_inner): - ret_pointee = r_inner - if val_pointee is not None and ret_pointee is not None \ - and t.CUInt64T(val_pointee) != t.CUInt64T(ret_pointee): - val = HandlesExpr.coerce_to_type(builder, val, ret_ty_rt, node) - elif val_bits != 0 and ret_bits != 0 and val_bits != ret_bits: - if val_bits == 1 and val_bits < ret_bits: - val = llvmlite.build_zext(builder, val, ret_ty_rt) - else: - val = HandlesExpr.coerce_to_type(builder, val, ret_ty_rt, node) - llvmlite.build_ret(builder, val) - return 0 - - # ============================================================ - # translate_if - if/elif/else 语句翻译(迁移自 HandlesIf.IfHandle.Handle) - # - # 编译期宏条件: if c.CIf(...) / c.CIfdef(...) / c.CIfndef(...) - # 求值成功 → 只编译命中的分支(剪枝,不发射运行时 IR),elif 递归 - # 求值失败(运行时变量等)→ 回退运行时翻译。 - # 运行时翻译 if 语句为 LLVM IR 控制流: - # br i1 %cond, label %then, label %else - # then: - # ... body ... - # br label %end - # else: - # ... orelse ... - # br label %end - # end: - # ============================================================ - def translate_if(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 if/elif/else 语句""" - if node is None: - return 0 - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - func: llvmlite.Function | t.CPtr = trans._cur_func - - if builder is None or func is None: - return 0 - - if_node: ast.If | t.CPtr = (ast.If | t.CPtr)(node) - - # 0. 编译期宏条件: if c.CIf(...) / c.CIfdef(...) / c.CIfndef(...) - # 求值成功 → 只编译命中的分支(剪枝,不发射运行时 IR),elif 递归 - # 求值失败(运行时变量等)→ 回退运行时翻译 - if self._is_cif_call(if_node.test) == 1: - cif_val: int = self._evaluate_cif_test(pool, trans, if_node.test) - if self.CifEvalOk != 0: - if cif_val != 0: - body_cif: list[ast.AST | t.CPtr] | t.CPtr = if_node.children - if body_cif is not None: - bc_cif: t.CSizeT = len(body_cif) - bi_cif: t.CSizeT - for bi_cif in range(bc_cif): - stmt_cif: ast.AST | t.CPtr = body_cif.get(bi_cif) - if stmt_cif is not None: - HandlesBody.translate_stmt(trans, stmt_cif) - else: - orelse_cif: list[ast.AST | t.CPtr] | t.CPtr = if_node.orelse - if orelse_cif is not None and len(orelse_cif) == 1: - sub_cif: ast.AST | t.CPtr = orelse_cif.get(0) - if sub_cif is not None and sub_cif.kind() == ast.ASTKind.If: - # elif: 递归(子 If 的 test 仍会走 CIf 判定或运行时翻译) - self.translate_if(trans, sub_cif) - elif sub_cif is not None: - HandlesBody.translate_stmt(trans, sub_cif) - elif orelse_cif is not None: - oc_cif: t.CSizeT = len(orelse_cif) - oi_cif: t.CSizeT - for oi_cif in range(oc_cif): - stmt_cif2: ast.AST | t.CPtr = orelse_cif.get(oi_cif) - if stmt_cif2 is not None: - HandlesBody.translate_stmt(trans, stmt_cif2) - return 0 - - # 1. 求值条件表达式 - cond_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, if_node.test, - trans._funcs, trans._func_count, trans) - - # 2. 转换为 i1 条件 - # Compare/Not 表达式已返回 i1,直接使用;指针类型与 null 比较;其他类型与 0 比较 - if cond_val is None: - # fail-fast: if 条件表达式翻译失败 - HandlesType.fatal_error(if_node.test, "if 条件表达式翻译失败", "TypeError") - cond_bits: int = HandlesExpr.get_llvm_type_bits(cond_val.Ty) - if cond_bits == 1: - cond_i1: llvmlite.Value | t.CPtr = cond_val - elif HandlesExpr.is_ptr_type(cond_val.Ty) != 0: - # 指针类型:与 null 比较(不能用整数 0,否则 llc 报 "integer constant must have integer type") - null_cond: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cond_val.Ty, "null") - cond_i1 = llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, cond_val, null_cond) - else: - zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - cond_i1 = llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, cond_val, zero) - - # 3. 创建基本块(使用 trans._label_counter 生成唯一标签名,不与 SSA 名共享) - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - - name_buf: str = pool.alloc(32) - viperlib.snprintf(name_buf, 32, "if.then.%d", cnt) - then_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "if.end.%d", cnt) - merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - # 检查是否有 else 分支 - has_else: int = 0 - orelse_list: list[ast.AST | t.CPtr] | t.CPtr = if_node.orelse - if orelse_list is not None: - if len(orelse_list) > 0: - has_else = 1 - - else_bb: llvmlite.BasicBlock | t.CPtr = None - if has_else == 1: - viperlib.snprintf(name_buf, 32, "if.else.%d", cnt) - else_bb = llvmlite.create_block(pool, func, name_buf) - - # 4. 发射条件分支 - if has_else == 1: - llvmlite.build_cond_br(builder, cond_i1, then_bb, else_bb) - else: - llvmlite.build_cond_br(builder, cond_i1, then_bb, merge_bb) - - # 5. 翻译 then body - # 重置 merge 可达标志:分支内嵌套控制流会覆盖该标志,分支末尾判定依据 - # "分支最后语句的控制流状态",须防进入本 If 前的残留值污染(append90 - # 末句 If 全 return 被 fail-fast 误判"流程掉出末尾"的根因链一环) - trans._ctrl_merge_reachable = 1 - llvmlite.position_at_end(builder, then_bb) - body: list[ast.AST | t.CPtr] | t.CPtr = if_node.children - if body is not None: - body_count: t.CSizeT = len(body) - for bi in range(body_count): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - - # then 块未终止则跳到 merge(记录 then 是否 br 到 merge) - then_branches_merge: int = 0 - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - if trans._ctrl_merge_reachable == 0: - # 分支末尾是嵌套控制流且 merge 结构性不可达(全分支 return): - # 当前块是嵌套的 merge(无 terminator),补 unreachable 收尾。 - # 不补 br merge——否则外层 If 的"分支是否 br merge"判定把不可达 - # 分支当可达,函数末句 If 全 return 被误判"流程掉出末尾" - # (vipermath.vp atan2 根因;对齐 FuncGenDef append90 unreachable) - llvmlite.build_unreachable(builder) - else: - llvmlite.build_br(builder, merge_bb) - then_branches_merge = 1 - - # 6. 翻译 else body(若有) - else_branches_merge: int = 0 - if has_else == 1: - # 同 then:重置标志防残留(else 是普通语句时不被 then 的嵌套控制流值污染) - trans._ctrl_merge_reachable = 1 - llvmlite.position_at_end(builder, else_bb) - else_count: t.CSizeT = len(orelse_list) - for ei in range(else_count): - stmt: ast.AST | t.CPtr = orelse_list.get(ei) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - if trans._ctrl_merge_reachable == 0: - # 嵌套控制流全分支 return:补 unreachable,不 br merge(同 then 分支) - llvmlite.build_unreachable(builder) - else: - llvmlite.build_br(builder, merge_bb) - else_branches_merge = 1 - - # 7. merge 块可达性(追加90,末句控制流收尾判定用): - # 无 else 时 cond_br 直接跳 merge(恒可达);有 else 时任一分支 - # br 到 merge 即可达;全分支 return(无 br)才结构性不可达。 - # 经 HandlesBase 模块级全局传递(避免依赖 Translator 字段表) - trans._ctrl_merge_reachable = 1 - if has_else == 1 and then_branches_merge == 0 and else_branches_merge == 0: - trans._ctrl_merge_reachable = 0 - - # 8. 定位到 merge 块继续后续代码 - llvmlite.position_at_end(builder, merge_bb) - return 0 - - # ============================================================ - # translate_while - while 循环语句翻译(迁移自 HandlesWhile.WhileHandle.Handle) - # - # 翻译 while 语句为 LLVM IR 控制流: - # br label %cond - # cond: - # %t = - # %c = icmp ne i32 %t, 0 - # br i1 %c, label %body, label %end - # body: - # ... body ... - # br label %cond - # end: - # ============================================================ - def translate_while(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 while 循环语句""" - if node is None: - return 0 - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - func: llvmlite.Function | t.CPtr = trans._cur_func - - if builder is None or func is None: - return 0 - - while_node: ast.While | t.CPtr = (ast.While | t.CPtr)(node) - - # 1. 创建基本块: cond / body / end(使用 trans._label_counter,不与 SSA 名共享) - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - - name_buf: str = pool.alloc(32) - viperlib.snprintf(name_buf, 32, "while.cond.%d", cnt) - cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "while.body.%d", cnt) - body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "while.end.%d", cnt) - end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - # 2. 跳转到 cond 块 - llvmlite.build_br(builder, cond_bb) - - # 3. cond 块: 求值条件,条件分支 - llvmlite.position_at_end(builder, cond_bb) - cond_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, while_node.test, - trans._funcs, trans._func_count, trans) - if cond_val is None: - # fail-fast: while 条件表达式翻译失败 - HandlesType.fatal_error(while_node.test, "while 条件表达式翻译失败", "TypeError") - - # Compare/Not 表达式已返回 i1,直接使用;指针类型与 null 比较;其他类型与 0 比较 - cond_bits: int = HandlesExpr.get_llvm_type_bits(cond_val.Ty) - if cond_bits == 1: - cond_i1: llvmlite.Value | t.CPtr = cond_val - elif HandlesExpr.is_ptr_type(cond_val.Ty) != 0: - # 指针类型:与 null 比较(不能用整数 0,否则 llc 报 "integer constant must have integer type") - null_cond: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cond_val.Ty, "null") - cond_i1 = llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, cond_val, null_cond) - else: - zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - cond_i1 = llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, cond_val, zero) - llvmlite.build_cond_br(builder, cond_i1, body_bb, end_bb) - - # 4. body 块: 翻译循环体,跳回 cond - llvmlite.position_at_end(builder, body_bb) - - # 保存旧循环上下文,设置 break/continue 目标 - old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb - old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb - trans._break_bb = end_bb - trans._continue_bb = cond_bb - - body: list[ast.AST | t.CPtr] | t.CPtr = while_node.children - if body is not None: - body_count: t.CSizeT = len(body) - for bi in range(body_count): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - - # 恢复旧循环上下文 - trans._break_bb = old_break - trans._continue_bb = old_continue - - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, cond_bb) - - # 5. 定位到 end 块 - llvmlite.position_at_end(builder, end_bb) - # 追加90:while 的 cond_br 恒引用 end_bb → merge 恒可达(需正常收尾) - trans._ctrl_merge_reachable = 1 - # 无限循环(条件常量真 1/True)且循环体无本层 break → 运行时无任何边 - # 到达 end 块(merge 结构性不可达)→ 置 0,函数收尾对末句 While 生成 - # unreachable(追加90:无 br 到达 merge 时才安全;否则 llc O2 把 - # br-to-unreachable 优化为 fall-through → 双分支执行崩溃)。 - # 修复 vrandom.gammavariate 的 while 1 全 return 被误判"流程掉出末尾"。 - if self._IsConstTrue(while_node.test) != 0 and self._StmtHasBreak(body) == 0: - trans._ctrl_merge_reachable = 0 - return 0 - - # ============================================================ - # 无限循环判定辅助(merge 可达性,迁移自 HandlesWhile 模块级函数) - # - # _IsConstTrue: while 条件为常量真(CONST_INT 非 0 / CONST_BOOL 真) - # _NodeHasBreak / _StmtHasBreak: 扫描本层 break(跳过嵌套 While/For - # 子树——嵌套循环的 break 归内层,不影响外层 merge 可达性) - # ============================================================ - def _IsConstTrue(self, test: ast.AST | t.CPtr) -> int: - """while 条件为常量真(1 / True)返回 1""" - if test is None: - return 0 - if test.kind() == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(test) - if cn.const_kind == ast.CONST_INT and cn.int_val != 0: - return 1 - if cn.const_kind == ast.CONST_BOOL and cn.int_val != 0: - return 1 - return 0 - - def _NodeHasBreak(self, node: ast.AST | t.CPtr) -> int: - """递归扫描节点子树(跳过嵌套 While/For 子树),含 Break 返回 1""" - if node is None: - return 0 - ch: list[ast.AST | t.CPtr] | t.CPtr = node.children - if ch is not None: - n: t.CSizeT = len(ch) - for bi in range(n): - c: ast.AST | t.CPtr = ch.get(bi) - if c is None: - continue - k: int = c.kind() - if k == ast.ASTKind.Break: - return 1 - if k == ast.ASTKind.While or k == ast.ASTKind.For: - continue - if self._NodeHasBreak(c) != 0: - return 1 - return 0 - - def _StmtHasBreak(self, body: list[ast.AST | t.CPtr] | t.CPtr) -> int: - """语句列表是否含本层 break(嵌套循环的 break 归内层)""" - if body is None: - return 0 - n: t.CSizeT = len(body) - for bi in range(n): - s: ast.AST | t.CPtr = body.get(bi) - if s is None: - continue - k: int = s.kind() - if k == ast.ASTKind.Break: - return 1 - if k == ast.ASTKind.While or k == ast.ASTKind.For: - continue - if self._NodeHasBreak(s) != 0: - return 1 - return 0 - - # ============================================================ - # translate_for - for 循环语句翻译(迁移自 HandlesFor.ForHandle.Handle) - # - # 支持 for i in range(start, stop, step) 模式: - # %i = alloca i32 - # store i32 start, i32* %i - # br label %cond - # cond: - # %cur = load i32, i32* %i - # %cmp = icmp slt i32 %cur, stop - # br i1 %cmp, label %body, label %end - # body: - # ... body ... - # br label %incr - # incr: - # %cur2 = load i32, i32* %i - # %next = add i32 %cur2, step - # store i32 %next, i32* %i - # br label %cond - # end: - # ============================================================ - def translate_for(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 for i in range(...) 循环语句""" - if node is None: - return 0 - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - func: llvmlite.Function | t.CPtr = trans._cur_func - - if builder is None or func is None: - return 0 - - for_node: ast.For | t.CPtr = (ast.For | t.CPtr)(node) - - # 1. 获取循环变量(Name 单变量 / Tuple 多变量) - target: ast.AST | t.CPtr = for_node.target - if target is None: - return 0 - tk: int = target.kind() - if tk != ast.ASTKind.Name and tk != ast.ASTKind.Tuple: - return 0 - var_name: str = None - if tk == ast.ASTKind.Name: - target_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) - var_name = target_nm.id - if var_name is None: - return 0 - - # 2. 解析迭代器:支持 range() 和指针迭代 - iter_node: ast.AST | t.CPtr = for_node.iter - if iter_node is None: - return 0 - - # 检查是否是 range() 调用 - is_range_iter: int = 0 - if iter_node.kind() == ast.ASTKind.Call: - call_pre: ast.Call | t.CPtr = (ast.Call | t.CPtr)(iter_node) - fn_pre: str = HandlesExpr.get_func_name(call_pre.func) - if fn_pre is not None: - if string.strcmp(fn_pre, "range") == 0: - is_range_iter = 1 - elif string.strcmp(fn_pre, "enumerate") == 0 or string.strcmp(fn_pre, "zip") == 0: - pass # 多变量迭代,在下方非 range 分支处理 - else: - err_msg: str = pool.alloc(256) - if err_msg is not None: - viperlib.snprintf(err_msg, 256, "仅支持 range()/enumerate()/zip() 或指针迭代,got call '%s'", fn_pre) - HandlesType.fatal_error(iter_node, err_msg) - HandlesType.fatal_error(iter_node, "仅支持 range()/enumerate()/zip() 或指针迭代") - - # 非范围迭代:走指针/数组/列表字面量/容器/多变量迭代路径 - if is_range_iter == 0: - # 列表字面量:按元素顺序迭代(for x in [1, 2, 3]) - if iter_node.kind() == ast.ASTKind.List: - return self._handle_list_literal_iter(trans, for_node, var_name, iter_node) - # enumerate(x):for i, v in enumerate(x)(多变量迭代) - if iter_node.kind() == ast.ASTKind.Call: - call_mi: ast.Call | t.CPtr = (ast.Call | t.CPtr)(iter_node) - fn_mi: str = HandlesExpr.get_func_name(call_mi.func) - if fn_mi is not None and string.strcmp(fn_mi, "enumerate") == 0: - if tk != ast.ASTKind.Tuple: - HandlesType.fatal_error(iter_node, "enumerate 迭代需要两个循环变量 (for i, v in enumerate(x))") - tup_ie: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(target) - t1_buf_ie: bytes = pool.alloc(128) - t2_buf_ie: bytes = pool.alloc(128) - if t1_buf_ie is None or t2_buf_ie is None: - return 0 - t1_buf_ie[0] = '\0' - t2_buf_ie[0] = '\0' - if self._extract_tuple_names(tup_ie, t1_buf_ie, t2_buf_ie) == 0: - HandlesType.fatal_error(iter_node, "enumerate 迭代变量必须是简单名称") - return self._handle_enumerate_iter(trans, for_node, t1_buf_ie, t2_buf_ie, call_mi) - if fn_mi is not None and string.strcmp(fn_mi, "zip") == 0: - if tk != ast.ASTKind.Tuple: - HandlesType.fatal_error(iter_node, "zip 迭代需要两个循环变量 (for a, b in zip(...))") - tup_iz: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(target) - t1_buf_iz: bytes = pool.alloc(128) - t2_buf_iz: bytes = pool.alloc(128) - if t1_buf_iz is None or t2_buf_iz is None: - return 0 - t1_buf_iz[0] = '\0' - t2_buf_iz[0] = '\0' - if self._extract_tuple_names(tup_iz, t1_buf_iz, t2_buf_iz) == 0: - HandlesType.fatal_error(iter_node, "zip 迭代变量必须是简单名称") - return self._handle_zip_iter(trans, for_node, t1_buf_iz, t2_buf_iz, call_mi) - # list[T] 容器变量:按 __count__ 动态长度迭代 - if iter_node.kind() == ast.ASTKind.Name and trans is not None: - nm_lst: ast.Name | t.CPtr = (ast.Name | t.CPtr)(iter_node) - if nm_lst.id is not None: - ve_lst: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm_lst.id) - if ve_lst is not None and ve_lst.AnnotClassName is not None: - # dict 容器变量:按 __count__/__keys__ 布局迭代(__iter__ 协议内联) - if string.strstr(ve_lst.AnnotClassName, "dict") is not None: - lst_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, iter_node, - trans._funcs, trans._func_count, trans) - if lst_val is not None and lst_val.Ty is not None \ - and HandlesExpr.is_ptr_type(lst_val.Ty) != 0: - return self._handle_dict_iter(trans, for_node, var_name, lst_val) - if string.strstr(ve_lst.AnnotClassName, "list") is not None: - lst_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, iter_node, - trans._funcs, trans._func_count, trans) - if lst_val is not None and lst_val.Ty is not None \ - and HandlesExpr.is_ptr_type(lst_val.Ty) != 0: - return self._handle_list_iter(trans, for_node, var_name, lst_val) - # OOP iter 协议:迭代源是类对象且类有 __iter__/__next__ 方法 → - # 走 __iter__/__next__ 调用迭代(对齐 TPC HandlesFor.py L142-166 - # _HandleForIterLlvm)。dict/list 是内置泛型容器已在上方内联处理。 - ov_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, iter_node, - trans._funcs, trans._func_count, trans) - if ov_val is not None and ov_val.Ty is not None \ - and HandlesExpr.is_ptr_type(ov_val.Ty) != 0: - ov_st: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value( - ov_val) - if ov_st is not None: - ov_cn: str = HandlesStruct.get_class_name_by_type(pool, ov_st) - if ov_cn is not None: - oi_lookup: str = pool.alloc(128) - if oi_lookup is not None: - viperlib.snprintf(oi_lookup, 128, "%s.__iter__", ov_cn) - oi_fn: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module( - trans.Module, oi_lookup) - if oi_fn is not None: - on_lookup: str = pool.alloc(128) - if on_lookup is not None: - viperlib.snprintf(on_lookup, 128, "%s.__next__", ov_cn) - on_fn: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module( - trans.Module, on_lookup) - if on_fn is not None: - return self._handle_oop_iter( - trans, for_node, var_name, ov_cn, ov_val) - # 其它不支持的字面量:fast-fail 显式报错, - # 避免 translate_value 触发 list[T] 特化崩溃或语义歧义。 - ik: int = iter_node.kind() - if ik == ast.ASTKind.Constant: - cn_ik: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(iter_node) - if cn_ik.const_kind != ast.CONST_STR: - HandlesType.fatal_error( - iter_node, - "for 迭代不支持该常量(仅支持字符串、数组、列表字面量、range())") - elif ik == ast.ASTKind.Dict or ik == ast.ASTKind.Set or ik == ast.ASTKind.Tuple \ - or ik == ast.ASTKind.SetComp or ik == ast.ASTKind.DictComp: - HandlesType.fatal_error( - iter_node, - "for 迭代不支持字典/集合/元组字面量,请使用 range()、t.CArray 数组或列表字面量") - return self._handle_ptr_iter(trans, for_node, var_name) - - call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(iter_node) - - # 3. 解析 range 参数: range(stop) / range(start, stop) / range(start, stop, step) - args: list[ast.AST | t.CPtr] | t.CPtr = call.args - if args is None: - return 0 - arg_count: t.CSizeT = len(args) - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - start_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - stop_val: llvmlite.Value | t.CPtr = None - step_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) - - if arg_count == 0: - # fail-fast: range 无参数,立即终止 - HandlesType.fatal_error(call, "range 需要至少一个参数", "SyntaxError") - elif arg_count == 1: - stop_val = HandlesExpr.translate_value( - builder, pool, trans.Module, args.get(0), - trans._funcs, trans._func_count, trans) - if stop_val is None: - # fail-fast: range 参数翻译失败 - HandlesType.fatal_error(args.get(0), "range 参数翻译失败", "TypeError") - elif arg_count >= 2: - start_val = HandlesExpr.translate_value( - builder, pool, trans.Module, args.get(0), - trans._funcs, trans._func_count, trans) - if start_val is None: - # fail-fast: range 参数翻译失败 - HandlesType.fatal_error(args.get(0), "range 参数翻译失败", "TypeError") - stop_val = HandlesExpr.translate_value( - builder, pool, trans.Module, args.get(1), - trans._funcs, trans._func_count, trans) - if stop_val is None: - # fail-fast: range 参数翻译失败 - HandlesType.fatal_error(args.get(1), "range 参数翻译失败", "TypeError") - if arg_count >= 3: - step_val = HandlesExpr.translate_value( - builder, pool, trans.Module, args.get(2), - trans._funcs, trans._func_count, trans) - if step_val is None: - # fail-fast: range 参数翻译失败 - HandlesType.fatal_error(args.get(2), "range 参数翻译失败", "TypeError") - # step 为负数字面量时循环条件反转(对齐 TPC HandlesFor.py L86-94): - # range(a, b, -1) → i > stop;range(a, b, +1) → i < stop。 - # TPC 仅识别负数字面量(UnaryOp USub 常量 / 负常量);变量 step 保守按正。 - # 修复 _find_provider 的 range(top-1, -1, -1) 循环体不执行(i < -1 恒假)。 - step_neg_const: int = 0 - if arg_count >= 3: - step_arg_node: ast.AST | t.CPtr = args.get(2) - if step_arg_node is not None: - skn: int = step_arg_node.kind() - if skn == ast.ASTKind.UnaryOp: - uop_r: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(step_arg_node) - if uop_r.op == ast.OpKind.USub and uop_r.operand is not None: - if uop_r.operand.kind() == ast.ASTKind.Constant: - uoc_r: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(uop_r.operand) - if uoc_r.int_val > 0: - step_neg_const = 1 - elif skn == ast.ASTKind.Constant: - skc_r: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(step_arg_node) - if skc_r.int_val < 0: - step_neg_const = 1 - - # 4. 创建/查找循环变量 alloca - var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, var_name) - new_vars: int = 0 - if var_alloca is None: - var_alloca = HandlesVar._alloca_at_entry(builder, i32_ty) - if HandlesVar.define_var( - trans.SymTab, var_name, var_alloca) == 0: - new_vars = 1 - - # 获取循环变量的实际元素类型(alloca 是指针类型,需解引用 Pointee) - # 当循环变量已声明为 i64(如 t.CSizeT),使用 i64 而非硬编码 i32 - # 避免 load i32, i64* / store i32, i64* 类型不匹配 - loop_var_ty: llvmlite.LLVMType | t.CPtr = i32_ty - if var_alloca is not None and var_alloca.Ty is not None: - match var_alloca.Ty: - case llvmlite.LLVMType.Ptr(pointee_ty): - if pointee_ty is not None: - loop_var_ty = pointee_ty - loop_var_bits: int = HandlesExpr.get_llvm_type_bits(loop_var_ty) - - # 5. 存储初始值 (类型对齐: start_val 可能是 i32/i64,需对齐到 loop_var_ty) - init_val: llvmlite.Value | t.CPtr = start_val - if start_val is not None and start_val.Ty is not None: - start_bits: int = HandlesExpr.get_llvm_type_bits(start_val.Ty) - if start_bits != 0 and start_bits != loop_var_bits: - if start_bits < loop_var_bits: - init_val = llvmlite.build_sext(builder, start_val, loop_var_ty) - else: - init_val = llvmlite.build_trunc(builder, start_val, loop_var_ty) - llvmlite.build_store(builder, init_val, var_alloca) - - # 6. 创建基本块: cond / body / incr / end(使用 trans._label_counter,不与 SSA 名共享) - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - - name_buf: str = pool.alloc(32) - viperlib.snprintf(name_buf, 32, "for.cond.%d", cnt) - cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "for.body.%d", cnt) - body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "for.incr.%d", cnt) - incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "for.end.%d", cnt) - end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - # 7. 跳转到 cond 块 - llvmlite.build_br(builder, cond_bb) - - # 8. cond 块: load i, icmp slt i, stop, cond_br body/end - llvmlite.position_at_end(builder, cond_bb) - cur_i: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, loop_var_ty, var_alloca) - # 类型对齐: stop_val 可能是 i64 (如 range(strlen(s))),需将 cur_i 提升到 stop_val 类型 - cmp_lhs: llvmlite.Value | t.CPtr = cur_i - cmp_rhs: llvmlite.Value | t.CPtr = stop_val - if stop_val is not None and stop_val.Ty is not None: - stop_bits: int = HandlesExpr.get_llvm_type_bits(stop_val.Ty) - cur_bits: int = HandlesExpr.get_llvm_type_bits(cur_i.Ty) - if stop_bits != 0 and cur_bits != 0 and stop_bits != cur_bits: - if cur_bits < stop_bits: - cmp_lhs = llvmlite.build_sext(builder, cur_i, stop_val.Ty) - else: - # 循环变量位宽 > stop 位宽(如 t.CSizeT 循环变量 + range(i32)): - # 应把 cur_i 截断到 stop_val 类型(低向高才 sext/zext,高向低用 - # trunc)。原实现反了——把小的 stop_val trunc 到大的 loop_var_ty, - # 生成 `trunc i32 to i64` 扩宽非法 IR,llc 报 - # "invalid cast opcode for cast from 'i32' to 'i64'" - # (VpiReader.vp range(arg_count) 追加86 根因)。 - cmp_lhs = llvmlite.build_trunc(builder, cur_i, stop_val.Ty) - # step 为负时条件反转:i > stop(ICMP_SGT);正/缺省 step 保持 i < stop - range_cmp_op: int = llvmlite.ICMP_SLT - if step_neg_const != 0: - range_cmp_op = llvmlite.ICMP_SGT - cond_i1: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, range_cmp_op, cmp_lhs, cmp_rhs) - llvmlite.build_cond_br(builder, cond_i1, body_bb, end_bb) - - # 9. body 块: 翻译循环体,跳到 incr - llvmlite.position_at_end(builder, body_bb) - - # 保存旧循环上下文,设置 break/continue 目标 - old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb - old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb - trans._break_bb = end_bb - trans._continue_bb = incr_bb - - body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children - if body is not None: - body_count: t.CSizeT = len(body) - for bi in range(body_count): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - - # 恢复旧循环上下文 - trans._break_bb = old_break - trans._continue_bb = old_continue - - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, incr_bb) - - # 10. incr 块: i = i + step, 跳回 cond - llvmlite.position_at_end(builder, incr_bb) - cur_i2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, loop_var_ty, var_alloca) - # 类型对齐: step_val 可能是 i32/i64,需对齐到 loop_var_ty 与 cur_i2 类型一致 - incr_step: llvmlite.Value | t.CPtr = step_val - if step_val is not None and step_val.Ty is not None: - step_bits: int = HandlesExpr.get_llvm_type_bits(step_val.Ty) - cur2_bits: int = HandlesExpr.get_llvm_type_bits(cur_i2.Ty) - if step_bits != 0 and cur2_bits != 0 and step_bits != cur2_bits: - if step_bits > cur2_bits: - incr_step = llvmlite.build_trunc(builder, step_val, loop_var_ty) - else: - incr_step = llvmlite.build_sext(builder, step_val, loop_var_ty) - next_i: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_i2, incr_step) - llvmlite.build_store(builder, next_i, var_alloca) - llvmlite.build_br(builder, cond_bb) - - # 11. 定位到 end 块 - llvmlite.position_at_end(builder, end_bb) - # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) - trans._ctrl_merge_reachable = 1 - return new_vars - - # ============================================================ - # 多变量迭代辅助(enumerate / zip,迁移自 ForHandleBase) - # - # 支持迭代源: range(start, stop, step) / 字符串(常量|变量) / list[T] - # enumerate(x) → for i, v in enumerate(x):i 为序号,v 为元素 - # zip(a, b) → for x, y in zip(a, b):任一源耗尽即终止 - # ============================================================ - def _extract_tuple_names(self, tup: ast.Tuple | t.CPtr, - out1: str | t.CPtr, out2: str | t.CPtr) -> int: - """从 Tuple target 提取前两个 Name 变量名,写入 out1/out2,成功返回 1""" - if tup is None or tup.elts is None or out1 is None or out2 is None: - return 0 - elts: list[ast.AST | t.CPtr] | t.CPtr = tup.elts - n: t.CSizeT = len(elts) - if n < 2: - return 0 - e0: ast.AST | t.CPtr = elts.get(0) - e1: ast.AST | t.CPtr = elts.get(1) - if e0 is None or e1 is None: - return 0 - if e0.kind() != ast.ASTKind.Name or e1.kind() != ast.ASTKind.Name: - return 0 - n0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(e0) - n1: ast.Name | t.CPtr = (ast.Name | t.CPtr)(e1) - if n0.id is None or n1.id is None: - return 0 - string.strcpy(out1, n0.id) - string.strcpy(out2, n1.id) - return 1 - - def _seq_kind(self, trans: HT.Translator | t.CPtr, - src: ast.AST | t.CPtr) -> int: - """判断迭代源类型: SEQ_KIND_RANGE / STR / LIST,不支持返回 0""" - if src is None: - return 0 - k: int = src.kind() - if k == ast.ASTKind.Call: - cl_s: ast.Call | t.CPtr = (ast.Call | t.CPtr)(src) - fn_s: str = HandlesExpr.get_func_name(cl_s.func) - if fn_s is not None and string.strcmp(fn_s, "range") == 0: - return HandlesFor.SEQ_KIND_RANGE - return 0 - if k == ast.ASTKind.Constant: - cn_s: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(src) - if cn_s is not None and cn_s.const_kind == ast.CONST_STR: - return HandlesFor.SEQ_KIND_STR - return 0 - if k == ast.ASTKind.Name: - nm_s: ast.Name | t.CPtr = (ast.Name | t.CPtr)(src) - if nm_s.id is not None and trans is not None: - ve_s: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm_s.id) - if ve_s is not None and ve_s.AnnotClassName is not None: - if string.strstr(ve_s.AnnotClassName, "list") is not None: - return HandlesFor.SEQ_KIND_LIST - return HandlesFor.SEQ_KIND_STR - return 0 - - def _build_seq_loop(self, trans: HT.Translator | t.CPtr, - for_node: ast.For | t.CPtr, - t1: str, t2: str, - src1: ast.AST | t.CPtr, - src2: ast.AST | t.CPtr, - n_srcs: int) -> int: - """生成序列迭代循环(enumerate: n_srcs=1 / zip: n_srcs=2) - - 循环变量 alloca 自动创建或复用;元素类型由源类型决定 - (RANGE→i32, STR→i8, LIST→i8*)。索引内部统一 i64。 - """ - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - func: llvmlite.Function | t.CPtr = trans._cur_func - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - # ---- 源 1 准备 ---- - kind1: int = self._seq_kind(trans, src1) - if kind1 == 0: - HandlesType.fatal_error(for_node, "序列迭代: 源 1 类型不支持") - r1_start: llvmlite.Value | t.CPtr = None - r1_stop: llvmlite.Value | t.CPtr = None - r1_step: llvmlite.Value | t.CPtr = None - s1_ptr: llvmlite.Value | t.CPtr = None - l1_count: llvmlite.Value | t.CPtr = None - l1_data: llvmlite.Value | t.CPtr = None - l1_esize: llvmlite.Value | t.CPtr = None - elem1_ty: llvmlite.LLVMType | t.CPtr = i8_ptr_ty - if kind1 == HandlesFor.SEQ_KIND_RANGE: - elem1_ty = i32_ty - r1_start = llvmlite.const_int64(pool, 0) - r1_step = llvmlite.const_int64(pool, 1) - r1_stop = llvmlite.const_int64(pool, 0) - # 先赋中间变量再取 args(cast 链式属性访问会推断错字段偏移) - call_src1: ast.Call | t.CPtr = (ast.Call | t.CPtr)(src1) - cargs1: list[ast.AST | t.CPtr] | t.CPtr = call_src1.args - if cargs1 is not None: - n1: t.CSizeT = len(cargs1) - if n1 >= 1: - sv: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, cargs1.get(0), - trans._funcs, trans._func_count, trans) - if sv is None: - # fail-fast: range 参数翻译失败 - HandlesType.fatal_error(cargs1.get(0), "range 参数翻译失败", "TypeError") - r1_stop = HandlesExpr.coerce_to_type(builder, sv, i64_ty, cargs1.get(0)) - if n1 >= 2: - sv2: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, cargs1.get(1), - trans._funcs, trans._func_count, trans) - if sv2 is None: - # fail-fast: range 参数翻译失败 - HandlesType.fatal_error(cargs1.get(1), "range 参数翻译失败", "TypeError") - r1_start = HandlesExpr.coerce_to_type(builder, sv2, i64_ty, cargs1.get(1)) - if n1 >= 3: - sv3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, cargs1.get(2), - trans._funcs, trans._func_count, trans) - if sv3 is None: - # fail-fast: range 参数翻译失败 - HandlesType.fatal_error(cargs1.get(2), "range 参数翻译失败", "TypeError") - r1_step = HandlesExpr.coerce_to_type(builder, sv3, i64_ty, cargs1.get(2)) - elif kind1 == HandlesFor.SEQ_KIND_STR: - elem1_ty = i8_ty - s1_ptr = HandlesExpr.translate_value( - builder, pool, trans.Module, src1, - trans._funcs, trans._func_count, trans) - if s1_ptr is None: - HandlesType.fatal_error(for_node, "序列迭代: 字符串源翻译失败") - elif kind1 == HandlesFor.SEQ_KIND_LIST: - elem1_ty = i8_ptr_ty - l1_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, src1, - trans._funcs, trans._func_count, trans) - if l1_obj is None or l1_obj.Ty is None \ - or HandlesExpr.is_ptr_type(l1_obj.Ty) == 0: - HandlesType.fatal_error(for_node, "序列迭代: list 源不是指针类型") - l1_count = llvmlite.build_load(builder, i64_ty, - llvmlite.build_gep(builder, i64_ty, l1_obj, llvmlite.const_int64(pool, 1))) - l1_data = llvmlite.build_load(builder, i8_ptr_ty, - llvmlite.build_gep(builder, i64_ty, l1_obj, llvmlite.const_int64(pool, 0))) - l1_esize = llvmlite.build_load(builder, i64_ty, - llvmlite.build_gep(builder, i64_ty, l1_obj, llvmlite.const_int64(pool, 4))) - - # ---- 源 2 准备(zip)---- - kind2: int = 0 - elem2_ty: llvmlite.LLVMType | t.CPtr = elem1_ty - s2_ptr: llvmlite.Value | t.CPtr = None - l2_count: llvmlite.Value | t.CPtr = None - l2_data: llvmlite.Value | t.CPtr = None - l2_esize: llvmlite.Value | t.CPtr = None - r2_start: llvmlite.Value | t.CPtr = None - r2_stop: llvmlite.Value | t.CPtr = None - r2_step: llvmlite.Value | t.CPtr = None - if n_srcs >= 2: - kind2 = self._seq_kind(trans, src2) - if kind2 == 0: - HandlesType.fatal_error(for_node, "序列迭代: 源 2 类型不支持") - if kind2 == HandlesFor.SEQ_KIND_RANGE: - elem2_ty = i32_ty - r2_start = llvmlite.const_int64(pool, 0) - r2_step = llvmlite.const_int64(pool, 1) - r2_stop = llvmlite.const_int64(pool, 0) - # 先赋中间变量再取 args(cast 链式属性访问会推断错字段偏移) - call_src2: ast.Call | t.CPtr = (ast.Call | t.CPtr)(src2) - cargs2: list[ast.AST | t.CPtr] | t.CPtr = call_src2.args - if cargs2 is not None: - n2: t.CSizeT = len(cargs2) - if n2 >= 1: - svz: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, cargs2.get(0), - trans._funcs, trans._func_count, trans) - if svz is None: - # fail-fast: range 参数翻译失败 - HandlesType.fatal_error(cargs2.get(0), "range 参数翻译失败", "TypeError") - r2_stop = HandlesExpr.coerce_to_type(builder, svz, i64_ty, cargs2.get(0)) - if n2 >= 2: - svz2: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, cargs2.get(1), - trans._funcs, trans._func_count, trans) - if svz2 is None: - # fail-fast: range 参数翻译失败 - HandlesType.fatal_error(cargs2.get(1), "range 参数翻译失败", "TypeError") - r2_start = HandlesExpr.coerce_to_type(builder, svz2, i64_ty, cargs2.get(1)) - if n2 >= 3: - svz3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, cargs2.get(2), - trans._funcs, trans._func_count, trans) - if svz3 is None: - # fail-fast: range 参数翻译失败 - HandlesType.fatal_error(cargs2.get(2), "range 参数翻译失败", "TypeError") - r2_step = HandlesExpr.coerce_to_type(builder, svz3, i64_ty, cargs2.get(2)) - elif kind2 == HandlesFor.SEQ_KIND_STR: - elem2_ty = i8_ty - s2_ptr = HandlesExpr.translate_value( - builder, pool, trans.Module, src2, - trans._funcs, trans._func_count, trans) - if s2_ptr is None: - HandlesType.fatal_error(for_node, "序列迭代: 字符串源 2 翻译失败") - elif kind2 == HandlesFor.SEQ_KIND_LIST: - elem2_ty = i8_ptr_ty - l2_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, src2, - trans._funcs, trans._func_count, trans) - if l2_obj is None or l2_obj.Ty is None \ - or HandlesExpr.is_ptr_type(l2_obj.Ty) == 0: - HandlesType.fatal_error(for_node, "序列迭代: list 源 2 不是指针类型") - l2_count = llvmlite.build_load(builder, i64_ty, - llvmlite.build_gep(builder, i64_ty, l2_obj, llvmlite.const_int64(pool, 1))) - l2_data = llvmlite.build_load(builder, i8_ptr_ty, - llvmlite.build_gep(builder, i64_ty, l2_obj, llvmlite.const_int64(pool, 0))) - l2_esize = llvmlite.build_load(builder, i64_ty, - llvmlite.build_gep(builder, i64_ty, l2_obj, llvmlite.const_int64(pool, 4))) - - # ---- 循环变量 alloca ---- - # t1: enumerate → 序号 (i32);zip → 源 1 元素 - t1_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, t1) - new_vars: int = 0 - if t1_alloca is None: - if n_srcs == 1: - t1_alloca = HandlesVar._alloca_at_entry(builder, i32_ty) - else: - t1_alloca = HandlesVar._alloca_at_entry(builder, elem1_ty) - if t1_alloca is not None: - if HandlesVar.define_var(trans.SymTab, t1, t1_alloca) == 0: - new_vars += 1 - # t2: 源 2 元素(enumerate 时 = 源 1 元素) - t2_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, t2) - if t2_alloca is None: - t2_alloca = HandlesVar._alloca_at_entry(builder, elem2_ty) - if t2_alloca is not None: - if HandlesVar.define_var(trans.SymTab, t2, t2_alloca) == 0: - new_vars += 1 - - # 隐式 index 变量 (i64) - idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i64_ty) - llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), idx_alloca) - - # 基本块: cond / body / incr / end - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - - name_buf: str = pool.alloc(32) - viperlib.snprintf(name_buf, 32, "seq.cond.%d", cnt) - cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "seq.body.%d", cnt) - body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "seq.incr.%d", cnt) - incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "seq.end.%d", cnt) - end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - llvmlite.build_br(builder, cond_bb) - - # cond 块: 源 1 done 检查(zip 需源 2 也 done) - llvmlite.position_at_end(builder, cond_bb) - cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, idx_alloca) - done1: llvmlite.Value | t.CPtr = None - if kind1 == HandlesFor.SEQ_KIND_RANGE: - done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, r1_stop) - elif kind1 == HandlesFor.SEQ_KIND_STR: - ch_ptr1: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s1_ptr, cur_idx) - ch1: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ty, ch_ptr1) - zero1: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, 8, 0) - done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, ch1, zero1) - elif kind1 == HandlesFor.SEQ_KIND_LIST: - done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, l1_count) - cont: llvmlite.Value | t.CPtr = done1 - if n_srcs >= 2: - done2: llvmlite.Value | t.CPtr = None - if kind2 == HandlesFor.SEQ_KIND_RANGE: - done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, r2_stop) - elif kind2 == HandlesFor.SEQ_KIND_STR: - ch_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s2_ptr, cur_idx) - ch2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ty, ch_ptr2) - zero2: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, 8, 0) - done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, ch2, zero2) - elif kind2 == HandlesFor.SEQ_KIND_LIST: - done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, l2_count) - cont = llvmlite.build_and(builder, done1, done2) - llvmlite.build_cond_br(builder, cont, body_bb, end_bb) - - # body 块: 获取元素 → store → 循环体 - llvmlite.position_at_end(builder, body_bb) - # 源 1 元素 - v1: llvmlite.Value | t.CPtr = None - if kind1 == HandlesFor.SEQ_KIND_RANGE: - step1: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, r1_step) - v1 = llvmlite.build_add(builder, r1_start, step1) - elif kind1 == HandlesFor.SEQ_KIND_STR: - ch_ptr1b: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s1_ptr, cur_idx) - v1 = llvmlite.build_load(builder, i8_ty, ch_ptr1b) - elif kind1 == HandlesFor.SEQ_KIND_LIST: - off1: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, l1_esize) - addr1: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, l1_data, off1) - v1 = llvmlite.build_load(builder, i8_ptr_ty, addr1) - # store t1 / t2 - if t1_alloca is not None and t1_alloca.Ty is not None: - t1_ty: llvmlite.LLVMType | t.CPtr = t1_alloca.Ty.Pointee - if n_srcs == 1: - # enumerate: t1 = 序号(trunc i64 → i32) - idx32: llvmlite.Value | t.CPtr = llvmlite.build_trunc(builder, cur_idx, i32_ty) - llvmlite.build_store(builder, idx32, t1_alloca) - if t2_alloca is not None and t2_alloca.Ty is not None and v1 is not None: - t2_ty: llvmlite.LLVMType | t.CPtr = t2_alloca.Ty.Pointee - v1c: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, v1, t2_ty, src1) - llvmlite.build_store(builder, v1c, t2_alloca) - else: - if v1 is not None: - v1c: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, v1, t1_ty, src1) - llvmlite.build_store(builder, v1c, t1_alloca) - # 源 2 元素 → t2 - v2: llvmlite.Value | t.CPtr = None - if kind2 == HandlesFor.SEQ_KIND_RANGE: - step2: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, r2_step) - v2 = llvmlite.build_add(builder, r2_start, step2) - elif kind2 == HandlesFor.SEQ_KIND_STR: - ch_ptr2b: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s2_ptr, cur_idx) - v2 = llvmlite.build_load(builder, i8_ty, ch_ptr2b) - elif kind2 == HandlesFor.SEQ_KIND_LIST: - off2: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, l2_esize) - addr2: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, l2_data, off2) - v2 = llvmlite.build_load(builder, i8_ptr_ty, addr2) - if t2_alloca is not None and t2_alloca.Ty is not None and v2 is not None: - t2_ty2: llvmlite.LLVMType | t.CPtr = t2_alloca.Ty.Pointee - v2c: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, v2, t2_ty2, src2) - llvmlite.build_store(builder, v2c, t2_alloca) - - # 保存旧循环上下文,设置 break/continue 目标 - old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb - old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb - trans._break_bb = end_bb - trans._continue_bb = incr_bb - - body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children - if body is not None: - body_count: t.CSizeT = len(body) - for bi in range(body_count): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - - trans._break_bb = old_break - trans._continue_bb = old_continue - - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, incr_bb) - - # incr 块: index++ - llvmlite.position_at_end(builder, incr_bb) - one_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) - next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val) - llvmlite.build_store(builder, next_idx, idx_alloca) - llvmlite.build_br(builder, cond_bb) - - # 定位到 end 块 - llvmlite.position_at_end(builder, end_bb) - # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) - trans._ctrl_merge_reachable = 1 - return new_vars - - # ============================================================ - # _handle_ptr_iter - 指针迭代: for x in ptr:(迁移自 ForHandleIter) - # 遍历指针,依赖隐式 index,直到解引用为空(null 终止符) - # - # 生成 IR 结构: - # %idx = alloca i32 - # store i32 0, i32* %idx - # br label %cond - # cond: - # %i = load i32, i32* %idx - # %ep = getelementptr elem_ty, ptr_ty %ptr, i32 %i - # %ev = load elem_ty, elem_ty* %ep - # %null = icmp eq elem_ty %ev, 0 - # br i1 %null, label %end, label %body - # body: - # store elem_ty %ev, elem_ty* %var - # ... 循环体 ... - # br label %incr - # incr: - # %next = add i32 %i, 1 - # store i32 %next, i32* %idx - # br label %cond - # end: - # ============================================================ - def _handle_ptr_iter(self, trans: HT.Translator | t.CPtr, - for_node: ast.For | t.CPtr, - var_name: str) -> int: - """指针迭代: for x in ptr: 直到解引用为空""" - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - func: llvmlite.Function | t.CPtr = trans._cur_func - - # 翻译迭代器表达式,获取指针值 - ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, for_node.iter, - trans._funcs, trans._func_count, trans) - if ptr_val is None: - HandlesType.fatal_error(for_node, "指针迭代: 无法翻译迭代器表达式") - - # 检查迭代器类型 - if HandlesExpr.is_ptr_type(ptr_val.Ty) == 0: - # 数组迭代:for k in arr(定长数组按长度迭代,元素可为任意类型) - if HandlesExpr.is_array_type(ptr_val.Ty) != 0: - return self._handle_array_iter(trans, for_node, var_name, ptr_val) - HandlesType.fatal_error(for_node, "指针迭代: 迭代器不是指针类型") - - # 获取元素类型 - elem_ty: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee - if elem_ty is None: - HandlesType.fatal_error(for_node, "指针迭代: 无法获取元素类型") - - # 元素类型是数组(Ptr([N x T]),如 t.CArray 变量退化指针): - # load 出数组值后走数组迭代(按长度,非 null 终止) - if HandlesExpr.is_array_type(elem_ty) != 0: - arr_v2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, ptr_val) - if arr_v2 is not None: - return self._handle_array_iter(trans, for_node, var_name, arr_v2) - - # 元素类型必须是整数(用于 icmp eq 0 检查 null 终止符) - elem_bits: int = HandlesExpr.get_llvm_type_bits(elem_ty) - if elem_bits == 0: - HandlesType.fatal_error(for_node, "指针迭代: 元素类型不是整数,无法检查 null 终止符") - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - - # 创建循环变量 alloca(存储元素值) - var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, var_name) - new_vars: int = 0 - if var_alloca is None: - var_alloca = HandlesVar._alloca_at_entry(builder, elem_ty) - if HandlesVar.define_var( - trans.SymTab, var_name, var_alloca) == 0: - new_vars = 1 - - # 创建隐式 index 变量,初始为 0 - idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i32_ty) - llvmlite.build_store(builder, llvmlite.const_int32(pool, 0), idx_alloca) - - # 创建基本块: cond / body / incr / end - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - - name_buf: str = pool.alloc(32) - viperlib.snprintf(name_buf, 32, "ptr.cond.%d", cnt) - cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "ptr.body.%d", cnt) - body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "ptr.incr.%d", cnt) - incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "ptr.end.%d", cnt) - end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - # 跳转到 cond - llvmlite.build_br(builder, cond_bb) - - # cond 块: load index, GEP, load elem, icmp eq 0 - llvmlite.position_at_end(builder, cond_bb) - cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i32_ty, idx_alloca) - elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, elem_ty, ptr_val, cur_idx) - cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, elem_ptr) - null_val: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, elem_bits, 0) - is_null: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_EQ, cur_elem, null_val) - llvmlite.build_cond_br(builder, is_null, end_bb, body_bb) - - # body 块: store elem to var, 翻译循环体 - llvmlite.position_at_end(builder, body_bb) - llvmlite.build_store(builder, cur_elem, var_alloca) - - # 保存旧循环上下文,设置 break/continue 目标 - old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb - old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb - trans._break_bb = end_bb - trans._continue_bb = incr_bb - - body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children - if body is not None: - body_count: t.CSizeT = len(body) - for bi in range(body_count): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - - # 恢复旧循环上下文 - trans._break_bb = old_break - trans._continue_bb = old_continue - - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, incr_bb) - - # incr 块: index++, br cond - llvmlite.position_at_end(builder, incr_bb) - one_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) - next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val) - llvmlite.build_store(builder, next_idx, idx_alloca) - llvmlite.build_br(builder, cond_bb) - - # 定位到 end 块 - llvmlite.position_at_end(builder, end_bb) - # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) - trans._ctrl_merge_reachable = 1 - return new_vars - - # ============================================================ - # _handle_array_iter - 数组迭代: for x in arr:(迁移自 ForHandleIter) - # 定长数组按长度迭代(元素可为任意类型,不做 null 终止符检查) - # - # 数组值是数组类型而非指针(如局部 t.CArray 修复后), - # 先拷到临时 alloca 获得地址,再按 [0, N) 迭代。 - # - # 生成 IR 结构: - # %tmp = alloca [N x elem_ty] - # store [N x elem_ty] %arr_val, [N x elem_ty]* %tmp - # %idx = alloca i32 ; store 0 - # br %cond - # cond: - # %i = load i32, i32* %idx - # %c = icmp slt i32 %i, N - # br i1 %c, %body, %end - # body: - # %ep = getelementptr [N x elem_ty], [N x elem_ty]* %tmp, i32 0, i32 %i - # %ev = load elem_ty, elem_ty* %ep - # store elem_ty %ev, elem_ty* %var - # ... 循环体 ... - # br %incr - # incr: - # %n = add i32 %i, 1 ; store %n ; br %cond - # end: - # ============================================================ - def _handle_array_iter(self, trans: HT.Translator | t.CPtr, - for_node: ast.For | t.CPtr, - var_name: str, - array_val: llvmlite.Value | t.CPtr) -> int: - """数组迭代: for x in arr: 按数组长度迭代""" - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - func: llvmlite.Function | t.CPtr = trans._cur_func - - # 解析数组类型 [N x elem_ty] - arr_ty: llvmlite.LLVMType | t.CPtr = array_val.Ty - elem_ty: llvmlite.LLVMType | t.CPtr = None - elem_count: int = 0 - match arr_ty: - case llvmlite.LLVMType.Array(et, n): - elem_ty = et - elem_count = n - if elem_ty is None or elem_count <= 0: - HandlesType.fatal_error(for_node, "数组迭代: 无法解析数组类型") - - # 数组值 → 临时 alloca(数组值不是指针,需拷贝后 GEP 迭代) - arr_tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, arr_ty) - if arr_tmp is None: - HandlesType.fatal_error(for_node, "数组迭代: 临时存储分配失败") - llvmlite.build_store(builder, array_val, arr_tmp) - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - - # 循环变量 alloca(存储元素值) - var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, var_name) - new_vars: int = 0 - if var_alloca is None: - var_alloca = HandlesVar._alloca_at_entry(builder, elem_ty) - if HandlesVar.define_var( - trans.SymTab, var_name, var_alloca) == 0: - new_vars = 1 - - # 隐式 index 变量,初始为 0 - idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i32_ty) - llvmlite.build_store(builder, llvmlite.const_int32(pool, 0), idx_alloca) - - # 基本块: cond / body / incr / end - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - - name_buf: str = pool.alloc(32) - viperlib.snprintf(name_buf, 32, "arr.cond.%d", cnt) - cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "arr.body.%d", cnt) - body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "arr.incr.%d", cnt) - incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "arr.end.%d", cnt) - end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - llvmlite.build_br(builder, cond_bb) - - # cond 块: load index, icmp slt idx, elem_count - llvmlite.position_at_end(builder, cond_bb) - cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i32_ty, idx_alloca) - count_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, elem_count) - in_bounds: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_SLT, cur_idx, count_val) - llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb) - - # body 块: GEP(0, idx) → load elem → store to var → 循环体 - llvmlite.position_at_end(builder, body_bb) - elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, arr_ty, elem_ty, arr_tmp, cur_idx) - cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, elem_ptr) - llvmlite.build_store(builder, cur_elem, var_alloca) - - old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb - old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb - trans._break_bb = end_bb - trans._continue_bb = incr_bb - - body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children - if body is not None: - body_count: t.CSizeT = len(body) - for bi in range(body_count): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - - trans._break_bb = old_break - trans._continue_bb = old_continue - - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, incr_bb) - - # incr 块: index++ - llvmlite.position_at_end(builder, incr_bb) - one_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) - next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val) - llvmlite.build_store(builder, next_idx, idx_alloca) - llvmlite.build_br(builder, cond_bb) - - # 定位到 end 块 - llvmlite.position_at_end(builder, end_bb) - # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) - trans._ctrl_merge_reachable = 1 - return new_vars - - # ============================================================ - # _handle_list_literal_iter - 列表字面量迭代: for x in [a, b, c]:(迁移自 ForHandleIter) - # 把列表字面量转成定长数组值,再复用数组迭代(按长度迭代)。 - # - # 元素类型取第一个元素的值类型,其余元素 coerce 到该类型。 - # ============================================================ - def _handle_list_literal_iter(self, trans: HT.Translator | t.CPtr, - for_node: ast.For | t.CPtr, - var_name: str, - list_node: ast.AST | t.CPtr) -> int: - """列表字面量迭代: for x in [a, b, c]: 按元素顺序迭代""" - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - - lst: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node) - if lst is None or lst.elts is None: - HandlesType.fatal_error(for_node, "列表字面量迭代: 空列表") - elts: list[ast.AST | t.CPtr] | t.CPtr = lst.elts - elts_count: t.CSizeT = len(elts) - if elts_count <= 0: - HandlesType.fatal_error(for_node, "列表字面量迭代: 空列表") - - # 翻译第一个元素,确定元素类型 - first_el: ast.AST | t.CPtr = elts.get(0) - first_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, first_el, - trans._funcs, trans._func_count, trans) - if first_val is None or first_val.Ty is None: - HandlesType.fatal_error(first_el, "列表字面量迭代: 无法确定元素类型") - elem_ty: llvmlite.LLVMType | t.CPtr = first_val.Ty - - # 构建 [N x elem_ty] 数组值:临时 alloca 逐元素写入后 load - arr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, elem_ty, elts_count) - tmp_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, arr_ty) - if tmp_alloca is None: - HandlesType.fatal_error(for_node, "列表字面量迭代: 临时数组分配失败") - first_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, arr_ty, elem_ty, tmp_alloca, llvmlite.const_int32(pool, 0)) - if first_ptr is not None: - llvmlite.build_store(builder, first_val, first_ptr) - # 写其余元素(coerce 到 elem_ty) - i: t.CSizeT = 1 - while i < elts_count: - el_node: ast.AST | t.CPtr = elts.get(i) - el_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, el_node, - trans._funcs, trans._func_count, trans) - if el_val is not None: - el_val = HandlesExpr.coerce_to_type(builder, el_val, elem_ty, el_node) - el_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, arr_ty, elem_ty, tmp_alloca, - llvmlite.const_int32(pool, i)) - if el_ptr is not None: - llvmlite.build_store(builder, el_val, el_ptr) - i += 1 - # load 回数组值,复用数组迭代 - arr_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, arr_ty, tmp_alloca) - if arr_val is None: - HandlesType.fatal_error(for_node, "列表字面量迭代: 数组加载失败") - return self._handle_array_iter(trans, for_node, var_name, arr_val) - - # ============================================================ - # _handle_list_iter - list[T] 容器迭代: for v in lst:(迁移自 ForHandleIter) - # 按 __count__ 动态长度迭代(元素任意类型,不做 null 终止符检查) - # - # list 结构布局 (6 字段 × 8 字节): - # __data__(0) __count__(8) __capacity__(16) __pool__(24) - # __elem_size__(32) __iter_index__(40) - # - # 生成 IR 结构: - # %count = load __count__ - # %idx = alloca i64 ; store 0 - # br %cond - # cond: - # %i = load i64, %idx - # %c = icmp slt i64 %i, %count - # br i1 %c, %body, %end - # body: - # %data = load __data__ (i8*) - # %es = load __elem_size__ (i64) - # %off = mul i64 %i, %es - # %addr = getelementptr i8, i8* %data, i64 %off - # %el = load i8*, i8** %addr - # store i8* %el, i8** %var - # ... 循环体 ... - # br %incr - # incr: - # %n = add i64 %i, 1 ; store ; br %cond - # end: - # ============================================================ - def _handle_list_iter(self, trans: HT.Translator | t.CPtr, - for_node: ast.For | t.CPtr, - var_name: str, - list_val: llvmlite.Value | t.CPtr) -> int: - """list[T] 容器迭代: for v in lst: 按 __count__ 动态长度迭代""" - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - func: llvmlite.Function | t.CPtr = trans._cur_func - - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - # 读取 __count__ (偏移 8, GEP index 1) - cnt_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i64_ty, list_val, llvmlite.const_int64(pool, 1)) - if cnt_ptr is None: - HandlesType.fatal_error(for_node, "list 迭代: 无法定位 __count__") - count_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, cnt_ptr) - - # 循环变量 alloca(元素类型 i8*,与 list.get 内联一致) - var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, var_name) - new_vars: int = 0 - if var_alloca is None: - var_alloca = HandlesVar._alloca_at_entry(builder, i8_ptr_ty) - if HandlesVar.define_var( - trans.SymTab, var_name, var_alloca) == 0: - new_vars = 1 - - # 隐式 index 变量 (i64,与 __count__ 类型对齐) - idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i64_ty) - llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), idx_alloca) - - # 基本块: cond / body / incr / end - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - - name_buf: str = pool.alloc(32) - viperlib.snprintf(name_buf, 32, "lst.cond.%d", cnt) - cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "lst.body.%d", cnt) - body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "lst.incr.%d", cnt) - incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "lst.end.%d", cnt) - end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - llvmlite.build_br(builder, cond_bb) - - # cond 块: load index, icmp slt idx, count - llvmlite.position_at_end(builder, cond_bb) - cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, idx_alloca) - in_bounds: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_SLT, cur_idx, count_val) - llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb) - - # body 块: __data__ + idx*__elem_size__ → load 元素 → store to var - llvmlite.position_at_end(builder, body_bb) - dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i64_ty, list_val, llvmlite.const_int64(pool, 0)) - data_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, dpp) - epp: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i64_ty, list_val, llvmlite.const_int64(pool, 4)) - esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, epp) - offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, esize) - elem_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i8_ty, data_ptr, offset) - cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, elem_addr) - llvmlite.build_store(builder, cur_elem, var_alloca) - - # 保存旧循环上下文,设置 break/continue 目标 - old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb - old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb - trans._break_bb = end_bb - trans._continue_bb = incr_bb - - body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children - if body is not None: - body_count: t.CSizeT = len(body) - for bi in range(body_count): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - - trans._break_bb = old_break - trans._continue_bb = old_continue - - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, incr_bb) - - # incr 块: index++ - llvmlite.position_at_end(builder, incr_bb) - one_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) - next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val) - llvmlite.build_store(builder, next_idx, idx_alloca) - llvmlite.build_br(builder, cond_bb) - - # 定位到 end 块 - llvmlite.position_at_end(builder, end_bb) - # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) - trans._ctrl_merge_reachable = 1 - return new_vars - - def _handle_dict_iter(self, trans: HT.Translator | t.CPtr, - for_node: ast.For | t.CPtr, - var_name: str, - dict_val: llvmlite.Value | t.CPtr) -> int: - """dict 容器迭代: for key in d: 按 __count__/__keys__ 布局迭代 - - _dict.vp 布局(8 字节槽):__keys__@0, __values__@1, __count__@2, - __capacity__@3, __mbuddy__@4, __iter_index__@5。 - __iter__ 协议(__iter__ 重置 iter_index + __next__ 取 key)内联为 - 循环:iter_idx < __count__ → key = __keys__[iter_idx]。 - """ - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - func: llvmlite.Function | t.CPtr = trans._cur_func - - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - # 读取 __count__(槽 2,字节偏移 16) - cnt_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i64_ty, dict_val, llvmlite.const_int64(pool, 2)) - if cnt_ptr is None: - HandlesType.fatal_error(for_node, "dict 迭代: 无法定位 __count__") - count_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, cnt_ptr) - - # 循环变量 alloca(元素类型 i8*,与 dict.__next__ 返回 str 一致) - var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, var_name) - new_vars: int = 0 - if var_alloca is None: - var_alloca = HandlesVar._alloca_at_entry(builder, i8_ptr_ty) - if HandlesVar.define_var( - trans.SymTab, var_name, var_alloca) == 0: - new_vars = 1 - - # 隐式 index 变量 (i64,与 __count__ 类型对齐) - idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i64_ty) - llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), idx_alloca) - - # 基本块: cond / body / incr / end - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - - name_buf: str = pool.alloc(32) - viperlib.snprintf(name_buf, 32, "dict.cond.%d", cnt) - cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "dict.body.%d", cnt) - body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "dict.incr.%d", cnt) - incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "dict.end.%d", cnt) - end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - llvmlite.build_br(builder, cond_bb) - - # cond 块: load index, icmp slt idx, count - llvmlite.position_at_end(builder, cond_bb) - cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, idx_alloca) - in_bounds: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_SLT, cur_idx, count_val) - llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb) - - # body 块: __keys__ + idx*8 → load key (i8*) → store to var - llvmlite.position_at_end(builder, body_bb) - kpp: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i64_ty, dict_val, llvmlite.const_int64(pool, 0)) - keys_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, kpp) - eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 8) - key_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, eight_val) - key_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i8_ty, keys_ptr, key_offset) - cur_key: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, key_addr) - llvmlite.build_store(builder, cur_key, var_alloca) - - # 保存旧循环上下文,设置 break/continue 目标 - old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb - old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb - trans._break_bb = end_bb - trans._continue_bb = incr_bb - - body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children - if body is not None: - body_count: t.CSizeT = len(body) - for bi in range(body_count): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - - trans._break_bb = old_break - trans._continue_bb = old_continue - - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, incr_bb) - - # incr 块: index++ - llvmlite.position_at_end(builder, incr_bb) - one_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) - next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val) - llvmlite.build_store(builder, next_idx, idx_alloca) - llvmlite.build_br(builder, cond_bb) - - # 定位到 end 块 - llvmlite.position_at_end(builder, end_bb) - # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) - trans._ctrl_merge_reachable = 1 - return new_vars - - # ============================================================ - # _handle_oop_iter - OOP 迭代协议: for x in obj:(迁移自 ForHandleIter) - # obj 的类有 __iter__/__next__ 方法时调用协议迭代 - # (对齐 TPC HandlesFor.py _HandleForIterLlvm L599-663) - # - # 生成 IR 结构: - # %it = call {Class}.__iter__(obj) - # %flag = alloca i1 ; store 0 - # br %cond - # cond: - # store 0, %flag - # %v = call {Class}.__next__(%it, %flag) - # %stop = load i1, %flag - # br i1 %stop==0, %body, %end - # body: - # store %v, %var - # ... 循环体 ... - # br %step - # step: - # br %cond - # end: - # - # __next__ 的隐藏参数 __stop_iter_flag__(i1*)由 ClassGenMixin - # _translate_method 注入,raise StopIteration 时置 1(translate_raise); - # VpiReader stub 声明同步该参数(_inject_method_declare)。 - # ============================================================ - def _handle_oop_iter(self, trans: HT.Translator | t.CPtr, - for_node: ast.For | t.CPtr, - var_name: str, - class_name: str, - obj_val: llvmlite.Value | t.CPtr) -> int: - """OOP iter 协议: for x in obj: 调用 __iter__/__next__ 迭代""" - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - func: llvmlite.Function | t.CPtr = trans._cur_func - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - - if builder is None or func is None or mod is None: - return 0 - if obj_val is None or obj_val.Ty is None: - HandlesType.fatal_error(for_node, "OOP 迭代: 迭代源对象类型未知") - if HandlesExpr.is_ptr_type(obj_val.Ty) == 0: - HandlesType.fatal_error(for_node, "OOP 迭代: 迭代源对象不是指针类型") - - # 1. 查找 {Class}.__iter__ 并调用,得到迭代器 - iter_lookup: str = pool.alloc(128) - if iter_lookup is None: - return 0 - viperlib.snprintf(iter_lookup, 128, "%s.__iter__", class_name) - iter_fn: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module( - mod, iter_lookup) - if iter_fn is None: - HandlesType.fatal_error( - for_node, f"OOP 迭代: 类 '{class_name}' 没有 __iter__ 方法") - iter_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(iter_fn) - iter_fn_name: str = llvmlite.function_get_name(iter_fn) - if iter_ret_ty is None or iter_fn_name is None: - return 0 - # self 参数按 __iter__ 首参类型对齐(stub 声明 self 可能是 i8*) - iter_self: llvmlite.Value | t.CPtr = obj_val - iter_first: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(iter_fn) - if iter_first is not None: - iter_self_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(iter_first) - if iter_self_ty is not None: - iter_self = llvmlite.build_bitcast(builder, obj_val, iter_self_ty) - if iter_self is None: - return 0 - iter_self.Next = None - iter_result: llvmlite.Value | t.CPtr = llvmlite.build_call( - builder, iter_fn_name, iter_self, 1, iter_ret_ty, 0) - if iter_result is None: - return 0 - - # 2. 查找 {Class}.__next__(带隐藏 __stop_iter_flag__ i1* 参数) - next_lookup: str = pool.alloc(128) - if next_lookup is None: - return 0 - viperlib.snprintf(next_lookup, 128, "%s.__next__", class_name) - next_fn: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module( - mod, next_lookup) - if next_fn is None: - HandlesType.fatal_error( - for_node, f"OOP 迭代: 类 '{class_name}' 没有 __next__ 方法") - next_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(next_fn) - next_fn_name: str = llvmlite.function_get_name(next_fn) - if next_ret_ty is None or next_fn_name is None: - return 0 - - # 3. 循环变量 alloca(元素类型 = __next__ 返回类型) - var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, var_name) - new_vars: int = 0 - if var_alloca is None: - var_alloca = HandlesVar._alloca_at_entry(builder, next_ret_ty) - if var_alloca is not None: - if HandlesVar.define_var( - trans.SymTab, var_name, var_alloca) == 0: - new_vars = 1 - - # 4. stop flag alloca(i1,初始 0) - i1_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - flag_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i1_ty) - if flag_alloca is None: - return 0 - flag_zero: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i1_ty, 0, "0") - if flag_zero is not None: - llvmlite.build_store(builder, flag_zero, flag_alloca) - - # 5. 创建基本块: cond / body / step / end - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - name_buf: str = pool.alloc(32) - viperlib.snprintf(name_buf, 32, "oop.cond.%d", cnt) - cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - viperlib.snprintf(name_buf, 32, "oop.body.%d", cnt) - body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - viperlib.snprintf(name_buf, 32, "oop.step.%d", cnt) - step_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - viperlib.snprintf(name_buf, 32, "oop.end.%d", cnt) - end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - if cond_bb is None or body_bb is None or step_bb is None or end_bb is None: - return 0 - - llvmlite.build_br(builder, cond_bb) - - # 6. cond 块: 重置 flag → 调 __next__(iter, flag) → 检查 flag 判结束 - llvmlite.position_at_end(builder, cond_bb) - if flag_zero is not None: - llvmlite.build_store(builder, flag_zero, flag_alloca) - # __next__ 参数 1:迭代器(按首参类型 bitcast) - next_self: llvmlite.Value | t.CPtr = iter_result - next_first: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(next_fn) - if next_first is not None: - next_self_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(next_first) - if next_self_ty is not None and iter_result.Ty is not None: - next_self = llvmlite.build_bitcast(builder, iter_result, next_self_ty) - if next_self is None: - return 0 - # 参数链表: arg1(iter).Next = arg2(flag);flag 独立 null 结尾防自链接 - next_self.Next = flag_alloca - flag_alloca.Next = None - next_val: llvmlite.Value | t.CPtr = llvmlite.build_call( - builder, next_fn_name, next_self, 2, next_ret_ty, 0) - if next_val is None: - return 0 - stop_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i1_ty, flag_alloca) - if stop_val is None: - return 0 - flag_zero2: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i1_ty, 0, "0") - continue_i1: llvmlite.Value | t.CPtr = None - if flag_zero2 is not None: - continue_i1 = llvmlite.build_icmp( - builder, llvmlite.ICMP_EQ, stop_val, flag_zero2) - if continue_i1 is None: - return 0 - llvmlite.build_cond_br(builder, continue_i1, body_bb, end_bb) - - # 7. body 块: store 元素 → 翻译循环体 → br step - llvmlite.position_at_end(builder, body_bb) - if var_alloca is not None: - llvmlite.build_store(builder, next_val, var_alloca) - old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb - old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb - trans._break_bb = end_bb - trans._continue_bb = step_bb - body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children - if body is not None: - body_count: t.CSizeT = len(body) - for bi in range(body_count): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - trans._break_bb = old_break - trans._continue_bb = old_continue - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, step_bb) - - # 8. step 块 → cond;定位到 end 块 - llvmlite.position_at_end(builder, step_bb) - llvmlite.build_br(builder, cond_bb) - llvmlite.position_at_end(builder, end_bb) - # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) - trans._ctrl_merge_reachable = 1 - return new_vars - - def _handle_enumerate_iter(self, trans: HT.Translator | t.CPtr, - for_node: ast.For | t.CPtr, - t1: str, t2: str, - call: ast.Call | t.CPtr) -> int: - """enumerate 迭代: for i, v in enumerate(x)""" - if call is None or call.args is None: - return 0 - cargs: list[ast.AST | t.CPtr] | t.CPtr = call.args - if len(cargs) < 1: - HandlesType.fatal_error(for_node, "enumerate 需要至少一个参数") - return self._build_seq_loop(trans, for_node, t1, t2, cargs.get(0), None, 1) - - def _handle_zip_iter(self, trans: HT.Translator | t.CPtr, - for_node: ast.For | t.CPtr, - t1: str, t2: str, - call: ast.Call | t.CPtr) -> int: - """zip 迭代: for a, b in zip(x, y)""" - if call is None or call.args is None: - # fail-fast: zip 参数缺失 - HandlesType.fatal_error(call, "zip 参数缺失", "SyntaxError") - cargs: list[ast.AST | t.CPtr] | t.CPtr = call.args - if len(cargs) < 2: - HandlesType.fatal_error(for_node, "zip 需要至少两个参数") - return self._build_seq_loop(trans, for_node, t1, t2, cargs.get(0), cargs.get(1), 2) - +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.Generator as Generator +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdlib +import stdio +import viperlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.CompilerFactory as CompilerFactory +import lib.Projectrans.Config as Config +# ============================================================ +# StmtGenCifMixin - StmtGen 拆分 1/3:CIf 编译期求值 + NewXxxHandle 工厂 +# +# 按功能域从 StmtGenMixin.vp 拆出(500~1500 行/文件架构重构,试点): +# 簇 B(CIf 宏求值)+ NewIfHandle/NewWhileHandle/NewForHandle/ +# NewReturnHandle/NewMatchHandle 工厂。 +# 全部字段保留在本最底层父类(顺序 CifEvalOk->EnumTable->EnumCount-> +# DiagStmtCount 与 Generator 组合布局一致,见下方字段注释)。 +# +# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 +# ============================================================ + + +# ============================================================ +# StmtGenCifMixin - CIf 求值 + 工厂(最底层父类) +# ============================================================ +@t.NoVTable +class StmtGenCifMixin: + """CIf 编译期求值 + NewXxxHandle 工厂(StmtGen 拆分 1/3,最底层)""" + + # --- 编译期 CIf 求值状态(原 HandlesIf._g_cif_eval_ok) --- + # 用 8 字节类型:Mixin 独立布局与 Generator 组合布局的字段对齐必须一致 + # (i32 首字段在组合布局中导致 EnumTable 相对偏移 4 vs 独立布局 8 的错位, + # this_adjust 无法同时修正,枚举表错位到相邻字段被覆盖——ASTCtx 丢失根因)。 + Gen: Generator.Generator | t.CPtr + CifEvalOk: t.CSizeT + + # --- 枚举注册表(原 HandlesEnum._enum_table/_enum_count) --- + EnumTable: GenTypes.EnumEntry | t.CPtr + EnumCount: int + + # --- OOM 语句级诊断计数(translate_stmt 限频打印 used) --- + DiagStmtCount: int + + # ============================================================ + # 簇 B:编译期 CIf 宏求值(迁移自 HandlesIf.vp 模块级函数) + # ============================================================ + + def _is_cif_attr(self, attr: str) -> int: + """检查方法名是否为 CIf 系(CIf/CIfdef/CIfndef)""" + if attr is None: + return 0 + if string.strcmp(attr, "CIf") == 0: return 1 + if string.strcmp(attr, "CIfdef") == 0: return 1 + if string.strcmp(attr, "CIfndef") == 0: return 1 + return 0 + + def _is_cif_call(self, node: ast.AST | t.CPtr) -> int: + """检查 test 是否为 c.CIf(...)/c.CIfdef(...)/c.CIfndef(...)(或裸 CIf 系)调用""" + if node is None or node.kind() != ast.ASTKind.Call: + return 0 + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + if cl.func is None: + return 0 + fk: int = cl.func.kind() + if fk == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if at.attr is None: + return 0 + if at.value is not None and at.value.kind() == ast.ASTKind.Name: + vn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if vn.id is not None and string.strcmp(vn.id, "c") == 0: + return self._is_cif_attr(at.attr) + return 0 + if fk == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl.func) + if nm.id is not None and self._is_cif_attr(nm.id) != 0: + return 1 + return 0 + + def _get_platform_macro_value(self, name: str) -> int: + """平台内置宏值(从目标三元组推导,对齐 TPC HandlesIf._get_platform_macros)。 + + 命中置 self.CifEvalOk=1;未命中置 0 返回 0。 + """ + self.CifEvalOk = 0 + if name is None: + return 0 + triple: str = Config.TargetTriple + if triple is None: + triple = "x86_64-pc-windows-gnu" + is_win: int = 0 + is_linux: int = 0 + is_x64: int = 0 + if string.strstr(triple, "windows") is not None \ + or string.strstr(triple, "win32") is not None \ + or string.strstr(triple, "mingw") is not None \ + or string.strstr(triple, "msvc") is not None: + is_win = 1 + if string.strstr(triple, "linux") is not None: + is_linux = 1 + if string.strstr(triple, "x86_64") is not None: + is_x64 = 1 + # 简化:本编译目标为 x86_64 Windows(_WIN64/WIN64 恒与 is_win 一致) + if string.strcmp(name, "_WIN32") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0 + if string.strcmp(name, "WIN32") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0 + if string.strcmp(name, "_WIN64") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0 + if string.strcmp(name, "WIN64") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0 + if string.strcmp(name, "__linux__") == 0: self.CifEvalOk = is_linux; return 1 if is_linux else 0 + if string.strcmp(name, "__x86_64__") == 0: self.CifEvalOk = is_x64; return 1 if is_x64 else 0 + if string.strcmp(name, "__x86_64") == 0: self.CifEvalOk = is_x64; return 1 if is_x64 else 0 + if string.strcmp(name, "_M_X64") == 0: self.CifEvalOk = is_x64; return 1 if is_x64 else 0 + if string.strcmp(name, "SIZEOF_VOID_P") == 0: self.CifEvalOk = 1; return 8 if is_x64 else 4 + if string.strcmp(name, "__SIZEOF_POINTER__") == 0: self.CifEvalOk = 1; return 8 if is_x64 else 4 + if string.strcmp(name, "NDEBUG") == 0: self.CifEvalOk = 1; return 0 + return 0 + + def _cif_name_value(self, pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr, + name: str) -> int: + """查宏名值: 本地 CDefine → 跨模块 CDefine → 平台宏。 + + 命中置 self.CifEvalOk=1(值 0 也算命中,如 DISABLED=0);未命中置 0。 + """ + self.CifEvalOk = 0 + if name is None or trans is None: + return 0 + v: int = self.Gen.TypeGenCDef.lookup_cdefine_constant(name) + if self.Gen.TypeGenCDef.is_cdefine_found() != 0: + self.CifEvalOk = 1 + return v + v2: int = self.Gen.ExprGenCdef._lookup_cross_module_cdefine( + pool, name, trans._from_imports, trans._imported_modules) + if self.Gen.TypeGenCDef.is_cdefine_found() != 0: + self.CifEvalOk = 1 + return v2 + pv: int = self._get_platform_macro_value(name) + if self.CifEvalOk != 0: + return pv + return 0 + + def _cif_attr_value(self, pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr, + at: ast.Attribute | t.CPtr) -> int: + """Attribute 宏值: platmacro.IS_WINDOWS → 本地 CDefine(attr) → 跨模块 CDefine。 + + 命中置 self.CifEvalOk=1;未命中置 0。 + """ + self.CifEvalOk = 0 + if at is None or at.attr is None or at.value is None or trans is None: + return 0 + if at.value.kind() != ast.ASTKind.Name: + return 0 + vn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if vn.id is None: + return 0 + v: int = self.Gen.TypeGenCDef.lookup_cdefine_constant(at.attr) + if self.Gen.TypeGenCDef.is_cdefine_found() != 0: + self.CifEvalOk = 1 + return v + # 跨模块: 确定真实模块名(解析 from_imports 别名) + real_mod: str = vn.id + if trans._from_imports is not None: + resolved: str = self.Gen.ImportsGen.lookup_from_import( + trans._from_imports, vn.id, 0) + if resolved is not None: + rm_len: t.CSizeT = 0 + while resolved[rm_len] != ' ' and resolved[rm_len] != '\0' and resolved[rm_len] != ':': + rm_len += 1 + rm_buf: str = pool.alloc(rm_len + 1) + if rm_buf is not None: + for rm_i in range(rm_len): + rm_buf[rm_i] = resolved[rm_i] + rm_buf[rm_len] = '\0' + real_mod = rm_buf + fi_len: t.CSizeT = string.strlen(at.attr) + string.strlen(real_mod) + 2 + fi: str = pool.alloc(fi_len) + if fi is None: + return 0 + viperlib.snprintf(fi, fi_len, "%s:%s", at.attr, real_mod) + v2: int = self.Gen.ExprGenCdef._lookup_cross_module_cdefine(pool, at.attr, fi) + if self.Gen.TypeGenCDef.is_cdefine_found() != 0: + self.CifEvalOk = 1 + return v2 + return 0 + + def _cif_eval_node(self, pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """递归常量求值 CIf 表达式。 + + 支持: Constant(int) / Name(CDefine/跨模块/平台宏) / Attribute(跨模块 CDefine) + / BinOp(+ - * // % & | ^ << >>) / Compare(== != < > <= >=) + / BoolOp(and/or) / UnaryOp(not - + ~)。 + 成功置 self.CifEvalOk=1;失败(含运行时变量)置 0 返回 0。 + """ + if node is None: + self.CifEvalOk = 0 + return 0 + k: int = node.kind() + if k == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + if cn.const_kind == ast.CONST_INT: + self.CifEvalOk = 1 + return cn.int_val + self.CifEvalOk = 0 + return 0 + if k == ast.ASTKind.Call: + return self._cif_eval_call(pool, trans, node) + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is None: + self.CifEvalOk = 0 + return 0 + return self._cif_name_value(pool, trans, nm.id) + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + return self._cif_attr_value(pool, trans, at) + if k == ast.ASTKind.UnaryOp: + uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + if uop.operand is None: + self.CifEvalOk = 0 + return 0 + ov: int = self._cif_eval_node(pool, trans, uop.operand) + if self.CifEvalOk == 0: + return 0 + if uop.op == ast.OpKind.Not: return 1 if ov == 0 else 0 + if uop.op == ast.OpKind.USub: return -ov + if uop.op == ast.OpKind.UAdd: return ov + if uop.op == ast.OpKind.Invert: return ~ov + self.CifEvalOk = 0 + return 0 + if k == ast.ASTKind.BoolOp: + bo: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) + vals: list[ast.AST | t.CPtr] | t.CPtr = bo.values + if vals is None: + self.CifEvalOk = 0 + return 0 + bn: t.CSizeT = len(vals) + if bo.op == ast.OpKind.And: + for bi in range(bn): + rv: int = self._cif_eval_node(pool, trans, vals.get(bi)) + if self.CifEvalOk == 0: + return 0 + if rv == 0: + return 0 + return 1 + if bo.op == ast.OpKind.Or: + for bi in range(bn): + rv: int = self._cif_eval_node(pool, trans, vals.get(bi)) + if self.CifEvalOk == 0: + return 0 + if rv != 0: + return 1 + return 0 + self.CifEvalOk = 0 + return 0 + if k == ast.ASTKind.Compare: + cmp: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) + lv: int = self._cif_eval_node(pool, trans, cmp.left) + if self.CifEvalOk == 0: + return 0 + ops_list: list[t.CInt] | t.CPtr = (list[t.CInt] | t.CPtr)(cmp.ops) + comps: list[ast.AST | t.CPtr] | t.CPtr = cmp.comparators + if ops_list is None or comps is None: + self.CifEvalOk = 0 + return 0 + cc: t.CSizeT = len(comps) + ci: t.CSizeT + for ci in range(cc): + rv: int = self._cif_eval_node(pool, trans, comps.get(ci)) + if self.CifEvalOk == 0: + return 0 + op_id: int = ops_list.get(ci) + ok_cmp: int = 0 + if op_id == ast.OpKind.Eq: ok_cmp = 1 if lv == rv else 0 + elif op_id == ast.OpKind.Ne: ok_cmp = 1 if lv != rv else 0 + elif op_id == ast.OpKind.Lt: ok_cmp = 1 if lv < rv else 0 + elif op_id == ast.OpKind.Le: ok_cmp = 1 if lv <= rv else 0 + elif op_id == ast.OpKind.Gt: ok_cmp = 1 if lv > rv else 0 + elif op_id == ast.OpKind.Ge: ok_cmp = 1 if lv >= rv else 0 + else: + self.CifEvalOk = 0 + return 0 + if ok_cmp == 0: + return 0 + lv = rv + return 1 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + lv: int = self._cif_eval_node(pool, trans, bop.left) + if self.CifEvalOk == 0: + return 0 + rv: int = self._cif_eval_node(pool, trans, bop.right) + if self.CifEvalOk == 0: + return 0 + if bop.op == ast.OpKind.Add: return lv + rv + if bop.op == ast.OpKind.Sub: return lv - rv + if bop.op == ast.OpKind.Mult: return lv * rv + if bop.op == ast.OpKind.Div: + # 整数常量除法:与 FloorDiv 一致(对齐 TPC ConstEvaluator L354-355) + if rv == 0: + self.CifEvalOk = 0 + return 0 + return lv // rv + if bop.op == ast.OpKind.FloorDiv: + if rv == 0: + self.CifEvalOk = 0 + return 0 + return lv // rv + if bop.op == ast.OpKind.Mod: + if rv == 0: + self.CifEvalOk = 0 + return 0 + return lv % rv + if bop.op == ast.OpKind.BitAnd: return lv & rv + if bop.op == ast.OpKind.BitOr: return lv | rv + if bop.op == ast.OpKind.BitXor: return lv ^ rv + if bop.op == ast.OpKind.LShift: return lv << rv + if bop.op == ast.OpKind.RShift: return lv >> rv + self.CifEvalOk = 0 + return 0 + self.CifEvalOk = 0 + return 0 + + def _eval_ctraits_isptr(self, symtab: GenTypes.SymbolTable | t.CPtr, + name: str) -> int: + """ctraits.isptr(name) 编译期求值。 + + 按变量实际存储类型判断是否指针:alloca 的 pointee 为 Ptr 即指针 + (与 TPC ConstEvaluator._eval_compile_time_call 的 LLVM 类型判断一致)。 + 返回: 1=指针 0=非指针 -1=无法求值(变量不存在/无类型信息)。 + """ + if name is None or symtab is None: + return -1 + v: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(symtab, name) + if v is None or v.Ty is None: + return -1 + pointee: llvmlite.LLVMType | t.CPtr = v.Ty.Pointee + if pointee is not None and self.Gen.ExprGenBase.is_ptr_type(pointee) != 0: + return 1 + return 0 + + def _cif_eval_call(self, pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """编译期函数调用求值:ctraits.isptr(x)。 + + 命中置 self.CifEvalOk=1 返回 1/0;未识别调用置 0 返回 0。 + """ + self.CifEvalOk = 0 + if node is None or trans is None: + return 0 + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + if cl is None or cl.func is None: + return 0 + fk: int = cl.func.kind() + if fk != ast.ASTKind.Attribute: + return 0 + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if at.value is None or at.attr is None: + return 0 + if at.value.kind() != ast.ASTKind.Name: + return 0 + vn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if vn.id is None: + return 0 + if string.strcmp(vn.id, "ctraits") != 0 or string.strcmp(at.attr, "isptr") != 0: + return 0 + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or len(cargs) < 1: + self.CifEvalOk = 0 + return 0 + arg0: ast.AST | t.CPtr = cargs.get(0) + if arg0 is None or arg0.kind() != ast.ASTKind.Name: + self.CifEvalOk = 0 + return 0 + nm0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0) + if nm0.id is None: + self.CifEvalOk = 0 + return 0 + r: int = self._eval_ctraits_isptr(trans.SymTab, nm0.id) + if r < 0: + self.CifEvalOk = 0 + return 0 + self.CifEvalOk = 1 + return r + + def _evaluate_cif_test(self, pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr, + test: ast.AST | t.CPtr) -> int: + """求值 CIf 调用(test 必须是 c.CIf 系调用)。 + + 成功: 置 self.CifEvalOk=1,返回条件值(0/1) + 失败(运行时变量/未知结构): 置 self.CifEvalOk=0,返回 0 + """ + self.CifEvalOk = 0 + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(test) + if cl is None or cl.func is None: + return 0 + kind: str = None + fk: int = cl.func.kind() + if fk == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + kind = at.attr + elif fk == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl.func) + kind = nm.id + if kind is None: + return 0 + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or len(cargs) < 1: + return 0 + arg0: ast.AST | t.CPtr = cargs.get(0) + if string.strcmp(kind, "CIf") == 0: + v: int = self._cif_eval_node(pool, trans, arg0) + if self.CifEvalOk == 0: + return 0 + return 1 if v != 0 else 0 + # CIfdef / CIfndef: 判定宏名是否已定义 + defined: int = 0 + if arg0 is not None and arg0.kind() == ast.ASTKind.Name: + nm0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0) + if nm0.id is None: + return 0 + self._cif_name_value(pool, trans, nm0.id) + defined = self.CifEvalOk + elif arg0 is not None and arg0.kind() == ast.ASTKind.Constant: + cn0: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg0) + if cn0.const_kind == ast.CONST_STR and cn0.str_val is not None: + self._cif_name_value(pool, trans, cn0.str_val) + defined = self.CifEvalOk + else: + return 0 + elif arg0 is not None and arg0.kind() == ast.ASTKind.Attribute: + at0: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg0) + self._cif_attr_value(pool, trans, at0) + defined = self.CifEvalOk + else: + return 0 + # 定义判定本身成功(未定义名特判:不报错,defined=0 走 else) + self.CifEvalOk = 1 + if string.strcmp(kind, "CIfdef") == 0: + return 1 if defined != 0 else 0 + # CIfndef + return 0 if defined != 0 else 1 + + # ============================================================ + # translate_return - Return 语句翻译(迁移自 HandlesReturn.ReturnHandle.Handle) + # + # 翻译返回值(若有)并生成 ret 指令;裸 return 按函数返回类型生成 + # 默认零值(void→ret void,ptr→null,float→0.0,其余→零值)。 + # ============================================================ + def translate_return(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 Return 语句""" + rt: ast.Return | t.CPtr = (ast.Return | t.CPtr)(node) + if rt is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + + val: llvmlite.Value | t.CPtr = None + if rt.value is not None: + # return a, b → 打包匿名 struct 值(多返回值,函数返回类型 tuple[T1,T2]) + if rt.value.kind() == ast.ASTKind.Tuple: + rtp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(rt.value) + rtp_elts: list[ast.AST | t.CPtr] | t.CPtr = rtp.elts + rt_n: t.CSizeT = 0 + if rtp_elts is not None: + rt_n = len(rtp_elts) + if rt_n > 0 and rt_n <= 16: + rt_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 16) + if rt_vals is not None: + rt_val_ok: int = 1 + rt_head: llvmlite.ParamNode | t.CPtr = None + rt_tail: llvmlite.ParamNode | t.CPtr = None + rvi: t.CSizeT + for rvi in range(rt_n): + ev_i: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, rtp_elts.get(rvi), + trans._funcs, trans._func_count, trans) + if ev_i is None: + rt_val_ok = 0 + break + rt_vals[rvi] = t.CSizeT(ev_i) + if rt_val_ok != 0: + # 构建匿名 struct 类型(字段类型 = 元素值类型) + rvi2: t.CSizeT + for rvi2 in range(rt_n): + rv_i: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)( + t.CVoid(rt_vals[rvi2], t.CPtr)) + if rv_i is None or rv_i.Ty is None: + rt_val_ok = 0 + break + rn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, rv_i.Ty) + if rn is None: + rt_val_ok = 0 + break + if rt_head is None: + rt_head = rn + else: + llvmlite.paramnode_set_next(rt_tail, rn) + rt_tail = rn + rt_struct_ty: llvmlite.LLVMType | t.CPtr = None + if rt_val_ok != 0 and rt_head is not None: + rt_struct_ty = llvmlite.Struct(pool, rt_head, rt_n, None) + rt_tmp: llvmlite.Value | t.CPtr = None + if rt_struct_ty is not None: + rt_tmp = llvmlite.build_alloca(builder, rt_struct_ty) + if rt_tmp is not None: + rvi3: t.CSizeT + for rvi3 in range(rt_n): + rv3: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)( + t.CVoid(rt_vals[rvi3], t.CPtr)) + rfp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, rt_struct_ty, rv3.Ty, rt_tmp, rvi3) + if rfp is None: + rt_val_ok = 0 + break + llvmlite.build_store(builder, rv3, rfp) + if rt_val_ok != 0: + val = llvmlite.build_load(builder, rt_struct_ty, rt_tmp) + # return self: 返回 self 指针本身(Ptr(StructTy)),而非结构体值 + # translate_value 会 load 得到结构体值,但 return self 需要指针 + # 注意: lookup_var 返回的是存储 self 的 alloca (Ptr(Ptr(StructTy))) + # 需要 load 得到实际的 self 指针 (Ptr(StructTy)) + if rt.value.kind() == ast.ASTKind.Name: + ret_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rt.value) + if ret_nm is not None and ret_nm.id is not None \ + and string.strcmp(ret_nm.id, "self") == 0: + self_ptr: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, "self") + if self_ptr is not None: + # 检查 self_ptr 是否是 Ptr(Ptr(...))(alloca 存储指针) + self_pointee_ty: llvmlite.LLVMType | t.CPtr = None + match self_ptr.Ty: + case llvmlite.LLVMType.Ptr(inner_ty): + self_pointee_ty = inner_ty + if self_pointee_ty is not None and self.Gen.ExprGenBase.is_ptr_type(self_pointee_ty) != 0: + # Ptr(Ptr(StructTy)) → load 得到 Ptr(StructTy) + val = llvmlite.build_load(builder, self_pointee_ty, self_ptr) + else: + val = self_ptr + if val is None: + val = self.Gen.ExprGen.translate_value( + builder, pool, mod, rt.value, + trans._funcs, trans._func_count, trans) + + # val 为 None 时(裸 return):检查当前函数返回类型 + # void 函数(如 __init__/__before_init__)生成 ret void, + # ptr 函数生成 ret ptr null,浮点函数生成 ConstFloat(0.0), + # 否则 ret i32 0(浮点漏处理会报 llc: value doesn't match function result type) + if val is None: + cur_func: llvmlite.Function | t.CPtr = trans._cur_func + is_void_ret: int = 0 + is_ptr_ret: int = 0 + is_float_ret: int = 0 + ret_ty: llvmlite.LLVMType | t.CPtr = None + if cur_func is not None: + ret_ty = llvmlite.function_get_ret_ty(cur_func) + if ret_ty is not None: + match ret_ty: + case llvmlite.LLVMType.Void(): + is_void_ret = 1 + case llvmlite.LLVMType.Ptr(_pe): + is_ptr_ret = 1 + case llvmlite.LLVMType.Float(_fb): + is_float_ret = 1 + if is_void_ret != 0: + llvmlite.build_ret_void(builder) + return 0 + if is_ptr_ret != 0: + null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, ret_ty, "null") + llvmlite.build_ret(builder, null_val) + return 0 + if is_float_ret != 0: + zero_f: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, ret_ty, 0.0) + llvmlite.build_ret(builder, zero_f) + return 0 + if ret_ty is None: + # fail-fast: 裸 return 无法确定函数返回类型,禁止硬编码 i32 零值兜底 + self.Gen.TypeGenErr.fatal_error(rt, "函数返回类型无法确定", "TypeError") + val = llvmlite.ConstZero(pool, ret_ty) + if val is None: + # fail-fast: 无法按返回类型构造零值 + self.Gen.TypeGenErr.fatal_error(rt, "函数返回类型无法确定", "TypeError") + + # 类型转换:确保 val 类型与函数返回类型匹配 + # 处理 i1(bool 比较结果)→ i8(t.CBool)等情况 + # i1 → 更宽整数用 zext(bool 语义:1 保持 1,而非 sext 的 0xFF) + # 注意:当 val 是整数而 ret_ty 是 ptr 时(即使 bits 相同,如 i64 vs ptr), + # 也必须 inttoptr 转换,否则 llc 报 "value doesn't match function result type" + cur_func_rt: llvmlite.Function | t.CPtr = trans._cur_func + ret_ty_rt: llvmlite.LLVMType | t.CPtr = None + if cur_func_rt is not None and val is not None and val.Ty is not None: + ret_ty_rt = llvmlite.function_get_ret_ty(cur_func_rt) + if ret_ty_rt is not None: + val_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(val.Ty) + ret_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(ret_ty_rt) + val_is_ptr: int = self.Gen.ExprGenBase.is_ptr_type(val.Ty) + ret_is_ptr: int = self.Gen.ExprGenBase.is_ptr_type(ret_ty_rt) + # ptr 类型不一致性:val 是整数但 ret 是 ptr(或反之),必须转换 + if val_is_ptr != ret_is_ptr: + val = self.Gen.ExprGenBase.coerce_to_type(builder, val, ret_ty_rt, node) + elif val_is_ptr != 0 and ret_is_ptr != 0: + # 指针 → 指针且元素类型不同(如 t.CVoid(x, CPtr) 得到 i8*, + # 函数返回类型是类指针 Circle* 时)需 bitcast 回, + # 否则 llc 报 "value doesn't match function result type"。 + val_pointee: llvmlite.LLVMType | t.CPtr = None + ret_pointee: llvmlite.LLVMType | t.CPtr = None + match val.Ty: + case llvmlite.LLVMType.Ptr(v_inner): + val_pointee = v_inner + match ret_ty_rt: + case llvmlite.LLVMType.Ptr(r_inner): + ret_pointee = r_inner + if val_pointee is not None and ret_pointee is not None \ + and t.CUInt64T(val_pointee) != t.CUInt64T(ret_pointee): + val = self.Gen.ExprGenBase.coerce_to_type(builder, val, ret_ty_rt, node) + elif val_bits != 0 and ret_bits != 0 and val_bits != ret_bits: + if val_bits == 1 and val_bits < ret_bits: + val = llvmlite.build_zext(builder, val, ret_ty_rt) + else: + val = self.Gen.ExprGenBase.coerce_to_type(builder, val, ret_ty_rt, node) + llvmlite.build_ret(builder, val) + return 0 + + # ============================================================ + # translate_if - if/elif/else 语句翻译(迁移自 HandlesIf.IfHandle.Handle) + # + # 编译期宏条件: if c.CIf(...) / c.CIfdef(...) / c.CIfndef(...) + # 求值成功 → 只编译命中的分支(剪枝,不发射运行时 IR),elif 递归 + # 求值失败(运行时变量等)→ 回退运行时翻译。 + # 运行时翻译 if 语句为 LLVM IR 控制流: + # br i1 %cond, label %then, label %else + # then: + # ... body ... + # br label %end + # else: + # ... orelse ... + # br label %end + # end: + # ============================================================ + def translate_if(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 if/elif/else 语句""" + if node is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + + if builder is None or func is None: + return 0 + + if_node: ast.If | t.CPtr = (ast.If | t.CPtr)(node) + + # 0. 编译期宏条件: if c.CIf(...) / c.CIfdef(...) / c.CIfndef(...) + # 求值成功 → 只编译命中的分支(剪枝,不发射运行时 IR),elif 递归 + # 求值失败(运行时变量等)→ 回退运行时翻译 + if self._is_cif_call(if_node.test) == 1: + cif_val: int = self._evaluate_cif_test(pool, trans, if_node.test) + if self.CifEvalOk != 0: + if cif_val != 0: + body_cif: list[ast.AST | t.CPtr] | t.CPtr = if_node.children + if body_cif is not None: + bc_cif: t.CSizeT = len(body_cif) + bi_cif: t.CSizeT + for bi_cif in range(bc_cif): + stmt_cif: ast.AST | t.CPtr = body_cif.get(bi_cif) + if stmt_cif is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt_cif) + else: + orelse_cif: list[ast.AST | t.CPtr] | t.CPtr = if_node.orelse + if orelse_cif is not None and len(orelse_cif) == 1: + sub_cif: ast.AST | t.CPtr = orelse_cif.get(0) + if sub_cif is not None and sub_cif.kind() == ast.ASTKind.If: + # elif: 递归(子 If 的 test 仍会走 CIf 判定或运行时翻译) + self.translate_if(trans, sub_cif) + elif sub_cif is not None: + self.Gen.StmtGen.translate_stmt(trans, sub_cif) + elif orelse_cif is not None: + oc_cif: t.CSizeT = len(orelse_cif) + oi_cif: t.CSizeT + for oi_cif in range(oc_cif): + stmt_cif2: ast.AST | t.CPtr = orelse_cif.get(oi_cif) + if stmt_cif2 is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt_cif2) + return 0 + + # 1. 求值条件表达式 + cond_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, if_node.test, + trans._funcs, trans._func_count, trans) + + # 2. 转换为 i1 条件 + # Compare/Not 表达式已返回 i1,直接使用;指针类型与 null 比较;其他类型与 0 比较 + if cond_val is None: + # fail-fast: if 条件表达式翻译失败 + self.Gen.TypeGenErr.fatal_error(if_node.test, "if 条件表达式翻译失败", "TypeError") + cond_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(cond_val.Ty) + if cond_bits == 1: + cond_i1: llvmlite.Value | t.CPtr = cond_val + elif self.Gen.ExprGenBase.is_ptr_type(cond_val.Ty) != 0: + # 指针类型:与 null 比较(不能用整数 0,否则 llc 报 "integer constant must have integer type") + null_cond: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cond_val.Ty, "null") + cond_i1 = llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, cond_val, null_cond) + else: + zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + cond_i1 = llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, cond_val, zero) + + # 3. 创建基本块(使用 trans._label_counter 生成唯一标签名,不与 SSA 名共享) + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + + name_buf: str = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "if.then.%d", cnt) + then_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "if.end.%d", cnt) + merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + # 检查是否有 else 分支 + has_else: int = 0 + orelse_list: list[ast.AST | t.CPtr] | t.CPtr = if_node.orelse + if orelse_list is not None: + if len(orelse_list) > 0: + has_else = 1 + + else_bb: llvmlite.BasicBlock | t.CPtr = None + if has_else == 1: + viperlib.snprintf(name_buf, 32, "if.else.%d", cnt) + else_bb = llvmlite.create_block(pool, func, name_buf) + + # 4. 发射条件分支 + if has_else == 1: + llvmlite.build_cond_br(builder, cond_i1, then_bb, else_bb) + else: + llvmlite.build_cond_br(builder, cond_i1, then_bb, merge_bb) + + # 5. 翻译 then body + # 重置 merge 可达标志:分支内嵌套控制流会覆盖该标志,分支末尾判定依据 + # "分支最后语句的控制流状态",须防进入本 If 前的残留值污染(append90 + # 末句 If 全 return 被 fail-fast 误判"流程掉出末尾"的根因链一环) + trans._ctrl_merge_reachable = 1 + llvmlite.position_at_end(builder, then_bb) + body: list[ast.AST | t.CPtr] | t.CPtr = if_node.children + if body is not None: + body_count: t.CSizeT = len(body) + for bi in range(body_count): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt) + + # then 块未终止则跳到 merge(记录 then 是否 br 到 merge) + then_branches_merge: int = 0 + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + if trans._ctrl_merge_reachable == 0: + # 分支末尾是嵌套控制流且 merge 结构性不可达(全分支 return): + # 当前块是嵌套的 merge(无 terminator),补 unreachable 收尾。 + # 不补 br merge——否则外层 If 的"分支是否 br merge"判定把不可达 + # 分支当可达,函数末句 If 全 return 被误判"流程掉出末尾" + # (vipermath.vp atan2 根因;对齐 FuncGenDef append90 unreachable) + llvmlite.build_unreachable(builder) + else: + llvmlite.build_br(builder, merge_bb) + then_branches_merge = 1 + + # 6. 翻译 else body(若有) + else_branches_merge: int = 0 + if has_else == 1: + # 同 then:重置标志防残留(else 是普通语句时不被 then 的嵌套控制流值污染) + trans._ctrl_merge_reachable = 1 + llvmlite.position_at_end(builder, else_bb) + else_count: t.CSizeT = len(orelse_list) + for ei in range(else_count): + stmt: ast.AST | t.CPtr = orelse_list.get(ei) + if stmt is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt) + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + if trans._ctrl_merge_reachable == 0: + # 嵌套控制流全分支 return:补 unreachable,不 br merge(同 then 分支) + llvmlite.build_unreachable(builder) + else: + llvmlite.build_br(builder, merge_bb) + else_branches_merge = 1 + + # 7. merge 块可达性(追加90,末句控制流收尾判定用): + # 无 else 时 cond_br 直接跳 merge(恒可达);有 else 时任一分支 + # br 到 merge 即可达;全分支 return(无 br)才结构性不可达。 + # 经 HandlesBase 模块级全局传递(避免依赖 Translator 字段表) + trans._ctrl_merge_reachable = 1 + if has_else == 1 and then_branches_merge == 0 and else_branches_merge == 0: + trans._ctrl_merge_reachable = 0 + + # 8. 定位到 merge 块继续后续代码 + llvmlite.position_at_end(builder, merge_bb) + return 0 + + # ============================================================ + # translate_while - while 循环语句翻译(迁移自 HandlesWhile.WhileHandle.Handle) + # + # 翻译 while 语句为 LLVM IR 控制流: + # br label %cond + # cond: + # %t = + # %c = icmp ne i32 %t, 0 + # br i1 %c, label %body, label %end + # body: + # ... body ... + # br label %cond + # end: + # ============================================================ + def translate_while(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 while 循环语句""" + if node is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + + if builder is None or func is None: + return 0 + + while_node: ast.While | t.CPtr = (ast.While | t.CPtr)(node) + + # 1. 创建基本块: cond / body / end(使用 trans._label_counter,不与 SSA 名共享) + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + + name_buf: str = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "while.cond.%d", cnt) + cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "while.body.%d", cnt) + body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "while.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + # 2. 跳转到 cond 块 + llvmlite.build_br(builder, cond_bb) + + # 3. cond 块: 求值条件,条件分支 + llvmlite.position_at_end(builder, cond_bb) + cond_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, while_node.test, + trans._funcs, trans._func_count, trans) + if cond_val is None: + # fail-fast: while 条件表达式翻译失败 + self.Gen.TypeGenErr.fatal_error(while_node.test, "while 条件表达式翻译失败", "TypeError") + + # Compare/Not 表达式已返回 i1,直接使用;指针类型与 null 比较;其他类型与 0 比较 + cond_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(cond_val.Ty) + if cond_bits == 1: + cond_i1: llvmlite.Value | t.CPtr = cond_val + elif self.Gen.ExprGenBase.is_ptr_type(cond_val.Ty) != 0: + # 指针类型:与 null 比较(不能用整数 0,否则 llc 报 "integer constant must have integer type") + null_cond: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cond_val.Ty, "null") + cond_i1 = llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, cond_val, null_cond) + else: + zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + cond_i1 = llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, cond_val, zero) + llvmlite.build_cond_br(builder, cond_i1, body_bb, end_bb) + + # 4. body 块: 翻译循环体,跳回 cond + llvmlite.position_at_end(builder, body_bb) + + # 保存旧循环上下文,设置 break/continue 目标 + old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb + old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb + trans._break_bb = end_bb + trans._continue_bb = cond_bb + + body: list[ast.AST | t.CPtr] | t.CPtr = while_node.children + if body is not None: + body_count: t.CSizeT = len(body) + for bi in range(body_count): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt) + + # 恢复旧循环上下文 + trans._break_bb = old_break + trans._continue_bb = old_continue + + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, cond_bb) + + # 5. 定位到 end 块 + llvmlite.position_at_end(builder, end_bb) + # 追加90:while 的 cond_br 恒引用 end_bb → merge 恒可达(需正常收尾) + trans._ctrl_merge_reachable = 1 + # 无限循环(条件常量真 1/True)且循环体无本层 break → 运行时无任何边 + # 到达 end 块(merge 结构性不可达)→ 置 0,函数收尾对末句 While 生成 + # unreachable(追加90:无 br 到达 merge 时才安全;否则 llc O2 把 + # br-to-unreachable 优化为 fall-through → 双分支执行崩溃)。 + # 修复 vrandom.gammavariate 的 while 1 全 return 被误判"流程掉出末尾"。 + if self._IsConstTrue(while_node.test) != 0 and self._StmtHasBreak(body) == 0: + trans._ctrl_merge_reachable = 0 + return 0 + + # ============================================================ + # 无限循环判定辅助(merge 可达性,迁移自 HandlesWhile 模块级函数) + # + # _IsConstTrue: while 条件为常量真(CONST_INT 非 0 / CONST_BOOL 真) + # _NodeHasBreak / _StmtHasBreak: 扫描本层 break(跳过嵌套 While/For + # 子树——嵌套循环的 break 归内层,不影响外层 merge 可达性) + # ============================================================ + def _IsConstTrue(self, test: ast.AST | t.CPtr) -> int: + """while 条件为常量真(1 / True)返回 1""" + if test is None: + return 0 + if test.kind() == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(test) + if cn.const_kind == ast.CONST_INT and cn.int_val != 0: + return 1 + if cn.const_kind == ast.CONST_BOOL and cn.int_val != 0: + return 1 + return 0 + + def _NodeHasBreak(self, node: ast.AST | t.CPtr) -> int: + """递归扫描节点子树(跳过嵌套 While/For 子树),含 Break 返回 1""" + if node is None: + return 0 + ch: list[ast.AST | t.CPtr] | t.CPtr = node.children + if ch is not None: + n: t.CSizeT = len(ch) + for bi in range(n): + c: ast.AST | t.CPtr = ch.get(bi) + if c is None: + continue + k: int = c.kind() + if k == ast.ASTKind.Break: + return 1 + if k == ast.ASTKind.While or k == ast.ASTKind.For: + continue + if self._NodeHasBreak(c) != 0: + return 1 + return 0 + + def _StmtHasBreak(self, body: list[ast.AST | t.CPtr] | t.CPtr) -> int: + """语句列表是否含本层 break(嵌套循环的 break 归内层)""" + if body is None: + return 0 + n: t.CSizeT = len(body) + for bi in range(n): + s: ast.AST | t.CPtr = body.get(bi) + if s is None: + continue + k: int = s.kind() + if k == ast.ASTKind.Break: + return 1 + if k == ast.ASTKind.While or k == ast.ASTKind.For: + continue + if self._NodeHasBreak(s) != 0: + return 1 + return 0 + + # ============================================================ + # translate_for - for 循环语句翻译(迁移自 HandlesFor.ForHandle.Handle) + # + # 支持 for i in range(start, stop, step) 模式: + # %i = alloca i32 + # store i32 start, i32* %i + # br label %cond + # cond: + # %cur = load i32, i32* %i + # %cmp = icmp slt i32 %cur, stop + # br i1 %cmp, label %body, label %end + # body: + # ... body ... + # br label %incr + # incr: + # %cur2 = load i32, i32* %i + # %next = add i32 %cur2, step + # store i32 %next, i32* %i + # br label %cond + # end: + # ============================================================ + def translate_for(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 for i in range(...) 循环语句""" + if node is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + + if builder is None or func is None: + return 0 + + for_node: ast.For | t.CPtr = (ast.For | t.CPtr)(node) + + # 1. 获取循环变量(Name 单变量 / Tuple 多变量) + target: ast.AST | t.CPtr = for_node.target + if target is None: + return 0 + tk: int = target.kind() + if tk != ast.ASTKind.Name and tk != ast.ASTKind.Tuple: + return 0 + var_name: str = None + if tk == ast.ASTKind.Name: + target_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) + var_name = target_nm.id + if var_name is None: + return 0 + + # 2. 解析迭代器:支持 range() 和指针迭代 + iter_node: ast.AST | t.CPtr = for_node.iter + if iter_node is None: + return 0 + + # 检查是否是 range() 调用 + is_range_iter: int = 0 + if iter_node.kind() == ast.ASTKind.Call: + call_pre: ast.Call | t.CPtr = (ast.Call | t.CPtr)(iter_node) + fn_pre: str = self.Gen.ExprGenBase.get_func_name(call_pre.func) + if fn_pre is not None: + if string.strcmp(fn_pre, "range") == 0: + is_range_iter = 1 + elif string.strcmp(fn_pre, "enumerate") == 0 or string.strcmp(fn_pre, "zip") == 0: + pass # 多变量迭代,在下方非 range 分支处理 + else: + err_msg: str = pool.alloc(256) + if err_msg is not None: + viperlib.snprintf(err_msg, 256, "仅支持 range()/enumerate()/zip() 或指针迭代,got call '%s'", fn_pre) + self.Gen.TypeGenErr.fatal_error(iter_node, err_msg) + self.Gen.TypeGenErr.fatal_error(iter_node, "仅支持 range()/enumerate()/zip() 或指针迭代") + + # 非范围迭代:走指针/数组/列表字面量/容器/多变量迭代路径 + if is_range_iter == 0: + # 列表字面量:按元素顺序迭代(for x in [1, 2, 3]) + if iter_node.kind() == ast.ASTKind.List: + return self._handle_list_literal_iter(trans, for_node, var_name, iter_node) + # enumerate(x):for i, v in enumerate(x)(多变量迭代) + if iter_node.kind() == ast.ASTKind.Call: + call_mi: ast.Call | t.CPtr = (ast.Call | t.CPtr)(iter_node) + fn_mi: str = self.Gen.ExprGenBase.get_func_name(call_mi.func) + if fn_mi is not None and string.strcmp(fn_mi, "enumerate") == 0: + if tk != ast.ASTKind.Tuple: + self.Gen.TypeGenErr.fatal_error(iter_node, "enumerate 迭代需要两个循环变量 (for i, v in enumerate(x))") + tup_ie: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(target) + t1_buf_ie: bytes = pool.alloc(128) + t2_buf_ie: bytes = pool.alloc(128) + if t1_buf_ie is None or t2_buf_ie is None: + return 0 + t1_buf_ie[0] = '\0' + t2_buf_ie[0] = '\0' + if self._extract_tuple_names(tup_ie, t1_buf_ie, t2_buf_ie) == 0: + self.Gen.TypeGenErr.fatal_error(iter_node, "enumerate 迭代变量必须是简单名称") + return self._handle_enumerate_iter(trans, for_node, t1_buf_ie, t2_buf_ie, call_mi) + if fn_mi is not None and string.strcmp(fn_mi, "zip") == 0: + if tk != ast.ASTKind.Tuple: + self.Gen.TypeGenErr.fatal_error(iter_node, "zip 迭代需要两个循环变量 (for a, b in zip(...))") + tup_iz: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(target) + t1_buf_iz: bytes = pool.alloc(128) + t2_buf_iz: bytes = pool.alloc(128) + if t1_buf_iz is None or t2_buf_iz is None: + return 0 + t1_buf_iz[0] = '\0' + t2_buf_iz[0] = '\0' + if self._extract_tuple_names(tup_iz, t1_buf_iz, t2_buf_iz) == 0: + self.Gen.TypeGenErr.fatal_error(iter_node, "zip 迭代变量必须是简单名称") + return self._handle_zip_iter(trans, for_node, t1_buf_iz, t2_buf_iz, call_mi) + # list[T] 容器变量:按 __count__ 动态长度迭代 + if iter_node.kind() == ast.ASTKind.Name and trans is not None: + nm_lst: ast.Name | t.CPtr = (ast.Name | t.CPtr)(iter_node) + if nm_lst.id is not None: + ve_lst: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, nm_lst.id) + if ve_lst is not None and ve_lst.AnnotClassName is not None: + # dict 容器变量:按 __count__/__keys__ 布局迭代(__iter__ 协议内联) + if string.strstr(ve_lst.AnnotClassName, "dict") is not None: + lst_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, iter_node, + trans._funcs, trans._func_count, trans) + if lst_val is not None and lst_val.Ty is not None \ + and self.Gen.ExprGenBase.is_ptr_type(lst_val.Ty) != 0: + return self._handle_dict_iter(trans, for_node, var_name, lst_val) + if string.strstr(ve_lst.AnnotClassName, "list") is not None: + lst_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, iter_node, + trans._funcs, trans._func_count, trans) + if lst_val is not None and lst_val.Ty is not None \ + and self.Gen.ExprGenBase.is_ptr_type(lst_val.Ty) != 0: + return self._handle_list_iter(trans, for_node, var_name, lst_val) + # OOP iter 协议:迭代源是类对象且类有 __iter__/__next__ 方法 → + # 走 __iter__/__next__ 调用迭代(对齐 TPC HandlesFor.py L142-166 + # _HandleForIterLlvm)。dict/list 是内置泛型容器已在上方内联处理。 + ov_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, iter_node, + trans._funcs, trans._func_count, trans) + if ov_val is not None and ov_val.Ty is not None \ + and self.Gen.ExprGenBase.is_ptr_type(ov_val.Ty) != 0: + ov_st: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type_from_value( + ov_val) + if ov_st is not None: + ov_cn: str = self.Gen.StructGen.get_class_name_by_type(pool, ov_st) + if ov_cn is not None: + oi_lookup: str = pool.alloc(128) + if oi_lookup is not None: + viperlib.snprintf(oi_lookup, 128, "%s.__iter__", ov_cn) + oi_fn: llvmlite.Function | t.CPtr = self.Gen.CallGenBase.find_func_in_module( + trans.Module, oi_lookup) + if oi_fn is not None: + on_lookup: str = pool.alloc(128) + if on_lookup is not None: + viperlib.snprintf(on_lookup, 128, "%s.__next__", ov_cn) + on_fn: llvmlite.Function | t.CPtr = self.Gen.CallGenBase.find_func_in_module( + trans.Module, on_lookup) + if on_fn is not None: + return self._handle_oop_iter( + trans, for_node, var_name, ov_cn, ov_val) + # 其它不支持的字面量:fast-fail 显式报错, + # 避免 translate_value 触发 list[T] 特化崩溃或语义歧义。 + ik: int = iter_node.kind() + if ik == ast.ASTKind.Constant: + cn_ik: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(iter_node) + if cn_ik.const_kind != ast.CONST_STR: + self.Gen.TypeGenErr.fatal_error( + iter_node, + "for 迭代不支持该常量(仅支持字符串、数组、列表字面量、range())") + elif ik == ast.ASTKind.Dict or ik == ast.ASTKind.Set or ik == ast.ASTKind.Tuple \ + or ik == ast.ASTKind.SetComp or ik == ast.ASTKind.DictComp: + self.Gen.TypeGenErr.fatal_error( + iter_node, + "for 迭代不支持字典/集合/元组字面量,请使用 range()、t.CArray 数组或列表字面量") + return self._handle_ptr_iter(trans, for_node, var_name) + + call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(iter_node) + + # 3. 解析 range 参数: range(stop) / range(start, stop) / range(start, stop, step) + args: list[ast.AST | t.CPtr] | t.CPtr = call.args + if args is None: + return 0 + arg_count: t.CSizeT = len(args) + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + start_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + stop_val: llvmlite.Value | t.CPtr = None + step_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) + + if arg_count == 0: + # fail-fast: range 无参数,立即终止 + self.Gen.TypeGenErr.fatal_error(call, "range 需要至少一个参数", "SyntaxError") + elif arg_count == 1: + stop_val = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, args.get(0), + trans._funcs, trans._func_count, trans) + if stop_val is None: + # fail-fast: range 参数翻译失败 + self.Gen.TypeGenErr.fatal_error(args.get(0), "range 参数翻译失败", "TypeError") + elif arg_count >= 2: + start_val = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, args.get(0), + trans._funcs, trans._func_count, trans) + if start_val is None: + # fail-fast: range 参数翻译失败 + self.Gen.TypeGenErr.fatal_error(args.get(0), "range 参数翻译失败", "TypeError") + stop_val = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, args.get(1), + trans._funcs, trans._func_count, trans) + if stop_val is None: + # fail-fast: range 参数翻译失败 + self.Gen.TypeGenErr.fatal_error(args.get(1), "range 参数翻译失败", "TypeError") + if arg_count >= 3: + step_val = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, args.get(2), + trans._funcs, trans._func_count, trans) + if step_val is None: + # fail-fast: range 参数翻译失败 + self.Gen.TypeGenErr.fatal_error(args.get(2), "range 参数翻译失败", "TypeError") + # step 为负数字面量时循环条件反转(对齐 TPC HandlesFor.py L86-94): + # range(a, b, -1) → i > stop;range(a, b, +1) → i < stop。 + # TPC 仅识别负数字面量(UnaryOp USub 常量 / 负常量);变量 step 保守按正。 + # 修复 _find_provider 的 range(top-1, -1, -1) 循环体不执行(i < -1 恒假)。 + step_neg_const: int = 0 + if arg_count >= 3: + step_arg_node: ast.AST | t.CPtr = args.get(2) + if step_arg_node is not None: + skn: int = step_arg_node.kind() + if skn == ast.ASTKind.UnaryOp: + uop_r: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(step_arg_node) + if uop_r.op == ast.OpKind.USub and uop_r.operand is not None: + if uop_r.operand.kind() == ast.ASTKind.Constant: + uoc_r: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(uop_r.operand) + if uoc_r.int_val > 0: + step_neg_const = 1 + elif skn == ast.ASTKind.Constant: + skc_r: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(step_arg_node) + if skc_r.int_val < 0: + step_neg_const = 1 + + # 4. 创建/查找循环变量 alloca + var_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, var_name) + new_vars: int = 0 + if var_alloca is None: + var_alloca = self.Gen.VarGen._alloca_at_entry(builder, i32_ty) + if self.Gen.VarGen.define_var( + trans.SymTab, var_name, var_alloca) == 0: + new_vars = 1 + + # 获取循环变量的实际元素类型(alloca 是指针类型,需解引用 Pointee) + # 当循环变量已声明为 i64(如 t.CSizeT),使用 i64 而非硬编码 i32 + # 避免 load i32, i64* / store i32, i64* 类型不匹配 + loop_var_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if var_alloca is not None and var_alloca.Ty is not None: + match var_alloca.Ty: + case llvmlite.LLVMType.Ptr(pointee_ty): + if pointee_ty is not None: + loop_var_ty = pointee_ty + loop_var_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(loop_var_ty) + + # 5. 存储初始值 (类型对齐: start_val 可能是 i32/i64,需对齐到 loop_var_ty) + init_val: llvmlite.Value | t.CPtr = start_val + if start_val is not None and start_val.Ty is not None: + start_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(start_val.Ty) + if start_bits != 0 and start_bits != loop_var_bits: + if start_bits < loop_var_bits: + init_val = llvmlite.build_sext(builder, start_val, loop_var_ty) + else: + init_val = llvmlite.build_trunc(builder, start_val, loop_var_ty) + llvmlite.build_store(builder, init_val, var_alloca) + + # 6. 创建基本块: cond / body / incr / end(使用 trans._label_counter,不与 SSA 名共享) + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + + name_buf: str = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "for.cond.%d", cnt) + cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "for.body.%d", cnt) + body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "for.incr.%d", cnt) + incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "for.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + # 7. 跳转到 cond 块 + llvmlite.build_br(builder, cond_bb) + + # 8. cond 块: load i, icmp slt i, stop, cond_br body/end + llvmlite.position_at_end(builder, cond_bb) + cur_i: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, loop_var_ty, var_alloca) + # 类型对齐: stop_val 可能是 i64 (如 range(strlen(s))),需将 cur_i 提升到 stop_val 类型 + cmp_lhs: llvmlite.Value | t.CPtr = cur_i + cmp_rhs: llvmlite.Value | t.CPtr = stop_val + if stop_val is not None and stop_val.Ty is not None: + stop_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(stop_val.Ty) + cur_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(cur_i.Ty) + if stop_bits != 0 and cur_bits != 0 and stop_bits != cur_bits: + if cur_bits < stop_bits: + cmp_lhs = llvmlite.build_sext(builder, cur_i, stop_val.Ty) + else: + # 循环变量位宽 > stop 位宽(如 t.CSizeT 循环变量 + range(i32)): + # 应把 cur_i 截断到 stop_val 类型(低向高才 sext/zext,高向低用 + # trunc)。原实现反了——把小的 stop_val trunc 到大的 loop_var_ty, + # 生成 `trunc i32 to i64` 扩宽非法 IR,llc 报 + # "invalid cast opcode for cast from 'i32' to 'i64'" + # (VpiReader.vp range(arg_count) 追加86 根因)。 + cmp_lhs = llvmlite.build_trunc(builder, cur_i, stop_val.Ty) + # step 为负时条件反转:i > stop(ICMP_SGT);正/缺省 step 保持 i < stop + range_cmp_op: int = llvmlite.ICMP_SLT + if step_neg_const != 0: + range_cmp_op = llvmlite.ICMP_SGT + cond_i1: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, range_cmp_op, cmp_lhs, cmp_rhs) + llvmlite.build_cond_br(builder, cond_i1, body_bb, end_bb) + + # 9. body 块: 翻译循环体,跳到 incr + llvmlite.position_at_end(builder, body_bb) + + # 保存旧循环上下文,设置 break/continue 目标 + old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb + old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb + trans._break_bb = end_bb + trans._continue_bb = incr_bb + + body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children + if body is not None: + body_count: t.CSizeT = len(body) + for bi in range(body_count): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt) + + # 恢复旧循环上下文 + trans._break_bb = old_break + trans._continue_bb = old_continue + + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, incr_bb) + + # 10. incr 块: i = i + step, 跳回 cond + llvmlite.position_at_end(builder, incr_bb) + cur_i2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, loop_var_ty, var_alloca) + # 类型对齐: step_val 可能是 i32/i64,需对齐到 loop_var_ty 与 cur_i2 类型一致 + incr_step: llvmlite.Value | t.CPtr = step_val + if step_val is not None and step_val.Ty is not None: + step_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(step_val.Ty) + cur2_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(cur_i2.Ty) + if step_bits != 0 and cur2_bits != 0 and step_bits != cur2_bits: + if step_bits > cur2_bits: + incr_step = llvmlite.build_trunc(builder, step_val, loop_var_ty) + else: + incr_step = llvmlite.build_sext(builder, step_val, loop_var_ty) + next_i: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_i2, incr_step) + llvmlite.build_store(builder, next_i, var_alloca) + llvmlite.build_br(builder, cond_bb) + + # 11. 定位到 end 块 + llvmlite.position_at_end(builder, end_bb) + # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) + trans._ctrl_merge_reachable = 1 + return new_vars + + # ============================================================ + # 多变量迭代辅助(enumerate / zip,迁移自 ForHandleBase) + # + # 支持迭代源: range(start, stop, step) / 字符串(常量|变量) / list[T] + # enumerate(x) → for i, v in enumerate(x):i 为序号,v 为元素 + # zip(a, b) → for x, y in zip(a, b):任一源耗尽即终止 + # ============================================================ + def _extract_tuple_names(self, tup: ast.Tuple | t.CPtr, + out1: str | t.CPtr, out2: str | t.CPtr) -> int: + """从 Tuple target 提取前两个 Name 变量名,写入 out1/out2,成功返回 1""" + if tup is None or tup.elts is None or out1 is None or out2 is None: + return 0 + elts: list[ast.AST | t.CPtr] | t.CPtr = tup.elts + n: t.CSizeT = len(elts) + if n < 2: + return 0 + e0: ast.AST | t.CPtr = elts.get(0) + e1: ast.AST | t.CPtr = elts.get(1) + if e0 is None or e1 is None: + return 0 + if e0.kind() != ast.ASTKind.Name or e1.kind() != ast.ASTKind.Name: + return 0 + n0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(e0) + n1: ast.Name | t.CPtr = (ast.Name | t.CPtr)(e1) + if n0.id is None or n1.id is None: + return 0 + string.strcpy(out1, n0.id) + string.strcpy(out2, n1.id) + return 1 + + def _seq_kind(self, trans: HT.Translator | t.CPtr, + src: ast.AST | t.CPtr) -> int: + """判断迭代源类型: SEQ_KIND_RANGE / STR / LIST,不支持返回 0""" + if src is None: + return 0 + k: int = src.kind() + if k == ast.ASTKind.Call: + cl_s: ast.Call | t.CPtr = (ast.Call | t.CPtr)(src) + fn_s: str = self.Gen.ExprGenBase.get_func_name(cl_s.func) + if fn_s is not None and string.strcmp(fn_s, "range") == 0: + return GenTypes.SEQ_KIND_RANGE + return 0 + if k == ast.ASTKind.Constant: + cn_s: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(src) + if cn_s is not None and cn_s.const_kind == ast.CONST_STR: + return GenTypes.SEQ_KIND_STR + return 0 + if k == ast.ASTKind.Name: + nm_s: ast.Name | t.CPtr = (ast.Name | t.CPtr)(src) + if nm_s.id is not None and trans is not None: + ve_s: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, nm_s.id) + if ve_s is not None and ve_s.AnnotClassName is not None: + if string.strstr(ve_s.AnnotClassName, "list") is not None: + return GenTypes.SEQ_KIND_LIST + return GenTypes.SEQ_KIND_STR + return 0 + + def _build_seq_loop(self, trans: HT.Translator | t.CPtr, + for_node: ast.For | t.CPtr, + t1: str, t2: str, + src1: ast.AST | t.CPtr, + src2: ast.AST | t.CPtr, + n_srcs: int) -> int: + """生成序列迭代循环(enumerate: n_srcs=1 / zip: n_srcs=2) + + 循环变量 alloca 自动创建或复用;元素类型由源类型决定 + (RANGE→i32, STR→i8, LIST→i8*)。索引内部统一 i64。 + """ + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + # ---- 源 1 准备 ---- + kind1: int = self._seq_kind(trans, src1) + if kind1 == 0: + self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: 源 1 类型不支持") + r1_start: llvmlite.Value | t.CPtr = None + r1_stop: llvmlite.Value | t.CPtr = None + r1_step: llvmlite.Value | t.CPtr = None + s1_ptr: llvmlite.Value | t.CPtr = None + l1_count: llvmlite.Value | t.CPtr = None + l1_data: llvmlite.Value | t.CPtr = None + l1_esize: llvmlite.Value | t.CPtr = None + elem1_ty: llvmlite.LLVMType | t.CPtr = i8_ptr_ty + if kind1 == GenTypes.SEQ_KIND_RANGE: + elem1_ty = i32_ty + r1_start = llvmlite.const_int64(pool, 0) + r1_step = llvmlite.const_int64(pool, 1) + r1_stop = llvmlite.const_int64(pool, 0) + # 先赋中间变量再取 args(cast 链式属性访问会推断错字段偏移) + call_src1: ast.Call | t.CPtr = (ast.Call | t.CPtr)(src1) + cargs1: list[ast.AST | t.CPtr] | t.CPtr = call_src1.args + if cargs1 is not None: + n1: t.CSizeT = len(cargs1) + if n1 >= 1: + sv: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, cargs1.get(0), + trans._funcs, trans._func_count, trans) + if sv is None: + # fail-fast: range 参数翻译失败 + self.Gen.TypeGenErr.fatal_error(cargs1.get(0), "range 参数翻译失败", "TypeError") + r1_stop = self.Gen.ExprGenBase.coerce_to_type(builder, sv, i64_ty, cargs1.get(0)) + if n1 >= 2: + sv2: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, cargs1.get(1), + trans._funcs, trans._func_count, trans) + if sv2 is None: + # fail-fast: range 参数翻译失败 + self.Gen.TypeGenErr.fatal_error(cargs1.get(1), "range 参数翻译失败", "TypeError") + r1_start = self.Gen.ExprGenBase.coerce_to_type(builder, sv2, i64_ty, cargs1.get(1)) + if n1 >= 3: + sv3: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, cargs1.get(2), + trans._funcs, trans._func_count, trans) + if sv3 is None: + # fail-fast: range 参数翻译失败 + self.Gen.TypeGenErr.fatal_error(cargs1.get(2), "range 参数翻译失败", "TypeError") + r1_step = self.Gen.ExprGenBase.coerce_to_type(builder, sv3, i64_ty, cargs1.get(2)) + elif kind1 == GenTypes.SEQ_KIND_STR: + elem1_ty = i8_ty + s1_ptr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, src1, + trans._funcs, trans._func_count, trans) + if s1_ptr is None: + self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: 字符串源翻译失败") + elif kind1 == GenTypes.SEQ_KIND_LIST: + elem1_ty = i8_ptr_ty + l1_obj: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, src1, + trans._funcs, trans._func_count, trans) + if l1_obj is None or l1_obj.Ty is None \ + or self.Gen.ExprGenBase.is_ptr_type(l1_obj.Ty) == 0: + self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: list 源不是指针类型") + l1_count = llvmlite.build_load(builder, i64_ty, + llvmlite.build_gep(builder, i64_ty, l1_obj, llvmlite.const_int64(pool, 1))) + l1_data = llvmlite.build_load(builder, i8_ptr_ty, + llvmlite.build_gep(builder, i64_ty, l1_obj, llvmlite.const_int64(pool, 0))) + l1_esize = llvmlite.build_load(builder, i64_ty, + llvmlite.build_gep(builder, i64_ty, l1_obj, llvmlite.const_int64(pool, 4))) + + # ---- 源 2 准备(zip)---- + kind2: int = 0 + elem2_ty: llvmlite.LLVMType | t.CPtr = elem1_ty + s2_ptr: llvmlite.Value | t.CPtr = None + l2_count: llvmlite.Value | t.CPtr = None + l2_data: llvmlite.Value | t.CPtr = None + l2_esize: llvmlite.Value | t.CPtr = None + r2_start: llvmlite.Value | t.CPtr = None + r2_stop: llvmlite.Value | t.CPtr = None + r2_step: llvmlite.Value | t.CPtr = None + if n_srcs >= 2: + kind2 = self._seq_kind(trans, src2) + if kind2 == 0: + self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: 源 2 类型不支持") + if kind2 == GenTypes.SEQ_KIND_RANGE: + elem2_ty = i32_ty + r2_start = llvmlite.const_int64(pool, 0) + r2_step = llvmlite.const_int64(pool, 1) + r2_stop = llvmlite.const_int64(pool, 0) + # 先赋中间变量再取 args(cast 链式属性访问会推断错字段偏移) + call_src2: ast.Call | t.CPtr = (ast.Call | t.CPtr)(src2) + cargs2: list[ast.AST | t.CPtr] | t.CPtr = call_src2.args + if cargs2 is not None: + n2: t.CSizeT = len(cargs2) + if n2 >= 1: + svz: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, cargs2.get(0), + trans._funcs, trans._func_count, trans) + if svz is None: + # fail-fast: range 参数翻译失败 + self.Gen.TypeGenErr.fatal_error(cargs2.get(0), "range 参数翻译失败", "TypeError") + r2_stop = self.Gen.ExprGenBase.coerce_to_type(builder, svz, i64_ty, cargs2.get(0)) + if n2 >= 2: + svz2: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, cargs2.get(1), + trans._funcs, trans._func_count, trans) + if svz2 is None: + # fail-fast: range 参数翻译失败 + self.Gen.TypeGenErr.fatal_error(cargs2.get(1), "range 参数翻译失败", "TypeError") + r2_start = self.Gen.ExprGenBase.coerce_to_type(builder, svz2, i64_ty, cargs2.get(1)) + if n2 >= 3: + svz3: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, cargs2.get(2), + trans._funcs, trans._func_count, trans) + if svz3 is None: + # fail-fast: range 参数翻译失败 + self.Gen.TypeGenErr.fatal_error(cargs2.get(2), "range 参数翻译失败", "TypeError") + r2_step = self.Gen.ExprGenBase.coerce_to_type(builder, svz3, i64_ty, cargs2.get(2)) + elif kind2 == GenTypes.SEQ_KIND_STR: + elem2_ty = i8_ty + s2_ptr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, src2, + trans._funcs, trans._func_count, trans) + if s2_ptr is None: + self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: 字符串源 2 翻译失败") + elif kind2 == GenTypes.SEQ_KIND_LIST: + elem2_ty = i8_ptr_ty + l2_obj: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, src2, + trans._funcs, trans._func_count, trans) + if l2_obj is None or l2_obj.Ty is None \ + or self.Gen.ExprGenBase.is_ptr_type(l2_obj.Ty) == 0: + self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: list 源 2 不是指针类型") + l2_count = llvmlite.build_load(builder, i64_ty, + llvmlite.build_gep(builder, i64_ty, l2_obj, llvmlite.const_int64(pool, 1))) + l2_data = llvmlite.build_load(builder, i8_ptr_ty, + llvmlite.build_gep(builder, i64_ty, l2_obj, llvmlite.const_int64(pool, 0))) + l2_esize = llvmlite.build_load(builder, i64_ty, + llvmlite.build_gep(builder, i64_ty, l2_obj, llvmlite.const_int64(pool, 4))) + + # ---- 循环变量 alloca ---- + # t1: enumerate → 序号 (i32);zip → 源 1 元素 + t1_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, t1) + new_vars: int = 0 + if t1_alloca is None: + if n_srcs == 1: + t1_alloca = self.Gen.VarGen._alloca_at_entry(builder, i32_ty) + else: + t1_alloca = self.Gen.VarGen._alloca_at_entry(builder, elem1_ty) + if t1_alloca is not None: + if self.Gen.VarGen.define_var(trans.SymTab, t1, t1_alloca) == 0: + new_vars += 1 + # t2: 源 2 元素(enumerate 时 = 源 1 元素) + t2_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, t2) + if t2_alloca is None: + t2_alloca = self.Gen.VarGen._alloca_at_entry(builder, elem2_ty) + if t2_alloca is not None: + if self.Gen.VarGen.define_var(trans.SymTab, t2, t2_alloca) == 0: + new_vars += 1 + + # 隐式 index 变量 (i64) + idx_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen._alloca_at_entry(builder, i64_ty) + llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), idx_alloca) + + # 基本块: cond / body / incr / end + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + + name_buf: str = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "seq.cond.%d", cnt) + cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "seq.body.%d", cnt) + body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "seq.incr.%d", cnt) + incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "seq.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + llvmlite.build_br(builder, cond_bb) + + # cond 块: 源 1 done 检查(zip 需源 2 也 done) + llvmlite.position_at_end(builder, cond_bb) + cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, idx_alloca) + done1: llvmlite.Value | t.CPtr = None + if kind1 == GenTypes.SEQ_KIND_RANGE: + done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, r1_stop) + elif kind1 == GenTypes.SEQ_KIND_STR: + ch_ptr1: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s1_ptr, cur_idx) + ch1: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ty, ch_ptr1) + zero1: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, 8, 0) + done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, ch1, zero1) + elif kind1 == GenTypes.SEQ_KIND_LIST: + done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, l1_count) + cont: llvmlite.Value | t.CPtr = done1 + if n_srcs >= 2: + done2: llvmlite.Value | t.CPtr = None + if kind2 == GenTypes.SEQ_KIND_RANGE: + done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, r2_stop) + elif kind2 == GenTypes.SEQ_KIND_STR: + ch_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s2_ptr, cur_idx) + ch2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ty, ch_ptr2) + zero2: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, 8, 0) + done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, ch2, zero2) + elif kind2 == GenTypes.SEQ_KIND_LIST: + done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, l2_count) + cont = llvmlite.build_and(builder, done1, done2) + llvmlite.build_cond_br(builder, cont, body_bb, end_bb) + + # body 块: 获取元素 → store → 循环体 + llvmlite.position_at_end(builder, body_bb) + # 源 1 元素 + v1: llvmlite.Value | t.CPtr = None + if kind1 == GenTypes.SEQ_KIND_RANGE: + step1: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, r1_step) + v1 = llvmlite.build_add(builder, r1_start, step1) + elif kind1 == GenTypes.SEQ_KIND_STR: + ch_ptr1b: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s1_ptr, cur_idx) + v1 = llvmlite.build_load(builder, i8_ty, ch_ptr1b) + elif kind1 == GenTypes.SEQ_KIND_LIST: + off1: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, l1_esize) + addr1: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, l1_data, off1) + v1 = llvmlite.build_load(builder, i8_ptr_ty, addr1) + # store t1 / t2 + if t1_alloca is not None and t1_alloca.Ty is not None: + t1_ty: llvmlite.LLVMType | t.CPtr = t1_alloca.Ty.Pointee + if n_srcs == 1: + # enumerate: t1 = 序号(trunc i64 → i32) + idx32: llvmlite.Value | t.CPtr = llvmlite.build_trunc(builder, cur_idx, i32_ty) + llvmlite.build_store(builder, idx32, t1_alloca) + if t2_alloca is not None and t2_alloca.Ty is not None and v1 is not None: + t2_ty: llvmlite.LLVMType | t.CPtr = t2_alloca.Ty.Pointee + v1c: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type(builder, v1, t2_ty, src1) + llvmlite.build_store(builder, v1c, t2_alloca) + else: + if v1 is not None: + v1c: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type(builder, v1, t1_ty, src1) + llvmlite.build_store(builder, v1c, t1_alloca) + # 源 2 元素 → t2 + v2: llvmlite.Value | t.CPtr = None + if kind2 == GenTypes.SEQ_KIND_RANGE: + step2: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, r2_step) + v2 = llvmlite.build_add(builder, r2_start, step2) + elif kind2 == GenTypes.SEQ_KIND_STR: + ch_ptr2b: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s2_ptr, cur_idx) + v2 = llvmlite.build_load(builder, i8_ty, ch_ptr2b) + elif kind2 == GenTypes.SEQ_KIND_LIST: + off2: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, l2_esize) + addr2: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, l2_data, off2) + v2 = llvmlite.build_load(builder, i8_ptr_ty, addr2) + if t2_alloca is not None and t2_alloca.Ty is not None and v2 is not None: + t2_ty2: llvmlite.LLVMType | t.CPtr = t2_alloca.Ty.Pointee + v2c: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type(builder, v2, t2_ty2, src2) + llvmlite.build_store(builder, v2c, t2_alloca) + + # 保存旧循环上下文,设置 break/continue 目标 + old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb + old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb + trans._break_bb = end_bb + trans._continue_bb = incr_bb + + body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children + if body is not None: + body_count: t.CSizeT = len(body) + for bi in range(body_count): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt) + + trans._break_bb = old_break + trans._continue_bb = old_continue + + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, incr_bb) + + # incr 块: index++ + llvmlite.position_at_end(builder, incr_bb) + one_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) + next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val) + llvmlite.build_store(builder, next_idx, idx_alloca) + llvmlite.build_br(builder, cond_bb) + + # 定位到 end 块 + llvmlite.position_at_end(builder, end_bb) + # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) + trans._ctrl_merge_reachable = 1 + return new_vars + + # ============================================================ + # _handle_ptr_iter - 指针迭代: for x in ptr:(迁移自 ForHandleIter) + # 遍历指针,依赖隐式 index,直到解引用为空(null 终止符) + # + # 生成 IR 结构: + # %idx = alloca i32 + # store i32 0, i32* %idx + # br label %cond + # cond: + # %i = load i32, i32* %idx + # %ep = getelementptr elem_ty, ptr_ty %ptr, i32 %i + # %ev = load elem_ty, elem_ty* %ep + # %null = icmp eq elem_ty %ev, 0 + # br i1 %null, label %end, label %body + # body: + # store elem_ty %ev, elem_ty* %var + # ... 循环体 ... + # br label %incr + # incr: + # %next = add i32 %i, 1 + # store i32 %next, i32* %idx + # br label %cond + # end: + # ============================================================ + def _handle_ptr_iter(self, trans: HT.Translator | t.CPtr, + for_node: ast.For | t.CPtr, + var_name: str) -> int: + """指针迭代: for x in ptr: 直到解引用为空""" + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + + # 翻译迭代器表达式,获取指针值 + ptr_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, for_node.iter, + trans._funcs, trans._func_count, trans) + if ptr_val is None: + self.Gen.TypeGenErr.fatal_error(for_node, "指针迭代: 无法翻译迭代器表达式") + + # 检查迭代器类型 + if self.Gen.ExprGenBase.is_ptr_type(ptr_val.Ty) == 0: + # 数组迭代:for k in arr(定长数组按长度迭代,元素可为任意类型) + if self.Gen.ExprGenBase.is_array_type(ptr_val.Ty) != 0: + return self._handle_array_iter(trans, for_node, var_name, ptr_val) + self.Gen.TypeGenErr.fatal_error(for_node, "指针迭代: 迭代器不是指针类型") + + # 获取元素类型 + elem_ty: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee + if elem_ty is None: + self.Gen.TypeGenErr.fatal_error(for_node, "指针迭代: 无法获取元素类型") + + # 元素类型是数组(Ptr([N x T]),如 t.CArray 变量退化指针): + # load 出数组值后走数组迭代(按长度,非 null 终止) + if self.Gen.ExprGenBase.is_array_type(elem_ty) != 0: + arr_v2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, ptr_val) + if arr_v2 is not None: + return self._handle_array_iter(trans, for_node, var_name, arr_v2) + + # 元素类型必须是整数(用于 icmp eq 0 检查 null 终止符) + elem_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(elem_ty) + if elem_bits == 0: + self.Gen.TypeGenErr.fatal_error(for_node, "指针迭代: 元素类型不是整数,无法检查 null 终止符") + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + + # 创建循环变量 alloca(存储元素值) + var_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, var_name) + new_vars: int = 0 + if var_alloca is None: + var_alloca = self.Gen.VarGen._alloca_at_entry(builder, elem_ty) + if self.Gen.VarGen.define_var( + trans.SymTab, var_name, var_alloca) == 0: + new_vars = 1 + + # 创建隐式 index 变量,初始为 0 + idx_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen._alloca_at_entry(builder, i32_ty) + llvmlite.build_store(builder, llvmlite.const_int32(pool, 0), idx_alloca) + + # 创建基本块: cond / body / incr / end + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + + name_buf: str = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "ptr.cond.%d", cnt) + cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "ptr.body.%d", cnt) + body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "ptr.incr.%d", cnt) + incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "ptr.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + # 跳转到 cond + llvmlite.build_br(builder, cond_bb) + + # cond 块: load index, GEP, load elem, icmp eq 0 + llvmlite.position_at_end(builder, cond_bb) + cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i32_ty, idx_alloca) + elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, elem_ty, ptr_val, cur_idx) + cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, elem_ptr) + null_val: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, elem_bits, 0) + is_null: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_EQ, cur_elem, null_val) + llvmlite.build_cond_br(builder, is_null, end_bb, body_bb) + + # body 块: store elem to var, 翻译循环体 + llvmlite.position_at_end(builder, body_bb) + llvmlite.build_store(builder, cur_elem, var_alloca) + + # 保存旧循环上下文,设置 break/continue 目标 + old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb + old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb + trans._break_bb = end_bb + trans._continue_bb = incr_bb + + body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children + if body is not None: + body_count: t.CSizeT = len(body) + for bi in range(body_count): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt) + + # 恢复旧循环上下文 + trans._break_bb = old_break + trans._continue_bb = old_continue + + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, incr_bb) + + # incr 块: index++, br cond + llvmlite.position_at_end(builder, incr_bb) + one_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) + next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val) + llvmlite.build_store(builder, next_idx, idx_alloca) + llvmlite.build_br(builder, cond_bb) + + # 定位到 end 块 + llvmlite.position_at_end(builder, end_bb) + # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) + trans._ctrl_merge_reachable = 1 + return new_vars + + # ============================================================ + # _handle_array_iter - 数组迭代: for x in arr:(迁移自 ForHandleIter) + # 定长数组按长度迭代(元素可为任意类型,不做 null 终止符检查) + # + # 数组值是数组类型而非指针(如局部 t.CArray 修复后), + # 先拷到临时 alloca 获得地址,再按 [0, N) 迭代。 + # + # 生成 IR 结构: + # %tmp = alloca [N x elem_ty] + # store [N x elem_ty] %arr_val, [N x elem_ty]* %tmp + # %idx = alloca i32 ; store 0 + # br %cond + # cond: + # %i = load i32, i32* %idx + # %c = icmp slt i32 %i, N + # br i1 %c, %body, %end + # body: + # %ep = getelementptr [N x elem_ty], [N x elem_ty]* %tmp, i32 0, i32 %i + # %ev = load elem_ty, elem_ty* %ep + # store elem_ty %ev, elem_ty* %var + # ... 循环体 ... + # br %incr + # incr: + # %n = add i32 %i, 1 ; store %n ; br %cond + # end: + # ============================================================ + def _handle_array_iter(self, trans: HT.Translator | t.CPtr, + for_node: ast.For | t.CPtr, + var_name: str, + array_val: llvmlite.Value | t.CPtr) -> int: + """数组迭代: for x in arr: 按数组长度迭代""" + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + + # 解析数组类型 [N x elem_ty] + arr_ty: llvmlite.LLVMType | t.CPtr = array_val.Ty + elem_ty: llvmlite.LLVMType | t.CPtr = None + elem_count: int = 0 + match arr_ty: + case llvmlite.LLVMType.Array(et, n): + elem_ty = et + elem_count = n + if elem_ty is None or elem_count <= 0: + self.Gen.TypeGenErr.fatal_error(for_node, "数组迭代: 无法解析数组类型") + + # 数组值 → 临时 alloca(数组值不是指针,需拷贝后 GEP 迭代) + arr_tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, arr_ty) + if arr_tmp is None: + self.Gen.TypeGenErr.fatal_error(for_node, "数组迭代: 临时存储分配失败") + llvmlite.build_store(builder, array_val, arr_tmp) + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + + # 循环变量 alloca(存储元素值) + var_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, var_name) + new_vars: int = 0 + if var_alloca is None: + var_alloca = self.Gen.VarGen._alloca_at_entry(builder, elem_ty) + if self.Gen.VarGen.define_var( + trans.SymTab, var_name, var_alloca) == 0: + new_vars = 1 + + # 隐式 index 变量,初始为 0 + idx_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen._alloca_at_entry(builder, i32_ty) + llvmlite.build_store(builder, llvmlite.const_int32(pool, 0), idx_alloca) + + # 基本块: cond / body / incr / end + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + + name_buf: str = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "arr.cond.%d", cnt) + cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "arr.body.%d", cnt) + body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "arr.incr.%d", cnt) + incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "arr.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + llvmlite.build_br(builder, cond_bb) + + # cond 块: load index, icmp slt idx, elem_count + llvmlite.position_at_end(builder, cond_bb) + cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i32_ty, idx_alloca) + count_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, elem_count) + in_bounds: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_SLT, cur_idx, count_val) + llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb) + + # body 块: GEP(0, idx) → load elem → store to var → 循环体 + llvmlite.position_at_end(builder, body_bb) + elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( + builder, arr_ty, elem_ty, arr_tmp, cur_idx) + cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, elem_ptr) + llvmlite.build_store(builder, cur_elem, var_alloca) + + old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb + old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb + trans._break_bb = end_bb + trans._continue_bb = incr_bb + + body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children + if body is not None: + body_count: t.CSizeT = len(body) + for bi in range(body_count): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt) + + trans._break_bb = old_break + trans._continue_bb = old_continue + + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, incr_bb) + + # incr 块: index++ + llvmlite.position_at_end(builder, incr_bb) + one_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) + next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val) + llvmlite.build_store(builder, next_idx, idx_alloca) + llvmlite.build_br(builder, cond_bb) + + # 定位到 end 块 + llvmlite.position_at_end(builder, end_bb) + # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) + trans._ctrl_merge_reachable = 1 + return new_vars + + # ============================================================ + # _handle_list_literal_iter - 列表字面量迭代: for x in [a, b, c]:(迁移自 ForHandleIter) + # 把列表字面量转成定长数组值,再复用数组迭代(按长度迭代)。 + # + # 元素类型取第一个元素的值类型,其余元素 coerce 到该类型。 + # ============================================================ + def _handle_list_literal_iter(self, trans: HT.Translator | t.CPtr, + for_node: ast.For | t.CPtr, + var_name: str, + list_node: ast.AST | t.CPtr) -> int: + """列表字面量迭代: for x in [a, b, c]: 按元素顺序迭代""" + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + + lst: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node) + if lst is None or lst.elts is None: + self.Gen.TypeGenErr.fatal_error(for_node, "列表字面量迭代: 空列表") + elts: list[ast.AST | t.CPtr] | t.CPtr = lst.elts + elts_count: t.CSizeT = len(elts) + if elts_count <= 0: + self.Gen.TypeGenErr.fatal_error(for_node, "列表字面量迭代: 空列表") + + # 翻译第一个元素,确定元素类型 + first_el: ast.AST | t.CPtr = elts.get(0) + first_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, first_el, + trans._funcs, trans._func_count, trans) + if first_val is None or first_val.Ty is None: + self.Gen.TypeGenErr.fatal_error(first_el, "列表字面量迭代: 无法确定元素类型") + elem_ty: llvmlite.LLVMType | t.CPtr = first_val.Ty + + # 构建 [N x elem_ty] 数组值:临时 alloca 逐元素写入后 load + arr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, elem_ty, elts_count) + tmp_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, arr_ty) + if tmp_alloca is None: + self.Gen.TypeGenErr.fatal_error(for_node, "列表字面量迭代: 临时数组分配失败") + first_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( + builder, arr_ty, elem_ty, tmp_alloca, llvmlite.const_int32(pool, 0)) + if first_ptr is not None: + llvmlite.build_store(builder, first_val, first_ptr) + # 写其余元素(coerce 到 elem_ty) + i: t.CSizeT = 1 + while i < elts_count: + el_node: ast.AST | t.CPtr = elts.get(i) + el_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, el_node, + trans._funcs, trans._func_count, trans) + if el_val is not None: + el_val = self.Gen.ExprGenBase.coerce_to_type(builder, el_val, elem_ty, el_node) + el_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( + builder, arr_ty, elem_ty, tmp_alloca, + llvmlite.const_int32(pool, i)) + if el_ptr is not None: + llvmlite.build_store(builder, el_val, el_ptr) + i += 1 + # load 回数组值,复用数组迭代 + arr_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, arr_ty, tmp_alloca) + if arr_val is None: + self.Gen.TypeGenErr.fatal_error(for_node, "列表字面量迭代: 数组加载失败") + return self._handle_array_iter(trans, for_node, var_name, arr_val) + + # ============================================================ + # _handle_list_iter - list[T] 容器迭代: for v in lst:(迁移自 ForHandleIter) + # 按 __count__ 动态长度迭代(元素任意类型,不做 null 终止符检查) + # + # list 结构布局 (6 字段 × 8 字节): + # __data__(0) __count__(8) __capacity__(16) __pool__(24) + # __elem_size__(32) __iter_index__(40) + # + # 生成 IR 结构: + # %count = load __count__ + # %idx = alloca i64 ; store 0 + # br %cond + # cond: + # %i = load i64, %idx + # %c = icmp slt i64 %i, %count + # br i1 %c, %body, %end + # body: + # %data = load __data__ (i8*) + # %es = load __elem_size__ (i64) + # %off = mul i64 %i, %es + # %addr = getelementptr i8, i8* %data, i64 %off + # %el = load i8*, i8** %addr + # store i8* %el, i8** %var + # ... 循环体 ... + # br %incr + # incr: + # %n = add i64 %i, 1 ; store ; br %cond + # end: + # ============================================================ + def _handle_list_iter(self, trans: HT.Translator | t.CPtr, + for_node: ast.For | t.CPtr, + var_name: str, + list_val: llvmlite.Value | t.CPtr) -> int: + """list[T] 容器迭代: for v in lst: 按 __count__ 动态长度迭代""" + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + # 读取 __count__ (偏移 8, GEP index 1) + cnt_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i64_ty, list_val, llvmlite.const_int64(pool, 1)) + if cnt_ptr is None: + self.Gen.TypeGenErr.fatal_error(for_node, "list 迭代: 无法定位 __count__") + count_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, cnt_ptr) + + # 循环变量 alloca(元素类型 i8*,与 list.get 内联一致) + var_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, var_name) + new_vars: int = 0 + if var_alloca is None: + var_alloca = self.Gen.VarGen._alloca_at_entry(builder, i8_ptr_ty) + if self.Gen.VarGen.define_var( + trans.SymTab, var_name, var_alloca) == 0: + new_vars = 1 + + # 隐式 index 变量 (i64,与 __count__ 类型对齐) + idx_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen._alloca_at_entry(builder, i64_ty) + llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), idx_alloca) + + # 基本块: cond / body / incr / end + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + + name_buf: str = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "lst.cond.%d", cnt) + cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "lst.body.%d", cnt) + body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "lst.incr.%d", cnt) + incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "lst.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + llvmlite.build_br(builder, cond_bb) + + # cond 块: load index, icmp slt idx, count + llvmlite.position_at_end(builder, cond_bb) + cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, idx_alloca) + in_bounds: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_SLT, cur_idx, count_val) + llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb) + + # body 块: __data__ + idx*__elem_size__ → load 元素 → store to var + llvmlite.position_at_end(builder, body_bb) + dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i64_ty, list_val, llvmlite.const_int64(pool, 0)) + data_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, dpp) + epp: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i64_ty, list_val, llvmlite.const_int64(pool, 4)) + esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, epp) + offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, esize) + elem_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i8_ty, data_ptr, offset) + cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, elem_addr) + llvmlite.build_store(builder, cur_elem, var_alloca) + + # 保存旧循环上下文,设置 break/continue 目标 + old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb + old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb + trans._break_bb = end_bb + trans._continue_bb = incr_bb + + body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children + if body is not None: + body_count: t.CSizeT = len(body) + for bi in range(body_count): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt) + + trans._break_bb = old_break + trans._continue_bb = old_continue + + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, incr_bb) + + # incr 块: index++ + llvmlite.position_at_end(builder, incr_bb) + one_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) + next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val) + llvmlite.build_store(builder, next_idx, idx_alloca) + llvmlite.build_br(builder, cond_bb) + + # 定位到 end 块 + llvmlite.position_at_end(builder, end_bb) + # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) + trans._ctrl_merge_reachable = 1 + return new_vars + + def _handle_dict_iter(self, trans: HT.Translator | t.CPtr, + for_node: ast.For | t.CPtr, + var_name: str, + dict_val: llvmlite.Value | t.CPtr) -> int: + """dict 容器迭代: for key in d: 按 __count__/__keys__ 布局迭代 + + _dict.vp 布局(8 字节槽):__keys__@0, __values__@1, __count__@2, + __capacity__@3, __mbuddy__@4, __iter_index__@5。 + __iter__ 协议(__iter__ 重置 iter_index + __next__ 取 key)内联为 + 循环:iter_idx < __count__ → key = __keys__[iter_idx]。 + """ + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + # 读取 __count__(槽 2,字节偏移 16) + cnt_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i64_ty, dict_val, llvmlite.const_int64(pool, 2)) + if cnt_ptr is None: + self.Gen.TypeGenErr.fatal_error(for_node, "dict 迭代: 无法定位 __count__") + count_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, cnt_ptr) + + # 循环变量 alloca(元素类型 i8*,与 dict.__next__ 返回 str 一致) + var_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, var_name) + new_vars: int = 0 + if var_alloca is None: + var_alloca = self.Gen.VarGen._alloca_at_entry(builder, i8_ptr_ty) + if self.Gen.VarGen.define_var( + trans.SymTab, var_name, var_alloca) == 0: + new_vars = 1 + + # 隐式 index 变量 (i64,与 __count__ 类型对齐) + idx_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen._alloca_at_entry(builder, i64_ty) + llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), idx_alloca) + + # 基本块: cond / body / incr / end + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + + name_buf: str = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "dict.cond.%d", cnt) + cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "dict.body.%d", cnt) + body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "dict.incr.%d", cnt) + incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "dict.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + llvmlite.build_br(builder, cond_bb) + + # cond 块: load index, icmp slt idx, count + llvmlite.position_at_end(builder, cond_bb) + cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, idx_alloca) + in_bounds: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_SLT, cur_idx, count_val) + llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb) + + # body 块: __keys__ + idx*8 → load key (i8*) → store to var + llvmlite.position_at_end(builder, body_bb) + kpp: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i64_ty, dict_val, llvmlite.const_int64(pool, 0)) + keys_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, kpp) + eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 8) + key_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, eight_val) + key_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i8_ty, keys_ptr, key_offset) + cur_key: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, key_addr) + llvmlite.build_store(builder, cur_key, var_alloca) + + # 保存旧循环上下文,设置 break/continue 目标 + old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb + old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb + trans._break_bb = end_bb + trans._continue_bb = incr_bb + + body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children + if body is not None: + body_count: t.CSizeT = len(body) + for bi in range(body_count): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt) + + trans._break_bb = old_break + trans._continue_bb = old_continue + + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, incr_bb) + + # incr 块: index++ + llvmlite.position_at_end(builder, incr_bb) + one_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) + next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val) + llvmlite.build_store(builder, next_idx, idx_alloca) + llvmlite.build_br(builder, cond_bb) + + # 定位到 end 块 + llvmlite.position_at_end(builder, end_bb) + # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) + trans._ctrl_merge_reachable = 1 + return new_vars + + # ============================================================ + # _handle_oop_iter - OOP 迭代协议: for x in obj:(迁移自 ForHandleIter) + # obj 的类有 __iter__/__next__ 方法时调用协议迭代 + # (对齐 TPC HandlesFor.py _HandleForIterLlvm L599-663) + # + # 生成 IR 结构: + # %it = call {Class}.__iter__(obj) + # %flag = alloca i1 ; store 0 + # br %cond + # cond: + # store 0, %flag + # %v = call {Class}.__next__(%it, %flag) + # %stop = load i1, %flag + # br i1 %stop==0, %body, %end + # body: + # store %v, %var + # ... 循环体 ... + # br %step + # step: + # br %cond + # end: + # + # __next__ 的隐藏参数 __stop_iter_flag__(i1*)由 ClassGenMixin + # _translate_method 注入,raise StopIteration 时置 1(translate_raise); + # VpiReader stub 声明同步该参数(_inject_method_declare)。 + # ============================================================ + def _handle_oop_iter(self, trans: HT.Translator | t.CPtr, + for_node: ast.For | t.CPtr, + var_name: str, + class_name: str, + obj_val: llvmlite.Value | t.CPtr) -> int: + """OOP iter 协议: for x in obj: 调用 __iter__/__next__ 迭代""" + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + + if builder is None or func is None or mod is None: + return 0 + if obj_val is None or obj_val.Ty is None: + self.Gen.TypeGenErr.fatal_error(for_node, "OOP 迭代: 迭代源对象类型未知") + if self.Gen.ExprGenBase.is_ptr_type(obj_val.Ty) == 0: + self.Gen.TypeGenErr.fatal_error(for_node, "OOP 迭代: 迭代源对象不是指针类型") + + # 1. 查找 {Class}.__iter__ 并调用,得到迭代器 + iter_lookup: str = pool.alloc(128) + if iter_lookup is None: + return 0 + viperlib.snprintf(iter_lookup, 128, "%s.__iter__", class_name) + iter_fn: llvmlite.Function | t.CPtr = self.Gen.CallGenBase.find_func_in_module( + mod, iter_lookup) + if iter_fn is None: + self.Gen.TypeGenErr.fatal_error( + for_node, f"OOP 迭代: 类 '{class_name}' 没有 __iter__ 方法") + iter_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(iter_fn) + iter_fn_name: str = llvmlite.function_get_name(iter_fn) + if iter_ret_ty is None or iter_fn_name is None: + return 0 + # self 参数按 __iter__ 首参类型对齐(stub 声明 self 可能是 i8*) + iter_self: llvmlite.Value | t.CPtr = obj_val + iter_first: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(iter_fn) + if iter_first is not None: + iter_self_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(iter_first) + if iter_self_ty is not None: + iter_self = llvmlite.build_bitcast(builder, obj_val, iter_self_ty) + if iter_self is None: + return 0 + iter_self.Next = None + iter_result: llvmlite.Value | t.CPtr = llvmlite.build_call( + builder, iter_fn_name, iter_self, 1, iter_ret_ty, 0) + if iter_result is None: + return 0 + + # 2. 查找 {Class}.__next__(带隐藏 __stop_iter_flag__ i1* 参数) + next_lookup: str = pool.alloc(128) + if next_lookup is None: + return 0 + viperlib.snprintf(next_lookup, 128, "%s.__next__", class_name) + next_fn: llvmlite.Function | t.CPtr = self.Gen.CallGenBase.find_func_in_module( + mod, next_lookup) + if next_fn is None: + self.Gen.TypeGenErr.fatal_error( + for_node, f"OOP 迭代: 类 '{class_name}' 没有 __next__ 方法") + next_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(next_fn) + next_fn_name: str = llvmlite.function_get_name(next_fn) + if next_ret_ty is None or next_fn_name is None: + return 0 + + # 3. 循环变量 alloca(元素类型 = __next__ 返回类型) + var_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, var_name) + new_vars: int = 0 + if var_alloca is None: + var_alloca = self.Gen.VarGen._alloca_at_entry(builder, next_ret_ty) + if var_alloca is not None: + if self.Gen.VarGen.define_var( + trans.SymTab, var_name, var_alloca) == 0: + new_vars = 1 + + # 4. stop flag alloca(i1,初始 0) + i1_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + flag_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i1_ty) + if flag_alloca is None: + return 0 + flag_zero: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i1_ty, 0, "0") + if flag_zero is not None: + llvmlite.build_store(builder, flag_zero, flag_alloca) + + # 5. 创建基本块: cond / body / step / end + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + name_buf: str = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "oop.cond.%d", cnt) + cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + viperlib.snprintf(name_buf, 32, "oop.body.%d", cnt) + body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + viperlib.snprintf(name_buf, 32, "oop.step.%d", cnt) + step_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + viperlib.snprintf(name_buf, 32, "oop.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + if cond_bb is None or body_bb is None or step_bb is None or end_bb is None: + return 0 + + llvmlite.build_br(builder, cond_bb) + + # 6. cond 块: 重置 flag → 调 __next__(iter, flag) → 检查 flag 判结束 + llvmlite.position_at_end(builder, cond_bb) + if flag_zero is not None: + llvmlite.build_store(builder, flag_zero, flag_alloca) + # __next__ 参数 1:迭代器(按首参类型 bitcast) + next_self: llvmlite.Value | t.CPtr = iter_result + next_first: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(next_fn) + if next_first is not None: + next_self_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(next_first) + if next_self_ty is not None and iter_result.Ty is not None: + next_self = llvmlite.build_bitcast(builder, iter_result, next_self_ty) + if next_self is None: + return 0 + # 参数链表: arg1(iter).Next = arg2(flag);flag 独立 null 结尾防自链接 + next_self.Next = flag_alloca + flag_alloca.Next = None + next_val: llvmlite.Value | t.CPtr = llvmlite.build_call( + builder, next_fn_name, next_self, 2, next_ret_ty, 0) + if next_val is None: + return 0 + stop_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i1_ty, flag_alloca) + if stop_val is None: + return 0 + flag_zero2: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i1_ty, 0, "0") + continue_i1: llvmlite.Value | t.CPtr = None + if flag_zero2 is not None: + continue_i1 = llvmlite.build_icmp( + builder, llvmlite.ICMP_EQ, stop_val, flag_zero2) + if continue_i1 is None: + return 0 + llvmlite.build_cond_br(builder, continue_i1, body_bb, end_bb) + + # 7. body 块: store 元素 → 翻译循环体 → br step + llvmlite.position_at_end(builder, body_bb) + if var_alloca is not None: + llvmlite.build_store(builder, next_val, var_alloca) + old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb + old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb + trans._break_bb = end_bb + trans._continue_bb = step_bb + body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children + if body is not None: + body_count: t.CSizeT = len(body) + for bi in range(body_count): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt) + trans._break_bb = old_break + trans._continue_bb = old_continue + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, step_bb) + + # 8. step 块 → cond;定位到 end 块 + llvmlite.position_at_end(builder, step_bb) + llvmlite.build_br(builder, cond_bb) + llvmlite.position_at_end(builder, end_bb) + # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) + trans._ctrl_merge_reachable = 1 + return new_vars + + def _handle_enumerate_iter(self, trans: HT.Translator | t.CPtr, + for_node: ast.For | t.CPtr, + t1: str, t2: str, + call: ast.Call | t.CPtr) -> int: + """enumerate 迭代: for i, v in enumerate(x)""" + if call is None or call.args is None: + return 0 + cargs: list[ast.AST | t.CPtr] | t.CPtr = call.args + if len(cargs) < 1: + self.Gen.TypeGenErr.fatal_error(for_node, "enumerate 需要至少一个参数") + return self._build_seq_loop(trans, for_node, t1, t2, cargs.get(0), None, 1) + + def _handle_zip_iter(self, trans: HT.Translator | t.CPtr, + for_node: ast.For | t.CPtr, + t1: str, t2: str, + call: ast.Call | t.CPtr) -> int: + """zip 迭代: for a, b in zip(x, y)""" + if call is None or call.args is None: + # fail-fast: zip 参数缺失 + self.Gen.TypeGenErr.fatal_error(call, "zip 参数缺失", "SyntaxError") + cargs: list[ast.AST | t.CPtr] | t.CPtr = call.args + if len(cargs) < 2: + self.Gen.TypeGenErr.fatal_error(for_node, "zip 需要至少两个参数") + return self._build_seq_loop(trans, for_node, t1, t2, cargs.get(0), cargs.get(1), 2) + + + def InitStmtGen(self) -> int: + """初始化 StmtGen 族字段(构造时由 Generator 调用)""" + if self is None: + return 1 + self.CifEvalOk = 0 + self.EnumTable = None + self.EnumCount = 0 + self.DiagStmtCount = 0 + return 0 diff --git a/App/lib/core/Gen/StmtGenDeclMixin.vp b/App/lib/core/Gen/StmtGenDeclMixin.vp index d6e5731..d23f754 100644 --- a/App/lib/core/Gen/StmtGenDeclMixin.vp +++ b/App/lib/core/Gen/StmtGenDeclMixin.vp @@ -1,517 +1,503 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdlib -import stdio -import viperlib -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesFunctions as HandlesFunctions -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesIf as HandlesIf -import lib.core.Handles.HandlesWhile as HandlesWhile -import lib.core.Handles.HandlesFor as HandlesFor -import lib.core.Handles.HandlesReturn as HandlesReturn -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesMatch as HandlesMatch -import lib.core.Handles.HandlesEnum as HandlesEnum -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.CompilerFactory as CompilerFactory -import lib.Projectrans.Config as Config -import lib.core.Gen.StmtGenCifMixin as StmtGenCifMixin -import lib.core.Handles.ExprCallCall as ExprCallCall - - -# ============================================================ -# StmtGenDeclMixin - StmtGen 拆分 2/3:声明/枚举/nonlocal 访问 -# -# 按功能域从 StmtGenMixin.vp 拆出(500~1500 行/文件架构重构,试点): -# translate_global/nonlocal/expr_stmt/pre_scan、break/continue、 -# nonlocal 闭包 env 访问、枚举注册表。继承 StmtGenCifMixin。 -# -# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 -# ============================================================ - - -# ============================================================ -# 常量(与 HandlesEnum 保持一致,本地副本避免跨模块 CDefine 查找 bug) -# ============================================================ -ENUM_MAX: t.CDefine = 64 -ENUM_MEMBER_MAX: t.CDefine = 128 - -# ============================================================ -# StmtGenDeclMixin - 声明/枚举/nonlocal(中层级) -# ============================================================ -@t.NoVTable -class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin): - """声明/枚举/nonlocal 访问(StmtGen 拆分 2/3,继承 Cif)""" - - def translate_global(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 global 语句:记录 global 变量名""" - gn: ast.Global | t.CPtr = (ast.Global | t.CPtr)(node) - if gn is None: - return 0 - names: list[ast.AST | t.CPtr] | t.CPtr = gn.names - if names is None: - return 0 - n: t.CSizeT = len(names) - for i in range(n): - nm_node: ast.AST | t.CPtr = names.get(i) - if nm_node is not None and nm_node.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(nm_node) - if nm.id is not None: - HT.add_global_name(trans, nm.id) - return 0 - - def translate_nonlocal(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 nonlocal 语句:记录 nonlocal 变量名及其类型 - - 类型信息通过查找父作用域的 alloca 获取(用于 env 指针数组方案的类型恢复)。 - """ - nl: ast.Nonlocal | t.CPtr = (ast.Nonlocal | t.CPtr)(node) - if nl is None: - return 0 - names: list[ast.AST | t.CPtr] | t.CPtr = nl.names - if names is None: - return 0 - n: t.CSizeT = len(names) - for i in range(n): - nm_node: ast.AST | t.CPtr = names.get(i) - if nm_node is not None and nm_node.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(nm_node) - if nm.id is not None: - # 查找父作用域中的变量 alloca,获取类型信息 - var_ty: llvmlite.LLVMType | t.CPtr = None - var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, nm.id) - if var_alloca is not None and var_alloca.Ty is not None: - var_ty = var_alloca.Ty.Pointee - # Void 类型视为无效(Pointee 访问异常时可能返回 Void), - # 类型无效直接报错终止(fail-fast),避免生成 - # "bitcast ... to void*" / "load void, void*" 非法 IR - if var_ty is not None: - match var_ty: - case llvmlite.LLVMType.Void(): - HandlesType.fatal_error(nm_node, f"nonlocal 变量 '{nm.id}' 类型无效(Void/无法解析)", "TypeError") - case _: - pass - HT.add_nonlocal_name(trans, nm.id, var_ty) - return 0 - - def translate_expr_stmt(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译表达式语句(printf 调用等)""" - ex: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(node) - if ex is None: - return 0 - call_node: ast.AST | t.CPtr = ex.value - if call_node is None: - return 0 - ck: int = call_node.kind() - if ck != ast.ASTKind.Call: - return 0 - - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(call_node) - func_node: ast.AST | t.CPtr = cl.func - if func_node is None: - return 0 - - func_name: str = HandlesExpr.get_func_name(func_node) - if func_name is None: - # 函数名解析失败:直接报错终止(fail-fast) - HandlesType.fatal_error(call_node, "表达式语句的函数名解析失败", "SyntaxError") - - # printf / print 走特殊路径(print 是类型感知格式化,不映射到 printf) - if string.strcmp(func_name, "printf") == 0: - ExprCallCall.translate_printf_call( - trans.Pool, trans._cur_builder, trans.Module, cl, trans) - elif string.strcmp(func_name, "print") == 0: - ExprCallCall.translate_print_call( - trans.Pool, trans._cur_builder, trans.Module, cl, trans) - else: - # 通用函数调用(返回值丢弃) - ExprCallCall.translate_call( - trans.Pool, trans._cur_builder, trans.Module, call_node, - trans._funcs, trans._func_count, trans) - return 0 - - def pre_scan_allocas(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """预扫描语句中的 AnnAssign,提前创建 alloca - - 返回新增的变量数 - """ - if node is None: - return 0 - return HandlesAnnAssign.translate_annassign_prescan(trans, node) - - def pre_scan_scope_decls(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """预扫描 Global/Nonlocal 声明,提前注册作用域名称""" - if node is None: - return 0 - k: int = node.kind() - if k == ast.ASTKind.Global: - return self.translate_global(trans, node) - if k == ast.ASTKind.Nonlocal: - return self.translate_nonlocal(trans, node) - return 0 - - def translate_break(self, trans: HT.Translator | t.CPtr) -> int: - """翻译 break 语句:跳转到循环 end 块""" - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - func: llvmlite.Function | t.CPtr = trans._cur_func - pool: memhub.MemBuddy | t.CPtr = trans.Pool - - if builder is None or func is None: - return 0 - - # 发射 br 到 break 目标 - if trans._break_bb is not None: - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, trans._break_bb) - - # 创建死代码 BB,用于后续语句(break 后面的代码不可达) - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - name_buf: str = pool.alloc(32) - viperlib.snprintf(name_buf, 32, "dead.%d", cnt) - dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - llvmlite.position_at_end(builder, dead_bb) - return 0 - - def translate_continue(self, trans: HT.Translator | t.CPtr) -> int: - """翻译 continue 语句:跳转到循环 cond/incr 块""" - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - func: llvmlite.Function | t.CPtr = trans._cur_func - pool: memhub.MemBuddy | t.CPtr = trans.Pool - - if builder is None or func is None: - return 0 - - # 发射 br 到 continue 目标 - if trans._continue_bb is not None: - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, trans._continue_bb) - - # 创建死代码 BB,用于后续语句 - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - name_buf: str = pool.alloc(32) - viperlib.snprintf(name_buf, 32, "dead.%d", cnt) - dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - llvmlite.position_at_end(builder, dead_bb) - return 0 - - def get_stmt_kind_name(self, node: ast.AST | t.CPtr) -> str: - """获取语句类型名""" - if node is None: - return None - return node.type_name() - - # ============================================================ - # 簇 D:nonlocal/闭包 env 访问(迁移自 HandlesNonlocal.vp) - # ============================================================ - - def _is_void_type(self, ty: llvmlite.LLVMType | t.CPtr) -> int: - """判断是否为 Void 类型,是则返回 1,否则 0""" - if ty is None: - return 0 - match ty: - case llvmlite.LLVMType.Void(): - return 1 - case _: - return 0 - - def get_env_ptr_var(self, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """获取或创建 _env_ptr 变量(存储闭包 env 指针)""" - env_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, "_env_ptr") - if env_var is not None: - return env_var - # 创建 alloca 存储 env - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i8_ptr_ty) - if alloca is None: - return None - HandlesVar.define_var(trans.SymTab, "_env_ptr", alloca) - return alloca - - def _load_raw_var_ptr(self, trans: HT.Translator | t.CPtr, - name: str) -> llvmlite.Value | t.CPtr: - """从闭包 env 加载 nonlocal 变量的原始指针(i8*) - - 返回 i8* 类型的 Value,调用方需 bitcast 为具体类型指针后 load/store。 - """ - idx: int = HT.get_nonlocal_index(trans, name) - if idx < 0: - return None - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty) - - # 1. 加载 env_ptr - env_alloca: llvmlite.Value | t.CPtr = self.get_env_ptr_var(trans) - if env_alloca is None: - return None - env_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, env_alloca) - if env_ptr is None: - return None - - # 2. GEP to offset (idx * 8) — env 存储指针数组,每槽 8 字节 - offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, idx * 8) - addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, env_ptr, offset_val) - if addr is None: - return None - - # 3. Bitcast to i8** and load the raw pointer - ptr_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, addr, i8_ptr_ptr_ty) - if ptr_addr is None: - return None - return llvmlite.build_load(builder, i8_ptr_ty, ptr_addr) - - def load_nonlocal_var(self, trans: HT.Translator | t.CPtr, - name: str) -> llvmlite.Value | t.CPtr: - """从闭包 env 加载 nonlocal 变量值 - - 通过 HT.get_nonlocal_type 获取变量类型,bitcast 原始指针后 load。 - """ - raw_ptr: llvmlite.Value | t.CPtr = self._load_raw_var_ptr(trans, name) - if raw_ptr is None: - return None - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - - # 获取变量类型(从注册时存储的类型信息) - var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name) - if var_ty is None or self._is_void_type(var_ty) != 0: - # 类型缺失/无效直接报错终止(fail-fast),避免生成 "load void, void*" 非法 IR - HandlesType.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法 load", "TypeError") - - # bitcast raw i8* to var_ty* - var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty) - var_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, raw_ptr, var_ptr_ty) - if var_ptr is None: - return None - return llvmlite.build_load(builder, var_ty, var_ptr) - - def get_nonlocal_var_ptr(self, trans: HT.Translator | t.CPtr, - name: str) -> llvmlite.Value | t.CPtr: - """获取 nonlocal 变量的存储指针(var_ty*),用于 store 操作 - - 返回的指针指向父函数的 alloca,store 操作对父函数可见。 - """ - raw_ptr: llvmlite.Value | t.CPtr = self._load_raw_var_ptr(trans, name) - if raw_ptr is None: - return None - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - - # 获取变量类型 - var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name) - if var_ty is None or self._is_void_type(var_ty) != 0: - # 类型缺失/无效直接报错终止(fail-fast),避免生成 "bitcast ... to void*" 非法 IR - HandlesType.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法 load", "TypeError") - - # bitcast raw i8* to var_ty* - var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty) - return llvmlite.build_bitcast(builder, raw_ptr, var_ptr_ty) - - # ============================================================ - # 簇 E:枚举注册表(迁移自 HandlesEnum.vp) - # ============================================================ - - def init_enum_table(self, pool: memhub.MemBuddy | t.CPtr) -> int: - """初始化枚举注册表,返回 1 成功 - - 表用 stdlib 分配(跨 Phase1 1b 的 mark/reset_to 存活——枚举表是 - 跨文件持久表,pool 分配会被 reset 回收导致 Phase B 读垃圾, - enum_count 出现 512 等垃圾值 / entry.Name 解引用崩溃)。 - """ - if self.EnumTable is not None: - return 1 - - entry_size: t.CSizeT = HandlesEnum.EnumEntry.__sizeof__() - self.EnumTable = CompilerFactory.get_perm_pool().alloc(entry_size * ENUM_MAX) - if self.EnumTable is None: - return 0 - string.memset(self.EnumTable, 0, entry_size * ENUM_MAX) - self.EnumCount = 0 - return 1 - - def _get_enum_entry(self, i: int) -> HandlesEnum.EnumEntry | t.CPtr: - """获取第 i 个枚举条目""" - if self.EnumTable is None or i < 0 or i >= ENUM_MAX: - return None - entry_size: t.CSizeT = HandlesEnum.EnumEntry.__sizeof__() - addr: t.CUInt64T = t.CUInt64T(self.EnumTable) + i * entry_size - return (HandlesEnum.EnumEntry | t.CPtr)(t.CVoid(addr, t.CPtr)) - - def _get_enum_member(self, enum_entry: HandlesEnum.EnumEntry | t.CPtr, - i: int) -> HandlesEnum.EnumMember | t.CPtr: - """获取枚举中第 i 个成员条目""" - if enum_entry is None or i < 0 or i >= ENUM_MEMBER_MAX: - return None - member_size: t.CSizeT = HandlesEnum.EnumMember.__sizeof__() - addr: t.CUInt64T = t.CUInt64T(enum_entry.Members) + i * member_size - return (HandlesEnum.EnumMember | t.CPtr)(t.CVoid(addr, t.CPtr)) - - def register_enum(self, pool: memhub.MemBuddy | t.CPtr, - name: str, - base_ty: llvmlite.LLVMType | t.CPtr) -> HandlesEnum.EnumEntry | t.CPtr: - """注册枚举类型,返回 EnumEntry 指针""" - if self.init_enum_table(pool) == 0: - return None - - # 检查是否已注册 - existing: HandlesEnum.EnumEntry | t.CPtr = self.find_enum(name) - if existing is not None: - return existing - - if self.EnumCount >= ENUM_MAX: - fb_et: str = VLogger.fmt_buf() - if fb_et is not None: - viperlib.snprintf(fb_et, 1024, "table full, cannot register %s", name) - VLogger.error(fb_et, "ENUM") - return None - - entry: HandlesEnum.EnumEntry | t.CPtr = self._get_enum_entry(self.EnumCount) - if entry is None: - return None - - # 分配成员数组(永久池:跨 mark/reset 存活,对齐 EnumTable 永久池化) - member_size: t.CSizeT = HandlesEnum.EnumMember.__sizeof__() - entry.Members = CompilerFactory.get_perm_pool().alloc(member_size * ENUM_MEMBER_MAX) - if entry.Members is None: - return None - string.memset(entry.Members, 0, member_size * ENUM_MEMBER_MAX) - - # 复制类名(永久池深拷贝) - name_len: t.CSizeT = string.strlen(name) - name_buf: str = CompilerFactory.get_perm_pool().alloc(name_len + 1) - if name_buf is not None: - string.strcpy(name_buf, name) - entry.Name = name_buf - - # BaseTy 深拷贝:LLVMType 是 pool 分配,StdlibAlloc=1(Phase2 mark2 后) - # 时 reset 回收悬空 → Phase B 枚举访问 ConstInt(悬空 BaseTy) 生成 void - # 值(DecoratorMarkerTest `store void 2` llc 报错根因)。Phase1 1a - # (StdlibAlloc=0,mark1 前)保持 pool 存活,无需拷贝。 - # 注意:StdlibAlloc 是 StructGenMixin 字段,本 Mixin 方法体不能直接 - # self.StdlibAlloc(NoVTable 按本 Mixin 字段布局编译),走模块级委托。 - if HandlesStruct.get_stdlib_alloc() != 0: - base_ty_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( - CompilerFactory.get_perm_pool(), base_ty) - if base_ty_copy is not None: - entry.BaseTy = base_ty_copy - else: - entry.BaseTy = base_ty - else: - entry.BaseTy = base_ty - entry.MemberCount = 0 - - self.EnumCount += 1 - return entry - - def add_enum_member(self, pool: memhub.MemBuddy | t.CPtr, - enum_entry: HandlesEnum.EnumEntry | t.CPtr, - member_name: str, - member_val: t.CInt64T, - member_ty: llvmlite.LLVMType | t.CPtr) -> int: - """向枚举添加成员,返回成员索引(-1 失败)""" - if enum_entry is None or member_name is None or member_ty is None: - return -1 - - # 去重:同名成员已存在则跳过(跨模块同名枚举合并注册 / 同模块 - # 重复处理幂等——如 w32.fileio 与 fat32_types 都有 FRESULT) - for ei_d in range(enum_entry.MemberCount): - ex_d: HandlesEnum.EnumMember | t.CPtr = self._get_enum_member( - enum_entry, ei_d) - if ex_d is not None and ex_d.Name is not None: - if string.strcmp(ex_d.Name, member_name) == 0: - return ei_d - - if enum_entry.MemberCount >= ENUM_MEMBER_MAX: - fb_em: str = VLogger.fmt_buf() - if fb_em is not None: - viperlib.snprintf(fb_em, 1024, "member table full for %s", enum_entry.Name) - VLogger.error(fb_em, "ENUM") - return -1 - - idx: int = enum_entry.MemberCount - me: HandlesEnum.EnumMember | t.CPtr = self._get_enum_member(enum_entry, idx) - if me is None: - return -1 - - # 复制成员名(永久池深拷贝:成员表跨 mark/reset 存活) - name_len: t.CSizeT = string.strlen(member_name) - name_buf: str = CompilerFactory.get_perm_pool().alloc(name_len + 1) - if name_buf is not None: - string.strcpy(name_buf, member_name) - me.Name = name_buf - - me.Value = member_val - me.Ty = member_ty - - enum_entry.MemberCount = idx + 1 - return idx - - def find_enum(self, name: str) -> HandlesEnum.EnumEntry | t.CPtr: - """按枚举类名查找,返回 EnumEntry 或 None""" - if name is None or self.EnumTable is None: - return None - for i in range(self.EnumCount): - entry: HandlesEnum.EnumEntry | t.CPtr = self._get_enum_entry(i) - if entry is not None and entry.Name is not None: - if string.strcmp(entry.Name, name) == 0: - return entry - return None - - def lookup_enum_member(self, enum_name: str, - member_name: str) -> HandlesEnum.EnumMember | t.CPtr: - """按枚举类名和成员名查找,返回 EnumMember 或 None""" - if enum_name is None or member_name is None: - return None - entry: HandlesEnum.EnumEntry | t.CPtr = self.find_enum(enum_name) - if entry is None: - return None - for mi in range(entry.MemberCount): - me: HandlesEnum.EnumMember | t.CPtr = self._get_enum_member(entry, mi) - if me is not None and me.Name is not None: - if string.strcmp(me.Name, member_name) == 0: - return me - return None - - def is_enum_class(self, name: str) -> int: - """检查类名是否为已注册枚举,返回 1=是 / 0=否""" - if name is None: - return 0 - if self.find_enum(name) is not None: - return 1 - return 0 - - def get_enum_base_type(self, enum_name: str) -> llvmlite.LLVMType | t.CPtr: - """按枚举类名获取基准类型""" - entry: HandlesEnum.EnumEntry | t.CPtr = self.find_enum(enum_name) - if entry is not None: - return entry.BaseTy - return None +import lib.core.Gen.GenTypes as GenTypes +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdlib +import stdio +import viperlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.CompilerFactory as CompilerFactory +import lib.Projectrans.Config as Config +import lib.core.Gen.StmtGenCifMixin as StmtGenCifMixin + + +# ============================================================ +# StmtGenDeclMixin - StmtGen 拆分 2/3:声明/枚举/nonlocal 访问 +# +# 按功能域从 StmtGenMixin.vp 拆出(500~1500 行/文件架构重构,试点): +# translate_global/nonlocal/expr_stmt/pre_scan、break/continue、 +# nonlocal 闭包 env 访问、枚举注册表。继承 StmtGenCifMixin。 +# +# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 +# ============================================================ + + +# ============================================================ +# 常量(与 HandlesEnum 保持一致,本地副本避免跨模块 CDefine 查找 bug) +# ============================================================ +ENUM_MAX: t.CDefine = 64 +ENUM_MEMBER_MAX: t.CDefine = 128 + +# ============================================================ +# StmtGenDeclMixin - 声明/枚举/nonlocal(中层级) +# ============================================================ +@t.NoVTable +class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin): + """声明/枚举/nonlocal 访问(StmtGen 拆分 2/3,继承 Cif)""" + + def translate_global(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 global 语句:记录 global 变量名""" + gn: ast.Global | t.CPtr = (ast.Global | t.CPtr)(node) + if gn is None: + return 0 + names: list[ast.AST | t.CPtr] | t.CPtr = gn.names + if names is None: + return 0 + n: t.CSizeT = len(names) + for i in range(n): + nm_node: ast.AST | t.CPtr = names.get(i) + if nm_node is not None and nm_node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(nm_node) + if nm.id is not None: + HT.add_global_name(trans, nm.id) + return 0 + + def translate_nonlocal(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 nonlocal 语句:记录 nonlocal 变量名及其类型 + + 类型信息通过查找父作用域的 alloca 获取(用于 env 指针数组方案的类型恢复)。 + """ + nl: ast.Nonlocal | t.CPtr = (ast.Nonlocal | t.CPtr)(node) + if nl is None: + return 0 + names: list[ast.AST | t.CPtr] | t.CPtr = nl.names + if names is None: + return 0 + n: t.CSizeT = len(names) + for i in range(n): + nm_node: ast.AST | t.CPtr = names.get(i) + if nm_node is not None and nm_node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(nm_node) + if nm.id is not None: + # 查找父作用域中的变量 alloca,获取类型信息 + var_ty: llvmlite.LLVMType | t.CPtr = None + var_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, nm.id) + if var_alloca is not None and var_alloca.Ty is not None: + var_ty = var_alloca.Ty.Pointee + # Void 类型视为无效(Pointee 访问异常时可能返回 Void), + # 类型无效直接报错终止(fail-fast),避免生成 + # "bitcast ... to void*" / "load void, void*" 非法 IR + if var_ty is not None: + match var_ty: + case llvmlite.LLVMType.Void(): + self.Gen.TypeGenErr.fatal_error(nm_node, f"nonlocal 变量 '{nm.id}' 类型无效(Void/无法解析)", "TypeError") + case _: + pass + HT.add_nonlocal_name(trans, nm.id, var_ty) + return 0 + + def translate_expr_stmt(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译表达式语句(printf 调用等)""" + ex: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(node) + if ex is None: + return 0 + call_node: ast.AST | t.CPtr = ex.value + if call_node is None: + return 0 + ck: int = call_node.kind() + if ck != ast.ASTKind.Call: + return 0 + + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(call_node) + func_node: ast.AST | t.CPtr = cl.func + if func_node is None: + return 0 + + func_name: str = self.Gen.ExprGenBase.get_func_name(func_node) + if func_name is None: + # 函数名解析失败:直接报错终止(fail-fast) + self.Gen.TypeGenErr.fatal_error(call_node, "表达式语句的函数名解析失败", "SyntaxError") + + # printf / print 走特殊路径(print 是类型感知格式化,不映射到 printf) + if string.strcmp(func_name, "printf") == 0: + self.Gen.CallGenLeafKit.translate_printf_call( + trans.Pool, trans._cur_builder, trans.Module, cl, trans) + elif string.strcmp(func_name, "print") == 0: + self.Gen.CallGenLeafKit.translate_print_call( + trans.Pool, trans._cur_builder, trans.Module, cl, trans) + else: + # 通用函数调用(返回值丢弃) + self.Gen.CallGen.translate_call( + trans.Pool, trans._cur_builder, trans.Module, call_node, + trans._funcs, trans._func_count, trans) + return 0 + + def pre_scan_allocas(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """预扫描语句中的 AnnAssign,提前创建 alloca + + 返回新增的变量数 + """ + if node is None: + return 0 + return self.Gen.AssignGen.translate_annassign_prescan(trans, node) + + def pre_scan_scope_decls(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """预扫描 Global/Nonlocal 声明,提前注册作用域名称""" + if node is None: + return 0 + k: int = node.kind() + if k == ast.ASTKind.Global: + return self.translate_global(trans, node) + if k == ast.ASTKind.Nonlocal: + return self.translate_nonlocal(trans, node) + return 0 + + def translate_break(self, trans: HT.Translator | t.CPtr) -> int: + """翻译 break 语句:跳转到循环 end 块""" + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + pool: memhub.MemBuddy | t.CPtr = trans.Pool + + if builder is None or func is None: + return 0 + + # 发射 br 到 break 目标 + if trans._break_bb is not None: + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, trans._break_bb) + + # 创建死代码 BB,用于后续语句(break 后面的代码不可达) + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + name_buf: str = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "dead.%d", cnt) + dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + llvmlite.position_at_end(builder, dead_bb) + return 0 + + def translate_continue(self, trans: HT.Translator | t.CPtr) -> int: + """翻译 continue 语句:跳转到循环 cond/incr 块""" + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + pool: memhub.MemBuddy | t.CPtr = trans.Pool + + if builder is None or func is None: + return 0 + + # 发射 br 到 continue 目标 + if trans._continue_bb is not None: + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, trans._continue_bb) + + # 创建死代码 BB,用于后续语句 + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + name_buf: str = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "dead.%d", cnt) + dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + llvmlite.position_at_end(builder, dead_bb) + return 0 + + def get_stmt_kind_name(self, node: ast.AST | t.CPtr) -> str: + """获取语句类型名""" + if node is None: + return None + return node.type_name() + + # ============================================================ + # 簇 D:nonlocal/闭包 env 访问(迁移自 HandlesNonlocal.vp) + # ============================================================ + + def _is_void_type(self, ty: llvmlite.LLVMType | t.CPtr) -> int: + """判断是否为 Void 类型,是则返回 1,否则 0""" + if ty is None: + return 0 + match ty: + case llvmlite.LLVMType.Void(): + return 1 + case _: + return 0 + + def get_env_ptr_var(self, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """获取或创建 _env_ptr 变量(存储闭包 env 指针)""" + env_var: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, "_env_ptr") + if env_var is not None: + return env_var + # 创建 alloca 存储 env + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i8_ptr_ty) + if alloca is None: + return None + self.Gen.VarGen.define_var(trans.SymTab, "_env_ptr", alloca) + return alloca + + def _load_raw_var_ptr(self, trans: HT.Translator | t.CPtr, + name: str) -> llvmlite.Value | t.CPtr: + """从闭包 env 加载 nonlocal 变量的原始指针(i8*) + + 返回 i8* 类型的 Value,调用方需 bitcast 为具体类型指针后 load/store。 + """ + idx: int = HT.get_nonlocal_index(trans, name) + if idx < 0: + return None + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty) + + # 1. 加载 env_ptr + env_alloca: llvmlite.Value | t.CPtr = self.get_env_ptr_var(trans) + if env_alloca is None: + return None + env_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, env_alloca) + if env_ptr is None: + return None + + # 2. GEP to offset (idx * 8) — env 存储指针数组,每槽 8 字节 + offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, idx * 8) + addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, env_ptr, offset_val) + if addr is None: + return None + + # 3. Bitcast to i8** and load the raw pointer + ptr_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, addr, i8_ptr_ptr_ty) + if ptr_addr is None: + return None + return llvmlite.build_load(builder, i8_ptr_ty, ptr_addr) + + def load_nonlocal_var(self, trans: HT.Translator | t.CPtr, + name: str) -> llvmlite.Value | t.CPtr: + """从闭包 env 加载 nonlocal 变量值 + + 通过 HT.get_nonlocal_type 获取变量类型,bitcast 原始指针后 load。 + """ + raw_ptr: llvmlite.Value | t.CPtr = self._load_raw_var_ptr(trans, name) + if raw_ptr is None: + return None + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + + # 获取变量类型(从注册时存储的类型信息) + var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name) + if var_ty is None or self._is_void_type(var_ty) != 0: + # 类型缺失/无效直接报错终止(fail-fast),避免生成 "load void, void*" 非法 IR + self.Gen.TypeGenErr.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法 load", "TypeError") + + # bitcast raw i8* to var_ty* + var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty) + var_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, raw_ptr, var_ptr_ty) + if var_ptr is None: + return None + return llvmlite.build_load(builder, var_ty, var_ptr) + + def get_nonlocal_var_ptr(self, trans: HT.Translator | t.CPtr, + name: str) -> llvmlite.Value | t.CPtr: + """获取 nonlocal 变量的存储指针(var_ty*),用于 store 操作 + + 返回的指针指向父函数的 alloca,store 操作对父函数可见。 + """ + raw_ptr: llvmlite.Value | t.CPtr = self._load_raw_var_ptr(trans, name) + if raw_ptr is None: + return None + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + + # 获取变量类型 + var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name) + if var_ty is None or self._is_void_type(var_ty) != 0: + # 类型缺失/无效直接报错终止(fail-fast),避免生成 "bitcast ... to void*" 非法 IR + self.Gen.TypeGenErr.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法 load", "TypeError") + + # bitcast raw i8* to var_ty* + var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty) + return llvmlite.build_bitcast(builder, raw_ptr, var_ptr_ty) + + # ============================================================ + # 簇 E:枚举注册表(迁移自 HandlesEnum.vp) + # ============================================================ + + def init_enum_table(self, pool: memhub.MemBuddy | t.CPtr) -> int: + """初始化枚举注册表,返回 1 成功 + + 表用 stdlib 分配(跨 Phase1 1b 的 mark/reset_to 存活——枚举表是 + 跨文件持久表,pool 分配会被 reset 回收导致 Phase B 读垃圾, + enum_count 出现 512 等垃圾值 / entry.Name 解引用崩溃)。 + """ + if self.EnumTable is not None: + return 1 + + entry_size: t.CSizeT = GenTypes.EnumEntry.__sizeof__() + self.EnumTable = CompilerFactory.get_perm_pool().alloc(entry_size * ENUM_MAX) + if self.EnumTable is None: + return 0 + string.memset(self.EnumTable, 0, entry_size * ENUM_MAX) + self.EnumCount = 0 + return 1 + + def _get_enum_entry(self, i: int) -> GenTypes.EnumEntry | t.CPtr: + """获取第 i 个枚举条目""" + if self.EnumTable is None or i < 0 or i >= ENUM_MAX: + return None + entry_size: t.CSizeT = GenTypes.EnumEntry.__sizeof__() + addr: t.CUInt64T = t.CUInt64T(self.EnumTable) + i * entry_size + return (GenTypes.EnumEntry | t.CPtr)(t.CVoid(addr, t.CPtr)) + + def _get_enum_member(self, enum_entry: GenTypes.EnumEntry | t.CPtr, + i: int) -> GenTypes.EnumMember | t.CPtr: + """获取枚举中第 i 个成员条目""" + if enum_entry is None or i < 0 or i >= ENUM_MEMBER_MAX: + return None + member_size: t.CSizeT = GenTypes.EnumMember.__sizeof__() + addr: t.CUInt64T = t.CUInt64T(enum_entry.Members) + i * member_size + return (GenTypes.EnumMember | t.CPtr)(t.CVoid(addr, t.CPtr)) + + def register_enum(self, pool: memhub.MemBuddy | t.CPtr, + name: str, + base_ty: llvmlite.LLVMType | t.CPtr) -> GenTypes.EnumEntry | t.CPtr: + """注册枚举类型,返回 EnumEntry 指针""" + if self.init_enum_table(pool) == 0: + return None + + # 检查是否已注册 + existing: GenTypes.EnumEntry | t.CPtr = self.find_enum(name) + if existing is not None: + return existing + + if self.EnumCount >= ENUM_MAX: + fb_et: str = VLogger.fmt_buf() + if fb_et is not None: + viperlib.snprintf(fb_et, 1024, "table full, cannot register %s", name) + VLogger.error(fb_et, "ENUM") + return None + + entry: GenTypes.EnumEntry | t.CPtr = self._get_enum_entry(self.EnumCount) + if entry is None: + return None + + # 分配成员数组(永久池:跨 mark/reset 存活,对齐 EnumTable 永久池化) + member_size: t.CSizeT = GenTypes.EnumMember.__sizeof__() + entry.Members = CompilerFactory.get_perm_pool().alloc(member_size * ENUM_MEMBER_MAX) + if entry.Members is None: + return None + string.memset(entry.Members, 0, member_size * ENUM_MEMBER_MAX) + + # 复制类名(永久池深拷贝) + name_len: t.CSizeT = string.strlen(name) + name_buf: str = CompilerFactory.get_perm_pool().alloc(name_len + 1) + if name_buf is not None: + string.strcpy(name_buf, name) + entry.Name = name_buf + + # BaseTy 深拷贝:LLVMType 是 pool 分配,StdlibAlloc=1(Phase2 mark2 后) + # 时 reset 回收悬空 → Phase B 枚举访问 ConstInt(悬空 BaseTy) 生成 void + # 值(DecoratorMarkerTest `store void 2` llc 报错根因)。Phase1 1a + # (StdlibAlloc=0,mark1 前)保持 pool 存活,无需拷贝。 + # 注意:StdlibAlloc 是 StructGenMixin 字段,本 Mixin 方法体不能直接 + # self.StdlibAlloc(NoVTable 按本 Mixin 字段布局编译),走模块级委托。 + if self.Gen.StructGen.get_stdlib_alloc() != 0: + base_ty_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( + CompilerFactory.get_perm_pool(), base_ty) + if base_ty_copy is not None: + entry.BaseTy = base_ty_copy + else: + entry.BaseTy = base_ty + else: + entry.BaseTy = base_ty + entry.MemberCount = 0 + + self.EnumCount += 1 + return entry + + def add_enum_member(self, pool: memhub.MemBuddy | t.CPtr, + enum_entry: GenTypes.EnumEntry | t.CPtr, + member_name: str, + member_val: t.CInt64T, + member_ty: llvmlite.LLVMType | t.CPtr) -> int: + """向枚举添加成员,返回成员索引(-1 失败)""" + if enum_entry is None or member_name is None or member_ty is None: + return -1 + + # 去重:同名成员已存在则跳过(跨模块同名枚举合并注册 / 同模块 + # 重复处理幂等——如 w32.fileio 与 fat32_types 都有 FRESULT) + for ei_d in range(enum_entry.MemberCount): + ex_d: GenTypes.EnumMember | t.CPtr = self._get_enum_member( + enum_entry, ei_d) + if ex_d is not None and ex_d.Name is not None: + if string.strcmp(ex_d.Name, member_name) == 0: + return ei_d + + if enum_entry.MemberCount >= ENUM_MEMBER_MAX: + fb_em: str = VLogger.fmt_buf() + if fb_em is not None: + viperlib.snprintf(fb_em, 1024, "member table full for %s", enum_entry.Name) + VLogger.error(fb_em, "ENUM") + return -1 + + idx: int = enum_entry.MemberCount + me: GenTypes.EnumMember | t.CPtr = self._get_enum_member(enum_entry, idx) + if me is None: + return -1 + + # 复制成员名(永久池深拷贝:成员表跨 mark/reset 存活) + name_len: t.CSizeT = string.strlen(member_name) + name_buf: str = CompilerFactory.get_perm_pool().alloc(name_len + 1) + if name_buf is not None: + string.strcpy(name_buf, member_name) + me.Name = name_buf + + me.Value = member_val + me.Ty = member_ty + + enum_entry.MemberCount = idx + 1 + return idx + + def find_enum(self, name: str) -> GenTypes.EnumEntry | t.CPtr: + """按枚举类名查找,返回 EnumEntry 或 None""" + if name is None or self.EnumTable is None: + return None + for i in range(self.EnumCount): + entry: GenTypes.EnumEntry | t.CPtr = self._get_enum_entry(i) + if entry is not None and entry.Name is not None: + if string.strcmp(entry.Name, name) == 0: + return entry + return None + + def lookup_enum_member(self, enum_name: str, + member_name: str) -> GenTypes.EnumMember | t.CPtr: + """按枚举类名和成员名查找,返回 EnumMember 或 None""" + if enum_name is None or member_name is None: + return None + entry: GenTypes.EnumEntry | t.CPtr = self.find_enum(enum_name) + if entry is None: + return None + for mi in range(entry.MemberCount): + me: GenTypes.EnumMember | t.CPtr = self._get_enum_member(entry, mi) + if me is not None and me.Name is not None: + if string.strcmp(me.Name, member_name) == 0: + return me + return None + + def is_enum_class(self, name: str) -> int: + """检查类名是否为已注册枚举,返回 1=是 / 0=否""" + if name is None: + return 0 + if self.find_enum(name) is not None: + return 1 + return 0 + + def get_enum_base_type(self, enum_name: str) -> llvmlite.LLVMType | t.CPtr: + """按枚举类名获取基准类型""" + entry: GenTypes.EnumEntry | t.CPtr = self.find_enum(enum_name) + if entry is not None: + return entry.BaseTy + return None diff --git a/App/lib/core/Gen/StmtGenMixin.vp b/App/lib/core/Gen/StmtGenMixin.vp index c180d40..ffbcbb8 100644 --- a/App/lib/core/Gen/StmtGenMixin.vp +++ b/App/lib/core/Gen/StmtGenMixin.vp @@ -1,767 +1,745 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdlib -import stdio -import viperlib -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesFunctions as HandlesFunctions -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesIf as HandlesIf -import lib.core.Handles.HandlesWhile as HandlesWhile -import lib.core.Handles.HandlesFor as HandlesFor -import lib.core.Handles.HandlesReturn as HandlesReturn -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesMatch as HandlesMatch -import lib.core.Handles.HandlesEnum as HandlesEnum -import lib.core.CompilerFactory as CompilerFactory -import lib.Projectrans.Config as Config -import lib.core.Gen.StmtGenDeclMixin as StmtGenDeclMixin -import lib.core.Handles.ExprCallBase as ExprCallBase -import lib.core.Handles.ExprCallCtor as ExprCallCtor -import lib.core.Handles.HandlesAssign as HandlesAssign -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.Handles.HandlesAugAssign as HandlesAugAssign - - -# ============================================================ -# StmtGenMixin - 语句/流程翻译 Mixin(P6 对象化重构 A 组,拆分后顶层) -# -# 按功能域拆分(500~1500 行/文件架构重构,试点): -# 顶层保留语句分派中枢簇 A(translate_stmt/try/raise/with/delete/ -# _eh_ret_default/_with_ctx_call);global/nonlocal/枚举/CIf 已拆至 -# StmtGenDeclMixin / StmtGenCifMixin(本类继承链 1/3、2/3)。 -# 外部引用(Generator.vp import + HandlesBody 委托)零改动。 -# -# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 -# ============================================================ - - -# ============================================================ -# StmtGenMixin - 语句分派中枢(顶层) -# ============================================================ -@t.NoVTable -class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin): - """语句/流程翻译 Mixin(拆分后顶层,继承 Decl)""" - - def translate_stmt(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译单条语句,返回新增的变量数""" - if node is None: - return 0 - k: int = node.kind() - - if k == ast.ASTKind.Expr: - return self.translate_expr_stmt(trans, node) - elif k == ast.ASTKind.Assign: - return HandlesAssign.translate_assign(trans, node) - elif k == ast.ASTKind.AnnAssign: - return HandlesAnnAssign.translate_annassign(trans, node) - elif k == ast.ASTKind.FunctionDef: - # 嵌套函数定义:提升为顶层函数 + 创建闭包 - return HandlesFunctions.translate_nested_function_def(trans, node) - elif k == ast.ASTKind.Return: - return HandlesReturn.translate_return(trans, node) - elif k == ast.ASTKind.If: - return HandlesIf.translate_if(trans, node) - elif k == ast.ASTKind.While: - return HandlesWhile.translate_while(trans, node) - elif k == ast.ASTKind.AugAssign: - return HandlesAugAssign.translate_augassign(trans, node) - elif k == ast.ASTKind.For: - return HandlesFor.translate_for(trans, node) - elif k == ast.ASTKind.ClassDef: - return HandlesClassDef.translate_class_def(trans, node) - elif k == ast.ASTKind.Import: - return HandlesImports.translate_import(trans, node) - elif k == ast.ASTKind.ImportFrom: - HandlesImports.translate_import_from_module(trans, node) - return HandlesImports.translate_import_from_names(trans, node) - elif k == ast.ASTKind.Global: - return self.translate_global(trans, node) - elif k == ast.ASTKind.Nonlocal: - return self.translate_nonlocal(trans, node) - elif k == ast.ASTKind.Pass: - return 0 - elif k == ast.ASTKind.Break: - return self.translate_break(trans) - elif k == ast.ASTKind.Continue: - return self.translate_continue(trans) - elif k == ast.ASTKind.Match: - return HandlesMatch.translate_match(trans, node) - elif k == ast.ASTKind.Delete: - return self.translate_delete(trans, node) - elif k == ast.ASTKind.Raise: - return self.translate_raise(trans, node) - elif k == ast.ASTKind.Try: - return self.translate_try(trans, node) - elif k == ast.ASTKind.With: - return self.translate_with(trans, node) - # 未知语句类型:直接报错终止(fail-fast),暴露上游解析问题 - HandlesType.fatal_error(node, f"未知语句类型 kind={k}", "SyntaxError") - return 0 - - def translate_delete(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 del 语句,返回 0""" - if trans is None or node is None: - return 0 - dnode: ast.Delete | t.CPtr = (ast.Delete | t.CPtr)(node) - if dnode is None or dnode.targets is None: - return 0 - pool: memhub.MemBuddy | t.CPtr = trans.Pool - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - if pool is None or mod is None or builder is None: - return 0 - tn: t.CSizeT = len(dnode.targets) - for ti in range(tn): - tgt: ast.AST | t.CPtr = dnode.targets.get(ti) - if tgt is None: - continue - # del obj.attr → property deleter - if tgt.kind() == ast.ASTKind.Attribute: - del_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(tgt) - if del_at is not None: - ExprCallCtor._try_property_deleter( - pool, builder, mod, del_at, trans) - # del obj[key] → __delitem__(obj, key) - # (对齐 TPC HandlesDelete.py L14-25;此前 Subscript 目标被静默 - # 忽略,HashTableTest Test 11 的 del ht3[del_buf] 未执行 → len 不变) - elif tgt.kind() == ast.ASTKind.Subscript: - dl_sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(tgt) - if dl_sub is not None and dl_sub.value is not None and dl_sub.slice is not None: - dl_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, dl_sub.value, None, 0, trans) - dl_idx: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, dl_sub.slice, None, 0, trans) - if dl_obj is not None and dl_idx is not None: - dl_st: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value( - dl_obj) - if dl_st is not None: - dl_cls: str = HandlesStruct.get_class_name_by_type(pool, dl_st) - if dl_cls is not None: - dl_lookup: str = pool.alloc(128) - if dl_lookup is not None: - viperlib.snprintf(dl_lookup, 128, "%s.__delitem__", dl_cls) - dl_fn: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module( - mod, dl_lookup) - if dl_fn is not None: - dl_ret: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(dl_fn) - dl_fn_name: str = llvmlite.function_get_name(dl_fn) - if dl_ret is not None and dl_fn_name is not None: - # self 参数(容器)按 __delitem__ 首参类型对齐 - dl_self: llvmlite.Value | t.CPtr = dl_obj - dl_first: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(dl_fn) - if dl_first is not None: - dl_self_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(dl_first) - if dl_self_ty is not None: - dl_self = llvmlite.build_bitcast(builder, dl_obj, dl_self_ty) - if dl_self is not None: - # 参数链表: self → key(独立 null 结尾) - dl_self.Next = dl_idx - dl_idx.Next = None - llvmlite.build_call( - builder, dl_fn_name, dl_self, 2, dl_ret, 0) - return 0 - - # ============================================================ - # translate_try - try/except 语句翻译 - # - # 对齐 TPC HandlesTry.py L59-214(v1 迁移)。异常 = (i32 code, i8* msg) - # 二元组;except X 编译期静态展开 X 及全部子孙异常类编码。布局: - # pre → TryBB → DispatchBB(编码检查链)→ MatchBB → ExceptBB → AfterBB - # try 体正常结束 → store 0 →(else 若有)→ AfterBB - # DispatchBB 无匹配 → UnhandledBB:函数有 EH 输出参数则写入并返回 - # (向上传播),否则 store 0 → AfterBB(吞掉) - # try 上下文(DispatchBB + 两个 alloca)写入 trans._eh_*,translate_raise - # 与调用侧 EH 检测(CallGenMixin._emit_eh_guarded_call)据此重定向; - # 退出时恢复外层上下文(嵌套 try 支持)。 - # v1 未实现 finalbody(TestFBProject 未使用;finally+return 交互复杂, - # 后续按 TPC HandlesTry.py L188-214 的 pending_ret 方案扩展)。 - # ============================================================ - def translate_try(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 try/except 语句,返回 0""" - if trans is None or node is None: - return 0 - tr: ast.Try | t.CPtr = (ast.Try | t.CPtr)(node) - if tr is None: - return 0 - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - func: llvmlite.Function | t.CPtr = trans._cur_func - if pool is None or builder is None or func is None: - return 0 - if llvmlite.builder_cur_block_is_terminated(builder) != 0: - return 0 - - # ---- 1. 异常编码/消息 alloca(当前 try 上下文)---- - i32_ty_t: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i8_ty_t: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty_t: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_t) - if i32_ty_t is None or i8_ptr_ty_t is None: - return 0 - exception_code: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i32_ty_t) - eh_message: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i8_ptr_ty_t) - if exception_code is None or eh_message is None: - return 0 - init_code_t: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - init_msg_t: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty_t, "null") - if init_code_t is not None: - llvmlite.build_store(builder, init_code_t, exception_code) - if init_msg_t is not None: - llvmlite.build_store(builder, init_msg_t, eh_message) - - # ---- 2. 块布局(块名唯一化,create_block 不自动编号)---- - lc_t: int = trans._label_counter - trans._label_counter = lc_t + 1 - bb_buf_t: str = pool.alloc(64) - if bb_buf_t is None: - return 0 - viperlib.snprintf(bb_buf_t, 64, "try.dispatch.%d", lc_t) - dispatch_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t) - viperlib.snprintf(bb_buf_t, 64, "try.after.%d", lc_t) - after_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t) - viperlib.snprintf(bb_buf_t, 64, "try.unhandled.%d", lc_t) - unhandled_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t) - viperlib.snprintf(bb_buf_t, 64, "try.body.%d", lc_t) - try_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t) - if dispatch_bb is None or after_bb is None or unhandled_bb is None or try_bb is None: - return 0 - else_bb: llvmlite.BasicBlock | t.CPtr = None - if tr.orelse is not None and len(tr.orelse) > 0: - viperlib.snprintf(bb_buf_t, 64, "try.else.%d", lc_t) - else_bb = llvmlite.create_block(pool, func, bb_buf_t) - n_handlers_t: t.CSizeT = 0 - if tr.handlers is not None: - n_handlers_t = len(tr.handlers) - # 注意:list[ptr](pool, N) 第二参数是 elem_size 不是容量! - # 指针元素必须显式传 8(T.__sizeof__ 对联合类型不可靠), - # 否则 append 按 N 字节步长错位存取 → 读出垃圾指针(崩溃)。 - except_bbs: list[llvmlite.BasicBlock | t.CPtr] | t.CPtr = \ - list[llvmlite.BasicBlock | t.CPtr](pool, 8) - match_bbs: list[llvmlite.BasicBlock | t.CPtr] | t.CPtr = \ - list[llvmlite.BasicBlock | t.CPtr](pool, 8) - if except_bbs is None or match_bbs is None: - return 0 - for i_t in range(n_handlers_t): - viperlib.snprintf(bb_buf_t, 64, "try.except.%d.%d", lc_t, i_t) - eb_t: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t) - viperlib.snprintf(bb_buf_t, 64, "try.match.%d.%d", lc_t, i_t) - mb_t: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t) - except_bbs.append(eb_t) - match_bbs.append(mb_t) - - # ---- 3. 保存外层 try 上下文,设置本 try 上下文 ---- - old_dispatch_t: llvmlite.BasicBlock | t.CPtr = trans._eh_dispatch_bb - old_code_t: llvmlite.Value | t.CPtr = trans._eh_code_ptr - old_msg_t: llvmlite.Value | t.CPtr = trans._eh_msg_ptr - trans._eh_dispatch_bb = dispatch_bb - trans._eh_code_ptr = exception_code - trans._eh_msg_ptr = eh_message - - # ---- 4. Try 体 ---- - llvmlite.build_br(builder, try_bb) - llvmlite.position_at_end(builder, try_bb) - if tr.children is not None: - tb_n: t.CSizeT = len(tr.children) - for tbi in range(tb_n): - stmt_t: ast.AST | t.CPtr = tr.children.get(tbi) - if stmt_t is not None: - self.translate_stmt(trans, stmt_t) - # 正常走完 try 体:清异常码,进 else(若有)或 After - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - if init_code_t is not None: - llvmlite.build_store(builder, init_code_t, exception_code) - if else_bb is not None: - llvmlite.build_br(builder, else_bb) - else: - llvmlite.build_br(builder, after_bb) - - # ---- 5. DispatchBB:编码检查链 ---- - llvmlite.position_at_end(builder, dispatch_bb) - if n_handlers_t == 0: - # 无 except(非法 try,防御):直接吞掉 - llvmlite.build_br(builder, unhandled_bb) - else: - eh_code_val: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i32_ty_t, exception_code) - next_check_t: llvmlite.BasicBlock | t.CPtr = None - for i_t in range(n_handlers_t): - hdr_t: ast.ExceptHandler | t.CPtr = (ast.ExceptHandler | t.CPtr)( - tr.handlers.get(i_t)) - match_bb_t: llvmlite.BasicBlock | t.CPtr = match_bbs.get(i_t) - if i_t > 0 and next_check_t is not None: - llvmlite.position_at_end(builder, next_check_t) - eh_code_val = llvmlite.build_load( - builder, i32_ty_t, exception_code) - if hdr_t is None or hdr_t.type is None: - # 裸 except:无条件匹配 - llvmlite.build_br(builder, match_bb_t) - else: - # 展开匹配编码集(handler.type 自身 + 全部子孙异常类) - hname_t: str = None - htype_t: ast.AST | t.CPtr = hdr_t.type - if htype_t.kind() == ast.ASTKind.Name: - hname_t = ((ast.Name | t.CPtr)(htype_t)).id - elif htype_t.kind() == ast.ASTKind.Attribute: - hname_t = ((ast.Attribute | t.CPtr)(htype_t)).attr - # 匹配编码缓冲:必须是 t.CInt*(i32 步长)——collect_descendant_codes - # 按 out_codes[i](4 字节)写入;若用 t.CSizeT*(8 字节)读, - # 多码时读出 (code[i+1]<<32)|code[i] 的 64 位拼接垃圾(单码时 - # 高位恰为 0 掩盖;Test 2/3/8 父类多码捕获失败的根因)。 - codes_buf_t: t.CInt | t.CPtr = pool.alloc(64 * 4) - if codes_buf_t is None: - return 0 - n_codes_t: int = 0 - if hname_t is not None and HandlesClassDef.is_exception_name(hname_t) != 0: - n_codes_t = HandlesClassDef.collect_descendant_codes( - hname_t, codes_buf_t, 64) - else: - c0_t: int = 1 - if hname_t is not None: - c0_t = HandlesClassDef.lookup_exception_code(hname_t) - if c0_t == 0: - c0_t = 1 - codes_buf_t[0] = c0_t - n_codes_t = 1 - match_cond_t: llvmlite.Value | t.CPtr = None - for ci_t in range(n_codes_t): - code_val_t: llvmlite.Value | t.CPtr = llvmlite.const_int32( - pool, codes_buf_t[ci_t]) - is_match_t: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_EQ, eh_code_val, code_val_t) - if match_cond_t is None: - match_cond_t = is_match_t - elif is_match_t is not None: - match_cond_t = llvmlite.build_or( - builder, match_cond_t, is_match_t) - if i_t < n_handlers_t - 1: - viperlib.snprintf(bb_buf_t, 64, "try.check.%d.%d", lc_t, i_t) - next_check_t = llvmlite.create_block(pool, func, bb_buf_t) - else: - next_check_t = unhandled_bb - llvmlite.build_cond_br( - builder, match_cond_t, match_bb_t, next_check_t) - # MatchBB:绑定 handler 变量(e = 消息指针),跳 ExceptBB - llvmlite.position_at_end(builder, match_bb_t) - if hdr_t is not None and hdr_t.name is not None and hdr_t.name[0] != '\0': - # 同名 handler 变量复用函数入口 alloca(find_var 首条命中、 - # 重复 define_var 不 shadow——多 try 共用 `as e` 时各 MatchBB - # 各自 store 消息,各 ExceptBB 读同一入口 alloca,避免 - # 非支配 alloca 触发 "does not dominate all uses")。 - h_ent_t: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, hdr_t.name) - if h_ent_t is not None and h_ent_t.Alloca is not None: - h_alloca_t: llvmlite.Value | t.CPtr = h_ent_t.Alloca - else: - h_alloca_t = HandlesVar._alloca_at_entry(builder, i8_ptr_ty_t) - if h_alloca_t is not None: - HandlesVar.define_var(trans.SymTab, hdr_t.name, h_alloca_t) - if h_alloca_t is not None: - h_msg_t: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i8_ptr_ty_t, eh_message) - if h_msg_t is not None: - llvmlite.build_store(builder, h_msg_t, h_alloca_t) - except_bb_t: llvmlite.BasicBlock | t.CPtr = except_bbs.get(i_t) - llvmlite.build_br(builder, except_bb_t) - - # ---- 6. UnhandledBB:无 except 匹配 → 向上传播或吞掉 ---- - llvmlite.position_at_end(builder, unhandled_bb) - if trans._cur_func_has_eh != 0 and trans._eh_msg_out_param is not None \ - and trans._eh_code_out_param is not None: - un_msg_t: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i8_ptr_ty_t, eh_message) - un_code_t: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i32_ty_t, exception_code) - if un_msg_t is not None: - llvmlite.build_store(builder, un_msg_t, trans._eh_msg_out_param) - if un_code_t is not None: - llvmlite.build_store(builder, un_code_t, trans._eh_code_out_param) - self._eh_ret_default(trans, pool, builder) - else: - if init_code_t is not None: - llvmlite.build_store(builder, init_code_t, exception_code) - llvmlite.build_br(builder, after_bb) - - # ---- 7. Except 体 ---- - for i_t in range(n_handlers_t): - hdr2_t: ast.ExceptHandler | t.CPtr = (ast.ExceptHandler | t.CPtr)( - tr.handlers.get(i_t)) - except_bb2_t: llvmlite.BasicBlock | t.CPtr = except_bbs.get(i_t) - llvmlite.position_at_end(builder, except_bb2_t) - if hdr2_t is not None and hdr2_t.children is not None: - hn2_t: t.CSizeT = len(hdr2_t.children) - for hi2 in range(hn2_t): - stmt2_t: ast.AST | t.CPtr = hdr2_t.children.get(hi2) - if stmt2_t is not None: - self.translate_stmt(trans, stmt2_t) - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, after_bb) - - # ---- 8. Else 体 ---- - if else_bb is not None: - llvmlite.position_at_end(builder, else_bb) - if tr.orelse is not None: - en_t: t.CSizeT = len(tr.orelse) - for ei in range(en_t): - stmt3_t: ast.AST | t.CPtr = tr.orelse.get(ei) - if stmt3_t is not None: - self.translate_stmt(trans, stmt3_t) - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, after_bb) - - # ---- 9. AfterBB + 恢复外层 try 上下文 ---- - llvmlite.position_at_end(builder, after_bb) - trans._eh_dispatch_bb = old_dispatch_t - trans._eh_code_ptr = old_code_t - trans._eh_msg_ptr = old_msg_t - return 0 - - def translate_raise(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 raise 语句,返回 0 - - 对齐 TPC HandlesRaise.py 的 try-except 语义(v1 迁移): - - StopIteration:置 __stop_iter_flag__ = 1 后返回默认值(迭代结束协议) - - 非 StopIteration: - 1. 处于 try(trans._eh_dispatch_bb 非空):异常编码/消息写入当前 - try 的 eh_code/eh_message alloca,分支到 DispatchBB 由 except 链裁决 - 2. 函数有 EH 输出参数(_cur_func_has_eh):编码/消息写入 - __eh_code_out__/__eh_msg_out__,返回默认值(异常向调用方传播) - 3. 两者皆无:仅返回默认值(v1 语义:异常被吞掉) - """ - if trans is None or node is None: - return 0 - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - if pool is None or builder is None or mod is None: - return 0 - rn: ast.Raise | t.CPtr = (ast.Raise | t.CPtr)(node) - if rn is None or rn.exc is None: - # bare raise(无 exc):v1 无活动异常可再抛,仅返回默认值 - self._eh_ret_default(trans, pool, builder) - return 0 - - # OOP iter 协议:raise StopIteration → 置 __stop_iter_flag__ = 1 - # (对齐 TPC HandlesRaise.py L76-100),随后按迭代结束返回默认值。 - ek: int = rn.exc.kind() - is_stop_iter: int = 0 - if ek == ast.ASTKind.Name: - enm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rn.exc) - if enm.id is not None and string.strcmp(enm.id, "StopIteration") == 0: - is_stop_iter = 1 - elif ek == ast.ASTKind.Call: - ecl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(rn.exc) - if ecl.func is not None and ecl.func.kind() == ast.ASTKind.Name: - ecn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ecl.func) - if ecn.id is not None and string.strcmp(ecn.id, "StopIteration") == 0: - is_stop_iter = 1 - if is_stop_iter != 0: - if trans._stop_iter_flag_ptr is not None: - i1_ty_r: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - if i1_ty_r is not None: - one_i1_r: llvmlite.Value | t.CPtr = llvmlite.ConstInt( - pool, i1_ty_r, 1, "1") - if one_i1_r is not None: - llvmlite.build_store( - builder, one_i1_r, trans._stop_iter_flag_ptr) - self._eh_ret_default(trans, pool, builder) - return 0 - - # ---- 非 StopIteration:计算异常编码与消息 ---- - exc_code: int = 1 - exc_msg: llvmlite.Value | t.CPtr = None - if ek == ast.ASTKind.Constant: - cst_r: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(rn.exc) - if cst_r is not None and cst_r.const_kind == ast.CONST_INT: - exc_code = cst_r.int_val - elif ek == ast.ASTKind.Name: - enm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rn.exc) - if enm2.id is not None: - exc_code = HandlesClassDef.lookup_exception_code(enm2.id) - if exc_code == 0: - exc_code = 1 - elif ek == ast.ASTKind.Call: - ecl2: ast.Call | t.CPtr = (ast.Call | t.CPtr)(rn.exc) - if ecl2.func is not None and ecl2.func.kind() == ast.ASTKind.Name: - ecn2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ecl2.func) - if ecn2.id is not None: - exc_code = HandlesClassDef.lookup_exception_code(ecn2.id) - if exc_code == 0: - exc_code = 1 - if ecl2.args is not None and len(ecl2.args) > 0: - exc_msg = HandlesExpr.translate_value( - builder, pool, mod, ecl2.args.get(0), None, 0, trans) - - # ---- 异常分发 ---- - # 1. try 内:写入 try 的 eh_code/eh_message alloca,分支 DispatchBB - if trans._eh_dispatch_bb is not None and trans._eh_code_ptr is not None: - code_val_r: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, exc_code) - if code_val_r is not None: - llvmlite.build_store(builder, code_val_r, trans._eh_code_ptr) - if exc_msg is None: - exc_msg = llvmlite.ConstNull( - pool, llvmlite.Ptr(pool, llvmlite.Int8(pool)), "null") - if exc_msg is not None and trans._eh_msg_ptr is not None: - llvmlite.build_store(builder, exc_msg, trans._eh_msg_ptr) - llvmlite.build_br(builder, trans._eh_dispatch_bb) - return 0 - # 2. 函数有 EH 输出参数:写入 out 参数(异常向调用方传播) - if trans._cur_func_has_eh != 0 and trans._eh_msg_out_param is not None \ - and trans._eh_code_out_param is not None: - code_val_r2: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, exc_code) - if code_val_r2 is not None: - llvmlite.build_store(builder, code_val_r2, trans._eh_code_out_param) - if exc_msg is None: - exc_msg = llvmlite.ConstNull( - pool, llvmlite.Ptr(pool, llvmlite.Int8(pool)), "null") - if exc_msg is not None: - llvmlite.build_store(builder, exc_msg, trans._eh_msg_out_param) - self._eh_ret_default(trans, pool, builder) - return 0 - # 3. 无 try 无 EH 参数:仅返回默认值 - self._eh_ret_default(trans, pool, builder) - return 0 - - # ============================================================ - # _eh_ret_default - 异常路径返回当前函数的默认零值 - # - # 对齐 TPC HandlesTry.py UnhandledBB / HandlesRaise.py 的返回生成 - # (void→ret_void,ptr→null,float→0.0,其余→零值)。当前块已 - # 终结(前一条是 raise/return)时跳过,避免在终止块后插指令。 - # ============================================================ - def _eh_ret_default(self, trans: HT.Translator | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr) -> int: - """异常路径返回当前函数默认零值,返回 0""" - if trans is None or builder is None: - return 0 - if llvmlite.builder_cur_block_is_terminated(builder) != 0: - return 0 - cur_func: llvmlite.Function | t.CPtr = trans._cur_func - if cur_func is None: - return 0 - ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(cur_func) - if ret_ty is None: - return 0 - match ret_ty: - case llvmlite.LLVMType.Void(): - llvmlite.build_ret_void(builder) - case llvmlite.LLVMType.Ptr(_pe): - null_v: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, ret_ty, "null") - if null_v is not None: - llvmlite.build_ret(builder, null_v) - case llvmlite.LLVMType.Float(_fb): - zero_f: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, ret_ty, 0.0) - if zero_f is not None: - llvmlite.build_ret(builder, zero_f) - case _: - zero_v: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, ret_ty) - if zero_v is not None: - llvmlite.build_ret(builder, zero_v) - return 0 - - # ============================================================ - # translate_with - with 语句翻译 - # - # with expr() as x: body - # → 1. 构造 context 对象(expr() 调用) - # 2. 调用 __enter__()(沿继承链 MRO 解析,如 MemPool → MemManager) - # 3. x 绑定 __enter__ 返回值(缺失时退回 context 对象) - # 4. 翻译 body - # 5. 逆序调用 __exit__()(无异常传播,__exit__ 仅做清理如 reset) - # - # 实现:context 对象存入临时变量 __with_ctx,方法调用复用 - # translate_call 的 Attribute 分派 + _translate_method_call 的 MRO 回退 - # (与普通 obj.method() 调用一致)。嵌套 with 时保存外层 __with_ctx, - # 退出后恢复,避免内层覆盖导致外层 __exit__ 解析到错误对象。 - # 对齐 TPC HandlesWith 语义(不含 __provides__ provider 机制)。 - # ============================================================ - def translate_with(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 with 语句,返回 0""" - if trans is None or node is None: - return 0 - wt: ast.With | t.CPtr = (ast.With | t.CPtr)(node) - if wt is None: - return 0 - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - if pool is None or builder is None or mod is None: - return 0 - items: list[ast.AST | t.CPtr] | t.CPtr = wt.items - if items is None: - return 0 - n: t.CSizeT = len(items) - - # 保存外层 __with_ctx(嵌套 with 时退出后恢复) - old_ctx_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, "__with_ctx") - - # 记录每个 item 的类名(__exit__ 调用时设置 __with_ctx 类型用) - ctx_class_buf: t.CSizeT | t.CPtr = pool.alloc(8 * n) - if ctx_class_buf is None: - return 0 - string.memset(ctx_class_buf, 0, 8 * n) - - # 1. 全部 item:构造 context 对象 + 调用 __enter__ + asname 绑定 - for i in range(n): - item_node: ast.AST | t.CPtr = items.get(i) - if item_node is None: - continue - if item_node.kind() != ast.ASTKind.WithItem: - continue - item: ast.WithItem | t.CPtr = (ast.WithItem | t.CPtr)(item_node) - if item is None or item.context_expr is None: - continue - # 翻译 context_expr(对象构造,如 MemPool(arena, 4096)) - ctx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, item.context_expr, - trans._funcs, trans._func_count, trans) - if ctx_val is None: - continue - # 提取类名(注解类名,Attribute 时带模块前缀,如 "memhub.MemPool"—— - # 与 AnnAssign 的 extract_class_name_from_annotation 一致,跨模块 - # 方法调用靠 AnnotClassName 回退按模块名查 SHA1) - cls_name: str = None - ce: ast.AST | t.CPtr = item.context_expr - if ce.kind() == ast.ASTKind.Call: - cfn: ast.AST | t.CPtr = ((ast.Call | t.CPtr)(ce)).func - if cfn is not None: - if cfn.kind() == ast.ASTKind.Attribute: - ca: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cfn) - if ca.value is not None and ca.value.kind() == ast.ASTKind.Name: - cmn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ca.value) - if cmn.id is not None: - ml2: t.CSizeT = string.strlen(cmn.id) + string.strlen(ca.attr) + 2 - mbuf: str = pool.alloc(ml2) - if mbuf is not None: - viperlib.snprintf(mbuf, ml2, "%s.%s", cmn.id, ca.attr) - cls_name = mbuf - if cls_name is None: - cls_name = ca.attr - elif cfn.kind() == ast.ASTKind.Name: - cls_name = ((ast.Name | t.CPtr)(cfn)).id - # context 对象存入 __with_ctx(方法调用解析 self 用) - ctx_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca( - builder, ctx_val.Ty) - if ctx_alloca is None: - continue - llvmlite.build_store(builder, ctx_val, ctx_alloca) - HandlesVar.define_var(trans.SymTab, "__with_ctx", ctx_alloca) - if cls_name is not None: - HandlesVar.set_var_annot_class_name( - trans.SymTab, "__with_ctx", cls_name) - ctx_class_buf[i] = t.CSizeT(cls_name) - # 调用 __enter__() - enter_val: llvmlite.Value | t.CPtr = self._with_ctx_call( - trans, pool, builder, mod, "__enter__") - # asname 绑定(__enter__ 返回值,缺失时退回 context 对象) - if item.optional_vars is not None: - ov: ast.AST | t.CPtr = item.optional_vars - if ov.kind() == ast.ASTKind.Name: - asname: str = ((ast.Name | t.CPtr)(ov)).id - if asname is not None: - bind_val: llvmlite.Value | t.CPtr = enter_val - if bind_val is None: - bind_val = ctx_val - if bind_val is not None: - asn_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca( - builder, bind_val.Ty) - if asn_alloca is not None: - llvmlite.build_store(builder, bind_val, asn_alloca) - HandlesVar.define_var(trans.SymTab, asname, asn_alloca) - if cls_name is not None: - HandlesVar.set_var_annot_class_name( - trans.SymTab, asname, cls_name) - # FakeDuck: __provides__ 元数据 → 生成 _push_provider 调用 - # (对齐 TPC HandlesWith.py L138-159;经 gen 单例委托 CallGenMixin。 - # 类名去模块前缀后查 __provides__ 表,如 memhub.MemBuddy → MemBuddy) - fd_cls_bare: str = cls_name - if cls_name is not None: - fd_dot: str = string.strrchr(cls_name, '.') - if fd_dot is not None: - fd_cls_bare = fd_dot + 1 - import lib.core.Gen.Generator as Generator - g_fd6: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( - t.CVoid(HandlesExpr._g_gen, t.CPtr)) - if g_fd6 is not None and fd_cls_bare is not None: - g_fd6._emit_provider_push( - trans, pool, builder, mod, fd_cls_bare, ctx_val) - - # 2. 翻译 body - body: list[ast.AST | t.CPtr] | t.CPtr = wt.children - if body is not None: - bn: t.CSizeT = len(body) - for bi in range(bn): - st: ast.AST | t.CPtr = body.get(bi) - if st is not None: - self.translate_stmt(trans, st) - - # 2.5 FakeDuck: __provides__ 元数据 → 生成 _pop_provider 调用 - # (对齐 TPC HandlesWith.py L167-174;逆序弹栈,经 gen 单例委托) - import lib.core.Gen.Generator as Generator - g_fd6b: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( - t.CVoid(HandlesExpr._g_gen, t.CPtr)) - if g_fd6b is not None: - for pi_pop in range(n): - if ctx_class_buf[pi_pop] != 0: - cls_pop: str = (str | t.CPtr)(t.CVoid(ctx_class_buf[pi_pop], t.CPtr)) - fd_cls_bare_p: str = cls_pop - if cls_pop is not None: - fd_dot_p: str = string.strrchr(cls_pop, '.') - if fd_dot_p is not None: - fd_cls_bare_p = fd_dot_p + 1 - if fd_cls_bare_p is not None: - g_fd6b._emit_provider_pop( - trans, pool, builder, mod, fd_cls_bare_p) - - # 3. 逆序调用 __exit__()(Python with 语义:后进先出) - for i in range(n): - ci: int = n - 1 - i - if ctx_class_buf[ci] != 0: - cls_ci: str = (str | t.CPtr)(t.CVoid(ctx_class_buf[ci], t.CPtr)) - HandlesVar.set_var_annot_class_name( - trans.SymTab, "__with_ctx", cls_ci) - self._with_ctx_call(trans, pool, builder, mod, "__exit__") - - # 4. 恢复外层 __with_ctx - if old_ctx_alloca is not None: - HandlesVar.define_var(trans.SymTab, "__with_ctx", old_ctx_alloca) - return 0 - - def _with_ctx_call(self, trans: HT.Translator | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - method_name: str) -> llvmlite.Value | t.CPtr: - """构造并翻译 __with_ctx.() 调用(__enter__/__exit__)""" - if pool is None or method_name is None: - return None - name_node: ast.AST | t.CPtr = ast.Name(pool, "__with_ctx", ast.ASTCtx.Load) - if name_node is None: - return None - attr_node: ast.AST | t.CPtr = ast.Attribute( - pool, name_node, method_name, ast.ASTCtx.Load) - if attr_node is None: - return None - call_node: ast.AST | t.CPtr = ast.Call(pool, attr_node, None, None) - if call_node is None: - return None - return HandlesExpr.translate_value( - builder, pool, mod, call_node, - trans._funcs, trans._func_count, trans) +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.Generator as Generator +import lib.core.Gen.CallGenFd as CallGenFd +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdlib +import stdio +import viperlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.CompilerFactory as CompilerFactory +import lib.Projectrans.Config as Config +import lib.core.Gen.StmtGenDeclMixin as StmtGenDeclMixin + + +# ============================================================ +# StmtGenMixin - 语句/流程翻译 Mixin(P6 对象化重构 A 组,拆分后顶层) +# +# 按功能域拆分(500~1500 行/文件架构重构,试点): +# 顶层保留语句分派中枢簇 A(translate_stmt/try/raise/with/delete/ +# _eh_ret_default/_with_ctx_call);global/nonlocal/枚举/CIf 已拆至 +# StmtGenDeclMixin / StmtGenCifMixin(本类继承链 1/3、2/3)。 +# 外部引用(Generator.vp import + HandlesBody 委托)零改动。 +# +# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 +# ============================================================ + + +# ============================================================ +# StmtGenMixin - 语句分派中枢(顶层) +# ============================================================ +@t.NoVTable +class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin): + """语句/流程翻译 Mixin(拆分后顶层,继承 Decl)""" + + def translate_stmt(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译单条语句,返回新增的变量数""" + if node is None: + return 0 + k: int = node.kind() + + if k == ast.ASTKind.Expr: + return self.translate_expr_stmt(trans, node) + elif k == ast.ASTKind.Assign: + return self.Gen.AssignGen.translate_assign(trans, node) + elif k == ast.ASTKind.AnnAssign: + return self.Gen.AssignGen.translate_annassign(trans, node) + elif k == ast.ASTKind.FunctionDef: + # 嵌套函数定义:提升为顶层函数 + 创建闭包 + return self.Gen.FuncGen.translate_nested_function_def(trans, node) + elif k == ast.ASTKind.Return: + return self.Gen.StmtGenCif.translate_return(trans, node) + elif k == ast.ASTKind.If: + return self.Gen.StmtGenCif.translate_if(trans, node) + elif k == ast.ASTKind.While: + return self.Gen.StmtGenCif.translate_while(trans, node) + elif k == ast.ASTKind.AugAssign: + return self.Gen.AssignGen.translate_augassign(trans, node) + elif k == ast.ASTKind.For: + return self.Gen.StmtGenCif.translate_for(trans, node) + elif k == ast.ASTKind.ClassDef: + return self.Gen.ClassGenDef.translate_class_def(trans, node) + elif k == ast.ASTKind.Import: + return self.Gen.ImportsGen.translate_import(trans, node) + elif k == ast.ASTKind.ImportFrom: + self.Gen.ImportsGen.translate_import_from_module(trans, node) + return self.Gen.ImportsGen.translate_import_from_names(trans, node) + elif k == ast.ASTKind.Global: + return self.translate_global(trans, node) + elif k == ast.ASTKind.Nonlocal: + return self.translate_nonlocal(trans, node) + elif k == ast.ASTKind.Pass: + return 0 + elif k == ast.ASTKind.Break: + return self.translate_break(trans) + elif k == ast.ASTKind.Continue: + return self.translate_continue(trans) + elif k == ast.ASTKind.Match: + return self.Gen.MatchGen.translate_match(trans, node) + elif k == ast.ASTKind.Delete: + return self.translate_delete(trans, node) + elif k == ast.ASTKind.Raise: + return self.translate_raise(trans, node) + elif k == ast.ASTKind.Try: + return self.translate_try(trans, node) + elif k == ast.ASTKind.With: + return self.translate_with(trans, node) + # 未知语句类型:直接报错终止(fail-fast),暴露上游解析问题 + self.Gen.TypeGenErr.fatal_error(node, f"未知语句类型 kind={k}", "SyntaxError") + return 0 + + def translate_delete(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 del 语句,返回 0""" + if trans is None or node is None: + return 0 + dnode: ast.Delete | t.CPtr = (ast.Delete | t.CPtr)(node) + if dnode is None or dnode.targets is None: + return 0 + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + if pool is None or mod is None or builder is None: + return 0 + tn: t.CSizeT = len(dnode.targets) + for ti in range(tn): + tgt: ast.AST | t.CPtr = dnode.targets.get(ti) + if tgt is None: + continue + # del obj.attr → property deleter + if tgt.kind() == ast.ASTKind.Attribute: + del_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(tgt) + if del_at is not None: + self.Gen.CallGenProp._try_property_deleter( + pool, builder, mod, del_at, trans) + # del obj[key] → __delitem__(obj, key) + # (对齐 TPC HandlesDelete.py L14-25;此前 Subscript 目标被静默 + # 忽略,HashTableTest Test 11 的 del ht3[del_buf] 未执行 → len 不变) + elif tgt.kind() == ast.ASTKind.Subscript: + dl_sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(tgt) + if dl_sub is not None and dl_sub.value is not None and dl_sub.slice is not None: + dl_obj: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, dl_sub.value, None, 0, trans) + dl_idx: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, dl_sub.slice, None, 0, trans) + if dl_obj is not None and dl_idx is not None: + dl_st: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type_from_value( + dl_obj) + if dl_st is not None: + dl_cls: str = self.Gen.StructGen.get_class_name_by_type(pool, dl_st) + if dl_cls is not None: + dl_lookup: str = pool.alloc(128) + if dl_lookup is not None: + viperlib.snprintf(dl_lookup, 128, "%s.__delitem__", dl_cls) + dl_fn: llvmlite.Function | t.CPtr = self.Gen.CallGenBase.find_func_in_module( + mod, dl_lookup) + if dl_fn is not None: + dl_ret: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(dl_fn) + dl_fn_name: str = llvmlite.function_get_name(dl_fn) + if dl_ret is not None and dl_fn_name is not None: + # self 参数(容器)按 __delitem__ 首参类型对齐 + dl_self: llvmlite.Value | t.CPtr = dl_obj + dl_first: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(dl_fn) + if dl_first is not None: + dl_self_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(dl_first) + if dl_self_ty is not None: + dl_self = llvmlite.build_bitcast(builder, dl_obj, dl_self_ty) + if dl_self is not None: + # 参数链表: self → key(独立 null 结尾) + dl_self.Next = dl_idx + dl_idx.Next = None + llvmlite.build_call( + builder, dl_fn_name, dl_self, 2, dl_ret, 0) + return 0 + + # ============================================================ + # translate_try - try/except 语句翻译 + # + # 对齐 TPC HandlesTry.py L59-214(v1 迁移)。异常 = (i32 code, i8* msg) + # 二元组;except X 编译期静态展开 X 及全部子孙异常类编码。布局: + # pre → TryBB → DispatchBB(编码检查链)→ MatchBB → ExceptBB → AfterBB + # try 体正常结束 → store 0 →(else 若有)→ AfterBB + # DispatchBB 无匹配 → UnhandledBB:函数有 EH 输出参数则写入并返回 + # (向上传播),否则 store 0 → AfterBB(吞掉) + # try 上下文(DispatchBB + 两个 alloca)写入 trans._eh_*,translate_raise + # 与调用侧 EH 检测(CallGenMixin._emit_eh_guarded_call)据此重定向; + # 退出时恢复外层上下文(嵌套 try 支持)。 + # v1 未实现 finalbody(TestFBProject 未使用;finally+return 交互复杂, + # 后续按 TPC HandlesTry.py L188-214 的 pending_ret 方案扩展)。 + # ============================================================ + def translate_try(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 try/except 语句,返回 0""" + if trans is None or node is None: + return 0 + tr: ast.Try | t.CPtr = (ast.Try | t.CPtr)(node) + if tr is None: + return 0 + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + if pool is None or builder is None or func is None: + return 0 + if llvmlite.builder_cur_block_is_terminated(builder) != 0: + return 0 + + # ---- 1. 异常编码/消息 alloca(当前 try 上下文)---- + i32_ty_t: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i8_ty_t: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty_t: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_t) + if i32_ty_t is None or i8_ptr_ty_t is None: + return 0 + exception_code: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i32_ty_t) + eh_message: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i8_ptr_ty_t) + if exception_code is None or eh_message is None: + return 0 + init_code_t: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + init_msg_t: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty_t, "null") + if init_code_t is not None: + llvmlite.build_store(builder, init_code_t, exception_code) + if init_msg_t is not None: + llvmlite.build_store(builder, init_msg_t, eh_message) + + # ---- 2. 块布局(块名唯一化,create_block 不自动编号)---- + lc_t: int = trans._label_counter + trans._label_counter = lc_t + 1 + bb_buf_t: str = pool.alloc(64) + if bb_buf_t is None: + return 0 + viperlib.snprintf(bb_buf_t, 64, "try.dispatch.%d", lc_t) + dispatch_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t) + viperlib.snprintf(bb_buf_t, 64, "try.after.%d", lc_t) + after_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t) + viperlib.snprintf(bb_buf_t, 64, "try.unhandled.%d", lc_t) + unhandled_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t) + viperlib.snprintf(bb_buf_t, 64, "try.body.%d", lc_t) + try_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t) + if dispatch_bb is None or after_bb is None or unhandled_bb is None or try_bb is None: + return 0 + else_bb: llvmlite.BasicBlock | t.CPtr = None + if tr.orelse is not None and len(tr.orelse) > 0: + viperlib.snprintf(bb_buf_t, 64, "try.else.%d", lc_t) + else_bb = llvmlite.create_block(pool, func, bb_buf_t) + n_handlers_t: t.CSizeT = 0 + if tr.handlers is not None: + n_handlers_t = len(tr.handlers) + # 注意:list[ptr](pool, N) 第二参数是 elem_size 不是容量! + # 指针元素必须显式传 8(T.__sizeof__ 对联合类型不可靠), + # 否则 append 按 N 字节步长错位存取 → 读出垃圾指针(崩溃)。 + except_bbs: list[llvmlite.BasicBlock | t.CPtr] | t.CPtr = \ + list[llvmlite.BasicBlock | t.CPtr](pool, 8) + match_bbs: list[llvmlite.BasicBlock | t.CPtr] | t.CPtr = \ + list[llvmlite.BasicBlock | t.CPtr](pool, 8) + if except_bbs is None or match_bbs is None: + return 0 + for i_t in range(n_handlers_t): + viperlib.snprintf(bb_buf_t, 64, "try.except.%d.%d", lc_t, i_t) + eb_t: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t) + viperlib.snprintf(bb_buf_t, 64, "try.match.%d.%d", lc_t, i_t) + mb_t: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t) + except_bbs.append(eb_t) + match_bbs.append(mb_t) + + # ---- 3. 保存外层 try 上下文,设置本 try 上下文 ---- + old_dispatch_t: llvmlite.BasicBlock | t.CPtr = trans._eh_dispatch_bb + old_code_t: llvmlite.Value | t.CPtr = trans._eh_code_ptr + old_msg_t: llvmlite.Value | t.CPtr = trans._eh_msg_ptr + trans._eh_dispatch_bb = dispatch_bb + trans._eh_code_ptr = exception_code + trans._eh_msg_ptr = eh_message + + # ---- 4. Try 体 ---- + llvmlite.build_br(builder, try_bb) + llvmlite.position_at_end(builder, try_bb) + if tr.children is not None: + tb_n: t.CSizeT = len(tr.children) + for tbi in range(tb_n): + stmt_t: ast.AST | t.CPtr = tr.children.get(tbi) + if stmt_t is not None: + self.translate_stmt(trans, stmt_t) + # 正常走完 try 体:清异常码,进 else(若有)或 After + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + if init_code_t is not None: + llvmlite.build_store(builder, init_code_t, exception_code) + if else_bb is not None: + llvmlite.build_br(builder, else_bb) + else: + llvmlite.build_br(builder, after_bb) + + # ---- 5. DispatchBB:编码检查链 ---- + llvmlite.position_at_end(builder, dispatch_bb) + if n_handlers_t == 0: + # 无 except(非法 try,防御):直接吞掉 + llvmlite.build_br(builder, unhandled_bb) + else: + eh_code_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i32_ty_t, exception_code) + next_check_t: llvmlite.BasicBlock | t.CPtr = None + for i_t in range(n_handlers_t): + hdr_t: ast.ExceptHandler | t.CPtr = (ast.ExceptHandler | t.CPtr)( + tr.handlers.get(i_t)) + match_bb_t: llvmlite.BasicBlock | t.CPtr = match_bbs.get(i_t) + if i_t > 0 and next_check_t is not None: + llvmlite.position_at_end(builder, next_check_t) + eh_code_val = llvmlite.build_load( + builder, i32_ty_t, exception_code) + if hdr_t is None or hdr_t.type is None: + # 裸 except:无条件匹配 + llvmlite.build_br(builder, match_bb_t) + else: + # 展开匹配编码集(handler.type 自身 + 全部子孙异常类) + hname_t: str = None + htype_t: ast.AST | t.CPtr = hdr_t.type + if htype_t.kind() == ast.ASTKind.Name: + hname_t = ((ast.Name | t.CPtr)(htype_t)).id + elif htype_t.kind() == ast.ASTKind.Attribute: + hname_t = ((ast.Attribute | t.CPtr)(htype_t)).attr + # 匹配编码缓冲:必须是 t.CInt*(i32 步长)——collect_descendant_codes + # 按 out_codes[i](4 字节)写入;若用 t.CSizeT*(8 字节)读, + # 多码时读出 (code[i+1]<<32)|code[i] 的 64 位拼接垃圾(单码时 + # 高位恰为 0 掩盖;Test 2/3/8 父类多码捕获失败的根因)。 + codes_buf_t: t.CInt | t.CPtr = pool.alloc(64 * 4) + if codes_buf_t is None: + return 0 + n_codes_t: int = 0 + if hname_t is not None and self.Gen.ClassGenBase.is_exception_name(hname_t) != 0: + n_codes_t = self.Gen.ClassGenBase.collect_descendant_codes( + hname_t, codes_buf_t, 64) + else: + c0_t: int = 1 + if hname_t is not None: + c0_t = self.Gen.ClassGenBase.lookup_exception_code(hname_t) + if c0_t == 0: + c0_t = 1 + codes_buf_t[0] = c0_t + n_codes_t = 1 + match_cond_t: llvmlite.Value | t.CPtr = None + for ci_t in range(n_codes_t): + code_val_t: llvmlite.Value | t.CPtr = llvmlite.const_int32( + pool, codes_buf_t[ci_t]) + is_match_t: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_EQ, eh_code_val, code_val_t) + if match_cond_t is None: + match_cond_t = is_match_t + elif is_match_t is not None: + match_cond_t = llvmlite.build_or( + builder, match_cond_t, is_match_t) + if i_t < n_handlers_t - 1: + viperlib.snprintf(bb_buf_t, 64, "try.check.%d.%d", lc_t, i_t) + next_check_t = llvmlite.create_block(pool, func, bb_buf_t) + else: + next_check_t = unhandled_bb + llvmlite.build_cond_br( + builder, match_cond_t, match_bb_t, next_check_t) + # MatchBB:绑定 handler 变量(e = 消息指针),跳 ExceptBB + llvmlite.position_at_end(builder, match_bb_t) + if hdr_t is not None and hdr_t.name is not None and hdr_t.name[0] != '\0': + # 同名 handler 变量复用函数入口 alloca(find_var 首条命中、 + # 重复 define_var 不 shadow——多 try 共用 `as e` 时各 MatchBB + # 各自 store 消息,各 ExceptBB 读同一入口 alloca,避免 + # 非支配 alloca 触发 "does not dominate all uses")。 + h_ent_t: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, hdr_t.name) + if h_ent_t is not None and h_ent_t.Alloca is not None: + h_alloca_t: llvmlite.Value | t.CPtr = h_ent_t.Alloca + else: + h_alloca_t = self.Gen.VarGen._alloca_at_entry(builder, i8_ptr_ty_t) + if h_alloca_t is not None: + self.Gen.VarGen.define_var(trans.SymTab, hdr_t.name, h_alloca_t) + if h_alloca_t is not None: + h_msg_t: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i8_ptr_ty_t, eh_message) + if h_msg_t is not None: + llvmlite.build_store(builder, h_msg_t, h_alloca_t) + except_bb_t: llvmlite.BasicBlock | t.CPtr = except_bbs.get(i_t) + llvmlite.build_br(builder, except_bb_t) + + # ---- 6. UnhandledBB:无 except 匹配 → 向上传播或吞掉 ---- + llvmlite.position_at_end(builder, unhandled_bb) + if trans._cur_func_has_eh != 0 and trans._eh_msg_out_param is not None \ + and trans._eh_code_out_param is not None: + un_msg_t: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i8_ptr_ty_t, eh_message) + un_code_t: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i32_ty_t, exception_code) + if un_msg_t is not None: + llvmlite.build_store(builder, un_msg_t, trans._eh_msg_out_param) + if un_code_t is not None: + llvmlite.build_store(builder, un_code_t, trans._eh_code_out_param) + self._eh_ret_default(trans, pool, builder) + else: + if init_code_t is not None: + llvmlite.build_store(builder, init_code_t, exception_code) + llvmlite.build_br(builder, after_bb) + + # ---- 7. Except 体 ---- + for i_t in range(n_handlers_t): + hdr2_t: ast.ExceptHandler | t.CPtr = (ast.ExceptHandler | t.CPtr)( + tr.handlers.get(i_t)) + except_bb2_t: llvmlite.BasicBlock | t.CPtr = except_bbs.get(i_t) + llvmlite.position_at_end(builder, except_bb2_t) + if hdr2_t is not None and hdr2_t.children is not None: + hn2_t: t.CSizeT = len(hdr2_t.children) + for hi2 in range(hn2_t): + stmt2_t: ast.AST | t.CPtr = hdr2_t.children.get(hi2) + if stmt2_t is not None: + self.translate_stmt(trans, stmt2_t) + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, after_bb) + + # ---- 8. Else 体 ---- + if else_bb is not None: + llvmlite.position_at_end(builder, else_bb) + if tr.orelse is not None: + en_t: t.CSizeT = len(tr.orelse) + for ei in range(en_t): + stmt3_t: ast.AST | t.CPtr = tr.orelse.get(ei) + if stmt3_t is not None: + self.translate_stmt(trans, stmt3_t) + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, after_bb) + + # ---- 9. AfterBB + 恢复外层 try 上下文 ---- + llvmlite.position_at_end(builder, after_bb) + trans._eh_dispatch_bb = old_dispatch_t + trans._eh_code_ptr = old_code_t + trans._eh_msg_ptr = old_msg_t + return 0 + + def translate_raise(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 raise 语句,返回 0 + + 对齐 TPC HandlesRaise.py 的 try-except 语义(v1 迁移): + - StopIteration:置 __stop_iter_flag__ = 1 后返回默认值(迭代结束协议) + - 非 StopIteration: + 1. 处于 try(trans._eh_dispatch_bb 非空):异常编码/消息写入当前 + try 的 eh_code/eh_message alloca,分支到 DispatchBB 由 except 链裁决 + 2. 函数有 EH 输出参数(_cur_func_has_eh):编码/消息写入 + __eh_code_out__/__eh_msg_out__,返回默认值(异常向调用方传播) + 3. 两者皆无:仅返回默认值(v1 语义:异常被吞掉) + """ + if trans is None or node is None: + return 0 + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + if pool is None or builder is None or mod is None: + return 0 + rn: ast.Raise | t.CPtr = (ast.Raise | t.CPtr)(node) + if rn is None or rn.exc is None: + # bare raise(无 exc):v1 无活动异常可再抛,仅返回默认值 + self._eh_ret_default(trans, pool, builder) + return 0 + + # OOP iter 协议:raise StopIteration → 置 __stop_iter_flag__ = 1 + # (对齐 TPC HandlesRaise.py L76-100),随后按迭代结束返回默认值。 + ek: int = rn.exc.kind() + is_stop_iter: int = 0 + if ek == ast.ASTKind.Name: + enm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rn.exc) + if enm.id is not None and string.strcmp(enm.id, "StopIteration") == 0: + is_stop_iter = 1 + elif ek == ast.ASTKind.Call: + ecl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(rn.exc) + if ecl.func is not None and ecl.func.kind() == ast.ASTKind.Name: + ecn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ecl.func) + if ecn.id is not None and string.strcmp(ecn.id, "StopIteration") == 0: + is_stop_iter = 1 + if is_stop_iter != 0: + if trans._stop_iter_flag_ptr is not None: + i1_ty_r: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + if i1_ty_r is not None: + one_i1_r: llvmlite.Value | t.CPtr = llvmlite.ConstInt( + pool, i1_ty_r, 1, "1") + if one_i1_r is not None: + llvmlite.build_store( + builder, one_i1_r, trans._stop_iter_flag_ptr) + self._eh_ret_default(trans, pool, builder) + return 0 + + # ---- 非 StopIteration:计算异常编码与消息 ---- + exc_code: int = 1 + exc_msg: llvmlite.Value | t.CPtr = None + if ek == ast.ASTKind.Constant: + cst_r: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(rn.exc) + if cst_r is not None and cst_r.const_kind == ast.CONST_INT: + exc_code = cst_r.int_val + elif ek == ast.ASTKind.Name: + enm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rn.exc) + if enm2.id is not None: + exc_code = self.Gen.ClassGenBase.lookup_exception_code(enm2.id) + if exc_code == 0: + exc_code = 1 + elif ek == ast.ASTKind.Call: + ecl2: ast.Call | t.CPtr = (ast.Call | t.CPtr)(rn.exc) + if ecl2.func is not None and ecl2.func.kind() == ast.ASTKind.Name: + ecn2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ecl2.func) + if ecn2.id is not None: + exc_code = self.Gen.ClassGenBase.lookup_exception_code(ecn2.id) + if exc_code == 0: + exc_code = 1 + if ecl2.args is not None and len(ecl2.args) > 0: + exc_msg = self.Gen.ExprGen.translate_value( + builder, pool, mod, ecl2.args.get(0), None, 0, trans) + + # ---- 异常分发 ---- + # 1. try 内:写入 try 的 eh_code/eh_message alloca,分支 DispatchBB + if trans._eh_dispatch_bb is not None and trans._eh_code_ptr is not None: + code_val_r: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, exc_code) + if code_val_r is not None: + llvmlite.build_store(builder, code_val_r, trans._eh_code_ptr) + if exc_msg is None: + exc_msg = llvmlite.ConstNull( + pool, llvmlite.Ptr(pool, llvmlite.Int8(pool)), "null") + if exc_msg is not None and trans._eh_msg_ptr is not None: + llvmlite.build_store(builder, exc_msg, trans._eh_msg_ptr) + llvmlite.build_br(builder, trans._eh_dispatch_bb) + return 0 + # 2. 函数有 EH 输出参数:写入 out 参数(异常向调用方传播) + if trans._cur_func_has_eh != 0 and trans._eh_msg_out_param is not None \ + and trans._eh_code_out_param is not None: + code_val_r2: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, exc_code) + if code_val_r2 is not None: + llvmlite.build_store(builder, code_val_r2, trans._eh_code_out_param) + if exc_msg is None: + exc_msg = llvmlite.ConstNull( + pool, llvmlite.Ptr(pool, llvmlite.Int8(pool)), "null") + if exc_msg is not None: + llvmlite.build_store(builder, exc_msg, trans._eh_msg_out_param) + self._eh_ret_default(trans, pool, builder) + return 0 + # 3. 无 try 无 EH 参数:仅返回默认值 + self._eh_ret_default(trans, pool, builder) + return 0 + + # ============================================================ + # _eh_ret_default - 异常路径返回当前函数的默认零值 + # + # 对齐 TPC HandlesTry.py UnhandledBB / HandlesRaise.py 的返回生成 + # (void→ret_void,ptr→null,float→0.0,其余→零值)。当前块已 + # 终结(前一条是 raise/return)时跳过,避免在终止块后插指令。 + # ============================================================ + def _eh_ret_default(self, trans: HT.Translator | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr) -> int: + """异常路径返回当前函数默认零值,返回 0""" + if trans is None or builder is None: + return 0 + if llvmlite.builder_cur_block_is_terminated(builder) != 0: + return 0 + cur_func: llvmlite.Function | t.CPtr = trans._cur_func + if cur_func is None: + return 0 + ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(cur_func) + if ret_ty is None: + return 0 + match ret_ty: + case llvmlite.LLVMType.Void(): + llvmlite.build_ret_void(builder) + case llvmlite.LLVMType.Ptr(_pe): + null_v: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, ret_ty, "null") + if null_v is not None: + llvmlite.build_ret(builder, null_v) + case llvmlite.LLVMType.Float(_fb): + zero_f: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, ret_ty, 0.0) + if zero_f is not None: + llvmlite.build_ret(builder, zero_f) + case _: + zero_v: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, ret_ty) + if zero_v is not None: + llvmlite.build_ret(builder, zero_v) + return 0 + + # ============================================================ + # translate_with - with 语句翻译 + # + # with expr() as x: body + # → 1. 构造 context 对象(expr() 调用) + # 2. 调用 __enter__()(沿继承链 MRO 解析,如 MemPool → MemManager) + # 3. x 绑定 __enter__ 返回值(缺失时退回 context 对象) + # 4. 翻译 body + # 5. 逆序调用 __exit__()(无异常传播,__exit__ 仅做清理如 reset) + # + # 实现:context 对象存入临时变量 __with_ctx,方法调用复用 + # translate_call 的 Attribute 分派 + _translate_method_call 的 MRO 回退 + # (与普通 obj.method() 调用一致)。嵌套 with 时保存外层 __with_ctx, + # 退出后恢复,避免内层覆盖导致外层 __exit__ 解析到错误对象。 + # 对齐 TPC HandlesWith 语义(不含 __provides__ provider 机制)。 + # ============================================================ + def translate_with(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 with 语句,返回 0""" + if trans is None or node is None: + return 0 + wt: ast.With | t.CPtr = (ast.With | t.CPtr)(node) + if wt is None: + return 0 + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + if pool is None or builder is None or mod is None: + return 0 + items: list[ast.AST | t.CPtr] | t.CPtr = wt.items + if items is None: + return 0 + n: t.CSizeT = len(items) + + # 保存外层 __with_ctx(嵌套 with 时退出后恢复) + old_ctx_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, "__with_ctx") + + # 记录每个 item 的类名(__exit__ 调用时设置 __with_ctx 类型用) + ctx_class_buf: t.CSizeT | t.CPtr = pool.alloc(8 * n) + if ctx_class_buf is None: + return 0 + string.memset(ctx_class_buf, 0, 8 * n) + + # 1. 全部 item:构造 context 对象 + 调用 __enter__ + asname 绑定 + for i in range(n): + item_node: ast.AST | t.CPtr = items.get(i) + if item_node is None: + continue + if item_node.kind() != ast.ASTKind.WithItem: + continue + item: ast.WithItem | t.CPtr = (ast.WithItem | t.CPtr)(item_node) + if item is None or item.context_expr is None: + continue + # 翻译 context_expr(对象构造,如 MemPool(arena, 4096)) + ctx_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, item.context_expr, + trans._funcs, trans._func_count, trans) + if ctx_val is None: + continue + # 提取类名(注解类名,Attribute 时带模块前缀,如 "memhub.MemPool"—— + # 与 AnnAssign 的 extract_class_name_from_annotation 一致,跨模块 + # 方法调用靠 AnnotClassName 回退按模块名查 SHA1) + cls_name: str = None + ce: ast.AST | t.CPtr = item.context_expr + if ce.kind() == ast.ASTKind.Call: + cfn: ast.AST | t.CPtr = ((ast.Call | t.CPtr)(ce)).func + if cfn is not None: + if cfn.kind() == ast.ASTKind.Attribute: + ca: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cfn) + if ca.value is not None and ca.value.kind() == ast.ASTKind.Name: + cmn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ca.value) + if cmn.id is not None: + ml2: t.CSizeT = string.strlen(cmn.id) + string.strlen(ca.attr) + 2 + mbuf: str = pool.alloc(ml2) + if mbuf is not None: + viperlib.snprintf(mbuf, ml2, "%s.%s", cmn.id, ca.attr) + cls_name = mbuf + if cls_name is None: + cls_name = ca.attr + elif cfn.kind() == ast.ASTKind.Name: + cls_name = ((ast.Name | t.CPtr)(cfn)).id + # context 对象存入 __with_ctx(方法调用解析 self 用) + ctx_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca( + builder, ctx_val.Ty) + if ctx_alloca is None: + continue + llvmlite.build_store(builder, ctx_val, ctx_alloca) + self.Gen.VarGen.define_var(trans.SymTab, "__with_ctx", ctx_alloca) + if cls_name is not None: + self.Gen.VarGen.set_var_annot_class_name( + trans.SymTab, "__with_ctx", cls_name) + ctx_class_buf[i] = t.CSizeT(cls_name) + # 调用 __enter__() + enter_val: llvmlite.Value | t.CPtr = self._with_ctx_call( + trans, pool, builder, mod, "__enter__") + # asname 绑定(__enter__ 返回值,缺失时退回 context 对象) + if item.optional_vars is not None: + ov: ast.AST | t.CPtr = item.optional_vars + if ov.kind() == ast.ASTKind.Name: + asname: str = ((ast.Name | t.CPtr)(ov)).id + if asname is not None: + bind_val: llvmlite.Value | t.CPtr = enter_val + if bind_val is None: + bind_val = ctx_val + if bind_val is not None: + asn_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca( + builder, bind_val.Ty) + if asn_alloca is not None: + llvmlite.build_store(builder, bind_val, asn_alloca) + self.Gen.VarGen.define_var(trans.SymTab, asname, asn_alloca) + if cls_name is not None: + self.Gen.VarGen.set_var_annot_class_name( + trans.SymTab, asname, cls_name) + # FakeDuck: __provides__ 元数据 → 生成 _push_provider 调用 + # (对齐 TPC HandlesWith.py L138-159;经 gen 单例委托 CallGenMixin。 + # 类名去模块前缀后查 __provides__ 表,如 memhub.MemBuddy → MemBuddy) + fd_cls_bare: str = cls_name + if cls_name is not None: + fd_dot: str = string.strrchr(cls_name, '.') + if fd_dot is not None: + fd_cls_bare = fd_dot + 1 + if fd_cls_bare is not None: + self.Gen.CallGenFd._emit_provider_push( + trans, pool, builder, mod, fd_cls_bare, ctx_val) + + # 2. 翻译 body + body: list[ast.AST | t.CPtr] | t.CPtr = wt.children + if body is not None: + bn: t.CSizeT = len(body) + for bi in range(bn): + st: ast.AST | t.CPtr = body.get(bi) + if st is not None: + self.translate_stmt(trans, st) + + # 2.5 FakeDuck: __provides__ 元数据 → 生成 _pop_provider 调用 + # (对齐 TPC HandlesWith.py L167-174;逆序弹栈,经 gen 单例委托) + for pi_pop in range(n): + if ctx_class_buf[pi_pop] != 0: + cls_pop: str = (str | t.CPtr)(t.CVoid(ctx_class_buf[pi_pop], t.CPtr)) + fd_cls_bare_p: str = cls_pop + if cls_pop is not None: + fd_dot_p: str = string.strrchr(cls_pop, '.') + if fd_dot_p is not None: + fd_cls_bare_p = fd_dot_p + 1 + if fd_cls_bare_p is not None: + self.Gen.CallGenFd._emit_provider_pop( + trans, pool, builder, mod, fd_cls_bare_p) + + # 3. 逆序调用 __exit__()(Python with 语义:后进先出) + for i in range(n): + ci: int = n - 1 - i + if ctx_class_buf[ci] != 0: + cls_ci: str = (str | t.CPtr)(t.CVoid(ctx_class_buf[ci], t.CPtr)) + self.Gen.VarGen.set_var_annot_class_name( + trans.SymTab, "__with_ctx", cls_ci) + self._with_ctx_call(trans, pool, builder, mod, "__exit__") + + # 4. 恢复外层 __with_ctx + if old_ctx_alloca is not None: + self.Gen.VarGen.define_var(trans.SymTab, "__with_ctx", old_ctx_alloca) + return 0 + + def _with_ctx_call(self, trans: HT.Translator | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + method_name: str) -> llvmlite.Value | t.CPtr: + """构造并翻译 __with_ctx.() 调用(__enter__/__exit__)""" + if pool is None or method_name is None: + return None + name_node: ast.AST | t.CPtr = ast.Name(pool, "__with_ctx", ast.ASTCtx.Load) + if name_node is None: + return None + attr_node: ast.AST | t.CPtr = ast.Attribute( + pool, name_node, method_name, ast.ASTCtx.Load) + if attr_node is None: + return None + call_node: ast.AST | t.CPtr = ast.Call(pool, attr_node, None, None) + if call_node is None: + return None + return self.Gen.ExprGen.translate_value( + builder, pool, mod, call_node, + trans._funcs, trans._func_count, trans) diff --git a/App/lib/core/Gen/StructGenMixin.vp b/App/lib/core/Gen/StructGenMixin.vp index f542f26..f05a402 100644 --- a/App/lib/core/Gen/StructGenMixin.vp +++ b/App/lib/core/Gen/StructGenMixin.vp @@ -1,1339 +1,1341 @@ -import t, c -from stdint import * -import memhub -import string -import stdlib -import llvmlite -import stdio -import ast -import hashtable -import viperlib -import lib.core.CompilerFactory as CompilerFactory -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesStruct as HandlesStruct - - -# ============================================================ -# StructGenMixin - 结构体注册/字段查找 Mixin(对象化 P2-2,wiki/14-oo-refactor.md) -# -# 从 HandlesStruct.vp 迁移: -# 全局状态(_struct_table/_struct_count/_g_stdlib_alloc/ -# _visible_structs/_strict_visibility)→ 本类字段 -# 模块级函数(register_struct/find_struct/lookup_field/...)→ 本类方法 -# -# 迁移原则(与 TypeGenMixin P2-1 一致,行为零变化): -# 1. 方法保留原函数签名(含 pool 首参),仅函数体内的全局变量改为 self.字段 -# 2. HandlesStruct.vp 原函数保留为"委托":本地模块级单例 _g_gen(BuildPipeline -# /main 注入)cast 成 Generator 类型后调本类方法 -# 3. FieldEntry/StructEntry 类型保留在 HandlesStruct.vp(本类字段引用) -# -# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整,无 vtable 开销)。 -# ============================================================ - - -# ============================================================ -# 常量(与 HandlesStruct 保持一致) -# ============================================================ -STRUCT_MAX: t.CDefine = 512 -# 字段槽位上限制(与 HandlesStruct 保持一致;Generator 43 Mixin 展平 ~120 字段, -# 2026-08-16 追加78:64 截断导致第 9+ 父类字段(StmtGenMixin.DiagStmtCount 等) -# 丢失 → __init__ 写 self.DiagStmtCount "属性写入失败") -FIELD_MAX: t.CDefine = 256 -FIELD_NAME_MAX: t.CDefine = 64 -# 多继承(MRO)支持:单类最大父类数 / MRO 链最大长度(Generator 43 父类; -# PARENT_MAX=16 时第 17+ 父类字段丢失 → __init__ 写 self.DiagStmtCount 失败) -PARENT_MAX: t.CDefine = 64 -MRO_MAX: t.CDefine = 64 - - -# ============================================================ -# StructGenMixin - 结构体注册表/字段查找/可见性 -# ============================================================ -@t.NoVTable -class StructGenMixin: - """结构体注册与查找 Mixin(状态从 HandlesStruct 全局变量迁入)""" - - # --- 全局注册表(原 _struct_table/_struct_count) --- - StructTable: HandlesStruct.StructEntry | t.CPtr # STRUCT_MAX 槽位数组 - StructCount: int - - # --- OOM 回收分配模式(原 _g_stdlib_alloc) --- - StdlibAlloc: int - - # --- 跨模块命名空间隔离(原 _visible_structs/_strict_visibility) --- - VisibleStructs: hashtable.HashTable | t.CPtr - StrictVisibility: int - - def InitStructGen(self) -> int: - """初始化结构体 Mixin 字段(子类构造时内联调用,规避 NoVTable 继承符号不转发)""" - if self is None: - return 1 - self.StructTable = None - self.StructCount = 0 - self.StdlibAlloc = 0 - self.VisibleStructs = None - self.StrictVisibility = 0 - return 0 - - # ============================================================ - # P2-2 迁移方法(函数体来自 HandlesStruct.vp,全局变量改 self.字段, - # 同模块函数调用改 self.方法;签名与 HandlesStruct 原函数一致) - # ============================================================ - - def set_stdlib_alloc(self, flag: int): - """设置 OOM 回收分配模式:1=1b 阶段(新条目用 stdlib),0=注册阶段(用 pool)""" - self.StdlibAlloc = flag - - def get_stdlib_alloc(self) -> int: - """读取 OOM 回收分配模式(供其他 Mixin 经 HandlesStruct 委托访问, - 避免跨 Mixin 直接读 self.StdlibAlloc——Mixin 方法体按自身块内索引编译)""" - return self.StdlibAlloc - - def reset_visible_structs(self, pool: memhub.MemBuddy | t.CPtr, strict: int): - """重置可见性状态(每个文件翻译前调用) - - pool: 内存分配器(严格模式下创建 HashTable) - strict: 1=严格模式(用户文件),0=宽松模式(includes 文件) - """ - self.StrictVisibility = strict - if strict != 0: - # 严格模式:创建新的 HashTable 记录可见结构体 - self.VisibleStructs = hashtable.HashTable(pool) - else: - # 宽松模式:全部可见,不需要 HashTable - self.VisibleStructs = None - - def add_visible_struct(self, pool: memhub.MemBuddy | t.CPtr, name: str): - """添加可见结构体名(类定义时和 from-import 时调用)""" - if name is None: - return - # 宽松模式:全部可见,无需记录 - if self.StrictVisibility == 0: - return - if self.VisibleStructs is None: - return - # 已存在则跳过(HashTable.__setitem__ 会覆盖,此处提前检查避免重复分配) - if self.VisibleStructs.__contains__(name) != 0: - return - self.VisibleStructs.set_int(name, 1) - - def is_struct_visible(self, name: str) -> int: - """检查结构体是否可见,返回 1=可见 / 0=不可见""" - if self.StrictVisibility == 0: - return 1 - if name is None or self.VisibleStructs is None: - return 0 - return self.VisibleStructs.__contains__(name) - - def init_struct_table(self, pool: memhub.MemBuddy | t.CPtr) -> int: - """初始化结构体注册表,返回 1 成功 - - StdlibAlloc=1 时表体分配在 perm_pool:1a 每文件 reset 后表本体 - 不被回收(否则首次 register_struct 若发生在文件级 mark 之后, - reset 会把 StructTable 连根回收,全局 find_struct 悬空)。 - """ - if self.StructTable is not None: - return 1 - - entry_size: t.CSizeT = HandlesStruct.StructEntry.__sizeof__() - table_pool: memhub.MemBuddy | t.CPtr = pool - if self.StdlibAlloc != 0: - table_pool = CompilerFactory.get_perm_pool() - if table_pool is None: - table_pool = pool - self.StructTable = table_pool.alloc(entry_size * STRUCT_MAX) - if self.StructTable is None: - return 0 - string.memset(self.StructTable, 0, entry_size * STRUCT_MAX) - self.StructCount = 0 - return 1 - - def _get_struct_entry(self, i: int) -> HandlesStruct.StructEntry | t.CPtr: - """获取第 i 个结构体条目""" - if self.StructTable is None or i < 0 or i >= STRUCT_MAX: - return None - entry_size: t.CSizeT = HandlesStruct.StructEntry.__sizeof__() - addr: t.CUInt64T = t.CUInt64T(self.StructTable) + i * entry_size - return (HandlesStruct.StructEntry | t.CPtr)(t.CVoid(addr, t.CPtr)) - - def _get_field_entry(self, struct_entry: HandlesStruct.StructEntry | t.CPtr, i: int) -> HandlesStruct.FieldEntry | t.CPtr: - """获取结构体中第 i 个字段条目""" - if struct_entry is None or i < 0 or i >= FIELD_MAX: - return None - field_size: t.CSizeT = HandlesStruct.FieldEntry.__sizeof__() - addr: t.CUInt64T = t.CUInt64T(struct_entry.Fields) + i * field_size - return (HandlesStruct.FieldEntry | t.CPtr)(t.CVoid(addr, t.CPtr)) - - def register_struct(self, pool: memhub.MemBuddy | t.CPtr, - name: str, - struct_ty: llvmlite.LLVMType | t.CPtr, - sha1: str = None) -> HandlesStruct.StructEntry | t.CPtr: - """注册结构体类型,返回 StructEntry 指针 - - 用类型指针去重(is 比较),不用类名去重。 - 这样跨模块同名类可以共存,各自有独立的字段定义。 - sha1 参数在注册时直接设置 ModuleSha1(避免 set_struct_sha1 找错 entry)。 - """ - if self.init_struct_table(pool) == 0: - return None - - # 用类型指针去重(同一类型不重复注册,支持跨模块同名类) - # 用 t.CUInt64T 指针值比较(is 比较会触发类型安全检查解引用悬空 Ty) - st_dedup: t.CUInt64T = t.CUInt64T(struct_ty) - for i in range(self.StructCount): - existing: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i) - if existing is not None and existing.Ty is not None: - if t.CUInt64T(existing.Ty) == st_dedup: - return existing - - if self.StructCount >= STRUCT_MAX: - fb_st: str = VLogger.fmt_buf() - if fb_st is not None: - viperlib.snprintf(fb_st, 1024, "table full, cannot register %s", name) - VLogger.error(fb_st, "STRUCT") - return None - - entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(self.StructCount) - if entry is None: - return None - - # 分配字段数组(1b 阶段用永久池,避免 reset 回收后 Fields 悬空) - field_size: t.CSizeT = HandlesStruct.FieldEntry.__sizeof__() - if self.StdlibAlloc != 0: - perm_sg: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool() - if perm_sg is None: - perm_sg = pool - entry.Fields = perm_sg.alloc(field_size * FIELD_MAX) - else: - entry.Fields = pool.alloc(field_size * FIELD_MAX) - if entry.Fields is None: - return None - string.memset(entry.Fields, 0, field_size * FIELD_MAX) - - # 复制类名(1b/Phase2(StdlibAlloc=1)用永久池跨 reset 存活; - # 1a(StdlibAlloc=0)用主 pool,mark1 前不回收同样存活。 - # 此前 1a 用 pool、1b 用 stdlib,find_struct_by_module 的 strcmp - # 曾读悬空 Name 越界 → G3 LinkedNode.prepend 挂起根因) - name_pool: memhub.MemBuddy | t.CPtr = pool - if self.StdlibAlloc != 0: - name_pool = CompilerFactory.get_perm_pool() - if name_pool is None: - name_pool = pool - name_len: t.CSizeT = string.strlen(name) - name_buf: str = name_pool.alloc(name_len + 1) - if name_buf is not None: - string.strcpy(name_buf, name) - entry.Name = name_buf - - entry.Ty = struct_ty - entry.FieldCount = 0 - - # 注册时直接设置 SHA1(避免 set_struct_sha1 跨模块同名时找错 entry) - # SHA1 同样按 StdlibAlloc 选分配源(跨 1a/1b 存活,防 strcmp 悬空) - if sha1 is not None: - sha1_len: t.CSizeT = string.strlen(sha1) - sha1_buf: str = name_pool.alloc(sha1_len + 1) - if sha1_buf is not None: - string.strcpy(sha1_buf, sha1) - entry.ModuleSha1 = sha1_buf - - self.StructCount += 1 - return entry - - def set_struct_sha1(self, pool: memhub.MemBuddy | t.CPtr, - class_name: str, sha1: str) -> int: - """设置结构体所属模块的 SHA1,返回 1=成功 / 0=失败""" - if class_name is None or sha1 is None: - return 0 - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(class_name) - if entry is None: - return 0 - # 复制 SHA1 字符串(StdlibAlloc=1 用永久池,跨 1a/1b 存活防 strcmp 悬空) - sha1_len: t.CSizeT = string.strlen(sha1) - sha1_pool: memhub.MemBuddy | t.CPtr = pool - if self.StdlibAlloc != 0: - sha1_pool = CompilerFactory.get_perm_pool() - if sha1_pool is None: - sha1_pool = pool - sha1_buf: str = sha1_pool.alloc(sha1_len + 1) - if sha1_buf is None: - return 0 - string.strcpy(sha1_buf, sha1) - entry.ModuleSha1 = sha1_buf - return 1 - - def get_struct_sha1(self, class_name: str) -> str: - """获取结构体所属模块的 SHA1,返回 None=无 SHA1""" - if class_name is None or self.StructTable is None: - return None - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(class_name) - if entry is None: - return None - return entry.ModuleSha1 - - def add_field(self, pool: memhub.MemBuddy | t.CPtr, - struct_entry: HandlesStruct.StructEntry | t.CPtr, - field_name: str, - field_ty: llvmlite.LLVMType | t.CPtr, - default_val: ast.AST | t.CPtr = None, - annot_class_name: str = None) -> int: - """向结构体添加字段,返回字段索引(-1 失败) - - default_val: 字段默认值 AST 节点(可选,None=无默认值) - annot_class_name: 原始类型注解的类名(可选,用于联合类型字段的方法调用解析) - """ - if struct_entry is None or field_name is None or field_ty is None: - return -1 - - if struct_entry.FieldCount >= FIELD_MAX: - fb_sf: str = VLogger.fmt_buf() - if fb_sf is not None: - viperlib.snprintf(fb_sf, 1024, "field table full for %s", struct_entry.Name) - VLogger.error(fb_sf, "STRUCT") - return -1 - - idx: int = struct_entry.FieldCount - fe: HandlesStruct.FieldEntry | t.CPtr = self._get_field_entry(struct_entry, idx) - if fe is None: - return -1 - - # 复制字段名(StdlibAlloc=1 用永久池跨 reset 存活, - # 否则 lookup_field 的 strcmp(fe.Name, ...) 读悬空越界挂起, - # 与 register_struct 的 Name 悬空同根因) - fname_pool: memhub.MemBuddy | t.CPtr = pool - if self.StdlibAlloc != 0: - fname_pool = CompilerFactory.get_perm_pool() - if fname_pool is None: - fname_pool = pool - name_len: t.CSizeT = string.strlen(field_name) - name_buf: str = fname_pool.alloc(name_len + 1) - if name_buf is not None: - string.strcpy(name_buf, field_name) - fe.Name = name_buf - - fe.Index = idx - # 1b 阶段(StdlibAlloc=1)字段类型/注解类名必须深拷贝到 stdlib: - # register_struct 已迁 Fields/Name/ModuleSha1/Ty(translate_class_def L2566 - # DeepCopyType),但字段级 Ty/AnnotClassName 仍存 pool 指针,本文件 - # reset_to(mark1) 回收后,跨文件读取(字段展平、多继承 this 调整、 - # AnnotClassName 回退、_apply_struct_defaults 的 build_gep_struct 用 fe.Ty - # 作 GEP 结果类型)解引用悬空内存 → 崩溃点漂移(json/string/builtins 之间)。 - if self.StdlibAlloc != 0: - dp_pool_sg: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool() - if dp_pool_sg is None: - dp_pool_sg = pool - ty_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(dp_pool_sg, field_ty) - if ty_copy is not None: - fe.Ty = ty_copy - else: - fe.Ty = field_ty - if annot_class_name is not None: - annot_len: t.CSizeT = string.strlen(annot_class_name) - annot_buf: str = CompilerFactory.get_perm_pool().alloc(annot_len + 1) - if annot_buf is not None: - string.strcpy(annot_buf, annot_class_name) - fe.AnnotClassName = annot_buf - # DefaultVal:跨文件结构体构造(_translate_struct_ctor→_apply_struct_defaults) - # 在调用方文件翻译时读取字段默认值,原 pool AST 已 reset 回收 → 常量深拷贝 - # 到 perm_pool(1a 每文件 reset 后 DefaultVal 同样必须跨文件存活) - fe.DefaultVal = self._deep_copy_default_ast(dp_pool_sg, default_val) - else: - fe.Ty = field_ty - fe.AnnotClassName = annot_class_name - fe.DefaultVal = default_val - - struct_entry.FieldCount = idx + 1 - return idx - - def _deep_copy_default_ast(self, pool: memhub.MemBuddy | t.CPtr, - default_val: ast.AST | t.CPtr) -> ast.AST | t.CPtr: - """深拷贝字段默认值 AST 到永久池(仅常量节点),跨 1b reset 存活。 - - 字段默认值(fe.DefaultVal)除定义文件内 _generate_before_init 使用外, - 跨文件结构体构造(_translate_struct_ctor → _apply_struct_defaults)会在 - 调用方文件翻译时读取——原 pool AST 已 reset 回收必须深拷贝。 - 支持 Constant(标量)与 List(列表字面量,如 t.CArray[str] = ["py", "pyw"])。 - 其他非常量默认值(Name/BinOp 等引用表达式)无法安全深拷贝:返回 None - (调用方 fe.DefaultVal 保持 None,仅定义文件内 _generate_before_init - 仍持有原始 pool 指针,不受影响)。 - """ - if default_val is None: - return None - if default_val.kind() == ast.ASTKind.List: - return self._deep_copy_list_ast(pool, default_val) - if default_val.kind() != ast.ASTKind.Constant: - return None - src_c: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(default_val) - dst_c: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)( - pool.alloc(ast.Constant.__sizeof__())) - if dst_c is None: - return None - string.memset(dst_c, 0, ast.Constant.__sizeof__()) - # 拷贝 vtable 指针(AST 是 @t.CVTable,kind() 虚调用依赖首字段 vptr) - vt_ptr: t.CVoid | t.CPtr = t.CVoid( - c.Deref(t.CUInt64T(default_val, t.CPtr), t.CPtr), t.CPtr) - c.DerefAs(dst_c, vt_ptr) - # 拷贝位置字段(报错定位用) - dst_c.lineno = src_c.lineno - dst_c.col_offset = src_c.col_offset - dst_c.end_lineno = src_c.end_lineno - dst_c.end_col_offset = src_c.end_col_offset - # 拷贝常量值(int/float/str/bool 由 const_kind 区分) - dst_c.const_kind = src_c.const_kind - dst_c.int_val = src_c.int_val - dst_c.float_val = src_c.float_val - if src_c.str_val is not None: - s_len: t.CSizeT = string.strlen(src_c.str_val) - s_copy: str = pool.alloc(s_len + 1) - if s_copy is not None: - string.strcpy(s_copy, src_c.str_val) - dst_c.str_val = s_copy - return (ast.AST | t.CPtr)(dst_c) - - def _deep_copy_list_ast(self, pool: memhub.MemBuddy | t.CPtr, - default_val: ast.AST | t.CPtr) -> ast.AST | t.CPtr: - """深拷贝 List 节点(列表字面量默认值)到永久池,跨 1b reset 存活。 - - elts 容器手动在永久池构造(list 的 __pool__ 置 None:深拷贝的 elts - 只被只读访问 get/__len__/迭代,不 append,不会触发 pool 扩容)。 - 元素递归调用 _deep_copy_default_ast(支持 Constant 与嵌套 List)。 - """ - src_l: ast.List | t.CPtr = (ast.List | t.CPtr)(default_val) - dst_l: ast.List | t.CPtr = (ast.List | t.CPtr)( - pool.alloc(ast.List.__sizeof__())) - if dst_l is None: - return None - string.memset(dst_l, 0, ast.List.__sizeof__()) - # 拷贝 vtable 指针(AST 是 @t.CVTable,kind() 虚调用依赖首字段 vptr) - vt_l: t.CVoid | t.CPtr = t.CVoid( - c.Deref(t.CUInt64T(default_val, t.CPtr), t.CPtr), t.CPtr) - c.DerefAs(dst_l, vt_l) - # 拷贝位置字段与 ctx - dst_l.lineno = src_l.lineno - dst_l.col_offset = src_l.col_offset - dst_l.end_lineno = src_l.end_lineno - dst_l.end_col_offset = src_l.end_col_offset - dst_l.ctx = src_l.ctx - # 深拷贝 elts:stdlib 手动构造 list[AST | t.CPtr] 容器 - src_elts_l: list[ast.AST | t.CPtr] | t.CPtr = src_l.elts - if src_elts_l is not None: - cnt_l: t.CSizeT = len(src_elts_l) - lst_copy_l: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)( - pool.alloc(list[ast.AST | t.CPtr].__sizeof__())) - if lst_copy_l is not None: - string.memset(lst_copy_l, 0, list[ast.AST | t.CPtr].__sizeof__()) - lst_copy_l.__count__ = cnt_l - lst_copy_l.__capacity__ = cnt_l - lst_copy_l.__elem_size__ = 8 - lst_copy_l.__pool__ = None - data_l: t.CVoid | t.CPtr = pool.alloc(cnt_l * 8) - if data_l is not None: - string.memset(data_l, 0, cnt_l * 8) - lst_copy_l.__data__ = data_l - li_l: t.CSizeT - for li_l in range(cnt_l): - elem_src_l: ast.AST | t.CPtr = src_elts_l.get(li_l) - if elem_src_l is not None: - elem_dst_l: ast.AST | t.CPtr = self._deep_copy_default_ast(pool, elem_src_l) - if elem_dst_l is not None: - slot_l: ast.AST | t.CPtr = (ast.AST | t.CPtr)( - t.CVoid(t.CUInt64T(data_l) + li_l * 8, t.CPtr)) - slot_l[0] = elem_dst_l - dst_l.elts = lst_copy_l - return (ast.AST | t.CPtr)(dst_l) - - def get_struct_count(self) -> int: - """返回当前已注册的结构体数量""" - return self.StructCount - - def find_struct(self, name: str) -> HandlesStruct.StructEntry | t.CPtr: - """按类名查找结构体,返回 StructEntry 或 None - - 支持模块限定名(如 "HT.Translator"): - 第一遍精确匹配,第二遍按类名(最后一个 '.' 之后的部分)回退 - """ - if name is None or self.StructTable is None: - return None - # 第一遍:精确匹配 - # StructCount 合理性守卫(内存损坏导致巨大值 → 索引循环假挂起) - if self.StructCount < 0 or self.StructCount > 200000: - VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct)", "STRUCT") - stdlib.exit(1) - for i in range(self.StructCount): - entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i) - if entry is not None and entry.Name is not None: - if string.strcmp(entry.Name, name) == 0: - return entry - # 第二遍:类名回退(处理模块限定名 "HT.Translator" → "Translator") - dot_pos: str = string.strrchr(name, '.') - if dot_pos is not None: - class_name: str = dot_pos + 1 - if class_name is not None and class_name[0] != '\0': - for i in range(self.StructCount): - entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i) - if entry is not None and entry.Name is not None: - if string.strcmp(entry.Name, class_name) == 0: - return entry - return None - - def find_struct_by_module(self, name: str, sha1: str) -> HandlesStruct.StructEntry | t.CPtr: - """按类名 + SHA1 查找结构体,返回 StructEntry 或 None - - SHA1 非 None 时:精确匹配 name+sha1,未找到返回 None(不回退,避免跨模块同名找错) - SHA1 为 None 时:回退到 find_struct(name) 按类名查找第一个 - """ - if name is None or self.StructTable is None: - return None - # StructCount 合理性守卫(内存损坏导致巨大值 → 索引循环假挂起) - if self.StructCount < 0 or self.StructCount > 200000: - VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct_by_module)", "STRUCT") - stdlib.exit(1) - if sha1 is not None: - for i in range(self.StructCount): - entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i) - if entry is not None and entry.Name is not None: - if string.strcmp(entry.Name, name) == 0: - if entry.ModuleSha1 is not None: - if string.strcmp(entry.ModuleSha1, sha1) == 0: - return entry - # SHA1 查找失败:不回退到 find_struct(会返回跨模块同名错误 entry) - # 返回 None 让调用方创建新类型,避免 Phase B 用错误类型短路 - return None - # 无 SHA1:按类名查找第一个 - return self.find_struct(name) - - def reset_module_methods_emitted(self, sha1: str) -> int: - """回滚指定模块注册类的 MethodsEmitted 标志(Phase A 重试前调用) - - 根因(追加87):Phase A 第 1 遍翻译类方法体时 _translate_oop_methods - 先置 MethodsEmitted=1(防重入)再发射方法;方法体内跨模块调用因依赖 - text.ll 未生成触发 trans._deps_pending → 整文件不写盘下遍重译。但 - MethodsEmitted 存于 perm_pool 分配的 StructEntry,跨 mb.reset_to(mark2) - 存活 → 第 2 遍 existing 分支被 _translate_oop_methods 的 - MethodsEmitted==1 防重复检查拦截 → 类方法(含 __before_init__)永不 - 发射 → 链接 undefined symbol(模块级函数不受此标志保护所以正常, - AssignGenMixin text.ll 空 / HandlesTranslator 有模块函数缺类方法)。 - 按本文件 ModuleSha1 精确回滚,不影响其他已写盘文件的 MethodsEmitted。 - """ - if sha1 is None or self.StructTable is None: - return 0 - if self.StructCount < 0 or self.StructCount > 200000: - VLogger.error(f"StructCount 异常: {self.StructCount} (reset_module_methods_emitted)", "STRUCT") - return 0 - reset_count: int = 0 - for i in range(self.StructCount): - entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i) - if entry is not None: - # 普通类按 ModuleSha1 匹配 - if entry.ModuleSha1 is not None: - if string.strcmp(entry.ModuleSha1, sha1) == 0: - entry.MethodsEmitted = 0 - reset_count += 1 - continue - # 泛型特化类按触发文件 sha1 匹配:特化类 ModuleSha1 是模板 sha1 - # (方法名带模板前缀),无法匹配当前作废文件。不重置则特化方法体 - # 残留 MethodsEmitted=1,下遍不补译 → text.ll 只有 call 无 define - # → ld.lld undefined symbol(list[ast.ClassDef|t.CPtr].* 根因) - if entry.SpecTriggerSha1 is not None: - if string.strcmp(entry.SpecTriggerSha1, sha1) == 0: - entry.MethodsEmitted = 0 - reset_count += 1 - return reset_count - - def find_struct_by_type(self, struct_ty: llvmlite.LLVMType | t.CPtr) -> HandlesStruct.StructEntry | t.CPtr: - """按类型指针查找结构体(指针值比较),返回 StructEntry 或 None - - 注意: 不能用 `entry.Ty is struct_ty` 的 is 比较——TPV 编译 is 时会触发 - translate_compare 的类型安全检查(is_ptr_type/TypePrint 递归打印), - 对悬空 entry.Ty(1b 泛型特化类注册后被 reset 回收的 pool 指针)解引用崩溃。 - 改用 t.CUInt64T 纯指针值比较,不解引用任何内容。 - """ - if struct_ty is None or self.StructTable is None: - return None - # StructCount 合理性守卫(内存损坏导致巨大值 → 索引循环假挂起) - if self.StructCount < 0 or self.StructCount > 200000: - VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct_by_type)", "STRUCT") - stdlib.exit(1) - st_val: t.CUInt64T = t.CUInt64T(struct_ty) - for i in range(self.StructCount): - entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i) - if entry is not None and entry.Ty is not None: - if t.CUInt64T(entry.Ty) == st_val: - return entry - return None - - def lookup_field(self, struct_ty: llvmlite.LLVMType | t.CPtr, - field_name: str) -> HandlesStruct.FieldEntry | t.CPtr: - """按结构体类型和字段名查找字段信息 - - 两遍查找策略(跨模块同名类冲突的根本修复): - 第一遍: 类型指针 is 身份比较(最高优先级,类型唯一确定 entry) - 第二遍: 名称回退(is 未匹配时,按类名/strstr 匹配,字段未找到时 continue) - """ - if struct_ty is None or field_name is None or self.StructTable is None: - return None - - # ============================================================ - # 两遍查找策略(跨模块同名类冲突的根本修复): - # - # 第一遍: 用类型指针 is 身份比较(最高优先级) - # - is 匹配唯一确定 entry,字段未找到直接返回 None - # - 规避联合类型 == BUG,且不受遍历顺序影响 - # - # 第二遍: 名称回退(is 未匹配到任何 entry 时才执行) - # - 用于未注册类型或 is 不可靠的场景 - # - 名称匹配但字段未找到时 continue(继续检查其他同名 entry) - # ============================================================ - - # 第一遍: is 身份比较(用 t.CUInt64T 指针值比较,避免 is 编译路径解引用悬空 Ty) - st_lk: t.CUInt64T = t.CUInt64T(struct_ty) - for i in range(self.StructCount): - entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i) - if entry is not None and entry.Ty is not None: - if t.CUInt64T(entry.Ty) == st_lk: - # is 匹配,查找字段 - for fi in range(entry.FieldCount): - fe: HandlesStruct.FieldEntry | t.CPtr = self._get_field_entry(entry, fi) - if fe is not None and fe.Name is not None: - if string.strcmp(fe.Name, field_name) == 0: - return fe - # is 匹配但字段未找到(类型唯一确定,无需继续) - return None - - # 第二遍: 名称回退(is 未匹配到) - ty_name: str = self._extract_struct_name(struct_ty) - if ty_name is not None: - for i in range(self.StructCount): - entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i) - if entry is not None and entry.Name is not None: - matched: int = 0 - if string.strcmp(entry.Name, ty_name) == 0: - matched = 1 - elif string.strstr(ty_name, entry.Name) is not None: - matched = 1 - if matched != 0: - # 查找字段 - for fi in range(entry.FieldCount): - fe: HandlesStruct.FieldEntry | t.CPtr = self._get_field_entry(entry, fi) - if fe is not None and fe.Name is not None: - if string.strcmp(fe.Name, field_name) == 0: - return fe - # 名称匹配但字段未找到,继续检查其他同名 entry(跨模块同名) - continue - # 所有条目都未匹配 - return None - - def lookup_field_by_class(self, class_name: str, - field_name: str, - sha1: str = None) -> HandlesStruct.FieldEntry | t.CPtr: - """按类名和字段名查找字段信息 - - 优先用 SHA1 匹配(跨模块同名类区分),无 SHA1 时按类名查找第一个 - """ - if class_name is None or field_name is None: - return None - - # 优先用 SHA1 匹配(跨模块同名类区分) - # 支持模块限定名:class_name 可能是 "HT.Translator",entry.Name 是 "Translator" - # 先精确匹配,失败后用 strrchr 提取类名部分回退匹配 - if sha1 is not None: - sha1_matched: int = 0 - # 计算类名回退部分("HT.Translator" → "Translator") - bare_name: str = class_name - dot_pos_lfbc: str = string.strrchr(class_name, '.') - if dot_pos_lfbc is not None: - bare_name = dot_pos_lfbc + 1 - if bare_name is None or bare_name[0] == '\0': - bare_name = class_name - for i in range(self.StructCount): - entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i) - if entry is not None and entry.Name is not None: - # 精确匹配或类名回退匹配 - name_match: int = 0 - if string.strcmp(entry.Name, class_name) == 0: - name_match = 1 - elif bare_name is not class_name and string.strcmp(entry.Name, bare_name) == 0: - name_match = 1 - if name_match != 0: - if entry.ModuleSha1 is not None \ - and string.strcmp(entry.ModuleSha1, sha1) == 0: - sha1_matched = 1 - # SHA1 + 类名匹配,查找字段 - for fi in range(entry.FieldCount): - fe: HandlesStruct.FieldEntry | t.CPtr = self._get_field_entry(entry, fi) - if fe is not None and fe.Name is not None \ - and string.strcmp(fe.Name, field_name) == 0: - return fe - return None - - # 回退: 无 SHA1 或 SHA1 匹配失败,按类名查找第一个 - entry = self.find_struct(class_name) - if entry is None: - # 诊断:目标类未注册 - fb_lfbc: str = VLogger.fmt_buf() - if fb_lfbc is not None: - viperlib.snprintf(fb_lfbc, 1024, - "lookup_field_by_class: 类 '%s' 未注册 (struct_count=%d)", - class_name, self.StructCount) - VLogger.error(fb_lfbc, "STRUCT") - return None - # 先查找字段(诊断/error 之前返回,否则 error 立即退出导致查找永远失败) - for fi in range(entry.FieldCount): - fe: HandlesStruct.FieldEntry | t.CPtr = self._get_field_entry(entry, fi) - if fe is not None and fe.Name is not None: - if string.strcmp(fe.Name, field_name) == 0: - return fe - # REnum 变体字段别名回退:REnum 类(如 LLVMType)的变体内部字段 - # (Ptr.Pointee 等)不是普通字段,而是 _p1/_p2 槽位别名。此前在调用方 - # (ExprGenMixin 按需过滤 L5046/L5500)回退,但本函数字段未找到的 - # VLogger.error 立即 sys.exit(1),调用方回退永远执行不到("LLVMType 已注册 - # 但字段 Pointee 未找到"四次依旧的根因)。此处直接查变体别名,所有调用方 - # 统一受益。注意:_lookup_renum_field_alias 用 class_name 指针值比较, - # 必须传 entry.Name(register_struct 复制 + _update_renum_alias_class_ptr - # 统一后的池指针),传调用方 class_name(AnnotClassName 等不同指针) - # 恒不匹配 → 返回 -1 → 回退失效。 - import lib.core.Handles.HandlesClassDef as HandlesClassDef - rn_cls_l: str = entry.Name - if rn_cls_l is None: - rn_cls_l = class_name - rn_is_renum_l: int = HandlesClassDef._is_renum_class_name(class_name) - if rn_is_renum_l == 0 and rn_cls_l is not None: - # 类名可能是模块限定名("mod.LLVMType"),REnum 表存裸名,双保险 - rn_is_renum_l = HandlesClassDef._is_renum_class_name(rn_cls_l) - rn_alias_l: int = -1 - if rn_is_renum_l != 0: - rn_alias_l = HandlesClassDef._lookup_renum_field_alias( - rn_cls_l, field_name) - if rn_alias_l < 1 and class_name is not rn_cls_l: - # 双保险:别名表可能仍持有旧 AST 指针(_update_renum_alias_class_ptr - # 未执行/多模块重复注册场景),用调用方 class_name 再试一次 - rn_alias_l = HandlesClassDef._lookup_renum_field_alias( - class_name, field_name) - if rn_alias_l >= 1: - rn_fe_l: HandlesStruct.FieldEntry | t.CPtr = \ - HandlesStruct._get_field_entry(entry, rn_alias_l) - if rn_fe_l is not None and rn_fe_l.Ty is not None: - return rn_fe_l - # 诊断:找到结构体但字段确实未找到,打印字段表 - # 注意:VLogger.error 会立即退出进程,字段表须在 error 之前用 warning 打印 - for fi in range(entry.FieldCount): - fe: HandlesStruct.FieldEntry | t.CPtr = self._get_field_entry(entry, fi) - if fe is not None: - fb_fn: str = VLogger.fmt_buf() - if fb_fn is not None: - if fe.Name is not None: - viperlib.snprintf(fb_fn, 1024, " 字段[%d]: '%s'", fi, fe.Name) - else: - viperlib.snprintf(fb_fn, 1024, " 字段[%d]: (null)", fi) - VLogger.warning(fb_fn, "STRUCT") - fb_fields: str = VLogger.fmt_buf() - if fb_fields is not None: - if rn_is_renum_l != 0: - # 报错友好化:REnum 类直接说明是"变体字段别名查找失败",并附 - # entry.Name 与别名槽位结果,一眼可辨"别名未注册"(槽位=-1) - # 还是"class_name 指针未统一"(已注册但传错指针查不到) - viperlib.snprintf(fb_fields, 1024, - "lookup_field_by_class: 类 '%s' 是 REnum 类(FieldCount=%d)," - "变体字段 '%s' 别名查找失败(entry.Name='%s',别名槽位=%d," - "请检查该变体字段是否已注册别名,或 class_name 指针是否统一)", - class_name, entry.FieldCount, field_name, rn_cls_l, rn_alias_l) - else: - viperlib.snprintf(fb_fields, 1024, - "lookup_field_by_class: 类 '%s' 已注册 (FieldCount=%d) 但字段 '%s' 未找到", - class_name, entry.FieldCount, field_name) - VLogger.error(fb_fields, "STRUCT") - # 诊断:找到结构体但字段未找到 - return None - - def get_struct_type(self, class_name: str) -> llvmlite.LLVMType | t.CPtr: - """按类名获取结构体的 LLVM 类型""" - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(class_name) - if entry is not None: - return entry.Ty - return None - - def get_field_by_index(self, class_name: str, - idx: int) -> HandlesStruct.FieldEntry | t.CPtr: - """按类名和字段索引获取字段信息""" - if class_name is None: - return None - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(class_name) - if entry is None: - return None - if idx < 0 or idx >= entry.FieldCount: - return None - return self._get_field_entry(entry, idx) - - def struct_has_defaults(self, class_name: str) -> int: - """检查结构体是否有任何带默认值的字段,返回 1=有 / 0=无""" - if class_name is None: - return 0 - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(class_name) - if entry is None: - return 0 - for fi in range(entry.FieldCount): - fe: HandlesStruct.FieldEntry | t.CPtr = self._get_field_entry(entry, fi) - if fe is not None and fe.DefaultVal is not None: - return 1 - return 0 - - def get_struct_type_from_value(self, val: llvmlite.Value | t.CPtr) -> llvmlite.LLVMType | t.CPtr: - """从 Value 的类型推断结构体类型 - - 递归解 Ptr:支持 X|t.CPtr 联合简化产生的 Ptr(Ptr(Struct)) 对象指针 - (如运算符重载中间结果 a*2.0 的 Vec3**),否则 try_operator_overload - 重载识别失败回退原生运算,对指针生成非法 sub 指令(llc: invalid - operand type for instruction)。 - """ - if val is None or val.Ty is None: - return None - ty: llvmlite.LLVMType | t.CPtr = val.Ty - while ty is not None: - match ty: - case llvmlite.LLVMType.Ptr(pointee): - ty = pointee - case llvmlite.LLVMType.Struct(fields, fcount, name): - return ty - case _: - return None - return None - - def mark_as_union(self, name: str) -> int: - """标记已注册的结构体为联合体,返回 1=成功 / 0=失败""" - if name is None: - return 0 - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name) - if entry is None: - return 0 - entry.IsUnion = 1 - return 1 - - def is_union_by_name(self, name: str) -> int: - """按类名检查是否为联合体,返回 1=是 / 0=否""" - if name is None: - return 0 - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name) - if entry is None: - return 0 - return entry.IsUnion - - def is_union_by_type(self, struct_ty: llvmlite.LLVMType | t.CPtr) -> int: - """按类型指针检查是否为联合体,返回 1=是 / 0=否 - - 先尝试类型指针 == 比较,失败时回退到名称匹配 - """ - if struct_ty is None or self.StructTable is None: - return 0 - ty_name: str = self._extract_struct_name(struct_ty) - st_iu: t.CUInt64T = t.CUInt64T(struct_ty) - for i in range(self.StructCount): - entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i) - if entry is not None and entry.Ty is not None: - matched: int = 0 - if t.CUInt64T(entry.Ty) == st_iu: - matched = 1 - elif ty_name is not None and entry.Name is not None: - if string.strcmp(entry.Name, ty_name) == 0: - matched = 1 - elif string.strstr(ty_name, entry.Name) is not None: - matched = 1 - if matched != 0: - return entry.IsUnion - return 0 - - def mark_as_oop(self, name: str) -> int: - """标记已注册的结构体为 OOP,返回 1=成功 / 0=失败""" - if name is None: - return 0 - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name) - if entry is None: - return 0 - entry.IsOOP = 1 - return 1 - - def is_oop_by_name(self, name: str) -> int: - """按类名检查是否为 OOP 结构体,返回 1=是 / 0=否""" - if name is None: - return 0 - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name) - if entry is None: - return 0 - return entry.IsOOP - - def mark_has_init(self, name: str) -> int: - """标记结构体拥有 __init__ 方法,返回 1=成功 / 0=失败""" - if name is None: - return 0 - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name) - if entry is None: - return 0 - entry.HasInit = 1 - return 1 - - def has_init_by_name(self, name: str) -> int: - """按类名检查是否有 __init__ 方法,返回 1=有 / 0=无""" - if name is None: - return 0 - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name) - if entry is None: - return 0 - return entry.HasInit - - def mark_has_new(self, name: str) -> int: - """标记结构体拥有 __new__ 方法,返回 1=成功 / 0=失败""" - if name is None: - return 0 - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name) - if entry is None: - return 0 - entry.HasNew = 1 - return 1 - - def has_new_by_name(self, name: str) -> int: - """按类名检查是否有 __new__ 方法,返回 1=有 / 0=无""" - if name is None: - return 0 - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name) - if entry is None: - return 0 - return entry.HasNew - - def get_class_name_by_type(self, pool: memhub.MemBuddy | t.CPtr, - struct_ty: llvmlite.LLVMType | t.CPtr) -> str: - """按类型指针查找类名,返回类名字符串或 None""" - if struct_ty is None or self.StructTable is None: - return None - st_cn: t.CUInt64T = t.CUInt64T(struct_ty) - for i in range(self.StructCount): - entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i) - if entry is not None and entry.Ty is not None: - if t.CUInt64T(entry.Ty) == st_cn: - return entry.Name - # 回退: 类型指针比较失败时,遍历所有注册的结构体按名称匹配 - # 提取 struct_ty 的 Name 字段(可能是 "SHA1.ClassName" 格式) - ty_name: str = self._extract_struct_name(struct_ty) - if ty_name is not None: - for j in range(self.StructCount): - entry2: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(j) - if entry2 is not None and entry2.Name is not None: - # 构造 "SHA1.ClassName" 格式进行比较 - entry2_sha1: str = entry2.ModuleSha1 - if entry2_sha1 is not None: - full_nm: str = pool.alloc(128) - if full_nm is not None: - viperlib.snprintf(full_nm, 128, "%s.%s", entry2_sha1, entry2.Name) - if string.strcmp(full_nm, ty_name) == 0: - return entry2.Name - # 也直接比较类名(struct_ty 的 Name 可能无 SHA1 前缀) - if string.strcmp(entry2.Name, ty_name) == 0: - return entry2.Name - # 最后回退: 后缀匹配("SHA1.ClassName" 尾部)——比 strstr 子串 - # 匹配安全:特化名 "SHA1.GSList[Param]" 会被基础名 "GSList" 错误 - # 命中(子串),导致链式方法调用 class_name 解析错(如 - # func.Params.append → GSList.append 查找失败 → 兄弟 Mixin 兜底 - # 误匹配 LinkedNode.append,this 前移 sizeof(LinkedNode) 写穿 - # 容器前 48 字节,LLvmLiteTest Test 3 崩溃根因)。 - if entry2.Name is not None and string.strlen(entry2.Name) > 0: - _tlen_cn: t.CSizeT = string.strlen(ty_name) - _nlen_cn: t.CSizeT = string.strlen(entry2.Name) - if _tlen_cn > _nlen_cn and ty_name[_tlen_cn - _nlen_cn - 1] == '.': - _tail_ok_cn: int = 1 - _ti_cn: t.CSizeT - for _ti_cn in range(_nlen_cn): - if ty_name[_tlen_cn - _nlen_cn + _ti_cn] != entry2.Name[_ti_cn]: - _tail_ok_cn = 0 - break - if _tail_ok_cn == 1: - return entry2.Name - return None - - def _extract_struct_name(self, ty: llvmlite.LLVMType | t.CPtr) -> str: - """从 LLVMType 提取 Struct 变体的 Name 字段,返回 None 非 Struct""" - if ty is None: - return None - match ty: - case llvmlite.LLVMType.Struct(fields, fcount, name): - return name - case _: - return None - - def mark_has_vtable(self, name: str) -> int: - """标记结构体拥有虚表,返回 1=成功 / 0=失败""" - if name is None: - return 0 - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name) - if entry is None: - return 0 - entry.HasVTable = 1 - return 1 - - def has_vtable_by_name(self, name: str) -> int: - """按类名检查是否有虚表,返回 1=有 / 0=无""" - if name is None: - return 0 - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name) - if entry is None: - return 0 - return entry.HasVTable - - def mark_novtable(self, name: str) -> int: - """标记结构体为 NoVTable,返回 1=成功 / 0=失败""" - if name is None: - return 0 - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name) - if entry is None: - return 0 - entry.IsNoVTable = 1 - return 1 - - def is_novtable_by_name(self, name: str) -> int: - """按类名检查是否为 NoVTable,返回 1=是 / 0=否""" - if name is None: - return 0 - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name) - if entry is None: - return 0 - return entry.IsNoVTable - - def set_parent_name(self, name: str, parent_name: str) -> int: - """设置结构体的父类名,返回 1=成功 / 0=失败""" - if name is None: - return 0 - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name) - if entry is None: - return 0 - entry.ParentName = parent_name - return 1 - - def set_parent_names(self, pool: memhub.MemBuddy | t.CPtr, - name: str, names_ptr: t.CSizeT | t.CPtr, - count: int) -> int: - """设置结构体的父类名数组(永久池深拷贝,跨文件永久存活)""" - if name is None: - return 0 - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name) - if entry is None: - return 0 - if names_ptr is None or count <= 0: - entry.ParentNames = None - entry.ParentCount = 0 - return 1 - if count > PARENT_MAX: - count = PARENT_MAX - pn_pool: memhub.MemBuddy | t.CPtr = pool - if self.StdlibAlloc != 0: - pn_pool = CompilerFactory.get_perm_pool() - if pn_pool is None: - pn_pool = pool - arr: t.CSizeT | t.CPtr = pn_pool.alloc(8 * count) - if arr is None: - return 0 - for i in range(count): - addr: t.CSizeT = names_ptr[i] - arr[i] = 0 - if addr != 0: - src: str = (str | t.CPtr)(t.CVoid(addr, t.CPtr)) - if src is not None: - slen: t.CSizeT = string.strlen(src) - dup: str = pn_pool.alloc(slen + 1) - if dup is not None: - string.strcpy(dup, src) - arr[i] = t.CSizeT(dup) - entry.ParentNames = t.CSizeT(arr) - entry.ParentCount = count - return 1 - - def get_parent_count(self, name: str) -> int: - """获取父类数量(0=无父类,1=单继承,>1=多继承)""" - if name is None: - return 0 - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name) - if entry is None: - return 0 - return entry.ParentCount - - def get_parent_name_at(self, name: str, idx: int) -> str: - """获取第 idx 个父类名,越界返回 None""" - if name is None or idx < 0: - return None - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name) - if entry is None or entry.ParentNames is None: - return None - if idx >= entry.ParentCount: - return None - parr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(entry.ParentNames, t.CPtr)) - addr: t.CSizeT = parr[idx] - if addr == 0: - return None - return (str | t.CPtr)(t.CVoid(addr, t.CPtr)) - - def get_mro_chain(self, pool: memhub.MemBuddy | t.CPtr, - name: str) -> t.CSizeT | t.CPtr: - """MRO 线性化类名数组(深度优先 + 声明顺序 + 去重,含自身)""" - if pool is None or name is None: - return None - arr: t.CSizeT | t.CPtr = pool.alloc(8 * (MRO_MAX + 1)) - if arr is None: - return None - stack: t.CSizeT | t.CPtr = pool.alloc(8 * MRO_MAX) - if stack is None: - return None - visited: t.CSizeT | t.CPtr = pool.alloc(8 * MRO_MAX) - if visited is None: - return None - stack_count: int = 0 - out_count: int = 0 - visit_count: int = 0 - # 初始压入自身 - stack[0] = t.CSizeT(name) - stack_count = 1 - while stack_count > 0: - stack_count -= 1 - cur_addr: t.CSizeT = stack[stack_count] - cur: str = (str | t.CPtr)(t.CVoid(cur_addr, t.CPtr)) - if cur is None: - continue - # 已访问检查(线性搜索) - dup: int = 0 - for vi in range(visit_count): - va: t.CSizeT = visited[vi] - if va != 0: - vn: str = (str | t.CPtr)(t.CVoid(va, t.CPtr)) - if vn is not None and string.strcmp(vn, cur) == 0: - dup = 1 - break - if dup != 0: - continue - # 加入结果与已访问集合 - if out_count < MRO_MAX: - arr[out_count] = t.CSizeT(cur) - out_count += 1 - if visit_count < MRO_MAX: - visited[visit_count] = t.CSizeT(cur) - visit_count += 1 - # 父类逆序压栈(正向 range 计算逆序索引,保证声明顺序弹出) - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(cur) - if entry is not None and entry.ParentCount > 0 and entry.ParentNames is not None: - pc: int = entry.ParentCount - parr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(entry.ParentNames, t.CPtr)) - for pi2 in range(pc): - pi: int = pc - 1 - pi2 - if stack_count < MRO_MAX: - stack[stack_count] = parr[pi] - stack_count += 1 - # 末尾 0 结束 - arr[out_count] = 0 - return arr - - def get_parent_name(self, name: str) -> str: - """获取结构体的父类名,返回 None=无父类""" - if name is None: - return None - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name) - if entry is None: - return None - return entry.ParentName - - def set_vtable_methods(self, name: str, methods: str, count: int) -> int: - """设置虚表方法名数组,返回 1=成功 / 0=失败""" - if name is None: - return 0 - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name) - if entry is None: - return 0 - entry.VTableMethods = methods - entry.VTableMethodCount = count - return 1 - - def get_vtable_method_index(self, name: str, method_name: str) -> int: - """获取方法在虚表中的索引,返回 -1=未找到""" - if name is None or method_name is None: - return -1 - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name) - if entry is None or entry.VTableMethods is None: - return -1 - # VTableMethods 字段声明为 t.CChar*,但实际存储的是 t.CSizeT 数组 - # 必须转换为 t.CSizeT* 才能正确读取 8 字节指针值 - methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(entry.VTableMethods, t.CPtr)) - for i in range(entry.VTableMethodCount): - mname_addr: t.CSizeT = methods_arr[i] - if mname_addr == 0: - continue - mname: str = (str | t.CPtr)(t.CVoid(mname_addr, t.CPtr)) - if mname is not None and string.strcmp(mname, method_name) == 0: - return i - return -1 - - def get_vtable_method_count(self, name: str) -> int: - """获取虚表方法数量""" - if name is None: - return 0 - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name) - if entry is None: - return 0 - return entry.VTableMethodCount - - def get_vtable_method_name(self, name: str, idx: int) -> str: - """获取虚表中第 idx 个方法名,返回 None=越界""" - if name is None or idx < 0: - return None - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name) - if entry is None or entry.VTableMethods is None: - return None - if idx >= entry.VTableMethodCount: - return None - methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(entry.VTableMethods, t.CPtr)) - mname_addr: t.CSizeT = methods_arr[idx] - if mname_addr == 0: - return None - return (str | t.CPtr)(t.CVoid(mname_addr, t.CPtr)) - - def get_field_count(self, name: str) -> int: - """获取结构体字段数量,返回 -1=未找到""" - if name is None: - return -1 - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name) - if entry is None: - return -1 - return entry.FieldCount - - def ensure_struct_def_in_module(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - ty: llvmlite.LLVMType | t.CPtr): - """确保跨模块结构体的完整定义在当前模块中可用(供 alloca 使用) - - 处理两种情况: - 1. Struct 值类型:需要完整定义(供 alloca 分配空间) - 2. Ptr(Struct) 指针类型:需要 pointee 至少有 opaque 声明 - """ - if ty is None or mod is None or pool is None: - return - # 指针类型:确保 pointee 至少有 opaque 声明 - match ty: - case llvmlite.LLVMType.Ptr(pointee): - llvmlite.module_ensure_opaque_for_type(mod, pool, ty) - # 如果 pointee 是 Struct,递归复制完整定义 - # (GEP 访问字段需要 sized 类型,仅 opaque 会导致 llc 报错) - if pointee is not None: - self.ensure_struct_def_in_module(pool, mod, pointee) - return - case _: - pass - # 获取结构体名称(非 Struct 类型返回 None) - sname: str = llvmlite.get_struct_name(ty) - if sname is None: - return - # 检查是否为跨模块引用(名称包含 '.') - if string.strchr(sname, 46) is None: - return # 非跨模块引用,无需处理 - # 提取类名(第一个 '.' 之后的部分) - # 必须用 strchr 而非 strrchr:泛型特化名如 "list[ast.AST|t.CPtr]" - # 内部含 '.'(ast.AST),strrchr 会错误地把类名解析为 "AST|t.CPtr]" - dot_pos: str = string.strchr(sname, '.') - if dot_pos is None: - return - class_name: str = dot_pos + 1 - if class_name is None or class_name[0] == '\0': - return - # 提取 SHA1(sname 到 dot_pos 之间,用 strlen 避免指针减法) - total_len: t.CSizeT = string.strlen(sname) - class_name_len: t.CSizeT = string.strlen(class_name) - sha1_len: t.CSizeT = total_len - class_name_len - 1 - sha1_buf: str = pool.alloc(32) - if sha1_buf is None: - return - # 32 字节缓冲:strncpy 不截断,前缀超过 31 字符会越界写 + 手动 NUL 再越界 - sha1_cp: t.CSizeT = sha1_len - if sha1_cp > 31: - sha1_cp = 31 - string.strncpy(sha1_buf, sname, sha1_cp) - sha1_buf[sha1_cp] = '\0' - # 按类名 + SHA1 查找结构体定义 - entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct_by_module(class_name, sha1_buf) - if entry is None: - # 回退到按类名查找(可能找到不同模块的同名类,但总比没有好) - entry = self.find_struct(class_name) - if entry is None: - return - if entry.Ty is None: - return - # 将完整定义添加到当前模块(会替换已存在的 opaque 声明) - llvmlite.module_add_named_type(mod, pool, entry.Ty) - # 递归扫描字段类型,确保值类型子结构体(如 WIN32_FIND_DATAA 中的 FILETIME) - # 也有完整定义。指针类型字段只需 opaque 声明(已由 module_ensure_opaque_for_type 处理)。 - self._ensure_field_types_in_module(pool, mod, entry.Ty) - - def _ensure_field_types_in_module(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - ty: llvmlite.LLVMType | t.CPtr): - """递归扫描类型树,确保值类型子结构体有完整定义""" - if ty is None or mod is None or pool is None: - return - # 嵌套 match 遍历类型树 - match ty: - case llvmlite.LLVMType.Struct(fields, fcount, sname): - # 遍历字段链表 - if fields is not None: - fld: llvmlite.ParamNode | t.CPtr = fields - cnt_ef: t.CInt = 0 - while fld is not None: - # 步数守卫:字段链表成环(内存损坏)导致无限遍历挂起 - # (G3 LinkedNode.prepend 挂起候选),超限立即报错终止 - cnt_ef += 1 - if cnt_ef > 100000: - VLogger.error( - "字段链表疑似成环(_ensure_field_types_in_module),强制终止", - "STRUCT") - stdlib.exit(1) - if fld.Ty is not None: - # 值类型子结构体(如 FILETIME)需要完整定义 - match fld.Ty: - case llvmlite.LLVMType.Struct(f2, fc2, n2): - self.ensure_struct_def_in_module(pool, mod, fld.Ty) - case _: - pass - self._ensure_field_types_in_module(pool, mod, fld.Ty) - fld = fld.Next - case llvmlite.LLVMType.Ptr(pointee): - # 指针类型:pointee 只需 opaque 声明,不需要完整定义 - # 但如果 pointee 是 Struct,确保 opaque 声明存在 - if pointee is not None: - llvmlite.module_ensure_opaque_for_type(mod, pool, ty) - case llvmlite.LLVMType.Array(elem_ty, acount): - # 数组类型:元素如果是值类型结构体,需要完整定义 - # (如 zhuff_decode_tree = {MemManager*, [576 x zhuff_decode_node], - # i32, i32}——Array 元素 node 只递归字段不发射定义 → llc "use of - # undefined type named '...zhuff_decode_node'",ZlibTest 根因) - if elem_ty is not None: - match elem_ty: - case llvmlite.LLVMType.Struct(_, _, _): - self.ensure_struct_def_in_module(pool, mod, elem_ty) - case _: - pass - self._ensure_field_types_in_module(pool, mod, elem_ty) - case _: - pass - - def get_field_name_ptr(self, fe: HandlesStruct.FieldEntry | t.CPtr) -> str: - """获取 FieldEntry 的字段名,返回 None=未设置""" - if fe is None: - return None - return fe.Name - - def get_field_type_ptr(self, fe: HandlesStruct.FieldEntry | t.CPtr) -> llvmlite.LLVMType | t.CPtr: - """获取 FieldEntry 的字段类型,返回 None=未设置""" - if fe is None: - return None - return fe.Ty - - def get_field_default_ptr(self, fe: HandlesStruct.FieldEntry | t.CPtr) -> ast.AST | t.CPtr: - """获取 FieldEntry 的默认值 AST 节点,返回 None=无默认值""" - if fe is None: - return None - return fe.DefaultVal - - def get_field_annot_class_name(self, fe: HandlesStruct.FieldEntry | t.CPtr) -> str: - """获取 FieldEntry 的原始类型注解类名,返回 None=未设置""" - if fe is None: - return None - return fe.AnnotClassName +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.Generator as Generator +import t, c +from stdint import * +import memhub +import string +import stdlib +import llvmlite +import stdio +import ast +import hashtable +import viperlib +import lib.core.CompilerFactory as CompilerFactory +import lib.core.VLogger as VLogger + + +# ============================================================ +# StructGenMixin - 结构体注册/字段查找 Mixin(对象化 P2-2,wiki/14-oo-refactor.md) +# +# 从 HandlesStruct.vp 迁移: +# 全局状态(_struct_table/_struct_count/_g_stdlib_alloc/ +# _visible_structs/_strict_visibility)→ 本类字段 +# 模块级函数(register_struct/find_struct/lookup_field/...)→ 本类方法 +# +# 迁移原则(与 TypeGenMixin P2-1 一致,行为零变化): +# 1. 方法保留原函数签名(含 pool 首参),仅函数体内的全局变量改为 self.字段 +# 2. HandlesStruct.vp 原函数保留为"委托":本地模块级单例 _g_gen(BuildPipeline +# /main 注入)cast 成 Generator 类型后调本类方法 +# 3. FieldEntry/StructEntry 类型保留在 HandlesStruct.vp(本类字段引用) +# +# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整,无 vtable 开销)。 +# ============================================================ + + +# ============================================================ +# 常量(与 HandlesStruct 保持一致) +# ============================================================ +STRUCT_MAX: t.CDefine = 512 +# 字段槽位上限制(与 HandlesStruct 保持一致;Generator 43 Mixin 展平 ~120 字段, +# 2026-08-16 追加78:64 截断导致第 9+ 父类字段(StmtGenMixin.DiagStmtCount 等) +# 丢失 → __init__ 写 self.DiagStmtCount "属性写入失败") +FIELD_MAX: t.CDefine = 256 +FIELD_NAME_MAX: t.CDefine = 64 +# 多继承(MRO)支持:单类最大父类数 / MRO 链最大长度(Generator 43 父类; +# PARENT_MAX=16 时第 17+ 父类字段丢失 → __init__ 写 self.DiagStmtCount 失败) +PARENT_MAX: t.CDefine = 64 +MRO_MAX: t.CDefine = 64 + + +# ============================================================ +# StructGenMixin - 结构体注册表/字段查找/可见性 +# ============================================================ +@t.NoVTable +class StructGenMixin: + """结构体注册与查找 Mixin(状态从 HandlesStruct 全局变量迁入)""" + + # --- 全局注册表(原 _struct_table/_struct_count) --- + Gen: Generator.Generator | t.CPtr + StructTable: GenTypes.StructEntry | t.CPtr # STRUCT_MAX 槽位数组 + StructCount: int + + # --- OOM 回收分配模式(原 _g_stdlib_alloc) --- + StdlibAlloc: int + + # --- 跨模块命名空间隔离(原 _visible_structs/_strict_visibility) --- + VisibleStructs: hashtable.HashTable | t.CPtr + StrictVisibility: int + + def InitStructGen(self) -> int: + """初始化结构体 Mixin 字段(子类构造时内联调用,规避 NoVTable 继承符号不转发)""" + if self is None: + return 1 + self.StructTable = None + self.StructCount = 0 + self.StdlibAlloc = 0 + self.VisibleStructs = None + self.StrictVisibility = 0 + return 0 + + # ============================================================ + # P2-2 迁移方法(函数体来自 HandlesStruct.vp,全局变量改 self.字段, + # 同模块函数调用改 self.方法;签名与 HandlesStruct 原函数一致) + # ============================================================ + + def set_stdlib_alloc(self, flag: int): + """设置 OOM 回收分配模式:1=1b 阶段(新条目用 stdlib),0=注册阶段(用 pool)""" + self.StdlibAlloc = flag + + def get_stdlib_alloc(self) -> int: + """读取 OOM 回收分配模式(供其他 Mixin 经 HandlesStruct 委托访问, + 避免跨 Mixin 直接读 self.StdlibAlloc——Mixin 方法体按自身块内索引编译)""" + return self.StdlibAlloc + + def reset_visible_structs(self, pool: memhub.MemBuddy | t.CPtr, strict: int): + """重置可见性状态(每个文件翻译前调用) + + pool: 内存分配器(严格模式下创建 HashTable) + strict: 1=严格模式(用户文件),0=宽松模式(includes 文件) + """ + self.StrictVisibility = strict + if strict != 0: + # 严格模式:创建新的 HashTable 记录可见结构体 + self.VisibleStructs = hashtable.HashTable(pool) + else: + # 宽松模式:全部可见,不需要 HashTable + self.VisibleStructs = None + + def add_visible_struct(self, pool: memhub.MemBuddy | t.CPtr, name: str): + """添加可见结构体名(类定义时和 from-import 时调用)""" + if name is None: + return + # 宽松模式:全部可见,无需记录 + if self.StrictVisibility == 0: + return + if self.VisibleStructs is None: + return + # 已存在则跳过(HashTable.__setitem__ 会覆盖,此处提前检查避免重复分配) + if self.VisibleStructs.__contains__(name) != 0: + return + self.VisibleStructs.set_int(name, 1) + + def is_struct_visible(self, name: str) -> int: + """检查结构体是否可见,返回 1=可见 / 0=不可见""" + if self.StrictVisibility == 0: + return 1 + if name is None or self.VisibleStructs is None: + return 0 + return self.VisibleStructs.__contains__(name) + + def init_struct_table(self, pool: memhub.MemBuddy | t.CPtr) -> int: + """初始化结构体注册表,返回 1 成功 + + StdlibAlloc=1 时表体分配在 perm_pool:1a 每文件 reset 后表本体 + 不被回收(否则首次 register_struct 若发生在文件级 mark 之后, + reset 会把 StructTable 连根回收,全局 find_struct 悬空)。 + """ + if self.StructTable is not None: + return 1 + + entry_size: t.CSizeT = GenTypes.StructEntry.__sizeof__() + table_pool: memhub.MemBuddy | t.CPtr = pool + if self.StdlibAlloc != 0: + table_pool = CompilerFactory.get_perm_pool() + if table_pool is None: + table_pool = pool + self.StructTable = table_pool.alloc(entry_size * STRUCT_MAX) + if self.StructTable is None: + return 0 + string.memset(self.StructTable, 0, entry_size * STRUCT_MAX) + self.StructCount = 0 + return 1 + + def _get_struct_entry(self, i: int) -> GenTypes.StructEntry | t.CPtr: + """获取第 i 个结构体条目""" + if self.StructTable is None or i < 0 or i >= STRUCT_MAX: + return None + entry_size: t.CSizeT = GenTypes.StructEntry.__sizeof__() + addr: t.CUInt64T = t.CUInt64T(self.StructTable) + i * entry_size + return (GenTypes.StructEntry | t.CPtr)(t.CVoid(addr, t.CPtr)) + + def _get_field_entry(self, struct_entry: GenTypes.StructEntry | t.CPtr, i: int) -> GenTypes.FieldEntry | t.CPtr: + """获取结构体中第 i 个字段条目""" + if struct_entry is None or i < 0 or i >= FIELD_MAX: + return None + field_size: t.CSizeT = GenTypes.FieldEntry.__sizeof__() + addr: t.CUInt64T = t.CUInt64T(struct_entry.Fields) + i * field_size + return (GenTypes.FieldEntry | t.CPtr)(t.CVoid(addr, t.CPtr)) + + def register_struct(self, pool: memhub.MemBuddy | t.CPtr, + name: str, + struct_ty: llvmlite.LLVMType | t.CPtr, + sha1: str = None) -> GenTypes.StructEntry | t.CPtr: + """注册结构体类型,返回 StructEntry 指针 + + 用类型指针去重(is 比较),不用类名去重。 + 这样跨模块同名类可以共存,各自有独立的字段定义。 + sha1 参数在注册时直接设置 ModuleSha1(避免 set_struct_sha1 找错 entry)。 + """ + if self.init_struct_table(pool) == 0: + return None + + # 用类型指针去重(同一类型不重复注册,支持跨模块同名类) + # 用 t.CUInt64T 指针值比较(is 比较会触发类型安全检查解引用悬空 Ty) + st_dedup: t.CUInt64T = t.CUInt64T(struct_ty) + for i in range(self.StructCount): + existing: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i) + if existing is not None and existing.Ty is not None: + if t.CUInt64T(existing.Ty) == st_dedup: + return existing + + if self.StructCount >= STRUCT_MAX: + fb_st: str = VLogger.fmt_buf() + if fb_st is not None: + viperlib.snprintf(fb_st, 1024, "table full, cannot register %s", name) + VLogger.error(fb_st, "STRUCT") + return None + + entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(self.StructCount) + if entry is None: + return None + + # 分配字段数组(1b 阶段用永久池,避免 reset 回收后 Fields 悬空) + field_size: t.CSizeT = GenTypes.FieldEntry.__sizeof__() + if self.StdlibAlloc != 0: + perm_sg: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool() + if perm_sg is None: + perm_sg = pool + entry.Fields = perm_sg.alloc(field_size * FIELD_MAX) + else: + entry.Fields = pool.alloc(field_size * FIELD_MAX) + if entry.Fields is None: + return None + string.memset(entry.Fields, 0, field_size * FIELD_MAX) + + # 复制类名(1b/Phase2(StdlibAlloc=1)用永久池跨 reset 存活; + # 1a(StdlibAlloc=0)用主 pool,mark1 前不回收同样存活。 + # 此前 1a 用 pool、1b 用 stdlib,find_struct_by_module 的 strcmp + # 曾读悬空 Name 越界 → G3 LinkedNode.prepend 挂起根因) + name_pool: memhub.MemBuddy | t.CPtr = pool + if self.StdlibAlloc != 0: + name_pool = CompilerFactory.get_perm_pool() + if name_pool is None: + name_pool = pool + name_len: t.CSizeT = string.strlen(name) + name_buf: str = name_pool.alloc(name_len + 1) + if name_buf is not None: + string.strcpy(name_buf, name) + entry.Name = name_buf + + entry.Ty = struct_ty + entry.FieldCount = 0 + + # 注册时直接设置 SHA1(避免 set_struct_sha1 跨模块同名时找错 entry) + # SHA1 同样按 StdlibAlloc 选分配源(跨 1a/1b 存活,防 strcmp 悬空) + if sha1 is not None: + sha1_len: t.CSizeT = string.strlen(sha1) + sha1_buf: str = name_pool.alloc(sha1_len + 1) + if sha1_buf is not None: + string.strcpy(sha1_buf, sha1) + entry.ModuleSha1 = sha1_buf + + self.StructCount += 1 + return entry + + def set_struct_sha1(self, pool: memhub.MemBuddy | t.CPtr, + class_name: str, sha1: str) -> int: + """设置结构体所属模块的 SHA1,返回 1=成功 / 0=失败""" + if class_name is None or sha1 is None: + return 0 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(class_name) + if entry is None: + return 0 + # 复制 SHA1 字符串(StdlibAlloc=1 用永久池,跨 1a/1b 存活防 strcmp 悬空) + sha1_len: t.CSizeT = string.strlen(sha1) + sha1_pool: memhub.MemBuddy | t.CPtr = pool + if self.StdlibAlloc != 0: + sha1_pool = CompilerFactory.get_perm_pool() + if sha1_pool is None: + sha1_pool = pool + sha1_buf: str = sha1_pool.alloc(sha1_len + 1) + if sha1_buf is None: + return 0 + string.strcpy(sha1_buf, sha1) + entry.ModuleSha1 = sha1_buf + return 1 + + def get_struct_sha1(self, class_name: str) -> str: + """获取结构体所属模块的 SHA1,返回 None=无 SHA1""" + if class_name is None or self.StructTable is None: + return None + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(class_name) + if entry is None: + return None + return entry.ModuleSha1 + + def add_field(self, pool: memhub.MemBuddy | t.CPtr, + struct_entry: GenTypes.StructEntry | t.CPtr, + field_name: str, + field_ty: llvmlite.LLVMType | t.CPtr, + default_val: ast.AST | t.CPtr = None, + annot_class_name: str = None) -> int: + """向结构体添加字段,返回字段索引(-1 失败) + + default_val: 字段默认值 AST 节点(可选,None=无默认值) + annot_class_name: 原始类型注解的类名(可选,用于联合类型字段的方法调用解析) + """ + if struct_entry is None or field_name is None or field_ty is None: + return -1 + + if struct_entry.FieldCount >= FIELD_MAX: + fb_sf: str = VLogger.fmt_buf() + if fb_sf is not None: + viperlib.snprintf(fb_sf, 1024, "field table full for %s", struct_entry.Name) + VLogger.error(fb_sf, "STRUCT") + return -1 + + idx: int = struct_entry.FieldCount + fe: GenTypes.FieldEntry | t.CPtr = self._get_field_entry(struct_entry, idx) + if fe is None: + return -1 + + # 复制字段名(StdlibAlloc=1 用永久池跨 reset 存活, + # 否则 lookup_field 的 strcmp(fe.Name, ...) 读悬空越界挂起, + # 与 register_struct 的 Name 悬空同根因) + fname_pool: memhub.MemBuddy | t.CPtr = pool + if self.StdlibAlloc != 0: + fname_pool = CompilerFactory.get_perm_pool() + if fname_pool is None: + fname_pool = pool + name_len: t.CSizeT = string.strlen(field_name) + name_buf: str = fname_pool.alloc(name_len + 1) + if name_buf is not None: + string.strcpy(name_buf, field_name) + fe.Name = name_buf + + fe.Index = idx + # 1b 阶段(StdlibAlloc=1)字段类型/注解类名必须深拷贝到 stdlib: + # register_struct 已迁 Fields/Name/ModuleSha1/Ty(translate_class_def L2566 + # DeepCopyType),但字段级 Ty/AnnotClassName 仍存 pool 指针,本文件 + # reset_to(mark1) 回收后,跨文件读取(字段展平、多继承 this 调整、 + # AnnotClassName 回退、_apply_struct_defaults 的 build_gep_struct 用 fe.Ty + # 作 GEP 结果类型)解引用悬空内存 → 崩溃点漂移(json/string/builtins 之间)。 + if self.StdlibAlloc != 0: + dp_pool_sg: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool() + if dp_pool_sg is None: + dp_pool_sg = pool + ty_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(dp_pool_sg, field_ty) + if ty_copy is not None: + fe.Ty = ty_copy + else: + fe.Ty = field_ty + if annot_class_name is not None: + annot_len: t.CSizeT = string.strlen(annot_class_name) + annot_buf: str = CompilerFactory.get_perm_pool().alloc(annot_len + 1) + if annot_buf is not None: + string.strcpy(annot_buf, annot_class_name) + fe.AnnotClassName = annot_buf + # DefaultVal:跨文件结构体构造(_translate_struct_ctor→_apply_struct_defaults) + # 在调用方文件翻译时读取字段默认值,原 pool AST 已 reset 回收 → 常量深拷贝 + # 到 perm_pool(1a 每文件 reset 后 DefaultVal 同样必须跨文件存活) + fe.DefaultVal = self._deep_copy_default_ast(dp_pool_sg, default_val) + else: + fe.Ty = field_ty + fe.AnnotClassName = annot_class_name + fe.DefaultVal = default_val + + struct_entry.FieldCount = idx + 1 + return idx + + def _deep_copy_default_ast(self, pool: memhub.MemBuddy | t.CPtr, + default_val: ast.AST | t.CPtr) -> ast.AST | t.CPtr: + """深拷贝字段默认值 AST 到永久池(仅常量节点),跨 1b reset 存活。 + + 字段默认值(fe.DefaultVal)除定义文件内 _generate_before_init 使用外, + 跨文件结构体构造(_translate_struct_ctor → _apply_struct_defaults)会在 + 调用方文件翻译时读取——原 pool AST 已 reset 回收必须深拷贝。 + 支持 Constant(标量)与 List(列表字面量,如 t.CArray[str] = ["py", "pyw"])。 + 其他非常量默认值(Name/BinOp 等引用表达式)无法安全深拷贝:返回 None + (调用方 fe.DefaultVal 保持 None,仅定义文件内 _generate_before_init + 仍持有原始 pool 指针,不受影响)。 + """ + if default_val is None: + return None + if default_val.kind() == ast.ASTKind.List: + return self._deep_copy_list_ast(pool, default_val) + if default_val.kind() != ast.ASTKind.Constant: + return None + src_c: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(default_val) + dst_c: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)( + pool.alloc(ast.Constant.__sizeof__())) + if dst_c is None: + return None + string.memset(dst_c, 0, ast.Constant.__sizeof__()) + # 拷贝 vtable 指针(AST 是 @t.CVTable,kind() 虚调用依赖首字段 vptr) + vt_ptr: t.CVoid | t.CPtr = t.CVoid( + c.Deref(t.CUInt64T(default_val, t.CPtr), t.CPtr), t.CPtr) + c.DerefAs(dst_c, vt_ptr) + # 拷贝位置字段(报错定位用) + dst_c.lineno = src_c.lineno + dst_c.col_offset = src_c.col_offset + dst_c.end_lineno = src_c.end_lineno + dst_c.end_col_offset = src_c.end_col_offset + # 拷贝常量值(int/float/str/bool 由 const_kind 区分) + dst_c.const_kind = src_c.const_kind + dst_c.int_val = src_c.int_val + dst_c.float_val = src_c.float_val + if src_c.str_val is not None: + s_len: t.CSizeT = string.strlen(src_c.str_val) + s_copy: str = pool.alloc(s_len + 1) + if s_copy is not None: + string.strcpy(s_copy, src_c.str_val) + dst_c.str_val = s_copy + return (ast.AST | t.CPtr)(dst_c) + + def _deep_copy_list_ast(self, pool: memhub.MemBuddy | t.CPtr, + default_val: ast.AST | t.CPtr) -> ast.AST | t.CPtr: + """深拷贝 List 节点(列表字面量默认值)到永久池,跨 1b reset 存活。 + + elts 容器手动在永久池构造(list 的 __pool__ 置 None:深拷贝的 elts + 只被只读访问 get/__len__/迭代,不 append,不会触发 pool 扩容)。 + 元素递归调用 _deep_copy_default_ast(支持 Constant 与嵌套 List)。 + """ + src_l: ast.List | t.CPtr = (ast.List | t.CPtr)(default_val) + dst_l: ast.List | t.CPtr = (ast.List | t.CPtr)( + pool.alloc(ast.List.__sizeof__())) + if dst_l is None: + return None + string.memset(dst_l, 0, ast.List.__sizeof__()) + # 拷贝 vtable 指针(AST 是 @t.CVTable,kind() 虚调用依赖首字段 vptr) + vt_l: t.CVoid | t.CPtr = t.CVoid( + c.Deref(t.CUInt64T(default_val, t.CPtr), t.CPtr), t.CPtr) + c.DerefAs(dst_l, vt_l) + # 拷贝位置字段与 ctx + dst_l.lineno = src_l.lineno + dst_l.col_offset = src_l.col_offset + dst_l.end_lineno = src_l.end_lineno + dst_l.end_col_offset = src_l.end_col_offset + dst_l.ctx = src_l.ctx + # 深拷贝 elts:stdlib 手动构造 list[AST | t.CPtr] 容器 + src_elts_l: list[ast.AST | t.CPtr] | t.CPtr = src_l.elts + if src_elts_l is not None: + cnt_l: t.CSizeT = len(src_elts_l) + lst_copy_l: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)( + pool.alloc(list[ast.AST | t.CPtr].__sizeof__())) + if lst_copy_l is not None: + string.memset(lst_copy_l, 0, list[ast.AST | t.CPtr].__sizeof__()) + lst_copy_l.__count__ = cnt_l + lst_copy_l.__capacity__ = cnt_l + lst_copy_l.__elem_size__ = 8 + lst_copy_l.__pool__ = None + data_l: t.CVoid | t.CPtr = pool.alloc(cnt_l * 8) + if data_l is not None: + string.memset(data_l, 0, cnt_l * 8) + lst_copy_l.__data__ = data_l + li_l: t.CSizeT + for li_l in range(cnt_l): + elem_src_l: ast.AST | t.CPtr = src_elts_l.get(li_l) + if elem_src_l is not None: + elem_dst_l: ast.AST | t.CPtr = self._deep_copy_default_ast(pool, elem_src_l) + if elem_dst_l is not None: + slot_l: ast.AST | t.CPtr = (ast.AST | t.CPtr)( + t.CVoid(t.CUInt64T(data_l) + li_l * 8, t.CPtr)) + slot_l[0] = elem_dst_l + dst_l.elts = lst_copy_l + return (ast.AST | t.CPtr)(dst_l) + + def get_struct_count(self) -> int: + """返回当前已注册的结构体数量""" + return self.StructCount + + def find_struct(self, name: str) -> GenTypes.StructEntry | t.CPtr: + """按类名查找结构体,返回 StructEntry 或 None + + 支持模块限定名(如 "HT.Translator"): + 第一遍精确匹配,第二遍按类名(最后一个 '.' 之后的部分)回退 + """ + if name is None or self.StructTable is None: + return None + # 第一遍:精确匹配 + # StructCount 合理性守卫(内存损坏导致巨大值 → 索引循环假挂起) + if self.StructCount < 0 or self.StructCount > 200000: + VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct)", "STRUCT") + stdlib.exit(1) + for i in range(self.StructCount): + entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i) + if entry is not None and entry.Name is not None: + if string.strcmp(entry.Name, name) == 0: + return entry + # 第二遍:类名回退(处理模块限定名 "HT.Translator" → "Translator") + dot_pos: str = string.strrchr(name, '.') + if dot_pos is not None: + class_name: str = dot_pos + 1 + if class_name is not None and class_name[0] != '\0': + for i in range(self.StructCount): + entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i) + if entry is not None and entry.Name is not None: + if string.strcmp(entry.Name, class_name) == 0: + return entry + return None + + def find_struct_by_module(self, name: str, sha1: str) -> GenTypes.StructEntry | t.CPtr: + """按类名 + SHA1 查找结构体,返回 StructEntry 或 None + + SHA1 非 None 时:精确匹配 name+sha1,未找到返回 None(不回退,避免跨模块同名找错) + SHA1 为 None 时:回退到 find_struct(name) 按类名查找第一个 + """ + if name is None or self.StructTable is None: + return None + # StructCount 合理性守卫(内存损坏导致巨大值 → 索引循环假挂起) + if self.StructCount < 0 or self.StructCount > 200000: + VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct_by_module)", "STRUCT") + stdlib.exit(1) + if sha1 is not None: + for i in range(self.StructCount): + entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i) + if entry is not None and entry.Name is not None: + if string.strcmp(entry.Name, name) == 0: + if entry.ModuleSha1 is not None: + if string.strcmp(entry.ModuleSha1, sha1) == 0: + return entry + # SHA1 查找失败:不回退到 find_struct(会返回跨模块同名错误 entry) + # 返回 None 让调用方创建新类型,避免 Phase B 用错误类型短路 + return None + # 无 SHA1:按类名查找第一个 + return self.find_struct(name) + + def reset_module_methods_emitted(self, sha1: str) -> int: + """回滚指定模块注册类的 MethodsEmitted 标志(Phase A 重试前调用) + + 根因(追加87):Phase A 第 1 遍翻译类方法体时 _translate_oop_methods + 先置 MethodsEmitted=1(防重入)再发射方法;方法体内跨模块调用因依赖 + text.ll 未生成触发 trans._deps_pending → 整文件不写盘下遍重译。但 + MethodsEmitted 存于 perm_pool 分配的 StructEntry,跨 mb.reset_to(mark2) + 存活 → 第 2 遍 existing 分支被 _translate_oop_methods 的 + MethodsEmitted==1 防重复检查拦截 → 类方法(含 __before_init__)永不 + 发射 → 链接 undefined symbol(模块级函数不受此标志保护所以正常, + AssignGenMixin text.ll 空 / HandlesTranslator 有模块函数缺类方法)。 + 按本文件 ModuleSha1 精确回滚,不影响其他已写盘文件的 MethodsEmitted。 + """ + if sha1 is None or self.StructTable is None: + return 0 + if self.StructCount < 0 or self.StructCount > 200000: + VLogger.error(f"StructCount 异常: {self.StructCount} (reset_module_methods_emitted)", "STRUCT") + return 0 + reset_count: int = 0 + for i in range(self.StructCount): + entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i) + if entry is not None: + # 普通类按 ModuleSha1 匹配 + if entry.ModuleSha1 is not None: + if string.strcmp(entry.ModuleSha1, sha1) == 0: + entry.MethodsEmitted = 0 + reset_count += 1 + continue + # 泛型特化类按触发文件 sha1 匹配:特化类 ModuleSha1 是模板 sha1 + # (方法名带模板前缀),无法匹配当前作废文件。不重置则特化方法体 + # 残留 MethodsEmitted=1,下遍不补译 → text.ll 只有 call 无 define + # → ld.lld undefined symbol(list[ast.ClassDef|t.CPtr].* 根因) + if entry.SpecTriggerSha1 is not None: + if string.strcmp(entry.SpecTriggerSha1, sha1) == 0: + entry.MethodsEmitted = 0 + reset_count += 1 + return reset_count + + def find_struct_by_type(self, struct_ty: llvmlite.LLVMType | t.CPtr) -> GenTypes.StructEntry | t.CPtr: + """按类型指针查找结构体(指针值比较),返回 StructEntry 或 None + + 注意: 不能用 `entry.Ty is struct_ty` 的 is 比较——TPV 编译 is 时会触发 + translate_compare 的类型安全检查(is_ptr_type/TypePrint 递归打印), + 对悬空 entry.Ty(1b 泛型特化类注册后被 reset 回收的 pool 指针)解引用崩溃。 + 改用 t.CUInt64T 纯指针值比较,不解引用任何内容。 + """ + if struct_ty is None or self.StructTable is None: + return None + # StructCount 合理性守卫(内存损坏导致巨大值 → 索引循环假挂起) + if self.StructCount < 0 or self.StructCount > 200000: + VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct_by_type)", "STRUCT") + stdlib.exit(1) + st_val: t.CUInt64T = t.CUInt64T(struct_ty) + for i in range(self.StructCount): + entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i) + if entry is not None and entry.Ty is not None: + if t.CUInt64T(entry.Ty) == st_val: + return entry + return None + + def lookup_field(self, struct_ty: llvmlite.LLVMType | t.CPtr, + field_name: str) -> GenTypes.FieldEntry | t.CPtr: + """按结构体类型和字段名查找字段信息 + + 两遍查找策略(跨模块同名类冲突的根本修复): + 第一遍: 类型指针 is 身份比较(最高优先级,类型唯一确定 entry) + 第二遍: 名称回退(is 未匹配时,按类名/strstr 匹配,字段未找到时 continue) + """ + if struct_ty is None or field_name is None or self.StructTable is None: + return None + + # ============================================================ + # 两遍查找策略(跨模块同名类冲突的根本修复): + # + # 第一遍: 用类型指针 is 身份比较(最高优先级) + # - is 匹配唯一确定 entry,字段未找到直接返回 None + # - 规避联合类型 == BUG,且不受遍历顺序影响 + # + # 第二遍: 名称回退(is 未匹配到任何 entry 时才执行) + # - 用于未注册类型或 is 不可靠的场景 + # - 名称匹配但字段未找到时 continue(继续检查其他同名 entry) + # ============================================================ + + # 第一遍: is 身份比较(用 t.CUInt64T 指针值比较,避免 is 编译路径解引用悬空 Ty) + st_lk: t.CUInt64T = t.CUInt64T(struct_ty) + for i in range(self.StructCount): + entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i) + if entry is not None and entry.Ty is not None: + if t.CUInt64T(entry.Ty) == st_lk: + # is 匹配,查找字段 + for fi in range(entry.FieldCount): + fe: GenTypes.FieldEntry | t.CPtr = self._get_field_entry(entry, fi) + if fe is not None and fe.Name is not None: + if string.strcmp(fe.Name, field_name) == 0: + return fe + # is 匹配但字段未找到(类型唯一确定,无需继续) + return None + + # 第二遍: 名称回退(is 未匹配到) + ty_name: str = self._extract_struct_name(struct_ty) + if ty_name is not None: + for i in range(self.StructCount): + entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i) + if entry is not None and entry.Name is not None: + matched: int = 0 + if string.strcmp(entry.Name, ty_name) == 0: + matched = 1 + elif string.strstr(ty_name, entry.Name) is not None: + matched = 1 + if matched != 0: + # 查找字段 + for fi in range(entry.FieldCount): + fe: GenTypes.FieldEntry | t.CPtr = self._get_field_entry(entry, fi) + if fe is not None and fe.Name is not None: + if string.strcmp(fe.Name, field_name) == 0: + return fe + # 名称匹配但字段未找到,继续检查其他同名 entry(跨模块同名) + continue + # 所有条目都未匹配 + return None + + def lookup_field_by_class(self, class_name: str, + field_name: str, + sha1: str = None) -> GenTypes.FieldEntry | t.CPtr: + """按类名和字段名查找字段信息 + + 优先用 SHA1 匹配(跨模块同名类区分),无 SHA1 时按类名查找第一个 + """ + if class_name is None or field_name is None: + return None + + # 优先用 SHA1 匹配(跨模块同名类区分) + # 支持模块限定名:class_name 可能是 "HT.Translator",entry.Name 是 "Translator" + # 先精确匹配,失败后用 strrchr 提取类名部分回退匹配 + if sha1 is not None: + sha1_matched: int = 0 + # 计算类名回退部分("HT.Translator" → "Translator") + bare_name: str = class_name + dot_pos_lfbc: str = string.strrchr(class_name, '.') + if dot_pos_lfbc is not None: + bare_name = dot_pos_lfbc + 1 + if bare_name is None or bare_name[0] == '\0': + bare_name = class_name + for i in range(self.StructCount): + entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i) + if entry is not None and entry.Name is not None: + # 精确匹配或类名回退匹配 + name_match: int = 0 + if string.strcmp(entry.Name, class_name) == 0: + name_match = 1 + elif bare_name is not class_name and string.strcmp(entry.Name, bare_name) == 0: + name_match = 1 + if name_match != 0: + if entry.ModuleSha1 is not None \ + and string.strcmp(entry.ModuleSha1, sha1) == 0: + sha1_matched = 1 + # SHA1 + 类名匹配,查找字段 + for fi in range(entry.FieldCount): + fe: GenTypes.FieldEntry | t.CPtr = self._get_field_entry(entry, fi) + if fe is not None and fe.Name is not None \ + and string.strcmp(fe.Name, field_name) == 0: + return fe + return None + + # 回退: 无 SHA1 或 SHA1 匹配失败,按类名查找第一个 + entry = self.find_struct(class_name) + if entry is None: + # 诊断:目标类未注册 + fb_lfbc: str = VLogger.fmt_buf() + if fb_lfbc is not None: + viperlib.snprintf(fb_lfbc, 1024, + "lookup_field_by_class: 类 '%s' 未注册 (struct_count=%d)", + class_name, self.StructCount) + VLogger.error(fb_lfbc, "STRUCT") + return None + # 先查找字段(诊断/error 之前返回,否则 error 立即退出导致查找永远失败) + for fi in range(entry.FieldCount): + fe: GenTypes.FieldEntry | t.CPtr = self._get_field_entry(entry, fi) + if fe is not None and fe.Name is not None: + if string.strcmp(fe.Name, field_name) == 0: + return fe + # REnum 变体字段别名回退:REnum 类(如 LLVMType)的变体内部字段 + # (Ptr.Pointee 等)不是普通字段,而是 _p1/_p2 槽位别名。此前在调用方 + # (ExprGenMixin 按需过滤 L5046/L5500)回退,但本函数字段未找到的 + # VLogger.error 立即 sys.exit(1),调用方回退永远执行不到("LLVMType 已注册 + # 但字段 Pointee 未找到"四次依旧的根因)。此处直接查变体别名,所有调用方 + # 统一受益。注意:_lookup_renum_field_alias 用 class_name 指针值比较, + # 必须传 entry.Name(register_struct 复制 + _update_renum_alias_class_ptr + # 统一后的池指针),传调用方 class_name(AnnotClassName 等不同指针) + # 恒不匹配 → 返回 -1 → 回退失效。 + import lib.core.Handles.HandlesClassDef as HandlesClassDef + rn_cls_l: str = entry.Name + if rn_cls_l is None: + rn_cls_l = class_name + rn_is_renum_l: int = self.Gen.ClassGenEnum._is_renum_class_name(class_name) + if rn_is_renum_l == 0 and rn_cls_l is not None: + # 类名可能是模块限定名("mod.LLVMType"),REnum 表存裸名,双保险 + rn_is_renum_l = self.Gen.ClassGenEnum._is_renum_class_name(rn_cls_l) + rn_alias_l: int = -1 + if rn_is_renum_l != 0: + rn_alias_l = self.Gen.ClassGenEnum._lookup_renum_field_alias( + rn_cls_l, field_name) + if rn_alias_l < 1 and class_name is not rn_cls_l: + # 双保险:别名表可能仍持有旧 AST 指针(_update_renum_alias_class_ptr + # 未执行/多模块重复注册场景),用调用方 class_name 再试一次 + rn_alias_l = self.Gen.ClassGenEnum._lookup_renum_field_alias( + class_name, field_name) + if rn_alias_l >= 1: + rn_fe_l: GenTypes.FieldEntry | t.CPtr = \ + self.Gen.StructGen._get_field_entry(entry, rn_alias_l) + if rn_fe_l is not None and rn_fe_l.Ty is not None: + return rn_fe_l + # 诊断:找到结构体但字段确实未找到,打印字段表 + # 注意:VLogger.error 会立即退出进程,字段表须在 error 之前用 warning 打印 + for fi in range(entry.FieldCount): + fe: GenTypes.FieldEntry | t.CPtr = self._get_field_entry(entry, fi) + if fe is not None: + fb_fn: str = VLogger.fmt_buf() + if fb_fn is not None: + if fe.Name is not None: + viperlib.snprintf(fb_fn, 1024, " 字段[%d]: '%s'", fi, fe.Name) + else: + viperlib.snprintf(fb_fn, 1024, " 字段[%d]: (null)", fi) + VLogger.warning(fb_fn, "STRUCT") + fb_fields: str = VLogger.fmt_buf() + if fb_fields is not None: + if rn_is_renum_l != 0: + # 报错友好化:REnum 类直接说明是"变体字段别名查找失败",并附 + # entry.Name 与别名槽位结果,一眼可辨"别名未注册"(槽位=-1) + # 还是"class_name 指针未统一"(已注册但传错指针查不到) + viperlib.snprintf(fb_fields, 1024, + "lookup_field_by_class: 类 '%s' 是 REnum 类(FieldCount=%d)," + "变体字段 '%s' 别名查找失败(entry.Name='%s',别名槽位=%d," + "请检查该变体字段是否已注册别名,或 class_name 指针是否统一)", + class_name, entry.FieldCount, field_name, rn_cls_l, rn_alias_l) + else: + viperlib.snprintf(fb_fields, 1024, + "lookup_field_by_class: 类 '%s' 已注册 (FieldCount=%d) 但字段 '%s' 未找到", + class_name, entry.FieldCount, field_name) + VLogger.error(fb_fields, "STRUCT") + # 诊断:找到结构体但字段未找到 + return None + + def get_struct_type(self, class_name: str) -> llvmlite.LLVMType | t.CPtr: + """按类名获取结构体的 LLVM 类型""" + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(class_name) + if entry is not None: + return entry.Ty + return None + + def get_field_by_index(self, class_name: str, + idx: int) -> GenTypes.FieldEntry | t.CPtr: + """按类名和字段索引获取字段信息""" + if class_name is None: + return None + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(class_name) + if entry is None: + return None + if idx < 0 or idx >= entry.FieldCount: + return None + return self._get_field_entry(entry, idx) + + def struct_has_defaults(self, class_name: str) -> int: + """检查结构体是否有任何带默认值的字段,返回 1=有 / 0=无""" + if class_name is None: + return 0 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(class_name) + if entry is None: + return 0 + for fi in range(entry.FieldCount): + fe: GenTypes.FieldEntry | t.CPtr = self._get_field_entry(entry, fi) + if fe is not None and fe.DefaultVal is not None: + return 1 + return 0 + + def get_struct_type_from_value(self, val: llvmlite.Value | t.CPtr) -> llvmlite.LLVMType | t.CPtr: + """从 Value 的类型推断结构体类型 + + 递归解 Ptr:支持 X|t.CPtr 联合简化产生的 Ptr(Ptr(Struct)) 对象指针 + (如运算符重载中间结果 a*2.0 的 Vec3**),否则 try_operator_overload + 重载识别失败回退原生运算,对指针生成非法 sub 指令(llc: invalid + operand type for instruction)。 + """ + if val is None or val.Ty is None: + return None + ty: llvmlite.LLVMType | t.CPtr = val.Ty + while ty is not None: + match ty: + case llvmlite.LLVMType.Ptr(pointee): + ty = pointee + case llvmlite.LLVMType.Struct(fields, fcount, name): + return ty + case _: + return None + return None + + def mark_as_union(self, name: str) -> int: + """标记已注册的结构体为联合体,返回 1=成功 / 0=失败""" + if name is None: + return 0 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name) + if entry is None: + return 0 + entry.IsUnion = 1 + return 1 + + def is_union_by_name(self, name: str) -> int: + """按类名检查是否为联合体,返回 1=是 / 0=否""" + if name is None: + return 0 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name) + if entry is None: + return 0 + return entry.IsUnion + + def is_union_by_type(self, struct_ty: llvmlite.LLVMType | t.CPtr) -> int: + """按类型指针检查是否为联合体,返回 1=是 / 0=否 + + 先尝试类型指针 == 比较,失败时回退到名称匹配 + """ + if struct_ty is None or self.StructTable is None: + return 0 + ty_name: str = self._extract_struct_name(struct_ty) + st_iu: t.CUInt64T = t.CUInt64T(struct_ty) + for i in range(self.StructCount): + entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i) + if entry is not None and entry.Ty is not None: + matched: int = 0 + if t.CUInt64T(entry.Ty) == st_iu: + matched = 1 + elif ty_name is not None and entry.Name is not None: + if string.strcmp(entry.Name, ty_name) == 0: + matched = 1 + elif string.strstr(ty_name, entry.Name) is not None: + matched = 1 + if matched != 0: + return entry.IsUnion + return 0 + + def mark_as_oop(self, name: str) -> int: + """标记已注册的结构体为 OOP,返回 1=成功 / 0=失败""" + if name is None: + return 0 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name) + if entry is None: + return 0 + entry.IsOOP = 1 + return 1 + + def is_oop_by_name(self, name: str) -> int: + """按类名检查是否为 OOP 结构体,返回 1=是 / 0=否""" + if name is None: + return 0 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name) + if entry is None: + return 0 + return entry.IsOOP + + def mark_has_init(self, name: str) -> int: + """标记结构体拥有 __init__ 方法,返回 1=成功 / 0=失败""" + if name is None: + return 0 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name) + if entry is None: + return 0 + entry.HasInit = 1 + return 1 + + def has_init_by_name(self, name: str) -> int: + """按类名检查是否有 __init__ 方法,返回 1=有 / 0=无""" + if name is None: + return 0 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name) + if entry is None: + return 0 + return entry.HasInit + + def mark_has_new(self, name: str) -> int: + """标记结构体拥有 __new__ 方法,返回 1=成功 / 0=失败""" + if name is None: + return 0 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name) + if entry is None: + return 0 + entry.HasNew = 1 + return 1 + + def has_new_by_name(self, name: str) -> int: + """按类名检查是否有 __new__ 方法,返回 1=有 / 0=无""" + if name is None: + return 0 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name) + if entry is None: + return 0 + return entry.HasNew + + def get_class_name_by_type(self, pool: memhub.MemBuddy | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr) -> str: + """按类型指针查找类名,返回类名字符串或 None""" + if struct_ty is None or self.StructTable is None: + return None + st_cn: t.CUInt64T = t.CUInt64T(struct_ty) + for i in range(self.StructCount): + entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i) + if entry is not None and entry.Ty is not None: + if t.CUInt64T(entry.Ty) == st_cn: + return entry.Name + # 回退: 类型指针比较失败时,遍历所有注册的结构体按名称匹配 + # 提取 struct_ty 的 Name 字段(可能是 "SHA1.ClassName" 格式) + ty_name: str = self._extract_struct_name(struct_ty) + if ty_name is not None: + for j in range(self.StructCount): + entry2: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(j) + if entry2 is not None and entry2.Name is not None: + # 构造 "SHA1.ClassName" 格式进行比较 + entry2_sha1: str = entry2.ModuleSha1 + if entry2_sha1 is not None: + full_nm: str = pool.alloc(128) + if full_nm is not None: + viperlib.snprintf(full_nm, 128, "%s.%s", entry2_sha1, entry2.Name) + if string.strcmp(full_nm, ty_name) == 0: + return entry2.Name + # 也直接比较类名(struct_ty 的 Name 可能无 SHA1 前缀) + if string.strcmp(entry2.Name, ty_name) == 0: + return entry2.Name + # 最后回退: 后缀匹配("SHA1.ClassName" 尾部)——比 strstr 子串 + # 匹配安全:特化名 "SHA1.GSList[Param]" 会被基础名 "GSList" 错误 + # 命中(子串),导致链式方法调用 class_name 解析错(如 + # func.Params.append → GSList.append 查找失败 → 兄弟 Mixin 兜底 + # 误匹配 LinkedNode.append,this 前移 sizeof(LinkedNode) 写穿 + # 容器前 48 字节,LLvmLiteTest Test 3 崩溃根因)。 + if entry2.Name is not None and string.strlen(entry2.Name) > 0: + _tlen_cn: t.CSizeT = string.strlen(ty_name) + _nlen_cn: t.CSizeT = string.strlen(entry2.Name) + if _tlen_cn > _nlen_cn and ty_name[_tlen_cn - _nlen_cn - 1] == '.': + _tail_ok_cn: int = 1 + _ti_cn: t.CSizeT + for _ti_cn in range(_nlen_cn): + if ty_name[_tlen_cn - _nlen_cn + _ti_cn] != entry2.Name[_ti_cn]: + _tail_ok_cn = 0 + break + if _tail_ok_cn == 1: + return entry2.Name + return None + + def _extract_struct_name(self, ty: llvmlite.LLVMType | t.CPtr) -> str: + """从 LLVMType 提取 Struct 变体的 Name 字段,返回 None 非 Struct""" + if ty is None: + return None + match ty: + case llvmlite.LLVMType.Struct(fields, fcount, name): + return name + case _: + return None + + def mark_has_vtable(self, name: str) -> int: + """标记结构体拥有虚表,返回 1=成功 / 0=失败""" + if name is None: + return 0 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name) + if entry is None: + return 0 + entry.HasVTable = 1 + return 1 + + def has_vtable_by_name(self, name: str) -> int: + """按类名检查是否有虚表,返回 1=有 / 0=无""" + if name is None: + return 0 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name) + if entry is None: + return 0 + return entry.HasVTable + + def mark_novtable(self, name: str) -> int: + """标记结构体为 NoVTable,返回 1=成功 / 0=失败""" + if name is None: + return 0 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name) + if entry is None: + return 0 + entry.IsNoVTable = 1 + return 1 + + def is_novtable_by_name(self, name: str) -> int: + """按类名检查是否为 NoVTable,返回 1=是 / 0=否""" + if name is None: + return 0 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name) + if entry is None: + return 0 + return entry.IsNoVTable + + def set_parent_name(self, name: str, parent_name: str) -> int: + """设置结构体的父类名,返回 1=成功 / 0=失败""" + if name is None: + return 0 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name) + if entry is None: + return 0 + entry.ParentName = parent_name + return 1 + + def set_parent_names(self, pool: memhub.MemBuddy | t.CPtr, + name: str, names_ptr: t.CSizeT | t.CPtr, + count: int) -> int: + """设置结构体的父类名数组(永久池深拷贝,跨文件永久存活)""" + if name is None: + return 0 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name) + if entry is None: + return 0 + if names_ptr is None or count <= 0: + entry.ParentNames = None + entry.ParentCount = 0 + return 1 + if count > PARENT_MAX: + count = PARENT_MAX + pn_pool: memhub.MemBuddy | t.CPtr = pool + if self.StdlibAlloc != 0: + pn_pool = CompilerFactory.get_perm_pool() + if pn_pool is None: + pn_pool = pool + arr: t.CSizeT | t.CPtr = pn_pool.alloc(8 * count) + if arr is None: + return 0 + for i in range(count): + addr: t.CSizeT = names_ptr[i] + arr[i] = 0 + if addr != 0: + src: str = (str | t.CPtr)(t.CVoid(addr, t.CPtr)) + if src is not None: + slen: t.CSizeT = string.strlen(src) + dup: str = pn_pool.alloc(slen + 1) + if dup is not None: + string.strcpy(dup, src) + arr[i] = t.CSizeT(dup) + entry.ParentNames = t.CSizeT(arr) + entry.ParentCount = count + return 1 + + def get_parent_count(self, name: str) -> int: + """获取父类数量(0=无父类,1=单继承,>1=多继承)""" + if name is None: + return 0 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name) + if entry is None: + return 0 + return entry.ParentCount + + def get_parent_name_at(self, name: str, idx: int) -> str: + """获取第 idx 个父类名,越界返回 None""" + if name is None or idx < 0: + return None + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name) + if entry is None or entry.ParentNames is None: + return None + if idx >= entry.ParentCount: + return None + parr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(entry.ParentNames, t.CPtr)) + addr: t.CSizeT = parr[idx] + if addr == 0: + return None + return (str | t.CPtr)(t.CVoid(addr, t.CPtr)) + + def get_mro_chain(self, pool: memhub.MemBuddy | t.CPtr, + name: str) -> t.CSizeT | t.CPtr: + """MRO 线性化类名数组(深度优先 + 声明顺序 + 去重,含自身)""" + if pool is None or name is None: + return None + arr: t.CSizeT | t.CPtr = pool.alloc(8 * (MRO_MAX + 1)) + if arr is None: + return None + stack: t.CSizeT | t.CPtr = pool.alloc(8 * MRO_MAX) + if stack is None: + return None + visited: t.CSizeT | t.CPtr = pool.alloc(8 * MRO_MAX) + if visited is None: + return None + stack_count: int = 0 + out_count: int = 0 + visit_count: int = 0 + # 初始压入自身 + stack[0] = t.CSizeT(name) + stack_count = 1 + while stack_count > 0: + stack_count -= 1 + cur_addr: t.CSizeT = stack[stack_count] + cur: str = (str | t.CPtr)(t.CVoid(cur_addr, t.CPtr)) + if cur is None: + continue + # 已访问检查(线性搜索) + dup: int = 0 + for vi in range(visit_count): + va: t.CSizeT = visited[vi] + if va != 0: + vn: str = (str | t.CPtr)(t.CVoid(va, t.CPtr)) + if vn is not None and string.strcmp(vn, cur) == 0: + dup = 1 + break + if dup != 0: + continue + # 加入结果与已访问集合 + if out_count < MRO_MAX: + arr[out_count] = t.CSizeT(cur) + out_count += 1 + if visit_count < MRO_MAX: + visited[visit_count] = t.CSizeT(cur) + visit_count += 1 + # 父类逆序压栈(正向 range 计算逆序索引,保证声明顺序弹出) + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(cur) + if entry is not None and entry.ParentCount > 0 and entry.ParentNames is not None: + pc: int = entry.ParentCount + parr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(entry.ParentNames, t.CPtr)) + for pi2 in range(pc): + pi: int = pc - 1 - pi2 + if stack_count < MRO_MAX: + stack[stack_count] = parr[pi] + stack_count += 1 + # 末尾 0 结束 + arr[out_count] = 0 + return arr + + def get_parent_name(self, name: str) -> str: + """获取结构体的父类名,返回 None=无父类""" + if name is None: + return None + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name) + if entry is None: + return None + return entry.ParentName + + def set_vtable_methods(self, name: str, methods: str, count: int) -> int: + """设置虚表方法名数组,返回 1=成功 / 0=失败""" + if name is None: + return 0 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name) + if entry is None: + return 0 + entry.VTableMethods = methods + entry.VTableMethodCount = count + return 1 + + def get_vtable_method_index(self, name: str, method_name: str) -> int: + """获取方法在虚表中的索引,返回 -1=未找到""" + if name is None or method_name is None: + return -1 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name) + if entry is None or entry.VTableMethods is None: + return -1 + # VTableMethods 字段声明为 t.CChar*,但实际存储的是 t.CSizeT 数组 + # 必须转换为 t.CSizeT* 才能正确读取 8 字节指针值 + methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(entry.VTableMethods, t.CPtr)) + for i in range(entry.VTableMethodCount): + mname_addr: t.CSizeT = methods_arr[i] + if mname_addr == 0: + continue + mname: str = (str | t.CPtr)(t.CVoid(mname_addr, t.CPtr)) + if mname is not None and string.strcmp(mname, method_name) == 0: + return i + return -1 + + def get_vtable_method_count(self, name: str) -> int: + """获取虚表方法数量""" + if name is None: + return 0 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name) + if entry is None: + return 0 + return entry.VTableMethodCount + + def get_vtable_method_name(self, name: str, idx: int) -> str: + """获取虚表中第 idx 个方法名,返回 None=越界""" + if name is None or idx < 0: + return None + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name) + if entry is None or entry.VTableMethods is None: + return None + if idx >= entry.VTableMethodCount: + return None + methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(entry.VTableMethods, t.CPtr)) + mname_addr: t.CSizeT = methods_arr[idx] + if mname_addr == 0: + return None + return (str | t.CPtr)(t.CVoid(mname_addr, t.CPtr)) + + def get_field_count(self, name: str) -> int: + """获取结构体字段数量,返回 -1=未找到""" + if name is None: + return -1 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name) + if entry is None: + return -1 + return entry.FieldCount + + def ensure_struct_def_in_module(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + ty: llvmlite.LLVMType | t.CPtr): + """确保跨模块结构体的完整定义在当前模块中可用(供 alloca 使用) + + 处理两种情况: + 1. Struct 值类型:需要完整定义(供 alloca 分配空间) + 2. Ptr(Struct) 指针类型:需要 pointee 至少有 opaque 声明 + """ + if ty is None or mod is None or pool is None: + return + # 指针类型:确保 pointee 至少有 opaque 声明 + match ty: + case llvmlite.LLVMType.Ptr(pointee): + llvmlite.module_ensure_opaque_for_type(mod, pool, ty) + # 如果 pointee 是 Struct,递归复制完整定义 + # (GEP 访问字段需要 sized 类型,仅 opaque 会导致 llc 报错) + if pointee is not None: + self.ensure_struct_def_in_module(pool, mod, pointee) + return + case _: + pass + # 获取结构体名称(非 Struct 类型返回 None) + sname: str = llvmlite.get_struct_name(ty) + if sname is None: + return + # 检查是否为跨模块引用(名称包含 '.') + if string.strchr(sname, 46) is None: + return # 非跨模块引用,无需处理 + # 提取类名(第一个 '.' 之后的部分) + # 必须用 strchr 而非 strrchr:泛型特化名如 "list[ast.AST|t.CPtr]" + # 内部含 '.'(ast.AST),strrchr 会错误地把类名解析为 "AST|t.CPtr]" + dot_pos: str = string.strchr(sname, '.') + if dot_pos is None: + return + class_name: str = dot_pos + 1 + if class_name is None or class_name[0] == '\0': + return + # 提取 SHA1(sname 到 dot_pos 之间,用 strlen 避免指针减法) + total_len: t.CSizeT = string.strlen(sname) + class_name_len: t.CSizeT = string.strlen(class_name) + sha1_len: t.CSizeT = total_len - class_name_len - 1 + sha1_buf: str = pool.alloc(32) + if sha1_buf is None: + return + # 32 字节缓冲:strncpy 不截断,前缀超过 31 字符会越界写 + 手动 NUL 再越界 + sha1_cp: t.CSizeT = sha1_len + if sha1_cp > 31: + sha1_cp = 31 + string.strncpy(sha1_buf, sname, sha1_cp) + sha1_buf[sha1_cp] = '\0' + # 按类名 + SHA1 查找结构体定义 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct_by_module(class_name, sha1_buf) + if entry is None: + # 回退到按类名查找(可能找到不同模块的同名类,但总比没有好) + entry = self.find_struct(class_name) + if entry is None: + return + if entry.Ty is None: + return + # 将完整定义添加到当前模块(会替换已存在的 opaque 声明) + llvmlite.module_add_named_type(mod, pool, entry.Ty) + # 递归扫描字段类型,确保值类型子结构体(如 WIN32_FIND_DATAA 中的 FILETIME) + # 也有完整定义。指针类型字段只需 opaque 声明(已由 module_ensure_opaque_for_type 处理)。 + self._ensure_field_types_in_module(pool, mod, entry.Ty) + + def _ensure_field_types_in_module(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + ty: llvmlite.LLVMType | t.CPtr): + """递归扫描类型树,确保值类型子结构体有完整定义""" + if ty is None or mod is None or pool is None: + return + # 嵌套 match 遍历类型树 + match ty: + case llvmlite.LLVMType.Struct(fields, fcount, sname): + # 遍历字段链表 + if fields is not None: + fld: llvmlite.ParamNode | t.CPtr = fields + cnt_ef: t.CInt = 0 + while fld is not None: + # 步数守卫:字段链表成环(内存损坏)导致无限遍历挂起 + # (G3 LinkedNode.prepend 挂起候选),超限立即报错终止 + cnt_ef += 1 + if cnt_ef > 100000: + VLogger.error( + "字段链表疑似成环(_ensure_field_types_in_module),强制终止", + "STRUCT") + stdlib.exit(1) + if fld.Ty is not None: + # 值类型子结构体(如 FILETIME)需要完整定义 + match fld.Ty: + case llvmlite.LLVMType.Struct(f2, fc2, n2): + self.ensure_struct_def_in_module(pool, mod, fld.Ty) + case _: + pass + self._ensure_field_types_in_module(pool, mod, fld.Ty) + fld = fld.Next + case llvmlite.LLVMType.Ptr(pointee): + # 指针类型:pointee 只需 opaque 声明,不需要完整定义 + # 但如果 pointee 是 Struct,确保 opaque 声明存在 + if pointee is not None: + llvmlite.module_ensure_opaque_for_type(mod, pool, ty) + case llvmlite.LLVMType.Array(elem_ty, acount): + # 数组类型:元素如果是值类型结构体,需要完整定义 + # (如 zhuff_decode_tree = {MemManager*, [576 x zhuff_decode_node], + # i32, i32}——Array 元素 node 只递归字段不发射定义 → llc "use of + # undefined type named '...zhuff_decode_node'",ZlibTest 根因) + if elem_ty is not None: + match elem_ty: + case llvmlite.LLVMType.Struct(_, _, _): + self.ensure_struct_def_in_module(pool, mod, elem_ty) + case _: + pass + self._ensure_field_types_in_module(pool, mod, elem_ty) + case _: + pass + + def get_field_name_ptr(self, fe: GenTypes.FieldEntry | t.CPtr) -> str: + """获取 FieldEntry 的字段名,返回 None=未设置""" + if fe is None: + return None + return fe.Name + + def get_field_type_ptr(self, fe: GenTypes.FieldEntry | t.CPtr) -> llvmlite.LLVMType | t.CPtr: + """获取 FieldEntry 的字段类型,返回 None=未设置""" + if fe is None: + return None + return fe.Ty + + def get_field_default_ptr(self, fe: GenTypes.FieldEntry | t.CPtr) -> ast.AST | t.CPtr: + """获取 FieldEntry 的默认值 AST 节点,返回 None=无默认值""" + if fe is None: + return None + return fe.DefaultVal + + def get_field_annot_class_name(self, fe: GenTypes.FieldEntry | t.CPtr) -> str: + """获取 FieldEntry 的原始类型注解类名,返回 None=未设置""" + if fe is None: + return None + return fe.AnnotClassName diff --git a/App/lib/core/Gen/TranslatorGenMixin.vp b/App/lib/core/Gen/TranslatorGenMixin.vp index b3ae03c..337d9b8 100644 --- a/App/lib/core/Gen/TranslatorGenMixin.vp +++ b/App/lib/core/Gen/TranslatorGenMixin.vp @@ -1,799 +1,793 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import viperlib -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesBody as HandlesBody -import lib.core.Handles.HandlesFunctions as HandlesFunctions -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.Handles.ExprCallBase as ExprCallBase - - -# ============================================================ -# TranslatorGenMixin - 翻译驱动 Mixin(对象化 P6-E) -# -# 从 HandlesMain.vp / HandlesTranslator.vp 迁移:模块级纯函数 -# (trans 首参)→ 类方法。包含: -# - 模块级翻译入口(translate_children/create_wrapper_main/ -# handle_module_level_var 等,原 HandlesMain.vp) -# - global/nonlocal 名称管理辅助函数(原 HandlesTranslator.vp) -# -# 迁移原则(与 P2-P5 一致,行为零变化): -# 1. 方法保留原函数签名(含 trans/pool 首参),仅函数体内的 -# 本模块函数调用改为 self.xxx(...) -# 2. 外部模块调用(HandlesType.xxx/HandlesVar.xxx 等)保留模块前缀 -# 3. HandlesMain/HandlesTranslator 原函数保留为"委托":本地模块级 -# 单例 _g_gen(BuildPipeline/main 注入)cast 成 Generator 类型 -# 4. 嵌套函数保持嵌套 -# -# 常量(MAX_VARS/MAX_FUNCS/MAX_GLOBAL_NAMES)与原模块保持一致。 -# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 -# ============================================================ - - -# ============================================================ -# 常量(与 HandlesTranslator 保持一致) -# ============================================================ -MAX_VARS: t.CDefine = 1024 -MAX_FUNCS: t.CDefine = 1024 -MAX_GLOBAL_NAMES: t.CDefine = 32 - - -# ============================================================ -# TranslatorGenMixin - 翻译驱动(模块级翻译入口 + 作用域名称管理) -# ============================================================ -@t.NoVTable -class TranslatorGenMixin: - """翻译驱动 Mixin(P6 方法化)""" - - # ============================================================ - # _register_cexport_from_funcdef - Phase 1a 预注册 CExport/State 函数 - # - # 解决翻译顺序依赖问题:Phase 1b 按字母序翻译,后翻译的模块的 - # CExport 函数无法被先翻译的模块正确识别为裸名调用。 - # Phase 1a 预注册所有 CExport/State 函数名到全局表。 - # ============================================================ - def _register_cexport_from_funcdef(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """预注册 CExport/State 函数到全局表(仅注册,不生成 IR)""" - fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node) - if fd is None or fd.name is None: - return 0 - if trans is None or trans.ModuleSha1 is None: - return 0 - - # 检查返回类型是否有 CExport 或 State 标记 - has_export: int = 0 - has_state: int = 0 - if fd.returns is not None: - has_export = HandlesType.has_decorator_marker(fd.returns, "CExport") - has_state = HandlesType.has_decorator_marker(fd.returns, "State") - - if has_export != 0 or has_state != 0: - ExprCallBase.register_cexport_func(trans.ModuleSha1, fd.name) - - return 0 - - # ============================================================ - # translate_children - 遍历 AST 子节点并分派翻译 - # - # 对应 TransPyC translator._translate_children() - # 共享状态从 trans 获取,imported_modules/from_imports 更新到 trans - # ============================================================ - def translate_children(self, trans: HT.Translator | t.CPtr, - tree: ast.AST | t.CPtr) -> int: - """遍历 tree.children 并翻译每个子节点 - - Args: - trans: 翻译器(含所有共享状态) - tree: AST 模块节点 - - Returns: - t.CInt: 新增的变量数 - """ - ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children - if ch is None: - return 0 - - cn_count: t.CSizeT = len(ch) - added_total: int = 0 - - for ci in range(cn_count): - child: ast.AST | t.CPtr = ch.get(ci) - if child is None: continue - kd: int = child.kind() - - # _declare_only == 0 时,_translate_module_level 已预处理导入语句, - # 此处跳过避免重复处理(from_imports 条目重复) - if trans._declare_only == 0 and (kd == ast.ASTKind.Import or kd == ast.ASTKind.ImportFrom): - continue - if kd == ast.ASTKind.Import: - HandlesImports.translate_import(trans, child) - elif kd == ast.ASTKind.ImportFrom: - HandlesImports.translate_import_from_module(trans, child) - HandlesImports.translate_import_from_names(trans, child) - elif kd == ast.ASTKind.FunctionDef: - # Phase 1a 声明模式:只注册 CExport/State 函数到全局表(解决翻译顺序依赖) - # Phase 1b 全量翻译:正常翻译函数体 - if trans._declare_only == 0: - added: int = HandlesFunctions.translate_function_def(trans, child) - added_total += added - elif trans._declare_only == 1: - self._register_cexport_from_funcdef(trans, child) - # 预解析函数签名类型,触发泛型类特化(如 numpy 的 _empty_like - # 签名 ndarray[t.CDouble] → 特化结构体注册)。 - # 1a 阶段在 mark1 之前,特化结构体的 Ty/Fields 分配在 mark1 前, - # 不被 1b 的 mark/reset 回收 → 避免 Phase2 翻译 App 文件时 UAF - # (Phase1 1b 才触发特化时,结构体 Ty/Fields 在 pool 被 reset 覆写)。 - # 仅触发特化,不验证结果(1b 全量翻译时仍会重新解析)。 - self._prescan_funcdef_signatures(trans, child) - elif kd == ast.ASTKind.ClassDef: - # ClassDef 在模块级直接处理(不需要 builder) - # _declare_only=2(import扫描模式)时跳过,只处理 import 依赖 - if trans._declare_only != 2: - HandlesClassDef.translate_class_def(trans, child) - elif trans._declare_only == 0 and trans._cur_builder is not None: - # 有 builder → 委托 HandlesBody 分派 - added = HandlesBody.translate_stmt(trans, child) - added_total += added - elif kd == ast.ASTKind.AnnAssign and trans._declare_only != 2: - # 模块级 AnnAssign - # _declare_only=2(import扫描模式)时跳过 - # _declare_only=1(struct注册模式)时只处理 CDefine(在 handle_module_level_var 内部判断) - # _declare_only=0(全量翻译)时处理所有模块级 AnnAssign - added = self.handle_module_level_var(trans, child) - added_total += added - elif trans._declare_only == 0 and kd == ast.ASTKind.Assign: - # 无 builder 的模块级 Assign → 创建全局变量(仅全量翻译模式) - added = self.handle_module_level_var(trans, child) - added_total += added - - return added_total - - # ============================================================ - # _prescan_funcdef_signatures - 1a 阶段预解析模块级函数签名 - # - # 触发泛型类特化(如 numpy 的 _empty_like 签名 ndarray[t.CDouble]), - # 使特化结构体在 mark1 前注册(Ty/Fields 不被 1b 的 mark/reset 回收), - # 避免 Phase2 翻译 App 文件时访问悬空结构体(UAF)。 - # 仅解析类型触发特化,不验证结果(1b 全量翻译时重新解析)。 - # ============================================================ - def _prescan_funcdef_signatures(self, trans: HT.Translator | t.CPtr, - fd: ast.FunctionDef | t.CPtr) -> None: - """预解析模块级函数签名的返回/参数类型,触发泛型类特化""" - if trans is None or fd is None: - return - pool: memhub.MemBuddy | t.CPtr = trans.Pool - if pool is None: - return - imp: str = trans._imported_modules - fi: str = trans._from_imports - if fd.returns is not None: - HandlesType.resolve_annotation_type(pool, fd.returns, imp, fi, trans) - if fd.args is not None: - ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args) - if ags.args is not None: - al: list[ast.AST | t.CPtr] | t.CPtr = ags.args - an: t.CSizeT = len(al) - ai: t.CSizeT - for ai in range(an): - ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(al.get(ai)) - if ag is not None and ag.annotation is not None: - HandlesType.resolve_annotation_type(pool, ag.annotation, imp, fi, trans) - - # ============================================================ - # _build_array_initializer_text - 从 AST List 生成 LLVM IR 数组初始化器 - # - # 生成格式: [N x elem_ty] [elem_ty val0, elem_ty val1, ...] - # 用于模块级 t.CArray 列表字面量初始化(不依赖 builder,直接生成常量初始化器) - # ============================================================ - def _build_array_initializer_text(self, pool: memhub.MemBuddy | t.CPtr, - var_ty: llvmlite.LLVMType | t.CPtr, - list_node: ast.List | t.CPtr) -> str: - """从 AST List 节点生成 LLVM IR 数组初始化器文本,None 失败""" - if var_ty is None or list_node is None: - return None - - # 重新进行类型转换,确保 TPV 编译器正确识别 ast.List 类型 - # (避免 init_list_node 初始值为 None 时类型推断退化为 t.CPtr) - ln: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node) - if ln is None: - return None - - # 从 var_ty 提取数组元素类型和数量 - elem_ty: llvmlite.LLVMType | t.CPtr = None - arr_count: t.CInt = 0 - match var_ty: - case llvmlite.LLVMType.Array(et, cnt): - elem_ty = et - arr_count = cnt - - if elem_ty is None or arr_count <= 0: - return None - - # 确定元素类型的 IR 表示 - elem_ir_ty: str = "i8" - match elem_ty: - case llvmlite.LLVMType.Int(bits): - if bits == 8: - elem_ir_ty = "i8" - elif bits == 16: - elem_ir_ty = "i16" - elif bits == 32: - elem_ir_ty = "i32" - elif bits == 64: - elem_ir_ty = "i64" - - # 获取列表元素(通过 ln.elts 而非 list_node.elts,确保类型正确识别) - elts: list[ast.AST | t.CPtr] | t.CPtr = ln.elts - if elts is None: - return None - elts_count: t.CSizeT = len(elts) - - # 计算缓冲区大小: 每个元素最多 "i32 -9223372036854775808, " 约 26 字符 - # 按数组声明长度 arr_count 计算(元素不足时补零,可能多于 elts_count) - cnt_total: t.CSizeT = t.CSizeT(arr_count) - buf_size: t.CSizeT = 64 + cnt_total * 32 - buf: str = pool.alloc(buf_size) - if buf is None: - return None - - # 写入前缀: "["(类型前缀由 _print_global 输出,初始化器只需元素列表) - written: t.CInt = viperlib.snprintf(buf, buf_size, "[") - pos: t.CSizeT = t.CSizeT(written) - - # 逐个元素写入:元素数必须与数组声明长度 arr_count 一致, - # 列表元素不足时补零(如 g_arr: t.CArray[t.CInt, 4] = [0] → - # [i32 0, i32 0, i32 0, i32 0]),否则 llc 报 - # "constant expression type mismatch: got type '[1 x i32]' but expected '[4 x i32]'" - i: t.CSizeT = 0 - while i < cnt_total: - elem_val: t.CInt64T = 0 - if i < elts_count: - elem_node: ast.AST | t.CPtr = elts.get(i) - # 直接从 Constant 节点提取 int_val(避免 extract_cdefine_int_value 的 t.CInt 截断) - if elem_node is not None: - ek: int = elem_node.kind() - if ek == ast.ASTKind.Constant: - ec: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(elem_node) - if ec is not None and ec.const_kind == ast.CONST_INT: - elem_val = ec.int_val - elif ek == ast.ASTKind.UnaryOp: - # 负数: UnaryOp(USub, Constant) - elem_val = HandlesAnnAssign.extract_cdefine_int_value(elem_node) - if i > 0: - written = viperlib.snprintf(buf + pos, buf_size - pos, ", ") - pos += t.CSizeT(written) - written = viperlib.snprintf(buf + pos, buf_size - pos, "%s %lld", elem_ir_ty, elem_val) - pos += t.CSizeT(written) - i += 1 - - # 写入后缀 "]" - viperlib.snprintf(buf + pos, buf_size - pos, "]") - return buf - - # ============================================================ - # _build_string_array_initializer_text - 字符串字面量初始化数组全局 - # - # t.CArray[t.CChar, N] = "..." → [i8 b0, i8 b1, ..., i8 0, ...] - # (字符串字节 + 零填充到数组长度;空串返回 zeroinitializer)。 - # 此前统一走字符串指针 GEP 初始化器 → @g = global [N x i8] - # 类型不匹配(llc constant expression type mismatch, - # pyzlib_error_msg = global [512 x i8] 根因)。 - # ============================================================ - def _build_string_array_initializer_text(self, pool: memhub.MemBuddy | t.CPtr, - var_ty: llvmlite.LLVMType | t.CPtr, - str_val: str) -> str: - """字符串字面量初始化数组全局,返回初始化器文本或 None""" - if var_ty is None or str_val is None: - return None - arr_count: t.CInt = 0 - match var_ty: - case llvmlite.LLVMType.Array(_, cnt): - arr_count = cnt - if arr_count <= 0: - return None - slen: t.CSizeT = string.strlen(str_val) - if slen == 0: - return "zeroinitializer" - buf_size: t.CSizeT = 64 + t.CSizeT(arr_count) * 16 - buf: str = pool.alloc(buf_size) - if buf is None: - return None - written: t.CInt = viperlib.snprintf(buf, buf_size, "[") - pos: t.CSizeT = t.CSizeT(written) - i: t.CSizeT = 0 - while i < t.CSizeT(arr_count): - if i > 0: - written = viperlib.snprintf(buf + pos, buf_size - pos, ", ") - pos += t.CSizeT(written) - bv: t.CInt64T = 0 - if i < slen: - bv = t.CInt64T(str_val[i]) - written = viperlib.snprintf(buf + pos, buf_size - pos, "i8 %lld", bv) - pos += t.CSizeT(written) - i += 1 - viperlib.snprintf(buf + pos, buf_size - pos, "]") - return buf - - # ============================================================ - # _build_string_ptr_initializer - 为字符串字面量初始化指针类型全局变量 - # - # 创建内部字符串常量全局 @.str.{var_name} = private constant [len+1 x i8] c"...\00" - # 返回 GEP 初始化器文本: getelementptr inbounds ([len+1 x i8], [len+1 x i8]* @.str.{var_name}, i32 0, i32 0) - # 用于 b64_tab: t.CArray[t.CChar, None] = "ABC..." 等字符串初始化指针类型 - # ============================================================ - def _build_string_ptr_initializer(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - var_name: str, - str_val: str) -> str: - """为字符串字面量创建内部常量全局并返回 GEP 初始化器文本,None 失败""" - if str_val is None or var_name is None: - return None - - # 构造内部字符串常量名称: .str.{var_name} - str_name_buf: str = pool.alloc(64) - if str_name_buf is None: - return None - viperlib.snprintf(str_name_buf, 64, ".str.%s", var_name) - - # 调用 llvmlite.create_global_string 创建字符串常量全局 - str_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.create_global_string( - pool, mod, str_name_buf, str_val) - if str_gv is None: - return None - - # 生成 GEP 初始化器文本 - str_len: t.CSizeT = string.strlen(str_val) - init_buf: str = pool.alloc(128) - if init_buf is None: - return None - viperlib.snprintf(init_buf, 128, - "getelementptr inbounds ([%d x i8], [%d x i8]* @%s, i32 0, i32 0)", - str_len + 1, str_len + 1, str_name_buf) - return init_buf - - # ============================================================ - # handle_module_level_var - 模块级变量声明 → 创建 LLVM 全局变量 - # - # 当用户已定义 main(无 wrapper main builder)时,模块级 - # AnnAssign/Assign 创建全局变量 @var_name 并注册到 SymTab 模块作用域 - # 支持整数、列表字面量、字符串字面量初始值 - # ============================================================ - def handle_module_level_var(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """处理模块级变量声明,创建全局变量""" - pool: memhub.MemBuddy | t.CPtr = trans.Pool - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - - # CDefine 注解: 编译期常量,不创建全局变量 - # 注册到全局 CDefine 表供 t.CArray[elem_ty, NAME] 解析 - k: int = node.kind() - if k == ast.ASTKind.AnnAssign: - aa_cd: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) - if aa_cd is not None and aa_cd.target is not None: - if aa_cd.target.kind() == ast.ASTKind.Name: - nm_cd: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa_cd.target) - if nm_cd.id is not None: - if HandlesAnnAssign.is_cdefine_annotation(aa_cd.annotation) != 0: - # 浮点/整数自动识别注册(浮点 CDefine 如 vipermath U_M_PI) - HandlesAnnAssign._register_cdefine_from_value( - pool, nm_cd.id, aa_cd.value) - return 0 - # CTypedef 注解(如 posix.vp mode_t: t.CTypedef = t.CUInt32T): - # 不创建全局变量——否则生成 @mode_t 符号 → 链接 duplicate - # symbol warning。预注册阶段(forward_declare_functions - # 之前)按需注册到 CTypedef 表:翻译期表已被 clear_ctypedefs - # 清空(每文件隔离),若不在此时注册,S_ISREG(mode: mode_t) - # 等函数参数注解在 FuncGenDef 正式翻译时查表失败 → - # NameError: mode_t(AstTest/posix.vp 根因;模块级 AnnAssign - # 经本函数分派,不经过 AnnAssignHandle.Handle 的注册分支)。 - if HandlesAnnAssign.is_ctypedef_annotation(aa_cd.annotation) != 0: - ctd_str: str = HandlesType._get_type_name_from_annotation( - pool, aa_cd.value) - if ctd_str is not None: - HandlesType.register_ctypedef(pool, nm_cd.id, ctd_str) - return 0 - - # _declare_only=1(struct注册模式)时只处理 CDefine,不创建全局变量 - # CDefine 已在上面处理并返回,到这里说明不是 CDefine,直接跳过 - if trans._declare_only == 1: - return 0 - - var_name: str = None - var_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - init_val: t.CInt64T = 0 - init_kind: int = 0 # 0=none, 1=int, 2=list, 3=str - init_str_val: str = None - init_list_node: ast.List | t.CPtr = None - - if k == ast.ASTKind.AnnAssign: - aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) - if aa is None or aa.target is None: - return 0 - if aa.target.kind() != ast.ASTKind.Name: - return 0 - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) - var_name = nm.id - # 解析类型 - if aa.annotation is not None: - resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, aa.annotation, trans._imported_modules, trans._from_imports, trans) - if resolved is not None: - var_ty = resolved - # 解析初始值(支持整数、列表字面量、字符串字面量) - if aa.value is not None: - val_kind: int = aa.value.kind() - if val_kind == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(aa.value) - if cn.const_kind == ast.CONST_INT: - init_val = cn.int_val - init_kind = 1 - elif cn.const_kind == ast.CONST_STR: - init_str_val = cn.str_val - init_kind = 3 - elif val_kind == ast.ASTKind.List: - init_list_node = (ast.List | t.CPtr)(aa.value) - init_kind = 2 - elif k == ast.ASTKind.Assign: - asgn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node) - if asgn is None or asgn.targets is None: - return 0 - targets: list[ast.AST | t.CPtr] | t.CPtr = asgn.targets - if len(targets) < 1: - return 0 - t0: ast.AST | t.CPtr = targets.get(0) - if t0 is None or t0.kind() != ast.ASTKind.Name: - return 0 - nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(t0) - var_name = nm2.id - if asgn.value is not None: - val_kind2: int = asgn.value.kind() - if val_kind2 == ast.ASTKind.Constant: - cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(asgn.value) - if cn2.const_kind == ast.CONST_INT: - init_val = cn2.int_val - init_kind = 1 - elif cn2.const_kind == ast.CONST_STR: - init_str_val = cn2.str_val - init_kind = 3 - elif val_kind2 == ast.ASTKind.List: - init_list_node = (ast.List | t.CPtr)(asgn.value) - init_kind = 2 - - if var_name is None: - return 0 - - # __all__ 是 Python 模块元数据(公开名列表),无运行时语义: - # StubGen 的 .vpi 不为其生成 stub 声明(无注解模块级赋值不产出 vpi - # 条目),此处同样跳过全局创建——否则无注解 list-of-strings 全局 - # 类型推断缺失(var_ty 默认 i32)→ _build_array_initializer_text - # 返回 None → fail-fast "初始化器构建失败" 误报 - # (Projectrans/__init__.vp 追加83 根因)。与 CDefine/CTypedef - # 同类:编译期/元数据实体不落入 LLVM 全局。 - if string.strcmp(var_name, "__all__") == 0: - return 0 - - # 检查是否已注册 - existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( - trans.SymTab, var_name) - if existing is not None: - return 0 - - # 创建全局变量 @var_name - # 先确保 var_ty 中的跨模块结构体类型在模块中有 opaque 声明 - # 否则 @var_name = global %"sha1.ClassName"* zeroinitializer 会报 - # "use of undefined type named 'sha1.ClassName'" 错误 - # (如 _mbuddy: memhub.MemManager | t.CPtr → Ptr(Struct("aeb3...MemManager"))) - llvmlite.module_ensure_opaque_for_type(mod, pool, var_ty) - # 模块级全局命名带 SHA1 前缀(对齐函数名 mangling):多个模块声明同名 - # 全局(如 _mbuddy)时各自独立命名,消除 ld.lld duplicate symbol。 - # SymTab 注册 key 保持裸名(查找逻辑零改动),LLVM 符号名用 mangled 名。 - mangled_name: str = HandlesFunctions._mangle_name(trans, var_name) - gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, mangled_name, var_ty) - if gv is None: - return 0 - llvmlite.module_add_global(mod, gv) - - # 设置初始值(有初始值时清除 external linkage,因为 LLVM 22+ 不允许 external global 带初始值) - gv.Linkage = None - if init_kind == 1: - # 整数初始值 - init_buf: str = pool.alloc(48) - if init_buf is not None: - viperlib.snprintf(init_buf, 48, "%lld", init_val) - gv.Initializer = init_buf - elif init_kind == 2: - # 列表字面量 → 数组初始化器 [N x elem_ty] [elem_ty val0, ...] - arr_init: str = self._build_array_initializer_text(pool, var_ty, init_list_node) - if arr_init is not None: - gv.Initializer = arr_init - else: - # 初始化器构建失败:直接报错终止(fail-fast),不再回退 zeroinitializer - HandlesType.fatal_error(node, f"模块级变量 '{var_name}' 初始化器构建失败", "TypeError") - elif init_kind == 3: - # 字符串字面量初始化 - # 数组类型(t.CArray[t.CChar, N]):字节数组初始化器(字符串内容 + 零填充) - # ——此前统一走字符串指针 GEP 初始化器 → @g = global [N x i8] 类型 - # 不匹配(llc constant expression type mismatch,pyzlib_error_msg 根因) - is_arr_g: int = 0 - match var_ty: - case llvmlite.LLVMType.Array(_, _): - is_arr_g = 1 - case _: - pass - if is_arr_g != 0: - arr_str_init: str = self._build_string_array_initializer_text( - pool, var_ty, init_str_val) - if arr_str_init is not None: - gv.Initializer = arr_str_init - else: - HandlesType.fatal_error( - node, f"模块级数组变量 '{var_name}' 字符串初始化器构建失败", "TypeError") - else: - # 指针类型(如 b64_tab: t.CArray[t.CChar, None] = "ABC..."): - # 创建字符串常量全局 + GEP 引用 - str_init: str = self._build_string_ptr_initializer(pool, mod, var_name, init_str_val) - if str_init is not None: - gv.Initializer = str_init - else: - HandlesType.fatal_error( - node, f"模块级变量 '{var_name}' 初始化器构建失败", "TypeError") - else: - # 使用 zeroinitializer 而非 "0":指针类型必须用 null/zeroinitializer, - # 整数/聚合类型也兼容 zeroinitializer,避免 "integer constant must have integer type" - gv.Initializer = "zeroinitializer" - - # 创建 Value 引用(@mangled_name, 类型为 var_ty*) - var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty) - ref_name: str = pool.alloc(96) - if ref_name is not None: - # mangled 名带 SHA1 前缀(数字开头),引用必须加引号(对齐 make_global_ref) - if HandlesClassDef._vtable_name_needs_quote(mangled_name) != 0: - viperlib.snprintf(ref_name, 96, "@\"%s\"", mangled_name) - else: - viperlib.snprintf(ref_name, 96, "@%s", mangled_name) - gv_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, var_ptr_ty, ref_name) - - # 注册到模块作用域 - if HandlesVar.define_module_var(trans.SymTab, var_name, gv_ref) == 0: - # 设置 AnnotClassName(联合类型如 Logger|t.CPtr 简化为 Ptr(i8) 时, - # 属性访问需要通过 AnnotClassName 回退到类名查找结构体) - if k == ast.ASTKind.AnnAssign: - aa_ml: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) - if aa_ml is not None and aa_ml.annotation is not None: - cls_nm_ml: str = HandlesType.extract_class_name_from_annotation( - aa_ml.annotation, trans._imported_modules, pool) - if cls_nm_ml is not None: - HandlesVar.set_var_annot_class_name( - trans.SymTab, var_name, cls_nm_ml) - return 1 - return 0 - - # ============================================================ - # create_wrapper_main - 创建包装 main 函数 - # - # 当用户未定义 main 函数时调用。 - # 创建 main() -> i32 函数 → 设置 trans._cur_func/_cur_builder → - # 预扫描 alloca → 翻译子节点 → ret 0 - # ============================================================ - def create_wrapper_main(self, trans: HT.Translator | t.CPtr, - tree: ast.AST | t.CPtr, - i32_ty: llvmlite.LLVMType | t.CPtr) -> int: - """创建包装 main 函数并翻译所有顶层语句 - - Args: - trans: 翻译器(含所有共享状态) - tree: AST 模块节点 - i32_ty: i32 LLVMType - - Returns: - t.CInt: 新增的变量数 - """ - pool: memhub.MemBuddy | t.CPtr = trans.Pool - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - - main_func: llvmlite.Function | t.CPtr = llvmlite.create_function( - pool, mod, "main", i32_ty) - if main_func is None: - VLogger.error("CreateFunction main returned NULL", "TR") - return 0 - - entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, main_func, "entry") - if entry_blk is None: - VLogger.error("CreateBlock returned NULL", "TR") - return 0 - - builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, main_func) - if builder is None: - VLogger.error("NewBuilder returned NULL", "TR") - return 0 - llvmlite.position_at_end(builder, entry_blk) - - # 设置当前翻译上下文(供 Handle 通过 self.Trans._cur_builder 访问) - trans._cur_func = main_func - trans._cur_builder = builder - - # 预处理模块级变量:为 AnnAssign/Assign 创建 LLVM 全局变量 - # 必须在 pre_scan_allocas 之前执行,否则 PreScan 会创建局部 alloca, - # 导致其他函数通过 SSA 编号引用 wrapper main 的局部变量(无效 IR) - ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children - if ch is not None: - cn_count: t.CSizeT = len(ch) - for ci in range(cn_count): - child: ast.AST | t.CPtr = ch.get(ci) - if child is not None: - kd: int = child.kind() - if kd == ast.ASTKind.AnnAssign or kd == ast.ASTKind.Assign: - self.handle_module_level_var(trans, child) - - # 预扫描顶层语句:为函数内 AnnAssign 提前创建 alloca - # (模块级变量已在上面注册到模块作用域,PreScan 的 lookup_current 会跳过它们) - if ch is not None: - for ci in range(cn_count): - child: ast.AST | t.CPtr = ch.get(ci) - if child is not None: - HandlesBody.pre_scan_allocas(trans, child) - - # 翻译子节点 - added_total: int = self.translate_children(trans, tree) - - # 返回 0 - zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - llvmlite.build_ret(builder, zero_val) - - return added_total - - # ============================================================ - # global/nonlocal 名称管理(迁移自 HandlesTranslator.vp 模块级函数) - # ============================================================ - def add_global_name(self, trans: HT.Translator | t.CPtr, name: str): - """添加一个 global 变量名""" - if trans is None or name is None: - return - if trans._global_names is None: - return - # 检查是否已存在 - if self.is_global_name(trans, name) != 0: - return - if trans._global_name_count >= MAX_GLOBAL_NAMES: - pool_err: memhub.MemBuddy | t.CPtr = trans.Pool - err_buf: str = None - if pool_err is not None: - err_buf = pool_err.alloc(256) - if err_buf is not None: - viperlib.snprintf(err_buf, 256, "global 变量数量超过上限 MAX_GLOBAL_NAMES=%d,请减少 global 声明或增大 MAX_GLOBAL_NAMES", MAX_GLOBAL_NAMES) - VLogger.error(err_buf, "ScopeDecl") - else: - VLogger.error("global 变量数量超过上限,请减少 global 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl") - return - entry_addr: t.CUInt64T = t.CUInt64T(trans._global_names) + trans._global_name_count * 8 - slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr) - slot_ptr[0] = name - trans._global_name_count += 1 - - def is_global_name(self, trans: HT.Translator | t.CPtr, name: str) -> int: - """检查 name 是否在当前函数的 global 集合中""" - if trans is None or name is None or trans._global_names is None: - return 0 - for i in range(trans._global_name_count): - entry_addr: t.CUInt64T = t.CUInt64T(trans._global_names) + i * 8 - slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr) - entry: str = slot_ptr[0] - if entry is not None: - if string.strcmp(entry, name) == 0: - return 1 - return 0 - - def add_nonlocal_name(self, trans: HT.Translator | t.CPtr, name: str, - var_ty: llvmlite.LLVMType | t.CPtr = None): - """添加一个 nonlocal 变量名 - - Args: - name: nonlocal 变量名 - var_ty: 变量的 LLVM 类型(用于 env 指针数组方案的类型恢复, - None 时回退为 i32) - """ - if trans is None or name is None: - return - if trans._nonlocal_names is None: - return - if self.is_nonlocal_name(trans, name) != 0: - # 已存在:更新类型信息(可能在预扫描时类型未知,正式翻译时更新) - # _nonlocal_types 每槽 8 字节,存 LLVMType* 指针。 - # 用 str|t.CPtr (i8**) 二级指针存取(与 _nonlocal_names 模式一致), - # [0] 解引用只拷贝 8 字节指针,避免值拷贝 24+ 字节 LLVMType 结构体溢出。 - if var_ty is not None and trans._nonlocal_types is not None: - idx: int = self.get_nonlocal_index(trans, name) - if idx >= 0: - ty_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + idx * 8 - ty_slot: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr) - ty_slot[0] = var_ty - return - if trans._nonlocal_name_count >= MAX_GLOBAL_NAMES: - pool_err_nl: memhub.MemBuddy | t.CPtr = trans.Pool - err_buf_nl: str = None - if pool_err_nl is not None: - err_buf_nl = pool_err_nl.alloc(256) - if err_buf_nl is not None: - viperlib.snprintf(err_buf_nl, 256, "nonlocal 变量数量超过上限 MAX_GLOBAL_NAMES=%d,请减少 nonlocal 声明或增大 MAX_GLOBAL_NAMES", MAX_GLOBAL_NAMES) - VLogger.error(err_buf_nl, "ScopeDecl") - else: - VLogger.error("nonlocal 变量数量超过上限,请减少 nonlocal 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl") - return - entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + trans._nonlocal_name_count * 8 - slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr) - slot_ptr[0] = name - # 存储类型信息(用 str|t.CPtr = i8** 二级指针,与 _nonlocal_names 一致) - if trans._nonlocal_types is not None: - ty_addr2: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + trans._nonlocal_name_count * 8 - ty_slot2: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr2) - # var_ty 为 None 时直接报错终止(fail-fast),不再默认 i32 - stored_ty: llvmlite.LLVMType | t.CPtr = var_ty - if stored_ty is None: - HandlesType.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法注册", "TypeError") - return - ty_slot2[0] = stored_ty - trans._nonlocal_name_count += 1 - trans._closure_env_count += 1 - - def get_nonlocal_type(self, trans: HT.Translator | t.CPtr, - name: str) -> llvmlite.LLVMType | t.CPtr: - """获取 nonlocal 变量的 LLVM 类型 - - Returns: 找到的类型指针,找不到返回 None - """ - if trans is None or name is None or trans._nonlocal_types is None: - return None - idx: int = self.get_nonlocal_index(trans, name) - if idx < 0: - return None - ty_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + idx * 8 - ty_slot: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr) - return (llvmlite.LLVMType | t.CPtr)(ty_slot[0]) - - def is_nonlocal_name(self, trans: HT.Translator | t.CPtr, name: str) -> int: - """检查 name 是否在当前函数的 nonlocal 集合中""" - if trans is None or name is None or trans._nonlocal_names is None: - return 0 - for i in range(trans._nonlocal_name_count): - entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + i * 8 - slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr) - entry: str = slot_ptr[0] - if entry is not None: - if string.strcmp(entry, name) == 0: - return 1 - return 0 - - def get_nonlocal_index(self, trans: HT.Translator | t.CPtr, name: str) -> int: - """获取 nonlocal 变量在 env 中的索引(0-based),找不到返回 -1""" - if trans is None or name is None or trans._nonlocal_names is None: - return -1 - for i in range(trans._nonlocal_name_count): - entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + i * 8 - slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr) - entry: str = slot_ptr[0] - if entry is not None: - if string.strcmp(entry, name) == 0: - return i - return -1 - - def clear_scope_names(self, trans: HT.Translator | t.CPtr): - """清空当前函数的 global/nonlocal 名称集合(进入新函数时调用)""" - if trans is None: - return - trans._global_name_count = 0 - trans._nonlocal_name_count = 0 - trans._closure_env_count = 0 +import lib.core.Gen.Generator as Generator +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExprCall as HandlesExprCall + + +# ============================================================ +# TranslatorGenMixin - 翻译驱动 Mixin(对象化 P6-E) +# +# 从 HandlesMain.vp / HandlesTranslator.vp 迁移:模块级纯函数 +# (trans 首参)→ 类方法。包含: +# - 模块级翻译入口(translate_children/create_wrapper_main/ +# handle_module_level_var 等,原 HandlesMain.vp) +# - global/nonlocal 名称管理辅助函数(原 HandlesTranslator.vp) +# +# 迁移原则(与 P2-P5 一致,行为零变化): +# 1. 方法保留原函数签名(含 trans/pool 首参),仅函数体内的 +# 本模块函数调用改为 self.xxx(...) +# 2. 外部模块调用(HandlesType.xxx/HandlesVar.xxx 等)保留模块前缀 +# 3. HandlesMain/HandlesTranslator 原函数保留为"委托":本地模块级 +# 单例 _g_gen(BuildPipeline/main 注入)cast 成 Generator 类型 +# 4. 嵌套函数保持嵌套 +# +# 常量(MAX_VARS/MAX_FUNCS/MAX_GLOBAL_NAMES)与原模块保持一致。 +# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 +# ============================================================ + + +# ============================================================ +# 常量(与 HandlesTranslator 保持一致) +# ============================================================ +MAX_VARS: t.CDefine = 1024 +MAX_FUNCS: t.CDefine = 1024 +MAX_GLOBAL_NAMES: t.CDefine = 32 + + +# ============================================================ +# TranslatorGenMixin - 翻译驱动(模块级翻译入口 + 作用域名称管理) +# ============================================================ +@t.NoVTable +class TranslatorGenMixin: + """翻译驱动 Mixin(P6 方法化)""" + + # ============================================================ + # _register_cexport_from_funcdef - Phase 1a 预注册 CExport/State 函数 + # + # 解决翻译顺序依赖问题:Phase 1b 按字母序翻译,后翻译的模块的 + # CExport 函数无法被先翻译的模块正确识别为裸名调用。 + # Phase 1a 预注册所有 CExport/State 函数名到全局表。 + # ============================================================ + Gen: Generator.Generator | t.CPtr + def _register_cexport_from_funcdef(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """预注册 CExport/State 函数到全局表(仅注册,不生成 IR)""" + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node) + if fd is None or fd.name is None: + return 0 + if trans is None or trans.ModuleSha1 is None: + return 0 + + # 检查返回类型是否有 CExport 或 State 标记 + has_export: int = 0 + has_state: int = 0 + if fd.returns is not None: + has_export = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "CExport") + has_state = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "State") + + if has_export != 0 or has_state != 0: + self.Gen.CallGenBase.register_cexport_func(trans.ModuleSha1, fd.name) + + return 0 + + # ============================================================ + # translate_children - 遍历 AST 子节点并分派翻译 + # + # 对应 TransPyC translator._translate_children() + # 共享状态从 trans 获取,imported_modules/from_imports 更新到 trans + # ============================================================ + def translate_children(self, trans: HT.Translator | t.CPtr, + tree: ast.AST | t.CPtr) -> int: + """遍历 tree.children 并翻译每个子节点 + + Args: + trans: 翻译器(含所有共享状态) + tree: AST 模块节点 + + Returns: + t.CInt: 新增的变量数 + """ + ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children + if ch is None: + return 0 + + cn_count: t.CSizeT = len(ch) + added_total: int = 0 + + for ci in range(cn_count): + child: ast.AST | t.CPtr = ch.get(ci) + if child is None: continue + kd: int = child.kind() + + # _declare_only == 0 时,_translate_module_level 已预处理导入语句, + # 此处跳过避免重复处理(from_imports 条目重复) + if trans._declare_only == 0 and (kd == ast.ASTKind.Import or kd == ast.ASTKind.ImportFrom): + continue + if kd == ast.ASTKind.Import: + self.Gen.ImportsGen.translate_import(trans, child) + elif kd == ast.ASTKind.ImportFrom: + self.Gen.ImportsGen.translate_import_from_module(trans, child) + self.Gen.ImportsGen.translate_import_from_names(trans, child) + elif kd == ast.ASTKind.FunctionDef: + # Phase 1a 声明模式:只注册 CExport/State 函数到全局表(解决翻译顺序依赖) + # Phase 1b 全量翻译:正常翻译函数体 + if trans._declare_only == 0: + added: int = self.Gen.FuncGenDef.translate_function_def(trans, child) + added_total += added + elif trans._declare_only == 1: + self._register_cexport_from_funcdef(trans, child) + # 预解析函数签名类型,触发泛型类特化(如 numpy 的 _empty_like + # 签名 ndarray[t.CDouble] → 特化结构体注册)。 + # 1a 阶段在 mark1 之前,特化结构体的 Ty/Fields 分配在 mark1 前, + # 不被 1b 的 mark/reset 回收 → 避免 Phase2 翻译 App 文件时 UAF + # (Phase1 1b 才触发特化时,结构体 Ty/Fields 在 pool 被 reset 覆写)。 + # 仅触发特化,不验证结果(1b 全量翻译时仍会重新解析)。 + self._prescan_funcdef_signatures(trans, child) + elif kd == ast.ASTKind.ClassDef: + # ClassDef 在模块级直接处理(不需要 builder) + # _declare_only=2(import扫描模式)时跳过,只处理 import 依赖 + if trans._declare_only != 2: + self.Gen.ClassGenDef.translate_class_def(trans, child) + elif trans._declare_only == 0 and trans._cur_builder is not None: + # 有 builder → 委托 HandlesBody 分派 + added = self.Gen.StmtGen.translate_stmt(trans, child) + added_total += added + elif kd == ast.ASTKind.AnnAssign and trans._declare_only != 2: + # 模块级 AnnAssign + # _declare_only=2(import扫描模式)时跳过 + # _declare_only=1(struct注册模式)时只处理 CDefine(在 handle_module_level_var 内部判断) + # _declare_only=0(全量翻译)时处理所有模块级 AnnAssign + added = self.handle_module_level_var(trans, child) + added_total += added + elif trans._declare_only == 0 and kd == ast.ASTKind.Assign: + # 无 builder 的模块级 Assign → 创建全局变量(仅全量翻译模式) + added = self.handle_module_level_var(trans, child) + added_total += added + + return added_total + + # ============================================================ + # _prescan_funcdef_signatures - 1a 阶段预解析模块级函数签名 + # + # 触发泛型类特化(如 numpy 的 _empty_like 签名 ndarray[t.CDouble]), + # 使特化结构体在 mark1 前注册(Ty/Fields 不被 1b 的 mark/reset 回收), + # 避免 Phase2 翻译 App 文件时访问悬空结构体(UAF)。 + # 仅解析类型触发特化,不验证结果(1b 全量翻译时重新解析)。 + # ============================================================ + def _prescan_funcdef_signatures(self, trans: HT.Translator | t.CPtr, + fd: ast.FunctionDef | t.CPtr) -> None: + """预解析模块级函数签名的返回/参数类型,触发泛型类特化""" + if trans is None or fd is None: + return + pool: memhub.MemBuddy | t.CPtr = trans.Pool + if pool is None: + return + imp: str = trans._imported_modules + fi: str = trans._from_imports + if fd.returns is not None: + self.Gen.TypeGenResolve.resolve_annotation_type(pool, fd.returns, imp, fi, trans) + if fd.args is not None: + ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args) + if ags.args is not None: + al: list[ast.AST | t.CPtr] | t.CPtr = ags.args + an: t.CSizeT = len(al) + ai: t.CSizeT + for ai in range(an): + ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(al.get(ai)) + if ag is not None and ag.annotation is not None: + self.Gen.TypeGenResolve.resolve_annotation_type(pool, ag.annotation, imp, fi, trans) + + # ============================================================ + # _build_array_initializer_text - 从 AST List 生成 LLVM IR 数组初始化器 + # + # 生成格式: [N x elem_ty] [elem_ty val0, elem_ty val1, ...] + # 用于模块级 t.CArray 列表字面量初始化(不依赖 builder,直接生成常量初始化器) + # ============================================================ + def _build_array_initializer_text(self, pool: memhub.MemBuddy | t.CPtr, + var_ty: llvmlite.LLVMType | t.CPtr, + list_node: ast.List | t.CPtr) -> str: + """从 AST List 节点生成 LLVM IR 数组初始化器文本,None 失败""" + if var_ty is None or list_node is None: + return None + + # 重新进行类型转换,确保 TPV 编译器正确识别 ast.List 类型 + # (避免 init_list_node 初始值为 None 时类型推断退化为 t.CPtr) + ln: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node) + if ln is None: + return None + + # 从 var_ty 提取数组元素类型和数量 + elem_ty: llvmlite.LLVMType | t.CPtr = None + arr_count: t.CInt = 0 + match var_ty: + case llvmlite.LLVMType.Array(et, cnt): + elem_ty = et + arr_count = cnt + + if elem_ty is None or arr_count <= 0: + return None + + # 确定元素类型的 IR 表示 + elem_ir_ty: str = "i8" + match elem_ty: + case llvmlite.LLVMType.Int(bits): + if bits == 8: + elem_ir_ty = "i8" + elif bits == 16: + elem_ir_ty = "i16" + elif bits == 32: + elem_ir_ty = "i32" + elif bits == 64: + elem_ir_ty = "i64" + + # 获取列表元素(通过 ln.elts 而非 list_node.elts,确保类型正确识别) + elts: list[ast.AST | t.CPtr] | t.CPtr = ln.elts + if elts is None: + return None + elts_count: t.CSizeT = len(elts) + + # 计算缓冲区大小: 每个元素最多 "i32 -9223372036854775808, " 约 26 字符 + # 按数组声明长度 arr_count 计算(元素不足时补零,可能多于 elts_count) + cnt_total: t.CSizeT = t.CSizeT(arr_count) + buf_size: t.CSizeT = 64 + cnt_total * 32 + buf: str = pool.alloc(buf_size) + if buf is None: + return None + + # 写入前缀: "["(类型前缀由 _print_global 输出,初始化器只需元素列表) + written: t.CInt = viperlib.snprintf(buf, buf_size, "[") + pos: t.CSizeT = t.CSizeT(written) + + # 逐个元素写入:元素数必须与数组声明长度 arr_count 一致, + # 列表元素不足时补零(如 g_arr: t.CArray[t.CInt, 4] = [0] → + # [i32 0, i32 0, i32 0, i32 0]),否则 llc 报 + # "constant expression type mismatch: got type '[1 x i32]' but expected '[4 x i32]'" + i: t.CSizeT = 0 + while i < cnt_total: + elem_val: t.CInt64T = 0 + if i < elts_count: + elem_node: ast.AST | t.CPtr = elts.get(i) + # 直接从 Constant 节点提取 int_val(避免 extract_cdefine_int_value 的 t.CInt 截断) + if elem_node is not None: + ek: int = elem_node.kind() + if ek == ast.ASTKind.Constant: + ec: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(elem_node) + if ec is not None and ec.const_kind == ast.CONST_INT: + elem_val = ec.int_val + elif ek == ast.ASTKind.UnaryOp: + # 负数: UnaryOp(USub, Constant) + elem_val = self.Gen.AssignGen.extract_cdefine_int_value(elem_node) + if i > 0: + written = viperlib.snprintf(buf + pos, buf_size - pos, ", ") + pos += t.CSizeT(written) + written = viperlib.snprintf(buf + pos, buf_size - pos, "%s %lld", elem_ir_ty, elem_val) + pos += t.CSizeT(written) + i += 1 + + # 写入后缀 "]" + viperlib.snprintf(buf + pos, buf_size - pos, "]") + return buf + + # ============================================================ + # _build_string_array_initializer_text - 字符串字面量初始化数组全局 + # + # t.CArray[t.CChar, N] = "..." → [i8 b0, i8 b1, ..., i8 0, ...] + # (字符串字节 + 零填充到数组长度;空串返回 zeroinitializer)。 + # 此前统一走字符串指针 GEP 初始化器 → @g = global [N x i8] + # 类型不匹配(llc constant expression type mismatch, + # pyzlib_error_msg = global [512 x i8] 根因)。 + # ============================================================ + def _build_string_array_initializer_text(self, pool: memhub.MemBuddy | t.CPtr, + var_ty: llvmlite.LLVMType | t.CPtr, + str_val: str) -> str: + """字符串字面量初始化数组全局,返回初始化器文本或 None""" + if var_ty is None or str_val is None: + return None + arr_count: t.CInt = 0 + match var_ty: + case llvmlite.LLVMType.Array(_, cnt): + arr_count = cnt + if arr_count <= 0: + return None + slen: t.CSizeT = string.strlen(str_val) + if slen == 0: + return "zeroinitializer" + buf_size: t.CSizeT = 64 + t.CSizeT(arr_count) * 16 + buf: str = pool.alloc(buf_size) + if buf is None: + return None + written: t.CInt = viperlib.snprintf(buf, buf_size, "[") + pos: t.CSizeT = t.CSizeT(written) + i: t.CSizeT = 0 + while i < t.CSizeT(arr_count): + if i > 0: + written = viperlib.snprintf(buf + pos, buf_size - pos, ", ") + pos += t.CSizeT(written) + bv: t.CInt64T = 0 + if i < slen: + bv = t.CInt64T(str_val[i]) + written = viperlib.snprintf(buf + pos, buf_size - pos, "i8 %lld", bv) + pos += t.CSizeT(written) + i += 1 + viperlib.snprintf(buf + pos, buf_size - pos, "]") + return buf + + # ============================================================ + # _build_string_ptr_initializer - 为字符串字面量初始化指针类型全局变量 + # + # 创建内部字符串常量全局 @.str.{var_name} = private constant [len+1 x i8] c"...\00" + # 返回 GEP 初始化器文本: getelementptr inbounds ([len+1 x i8], [len+1 x i8]* @.str.{var_name}, i32 0, i32 0) + # 用于 b64_tab: t.CArray[t.CChar, None] = "ABC..." 等字符串初始化指针类型 + # ============================================================ + def _build_string_ptr_initializer(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + var_name: str, + str_val: str) -> str: + """为字符串字面量创建内部常量全局并返回 GEP 初始化器文本,None 失败""" + if str_val is None or var_name is None: + return None + + # 构造内部字符串常量名称: .str.{var_name} + str_name_buf: str = pool.alloc(64) + if str_name_buf is None: + return None + viperlib.snprintf(str_name_buf, 64, ".str.%s", var_name) + + # 调用 llvmlite.create_global_string 创建字符串常量全局 + str_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.create_global_string( + pool, mod, str_name_buf, str_val) + if str_gv is None: + return None + + # 生成 GEP 初始化器文本 + str_len: t.CSizeT = string.strlen(str_val) + init_buf: str = pool.alloc(128) + if init_buf is None: + return None + viperlib.snprintf(init_buf, 128, + "getelementptr inbounds ([%d x i8], [%d x i8]* @%s, i32 0, i32 0)", + str_len + 1, str_len + 1, str_name_buf) + return init_buf + + # ============================================================ + # handle_module_level_var - 模块级变量声明 → 创建 LLVM 全局变量 + # + # 当用户已定义 main(无 wrapper main builder)时,模块级 + # AnnAssign/Assign 创建全局变量 @var_name 并注册到 SymTab 模块作用域 + # 支持整数、列表字面量、字符串字面量初始值 + # ============================================================ + def handle_module_level_var(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """处理模块级变量声明,创建全局变量""" + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + + # CDefine 注解: 编译期常量,不创建全局变量 + # 注册到全局 CDefine 表供 t.CArray[elem_ty, NAME] 解析 + k: int = node.kind() + if k == ast.ASTKind.AnnAssign: + aa_cd: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) + if aa_cd is not None and aa_cd.target is not None: + if aa_cd.target.kind() == ast.ASTKind.Name: + nm_cd: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa_cd.target) + if nm_cd.id is not None: + if self.Gen.AssignGen.is_cdefine_annotation(aa_cd.annotation) != 0: + # 浮点/整数自动识别注册(浮点 CDefine 如 vipermath U_M_PI) + self.Gen.AssignGen._register_cdefine_from_value( + pool, nm_cd.id, aa_cd.value) + return 0 + # CTypedef 注解(如 posix.vp mode_t: t.CTypedef = t.CUInt32T): + # 不创建全局变量——否则生成 @mode_t 符号 → 链接 duplicate + # symbol warning。预注册阶段(forward_declare_functions + # 之前)按需注册到 CTypedef 表:翻译期表已被 clear_ctypedefs + # 清空(每文件隔离),若不在此时注册,S_ISREG(mode: mode_t) + # 等函数参数注解在 FuncGenDef 正式翻译时查表失败 → + # NameError: mode_t(AstTest/posix.vp 根因;模块级 AnnAssign + # 经本函数分派,不经过 AnnAssignHandle.Handle 的注册分支)。 + if self.Gen.TypeGenCType._is_ctypedef_annotation(aa_cd.annotation) != 0: + ctd_str: str = self.Gen.TypeGenResolve._get_type_name_from_annotation( + pool, aa_cd.value) + if ctd_str is not None: + self.Gen.TypeGenCType.register_ctypedef(pool, nm_cd.id, ctd_str) + return 0 + + # _declare_only=1(struct注册模式)时只处理 CDefine,不创建全局变量 + # CDefine 已在上面处理并返回,到这里说明不是 CDefine,直接跳过 + if trans._declare_only == 1: + return 0 + + var_name: str = None + var_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + init_val: t.CInt64T = 0 + init_kind: int = 0 # 0=none, 1=int, 2=list, 3=str + init_str_val: str = None + init_list_node: ast.List | t.CPtr = None + + if k == ast.ASTKind.AnnAssign: + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) + if aa is None or aa.target is None: + return 0 + if aa.target.kind() != ast.ASTKind.Name: + return 0 + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) + var_name = nm.id + # 解析类型 + if aa.annotation is not None: + resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, aa.annotation, trans._imported_modules, trans._from_imports, trans) + if resolved is not None: + var_ty = resolved + # 解析初始值(支持整数、列表字面量、字符串字面量) + if aa.value is not None: + val_kind: int = aa.value.kind() + if val_kind == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(aa.value) + if cn.const_kind == ast.CONST_INT: + init_val = cn.int_val + init_kind = 1 + elif cn.const_kind == ast.CONST_STR: + init_str_val = cn.str_val + init_kind = 3 + elif val_kind == ast.ASTKind.List: + init_list_node = (ast.List | t.CPtr)(aa.value) + init_kind = 2 + elif k == ast.ASTKind.Assign: + asgn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node) + if asgn is None or asgn.targets is None: + return 0 + targets: list[ast.AST | t.CPtr] | t.CPtr = asgn.targets + if len(targets) < 1: + return 0 + t0: ast.AST | t.CPtr = targets.get(0) + if t0 is None or t0.kind() != ast.ASTKind.Name: + return 0 + nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(t0) + var_name = nm2.id + if asgn.value is not None: + val_kind2: int = asgn.value.kind() + if val_kind2 == ast.ASTKind.Constant: + cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(asgn.value) + if cn2.const_kind == ast.CONST_INT: + init_val = cn2.int_val + init_kind = 1 + elif cn2.const_kind == ast.CONST_STR: + init_str_val = cn2.str_val + init_kind = 3 + elif val_kind2 == ast.ASTKind.List: + init_list_node = (ast.List | t.CPtr)(asgn.value) + init_kind = 2 + + if var_name is None: + return 0 + + # __all__ 是 Python 模块元数据(公开名列表),无运行时语义: + # StubGen 的 .vpi 不为其生成 stub 声明(无注解模块级赋值不产出 vpi + # 条目),此处同样跳过全局创建——否则无注解 list-of-strings 全局 + # 类型推断缺失(var_ty 默认 i32)→ _build_array_initializer_text + # 返回 None → fail-fast "初始化器构建失败" 误报 + # (Projectrans/__init__.vp 追加83 根因)。与 CDefine/CTypedef + # 同类:编译期/元数据实体不落入 LLVM 全局。 + if string.strcmp(var_name, "__all__") == 0: + return 0 + + # 检查是否已注册 + existing: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_module_var( + trans.SymTab, var_name) + if existing is not None: + return 0 + + # 创建全局变量 @var_name + # 先确保 var_ty 中的跨模块结构体类型在模块中有 opaque 声明 + # 否则 @var_name = global %"sha1.ClassName"* zeroinitializer 会报 + # "use of undefined type named 'sha1.ClassName'" 错误 + # (如 _mbuddy: memhub.MemManager | t.CPtr → Ptr(Struct("aeb3...MemManager"))) + llvmlite.module_ensure_opaque_for_type(mod, pool, var_ty) + # 模块级全局命名带 SHA1 前缀(对齐函数名 mangling):多个模块声明同名 + # 全局(如 _mbuddy)时各自独立命名,消除 ld.lld duplicate symbol。 + # SymTab 注册 key 保持裸名(查找逻辑零改动),LLVM 符号名用 mangled 名。 + mangled_name: str = self.Gen.FuncGenBase._mangle_name(trans, var_name) + gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, mangled_name, var_ty) + if gv is None: + return 0 + llvmlite.module_add_global(mod, gv) + + # 设置初始值(有初始值时清除 external linkage,因为 LLVM 22+ 不允许 external global 带初始值) + gv.Linkage = None + if init_kind == 1: + # 整数初始值 + init_buf: str = pool.alloc(48) + if init_buf is not None: + viperlib.snprintf(init_buf, 48, "%lld", init_val) + gv.Initializer = init_buf + elif init_kind == 2: + # 列表字面量 → 数组初始化器 [N x elem_ty] [elem_ty val0, ...] + arr_init: str = self._build_array_initializer_text(pool, var_ty, init_list_node) + if arr_init is not None: + gv.Initializer = arr_init + else: + # 初始化器构建失败:直接报错终止(fail-fast),不再回退 zeroinitializer + self.Gen.TypeGenErr.fatal_error(node, f"模块级变量 '{var_name}' 初始化器构建失败", "TypeError") + elif init_kind == 3: + # 字符串字面量初始化 + # 数组类型(t.CArray[t.CChar, N]):字节数组初始化器(字符串内容 + 零填充) + # ——此前统一走字符串指针 GEP 初始化器 → @g = global [N x i8] 类型 + # 不匹配(llc constant expression type mismatch,pyzlib_error_msg 根因) + is_arr_g: int = 0 + match var_ty: + case llvmlite.LLVMType.Array(_, _): + is_arr_g = 1 + case _: + pass + if is_arr_g != 0: + arr_str_init: str = self._build_string_array_initializer_text( + pool, var_ty, init_str_val) + if arr_str_init is not None: + gv.Initializer = arr_str_init + else: + self.Gen.TypeGenErr.fatal_error( + node, f"模块级数组变量 '{var_name}' 字符串初始化器构建失败", "TypeError") + else: + # 指针类型(如 b64_tab: t.CArray[t.CChar, None] = "ABC..."): + # 创建字符串常量全局 + GEP 引用 + str_init: str = self._build_string_ptr_initializer(pool, mod, var_name, init_str_val) + if str_init is not None: + gv.Initializer = str_init + else: + self.Gen.TypeGenErr.fatal_error( + node, f"模块级变量 '{var_name}' 初始化器构建失败", "TypeError") + else: + # 使用 zeroinitializer 而非 "0":指针类型必须用 null/zeroinitializer, + # 整数/聚合类型也兼容 zeroinitializer,避免 "integer constant must have integer type" + gv.Initializer = "zeroinitializer" + + # 创建 Value 引用(@mangled_name, 类型为 var_ty*) + var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty) + ref_name: str = pool.alloc(96) + if ref_name is not None: + # mangled 名带 SHA1 前缀(数字开头),引用必须加引号(对齐 make_global_ref) + if self.Gen.ClassGenVTable._vtable_name_needs_quote(mangled_name) != 0: + viperlib.snprintf(ref_name, 96, "@\"%s\"", mangled_name) + else: + viperlib.snprintf(ref_name, 96, "@%s", mangled_name) + gv_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, var_ptr_ty, ref_name) + + # 注册到模块作用域 + if self.Gen.VarGen.define_module_var(trans.SymTab, var_name, gv_ref) == 0: + # 设置 AnnotClassName(联合类型如 Logger|t.CPtr 简化为 Ptr(i8) 时, + # 属性访问需要通过 AnnotClassName 回退到类名查找结构体) + if k == ast.ASTKind.AnnAssign: + aa_ml: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) + if aa_ml is not None and aa_ml.annotation is not None: + cls_nm_ml: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation( + aa_ml.annotation, trans._imported_modules, pool) + if cls_nm_ml is not None: + self.Gen.VarGen.set_var_annot_class_name( + trans.SymTab, var_name, cls_nm_ml) + return 1 + return 0 + + # ============================================================ + # create_wrapper_main - 创建包装 main 函数 + # + # 当用户未定义 main 函数时调用。 + # 创建 main() -> i32 函数 → 设置 trans._cur_func/_cur_builder → + # 预扫描 alloca → 翻译子节点 → ret 0 + # ============================================================ + def create_wrapper_main(self, trans: HT.Translator | t.CPtr, + tree: ast.AST | t.CPtr, + i32_ty: llvmlite.LLVMType | t.CPtr) -> int: + """创建包装 main 函数并翻译所有顶层语句 + + Args: + trans: 翻译器(含所有共享状态) + tree: AST 模块节点 + i32_ty: i32 LLVMType + + Returns: + t.CInt: 新增的变量数 + """ + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + + main_func: llvmlite.Function | t.CPtr = llvmlite.create_function( + pool, mod, "main", i32_ty) + if main_func is None: + VLogger.error("CreateFunction main returned NULL", "TR") + return 0 + + entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, main_func, "entry") + if entry_blk is None: + VLogger.error("CreateBlock returned NULL", "TR") + return 0 + + builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, main_func) + if builder is None: + VLogger.error("NewBuilder returned NULL", "TR") + return 0 + llvmlite.position_at_end(builder, entry_blk) + + # 设置当前翻译上下文(供 Handle 通过 self.Trans._cur_builder 访问) + trans._cur_func = main_func + trans._cur_builder = builder + + # 预处理模块级变量:为 AnnAssign/Assign 创建 LLVM 全局变量 + # 必须在 pre_scan_allocas 之前执行,否则 PreScan 会创建局部 alloca, + # 导致其他函数通过 SSA 编号引用 wrapper main 的局部变量(无效 IR) + ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children + if ch is not None: + cn_count: t.CSizeT = len(ch) + for ci in range(cn_count): + child: ast.AST | t.CPtr = ch.get(ci) + if child is not None: + kd: int = child.kind() + if kd == ast.ASTKind.AnnAssign or kd == ast.ASTKind.Assign: + self.handle_module_level_var(trans, child) + + # 预扫描顶层语句:为函数内 AnnAssign 提前创建 alloca + # (模块级变量已在上面注册到模块作用域,PreScan 的 lookup_current 会跳过它们) + if ch is not None: + for ci in range(cn_count): + child: ast.AST | t.CPtr = ch.get(ci) + if child is not None: + self.Gen.StmtGenDecl.pre_scan_allocas(trans, child) + + # 翻译子节点 + added_total: int = self.translate_children(trans, tree) + + # 返回 0 + zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + llvmlite.build_ret(builder, zero_val) + + return added_total + + # ============================================================ + # global/nonlocal 名称管理(迁移自 HandlesTranslator.vp 模块级函数) + # ============================================================ + def add_global_name(self, trans: HT.Translator | t.CPtr, name: str): + """添加一个 global 变量名""" + if trans is None or name is None: + return + if trans._global_names is None: + return + # 检查是否已存在 + if self.is_global_name(trans, name) != 0: + return + if trans._global_name_count >= MAX_GLOBAL_NAMES: + pool_err: memhub.MemBuddy | t.CPtr = trans.Pool + err_buf: str = None + if pool_err is not None: + err_buf = pool_err.alloc(256) + if err_buf is not None: + viperlib.snprintf(err_buf, 256, "global 变量数量超过上限 MAX_GLOBAL_NAMES=%d,请减少 global 声明或增大 MAX_GLOBAL_NAMES", MAX_GLOBAL_NAMES) + VLogger.error(err_buf, "ScopeDecl") + else: + VLogger.error("global 变量数量超过上限,请减少 global 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl") + return + entry_addr: t.CUInt64T = t.CUInt64T(trans._global_names) + trans._global_name_count * 8 + slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr) + slot_ptr[0] = name + trans._global_name_count += 1 + + def is_global_name(self, trans: HT.Translator | t.CPtr, name: str) -> int: + """检查 name 是否在当前函数的 global 集合中""" + if trans is None or name is None or trans._global_names is None: + return 0 + for i in range(trans._global_name_count): + entry_addr: t.CUInt64T = t.CUInt64T(trans._global_names) + i * 8 + slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr) + entry: str = slot_ptr[0] + if entry is not None: + if string.strcmp(entry, name) == 0: + return 1 + return 0 + + def add_nonlocal_name(self, trans: HT.Translator | t.CPtr, name: str, + var_ty: llvmlite.LLVMType | t.CPtr = None): + """添加一个 nonlocal 变量名 + + Args: + name: nonlocal 变量名 + var_ty: 变量的 LLVM 类型(用于 env 指针数组方案的类型恢复, + None 时回退为 i32) + """ + if trans is None or name is None: + return + if trans._nonlocal_names is None: + return + if self.is_nonlocal_name(trans, name) != 0: + # 已存在:更新类型信息(可能在预扫描时类型未知,正式翻译时更新) + # _nonlocal_types 每槽 8 字节,存 LLVMType* 指针。 + # 用 str|t.CPtr (i8**) 二级指针存取(与 _nonlocal_names 模式一致), + # [0] 解引用只拷贝 8 字节指针,避免值拷贝 24+ 字节 LLVMType 结构体溢出。 + if var_ty is not None and trans._nonlocal_types is not None: + idx: int = self.get_nonlocal_index(trans, name) + if idx >= 0: + ty_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + idx * 8 + ty_slot: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr) + ty_slot[0] = var_ty + return + if trans._nonlocal_name_count >= MAX_GLOBAL_NAMES: + pool_err_nl: memhub.MemBuddy | t.CPtr = trans.Pool + err_buf_nl: str = None + if pool_err_nl is not None: + err_buf_nl = pool_err_nl.alloc(256) + if err_buf_nl is not None: + viperlib.snprintf(err_buf_nl, 256, "nonlocal 变量数量超过上限 MAX_GLOBAL_NAMES=%d,请减少 nonlocal 声明或增大 MAX_GLOBAL_NAMES", MAX_GLOBAL_NAMES) + VLogger.error(err_buf_nl, "ScopeDecl") + else: + VLogger.error("nonlocal 变量数量超过上限,请减少 nonlocal 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl") + return + entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + trans._nonlocal_name_count * 8 + slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr) + slot_ptr[0] = name + # 存储类型信息(用 str|t.CPtr = i8** 二级指针,与 _nonlocal_names 一致) + if trans._nonlocal_types is not None: + ty_addr2: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + trans._nonlocal_name_count * 8 + ty_slot2: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr2) + # var_ty 为 None 时直接报错终止(fail-fast),不再默认 i32 + stored_ty: llvmlite.LLVMType | t.CPtr = var_ty + if stored_ty is None: + self.Gen.TypeGenErr.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法注册", "TypeError") + return + ty_slot2[0] = stored_ty + trans._nonlocal_name_count += 1 + trans._closure_env_count += 1 + + def get_nonlocal_type(self, trans: HT.Translator | t.CPtr, + name: str) -> llvmlite.LLVMType | t.CPtr: + """获取 nonlocal 变量的 LLVM 类型 + + Returns: 找到的类型指针,找不到返回 None + """ + if trans is None or name is None or trans._nonlocal_types is None: + return None + idx: int = self.get_nonlocal_index(trans, name) + if idx < 0: + return None + ty_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + idx * 8 + ty_slot: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr) + return (llvmlite.LLVMType | t.CPtr)(ty_slot[0]) + + def is_nonlocal_name(self, trans: HT.Translator | t.CPtr, name: str) -> int: + """检查 name 是否在当前函数的 nonlocal 集合中""" + if trans is None or name is None or trans._nonlocal_names is None: + return 0 + for i in range(trans._nonlocal_name_count): + entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + i * 8 + slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr) + entry: str = slot_ptr[0] + if entry is not None: + if string.strcmp(entry, name) == 0: + return 1 + return 0 + + def get_nonlocal_index(self, trans: HT.Translator | t.CPtr, name: str) -> int: + """获取 nonlocal 变量在 env 中的索引(0-based),找不到返回 -1""" + if trans is None or name is None or trans._nonlocal_names is None: + return -1 + for i in range(trans._nonlocal_name_count): + entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + i * 8 + slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr) + entry: str = slot_ptr[0] + if entry is not None: + if string.strcmp(entry, name) == 0: + return i + return -1 + + def clear_scope_names(self, trans: HT.Translator | t.CPtr): + """清空当前函数的 global/nonlocal 名称集合(进入新函数时调用)""" + if trans is None: + return + trans._global_name_count = 0 + trans._nonlocal_name_count = 0 + trans._closure_env_count = 0 diff --git a/App/lib/core/Gen/TypeGenBase.vp b/App/lib/core/Gen/TypeGenBase.vp index e169b22..d1ea7ad 100644 --- a/App/lib/core/Gen/TypeGenBase.vp +++ b/App/lib/core/Gen/TypeGenBase.vp @@ -1,3 +1,5 @@ +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.Generator as Generator import t, c from stdint import * import ast @@ -8,18 +10,6 @@ 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 @@ -37,12 +27,10 @@ class TypeGenBase: """字段 + InitTypeGen + trace/临时目录/generic 上下文""" # --- 仿 Python Traceback 调用栈(原 _g_trace_frames/_g_trace_count) --- - TraceFrames: HandlesType.TraceFrame | t.CPtr # malloc 数组(TRACE_MAX 槽) + Gen: Generator.Generator | t.CPtr + TraceFrames: GenTypes.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 @@ -92,7 +80,6 @@ class TypeGenBase: return 1 self.TraceFrames = None self.TraceCount = 0 - self.TempDir = None self.GenericTpNames = None self.GenericTypeArgs = None self.GenericCtxStack = None @@ -126,26 +113,26 @@ class TypeGenBase: """确保调用栈已初始化(懒加载,用 malloc 不依赖 pool)""" if self.TraceFrames is not None: return 1 - entry_size: t.CSizeT = HandlesType.TraceFrame.__sizeof__() + entry_size: t.CSizeT = GenTypes.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: + def _get_trace_frame(self, i: int) -> GenTypes.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__() + entry_size: t.CSizeT = GenTypes.TraceFrame.__sizeof__() addr: t.CUInt64T = t.CUInt64T(self.TraceFrames) + i * entry_size - return (HandlesType.TraceFrame | t.CPtr)(t.CVoid(addr, t.CPtr)) + return (GenTypes.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) + frame: GenTypes.TraceFrame | t.CPtr = self._get_trace_frame(self.TraceCount) if frame is None: return frame.file_name = file_name @@ -158,7 +145,7 @@ class TypeGenBase: if self.TraceCount <= 0: return self.TraceCount -= 1 - frame: HandlesType.TraceFrame | t.CPtr = self._get_trace_frame(self.TraceCount) + frame: GenTypes.TraceFrame | t.CPtr = self._get_trace_frame(self.TraceCount) if frame is not None: frame.file_name = None frame.lineno = 0 @@ -168,7 +155,7 @@ class TypeGenBase: """清空调用栈(每个文件翻译开始前调用)""" i: int for i in range(self.TraceCount): - frame: HandlesType.TraceFrame | t.CPtr = self._get_trace_frame(i) + frame: GenTypes.TraceFrame | t.CPtr = self._get_trace_frame(i) if frame is not None: frame.file_name = None frame.lineno = 0 @@ -176,11 +163,11 @@ class TypeGenBase: frame.col_end = 0 self.TraceCount = 0 def set_temp_dir(self, temp_dir: str) -> None: - """设置全局 temp_dir(每个项目编译开始时由 BuildPipeline/Phase1 设置)""" - self.TempDir = temp_dir + """设置全局 temp_dir(统一写入 CallGenBase.TempDir,跨子对象经 Gen 指针)""" + self.Gen.CallGenBase.SetTempDir(temp_dir) def get_temp_dir(self) -> str: - """获取全局 temp_dir""" - return self.TempDir + """获取全局 temp_dir(从 CallGenBase 读取)""" + return self.Gen.CallGenBase.TempDir def set_current_module_sha1(self, sha1: str) -> None: """设置当前正在编译的模块 SHA1(Phase1 在模块开始翻译前调用)""" self.CurrentModuleSha1 = sha1 diff --git a/App/lib/core/Gen/TypeGenCDef.vp b/App/lib/core/Gen/TypeGenCDef.vp index b1e11c3..8db1946 100644 --- a/App/lib/core/Gen/TypeGenCDef.vp +++ b/App/lib/core/Gen/TypeGenCDef.vp @@ -1,306 +1,298 @@ -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 +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.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +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") + self.Gen.TypeGenErr.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: + self.Gen.TypeGenErr.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: + self.Gen.TypeGenErr.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 index 2f8dddf..9c8dec2 100644 --- a/App/lib/core/Gen/TypeGenCType.vp +++ b/App/lib/core/Gen/TypeGenCType.vp @@ -1,422 +1,415 @@ -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 - k_v: int = annotation.kind() - if k_v != ast.ASTKind.Attribute: - return 0 - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annotation) - # 字段访问改用 ast 模块访问器(跨模块 stub 字段访问陷阱防护: - # TypeGenCType 直接访问 at.attr 可能按 stub 类型生成错误 GEP, - # 读垃圾地址 → strcmp 0xC0000005 崩溃,stdint.vp 根因)。 - at_attr_v: str = ast.attribute_get_attr(at) - if at_attr_v is None: - return 0 - # 限长比较替代 strcmp:attr 是零拷贝引用 src_buf 的 token 字符串, - # 可能无 NUL 结尾("CTypedef" 后紧跟空格/其他字符),strcmp 会 - # 无限读穿到页边界 → 0xC0000005(stdint.vp 崩溃根因)。strncmp - # 只读 8 字节,再校验第 9 字节为终止/分隔符(防 "CTypedefXXX" 误匹配)。 - if string.strncmp(at_attr_v, "CTypedef", 8) != 0: - return 0 - sep_ch_d: t.CChar = at_attr_v[8] - if sep_ch_d != '\0' and sep_ch_d != ' ' and sep_ch_d != '\n' \ - and sep_ch_d != '\r' and sep_ch_d != '\t' and sep_ch_d != '|': - return 0 - at_val_v: ast.AST | t.CPtr = ast.attribute_get_value(at) - if at_val_v is None or at_val_v.kind() != ast.ASTKind.Name: - return 0 - mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_val_v) - mod_id_v: str = ast.name_get_id(mod_nm) - if mod_id_v is None: - return 0 - # 同样限长比较("t" 无 NUL 结尾时 strcmp 读穿) - if string.strncmp(mod_id_v, "t", 1) != 0: - return 0 - sep_ch_m: t.CChar = mod_id_v[1] - if sep_ch_m != '\0' and sep_ch_m != ' ' and sep_ch_m != '\n' \ - and sep_ch_m != '\r' and sep_ch_m != '\t' and sep_ch_m != '|': - 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) - if aa.annotation is None: - continue - # 检测注解是否为 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) - tgt_id_v: str = ast.name_get_id(tgt) - if tgt_id_v 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_v, type_str) - count += 1 - return count - def register_ctypedef_from_source(self, pool: memhub.MemBuddy | t.CPtr, - src: str) -> int: - """从源码文本逐行扫描注册 CTypedef(NAME: t.CTypedef = TYPE) - - stdint.vp 崩溃根因修复:AST 字符串字段(attr/id)token 零拷贝指向 - src_buf,跨阶段内容不稳定(悬空),ScanCTypedefDeclarations 读 - attr 会 0xC0000005。本函数在 src_buf 有效期内(Phase1 1b translate - 前)用纯文本匹配注册,不依赖 AST 节点内容。 - """ - if pool is None or src is None: - return 0 - # 文件边界防护:clear_ctypedefs 只在 translate 前调用(Phase1Main - # L800),文件级 reset_to(mark1) 回收本文件翻译期 pool 分配后,上一 - # 文件的 CTypedefNames 表指针悬空(非 None,list 本身也 pool 分配)。 - # 本函数去重遍历(register_ctypedef 内 strcmp)读已回收内存 → - # 0xC0000005(1.log: stdint.vp 翻译时 strcmp 读地址 0x4)。先清表 - # 重建,杜绝悬空遍历。翻译期 Handle 按需注册不受影响(L800 会再清)。 - self.clear_ctypedefs() - src_len: t.CSizeT = string.strlen(src) - count: int = 0 - line_start: t.CSizeT = 0 - i: t.CSizeT = 0 - while i <= src_len: - if i == src_len or src[i] == '\n': - line_len: t.CSizeT = i - line_start - if line_len > 0: - # 找行内第一个 ':'(跳过注释行) - j: t.CSizeT = 0 - found_colon: int = 0 - while j < line_len: - ch_c: t.CChar = src[line_start + j] - if ch_c == ':': - found_colon = 1 - break - if ch_c == '#' or ch_c == '\r': - break - j += 1 - if found_colon != 0: - # 左段 NAME(trim 尾随空格) - name_len: t.CSizeT = j - while name_len > 0 and src[line_start + name_len - 1] == ' ': - name_len -= 1 - if name_len > 0 and name_len < 128: - # 右段必须含 "t.CTypedef" - rest: str = src + line_start + j + 1 - if string.strstr(rest, "t.CTypedef") is not None: - # 提取 "=" 后的类型表达式(trim 空格) - eq_ptr: str = string.strstr(rest, "=") - if eq_ptr is not None: - ty_start: str = eq_ptr + 1 - while ty_start[0] == ' ': - ty_start += 1 - ty_end: t.CSizeT = string.strlen(ty_start) - while ty_end > 0 and (ty_start[ty_end - 1] == ' ' - or ty_start[ty_end - 1] == '\r'): - ty_end -= 1 - if ty_end > 0: - name_buf: str = pool.alloc(name_len + 1) - ty_buf: str = pool.alloc(ty_end + 1) - if name_buf is not None and ty_buf is not None: - string.strncpy(name_buf, src + line_start, name_len) - name_buf[name_len] = '\0' - string.strncpy(ty_buf, ty_start, ty_end) - ty_buf[ty_end] = '\0' - self.register_ctypedef(pool, name_buf, ty_buf) - count += 1 - line_start = i + 1 - i += 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 +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.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +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 + k_v: int = annotation.kind() + if k_v != ast.ASTKind.Attribute: + return 0 + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annotation) + # 字段访问改用 ast 模块访问器(跨模块 stub 字段访问陷阱防护: + # TypeGenCType 直接访问 at.attr 可能按 stub 类型生成错误 GEP, + # 读垃圾地址 → strcmp 0xC0000005 崩溃,stdint.vp 根因)。 + at_attr_v: str = ast.attribute_get_attr(at) + if at_attr_v is None: + return 0 + # 限长比较替代 strcmp:attr 是零拷贝引用 src_buf 的 token 字符串, + # 可能无 NUL 结尾("CTypedef" 后紧跟空格/其他字符),strcmp 会 + # 无限读穿到页边界 → 0xC0000005(stdint.vp 崩溃根因)。strncmp + # 只读 8 字节,再校验第 9 字节为终止/分隔符(防 "CTypedefXXX" 误匹配)。 + if string.strncmp(at_attr_v, "CTypedef", 8) != 0: + return 0 + sep_ch_d: t.CChar = at_attr_v[8] + if sep_ch_d != '\0' and sep_ch_d != ' ' and sep_ch_d != '\n' \ + and sep_ch_d != '\r' and sep_ch_d != '\t' and sep_ch_d != '|': + return 0 + at_val_v: ast.AST | t.CPtr = ast.attribute_get_value(at) + if at_val_v is None or at_val_v.kind() != ast.ASTKind.Name: + return 0 + mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_val_v) + mod_id_v: str = ast.name_get_id(mod_nm) + if mod_id_v is None: + return 0 + # 同样限长比较("t" 无 NUL 结尾时 strcmp 读穿) + if string.strncmp(mod_id_v, "t", 1) != 0: + return 0 + sep_ch_m: t.CChar = mod_id_v[1] + if sep_ch_m != '\0' and sep_ch_m != ' ' and sep_ch_m != '\n' \ + and sep_ch_m != '\r' and sep_ch_m != '\t' and sep_ch_m != '|': + 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) + if aa.annotation is None: + continue + # 检测注解是否为 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) + tgt_id_v: str = ast.name_get_id(tgt) + if tgt_id_v is None: + continue + # 提取类型表达式字符串(从 value AST 节点) + if aa.value is None: + continue + type_str: str = self.Gen.TypeGenResolve._get_type_name_from_annotation(pool, aa.value) + if type_str is None: + continue + # 注册 CTypedef + self.register_ctypedef(pool, tgt_id_v, type_str) + count += 1 + return count + def register_ctypedef_from_source(self, pool: memhub.MemBuddy | t.CPtr, + src: str) -> int: + """从源码文本逐行扫描注册 CTypedef(NAME: t.CTypedef = TYPE) + + stdint.vp 崩溃根因修复:AST 字符串字段(attr/id)token 零拷贝指向 + src_buf,跨阶段内容不稳定(悬空),ScanCTypedefDeclarations 读 + attr 会 0xC0000005。本函数在 src_buf 有效期内(Phase1 1b translate + 前)用纯文本匹配注册,不依赖 AST 节点内容。 + """ + if pool is None or src is None: + return 0 + # 文件边界防护:clear_ctypedefs 只在 translate 前调用(Phase1Main + # L800),文件级 reset_to(mark1) 回收本文件翻译期 pool 分配后,上一 + # 文件的 CTypedefNames 表指针悬空(非 None,list 本身也 pool 分配)。 + # 本函数去重遍历(register_ctypedef 内 strcmp)读已回收内存 → + # 0xC0000005(1.log: stdint.vp 翻译时 strcmp 读地址 0x4)。先清表 + # 重建,杜绝悬空遍历。翻译期 Handle 按需注册不受影响(L800 会再清)。 + self.clear_ctypedefs() + src_len: t.CSizeT = string.strlen(src) + count: int = 0 + line_start: t.CSizeT = 0 + i: t.CSizeT = 0 + while i <= src_len: + if i == src_len or src[i] == '\n': + line_len: t.CSizeT = i - line_start + if line_len > 0: + # 找行内第一个 ':'(跳过注释行) + j: t.CSizeT = 0 + found_colon: int = 0 + while j < line_len: + ch_c: t.CChar = src[line_start + j] + if ch_c == ':': + found_colon = 1 + break + if ch_c == '#' or ch_c == '\r': + break + j += 1 + if found_colon != 0: + # 左段 NAME(trim 尾随空格) + name_len: t.CSizeT = j + while name_len > 0 and src[line_start + name_len - 1] == ' ': + name_len -= 1 + if name_len > 0 and name_len < 128: + # 右段必须含 "t.CTypedef" + rest: str = src + line_start + j + 1 + if string.strstr(rest, "t.CTypedef") is not None: + # 提取 "=" 后的类型表达式(trim 空格) + eq_ptr: str = string.strstr(rest, "=") + if eq_ptr is not None: + ty_start: str = eq_ptr + 1 + while ty_start[0] == ' ': + ty_start += 1 + ty_end: t.CSizeT = string.strlen(ty_start) + while ty_end > 0 and (ty_start[ty_end - 1] == ' ' + or ty_start[ty_end - 1] == '\r'): + ty_end -= 1 + if ty_end > 0: + name_buf: str = pool.alloc(name_len + 1) + ty_buf: str = pool.alloc(ty_end + 1) + if name_buf is not None and ty_buf is not None: + string.strncpy(name_buf, src + line_start, name_len) + name_buf[name_len] = '\0' + string.strncpy(ty_buf, ty_start, ty_end) + ty_buf[ty_end] = '\0' + self.register_ctypedef(pool, name_buf, ty_buf) + count += 1 + line_start = i + 1 + i += 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.Gen.TypeGenCDef.lookup_cdefine_constant(nm.id) + if self.Gen.TypeGenCDef.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 = self.Gen.ExprGenCdef._lookup_cross_module_cdefine( + pool, nm.id, from_imports, imported_modules) + if self.Gen.TypeGenCDef.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 = self.Gen.ExprGenCdef._lookup_cross_module_cdefine( + pool, at.attr, fi_buf, imported_modules) + if self.Gen.TypeGenCDef.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 + diff --git a/App/lib/core/Gen/TypeGenErr.vp b/App/lib/core/Gen/TypeGenErr.vp index 4eb54a2..e67b160 100644 --- a/App/lib/core/Gen/TypeGenErr.vp +++ b/App/lib/core/Gen/TypeGenErr.vp @@ -1,3 +1,5 @@ +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.Generator as Generator import t, c from stdint import * import ast @@ -9,20 +11,9 @@ import stdio import stdlib import w32.fileio as fileio 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.Handles.HandlesTranslator as HT import lib.core.Gen.TypeGenBase as TypeGenBase @@ -123,8 +114,8 @@ class TypeGenErr(TypeGenBase.TypeGenBase): 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) + for i in range(self.Gen.TypeGenBase.TraceCount): + frame: GenTypes.TraceFrame | t.CPtr = self.Gen.TypeGenBase._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) @@ -138,16 +129,16 @@ class TypeGenErr(TypeGenBase.TypeGenBase): lineno: int = 0 if node is not None: lineno = node.lineno - file_name: str = self.CurrentFile + file_name: str = self.Gen.TypeGenResolve.get_current_file() 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 + if lineno <= 0 and self.Gen.TypeGenBase.TraceCount > 0: + ti_b: int = self.Gen.TypeGenBase.TraceCount - 1 while ti_b >= 0: - tfb: HandlesType.TraceFrame | t.CPtr = HandlesType._get_trace_frame(ti_b) + tfb: GenTypes.TraceFrame | t.CPtr = self.Gen.TypeGenBase._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 @@ -213,7 +204,7 @@ class TypeGenErr(TypeGenBase.TypeGenBase): 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) + return self.Gen.TypeGenResolve.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: """检测类型注解中是否包含指定的装饰器标记""" @@ -366,7 +357,7 @@ class TypeGenErr(TypeGenBase.TypeGenBase): 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) + resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.map_t_type(pool, at.attr) if resolved is not None: param_ty = resolved bits: int = self.get_llvm_type_bits(param_ty) diff --git a/App/lib/core/Gen/TypeGenMixin.vp b/App/lib/core/Gen/TypeGenMixin.vp index 0be0f84..4938353 100644 --- a/App/lib/core/Gen/TypeGenMixin.vp +++ b/App/lib/core/Gen/TypeGenMixin.vp @@ -1,44 +1,40 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import sys -import stdlib -import viperlib -import w32.fileio as fileio -import lib.core.CompilerFactory as CompilerFactory -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT -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) -# -# 500~1500 行/文件架构重构阶段 D:全部方法已拆至 -# TypeGenBase/CDef/CType/Resolve/Err,本文件保留类声明(Generator 继承链入口)。 -# -# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整,无 vtable 开销)。 -# ============================================================ - - -# ============================================================ -# 常量(与 HandlesType 保持一致) -# ============================================================ -TRACE_MAX: t.CDefine = 32 -MAX_CTYPEDEF_DEPTH: t.CDefine = 10 - - -# ============================================================ -# TypeGenMixin - 类型映射/注解解析/编译期常量表/错误上报 -# ============================================================ -@t.NoVTable -class TypeGenMixin(TypeGenBase.TypeGenBase): - """类型映射与解析 Mixin(阶段 D 拆分后顶层,方法全部在子 Mixin)""" +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import sys +import stdlib +import viperlib +import w32.fileio as fileio +import lib.core.CompilerFactory as CompilerFactory +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Gen.TypeGenBase as TypeGenBase + + +# ============================================================ +# TypeGenMixin - 类型映射与解析 Mixin(对象化 P2,wiki/14-oo-refactor.md) +# +# 500~1500 行/文件架构重构阶段 D:全部方法已拆至 +# TypeGenBase/CDef/CType/Resolve/Err,本文件保留类声明(Generator 继承链入口)。 +# +# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整,无 vtable 开销)。 +# ============================================================ + + +# ============================================================ +# 常量(与 HandlesType 保持一致) +# ============================================================ +TRACE_MAX: t.CDefine = 32 +MAX_CTYPEDEF_DEPTH: t.CDefine = 10 + + +# ============================================================ +# TypeGenMixin - 类型映射/注解解析/编译期常量表/错误上报 +# ============================================================ +@t.NoVTable +class TypeGenMixin(TypeGenBase.TypeGenBase): + """类型映射与解析 Mixin(阶段 D 拆分后顶层,方法全部在子 Mixin)""" diff --git a/App/lib/core/Gen/TypeGenResolve.vp b/App/lib/core/Gen/TypeGenResolve.vp index 9aaed66..b110c55 100644 --- a/App/lib/core/Gen/TypeGenResolve.vp +++ b/App/lib/core/Gen/TypeGenResolve.vp @@ -1,1453 +1,1450 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import viperlib -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 -import lib.core.Handles.ExprCallCtor as ExprCallCtor - -# ============================================================ -# 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) - cn_val_v: str = ast.constant_get_str_val(cn) - if cn.const_kind == ast.CONST_STR and cn_val_v is not None: - return cn_val_v - 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(ast.name_get_id(nm)) - # Attribute: 构造 "module.attr" 格式 - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - at_attr_v: str = ast.attribute_get_attr(at) - if at_attr_v is None: - return None - at_val_v: ast.AST | t.CPtr = ast.attribute_get_value(at) - if at_val_v is not None and at_val_v.kind() == ast.ASTKind.Name: - mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_val_v) - mod_id_v: str = ast.name_get_id(mod_nm) - if mod_id_v is not None: - total: t.CSizeT = string.strlen(mod_id_v) + 1 + string.strlen(at_attr_v) + 1 - buf: str = pool.alloc(total) - if buf is not None: - buf[0] = '\0' - string.strcat(buf, mod_id_v) - string.strcat(buf, ".") - string.strcat(buf, at_attr_v) - return buf - return at_attr_v - # 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, ast.binop_get_left(bop)) - right_str: str = self._get_type_name_from_annotation(pool, ast.binop_get_right(bop)) - 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 = ExprCallCtor._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) - 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)) - 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 函数名白名单) +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.Generator as Generator +import lib.core.Gen.TypeGenCType as TypeGenCType +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import viperlib +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.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +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) + cn_val_v: str = ast.constant_get_str_val(cn) + if cn.const_kind == ast.CONST_STR and cn_val_v is not None: + return cn_val_v + 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.Gen.TypeGenBase.resolve_generic_type_name(ast.name_get_id(nm)) + # Attribute: 构造 "module.attr" 格式 + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + at_attr_v: str = ast.attribute_get_attr(at) + if at_attr_v is None: + return None + at_val_v: ast.AST | t.CPtr = ast.attribute_get_value(at) + if at_val_v is not None and at_val_v.kind() == ast.ASTKind.Name: + mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_val_v) + mod_id_v: str = ast.name_get_id(mod_nm) + if mod_id_v is not None: + total: t.CSizeT = string.strlen(mod_id_v) + 1 + string.strlen(at_attr_v) + 1 + buf: str = pool.alloc(total) + if buf is not None: + buf[0] = '\0' + string.strcat(buf, mod_id_v) + string.strcat(buf, ".") + string.strcat(buf, at_attr_v) + return buf + return at_attr_v + # 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, ast.binop_get_left(bop)) + right_str: str = self._get_type_name_from_annotation(pool, ast.binop_get_right(bop)) + 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 self.Gen.ImportsGen.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.Gen.TypeGenBase.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 = self.Gen.StructGen.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: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.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 = self.Gen.TypeGenResolve.get_current_file() + self.Gen.TypeGenBase.push_trace(gen_cur_f, sub.lineno) + self.Gen.ClassGenGeneric._specialize_generic_class(trans, gen_cls_name, gen_arg_names) + self.Gen.TypeGenBase.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 = self.Gen.ClassGenGeneric._find_generic_template(gen_cls_name) + if template_cd_chk is not None: + type_args_chk: list[str] | t.CPtr = self.Gen.CallGenCtor._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 = self.Gen.TypeGenResolve.get_current_file() + self.Gen.TypeGenBase.push_trace(gen_cur_f2, sub.lineno) + spec_name_chk: str = self.Gen.ClassGenGeneric._specialize_generic_class( + trans, gen_cls_name, type_args_chk) + self.Gen.TypeGenBase.pop_trace() + if spec_name_chk is not None: + gen_spec_ty = self.Gen.StructGen.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) + 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 替换为具体类型 + tpn_g: list[str] | t.CPtr = self.Gen.TypeGenBase.GenericTpNames + tpa_g: list[str] | t.CPtr = self.Gen.TypeGenBase.GenericTypeArgs + if tpn_g is not None and tpa_g is not None: + gp_n: t.CSizeT = len(tpn_g) + gp_i: t.CSizeT + for gp_i in range(gp_n): + gp_tpn: str = tpn_g.get(gp_i) + if gp_tpn is not None and string.strcmp(nm.id, gp_tpn) == 0: + gp_ta: str = tpa_g.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 = tpn_g.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)) + 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: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.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 self.Gen.StructGen.is_struct_visible(nm.id) != 0: + struct_ty: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type(nm.id) + if struct_ty is not None: + nm_entry_s: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.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 self.Gen.StmtGenDecl.is_enum_class(nm.id) == 1: + return self.Gen.StmtGenDecl.get_enum_base_type(nm.id) + # CTypedef 动态查表:查动态 CTypedef 表,递归解析类型表达式 + # 用户自定义 CTypedef(如 MyHandle: t.CTypedef = VOIDPTR)在此解析 + # 递归深度限制 MAX_CTYPEDEF_DEPTH 防止无限递归,循环检测防止 A→B→A + if self.Gen.TypeGenCType.CTypedefResolveDepth < MAX_CTYPEDEF_DEPTH: + ctypedef_str: str = self.Gen.TypeGenCType.lookup_ctypedef(nm.id) + if ctypedef_str is not None and self.Gen.TypeGenCType.CTypedefFound != 0: + # 循环检测:将当前 CTypedef 名加入正在解析列表 + if self.Gen.TypeGenCType._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.Gen.TypeGenCType.CTypedefResolveDepth += 1 + inner_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( + pool, inner_node, imported_modules, from_imports, trans) + self.Gen.TypeGenCType.CTypedefResolveDepth -= 1 + self.Gen.TypeGenCType._ctypedef_pop_visiting() + if inner_ty is not None: + return inner_ty + else: + self.Gen.TypeGenCType._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 = self.Gen.ImportsGen.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 = self.Gen.StructGen.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 self.Gen.StmtGenDecl.is_enum_class(at.attr) == 1: + return self.Gen.StmtGenDecl.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.Gen.TypeGenCType.CTypedefResolveDepth < MAX_CTYPEDEF_DEPTH: + mod_td_str: str = self.Gen.TypeGenCType.lookup_ctypedef(at.attr) + if mod_td_str is not None and self.Gen.TypeGenCType.CTypedefFound != 0: + if self.Gen.TypeGenCType._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.Gen.TypeGenCType.CTypedefResolveDepth += 1 + mod_td_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( + pool, mod_td_inner, imported_modules, from_imports, trans) + self.Gen.TypeGenCType.CTypedefResolveDepth -= 1 + self.Gen.TypeGenCType._ctypedef_pop_visiting() + if mod_td_ty is not None: + return mod_td_ty + else: + self.Gen.TypeGenCType._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 = self.Gen.StructGen.get_struct_type(at.attr) + if nested_struct_ty is not None: + return nested_struct_ty + # 嵌套模块限定的枚举类(fat32_types.FRESULT 三级名):查枚举基类型 + if self.Gen.StmtGenDecl.is_enum_class(at.attr) == 1: + return self.Gen.StmtGenDecl.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.Gen.TypeGenCType.CTypedefResolveDepth < MAX_CTYPEDEF_DEPTH: + nested_td_str: str = self.Gen.TypeGenCType.lookup_ctypedef(at.attr) + if nested_td_str is not None and self.Gen.TypeGenCType.CTypedefFound != 0: + if self.Gen.TypeGenCType._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.Gen.TypeGenCType.CTypedefResolveDepth += 1 + nested_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( + pool, nested_inner, imported_modules, from_imports, trans) + self.Gen.TypeGenCType.CTypedefResolveDepth -= 1 + self.Gen.TypeGenCType._ctypedef_pop_visiting() + if nested_ty is not None: + return nested_ty + else: + self.Gen.TypeGenCType._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 self.Gen.ImportsGen.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 self.Gen.StructGen.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 + tpn_g2: list[str] | t.CPtr = self.Gen.TypeGenBase.GenericTpNames + if tpn_g2 is not None: + other_nm_x: ast.Name | t.CPtr = (ast.Name | t.CPtr)(other_node) + gtn_nx: t.CSizeT = len(tpn_g2) + gtn_ix: t.CSizeT + for gtn_ix in range(gtn_nx): + gtn_nmx: str = tpn_g2.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 = self.Gen.StructGen.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.Gen.TypeGenErr.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.Gen.TypeGenCType._eval_const_int_expr( + count_node_n, pool, from_imports, imported_modules) + if self.Gen.TypeGenCType.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.Gen.TypeGenErr.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.Gen.TypeGenErr.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 self.Gen.ClassGenGeneric._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.Gen.TypeGenErr.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.Gen.TypeGenErr.fatal_type_error(node, "Subscript 模块名为 None") + # 函数指针类型: t.Callable[[A, B], Ret] → i8* + # 与 TPV 函数传指针惯例一致(函数值 bitcast 为 i8* 存储,调用时按实参重建签名) + if string.strcmp(arr_at.attr, "Callable") == 0: + if self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0: + self.Gen.TypeGenErr.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 self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0: + self.Gen.TypeGenErr.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.Gen.TypeGenErr.fatal_type_error(sub.slice, "t.CPtr[?] 元素类型解析失败") + return llvmlite.Ptr(pool, inner_cptr_ty) + if string.strcmp(arr_at.attr, "CArray") != 0: + self.Gen.TypeGenErr.fatal_type_error(node, "不支持的 Subscript 类型注解(仅支持 t.CArray / t.Callable)") + if self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0: + self.Gen.TypeGenErr.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.Gen.TypeGenErr.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.Gen.TypeGenErr.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.Gen.TypeGenErr.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.Gen.TypeGenErr.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.Gen.TypeGenErr.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.Gen.TypeGenCType._eval_const_int_expr(count_node, pool, from_imports, imported_modules) + if self.Gen.TypeGenCType.ConstEvalOk == 0: + self.Gen.TypeGenErr.fatal_type_error(count_node, "t.CArray count 必须是整数常量、None、CDefine 常量名或常量表达式") + if count_val <= 0: + self.Gen.TypeGenErr.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.Gen.TypeGenErr.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/Gen/VarGenMixin.vp b/App/lib/core/Gen/VarGenMixin.vp index 1befeac..968b358 100644 --- a/App/lib/core/Gen/VarGenMixin.vp +++ b/App/lib/core/Gen/VarGenMixin.vp @@ -1,403 +1,404 @@ -import t, c -from stdint import * -import llvmlite -import memhub -import string -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesType as HandlesType - - -# ============================================================ -# VarGenMixin - 变量/作用域符号表 Mixin(P6 对象化,wiki/14-oo-refactor.md) -# -# 从 HandlesVar.vp 迁移:模块级函数(init_vars/find_var/find_var_entry/ -# lookup_var_entry/set_var_annot_class_name/set_var_ptr_element/add_var/ -# _alloca_at_entry/get_or_create_var/_create_scope/init_symbol_table/ -# enter_scope/exit_scope/define_var/define_module_var/lookup_var/ -# lookup_current/lookup_module_var/is_module_scope/get_or_create_sym) -# → 本类方法。 -# -# 迁移原则(与 P1-P5 一致,行为零变化): -# 1. 方法保留原函数签名(含 symtab/vars_ptr 等指针首参——self 是宿主 -# Generator,这些函数操作数据结构指针,self 可能少用,但为风格 -# 统一仍方法化) -# 2. 函数体原样搬入,本模块内部函数调用改为 self.xxx(...); -# 跨模块调用保留模块前缀(本模块无跨模块调用) -# 3. HandlesVar.vp 原函数保留为"一行委托":本地模块级单例 _g_gen -# (BuildPipeline/main 注入)cast 成 Generator 类型后调本类方法 -# 4. VarEntry/Scope/SymbolTable 数据结构类保留在 HandlesVar.vp -# (本类方法签名/函数体经 HandlesVar 前缀引用) -# -# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整,无 vtable 开销)。 -# ============================================================ - - -# ============================================================ -# 常量(与 HandlesVar 保持一致) -# ============================================================ -# 作用域类型常量 -SCOPE_MODULE: t.CDefine = 0 -SCOPE_FUNCTION: t.CDefine = 1 -SCOPE_BLOCK: t.CDefine = 2 - -# 每个作用域最大变量数 -# 256 太小:NewAstTest main() 有 289 个局部变量(几十个测试用例), -# add_var 超限静默失败导致变量未注册,后续使用报"未定义名称"(NameError)。 -MAX_VARS: t.CDefine = 1024 - - -# ============================================================ -# VarGenMixin - 变量/作用域符号表 Mixin -# ============================================================ -@t.NoVTable -class VarGenMixin: - """变量/作用域 Mixin(P6 方法化)""" - # 迁移自 HandlesVar 的模块级函数 - - # ============================================================ - # init_vars — 分配并清零 VarEntry 数组 - # ============================================================ - def init_vars(self, pool: memhub.MemBuddy | t.CPtr) -> HandlesVar.VarEntry | t.CPtr: - """分配并清零变量表数组""" - size: t.CSizeT = MAX_VARS * HandlesVar.VarEntry.__sizeof__() - vars_ptr: HandlesVar.VarEntry | t.CPtr = pool.alloc(size) - if vars_ptr is not None: - string.memset(vars_ptr, 0, size) - return vars_ptr - - # ============================================================ - # find_var — 在变量表中按名称查找 - # ============================================================ - def find_var(self, vars_ptr: HandlesVar.VarEntry | t.CPtr, - var_count: int, - name: str) -> llvmlite.Value | t.CPtr: - """在变量表中按名称查找""" - if name is None or vars_ptr is None: - return None - entry_size: t.CSizeT = HandlesVar.VarEntry.__sizeof__() - for i in range(var_count): - entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + i * entry_size - entry: HandlesVar.VarEntry | t.CPtr = (HandlesVar.VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - if entry.Name is not None and entry.Used != 0: - if string.strcmp(entry.Name, name) == 0: - return entry.Alloca - return None - - # ============================================================ - # find_var_entry — 在变量表中按名称查找,返回 VarEntry(含 AnnotTy) - # ============================================================ - def find_var_entry(self, vars_ptr: HandlesVar.VarEntry | t.CPtr, - var_count: int, - name: str) -> HandlesVar.VarEntry | t.CPtr: - """在变量表中按名称查找,返回 VarEntry 或 None""" - if name is None or vars_ptr is None: - return None - entry_size: t.CSizeT = HandlesVar.VarEntry.__sizeof__() - for i in range(var_count): - entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + i * entry_size - entry: HandlesVar.VarEntry | t.CPtr = (HandlesVar.VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - if entry.Name is not None and entry.Used != 0: - if string.strcmp(entry.Name, name) == 0: - return entry - return None - - # ============================================================ - # lookup_var_entry — 从当前作用域逐级向上查找变量,返回 VarEntry - # ============================================================ - def lookup_var_entry(self, symtab: HandlesVar.SymbolTable | t.CPtr, - name: str) -> HandlesVar.VarEntry | t.CPtr: - """从当前作用域逐级向上查找变量,返回 VarEntry 或 None""" - if symtab is None or name is None: - return None - scope: HandlesVar.Scope | t.CPtr = symtab.Current - while scope is not None: - result: HandlesVar.VarEntry | t.CPtr = self.find_var_entry(scope.Vars, scope.VarCount, name) - if result is not None: - return result - scope = scope.Parent - return None - - # ============================================================ - # set_var_annot_class_name — 设置变量的原始类型注解类名 - # - # 在函数参数定义后调用,存储原始类型注解的类名。 - # 方法调用检测时,当 alloca 类型是 Ptr(i8)(联合类型简化), - # 通过 AnnotClassName 查找实际结构体类型。 - # ============================================================ - def set_var_annot_class_name(self, symtab: HandlesVar.SymbolTable | t.CPtr, - name: str, - class_name: str) -> int: - """设置变量的原始类型注解类名,返回 0=成功 / 1=失败""" - if symtab is None or name is None: - return 1 - entry: HandlesVar.VarEntry | t.CPtr = self.lookup_var_entry(symtab, name) - if entry is None: - return 1 - entry.AnnotClassName = class_name - return 0 - - # ============================================================ - # set_var_ptr_element — 标记变量为"指针到 str/bytes"类型 - # - # 注解为 bytes|t.CPtr 或 str|t.CPtr 的变量,其 alloca 类型是 i8*, - # 但下标访问应按 8 字节步长(i8** 语义),而非 1 字节步长(i8* 语义)。 - # 此标志在 HandlesAnnAssign 中根据注解形式设置。 - # ============================================================ - def set_var_ptr_element(self, symtab: HandlesVar.SymbolTable | t.CPtr, - name: str) -> int: - """标记变量为 ptr_element 类型,返回 0=成功 / 1=失败""" - if symtab is None or name is None: - return 1 - entry: HandlesVar.VarEntry | t.CPtr = self.lookup_var_entry(symtab, name) - if entry is None: - return 1 - entry.IsPtrElement = 1 - return 0 - - # ============================================================ - # add_var — 添加变量到变量表 - # ============================================================ - def add_var(self, vars_ptr: HandlesVar.VarEntry | t.CPtr, - var_count: int, - name: str, - alloca: llvmlite.Value | t.CPtr) -> int: - """添加变量到变量表""" - if name is None or alloca is None or vars_ptr is None: - return 1 - if var_count >= MAX_VARS: - return 1 - entry_size: t.CSizeT = HandlesVar.VarEntry.__sizeof__() - entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + var_count * entry_size - entry: HandlesVar.VarEntry | t.CPtr = (HandlesVar.VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - entry.Name = name - entry.Alloca = alloca - entry.Used = 1 - return 0 - - # ============================================================ - # _alloca_at_entry - 在函数入口块生成 alloca(确保支配性) - # - # LLVM IR 要求指令支配所有使用点。如果 alloca 在条件分支内生成, - # 但在其他分支使用,会违反支配性(Instruction does not dominate all uses)。 - # 标准做法:所有 alloca 在函数入口块生成。 - # - # 临时切换 builder.CurBlock 到入口块,生成 alloca,然后恢复。 - # ============================================================ - def _alloca_at_entry(self, builder: llvmlite.IRBuilder | t.CPtr, - ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: - """在函数入口块生成 alloca,返回 alloca 值 - - 使用 llvmlite.build_alloca_at_entry 在入口块终止指令之前插入 alloca, - 确保所有 alloca 在入口块,避免支配性违规。 - """ - if builder is None or ty is None: - return None - return llvmlite.build_alloca_at_entry(builder, ty) - - # ============================================================ - # get_or_create_var — 查找或创建变量 alloca(旧版兼容) - # ============================================================ - def get_or_create_var(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - vars_ptr: HandlesVar.VarEntry | t.CPtr, - var_count: int, - name: str, - ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: - """查找或创建变量 alloca""" - existing: llvmlite.Value | t.CPtr = self.find_var(vars_ptr, var_count, name) - if existing is not None: - return existing - alloca: llvmlite.Value | t.CPtr = self._alloca_at_entry(builder, ty) - if alloca is None: - return None - if self.add_var(vars_ptr, var_count, name, alloca) != 0: - return None - return alloca - - # ============================================================ - # _create_scope — 创建新作用域节点(内部辅助函数) - # ============================================================ - def _create_scope(self, pool: memhub.MemBuddy | t.CPtr, - parent: HandlesVar.Scope | t.CPtr, - kind: int) -> HandlesVar.Scope | t.CPtr: - """创建并初始化作用域节点""" - scope: HandlesVar.Scope | t.CPtr = pool.alloc(HandlesVar.Scope.__sizeof__()) - if scope is None: - return None - string.memset(scope, 0, HandlesVar.Scope.__sizeof__()) - scope.Parent = parent - scope.Vars = self.init_vars(pool) - scope.VarCount = 0 - scope.Kind = kind - if scope.Vars is None: - return None - return scope - - # ============================================================ - # init_symbol_table — 创建符号表(含模块级根作用域) - # ============================================================ - def init_symbol_table(self, pool: memhub.MemBuddy | t.CPtr) -> HandlesVar.SymbolTable | t.CPtr: - """创建并初始化符号表,包含模块级根作用域""" - if pool is None: - return None - symtab: HandlesVar.SymbolTable | t.CPtr = pool.alloc(HandlesVar.SymbolTable.__sizeof__()) - if symtab is None: - return None - string.memset(symtab, 0, HandlesVar.SymbolTable.__sizeof__()) - symtab.Pool = pool - - # 创建根作用域(模块级) - root: HandlesVar.Scope | t.CPtr = self._create_scope(pool, None, SCOPE_MODULE) - if root is None: - return None - - symtab.Root = root - symtab.Current = root - return symtab - - # ============================================================ - # enter_scope — 进入新作用域 - # ============================================================ - def enter_scope(self, symtab: HandlesVar.SymbolTable | t.CPtr, - kind: int) -> HandlesVar.Scope | t.CPtr: - """进入新作用域,返回新创建的作用域""" - if symtab is None: - return None - pool: memhub.MemBuddy | t.CPtr = symtab.Pool - scope: HandlesVar.Scope | t.CPtr = self._create_scope(pool, symtab.Current, kind) - if scope is None: - return None - symtab.Current = scope - return scope - - # ============================================================ - # exit_scope — 退出当前作用域 - # ============================================================ - def exit_scope(self, symtab: HandlesVar.SymbolTable | t.CPtr): - """退出当前作用域,恢复到父作用域""" - if symtab is not None and symtab.Current is not None: - symtab.Current = symtab.Current.Parent - - # ============================================================ - # define_var — 在当前作用域定义变量 - # ============================================================ - def define_var(self, symtab: HandlesVar.SymbolTable | t.CPtr, - name: str, - alloca: llvmlite.Value | t.CPtr) -> int: - """在当前作用域定义变量,返回 0 成功""" - if symtab is None or name is None or alloca is None: - return 1 - scope: HandlesVar.Scope | t.CPtr = symtab.Current - if scope is None: - return 1 - ret: int = self.add_var(scope.Vars, scope.VarCount, name, alloca) - if ret == 0: - scope.VarCount = scope.VarCount + 1 - return ret - - # ============================================================ - # define_module_var — 在模块作用域定义变量 - # ============================================================ - def define_module_var(self, symtab: HandlesVar.SymbolTable | t.CPtr, - name: str, - alloca: llvmlite.Value | t.CPtr) -> int: - """在模块作用域定义变量,返回 0 成功""" - if symtab is None or name is None or alloca is None: - return 1 - scope: HandlesVar.Scope | t.CPtr = symtab.Root - if scope is None: - return 1 - ret: int = self.add_var(scope.Vars, scope.VarCount, name, alloca) - if ret == 0: - scope.VarCount = scope.VarCount + 1 - return ret - - # ============================================================ - # lookup_var — 从当前作用域逐级向上查找变量 - # ============================================================ - def lookup_var(self, symtab: HandlesVar.SymbolTable | t.CPtr, - name: str) -> llvmlite.Value | t.CPtr: - """从当前作用域逐级向上查找变量,返回 alloca 或 None""" - if symtab is None or name is None: - return None - scope: HandlesVar.Scope | t.CPtr = symtab.Current - while scope is not None: - result: llvmlite.Value | t.CPtr = self.find_var( - scope.Vars, scope.VarCount, name) - if result is not None: - return result - scope = scope.Parent - return None - - # ============================================================ - # lookup_current — 仅在当前作用域查找变量 - # ============================================================ - def lookup_current(self, symtab: HandlesVar.SymbolTable | t.CPtr, - name: str) -> llvmlite.Value | t.CPtr: - """仅在当前作用域查找变量""" - if symtab is None or name is None: - return None - scope: HandlesVar.Scope | t.CPtr = symtab.Current - if scope is None: - return None - return self.find_var(scope.Vars, scope.VarCount, name) - - # ============================================================ - # lookup_module_var — 在模块作用域查找变量 - # ============================================================ - def lookup_module_var(self, symtab: HandlesVar.SymbolTable | t.CPtr, - name: str) -> llvmlite.Value | t.CPtr: - """在模块作用域查找变量""" - if symtab is None or name is None: - return None - scope: HandlesVar.Scope | t.CPtr = symtab.Root - if scope is None: - return None - return self.find_var(scope.Vars, scope.VarCount, name) - - # ============================================================ - # is_module_scope - 判断当前是否在模块级作用域 - # - # 用于区分模块级代码和函数内代码: - # - 模块级代码:AnnAssign 应修改模块级变量(Python 语义) - # - 函数内代码:无 global 声明时 AnnAssign 应创建局部变量(Python 语义) - # ============================================================ - def is_module_scope(self, symtab: HandlesVar.SymbolTable | t.CPtr) -> int: - """判断当前作用域是否为模块级作用域(Current == Root) - - Returns: 1=模块级作用域, 0=函数内作用域 - """ - if symtab is None: - return 0 - if symtab.Root is None or symtab.Current is None: - return 0 - # 比较指针:Current 与 Root 相同则为模块级 - if t.CUInt64T(symtab.Current) == t.CUInt64T(symtab.Root): - return 1 - return 0 - - # ============================================================ - # get_or_create_sym — 查找或创建变量(在当前作用域) - # ============================================================ - def get_or_create_sym(self, symtab: HandlesVar.SymbolTable | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - name: str, - ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: - """查找或创建变量 alloca(在当前作用域)""" - existing: llvmlite.Value | t.CPtr = self.lookup_current(symtab, name) - if existing is not None: - return existing - alloca: llvmlite.Value | t.CPtr = self._alloca_at_entry(builder, ty) - if alloca is None: - return None - if self.define_var(symtab, name, alloca) != 0: - # fail-fast: 变量注册失败(如超过 MAX_VARS)必须立即终止。 - # 此前静默忽略返回值:alloca 已创建但未入符号表,后续读取该变量 - # 报"未定义名称"(NewAstTest main() 289 个局部变量 > MAX_VARS=256 - # 的 NameError 根因),误导排查。变量表超限暴露上游规模问题。 - HandlesType.fatal_error( - None, - f"变量 '{name}' 注册失败(作用域变量数超过上限 MAX_VARS)", - "InternalCompilerError") - return alloca +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.Generator as Generator +import t, c +from stdint import * +import llvmlite +import memhub +import string + + +# ============================================================ +# VarGenMixin - 变量/作用域符号表 Mixin(P6 对象化,wiki/14-oo-refactor.md) +# +# 从 HandlesVar.vp 迁移:模块级函数(init_vars/find_var/find_var_entry/ +# lookup_var_entry/set_var_annot_class_name/set_var_ptr_element/add_var/ +# _alloca_at_entry/get_or_create_var/_create_scope/init_symbol_table/ +# enter_scope/exit_scope/define_var/define_module_var/lookup_var/ +# lookup_current/lookup_module_var/is_module_scope/get_or_create_sym) +# → 本类方法。 +# +# 迁移原则(与 P1-P5 一致,行为零变化): +# 1. 方法保留原函数签名(含 symtab/vars_ptr 等指针首参——self 是宿主 +# Generator,这些函数操作数据结构指针,self 可能少用,但为风格 +# 统一仍方法化) +# 2. 函数体原样搬入,本模块内部函数调用改为 self.xxx(...); +# 跨模块调用保留模块前缀(本模块无跨模块调用) +# 3. HandlesVar.vp 原函数保留为"一行委托":本地模块级单例 _g_gen +# (BuildPipeline/main 注入)cast 成 Generator 类型后调本类方法 +# 4. VarEntry/Scope/SymbolTable 数据结构类保留在 HandlesVar.vp +# (本类方法签名/函数体经 HandlesVar 前缀引用) +# +# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整,无 vtable 开销)。 +# ============================================================ + + +# ============================================================ +# 常量(与 HandlesVar 保持一致) +# ============================================================ +# 作用域类型常量 +SCOPE_MODULE: t.CDefine = 0 +SCOPE_FUNCTION: t.CDefine = 1 +SCOPE_BLOCK: t.CDefine = 2 + +# 每个作用域最大变量数 +# 256 太小:NewAstTest main() 有 289 个局部变量(几十个测试用例), +# add_var 超限静默失败导致变量未注册,后续使用报"未定义名称"(NameError)。 +MAX_VARS: t.CDefine = 1024 + + +# ============================================================ +# VarGenMixin - 变量/作用域符号表 Mixin +# ============================================================ +@t.NoVTable +class VarGenMixin: + """变量/作用域 Mixin(P6 方法化)""" + # 迁移自 HandlesVar 的模块级函数 + + # ============================================================ + # init_vars — 分配并清零 VarEntry 数组 + # ============================================================ + Gen: Generator.Generator | t.CPtr + def init_vars(self, pool: memhub.MemBuddy | t.CPtr) -> GenTypes.VarEntry | t.CPtr: + """分配并清零变量表数组""" + size: t.CSizeT = MAX_VARS * GenTypes.VarEntry.__sizeof__() + vars_ptr: GenTypes.VarEntry | t.CPtr = pool.alloc(size) + if vars_ptr is not None: + string.memset(vars_ptr, 0, size) + return vars_ptr + + # ============================================================ + # find_var — 在变量表中按名称查找 + # ============================================================ + def find_var(self, vars_ptr: GenTypes.VarEntry | t.CPtr, + var_count: int, + name: str) -> llvmlite.Value | t.CPtr: + """在变量表中按名称查找""" + if name is None or vars_ptr is None: + return None + entry_size: t.CSizeT = GenTypes.VarEntry.__sizeof__() + for i in range(var_count): + entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + i * entry_size + entry: GenTypes.VarEntry | t.CPtr = (GenTypes.VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + if entry.Name is not None and entry.Used != 0: + if string.strcmp(entry.Name, name) == 0: + return entry.Alloca + return None + + # ============================================================ + # find_var_entry — 在变量表中按名称查找,返回 VarEntry(含 AnnotTy) + # ============================================================ + def find_var_entry(self, vars_ptr: GenTypes.VarEntry | t.CPtr, + var_count: int, + name: str) -> GenTypes.VarEntry | t.CPtr: + """在变量表中按名称查找,返回 VarEntry 或 None""" + if name is None or vars_ptr is None: + return None + entry_size: t.CSizeT = GenTypes.VarEntry.__sizeof__() + for i in range(var_count): + entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + i * entry_size + entry: GenTypes.VarEntry | t.CPtr = (GenTypes.VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + if entry.Name is not None and entry.Used != 0: + if string.strcmp(entry.Name, name) == 0: + return entry + return None + + # ============================================================ + # lookup_var_entry — 从当前作用域逐级向上查找变量,返回 VarEntry + # ============================================================ + def lookup_var_entry(self, symtab: GenTypes.SymbolTable | t.CPtr, + name: str) -> GenTypes.VarEntry | t.CPtr: + """从当前作用域逐级向上查找变量,返回 VarEntry 或 None""" + if symtab is None or name is None: + return None + scope: GenTypes.Scope | t.CPtr = symtab.Current + while scope is not None: + result: GenTypes.VarEntry | t.CPtr = self.find_var_entry(scope.Vars, scope.VarCount, name) + if result is not None: + return result + scope = scope.Parent + return None + + # ============================================================ + # set_var_annot_class_name — 设置变量的原始类型注解类名 + # + # 在函数参数定义后调用,存储原始类型注解的类名。 + # 方法调用检测时,当 alloca 类型是 Ptr(i8)(联合类型简化), + # 通过 AnnotClassName 查找实际结构体类型。 + # ============================================================ + def set_var_annot_class_name(self, symtab: GenTypes.SymbolTable | t.CPtr, + name: str, + class_name: str) -> int: + """设置变量的原始类型注解类名,返回 0=成功 / 1=失败""" + if symtab is None or name is None: + return 1 + entry: GenTypes.VarEntry | t.CPtr = self.lookup_var_entry(symtab, name) + if entry is None: + return 1 + entry.AnnotClassName = class_name + return 0 + + # ============================================================ + # set_var_ptr_element — 标记变量为"指针到 str/bytes"类型 + # + # 注解为 bytes|t.CPtr 或 str|t.CPtr 的变量,其 alloca 类型是 i8*, + # 但下标访问应按 8 字节步长(i8** 语义),而非 1 字节步长(i8* 语义)。 + # 此标志在 HandlesAnnAssign 中根据注解形式设置。 + # ============================================================ + def set_var_ptr_element(self, symtab: GenTypes.SymbolTable | t.CPtr, + name: str) -> int: + """标记变量为 ptr_element 类型,返回 0=成功 / 1=失败""" + if symtab is None or name is None: + return 1 + entry: GenTypes.VarEntry | t.CPtr = self.lookup_var_entry(symtab, name) + if entry is None: + return 1 + entry.IsPtrElement = 1 + return 0 + + # ============================================================ + # add_var — 添加变量到变量表 + # ============================================================ + def add_var(self, vars_ptr: GenTypes.VarEntry | t.CPtr, + var_count: int, + name: str, + alloca: llvmlite.Value | t.CPtr) -> int: + """添加变量到变量表""" + if name is None or alloca is None or vars_ptr is None: + return 1 + if var_count >= MAX_VARS: + return 1 + entry_size: t.CSizeT = GenTypes.VarEntry.__sizeof__() + entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + var_count * entry_size + entry: GenTypes.VarEntry | t.CPtr = (GenTypes.VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + entry.Name = name + entry.Alloca = alloca + entry.Used = 1 + return 0 + + # ============================================================ + # _alloca_at_entry - 在函数入口块生成 alloca(确保支配性) + # + # LLVM IR 要求指令支配所有使用点。如果 alloca 在条件分支内生成, + # 但在其他分支使用,会违反支配性(Instruction does not dominate all uses)。 + # 标准做法:所有 alloca 在函数入口块生成。 + # + # 临时切换 builder.CurBlock 到入口块,生成 alloca,然后恢复。 + # ============================================================ + def _alloca_at_entry(self, builder: llvmlite.IRBuilder | t.CPtr, + ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: + """在函数入口块生成 alloca,返回 alloca 值 + + 使用 llvmlite.build_alloca_at_entry 在入口块终止指令之前插入 alloca, + 确保所有 alloca 在入口块,避免支配性违规。 + """ + if builder is None or ty is None: + return None + return llvmlite.build_alloca_at_entry(builder, ty) + + # ============================================================ + # get_or_create_var — 查找或创建变量 alloca(旧版兼容) + # ============================================================ + def get_or_create_var(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + vars_ptr: GenTypes.VarEntry | t.CPtr, + var_count: int, + name: str, + ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: + """查找或创建变量 alloca""" + existing: llvmlite.Value | t.CPtr = self.find_var(vars_ptr, var_count, name) + if existing is not None: + return existing + alloca: llvmlite.Value | t.CPtr = self._alloca_at_entry(builder, ty) + if alloca is None: + return None + if self.add_var(vars_ptr, var_count, name, alloca) != 0: + return None + return alloca + + # ============================================================ + # _create_scope — 创建新作用域节点(内部辅助函数) + # ============================================================ + def _create_scope(self, pool: memhub.MemBuddy | t.CPtr, + parent: GenTypes.Scope | t.CPtr, + kind: int) -> GenTypes.Scope | t.CPtr: + """创建并初始化作用域节点""" + scope: GenTypes.Scope | t.CPtr = pool.alloc(GenTypes.Scope.__sizeof__()) + if scope is None: + return None + string.memset(scope, 0, GenTypes.Scope.__sizeof__()) + scope.Parent = parent + scope.Vars = self.init_vars(pool) + scope.VarCount = 0 + scope.Kind = kind + if scope.Vars is None: + return None + return scope + + # ============================================================ + # init_symbol_table — 创建符号表(含模块级根作用域) + # ============================================================ + def init_symbol_table(self, pool: memhub.MemBuddy | t.CPtr) -> GenTypes.SymbolTable | t.CPtr: + """创建并初始化符号表,包含模块级根作用域""" + if pool is None: + return None + symtab: GenTypes.SymbolTable | t.CPtr = pool.alloc(GenTypes.SymbolTable.__sizeof__()) + if symtab is None: + return None + string.memset(symtab, 0, GenTypes.SymbolTable.__sizeof__()) + symtab.Pool = pool + + # 创建根作用域(模块级) + root: GenTypes.Scope | t.CPtr = self._create_scope(pool, None, SCOPE_MODULE) + if root is None: + return None + + symtab.Root = root + symtab.Current = root + return symtab + + # ============================================================ + # enter_scope — 进入新作用域 + # ============================================================ + def enter_scope(self, symtab: GenTypes.SymbolTable | t.CPtr, + kind: int) -> GenTypes.Scope | t.CPtr: + """进入新作用域,返回新创建的作用域""" + if symtab is None: + return None + pool: memhub.MemBuddy | t.CPtr = symtab.Pool + scope: GenTypes.Scope | t.CPtr = self._create_scope(pool, symtab.Current, kind) + if scope is None: + return None + symtab.Current = scope + return scope + + # ============================================================ + # exit_scope — 退出当前作用域 + # ============================================================ + def exit_scope(self, symtab: GenTypes.SymbolTable | t.CPtr): + """退出当前作用域,恢复到父作用域""" + if symtab is not None and symtab.Current is not None: + symtab.Current = symtab.Current.Parent + + # ============================================================ + # define_var — 在当前作用域定义变量 + # ============================================================ + def define_var(self, symtab: GenTypes.SymbolTable | t.CPtr, + name: str, + alloca: llvmlite.Value | t.CPtr) -> int: + """在当前作用域定义变量,返回 0 成功""" + if symtab is None or name is None or alloca is None: + return 1 + scope: GenTypes.Scope | t.CPtr = symtab.Current + if scope is None: + return 1 + ret: int = self.add_var(scope.Vars, scope.VarCount, name, alloca) + if ret == 0: + scope.VarCount = scope.VarCount + 1 + return ret + + # ============================================================ + # define_module_var — 在模块作用域定义变量 + # ============================================================ + def define_module_var(self, symtab: GenTypes.SymbolTable | t.CPtr, + name: str, + alloca: llvmlite.Value | t.CPtr) -> int: + """在模块作用域定义变量,返回 0 成功""" + if symtab is None or name is None or alloca is None: + return 1 + scope: GenTypes.Scope | t.CPtr = symtab.Root + if scope is None: + return 1 + ret: int = self.add_var(scope.Vars, scope.VarCount, name, alloca) + if ret == 0: + scope.VarCount = scope.VarCount + 1 + return ret + + # ============================================================ + # lookup_var — 从当前作用域逐级向上查找变量 + # ============================================================ + def lookup_var(self, symtab: GenTypes.SymbolTable | t.CPtr, + name: str) -> llvmlite.Value | t.CPtr: + """从当前作用域逐级向上查找变量,返回 alloca 或 None""" + if symtab is None or name is None: + return None + scope: GenTypes.Scope | t.CPtr = symtab.Current + while scope is not None: + result: llvmlite.Value | t.CPtr = self.find_var( + scope.Vars, scope.VarCount, name) + if result is not None: + return result + scope = scope.Parent + return None + + # ============================================================ + # lookup_current — 仅在当前作用域查找变量 + # ============================================================ + def lookup_current(self, symtab: GenTypes.SymbolTable | t.CPtr, + name: str) -> llvmlite.Value | t.CPtr: + """仅在当前作用域查找变量""" + if symtab is None or name is None: + return None + scope: GenTypes.Scope | t.CPtr = symtab.Current + if scope is None: + return None + return self.find_var(scope.Vars, scope.VarCount, name) + + # ============================================================ + # lookup_module_var — 在模块作用域查找变量 + # ============================================================ + def lookup_module_var(self, symtab: GenTypes.SymbolTable | t.CPtr, + name: str) -> llvmlite.Value | t.CPtr: + """在模块作用域查找变量""" + if symtab is None or name is None: + return None + scope: GenTypes.Scope | t.CPtr = symtab.Root + if scope is None: + return None + return self.find_var(scope.Vars, scope.VarCount, name) + + # ============================================================ + # is_module_scope - 判断当前是否在模块级作用域 + # + # 用于区分模块级代码和函数内代码: + # - 模块级代码:AnnAssign 应修改模块级变量(Python 语义) + # - 函数内代码:无 global 声明时 AnnAssign 应创建局部变量(Python 语义) + # ============================================================ + def is_module_scope(self, symtab: GenTypes.SymbolTable | t.CPtr) -> int: + """判断当前作用域是否为模块级作用域(Current == Root) + + Returns: 1=模块级作用域, 0=函数内作用域 + """ + if symtab is None: + return 0 + if symtab.Root is None or symtab.Current is None: + return 0 + # 比较指针:Current 与 Root 相同则为模块级 + if t.CUInt64T(symtab.Current) == t.CUInt64T(symtab.Root): + return 1 + return 0 + + # ============================================================ + # get_or_create_sym — 查找或创建变量(在当前作用域) + # ============================================================ + def get_or_create_sym(self, symtab: GenTypes.SymbolTable | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + name: str, + ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: + """查找或创建变量 alloca(在当前作用域)""" + existing: llvmlite.Value | t.CPtr = self.lookup_current(symtab, name) + if existing is not None: + return existing + alloca: llvmlite.Value | t.CPtr = self._alloca_at_entry(builder, ty) + if alloca is None: + return None + if self.define_var(symtab, name, alloca) != 0: + # fail-fast: 变量注册失败(如超过 MAX_VARS)必须立即终止。 + # 此前静默忽略返回值:alloca 已创建但未入符号表,后续读取该变量 + # 报"未定义名称"(NewAstTest main() 289 个局部变量 > MAX_VARS=256 + # 的 NameError 根因),误导排查。变量表超限暴露上游规模问题。 + self.Gen.TypeGenErr.fatal_error( + None, + f"变量 '{name}' 注册失败(作用域变量数超过上限 MAX_VARS)", + "InternalCompilerError") + return alloca diff --git a/App/lib/core/Handles/ExprCallBase.vp b/App/lib/core/Handles/ExprCallBase.vp deleted file mode 100644 index 168f4af..0000000 --- a/App/lib/core/Handles/ExprCallBase.vp +++ /dev/null @@ -1,246 +0,0 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import sys -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.StubMerger as StubMerger - - -import lib.core.Handles.ExprCallDeref as ExprCallDeref -import lib.core.Handles.ExprCallCtor as ExprCallCtor -import lib.core.Handles.ExprCallCall as ExprCallCall -import lib.core.Handles.ExprCallTable as ExprCallTable -import lib.core.Handles.ExprCallHandle as ExprCallHandle -import lib.core.Handles.HandlesExprCall as HandlesExprCall - -# ============================================================ -# ExprCallBase - HandlesExprCall 拆分(阶段 E):ExprCallBase -# -# 直接移动模式:委托函数迁至此模块,原 HandlesExprCall.vp 仅 -# 保留 _g_gen/常量/类;调用方经本模块前缀访问。 -# ============================================================ - -# ============================================================ -# _lookup_module_sha1 — 按模块名查找 SHA1(委托到 gen._lookup_module_sha1) -# ============================================================ - - -# ============================================================ -# 模块 SHA1 查询(委托给 StubMerger 全局存储器) -# -# 翻译时用于跨模块函数调用名混淆: -# string.strchr(...) → call @{sha1_of_string}.strchr(...) -# -# 数据来源是 StubMerger.PopulateSha1MapStore/AppendToSha1MapStore -# 填充的全局存储器,不再维护独立的 SHA1 映射表副本。 -# ============================================================ - -def _lookup_module_sha1(mod_name: str) -> str: - """查找模块名对应的 SHA1,找不到返回 None(委托到 gen._lookup_module_sha1)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._lookup_module_sha1(mod_name) - return None -def _lookup_module_sha1_suffix(mod_suffix: str) -> str: - """后缀匹配查找模块 SHA1(委托到 gen._lookup_module_sha1_suffix)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._lookup_module_sha1_suffix(mod_suffix) - return None - -# ============================================================ -# 全局 CExport 函数表(module_sha1 + func_name) -# -# t.CExport 函数定义时不加 SHA1 前缀(如 @strlen), -# 跨模块调用时需要查表确认目标函数是否是 CExport 函数。 -# 若是,使用裸名调用(@strlen);否则使用 @{sha1}.func。 -# 必须包含模块 SHA1 记录,避免同名跨模块函数冲突 -# (一个模块有 CExport 的 strlen→@strlen,另一个没有→@{sha1}.strlen)。 -# -# 注:表数据已迁入 gen 字段(CallGenMixin.CexportSha1Arr/CexportFuncArr/ -# CexportCount),本模块不再持有(P4 簇 1+2)。 -# ============================================================ -_CEXPORT_MAX: t.CDefine = 256 -def register_cexport_func(sha1: str, func_name: str) -> int: - """注册 CExport 函数到全局表(委托到 gen.register_cexport_func)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.register_cexport_func(sha1, func_name) - return 0 -def is_cexport_func(sha1: str, func_name: str) -> int: - """检查(sha1, func_name) 是否是 CExport 函数(委托到 gen.is_cexport_func)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.is_cexport_func(sha1, func_name) - return 0 -# ============================================================ -# _lookup_mod_sha1 - 从 from_imports 查找类所属模块的 SHA1 -# -# lookup_from_import 返回指向 from_imports 内部的指针,不是 null 终止 -# (如 "namespace_defs Gadget:namespace_defs ...")。此函数手动截断 -# 模块名,复制到新缓冲区,再查找 SHA1(精确+后缀匹配)。 -# ============================================================ -def _lookup_mod_sha1(pool: memhub.MemBuddy | t.CPtr, - from_imports: str, class_name: str, - allow_star_fallback: int = 1) -> str: - """从 from_imports 查找类所属模块的 SHA1(委托到 gen._lookup_mod_sha1)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._lookup_mod_sha1(pool, from_imports, class_name, allow_star_fallback) - return None -# ============================================================ -# _lookup_sha1_from_modname_raw - 原始模块名 → SHA1 -# -# 截断模块名(lookup_from_import 返回内部指针,空格/冒号/null 分隔), -# 去掉相对导入前导点,再精确+后缀查找 SHA1。 -# 供 _lookup_mod_sha1 与 HandlesExpr._lookup_cross_module_cdefine 复用。 -# ============================================================ -def _lookup_sha1_from_modname_raw(pool: memhub.MemBuddy | t.CPtr, - mod_name_raw: str) -> str: - """从原始模块名查找 SHA1(委托到 gen._lookup_sha1_from_modname_raw)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._lookup_sha1_from_modname_raw(pool, mod_name_raw) - return None -# ============================================================ -# HandlesExprCall - 函数调用表达式处理(Mixin 继承模式) -# -# 工具函数和 HandlesExprCall.FuncEntry 保留为模块级,HandlesExprCall.ExprCallHandle 提供 trans 接口 -# ============================================================ - -# ============================================================ -# 在模块函数链表中按名称查找函数 -# ============================================================ -def find_func_in_module(mod: llvmlite.LLVMModule | t.CPtr, - name: str) -> llvmlite.Function | t.CPtr: - """在模块的函数链表中按名称查找函数(委托到 gen.find_func_in_module)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.find_func_in_module(mod, name) - return None -# ============================================================ -# _ensure_c_lib_declare - 为已知的 C 库函数创建 declare 声明 -# -# 对应 TPC 的 _C_LIB_FUNCS 机制。当裸名调用 memset/memmove/memcmp/ -# strcmp/strlen 等已知 C 库函数时,自动在当前模块创建 declare, -# 避免报 "裸名调用未定义且未导入" 错误。 -# memcpy 不在此处理(已有 _emit_llvm_memcpy_intrinsic 映射到 @llvm.memcpy)。 -# -# Args: -# pool: 内存池 -# mod: LLVM 模块 -# name: 函数名 -# -# Returns: -# Function 指针(已创建 declare),或 None 如果不是已知 C 库函数 -# ============================================================ -def _ensure_c_lib_declare(pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - name: str) -> llvmlite.Function | t.CPtr: - """为已知的 C 库函数创建 declare 声明(委托到 gen._ensure_c_lib_declare)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._ensure_c_lib_declare(pool, mod, name) - return None -# ============================================================ -# _infer_external_func_ret_ty - 根据函数名推断外部函数返回类型 -# -# stubs 在翻译后才注入 IR,翻译时模块中无 stub 函数声明, -# 因此对 includes 库函数(如 string.strchr 返回 i8*)需根据 -# 函数名推断返回类型,避免指针被截断为 i32。 -# -# 覆盖 includes/string.py 所有导出函数: -# i8*: strcpy, strncpy, strchr, strrchr, strstr, memset, memset32, memcpy, memmove -# i64: strlen, atoll -# double: atof -# i8: samestr -# i32(默认): strcmp, strncmp, memcmp, strspn, atoi, split -# ============================================================ -def _infer_external_func_ret_ty(pool: memhub.MemBuddy | t.CPtr, - func_name: str) -> llvmlite.LLVMType | t.CPtr: - """根据函数名推断外部 includes 函数的返回类型(委托到 gen._infer_external_func_ret_ty)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._infer_external_func_ret_ty(pool, func_name) - return None -# ============================================================ -# _get_external_func_param_ty - 获取外部函数第 idx 个参数的期望类型 -# -# stubs 翻译时未注入,需推断参数类型以提升字面量(如 i32→i64), -# 避免 declare(i64) 与 call(i32) 类型不匹配。 -# -# 注意:stubs 翻译时 ULONG(t.CUnsignedLong) 在 LLVM IR 中被翻译为 i64 -# (因为 LLVM 中 long 是 64 位),因此 Win32 API 中所有 ULONG/DWORD/SIZE_T -# 参数在 declare 中都是 i64。call 时必须匹配,否则类型不匹配。 -# -# 策略:对 Win32 API 函数的所有非指针参数(字面量)都提升为 i64, -# 以匹配 declare 中 ULONG 被翻译为 i64 的情况。 -# -# 指针参数(VOIDPTR/HANDLE)不在此处理,由调用点的 inttoptr 处理。 -# ============================================================ -def _get_external_func_param_ty(pool: memhub.MemBuddy | t.CPtr, - func_name: str, - param_idx: int) -> llvmlite.LLVMType | t.CPtr: - """获取外部函数第 param_idx 个参数的期望类型(委托到 gen._get_external_func_param_ty)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._get_external_func_param_ty(pool, func_name, param_idx) - return None -# ============================================================ -# _emit_llvm_memcpy_intrinsic — 将 memcpy 调用映射到 @llvm.memcpy 内联函数 -# -# 背景: string.memcpy 是 t.CExport 函数,跨模块调用生成 @memcpy 裸名调用。 -# 但在 monomorphization 场景下,目标模块的 deps.txt 可能不含 string, -# 导致 @memcpy 声明缺失,链接器报 undefined value。 -# -# 解决: 将 memcpy 调用映射到 LLVM 内联函数 @llvm.memcpy, -# 该内联函数在当前模块内声明,无需跨模块依赖。 -# -# @llvm.memcpy 签名: void(i8* dst, i8* src, i64 len, i1 isvolatile) -# C memcpy 签名: i8* (i8* dst, i8* src, i64 len) — 返回 dst -# -# Args: -# args_head: 参数链表头(dst, src, num),通过 Value.Next 链接 -# arg_count: 参数数量(应为 3) -# -# Returns: -# dst 值(匹配 C memcpy 语义: 返回 dest 指针) -# ============================================================ -def _emit_llvm_memcpy_intrinsic(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - dst_val: llvmlite.Value | t.CPtr, - src_val: llvmlite.Value | t.CPtr, - num_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: - """将 memcpy 调用映射到 @llvm.memcpy 内联函数(委托到 gen._emit_llvm_memcpy_intrinsic)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._emit_llvm_memcpy_intrinsic(pool, builder, mod, dst_val, src_val, num_val) - return None diff --git a/App/lib/core/Handles/ExprCallCall.vp b/App/lib/core/Handles/ExprCallCall.vp deleted file mode 100644 index a405511..0000000 --- a/App/lib/core/Handles/ExprCallCall.vp +++ /dev/null @@ -1,338 +0,0 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import sys -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.StubMerger as StubMerger - - -import lib.core.Handles.ExprCallBase as ExprCallBase -import lib.core.Handles.ExprCallDeref as ExprCallDeref -import lib.core.Handles.ExprCallCtor as ExprCallCtor -import lib.core.Handles.ExprCallTable as ExprCallTable -import lib.core.Handles.ExprCallHandle as ExprCallHandle -import lib.core.Handles.HandlesExprCall as HandlesExprCall - -# ============================================================ -# ExprCallCall - HandlesExprCall 拆分(阶段 E):ExprCallCall -# -# 直接移动模式:委托函数迁至此模块,原 HandlesExprCall.vp 仅 -# 保留 _g_gen/常量/类;调用方经本模块前缀访问。 -# ============================================================ - -# ============================================================ -# 翻译函数调用 Call(func, args) — 模块级版本 -# ============================================================ -def translate_call(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译函数调用,返回 call 结果 Value(委托到 gen.translate_call)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.translate_call(pool, builder, mod, node, funcs_ptr, func_count, trans) - return None -# ============================================================ -# 翻译闭包调用 — 通过闭包指针间接调用 -# -# 闭包结构: {i8* fn_ptr, i8* env_ptr} (16 字节) -# 调用过程: -# 1. load closure_ptr 从变量 alloca -# 2. load fn_ptr 从 offset 0 -# 3. load env_ptr 从 offset 8 -# 4. bitcast fn_ptr to i32(i8*)* -# 5. call i32 %fn_typed(i8* %env_ptr) -# ============================================================ -def translate_closure_call(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - closure_alloca: llvmlite.Value | t.CPtr, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """通过闭包指针间接调用(委托到 gen.translate_closure_call)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.translate_closure_call(pool, builder, mod, closure_alloca, cargs, can, trans) - return None -# ============================================================ -# _is_func_ptr_alloca - 判断变量 alloca 是否为函数指针变量 -# -# 函数指针变量(t.Callable 注解 → i8*)的 alloca 类型是 Ptr(Ptr(i8)) = i8**; -# 闭包变量 alloca 是 i8*(Ptr(i8))。通过类型层级区分。 -# ============================================================ -def _is_func_ptr_alloca(alloca: llvmlite.Value | t.CPtr) -> int: - """判断 alloca 是否为函数指针变量(类型 Ptr(Ptr(i8))),1=是 / 0=否(委托到 gen._is_func_ptr_alloca)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._is_func_ptr_alloca(alloca) - return 0 - - -# ============================================================ -# 闭包变量名集合(stdlib 分配,懒初始化) -# -# 背景: 嵌套函数提升后闭包变量 alloca 类型是 i8**(alloca i8*), -# 与函数指针变量(t.Callable → i8** alloca)类型完全相同,_is_func_ptr_alloca -# 无法区分,导致 inner() 被误判为函数指针调用(直接 bitcast 闭包对象到函数指针、 -# 无 env 参数调用 → 运行时崩溃)。translate_nested_function_def 创建闭包时 -# 注册嵌套函数名,调用时优先按闭包调用处理。 -# ============================================================ -MAX_CLOSURE_NAMES: t.CDefine = 128 -def _ensure_closure_names() -> int: - """确保闭包名表已分配,0 失败(委托到 gen._ensure_closure_names)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._ensure_closure_names() - return 0 -def register_closure_name(name: str) -> int: - """注册嵌套函数(闭包变量)名,0 成功(委托到 gen.register_closure_name)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.register_closure_name(name) - return 0 -def is_closure_name(name: str) -> int: - """检查 name 是否已注册为闭包变量名,1=是 / 0=否(委托到 gen.is_closure_name)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.is_closure_name(name) - return 0 - -# ============================================================ -# 函数指针变量签名表(变量名 → 返回类型) -# -# AnnAssign 处理 t.Callable 注解时注册,函数指针间接调用时 -# 按注册的返回类型构造签名(而非默认 i32)。 -# ============================================================ -MAX_FUNC_PTR_SIGS: t.CDefine = 64 -def _ensure_funcptr_sigs() -> int: - """确保函数指针签名表已分配(stdlib.malloc,懒初始化)(委托到 gen._ensure_funcptr_sigs)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._ensure_funcptr_sigs() - return 0 -def register_func_ptr_sig(name: str, - ret_ty: llvmlite.LLVMType | t.CPtr) -> int: - """注册函数指针变量的返回类型签名,0 成功(委托到 gen.register_func_ptr_sig)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.register_func_ptr_sig(name, ret_ty) - return 0 -def lookup_func_ptr_ret(name: str) -> llvmlite.LLVMType | t.CPtr: - """查函数指针变量的返回类型,None=未注册(调用时默认 i32)(委托到 gen.lookup_func_ptr_ret)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.lookup_func_ptr_ret(name) - return None -# ============================================================ -# _translate_func_ptr_call - 函数指针变量间接调用 -# -# func_p: t.Callable[[A, B], Ret] 后调用 func_p(a, b): -# 1. load 函数地址(i8*) -# 2. 翻译实参并链接为 Value 链表 -# 3. 按实参类型 + 注册的返回类型构造签名(未注册时默认 i32) -# 4. bitcast i8* → 函数指针类型,间接调用 -# ============================================================ -def _translate_func_ptr_call(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - fp_alloca: llvmlite.Value | t.CPtr, - func_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """函数指针变量间接调用,返回结果 Value(委托到 gen._translate_func_ptr_call)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._translate_func_ptr_call(pool, builder, mod, fp_alloca, func_name, cargs, can, trans) - return None -# ============================================================ -# 翻译 printf 调用 — 模块级版本 -# ============================================================ -def translate_printf_call(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None): - """翻译 printf 调用(特殊处理格式字符串)(委托到 gen.translate_printf_call)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - g.translate_printf_call(pool, builder, mod, cl, trans) -# ============================================================ -# 翻译 print 调用 — 类型感知格式化 + 默认换行 -# -# 与 printf 不同,print 不需要用户提供格式串:每个参数按 LLVM -# 类型自动选择格式(%s/%d/%f/0x%llx),结尾追加 "\n"(对齐 Python -# print 默认 end="\n",以及 TPC HandlesExprBuiltin._HandlePrintLlvm)。 -# -# 类型分派规则: -# i8*(str/bytes) → %s -# 其他指针(struct*/int*) → 0x%llx(ptrtoint 到 i64) -# i1(bool) → %d(zext 到 i32) -# i8/i16/i32 → %d(sext 到 i32,C ABI 整数提升) -# i64 → %lld -# float/double → %f(float fpext 到 double,C ABI 提升) -# 无法识别的类型 → "(unknown)"(不传参) -# ============================================================ -def translate_print_call(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None): - """翻译 print 调用(类型感知格式化 + 默认换行)(委托到 gen.translate_print_call)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - g.translate_print_call(pool, builder, mod, cl, trans) -# ============================================================ -# stdarg 糖函数实现: va_arg / arg / va_start / va_end -# -# 这些函数对应 stdarg.vp 中的 pass 体声明,由编译器在翻译期 -# 转换为 LLVM 指令或 intrinsic 调用,不生成函数 call。 -# -# va_list 在 TPV 中表示为 i8*(与 stdarg.vp 中 va_list = t.CUnsignedChar | t.CPtr 一致)。 -# va_list 对象存储在 alloca 中(i8**),va_arg/va_start/va_end 需要传入 alloca 指针。 -# ============================================================ - -def _va_arg_get_alloca_ptr(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - arg_node: ast.AST | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """获取 va_list 变量的 alloca 指针(不 load)(委托到 gen._va_arg_get_alloca_ptr)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._va_arg_get_alloca_ptr(pool, builder, mod, arg_node, funcs_ptr, func_count, trans) - return None -def _resolve_va_arg_type(pool: memhub.MemBuddy | t.CPtr, - type_node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.LLVMType | t.CPtr: - """解析 va_arg/arg 的类型参数为 LLVMType(委托到 gen._resolve_va_arg_type)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._resolve_va_arg_type(pool, type_node, trans) - return None -def _translate_va_arg_sugar(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """va_arg(ap, type) / va_arg(ap) → %N = va_arg , (委托到 gen._translate_va_arg_sugar)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._translate_va_arg_sugar(pool, builder, mod, cl, cargs, can, funcs_ptr, func_count, trans) - return None -def _translate_arg_sugar(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """arg(type) → %N = va_arg , (委托到 gen._translate_arg_sugar)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._translate_arg_sugar(pool, builder, mod, cl, cargs, can, funcs_ptr, func_count, trans) - return None -def _translate_va_start_sugar(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """va_start(ap, last_arg) → call void @llvm.va_start(i8* %ap)(委托到 gen._translate_va_start_sugar)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._translate_va_start_sugar(pool, builder, mod, cargs, can, funcs_ptr, func_count, trans) - return None -def _translate_va_end_sugar(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """va_end(ap) → call void @llvm.va_end(i8* %ap)(委托到 gen._translate_va_end_sugar)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._translate_va_end_sugar(pool, builder, mod, cargs, can, funcs_ptr, func_count, trans) - return None -# ============================================================ -# 变长函数调用支持: 检查 IsVarArg + C ABI 参数提升 -# -# C ABI 要求变长参数(...部分)进行默认提升: -# 整数提升: i8/i16 → i32(sext/zext) -# 浮点提升: float → double(fpext) -# 固定参数不需要提升(有明确类型签名)。 -# ============================================================ - -def _get_func_fixed_param_count(func: llvmlite.Function | t.CPtr) -> int: - """获取函数的固定参数数量(遍历 Params 链表)(委托到 gen._get_func_fixed_param_count)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._get_func_fixed_param_count(func) - return 0 -def _check_and_promote_variadic_call(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - call_name: str, - head: llvmlite.Value | t.CPtr, - can: t.CSizeT, - arg_nodes: list[ast.AST | t.CPtr] | t.CPtr = None, - self_offset: int = 0, - trans: HT.Translator | t.CPtr = None) -> int: - """检查被调用函数是否为变长函数,若是则对变长参数进行 C ABI 提升(委托到 gen._check_and_promote_variadic_call)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._check_and_promote_variadic_call(pool, builder, mod, call_name, head, can, - arg_nodes, self_offset, trans) - return 0 diff --git a/App/lib/core/Handles/ExprCallCtor.vp b/App/lib/core/Handles/ExprCallCtor.vp deleted file mode 100644 index f5e9466..0000000 --- a/App/lib/core/Handles/ExprCallCtor.vp +++ /dev/null @@ -1,622 +0,0 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import sys -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.StubMerger as StubMerger - - -import lib.core.Handles.ExprCallBase as ExprCallBase -import lib.core.Handles.ExprCallDeref as ExprCallDeref -import lib.core.Handles.ExprCallCall as ExprCallCall -import lib.core.Handles.ExprCallTable as ExprCallTable -import lib.core.Handles.ExprCallHandle as ExprCallHandle -import lib.core.Handles.HandlesExprCall as HandlesExprCall - -# ============================================================ -# ExprCallCtor - HandlesExprCall 拆分(阶段 E):ExprCallCtor -# -# 直接移动模式:委托函数迁至此模块,原 HandlesExprCall.vp 仅 -# 保留 _g_gen/常量/类;调用方经本模块前缀访问。 -# ============================================================ - -# ============================================================ -# _apply_struct_defaults — 应用结构体字段的默认值 -# -# 在 zeroinitializer 之后、显式参数之前调用 -# 遍历所有字段,对有默认值的字段翻译并 store -# 显式参数(位置/关键字)后续会覆盖默认值 -# ============================================================ -def _apply_struct_defaults(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - struct_ty: llvmlite.LLVMType | t.CPtr, - class_name: str, - tmp: llvmlite.Value | t.CPtr, - trans: HT.Translator | t.CPtr): - """应用结构体字段的默认值(委托到 gen._apply_struct_defaults)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - g._apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans) -# ============================================================ -# _translate_struct_ctor — 结构体构造函数 Point(10, 20) -# -# 生成: -# %tmp = alloca {i32, i32} -# store {i32, i32} zeroinitializer, {i32, i32}* %tmp -# %f0 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 0 -# store i32 10, i32* %f0 -# %f1 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 1 -# store i32 20, i32* %f1 -# %result = load {i32, i32}, {i32, i32}* %tmp -# ============================================================ -def _translate_struct_ctor(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - struct_ty: llvmlite.LLVMType | t.CPtr, - class_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """结构体构造函数:按字段顺序 store 参数值,返回结构体值(委托到 gen._translate_struct_ctor)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._translate_struct_ctor(pool, builder, mod, struct_ty, class_name, cargs, can, trans) - return None -# ============================================================ -# _translate_renum_construct — REnum 变体构造函数 -# -# 语法: ClassName.VariantName(args...) -# 如 LLVMType.Int(1) → 构造 LLVMType 的 Int 变体,__tag=0,_p1=1 -# -# 生成 IR: -# %tmp = alloca {i32, i32, ...} ; REnum 类型 -# store zeroinitializer, %tmp ; 清零 -# %tag_ptr = gep %tmp, 0, 0 ; __tag 字段 -# store i32 , %tag_ptr ; 写入 tag -# %p1_ptr = gep %tmp, 0, 1 ; _p1 字段 -# store , %p1_ptr ; 写入 payload[0] -# ... (更多 payload 字段) -# return %tmp ; 返回指针 -# -# 对应 TPC 的 _HandleREnumConstructLlvm -# ============================================================ -def _translate_renum_construct(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, - variant_name: str, - tag_value: int, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """构造 REnum 变体实例,返回指向 alloca 的指针(委托到 gen._translate_renum_construct)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._translate_renum_construct(pool, builder, mod, class_name, variant_name, - tag_value, cargs, can, trans) - return None -# ============================================================ -# _do_virtual_call — 通过虚表间接调用虚方法 -# -# IR 模式: -# %1 = getelementptr StructTy, StructTy* %self, i32 0, i32 0 ; i8** -# %2 = load i8*, i8** %1 ; i8* (vtable ptr) -# %3 = bitcast i8* %2 to {i8*, ...}* ; vtable typed ptr -# %4 = getelementptr {i8*, ...}, {i8*, ...}* %3, i32 0, i32 N ; i8** -# %5 = load i8*, i8** %4 ; i8* (func ptr) -# %6 = bitcast i8* %5 to RetTy(Params)* ; func typed ptr -# call RetTy %6(Params %self, ...) -# -# 参数: -# args_head — 已构建好的参数链表头(self_ptr 为首节点) -# args_count — 参数总数(含 self) -# found_func — 方法对应的 Function 对象(用于推断函数签名) -# ret_ty — 返回类型 -# ============================================================ -def _do_virtual_call(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, - method_name: str, - self_ptr: llvmlite.Value | t.CPtr, - args_head: llvmlite.Value | t.CPtr, - args_count: int, - found_func: llvmlite.Function | t.CPtr, - ret_ty: llvmlite.LLVMType | t.CPtr, - vtable_base: llvmlite.Value | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """通过虚表间接调用虚方法,返回 call 结果(void 方法返回 None)(委托到 gen._do_virtual_call)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._do_virtual_call(pool, builder, mod, class_name, method_name, - self_ptr, args_head, args_count, found_func, ret_ty, vtable_base) - return None -# ============================================================ -# _call_method_on_ptr — 在结构体指针上调用方法 -# -# 辅助函数:构造 ClassName.method_name 调用,self 指针为首个参数 -# 如果该方法在虚表中,则走虚方法分发路径(间接调用) -# ============================================================ -def _call_method_on_ptr(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, - method_name: str, - self_ptr: llvmlite.Value | t.CPtr, - extra_args: t.CSizeT | t.CPtr, - extra_count: int, - trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """在结构体指针上调用方法,返回 call 结果(void 方法返回 None)(委托到 gen._call_method_on_ptr)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._call_method_on_ptr(pool, builder, mod, class_name, method_name, - self_ptr, extra_args, extra_count, trans, node) - return None -# ============================================================ -# _ensure_method_declare - 为跨模块方法调用创建 declare 声明 -# -# 当 found_func 为 None(stub 未注入或跨模块调用)时, -# 在当前模块中创建函数声明,避免 llc 报 undefined value。 -# ============================================================ -def _ensure_method_declare(pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - call_name: str, - ret_ty: llvmlite.LLVMType | t.CPtr, - param_head: llvmlite.ParamNode | t.CPtr, - param_count: int): - """为跨模块方法调用创建 declare 声明(委托到 gen._ensure_method_declare)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - g._ensure_method_declare(pool, mod, call_name, ret_ty, param_head, param_count) -# ============================================================ -# _lookup_method_ret_ty_via_vpi - 从 vpi stub 返回注解缓存精确获取方法返回类型 -# -# 方法定义处(.vpi stub)的返回注解(如 json.JsonValue._pool_alloc → -# "str")在 stub 注入时由 VpiReader 缓存(_cache_vpi_return_annots_text)。 -# 此函数按 模块SHA1 + 类名 + 方法名 查缓存并纯字符串解析为 LLVMType。 -# 无需硬编码白名单——返回类型始终来自方法定义处。 -# ============================================================ -def _lookup_method_ret_ty_via_vpi(pool: memhub.MemBuddy | t.CPtr, - cls_sha1: str, - cls_name: str, - method_name: str) -> llvmlite.LLVMType | t.CPtr: - """从 vpi stub 返回注解缓存获取方法返回类型,未命中返回 None(委托到 gen._lookup_method_ret_ty_via_vpi)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._lookup_method_ret_ty_via_vpi(pool, cls_sha1, cls_name, method_name) - return None -# ============================================================ -# _special_method_ret_ty - 编译器内置特殊方法的固定返回类型 -# -# __before_init__ / __init__:编译器生成/约定返回 void -# __new__:返回 Ptr(StructTy)(存储空间指针) -# -# 这些方法不存在于源码(vpi stub 无条目),跨模块调用时 -# found_func/text.ll/vpi 缓存必然未命中,但返回类型是编译器 -# 确定性语义(与 HandlesClassDef._translate_method 3543-3548 一致), -# 在此直接固定,不触发 fail-fast 误报。非特殊方法返回 None。 -# ============================================================ -def _special_method_ret_ty(pool: memhub.MemBuddy | t.CPtr, - class_name: str, - method_name: str) -> llvmlite.LLVMType | t.CPtr: - """编译器内置特殊方法的固定返回类型;非特殊返回 None(委托到 gen._special_method_ret_ty)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._special_method_ret_ty(pool, class_name, method_name) - return None -# ============================================================ -# _fail_method_ret_ty - 方法返回类型无法精确获取时 fail-fast -# -# 返回类型来源(按序):当前模块函数 → text.ll define → vpi stub 返回注解缓存。 -# 全部未命中时立即 ERROR + 错误堆栈终止,绝不按名推断白名单/静默默认 i32。 -# -# node: 调用点 AST 节点(可选,用于 ERROR 堆栈定位) -# ============================================================ -def _fail_method_ret_ty(method_name: str, - node: ast.AST | t.CPtr = None) -> llvmlite.LLVMType | t.CPtr: - """方法返回类型无法精确获取时 fail-fast(ERROR + 错误堆栈)(委托到 gen._fail_method_ret_ty)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._fail_method_ret_ty(method_name, node) - return None -# ============================================================ -# 跨模块方法返回类型查找(从 text.ll) -# -# Phase A 翻译每个源文件后生成 text.ll,其中 define 行包含 -# 方法的实际返回类型。当 Phase A 翻译后续文件调用跨模块方法时, -# 方法调用默认返回 i32,导致指针返回值被截断。 -# _LookupMethodRetTyFromTextLL 读取依赖模块的 text.ll,从 define -# 行提取实际返回类型,避免指针截断(未命中时回退 vpi stub 缓存)。 -# ============================================================ - -# ============================================================ -# SetTempDir - 设置 temp 目录路径 -# -# 在 Phase2.py 的 Phase A 翻译前调用,使 CallGenMixin -# 能够读取依赖模块的 text.ll 文件。 -# ============================================================ -def SetTempDir(temp_dir: str): - """设置 temp 目录路径(供跨模块方法返回类型查找使用)(委托到 gen.SetTempDir)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - g.SetTempDir(temp_dir) -# ============================================================ -# _ParseLLVMRetTyStr - 将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType -# -# 从 define 行中提取的返回类型字符串(define 与 @ 之间的内容), -# 转换为 llvmlite.LLVMType 对象。 -# -# 支持的类型: -# void → Void -# i8/i16/i32/i64 → Int8/Int16/Int32/Int64 -# double → Double, float → Float -# 任何含 * 的类型 → Ptr(Int8)(通用指针,保留 64 位地址) -# -# Args: -# pool: 内存池 -# buf: 包含类型字符串的缓冲区 -# start: 类型字符串起始位置 -# end: 类型字符串结束位置(不含) -# -# Returns: -# LLVM 类型对象,或 None(无法解析) -# ============================================================ -def _ParseLLVMRetTyStr(pool: memhub.MemBuddy | t.CPtr, - buf: bytes, - start: t.CSizeT, - end: t.CSizeT) -> llvmlite.LLVMType | t.CPtr: - """将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType(委托到 gen._ParseLLVMRetTyStr)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._ParseLLVMRetTyStr(pool, buf, start, end) - return None -# ============================================================ -# _LookupMethodRetTyFromTextLL - 从依赖模块的 text.ll 查找方法返回类型 -# -# 读取 {temp_dir}/{sha1[0:2]}/{sha1}.text.ll(level=1),搜索 -# define 行中包含 "{sha1}.{class_name}.{method_name}" 的函数, -# 提取返回类型并转换为 llvmlite.LLVMType。 -# -# 解决问题: 旧实现 _infer_method_ret_ty(已移除)默认返回 i32,导致指针返回值 -# 被 inttoptr 截断为 32 位(coerce_to_type line 238-239)。 -# 本函数从 text.ll 获取实际返回类型,避免截断。 -# -# Args: -# pool: 内存池 -# class_sha1: 类所属模块的 SHA1 -# class_name: 类名 -# method_name: 方法名 -# -# Returns: -# LLVM 类型对象,或 None(未找到/text.ll 不存在) -# ============================================================ -def _LookupMethodRetTyFromTextLL(pool: memhub.MemBuddy | t.CPtr, - class_sha1: str, - class_name: str, - method_name: str, - use_bare: int = 0) -> llvmlite.LLVMType | t.CPtr: - """从依赖模块的 text.ll 中查找方法返回类型(委托到 gen._LookupMethodRetTyFromTextLL)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._LookupMethodRetTyFromTextLL(pool, class_sha1, class_name, method_name, use_bare) - return None -# ============================================================ -# 属性方法(@property/@x.setter/@x.deleter)与静态/类方法调用辅助 -# -# 元数据表由 HandlesClassDef 在类翻译/预注册阶段填充, -# 这里负责把 obj.prop / obj.prop=v / del obj.prop / Class.method() -# 翻译为对应的 {sha1}.ClassName.prop 系列函数调用。 -# ============================================================ - -# ============================================================ -# _translate_property_call — 翻译属性方法调用 -# -# 与 _translate_method_call 的调用名/返回类型解析逻辑一致: -# 1. 优先用模块中已有的函数(精确/后缀匹配,来自 stub 注入) -# 2. 否则用类所属模块的 SHA1 构造 "{sha1}.ClassName.method" 调用名 -# 3. 返回类型:函数实类型 → text.ll 查找 → 按方法名推断(默认 i32) -# -# call_head/call_count: 已构建好的参数链表(如 getter 只有 obj 一个参数) -# ============================================================ -def _translate_property_call(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, - method_name: str, - call_head: llvmlite.Value | t.CPtr, - call_count: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """翻译属性/静态方法调用,返回 call 结果 Value(委托到 gen._translate_property_call)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._translate_property_call(pool, builder, mod, class_name, method_name, - call_head, call_count, trans) - return None -# ============================================================ -# _resolve_obj_class_name — 解析对象表达式的类名(短名) -# -# 优先从变量注解(AnnotClassName)解析(如 "memhub.MemBuddy" → "MemBuddy"), -# 失败时从 LLVM 类型解析(Ptr(Struct) → 类名)。 -# 供属性访问/赋值/删除识别 property 时使用。 -# ============================================================ -def _resolve_obj_class_name(pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - obj_node: ast.AST | t.CPtr) -> str: - """解析对象表达式的类名(短名),失败返回 None(委托到 gen._resolve_obj_class_name)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._resolve_obj_class_name(pool, trans, obj_node) - return None -# ============================================================ -# _try_property_getter_attr — 尝试将 obj.attr 翻译为 property getter 调用 -# -# 检查 obj 的类是否有 @property/@x.getter 的 attr 方法; -# 若有则生成 call Class.attr(obj) 并返回调用结果 Value;否则返回 None。 -# ============================================================ -def _try_property_getter_attr(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - at_node: ast.Attribute | t.CPtr, - obj_ptr: llvmlite.Value | t.CPtr, - trans: HT.Translator | t.CPtr, - fallback_class_name: str = None) -> llvmlite.Value | t.CPtr: - """尝试 property getter 属性访问,返回调用结果 Value;非 getter 返回 None(委托到 gen._try_property_getter_attr)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._try_property_getter_attr(pool, builder, mod, at_node, obj_ptr, - trans, fallback_class_name) - return None -# ============================================================ -# _try_property_setter — 尝试将 obj.attr = v 翻译为 property setter 调用 -# -# 检查 obj 的类是否有 @x.setter 的 attr 方法; -# 若有则生成 call Class.attr$set(obj, v),返回 1;否则返回 0。 -# ============================================================ -def _try_property_setter(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - target_attr: ast.Attribute | t.CPtr, - rhs_val: llvmlite.Value | t.CPtr, - trans: HT.Translator | t.CPtr) -> int: - """尝试 property setter 赋值,返回 1=已处理(生成调用)(委托到 gen._try_property_setter)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._try_property_setter(pool, builder, mod, target_attr, rhs_val, trans) - return 0 -# ============================================================ -# _try_property_deleter — 尝试将 del obj.attr 翻译为 property deleter 调用 -# -# 检查 obj 的类是否有 @x.deleter 的 attr 方法; -# 若有则生成 call Class.attr$del(obj),返回 1;否则返回 0。 -# ============================================================ -def _try_property_deleter(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - target_attr: ast.Attribute | t.CPtr, - trans: HT.Translator | t.CPtr) -> int: - """尝试 property deleter 删除,返回 1=已处理(生成调用)(委托到 gen._try_property_deleter)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._try_property_deleter(pool, builder, mod, target_attr, trans) - return 0 -# ============================================================ -# _translate_static_class_call — 翻译 ClassName.method(args) 静态/类方法调用 -# -# @staticmethod: 直接 call Class.method(args...),无 self -# @classmethod: 在参数前插入栈上分配的类实例指针(与 TPC 一致) -# ============================================================ -def _translate_static_class_call(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, - method_name: str, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """翻译类名静态/类方法调用,返回 call 结果 Value;非静态/类方法返回 None(委托到 gen._translate_static_class_call)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._translate_static_class_call(pool, builder, mod, class_name, method_name, cl, trans) - return None -# ============================================================ -# _translate_method_call - 翻译方法调用 obj.method(args) -# -# 生成: call @SHA1.ClassName.method_name(Ptr(StructTy) %obj, args...) -# -# obj_ptr 是对象变量的 alloca(Ptr(StructTy)),作为 self 参数传入 -# ============================================================ -def _translate_method_call(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, - method_name: str, - obj_ptr: llvmlite.Value | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """翻译方法调用,返回 call 结果 Value(委托到 gen._translate_method_call)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._translate_method_call(pool, builder, mod, class_name, method_name, - obj_ptr, cl, trans) - return None -# ============================================================ -# _kwarg_name_matches — 检查关键字参数名是否匹配函数参数名 -# -# 函数参数名在 LLVM IR 中带 % 前缀(如 "%a"),关键字参数名无前缀(如 "a") -# 跳过 % 前缀后逐字符比较 -# ============================================================ -def _kwarg_name_matches(kw_arg: str, - param_name: str) -> int: - """检查关键字参数名 kw_arg 是否匹配参数名 param_name(跳过 % 前缀)(委托到 gen._kwarg_name_matches)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._kwarg_name_matches(kw_arg, param_name) - return 0 -# ============================================================ -# _translate_struct_ctor_kw — 结构体构造函数(关键字参数) -# -# 支持两种语法: -# Point(x=10, y=20) — 全关键字 -# Point(10, y=20) — 混合(位置 + 关键字) -# -# 位置参数按字段索引赋值,关键字参数按字段名查找赋值 -# ============================================================ -def _translate_struct_ctor_kw(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - struct_ty: llvmlite.LLVMType | t.CPtr, - class_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - keywords: list[ast.AST | t.CPtr] | t.CPtr, - kw_count: t.CSizeT, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """结构体构造函数(关键字参数版本)(委托到 gen._translate_struct_ctor_kw)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._translate_struct_ctor_kw(pool, builder, mod, struct_ty, class_name, - cargs, can, keywords, kw_count, trans) - return None -# ============================================================ -# _translate_call_with_kwargs — 带关键字参数的函数调用 -# -# 支持两种语法: -# add(b=4, a=3) — 全关键字乱序 -# greet("Hello", name="World") — 位置 + 关键字混合 -# -# 策略: 遍历 found_func.Params 链表,对每个参数: -# 1. 若位置参数仍有剩余(param_idx < can),取位置参数 -# 2. 否则按参数名匹配关键字参数 -# 3. 按参数顺序构建调用参数链表 -# ============================================================ -def _translate_call_with_kwargs(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - func_name: str, - found_func: llvmlite.Function | t.CPtr, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - keywords: list[ast.AST | t.CPtr] | t.CPtr, - kw_count: t.CSizeT, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """带关键字参数的函数调用,按参数顺序构建调用链表(委托到 gen._translate_call_with_kwargs)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._translate_call_with_kwargs(pool, builder, mod, func_name, found_func, - cargs, can, keywords, kw_count, trans) - return None -# ============================================================ -# _translate_t_type_cast - 翻译 t.XXX(value) 类型转换 -# -# 当 func 是 t.XXX 形式且 XXX 是已知类型名(map_t_type 能映射)时, -# 将 value 转换为目标类型: -# - 指针 → 整数: ptrtoint(如 t.CUInt64T(ptr) → i64) -# - 整数 → 指针: inttoptr(如 t.CPtr(int_val) → i8*) -# - 整数 → 整数: trunc/zext(如 t.CInt8T(i32_val) → i8) -# - 指针 → 指针: bitcast(如 t.CPtr(ptr_val) → i8*) -# - 整数 → 浮点: sitofp(如 t.CDouble(i32_val) → double) -# - 浮点 → 整数: fptosi(如 t.CInt(double_val) → i32) -# - 浮点 → 浮点: fpext/fptrunc(如 t.CFloat(double_val) → float) -# ============================================================ -def _translate_t_type_cast(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - val: llvmlite.Value | t.CPtr, - target_ty: llvmlite.LLVMType | t.CPtr, - target_name: str = None, - src_node: ast.AST | t.CPtr = None, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """类型转换:根据参数类型和目标类型选择转换方式(委托到 gen._translate_t_type_cast)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._translate_t_type_cast(pool, builder, val, target_ty, - target_name, src_node, trans) - return None -# ============================================================ -# 泛型实例化辅助:从 Subscript slice 提取类型实参名 -# ============================================================ -# _get_type_name_from_annotation 已移至 HandlesType.py(支持 BinOp/Attribute) -# HandlesExprCall 通过 HandlesType._get_type_name_from_annotation 调用 - -def _extract_type_args_from_slice(pool: memhub.MemBuddy | t.CPtr, - slice_node: ast.AST | t.CPtr) -> list[str] | t.CPtr: - """从 Subscript.slice 提取类型实参名列表(委托到 gen._extract_type_args_from_slice)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._extract_type_args_from_slice(pool, slice_node) - return None -# ============================================================ -# 泛型类构造调用辅助: list[str](pool, 8) → __new__ + __before_init__ + __init__ -# -# 复用 translate_list_literal 的构造逻辑: -# 1. alloca tmp(特化类临时空间,作为 __new__ 的 self) -# 2. 翻译 cl.args 为参数指针数组 -# 3. call __new__(tmp, *args) → storage_ptr -# 4. call __before_init__(storage_ptr) -# 5. call __init__(storage_ptr, *args) -# 6. return storage_ptr -# -# 必须独立于 translate_call 的普通函数路径:spec_name 是类名不是函数名, -# 走裸名路径会被 _lookup_mod_sha1 的 star import 回退误导,用错误的 SHA1 -# 且缺少 __new__ 方法名后缀,导致链接报 undefined reference。 -# ============================================================ -def _infer_generic_ctor_type_arg(pool: memhub.MemBuddy | t.CPtr, - arg_node: ast.AST | t.CPtr, - class_name: str) -> str: - """从构造实参 AST 推断泛型类型实参名;无法推断时默认 "int"(与 TPC 一致)(委托到 gen._infer_generic_ctor_type_arg)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._infer_generic_ctor_type_arg(pool, arg_node, class_name) - return "int" -def _translate_generic_ctor_call(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - spec_name: str, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """泛型类构造调用: list[str](pool, 8) → __new__ + __before_init__ + __init__(委托到 gen._translate_generic_ctor_call)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._translate_generic_ctor_call(pool, builder, mod, spec_name, cl, trans) - return None diff --git a/App/lib/core/Handles/ExprCallDeref.vp b/App/lib/core/Handles/ExprCallDeref.vp deleted file mode 100644 index 2db6191..0000000 --- a/App/lib/core/Handles/ExprCallDeref.vp +++ /dev/null @@ -1,291 +0,0 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import sys -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.StubMerger as StubMerger - - -import lib.core.Handles.ExprCallBase as ExprCallBase -import lib.core.Handles.ExprCallCtor as ExprCallCtor -import lib.core.Handles.ExprCallCall as ExprCallCall -import lib.core.Handles.ExprCallTable as ExprCallTable -import lib.core.Handles.ExprCallHandle as ExprCallHandle -import lib.core.Handles.HandlesExprCall as HandlesExprCall - -# ============================================================ -# ExprCallDeref - HandlesExprCall 拆分(阶段 E):ExprCallDeref -# -# 直接移动模式:委托函数迁至此模块,原 HandlesExprCall.vp 仅 -# 保留 _g_gen/常量/类;调用方经本模块前缀访问。 -# ============================================================ - -# ============================================================ -# c.Deref(ptr) — 解引用指针,按指针 pointee 类型读取 -# -# 生成: %N = load , * %ptr -# 返回 pointee 类型的值 -# -# 注意: 必须按 ptr 的 pointee 类型决定读取宽度。 -# - i8* (str/bytes/字符遍历) → load i8 -# - i64* (t.CUInt64T, 块头部) → load i64(memhub 的 free list 链表读 8 字节头部) -# 之前固定 load i8 导致 memhub 读块头部只读到低 8 位, -# free list 的 next 指针被截断成 0x88 等垃圾值,alloc 崩溃。 -# ============================================================ -def translate_c_deref(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """c.Deref(ptr) → load 按 ptr 的 pointee 类型(委托到 gen.translate_c_deref)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.translate_c_deref(pool, builder, mod, cl, trans) - return None -# ============================================================ -# c.DerefAs(ptr, val) — 解引用写入,*ptr = val -# -# 生成: %pc = bitcast i8* %ptr to * -# store %val, * %pc -# ============================================================ -def translate_c_derefas(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """c.DerefAs(ptr, val) → store val to ptr(bitcast 后 store)(委托到 gen.translate_c_derefas)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.translate_c_derefas(pool, builder, mod, cl, trans) - return None -# ============================================================ -# c.Set(a, b) — 赋值语义 a = b(与 c.DerefAs 的指针语义不同) -# -# c.DerefAs(ptr, val) 是 *ptr = val(指针解引用写); -# c.Set(a, b) 是 a = b(a 为左值),a 支持三种形态: -# 1. c.Deref(ptr) → *ptr = b(zlib/vipermath 的 c.Set(c.Deref(p), v) 用法) -# 2. Name 变量 → 变量赋值(含 global/nonlocal/局部) -# 3. Attribute → 字段赋值(GEP + store) -# ============================================================ -def translate_c_set(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """c.Set(a, b) → a = b(赋值语义,a 为左值)(委托到 gen.translate_c_set)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.translate_c_set(pool, builder, mod, cl, trans) - return None -# ============================================================ -# c.Addr(var) — 取变量地址,返回 alloca 指针(不 load) -# -# 用于获取栈变量的可写地址,配合 c.DerefAs 使用 -# ============================================================ -def translate_c_addr(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """c.Addr(var) → 返回变量的 alloca 指针(不 load)(委托到 gen.translate_c_addr)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.translate_c_addr(pool, builder, mod, cl, trans) - return None -# ============================================================ -# c.Load(a, b) — 指针间复制: *a = *b -# -# 加载 b 指向的值,存储到 a 指向的地址。 -# 生成: %pc_src = bitcast i8* %src to * -# %loaded = load , * %pc_src -# %pc_dst = bitcast i8* %dst to * -# store %loaded, * %pc_dst -# ============================================================ -def translate_c_load(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """c.Load(a, b) → *a = *b(加载 b 的值,存储到 a)(委托到 gen.translate_c_load)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.translate_c_load(pool, builder, mod, cl, trans) - return None - -# ============================================================ -# c.Asm — 内联汇编支持 -# -# 生成: %N = call asm sideeffect "", ""() -# 或: call void asm sideeffect "", ""() -# -# 操作数按出现顺序编号 $0, $1, ...(用户需按输出在前写 f-string) -# ============================================================ - -ASM_MAX_OPERANDS: t.CDefine = 16 -ASM_TEXT_BUF_SIZE: t.CDefine = 2048 -ASM_CONST_BUF_SIZE: t.CDefine = 512 -ASM_ARGS_BUF_SIZE: t.CDefine = 512 -ASM_LINE_BUF_SIZE: t.CDefine = 4096 -# ============================================================ -# _asm_append_cstr — 将 C 字符串 src 追加到 dst 末尾 -# ============================================================ -def _asm_append_cstr(dst: str, dst_size: t.CSizeT, - src: str): - """将 C 字符串 src 追加到 dst 末尾(委托到 gen._asm_append_cstr)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - g._asm_append_cstr(dst, dst_size, src) -# ============================================================ -# _asm_escape_for_ir — 将汇编文本转义为 LLVM IR 字符串内容 -# -# \n → \0A, " → \22, \ → \5C -# ============================================================ -def _asm_escape_for_ir(pool: memhub.MemBuddy | t.CPtr, - src: str) -> str: - """转义汇编文本用于 LLVM IR 字符串字面量(委托到 gen._asm_escape_for_ir)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._asm_escape_for_ir(pool, src) - return None -# ============================================================ -# _resolve_register — 将 ASM_DESCR 属性名映射到约束字符串 -# ============================================================ -def _resolve_register(attr_name: str) -> str: - """将 t.ASM_DESCR.XXX 的属性名映射到约束字符串值(委托到 gen._resolve_register)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._resolve_register(attr_name) - return "" -# ============================================================ -# _resolve_asm_descr — 递归解析约束表达式 -# -# 支持: -# t.ASM_DESCR.XXX → _resolve_register(XXX) -# expr | expr(BinOp BitOr) → 拼接 -# "string" (Constant) → 直接返回 -# ============================================================ -def _resolve_asm_descr(pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr) -> str: - """递归解析约束表达式,返回约束字符串(委托到 gen._resolve_asm_descr)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._resolve_asm_descr(pool, node) - return "" -# ============================================================ -# _asm_get_operand — 获取操作数数组中第 idx 个元素的指针 -# ============================================================ -def _asm_get_operand(base: HandlesExprCall.AsmOperand | t.CPtr, - idx: int) -> HandlesExprCall.AsmOperand | t.CPtr: - """获取操作数数组中第 idx 个元素的指针(委托到 gen._asm_get_operand)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._asm_get_operand(base, idx) - return None -# ============================================================ -# _asm_is_c_call — 检查 Call 节点是否是 c.XXX 调用 -# -# 返回 attr_name(如 "AsmInp"/"AsmOut"),不是则返回 None -# ============================================================ -def _asm_is_c_call(node: ast.Call | t.CPtr) -> str: - """检查 Call 节点是否是 c.XXX 调用,返回属性名或 None(委托到 gen._asm_is_c_call)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._asm_is_c_call(node) - return None -# ============================================================ -# _asm_add_operand — 添加操作数到数组 -# -# 返回 1 成功, 0 失败(数组已满) -# ============================================================ -def _asm_add_operand(operands: HandlesExprCall.AsmOperand | t.CPtr, - count: int, - val: llvmlite.Value | t.CPtr, - constraint: str, - is_output: int) -> int: - """添加操作数到数组,返回新计数(失败返回原计数)(委托到 gen._asm_add_operand)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._asm_add_operand(operands, count, val, constraint, is_output) - return 0 -# ============================================================ -# translate_c_asm — 翻译 c.Asm 内联汇编 -# -# 语法: -# c.Asm("nop", [t.ASM_DESCR.CLOBBER_MEMORY]) -# c.Asm(f"mov rax, {c.AsmInp(val, t.ASM_DESCR.REG_ANY)}", op=[...]) -# c.Asm(f"...", out=[c.AsmOut(var, t.ASM_DESCR.OUTPUT_REG)], op=[...]) -# ============================================================ -def translate_c_asm(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译 c.Asm 内联汇编,返回结果 Value(委托到 gen.translate_c_asm)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.translate_c_asm(pool, builder, mod, cl, trans) - return None - -# ============================================================ -# c.LLVMIR — 内联 LLVM IR(无返回值,直接嵌入原始 IR 文本) -# -# 语法: -# c.LLVMIR(f"add i32 {c.LInp(a)}, {c.LInp(b)}") -# c.LLVMIR(f"{c.LOut(result)} = add i32 {c.LInp(a)}, {c.LInp(b)}") -# -# c.LInp(expr) - 输入操作数,替换为 expr 的 LLVM 值引用文本(SSA 名 "%x" 或常量 "42") -# c.LOut(expr) - 输出操作数:为 expr 变量分配唯一 SSA 寄存器 %llvmirN, -# 模板嵌入后自动追加 store %llvmirN, * %expr 写回变量 -# -# 语义(2026-08-08 用户决策):不做指令解析,模板文本直接嵌入当前基本块, -# 返回 None(无返回值)。ret_ty 第二参数已废弃(兼容忽略)。 -# ============================================================ - -LLVMIR_MAX_OPS: t.CDefine = 16 -LLVMIR_TEMPLATE_BUF: t.CDefine = 512 -# 注:LOut 唯一 SSA 寄存器名计数器已迁入 gen 字段(CallGenMixin.LLVMIRRegSeq), -# 本模块不再持有(P4 簇 1+2)。 - -# ============================================================ -# translate_c_llvmir — 翻译 c.LLVMIR 内联 LLVM IR -# ============================================================ -def translate_c_llvmir(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """c.LLVMIR 内联 LLVM IR:无返回值,直接嵌入原始 IR 文本(委托到 gen.translate_c_llvmir)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.translate_c_llvmir(pool, builder, mod, cl, trans) - return None diff --git a/App/lib/core/Handles/ExprCallHandle.vp b/App/lib/core/Handles/ExprCallHandle.vp deleted file mode 100644 index 3cde168..0000000 --- a/App/lib/core/Handles/ExprCallHandle.vp +++ /dev/null @@ -1,287 +0,0 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import sys -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.StubMerger as StubMerger - - -import lib.core.Handles.ExprCallBase as ExprCallBase -import lib.core.Handles.ExprCallDeref as ExprCallDeref -import lib.core.Handles.ExprCallCtor as ExprCallCtor -import lib.core.Handles.ExprCallCall as ExprCallCall -import lib.core.Handles.ExprCallTable as ExprCallTable -import lib.core.Handles.HandlesExprCall as HandlesExprCall - -# ============================================================ -# ExprCallHandle - HandlesExprCall 拆分(阶段 E):ExprCallHandle -# -# 直接移动模式:委托函数迁至此模块,原 HandlesExprCall.vp 仅 -# 保留 _g_gen/常量/类;调用方经本模块前缀访问。 -# ============================================================ - -# ============================================================ -# NewExprCallHandle - 工厂函数 -# ============================================================ -def NewExprCallHandle(pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr) -> HandlesExprCall.ExprCallHandle | t.CPtr: - """新建 HandlesExprCall.ExprCallHandle 工厂(委托到 gen.NewExprCallHandle)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.NewExprCallHandle(pool, trans) - return None -# ============================================================ -# _make_vtable_ref_i8 / _emit_eh_guarded_call / _translate_isinstance -# (追加91:CallGenMixin 拆分后顶层经委托调用 CallGenLeafKit 方法—— -# TPV self 调用仅支持 1 级父类,跨 Mixin 统一走 HandlesExprCall._g_gen 委托) -# ============================================================ -def _make_vtable_ref_i8(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """构造类 vtable 地址引用(i8*)(委托到 gen._make_vtable_ref_i8)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._make_vtable_ref_i8(pool, builder, mod, class_name, trans) - return None -def _emit_eh_guarded_call(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - trans: HT.Translator | t.CPtr, - func: llvmlite.Function | t.CPtr, - call_name: str, - head: llvmlite.Value | t.CPtr, - count: int, - ret_ty: llvmlite.LLVMType | t.CPtr, - is_variadic: int) -> llvmlite.Value | t.CPtr: - """带 try-except EH 检测的函数调用(委托到 gen._emit_eh_guarded_call)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._emit_eh_guarded_call(builder, pool, mod, trans, func, call_name, head, count, ret_ty, is_variadic) - return None -def _translate_isinstance(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - obj_node: ast.AST | t.CPtr, - cls_node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译 isinstance()(委托到 gen._translate_isinstance)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._translate_isinstance(pool, builder, mod, obj_node, cls_node, trans) - return None -# ============================================================ -# _is_sha1_mangled_call / _is_list_builtin_method / _translate_fakeduck_call / -# _translate_super_call(阶段 B:CallGenMixin 拆分后顶层经委托调用这些方法) -# ============================================================ -def _is_sha1_mangled_call(call_name: str) -> int: - """判断 call_name 是否为跨模块 Viper 函数(委托到 gen._is_sha1_mangled_call)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._is_sha1_mangled_call(call_name) - return 0 -def _is_list_builtin_method(class_name: str, method_name: str) -> int: - """判断(class_name, method_name) 是否是 list 泛型内置方法(委托到 gen._is_list_builtin_method)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._is_list_builtin_method(class_name, method_name) - return 0 -def _translate_fakeduck_call(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cls_name: str, - method_name: str, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """FakeDuck: str 变量方法调用(委托到 gen._translate_fakeduck_call)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._translate_fakeduck_call(pool, builder, mod, cls_name, method_name, cl, trans) - return None -def _translate_super_call(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - method_name: str, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """super().method(args) → 父类方法静态调用(委托到 gen._translate_super_call)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._translate_super_call(pool, builder, mod, cl, method_name, trans) - return None -# ============================================================ -# translate_call 前置检测 helper(阶段 C:CallGenMixin 拆分后顶层经委托 -# 调用 CallGenDispatch 方法。每个返回 Value|CPtr,None = 未命中继续主路径) -# ============================================================ -def _tc_h1_super_ctraits(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr, - func_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - hit_box: t.CPtr = None) -> llvmlite.Value | t.CPtr: - """super()/ctraits 编译期检测(委托到 gen._tc_h1_super_ctraits)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._tc_h1_super_ctraits(pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can, hit_box) - return None -def _tc_h2_c_special(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr, - func_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - hit_box: t.CPtr = None) -> llvmlite.Value | t.CPtr: - """c.Deref/Asm/LLVMIR 等特殊调用(委托到 gen._tc_h2_c_special)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._tc_h2_c_special(pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can, hit_box) - return None -def _tc_h3_stdarg_cast(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr, - func_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT) -> llvmlite.Value | t.CPtr: - """stdarg 糖 + str/int/bool 内置强转(委托到 gen._tc_h3_stdarg_cast)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._tc_h3_stdarg_cast(pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) - return None -def _tc_h4_type_casts(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr, - func_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT) -> llvmlite.Value | t.CPtr: - """t.XXX / typedef 类型转换(委托到 gen._tc_h4_type_casts)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._tc_h4_type_casts(pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) - return None -def _tc_h5_sizeof_len_isinst(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr, - func_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT) -> llvmlite.Value | t.CPtr: - """__sizeof__/len/isinstance 内置(委托到 gen._tc_h5_sizeof_len_isinst)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._tc_h5_sizeof_len_isinst(pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) - return None -def _tc_h6_method_dispatch(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr, - func_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - hit_box: t.CPtr = None) -> llvmlite.Value | t.CPtr: - """静态类/方法调用/表达式接收者/self.field/list 内置(委托到 gen._tc_h6_method_dispatch)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._tc_h6_method_dispatch(pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can, hit_box) - return None -# ============================================================ -# FuncGen 跨 Mixin 委托(阶段 D:FuncGenMixin 拆 Base/Def 后顶层经 -# 此调用这些方法。参数与目标方法一致,去 self) -# ============================================================ -def extract_func_attrs(pool: memhub.MemBuddy | t.CPtr, - decorator_list: list[ast.AST | t.CPtr] | t.CPtr, - imported_modules: str) -> str: - """从 decorator_list 提取 c.Attribute 属性(委托到 gen.extract_func_attrs)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.extract_func_attrs(pool, decorator_list, imported_modules) - return None -def _mangle_name(trans: HT.Translator | t.CPtr, name: str) -> str: - """为任意名称添加 SHA1 前缀(委托到 gen._mangle_name)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._mangle_name(trans, name) - return name -def _mangle_func_name(trans: HT.Translator | t.CPtr, name: str, - has_export: int) -> str: - """为函数名添加 SHA1 前缀(委托到 gen._mangle_func_name)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._mangle_func_name(trans, name, has_export) - return name -def _body_has_raise(fd: ast.FunctionDef | t.CPtr) -> int: - """函数体顶层是否含 raise(委托到 gen._body_has_raise)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._body_has_raise(fd) - return 0 -def _prepare_chain_nonlocals(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - i8_ty: llvmlite.LLVMType | t.CPtr, - i8_ptr_ty: llvmlite.LLVMType | t.CPtr) -> int: - """准备嵌套函数 nonlocals 链(委托到 gen._prepare_chain_nonlocals)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._prepare_chain_nonlocals(trans, node, pool, builder, mod, i8_ty, i8_ptr_ty) - return 0 diff --git a/App/lib/core/Handles/ExprCallTable.vp b/App/lib/core/Handles/ExprCallTable.vp index 27b2fde..32afb1a 100644 --- a/App/lib/core/Handles/ExprCallTable.vp +++ b/App/lib/core/Handles/ExprCallTable.vp @@ -1,206 +1,197 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import sys -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.StubMerger as StubMerger - - -import lib.core.Handles.ExprCallBase as ExprCallBase -import lib.core.Handles.ExprCallDeref as ExprCallDeref -import lib.core.Handles.ExprCallCtor as ExprCallCtor -import lib.core.Handles.ExprCallCall as ExprCallCall -import lib.core.Handles.ExprCallHandle as ExprCallHandle -import lib.core.Handles.HandlesExprCall as HandlesExprCall - -# ============================================================ -# ExprCallTable - HandlesExprCall 拆分(阶段 E):ExprCallTable -# -# 直接移动模式:委托函数迁至此模块,原 HandlesExprCall.vp 仅 -# 保留 _g_gen/常量/类;调用方经本模块前缀访问。 -# ============================================================ - -# ============================================================ -# 初始化函数表 -# ============================================================ -def init_func_table(pool: memhub.MemBuddy | t.CPtr, - max_count: int) -> HandlesExprCall.FuncEntry | t.CPtr: - """分配并清零函数表数组(委托到 gen.init_func_table)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.init_func_table(pool, max_count) - return None -# ============================================================ -# 查找函数 -# ============================================================ -def find_func_in_table(funcs: HandlesExprCall.FuncEntry | t.CPtr, - func_count: int, - name: str) -> llvmlite.Function | t.CPtr: - """在函数表中按名称查找,返回 Function 指针或 None(委托到 gen.find_func_in_table)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.find_func_in_table(funcs, func_count, name) - return None -# ============================================================ -# 添加函数到函数表 -# ============================================================ -def add_func_to_table(funcs: HandlesExprCall.FuncEntry | t.CPtr, - func_count: int, - name: str, - func: llvmlite.Function | t.CPtr, - max_count: int, - defaults: t.CVoid | t.CPtr = None, - default_count: int = 0, - param_count: int = 0, - pool: memhub.MemBuddy | t.CPtr = None) -> int: - """添加函数到函数表,返回 0 成功(委托到 gen.add_func_to_table)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.add_func_to_table(funcs, func_count, name, func, max_count, - defaults, default_count, param_count, pool) - return 0 - -# ============================================================ -# 全局函数注册表(跨模块函数查找) -# -# 所有模块翻译的函数都会注册到此表(通过 add_func_to_table 自动注册)。 -# 主要用途: vtable 初始化时查找跨模块继承方法的 Function 对象, -# 以获取函数类型信息构造 bitcast 字符串。 -# ============================================================ -GLOBAL_FUNC_MAX: t.CDefine = 8192 -def _init_global_func_table() -> int: - """初始化全局函数表(用 stdlib.malloc 分配,生命周期=整个程序)(委托到 gen._init_global_func_table)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._init_global_func_table() - return 0 -# _build_func_type_str — 从 Function 对象生成函数类型文本(stdlib 存储) -# -# 格式: ret_ty(param1_ty, param2_ty, ...),与 vtable bitcast 需要一致。 -# 用 stdlib.malloc 分配返回,跨文件永久存活(1b reset 不回收)。 -# 返回 None 表示失败。 -def _build_func_type_str(pool: memhub.MemBuddy | t.CPtr, - func: llvmlite.Function | t.CPtr) -> str: - """生成函数类型文本(stdlib 分配)(委托到 gen._build_func_type_str)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._build_func_type_str(pool, func) - return None -def _register_global_func(name: str, func: llvmlite.Function | t.CPtr, - pool: memhub.MemBuddy | t.CPtr = None) -> int: - """注册函数到全局表(已存在则跳过),返回 0 成功(委托到 gen._register_global_func)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._register_global_func(name, func, pool) - return 0 -def update_global_func_typestr(pool: memhub.MemBuddy | t.CPtr, - name: str, - func: llvmlite.Function | t.CPtr) -> int: - """更新全局函数表的 TypeStr(在函数参数全部添加完成后调用)(委托到 gen.update_global_func_typestr)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.update_global_func_typestr(pool, name, func) - return 0 -def find_func_global(name: str) -> llvmlite.Function | t.CPtr: - """在全局函数表中按名称查找,返回 Function 指针或 None(委托到 gen.find_func_global)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.find_func_global(name) - return None -def find_func_entry_global(name: str) -> HandlesExprCall.FuncEntry | t.CPtr: - """在全局函数表中按名称查找,返回完整 HandlesExprCall.FuncEntry(含 TypeStr)或 None(委托到 gen.find_func_entry_global)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.find_func_entry_global(name) - return None - - -# ============================================================ -# 全局默认参数注册表(跨模块默认参数填充) -# -# 独立于 _global_funcs,因为 _register_global_func 可能在 -# add_func_to_table 之前被调用(如 stub 注入),此时 defaults 还不可用。 -# ============================================================ -GLOBAL_DEFAULTS_MAX: t.CDefine = 4096 -def _init_global_defaults_table() -> int: - """初始化全局默认参数表(委托到 gen._init_global_defaults_table)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._init_global_defaults_table() - return 0 -def _register_global_defaults(name: str, - defaults: t.CVoid | t.CPtr, - default_count: int, - param_count: int) -> int: - """注册函数默认参数到全局表,返回 0 成功(委托到 gen._register_global_defaults)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._register_global_defaults(name, defaults, default_count, param_count) - return 0 -def find_func_defaults(name: str) -> HandlesExprCall.FuncDefaultsEntry | t.CPtr: - """按函数名查找默认参数信息,返回 HandlesExprCall.FuncDefaultsEntry 或 None(委托到 gen.find_func_defaults)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g.find_func_defaults(name) - return None -# _build_const_from_snapshot — 从常量快照重建常量 IR 值 -# -# 用于跨模块默认参数填充:gd_entry.Defaults(pool 内 AST)可能已被 reset 回收, -# 改用注册时提取的 stdlib 常量快照(ConstKinds/ConstInts/ConstStrs)重建常量 IR。 -# 返回 llvmlite.Value*,失败返回 None。 -def _build_const_from_snapshot(pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - gd_entry: HandlesExprCall.FuncDefaultsEntry | t.CPtr, - di: int, - trans: HT.Translator | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr) -> llvmlite.Value | t.CPtr: - """从快照重建第 di 个默认值常量 IR(委托到 gen._build_const_from_snapshot)""" - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) - if g is not None: - return g._build_const_from_snapshot(pool, mod, gd_entry, di, trans, builder) - return None -def find_func_entry_in_table(funcs: HandlesExprCall.FuncEntry | t.CPtr, - func_count: int, - name: str) -> HandlesExprCall.FuncEntry | t.CPtr: - """在函数表中按名称查找,返回完整 HandlesExprCall.FuncEntry 或 None""" - if name is None or funcs is None: - return None - entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__() - i: int = 0 - while i < func_count: - entry_addr: t.CUInt64T = t.CUInt64T(funcs) + i * entry_size - entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - if entry.Name is not None: - if string.strcmp(entry.Name, name) == 0: - return entry - i += 1 - return None +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.CallGenLeafKit as CallGenLeafKit +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import sys +import viperlib +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.StubMerger as StubMerger + + +import lib.core.Handles.HandlesExprCall as HandlesExprCall + +# ============================================================ +# ExprCallTable - HandlesExprCall 拆分(阶段 E):ExprCallTable +# +# 直接移动模式:委托函数迁至此模块,原 HandlesExprCall.vp 仅 +# 保留 _g_gen/常量/类;调用方经本模块前缀访问。 +# ============================================================ + +# ============================================================ +# 初始化函数表 +# ============================================================ +def init_func_table(pool: memhub.MemBuddy | t.CPtr, + max_count: int) -> GenTypes.FuncEntry | t.CPtr: + """分配并清零函数表数组(委托到 gen.init_func_table)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) + if g is not None: + return g.CallGenLeafKit.init_func_table(pool, max_count) + return None +# ============================================================ +# 查找函数 +# ============================================================ +def find_func_in_table(funcs: GenTypes.FuncEntry | t.CPtr, + func_count: int, + name: str) -> llvmlite.Function | t.CPtr: + """在函数表中按名称查找,返回 Function 指针或 None(委托到 gen.find_func_in_table)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) + if g is not None: + return g.CallGenLeafKit.find_func_in_table(funcs, func_count, name) + return None +# ============================================================ +# 添加函数到函数表 +# ============================================================ +def add_func_to_table(funcs: GenTypes.FuncEntry | t.CPtr, + func_count: int, + name: str, + func: llvmlite.Function | t.CPtr, + max_count: int, + defaults: t.CVoid | t.CPtr = None, + default_count: int = 0, + param_count: int = 0, + pool: memhub.MemBuddy | t.CPtr = None) -> int: + """添加函数到函数表,返回 0 成功(委托到 gen.add_func_to_table)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) + if g is not None: + return g.CallGenLeafKit.add_func_to_table(funcs, func_count, name, func, max_count, + defaults, default_count, param_count, pool) + return 0 + +# ============================================================ +# 全局函数注册表(跨模块函数查找) +# +# 所有模块翻译的函数都会注册到此表(通过 add_func_to_table 自动注册)。 +# 主要用途: vtable 初始化时查找跨模块继承方法的 Function 对象, +# 以获取函数类型信息构造 bitcast 字符串。 +# ============================================================ +GLOBAL_FUNC_MAX: t.CDefine = 8192 +def _init_global_func_table() -> int: + """初始化全局函数表(用 stdlib.malloc 分配,生命周期=整个程序)(委托到 gen._init_global_func_table)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) + if g is not None: + return g.CallGenLeafKit._init_global_func_table() + return 0 +# _build_func_type_str — 从 Function 对象生成函数类型文本(stdlib 存储) +# +# 格式: ret_ty(param1_ty, param2_ty, ...),与 vtable bitcast 需要一致。 +# 用 stdlib.malloc 分配返回,跨文件永久存活(1b reset 不回收)。 +# 返回 None 表示失败。 +def _build_func_type_str(pool: memhub.MemBuddy | t.CPtr, + func: llvmlite.Function | t.CPtr) -> str: + """生成函数类型文本(stdlib 分配)(委托到 gen._build_func_type_str)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) + if g is not None: + return g.CallGenLeafKit._build_func_type_str(pool, func) + return None +def _register_global_func(name: str, func: llvmlite.Function | t.CPtr, + pool: memhub.MemBuddy | t.CPtr = None) -> int: + """注册函数到全局表(已存在则跳过),返回 0 成功(委托到 gen._register_global_func)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) + if g is not None: + return g.CallGenLeafKit._register_global_func(name, func, pool) + return 0 +def update_global_func_typestr(pool: memhub.MemBuddy | t.CPtr, + name: str, + func: llvmlite.Function | t.CPtr) -> int: + """更新全局函数表的 TypeStr(在函数参数全部添加完成后调用)(委托到 gen.update_global_func_typestr)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) + if g is not None: + return g.CallGenLeafKit.update_global_func_typestr(pool, name, func) + return 0 +def find_func_global(name: str) -> llvmlite.Function | t.CPtr: + """在全局函数表中按名称查找,返回 Function 指针或 None(委托到 gen.find_func_global)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) + if g is not None: + return g.CallGenLeafKit.find_func_global(name) + return None +def find_func_entry_global(name: str) -> GenTypes.FuncEntry | t.CPtr: + """在全局函数表中按名称查找,返回完整 GenTypes.FuncEntry(含 TypeStr)或 None(委托到 gen.find_func_entry_global)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) + if g is not None: + return g.CallGenLeafKit.find_func_entry_global(name) + return None + + +# ============================================================ +# 全局默认参数注册表(跨模块默认参数填充) +# +# 独立于 _global_funcs,因为 _register_global_func 可能在 +# add_func_to_table 之前被调用(如 stub 注入),此时 defaults 还不可用。 +# ============================================================ +GLOBAL_DEFAULTS_MAX: t.CDefine = 4096 +def _init_global_defaults_table() -> int: + """初始化全局默认参数表(委托到 gen._init_global_defaults_table)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) + if g is not None: + return g.CallGenLeafKit._init_global_defaults_table() + return 0 +def _register_global_defaults(name: str, + defaults: t.CVoid | t.CPtr, + default_count: int, + param_count: int) -> int: + """注册函数默认参数到全局表,返回 0 成功(委托到 gen._register_global_defaults)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) + if g is not None: + return g.CallGenLeafKit._register_global_defaults(name, defaults, default_count, param_count) + return 0 +def find_func_defaults(name: str) -> GenTypes.FuncDefaultsEntry | t.CPtr: + """按函数名查找默认参数信息,返回 GenTypes.FuncDefaultsEntry 或 None(委托到 gen.find_func_defaults)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) + if g is not None: + return g.CallGenLeafKit.find_func_defaults(name) + return None +# _build_const_from_snapshot — 从常量快照重建常量 IR 值 +# +# 用于跨模块默认参数填充:gd_entry.Defaults(pool 内 AST)可能已被 reset 回收, +# 改用注册时提取的 stdlib 常量快照(ConstKinds/ConstInts/ConstStrs)重建常量 IR。 +# 返回 llvmlite.Value*,失败返回 None。 +def _build_const_from_snapshot(pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + gd_entry: GenTypes.FuncDefaultsEntry | t.CPtr, + di: int, + trans: HT.Translator | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr) -> llvmlite.Value | t.CPtr: + """从快照重建第 di 个默认值常量 IR(委托到 gen._build_const_from_snapshot)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr)) + if g is not None: + return g.CallGenLeafKit._build_const_from_snapshot(pool, mod, gd_entry, di, trans, builder) + return None +def find_func_entry_in_table(funcs: GenTypes.FuncEntry | t.CPtr, + func_count: int, + name: str) -> GenTypes.FuncEntry | t.CPtr: + """在函数表中按名称查找,返回完整 GenTypes.FuncEntry 或 None""" + if name is None or funcs is None: + return None + entry_size: t.CSizeT = GenTypes.FuncEntry.__sizeof__() + i: int = 0 + while i < func_count: + entry_addr: t.CUInt64T = t.CUInt64T(funcs) + i * entry_size + entry: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + if entry.Name is not None: + if string.strcmp(entry.Name, name) == 0: + return entry + i += 1 + return None diff --git a/App/lib/core/Handles/ForHandleBase.vp b/App/lib/core/Handles/ForHandleBase.vp deleted file mode 100644 index 278e717..0000000 --- a/App/lib/core/Handles/ForHandleBase.vp +++ /dev/null @@ -1,18 +0,0 @@ -import t, c -from stdint import * -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# ForHandleBase - HandlesFor 拆分(迁移完成,仅保留 _g_gen 单例) -# -# P6 机械化迁移:ForHandleBase 全部方法(_extract_tuple_names/ -# _seq_kind/_build_seq_loop)→ StmtGenCifMixin 方法。 -# main/BuildPipeline 仍注入 _g_gen,不可删。 -# ============================================================ - - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None diff --git a/App/lib/core/Handles/ForHandleIter.vp b/App/lib/core/Handles/ForHandleIter.vp deleted file mode 100644 index 4db2155..0000000 --- a/App/lib/core/Handles/ForHandleIter.vp +++ /dev/null @@ -1,20 +0,0 @@ -import t, c -from stdint import * -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# ForHandleIter - HandlesFor 拆分(迁移完成,仅保留 _g_gen 单例) -# -# P6 机械化迁移:ForHandleIter 全部方法(_handle_ptr_iter/ -# _handle_array_iter/_handle_list_literal_iter/_handle_list_iter/ -# _handle_dict_iter/_handle_oop_iter/_handle_enumerate_iter/ -# _handle_zip_iter)→ StmtGenCifMixin 方法。 -# main/BuildPipeline 仍注入 _g_gen,不可删。 -# ============================================================ - - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None diff --git a/App/lib/core/Handles/HandlesAnnAssign.vp b/App/lib/core/Handles/HandlesAnnAssign.vp deleted file mode 100644 index 3ab35c8..0000000 --- a/App/lib/core/Handles/HandlesAnnAssign.vp +++ /dev/null @@ -1,234 +0,0 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import w32.fileio as fileio -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.HandlesType as HandlesType -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.VLogger as VLogger -import lib.core.Handles.ExprCallCall as ExprCallCall -import lib.core.Handles.ExprCallCtor as ExprCallCtor -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# HandlesAnnAssign - AnnAssign 语句处理(迁移完成,保留跨 Mixin 委托壳) -# -# P6 机械化迁移:AnnAssignHandle 类 → AssignGenMixin.translate_annassign / -# translate_annassign_prescan。分派中枢(StmtGenMixin/StmtGenDeclMixin)经 -# 本壳跨链调用(Viper @t.NoVTable 静态绑定下跨 Mixin self. 调用 mangle -# 失败,须经模块级委托壳桥回 gen 单例)。迁移收尾后统一删除。 -# ============================================================ - - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - - -# ============================================================ -# is_cdefine_annotation - 检测注解是否为 t.CDefine(模块级函数) -# -# 支持两种形式: -# 1. Attribute(Name('t'), 'CDefine') -# 2. BinOp(... | Attribute(Name('t'), 'CDefine'))(联合注解) -# ============================================================ -def is_cdefine_annotation(annot: ast.AST | t.CPtr) -> int: - """检测注解是否为 t.CDefine,返回 1 表示是,0 表示否(委托到 gen.is_cdefine_annotation)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.is_cdefine_annotation(annot) - return 0 - - -def is_ctypedef_annotation(annot: ast.AST | t.CPtr) -> int: - """检测注解是否为 t.CTypedef,返回 1 表示是,0 表示否(委托到 gen._is_ctypedef_annotation)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_ctypedef_annotation(annot) - return 0 - - -# ============================================================ -# extract_cdefine_int_value - 从 AnnAssign.value 提取整数常量(模块级函数) -# -# 支持的表达式形式: -# 1. Constant(INT) — 如 0x0002, 42 -# 2. BinOp(BitOr/BitAnd) — 如 FOREGROUND_RED | FOREGROUND_GREEN -# 3. Name — 引用已注册的 CDefine 常量 -# 4. Call — 如 t.CUnsignedLong(-11) → 取第一个参数 -# 5. UnaryOp(USub/UAdd/Invert) — 如 -11 -# ============================================================ -def extract_cdefine_int_value(val_node: ast.AST | t.CPtr) -> t.CInt64T: - """从值节点提取整数常量(支持 Constant/BinOp/Name/Call/UnaryOp,委托到 gen.extract_cdefine_int_value)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.extract_cdefine_int_value(val_node) - return 0 - - -# ============================================================ -# _register_cdefine_from_value - 注册 CDefine 常量(浮点/整数自动识别) -# -# 浮点字面量(如 vipermath 的 U_M_PI: t.CDefine = 3.14159...)走 -# register_cdefine_double,否则 translate_value 查表得 0 生成 -# ret i32 0(llc 报错 "value doesn't match function result type")。 -# ============================================================ -def _register_cdefine_from_value(pool: memhub.MemBuddy | t.CPtr, - name: str, val_node: ast.AST | t.CPtr) -> None: - """注册 CDefine 常量(浮点字面量 → register_cdefine_double,否则整数,委托到 gen._register_cdefine_from_value)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g._register_cdefine_from_value(pool, name, val_node) - - -# ============================================================ -# 源文件重读恢复 CDefine 浮点值 -# -# 背景:AST 节点的 float_val/str_val 字段可能被 pool 分配操作覆写 -# (MemBuddy 内存冲突),导致注册的浮点 CDefine 值错误(llc ret i32 0)。 -# 本函数直接读源文件找 "NAME: t.CDefine = value" 行,atof 解析 value—— -# 源文件文本不受 pool 影响,是最可靠的恢复路径。 -# 原模块级 _g_recover_found 全局已迁移为 gen 字段(RecoverFound)。 -# ============================================================ - - -def _recover_found() -> int: - """检查最近一次 _recover_cdefine_float 是否成功(委托到 gen._recover_found)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._recover_found() - return 0 - - -def _recover_cdefine_float(name: str, out: t.CDouble | t.CPtr) -> int: - """从当前模块源文件恢复浮点 CDefine 值,写入 out[0],成功返回 1 - - 用输出参数传递 double,避免 TPV 跨模块 double 返回值传递 bug。 - (委托到 gen._recover_cdefine_float) - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._recover_cdefine_float(name, out) - return 0 - - -# ============================================================ -# _annotation_contains_name - 递归检查注解中是否包含指定名称 -# -# 支持 BinOp(BitOr) 递归,同时检查 Attribute.attr 和 Name.id。 -# ============================================================ -def _annotation_contains_name(annot: ast.AST | t.CPtr, name: str) -> int: - """递归检查注解中是否包含指定名称,返回 1=包含 / 0=不包含(委托到 gen._annotation_contains_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._annotation_contains_name(annot, name) - return 0 - - -# ============================================================ -# _is_ptr_element_annotation - 检查注解是否为 bytes|t.CPtr 或 str|t.CPtr -# -# 返回 1=是(下标按 8 字节步长, i8** 语义), 0=否(下标按 1 字节步长, i8* 语义) -# -# 规则: -# bytes|t.CPtr / str|t.CPtr → i8**(8 字节步长)→ 返回 1 -# t.CChar|t.CPtr / t.CInt8T|t.CPtr → i8*(1 字节步长)→ 返回 0 -# 纯 bytes / str → i8*(1 字节步长)→ 返回 0 -# -# 注: 注解中的 "|" 是"和"的意思(组合类型),非右值中的位或运算 -# ============================================================ -def _is_ptr_element_annotation(annot: ast.AST | t.CPtr) -> int: - """检查注解是否为 bytes|t.CPtr 或 str|t.CPtr 形式(委托到 gen._is_ptr_element_annotation)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_ptr_element_annotation(annot) - return 0 - - -# ============================================================ -# _infer_static_array_ty_from_literal - 单参 CArray + 列表字面量 → 静态数组 -# -# 单参 t.CArray[elem_ty] 解析为 Ptr(elem_ty),但当 RHS 是列表字面量时, -# 按 TPC 语义应推断为 [len x elem_ty](对齐 TPC ParseListAnnotation): -# 避免误走动态 list 构造(_find_pool_var 兜底引用外部 @_mbuddy → 链接期 -# undefined)。PreScan 与 Handle 都调用(PreScan 预创建 alloca 的类型必须 -# 与 Handle 一致,否则 get_or_create_sym 复用旧 alloca 使推断失效)。 -# 真实实现已迁移至 gen._infer_static_array_ty_from_literal,本壳保留供 -# ClassGenDef(Gen 侧字段类型推断)等跨模块调用方使用。 -# ============================================================ -def _infer_static_array_ty_from_literal(pool: memhub.MemBuddy | t.CPtr, - annot: ast.AST | t.CPtr, - value: ast.AST | t.CPtr, - resolved_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.LLVMType | t.CPtr: - """单参 CArray + 列表字面量 → Array(elem_ty, len);否则返回原类型(委托到 gen._infer_static_array_ty_from_literal)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._infer_static_array_ty_from_literal(pool, annot, value, resolved_ty) - return resolved_ty - - -# ============================================================ -# _init_global_array_from_list — 从列表字面量初始化全局数组 -# -# 为每个元素生成 GEP + store 指令,将值存入全局数组的对应位置。 -# 适用于模块级 t.CArray[elem_ty, count] = [v0, v1, ...] 的初始化。 -# -# Args: -# builder: IRBuilder -# pool: 编译器内存池 -# mod: LLVMModule -# array_alloca: 全局数组变量的 Value 引用(类型为 [N x elem_ty]*) -# list_node: ast.List 节点 -# trans: Translator 对象 -# -# Returns: -# 0 成功,1 失败 -# ============================================================ -def _init_global_array_from_list(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - array_alloca: llvmlite.Value | t.CPtr, - list_node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr) -> int: - """从列表字面量初始化全局数组,为每个元素生成 GEP + store(委托到 gen._init_global_array_from_list)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._init_global_array_from_list(builder, pool, mod, array_alloca, list_node, trans) - return 0 - - -# ============================================================ -# translate_annassign - AnnAssign 语句翻译(委托到 gen.translate_annassign) -# ============================================================ -def translate_annassign(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 AnnAssign 语句,返回新增变量数(委托到 gen.translate_annassign)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_annassign(trans, node) - return 0 - - -# ============================================================ -# translate_annassign_prescan - AnnAssign 预扫描(委托到 gen.translate_annassign_prescan) -# ============================================================ -def translate_annassign_prescan(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """预扫描 AnnAssign,提前创建 alloca 到 entry block 顶部(委托到 gen.translate_annassign_prescan)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_annassign_prescan(trans, node) - return 0 diff --git a/App/lib/core/Handles/HandlesAssign.vp b/App/lib/core/Handles/HandlesAssign.vp deleted file mode 100644 index 997d1c2..0000000 --- a/App/lib/core/Handles/HandlesAssign.vp +++ /dev/null @@ -1,51 +0,0 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import viperlib -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.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.StubMerger as StubMerger -import lib.core.StubMergerStore as StubMergerStore -import lib.core.Handles.ExprCallBase as ExprCallBase -import lib.core.Handles.ExprCallCall as ExprCallCall -import lib.core.Handles.ExprCallCtor as ExprCallCtor -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# HandlesAssign - Assign 语句处理(迁移完成,保留跨 Mixin 委托壳) -# -# P6 机械化迁移:AssignHandle 类 → AssignGenMixin.translate_assign -# (lib.core.Gen.AssignGenMixin)。分派中枢(StmtGenMixin)经本壳跨链 -# 调用(Viper @t.NoVTable 静态绑定下跨 Mixin self. 调用 mangle 失败, -# 须经模块级委托壳桥回 gen 单例)。迁移收尾后统一删除。 -# ============================================================ - - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - - -# ============================================================ -# translate_assign - Assign 语句翻译(委托到 gen.translate_assign) -# ============================================================ -def translate_assign(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译赋值语句,返回新增变量数(委托到 gen.translate_assign)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_assign(trans, node) - return 0 diff --git a/App/lib/core/Handles/HandlesAugAssign.vp b/App/lib/core/Handles/HandlesAugAssign.vp deleted file mode 100644 index 19fbe29..0000000 --- a/App/lib/core/Handles/HandlesAugAssign.vp +++ /dev/null @@ -1,34 +0,0 @@ -import t, c -from stdint import * -import ast -import memhub -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# HandlesAugAssign - 增强赋值语句处理(迁移完成,保留跨 Mixin 委托壳) -# -# P6 机械化迁移:AugAssignHandle 类 → AssignGenMixin.translate_augassign。 -# 分派中枢(StmtGenMixin)经本壳跨链调用(Viper @t.NoVTable 静态绑定下 -# 跨 Mixin self. 调用 mangle 失败,须经模块级委托壳桥回 gen 单例)。 -# 迁移收尾(编译器缺陷修复)后统一删除。 -# ============================================================ - - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - - -# ============================================================ -# translate_augassign - 增强赋值翻译(委托到 gen.translate_augassign) -# ============================================================ -def translate_augassign(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译增强赋值语句,返回新增变量数(委托到 gen.translate_augassign)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_augassign(trans, node) - return 0 diff --git a/App/lib/core/Handles/HandlesBody.vp b/App/lib/core/Handles/HandlesBody.vp deleted file mode 100644 index c55ef5d..0000000 --- a/App/lib/core/Handles/HandlesBody.vp +++ /dev/null @@ -1,168 +0,0 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import viperlib -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesFunctions as HandlesFunctions -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# HandlesBody - 语句分派(P6 对象化后的委托层) -# -# 全部模块级函数已迁移为 lib.core.Gen.StmtGenMixin 的方法,本模块 -# 保留同名模块级函数作为"一行委托":延迟 import Gen 取全局单例 -# (BuildPipeline/main 创建后 set_global_gen 注册),再调用 gen 的 -# 对应方法。签名与旧函数完全一致,调用方零改动。 -# -# 所有语句类型通过 trans.XxxH.Handle(node) 分派到对应 Handle。 -# 对应 TransPyC BodyHandle.HandleBodyLlvm 的 isinstance 分派。 -# ============================================================ - - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式) -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - - -# ============================================================ -# 语句翻译分派 -# ============================================================ -def translate_stmt(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译单条语句,返回新增的变量数(委托到 gen.translate_stmt)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_stmt(trans, node) - return 0 - - -# ============================================================ -# 翻译 Delete 语句: del obj.attr -# -# 支持 property deleter: 当目标 attr 是 @x.deleter 方法时, -# 生成 call Class.attr$del(obj)。其余目标暂不生成代码。 -# ============================================================ -def translate_delete(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 del 语句,返回 0(委托到 gen.translate_delete)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_delete(trans, node) - return 0 - - -# ============================================================ -# 翻译 Global 语句: global x, y -# -# 将 names 中的变量名加入 _global_names 集合 -# ============================================================ -def translate_global(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 global 语句:记录 global 变量名(委托到 gen.translate_global)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_global(trans, node) - return 0 - - -# ============================================================ -# 翻译 Nonlocal 语句: nonlocal x, y -# -# 将 names 中的变量名加入 _nonlocal_names 集合 -# ============================================================ -def translate_nonlocal(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 nonlocal 语句:记录 nonlocal 变量名及其类型(委托到 gen.translate_nonlocal) - - 类型信息通过查找父作用域的 alloca 获取(用于 env 指针数组方案的类型恢复)。 - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_nonlocal(trans, node) - return 0 - - -# ============================================================ -# 翻译表达式语句 Expr(value=Call(...)) -# ============================================================ -def translate_expr_stmt(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译表达式语句(printf 调用等)(委托到 gen.translate_expr_stmt)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_expr_stmt(trans, node) - return 0 - - -# ============================================================ -# 预扫描:为局部变量提前创建 alloca -# ============================================================ -def pre_scan_allocas(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """预扫描语句中的 AnnAssign,提前创建 alloca(委托到 gen.pre_scan_allocas) - - 返回新增的变量数 - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.pre_scan_allocas(trans, node) - return 0 - - -# ============================================================ -# 预扫描:Global/Nonlocal 声明(Python 作用域语义) -# -# Python 中 global/nonlocal 声明对整个函数作用域生效,与声明 -# 位置无关。必须在翻译任何赋值之前注册 global/nonlocal 名称, -# 否则 global 声明前的赋值会错误创建局部变量遮蔽全局。 -# ============================================================ -def pre_scan_scope_decls(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """预扫描 Global/Nonlocal 声明,提前注册作用域名称(委托到 gen.pre_scan_scope_decls)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.pre_scan_scope_decls(trans, node) - return 0 - - -# ============================================================ -# 翻译 break 语句 -# ============================================================ -def translate_break(trans: HT.Translator | t.CPtr) -> int: - """翻译 break 语句:跳转到循环 end 块(委托到 gen.translate_break)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_break(trans) - return 0 - - -# ============================================================ -# 翻译 continue 语句 -# ============================================================ -def translate_continue(trans: HT.Translator | t.CPtr) -> int: - """翻译 continue 语句:跳转到循环 cond/incr 块(委托到 gen.translate_continue)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_continue(trans) - return 0 - - -# ============================================================ -# 获取语句类型名(调试用) -# ============================================================ -def get_stmt_kind_name(node: ast.AST | t.CPtr) -> str: - """获取语句类型名(委托到 gen.get_stmt_kind_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_stmt_kind_name(node) - return None diff --git a/App/lib/core/Handles/HandlesClassDef.vp b/App/lib/core/Handles/HandlesClassDef.vp deleted file mode 100644 index cf73c4d..0000000 --- a/App/lib/core/Handles/HandlesClassDef.vp +++ /dev/null @@ -1,1200 +0,0 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import viperlib -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesEnum as HandlesEnum -import lib.core.StubMerger as StubMerger -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - - -# 枚举成员临时数组最大数量(本地常量) -ENUM_MEMBER_MAX_LOCAL: t.CDefine = 128 - -# REnum 变体表容量上限(本地常量) -RENUM_CLASS_MAX: t.CDefine = 64 - -# 作用域类型常量(本地副本,避免旧编译器跨模块 CDefine 查找 bug) -SCOPE_FUNCTION: t.CDefine = 1 -RENUM_VARIANT_PER_CLASS: t.CDefine = 32 -RENUM_FIELD_PER_VARIANT: t.CDefine = 16 - - -# ============================================================ -# HandlesClassDef - class 定义处理 -# -# 解析 class 定义,创建 LLVM StructType 并注册字段信息 -# -# 纯内存结构体(无方法)的 class 定义: -# class Point: -# x: t.CInt -# y: t.CInt -# -# 生成 LLVM 类型: { i32, i32 } -# 注册字段: x→index 0, y→index 1 -# ============================================================ - - -# ============================================================ -# _is_cenum_base — 检查 base 节点是否为 t.CEnum -# -# 支持 Name(id='CEnum') 和 Attribute(value=Name('t'), attr='CEnum') -# ============================================================ -def _is_cenum_base(base_node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> int: - """检查 base 节点是否为 t.CEnum,返回 1=是 / 0=否(委托到 gen._is_cenum_base)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_cenum_base(base_node, trans) - return 0 - - -# ============================================================ -# _is_enum_class — 检查 ClassDef 是否继承自 t.CEnum -# ============================================================ -def _is_enum_class(cd: ast.ClassDef | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> int: - """检查 ClassDef 是否继承自 t.CEnum,返回 1=是 / 0=否(委托到 gen._is_enum_class)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_enum_class(cd, trans) - return 0 - - -# ============================================================ -# _is_cunion_base — 检查 base 节点是否为 t.CUnion -# -# 支持 Name(id='CUnion') 和 Attribute(value=Name('t'), attr='CUnion') -# ============================================================ -def _is_cunion_base(base_node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> int: - """检查 base 节点是否为 t.CUnion,返回 1=是 / 0=否(委托到 gen._is_cunion_base)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_cunion_base(base_node, trans) - return 0 - - -# ============================================================ -# _is_union_class — 检查 ClassDef 是否继承自 t.CUnion -# ============================================================ -def _is_union_class(cd: ast.ClassDef | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> int: - """检查 ClassDef 是否继承自 t.CUnion,返回 1=是 / 0=否(委托到 gen._is_union_class)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_union_class(cd, trans) - return 0 - - -# ============================================================ -# _is_crenum_base — 检查 base 节点是否为 t.REnum -# -# 支持 Name(id='REnum') 和 Attribute(value=Name('t'), attr='REnum') -# ============================================================ -def _is_crenum_base(base_node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> int: - """检查 base 节点是否为 t.REnum,返回 1=是 / 0=否(委托到 gen._is_crenum_base)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_crenum_base(base_node, trans) - return 0 - - -# ============================================================ -# _is_renum_class — 检查 ClassDef 是否继承自 t.REnum -# ============================================================ -def _is_renum_class(cd: ast.ClassDef | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> int: - """检查 ClassDef 是否继承自 t.REnum,返回 1=是 / 0=否(委托到 gen._is_renum_class)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_renum_class(cd, trans) - return 0 - - -# ============================================================ -# VTable 装饰器检测和继承关系判断 -# ============================================================ - -# 标记基类集合(非真实父类,仅作为类型标记) -_MARKER_BASES: t.CDefine = 9 -# 使用字符串比较代替集合,标记基类列表 -# Object, CVTable, Exception, CEnum, Enum, CStruct, CUnion, REnum, Struct(t.Struct) - - -# ============================================================ -# _has_decorator — 检查 ClassDef/FunctionDef 的 decorator_list 中是否有指定装饰器 -# -# 支持 @t.Name 和 @Name 两种形式 -# 返回 1=有 / 0=无 -# ============================================================ -def _has_decorator(decorator_list: list[ast.AST | t.CPtr] | t.CPtr, - deco_name: str) -> int: - """检查 decorator_list 中是否有指定装饰器名(委托到 gen._has_decorator)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._has_decorator(decorator_list, deco_name) - return 0 - - -def register_decorator(pool: memhub.MemBuddy | t.CPtr, - func_name: str, wrapper_name: str, - arg0: t.CInt64T) -> int: - """注册自定义装饰器函数(@log/@skip/@repeat(3) → __decor_wrap_{name},委托到 gen)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.register_decorator(pool, func_name, wrapper_name, arg0) - return -1 - - -def lookup_decor_wrapper(func_name: str) -> str: - """按原函数名查装饰器 wrapper 名,未注册返回 None(委托到 gen)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.lookup_decor_wrapper(func_name) - return None - - -def lookup_decor_arg0(func_name: str) -> t.CInt64T: - """按原函数名查装饰器首个常量参数(无参数为 0,委托到 gen)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.lookup_decor_arg0(func_name) - return 0 - - -# ============================================================ -# 异常类注册表委托(try-except,对齐 TPC HandlesClassDef.py L47-61) -# ============================================================ -def register_exception(class_name: str, parent_name: str) -> int: - """注册用户异常类并分配编码(幂等,委托到 gen)。返回编码或 -1""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.register_exception(class_name, parent_name) - return -1 - - -def lookup_exception_code(name: str) -> int: - """查异常编码:内置表优先,其次用户异常表(委托到 gen)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.lookup_exception_code(name) - return 0 - - -def is_exception_name(name: str) -> int: - """name 是否是内置或用户异常类名(委托到 gen)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.is_exception_name(name) - return 0 - - -def collect_descendant_codes(name: str, out_codes: t.CInt | t.CPtr, - max_codes: int) -> int: - """收集 name 及全部子孙异常编码(委托到 gen)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.collect_descendant_codes(name, out_codes, max_codes) - return 0 - - -def register_exception_class_def(trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr) -> int: - """注册异常类定义(分配编码 + 记录父类,不生成 struct,委托到 gen)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._register_exception_class_def(trans, cd) - return 0 - - -# ============================================================ -# 方法元数据(装饰器)支持 -# -# 与 TPC 的 FuncMeta 对齐,按位掩码存储: -# META_STATIC @staticmethod 无 self 参数 -# META_CLASS @classmethod cls 为首参(Ptr(struct_ty)) -# META_PROP_GETTER @property / @x.getter obj.prop → call Class.prop(obj) -# META_PROP_SETTER @x.setter obj.prop = v → call Class.prop$set(obj, v) -# META_PROP_DELETER @x.deleter del obj.prop → call Class.prop$del(obj) -# -# setter/deleter 函数名带 $set/$del 后缀,避免与 getter 冲突(与 TPC 一致)。 -# 元数据表用 stdlib 全局分配,跨模块持久(属性访问可能发生在其他模块)。 -# 注册时机:_translate_oop_methods(含 mark_only=1 的 struct 预注册阶段), -# 确保在 App 源文件翻译前元数据已就绪(不依赖 includes 是否已全量翻译)。 -# ============================================================ -META_STATIC: t.CDefine = 1 -META_CLASS: t.CDefine = 2 -META_PROP_GETTER: t.CDefine = 4 -META_PROP_SETTER: t.CDefine = 8 -META_PROP_DELETER: t.CDefine = 16 - -META_MAX: t.CDefine = 512 -META_KEY_LEN: t.CDefine = 128 - - -# ============================================================ -# _extract_func_meta — 从 decorator_list 提取方法元数据位掩码 -# -# 支持(与 TPC HandlesFunctions._ExtractFuncMeta 对齐): -# @staticmethod / @property / @classmethod(Name 形式) -# @property.setter / @x.setter / @x.getter / @x.deleter(Attribute 形式) -# ============================================================ -def _extract_func_meta(decorator_list: list[ast.AST | t.CPtr] | t.CPtr) -> int: - """从装饰器列表提取元数据位掩码,返回 0=无装饰器元数据(委托到 gen._extract_func_meta)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._extract_func_meta(decorator_list) - return 0 - - -# ============================================================ -# register_method_meta — 注册方法元数据(ClassName.method → meta) -# -# 幂等:重复注册相同 key 时更新标志位。内存用 stdlib 全局分配。 -# ============================================================ -def register_method_meta(class_name: str, method_name: str, - meta: int) -> None: - """注册方法元数据(幂等,委托到 gen.register_method_meta)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.register_method_meta(class_name, method_name, meta) - - -# ============================================================ -# lookup_method_meta — 查找方法元数据(ClassName.method → meta) -# -# 返回位掩码;未注册返回 0。跨模块持久,供属性访问/赋值/删除识别。 -# ============================================================ -def lookup_method_meta(class_name: str, method_name: str) -> int: - """查找方法元数据位掩码,返回 0=未注册或非装饰器方法(委托到 gen.lookup_method_meta)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.lookup_method_meta(class_name, method_name) - return 0 - - -# ============================================================ -# _is_marker_base — 检查基类名是否为标记基类(非真实父类) -# -# 标记基类: Object, CVTable, Exception, CEnum, Enum, CStruct, CUnion, REnum, Struct(t.Struct) -# ============================================================ -def _is_marker_base(base_name: str) -> int: - """检查基类名是否为标记基类,返回 1=是 / 0=否 - - 含 t.Struct:t.py 未定义 Struct 类(不被编译),`class X(t.Struct)` - 的 Struct 只是"普通结构体"标记。若不当成标记基类,会被误判为真实父类: - - 自动启用虚表 → 结构体多出 i8* 槽位(与 TPC 的 {i32,i32} 布局不符) - - Phase A-pre(declare_only=1)父类延迟检查找不到 "Struct" → 类被延迟注册 - → forward_declare 时类型未注册 → 裸类形参退化为 i32 → 函数签名与 - 函数体 alloca(Ptr(struct))不一致 → llc 报 "'%p' defined with type - 'i32' but expected 'ptr'"。 - 与 TPC(_resolve_base_kind 对 t.Struct 返回 None → 无父类)保持一致。 - (委托到 gen._is_marker_base) - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_marker_base(base_name) - return 0 - - -# ============================================================ -# _get_base_name — 从 base AST 节点提取基类名 -# -# 支持 Name(id), Attribute(attr), Subscript(value, slice) -# 对于 Subscript(如 GSListNode[Value]),需要 pool 拼接特化名 "GSListNode[Value]" -# ============================================================ -def _get_base_name(base_node: ast.AST | t.CPtr, - pool: memhub.MemBuddy | t.CPtr = None) -> str: - """从 base AST 节点提取基类名,返回 None=失败 - - 对于 Subscript 节点,需要 pool 分配内存拼接特化名; - pool=None 时降级返回基类名(不含类型实参) - (委托到 gen._get_base_name) - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._get_base_name(base_node, pool) - return None - - -# ============================================================ -# _get_parent_class — 获取 ClassDef 的真实父类名(非标记基类) -# -# 遍历 bases,返回第一个非标记基类的名字,None=无真实父类 -# 支持 Name, Attribute, Subscript 三种 base 节点 -# 对于 Subscript(如 GSListNode[Value]),需要 trans.Pool 拼接特化名 -# ============================================================ -def _get_parent_class(cd: ast.ClassDef | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> str: - """获取 ClassDef 的真实父类名,返回 None=无真实父类(委托到 gen._get_parent_class)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._get_parent_class(cd, trans) - return None - - -# ============================================================ -# _collect_parents — 收集 ClassDef 的所有真实父类名(多继承) -# -# 遍历 cd.bases,跳过 marker base(Object/CVTable/NoVTable 等), -# 收集全部真实父类名到 parents_buf(t.CSizeT 数组,每元素 str 指针)。 -# 返回收集数量。 -# ============================================================ -def _collect_parents(pool: memhub.MemBuddy | t.CPtr, - cd: ast.ClassDef | t.CPtr, - parents_buf: t.CSizeT | t.CPtr, - max_parents: int, - trans: HT.Translator | t.CPtr = None) -> int: - """收集所有非 marker 父类名到 parents_buf,返回数量(委托到 gen._collect_parents)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._collect_parents(pool, cd, parents_buf, max_parents, trans) - return 0 - - -# ============================================================ -# _field_name_exists — 检查字段名是否已存在于收集数组(去重) -# ============================================================ -def _field_name_exists(names_buf: t.CSizeT | t.CPtr, - count: int, name: str) -> int: - """检查字段名是否已在 names_buf 中(先声明父类优先,重复跳过)(委托到 gen._field_name_exists)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._field_name_exists(names_buf, count, name) - return 0 - - -# ============================================================ -# _class_body_has_field — 检查类体是否声明了字段(AnnAssign) -# -# 用于区分"无字段类"(接口/标记类,合法)与"注册不完整" -# (类体有字段但 FieldCount==0,漏注册报错)。 -# ============================================================ -def _class_body_has_field(cd: ast.ClassDef | t.CPtr) -> int: - """检查类体是否声明了字段(AnnAssign),0=纯方法/无字段类(委托到 gen._class_body_has_field)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._class_body_has_field(cd) - return 0 - - -# ============================================================ -# _trigger_base_specialization — 触发 base 中 Subscript 的泛型特化 -# -# 对于 class Value(GSListNode[Value]),GSListNode[Value] 是 Subscript 节点。 -# 在 translate_class_def 处理 Value 之前,需要先特化 GSListNode[Value], -# 否则 find_struct_by_module("GSListNode[Value]") 返回 None,父类字段不被继承。 -# -# 遍历 cd.bases,如果 base 是 Subscript,提取 class_name 和 type_args, -# 调用 _specialize_generic_class 触发特化。 -# ============================================================ -def _trigger_base_specialization(trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr): - """触发 base 中 Subscript 的泛型特化(如 GSListNode[Value])(委托到 gen._trigger_base_specialization)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g._trigger_base_specialization(trans, cd) - - -# ============================================================ -# _has_any_func_cvtable — 检查类中是否有任何函数标记了 @t.CVTable -# -# 用于类级别未启用虚表时,检查函数级 @t.CVTable 是否触发虚表。 -# 跳过 __init__ 和 __before_init__(构造函数不进入虚表)。 -# ============================================================ -def _has_any_func_cvtable(cd: ast.ClassDef | t.CPtr) -> int: - """检查类中是否有任何函数标记了 @t.CVTable,返回 1=有 / 0=无(委托到 gen._has_any_func_cvtable)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._has_any_func_cvtable(cd) - return 0 - - -# ============================================================ -# _should_method_be_virtual — 判断方法是否应该进入虚表 -# -# 规则(优先级从高到低): -# 1. 函数有 @t.NoVTable → 排除(返回 0) -# 2. 函数有 @t.CVTable → 包含(返回 1) -# 3. 类有 @t.CVTable → 包含(返回 1) -# 4. 有继承关系(父类非 NoVTable)→ 包含(返回 1) -# 5. 默认 → 排除(返回 0) -# ============================================================ -def _should_method_be_virtual(cd: ast.ClassDef | t.CPtr, - fd: ast.FunctionDef | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> int: - """判断方法是否应该进入虚表,返回 1=包含 / 0=排除(委托到 gen._should_method_be_virtual)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._should_method_be_virtual(cd, fd, trans) - return 0 - - -# ============================================================ -# _detect_vtable_status — 检测类是否应该启用虚表 -# -# 规则: -# 1. @t.CVTable → 有虚表 -# 2. 有真实父类且非 NoVTable → 有虚表(自动启用) -# 3. @t.NoVTable → 检查函数级 @t.CVTable,有则启用 -# 4. 默认 → 检查函数级 @t.CVTable,有则启用 -# -# 返回: 1=有虚表 / 0=无虚表 -# ============================================================ -def _detect_vtable_status(cd: ast.ClassDef | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> int: - """检测类是否应该启用虚表(委托到 gen._detect_vtable_status)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._detect_vtable_status(cd, trans) - return 0 - - -# ============================================================ -# _resolve_enum_member_type — 解析枚举成员的类型 -# -# - t.State → 默认 i32 -# - int / t.CInt8T / t.CInt16T / t.CInt32T / t.CInt64T 等 → 对应整数类型 -# - 联合注解(t.State | t.CInt8T)递归查找实际类型 -# ============================================================ -def _resolve_enum_member_type(pool: memhub.MemBuddy | t.CPtr, - ann_node: ast.AST | t.CPtr, - imported_modules: str, - from_imports: str) -> llvmlite.LLVMType | t.CPtr: - """解析枚举成员的类型注解为 LLVM 整数类型(委托到 gen._resolve_enum_member_type)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._resolve_enum_member_type(pool, ann_node, imported_modules, from_imports) - return None - - -# ============================================================ -# _is_state_annotation — 检查注解节点是否为 t.State -# ============================================================ -def _is_state_annotation(node: ast.AST | t.CPtr) -> int: - """检查注解节点是否为 t.State,返回 1=是 / 0=否(委托到 gen._is_state_annotation)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_state_annotation(node) - return 0 - - -# ============================================================ -# _extract_int_value — 从 AST 节点提取整数值 -# -# 支持 Constant(int) 和 UnaryOp(USub, Constant(int)) -# ============================================================ -def _extract_int_value(node: ast.AST | t.CPtr) -> t.CInt64T: - """从 AST 节点提取整数值,失败返回 0(委托到 gen._extract_int_value)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._extract_int_value(node) - return 0 - - -# ============================================================ -# _translate_enum_def — 翻译枚举类定义 -# -# 遍历 class body 中的 AnnAssign,收集成员名、类型、值 -# 自动赋值:无值时从上一值+1递增(首值默认 0) -# 基准类型:所有成员类型中 Bits 最大的(t.State 视为 i32) -# ============================================================ -def _translate_enum_def(trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr) -> int: - """翻译枚举类定义,返回 0(委托到 gen._translate_enum_def)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._translate_enum_def(trans, cd) - return 0 - - -# ============================================================ -# _get_type_size — 计算 LLVM 类型的字节大小 -# -# 用于联合体确定最大字段大小 -# ============================================================ -def _get_type_size(ty: llvmlite.LLVMType | t.CPtr) -> int: - """计算 LLVM 类型的字节大小(含对齐 padding)(委托到 gen._get_type_size)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._get_type_size(ty) - return 0 - - -def _get_type_align(ty: llvmlite.LLVMType | t.CPtr) -> int: - """返回类型的自然对齐(字节)(委托到 gen._get_type_align)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._get_type_align(ty) - return 0 - - -# ============================================================ -# _translate_union_def — 翻译联合体定义 -# -# 联合体语法: -# class MyUnion(t.CUnion): -# a: t.CInt -# b: t.CFloat -# c: t.CInt64T -# -# 实现方式: -# - 收集所有字段类型 -# - 计算最大字段字节大小 max_size -# - LLVM 类型 = Struct([Array(Int8, max_size)]) # { [N x i8] } -# - 注册到 HandlesStruct 并标记 IsUnion=1 -# - 字段访问通过 bitcast 实现(HandlesExpr 中处理) -# ============================================================ -def _translate_union_def(trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr) -> int: - """翻译联合体定义,返回 0(委托到 gen._translate_union_def)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._translate_union_def(trans, cd) - return 0 - - -# ============================================================ -# _get_annotation_field_size — 计算注解类型的字节大小 -# -# 用于 REnum 布局计算,不要求类型已注册(避免自引用死锁)。 -# 联合类型 (A | B) 按指针 8 字节处理。 -# 未知类型默认 8 字节(指针)。 -# ============================================================ -def _get_annotation_field_size(annotation: ast.AST | t.CPtr) -> int: - """计算注解类型的字节大小,用于 REnum 布局计算(委托到 gen._get_annotation_field_size)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._get_annotation_field_size(annotation) - return 0 - - -# ============================================================ -# _translate_renum_def — 翻译 REnum 类定义 -# -# REnum 语法: -# class LLVMType(t.REnum): -# class Int: -# Bits: t.CInt -# class Ptr: -# Pointee: LLVMType | t.CPtr -# ... -# -# 内存布局: {i32 __tag, , , ...} -# 每个字段位置取所有变体在该位置的最大字段大小: -# - max_size <= 4 → i32 -# - max_size > 4 → i64(可容纳指针) -# 至少包含 {i32, i32}(tag + 最小 payload) -# -# 对应 TPC 中 HandlesClassDef._RegisterREnumMembers 的逻辑 -# ============================================================ -def _translate_renum_def(trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr) -> int: - """翻译 REnum 类定义,返回 0(委托到 gen._translate_renum_def)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._translate_renum_def(trans, cd) - return 0 - - -# ============================================================ -# REnum 变体表(全局静态分配) -# -# 存储 ClassName → [VariantName, TagValue] 映射, -# 供 translate_call 检测 ClassName.VariantName(args) 形式的变体构造调用。 -# -# P5-2 后已迁入 gen 字段(ClassGenMixin.RenumClassNames/RenumClassCount/ -# RenumVariantNames/RenumVariantTags),经下方委托函数访问。 -# ============================================================ - - -# ============================================================ -# REnum 字段别名表(全局静态分配) -# -# 存储 (class_name, field_name) → payload_index 映射, -# 供 translate_attribute 查找 REnum 变体字段。 -# -# REnum 结构体布局为 {i32 __tag, _p1, _p2, ...}, -# 但源码用变体字段名访问(如 ty.Pointee)。 -# 此表将变体字段名映射到 payload 索引(_p1=1, _p2=2, ...)。 -# -# 布局: -# _renum_alias_class[i] = 类名(str 指针,以 CSizeT 存储) -# _renum_alias_field[i] = 字段名(str 指针,以 CSizeT 存储) -# _renum_alias_index[i] = payload 索引(CSizeT) -# ============================================================ -RENUM_ALIAS_MAX: t.CDefine = 512 - - -# ============================================================ -# _register_renum_variants — 注册 REnum 类的变体名和 tag 值 -# -# 遍历 ClassDef 的 children,提取嵌套变体类的名称, -# 按 children 顺序分配 tag 值(0, 1, 2, ...) -# -# 参数: -# pool: 内存分配器 -# class_name: REnum 类名(如 "LLVMType") -# cd: REnum 类的 ClassDef AST 节点 -# variant_count: 变体数量(由 _translate_renum_def 预计算) -# ============================================================ -def _register_renum_variants(pool: memhub.MemBuddy | t.CPtr, - class_name: str, - cd: ast.ClassDef | t.CPtr, - variant_count: int): - """注册 REnum 类的变体名和 tag 值到全局变体表(委托到 gen._register_renum_variants)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g._register_renum_variants(pool, class_name, cd, variant_count) - - -# ============================================================ -# _lookup_renum_variant — 查找变体所属的 REnum 类名 -# -# 参数: -# variant_name: 变体名(如 "Int"、"Ptr") -# -# 返回: -# 成功: class_name (str) -# 失败: None -# 注: tag_value 可通过 _lookup_renum_variant_in_class(class_name, variant_name) 获取 -# ============================================================ -def _lookup_renum_variant(variant_name: str) -> str: - """查找变体名所属的 REnum 类名 - - 返回: class_name (str),或 None(委托到 gen._lookup_renum_variant) - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._lookup_renum_variant(variant_name) - return None - - -# ============================================================ -# _is_renum_class_name — 检查名称是否是已注册的 REnum 类名 -# -# 用于 translate_call 检测 ClassName.Variant(args) 形式调用时, -# 先验证 ClassName 是否是 REnum 类。 -# ============================================================ -def _is_renum_class_name(class_name: str) -> int: - """检查名称是否是已注册的 REnum 类名,返回 1=是 / 0=否(委托到 gen._is_renum_class_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_renum_class_name(class_name) - return 0 - - -# ============================================================ -# _lookup_renum_variant_in_class — 在指定 REnum 类中查找变体 -# -# 参数: -# class_name: REnum 类名 -# variant_name: 变体名 -# -# 返回: -# 成功: tag_value (int) -# 失败: -1 -# ============================================================ -def _lookup_renum_variant_in_class(class_name: str, variant_name: str) -> int: - """在指定 REnum 类中查找变体,返回 tag 值或 -1(委托到 gen._lookup_renum_variant_in_class)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._lookup_renum_variant_in_class(class_name, variant_name) - return 0 - - -# ============================================================ -# _register_renum_field_alias — 注册 REnum 变体字段名别名 -# -# 将变体字段名(如 "Pointee")映射到 payload 索引(如 1), -# 供 translate_attribute 查找 REnum 变体字段。 -# -# 参数: -# pool: 内存分配器 -# class_name: REnum 类名(如 "LLVMType") -# field_name: 变体字段名(如 "Pointee") -# payload_idx: payload 索引(1=_p1, 2=_p2, ...) -# ============================================================ -def _register_renum_field_alias(pool: memhub.MemBuddy | t.CPtr, - class_name: str, - field_name: str, - payload_idx: int, - field_ty: llvmlite.LLVMType | t.CPtr = None, - variant_name: str = None): - """注册 REnum 变体字段名别名到全局表(委托到 gen._register_renum_field_alias) - - field_ty: 变体成员实际 LLVM 类型(可选,供 match 绑定 bitcast) - variant_name: 所属变体名(可选,match 绑定按 (class, 变体, 位置) 定位成员) - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g._register_renum_field_alias(pool, class_name, field_name, payload_idx, - field_ty, variant_name) - - -# ============================================================ -# _update_renum_alias_class_ptr — 更新别名表中的 class_name 指针 -# -# register_struct 会通过 pool.alloc+strcpy 复制类名,导致 entry.Name -# 与原始 cd.name 是不同指针。别名注册时用 cd.name,查找时用 entry.Name, -# CSizeT 指针值比较会失败。此函数将别名表中所有匹配 old_ptr 的 class_name -# 更新为 new_ptr,确保注册和查找使用同一指针。 -# -# 参数: -# old_ptr: 旧 class_name 指针值(CSizeT(cd.name)) -# new_ptr: 新 class_name 指针值(CSizeT(entry.Name)) -# ============================================================ -def _update_renum_alias_class_ptr(old_ptr: t.CSizeT, new_ptr: t.CSizeT): - """更新别名表中的 class_name 指针,从 old_ptr 更新为 new_ptr(委托到 gen._update_renum_alias_class_ptr)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g._update_renum_alias_class_ptr(old_ptr, new_ptr) - - -# ============================================================ -# _lookup_renum_field_alias — 查找 REnum 变体字段名的 payload 索引 -# -# 参数: -# class_name: REnum 类名(如 "LLVMType") -# field_name: 变体字段名(如 "Pointee") -# -# 返回: -# 成功: payload 索引(1, 2, ...) -# 失败: -1 -# ============================================================ -def _lookup_renum_field_alias(class_name: str, field_name: str) -> int: - """查找 REnum 变体字段名的 payload 索引,返回索引或 -1 - - class_name: 用 CSizeT 指针值比较(_update_renum_alias_class_ptr 已统一指针) - field_name: 用 strcmp 内容比较(注册时 vnm.id 与查找时 at.attr 是不同指针) - (委托到 gen._lookup_renum_field_alias) - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._lookup_renum_field_alias(class_name, field_name) - return 0 - - -# ============================================================ -# _lookup_renum_field_alias_ty — 查找 REnum 变体成员的实际 LLVM 类型 -# -# 与 _lookup_renum_field_alias 同表同键。供 match 绑定把槽位地址 -# bitcast 成成员真实类型(Struct.Name: i8* 而非槽位 i64)。 -# -# 返回: -# 成功: LLVMType(perm_pool 深拷贝,跨文件存活) -# 失败: None -# ============================================================ -def _lookup_renum_field_alias_ty(class_name: str, - field_name: str) -> llvmlite.LLVMType | t.CPtr: - """查找 REnum 变体成员的实际 LLVM 类型,返回类型或 None(委托到 gen._lookup_renum_field_alias_ty)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._lookup_renum_field_alias_ty(class_name, field_name) - return None - - -# ============================================================ -# _lookup_renum_member_ty — 按 (class, 变体名, payload 位置) 查找成员类型 -# -# match 绑定用:同一 payload 位置跨变体类型不同,必须带变体名定位。 -# -# 返回: -# 成功: LLVMType(perm_pool 深拷贝,跨文件存活) -# 失败: None -# ============================================================ -def _lookup_renum_member_ty(class_name: str, - variant_name: str, - payload_idx: int) -> llvmlite.LLVMType | t.CPtr: - """按 (class, 变体名, payload 位置) 查找变体成员实际类型,返回类型或 None(委托到 gen._lookup_renum_member_ty)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._lookup_renum_member_ty(class_name, variant_name, payload_idx) - return None - - -# ============================================================ -# translate_class_def — 翻译 class 定义 -# -# 遍历 class body 中的 AnnAssign 语句,收集字段类型 -# 创建 LLVM StructType 并注册到 HandlesStruct -# ============================================================ -# ============================================================ -# 泛型类模板存储 -# -# 泛型类 class list[T]: 不直接发射 IR,而是存储为模板, -# 等遇到 list[int](pool) 实例化时触发 _specialize_generic_class。 -# -# P5-2 收尾:已迁入 gen 字段(ClassGenMixin.GenericClassNames/ -# GenericClassNodes/GenericClassSha1s),经下方委托函数访问。 -# ============================================================ - - -def _is_generic_class(tp: list[str] | t.CPtr) -> int: - """检查 ClassDef 是否有类型参数(泛型类),返回 1=是 / 0=否(委托到 gen._is_generic_class)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_generic_class(tp) - return 0 - - -def _register_generic_template(pool: memhub.MemBuddy | t.CPtr, - cd: ast.ClassDef | t.CPtr, - module_sha1: str): - """注册泛型类模板(类名 + ClassDef 节点 + 来源模块 SHA1)(委托到 gen._register_generic_template)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g._register_generic_template(pool, cd, module_sha1) - - -def _find_generic_template(class_name: str) -> ast.ClassDef | t.CPtr: - """查找泛型类模板,返回 ClassDef 节点或 None(委托到 gen._find_generic_template)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._find_generic_template(class_name) - return None - - -def _find_generic_template_sha1(class_name: str) -> str: - """查找泛型类模板的来源模块 SHA1,未找到返回 None(委托到 gen._find_generic_template_sha1)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._find_generic_template_sha1(class_name) - return None - - -def _mangle_generic_class_name(pool: memhub.MemBuddy | t.CPtr, - class_name: str, - type_args: list[str] | t.CPtr) -> str: - """生成特化类名: list + [int] -> list[int](委托到 gen._mangle_generic_class_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._mangle_generic_class_name(pool, class_name, type_args) - return None - - -# ============================================================ -# 类型注解拷贝(用于泛型特化) -# -# _clone_annotation: 拷贝类型注解表达式,替换类型参数 T 为具体类型 -# _clone_arguments: 拷贝 Arguments 节点,替换 arg annotation 中的 T -# _clone_classdef_for_spec: 拷贝 ClassDef 用于泛型特化 -# ============================================================ - -def _clone_annotation(pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr, - tp_names: list[str] | t.CPtr, - type_args: list[str] | t.CPtr) -> ast.AST | t.CPtr: - """拷贝类型注解表达式,替换类型参数 T 为具体类型名(委托到 gen._clone_annotation)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._clone_annotation(pool, node, tp_names, type_args) - return None - - -def _clone_arguments(pool: memhub.MemBuddy | t.CPtr, - args: ast.AST | t.CPtr, - tp_names: list[str] | t.CPtr, - type_args: list[str] | t.CPtr) -> ast.AST | t.CPtr: - """拷贝 Arguments 节点,替换 arg annotation 中的 T(委托到 gen._clone_arguments)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._clone_arguments(pool, args, tp_names, type_args) - return None - - -def _clone_classdef_for_spec(pool: memhub.MemBuddy | t.CPtr, - cd: ast.ClassDef | t.CPtr, - spec_name: str, - tp_names: list[str] | t.CPtr, - type_args: list[str] | t.CPtr) -> ast.ClassDef | t.CPtr: - """拷贝 ClassDef 节点用于泛型特化(委托到 gen._clone_classdef_for_spec)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._clone_classdef_for_spec(pool, cd, spec_name, tp_names, type_args) - return None - - -# ============================================================ -# 泛型特化缓存(容量常量) -# -# 用扁平 stdlib 数组 + stdlib 深拷贝字符串,保证缓存条目 -# 跨文件永久存活(1b 每文件 reset_to(mark1) 不会回收)。 -# 缓存状态(_spec_keys/_spec_names/_spec_count)已迁移为 -# ClassGenMixin.SpecKeys/SpecNames/SpecCount(P5-2 簇 C)。 -# ============================================================ - -SPEC_CACHE_MAX: t.CDefine = 512 - - -def _find_cached_spec(spec_key: str) -> str: - """查找已缓存的特化名,未找到返回 None(委托到 gen._find_cached_spec)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._find_cached_spec(spec_key) - return None - - -def _cache_spec(pool: memhub.MemBuddy | t.CPtr, spec_key: str, spec_name: str): - """缓存特化结果(stdlib 深拷贝存储,跨文件安全)(委托到 gen._cache_spec)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g._cache_spec(pool, spec_key, spec_name) - - -# ============================================================ -# _merge_template_imports - 特化翻译前并入模板模块的 imports -# -# 泛型特化(_specialize_generic_class)用触发方文件的 Translator 翻译 -# 模板方法体,但模板方法体引用的模块(如 _list.vp 的 append 里 -# string.memcpy 依赖 string)来自模板文件自身的 import。若不并入, -# 跨模块 fast-fail 检查会把 string.memcpy 误报为"模块 string 未导入"。 -# 调用方负责在特化翻译后恢复 trans._imported_modules。 -# ============================================================ -def _merge_template_imports(trans: HT.Translator | t.CPtr, - template_sha1: str) -> None: - """将模板模块的 imports 并入 trans._imported_modules(空格分隔)(委托到 gen._merge_template_imports)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g._merge_template_imports(trans, template_sha1) - - -def _specialize_generic_class(trans: HT.Translator | t.CPtr, - class_name: str, - type_args: list[str] | t.CPtr) -> str: - """特化泛型类,返回特化类名(委托到 gen._specialize_generic_class)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._specialize_generic_class(trans, class_name, type_args) - return None - - -def translate_class_def(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 class 定义,返回 0(委托到 gen.translate_class_def)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_class_def(trans, node) - return 0 - - -# ============================================================ -# ClassGenDef 跨 Mixin 委托(阶段 D:ClassGenMixin 拆 Base/Def 后 -# translate_class_def 经此调用这些方法。参数与目标方法一致,去 self) -# ============================================================ -def _is_exception_class_def(cd: ast.ClassDef | t.CPtr) -> int: - """类定义是否是异常类(委托到 gen._is_exception_class_def)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_exception_class_def(cd) - return 0 - - -def _register_exception_class_def(trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr) -> int: - """注册异常类(分配编码 + 记录父类)(委托到 gen._register_exception_class_def)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._register_exception_class_def(trans, cd) - return 0 - - -def _register_class_meta_list(pool: memhub.MemBuddy | t.CPtr, - kind: int, cls: str, - value_node: ast.AST | t.CPtr) -> None: - """解析类体 __provides__/__requires__ 的 list[str] 字面量并注册(委托到 gen._register_class_meta_list)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g._register_class_meta_list(pool, kind, cls, value_node) - - -# ============================================================ -# VTable 生成 -# -# 生成 VTable 全局变量: -# @"SHA1.ClassName.vtable" = internal constant { i8*, i8*, ... } { -# i8* bitcast (ret (params)* @"SHA1.ClassName.method1" to i8*), -# ... -# } -# -# VTable 槽位顺序: class body 中 FunctionDef 的出现顺序 -# ============================================================ - -VTBL_METHOD_MAX: t.CDefine = 32 - - -# _vtable_strcat — 将 src 追加到 dst 末尾 -def _vtable_strcat(dst: str, dst_size: t.CSizeT, - src: str): - """将 src 追加到 dst 末尾(委托到 gen._vtable_strcat)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g._vtable_strcat(dst, dst_size, src) - - -# _vtable_name_needs_quote — 检查 LLVM 标识符是否需要引号 -def _vtable_name_needs_quote(name: str) -> int: - """检查 LLVM 标识符是否需要引号(以数字开头或含 '.')(委托到 gen._vtable_name_needs_quote)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._vtable_name_needs_quote(name) - return 0 - - -# _format_func_type_str — 从 Function 对象生成函数类型字符串 -# -# 格式: ret_ty (param1_ty, param2_ty, ...) -# 例如: void ({i32, i32}*, i32) -def _format_func_type_str(pool: memhub.MemBuddy | t.CPtr, - buf: str, buf_size: t.CSizeT, - func: llvmlite.Function | t.CPtr) -> int: - """从 Function 对象生成函数类型字符串(委托到 gen._format_func_type_str)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._format_func_type_str(pool, buf, buf_size, func) - return 0 - - -# ============================================================ -# vtable 收集暂存区(已迁移为 ClassGenMixin.VtFullNames/ -# VtMethodNames/VtParentSha1s/VtMethodCount,P5-2 簇 D) -# -# _collect_vtable_methods 的收集结果,跨函数传递: -# - _translate_oop_methods 在翻译方法体之前先收集一次, -# 使方法体内的 self.虚方法 调用能查到 VTableMethods(虚分派依赖) -# - _generate_vtable 再收集一次,生成 vtable 全局变量 -# method_names_buf 是 stdlib 分配,存入 StructEntry.VTableMethods -# 后跨模块持久(不得迁入 mb 池 reset 区间)。 -# ============================================================ - - -# ============================================================ -# _collect_vtable_methods — 收集类的虚方法信息 -# -# 1. 继承父类虚方法(父类方法排在子类方法之前,保持槽位顺序一致) -# 2. 收集当前类虚方法(跳过已继承的) -# -# 结果存入 ClassGenMixin.VtFullNames/VtMethodNames/VtParentSha1s/ -# VtMethodCount(原模块级 _g_vt_*),并设置 entry.VTableMethodCount / -# VTableMethods(stdlib 分配,供虚分派跨模块查询)。 -# -# 返回 1=有虚方法 / 0=无方法或失败 -# ============================================================ -def _collect_vtable_methods(trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr, - class_name: str) -> int: - """收集虚方法信息,设置 entry.VTableMethods/VTableMethodCount(委托到 gen._collect_vtable_methods)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._collect_vtable_methods(trans, cd, class_name) - return 0 - - -# _generate_vtable — 生成 VTable 全局变量 -# -# 1. 收集 class body 中所有 FunctionDef 作为虚方法 -# 2. 构造 VTable 类型 { i8*, i8*, ... } -# 3. 构造初始化字符串 { i8* bitcast (...), ... } -# 4. 创建全局变量 @"SHA1.ClassName.vtable" -# 5. 存储虚方法名列表到 StructEntry -def _generate_vtable(trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr, - class_name: str) -> int: - """生成 VTable 全局变量(委托到 gen._generate_vtable)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._generate_vtable(trans, cd, class_name) - return 0 - - -# ============================================================ -# OOP 方法翻译 -# -# 存在任意 FunctionDef 的 class 自动升级为 OOP 结构体。 -# 方法翻译为 SHA1.ClassName.method_name(self: Ptr(StructTy), ...) 函数。 -# self 参数直接注册为 SSA 值(不创建 alloca),使 self.field 能通过 GEP 直接访问。 -# ============================================================ - - -# ============================================================ -# _translate_oop_methods — 扫描 class body 中的方法并翻译 -# -# 遍历 ClassDef.children,对每个 FunctionDef: -# - 标记 OOP(mark_as_oop) -# - 如果是 __init__,标记 has_init -# - 翻译方法(生成 SHA1.ClassName.method_name 函数) -# 翻译完所有方法后,生成 __before_init__ 函数 -# ============================================================ -def _translate_oop_methods(trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr, - struct_ty: llvmlite.LLVMType | t.CPtr, - class_name: str, - mark_only: int = 0, - reemit: int = 0) -> int: - """扫描 class body 中的方法并翻译,生成 __before_init__ - - mark_only: 0=全量翻译(默认),1=只设置 IsOOP/HasNew/HasInit 标志(不翻译方法体) - reemit: 1=补译模式(泛型特化 Phase B 补译调用,强制发射方法体) - (委托到 gen._translate_oop_methods) - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._translate_oop_methods(trans, cd, struct_ty, class_name, mark_only, reemit) - return 0 - - -# ============================================================ -# _translate_method — 翻译单个方法 -# -# 生成: define @SHA1.ClassName.method_name(Ptr(StructTy) %self, ...) -# -# self 参数处理: -# - 类型 Ptr(struct_ty),直接注册为 SSA 值(不创建 alloca) -# - 使 self.field 能通过 GEP 直接访问原始结构体 -# ============================================================ -def _translate_method(trans: HT.Translator | t.CPtr, - fd: ast.FunctionDef | t.CPtr, - struct_ty: llvmlite.LLVMType | t.CPtr, - class_name: str) -> int: - """翻译单个方法,返回 0(委托到 gen._translate_method)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._translate_method(trans, fd, struct_ty, class_name) - return 0 - - -# ============================================================ -# _generate_before_init — 生成 __before_init__ 函数 -# -# 生成: define void @SHA1.ClassName.__before_init__(Ptr(StructTy) %self) -# -# 执行: -# 1. store zeroinitializer 到 %self(零值填充) -# 2. 逐字段 store 默认值(如有) -# 3. ret void -# ============================================================ -def _generate_before_init(trans: HT.Translator | t.CPtr, - struct_ty: llvmlite.LLVMType | t.CPtr, - class_name: str) -> int: - """生成 __before_init__ 函数,返回 0(委托到 gen._generate_before_init)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._generate_before_init(trans, struct_ty, class_name) - return 0 diff --git a/App/lib/core/Handles/HandlesEnum.vp b/App/lib/core/Handles/HandlesEnum.vp deleted file mode 100644 index e89e7a9..0000000 --- a/App/lib/core/Handles/HandlesEnum.vp +++ /dev/null @@ -1,166 +0,0 @@ -import t, c -from stdint import * -import memhub -import string -import llvmlite -import stdio -import viperlib -import lib.core.VLogger as VLogger -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# HandlesEnum - 枚举类型注册和成员查找(P6 对象化后的委托层) -# -# 全部模块级函数已迁移为 lib.core.Gen.StmtGenMixin 的方法 -# (模块级全局 _enum_table/_enum_count → gen 实例字段 -# EnumTable/EnumCount),本模块保留同名模块级函数作为"一行委托": -# 延迟 import Gen 取全局单例(BuildPipeline/main 创建后 -# set_global_gen 注册),再调用 gen 的对应方法。签名与旧函数 -# 完全一致,调用方零改动。 -# -# EnumEntry/EnumMember 类型保留在本模块(gen 字段类型引用)。 -# 管理 t.CEnum 派生类的成员信息: -# - 枚举名 → EnumEntry(基准类型 + 成员表) -# - 成员名 → EnumMember(值、类型) -# -# 使用全局数组存储,线性查找(枚举数量通常很少) -# ============================================================ - -ENUM_MAX: t.CDefine = 64 -ENUM_MEMBER_MAX: t.CDefine = 128 - - -# ============================================================ -# EnumMember - 枚举成员条目 -# ============================================================ -@t.NoVTable -class EnumMember: - Name: str # 成员名(字符串) - Value: t.CInt64T # 成员的整数值 - Ty: llvmlite.LLVMType | t.CPtr # 成员的 LLVM 类型(用于混用类型场景) - - -# ============================================================ -# EnumEntry - 枚举类型条目 -# ============================================================ -@t.NoVTable -class EnumEntry: - Name: str # 枚举类名 - BaseTy: llvmlite.LLVMType | t.CPtr # 基准类型(所有成员类型中最大的) - MemberCount: int # 成员数量 - Members: EnumMember | t.CPtr # 成员数组(ENUM_MEMBER_MAX 个槽位) - - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式) -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - - -# ============================================================ -# init_enum_table — 初始化枚举注册表 -# ============================================================ -def init_enum_table(pool: memhub.MemBuddy | t.CPtr) -> int: - """初始化枚举注册表,返回 1 成功(委托到 gen.init_enum_table)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.init_enum_table(pool) - return 0 - - -# ============================================================ -# _get_enum_entry — 获取第 i 个 EnumEntry 槽位 -# ============================================================ -def _get_enum_entry(i: int) -> EnumEntry | t.CPtr: - """获取第 i 个枚举条目(委托到 gen._get_enum_entry)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._get_enum_entry(i) - return None - - -# ============================================================ -# _get_enum_member — 获取枚举中第 i 个 EnumMember 槽位 -# ============================================================ -def _get_enum_member(enum_entry: EnumEntry | t.CPtr, i: int) -> EnumMember | t.CPtr: - """获取枚举中第 i 个成员条目(委托到 gen._get_enum_member)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._get_enum_member(enum_entry, i) - return None - - -# ============================================================ -# register_enum — 注册枚举类型 -# -# 返回 EnumEntry 指针,可用于添加成员 -# ============================================================ -def register_enum(pool: memhub.MemBuddy | t.CPtr, - name: str, - base_ty: llvmlite.LLVMType | t.CPtr) -> EnumEntry | t.CPtr: - """注册枚举类型,返回 EnumEntry 指针(委托到 gen.register_enum)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.register_enum(pool, name, base_ty) - return None - - -# ============================================================ -# add_enum_member — 向枚举添加成员 -# ============================================================ -def add_enum_member(pool: memhub.MemBuddy | t.CPtr, - enum_entry: EnumEntry | t.CPtr, - member_name: str, - member_val: t.CInt64T, - member_ty: llvmlite.LLVMType | t.CPtr) -> int: - """向枚举添加成员,返回成员索引(-1 失败,委托到 gen.add_enum_member)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.add_enum_member(pool, enum_entry, member_name, member_val, member_ty) - return 0 - - -# ============================================================ -# find_enum — 按枚举类名查找 -# ============================================================ -def find_enum(name: str) -> EnumEntry | t.CPtr: - """按枚举类名查找,返回 EnumEntry 或 None(委托到 gen.find_enum)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.find_enum(name) - return None - - -# ============================================================ -# lookup_enum_member — 按枚举类名和成员名查找 -# ============================================================ -def lookup_enum_member(enum_name: str, - member_name: str) -> EnumMember | t.CPtr: - """按枚举类名和成员名查找,返回 EnumMember 或 None(委托到 gen.lookup_enum_member)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.lookup_enum_member(enum_name, member_name) - return None - - -# ============================================================ -# is_enum_class — 检查类名是否为已注册枚举 -# ============================================================ -def is_enum_class(name: str) -> int: - """检查类名是否为已注册枚举,返回 1=是 / 0=否(委托到 gen.is_enum_class)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.is_enum_class(name) - return 0 - - -# ============================================================ -# get_enum_base_type — 按枚举类名获取基准类型 -# ============================================================ -def get_enum_base_type(enum_name: str) -> llvmlite.LLVMType | t.CPtr: - """按枚举类名获取基准类型(委托到 gen.get_enum_base_type)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_enum_base_type(enum_name) - return None diff --git a/App/lib/core/Handles/HandlesExpr.vp b/App/lib/core/Handles/HandlesExpr.vp index 7dd1368..27c26a3 100644 --- a/App/lib/core/Handles/HandlesExpr.vp +++ b/App/lib/core/Handles/HandlesExpr.vp @@ -1,951 +1,953 @@ -import t, c -from stdint import * -import ast -import memhub -import string -import llvmlite -import stdlib -import stdio -import viperlib -import w32.fileio as fileio -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.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.VLogger as VLogger -import lib.Projectrans.Config as Config -import lib.Projectrans.Utils as Utils -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# HandlesExpr - 表达式处理(P3 对象化后的委托层) -# -# 全部模块级函数已迁移为 lib.core.Gen.ExprGenMixin 的方法 -# (全局状态迁入 gen 字段),本模块保留同名模块级函数作为 -# "一行委托":延迟 import Gen 取全局单例(BuildPipeline/main -# 创建后 set_global_gen 注册),再调用 gen 的对应方法。签名与 -# 旧函数完全一致,调用方零改动。 -# -# ExprHandle 类及其 NewExprHandle 工厂保留(translator handler 模式)。 -# ============================================================ - - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - - -# ============================================================ -# 委托函数:延迟 import Gen 取全局单例 → 调 gen 方法 -# (gen 未注册时正常流程不会发生;有返回值函数返回默认值) -# ============================================================ - - -# ============================================================ -# 从 AST 节点提取函数名 -# ============================================================ -def get_func_name(func_node: ast.AST | t.CPtr) -> str: - """从函数节点提取函数名(委托到 gen.get_func_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_func_name(func_node) - return None - - -# ============================================================ -# 转义 LLVM IR 字符串字面量 -# ============================================================ -def escape_llvm_string(pool: memhub.MemBuddy | t.CPtr, - src: str) -> str: - """将字符串转换为 LLVM IR 字符串字面量 c"...\\00"(委托到 gen.escape_llvm_string)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.escape_llvm_string(pool, src) - return None - - -# ============================================================ -# 获取 LLVM 整数类型的位宽 -# ============================================================ -def get_llvm_type_bits(ty: llvmlite.LLVMType | t.CPtr) -> int: - """获取 LLVM 整数类型的位宽,非整数类型返回 0(委托到 gen.get_llvm_type_bits)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_llvm_type_bits(ty) - return 0 - - -# ============================================================ -# 获取 LLVM 浮点类型的位宽 -# ============================================================ -def get_llvm_float_bits(ty: llvmlite.LLVMType | t.CPtr) -> int: - """获取 LLVM 浮点类型的位宽,非浮点类型返回 0(委托到 gen.get_llvm_float_bits)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_llvm_float_bits(ty) - return 0 - - -# ============================================================ -# is_ptr_type - 检查类型是否为 Ptr -# -# 返回 1=是, 0=否。作为类型检查工具函数被广泛使用(50+ 处调用)。 -# ============================================================ -def is_ptr_type(ty: llvmlite.LLVMType | t.CPtr) -> int: - """检查 ty 是否是 Ptr 类型,返回 1=是, 0=否(委托到 gen.is_ptr_type)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.is_ptr_type(ty) - return 0 - - -# ============================================================ -# get_ptr_level - 计算指针层级 -# -# 返回值: -# 0 = 非指针(数值/结构体等) -# 1 = 一级指针(如 i8*, Struct*) -# 2 = 二级指针(如 i8**, Struct**) -# 3+ = 更高级指针 -# ============================================================ -def get_ptr_level(ty: llvmlite.LLVMType | t.CPtr) -> int: - """计算指针层级,0=非指针, 1=一级指针, 2=二级指针...(委托到 gen.get_ptr_level)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_ptr_level(ty) - return 0 - - -# ============================================================ -# is_array_type - 检查类型是否为 Array -# -# 返回 1=是, 0=否。类型检查工具函数。 -# ============================================================ -def is_array_type(ty: llvmlite.LLVMType | t.CPtr) -> int: - """检查 ty 是否是 Array 类型,返回 1=是, 0=否(委托到 gen.is_array_type)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.is_array_type(ty) - return 0 - - -# ============================================================ -# _zext_index_to_i32 - 数组下标索引零扩展 -# -# LLVM GEP 对窄整数索引默认符号扩展:i8 0xE2(226) 会被当成 -30, -# 导致数组下标越界读(字节 >= 128 的乱码根因)。 -# 数组下标语义为非负,<32 位整数索引一律 zext 到 i32。 -# ============================================================ -def _zext_index_to_i32(builder: llvmlite.IRBuilder | t.CPtr, - idx_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: - """将 <32 位整数下标零扩展到 i32(数组下标非负语义)(委托到 gen._zext_index_to_i32)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._zext_index_to_i32(builder, idx_val) - return None - - -# ============================================================ -# _get_custom_struct_cls_nm - 检查类型是否为已注册的自定义结构体 -# -# 处理两种情况: -# - ty 直接是 Struct → 检查是否注册 -# - ty 是 Ptr(Struct) → 检查 pointee 是否注册 -# ============================================================ -def _get_custom_struct_cls_nm(pool: memhub.MemBuddy | t.CPtr, - ty: llvmlite.LLVMType | t.CPtr) -> str: - """检查 ty 或 ty 的 pointee 是否是已注册的自定义结构体,返回类名或 None(委托到 gen._get_custom_struct_cls_nm)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._get_custom_struct_cls_nm(pool, ty) - return None - - -# ============================================================ -# _is_list_subscript_base - 判断下标基座是否为 list[T] 变量 -# ============================================================ -def _is_list_subscript_base(pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - sub_node: ast.AST | t.CPtr) -> int: - """判断下标基座是否为 list[T] 变量(1=是)(委托到 gen._is_list_subscript_base)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_list_subscript_base(pool, trans, sub_node) - return 0 - - -# ============================================================ -# _sub_base_class_name - 解析下标基座变量的结构体类名 -# ============================================================ -def _sub_base_class_name(pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - sub_node: ast.AST | t.CPtr) -> str: - """解析下标基座变量的结构体类名(无则 None)(委托到 gen._sub_base_class_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._sub_base_class_name(pool, trans, sub_node) - return None - - -# ============================================================ -# _sub_base_uses_getitem - 下标基座是否应走 __getitem__ 语义 -# ============================================================ -def _sub_base_uses_getitem(pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - trans: HT.Translator | t.CPtr, - sub_node: ast.AST | t.CPtr) -> int: - """下标基座应走 __getitem__ 语义时返回 1,否则 0(应走 GEP 地址语义)(委托到 gen._sub_base_uses_getitem)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._sub_base_uses_getitem(pool, mod, trans, sub_node) - return 0 - - -# ============================================================ -# _deref_if_ptr_ptr - 如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用 -# ============================================================ -def _deref_if_ptr_ptr(builder: llvmlite.IRBuilder | t.CPtr, - obj_ptr: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: - """如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用获取内层指针(委托到 gen._deref_if_ptr_ptr)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._deref_if_ptr_ptr(builder, obj_ptr) - return None - - -# ============================================================ -# 类型强制转换:整数 sext/trunc,浮点 fpext/fptrunc,int↔float si2fp/fp2si -# ============================================================ -def coerce_to_type(builder: llvmlite.IRBuilder | t.CPtr, - val: llvmlite.Value | t.CPtr, - target_ty: llvmlite.LLVMType | t.CPtr, - node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """将 val 强制转换为 target_ty(委托到 gen.coerce_to_type)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.coerce_to_type(builder, val, target_ty, node) - return None - - -# ============================================================ -# translate_ptr_arith - 指针算术: ptr + int / ptr - int -# -# 用 getelementptr(按 pointee 元素大小缩放索引),对齐 TPC -# ExprGen.emit_binary_op / HandlesAugAssign.py。 -# ============================================================ -def translate_ptr_arith(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - ptr_val: llvmlite.Value | t.CPtr, - int_val: llvmlite.Value | t.CPtr, - op: int) -> llvmlite.Value | t.CPtr: - """指针算术: ptr + int / ptr - int → GEP(按元素大小缩放索引)(委托到 gen.translate_ptr_arith)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_ptr_arith(pool, builder, ptr_val, int_val, op) - return None - - -# ============================================================ -# 创建全局字符串常量 -# ============================================================ -def create_global_string(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - str_val: str, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """创建全局字符串常量并返回 i8* bitcast(委托到 gen.create_global_string)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.create_global_string(builder, pool, mod, str_val, trans) - return None - - -# ============================================================ -# 模块引用 AST → 模块路径字符串(递归拼接 Attribute 链) -# ============================================================ -def attr_module_path_str(pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr) -> str: - """把模块引用 AST 转成模块路径字符串(Name('sys')→"sys"、 - Attribute(Attribute(Name('os'),'_win32'))→"os._win32";非模块引用形态返回 None) - - 跨 mixin 委托:CallGenMixin 等不能 self. 直接调用 ExprGenMixin 的方法 - (@t.NoVTable 静态绑定会 mangle 成当前类名 → undefined reference)。 - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._attr_module_path_str(pool, node) - return None - - -# ============================================================ -# 翻译常量表达式 -# ============================================================ -def translate_constant(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译常量(int/str/bool)(委托到 gen.translate_constant)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_constant(builder, pool, mod, node, trans) - return None - - -# ============================================================ -# _infer_elem_type_from_value — 从 LLVM Value 推断 list 元素类型名 -# ============================================================ -def _infer_elem_type_from_value(pool: memhub.MemBuddy | t.CPtr, - value: llvmlite.Value | t.CPtr) -> str: - """从 LLVM Value 的类型推断 list 元素类型名(委托到 gen._infer_elem_type_from_value)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._infer_elem_type_from_value(pool, value) - return None - - -# ============================================================ -# _find_pool_var — 查找上下文中的 pool 变量 -# -# 依次尝试 "pool", "_mbuddy", "mbuddy", "mb" -# ============================================================ -def _find_pool_var(trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """查找上下文中的 pool 变量,返回 alloca 或 None(委托到 gen._find_pool_var)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._find_pool_var(trans) - return None - - -# ============================================================ -# translate_list_literal — 翻译 list 字面量 [a, b, c] -# -# 将 list 字面量翻译为 list[T](pool) 构造 + append 调用序列 -# ============================================================ -def translate_list_literal(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - elem_type_name: str, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """翻译 list 字面量 [a, b, c] → list[T](pool) + append 序列(委托到 gen.translate_list_literal)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_list_literal(builder, pool, mod, node, elem_type_name, trans) - return None - - -# ============================================================ -# 翻译值表达式(RHS 分派)— 模块级版本 -# ============================================================ -def translate_value(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - funcs_ptr: t.CPtr = None, - func_count: int = 0, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译值表达式为 LLVM Value(委托到 gen.translate_value)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_value(builder, pool, mod, node, funcs_ptr, func_count, trans) - return None - - -# ============================================================ -# 翻译 lambda 表达式 — 模块级委托 -# -# translate_lambda 定义在 FuncGenMixin(跨 Mixin 方法),ExprGenMixin -# 不能 self. 直接调用(NoVTable 下方法 mangle 成定义类符号,跨 Mixin -# self 调用会解析失败),与 translate_value 同模式走模块级委托。 -# ============================================================ -def translate_lambda(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译 lambda 表达式,返回闭包指针(i8*)(委托到 gen.translate_lambda)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_lambda(builder, pool, mod, node, trans) - return None - - -# ============================================================ -# 翻译三元表达式 IfExp(test, body, orelse) -# ============================================================ -def translate_ifexp(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译三元表达式 (body if test else orelse),返回 phi 结果 Value(委托到 gen.translate_ifexp)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_ifexp(builder, pool, mod, node, trans) - return None - - -# ============================================================ -# 翻译比较表达式 Compare(left, ops, comparators) -# ============================================================ -def should_zext_widen(pool: memhub.MemBuddy | t.CPtr, - narrow_val: llvmlite.Value | t.CPtr, - wide_val: llvmlite.Value | t.CPtr, - narrow_node: ast.AST | t.CPtr = None) -> int: - """判断整数拓宽方向:1=zext(无符号语义),0=sext(委托到 gen.should_zext_widen)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.should_zext_widen(pool, narrow_val, wide_val, narrow_node) - return 0 - - -def _node_type_unsigned(pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> int: - """轻量判断 AST 节点是否解析为无符号整数类型(1=是,0=否/未知)(委托到 gen._node_type_unsigned)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._node_type_unsigned(pool, node, trans) - return 0 - - -def _type_name_unsigned(type_name: str) -> int: - """类型名是否为无符号整数类型(精确匹配,避免子串误伤如 nUIntCount)(委托到 gen._type_name_unsigned)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._type_name_unsigned(type_name) - return 0 - - -def translate_compare(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译比较表达式,返回 i1 结果(委托到 gen.translate_compare)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_compare(builder, pool, mod, node, trans) - return None - - -# ============================================================ -# 翻译一元运算表达式 UnaryOp(op, operand) -# ============================================================ -def translate_unaryop(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译一元运算(-x, +x, not x, ~x)(委托到 gen.translate_unaryop)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_unaryop(builder, pool, mod, node, trans) - return None - - -# ============================================================ -# 翻译布尔运算 BoolOp(op, values) — 短路求值,返回 i1 -# ============================================================ -def translate_boolop(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - funcs_ptr: t.CPtr = None, - func_count: int = 0, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译布尔运算(and/or)的短路求值,返回 i1(委托到 gen.translate_boolop)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_boolop(builder, pool, mod, node, funcs_ptr, func_count, trans) - return None - - -# ============================================================ -# _build_source_path_from_sha1 - 通过 SHA1 从存储器构建源 .vp/.py 文件路径 -# ============================================================ -def _build_source_path_from_sha1(sha1: str) -> str: - """通过 SHA1 从全局存储器构建源 .py 文件路径(委托到 gen._build_source_path_from_sha1)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._build_source_path_from_sha1(sha1) - return None - - -# ============================================================ -# _lookup_cross_module_cdefine - 跨模块查找 CDefine 常量 -# ============================================================ -def _lookup_cross_module_cdefine(pool: memhub.MemBuddy | t.CPtr, - name: str, - from_imports: str, - imported_modules: str = None, - depth: int = 0, - node: ast.AST | t.CPtr = None) -> t.CInt64T: - """跨模块查找 CDefine 常量,返回值(64 位)或 -1(未找到)(委托到 gen._lookup_cross_module_cdefine)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._lookup_cross_module_cdefine(pool, name, from_imports, imported_modules, depth, node) - return 0 - - -# ============================================================ -# _is_cdefine_name_pattern - 检查名字是否符合 CDefine 命名约定 -# ============================================================ -def _is_cdefine_name_pattern(name: str) -> int: - """检查名字是否符合 CDefine 命名约定(全大写+下划线+数字)(委托到 gen._is_cdefine_name_pattern)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_cdefine_name_pattern(name) - return 0 - - -# ============================================================ -# 翻译变量引用(Name 节点)→ load -# ============================================================ -def translate_name_value(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译变量引用(Name 节点)→ load(委托到 gen.translate_name_value)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_name_value(builder, pool, node, trans) - return None - - -# ============================================================ -# ExprHandle - 表达式处理器(Mixin 继承模式) -# -# HandleValue 提供 trans 接口,委托到模块级 translate_value -# ============================================================ -@t.NoVTable -class ExprHandle(HandlesBase.Mixin): - """表达式处理器:继承 Mixin 获得 Trans 回指针""" - - def __init__(self, trans: HT.Translator | t.CPtr): - self.Trans = trans - - # ============================================================ - # HandleValue - 翻译值表达式为 LLVM Value - # ============================================================ - def HandleValue(self, node: ast.AST | t.CPtr) -> llvmlite.Value | t.CPtr: - """翻译值表达式,从 self.Trans 获取共享状态""" - return translate_value( - self.Trans._cur_builder, self.Trans.Pool, self.Trans.Module, - node, - self.Trans._funcs, self.Trans._func_count, self.Trans) - - -# ============================================================ -# NewExprHandle - 工厂函数 -# ============================================================ -def NewExprHandle(pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr) -> ExprHandle | t.CPtr: - h: ExprHandle | t.CPtr = pool.alloc(ExprHandle.__sizeof__()) - if h is None: - return None - string.memset(h, 0, ExprHandle.__sizeof__()) - h.Trans = trans - return h - - -# ============================================================ -# list_getitem_inline — 内联生成 list[T] __getitem__ 逻辑 -# -# list 结构布局 (6 字段 × 8 字节): -# __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40) -# 返回元素地址 (i8*),调用方根据元素类型 load 正确的值 -# ============================================================ -def list_getitem_inline(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - lm_obj: llvmlite.Value | t.CPtr, - idx_val: llvmlite.Value | t.CPtr, - node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """内联生成 list __getitem__ 逻辑,返回元素地址 (i8*)(委托到 gen.list_getitem_inline)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.list_getitem_inline(builder, pool, lm_obj, idx_val, node) - return None - - -# ============================================================ -# _list_elem_type_from_name — 从 list 类型名提取元素 LLVM 类型 -# ============================================================ -def _list_elem_type_from_name(pool: memhub.MemBuddy | t.CPtr, - struct_name: str) -> llvmlite.LLVMType | t.CPtr: - """从 list 类型名提取元素 LLVM 类型(委托到 gen._list_elem_type_from_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._list_elem_type_from_name(pool, struct_name) - return None - - -# ============================================================ -# list_setitem_inline — 内联生成 list[T] __setitem__ 逻辑 -# ============================================================ -def list_setitem_inline(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - lm_obj: llvmlite.Value | t.CPtr, - idx_val: llvmlite.Value | t.CPtr, - rhs_val: llvmlite.Value | t.CPtr, - node: ast.AST | t.CPtr = None) -> int: - """内联生成 list __setitem__ 逻辑,返回 0(委托到 gen.list_setitem_inline)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.list_setitem_inline(builder, pool, lm_obj, idx_val, rhs_val, node) - return 0 - - -# ============================================================ -# is_list_subscript — 检查 Subscript 节点是否是 list[T] 类型 -# -# 返回 list 对象指针 (Ptr(list[T])) 或 None -# ============================================================ -def is_list_subscript(node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """检查 Subscript 节点是否是 list[T] 类型,返回 list 对象指针或 None(委托到 gen.is_list_subscript)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.is_list_subscript(node, trans) - return None - - -# ============================================================ -# 翻译下标表达式 Subscript(value, slice, ctx) — ptr[i] / arr[i] -# ============================================================ -def translate_subscript(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译下标表达式,返回加载的元素值(委托到 gen.translate_subscript)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_subscript(builder, pool, mod, node, trans) - return None - - -# ============================================================ -# find_global_in_module - 在模块全局变量链表中按名称查找 -# -# 查找策略: -# 1. 精确匹配 (如 "_mbuddy" 匹配 @_mbuddy) -# 2. 后缀匹配 (如 "_mbuddy" 匹配 @"sha1._mbuddy") -# ============================================================ -def find_global_in_module(mod: llvmlite.LLVMModule | t.CPtr, - name: str) -> llvmlite.GlobalVariable | t.CPtr: - """在模块全局变量链表中按名称查找全局变量(委托到 gen.find_global_in_module)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.find_global_in_module(mod, name) - return None - - -# ============================================================ -# make_global_ref - 创建全局变量引用 (@name,类型为 ty*) -# ============================================================ -def make_global_ref(pool: memhub.MemBuddy | t.CPtr, - name: str, - ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: - """创建全局变量引用 (类型为 ty*,名称为 @name)(委托到 gen.make_global_ref)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.make_global_ref(pool, name, ty) - return None - - -# ============================================================ -# _is_t_type_object_name - 检查 name 是否是 t.py 中的类型对象名 -# ============================================================ -def _is_t_type_object_name(name: str) -> int: - """检查 name 是否是 t.py 中的类型对象名(CPtr/CInt/CDouble 等)(委托到 gen._is_t_type_object_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_t_type_object_name(name) - return 0 - - -# ============================================================ -# _resolve_module_attribute_global - 解析模块属性访问的全局变量引用 -# ============================================================ -def _resolve_module_attribute_global(pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - trans: HT.Translator | t.CPtr, - at: ast.Attribute | t.CPtr, - ty_hint: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: - """解析模块属性访问,返回全局变量引用 (用于跨模块 global 访问)(委托到 gen._resolve_module_attribute_global)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._resolve_module_attribute_global(pool, mod, trans, at, ty_hint) - return None - - -# ============================================================ -# _get_cderef_attr_base - c.Deref(ptr).attr 属性访问的 base 指针 -# ============================================================ -def _get_cderef_attr_base(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - at_value: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """检测 at.value 是否为 c.Deref(ptr) 调用,返回 ptr 指针(不做 load)(委托到 gen._get_cderef_attr_base)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._get_cderef_attr_base(builder, pool, mod, at_value, trans) - return None - - -# ============================================================ -# 翻译属性访问 Attribute(value, attr, ctx) — obj.field -# ============================================================ -def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译属性访问,返回加载的字段值(委托到 gen.translate_attribute)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_attribute(builder, pool, mod, node, trans) - return None - - -# ============================================================ -# 获取下标表达式的元素指针(不加载值,用于赋值) -# ============================================================ -def get_subscript_ptr(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """获取下标表达式的元素指针(用于赋值 lhs)(委托到 gen.get_subscript_ptr)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_subscript_ptr(builder, pool, mod, node, trans) - return None - - -# ============================================================ -# 获取属性访问的字段指针(不加载值,用于赋值) -# ============================================================ -def get_attribute_ptr(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """获取属性访问的字段指针(用于赋值 lhs)(委托到 gen.get_attribute_ptr)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_attribute_ptr(builder, pool, mod, node, trans) - return None - - -# ============================================================ -# 翻译 f-string(JoinedStr → snprintf 生成 i8* 栈缓冲)— 模块级委托 -# ============================================================ -def translate_joined_str(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译 f-string(委托到 gen.translate_joined_str,定义于 ExprGenFstr)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_joined_str(builder, pool, mod, node, trans) - return None - - -# ============================================================ -# 翻译裸 FormattedValue(f"{expr:spec}" 无字面量)— 模块级委托 -# ============================================================ -def translate_formatted_value(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译裸 FormattedValue(委托到 gen.translate_formatted_value,定义于 ExprGenFstr)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_formatted_value(builder, pool, mod, node, trans) - return None - - -# ============================================================ -# CDefine 整数常量 → LLVM 常量(64 位升级规则)— 模块级委托 -# ============================================================ -def _const_int_for_cdefine(pool: memhub.MemBuddy | t.CPtr, - value: t.CInt64T) -> llvmlite.Value | t.CPtr: - """CDefine 整数常量 → LLVM 常量(委托到 gen._const_int_for_cdefine,定义于 ExprGenCdef)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._const_int_for_cdefine(pool, value) - return None - - -# ============================================================ -# 解析嵌套 Attribute 链的 docstring 归属 — 模块级委托 -# ============================================================ -def _resolve_doc_symbol_attr(trans: HT.Translator | t.CPtr, - at: ast.Attribute | t.CPtr, - out_mod: str | t.CPtr, out_sym: str | t.CPtr) -> int: - """解析嵌套 Attribute 链的 docstring 归属(委托到 gen._resolve_doc_symbol_attr,定义于 ExprGenCls)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._resolve_doc_symbol_attr(trans, at, out_mod, out_sym) - return 0 - - -# ============================================================ -# 解析 Name 符号的 docstring 归属 — 模块级委托 -# ============================================================ -def _resolve_doc_symbol_name(trans: HT.Translator | t.CPtr, name_id: str, - out_mod: str | t.CPtr, out_sym: str | t.CPtr) -> int: - """解析 Name 符号的 docstring 归属(委托到 gen._resolve_doc_symbol_name,定义于 ExprGenCls)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._resolve_doc_symbol_name(trans, name_id, out_mod, out_sym) - return 0 - - -# ============================================================ -# 查找 docstring 内容(key="{module_sha1}.{symbol}")— 模块级委托 -# ============================================================ -def lookup_docstring(module_sha1: str, symbol: str) -> str: - """查找 docstring 内容(委托到 gen.lookup_docstring,定义于 ExprGenCls)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.lookup_docstring(module_sha1, symbol) - return None - - -# ============================================================ -# 解析属性链(a.b.c)中 c 字段的注解类名 — 模块级委托 -# ============================================================ -def _resolve_attr_field_class(pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - attr_node: ast.AST | t.CPtr) -> str: - """解析属性链最终字段的注解类名(委托到 gen._resolve_attr_field_class,定义于 ExprGenAttr)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._resolve_attr_field_class(pool, trans, attr_node) - return None - - -# ============================================================ -# 翻译二元运算(自动类型提升)— 模块级委托 -# ============================================================ -def translate_binop(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译二元运算(委托到 gen.translate_binop,定义于 ExprGenOps)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_binop(pool, builder, mod, node, trans) - return None - - -# ============================================================ -# binop op → dunder 方法名(如 Add → "__add__")— 模块级委托 -# ============================================================ -def _binop_to_dunder(op: int) -> str: - """binop op → dunder 方法名(委托到 gen._binop_to_dunder,定义于 ExprGenOps)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._binop_to_dunder(op) - return None - - -# ============================================================ -# unaryop op → dunder 方法名(如 USub → "__neg__")— 模块级委托 -# ============================================================ -def _unaryop_to_dunder(op: int) -> str: - """unaryop op → dunder 方法名(委托到 gen._unaryop_to_dunder,定义于 ExprGenOps)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._unaryop_to_dunder(op) - return None - - -# ============================================================ -# f-string 尾部:全局格式串 + 固定栈缓冲 + snprintf — 模块级委托 -# ============================================================ -def _fstr_finalize(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - fmt_buf: str, - arg_head: llvmlite.Value | t.CPtr, - arg_tail: llvmlite.Value | t.CPtr, - arg_count: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """f-string 尾部(委托到 gen._fstr_finalize,定义于 ExprGenFstr)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._fstr_finalize(builder, pool, mod, fmt_buf, arg_head, arg_tail, arg_count, trans) - return None - - -# ============================================================ -# 追加字面量到格式串(% 转义)— 模块级委托 -# ============================================================ -def _fstr_append_literal(fmt_buf: str, lit: str) -> None: - """追加字面量到格式串(委托到 gen._fstr_append_literal,定义于 ExprGenFstr)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g._fstr_append_literal(fmt_buf, lit) - - -# ============================================================ -# Python format_spec → C printf 格式串 — 模块级委托 -# ============================================================ -def _fstr_parse_format_spec(pool: memhub.MemBuddy | t.CPtr, - spec_node: ast.AST | t.CPtr, - val: llvmlite.Value | t.CPtr, - arg_node: ast.AST | t.CPtr) -> str: - """Python format_spec → C printf 格式串(委托到 gen._fstr_parse_format_spec,定义于 ExprGenFstr)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._fstr_parse_format_spec(pool, spec_node, val, arg_node) - return None - - -# ============================================================ -# 无 format_spec 时按值类型推断 C printf 格式 — 模块级委托 -# ============================================================ -def _fstr_infer_c_fmt(pool: memhub.MemBuddy | t.CPtr, - val: llvmlite.Value | t.CPtr, - arg_node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr) -> str: - """按值类型推断 C printf 格式(委托到 gen._fstr_infer_c_fmt,定义于 ExprGenFstr)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._fstr_infer_c_fmt(pool, val, arg_node, trans) - return None - - -# ============================================================ -# 按 C 格式转换值类型(i8/i16→i32、bool→i32、f32→f64)— 模块级委托 -# ============================================================ -def _fstr_cast_value(builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - val: llvmlite.Value | t.CPtr, - c_fmt: str, - arg_node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """按 C 格式转换值类型(委托到 gen._fstr_cast_value,定义于 ExprGenFstr)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._fstr_cast_value(builder, pool, val, c_fmt, arg_node, trans) - return None +import lib.core.Gen.ExprGenAttr as ExprGenAttr +import lib.core.Gen.ExprGenBase as ExprGenBase +import lib.core.Gen.ExprGenCdef as ExprGenCdef +import lib.core.Gen.ExprGenCls as ExprGenCls +import lib.core.Gen.ExprGenConst as ExprGenConst +import lib.core.Gen.ExprGenFstr as ExprGenFstr +import lib.core.Gen.ExprGenMixin as ExprGenMixin +import lib.core.Gen.ExprGenName as ExprGenName +import lib.core.Gen.ExprGenOps as ExprGenOps +import lib.core.Gen.FuncGenMixin as FuncGenMixin +import t, c +from stdint import * +import ast +import memhub +import string +import llvmlite +import stdlib +import stdio +import viperlib +import w32.fileio as fileio +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.StubMerger as StubMerger +import lib.core.VLogger as VLogger +import lib.Projectrans.Config as Config +import lib.Projectrans.Utils as Utils +import lib.core.Gen.Generator as Generator + + +# ============================================================ +# HandlesExpr - 表达式处理(P3 对象化后的委托层) +# +# 全部模块级函数已迁移为 lib.core.Gen.ExprGenMixin 的方法 +# (全局状态迁入 gen 字段),本模块保留同名模块级函数作为 +# "一行委托":延迟 import Gen 取全局单例(BuildPipeline/main +# 创建后 set_global_gen 注册),再调用 gen 的对应方法。签名与 +# 旧函数完全一致,调用方零改动。 +# +# ExprHandle 类及其 NewExprHandle 工厂保留(translator handler 模式)。 +# ============================================================ + + +# ============================================================ +# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) +# ============================================================ +_g_gen: Generator.Generator | t.CPtr = None + + +# ============================================================ +# 委托函数:延迟 import Gen 取全局单例 → 调 gen 方法 +# (gen 未注册时正常流程不会发生;有返回值函数返回默认值) +# ============================================================ + + +# ============================================================ +# 从 AST 节点提取函数名 +# ============================================================ +def get_func_name(func_node: ast.AST | t.CPtr) -> str: + """从函数节点提取函数名(委托到 gen.get_func_name)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenBase.get_func_name(func_node) + return None + + +# ============================================================ +# 转义 LLVM IR 字符串字面量 +# ============================================================ +def escape_llvm_string(pool: memhub.MemBuddy | t.CPtr, + src: str) -> str: + """将字符串转换为 LLVM IR 字符串字面量 c"...\\00"(委托到 gen.escape_llvm_string)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenBase.escape_llvm_string(pool, src) + return None + + +# ============================================================ +# 获取 LLVM 整数类型的位宽 +# ============================================================ +def get_llvm_type_bits(ty: llvmlite.LLVMType | t.CPtr) -> int: + """获取 LLVM 整数类型的位宽,非整数类型返回 0(委托到 gen.get_llvm_type_bits)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenBase.get_llvm_type_bits(ty) + return 0 + + +# ============================================================ +# 获取 LLVM 浮点类型的位宽 +# ============================================================ +def get_llvm_float_bits(ty: llvmlite.LLVMType | t.CPtr) -> int: + """获取 LLVM 浮点类型的位宽,非浮点类型返回 0(委托到 gen.get_llvm_float_bits)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenBase.get_llvm_float_bits(ty) + return 0 + + +# ============================================================ +# is_ptr_type - 检查类型是否为 Ptr +# +# 返回 1=是, 0=否。作为类型检查工具函数被广泛使用(50+ 处调用)。 +# ============================================================ +def is_ptr_type(ty: llvmlite.LLVMType | t.CPtr) -> int: + """检查 ty 是否是 Ptr 类型,返回 1=是, 0=否(委托到 gen.is_ptr_type)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenBase.is_ptr_type(ty) + return 0 + + +# ============================================================ +# get_ptr_level - 计算指针层级 +# +# 返回值: +# 0 = 非指针(数值/结构体等) +# 1 = 一级指针(如 i8*, Struct*) +# 2 = 二级指针(如 i8**, Struct**) +# 3+ = 更高级指针 +# ============================================================ +def get_ptr_level(ty: llvmlite.LLVMType | t.CPtr) -> int: + """计算指针层级,0=非指针, 1=一级指针, 2=二级指针...(委托到 gen.get_ptr_level)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenBase.get_ptr_level(ty) + return 0 + + +# ============================================================ +# is_array_type - 检查类型是否为 Array +# +# 返回 1=是, 0=否。类型检查工具函数。 +# ============================================================ +def is_array_type(ty: llvmlite.LLVMType | t.CPtr) -> int: + """检查 ty 是否是 Array 类型,返回 1=是, 0=否(委托到 gen.is_array_type)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenBase.is_array_type(ty) + return 0 + + +# ============================================================ +# _zext_index_to_i32 - 数组下标索引零扩展 +# +# LLVM GEP 对窄整数索引默认符号扩展:i8 0xE2(226) 会被当成 -30, +# 导致数组下标越界读(字节 >= 128 的乱码根因)。 +# 数组下标语义为非负,<32 位整数索引一律 zext 到 i32。 +# ============================================================ +def _zext_index_to_i32(builder: llvmlite.IRBuilder | t.CPtr, + idx_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: + """将 <32 位整数下标零扩展到 i32(数组下标非负语义)(委托到 gen._zext_index_to_i32)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenBase._zext_index_to_i32(builder, idx_val) + return None + + +# ============================================================ +# _get_custom_struct_cls_nm - 检查类型是否为已注册的自定义结构体 +# +# 处理两种情况: +# - ty 直接是 Struct → 检查是否注册 +# - ty 是 Ptr(Struct) → 检查 pointee 是否注册 +# ============================================================ +def _get_custom_struct_cls_nm(pool: memhub.MemBuddy | t.CPtr, + ty: llvmlite.LLVMType | t.CPtr) -> str: + """检查 ty 或 ty 的 pointee 是否是已注册的自定义结构体,返回类名或 None(委托到 gen._get_custom_struct_cls_nm)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenBase._get_custom_struct_cls_nm(pool, ty) + return None + + +# ============================================================ +# _is_list_subscript_base - 判断下标基座是否为 list[T] 变量 +# ============================================================ +def _is_list_subscript_base(pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr, + sub_node: ast.AST | t.CPtr) -> int: + """判断下标基座是否为 list[T] 变量(1=是)(委托到 gen._is_list_subscript_base)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenBase._is_list_subscript_base(pool, trans, sub_node) + return 0 + + +# ============================================================ +# _sub_base_class_name - 解析下标基座变量的结构体类名 +# ============================================================ +def _sub_base_class_name(pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr, + sub_node: ast.AST | t.CPtr) -> str: + """解析下标基座变量的结构体类名(无则 None)(委托到 gen._sub_base_class_name)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenBase._sub_base_class_name(pool, trans, sub_node) + return None + + +# ============================================================ +# _sub_base_uses_getitem - 下标基座是否应走 __getitem__ 语义 +# ============================================================ +def _sub_base_uses_getitem(pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + trans: HT.Translator | t.CPtr, + sub_node: ast.AST | t.CPtr) -> int: + """下标基座应走 __getitem__ 语义时返回 1,否则 0(应走 GEP 地址语义)(委托到 gen._sub_base_uses_getitem)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenBase._sub_base_uses_getitem(pool, mod, trans, sub_node) + return 0 + + +# ============================================================ +# _deref_if_ptr_ptr - 如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用 +# ============================================================ +def _deref_if_ptr_ptr(builder: llvmlite.IRBuilder | t.CPtr, + obj_ptr: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: + """如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用获取内层指针(委托到 gen._deref_if_ptr_ptr)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenBase._deref_if_ptr_ptr(builder, obj_ptr) + return None + + +# ============================================================ +# 类型强制转换:整数 sext/trunc,浮点 fpext/fptrunc,int↔float si2fp/fp2si +# ============================================================ +def coerce_to_type(builder: llvmlite.IRBuilder | t.CPtr, + val: llvmlite.Value | t.CPtr, + target_ty: llvmlite.LLVMType | t.CPtr, + node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """将 val 强制转换为 target_ty(委托到 gen.coerce_to_type)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenBase.coerce_to_type(builder, val, target_ty, node) + return None + + +# ============================================================ +# translate_ptr_arith - 指针算术: ptr + int / ptr - int +# +# 用 getelementptr(按 pointee 元素大小缩放索引),对齐 TPC +# ExprGen.emit_binary_op / HandlesAugAssign.py。 +# ============================================================ +def translate_ptr_arith(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + ptr_val: llvmlite.Value | t.CPtr, + int_val: llvmlite.Value | t.CPtr, + op: int) -> llvmlite.Value | t.CPtr: + """指针算术: ptr + int / ptr - int → GEP(按元素大小缩放索引)(委托到 gen.translate_ptr_arith)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenBase.translate_ptr_arith(pool, builder, ptr_val, int_val, op) + return None + + +# ============================================================ +# 创建全局字符串常量 +# ============================================================ +def create_global_string(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + str_val: str, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """创建全局字符串常量并返回 i8* bitcast(委托到 gen.create_global_string)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenConst.create_global_string(builder, pool, mod, str_val, trans) + return None + + +# ============================================================ +# 模块引用 AST → 模块路径字符串(递归拼接 Attribute 链) +# ============================================================ +def attr_module_path_str(pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr) -> str: + """把模块引用 AST 转成模块路径字符串(Name('sys')→"sys"、 + Attribute(Attribute(Name('os'),'_win32'))→"os._win32";非模块引用形态返回 None) + + 跨 mixin 委托:CallGenMixin 等不能 self. 直接调用 ExprGenMixin 的方法 + (@t.NoVTable 静态绑定会 mangle 成当前类名 → undefined reference)。 + """ + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenAttr._attr_module_path_str(pool, node) + return None + + +# ============================================================ +# 翻译常量表达式 +# ============================================================ +def translate_constant(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译常量(int/str/bool)(委托到 gen.translate_constant)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenConst.translate_constant(builder, pool, mod, node, trans) + return None + + +# ============================================================ +# _infer_elem_type_from_value — 从 LLVM Value 推断 list 元素类型名 +# ============================================================ +def _infer_elem_type_from_value(pool: memhub.MemBuddy | t.CPtr, + value: llvmlite.Value | t.CPtr) -> str: + """从 LLVM Value 的类型推断 list 元素类型名(委托到 gen._infer_elem_type_from_value)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenConst._infer_elem_type_from_value(pool, value) + return None + + +# ============================================================ +# _find_pool_var — 查找上下文中的 pool 变量 +# +# 依次尝试 "pool", "_mbuddy", "mbuddy", "mb" +# ============================================================ +def _find_pool_var(trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """查找上下文中的 pool 变量,返回 alloca 或 None(委托到 gen._find_pool_var)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenConst._find_pool_var(trans) + return None + + +# ============================================================ +# translate_list_literal — 翻译 list 字面量 [a, b, c] +# +# 将 list 字面量翻译为 list[T](pool) 构造 + append 调用序列 +# ============================================================ +def translate_list_literal(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + elem_type_name: str, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """翻译 list 字面量 [a, b, c] → list[T](pool) + append 序列(委托到 gen.translate_list_literal)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenConst.translate_list_literal(builder, pool, mod, node, elem_type_name, trans) + return None + + +# ============================================================ +# 翻译值表达式(RHS 分派)— 模块级版本 +# ============================================================ +def translate_value(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + funcs_ptr: t.CPtr = None, + func_count: int = 0, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译值表达式为 LLVM Value(委托到 gen.translate_value)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGen.translate_value(builder, pool, mod, node, funcs_ptr, func_count, trans) + return None + + +# ============================================================ +# 翻译 lambda 表达式 — 模块级委托 +# +# translate_lambda 定义在 FuncGenMixin(跨 Mixin 方法),ExprGenMixin +# 不能 self. 直接调用(NoVTable 下方法 mangle 成定义类符号,跨 Mixin +# self 调用会解析失败),与 translate_value 同模式走模块级委托。 +# ============================================================ +def translate_lambda(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译 lambda 表达式,返回闭包指针(i8*)(委托到 gen.translate_lambda)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.FuncGen.translate_lambda(builder, pool, mod, node, trans) + return None + + +# ============================================================ +# 翻译三元表达式 IfExp(test, body, orelse) +# ============================================================ +def translate_ifexp(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译三元表达式 (body if test else orelse),返回 phi 结果 Value(委托到 gen.translate_ifexp)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenOps.translate_ifexp(builder, pool, mod, node, trans) + return None + + +# ============================================================ +# 翻译比较表达式 Compare(left, ops, comparators) +# ============================================================ +def should_zext_widen(pool: memhub.MemBuddy | t.CPtr, + narrow_val: llvmlite.Value | t.CPtr, + wide_val: llvmlite.Value | t.CPtr, + narrow_node: ast.AST | t.CPtr = None) -> int: + """判断整数拓宽方向:1=zext(无符号语义),0=sext(委托到 gen.should_zext_widen)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenOps.should_zext_widen(pool, narrow_val, wide_val, narrow_node) + return 0 + + +def _node_type_unsigned(pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> int: + """轻量判断 AST 节点是否解析为无符号整数类型(1=是,0=否/未知)(委托到 gen._node_type_unsigned)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenOps._node_type_unsigned(pool, node, trans) + return 0 + + +def _type_name_unsigned(type_name: str) -> int: + """类型名是否为无符号整数类型(精确匹配,避免子串误伤如 nUIntCount)(委托到 gen._type_name_unsigned)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenOps._type_name_unsigned(type_name) + return 0 + + +def translate_compare(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译比较表达式,返回 i1 结果(委托到 gen.translate_compare)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenOps.translate_compare(builder, pool, mod, node, trans) + return None + + +# ============================================================ +# 翻译一元运算表达式 UnaryOp(op, operand) +# ============================================================ +def translate_unaryop(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译一元运算(-x, +x, not x, ~x)(委托到 gen.translate_unaryop)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenOps.translate_unaryop(builder, pool, mod, node, trans) + return None + + +# ============================================================ +# 翻译布尔运算 BoolOp(op, values) — 短路求值,返回 i1 +# ============================================================ +def translate_boolop(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + funcs_ptr: t.CPtr = None, + func_count: int = 0, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译布尔运算(and/or)的短路求值,返回 i1(委托到 gen.translate_boolop)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenOps.translate_boolop(builder, pool, mod, node, funcs_ptr, func_count, trans) + return None + + +# ============================================================ +# _build_source_path_from_sha1 - 通过 SHA1 从存储器构建源 .vp/.py 文件路径 +# ============================================================ +def _build_source_path_from_sha1(sha1: str) -> str: + """通过 SHA1 从全局存储器构建源 .py 文件路径(委托到 gen._build_source_path_from_sha1)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenCdef._build_source_path_from_sha1(sha1) + return None + + +# ============================================================ +# _lookup_cross_module_cdefine - 跨模块查找 CDefine 常量 +# ============================================================ +def _lookup_cross_module_cdefine(pool: memhub.MemBuddy | t.CPtr, + name: str, + from_imports: str, + imported_modules: str = None, + depth: int = 0, + node: ast.AST | t.CPtr = None) -> t.CInt64T: + """跨模块查找 CDefine 常量,返回值(64 位)或 -1(未找到)(委托到 gen._lookup_cross_module_cdefine)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenCdef._lookup_cross_module_cdefine(pool, name, from_imports, imported_modules, depth, node) + return 0 + + +# ============================================================ +# _is_cdefine_name_pattern - 检查名字是否符合 CDefine 命名约定 +# ============================================================ +def _is_cdefine_name_pattern(name: str) -> int: + """检查名字是否符合 CDefine 命名约定(全大写+下划线+数字)(委托到 gen._is_cdefine_name_pattern)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenCdef._is_cdefine_name_pattern(name) + return 0 + + +# ============================================================ +# 翻译变量引用(Name 节点)→ load +# ============================================================ +def translate_name_value(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译变量引用(Name 节点)→ load(委托到 gen.translate_name_value)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenName.translate_name_value(builder, pool, node, trans) + return None + + +# ============================================================ +# ExprHandle - 表达式处理器(Mixin 继承模式) +# +# HandleValue 提供 trans 接口,委托到模块级 translate_value +# ============================================================ +@t.NoVTable +class ExprHandle(HandlesBase.Mixin): + """表达式处理器:继承 Mixin 获得 Trans 回指针""" + + def __init__(self, trans: HT.Translator | t.CPtr): + self.Trans = trans + + # ============================================================ + # HandleValue - 翻译值表达式为 LLVM Value + # ============================================================ + def HandleValue(self, node: ast.AST | t.CPtr) -> llvmlite.Value | t.CPtr: + """翻译值表达式,从 self.Trans 获取共享状态""" + return translate_value( + self.Trans._cur_builder, self.Trans.Pool, self.Trans.Module, + node, + self.Trans._funcs, self.Trans._func_count, self.Trans) + + +# ============================================================ +# NewExprHandle - 工厂函数 +# ============================================================ +def NewExprHandle(pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr) -> ExprHandle | t.CPtr: + h: ExprHandle | t.CPtr = pool.alloc(ExprHandle.__sizeof__()) + if h is None: + return None + string.memset(h, 0, ExprHandle.__sizeof__()) + h.Trans = trans + return h + + +# ============================================================ +# list_getitem_inline — 内联生成 list[T] __getitem__ 逻辑 +# +# list 结构布局 (6 字段 × 8 字节): +# __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40) +# 返回元素地址 (i8*),调用方根据元素类型 load 正确的值 +# ============================================================ +def list_getitem_inline(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + lm_obj: llvmlite.Value | t.CPtr, + idx_val: llvmlite.Value | t.CPtr, + node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """内联生成 list __getitem__ 逻辑,返回元素地址 (i8*)(委托到 gen.list_getitem_inline)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenName.list_getitem_inline(builder, pool, lm_obj, idx_val, node) + return None + + +# ============================================================ +# _list_elem_type_from_name — 从 list 类型名提取元素 LLVM 类型 +# ============================================================ +def _list_elem_type_from_name(pool: memhub.MemBuddy | t.CPtr, + struct_name: str) -> llvmlite.LLVMType | t.CPtr: + """从 list 类型名提取元素 LLVM 类型(委托到 gen._list_elem_type_from_name)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenName._list_elem_type_from_name(pool, struct_name) + return None + + +# ============================================================ +# list_setitem_inline — 内联生成 list[T] __setitem__ 逻辑 +# ============================================================ +def list_setitem_inline(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + lm_obj: llvmlite.Value | t.CPtr, + idx_val: llvmlite.Value | t.CPtr, + rhs_val: llvmlite.Value | t.CPtr, + node: ast.AST | t.CPtr = None) -> int: + """内联生成 list __setitem__ 逻辑,返回 0(委托到 gen.list_setitem_inline)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenName.list_setitem_inline(builder, pool, lm_obj, idx_val, rhs_val, node) + return 0 + + +# ============================================================ +# is_list_subscript — 检查 Subscript 节点是否是 list[T] 类型 +# +# 返回 list 对象指针 (Ptr(list[T])) 或 None +# ============================================================ +def is_list_subscript(node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """检查 Subscript 节点是否是 list[T] 类型,返回 list 对象指针或 None(委托到 gen.is_list_subscript)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenName.is_list_subscript(node, trans) + return None + + +# ============================================================ +# 翻译下标表达式 Subscript(value, slice, ctx) — ptr[i] / arr[i] +# ============================================================ +def translate_subscript(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译下标表达式,返回加载的元素值(委托到 gen.translate_subscript)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenName.translate_subscript(builder, pool, mod, node, trans) + return None + + +# ============================================================ +# find_global_in_module - 在模块全局变量链表中按名称查找 +# +# 查找策略: +# 1. 精确匹配 (如 "_mbuddy" 匹配 @_mbuddy) +# 2. 后缀匹配 (如 "_mbuddy" 匹配 @"sha1._mbuddy") +# ============================================================ +def find_global_in_module(mod: llvmlite.LLVMModule | t.CPtr, + name: str) -> llvmlite.GlobalVariable | t.CPtr: + """在模块全局变量链表中按名称查找全局变量(委托到 gen.find_global_in_module)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenAttr.find_global_in_module(mod, name) + return None + + +# ============================================================ +# make_global_ref - 创建全局变量引用 (@name,类型为 ty*) +# ============================================================ +def make_global_ref(pool: memhub.MemBuddy | t.CPtr, + name: str, + ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: + """创建全局变量引用 (类型为 ty*,名称为 @name)(委托到 gen.make_global_ref)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenAttr.make_global_ref(pool, name, ty) + return None + + +# ============================================================ +# _is_t_type_object_name - 检查 name 是否是 t.py 中的类型对象名 +# ============================================================ +def _is_t_type_object_name(name: str) -> int: + """检查 name 是否是 t.py 中的类型对象名(CPtr/CInt/CDouble 等)(委托到 gen._is_t_type_object_name)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenAttr._is_t_type_object_name(name) + return 0 + + +# ============================================================ +# _resolve_module_attribute_global - 解析模块属性访问的全局变量引用 +# ============================================================ +def _resolve_module_attribute_global(pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + trans: HT.Translator | t.CPtr, + at: ast.Attribute | t.CPtr, + ty_hint: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: + """解析模块属性访问,返回全局变量引用 (用于跨模块 global 访问)(委托到 gen._resolve_module_attribute_global)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenAttr._resolve_module_attribute_global(pool, mod, trans, at, ty_hint) + return None + + +# ============================================================ +# _get_cderef_attr_base - c.Deref(ptr).attr 属性访问的 base 指针 +# ============================================================ +def _get_cderef_attr_base(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + at_value: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """检测 at.value 是否为 c.Deref(ptr) 调用,返回 ptr 指针(不做 load)(委托到 gen._get_cderef_attr_base)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenAttr._get_cderef_attr_base(builder, pool, mod, at_value, trans) + return None + + +# ============================================================ +# 翻译属性访问 Attribute(value, attr, ctx) — obj.field +# ============================================================ +def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译属性访问,返回加载的字段值(委托到 gen.translate_attribute)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenAttr.translate_attribute(builder, pool, mod, node, trans) + return None + + +# ============================================================ +# 获取下标表达式的元素指针(不加载值,用于赋值) +# ============================================================ +def get_subscript_ptr(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """获取下标表达式的元素指针(用于赋值 lhs)(委托到 gen.get_subscript_ptr)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenName.get_subscript_ptr(builder, pool, mod, node, trans) + return None + + +# ============================================================ +# 获取属性访问的字段指针(不加载值,用于赋值) +# ============================================================ +def get_attribute_ptr(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """获取属性访问的字段指针(用于赋值 lhs)(委托到 gen.get_attribute_ptr)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenAttr.get_attribute_ptr(builder, pool, mod, node, trans) + return None + + +# ============================================================ +# 翻译 f-string(JoinedStr → snprintf 生成 i8* 栈缓冲)— 模块级委托 +# ============================================================ +def translate_joined_str(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译 f-string(委托到 gen.translate_joined_str,定义于 ExprGenFstr)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenFstr.translate_joined_str(builder, pool, mod, node, trans) + return None + + +# ============================================================ +# 翻译裸 FormattedValue(f"{expr:spec}" 无字面量)— 模块级委托 +# ============================================================ +def translate_formatted_value(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译裸 FormattedValue(委托到 gen.translate_formatted_value,定义于 ExprGenFstr)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenFstr.translate_formatted_value(builder, pool, mod, node, trans) + return None + + +# ============================================================ +# CDefine 整数常量 → LLVM 常量(64 位升级规则)— 模块级委托 +# ============================================================ +def _const_int_for_cdefine(pool: memhub.MemBuddy | t.CPtr, + value: t.CInt64T) -> llvmlite.Value | t.CPtr: + """CDefine 整数常量 → LLVM 常量(委托到 gen._const_int_for_cdefine,定义于 ExprGenCdef)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenCdef._const_int_for_cdefine(pool, value) + return None + + +# ============================================================ +# 解析嵌套 Attribute 链的 docstring 归属 — 模块级委托 +# ============================================================ +def _resolve_doc_symbol_attr(trans: HT.Translator | t.CPtr, + at: ast.Attribute | t.CPtr, + out_mod: str | t.CPtr, out_sym: str | t.CPtr) -> int: + """解析嵌套 Attribute 链的 docstring 归属(委托到 gen._resolve_doc_symbol_attr,定义于 ExprGenCls)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenCls._resolve_doc_symbol_attr(trans, at, out_mod, out_sym) + return 0 + + +# ============================================================ +# 解析 Name 符号的 docstring 归属 — 模块级委托 +# ============================================================ +def _resolve_doc_symbol_name(trans: HT.Translator | t.CPtr, name_id: str, + out_mod: str | t.CPtr, out_sym: str | t.CPtr) -> int: + """解析 Name 符号的 docstring 归属(委托到 gen._resolve_doc_symbol_name,定义于 ExprGenCls)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenCls._resolve_doc_symbol_name(trans, name_id, out_mod, out_sym) + return 0 + + +# ============================================================ +# 查找 docstring 内容(key="{module_sha1}.{symbol}")— 模块级委托 +# ============================================================ +def lookup_docstring(module_sha1: str, symbol: str) -> str: + """查找 docstring 内容(委托到 gen.lookup_docstring,定义于 ExprGenCls)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenCls.lookup_docstring(module_sha1, symbol) + return None + + +# ============================================================ +# 解析属性链(a.b.c)中 c 字段的注解类名 — 模块级委托 +# ============================================================ +def _resolve_attr_field_class(pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr, + attr_node: ast.AST | t.CPtr) -> str: + """解析属性链最终字段的注解类名(委托到 gen._resolve_attr_field_class,定义于 ExprGenAttr)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenAttr._resolve_attr_field_class(pool, trans, attr_node) + return None + + +# ============================================================ +# 翻译二元运算(自动类型提升)— 模块级委托 +# ============================================================ +def translate_binop(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译二元运算(委托到 gen.translate_binop,定义于 ExprGenOps)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenOps.translate_binop(pool, builder, mod, node, trans) + return None + + +# ============================================================ +# binop op → dunder 方法名(如 Add → "__add__")— 模块级委托 +# ============================================================ +def _binop_to_dunder(op: int) -> str: + """binop op → dunder 方法名(委托到 gen._binop_to_dunder,定义于 ExprGenOps)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenOps._binop_to_dunder(op) + return None + + +# ============================================================ +# unaryop op → dunder 方法名(如 USub → "__neg__")— 模块级委托 +# ============================================================ +def _unaryop_to_dunder(op: int) -> str: + """unaryop op → dunder 方法名(委托到 gen._unaryop_to_dunder,定义于 ExprGenOps)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenOps._unaryop_to_dunder(op) + return None + + +# ============================================================ +# f-string 尾部:全局格式串 + 固定栈缓冲 + snprintf — 模块级委托 +# ============================================================ +def _fstr_finalize(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + fmt_buf: str, + arg_head: llvmlite.Value | t.CPtr, + arg_tail: llvmlite.Value | t.CPtr, + arg_count: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """f-string 尾部(委托到 gen._fstr_finalize,定义于 ExprGenFstr)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenFstr._fstr_finalize(builder, pool, mod, fmt_buf, arg_head, arg_tail, arg_count, trans) + return None + + +# ============================================================ +# 追加字面量到格式串(% 转义)— 模块级委托 +# ============================================================ +def _fstr_append_literal(fmt_buf: str, lit: str) -> None: + """追加字面量到格式串(委托到 gen._fstr_append_literal,定义于 ExprGenFstr)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + g.ExprGenFstr._fstr_append_literal(fmt_buf, lit) + + +# ============================================================ +# Python format_spec → C printf 格式串 — 模块级委托 +# ============================================================ +def _fstr_parse_format_spec(pool: memhub.MemBuddy | t.CPtr, + spec_node: ast.AST | t.CPtr, + val: llvmlite.Value | t.CPtr, + arg_node: ast.AST | t.CPtr) -> str: + """Python format_spec → C printf 格式串(委托到 gen._fstr_parse_format_spec,定义于 ExprGenFstr)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenFstr._fstr_parse_format_spec(pool, spec_node, val, arg_node) + return None + + +# ============================================================ +# 无 format_spec 时按值类型推断 C printf 格式 — 模块级委托 +# ============================================================ +def _fstr_infer_c_fmt(pool: memhub.MemBuddy | t.CPtr, + val: llvmlite.Value | t.CPtr, + arg_node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr) -> str: + """按值类型推断 C printf 格式(委托到 gen._fstr_infer_c_fmt,定义于 ExprGenFstr)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenFstr._fstr_infer_c_fmt(pool, val, arg_node, trans) + return None + + +# ============================================================ +# 按 C 格式转换值类型(i8/i16→i32、bool→i32、f32→f64)— 模块级委托 +# ============================================================ +def _fstr_cast_value(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + val: llvmlite.Value | t.CPtr, + c_fmt: str, + arg_node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """按 C 格式转换值类型(委托到 gen._fstr_cast_value,定义于 ExprGenFstr)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.ExprGenFstr._fstr_cast_value(builder, pool, val, c_fmt, arg_node, trans) + return None diff --git a/App/lib/core/Handles/HandlesExprCall.vp b/App/lib/core/Handles/HandlesExprCall.vp index 3f54706..820b6c7 100644 --- a/App/lib/core/Handles/HandlesExprCall.vp +++ b/App/lib/core/Handles/HandlesExprCall.vp @@ -1,143 +1,137 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import sys -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.StubMerger as StubMerger -import lib.core.Handles.ExprCallCall as ExprCallCall -import lib.core.Gen.Generator as Generator - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - - -# ============================================================ -# 本地常量(阶段 E 拆分时随函数块误删,补回;子模块经 HandlesExprCall.常量 引用) -# ============================================================ -_CEXPORT_MAX: t.CDefine = 256 -ASM_MAX_OPERANDS: t.CDefine = 16 -ASM_TEXT_BUF_SIZE: t.CDefine = 2048 -ASM_CONST_BUF_SIZE: t.CDefine = 512 -ASM_ARGS_BUF_SIZE: t.CDefine = 512 -ASM_LINE_BUF_SIZE: t.CDefine = 4096 -LLVMIR_MAX_OPS: t.CDefine = 16 -LLVMIR_TEMPLATE_BUF: t.CDefine = 512 -MAX_CLOSURE_NAMES: t.CDefine = 128 -MAX_FUNC_PTR_SIGS: t.CDefine = 64 -GLOBAL_FUNC_MAX: t.CDefine = 8192 -GLOBAL_DEFAULTS_MAX: t.CDefine = 4096 - - - -# ============================================================ -# AsmOperand - 内联汇编操作数条目 -# ============================================================ -@t.NoVTable -class AsmOperand: - """内联汇编操作数条目""" - Value: llvmlite.Value | t.CPtr # 输入值或输出 alloca - Constraint: str # 约束字符串 (如 "r", "=r") - IsOutput: int # 1=输出, 0=输入 - - - - - - -# ============================================================ -# FuncEntry 结构体(用于函数表) -# ============================================================ -@t.NoVTable -class FuncEntry: - """函数表条目""" - Name: str - Func: llvmlite.Function | t.CPtr - Defaults: t.CVoid | t.CPtr # defaults 列表节点指针 (list[AST | CPtr]),None=无默认值 - DefaultCount: int # 默认值数量 - ParamCount: int # 形参数量(不含 self) - # TypeStr: 函数类型文本(stdlib 深拷贝,跨文件安全) - # 1b 每文件 reset_to(mark1) 回收 pool 内 Function 对象后, - # vtable 生成 find_func_global 读类型改用此文本,避免悬空。 - TypeStr: str - - - - - -@t.NoVTable -class FuncDefaultsEntry: - """默认参数表条目""" - Name: str - Defaults: t.CVoid | t.CPtr # defaults 列表节点指针 (list[AST | CPtr])(pool 内,可能被 reset) - DefaultCount: int - ParamCount: int # 形参数量(不含 self) - # 常量快照(stdlib 分配,跨文件永久存活): - # 注册时提取每个默认值 Constant 的值,跨模块调用时优先用快照重建常量 IR, - # 避免读取已被 1b reset_to(mark1) 回收的 pool 内 AST。 - ConstKinds: t.CInt | t.CPtr # const_kind 数组(DefaultCount 个 i32) - ConstInts: t.CInt64T | t.CPtr # int_val 数组(DefaultCount 个 i64) - ConstStrs: t.CSizeT | t.CPtr # str_val 指针数组(DefaultCount 个 i8*) - - - - - - - -# ============================================================ -# ExprCallHandle - 函数调用处理器(Mixin 继承模式) -# -# HandleCall / HandlePrintfCall 提供 trans 接口 -# ============================================================ -@t.NoVTable -class ExprCallHandle(HandlesBase.Mixin): - """函数调用处理器:继承 Mixin 获得 Trans 回指针""" - - def __init__(self, trans: HT.Translator | t.CPtr): - self.Trans = trans - - # ============================================================ - # HandleCall - 翻译函数调用,返回 call 结果 Value - # ============================================================ - def HandleCall(self, node: ast.AST | t.CPtr) -> llvmlite.Value | t.CPtr: - """翻译函数调用,从 self.Trans 获取共享状态""" - return ExprCallCall.translate_call( - self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module, - node, - self.Trans._funcs, self.Trans._func_count, self.Trans) - - # ============================================================ - # HandlePrintfCall - 翻译 printf 调用 - # ============================================================ - def HandlePrintfCall(self, cl: ast.Call | t.CPtr): - """翻译 printf 调用,从 self.Trans 获取共享状态""" - ExprCallCall.translate_printf_call( - self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module, - cl, self.Trans) - - # ============================================================ - # HandlePrintCall - 翻译 print 调用 - # ============================================================ - def HandlePrintCall(self, cl: ast.Call | t.CPtr): - """翻译 print 调用(类型感知格式化 + 默认换行)""" - ExprCallCall.translate_print_call( - self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module, - cl, self.Trans) +import lib.core.Gen.GenApi as GenApi +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import sys +import viperlib +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.StubMerger as StubMerger +import lib.core.Gen.Generator as Generator + +# ============================================================ +# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) +# ============================================================ +_g_gen: Generator.Generator | t.CPtr = None + + +# ============================================================ +# 本地常量(阶段 E 拆分时随函数块误删,补回;子模块经 HandlesExprCall.常量 引用) +# ============================================================ +_CEXPORT_MAX: t.CDefine = 256 +ASM_MAX_OPERANDS: t.CDefine = 16 +ASM_TEXT_BUF_SIZE: t.CDefine = 2048 +ASM_CONST_BUF_SIZE: t.CDefine = 512 +ASM_ARGS_BUF_SIZE: t.CDefine = 512 +ASM_LINE_BUF_SIZE: t.CDefine = 4096 +LLVMIR_MAX_OPS: t.CDefine = 16 +LLVMIR_TEMPLATE_BUF: t.CDefine = 512 +MAX_CLOSURE_NAMES: t.CDefine = 128 +MAX_FUNC_PTR_SIGS: t.CDefine = 64 +GLOBAL_FUNC_MAX: t.CDefine = 8192 +GLOBAL_DEFAULTS_MAX: t.CDefine = 4096 + + + +# ============================================================ +# AsmOperand - 内联汇编操作数条目 +# ============================================================ +@t.NoVTable +class AsmOperand: + """内联汇编操作数条目""" + Value: llvmlite.Value | t.CPtr # 输入值或输出 alloca + Constraint: str # 约束字符串 (如 "r", "=r") + IsOutput: int # 1=输出, 0=输入 + + + + + + +# ============================================================ +# FuncEntry 结构体(用于函数表) +# ============================================================ +@t.NoVTable +class FuncEntry: + """函数表条目""" + Name: str + Func: llvmlite.Function | t.CPtr + Defaults: t.CVoid | t.CPtr # defaults 列表节点指针 (list[AST | CPtr]),None=无默认值 + DefaultCount: int # 默认值数量 + ParamCount: int # 形参数量(不含 self) + # TypeStr: 函数类型文本(stdlib 深拷贝,跨文件安全) + # 1b 每文件 reset_to(mark1) 回收 pool 内 Function 对象后, + # vtable 生成 find_func_global 读类型改用此文本,避免悬空。 + TypeStr: str + + + + + +@t.NoVTable +class FuncDefaultsEntry: + """默认参数表条目""" + Name: str + Defaults: t.CVoid | t.CPtr # defaults 列表节点指针 (list[AST | CPtr])(pool 内,可能被 reset) + DefaultCount: int + ParamCount: int # 形参数量(不含 self) + # 常量快照(stdlib 分配,跨文件永久存活): + # 注册时提取每个默认值 Constant 的值,跨模块调用时优先用快照重建常量 IR, + # 避免读取已被 1b reset_to(mark1) 回收的 pool 内 AST。 + ConstKinds: t.CInt | t.CPtr # const_kind 数组(DefaultCount 个 i32) + ConstInts: t.CInt64T | t.CPtr # int_val 数组(DefaultCount 个 i64) + ConstStrs: t.CSizeT | t.CPtr # str_val 指针数组(DefaultCount 个 i8*) + + + + + + + +# ============================================================ +# ExprCallHandle - 函数调用处理器(Mixin 继承模式) +# +# HandleCall / HandlePrintfCall 提供 trans 接口 +# ============================================================ +@t.NoVTable +class ExprCallHandle(HandlesBase.Mixin): + """函数调用处理器:继承 Mixin 获得 Trans 回指针""" + + def __init__(self, trans: HT.Translator | t.CPtr): + self.Trans = trans + + # ============================================================ + # HandleCall - 翻译函数调用,返回 call 结果 Value + # ============================================================ + def HandleCall(self, node: ast.AST | t.CPtr) -> llvmlite.Value | t.CPtr: + """翻译函数调用,从 self.Trans 获取共享状态""" + return GenApi.translate_call( + self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module, + node, + self.Trans._funcs, self.Trans._func_count, self.Trans) + + # ============================================================ + # HandlePrintfCall - 翻译 printf 调用 + # ============================================================ + def HandlePrintfCall(self, cl: ast.Call | t.CPtr): + """翻译 printf 调用,从 self.Trans 获取共享状态""" + GenApi.translate_printf_call( + self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module, + cl, self.Trans) + + # ============================================================ + # HandlePrintCall - 翻译 print 调用 + # ============================================================ + def HandlePrintCall(self, cl: ast.Call | t.CPtr): + """翻译 print 调用(类型感知格式化 + 默认换行)""" + GenApi.translate_print_call( + self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module, + cl, self.Trans) diff --git a/App/lib/core/Handles/HandlesExprOps.vp b/App/lib/core/Handles/HandlesExprOps.vp deleted file mode 100644 index 8e1df19..0000000 --- a/App/lib/core/Handles/HandlesExprOps.vp +++ /dev/null @@ -1,116 +0,0 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import viperlib -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Gen.Generator as Generator - -# ============================================================ -# HandlesExprOps - 二元运算处理(P3 对象化后的委托层) -# -# 全部函数已迁移为 lib.core.Gen.ExprGenMixin 的方法,本模块保留 -# 同名模块级函数作为"一行委托":延迟 import Gen 取全局单例 -# (BuildPipeline/main 创建后 set_global_gen 注册),再调用 gen -# 的对应方法。签名与旧函数完全一致,调用方零改动。 -# ============================================================ - - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - - -# ============================================================ -# 委托函数:延迟 import Gen 取全局单例 → 调 gen 方法 -# (gen 未注册时正常流程不会发生;有返回值函数返回默认值) -# ============================================================ - - -# BinOp 运算符 → dunder 方法名 -def _binop_to_dunder(op: int) -> str: - """将 BinOp 运算符映射到 dunder 方法名,无映射时返回 None(委托到 gen._binop_to_dunder)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._binop_to_dunder(op) - return None - - -# Compare 运算符 → dunder 方法名 -def _cmpop_to_dunder(op: int) -> str: - """将 Compare 运算符映射到 dunder 方法名,无映射时返回 None(委托到 gen._cmpop_to_dunder)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._cmpop_to_dunder(op) - return None - - -# UnaryOp 运算符 → dunder 方法名 -def _unaryop_to_dunder(op: int) -> str: - """将 UnaryOp 运算符映射到 dunder 方法名,无映射时返回 None(委托到 gen._unaryop_to_dunder)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._unaryop_to_dunder(op) - return None - - -# ============================================================ -# try_operator_overload - 尝试运算符重载 -# -# 检查 lhs 是否为结构体指针,并在该类(含继承链)中查找对应的 -# dunder 方法。找到则生成方法调用 lhs.__dunder__(rhs),返回 -# 调用结果;未找到返回 None,调用方回退到原生运算。 -# ============================================================ -def try_operator_overload(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - lhs: llvmlite.Value | t.CPtr, - rhs: llvmlite.Value | t.CPtr, - op: int, - trans: HT.Translator | t.CPtr, - is_compare: int) -> llvmlite.Value | t.CPtr: - """尝试运算符重载:lhs 是结构体指针时调用 dunder 方法,否则返回 None(委托到 gen.try_operator_overload)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.try_operator_overload(pool, builder, mod, lhs, rhs, op, trans, is_compare) - return None - - -# ============================================================ -# try_unary_operator_overload - 尝试一元运算符重载 -# -# 检查 operand 是否为结构体指针,并在该类(含继承链)中查找对应的 -# dunder 方法(__neg__/__pos__/__invert__)。找到则生成方法调用 -# operand.__dunder__(),返回调用结果;未找到返回 None,调用方回退到原生运算。 -# ============================================================ -def try_unary_operator_overload(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - operand: llvmlite.Value | t.CPtr, - op: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """尝试一元运算符重载:operand 是结构体指针时调用 dunder 方法,否则返回 None(委托到 gen.try_unary_operator_overload)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.try_unary_operator_overload(pool, builder, mod, operand, op, trans) - return None - - -# ============================================================ -# 翻译二元运算(自动类型提升) -# ============================================================ -def translate_binop(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译二元运算(自动类型提升)(委托到 gen.translate_binop)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_binop(pool, builder, mod, node, trans) - return None diff --git a/App/lib/core/Handles/HandlesFor.vp b/App/lib/core/Handles/HandlesFor.vp deleted file mode 100644 index 9dbe9f7..0000000 --- a/App/lib/core/Handles/HandlesFor.vp +++ /dev/null @@ -1,55 +0,0 @@ -import t, c -from stdint import * -import ast -import memhub -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# HandlesFor - for 循环语句处理(迁移完成,保留跨 Mixin 委托壳) -# -# P6 机械化迁移:ForHandle/ForHandleBase/ForHandleIter 全部方法 → -# StmtGenCifMixin.translate_for 及辅助方法(_handle_ptr_iter/ -# _handle_array_iter/_handle_list_literal_iter/_handle_list_iter/ -# _handle_dict_iter/_handle_oop_iter/_handle_enumerate_iter/ -# _handle_zip_iter/_extract_tuple_names/_seq_kind/_build_seq_loop)。 -# SEQ_KIND_* 常量保留:StmtGenCifMixin._seq_kind/_build_seq_loop 经 -# HandlesFor.SEQ_KIND_* 访问。 -# 分派中枢(StmtGenMixin)经本壳跨链调用(Viper @t.NoVTable 静态绑定下 -# 跨 Mixin self. 调用 mangle 失败,须经模块级委托壳桥回 gen 单例)。 -# 迁移收尾(编译器缺陷修复)后统一删除。 -# ============================================================ - - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) -# -# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。 -# 委托函数用本地 _g_gen(cast 成 Generator 类型)调 -# StmtGenCifMixin 方法,避免函数体 import 包模块与类/模块名歧义。 -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - - -# ============================================================ -# 序列迭代源类型码(for x in ... / enumerate / zip 迭代源分类) -# RANGE: range(start, stop, step) -# STR: 字符串(常量或 str 变量) -# LIST: list[T] 容器(按 __count__ + __data__ 迭代) -# ============================================================ -SEQ_KIND_RANGE: t.CDefine = 1 -SEQ_KIND_STR: t.CDefine = 2 -SEQ_KIND_LIST: t.CDefine = 3 - - -# ============================================================ -# translate_for - for 循环语句翻译(委托到 gen.translate_for) -# ============================================================ -def translate_for(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 for 循环语句(委托到 gen.translate_for)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_for(trans, node) - return 0 diff --git a/App/lib/core/Handles/HandlesFunctions.vp b/App/lib/core/Handles/HandlesFunctions.vp deleted file mode 100644 index d165096..0000000 --- a/App/lib/core/Handles/HandlesFunctions.vp +++ /dev/null @@ -1,143 +0,0 @@ -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.HandlesTranslator as HT -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesBody as HandlesBody -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# HandlesFunctions - 函数定义处理(P5-1 对象化后的委托层) -# -# P5-1 对象化重构(wiki/14-oo-refactor.md): -# 全部函数已迁移为 lib.core.Gen.FuncGenMixin 的方法,本模块保留 -# 同名模块级函数作为"一行委托":延迟 import Gen 取全局单例 -# (BuildPipeline/main 创建后 set_global_gen 注册),再调用 gen -# 的对应方法。签名与旧函数完全一致,调用方零改动。 -# ============================================================ - - -# ============================================================ -# 全局 gen 单例(模块级镜像) -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - - -# 作用域类型常量(本地副本,避免旧编译器跨模块 CDefine 查找 bug) -SCOPE_FUNCTION: t.CDefine = 1 - - -# ============================================================ -# 委托函数:延迟 import Gen 取全局单例 → 调 gen 方法 -# (gen 未注册时正常流程不会发生;有返回值函数返回默认值) -# ============================================================ - - -def extract_func_attrs(pool: memhub.MemBuddy | t.CPtr, - decorator_list: list[ast.AST | t.CPtr] | t.CPtr, - imported_modules: str) -> str: - """从 decorator_list 提取 c.Attribute 属性,返回 LLVM IR 属性字符串(委托到 gen.extract_func_attrs)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.extract_func_attrs(pool, decorator_list, imported_modules) - return None - - -def _get_attr_name_from_node(node: ast.AST | t.CPtr) -> str: - """从 AST 节点提取属性名(委托到 gen._get_attr_name_from_node)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._get_attr_name_from_node(node) - return None - - -def _append_llvm_attr(attrs_buf: str, attr_name: str) -> int: - """将属性名映射到 LLVM 属性名并追加到缓冲区(委托到 gen._append_llvm_attr)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._append_llvm_attr(attrs_buf, attr_name) - return 0 - - -def _append_str(buf: str, s: str) -> None: - """将字符串追加到 buf 末尾(用 strlen+strcpy 模拟 strcat)(委托到 gen._append_str)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g._append_str(buf, s) - - -def _mangle_name(trans: HT.Translator | t.CPtr, name: str) -> str: - """为任意名称添加 SHA1 前缀(不做 main/export 检查)(委托到 gen._mangle_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._mangle_name(trans, name) - return None - - -def _mangle_name_with_sha1(sha1: str, name: str) -> str: - """用指定 SHA1 为名称添加前缀(不做 main/export 检查)(委托到 gen._mangle_name_with_sha1)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._mangle_name_with_sha1(sha1, name) - return None - - -def _mangle_func_name(trans: HT.Translator | t.CPtr, name: str, - has_export: int) -> str: - """为函数名添加 SHA1 前缀(检查 main/export)(委托到 gen._mangle_func_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._mangle_func_name(trans, name, has_export) - return None - - -def forward_declare_functions(trans: HT.Translator | t.CPtr, - tree: ast.AST | t.CPtr) -> int: - """预扫描所有顶层 FunctionDef,创建前向声明(委托到 gen.forward_declare_functions)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.forward_declare_functions(trans, tree) - return 0 - - -def translate_function_def(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译函数定义,返回新增的变量数(通常为 0,函数定义不增加当前作用域变量)(委托到 gen.translate_function_def)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_function_def(trans, node) - return 0 - - -def translate_nested_function_def(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译嵌套函数定义:提升为顶层函数 + 创建闭包(委托到 gen.translate_nested_function_def)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_nested_function_def(trans, node) - return 0 - - -def create_function(pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - name: str, - args_node: ast.AST | t.CPtr, - ret_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Function | t.CPtr: - """创建 LLVM 函数并添加参数(委托到 gen.create_function)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.create_function(pool, mod, name, args_node, ret_ty) - return None diff --git a/App/lib/core/Handles/HandlesIf.vp b/App/lib/core/Handles/HandlesIf.vp deleted file mode 100644 index e6f3ed7..0000000 --- a/App/lib/core/Handles/HandlesIf.vp +++ /dev/null @@ -1,42 +0,0 @@ -import t, c -from stdint import * -import ast -import memhub -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# HandlesIf - if/elif/else 语句处理(迁移完成,保留跨 Mixin 委托壳) -# -# P6 机械化迁移:IfHandle 类 → StmtGenCifMixin.translate_if。 -# CIf 编译期求值(_is_cif_attr/_is_cif_call/_get_platform_macro_value/ -# _cif_name_value/_cif_attr_value/_cif_eval_node/_evaluate_cif_test 及 -# 模块级 _g_cif_eval_ok)已迁移为 StmtGenCifMixin 的方法/字段 -# (CifEvalOk)。 -# 分派中枢(StmtGenMixin)经本壳跨链调用(Viper @t.NoVTable 静态绑定下 -# 跨 Mixin self. 调用 mangle 失败,须经模块级委托壳桥回 gen 单例)。 -# 迁移收尾(编译器缺陷修复)后统一删除。 -# ============================================================ - - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) -# -# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。 -# 委托函数用本地 _g_gen(cast 成 Generator 类型)调 -# StmtGenCifMixin 方法,避免函数体 import 包模块与类/模块名歧义。 -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - - -# ============================================================ -# translate_if - if/elif/else 语句翻译(委托到 gen.translate_if) -# ============================================================ -def translate_if(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 if/elif/else 语句(委托到 gen.translate_if)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_if(trans, node) - return 0 diff --git a/App/lib/core/Handles/HandlesImports.vp b/App/lib/core/Handles/HandlesImports.vp deleted file mode 100644 index b00bd48..0000000 --- a/App/lib/core/Handles/HandlesImports.vp +++ /dev/null @@ -1,326 +0,0 @@ -import t, c -from stdint import * -import ast -import memhub -import string -import stdlib -import viperlib -import stdio -import sys -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.StubMerger as StubMerger -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# HandlesImports - 导入语句处理(P6-D 对象化后的委托层) -# -# 管理 _imported_modules 和 _from_imports 字符串 -# 注意:str = bytes = str = i8* -# -# P6-D 对象化重构(wiki/14-oo-refactor.md): -# 全部模块级函数已迁移为 lib.core.Gen.ImportsGenMixin 的方法 -# (全局状态 _g_reexport_* 与 _g_current_file 迁入 gen 字段),本模块 -# 保留同名模块级函数作为"一行委托":延迟 import Gen 取全局单例 -# (BuildPipeline/main 创建后 set_global_gen 注册),再调用 gen 的 -# 对应方法。签名与旧函数完全一致,调用方零改动。 -# ImportsHandle 类与 NewImportsHandle 工厂已删除(P6 机械化迁移: -# HandleImport/HandleImportFromModule/HandleImportFromNames → 本模块 -# 新增的 translate_import/translate_import_from_module/ -# translate_import_from_names 模块级委托壳,路由到 gen 方法)。 -# ============================================================ - -MAX_REEXPORT: t.CDefine = 512 - - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) -# -# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。 -# P6-D 委托函数用本地 _g_gen(cast 成 Generator 类型)调 -# ImportsGenMixin 方法,避免函数体 import 包模块与 Generator -# 类/模块名歧义。 -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - - -# ============================================================ -# 委托函数:延迟 import Gen 取全局单例 → 调 gen 方法 -# (gen 未注册时正常流程不会发生;有返回值函数返回默认值) -# ============================================================ - - -# ============================================================ -# 添加已导入模块名 -# ============================================================ -def add_imported_module(pool: memhub.MemBuddy | t.CPtr, - imported_modules: str, - name: str) -> str: - """记录已导入的模块名,返回新的 imported_modules 字符串指针(委托到 gen.add_imported_module)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.add_imported_module(pool, imported_modules, name) - return None - - -# ============================================================ -# 检查模块是否已导入 -# ============================================================ -def is_module_imported(imported_modules: str, name: str) -> int: - """检查模块是否已导入(词边界精确匹配,避免子串误匹配,委托到 gen.is_module_imported)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.is_module_imported(imported_modules, name) - return 0 - - -# ============================================================ -# 添加 from-import 名称映射 -# ============================================================ -def add_from_import(pool: memhub.MemBuddy | t.CPtr, - from_imports: str, - local_name: str, - module_name: str, - original_name: str = None) -> str: - """添加 from-import 映射,返回新的 from_imports 字符串(委托到 gen.add_from_import) - - 格式: - 无别名: "local_name:module_name" - 有别名: "local_name:module_name:original_name" - (original_name 为源模块中的真实函数名,用于跨模块 SHA1 修饰) - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.add_from_import(pool, from_imports, local_name, module_name, original_name) - return None - - -# ============================================================ -# 查找 from-import 名称 → 返回原始函数名(别名场景) -# -# 对于 from X import Y as Z,返回 Y(源模块中的真实函数名)。 -# 无别名时返回 None(local_name 即为原始名)。 -# ============================================================ -def lookup_from_import_original(from_imports: str, - local_name: str) -> str: - """查找 from-import 别名对应的原始函数名,返回 None=无别名或未找到(委托到 gen.lookup_from_import_original)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.lookup_from_import_original(from_imports, local_name) - return None - - -# ============================================================ -# 查找 from-import 名称 → 返回模块名或 None -# -# allow_star_fallback: 是否允许 star import 回退(默认 1=允许)。 -# 当查询明确模块名(如 "BuildPipeline")时,应传 0 禁用回退, -# 避免被 star import 模块名误导(如 from stdint import * 后 -# 查询 "BuildPipeline" 错误回退到 "stdint")。 -# ============================================================ -def lookup_from_import(from_imports: str, name: str, - allow_star_fallback: int = 1) -> str: - """查找 from-import 名称,返回模块名或 None(委托到 gen.lookup_from_import) - - 支持 star import: 如果 from_imports 中有 "*:module" 条目, - 且未找到精确名称匹配,且 allow_star_fallback != 0,则返回 star import 的模块名。 - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.lookup_from_import(from_imports, name, allow_star_fallback) - return None - - -# ============================================================ -# register_reexport - 注册 re-export 映射 -# -# 在 HandleImportFromNames 中调用:当处理 from .X import Y 时, -# 记录当前模块(通过 ModuleSha1)re-export 了函数 Y,源模块为 X。 -# -# 幂等:重复注册相同映射不会增加条目。 -# 内存用 stdlib.malloc 分配(全局存储器,跨 Phase 持久化)。 -# ============================================================ -def register_reexport(mod_sha1: str, func_name: str, source_module: str) -> int: - """注册 re-export 映射(幂等),返回 0 成功,-1 失败(委托到 gen.register_reexport)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.register_reexport(mod_sha1, func_name, source_module) - return 0 - - -# ============================================================ -# lookup_reexport - 查找 re-export 映射 -# -# 给定模块 SHA1 和函数名,返回源模块名(如 "ast.lexer")或 None。 -# 调用方通过 _lookup_module_sha1(source_module) 获取源模块的 SHA1。 -# ============================================================ -def lookup_reexport(mod_sha1: str, func_name: str) -> str: - """查找 re-export 映射,返回源模块名或 None(委托到 gen.lookup_reexport)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.lookup_reexport(mod_sha1, func_name) - return None - - -# ============================================================ -# _resolve_relative_module - 解析相对导入为完整模块名 -# -# 对于 from .X import Y(level=1, module="X")在包 pkg 中: -# 解析为 "pkg.X" -# 对于 from . import Y(level=1, module=None)在包 pkg 中: -# 解析为 "pkg" -# 对于 from ..X import Y(level=2, module="X")在包 pkg.sub 中: -# 解析为 "pkg.X"(先从 pkg.sub 上溯一级到 pkg,再追加 .X) -# -# Args: -# pool: 内存池 -# current_package: 当前文件所属包名(如 "llvmlite"),None 表示无包 -# level: 相对导入级别(0=绝对,1=., 2=..) -# module: ImportFrom 的 module 字段(可能为 None) -# -# Returns: -# 解析后的完整模块名;绝对导入(level<=0)直接返回 module; -# 无法解析时返回 module(回退到原始值) -# ============================================================ -def _resolve_relative_module(pool: memhub.MemBuddy | t.CPtr, - current_package: str, - level: t.CInt, - module: str) -> str: - """解析相对导入为完整模块名(委托到 gen._resolve_relative_module)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._resolve_relative_module(pool, current_package, level, module) - return None - - -# ============================================================ -# compute_package_from_relpath - 从相对路径计算包名 -# -# 包名 = 文件所在目录路径,将 / 和 \ 替换为 . -# 对于顶级文件(无目录分隔符),返回 None -# -# 示例: -# "llvmlite/__init__.vp" → "llvmlite" -# "llvmlite/__types.vp" → "llvmlite" -# "ast/parser.vp" → "ast" -# "ast.vp" → None(顶级文件) -# ============================================================ -def compute_package_from_relpath(pool: memhub.MemBuddy | t.CPtr, - rel_path: str) -> str: - """从相对路径计算包名(目录部分,分隔符替换为 .,委托到 gen.compute_package_from_relpath)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.compute_package_from_relpath(pool, rel_path) - return None - - -# ============================================================ -# set_current_file - 设置当前编译的文件名 -# -# 与 HandlesType.set_current_file 同步调用,写入 gen.CurrentFile -# (委托到 gen.set_current_file)。 -# ============================================================ -def set_current_file(file_path: str) -> None: - """设置当前正在编译的文件名(与 HandlesType.set_current_file 同步调用,委托到 gen.set_current_file)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.set_current_file(file_path) - - -# ============================================================ -# _report_import_error - 本地实现 Python 风格报错(避免循环依赖) -# -# 无法访问 HandlesType.fatal_error(HandlesType import 了本模块, -# 若本模块再 import HandlesType 会形成循环依赖),这里用简化格式: -# Traceback (most recent call last): -# File "<当前文件>", line -# ImportError: -# ============================================================ -def _report_import_error(node: ast.AST | t.CPtr, msg: str) -> None: - """以 Python 风格报错并退出(本地实现,避免循环依赖,委托到 gen._report_import_error)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g._report_import_error(node, msg) - - -# ============================================================ -# _is_local_module_file - 当前文件同目录存在 {mod_name}.vp/.py -# -# 多文件项目(如 Test/G4/App 的 caller1.vp import g4node)的兄弟模块 -# 不在 includes 扫描存储器中(SHA1 在项目源文件列表),检查应豁免。 -# ============================================================ -def _is_local_module_file(mod_name: str) -> int: - """当前文件同目录存在 {mod_name}.vp/.py → 项目内兄弟模块(委托到 gen._is_local_module_file)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_local_module_file(mod_name) - return 0 - - -# ============================================================ -# _check_import_sha1 - 导入时校验模块 SHA1 是否已注册(fast-fail) -# -# 背景:若 includes 路径配置错误(如 project.json 指向不存在的 -# ./includes),includes 扫描结果为 0,模块不会注册 SHA1。此前 -# 错误延迟到实际调用 module.func() 时才报误导性的 -# "跨模块调用 'bd.alloc' 找不到模块 SHA1"。 -# 现在在 import 语句处立即检测并报错,快速定位配置问题。 -# -# t/c 是内部库,不参与 includes 扫描,豁免检查。 -# ============================================================ -def _check_import_sha1(node: ast.AST | t.CPtr, mod_name: str) -> int: - """导入时校验模块 SHA1 是否已注册,未注册则立即报错退出(委托到 gen._check_import_sha1) - - Args: - node: Import/ImportFrom AST 节点(提供行号) - mod_name: 导入的模块名(如 "memhub"、"w32.fileio") - - Returns: - 1=检查通过;模块未注册时直接报错退出(不会返回 0) - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._check_import_sha1(node, mod_name) - return 0 - - -# ============================================================ -# translate_import - 处理 import 语句(委托到 gen.translate_import) -# ============================================================ -def translate_import(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """处理 import 语句,返回 0(委托到 gen.translate_import)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_import(trans, node) - return 0 - - -# ============================================================ -# translate_import_from_module - 处理 from X import Y 的模块部分 -# (委托到 gen.translate_import_from_module) -# ============================================================ -def translate_import_from_module(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """处理 from X import Y 的模块部分(委托到 gen.translate_import_from_module)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_import_from_module(trans, node) - return 0 - - -# ============================================================ -# translate_import_from_names - 处理 from X import Y 的名称部分 -# (委托到 gen.translate_import_from_names) -# ============================================================ -def translate_import_from_names(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """处理 from X import Y 的名称部分(委托到 gen.translate_import_from_names)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_import_from_names(trans, node) - return 0 diff --git a/App/lib/core/Handles/HandlesMain.vp b/App/lib/core/Handles/HandlesMain.vp deleted file mode 100644 index c89105b..0000000 --- a/App/lib/core/Handles/HandlesMain.vp +++ /dev/null @@ -1,172 +0,0 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import viperlib -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesBody as HandlesBody -import lib.core.Handles.HandlesFunctions as HandlesFunctions -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# HandlesMain - 模块级翻译入口 + wrapper main 创建 -# -# 从 translator.py 拆分出来,负责: -# 1. create_wrapper_main() - 无用户 main 时创建包装 main -# 2. translate_children() - 遍历 AST 子节点并分派翻译 -# -# trans 单参模式:所有共享状态从 trans 获取,无需 11 个参数 -# 注意: str = bytes = str = i8* -# -# P6-E 对象化重构:全部函数已迁移为 lib.core.Gen.TranslatorGenMixin -# 的方法,本模块保留同名模块级函数作为"一行委托"(同 P2-P5 模式): -# 延迟 import Gen 取全局单例,再调用 gen 的对应方法。 -# ============================================================ - - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - - -# ============================================================ -# _register_cexport_from_funcdef - Phase 1a 预注册 CExport/State 函数 -# -# 解决翻译顺序依赖问题:Phase 1b 按字母序翻译,后翻译的模块的 -# CExport 函数无法被先翻译的模块正确识别为裸名调用。 -# Phase 1a 预注册所有 CExport/State 函数名到全局表。 -# ============================================================ -def _register_cexport_from_funcdef(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """预注册 CExport/State 函数到全局表(仅注册,不生成 IR)(委托到 gen._register_cexport_from_funcdef)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._register_cexport_from_funcdef(trans, node) - return 0 - - -# ============================================================ -# translate_children - 遍历 AST 子节点并分派翻译 -# -# 对应 TransPyC translator._translate_children() -# 共享状态从 trans 获取,imported_modules/from_imports 更新到 trans -# ============================================================ -def translate_children(trans: HT.Translator | t.CPtr, - tree: ast.AST | t.CPtr) -> int: - """遍历 tree.children 并翻译每个子节点(委托到 gen.translate_children) - - Args: - trans: 翻译器(含所有共享状态) - tree: AST 模块节点 - - Returns: - t.CInt: 新增的变量数 - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_children(trans, tree) - return 0 - - -# ============================================================ -# _prescan_funcdef_signatures - 1a 阶段预解析模块级函数签名 -# -# 触发泛型类特化(如 numpy 的 _empty_like 签名 ndarray[t.CDouble]), -# 使特化结构体在 mark1 前注册(Ty/Fields 不被 1b 的 mark/reset 回收), -# 避免 Phase2 翻译 App 文件时访问悬空结构体(UAF)。 -# 仅解析类型触发特化,不验证结果(1b 全量翻译时重新解析)。 -# ============================================================ -def _prescan_funcdef_signatures(trans: HT.Translator | t.CPtr, - fd: ast.FunctionDef | t.CPtr) -> None: - """预解析模块级函数签名的返回/参数类型,触发泛型类特化(委托到 gen._prescan_funcdef_signatures)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g._prescan_funcdef_signatures(trans, fd) - - -# ============================================================ -# _build_array_initializer_text - 从 AST List 生成 LLVM IR 数组初始化器 -# -# 生成格式: [N x elem_ty] [elem_ty val0, elem_ty val1, ...] -# 用于模块级 t.CArray 列表字面量初始化(不依赖 builder,直接生成常量初始化器) -# ============================================================ -def _build_array_initializer_text(pool: memhub.MemBuddy | t.CPtr, - var_ty: llvmlite.LLVMType | t.CPtr, - list_node: ast.List | t.CPtr) -> str: - """从 AST List 节点生成 LLVM IR 数组初始化器文本,None 失败(委托到 gen._build_array_initializer_text)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._build_array_initializer_text(pool, var_ty, list_node) - return None - - -# ============================================================ -# _build_string_ptr_initializer - 为字符串字面量初始化指针类型全局变量 -# -# 创建内部字符串常量全局 @.str.{var_name} = private constant [len+1 x i8] c"...\00" -# 返回 GEP 初始化器文本: getelementptr inbounds ([len+1 x i8], [len+1 x i8]* @.str.{var_name}, i32 0, i32 0) -# 用于 b64_tab: t.CArray[t.CChar, None] = "ABC..." 等字符串初始化指针类型 -# ============================================================ -def _build_string_ptr_initializer(pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - var_name: str, - str_val: str) -> str: - """为字符串字面量创建内部常量全局并返回 GEP 初始化器文本,None 失败(委托到 gen._build_string_ptr_initializer)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._build_string_ptr_initializer(pool, mod, var_name, str_val) - return None - - -# ============================================================ -# handle_module_level_var - 模块级变量声明 → 创建 LLVM 全局变量 -# -# 当用户已定义 main(无 wrapper main builder)时,模块级 -# AnnAssign/Assign 创建全局变量 @var_name 并注册到 SymTab 模块作用域 -# 支持整数、列表字面量、字符串字面量初始值 -# ============================================================ -def handle_module_level_var(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """处理模块级变量声明,创建全局变量(委托到 gen.handle_module_level_var)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.handle_module_level_var(trans, node) - return 0 - - -# ============================================================ -# create_wrapper_main - 创建包装 main 函数 -# -# 当用户未定义 main 函数时调用。 -# 创建 main() -> i32 函数 → 设置 trans._cur_func/_cur_builder → -# 预扫描 alloca → 翻译子节点 → ret 0 -# ============================================================ -def create_wrapper_main(trans: HT.Translator | t.CPtr, - tree: ast.AST | t.CPtr, - i32_ty: llvmlite.LLVMType | t.CPtr) -> int: - """创建包装 main 函数并翻译所有顶层语句(委托到 gen.create_wrapper_main) - - Args: - trans: 翻译器(含所有共享状态) - tree: AST 模块节点 - i32_ty: i32 LLVMType - - Returns: - t.CInt: 新增的变量数 - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.create_wrapper_main(trans, tree, i32_ty) - return 0 diff --git a/App/lib/core/Handles/HandlesMatch.vp b/App/lib/core/Handles/HandlesMatch.vp deleted file mode 100644 index 3103b1f..0000000 --- a/App/lib/core/Handles/HandlesMatch.vp +++ /dev/null @@ -1,74 +0,0 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import viperlib -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesBody as HandlesBody -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# HandlesMatch - match 语句处理(P6 对象化后的委托层) -# -# P6 机械化迁移:MatchHandle 类 → lib.core.Gen.MatchGenMixin -# (Handle → translate_match,方法体 self.Trans → trans 首参; -# 类内辅助方法 + 模块级 _case_tail_unreachable 一并搬入成方法)。 -# 本模块保留同名模块级函数作为"一行委托":延迟 import Gen 取全局单例 -# (BuildPipeline/main 创建后 set_global_gen 注册),再调用 gen 的 -# 对应方法。签名与旧函数完全一致,调用方零改动。 -# 分派中枢(StmtGenMixin)经本壳跨链调用(Viper @t.NoVTable 静态绑定下 -# 跨 Mixin self. 调用 mangle 失败,须经模块级委托壳桥回 gen 单例)。 -# 迁移收尾(编译器缺陷修复)后统一删除。 -# -# 逻辑移植自 TPC 的 HandlesMatch.py,用 Viper 语法重写。 -# 两条路径: -# 1. REnum 路径:bitcast subject 到 i32* 读 __tag + switch 分派 -# 2. 非 REnum 路径:subject ptrtoint 到 i32 + switch 分派 -# -# IR 模式(REnum): -# %tag_ptr = bitcast * %subj to i32* -# %tag = load i32, i32* %tag_ptr -# switch i32 %tag, label %default [ i32 , label %case1 ... ] -# case1: -# ... body ... -# br label %end (若无 c.NoBreak) -# end: -# ============================================================ - -# match case 数量上限 -MAX_MATCH_CASES: t.CDefine = 32 - -# 作用域种类常量(与 HandlesVar 的 Scope.Kind 区分) -SCOPE_MATCH: t.CDefine = 6 - - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) -# -# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。 -# P6 委托函数用本地 _g_gen(cast 成 Generator 类型)调 -# MatchGenMixin 方法,避免函数体 import 包模块与 Generator -# 类/模块名歧义。 -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - - -# ============================================================ -# translate_match - match 语句翻译(委托到 gen.translate_match) -# ============================================================ -def translate_match(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 match 语句,返回 0(委托到 gen.translate_match)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_match(trans, node) - return 0 diff --git a/App/lib/core/Handles/HandlesNonlocal.vp b/App/lib/core/Handles/HandlesNonlocal.vp deleted file mode 100644 index d3f030c..0000000 --- a/App/lib/core/Handles/HandlesNonlocal.vp +++ /dev/null @@ -1,126 +0,0 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# HandlesNonlocal - nonlocal 变量访问(通过闭包 env)(P6 对象化后的委托层) -# -# 全部模块级函数已迁移为 lib.core.Gen.StmtGenMixin 的方法,本模块 -# 保留同名模块级函数作为"一行委托":延迟 import Gen 取全局单例 -# (BuildPipeline/main 创建后 set_global_gen 注册),再调用 gen 的 -# 对应方法。签名与旧函数完全一致,调用方零改动。 -# -# 闭包 env 结构: {i8* ptr0, i8* ptr1, ...} (每个 nonlocal 变量一个 i8* 指针) -# 指针指向父函数中变量的 alloca(原始存储位置),父与子共享同一存储, -# 子函数修改对父函数可见(符合 Python nonlocal 语义)。 -# -# 在提升的嵌套函数中: -# 1. 函数签名: define i32 @__closure_{name}(i8* %env) -# 2. 入口处: %env_alloca = alloca i8*; store i8* %env, i8** %env_alloca -# 3. 访问 nonlocal var: -# a. %env_ptr = load i8*, i8** %env_alloca -# b. %addr = gep i8, i8* %env_ptr, i32 (index * 8) -# c. %ptr_addr = bitcast i8* %addr to i8** -# d. %var_ptr_raw = load i8*, i8** %ptr_addr -# e. %var_ptr = bitcast i8* %var_ptr_raw to * -# f. read: %val = load , * %var_ptr -# write: store %new, * %var_ptr -# -# 变量类型通过 HT.get_nonlocal_type() 获取(注册 nonlocal 时记录)。 -# ============================================================ - - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式) -# -# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。 -# 委托函数用本地 _g_gen(cast 成 Generator 类型)调 -# StmtGenMixin 方法,避免函数体 import 包模块与类/模块名歧义。 -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - - -# ============================================================ -# _is_void_type — 判断是否为 Void 类型(非法用作变量类型) -# -# 由于某些路径(如 c.DerefAs 设置的 Pointee 字段访问异常)可能导致 -# 类型被设为 Void 而非 None,这里显式检测 Void 类型并视为无效, -# 回退为 i32,避免生成 "bitcast ... to void*" / "load void, void*" 的非法 IR。 -# ============================================================ -def _is_void_type(ty: llvmlite.LLVMType | t.CPtr) -> int: - """判断是否为 Void 类型,是则返回 1,否则 0(委托到 gen._is_void_type)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_void_type(ty) - return 0 - - -# ============================================================ -# 获取或创建 _env_ptr 变量(存储 env 参数的 alloca) -# ============================================================ -def get_env_ptr_var(trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """获取或创建 _env_ptr 变量(存储闭包 env 指针)(委托到 gen.get_env_ptr_var)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_env_ptr_var(trans) - return None - - -# ============================================================ -# 从 env 加载原始变量指针(i8*)→ 调用方 bitcast 为具体类型 -# -# env 存储指针数组(8 字节/槽),每个指针指向父函数的 alloca。 -# ============================================================ -def _load_raw_var_ptr(trans: HT.Translator | t.CPtr, - name: str) -> llvmlite.Value | t.CPtr: - """从闭包 env 加载 nonlocal 变量的原始指针(i8*)(委托到 gen._load_raw_var_ptr) - - 返回 i8* 类型的 Value,调用方需 bitcast 为具体类型指针后 load/store。 - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._load_raw_var_ptr(trans, name) - return None - - -# ============================================================ -# 加载 nonlocal 变量值 → 返回具体类型的 Value -# -# env 存储指向父函数 alloca 的指针,通过类型恢复 load 正确类型的值。 -# ============================================================ -def load_nonlocal_var(trans: HT.Translator | t.CPtr, - name: str) -> llvmlite.Value | t.CPtr: - """从闭包 env 加载 nonlocal 变量值(委托到 gen.load_nonlocal_var) - - 通过 HT.get_nonlocal_type 获取变量类型,bitcast 原始指针后 load。 - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.load_nonlocal_var(trans, name) - return None - - -# ============================================================ -# 获取 nonlocal 变量指针(用于 store) -# -# 返回具体类型指针(var_ty*),用于直接 store。 -# ============================================================ -def get_nonlocal_var_ptr(trans: HT.Translator | t.CPtr, - name: str) -> llvmlite.Value | t.CPtr: - """获取 nonlocal 变量的存储指针(var_ty*),用于 store 操作(委托到 gen.get_nonlocal_var_ptr) - - 返回的指针指向父函数的 alloca,store 操作对父函数可见。 - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_nonlocal_var_ptr(trans, name) - return None diff --git a/App/lib/core/Handles/HandlesReturn.vp b/App/lib/core/Handles/HandlesReturn.vp deleted file mode 100644 index 58951b2..0000000 --- a/App/lib/core/Handles/HandlesReturn.vp +++ /dev/null @@ -1,33 +0,0 @@ -import t, c -from stdint import * -import ast -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# HandlesReturn - Return 语句处理(迁移完成,保留跨 Mixin 委托壳) -# -# P6 机械化迁移:ReturnHandle 类 → StmtGenCifMixin.translate_return。 -# 分派中枢(StmtGenMixin)经本壳跨类调用(Viper @t.NoVTable 静态绑定下 -# 跨 Mixin self. 调用 mangle 失败,须经模块级委托壳桥回 gen 单例)。 -# 迁移收尾(编译器缺陷修复)后统一删除。 -# ============================================================ - - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - - -# ============================================================ -# translate_return - Return 语句翻译(委托到 gen.translate_return) -# ============================================================ -def translate_return(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 Return 语句,返回 0(委托到 gen.translate_return)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_return(trans, node) - return 0 diff --git a/App/lib/core/Handles/HandlesStruct.vp b/App/lib/core/Handles/HandlesStruct.vp deleted file mode 100644 index 0406754..0000000 --- a/App/lib/core/Handles/HandlesStruct.vp +++ /dev/null @@ -1,544 +0,0 @@ -import t, c -from stdint import * -import memhub -import string -import stdlib -import llvmlite -import stdio -import ast -import hashtable -import viperlib -import lib.core.VLogger as VLogger -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# HandlesStruct - 结构体类型注册和字段查找(P2-2 对象化后的委托层) -# -# 管理 class 定义的结构体类型信息: -# - 类名 → LLVM StructType -# - 字段名 → 字段索引和类型 -# -# P2-2 对象化重构(wiki/14-oo-refactor.md): -# 全部函数已迁移为 lib.core.Gen.StructGenMixin 的方法(全局状态迁入 -# gen 字段),本模块保留同名模块级函数作为"一行委托":延迟 import -# Gen 取全局单例(BuildPipeline/main 创建后 set_global_gen 注册), -# 再调用 gen 的对应方法。签名与旧函数完全一致,调用方零改动。 -# -# FieldEntry/StructEntry 类型与常量保留在本模块(gen 字段类型引用)。 -# ============================================================ - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesType 模式) -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - -STRUCT_MAX: t.CDefine = 512 -# 字段槽位上限制(Generator 43 Mixin 展平 ~120 字段;2026-08-16 追加78:64 -# 截断导致第 9+ 父类字段丢失 → __init__ 写 self.DiagStmtCount "属性写入失败"。 -# 拆分重构使 Generator 父类数增至 43,FIELD_MAX 提至 256 防静默截断) -FIELD_MAX: t.CDefine = 256 -FIELD_NAME_MAX: t.CDefine = 64 -# 多继承(MRO)支持:单类最大父类数 / MRO 链最大长度(Generator 43 父类; -# PARENT_MAX=16 时 _collect_parents/set_parent_names 只收前 16 个 → 第 17+ -# 父类字段丢失 → __init__ 写 self.DiagStmtCount "属性写入失败" 根因) -PARENT_MAX: t.CDefine = 64 -MRO_MAX: t.CDefine = 64 - - -# ============================================================ -# FieldEntry - 字段信息条目 -# ============================================================ -@t.NoVTable -class FieldEntry: - Name: str # 字段名(字符串) - Index: int # 字段在结构体中的索引 - Ty: llvmlite.LLVMType | t.CPtr # 字段的 LLVM 类型 - DefaultVal: ast.AST | t.CPtr # 默认值 AST 节点(None=无默认值) - AnnotClassName: str # 原始类型注解的类名(str 别名在结构体字段中触发编译器 bug,改用显式联合类型) - - -# ============================================================ -# StructEntry - 结构体注册条目 -# ============================================================ -@t.NoVTable -class StructEntry: - Name: str # 类名 - Ty: llvmlite.LLVMType | t.CPtr # LLVM StructType - FieldCount: int # 字段数量 - Fields: FieldEntry | t.CPtr # 字段数组(FIELD_MAX 个槽位) - IsUnion: int # 1=联合体 / 0=普通结构体 - IsOOP: int # 1=OOP结构体(有方法) / 0=纯内存结构体 - HasInit: int # 1=有__init__方法 / 0=无 - HasNew: int # 1=有__new__方法 / 0=无 - HasVTable: int # 1=有虚表 / 0=无虚表 - IsNoVTable: int # 1=明确标记 @t.NoVTable / 0=未标记 - ParentName: str # 父类名(None=无父类,多继承时为第一个父类,兼容旧调用) - ParentNames: t.CSizeT | t.CPtr # 多继承父类名数组(每元素 str 指针,ParentCount 个;stdlib 深拷贝) - ParentCount: t.CInt # 父类数量(0=无父类,1=单继承,>1=多继承) - VTableMethodCount: int # 虚表中的方法数量 - VTableMethods: str # 虚表方法名数组(每个方法名 str,VTableMethodCount 个) - ModuleSha1: str # 定义该类的模块 SHA1(None=无 SHA1) - MethodsEmitted: int # 1=方法体已翻译 / 0=未译(Phase 1a mark_only 未译,Phase B 据此补译) - SpecTriggerSha1: str # 泛型特化类的触发文件 SHA1(None=非特化类)。特化类 ModuleSha1=模板 - # sha1(方法名带模板前缀),作废重译时 reset_module_methods_emitted - # 按触发文件 sha1 精确重置 MethodsEmitted,防特化方法体残留 1 不补译 - # → 链接 undefined symbol(list[ast.ClassDef|t.CPtr].* 根因) - - -def set_stdlib_alloc(flag: int): - """设置 OOM 回收分配模式(委托到 gen.set_stdlib_alloc)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.set_stdlib_alloc(flag) - - -def get_stdlib_alloc() -> int: - """读取 OOM 回收分配模式(委托到 gen.get_stdlib_alloc)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_stdlib_alloc() - return 0 - - -def reset_visible_structs(pool: memhub.MemBuddy | t.CPtr, strict: int): - """重置可见性状态(每个文件翻译前调用,委托到 gen.reset_visible_structs)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.reset_visible_structs(pool, strict) - - -def add_visible_struct(pool: memhub.MemBuddy | t.CPtr, name: str): - """添加可见结构体名(类定义时和 from-import 时调用,委托到 gen.add_visible_struct)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.add_visible_struct(pool, name) - - -def is_struct_visible(name: str) -> int: - """检查结构体是否可见,返回 1=可见 / 0=不可见(委托到 gen.is_struct_visible)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.is_struct_visible(name) - return 0 - - -def init_struct_table(pool: memhub.MemBuddy | t.CPtr) -> int: - """初始化结构体注册表,返回 1 成功(委托到 gen.init_struct_table)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.init_struct_table(pool) - return 0 - - -def _get_struct_entry(i: int) -> StructEntry | t.CPtr: - """获取第 i 个结构体条目(委托到 gen._get_struct_entry)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._get_struct_entry(i) - return None - - -def _get_field_entry(struct_entry: StructEntry | t.CPtr, i: int) -> FieldEntry | t.CPtr: - """获取结构体中第 i 个字段条目(委托到 gen._get_field_entry)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._get_field_entry(struct_entry, i) - return None - - -def register_struct(pool: memhub.MemBuddy | t.CPtr, - name: str, - struct_ty: llvmlite.LLVMType | t.CPtr, - sha1: str = None) -> StructEntry | t.CPtr: - """注册结构体类型,返回 StructEntry 指针(委托到 gen.register_struct)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.register_struct(pool, name, struct_ty, sha1) - return None - - -def set_struct_sha1(pool: memhub.MemBuddy | t.CPtr, - class_name: str, sha1: str) -> int: - """设置结构体所属模块的 SHA1,返回 1=成功 / 0=失败(委托到 gen.set_struct_sha1)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.set_struct_sha1(pool, class_name, sha1) - return 0 - - -def get_struct_sha1(class_name: str) -> str: - """获取结构体所属模块的 SHA1,返回 None=无 SHA1(委托到 gen.get_struct_sha1)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_struct_sha1(class_name) - return None - - -def add_field(pool: memhub.MemBuddy | t.CPtr, - struct_entry: StructEntry | t.CPtr, - field_name: str, - field_ty: llvmlite.LLVMType | t.CPtr, - default_val: ast.AST | t.CPtr = None, - annot_class_name: str = None) -> int: - """向结构体添加字段,返回字段索引(-1 失败,委托到 gen.add_field)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.add_field(pool, struct_entry, field_name, field_ty, - default_val, annot_class_name) - return 0 - - -def get_struct_count() -> int: - """返回当前已注册的结构体数量(委托到 gen.get_struct_count)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_struct_count() - return 0 - - -def reset_module_methods_emitted(sha1: str) -> int: - """回滚指定模块注册类的 MethodsEmitted 标志(Phase A _deps_pending 重试 - 前调用,防 MethodsEmitted 跨遍残留导致类方法缺失——追加87,委托到 gen.reset_module_methods_emitted)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.reset_module_methods_emitted(sha1) - return 0 - - -def find_struct(name: str) -> StructEntry | t.CPtr: - """按类名查找结构体,返回 StructEntry 或 None(委托到 gen.find_struct)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.find_struct(name) - return None - - -def find_struct_by_module(name: str, sha1: str) -> StructEntry | t.CPtr: - """按类名 + SHA1 查找结构体,返回 StructEntry 或 None(委托到 gen.find_struct_by_module)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.find_struct_by_module(name, sha1) - return None - - -def find_struct_by_type(struct_ty: llvmlite.LLVMType | t.CPtr) -> StructEntry | t.CPtr: - """按类型指针查找结构体(指针值比较),返回 StructEntry 或 None(委托到 gen.find_struct_by_type)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.find_struct_by_type(struct_ty) - return None - - -def lookup_field(struct_ty: llvmlite.LLVMType | t.CPtr, - field_name: str) -> FieldEntry | t.CPtr: - """按结构体类型和字段名查找字段信息(委托到 gen.lookup_field)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.lookup_field(struct_ty, field_name) - return None - - -def lookup_field_by_class(class_name: str, - field_name: str, - sha1: str = None) -> FieldEntry | t.CPtr: - """按类名和字段名查找字段信息(委托到 gen.lookup_field_by_class)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.lookup_field_by_class(class_name, field_name, sha1) - return None - - -def get_struct_type(class_name: str) -> llvmlite.LLVMType | t.CPtr: - """按类名获取结构体的 LLVM 类型(委托到 gen.get_struct_type)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_struct_type(class_name) - return None - - -def get_field_by_index(class_name: str, - idx: int) -> FieldEntry | t.CPtr: - """按类名和字段索引获取字段信息(委托到 gen.get_field_by_index)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_field_by_index(class_name, idx) - return None - - -def struct_has_defaults(class_name: str) -> int: - """检查结构体是否有任何带默认值的字段,返回 1=有 / 0=无(委托到 gen.struct_has_defaults)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.struct_has_defaults(class_name) - return 0 - - -def get_struct_type_from_value(val: llvmlite.Value | t.CPtr) -> llvmlite.LLVMType | t.CPtr: - """从 Value 的类型推断结构体类型(委托到 gen.get_struct_type_from_value)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_struct_type_from_value(val) - return None - - -def mark_as_union(name: str) -> int: - """标记已注册的结构体为联合体,返回 1=成功 / 0=失败(委托到 gen.mark_as_union)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.mark_as_union(name) - return 0 - - -def is_union_by_name(name: str) -> int: - """按类名检查是否为联合体,返回 1=是 / 0=否(委托到 gen.is_union_by_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.is_union_by_name(name) - return 0 - - -def is_union_by_type(struct_ty: llvmlite.LLVMType | t.CPtr) -> int: - """按类型指针检查是否为联合体,返回 1=是 / 0=否(委托到 gen.is_union_by_type)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.is_union_by_type(struct_ty) - return 0 - - -def mark_as_oop(name: str) -> int: - """标记已注册的结构体为 OOP,返回 1=成功 / 0=失败(委托到 gen.mark_as_oop)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.mark_as_oop(name) - return 0 - - -def is_oop_by_name(name: str) -> int: - """按类名检查是否为 OOP 结构体,返回 1=是 / 0=否(委托到 gen.is_oop_by_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.is_oop_by_name(name) - return 0 - - -def mark_has_init(name: str) -> int: - """标记结构体拥有 __init__ 方法,返回 1=成功 / 0=失败(委托到 gen.mark_has_init)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.mark_has_init(name) - return 0 - - -def has_init_by_name(name: str) -> int: - """按类名检查是否有 __init__ 方法,返回 1=有 / 0=无(委托到 gen.has_init_by_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.has_init_by_name(name) - return 0 - - -def mark_has_new(name: str) -> int: - """标记结构体拥有 __new__ 方法,返回 1=成功 / 0=失败(委托到 gen.mark_has_new)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.mark_has_new(name) - return 0 - - -def has_new_by_name(name: str) -> int: - """按类名检查是否有 __new__ 方法,返回 1=有 / 0=无(委托到 gen.has_new_by_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.has_new_by_name(name) - return 0 - - -def get_class_name_by_type(pool: memhub.MemBuddy | t.CPtr, - struct_ty: llvmlite.LLVMType | t.CPtr) -> str: - """按类型指针查找类名,返回类名字符串或 None(委托到 gen.get_class_name_by_type)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_class_name_by_type(pool, struct_ty) - return None - - -def _extract_struct_name(ty: llvmlite.LLVMType | t.CPtr) -> str: - """从 LLVMType 提取 Struct 变体的 Name 字段,返回 None 非 Struct(委托到 gen._extract_struct_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._extract_struct_name(ty) - return None - - -def mark_has_vtable(name: str) -> int: - """标记结构体拥有虚表,返回 1=成功 / 0=失败(委托到 gen.mark_has_vtable)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.mark_has_vtable(name) - return 0 - - -def has_vtable_by_name(name: str) -> int: - """按类名检查是否有虚表,返回 1=有 / 0=无(委托到 gen.has_vtable_by_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.has_vtable_by_name(name) - return 0 - - -def mark_novtable(name: str) -> int: - """标记结构体为 NoVTable,返回 1=成功 / 0=失败(委托到 gen.mark_novtable)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.mark_novtable(name) - return 0 - - -def is_novtable_by_name(name: str) -> int: - """按类名检查是否为 NoVTable,返回 1=是 / 0=否(委托到 gen.is_novtable_by_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.is_novtable_by_name(name) - return 0 - - -def set_parent_name(name: str, parent_name: str) -> int: - """设置结构体的父类名,返回 1=成功 / 0=失败(委托到 gen.set_parent_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.set_parent_name(name, parent_name) - return 0 - - -def set_parent_names(pool: memhub.MemBuddy | t.CPtr, - name: str, names_ptr: t.CSizeT | t.CPtr, - count: int) -> int: - """设置结构体的父类名数组(永久池深拷贝,委托到 gen.set_parent_names)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.set_parent_names(pool, name, names_ptr, count) - return 0 - - -def get_parent_count(name: str) -> int: - """获取父类数量(0=无父类,1=单继承,>1=多继承,委托到 gen.get_parent_count)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_parent_count(name) - return 0 - - -def get_parent_name_at(name: str, idx: int) -> str: - """获取第 idx 个父类名,越界返回 None(委托到 gen.get_parent_name_at)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_parent_name_at(name, idx) - return None - - -def get_mro_chain(pool: memhub.MemBuddy | t.CPtr, - name: str) -> t.CSizeT | t.CPtr: - """MRO 线性化类名数组(深度优先 + 声明顺序 + 去重,含自身,委托到 gen.get_mro_chain)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_mro_chain(pool, name) - return None - - -def get_parent_name(name: str) -> str: - """获取结构体的父类名,返回 None=无父类(委托到 gen.get_parent_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_parent_name(name) - return None - - -def set_vtable_methods(name: str, methods: str, count: int) -> int: - """设置虚表方法名数组,返回 1=成功 / 0=失败(委托到 gen.set_vtable_methods)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.set_vtable_methods(name, methods, count) - return 0 - - -def get_vtable_method_index(name: str, method_name: str) -> int: - """获取方法在虚表中的索引,返回 -1=未找到(委托到 gen.get_vtable_method_index)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_vtable_method_index(name, method_name) - return 0 - - -def get_vtable_method_count(name: str) -> int: - """获取虚表方法数量(委托到 gen.get_vtable_method_count)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_vtable_method_count(name) - return 0 - - -def get_vtable_method_name(name: str, idx: int) -> str: - """获取虚表中第 idx 个方法名,返回 None=越界(委托到 gen.get_vtable_method_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_vtable_method_name(name, idx) - return None - - -def get_field_count(name: str) -> int: - """获取结构体字段数量,返回 -1=未找到(委托到 gen.get_field_count)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_field_count(name) - return 0 - - -def ensure_struct_def_in_module(pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - ty: llvmlite.LLVMType | t.CPtr): - """确保跨模块结构体的完整定义在当前模块中可用(委托到 gen.ensure_struct_def_in_module)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.ensure_struct_def_in_module(pool, mod, ty) - - -def _ensure_field_types_in_module(pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - ty: llvmlite.LLVMType | t.CPtr): - """递归扫描类型树,确保值类型子结构体有完整定义(委托到 gen._ensure_field_types_in_module)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g._ensure_field_types_in_module(pool, mod, ty) - - -def get_field_name_ptr(fe: FieldEntry | t.CPtr) -> str: - """获取 FieldEntry 的字段名,返回 None=未设置(委托到 gen.get_field_name_ptr)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_field_name_ptr(fe) - return None - - -def get_field_type_ptr(fe: FieldEntry | t.CPtr) -> llvmlite.LLVMType | t.CPtr: - """获取 FieldEntry 的字段类型,返回 None=未设置(委托到 gen.get_field_type_ptr)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_field_type_ptr(fe) - return None - - -def get_field_default_ptr(fe: FieldEntry | t.CPtr) -> ast.AST | t.CPtr: - """获取 FieldEntry 的默认值 AST 节点,返回 None=无默认值(委托到 gen.get_field_default_ptr)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_field_default_ptr(fe) - return None - - -def get_field_annot_class_name(fe: FieldEntry | t.CPtr) -> str: - """获取 FieldEntry 的原始类型注解类名,返回 None=未设置(委托到 gen.get_field_annot_class_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_field_annot_class_name(fe) - return None diff --git a/App/lib/core/Handles/HandlesTranslator.vp b/App/lib/core/Handles/HandlesTranslator.vp index 81506a4..b8133cf 100644 --- a/App/lib/core/Handles/HandlesTranslator.vp +++ b/App/lib/core/Handles/HandlesTranslator.vp @@ -1,611 +1,599 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import viperlib -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesMain as HandlesMain -import lib.core.Handles.HandlesAssign as HandlesAssign -import lib.core.Handles.HandlesReturn as HandlesReturn -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.Handles.HandlesAugAssign as HandlesAugAssign -import lib.core.Handles.HandlesIf as HandlesIf -import lib.core.Handles.HandlesWhile as HandlesWhile -import lib.core.Handles.HandlesFor as HandlesFor -import lib.core.Handles.HandlesMatch as HandlesMatch -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesFunctions as HandlesFunctions -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.Projectrans.Config as Config -import lib.core.StubMergerBuild as StubMergerBuild -import lib.core.Handles.ExprCallHandle as ExprCallHandle -import lib.core.Handles.ExprCallTable as ExprCallTable -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# HandlesTranslator - 翻译器状态管理 + 主入口 -# -# 从 translator.py 拆分出来,负责: -# 1. Translator 类 - 状态管理(Module, 变量表, 函数表, 导入) -# 2. translate() - 主翻译入口 -# 3. dump_ir() - IR 输出 -# -# 语句/表达式翻译全部委托给 Handles 模块: -# HandlesMain - wrapper main 创建 + children 遍历 -# HandlesBody - 语句分派 -# HandlesExpr - 表达式翻译 -# HandlesFunctions - 函数定义处理 -# 注意:str = bytes = t.CChar | t.CPtr = i8* -# -# P6-E 对象化重构:模块级 global/nonlocal 名称管理函数已迁移为 -# lib.core.Gen.TranslatorGenMixin 的方法,本模块保留同名模块级 -# 函数作为"一行委托"(同 P2-P5 模式)。Translator 类保留在本模块。 -# ============================================================ - -# 常量 -MAX_VARS: t.CDefine = 1024 -MAX_FUNCS: t.CDefine = 1024 -MAX_GLOBAL_NAMES: t.CDefine = 32 - - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - - -@t.NoVTable -class Translator: - """翻译器:管理编译状态,委托 Handles 模块执行翻译""" - - # LLVM 上下文(共享状态) - Module: llvmlite.LLVMModule | t.CPtr - Pool: memhub.MemBuddy | t.CPtr - - # 函数表 - _funcs: HandlesExprCall.FuncEntry | t.CPtr - _func_count: t.CInt - - # 导入模块跟踪 - _imported_modules: str - _from_imports: str - - # 当前翻译上下文 - _cur_func: llvmlite.Function | t.CPtr - _cur_builder: llvmlite.IRBuilder | t.CPtr - - # 当前赋值语句的注解节点(AnnAssign 翻译 rhs 前设置,Assign 翻译前清空)。 - # 供 c.Deref(i8*) 推断读取宽度:v: int = c.Deref(p) → bitcast i32* load, - # 对齐 TPC HandlesSpecialCall._infer_deref_target_type(DictTest 500→-12 根因: - # i8* Deref 固定读 1 字节 + sext 截断)。 - CurAssignAnnot: ast.AST | t.CPtr - - # 当前赋值语句的 RHS 节点(AnnAssign 翻译 rhs 前设置,rhs 翻译后清除)。 - # 供 c.Deref 判定"是否为赋值直接 RHS":仅 v: int = c.Deref(p) 时用 - # CurAssignAnnot 推断读取宽度;嵌套在 while 条件/比较/binop/类型转换 - # 调用中(如 while c.Deref(p) != 0、total += t.CInt(c.Deref(p)))不推断, - # 否则 i8* 会被残留 CurAssignAnnot 误判为 i32* 读 4 字节(对齐 TPC - # _infer_deref_target_type 的直接 RHS 检查)。 - CurAssignNode: ast.AST | t.CPtr - - # 循环控制流目标(break/continue) - _break_bb: llvmlite.BasicBlock | t.CPtr - _continue_bb: llvmlite.BasicBlock | t.CPtr - - # 独立标签计数器(不与 builder.Counter 共享,避免 SSA 编号非单调) - _label_counter: t.CInt - - # 追加90:控制流 merge 块可达性(1=有 br 进入可达/0=全分支 return 结构性不可达) - _ctrl_merge_reachable: t.CInt - - # global 声明的变量名集合(当前函数内) - _global_names: str - _global_name_count: t.CInt - - # nonlocal 声明的变量名集合(当前函数内) - _nonlocal_names: str - _nonlocal_name_count: t.CInt - # nonlocal 变量的类型信息(LLVMType 指针数组,与 _nonlocal_names 一一对应) - # 用于 env 指针数组方案:子函数访问 nonlocal 变量时需要知道原始类型 - _nonlocal_types: str - - # 闭包相关:当前函数名(用于嵌套函数提升命名) - _cur_func_name: str - - # *args 变长参数支持:当前函数的 va_list 指针(i8* alloca) - # 仅当函数声明了 *args 时设置,供 arg(type) 糖函数使用 - _va_list_ptr: llvmlite.Value | t.CPtr - # *args 参数名(如 "args"),用于符号表注册 - _vararg_name: str - - # OOP iter 协议:当前 __next__ 方法的隐藏 stop-flag 参数(i1*)。 - # _translate_method 注入 __stop_iter_flag__ 参数时设置;translate_raise - # 检测 raise StopIteration 时对该指针 store 1(对齐 TPC HandlesRaise.py)。 - # 非 __next__ 函数中为 None。 - _stop_iter_flag_ptr: llvmlite.Value | t.CPtr - - # try-except 机制(对齐 TPC HandlesTry.py):当前最内层 try 的 - # 分发块 + 异常编码/消息 alloca。translate_try 设置,translate_raise - # 与调用侧 EH 检测写入/跳转。try 外为 None。 - _eh_dispatch_bb: llvmlite.BasicBlock | t.CPtr - _eh_code_ptr: llvmlite.Value | t.CPtr - _eh_msg_ptr: llvmlite.Value | t.CPtr - # 当前函数的 __eh_msg_out__(i8**)/__eh_code_out__(i32*)输出参数 - # (函数签名含 raise 时由 translate_function_def/_translate_method 注入)。 - # 无 EH 参数时 _cur_func_has_eh == 0。 - _eh_msg_out_param: llvmlite.Value | t.CPtr - _eh_code_out_param: llvmlite.Value | t.CPtr - _cur_func_has_eh: int - - # 模块 SHA1 前缀(16 字符),用于函数名混淆(SHA1 命名空间) - ModuleSha1: str - # 当前文件所属包名(如 "llvmlite"),用于解析相对导入(from . import ...) - # None 表示当前文件是顶级模块(无包),相对导入无法解析 - CurrentPackage: str - # 闭包 env 中的 nonlocal 变量偏移映射(每个 nonlocal 变量在 env 中的字节偏移) - _closure_env_offsets: t.CInt - _closure_env_count: t.CInt - # lambda 表达式全局唯一 ID 计数器(生成提升函数名 __lambda_{id}) - # 独立于 _closure_env_count:后者随函数进入被 clear_scope_names 重置, - # lambda ID 需跨函数全局唯一(提升函数名避免冲突) - _lambda_count: t.CInt - # 函数链内 nonlocal 变量集合(预扫描收集,含嵌套函数声明的 nonlocal)。 - # 用于"不同层捕获不同变量"场景(如 level1→a, level2→b):b 定义在最外层 - # 但 level1 不捕获——level1 env 无 b 槽,level2 无法经 env 链获取 b 的堆。 - # 解决:在最外层函数中为链内所有 nonlocal 建堆,并把堆地址 store 到 - # 模块级映射变量 @nlheap.{sha1}.{name};内层闭包创建时从映射 load。 - _nl_chain_names: t.CVoid | t.CPtr - _nl_chain_count: t.CInt - # 链内 nonlocal 堆预建标志(每函数只建一次):translate_function_def 进入 - # 新函数时重置为 0;_prepare_chain_nonlocals 首次调用置 1。多个嵌套函数 - # 定义共享同一堆(防重复 malloc + 二次重定向 VarEntry.Alloca)。 - _nl_chain_done: t.CInt - - # 泛型特化上下文:当前正在特化的类型参数名/实参名列表 - # 由 _specialize_generic_class 设置,方法体翻译时用于将 T 替换为具体类型 - # None 表示不在泛型特化上下文中 - GenericTypeParamNames: list[str] | t.CPtr - GenericTypeArgs: list[str] | t.CPtr - - # Phase 1a 声明模式标志:1=只注册 struct/enum/union 不翻译代码体,0=全量翻译 - _declare_only: t.CInt - - # Phase A 依赖未就绪标志:1=本文件翻译时依赖模块的 text.ll 尚未生成 - # (同项目源文件按顺序翻译,main.vp 先于其 import 的 mbuddytest.vp), - # 跨模块函数返回类型无法精确解析。Phase A 多遍循环据此下遍重试。 - _deps_pending: t.CInt - - # 嵌套作用域符号表 - SymTab: HandlesVar.SymbolTable | t.CPtr - - def __init__(self): - self.Module = None - self.Pool = None - self._funcs = None - self._func_count = 0 - self._cur_func = None - self._cur_builder = None - self._break_bb = None - self._continue_bb = None - self._label_counter = 0 - self._imported_modules = None - self._from_imports = None - self._global_names = None - self._global_name_count = 0 - self._nonlocal_names = None - self._nonlocal_name_count = 0 - self._nonlocal_types = None - self._cur_func_name = None - self._va_list_ptr = None - self._vararg_name = None - self._stop_iter_flag_ptr = None - self._eh_dispatch_bb = None - self._eh_code_ptr = None - self._eh_msg_ptr = None - self._eh_msg_out_param = None - self._eh_code_out_param = None - self._cur_func_has_eh = 0 - self.ModuleSha1 = None - self.CurrentPackage = None - self._closure_env_offsets = 0 - self._closure_env_count = 0 - self._lambda_count = 0 - self._nl_chain_names = None - self._nl_chain_count = 0 - self._nl_chain_done = 0 - self.GenericTypeParamNames = None - self.GenericTypeArgs = None - self._declare_only = 0 - self._deps_pending = 0 - self.SymTab = None - - # ============================================================ - # 状态初始化 - # ============================================================ - def _init_state(self, pool: memhub.MemBuddy | t.CPtr): - """初始化变量表、函数表和子 Handle""" - self.Pool = pool - if self._funcs is None: - self._funcs = ExprCallTable.init_func_table(pool, MAX_FUNCS) - # 嵌套作用域符号表(新版) - if self.SymTab is None: - self.SymTab = HandlesVar.init_symbol_table(pool) - # global/nonlocal 名称集合缓冲区(32 个 char* 指针 = 256 字节) - if self._global_names is None: - self._global_names = stdlib.malloc(MAX_GLOBAL_NAMES * 8) - if self._global_names is not None: - string.memset(self._global_names, 0, MAX_GLOBAL_NAMES * 8) - self._global_name_count = 0 - if self._nonlocal_names is None: - self._nonlocal_names = stdlib.malloc(MAX_GLOBAL_NAMES * 8) - if self._nonlocal_names is not None: - string.memset(self._nonlocal_names, 0, MAX_GLOBAL_NAMES * 8) - self._nonlocal_name_count = 0 - # nonlocal 变量类型数组(LLVMType 指针数组,与 _nonlocal_names 一一对应) - if self._nonlocal_types is None: - self._nonlocal_types = stdlib.malloc(MAX_GLOBAL_NAMES * 8) - if self._nonlocal_types is not None: - string.memset(self._nonlocal_types, 0, MAX_GLOBAL_NAMES * 8) - - # ============================================================ - # 主翻译入口 - # ============================================================ - def translate(self, tree: ast.AST | t.CPtr) -> int: - """将 AST 翻译为 LLVM IR""" - if tree is None: - return 1 - if _mbuddy is None: - return 1 - - pool: memhub.MemBuddy | t.CPtr = _mbuddy - - # 初始化状态 - self._init_state(pool) - - # 创建 LLVM 模块 - mod: llvmlite.LLVMModule | t.CPtr = llvmlite.new_module(pool, "main") - if mod is None: - VLogger.error("NewModule returned NULL", "TR") - return 1 - self.Module = mod - - # 设置目标(优先使用 project.vpj 中的配置) - triple: str = Config.TargetTriple - if triple is None: - triple = "x86_64-pc-windows-msvc" - llvmlite.module_set_target(mod, triple) - - # 类型 - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - # 声明 printf - printf_func: llvmlite.Function | t.CPtr = llvmlite.create_declare( - pool, mod, "printf", i32_ty) - if printf_func is None: - VLogger.error("CreateDeclare printf returned NULL", "TR") - return 1 - llvmlite.add_param(pool, printf_func, i8_ptr_ty, "fmt") - printf_func.IsVarArg = 1 - # 声明 LLVM va_start/va_end intrinsic(供 *args 函数体内使用) - # declare void @llvm.va_start(i8*) - # declare void @llvm.va_end(i8*) - void_ty_decl: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) - va_start_func: llvmlite.Function | t.CPtr = llvmlite.create_declare( - pool, mod, "llvm.va_start", void_ty_decl) - if va_start_func is not None: - llvmlite.add_param(pool, va_start_func, i8_ptr_ty, "ap") - va_end_func: llvmlite.Function | t.CPtr = llvmlite.create_declare( - pool, mod, "llvm.va_end", void_ty_decl) - if va_end_func is not None: - llvmlite.add_param(pool, va_end_func, i8_ptr_ty, "ap") - - # 声明 malloc(闭包分配用) - malloc_func: llvmlite.Function | t.CPtr = llvmlite.create_declare( - pool, mod, "malloc", i8_ptr_ty) - if malloc_func is not None: - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - llvmlite.add_param(pool, malloc_func, i64_ty, "size") - - # 检查用户是否定义了 main 函数 - has_user_main: int = 0 - ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children - if ch is not None: - cn_count: t.CSizeT = len(ch) - for ci in range(cn_count): - child: ast.AST | t.CPtr = ch.get(ci) - if child is not None and child.kind() == ast.ASTKind.FunctionDef: - fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child) - if fd is not None and fd.name is not None: - if string.strcmp(fd.name, "main") == 0: - has_user_main = 1 - break - - if self._declare_only != 0: - # Phase 1a-pre(2=import扫描) / Phase 1a(1=struct注册): 只处理模块级,不创建 main 函数和 builder - self._translate_module_level(pool, mod, tree) - elif has_user_main == 0: - # 无用户 main → 只翻译模块级语句,不创建 wrapper main - # 修复:避免每个文件都生成 define i32 @main() 导致链接时 main 冲突 - # 只有包含 def main() 的入口文件才会有 define i32 @main() - self._translate_module_level(pool, mod, tree) - else: - # 用户已定义 main → 委托 HandlesMain 翻译模块级 - self._translate_module_level(pool, mod, tree) - - return 0 - - # ============================================================ - # 包装 main 函数(无用户 main 时)→ 委托 HandlesMain - # ============================================================ - def _translate_wrapper_main(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - tree: ast.AST | t.CPtr, - i32_ty: llvmlite.LLVMType | t.CPtr): - """委托 HandlesMain.create_wrapper_main() 创建包装 main(trans 单参)""" - added: int = HandlesMain.create_wrapper_main(self, tree, i32_ty) - - # ============================================================ - # 模块级翻译(用户已定义 main)→ 委托 HandlesMain - # ============================================================ - def _translate_module_level(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - tree: ast.AST | t.CPtr): - """委托 HandlesMain.translate_children() 翻译模块级语句(trans 单参)""" - # 全量翻译模式下,先处理导入语句,再创建前向声明,解决前向引用问题 - if self._declare_only == 0: - # 预处理导入语句,确保 _imported_modules 和 _from_imports 已填充 - # (前向声明需要解析类型注解,如 t.CArray[str] 依赖 t 模块已导入) - # 记录最后处理的 import 行号,供 vpi 注入错误上下文帧定位 - cur_imp_lineno: int = 0 - ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children - if ch is not None: - cn_count: t.CSizeT = len(ch) - for ci in range(cn_count): - child: ast.AST | t.CPtr = ch.get(ci) - if child is None: - continue - kd: int = child.kind() - if kd == ast.ASTKind.Import: - cur_imp_lineno = child.lineno - HandlesImports.translate_import(self, child) - elif kd == ast.ASTKind.ImportFrom: - cur_imp_lineno = child.lineno - HandlesImports.translate_import_from_module(self, child) - HandlesImports.translate_import_from_names(self, child) - # 对齐 TPC _inject_auto_imports:检测源文件对 list/dict 容器的使用 - # (裸名注解 d: dict / 构造 dict(...) / 下标 list[T]),自动把容器 - # 类标记为可见结构体。背景:_list.vp/_dict.vp 定义内建容器类且已由 - # Phase1 注册,但源文件不显式 import 它们(TPC 在翻译前自动注入 - # import _list/_dict);TPV 用可见性机制等效替代——否则裸名 - # `d: dict` 注解 resolve_annotation_type 时 is_struct_visible=0 - # 解析失败(DictTest 的 "变量类型注解解析失败")。 - self._inject_auto_container_visibility(pool, tree) - # 扫描当前模块的 CTypedef 声明已由 Phase1 1b 文本扫描注册 - # (RegisterCTypedefFromSource,见 Phase1Main.vp)——AST 字符串字段 - # token 零拷贝指向 src_buf,跨阶段内容不稳定,此处 AST 扫描读 attr - # 会 0xC0000005(stdint.vp 崩溃根因),故移除。 - # 跨模块 .vpi 注入:加载依赖模块的 .vpi 文件, - # 将函数 declare 声明注入到当前模块,解决跨模块函数调用找不到函数的问题 - # 严格保证 declare_only == 0 时才注入(避免 Phase A-pre-inc 死锁) - if self._imported_modules is not None: - import lib.core.StubMerger as StubMerger - # 错误上下文帧:当前模块触发依赖 stub 加载的 import 位置 - HandlesType.push_trace(HandlesType.get_current_file(), cur_imp_lineno) - StubMergerBuild.LoadDepVpiIntoModule( - pool, mod, self._imported_modules, self._from_imports, - HandlesType.get_temp_dir(), self) - HandlesType.pop_trace() - # 预注册模块级变量(AnnAssign/Assign)到 SymTab - # 解决时序问题:class Logger 的 __init__ 引用 _mbuddy 时, - # _mbuddy 的 AnnAssign 在 AST 中位于 class Logger 之后, - # 按 AST 顺序翻译时 _mbuddy 尚未注册 → lookup_var 返回 None → rhs_val is None - # 预处理先于 translate_children 注册所有模块级变量, - # 后续 translate_children 遍历到同一 AnnAssign 时 handle_module_level_var - # 通过 lookup_module_var 检测已存在并跳过(HandlesMain.py:206-209) - if ch is not None: - for ci in range(cn_count): - child: ast.AST | t.CPtr = ch.get(ci) - if child is None: - continue - kd_mv: int = child.kind() - if kd_mv == ast.ASTKind.AnnAssign or kd_mv == ast.ASTKind.Assign: - HandlesMain.handle_module_level_var(self, child) - # 创建前向声明 - HandlesFunctions.forward_declare_functions(self, tree) - added: int = HandlesMain.translate_children(self, tree) - - # ============================================================ - # 容器模块自动可见性注入(对齐 TPC _inject_auto_imports) - # - # TPC 在翻译前自动注入 `import _list / import _dict (+json)` 到源文件, - # 使 list/dict 内建容器类在符号表中可见。TPV 用可见性机制等效替代: - # _list.vp/_dict.vp 已由 Phase1 注册(可达集合含它们),这里只需在 - # 当前文件翻译时把容器类名标记为可见结构体,裸名注解/构造即可解析。 - # - # 检测模式(与 TPC Phase2Translator._inject_auto_imports 一致): - # - AnnAssign 注解裸名 Name(list/dict):d: dict - # - 构造调用 func 裸名 Name(list/dict):dict(bd) - # - Subscript 的 value 裸名 Name(list/dict):list[int] - # ============================================================ - def _inject_auto_container_visibility(self, pool: memhub.MemBuddy | t.CPtr, - tree: ast.AST | t.CPtr): - """检测 list/dict 容器使用,注入容器类可见性""" - if tree is None or tree.children is None: - return - # 用栈式缓冲区传递检测结果(跨函数参数用 4 字节 int 指针) - need_list_box: t.CPtr = stdlib.malloc(4) - need_dict_box: t.CPtr = stdlib.malloc(4) - if need_list_box is None or need_dict_box is None: - if need_list_box is not None: - stdlib.free(need_list_box) - if need_dict_box is not None: - stdlib.free(need_dict_box) - return - need_list_box[0] = 0 - need_dict_box[0] = 0 - self._scan_container_usage(tree, need_list_box, need_dict_box) - if need_dict_box[0] != 0: - # dict 类可见 + _dict 模块导入(构造/方法调用的 SHA1 解析) - HandlesStruct.add_visible_struct(pool, "dict") - if self._imported_modules is None or \ - HandlesImports.is_module_imported(self._imported_modules, "_dict") == 0: - self._imported_modules = HandlesImports.add_imported_module( - pool, self._imported_modules, "_dict") - if need_list_box[0] != 0: - HandlesStruct.add_visible_struct(pool, "list") - if self._imported_modules is None or \ - HandlesImports.is_module_imported(self._imported_modules, "_list") == 0: - self._imported_modules = HandlesImports.add_imported_module( - pool, self._imported_modules, "_list") - stdlib.free(need_list_box) - stdlib.free(need_dict_box) - - def _scan_container_usage(self, node: ast.AST | t.CPtr, - need_list_box: t.CPtr, - need_dict_box: t.CPtr): - """递归扫描 AST 语句结构,检测 list/dict 容器使用""" - if node is None: - return - k: int = node.kind() - if k == ast.ASTKind.AnnAssign: - aa_s: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) - if aa_s.annotation is not None: - self._check_container_type_node(aa_s.annotation, need_list_box, need_dict_box) - elif k == ast.ASTKind.Call: - cl_s: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) - if cl_s.func is not None: - self._check_container_type_node(cl_s.func, need_list_box, need_dict_box) - elif k == ast.ASTKind.Subscript: - sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - if sub_s.value is not None: - self._check_container_type_node(sub_s.value, need_list_box, need_dict_box) - elif k == ast.ASTKind.List: - # [] 字面量:容器模板仍需注册 - need_list_box[0] = 1 - elif k == ast.ASTKind.Dict: - # {} 字面量:容器模板仍需注册 - need_dict_box[0] = 1 - # 递归语句块子节点 - if node.children is not None: - ch_s: list[ast.AST | t.CPtr] | t.CPtr = node.children - n_s: t.CSizeT = len(ch_s) - for ci_s in range(n_s): - self._scan_container_usage(ch_s.get(ci_s), need_list_box, need_dict_box) - - def _check_container_type_node(self, node: ast.AST | t.CPtr, - need_list_box: t.CPtr, - need_dict_box: t.CPtr): - """检测类型位置节点是否为 list/dict(支持 Name 与 Subscript 外层)""" - if node is None: - return - k: int = node.kind() - if k == ast.ASTKind.Name: - nm_s: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm_s.id is not None: - if string.strcmp(nm_s.id, "dict") == 0: - need_dict_box[0] = 1 - elif string.strcmp(nm_s.id, "list") == 0: - need_list_box[0] = 1 - elif k == ast.ASTKind.Subscript: - sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - if sub_s.value is not None: - self._check_container_type_node(sub_s.value, need_list_box, need_dict_box) - - - # ============================================================ - # IR 输出 - # ============================================================ - def dump_ir(self, buf: bytes, size: t.CSizeT, mode: int): - """将 LLVM IR 输出到缓冲区 - - mode: 0=完整, 1=stub(仅声明), 2=text(仅代码) - """ - if self.Module is None or buf is None: - return - if _mbuddy is None: - return - buf[0] = '\0' - llvmlite.LLVMModulePrint(buf, size, self.Module, _mbuddy, mode) - - -# ============================================================ -# global/nonlocal 名称管理(模块级辅助函数,委托到 gen 方法) -# ============================================================ -def add_global_name(trans: HT.Translator | t.CPtr, name: str): - """添加一个 global 变量名(委托到 gen.add_global_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.add_global_name(trans, name) - - -def is_global_name(trans: HT.Translator | t.CPtr, name: str) -> int: - """检查 name 是否在当前函数的 global 集合中(委托到 gen.is_global_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.is_global_name(trans, name) - return 0 - - -def add_nonlocal_name(trans: HT.Translator | t.CPtr, name: str, - var_ty: llvmlite.LLVMType | t.CPtr = None): - """添加一个 nonlocal 变量名(委托到 gen.add_nonlocal_name) - - Args: - name: nonlocal 变量名 - var_ty: 变量的 LLVM 类型(用于 env 指针数组方案的类型恢复, - None 时回退为 i32) - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.add_nonlocal_name(trans, name, var_ty) - - -def get_nonlocal_type(trans: HT.Translator | t.CPtr, - name: str) -> llvmlite.LLVMType | t.CPtr: - """获取 nonlocal 变量的 LLVM 类型(委托到 gen.get_nonlocal_type) - - Returns: 找到的类型指针,找不到返回 None - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_nonlocal_type(trans, name) - return None - - -def is_nonlocal_name(trans: HT.Translator | t.CPtr, name: str) -> int: - """检查 name 是否在当前函数的 nonlocal 集合中(委托到 gen.is_nonlocal_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.is_nonlocal_name(trans, name) - return 0 - - -def get_nonlocal_index(trans: HT.Translator | t.CPtr, name: str) -> int: - """获取 nonlocal 变量在 env 中的索引(0-based),找不到返回 -1(委托到 gen.get_nonlocal_index)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_nonlocal_index(trans, name) - return 0 - - -def clear_scope_names(trans: HT.Translator | t.CPtr): - """清空当前函数的 global/nonlocal 名称集合(进入新函数时调用)(委托到 gen.clear_scope_names)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.clear_scope_names(trans) - - -# 全局 mbuddy 指针 -_mbuddy: memhub.MemBuddy | t.CPtr +import lib.core.Gen.GenApi as GenApi +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.TranslatorGenMixin as TranslatorGenMixin +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.Projectrans.Config as Config +import lib.core.StubMergerBuild as StubMergerBuild +import lib.core.Handles.ExprCallTable as ExprCallTable +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Gen.Generator as Generator + + +# ============================================================ +# HandlesTranslator - 翻译器状态管理 + 主入口 +# +# 从 translator.py 拆分出来,负责: +# 1. Translator 类 - 状态管理(Module, 变量表, 函数表, 导入) +# 2. translate() - 主翻译入口 +# 3. dump_ir() - IR 输出 +# +# 语句/表达式翻译全部委托给 Handles 模块: +# HandlesMain - wrapper main 创建 + children 遍历 +# HandlesBody - 语句分派 +# HandlesExpr - 表达式翻译 +# HandlesFunctions - 函数定义处理 +# 注意:str = bytes = t.CChar | t.CPtr = i8* +# +# P6-E 对象化重构:模块级 global/nonlocal 名称管理函数已迁移为 +# lib.core.Gen.TranslatorGenMixin 的方法,本模块保留同名模块级 +# 函数作为"一行委托"(同 P2-P5 模式)。Translator 类保留在本模块。 +# ============================================================ + +# 常量 +MAX_VARS: t.CDefine = 1024 +MAX_FUNCS: t.CDefine = 1024 +MAX_GLOBAL_NAMES: t.CDefine = 32 + + +# ============================================================ +# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) +# ============================================================ +_g_gen: Generator.Generator | t.CPtr = None + + +@t.NoVTable +class Translator: + """翻译器:管理编译状态,委托 Handles 模块执行翻译""" + + # LLVM 上下文(共享状态) + Module: llvmlite.LLVMModule | t.CPtr + Pool: memhub.MemBuddy | t.CPtr + + # 函数表 + _funcs: GenTypes.FuncEntry | t.CPtr + _func_count: t.CInt + + # 导入模块跟踪 + _imported_modules: str + _from_imports: str + + # 当前翻译上下文 + _cur_func: llvmlite.Function | t.CPtr + _cur_builder: llvmlite.IRBuilder | t.CPtr + + # 当前赋值语句的注解节点(AnnAssign 翻译 rhs 前设置,Assign 翻译前清空)。 + # 供 c.Deref(i8*) 推断读取宽度:v: int = c.Deref(p) → bitcast i32* load, + # 对齐 TPC HandlesSpecialCall._infer_deref_target_type(DictTest 500→-12 根因: + # i8* Deref 固定读 1 字节 + sext 截断)。 + CurAssignAnnot: ast.AST | t.CPtr + + # 当前赋值语句的 RHS 节点(AnnAssign 翻译 rhs 前设置,rhs 翻译后清除)。 + # 供 c.Deref 判定"是否为赋值直接 RHS":仅 v: int = c.Deref(p) 时用 + # CurAssignAnnot 推断读取宽度;嵌套在 while 条件/比较/binop/类型转换 + # 调用中(如 while c.Deref(p) != 0、total += t.CInt(c.Deref(p)))不推断, + # 否则 i8* 会被残留 CurAssignAnnot 误判为 i32* 读 4 字节(对齐 TPC + # _infer_deref_target_type 的直接 RHS 检查)。 + CurAssignNode: ast.AST | t.CPtr + + # 循环控制流目标(break/continue) + _break_bb: llvmlite.BasicBlock | t.CPtr + _continue_bb: llvmlite.BasicBlock | t.CPtr + + # 独立标签计数器(不与 builder.Counter 共享,避免 SSA 编号非单调) + _label_counter: t.CInt + + # 追加90:控制流 merge 块可达性(1=有 br 进入可达/0=全分支 return 结构性不可达) + _ctrl_merge_reachable: t.CInt + + # global 声明的变量名集合(当前函数内) + _global_names: str + _global_name_count: t.CInt + + # nonlocal 声明的变量名集合(当前函数内) + _nonlocal_names: str + _nonlocal_name_count: t.CInt + # nonlocal 变量的类型信息(LLVMType 指针数组,与 _nonlocal_names 一一对应) + # 用于 env 指针数组方案:子函数访问 nonlocal 变量时需要知道原始类型 + _nonlocal_types: str + + # 闭包相关:当前函数名(用于嵌套函数提升命名) + _cur_func_name: str + + # *args 变长参数支持:当前函数的 va_list 指针(i8* alloca) + # 仅当函数声明了 *args 时设置,供 arg(type) 糖函数使用 + _va_list_ptr: llvmlite.Value | t.CPtr + # *args 参数名(如 "args"),用于符号表注册 + _vararg_name: str + + # OOP iter 协议:当前 __next__ 方法的隐藏 stop-flag 参数(i1*)。 + # _translate_method 注入 __stop_iter_flag__ 参数时设置;translate_raise + # 检测 raise StopIteration 时对该指针 store 1(对齐 TPC HandlesRaise.py)。 + # 非 __next__ 函数中为 None。 + _stop_iter_flag_ptr: llvmlite.Value | t.CPtr + + # try-except 机制(对齐 TPC HandlesTry.py):当前最内层 try 的 + # 分发块 + 异常编码/消息 alloca。translate_try 设置,translate_raise + # 与调用侧 EH 检测写入/跳转。try 外为 None。 + _eh_dispatch_bb: llvmlite.BasicBlock | t.CPtr + _eh_code_ptr: llvmlite.Value | t.CPtr + _eh_msg_ptr: llvmlite.Value | t.CPtr + # 当前函数的 __eh_msg_out__(i8**)/__eh_code_out__(i32*)输出参数 + # (函数签名含 raise 时由 translate_function_def/_translate_method 注入)。 + # 无 EH 参数时 _cur_func_has_eh == 0。 + _eh_msg_out_param: llvmlite.Value | t.CPtr + _eh_code_out_param: llvmlite.Value | t.CPtr + _cur_func_has_eh: int + + # 模块 SHA1 前缀(16 字符),用于函数名混淆(SHA1 命名空间) + ModuleSha1: str + # 当前文件所属包名(如 "llvmlite"),用于解析相对导入(from . import ...) + # None 表示当前文件是顶级模块(无包),相对导入无法解析 + CurrentPackage: str + # 闭包 env 中的 nonlocal 变量偏移映射(每个 nonlocal 变量在 env 中的字节偏移) + _closure_env_offsets: t.CInt + _closure_env_count: t.CInt + # lambda 表达式全局唯一 ID 计数器(生成提升函数名 __lambda_{id}) + # 独立于 _closure_env_count:后者随函数进入被 clear_scope_names 重置, + # lambda ID 需跨函数全局唯一(提升函数名避免冲突) + _lambda_count: t.CInt + # 函数链内 nonlocal 变量集合(预扫描收集,含嵌套函数声明的 nonlocal)。 + # 用于"不同层捕获不同变量"场景(如 level1→a, level2→b):b 定义在最外层 + # 但 level1 不捕获——level1 env 无 b 槽,level2 无法经 env 链获取 b 的堆。 + # 解决:在最外层函数中为链内所有 nonlocal 建堆,并把堆地址 store 到 + # 模块级映射变量 @nlheap.{sha1}.{name};内层闭包创建时从映射 load。 + _nl_chain_names: t.CVoid | t.CPtr + _nl_chain_count: t.CInt + # 链内 nonlocal 堆预建标志(每函数只建一次):translate_function_def 进入 + # 新函数时重置为 0;_prepare_chain_nonlocals 首次调用置 1。多个嵌套函数 + # 定义共享同一堆(防重复 malloc + 二次重定向 VarEntry.Alloca)。 + _nl_chain_done: t.CInt + + # 泛型特化上下文:当前正在特化的类型参数名/实参名列表 + # 由 _specialize_generic_class 设置,方法体翻译时用于将 T 替换为具体类型 + # None 表示不在泛型特化上下文中 + GenericTypeParamNames: list[str] | t.CPtr + GenericTypeArgs: list[str] | t.CPtr + + # Phase 1a 声明模式标志:1=只注册 struct/enum/union 不翻译代码体,0=全量翻译 + _declare_only: t.CInt + + # Phase A 依赖未就绪标志:1=本文件翻译时依赖模块的 text.ll 尚未生成 + # (同项目源文件按顺序翻译,main.vp 先于其 import 的 mbuddytest.vp), + # 跨模块函数返回类型无法精确解析。Phase A 多遍循环据此下遍重试。 + _deps_pending: t.CInt + + # 嵌套作用域符号表 + SymTab: GenTypes.SymbolTable | t.CPtr + + def __init__(self): + self.Module = None + self.Pool = None + self._funcs = None + self._func_count = 0 + self._cur_func = None + self._cur_builder = None + self._break_bb = None + self._continue_bb = None + self._label_counter = 0 + self._imported_modules = None + self._from_imports = None + self._global_names = None + self._global_name_count = 0 + self._nonlocal_names = None + self._nonlocal_name_count = 0 + self._nonlocal_types = None + self._cur_func_name = None + self._va_list_ptr = None + self._vararg_name = None + self._stop_iter_flag_ptr = None + self._eh_dispatch_bb = None + self._eh_code_ptr = None + self._eh_msg_ptr = None + self._eh_msg_out_param = None + self._eh_code_out_param = None + self._cur_func_has_eh = 0 + self.ModuleSha1 = None + self.CurrentPackage = None + self._closure_env_offsets = 0 + self._closure_env_count = 0 + self._lambda_count = 0 + self._nl_chain_names = None + self._nl_chain_count = 0 + self._nl_chain_done = 0 + self.GenericTypeParamNames = None + self.GenericTypeArgs = None + self._declare_only = 0 + self._deps_pending = 0 + self.SymTab = None + + # ============================================================ + # 状态初始化 + # ============================================================ + def _init_state(self, pool: memhub.MemBuddy | t.CPtr): + """初始化变量表、函数表和子 Handle""" + self.Pool = pool + if self._funcs is None: + self._funcs = GenApi.init_func_table(pool, MAX_FUNCS) + # 嵌套作用域符号表(新版) + if self.SymTab is None: + self.SymTab = GenApi.init_symbol_table(pool) + # global/nonlocal 名称集合缓冲区(32 个 char* 指针 = 256 字节) + if self._global_names is None: + self._global_names = stdlib.malloc(MAX_GLOBAL_NAMES * 8) + if self._global_names is not None: + string.memset(self._global_names, 0, MAX_GLOBAL_NAMES * 8) + self._global_name_count = 0 + if self._nonlocal_names is None: + self._nonlocal_names = stdlib.malloc(MAX_GLOBAL_NAMES * 8) + if self._nonlocal_names is not None: + string.memset(self._nonlocal_names, 0, MAX_GLOBAL_NAMES * 8) + self._nonlocal_name_count = 0 + # nonlocal 变量类型数组(LLVMType 指针数组,与 _nonlocal_names 一一对应) + if self._nonlocal_types is None: + self._nonlocal_types = stdlib.malloc(MAX_GLOBAL_NAMES * 8) + if self._nonlocal_types is not None: + string.memset(self._nonlocal_types, 0, MAX_GLOBAL_NAMES * 8) + + # ============================================================ + # 主翻译入口 + # ============================================================ + def translate(self, tree: ast.AST | t.CPtr) -> int: + """将 AST 翻译为 LLVM IR""" + if tree is None: + return 1 + if _mbuddy is None: + return 1 + + pool: memhub.MemBuddy | t.CPtr = _mbuddy + + # 初始化状态 + self._init_state(pool) + + # 创建 LLVM 模块 + mod: llvmlite.LLVMModule | t.CPtr = llvmlite.new_module(pool, "main") + if mod is None: + VLogger.error("NewModule returned NULL", "TR") + return 1 + self.Module = mod + + # 设置目标(优先使用 project.vpj 中的配置) + triple: str = Config.TargetTriple + if triple is None: + triple = "x86_64-pc-windows-msvc" + llvmlite.module_set_target(mod, triple) + + # 类型 + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + # 声明 printf + printf_func: llvmlite.Function | t.CPtr = llvmlite.create_declare( + pool, mod, "printf", i32_ty) + if printf_func is None: + VLogger.error("CreateDeclare printf returned NULL", "TR") + return 1 + llvmlite.add_param(pool, printf_func, i8_ptr_ty, "fmt") + printf_func.IsVarArg = 1 + # 声明 LLVM va_start/va_end intrinsic(供 *args 函数体内使用) + # declare void @llvm.va_start(i8*) + # declare void @llvm.va_end(i8*) + void_ty_decl: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + va_start_func: llvmlite.Function | t.CPtr = llvmlite.create_declare( + pool, mod, "llvm.va_start", void_ty_decl) + if va_start_func is not None: + llvmlite.add_param(pool, va_start_func, i8_ptr_ty, "ap") + va_end_func: llvmlite.Function | t.CPtr = llvmlite.create_declare( + pool, mod, "llvm.va_end", void_ty_decl) + if va_end_func is not None: + llvmlite.add_param(pool, va_end_func, i8_ptr_ty, "ap") + + # 声明 malloc(闭包分配用) + malloc_func: llvmlite.Function | t.CPtr = llvmlite.create_declare( + pool, mod, "malloc", i8_ptr_ty) + if malloc_func is not None: + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + llvmlite.add_param(pool, malloc_func, i64_ty, "size") + + # 检查用户是否定义了 main 函数 + has_user_main: int = 0 + ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children + if ch is not None: + cn_count: t.CSizeT = len(ch) + for ci in range(cn_count): + child: ast.AST | t.CPtr = ch.get(ci) + if child is not None and child.kind() == ast.ASTKind.FunctionDef: + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child) + if fd is not None and fd.name is not None: + if string.strcmp(fd.name, "main") == 0: + has_user_main = 1 + break + + if self._declare_only != 0: + # Phase 1a-pre(2=import扫描) / Phase 1a(1=struct注册): 只处理模块级,不创建 main 函数和 builder + self._translate_module_level(pool, mod, tree) + elif has_user_main == 0: + # 无用户 main → 只翻译模块级语句,不创建 wrapper main + # 修复:避免每个文件都生成 define i32 @main() 导致链接时 main 冲突 + # 只有包含 def main() 的入口文件才会有 define i32 @main() + self._translate_module_level(pool, mod, tree) + else: + # 用户已定义 main → 委托 HandlesMain 翻译模块级 + self._translate_module_level(pool, mod, tree) + + return 0 + + # ============================================================ + # 包装 main 函数(无用户 main 时)→ 委托 HandlesMain + # ============================================================ + def _translate_wrapper_main(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + tree: ast.AST | t.CPtr, + i32_ty: llvmlite.LLVMType | t.CPtr): + """委托 GenApi.create_wrapper_main() 创建包装 main(trans 单参)""" + added: int = GenApi.create_wrapper_main(self, tree, i32_ty) + + # ============================================================ + # 模块级翻译(用户已定义 main)→ 委托 HandlesMain + # ============================================================ + def _translate_module_level(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + tree: ast.AST | t.CPtr): + """委托 GenApi.translate_children() 翻译模块级语句(trans 单参)""" + # 全量翻译模式下,先处理导入语句,再创建前向声明,解决前向引用问题 + if self._declare_only == 0: + # 预处理导入语句,确保 _imported_modules 和 _from_imports 已填充 + # (前向声明需要解析类型注解,如 t.CArray[str] 依赖 t 模块已导入) + # 记录最后处理的 import 行号,供 vpi 注入错误上下文帧定位 + cur_imp_lineno: int = 0 + ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children + if ch is not None: + cn_count: t.CSizeT = len(ch) + for ci in range(cn_count): + child: ast.AST | t.CPtr = ch.get(ci) + if child is None: + continue + kd: int = child.kind() + if kd == ast.ASTKind.Import: + cur_imp_lineno = child.lineno + GenApi.translate_import(self, child) + elif kd == ast.ASTKind.ImportFrom: + cur_imp_lineno = child.lineno + GenApi.translate_import_from_module(self, child) + GenApi.translate_import_from_names(self, child) + # 对齐 TPC _inject_auto_imports:检测源文件对 list/dict 容器的使用 + # (裸名注解 d: dict / 构造 dict(...) / 下标 list[T]),自动把容器 + # 类标记为可见结构体。背景:_list.vp/_dict.vp 定义内建容器类且已由 + # Phase1 注册,但源文件不显式 import 它们(TPC 在翻译前自动注入 + # import _list/_dict);TPV 用可见性机制等效替代——否则裸名 + # `d: dict` 注解 resolve_annotation_type 时 is_struct_visible=0 + # 解析失败(DictTest 的 "变量类型注解解析失败")。 + self._inject_auto_container_visibility(pool, tree) + # 扫描当前模块的 CTypedef 声明已由 Phase1 1b 文本扫描注册 + # (RegisterCTypedefFromSource,见 Phase1Main.vp)——AST 字符串字段 + # token 零拷贝指向 src_buf,跨阶段内容不稳定,此处 AST 扫描读 attr + # 会 0xC0000005(stdint.vp 崩溃根因),故移除。 + # 跨模块 .vpi 注入:加载依赖模块的 .vpi 文件, + # 将函数 declare 声明注入到当前模块,解决跨模块函数调用找不到函数的问题 + # 严格保证 declare_only == 0 时才注入(避免 Phase A-pre-inc 死锁) + if self._imported_modules is not None: + import lib.core.StubMerger as StubMerger + # 错误上下文帧:当前模块触发依赖 stub 加载的 import 位置 + GenApi.push_trace(GenApi.get_current_file(), cur_imp_lineno) + StubMergerBuild.LoadDepVpiIntoModule( + pool, mod, self._imported_modules, self._from_imports, + GenApi.get_temp_dir(), self) + GenApi.pop_trace() + # 预注册模块级变量(AnnAssign/Assign)到 SymTab + # 解决时序问题:class Logger 的 __init__ 引用 _mbuddy 时, + # _mbuddy 的 AnnAssign 在 AST 中位于 class Logger 之后, + # 按 AST 顺序翻译时 _mbuddy 尚未注册 → lookup_var 返回 None → rhs_val is None + # 预处理先于 translate_children 注册所有模块级变量, + # 后续 translate_children 遍历到同一 AnnAssign 时 handle_module_level_var + # 通过 lookup_module_var 检测已存在并跳过(HandlesMain.py:206-209) + if ch is not None: + for ci in range(cn_count): + child: ast.AST | t.CPtr = ch.get(ci) + if child is None: + continue + kd_mv: int = child.kind() + if kd_mv == ast.ASTKind.AnnAssign or kd_mv == ast.ASTKind.Assign: + GenApi.handle_module_level_var(self, child) + # 创建前向声明 + GenApi.forward_declare_functions(self, tree) + added: int = GenApi.translate_children(self, tree) + + # ============================================================ + # 容器模块自动可见性注入(对齐 TPC _inject_auto_imports) + # + # TPC 在翻译前自动注入 `import _list / import _dict (+json)` 到源文件, + # 使 list/dict 内建容器类在符号表中可见。TPV 用可见性机制等效替代: + # _list.vp/_dict.vp 已由 Phase1 注册(可达集合含它们),这里只需在 + # 当前文件翻译时把容器类名标记为可见结构体,裸名注解/构造即可解析。 + # + # 检测模式(与 TPC Phase2Translator._inject_auto_imports 一致): + # - AnnAssign 注解裸名 Name(list/dict):d: dict + # - 构造调用 func 裸名 Name(list/dict):dict(bd) + # - Subscript 的 value 裸名 Name(list/dict):list[int] + # ============================================================ + def _inject_auto_container_visibility(self, pool: memhub.MemBuddy | t.CPtr, + tree: ast.AST | t.CPtr): + """检测 list/dict 容器使用,注入容器类可见性""" + if tree is None or tree.children is None: + return + # 用栈式缓冲区传递检测结果(跨函数参数用 4 字节 int 指针) + need_list_box: t.CPtr = stdlib.malloc(4) + need_dict_box: t.CPtr = stdlib.malloc(4) + if need_list_box is None or need_dict_box is None: + if need_list_box is not None: + stdlib.free(need_list_box) + if need_dict_box is not None: + stdlib.free(need_dict_box) + return + need_list_box[0] = 0 + need_dict_box[0] = 0 + self._scan_container_usage(tree, need_list_box, need_dict_box) + if need_dict_box[0] != 0: + # dict 类可见 + _dict 模块导入(构造/方法调用的 SHA1 解析) + GenApi.add_visible_struct(pool, "dict") + if self._imported_modules is None or \ + GenApi.is_module_imported(self._imported_modules, "_dict") == 0: + self._imported_modules = GenApi.add_imported_module( + pool, self._imported_modules, "_dict") + if need_list_box[0] != 0: + GenApi.add_visible_struct(pool, "list") + if self._imported_modules is None or \ + GenApi.is_module_imported(self._imported_modules, "_list") == 0: + self._imported_modules = GenApi.add_imported_module( + pool, self._imported_modules, "_list") + stdlib.free(need_list_box) + stdlib.free(need_dict_box) + + def _scan_container_usage(self, node: ast.AST | t.CPtr, + need_list_box: t.CPtr, + need_dict_box: t.CPtr): + """递归扫描 AST 语句结构,检测 list/dict 容器使用""" + if node is None: + return + k: int = node.kind() + if k == ast.ASTKind.AnnAssign: + aa_s: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) + if aa_s.annotation is not None: + self._check_container_type_node(aa_s.annotation, need_list_box, need_dict_box) + elif k == ast.ASTKind.Call: + cl_s: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + if cl_s.func is not None: + self._check_container_type_node(cl_s.func, need_list_box, need_dict_box) + elif k == ast.ASTKind.Subscript: + sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + if sub_s.value is not None: + self._check_container_type_node(sub_s.value, need_list_box, need_dict_box) + elif k == ast.ASTKind.List: + # [] 字面量:容器模板仍需注册 + need_list_box[0] = 1 + elif k == ast.ASTKind.Dict: + # {} 字面量:容器模板仍需注册 + need_dict_box[0] = 1 + # 递归语句块子节点 + if node.children is not None: + ch_s: list[ast.AST | t.CPtr] | t.CPtr = node.children + n_s: t.CSizeT = len(ch_s) + for ci_s in range(n_s): + self._scan_container_usage(ch_s.get(ci_s), need_list_box, need_dict_box) + + def _check_container_type_node(self, node: ast.AST | t.CPtr, + need_list_box: t.CPtr, + need_dict_box: t.CPtr): + """检测类型位置节点是否为 list/dict(支持 Name 与 Subscript 外层)""" + if node is None: + return + k: int = node.kind() + if k == ast.ASTKind.Name: + nm_s: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm_s.id is not None: + if string.strcmp(nm_s.id, "dict") == 0: + need_dict_box[0] = 1 + elif string.strcmp(nm_s.id, "list") == 0: + need_list_box[0] = 1 + elif k == ast.ASTKind.Subscript: + sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + if sub_s.value is not None: + self._check_container_type_node(sub_s.value, need_list_box, need_dict_box) + + + # ============================================================ + # IR 输出 + # ============================================================ + def dump_ir(self, buf: bytes, size: t.CSizeT, mode: int): + """将 LLVM IR 输出到缓冲区 + + mode: 0=完整, 1=stub(仅声明), 2=text(仅代码) + """ + if self.Module is None or buf is None: + return + if _mbuddy is None: + return + buf[0] = '\0' + llvmlite.LLVMModulePrint(buf, size, self.Module, _mbuddy, mode) + + +# ============================================================ +# global/nonlocal 名称管理(模块级辅助函数,委托到 gen 方法) +# ============================================================ +def add_global_name(trans: HT.Translator | t.CPtr, name: str): + """添加一个 global 变量名(委托到 gen.add_global_name)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + g.TranslatorGen.add_global_name(trans, name) + + +def is_global_name(trans: HT.Translator | t.CPtr, name: str) -> int: + """检查 name 是否在当前函数的 global 集合中(委托到 gen.is_global_name)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.TranslatorGen.is_global_name(trans, name) + return 0 + + +def add_nonlocal_name(trans: HT.Translator | t.CPtr, name: str, + var_ty: llvmlite.LLVMType | t.CPtr = None): + """添加一个 nonlocal 变量名(委托到 gen.add_nonlocal_name) + + Args: + name: nonlocal 变量名 + var_ty: 变量的 LLVM 类型(用于 env 指针数组方案的类型恢复, + None 时回退为 i32) + """ + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + g.TranslatorGen.add_nonlocal_name(trans, name, var_ty) + + +def get_nonlocal_type(trans: HT.Translator | t.CPtr, + name: str) -> llvmlite.LLVMType | t.CPtr: + """获取 nonlocal 变量的 LLVM 类型(委托到 gen.get_nonlocal_type) + + Returns: 找到的类型指针,找不到返回 None + """ + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.TranslatorGen.get_nonlocal_type(trans, name) + return None + + +def is_nonlocal_name(trans: HT.Translator | t.CPtr, name: str) -> int: + """检查 name 是否在当前函数的 nonlocal 集合中(委托到 gen.is_nonlocal_name)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.TranslatorGen.is_nonlocal_name(trans, name) + return 0 + + +def get_nonlocal_index(trans: HT.Translator | t.CPtr, name: str) -> int: + """获取 nonlocal 变量在 env 中的索引(0-based),找不到返回 -1(委托到 gen.get_nonlocal_index)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.TranslatorGen.get_nonlocal_index(trans, name) + return 0 + + +def clear_scope_names(trans: HT.Translator | t.CPtr): + """清空当前函数的 global/nonlocal 名称集合(进入新函数时调用)(委托到 gen.clear_scope_names)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + g.TranslatorGen.clear_scope_names(trans) + + +# 全局 mbuddy 指针 +_mbuddy: memhub.MemBuddy | t.CPtr diff --git a/App/lib/core/Handles/HandlesType.vp b/App/lib/core/Handles/HandlesType.vp deleted file mode 100644 index 5021018..0000000 --- a/App/lib/core/Handles/HandlesType.vp +++ /dev/null @@ -1,598 +0,0 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import sys -import stdlib -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# HandlesType - 类型映射与解析(P2 对象化后的委托层) -# ============================================================ - - -# ============================================================ -# 常量(保留,供 TraceFrame 相关使用) -# ============================================================ -TRACE_MAX: t.CDefine = 32 -MAX_CTYPEDEF_DEPTH: t.CDefine = 10 - - -@t.NoVTable -class TraceFrame: - file_name: str # 文件名 - lineno: int # 行号 - col_start: int # 列起始(1-based,0=不指定) - col_end: int # 列结束(1-based,0=不指定) - - -# ============================================================ -# 全局 gen 单例(模块级镜像) -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - - -# ============================================================ -# 类编译期元数据(__provides__/__requires__/__require_must__) -# -# _fakeduck.vp 的 _str 用 __requires__ = ['__mbuddy__'] 声明 with 上下文 -# 依赖字段;with 提供者用 __provides__ 声明注入字段。这些是编译期 -# 元数据,不生成运行字段(FakeDuck 移植点 1)。 -# ============================================================ -CLASS_META_PROVIDES: t.CDefine = 1 -CLASS_META_REQUIRES: t.CDefine = 2 -CLASS_META_REQUIRE_MUST: t.CDefine = 3 - - -def register_class_meta(pool: memhub.MemBuddy | t.CPtr, - kind: int, cls: str, field: str) -> int: - """注册类编译期元数据字段(委托到 gen.register_class_meta),0=成功""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.register_class_meta(pool, kind, cls, field) - return 1 - - -def class_meta_count(kind: int, cls: str) -> int: - """返回某类某元数据类型的字段数(委托到 gen.class_meta_count)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.class_meta_count(kind, cls) - return 0 - - -def class_meta_field_at(kind: int, cls: str, idx: int) -> str: - """返回某类某元数据类型的第 idx 个字段名(委托到 gen.class_meta_field_at)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.class_meta_field_at(kind, cls, idx) - return None - - -def _ensure_trace_init() -> int: - """确保调用栈已初始化(委托到 gen._ensure_trace_init)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._ensure_trace_init() - return 0 - - -def _get_trace_frame(i: int) -> TraceFrame | t.CPtr: - """获取第 i 个 TraceFrame 槽位(委托到 gen._get_trace_frame)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._get_trace_frame(i) - return None - - -def push_trace(file_name: str, lineno: int, col_start: int = 0, col_end: int = 0): - """压入一个翻译上下文帧(委托到 gen.push_trace)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.push_trace(file_name, lineno, col_start, col_end) - - -def pop_trace(): - """弹出栈顶帧(委托到 gen.pop_trace)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.pop_trace() - - -def clear_trace(): - """清空调用栈(委托到 gen.clear_trace)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.clear_trace() - - -def set_temp_dir(temp_dir: str) -> None: - """设置全局 temp_dir(委托到 gen.set_temp_dir)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.set_temp_dir(temp_dir) - - -def get_temp_dir() -> str: - """获取全局 temp_dir(委托到 gen.get_temp_dir)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_temp_dir() - return None - - -def set_current_module_sha1(sha1: str) -> None: - """设置当前正在编译的模块 SHA1(委托到 gen.set_current_module_sha1)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.set_current_module_sha1(sha1) - - -def _dbg_check_ast_floats(mb: memhub.MemBuddy | t.CPtr, - tree: ast.AST | t.CPtr, tag: str): - """已移除调试插桩(占位保留签名,避免外部调用引用失败)""" - pass - - -def register_cdefine_constant(pool: memhub.MemBuddy | t.CPtr, - name: str, value: t.CInt64T) -> None: - """注册 CDefine 编译期常量到本地表(委托到 gen.register_cdefine_constant)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.register_cdefine_constant(pool, name, value) - - -def register_cdefine_double(pool: memhub.MemBuddy | t.CPtr, - name: str, value: double) -> None: - """注册浮点 CDefine 编译期常量(委托到 gen.register_cdefine_double)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.register_cdefine_double(pool, name, value) - - -def register_cdefine_string(pool: memhub.MemBuddy | t.CPtr, - name: str, value: str) -> None: - """注册字符串 CDefine 编译期常量(委托到 gen.register_cdefine_string)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.register_cdefine_string(pool, name, value) - - -def lookup_cdefine_constant(name: str) -> t.CInt64T: - """查找 CDefine 编译期常量(委托到 gen.lookup_cdefine_constant)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.lookup_cdefine_constant(name) - return 0 - - -def lookup_cdefine_double(name: str) -> double: - """查找 CDefine 编译期常量,返回 double 值(委托到 gen.lookup_cdefine_double)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.lookup_cdefine_double(name) - return 0.0 - - -def lookup_cdefine_string(name: str) -> str: - """查找 CDefine 编译期字符串值(委托到 gen.lookup_cdefine_string)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.lookup_cdefine_string(name) - return None - - -def is_cdefine_str() -> int: - """检查最近一次 CDefine 查找命中的是否是字符串常量(委托到 gen.is_cdefine_str)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.is_cdefine_str() - return 0 - - -def eval_ctraits_isptr(symtab: HandlesVar.SymbolTable | t.CPtr, - name: str) -> int: - """ctraits.isptr(name) 编译期求值(委托到 gen._eval_ctraits_isptr)。 - - 返回: 1=指针 0=非指针 -1=无法求值。 - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._eval_ctraits_isptr(symtab, name) - return -1 - - -def is_cdefine_double() -> int: - """检查最近一次 CDefine 查找命中的是否是浮点常量(委托到 gen.is_cdefine_double)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.is_cdefine_double() - return 0 - - -def is_cdefine_found() -> int: - """检查上次 lookup_cdefine_constant 是否找到值(委托到 gen.is_cdefine_found)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.is_cdefine_found() - return 0 - - -def set_cdefine_found(val: int) -> None: - """设置 cdefine_found 标志(委托到 gen.set_cdefine_found)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.set_cdefine_found(val) - - -def clear_cdefine_constants() -> None: - """清空 CDefine 常量表(委托到 gen.clear_cdefine_constants)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.clear_cdefine_constants() - - -def register_xmod_cdefine(name: str, value_str: str, - is_double: int, is_str: int) -> None: - """注册跨模块 CDefine 查找结果到 perm_pool 全局缓存(委托到 gen.register_xmod_cdefine)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.register_xmod_cdefine(name, value_str, is_double, is_str) - - -def lookup_xmod_cdefine(name: str) -> str: - """查找跨模块 CDefine 缓存(委托到 gen.lookup_xmod_cdefine)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.lookup_xmod_cdefine(name) - return None - - -def register_ctypedef(pool: memhub.MemBuddy | t.CPtr, - name: str, type_str: str) -> None: - """注册 CTypedef 到本地表(委托到 gen.register_ctypedef)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.register_ctypedef(pool, name, type_str) - - -def lookup_ctypedef(name: str) -> str: - """查找 CTypedef,返回类型表达式字符串(委托到 gen.lookup_ctypedef)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.lookup_ctypedef(name) - return None - - -def is_ctypedef_found() -> int: - """检查上次 lookup_ctypedef 是否找到值(委托到 gen.is_ctypedef_found)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.is_ctypedef_found() - return 0 - - -def clear_ctypedefs() -> None: - """清空 CTypedef 表(委托到 gen.clear_ctypedefs)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.clear_ctypedefs() - - -def _ctypedef_push_visiting(pool: memhub.MemBuddy | t.CPtr, name: str) -> int: - """将 CTypedef 名加入正在解析列表(委托到 gen._ctypedef_push_visiting)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._ctypedef_push_visiting(pool, name) - return 0 - - -def _ctypedef_pop_visiting() -> None: - """从正在解析列表弹出最后一个 CTypedef 名(委托到 gen._ctypedef_pop_visiting)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g._ctypedef_pop_visiting() - - -def _is_ctypedef_annotation(annotation: ast.AST | t.CPtr) -> int: - """检测类型注解是否为 t.CTypedef(委托到 gen._is_ctypedef_annotation)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_ctypedef_annotation(annotation) - return 0 - - -def ScanCTypedefDeclarations(pool: memhub.MemBuddy | t.CPtr, - tree: ast.AST | t.CPtr) -> int: - """扫描 AST 顶层节点,注册所有 NAME: t.CTypedef = Type 声明(委托到 gen.ScanCTypedefDeclarations)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.ScanCTypedefDeclarations(pool, tree) - return 0 - - -def RegisterCTypedefFromSource(pool: memhub.MemBuddy | t.CPtr, - src: str) -> int: - """从源码文本逐行注册 CTypedef 声明(委托到 gen.register_ctypedef_from_source) - - stdint.vp 崩溃根因修复:AST 字符串字段(attr/id)token 零拷贝指向 - src_buf,跨阶段内容不稳定(悬空),ScanCTypedefDeclarations 读 attr - 会 0xC0000005。改用文本匹配 "NAME: t.CTypedef = TYPE"。 - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.register_ctypedef_from_source(pool, src) - return 0 - - -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)""" - 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, pool, from_imports, imported_modules) - return 0 - - -def set_generic_context(tp_names: list[str] | t.CPtr, - type_args: list[str] | t.CPtr): - """设置泛型特化上下文(委托到 gen.set_generic_context)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.set_generic_context(tp_names, type_args) - - -def clear_generic_context(): - """清除泛型特化上下文(委托到 gen.clear_generic_context)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.clear_generic_context() - - -def resolve_generic_type_name(name: str) -> str: - """如果 name 是泛型类型参数,返回对应的具体类型名(委托到 gen.resolve_generic_type_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.resolve_generic_type_name(name) - return name - - -def _get_type_name_from_annotation(pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr) -> str: - """从类型注解节点提取类型名(委托到 gen._get_type_name_from_annotation)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._get_type_name_from_annotation(pool, node) - return None - - -def _parse_type_string(pool: memhub.MemBuddy | t.CPtr, - type_str: str, - ctx: t.CInt) -> ast.AST | t.CPtr: - """将类型名字符串解析为 AST 节点(委托到 gen._parse_type_string)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._parse_type_string(pool, type_str, ctx) - return None - - -def set_current_file(file_path: str): - """设置当前编译的文件名(委托到 gen.set_current_file)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.set_current_file(file_path) - - -def get_current_file() -> str: - """获取当前编译的文件名(委托到 gen.get_current_file)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_current_file() - return None - - -def _read_source_line(file_path: str, lineno: int) -> str: - """从源文件读取第 lineno 行内容(委托到 gen._read_source_line)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._read_source_line(file_path, lineno) - return None - - -def read_source_line(file_path: str, lineno: int) -> str: - """公开包装:从源文件读取第 lineno 行内容(委托到 gen.read_source_line)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.read_source_line(file_path, lineno) - return None - - -def dump_parse_traceback(file_path: str): - """解析失败时以 Python 风格输出 traceback(委托到 gen.dump_parse_traceback)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.dump_parse_traceback(file_path) - - -def fatal_error(node: ast.AST | t.CPtr, msg: str, - err_type: str = "SyntaxError", - col_start: int = 0, col_end: int = 0): - """以 Python 风格报错并退出(委托到 gen.fatal_error)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.fatal_error(node, msg, err_type, col_start, col_end) - - -def fatal_type_error(node: ast.AST | t.CPtr, msg: str, - col_start: int = 0, col_end: int = 0): - """以 Python 风格报错并退出(TypeError 版本,委托到 gen.fatal_type_error)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.fatal_type_error(node, msg, col_start, col_end) - - -def try_extract_callable_ret(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(委托到 gen.try_extract_callable_ret)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.try_extract_callable_ret(pool, annot, imported_modules, from_imports, trans) - return None - - -def map_t_type(pool: memhub.MemBuddy | t.CPtr, - type_name: str) -> llvmlite.LLVMType | t.CPtr: - """将 t.CXxx / c.CXxx 类型名映射到 LLVMType(委托到 gen.map_t_type)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.map_t_type(pool, type_name) - return None - - -def _is_t_attr(node: ast.AST | t.CPtr, - attr_name: str, - imported_modules: str) -> int: - """检测节点是否是 t.attr_name 形式(委托到 gen._is_t_attr)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_t_attr(node, attr_name, imported_modules) - return 0 - - -def _is_cptr_marker(node: ast.AST | t.CPtr, - imported_modules: str) -> int: - """检测节点是否为 CPtr 指针标记(委托到 gen._is_cptr_marker)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_cptr_marker(node, imported_modules) - return 0 - - -def _is_cvoid_marker(node: ast.AST | t.CPtr, - imported_modules: str) -> int: - """检测节点是否为 CVoid 指针标记(委托到 gen._is_cvoid_marker)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_cvoid_marker(node, imported_modules) - return 0 - - -def annotation_to_str(annot: ast.AST | t.CPtr) -> str: - """将类型注解 AST 转换为可读字符串(委托到 gen.annotation_to_str)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.annotation_to_str(annot) - return None - - -def extract_class_name_from_annotation(node: ast.AST | t.CPtr, - imported_modules: str, - pool: memhub.MemBuddy | t.CPtr = None) -> str: - """从类型注解 AST 中提取类名(委托到 gen.extract_class_name_from_annotation)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.extract_class_name_from_annotation(node, imported_modules, pool) - return None - - -def _resolve_generic_subscript_ty(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: - """解析泛型类类型注解(委托到 gen._resolve_generic_subscript_ty)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._resolve_generic_subscript_ty(pool, sub, gen_cls_name, trans, - imported_modules, from_imports) - return None - - -def resolve_annotation_type(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(委托到 gen.resolve_annotation_type)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.resolve_annotation_type(pool, node, imported_modules, from_imports, trans) - return None - - -def has_decorator_marker(node: ast.AST | t.CPtr, - marker_name: str) -> int: - """检测类型注解中是否包含指定的装饰器标记(委托到 gen.has_decorator_marker)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.has_decorator_marker(node, marker_name) - return 0 - - -def is_pass_body(body: list[ast.AST | t.CPtr] | t.CPtr) -> int: - """检测函数体是否为 pass(委托到 gen.is_pass_body)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.is_pass_body(body) - return 0 - - -def get_llvm_type_bits(ty: llvmlite.LLVMType | t.CPtr) -> int: - """获取 LLVM 整数类型的位宽(委托到 gen.get_llvm_type_bits)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_llvm_type_bits(ty) - return 0 - - -def infer_expr_type(pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr, - param_types: str) -> llvmlite.LLVMType | t.CPtr: - """推断表达式的 LLVM 类型(委托到 gen.infer_expr_type)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.infer_expr_type(pool, node, param_types) - return None - - -def infer_return_type(pool: memhub.MemBuddy | t.CPtr, - body: list[ast.AST | t.CPtr] | t.CPtr, - param_types: str) -> llvmlite.LLVMType | t.CPtr: - """扫描函数体中的 return 语句,推断返回类型(委托到 gen.infer_return_type)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.infer_return_type(pool, body, param_types) - return None - - -def build_param_types_str(pool: memhub.MemBuddy | t.CPtr, - args_node: ast.AST | t.CPtr) -> str: - """构建参数类型编码字符串(委托到 gen.build_param_types_str)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.build_param_types_str(pool, args_node) - return None - - -def _strappend(dst: str, dst_size: t.CSizeT, src: str): - """将 src 追加到 dst 末尾(委托到 gen._strappend)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g._strappend(dst, dst_size, src) diff --git a/App/lib/core/Handles/HandlesVar.vp b/App/lib/core/Handles/HandlesVar.vp deleted file mode 100644 index 877f54b..0000000 --- a/App/lib/core/Handles/HandlesVar.vp +++ /dev/null @@ -1,371 +0,0 @@ -import t, c -from stdint import * -import llvmlite -import memhub -import string -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# HandlesVar - 嵌套作用域符号表 + 变量管理(P6 对象化后的委托层) -# -# 使用 Scope 链(Parent 指针)管理嵌套作用域, -# 每个作用域包含一个 VarEntry 数组(扁平化,已验证可工作)。 -# -# 作用域类型: -# SCOPE_MODULE — 模块级(根作用域) -# SCOPE_FUNCTION — 函数级 -# SCOPE_BLOCK — 块级(if/for/while,当前未使用块作用域) -# -# P6 对象化重构(wiki/14-oo-refactor.md): -# 全部模块级函数已迁移为 lib.core.Gen.VarGenMixin 的方法(方法化迁移, -# 无全局状态),本模块保留同名模块级函数作为"一行委托":延迟 import -# Gen 取全局单例(BuildPipeline/main 创建后 set_global_gen 注册), -# 再调用 gen 的对应方法。签名与旧函数完全一致,调用方零改动。 -# -# VarEntry/Scope/SymbolTable 类型与常量保留在本模块(gen 方法签名引用)。 -# ============================================================ - -# 作用域类型常量 -SCOPE_MODULE: t.CDefine = 0 -SCOPE_FUNCTION: t.CDefine = 1 -SCOPE_BLOCK: t.CDefine = 2 - -# 每个作用域最大变量数 -# 256 太小:NewAstTest main() 有 289 个局部变量,add_var 超限静默失败 -# 导致变量未注册,后续使用报"未定义名称"(与 Gen/VarGenMixin 保持一致)。 -MAX_VARS: t.CDefine = 1024 - - -# ============================================================ -# VarEntry - 变量表条目 -# ============================================================ -@t.NoVTable -class VarEntry: - """变量表条目""" - Name: str - Alloca: llvmlite.Value | t.CPtr - Used: t.CInt - AnnotClassName: str # 原始类型注解的类名(str 别名在结构体字段中触发编译器 bug,改用显式联合类型) - IsPtrElement: t.CInt # 标志: 1=注解为 bytes|t.CPtr 或 str|t.CPtr, 下标按 8 字节步长 - - -# ============================================================ -# Scope - 作用域节点 -# -# Parent 指向父作用域(None 表示根), -# Vars 是 VarEntry 数组,VarCount 是当前变量数。 -# ============================================================ -@t.NoVTable -class Scope: - """作用域节点""" - Parent: Scope | t.CPtr - Vars: VarEntry | t.CPtr - VarCount: t.CInt - Kind: t.CInt - - -# ============================================================ -# SymbolTable - 嵌套作用域符号表 -# -# Root 是模块级根作用域,Current 是当前作用域。 -# enter_scope/exit_scope 管理作用域栈。 -# ============================================================ -@t.NoVTable -class SymbolTable: - """嵌套作用域符号表""" - Pool: memhub.MemBuddy | t.CPtr - Root: Scope | t.CPtr - Current: Scope | t.CPtr - - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) -# -# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。 -# P6 委托函数用本地 _g_gen(cast 成 Generator 类型)调 -# VarGenMixin 方法,避免函数体 import 包模块与 Generator -# 类/模块名歧义。 -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - - -# ============================================================ -# 委托函数:延迟 import Gen 取全局单例 → 调 gen 方法 -# (gen 未注册时正常流程不会发生;有返回值函数返回默认值) -# ============================================================ - - -# ============================================================ -# init_vars — 分配并清零 VarEntry 数组 -# ============================================================ -def init_vars(pool: memhub.MemBuddy | t.CPtr) -> VarEntry | t.CPtr: - """分配并清零变量表数组(委托到 gen.init_vars)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.init_vars(pool) - return None - - -# ============================================================ -# find_var — 在变量表中按名称查找 -# ============================================================ -def find_var(vars_ptr: VarEntry | t.CPtr, - var_count: int, - name: str) -> llvmlite.Value | t.CPtr: - """在变量表中按名称查找(委托到 gen.find_var)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.find_var(vars_ptr, var_count, name) - return None - - -# ============================================================ -# find_var_entry — 在变量表中按名称查找,返回 VarEntry(含 AnnotTy) -# ============================================================ -def find_var_entry(vars_ptr: VarEntry | t.CPtr, - var_count: int, - name: str) -> VarEntry | t.CPtr: - """在变量表中按名称查找,返回 VarEntry 或 None(委托到 gen.find_var_entry)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.find_var_entry(vars_ptr, var_count, name) - return None - - -# ============================================================ -# lookup_var_entry — 从当前作用域逐级向上查找变量,返回 VarEntry -# ============================================================ -def lookup_var_entry(symtab: SymbolTable | t.CPtr, - name: str) -> VarEntry | t.CPtr: - """从当前作用域逐级向上查找变量,返回 VarEntry 或 None(委托到 gen.lookup_var_entry)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.lookup_var_entry(symtab, name) - return None - - -# ============================================================ -# set_var_annot_class_name — 设置变量的原始类型注解类名 -# -# 在函数参数定义后调用,存储原始类型注解的类名。 -# 方法调用检测时,当 alloca 类型是 Ptr(i8)(联合类型简化), -# 通过 AnnotClassName 查找实际结构体类型。 -# ============================================================ -def set_var_annot_class_name(symtab: SymbolTable | t.CPtr, - name: str, - class_name: str) -> int: - """设置变量的原始类型注解类名,返回 0=成功 / 1=失败(委托到 gen.set_var_annot_class_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.set_var_annot_class_name(symtab, name, class_name) - return 0 - - -# ============================================================ -# set_var_ptr_element — 标记变量为"指针到 str/bytes"类型 -# -# 注解为 bytes|t.CPtr 或 str|t.CPtr 的变量,其 alloca 类型是 i8*, -# 但下标访问应按 8 字节步长(i8** 语义),而非 1 字节步长(i8* 语义)。 -# 此标志在 HandlesAnnAssign 中根据注解形式设置。 -# ============================================================ -def set_var_ptr_element(symtab: SymbolTable | t.CPtr, - name: str) -> int: - """标记变量为 ptr_element 类型,返回 0=成功 / 1=失败(委托到 gen.set_var_ptr_element)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.set_var_ptr_element(symtab, name) - return 0 - - -# ============================================================ -# add_var — 添加变量到变量表 -# ============================================================ -def add_var(vars_ptr: VarEntry | t.CPtr, - var_count: int, - name: str, - alloca: llvmlite.Value | t.CPtr) -> int: - """添加变量到变量表(委托到 gen.add_var)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.add_var(vars_ptr, var_count, name, alloca) - return 0 - - -# ============================================================ -# _alloca_at_entry - 在函数入口块生成 alloca(确保支配性) -# -# LLVM IR 要求指令支配所有使用点。如果 alloca 在条件分支内生成, -# 但在其他分支使用,会违反支配性(Instruction does not dominate all uses)。 -# 标准做法:所有 alloca 在函数入口块生成。 -# -# 临时切换 builder.CurBlock 到入口块,生成 alloca,然后恢复。 -# ============================================================ -def _alloca_at_entry(builder: llvmlite.IRBuilder | t.CPtr, - ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: - """在函数入口块生成 alloca,返回 alloca 值(委托到 gen._alloca_at_entry) - - 使用 llvmlite.build_alloca_at_entry 在入口块终止指令之前插入 alloca, - 确保所有 alloca 在入口块,避免支配性违规。 - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._alloca_at_entry(builder, ty) - return None - - -# ============================================================ -# get_or_create_var — 查找或创建变量 alloca(旧版兼容) -# ============================================================ -def get_or_create_var(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - vars_ptr: VarEntry | t.CPtr, - var_count: int, - name: str, - ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: - """查找或创建变量 alloca(委托到 gen.get_or_create_var)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_or_create_var(pool, builder, vars_ptr, var_count, name, ty) - return None - - -# ============================================================ -# _create_scope — 创建新作用域节点(内部辅助函数) -# ============================================================ -def _create_scope(pool: memhub.MemBuddy | t.CPtr, - parent: Scope | t.CPtr, - kind: int) -> Scope | t.CPtr: - """创建并初始化作用域节点(委托到 gen._create_scope)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._create_scope(pool, parent, kind) - return None - - -# ============================================================ -# init_symbol_table — 创建符号表(含模块级根作用域) -# ============================================================ -def init_symbol_table(pool: memhub.MemBuddy | t.CPtr) -> SymbolTable | t.CPtr: - """创建并初始化符号表,包含模块级根作用域(委托到 gen.init_symbol_table)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.init_symbol_table(pool) - return None - - -# ============================================================ -# enter_scope — 进入新作用域 -# ============================================================ -def enter_scope(symtab: SymbolTable | t.CPtr, - kind: int) -> Scope | t.CPtr: - """进入新作用域,返回新创建的作用域(委托到 gen.enter_scope)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.enter_scope(symtab, kind) - return None - - -# ============================================================ -# exit_scope — 退出当前作用域 -# ============================================================ -def exit_scope(symtab: SymbolTable | t.CPtr): - """退出当前作用域,恢复到父作用域(委托到 gen.exit_scope)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.exit_scope(symtab) - - -# ============================================================ -# define_var — 在当前作用域定义变量 -# ============================================================ -def define_var(symtab: SymbolTable | t.CPtr, - name: str, - alloca: llvmlite.Value | t.CPtr) -> int: - """在当前作用域定义变量,返回 0 成功(委托到 gen.define_var)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.define_var(symtab, name, alloca) - return 0 - - -# ============================================================ -# define_module_var — 在模块作用域定义变量 -# ============================================================ -def define_module_var(symtab: SymbolTable | t.CPtr, - name: str, - alloca: llvmlite.Value | t.CPtr) -> int: - """在模块作用域定义变量,返回 0 成功(委托到 gen.define_module_var)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.define_module_var(symtab, name, alloca) - return 0 - - -# ============================================================ -# lookup_var — 从当前作用域逐级向上查找变量 -# ============================================================ -def lookup_var(symtab: SymbolTable | t.CPtr, - name: str) -> llvmlite.Value | t.CPtr: - """从当前作用域逐级向上查找变量,返回 alloca 或 None(委托到 gen.lookup_var)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.lookup_var(symtab, name) - return None - - -# ============================================================ -# lookup_current — 仅在当前作用域查找变量 -# ============================================================ -def lookup_current(symtab: SymbolTable | t.CPtr, - name: str) -> llvmlite.Value | t.CPtr: - """仅在当前作用域查找变量(委托到 gen.lookup_current)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.lookup_current(symtab, name) - return None - - -# ============================================================ -# lookup_module_var — 在模块作用域查找变量 -# ============================================================ -def lookup_module_var(symtab: SymbolTable | t.CPtr, - name: str) -> llvmlite.Value | t.CPtr: - """在模块作用域查找变量(委托到 gen.lookup_module_var)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.lookup_module_var(symtab, name) - return None - - -# ============================================================ -# is_module_scope - 判断当前是否在模块级作用域 -# -# 用于区分模块级代码和函数内代码: -# - 模块级代码:AnnAssign 应修改模块级变量(Python 语义) -# - 函数内代码:无 global 声明时 AnnAssign 应创建局部变量(Python 语义) -# ============================================================ -def is_module_scope(symtab: SymbolTable | t.CPtr) -> int: - """判断当前作用域是否为模块级作用域(Current == Root,委托到 gen.is_module_scope) - - Returns: 1=模块级作用域, 0=函数内作用域 - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.is_module_scope(symtab) - return 0 - - -# ============================================================ -# get_or_create_sym — 查找或创建变量(在当前作用域) -# ============================================================ -def get_or_create_sym(symtab: SymbolTable | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - name: str, - ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: - """查找或创建变量 alloca(在当前作用域,委托到 gen.get_or_create_sym)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.get_or_create_sym(symtab, pool, builder, name, ty) - return None diff --git a/App/lib/core/Handles/HandlesWhile.vp b/App/lib/core/Handles/HandlesWhile.vp deleted file mode 100644 index a378cad..0000000 --- a/App/lib/core/Handles/HandlesWhile.vp +++ /dev/null @@ -1,40 +0,0 @@ -import t, c -from stdint import * -import ast -import memhub -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# HandlesWhile - while 循环语句处理(迁移完成,保留跨 Mixin 委托壳) -# -# P6 机械化迁移:WhileHandle 类 → StmtGenCifMixin.translate_while; -# 模块级辅助 _IsConstTrue/_NodeHasBreak/_StmtHasBreak → StmtGenCifMixin -# 方法(merge 可达性判定)。 -# 分派中枢(StmtGenMixin)经本壳跨链调用(Viper @t.NoVTable 静态绑定下 -# 跨 Mixin self. 调用 mangle 失败,须经模块级委托壳桥回 gen 单例)。 -# 迁移收尾(编译器缺陷修复)后统一删除。 -# ============================================================ - - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) -# -# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。 -# 委托函数用本地 _g_gen(cast 成 Generator 类型)调 -# StmtGenCifMixin 方法,避免函数体 import 包模块与类/模块名歧义。 -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - - -# ============================================================ -# translate_while - while 循环语句翻译(委托到 gen.translate_while) -# ============================================================ -def translate_while(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 while 循环语句(委托到 gen.translate_while)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.translate_while(trans, node) - return 0 diff --git a/App/lib/core/Handles/__init__.vp b/App/lib/core/Handles/__init__.vp index 619fc36..a6f57df 100644 --- a/App/lib/core/Handles/__init__.vp +++ b/App/lib/core/Handles/__init__.vp @@ -1,23 +1,9 @@ -import t, c -from stdint import * - -# Handles 模块(绝对导入,Viper 兼容) -# 参考 Python 版 TransPyC lib/core/Handles 的细粒度拆分 -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesExprOps as HandlesExprOps -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesAssign as HandlesAssign -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.Handles.HandlesReturn as HandlesReturn -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesFunctions as HandlesFunctions -import lib.core.Handles.HandlesBody as HandlesBody -import lib.core.Handles.HandlesIf as HandlesIf -import lib.core.Handles.HandlesWhile as HandlesWhile -import lib.core.Handles.HandlesFor as HandlesFor -import lib.core.Handles.HandlesAugAssign as HandlesAugAssign -import lib.core.Handles.HandlesMain as HandlesMain -import lib.core.Handles.HandlesTranslator as HandlesTranslator +import t, c +from stdint import * + +# Handles 实体模块(去除委托层后保留:数据类/Translator/实体逻辑) +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HandlesTranslator +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.ExprCallTable as ExprCallTable diff --git a/App/lib/core/Phase1.vp b/App/lib/core/Phase1.vp index 483cad0..dda7c58 100644 --- a/App/lib/core/Phase1.vp +++ b/App/lib/core/Phase1.vp @@ -1,46 +1,41 @@ -import t, c -from stdint import * -import string -import stdlib -import memhub -import viperlib -import w32.fileio as fileio -import w32.win32file -import w32.win32base -import ast -import llvmlite -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HandlesTranslator -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.IncludesScanner as IncludesScanner -import lib.core.StubMerger as StubMerger -import lib.core.Gen.Generator as GenGenerator -import lib.core.CompilerFactory as CompilerFactory -import lib.core.BuildPipeline as BuildPipeline -import lib.Projectrans.Config as Config -import lib.StubGen.Converter as StubConverter -import lib.core.StubMergerBuild as StubMergerBuild -import lib.core.StubMergerCollect as StubMergerCollect -import lib.core.StubMergerIR as StubMergerIR -import lib.core.StubMergerStore as StubMergerStore -import lib.core.Handles.ExprCallCtor as ExprCallCtor - -# 全局 mbuddy 指针 -_mbuddy: memhub.MemBuddy | t.CPtr - -# 源代码缓冲区大小(1MB) -SRC_BUF_SIZE: t.CDefine = 1048576 - -# vpi 缓冲区大小(256KB) -PYI_BUF_SIZE: t.CSizeT = 262144 - -# 拓扑排序相关常量 -MAX_CLASSES: t.CDefine = 512 -MAX_FILE_DEPS: t.CDefine = 256 -MAX_DEP_EDGES: t.CDefine = 16 -SHA1_LEN: t.CDefine = 17 -CLASS_NAME_LEN: t.CDefine = 64 +import t, c +from stdint import * +import string +import stdlib +import memhub +import viperlib +import w32.fileio as fileio +import w32.win32file +import w32.win32base +import ast +import llvmlite +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HandlesTranslator +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.IncludesScanner as IncludesScanner +import lib.core.StubMerger as StubMerger +import lib.core.Gen.Generator as GenGenerator +import lib.core.CompilerFactory as CompilerFactory +import lib.core.BuildPipeline as BuildPipeline +import lib.Projectrans.Config as Config +import lib.StubGen.Converter as StubConverter +import lib.core.StubMergerBuild as StubMergerBuild +import lib.core.StubMergerCollect as StubMergerCollect +import lib.core.StubMergerIR as StubMergerIR +import lib.core.StubMergerStore as StubMergerStore + +# 全局 mbuddy 指针 +_mbuddy: memhub.MemBuddy | t.CPtr + +# 源代码缓冲区大小(1MB) +SRC_BUF_SIZE: t.CDefine = 1048576 + +# vpi 缓冲区大小(256KB) +PYI_BUF_SIZE: t.CSizeT = 262144 + +# 拓扑排序相关常量 +MAX_CLASSES: t.CDefine = 512 +MAX_FILE_DEPS: t.CDefine = 256 +MAX_DEP_EDGES: t.CDefine = 16 +SHA1_LEN: t.CDefine = 17 +CLASS_NAME_LEN: t.CDefine = 64 diff --git a/App/lib/core/Phase1Main.vp b/App/lib/core/Phase1Main.vp index 9a3ea59..4d1ab96 100644 --- a/App/lib/core/Phase1Main.vp +++ b/App/lib/core/Phase1Main.vp @@ -1,973 +1,969 @@ -import t, c -from stdint import * -import string -import stdlib -import memhub -import viperlib -import w32.fileio as fileio -import w32.win32file -import w32.win32base -import ast -import llvmlite -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HandlesTranslator -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.IncludesScanner as IncludesScanner -import lib.core.StubMerger as StubMerger -import lib.core.Gen.Generator as GenGenerator -import lib.core.CompilerFactory as CompilerFactory -import lib.core.BuildPipeline as BuildPipeline -import lib.Projectrans.Config as Config -import lib.StubGen.Converter as StubConverter -import lib.core.StubMergerBuild as StubMergerBuild -import lib.core.StubMergerCollect as StubMergerCollect -import lib.core.StubMergerIR as StubMergerIR -import lib.core.StubMergerStore as StubMergerStore -import lib.core.Handles.ExprCallCtor as ExprCallCtor - - -import lib.core.Phase1Scan as Phase1Scan -import lib.core.Phase1Topo as Phase1Topo -import lib.core.Phase1 as Phase1 - -# ============================================================ -# Phase1Main - Phase1 拆分(阶段 E):Phase1Main -# -# 直接移动模式:函数迁至此模块,原 Phase1.vp 仅保留常量/_mbuddy; -# 调用方经本模块前缀访问。全局符号经 Phase1._xxx 跨模块访问。 -# ============================================================ - -# ============================================================ -# RunPhase1 - Phase1: 扫描 includes 目录,按需翻译并生成 stub -# -# 对每个 .vp/.py 文件检查 stub 是否已存在,若不存在则翻译并分离 stub。 -# "按需翻译":仅对 stub 不存在的文件执行翻译,避免重复工作。 -# -# Args: -# mb: 内存池 -# includes_dir: includes 目录路径 -# temp_dir: 临时目录(保存 stub) -# log: 日志器 -# -# Returns: -# 0 成功,非 0 失败 -# ============================================================ -def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, - log: VLogger.Logger | t.CPtr) -> int: - """Phase1: 扫描 includes 目录,按需翻译并生成 stub""" - if includes_dir is None or temp_dir is None: - VLogger.error("includes_dir 或 temp_dir 为空,无法运行 Phase1", "Phase1") - return 1 - - # 设置全局 temp_dir(供跨模块 CDefine 查找使用) - HandlesType.set_temp_dir(temp_dir) - # 同步设置 HandlesExprCall 的 temp_dir(供 vpi stub 返回注解缓存按需加载)。 - # 必须在 includes 翻译前设置:Phase1 翻译 json 等 includes 时,"同模块方法 - # 调用(定义在后)"(如 json.__setitem__ 调 _pool_alloc)需要读 - # {temp_dir}/{sha1[0:2]}/{sha1}.vpi 兜底,而 Phase2 的 SetTempDir 太晚。 - ExprCallCtor.SetTempDir(temp_dir) - - # 确保 temp 目录存在(build_dir/temp 可能尚未创建) - BuildPipeline.ensure_dir(temp_dir) - - if log is not None: - log.banner("Phase1: 扫描 includes(按需翻译)") - - # 扫描 includes 目录 - result: IncludesScanner.ScanResult | t.CPtr = IncludesScanner.scan_includes(mb, includes_dir) - if result is None: - VLogger.error("扫描失败", "Phase1") - return 1 - - # 从扫描结果直接构建 SHA1 集合(不依赖 _sha1_map.txt 文件) - # Phase1 作为编译器自身,应从内存中的扫描结果获取 SHA1,避免外部文件依赖 - sha1_set: str = stdlib.malloc(StubMerger.MAX_INCLUDES_SHA1 * 17) - if sha1_set is None: - VLogger.error("sha1_set 分配失败", "Phase1") - return 1 - string.memset(sha1_set, 0, StubMerger.MAX_INCLUDES_SHA1 * 17) - set_count: int = 0 - p1_entry_size_init: t.CSizeT = IncludesScanner.FileEntry.__sizeof__() - for se_i in range(result.Count): - if set_count >= StubMerger.MAX_INCLUDES_SHA1: - break - se_addr: t.CUInt64T = t.CUInt64T(result.Entries) + se_i * p1_entry_size_init - se_ent: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(se_addr, t.CPtr)) - if se_ent is None or se_ent.Sha1 is None: - continue - string.strcpy(sha1_set + set_count * 17, se_ent.Sha1) - set_count += 1 - # 先填充全局 SHA1 映射存储器(即使 set_count==0 也填充,确保 Phase2 能获取 includes 条目) - # 注意:PopulateSha1MapStore 会先 free 旧存储器再重新分配 - StubMergerStore.PopulateSha1MapStore(result) - # 写入 _sha1_map.txt(人类可读输出,程序内部不读取;机器分析使用 PopulateSha1MapStore 内存存储器) - StubMergerCollect.WriteIncludesSha1Map(mb, temp_dir, result, None, 0) - if set_count <= 0: - VLogger.warning("扫描结果无有效 SHA1,跳过 Phase1(项目可能无 includes 依赖)", "Phase1") - stdlib.free(sha1_set) - return 0 - # 模块 SHA1 映射已由 PopulateSha1MapStore 填充到 StubMerger 全局存储器, - # HandlesExprCall._lookup_module_sha1 直接查全局存储器,不再需要独立副本。 - - # 初始化 AST 表(只需一次) - ast._init_tables(mb) - - # FileEntry 结构体大小(Phase 1a 和 1b 共用) - entry_size: t.CSizeT = IncludesScanner.FileEntry.__sizeof__() - - # ============================================================ - # Phase 1a-pre: 扫描所有 includes 文件的 import 依赖 - # - # 只处理 Import/ImportFrom 语句,跳过 ClassDef/FunctionDef 等, - # 不调用 resolve_annotation_type,避免 list[...] 等不支持的语法触发 crash。 - # 生成 .deps.txt 供依赖图按需翻译使用。 - # ============================================================ - p1a_registered: int = 0 - p1a_skipped: int = 0 - p1a_failed: int = 0 - - for i in range(result.Count): - # 文件级 mark:import 依赖收集完(deps 写盘 + PopulateIncludesDeps - # 内部 stdlib 深拷贝)后立即回收本文件 AST——98 includes 全量 parse - # 的 AST 若驻留到 mark1 → 1GB 主池耗尽 OOM 根因之一 - scan_mark_a: t.CSizeT = mb.mark() - entry_addr_a: t.CUInt64T = t.CUInt64T(result.Entries) + i * entry_size - entry_a: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_a, t.CPtr)) - if entry_a is None: - p1a_failed += 1 - continue - - sha1_a: str = entry_a.Sha1 - if sha1_a is None: - p1a_failed += 1 - continue - - if StubMergerCollect._is_in_sha1_set(sha1_a, sha1_set, set_count) == 0: - p1a_skipped += 1 - continue - - # 读取文件内容 - file_path_a: str = entry_a.Path - f_a: fileio.File | t.CPtr = fileio.File(file_path_a, fileio.MODE.R) - if f_a.closed: - p1a_failed += 1 - continue - - src_buf_a: bytes = stdlib.malloc(Phase1.SRC_BUF_SIZE) - if src_buf_a is None: - f_a.close() - p1a_failed += 1 - continue - - bytes_read_a: LONG = f_a.read_all(src_buf_a, Phase1.SRC_BUF_SIZE) - f_a.close() - if bytes_read_a <= 0: - stdlib.free(src_buf_a) - p1a_failed += 1 - continue - if bytes_read_a < Phase1.SRC_BUF_SIZE: - src_buf_a[bytes_read_a] = 0 - else: - src_buf_a[Phase1.SRC_BUF_SIZE - 1] = 0 - - # 解析 AST - lx_a: ast.Lexer | t.CPtr = ast.new_lexer(mb) - if lx_a is None: - stdlib.free(src_buf_a) - p1a_failed += 1 - continue - ast._lexer_init(lx_a, src_buf_a, mb) - tokens_a: ast.Token | t.CPtr = ast.tokenize(lx_a) - tree_a: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens_a) - if tree_a is None: - stdlib.free(src_buf_a) - p1a_failed += 1 - continue - - # 创建 Translator,设置 _declare_only=2(只扫描 import,跳过 ClassDef) - tr_a: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator() - if tr_a is None: - stdlib.free(src_buf_a) - p1a_failed += 1 - continue - tr_a.ModuleSha1 = sha1_a - tr_a._declare_only = 2 - tr_a.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry_a.RelPath) - HandlesType.set_current_file(file_path_a) - HandlesImports.set_current_file(file_path_a) - HandlesType.set_current_module_sha1(sha1_a) - HandlesType.clear_cdefine_constants() - HandlesType.clear_ctypedefs() - HandlesStruct.reset_visible_structs(mb, 0) - ret_a: int = tr_a.translate(tree_a) - if ret_a != 0: - p1a_failed += 1 - else: - p1a_registered += 1 - - # 容器模板按需纳入依赖:includes 使用 list/dict 泛型/构造/字面量 - # (如 base.vp 的 list[AST | CPtr])时追加 _list/_dict 到 - # _imported_modules → 进 deps → _BuildReachableSha1Set 的可达集合 - # 自动包含(Phase1 与 Phase2 都受益),否则泛型模板未注册 → - # "泛型类 'list' 未找到模板"。对齐 App 层 _inject_auto_container_visibility。 - cl_box: t.CPtr = stdlib.malloc(4) - cd_box: t.CPtr = stdlib.malloc(4) - if cl_box is not None and cd_box is not None: - cl_box[0] = 0 - cd_box[0] = 0 - Phase1Scan._ScanTreeForContainers(tree_a, cl_box, cd_box) - if cl_box[0] != 0: - if tr_a._imported_modules is None or \ - HandlesImports.is_module_imported(tr_a._imported_modules, "_list") == 0: - tr_a._imported_modules = HandlesImports.add_imported_module( - mb, tr_a._imported_modules, "_list") - if cd_box[0] != 0: - if tr_a._imported_modules is None or \ - HandlesImports.is_module_imported(tr_a._imported_modules, "_dict") == 0: - tr_a._imported_modules = HandlesImports.add_imported_module( - mb, tr_a._imported_modules, "_dict") - if cl_box is not None: - stdlib.free(cl_box) - if cd_box is not None: - stdlib.free(cd_box) - - # 生成 .deps.txt(记录依赖模块名,供依赖图按需翻译使用) - # 同时填充内存依赖存储器(PopulateIncludesDeps),供 _BuildReachableSha1Set - # 直接从内存读取,不依赖 .deps.txt 过程文件 - td_len_a: t.CSizeT = string.strlen(temp_dir) - deps_path_a: str = StubMergerCollect._sliced_path(temp_dir, td_len_a, sha1_a, "deps.txt") - if deps_path_a is not None: - df_a: fileio.File | t.CPtr = fileio.File(deps_path_a, fileio.MODE.W) - if not df_a.closed: - if tr_a._imported_modules is not None: - dl_a: t.CSizeT = string.strlen(tr_a._imported_modules) - df_a.write(tr_a._imported_modules, dl_a) - df_a.close() - stdlib.free(deps_path_a) - # 填充内存依赖存储器(供 _BuildReachableSha1Set 使用,不读 .deps.txt) - if tr_a._imported_modules is not None: - StubMergerStore.PopulateIncludesDeps(sha1_a, tr_a._imported_modules) - - # 释放 Translator 的 C malloc 资源 - if tr_a._global_names is not None: - stdlib.free(tr_a._global_names) - if tr_a._nonlocal_names is not None: - stdlib.free(tr_a._nonlocal_names) - - stdlib.free(src_buf_a) - # 回收本文件 AST/lexer/token(deps 已写盘、依赖存储器已深拷贝) - mb.reset_to(scan_mark_a) - - if p1a_failed > 0: - fb_p1apre: str = VLogger.fmt_buf() - if fb_p1apre is not None: - viperlib.snprintf(fb_p1apre, 1024, "Phase 1a-pre 有 %d 个文件扫描失败", p1a_failed) - VLogger.error(fb_p1apre, "Phase1") - return 1 - - # ============================================================ - # 依赖图按需翻译:构建可达 SHA1 集合 - # - # 从 Config.SourceDir 的源文件开始,解析 import 语句,递归收集 - # 可达的 includes 文件 SHA1。Phase 1b 只翻译可达集合中的文件, - # 避免翻译不需要的 includes(如 Test 不依赖 llvmlite,则不翻译)。 - # 如果 Config.SourceDir 不可用(仅运行 Phase1),回退到 sha1_set。 - # ============================================================ - reachable_set: str = None - reachable_count: int = 0 - use_reachable: int = 0 - if Config.SourceDir is not None: - reachable_set = stdlib.malloc(StubMerger.MAX_INCLUDES_SHA1 * 17) - if reachable_set is not None: - string.memset(reachable_set, 0, StubMerger.MAX_INCLUDES_SHA1 * 17) - reachable_count = StubMergerBuild._BuildReachableSha1Set(mb, Config.SourceDir, temp_dir, reachable_set) - if reachable_count < 0: - VLogger.error("可达集合构建失败,终止", "Phase1") - return 1 - if reachable_count > 0: - use_reachable = 1 - # 用可达集合重新生成 _sha1_map.txt(按图求索的最终产物) - # Phase B+ 只遍历这些条目,避免编译不需要的 includes(如 asm.vp) - StubMergerCollect.WriteIncludesSha1Map(mb, temp_dir, result, reachable_set, reachable_count) - # 重新加载 sha1_set,使后续 Phase 1a-pre/1a/1b 的过滤也使用可达集合 - string.memset(sha1_set, 0, StubMerger.MAX_INCLUDES_SHA1 * 17) - set_count = StubMergerCollect._load_includes_sha1_set(mb, temp_dir, sha1_set) - else: - VLogger.warning("可达集合为空,回退全量扫描", "Phase1") - stdlib.free(reachable_set) - reachable_set = None - - # ============================================================ - # Phase 1a: 注册可达 includes 文件的 struct/enum/union - # - # 解决字母序依赖问题:按字母顺序翻译时,后面的 struct 未注册 - # 前面就需要用。Phase 1a 先注册所有 struct/enum/union 到全局表, - # Phase 1b 全量翻译时 struct 已注册,走 existing 路径只翻译方法体。 - # 只处理可达文件,避免翻译不需要的 includes(如 Test 不依赖 ast 模块)。 - # - # 拓扑排序:预扫描所有文件收集类继承关系,按依赖顺序处理文件, - # 确保父类所在文件先于子类所在文件处理(如 base.vp 先于 astaux.vp)。 - # ============================================================ - p1a_reg: int = 0 - p1a_skp: int = 0 - p1a_fl: int = 0 - - # 预扫描类继承关系,构建拓扑顺序(用扁平字节数组,避免结构体 str 指针 NULL 崩溃) - class_names_buf: bytes = mb.alloc(Phase1.MAX_CLASSES * Phase1.CLASS_NAME_LEN) - parent_names_buf: bytes = mb.alloc(Phase1.MAX_CLASSES * Phase1.CLASS_NAME_LEN) - def_sha1s_buf: bytes = mb.alloc(Phase1.MAX_CLASSES * Phase1.SHA1_LEN) - topo_order: t.CPtr = mb.alloc(4 * Phase1.MAX_FILE_DEPS) - topo_count_box: t.CPtr = mb.alloc(4) - generic_file_indices: t.CPtr = mb.alloc(4 * Phase1.MAX_FILE_DEPS) - generic_file_count_box: t.CPtr = mb.alloc(4) - if generic_file_indices is not None: - string.memset(generic_file_indices, 0, 4 * Phase1.MAX_FILE_DEPS) - if generic_file_count_box is not None: - string.memset(generic_file_count_box, 0, 4) - topo_count: int = 0 - - if class_names_buf is not None and parent_names_buf is not None and def_sha1s_buf is not None and topo_order is not None and topo_count_box is not None: - string.memset(class_names_buf, 0, Phase1.MAX_CLASSES * Phase1.CLASS_NAME_LEN) - string.memset(parent_names_buf, 0, Phase1.MAX_CLASSES * Phase1.CLASS_NAME_LEN) - string.memset(def_sha1s_buf, 0, Phase1.MAX_CLASSES * Phase1.SHA1_LEN) - string.memset(topo_order, 0, 4 * Phase1.MAX_FILE_DEPS) - string.memset(topo_count_box, 0, 4) - if generic_file_indices is not None: - string.memset(generic_file_indices, 0, 4 * Phase1.MAX_FILE_DEPS) - if generic_file_count_box is not None: - string.memset(generic_file_count_box, 0, 4) - - class_count_scanned: int = Phase1Scan._ScanClassInheritance( - mb, result, reachable_set, reachable_count, - use_reachable, sha1_set, set_count, - class_names_buf, parent_names_buf, def_sha1s_buf, - generic_file_indices, generic_file_count_box) - - if class_count_scanned > 0: - td_len_ts_call: t.CSizeT = string.strlen(temp_dir) - ret_topo: int = Phase1Topo._TopoSortFiles( - mb, result, reachable_set, reachable_count, - use_reachable, sha1_set, set_count, - class_names_buf, parent_names_buf, def_sha1s_buf, class_count_scanned, - topo_order, topo_count_box, - temp_dir, td_len_ts_call) - if ret_topo == 0: - tc_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(topo_count_box, t.CPtr)) - if tc_ptr is not None: - topo_count = tc_ptr[0] - fb_topo: str = VLogger.fmt_buf() - if fb_topo is not None: - viperlib.snprintf(fb_topo, 1024, - "拓扑排序: %d 个类, %d 个文件按依赖顺序处理", - class_count_scanned, topo_count) - VLogger.info(fb_topo, "Phase1") - else: - VLogger.error("拓扑排序失败(类继承依赖无法解析),终止编译", "Phase1") - return 1 - else: - VLogger.warning("类继承预扫描无结果,回退到字母序", "Phase1") - topo_count = 0 - - # ============================================================ - # Phase 1a-pre-generic-all: mark1 前全量预注册 includes 泛型模板 - # - # 1a-pre-generic 只覆盖"可达"泛型文件;非可达泛型文件(如 FuncTest - # 场景的 linkedlist/llvmlite/_list)的模板要等 Phase2 Phase A-pre-inc - # (mark2 之后)才注册 → reset 回收表/节点 → _find_generic_template - # strcmp 悬空崩溃。此处对全部 includes 轻量预注册,使模板表与节点 - # 都落在 mark1 之前(mark2 > mark1,reset_to(mark2) 不回收)。 - # ============================================================ - Phase1Scan._PreRegisterAllGenericTemplates(mb, result) - - # ============================================================ - # Phase 1a: 注册 struct/enum/union(mark1 前,全量 includes) - # - # OOM 治理:1a 对全部 includes parse 完整 AST(主 pool 分配),若 - # 驻留到 mark1(循环后)会累积 98 文件 × 每文件 AST 树 → 1GB 主池 - # 耗尽(NewAstTest alloc 失败 0xBE 根因)。现改为: - # 1) StdlibAlloc=1:1a 注册的跨文件持久数据(StructTable 表、 - # Fields/Name/ModuleSha1、struct_ty 深拷贝、枚举/Renum/泛型 - # 模板等)全部落在 perm_pool(永不 reset),不占主 pool; - # 2) 每文件翻译完 reset_to(文件级 mark):仅回收该文件的 AST/ - # lexer/token/IR 等瞬时数据,注册数据不受影响。 - # mark1 仍在 1a 结束后打,1b 每文件 reset_to(mark1) 语义不变。 - # ============================================================ - HandlesStruct.set_stdlib_alloc(1) - - # 遍历文件:优先使用拓扑顺序,回退到字母序 - iter_count: int = topo_count if topo_count > 0 else result.Count - for i in range(iter_count): - # 每文件级 mark:翻译完回收该文件 AST(注册数据在 perm_pool) - p1a_mark: t.CSizeT = mb.mark() - # 获取文件索引:拓扑顺序或字母序 - file_idx: int = i - if topo_count > 0: - od_addr: t.CUInt64T = t.CUInt64T(topo_order) + i * 4 - od_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(od_addr, t.CPtr)) - if od_ptr is not None: - file_idx = od_ptr[0] - - entry_addr_r: t.CUInt64T = t.CUInt64T(result.Entries) + file_idx * entry_size - entry_r: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_r, t.CPtr)) - if entry_r is None: - p1a_fl += 1 - continue - - sha1_r: str = entry_r.Sha1 - if sha1_r is None: - p1a_fl += 1 - continue - - # 按需翻译过滤(拓扑排序已过滤,但字母序回退需要检查) - if topo_count == 0: - if use_reachable != 0: - if StubMergerCollect._is_in_sha1_set(sha1_r, reachable_set, reachable_count) == 0: - p1a_skp += 1 - continue - else: - if StubMergerCollect._is_in_sha1_set(sha1_r, sha1_set, set_count) == 0: - p1a_skp += 1 - continue - - # 读取文件内容 - file_path_r: str = entry_r.Path - f_r: fileio.File | t.CPtr = fileio.File(file_path_r, fileio.MODE.R) - if f_r.closed: - p1a_fl += 1 - continue - - src_buf_r: bytes = stdlib.malloc(Phase1.SRC_BUF_SIZE) - if src_buf_r is None: - f_r.close() - p1a_fl += 1 - continue - - bytes_read_r: LONG = f_r.read_all(src_buf_r, Phase1.SRC_BUF_SIZE) - f_r.close() - if bytes_read_r <= 0: - stdlib.free(src_buf_r) - p1a_fl += 1 - continue - if bytes_read_r < Phase1.SRC_BUF_SIZE: - src_buf_r[bytes_read_r] = 0 - else: - src_buf_r[Phase1.SRC_BUF_SIZE - 1] = 0 - - # 解析 AST - lx_r: ast.Lexer | t.CPtr = ast.new_lexer(mb) - if lx_r is None: - stdlib.free(src_buf_r) - p1a_fl += 1 - continue - ast._lexer_init(lx_r, src_buf_r, mb) - tokens_r: ast.Token | t.CPtr = ast.tokenize(lx_r) - tree_r: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens_r) - if tree_r is None: - stdlib.free(src_buf_r) - p1a_fl += 1 - continue - - # 创建 Translator,设置 _declare_only=1(注册 struct/enum/union) - tr_r: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator() - if tr_r is None: - stdlib.free(src_buf_r) - p1a_fl += 1 - continue - tr_r.ModuleSha1 = sha1_r - tr_r._declare_only = 1 - tr_r.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry_r.RelPath) - HandlesType.set_current_file(file_path_r) - HandlesImports.set_current_file(file_path_r) - HandlesType.set_current_module_sha1(sha1_r) - HandlesType.clear_cdefine_constants() - HandlesType.clear_ctypedefs() - HandlesStruct.reset_visible_structs(mb, 0) - ret_r: int = tr_r.translate(tree_r) - if ret_r != 0: - p1a_fl += 1 - else: - p1a_reg += 1 - - # 释放 Translator 的 C malloc 资源 - if tr_r._global_names is not None: - stdlib.free(tr_r._global_names) - if tr_r._nonlocal_names is not None: - stdlib.free(tr_r._nonlocal_names) - stdlib.free(src_buf_r) - - # 回收本文件 AST/lexer/token/IR 等瞬时数据(注册数据已在 perm_pool, - # reset 不影响;IncludesScanner result 等在 p1a_mark 前分配同样保留) - mb.reset_to(p1a_mark) - - if p1a_fl > 0: - fb_p1ar: str = VLogger.fmt_buf() - if fb_p1ar is not None: - viperlib.snprintf(fb_p1ar, 1024, "Phase 1a 有 %d 个文件 struct 注册失败", p1a_fl) - VLogger.error(fb_p1ar, "Phase1") - return 1 - - # 释放拓扑排序资源(topo_order/topo_count_box 保留到 Phase 1b 结束, - # 1b 按拓扑序翻译需要它们;class/def 数组 1b 不再使用) - if class_names_buf is not None: - mb.free(class_names_buf) - if parent_names_buf is not None: - mb.free(parent_names_buf) - if def_sha1s_buf is not None: - mb.free(def_sha1s_buf) - if generic_file_indices is not None: - mb.free(generic_file_indices) - if generic_file_count_box is not None: - mb.free(generic_file_count_box) - - # ============================================================ - # Phase 1b: 全量翻译(struct 已注册,走 existing 路径翻译方法体) - # ============================================================ - # OOM 回收:1a-pre/泛型预注册/1a 全部结束后打 mark1, - # 所有跨文件持久表(_struct_table/_enum_table/_generic_class_nodes/ - # _renum_*/关键字表等)都落在 mark1 之前。 - # 1b 每文件翻译完后 reset_to(mark1) 回收该文件的 AST/IR/Handler/dump 临时, - # 避免 90 文件累积导致 1GB 池 OOM。 - mark1: t.CSizeT = mb.mark() - - # 1b 阶段新注册的 struct/enum 条目改 stdlib 分配(跨文件永久存活,不被 reset 回收) - HandlesStruct.set_stdlib_alloc(1) - - # ============================================================ - # Phase 1b-pre: 预生成所有待翻译文件的 .vpi stub - # - # 依赖模块的 .vpi 必须在翻译前可用:1b 主循环按扫描顺序翻译(非拓扑), - # 若 argparse 先于 hashtable 翻译,hashtable.vpi 尚未生成, - # LoadDepVpiIntoModule 读不到 → declare 未注入 → 跨模块调用 - # 返回类型推断错误(如 HashTable.__getitem__ 被推断为 Ptr(HashTable) - # 而 define 返回 i8*)→ 运行时返回值截断崩溃。 - # ============================================================ - p1bpre_failed: int = 0 - dir_len_pv: t.CSizeT = string.strlen(temp_dir) - for i_pv in range(result.Count): - entry_addr_pv: t.CUInt64T = t.CUInt64T(result.Entries) + i_pv * entry_size - entry_pv: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_pv, t.CPtr)) - if entry_pv is None or entry_pv.Sha1 is None: - p1bpre_failed += 1 - continue - sha1_pv: str = entry_pv.Sha1 - in_set_pv: int = 0 - if use_reachable != 0: - in_set_pv = StubMergerCollect._is_in_sha1_set(sha1_pv, reachable_set, reachable_count) - else: - in_set_pv = StubMergerCollect._is_in_sha1_set(sha1_pv, sha1_set, set_count) - if in_set_pv == 0: - continue - # vpi 已存在则跳过 - vpi_path_pv: str = StubMergerCollect._sliced_path(temp_dir, dir_len_pv, sha1_pv, "vpi") - if vpi_path_pv is None: - p1bpre_failed += 1 - continue - vf_pv: fileio.File | t.CPtr = fileio.File(vpi_path_pv, fileio.MODE.R) - if not vf_pv.closed: - vf_pv.close() - stdlib.free(vpi_path_pv) - continue - stdlib.free(vpi_path_pv) - # 读取文件、解析 AST、生成 vpi - file_path_pv: str = entry_pv.Path - f_pv: fileio.File | t.CPtr = fileio.File(file_path_pv, fileio.MODE.R) - if f_pv.closed: - p1bpre_failed += 1 - continue - src_buf_pv: bytes = stdlib.malloc(Phase1.SRC_BUF_SIZE) - if src_buf_pv is None: - f_pv.close() - p1bpre_failed += 1 - continue - bytes_read_pv: LONG = f_pv.read_all(src_buf_pv, Phase1.SRC_BUF_SIZE) - f_pv.close() - if bytes_read_pv <= 0: - stdlib.free(src_buf_pv) - p1bpre_failed += 1 - continue - if bytes_read_pv < Phase1.SRC_BUF_SIZE: - src_buf_pv[bytes_read_pv] = 0 - else: - src_buf_pv[Phase1.SRC_BUF_SIZE - 1] = 0 - lx_pv: ast.Lexer | t.CPtr = ast.new_lexer(mb) - if lx_pv is None: - stdlib.free(src_buf_pv) - p1bpre_failed += 1 - continue - ast._lexer_init(lx_pv, src_buf_pv, mb) - tokens_pv: ast.Token | t.CPtr = ast.tokenize(lx_pv) - tree_pv: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens_pv) - if tree_pv is None: - stdlib.free(src_buf_pv) - p1bpre_failed += 1 - continue - pyi_buf_pv: bytes = stdlib.malloc(Phase1.PYI_BUF_SIZE) - if pyi_buf_pv is not None: - pyi_pos_pv: t.CSizeT = StubConverter._GeneratePyiFromAst(mb, tree_pv, entry_pv.RelPath, pyi_buf_pv, Phase1.PYI_BUF_SIZE) - if pyi_pos_pv > 0: - pyi_path_pv: str = StubMergerCollect._sliced_path(temp_dir, dir_len_pv, sha1_pv, "vpi") - if pyi_path_pv is not None: - pf_pv: fileio.File | t.CPtr = fileio.File(pyi_path_pv, fileio.MODE.W) - if not pf_pv.closed: - pf_pv.write(pyi_buf_pv, pyi_pos_pv) - pf_pv.close() - stdlib.free(pyi_path_pv) - stdlib.free(pyi_buf_pv) - else: - p1bpre_failed += 1 - stdlib.free(src_buf_pv) - # 回收本文件 AST(vpi 已写盘,AST 不再需要;mark1 后无其他持久数据) - mb.reset_to(mark1) - - if p1bpre_failed > 0: - fb_p1bpre: str = VLogger.fmt_buf() - if fb_p1bpre is not None: - viperlib.snprintf(fb_p1bpre, 1024, "Phase 1b-pre 有 %d 个文件 vpi 预生成失败", p1bpre_failed) - VLogger.error(fb_p1bpre, "Phase1") - return 1 - - # 遍历每个文件(拓扑序优先:父类所在文件先翻译,确保跨模块 vtable - # 生成时依赖模块的函数 TypeStr 已注册;topo_count==0 回退扫描顺序) - translated: int = 0 - skipped: int = 0 - failed: int = 0 - - loop_n_b: int = result.Count - if topo_count > 0: - loop_n_b = topo_count - for i in range(loop_n_b): - # 获取 entry(拓扑序:file_idx 从 topo_order 取,否则用扫描索引) - file_idx_b: int = i - if topo_count > 0: - od_addr_b: t.CUInt64T = t.CUInt64T(topo_order) + t.CSizeT(i) * 4 - od_ptr_b: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(od_addr_b, t.CPtr)) - if od_ptr_b is not None: - file_idx_b = od_ptr_b[0] - entry_addr: t.CUInt64T = t.CUInt64T(result.Entries) + t.CSizeT(file_idx_b) * entry_size - entry: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - if entry is None: - failed += 1 - continue - - sha1: str = entry.Sha1 - if sha1 is None: - failed += 1 - continue - - # 检查 SHA1 是否在翻译集合中(拓扑序已过滤可达;仅回退扫描顺序时检查) - in_set: int = 1 - if topo_count == 0: - in_set = 0 - if use_reachable != 0: - in_set = StubMergerCollect._is_in_sha1_set(sha1, reachable_set, reachable_count) - else: - in_set = StubMergerCollect._is_in_sha1_set(sha1, sha1_set, set_count) - if in_set == 0: - skipped += 1 - continue - - # 构造 stub 路径: {temp_dir}/{sha1}.stub.ll - dir_len: t.CSizeT = string.strlen(temp_dir) - sha1_len: t.CSizeT = string.strlen(sha1) - stub_path: str = StubMergerCollect._sliced_path(temp_dir, dir_len, sha1, "stub.ll") - if stub_path is None: - failed += 1 - continue - - # 检查 stub 是否已存在(按需翻译:跳过已存在的) - sf: fileio.File | t.CPtr = fileio.File(stub_path, fileio.MODE.R) - if not sf.closed: - sf.close() - # 检查 text.ll 是否也存在(虚表扫描需要 text.ll) - text_path: str = StubMergerCollect._sliced_path(temp_dir, dir_len, sha1, "text.ll") - if text_path is not None: - tf: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R) - if not tf.closed: - tf.close() - stdlib.free(text_path) - stdlib.free(stub_path) - continue - stdlib.free(text_path) - # text.ll 不存在,需要重新翻译 - rp: str = entry.RelPath - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "text.ll 不存在,重新翻译: %s(sha1=%s)", rp, sha1) - VLogger.info(fb, "Phase1") - else: - # stub 不存在,需要翻译 - rp: str = entry.RelPath - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "翻译: %s(sha1=%s)", rp, sha1) - VLogger.info(fb, "Phase1") - - stdlib.free(stub_path) - - # 读取文件内容 - file_path: str = entry.Path - f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R) - if f is None: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "无法打开(None): %s", file_path) - VLogger.error(fb, "Phase1") - failed += 1 - continue - if f.closed: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "无法打开: %s", file_path) - VLogger.error(fb, "Phase1") - failed += 1 - continue - - src_buf: bytes = stdlib.malloc(Phase1.SRC_BUF_SIZE) - if src_buf is None: - f.close() - failed += 1 - continue - - bytes_read: LONG = f.read_all(src_buf, Phase1.SRC_BUF_SIZE) - f.close() - if bytes_read <= 0: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "读取失败: %s", file_path) - VLogger.error(fb, "Phase1") - stdlib.free(src_buf) - failed += 1 - continue - if bytes_read < Phase1.SRC_BUF_SIZE: - src_buf[bytes_read] = 0 - else: - src_buf[Phase1.SRC_BUF_SIZE - 1] = 0 - - # 解析 AST - lx: ast.Lexer | t.CPtr = ast.new_lexer(mb) - if lx is None: - stdlib.free(src_buf) - failed += 1 - continue - ast._lexer_init(lx, src_buf, mb) - tokens: ast.Token | t.CPtr = ast.tokenize(lx) - tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens) - if tree is None: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "AST 解析失败: %s", file_path) - VLogger.error(fb, "Phase1") - stdlib.free(src_buf) - failed += 1 - continue - - # 文本扫描注册 CTypedef(stdint.vp 崩溃根因修复):AST 字符串字段 - # (attr/id)token 零拷贝指向 src_buf,跨阶段内容不稳定(悬空), - # ScanCTypedefDeclarations 读 attr 会 0xC0000005。改用源码文本逐行 - # 匹配 "NAME: t.CTypedef = TYPE",在 src_buf 有效期内注册。 - HandlesType.RegisterCTypedefFromSource(mb, src_buf) - - # 生成 .vpi 存根文件(直接遍历 AST,不依赖 PythonToStubConverter) - pyi_buf: bytes = stdlib.malloc(Phase1.PYI_BUF_SIZE) - if pyi_buf is not None: - pyi_pos: t.CSizeT = StubConverter._GeneratePyiFromAst(mb, tree, entry.RelPath, pyi_buf, Phase1.PYI_BUF_SIZE) - if pyi_pos > 0: - pyi_path: str = StubMergerCollect._sliced_path(temp_dir, dir_len, sha1, "vpi") - if pyi_path is not None: - pf: fileio.File | t.CPtr = fileio.File(pyi_path, fileio.MODE.W) - if not pf.closed: - pf.write(pyi_buf, pyi_pos) - pf.close() - stdlib.free(pyi_path) - stdlib.free(pyi_buf) - - # 翻译 AST → LLVM IR - tr: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator() - if tr is None: - stdlib.free(src_buf) - failed += 1 - continue - tr.ModuleSha1 = sha1 - tr.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry.RelPath) - HandlesType.set_current_file(file_path) - HandlesImports.set_current_file(file_path) - HandlesType.set_current_module_sha1(sha1) - HandlesType.clear_cdefine_constants() - HandlesType.clear_ctypedefs() - HandlesStruct.reset_visible_structs(mb, 0) - - # 翻译前哨兵:AST 解析(lexer/tokenize/parse_tokens)同样在 pool 分配, - # 若解析器越界写破坏了存活块 header,此处立即定位到当前文件 - # (崩溃点漂移排查:把"翻译过程中随机崩"变成确定性定位) - pre_rc: t.CInt = mb.check_alive_blocks(mark1) - if pre_rc != 0: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, - "内存损坏(翻译前存活块, rc=%d): %s", pre_rc, file_path) - VLogger.error(fb, "Phase1") - stdlib.exit(1) - - ret: int = tr.translate(tree) - # 诊断:translate 正常返回(若挂起在 translate 内部,此行不会打印, - # 用于区分"translate 内部挂起"与"后续 dump 挂起") - if ret == 0: - fb_done: str = VLogger.fmt_buf() - if fb_done is not None: - viperlib.snprintf(fb_done, 1024, "翻译完成(translate返回): %s", file_path) - VLogger.info(fb_done, "Phase1") - if ret != 0: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "翻译失败: %s", file_path) - VLogger.error(fb, "Phase1") - stdlib.free(src_buf) - if tr._global_names is not None: - stdlib.free(tr._global_names) - if tr._nonlocal_names is not None: - stdlib.free(tr._nonlocal_names) - failed += 1 - continue - - # 诊断(builtins.vp dump 卡死根因排查):pre_rc 哨兵在 translate 前, - # 覆盖不到 translate 期间的 AST/IR 写穿。dump 前立即检查存活块 - # header/canary(rc=6 块尾 canary 损坏=越界写穿数据区),把"dump - # 时链表成环卡死"变成"定位到 translate 期间写穿发生的文件"。 - post_rc: t.CInt = mb.check_alive_blocks(mark1) - if post_rc != 0: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, - "内存损坏(translate后存活块, rc=%d): %s", post_rc, file_path) - VLogger.error(fb, "Phase1") - stdlib.exit(1) - - # dump stub IR(declarations only) - PHASE1_IR_SIZE: t.CSizeT = 1048576 - stub_buf: bytes = stdlib.malloc(PHASE1_IR_SIZE) - if stub_buf is None: - stdlib.free(src_buf) - if tr._global_names is not None: - stdlib.free(tr._global_names) - if tr._nonlocal_names is not None: - stdlib.free(tr._nonlocal_names) - failed += 1 - continue - tr.dump_ir(stub_buf, PHASE1_IR_SIZE, llvmlite.OUTPUT_STUB) - stub_len: t.CSizeT = string.strlen(stub_buf) - - # save stub.ll - dir_len_p1: t.CSizeT = string.strlen(temp_dir) - stub_path_p1: str = StubMergerCollect._sliced_path(temp_dir, dir_len_p1, sha1, "stub.ll") - if stub_path_p1 is not None: - sf_p1: fileio.File | t.CPtr = fileio.File(stub_path_p1, fileio.MODE.W) - if not sf_p1.closed: - sf_p1.write(stub_buf, stub_len) - sf_p1.close() - stdlib.free(stub_path_p1) - stdlib.free(stub_buf) - - # dump text IR(definitions only) - text_buf: bytes = stdlib.malloc(PHASE1_IR_SIZE) - if text_buf is None: - stdlib.free(src_buf) - if tr._global_names is not None: - stdlib.free(tr._global_names) - if tr._nonlocal_names is not None: - stdlib.free(tr._nonlocal_names) - failed += 1 - continue - tr.dump_ir(text_buf, PHASE1_IR_SIZE, llvmlite.OUTPUT_TEXT) - text_len: t.CSizeT = string.strlen(text_buf) - - # save text.ll - text_path_p1: str = StubMergerCollect._sliced_path(temp_dir, dir_len_p1, sha1, "text.ll") - if text_path_p1 is not None: - tf_p1: fileio.File | t.CPtr = fileio.File(text_path_p1, fileio.MODE.W) - if not tf_p1.closed: - tf_p1.write(text_buf, text_len) - tf_p1.close() - stdlib.free(text_path_p1) - stdlib.free(text_buf) - - # save dependencies(_imported_modules) for Phase B - deps_path_p1: str = StubMergerCollect._sliced_path(temp_dir, dir_len_p1, sha1, "deps.txt") - if deps_path_p1 is not None: - df_p1: fileio.File | t.CPtr = fileio.File(deps_path_p1, fileio.MODE.W) - if not df_p1.closed: - if tr._imported_modules is not None: - dl: t.CSizeT = string.strlen(tr._imported_modules) - df_p1.write(tr._imported_modules, dl) - df_p1.close() - stdlib.free(deps_path_p1) - - # 释放 Translator 的 C malloc 资源 - if tr._global_names is not None: - stdlib.free(tr._global_names) - if tr._nonlocal_names is not None: - stdlib.free(tr._nonlocal_names) - - # 所有 dump_ir 完成,src_buf 不再需要 - stdlib.free(src_buf) - - translated += 1 - - # OOM 回收:回收本文件翻译产生的瞬时数据(AST/tokens/lexer/IR/Handler/dump 临时) - # 持久表(struct/enum/REnum/spec 缓存/全局函数名等)已迁出 reset 区间(stdlib), - # reset_to(mark1) 只回收 mark1 之后分配、未被单独 free 的块。 - # - # 内存哨兵(崩溃点漂移排查):reset 前检查存活块 header(抓越界写), - # reset 后检查 free list 完整性(抓链表损坏)。任一损坏立即终止, - # 把"随机崩溃漂移"变成"确定性定位到当前文件"。 - # rc 语义(check_alive_blocks):1=块地址低于 usable,2=高于 usable+size, - # 3=order 为负,4=order 超 max_order,5=块未对齐到 order 大小, - # 6=块尾 canary 损坏(越界写穿数据区——事发地定位) - # rc 语义(self_check):1/2=越界,3=对齐错,4=free list 成环/超步数 - chk_rc: t.CInt = mb.check_alive_blocks(mark1) - if chk_rc != 0: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, - "内存损坏(存活块 header, rc=%d): %s", chk_rc, file_path) - VLogger.error(fb, "Phase1") - stdlib.exit(1) - # A/B 实验结论(已确认):禁用 reset_to 后 stdarg 仍崩 → 越界写是根因, - # 与回收/UAF 无关。恢复 reset_to,改用块尾 canary(check_alive_blocks 校验) - # 定位越界写事发地到具体文件。 - mb.reset_to(mark1) - sc_rc: t.CInt = mb.self_check() - if sc_rc != 0: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, - "内存损坏(free list, rc=%d): %s", sc_rc, file_path) - VLogger.error(fb, "Phase1") - stdlib.exit(1) - - # 释放 Phase 1b 使用的拓扑排序资源 - if topo_order is not None: - mb.free(topo_order) - if topo_count_box is not None: - mb.free(topo_count_box) - - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "完成: 翻译=%d 跳过=%d 失败=%d", translated, skipped, failed) - VLogger.info(fb, "Phase1") - - if failed > 0: - fb_fail: str = VLogger.fmt_buf() - if fb_fail is not None: - viperlib.snprintf(fb_fail, 1024, "Phase1 有 %d 个文件翻译失败", failed) - VLogger.error(fb_fail, "Phase1") - return 1 - - # 释放可达 SHA1 集合(如果分配了) - if reachable_set is not None: - stdlib.free(reachable_set) - - return 0 +import lib.core.Gen.GenApi as GenApi +import t, c +from stdint import * +import string +import stdlib +import memhub +import viperlib +import w32.fileio as fileio +import w32.win32file +import w32.win32base +import ast +import llvmlite +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HandlesTranslator +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.IncludesScanner as IncludesScanner +import lib.core.StubMerger as StubMerger +import lib.core.Gen.Generator as GenGenerator +import lib.core.CompilerFactory as CompilerFactory +import lib.core.BuildPipeline as BuildPipeline +import lib.Projectrans.Config as Config +import lib.StubGen.Converter as StubConverter +import lib.core.StubMergerBuild as StubMergerBuild +import lib.core.StubMergerCollect as StubMergerCollect +import lib.core.StubMergerIR as StubMergerIR +import lib.core.StubMergerStore as StubMergerStore + + +import lib.core.Phase1Scan as Phase1Scan +import lib.core.Phase1Topo as Phase1Topo +import lib.core.Phase1 as Phase1 + +# ============================================================ +# Phase1Main - Phase1 拆分(阶段 E):Phase1Main +# +# 直接移动模式:函数迁至此模块,原 Phase1.vp 仅保留常量/_mbuddy; +# 调用方经本模块前缀访问。全局符号经 Phase1._xxx 跨模块访问。 +# ============================================================ + +# ============================================================ +# RunPhase1 - Phase1: 扫描 includes 目录,按需翻译并生成 stub +# +# 对每个 .vp/.py 文件检查 stub 是否已存在,若不存在则翻译并分离 stub。 +# "按需翻译":仅对 stub 不存在的文件执行翻译,避免重复工作。 +# +# Args: +# mb: 内存池 +# includes_dir: includes 目录路径 +# temp_dir: 临时目录(保存 stub) +# log: 日志器 +# +# Returns: +# 0 成功,非 0 失败 +# ============================================================ +def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, + log: VLogger.Logger | t.CPtr) -> int: + """Phase1: 扫描 includes 目录,按需翻译并生成 stub""" + if includes_dir is None or temp_dir is None: + VLogger.error("includes_dir 或 temp_dir 为空,无法运行 Phase1", "Phase1") + return 1 + + # 设置全局 temp_dir(供跨模块 CDefine 查找使用) + GenApi.set_temp_dir(temp_dir) + # 同步设置 HandlesExprCall 的 temp_dir(供 vpi stub 返回注解缓存按需加载)。 + # 必须在 includes 翻译前设置:Phase1 翻译 json 等 includes 时,"同模块方法 + # 调用(定义在后)"(如 json.__setitem__ 调 _pool_alloc)需要读 + # {temp_dir}/{sha1[0:2]}/{sha1}.vpi 兜底,而 Phase2 的 SetTempDir 太晚。 + GenApi.SetTempDir(temp_dir) + + # 确保 temp 目录存在(build_dir/temp 可能尚未创建) + BuildPipeline.ensure_dir(temp_dir) + + if log is not None: + log.banner("Phase1: 扫描 includes(按需翻译)") + + # 扫描 includes 目录 + result: IncludesScanner.ScanResult | t.CPtr = IncludesScanner.scan_includes(mb, includes_dir) + if result is None: + VLogger.error("扫描失败", "Phase1") + return 1 + + # 从扫描结果直接构建 SHA1 集合(不依赖 _sha1_map.txt 文件) + # Phase1 作为编译器自身,应从内存中的扫描结果获取 SHA1,避免外部文件依赖 + sha1_set: str = stdlib.malloc(StubMerger.MAX_INCLUDES_SHA1 * 17) + if sha1_set is None: + VLogger.error("sha1_set 分配失败", "Phase1") + return 1 + string.memset(sha1_set, 0, StubMerger.MAX_INCLUDES_SHA1 * 17) + set_count: int = 0 + p1_entry_size_init: t.CSizeT = IncludesScanner.FileEntry.__sizeof__() + for se_i in range(result.Count): + if set_count >= StubMerger.MAX_INCLUDES_SHA1: + break + se_addr: t.CUInt64T = t.CUInt64T(result.Entries) + se_i * p1_entry_size_init + se_ent: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(se_addr, t.CPtr)) + if se_ent is None or se_ent.Sha1 is None: + continue + string.strcpy(sha1_set + set_count * 17, se_ent.Sha1) + set_count += 1 + # 先填充全局 SHA1 映射存储器(即使 set_count==0 也填充,确保 Phase2 能获取 includes 条目) + # 注意:PopulateSha1MapStore 会先 free 旧存储器再重新分配 + StubMergerStore.PopulateSha1MapStore(result) + # 写入 _sha1_map.txt(人类可读输出,程序内部不读取;机器分析使用 PopulateSha1MapStore 内存存储器) + StubMergerCollect.WriteIncludesSha1Map(mb, temp_dir, result, None, 0) + if set_count <= 0: + VLogger.warning("扫描结果无有效 SHA1,跳过 Phase1(项目可能无 includes 依赖)", "Phase1") + stdlib.free(sha1_set) + return 0 + # 模块 SHA1 映射已由 PopulateSha1MapStore 填充到 StubMerger 全局存储器, + # HandlesExprCall._lookup_module_sha1 直接查全局存储器,不再需要独立副本。 + + # 初始化 AST 表(只需一次) + ast._init_tables(mb) + + # FileEntry 结构体大小(Phase 1a 和 1b 共用) + entry_size: t.CSizeT = IncludesScanner.FileEntry.__sizeof__() + + # ============================================================ + # Phase 1a-pre: 扫描所有 includes 文件的 import 依赖 + # + # 只处理 Import/ImportFrom 语句,跳过 ClassDef/FunctionDef 等, + # 不调用 resolve_annotation_type,避免 list[...] 等不支持的语法触发 crash。 + # 生成 .deps.txt 供依赖图按需翻译使用。 + # ============================================================ + p1a_registered: int = 0 + p1a_skipped: int = 0 + p1a_failed: int = 0 + + for i in range(result.Count): + # 文件级 mark:import 依赖收集完(deps 写盘 + PopulateIncludesDeps + # 内部 stdlib 深拷贝)后立即回收本文件 AST——98 includes 全量 parse + # 的 AST 若驻留到 mark1 → 1GB 主池耗尽 OOM 根因之一 + scan_mark_a: t.CSizeT = mb.mark() + entry_addr_a: t.CUInt64T = t.CUInt64T(result.Entries) + i * entry_size + entry_a: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_a, t.CPtr)) + if entry_a is None: + p1a_failed += 1 + continue + + sha1_a: str = entry_a.Sha1 + if sha1_a is None: + p1a_failed += 1 + continue + + if StubMergerCollect._is_in_sha1_set(sha1_a, sha1_set, set_count) == 0: + p1a_skipped += 1 + continue + + # 读取文件内容 + file_path_a: str = entry_a.Path + f_a: fileio.File | t.CPtr = fileio.File(file_path_a, fileio.MODE.R) + if f_a.closed: + p1a_failed += 1 + continue + + src_buf_a: bytes = stdlib.malloc(Phase1.SRC_BUF_SIZE) + if src_buf_a is None: + f_a.close() + p1a_failed += 1 + continue + + bytes_read_a: LONG = f_a.read_all(src_buf_a, Phase1.SRC_BUF_SIZE) + f_a.close() + if bytes_read_a <= 0: + stdlib.free(src_buf_a) + p1a_failed += 1 + continue + if bytes_read_a < Phase1.SRC_BUF_SIZE: + src_buf_a[bytes_read_a] = 0 + else: + src_buf_a[Phase1.SRC_BUF_SIZE - 1] = 0 + + # 解析 AST + lx_a: ast.Lexer | t.CPtr = ast.new_lexer(mb) + if lx_a is None: + stdlib.free(src_buf_a) + p1a_failed += 1 + continue + ast._lexer_init(lx_a, src_buf_a, mb) + tokens_a: ast.Token | t.CPtr = ast.tokenize(lx_a) + tree_a: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens_a) + if tree_a is None: + stdlib.free(src_buf_a) + p1a_failed += 1 + continue + + # 创建 Translator,设置 _declare_only=2(只扫描 import,跳过 ClassDef) + tr_a: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator() + if tr_a is None: + stdlib.free(src_buf_a) + p1a_failed += 1 + continue + tr_a.ModuleSha1 = sha1_a + tr_a._declare_only = 2 + tr_a.CurrentPackage = GenApi.compute_package_from_relpath(mb, entry_a.RelPath) + GenApi.set_current_file_type(file_path_a) + GenApi.set_current_file_imports(file_path_a) + GenApi.set_current_module_sha1(sha1_a) + GenApi.clear_cdefine_constants() + GenApi.clear_ctypedefs() + GenApi.reset_visible_structs(mb, 0) + ret_a: int = tr_a.translate(tree_a) + if ret_a != 0: + p1a_failed += 1 + else: + p1a_registered += 1 + + # 容器模板按需纳入依赖:includes 使用 list/dict 泛型/构造/字面量 + # (如 base.vp 的 list[AST | CPtr])时追加 _list/_dict 到 + # _imported_modules → 进 deps → _BuildReachableSha1Set 的可达集合 + # 自动包含(Phase1 与 Phase2 都受益),否则泛型模板未注册 → + # "泛型类 'list' 未找到模板"。对齐 App 层 _inject_auto_container_visibility。 + cl_box: t.CPtr = stdlib.malloc(4) + cd_box: t.CPtr = stdlib.malloc(4) + if cl_box is not None and cd_box is not None: + cl_box[0] = 0 + cd_box[0] = 0 + Phase1Scan._ScanTreeForContainers(tree_a, cl_box, cd_box) + if cl_box[0] != 0: + if tr_a._imported_modules is None or \ + GenApi.is_module_imported(tr_a._imported_modules, "_list") == 0: + tr_a._imported_modules = GenApi.add_imported_module( + mb, tr_a._imported_modules, "_list") + if cd_box[0] != 0: + if tr_a._imported_modules is None or \ + GenApi.is_module_imported(tr_a._imported_modules, "_dict") == 0: + tr_a._imported_modules = GenApi.add_imported_module( + mb, tr_a._imported_modules, "_dict") + if cl_box is not None: + stdlib.free(cl_box) + if cd_box is not None: + stdlib.free(cd_box) + + # 生成 .deps.txt(记录依赖模块名,供依赖图按需翻译使用) + # 同时填充内存依赖存储器(PopulateIncludesDeps),供 _BuildReachableSha1Set + # 直接从内存读取,不依赖 .deps.txt 过程文件 + td_len_a: t.CSizeT = string.strlen(temp_dir) + deps_path_a: str = StubMergerCollect._sliced_path(temp_dir, td_len_a, sha1_a, "deps.txt") + if deps_path_a is not None: + df_a: fileio.File | t.CPtr = fileio.File(deps_path_a, fileio.MODE.W) + if not df_a.closed: + if tr_a._imported_modules is not None: + dl_a: t.CSizeT = string.strlen(tr_a._imported_modules) + df_a.write(tr_a._imported_modules, dl_a) + df_a.close() + stdlib.free(deps_path_a) + # 填充内存依赖存储器(供 _BuildReachableSha1Set 使用,不读 .deps.txt) + if tr_a._imported_modules is not None: + StubMergerStore.PopulateIncludesDeps(sha1_a, tr_a._imported_modules) + + # 释放 Translator 的 C malloc 资源 + if tr_a._global_names is not None: + stdlib.free(tr_a._global_names) + if tr_a._nonlocal_names is not None: + stdlib.free(tr_a._nonlocal_names) + + stdlib.free(src_buf_a) + # 回收本文件 AST/lexer/token(deps 已写盘、依赖存储器已深拷贝) + mb.reset_to(scan_mark_a) + + if p1a_failed > 0: + fb_p1apre: str = VLogger.fmt_buf() + if fb_p1apre is not None: + viperlib.snprintf(fb_p1apre, 1024, "Phase 1a-pre 有 %d 个文件扫描失败", p1a_failed) + VLogger.error(fb_p1apre, "Phase1") + return 1 + + # ============================================================ + # 依赖图按需翻译:构建可达 SHA1 集合 + # + # 从 Config.SourceDir 的源文件开始,解析 import 语句,递归收集 + # 可达的 includes 文件 SHA1。Phase 1b 只翻译可达集合中的文件, + # 避免翻译不需要的 includes(如 Test 不依赖 llvmlite,则不翻译)。 + # 如果 Config.SourceDir 不可用(仅运行 Phase1),回退到 sha1_set。 + # ============================================================ + reachable_set: str = None + reachable_count: int = 0 + use_reachable: int = 0 + if Config.SourceDir is not None: + reachable_set = stdlib.malloc(StubMerger.MAX_INCLUDES_SHA1 * 17) + if reachable_set is not None: + string.memset(reachable_set, 0, StubMerger.MAX_INCLUDES_SHA1 * 17) + reachable_count = StubMergerBuild._BuildReachableSha1Set(mb, Config.SourceDir, temp_dir, reachable_set) + if reachable_count < 0: + VLogger.error("可达集合构建失败,终止", "Phase1") + return 1 + if reachable_count > 0: + use_reachable = 1 + # 用可达集合重新生成 _sha1_map.txt(按图求索的最终产物) + # Phase B+ 只遍历这些条目,避免编译不需要的 includes(如 asm.vp) + StubMergerCollect.WriteIncludesSha1Map(mb, temp_dir, result, reachable_set, reachable_count) + # 重新加载 sha1_set,使后续 Phase 1a-pre/1a/1b 的过滤也使用可达集合 + string.memset(sha1_set, 0, StubMerger.MAX_INCLUDES_SHA1 * 17) + set_count = StubMergerCollect._load_includes_sha1_set(mb, temp_dir, sha1_set) + else: + VLogger.warning("可达集合为空,回退全量扫描", "Phase1") + stdlib.free(reachable_set) + reachable_set = None + + # ============================================================ + # Phase 1a: 注册可达 includes 文件的 struct/enum/union + # + # 解决字母序依赖问题:按字母顺序翻译时,后面的 struct 未注册 + # 前面就需要用。Phase 1a 先注册所有 struct/enum/union 到全局表, + # Phase 1b 全量翻译时 struct 已注册,走 existing 路径只翻译方法体。 + # 只处理可达文件,避免翻译不需要的 includes(如 Test 不依赖 ast 模块)。 + # + # 拓扑排序:预扫描所有文件收集类继承关系,按依赖顺序处理文件, + # 确保父类所在文件先于子类所在文件处理(如 base.vp 先于 astaux.vp)。 + # ============================================================ + p1a_reg: int = 0 + p1a_skp: int = 0 + p1a_fl: int = 0 + + # 预扫描类继承关系,构建拓扑顺序(用扁平字节数组,避免结构体 str 指针 NULL 崩溃) + class_names_buf: bytes = mb.alloc(Phase1.MAX_CLASSES * Phase1.CLASS_NAME_LEN) + parent_names_buf: bytes = mb.alloc(Phase1.MAX_CLASSES * Phase1.CLASS_NAME_LEN) + def_sha1s_buf: bytes = mb.alloc(Phase1.MAX_CLASSES * Phase1.SHA1_LEN) + topo_order: t.CPtr = mb.alloc(4 * Phase1.MAX_FILE_DEPS) + topo_count_box: t.CPtr = mb.alloc(4) + generic_file_indices: t.CPtr = mb.alloc(4 * Phase1.MAX_FILE_DEPS) + generic_file_count_box: t.CPtr = mb.alloc(4) + if generic_file_indices is not None: + string.memset(generic_file_indices, 0, 4 * Phase1.MAX_FILE_DEPS) + if generic_file_count_box is not None: + string.memset(generic_file_count_box, 0, 4) + topo_count: int = 0 + + if class_names_buf is not None and parent_names_buf is not None and def_sha1s_buf is not None and topo_order is not None and topo_count_box is not None: + string.memset(class_names_buf, 0, Phase1.MAX_CLASSES * Phase1.CLASS_NAME_LEN) + string.memset(parent_names_buf, 0, Phase1.MAX_CLASSES * Phase1.CLASS_NAME_LEN) + string.memset(def_sha1s_buf, 0, Phase1.MAX_CLASSES * Phase1.SHA1_LEN) + string.memset(topo_order, 0, 4 * Phase1.MAX_FILE_DEPS) + string.memset(topo_count_box, 0, 4) + if generic_file_indices is not None: + string.memset(generic_file_indices, 0, 4 * Phase1.MAX_FILE_DEPS) + if generic_file_count_box is not None: + string.memset(generic_file_count_box, 0, 4) + + class_count_scanned: int = Phase1Scan._ScanClassInheritance( + mb, result, reachable_set, reachable_count, + use_reachable, sha1_set, set_count, + class_names_buf, parent_names_buf, def_sha1s_buf, + generic_file_indices, generic_file_count_box) + + if class_count_scanned > 0: + td_len_ts_call: t.CSizeT = string.strlen(temp_dir) + ret_topo: int = Phase1Topo._TopoSortFiles( + mb, result, reachable_set, reachable_count, + use_reachable, sha1_set, set_count, + class_names_buf, parent_names_buf, def_sha1s_buf, class_count_scanned, + topo_order, topo_count_box, + temp_dir, td_len_ts_call) + if ret_topo == 0: + tc_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(topo_count_box, t.CPtr)) + if tc_ptr is not None: + topo_count = tc_ptr[0] + fb_topo: str = VLogger.fmt_buf() + if fb_topo is not None: + viperlib.snprintf(fb_topo, 1024, + "拓扑排序: %d 个类, %d 个文件按依赖顺序处理", + class_count_scanned, topo_count) + VLogger.info(fb_topo, "Phase1") + else: + VLogger.error("拓扑排序失败(类继承依赖无法解析),终止编译", "Phase1") + return 1 + else: + VLogger.warning("类继承预扫描无结果,回退到字母序", "Phase1") + topo_count = 0 + + # ============================================================ + # Phase 1a-pre-generic-all: mark1 前全量预注册 includes 泛型模板 + # + # 1a-pre-generic 只覆盖"可达"泛型文件;非可达泛型文件(如 FuncTest + # 场景的 linkedlist/llvmlite/_list)的模板要等 Phase2 Phase A-pre-inc + # (mark2 之后)才注册 → reset 回收表/节点 → _find_generic_template + # strcmp 悬空崩溃。此处对全部 includes 轻量预注册,使模板表与节点 + # 都落在 mark1 之前(mark2 > mark1,reset_to(mark2) 不回收)。 + # ============================================================ + Phase1Scan._PreRegisterAllGenericTemplates(mb, result) + + # ============================================================ + # Phase 1a: 注册 struct/enum/union(mark1 前,全量 includes) + # + # OOM 治理:1a 对全部 includes parse 完整 AST(主 pool 分配),若 + # 驻留到 mark1(循环后)会累积 98 文件 × 每文件 AST 树 → 1GB 主池 + # 耗尽(NewAstTest alloc 失败 0xBE 根因)。现改为: + # 1) StdlibAlloc=1:1a 注册的跨文件持久数据(StructTable 表、 + # Fields/Name/ModuleSha1、struct_ty 深拷贝、枚举/Renum/泛型 + # 模板等)全部落在 perm_pool(永不 reset),不占主 pool; + # 2) 每文件翻译完 reset_to(文件级 mark):仅回收该文件的 AST/ + # lexer/token/IR 等瞬时数据,注册数据不受影响。 + # mark1 仍在 1a 结束后打,1b 每文件 reset_to(mark1) 语义不变。 + # ============================================================ + GenApi.set_stdlib_alloc(1) + + # 遍历文件:优先使用拓扑顺序,回退到字母序 + iter_count: int = topo_count if topo_count > 0 else result.Count + for i in range(iter_count): + # 每文件级 mark:翻译完回收该文件 AST(注册数据在 perm_pool) + p1a_mark: t.CSizeT = mb.mark() + # 获取文件索引:拓扑顺序或字母序 + file_idx: int = i + if topo_count > 0: + od_addr: t.CUInt64T = t.CUInt64T(topo_order) + i * 4 + od_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(od_addr, t.CPtr)) + if od_ptr is not None: + file_idx = od_ptr[0] + + entry_addr_r: t.CUInt64T = t.CUInt64T(result.Entries) + file_idx * entry_size + entry_r: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_r, t.CPtr)) + if entry_r is None: + p1a_fl += 1 + continue + + sha1_r: str = entry_r.Sha1 + if sha1_r is None: + p1a_fl += 1 + continue + + # 按需翻译过滤(拓扑排序已过滤,但字母序回退需要检查) + if topo_count == 0: + if use_reachable != 0: + if StubMergerCollect._is_in_sha1_set(sha1_r, reachable_set, reachable_count) == 0: + p1a_skp += 1 + continue + else: + if StubMergerCollect._is_in_sha1_set(sha1_r, sha1_set, set_count) == 0: + p1a_skp += 1 + continue + + # 读取文件内容 + file_path_r: str = entry_r.Path + f_r: fileio.File | t.CPtr = fileio.File(file_path_r, fileio.MODE.R) + if f_r.closed: + p1a_fl += 1 + continue + + src_buf_r: bytes = stdlib.malloc(Phase1.SRC_BUF_SIZE) + if src_buf_r is None: + f_r.close() + p1a_fl += 1 + continue + + bytes_read_r: LONG = f_r.read_all(src_buf_r, Phase1.SRC_BUF_SIZE) + f_r.close() + if bytes_read_r <= 0: + stdlib.free(src_buf_r) + p1a_fl += 1 + continue + if bytes_read_r < Phase1.SRC_BUF_SIZE: + src_buf_r[bytes_read_r] = 0 + else: + src_buf_r[Phase1.SRC_BUF_SIZE - 1] = 0 + + # 解析 AST + lx_r: ast.Lexer | t.CPtr = ast.new_lexer(mb) + if lx_r is None: + stdlib.free(src_buf_r) + p1a_fl += 1 + continue + ast._lexer_init(lx_r, src_buf_r, mb) + tokens_r: ast.Token | t.CPtr = ast.tokenize(lx_r) + tree_r: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens_r) + if tree_r is None: + stdlib.free(src_buf_r) + p1a_fl += 1 + continue + + # 创建 Translator,设置 _declare_only=1(注册 struct/enum/union) + tr_r: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator() + if tr_r is None: + stdlib.free(src_buf_r) + p1a_fl += 1 + continue + tr_r.ModuleSha1 = sha1_r + tr_r._declare_only = 1 + tr_r.CurrentPackage = GenApi.compute_package_from_relpath(mb, entry_r.RelPath) + GenApi.set_current_file_type(file_path_r) + GenApi.set_current_file_imports(file_path_r) + GenApi.set_current_module_sha1(sha1_r) + GenApi.clear_cdefine_constants() + GenApi.clear_ctypedefs() + GenApi.reset_visible_structs(mb, 0) + ret_r: int = tr_r.translate(tree_r) + if ret_r != 0: + p1a_fl += 1 + else: + p1a_reg += 1 + + # 释放 Translator 的 C malloc 资源 + if tr_r._global_names is not None: + stdlib.free(tr_r._global_names) + if tr_r._nonlocal_names is not None: + stdlib.free(tr_r._nonlocal_names) + stdlib.free(src_buf_r) + + # 回收本文件 AST/lexer/token/IR 等瞬时数据(注册数据已在 perm_pool, + # reset 不影响;IncludesScanner result 等在 p1a_mark 前分配同样保留) + mb.reset_to(p1a_mark) + + if p1a_fl > 0: + fb_p1ar: str = VLogger.fmt_buf() + if fb_p1ar is not None: + viperlib.snprintf(fb_p1ar, 1024, "Phase 1a 有 %d 个文件 struct 注册失败", p1a_fl) + VLogger.error(fb_p1ar, "Phase1") + return 1 + + # 释放拓扑排序资源(topo_order/topo_count_box 保留到 Phase 1b 结束, + # 1b 按拓扑序翻译需要它们;class/def 数组 1b 不再使用) + if class_names_buf is not None: + mb.free(class_names_buf) + if parent_names_buf is not None: + mb.free(parent_names_buf) + if def_sha1s_buf is not None: + mb.free(def_sha1s_buf) + if generic_file_indices is not None: + mb.free(generic_file_indices) + if generic_file_count_box is not None: + mb.free(generic_file_count_box) + + # ============================================================ + # Phase 1b: 全量翻译(struct 已注册,走 existing 路径翻译方法体) + # ============================================================ + # OOM 回收:1a-pre/泛型预注册/1a 全部结束后打 mark1, + # 所有跨文件持久表(_struct_table/_enum_table/_generic_class_nodes/ + # _renum_*/关键字表等)都落在 mark1 之前。 + # 1b 每文件翻译完后 reset_to(mark1) 回收该文件的 AST/IR/Handler/dump 临时, + # 避免 90 文件累积导致 1GB 池 OOM。 + mark1: t.CSizeT = mb.mark() + + # 1b 阶段新注册的 struct/enum 条目改 stdlib 分配(跨文件永久存活,不被 reset 回收) + GenApi.set_stdlib_alloc(1) + + # ============================================================ + # Phase 1b-pre: 预生成所有待翻译文件的 .vpi stub + # + # 依赖模块的 .vpi 必须在翻译前可用:1b 主循环按扫描顺序翻译(非拓扑), + # 若 argparse 先于 hashtable 翻译,hashtable.vpi 尚未生成, + # LoadDepVpiIntoModule 读不到 → declare 未注入 → 跨模块调用 + # 返回类型推断错误(如 HashTable.__getitem__ 被推断为 Ptr(HashTable) + # 而 define 返回 i8*)→ 运行时返回值截断崩溃。 + # ============================================================ + p1bpre_failed: int = 0 + dir_len_pv: t.CSizeT = string.strlen(temp_dir) + for i_pv in range(result.Count): + entry_addr_pv: t.CUInt64T = t.CUInt64T(result.Entries) + i_pv * entry_size + entry_pv: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_pv, t.CPtr)) + if entry_pv is None or entry_pv.Sha1 is None: + p1bpre_failed += 1 + continue + sha1_pv: str = entry_pv.Sha1 + in_set_pv: int = 0 + if use_reachable != 0: + in_set_pv = StubMergerCollect._is_in_sha1_set(sha1_pv, reachable_set, reachable_count) + else: + in_set_pv = StubMergerCollect._is_in_sha1_set(sha1_pv, sha1_set, set_count) + if in_set_pv == 0: + continue + # vpi 已存在则跳过 + vpi_path_pv: str = StubMergerCollect._sliced_path(temp_dir, dir_len_pv, sha1_pv, "vpi") + if vpi_path_pv is None: + p1bpre_failed += 1 + continue + vf_pv: fileio.File | t.CPtr = fileio.File(vpi_path_pv, fileio.MODE.R) + if not vf_pv.closed: + vf_pv.close() + stdlib.free(vpi_path_pv) + continue + stdlib.free(vpi_path_pv) + # 读取文件、解析 AST、生成 vpi + file_path_pv: str = entry_pv.Path + f_pv: fileio.File | t.CPtr = fileio.File(file_path_pv, fileio.MODE.R) + if f_pv.closed: + p1bpre_failed += 1 + continue + src_buf_pv: bytes = stdlib.malloc(Phase1.SRC_BUF_SIZE) + if src_buf_pv is None: + f_pv.close() + p1bpre_failed += 1 + continue + bytes_read_pv: LONG = f_pv.read_all(src_buf_pv, Phase1.SRC_BUF_SIZE) + f_pv.close() + if bytes_read_pv <= 0: + stdlib.free(src_buf_pv) + p1bpre_failed += 1 + continue + if bytes_read_pv < Phase1.SRC_BUF_SIZE: + src_buf_pv[bytes_read_pv] = 0 + else: + src_buf_pv[Phase1.SRC_BUF_SIZE - 1] = 0 + lx_pv: ast.Lexer | t.CPtr = ast.new_lexer(mb) + if lx_pv is None: + stdlib.free(src_buf_pv) + p1bpre_failed += 1 + continue + ast._lexer_init(lx_pv, src_buf_pv, mb) + tokens_pv: ast.Token | t.CPtr = ast.tokenize(lx_pv) + tree_pv: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens_pv) + if tree_pv is None: + stdlib.free(src_buf_pv) + p1bpre_failed += 1 + continue + pyi_buf_pv: bytes = stdlib.malloc(Phase1.PYI_BUF_SIZE) + if pyi_buf_pv is not None: + pyi_pos_pv: t.CSizeT = StubConverter._GeneratePyiFromAst(mb, tree_pv, entry_pv.RelPath, pyi_buf_pv, Phase1.PYI_BUF_SIZE) + if pyi_pos_pv > 0: + pyi_path_pv: str = StubMergerCollect._sliced_path(temp_dir, dir_len_pv, sha1_pv, "vpi") + if pyi_path_pv is not None: + pf_pv: fileio.File | t.CPtr = fileio.File(pyi_path_pv, fileio.MODE.W) + if not pf_pv.closed: + pf_pv.write(pyi_buf_pv, pyi_pos_pv) + pf_pv.close() + stdlib.free(pyi_path_pv) + stdlib.free(pyi_buf_pv) + else: + p1bpre_failed += 1 + stdlib.free(src_buf_pv) + # 回收本文件 AST(vpi 已写盘,AST 不再需要;mark1 后无其他持久数据) + mb.reset_to(mark1) + + if p1bpre_failed > 0: + fb_p1bpre: str = VLogger.fmt_buf() + if fb_p1bpre is not None: + viperlib.snprintf(fb_p1bpre, 1024, "Phase 1b-pre 有 %d 个文件 vpi 预生成失败", p1bpre_failed) + VLogger.error(fb_p1bpre, "Phase1") + return 1 + + # 遍历每个文件(拓扑序优先:父类所在文件先翻译,确保跨模块 vtable + # 生成时依赖模块的函数 TypeStr 已注册;topo_count==0 回退扫描顺序) + translated: int = 0 + skipped: int = 0 + failed: int = 0 + + loop_n_b: int = result.Count + if topo_count > 0: + loop_n_b = topo_count + for i in range(loop_n_b): + # 获取 entry(拓扑序:file_idx 从 topo_order 取,否则用扫描索引) + file_idx_b: int = i + if topo_count > 0: + od_addr_b: t.CUInt64T = t.CUInt64T(topo_order) + t.CSizeT(i) * 4 + od_ptr_b: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(od_addr_b, t.CPtr)) + if od_ptr_b is not None: + file_idx_b = od_ptr_b[0] + entry_addr: t.CUInt64T = t.CUInt64T(result.Entries) + t.CSizeT(file_idx_b) * entry_size + entry: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + if entry is None: + failed += 1 + continue + + sha1: str = entry.Sha1 + if sha1 is None: + failed += 1 + continue + + # 检查 SHA1 是否在翻译集合中(拓扑序已过滤可达;仅回退扫描顺序时检查) + in_set: int = 1 + if topo_count == 0: + in_set = 0 + if use_reachable != 0: + in_set = StubMergerCollect._is_in_sha1_set(sha1, reachable_set, reachable_count) + else: + in_set = StubMergerCollect._is_in_sha1_set(sha1, sha1_set, set_count) + if in_set == 0: + skipped += 1 + continue + + # 构造 stub 路径: {temp_dir}/{sha1}.stub.ll + dir_len: t.CSizeT = string.strlen(temp_dir) + sha1_len: t.CSizeT = string.strlen(sha1) + stub_path: str = StubMergerCollect._sliced_path(temp_dir, dir_len, sha1, "stub.ll") + if stub_path is None: + failed += 1 + continue + + # 检查 stub 是否已存在(按需翻译:跳过已存在的) + sf: fileio.File | t.CPtr = fileio.File(stub_path, fileio.MODE.R) + if not sf.closed: + sf.close() + # 检查 text.ll 是否也存在(虚表扫描需要 text.ll) + text_path: str = StubMergerCollect._sliced_path(temp_dir, dir_len, sha1, "text.ll") + if text_path is not None: + tf: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R) + if not tf.closed: + tf.close() + stdlib.free(text_path) + stdlib.free(stub_path) + continue + stdlib.free(text_path) + # text.ll 不存在,需要重新翻译 + rp: str = entry.RelPath + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "text.ll 不存在,重新翻译: %s(sha1=%s)", rp, sha1) + VLogger.info(fb, "Phase1") + else: + # stub 不存在,需要翻译 + rp: str = entry.RelPath + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "翻译: %s(sha1=%s)", rp, sha1) + VLogger.info(fb, "Phase1") + + stdlib.free(stub_path) + + # 读取文件内容 + file_path: str = entry.Path + f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R) + if f is None: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "无法打开(None): %s", file_path) + VLogger.error(fb, "Phase1") + failed += 1 + continue + if f.closed: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "无法打开: %s", file_path) + VLogger.error(fb, "Phase1") + failed += 1 + continue + + src_buf: bytes = stdlib.malloc(Phase1.SRC_BUF_SIZE) + if src_buf is None: + f.close() + failed += 1 + continue + + bytes_read: LONG = f.read_all(src_buf, Phase1.SRC_BUF_SIZE) + f.close() + if bytes_read <= 0: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "读取失败: %s", file_path) + VLogger.error(fb, "Phase1") + stdlib.free(src_buf) + failed += 1 + continue + if bytes_read < Phase1.SRC_BUF_SIZE: + src_buf[bytes_read] = 0 + else: + src_buf[Phase1.SRC_BUF_SIZE - 1] = 0 + + # 解析 AST + lx: ast.Lexer | t.CPtr = ast.new_lexer(mb) + if lx is None: + stdlib.free(src_buf) + failed += 1 + continue + ast._lexer_init(lx, src_buf, mb) + tokens: ast.Token | t.CPtr = ast.tokenize(lx) + tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens) + if tree is None: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "AST 解析失败: %s", file_path) + VLogger.error(fb, "Phase1") + stdlib.free(src_buf) + failed += 1 + continue + + # 文本扫描注册 CTypedef(stdint.vp 崩溃根因修复):AST 字符串字段 + # (attr/id)token 零拷贝指向 src_buf,跨阶段内容不稳定(悬空), + # ScanCTypedefDeclarations 读 attr 会 0xC0000005。改用源码文本逐行 + # 匹配 "NAME: t.CTypedef = TYPE",在 src_buf 有效期内注册。 + GenApi.RegisterCTypedefFromSource(mb, src_buf) + + # 生成 .vpi 存根文件(直接遍历 AST,不依赖 PythonToStubConverter) + pyi_buf: bytes = stdlib.malloc(Phase1.PYI_BUF_SIZE) + if pyi_buf is not None: + pyi_pos: t.CSizeT = StubConverter._GeneratePyiFromAst(mb, tree, entry.RelPath, pyi_buf, Phase1.PYI_BUF_SIZE) + if pyi_pos > 0: + pyi_path: str = StubMergerCollect._sliced_path(temp_dir, dir_len, sha1, "vpi") + if pyi_path is not None: + pf: fileio.File | t.CPtr = fileio.File(pyi_path, fileio.MODE.W) + if not pf.closed: + pf.write(pyi_buf, pyi_pos) + pf.close() + stdlib.free(pyi_path) + stdlib.free(pyi_buf) + + # 翻译 AST → LLVM IR + tr: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator() + if tr is None: + stdlib.free(src_buf) + failed += 1 + continue + tr.ModuleSha1 = sha1 + tr.CurrentPackage = GenApi.compute_package_from_relpath(mb, entry.RelPath) + GenApi.set_current_file_type(file_path) + GenApi.set_current_file_imports(file_path) + GenApi.set_current_module_sha1(sha1) + GenApi.clear_cdefine_constants() + GenApi.clear_ctypedefs() + GenApi.reset_visible_structs(mb, 0) + + # 翻译前哨兵:AST 解析(lexer/tokenize/parse_tokens)同样在 pool 分配, + # 若解析器越界写破坏了存活块 header,此处立即定位到当前文件 + # (崩溃点漂移排查:把"翻译过程中随机崩"变成确定性定位) + pre_rc: t.CInt = mb.check_alive_blocks(mark1) + if pre_rc != 0: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, + "内存损坏(翻译前存活块, rc=%d): %s", pre_rc, file_path) + VLogger.error(fb, "Phase1") + stdlib.exit(1) + + ret: int = tr.translate(tree) + # 诊断:translate 正常返回(若挂起在 translate 内部,此行不会打印, + # 用于区分"translate 内部挂起"与"后续 dump 挂起") + if ret == 0: + fb_done: str = VLogger.fmt_buf() + if fb_done is not None: + viperlib.snprintf(fb_done, 1024, "翻译完成(translate返回): %s", file_path) + VLogger.info(fb_done, "Phase1") + if ret != 0: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "翻译失败: %s", file_path) + VLogger.error(fb, "Phase1") + stdlib.free(src_buf) + if tr._global_names is not None: + stdlib.free(tr._global_names) + if tr._nonlocal_names is not None: + stdlib.free(tr._nonlocal_names) + failed += 1 + continue + + # 诊断(builtins.vp dump 卡死根因排查):pre_rc 哨兵在 translate 前, + # 覆盖不到 translate 期间的 AST/IR 写穿。dump 前立即检查存活块 + # header/canary(rc=6 块尾 canary 损坏=越界写穿数据区),把"dump + # 时链表成环卡死"变成"定位到 translate 期间写穿发生的文件"。 + post_rc: t.CInt = mb.check_alive_blocks(mark1) + if post_rc != 0: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, + "内存损坏(translate后存活块, rc=%d): %s", post_rc, file_path) + VLogger.error(fb, "Phase1") + stdlib.exit(1) + + # dump stub IR(declarations only) + PHASE1_IR_SIZE: t.CSizeT = 1048576 + stub_buf: bytes = stdlib.malloc(PHASE1_IR_SIZE) + if stub_buf is None: + stdlib.free(src_buf) + if tr._global_names is not None: + stdlib.free(tr._global_names) + if tr._nonlocal_names is not None: + stdlib.free(tr._nonlocal_names) + failed += 1 + continue + tr.dump_ir(stub_buf, PHASE1_IR_SIZE, llvmlite.OUTPUT_STUB) + stub_len: t.CSizeT = string.strlen(stub_buf) + + # save stub.ll + dir_len_p1: t.CSizeT = string.strlen(temp_dir) + stub_path_p1: str = StubMergerCollect._sliced_path(temp_dir, dir_len_p1, sha1, "stub.ll") + if stub_path_p1 is not None: + sf_p1: fileio.File | t.CPtr = fileio.File(stub_path_p1, fileio.MODE.W) + if not sf_p1.closed: + sf_p1.write(stub_buf, stub_len) + sf_p1.close() + stdlib.free(stub_path_p1) + stdlib.free(stub_buf) + + # dump text IR(definitions only) + text_buf: bytes = stdlib.malloc(PHASE1_IR_SIZE) + if text_buf is None: + stdlib.free(src_buf) + if tr._global_names is not None: + stdlib.free(tr._global_names) + if tr._nonlocal_names is not None: + stdlib.free(tr._nonlocal_names) + failed += 1 + continue + tr.dump_ir(text_buf, PHASE1_IR_SIZE, llvmlite.OUTPUT_TEXT) + text_len: t.CSizeT = string.strlen(text_buf) + + # save text.ll + text_path_p1: str = StubMergerCollect._sliced_path(temp_dir, dir_len_p1, sha1, "text.ll") + if text_path_p1 is not None: + tf_p1: fileio.File | t.CPtr = fileio.File(text_path_p1, fileio.MODE.W) + if not tf_p1.closed: + tf_p1.write(text_buf, text_len) + tf_p1.close() + stdlib.free(text_path_p1) + stdlib.free(text_buf) + + # save dependencies(_imported_modules) for Phase B + deps_path_p1: str = StubMergerCollect._sliced_path(temp_dir, dir_len_p1, sha1, "deps.txt") + if deps_path_p1 is not None: + df_p1: fileio.File | t.CPtr = fileio.File(deps_path_p1, fileio.MODE.W) + if not df_p1.closed: + if tr._imported_modules is not None: + dl: t.CSizeT = string.strlen(tr._imported_modules) + df_p1.write(tr._imported_modules, dl) + df_p1.close() + stdlib.free(deps_path_p1) + + # 释放 Translator 的 C malloc 资源 + if tr._global_names is not None: + stdlib.free(tr._global_names) + if tr._nonlocal_names is not None: + stdlib.free(tr._nonlocal_names) + + # 所有 dump_ir 完成,src_buf 不再需要 + stdlib.free(src_buf) + + translated += 1 + + # OOM 回收:回收本文件翻译产生的瞬时数据(AST/tokens/lexer/IR/Handler/dump 临时) + # 持久表(struct/enum/REnum/spec 缓存/全局函数名等)已迁出 reset 区间(stdlib), + # reset_to(mark1) 只回收 mark1 之后分配、未被单独 free 的块。 + # + # 内存哨兵(崩溃点漂移排查):reset 前检查存活块 header(抓越界写), + # reset 后检查 free list 完整性(抓链表损坏)。任一损坏立即终止, + # 把"随机崩溃漂移"变成"确定性定位到当前文件"。 + # rc 语义(check_alive_blocks):1=块地址低于 usable,2=高于 usable+size, + # 3=order 为负,4=order 超 max_order,5=块未对齐到 order 大小, + # 6=块尾 canary 损坏(越界写穿数据区——事发地定位) + # rc 语义(self_check):1/2=越界,3=对齐错,4=free list 成环/超步数 + chk_rc: t.CInt = mb.check_alive_blocks(mark1) + if chk_rc != 0: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, + "内存损坏(存活块 header, rc=%d): %s", chk_rc, file_path) + VLogger.error(fb, "Phase1") + stdlib.exit(1) + # A/B 实验结论(已确认):禁用 reset_to 后 stdarg 仍崩 → 越界写是根因, + # 与回收/UAF 无关。恢复 reset_to,改用块尾 canary(check_alive_blocks 校验) + # 定位越界写事发地到具体文件。 + mb.reset_to(mark1) + sc_rc: t.CInt = mb.self_check() + if sc_rc != 0: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, + "内存损坏(free list, rc=%d): %s", sc_rc, file_path) + VLogger.error(fb, "Phase1") + stdlib.exit(1) + + # 释放 Phase 1b 使用的拓扑排序资源 + if topo_order is not None: + mb.free(topo_order) + if topo_count_box is not None: + mb.free(topo_count_box) + + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "完成: 翻译=%d 跳过=%d 失败=%d", translated, skipped, failed) + VLogger.info(fb, "Phase1") + + if failed > 0: + fb_fail: str = VLogger.fmt_buf() + if fb_fail is not None: + viperlib.snprintf(fb_fail, 1024, "Phase1 有 %d 个文件翻译失败", failed) + VLogger.error(fb_fail, "Phase1") + return 1 + + # 释放可达 SHA1 集合(如果分配了) + if reachable_set is not None: + stdlib.free(reachable_set) + + return 0 diff --git a/App/lib/core/Phase1Scan.vp b/App/lib/core/Phase1Scan.vp index 7e728a9..fdcff1d 100644 --- a/App/lib/core/Phase1Scan.vp +++ b/App/lib/core/Phase1Scan.vp @@ -1,505 +1,501 @@ -import t, c -from stdint import * -import string -import stdlib -import memhub -import viperlib -import w32.fileio as fileio -import w32.win32file -import w32.win32base -import ast -import llvmlite -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HandlesTranslator -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.IncludesScanner as IncludesScanner -import lib.core.StubMerger as StubMerger -import lib.core.Gen.Generator as GenGenerator -import lib.core.CompilerFactory as CompilerFactory -import lib.core.BuildPipeline as BuildPipeline -import lib.Projectrans.Config as Config -import lib.StubGen.Converter as StubConverter -import lib.core.StubMergerBuild as StubMergerBuild -import lib.core.StubMergerCollect as StubMergerCollect -import lib.core.StubMergerIR as StubMergerIR -import lib.core.StubMergerStore as StubMergerStore -import lib.core.Handles.ExprCallCtor as ExprCallCtor - - -import lib.core.Phase1Topo as Phase1Topo -import lib.core.Phase1Main as Phase1Main -import lib.core.Phase1 as Phase1 - -# ============================================================ -# Phase1Scan - Phase1 拆分(阶段 E):Phase1Scan -# -# 直接移动模式:函数迁至此模块,原 Phase1.vp 仅保留常量/_mbuddy; -# 调用方经本模块前缀访问。全局符号经 Phase1._xxx 跨模块访问。 -# ============================================================ - -# 拓扑排序使用扁平字节数组存储类信息和文件依赖, -# 避免结构体中的 str 指针字段在 mb.alloc 零填充时为 NULL 导致崩溃。 -# 类名/父类名存储在 class_names_buf/parent_names_buf(每个 Phase1.CLASS_NAME_LEN 字节), -# 定义 SHA1 存储在 def_sha1s_buf(每个 Phase1.SHA1_LEN 字节)。 - - -# ============================================================ -# _ScanClassInheritance - 预扫描 includes 文件,收集类继承关系 -# -# 遍历所有可达 includes 文件,解析 AST 收集 ClassDef 的类名和父类名。 -# 结果存入扁平字节数组,返回收集到的类数量。 -# -# Args: -# mb: 内存池 -# result: IncludesScanner 扫描结果 -# reachable_set: 可达 SHA1 集合 -# reachable_count: 可达 SHA1 数量 -# use_reachable: 是否使用可达集合过滤 -# sha1_set: SHA1 集合(use_reachable=0 时使用) -# set_count: SHA1 集合数量 -# class_names_buf: 类名扁平数组(每个 Phase1.CLASS_NAME_LEN 字节,连续内存) -# parent_names_buf: 父类名扁平数组(每个 Phase1.CLASS_NAME_LEN 字节,无父类填 '\0') -# def_sha1s_buf: 定义 SHA1 扁平数组(每个 Phase1.SHA1_LEN 字节) -# -# Returns: -# 收集到的类数量,-1 失败 -# ============================================================ -def _ScanClassInheritance(mb: memhub.MemBuddy | t.CPtr, - result: IncludesScanner.ScanResult | t.CPtr, - reachable_set: str, reachable_count: int, - use_reachable: int, - sha1_set: str, set_count: int, - class_names_buf: bytes, - parent_names_buf: bytes, - def_sha1s_buf: bytes, - generic_file_indices: t.CPtr, - generic_file_count_box: t.CPtr) -> int: - """预扫描 includes 文件,收集类继承关系""" - if result is None or class_names_buf is None or parent_names_buf is None or def_sha1s_buf is None: - return -1 - - entry_size: t.CSizeT = IncludesScanner.FileEntry.__sizeof__() - class_count: int = 0 - - for i in range(result.Count): - # 文件级 mark:收集完类继承信息后立即回收本文件 AST(可达 includes - # 全量 parse 的 AST 若驻留到 mark1 → 1GB 主池耗尽 OOM 根因; - # class_names_buf/parent_names_buf/def_sha1s_buf 在调用前分配, - # 位于本 mark 之前,reset 不影响;generic_file_indices 同理) - scan_mark: t.CSizeT = mb.mark() - entry_addr: t.CUInt64T = t.CUInt64T(result.Entries) + i * entry_size - entry: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - if entry is None or entry.Sha1 is None: - continue - - sha1_e: str = entry.Sha1 - file_has_generic: int = 0 - - # 按需翻译过滤 - in_set: int = 0 - if use_reachable != 0: - in_set = StubMergerCollect._is_in_sha1_set(sha1_e, reachable_set, reachable_count) - else: - in_set = StubMergerCollect._is_in_sha1_set(sha1_e, sha1_set, set_count) - if in_set == 0: - continue - - # 读取文件 - file_path: str = entry.Path - f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R) - if f.closed: - continue - - src_buf: bytes = stdlib.malloc(Phase1.SRC_BUF_SIZE) - if src_buf is None: - f.close() - continue - - bytes_read: LONG = f.read_all(src_buf, Phase1.SRC_BUF_SIZE) - f.close() - if bytes_read <= 0: - stdlib.free(src_buf) - continue - if bytes_read < Phase1.SRC_BUF_SIZE: - src_buf[bytes_read] = 0 - else: - src_buf[Phase1.SRC_BUF_SIZE - 1] = 0 - - # 解析 AST - lx: ast.Lexer | t.CPtr = ast.new_lexer(mb) - if lx is None: - stdlib.free(src_buf) - continue - ast._lexer_init(lx, src_buf, mb) - tokens: ast.Token | t.CPtr = ast.tokenize(lx) - tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens) - if tree is None: - stdlib.free(src_buf) - continue - - # 遍历 AST 顶层节点,收集 ClassDef - ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children - if ch is not None: - cn: t.CSizeT = len(ch) - for ci in range(cn): - child: ast.AST | t.CPtr = ch.get(ci) - if child is None: - continue - kd: int = child.kind() - if kd != ast.ASTKind.ClassDef: - continue - - cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child) - if cd is None or cd.name is None: - continue - - # 检测泛型类(有 type_params),记录文件索引以供 Phase 1a 预注册 - if file_has_generic == 0: - tp_scan: list[str] | t.CPtr = cd.type_params - if tp_scan is not None: - file_has_generic = 1 - if generic_file_count_box is not None: - gfc_ptr_scan: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(generic_file_count_box, t.CPtr)) - if gfc_ptr_scan is not None: - gfc_scan: int = gfc_ptr_scan[0] - if gfc_scan < Phase1.MAX_FILE_DEPS and generic_file_indices is not None: - gi_addr_scan: t.CUInt64T = t.CUInt64T(generic_file_indices) + gfc_scan * 4 - gi_ptr_scan: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(gi_addr_scan, t.CPtr)) - if gi_ptr_scan is not None: - gi_ptr_scan[0] = i - gfc_ptr_scan[0] = gfc_scan + 1 - - if class_count >= Phase1.MAX_CLASSES: - break - - # 填充扁平数组:类名(偏移 = class_count * Phase1.CLASS_NAME_LEN) - name_dst: str = class_names_buf + class_count * Phase1.CLASS_NAME_LEN - nm_len: t.CSizeT = string.strlen(cd.name) - if nm_len >= Phase1.CLASS_NAME_LEN: - string.strncpy(name_dst, cd.name, Phase1.CLASS_NAME_LEN - 1) - name_dst[Phase1.CLASS_NAME_LEN - 1] = '\0' - else: - string.strcpy(name_dst, cd.name) - - # 填充扁平数组:父类名(无父类填 '\0') - parent_dst: str = parent_names_buf + class_count * Phase1.CLASS_NAME_LEN - parent_dst[0] = '\0' - parent_nm: str = HandlesClassDef._get_parent_class(cd, None) - # parent_nm 是 AST 节点内部指针,不需要释放 - if parent_nm is not None: - pnm_len: t.CSizeT = string.strlen(parent_nm) - if pnm_len >= Phase1.CLASS_NAME_LEN: - string.strncpy(parent_dst, parent_nm, Phase1.CLASS_NAME_LEN - 1) - parent_dst[Phase1.CLASS_NAME_LEN - 1] = '\0' - else: - string.strcpy(parent_dst, parent_nm) - - # 填充扁平数组:定义 SHA1(偏移 = class_count * Phase1.SHA1_LEN) - sha1_dst: str = def_sha1s_buf + class_count * Phase1.SHA1_LEN - string.strcpy(sha1_dst, sha1_e) - - class_count += 1 - - stdlib.free(src_buf) - # 回收本文件 AST/lexer/token(类名/父类/SHA1 已拷入扁平数组) - mb.reset_to(scan_mark) - - return class_count -# ============================================================ -# _BufHasGenericClassMarker - 文本扫描检测文件是否含泛型类标记 -# -# 泛型类(PEP 695)语法: class Name[T]:(类名后紧跟 '[')。 -# 逐字节扫描找词边界 'class' 关键字,其后标识符后非空白是 '[' → 命中。 -# 用于 _PreRegisterAllGenericTemplates 预注册前筛选,避免 parse 全部 -# 98 个 includes 导致 AST 驻留 mark1 前把 pool 推到 OOM -# (NewAstTest [52/68] pool 耗尽根因:1a-pre 已 parse 全部驻留, -# 预注册再全量 parse 等于翻倍)。 -# 误报(字符串/注释里的 "class X[")无害(多 parse 一个文件); -# 漏报有害(泛型模板未预注册 → 悬空复发),模式保守匹配行内单行形式 -# (TPV 源码泛型类均为单行 `class X[T]:`,grep 确认)。 -# ============================================================ -def _BufHasGenericClassMarker(buf: bytes, blen: t.CSizeT) -> int: - """文本扫描:buf 中是否有 'class 标识符[' 泛型类标记,返回 1/0""" - if buf is None or blen <= 6: - return 0 - pos: t.CSizeT = 0 - while pos + 5 < blen: - if buf[pos] == 'c' and buf[pos + 1] == 'l' and buf[pos + 2] == 'a' \ - and buf[pos + 3] == 's' and buf[pos + 4] == 's': - # class 前是词边界(行首或非标识符字符) - prev_ok: int = 1 - if pos > 0: - pc: t.CChar = buf[pos - 1] - if(pc >= 'a' and pc <= 'z') or(pc >= 'A' and pc <= 'Z') \ - or(pc >= '0' and pc <= '9') or pc == '_': - prev_ok = 0 - if prev_ok != 0: - p: t.CSizeT = pos + 5 - # 跳过空白 - while p < blen and(buf[p] == ' ' or buf[p] == '\t'): - p += 1 - # 读类名标识符 - if p < blen and((buf[p] >= 'a' and buf[p] <= 'z') - or(buf[p] >= 'A' and buf[p] <= 'Z') or buf[p] == '_'): - while p < blen and((buf[p] >= 'a' and buf[p] <= 'z') - or(buf[p] >= 'A' and buf[p] <= 'Z') - or(buf[p] >= '0' and buf[p] <= '9') - or buf[p] == '_'): - p += 1 - # 类名后非空白是 '[' → 泛型类 - while p < blen and(buf[p] == ' ' or buf[p] == '\t'): - p += 1 - if p < blen and buf[p] == '[': - return 1 - pos += 1 - else: - pos += 1 - return 0 -# ============================================================ -# _PreRegisterAllGenericTemplates - 预注册 includes 泛型类模板(mark1 前) -# -# 背景:泛型模板表(GenericClassNames/GenericClassNodes/GenericClassSha1s/ -# GenericClassFiles + 模板节点)是懒分配的跨文件持久表,首次注册必须落在 -# mark1 之前才能跨 Phase1 1b(reset_to(mark1))与 Phase2(reset_to(mark2), -# mark2 > mark1)存活。现有 1a-pre-generic 只注册"可达"泛型文件;FuncTest -# 这类可达集合无泛型的项目,模板要等 Phase2 Phase A-pre-inc(mark2 之后) -# 翻译全部 includes 时才注册 → reset 回收表与节点 → _find_generic_template -# 遍历悬空内存 strcmp 崩溃。 -# 本函数先文本扫描(_BufHasGenericClassMarker,不 parse、不驻留)筛选出 -# 含泛型类的文件(全量 parse 会把 98 个 includes 的 AST 驻留 mark1 前 → -# NewAstTest [52/68] pool 耗尽 OOM),仅对命中的文件用**永久池(perm_pool)** -# 解析 → 模板节点与表直接进 perm_pool,跨 mark 永久存活、不占主 pool。 -# 重复注册由 _register_generic_template 内部查重跳过。 -# ============================================================ -def _PreRegisterAllGenericTemplates(mb: memhub.MemBuddy | t.CPtr, - result: IncludesScanner.ScanResult | t.CPtr) -> int: - """预注册全部 includes 文件的泛型类模板,返回处理到的泛型类数量""" - if result is None or mb is None: - return 0 - perm: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool() - if perm is None: - return 0 - p1e_size: t.CSizeT = IncludesScanner.FileEntry.__sizeof__() - handled_count: int = 0 - for i in range(result.Count): - entry_addr_pg: t.CUInt64T = t.CUInt64T(result.Entries) + i * p1e_size - entry_pg: IncludesScanner.FileEntry | t.CPtr = ( - IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_pg, t.CPtr)) - if entry_pg is None or entry_pg.Sha1 is None: - continue - # 读取文件 - file_path_pg: str = entry_pg.Path - f_pg: fileio.File | t.CPtr = fileio.File(file_path_pg, fileio.MODE.R) - if f_pg.closed: - continue - src_buf_pg: bytes = stdlib.malloc(Phase1.SRC_BUF_SIZE) - if src_buf_pg is None: - f_pg.close() - continue - bytes_read_pg: LONG = f_pg.read_all(src_buf_pg, Phase1.SRC_BUF_SIZE) - f_pg.close() - if bytes_read_pg <= 0: - stdlib.free(src_buf_pg) - continue - if bytes_read_pg < Phase1.SRC_BUF_SIZE: - src_buf_pg[bytes_read_pg] = 0 - else: - src_buf_pg[Phase1.SRC_BUF_SIZE - 1] = 0 - # 文本扫描筛选:非泛型文件跳过(不 parse、不驻留,防 OOM) - if _BufHasGenericClassMarker(src_buf_pg, bytes_read_pg) == 0: - stdlib.free(src_buf_pg) - continue - # 泛型文件:永久池解析 → 注册模板(节点/表进 perm_pool,跨 reset 存活) - lx_pg: ast.Lexer | t.CPtr = ast.new_lexer(perm) - if lx_pg is None: - stdlib.free(src_buf_pg) - continue - ast._lexer_init(lx_pg, src_buf_pg, perm) - tokens_pg: ast.Token | t.CPtr = ast.tokenize(lx_pg) - tree_pg: ast.AST | t.CPtr = ast.parse_tokens(perm, tokens_pg) - if tree_pg is None: - stdlib.free(src_buf_pg) - continue - # 遍历顶层 ClassDef,注册泛型模板(type_params 非 None) - ch_pg: list[ast.AST | t.CPtr] | t.CPtr = tree_pg.children - if ch_pg is not None: - cn_pg: t.CSizeT = len(ch_pg) - for ci_pg in range(cn_pg): - child_pg: ast.AST | t.CPtr = ch_pg.get(ci_pg) - if child_pg is None or child_pg.kind() != ast.ASTKind.ClassDef: - continue - cd_pg: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child_pg) - if cd_pg is None or cd_pg.name is None: - continue - tp_pg: list[str] | t.CPtr = cd_pg.type_params - if tp_pg is None: - continue - HandlesType.set_current_file(file_path_pg) - HandlesClassDef._register_generic_template(perm, cd_pg, entry_pg.Sha1) - handled_count += 1 - stdlib.free(src_buf_pg) - if handled_count > 0: - fb_gpre2: str = VLogger.fmt_buf() - if fb_gpre2 is not None: - viperlib.snprintf(fb_gpre2, 1024, "mark1 前永久池预注册 %d 个 includes 泛型类模板", handled_count) - VLogger.info(fb_gpre2, "Phase1") - return handled_count -# ============================================================ -# _FindClassDefSha1 - 在扁平数组中查找类名对应的定义文件 SHA1 -# -# Args: -# class_names_buf: 类名扁平数组 -# def_sha1s_buf: 定义 SHA1 扁平数组 -# class_count: 类数量 -# class_name: 要查找的类名 -# -# Returns: -# SHA1 字符串指针(指向 def_sha1s_buf 内部偏移),None 未找到 -# ============================================================ -def _FindClassDefSha1(class_names_buf: bytes, def_sha1s_buf: bytes, - class_count: int, class_name: str) -> str: - """查找类名对应的定义文件 SHA1""" - if class_names_buf is None or def_sha1s_buf is None or class_name is None: - return None - for i in range(class_count): - name_ptr: str = class_names_buf + i * Phase1.CLASS_NAME_LEN - if string.strcmp(name_ptr, class_name) == 0: - return def_sha1s_buf + i * Phase1.SHA1_LEN - return None -# ============================================================ -# _ScanTreeForContainers - 递归扫描 AST 检测 list/dict 容器使用 -# -# TPV 的 AST 中,语句块挂在 children,而表达式/注解树全部以结构体 -# 字段挂载(value/slice/func/args/annotation/targets/returns/bases/ -# left/right 等)。只递归 children 会漏掉 list[...] | t.CPtr(BinOp -# 包裹)、list[...](...)(Call.func)、字段注解等一切非语句块位置。 -# 因此每个节点先递归其表达式承载字段,再递归 children 语句块。 -# 命中即置 need_list/need_dict;误报无害(最多多编译两个空壳模块)。 -# ============================================================ -def _ScanTreeForContainers(node: ast.AST | t.CPtr, - need_list_box: t.CPtr, - need_dict_box: t.CPtr): - """递归扫描 AST(字段 + 语句块),检测 list/dict 容器使用""" - if node is None: - return - k_s: int = node.kind() - if k_s == ast.ASTKind.Name: - nm_s: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm_s.id is not None: - if string.strcmp(nm_s.id, "list") == 0: - need_list_box[0] = 1 - elif string.strcmp(nm_s.id, "dict") == 0: - need_dict_box[0] = 1 - elif k_s == ast.ASTKind.Subscript: - sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - _ScanTreeForContainers(sub_s.value, need_list_box, need_dict_box) - _ScanTreeForContainers(sub_s.slice, need_list_box, need_dict_box) - elif k_s == ast.ASTKind.BinOp: - bop_s: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - _ScanTreeForContainers(bop_s.left, need_list_box, need_dict_box) - _ScanTreeForContainers(bop_s.right, need_list_box, need_dict_box) - elif k_s == ast.ASTKind.Call: - cl_s2: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) - _ScanTreeForContainers(cl_s2.func, need_list_box, need_dict_box) - cl_args_s: list[ast.AST | t.CPtr] | t.CPtr = cl_s2.args - if cl_args_s is not None: - na_s: t.CSizeT = len(cl_args_s) - i_a2: t.CSizeT - for i_a2 in range(na_s): - _ScanTreeForContainers(cl_args_s.get(i_a2), need_list_box, need_dict_box) - cl_kws_s: list[ast.AST | t.CPtr] | t.CPtr = cl_s2.keywords - if cl_kws_s is not None: - nk_s: t.CSizeT = len(cl_kws_s) - i_k2: t.CSizeT - for i_k2 in range(nk_s): - kw_s: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(cl_kws_s.get(i_k2)) - if kw_s is not None: - _ScanTreeForContainers(kw_s.value, need_list_box, need_dict_box) - elif k_s == ast.ASTKind.Assign: - asn_s: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node) - _ScanTreeForContainers(asn_s.value, need_list_box, need_dict_box) - tgts_s: list[ast.AST | t.CPtr] | t.CPtr = asn_s.targets - if tgts_s is not None: - nt_s: t.CSizeT = len(tgts_s) - i_t2: t.CSizeT - for i_t2 in range(nt_s): - _ScanTreeForContainers(tgts_s.get(i_t2), need_list_box, need_dict_box) - elif k_s == ast.ASTKind.AnnAssign: - aa_s2: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) - _ScanTreeForContainers(aa_s2.annotation, need_list_box, need_dict_box) - _ScanTreeForContainers(aa_s2.value, need_list_box, need_dict_box) - elif k_s == ast.ASTKind.FunctionDef: - fn_s: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node) - _ScanTreeForContainers(fn_s.returns, need_list_box, need_dict_box) - fn_args_s: ast.Arguments | t.CPtr = fn_s.args - if fn_args_s is not None: - fa_s: list[ast.AST | t.CPtr] | t.CPtr = fn_args_s.args - if fa_s is not None: - nf_s: t.CSizeT = len(fa_s) - i_f2: t.CSizeT - for i_f2 in range(nf_s): - arg_s: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(fa_s.get(i_f2)) - if arg_s is not None: - _ScanTreeForContainers(arg_s.annotation, need_list_box, need_dict_box) - elif k_s == ast.ASTKind.ClassDef: - cd_s: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(node) - bases_s: list[ast.AST | t.CPtr] | t.CPtr = cd_s.bases - if bases_s is not None: - nb_s: t.CSizeT = len(bases_s) - i_b2: t.CSizeT - for i_b2 in range(nb_s): - _ScanTreeForContainers(bases_s.get(i_b2), need_list_box, need_dict_box) - elif k_s == ast.ASTKind.Attribute: - at_s: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - _ScanTreeForContainers(at_s.value, need_list_box, need_dict_box) - elif k_s == ast.ASTKind.Tuple: - tu_s: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(node) - elts_s: list[ast.AST | t.CPtr] | t.CPtr = tu_s.elts - if elts_s is not None: - ne_s: t.CSizeT = len(elts_s) - i_e2: t.CSizeT - for i_e2 in range(ne_s): - _ScanTreeForContainers(elts_s.get(i_e2), need_list_box, need_dict_box) - elif k_s == ast.ASTKind.UnaryOp: - uop_s: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) - _ScanTreeForContainers(uop_s.operand, need_list_box, need_dict_box) - elif k_s == ast.ASTKind.Expr: - ex_s: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(node) - _ScanTreeForContainers(ex_s.value, need_list_box, need_dict_box) - elif k_s == ast.ASTKind.Return: - rt_s: ast.Return | t.CPtr = (ast.Return | t.CPtr)(node) - _ScanTreeForContainers(rt_s.value, need_list_box, need_dict_box) - elif k_s == ast.ASTKind.Compare: - cp_s: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) - _ScanTreeForContainers(cp_s.left, need_list_box, need_dict_box) - cps_s: list[ast.AST | t.CPtr] | t.CPtr = cp_s.comparators - if cps_s is not None: - nc_s: t.CSizeT = len(cps_s) - i_c2: t.CSizeT - for i_c2 in range(nc_s): - _ScanTreeForContainers(cps_s.get(i_c2), need_list_box, need_dict_box) - elif k_s == ast.ASTKind.BoolOp: - bo_s: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) - bvs_s: list[ast.AST | t.CPtr] | t.CPtr = bo_s.values - if bvs_s is not None: - nv_s: t.CSizeT = len(bvs_s) - i_v2: t.CSizeT - for i_v2 in range(nv_s): - _ScanTreeForContainers(bvs_s.get(i_v2), need_list_box, need_dict_box) - elif k_s == ast.ASTKind.List: - # [] 字面量 - need_list_box[0] = 1 - elif k_s == ast.ASTKind.Dict: - # {} 字面量 - need_dict_box[0] = 1 - # 递归语句块子节点 - if node.children is not None: - ch_s: list[ast.AST | t.CPtr] | t.CPtr = node.children - n_s: t.CSizeT = len(ch_s) - ci_s: t.CSizeT - for ci_s in range(n_s): - _ScanTreeForContainers(ch_s.get(ci_s), need_list_box, need_dict_box) +import lib.core.Gen.GenApi as GenApi +import t, c +from stdint import * +import string +import stdlib +import memhub +import viperlib +import w32.fileio as fileio +import w32.win32file +import w32.win32base +import ast +import llvmlite +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HandlesTranslator +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.IncludesScanner as IncludesScanner +import lib.core.StubMerger as StubMerger +import lib.core.Gen.Generator as GenGenerator +import lib.core.CompilerFactory as CompilerFactory +import lib.core.BuildPipeline as BuildPipeline +import lib.Projectrans.Config as Config +import lib.StubGen.Converter as StubConverter +import lib.core.StubMergerBuild as StubMergerBuild +import lib.core.StubMergerCollect as StubMergerCollect +import lib.core.StubMergerIR as StubMergerIR +import lib.core.StubMergerStore as StubMergerStore + + +import lib.core.Phase1Topo as Phase1Topo +import lib.core.Phase1Main as Phase1Main +import lib.core.Phase1 as Phase1 + +# ============================================================ +# Phase1Scan - Phase1 拆分(阶段 E):Phase1Scan +# +# 直接移动模式:函数迁至此模块,原 Phase1.vp 仅保留常量/_mbuddy; +# 调用方经本模块前缀访问。全局符号经 Phase1._xxx 跨模块访问。 +# ============================================================ + +# 拓扑排序使用扁平字节数组存储类信息和文件依赖, +# 避免结构体中的 str 指针字段在 mb.alloc 零填充时为 NULL 导致崩溃。 +# 类名/父类名存储在 class_names_buf/parent_names_buf(每个 Phase1.CLASS_NAME_LEN 字节), +# 定义 SHA1 存储在 def_sha1s_buf(每个 Phase1.SHA1_LEN 字节)。 + + +# ============================================================ +# _ScanClassInheritance - 预扫描 includes 文件,收集类继承关系 +# +# 遍历所有可达 includes 文件,解析 AST 收集 ClassDef 的类名和父类名。 +# 结果存入扁平字节数组,返回收集到的类数量。 +# +# Args: +# mb: 内存池 +# result: IncludesScanner 扫描结果 +# reachable_set: 可达 SHA1 集合 +# reachable_count: 可达 SHA1 数量 +# use_reachable: 是否使用可达集合过滤 +# sha1_set: SHA1 集合(use_reachable=0 时使用) +# set_count: SHA1 集合数量 +# class_names_buf: 类名扁平数组(每个 Phase1.CLASS_NAME_LEN 字节,连续内存) +# parent_names_buf: 父类名扁平数组(每个 Phase1.CLASS_NAME_LEN 字节,无父类填 '\0') +# def_sha1s_buf: 定义 SHA1 扁平数组(每个 Phase1.SHA1_LEN 字节) +# +# Returns: +# 收集到的类数量,-1 失败 +# ============================================================ +def _ScanClassInheritance(mb: memhub.MemBuddy | t.CPtr, + result: IncludesScanner.ScanResult | t.CPtr, + reachable_set: str, reachable_count: int, + use_reachable: int, + sha1_set: str, set_count: int, + class_names_buf: bytes, + parent_names_buf: bytes, + def_sha1s_buf: bytes, + generic_file_indices: t.CPtr, + generic_file_count_box: t.CPtr) -> int: + """预扫描 includes 文件,收集类继承关系""" + if result is None or class_names_buf is None or parent_names_buf is None or def_sha1s_buf is None: + return -1 + + entry_size: t.CSizeT = IncludesScanner.FileEntry.__sizeof__() + class_count: int = 0 + + for i in range(result.Count): + # 文件级 mark:收集完类继承信息后立即回收本文件 AST(可达 includes + # 全量 parse 的 AST 若驻留到 mark1 → 1GB 主池耗尽 OOM 根因; + # class_names_buf/parent_names_buf/def_sha1s_buf 在调用前分配, + # 位于本 mark 之前,reset 不影响;generic_file_indices 同理) + scan_mark: t.CSizeT = mb.mark() + entry_addr: t.CUInt64T = t.CUInt64T(result.Entries) + i * entry_size + entry: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + if entry is None or entry.Sha1 is None: + continue + + sha1_e: str = entry.Sha1 + file_has_generic: int = 0 + + # 按需翻译过滤 + in_set: int = 0 + if use_reachable != 0: + in_set = StubMergerCollect._is_in_sha1_set(sha1_e, reachable_set, reachable_count) + else: + in_set = StubMergerCollect._is_in_sha1_set(sha1_e, sha1_set, set_count) + if in_set == 0: + continue + + # 读取文件 + file_path: str = entry.Path + f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R) + if f.closed: + continue + + src_buf: bytes = stdlib.malloc(Phase1.SRC_BUF_SIZE) + if src_buf is None: + f.close() + continue + + bytes_read: LONG = f.read_all(src_buf, Phase1.SRC_BUF_SIZE) + f.close() + if bytes_read <= 0: + stdlib.free(src_buf) + continue + if bytes_read < Phase1.SRC_BUF_SIZE: + src_buf[bytes_read] = 0 + else: + src_buf[Phase1.SRC_BUF_SIZE - 1] = 0 + + # 解析 AST + lx: ast.Lexer | t.CPtr = ast.new_lexer(mb) + if lx is None: + stdlib.free(src_buf) + continue + ast._lexer_init(lx, src_buf, mb) + tokens: ast.Token | t.CPtr = ast.tokenize(lx) + tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens) + if tree is None: + stdlib.free(src_buf) + continue + + # 遍历 AST 顶层节点,收集 ClassDef + ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children + if ch is not None: + cn: t.CSizeT = len(ch) + for ci in range(cn): + child: ast.AST | t.CPtr = ch.get(ci) + if child is None: + continue + kd: int = child.kind() + if kd != ast.ASTKind.ClassDef: + continue + + cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child) + if cd is None or cd.name is None: + continue + + # 检测泛型类(有 type_params),记录文件索引以供 Phase 1a 预注册 + if file_has_generic == 0: + tp_scan: list[str] | t.CPtr = cd.type_params + if tp_scan is not None: + file_has_generic = 1 + if generic_file_count_box is not None: + gfc_ptr_scan: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(generic_file_count_box, t.CPtr)) + if gfc_ptr_scan is not None: + gfc_scan: int = gfc_ptr_scan[0] + if gfc_scan < Phase1.MAX_FILE_DEPS and generic_file_indices is not None: + gi_addr_scan: t.CUInt64T = t.CUInt64T(generic_file_indices) + gfc_scan * 4 + gi_ptr_scan: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(gi_addr_scan, t.CPtr)) + if gi_ptr_scan is not None: + gi_ptr_scan[0] = i + gfc_ptr_scan[0] = gfc_scan + 1 + + if class_count >= Phase1.MAX_CLASSES: + break + + # 填充扁平数组:类名(偏移 = class_count * Phase1.CLASS_NAME_LEN) + name_dst: str = class_names_buf + class_count * Phase1.CLASS_NAME_LEN + nm_len: t.CSizeT = string.strlen(cd.name) + if nm_len >= Phase1.CLASS_NAME_LEN: + string.strncpy(name_dst, cd.name, Phase1.CLASS_NAME_LEN - 1) + name_dst[Phase1.CLASS_NAME_LEN - 1] = '\0' + else: + string.strcpy(name_dst, cd.name) + + # 填充扁平数组:父类名(无父类填 '\0') + parent_dst: str = parent_names_buf + class_count * Phase1.CLASS_NAME_LEN + parent_dst[0] = '\0' + parent_nm: str = GenApi._get_parent_class(cd, None) + # parent_nm 是 AST 节点内部指针,不需要释放 + if parent_nm is not None: + pnm_len: t.CSizeT = string.strlen(parent_nm) + if pnm_len >= Phase1.CLASS_NAME_LEN: + string.strncpy(parent_dst, parent_nm, Phase1.CLASS_NAME_LEN - 1) + parent_dst[Phase1.CLASS_NAME_LEN - 1] = '\0' + else: + string.strcpy(parent_dst, parent_nm) + + # 填充扁平数组:定义 SHA1(偏移 = class_count * Phase1.SHA1_LEN) + sha1_dst: str = def_sha1s_buf + class_count * Phase1.SHA1_LEN + string.strcpy(sha1_dst, sha1_e) + + class_count += 1 + + stdlib.free(src_buf) + # 回收本文件 AST/lexer/token(类名/父类/SHA1 已拷入扁平数组) + mb.reset_to(scan_mark) + + return class_count +# ============================================================ +# _BufHasGenericClassMarker - 文本扫描检测文件是否含泛型类标记 +# +# 泛型类(PEP 695)语法: class Name[T]:(类名后紧跟 '[')。 +# 逐字节扫描找词边界 'class' 关键字,其后标识符后非空白是 '[' → 命中。 +# 用于 _PreRegisterAllGenericTemplates 预注册前筛选,避免 parse 全部 +# 98 个 includes 导致 AST 驻留 mark1 前把 pool 推到 OOM +# (NewAstTest [52/68] pool 耗尽根因:1a-pre 已 parse 全部驻留, +# 预注册再全量 parse 等于翻倍)。 +# 误报(字符串/注释里的 "class X[")无害(多 parse 一个文件); +# 漏报有害(泛型模板未预注册 → 悬空复发),模式保守匹配行内单行形式 +# (TPV 源码泛型类均为单行 `class X[T]:`,grep 确认)。 +# ============================================================ +def _BufHasGenericClassMarker(buf: bytes, blen: t.CSizeT) -> int: + """文本扫描:buf 中是否有 'class 标识符[' 泛型类标记,返回 1/0""" + if buf is None or blen <= 6: + return 0 + pos: t.CSizeT = 0 + while pos + 5 < blen: + if buf[pos] == 'c' and buf[pos + 1] == 'l' and buf[pos + 2] == 'a' \ + and buf[pos + 3] == 's' and buf[pos + 4] == 's': + # class 前是词边界(行首或非标识符字符) + prev_ok: int = 1 + if pos > 0: + pc: t.CChar = buf[pos - 1] + if(pc >= 'a' and pc <= 'z') or(pc >= 'A' and pc <= 'Z') \ + or(pc >= '0' and pc <= '9') or pc == '_': + prev_ok = 0 + if prev_ok != 0: + p: t.CSizeT = pos + 5 + # 跳过空白 + while p < blen and(buf[p] == ' ' or buf[p] == '\t'): + p += 1 + # 读类名标识符 + if p < blen and((buf[p] >= 'a' and buf[p] <= 'z') + or(buf[p] >= 'A' and buf[p] <= 'Z') or buf[p] == '_'): + while p < blen and((buf[p] >= 'a' and buf[p] <= 'z') + or(buf[p] >= 'A' and buf[p] <= 'Z') + or(buf[p] >= '0' and buf[p] <= '9') + or buf[p] == '_'): + p += 1 + # 类名后非空白是 '[' → 泛型类 + while p < blen and(buf[p] == ' ' or buf[p] == '\t'): + p += 1 + if p < blen and buf[p] == '[': + return 1 + pos += 1 + else: + pos += 1 + return 0 +# ============================================================ +# _PreRegisterAllGenericTemplates - 预注册 includes 泛型类模板(mark1 前) +# +# 背景:泛型模板表(GenericClassNames/GenericClassNodes/GenericClassSha1s/ +# GenericClassFiles + 模板节点)是懒分配的跨文件持久表,首次注册必须落在 +# mark1 之前才能跨 Phase1 1b(reset_to(mark1))与 Phase2(reset_to(mark2), +# mark2 > mark1)存活。现有 1a-pre-generic 只注册"可达"泛型文件;FuncTest +# 这类可达集合无泛型的项目,模板要等 Phase2 Phase A-pre-inc(mark2 之后) +# 翻译全部 includes 时才注册 → reset 回收表与节点 → _find_generic_template +# 遍历悬空内存 strcmp 崩溃。 +# 本函数先文本扫描(_BufHasGenericClassMarker,不 parse、不驻留)筛选出 +# 含泛型类的文件(全量 parse 会把 98 个 includes 的 AST 驻留 mark1 前 → +# NewAstTest [52/68] pool 耗尽 OOM),仅对命中的文件用**永久池(perm_pool)** +# 解析 → 模板节点与表直接进 perm_pool,跨 mark 永久存活、不占主 pool。 +# 重复注册由 _register_generic_template 内部查重跳过。 +# ============================================================ +def _PreRegisterAllGenericTemplates(mb: memhub.MemBuddy | t.CPtr, + result: IncludesScanner.ScanResult | t.CPtr) -> int: + """预注册全部 includes 文件的泛型类模板,返回处理到的泛型类数量""" + if result is None or mb is None: + return 0 + perm: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool() + if perm is None: + return 0 + p1e_size: t.CSizeT = IncludesScanner.FileEntry.__sizeof__() + handled_count: int = 0 + for i in range(result.Count): + entry_addr_pg: t.CUInt64T = t.CUInt64T(result.Entries) + i * p1e_size + entry_pg: IncludesScanner.FileEntry | t.CPtr = ( + IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_pg, t.CPtr)) + if entry_pg is None or entry_pg.Sha1 is None: + continue + # 读取文件 + file_path_pg: str = entry_pg.Path + f_pg: fileio.File | t.CPtr = fileio.File(file_path_pg, fileio.MODE.R) + if f_pg.closed: + continue + src_buf_pg: bytes = stdlib.malloc(Phase1.SRC_BUF_SIZE) + if src_buf_pg is None: + f_pg.close() + continue + bytes_read_pg: LONG = f_pg.read_all(src_buf_pg, Phase1.SRC_BUF_SIZE) + f_pg.close() + if bytes_read_pg <= 0: + stdlib.free(src_buf_pg) + continue + if bytes_read_pg < Phase1.SRC_BUF_SIZE: + src_buf_pg[bytes_read_pg] = 0 + else: + src_buf_pg[Phase1.SRC_BUF_SIZE - 1] = 0 + # 文本扫描筛选:非泛型文件跳过(不 parse、不驻留,防 OOM) + if _BufHasGenericClassMarker(src_buf_pg, bytes_read_pg) == 0: + stdlib.free(src_buf_pg) + continue + # 泛型文件:永久池解析 → 注册模板(节点/表进 perm_pool,跨 reset 存活) + lx_pg: ast.Lexer | t.CPtr = ast.new_lexer(perm) + if lx_pg is None: + stdlib.free(src_buf_pg) + continue + ast._lexer_init(lx_pg, src_buf_pg, perm) + tokens_pg: ast.Token | t.CPtr = ast.tokenize(lx_pg) + tree_pg: ast.AST | t.CPtr = ast.parse_tokens(perm, tokens_pg) + if tree_pg is None: + stdlib.free(src_buf_pg) + continue + # 遍历顶层 ClassDef,注册泛型模板(type_params 非 None) + ch_pg: list[ast.AST | t.CPtr] | t.CPtr = tree_pg.children + if ch_pg is not None: + cn_pg: t.CSizeT = len(ch_pg) + for ci_pg in range(cn_pg): + child_pg: ast.AST | t.CPtr = ch_pg.get(ci_pg) + if child_pg is None or child_pg.kind() != ast.ASTKind.ClassDef: + continue + cd_pg: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child_pg) + if cd_pg is None or cd_pg.name is None: + continue + tp_pg: list[str] | t.CPtr = cd_pg.type_params + if tp_pg is None: + continue + GenApi.set_current_file_type(file_path_pg) + GenApi._register_generic_template(perm, cd_pg, entry_pg.Sha1) + handled_count += 1 + stdlib.free(src_buf_pg) + if handled_count > 0: + fb_gpre2: str = VLogger.fmt_buf() + if fb_gpre2 is not None: + viperlib.snprintf(fb_gpre2, 1024, "mark1 前永久池预注册 %d 个 includes 泛型类模板", handled_count) + VLogger.info(fb_gpre2, "Phase1") + return handled_count +# ============================================================ +# _FindClassDefSha1 - 在扁平数组中查找类名对应的定义文件 SHA1 +# +# Args: +# class_names_buf: 类名扁平数组 +# def_sha1s_buf: 定义 SHA1 扁平数组 +# class_count: 类数量 +# class_name: 要查找的类名 +# +# Returns: +# SHA1 字符串指针(指向 def_sha1s_buf 内部偏移),None 未找到 +# ============================================================ +def _FindClassDefSha1(class_names_buf: bytes, def_sha1s_buf: bytes, + class_count: int, class_name: str) -> str: + """查找类名对应的定义文件 SHA1""" + if class_names_buf is None or def_sha1s_buf is None or class_name is None: + return None + for i in range(class_count): + name_ptr: str = class_names_buf + i * Phase1.CLASS_NAME_LEN + if string.strcmp(name_ptr, class_name) == 0: + return def_sha1s_buf + i * Phase1.SHA1_LEN + return None +# ============================================================ +# _ScanTreeForContainers - 递归扫描 AST 检测 list/dict 容器使用 +# +# TPV 的 AST 中,语句块挂在 children,而表达式/注解树全部以结构体 +# 字段挂载(value/slice/func/args/annotation/targets/returns/bases/ +# left/right 等)。只递归 children 会漏掉 list[...] | t.CPtr(BinOp +# 包裹)、list[...](...)(Call.func)、字段注解等一切非语句块位置。 +# 因此每个节点先递归其表达式承载字段,再递归 children 语句块。 +# 命中即置 need_list/need_dict;误报无害(最多多编译两个空壳模块)。 +# ============================================================ +def _ScanTreeForContainers(node: ast.AST | t.CPtr, + need_list_box: t.CPtr, + need_dict_box: t.CPtr): + """递归扫描 AST(字段 + 语句块),检测 list/dict 容器使用""" + if node is None: + return + k_s: int = node.kind() + if k_s == ast.ASTKind.Name: + nm_s: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm_s.id is not None: + if string.strcmp(nm_s.id, "list") == 0: + need_list_box[0] = 1 + elif string.strcmp(nm_s.id, "dict") == 0: + need_dict_box[0] = 1 + elif k_s == ast.ASTKind.Subscript: + sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + _ScanTreeForContainers(sub_s.value, need_list_box, need_dict_box) + _ScanTreeForContainers(sub_s.slice, need_list_box, need_dict_box) + elif k_s == ast.ASTKind.BinOp: + bop_s: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + _ScanTreeForContainers(bop_s.left, need_list_box, need_dict_box) + _ScanTreeForContainers(bop_s.right, need_list_box, need_dict_box) + elif k_s == ast.ASTKind.Call: + cl_s2: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + _ScanTreeForContainers(cl_s2.func, need_list_box, need_dict_box) + cl_args_s: list[ast.AST | t.CPtr] | t.CPtr = cl_s2.args + if cl_args_s is not None: + na_s: t.CSizeT = len(cl_args_s) + i_a2: t.CSizeT + for i_a2 in range(na_s): + _ScanTreeForContainers(cl_args_s.get(i_a2), need_list_box, need_dict_box) + cl_kws_s: list[ast.AST | t.CPtr] | t.CPtr = cl_s2.keywords + if cl_kws_s is not None: + nk_s: t.CSizeT = len(cl_kws_s) + i_k2: t.CSizeT + for i_k2 in range(nk_s): + kw_s: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(cl_kws_s.get(i_k2)) + if kw_s is not None: + _ScanTreeForContainers(kw_s.value, need_list_box, need_dict_box) + elif k_s == ast.ASTKind.Assign: + asn_s: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node) + _ScanTreeForContainers(asn_s.value, need_list_box, need_dict_box) + tgts_s: list[ast.AST | t.CPtr] | t.CPtr = asn_s.targets + if tgts_s is not None: + nt_s: t.CSizeT = len(tgts_s) + i_t2: t.CSizeT + for i_t2 in range(nt_s): + _ScanTreeForContainers(tgts_s.get(i_t2), need_list_box, need_dict_box) + elif k_s == ast.ASTKind.AnnAssign: + aa_s2: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) + _ScanTreeForContainers(aa_s2.annotation, need_list_box, need_dict_box) + _ScanTreeForContainers(aa_s2.value, need_list_box, need_dict_box) + elif k_s == ast.ASTKind.FunctionDef: + fn_s: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node) + _ScanTreeForContainers(fn_s.returns, need_list_box, need_dict_box) + fn_args_s: ast.Arguments | t.CPtr = fn_s.args + if fn_args_s is not None: + fa_s: list[ast.AST | t.CPtr] | t.CPtr = fn_args_s.args + if fa_s is not None: + nf_s: t.CSizeT = len(fa_s) + i_f2: t.CSizeT + for i_f2 in range(nf_s): + arg_s: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(fa_s.get(i_f2)) + if arg_s is not None: + _ScanTreeForContainers(arg_s.annotation, need_list_box, need_dict_box) + elif k_s == ast.ASTKind.ClassDef: + cd_s: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(node) + bases_s: list[ast.AST | t.CPtr] | t.CPtr = cd_s.bases + if bases_s is not None: + nb_s: t.CSizeT = len(bases_s) + i_b2: t.CSizeT + for i_b2 in range(nb_s): + _ScanTreeForContainers(bases_s.get(i_b2), need_list_box, need_dict_box) + elif k_s == ast.ASTKind.Attribute: + at_s: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + _ScanTreeForContainers(at_s.value, need_list_box, need_dict_box) + elif k_s == ast.ASTKind.Tuple: + tu_s: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(node) + elts_s: list[ast.AST | t.CPtr] | t.CPtr = tu_s.elts + if elts_s is not None: + ne_s: t.CSizeT = len(elts_s) + i_e2: t.CSizeT + for i_e2 in range(ne_s): + _ScanTreeForContainers(elts_s.get(i_e2), need_list_box, need_dict_box) + elif k_s == ast.ASTKind.UnaryOp: + uop_s: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + _ScanTreeForContainers(uop_s.operand, need_list_box, need_dict_box) + elif k_s == ast.ASTKind.Expr: + ex_s: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(node) + _ScanTreeForContainers(ex_s.value, need_list_box, need_dict_box) + elif k_s == ast.ASTKind.Return: + rt_s: ast.Return | t.CPtr = (ast.Return | t.CPtr)(node) + _ScanTreeForContainers(rt_s.value, need_list_box, need_dict_box) + elif k_s == ast.ASTKind.Compare: + cp_s: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) + _ScanTreeForContainers(cp_s.left, need_list_box, need_dict_box) + cps_s: list[ast.AST | t.CPtr] | t.CPtr = cp_s.comparators + if cps_s is not None: + nc_s: t.CSizeT = len(cps_s) + i_c2: t.CSizeT + for i_c2 in range(nc_s): + _ScanTreeForContainers(cps_s.get(i_c2), need_list_box, need_dict_box) + elif k_s == ast.ASTKind.BoolOp: + bo_s: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) + bvs_s: list[ast.AST | t.CPtr] | t.CPtr = bo_s.values + if bvs_s is not None: + nv_s: t.CSizeT = len(bvs_s) + i_v2: t.CSizeT + for i_v2 in range(nv_s): + _ScanTreeForContainers(bvs_s.get(i_v2), need_list_box, need_dict_box) + elif k_s == ast.ASTKind.List: + # [] 字面量 + need_list_box[0] = 1 + elif k_s == ast.ASTKind.Dict: + # {} 字面量 + need_dict_box[0] = 1 + # 递归语句块子节点 + if node.children is not None: + ch_s: list[ast.AST | t.CPtr] | t.CPtr = node.children + n_s: t.CSizeT = len(ch_s) + ci_s: t.CSizeT + for ci_s in range(n_s): + _ScanTreeForContainers(ch_s.get(ci_s), need_list_box, need_dict_box) diff --git a/App/lib/core/Phase1Topo.vp b/App/lib/core/Phase1Topo.vp index fdf6b29..b92b19b 100644 --- a/App/lib/core/Phase1Topo.vp +++ b/App/lib/core/Phase1Topo.vp @@ -1,417 +1,412 @@ -import t, c -from stdint import * -import string -import stdlib -import memhub -import viperlib -import w32.fileio as fileio -import w32.win32file -import w32.win32base -import ast -import llvmlite -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HandlesTranslator -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.IncludesScanner as IncludesScanner -import lib.core.StubMerger as StubMerger -import lib.core.Gen.Generator as GenGenerator -import lib.core.CompilerFactory as CompilerFactory -import lib.core.BuildPipeline as BuildPipeline -import lib.Projectrans.Config as Config -import lib.StubGen.Converter as StubConverter -import lib.core.StubMergerBuild as StubMergerBuild -import lib.core.StubMergerCollect as StubMergerCollect -import lib.core.StubMergerIR as StubMergerIR -import lib.core.StubMergerStore as StubMergerStore -import lib.core.Handles.ExprCallCtor as ExprCallCtor - - -import lib.core.Phase1Scan as Phase1Scan -import lib.core.Phase1Main as Phase1Main -import lib.core.Phase1 as Phase1 - -# ============================================================ -# Phase1Topo - Phase1 拆分(阶段 E):Phase1Topo -# -# 直接移动模式:函数迁至此模块,原 Phase1.vp 仅保留常量/_mbuddy; -# 调用方经本模块前缀访问。全局符号经 Phase1._xxx 跨模块访问。 -# ============================================================ - -# ============================================================ -# _TopoSortFiles - 根据类继承关系对文件进行拓扑排序 -# -# 算法(Kahn): -# 1. 从扁平类信息数组构建"文件 SHA1 → 依赖文件 SHA1 集合"映射 -# 2. 计算每个文件的入度(依赖数量) -# 3. 入度为 0 的文件先处理,处理后减少依赖它的文件入度 -# 4. 重复直到所有文件处理完成 -# -# 注意:依赖方向是"父类所在文件 → 子类所在文件", -# 即父类文件必须先处理。Kahn 用 DepCount 作为剩余依赖计数, -# 依赖为 0 的先处理,初始化 InDegree = DepCount。 -# -# Args: -# mb: 内存池 -# result: IncludesScanner 扫描结果 -# reachable_set: 可达 SHA1 集合 -# reachable_count: 可达 SHA1 数量 -# use_reachable: 是否使用可达集合过滤 -# sha1_set: SHA1 集合 -# set_count: SHA1 集合数量 -# class_names_buf: 类名扁平数组 -# parent_names_buf: 父类名扁平数组 -# def_sha1s_buf: 定义 SHA1 扁平数组 -# class_count: 类数量 -# out_order: 输出拓扑顺序的文件索引数组(调用者分配,int 数组) -# out_count: 输出文件数量 -# -# Returns: -# 0 成功,-1 失败 -# ============================================================ -def _TopoSortFiles(mb: memhub.MemBuddy | t.CPtr, - result: IncludesScanner.ScanResult | t.CPtr, - reachable_set: str, reachable_count: int, - use_reachable: int, - sha1_set: str, set_count: int, - class_names_buf: bytes, parent_names_buf: bytes, - def_sha1s_buf: bytes, class_count: int, - out_order: t.CPtr, out_count: t.CPtr, - temp_dir: str, td_len_ts: t.CSizeT) -> int: - """根据类继承关系对文件进行拓扑排序""" - if result is None or out_order is None or out_count is None: - return -1 - - entry_size: t.CSizeT = IncludesScanner.FileEntry.__sizeof__() - - # 1. 分配扁平数组:文件 SHA1、依赖 SHA1 列表、依赖数量、入度、处理状态 - # 用扁平数组代替 FileDepEntry 结构体,避免 str 指针字段 NULL 崩溃 - file_sha1s_buf: bytes = mb.alloc(Phase1.MAX_FILE_DEPS * Phase1.SHA1_LEN) - file_deps_buf: bytes = mb.alloc(Phase1.MAX_FILE_DEPS * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN) - file_dep_counts: t.CPtr = mb.alloc(Phase1.MAX_FILE_DEPS * 4) - file_indegrees: t.CPtr = mb.alloc(Phase1.MAX_FILE_DEPS * 4) - file_processed: t.CPtr = mb.alloc(Phase1.MAX_FILE_DEPS * 4) - - if file_sha1s_buf is None or file_deps_buf is None or file_dep_counts is None or file_indegrees is None or file_processed is None: - if file_sha1s_buf is not None: - mb.free(file_sha1s_buf) - if file_deps_buf is not None: - mb.free(file_deps_buf) - if file_dep_counts is not None: - mb.free(file_dep_counts) - if file_indegrees is not None: - mb.free(file_indegrees) - if file_processed is not None: - mb.free(file_processed) - return -1 - - string.memset(file_sha1s_buf, 0, Phase1.MAX_FILE_DEPS * Phase1.SHA1_LEN) - string.memset(file_deps_buf, 0, Phase1.MAX_FILE_DEPS * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN) - string.memset(file_dep_counts, 0, Phase1.MAX_FILE_DEPS * 4) - string.memset(file_indegrees, 0, Phase1.MAX_FILE_DEPS * 4) - string.memset(file_processed, 0, Phase1.MAX_FILE_DEPS * 4) - - file_count: int = 0 - # sha1→file_index 映射(简单线性查找,文件数不多) - for i in range(result.Count): - entry_addr: t.CUInt64T = t.CUInt64T(result.Entries) + i * entry_size - entry: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - if entry is None or entry.Sha1 is None: - continue - - sha1_e: str = entry.Sha1 - in_set: int = 0 - if use_reachable != 0: - in_set = StubMergerCollect._is_in_sha1_set(sha1_e, reachable_set, reachable_count) - else: - in_set = StubMergerCollect._is_in_sha1_set(sha1_e, sha1_set, set_count) - if in_set == 0: - continue - - if file_count >= Phase1.MAX_FILE_DEPS: - break - - # 初始化扁平数组:文件 SHA1(偏移 = file_count * Phase1.SHA1_LEN) - # DepCount/InDegree/Processed 已由 memset 清零 - sha1_dst: str = file_sha1s_buf + file_count * Phase1.SHA1_LEN - string.strcpy(sha1_dst, sha1_e) - - file_count += 1 - - # 2. 构建依赖边:对每个类,找到父类定义所在文件,建立 子文件→父文件 依赖 - for ci in range(class_count): - # 读取父类名(偏移 = ci * Phase1.CLASS_NAME_LEN) - parent_ptr: str = parent_names_buf + ci * Phase1.CLASS_NAME_LEN - if parent_ptr[0] == '\0': - continue - - # 读取子类定义 SHA1(偏移 = ci * Phase1.SHA1_LEN) - child_def_sha1: str = def_sha1s_buf + ci * Phase1.SHA1_LEN - - # 查找父类定义所在文件的 SHA1 - parent_sha1: str = Phase1Scan._FindClassDefSha1(class_names_buf, def_sha1s_buf, class_count, parent_ptr) - if parent_sha1 is None: - continue # 父类不在 includes 中(如 Object、CEnum 等标记基类) - - # 父类文件 SHA1 不能等于子类文件 SHA1(同文件内继承不需要依赖) - if string.strcmp(parent_sha1, child_def_sha1) == 0: - continue - - # 找到子类文件对应的索引,添加父文件 SHA1 到依赖列表 - for fi in range(file_count): - fsha1: str = file_sha1s_buf + fi * Phase1.SHA1_LEN - if string.strcmp(fsha1, child_def_sha1) != 0: - continue - - # 读取当前依赖数量 - cnt_addr: t.CUInt64T = t.CUInt64T(file_dep_counts) + fi * 4 - cnt_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(cnt_addr, t.CPtr)) - if cnt_ptr is None: - break - cur_cnt: int = cnt_ptr[0] - - # 检查依赖是否已添加(去重) - already: int = 0 - for di in range(cur_cnt): - dep_slot: str = file_deps_buf + fi * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN + di * Phase1.SHA1_LEN - if string.strcmp(dep_slot, parent_sha1) == 0: - already = 1 - break - if already != 0: - break - - if cur_cnt < Phase1.MAX_DEP_EDGES: - dep_dst: str = file_deps_buf + fi * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN + cur_cnt * Phase1.SHA1_LEN - string.strcpy(dep_dst, parent_sha1) - cnt_ptr[0] = cur_cnt + 1 - break - - # 2.5 补充 import 依赖边:被 import 的模块先完整翻译。 - # - # 仅按类继承建边不够:跨模块全局变量 stub(lexer.vp from-import - # tokens.vp 的 _op_head)、跨模块 vtable TypeStr(astaux 继承 base 的 - # AST)、泛型模板(base.vp 用 list[...])都要求依赖模块先翻译,而它们 - # 之间可能无类继承关系。deps(_includes_deps_*)由 Phase 1a-pre 填充 - # (含容器按需注入的 _list/_dict)。 - # - # 用 _BuildIncludesSha1Map 复制局部 sha1→模块名 数组(与 - # _BuildReachableSha1Set 的 BFS 一致),避免直接使用全局 store 返回值 - # 跨函数传参(bytes|t.CPtr 联合转 str 参数)的地址异常。 - sha1_arr_ts: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 17) - mod_arr_ts: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 64) - map_count_ts: int = 0 - if sha1_arr_ts is not None and mod_arr_ts is not None: - map_count_ts = StubMergerIR._BuildIncludesSha1Map( - temp_dir, td_len_ts, sha1_arr_ts, mod_arr_ts) - for fi_imp in range(file_count): - if map_count_ts <= 0: - break - fsha1_imp: str = file_sha1s_buf + fi_imp * Phase1.SHA1_LEN - deps_imp: str = StubMergerStore.LookupIncludesDeps(fsha1_imp) - if deps_imp is None: - continue - dl_imp: t.CSizeT = string.strlen(deps_imp) - dpos_imp: t.CSizeT = 0 - while dpos_imp < dl_imp: - dstart_imp: t.CSizeT = dpos_imp - while dpos_imp < dl_imp and deps_imp[dpos_imp] != ' ': - dpos_imp += 1 - dlen_imp: t.CSizeT = dpos_imp - dstart_imp - if dpos_imp < dl_imp: - dpos_imp += 1 - if dlen_imp == 0: - continue - dname_imp: bytes = stdlib.malloc(dlen_imp + 1) - if dname_imp is None: - continue - string.strncpy(dname_imp, deps_imp + dstart_imp, dlen_imp) - dname_imp[dlen_imp] = '\0' - dsha1_imp: str = StubMergerIR._FindSha1ByModName( - sha1_arr_ts, mod_arr_ts, map_count_ts, dname_imp) - stdlib.free(dname_imp) - if dsha1_imp is None: - continue - # 找依赖文件在列表中的索引(跳过自身) - for fj_imp in range(file_count): - if string.strcmp(file_sha1s_buf + fj_imp * Phase1.SHA1_LEN, dsha1_imp) != 0: - continue - if fj_imp == fi_imp: - break - # 去重 + 加边:fi_imp 依赖 fj_imp(InDegree[fi_imp]++) - cnt_addr_imp: t.CUInt64T = t.CUInt64T(file_dep_counts) + fi_imp * 4 - cnt_ptr_imp: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(cnt_addr_imp, t.CPtr)) - if cnt_ptr_imp is None: - break - cur_cnt_imp: int = cnt_ptr_imp[0] - already_imp: int = 0 - for di_imp in range(cur_cnt_imp): - dep_slot_imp: str = file_deps_buf + fi_imp * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN + di_imp * Phase1.SHA1_LEN - if string.strcmp(dep_slot_imp, dsha1_imp) == 0: - already_imp = 1 - break - if already_imp == 0 and cur_cnt_imp < Phase1.MAX_DEP_EDGES: - dep_dst_imp: str = file_deps_buf + fi_imp * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN + cur_cnt_imp * Phase1.SHA1_LEN - string.strcpy(dep_dst_imp, dsha1_imp) - cnt_ptr_imp[0] = cur_cnt_imp + 1 - break - - # 释放 import 边用的局部映射数组 - if sha1_arr_ts is not None: - stdlib.free(sha1_arr_ts) - if mod_arr_ts is not None: - stdlib.free(mod_arr_ts) - - # 3. Kahn 算法:InDegree = DepCount(依赖多少个父文件) - # 依赖为 0 的先处理,处理后减少依赖它的文件入度 - for fi in range(file_count): - cnt_addr3: t.CUInt64T = t.CUInt64T(file_dep_counts) + fi * 4 - cnt_ptr3: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(cnt_addr3, t.CPtr)) - ind_addr3: t.CUInt64T = t.CUInt64T(file_indegrees) + fi * 4 - ind_ptr3: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(ind_addr3, t.CPtr)) - if cnt_ptr3 is not None and ind_ptr3 is not None: - ind_ptr3[0] = cnt_ptr3[0] - - # 4. 拓扑排序输出 - out_idx: int = 0 - changed: int = 1 - while changed != 0: - changed = 0 - for fi in range(file_count): - # 检查处理状态 - proc_addr4: t.CUInt64T = t.CUInt64T(file_processed) + fi * 4 - proc_ptr4: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(proc_addr4, t.CPtr)) - if proc_ptr4 is None or proc_ptr4[0] != 0: - continue - # 检查入度 - ind_addr4: t.CUInt64T = t.CUInt64T(file_indegrees) + fi * 4 - ind_ptr4: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(ind_addr4, t.CPtr)) - if ind_ptr4 is None or ind_ptr4[0] > 0: - continue - - # 入度为 0,可以处理 - # 找到对应的 result.Entries 索引 - target_sha1: str = file_sha1s_buf + fi * Phase1.SHA1_LEN - for ri in range(result.Count): - ea_r: t.CUInt64T = t.CUInt64T(result.Entries) + ri * entry_size - ent_r: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea_r, t.CPtr)) - if ent_r is not None and ent_r.Sha1 is not None: - if string.strcmp(ent_r.Sha1, target_sha1) == 0: - # 写入输出索引数组 - out_idx_addr: t.CUInt64T = t.CUInt64T(out_order) + out_idx * 4 - out_int_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(out_idx_addr, t.CPtr)) - if out_int_ptr is not None: - out_int_ptr[0] = ri - out_idx += 1 - break - - # 标记已处理 - proc_ptr4[0] = 1 - changed = 1 - - # 减少依赖该文件的其他文件的入度 - for fj in range(file_count): - proc_addr5: t.CUInt64T = t.CUInt64T(file_processed) + fj * 4 - proc_ptr5: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(proc_addr5, t.CPtr)) - if proc_ptr5 is None or proc_ptr5[0] != 0: - continue - # 读取 fj 的依赖数量 - cnt_addr5: t.CUInt64T = t.CUInt64T(file_dep_counts) + fj * 4 - cnt_ptr5: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(cnt_addr5, t.CPtr)) - if cnt_ptr5 is None: - continue - fj_dep_cnt: int = cnt_ptr5[0] - for di in range(fj_dep_cnt): - dep_slot5: str = file_deps_buf + fj * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN + di * Phase1.SHA1_LEN - if string.strcmp(dep_slot5, target_sha1) == 0: - ind_addr5: t.CUInt64T = t.CUInt64T(file_indegrees) + fj * 4 - ind_ptr5: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(ind_addr5, t.CPtr)) - if ind_ptr5 is not None: - ind_ptr5[0] = ind_ptr5[0] - 1 - break - - # 处理循环依赖:环内优先输出"被依赖者"(被其余剩余文件依赖数量多者先)。 - # - # 背景:容器按需注入(string 用 list 泛型 → 依赖 _list)与真实 import - # (_list import string)形成伪环,Kahn 无法完全归零。若按扫描顺序追加, - # 依赖者(astaux)会先于被依赖者(base)翻译 → 跨模块 vtable TypeStr - # 未注册 → 误杀。被依赖者先翻译,其 stub/TypeStr/模板先就绪,依赖者 - # 翻译时可引用(函数/全局声明由 1a-pre 的 vpi 兜底)。 - if out_idx < file_count: - rem_idx: t.CPtr = stdlib.malloc(4 * file_count) - rem_depcnt: t.CPtr = stdlib.malloc(4 * file_count) - rem_count: int = 0 - if rem_idx is not None and rem_depcnt is not None: - for fi in range(file_count): - proc_addr7: t.CUInt64T = t.CUInt64T(file_processed) + fi * 4 - proc_ptr7: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(proc_addr7, t.CPtr)) - if proc_ptr7 is not None and proc_ptr7[0] == 0: - rem_idx[rem_count] = fi - rem_depcnt[rem_count] = 0 - rem_count += 1 - # 计算每个剩余文件的被依赖数(被其余剩余文件依赖) - for i_a in range(rem_count): - fi_a: int = rem_idx[i_a] - target_sha1_a: str = file_sha1s_buf + fi_a * Phase1.SHA1_LEN - for i_b in range(rem_count): - fi_b: int = rem_idx[i_b] - if fi_b == fi_a: - continue - cnt_addr_b: t.CUInt64T = t.CUInt64T(file_dep_counts) + fi_b * 4 - cnt_ptr_b: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(cnt_addr_b, t.CPtr)) - if cnt_ptr_b is None: - continue - cnt_b: int = cnt_ptr_b[0] - for di_b in range(cnt_b): - dep_slot_b: str = file_deps_buf + fi_b * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN + di_b * Phase1.SHA1_LEN - if string.strcmp(dep_slot_b, target_sha1_a) == 0: - rem_depcnt[i_a] = rem_depcnt[i_a] + 1 - break - # 冒泡降序(被依赖数多者在前) - for i_a in range(rem_count): - for j_a in range(rem_count - 1): - if rem_depcnt[j_a] < rem_depcnt[j_a + 1]: - tmp_i: int = rem_idx[j_a] - rem_idx[j_a] = rem_idx[j_a + 1] - rem_idx[j_a + 1] = tmp_i - tmp_d: int = rem_depcnt[j_a] - rem_depcnt[j_a] = rem_depcnt[j_a + 1] - rem_depcnt[j_a + 1] = tmp_d - # 按序输出剩余文件 - for i_a in range(rem_count): - fi_a2: int = rem_idx[i_a] - proc_addr8: t.CUInt64T = t.CUInt64T(file_processed) + fi_a2 * 4 - proc_ptr8: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(proc_addr8, t.CPtr)) - if proc_ptr8 is None or proc_ptr8[0] != 0: - continue - target_sha1_2: str = file_sha1s_buf + fi_a2 * Phase1.SHA1_LEN - for ri in range(result.Count): - ea_r2: t.CUInt64T = t.CUInt64T(result.Entries) + ri * entry_size - ent_r2: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea_r2, t.CPtr)) - if ent_r2 is not None and ent_r2.Sha1 is not None: - if string.strcmp(ent_r2.Sha1, target_sha1_2) == 0: - out_idx_addr2: t.CUInt64T = t.CUInt64T(out_order) + out_idx * 4 - out_int_ptr2: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(out_idx_addr2, t.CPtr)) - if out_int_ptr2 is not None: - out_int_ptr2[0] = ri - out_idx += 1 - break - proc_ptr8[0] = 1 - stdlib.free(rem_idx) - stdlib.free(rem_depcnt) - - # 写入输出数量 - out_count_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(out_count, t.CPtr)) - if out_count_ptr is not None: - out_count_ptr[0] = out_idx - - # 释放扁平数组 - mb.free(file_sha1s_buf) - mb.free(file_deps_buf) - mb.free(file_dep_counts) - mb.free(file_indegrees) - mb.free(file_processed) - - return 0 +import t, c +from stdint import * +import string +import stdlib +import memhub +import viperlib +import w32.fileio as fileio +import w32.win32file +import w32.win32base +import ast +import llvmlite +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HandlesTranslator +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.IncludesScanner as IncludesScanner +import lib.core.StubMerger as StubMerger +import lib.core.Gen.Generator as GenGenerator +import lib.core.CompilerFactory as CompilerFactory +import lib.core.BuildPipeline as BuildPipeline +import lib.Projectrans.Config as Config +import lib.StubGen.Converter as StubConverter +import lib.core.StubMergerBuild as StubMergerBuild +import lib.core.StubMergerCollect as StubMergerCollect +import lib.core.StubMergerIR as StubMergerIR +import lib.core.StubMergerStore as StubMergerStore + + +import lib.core.Phase1Scan as Phase1Scan +import lib.core.Phase1Main as Phase1Main +import lib.core.Phase1 as Phase1 + +# ============================================================ +# Phase1Topo - Phase1 拆分(阶段 E):Phase1Topo +# +# 直接移动模式:函数迁至此模块,原 Phase1.vp 仅保留常量/_mbuddy; +# 调用方经本模块前缀访问。全局符号经 Phase1._xxx 跨模块访问。 +# ============================================================ + +# ============================================================ +# _TopoSortFiles - 根据类继承关系对文件进行拓扑排序 +# +# 算法(Kahn): +# 1. 从扁平类信息数组构建"文件 SHA1 → 依赖文件 SHA1 集合"映射 +# 2. 计算每个文件的入度(依赖数量) +# 3. 入度为 0 的文件先处理,处理后减少依赖它的文件入度 +# 4. 重复直到所有文件处理完成 +# +# 注意:依赖方向是"父类所在文件 → 子类所在文件", +# 即父类文件必须先处理。Kahn 用 DepCount 作为剩余依赖计数, +# 依赖为 0 的先处理,初始化 InDegree = DepCount。 +# +# Args: +# mb: 内存池 +# result: IncludesScanner 扫描结果 +# reachable_set: 可达 SHA1 集合 +# reachable_count: 可达 SHA1 数量 +# use_reachable: 是否使用可达集合过滤 +# sha1_set: SHA1 集合 +# set_count: SHA1 集合数量 +# class_names_buf: 类名扁平数组 +# parent_names_buf: 父类名扁平数组 +# def_sha1s_buf: 定义 SHA1 扁平数组 +# class_count: 类数量 +# out_order: 输出拓扑顺序的文件索引数组(调用者分配,int 数组) +# out_count: 输出文件数量 +# +# Returns: +# 0 成功,-1 失败 +# ============================================================ +def _TopoSortFiles(mb: memhub.MemBuddy | t.CPtr, + result: IncludesScanner.ScanResult | t.CPtr, + reachable_set: str, reachable_count: int, + use_reachable: int, + sha1_set: str, set_count: int, + class_names_buf: bytes, parent_names_buf: bytes, + def_sha1s_buf: bytes, class_count: int, + out_order: t.CPtr, out_count: t.CPtr, + temp_dir: str, td_len_ts: t.CSizeT) -> int: + """根据类继承关系对文件进行拓扑排序""" + if result is None or out_order is None or out_count is None: + return -1 + + entry_size: t.CSizeT = IncludesScanner.FileEntry.__sizeof__() + + # 1. 分配扁平数组:文件 SHA1、依赖 SHA1 列表、依赖数量、入度、处理状态 + # 用扁平数组代替 FileDepEntry 结构体,避免 str 指针字段 NULL 崩溃 + file_sha1s_buf: bytes = mb.alloc(Phase1.MAX_FILE_DEPS * Phase1.SHA1_LEN) + file_deps_buf: bytes = mb.alloc(Phase1.MAX_FILE_DEPS * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN) + file_dep_counts: t.CPtr = mb.alloc(Phase1.MAX_FILE_DEPS * 4) + file_indegrees: t.CPtr = mb.alloc(Phase1.MAX_FILE_DEPS * 4) + file_processed: t.CPtr = mb.alloc(Phase1.MAX_FILE_DEPS * 4) + + if file_sha1s_buf is None or file_deps_buf is None or file_dep_counts is None or file_indegrees is None or file_processed is None: + if file_sha1s_buf is not None: + mb.free(file_sha1s_buf) + if file_deps_buf is not None: + mb.free(file_deps_buf) + if file_dep_counts is not None: + mb.free(file_dep_counts) + if file_indegrees is not None: + mb.free(file_indegrees) + if file_processed is not None: + mb.free(file_processed) + return -1 + + string.memset(file_sha1s_buf, 0, Phase1.MAX_FILE_DEPS * Phase1.SHA1_LEN) + string.memset(file_deps_buf, 0, Phase1.MAX_FILE_DEPS * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN) + string.memset(file_dep_counts, 0, Phase1.MAX_FILE_DEPS * 4) + string.memset(file_indegrees, 0, Phase1.MAX_FILE_DEPS * 4) + string.memset(file_processed, 0, Phase1.MAX_FILE_DEPS * 4) + + file_count: int = 0 + # sha1→file_index 映射(简单线性查找,文件数不多) + for i in range(result.Count): + entry_addr: t.CUInt64T = t.CUInt64T(result.Entries) + i * entry_size + entry: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + if entry is None or entry.Sha1 is None: + continue + + sha1_e: str = entry.Sha1 + in_set: int = 0 + if use_reachable != 0: + in_set = StubMergerCollect._is_in_sha1_set(sha1_e, reachable_set, reachable_count) + else: + in_set = StubMergerCollect._is_in_sha1_set(sha1_e, sha1_set, set_count) + if in_set == 0: + continue + + if file_count >= Phase1.MAX_FILE_DEPS: + break + + # 初始化扁平数组:文件 SHA1(偏移 = file_count * Phase1.SHA1_LEN) + # DepCount/InDegree/Processed 已由 memset 清零 + sha1_dst: str = file_sha1s_buf + file_count * Phase1.SHA1_LEN + string.strcpy(sha1_dst, sha1_e) + + file_count += 1 + + # 2. 构建依赖边:对每个类,找到父类定义所在文件,建立 子文件→父文件 依赖 + for ci in range(class_count): + # 读取父类名(偏移 = ci * Phase1.CLASS_NAME_LEN) + parent_ptr: str = parent_names_buf + ci * Phase1.CLASS_NAME_LEN + if parent_ptr[0] == '\0': + continue + + # 读取子类定义 SHA1(偏移 = ci * Phase1.SHA1_LEN) + child_def_sha1: str = def_sha1s_buf + ci * Phase1.SHA1_LEN + + # 查找父类定义所在文件的 SHA1 + parent_sha1: str = Phase1Scan._FindClassDefSha1(class_names_buf, def_sha1s_buf, class_count, parent_ptr) + if parent_sha1 is None: + continue # 父类不在 includes 中(如 Object、CEnum 等标记基类) + + # 父类文件 SHA1 不能等于子类文件 SHA1(同文件内继承不需要依赖) + if string.strcmp(parent_sha1, child_def_sha1) == 0: + continue + + # 找到子类文件对应的索引,添加父文件 SHA1 到依赖列表 + for fi in range(file_count): + fsha1: str = file_sha1s_buf + fi * Phase1.SHA1_LEN + if string.strcmp(fsha1, child_def_sha1) != 0: + continue + + # 读取当前依赖数量 + cnt_addr: t.CUInt64T = t.CUInt64T(file_dep_counts) + fi * 4 + cnt_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(cnt_addr, t.CPtr)) + if cnt_ptr is None: + break + cur_cnt: int = cnt_ptr[0] + + # 检查依赖是否已添加(去重) + already: int = 0 + for di in range(cur_cnt): + dep_slot: str = file_deps_buf + fi * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN + di * Phase1.SHA1_LEN + if string.strcmp(dep_slot, parent_sha1) == 0: + already = 1 + break + if already != 0: + break + + if cur_cnt < Phase1.MAX_DEP_EDGES: + dep_dst: str = file_deps_buf + fi * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN + cur_cnt * Phase1.SHA1_LEN + string.strcpy(dep_dst, parent_sha1) + cnt_ptr[0] = cur_cnt + 1 + break + + # 2.5 补充 import 依赖边:被 import 的模块先完整翻译。 + # + # 仅按类继承建边不够:跨模块全局变量 stub(lexer.vp from-import + # tokens.vp 的 _op_head)、跨模块 vtable TypeStr(astaux 继承 base 的 + # AST)、泛型模板(base.vp 用 list[...])都要求依赖模块先翻译,而它们 + # 之间可能无类继承关系。deps(_includes_deps_*)由 Phase 1a-pre 填充 + # (含容器按需注入的 _list/_dict)。 + # + # 用 _BuildIncludesSha1Map 复制局部 sha1→模块名 数组(与 + # _BuildReachableSha1Set 的 BFS 一致),避免直接使用全局 store 返回值 + # 跨函数传参(bytes|t.CPtr 联合转 str 参数)的地址异常。 + sha1_arr_ts: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 17) + mod_arr_ts: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 64) + map_count_ts: int = 0 + if sha1_arr_ts is not None and mod_arr_ts is not None: + map_count_ts = StubMergerIR._BuildIncludesSha1Map( + temp_dir, td_len_ts, sha1_arr_ts, mod_arr_ts) + for fi_imp in range(file_count): + if map_count_ts <= 0: + break + fsha1_imp: str = file_sha1s_buf + fi_imp * Phase1.SHA1_LEN + deps_imp: str = StubMergerStore.LookupIncludesDeps(fsha1_imp) + if deps_imp is None: + continue + dl_imp: t.CSizeT = string.strlen(deps_imp) + dpos_imp: t.CSizeT = 0 + while dpos_imp < dl_imp: + dstart_imp: t.CSizeT = dpos_imp + while dpos_imp < dl_imp and deps_imp[dpos_imp] != ' ': + dpos_imp += 1 + dlen_imp: t.CSizeT = dpos_imp - dstart_imp + if dpos_imp < dl_imp: + dpos_imp += 1 + if dlen_imp == 0: + continue + dname_imp: bytes = stdlib.malloc(dlen_imp + 1) + if dname_imp is None: + continue + string.strncpy(dname_imp, deps_imp + dstart_imp, dlen_imp) + dname_imp[dlen_imp] = '\0' + dsha1_imp: str = StubMergerIR._FindSha1ByModName( + sha1_arr_ts, mod_arr_ts, map_count_ts, dname_imp) + stdlib.free(dname_imp) + if dsha1_imp is None: + continue + # 找依赖文件在列表中的索引(跳过自身) + for fj_imp in range(file_count): + if string.strcmp(file_sha1s_buf + fj_imp * Phase1.SHA1_LEN, dsha1_imp) != 0: + continue + if fj_imp == fi_imp: + break + # 去重 + 加边:fi_imp 依赖 fj_imp(InDegree[fi_imp]++) + cnt_addr_imp: t.CUInt64T = t.CUInt64T(file_dep_counts) + fi_imp * 4 + cnt_ptr_imp: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(cnt_addr_imp, t.CPtr)) + if cnt_ptr_imp is None: + break + cur_cnt_imp: int = cnt_ptr_imp[0] + already_imp: int = 0 + for di_imp in range(cur_cnt_imp): + dep_slot_imp: str = file_deps_buf + fi_imp * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN + di_imp * Phase1.SHA1_LEN + if string.strcmp(dep_slot_imp, dsha1_imp) == 0: + already_imp = 1 + break + if already_imp == 0 and cur_cnt_imp < Phase1.MAX_DEP_EDGES: + dep_dst_imp: str = file_deps_buf + fi_imp * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN + cur_cnt_imp * Phase1.SHA1_LEN + string.strcpy(dep_dst_imp, dsha1_imp) + cnt_ptr_imp[0] = cur_cnt_imp + 1 + break + + # 释放 import 边用的局部映射数组 + if sha1_arr_ts is not None: + stdlib.free(sha1_arr_ts) + if mod_arr_ts is not None: + stdlib.free(mod_arr_ts) + + # 3. Kahn 算法:InDegree = DepCount(依赖多少个父文件) + # 依赖为 0 的先处理,处理后减少依赖它的文件入度 + for fi in range(file_count): + cnt_addr3: t.CUInt64T = t.CUInt64T(file_dep_counts) + fi * 4 + cnt_ptr3: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(cnt_addr3, t.CPtr)) + ind_addr3: t.CUInt64T = t.CUInt64T(file_indegrees) + fi * 4 + ind_ptr3: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(ind_addr3, t.CPtr)) + if cnt_ptr3 is not None and ind_ptr3 is not None: + ind_ptr3[0] = cnt_ptr3[0] + + # 4. 拓扑排序输出 + out_idx: int = 0 + changed: int = 1 + while changed != 0: + changed = 0 + for fi in range(file_count): + # 检查处理状态 + proc_addr4: t.CUInt64T = t.CUInt64T(file_processed) + fi * 4 + proc_ptr4: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(proc_addr4, t.CPtr)) + if proc_ptr4 is None or proc_ptr4[0] != 0: + continue + # 检查入度 + ind_addr4: t.CUInt64T = t.CUInt64T(file_indegrees) + fi * 4 + ind_ptr4: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(ind_addr4, t.CPtr)) + if ind_ptr4 is None or ind_ptr4[0] > 0: + continue + + # 入度为 0,可以处理 + # 找到对应的 result.Entries 索引 + target_sha1: str = file_sha1s_buf + fi * Phase1.SHA1_LEN + for ri in range(result.Count): + ea_r: t.CUInt64T = t.CUInt64T(result.Entries) + ri * entry_size + ent_r: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea_r, t.CPtr)) + if ent_r is not None and ent_r.Sha1 is not None: + if string.strcmp(ent_r.Sha1, target_sha1) == 0: + # 写入输出索引数组 + out_idx_addr: t.CUInt64T = t.CUInt64T(out_order) + out_idx * 4 + out_int_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(out_idx_addr, t.CPtr)) + if out_int_ptr is not None: + out_int_ptr[0] = ri + out_idx += 1 + break + + # 标记已处理 + proc_ptr4[0] = 1 + changed = 1 + + # 减少依赖该文件的其他文件的入度 + for fj in range(file_count): + proc_addr5: t.CUInt64T = t.CUInt64T(file_processed) + fj * 4 + proc_ptr5: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(proc_addr5, t.CPtr)) + if proc_ptr5 is None or proc_ptr5[0] != 0: + continue + # 读取 fj 的依赖数量 + cnt_addr5: t.CUInt64T = t.CUInt64T(file_dep_counts) + fj * 4 + cnt_ptr5: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(cnt_addr5, t.CPtr)) + if cnt_ptr5 is None: + continue + fj_dep_cnt: int = cnt_ptr5[0] + for di in range(fj_dep_cnt): + dep_slot5: str = file_deps_buf + fj * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN + di * Phase1.SHA1_LEN + if string.strcmp(dep_slot5, target_sha1) == 0: + ind_addr5: t.CUInt64T = t.CUInt64T(file_indegrees) + fj * 4 + ind_ptr5: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(ind_addr5, t.CPtr)) + if ind_ptr5 is not None: + ind_ptr5[0] = ind_ptr5[0] - 1 + break + + # 处理循环依赖:环内优先输出"被依赖者"(被其余剩余文件依赖数量多者先)。 + # + # 背景:容器按需注入(string 用 list 泛型 → 依赖 _list)与真实 import + # (_list import string)形成伪环,Kahn 无法完全归零。若按扫描顺序追加, + # 依赖者(astaux)会先于被依赖者(base)翻译 → 跨模块 vtable TypeStr + # 未注册 → 误杀。被依赖者先翻译,其 stub/TypeStr/模板先就绪,依赖者 + # 翻译时可引用(函数/全局声明由 1a-pre 的 vpi 兜底)。 + if out_idx < file_count: + rem_idx: t.CPtr = stdlib.malloc(4 * file_count) + rem_depcnt: t.CPtr = stdlib.malloc(4 * file_count) + rem_count: int = 0 + if rem_idx is not None and rem_depcnt is not None: + for fi in range(file_count): + proc_addr7: t.CUInt64T = t.CUInt64T(file_processed) + fi * 4 + proc_ptr7: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(proc_addr7, t.CPtr)) + if proc_ptr7 is not None and proc_ptr7[0] == 0: + rem_idx[rem_count] = fi + rem_depcnt[rem_count] = 0 + rem_count += 1 + # 计算每个剩余文件的被依赖数(被其余剩余文件依赖) + for i_a in range(rem_count): + fi_a: int = rem_idx[i_a] + target_sha1_a: str = file_sha1s_buf + fi_a * Phase1.SHA1_LEN + for i_b in range(rem_count): + fi_b: int = rem_idx[i_b] + if fi_b == fi_a: + continue + cnt_addr_b: t.CUInt64T = t.CUInt64T(file_dep_counts) + fi_b * 4 + cnt_ptr_b: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(cnt_addr_b, t.CPtr)) + if cnt_ptr_b is None: + continue + cnt_b: int = cnt_ptr_b[0] + for di_b in range(cnt_b): + dep_slot_b: str = file_deps_buf + fi_b * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN + di_b * Phase1.SHA1_LEN + if string.strcmp(dep_slot_b, target_sha1_a) == 0: + rem_depcnt[i_a] = rem_depcnt[i_a] + 1 + break + # 冒泡降序(被依赖数多者在前) + for i_a in range(rem_count): + for j_a in range(rem_count - 1): + if rem_depcnt[j_a] < rem_depcnt[j_a + 1]: + tmp_i: int = rem_idx[j_a] + rem_idx[j_a] = rem_idx[j_a + 1] + rem_idx[j_a + 1] = tmp_i + tmp_d: int = rem_depcnt[j_a] + rem_depcnt[j_a] = rem_depcnt[j_a + 1] + rem_depcnt[j_a + 1] = tmp_d + # 按序输出剩余文件 + for i_a in range(rem_count): + fi_a2: int = rem_idx[i_a] + proc_addr8: t.CUInt64T = t.CUInt64T(file_processed) + fi_a2 * 4 + proc_ptr8: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(proc_addr8, t.CPtr)) + if proc_ptr8 is None or proc_ptr8[0] != 0: + continue + target_sha1_2: str = file_sha1s_buf + fi_a2 * Phase1.SHA1_LEN + for ri in range(result.Count): + ea_r2: t.CUInt64T = t.CUInt64T(result.Entries) + ri * entry_size + ent_r2: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea_r2, t.CPtr)) + if ent_r2 is not None and ent_r2.Sha1 is not None: + if string.strcmp(ent_r2.Sha1, target_sha1_2) == 0: + out_idx_addr2: t.CUInt64T = t.CUInt64T(out_order) + out_idx * 4 + out_int_ptr2: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(out_idx_addr2, t.CPtr)) + if out_int_ptr2 is not None: + out_int_ptr2[0] = ri + out_idx += 1 + break + proc_ptr8[0] = 1 + stdlib.free(rem_idx) + stdlib.free(rem_depcnt) + + # 写入输出数量 + out_count_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(out_count, t.CPtr)) + if out_count_ptr is not None: + out_count_ptr[0] = out_idx + + # 释放扁平数组 + mb.free(file_sha1s_buf) + mb.free(file_deps_buf) + mb.free(file_dep_counts) + mb.free(file_indegrees) + mb.free(file_processed) + + return 0 diff --git a/App/lib/core/Phase2.vp b/App/lib/core/Phase2.vp index 4bbed38..a34c7fc 100644 --- a/App/lib/core/Phase2.vp +++ b/App/lib/core/Phase2.vp @@ -1,1289 +1,1285 @@ -import t, c -from stdint import * -import stdio -import string -import stdlib -import memhub -import viperlib -import w32.fileio as fileio -import w32.win32file -import w32.win32base -import sys -import ast -import llvmlite -import subprocess -import argparse -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HandlesTranslator -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesType as HandlesType -import lib.core.BuildPipeline as BuildPipeline -import lib.core.IncludesScanner as IncludesScanner -import lib.core.CompilerFactory as CompilerFactory -import lib.core.StubMerger as StubMerger -import lib.Projectrans.Utils as Utils -import lib.Projectrans.Config as Config -import lib.core.StubMergerBuild as StubMergerBuild -import lib.core.StubMergerCollect as StubMergerCollect -import lib.core.StubMergerIR as StubMergerIR -import lib.core.StubMergerStore as StubMergerStore -import lib.core.StubMergerTopo as StubMergerTopo -import lib.core.Handles.ExprCallCtor as ExprCallCtor - -# 全局 mbuddy 指针 -_mbuddy: memhub.MemBuddy | t.CPtr - -# 源代码缓冲区大小(1MB) -SRC_BUF_SIZE: t.CDefine = 1048576 - -# 最大源文件数(递归扫描子目录后文件数增多:App 现有 65 个 .vp, -# 2026-08-14 CompilerFactory.vp 加入后超出 64 被截断 → 链接 undefined symbol -# CompilerFactory.get_perm_pool。增大到 128 留余量) -MAX_SRC_FILES: t.CDefine = 128 - -# 全局栈金丝雀(避免局部变量改变栈布局) -_g_canary: t.CUInt32T - - -@t.NoVTable -class SrcFileEntry: - """源文件条目""" - Path: str # 完整路径 - Sha1: str # SHA1 前16字符 - - -# ============================================================ -# _ScanDirForPyFiles - 递归扫描目录,收集 .vp/.py 文件到 entries -# -# 替代旧的非递归 FindFirstFileA(dir/*.py) 扫描,支持子目录 -# (如 App/lib/core/Handles/)。遇到目录递归扫描,遇到 .vp/.py -# 文件读取内容、计算 SHA1、加入 entries。 -# -# Args: -# mb: 内存池 -# dir_path: 当前扫描目录 -# entries: SrcFileEntry 数组 -# entry_size: 单个条目大小(SrcFileEntry.__sizeof__()) -# file_count: 当前已收集的文件数 -# max_files: 最大文件数 -# -# Returns: -# 新的 file_count -# ============================================================ -def _ScanDirForPyFiles(mb: memhub.MemBuddy | t.CPtr, - dir_path: str, - entries: SrcFileEntry | t.CPtr, - entry_size: t.CSizeT, - file_count: int, max_files: int) -> int: - """递归扫描目录,收集 .vp/.py 文件到 entries,返回新的 file_count""" - if dir_path is None or entries is None: - return file_count - if file_count >= max_files: - return file_count - - dir_len: t.CSizeT = string.strlen(dir_path) - pattern: bytes = stdlib.malloc(dir_len + 16) - if pattern is None: - return file_count - viperlib.snprintf(pattern, dir_len + 16, "%s/*", dir_path) - - find_data_size: t.CSizeT = w32.win32file.WIN32_FIND_DATAA.__sizeof__() - find_data: w32.win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(find_data_size + 16) - if find_data is None: - stdlib.free(pattern) - return file_count - string.memset(find_data, 0, find_data_size + 16) - - handle: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(pattern, find_data) - if handle == w32.win32base.INVALID_HANDLE_VALUE: - stdlib.free(pattern) - stdlib.free(find_data) - return file_count - - while True: - fname: str = find_data.cFileName - if fname is None: - if w32.win32file.FindNextFileA(handle, find_data) == 0: - break - continue - fname_len: t.CSizeT = string.strlen(fname) - if fname_len <= 0: - if w32.win32file.FindNextFileA(handle, find_data) == 0: - break - continue - # 跳过 . 和 .. - is_dot: int = 0 - if fname_len == 1 and fname[0] == '.': - is_dot = 1 - elif fname_len == 2 and fname[0] == '.' and fname[1] == '.': - is_dot = 1 - if is_dot != 0: - if w32.win32file.FindNextFileA(handle, find_data) == 0: - break - continue - # 检查是否是目录 - attrs: ULONG = find_data.dwFileAttributes - is_dir: int = 0 - if (attrs & w32.win32file.FILE_ATTRIBUTE_DIRECTORY) != 0: - is_dir = 1 - if is_dir != 0: - # 递归扫描子目录 - sub_dir: bytes = Utils.JoinPath(dir_path, fname) - if sub_dir is not None: - file_count = _ScanDirForPyFiles(mb, sub_dir, entries, entry_size, file_count, max_files) - stdlib.free(sub_dir) - if w32.win32file.FindNextFileA(handle, find_data) == 0: - break - continue - # 检查是否是 .vp 或 .py 文件(.vp 为 Viper 源,.py 向后兼容) - if fname_len > 3 and Utils.is_vp_or_py_at(fname, 0, fname_len) != 0 \ - and file_count < max_files: - full_path: bytes = Utils.JoinPath(dir_path, fname) - if full_path is not None: - sbuf: bytes = Utils.read_file_to_buf(full_path, SRC_BUF_SIZE) - if sbuf is None: - if w32.win32file.FindNextFileA(handle, find_data) == 0: - break - continue - # 统一用 IncludesScanner.compute_file_sha1(CRLF→LF 归一化), - # 与 StubMerger.vp:1510 对同一批 App 源文件的口径一致; - # 此前用 Utils.compute_sha1(原始字节)会导致 stub/define - # 符号前缀不一致 → 链接报 undefined reference。 - sha1_val: str = IncludesScanner.compute_file_sha1(mb, full_path) - if sha1_val is not None: - ea: t.CUInt64T = t.CUInt64T(entries) + file_count * entry_size - ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr)) - if ent is not None: - ent.Path = full_path - ent.Sha1 = sha1_val - file_count += 1 - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "%s (sha1=%s)", fname, sha1_val) - VLogger.info(fb, "project") - stdlib.free(sbuf) - # full_path 不释放:ent.Path 引用它 - - if w32.win32file.FindNextFileA(handle, find_data) == 0: - break - - w32.win32file.FindClose(handle) - stdlib.free(pattern) - stdlib.free(find_data) - return file_count - - -# ============================================================ -# _PreRegisterAppGenericTemplates - mark2 前预注册 App 源文件泛型类模板 -# -# 与 Phase1 的 includes 全量预注册同理:泛型模板表(GenericClassNames 等 -# 4 张 + 模板节点)是 pool 懒分配的跨文件持久表,若在 mark2 之后 -# (Phase A-pre 翻译 App 文件时)才首次注册,reset_to(mark2) 会回收表与 -# 节点 → 后续查重/特化遍历悬空内存崩溃。App 文件数量少,mark2 前预注册 -# 产生的 AST 驻留内存可忽略。重复注册由 _register_generic_template 查重跳过。 -# ============================================================ -def _PreRegisterAppGenericTemplates(mb: memhub.MemBuddy | t.CPtr, - entries: SrcFileEntry | t.CPtr, - file_count: int, - entry_size: t.CSizeT) -> int: - """mark2 前预注册 App 源文件的泛型类模板,返回处理到的泛型类数量""" - if mb is None or entries is None or file_count <= 0: - return 0 - handled: int = 0 - for i in range(file_count): - ea_pa: t.CUInt64T = t.CUInt64T(entries) + i * entry_size - ent_pa: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_pa, t.CPtr)) - if ent_pa is None or ent_pa.Path is None or ent_pa.Sha1 is None: - continue - # 读取文件 - f_pa: fileio.File | t.CPtr = fileio.File(ent_pa.Path, fileio.MODE.R) - if f_pa.closed: - continue - src_buf_pa: bytes = stdlib.malloc(SRC_BUF_SIZE) - if src_buf_pa is None: - f_pa.close() - continue - bytes_read_pa: LONG = f_pa.read_all(src_buf_pa, SRC_BUF_SIZE) - f_pa.close() - if bytes_read_pa <= 0: - stdlib.free(src_buf_pa) - continue - if bytes_read_pa < SRC_BUF_SIZE: - src_buf_pa[bytes_read_pa] = 0 - else: - src_buf_pa[SRC_BUF_SIZE - 1] = 0 - # 解析 AST(只解析,不完整翻译;用永久池使模板节点跨 mark2 reset 存活) - perm_pa: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool() - if perm_pa is None: - perm_pa = mb - lx_pa: ast.Lexer | t.CPtr = ast.new_lexer(perm_pa) - if lx_pa is None: - stdlib.free(src_buf_pa) - continue - ast._lexer_init(lx_pa, src_buf_pa, perm_pa) - tokens_pa: ast.Token | t.CPtr = ast.tokenize(lx_pa) - tree_pa: ast.AST | t.CPtr = ast.parse_tokens(perm_pa, tokens_pa) - if tree_pa is None: - stdlib.free(src_buf_pa) - continue - # 遍历顶层 ClassDef,注册泛型模板(type_params 非 None) - ch_pa: list[ast.AST | t.CPtr] | t.CPtr = tree_pa.children - if ch_pa is not None: - cn_pa: t.CSizeT = len(ch_pa) - for ci_pa in range(cn_pa): - child_pa: ast.AST | t.CPtr = ch_pa.get(ci_pa) - if child_pa is None or child_pa.kind() != ast.ASTKind.ClassDef: - continue - cd_pa: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child_pa) - if cd_pa is None or cd_pa.name is None: - continue - tp_pa: list[str] | t.CPtr = cd_pa.type_params - if tp_pa is None: - continue - HandlesType.set_current_file(ent_pa.Path) - HandlesClassDef._register_generic_template(perm_pa, cd_pa, ent_pa.Sha1) - handled += 1 - stdlib.free(src_buf_pa) - if handled > 0: - fb_pg3: str = VLogger.fmt_buf() - if fb_pg3 is not None: - viperlib.snprintf(fb_pg3, 1024, "mark2 前预注册 %d 个 App 泛型类模板", handled) - VLogger.info(fb_pg3, "PhaseA") - return handled - - -def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, - source_dir: str, temp_dir: str, output_dir: str, - cc_cmd: str, cc_flags: str, - linker_cmd: str, linker_flags: str, linker_output: str, - includes_binary_dir: str, - includes_dir: str, - do_phase1: int, do_phase2: int, - log: VLogger.Logger | t.CPtr, - args: argparse.ParsedArgs | t.CPtr) -> int: - """多文件项目编译 - - Returns: 0 成功,非 0 失败 - """ - if source_dir is None: - VLogger.error("source_dir 为空", "project") - return 1 - - # === 栈金丝雀检查(全局变量,不影响栈布局)=== - global _g_canary - _g_canary = 305419896 - - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "多文件项目编译: %s", source_dir) - VLogger.info(fb, "project") - - # === 1. 递归扫描 source_dir 下的 .vp/.py 文件(包括子目录)=== - entry_size: t.CSizeT = SrcFileEntry.__sizeof__() - entries: SrcFileEntry | t.CPtr = stdlib.malloc(MAX_SRC_FILES * entry_size) - if entries is None: - return 1 - string.memset(entries, 0, MAX_SRC_FILES * entry_size) - - file_count: int = _ScanDirForPyFiles(mb, source_dir, entries, entry_size, 0, MAX_SRC_FILES) - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "共 %d 个源文件", file_count) - VLogger.info(fb, "project") - - if file_count == 0: - stdlib.free(entries) - return 1 - - # 初始化 AST 表 - ast._init_tables(mb) - - # mark2 之前预注册 App 源文件的泛型类模板:泛型模板表/节点是 pool 懒分配, - # 必须在 mark2 之前注册才能跨 reset_to(mark2) 存活(与 Phase1 的 includes - # 全量预注册同理),否则 Phase A-pre 首次注册后 reset 回收 → 后续查重/特化 - # 遍历悬空内存崩溃(1.log FuncTest ASAN access-violation 同类根因)。 - _PreRegisterAppGenericTemplates(mb, entries, file_count, entry_size) - - # OOM 清理(对齐 Phase1 1b 的 mark1/reset_to 模式): - # Phase2 的 includes 预注册(Phase A-pre-inc)、App 源文件预注册(Phase A-pre)、 - # App 全量翻译(Phase A)、缺失 includes 翻译(Phase B+)都会产生大量瞬时数据 - # (AST/tokens/lexer/IR/Handler/dump 临时)。无回收时 98 个 includes 的 AST/IR - # 全量累积 pool → 1GB OOM(NewAstTest 依赖 ast 模块场景)。 - # 此处打 mark2,各处翻译完成后 reset_to(mark2) 回收该文件瞬时数据; - # 跨文件持久表(struct/enum/docstring/CDefine/函数注册表等)已 stdlib 化 - # 或落在 mark2 之前,reset 不受影响(与 Phase1 1b 同翻译路径,已验证安全)。 - mark2: t.CSizeT = mb.mark() - # mark2 之后新注册的 struct/enum 条目改 stdlib 分配(跨 reset 存活,对齐 Phase1) - HandlesStruct.set_stdlib_alloc(1) - - # 确保 temp/output 目录存在 - BuildPipeline.ensure_dir(temp_dir) - BuildPipeline.ensure_dir(output_dir) - - # === 0.5 扫描 includes 目录填充 Sha1Store(消除 Phase1 依赖)=== - # Phase2 不依赖 Phase1 的副作用:如果 Sha1Store 为空(Phase1 未运行或提前返回), - # 自行扫描 includes 目录并填充 Sha1Store,确保后续"编译缺失 includes"逻辑能正常工作 - if includes_dir is not None: - if StubMergerStore.GetSha1StoreCount() == 0: - inc_scan_result: IncludesScanner.ScanResult | t.CPtr = IncludesScanner.scan_includes(mb, includes_dir) - if inc_scan_result is None: - VLogger.error("includes 扫描失败,无法填充 Sha1Store", "project") - if inc_scan_result is not None: - inc_filled: int = StubMergerStore.PopulateSha1MapStore(inc_scan_result) - fb_inc: str = VLogger.fmt_buf() - if fb_inc is not None: - viperlib.snprintf(fb_inc, 1024, "Phase2 自主填充 includes Sha1Store: %d 个", inc_filled) - VLogger.info(fb_inc, "project") - - # 追加 App 源文件 SHA1 到 _sha1_map.txt(人类可读输出,程序内部不读取此文件) - # 格式: {sha1}:{rel_path}\n (保留目录结构,如 lib/core/VLogger.vp) - # 同步追加到内存存储器(AppendToSha1MapStore,供跨模块 CDefine 查找) - td_len_am: t.CSizeT = string.strlen(temp_dir) - src_dir_len_am: t.CSizeT = string.strlen(source_dir) - map_path_am: bytes = stdlib.malloc(td_len_am + 32) - if map_path_am is not None: - viperlib.snprintf(map_path_am, td_len_am + 32, "%s/_sha1_map.txt", temp_dir) - mf: fileio.File | t.CPtr = fileio.File(map_path_am, fileio.MODE.A) - line_am: bytes = stdlib.malloc(512) - # 先遍历一次填充内存存储器(不依赖文件 I/O),再写入 _sha1_map.txt - app_filled: int = 0 - for i in range(file_count): - ea_am: t.CUInt64T = t.CUInt64T(entries) + i * entry_size - ent_am: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_am, t.CPtr)) - if ent_am is None or ent_am.Path is None or ent_am.Sha1 is None: - continue - # 计算相对路径(去除 source_dir 前缀,保留目录结构) - p_str: str = ent_am.Path - p_len: t.CSizeT = string.strlen(p_str) - rel_path_am: str = p_str - if p_len > src_dir_len_am + 1: - if string.strncmp(p_str, source_dir, src_dir_len_am) == 0: - rel_path_am = p_str + src_dir_len_am + 1 - # 同步追加到内存存储器(供跨模块 CDefine 查找) - # rel_path_am 格式如 "lib/core/StubMerger.vp",与 _sha1_map.txt 一致 - if StubMergerStore.AppendToSha1MapStore(ent_am.Sha1, rel_path_am) != 0: - fb_apf: str = VLogger.fmt_buf() - if fb_apf is not None: - viperlib.snprintf(fb_apf, 1024, "AppendToSha1MapStore 失败: %s", rel_path_am) - VLogger.error(fb_apf, "project") - app_filled += 1 - # 写入 _sha1_map.txt(人类可读输出) - if not mf.closed and line_am is not None: - viperlib.snprintf(line_am, 512, "%s:%s\n", ent_am.Sha1, rel_path_am) - ll_am: t.CSizeT = string.strlen(line_am) - mf.write(line_am, ll_am) - if line_am is not None: - stdlib.free(line_am) - if not mf.closed: - mf.close() - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "已追加 %d 个 App 文件到 _sha1_map.txt 和内存存储器", app_filled) - VLogger.info(fb, "project") - stdlib.free(map_path_am) - - # 模块 SHA1 映射已由 PopulateSha1MapStore + AppendToSha1MapStore 统一填充到 - # StubMerger 全局存储器,HandlesExprCall._lookup_module_sha1 直接查全局存储器, - # 不再需要构建独立的 SHA1 映射表副本。 - - - # === 2. Phase A: 为每个文件生成 stub + text === - # app_deps_buf: 收集所有 App 源文件的直接依赖模块名(空格分隔) - # 供 Phase B+ 的 _BuildReachableSha1Set 作为初始 worklist,实现按需编译 - # 声明在 if 块外,确保 Phase B+ 和清理代码能访问 - # 65536 与 StubMerger.REACH_WORKLIST_BUF 对齐:全量 App imports 拼接 - # 超 8192(追加82 同源溢出),8192 会静默丢依赖致 Phase B+ 可达集合不全 - APP_DEPS_BUF_SIZE: t.CSizeT = 65536 - app_deps_buf: bytes = None - app_deps_len: t.CSizeT = 0 - if do_phase1 != 0: - if log is not None: - log.banner("Phase A: 生成 stub + text") - - # === Phase A-pre-inc: includes 预注册 struct + 依赖填充 === - # 必须在 App 源文件预注册之前执行:App 源文件(strict_mode=1)可能继承 - # 或引用 includes 中的 struct(如 ast.AST)。若 includes struct 未注册, - # App 源文件翻译会失败 → .obj 缺失 → undefined reference。 - # 同时填充 PopulateIncludesDeps,供 Phase B+ 的 _BuildReachableSha1Set 使用。 - # 多遍扫描:解决跨文件继承问题(如 Constant(AST) 在 AST 未注册时被跳过)。 - if includes_dir is not None and includes_binary_dir is not None: - store_count_inc_pre: int = StubMergerStore.GetSha1StoreCount() - if store_count_inc_pre > 0: - store_sha1_inc_pre: bytes | t.CPtr = StubMergerStore.GetSha1StoreArrPtr() - store_rel_inc_pre: bytes | t.CPtr = StubMergerStore.GetSha1StoreRelArrPtr() - store_incdir_inc_pre: bytes | t.CPtr = StubMergerStore.GetSha1StoreIncdirArrPtr() - deps_filled_pre: int = 0 - PHASE_A_INC_MAX_PASSES: t.CInt = 3 - # [修复] 记录预注册失败的 includes:多遍后仍失败 → 报错终止编译。 - # 不允许静默降级——静默失败会让 App 源文件的跨模块类构造退化为 - # 普通函数调用(返回类型默认推断成 i32),调用点报误导性的 - # "跨模块调用 'parser.add_argument' 找不到模块 SHA1" - # (如 argparse.ArgumentParser 类未注册导致 parser 变量类型崩坏)。 - # declare_only=1 时 import 的 SHA1 检查跳过(容忍依赖未注册), - # 因此预注册失败只可能是文件自身无法翻译(语法/解析/编译错误)。 - # 注意:Sha1Store 因 AppendToSha1MapStore 追加了 App 源文件 SHA1 - # (供跨模块 CDefine 查找),此处必须跳过 App 文件——App 文件的 - # 预注册由 Phase A-pre(遍历 entries,declare_only=1)负责。 - # App 文件是严格模式(仅本地+import 可见)且预注册阶段依赖未就绪, - # 若在此预注册必然失败,误报"预注册失败: main.vp"。 - inc_fail_flags: bytes = stdlib.malloc(store_count_inc_pre) - if inc_fail_flags is not None: - string.memset(inc_fail_flags, 1, store_count_inc_pre) - for pass_inc_i in range(PHASE_A_INC_MAX_PASSES): - struct_count_before_inc: int = HandlesStruct.get_struct_count() - for si_inc in range(store_count_inc_pre): - inc_sha1_pre: str = store_sha1_inc_pre + t.CSizeT(si_inc) * 17 - inc_rel_pre: str = store_rel_inc_pre + t.CSizeT(si_inc) * StubMerger.MAX_REL_PATH_LEN - if inc_rel_pre is None or inc_rel_pre[0] == '\0': - continue - # 跳过 App 源文件(main.vp 等):由 Phase A-pre 预注册,不算失败 - is_app_file_inc: int = 0 - for i_app_inc in range(file_count): - ea_app_inc: t.CUInt64T = t.CUInt64T(entries) + i_app_inc * entry_size - ent_app_inc: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_app_inc, t.CPtr)) - if ent_app_inc is not None and ent_app_inc.Sha1 is not None \ - and string.strcmp(ent_app_inc.Sha1, inc_sha1_pre) == 0: - is_app_file_inc = 1 - break - if is_app_file_inc != 0 and inc_fail_flags is not None: - inc_fail_flags[si_inc] = 0 - continue - rel_len_pre: t.CSizeT = string.strlen(inc_rel_pre) - # 所属 includes 根目录(多目录逐条取自 IncDir 数组,空串回退 includes_dir) - incdir_pre: str = store_incdir_inc_pre + t.CSizeT(si_inc) * StubMerger.MAX_INC_DIR_LEN - if incdir_pre is None or incdir_pre[0] == '\0': - incdir_pre = includes_dir - incdir_len_pre: t.CSizeT = string.strlen(incdir_pre) - full_path_pre: bytes = stdlib.malloc(incdir_len_pre + rel_len_pre + 2) - if full_path_pre is None: - continue - viperlib.snprintf(full_path_pre, incdir_len_pre + rel_len_pre + 2, - "%s/%s", incdir_pre, inc_rel_pre) - pkg_inc_pre: str = HandlesImports.compute_package_from_relpath(mb, inc_rel_pre) - tr_inc_pre: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans( - mb, full_path_pre, inc_sha1_pre, pkg_inc_pre, 1) - stdlib.free(full_path_pre) - if tr_inc_pre is not None: - # 预注册成功:清除失败标记 - if inc_fail_flags is not None: - inc_fail_flags[si_inc] = 0 - # 依赖填充只在第一遍执行(PopulateIncludesDeps 内部有去重) - # 注意:必须在 reset_to(mark2) 之前调用——内部深拷贝到 stdlib - if pass_inc_i == 0 and tr_inc_pre._imported_modules is not None \ - and StubMergerStore.PopulateIncludesDeps( - inc_sha1_pre, tr_inc_pre._imported_modules) == 0: - deps_filled_pre = deps_filled_pre + 1 - # OOM 清理:回收本 includes 文件预注册翻译的瞬时数据 - # (AST/tokens/lexer/IR/Handler);struct 注册表条目 stdlib 分配不受影响 - mb.reset_to(mark2) - struct_count_after_inc: int = HandlesStruct.get_struct_count() - # 收敛检查:本遍没有新结构体注册 → 所有类已注册 - if struct_count_after_inc == struct_count_before_inc: - break - # 多遍后仍预注册失败的 includes → 报错终止(不允许降级) - if inc_fail_flags is not None: - for si_inc_f in range(store_count_inc_pre): - if inc_fail_flags[si_inc_f] != 0: - rel_f: str = store_rel_inc_pre + t.CSizeT(si_inc_f) * StubMerger.MAX_REL_PATH_LEN - fb_inc_f: str = VLogger.fmt_buf() - if fb_inc_f is not None: - viperlib.snprintf(fb_inc_f, 1024, - "includes 预注册失败: %s(文件无法翻译,可能是语法/解析/编译错误),终止编译", - rel_f) - VLogger.error(fb_inc_f, "prePhaseA") - sys.exit(1) - stdlib.free(inc_fail_flags) - fb_inc_pre: str = VLogger.fmt_buf() - if fb_inc_pre is not None: - viperlib.snprintf(fb_inc_pre, 1024, "includes 预注册 + 依赖填充: %d/%d", deps_filled_pre, store_count_inc_pre) - VLogger.info(fb_inc_pre, "prePhaseA") - - # === Phase A-pre: 预注册所有源文件的 struct/enum/union === - # 解决循环引用问题:circ_a 翻译时需要知道 circ_b.ClassB 的 struct 定义 - # 仅注册 struct/enum/union(declare_only=1),不翻译方法体 - # 多遍扫描:解决跨文件继承的字母序问题(如 HandlesAnnAssign.vp/.py 在 HandlesBase.vp/.py 之前, - # AnnAssignHandle 继承 Mixin 时 Mixin 未注册)。每遍注册新类后,下一遍子类可继承。 - VLogger.info("预注册 struct/enum/union...", "PhaseA") - src_dir_len_pre: t.CSizeT = string.strlen(source_dir) - PHASE_A_PRE_MAX_PASSES: t.CInt = 3 - for pass_i in range(PHASE_A_PRE_MAX_PASSES): - struct_count_before: int = HandlesStruct.get_struct_count() - for i in range(file_count): - ea_pre: t.CUInt64T = t.CUInt64T(entries) + i * entry_size - ent_pre: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_pre, t.CPtr)) - if ent_pre is None or ent_pre.Path is None: - continue - pkg_pre: str = None - if string.strlen(ent_pre.Path) > src_dir_len_pre + 1: - rel_path_pre: str = ent_pre.Path + src_dir_len_pre + 1 - pkg_pre = HandlesImports.compute_package_from_relpath(mb, rel_path_pre) - tr_pre: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, ent_pre.Path, ent_pre.Sha1, pkg_pre, 1) - if tr_pre is None: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "预注册失败: %s", ent_pre.Path) - VLogger.error(fb, "PhaseA") - # OOM 清理:回收本 App 文件预注册翻译的瞬时数据 - mb.reset_to(mark2) - struct_count_after: int = HandlesStruct.get_struct_count() - # 收敛检查:本遍没有新结构体注册 → 所有类已注册 - if struct_count_after == struct_count_before: - break - VLogger.info("预注册完成", "PhaseA") - - PHASE_A_IR_SIZE: t.CSizeT = 1048576 - td_len_pa: t.CSizeT = string.strlen(temp_dir) - - # 设置 temp 目录路径,使 HandlesExprCall 能读取依赖模块的 text.ll - # 用于跨模块方法返回类型查找(避免指针返回值被截断为 i32) - ExprCallCtor.SetTempDir(temp_dir) - - # app_deps_buf: 收集所有 App 源文件的直接依赖模块名(空格分隔) - # 供 Phase B+ 的 _BuildReachableSha1Set 作为初始 worklist 使用 - # 声明已在 if 块外,此处仅赋值 - app_deps_buf = stdlib.malloc(APP_DEPS_BUF_SIZE) - app_deps_len = 0 - if app_deps_buf is not None: - app_deps_buf[0] = '\0' - - # Phase A 多遍重试:同项目多源文件时,main.vp 可能先于其 import 的 - # mbuddytest.vp 翻译(文件系统顺序),跨模块函数返回类型精确解析会因 - # 依赖 text.ll 未生成而标记 _deps_pending=1(见 CallGenMixin 跨模块 - # 返回类型解析段)。下遍重译即可命中(依赖已生成 text.ll)。 - # 每遍至少完成一个文件,最多 file_count 遍收敛。 - done_flags: bytes = stdlib.malloc(file_count) - if done_flags is None: - VLogger.error("Phase A done_flags 分配失败", "PhaseA") - stdlib.free(entries) - return 1 - string.memset(done_flags, 0, file_count) - PHASE_A_MAX_PASSES: t.CInt = 32 - for pass_a in range(PHASE_A_MAX_PASSES): - completed_this_pass: int = 0 - for i in range(file_count): - if done_flags[i] != 0: - continue - ea: t.CUInt64T = t.CUInt64T(entries) + i * entry_size - ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr)) - if ent is None or ent.Path is None: - done_flags[i] = 1 - completed_this_pass += 1 - continue - # 计算源文件的包名(相对 source_dir 的目录部分) - src_dir_len_pa: t.CSizeT = string.strlen(source_dir) - pkg_pa: str = None - if string.strlen(ent.Path) > src_dir_len_pa + 1: - rel_path_pa: str = ent.Path + src_dir_len_pa + 1 - pkg_pa = HandlesImports.compute_package_from_relpath(mb, rel_path_pa) - tr_a: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, ent.Path, ent.Sha1, pkg_pa, 0, temp_dir) - if tr_a is None: - # 翻译失败(语法/解析错误):记录待下遍重试,收敛检查统一报错 - # OOM 清理:失败翻译也已产生 AST/tokens 瞬时数据,立即回收 - mb.reset_to(mark2) - continue - # 收集 _imported_modules 到 app_deps_buf(供 Phase B+ 按需编译)。 - # 依赖在翻译早期已填充,即使 _deps_pending 也收集。 - if tr_a._imported_modules is not None and app_deps_buf is not None: - # 逐模块去重拼接:多个 App 文件 import 同一模块(builtins/ - # _list/_dict/stdlib/t/c 等公共依赖)会让 app_deps 无去重 - # 膨胀到接近 64KB,_BuildReachableSha1Set 的初始 worklist - # 即满 → BFS 展开必报"依赖 worklist 溢出"。 - im_len_a: t.CSizeT = string.strlen(tr_a._imported_modules) - im_pos_a: t.CSizeT = 0 - while im_pos_a < im_len_a: - im_start_a: t.CSizeT = im_pos_a - while im_pos_a < im_len_a and tr_a._imported_modules[im_pos_a] != ' ': - im_pos_a += 1 - im_mod_len: t.CSizeT = im_pos_a - im_start_a - if im_pos_a < im_len_a: - im_pos_a += 1 - if im_mod_len == 0: - continue - im_mod_buf: bytes = stdlib.malloc(im_mod_len + 1) - if im_mod_buf is None: - continue - string.strncpy(im_mod_buf, tr_a._imported_modules + im_start_a, im_mod_len) - im_mod_buf[im_mod_len] = '\0' - # 已在 app_deps 中则跳过(词边界精确匹配) - if app_deps_len > 0 and HandlesImports.is_module_imported(app_deps_buf, im_mod_buf) != 0: - stdlib.free(im_mod_buf) - continue - if app_deps_len + im_mod_len + 2 < APP_DEPS_BUF_SIZE: - if app_deps_len > 0: - app_deps_buf[app_deps_len] = ' ' - app_deps_len = app_deps_len + 1 - string.strcpy(app_deps_buf + app_deps_len, im_mod_buf) - app_deps_len = app_deps_len + im_mod_len - app_deps_buf[app_deps_len] = '\0' - stdlib.free(im_mod_buf) - if tr_a._deps_pending != 0: - # 依赖模块 text.ll 未生成(同项目文件顺序),不写盘,下遍重试 - fb_dp: str = VLogger.fmt_buf() - if fb_dp is not None: - viperlib.snprintf(fb_dp, 1024, - "Phase A 依赖未就绪,下遍重试: %s", ent.Path) - # --nowarn-register 亦抑制此类 Phase A 依赖重试 WARN(刷屏收敛) - if VLogger.nowarn_register() == 0: - VLogger.warning(fb_dp, "PhaseA-DBG") - # 回滚本文件已注册类的 MethodsEmitted:第 1 遍 _translate_oop_methods - # 发射方法体前已置 MethodsEmitted=1(防重入),但方法体内跨模块调用 - # 依赖 text.ll 未生成触发 _deps_pending → 本遍作废;若不回滚, - # 下遍重译 existing 分支被 MethodsEmitted==1 防重复检查拦截 → 类方法 - # 永不发射 → 链接 undefined symbol(追加87 根因)。 - # 必须先于 mb.reset_to(mark2)(MethodsEmitted 在 perm_pool 上跨 reset 存活)。 - if ent.Sha1 is not None: - HandlesStruct.reset_module_methods_emitted(ent.Sha1) - # OOM 清理:本文件翻译已产生瞬时数据(下遍会重新翻译),立即回收 - mb.reset_to(mark2) - continue - - # dump stub IR (declarations only) - stub_buf_a: bytes = stdlib.malloc(PHASE_A_IR_SIZE) - if stub_buf_a is None: - VLogger.error("stub 缓冲区分配失败", "PhaseA") - tr_a.dump_ir(stub_buf_a, PHASE_A_IR_SIZE, llvmlite.OUTPUT_STUB) - stub_len_a: t.CSizeT = string.strlen(stub_buf_a) - - # save stub.ll (切片路径: temp_dir/{sha1前缀}/{sha1}.stub.ll) - stub_path_a: str = StubMergerCollect._sliced_path(temp_dir, td_len_pa, ent.Sha1, "stub.ll") - if stub_path_a is not None: - sf_a: fileio.File | t.CPtr = fileio.File(stub_path_a, fileio.MODE.W) - if not sf_a.closed: - sf_a.write(stub_buf_a, stub_len_a) - sf_a.close() - stdlib.free(stub_path_a) - stdlib.free(stub_buf_a) - - # dump text IR (definitions only) - text_buf_a: bytes = stdlib.malloc(PHASE_A_IR_SIZE) - if text_buf_a is None: - VLogger.error("text 缓冲区分配失败", "PhaseA") - tr_a.dump_ir(text_buf_a, PHASE_A_IR_SIZE, llvmlite.OUTPUT_TEXT) - text_len_a: t.CSizeT = string.strlen(text_buf_a) - - # save text.ll (切片路径) - text_path_a: str = StubMergerCollect._sliced_path(temp_dir, td_len_pa, ent.Sha1, "text.ll") - if text_path_a is not None: - tf_a: fileio.File | t.CPtr = fileio.File(text_path_a, fileio.MODE.W) - if not tf_a.closed: - tf_a.write(text_buf_a, text_len_a) - tf_a.close() - stdlib.free(text_path_a) - stdlib.free(text_buf_a) - - # save dependencies (_imported_modules) for Phase B (切片路径) - deps_path_a: str = StubMergerCollect._sliced_path(temp_dir, td_len_pa, ent.Sha1, "deps.txt") - if deps_path_a is not None: - df_a: fileio.File | t.CPtr = fileio.File(deps_path_a, fileio.MODE.W) - if not df_a.closed: - if tr_a._imported_modules is not None: - dl_a: t.CSizeT = string.strlen(tr_a._imported_modules) - df_a.write(tr_a._imported_modules, dl_a) - df_a.close() - stdlib.free(deps_path_a) - - done_flags[i] = 1 - completed_this_pass += 1 - # OOM 清理:stub/text/deps 已写盘,回收本文件翻译瞬时数据 - # (AST/tokens/lexer/IR/Handler);app_deps_buf 已深拷贝依赖,不受影响 - mb.reset_to(mark2) - # 收敛检查:所有文件完成则结束 - all_done: int = 1 - for i_ck in range(file_count): - if done_flags[i_ck] == 0: - all_done = 0 - break - if all_done != 0: - break - if completed_this_pass == 0: - # 无进展:剩余文件无法完成(真实编译错误),终止并列出未完成文件 - for i_err in range(file_count): - if done_flags[i_err] == 0: - ea_err: t.CUInt64T = t.CUInt64T(entries) + i_err * entry_size - ent_err: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_err, t.CPtr)) - if ent_err is not None and ent_err.Path is not None: - fb_err: str = VLogger.fmt_buf() - if fb_err is not None: - viperlib.snprintf(fb_err, 1024, - "Phase A 无法完成翻译: %s(请检查依赖模块是否已编译/注册)", ent_err.Path) - VLogger.error(fb_err, "PhaseA") - stdlib.free(done_flags) - VLogger.error("Phase A 多遍收敛失败,终止编译", "PhaseA") - stdlib.free(entries) - return 1 - stdlib.free(done_flags) - - if do_phase2 == 0: - VLogger.info("Phase A 完成(仅 stub 生成)", "project") - if app_deps_buf is not None: - stdlib.free(app_deps_buf) - stdlib.free(entries) - return 0 - - # === 3. Phase B: 编译每个文件为 .obj === - if do_phase2 != 0: - if log is not None: - log.banner("Phase B: 编译 .obj") - - # 收集 .obj 路径(增大到 64KB,避免 includes .obj 路径溢出导致链接丢失符号) - # reachable_set/reachable_count: Phase B+ 填充,Phase C 用于按需链接 - reachable_set: bytes = None - reachable_count: int = 0 - OBJ_PATHS_SIZE: t.CSizeT = 65536 - obj_paths: bytes = stdlib.malloc(OBJ_PATHS_SIZE) - if obj_paths is None: - return 1 - obj_paths[0] = '\0' - obj_pos: t.CSizeT = 0 - # main_obj_path: 存放定义了用户 main 的 .obj 路径(链接时放在最前面, - # 避免 --allow-multiple-definition 选择了其他模块的 wrapper main) - main_obj_path: bytes = stdlib.malloc(512) - if main_obj_path is None: - return 1 - main_obj_path[0] = '\0' - compiled_count: int = 0 - - # 组合 IR 缓冲区大小(4MB,足够容纳本地 stub + 所有依赖 stub + 本地 text) - COMBINED_IR_SIZE: t.CSizeT = 4194304 - - # llc 任务表(stdlib.malloc,跨线程存活):连续 LlcTask 记录数组, - # 循环内只写 .ll + 构造任务,循环后 run_llc_parallel 分批并行跑 llc - llc_tasks: bytes = stdlib.malloc(t.CSizeT(file_count) * BuildPipeline.LlcTask.__sizeof__()) - if llc_tasks is None: - VLogger.error("llc 任务表分配失败", "PhaseB") - return 1 - llc_task_count: int = 0 - - for i in range(file_count): - ea: t.CUInt64T = t.CUInt64T(entries) + i * entry_size - ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr)) - if ent is None or ent.Path is None or ent.Sha1 is None: - continue - # 组合本地 stub + 所有依赖 stub + 本地 text → 完整 IR - combined_ir: bytes = stdlib.malloc(COMBINED_IR_SIZE) - if combined_ir is None: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "combined_ir 分配失败: %s", ent.Path) - VLogger.error(fb, "PhaseB") - continue - combined_len: t.CSizeT = StubMergerBuild.BuildCombinedIR(temp_dir, ent.Sha1, combined_ir, COMBINED_IR_SIZE) - if combined_len == 0: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "BuildCombinedIR 失败: %s", ent.Path) - VLogger.error(fb, "PhaseB") - stdlib.free(combined_ir) - continue - - # 写 .ll(llc 线程只读此文件);llc 本身改为循环后批量并行 - ret_w: int = BuildPipeline.write_ir_to_file(combined_ir, combined_len, temp_dir, ent.Sha1) - stdlib.free(combined_ir) - if ret_w != 0: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "写 .ll 失败: %s", ent.Path) - VLogger.error(fb, "PhaseB") - sys.exit(1) - - # 构造 llc 任务(命令串 stdlib.malloc,线程运行期不被 reset 回收) - llc_ir_path: str = BuildPipeline.build_sliced_path(temp_dir, ent.Sha1, "ll") - if llc_ir_path is None: - VLogger.error("llc 输入路径构造失败", "PhaseB") - sys.exit(1) - tslot: BuildPipeline.LlcTask | t.CPtr = (BuildPipeline.LlcTask | t.CPtr)(t.CVoid( - t.CUInt64T(llc_tasks) + t.CSizeT(llc_task_count) * BuildPipeline.LlcTask.__sizeof__(), t.CPtr)) - if BuildPipeline.init_llc_task(tslot, llc_ir_path, output_dir, ent.Sha1, - cc_cmd, cc_flags) != 0: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "llc 任务构造失败: %s", ent.Path) - VLogger.error(fb, "PhaseB") - sys.exit(1) - llc_task_count += 1 - - compiled_count += 1 - # 显示已提交 llc 的文件 - fb_comp: str = VLogger.fmt_buf() - if fb_comp is not None: - viperlib.snprintf(fb_comp, 1024, "[%d/%d] llc 已提交: %s", i + 1, file_count, ent.Path) - VLogger.info(fb_comp, "PhaseB") - # 构造 .obj 路径,检测是否是 main 模块(test_main.vp/.py 或 main.vp/.py) - od_len: t.CSizeT = string.strlen(output_dir) - is_main_mod: int = 0 - if string.strstr(ent.Path, "test_main.vp") is not None or string.strstr(ent.Path, "test_main.py") is not None: - is_main_mod = 1 - elif string.strstr(ent.Path, "main.vp") is not None or string.strstr(ent.Path, "main.py") is not None: - is_main_mod = 1 - - # 切片路径: output_dir/{sha1前缀}/{sha1}.obj - obj_path_sliced: str = StubMergerCollect._sliced_path(output_dir, od_len, ent.Sha1, "obj") - if obj_path_sliced is not None: - op_sliced_len: t.CSizeT = string.strlen(obj_path_sliced) - if is_main_mod != 0: - # main 模块: 复制到 main_obj_path(确保链接时 main 在最前) - if op_sliced_len < 512: - string.strcpy(main_obj_path, obj_path_sliced) - else: - VLogger.error("main_obj_path 缓冲区不足,终止编译", "PhaseB") - else: - # 其他模块: 追加到 obj_paths - if obj_pos + op_sliced_len + 2 < OBJ_PATHS_SIZE: - if obj_pos > 0: - obj_paths[obj_pos] = ' ' - obj_pos += 1 - string.strcpy(obj_paths + obj_pos, obj_path_sliced) - obj_pos += op_sliced_len - obj_paths[obj_pos] = '\0' - else: - VLogger.error(".obj 路径缓冲区不足", "PhaseB") - stdlib.free(obj_path_sliced) - - # 并行执行全部 llc(分批 LLC_MAX_THREADS 线程) - ret_p: int = BuildPipeline.run_llc_parallel(llc_tasks, llc_task_count, - BuildPipeline.LLC_MAX_THREADS) - if ret_p != 0: - VLogger.error("llc 编译失败,终止编译", "PhaseB") - sys.exit(1) - - # 释放 llc 任务(命令串 + 记录) - ti: int = 0 - while ti < llc_task_count: - tfree: BuildPipeline.LlcTask | t.CPtr = (BuildPipeline.LlcTask | t.CPtr)(t.CVoid( - t.CUInt64T(llc_tasks) + t.CSizeT(ti) * BuildPipeline.LlcTask.__sizeof__(), t.CPtr)) - BuildPipeline.free_llc_task(tfree) - ti += 1 - stdlib.free(llc_tasks) - - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "编译完成: %d/%d", compiled_count, file_count) - VLogger.success(fb, "PhaseB") - - if compiled_count == 0: - VLogger.error("无成功编译的文件", "PhaseB") - stdlib.free(entries) - return 1 - - # === 3.5 编译缺失的 includes 文件(按依赖图按需编译)=== - # 只编译被 App 源文件直接/间接引用的 includes 文件(可达集合), - # 而非遍历整个 includes 目录。通过 _BuildReachableSha1Set 构建依赖图。 - if includes_dir is not None and includes_binary_dir is not None: - inc_compiled: int = 0 - td_len_mi: t.CSizeT = string.strlen(temp_dir) - - # 诊断日志:确认 Phase B+ 入口和 Sha1Store 状态 - fb_pbp_enter: str = VLogger.fmt_buf() - if fb_pbp_enter is not None: - viperlib.snprintf(fb_pbp_enter, 1024, - "PhaseB+ 入口: store_count=%d includes_binary_dir=%s", - StubMergerStore.GetSha1StoreCount(), includes_binary_dir) - VLogger.info(fb_pbp_enter, "PhaseB+") - - # 创建 includes_binary_dir 目录(确保 .obj 能写入和 collect_obj_files 能扫描) - BuildPipeline.ensure_dir(includes_binary_dir) - - # declare_only 预处理已移至 Phase A 之前(Phase A-pre-inc), - # 确保 Phase A 翻译 App 源文件时 includes struct 已注册。 - # PopulateIncludesDeps 已在 Phase A-pre-inc 中填充。 - - # 构建可达 SHA1 集合(依赖图遍历) - # app_deps_buf 为 None 时回退到扫描 source_dir(非递归) - REACHABLE_SET_SIZE: t.CSizeT = t.CSizeT(StubMerger.MAX_INCLUDES_SHA1) * 17 - reachable_set: bytes = stdlib.malloc(REACHABLE_SET_SIZE) - reachable_count: int = 0 - if reachable_set is not None: - string.memset(reachable_set, 0, REACHABLE_SET_SIZE) - reachable_count = StubMergerBuild._BuildReachableSha1Set( - mb, source_dir, temp_dir, reachable_set, app_deps_buf) - fb_reach: str = VLogger.fmt_buf() - if fb_reach is not None: - viperlib.snprintf(fb_reach, 1024, "可达 includes SHA1: %d 个", reachable_count) - VLogger.info(fb_reach, "PhaseB+") - # fast-fail: 可达集合构建失败(依赖未找到),永不回退,直接终止 - if reachable_count < 0: - VLogger.error("可达集合构建失败(fast-fail),终止编译", "PhaseB+") - return 1 - else: - VLogger.error("reachable_set 分配失败,终止编译", "PhaseB+") - return 1 - - # 释放 app_deps_buf(已构建完 reachable_set,不再需要) - if app_deps_buf is not None: - stdlib.free(app_deps_buf) - app_deps_buf = None - - # 从全局存储器获取 SHA1/模块名 数组:复制局部副本(bytes), - # 避免 store 联合返回值(bytes|t.CPtr)跨函数传参/索引的地址异常 - # (与 _BuildReachableSha1Set 的 BFS 一致)。 - # rel/incdir 仅本函数内按索引读取(不跨函数传参),保留 store 指针。 - td_len_pb: t.CSizeT = string.strlen(temp_dir) - store_sha1_arr_mi: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 17) - store_mod_arr_mi: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 64) - store_count_mi: int = 0 - if store_sha1_arr_mi is not None and store_mod_arr_mi is not None: - store_count_mi = StubMergerIR._BuildIncludesSha1Map( - temp_dir, td_len_pb, store_sha1_arr_mi, store_mod_arr_mi) - store_rel_arr_mi: bytes | t.CPtr = StubMergerStore.GetSha1StoreRelArrPtr() - store_incdir_arr_mi: bytes | t.CPtr = StubMergerStore.GetSha1StoreIncdirArrPtr() - if store_count_mi > 0: - - # 拓扑排序可达 includes:被依赖模块先完整翻译。跨模块 vtable 生成 - # 需要依赖模块的函数 TypeStr 已注册到全局表(如 astaux 继承 base 的 AST) - topo_idx: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(stdlib.malloc(8 * (store_count_mi + 1))) - topo_count: int = 0 - if topo_idx is None: - VLogger.error("拓扑排序索引分配失败,终止编译", "PhaseB+") - topo_count = 0 - else: - topo_count = StubMergerTopo.BuildTopoSortedIndices( - store_count_mi, store_sha1_arr_mi, store_mod_arr_mi, - reachable_set, reachable_count, topo_idx) - - for si_mi in range(topo_count): - # 当前条目(拓扑序索引,仅含可达模块) - ti: int = topo_idx[si_mi] - # 获取当前条目的 SHA1 和 rel_path - inc_sha1_mi: str = store_sha1_arr_mi + t.CSizeT(ti) * 17 - inc_rel_mi: str = store_rel_arr_mi + t.CSizeT(ti) * StubMerger.MAX_REL_PATH_LEN - # 检查 .obj 是否已存在于 includes.binary(切片子目录) - ibd_len_mi: t.CSizeT = string.strlen(includes_binary_dir) - check_pat_mi: str = StubMergerCollect._sliced_path(includes_binary_dir, ibd_len_mi, inc_sha1_mi, "obj") - check_fd_mi: w32.win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__()) - obj_exists_mi: int = 0 - if check_pat_mi is not None and check_fd_mi is not None: - string.memset(check_fd_mi, 0, w32.win32file.WIN32_FIND_DATAA.__sizeof__()) - check_h_mi: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(check_pat_mi, check_fd_mi) - if check_h_mi != w32.win32base.INVALID_HANDLE_VALUE: - w32.win32file.FindClose(check_h_mi) - obj_exists_mi = 1 - if obj_exists_mi != 0: - if check_pat_mi is not None: - stdlib.free(check_pat_mi) - stdlib.free(check_fd_mi) - continue - - # .obj 不存在,需要编译 - # 构造源文件路径: {所属 includes 根目录}/{rel_path}(多目录逐条取 IncDir,空串回退 includes_dir) - rel_path_len_mi: t.CSizeT = string.strlen(inc_rel_mi) - incdir_mi: str = store_incdir_arr_mi + t.CSizeT(ti) * StubMerger.MAX_INC_DIR_LEN - if incdir_mi is None or incdir_mi[0] == '\0': - incdir_mi = includes_dir - inc_dir_len_mi: t.CSizeT = string.strlen(incdir_mi) - src_fp_mi: bytes = stdlib.malloc(inc_dir_len_mi + 1 + rel_path_len_mi + 1) - if src_fp_mi is None: - stdlib.free(check_pat_mi) - if check_fd_mi is not None: - stdlib.free(check_fd_mi) - VLogger.error("includes 源路径分配失败,终止编译", "PhaseB+") - viperlib.snprintf(src_fp_mi, inc_dir_len_mi + 1 + rel_path_len_mi + 1, - "%s/%s", incdir_mi, inc_rel_mi) - - # 检查是否为声明文件(只有 declare 没有实质 define) - # 判断方法: text.ll 中若有混淆函数 define(含 @")则为实现文件 - is_decl_mi: int = -1 - tpath_mi: str = StubMergerCollect._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll") - if tpath_mi is not None: - tf_mi: fileio.File | t.CPtr = fileio.File(tpath_mi, fileio.MODE.R) - if not tf_mi.closed: - is_decl_mi = 1 - tbuf_mi: bytes = stdlib.malloc(StubMerger.STUB_READ_BUF_SIZE) - tbr_mi: t.CInt64T = 0 - if tbuf_mi is not None: - tbr_mi = tf_mi.read_all(tbuf_mi, StubMerger.STUB_READ_BUF_SIZE) - if tbuf_mi is not None and tbr_mi > 0: - if tbr_mi < StubMerger.STUB_READ_BUF_SIZE: - tbuf_mi[tbr_mi] = '\0' - else: - tbuf_mi[StubMerger.STUB_READ_BUF_SIZE - 1] = '\0' - # 逐行扫描: 找 define 行即为实现文件 - # (不再要求行中含 @",因为 memhub 等模块的函数名 - # 如 @ca40915f11b8b6ad._align_up 不带引号但仍是实现文件) - tpos_mi: t.CSizeT = 0 - while tpos_mi < tbr_mi: - tls_mi: t.CSizeT = tpos_mi - while tpos_mi < tbr_mi: - if tbuf_mi[tpos_mi] == '\n': - break - tpos_mi += 1 - tll_mi: t.CSizeT = tpos_mi - tls_mi - if tpos_mi < tbr_mi: - tpos_mi += 1 - if tll_mi >= 7 and string.strncmp(tbuf_mi + tls_mi, "define ", 7) == 0: - is_decl_mi = 0 - break - stdlib.free(tbuf_mi) - tf_mi.close() - stdlib.free(tpath_mi) - # is_decl_mi == -1: text.ll 不存在(Phase1 未翻译此文件) - # is_decl_mi == 1: 声明文件(仅 declare 无 define) - # is_decl_mi == 0: 实现文件(有 define) - # 只跳过声明文件(is_decl_mi == 1);text.ll 不存在时继续,让后续翻译逻辑处理 - if is_decl_mi == 1: - stdlib.free(check_pat_mi) - if check_fd_mi is not None: - stdlib.free(check_fd_mi) - stdlib.free(src_fp_mi) - continue - - # 尝试 BuildCombinedIR(stub/text 应已由 Phase1 生成) - inc_combined_mi: bytes = stdlib.malloc(COMBINED_IR_SIZE) - inc_combined_len_mi: t.CSizeT = 0 - if inc_combined_mi is not None: - inc_combined_len_mi = StubMergerBuild.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE) - - # 如果 stub/text 不存在,翻译源文件并保存 stub + text,然后重试 - if inc_combined_len_mi == 0 and inc_combined_mi is not None: - # 计算 includes 文件的包名(相对 includes_dir 的目录部分) - inc_pkg_mi: str = None - if string.strlen(src_fp_mi) > inc_dir_len_mi + 1: - inc_rel_mi2: str = src_fp_mi + inc_dir_len_mi + 1 - inc_pkg_mi = HandlesImports.compute_package_from_relpath(mb, inc_rel_mi2) - tr_mi: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, src_fp_mi, inc_sha1_mi, inc_pkg_mi) - if tr_mi is not None: - PBP_IR_SIZE: t.CSizeT = 1048576 - # 保存 stub.ll (切片路径) - inc_stub_buf: bytes = stdlib.malloc(PBP_IR_SIZE) - if inc_stub_buf is not None: - tr_mi.dump_ir(inc_stub_buf, PBP_IR_SIZE, llvmlite.OUTPUT_STUB) - inc_stub_len: t.CSizeT = string.strlen(inc_stub_buf) - inc_stub_path: str = StubMergerCollect._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "stub.ll") - if inc_stub_path is not None: - isf: fileio.File | t.CPtr = fileio.File(inc_stub_path, fileio.MODE.W) - if not isf.closed: - isf.write(inc_stub_buf, inc_stub_len) - isf.close() - stdlib.free(inc_stub_path) - stdlib.free(inc_stub_buf) - # 保存 text.ll (切片路径) - inc_text_buf: bytes = stdlib.malloc(PBP_IR_SIZE) - if inc_text_buf is not None: - tr_mi.dump_ir(inc_text_buf, PBP_IR_SIZE, llvmlite.OUTPUT_TEXT) - inc_text_len: t.CSizeT = string.strlen(inc_text_buf) - inc_text_path: str = StubMergerCollect._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll") - if inc_text_path is not None: - itf: fileio.File | t.CPtr = fileio.File(inc_text_path, fileio.MODE.W) - if not itf.closed: - itf.write(inc_text_buf, inc_text_len) - itf.close() - stdlib.free(inc_text_path) - stdlib.free(inc_text_buf) - # 重试 BuildCombinedIR - inc_combined_len_mi = StubMergerBuild.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE) - # OOM 清理:stub/text 已写盘,回收本 includes 文件翻译瞬时数据 - # (AST/tokens/lexer/IR/Handler);BuildCombinedIR 只读文件,不受影响 - mb.reset_to(mark2) - - if inc_combined_len_mi == 0: - # 诊断:检查 stub.ll/text.ll 是否存在 - diag_stub: str = StubMergerCollect._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "stub.ll") - diag_text: str = StubMergerCollect._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll") - diag_stub_ex: int = 0 - diag_text_ex: int = 0 - if diag_stub is not None: - df_diag_s: fileio.File | t.CPtr = fileio.File(diag_stub, fileio.MODE.R) - if not df_diag_s.closed: - diag_stub_ex = 1 - df_diag_s.close() - stdlib.free(diag_stub) - if diag_text is not None: - df_diag_t: fileio.File | t.CPtr = fileio.File(diag_text, fileio.MODE.R) - if not df_diag_t.closed: - diag_text_ex = 1 - df_diag_t.close() - stdlib.free(diag_text) - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, - "BuildCombinedIR 失败: %s (stub=%d text=%d is_decl=%d)", - src_fp_mi, diag_stub_ex, diag_text_ex, is_decl_mi) - VLogger.error(fb, "PhaseB+") - if inc_combined_mi is not None: - stdlib.free(inc_combined_mi) - stdlib.free(check_pat_mi) - if check_fd_mi is not None: - stdlib.free(check_fd_mi) - stdlib.free(src_fp_mi) - continue - - # 编译为 .obj(输出到 includes_binary_dir,与存在性检查和链接收集一致) - inc_cret_mi: int = BuildPipeline.compile_module_to_obj( - inc_combined_mi, inc_combined_len_mi, temp_dir, includes_binary_dir, inc_sha1_mi, - cc_cmd, cc_flags) - stdlib.free(inc_combined_mi) - - if inc_cret_mi != 0: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "llc 编译失败,终止编译: %s", src_fp_mi) - VLogger.error(fb, "PhaseB+") - sys.exit(1) - - inc_compiled += 1 - # 显示编译完成的 includes 文件 - fb_inc_comp: str = VLogger.fmt_buf() - if fb_inc_comp is not None: - viperlib.snprintf(fb_inc_comp, 1024, "[includes %d] 编译完成: %s", inc_compiled, src_fp_mi) - VLogger.info(fb_inc_comp, "PhaseB+") - - # 添加到 obj_paths (切片路径,从 includes_binary_dir 取) - ibd_len_mi2: t.CSizeT = string.strlen(includes_binary_dir) - inc_obj_sliced: str = StubMergerCollect._sliced_path(includes_binary_dir, ibd_len_mi2, inc_sha1_mi, "obj") - - if inc_obj_sliced is not None: - inc_obj_len: t.CSizeT = string.strlen(inc_obj_sliced) - if obj_pos + inc_obj_len + 2 < OBJ_PATHS_SIZE: - if obj_pos > 0: - obj_paths[obj_pos] = ' ' - obj_pos += 1 - string.strcpy(obj_paths + obj_pos, inc_obj_sliced) - obj_pos += inc_obj_len - obj_paths[obj_pos] = '\0' - else: - VLogger.error("includes .obj 路径缓冲区溢出,终止编译", "PhaseB+") - stdlib.free(inc_obj_sliced) - - # 释放本次迭代的临时内存 - if check_pat_mi is not None: - stdlib.free(check_pat_mi) - - if check_fd_mi is not None: - stdlib.free(check_fd_mi) - - stdlib.free(src_fp_mi) - - # 释放拓扑排序索引与局部映射副本 - if topo_idx is not None: - stdlib.free(topo_idx) - if store_sha1_arr_mi is not None: - stdlib.free(store_sha1_arr_mi) - if store_mod_arr_mi is not None: - stdlib.free(store_mod_arr_mi) - - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "编译缺失 includes: %d 个", inc_compiled) - VLogger.info(fb, "PhaseB+") - - # 释放 app_deps_buf(Phase B+ 块未执行时此处兜底释放) - if app_deps_buf is not None: - stdlib.free(app_deps_buf) - app_deps_buf = None - - # === 4. Phase C: 链接所有 .obj → .exe === - if log is not None: - log.banner("Phase C: 链接") - - od_len2: t.CSizeT = string.strlen(output_dir) - lo_len: t.CSizeT = string.strlen(linker_output) - exe_path: bytes = stdlib.malloc(od_len2 + lo_len + 2) - if exe_path is not None: - viperlib.snprintf(exe_path, od_len2 + lo_len + 2, "%s/%s", output_dir, linker_output) - else: - exe_path = linker_output - VLogger.error("exe_path 分配失败,终止编译", "PhaseC") - - # 构造最终 .obj 路径列表:main_obj_path 在前,reachable .obj 在后 - final_obj_paths: bytes = stdlib.malloc(OBJ_PATHS_SIZE + 512) - if final_obj_paths is None: - stdlib.free(entries) - return 1 - final_obj_paths[0] = '\0' - fop_pos: t.CSizeT = 0 - # main_obj_path 放在最前面(确保 --allow-multiple-definition 选择用户 main) - if main_obj_path[0] != '\0': - mlen: t.CSizeT = string.strlen(main_obj_path) - string.strcpy(final_obj_paths, main_obj_path) - fop_pos = mlen - - # 合并 Phase B/B+ 编译的 App 非 main 模块 .obj(obj_paths,空格分隔)。 - # 此前 final_obj_paths 只含 main_obj + reachable includes,App 依赖文件 - # (main import 的 syslibtest_impl/os_backend 等)的 .obj 从未入链——追加28 - # 前靠 reachable 误含 App 时从 includes.binary 的重复 obj 兜底(undefined - # symbol: ae2038ced7b4634f.run 根因)。obj_paths 同时含 Phase B+ 本次 - # 新编译的 includes obj(与下方 reachable 收集重复,--allow-multiple- - # definition 容忍,仅本次编译的少量文件)。 - if obj_pos > 0: - if fop_pos + obj_pos + 1 < OBJ_PATHS_SIZE + 512: - if fop_pos > 0: - final_obj_paths[fop_pos] = ' ' - fop_pos += 1 - string.strcpy(final_obj_paths + fop_pos, obj_paths) - fop_pos += obj_pos - final_obj_paths[fop_pos] = '\0' - - # 按图链接:遍历 reachable_set,只收集可达 includes 的 .obj - # 不再全量收集 includes.binary 下的所有 .obj - if reachable_set is not None and reachable_count > 0: - ibd_len_pc: t.CSizeT = string.strlen(includes_binary_dir) - td_len_pc: t.CSizeT = string.strlen(temp_dir) - ri_pc: int - for ri_pc in range(reachable_count): - rsha1_pc: str = reachable_set + t.CSizeT(ri_pc) * 17 - if rsha1_pc[0] == '\0': - continue - obj_path_pc: str = StubMergerCollect._sliced_path(includes_binary_dir, ibd_len_pc, rsha1_pc, "obj") - if obj_path_pc is not None: - # 检查 .obj 文件是否存在 - cf_pc: fileio.File | t.CPtr = fileio.File(obj_path_pc, fileio.MODE.R) - if not cf_pc.closed: - cf_pc.close() - # .obj 存在,追加到 final_obj_paths - op_len_pc: t.CSizeT = string.strlen(obj_path_pc) - if fop_pos + op_len_pc + 2 < OBJ_PATHS_SIZE + 512: - if fop_pos > 0: - final_obj_paths[fop_pos] = ' ' - fop_pos += 1 - string.strcpy(final_obj_paths + fop_pos, obj_path_pc) - fop_pos += op_len_pc - final_obj_paths[fop_pos] = '\0' - else: - # .obj 缺失:纯声明模块(text.ll 无 define 行,如 stdio.vp 全 pass) - # 无需 .obj,静默跳过;实现文件缺失才是编译产物异常(fail-fast) - if StubMergerIR.IsDeclOnlyModule(temp_dir, td_len_pc, rsha1_pc) != 1: - fb_pc: str = VLogger.fmt_buf() - if fb_pc is not None: - viperlib.snprintf(fb_pc, 1024, "可达模块 .obj 缺失: %s", obj_path_pc) - VLogger.error(fb_pc, "PhaseC") - stdlib.free(obj_path_pc) - - final_obj_paths[fop_pos] = '\0' - obj_paths_len: t.CSizeT = fop_pos - - # 释放 reachable_set(Phase C 已使用完毕) - if reachable_set is not None: - stdlib.free(reachable_set) - reachable_set = None - - # 按图链接:不传 includes_binary_dir(传 None),避免全量收集 - lret: int = BuildPipeline.link_objs_to_exe( - final_obj_paths, obj_paths_len, - linker_cmd, linker_flags, exe_path, - None) - - if lret == 0: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "输出: %s", exe_path) - VLogger.success(fb, "PhaseC") - if args.get_bool("run"): - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "执行: %s", exe_path) - VLogger.info(fb, "run") - rp: subprocess.CompletedProcess | t.CPtr = subprocess.run(exe_path, False, False) - if rp is not None: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "退出码: %d", rp.returncode) - VLogger.info(fb, "run") - else: - VLogger.error("链接失败", "PhaseC") - stdlib.free(entries) - return 1 - - stdlib.free(entries) - return 0 +import lib.core.Gen.GenApi as GenApi +import t, c +from stdint import * +import stdio +import string +import stdlib +import memhub +import viperlib +import w32.fileio as fileio +import w32.win32file +import w32.win32base +import sys +import ast +import llvmlite +import subprocess +import argparse +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HandlesTranslator +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.BuildPipeline as BuildPipeline +import lib.core.IncludesScanner as IncludesScanner +import lib.core.CompilerFactory as CompilerFactory +import lib.core.StubMerger as StubMerger +import lib.Projectrans.Utils as Utils +import lib.Projectrans.Config as Config +import lib.core.StubMergerBuild as StubMergerBuild +import lib.core.StubMergerCollect as StubMergerCollect +import lib.core.StubMergerIR as StubMergerIR +import lib.core.StubMergerStore as StubMergerStore +import lib.core.StubMergerTopo as StubMergerTopo + +# 全局 mbuddy 指针 +_mbuddy: memhub.MemBuddy | t.CPtr + +# 源代码缓冲区大小(1MB) +SRC_BUF_SIZE: t.CDefine = 1048576 + +# 最大源文件数(递归扫描子目录后文件数增多:App 现有 65 个 .vp, +# 2026-08-14 CompilerFactory.vp 加入后超出 64 被截断 → 链接 undefined symbol +# CompilerFactory.get_perm_pool。增大到 128 留余量) +MAX_SRC_FILES: t.CDefine = 128 + +# 全局栈金丝雀(避免局部变量改变栈布局) +_g_canary: t.CUInt32T + + +@t.NoVTable +class SrcFileEntry: + """源文件条目""" + Path: str # 完整路径 + Sha1: str # SHA1 前16字符 + + +# ============================================================ +# _ScanDirForPyFiles - 递归扫描目录,收集 .vp/.py 文件到 entries +# +# 替代旧的非递归 FindFirstFileA(dir/*.py) 扫描,支持子目录 +# (如 App/lib/core/Handles/)。遇到目录递归扫描,遇到 .vp/.py +# 文件读取内容、计算 SHA1、加入 entries。 +# +# Args: +# mb: 内存池 +# dir_path: 当前扫描目录 +# entries: SrcFileEntry 数组 +# entry_size: 单个条目大小(SrcFileEntry.__sizeof__()) +# file_count: 当前已收集的文件数 +# max_files: 最大文件数 +# +# Returns: +# 新的 file_count +# ============================================================ +def _ScanDirForPyFiles(mb: memhub.MemBuddy | t.CPtr, + dir_path: str, + entries: SrcFileEntry | t.CPtr, + entry_size: t.CSizeT, + file_count: int, max_files: int) -> int: + """递归扫描目录,收集 .vp/.py 文件到 entries,返回新的 file_count""" + if dir_path is None or entries is None: + return file_count + if file_count >= max_files: + return file_count + + dir_len: t.CSizeT = string.strlen(dir_path) + pattern: bytes = stdlib.malloc(dir_len + 16) + if pattern is None: + return file_count + viperlib.snprintf(pattern, dir_len + 16, "%s/*", dir_path) + + find_data_size: t.CSizeT = w32.win32file.WIN32_FIND_DATAA.__sizeof__() + find_data: w32.win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(find_data_size + 16) + if find_data is None: + stdlib.free(pattern) + return file_count + string.memset(find_data, 0, find_data_size + 16) + + handle: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(pattern, find_data) + if handle == w32.win32base.INVALID_HANDLE_VALUE: + stdlib.free(pattern) + stdlib.free(find_data) + return file_count + + while True: + fname: str = find_data.cFileName + if fname is None: + if w32.win32file.FindNextFileA(handle, find_data) == 0: + break + continue + fname_len: t.CSizeT = string.strlen(fname) + if fname_len <= 0: + if w32.win32file.FindNextFileA(handle, find_data) == 0: + break + continue + # 跳过 . 和 .. + is_dot: int = 0 + if fname_len == 1 and fname[0] == '.': + is_dot = 1 + elif fname_len == 2 and fname[0] == '.' and fname[1] == '.': + is_dot = 1 + if is_dot != 0: + if w32.win32file.FindNextFileA(handle, find_data) == 0: + break + continue + # 检查是否是目录 + attrs: ULONG = find_data.dwFileAttributes + is_dir: int = 0 + if (attrs & w32.win32file.FILE_ATTRIBUTE_DIRECTORY) != 0: + is_dir = 1 + if is_dir != 0: + # 递归扫描子目录 + sub_dir: bytes = Utils.JoinPath(dir_path, fname) + if sub_dir is not None: + file_count = _ScanDirForPyFiles(mb, sub_dir, entries, entry_size, file_count, max_files) + stdlib.free(sub_dir) + if w32.win32file.FindNextFileA(handle, find_data) == 0: + break + continue + # 检查是否是 .vp 或 .py 文件(.vp 为 Viper 源,.py 向后兼容) + if fname_len > 3 and Utils.is_vp_or_py_at(fname, 0, fname_len) != 0 \ + and file_count < max_files: + full_path: bytes = Utils.JoinPath(dir_path, fname) + if full_path is not None: + sbuf: bytes = Utils.read_file_to_buf(full_path, SRC_BUF_SIZE) + if sbuf is None: + if w32.win32file.FindNextFileA(handle, find_data) == 0: + break + continue + # 统一用 IncludesScanner.compute_file_sha1(CRLF→LF 归一化), + # 与 StubMerger.vp:1510 对同一批 App 源文件的口径一致; + # 此前用 Utils.compute_sha1(原始字节)会导致 stub/define + # 符号前缀不一致 → 链接报 undefined reference。 + sha1_val: str = IncludesScanner.compute_file_sha1(mb, full_path) + if sha1_val is not None: + ea: t.CUInt64T = t.CUInt64T(entries) + file_count * entry_size + ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr)) + if ent is not None: + ent.Path = full_path + ent.Sha1 = sha1_val + file_count += 1 + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "%s (sha1=%s)", fname, sha1_val) + VLogger.info(fb, "project") + stdlib.free(sbuf) + # full_path 不释放:ent.Path 引用它 + + if w32.win32file.FindNextFileA(handle, find_data) == 0: + break + + w32.win32file.FindClose(handle) + stdlib.free(pattern) + stdlib.free(find_data) + return file_count + + +# ============================================================ +# _PreRegisterAppGenericTemplates - mark2 前预注册 App 源文件泛型类模板 +# +# 与 Phase1 的 includes 全量预注册同理:泛型模板表(GenericClassNames 等 +# 4 张 + 模板节点)是 pool 懒分配的跨文件持久表,若在 mark2 之后 +# (Phase A-pre 翻译 App 文件时)才首次注册,reset_to(mark2) 会回收表与 +# 节点 → 后续查重/特化遍历悬空内存崩溃。App 文件数量少,mark2 前预注册 +# 产生的 AST 驻留内存可忽略。重复注册由 _register_generic_template 查重跳过。 +# ============================================================ +def _PreRegisterAppGenericTemplates(mb: memhub.MemBuddy | t.CPtr, + entries: SrcFileEntry | t.CPtr, + file_count: int, + entry_size: t.CSizeT) -> int: + """mark2 前预注册 App 源文件的泛型类模板,返回处理到的泛型类数量""" + if mb is None or entries is None or file_count <= 0: + return 0 + handled: int = 0 + for i in range(file_count): + ea_pa: t.CUInt64T = t.CUInt64T(entries) + i * entry_size + ent_pa: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_pa, t.CPtr)) + if ent_pa is None or ent_pa.Path is None or ent_pa.Sha1 is None: + continue + # 读取文件 + f_pa: fileio.File | t.CPtr = fileio.File(ent_pa.Path, fileio.MODE.R) + if f_pa.closed: + continue + src_buf_pa: bytes = stdlib.malloc(SRC_BUF_SIZE) + if src_buf_pa is None: + f_pa.close() + continue + bytes_read_pa: LONG = f_pa.read_all(src_buf_pa, SRC_BUF_SIZE) + f_pa.close() + if bytes_read_pa <= 0: + stdlib.free(src_buf_pa) + continue + if bytes_read_pa < SRC_BUF_SIZE: + src_buf_pa[bytes_read_pa] = 0 + else: + src_buf_pa[SRC_BUF_SIZE - 1] = 0 + # 解析 AST(只解析,不完整翻译;用永久池使模板节点跨 mark2 reset 存活) + perm_pa: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool() + if perm_pa is None: + perm_pa = mb + lx_pa: ast.Lexer | t.CPtr = ast.new_lexer(perm_pa) + if lx_pa is None: + stdlib.free(src_buf_pa) + continue + ast._lexer_init(lx_pa, src_buf_pa, perm_pa) + tokens_pa: ast.Token | t.CPtr = ast.tokenize(lx_pa) + tree_pa: ast.AST | t.CPtr = ast.parse_tokens(perm_pa, tokens_pa) + if tree_pa is None: + stdlib.free(src_buf_pa) + continue + # 遍历顶层 ClassDef,注册泛型模板(type_params 非 None) + ch_pa: list[ast.AST | t.CPtr] | t.CPtr = tree_pa.children + if ch_pa is not None: + cn_pa: t.CSizeT = len(ch_pa) + for ci_pa in range(cn_pa): + child_pa: ast.AST | t.CPtr = ch_pa.get(ci_pa) + if child_pa is None or child_pa.kind() != ast.ASTKind.ClassDef: + continue + cd_pa: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child_pa) + if cd_pa is None or cd_pa.name is None: + continue + tp_pa: list[str] | t.CPtr = cd_pa.type_params + if tp_pa is None: + continue + GenApi.set_current_file_type(ent_pa.Path) + GenApi._register_generic_template(perm_pa, cd_pa, ent_pa.Sha1) + handled += 1 + stdlib.free(src_buf_pa) + if handled > 0: + fb_pg3: str = VLogger.fmt_buf() + if fb_pg3 is not None: + viperlib.snprintf(fb_pg3, 1024, "mark2 前预注册 %d 个 App 泛型类模板", handled) + VLogger.info(fb_pg3, "PhaseA") + return handled + + +def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, + source_dir: str, temp_dir: str, output_dir: str, + cc_cmd: str, cc_flags: str, + linker_cmd: str, linker_flags: str, linker_output: str, + includes_binary_dir: str, + includes_dir: str, + do_phase1: int, do_phase2: int, + log: VLogger.Logger | t.CPtr, + args: argparse.ParsedArgs | t.CPtr) -> int: + """多文件项目编译 + + Returns: 0 成功,非 0 失败 + """ + if source_dir is None: + VLogger.error("source_dir 为空", "project") + return 1 + + # === 栈金丝雀检查(全局变量,不影响栈布局)=== + global _g_canary + _g_canary = 305419896 + + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "多文件项目编译: %s", source_dir) + VLogger.info(fb, "project") + + # === 1. 递归扫描 source_dir 下的 .vp/.py 文件(包括子目录)=== + entry_size: t.CSizeT = SrcFileEntry.__sizeof__() + entries: SrcFileEntry | t.CPtr = stdlib.malloc(MAX_SRC_FILES * entry_size) + if entries is None: + return 1 + string.memset(entries, 0, MAX_SRC_FILES * entry_size) + + file_count: int = _ScanDirForPyFiles(mb, source_dir, entries, entry_size, 0, MAX_SRC_FILES) + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "共 %d 个源文件", file_count) + VLogger.info(fb, "project") + + if file_count == 0: + stdlib.free(entries) + return 1 + + # 初始化 AST 表 + ast._init_tables(mb) + + # mark2 之前预注册 App 源文件的泛型类模板:泛型模板表/节点是 pool 懒分配, + # 必须在 mark2 之前注册才能跨 reset_to(mark2) 存活(与 Phase1 的 includes + # 全量预注册同理),否则 Phase A-pre 首次注册后 reset 回收 → 后续查重/特化 + # 遍历悬空内存崩溃(1.log FuncTest ASAN access-violation 同类根因)。 + _PreRegisterAppGenericTemplates(mb, entries, file_count, entry_size) + + # OOM 清理(对齐 Phase1 1b 的 mark1/reset_to 模式): + # Phase2 的 includes 预注册(Phase A-pre-inc)、App 源文件预注册(Phase A-pre)、 + # App 全量翻译(Phase A)、缺失 includes 翻译(Phase B+)都会产生大量瞬时数据 + # (AST/tokens/lexer/IR/Handler/dump 临时)。无回收时 98 个 includes 的 AST/IR + # 全量累积 pool → 1GB OOM(NewAstTest 依赖 ast 模块场景)。 + # 此处打 mark2,各处翻译完成后 reset_to(mark2) 回收该文件瞬时数据; + # 跨文件持久表(struct/enum/docstring/CDefine/函数注册表等)已 stdlib 化 + # 或落在 mark2 之前,reset 不受影响(与 Phase1 1b 同翻译路径,已验证安全)。 + mark2: t.CSizeT = mb.mark() + # mark2 之后新注册的 struct/enum 条目改 stdlib 分配(跨 reset 存活,对齐 Phase1) + GenApi.set_stdlib_alloc(1) + + # 确保 temp/output 目录存在 + BuildPipeline.ensure_dir(temp_dir) + BuildPipeline.ensure_dir(output_dir) + + # === 0.5 扫描 includes 目录填充 Sha1Store(消除 Phase1 依赖)=== + # Phase2 不依赖 Phase1 的副作用:如果 Sha1Store 为空(Phase1 未运行或提前返回), + # 自行扫描 includes 目录并填充 Sha1Store,确保后续"编译缺失 includes"逻辑能正常工作 + if includes_dir is not None: + if StubMergerStore.GetSha1StoreCount() == 0: + inc_scan_result: IncludesScanner.ScanResult | t.CPtr = IncludesScanner.scan_includes(mb, includes_dir) + if inc_scan_result is None: + VLogger.error("includes 扫描失败,无法填充 Sha1Store", "project") + if inc_scan_result is not None: + inc_filled: int = StubMergerStore.PopulateSha1MapStore(inc_scan_result) + fb_inc: str = VLogger.fmt_buf() + if fb_inc is not None: + viperlib.snprintf(fb_inc, 1024, "Phase2 自主填充 includes Sha1Store: %d 个", inc_filled) + VLogger.info(fb_inc, "project") + + # 追加 App 源文件 SHA1 到 _sha1_map.txt(人类可读输出,程序内部不读取此文件) + # 格式: {sha1}:{rel_path}\n (保留目录结构,如 lib/core/VLogger.vp) + # 同步追加到内存存储器(AppendToSha1MapStore,供跨模块 CDefine 查找) + td_len_am: t.CSizeT = string.strlen(temp_dir) + src_dir_len_am: t.CSizeT = string.strlen(source_dir) + map_path_am: bytes = stdlib.malloc(td_len_am + 32) + if map_path_am is not None: + viperlib.snprintf(map_path_am, td_len_am + 32, "%s/_sha1_map.txt", temp_dir) + mf: fileio.File | t.CPtr = fileio.File(map_path_am, fileio.MODE.A) + line_am: bytes = stdlib.malloc(512) + # 先遍历一次填充内存存储器(不依赖文件 I/O),再写入 _sha1_map.txt + app_filled: int = 0 + for i in range(file_count): + ea_am: t.CUInt64T = t.CUInt64T(entries) + i * entry_size + ent_am: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_am, t.CPtr)) + if ent_am is None or ent_am.Path is None or ent_am.Sha1 is None: + continue + # 计算相对路径(去除 source_dir 前缀,保留目录结构) + p_str: str = ent_am.Path + p_len: t.CSizeT = string.strlen(p_str) + rel_path_am: str = p_str + if p_len > src_dir_len_am + 1: + if string.strncmp(p_str, source_dir, src_dir_len_am) == 0: + rel_path_am = p_str + src_dir_len_am + 1 + # 同步追加到内存存储器(供跨模块 CDefine 查找) + # rel_path_am 格式如 "lib/core/StubMerger.vp",与 _sha1_map.txt 一致 + if StubMergerStore.AppendToSha1MapStore(ent_am.Sha1, rel_path_am) != 0: + fb_apf: str = VLogger.fmt_buf() + if fb_apf is not None: + viperlib.snprintf(fb_apf, 1024, "AppendToSha1MapStore 失败: %s", rel_path_am) + VLogger.error(fb_apf, "project") + app_filled += 1 + # 写入 _sha1_map.txt(人类可读输出) + if not mf.closed and line_am is not None: + viperlib.snprintf(line_am, 512, "%s:%s\n", ent_am.Sha1, rel_path_am) + ll_am: t.CSizeT = string.strlen(line_am) + mf.write(line_am, ll_am) + if line_am is not None: + stdlib.free(line_am) + if not mf.closed: + mf.close() + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "已追加 %d 个 App 文件到 _sha1_map.txt 和内存存储器", app_filled) + VLogger.info(fb, "project") + stdlib.free(map_path_am) + + # 模块 SHA1 映射已由 PopulateSha1MapStore + AppendToSha1MapStore 统一填充到 + # StubMerger 全局存储器,HandlesExprCall._lookup_module_sha1 直接查全局存储器, + # 不再需要构建独立的 SHA1 映射表副本。 + + + # === 2. Phase A: 为每个文件生成 stub + text === + # app_deps_buf: 收集所有 App 源文件的直接依赖模块名(空格分隔) + # 供 Phase B+ 的 _BuildReachableSha1Set 作为初始 worklist,实现按需编译 + # 声明在 if 块外,确保 Phase B+ 和清理代码能访问 + # 65536 与 StubMerger.REACH_WORKLIST_BUF 对齐:全量 App imports 拼接 + # 超 8192(追加82 同源溢出),8192 会静默丢依赖致 Phase B+ 可达集合不全 + APP_DEPS_BUF_SIZE: t.CSizeT = 65536 + app_deps_buf: bytes = None + app_deps_len: t.CSizeT = 0 + if do_phase1 != 0: + if log is not None: + log.banner("Phase A: 生成 stub + text") + + # === Phase A-pre-inc: includes 预注册 struct + 依赖填充 === + # 必须在 App 源文件预注册之前执行:App 源文件(strict_mode=1)可能继承 + # 或引用 includes 中的 struct(如 ast.AST)。若 includes struct 未注册, + # App 源文件翻译会失败 → .obj 缺失 → undefined reference。 + # 同时填充 PopulateIncludesDeps,供 Phase B+ 的 _BuildReachableSha1Set 使用。 + # 多遍扫描:解决跨文件继承问题(如 Constant(AST) 在 AST 未注册时被跳过)。 + if includes_dir is not None and includes_binary_dir is not None: + store_count_inc_pre: int = StubMergerStore.GetSha1StoreCount() + if store_count_inc_pre > 0: + store_sha1_inc_pre: bytes | t.CPtr = StubMergerStore.GetSha1StoreArrPtr() + store_rel_inc_pre: bytes | t.CPtr = StubMergerStore.GetSha1StoreRelArrPtr() + store_incdir_inc_pre: bytes | t.CPtr = StubMergerStore.GetSha1StoreIncdirArrPtr() + deps_filled_pre: int = 0 + PHASE_A_INC_MAX_PASSES: t.CInt = 3 + # [修复] 记录预注册失败的 includes:多遍后仍失败 → 报错终止编译。 + # 不允许静默降级——静默失败会让 App 源文件的跨模块类构造退化为 + # 普通函数调用(返回类型默认推断成 i32),调用点报误导性的 + # "跨模块调用 'parser.add_argument' 找不到模块 SHA1" + # (如 argparse.ArgumentParser 类未注册导致 parser 变量类型崩坏)。 + # declare_only=1 时 import 的 SHA1 检查跳过(容忍依赖未注册), + # 因此预注册失败只可能是文件自身无法翻译(语法/解析/编译错误)。 + # 注意:Sha1Store 因 AppendToSha1MapStore 追加了 App 源文件 SHA1 + # (供跨模块 CDefine 查找),此处必须跳过 App 文件——App 文件的 + # 预注册由 Phase A-pre(遍历 entries,declare_only=1)负责。 + # App 文件是严格模式(仅本地+import 可见)且预注册阶段依赖未就绪, + # 若在此预注册必然失败,误报"预注册失败: main.vp"。 + inc_fail_flags: bytes = stdlib.malloc(store_count_inc_pre) + if inc_fail_flags is not None: + string.memset(inc_fail_flags, 1, store_count_inc_pre) + for pass_inc_i in range(PHASE_A_INC_MAX_PASSES): + struct_count_before_inc: int = GenApi.get_struct_count() + for si_inc in range(store_count_inc_pre): + inc_sha1_pre: str = store_sha1_inc_pre + t.CSizeT(si_inc) * 17 + inc_rel_pre: str = store_rel_inc_pre + t.CSizeT(si_inc) * StubMerger.MAX_REL_PATH_LEN + if inc_rel_pre is None or inc_rel_pre[0] == '\0': + continue + # 跳过 App 源文件(main.vp 等):由 Phase A-pre 预注册,不算失败 + is_app_file_inc: int = 0 + for i_app_inc in range(file_count): + ea_app_inc: t.CUInt64T = t.CUInt64T(entries) + i_app_inc * entry_size + ent_app_inc: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_app_inc, t.CPtr)) + if ent_app_inc is not None and ent_app_inc.Sha1 is not None \ + and string.strcmp(ent_app_inc.Sha1, inc_sha1_pre) == 0: + is_app_file_inc = 1 + break + if is_app_file_inc != 0 and inc_fail_flags is not None: + inc_fail_flags[si_inc] = 0 + continue + rel_len_pre: t.CSizeT = string.strlen(inc_rel_pre) + # 所属 includes 根目录(多目录逐条取自 IncDir 数组,空串回退 includes_dir) + incdir_pre: str = store_incdir_inc_pre + t.CSizeT(si_inc) * StubMerger.MAX_INC_DIR_LEN + if incdir_pre is None or incdir_pre[0] == '\0': + incdir_pre = includes_dir + incdir_len_pre: t.CSizeT = string.strlen(incdir_pre) + full_path_pre: bytes = stdlib.malloc(incdir_len_pre + rel_len_pre + 2) + if full_path_pre is None: + continue + viperlib.snprintf(full_path_pre, incdir_len_pre + rel_len_pre + 2, + "%s/%s", incdir_pre, inc_rel_pre) + pkg_inc_pre: str = GenApi.compute_package_from_relpath(mb, inc_rel_pre) + tr_inc_pre: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans( + mb, full_path_pre, inc_sha1_pre, pkg_inc_pre, 1) + stdlib.free(full_path_pre) + if tr_inc_pre is not None: + # 预注册成功:清除失败标记 + if inc_fail_flags is not None: + inc_fail_flags[si_inc] = 0 + # 依赖填充只在第一遍执行(PopulateIncludesDeps 内部有去重) + # 注意:必须在 reset_to(mark2) 之前调用——内部深拷贝到 stdlib + if pass_inc_i == 0 and tr_inc_pre._imported_modules is not None \ + and StubMergerStore.PopulateIncludesDeps( + inc_sha1_pre, tr_inc_pre._imported_modules) == 0: + deps_filled_pre = deps_filled_pre + 1 + # OOM 清理:回收本 includes 文件预注册翻译的瞬时数据 + # (AST/tokens/lexer/IR/Handler);struct 注册表条目 stdlib 分配不受影响 + mb.reset_to(mark2) + struct_count_after_inc: int = GenApi.get_struct_count() + # 收敛检查:本遍没有新结构体注册 → 所有类已注册 + if struct_count_after_inc == struct_count_before_inc: + break + # 多遍后仍预注册失败的 includes → 报错终止(不允许降级) + if inc_fail_flags is not None: + for si_inc_f in range(store_count_inc_pre): + if inc_fail_flags[si_inc_f] != 0: + rel_f: str = store_rel_inc_pre + t.CSizeT(si_inc_f) * StubMerger.MAX_REL_PATH_LEN + fb_inc_f: str = VLogger.fmt_buf() + if fb_inc_f is not None: + viperlib.snprintf(fb_inc_f, 1024, + "includes 预注册失败: %s(文件无法翻译,可能是语法/解析/编译错误),终止编译", + rel_f) + VLogger.error(fb_inc_f, "prePhaseA") + sys.exit(1) + stdlib.free(inc_fail_flags) + fb_inc_pre: str = VLogger.fmt_buf() + if fb_inc_pre is not None: + viperlib.snprintf(fb_inc_pre, 1024, "includes 预注册 + 依赖填充: %d/%d", deps_filled_pre, store_count_inc_pre) + VLogger.info(fb_inc_pre, "prePhaseA") + + # === Phase A-pre: 预注册所有源文件的 struct/enum/union === + # 解决循环引用问题:circ_a 翻译时需要知道 circ_b.ClassB 的 struct 定义 + # 仅注册 struct/enum/union(declare_only=1),不翻译方法体 + # 多遍扫描:解决跨文件继承的字母序问题(如 HandlesAnnAssign.vp/.py 在 HandlesBase.vp/.py 之前, + # AnnAssignHandle 继承 Mixin 时 Mixin 未注册)。每遍注册新类后,下一遍子类可继承。 + VLogger.info("预注册 struct/enum/union...", "PhaseA") + src_dir_len_pre: t.CSizeT = string.strlen(source_dir) + PHASE_A_PRE_MAX_PASSES: t.CInt = 3 + for pass_i in range(PHASE_A_PRE_MAX_PASSES): + struct_count_before: int = GenApi.get_struct_count() + for i in range(file_count): + ea_pre: t.CUInt64T = t.CUInt64T(entries) + i * entry_size + ent_pre: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_pre, t.CPtr)) + if ent_pre is None or ent_pre.Path is None: + continue + pkg_pre: str = None + if string.strlen(ent_pre.Path) > src_dir_len_pre + 1: + rel_path_pre: str = ent_pre.Path + src_dir_len_pre + 1 + pkg_pre = GenApi.compute_package_from_relpath(mb, rel_path_pre) + tr_pre: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, ent_pre.Path, ent_pre.Sha1, pkg_pre, 1) + if tr_pre is None: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "预注册失败: %s", ent_pre.Path) + VLogger.error(fb, "PhaseA") + # OOM 清理:回收本 App 文件预注册翻译的瞬时数据 + mb.reset_to(mark2) + struct_count_after: int = GenApi.get_struct_count() + # 收敛检查:本遍没有新结构体注册 → 所有类已注册 + if struct_count_after == struct_count_before: + break + VLogger.info("预注册完成", "PhaseA") + + PHASE_A_IR_SIZE: t.CSizeT = 1048576 + td_len_pa: t.CSizeT = string.strlen(temp_dir) + + # 设置 temp 目录路径,使 HandlesExprCall 能读取依赖模块的 text.ll + # 用于跨模块方法返回类型查找(避免指针返回值被截断为 i32) + GenApi.SetTempDir(temp_dir) + + # app_deps_buf: 收集所有 App 源文件的直接依赖模块名(空格分隔) + # 供 Phase B+ 的 _BuildReachableSha1Set 作为初始 worklist 使用 + # 声明已在 if 块外,此处仅赋值 + app_deps_buf = stdlib.malloc(APP_DEPS_BUF_SIZE) + app_deps_len = 0 + if app_deps_buf is not None: + app_deps_buf[0] = '\0' + + # Phase A 多遍重试:同项目多源文件时,main.vp 可能先于其 import 的 + # mbuddytest.vp 翻译(文件系统顺序),跨模块函数返回类型精确解析会因 + # 依赖 text.ll 未生成而标记 _deps_pending=1(见 CallGenMixin 跨模块 + # 返回类型解析段)。下遍重译即可命中(依赖已生成 text.ll)。 + # 每遍至少完成一个文件,最多 file_count 遍收敛。 + done_flags: bytes = stdlib.malloc(file_count) + if done_flags is None: + VLogger.error("Phase A done_flags 分配失败", "PhaseA") + stdlib.free(entries) + return 1 + string.memset(done_flags, 0, file_count) + PHASE_A_MAX_PASSES: t.CInt = 32 + for pass_a in range(PHASE_A_MAX_PASSES): + completed_this_pass: int = 0 + for i in range(file_count): + if done_flags[i] != 0: + continue + ea: t.CUInt64T = t.CUInt64T(entries) + i * entry_size + ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr)) + if ent is None or ent.Path is None: + done_flags[i] = 1 + completed_this_pass += 1 + continue + # 计算源文件的包名(相对 source_dir 的目录部分) + src_dir_len_pa: t.CSizeT = string.strlen(source_dir) + pkg_pa: str = None + if string.strlen(ent.Path) > src_dir_len_pa + 1: + rel_path_pa: str = ent.Path + src_dir_len_pa + 1 + pkg_pa = GenApi.compute_package_from_relpath(mb, rel_path_pa) + tr_a: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, ent.Path, ent.Sha1, pkg_pa, 0, temp_dir) + if tr_a is None: + # 翻译失败(语法/解析错误):记录待下遍重试,收敛检查统一报错 + # OOM 清理:失败翻译也已产生 AST/tokens 瞬时数据,立即回收 + mb.reset_to(mark2) + continue + # 收集 _imported_modules 到 app_deps_buf(供 Phase B+ 按需编译)。 + # 依赖在翻译早期已填充,即使 _deps_pending 也收集。 + if tr_a._imported_modules is not None and app_deps_buf is not None: + # 逐模块去重拼接:多个 App 文件 import 同一模块(builtins/ + # _list/_dict/stdlib/t/c 等公共依赖)会让 app_deps 无去重 + # 膨胀到接近 64KB,_BuildReachableSha1Set 的初始 worklist + # 即满 → BFS 展开必报"依赖 worklist 溢出"。 + im_len_a: t.CSizeT = string.strlen(tr_a._imported_modules) + im_pos_a: t.CSizeT = 0 + while im_pos_a < im_len_a: + im_start_a: t.CSizeT = im_pos_a + while im_pos_a < im_len_a and tr_a._imported_modules[im_pos_a] != ' ': + im_pos_a += 1 + im_mod_len: t.CSizeT = im_pos_a - im_start_a + if im_pos_a < im_len_a: + im_pos_a += 1 + if im_mod_len == 0: + continue + im_mod_buf: bytes = stdlib.malloc(im_mod_len + 1) + if im_mod_buf is None: + continue + string.strncpy(im_mod_buf, tr_a._imported_modules + im_start_a, im_mod_len) + im_mod_buf[im_mod_len] = '\0' + # 已在 app_deps 中则跳过(词边界精确匹配) + if app_deps_len > 0 and GenApi.is_module_imported(app_deps_buf, im_mod_buf) != 0: + stdlib.free(im_mod_buf) + continue + if app_deps_len + im_mod_len + 2 < APP_DEPS_BUF_SIZE: + if app_deps_len > 0: + app_deps_buf[app_deps_len] = ' ' + app_deps_len = app_deps_len + 1 + string.strcpy(app_deps_buf + app_deps_len, im_mod_buf) + app_deps_len = app_deps_len + im_mod_len + app_deps_buf[app_deps_len] = '\0' + stdlib.free(im_mod_buf) + if tr_a._deps_pending != 0: + # 依赖模块 text.ll 未生成(同项目文件顺序),不写盘,下遍重试 + fb_dp: str = VLogger.fmt_buf() + if fb_dp is not None: + viperlib.snprintf(fb_dp, 1024, + "Phase A 依赖未就绪,下遍重试: %s", ent.Path) + # --nowarn-register 亦抑制此类 Phase A 依赖重试 WARN(刷屏收敛) + if VLogger.nowarn_register() == 0: + VLogger.warning(fb_dp, "PhaseA-DBG") + # 回滚本文件已注册类的 MethodsEmitted:第 1 遍 _translate_oop_methods + # 发射方法体前已置 MethodsEmitted=1(防重入),但方法体内跨模块调用 + # 依赖 text.ll 未生成触发 _deps_pending → 本遍作废;若不回滚, + # 下遍重译 existing 分支被 MethodsEmitted==1 防重复检查拦截 → 类方法 + # 永不发射 → 链接 undefined symbol(追加87 根因)。 + # 必须先于 mb.reset_to(mark2)(MethodsEmitted 在 perm_pool 上跨 reset 存活)。 + if ent.Sha1 is not None: + GenApi.reset_module_methods_emitted(ent.Sha1) + # OOM 清理:本文件翻译已产生瞬时数据(下遍会重新翻译),立即回收 + mb.reset_to(mark2) + continue + + # dump stub IR (declarations only) + stub_buf_a: bytes = stdlib.malloc(PHASE_A_IR_SIZE) + if stub_buf_a is None: + VLogger.error("stub 缓冲区分配失败", "PhaseA") + tr_a.dump_ir(stub_buf_a, PHASE_A_IR_SIZE, llvmlite.OUTPUT_STUB) + stub_len_a: t.CSizeT = string.strlen(stub_buf_a) + + # save stub.ll (切片路径: temp_dir/{sha1前缀}/{sha1}.stub.ll) + stub_path_a: str = StubMergerCollect._sliced_path(temp_dir, td_len_pa, ent.Sha1, "stub.ll") + if stub_path_a is not None: + sf_a: fileio.File | t.CPtr = fileio.File(stub_path_a, fileio.MODE.W) + if not sf_a.closed: + sf_a.write(stub_buf_a, stub_len_a) + sf_a.close() + stdlib.free(stub_path_a) + stdlib.free(stub_buf_a) + + # dump text IR (definitions only) + text_buf_a: bytes = stdlib.malloc(PHASE_A_IR_SIZE) + if text_buf_a is None: + VLogger.error("text 缓冲区分配失败", "PhaseA") + tr_a.dump_ir(text_buf_a, PHASE_A_IR_SIZE, llvmlite.OUTPUT_TEXT) + text_len_a: t.CSizeT = string.strlen(text_buf_a) + + # save text.ll (切片路径) + text_path_a: str = StubMergerCollect._sliced_path(temp_dir, td_len_pa, ent.Sha1, "text.ll") + if text_path_a is not None: + tf_a: fileio.File | t.CPtr = fileio.File(text_path_a, fileio.MODE.W) + if not tf_a.closed: + tf_a.write(text_buf_a, text_len_a) + tf_a.close() + stdlib.free(text_path_a) + stdlib.free(text_buf_a) + + # save dependencies (_imported_modules) for Phase B (切片路径) + deps_path_a: str = StubMergerCollect._sliced_path(temp_dir, td_len_pa, ent.Sha1, "deps.txt") + if deps_path_a is not None: + df_a: fileio.File | t.CPtr = fileio.File(deps_path_a, fileio.MODE.W) + if not df_a.closed: + if tr_a._imported_modules is not None: + dl_a: t.CSizeT = string.strlen(tr_a._imported_modules) + df_a.write(tr_a._imported_modules, dl_a) + df_a.close() + stdlib.free(deps_path_a) + + done_flags[i] = 1 + completed_this_pass += 1 + # OOM 清理:stub/text/deps 已写盘,回收本文件翻译瞬时数据 + # (AST/tokens/lexer/IR/Handler);app_deps_buf 已深拷贝依赖,不受影响 + mb.reset_to(mark2) + # 收敛检查:所有文件完成则结束 + all_done: int = 1 + for i_ck in range(file_count): + if done_flags[i_ck] == 0: + all_done = 0 + break + if all_done != 0: + break + if completed_this_pass == 0: + # 无进展:剩余文件无法完成(真实编译错误),终止并列出未完成文件 + for i_err in range(file_count): + if done_flags[i_err] == 0: + ea_err: t.CUInt64T = t.CUInt64T(entries) + i_err * entry_size + ent_err: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_err, t.CPtr)) + if ent_err is not None and ent_err.Path is not None: + fb_err: str = VLogger.fmt_buf() + if fb_err is not None: + viperlib.snprintf(fb_err, 1024, + "Phase A 无法完成翻译: %s(请检查依赖模块是否已编译/注册)", ent_err.Path) + VLogger.error(fb_err, "PhaseA") + stdlib.free(done_flags) + VLogger.error("Phase A 多遍收敛失败,终止编译", "PhaseA") + stdlib.free(entries) + return 1 + stdlib.free(done_flags) + + if do_phase2 == 0: + VLogger.info("Phase A 完成(仅 stub 生成)", "project") + if app_deps_buf is not None: + stdlib.free(app_deps_buf) + stdlib.free(entries) + return 0 + + # === 3. Phase B: 编译每个文件为 .obj === + if do_phase2 != 0: + if log is not None: + log.banner("Phase B: 编译 .obj") + + # 收集 .obj 路径(增大到 64KB,避免 includes .obj 路径溢出导致链接丢失符号) + # reachable_set/reachable_count: Phase B+ 填充,Phase C 用于按需链接 + reachable_set: bytes = None + reachable_count: int = 0 + OBJ_PATHS_SIZE: t.CSizeT = 65536 + obj_paths: bytes = stdlib.malloc(OBJ_PATHS_SIZE) + if obj_paths is None: + return 1 + obj_paths[0] = '\0' + obj_pos: t.CSizeT = 0 + # main_obj_path: 存放定义了用户 main 的 .obj 路径(链接时放在最前面, + # 避免 --allow-multiple-definition 选择了其他模块的 wrapper main) + main_obj_path: bytes = stdlib.malloc(512) + if main_obj_path is None: + return 1 + main_obj_path[0] = '\0' + compiled_count: int = 0 + + # 组合 IR 缓冲区大小(4MB,足够容纳本地 stub + 所有依赖 stub + 本地 text) + COMBINED_IR_SIZE: t.CSizeT = 4194304 + + # llc 任务表(stdlib.malloc,跨线程存活):连续 LlcTask 记录数组, + # 循环内只写 .ll + 构造任务,循环后 run_llc_parallel 分批并行跑 llc + llc_tasks: bytes = stdlib.malloc(t.CSizeT(file_count) * BuildPipeline.LlcTask.__sizeof__()) + if llc_tasks is None: + VLogger.error("llc 任务表分配失败", "PhaseB") + return 1 + llc_task_count: int = 0 + + for i in range(file_count): + ea: t.CUInt64T = t.CUInt64T(entries) + i * entry_size + ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr)) + if ent is None or ent.Path is None or ent.Sha1 is None: + continue + # 组合本地 stub + 所有依赖 stub + 本地 text → 完整 IR + combined_ir: bytes = stdlib.malloc(COMBINED_IR_SIZE) + if combined_ir is None: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "combined_ir 分配失败: %s", ent.Path) + VLogger.error(fb, "PhaseB") + continue + combined_len: t.CSizeT = StubMergerBuild.BuildCombinedIR(temp_dir, ent.Sha1, combined_ir, COMBINED_IR_SIZE) + if combined_len == 0: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "BuildCombinedIR 失败: %s", ent.Path) + VLogger.error(fb, "PhaseB") + stdlib.free(combined_ir) + continue + + # 写 .ll(llc 线程只读此文件);llc 本身改为循环后批量并行 + ret_w: int = BuildPipeline.write_ir_to_file(combined_ir, combined_len, temp_dir, ent.Sha1) + stdlib.free(combined_ir) + if ret_w != 0: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "写 .ll 失败: %s", ent.Path) + VLogger.error(fb, "PhaseB") + sys.exit(1) + + # 构造 llc 任务(命令串 stdlib.malloc,线程运行期不被 reset 回收) + llc_ir_path: str = BuildPipeline.build_sliced_path(temp_dir, ent.Sha1, "ll") + if llc_ir_path is None: + VLogger.error("llc 输入路径构造失败", "PhaseB") + sys.exit(1) + tslot: BuildPipeline.LlcTask | t.CPtr = (BuildPipeline.LlcTask | t.CPtr)(t.CVoid( + t.CUInt64T(llc_tasks) + t.CSizeT(llc_task_count) * BuildPipeline.LlcTask.__sizeof__(), t.CPtr)) + if BuildPipeline.init_llc_task(tslot, llc_ir_path, output_dir, ent.Sha1, + cc_cmd, cc_flags) != 0: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "llc 任务构造失败: %s", ent.Path) + VLogger.error(fb, "PhaseB") + sys.exit(1) + llc_task_count += 1 + + compiled_count += 1 + # 显示已提交 llc 的文件 + fb_comp: str = VLogger.fmt_buf() + if fb_comp is not None: + viperlib.snprintf(fb_comp, 1024, "[%d/%d] llc 已提交: %s", i + 1, file_count, ent.Path) + VLogger.info(fb_comp, "PhaseB") + # 构造 .obj 路径,检测是否是 main 模块(test_main.vp/.py 或 main.vp/.py) + od_len: t.CSizeT = string.strlen(output_dir) + is_main_mod: int = 0 + if string.strstr(ent.Path, "test_main.vp") is not None or string.strstr(ent.Path, "test_main.py") is not None: + is_main_mod = 1 + elif string.strstr(ent.Path, "main.vp") is not None or string.strstr(ent.Path, "main.py") is not None: + is_main_mod = 1 + + # 切片路径: output_dir/{sha1前缀}/{sha1}.obj + obj_path_sliced: str = StubMergerCollect._sliced_path(output_dir, od_len, ent.Sha1, "obj") + if obj_path_sliced is not None: + op_sliced_len: t.CSizeT = string.strlen(obj_path_sliced) + if is_main_mod != 0: + # main 模块: 复制到 main_obj_path(确保链接时 main 在最前) + if op_sliced_len < 512: + string.strcpy(main_obj_path, obj_path_sliced) + else: + VLogger.error("main_obj_path 缓冲区不足,终止编译", "PhaseB") + else: + # 其他模块: 追加到 obj_paths + if obj_pos + op_sliced_len + 2 < OBJ_PATHS_SIZE: + if obj_pos > 0: + obj_paths[obj_pos] = ' ' + obj_pos += 1 + string.strcpy(obj_paths + obj_pos, obj_path_sliced) + obj_pos += op_sliced_len + obj_paths[obj_pos] = '\0' + else: + VLogger.error(".obj 路径缓冲区不足", "PhaseB") + stdlib.free(obj_path_sliced) + + # 并行执行全部 llc(分批 LLC_MAX_THREADS 线程) + ret_p: int = BuildPipeline.run_llc_parallel(llc_tasks, llc_task_count, + BuildPipeline.LLC_MAX_THREADS) + if ret_p != 0: + VLogger.error("llc 编译失败,终止编译", "PhaseB") + sys.exit(1) + + # 释放 llc 任务(命令串 + 记录) + ti: int = 0 + while ti < llc_task_count: + tfree: BuildPipeline.LlcTask | t.CPtr = (BuildPipeline.LlcTask | t.CPtr)(t.CVoid( + t.CUInt64T(llc_tasks) + t.CSizeT(ti) * BuildPipeline.LlcTask.__sizeof__(), t.CPtr)) + BuildPipeline.free_llc_task(tfree) + ti += 1 + stdlib.free(llc_tasks) + + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "编译完成: %d/%d", compiled_count, file_count) + VLogger.success(fb, "PhaseB") + + if compiled_count == 0: + VLogger.error("无成功编译的文件", "PhaseB") + stdlib.free(entries) + return 1 + + # === 3.5 编译缺失的 includes 文件(按依赖图按需编译)=== + # 只编译被 App 源文件直接/间接引用的 includes 文件(可达集合), + # 而非遍历整个 includes 目录。通过 _BuildReachableSha1Set 构建依赖图。 + if includes_dir is not None and includes_binary_dir is not None: + inc_compiled: int = 0 + td_len_mi: t.CSizeT = string.strlen(temp_dir) + + # 诊断日志:确认 Phase B+ 入口和 Sha1Store 状态 + fb_pbp_enter: str = VLogger.fmt_buf() + if fb_pbp_enter is not None: + viperlib.snprintf(fb_pbp_enter, 1024, + "PhaseB+ 入口: store_count=%d includes_binary_dir=%s", + StubMergerStore.GetSha1StoreCount(), includes_binary_dir) + VLogger.info(fb_pbp_enter, "PhaseB+") + + # 创建 includes_binary_dir 目录(确保 .obj 能写入和 collect_obj_files 能扫描) + BuildPipeline.ensure_dir(includes_binary_dir) + + # declare_only 预处理已移至 Phase A 之前(Phase A-pre-inc), + # 确保 Phase A 翻译 App 源文件时 includes struct 已注册。 + # PopulateIncludesDeps 已在 Phase A-pre-inc 中填充。 + + # 构建可达 SHA1 集合(依赖图遍历) + # app_deps_buf 为 None 时回退到扫描 source_dir(非递归) + REACHABLE_SET_SIZE: t.CSizeT = t.CSizeT(StubMerger.MAX_INCLUDES_SHA1) * 17 + reachable_set: bytes = stdlib.malloc(REACHABLE_SET_SIZE) + reachable_count: int = 0 + if reachable_set is not None: + string.memset(reachable_set, 0, REACHABLE_SET_SIZE) + reachable_count = StubMergerBuild._BuildReachableSha1Set( + mb, source_dir, temp_dir, reachable_set, app_deps_buf) + fb_reach: str = VLogger.fmt_buf() + if fb_reach is not None: + viperlib.snprintf(fb_reach, 1024, "可达 includes SHA1: %d 个", reachable_count) + VLogger.info(fb_reach, "PhaseB+") + # fast-fail: 可达集合构建失败(依赖未找到),永不回退,直接终止 + if reachable_count < 0: + VLogger.error("可达集合构建失败(fast-fail),终止编译", "PhaseB+") + return 1 + else: + VLogger.error("reachable_set 分配失败,终止编译", "PhaseB+") + return 1 + + # 释放 app_deps_buf(已构建完 reachable_set,不再需要) + if app_deps_buf is not None: + stdlib.free(app_deps_buf) + app_deps_buf = None + + # 从全局存储器获取 SHA1/模块名 数组:复制局部副本(bytes), + # 避免 store 联合返回值(bytes|t.CPtr)跨函数传参/索引的地址异常 + # (与 _BuildReachableSha1Set 的 BFS 一致)。 + # rel/incdir 仅本函数内按索引读取(不跨函数传参),保留 store 指针。 + td_len_pb: t.CSizeT = string.strlen(temp_dir) + store_sha1_arr_mi: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 17) + store_mod_arr_mi: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 64) + store_count_mi: int = 0 + if store_sha1_arr_mi is not None and store_mod_arr_mi is not None: + store_count_mi = StubMergerIR._BuildIncludesSha1Map( + temp_dir, td_len_pb, store_sha1_arr_mi, store_mod_arr_mi) + store_rel_arr_mi: bytes | t.CPtr = StubMergerStore.GetSha1StoreRelArrPtr() + store_incdir_arr_mi: bytes | t.CPtr = StubMergerStore.GetSha1StoreIncdirArrPtr() + if store_count_mi > 0: + + # 拓扑排序可达 includes:被依赖模块先完整翻译。跨模块 vtable 生成 + # 需要依赖模块的函数 TypeStr 已注册到全局表(如 astaux 继承 base 的 AST) + topo_idx: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(stdlib.malloc(8 * (store_count_mi + 1))) + topo_count: int = 0 + if topo_idx is None: + VLogger.error("拓扑排序索引分配失败,终止编译", "PhaseB+") + topo_count = 0 + else: + topo_count = StubMergerTopo.BuildTopoSortedIndices( + store_count_mi, store_sha1_arr_mi, store_mod_arr_mi, + reachable_set, reachable_count, topo_idx) + + for si_mi in range(topo_count): + # 当前条目(拓扑序索引,仅含可达模块) + ti: int = topo_idx[si_mi] + # 获取当前条目的 SHA1 和 rel_path + inc_sha1_mi: str = store_sha1_arr_mi + t.CSizeT(ti) * 17 + inc_rel_mi: str = store_rel_arr_mi + t.CSizeT(ti) * StubMerger.MAX_REL_PATH_LEN + # 检查 .obj 是否已存在于 includes.binary(切片子目录) + ibd_len_mi: t.CSizeT = string.strlen(includes_binary_dir) + check_pat_mi: str = StubMergerCollect._sliced_path(includes_binary_dir, ibd_len_mi, inc_sha1_mi, "obj") + check_fd_mi: w32.win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__()) + obj_exists_mi: int = 0 + if check_pat_mi is not None and check_fd_mi is not None: + string.memset(check_fd_mi, 0, w32.win32file.WIN32_FIND_DATAA.__sizeof__()) + check_h_mi: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(check_pat_mi, check_fd_mi) + if check_h_mi != w32.win32base.INVALID_HANDLE_VALUE: + w32.win32file.FindClose(check_h_mi) + obj_exists_mi = 1 + if obj_exists_mi != 0: + if check_pat_mi is not None: + stdlib.free(check_pat_mi) + stdlib.free(check_fd_mi) + continue + + # .obj 不存在,需要编译 + # 构造源文件路径: {所属 includes 根目录}/{rel_path}(多目录逐条取 IncDir,空串回退 includes_dir) + rel_path_len_mi: t.CSizeT = string.strlen(inc_rel_mi) + incdir_mi: str = store_incdir_arr_mi + t.CSizeT(ti) * StubMerger.MAX_INC_DIR_LEN + if incdir_mi is None or incdir_mi[0] == '\0': + incdir_mi = includes_dir + inc_dir_len_mi: t.CSizeT = string.strlen(incdir_mi) + src_fp_mi: bytes = stdlib.malloc(inc_dir_len_mi + 1 + rel_path_len_mi + 1) + if src_fp_mi is None: + stdlib.free(check_pat_mi) + if check_fd_mi is not None: + stdlib.free(check_fd_mi) + VLogger.error("includes 源路径分配失败,终止编译", "PhaseB+") + viperlib.snprintf(src_fp_mi, inc_dir_len_mi + 1 + rel_path_len_mi + 1, + "%s/%s", incdir_mi, inc_rel_mi) + + # 检查是否为声明文件(只有 declare 没有实质 define) + # 判断方法: text.ll 中若有混淆函数 define(含 @")则为实现文件 + is_decl_mi: int = -1 + tpath_mi: str = StubMergerCollect._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll") + if tpath_mi is not None: + tf_mi: fileio.File | t.CPtr = fileio.File(tpath_mi, fileio.MODE.R) + if not tf_mi.closed: + is_decl_mi = 1 + tbuf_mi: bytes = stdlib.malloc(StubMerger.STUB_READ_BUF_SIZE) + tbr_mi: t.CInt64T = 0 + if tbuf_mi is not None: + tbr_mi = tf_mi.read_all(tbuf_mi, StubMerger.STUB_READ_BUF_SIZE) + if tbuf_mi is not None and tbr_mi > 0: + if tbr_mi < StubMerger.STUB_READ_BUF_SIZE: + tbuf_mi[tbr_mi] = '\0' + else: + tbuf_mi[StubMerger.STUB_READ_BUF_SIZE - 1] = '\0' + # 逐行扫描: 找 define 行即为实现文件 + # (不再要求行中含 @",因为 memhub 等模块的函数名 + # 如 @ca40915f11b8b6ad._align_up 不带引号但仍是实现文件) + tpos_mi: t.CSizeT = 0 + while tpos_mi < tbr_mi: + tls_mi: t.CSizeT = tpos_mi + while tpos_mi < tbr_mi: + if tbuf_mi[tpos_mi] == '\n': + break + tpos_mi += 1 + tll_mi: t.CSizeT = tpos_mi - tls_mi + if tpos_mi < tbr_mi: + tpos_mi += 1 + if tll_mi >= 7 and string.strncmp(tbuf_mi + tls_mi, "define ", 7) == 0: + is_decl_mi = 0 + break + stdlib.free(tbuf_mi) + tf_mi.close() + stdlib.free(tpath_mi) + # is_decl_mi == -1: text.ll 不存在(Phase1 未翻译此文件) + # is_decl_mi == 1: 声明文件(仅 declare 无 define) + # is_decl_mi == 0: 实现文件(有 define) + # 只跳过声明文件(is_decl_mi == 1);text.ll 不存在时继续,让后续翻译逻辑处理 + if is_decl_mi == 1: + stdlib.free(check_pat_mi) + if check_fd_mi is not None: + stdlib.free(check_fd_mi) + stdlib.free(src_fp_mi) + continue + + # 尝试 BuildCombinedIR(stub/text 应已由 Phase1 生成) + inc_combined_mi: bytes = stdlib.malloc(COMBINED_IR_SIZE) + inc_combined_len_mi: t.CSizeT = 0 + if inc_combined_mi is not None: + inc_combined_len_mi = StubMergerBuild.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE) + + # 如果 stub/text 不存在,翻译源文件并保存 stub + text,然后重试 + if inc_combined_len_mi == 0 and inc_combined_mi is not None: + # 计算 includes 文件的包名(相对 includes_dir 的目录部分) + inc_pkg_mi: str = None + if string.strlen(src_fp_mi) > inc_dir_len_mi + 1: + inc_rel_mi2: str = src_fp_mi + inc_dir_len_mi + 1 + inc_pkg_mi = GenApi.compute_package_from_relpath(mb, inc_rel_mi2) + tr_mi: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, src_fp_mi, inc_sha1_mi, inc_pkg_mi) + if tr_mi is not None: + PBP_IR_SIZE: t.CSizeT = 1048576 + # 保存 stub.ll (切片路径) + inc_stub_buf: bytes = stdlib.malloc(PBP_IR_SIZE) + if inc_stub_buf is not None: + tr_mi.dump_ir(inc_stub_buf, PBP_IR_SIZE, llvmlite.OUTPUT_STUB) + inc_stub_len: t.CSizeT = string.strlen(inc_stub_buf) + inc_stub_path: str = StubMergerCollect._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "stub.ll") + if inc_stub_path is not None: + isf: fileio.File | t.CPtr = fileio.File(inc_stub_path, fileio.MODE.W) + if not isf.closed: + isf.write(inc_stub_buf, inc_stub_len) + isf.close() + stdlib.free(inc_stub_path) + stdlib.free(inc_stub_buf) + # 保存 text.ll (切片路径) + inc_text_buf: bytes = stdlib.malloc(PBP_IR_SIZE) + if inc_text_buf is not None: + tr_mi.dump_ir(inc_text_buf, PBP_IR_SIZE, llvmlite.OUTPUT_TEXT) + inc_text_len: t.CSizeT = string.strlen(inc_text_buf) + inc_text_path: str = StubMergerCollect._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll") + if inc_text_path is not None: + itf: fileio.File | t.CPtr = fileio.File(inc_text_path, fileio.MODE.W) + if not itf.closed: + itf.write(inc_text_buf, inc_text_len) + itf.close() + stdlib.free(inc_text_path) + stdlib.free(inc_text_buf) + # 重试 BuildCombinedIR + inc_combined_len_mi = StubMergerBuild.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE) + # OOM 清理:stub/text 已写盘,回收本 includes 文件翻译瞬时数据 + # (AST/tokens/lexer/IR/Handler);BuildCombinedIR 只读文件,不受影响 + mb.reset_to(mark2) + + if inc_combined_len_mi == 0: + # 诊断:检查 stub.ll/text.ll 是否存在 + diag_stub: str = StubMergerCollect._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "stub.ll") + diag_text: str = StubMergerCollect._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll") + diag_stub_ex: int = 0 + diag_text_ex: int = 0 + if diag_stub is not None: + df_diag_s: fileio.File | t.CPtr = fileio.File(diag_stub, fileio.MODE.R) + if not df_diag_s.closed: + diag_stub_ex = 1 + df_diag_s.close() + stdlib.free(diag_stub) + if diag_text is not None: + df_diag_t: fileio.File | t.CPtr = fileio.File(diag_text, fileio.MODE.R) + if not df_diag_t.closed: + diag_text_ex = 1 + df_diag_t.close() + stdlib.free(diag_text) + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, + "BuildCombinedIR 失败: %s (stub=%d text=%d is_decl=%d)", + src_fp_mi, diag_stub_ex, diag_text_ex, is_decl_mi) + VLogger.error(fb, "PhaseB+") + if inc_combined_mi is not None: + stdlib.free(inc_combined_mi) + stdlib.free(check_pat_mi) + if check_fd_mi is not None: + stdlib.free(check_fd_mi) + stdlib.free(src_fp_mi) + continue + + # 编译为 .obj(输出到 includes_binary_dir,与存在性检查和链接收集一致) + inc_cret_mi: int = BuildPipeline.compile_module_to_obj( + inc_combined_mi, inc_combined_len_mi, temp_dir, includes_binary_dir, inc_sha1_mi, + cc_cmd, cc_flags) + stdlib.free(inc_combined_mi) + + if inc_cret_mi != 0: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "llc 编译失败,终止编译: %s", src_fp_mi) + VLogger.error(fb, "PhaseB+") + sys.exit(1) + + inc_compiled += 1 + # 显示编译完成的 includes 文件 + fb_inc_comp: str = VLogger.fmt_buf() + if fb_inc_comp is not None: + viperlib.snprintf(fb_inc_comp, 1024, "[includes %d] 编译完成: %s", inc_compiled, src_fp_mi) + VLogger.info(fb_inc_comp, "PhaseB+") + + # 添加到 obj_paths (切片路径,从 includes_binary_dir 取) + ibd_len_mi2: t.CSizeT = string.strlen(includes_binary_dir) + inc_obj_sliced: str = StubMergerCollect._sliced_path(includes_binary_dir, ibd_len_mi2, inc_sha1_mi, "obj") + + if inc_obj_sliced is not None: + inc_obj_len: t.CSizeT = string.strlen(inc_obj_sliced) + if obj_pos + inc_obj_len + 2 < OBJ_PATHS_SIZE: + if obj_pos > 0: + obj_paths[obj_pos] = ' ' + obj_pos += 1 + string.strcpy(obj_paths + obj_pos, inc_obj_sliced) + obj_pos += inc_obj_len + obj_paths[obj_pos] = '\0' + else: + VLogger.error("includes .obj 路径缓冲区溢出,终止编译", "PhaseB+") + stdlib.free(inc_obj_sliced) + + # 释放本次迭代的临时内存 + if check_pat_mi is not None: + stdlib.free(check_pat_mi) + + if check_fd_mi is not None: + stdlib.free(check_fd_mi) + + stdlib.free(src_fp_mi) + + # 释放拓扑排序索引与局部映射副本 + if topo_idx is not None: + stdlib.free(topo_idx) + if store_sha1_arr_mi is not None: + stdlib.free(store_sha1_arr_mi) + if store_mod_arr_mi is not None: + stdlib.free(store_mod_arr_mi) + + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "编译缺失 includes: %d 个", inc_compiled) + VLogger.info(fb, "PhaseB+") + + # 释放 app_deps_buf(Phase B+ 块未执行时此处兜底释放) + if app_deps_buf is not None: + stdlib.free(app_deps_buf) + app_deps_buf = None + + # === 4. Phase C: 链接所有 .obj → .exe === + if log is not None: + log.banner("Phase C: 链接") + + od_len2: t.CSizeT = string.strlen(output_dir) + lo_len: t.CSizeT = string.strlen(linker_output) + exe_path: bytes = stdlib.malloc(od_len2 + lo_len + 2) + if exe_path is not None: + viperlib.snprintf(exe_path, od_len2 + lo_len + 2, "%s/%s", output_dir, linker_output) + else: + exe_path = linker_output + VLogger.error("exe_path 分配失败,终止编译", "PhaseC") + + # 构造最终 .obj 路径列表:main_obj_path 在前,reachable .obj 在后 + final_obj_paths: bytes = stdlib.malloc(OBJ_PATHS_SIZE + 512) + if final_obj_paths is None: + stdlib.free(entries) + return 1 + final_obj_paths[0] = '\0' + fop_pos: t.CSizeT = 0 + # main_obj_path 放在最前面(确保 --allow-multiple-definition 选择用户 main) + if main_obj_path[0] != '\0': + mlen: t.CSizeT = string.strlen(main_obj_path) + string.strcpy(final_obj_paths, main_obj_path) + fop_pos = mlen + + # 合并 Phase B/B+ 编译的 App 非 main 模块 .obj(obj_paths,空格分隔)。 + # 此前 final_obj_paths 只含 main_obj + reachable includes,App 依赖文件 + # (main import 的 syslibtest_impl/os_backend 等)的 .obj 从未入链——追加28 + # 前靠 reachable 误含 App 时从 includes.binary 的重复 obj 兜底(undefined + # symbol: ae2038ced7b4634f.run 根因)。obj_paths 同时含 Phase B+ 本次 + # 新编译的 includes obj(与下方 reachable 收集重复,--allow-multiple- + # definition 容忍,仅本次编译的少量文件)。 + if obj_pos > 0: + if fop_pos + obj_pos + 1 < OBJ_PATHS_SIZE + 512: + if fop_pos > 0: + final_obj_paths[fop_pos] = ' ' + fop_pos += 1 + string.strcpy(final_obj_paths + fop_pos, obj_paths) + fop_pos += obj_pos + final_obj_paths[fop_pos] = '\0' + + # 按图链接:遍历 reachable_set,只收集可达 includes 的 .obj + # 不再全量收集 includes.binary 下的所有 .obj + if reachable_set is not None and reachable_count > 0: + ibd_len_pc: t.CSizeT = string.strlen(includes_binary_dir) + td_len_pc: t.CSizeT = string.strlen(temp_dir) + ri_pc: int + for ri_pc in range(reachable_count): + rsha1_pc: str = reachable_set + t.CSizeT(ri_pc) * 17 + if rsha1_pc[0] == '\0': + continue + obj_path_pc: str = StubMergerCollect._sliced_path(includes_binary_dir, ibd_len_pc, rsha1_pc, "obj") + if obj_path_pc is not None: + # 检查 .obj 文件是否存在 + cf_pc: fileio.File | t.CPtr = fileio.File(obj_path_pc, fileio.MODE.R) + if not cf_pc.closed: + cf_pc.close() + # .obj 存在,追加到 final_obj_paths + op_len_pc: t.CSizeT = string.strlen(obj_path_pc) + if fop_pos + op_len_pc + 2 < OBJ_PATHS_SIZE + 512: + if fop_pos > 0: + final_obj_paths[fop_pos] = ' ' + fop_pos += 1 + string.strcpy(final_obj_paths + fop_pos, obj_path_pc) + fop_pos += op_len_pc + final_obj_paths[fop_pos] = '\0' + else: + # .obj 缺失:纯声明模块(text.ll 无 define 行,如 stdio.vp 全 pass) + # 无需 .obj,静默跳过;实现文件缺失才是编译产物异常(fail-fast) + if StubMergerIR.IsDeclOnlyModule(temp_dir, td_len_pc, rsha1_pc) != 1: + fb_pc: str = VLogger.fmt_buf() + if fb_pc is not None: + viperlib.snprintf(fb_pc, 1024, "可达模块 .obj 缺失: %s", obj_path_pc) + VLogger.error(fb_pc, "PhaseC") + stdlib.free(obj_path_pc) + + final_obj_paths[fop_pos] = '\0' + obj_paths_len: t.CSizeT = fop_pos + + # 释放 reachable_set(Phase C 已使用完毕) + if reachable_set is not None: + stdlib.free(reachable_set) + reachable_set = None + + # 按图链接:不传 includes_binary_dir(传 None),避免全量收集 + lret: int = BuildPipeline.link_objs_to_exe( + final_obj_paths, obj_paths_len, + linker_cmd, linker_flags, exe_path, + None) + + if lret == 0: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "输出: %s", exe_path) + VLogger.success(fb, "PhaseC") + if args.get_bool("run"): + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "执行: %s", exe_path) + VLogger.info(fb, "run") + rp: subprocess.CompletedProcess | t.CPtr = subprocess.run(exe_path, False, False) + if rp is not None: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "退出码: %d", rp.returncode) + VLogger.info(fb, "run") + else: + VLogger.error("链接失败", "PhaseC") + stdlib.free(entries) + return 1 + + stdlib.free(entries) + return 0 diff --git a/App/lib/core/StubMerger.vp b/App/lib/core/StubMerger.vp index 11a25eb..229ab7c 100644 --- a/App/lib/core/StubMerger.vp +++ b/App/lib/core/StubMerger.vp @@ -1,80 +1,78 @@ -import t, c -from stdint import * -import memhub -import string -import stdlib -import llvmlite -import w32.win32file as win32file -import w32.win32base as win32base -import w32.fileio as fileio -import viperlib -import sys -import ast -import lib.core.VLogger as VLogger -import lib.core.IncludesScanner as IncludesScanner -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesTranslator as HandlesTranslator -import lib.core.BuildPipeline as BuildPipeline -import lib.StubGen.VpiReader as VpiReader -import lib.Projectrans.Utils as Utils -import lib.Projectrans.Config as Config - - -# ============================================================ -# StubMerger - stub 声明合并模块 -# -# 从 temp 目录加载所有 .stub.ll 文件,将声明内容合并到主 IR。 -# 这是 Phase2 的核心功能:翻译主文件时,将所有依赖的 stub -# 声明合并到主 IR 前面,使链接器能解析跨模块符号引用。 -# -# 合并策略: -# 1. 扫描 temp 目录,收集所有 {sha1}.stub.ll 文件 -# 2. 读取每个 stub 文件内容 -# 3. 过滤去重(避免重复声明) -# 4. 将声明插入到主 IR 的 target triple 之后 -# ============================================================ - -# 全局 mbuddy 指针 -_mbuddy: memhub.MemBuddy | t.CPtr - -# 最大 includes SHA1 数(用于过滤) -MAX_INCLUDES_SHA1: t.CDefine = 1024 -# stub 读取缓冲区大小 -STUB_READ_BUF_SIZE: t.CDefine = 1048576 -# 最大 includes 条目数 -MAX_INCLUDES: t.CDefine = 1024 -# 可达性分析 worklist/processed 缓冲区大小(8192 不够:递归扫描 source_dir -# 后 worklist 含全部 App 文件 imports 的拼接 + BFS 依赖展开,追加82 溢出) -REACH_WORKLIST_BUF: t.CDefine = 65536 - -# 全局 SHA1 映射存储器(内存中,不依赖 _sha1_map.txt 文件) -# Phase1 扫描完成后填充,供所有函数使用 -_sha1_store_arr: bytes # SHA1 数组(每个 17 字节,MAX_INCLUDES 个) -_sha1_store_mod: bytes # 模块名数组(每个 64 字节,MAX_INCLUDES 个) -_sha1_store_rel: bytes # 相对路径数组(每个 256 字节,MAX_INCLUDES 个) -_sha1_store_incdir: bytes # 所属 includes 根目录数组(每个 512 字节,MAX_INCLUDES 个,多 includes 支持) -_sha1_store_count: int # 条目数 - -# includes 依赖内存存储(不依赖 deps.txt 过程文件) -# Phase B+ 前用 declare_only 翻译所有 includes 文件,提取 _imported_modules 存入此处 -# _BuildReachableSha1Set 从此处读取依赖,不读 deps.txt -_includes_deps_sha1: bytes # SHA1 数组(每个 17 字节,MAX_INCLUDES 个) -_includes_deps_str: bytes # 依赖字符串数组(每个 512 字节,MAX_INCLUDES 个) -_includes_deps_count: int # 条目数 - -# BuildCombinedIR 全目录扫描缓存:Phase B 对每个源文件调用一次 BuildCombinedIR, -# 每次 _collect_stub_sha1s 递归扫描 temp_dir 全部切片子目录(O(N×S) 目录枚举, -# 90 文件 × 全目录是 Phase B 慢的根因之一)。按 temp_dir 缓存扫描结果, -# 首次扫描后复用,temp_dir 变化时自动重建。 -_stub_scan_cache_dir: str # 缓存对应的 temp_dir(None=未初始化) -_stub_scan_cache_arr: str # 扫描结果数组(每 17 字节一个 SHA1,MAX_INCLUDES_SHA1 个) -_stub_scan_cache_count: int # 收集数量 - -# 单条依赖字符串最大长度 -MAX_DEPS_STR_LEN: t.CDefine = 512 - -# rel_path 最大长度 -MAX_REL_PATH_LEN: t.CDefine = 256 -# includes 根目录最大长度(绝对路径,多 includes 支持) -MAX_INC_DIR_LEN: t.CDefine = 512 +import t, c +from stdint import * +import memhub +import string +import stdlib +import llvmlite +import w32.win32file as win32file +import w32.win32base as win32base +import w32.fileio as fileio +import viperlib +import sys +import ast +import lib.core.VLogger as VLogger +import lib.core.IncludesScanner as IncludesScanner +import lib.core.Handles.HandlesTranslator as HandlesTranslator +import lib.core.BuildPipeline as BuildPipeline +import lib.StubGen.VpiReader as VpiReader +import lib.Projectrans.Utils as Utils +import lib.Projectrans.Config as Config + + +# ============================================================ +# StubMerger - stub 声明合并模块 +# +# 从 temp 目录加载所有 .stub.ll 文件,将声明内容合并到主 IR。 +# 这是 Phase2 的核心功能:翻译主文件时,将所有依赖的 stub +# 声明合并到主 IR 前面,使链接器能解析跨模块符号引用。 +# +# 合并策略: +# 1. 扫描 temp 目录,收集所有 {sha1}.stub.ll 文件 +# 2. 读取每个 stub 文件内容 +# 3. 过滤去重(避免重复声明) +# 4. 将声明插入到主 IR 的 target triple 之后 +# ============================================================ + +# 全局 mbuddy 指针 +_mbuddy: memhub.MemBuddy | t.CPtr + +# 最大 includes SHA1 数(用于过滤) +MAX_INCLUDES_SHA1: t.CDefine = 1024 +# stub 读取缓冲区大小 +STUB_READ_BUF_SIZE: t.CDefine = 1048576 +# 最大 includes 条目数 +MAX_INCLUDES: t.CDefine = 1024 +# 可达性分析 worklist/processed 缓冲区大小(8192 不够:递归扫描 source_dir +# 后 worklist 含全部 App 文件 imports 的拼接 + BFS 依赖展开,追加82 溢出) +REACH_WORKLIST_BUF: t.CDefine = 65536 + +# 全局 SHA1 映射存储器(内存中,不依赖 _sha1_map.txt 文件) +# Phase1 扫描完成后填充,供所有函数使用 +_sha1_store_arr: bytes # SHA1 数组(每个 17 字节,MAX_INCLUDES 个) +_sha1_store_mod: bytes # 模块名数组(每个 64 字节,MAX_INCLUDES 个) +_sha1_store_rel: bytes # 相对路径数组(每个 256 字节,MAX_INCLUDES 个) +_sha1_store_incdir: bytes # 所属 includes 根目录数组(每个 512 字节,MAX_INCLUDES 个,多 includes 支持) +_sha1_store_count: int # 条目数 + +# includes 依赖内存存储(不依赖 deps.txt 过程文件) +# Phase B+ 前用 declare_only 翻译所有 includes 文件,提取 _imported_modules 存入此处 +# _BuildReachableSha1Set 从此处读取依赖,不读 deps.txt +_includes_deps_sha1: bytes # SHA1 数组(每个 17 字节,MAX_INCLUDES 个) +_includes_deps_str: bytes # 依赖字符串数组(每个 512 字节,MAX_INCLUDES 个) +_includes_deps_count: int # 条目数 + +# BuildCombinedIR 全目录扫描缓存:Phase B 对每个源文件调用一次 BuildCombinedIR, +# 每次 _collect_stub_sha1s 递归扫描 temp_dir 全部切片子目录(O(N×S) 目录枚举, +# 90 文件 × 全目录是 Phase B 慢的根因之一)。按 temp_dir 缓存扫描结果, +# 首次扫描后复用,temp_dir 变化时自动重建。 +_stub_scan_cache_dir: str # 缓存对应的 temp_dir(None=未初始化) +_stub_scan_cache_arr: str # 扫描结果数组(每 17 字节一个 SHA1,MAX_INCLUDES_SHA1 个) +_stub_scan_cache_count: int # 收集数量 + +# 单条依赖字符串最大长度 +MAX_DEPS_STR_LEN: t.CDefine = 512 + +# rel_path 最大长度 +MAX_REL_PATH_LEN: t.CDefine = 256 +# includes 根目录最大长度(绝对路径,多 includes 支持) +MAX_INC_DIR_LEN: t.CDefine = 512 diff --git a/App/lib/core/StubMergerBuild.vp b/App/lib/core/StubMergerBuild.vp index 3610544..56d55fa 100644 --- a/App/lib/core/StubMergerBuild.vp +++ b/App/lib/core/StubMergerBuild.vp @@ -1,1230 +1,1229 @@ -import t, c -from stdint import * -import memhub -import string -import stdlib -import llvmlite -import w32.win32file as win32file -import w32.win32base as win32base -import w32.fileio as fileio -import viperlib -import sys -import ast -import lib.core.VLogger as VLogger -import lib.core.IncludesScanner as IncludesScanner -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesTranslator as HandlesTranslator -import lib.core.BuildPipeline as BuildPipeline -import lib.StubGen.VpiReader as VpiReader -import lib.Projectrans.Utils as Utils -import lib.Projectrans.Config as Config - - -import lib.core.StubMergerCollect as StubMergerCollect -import lib.core.StubMergerStore as StubMergerStore -import lib.core.StubMergerTopo as StubMergerTopo -import lib.core.StubMergerIR as StubMergerIR -import lib.core.StubMerger as StubMerger - -# ============================================================ -# StubMergerBuild - StubMerger 拆分(阶段 E):StubMergerBuild -# -# 直接移动模式:函数实现迁至此模块,原 StubMerger.vp 仅保留 -# 常量/全局变量;调用方经本模块前缀访问。全局变量跨模块经 -# StubMerger._xxx 访问(main.vp 先例)。 -# ============================================================ - -# ============================================================ -# _LoadAndAppendStub - 加载依赖 stub 并追加到 out_buf -# -# 读取 {temp_dir}/{sha1}.stub.ll,跳过 header(;, target, source_filename), -# 去重 declare/global,追加到 out_buf。返回新 out_pos。 -# ============================================================ -def _LoadAndAppendStub(temp_dir: str, td_len: t.CSizeT, dep_sha1: str, - dep_buf: bytes, out_buf: bytes, out_size: t.CSizeT, - out_pos: t.CSizeT) -> t.CSizeT: - """加载依赖 stub 并追加(跳过 header,去重)""" - if temp_dir is None or dep_sha1 is None or dep_buf is None or out_buf is None: - return out_pos - - dep_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, dep_sha1, "stub.ll") - if dep_path is None: - return out_pos - df_ls: fileio.File | t.CPtr = fileio.File(dep_path, fileio.MODE.R) - if df_ls.closed: - stdlib.free(dep_path) - # 依赖 stub 缺失:includes 映射内的模块缺失属编译错误(fail-fast), - # 非映射模块(如 t/c 内部库、用户文件)按设计跳过 - if StubMergerStore.LookupSha1RelPath(dep_sha1) is not None: - fb_ls: str = VLogger.fmt_buf() - if fb_ls is not None: - viperlib.snprintf(fb_ls, 1024, "依赖 stub 缺失: %s", dep_sha1) - VLogger.error(fb_ls, "StubMerger") - return out_pos - dep_br_ls: t.CInt64T = df_ls.read_all(dep_buf, STUB_READ_BUF_SIZE) - df_ls.close() - stdlib.free(dep_path) - if dep_br_ls <= 0: - # 依赖 stub 为空:纯声明/纯常量模块(如 stdio.vp 全 pass、CDefine 模块) - # 无可声明符号,stub.ll 为空属合法形态,静默跳过 - return out_pos - if dep_br_ls < STUB_READ_BUF_SIZE: - dep_buf[dep_br_ls] = '\0' - else: - dep_buf[STUB_READ_BUF_SIZE - 1] = '\0' - - # 注释掉依赖 stub 中的字符串常量行(模块内部的,不需要) - # 简单方案:搜索 "= external unnamed_addr constant" 并将行首的 @ 改为 ;@ - cfs_pos: t.CSizeT = 0 - while cfs_pos + 30 < t.CSizeT(dep_br_ls): - ext_p: t.CPtr = string.strstr(dep_buf + cfs_pos, "= external unnamed_addr constant") - if ext_p is None: - break - ext_off2: t.CSizeT = t.CSizeT(t.CUInt64T(ext_p) - t.CUInt64T(dep_buf)) - # 向前查找行首的 @ - ls: t.CSizeT = ext_off2 - while ls > 0: - if dep_buf[ls] == '\n': - ls += 1 - break - ls -= 1 - if ls < ext_off2 and dep_buf[ls] == '@': - dep_buf[ls] = ';' - cfs_pos = ext_off2 + 30 - - # 跳过 header,追加内容(去重 declare/global) - dep_pos: t.CSizeT = 0 - skipping: int = 1 - while dep_pos < dep_br_ls: - line_start: t.CSizeT = dep_pos - while dep_pos < dep_br_ls: - if dep_buf[dep_pos] == '\n': - break - dep_pos += 1 - line_len: t.CSizeT = dep_pos - line_start - if dep_pos < dep_br_ls: - dep_pos += 1 - if skipping != 0: - if line_len == 0: - continue - ch0: int = dep_buf[line_start] - if ch0 == ';': - continue - if ch0 == 't' and line_len >= 6: - if string.strncmp(dep_buf + line_start, "target", 6) == 0: - continue - if ch0 == 's' and line_len >= 15: - if string.strncmp(dep_buf + line_start, "source_filename", 15) == 0: - continue - skipping = 0 - # 去重:declare(用 _IsFuncDeclaredOrDefined 避免误匹配 call 语句) - if line_len >= 8 and string.strncmp(dep_buf + line_start, "declare ", 8) == 0: - at: t.CSizeT = line_start + 8 - while at < line_start + line_len: - if dep_buf[at] == '@': - break - at += 1 - if at < line_start + line_len: - lp: t.CSizeT = at + 1 - while lp < line_start + line_len: - if dep_buf[lp] == '(': - break - lp += 1 - if lp < line_start + line_len: - saved: t.CChar = dep_buf[lp + 1] - dep_buf[lp + 1] = '\0' - if StubMergerIR._IsFuncDeclaredOrDefined(out_buf, dep_buf + at) != 0: - dep_buf[lp + 1] = saved - continue - dep_buf[lp + 1] = saved - # 去重:external global - if line_len > 0 and dep_buf[line_start] == '@': - eq: t.CSizeT = line_start + 1 - while eq < line_start + line_len: - if dep_buf[eq] == '=': - break - eq += 1 - if eq < line_start + line_len: - saved: t.CChar = dep_buf[eq + 1] - dep_buf[eq + 1] = '\0' - if string.strstr(out_buf, dep_buf + line_start) is not None: - dep_buf[eq + 1] = saved - continue - dep_buf[eq + 1] = saved - # 去重:type 定义(如 %"sha1.Point" = type {i32, i32}) - # 区分完整定义(= type { ... } / = type < ... >)和 opaque 声明(= type opaque) - # 当本地 stub 有 opaque 声明而依赖 stub 有完整定义时,注释掉 opaque 行, - # 让完整定义被追加,避免 LLC "Cannot allocate unsized type" 错误。 - if line_len > 0 and dep_buf[line_start] == '%': - eq2: t.CSizeT = line_start + 1 - while eq2 < line_start + line_len: - if dep_buf[eq2] == '=': - break - eq2 += 1 - if eq2 < line_start + line_len: - saved2: t.CChar = dep_buf[eq2 + 1] - dep_buf[eq2 + 1] = '\0' - # 检查依赖行是否为完整定义(= type { 或 = type <) - dep_is_full_def: int = 0 - if eq2 + 8 <= line_start + line_len: - if dep_buf[eq2 + 2] == 't' and dep_buf[eq2 + 3] == 'y' and dep_buf[eq2 + 4] == 'p' and dep_buf[eq2 + 5] == 'e' and dep_buf[eq2 + 6] == ' ': - if dep_buf[eq2 + 7] == '{' or dep_buf[eq2 + 7] == '<': - dep_is_full_def = 1 - if dep_is_full_def == 1: - # 依赖行是完整定义 - # 临时截断到 '=' 之前(不含 '='),辅助函数期望纯类型名前缀 - saved_eq: t.CChar = dep_buf[eq2] - dep_buf[eq2] = '\0' - # 1. 注释掉 out_buf 中的 opaque 声明(如果有) - commented: int = StubMergerIR._CommentOutOpaqueTypeInBuf(out_buf, dep_buf + line_start) - # 2. 检查 out_buf 中是否已有完整定义(避免重复) - has_full: int = StubMergerIR._HasFullTypeDefinition(out_buf, dep_buf + line_start) - dep_buf[eq2] = saved_eq - if has_full == 1: - dep_buf[eq2 + 1] = saved2 - continue - # 3. 追加完整定义 - else: - # 依赖行是 opaque 声明,用原有子串匹配去重 - found_opaque: t.CPtr = string.strstr(out_buf, dep_buf + line_start) - if found_opaque is not None: - dep_buf[eq2 + 1] = saved2 - continue - dep_buf[eq2 + 1] = saved2 - # 追加 - if out_pos + line_len + 2 < out_size: - string.strncpy(out_buf + out_pos, dep_buf + line_start, line_len) - out_pos += line_len - out_buf[out_pos] = '\n' - out_pos += 1 - out_buf[out_pos] = '\0' - return out_pos -# ============================================================ -# _LoadAndAppendTextDeclares - 从依赖 text.ll 提取 declare 追加到 out_buf -# -# 读取 {temp_dir}/{sha1}.text.ll,将 define 行转为 declare(提取函数签名), -# 跳过函数体,去重后追加到 out_buf。返回新 out_pos。 -# ============================================================ -def _LoadAndAppendTextDeclares(temp_dir: str, td_len: t.CSizeT, dep_sha1: str, - dep_buf: bytes, out_buf: bytes, out_size: t.CSizeT, - out_pos: t.CSizeT) -> t.CSizeT: - """从依赖 text.ll 提取 declare(define 转 declare),追加到 out_buf""" - if temp_dir is None or dep_sha1 is None or dep_buf is None or out_buf is None: - return out_pos - - text_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, dep_sha1, "text.ll") - if text_path is None: - return out_pos - tf_lt: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R) - if tf_lt.closed: - stdlib.free(text_path) - # 依赖 text 缺失:includes 映射内的模块缺失属编译错误(fail-fast), - # 非映射模块(如 t/c 内部库、用户文件)按设计跳过 - if StubMergerStore.LookupSha1RelPath(dep_sha1) is not None: - fb_lt: str = VLogger.fmt_buf() - if fb_lt is not None: - viperlib.snprintf(fb_lt, 1024, "依赖 text 缺失: %s", dep_sha1) - VLogger.error(fb_lt, "StubMerger") - return out_pos - text_br: t.CInt64T = tf_lt.read_all(dep_buf, STUB_READ_BUF_SIZE) - tf_lt.close() - stdlib.free(text_path) - if text_br <= 0: - # 依赖 text 为空:纯 stub 模块(如 stdio.vp 全 pass 声明)无函数体, - # text.ll 为空属合法形态,无可提取 declare,静默跳过 - return out_pos - if text_br < STUB_READ_BUF_SIZE: - dep_buf[text_br] = '\0' - else: - dep_buf[STUB_READ_BUF_SIZE - 1] = '\0' - - dep_pos_lt: t.CSizeT = 0 - in_body: int = 0 - while dep_pos_lt < text_br: - ls: t.CSizeT = dep_pos_lt - while dep_pos_lt < text_br: - if dep_buf[dep_pos_lt] == '\n': - break - dep_pos_lt += 1 - ll: t.CSizeT = dep_pos_lt - ls - if dep_pos_lt < text_br: - dep_pos_lt += 1 - - # 函数体跳过:直到单独的 } 行 - if in_body != 0: - if ll == 1 and dep_buf[ls] == '}': - in_body = 0 - continue - - # 跳过空行和 header - if ll == 0: - continue - c0: int = dep_buf[ls] - if c0 == ';': - continue - if c0 == 't' and ll >= 6 and string.strncmp(dep_buf + ls, "target", 6) == 0: - continue - if c0 == 's' and ll >= 15 and string.strncmp(dep_buf + ls, "source_filename", 15) == 0: - continue - - # 处理 define 行:转为 declare - if ll >= 7 and string.strncmp(dep_buf + ls, "define ", 7) == 0: - # 提取 @funcname( 用于去重 - at_lt: t.CSizeT = ls + 7 - while at_lt < ls + ll: - if dep_buf[at_lt] == '@': - break - at_lt += 1 - if at_lt >= ls + ll: - in_body = 1 - continue - lp_lt: t.CSizeT = at_lt + 1 - while lp_lt < ls + ll: - if dep_buf[lp_lt] == '(': - break - lp_lt += 1 - if lp_lt >= ls + ll: - in_body = 1 - continue - # 去重检查:用 _IsFuncDeclaredOrDefined 避免误匹配 call 语句 - saved_lt: t.CChar = dep_buf[lp_lt + 1] - dep_buf[lp_lt + 1] = '\0' - if StubMergerIR._IsFuncDeclaredOrDefined(out_buf, dep_buf + at_lt) != 0: - dep_buf[lp_lt + 1] = saved_lt - in_body = 1 - continue - dep_buf[lp_lt + 1] = saved_lt - - # 找行尾的 ' {' 并截断 - decl_end: t.CSizeT = ls + ll - if decl_end > ls + 1: - if dep_buf[decl_end - 1] == '{' and dep_buf[decl_end - 2] == ' ': - decl_end -= 2 - - # 输出: declare + content(skip "define " 7 chars, up to decl_end) - # 泛型特化方法 define 是 "define linkonce_odr ..."(FunctionPrint - # 对名含 '[' 的函数输出 linkonce_odr):若只跳过 "define " 会拼出 - # "declare linkonce_odr ..." → llc 报 "invalid linkage for function - # declaration"(LLVM 只允许 define 用 linkonce_odr,declare 必须 - # external)。对齐 TPC Phase2Translator 的 decl_line 剥 linkage 逻辑, - # 循环跳过所有 linkage 词。 - c_start_lt: t.CSizeT = ls + 7 - skipped_lt: int = 1 - while skipped_lt != 0: - skipped_lt = 0 - if c_start_lt + 13 <= decl_end and \ - string.strncmp(dep_buf + c_start_lt, "linkonce_odr ", 13) == 0: - c_start_lt += 13 - skipped_lt = 1 - elif c_start_lt + 10 <= decl_end and \ - string.strncmp(dep_buf + c_start_lt, "weak_odr ", 9) == 0: - c_start_lt += 9 - skipped_lt = 1 - elif c_start_lt + 10 <= decl_end and \ - string.strncmp(dep_buf + c_start_lt, "linkonce ", 9) == 0: - c_start_lt += 9 - skipped_lt = 1 - elif c_start_lt + 6 <= decl_end and \ - string.strncmp(dep_buf + c_start_lt, "weak ", 5) == 0: - c_start_lt += 5 - skipped_lt = 1 - elif c_start_lt + 10 <= decl_end and \ - string.strncmp(dep_buf + c_start_lt, "internal ", 9) == 0: - c_start_lt += 9 - skipped_lt = 1 - elif c_start_lt + 9 <= decl_end and \ - string.strncmp(dep_buf + c_start_lt, "private ", 8) == 0: - c_start_lt += 8 - skipped_lt = 1 - copy_len_lt: t.CSizeT = decl_end - c_start_lt - if out_pos + 8 + copy_len_lt + 2 < out_size: - string.strncpy(out_buf + out_pos, "declare ", 8) - out_pos += 8 - string.strncpy(out_buf + out_pos, dep_buf + c_start_lt, copy_len_lt) - out_pos += copy_len_lt - out_buf[out_pos] = '\n' - out_pos += 1 - out_buf[out_pos] = '\0' - in_body = 1 - continue - - # 提取类型定义(%... = type { ... } 或 %... = type < ... >) - # stub.ll 中只有 opaque 声明,需要从 text.ll 中提取完整定义 - # 用于 alloca 和 getelementptr 等需要完整类型的指令 - if ll > 0 and dep_buf[ls] == '%': - eq_td: t.CSizeT = ls + 1 - while eq_td < ls + ll: - if dep_buf[eq_td] == '=': - break - eq_td += 1 - if eq_td < ls + ll: - # 检查是否为完整定义(= type { 或 = type <) - dep_is_full_td: int = 0 - if eq_td + 8 <= ls + ll: - if dep_buf[eq_td + 2] == 't' and dep_buf[eq_td + 3] == 'y' \ - and dep_buf[eq_td + 4] == 'p' and dep_buf[eq_td + 5] == 'e' \ - and dep_buf[eq_td + 6] == ' ': - if dep_buf[eq_td + 7] == '{' or dep_buf[eq_td + 7] == '<': - dep_is_full_td = 1 - if dep_is_full_td == 1: - # 临时截断到 '=' 之前(不含 '='),辅助函数期望纯类型名前缀 - saved_eq_td: t.CChar = dep_buf[eq_td] - dep_buf[eq_td] = '\0' - # 1. 注释掉 out_buf 中的 opaque 声明(如果有) - StubMergerIR._CommentOutOpaqueTypeInBuf(out_buf, dep_buf + ls) - # 2. 检查 out_buf 中是否已有完整定义(避免重复) - has_full_td: int = StubMergerIR._HasFullTypeDefinition(out_buf, dep_buf + ls) - dep_buf[eq_td] = saved_eq_td - if has_full_td == 0: - # 追加完整类型定义 - if out_pos + ll + 2 < out_size: - string.strncpy(out_buf + out_pos, dep_buf + ls, ll) - out_pos += ll - out_buf[out_pos] = '\n' - out_pos += 1 - out_buf[out_pos] = '\0' - continue - - # 提取全局变量定义(@... = ...) - # 依赖 text.ll 中的全局变量带初值定义(如 @StubMerger._mbuddy = global ...) - # stub.ll 中只有 external 声明,需要从 text.ll 提取完整定义 - # 注释掉 out_buf 中的同名行(external 声明或旧定义),追加 text.ll 中的完整定义 - if ll > 0 and dep_buf[ls] == '@': - eq_gv: t.CSizeT = ls + 1 - while eq_gv < ls + ll: - if dep_buf[eq_gv] == '=': - break - eq_gv += 1 - if eq_gv < ls + ll: - # 截断到 '=' 之前(不含 '='),得到全局变量名 @name - saved_gv: t.CChar = dep_buf[eq_gv] - dep_buf[eq_gv] = '\0' - # 依赖方已有同名全局(stub 注入的 external 声明或先前依赖的定义) - # 时跳过:跨模块全局(如 _op_head、MemBuddy.vtable)只需一份 - # 强定义(在定义模块的 text.ll 中),复制进每个依赖方会导致 - # ld.lld duplicate symbol(NewAstTest _op_head/MemBuddy.vtable 根因)。 - # 仅当依赖方完全没有该全局(既无 external 也无定义)时才需要补充。 - if StubMergerIR._HasGlobalInBuf(out_buf, dep_buf + ls) == 0: - # 注释掉 out_buf 中的同名行(external 声明或旧定义) - StubMergerIR._CommentOutGlobalInBuf(out_buf, dep_buf + ls) - dep_buf[eq_gv] = saved_gv - # 追加完整定义 - if out_pos + ll + 2 < out_size: - string.strncpy(out_buf + out_pos, dep_buf + ls, ll) - out_pos += ll - out_buf[out_pos] = '\n' - out_pos += 1 - out_buf[out_pos] = '\0' - else: - dep_buf[eq_gv] = saved_gv - continue - - # 跳过其他行 - return out_pos -# ============================================================ -# _BuildReachableSha1Set - 构建可达 SHA1 集合(依赖图按需翻译) -# -# 从 source_dir 的源文件开始,解析 import 语句,递归收集可达的 -# includes 文件 SHA1。Phase 1b 只翻译可达集合中的文件,避免 -# 翻译不需要的 includes(如 Test 不依赖 llvmlite,则不翻译)。 -# -# 算法(工作列表): -# 1. 扫描 source_dir 下的 .vp/.py 文件,解析 AST 获取 _imported_modules -# 2. 构建 SHA1→module_name 映射(从全局内存存储器) -# 3. 工作列表递归:模块名 → 查 SHA1 → 加入 reachable_set → 读 .deps.txt → 追加新模块名 -# -# Args: -# mb: 内存池 -# source_dir: 源文件目录(Config.SourceDir) -# temp_dir: 临时目录(.deps.txt 所在位置;_sha1_map.txt 仅人类可读输出,不读取) -# reachable_set: 输出参数,可达 SHA1 集合缓冲区(MAX_INCLUDES_SHA1 * 17 字节) -# -# Returns: -# 可达 SHA1 数量(>0 成功,<=0 失败) -# ============================================================ -def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str, - temp_dir: str, - reachable_set: str, - app_deps: str = None) -> int: - """构建可达 SHA1 集合(依赖图按需翻译) - - app_deps: App 源文件的直接依赖模块名(空格分隔),如果非空则跳过自己的扫描步骤 - """ - if source_dir is None or temp_dir is None or reachable_set is None: - return -1 - - SRC_BUF_SIZE_R: t.CSizeT = 1048576 - - # 1. 构建 SHA1→module_name 映射 - td_len_r: t.CSizeT = string.strlen(temp_dir) - sha1_arr: bytes = stdlib.malloc(MAX_INCLUDES * 17) - mod_arr: bytes = stdlib.malloc(MAX_INCLUDES * 64) - if sha1_arr is None or mod_arr is None: - if sha1_arr is not None: - stdlib.free(sha1_arr) - if mod_arr is not None: - stdlib.free(mod_arr) - return -1 - map_count: int = StubMergerIR._BuildIncludesSha1Map(temp_dir, td_len_r, sha1_arr, mod_arr) - if map_count <= 0: - VLogger.error("无法构建 SHA1 映射", "Reachable") - stdlib.free(sha1_arr) - stdlib.free(mod_arr) - return -1 - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "SHA1 映射: %d 个", map_count) - VLogger.debug(fb, "Reachable") - - # 工作列表(空格分隔的模块名) - worklist: bytes = stdlib.malloc(REACH_WORKLIST_BUF) - if worklist is None: - stdlib.free(sha1_arr) - stdlib.free(mod_arr) - return -1 - worklist[0] = '\0' - wl_len: t.CSizeT = 0 - - reachable_count: int = 0 - - # 2. 如果 app_deps 非空,直接使用它作为初始 worklist(跳过自己的非递归扫描) - # 否则,回退到自己的非递归扫描(source_dir/*.py,只扫描顶层) - if app_deps is not None and app_deps[0] != '\0': - ad_len: t.CSizeT = string.strlen(app_deps) - if ad_len > 0 and ad_len < REACH_WORKLIST_BUF: - string.strcpy(worklist, app_deps) - wl_len = ad_len - else: - VLogger.error("app_deps 过长,无法构建可达集合", "StubMerger") - else: - # app_deps 缺失:Phase1 场景(未翻译 App 源文件)为设计性回退, - # 显式 warning 暴露回退,不再静默。 - # 原实现仅非递归扫描 source_dir 顶层("%s/*"),漏掉 lib/ 等子目录的 - # App 文件 → 其依赖(如 lib/Projectrans/Config.vp 的 json)不进入 - # worklist → json 不可达 → Phase1 不 stub 不翻译 → Phase2 Phase A - # 翻译 Config.vp 时 root.is_object() 跨模块调用无 stub 可查 → 静默 - # translate_value 返回 None → "if 条件表达式翻译失败"(追加82 根因)。 - # 改为递归扫描(复用 IncludesScanner.scan_includes),覆盖全部子目录。 - VLogger.warning("app_deps 缺失,递归扫描 source_dir", "Reachable") - scan_res_r: IncludesScanner.ScanResult | t.CPtr = IncludesScanner.scan_includes(mb, source_dir) - if scan_res_r is not None: - es_r: t.CSizeT = IncludesScanner.FileEntry.__sizeof__() - for e_i_r in range(scan_res_r.Count): - e_r: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)( - t.CVoid(t.CUInt64T(scan_res_r.Entries) + t.CUInt64T(e_i_r) * es_r, t.CPtr)) - if e_r is None or e_r.Path is None: - continue - sbuf: bytes = Utils.read_file_to_buf(e_r.Path, SRC_BUF_SIZE_R) - if sbuf is None: - continue - # 解析 AST 获取 _imported_modules(与原顶层扫描一致) - lx: ast.Lexer | t.CPtr = ast.new_lexer(mb) - if lx is not None: - ast._lexer_init(lx, sbuf, mb) - tokens: ast.Token | t.CPtr = ast.tokenize(lx) - tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens) - if tree is not None: - tr: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator() - if tr is not None: - tr._declare_only = 2 - # 源文件包名:用 RelPath(相对 source_dir,支持子目录), - # 保证 from .xxx import 相对导入解析正确 - tr.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, e_r.RelPath) - HandlesStruct.reset_visible_structs(mb, 0) - tr.translate(tree) - # 容器使用检测:App 源文件用 list/dict(裸名注解/构造/[] - # /{} 字面量)时注入 _list/_dict 依赖(与原实现一致) - tr._inject_auto_container_visibility(mb, tree) - # 获取 _imported_modules - if tr._imported_modules is not None: - # 逐模块去重追加(同 app_deps 拼接,防 worklist 膨胀溢出) - im_len: t.CSizeT = string.strlen(tr._imported_modules) - im_pos: t.CSizeT = 0 - while im_pos < im_len: - im_start: t.CSizeT = im_pos - while im_pos < im_len and tr._imported_modules[im_pos] != ' ': - im_pos += 1 - im_mod_len: t.CSizeT = im_pos - im_start - if im_pos < im_len: - im_pos += 1 - if im_mod_len == 0: - continue - im_buf: bytes = stdlib.malloc(im_mod_len + 1) - if im_buf is None: - continue - string.strncpy(im_buf, tr._imported_modules + im_start, im_mod_len) - im_buf[im_mod_len] = '\0' - if wl_len > 0 and HandlesImports.is_module_imported(worklist, im_buf) != 0: - stdlib.free(im_buf) - continue - if wl_len + im_mod_len + 2 < REACH_WORKLIST_BUF: - if wl_len > 0: - worklist[wl_len] = ' ' - wl_len += 1 - string.strcpy(worklist + wl_len, im_buf) - wl_len += im_mod_len - worklist[wl_len] = ' ' - wl_len += 1 - worklist[wl_len] = '\0' - stdlib.free(im_buf) - # 计算 App 源文件 SHA1,填充依赖到内存存储器 - # worklist 遍历时,LookupIncludesDeps 能找到 App 源文件的依赖 - if e_r.Sha1 is not None: - StubMergerStore.PopulateIncludesDeps(e_r.Sha1, tr._imported_modules) - # 释放 Translator 资源 - if tr._global_names is not None: - stdlib.free(tr._global_names) - if tr._nonlocal_names is not None: - stdlib.free(tr._nonlocal_names) - stdlib.free(sbuf) - - # 去掉末尾多余空格 - if wl_len > 0 and worklist[wl_len - 1] == ' ': - worklist[wl_len - 1] = '\0' - wl_len -= 1 - - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "源文件直接依赖: '%s'", worklist) - VLogger.debug(fb, "Reachable") - - # 2.5. 预加入基础模块(builtins) - # - # builtins(内置函数模块:ord/chr 等)始终纳入编译链,调用时自动关联。 - # _list/_dict 不再无条件预加入:Phase A 翻译 App 源文件时 - # _inject_auto_container_visibility 已按需检测 list/dict 使用并注入 - # _imported_modules(含 []/{} 字面量),json 由 _dict 的真实 import 链带入。 - if HandlesImports.is_module_imported(worklist, "builtins") == 0: - bsha1_b: str = StubMergerIR._FindSha1ByModName(sha1_arr, mod_arr, map_count, "builtins") - if bsha1_b is not None: - if wl_len + 9 < REACH_WORKLIST_BUF: - if wl_len > 0: - worklist[wl_len] = ' ' - wl_len += 1 - string.strcpy(worklist + wl_len, "builtins") - wl_len += 8 - worklist[wl_len] = ' ' - wl_len += 1 - worklist[wl_len] = '\0' - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "预加入容器模块后: '%s'", worklist) - VLogger.debug(fb, "Reachable") - - # 3. 工作列表算法:递归收集可达 SHA1 - processed: bytes = stdlib.malloc(REACH_WORKLIST_BUF) - if processed is None: - stdlib.free(sha1_arr) - stdlib.free(mod_arr) - stdlib.free(worklist) - return -1 - processed[0] = '\0' - proc_len: t.CSizeT = 0 - - wl_pos: t.CSizeT = 0 - wl_iter: int = 0 - while wl_pos < wl_len: - wl_iter += 1 - # 提取一个模块名(到空格或末尾) - name_start: t.CSizeT = wl_pos - while wl_pos < wl_len and worklist[wl_pos] != ' ': - wl_pos += 1 - name_len: t.CSizeT = wl_pos - name_start - if wl_pos < wl_len: - wl_pos += 1 - if name_len == 0: - continue - - # 复制模块名 - mod_buf: bytes = stdlib.malloc(name_len + 1) - if mod_buf is None: - continue - string.strncpy(mod_buf, worklist + name_start, name_len) - mod_buf[name_len] = '\0' - - # 检查是否已处理 - already: int = 0 - if HandlesImports.is_module_imported(processed, mod_buf) != 0: - already = 1 - if already == 0: - # 加入 processed(嵌套 if 拆分 + 用 = 代替 += 绕过 TPC AUGASGN bug) - if processed is not None: - if proc_len + name_len + 1 < REACH_WORKLIST_BUF: - string.strcpy(processed + proc_len, mod_buf) - proc_len = proc_len + name_len - processed[proc_len] = ' ' - proc_len = proc_len + 1 - processed[proc_len] = '\0' - else: - VLogger.error("依赖 worklist 溢出", "StubMerger") - - # 查找 SHA1 - found_sha1: str = StubMergerIR._FindSha1ByModName(sha1_arr, mod_arr, map_count, mod_buf) - if found_sha1 is not None: - # App 源文件(Sha1Store 中 IncDir 为空,AppendToSha1MapStore 规则) - # 不加入 reachable_set:Phase B 已编译其 .obj,若加入会导致 Phase B+ - # 把 App 文件重复编译进 includes.binary,Phase C 链接时与 Phase B 的 - # App obj 重复符号(SysLibTest ld.lld duplicate symbol: StubMerger._mbuddy 根因)。 - # 依赖仍继续展开(App 文件是依赖图中间节点,其 includes 依赖必须可达)。 - is_app_r: int = 0 - if StubMerger._sha1_store_incdir is not None: - for ai_r in range(StubMerger._sha1_store_count): - asi_r: t.CSizeT = t.CSizeT(ai_r) * 17 - if string.strcmp(StubMerger._sha1_store_arr + asi_r, found_sha1) == 0: - aii_r: t.CSizeT = t.CSizeT(ai_r) * MAX_INC_DIR_LEN - if StubMerger._sha1_store_incdir[aii_r] == '\0': - is_app_r = 1 - break - if is_app_r == 0: - reachable_count = StubMergerIR._AddSha1ToSet(reachable_set, reachable_count, found_sha1) - - # 从内存查找依赖(不读 deps.txt 过程文件) - # Phase B+ 前用 declare_only 翻译所有 includes 文件,提取 _imported_modules 存入内存 - deps_str: str = StubMergerStore.LookupIncludesDeps(found_sha1) - if deps_str is not None: - dl: t.CSizeT = string.strlen(deps_str) - if dl > 0: - # 逐模块追加 + 去重:worklist 初始已含全部 App 直接依赖, - # deps_str 中的模块若已在 worklist/processed 不重复追加, - # 否则 BFS 沿共享依赖(builtins/stdlib 等)反复累积到 - # 64KB 溢出("依赖 worklist 溢出"根因)。 - dpos: t.CSizeT = 0 - while dpos < dl: - dstart: t.CSizeT = dpos - while dpos < dl and deps_str[dpos] != ' ': - dpos += 1 - dlen: t.CSizeT = dpos - dstart - if dpos < dl: - dpos += 1 - if dlen == 0: - continue - dmod: bytes = stdlib.malloc(dlen + 1) - if dmod is None: - continue - string.strncpy(dmod, deps_str + dstart, dlen) - dmod[dlen] = '\0' - in_wl: int = 0 - if HandlesImports.is_module_imported(worklist, dmod) != 0: - in_wl = 1 - if in_wl == 0 and processed is not None: - if HandlesImports.is_module_imported(processed, dmod) != 0: - in_wl = 1 - if in_wl == 0: - if wl_len + dlen + 2 < REACH_WORKLIST_BUF: - if wl_len > 0 and worklist[wl_len - 1] != ' ': - worklist[wl_len] = ' ' - wl_len = wl_len + 1 - string.strcpy(worklist + wl_len, dmod) - wl_len = wl_len + dlen - worklist[wl_len] = ' ' - wl_len = wl_len + 1 - worklist[wl_len] = '\0' - else: - VLogger.error("依赖 worklist 溢出", "StubMerger") - stdlib.free(dmod) - # deps_str 为空字符串视为无依赖(合法情况,如叶子模块) - else: - # 依赖未在内存中找到 - # 按需过滤: 检查是否是 App 源文件(source_dir 下的 .vp/.py 文件) - # App 源文件不需要加入 reachable_set(只用于 includes 过滤),跳过 - sd_len_ff: t.CSizeT = string.strlen(source_dir) - mb_len_ff: t.CSizeT = string.strlen(mod_buf) - app_mod_path: bytes = stdlib.malloc(sd_len_ff + mb_len_ff + 6) - is_app_src: int = 0 - if app_mod_path is not None: - # 优先尝试 .vp,向后兼容 .py - viperlib.snprintf(app_mod_path, sd_len_ff + mb_len_ff + 6, "%s/%s.vp", source_dir, mod_buf) - af: fileio.File | t.CPtr = fileio.File(app_mod_path, fileio.MODE.R) - if not af.closed: - is_app_src = 1 - af.close() - else: - # .vp 不存在,回退 .py - viperlib.snprintf(app_mod_path, sd_len_ff + mb_len_ff + 6, "%s/%s.py", source_dir, mod_buf) - af = fileio.File(app_mod_path, fileio.MODE.R) - if not af.closed: - is_app_src = 1 - af.close() - stdlib.free(app_mod_path) - if is_app_src == 0: - # fast-fail: includes 文件依赖未在内存中找到,Phase 1a-pre 未正确填充 - fb_ff: str = VLogger.fmt_buf() - if fb_ff is not None: - viperlib.snprintf(fb_ff, 1024, "依赖未找到 fast-fail: 模块 %s(sha1=%s) 的依赖未在内存中注册", mod_buf, found_sha1) - VLogger.error(fb_ff, "Reachable") - stdlib.free(sha1_arr) - stdlib.free(mod_arr) - stdlib.free(worklist) - stdlib.free(processed) - stdlib.free(mod_buf) - return -1 - stdlib.free(mod_buf) - stdlib.free(sha1_arr) - stdlib.free(mod_arr) - stdlib.free(worklist) - stdlib.free(processed) - - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "可达 SHA1: %d 个", reachable_count) - VLogger.debug(fb, "Reachable") - return reachable_count -# ============================================================ -# BuildCombinedIR - 组合本地 stub + 依赖 stubs + 本地 text → 完整 IR -# -# 按需加载:读取 deps.txt 获取导入模块名,通过内存存储器查找 SHA1, -# 仅加载实际使用的依赖 stub(而非全部扫描)。 -# _sha1_map.txt 仅作为人类可读输出,程序内部不读取。 -# ============================================================ -def BuildCombinedIR(temp_dir: str, local_sha1: str, - out_buf: bytes, out_size: t.CSizeT) -> t.CSizeT: - """组合本地 stub + 依赖 stubs + 本地 text → out_buf(按需加载)""" - if temp_dir is None or local_sha1 is None or out_buf is None or out_size == 0: - return 0 - - td_len: t.CSizeT = string.strlen(temp_dir) - out_buf[0] = '\0' - out_pos: t.CSizeT = 0 - - # 1. 读取并追加本地 stub.ll(含 header) - stub_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, local_sha1, "stub.ll") - if stub_path is None: - return 0 - sf: fileio.File | t.CPtr = fileio.File(stub_path, fileio.MODE.R) - if sf.closed: - stdlib.free(stub_path) - return 0 - stub_content: bytes = stdlib.malloc(STUB_READ_BUF_SIZE) - if stub_content is None: - sf.close() - stdlib.free(stub_path) - return 0 - stub_br: t.CInt64T = sf.read_all(stub_content, STUB_READ_BUF_SIZE) - sf.close() - stdlib.free(stub_path) - if stub_br <= 0: - stdlib.free(stub_content) - return 0 - if stub_br < STUB_READ_BUF_SIZE: - stub_content[stub_br] = '\0' - else: - stub_content[STUB_READ_BUF_SIZE - 1] = '\0' - slen: t.CSizeT = stub_br - # 修复本地 stub.ll 中字符串常量的非法 IR: - # llvmlite OUTPUT_STUB 模式输出 "= external unnamed_addr constant" 的非法形式。 - # 简单方案:搜索 "= external unnamed_addr constant" 并将 external 替换为 8 个空格。 - fix_pos: t.CSizeT = 0 - while fix_pos + 30 < slen: - ext_ptr: t.CPtr = string.strstr(stub_content + fix_pos, "= external unnamed_addr constant") - if ext_ptr is None: - break - # ext_ptr 指向 "= external ..." 中的 '=' - # 'external' 开始于 ext_ptr + 2 - ext_off: t.CSizeT = t.CSizeT(t.CUInt64T(ext_ptr) - t.CUInt64T(stub_content)) + 2 - if ext_off + 8 <= slen: - stub_content[ext_off] = ' ' - stub_content[ext_off + 1] = ' ' - stub_content[ext_off + 2] = ' ' - stub_content[ext_off + 3] = ' ' - stub_content[ext_off + 4] = ' ' - stub_content[ext_off + 5] = ' ' - stub_content[ext_off + 6] = ' ' - stub_content[ext_off + 7] = ' ' - fix_pos = ext_off + 8 - # 直接复制修复后的 stub 内容 - if out_pos + slen + 2 < out_size: - string.strcpy(out_buf + out_pos, stub_content) - out_pos += slen - if out_buf[out_pos - 1] != '\n': - out_buf[out_pos] = '\n' - out_pos += 1 - out_buf[out_pos] = '\0' - stdlib.free(stub_content) - - # 2. 按需加载依赖 stubs(根据 deps.txt 过滤,而非扫描全部) - # 先加载依赖 stub(含 type 定义),确保 type 定义在本地 text.ll 的 define 块之前 - # 2a. 构建 includes SHA1 → module_name 映射(从全局内存存储器) - sha1_arr: bytes = stdlib.malloc(MAX_INCLUDES * 17) - mod_arr: bytes = stdlib.malloc(MAX_INCLUDES * 64) - inc_count: int = 0 - if sha1_arr is not None and mod_arr is not None: - inc_count = StubMergerIR._BuildIncludesSha1Map(temp_dir, td_len, sha1_arr, mod_arr) - - # 2b. 读取 deps.txt 获取导入模块名集合 - deps_buf: str = None - deps_loaded: int = 0 - deps_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, local_sha1, "deps.txt") - if deps_path is not None: - df_deps: fileio.File | t.CPtr = fileio.File(deps_path, fileio.MODE.R) - if not df_deps.closed: - deps_buf = stdlib.malloc(4096) - if deps_buf is not None: - deps_br: t.CInt64T = df_deps.read_all(deps_buf, 4096) - if deps_br > 0: - if deps_br < 4096: - deps_buf[deps_br] = '\0' - else: - deps_buf[4095] = '\0' - deps_loaded = 1 - elif deps_br == 0: - # 空 deps.txt:无 import 的包标记文件(如 lib/core/Gen/__init__.vp、 - # lib/StubGen/__init__.vp 纯注释)合法——deps_loaded 置 1 视为 - # "已加载且无依赖",避免下方"deps.txt 缺失"误报(追加85 根因)。 - # deps_buf 是 malloc 未初始化内存,必须显式置空串, - # 否则后续 strlen(deps_buf) 读到垃圾长度遍历越界。 - deps_buf[0] = '\0' - deps_loaded = 1 - df_deps.close() - stdlib.free(deps_path) - - # deps.txt 缺失但存在 includes 映射:依赖无法按需过滤,fail-fast 终止 - if deps_loaded == 0 and inc_count > 0: - VLogger.error("依赖文件 deps.txt 缺失,无法合并 includes stub", "StubMerger") - - # 2c. 递归扫描 temp_dir 中所有 .stub.ll,按需加载 - # 全目录扫描结果按 temp_dir 缓存(Phase B 对每个源文件调用一次 - # BuildCombinedIR,每次递归扫盘 O(N×S) 是 Phase B 慢的根因之一; - # 首次扫描后复用缓存,temp_dir 变化时自动重建) - cache_valid_sc: int = 0 - if StubMerger._stub_scan_cache_arr is not None and StubMerger._stub_scan_cache_dir is not None: - if string.strcmp(StubMerger._stub_scan_cache_dir, temp_dir) == 0: - cache_valid_sc = 1 - if cache_valid_sc == 0: - new_scan_arr: str = stdlib.malloc(MAX_INCLUDES_SHA1 * 17) - if new_scan_arr is not None: - string.memset(new_scan_arr, 0, MAX_INCLUDES_SHA1 * 17) - new_scan_count: int = StubMergerCollect._collect_stub_sha1s( - temp_dir, td_len, Config.Sha1SliceLevel, new_scan_arr, 0, MAX_INCLUDES_SHA1) - if new_scan_count > 0: - # 缓存目录键(stdlib 深拷贝,跨调用存活) - dir_buf_sc: str = stdlib.malloc(td_len + 1) - if dir_buf_sc is not None: - string.strcpy(dir_buf_sc, temp_dir) - if StubMerger._stub_scan_cache_arr is not None: - stdlib.free(StubMerger._stub_scan_cache_arr) - StubMerger._stub_scan_cache_arr = None - if StubMerger._stub_scan_cache_dir is not None: - stdlib.free(StubMerger._stub_scan_cache_dir) - StubMerger._stub_scan_cache_dir = None - StubMerger._stub_scan_cache_arr = new_scan_arr - StubMerger._stub_scan_cache_dir = dir_buf_sc - StubMerger._stub_scan_cache_count = new_scan_count - else: - stdlib.free(new_scan_arr) - else: - stdlib.free(new_scan_arr) - all_sha1_arr: str = StubMerger._stub_scan_cache_arr - all_count: int = StubMerger._stub_scan_cache_count - if all_sha1_arr is not None and all_count > 0: - dep_buf: bytes = stdlib.malloc(STUB_READ_BUF_SIZE) - if dep_buf is not None: - si: int = 0 - while si < all_count: - dep_sha1: str = all_sha1_arr + t.CSizeT(si) * 17 - if string.strcmp(dep_sha1, local_sha1) == 0: - si += 1 - continue - should_load: int = 0 - # 检查是否在 includes 映射中 - is_include: int = 0 - if inc_count > 0: - for ii in range(inc_count): - idx_ii: t.CSizeT = t.CSizeT(ii) * 17 - if string.strcmp(sha1_arr + idx_ii, dep_sha1) != 0: - continue - is_include = 1 - if deps_loaded != 0: - idx_mi: t.CSizeT = t.CSizeT(ii) * 64 - dep_mod_name: str = mod_arr + idx_mi - if HandlesImports.is_module_imported(deps_buf, dep_mod_name) != 0: - should_load = 1 - elif StubMergerIR._is_submodule_of_imported(deps_buf, dep_mod_name) != 0: - # 传递性依赖:deps.txt 只记录直接导入(如 ast), - # 但包的 __init__.vp 内部 from .lexer import Lexer - # 会让 IR 引用 ast.lexer 子模块类型。 - # 检查 dep_mod_name 是否是已导入包的子模块 - # (如 ast.lexer 是 ast 的子模块) - should_load = 1 - break - if is_include == 0: - # 非 includes stub(用户文件),总是加载 - should_load = 1 - if should_load != 0: - out_pos = _LoadAndAppendStub(temp_dir, td_len, dep_sha1, dep_buf, out_buf, out_size, out_pos) - out_pos = _LoadAndAppendTextDeclares(temp_dir, td_len, dep_sha1, dep_buf, out_buf, out_size, out_pos) - si += 1 - stdlib.free(dep_buf) - # all_sha1_arr 是模块级缓存(StubMerger._stub_scan_cache_arr),跨调用共享,不释放 - - # 2d. 验证 deps.txt 中所有依赖模块的 stub 文件都存在(fail-fast) - # 避免到 llc 才报 undefined value 错误。 - # 仅验证在 includes 映射中找到的模块(t/c 等内部库无 SHA1 映射,自动跳过)。 - if deps_loaded != 0 and inc_count > 0: - dep_total: t.CSizeT = string.strlen(deps_buf) - dp: t.CSizeT = 0 - while dp < dep_total: - # 跳过前导空格 - while dp < dep_total: - if deps_buf[dp] != ' ': - break - dp += 1 - if dp >= dep_total: - break - # 提取模块名(到下一个空格或末尾) - ms: t.CSizeT = dp - while dp < dep_total: - if deps_buf[dp] == ' ': - break - dp += 1 - ml: t.CSizeT = dp - ms - if ml == 0: - continue - # 复制模块名到临时缓冲区并 null 终止 - mod_nm: str = stdlib.malloc(ml + 1) - if mod_nm is None: - continue - string.strncpy(mod_nm, deps_buf + ms, ml) - mod_nm[ml] = '\0' - # 在 includes 映射中查找模块对应的 SHA1 - found_s: str = None - for mi2 in range(inc_count): - idx_m2: t.CSizeT = t.CSizeT(mi2) * 64 - if string.strcmp(mod_arr + idx_m2, mod_nm) == 0: - idx_s2: t.CSizeT = t.CSizeT(mi2) * 17 - found_s = sha1_arr + idx_s2 - break - if found_s is not None: - # 检查 stub 文件是否存在 - chk_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, found_s, "stub.ll") - if chk_path is not None: - chk_f: fileio.File | t.CPtr = fileio.File(chk_path, fileio.MODE.R) - if chk_f.closed: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "依赖模块 '%s' (sha1=%s) 的 stub 文件不存在: %s,立即终止编译", mod_nm, found_s, chk_path) - VLogger.error(fb, "BuildCombinedIR") - chk_f.close() - stdlib.free(chk_path) - stdlib.free(mod_nm) - - # 3. 读取并追加本地 text.ll(行级去重,跳过 stub.ll 中已存在的定义) - text_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, local_sha1, "text.ll") - if text_path is None: - return out_pos - tf: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R) - if tf.closed: - # 本地 text.ll 缺失:合并 IR 无法生成定义块,fail-fast 终止 - fb_tlp: str = VLogger.fmt_buf() - if fb_tlp is not None: - viperlib.snprintf(fb_tlp, 1024, "本地 text.ll 缺失: %s", text_path) - VLogger.error(fb_tlp, "StubMerger") - stdlib.free(text_path) - else: - text_content: bytes = stdlib.malloc(STUB_READ_BUF_SIZE) - if text_content is None: - tf.close() - stdlib.free(text_path) - else: - text_br: t.CInt64T = tf.read_all(text_content, STUB_READ_BUF_SIZE) - tf.close() - stdlib.free(text_path) - if text_br > 0: - if text_br < STUB_READ_BUF_SIZE: - text_content[text_br] = '\0' - else: - text_content[STUB_READ_BUF_SIZE - 1] = '\0' - # 行级去重追加(与 _LoadAndAppendStub 相同逻辑) - tx_pos: t.CSizeT = 0 - tx_skip: int = 1 - while tx_pos < text_br: - tx_ls: t.CSizeT = tx_pos - while tx_pos < text_br: - if text_content[tx_pos] == '\n': - break - tx_pos += 1 - tx_ll: t.CSizeT = tx_pos - tx_ls - if tx_pos < text_br: - tx_pos += 1 - if tx_skip != 0: - if tx_ll == 0: - continue - tx_c0: int = text_content[tx_ls] - if tx_c0 == ';': - continue - if tx_c0 == 't' and tx_ll >= 6: - if string.strncmp(text_content + tx_ls, "target", 6) == 0: - continue - if tx_c0 == 's' and tx_ll >= 15: - if string.strncmp(text_content + tx_ls, "source_filename", 15) == 0: - continue - tx_skip = 0 - # 去重:declare(用 _IsFuncDeclaredOrDefined 避免误匹配 call 语句) - if tx_ll >= 8 and string.strncmp(text_content + tx_ls, "declare ", 8) == 0: - tx_at: t.CSizeT = tx_ls + 8 - while tx_at < tx_ls + tx_ll: - if text_content[tx_at] == '@': - break - tx_at += 1 - if tx_at < tx_ls + tx_ll: - tx_lp: t.CSizeT = tx_at + 1 - while tx_lp < tx_ls + tx_ll: - if text_content[tx_lp] == '(': - break - tx_lp += 1 - if tx_lp < tx_ls + tx_ll: - tx_sv: t.CChar = text_content[tx_lp + 1] - text_content[tx_lp + 1] = '\0' - if StubMergerIR._IsFuncDeclaredOrDefined(out_buf, text_content + tx_at) != 0: - text_content[tx_lp + 1] = tx_sv - continue - text_content[tx_lp + 1] = tx_sv - # 去重:define(注释掉 out_buf 中已有的 declare,避免 declare/define 冲突) - if tx_ll >= 7 and string.strncmp(text_content + tx_ls, "define ", 7) == 0: - tx_at_d: t.CSizeT = tx_ls + 7 - while tx_at_d < tx_ls + tx_ll: - if text_content[tx_at_d] == '@': - break - tx_at_d += 1 - if tx_at_d < tx_ls + tx_ll: - tx_lp_d: t.CSizeT = tx_at_d + 1 - while tx_lp_d < tx_ls + tx_ll: - if text_content[tx_lp_d] == '(': - break - tx_lp_d += 1 - if tx_lp_d < tx_ls + tx_ll: - tx_sv_d: t.CChar = text_content[tx_lp_d + 1] - text_content[tx_lp_d + 1] = '\0' - StubMergerIR._CommentOutDeclareInBuf(out_buf, text_content + tx_at_d) - text_content[tx_lp_d + 1] = tx_sv_d - # 处理:@global = ... - # stub 中可能是 external 声明或完整定义,以 text 中的定义为准 - # 找到 stub 中同名全局变量行并注释掉,然后追加 text 中的 - if tx_ll > 0 and text_content[tx_ls] == '@': - tx_eq: t.CSizeT = tx_ls + 1 - while tx_eq < tx_ls + tx_ll: - if text_content[tx_eq] == '=': - break - tx_eq += 1 - if tx_eq < tx_ls + tx_ll: - tx_sv2: t.CChar = text_content[tx_eq + 1] - text_content[tx_eq + 1] = '\0' - StubMergerIR._CommentOutGlobalInBuf(out_buf, text_content + tx_ls) - text_content[tx_eq + 1] = tx_sv2 - # 去重:%type = ... - if tx_ll > 0 and text_content[tx_ls] == '%': - tx_eq2: t.CSizeT = tx_ls + 1 - while tx_eq2 < tx_ls + tx_ll: - if text_content[tx_eq2] == '=': - break - tx_eq2 += 1 - if tx_eq2 < tx_ls + tx_ll: - tx_sv3: t.CChar = text_content[tx_eq2 + 1] - text_content[tx_eq2 + 1] = '\0' - if string.strstr(out_buf, text_content + tx_ls) is not None: - text_content[tx_eq2 + 1] = tx_sv3 - continue - text_content[tx_eq2 + 1] = tx_sv3 - # 追加 - if out_pos + tx_ll + 2 < out_size: - string.strncpy(out_buf + out_pos, text_content + tx_ls, tx_ll) - out_pos += tx_ll - out_buf[out_pos] = '\n' - out_pos += 1 - out_buf[out_pos] = '\0' - stdlib.free(text_content) - - if deps_buf is not None: - stdlib.free(deps_buf) - if sha1_arr is not None: - stdlib.free(sha1_arr) - if mod_arr is not None: - stdlib.free(mod_arr) - - return out_pos -# ============================================================ -# LoadDepVpiIntoModule - 加载依赖模块的 .vpi 文件,注入 declare 到当前模块 -# -# 遍历 imported_modules(空格分隔的模块名),对每个模块: -# 1. 用 LookupSha1ByModName 获取 SHA1 -# 2. 用 _sliced_path 构造 .vpi 文件路径 -# 3. 调用 VpiReader.ParseVpiIntoModule 解析 .vpi 并注入 declare -# -# 在 _translate_module_level 中、Import 处理完成后、translate_children -# 之前调用,确保跨模块函数调用时 declare 已存在。 -# -# Args: -# pool: 内存池 -# mod: 当前 LLVM 模块 -# imported_modules: 已导入模块名字符串(空格分隔) -# from_imports: from-import 映射字符串("name:module name:module" 格式) -# temp_dir: temp 目录路径 -# trans: 翻译器对象 -# -# Returns: -# 成功加载的 .vpi 文件数 -# ============================================================ -def LoadDepVpiIntoModule(pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - imported_modules: str, - from_imports: str, - temp_dir: str, - trans: HandlesTranslator.Translator | t.CPtr) -> int: - """加载依赖模块的 .vpi 文件,将函数声明注入到当前模块""" - if pool is None or mod is None or temp_dir is None or trans is None: - return 0 - if imported_modules is None: - return 0 - - td_len: t.CSizeT = string.strlen(temp_dir) - total_len: t.CSizeT = string.strlen(imported_modules) - success_count: int = 0 - - # 遍历 imported_modules 中的每个模块名(空格分隔) - ci: t.CSizeT = 0 - while ci < total_len: - # 跳过前导空格 - while ci < total_len and imported_modules[ci] == ' ': - ci += 1 - if ci >= total_len: - break - # 提取模块名(到下一个空格或字符串末尾) - word_start: t.CSizeT = ci - while ci < total_len and imported_modules[ci] != ' ': - ci += 1 - word_len: t.CSizeT = ci - word_start - if word_len == 0: - continue - - # 复制模块名到临时缓冲区并 null 终止 - mod_nm_buf: str = stdlib.malloc(word_len + 1) - if mod_nm_buf is None: - continue - string.strncpy(mod_nm_buf, imported_modules + word_start, word_len) - mod_nm_buf[word_len] = '\0' - - # 用 LookupSha1ByModName 查找模块的 SHA1 - sha1_val: str = StubMergerStore.LookupSha1ByModName(mod_nm_buf) - - # 如果精确查找失败,尝试包名回退(如 "ast" → "ast.__init__") - # LookupSha1ByModName 内部已处理包名回退,此处无需重复 - - if sha1_val is not None: - # 构造 .vpi 文件路径 - vpi_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, sha1_val, "vpi") - if vpi_path is not None: - # 检查 .vpi 文件是否存在(可读) - vf: fileio.File | t.CPtr = fileio.File(vpi_path, fileio.MODE.R) - if not vf.closed: - vf.close() - # 调用 VpiReader 解析 .vpi 并注入 declare - # (错误上下文帧由调用方 HandlesTranslator 维护) - ret: int = VpiReader.ParseVpiIntoModule(pool, mod, vpi_path, trans) - if ret == 1: - success_count += 1 - stdlib.free(vpi_path) - # sha1_val 指向内部存储,无需 free - - stdlib.free(mod_nm_buf) - - return success_count +import lib.core.Gen.GenApi as GenApi +import t, c +from stdint import * +import memhub +import string +import stdlib +import llvmlite +import w32.win32file as win32file +import w32.win32base as win32base +import w32.fileio as fileio +import viperlib +import sys +import ast +import lib.core.VLogger as VLogger +import lib.core.IncludesScanner as IncludesScanner +import lib.core.Handles.HandlesTranslator as HandlesTranslator +import lib.core.BuildPipeline as BuildPipeline +import lib.StubGen.VpiReader as VpiReader +import lib.Projectrans.Utils as Utils +import lib.Projectrans.Config as Config + + +import lib.core.StubMergerCollect as StubMergerCollect +import lib.core.StubMergerStore as StubMergerStore +import lib.core.StubMergerTopo as StubMergerTopo +import lib.core.StubMergerIR as StubMergerIR +import lib.core.StubMerger as StubMerger + +# ============================================================ +# StubMergerBuild - StubMerger 拆分(阶段 E):StubMergerBuild +# +# 直接移动模式:函数实现迁至此模块,原 StubMerger.vp 仅保留 +# 常量/全局变量;调用方经本模块前缀访问。全局变量跨模块经 +# StubMerger._xxx 访问(main.vp 先例)。 +# ============================================================ + +# ============================================================ +# _LoadAndAppendStub - 加载依赖 stub 并追加到 out_buf +# +# 读取 {temp_dir}/{sha1}.stub.ll,跳过 header(;, target, source_filename), +# 去重 declare/global,追加到 out_buf。返回新 out_pos。 +# ============================================================ +def _LoadAndAppendStub(temp_dir: str, td_len: t.CSizeT, dep_sha1: str, + dep_buf: bytes, out_buf: bytes, out_size: t.CSizeT, + out_pos: t.CSizeT) -> t.CSizeT: + """加载依赖 stub 并追加(跳过 header,去重)""" + if temp_dir is None or dep_sha1 is None or dep_buf is None or out_buf is None: + return out_pos + + dep_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, dep_sha1, "stub.ll") + if dep_path is None: + return out_pos + df_ls: fileio.File | t.CPtr = fileio.File(dep_path, fileio.MODE.R) + if df_ls.closed: + stdlib.free(dep_path) + # 依赖 stub 缺失:includes 映射内的模块缺失属编译错误(fail-fast), + # 非映射模块(如 t/c 内部库、用户文件)按设计跳过 + if StubMergerStore.LookupSha1RelPath(dep_sha1) is not None: + fb_ls: str = VLogger.fmt_buf() + if fb_ls is not None: + viperlib.snprintf(fb_ls, 1024, "依赖 stub 缺失: %s", dep_sha1) + VLogger.error(fb_ls, "StubMerger") + return out_pos + dep_br_ls: t.CInt64T = df_ls.read_all(dep_buf, STUB_READ_BUF_SIZE) + df_ls.close() + stdlib.free(dep_path) + if dep_br_ls <= 0: + # 依赖 stub 为空:纯声明/纯常量模块(如 stdio.vp 全 pass、CDefine 模块) + # 无可声明符号,stub.ll 为空属合法形态,静默跳过 + return out_pos + if dep_br_ls < STUB_READ_BUF_SIZE: + dep_buf[dep_br_ls] = '\0' + else: + dep_buf[STUB_READ_BUF_SIZE - 1] = '\0' + + # 注释掉依赖 stub 中的字符串常量行(模块内部的,不需要) + # 简单方案:搜索 "= external unnamed_addr constant" 并将行首的 @ 改为 ;@ + cfs_pos: t.CSizeT = 0 + while cfs_pos + 30 < t.CSizeT(dep_br_ls): + ext_p: t.CPtr = string.strstr(dep_buf + cfs_pos, "= external unnamed_addr constant") + if ext_p is None: + break + ext_off2: t.CSizeT = t.CSizeT(t.CUInt64T(ext_p) - t.CUInt64T(dep_buf)) + # 向前查找行首的 @ + ls: t.CSizeT = ext_off2 + while ls > 0: + if dep_buf[ls] == '\n': + ls += 1 + break + ls -= 1 + if ls < ext_off2 and dep_buf[ls] == '@': + dep_buf[ls] = ';' + cfs_pos = ext_off2 + 30 + + # 跳过 header,追加内容(去重 declare/global) + dep_pos: t.CSizeT = 0 + skipping: int = 1 + while dep_pos < dep_br_ls: + line_start: t.CSizeT = dep_pos + while dep_pos < dep_br_ls: + if dep_buf[dep_pos] == '\n': + break + dep_pos += 1 + line_len: t.CSizeT = dep_pos - line_start + if dep_pos < dep_br_ls: + dep_pos += 1 + if skipping != 0: + if line_len == 0: + continue + ch0: int = dep_buf[line_start] + if ch0 == ';': + continue + if ch0 == 't' and line_len >= 6: + if string.strncmp(dep_buf + line_start, "target", 6) == 0: + continue + if ch0 == 's' and line_len >= 15: + if string.strncmp(dep_buf + line_start, "source_filename", 15) == 0: + continue + skipping = 0 + # 去重:declare(用 _IsFuncDeclaredOrDefined 避免误匹配 call 语句) + if line_len >= 8 and string.strncmp(dep_buf + line_start, "declare ", 8) == 0: + at: t.CSizeT = line_start + 8 + while at < line_start + line_len: + if dep_buf[at] == '@': + break + at += 1 + if at < line_start + line_len: + lp: t.CSizeT = at + 1 + while lp < line_start + line_len: + if dep_buf[lp] == '(': + break + lp += 1 + if lp < line_start + line_len: + saved: t.CChar = dep_buf[lp + 1] + dep_buf[lp + 1] = '\0' + if StubMergerIR._IsFuncDeclaredOrDefined(out_buf, dep_buf + at) != 0: + dep_buf[lp + 1] = saved + continue + dep_buf[lp + 1] = saved + # 去重:external global + if line_len > 0 and dep_buf[line_start] == '@': + eq: t.CSizeT = line_start + 1 + while eq < line_start + line_len: + if dep_buf[eq] == '=': + break + eq += 1 + if eq < line_start + line_len: + saved: t.CChar = dep_buf[eq + 1] + dep_buf[eq + 1] = '\0' + if string.strstr(out_buf, dep_buf + line_start) is not None: + dep_buf[eq + 1] = saved + continue + dep_buf[eq + 1] = saved + # 去重:type 定义(如 %"sha1.Point" = type {i32, i32}) + # 区分完整定义(= type { ... } / = type < ... >)和 opaque 声明(= type opaque) + # 当本地 stub 有 opaque 声明而依赖 stub 有完整定义时,注释掉 opaque 行, + # 让完整定义被追加,避免 LLC "Cannot allocate unsized type" 错误。 + if line_len > 0 and dep_buf[line_start] == '%': + eq2: t.CSizeT = line_start + 1 + while eq2 < line_start + line_len: + if dep_buf[eq2] == '=': + break + eq2 += 1 + if eq2 < line_start + line_len: + saved2: t.CChar = dep_buf[eq2 + 1] + dep_buf[eq2 + 1] = '\0' + # 检查依赖行是否为完整定义(= type { 或 = type <) + dep_is_full_def: int = 0 + if eq2 + 8 <= line_start + line_len: + if dep_buf[eq2 + 2] == 't' and dep_buf[eq2 + 3] == 'y' and dep_buf[eq2 + 4] == 'p' and dep_buf[eq2 + 5] == 'e' and dep_buf[eq2 + 6] == ' ': + if dep_buf[eq2 + 7] == '{' or dep_buf[eq2 + 7] == '<': + dep_is_full_def = 1 + if dep_is_full_def == 1: + # 依赖行是完整定义 + # 临时截断到 '=' 之前(不含 '='),辅助函数期望纯类型名前缀 + saved_eq: t.CChar = dep_buf[eq2] + dep_buf[eq2] = '\0' + # 1. 注释掉 out_buf 中的 opaque 声明(如果有) + commented: int = StubMergerIR._CommentOutOpaqueTypeInBuf(out_buf, dep_buf + line_start) + # 2. 检查 out_buf 中是否已有完整定义(避免重复) + has_full: int = StubMergerIR._HasFullTypeDefinition(out_buf, dep_buf + line_start) + dep_buf[eq2] = saved_eq + if has_full == 1: + dep_buf[eq2 + 1] = saved2 + continue + # 3. 追加完整定义 + else: + # 依赖行是 opaque 声明,用原有子串匹配去重 + found_opaque: t.CPtr = string.strstr(out_buf, dep_buf + line_start) + if found_opaque is not None: + dep_buf[eq2 + 1] = saved2 + continue + dep_buf[eq2 + 1] = saved2 + # 追加 + if out_pos + line_len + 2 < out_size: + string.strncpy(out_buf + out_pos, dep_buf + line_start, line_len) + out_pos += line_len + out_buf[out_pos] = '\n' + out_pos += 1 + out_buf[out_pos] = '\0' + return out_pos +# ============================================================ +# _LoadAndAppendTextDeclares - 从依赖 text.ll 提取 declare 追加到 out_buf +# +# 读取 {temp_dir}/{sha1}.text.ll,将 define 行转为 declare(提取函数签名), +# 跳过函数体,去重后追加到 out_buf。返回新 out_pos。 +# ============================================================ +def _LoadAndAppendTextDeclares(temp_dir: str, td_len: t.CSizeT, dep_sha1: str, + dep_buf: bytes, out_buf: bytes, out_size: t.CSizeT, + out_pos: t.CSizeT) -> t.CSizeT: + """从依赖 text.ll 提取 declare(define 转 declare),追加到 out_buf""" + if temp_dir is None or dep_sha1 is None or dep_buf is None or out_buf is None: + return out_pos + + text_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, dep_sha1, "text.ll") + if text_path is None: + return out_pos + tf_lt: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R) + if tf_lt.closed: + stdlib.free(text_path) + # 依赖 text 缺失:includes 映射内的模块缺失属编译错误(fail-fast), + # 非映射模块(如 t/c 内部库、用户文件)按设计跳过 + if StubMergerStore.LookupSha1RelPath(dep_sha1) is not None: + fb_lt: str = VLogger.fmt_buf() + if fb_lt is not None: + viperlib.snprintf(fb_lt, 1024, "依赖 text 缺失: %s", dep_sha1) + VLogger.error(fb_lt, "StubMerger") + return out_pos + text_br: t.CInt64T = tf_lt.read_all(dep_buf, STUB_READ_BUF_SIZE) + tf_lt.close() + stdlib.free(text_path) + if text_br <= 0: + # 依赖 text 为空:纯 stub 模块(如 stdio.vp 全 pass 声明)无函数体, + # text.ll 为空属合法形态,无可提取 declare,静默跳过 + return out_pos + if text_br < STUB_READ_BUF_SIZE: + dep_buf[text_br] = '\0' + else: + dep_buf[STUB_READ_BUF_SIZE - 1] = '\0' + + dep_pos_lt: t.CSizeT = 0 + in_body: int = 0 + while dep_pos_lt < text_br: + ls: t.CSizeT = dep_pos_lt + while dep_pos_lt < text_br: + if dep_buf[dep_pos_lt] == '\n': + break + dep_pos_lt += 1 + ll: t.CSizeT = dep_pos_lt - ls + if dep_pos_lt < text_br: + dep_pos_lt += 1 + + # 函数体跳过:直到单独的 } 行 + if in_body != 0: + if ll == 1 and dep_buf[ls] == '}': + in_body = 0 + continue + + # 跳过空行和 header + if ll == 0: + continue + c0: int = dep_buf[ls] + if c0 == ';': + continue + if c0 == 't' and ll >= 6 and string.strncmp(dep_buf + ls, "target", 6) == 0: + continue + if c0 == 's' and ll >= 15 and string.strncmp(dep_buf + ls, "source_filename", 15) == 0: + continue + + # 处理 define 行:转为 declare + if ll >= 7 and string.strncmp(dep_buf + ls, "define ", 7) == 0: + # 提取 @funcname( 用于去重 + at_lt: t.CSizeT = ls + 7 + while at_lt < ls + ll: + if dep_buf[at_lt] == '@': + break + at_lt += 1 + if at_lt >= ls + ll: + in_body = 1 + continue + lp_lt: t.CSizeT = at_lt + 1 + while lp_lt < ls + ll: + if dep_buf[lp_lt] == '(': + break + lp_lt += 1 + if lp_lt >= ls + ll: + in_body = 1 + continue + # 去重检查:用 _IsFuncDeclaredOrDefined 避免误匹配 call 语句 + saved_lt: t.CChar = dep_buf[lp_lt + 1] + dep_buf[lp_lt + 1] = '\0' + if StubMergerIR._IsFuncDeclaredOrDefined(out_buf, dep_buf + at_lt) != 0: + dep_buf[lp_lt + 1] = saved_lt + in_body = 1 + continue + dep_buf[lp_lt + 1] = saved_lt + + # 找行尾的 ' {' 并截断 + decl_end: t.CSizeT = ls + ll + if decl_end > ls + 1: + if dep_buf[decl_end - 1] == '{' and dep_buf[decl_end - 2] == ' ': + decl_end -= 2 + + # 输出: declare + content(skip "define " 7 chars, up to decl_end) + # 泛型特化方法 define 是 "define linkonce_odr ..."(FunctionPrint + # 对名含 '[' 的函数输出 linkonce_odr):若只跳过 "define " 会拼出 + # "declare linkonce_odr ..." → llc 报 "invalid linkage for function + # declaration"(LLVM 只允许 define 用 linkonce_odr,declare 必须 + # external)。对齐 TPC Phase2Translator 的 decl_line 剥 linkage 逻辑, + # 循环跳过所有 linkage 词。 + c_start_lt: t.CSizeT = ls + 7 + skipped_lt: int = 1 + while skipped_lt != 0: + skipped_lt = 0 + if c_start_lt + 13 <= decl_end and \ + string.strncmp(dep_buf + c_start_lt, "linkonce_odr ", 13) == 0: + c_start_lt += 13 + skipped_lt = 1 + elif c_start_lt + 10 <= decl_end and \ + string.strncmp(dep_buf + c_start_lt, "weak_odr ", 9) == 0: + c_start_lt += 9 + skipped_lt = 1 + elif c_start_lt + 10 <= decl_end and \ + string.strncmp(dep_buf + c_start_lt, "linkonce ", 9) == 0: + c_start_lt += 9 + skipped_lt = 1 + elif c_start_lt + 6 <= decl_end and \ + string.strncmp(dep_buf + c_start_lt, "weak ", 5) == 0: + c_start_lt += 5 + skipped_lt = 1 + elif c_start_lt + 10 <= decl_end and \ + string.strncmp(dep_buf + c_start_lt, "internal ", 9) == 0: + c_start_lt += 9 + skipped_lt = 1 + elif c_start_lt + 9 <= decl_end and \ + string.strncmp(dep_buf + c_start_lt, "private ", 8) == 0: + c_start_lt += 8 + skipped_lt = 1 + copy_len_lt: t.CSizeT = decl_end - c_start_lt + if out_pos + 8 + copy_len_lt + 2 < out_size: + string.strncpy(out_buf + out_pos, "declare ", 8) + out_pos += 8 + string.strncpy(out_buf + out_pos, dep_buf + c_start_lt, copy_len_lt) + out_pos += copy_len_lt + out_buf[out_pos] = '\n' + out_pos += 1 + out_buf[out_pos] = '\0' + in_body = 1 + continue + + # 提取类型定义(%... = type { ... } 或 %... = type < ... >) + # stub.ll 中只有 opaque 声明,需要从 text.ll 中提取完整定义 + # 用于 alloca 和 getelementptr 等需要完整类型的指令 + if ll > 0 and dep_buf[ls] == '%': + eq_td: t.CSizeT = ls + 1 + while eq_td < ls + ll: + if dep_buf[eq_td] == '=': + break + eq_td += 1 + if eq_td < ls + ll: + # 检查是否为完整定义(= type { 或 = type <) + dep_is_full_td: int = 0 + if eq_td + 8 <= ls + ll: + if dep_buf[eq_td + 2] == 't' and dep_buf[eq_td + 3] == 'y' \ + and dep_buf[eq_td + 4] == 'p' and dep_buf[eq_td + 5] == 'e' \ + and dep_buf[eq_td + 6] == ' ': + if dep_buf[eq_td + 7] == '{' or dep_buf[eq_td + 7] == '<': + dep_is_full_td = 1 + if dep_is_full_td == 1: + # 临时截断到 '=' 之前(不含 '='),辅助函数期望纯类型名前缀 + saved_eq_td: t.CChar = dep_buf[eq_td] + dep_buf[eq_td] = '\0' + # 1. 注释掉 out_buf 中的 opaque 声明(如果有) + StubMergerIR._CommentOutOpaqueTypeInBuf(out_buf, dep_buf + ls) + # 2. 检查 out_buf 中是否已有完整定义(避免重复) + has_full_td: int = StubMergerIR._HasFullTypeDefinition(out_buf, dep_buf + ls) + dep_buf[eq_td] = saved_eq_td + if has_full_td == 0: + # 追加完整类型定义 + if out_pos + ll + 2 < out_size: + string.strncpy(out_buf + out_pos, dep_buf + ls, ll) + out_pos += ll + out_buf[out_pos] = '\n' + out_pos += 1 + out_buf[out_pos] = '\0' + continue + + # 提取全局变量定义(@... = ...) + # 依赖 text.ll 中的全局变量带初值定义(如 @StubMerger._mbuddy = global ...) + # stub.ll 中只有 external 声明,需要从 text.ll 提取完整定义 + # 注释掉 out_buf 中的同名行(external 声明或旧定义),追加 text.ll 中的完整定义 + if ll > 0 and dep_buf[ls] == '@': + eq_gv: t.CSizeT = ls + 1 + while eq_gv < ls + ll: + if dep_buf[eq_gv] == '=': + break + eq_gv += 1 + if eq_gv < ls + ll: + # 截断到 '=' 之前(不含 '='),得到全局变量名 @name + saved_gv: t.CChar = dep_buf[eq_gv] + dep_buf[eq_gv] = '\0' + # 依赖方已有同名全局(stub 注入的 external 声明或先前依赖的定义) + # 时跳过:跨模块全局(如 _op_head、MemBuddy.vtable)只需一份 + # 强定义(在定义模块的 text.ll 中),复制进每个依赖方会导致 + # ld.lld duplicate symbol(NewAstTest _op_head/MemBuddy.vtable 根因)。 + # 仅当依赖方完全没有该全局(既无 external 也无定义)时才需要补充。 + if StubMergerIR._HasGlobalInBuf(out_buf, dep_buf + ls) == 0: + # 注释掉 out_buf 中的同名行(external 声明或旧定义) + StubMergerIR._CommentOutGlobalInBuf(out_buf, dep_buf + ls) + dep_buf[eq_gv] = saved_gv + # 追加完整定义 + if out_pos + ll + 2 < out_size: + string.strncpy(out_buf + out_pos, dep_buf + ls, ll) + out_pos += ll + out_buf[out_pos] = '\n' + out_pos += 1 + out_buf[out_pos] = '\0' + else: + dep_buf[eq_gv] = saved_gv + continue + + # 跳过其他行 + return out_pos +# ============================================================ +# _BuildReachableSha1Set - 构建可达 SHA1 集合(依赖图按需翻译) +# +# 从 source_dir 的源文件开始,解析 import 语句,递归收集可达的 +# includes 文件 SHA1。Phase 1b 只翻译可达集合中的文件,避免 +# 翻译不需要的 includes(如 Test 不依赖 llvmlite,则不翻译)。 +# +# 算法(工作列表): +# 1. 扫描 source_dir 下的 .vp/.py 文件,解析 AST 获取 _imported_modules +# 2. 构建 SHA1→module_name 映射(从全局内存存储器) +# 3. 工作列表递归:模块名 → 查 SHA1 → 加入 reachable_set → 读 .deps.txt → 追加新模块名 +# +# Args: +# mb: 内存池 +# source_dir: 源文件目录(Config.SourceDir) +# temp_dir: 临时目录(.deps.txt 所在位置;_sha1_map.txt 仅人类可读输出,不读取) +# reachable_set: 输出参数,可达 SHA1 集合缓冲区(MAX_INCLUDES_SHA1 * 17 字节) +# +# Returns: +# 可达 SHA1 数量(>0 成功,<=0 失败) +# ============================================================ +def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str, + temp_dir: str, + reachable_set: str, + app_deps: str = None) -> int: + """构建可达 SHA1 集合(依赖图按需翻译) + + app_deps: App 源文件的直接依赖模块名(空格分隔),如果非空则跳过自己的扫描步骤 + """ + if source_dir is None or temp_dir is None or reachable_set is None: + return -1 + + SRC_BUF_SIZE_R: t.CSizeT = 1048576 + + # 1. 构建 SHA1→module_name 映射 + td_len_r: t.CSizeT = string.strlen(temp_dir) + sha1_arr: bytes = stdlib.malloc(MAX_INCLUDES * 17) + mod_arr: bytes = stdlib.malloc(MAX_INCLUDES * 64) + if sha1_arr is None or mod_arr is None: + if sha1_arr is not None: + stdlib.free(sha1_arr) + if mod_arr is not None: + stdlib.free(mod_arr) + return -1 + map_count: int = StubMergerIR._BuildIncludesSha1Map(temp_dir, td_len_r, sha1_arr, mod_arr) + if map_count <= 0: + VLogger.error("无法构建 SHA1 映射", "Reachable") + stdlib.free(sha1_arr) + stdlib.free(mod_arr) + return -1 + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "SHA1 映射: %d 个", map_count) + VLogger.debug(fb, "Reachable") + + # 工作列表(空格分隔的模块名) + worklist: bytes = stdlib.malloc(REACH_WORKLIST_BUF) + if worklist is None: + stdlib.free(sha1_arr) + stdlib.free(mod_arr) + return -1 + worklist[0] = '\0' + wl_len: t.CSizeT = 0 + + reachable_count: int = 0 + + # 2. 如果 app_deps 非空,直接使用它作为初始 worklist(跳过自己的非递归扫描) + # 否则,回退到自己的非递归扫描(source_dir/*.py,只扫描顶层) + if app_deps is not None and app_deps[0] != '\0': + ad_len: t.CSizeT = string.strlen(app_deps) + if ad_len > 0 and ad_len < REACH_WORKLIST_BUF: + string.strcpy(worklist, app_deps) + wl_len = ad_len + else: + VLogger.error("app_deps 过长,无法构建可达集合", "StubMerger") + else: + # app_deps 缺失:Phase1 场景(未翻译 App 源文件)为设计性回退, + # 显式 warning 暴露回退,不再静默。 + # 原实现仅非递归扫描 source_dir 顶层("%s/*"),漏掉 lib/ 等子目录的 + # App 文件 → 其依赖(如 lib/Projectrans/Config.vp 的 json)不进入 + # worklist → json 不可达 → Phase1 不 stub 不翻译 → Phase2 Phase A + # 翻译 Config.vp 时 root.is_object() 跨模块调用无 stub 可查 → 静默 + # translate_value 返回 None → "if 条件表达式翻译失败"(追加82 根因)。 + # 改为递归扫描(复用 IncludesScanner.scan_includes),覆盖全部子目录。 + VLogger.warning("app_deps 缺失,递归扫描 source_dir", "Reachable") + scan_res_r: IncludesScanner.ScanResult | t.CPtr = IncludesScanner.scan_includes(mb, source_dir) + if scan_res_r is not None: + es_r: t.CSizeT = IncludesScanner.FileEntry.__sizeof__() + for e_i_r in range(scan_res_r.Count): + e_r: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)( + t.CVoid(t.CUInt64T(scan_res_r.Entries) + t.CUInt64T(e_i_r) * es_r, t.CPtr)) + if e_r is None or e_r.Path is None: + continue + sbuf: bytes = Utils.read_file_to_buf(e_r.Path, SRC_BUF_SIZE_R) + if sbuf is None: + continue + # 解析 AST 获取 _imported_modules(与原顶层扫描一致) + lx: ast.Lexer | t.CPtr = ast.new_lexer(mb) + if lx is not None: + ast._lexer_init(lx, sbuf, mb) + tokens: ast.Token | t.CPtr = ast.tokenize(lx) + tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens) + if tree is not None: + tr: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator() + if tr is not None: + tr._declare_only = 2 + # 源文件包名:用 RelPath(相对 source_dir,支持子目录), + # 保证 from .xxx import 相对导入解析正确 + tr.CurrentPackage = GenApi.compute_package_from_relpath(mb, e_r.RelPath) + GenApi.reset_visible_structs(mb, 0) + tr.translate(tree) + # 容器使用检测:App 源文件用 list/dict(裸名注解/构造/[] + # /{} 字面量)时注入 _list/_dict 依赖(与原实现一致) + tr._inject_auto_container_visibility(mb, tree) + # 获取 _imported_modules + if tr._imported_modules is not None: + # 逐模块去重追加(同 app_deps 拼接,防 worklist 膨胀溢出) + im_len: t.CSizeT = string.strlen(tr._imported_modules) + im_pos: t.CSizeT = 0 + while im_pos < im_len: + im_start: t.CSizeT = im_pos + while im_pos < im_len and tr._imported_modules[im_pos] != ' ': + im_pos += 1 + im_mod_len: t.CSizeT = im_pos - im_start + if im_pos < im_len: + im_pos += 1 + if im_mod_len == 0: + continue + im_buf: bytes = stdlib.malloc(im_mod_len + 1) + if im_buf is None: + continue + string.strncpy(im_buf, tr._imported_modules + im_start, im_mod_len) + im_buf[im_mod_len] = '\0' + if wl_len > 0 and GenApi.is_module_imported(worklist, im_buf) != 0: + stdlib.free(im_buf) + continue + if wl_len + im_mod_len + 2 < REACH_WORKLIST_BUF: + if wl_len > 0: + worklist[wl_len] = ' ' + wl_len += 1 + string.strcpy(worklist + wl_len, im_buf) + wl_len += im_mod_len + worklist[wl_len] = ' ' + wl_len += 1 + worklist[wl_len] = '\0' + stdlib.free(im_buf) + # 计算 App 源文件 SHA1,填充依赖到内存存储器 + # worklist 遍历时,LookupIncludesDeps 能找到 App 源文件的依赖 + if e_r.Sha1 is not None: + StubMergerStore.PopulateIncludesDeps(e_r.Sha1, tr._imported_modules) + # 释放 Translator 资源 + if tr._global_names is not None: + stdlib.free(tr._global_names) + if tr._nonlocal_names is not None: + stdlib.free(tr._nonlocal_names) + stdlib.free(sbuf) + + # 去掉末尾多余空格 + if wl_len > 0 and worklist[wl_len - 1] == ' ': + worklist[wl_len - 1] = '\0' + wl_len -= 1 + + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "源文件直接依赖: '%s'", worklist) + VLogger.debug(fb, "Reachable") + + # 2.5. 预加入基础模块(builtins) + # + # builtins(内置函数模块:ord/chr 等)始终纳入编译链,调用时自动关联。 + # _list/_dict 不再无条件预加入:Phase A 翻译 App 源文件时 + # _inject_auto_container_visibility 已按需检测 list/dict 使用并注入 + # _imported_modules(含 []/{} 字面量),json 由 _dict 的真实 import 链带入。 + if GenApi.is_module_imported(worklist, "builtins") == 0: + bsha1_b: str = StubMergerIR._FindSha1ByModName(sha1_arr, mod_arr, map_count, "builtins") + if bsha1_b is not None: + if wl_len + 9 < REACH_WORKLIST_BUF: + if wl_len > 0: + worklist[wl_len] = ' ' + wl_len += 1 + string.strcpy(worklist + wl_len, "builtins") + wl_len += 8 + worklist[wl_len] = ' ' + wl_len += 1 + worklist[wl_len] = '\0' + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "预加入容器模块后: '%s'", worklist) + VLogger.debug(fb, "Reachable") + + # 3. 工作列表算法:递归收集可达 SHA1 + processed: bytes = stdlib.malloc(REACH_WORKLIST_BUF) + if processed is None: + stdlib.free(sha1_arr) + stdlib.free(mod_arr) + stdlib.free(worklist) + return -1 + processed[0] = '\0' + proc_len: t.CSizeT = 0 + + wl_pos: t.CSizeT = 0 + wl_iter: int = 0 + while wl_pos < wl_len: + wl_iter += 1 + # 提取一个模块名(到空格或末尾) + name_start: t.CSizeT = wl_pos + while wl_pos < wl_len and worklist[wl_pos] != ' ': + wl_pos += 1 + name_len: t.CSizeT = wl_pos - name_start + if wl_pos < wl_len: + wl_pos += 1 + if name_len == 0: + continue + + # 复制模块名 + mod_buf: bytes = stdlib.malloc(name_len + 1) + if mod_buf is None: + continue + string.strncpy(mod_buf, worklist + name_start, name_len) + mod_buf[name_len] = '\0' + + # 检查是否已处理 + already: int = 0 + if GenApi.is_module_imported(processed, mod_buf) != 0: + already = 1 + if already == 0: + # 加入 processed(嵌套 if 拆分 + 用 = 代替 += 绕过 TPC AUGASGN bug) + if processed is not None: + if proc_len + name_len + 1 < REACH_WORKLIST_BUF: + string.strcpy(processed + proc_len, mod_buf) + proc_len = proc_len + name_len + processed[proc_len] = ' ' + proc_len = proc_len + 1 + processed[proc_len] = '\0' + else: + VLogger.error("依赖 worklist 溢出", "StubMerger") + + # 查找 SHA1 + found_sha1: str = StubMergerIR._FindSha1ByModName(sha1_arr, mod_arr, map_count, mod_buf) + if found_sha1 is not None: + # App 源文件(Sha1Store 中 IncDir 为空,AppendToSha1MapStore 规则) + # 不加入 reachable_set:Phase B 已编译其 .obj,若加入会导致 Phase B+ + # 把 App 文件重复编译进 includes.binary,Phase C 链接时与 Phase B 的 + # App obj 重复符号(SysLibTest ld.lld duplicate symbol: StubMerger._mbuddy 根因)。 + # 依赖仍继续展开(App 文件是依赖图中间节点,其 includes 依赖必须可达)。 + is_app_r: int = 0 + if StubMerger._sha1_store_incdir is not None: + for ai_r in range(StubMerger._sha1_store_count): + asi_r: t.CSizeT = t.CSizeT(ai_r) * 17 + if string.strcmp(StubMerger._sha1_store_arr + asi_r, found_sha1) == 0: + aii_r: t.CSizeT = t.CSizeT(ai_r) * MAX_INC_DIR_LEN + if StubMerger._sha1_store_incdir[aii_r] == '\0': + is_app_r = 1 + break + if is_app_r == 0: + reachable_count = StubMergerIR._AddSha1ToSet(reachable_set, reachable_count, found_sha1) + + # 从内存查找依赖(不读 deps.txt 过程文件) + # Phase B+ 前用 declare_only 翻译所有 includes 文件,提取 _imported_modules 存入内存 + deps_str: str = StubMergerStore.LookupIncludesDeps(found_sha1) + if deps_str is not None: + dl: t.CSizeT = string.strlen(deps_str) + if dl > 0: + # 逐模块追加 + 去重:worklist 初始已含全部 App 直接依赖, + # deps_str 中的模块若已在 worklist/processed 不重复追加, + # 否则 BFS 沿共享依赖(builtins/stdlib 等)反复累积到 + # 64KB 溢出("依赖 worklist 溢出"根因)。 + dpos: t.CSizeT = 0 + while dpos < dl: + dstart: t.CSizeT = dpos + while dpos < dl and deps_str[dpos] != ' ': + dpos += 1 + dlen: t.CSizeT = dpos - dstart + if dpos < dl: + dpos += 1 + if dlen == 0: + continue + dmod: bytes = stdlib.malloc(dlen + 1) + if dmod is None: + continue + string.strncpy(dmod, deps_str + dstart, dlen) + dmod[dlen] = '\0' + in_wl: int = 0 + if GenApi.is_module_imported(worklist, dmod) != 0: + in_wl = 1 + if in_wl == 0 and processed is not None: + if GenApi.is_module_imported(processed, dmod) != 0: + in_wl = 1 + if in_wl == 0: + if wl_len + dlen + 2 < REACH_WORKLIST_BUF: + if wl_len > 0 and worklist[wl_len - 1] != ' ': + worklist[wl_len] = ' ' + wl_len = wl_len + 1 + string.strcpy(worklist + wl_len, dmod) + wl_len = wl_len + dlen + worklist[wl_len] = ' ' + wl_len = wl_len + 1 + worklist[wl_len] = '\0' + else: + VLogger.error("依赖 worklist 溢出", "StubMerger") + stdlib.free(dmod) + # deps_str 为空字符串视为无依赖(合法情况,如叶子模块) + else: + # 依赖未在内存中找到 + # 按需过滤: 检查是否是 App 源文件(source_dir 下的 .vp/.py 文件) + # App 源文件不需要加入 reachable_set(只用于 includes 过滤),跳过 + sd_len_ff: t.CSizeT = string.strlen(source_dir) + mb_len_ff: t.CSizeT = string.strlen(mod_buf) + app_mod_path: bytes = stdlib.malloc(sd_len_ff + mb_len_ff + 6) + is_app_src: int = 0 + if app_mod_path is not None: + # 优先尝试 .vp,向后兼容 .py + viperlib.snprintf(app_mod_path, sd_len_ff + mb_len_ff + 6, "%s/%s.vp", source_dir, mod_buf) + af: fileio.File | t.CPtr = fileio.File(app_mod_path, fileio.MODE.R) + if not af.closed: + is_app_src = 1 + af.close() + else: + # .vp 不存在,回退 .py + viperlib.snprintf(app_mod_path, sd_len_ff + mb_len_ff + 6, "%s/%s.py", source_dir, mod_buf) + af = fileio.File(app_mod_path, fileio.MODE.R) + if not af.closed: + is_app_src = 1 + af.close() + stdlib.free(app_mod_path) + if is_app_src == 0: + # fast-fail: includes 文件依赖未在内存中找到,Phase 1a-pre 未正确填充 + fb_ff: str = VLogger.fmt_buf() + if fb_ff is not None: + viperlib.snprintf(fb_ff, 1024, "依赖未找到 fast-fail: 模块 %s(sha1=%s) 的依赖未在内存中注册", mod_buf, found_sha1) + VLogger.error(fb_ff, "Reachable") + stdlib.free(sha1_arr) + stdlib.free(mod_arr) + stdlib.free(worklist) + stdlib.free(processed) + stdlib.free(mod_buf) + return -1 + stdlib.free(mod_buf) + stdlib.free(sha1_arr) + stdlib.free(mod_arr) + stdlib.free(worklist) + stdlib.free(processed) + + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "可达 SHA1: %d 个", reachable_count) + VLogger.debug(fb, "Reachable") + return reachable_count +# ============================================================ +# BuildCombinedIR - 组合本地 stub + 依赖 stubs + 本地 text → 完整 IR +# +# 按需加载:读取 deps.txt 获取导入模块名,通过内存存储器查找 SHA1, +# 仅加载实际使用的依赖 stub(而非全部扫描)。 +# _sha1_map.txt 仅作为人类可读输出,程序内部不读取。 +# ============================================================ +def BuildCombinedIR(temp_dir: str, local_sha1: str, + out_buf: bytes, out_size: t.CSizeT) -> t.CSizeT: + """组合本地 stub + 依赖 stubs + 本地 text → out_buf(按需加载)""" + if temp_dir is None or local_sha1 is None or out_buf is None or out_size == 0: + return 0 + + td_len: t.CSizeT = string.strlen(temp_dir) + out_buf[0] = '\0' + out_pos: t.CSizeT = 0 + + # 1. 读取并追加本地 stub.ll(含 header) + stub_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, local_sha1, "stub.ll") + if stub_path is None: + return 0 + sf: fileio.File | t.CPtr = fileio.File(stub_path, fileio.MODE.R) + if sf.closed: + stdlib.free(stub_path) + return 0 + stub_content: bytes = stdlib.malloc(STUB_READ_BUF_SIZE) + if stub_content is None: + sf.close() + stdlib.free(stub_path) + return 0 + stub_br: t.CInt64T = sf.read_all(stub_content, STUB_READ_BUF_SIZE) + sf.close() + stdlib.free(stub_path) + if stub_br <= 0: + stdlib.free(stub_content) + return 0 + if stub_br < STUB_READ_BUF_SIZE: + stub_content[stub_br] = '\0' + else: + stub_content[STUB_READ_BUF_SIZE - 1] = '\0' + slen: t.CSizeT = stub_br + # 修复本地 stub.ll 中字符串常量的非法 IR: + # llvmlite OUTPUT_STUB 模式输出 "= external unnamed_addr constant" 的非法形式。 + # 简单方案:搜索 "= external unnamed_addr constant" 并将 external 替换为 8 个空格。 + fix_pos: t.CSizeT = 0 + while fix_pos + 30 < slen: + ext_ptr: t.CPtr = string.strstr(stub_content + fix_pos, "= external unnamed_addr constant") + if ext_ptr is None: + break + # ext_ptr 指向 "= external ..." 中的 '=' + # 'external' 开始于 ext_ptr + 2 + ext_off: t.CSizeT = t.CSizeT(t.CUInt64T(ext_ptr) - t.CUInt64T(stub_content)) + 2 + if ext_off + 8 <= slen: + stub_content[ext_off] = ' ' + stub_content[ext_off + 1] = ' ' + stub_content[ext_off + 2] = ' ' + stub_content[ext_off + 3] = ' ' + stub_content[ext_off + 4] = ' ' + stub_content[ext_off + 5] = ' ' + stub_content[ext_off + 6] = ' ' + stub_content[ext_off + 7] = ' ' + fix_pos = ext_off + 8 + # 直接复制修复后的 stub 内容 + if out_pos + slen + 2 < out_size: + string.strcpy(out_buf + out_pos, stub_content) + out_pos += slen + if out_buf[out_pos - 1] != '\n': + out_buf[out_pos] = '\n' + out_pos += 1 + out_buf[out_pos] = '\0' + stdlib.free(stub_content) + + # 2. 按需加载依赖 stubs(根据 deps.txt 过滤,而非扫描全部) + # 先加载依赖 stub(含 type 定义),确保 type 定义在本地 text.ll 的 define 块之前 + # 2a. 构建 includes SHA1 → module_name 映射(从全局内存存储器) + sha1_arr: bytes = stdlib.malloc(MAX_INCLUDES * 17) + mod_arr: bytes = stdlib.malloc(MAX_INCLUDES * 64) + inc_count: int = 0 + if sha1_arr is not None and mod_arr is not None: + inc_count = StubMergerIR._BuildIncludesSha1Map(temp_dir, td_len, sha1_arr, mod_arr) + + # 2b. 读取 deps.txt 获取导入模块名集合 + deps_buf: str = None + deps_loaded: int = 0 + deps_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, local_sha1, "deps.txt") + if deps_path is not None: + df_deps: fileio.File | t.CPtr = fileio.File(deps_path, fileio.MODE.R) + if not df_deps.closed: + deps_buf = stdlib.malloc(4096) + if deps_buf is not None: + deps_br: t.CInt64T = df_deps.read_all(deps_buf, 4096) + if deps_br > 0: + if deps_br < 4096: + deps_buf[deps_br] = '\0' + else: + deps_buf[4095] = '\0' + deps_loaded = 1 + elif deps_br == 0: + # 空 deps.txt:无 import 的包标记文件(如 lib/core/Gen/__init__.vp、 + # lib/StubGen/__init__.vp 纯注释)合法——deps_loaded 置 1 视为 + # "已加载且无依赖",避免下方"deps.txt 缺失"误报(追加85 根因)。 + # deps_buf 是 malloc 未初始化内存,必须显式置空串, + # 否则后续 strlen(deps_buf) 读到垃圾长度遍历越界。 + deps_buf[0] = '\0' + deps_loaded = 1 + df_deps.close() + stdlib.free(deps_path) + + # deps.txt 缺失但存在 includes 映射:依赖无法按需过滤,fail-fast 终止 + if deps_loaded == 0 and inc_count > 0: + VLogger.error("依赖文件 deps.txt 缺失,无法合并 includes stub", "StubMerger") + + # 2c. 递归扫描 temp_dir 中所有 .stub.ll,按需加载 + # 全目录扫描结果按 temp_dir 缓存(Phase B 对每个源文件调用一次 + # BuildCombinedIR,每次递归扫盘 O(N×S) 是 Phase B 慢的根因之一; + # 首次扫描后复用缓存,temp_dir 变化时自动重建) + cache_valid_sc: int = 0 + if StubMerger._stub_scan_cache_arr is not None and StubMerger._stub_scan_cache_dir is not None: + if string.strcmp(StubMerger._stub_scan_cache_dir, temp_dir) == 0: + cache_valid_sc = 1 + if cache_valid_sc == 0: + new_scan_arr: str = stdlib.malloc(MAX_INCLUDES_SHA1 * 17) + if new_scan_arr is not None: + string.memset(new_scan_arr, 0, MAX_INCLUDES_SHA1 * 17) + new_scan_count: int = StubMergerCollect._collect_stub_sha1s( + temp_dir, td_len, Config.Sha1SliceLevel, new_scan_arr, 0, MAX_INCLUDES_SHA1) + if new_scan_count > 0: + # 缓存目录键(stdlib 深拷贝,跨调用存活) + dir_buf_sc: str = stdlib.malloc(td_len + 1) + if dir_buf_sc is not None: + string.strcpy(dir_buf_sc, temp_dir) + if StubMerger._stub_scan_cache_arr is not None: + stdlib.free(StubMerger._stub_scan_cache_arr) + StubMerger._stub_scan_cache_arr = None + if StubMerger._stub_scan_cache_dir is not None: + stdlib.free(StubMerger._stub_scan_cache_dir) + StubMerger._stub_scan_cache_dir = None + StubMerger._stub_scan_cache_arr = new_scan_arr + StubMerger._stub_scan_cache_dir = dir_buf_sc + StubMerger._stub_scan_cache_count = new_scan_count + else: + stdlib.free(new_scan_arr) + else: + stdlib.free(new_scan_arr) + all_sha1_arr: str = StubMerger._stub_scan_cache_arr + all_count: int = StubMerger._stub_scan_cache_count + if all_sha1_arr is not None and all_count > 0: + dep_buf: bytes = stdlib.malloc(STUB_READ_BUF_SIZE) + if dep_buf is not None: + si: int = 0 + while si < all_count: + dep_sha1: str = all_sha1_arr + t.CSizeT(si) * 17 + if string.strcmp(dep_sha1, local_sha1) == 0: + si += 1 + continue + should_load: int = 0 + # 检查是否在 includes 映射中 + is_include: int = 0 + if inc_count > 0: + for ii in range(inc_count): + idx_ii: t.CSizeT = t.CSizeT(ii) * 17 + if string.strcmp(sha1_arr + idx_ii, dep_sha1) != 0: + continue + is_include = 1 + if deps_loaded != 0: + idx_mi: t.CSizeT = t.CSizeT(ii) * 64 + dep_mod_name: str = mod_arr + idx_mi + if GenApi.is_module_imported(deps_buf, dep_mod_name) != 0: + should_load = 1 + elif StubMergerIR._is_submodule_of_imported(deps_buf, dep_mod_name) != 0: + # 传递性依赖:deps.txt 只记录直接导入(如 ast), + # 但包的 __init__.vp 内部 from .lexer import Lexer + # 会让 IR 引用 ast.lexer 子模块类型。 + # 检查 dep_mod_name 是否是已导入包的子模块 + # (如 ast.lexer 是 ast 的子模块) + should_load = 1 + break + if is_include == 0: + # 非 includes stub(用户文件),总是加载 + should_load = 1 + if should_load != 0: + out_pos = _LoadAndAppendStub(temp_dir, td_len, dep_sha1, dep_buf, out_buf, out_size, out_pos) + out_pos = _LoadAndAppendTextDeclares(temp_dir, td_len, dep_sha1, dep_buf, out_buf, out_size, out_pos) + si += 1 + stdlib.free(dep_buf) + # all_sha1_arr 是模块级缓存(StubMerger._stub_scan_cache_arr),跨调用共享,不释放 + + # 2d. 验证 deps.txt 中所有依赖模块的 stub 文件都存在(fail-fast) + # 避免到 llc 才报 undefined value 错误。 + # 仅验证在 includes 映射中找到的模块(t/c 等内部库无 SHA1 映射,自动跳过)。 + if deps_loaded != 0 and inc_count > 0: + dep_total: t.CSizeT = string.strlen(deps_buf) + dp: t.CSizeT = 0 + while dp < dep_total: + # 跳过前导空格 + while dp < dep_total: + if deps_buf[dp] != ' ': + break + dp += 1 + if dp >= dep_total: + break + # 提取模块名(到下一个空格或末尾) + ms: t.CSizeT = dp + while dp < dep_total: + if deps_buf[dp] == ' ': + break + dp += 1 + ml: t.CSizeT = dp - ms + if ml == 0: + continue + # 复制模块名到临时缓冲区并 null 终止 + mod_nm: str = stdlib.malloc(ml + 1) + if mod_nm is None: + continue + string.strncpy(mod_nm, deps_buf + ms, ml) + mod_nm[ml] = '\0' + # 在 includes 映射中查找模块对应的 SHA1 + found_s: str = None + for mi2 in range(inc_count): + idx_m2: t.CSizeT = t.CSizeT(mi2) * 64 + if string.strcmp(mod_arr + idx_m2, mod_nm) == 0: + idx_s2: t.CSizeT = t.CSizeT(mi2) * 17 + found_s = sha1_arr + idx_s2 + break + if found_s is not None: + # 检查 stub 文件是否存在 + chk_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, found_s, "stub.ll") + if chk_path is not None: + chk_f: fileio.File | t.CPtr = fileio.File(chk_path, fileio.MODE.R) + if chk_f.closed: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "依赖模块 '%s' (sha1=%s) 的 stub 文件不存在: %s,立即终止编译", mod_nm, found_s, chk_path) + VLogger.error(fb, "BuildCombinedIR") + chk_f.close() + stdlib.free(chk_path) + stdlib.free(mod_nm) + + # 3. 读取并追加本地 text.ll(行级去重,跳过 stub.ll 中已存在的定义) + text_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, local_sha1, "text.ll") + if text_path is None: + return out_pos + tf: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R) + if tf.closed: + # 本地 text.ll 缺失:合并 IR 无法生成定义块,fail-fast 终止 + fb_tlp: str = VLogger.fmt_buf() + if fb_tlp is not None: + viperlib.snprintf(fb_tlp, 1024, "本地 text.ll 缺失: %s", text_path) + VLogger.error(fb_tlp, "StubMerger") + stdlib.free(text_path) + else: + text_content: bytes = stdlib.malloc(STUB_READ_BUF_SIZE) + if text_content is None: + tf.close() + stdlib.free(text_path) + else: + text_br: t.CInt64T = tf.read_all(text_content, STUB_READ_BUF_SIZE) + tf.close() + stdlib.free(text_path) + if text_br > 0: + if text_br < STUB_READ_BUF_SIZE: + text_content[text_br] = '\0' + else: + text_content[STUB_READ_BUF_SIZE - 1] = '\0' + # 行级去重追加(与 _LoadAndAppendStub 相同逻辑) + tx_pos: t.CSizeT = 0 + tx_skip: int = 1 + while tx_pos < text_br: + tx_ls: t.CSizeT = tx_pos + while tx_pos < text_br: + if text_content[tx_pos] == '\n': + break + tx_pos += 1 + tx_ll: t.CSizeT = tx_pos - tx_ls + if tx_pos < text_br: + tx_pos += 1 + if tx_skip != 0: + if tx_ll == 0: + continue + tx_c0: int = text_content[tx_ls] + if tx_c0 == ';': + continue + if tx_c0 == 't' and tx_ll >= 6: + if string.strncmp(text_content + tx_ls, "target", 6) == 0: + continue + if tx_c0 == 's' and tx_ll >= 15: + if string.strncmp(text_content + tx_ls, "source_filename", 15) == 0: + continue + tx_skip = 0 + # 去重:declare(用 _IsFuncDeclaredOrDefined 避免误匹配 call 语句) + if tx_ll >= 8 and string.strncmp(text_content + tx_ls, "declare ", 8) == 0: + tx_at: t.CSizeT = tx_ls + 8 + while tx_at < tx_ls + tx_ll: + if text_content[tx_at] == '@': + break + tx_at += 1 + if tx_at < tx_ls + tx_ll: + tx_lp: t.CSizeT = tx_at + 1 + while tx_lp < tx_ls + tx_ll: + if text_content[tx_lp] == '(': + break + tx_lp += 1 + if tx_lp < tx_ls + tx_ll: + tx_sv: t.CChar = text_content[tx_lp + 1] + text_content[tx_lp + 1] = '\0' + if StubMergerIR._IsFuncDeclaredOrDefined(out_buf, text_content + tx_at) != 0: + text_content[tx_lp + 1] = tx_sv + continue + text_content[tx_lp + 1] = tx_sv + # 去重:define(注释掉 out_buf 中已有的 declare,避免 declare/define 冲突) + if tx_ll >= 7 and string.strncmp(text_content + tx_ls, "define ", 7) == 0: + tx_at_d: t.CSizeT = tx_ls + 7 + while tx_at_d < tx_ls + tx_ll: + if text_content[tx_at_d] == '@': + break + tx_at_d += 1 + if tx_at_d < tx_ls + tx_ll: + tx_lp_d: t.CSizeT = tx_at_d + 1 + while tx_lp_d < tx_ls + tx_ll: + if text_content[tx_lp_d] == '(': + break + tx_lp_d += 1 + if tx_lp_d < tx_ls + tx_ll: + tx_sv_d: t.CChar = text_content[tx_lp_d + 1] + text_content[tx_lp_d + 1] = '\0' + StubMergerIR._CommentOutDeclareInBuf(out_buf, text_content + tx_at_d) + text_content[tx_lp_d + 1] = tx_sv_d + # 处理:@global = ... + # stub 中可能是 external 声明或完整定义,以 text 中的定义为准 + # 找到 stub 中同名全局变量行并注释掉,然后追加 text 中的 + if tx_ll > 0 and text_content[tx_ls] == '@': + tx_eq: t.CSizeT = tx_ls + 1 + while tx_eq < tx_ls + tx_ll: + if text_content[tx_eq] == '=': + break + tx_eq += 1 + if tx_eq < tx_ls + tx_ll: + tx_sv2: t.CChar = text_content[tx_eq + 1] + text_content[tx_eq + 1] = '\0' + StubMergerIR._CommentOutGlobalInBuf(out_buf, text_content + tx_ls) + text_content[tx_eq + 1] = tx_sv2 + # 去重:%type = ... + if tx_ll > 0 and text_content[tx_ls] == '%': + tx_eq2: t.CSizeT = tx_ls + 1 + while tx_eq2 < tx_ls + tx_ll: + if text_content[tx_eq2] == '=': + break + tx_eq2 += 1 + if tx_eq2 < tx_ls + tx_ll: + tx_sv3: t.CChar = text_content[tx_eq2 + 1] + text_content[tx_eq2 + 1] = '\0' + if string.strstr(out_buf, text_content + tx_ls) is not None: + text_content[tx_eq2 + 1] = tx_sv3 + continue + text_content[tx_eq2 + 1] = tx_sv3 + # 追加 + if out_pos + tx_ll + 2 < out_size: + string.strncpy(out_buf + out_pos, text_content + tx_ls, tx_ll) + out_pos += tx_ll + out_buf[out_pos] = '\n' + out_pos += 1 + out_buf[out_pos] = '\0' + stdlib.free(text_content) + + if deps_buf is not None: + stdlib.free(deps_buf) + if sha1_arr is not None: + stdlib.free(sha1_arr) + if mod_arr is not None: + stdlib.free(mod_arr) + + return out_pos +# ============================================================ +# LoadDepVpiIntoModule - 加载依赖模块的 .vpi 文件,注入 declare 到当前模块 +# +# 遍历 imported_modules(空格分隔的模块名),对每个模块: +# 1. 用 LookupSha1ByModName 获取 SHA1 +# 2. 用 _sliced_path 构造 .vpi 文件路径 +# 3. 调用 VpiReader.ParseVpiIntoModule 解析 .vpi 并注入 declare +# +# 在 _translate_module_level 中、Import 处理完成后、translate_children +# 之前调用,确保跨模块函数调用时 declare 已存在。 +# +# Args: +# pool: 内存池 +# mod: 当前 LLVM 模块 +# imported_modules: 已导入模块名字符串(空格分隔) +# from_imports: from-import 映射字符串("name:module name:module" 格式) +# temp_dir: temp 目录路径 +# trans: 翻译器对象 +# +# Returns: +# 成功加载的 .vpi 文件数 +# ============================================================ +def LoadDepVpiIntoModule(pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + imported_modules: str, + from_imports: str, + temp_dir: str, + trans: HandlesTranslator.Translator | t.CPtr) -> int: + """加载依赖模块的 .vpi 文件,将函数声明注入到当前模块""" + if pool is None or mod is None or temp_dir is None or trans is None: + return 0 + if imported_modules is None: + return 0 + + td_len: t.CSizeT = string.strlen(temp_dir) + total_len: t.CSizeT = string.strlen(imported_modules) + success_count: int = 0 + + # 遍历 imported_modules 中的每个模块名(空格分隔) + ci: t.CSizeT = 0 + while ci < total_len: + # 跳过前导空格 + while ci < total_len and imported_modules[ci] == ' ': + ci += 1 + if ci >= total_len: + break + # 提取模块名(到下一个空格或字符串末尾) + word_start: t.CSizeT = ci + while ci < total_len and imported_modules[ci] != ' ': + ci += 1 + word_len: t.CSizeT = ci - word_start + if word_len == 0: + continue + + # 复制模块名到临时缓冲区并 null 终止 + mod_nm_buf: str = stdlib.malloc(word_len + 1) + if mod_nm_buf is None: + continue + string.strncpy(mod_nm_buf, imported_modules + word_start, word_len) + mod_nm_buf[word_len] = '\0' + + # 用 LookupSha1ByModName 查找模块的 SHA1 + sha1_val: str = StubMergerStore.LookupSha1ByModName(mod_nm_buf) + + # 如果精确查找失败,尝试包名回退(如 "ast" → "ast.__init__") + # LookupSha1ByModName 内部已处理包名回退,此处无需重复 + + if sha1_val is not None: + # 构造 .vpi 文件路径 + vpi_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, sha1_val, "vpi") + if vpi_path is not None: + # 检查 .vpi 文件是否存在(可读) + vf: fileio.File | t.CPtr = fileio.File(vpi_path, fileio.MODE.R) + if not vf.closed: + vf.close() + # 调用 VpiReader 解析 .vpi 并注入 declare + # (错误上下文帧由调用方 HandlesTranslator 维护) + ret: int = VpiReader.ParseVpiIntoModule(pool, mod, vpi_path, trans) + if ret == 1: + success_count += 1 + stdlib.free(vpi_path) + # sha1_val 指向内部存储,无需 free + + stdlib.free(mod_nm_buf) + + return success_count diff --git a/App/lib/core/StubMergerCollect.vp b/App/lib/core/StubMergerCollect.vp index 8dcb2ec..1d4fb34 100644 --- a/App/lib/core/StubMergerCollect.vp +++ b/App/lib/core/StubMergerCollect.vp @@ -1,286 +1,284 @@ -import t, c -from stdint import * -import memhub -import string -import stdlib -import llvmlite -import w32.win32file as win32file -import w32.win32base as win32base -import w32.fileio as fileio -import viperlib -import sys -import ast -import lib.core.VLogger as VLogger -import lib.core.IncludesScanner as IncludesScanner -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesTranslator as HandlesTranslator -import lib.core.BuildPipeline as BuildPipeline -import lib.StubGen.VpiReader as VpiReader -import lib.Projectrans.Utils as Utils -import lib.Projectrans.Config as Config - - -import lib.core.StubMergerStore as StubMergerStore -import lib.core.StubMergerTopo as StubMergerTopo -import lib.core.StubMergerIR as StubMergerIR -import lib.core.StubMergerBuild as StubMergerBuild -import lib.core.StubMerger as StubMerger - -# ============================================================ -# StubMergerCollect - StubMerger 拆分(阶段 E):StubMergerCollect -# -# 直接移动模式:函数实现迁至此模块,原 StubMerger.vp 仅保留 -# 常量/全局变量;调用方经本模块前缀访问。全局变量跨模块经 -# StubMerger._xxx 访问(main.vp 先例)。 -# ============================================================ - -# ============================================================ -# _sliced_path - 构建切片路径(stdlib.malloc 分配,调用者负责 free) -# -# 根据 Config.Sha1SliceLevel 将文件分散到 SHA1 前缀子目录: -# level=0 → {temp_dir}/{sha1}.{ext} -# level=1 → {temp_dir}/b7/{sha1}.{ext} -# level=2 → {temp_dir}/b7/90/{sha1}.{ext} -# -# 自动调用 BuildPipeline.ensure_dir 创建子目录(level>0 时)。 -# -# Args: -# temp_dir: 基础目录 -# td_len: temp_dir 长度(避免重复 strlen) -# sha1: SHA1 字符串 -# ext: 文件扩展名(如 "stub.ll") -# -# Returns: -# 完整路径(stdlib.malloc 分配,需 stdlib.free),None 失败 -# ============================================================ -def _sliced_path(temp_dir: str, td_len: t.CSizeT, sha1: str, ext: str) -> str: - """构建切片路径(stdlib.malloc 分配,调用者负责 free) - - level>0 时自动调用 ensure_dir 创建子目录。 - """ - if temp_dir is None or sha1 is None or ext is None: - return None - sha1_len: t.CSizeT = string.strlen(sha1) - ext_len: t.CSizeT = string.strlen(ext) - - # 子目录前缀:复用 Config.slice_subdir(SHA1 切片唯一权威实现,mbuddy 分配无需 free) - subdir_buf: str = Config.slice_subdir(sha1, Config.Sha1SliceLevel) - sub_len: t.CSizeT = 0 - if subdir_buf is not None: - sub_len = string.strlen(subdir_buf) - - # 确保子目录存在: {temp_dir}/{subdir} - # 不创建目录会导致 fileio.File(MODE.W) 静默失败(file.closed==True), - # 进而 BuildCombinedIR 读不到文件返回 0("BuildCombinedIR 失败")。 - dir_path_len: t.CSizeT = td_len + sub_len + 2 - dir_path: bytes = stdlib.malloc(dir_path_len) - if dir_path is not None: - viperlib.snprintf(dir_path, dir_path_len, "%s/%s", temp_dir, subdir_buf) - BuildPipeline.ensure_dir(dir_path) - stdlib.free(dir_path) - - # 构建完整路径 - path: str = None - path_len: t.CSizeT = 0 - if sub_len > 0: - path_len = td_len + sub_len + sha1_len + ext_len + 4 - path = stdlib.malloc(path_len) - if path is not None: - viperlib.snprintf(path, path_len, "%s/%s/%s.%s", temp_dir, subdir_buf, sha1, ext) - else: - path_len = td_len + sha1_len + ext_len + 3 - path = stdlib.malloc(path_len) - if path is not None: - viperlib.snprintf(path, path_len, "%s/%s.%s", temp_dir, sha1, ext) - - return path -# ============================================================ -# _collect_stub_sha1s - 递归扫描子目录,收集 .stub.ll 文件的 SHA1 -# -# 根据 level 递归扫描子目录: -# level=0 → 扫描 {base_dir}/*.stub.ll,从文件名提取 SHA1 -# level>0 → 扫描 {base_dir}/* 的子目录,对每个子目录递归调用 -# -# Args: -# base_dir: 当前扫描目录 -# bd_len: base_dir 长度 -# level: 剩余递归层数 -# out_arr: 输出数组(每个 SHA1 17 字节 = 16字符 + null) -# out_count: 当前已收集数量 -# max_count: 最大数量 -# -# Returns: -# 收集后的总数量 -# ============================================================ -def _collect_stub_sha1s(base_dir: str, bd_len: t.CSizeT, level: int, - out_arr: str, out_count: int, max_count: int) -> int: - """递归扫描子目录,收集 .stub.ll 文件的 SHA1""" - if base_dir is None or out_arr is None: - return out_count - if out_count >= max_count: - return out_count - - find_data: win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(win32file.WIN32_FIND_DATAA.__sizeof__()) - if find_data is None: - return out_count - string.memset(find_data, 0, win32file.WIN32_FIND_DATAA.__sizeof__()) - - if level <= 0: - # 扫描 {base_dir}/*.stub.ll - pattern: bytes = stdlib.malloc(bd_len + 16) - if pattern is None: - stdlib.free(find_data) - return out_count - viperlib.snprintf(pattern, bd_len + 16, "%s/*.stub.ll", base_dir) - handle: win32base.HANDLE = win32file.FindFirstFileA(pattern, find_data) - stdlib.free(pattern) - if handle != win32base.INVALID_HANDLE_VALUE: - while 1: - if out_count >= max_count: - break - fname: str = find_data.cFileName - if fname is not None: - if fname[0] != '\0': - # 从文件名提取 SHA1(前 16 字符) - string.strncpy(out_arr + out_count * 17, fname, 16) - out_arr[out_count * 17 + 16] = '\0' - out_count += 1 - if win32file.FindNextFileA(handle, find_data) == 0: - break - win32file.FindClose(handle) - else: - # 扫描 {base_dir}/* 的子目录 - pattern = stdlib.malloc(bd_len + 4) - if pattern is None: - stdlib.free(find_data) - return out_count - viperlib.snprintf(pattern, bd_len + 4, "%s/*", base_dir) - handle = win32file.FindFirstFileA(pattern, find_data) - stdlib.free(pattern) - if handle != win32base.INVALID_HANDLE_VALUE: - while 1: - # 检查是否是目录(FILE_ATTRIBUTE_DIRECTORY = 0x10 = 16) - attrs: t.CUInt32T = find_data.dwFileAttributes - if(attrs & 16) != 0: - fname = find_data.cFileName - if fname is not None: - # 跳过 "." 和 ".." - is_dot: int = 0 - if fname[0] == '.': - if fname[1] == '\0': - is_dot = 1 - elif fname[1] == '.' and fname[2] == '\0': - is_dot = 1 - if is_dot == 0: - # 构建子目录路径并递归扫描 - sub_dir: str = Utils.JoinPath(base_dir, fname) - if sub_dir is not None: - sub_dir_len: t.CSizeT = string.strlen(sub_dir) - out_count = _collect_stub_sha1s(sub_dir, sub_dir_len, level - 1, out_arr, out_count, max_count) - stdlib.free(sub_dir) - if win32file.FindNextFileA(handle, find_data) == 0: - break - win32file.FindClose(handle) - - stdlib.free(find_data) - return out_count -# ============================================================ -# _load_includes_sha1_set - 从全局内存存储器收集 includes 的 SHA1 -# -# 数据来源是 PopulateSha1MapStore 填充的全局存储器(不读取 _sha1_map.txt)。 -# 用于过滤 stub 文件,避免加载 TransPyV 自身源文件(lib/*)的 stub 导致链接失败。 -# ============================================================ -def _load_includes_sha1_set(pool: memhub.MemBuddy | t.CPtr, - temp_dir: str, - sha1_set: str) -> int: - """从全局内存存储器将 includes 的 SHA1 写入 sha1_set - - pool/temp_dir 参数保留以兼容现有调用者,但不再使用。 - 数据来源是 PopulateSha1MapStore 填充的全局存储器。 - sha1_set 大小为 MAX_INCLUDES_SHA1 * 17(每个 SHA1 16字符+null) - 返回找到的 includes SHA1 数量,-1 表示错误""" - if sha1_set is None: - return -1 - if StubMerger._sha1_store_arr is None: - return -1 - count: int = 0 - for i in range(StubMerger._sha1_store_count): - if count >= MAX_INCLUDES_SHA1: - break - idx: t.CSizeT = t.CSizeT(i) * 17 - string.strcpy(sha1_set + t.CSizeT(count) * 17, StubMerger._sha1_store_arr + idx) - count += 1 - return count -# ============================================================ -# _is_in_sha1_set - 检查 SHA1 是否在集合中 -# ============================================================ -def _is_in_sha1_set(sha1: str, sha1_set: str, set_count: int) -> int: - """检查 sha1 是否在集合中""" - if sha1 is None or sha1_set is None: - return 0 - for i in range(set_count): - if string.strcmp(sha1_set + i * 17, sha1) == 0: - return 1 - return 0 -# ============================================================ -# WriteIncludesSha1Map - 将 includes 扫描结果写入 _sha1_map.txt(人类可读输出) -# -# _sha1_map.txt 仅作为人类可读的调试输出,程序内部不读取此文件。 -# 机器分析使用 PopulateSha1MapStore 填充的全局内存存储器。 -# -# Args: -# mb: 内存池 -# temp_dir: 临时目录(_sha1_map.txt 写入位置) -# scan_result: IncludesScanner 扫描结果 -# -# Returns: -# 0 成功,非 0 失败 -# ============================================================ -def WriteIncludesSha1Map(mb: memhub.MemBuddy | t.CPtr, temp_dir: str, - scan_result: IncludesScanner.ScanResult | t.CPtr, - filter_set: str, - filter_count: int) -> int: - """将 includes 扫描结果写入 _sha1_map.txt(人类可读输出,程序内部使用内存存储器) - - 若 filter_set 不为 None 且 filter_count > 0,只写入 filter_set 中的条目。 - """ - if temp_dir is None or scan_result is None: - return 1 - - # 构造路径 temp_dir/_sha1_map.txt - dir_len: t.CSizeT = string.strlen(temp_dir) - map_path: bytes = stdlib.malloc(dir_len + 32) - if map_path is None: - return 1 - viperlib.snprintf(map_path, dir_len + 32, "%s/_sha1_map.txt", temp_dir) - - # 打开文件写入(CREATE_ALWAYS) - f: fileio.File | t.CPtr = fileio.File(map_path, fileio.MODE.W) - if f.closed: - return 1 - - # 写入每个 include 条目: {sha1}:includes/{rel_path}\n - entry_size_w: t.CSizeT = IncludesScanner.FileEntry.__sizeof__() - line_buf: bytes = stdlib.malloc(512) - if line_buf is None: - f.close() - return 1 - - written_count: int = 0 - for i in range(scan_result.Count): - ea_w: t.CUInt64T = t.CUInt64T(scan_result.Entries) + i * entry_size_w - ent_w: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea_w, t.CPtr)) - if ent_w is None or ent_w.Sha1 is None or ent_w.RelPath is None: - continue - # 若提供过滤集合,只写入集合中的条目 - if filter_set is not None and filter_count > 0: - if _is_in_sha1_set(ent_w.Sha1, filter_set, filter_count) == 0: - continue - viperlib.snprintf(line_buf, 512, "%s:includes/%s\n", ent_w.Sha1, ent_w.RelPath) - line_len_w: t.CSizeT = string.strlen(line_buf) - f.write(line_buf, line_len_w) - written_count += 1 - - f.close() - return 0 +import t, c +from stdint import * +import memhub +import string +import stdlib +import llvmlite +import w32.win32file as win32file +import w32.win32base as win32base +import w32.fileio as fileio +import viperlib +import sys +import ast +import lib.core.VLogger as VLogger +import lib.core.IncludesScanner as IncludesScanner +import lib.core.Handles.HandlesTranslator as HandlesTranslator +import lib.core.BuildPipeline as BuildPipeline +import lib.StubGen.VpiReader as VpiReader +import lib.Projectrans.Utils as Utils +import lib.Projectrans.Config as Config + + +import lib.core.StubMergerStore as StubMergerStore +import lib.core.StubMergerTopo as StubMergerTopo +import lib.core.StubMergerIR as StubMergerIR +import lib.core.StubMergerBuild as StubMergerBuild +import lib.core.StubMerger as StubMerger + +# ============================================================ +# StubMergerCollect - StubMerger 拆分(阶段 E):StubMergerCollect +# +# 直接移动模式:函数实现迁至此模块,原 StubMerger.vp 仅保留 +# 常量/全局变量;调用方经本模块前缀访问。全局变量跨模块经 +# StubMerger._xxx 访问(main.vp 先例)。 +# ============================================================ + +# ============================================================ +# _sliced_path - 构建切片路径(stdlib.malloc 分配,调用者负责 free) +# +# 根据 Config.Sha1SliceLevel 将文件分散到 SHA1 前缀子目录: +# level=0 → {temp_dir}/{sha1}.{ext} +# level=1 → {temp_dir}/b7/{sha1}.{ext} +# level=2 → {temp_dir}/b7/90/{sha1}.{ext} +# +# 自动调用 BuildPipeline.ensure_dir 创建子目录(level>0 时)。 +# +# Args: +# temp_dir: 基础目录 +# td_len: temp_dir 长度(避免重复 strlen) +# sha1: SHA1 字符串 +# ext: 文件扩展名(如 "stub.ll") +# +# Returns: +# 完整路径(stdlib.malloc 分配,需 stdlib.free),None 失败 +# ============================================================ +def _sliced_path(temp_dir: str, td_len: t.CSizeT, sha1: str, ext: str) -> str: + """构建切片路径(stdlib.malloc 分配,调用者负责 free) + + level>0 时自动调用 ensure_dir 创建子目录。 + """ + if temp_dir is None or sha1 is None or ext is None: + return None + sha1_len: t.CSizeT = string.strlen(sha1) + ext_len: t.CSizeT = string.strlen(ext) + + # 子目录前缀:复用 Config.slice_subdir(SHA1 切片唯一权威实现,mbuddy 分配无需 free) + subdir_buf: str = Config.slice_subdir(sha1, Config.Sha1SliceLevel) + sub_len: t.CSizeT = 0 + if subdir_buf is not None: + sub_len = string.strlen(subdir_buf) + + # 确保子目录存在: {temp_dir}/{subdir} + # 不创建目录会导致 fileio.File(MODE.W) 静默失败(file.closed==True), + # 进而 BuildCombinedIR 读不到文件返回 0("BuildCombinedIR 失败")。 + dir_path_len: t.CSizeT = td_len + sub_len + 2 + dir_path: bytes = stdlib.malloc(dir_path_len) + if dir_path is not None: + viperlib.snprintf(dir_path, dir_path_len, "%s/%s", temp_dir, subdir_buf) + BuildPipeline.ensure_dir(dir_path) + stdlib.free(dir_path) + + # 构建完整路径 + path: str = None + path_len: t.CSizeT = 0 + if sub_len > 0: + path_len = td_len + sub_len + sha1_len + ext_len + 4 + path = stdlib.malloc(path_len) + if path is not None: + viperlib.snprintf(path, path_len, "%s/%s/%s.%s", temp_dir, subdir_buf, sha1, ext) + else: + path_len = td_len + sha1_len + ext_len + 3 + path = stdlib.malloc(path_len) + if path is not None: + viperlib.snprintf(path, path_len, "%s/%s.%s", temp_dir, sha1, ext) + + return path +# ============================================================ +# _collect_stub_sha1s - 递归扫描子目录,收集 .stub.ll 文件的 SHA1 +# +# 根据 level 递归扫描子目录: +# level=0 → 扫描 {base_dir}/*.stub.ll,从文件名提取 SHA1 +# level>0 → 扫描 {base_dir}/* 的子目录,对每个子目录递归调用 +# +# Args: +# base_dir: 当前扫描目录 +# bd_len: base_dir 长度 +# level: 剩余递归层数 +# out_arr: 输出数组(每个 SHA1 17 字节 = 16字符 + null) +# out_count: 当前已收集数量 +# max_count: 最大数量 +# +# Returns: +# 收集后的总数量 +# ============================================================ +def _collect_stub_sha1s(base_dir: str, bd_len: t.CSizeT, level: int, + out_arr: str, out_count: int, max_count: int) -> int: + """递归扫描子目录,收集 .stub.ll 文件的 SHA1""" + if base_dir is None or out_arr is None: + return out_count + if out_count >= max_count: + return out_count + + find_data: win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(win32file.WIN32_FIND_DATAA.__sizeof__()) + if find_data is None: + return out_count + string.memset(find_data, 0, win32file.WIN32_FIND_DATAA.__sizeof__()) + + if level <= 0: + # 扫描 {base_dir}/*.stub.ll + pattern: bytes = stdlib.malloc(bd_len + 16) + if pattern is None: + stdlib.free(find_data) + return out_count + viperlib.snprintf(pattern, bd_len + 16, "%s/*.stub.ll", base_dir) + handle: win32base.HANDLE = win32file.FindFirstFileA(pattern, find_data) + stdlib.free(pattern) + if handle != win32base.INVALID_HANDLE_VALUE: + while 1: + if out_count >= max_count: + break + fname: str = find_data.cFileName + if fname is not None: + if fname[0] != '\0': + # 从文件名提取 SHA1(前 16 字符) + string.strncpy(out_arr + out_count * 17, fname, 16) + out_arr[out_count * 17 + 16] = '\0' + out_count += 1 + if win32file.FindNextFileA(handle, find_data) == 0: + break + win32file.FindClose(handle) + else: + # 扫描 {base_dir}/* 的子目录 + pattern = stdlib.malloc(bd_len + 4) + if pattern is None: + stdlib.free(find_data) + return out_count + viperlib.snprintf(pattern, bd_len + 4, "%s/*", base_dir) + handle = win32file.FindFirstFileA(pattern, find_data) + stdlib.free(pattern) + if handle != win32base.INVALID_HANDLE_VALUE: + while 1: + # 检查是否是目录(FILE_ATTRIBUTE_DIRECTORY = 0x10 = 16) + attrs: t.CUInt32T = find_data.dwFileAttributes + if(attrs & 16) != 0: + fname = find_data.cFileName + if fname is not None: + # 跳过 "." 和 ".." + is_dot: int = 0 + if fname[0] == '.': + if fname[1] == '\0': + is_dot = 1 + elif fname[1] == '.' and fname[2] == '\0': + is_dot = 1 + if is_dot == 0: + # 构建子目录路径并递归扫描 + sub_dir: str = Utils.JoinPath(base_dir, fname) + if sub_dir is not None: + sub_dir_len: t.CSizeT = string.strlen(sub_dir) + out_count = _collect_stub_sha1s(sub_dir, sub_dir_len, level - 1, out_arr, out_count, max_count) + stdlib.free(sub_dir) + if win32file.FindNextFileA(handle, find_data) == 0: + break + win32file.FindClose(handle) + + stdlib.free(find_data) + return out_count +# ============================================================ +# _load_includes_sha1_set - 从全局内存存储器收集 includes 的 SHA1 +# +# 数据来源是 PopulateSha1MapStore 填充的全局存储器(不读取 _sha1_map.txt)。 +# 用于过滤 stub 文件,避免加载 TransPyV 自身源文件(lib/*)的 stub 导致链接失败。 +# ============================================================ +def _load_includes_sha1_set(pool: memhub.MemBuddy | t.CPtr, + temp_dir: str, + sha1_set: str) -> int: + """从全局内存存储器将 includes 的 SHA1 写入 sha1_set + + pool/temp_dir 参数保留以兼容现有调用者,但不再使用。 + 数据来源是 PopulateSha1MapStore 填充的全局存储器。 + sha1_set 大小为 MAX_INCLUDES_SHA1 * 17(每个 SHA1 16字符+null) + 返回找到的 includes SHA1 数量,-1 表示错误""" + if sha1_set is None: + return -1 + if StubMerger._sha1_store_arr is None: + return -1 + count: int = 0 + for i in range(StubMerger._sha1_store_count): + if count >= MAX_INCLUDES_SHA1: + break + idx: t.CSizeT = t.CSizeT(i) * 17 + string.strcpy(sha1_set + t.CSizeT(count) * 17, StubMerger._sha1_store_arr + idx) + count += 1 + return count +# ============================================================ +# _is_in_sha1_set - 检查 SHA1 是否在集合中 +# ============================================================ +def _is_in_sha1_set(sha1: str, sha1_set: str, set_count: int) -> int: + """检查 sha1 是否在集合中""" + if sha1 is None or sha1_set is None: + return 0 + for i in range(set_count): + if string.strcmp(sha1_set + i * 17, sha1) == 0: + return 1 + return 0 +# ============================================================ +# WriteIncludesSha1Map - 将 includes 扫描结果写入 _sha1_map.txt(人类可读输出) +# +# _sha1_map.txt 仅作为人类可读的调试输出,程序内部不读取此文件。 +# 机器分析使用 PopulateSha1MapStore 填充的全局内存存储器。 +# +# Args: +# mb: 内存池 +# temp_dir: 临时目录(_sha1_map.txt 写入位置) +# scan_result: IncludesScanner 扫描结果 +# +# Returns: +# 0 成功,非 0 失败 +# ============================================================ +def WriteIncludesSha1Map(mb: memhub.MemBuddy | t.CPtr, temp_dir: str, + scan_result: IncludesScanner.ScanResult | t.CPtr, + filter_set: str, + filter_count: int) -> int: + """将 includes 扫描结果写入 _sha1_map.txt(人类可读输出,程序内部使用内存存储器) + + 若 filter_set 不为 None 且 filter_count > 0,只写入 filter_set 中的条目。 + """ + if temp_dir is None or scan_result is None: + return 1 + + # 构造路径 temp_dir/_sha1_map.txt + dir_len: t.CSizeT = string.strlen(temp_dir) + map_path: bytes = stdlib.malloc(dir_len + 32) + if map_path is None: + return 1 + viperlib.snprintf(map_path, dir_len + 32, "%s/_sha1_map.txt", temp_dir) + + # 打开文件写入(CREATE_ALWAYS) + f: fileio.File | t.CPtr = fileio.File(map_path, fileio.MODE.W) + if f.closed: + return 1 + + # 写入每个 include 条目: {sha1}:includes/{rel_path}\n + entry_size_w: t.CSizeT = IncludesScanner.FileEntry.__sizeof__() + line_buf: bytes = stdlib.malloc(512) + if line_buf is None: + f.close() + return 1 + + written_count: int = 0 + for i in range(scan_result.Count): + ea_w: t.CUInt64T = t.CUInt64T(scan_result.Entries) + i * entry_size_w + ent_w: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea_w, t.CPtr)) + if ent_w is None or ent_w.Sha1 is None or ent_w.RelPath is None: + continue + # 若提供过滤集合,只写入集合中的条目 + if filter_set is not None and filter_count > 0: + if _is_in_sha1_set(ent_w.Sha1, filter_set, filter_count) == 0: + continue + viperlib.snprintf(line_buf, 512, "%s:includes/%s\n", ent_w.Sha1, ent_w.RelPath) + line_len_w: t.CSizeT = string.strlen(line_buf) + f.write(line_buf, line_len_w) + written_count += 1 + + f.close() + return 0 diff --git a/App/lib/core/StubMergerIR.vp b/App/lib/core/StubMergerIR.vp index de7322c..a01a5d0 100644 --- a/App/lib/core/StubMergerIR.vp +++ b/App/lib/core/StubMergerIR.vp @@ -1,416 +1,415 @@ -import t, c -from stdint import * -import memhub -import string -import stdlib -import llvmlite -import w32.win32file as win32file -import w32.win32base as win32base -import w32.fileio as fileio -import viperlib -import sys -import ast -import lib.core.VLogger as VLogger -import lib.core.IncludesScanner as IncludesScanner -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesTranslator as HandlesTranslator -import lib.core.BuildPipeline as BuildPipeline -import lib.StubGen.VpiReader as VpiReader -import lib.Projectrans.Utils as Utils -import lib.Projectrans.Config as Config - - -import lib.core.StubMergerCollect as StubMergerCollect -import lib.core.StubMergerStore as StubMergerStore -import lib.core.StubMergerTopo as StubMergerTopo -import lib.core.StubMergerBuild as StubMergerBuild -import lib.core.StubMerger as StubMerger - -# ============================================================ -# StubMergerIR - StubMerger 拆分(阶段 E):StubMergerIR -# -# 直接移动模式:函数实现迁至此模块,原 StubMerger.vp 仅保留 -# 常量/全局变量;调用方经本模块前缀访问。全局变量跨模块经 -# StubMerger._xxx 访问(main.vp 先例)。 -# ============================================================ - -# ============================================================ -# IsDeclOnlyModule - 判断模块是否为纯声明文件 -# -# 读取 {temp_dir}/{sha1}.text.ll,扫描是否含 "define " 行: -# 返回 1 = 纯声明(无函数体,如 stdio.vp 全 pass),无需 .obj -# 返回 0 = 实现文件(含 define 函数体) -# 返回 -1 = text.ll 不存在/无法判断 -# -# 与 Phase B+(Phase2.vp 编译缺失 includes 时)的内联判断逻辑一致, -# 供 Phase C 链接时区分"声明文件无需 .obj"与"实现文件缺失"。 -# ============================================================ -def IsDeclOnlyModule(temp_dir: str, td_len: t.CSizeT, sha1: str) -> int: - """判断模块是否为纯声明文件(text.ll 无 define 行)""" - if temp_dir is None or sha1 is None: - return -1 - tpath: str = StubMergerCollect._sliced_path(temp_dir, td_len, sha1, "text.ll") - if tpath is None: - return -1 - tf_d: fileio.File | t.CPtr = fileio.File(tpath, fileio.MODE.R) - stdlib.free(tpath) - if tf_d.closed: - return -1 - tbuf_d: bytes = stdlib.malloc(STUB_READ_BUF_SIZE) - tbr_d: t.CInt64T = 0 - if tbuf_d is not None: - tbr_d = tf_d.read_all(tbuf_d, STUB_READ_BUF_SIZE) - tf_d.close() - if tbuf_d is None: - return -1 - if tbr_d <= 0: - # 空 text.ll:无函数体,纯声明 - stdlib.free(tbuf_d) - return 1 - if tbr_d < STUB_READ_BUF_SIZE: - tbuf_d[tbr_d] = '\0' - else: - tbuf_d[STUB_READ_BUF_SIZE - 1] = '\0' - # 逐行扫描:找 "define " 行即为实现文件 - tpos_d: t.CSizeT = 0 - while tpos_d < tbr_d: - tls_d: t.CSizeT = tpos_d - while tpos_d < tbr_d: - if tbuf_d[tpos_d] == '\n': - break - tpos_d += 1 - tll_d: t.CSizeT = tpos_d - tls_d - if tpos_d < tbr_d: - tpos_d += 1 - if tll_d >= 7 and string.strncmp(tbuf_d + tls_d, "define ", 7) == 0: - stdlib.free(tbuf_d) - return 0 - stdlib.free(tbuf_d) - return 1 -# ============================================================ -# _IsFuncDeclaredOrDefined - 检查 out_buf 中是否已有函数的 declare/define -# -# 逐字节strncmp搜索 func_sig(如 @"sha1.func"(/ @printf( ),每次 -# 找到匹配后检查行首是否以 "declare " 或 "define " 开头,跳过 call 语句。 -# 避免 strstr 子串匹配误匹配 call ... @"func"(...) 中的 @"func"( 子串。 -# -# Args: -# out_buf: 已有的 IR 文本缓冲区 -# func_sig: 函数签名片段,如 @"sha1.func"(/ @printf( -# -# Returns: -# 1=已存在 declare/define, 0=不存在 -# ============================================================ -def _IsFuncDeclaredOrDefined(out_buf: bytes, func_sig: str) -> int: - """检查 out_buf 中是否已有函数的 declare 或 define 行""" - if out_buf is None or func_sig is None: - return 0 - sig_len: t.CSizeT = string.strlen(func_sig) - out_len: t.CSizeT = string.strlen(out_buf) - if sig_len == 0 or out_len == 0 or sig_len > out_len: - return 0 - pos: t.CSizeT = 0 - while pos + sig_len <= out_len: - if string.strncmp(out_buf + pos, func_sig, sig_len) == 0: - ls: t.CSizeT = pos - while ls > 0 and out_buf[ls - 1] != '\n': - ls -= 1 - if string.strncmp(out_buf + ls, "declare ", 8) == 0: - return 1 - if string.strncmp(out_buf + ls, "define ", 7) == 0: - return 1 - pos += 1 - return 0 -# ============================================================ -# _CommentOutDeclareInBuf - 将 out_buf 中匹配 func_sig 的 declare 行注释掉 -# -# 用于解决 declare/define 冲突:当本地 text.ll 包含 define 而依赖 -# text.ll 已生成了同函数的 declare 时,将 declare 行首字符改为 ';' -# 使其成为注释,然后追加 define 行。 -# ============================================================ -def _CommentOutDeclareInBuf(out_buf: bytes, func_sig: str) -> int: - """在 out_buf 中搜索 declare 行(包含 func_sig),将其注释掉""" - if out_buf is None or func_sig is None: - return 0 - sig_len: t.CSizeT = string.strlen(func_sig) - out_len: t.CSizeT = string.strlen(out_buf) - if sig_len == 0 or out_len == 0 or sig_len > out_len: - return 0 - pos: t.CSizeT = 0 - while pos + sig_len <= out_len: - if string.strncmp(out_buf + pos, func_sig, sig_len) == 0: - ls: t.CSizeT = pos - while ls > 0 and out_buf[ls - 1] != '\n': - ls -= 1 - if string.strncmp(out_buf + ls, "declare ", 8) == 0: - out_buf[ls] = ';' - return 1 - pos += 1 - return 0 -# ============================================================ -# _CommentOutGlobalInBuf - 将 out_buf 中匹配全局变量名的行注释掉 -# -# 解决 stub/text 全局变量重复定义问题:stub 中可能是 external 声明 -# 或完整定义,以 text 中的定义为准,将 stub 中的同名行注释掉。 -# ============================================================ -def _CommentOutGlobalInBuf(out_buf: bytes, global_name: str) -> int: - """在 out_buf 中搜索全局变量定义行(以 global_name 开头),将行首改为 ';' - - 注释掉**所有**匹配行(而非仅第一个):跨模块同名裸全局(如 main.vp 与 - argparse.vp 都声明 StubMerger._mbuddy)时,本地 stub external + 依赖 stub external + - 依赖 text 定义会同时存在。只注释第一个会导致依赖 text 的定义残留 → - 合成 IR 重复定义 → llc "redefinition of global '@StubMerger._mbuddy'"(ArgparseTest - 回归根因)。"以 text 中定义为准"的语义:后追加者注释掉全部旧行,最终 - 只保留最后一个定义。 - """ - if out_buf is None or global_name is None: - return 0 - name_len: t.CSizeT = string.strlen(global_name) - out_len: t.CSizeT = string.strlen(out_buf) - if name_len == 0 or out_len == 0 or name_len > out_len: - return 0 - pos: t.CSizeT = 0 - commented: int = 0 - while pos + name_len <= out_len: - if string.strncmp(out_buf + pos, global_name, name_len) == 0: - # 确认是行首(前一个是换行或 pos==0) - if pos == 0 or out_buf[pos - 1] == '\n': - out_buf[pos] = ';' - commented = 1 - pos += 1 - return commented -def _HasGlobalInBuf(out_buf: bytes, global_name: str) -> int: - """检测 out_buf 中是否已有同名全局变量行(行首匹配,未注释) - - 用于跳过重复追加依赖全局强定义:stub 注入已提供 external 声明, - 依赖 text.ll 的强定义只需在定义模块存在一份,复制进每个依赖方 - 会导致 ld.lld duplicate symbol(如 _op_head、MemBuddy.vtable)。 - """ - if out_buf is None or global_name is None: - return 0 - name_len: t.CSizeT = string.strlen(global_name) - out_len: t.CSizeT = string.strlen(out_buf) - if name_len == 0 or out_len == 0 or name_len > out_len: - return 0 - pos: t.CSizeT = 0 - while pos + name_len <= out_len: - if string.strncmp(out_buf + pos, global_name, name_len) == 0: - # 确认是行首(前一个是换行或 pos==0) - if pos == 0 or out_buf[pos - 1] == '\n': - return 1 - pos += 1 - return 0 -# ============================================================ -# _CommentOutOpaqueTypeInBuf - 将 out_buf 中匹配类型名的 opaque 声明行注释掉 -# -# 解决跨模块类型定义冲突:本地 stub 可能包含自动生成的 opaque 声明 -#(如 %"sha1.Widget" = type opaque),而依赖 stub 包含完整定义 -#(如 %"sha1.Widget" = type { i8*, i32 })。去重时需要将 opaque 声明 -# 注释掉,让完整定义被追加,否则 LLC 报错 "Cannot allocate unsized type"。 -# ============================================================ -def _CommentOutOpaqueTypeInBuf(out_buf: bytes, type_name_prefix: str) -> int: - """在 out_buf 中搜索 type_name_prefix 对应的 opaque 声明行,将行首改为 ';' - - type_name_prefix 格式: '%"sha1.ClassName"'(不含 '=' 和后续内容) - 返回 1=已注释, 0=未找到 - """ - if out_buf is None or type_name_prefix is None: - return 0 - prefix_len: t.CSizeT = string.strlen(type_name_prefix) - out_len: t.CSizeT = string.strlen(out_buf) - if prefix_len == 0 or out_len == 0 or prefix_len > out_len: - return 0 - pos: t.CSizeT = 0 - while pos + prefix_len <= out_len: - if string.strncmp(out_buf + pos, type_name_prefix, prefix_len) == 0: - # 确认是行首(前一个是换行或 pos==0) - if pos == 0 or out_buf[pos - 1] == '\n': - # 检查后面是否是 " = type opaque" - p: t.CSizeT = pos + prefix_len - # 跳过空格 - while p < out_len and out_buf[p] == ' ': - p += 1 - if p < out_len and out_buf[p] == '=': - p += 1 - while p < out_len and out_buf[p] == ' ': - p += 1 - if p + 11 <= out_len: - if string.strncmp(out_buf + p, "type opaque", 11) == 0: - # 找到 opaque 声明,将行首改为 ';' - out_buf[pos] = ';' - return 1 - pos += 1 - return 0 -# ============================================================ -# _is_submodule_of_imported - 检查模块名是否是已导入包的子模块 -# -# deps.txt 只记录直接导入的模块名(如 "ast"),但包的 __init__.vp -# 内部 from .lexer import Lexer 会让 IR 引用 ast.lexer 子模块类型。 -# 当模块名包含 '.' 时,检查其顶层包名是否在 deps_buf 中。 -# -# 例如: -# deps_buf = "ast stdio string" -# mod_name = "ast.lexer" → 顶层包 "ast" 在 deps_buf 中 → 返回 1 -# mod_name = "ast.token" → 顶层包 "ast" 在 deps_buf 中 → 返回 1 -# mod_name = "foo.bar" → 顶层包 "foo" 不在 deps_buf 中 → 返回 0 -# ============================================================ -def _is_submodule_of_imported(deps_buf: str, mod_name: str) -> int: - """检查 mod_name 是否是 deps_buf 中已导入包的子模块""" - if deps_buf is None or mod_name is None: - return 0 - # 查找第一个 '.',提取顶层包名 - dot_pos: str = string.strchr(mod_name, 46) # '.' = 46 - if dot_pos is None: - return 0 - pkg_len: t.CSizeT = t.CSizeT(t.CUInt64T(dot_pos) - t.CUInt64T(mod_name)) - if pkg_len == 0 or pkg_len >= 256: - return 0 - # 构造顶层包名(截断到 '.' 之前) - # 直接在 mod_name 上临时截断检查,避免分配 - saved_ch: t.CChar = mod_name[pkg_len] - mod_name[pkg_len] = '\0' - result: int = HandlesImports.is_module_imported(deps_buf, mod_name) - mod_name[pkg_len] = saved_ch - return result -# ============================================================ -# _HasFullTypeDefinition - 检查 out_buf 中是否已有完整类型定义(非 opaque) -# -# type_name_prefix 格式: '%"sha1.ClassName"'(不含 '=') -# 完整定义: %"name" = type { ... } 或 %"name" = type < { ... } > -# 返回 1=已有完整定义, 0=无完整定义 -# ============================================================ -def _HasFullTypeDefinition(out_buf: bytes, type_name_prefix: str) -> int: - """检查 out_buf 中是否已有 type_name_prefix 的完整定义""" - if out_buf is None or type_name_prefix is None: - return 0 - prefix_len: t.CSizeT = string.strlen(type_name_prefix) - out_len: t.CSizeT = string.strlen(out_buf) - if prefix_len == 0 or out_len == 0 or prefix_len > out_len: - return 0 - pos: t.CSizeT = 0 - while pos + prefix_len <= out_len: - if string.strncmp(out_buf + pos, type_name_prefix, prefix_len) == 0: - # 确认是行首(前一个是换行或 pos==0),且未被注释(行首不是 ';') - is_line_start: int = 0 - if pos == 0: - is_line_start = 1 - elif out_buf[pos - 1] == '\n': - is_line_start = 1 - if is_line_start == 1: - # 检查后面是否是 " = type {" 或 " = type <" - p: t.CSizeT = pos + prefix_len - while p < out_len and out_buf[p] == ' ': - p += 1 - if p < out_len and out_buf[p] == '=': - p += 1 - while p < out_len and out_buf[p] == ' ': - p += 1 - if p + 5 < out_len: - if string.strncmp(out_buf + p, "type ", 5) == 0: - p += 5 - if p < out_len: - if out_buf[p] == '{' or out_buf[p] == '<': - return 1 - pos += 1 - return 0 -# ============================================================ -# _BuildIncludesSha1Map - 从全局内存存储器构建 sha1 → module_name 映射 -# -# 数据来源是 PopulateSha1MapStore 填充的全局存储器(不读取 _sha1_map.txt)。 -# 返回两个数组(sha1_list 和 mod_list),长度存储在 count 中。 -# 所有内存由 stdlib.malloc 分配,调用者负责释放。 -# ============================================================ -def _BuildIncludesSha1Map(temp_dir: str, td_len: t.CSizeT, - sha1_list: str, - mod_list: str) -> int: - """从全局内存存储器复制 sha1→module_name 映射到调用者数组 - - temp_dir/td_len 参数保留以兼容现有调用者,但不再使用。 - 数据来源是 PopulateSha1MapStore 填充的全局存储器。 - """ - if sha1_list is None or mod_list is None: - return 0 - if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None: - return 0 - count: int = 0 - for i in range(StubMerger._sha1_store_count): - if count >= MAX_INCLUDES: - break - idx: t.CSizeT = t.CSizeT(i) * 17 - idx2: t.CSizeT = t.CSizeT(i) * 64 - string.strcpy(sha1_list + t.CSizeT(count) * 17, StubMerger._sha1_store_arr + idx) - string.strcpy(mod_list + t.CSizeT(count) * 64, StubMerger._sha1_store_mod + idx2) - count += 1 - return count -# ============================================================ -# _FindSha1ByModName - 从模块名查找 SHA1(精确匹配) -# -# 在 sha1_arr/mod_arr 映射中查找模块名对应的 SHA1。 -# 用于依赖图分析:模块名 → SHA1。 -# -# Args: -# sha1_arr: SHA1 数组(每个 17 字节) -# mod_arr: 模块名数组(每个 64 字节) -# count: 映射条目数 -# mod_name: 要查找的模块名 -# -# Returns: -# SHA1 字符串指针(指向 sha1_arr 内部,无需释放),未找到返回 None -# ============================================================ -def _FindSha1ByModName(sha1_arr: str, mod_arr: str, - count: int, mod_name: str) -> str: - """从模块名查找 SHA1(精确匹配 + 包名回退) - - 精确匹配失败时,尝试 "{mod_name}.__init__" 回退, - 支持 import ast(包)→ ast.__init__ 的 SHA1 查找。 - """ - if sha1_arr is None or mod_arr is None or mod_name is None: - return None - if count <= 0: - return None - # 第一遍:精确匹配 - for i in range(count): - idx: t.CSizeT = t.CSizeT(i) * 64 - if string.strcmp(mod_arr + idx, mod_name) == 0: - sidx: t.CSizeT = t.CSizeT(i) * 17 - return sha1_arr + sidx - # 第二遍:包名回退("ast" → "ast.__init__") - nm_len: t.CSizeT = string.strlen(mod_name) - init_buf: bytes = stdlib.malloc(nm_len + 12) - if init_buf is not None: - viperlib.snprintf(init_buf, nm_len + 12, "%s.__init__", mod_name) - for i in range(count): - idx2: t.CSizeT = t.CSizeT(i) * 64 - if string.strcmp(mod_arr + idx2, init_buf) == 0: - sidx2: t.CSizeT = t.CSizeT(i) * 17 - stdlib.free(init_buf) - return sha1_arr + sidx2 - stdlib.free(init_buf) - return None -# ============================================================ -# _AddSha1ToSet - 将 SHA1 加入集合(去重) -# -# 检查 SHA1 是否已在集合中,若不在则加入。返回新的 count。 -# -# Args: -# set_buf: SHA1 集合缓冲区(每个 17 字节) -# count: 当前集合中的 SHA1 数量 -# sha1: 要加入的 SHA1 -# -# Returns: -# 新的 count(如果已存在则不变) -# ============================================================ -def _AddSha1ToSet(set_buf: str, count: int, sha1: str) -> int: - """将 SHA1 加入集合,返回新 count""" - if set_buf is None or sha1 is None: - return count - for i in range(count): - idx: t.CSizeT = t.CSizeT(i) * 17 - if string.strcmp(set_buf + idx, sha1) == 0: - return count - if count < MAX_INCLUDES_SHA1: - idx: t.CSizeT = t.CSizeT(count) * 17 - string.strcpy(set_buf + idx, sha1) - return count + 1 - return count +import lib.core.Gen.GenApi as GenApi +import t, c +from stdint import * +import memhub +import string +import stdlib +import llvmlite +import w32.win32file as win32file +import w32.win32base as win32base +import w32.fileio as fileio +import viperlib +import sys +import ast +import lib.core.VLogger as VLogger +import lib.core.IncludesScanner as IncludesScanner +import lib.core.Handles.HandlesTranslator as HandlesTranslator +import lib.core.BuildPipeline as BuildPipeline +import lib.StubGen.VpiReader as VpiReader +import lib.Projectrans.Utils as Utils +import lib.Projectrans.Config as Config + + +import lib.core.StubMergerCollect as StubMergerCollect +import lib.core.StubMergerStore as StubMergerStore +import lib.core.StubMergerTopo as StubMergerTopo +import lib.core.StubMergerBuild as StubMergerBuild +import lib.core.StubMerger as StubMerger + +# ============================================================ +# StubMergerIR - StubMerger 拆分(阶段 E):StubMergerIR +# +# 直接移动模式:函数实现迁至此模块,原 StubMerger.vp 仅保留 +# 常量/全局变量;调用方经本模块前缀访问。全局变量跨模块经 +# StubMerger._xxx 访问(main.vp 先例)。 +# ============================================================ + +# ============================================================ +# IsDeclOnlyModule - 判断模块是否为纯声明文件 +# +# 读取 {temp_dir}/{sha1}.text.ll,扫描是否含 "define " 行: +# 返回 1 = 纯声明(无函数体,如 stdio.vp 全 pass),无需 .obj +# 返回 0 = 实现文件(含 define 函数体) +# 返回 -1 = text.ll 不存在/无法判断 +# +# 与 Phase B+(Phase2.vp 编译缺失 includes 时)的内联判断逻辑一致, +# 供 Phase C 链接时区分"声明文件无需 .obj"与"实现文件缺失"。 +# ============================================================ +def IsDeclOnlyModule(temp_dir: str, td_len: t.CSizeT, sha1: str) -> int: + """判断模块是否为纯声明文件(text.ll 无 define 行)""" + if temp_dir is None or sha1 is None: + return -1 + tpath: str = StubMergerCollect._sliced_path(temp_dir, td_len, sha1, "text.ll") + if tpath is None: + return -1 + tf_d: fileio.File | t.CPtr = fileio.File(tpath, fileio.MODE.R) + stdlib.free(tpath) + if tf_d.closed: + return -1 + tbuf_d: bytes = stdlib.malloc(STUB_READ_BUF_SIZE) + tbr_d: t.CInt64T = 0 + if tbuf_d is not None: + tbr_d = tf_d.read_all(tbuf_d, STUB_READ_BUF_SIZE) + tf_d.close() + if tbuf_d is None: + return -1 + if tbr_d <= 0: + # 空 text.ll:无函数体,纯声明 + stdlib.free(tbuf_d) + return 1 + if tbr_d < STUB_READ_BUF_SIZE: + tbuf_d[tbr_d] = '\0' + else: + tbuf_d[STUB_READ_BUF_SIZE - 1] = '\0' + # 逐行扫描:找 "define " 行即为实现文件 + tpos_d: t.CSizeT = 0 + while tpos_d < tbr_d: + tls_d: t.CSizeT = tpos_d + while tpos_d < tbr_d: + if tbuf_d[tpos_d] == '\n': + break + tpos_d += 1 + tll_d: t.CSizeT = tpos_d - tls_d + if tpos_d < tbr_d: + tpos_d += 1 + if tll_d >= 7 and string.strncmp(tbuf_d + tls_d, "define ", 7) == 0: + stdlib.free(tbuf_d) + return 0 + stdlib.free(tbuf_d) + return 1 +# ============================================================ +# _IsFuncDeclaredOrDefined - 检查 out_buf 中是否已有函数的 declare/define +# +# 逐字节strncmp搜索 func_sig(如 @"sha1.func"(/ @printf( ),每次 +# 找到匹配后检查行首是否以 "declare " 或 "define " 开头,跳过 call 语句。 +# 避免 strstr 子串匹配误匹配 call ... @"func"(...) 中的 @"func"( 子串。 +# +# Args: +# out_buf: 已有的 IR 文本缓冲区 +# func_sig: 函数签名片段,如 @"sha1.func"(/ @printf( +# +# Returns: +# 1=已存在 declare/define, 0=不存在 +# ============================================================ +def _IsFuncDeclaredOrDefined(out_buf: bytes, func_sig: str) -> int: + """检查 out_buf 中是否已有函数的 declare 或 define 行""" + if out_buf is None or func_sig is None: + return 0 + sig_len: t.CSizeT = string.strlen(func_sig) + out_len: t.CSizeT = string.strlen(out_buf) + if sig_len == 0 or out_len == 0 or sig_len > out_len: + return 0 + pos: t.CSizeT = 0 + while pos + sig_len <= out_len: + if string.strncmp(out_buf + pos, func_sig, sig_len) == 0: + ls: t.CSizeT = pos + while ls > 0 and out_buf[ls - 1] != '\n': + ls -= 1 + if string.strncmp(out_buf + ls, "declare ", 8) == 0: + return 1 + if string.strncmp(out_buf + ls, "define ", 7) == 0: + return 1 + pos += 1 + return 0 +# ============================================================ +# _CommentOutDeclareInBuf - 将 out_buf 中匹配 func_sig 的 declare 行注释掉 +# +# 用于解决 declare/define 冲突:当本地 text.ll 包含 define 而依赖 +# text.ll 已生成了同函数的 declare 时,将 declare 行首字符改为 ';' +# 使其成为注释,然后追加 define 行。 +# ============================================================ +def _CommentOutDeclareInBuf(out_buf: bytes, func_sig: str) -> int: + """在 out_buf 中搜索 declare 行(包含 func_sig),将其注释掉""" + if out_buf is None or func_sig is None: + return 0 + sig_len: t.CSizeT = string.strlen(func_sig) + out_len: t.CSizeT = string.strlen(out_buf) + if sig_len == 0 or out_len == 0 or sig_len > out_len: + return 0 + pos: t.CSizeT = 0 + while pos + sig_len <= out_len: + if string.strncmp(out_buf + pos, func_sig, sig_len) == 0: + ls: t.CSizeT = pos + while ls > 0 and out_buf[ls - 1] != '\n': + ls -= 1 + if string.strncmp(out_buf + ls, "declare ", 8) == 0: + out_buf[ls] = ';' + return 1 + pos += 1 + return 0 +# ============================================================ +# _CommentOutGlobalInBuf - 将 out_buf 中匹配全局变量名的行注释掉 +# +# 解决 stub/text 全局变量重复定义问题:stub 中可能是 external 声明 +# 或完整定义,以 text 中的定义为准,将 stub 中的同名行注释掉。 +# ============================================================ +def _CommentOutGlobalInBuf(out_buf: bytes, global_name: str) -> int: + """在 out_buf 中搜索全局变量定义行(以 global_name 开头),将行首改为 ';' + + 注释掉**所有**匹配行(而非仅第一个):跨模块同名裸全局(如 main.vp 与 + argparse.vp 都声明 StubMerger._mbuddy)时,本地 stub external + 依赖 stub external + + 依赖 text 定义会同时存在。只注释第一个会导致依赖 text 的定义残留 → + 合成 IR 重复定义 → llc "redefinition of global '@StubMerger._mbuddy'"(ArgparseTest + 回归根因)。"以 text 中定义为准"的语义:后追加者注释掉全部旧行,最终 + 只保留最后一个定义。 + """ + if out_buf is None or global_name is None: + return 0 + name_len: t.CSizeT = string.strlen(global_name) + out_len: t.CSizeT = string.strlen(out_buf) + if name_len == 0 or out_len == 0 or name_len > out_len: + return 0 + pos: t.CSizeT = 0 + commented: int = 0 + while pos + name_len <= out_len: + if string.strncmp(out_buf + pos, global_name, name_len) == 0: + # 确认是行首(前一个是换行或 pos==0) + if pos == 0 or out_buf[pos - 1] == '\n': + out_buf[pos] = ';' + commented = 1 + pos += 1 + return commented +def _HasGlobalInBuf(out_buf: bytes, global_name: str) -> int: + """检测 out_buf 中是否已有同名全局变量行(行首匹配,未注释) + + 用于跳过重复追加依赖全局强定义:stub 注入已提供 external 声明, + 依赖 text.ll 的强定义只需在定义模块存在一份,复制进每个依赖方 + 会导致 ld.lld duplicate symbol(如 _op_head、MemBuddy.vtable)。 + """ + if out_buf is None or global_name is None: + return 0 + name_len: t.CSizeT = string.strlen(global_name) + out_len: t.CSizeT = string.strlen(out_buf) + if name_len == 0 or out_len == 0 or name_len > out_len: + return 0 + pos: t.CSizeT = 0 + while pos + name_len <= out_len: + if string.strncmp(out_buf + pos, global_name, name_len) == 0: + # 确认是行首(前一个是换行或 pos==0) + if pos == 0 or out_buf[pos - 1] == '\n': + return 1 + pos += 1 + return 0 +# ============================================================ +# _CommentOutOpaqueTypeInBuf - 将 out_buf 中匹配类型名的 opaque 声明行注释掉 +# +# 解决跨模块类型定义冲突:本地 stub 可能包含自动生成的 opaque 声明 +#(如 %"sha1.Widget" = type opaque),而依赖 stub 包含完整定义 +#(如 %"sha1.Widget" = type { i8*, i32 })。去重时需要将 opaque 声明 +# 注释掉,让完整定义被追加,否则 LLC 报错 "Cannot allocate unsized type"。 +# ============================================================ +def _CommentOutOpaqueTypeInBuf(out_buf: bytes, type_name_prefix: str) -> int: + """在 out_buf 中搜索 type_name_prefix 对应的 opaque 声明行,将行首改为 ';' + + type_name_prefix 格式: '%"sha1.ClassName"'(不含 '=' 和后续内容) + 返回 1=已注释, 0=未找到 + """ + if out_buf is None or type_name_prefix is None: + return 0 + prefix_len: t.CSizeT = string.strlen(type_name_prefix) + out_len: t.CSizeT = string.strlen(out_buf) + if prefix_len == 0 or out_len == 0 or prefix_len > out_len: + return 0 + pos: t.CSizeT = 0 + while pos + prefix_len <= out_len: + if string.strncmp(out_buf + pos, type_name_prefix, prefix_len) == 0: + # 确认是行首(前一个是换行或 pos==0) + if pos == 0 or out_buf[pos - 1] == '\n': + # 检查后面是否是 " = type opaque" + p: t.CSizeT = pos + prefix_len + # 跳过空格 + while p < out_len and out_buf[p] == ' ': + p += 1 + if p < out_len and out_buf[p] == '=': + p += 1 + while p < out_len and out_buf[p] == ' ': + p += 1 + if p + 11 <= out_len: + if string.strncmp(out_buf + p, "type opaque", 11) == 0: + # 找到 opaque 声明,将行首改为 ';' + out_buf[pos] = ';' + return 1 + pos += 1 + return 0 +# ============================================================ +# _is_submodule_of_imported - 检查模块名是否是已导入包的子模块 +# +# deps.txt 只记录直接导入的模块名(如 "ast"),但包的 __init__.vp +# 内部 from .lexer import Lexer 会让 IR 引用 ast.lexer 子模块类型。 +# 当模块名包含 '.' 时,检查其顶层包名是否在 deps_buf 中。 +# +# 例如: +# deps_buf = "ast stdio string" +# mod_name = "ast.lexer" → 顶层包 "ast" 在 deps_buf 中 → 返回 1 +# mod_name = "ast.token" → 顶层包 "ast" 在 deps_buf 中 → 返回 1 +# mod_name = "foo.bar" → 顶层包 "foo" 不在 deps_buf 中 → 返回 0 +# ============================================================ +def _is_submodule_of_imported(deps_buf: str, mod_name: str) -> int: + """检查 mod_name 是否是 deps_buf 中已导入包的子模块""" + if deps_buf is None or mod_name is None: + return 0 + # 查找第一个 '.',提取顶层包名 + dot_pos: str = string.strchr(mod_name, 46) # '.' = 46 + if dot_pos is None: + return 0 + pkg_len: t.CSizeT = t.CSizeT(t.CUInt64T(dot_pos) - t.CUInt64T(mod_name)) + if pkg_len == 0 or pkg_len >= 256: + return 0 + # 构造顶层包名(截断到 '.' 之前) + # 直接在 mod_name 上临时截断检查,避免分配 + saved_ch: t.CChar = mod_name[pkg_len] + mod_name[pkg_len] = '\0' + result: int = GenApi.is_module_imported(deps_buf, mod_name) + mod_name[pkg_len] = saved_ch + return result +# ============================================================ +# _HasFullTypeDefinition - 检查 out_buf 中是否已有完整类型定义(非 opaque) +# +# type_name_prefix 格式: '%"sha1.ClassName"'(不含 '=') +# 完整定义: %"name" = type { ... } 或 %"name" = type < { ... } > +# 返回 1=已有完整定义, 0=无完整定义 +# ============================================================ +def _HasFullTypeDefinition(out_buf: bytes, type_name_prefix: str) -> int: + """检查 out_buf 中是否已有 type_name_prefix 的完整定义""" + if out_buf is None or type_name_prefix is None: + return 0 + prefix_len: t.CSizeT = string.strlen(type_name_prefix) + out_len: t.CSizeT = string.strlen(out_buf) + if prefix_len == 0 or out_len == 0 or prefix_len > out_len: + return 0 + pos: t.CSizeT = 0 + while pos + prefix_len <= out_len: + if string.strncmp(out_buf + pos, type_name_prefix, prefix_len) == 0: + # 确认是行首(前一个是换行或 pos==0),且未被注释(行首不是 ';') + is_line_start: int = 0 + if pos == 0: + is_line_start = 1 + elif out_buf[pos - 1] == '\n': + is_line_start = 1 + if is_line_start == 1: + # 检查后面是否是 " = type {" 或 " = type <" + p: t.CSizeT = pos + prefix_len + while p < out_len and out_buf[p] == ' ': + p += 1 + if p < out_len and out_buf[p] == '=': + p += 1 + while p < out_len and out_buf[p] == ' ': + p += 1 + if p + 5 < out_len: + if string.strncmp(out_buf + p, "type ", 5) == 0: + p += 5 + if p < out_len: + if out_buf[p] == '{' or out_buf[p] == '<': + return 1 + pos += 1 + return 0 +# ============================================================ +# _BuildIncludesSha1Map - 从全局内存存储器构建 sha1 → module_name 映射 +# +# 数据来源是 PopulateSha1MapStore 填充的全局存储器(不读取 _sha1_map.txt)。 +# 返回两个数组(sha1_list 和 mod_list),长度存储在 count 中。 +# 所有内存由 stdlib.malloc 分配,调用者负责释放。 +# ============================================================ +def _BuildIncludesSha1Map(temp_dir: str, td_len: t.CSizeT, + sha1_list: str, + mod_list: str) -> int: + """从全局内存存储器复制 sha1→module_name 映射到调用者数组 + + temp_dir/td_len 参数保留以兼容现有调用者,但不再使用。 + 数据来源是 PopulateSha1MapStore 填充的全局存储器。 + """ + if sha1_list is None or mod_list is None: + return 0 + if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None: + return 0 + count: int = 0 + for i in range(StubMerger._sha1_store_count): + if count >= MAX_INCLUDES: + break + idx: t.CSizeT = t.CSizeT(i) * 17 + idx2: t.CSizeT = t.CSizeT(i) * 64 + string.strcpy(sha1_list + t.CSizeT(count) * 17, StubMerger._sha1_store_arr + idx) + string.strcpy(mod_list + t.CSizeT(count) * 64, StubMerger._sha1_store_mod + idx2) + count += 1 + return count +# ============================================================ +# _FindSha1ByModName - 从模块名查找 SHA1(精确匹配) +# +# 在 sha1_arr/mod_arr 映射中查找模块名对应的 SHA1。 +# 用于依赖图分析:模块名 → SHA1。 +# +# Args: +# sha1_arr: SHA1 数组(每个 17 字节) +# mod_arr: 模块名数组(每个 64 字节) +# count: 映射条目数 +# mod_name: 要查找的模块名 +# +# Returns: +# SHA1 字符串指针(指向 sha1_arr 内部,无需释放),未找到返回 None +# ============================================================ +def _FindSha1ByModName(sha1_arr: str, mod_arr: str, + count: int, mod_name: str) -> str: + """从模块名查找 SHA1(精确匹配 + 包名回退) + + 精确匹配失败时,尝试 "{mod_name}.__init__" 回退, + 支持 import ast(包)→ ast.__init__ 的 SHA1 查找。 + """ + if sha1_arr is None or mod_arr is None or mod_name is None: + return None + if count <= 0: + return None + # 第一遍:精确匹配 + for i in range(count): + idx: t.CSizeT = t.CSizeT(i) * 64 + if string.strcmp(mod_arr + idx, mod_name) == 0: + sidx: t.CSizeT = t.CSizeT(i) * 17 + return sha1_arr + sidx + # 第二遍:包名回退("ast" → "ast.__init__") + nm_len: t.CSizeT = string.strlen(mod_name) + init_buf: bytes = stdlib.malloc(nm_len + 12) + if init_buf is not None: + viperlib.snprintf(init_buf, nm_len + 12, "%s.__init__", mod_name) + for i in range(count): + idx2: t.CSizeT = t.CSizeT(i) * 64 + if string.strcmp(mod_arr + idx2, init_buf) == 0: + sidx2: t.CSizeT = t.CSizeT(i) * 17 + stdlib.free(init_buf) + return sha1_arr + sidx2 + stdlib.free(init_buf) + return None +# ============================================================ +# _AddSha1ToSet - 将 SHA1 加入集合(去重) +# +# 检查 SHA1 是否已在集合中,若不在则加入。返回新的 count。 +# +# Args: +# set_buf: SHA1 集合缓冲区(每个 17 字节) +# count: 当前集合中的 SHA1 数量 +# sha1: 要加入的 SHA1 +# +# Returns: +# 新的 count(如果已存在则不变) +# ============================================================ +def _AddSha1ToSet(set_buf: str, count: int, sha1: str) -> int: + """将 SHA1 加入集合,返回新 count""" + if set_buf is None or sha1 is None: + return count + for i in range(count): + idx: t.CSizeT = t.CSizeT(i) * 17 + if string.strcmp(set_buf + idx, sha1) == 0: + return count + if count < MAX_INCLUDES_SHA1: + idx: t.CSizeT = t.CSizeT(count) * 17 + string.strcpy(set_buf + idx, sha1) + return count + 1 + return count diff --git a/App/lib/core/StubMergerStore.vp b/App/lib/core/StubMergerStore.vp index 9319c2c..b2a6970 100644 --- a/App/lib/core/StubMergerStore.vp +++ b/App/lib/core/StubMergerStore.vp @@ -1,409 +1,407 @@ -import t, c -from stdint import * -import memhub -import string -import stdlib -import llvmlite -import w32.win32file as win32file -import w32.win32base as win32base -import w32.fileio as fileio -import viperlib -import sys -import ast -import lib.core.VLogger as VLogger -import lib.core.IncludesScanner as IncludesScanner -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesTranslator as HandlesTranslator -import lib.core.BuildPipeline as BuildPipeline -import lib.StubGen.VpiReader as VpiReader -import lib.Projectrans.Utils as Utils -import lib.Projectrans.Config as Config - - -import lib.core.StubMergerCollect as StubMergerCollect -import lib.core.StubMergerTopo as StubMergerTopo -import lib.core.StubMergerIR as StubMergerIR -import lib.core.StubMergerBuild as StubMergerBuild -import lib.core.StubMerger as StubMerger - -# ============================================================ -# StubMergerStore - StubMerger 拆分(阶段 E):StubMergerStore -# -# 直接移动模式:函数实现迁至此模块,原 StubMerger.vp 仅保留 -# 常量/全局变量;调用方经本模块前缀访问。全局变量跨模块经 -# StubMerger._xxx 访问(main.vp 先例)。 -# ============================================================ - -# ============================================================ -# PopulateSha1MapStore - 从扫描结果填充全局 SHA1 映射存储器 -# -# 遍历 ScanResult.Entries,为每个条目构建 sha1→module_name 映射。 -# 模块名通过 _PathToModuleName(includes/rel_path) 计算。 -# 内存用 stdlib.malloc 分配(全局存储器,不随 mbuddy 释放)。 -# -# Args: -# scan_result: IncludesScanner 扫描结果 -# -# Returns: -# 填充的条目数,-1 表示失败 -# ============================================================ -def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> int: - """从扫描结果填充全局 SHA1 映射存储器 - - 遍历 ScanResult.Entries,为每个条目构建 sha1→module_name 映射。 - 模块名通过 _PathToModuleName(includes/rel_path) 计算。 - 内存用 stdlib.malloc 分配(全局存储器,不随 mbuddy 释放)。 - """ - if scan_result is None: - return -1 - # 释放旧存储器 - if StubMerger._sha1_store_arr is not None: - stdlib.free(StubMerger._sha1_store_arr) - if StubMerger._sha1_store_mod is not None: - stdlib.free(StubMerger._sha1_store_mod) - if StubMerger._sha1_store_rel is not None: - stdlib.free(StubMerger._sha1_store_rel) - if StubMerger._sha1_store_incdir is not None: - stdlib.free(StubMerger._sha1_store_incdir) - StubMerger._sha1_store_arr = stdlib.malloc(MAX_INCLUDES * 17) - StubMerger._sha1_store_mod = stdlib.malloc(MAX_INCLUDES * 64) - StubMerger._sha1_store_rel = stdlib.malloc(MAX_INCLUDES * MAX_REL_PATH_LEN) - StubMerger._sha1_store_incdir = stdlib.malloc(MAX_INCLUDES * MAX_INC_DIR_LEN) - if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None or StubMerger._sha1_store_rel is None or StubMerger._sha1_store_incdir is None: - return -1 - string.memset(StubMerger._sha1_store_arr, 0, MAX_INCLUDES * 17) - string.memset(StubMerger._sha1_store_mod, 0, MAX_INCLUDES * 64) - string.memset(StubMerger._sha1_store_rel, 0, MAX_INCLUDES * MAX_REL_PATH_LEN) - string.memset(StubMerger._sha1_store_incdir, 0, MAX_INCLUDES * MAX_INC_DIR_LEN) - StubMerger._sha1_store_count = 0 - p_bad: int = 0 - entry_size_p: t.CSizeT = IncludesScanner.FileEntry.__sizeof__() - for i in range(scan_result.Count): - if StubMerger._sha1_store_count >= MAX_INCLUDES: - VLogger.error("includes SHA1 存储超上限,终止", "StubMerger") - ea: t.CUInt64T = t.CUInt64T(scan_result.Entries) + i * entry_size_p - ent: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea, t.CPtr)) - if ent is None or ent.Sha1 is None or ent.RelPath is None: - p_bad += 1 - continue - # 构建完整路径 includes/{RelPath}(_PathToModuleName 需要) - rp_len: t.CSizeT = string.strlen(ent.RelPath) - full_path_buf: bytes = stdlib.malloc(rp_len + 10) - if full_path_buf is None: - p_bad += 1 - continue - viperlib.snprintf(full_path_buf, rp_len + 10, "includes/%s", ent.RelPath) - mod_name: str = Utils.PathToModuleName(full_path_buf, 1) - stdlib.free(full_path_buf) - if mod_name is not None: - idx: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * 17 - string.strcpy(StubMerger._sha1_store_arr + idx, ent.Sha1) - idx2: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * 64 - mn_len: t.CSizeT = string.strlen(mod_name) - if mn_len < 64: - string.strcpy(StubMerger._sha1_store_mod + idx2, mod_name) - else: - string.strncpy(StubMerger._sha1_store_mod + idx2, mod_name, 63) - StubMerger._sha1_store_mod[idx2 + 63] = '\0' - stdlib.free(mod_name) - # 保存 rel_path(供 Phase2 3.5 编译缺失 includes 使用) - idx3: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * MAX_REL_PATH_LEN - if rp_len < MAX_REL_PATH_LEN: - string.strcpy(StubMerger._sha1_store_rel + idx3, ent.RelPath) - else: - string.strncpy(StubMerger._sha1_store_rel + idx3, ent.RelPath, MAX_REL_PATH_LEN - 1) - StubMerger._sha1_store_rel[idx3 + MAX_REL_PATH_LEN - 1] = '\0' - # 保存所属 includes 根目录(Phase2 预注册/按需编译拼路径用) - idx_inc: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * MAX_INC_DIR_LEN - if ent.IncDir is not None: - icd_len: t.CSizeT = string.strlen(ent.IncDir) - if icd_len < MAX_INC_DIR_LEN: - string.strcpy(StubMerger._sha1_store_incdir + idx_inc, ent.IncDir) - else: - string.strncpy(StubMerger._sha1_store_incdir + idx_inc, ent.IncDir, MAX_INC_DIR_LEN - 1) - StubMerger._sha1_store_incdir[idx_inc + MAX_INC_DIR_LEN - 1] = '\0' - StubMerger._sha1_store_count += 1 - if p_bad > 0: - fb_pbad: str = VLogger.fmt_buf() - if fb_pbad is not None: - viperlib.snprintf(fb_pbad, 1024, "includes SHA1 存储有 %d 个条目失败", p_bad) - VLogger.error(fb_pbad, "StubMerger") - return StubMerger._sha1_store_count -# ============================================================ -# AppendToSha1MapStore - 追加条目到全局 SHA1 映射存储器 -# -# Phase1 调用 PopulateSha1MapStore 填充 includes 文件, -# Phase2 扫描 App 源文件后调用此函数追加 App 模块条目, -# 确保编译 App 自身时跨模块 CDefine 查找能命中 App 模块 -# (如 StubMerger.MAX_INCLUDES 在编译 Phase2 时通过 -# _build_source_path_from_sha1 查找 StubMerger 的源路径)。 -# -# 若存储器未初始化(PopulateSha1MapStore 未调用),自动初始化。 -# 若 SHA1 已存在(去重),跳过。 -# -# Args: -# sha1: SHA1 字符串(16 字符 + null) -# rel_path: 相对路径(如 "lib/core/StubMerger.vp", -# 不含 includes/ 前缀,与 _sha1_map.txt 格式一致) -# -# Returns: -# 0 成功(含去重跳过),1 失败 -# ============================================================ -def AppendToSha1MapStore(sha1: str, rel_path: str) -> int: - """追加条目到全局 SHA1 映射存储器(Phase2 用)""" - if sha1 is None or rel_path is None: - return 1 - # 存储器未初始化:自动初始化(Phase2 可能先于 Phase1 调用) - if StubMerger._sha1_store_arr is None: - StubMerger._sha1_store_arr = stdlib.malloc(MAX_INCLUDES * 17) - StubMerger._sha1_store_mod = stdlib.malloc(MAX_INCLUDES * 64) - StubMerger._sha1_store_rel = stdlib.malloc(MAX_INCLUDES * MAX_REL_PATH_LEN) - StubMerger._sha1_store_incdir = stdlib.malloc(MAX_INCLUDES * MAX_INC_DIR_LEN) - if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None or StubMerger._sha1_store_rel is None or StubMerger._sha1_store_incdir is None: - return 1 - string.memset(StubMerger._sha1_store_arr, 0, MAX_INCLUDES * 17) - string.memset(StubMerger._sha1_store_mod, 0, MAX_INCLUDES * 64) - string.memset(StubMerger._sha1_store_rel, 0, MAX_INCLUDES * MAX_REL_PATH_LEN) - string.memset(StubMerger._sha1_store_incdir, 0, MAX_INCLUDES * MAX_INC_DIR_LEN) - StubMerger._sha1_store_count = 0 - if StubMerger._sha1_store_count >= MAX_INCLUDES: - return 1 - # 去重:若 SHA1 已存在则跳过 - for i in range(StubMerger._sha1_store_count): - sidx_d: t.CSizeT = t.CSizeT(i) * 17 - if string.strcmp(StubMerger._sha1_store_arr + sidx_d, sha1) == 0: - return 0 - # 模块名:rel_path "lib/core/StubMerger.vp" → "lib.core.StubMerger" - full_path_buf: bytes = stdlib.malloc(string.strlen(rel_path) + 10) - if full_path_buf is None: - return 1 - viperlib.snprintf(full_path_buf, string.strlen(rel_path) + 10, "includes/%s", rel_path) - mod_name: str = Utils.PathToModuleName(full_path_buf, 1) - stdlib.free(full_path_buf) - if mod_name is None: - return 1 - # 写入 SHA1 - idx_a: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * 17 - string.strcpy(StubMerger._sha1_store_arr + idx_a, sha1) - # 写入模块名 - idx_m: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * 64 - mn_len: t.CSizeT = string.strlen(mod_name) - if mn_len < 64: - string.strcpy(StubMerger._sha1_store_mod + idx_m, mod_name) - else: - string.strncpy(StubMerger._sha1_store_mod + idx_m, mod_name, 63) - StubMerger._sha1_store_mod[idx_m + 63] = '\0' - stdlib.free(mod_name) - # 写入相对路径 - idx_r: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * MAX_REL_PATH_LEN - rp_len: t.CSizeT = string.strlen(rel_path) - if rp_len < MAX_REL_PATH_LEN: - string.strcpy(StubMerger._sha1_store_rel + idx_r, rel_path) - else: - string.strncpy(StubMerger._sha1_store_rel + idx_r, rel_path, MAX_REL_PATH_LEN - 1) - StubMerger._sha1_store_rel[idx_r + MAX_REL_PATH_LEN - 1] = '\0' - # App 源文件不属于任何 includes 目录:IncDir 留空(Phase2 回退 includes_dir 参数) - idx_inc_a: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * MAX_INC_DIR_LEN - StubMerger._sha1_store_incdir[idx_inc_a] = '\0' - StubMerger._sha1_store_count += 1 - return 0 -# ============================================================ -# GetSha1StoreCount - 获取全局存储器条目数 -# ============================================================ -def GetSha1StoreCount() -> int: - """返回全局 SHA1 存储器的条目数""" - return StubMerger._sha1_store_count -# ============================================================ -# LookupSha1ByModName - 从模块名查找 SHA1(直接查全局存储器) -# -# 精确匹配失败时,尝试 "{mod_name}.__init__" 回退, -# 支持 import ast(包)→ ast.__init__ 的 SHA1 查找。 -# -# Returns: -# SHA1 字符串指针(指向全局存储器内部,无需释放),None 未找到 -# ============================================================ -def LookupSha1ByModName(mod_name: str) -> str: - """从模块名查找 SHA1(精确匹配 + 包名回退),委托通用实现 _FindSha1ByModName""" - return StubMergerIR._FindSha1ByModName(StubMerger._sha1_store_arr, StubMerger._sha1_store_mod, StubMerger._sha1_store_count, mod_name) -# ============================================================ -# LookupSha1ByModNameSuffix - 后缀匹配查找模块 SHA1 -# -# 用于 from .X import Y 的相对导入:impf.module 是 ".X"(带前导点), -# 去掉前导点后为 "X",SHA1 映射表中键是 "pkg.X",需要后缀匹配。 -# 包含三种匹配方式:精确、后缀、反向后缀。 -# -# Returns: -# SHA1 字符串指针(指向全局存储器内部,无需释放),None 未找到 -# ============================================================ -def LookupSha1ByModNameSuffix(mod_suffix: str) -> str: - """后缀匹配查找模块 SHA1""" - if mod_suffix is None: - return None - if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None: - return None - if StubMerger._sha1_store_count <= 0: - return None - suffix_len_sf: t.CSizeT = string.strlen(mod_suffix) - if suffix_len_sf == 0: - return None - i_sf: int - for i_sf in range(StubMerger._sha1_store_count): - idx_sf: t.CSizeT = t.CSizeT(i_sf) * 64 - mod_name_sf: str = StubMerger._sha1_store_mod + idx_sf - mod_len_sf: t.CSizeT = string.strlen(mod_name_sf) - if mod_len_sf == 0: - continue - # 精确匹配 - if mod_len_sf == suffix_len_sf: - if string.strcmp(mod_name_sf, mod_suffix) == 0: - sidx_sf: t.CSizeT = t.CSizeT(i_sf) * 17 - return StubMerger._sha1_store_arr + sidx_sf - # 后缀匹配:mod_name 以 "." + mod_suffix 结尾 - if mod_len_sf > suffix_len_sf: - if mod_name_sf[mod_len_sf - suffix_len_sf - 1] == '.': - cmp_start_sf: str = mod_name_sf + mod_len_sf - suffix_len_sf - if string.strcmp(cmp_start_sf, mod_suffix) == 0: - sidx2_sf: t.CSizeT = t.CSizeT(i_sf) * 17 - return StubMerger._sha1_store_arr + sidx2_sf - # 反向后缀匹配:mod_suffix 以 "." + mod_name 结尾 - if suffix_len_sf > mod_len_sf: - if mod_suffix[suffix_len_sf - mod_len_sf - 1] == '.': - cmp_start_rev_sf: str = mod_suffix + suffix_len_sf - mod_len_sf - if string.strcmp(cmp_start_rev_sf, mod_name_sf) == 0: - sidx_rev_sf: t.CSizeT = t.CSizeT(i_sf) * 17 - return StubMerger._sha1_store_arr + sidx_rev_sf - return None -# ============================================================ -# PopulateIncludesDeps - 将 includes 文件的依赖存入内存 -# -# Phase B+ 前用 declare_only 翻译 includes 文件,提取 _imported_modules -# 后调用此函数存入内存。_BuildReachableSha1Set 从内存读取,不读 deps.txt。 -# -# Args: -# sha1: includes 文件的 SHA1(16字符) -# deps_str: 依赖模块名字符串(空格分隔,如 "t c stdint string") -# -# Returns: -# 0 成功,非 0 失败 -# ============================================================ -def PopulateIncludesDeps(sha1: str, deps_str: str) -> int: - """将 includes 文件的依赖存入内存""" - if sha1 is None: - return 1 - # 延迟初始化 - if StubMerger._includes_deps_sha1 is None: - StubMerger._includes_deps_sha1 = stdlib.malloc(MAX_INCLUDES * 17) - StubMerger._includes_deps_str = stdlib.malloc(MAX_INCLUDES * MAX_DEPS_STR_LEN) - if StubMerger._includes_deps_sha1 is None or StubMerger._includes_deps_str is None: - return 1 - string.memset(StubMerger._includes_deps_sha1, 0, MAX_INCLUDES * 17) - string.memset(StubMerger._includes_deps_str, 0, MAX_INCLUDES * MAX_DEPS_STR_LEN) - StubMerger._includes_deps_count = 0 - if StubMerger._includes_deps_count >= MAX_INCLUDES: - return 1 - # 去重:若 SHA1 已存在则跳过 - for i in range(StubMerger._includes_deps_count): - sidx: t.CSizeT = t.CSizeT(i) * 17 - if string.strcmp(StubMerger._includes_deps_sha1 + sidx, sha1) == 0: - return 0 - # 写入 SHA1 - idx: t.CSizeT = t.CSizeT(StubMerger._includes_deps_count) * 17 - string.strcpy(StubMerger._includes_deps_sha1 + idx, sha1) - # 写入依赖字符串 - idx2: t.CSizeT = t.CSizeT(StubMerger._includes_deps_count) * MAX_DEPS_STR_LEN - if deps_str is not None: - dl: t.CSizeT = string.strlen(deps_str) - if dl < MAX_DEPS_STR_LEN: - string.strcpy(StubMerger._includes_deps_str + idx2, deps_str) - else: - string.strncpy(StubMerger._includes_deps_str + idx2, deps_str, MAX_DEPS_STR_LEN - 1) - else: - StubMerger._includes_deps_str[idx2] = '\0' - StubMerger._includes_deps_count = StubMerger._includes_deps_count + 1 - return 0 -# ============================================================ -# LookupIncludesDeps - 从内存查找 includes 文件的依赖 -# -# Args: -# sha1: includes 文件的 SHA1(16字符) -# -# Returns: -# 依赖模块名字符串指针(空格分隔),None 表示未找到 -# ============================================================ -def LookupIncludesDeps(sha1: str) -> str: - """从内存查找 includes 文件的依赖""" - if sha1 is None or StubMerger._includes_deps_sha1 is None: - return None - if StubMerger._includes_deps_count <= 0: - return None - for i in range(StubMerger._includes_deps_count): - sidx: t.CSizeT = t.CSizeT(i) * 17 - if string.strcmp(StubMerger._includes_deps_sha1 + sidx, sha1) == 0: - idx2: t.CSizeT = t.CSizeT(i) * MAX_DEPS_STR_LEN - return StubMerger._includes_deps_str + idx2 - return None -def GetSha1StoreArrPtr() -> bytes | t.CPtr: - """返回 SHA1 数组指针(每个条目 17 字节)""" - return StubMerger._sha1_store_arr -def GetSha1StoreModArrPtr() -> bytes | t.CPtr: - """返回模块名数组指针(每个条目 64 字节)""" - return StubMerger._sha1_store_mod -def GetSha1StoreRelArrPtr() -> bytes | t.CPtr: - """返回相对路径数组指针(每个条目 MAX_REL_PATH_LEN 字节)""" - return StubMerger._sha1_store_rel -def GetSha1StoreIncdirArrPtr() -> bytes | t.CPtr: - """返回所属 includes 根目录数组指针(每个条目 MAX_INC_DIR_LEN 字节,空串表示不属于任何 includes 目录)""" - return StubMerger._sha1_store_incdir -# ============================================================ -# GetSha1StoreArr - 获取全局存储器数组指针(直接遍历用) -# -# 返回 sha1_arr、mod_arr、rel_arr 三个数组的指针和条目数。 -# 调用者直接遍历数组:sha1_arr[i*17]、mod_arr[i*64]、rel_arr[i*MAX_REL_PATH_LEN] -# 内存归全局存储器所有,调用者不要 free -# ============================================================ -def GetSha1StoreArr(out_sha1_arr: t.CPtr, out_mod_arr: t.CPtr, out_rel_arr: t.CPtr) -> int: - """获取全局存储器数组指针 - - out_sha1_arr/out_mod_arr/out_rel_arr 是调用者提供的 t.CPtr 指针, - 函数将存储器数组指针写入这些位置。 - 返回条目数,-1 失败 - """ - if out_sha1_arr is None or out_mod_arr is None or out_rel_arr is None: - return -1 - if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None or StubMerger._sha1_store_rel is None: - return -1 - sp: t.CPtr = (t.CPtr | t.CPtr)(t.CVoid(out_sha1_arr, t.CPtr)) - if sp is not None: - sp[0] = StubMerger._sha1_store_arr - mp: t.CPtr = (t.CPtr | t.CPtr)(t.CVoid(out_mod_arr, t.CPtr)) - if mp is not None: - mp[0] = StubMerger._sha1_store_mod - rp: t.CPtr = (t.CPtr | t.CPtr)(t.CVoid(out_rel_arr, t.CPtr)) - if rp is not None: - rp[0] = StubMerger._sha1_store_rel - return StubMerger._sha1_store_count -# ============================================================ -# LookupSha1RelPath - 通过 SHA1 查找相对路径 -# -# 遍历全局存储器,返回 sha1 对应的相对路径指针(只读,不要 free)。 -# 用于错误提示:将 sha1 转换为人类可读的文件路径。 -# -# Args: -# sha1: SHA1 字符串(16 字符) -# -# Returns: -# 相对路径字符串指针(只读),None=未找到 -# ============================================================ -def LookupSha1RelPath(sha1: str) -> str: - """通过 SHA1 查找相对路径,返回只读指针,None=未找到""" - if sha1 is None: - return None - if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_rel is None: - return None - for i in range(StubMerger._sha1_store_count): - sidx: t.CSizeT = t.CSizeT(i) * 17 - if string.strcmp(StubMerger._sha1_store_arr + sidx, sha1) == 0: - ridx: t.CSizeT = t.CSizeT(i) * MAX_REL_PATH_LEN - return StubMerger._sha1_store_rel + ridx - return None +import t, c +from stdint import * +import memhub +import string +import stdlib +import llvmlite +import w32.win32file as win32file +import w32.win32base as win32base +import w32.fileio as fileio +import viperlib +import sys +import ast +import lib.core.VLogger as VLogger +import lib.core.IncludesScanner as IncludesScanner +import lib.core.Handles.HandlesTranslator as HandlesTranslator +import lib.core.BuildPipeline as BuildPipeline +import lib.StubGen.VpiReader as VpiReader +import lib.Projectrans.Utils as Utils +import lib.Projectrans.Config as Config + + +import lib.core.StubMergerCollect as StubMergerCollect +import lib.core.StubMergerTopo as StubMergerTopo +import lib.core.StubMergerIR as StubMergerIR +import lib.core.StubMergerBuild as StubMergerBuild +import lib.core.StubMerger as StubMerger + +# ============================================================ +# StubMergerStore - StubMerger 拆分(阶段 E):StubMergerStore +# +# 直接移动模式:函数实现迁至此模块,原 StubMerger.vp 仅保留 +# 常量/全局变量;调用方经本模块前缀访问。全局变量跨模块经 +# StubMerger._xxx 访问(main.vp 先例)。 +# ============================================================ + +# ============================================================ +# PopulateSha1MapStore - 从扫描结果填充全局 SHA1 映射存储器 +# +# 遍历 ScanResult.Entries,为每个条目构建 sha1→module_name 映射。 +# 模块名通过 _PathToModuleName(includes/rel_path) 计算。 +# 内存用 stdlib.malloc 分配(全局存储器,不随 mbuddy 释放)。 +# +# Args: +# scan_result: IncludesScanner 扫描结果 +# +# Returns: +# 填充的条目数,-1 表示失败 +# ============================================================ +def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> int: + """从扫描结果填充全局 SHA1 映射存储器 + + 遍历 ScanResult.Entries,为每个条目构建 sha1→module_name 映射。 + 模块名通过 _PathToModuleName(includes/rel_path) 计算。 + 内存用 stdlib.malloc 分配(全局存储器,不随 mbuddy 释放)。 + """ + if scan_result is None: + return -1 + # 释放旧存储器 + if StubMerger._sha1_store_arr is not None: + stdlib.free(StubMerger._sha1_store_arr) + if StubMerger._sha1_store_mod is not None: + stdlib.free(StubMerger._sha1_store_mod) + if StubMerger._sha1_store_rel is not None: + stdlib.free(StubMerger._sha1_store_rel) + if StubMerger._sha1_store_incdir is not None: + stdlib.free(StubMerger._sha1_store_incdir) + StubMerger._sha1_store_arr = stdlib.malloc(MAX_INCLUDES * 17) + StubMerger._sha1_store_mod = stdlib.malloc(MAX_INCLUDES * 64) + StubMerger._sha1_store_rel = stdlib.malloc(MAX_INCLUDES * MAX_REL_PATH_LEN) + StubMerger._sha1_store_incdir = stdlib.malloc(MAX_INCLUDES * MAX_INC_DIR_LEN) + if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None or StubMerger._sha1_store_rel is None or StubMerger._sha1_store_incdir is None: + return -1 + string.memset(StubMerger._sha1_store_arr, 0, MAX_INCLUDES * 17) + string.memset(StubMerger._sha1_store_mod, 0, MAX_INCLUDES * 64) + string.memset(StubMerger._sha1_store_rel, 0, MAX_INCLUDES * MAX_REL_PATH_LEN) + string.memset(StubMerger._sha1_store_incdir, 0, MAX_INCLUDES * MAX_INC_DIR_LEN) + StubMerger._sha1_store_count = 0 + p_bad: int = 0 + entry_size_p: t.CSizeT = IncludesScanner.FileEntry.__sizeof__() + for i in range(scan_result.Count): + if StubMerger._sha1_store_count >= MAX_INCLUDES: + VLogger.error("includes SHA1 存储超上限,终止", "StubMerger") + ea: t.CUInt64T = t.CUInt64T(scan_result.Entries) + i * entry_size_p + ent: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea, t.CPtr)) + if ent is None or ent.Sha1 is None or ent.RelPath is None: + p_bad += 1 + continue + # 构建完整路径 includes/{RelPath}(_PathToModuleName 需要) + rp_len: t.CSizeT = string.strlen(ent.RelPath) + full_path_buf: bytes = stdlib.malloc(rp_len + 10) + if full_path_buf is None: + p_bad += 1 + continue + viperlib.snprintf(full_path_buf, rp_len + 10, "includes/%s", ent.RelPath) + mod_name: str = Utils.PathToModuleName(full_path_buf, 1) + stdlib.free(full_path_buf) + if mod_name is not None: + idx: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * 17 + string.strcpy(StubMerger._sha1_store_arr + idx, ent.Sha1) + idx2: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * 64 + mn_len: t.CSizeT = string.strlen(mod_name) + if mn_len < 64: + string.strcpy(StubMerger._sha1_store_mod + idx2, mod_name) + else: + string.strncpy(StubMerger._sha1_store_mod + idx2, mod_name, 63) + StubMerger._sha1_store_mod[idx2 + 63] = '\0' + stdlib.free(mod_name) + # 保存 rel_path(供 Phase2 3.5 编译缺失 includes 使用) + idx3: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * MAX_REL_PATH_LEN + if rp_len < MAX_REL_PATH_LEN: + string.strcpy(StubMerger._sha1_store_rel + idx3, ent.RelPath) + else: + string.strncpy(StubMerger._sha1_store_rel + idx3, ent.RelPath, MAX_REL_PATH_LEN - 1) + StubMerger._sha1_store_rel[idx3 + MAX_REL_PATH_LEN - 1] = '\0' + # 保存所属 includes 根目录(Phase2 预注册/按需编译拼路径用) + idx_inc: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * MAX_INC_DIR_LEN + if ent.IncDir is not None: + icd_len: t.CSizeT = string.strlen(ent.IncDir) + if icd_len < MAX_INC_DIR_LEN: + string.strcpy(StubMerger._sha1_store_incdir + idx_inc, ent.IncDir) + else: + string.strncpy(StubMerger._sha1_store_incdir + idx_inc, ent.IncDir, MAX_INC_DIR_LEN - 1) + StubMerger._sha1_store_incdir[idx_inc + MAX_INC_DIR_LEN - 1] = '\0' + StubMerger._sha1_store_count += 1 + if p_bad > 0: + fb_pbad: str = VLogger.fmt_buf() + if fb_pbad is not None: + viperlib.snprintf(fb_pbad, 1024, "includes SHA1 存储有 %d 个条目失败", p_bad) + VLogger.error(fb_pbad, "StubMerger") + return StubMerger._sha1_store_count +# ============================================================ +# AppendToSha1MapStore - 追加条目到全局 SHA1 映射存储器 +# +# Phase1 调用 PopulateSha1MapStore 填充 includes 文件, +# Phase2 扫描 App 源文件后调用此函数追加 App 模块条目, +# 确保编译 App 自身时跨模块 CDefine 查找能命中 App 模块 +# (如 StubMerger.MAX_INCLUDES 在编译 Phase2 时通过 +# _build_source_path_from_sha1 查找 StubMerger 的源路径)。 +# +# 若存储器未初始化(PopulateSha1MapStore 未调用),自动初始化。 +# 若 SHA1 已存在(去重),跳过。 +# +# Args: +# sha1: SHA1 字符串(16 字符 + null) +# rel_path: 相对路径(如 "lib/core/StubMerger.vp", +# 不含 includes/ 前缀,与 _sha1_map.txt 格式一致) +# +# Returns: +# 0 成功(含去重跳过),1 失败 +# ============================================================ +def AppendToSha1MapStore(sha1: str, rel_path: str) -> int: + """追加条目到全局 SHA1 映射存储器(Phase2 用)""" + if sha1 is None or rel_path is None: + return 1 + # 存储器未初始化:自动初始化(Phase2 可能先于 Phase1 调用) + if StubMerger._sha1_store_arr is None: + StubMerger._sha1_store_arr = stdlib.malloc(MAX_INCLUDES * 17) + StubMerger._sha1_store_mod = stdlib.malloc(MAX_INCLUDES * 64) + StubMerger._sha1_store_rel = stdlib.malloc(MAX_INCLUDES * MAX_REL_PATH_LEN) + StubMerger._sha1_store_incdir = stdlib.malloc(MAX_INCLUDES * MAX_INC_DIR_LEN) + if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None or StubMerger._sha1_store_rel is None or StubMerger._sha1_store_incdir is None: + return 1 + string.memset(StubMerger._sha1_store_arr, 0, MAX_INCLUDES * 17) + string.memset(StubMerger._sha1_store_mod, 0, MAX_INCLUDES * 64) + string.memset(StubMerger._sha1_store_rel, 0, MAX_INCLUDES * MAX_REL_PATH_LEN) + string.memset(StubMerger._sha1_store_incdir, 0, MAX_INCLUDES * MAX_INC_DIR_LEN) + StubMerger._sha1_store_count = 0 + if StubMerger._sha1_store_count >= MAX_INCLUDES: + return 1 + # 去重:若 SHA1 已存在则跳过 + for i in range(StubMerger._sha1_store_count): + sidx_d: t.CSizeT = t.CSizeT(i) * 17 + if string.strcmp(StubMerger._sha1_store_arr + sidx_d, sha1) == 0: + return 0 + # 模块名:rel_path "lib/core/StubMerger.vp" → "lib.core.StubMerger" + full_path_buf: bytes = stdlib.malloc(string.strlen(rel_path) + 10) + if full_path_buf is None: + return 1 + viperlib.snprintf(full_path_buf, string.strlen(rel_path) + 10, "includes/%s", rel_path) + mod_name: str = Utils.PathToModuleName(full_path_buf, 1) + stdlib.free(full_path_buf) + if mod_name is None: + return 1 + # 写入 SHA1 + idx_a: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * 17 + string.strcpy(StubMerger._sha1_store_arr + idx_a, sha1) + # 写入模块名 + idx_m: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * 64 + mn_len: t.CSizeT = string.strlen(mod_name) + if mn_len < 64: + string.strcpy(StubMerger._sha1_store_mod + idx_m, mod_name) + else: + string.strncpy(StubMerger._sha1_store_mod + idx_m, mod_name, 63) + StubMerger._sha1_store_mod[idx_m + 63] = '\0' + stdlib.free(mod_name) + # 写入相对路径 + idx_r: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * MAX_REL_PATH_LEN + rp_len: t.CSizeT = string.strlen(rel_path) + if rp_len < MAX_REL_PATH_LEN: + string.strcpy(StubMerger._sha1_store_rel + idx_r, rel_path) + else: + string.strncpy(StubMerger._sha1_store_rel + idx_r, rel_path, MAX_REL_PATH_LEN - 1) + StubMerger._sha1_store_rel[idx_r + MAX_REL_PATH_LEN - 1] = '\0' + # App 源文件不属于任何 includes 目录:IncDir 留空(Phase2 回退 includes_dir 参数) + idx_inc_a: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * MAX_INC_DIR_LEN + StubMerger._sha1_store_incdir[idx_inc_a] = '\0' + StubMerger._sha1_store_count += 1 + return 0 +# ============================================================ +# GetSha1StoreCount - 获取全局存储器条目数 +# ============================================================ +def GetSha1StoreCount() -> int: + """返回全局 SHA1 存储器的条目数""" + return StubMerger._sha1_store_count +# ============================================================ +# LookupSha1ByModName - 从模块名查找 SHA1(直接查全局存储器) +# +# 精确匹配失败时,尝试 "{mod_name}.__init__" 回退, +# 支持 import ast(包)→ ast.__init__ 的 SHA1 查找。 +# +# Returns: +# SHA1 字符串指针(指向全局存储器内部,无需释放),None 未找到 +# ============================================================ +def LookupSha1ByModName(mod_name: str) -> str: + """从模块名查找 SHA1(精确匹配 + 包名回退),委托通用实现 _FindSha1ByModName""" + return StubMergerIR._FindSha1ByModName(StubMerger._sha1_store_arr, StubMerger._sha1_store_mod, StubMerger._sha1_store_count, mod_name) +# ============================================================ +# LookupSha1ByModNameSuffix - 后缀匹配查找模块 SHA1 +# +# 用于 from .X import Y 的相对导入:impf.module 是 ".X"(带前导点), +# 去掉前导点后为 "X",SHA1 映射表中键是 "pkg.X",需要后缀匹配。 +# 包含三种匹配方式:精确、后缀、反向后缀。 +# +# Returns: +# SHA1 字符串指针(指向全局存储器内部,无需释放),None 未找到 +# ============================================================ +def LookupSha1ByModNameSuffix(mod_suffix: str) -> str: + """后缀匹配查找模块 SHA1""" + if mod_suffix is None: + return None + if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None: + return None + if StubMerger._sha1_store_count <= 0: + return None + suffix_len_sf: t.CSizeT = string.strlen(mod_suffix) + if suffix_len_sf == 0: + return None + i_sf: int + for i_sf in range(StubMerger._sha1_store_count): + idx_sf: t.CSizeT = t.CSizeT(i_sf) * 64 + mod_name_sf: str = StubMerger._sha1_store_mod + idx_sf + mod_len_sf: t.CSizeT = string.strlen(mod_name_sf) + if mod_len_sf == 0: + continue + # 精确匹配 + if mod_len_sf == suffix_len_sf: + if string.strcmp(mod_name_sf, mod_suffix) == 0: + sidx_sf: t.CSizeT = t.CSizeT(i_sf) * 17 + return StubMerger._sha1_store_arr + sidx_sf + # 后缀匹配:mod_name 以 "." + mod_suffix 结尾 + if mod_len_sf > suffix_len_sf: + if mod_name_sf[mod_len_sf - suffix_len_sf - 1] == '.': + cmp_start_sf: str = mod_name_sf + mod_len_sf - suffix_len_sf + if string.strcmp(cmp_start_sf, mod_suffix) == 0: + sidx2_sf: t.CSizeT = t.CSizeT(i_sf) * 17 + return StubMerger._sha1_store_arr + sidx2_sf + # 反向后缀匹配:mod_suffix 以 "." + mod_name 结尾 + if suffix_len_sf > mod_len_sf: + if mod_suffix[suffix_len_sf - mod_len_sf - 1] == '.': + cmp_start_rev_sf: str = mod_suffix + suffix_len_sf - mod_len_sf + if string.strcmp(cmp_start_rev_sf, mod_name_sf) == 0: + sidx_rev_sf: t.CSizeT = t.CSizeT(i_sf) * 17 + return StubMerger._sha1_store_arr + sidx_rev_sf + return None +# ============================================================ +# PopulateIncludesDeps - 将 includes 文件的依赖存入内存 +# +# Phase B+ 前用 declare_only 翻译 includes 文件,提取 _imported_modules +# 后调用此函数存入内存。_BuildReachableSha1Set 从内存读取,不读 deps.txt。 +# +# Args: +# sha1: includes 文件的 SHA1(16字符) +# deps_str: 依赖模块名字符串(空格分隔,如 "t c stdint string") +# +# Returns: +# 0 成功,非 0 失败 +# ============================================================ +def PopulateIncludesDeps(sha1: str, deps_str: str) -> int: + """将 includes 文件的依赖存入内存""" + if sha1 is None: + return 1 + # 延迟初始化 + if StubMerger._includes_deps_sha1 is None: + StubMerger._includes_deps_sha1 = stdlib.malloc(MAX_INCLUDES * 17) + StubMerger._includes_deps_str = stdlib.malloc(MAX_INCLUDES * MAX_DEPS_STR_LEN) + if StubMerger._includes_deps_sha1 is None or StubMerger._includes_deps_str is None: + return 1 + string.memset(StubMerger._includes_deps_sha1, 0, MAX_INCLUDES * 17) + string.memset(StubMerger._includes_deps_str, 0, MAX_INCLUDES * MAX_DEPS_STR_LEN) + StubMerger._includes_deps_count = 0 + if StubMerger._includes_deps_count >= MAX_INCLUDES: + return 1 + # 去重:若 SHA1 已存在则跳过 + for i in range(StubMerger._includes_deps_count): + sidx: t.CSizeT = t.CSizeT(i) * 17 + if string.strcmp(StubMerger._includes_deps_sha1 + sidx, sha1) == 0: + return 0 + # 写入 SHA1 + idx: t.CSizeT = t.CSizeT(StubMerger._includes_deps_count) * 17 + string.strcpy(StubMerger._includes_deps_sha1 + idx, sha1) + # 写入依赖字符串 + idx2: t.CSizeT = t.CSizeT(StubMerger._includes_deps_count) * MAX_DEPS_STR_LEN + if deps_str is not None: + dl: t.CSizeT = string.strlen(deps_str) + if dl < MAX_DEPS_STR_LEN: + string.strcpy(StubMerger._includes_deps_str + idx2, deps_str) + else: + string.strncpy(StubMerger._includes_deps_str + idx2, deps_str, MAX_DEPS_STR_LEN - 1) + else: + StubMerger._includes_deps_str[idx2] = '\0' + StubMerger._includes_deps_count = StubMerger._includes_deps_count + 1 + return 0 +# ============================================================ +# LookupIncludesDeps - 从内存查找 includes 文件的依赖 +# +# Args: +# sha1: includes 文件的 SHA1(16字符) +# +# Returns: +# 依赖模块名字符串指针(空格分隔),None 表示未找到 +# ============================================================ +def LookupIncludesDeps(sha1: str) -> str: + """从内存查找 includes 文件的依赖""" + if sha1 is None or StubMerger._includes_deps_sha1 is None: + return None + if StubMerger._includes_deps_count <= 0: + return None + for i in range(StubMerger._includes_deps_count): + sidx: t.CSizeT = t.CSizeT(i) * 17 + if string.strcmp(StubMerger._includes_deps_sha1 + sidx, sha1) == 0: + idx2: t.CSizeT = t.CSizeT(i) * MAX_DEPS_STR_LEN + return StubMerger._includes_deps_str + idx2 + return None +def GetSha1StoreArrPtr() -> bytes | t.CPtr: + """返回 SHA1 数组指针(每个条目 17 字节)""" + return StubMerger._sha1_store_arr +def GetSha1StoreModArrPtr() -> bytes | t.CPtr: + """返回模块名数组指针(每个条目 64 字节)""" + return StubMerger._sha1_store_mod +def GetSha1StoreRelArrPtr() -> bytes | t.CPtr: + """返回相对路径数组指针(每个条目 MAX_REL_PATH_LEN 字节)""" + return StubMerger._sha1_store_rel +def GetSha1StoreIncdirArrPtr() -> bytes | t.CPtr: + """返回所属 includes 根目录数组指针(每个条目 MAX_INC_DIR_LEN 字节,空串表示不属于任何 includes 目录)""" + return StubMerger._sha1_store_incdir +# ============================================================ +# GetSha1StoreArr - 获取全局存储器数组指针(直接遍历用) +# +# 返回 sha1_arr、mod_arr、rel_arr 三个数组的指针和条目数。 +# 调用者直接遍历数组:sha1_arr[i*17]、mod_arr[i*64]、rel_arr[i*MAX_REL_PATH_LEN] +# 内存归全局存储器所有,调用者不要 free +# ============================================================ +def GetSha1StoreArr(out_sha1_arr: t.CPtr, out_mod_arr: t.CPtr, out_rel_arr: t.CPtr) -> int: + """获取全局存储器数组指针 + + out_sha1_arr/out_mod_arr/out_rel_arr 是调用者提供的 t.CPtr 指针, + 函数将存储器数组指针写入这些位置。 + 返回条目数,-1 失败 + """ + if out_sha1_arr is None or out_mod_arr is None or out_rel_arr is None: + return -1 + if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None or StubMerger._sha1_store_rel is None: + return -1 + sp: t.CPtr = (t.CPtr | t.CPtr)(t.CVoid(out_sha1_arr, t.CPtr)) + if sp is not None: + sp[0] = StubMerger._sha1_store_arr + mp: t.CPtr = (t.CPtr | t.CPtr)(t.CVoid(out_mod_arr, t.CPtr)) + if mp is not None: + mp[0] = StubMerger._sha1_store_mod + rp: t.CPtr = (t.CPtr | t.CPtr)(t.CVoid(out_rel_arr, t.CPtr)) + if rp is not None: + rp[0] = StubMerger._sha1_store_rel + return StubMerger._sha1_store_count +# ============================================================ +# LookupSha1RelPath - 通过 SHA1 查找相对路径 +# +# 遍历全局存储器,返回 sha1 对应的相对路径指针(只读,不要 free)。 +# 用于错误提示:将 sha1 转换为人类可读的文件路径。 +# +# Args: +# sha1: SHA1 字符串(16 字符) +# +# Returns: +# 相对路径字符串指针(只读),None=未找到 +# ============================================================ +def LookupSha1RelPath(sha1: str) -> str: + """通过 SHA1 查找相对路径,返回只读指针,None=未找到""" + if sha1 is None: + return None + if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_rel is None: + return None + for i in range(StubMerger._sha1_store_count): + sidx: t.CSizeT = t.CSizeT(i) * 17 + if string.strcmp(StubMerger._sha1_store_arr + sidx, sha1) == 0: + ridx: t.CSizeT = t.CSizeT(i) * MAX_REL_PATH_LEN + return StubMerger._sha1_store_rel + ridx + return None diff --git a/App/lib/core/StubMergerTopo.vp b/App/lib/core/StubMergerTopo.vp index 711604a..e4a816f 100644 --- a/App/lib/core/StubMergerTopo.vp +++ b/App/lib/core/StubMergerTopo.vp @@ -1,168 +1,166 @@ -import t, c -from stdint import * -import memhub -import string -import stdlib -import llvmlite -import w32.win32file as win32file -import w32.win32base as win32base -import w32.fileio as fileio -import viperlib -import sys -import ast -import lib.core.VLogger as VLogger -import lib.core.IncludesScanner as IncludesScanner -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesTranslator as HandlesTranslator -import lib.core.BuildPipeline as BuildPipeline -import lib.StubGen.VpiReader as VpiReader -import lib.Projectrans.Utils as Utils -import lib.Projectrans.Config as Config - - -import lib.core.StubMergerCollect as StubMergerCollect -import lib.core.StubMergerStore as StubMergerStore -import lib.core.StubMergerIR as StubMergerIR -import lib.core.StubMergerBuild as StubMergerBuild -import lib.core.StubMerger as StubMerger - -# ============================================================ -# StubMergerTopo - StubMerger 拆分(阶段 E):StubMergerTopo -# -# 直接移动模式:函数实现迁至此模块,原 StubMerger.vp 仅保留 -# 常量/全局变量;调用方经本模块前缀访问。全局变量跨模块经 -# StubMerger._xxx 访问(main.vp 先例)。 -# ============================================================ - -# ============================================================ -# BuildTopoSortedIndices - 对可达 includes 逆拓扑排序(被依赖者先) -# -# 背景:跨模块 vtable 生成要求被依赖模块先完整翻译(如 astaux.vp 继承 -# base.vp 的 AST,vtable 槽位需 AST.accept 的 TypeStr 已注册到全局表)。 -# Phase B+ 原先按 store 扫描顺序编译,依赖顺序不保证 → fail-fast 暴露。 -# -# 算法:Kahn 逆拓扑。边 m→d 表示 m 依赖 d(d 在 m 的 deps 中)。 -# indegree[m] = m 在可达集合内的直接依赖数; -# 入度为 0(不依赖任何可达模块)者先输出,输出后对依赖它的模块 -# 减入度,入度归 0 者入队。结果即"被依赖者先编译"。 -# reachable_count <= 0 时对全部 store 排序(与既有全量编译行为一致)。 -# -# Args: -# store_count / store_sha1_arr / store_mod_arr: store 元数据 -# reachable_set / reachable_count: 可达集合(_BuildReachableSha1Set 输出) -# sorted_idx: 输出数组(store_count+1 个 8 字节槽),前 N 个为拓扑序 store 索引 -# -# Returns: -# 拓扑序条数;有环时剩余条目按 store 顺序补齐(避免漏编译) -# ============================================================ -def BuildTopoSortedIndices(store_count: int, store_sha1_arr: bytes, - store_mod_arr: bytes, reachable_set: bytes, - reachable_count: int, - sorted_idx: t.CSizeT | t.CPtr) -> int: - """对可达 includes 逆拓扑排序(被依赖者先),store 索引写入 sorted_idx""" - if store_count <= 0 or store_sha1_arr is None or store_mod_arr is None or sorted_idx is None: - return 0 - indegree: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(stdlib.malloc(8 * (store_count + 1))) - queue: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(stdlib.malloc(8 * (store_count + 1))) - rel_idx: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(stdlib.malloc(8 * (store_count + 1))) - if indegree is None or queue is None or rel_idx is None: - if indegree is not None: - stdlib.free(indegree) - if queue is not None: - stdlib.free(queue) - if rel_idx is not None: - stdlib.free(rel_idx) - return 0 - # 收集可达 store 索引(reachable_count<=0 时全量,对齐既有全量编译行为) - rel_count: int = 0 - i_t: int - if reachable_set is None or reachable_count <= 0: - for i_t in range(store_count): - rel_idx[rel_count] = i_t - rel_count += 1 - else: - for i_t in range(store_count): - if StubMergerCollect._is_in_sha1_set(store_sha1_arr + t.CSizeT(i_t) * 17, reachable_set, reachable_count) != 0: - rel_idx[rel_count] = i_t - rel_count += 1 - # 计算入度:m 在可达集合内的直接依赖数 - i_r: int - for i_r in range(rel_count): - si: int = rel_idx[i_r] - deps_si: str = StubMergerStore.LookupIncludesDeps(store_sha1_arr + t.CSizeT(si) * 17) - if deps_si is None: - continue - dl_si: t.CSizeT = string.strlen(deps_si) - dpos: t.CSizeT = 0 - while dpos < dl_si: - dstart: t.CSizeT = dpos - while dpos < dl_si and deps_si[dpos] != ' ': - dpos += 1 - dlen: t.CSizeT = dpos - dstart - if dpos < dl_si: - dpos += 1 - if dlen == 0: - continue - dname_buf: bytes = stdlib.malloc(dlen + 1) - if dname_buf is None: - continue - string.strncpy(dname_buf, deps_si + dstart, dlen) - dname_buf[dlen] = '\0' - dsha1: str = StubMergerIR._FindSha1ByModName(store_sha1_arr, store_mod_arr, store_count, dname_buf) - stdlib.free(dname_buf) - if dsha1 is not None and StubMergerCollect._is_in_sha1_set(dsha1, reachable_set, reachable_count) != 0: - indegree[si] = indegree[si] + 1 - # Kahn:入度为 0(不依赖任何可达模块)者先出 → 最先编译 - q_head: int = 0 - q_tail: int = 0 - for i_r in range(rel_count): - si2: int = rel_idx[i_r] - if indegree[si2] == 0: - queue[q_tail] = si2 - q_tail += 1 - out_count: int = 0 - while q_head < q_tail: - m: int = queue[q_head] - q_head += 1 - sorted_idx[out_count] = m - out_count += 1 - # 对依赖 m 的可达模块减入度 - mod_m: str = store_mod_arr + t.CSizeT(m) * 64 - mod_m_len: t.CSizeT = string.strlen(mod_m) - for i_r in range(rel_count): - si3: int = rel_idx[i_r] - if indegree[si3] == 0: - continue - deps_si3: str = StubMergerStore.LookupIncludesDeps(store_sha1_arr + t.CSizeT(si3) * 17) - if deps_si3 is None: - continue - dl_si3: t.CSizeT = string.strlen(deps_si3) - dpos3: t.CSizeT = 0 - found_dep: int = 0 - while dpos3 < dl_si3 and found_dep == 0: - dstart3: t.CSizeT = dpos3 - while dpos3 < dl_si3 and deps_si3[dpos3] != ' ': - dpos3 += 1 - dlen3: t.CSizeT = dpos3 - dstart3 - if dpos3 < dl_si3: - dpos3 += 1 - if dlen3 == 0: - continue - if dlen3 == mod_m_len and string.strncmp(deps_si3 + dstart3, mod_m, mod_m_len) == 0: - found_dep = 1 - if found_dep == 1: - indegree[si3] = indegree[si3] - 1 - if indegree[si3] == 0: - queue[q_tail] = si3 - q_tail += 1 - # 有环时剩余条目按 store 顺序补齐(避免漏编译) - for i_r in range(rel_count): - si4: int = rel_idx[i_r] - if indegree[si4] > 0: - sorted_idx[out_count] = si4 - out_count += 1 - stdlib.free(indegree) - stdlib.free(queue) - stdlib.free(rel_idx) - return out_count +import t, c +from stdint import * +import memhub +import string +import stdlib +import llvmlite +import w32.win32file as win32file +import w32.win32base as win32base +import w32.fileio as fileio +import viperlib +import sys +import ast +import lib.core.VLogger as VLogger +import lib.core.IncludesScanner as IncludesScanner +import lib.core.Handles.HandlesTranslator as HandlesTranslator +import lib.core.BuildPipeline as BuildPipeline +import lib.StubGen.VpiReader as VpiReader +import lib.Projectrans.Utils as Utils +import lib.Projectrans.Config as Config + + +import lib.core.StubMergerCollect as StubMergerCollect +import lib.core.StubMergerStore as StubMergerStore +import lib.core.StubMergerIR as StubMergerIR +import lib.core.StubMergerBuild as StubMergerBuild +import lib.core.StubMerger as StubMerger + +# ============================================================ +# StubMergerTopo - StubMerger 拆分(阶段 E):StubMergerTopo +# +# 直接移动模式:函数实现迁至此模块,原 StubMerger.vp 仅保留 +# 常量/全局变量;调用方经本模块前缀访问。全局变量跨模块经 +# StubMerger._xxx 访问(main.vp 先例)。 +# ============================================================ + +# ============================================================ +# BuildTopoSortedIndices - 对可达 includes 逆拓扑排序(被依赖者先) +# +# 背景:跨模块 vtable 生成要求被依赖模块先完整翻译(如 astaux.vp 继承 +# base.vp 的 AST,vtable 槽位需 AST.accept 的 TypeStr 已注册到全局表)。 +# Phase B+ 原先按 store 扫描顺序编译,依赖顺序不保证 → fail-fast 暴露。 +# +# 算法:Kahn 逆拓扑。边 m→d 表示 m 依赖 d(d 在 m 的 deps 中)。 +# indegree[m] = m 在可达集合内的直接依赖数; +# 入度为 0(不依赖任何可达模块)者先输出,输出后对依赖它的模块 +# 减入度,入度归 0 者入队。结果即"被依赖者先编译"。 +# reachable_count <= 0 时对全部 store 排序(与既有全量编译行为一致)。 +# +# Args: +# store_count / store_sha1_arr / store_mod_arr: store 元数据 +# reachable_set / reachable_count: 可达集合(_BuildReachableSha1Set 输出) +# sorted_idx: 输出数组(store_count+1 个 8 字节槽),前 N 个为拓扑序 store 索引 +# +# Returns: +# 拓扑序条数;有环时剩余条目按 store 顺序补齐(避免漏编译) +# ============================================================ +def BuildTopoSortedIndices(store_count: int, store_sha1_arr: bytes, + store_mod_arr: bytes, reachable_set: bytes, + reachable_count: int, + sorted_idx: t.CSizeT | t.CPtr) -> int: + """对可达 includes 逆拓扑排序(被依赖者先),store 索引写入 sorted_idx""" + if store_count <= 0 or store_sha1_arr is None or store_mod_arr is None or sorted_idx is None: + return 0 + indegree: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(stdlib.malloc(8 * (store_count + 1))) + queue: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(stdlib.malloc(8 * (store_count + 1))) + rel_idx: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(stdlib.malloc(8 * (store_count + 1))) + if indegree is None or queue is None or rel_idx is None: + if indegree is not None: + stdlib.free(indegree) + if queue is not None: + stdlib.free(queue) + if rel_idx is not None: + stdlib.free(rel_idx) + return 0 + # 收集可达 store 索引(reachable_count<=0 时全量,对齐既有全量编译行为) + rel_count: int = 0 + i_t: int + if reachable_set is None or reachable_count <= 0: + for i_t in range(store_count): + rel_idx[rel_count] = i_t + rel_count += 1 + else: + for i_t in range(store_count): + if StubMergerCollect._is_in_sha1_set(store_sha1_arr + t.CSizeT(i_t) * 17, reachable_set, reachable_count) != 0: + rel_idx[rel_count] = i_t + rel_count += 1 + # 计算入度:m 在可达集合内的直接依赖数 + i_r: int + for i_r in range(rel_count): + si: int = rel_idx[i_r] + deps_si: str = StubMergerStore.LookupIncludesDeps(store_sha1_arr + t.CSizeT(si) * 17) + if deps_si is None: + continue + dl_si: t.CSizeT = string.strlen(deps_si) + dpos: t.CSizeT = 0 + while dpos < dl_si: + dstart: t.CSizeT = dpos + while dpos < dl_si and deps_si[dpos] != ' ': + dpos += 1 + dlen: t.CSizeT = dpos - dstart + if dpos < dl_si: + dpos += 1 + if dlen == 0: + continue + dname_buf: bytes = stdlib.malloc(dlen + 1) + if dname_buf is None: + continue + string.strncpy(dname_buf, deps_si + dstart, dlen) + dname_buf[dlen] = '\0' + dsha1: str = StubMergerIR._FindSha1ByModName(store_sha1_arr, store_mod_arr, store_count, dname_buf) + stdlib.free(dname_buf) + if dsha1 is not None and StubMergerCollect._is_in_sha1_set(dsha1, reachable_set, reachable_count) != 0: + indegree[si] = indegree[si] + 1 + # Kahn:入度为 0(不依赖任何可达模块)者先出 → 最先编译 + q_head: int = 0 + q_tail: int = 0 + for i_r in range(rel_count): + si2: int = rel_idx[i_r] + if indegree[si2] == 0: + queue[q_tail] = si2 + q_tail += 1 + out_count: int = 0 + while q_head < q_tail: + m: int = queue[q_head] + q_head += 1 + sorted_idx[out_count] = m + out_count += 1 + # 对依赖 m 的可达模块减入度 + mod_m: str = store_mod_arr + t.CSizeT(m) * 64 + mod_m_len: t.CSizeT = string.strlen(mod_m) + for i_r in range(rel_count): + si3: int = rel_idx[i_r] + if indegree[si3] == 0: + continue + deps_si3: str = StubMergerStore.LookupIncludesDeps(store_sha1_arr + t.CSizeT(si3) * 17) + if deps_si3 is None: + continue + dl_si3: t.CSizeT = string.strlen(deps_si3) + dpos3: t.CSizeT = 0 + found_dep: int = 0 + while dpos3 < dl_si3 and found_dep == 0: + dstart3: t.CSizeT = dpos3 + while dpos3 < dl_si3 and deps_si3[dpos3] != ' ': + dpos3 += 1 + dlen3: t.CSizeT = dpos3 - dstart3 + if dpos3 < dl_si3: + dpos3 += 1 + if dlen3 == 0: + continue + if dlen3 == mod_m_len and string.strncmp(deps_si3 + dstart3, mod_m, mod_m_len) == 0: + found_dep = 1 + if found_dep == 1: + indegree[si3] = indegree[si3] - 1 + if indegree[si3] == 0: + queue[q_tail] = si3 + q_tail += 1 + # 有环时剩余条目按 store 顺序补齐(避免漏编译) + for i_r in range(rel_count): + si4: int = rel_idx[i_r] + if indegree[si4] > 0: + sorted_idx[out_count] = si4 + out_count += 1 + stdlib.free(indegree) + stdlib.free(queue) + stdlib.free(rel_idx) + return out_count diff --git a/App/main.vp b/App/main.vp index bb5153e..5a5ae1e 100644 --- a/App/main.vp +++ b/App/main.vp @@ -1,712 +1,673 @@ -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HandlesTranslator -import lib.core.Handles.HandlesStruct as HandlesStruct -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.HandlesFunctions as HandlesFunctions -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesBody as HandlesBody -import lib.core.Handles.HandlesIf as HandlesIf -import lib.core.Handles.HandlesWhile as HandlesWhile -import lib.core.Handles.HandlesFor as HandlesFor -import lib.core.Handles.HandlesReturn as HandlesReturn -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesMatch as HandlesMatch -import lib.core.Handles.HandlesEnum as HandlesEnum -import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign -import lib.core.Handles.HandlesAugAssign as HandlesAugAssign -import lib.core.Handles.HandlesAssign as HandlesAssign -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesMain as HandlesMain -import lib.core.BuildPipeline as BuildPipeline -import lib.core.IncludesScanner as IncludesScanner -import lib.core.StubMerger as StubMerger -import lib.core.Phase1 as Phase1 -import lib.core.Phase2 as Phase2 -import lib.core.CompilerFactory as CompilerFactory -import lib.core.Gen.Generator as GenGenerator -import lib.Projectrans.Config as Config -import lib.Projectrans.Utils as Utils -import lib -from stdint import * -import stdio -import string -import stdlib -import memhub -import argparse -import w32.win32console as w32cmd -import w32.fileio as fileio -import w32.win32file -import w32.win32base -import sys -import ast -import llvmlite -import subprocess -import viperlib -import hashlib -import t, c -import lib.core.StubMergerBuild as StubMergerBuild -import lib.core.StubMergerCollect as StubMergerCollect -import lib.core.Phase1Main as Phase1Main - - -# Main Pool 1 GiB -POOL_SIZE: t.CDefine = 1073741824 -# Permanent memory pool size: 2^29 + 264 = 512MB usable -PERM_POOL_SIZE: t.CDefine = 536871176 -# Code page: UTF-8 (Windows 65001) -CODE_PAGE: t.CDefine = 65001 -# Source code buffer size (1MB) -SRC_BUF_SIZE: t.CDefine = 1048576 -# Version (dev/beta/rc) -V_VIPER_VERSION: t.CDefine = "1.0.3-dev.29 2026-07-27 Non-LTS" -V_TPV_VERSION: t.CDefine = "0.0.2-dev.173" -V_RUNTIME_VERSION: t.CDefine = "0.2.2+3-Non-LTS" -V_TERMINEXUS_AGE: t.CDefine = "15.3" -V_TPC_COMMIT: t.CDefine = "a641c7c8da/2026‑08‑17T02:49:00Z" -V_TPV_COMMIT: t.CDefine = "" -V_RUNTIME_COMMIT: t.CDefine = "14ff9d109f/2026-08-17T03:02:20Z" -V_TARGET: t.CDefine = "x86_64-w64-windows-gnu" -V_LLVM: t.CDefine = "22.1.8" - -# ============================================================ -# main: Command-line entry -# ============================================================ -def main() -> int: - w32cmd.SetConsoleOutputCP(CODE_PAGE) - w32cmd.SetConsoleCP(CODE_PAGE) - - # Initialize the mbuddy memory pool - arena: bytes = stdlib.malloc(POOL_SIZE) - if arena is None: - stdio.printf("FAIL: malloc for arena failed\n") - return 1 - # Create a global permanent memory pool (perm_pool, 512MB) - perm_arena: bytes = stdlib.malloc(PERM_POOL_SIZE) - if perm_arena is None: - stdio.printf("FAIL: malloc for perm_pool arena failed\n") - return 1 - - mb: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, POOL_SIZE) - if mb is None: - stdio.printf("FAIL: MemBuddy init failed\n") - return 1 - - perm_pool: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(perm_arena, PERM_POOL_SIZE) - if perm_pool is None: - stdio.printf("FAIL: perm_pool init failed\n") - return 1 - - CompilerFactory.set_factory(CompilerFactory.CompilerFactory(mb, perm_pool)) - - # 设置全局 mbuddy 指针(sys 和 argparse 都需要) - sys._mbuddy = mb - argparse._mbuddy = mb - ast._mbuddy = mb - lib._mbuddy = mb - Config._mbuddy = mb - Utils._mbuddy = mb - HandlesTranslator._mbuddy = mb - BuildPipeline._mbuddy = mb - IncludesScanner._mbuddy = mb - StubMerger._mbuddy = mb - Phase1._mbuddy = mb - Phase2._mbuddy = mb - subprocess._mbuddy = mb - # hashlib._mbuddy = (mb) - VLogger._mbuddy = mb - lib.InitLib(mb) - - # P2: 创建项目级 Generator 单例(Phase1/Phase2/BuildPipeline 全程复用; - # HandlesType 等旧模块函数经延迟 import 委托到 gen 方法,实现对象化过渡) - gen: GenGenerator.Generator | t.CPtr = mb.alloc(GenGenerator.Generator.__sizeof__()) - if gen is None: - stdio.printf("FAIL: Generator alloc failed\n") - return 1 - gen.__before_init__() - gen.__init__(mb) - - GenGenerator._g_gen = gen - # P2-P5: 注入各 Handles 模块级单例(Phase1 阶段即调用其状态函数) - HandlesType._g_gen = gen - HandlesStruct._g_gen = gen - HandlesExpr._g_gen = gen - HandlesExprOps._g_gen = gen - HandlesExprCall._g_gen = gen - HandlesFunctions._g_gen = gen - HandlesClassDef._g_gen = gen - # P6: 注入语句/赋值/变量/导入/翻译驱动模块的单例 - HandlesImports._g_gen = gen - HandlesBody._g_gen = gen - HandlesIf._g_gen = gen - HandlesWhile._g_gen = gen - HandlesFor._g_gen = gen - HandlesReturn._g_gen = gen - HandlesNonlocal._g_gen = gen - HandlesMatch._g_gen = gen - HandlesEnum._g_gen = gen - HandlesAnnAssign._g_gen = gen - HandlesAugAssign._g_gen = gen - HandlesAssign._g_gen = gen - HandlesVar._g_gen = gen - HandlesTranslator._g_gen = gen - HandlesMain._g_gen = gen - - # 初始化 VLogger 并打印启动日志 - log: VLogger.Logger | t.CPtr = VLogger.get_logger() - if log is None: - log.error("TransPyV Failed to parse parameters") - - # 初始化命令行参数(Windows: GetCommandLineA, POSIX: /proc/self/cmdline) - sys._init_argv() - - # 创建参数解析器 - parser: argparse.ArgumentParser | t.CPtr = argparse.ArgumentParser("TransPyV", "TransPyV command-line parameter parser", pool=mb) - - # 注册参数(与 Projectrans.py main() 一致) - parser.add_argument("--project", None, argparse.STRING, 0, None, False, argparse.STORE, "Project VPJ path, by default it looks in the current directory") - parser.add_argument("--src", None, argparse.STRING, 0, None, False, argparse.STORE, "Source directory") - parser.add_argument("--temp", None, argparse.STRING, 0, None, False, argparse.STORE, "Declare a temporary directory for the interface") - parser.add_argument("--output", None, argparse.STRING, 0, None, False, argparse.STORE, "Output directory") - parser.add_argument("--phase", None, argparse.STRING, 0, None, False, argparse.STORE, "Phase: 1 = Generate statement, 2 = Translate and compile, all = Everything") - parser.add_argument("--cc", None, argparse.STRING, 0, None, False, argparse.STORE, "LLVM compiler command") - parser.add_argument("--clean", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Clean output and temp directories") - parser.add_argument("--run", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Run the generated executable after compilation") - parser.add_argument("--rebuild-includes", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Delete the includes.binary precompiled cache and rebuild all the includes") - parser.add_argument("--clear-cache", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Clear .transpyc_cache global cache") - parser.add_argument("--asan", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "ASan mode: .ll first opt -passes=asan then link -fsanitize=address") - parser.add_argument("--nowarn-register", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Suppress Phase A dependency WARN") - parser.add_argument("--version", "-v", argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Show version and exit") - parser.add_argument("--help", "-h", argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Show help and exit") - - # 解析命令行参数 - args: argparse.ParsedArgs | t.CPtr = parser.parse_args(sys._argc, sys._argv) - if args is None: - if log is not None: - log.error("参数解析失败", "argparse") - return 1 - - if args.get_bool("help"): - parser.print_help() - return 0 - - if args.get_bool("version"): - stdio.printf("""Viper %s -Copyright (C) 2026 Viper Project -License MIT -GVSDS(TM) Viper SE Runtime Environment and Library (VRTE) %s -Viper Frontend Compiler TransPyV %s -TermiNexus Age %sY - -Tpv commit: %s -Tpc commit: %s -VRTE commit: %s -Target: %s - -""", V_VIPER_VERSION, V_RUNTIME_VERSION, V_TPV_VERSION, V_TERMINEXUS_AGE, V_TPV_COMMIT, V_TPC_COMMIT, V_RUNTIME_COMMIT, V_TARGET, V_LLVM) - return 0 - - # 打印解析结果 - #if log is not None: - # log.banner("TransPyV 参数解析结果") - - # 字符串参数 - project: str = args.get_str("project") - #if project is not None: stdio.printf(" --project: %s\n", project) - #else: stdio.printf(" --project: (未指定)\n") - - src: str = args.get_str("src") - #if src is not None: stdio.printf(" --src: %s\n", src) - #else: stdio.printf(" --src: (未指定)\n") - - temp: str = args.get_str("temp") - #if temp is not None: stdio.printf(" --temp: %s\n", temp) - #else: stdio.printf(" --temp: (未指定)\n") - - output: str = args.get_str("output") - #if output is not None: stdio.printf(" --output: %s\n", output) - #else: stdio.printf(" --output: (未指定)\n") - - phase: str = args.get_str("phase") - #if phase is not None: stdio.printf(" --phase: %s\n", phase) - #else: stdio.printf(" --phase: (未指定,默认 all)\n") - - cc: str = args.get_str("cc") - #if cc is not None: stdio.printf(" --cc: %s\n", cc) - #else: stdio.printf(" --cc: (未指定)\n") - - # 布尔参数 - _gb_clean: INT = args.get_bool("clean") - #if _gb_clean: stdio.printf(" --clean: True\n") - #else: stdio.printf(" --clean: False\n") - - #if args.get_bool("run"): stdio.printf(" --run: True\n") - #else: stdio.printf(" --run: False\n") - - #if args.get_bool("rebuild-includes"): stdio.printf(" --rebuild-includes: True\n") - #else: stdio.printf(" --rebuild-includes: False\n") - - #if args.get_bool("clear-cache"): stdio.printf(" --clear-cache: True\n") - #else: stdio.printf(" --clear-cache: False\n") - - #stdio.printf("\n参数解析完成。\n") - - # ASan 模式:设置 BuildPipeline 全局标志(compile_ll_to_obj 先 opt 插桩,链接 asan 库) - # includes 缓存用独立目录 .binary_asan 隔离 asan 插桩 obj,避免与非 asan obj 混链 - # (asan obj 引用 __asan_init 等符号,非 asan 链接不提供 asan 库 → undefined reference) - if args.get_bool("asan"): - BuildPipeline._asan_mode = True - Config.set_inc_bin_suffix(".binary_asan") - if log is not None: - log.info("ASan 模式已启用(opt -passes=asan + libclang_rt)", "asan") - # ASan 模式清理 asan includes 缓存(强制重建 asan 插桩 obj) - mf_inc_bin_asan: str = Config.get_includes_binary_dir() - if mf_inc_bin_asan is not None: - n_asan: int = Utils.CleanDir(mf_inc_bin_asan) - if log is not None: - fb_asan: str = VLogger.fmt_buf() - if fb_asan is not None: - viperlib.snprintf(fb_asan, 1024, "ASan 模式清理 includes 缓存: %d 个文件(将重建 asan obj)", n_asan) - log.info(fb_asan, "asan") - else: - BuildPipeline._asan_mode = False - Config.set_inc_bin_suffix(".binary") - - # --nowarn-register:抑制"外部函数返回类型未登记"类 WARN 输出 - if args.get_bool("nowarn-register"): - VLogger.set_nowarn_register(1) - if log is not None: - log.info("--nowarn-register 已启用:抑制注册类 WARN 输出", "vlogger") - - # 加载 project.vpj 配置 - proj_loaded: int = 0 - proj_path: str = project - if proj_path is not None: - if log is not None: - log.banner("工程配置") - cfg_ret: int = Config.Load_project_config(proj_path) - if cfg_ret == 0: - proj_loaded = 1 - else: - if log is not None: - warn_buf: str = stdlib.malloc(256) - if warn_buf is not None: - viperlib.snprintf(warn_buf, 256, "无法加载 project.vpj: %s", proj_path) - log.warning(warn_buf, "config") - stdlib.free(warn_buf) - else: - # 尝试默认路径 project.vpj(当前目录和上级目录) - proj_path = "project.vpj" - if Config.Load_project_config(proj_path) == 0: - proj_loaded = 1 - else: - proj_path = "../project.vpj" - if Config.Load_project_config(proj_path) == 0: - proj_loaded = 1 - if proj_loaded == 1: - # 提取 project.vpj 所在目录,将相对路径解析为基于该目录的路径 - proj_len: t.CSizeT = string.strlen(proj_path) - slash_pos: t.CSizeT = proj_len - for i in range(proj_len): - idx: t.CSizeT = proj_len - 1 - i - ch: t.CChar = proj_path[idx] - if ch == '/' or ch == '\\': - slash_pos = idx - break - proj_dir: str = "" - if slash_pos > 0 and slash_pos < proj_len: - proj_dir = stdlib.malloc(slash_pos + 1) - if proj_dir is not None: - string.memcpy(proj_dir, proj_path, slash_pos) - proj_dir[slash_pos] = '\0' - Config.resolve_paths(proj_dir) - Config.print_config() - - # === --clean: 清理 temp、output 和 includes.binary 目录 === - if _gb_clean: - if log is not None: - log.info("清理临时目录...", "clean") - if Config.TempDir is not None: - n: int = Utils.CleanDir(Config.TempDir) - if log is not None: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "%s: 删除 %d 个文件", Config.TempDir, n) - log.info(fb, "clean") - if Config.OutputDir is not None: - n2: int = Utils.CleanDir(Config.OutputDir) - if log is not None: - fb2: str = VLogger.fmt_buf() - if fb2 is not None: - viperlib.snprintf(fb2, 1024, "%s: 删除 %d 个文件", Config.OutputDir, n2) - log.info(fb2, "clean") - # 清理 includes.binary 目录(旧 .obj 文件会导致跳过重新编译) - mf_inc_bin_clean: str = Config.get_includes_binary_dir() - if mf_inc_bin_clean is not None: - n3: int = Utils.CleanDir(mf_inc_bin_clean) - if log is not None: - fb3: str = VLogger.fmt_buf() - if fb3 is not None: - viperlib.snprintf(fb3, 1024, "%s: 删除 %d 个文件", mf_inc_bin_clean, n3) - log.info(fb3, "clean") - - # === --rebuild-includes: 删除 includes.binary 预编译缓存 === - # 强制下次编译时重新编译所有 includes(不清 temp/output) - if args.get_bool("rebuild-includes"): - if log is not None: - log.info("重建 includes 缓存...", "rebuild-includes") - mf_inc_bin_rb: str = Config.get_includes_binary_dir() - if mf_inc_bin_rb is not None: - n_rb: int = Utils.CleanDir(mf_inc_bin_rb) - if log is not None: - fb_rb: str = VLogger.fmt_buf() - if fb_rb is not None: - viperlib.snprintf(fb_rb, 1024, "%s: 删除 %d 个文件(includes 将重新编译)", mf_inc_bin_rb, n_rb) - log.info(fb_rb, "rebuild-includes") - - # === --clear-cache: 清除 temp 目录缓存(.vpi/.stub.ll/.text.ll) === - # 强制下次 Phase1 重新生成 stub(不清 output/includes.binary) - if args.get_bool("clear-cache"): - if log is not None: - log.info("清除 temp 缓存...", "clear-cache") - if Config.TempDir is not None: - n_cc: int = Utils.CleanDir(Config.TempDir) - if log is not None: - fb_cc: str = VLogger.fmt_buf() - if fb_cc is not None: - viperlib.snprintf(fb_cc, 1024, "%s: 删除 %d 个文件(.vpi/.stub.ll 缓存)", Config.TempDir, n_cc) - log.info(fb_cc, "clear-cache") - - # === --phase 参数控制 === - # phase=1: 仅 stub 分离(生成 .stub.ll/.text.ll),不编译 - # phase=2: 仅 stub 合并 + 编译(跳过 stub 分离) - # phase=all: 两者都执行(默认) - phase_mode: str = phase - if phase_mode is None: - phase_mode = "all" - do_phase1: int = 0 - do_phase2: int = 0 - # 注意: 使用 string.strcmp 而非 ==,避免编译器 == 语义 bug - if string.strcmp(phase_mode, "1") == 0 or string.strcmp(phase_mode, "all") == 0: - do_phase1 = 1 - if string.strcmp(phase_mode, "2") == 0 or string.strcmp(phase_mode, "all") == 0: - do_phase2 = 1 - if log is not None: - fb3: str = VLogger.fmt_buf() - if fb3 is not None: - viperlib.snprintf(fb3, 1024, "模式: %s (phase1=%d phase2=%d)", phase_mode, do_phase1, do_phase2) - log.info(fb3, "phase") - - # === Phase1: 扫描 includes(按需翻译)=== - # 对 includes 目录中每个 .vp/.py 文件,若 stub 不存在则翻译并分离 stub - if do_phase1 != 0 and Config.IncludesDirs is not None: - ph1_temp: str = Config.TempDir - if ph1_temp is None: - ph1_temp = "." - if Phase1Main.RunPhase1(mb, Config.IncludesDirs, ph1_temp, log) != 0: - VLogger.error("Phase1 失败,终止编译", "Phase1") - return 1 - # 如果仅 Phase1(不执行 Phase2),直接退出 - if do_phase2 == 0: - if log is not None: - log.info("Phase1 完成,退出", "phase") - return 0 - - # AST 解析:如果指定了 --src 或 --project,读取文件并解析为 AST 树 - src_path: str = args.get_str("src") - - # 无 project 配置且未指定 --src:无法构建,fail-fast 退出。 - # (非工作区执行时 CWD 无 project.vpj,proj_loaded=0;若继续执行, - # 未初始化的 Config 字段可能为垃圾指针 → is not None 检查通过 → - # 用非法路径 → 崩溃且 ASan 堆栈来不及输出) - if proj_loaded == 0 and src_path is None: - if log is not None: - log.error("未找到 project.vpj(当前目录/上级目录)且未指定 --src,无法构建", "config") - argparse.release(args) - return 1 - - # === 多文件项目模式 === - # 当 --project 指定但 --src 未指定时,扫描 source_dir 下所有 .vp/.py 文件编译 - if src_path is None and project is not None and Config.SourceDir is not None: - mf_temp: str = Config.TempDir if Config.TempDir is not None else "." - mf_output: str = Config.OutputDir if Config.OutputDir is not None else "." - mf_cc: str = Config.CompilerCmd if Config.CompilerCmd is not None else "llc" - mf_cc_flags: str = Config.CompilerFlags if Config.CompilerFlags is not None else "-filetype=obj -relocation-model=pic" - mf_linker: str = Config.LinkerCmd if Config.LinkerCmd is not None else "clang++" - mf_linker_flags: str = Config.LinkerFlags if Config.LinkerFlags is not None else "-lmsvcrt -lucrt -lpthread -lmingwex -lkernel32 -lgcc -Wl,--allow-multiple-definition" - mf_linker_out: str = Config.LinkerOutput if Config.LinkerOutput is not None else "app.exe" - mf_includes_bin: str = Config.get_includes_binary_dir() - - mf_ret: int = Phase2.RunMultiFileProject( - mb, Config.SourceDir, mf_temp, mf_output, - mf_cc, mf_cc_flags, mf_linker, mf_linker_flags, mf_linker_out, - mf_includes_bin, Config.IncludesDirs, do_phase1, do_phase2, log, args) - argparse.release(args) - if log is not None: - log.success("TransPyV 完成") - return mf_ret - - # === 单文件模式:--src 指定时使用指定文件;--project 但无 SourceDir 时回退 === - if src_path is None and project is not None: - if Config.SourceDir is not None: - # 构造入口路径: 优先 SourceDir/main.vp,回退 SourceDir/main.py - sd_len: t.CSizeT = string.strlen(Config.SourceDir) - path_buf: bytes = stdlib.malloc(sd_len + 16) - if path_buf is not None: - # 优先尝试 main.vp - viperlib.snprintf(path_buf, sd_len + 16, "%s/main.vp", Config.SourceDir) - ef: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R) - if ef.closed: - # .vp 不存在,回退 main.py - viperlib.snprintf(path_buf, sd_len + 16, "%s/main.py", Config.SourceDir) - else: - ef.close() - src_path = path_buf - if log is not None: - fb4: str = VLogger.fmt_buf() - if fb4 is not None: - viperlib.snprintf(fb4, 1024, "入口文件: %s", src_path) - log.info(fb4, "project") - if src_path is not None: - if log is not None: - log.banner("AST 解析") - # 打开文件 - f: fileio.File | t.CPtr = fileio.File(src_path, fileio.MODE.R) - if f.closed: - if log is not None: - fb5: str = VLogger.fmt_buf() - if fb5 is not None: - viperlib.snprintf(fb5, 1024, "无法打开文件: %s", src_path) - log.error(fb5, "fileio") - argparse.release(args) - return 1 - # 分配源代码缓冲区 - src_buf: bytes = stdlib.malloc(SRC_BUF_SIZE) - if src_buf is None: - if log is not None: - log.error("malloc for src_buf failed", "memhub") - f.close() - argparse.release(args) - return 1 - # 读取文件内容 - bytes_read: LONG = f.read_all(src_buf, SRC_BUF_SIZE) - f.close() - if bytes_read < 0: - if log is not None: - fb6: str = VLogger.fmt_buf() - if fb6 is not None: - viperlib.snprintf(fb6, 1024, "读取文件失败 (错误码: %d)", bytes_read) - log.error(fb6, "fileio") - argparse.release(args) - return 1 - # 添加 null 终止符,确保 strlen 和 SHA1 计算正确 - if bytes_read < SRC_BUF_SIZE: - src_buf[bytes_read] = 0 - else: - src_buf[SRC_BUF_SIZE - 1] = 0 - if log is not None: - log.info("文件读取完成", "fileio") - fb7: str = VLogger.fmt_buf() - if fb7 is not None: - viperlib.snprintf(fb7, 1024, "读取 %d 字节", bytes_read) - log.info(fb7, "fileio") - # 解析 AST(拆分为词法+语法两阶段,便于调试) - ast._init_tables(mb) - lx: ast.Lexer | t.CPtr = ast.new_lexer(mb) - ast._lexer_init(lx, src_buf, mb) - tokens: ast.Token | t.CPtr = ast.tokenize(lx) - tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens) - if tree is None: - if log is not None: - log.error("AST 解析失败", "ast") - argparse.release(args) - return 1 - - # === 翻译 AST → LLVM IR === - if log is not None: - log.banner("LLVM IR 翻译") - tr: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator() - result: int = tr.translate(tree) - if result == 0: - IR_BUF_SIZE: t.CSizeT = 262144 - ir_buf: bytes = stdlib.malloc(IR_BUF_SIZE) - if ir_buf is not None: - tr.dump_ir(ir_buf, IR_BUF_SIZE, llvmlite.OUTPUT_FULL) - - # === 编译管线: .ll → .obj → .exe === - if log is not None: - log.banner("编译管线") - - # module_name 用源代码内容的 SHA1(前 16 字符),与 Projectrans.py 一致 - # output_name 从文件名推导(如 test.vp -> test.exe),保持可读性 - module_name: str = Utils.compute_sha1(mb, src_buf) - if module_name is None: - VLogger.error("SHA1 计算失败", "main") - output_name: str = "test_prog.exe" - # 从文件名提取 output_name(去掉路径和 .vp/.py 扩展名) - src_len: t.CSizeT = string.strlen(src_path) - if src_len > 0: - # 找到最后一个 / 或 \ 之后的部分 - base_start: t.CSizeT = src_len - i: t.CSizeT = src_len - while i > 0: - i -= 1 - ch: t.CChar = src_path[i] - if ch == '/' or ch == '\\': - base_start = i + 1 - break - if i == 0: - base_start = 0 - # 找到 .vp/.py 扩展名 - base_end: t.CSizeT = src_len - j: t.CSizeT = base_start - while j < src_len: - if src_path[j] == '.': - base_end = j - break - j += 1 - # 输出名 = 文件名 + ".exe" - name_len: t.CSizeT = base_end - base_start - if name_len > 0: - out_len: t.CSizeT = name_len + 5 - output_name = stdlib.malloc(out_len) - if output_name is not None: - # 手动复制文件名并追加 .exe(viperlib.snprintf 不支持 %.*s,string 无 strcat) - string.strncpy(output_name, src_path + base_start, name_len) - output_name[name_len] = '.' - output_name[name_len + 1] = 'e' - output_name[name_len + 2] = 'x' - output_name[name_len + 3] = 'e' - output_name[name_len + 4] = '\0' - # 使用 project.vpj 中的配置 - temp_dir: str = Config.TempDir if Config.TempDir is not None else "." - output_dir: str = Config.OutputDir if Config.OutputDir is not None else "." - # 设置全局 temp_dir(供跨模块 CDefine 查找使用) - HandlesType.set_temp_dir(temp_dir) - cc_cmd: str = Config.CompilerCmd if Config.CompilerCmd is not None else "llc" - cc_flags: str = "-filetype=obj -relocation-model=pic" - linker_cmd: str = Config.LinkerCmd if Config.LinkerCmd is not None else "clang++" - linker_flags: str = "-lmsvcrt -lucrt -lpthread -lmingwex -lkernel32 -lgcc -Wl,--allow-multiple-definition" - # --project 模式且未显式指定 --src 时:使用 config 中的 linker_output(如 TransPyV.exe) - # 显式指定 --src 时:使用从文件名推导的 output_name(如 test.exe),避免覆盖正在运行的 exe - if project is not None and Config.LinkerOutput is not None and args.get_str("src") is None: - linker_output: str = Config.LinkerOutput - else: - linker_output: str = output_name - - # 计算 includes.binary 目录路径(链接时附加预编译 .obj) - includes_binary_dir: str = Config.get_includes_binary_dir() - - ir_len: t.CSizeT = string.strlen(ir_buf) - - # (--phase 参数已在配置加载后处理,此处直接使用 do_phase1/do_phase2) - - # === Phase1 stub 分离:使用 OUTPUT_STUB/TEXT 模式分别生成 stub.ll 和 text.ll === - if do_phase1 != 0 and temp_dir is not None and module_name is not None: - if log is not None: - log.banner("stub 分离") - SF_IR_SIZE: t.CSizeT = 262144 - td_len_sf: t.CSizeT = string.strlen(temp_dir) - # 保存 stub.ll - sf_stub_buf: bytes = stdlib.malloc(SF_IR_SIZE) - if sf_stub_buf is not None: - tr.dump_ir(sf_stub_buf, SF_IR_SIZE, llvmlite.OUTPUT_STUB) - sf_stub_len: t.CSizeT = string.strlen(sf_stub_buf) - sf_stub_path: str = StubMergerCollect._sliced_path(temp_dir, td_len_sf, module_name, "stub.ll") - if sf_stub_path is not None: - sf_f: fileio.File | t.CPtr = fileio.File(sf_stub_path, fileio.MODE.W) - if not sf_f.closed: - sf_f.write(sf_stub_buf, sf_stub_len) - sf_f.close() - stdlib.free(sf_stub_path) - stdlib.free(sf_stub_buf) - # 保存 text.ll - sf_text_buf: bytes = stdlib.malloc(SF_IR_SIZE) - if sf_text_buf is not None: - tr.dump_ir(sf_text_buf, SF_IR_SIZE, llvmlite.OUTPUT_TEXT) - sf_text_len: t.CSizeT = string.strlen(sf_text_buf) - sf_text_path: str = StubMergerCollect._sliced_path(temp_dir, td_len_sf, module_name, "text.ll") - if sf_text_path is not None: - sf_tf: fileio.File | t.CPtr = fileio.File(sf_text_path, fileio.MODE.W) - if not sf_tf.closed: - sf_tf.write(sf_text_buf, sf_text_len) - sf_tf.close() - stdlib.free(sf_text_path) - stdlib.free(sf_text_buf) - - # phase=1 模式:仅生成 stub,不执行编译 - if do_phase2 == 0: - if log is not None: - log.success("Phase1 完成(仅 stub 分离,跳过编译)") - argparse.release(args) - return 0 - - # === Phase2: 组合本地 stub + 依赖 stubs + 本地 text → 完整 IR === - final_ir: bytes = ir_buf - final_ir_len: t.CSizeT = ir_len - if temp_dir is not None and module_name is not None: - if log is not None: - log.banner("IR 组合") - SF_COMBINED_SIZE: t.CSizeT = 4194304 # 4MB - combined_buf: bytes = stdlib.malloc(SF_COMBINED_SIZE) - if combined_buf is not None: - combined_len: t.CSizeT = StubMergerBuild.BuildCombinedIR(temp_dir, module_name, combined_buf, SF_COMBINED_SIZE) - if combined_len > 0: - final_ir = combined_buf - final_ir_len = combined_len - else: - stdlib.free(combined_buf) - VLogger.error("BuildCombinedIR 失败,终止编译", "stub") - - br: BuildPipeline.BuildResult | t.CPtr = BuildPipeline.run_pipeline( - final_ir, final_ir_len, temp_dir, output_dir, module_name, - cc_cmd, cc_flags, linker_cmd, linker_flags, linker_output, - includes_binary_dir - ) - if br is not None and br.Success == 1: - if log is not None: - log.success("编译管线完成") - fb8: str = VLogger.fmt_buf() - if fb8 is not None: - viperlib.snprintf(fb8, 1024, "输出: %s/%s", output_dir, linker_output) - log.info(fb8) - # --run 模式:执行生成的可执行文件 - if args.get_bool("run"): - exe_path: bytes = stdlib.malloc(string.strlen(output_dir) + string.strlen(linker_output) + 2) - if exe_path is not None: - viperlib.snprintf(exe_path, 256, "%s/%s", output_dir, linker_output) - if log is not None: - fb9: str = VLogger.fmt_buf() - if fb9 is not None: - viperlib.snprintf(fb9, 1024, "执行: %s", exe_path) - log.info(fb9, "run") - r: subprocess.CompletedProcess | t.CPtr = subprocess.run(exe_path, False, False) - if r is not None: - if log is not None: - fb10: str = VLogger.fmt_buf() - if fb10 is not None: - viperlib.snprintf(fb10, 1024, "退出码: %d", r.returncode) - log.info(fb10, "run") - else: - if log is not None: - log.error("编译管线失败", "pipeline") - if br is not None and br.ErrorMsg is not None: - fb11: str = VLogger.fmt_buf() - if fb11 is not None: - viperlib.snprintf(fb11, 1024, "编译管线失败: %s", br.ErrorMsg) - log.error(fb11, "FATAL") - sys.exit(1) - else: - if log is not None: - log.error("malloc for IR buffer failed", "memhub") - else: - if log is not None: - log.error("翻译失败", "translator") - - argparse.release(args) - if log is not None: - log.success("TransPyV 完成") - return 0 +import lib.core.Gen.GenApi as GenApi +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HandlesTranslator +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.BuildPipeline as BuildPipeline +import lib.core.IncludesScanner as IncludesScanner +import lib.core.StubMerger as StubMerger +import lib.core.Phase1 as Phase1 +import lib.core.Phase2 as Phase2 +import lib.core.CompilerFactory as CompilerFactory +import lib.core.Gen.Generator as GenGenerator +import lib.Projectrans.Config as Config +import lib.Projectrans.Utils as Utils +import lib +from stdint import * +import stdio +import string +import stdlib +import memhub +import argparse +import w32.win32console as w32cmd +import w32.fileio as fileio +import w32.win32file +import w32.win32base +import sys +import ast +import llvmlite +import subprocess +import viperlib +import hashlib +import t, c +import lib.core.StubMergerBuild as StubMergerBuild +import lib.core.StubMergerCollect as StubMergerCollect +import lib.core.Phase1Main as Phase1Main + + +# Main Pool 1 GiB +POOL_SIZE: t.CDefine = 1073741824 +# Permanent memory pool size: 2^29 + 264 = 512MB usable +PERM_POOL_SIZE: t.CDefine = 536871176 +# Code page: UTF-8 (Windows 65001) +CODE_PAGE: t.CDefine = 65001 +# Source code buffer size (1MB) +SRC_BUF_SIZE: t.CDefine = 1048576 +# Version (dev/beta/rc) +V_VIPER_VERSION: t.CDefine = "1.0.3-dev.29 2026-07-27 Non-LTS" +V_TPV_VERSION: t.CDefine = "0.0.2-dev.173" +V_RUNTIME_VERSION: t.CDefine = "0.2.2+3-Non-LTS" +V_TERMINEXUS_AGE: t.CDefine = "15.3" +V_TPC_COMMIT: t.CDefine = "a641c7c8da/2026‑08‑17T02:49:00Z" +V_TPV_COMMIT: t.CDefine = "" +V_RUNTIME_COMMIT: t.CDefine = "14ff9d109f/2026-08-17T03:02:20Z" +V_TARGET: t.CDefine = "x86_64-w64-windows-gnu" +V_LLVM: t.CDefine = "22.1.8" + +# ============================================================ +# main: Command-line entry +# ============================================================ +def main() -> int: + w32cmd.SetConsoleOutputCP(CODE_PAGE) + w32cmd.SetConsoleCP(CODE_PAGE) + + # Initialize the mbuddy memory pool + arena: bytes = stdlib.malloc(POOL_SIZE) + if arena is None: + stdio.printf("FAIL: malloc for arena failed\n") + return 1 + # Create a global permanent memory pool (perm_pool, 512MB) + perm_arena: bytes = stdlib.malloc(PERM_POOL_SIZE) + if perm_arena is None: + stdio.printf("FAIL: malloc for perm_pool arena failed\n") + return 1 + + mb: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, POOL_SIZE) + if mb is None: + stdio.printf("FAIL: MemBuddy init failed\n") + return 1 + + perm_pool: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(perm_arena, PERM_POOL_SIZE) + if perm_pool is None: + stdio.printf("FAIL: perm_pool init failed\n") + return 1 + + CompilerFactory.set_factory(CompilerFactory.CompilerFactory(mb, perm_pool)) + + # 设置全局 mbuddy 指针(sys 和 argparse 都需要) + sys._mbuddy = mb + argparse._mbuddy = mb + ast._mbuddy = mb + lib._mbuddy = mb + Config._mbuddy = mb + Utils._mbuddy = mb + HandlesTranslator._mbuddy = mb + BuildPipeline._mbuddy = mb + IncludesScanner._mbuddy = mb + StubMerger._mbuddy = mb + Phase1._mbuddy = mb + Phase2._mbuddy = mb + subprocess._mbuddy = mb + # hashlib._mbuddy = (mb) + VLogger._mbuddy = mb + lib.InitLib(mb) + + # P2: 创建项目级 Generator 单例(Phase1/Phase2/BuildPipeline 全程复用; + # HandlesType 等旧模块函数经延迟 import 委托到 gen 方法,实现对象化过渡) + gen: GenGenerator.Generator | t.CPtr = mb.alloc(GenGenerator.Generator.__sizeof__()) + if gen is None: + stdio.printf("FAIL: Generator alloc failed\n") + return 1 + gen.__before_init__() + gen.__init__(mb) + + GenGenerator._g_gen = gen + # P2-P5: 注入各 Handles 模块级单例(Phase1 阶段即调用其状态函数) + GenApi._g_gen = gen + # P6: 注入语句/赋值/变量/导入/翻译驱动模块的单例 + + # 初始化 VLogger 并打印启动日志 + log: VLogger.Logger | t.CPtr = VLogger.get_logger() + if log is None: + log.error("TransPyV Failed to parse parameters") + + # 初始化命令行参数(Windows: GetCommandLineA, POSIX: /proc/self/cmdline) + sys._init_argv() + + # 创建参数解析器 + parser: argparse.ArgumentParser | t.CPtr = argparse.ArgumentParser("TransPyV", "TransPyV command-line parameter parser", pool=mb) + + # 注册参数(与 Projectrans.py main() 一致) + parser.add_argument("--project", None, argparse.STRING, 0, None, False, argparse.STORE, "Project VPJ path, by default it looks in the current directory") + parser.add_argument("--src", None, argparse.STRING, 0, None, False, argparse.STORE, "Source directory") + parser.add_argument("--temp", None, argparse.STRING, 0, None, False, argparse.STORE, "Declare a temporary directory for the interface") + parser.add_argument("--output", None, argparse.STRING, 0, None, False, argparse.STORE, "Output directory") + parser.add_argument("--phase", None, argparse.STRING, 0, None, False, argparse.STORE, "Phase: 1 = Generate statement, 2 = Translate and compile, all = Everything") + parser.add_argument("--cc", None, argparse.STRING, 0, None, False, argparse.STORE, "LLVM compiler command") + parser.add_argument("--clean", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Clean output and temp directories") + parser.add_argument("--run", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Run the generated executable after compilation") + parser.add_argument("--rebuild-includes", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Delete the includes.binary precompiled cache and rebuild all the includes") + parser.add_argument("--clear-cache", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Clear .transpyc_cache global cache") + parser.add_argument("--asan", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "ASan mode: .ll first opt -passes=asan then link -fsanitize=address") + parser.add_argument("--nowarn-register", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Suppress Phase A dependency WARN") + parser.add_argument("--version", "-v", argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Show version and exit") + parser.add_argument("--help", "-h", argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Show help and exit") + + # 解析命令行参数 + args: argparse.ParsedArgs | t.CPtr = parser.parse_args(sys._argc, sys._argv) + if args is None: + if log is not None: + log.error("参数解析失败", "argparse") + return 1 + + if args.get_bool("help"): + parser.print_help() + return 0 + + if args.get_bool("version"): + stdio.printf("""Viper %s +Copyright (C) 2026 Viper Project +License MIT +GVSDS(TM) Viper SE Runtime Environment and Library (VRTE) %s +Viper Frontend Compiler TransPyV %s +TermiNexus Age %sY + +Tpv commit: %s +Tpc commit: %s +VRTE commit: %s +Target: %s + +""", V_VIPER_VERSION, V_RUNTIME_VERSION, V_TPV_VERSION, V_TERMINEXUS_AGE, V_TPV_COMMIT, V_TPC_COMMIT, V_RUNTIME_COMMIT, V_TARGET, V_LLVM) + return 0 + + # 打印解析结果 + #if log is not None: + # log.banner("TransPyV 参数解析结果") + + # 字符串参数 + project: str = args.get_str("project") + #if project is not None: stdio.printf(" --project: %s\n", project) + #else: stdio.printf(" --project: (未指定)\n") + + src: str = args.get_str("src") + #if src is not None: stdio.printf(" --src: %s\n", src) + #else: stdio.printf(" --src: (未指定)\n") + + temp: str = args.get_str("temp") + #if temp is not None: stdio.printf(" --temp: %s\n", temp) + #else: stdio.printf(" --temp: (未指定)\n") + + output: str = args.get_str("output") + #if output is not None: stdio.printf(" --output: %s\n", output) + #else: stdio.printf(" --output: (未指定)\n") + + phase: str = args.get_str("phase") + #if phase is not None: stdio.printf(" --phase: %s\n", phase) + #else: stdio.printf(" --phase: (未指定,默认 all)\n") + + cc: str = args.get_str("cc") + #if cc is not None: stdio.printf(" --cc: %s\n", cc) + #else: stdio.printf(" --cc: (未指定)\n") + + # 布尔参数 + _gb_clean: INT = args.get_bool("clean") + #if _gb_clean: stdio.printf(" --clean: True\n") + #else: stdio.printf(" --clean: False\n") + + #if args.get_bool("run"): stdio.printf(" --run: True\n") + #else: stdio.printf(" --run: False\n") + + #if args.get_bool("rebuild-includes"): stdio.printf(" --rebuild-includes: True\n") + #else: stdio.printf(" --rebuild-includes: False\n") + + #if args.get_bool("clear-cache"): stdio.printf(" --clear-cache: True\n") + #else: stdio.printf(" --clear-cache: False\n") + + #stdio.printf("\n参数解析完成。\n") + + # ASan 模式:设置 BuildPipeline 全局标志(compile_ll_to_obj 先 opt 插桩,链接 asan 库) + # includes 缓存用独立目录 .binary_asan 隔离 asan 插桩 obj,避免与非 asan obj 混链 + # (asan obj 引用 __asan_init 等符号,非 asan 链接不提供 asan 库 → undefined reference) + if args.get_bool("asan"): + BuildPipeline._asan_mode = True + Config.set_inc_bin_suffix(".binary_asan") + if log is not None: + log.info("ASan 模式已启用(opt -passes=asan + libclang_rt)", "asan") + # ASan 模式清理 asan includes 缓存(强制重建 asan 插桩 obj) + mf_inc_bin_asan: str = Config.get_includes_binary_dir() + if mf_inc_bin_asan is not None: + n_asan: int = Utils.CleanDir(mf_inc_bin_asan) + if log is not None: + fb_asan: str = VLogger.fmt_buf() + if fb_asan is not None: + viperlib.snprintf(fb_asan, 1024, "ASan 模式清理 includes 缓存: %d 个文件(将重建 asan obj)", n_asan) + log.info(fb_asan, "asan") + else: + BuildPipeline._asan_mode = False + Config.set_inc_bin_suffix(".binary") + + # --nowarn-register:抑制"外部函数返回类型未登记"类 WARN 输出 + if args.get_bool("nowarn-register"): + VLogger.set_nowarn_register(1) + if log is not None: + log.info("--nowarn-register 已启用:抑制注册类 WARN 输出", "vlogger") + + # 加载 project.vpj 配置 + proj_loaded: int = 0 + proj_path: str = project + if proj_path is not None: + if log is not None: + log.banner("工程配置") + cfg_ret: int = Config.Load_project_config(proj_path) + if cfg_ret == 0: + proj_loaded = 1 + else: + if log is not None: + warn_buf: str = stdlib.malloc(256) + if warn_buf is not None: + viperlib.snprintf(warn_buf, 256, "无法加载 project.vpj: %s", proj_path) + log.warning(warn_buf, "config") + stdlib.free(warn_buf) + else: + # 尝试默认路径 project.vpj(当前目录和上级目录) + proj_path = "project.vpj" + if Config.Load_project_config(proj_path) == 0: + proj_loaded = 1 + else: + proj_path = "../project.vpj" + if Config.Load_project_config(proj_path) == 0: + proj_loaded = 1 + if proj_loaded == 1: + # 提取 project.vpj 所在目录,将相对路径解析为基于该目录的路径 + proj_len: t.CSizeT = string.strlen(proj_path) + slash_pos: t.CSizeT = proj_len + for i in range(proj_len): + idx: t.CSizeT = proj_len - 1 - i + ch: t.CChar = proj_path[idx] + if ch == '/' or ch == '\\': + slash_pos = idx + break + proj_dir: str = "" + if slash_pos > 0 and slash_pos < proj_len: + proj_dir = stdlib.malloc(slash_pos + 1) + if proj_dir is not None: + string.memcpy(proj_dir, proj_path, slash_pos) + proj_dir[slash_pos] = '\0' + Config.resolve_paths(proj_dir) + Config.print_config() + + # === --clean: 清理 temp、output 和 includes.binary 目录 === + if _gb_clean: + if log is not None: + log.info("清理临时目录...", "clean") + if Config.TempDir is not None: + n: int = Utils.CleanDir(Config.TempDir) + if log is not None: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "%s: 删除 %d 个文件", Config.TempDir, n) + log.info(fb, "clean") + if Config.OutputDir is not None: + n2: int = Utils.CleanDir(Config.OutputDir) + if log is not None: + fb2: str = VLogger.fmt_buf() + if fb2 is not None: + viperlib.snprintf(fb2, 1024, "%s: 删除 %d 个文件", Config.OutputDir, n2) + log.info(fb2, "clean") + # 清理 includes.binary 目录(旧 .obj 文件会导致跳过重新编译) + mf_inc_bin_clean: str = Config.get_includes_binary_dir() + if mf_inc_bin_clean is not None: + n3: int = Utils.CleanDir(mf_inc_bin_clean) + if log is not None: + fb3: str = VLogger.fmt_buf() + if fb3 is not None: + viperlib.snprintf(fb3, 1024, "%s: 删除 %d 个文件", mf_inc_bin_clean, n3) + log.info(fb3, "clean") + + # === --rebuild-includes: 删除 includes.binary 预编译缓存 === + # 强制下次编译时重新编译所有 includes(不清 temp/output) + if args.get_bool("rebuild-includes"): + if log is not None: + log.info("重建 includes 缓存...", "rebuild-includes") + mf_inc_bin_rb: str = Config.get_includes_binary_dir() + if mf_inc_bin_rb is not None: + n_rb: int = Utils.CleanDir(mf_inc_bin_rb) + if log is not None: + fb_rb: str = VLogger.fmt_buf() + if fb_rb is not None: + viperlib.snprintf(fb_rb, 1024, "%s: 删除 %d 个文件(includes 将重新编译)", mf_inc_bin_rb, n_rb) + log.info(fb_rb, "rebuild-includes") + + # === --clear-cache: 清除 temp 目录缓存(.vpi/.stub.ll/.text.ll) === + # 强制下次 Phase1 重新生成 stub(不清 output/includes.binary) + if args.get_bool("clear-cache"): + if log is not None: + log.info("清除 temp 缓存...", "clear-cache") + if Config.TempDir is not None: + n_cc: int = Utils.CleanDir(Config.TempDir) + if log is not None: + fb_cc: str = VLogger.fmt_buf() + if fb_cc is not None: + viperlib.snprintf(fb_cc, 1024, "%s: 删除 %d 个文件(.vpi/.stub.ll 缓存)", Config.TempDir, n_cc) + log.info(fb_cc, "clear-cache") + + # === --phase 参数控制 === + # phase=1: 仅 stub 分离(生成 .stub.ll/.text.ll),不编译 + # phase=2: 仅 stub 合并 + 编译(跳过 stub 分离) + # phase=all: 两者都执行(默认) + phase_mode: str = phase + if phase_mode is None: + phase_mode = "all" + do_phase1: int = 0 + do_phase2: int = 0 + # 注意: 使用 string.strcmp 而非 ==,避免编译器 == 语义 bug + if string.strcmp(phase_mode, "1") == 0 or string.strcmp(phase_mode, "all") == 0: + do_phase1 = 1 + if string.strcmp(phase_mode, "2") == 0 or string.strcmp(phase_mode, "all") == 0: + do_phase2 = 1 + if log is not None: + fb3: str = VLogger.fmt_buf() + if fb3 is not None: + viperlib.snprintf(fb3, 1024, "模式: %s (phase1=%d phase2=%d)", phase_mode, do_phase1, do_phase2) + log.info(fb3, "phase") + + # === Phase1: 扫描 includes(按需翻译)=== + # 对 includes 目录中每个 .vp/.py 文件,若 stub 不存在则翻译并分离 stub + if do_phase1 != 0 and Config.IncludesDirs is not None: + ph1_temp: str = Config.TempDir + if ph1_temp is None: + ph1_temp = "." + if Phase1Main.RunPhase1(mb, Config.IncludesDirs, ph1_temp, log) != 0: + VLogger.error("Phase1 失败,终止编译", "Phase1") + return 1 + # 如果仅 Phase1(不执行 Phase2),直接退出 + if do_phase2 == 0: + if log is not None: + log.info("Phase1 完成,退出", "phase") + return 0 + + # AST 解析:如果指定了 --src 或 --project,读取文件并解析为 AST 树 + src_path: str = args.get_str("src") + + # 无 project 配置且未指定 --src:无法构建,fail-fast 退出。 + # (非工作区执行时 CWD 无 project.vpj,proj_loaded=0;若继续执行, + # 未初始化的 Config 字段可能为垃圾指针 → is not None 检查通过 → + # 用非法路径 → 崩溃且 ASan 堆栈来不及输出) + if proj_loaded == 0 and src_path is None: + if log is not None: + log.error("未找到 project.vpj(当前目录/上级目录)且未指定 --src,无法构建", "config") + argparse.release(args) + return 1 + + # === 多文件项目模式 === + # 当 --project 指定但 --src 未指定时,扫描 source_dir 下所有 .vp/.py 文件编译 + if src_path is None and project is not None and Config.SourceDir is not None: + mf_temp: str = Config.TempDir if Config.TempDir is not None else "." + mf_output: str = Config.OutputDir if Config.OutputDir is not None else "." + mf_cc: str = Config.CompilerCmd if Config.CompilerCmd is not None else "llc" + mf_cc_flags: str = Config.CompilerFlags if Config.CompilerFlags is not None else "-filetype=obj -relocation-model=pic" + mf_linker: str = Config.LinkerCmd if Config.LinkerCmd is not None else "clang++" + mf_linker_flags: str = Config.LinkerFlags if Config.LinkerFlags is not None else "-lmsvcrt -lucrt -lpthread -lmingwex -lkernel32 -lgcc -Wl,--allow-multiple-definition" + mf_linker_out: str = Config.LinkerOutput if Config.LinkerOutput is not None else "app.exe" + mf_includes_bin: str = Config.get_includes_binary_dir() + + mf_ret: int = Phase2.RunMultiFileProject( + mb, Config.SourceDir, mf_temp, mf_output, + mf_cc, mf_cc_flags, mf_linker, mf_linker_flags, mf_linker_out, + mf_includes_bin, Config.IncludesDirs, do_phase1, do_phase2, log, args) + argparse.release(args) + if log is not None: + log.success("TransPyV 完成") + return mf_ret + + # === 单文件模式:--src 指定时使用指定文件;--project 但无 SourceDir 时回退 === + if src_path is None and project is not None: + if Config.SourceDir is not None: + # 构造入口路径: 优先 SourceDir/main.vp,回退 SourceDir/main.py + sd_len: t.CSizeT = string.strlen(Config.SourceDir) + path_buf: bytes = stdlib.malloc(sd_len + 16) + if path_buf is not None: + # 优先尝试 main.vp + viperlib.snprintf(path_buf, sd_len + 16, "%s/main.vp", Config.SourceDir) + ef: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R) + if ef.closed: + # .vp 不存在,回退 main.py + viperlib.snprintf(path_buf, sd_len + 16, "%s/main.py", Config.SourceDir) + else: + ef.close() + src_path = path_buf + if log is not None: + fb4: str = VLogger.fmt_buf() + if fb4 is not None: + viperlib.snprintf(fb4, 1024, "入口文件: %s", src_path) + log.info(fb4, "project") + if src_path is not None: + if log is not None: + log.banner("AST 解析") + # 打开文件 + f: fileio.File | t.CPtr = fileio.File(src_path, fileio.MODE.R) + if f.closed: + if log is not None: + fb5: str = VLogger.fmt_buf() + if fb5 is not None: + viperlib.snprintf(fb5, 1024, "无法打开文件: %s", src_path) + log.error(fb5, "fileio") + argparse.release(args) + return 1 + # 分配源代码缓冲区 + src_buf: bytes = stdlib.malloc(SRC_BUF_SIZE) + if src_buf is None: + if log is not None: + log.error("malloc for src_buf failed", "memhub") + f.close() + argparse.release(args) + return 1 + # 读取文件内容 + bytes_read: LONG = f.read_all(src_buf, SRC_BUF_SIZE) + f.close() + if bytes_read < 0: + if log is not None: + fb6: str = VLogger.fmt_buf() + if fb6 is not None: + viperlib.snprintf(fb6, 1024, "读取文件失败 (错误码: %d)", bytes_read) + log.error(fb6, "fileio") + argparse.release(args) + return 1 + # 添加 null 终止符,确保 strlen 和 SHA1 计算正确 + if bytes_read < SRC_BUF_SIZE: + src_buf[bytes_read] = 0 + else: + src_buf[SRC_BUF_SIZE - 1] = 0 + if log is not None: + log.info("文件读取完成", "fileio") + fb7: str = VLogger.fmt_buf() + if fb7 is not None: + viperlib.snprintf(fb7, 1024, "读取 %d 字节", bytes_read) + log.info(fb7, "fileio") + # 解析 AST(拆分为词法+语法两阶段,便于调试) + ast._init_tables(mb) + lx: ast.Lexer | t.CPtr = ast.new_lexer(mb) + ast._lexer_init(lx, src_buf, mb) + tokens: ast.Token | t.CPtr = ast.tokenize(lx) + tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens) + if tree is None: + if log is not None: + log.error("AST 解析失败", "ast") + argparse.release(args) + return 1 + + # === 翻译 AST → LLVM IR === + if log is not None: + log.banner("LLVM IR 翻译") + tr: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator() + result: int = tr.translate(tree) + if result == 0: + IR_BUF_SIZE: t.CSizeT = 262144 + ir_buf: bytes = stdlib.malloc(IR_BUF_SIZE) + if ir_buf is not None: + tr.dump_ir(ir_buf, IR_BUF_SIZE, llvmlite.OUTPUT_FULL) + + # === 编译管线: .ll → .obj → .exe === + if log is not None: + log.banner("编译管线") + + # module_name 用源代码内容的 SHA1(前 16 字符),与 Projectrans.py 一致 + # output_name 从文件名推导(如 test.vp -> test.exe),保持可读性 + module_name: str = Utils.compute_sha1(mb, src_buf) + if module_name is None: + VLogger.error("SHA1 计算失败", "main") + output_name: str = "test_prog.exe" + # 从文件名提取 output_name(去掉路径和 .vp/.py 扩展名) + src_len: t.CSizeT = string.strlen(src_path) + if src_len > 0: + # 找到最后一个 / 或 \ 之后的部分 + base_start: t.CSizeT = src_len + i: t.CSizeT = src_len + while i > 0: + i -= 1 + ch: t.CChar = src_path[i] + if ch == '/' or ch == '\\': + base_start = i + 1 + break + if i == 0: + base_start = 0 + # 找到 .vp/.py 扩展名 + base_end: t.CSizeT = src_len + j: t.CSizeT = base_start + while j < src_len: + if src_path[j] == '.': + base_end = j + break + j += 1 + # 输出名 = 文件名 + ".exe" + name_len: t.CSizeT = base_end - base_start + if name_len > 0: + out_len: t.CSizeT = name_len + 5 + output_name = stdlib.malloc(out_len) + if output_name is not None: + # 手动复制文件名并追加 .exe(viperlib.snprintf 不支持 %.*s,string 无 strcat) + string.strncpy(output_name, src_path + base_start, name_len) + output_name[name_len] = '.' + output_name[name_len + 1] = 'e' + output_name[name_len + 2] = 'x' + output_name[name_len + 3] = 'e' + output_name[name_len + 4] = '\0' + # 使用 project.vpj 中的配置 + temp_dir: str = Config.TempDir if Config.TempDir is not None else "." + output_dir: str = Config.OutputDir if Config.OutputDir is not None else "." + # 设置全局 temp_dir(供跨模块 CDefine 查找使用) + GenApi.set_temp_dir(temp_dir) + cc_cmd: str = Config.CompilerCmd if Config.CompilerCmd is not None else "llc" + cc_flags: str = "-filetype=obj -relocation-model=pic" + linker_cmd: str = Config.LinkerCmd if Config.LinkerCmd is not None else "clang++" + linker_flags: str = "-lmsvcrt -lucrt -lpthread -lmingwex -lkernel32 -lgcc -Wl,--allow-multiple-definition" + # --project 模式且未显式指定 --src 时:使用 config 中的 linker_output(如 TransPyV.exe) + # 显式指定 --src 时:使用从文件名推导的 output_name(如 test.exe),避免覆盖正在运行的 exe + if project is not None and Config.LinkerOutput is not None and args.get_str("src") is None: + linker_output: str = Config.LinkerOutput + else: + linker_output: str = output_name + + # 计算 includes.binary 目录路径(链接时附加预编译 .obj) + includes_binary_dir: str = Config.get_includes_binary_dir() + + ir_len: t.CSizeT = string.strlen(ir_buf) + + # (--phase 参数已在配置加载后处理,此处直接使用 do_phase1/do_phase2) + + # === Phase1 stub 分离:使用 OUTPUT_STUB/TEXT 模式分别生成 stub.ll 和 text.ll === + if do_phase1 != 0 and temp_dir is not None and module_name is not None: + if log is not None: + log.banner("stub 分离") + SF_IR_SIZE: t.CSizeT = 262144 + td_len_sf: t.CSizeT = string.strlen(temp_dir) + # 保存 stub.ll + sf_stub_buf: bytes = stdlib.malloc(SF_IR_SIZE) + if sf_stub_buf is not None: + tr.dump_ir(sf_stub_buf, SF_IR_SIZE, llvmlite.OUTPUT_STUB) + sf_stub_len: t.CSizeT = string.strlen(sf_stub_buf) + sf_stub_path: str = StubMergerCollect._sliced_path(temp_dir, td_len_sf, module_name, "stub.ll") + if sf_stub_path is not None: + sf_f: fileio.File | t.CPtr = fileio.File(sf_stub_path, fileio.MODE.W) + if not sf_f.closed: + sf_f.write(sf_stub_buf, sf_stub_len) + sf_f.close() + stdlib.free(sf_stub_path) + stdlib.free(sf_stub_buf) + # 保存 text.ll + sf_text_buf: bytes = stdlib.malloc(SF_IR_SIZE) + if sf_text_buf is not None: + tr.dump_ir(sf_text_buf, SF_IR_SIZE, llvmlite.OUTPUT_TEXT) + sf_text_len: t.CSizeT = string.strlen(sf_text_buf) + sf_text_path: str = StubMergerCollect._sliced_path(temp_dir, td_len_sf, module_name, "text.ll") + if sf_text_path is not None: + sf_tf: fileio.File | t.CPtr = fileio.File(sf_text_path, fileio.MODE.W) + if not sf_tf.closed: + sf_tf.write(sf_text_buf, sf_text_len) + sf_tf.close() + stdlib.free(sf_text_path) + stdlib.free(sf_text_buf) + + # phase=1 模式:仅生成 stub,不执行编译 + if do_phase2 == 0: + if log is not None: + log.success("Phase1 完成(仅 stub 分离,跳过编译)") + argparse.release(args) + return 0 + + # === Phase2: 组合本地 stub + 依赖 stubs + 本地 text → 完整 IR === + final_ir: bytes = ir_buf + final_ir_len: t.CSizeT = ir_len + if temp_dir is not None and module_name is not None: + if log is not None: + log.banner("IR 组合") + SF_COMBINED_SIZE: t.CSizeT = 4194304 # 4MB + combined_buf: bytes = stdlib.malloc(SF_COMBINED_SIZE) + if combined_buf is not None: + combined_len: t.CSizeT = StubMergerBuild.BuildCombinedIR(temp_dir, module_name, combined_buf, SF_COMBINED_SIZE) + if combined_len > 0: + final_ir = combined_buf + final_ir_len = combined_len + else: + stdlib.free(combined_buf) + VLogger.error("BuildCombinedIR 失败,终止编译", "stub") + + br: BuildPipeline.BuildResult | t.CPtr = BuildPipeline.run_pipeline( + final_ir, final_ir_len, temp_dir, output_dir, module_name, + cc_cmd, cc_flags, linker_cmd, linker_flags, linker_output, + includes_binary_dir + ) + if br is not None and br.Success == 1: + if log is not None: + log.success("编译管线完成") + fb8: str = VLogger.fmt_buf() + if fb8 is not None: + viperlib.snprintf(fb8, 1024, "输出: %s/%s", output_dir, linker_output) + log.info(fb8) + # --run 模式:执行生成的可执行文件 + if args.get_bool("run"): + exe_path: bytes = stdlib.malloc(string.strlen(output_dir) + string.strlen(linker_output) + 2) + if exe_path is not None: + viperlib.snprintf(exe_path, 256, "%s/%s", output_dir, linker_output) + if log is not None: + fb9: str = VLogger.fmt_buf() + if fb9 is not None: + viperlib.snprintf(fb9, 1024, "执行: %s", exe_path) + log.info(fb9, "run") + r: subprocess.CompletedProcess | t.CPtr = subprocess.run(exe_path, False, False) + if r is not None: + if log is not None: + fb10: str = VLogger.fmt_buf() + if fb10 is not None: + viperlib.snprintf(fb10, 1024, "退出码: %d", r.returncode) + log.info(fb10, "run") + else: + if log is not None: + log.error("编译管线失败", "pipeline") + if br is not None and br.ErrorMsg is not None: + fb11: str = VLogger.fmt_buf() + if fb11 is not None: + viperlib.snprintf(fb11, 1024, "编译管线失败: %s", br.ErrorMsg) + log.error(fb11, "FATAL") + sys.exit(1) + else: + if log is not None: + log.error("malloc for IR buffer failed", "memhub") + else: + if log is not None: + log.error("翻译失败", "translator") + + argparse.release(args) + if log is not None: + log.success("TransPyV 完成") + return 0 diff --git a/_ExprGenMixin_backup.vp b/_ExprGenMixin_backup.vp deleted file mode 100644 index df4eddd..0000000 --- a/_ExprGenMixin_backup.vp +++ /dev/null @@ -1,6203 +0,0 @@ -import t, c -from stdint import * -import ast -import memhub -import string -import llvmlite -import stdlib -import stdio -import viperlib -import w32.fileio as fileio -import lib.core.CompilerFactory as CompilerFactory -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.VLogger as VLogger -import lib.Projectrans.Config as Config -import lib.Projectrans.Utils as Utils - -# ============================================================ -# docstring 登记表容量(__doc__ 魔法属性支持) -# -# DOC_MAX: 登记条目上限(预注册阶段所有 App/includes 文件的 -# 函数/类/方法 docstring,幂等查重) -# DOC_KEY_SZ: key "{module_sha1}.{symbol}" 缓冲宽度 -# DOC_VAL_SZ: docstring 内容缓冲宽度 -# ============================================================ -DOC_MAX: t.CDefine = 512 -DOC_KEY_SZ: t.CDefine = 192 -DOC_VAL_SZ: t.CDefine = 4096 - -# ============================================================ -# f-string 翻译常量(对齐 TPC HandlesExprFormat) -# -# FSTR_BUF_SIZE: 运行时栈缓冲大小(snprintf 结果缓冲) -# FSTR_SPEC_MAX: 编译期 format_spec 解析缓冲宽度 -# FSTR_FMT_MAX: 编译期 C printf 格式串缓冲宽度 -# ============================================================ -FSTR_BUF_SIZE: t.CDefine = 1024 -FSTR_SPEC_MAX: t.CDefine = 64 -FSTR_FMT_MAX: t.CDefine = 64 - - -# ============================================================ -# ExprGenMixin - 表达式处理 Mixin(对象化 P3,wiki/14-oo-refactor.md) -# -# 从 HandlesExpr.vp(48 函数,无全局状态)与 HandlesExprOps.vp -# 迁移:模块级纯函数 → 类方法(self 替代,参数保留含 builder/pool)。 -# -# 迁移原则(与 P2 一致,行为零变化): -# 1. 方法保留原函数签名(含 builder/pool 首参),仅函数体内 -# 本模块函数调用改为 self.xxx(...) -# 2. 外部模块调用(HandlesExprCall.xxx / HandlesType.xxx 等)保留模块前缀 -# 3. HandlesExpr.vp / HandlesExprOps.vp 原函数保留为"委托":本地 -# 模块级单例 _g_gen(BuildPipeline/main 注入)cast 成 Generator 类型 -# 4. ExprHandle 类保留在 HandlesExpr.vp(translator handler 模式) -# -# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 -# ============================================================ - - -# ============================================================ -# ExprGenMixin - 表达式/常量/下标/属性访问/运算符 -# ============================================================ -@t.NoVTable -class ExprGenMixin: - """表达式处理 Mixin(纯方法化迁移,无状态字段)""" - - # --- docstring 登记表字段(__doc__ 魔法属性支持)--- - DocKeys: bytes - DocValues: bytes - DocCount: int - - # --- OOM 诊断:跨模块 CDefine 查找调用计数(CONST_INT 参数翻译疑似循环查找) --- - DiagCDefineCount: int - # --- OOM 诊断:translate_name_value 调用计数(顶层 CDefine 查找 14593 次来源) --- - DiagNameValueCount: int - # --- OOM 诊断:translate_value 调用计数(CONST_INT 循环调用源定位) --- - DiagTranslateValueCount: int - - # ============================================================ - # P3 迁移方法(函数体来自 HandlesExpr.vp 模块级函数, - # 本模块函数调用改 self.,外部模块调用保留模块前缀) - # ============================================================ - - # ============================================================ - # 从 AST 节点提取函数名 - # ============================================================ - def get_func_name(self, func_node: ast.AST | t.CPtr) -> str: - """从函数节点提取函数名""" - if func_node is None: - return None - k: int = func_node.kind() - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(func_node) - return nm.id - elif k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(func_node) - return at.attr - return None - - # ============================================================ - # 转义 LLVM IR 字符串字面量 - # ============================================================ - def escape_llvm_string(self, pool: memhub.MemBuddy | t.CPtr, - src: str) -> str: - """将字符串转换为 LLVM IR 字符串字面量 c"...\\00" """ - if src is None: - return None - slen: t.CSizeT = string.strlen(src) - alloc_size: t.CSizeT = 4 * slen + 8 - buf: str = pool.alloc(alloc_size) - if buf is None: - return None - pos: t.CSizeT = 0 - buf[pos] = 'c' - pos += 1 - buf[pos] = '"' - pos += 1 - for i in range(slen): - ch: t.CChar = src[i] - if ch == '\0': - break - if ch == '\"' or ch == '\\' or ch < 0x20: - buf[pos] = '\\' - pos += 1 - hi: int = (ch >> 4) & 0xF - lo: int = ch & 0xF - buf[pos] = Utils.nibble_to_hex_char(hi, 1) - pos += 1 - buf[pos] = Utils.nibble_to_hex_char(lo, 1) - pos += 1 - else: - buf[pos] = ch - pos += 1 - buf[pos] = '\\' - pos += 1 - buf[pos] = '0' - pos += 1 - buf[pos] = '0' - pos += 1 - buf[pos] = '"' - pos += 1 - buf[pos] = '\0' - return buf - - # ============================================================ - # 获取 LLVM 整数类型的位宽 - # ============================================================ - 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 - - # ============================================================ - # 获取 LLVM 浮点类型的位宽 - # ============================================================ - def get_llvm_float_bits(self, ty: llvmlite.LLVMType | t.CPtr) -> int: - """获取 LLVM 浮点类型的位宽,非浮点类型返回 0""" - if ty is None: - return 0 - match ty: - case llvmlite.LLVMType.Float(bits): - return bits - case _: - return 0 - - # ============================================================ - # is_ptr_type - 检查类型是否为 Ptr - # - # 返回 1=是, 0=否。作为类型检查工具函数被广泛使用(50+ 处调用)。 - # ============================================================ - def is_ptr_type(self, ty: llvmlite.LLVMType | t.CPtr) -> int: - """检查 ty 是否是 Ptr 类型,返回 1=是, 0=否""" - if ty is None: - return 0 - match ty: - case llvmlite.LLVMType.Ptr(pointee): - return 1 - case _: - return 0 - - # ============================================================ - # get_ptr_level - 计算指针层级 - # - # 返回值: - # 0 = 非指针(数值/结构体等) - # 1 = 一级指针(如 i8*, Struct*) - # 2 = 二级指针(如 i8**, Struct**) - # 3+ = 更高级指针 - # - # 用于比较运算的类型安全检查: - # - 数值(0) vs 数值(0) → 允许 - # - 一级指针(1) vs 一级指针(1) → 允许 - # - 数值(0) vs 指针(1+) → 禁止(fast-fail) - # - 不同级指针(1 vs 2) → 禁止(fast-fail) - # ============================================================ - def get_ptr_level(self, ty: llvmlite.LLVMType | t.CPtr) -> int: - """计算指针层级,0=非指针, 1=一级指针, 2=二级指针...""" - if ty is None: - return 0 - level: int = 0 - cur: llvmlite.LLVMType | t.CPtr = ty - while cur is not None: - match cur: - case llvmlite.LLVMType.Ptr(pointee): - level += 1 - cur = pointee - case _: - break - return level - - # ============================================================ - # _is_zero_int_literal - 判断 AST 节点是否为整数字面量 0 - # - # 用于指针判空比较(ptr != 0 / ptr == 0):指针与字面量 0 比较时 - # 0 视为 NULL,允许并转成 null 指针(比较类型检查的例外)。 - # ============================================================ - def _is_zero_int_literal(self, node: ast.AST | t.CPtr) -> int: - """判断节点是否为整数字面量 0,返回 1=是 / 0=否""" - if node is None: - return 0 - if node.kind() != ast.ASTKind.Constant: - return 0 - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) - if cn is None or cn.const_kind != ast.CONST_INT: - return 0 - if cn.int_val == 0: - return 1 - return 0 - - # ============================================================ - # is_array_type - 检查类型是否为 Array - # - # 返回 1=是, 0=否。类型检查工具函数。 - # ============================================================ - def is_array_type(self, ty: llvmlite.LLVMType | t.CPtr) -> int: - """检查 ty 是否是 Array 类型,返回 1=是, 0=否""" - if ty is None: - return 0 - match ty: - case llvmlite.LLVMType.Array(_, _): - return 1 - case _: - return 0 - - # ============================================================ - # _zext_index_to_i32 - 数组下标索引零扩展 - # - # LLVM GEP 对窄整数索引默认符号扩展:i8 0xE2(226) 会被当成 -30, - # 导致数组下标越界读(字节 >= 128 的乱码根因)。 - # 数组下标语义为非负,<32 位整数索引一律 zext 到 i32。 - # 仅用于数组 GEP;指针负偏移(p[-1])不经过此路径,不受影响。 - # ============================================================ - def _zext_index_to_i32(self, builder: llvmlite.IRBuilder | t.CPtr, - idx_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: - """将 <32 位整数下标零扩展到 i32(数组下标非负语义)""" - if idx_val is None or idx_val.Ty is None or builder is None: - return idx_val - idx_bits: int = self.get_llvm_type_bits(idx_val.Ty) - if idx_bits != 0 and idx_bits < 32: - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(builder.Pool) - return llvmlite.build_zext(builder, idx_val, i32_ty) - return idx_val - - # ============================================================ - # _get_custom_struct_cls_nm - 检查类型是否为已注册的自定义结构体 - # - # 处理两种情况: - # - ty 直接是 Struct → 检查是否注册 - # - ty 是 Ptr(Struct) → 检查 pointee 是否注册 - # - # 返回类名字符串或 None。用于 subscript 操作中判断是否需要 - # 转发到 __getitem__/__setitem__ 而非生成 GEP。 - # ============================================================ - def _get_custom_struct_cls_nm(self, pool: memhub.MemBuddy | t.CPtr, - ty: llvmlite.LLVMType | t.CPtr) -> str: - """检查 ty 或 ty 的 pointee 是否是已注册的自定义结构体,返回类名或 None""" - if ty is None: - return None - # 直接检查 ty 是否是注册的结构体 - cls_nm_direct: str = HandlesStruct.get_class_name_by_type(pool, ty) - if cls_nm_direct is not None: - return cls_nm_direct - # 如果 ty 是 Ptr,检查 pointee - if self.is_ptr_type(ty) != 0: - pointee_cs: llvmlite.LLVMType | t.CPtr = ty.Pointee - if pointee_cs is not None: - return HandlesStruct.get_class_name_by_type(pool, pointee_cs) - return None - - # ============================================================ - # _is_list_subscript_base - 判断下标基座是否为 list[T] 变量 - # - # 属性访问的 Subscript 基座(如 lst[i].x)需要区分: - # - list[T] 变量:translate_subscript 走 __getitem__ 内联返回元素地址 - # - 普通结构体指针数组(如 pts: Point | t.CPtr):get_subscript_ptr 返回元素地址 - # 路由错误会让 list[T] 被当作结构体数组 GEP,访问错位崩溃。 - # ============================================================ - def _is_list_subscript_base(self, pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - sub_node: ast.AST | t.CPtr) -> int: - """判断下标基座是否为 list[T] 变量(1=是)""" - if sub_node is None or trans is None: - return 0 - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sub_node) - if sub is None or sub.value is None or sub.value.kind() != ast.ASTKind.Name: - return 0 - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) - if nm.id is None: - return 0 - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is None or alloca.Ty is None: - return 0 - if self.is_ptr_type(alloca.Ty) == 0: - return 0 - pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee - if pointee is None: - return 0 - match pointee: - case llvmlite.LLVMType.Ptr(inner_ty): - lsn_ls: str = None - match inner_ty: - case llvmlite.LLVMType.Struct(_, _, lsn3): - lsn_ls = lsn3 - case _: - pass - if lsn_ls is not None and string.strstr(lsn_ls, "list[") is not None: - return 1 - case _: - pass - return 0 - - # ============================================================ - # _sub_base_class_name - 解析下标基座变量的结构体类名 - # ============================================================ - def _sub_base_class_name(self, pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - sub_node: ast.AST | t.CPtr) -> str: - """解析下标基座变量的结构体类名(无则 None)""" - if sub_node is None or trans is None: - return None - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sub_node) - if sub is None or sub.value is None or sub.value.kind() != ast.ASTKind.Name: - return None - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) - if nm.id is None: - return None - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is None or alloca.Ty is None: - return None - if self.is_ptr_type(alloca.Ty) == 0: - return None - pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee - if pointee is None: - return None - if self.is_ptr_type(pointee) != 0: - inner: llvmlite.LLVMType | t.CPtr = pointee.Pointee - if inner is not None: - return HandlesStruct.get_class_name_by_type(pool, inner) - return HandlesStruct.get_class_name_by_type(pool, pointee) - - # ============================================================ - # _sub_base_uses_getitem - 下标基座是否应走 __getitem__ 语义 - # - # 属性访问的 Subscript 基座路由依据: - # - list[T] / OOP 定义 __getitem__ 的类(如 dict[key])→ translate_value - # (translate_subscript 走 __getitem__ 内联/方法调用返回元素值或地址) - # - 普通结构体指针数组(如 pts: Point | t.CPtr)→ get_subscript_ptr - # (GEP 元素地址,避免结构体值 base=非指针 报错) - # ============================================================ - def _sub_base_uses_getitem(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - trans: HT.Translator | t.CPtr, - sub_node: ast.AST | t.CPtr) -> int: - """下标基座应走 __getitem__ 语义时返回 1,否则 0(应走 GEP 地址语义)""" - if self._is_list_subscript_base(pool, trans, sub_node) != 0: - return 1 - cls_ugi: str = self._sub_base_class_name(pool, trans, sub_node) - if cls_ugi is None: - return 0 - lookup_ugi: str = pool.alloc(128) - if lookup_ugi is None: - return 0 - viperlib.snprintf(lookup_ugi, 128, "%s.__getitem__", cls_ugi) - if HandlesExprCall.find_func_in_module(mod, lookup_ugi) is not None: - return 1 - return 0 - - # ============================================================ - # _deref_if_ptr_ptr - 如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用 - # - # 用于支持 X|t.CPtr 类型变量的属性访问: - # - 值类型变量 (cnt: Counter): alloca 类型是 Ptr(Struct) → 不解引用 - # - 指针类型变量 (r: Vec2|t.CPtr): alloca 类型是 Ptr(Ptr(Struct)) → load 解引用 - # ============================================================ - def _deref_if_ptr_ptr(self, builder: llvmlite.IRBuilder | t.CPtr, - obj_ptr: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: - """如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用获取内层指针""" - if obj_ptr is None or obj_ptr.Ty is None: - return obj_ptr - if self.is_ptr_type(obj_ptr.Ty) == 0: - return obj_ptr - pointee: llvmlite.LLVMType | t.CPtr = obj_ptr.Ty.Pointee - if pointee is None: - return obj_ptr - if self.is_ptr_type(pointee) == 0: - return obj_ptr - # obj_ptr 是 Ptr(Ptr(...)),load 解引用 - loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, pointee, obj_ptr) - if loaded is None: - return obj_ptr - return loaded - - # ============================================================ - # 类型强制转换:整数 sext/trunc,浮点 fpext/fptrunc,int↔float si2fp/fp2si - # ============================================================ - def coerce_to_type(self, builder: llvmlite.IRBuilder | t.CPtr, - val: llvmlite.Value | t.CPtr, - target_ty: llvmlite.LLVMType | t.CPtr, - node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """将 val 强制转换为 target_ty - - 整数: sext(扩展)/ trunc(截断) - 浮点: fpext(扩展)/ fptrunc(截断) - int→float: sitofp - float→int: fptosi - - node: AST 节点(用于错误定位),可为 None - """ - if val is None or target_ty is None: - return val - # 函数 → 指针: bitcast(如 CreateThread(..., _thread_alloc_free, ...) 传函数指针) - # 函数 Value 的 Ty 是 Func,既不是整数也不是指针,需在整数/浮点转换之前处理 - match val.Ty: - case llvmlite.LLVMType.Func(_, _, _): - if self.is_ptr_type(target_ty) != 0: - return llvmlite.build_bitcast(builder, val, target_ty) - return val - case _: - pass - # 整数转换 - val_bits: int = self.get_llvm_type_bits(val.Ty) - target_bits: int = self.get_llvm_type_bits(target_ty) - # 整数 → 指针: inttoptr(必须在纯整数转换之前检查,因为 ptr 的 bits 非零会误入 sext/trunc 路径) - # 适用于: 跨模块方法返回 i64/i32(默认推断),目标变量是指针类型 - if val_bits != 0 and self.is_ptr_type(target_ty) != 0: - return llvmlite.build_inttoptr(builder, val, target_ty) - # 指针 → 整数: ptrtoint(当目标明确是整数而非指针时) - # 注意: target_bits == 8 时跳过 ptrtoint,走后面的 build_load 解引用首字符 - # 修复: buf[idx] = '\0' 中 '\0' 是 CONST_STR → i8* 指针, - # ptrtoint 会截断地址低 8 位(非 0),应 load 解引用取首字符 0 - if self.is_ptr_type(val.Ty) != 0 and target_bits != 0 and target_bits != 8 and self.is_ptr_type(target_ty) == 0: - return llvmlite.build_ptrtoint(builder, val, target_ty) - if val_bits != 0 and target_bits != 0: - if val_bits == target_bits: - return val - if val_bits < target_bits: - # i1 (bool) → 更宽整数用 zext(bool 语义:1 保持 1,而非 sext 的 0xFF...) - # 与 HandlesReturn 中 return 语句的 i1 扩展规则保持一致 - if val_bits == 1: - return llvmlite.build_zext(builder, val, target_ty) - return llvmlite.build_sext(builder, val, target_ty) - return llvmlite.build_trunc(builder, val, target_ty) - # 浮点转换 - val_fbits: int = self.get_llvm_float_bits(val.Ty) - target_fbits: int = self.get_llvm_float_bits(target_ty) - # float ↔ ptr: 禁止(无意义的转换,fast-fail 防止误走入 build_load 路径) - if (val_fbits != 0 and self.is_ptr_type(target_ty) != 0) or \ - (self.is_ptr_type(val.Ty) != 0 and target_fbits != 0): - HandlesType.fatal_error(node, "unsupported type conversion: float <-> ptr", "CastError") - return val - if val_fbits != 0 and target_fbits != 0: - if val_fbits == target_fbits: - return val - if val_fbits < target_fbits: - return llvmlite.build_fpext(builder, val, target_ty) - return llvmlite.build_fptrunc(builder, val, target_ty) - # int → float - if val_bits != 0 and target_fbits != 0: - return llvmlite.build_si2fp(builder, val, target_ty) - # float → int - if val_fbits != 0 and target_bits != 0: - return llvmlite.build_fp2si(builder, val, target_ty) - # 指针 → 非指针值: build_load 解引用 - # 适用于: 指针 → 整数 (如 i8* → i8), 指针 → 结构体值 - # 当构造器返回 Ptr(Struct) 但目标变量是 Struct 值类型时,需要 load - if self.is_ptr_type(val.Ty) != 0 and self.is_ptr_type(target_ty) == 0: - return llvmlite.build_load(builder, target_ty, val) - # 指针 → 指针: bitcast (如 i8* → i8** 当目标是全局变量存储指针) - if self.is_ptr_type(val.Ty) != 0 and self.is_ptr_type(target_ty) != 0: - return llvmlite.build_bitcast(builder, val, target_ty) - return val - - # ============================================================ - # translate_ptr_arith - 指针算术: ptr + int / ptr - int - # - # 用 getelementptr(按 pointee 元素大小缩放索引),对齐 TPC - # ExprGen.emit_binary_op / HandlesAugAssign.py。 - # 旧实现用 ptrtoint + add + inttoptr(按字节加):i8* 元素大小 1 - # 恰好正确,但 i32*/struct* 等指针 `p + 3` 只前进 3 字节(应 12), - # 导致 StringIterTest Test 4/8 失败(指针偏移/指针算术)。 - # - # 数组 pointee([N x ty]*)先 decay 为元素指针(GEP 0,0), - # 避免以整个数组为步长(对齐 TPC ExprGen L53-55)。 - # ============================================================ - def translate_ptr_arith(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - ptr_val: llvmlite.Value | t.CPtr, - int_val: llvmlite.Value | t.CPtr, - op: int) -> llvmlite.Value | t.CPtr: - """指针算术: ptr + int / ptr - int → GEP(按元素大小缩放索引)""" - if ptr_val is None or int_val is None or ptr_val.Ty is None: - return None - # 提取 pointee 类型(非指针 → 不处理返回 None) - elem_ty: llvmlite.LLVMType | t.CPtr = None - match ptr_val.Ty: - case llvmlite.LLVMType.Ptr(pointee): - elem_ty = pointee - case _: - return None - if elem_ty is None: - return None - # 索引统一到 i64(对齐 TPC zext 到 i64) - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - idx: llvmlite.Value | t.CPtr = self.coerce_to_type(builder, int_val, i64_ty, None) - if idx is None: - return None - # ptr - int → 负索引(LLVM GEP 索引为加法语义) - if op == ast.OpKind.Sub: - neg_idx: llvmlite.Value | t.CPtr = llvmlite.build_sub( - builder, llvmlite.const_int64(pool, 0), idx) - if neg_idx is None: - return None - idx = neg_idx - # 数组 pointee → 先 decay 为元素指针(getelementptr [N x ty], [N x ty]* %p, i32 0, i32 0) - if self.is_array_type(elem_ty) != 0: - inner_ty: llvmlite.LLVMType | t.CPtr = None - match elem_ty: - case llvmlite.LLVMType.Array(inner, _): - inner_ty = inner - case _: - return None - if inner_ty is None: - return None - decayed: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, elem_ty, inner_ty, ptr_val, llvmlite.const_int64(pool, 0)) - if decayed is None: - return None - return llvmlite.build_gep(builder, inner_ty, decayed, idx) - return llvmlite.build_gep(builder, elem_ty, ptr_val, idx) - - # ============================================================ - # 创建全局字符串常量 - # ============================================================ - def create_global_string(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - str_val: str, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """创建全局字符串常量并返回 i8* bitcast""" - escaped: str = self.escape_llvm_string(pool, str_val) - if escaped is None: - return None - - slen: t.CSizeT = string.strlen(str_val) - count: int = slen + 1 - - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - arr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, count) - - # 使用模块级计数器(trans._label_counter)避免跨函数命名冲突 - str_idx: int = trans._label_counter - trans._label_counter += 1 - - # 字符串名加 SHA1 前缀,和函数导出规则一致,避免跨模块重名 - gv_name: str = pool.alloc(48) - if gv_name is None: - return None - if trans.ModuleSha1 is not None: - viperlib.snprintf(gv_name, 48, ".str.%s.%d", trans.ModuleSha1, str_idx) - else: - viperlib.snprintf(gv_name, 48, ".str.%d", str_idx) - - gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, gv_name, arr_ty) - if gv is None: - return None - llvmlite.module_add_global(mod, gv) - - # 去掉 private 链接,和函数一致:stub 中 declare,text 中 define - llvmlite.global_set_unnamed_addr(gv, 1) - llvmlite.global_set_constant(gv, 1) - # LLVM 22+ 不允许 external linkage 全局变量带初始值,设为 internal - gv.Linkage = "internal" - gv.Initializer = escaped - - arr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, arr_ty) - gv_ref_name: str = pool.alloc(64) - if gv_ref_name is None: - return None - viperlib.snprintf(gv_ref_name, 64, "@%s", gv.Name) - gv_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, arr_ptr_ty, gv_ref_name) - - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, gv_ref, i8_ptr_ty) - return bc - - # ============================================================ - # 翻译常量表达式 - # ============================================================ - def translate_constant(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译常量(int/str/bool)""" - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) - if cn is None: - return None - ck: int = cn.const_kind - if cn.const_kind == ast.CONST_INT: - # 超出 i32 范围则用 i64(避免常量创建时被截断) - iv: t.CInt64T = cn.int_val - if iv > 2147483647 or iv < -2147483648: - return llvmlite.const_int64(pool, iv) - return llvmlite.const_int32(pool, iv) - elif cn.const_kind == ast.CONST_FLOAT: - # 浮点常量默认创建为 double(64 位),赋值时由 coerce_to_type 自动 fptrunc - double_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) - return llvmlite.ConstFloat(pool, double_ty, cn.float_val) - elif cn.const_kind == ast.CONST_CHAR: - # 单引号单字符 → i32 值(字符 ASCII 码),coerce_to_type 会 trunc 为 i8 - cv: t.CInt64T = cn.int_val - return llvmlite.const_int32(pool, cv) - elif cn.const_kind == ast.CONST_STR: - sv: str = cn.str_val - if sv is None: - return None - r: llvmlite.Value | t.CPtr = self.create_global_string(builder, pool, mod, sv, trans) - return r - elif cn.const_kind == ast.CONST_BOOL: - if cn.int_val != 0: - return llvmlite.const_int32(pool, 1) - return llvmlite.const_int32(pool, 0) - elif cn.const_kind == ast.CONST_NONE: - # None → i8* null(空指针常量),用于 `p is None` / `p is not None` 比较 - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - if i8_ty is None: - return None - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - if i8_ptr_ty is None: - return None - rv_none: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty, "null") - return rv_none - return None - - # ============================================================ - # _infer_elem_type_from_value — 从 LLVM Value 推断 list 元素类型名 - # - # 用于 list 字面量 [a, b, c] 的元素类型推断 - # ============================================================ - def _infer_elem_type_from_value(self, pool: memhub.MemBuddy | t.CPtr, - value: llvmlite.Value | t.CPtr) -> str: - """从 LLVM Value 的类型推断 list 元素类型名 - - fail-fast:值类型缺失/无法映射时返回 None(调用方携带节点报错终止), - 绝不静默回退 "str"(掩盖上游 Value 类型缺失根因)。 - """ - if value is None or value.Ty is None: - return None - ty: llvmlite.LLVMType | t.CPtr = value.Ty - bits: int = self.get_llvm_type_bits(ty) - if bits != 0: - if bits == 32: - return "int" - if bits == 64: - return "CSizeT" - if bits == 8: - return "CInt8T" - if bits == 16: - return "CInt16T" - return None - if self.is_ptr_type(ty) != 0: - return "str" - fbits: int = self.get_llvm_float_bits(ty) - if fbits != 0: - if fbits == 64: - return "CDouble" - if fbits == 32: - return "CFloat" - return None - - # ============================================================ - # _find_pool_var — 查找上下文中的 pool 变量 - # - # 依次尝试 "pool", "_mbuddy", "mbuddy", "mb" - # ============================================================ - def _find_pool_var(self, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """查找上下文中的 pool 变量,返回 alloca 或 None - - 查找顺序: pool → _mbuddy → mbuddy → mb - 兜底: 若都未找到,注册外部全局 @_mbuddy (i8*) 供函数内动态 list 创建使用。 - 注意: 模块级 t.CArray 初始化不走此路径(由 _init_global_array_from_list 处理), - 此兜底仅用于函数内的动态 list 字面量(如 op=[...])。 - @_mbuddy 由入口模块(如 Phase2.py)定义并初始化,其他模块以 external 引用。 - """ - if trans is None: - return None - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, "pool") - if alloca is not None: - return alloca - alloca = HandlesVar.lookup_var(trans.SymTab, "_mbuddy") - if alloca is not None: - return alloca - alloca = HandlesVar.lookup_var(trans.SymTab, "mbuddy") - if alloca is not None: - return alloca - alloca = HandlesVar.lookup_var(trans.SymTab, "mb") - if alloca is not None: - return alloca - # 兜底: 创建外部全局 @_mbuddy 引用(i8** 类型) - # 仅用于函数内动态 list 字面量,@_mbuddy 由入口模块定义并初始化 - pool: memhub.MemBuddy | t.CPtr = trans.Pool - if pool is None or trans.Module is None or trans.SymTab is None: - return None - # 先检查是否已注册到模块作用域(避免重复创建全局变量) - existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(trans.SymTab, "_mbuddy") - if existing is not None: - return existing - # 创建 i8* 类型(t.CVoid | t.CPtr = i8*) - i8_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_fb) - # 创建外部全局 @_mbuddy(external linkage,无初始值) - gv_ext: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, "_mbuddy", i8_ptr_ty_fb) - if gv_ext is not None: - gv_ext.Linkage = "external" - llvmlite.module_add_global(trans.Module, gv_ext) - # 创建 Value 引用(@_mbuddy, 类型为 i8**) - i8_ptr_ptr_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty_fb) - ref_name_fb: str = pool.alloc(16) - if ref_name_fb is not None: - string.strcpy(ref_name_fb, "@_mbuddy") - gv_ref_fb: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ptr_ty_fb, ref_name_fb) - # 注册到模块作用域,避免重复创建 - HandlesVar.define_module_var(trans.SymTab, "_mbuddy", gv_ref_fb) - return gv_ref_fb - - # ============================================================ - # translate_list_literal — 翻译 list 字面量 [a, b, c] - # - # 将 list 字面量翻译为 list[T](pool) 构造 + append 调用序列 - # - # Args: - # builder: IRBuilder - # pool: 编译器内存池(MemBuddy) - # mod: LLVMModule - # node: ast.List 节点 - # elem_type_name: 元素类型名(如 "str", "int"),None 表示从元素推断 - # trans: Translator 对象 - # - # Returns: - # list 对象指针(Ptr(list[T] struct)),None 失败 - # ============================================================ - def translate_list_literal(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - elem_type_name: str, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """翻译 list 字面量 [a, b, c] → list[T](pool) + append 序列""" - if node is None or trans is None: - return None - - list_node: ast.List | t.CPtr = (ast.List | t.CPtr)(node) - if list_node is None: - return None - - elts: list[ast.AST | t.CPtr] | t.CPtr = list_node.elts - elts_count: t.CSizeT = 0 - if elts is not None: - elts_count = len(elts) - - # 推断元素类型 - inferred_type_name: str = elem_type_name - first_elem_val: llvmlite.Value | t.CPtr = None - if inferred_type_name is None: - if elts_count > 0: - first_elem_node: ast.AST | t.CPtr = elts.get(0) - first_elem_val = self.translate_value(builder, pool, mod, first_elem_node, None, 0, trans) - if first_elem_val is None or first_elem_val.Ty is None: - # fail-fast:首元素翻译失败/Value 类型缺失,立即终止编译(暴露上游根因) - HandlesType.fatal_error( - first_elem_node, "list 字面量元素类型推断失败(Value 类型缺失)", "TypeError") - inferred_type_name = self._infer_elem_type_from_value(pool, first_elem_val) - if inferred_type_name is None: - # fail-fast:首元素 Value 类型无法映射为 list 元素类型,立即终止编译 - HandlesType.fatal_error( - first_elem_node, "list 字面量元素类型推断失败(Value 类型缺失)", "TypeError") - else: - # 空 list 无元素可推断,保持默认 str(list[str]) - inferred_type_name = "str" - - # 查找 pool 变量 - pool_alloca: llvmlite.Value | t.CPtr = self._find_pool_var(trans) - if pool_alloca is None: - HandlesType.fatal_error(node, "list literal requires pool variable in context") - return None - - # load pool 变量值(i8*) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - pool_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, pool_alloca) - if pool_val is None: - return None - - # 特化 list[T] 类(elem_size=8:str 是指针,4 会导致双元素重叠损坏) - type_args: list[str] | t.CPtr = list[str](pool, 8) - type_args.append(inferred_type_name) - spec_name: str = HandlesClassDef._specialize_generic_class(trans, "list", type_args) - if spec_name is None: - HandlesType.fatal_error(node, "list literal generic specialization failed") - return None - - # 查找 struct entry - struct_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name) - if struct_entry is None: - HandlesType.fatal_error(node, "list literal specialized class not registered") - return None - struct_ty: llvmlite.LLVMType | t.CPtr = struct_entry.Ty - if struct_ty is None: - return None - - # alloca 临时 list 空间 - # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) - HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) - tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) - if tmp is None: - return None - - # 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针 - # __new__ 是可选的,仅当泛型类模板定义了 __new__ 方法时才调用 - # (与 _translate_struct_ctor/_translate_generic_ctor_call 保持一致, - # 避免为无 __new__ 的类生成过度声明) - storage_ptr: llvmlite.Value | t.CPtr = tmp - has_new_flag: int = 0 - if struct_entry is not None: - has_new_flag = struct_entry.HasNew - if has_new_flag != 0: - new_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if new_args is None: - return None - string.memset(new_args, 0, 8 * 32) - new_args[0] = t.CSizeT(pool_val) - new_ptr: llvmlite.Value | t.CPtr = HandlesExprCall._call_method_on_ptr( - pool, builder, mod, spec_name, "__new__", tmp, new_args, 1, trans) - if new_ptr is not None: - storage_ptr = new_ptr - - # 调用 __before_init__(storage_ptr) - HandlesExprCall._call_method_on_ptr( - pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans) - - # 调用 __init__(storage_ptr, pool_val, elem_size=0) - init_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if init_args is None: - return None - string.memset(init_args, 0, 8 * 32) - init_args[0] = t.CSizeT(pool_val) - elem_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) - init_args[1] = t.CSizeT(elem_size_val) - HandlesExprCall._call_method_on_ptr( - pool, builder, mod, spec_name, "__init__", storage_ptr, init_args, 2, trans) - - # 对每个元素调用 append(storage_ptr, elem_val) - if elts_count > 0: - # 第一个元素可能已经翻译过 - if first_elem_val is not None: - append_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if append_args is not None: - string.memset(append_args, 0, 8 * 32) - append_args[0] = t.CSizeT(first_elem_val) - HandlesExprCall._call_method_on_ptr( - pool, builder, mod, spec_name, "append", storage_ptr, append_args, 1, trans) - - # 翻译剩余元素 - i: t.CSizeT = 1 - while i < elts_count: - elem_node_i: ast.AST | t.CPtr = elts.get(i) - elem_val_i: llvmlite.Value | t.CPtr = self.translate_value(builder, pool, mod, elem_node_i, None, 0, trans) - if elem_val_i is not None: - ap_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if ap_args is not None: - string.memset(ap_args, 0, 8 * 32) - ap_args[0] = t.CSizeT(elem_val_i) - HandlesExprCall._call_method_on_ptr( - pool, builder, mod, spec_name, "append", storage_ptr, ap_args, 1, trans) - i += 1 - - return storage_ptr - - # ============================================================ - # 翻译值表达式(RHS 分派)— 模块级版本 - # ============================================================ - def translate_value(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - funcs_ptr: t.CPtr = None, - func_count: int = 0, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译值表达式为 LLVM Value""" - if node is None: - return None - k: int = node.kind() - if k == ast.ASTKind.Constant: - rv: llvmlite.Value | t.CPtr = self.translate_constant(builder, pool, mod, node, trans) - return rv - elif k == ast.ASTKind.Name: - return self.translate_name_value(builder, pool, node, trans) - elif k == ast.ASTKind.BinOp: - return self.translate_binop(pool, builder, mod, node, trans) - elif k == ast.ASTKind.Call: - return HandlesExprCall.translate_call(pool, builder, mod, node, - funcs_ptr, func_count, trans) - elif k == ast.ASTKind.Compare: - return self.translate_compare(builder, pool, mod, node, trans) - elif k == ast.ASTKind.UnaryOp: - return self.translate_unaryop(builder, pool, mod, node, trans) - elif k == ast.ASTKind.BoolOp: - return self.translate_boolop(builder, pool, mod, node, - funcs_ptr, func_count, trans) - elif k == ast.ASTKind.Subscript: - return self.translate_subscript(builder, pool, mod, node, trans) - elif k == ast.ASTKind.Attribute: - return self.translate_attribute(builder, pool, mod, node, trans) - elif k == ast.ASTKind.List: - return self.translate_list_literal(builder, pool, mod, node, None, trans) - elif k == ast.ASTKind.IfExp: - return self.translate_ifexp(builder, pool, mod, node, trans) - elif k == ast.ASTKind.Lambda: - # 模块级委托:translate_lambda 定义在 FuncGenMixin(跨 Mixin - # 方法不能 self. 直接调用,见 HandlesExpr.translate_lambda) - return HandlesExpr.translate_lambda(builder, pool, mod, node, trans) - elif k == ast.ASTKind.JoinedStr: - return self.translate_joined_str(builder, pool, mod, node, trans) - elif k == ast.ASTKind.FormattedValue: - # 解析器对 f"{expr:spec}"(单 FormattedValue 无字面量)返回裸 FormattedValue - # 而非 JoinedStr(见 ast/parser.vp _parse_fstring),需单独翻译 - return self.translate_formatted_value(builder, pool, mod, node, trans) - return None - - # ============================================================ - # translate_joined_str - f-string 翻译(对齐 TPC _HandleJoinedStrLlvm) - # - # f"..."(JoinedStr)→ 拼接字面量与格式说明符 → snprintf 生成 i8* - # 栈缓冲。之前 f-string 未翻译导致 print/赋值拿到 NULL 指针 - # ("(null)"输出 + printf("%s", 垃圾) 崩溃 0xC0000005)。 - # ============================================================ - def translate_joined_str(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """f-string → snprintf 生成 i8* 栈缓冲""" - if node is None or builder is None or trans is None: - return None - js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(node) - if js is None or js.values is None: - return None - - # 编译期格式串缓冲(pool 分配) - fmt_buf: str = pool.alloc(FSTR_BUF_SIZE) - if fmt_buf is None: - return None - fmt_buf[0] = '\0' - - # 运行时参数链表(Value.Next 链接,与 printf 调用一致) - arg_head: llvmlite.Value | t.CPtr = None - arg_tail: llvmlite.Value | t.CPtr = None - arg_count: int = 0 - - parts: list[ast.AST | t.CPtr] | t.CPtr = js.values - pn: t.CSizeT = len(parts) - for pi in range(pn): - part: ast.AST | t.CPtr = parts.get(pi) - if part is None: - continue - if part.kind() == ast.ASTKind.Constant: - pcn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part) - if pcn.const_kind == ast.CONST_STR and pcn.str_val is not None: - self._fstr_append_literal(fmt_buf, pcn.str_val) - continue - if part.kind() != ast.ASTKind.FormattedValue: - continue - fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part) - if fv.value is None: - continue - val: llvmlite.Value | t.CPtr = self.translate_value( - builder, pool, mod, fv.value, None, 0, trans) - if val is None: - # fail-fast:f-string 格式化值翻译失败必须终止编译,绝不在 - HandlesType.fatal_error( - fv.value, "f-string 格式化值翻译失败(表达式返回 None)", "TypeError") - continue - # 确定 C 格式说明符(format_spec 优先,否则按值类型推断) - c_fmt: str = None - if fv.format_spec is not None: - c_fmt = self._fstr_parse_format_spec(pool, fv.format_spec, val, fv.value) - if c_fmt is None: - c_fmt = self._fstr_infer_c_fmt(pool, val, fv.value, trans) - if c_fmt is None: - # fail-fast:f-string 格式无法推断(值类型缺失),立即终止编译 - HandlesType.fatal_error(fv.value, "f-string 格式无法推断(值类型缺失)", "TypeError") - # 追加格式说明符 - if string.strlen(fmt_buf) + string.strlen(c_fmt) < FSTR_BUF_SIZE - 1: - string.strcat(fmt_buf, c_fmt) - # 转换参数类型(i8/i16→i32、bool→i32、f32→f64) - cast_val: llvmlite.Value | t.CPtr = self._fstr_cast_value( - builder, pool, val, c_fmt, fv.value, trans) - if cast_val is None: - cast_val = val - cast_val.Next = None - if arg_head is None: - arg_head = cast_val - else: - arg_tail.Next = cast_val - arg_tail = cast_val - arg_count += 1 - - return self._fstr_finalize(builder, pool, mod, fmt_buf, arg_head, arg_tail, arg_count, trans) - - def translate_formatted_value(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译裸 FormattedValue(f"{expr:spec}" 无字面量时解析器返回 FormattedValue 而非 JoinedStr)""" - if node is None or builder is None or trans is None: - return None - fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(node) - if fv is None or fv.value is None: - return None - fmt_buf: str = pool.alloc(FSTR_BUF_SIZE) - if fmt_buf is None: - return None - fmt_buf[0] = '\0' - arg_head: llvmlite.Value | t.CPtr = None - arg_tail: llvmlite.Value | t.CPtr = None - arg_count: int = 0 - val: llvmlite.Value | t.CPtr = self.translate_value( - builder, pool, mod, fv.value, None, 0, trans) - if val is None: - # fail-fast:裸 FormattedValue 翻译失败必须终止编译,绝不在 - HandlesType.fatal_error( - fv.value, "f-string 格式化值翻译失败(表达式返回 None)", "TypeError") - else: - c_fmt: str = None - if fv.format_spec is not None: - c_fmt = self._fstr_parse_format_spec(pool, fv.format_spec, val, fv.value) - if c_fmt is None: - c_fmt = self._fstr_infer_c_fmt(pool, val, fv.value, trans) - if c_fmt is None: - # fail-fast:f-string 格式无法推断(值类型缺失),立即终止编译 - HandlesType.fatal_error(fv.value, "f-string 格式无法推断(值类型缺失)", "TypeError") - if string.strlen(fmt_buf) + string.strlen(c_fmt) < FSTR_BUF_SIZE - 1: - string.strcat(fmt_buf, c_fmt) - cast_val: llvmlite.Value | t.CPtr = self._fstr_cast_value( - builder, pool, val, c_fmt, fv.value, trans) - if cast_val is None: - cast_val = val - cast_val.Next = None - arg_head = cast_val - arg_tail = cast_val - arg_count = 1 - return self._fstr_finalize(builder, pool, mod, fmt_buf, arg_head, arg_tail, arg_count, trans) - - def _fstr_finalize(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - fmt_buf: str, - arg_head: llvmlite.Value | t.CPtr, - arg_tail: llvmlite.Value | t.CPtr, - arg_count: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """f-string 尾部:全局格式串 + 固定栈缓冲 + snprintf,返回 i8*""" - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - if fmt_buf is None or fmt_buf[0] == '\0': - # 空 f-string(f"")→ 空字符串常量 - return HandlesExpr.create_global_string(builder, pool, mod, "", trans) - # 格式串 → 全局字符串常量(i8*) - fmt_ptr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string( - builder, pool, mod, fmt_buf, trans) - if fmt_ptr is None: - return None - # 固定栈缓冲 [FSTR_BUF_SIZE x i8],GEP(0,0) 取 i8* - buf_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, FSTR_BUF_SIZE) - buf_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, buf_ty) - if buf_alloca is None: - return None - zero_i32: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - buf_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, buf_ty, i8_ty, buf_alloca, zero_i32) - if buf_ptr is None: - return None - # snprintf(buf, FSTR_BUF_SIZE, fmt, args...) - size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, FSTR_BUF_SIZE) - buf_ptr.Next = size_val - size_val.Next = fmt_ptr - fmt_ptr.Next = arg_head - if arg_tail is not None: - arg_tail.Next = None - llvmlite.build_call(builder, "snprintf", buf_ptr, 3 + arg_count, i32_ty, 1) - return buf_ptr - - def _fstr_append_literal(self, fmt_buf: str, - lit: str) -> None: - """追加字面量到格式串(% 转义为 %%)""" - if fmt_buf is None or lit is None: - return - cur_len: t.CSizeT = string.strlen(fmt_buf) - rem: t.CSizeT = FSTR_BUF_SIZE - 1 - cur_len - if rem == 0: - return - src_len: t.CSizeT = string.strlen(lit) - si: t.CSizeT = 0 - while si < src_len and rem > 0: - ch: t.CChar = lit[si] - if ch == '%': - if rem < 2: - break - fmt_buf[cur_len] = '%' - fmt_buf[cur_len + 1] = '%' - cur_len += 2 - rem -= 2 - else: - fmt_buf[cur_len] = ch - cur_len += 1 - rem -= 1 - si += 1 - fmt_buf[cur_len] = '\0' - - def _fstr_append_raw(self, fmt_buf: str, s: str) -> None: - """追加原始字符串(不做 % 转义)""" - if fmt_buf is None or s is None: - return - cur_len: t.CSizeT = string.strlen(fmt_buf) - src_len: t.CSizeT = string.strlen(s) - if cur_len + src_len < FSTR_BUF_SIZE: - string.strcpy(fmt_buf + cur_len, s) - - def _fstr_parse_format_spec(self, pool: memhub.MemBuddy | t.CPtr, - spec_node: ast.AST | t.CPtr, - val: llvmlite.Value | t.CPtr, - arg_node: ast.AST | t.CPtr) -> str: - """Python format_spec → C printf 格式串(pool 分配),无法解析返回 None""" - if spec_node is None or pool is None or val is None: - return None - # 1. 提取 spec 字符串(JoinedStr 仅常量拼接) - spec: str = pool.alloc(FSTR_SPEC_MAX) - if spec is None: - return None - spec[0] = '\0' - sk: int = spec_node.kind() - if sk == ast.ASTKind.JoinedStr: - jss: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(spec_node) - if jss.values is None: - return None - vn: t.CSizeT = len(jss.values) - for vi in range(vn): - vpart: ast.AST | t.CPtr = jss.values.get(vi) - if vpart is None: - continue - if vpart.kind() != ast.ASTKind.Constant: - return None - vcn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(vpart) - if vcn.const_kind != ast.CONST_STR or vcn.str_val is None: - return None - if string.strlen(spec) + string.strlen(vcn.str_val) < FSTR_SPEC_MAX - 1: - string.strcat(spec, vcn.str_val) - elif sk == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(spec_node) - if cn.const_kind != ast.CONST_STR or cn.str_val is None: - return None - string.strncpy(spec, cn.str_val, FSTR_SPEC_MAX - 1) - else: - return None - slen: t.CSizeT = string.strlen(spec) - if slen == 0: - return None - - # 2. 逐段解析: [fill]align / sign / # / 0 / width / , / .precision / type - pos: t.CSizeT = 0 - align_char: t.CChar = 0 - if pos < slen: - ch0: t.CChar = spec[pos] - if ch0 == '<' or ch0 == '>' or ch0 == '^' or ch0 == '=': - align_char = ch0 - pos += 1 - elif pos + 1 < slen: - ch1: t.CChar = spec[pos + 1] - if ch1 == '<' or ch1 == '>' or ch1 == '^' or ch1 == '=': - align_char = ch1 - pos += 2 - c_flags: str = pool.alloc(FSTR_FMT_MAX) - c_width: str = pool.alloc(32) - c_prec: str = pool.alloc(32) - if c_flags is None or c_width is None or c_prec is None: - return None - c_flags[0] = '\0' - c_width[0] = '\0' - c_prec[0] = '\0' - # sign - if pos < slen and (spec[pos] == '+' or spec[pos] == '-' or spec[pos] == ' '): - if spec[pos] == '+': - string.strcat(c_flags, "+") - elif spec[pos] == ' ': - string.strcat(c_flags, " ") - pos += 1 - # alt '#' - if pos < slen and spec[pos] == '#': - string.strcat(c_flags, "#") - pos += 1 - # zero '0' - if pos < slen and spec[pos] == '0': - string.strcat(c_flags, "0") - pos += 1 - # 左对齐 '<'/'^' → '-'(与 0 同时存在时 C 语义 '-' 优先) - if align_char == '<' or align_char == '^': - string.strcat(c_flags, "-") - # width digits - while pos < slen and spec[pos] >= '0' and spec[pos] <= '9': - wl: t.CSizeT = string.strlen(c_width) - if wl < 30: - c_width[wl] = spec[pos] - c_width[wl + 1] = '\0' - pos += 1 - # comma ',' → C printf 不支持千分位,忽略 - if pos < slen and spec[pos] == ',': - pos += 1 - # .precision - if pos < slen and spec[pos] == '.': - string.strcat(c_prec, ".") - pos += 1 - while pos < slen and spec[pos] >= '0' and spec[pos] <= '9': - pl: t.CSizeT = string.strlen(c_prec) - if pl < 30: - c_prec[pl] = spec[pos] - c_prec[pl + 1] = '\0' - pos += 1 - if string.strlen(c_prec) == 1: - return None # 只有 '.' 无效 - # type char - fmt_type: t.CChar = 0 - if pos < slen: - fmt_type = spec[pos] - pos += 1 - if pos != slen: - return None # 多余字符无法解析 - - # 3. 长度修饰(按值类型位宽) - len_mod: str = pool.alloc(4) - if len_mod is None: - return None - len_mod[0] = '\0' - ibits: int = HandlesExpr.get_llvm_type_bits(val.Ty) - if ibits == 64: - string.strcpy(len_mod, "ll") - elif ibits == 32: - string.strcpy(len_mod, "l") - elif ibits == 16: - string.strcpy(len_mod, "h") - elif ibits == 8: - string.strcpy(len_mod, "hh") - - # 4. 组装 C 格式串 - out: str = pool.alloc(FSTR_FMT_MAX) - if out is None: - return None - out[0] = '\0' - string.strcat(out, "%") - string.strcat(out, c_flags) - string.strcat(out, c_width) - string.strcat(out, c_prec) - if fmt_type == 0: - # 无 type:按值类型推断 - fbits2: int = HandlesExpr.get_llvm_float_bits(val.Ty) - if ibits != 0: - if ibits == 8: - string.strcat(out, "c") - elif ibits == 1: - string.strcat(out, "d") - else: - string.strcat(out, len_mod) - string.strcat(out, "d") - elif fbits2 != 0: - string.strcat(out, "f") - elif HandlesExpr.is_ptr_type(val.Ty) != 0: - string.strcat(out, "s") - else: - string.strcat(out, "d") - elif fmt_type == 'c': - string.strcat(out, "c") - elif fmt_type == 'f' or fmt_type == 'F': - string.strcat(out, "f") - elif fmt_type == 'e' or fmt_type == 'E' or fmt_type == 'g' or fmt_type == 'G': - tmp_ch: str = pool.alloc(2) - if tmp_ch is None: - return None - tmp_ch[0] = fmt_type - tmp_ch[1] = '\0' - string.strcat(out, tmp_ch) - elif fmt_type == 's': - string.strcat(out, "s") - elif fmt_type == '%': - string.strcat(out, "%") - elif fmt_type == 'b': - return None # 二进制不支持 - elif fmt_type == 'd' or fmt_type == 'i': - string.strcat(out, len_mod) - string.strcat(out, "d") - elif fmt_type == 'x' or fmt_type == 'X' or fmt_type == 'o' or fmt_type == 'u': - string.strcat(out, len_mod) - tmp_ch2: str = pool.alloc(2) - if tmp_ch2 is None: - return None - tmp_ch2[0] = fmt_type - tmp_ch2[1] = '\0' - string.strcat(out, tmp_ch2) - else: - return None - return out - - def _fstr_infer_c_fmt(self, pool: memhub.MemBuddy | t.CPtr, - val: llvmlite.Value | t.CPtr, - arg_node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr) -> str: - """无 format_spec 时按值类型推断 C printf 格式(对齐 TPC 无 spec 分支,带 % 前缀)""" - if val is None or pool is None: - return None - out: str = pool.alloc(16) - if out is None: - return None - out[0] = '\0' - ibits: int = HandlesExpr.get_llvm_type_bits(val.Ty) - fbits: int = HandlesExpr.get_llvm_float_bits(val.Ty) - if ibits == 1: - return "%d" # bool - if ibits == 8: - return "%c" # 字符 - if ibits != 0: - if self._node_type_unsigned(pool, arg_node, trans) != 0: - if ibits == 64: - string.strcpy(out, "%llu") - else: - string.strcpy(out, "%u") - else: - if ibits == 64: - string.strcpy(out, "%lld") - else: - string.strcpy(out, "%d") - return out - if fbits != 0: - return "%f" - if HandlesExpr.is_ptr_type(val.Ty) != 0: - return "%s" - # fail-fast:值类型缺失(非整数/浮点/指针),无法推断 C 格式,立即终止编译 - HandlesType.fatal_error(arg_node, "f-string 格式无法推断(值类型缺失)", "TypeError") - return None - - def _fstr_cast_value(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - val: llvmlite.Value | t.CPtr, - c_fmt: str, - arg_node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """按 C 格式转换值类型(i8/i16→i32、bool→i32、f32→f64)""" - if val is None or c_fmt is None: - return None - # 找格式类型字符(最后一个字母,忽略 l/h 长度修饰) - fmt_char: t.CChar = 0 - flen: t.CSizeT = string.strlen(c_fmt) - fi: t.CSizeT = flen - while fi > 0: - fi -= 1 - ch: t.CChar = c_fmt[fi] - if ch == '%': - break - if (ch >= 'a' and ch <= 'z') or (ch >= 'A' and ch <= 'Z'): - if ch != 'l' and ch != 'h': - fmt_char = ch - break - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if fmt_char == 's': - return val - if fmt_char == 'c': - ibits: int = HandlesExpr.get_llvm_type_bits(val.Ty) - if ibits != 0 and ibits < 32: - return llvmlite.build_zext(builder, val, i32_ty) - return val - if fmt_char == 'd' or fmt_char == 'i' or fmt_char == 'x' \ - or fmt_char == 'X' or fmt_char == 'o' or fmt_char == 'u': - ibits = HandlesExpr.get_llvm_type_bits(val.Ty) - if ibits == 1: - return llvmlite.build_zext(builder, val, i32_ty) - if ibits == 8 or ibits == 16: - if self._node_type_unsigned(pool, arg_node, trans) != 0: - return llvmlite.build_zext(builder, val, i32_ty) - return llvmlite.build_sext(builder, val, i32_ty) - return val - if fmt_char == 'f' or fmt_char == 'e' or fmt_char == 'E' \ - or fmt_char == 'g' or fmt_char == 'G': - fbits: int = HandlesExpr.get_llvm_float_bits(val.Ty) - if fbits == 32: - return llvmlite.build_fpext(builder, val, llvmlite.Double(pool)) - return val - return val - - # ============================================================ - # 翻译三元表达式 IfExp(test, body, orelse) - # - # 生成: cond ? body : orelse - # then_blk: 翻译 body → br merge - # else_blk: 翻译 orelse → br merge - # merge_blk: phi [body_val, then_blk], [orelse_val, else_blk] - # ============================================================ - def translate_ifexp(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译三元表达式 (body if test else orelse),返回 phi 结果 Value""" - if node is None or builder is None or trans is None: - return None - ie: ast.IfExp | t.CPtr = (ast.IfExp | t.CPtr)(node) - if ie is None: - return None - - func: llvmlite.Function | t.CPtr = trans._cur_func - if func is None: - return None - - # 1. 求值条件 - cond_val: llvmlite.Value | t.CPtr = self.translate_value( - builder, pool, mod, ie.test, None, 0, trans) - if cond_val is None: - return None - # 转换为 i1 - cond_bits: int = self.get_llvm_type_bits(cond_val.Ty) - if cond_bits == 1: - cond_i1: llvmlite.Value | t.CPtr = cond_val - else: - if self.is_ptr_type(cond_val.Ty) != 0: - # 指针类型:与 null 比较 - null_cond: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cond_val.Ty, "null") - cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, null_cond) - else: - zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, zero) - - # 2. 创建三个基本块 - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - name_buf: str = pool.alloc(32) - if name_buf is None: - return None - viperlib.snprintf(name_buf, 32, "ifexp.then.%d", cnt) - then_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - viperlib.snprintf(name_buf, 32, "ifexp.else.%d", cnt) - else_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - viperlib.snprintf(name_buf, 32, "ifexp.merge.%d", cnt) - merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - if then_bb is None or else_bb is None or merge_bb is None: - return None - - # 3. 条件跳转 - llvmlite.build_cond_br(builder, cond_i1, then_bb, else_bb) - - # 4. then 分支 - llvmlite.position_at_end(builder, then_bb) - body_val: llvmlite.Value | t.CPtr = self.translate_value( - builder, pool, mod, ie.body, None, 0, trans) - then_blk_for_phi: llvmlite.BasicBlock | t.CPtr = trans._cur_builder.CurBlock - if body_val is None: - # fail-fast:三元表达式 then 分支翻译失败,立即终止编译(暴露上游根因) - HandlesType.fatal_error(ie.body, "三元表达式分支翻译失败", "TypeError") - # 暂不 br,等类型对齐后再 br - - # 5. else 分支 - llvmlite.position_at_end(builder, else_bb) - orelse_val: llvmlite.Value | t.CPtr = self.translate_value( - builder, pool, mod, ie.orelse, None, 0, trans) - else_blk_for_phi: llvmlite.BasicBlock | t.CPtr = trans._cur_builder.CurBlock - if orelse_val is None: - # fail-fast:三元表达式 else 分支翻译失败,立即终止编译(暴露上游根因) - HandlesType.fatal_error(ie.orelse, "三元表达式分支翻译失败", "TypeError") - # 暂不 br,等类型对齐后再 br - - # 类型对齐 (两分支类型可能不同) - # 必须在各自分支中执行 coerce_to_type,确保 merge 块中 PHI 是第一条指令 - # (否则 coerce_to_type 生成的 sext/zext/ptrtoint/inttoptr 指令在 PHI 之前,违反 LLVM 规则) - body_bits: int = self.get_llvm_type_bits(body_val.Ty) - orelse_bits: int = self.get_llvm_type_bits(orelse_val.Ty) - body_is_ptr: int = self.is_ptr_type(body_val.Ty) - orelse_is_ptr: int = self.is_ptr_type(orelse_val.Ty) - # 情况0: 一侧是指针,另一侧是整数(如 i64 vs i8* null) - # 必须优先处理,因为 Ptr 的 bits=0 会导致下面三个分支全部跳过 - # 选择 body_val.Ty 作为 phi_ty(then 分支优先),orelse_val 对齐到它 - # coerce_to_type 内部会调用 ptrtoint(指针→整数)或 inttoptr(整数→指针) - if body_is_ptr != orelse_is_ptr: - llvmlite.position_at_end(builder, else_blk_for_phi) - orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node) - elif body_bits > orelse_bits and orelse_bits > 0: - # 在 else 块中转换 orelse_val - llvmlite.position_at_end(builder, else_blk_for_phi) - orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node) - elif orelse_bits > body_bits and body_bits > 0: - # 回到 then 块转换 body_val - llvmlite.position_at_end(builder, then_blk_for_phi) - body_val = self.coerce_to_type(builder, body_val, orelse_val.Ty, node) - elif body_bits == orelse_bits and body_bits > 0: - # bits 相同但类型不同(如 i64 vs Ptr):null 不能用于 i64 PHI - # 此分支理论上不会触发(已被情况0覆盖),保留作为防御 - if self.is_ptr_type(body_val.Ty) != self.is_ptr_type(orelse_val.Ty): - llvmlite.position_at_end(builder, else_blk_for_phi) - orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node) - - # 现在分别在 then/else 块中 br 到 merge(在类型转换之后) - llvmlite.position_at_end(builder, then_blk_for_phi) - llvmlite.build_br(builder, merge_bb) - llvmlite.position_at_end(builder, else_blk_for_phi) - llvmlite.build_br(builder, merge_bb) - - # 6. merge 块: phi(PHI 是 merge 块的第一条指令) - llvmlite.position_at_end(builder, merge_bb) - - phi_ty: llvmlite.LLVMType | t.CPtr = body_val.Ty - if phi_ty is None: - # fail-fast:三元表达式分支类型缺失,立即终止编译(暴露上游根因) - HandlesType.fatal_error(node, "三元表达式分支类型缺失", "TypeError") - - inc1: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming( - pool, body_val, then_blk_for_phi) - inc2: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming( - pool, orelse_val, else_blk_for_phi) - if inc1 is None or inc2 is None: - return None - # 链表顺序: inc1 (head) -> inc2 (tail) - # 之前错误写成 inc2.Next = inc1,导致 build_phi 从 inc1 遍历时 - # inc1.Next 为 None,只输出一个 phi 条目,引发 LLVM 验证错误: - # "PHINode should have one entry for each predecessor" - inc1.Next = inc2 - return llvmlite.build_phi(builder, phi_ty, inc1, 2) - - # ============================================================ - # 翻译比较表达式 Compare(left, ops, comparators) - # ============================================================ - def should_zext_widen(self, pool: memhub.MemBuddy | t.CPtr, - narrow_val: llvmlite.Value | t.CPtr, - wide_val: llvmlite.Value | t.CPtr, - narrow_node: ast.AST | t.CPtr = None) -> int: - """判断整数拓宽方向:1=zext(无符号语义),0=sext - - 对齐 TPC 的 _check_node_unsigned / HandlesExprOps 拓宽规则: - 1. i1 (bool) → zext(1 保持 1,而非 sext 的 0xFF...) - 2. i8 → zext(系统编程中 i8 几乎总是无符号字节) - 3. 宽侧是常量且其值超出窄侧位宽的有符号范围 → zext - (常量"想要"无符号解释,如 0xAABBCCDD > INT32_MAX 与 - t.CUInt32T 值比较,sext 会把 0xAABBCCDD 变成 - 0xFFFFFFFFAABBCCDD 导致恒不等) - """ - if narrow_val is None or narrow_val.Ty is None: - return 0 - narrow_bits: int = self.get_llvm_type_bits(narrow_val.Ty) - if narrow_bits == 1: - return 1 - if narrow_bits == 8: - return 1 - # 宽侧常量启发式 - if wide_val is not None and wide_val.IsConst == 1: - wide_bits: int = self.get_llvm_type_bits(wide_val.Ty) - if wide_bits > narrow_bits and narrow_bits < 64: - signed_max: t.CInt64T = (t.CInt64T(1) << (narrow_bits - 1)) - 1 - if wide_val.IntVal > signed_max: - return 1 - # 窄侧 AST 节点解析为无符号类型(如 t.CUIntXXT 字面量/强转) - if narrow_node is not None: - if self._node_type_unsigned(pool, narrow_node) != 0: - return 1 - return 0 - - def _node_type_unsigned(self, pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> int: - """轻量判断 AST 节点是否解析为无符号整数类型(1=是,0=否/未知) - - 覆盖常见形态(对齐 TPC _check_node_unsigned 的 Call/Subscript 分支): - - t.CUInt8T/CUInt16T/CUInt32T/CUInt64T/CUnsigned* 等显式无符号类型强转调用 - - 无符号类型名的 Name 引用(如 UInt32T 别名) - - 变量名(trans 可用时):查询 SymTab 中变量的 AnnotClassName(如 v: t.CUInt32T) - """ - if node is None: - return 0 - k: int = node.kind() - if k == ast.ASTKind.Call: - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - 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 and string.strcmp(mod_nm.id, "t") == 0 \ - and at.attr is not None: - if self._type_name_unsigned(at.attr) != 0: - return 1 - return 0 - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm.id is not None: - # 1) 名字本身是无符号类型名(如 UInt32T 别名) - if self._type_name_unsigned(nm.id) != 0: - return 1 - # 2) 变量注解类型为无符号类型(trans 可用时查 SymTab) - if trans is not None: - ve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm.id) - if ve is not None and ve.AnnotClassName is not None: - if self._type_name_unsigned(ve.AnnotClassName) != 0: - return 1 - return 0 - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - if self._node_type_unsigned(pool, bop.left, trans) != 0: - return 1 - if self._node_type_unsigned(pool, bop.right, trans) != 0: - return 1 - return 0 - if k == ast.ASTKind.UnaryOp: - uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) - if self._node_type_unsigned(pool, uop.operand, trans) != 0: - return 1 - return 0 - if k == ast.ASTKind.Subscript: - # 数组/指针下标: md5_buf[i](t.CArray[t.CUInt8T, N])或 buf[i] - # (形参 t.CUInt8T | t.CPtr)元素是无符号整型 → printf("%02x", ...) zext。 - sub_su: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - if sub_su.value is not None and sub_su.value.kind() == ast.ASTKind.Name: - snm_su: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_su.value) - if snm_su.id is not None and trans is not None: - ve_su: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, snm_su.id) - if ve_su is not None and ve_su.AnnotClassName is not None: - if self._annot_str_unsigned(ve_su.AnnotClassName) != 0: - return 1 - return 0 - return 0 - - def _type_name_unsigned(self, type_name: str) -> int: - """类型名是否为无符号整数类型(精确匹配,避免子串误伤如 nUIntCount)""" - if type_name is None: - return 0 - # t.CUIntXXT 形式 - if string.strcmp(type_name, "CUInt8T") == 0: return 1 - if string.strcmp(type_name, "CUInt16T") == 0: return 1 - if string.strcmp(type_name, "CUInt32T") == 0: return 1 - if string.strcmp(type_name, "CUInt64T") == 0: return 1 - # stdint 裸别名(from stdint import *) - if string.strcmp(type_name, "UInt8T") == 0: return 1 - if string.strcmp(type_name, "UInt16T") == 0: return 1 - if string.strcmp(type_name, "UInt32T") == 0: return 1 - if string.strcmp(type_name, "UInt64T") == 0: return 1 - # CUnsigned* 形式 - if string.strcmp(type_name, "CUnsignedChar") == 0: return 1 - if string.strcmp(type_name, "CUnsignedShort") == 0: return 1 - if string.strcmp(type_name, "CUnsignedInt") == 0: return 1 - if string.strcmp(type_name, "CUnsignedLong") == 0: return 1 - if string.strcmp(type_name, "CUnsignedLongLong") == 0: return 1 - # 常见无符号别名 - if string.strcmp(type_name, "BYTE") == 0: return 1 - if string.strcmp(type_name, "UCHAR") == 0: return 1 - if string.strcmp(type_name, "USHORT") == 0: return 1 - if string.strcmp(type_name, "UINT") == 0: return 1 - if string.strcmp(type_name, "ULONG") == 0: return 1 - return 0 - - def _annot_str_unsigned(self, annot: str) -> int: - """检查类型注解字符串是否引用无符号整型(子串扫描) - - 用于复合注解(t.CArray[t.CUInt8T, 16] / t.CUInt8T | t.CPtr), - _type_name_unsigned 的精确匹配对这类串不适用。 - """ - if annot is None: - return 0 - if string.strstr(annot, "CUInt8T") is not None: return 1 - if string.strstr(annot, "CUInt16T") is not None: return 1 - if string.strstr(annot, "CUInt32T") is not None: return 1 - if string.strstr(annot, "CUInt64T") is not None: return 1 - if string.strstr(annot, "CUnsigned") is not None: return 1 - if string.strstr(annot, "BYTE") is not None: return 1 - if string.strstr(annot, "UCHAR") is not None: return 1 - if string.strstr(annot, "USHORT") is not None: return 1 - if string.strstr(annot, "UINT") is not None: return 1 - if string.strstr(annot, "ULONG") is not None: return 1 - return 0 - - def translate_compare(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译比较表达式,返回 i1 结果""" - cmp: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) - if cmp is None: - return None - - ops_list: list[t.CInt] | t.CPtr = (list[t.CInt] | t.CPtr)(cmp.ops) - if ops_list is None or len(ops_list) == 0: - return None - op: int = ops_list.get(0) - - comparators: list[ast.AST | t.CPtr] | t.CPtr = cmp.comparators - if comparators is None or len(comparators) == 0: - return None - rhs_node: ast.AST | t.CPtr = comparators.get(0) - rhs: llvmlite.Value | t.CPtr = self.translate_value( - builder, pool, mod, rhs_node, None, 0, trans) - if rhs is None: - return None - - # === None 比较优化: x == None / x != None 走身份比较(icmp eq/ne null)=== - # 避免对结构体指针生成无效的 __eq__/__ne__ 调用(方法未定义但类有 SHA1 时 - # try_operator_overload 会误生成 call void @...__eq__(...) 导致链接错误) - # 语义依据: Python 中 == None / != None 默认走身份比较,不调用 __eq__/__ne__ - lhs_node: ast.AST | t.CPtr = cmp.left - cmp_with_none: int = 0 - if op == ast.OpKind.Eq or op == ast.OpKind.Ne or op == ast.OpKind.Is or op == ast.OpKind.IsNot: - if rhs_node is not None and rhs_node.kind() == ast.ASTKind.Constant: - rhs_cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(rhs_node) - if rhs_cn is not None and rhs_cn.const_kind == ast.CONST_NONE: - cmp_with_none = 1 - if cmp_with_none == 0 and lhs_node is not None and lhs_node.kind() == ast.ASTKind.Constant: - lhs_cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(lhs_node) - if lhs_cn is not None and lhs_cn.const_kind == ast.CONST_NONE: - cmp_with_none = 1 - - # === 指针判空模式: ptr != 0 / ptr == 0 === - # 跳过运算符重载走身份比较(icmp null)。跨模块类(如 cpython.PyObject) - # 未定义 __eq__/__ne__ 时,try_operator_overload 无法判定方法不存在 - # (类在依赖模块,cls_sha1 != trans.ModuleSha1),会误发幽灵 - # `call void @...__ne__` → 链接 undefined reference(CPythonTest main.vp - # `py_num != 0` 根因)。C 语义:指针与字面量 0 比较 = 判空。 - cmp_zero: int = 0 - if op == ast.OpKind.Eq or op == ast.OpKind.Ne: - if rhs_node is not None and self._is_zero_int_literal(rhs_node) != 0: - cmp_zero = 1 - if cmp_zero == 0 and lhs_node is not None and self._is_zero_int_literal(lhs_node) != 0: - cmp_zero = 1 - - # === 比较运算符重载路径 1: lhs 是 Name 且对应结构体变量 === - # 对于值类型变量(如 cnt: Counter),用 alloca 指针尝试重载 - # None 比较跳过重载(走身份比较) - if cmp_with_none == 0 and lhs_node is not None and lhs_node.kind() == ast.ASTKind.Name and trans is not None: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(lhs_node) - if nm is not None and nm.id is not None: - lhs_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, nm.id) - if lhs_alloca is not None: - if cmp_zero == 0 or self.get_ptr_level(lhs_alloca.Ty) == 0: - ovl_self1: llvmlite.Value | t.CPtr = lhs_alloca - # Ptr(Ptr(Struct)) 对象存储槽:load 出对象指针作 self - # (与 translate_binop 路径 1 一致,避免槽地址当对象地址) - if lhs_alloca.Ty is not None and lhs_alloca.Ty.Pointee is not None \ - and HandlesExpr.is_ptr_type(lhs_alloca.Ty.Pointee) != 0: - load_self1: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, lhs_alloca.Ty.Pointee, lhs_alloca) - if load_self1 is not None: - ovl_self1 = load_self1 - ovl_result: llvmlite.Value | t.CPtr = self.try_operator_overload( - pool, builder, mod, ovl_self1, rhs, op, trans, 1) - if ovl_result is not None: - return ovl_result - - # 正常翻译 lhs - lhs: llvmlite.Value | t.CPtr = self.translate_value( - builder, pool, mod, cmp.left, None, 0, trans) - if lhs is None: - return None - - # === in / not in:容器右操作数调用 __contains__(对齐 TPC - # HandlesExprOps.py L261-281)。x in y → y.__contains__(x); - # x not in y → !y.__contains__(x)。容器无 __contains__ → - # 返回 i1 0(TPC 同:恒 False)。 - if op == ast.OpKind.In or op == ast.OpKind.NotIn: - cn_st: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(rhs) - if cn_st is not None: - cn_cls: str = HandlesStruct.get_class_name_by_type(pool, cn_st) - if cn_cls is not None: - cn_lookup: str = pool.alloc(128) - if cn_lookup is not None: - viperlib.snprintf(cn_lookup, 128, "%s.__contains__", cn_cls) - cn_fn: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module( - mod, cn_lookup) - if cn_fn is not None: - cn_ret: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(cn_fn) - cn_fn_name: str = llvmlite.function_get_name(cn_fn) - if cn_ret is not None and cn_fn_name is not None: - # self 参数(容器)按 __contains__ 首参类型对齐 - cn_self: llvmlite.Value | t.CPtr = rhs - cn_first: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(cn_fn) - if cn_first is not None: - cn_self_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cn_first) - if cn_self_ty is not None: - cn_self = llvmlite.build_bitcast(builder, rhs, cn_self_ty) - if cn_self is not None: - # 参数链表: self → key(独立 null 结尾) - cn_self.Next = lhs - lhs.Next = None - cn_res: llvmlite.Value | t.CPtr = llvmlite.build_call( - builder, cn_fn_name, cn_self, 2, cn_ret, 0) - if cn_res is not None: - # 归一化到 i1(__contains__ 返回 t.CInt/i32 等) - cn_i1: llvmlite.Value | t.CPtr = cn_res - match cn_ret: - case llvmlite.LLVMType.Int(cn_bits): - if cn_bits > 1: - cn_zero: llvmlite.Value | t.CPtr = llvmlite.ConstInt( - pool, cn_ret, 0, "0") - if cn_zero is not None: - cn_i1 = llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, cn_res, cn_zero) - case _: - pass - if op == ast.OpKind.NotIn: - i1_ty_ni: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - if i1_ty_ni is not None and cn_i1 is not None: - one_i1_ni: llvmlite.Value | t.CPtr = llvmlite.ConstInt( - pool, i1_ty_ni, 1, "1") - if one_i1_ni is not None: - cn_i1 = llvmlite.build_xor(builder, cn_i1, one_i1_ni) - if cn_i1 is not None: - return cn_i1 - # 容器无 __contains__:TPC 语义恒 False(i1 0) - i1_ty_in: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - if i1_ty_in is not None: - return llvmlite.ConstInt(pool, i1_ty_in, 0, "0") - return None - - # === 比较运算符重载路径 2: lhs 是 Ptr(Struct) === - # Is/IsNot 不在 _cmpop_to_dunder 映射中,会自动返回 None 回退原生比较 - # None 比较跳过重载(走身份比较);指针判空(cmp_zero + 指针)同样跳过 - if cmp_with_none == 0 and (cmp_zero == 0 or self.get_ptr_level(lhs.Ty) == 0): - ovl_result2: llvmlite.Value | t.CPtr = self.try_operator_overload( - pool, builder, mod, lhs, rhs, op, trans, 1) - if ovl_result2 is not None: - return ovl_result2 - - predicate: int = llvmlite.ICMP_SLT - if op == ast.OpKind.Lt: - predicate = llvmlite.ICMP_SLT - elif op == ast.OpKind.Le: - predicate = llvmlite.ICMP_SLE - elif op == ast.OpKind.Gt: - predicate = llvmlite.ICMP_SGT - elif op == ast.OpKind.Ge: - predicate = llvmlite.ICMP_SGE - elif op == ast.OpKind.Eq: - predicate = llvmlite.ICMP_EQ - elif op == ast.OpKind.Ne: - predicate = llvmlite.ICMP_NE - elif op == ast.OpKind.Is: - # `x is y` → 指针/值相等比较 - predicate = llvmlite.ICMP_EQ - elif op == ast.OpKind.IsNot: - # `x is not y` → 指针/值不等比较 - predicate = llvmlite.ICMP_NE - - # === 类型安全检查(BUG2 修复)=== - # 规则: - # - 数值(0) vs 数值(0) → 允许(无关类型,按位宽 sext 对齐) - # - 一级指针(1) vs 一级指针(1) → 允许(无关 pointee 类型,地址比较) - # - 数值(0) vs 指针(1+) → 禁止(fast-fail,除 None 比较外) - # - 不同级指针(1 vs 2 等) → 禁止(fast-fail) - # - # None 比较跳过此检查(None 被翻译为 null 指针或 0,与任意指针/数值比较合法) - if cmp_with_none == 0: - lhs_ptr_level: int = self.get_ptr_level(lhs.Ty) - rhs_ptr_level: int = self.get_ptr_level(rhs.Ty) - if lhs_ptr_level != rhs_ptr_level: - # 指针 vs 整数字面量 0(判空模式 ptr != 0 / ptr == 0): - # 0 视为 NULL,转成与指针侧同类型的 null 指针(icmp 需要同类型), - # 不报类型不匹配(ClassArrayTest 的 if ptr != 0 等常见模式)。 - zero_is_rhs: int = 0 - zero_is_lhs: int = 0 - if rhs_ptr_level == 0 and self._is_zero_int_literal(rhs_node) != 0: - zero_is_rhs = 1 - if lhs_ptr_level == 0 and self._is_zero_int_literal(lhs_node) != 0: - zero_is_lhs = 1 - if zero_is_rhs != 0 or zero_is_lhs != 0: - if zero_is_rhs != 0: - rhs = llvmlite.ConstNull(pool, lhs.Ty, "null") - else: - lhs = llvmlite.ConstNull(pool, rhs.Ty, "null") - else: - # 指针 vs 非零整数(C 哨兵值模式,如 w32.win32base.INVALID_HANDLE_VALUE = -1): - # 对齐 TPC HandlesExprOps.py L388-398 —— 指针 ptrtoint 成整数做地址值比较。 - # (指针 vs 整数字面量 0 已在上方转 null 处理;此处处理非零整数哨兵) - if lhs_ptr_level != 0 and rhs_ptr_level == 0: - lhs = llvmlite.build_ptrtoint(builder, lhs, rhs.Ty) - elif rhs_ptr_level != 0 and lhs_ptr_level == 0: - rhs = llvmlite.build_ptrtoint(builder, rhs, lhs.Ty) - else: - # 不同级指针(1 vs 2 等)→ 禁止(fast-fail) - HandlesType.fatal_error( - cmp, - f"比较类型不匹配: 不同级指针比较 (lhs 层级={lhs_ptr_level}, rhs 层级={rhs_ptr_level})", - "TypeError") - else: - # None 比较: None 被翻译为 i8* null(一级指针) - # 如果 lhs 是指针,将 rhs (i8* null) bitcast 为 lhs 的指针类型 - # 如果 lhs 是数值,将 rhs 转为数值 0(走正常整数比较) - # 如果 lhs 是结构体值类型,结构体永远不等于 None,返回常量 i1 - lhs_ptr_level_none: int = self.get_ptr_level(lhs.Ty) - rhs_ptr_level_none: int = self.get_ptr_level(rhs.Ty) - if lhs_ptr_level_none != 0 and rhs_ptr_level_none != 0: - # 两边都是指针,类型可能不同(如 lhs=Struct*, rhs=i8* null) - # 由下方 bitcast 对齐处理,此处不处理 - pass - elif lhs_ptr_level_none != 0 and rhs_ptr_level_none == 0: - # lhs 是指针, rhs 是数值 → 将 rhs 转为同层级 null 指针 - rhs = llvmlite.ConstNull(pool, lhs.Ty, "null") - elif rhs_ptr_level_none != 0 and lhs_ptr_level_none == 0: - # 检查 lhs 是否是结构体值类型(非指针的 Struct) - lhs_is_struct_none: int = 0 - match lhs.Ty: - case llvmlite.LLVMType.Struct(_, _, _): - lhs_is_struct_none = 1 - case _: - lhs_is_struct_none = 0 - if lhs_is_struct_none != 0: - # 结构体值永远不等于 None:==/is 返回 false,!=/is not 返回 true - if op == ast.OpKind.Eq or op == ast.OpKind.Is: - return llvmlite.const_int(pool, 1, 0) - else: # Ne, IsNot - return llvmlite.const_int(pool, 1, 1) - # lhs 是数值, rhs 是 i8* null → 将 rhs 转为数值 0(保持 lhs 不变) - rhs = llvmlite.const_int32(pool, 0) - - # 类型对齐:icmp 要求两边类型相同 - # 仅对数值类型做对齐(指针类型无需对齐,LLVM 允许同层级指针直接 icmp) - # i1 (bool) 侧用 zext 对齐(1 保持 1,而非 sext 的 0xFF...) - lhs_bits: int = self.get_llvm_type_bits(lhs.Ty) - rhs_bits: int = self.get_llvm_type_bits(rhs.Ty) - if lhs_bits != 0 and rhs_bits != 0 and lhs_bits != rhs_bits: - if lhs_bits < rhs_bits: - if self.should_zext_widen(pool, lhs, rhs, cmp.left) != 0: - lhs = llvmlite.build_zext(builder, lhs, rhs.Ty) - else: - lhs = llvmlite.build_sext(builder, lhs, rhs.Ty) - else: - if self.should_zext_widen(pool, rhs, lhs, rhs_node) != 0: - rhs = llvmlite.build_zext(builder, rhs, lhs.Ty) - else: - rhs = llvmlite.build_sext(builder, rhs, lhs.Ty) - - # 指针类型对齐:同层级但不同 pointee 类型的指针需要 bitcast 统一类型 - # 例如 i8* vs Struct* → 将 rhs bitcast 为 lhs 的类型 - if lhs_bits == 0 and rhs_bits == 0: - lhs_is_ptr_now: int = self.is_ptr_type(lhs.Ty) - rhs_is_ptr_now: int = self.is_ptr_type(rhs.Ty) - if lhs_is_ptr_now != 0 and rhs_is_ptr_now != 0: - # 两边都是指针,用 TypePrint 比较类型字符串 - lhs_ty_buf: str = pool.alloc(128) - rhs_ty_buf: str = pool.alloc(128) - if lhs_ty_buf is not None and rhs_ty_buf is not None: - llvmlite.TypePrint(lhs_ty_buf, 128, lhs.Ty, pool) - llvmlite.TypePrint(rhs_ty_buf, 128, rhs.Ty, pool) - if string.strcmp(lhs_ty_buf, rhs_ty_buf) != 0: - rhs = llvmlite.build_bitcast(builder, rhs, lhs.Ty) - - # 浮点比较:任一操作数为浮点类型时使用 fcmp 而非 icmp - lhs_fbits: int = self.get_llvm_float_bits(lhs.Ty) - rhs_fbits: int = self.get_llvm_float_bits(rhs.Ty) - if lhs_fbits != 0 or rhs_fbits != 0: - # 浮点类型对齐(fpext/fptrunc) - if lhs_fbits != 0 and rhs_fbits != 0 and lhs_fbits != rhs_fbits: - if lhs_fbits < rhs_fbits: - lhs = llvmlite.build_fpext(builder, lhs, rhs.Ty) - else: - rhs = llvmlite.build_fptrunc(builder, rhs, lhs.Ty) - elif lhs_fbits != 0 and rhs_fbits == 0: - # int → float - rhs = llvmlite.build_si2fp(builder, rhs, lhs.Ty) - elif rhs_fbits != 0 and lhs_fbits == 0: - lhs = llvmlite.build_si2fp(builder, lhs, rhs.Ty) - # 映射比较谓词到 fcmp - fpredicate: int = llvmlite.FCMP_OEQ - if op == ast.OpKind.Eq or op == ast.OpKind.Is: - fpredicate = llvmlite.FCMP_OEQ - elif op == ast.OpKind.Ne or op == ast.OpKind.IsNot: - fpredicate = llvmlite.FCMP_ONE - elif op == ast.OpKind.Lt: - fpredicate = llvmlite.FCMP_OLT - elif op == ast.OpKind.Le: - fpredicate = llvmlite.FCMP_OLE - elif op == ast.OpKind.Gt: - fpredicate = llvmlite.FCMP_OGT - elif op == ast.OpKind.Ge: - fpredicate = llvmlite.FCMP_OGE - return llvmlite.build_fcmp(builder, fpredicate, lhs, rhs) - - return llvmlite.build_icmp(builder, predicate, lhs, rhs) - - # ============================================================ - # 翻译一元运算表达式 UnaryOp(op, operand) - # ============================================================ - def translate_unaryop(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译一元运算(-x, +x, not x, ~x)""" - uo: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) - if uo is None: - return None - - operand: llvmlite.Value | t.CPtr = self.translate_value( - builder, pool, mod, uo.operand, None, 0, trans) - if operand is None: - return None - - # === 一元运算符重载: -obj/+obj/~obj 调用 __neg__/__pos__/__invert__ === - # 仅 USub/UAdd/Invert 有重载语义(not 无 dunder 方法) - if uo.op == ast.OpKind.USub or uo.op == ast.OpKind.UAdd or uo.op == ast.OpKind.Invert: - ovl_u: llvmlite.Value | t.CPtr = self.try_unary_operator_overload( - pool, builder, mod, operand, uo.op, trans) - if ovl_u is not None: - return ovl_u - - if uo.op == ast.OpKind.USub: - # -x - # 浮点类型用 fneg(直接生成 fneg 指令,避免 0.0 - x 的类型不匹配) - operand_fbits: int = self.get_llvm_float_bits(operand.Ty) - if operand_fbits > 0: - return llvmlite.build_fneg(builder, operand) - # 整数类型:-x = 0 - x,根据位宽选择零值常量(避免 i32 与 i64 类型不匹配) - operand_bits: int = self.get_llvm_type_bits(operand.Ty) - zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - if operand_bits == 64: - zero = llvmlite.const_int64(pool, 0) - elif operand_bits > 0 and operand_bits != 32: - # 其他位宽(i8/i16 等):用 i32 零值,operand 会被 coerce - zero = llvmlite.const_int32(pool, 0) - return llvmlite.build_sub(builder, zero, operand) - elif uo.op == ast.OpKind.UAdd: - # +x = x - return operand - elif uo.op == ast.OpKind.Not: - # not x = (x == 0/null),返回 i1 - if self.is_ptr_type(operand.Ty) != 0: - # 指针类型:与 null 比较 - null_op: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, operand.Ty, "null") - return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, operand, null_op) - # 结构体值类型:永远为真(非空),not 返回 false - operand_is_struct_not: int = 0 - match operand.Ty: - case llvmlite.LLVMType.Struct(_, _, _): - operand_is_struct_not = 1 - case _: - operand_is_struct_not = 0 - if operand_is_struct_not != 0: - return llvmlite.const_int(pool, 1, 0) - operand_bits_not: int = self.get_llvm_type_bits(operand.Ty) - zero = llvmlite.const_int32(pool, 0) - if operand_bits_not == 64: - zero = llvmlite.const_int64(pool, 0) - return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, operand, zero) - elif uo.op == ast.OpKind.Invert: - # ~x = x ^ -1 - operand_bits_inv: int = self.get_llvm_type_bits(operand.Ty) - neg1: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, -1) - if operand_bits_inv == 64: - neg1 = llvmlite.const_int64(pool, -1) - return llvmlite.build_xor(builder, operand, neg1) - return operand - - # ============================================================ - # 翻译布尔运算 BoolOp(op, values) — 短路求值,返回 i1 - # - # and: a and b and c → 若 a 为假短路到 merge(返回 a 的 i1),否则求 b, - # 最后一个值直接求值并跳 merge - # or: a or b or c → 若 a 为真短路到 merge(返回 a 的 i1),否则求 b, - # 最后一个值直接求值并跳 merge - # merge 块用 phi 合并所有入边的 i1 - # ============================================================ - def translate_boolop(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - funcs_ptr: t.CPtr = None, - func_count: int = 0, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译布尔运算(and/or)的短路求值,返回 i1""" - bo: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) - if bo is None: - return None - - op: int = bo.op - values: list[ast.AST | t.CPtr] | t.CPtr = bo.values - if values is None: - return None - count: t.CSizeT = len(values) - if count == 0: - return None - if count == 1: - return self.translate_value(builder, pool, mod, values.get(0), - funcs_ptr, func_count, trans) - - func: llvmlite.Function | t.CPtr = builder.Func - if func is None: - return None - - # 创建 merge BB(用 builder.Counter 生成唯一标签名,position_at_end 的 - # move_to_end 保证 BB 文本顺序与控制流顺序一致,标签名用 counter 安全) - cnt: int = builder.Counter - builder.Counter = cnt + 1 - name_buf: str = pool.alloc(32) - if name_buf is None: - return None - viperlib.snprintf(name_buf, 32, "bool.merge.%d", cnt) - merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - # phi 入边链表头/尾 - phi_head: llvmlite.PhiIncoming | t.CPtr = None - phi_tail: llvmlite.PhiIncoming | t.CPtr = None - phi_count: int = count - 1 # 循环次数 - - # 对每个值(除最后一个)求值并短路 - for i in range(count - 1): - val_node: ast.AST | t.CPtr = values.get(i) - val: llvmlite.Value | t.CPtr = self.translate_value( - builder, pool, mod, val_node, - funcs_ptr, func_count, trans) - if val is None: - return None - - # 转为 i1(已经是 i1 的直接用,否则与 0/null 比较) - val_bits: int = self.get_llvm_type_bits(val.Ty) - val_i1: llvmlite.Value | t.CPtr = val - if val_bits != 1: - if self.is_ptr_type(val.Ty) != 0: - # 指针类型:与 null 比较(避免 i8* 与 i32 类型不匹配) - null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, val.Ty, "null") - val_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, val, null_val) - else: - zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - val_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, val, zero) - - # 创建 next BB(求值下一个值) - cnt = builder.Counter - builder.Counter = cnt + 1 - viperlib.snprintf(name_buf, 32, "bool.next.%d", cnt) - next_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - # and: 短路假→merge,真→next;or: 短路真→merge,假→next - if op == ast.OpKind.And: - llvmlite.build_cond_br(builder, val_i1, next_bb, merge_bb) - else: - llvmlite.build_cond_br(builder, val_i1, merge_bb, next_bb) - - # 添加 phi 入边:(val_i1, cond_br 所在 BB) - cur_bb: llvmlite.BasicBlock | t.CPtr = builder.CurBlock - inc: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming(pool, val_i1, cur_bb) - if phi_head is None: - phi_head = inc - phi_tail = inc - else: - phi_tail.Next = inc - phi_tail = inc - - # 定位到 next BB,求值下一个值 - llvmlite.position_at_end(builder, next_bb) - - # 最后一个值:求值后直接跳 merge - last_node: ast.AST | t.CPtr = values.get(count - 1) - last_val: llvmlite.Value | t.CPtr = self.translate_value( - builder, pool, mod, last_node, - funcs_ptr, func_count, trans) - if last_val is None: - return None - last_bits: int = self.get_llvm_type_bits(last_val.Ty) - last_i1: llvmlite.Value | t.CPtr = last_val - if last_bits != 1: - if self.is_ptr_type(last_val.Ty) != 0: - # 指针类型:与 null 比较(避免 i8* 与 i32 类型不匹配) - null_val2: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, last_val.Ty, "null") - last_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, last_val, null_val2) - else: - zero = llvmlite.const_int32(pool, 0) - last_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, last_val, zero) - - llvmlite.build_br(builder, merge_bb) - - cur_bb = builder.CurBlock - inc = llvmlite.new_phi_incoming(pool, last_i1, cur_bb) - if phi_head is None: - phi_head = inc - else: - phi_tail.Next = inc - phi_count += 1 - - # 定位到 merge,创建 phi 合并所有入边 - llvmlite.position_at_end(builder, merge_bb) - i1_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - return llvmlite.build_phi(builder, i1_ty, phi_head, phi_count) - - # ============================================================ - # _build_source_path_from_sha1 - 通过 SHA1 从存储器构建源 .vp/.py 文件路径 - # - # .vpi 文件可能未生成(Phase1 未输出 vpi),此时回退读取源 .py 文件。 - # 从 StubMerger 全局存储器查找 SHA1 对应的相对路径, - # 根据 rel_path 前缀选择基础目录: - # - rel_path 以 "lib/" 开头 → App 源文件,用 {Config.SourceDir}/{rel_path} - # - 其他 → includes 文件,用 {Config.IncludesDir}/{rel_path} - # - # Returns: - # stdlib.malloc 分配的路径字符串(调用者负责 free),None 失败 - # ============================================================ - def _build_source_path_from_sha1(self, sha1: str) -> str: - """通过 SHA1 从全局存储器构建源 .py 文件路径""" - if sha1 is None: - return None - if Config.IncludesDir is None: - return None - # 从 StubMerger 全局存储器获取相对路径数组 - rel_arr_ptr: bytes | t.CPtr = StubMerger.GetSha1StoreRelArrPtr() - count: int = StubMerger.GetSha1StoreCount() - if rel_arr_ptr is None or count <= 0: - return None - sha1_arr_ptr: bytes | t.CPtr = StubMerger.GetSha1StoreArrPtr() - if sha1_arr_ptr is None: - return None - # 遍历查找匹配的 SHA1 - idx_s: int = -1 - for i in range(count): - sidx: t.CSizeT = t.CSizeT(i) * 17 - cur_sha1: str = sha1_arr_ptr + sidx - if cur_sha1[0] == '\0': - continue - if string.strcmp(cur_sha1, sha1) == 0: - idx_s = i - break - if idx_s < 0: - return None - # 获取相对路径(MAX_REL_PATH_LEN=256,避免跨模块 CDefine 解析问题) - MAX_RPL: t.CSizeT = 256 - ridx: t.CSizeT = t.CSizeT(idx_s) * MAX_RPL - rel_path: str = rel_arr_ptr + ridx - if rel_path[0] == '\0': - return None - # 选择基础目录:rel_path 以 "lib/" 开头 → App 源文件(SourceDir); - # 以 "includes/" 开头 → includes 文件(去掉 "includes/" 前缀)。 - # 其他 rel_path(如 VKernel 的 "drivers/core/cpu/cpu.vp")无前缀, - # 无法从 rel_path 判断归属:先试 SourceDir(App 文件),文件不存在 - # 再试 IncludesDir(includes 文件的 RelPath 同样无前缀存储)。 - # 避免路径构建错误导致跨模块 CDefine 查找静默失败。 - base_dir: str = None - rel_used: str = rel_path - if string.strlen(rel_path) >= 4: - if (rel_path[0] == 'l' and rel_path[1] == 'i' and - rel_path[2] == 'b' and rel_path[3] == '/'): - base_dir = Config.SourceDir if Config.SourceDir is not None else Config.IncludesDir - if base_dir is None and string.strlen(rel_path) >= 9: - if (rel_path[0] == 'i' and rel_path[1] == 'n' and - rel_path[2] == 'c' and rel_path[3] == 'l' and - rel_path[4] == 'u' and rel_path[5] == 'd' and - rel_path[6] == 'e' and rel_path[7] == 's' and - rel_path[8] == '/'): - rel_used = rel_path + 9 - base_dir = Config.IncludesDir - if base_dir is None: - base_dir = Config.SourceDir if Config.SourceDir is not None else Config.IncludesDir - # 构建完整路径: {base_dir}/{rel_used} - base_len: t.CSizeT = string.strlen(base_dir) - rel_len: t.CSizeT = string.strlen(rel_used) - path_len: t.CSizeT = base_len + rel_len + 2 - buf: str = stdlib.malloc(path_len) - if buf is None: - return None - viperlib.snprintf(buf, path_len, "%s/%s", base_dir, rel_used) - # 存在性检查:SourceDir 下不存在且 IncludesDir 不同 → 重试 IncludesDir - pf_chk: fileio.File | t.CPtr = fileio.File(buf, fileio.MODE.R) - if pf_chk.closed: - pf_chk.close() - if Config.IncludesDir is not None and base_dir != Config.IncludesDir: - stdlib.free(buf) - base_len2: t.CSizeT = string.strlen(Config.IncludesDir) - path_len2: t.CSizeT = base_len2 + rel_len + 2 - buf = stdlib.malloc(path_len2) - if buf is None: - return None - viperlib.snprintf(buf, path_len2, "%s/%s", Config.IncludesDir, rel_used) - pf_chk2: fileio.File | t.CPtr = fileio.File(buf, fileio.MODE.R) - if pf_chk2.closed: - pf_chk2.close() - stdlib.free(buf) - return None - pf_chk2.close() - else: - stdlib.free(buf) - return None - else: - pf_chk.close() - return buf - - # ============================================================ - # _lookup_cross_module_cdefine - 跨模块查找 CDefine 常量 - # - # 当当前模块的 CDefine 表中找不到某个 Name 时,从 from_imports - # 解析出源模块,再从该模块的 pyi 文件中解析 CDefine 常量值。 - # 找到后缓存到当前模块的 CDefine 表中,避免重复查找。 - # - # pyi 文件格式: "NAME: t.CDefine = value" - # ============================================================ - def _lookup_cross_module_cdefine(self, pool: memhub.MemBuddy | t.CPtr, - name: str, - from_imports: str, - imported_modules: str = None, - depth: int = 0, - node: ast.AST | t.CPtr = None) -> t.CInt64T: - """跨模块查找 CDefine 常量,返回值(64 位)或 -1(未找到) - - 查找顺序: - 1. from_imports 精确匹配(from X import NAME) - 2. from_imports star 回退(from X import *) - 3. imported_modules 遍历(import X):当通过 import X 导入模块时, - 模块中定义的 CDefine 常量可通过此路径找到(如方法签名默认参数引用) - - depth: 递归深度(子模块递归/imported_modules 遍历的内部调用递增)。 - node: 触发查找的 AST 节点(递归内传 None,line 0;顶层调用点传实际节点)。 - """ - # 递归深度守卫:子模块递归(from .X import NAME re-export 链)与 - # imported_modules 遍历组合可能形成循环(模块间互相 from import), - # 无上限时无限递归 → 每次递归 pool.alloc 缓冲(rc_sub_buf/rc_full_mod/ - # rc_fi/im_buf/sub_fi)→ O(n²) 累积 → 主池 1.5GB OOM - # (NewAstTest CONST_INT 单次查找 14593 次调用,fi 恒为 CONST_INT:ast)。 - # 正常跨模块 CDefine 查找深度 < 8(如 ast → ast.base),32 上限 fail-fast - # 暴露循环 import 链(而非静默 OOM)。报错带 node 行号 + 当前递归模块链。 - if depth > 32: - err_buf: str = pool.alloc(256) - if err_buf is not None: - viperlib.snprintf(err_buf, 256, - "跨模块 CDefine 查找递归过深(疑似模块循环 import/re-export): %s (depth=%d fi=%s)", - name, depth, - from_imports if from_imports is not None else "(nil)") - HandlesType.fatal_error(node, err_buf, "InternalCompilerError") - HandlesType.fatal_error(node, - "跨模块 CDefine 查找递归过深(疑似模块循环 import/re-export)", "InternalCompilerError") - # 入口处清零标志,确保所有早退路径(return -1)都返回"未找到"状态 - # 避免递归调用时前一次成功的标志残留导致误判 - HandlesType.set_cdefine_found(0) - if name is None: - return -1 - if from_imports is None: - from_imports = "" - - # 1. 从 from_imports 查找名称对应的模块名 - # 先尝试精确匹配(allow_star_fallback=0),避免 CDefine 常量被 star import 误导 - mod_name_raw: str = HandlesImports.lookup_from_import(from_imports, name, 0) - if mod_name_raw is None: - # 精确匹配失败:尝试 star import 回退 - mod_name_raw = HandlesImports.lookup_from_import(from_imports, name, 1) - - # 截断模块名到 NUL 结尾:lookup_from_import 返回指向 from_imports 内部的 - # 指针(非 NUL 结尾,后随空格分隔的其他条目,如 "ast CONST_STR:ast ...")。 - # 不截断会污染 base_mod:strlen 读到整个 from_imports 末尾 → rc_full_mod - # 每层累积整个列表 + ".base"(dump:ast.base.base.base 无限递归根因), - # 且缓存 key 错乱("CONST_INT@ast CONST_STR:ast ...")无法命中。 - # 与 _lookup_sha1_from_modname_raw 的截断逻辑一致(空格/冒号/NUL 分隔)。 - base_mod: str = None - if mod_name_raw is not None: - mbl: t.CSizeT = 0 - while mod_name_raw[mbl] != ' ' and mod_name_raw[mbl] != '\0' \ - and mod_name_raw[mbl] != ':': - mbl += 1 - mb_buf: str = pool.alloc(mbl + 1) - if mb_buf is not None: - mi2: t.CSizeT - for mi2 in range(mbl): - mb_buf[mi2] = mod_name_raw[mi2] - mb_buf[mbl] = '\0' - base_mod = mb_buf - while base_mod is not None and base_mod[0] == '.': - base_mod = base_mod + 1 - - # 跨模块 CDefine 查找缓存(perm_pool 永久,跨文件复用): - # 首次查找成功后结果缓存,后续文件(含 reset_to(mark2)/模块切换)直接命中, - # 避免 CONST_INT 跨模块递归查找反复触发(NewAstTest OOM 根因—— - # 14593 次调用全部重复递归 ast → ast.base → ...)。 - # key = "name@源模块"(源模块维度,用去点后的 base_mod 保证一致), - # 保持模块隔离:不同源模块的同名 CDefine 值不同时不串值。 - # 仅 ALL_CAPS 全局唯一宏名才进入本函数(_is_cdefine_name_pattern 已过滤)。 - xkey_buf: str = None - if base_mod is not None: - xk_len: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2 - xkey_buf = pool.alloc(xk_len) - if xkey_buf is not None: - viperlib.snprintf(xkey_buf, xk_len, "%s@%s", name, base_mod) - xval: str = HandlesType.lookup_xmod_cdefine(xkey_buf) - if HandlesType.is_cdefine_found() != 0: - if HandlesType.is_cdefine_str() != 0: - HandlesType.register_cdefine_string(pool, name, xval) - elif HandlesType.is_cdefine_double() != 0: - xd_v: double = string.atof(xval) - HandlesType.register_cdefine_double(pool, name, xd_v) - else: - xv_i: t.CInt64T = string.atoll(xval) - HandlesType.register_cdefine_constant(pool, name, xv_i) - return string.atoll(xval) - - # 2. from_imports 查找失败:直接回退到 imported_modules 遍历(步骤 9.6) - # 注意:star fallback 可能返回错误模块(如 stdint),常量实际不在其中, - # 步骤 9.6 会在该模块查找失败后继续遍历 imported_modules - if mod_name_raw is None: - # from_imports 完全没有匹配(精确和 star 都失败) - # 直接进入 imported_modules 遍历(步骤 9.6) - if imported_modules is None: - return -1 - # 跳过 from_imports 模块读取,直接走步骤 9.6 的 imported_modules 遍历 - # 设置 result_found=0 跳过步骤 3-9,直接到 9.6 - HandlesType.set_cdefine_found(0) - # 直接遍历 imported_modules - im_len: t.CSizeT = string.strlen(imported_modules) - im_ci: t.CSizeT = 0 - while im_ci < im_len: - while im_ci < im_len and imported_modules[im_ci] == ' ': - im_ci += 1 - if im_ci >= im_len: - break - im_start: t.CSizeT = im_ci - while im_ci < im_len and imported_modules[im_ci] != ' ': - im_ci += 1 - im_end: t.CSizeT = im_ci - im_nlen: t.CSizeT = im_end - im_start - if im_nlen > 0 and im_nlen < 256: - im_buf: str = pool.alloc(im_nlen + 1) - if im_buf is not None: - mk: t.CSizeT = 0 - while mk < im_nlen: - im_buf[mk] = imported_modules[im_start + mk] - mk += 1 - im_buf[im_nlen] = '\0' - sub_fi: str = pool.alloc(im_nlen + 3) - if sub_fi is not None: - sub_fi[0] = '*' - sub_fi[1] = ':' - mk2: t.CSizeT = 0 - while mk2 < im_nlen: - sub_fi[2 + mk2] = im_buf[mk2] - mk2 += 1 - sub_fi[2 + im_nlen] = '\0' - sub_val: t.CInt64T = self._lookup_cross_module_cdefine(pool, name, sub_fi, None, depth + 1, node) - if HandlesType.is_cdefine_found() != 0: - return sub_val - return -1 - - # 2. 截断模块名 → 去前导点 → 精确+后缀查找 SHA1(复用 HandlesExprCall 公共逻辑) - sha1: str = HandlesExprCall._lookup_sha1_from_modname_raw(pool, mod_name_raw) - if sha1 is None: - return -1 - - # 5. 获取 temp_dir - temp_dir: str = HandlesType.get_temp_dir() - if temp_dir is None: - return -1 - - # 6. 构建 vpi 文件路径 - td_len: t.CSizeT = string.strlen(temp_dir) - pyi_path: str = StubMerger._sliced_path(temp_dir, td_len, sha1, "vpi") - if pyi_path is None: - return -1 - - # 7. 读取 vpi 文件;若不存在或内容过短(空 stub)则回退读取源 .vp/.py 文件 - PYI_READ_BUF_SIZE: t.CSizeT = 65536 - pyi_buf: bytes = stdlib.malloc(PYI_READ_BUF_SIZE) - if pyi_buf is None: - stdlib.free(pyi_path) - return -1 - pf: fileio.File | t.CPtr = fileio.File(pyi_path, fileio.MODE.R) - need_py_fallback: int = 0 - bytes_read: LONG = 0 - if pf.closed: - # .vpi 文件不存在:回退读取源 .vp/.py 文件 - need_py_fallback = 1 - else: - bytes_read = pf.read_all(pyi_buf, PYI_READ_BUF_SIZE) - pf.close() - # vpi 内容过短(< 10 字节)视为空 stub,回退 .py - if bytes_read < 10: - need_py_fallback = 1 - else: - if bytes_read < PYI_READ_BUF_SIZE: - pyi_buf[bytes_read] = 0 - else: - pyi_buf[PYI_READ_BUF_SIZE - 1] = 0 - # vpi(存根签名文件)中的 CDefine 声明可能只带名字不带值 - # (Converter 旧版只对 CONST_INT/BOOL 等输出 "= value",CONST_FLOAT - # 等不输出 → numpy 的 pi/e 在 stub 中无值),真正的值在源 - # .vp/.py 文件中。旧启发式"vpi 中任一 CDefine 带值 → 不读源"是错的: - # 模块同时含 int CDefine(带值,如 numpy.MAX_NDIM=4)与 float - # CDefine(无值,如 pi)时,int 行让 cd_sig=1 而漏回退源 → pi - # 解析失败 → 退化 @pi 全局指针 → float<->ptr 报错(NumpyTest 根因)。 - # 改为按目标名判定:仅当 vpi 中 name 的 CDefine 行带值时才信任 - # vpi,否则(name 行无值 / name 不在 vpi / 整个 vpi 无带值 CDefine) - # 一律回退读源文件。 - cd_sig: int = 0 - name_has_val: int = 0 - cs_name_len: t.CSizeT = string.strlen(name) - cs_total: t.CSizeT = string.strlen(pyi_buf) - cs_i: t.CSizeT = 0 - while cs_i + 9 < cs_total: - if (pyi_buf[cs_i] == 't' and pyi_buf[cs_i + 1] == '.' and - pyi_buf[cs_i + 2] == 'C' and pyi_buf[cs_i + 3] == 'D' and - pyi_buf[cs_i + 4] == 'e' and pyi_buf[cs_i + 5] == 'f' and - pyi_buf[cs_i + 6] == 'i' and pyi_buf[cs_i + 7] == 'n' and - pyi_buf[cs_i + 8] == 'e'): - # 检查该行剩余部分是否有 '='(带值声明才在 vpi 中匹配) - cd_eq: int = 0 - cs_j: t.CSizeT = cs_i + 9 - while cs_j < cs_total and pyi_buf[cs_j] != '\n': - if pyi_buf[cs_j] == '=': - cd_eq = 1 - break - cs_j += 1 - if cd_eq != 0: - cd_sig = 1 - # 定位该行行首,检查是否以 "name:" 开头(目标名带值) - cs_line_start: t.CSizeT = cs_i - while cs_line_start > 0 and pyi_buf[cs_line_start - 1] != '\n': - cs_line_start -= 1 - if cs_i - cs_line_start >= cs_name_len + 1: - nm_ok: int = 1 - for ki2 in range(cs_name_len): - if pyi_buf[cs_line_start + ki2] != name[ki2]: - nm_ok = 0 - break - if nm_ok == 1 and pyi_buf[cs_line_start + cs_name_len] == ':': - name_has_val = 1 - cs_i += 1 - if cd_sig == 0 or name_has_val == 0: - need_py_fallback = 1 - stdlib.free(pyi_path) - - if need_py_fallback != 0: - # 从 SHA1 存储器查找相对路径,构建 {base_dir}/{rel_path} - src_path: str = self._build_source_path_from_sha1(sha1) - if src_path is None: - # 存储器中找不到 SHA1 = 编译器 bug(Phase1/Phase2 未填充存储器) - # 报错终止,不静默返回 -1(避免后续生成错误的 @UNDEFINED 全局变量引用) - err_buf: str = pool.alloc(512) - if err_buf is not None: - viperlib.snprintf(err_buf, 512, - "跨模块 CDefine 查找失败:SHA1 %s 不在存储器中(base_mod=%s name=%s)。" - "Phase1/Phase2 未正确填充 PopulateSha1MapStore/AppendToSha1MapStore", - sha1, base_mod, name) - VLogger.error(err_buf, "XMOD-CD") - stdlib.free(pyi_buf) - return -1 - pf = fileio.File(src_path, fileio.MODE.R) - stdlib.free(src_path) - if pf.closed: - stdlib.free(pyi_buf) - return -1 - bytes_read = pf.read_all(pyi_buf, PYI_READ_BUF_SIZE) - pf.close() - if bytes_read <= 0: - stdlib.free(pyi_buf) - return -1 - if bytes_read < PYI_READ_BUF_SIZE: - pyi_buf[bytes_read] = 0 - else: - pyi_buf[PYI_READ_BUF_SIZE - 1] = 0 - - # 8. 在 pyi_buf 中查找 "name: t.CDefine = value" 行 - # 格式: NAME: t.CDefine = value - name_len: t.CSizeT = string.strlen(name) - total_len: t.CSizeT = string.strlen(pyi_buf) - pos: t.CSizeT = 0 - result_val: t.CInt64T = 0 - result_found: int = 0 - res_is_double: int = 0 - res_is_str: int = 0 - while pos < total_len: - # 找到行首 - line_start: t.CSizeT = pos - # 找到行尾 - while pos < total_len and pyi_buf[pos] != '\n': - pos += 1 - line_len: t.CSizeT = pos - line_start - if pos < total_len: - pos += 1 # 跳过 '\n' - - # 检查行是否以 "name:" 开头 - if line_len < name_len + 1: - continue - match_ok: int = 1 - for ki in range(name_len): - if pyi_buf[line_start + ki] != name[ki]: - match_ok = 0 - break - if match_ok == 0: - continue - if pyi_buf[line_start + name_len] != ':': - continue - - # 检查行是否包含 "t.CDefine" - # 在行中查找 "t.CDefine" - has_cdefine: int = 0 - ci: t.CSizeT = line_start + name_len + 1 - while ci + 8 <= line_start + line_len: - if (pyi_buf[ci] == 't' and pyi_buf[ci + 1] == '.' and - pyi_buf[ci + 2] == 'C' and pyi_buf[ci + 3] == 'D' and - pyi_buf[ci + 4] == 'e' and pyi_buf[ci + 5] == 'f' and - pyi_buf[ci + 6] == 'i' and pyi_buf[ci + 7] == 'n' and - pyi_buf[ci + 8] == 'e'): - has_cdefine = 1 - break - ci += 1 - if has_cdefine == 0: - continue - - # 找到 "=" 后面的值 - eq_pos: t.CSizeT = line_start + name_len + 1 - while eq_pos < line_start + line_len and pyi_buf[eq_pos] != '=': - eq_pos += 1 - if eq_pos >= line_start + line_len: - continue - eq_pos += 1 # 跳过 '=' - - # 跳过空格 - while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': - eq_pos += 1 - - # 检查是否是 t.CUnsignedLong(...) / t.CLong(...) / t.CInt(...) 等类型构造函数 - # 格式: t.CUnsignedLong(-11) / t.CUnsignedLong(0xFFFFFFFF) - # 如果是,跳过 "t.CXxx(" 前缀,解析括号内的值,忽略结尾 ')' - is_type_ctor: int = 0 - if eq_pos + 2 < line_start + line_len: - if pyi_buf[eq_pos] == 't' and pyi_buf[eq_pos + 1] == '.': - # 找到 '(' 的位置 - paren_pos: t.CSizeT = eq_pos + 2 - while paren_pos < line_start + line_len and pyi_buf[paren_pos] != '(': - paren_pos += 1 - if paren_pos < line_start + line_len and pyi_buf[paren_pos] == '(': - is_type_ctor = 1 - eq_pos = paren_pos + 1 # 跳过 '(' - # 跳过括号内可能的前导空格 - while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': - eq_pos += 1 - - # 括号包裹标记:(1 << 23) / (512) / (A | B) - is_paren_expr: int = 0 - if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '(': - is_paren_expr = 1 - eq_pos += 1 - while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': - eq_pos += 1 - - # === 解析左操作数 token(数字 / hex / 负号 / 名称) === - # 负号标记 - is_neg: int = 0 - if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '-': - is_neg = 1 - eq_pos += 1 - val_str_start: t.CSizeT = eq_pos - val_str_len: t.CSizeT = 0 - is_hex: int = 0 - is_float_val: int = 0 - is_name_val: int = 0 - is_str_val: int = 0 - # 字符串值(如 ZLIB_VERSION: t.CDefine = "1.3.2"):读引号内内容。 - # 跨模块读回此前不支持引号 → val_str_len=0 被跳过 → "跨模块 CDefine - # 未找到"(test_pyzlib.vp pyzlib.ZLIB_VERSION 根因) - if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '"': - is_str_val = 1 - eq_pos += 1 # 跳过开引号 - val_str_start = eq_pos - while eq_pos < line_start + line_len and pyi_buf[eq_pos] != '"': - val_str_len += 1 - eq_pos += 1 - if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '"': - eq_pos += 1 # 跳过闭引号 - if eq_pos + 1 < line_start + line_len: - if pyi_buf[eq_pos] == '0' and (pyi_buf[eq_pos + 1] == 'x' or pyi_buf[eq_pos + 1] == 'X'): - is_hex = 1 - val_str_len = 2 - eq_pos += 2 - elif (pyi_buf[eq_pos] >= 'A' and pyi_buf[eq_pos] <= 'Z') or \ - (pyi_buf[eq_pos] >= 'a' and pyi_buf[eq_pos] <= 'z') or \ - pyi_buf[eq_pos] == '_': - is_name_val = 1 - while eq_pos < line_start + line_len: - c_tk: t.CChar = pyi_buf[eq_pos] - if (c_tk >= 'A' and c_tk <= 'Z') or (c_tk >= 'a' and c_tk <= 'z') or \ - (c_tk >= '0' and c_tk <= '9') or c_tk == '_': - val_str_len += 1 - eq_pos += 1 - else: - break - # 数字/hex 字符续读(字符串值已整体读取,跳过) - while eq_pos < line_start + line_len and is_name_val == 0 and is_str_val == 0: - ch: t.CChar = pyi_buf[eq_pos] - if is_hex == 1: - if ((ch >= '0' and ch <= '9') or - (ch >= 'a' and ch <= 'f') or - (ch >= 'A' and ch <= 'F')): - val_str_len += 1 - eq_pos += 1 - else: - break - else: - if ch >= '0' and ch <= '9': - val_str_len += 1 - eq_pos += 1 - elif ch == '.' and is_float_val == 0: - # 浮点值:'3.14159'('.' 只允许一次) - is_float_val = 1 - val_str_len += 1 - eq_pos += 1 - else: - break - - if val_str_len == 0 and is_str_val == 0: - continue - - # 复制左 token 到缓冲区 - val_buf: str = pool.alloc(val_str_len + 1) - if val_buf is None: - continue - for vi in range(val_str_len): - val_buf[vi] = pyi_buf[val_str_start + vi] - val_buf[val_str_len] = '\0' - - # 左 token 求值 - lval: t.CInt64T = 0 - l_is_double: int = 0 - ldbl: double = 0.0 - if is_str_val != 0: - # 字符串 CDefine(如 ZLIB_VERSION = "1.3.2"):注册字符串值 - # (含空串 ""),result_found 标记 + res_is_str 供尾部跳过整数 - # 注册/缓存(否则 register_cdefine_constant 把字符串当 0 整数) - HandlesType.register_cdefine_string(pool, name, val_buf) - result_val = 0 - result_found = 1 - res_is_str = 1 - elif is_name_val != 0: - # True/False 布尔字面量 → 1/0(对齐 TPC:bool 在 CDefine 语境按整数处理) - if string.strcmp(val_buf, "True") == 0: - lval = 1 - elif string.strcmp(val_buf, "False") == 0: - lval = 0 - else: - # 名称引用:查当前 CDefine 表(如 FOREGROUND_COMBO = FOREGROUND_RED) - lval = HandlesType.lookup_cdefine_constant(val_buf) - if HandlesType.is_cdefine_found() == 0: - # 名称未注册:该行无法求值,跳过 - continue - elif is_hex == 1: - # 手动解析十六进制(跳过 0x 前缀)——64 位累加, - # 0xFFFFFFFF=4294967295 保持全精度(常量生成端 i32 截断回 -1) - hex_result: t.CInt64T = 0 - hex_buf: str = val_buf + 2 # 跳过 "0x" - for hi in range(val_str_len - 2): - hc: t.CChar = hex_buf[hi] - hd: int = 0 - if hc >= '0' and hc <= '9': - hd = hc - '0' - elif hc >= 'a' and hc <= 'f': - hd = hc - 'a' + 10 - elif hc >= 'A' and hc <= 'F': - hd = hc - 'A' + 10 - else: - break - hex_result = hex_result * 16 + hd - lval = hex_result - elif is_float_val != 0: - l_is_double = 1 - ldbl = string.atof(val_buf) - lval = string.atoll(val_buf) - else: - lval = string.atoll(val_buf) - if is_neg != 0: - lval = -lval - if l_is_double != 0: - ldbl = -ldbl - - # 跳过空格,检查是否有二元运算符 - while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': - eq_pos += 1 - - # 解析运算符(<< >> | & ^ + - * /) - cd_op: int = 0 - if eq_pos + 1 < line_start + line_len: - if pyi_buf[eq_pos] == '<' and pyi_buf[eq_pos + 1] == '<': - cd_op = 1 # LShift - eq_pos += 2 - elif pyi_buf[eq_pos] == '>' and pyi_buf[eq_pos + 1] == '>': - cd_op = 2 # RShift - eq_pos += 2 - if cd_op == 0 and eq_pos < line_start + line_len: - if pyi_buf[eq_pos] == '|': - cd_op = 3 # BitOr - eq_pos += 1 - elif pyi_buf[eq_pos] == '&': - cd_op = 4 # BitAnd - eq_pos += 1 - elif pyi_buf[eq_pos] == '^': - cd_op = 5 # BitXor - eq_pos += 1 - elif pyi_buf[eq_pos] == '+': - cd_op = 6 # Add - eq_pos += 1 - elif pyi_buf[eq_pos] == '-': - cd_op = 7 # Sub - eq_pos += 1 - elif pyi_buf[eq_pos] == '*': - cd_op = 8 # Mult - eq_pos += 1 - elif pyi_buf[eq_pos] == '/': - cd_op = 9 # Div - eq_pos += 1 - - if cd_op != 0: - # === 解析右操作数 token === - while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': - eq_pos += 1 - r_neg: int = 0 - if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '-': - r_neg = 1 - eq_pos += 1 - r_start: t.CSizeT = eq_pos - r_len: t.CSizeT = 0 - r_hex: int = 0 - r_name: int = 0 - if eq_pos + 1 < line_start + line_len: - if pyi_buf[eq_pos] == '0' and (pyi_buf[eq_pos + 1] == 'x' or pyi_buf[eq_pos + 1] == 'X'): - r_hex = 1 - r_len = 2 - eq_pos += 2 - elif (pyi_buf[eq_pos] >= 'A' and pyi_buf[eq_pos] <= 'Z') or \ - (pyi_buf[eq_pos] >= 'a' and pyi_buf[eq_pos] <= 'z') or \ - pyi_buf[eq_pos] == '_': - r_name = 1 - while eq_pos < line_start + line_len: - c_r: t.CChar = pyi_buf[eq_pos] - if (c_r >= 'A' and c_r <= 'Z') or (c_r >= 'a' and c_r <= 'z') or \ - (c_r >= '0' and c_r <= '9') or c_r == '_': - r_len += 1 - eq_pos += 1 - else: - break - while eq_pos < line_start + line_len and r_name == 0: - c_r2: t.CChar = pyi_buf[eq_pos] - if r_hex == 1: - if ((c_r2 >= '0' and c_r2 <= '9') or - (c_r2 >= 'a' and c_r2 <= 'f') or - (c_r2 >= 'A' and c_r2 <= 'F')): - r_len += 1 - eq_pos += 1 - else: - break - else: - if c_r2 >= '0' and c_r2 <= '9': - r_len += 1 - eq_pos += 1 - else: - break - if r_len == 0: - # 运算符后无右操作数:无法求值,跳过该行 - continue - r_buf: str = pool.alloc(r_len + 1) - if r_buf is None: - continue - for r_i in range(r_len): - r_buf[r_i] = pyi_buf[r_start + r_i] - r_buf[r_len] = '\0' - rval: t.CInt64T = 0 - if r_name != 0: - # True/False 布尔字面量 → 1/0 - if string.strcmp(r_buf, "True") == 0: - rval = 1 - elif string.strcmp(r_buf, "False") == 0: - rval = 0 - else: - rval = HandlesType.lookup_cdefine_constant(r_buf) - if HandlesType.is_cdefine_found() == 0: - # 名称未注册:无法求值,跳过该行 - continue - elif r_hex != 0: - rhex_v: t.CInt64T = 0 - rh_buf: str = r_buf + 2 - for rh_i in range(r_len - 2): - rc: t.CChar = rh_buf[rh_i] - rd: int = 0 - if rc >= '0' and rc <= '9': - rd = rc - '0' - elif rc >= 'a' and rc <= 'f': - rd = rc - 'a' + 10 - elif rc >= 'A' and rc <= 'F': - rd = rc - 'A' + 10 - else: - break - rhex_v = rhex_v * 16 + rd - rval = rhex_v - else: - rval = string.atoll(r_buf) - if r_neg != 0: - rval = -rval - # 计算二元表达式结果(对齐 TPC ConstEvaluator) - if cd_op == 1: - result_val = lval << rval - elif cd_op == 2: - result_val = lval >> rval - elif cd_op == 3: - result_val = lval | rval - elif cd_op == 4: - result_val = lval & rval - elif cd_op == 5: - result_val = lval ^ rval - elif cd_op == 6: - result_val = lval + rval - elif cd_op == 7: - result_val = lval - rval - elif cd_op == 8: - result_val = lval * rval - else: - if rval == 0: - continue - result_val = lval // rval - result_found = 1 - break - else: - # 单值(无运算符):括号内单值如 (512) / (-11) 也走这里 - if is_paren_expr != 0: - while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': - eq_pos += 1 - if eq_pos < line_start + line_len and pyi_buf[eq_pos] == ')': - eq_pos += 1 - if is_float_val != 0: - # 浮点 CDefine(如 U_M_PI = 3.14159...): - # 值缓存为 double(register_cdefine_double),供调用处生成 - # double 常量;整数部分供 int 路径使用(is_cdefine_double 标志)。 - HandlesType.register_cdefine_double(pool, name, ldbl) - result_val = lval - result_found = 1 - res_is_double = 1 - else: - result_val = lval - result_found = 1 - break - - # 9.5 如果当前模块文件中没找到,递归查找子模块 - # 处理 from .X import NAME 和 from .X import * 的情况 - # 例如 ast.__init__.vp 中 from .base import CONST_INT, ... - # 需要递归查找 ast.base 子模块中的 CONST_INT: t.CDefine = 1 - if result_found == 0: - # base_mod 已在函数开头计算(mod_name_raw 去前导点), - # 供子模块递归构建 "base_mod.X" 全名。 - name_len_rc: t.CSizeT = string.strlen(name) - rc_pos: t.CSizeT = 0 - while rc_pos < total_len and result_found == 0: - # 找到行首 - rc_line_start: t.CSizeT = rc_pos - # 找到行尾 - while rc_pos < total_len and pyi_buf[rc_pos] != '\n': - rc_pos += 1 - rc_line_len: t.CSizeT = rc_pos - rc_line_start - if rc_pos < total_len: - rc_pos += 1 - - # 检查行是否以 "from ." 开头(相对导入子模块) - if rc_line_len < 12: - continue - if pyi_buf[rc_line_start] != 'f' or pyi_buf[rc_line_start+1] != 'r' or \ - pyi_buf[rc_line_start+2] != 'o' or pyi_buf[rc_line_start+3] != 'm' or \ - pyi_buf[rc_line_start+4] != ' ' or pyi_buf[rc_line_start+5] != '.': - continue - - # 提取子模块名(从 rc_line_start+6 开始,到空格/tab 为止) - rc_sub_start: t.CSizeT = rc_line_start + 6 - rc_sub_end: t.CSizeT = rc_sub_start - while rc_sub_end < rc_line_start + rc_line_len and \ - pyi_buf[rc_sub_end] != ' ' and pyi_buf[rc_sub_end] != '\t': - rc_sub_end += 1 - rc_sub_len: t.CSizeT = rc_sub_end - rc_sub_start - if rc_sub_len == 0: - continue - - # 检查行是否包含 "import" - rc_has_import: int = 0 - rc_ipos: t.CSizeT = rc_sub_end - while rc_ipos + 6 <= rc_line_start + rc_line_len: - if pyi_buf[rc_ipos] == 'i' and pyi_buf[rc_ipos+1] == 'm' and \ - pyi_buf[rc_ipos+2] == 'p' and pyi_buf[rc_ipos+3] == 'o' and \ - pyi_buf[rc_ipos+4] == 'r' and pyi_buf[rc_ipos+5] == 't': - rc_has_import = 1 - break - rc_ipos += 1 - if rc_has_import == 0: - continue - - # 检查 NAME 是否在导入列表中,或导入是 * - # 处理多行导入:from .X import (... NAME, ...) - # 从 "import" 之后扫描,如果有 "(" 则扫描到 ")" 为止 - rc_imp_start: t.CSizeT = rc_ipos + 6 - rc_star: int = 0 - rc_name_match: int = 0 - - # 确定扫描范围:单行或跨行(括号内) - rc_scan_end: t.CSizeT = rc_line_start + rc_line_len - rc_has_paren: int = 0 - rc_pp: t.CSizeT = rc_imp_start - while rc_pp < rc_line_start + rc_line_len: - if pyi_buf[rc_pp] == '(': - rc_has_paren = 1 - break - if pyi_buf[rc_pp] == '*': - rc_star = 1 - rc_pp += 1 - if rc_has_paren != 0: - # 多行导入:从 "(" 之后扫描到 ")" 为止 - rc_scan_end = rc_pp + 1 - rc_paren_closed: int = 0 - rc_sp: t.CSizeT = rc_pp + 1 - while rc_sp < total_len and rc_paren_closed == 0: - if pyi_buf[rc_sp] == ')': - rc_paren_closed = 1 - rc_scan_end = rc_sp - break - rc_sp += 1 - if rc_paren_closed == 0: - rc_scan_end = total_len - - # 在 rc_imp_start 到 rc_scan_end 范围内查找 NAME 和 * - rc_cpos: t.CSizeT = rc_imp_start - while rc_cpos < rc_scan_end: - rc_ch: t.CChar = pyi_buf[rc_cpos] - if rc_ch == '*': - rc_star = 1 - # 检查 NAME 是否匹配(作为完整单词) - if rc_cpos + name_len_rc <= rc_scan_end: - rc_match: int = 1 - rc_ki: t.CSizeT - for rc_ki in range(name_len_rc): - if pyi_buf[rc_cpos + rc_ki] != name[rc_ki]: - rc_match = 0 - break - if rc_match == 1: - # 检查前字符是否是非标识符字符 - rc_before_ok: int = 0 - if rc_cpos == rc_imp_start: - rc_before_ok = 1 - else: - rc_before_ch: t.CChar = pyi_buf[rc_cpos - 1] - if rc_before_ch == ' ' or rc_before_ch == '\t' or \ - rc_before_ch == '(' or rc_before_ch == ',' or \ - rc_before_ch == '\n' or rc_before_ch == '\r': - rc_before_ok = 1 - # 检查后字符是否是非标识符字符 - rc_after_ok: int = 0 - rc_after_pos: t.CSizeT = rc_cpos + name_len_rc - if rc_after_pos >= rc_scan_end: - rc_after_ok = 1 - else: - rc_after_ch: t.CChar = pyi_buf[rc_after_pos] - if rc_after_ch == ' ' or rc_after_ch == '\t' or \ - rc_after_ch == ')' or rc_after_ch == ',' or \ - rc_after_ch == '\r' or rc_after_ch == '\n': - rc_after_ok = 1 - if rc_before_ok == 1 and rc_after_ok == 1: - rc_name_match = 1 - rc_cpos += 1 - - if rc_star == 0 and rc_name_match == 0: - continue - - # 复制子模块名到新缓冲区(pyi_buf + rc_sub_start 不是 NUL 结尾) - rc_sub_buf: str = pool.alloc(rc_sub_len + 1) - if rc_sub_buf is None: - continue - rc_si: t.CSizeT - for rc_si in range(rc_sub_len): - rc_sub_buf[rc_si] = pyi_buf[rc_sub_start + rc_si] - rc_sub_buf[rc_sub_len] = '\0' - - # 构建完整子模块名 base_mod.X - rc_full_len: t.CSizeT = string.strlen(base_mod) + 1 + rc_sub_len + 1 - rc_full_mod: str = pool.alloc(rc_full_len) - if rc_full_mod is None: - continue - viperlib.snprintf(rc_full_mod, rc_full_len, "%s.%s", base_mod, rc_sub_buf) - - # 防循环:若 base_mod 已以 "."+rc_sub_buf 结尾(如 ast.base 再拼 - # .base → ast.base.base),说明子模块递归在重复追加同一模块段 - # (模块间循环 re-export / 后缀匹配容错命中自身),跳过该次递归 - # (NewAstTest CONST_INT 查找 dump:ast.base.base.base 无限增长根因)。 - rc_blen: t.CSizeT = string.strlen(base_mod) - if rc_blen > rc_sub_len + 1: - rc_tail: str = base_mod + (rc_blen - rc_sub_len) - if rc_tail[0] == '.' and \ - string.strncmp(rc_tail + 1, rc_sub_buf, rc_sub_len) == 0: - continue - - # 构建临时 from_imports "name:full_mod" - rc_fi_len: t.CSizeT = name_len_rc + 1 + string.strlen(rc_full_mod) + 1 - rc_fi: str = pool.alloc(rc_fi_len) - if rc_fi is None: - continue - viperlib.snprintf(rc_fi, rc_fi_len, "%s:%s", name, rc_full_mod) - - # 递归调用查找子模块 - rc_sub_val: int = self._lookup_cross_module_cdefine(pool, name, rc_fi, None, depth + 1, node) - if HandlesType.is_cdefine_found() != 0: - result_val = rc_sub_val - result_found = 1 - - stdlib.free(pyi_buf) - - # 9.6 from_imports star fallback 模块中未找到:回退到 imported_modules 遍历 - # 当 `from stdint import *` 导致 star fallback 返回 stdint,但目标常量 - # (如 SHARE_READ)实际在 `import w32.fileio` 导入的模块中时, - # 需要遍历 imported_modules 逐个查找 - if result_found == 0 and imported_modules is not None: - im2_len: t.CSizeT = string.strlen(imported_modules) - im2_ci: t.CSizeT = 0 - while im2_ci < im2_len and result_found == 0: - while im2_ci < im2_len and imported_modules[im2_ci] == ' ': - im2_ci += 1 - if im2_ci >= im2_len: - break - im2_start: t.CSizeT = im2_ci - while im2_ci < im2_len and imported_modules[im2_ci] != ' ': - im2_ci += 1 - im2_end: t.CSizeT = im2_ci - im2_nlen: t.CSizeT = im2_end - im2_start - if im2_nlen > 0 and im2_nlen < 256: - im2_buf: str = pool.alloc(im2_nlen + 1) - if im2_buf is not None: - mk3: t.CSizeT = 0 - while mk3 < im2_nlen: - im2_buf[mk3] = imported_modules[im2_start + mk3] - mk3 += 1 - im2_buf[im2_nlen] = '\0' - sub_fi2: str = pool.alloc(im2_nlen + 3) - if sub_fi2 is not None: - sub_fi2[0] = '*' - sub_fi2[1] = ':' - mk4: t.CSizeT = 0 - while mk4 < im2_nlen: - sub_fi2[2 + mk4] = im2_buf[mk4] - mk4 += 1 - sub_fi2[2 + im2_nlen] = '\0' - sub_val2: t.CInt64T = self._lookup_cross_module_cdefine(pool, name, sub_fi2, None, depth + 1, node) - if HandlesType.is_cdefine_found() != 0: - result_val = sub_val2 - result_found = 1 - - # 10. 缓存到当前模块的 CDefine 表中,并写入跨模块 perm_pool 缓存 - # 浮点 CDefine 已在匹配循环中 register_cdefine_double 缓存 - # (res_is_double=1),此处只缓存整数 CDefine,避免覆盖 double。 - if result_found != 0: - if res_is_str != 0: - # 字符串 CDefine:值已在匹配循环 register_cdefine_string(val_buf - # 是命中行的字符串内容,pool 分配跨函数有效),此处只写跨模块缓存 - if base_mod is not None: - ck_len_s: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2 - ckey_s: str = pool.alloc(ck_len_s) - if ckey_s is not None: - viperlib.snprintf(ckey_s, ck_len_s, "%s@%s", name, base_mod) - HandlesType.register_xmod_cdefine(ckey_s, val_buf, 0, 1) - elif res_is_double == 0: - HandlesType.register_cdefine_constant(pool, name, result_val) - # 跨模块查找缓存(perm_pool 永久,跨文件复用):整数 - # key 与入口查询一致:"name@源模块"(用截断后的 base_mod, - # 与 mod_name_raw 一致——两者都是去点后的模块名,保证 key 匹配) - if base_mod is not None: - ck_len: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2 - ckey_buf: str = pool.alloc(ck_len) - if ckey_buf is not None: - viperlib.snprintf(ckey_buf, ck_len, "%s@%s", name, base_mod) - cbuf_i: str = pool.alloc(32) - if cbuf_i is not None: - viperlib.snprintf(cbuf_i, 32, "%lld", result_val) - HandlesType.register_xmod_cdefine(ckey_buf, cbuf_i, 0, 0) - else: - # 浮点:从本地表取回 %.17g 文本,写入跨模块缓存(保精度) - if base_mod is not None: - ck_len2: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2 - ckey2: str = pool.alloc(ck_len2) - if ckey2 is not None: - viperlib.snprintf(ckey2, ck_len2, "%s@%s", name, base_mod) - dval_cc: double = HandlesType.lookup_cdefine_double(name) - if HandlesType.is_cdefine_double() != 0: - cbuf_d: str = pool.alloc(64) - if cbuf_d is not None: - stdio.snprintf(cbuf_d, 64, "%.17g", dval_cc) - HandlesType.register_xmod_cdefine(ckey2, cbuf_d, 1, 0) - HandlesType.set_cdefine_found(1) - else: - HandlesType.set_cdefine_found(0) - - return result_val - - # ============================================================ - # _is_cdefine_name_pattern - 检查名字是否符合 CDefine 命名约定 - # - # CDefine 常量(如 FOREGROUND_GREEN, STD_OUTPUT_HANDLE, SCOPE_MODULE) - # 都遵循 ALL_CAPS 约定:仅含大写字母 A-Z、数字 0-9、下划线 _, - # 且至少含一个大写字母。 - # - # Python 关键字(match, if, for)和变量名(self, pool, builder) - # 都含小写字母,不会匹配,从而避免 fail-fast 误报。 - # - # 返回: 1=符合 CDefine 命名约定, 0=不符合 - # ============================================================ - def _is_cdefine_name_pattern(self, name: str) -> int: - """检查名字是否符合 CDefine 命名约定(全大写+下划线+数字)""" - if name is None: - return 0 - has_upper: int = 0 - i: t.CSizeT = 0 - while name[i] != '\0': - c: t.CChar = name[i] - if c >= 'a' and c <= 'z': - return 0 - if c >= 'A' and c <= 'Z': - has_upper = 1 - i += 1 - return has_upper - - # ============================================================ - # 翻译变量引用(Name 节点)→ load - # ============================================================ - def _const_int_for_cdefine(self, pool: memhub.MemBuddy | t.CPtr, - value: t.CInt64T) -> llvmlite.Value | t.CPtr: - """CDefine 整数常量 → LLVM 常量(对齐 TPC TypeConvert 的 64 位升级) - - 规则(与 translate_constant 的 i32 溢出升级一致,但保留 0xFFFFFFFF 语义): - 值超 32 位无符号范围(> 0xFFFFFFFF)→ i64 全精度常量 - (如 sys.maxsize = 9223372036854775807); - 否则 → i32 常量,内部 t.CInt 截断(0xFFFFFFFF → -1,保持既有 - INVALID_HANDLE_VALUE / WAIT_FAILED = -1 语义不变,避免 i32 4294967295 - 生成非法 LLVM IR 文本 "i32 4294967295")。 - - 注意:不能用 `value > 4294967295` 直接比较——TPV 编译自身源码时大数字面量 - (> 0x7FFFFFFF)在字面量层回绕成 i32(sext 后等于 -1),阈值恒成立导致所有 - 正数 CDefine 都被升 i64(INVALID_FILE_ATTRIBUTES 0xFFFFFFFF 从 i32 -1 变 - i64 4294967295 → 与 _get_attrs 的 sext(-1) 比较失败,SysLibTest exists FAIL 根因)。 - 改用截断回比较:t.CUInt32T(value) 回绕后还原,与 value 不等即超 u32 范围。 - """ - if value >= 0 and t.CUInt64T(t.CUInt32T(value)) != value: - return llvmlite.const_int64(pool, value) - return llvmlite.const_int32(pool, t.CInt(value)) - - def translate_name_value(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译变量引用(Name 节点)→ load""" - # mod 必须取自 trans.Module:函数签名无 mod 参数,若用裸名 mod 会被 - # 解析为 None → create_global_string 的 module_add_global(None, gv) 被 - # add_global 的 `if self is None: return` 静默丢弃 → 字符串 CDefine 的 - # global 定义丢失但 _label_counter/IR 引用已生成 → llc 报 - # "use of undefined value '@.str.{sha1}.N'(SysLibTest _cleanup 根因)" - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm is None: - return None - nm_id: str = nm.id - if nm_id is None: - return None - # CDefine 编译期常量: 返回常量值(浮点 CDefine → double 常量,整数 → i32) - # NAME: t.CDefine = value 形式定义的常量在编译期已注册到本地表 - # 浮点 CDefine(如 vipermath 的 U_M_PI=3.14...)必须返回浮点常量, - # 否则在 double 函数里 return 生成 ret i32 0(llc 报错)。 - cdef_val_d: double = HandlesType.lookup_cdefine_double(nm_id) - if HandlesType.is_cdefine_found() != 0: - if HandlesType.is_cdefine_str() != 0: - # 字符串 CDefine(如 ZLIB_VERSION: t.CDefine = "1.3.2"): - # 返回 global string(i8*),供 return ZLIB_VERSION 等使用。 - cdef_sv: str = HandlesType.lookup_cdefine_string(nm_id) - if cdef_sv is not None: - return self.create_global_string(builder, pool, mod, cdef_sv, trans) - HandlesType.fatal_error(node, f"CDefine 字符串值缺失: {nm_id}", "InternalCompilerError") - if HandlesType.is_cdefine_double() != 0: - return llvmlite.ConstFloat(pool, llvmlite.Double(pool), cdef_val_d) - # 整数 CDefine:重新查表取 64 位全精度值(double 往返会丢精度, - # 9223372036854775807 → 9.223372036854776e18 舍入错位,生成错常量) - cdef_val_c: t.CInt64T = HandlesType.lookup_cdefine_constant(nm_id) - return self._const_int_for_cdefine(pool, cdef_val_c) - - # 本地表未找到:尝试跨模块 .vpi 查找(保证多模块查表存表一致) - # 仅对符合 CDefine 命名约定(ALL_CAPS)的名字触发跨模块查找, - # 避免对普通变量名(mb/name/ptr/pool/self 等)误触发,造成严重性能损耗 - if self._is_cdefine_name_pattern(nm_id) != 0: - if trans is not None: - cdef_val: t.CInt64T = self._lookup_cross_module_cdefine( - pool, nm_id, trans._from_imports, trans._imported_modules, 0, node) - if HandlesType.is_cdefine_found() != 0: - if HandlesType.is_cdefine_str() != 0: - cdef_sv2: str = HandlesType.lookup_cdefine_string(nm_id) - if cdef_sv2 is not None: - return self.create_global_string(builder, pool, mod, cdef_sv2, trans) - HandlesType.fatal_error(node, f"CDefine 字符串值缺失: {nm_id}", "InternalCompilerError") - # 跨模块浮点 CDefine 已缓存为 double(is_cdefine_double), - # 需返回浮点常量而非截断的整数 - dchk_nm: double = HandlesType.lookup_cdefine_double(nm_id) - if HandlesType.is_cdefine_double() != 0: - return llvmlite.ConstFloat(pool, llvmlite.Double(pool), dchk_nm) - return self._const_int_for_cdefine(pool, cdef_val) - - # global 变量:从模块作用域查找(global 声明优先级最高) - if trans is not None: - if HT.is_global_name(trans, nm_id) != 0: - mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( - trans.SymTab, nm_id) - if mod_alloca is not None: - load_ty: llvmlite.LLVMType | t.CPtr = None - if mod_alloca.Ty is not None: - load_ty = mod_alloca.Ty.Pointee - if load_ty is None: - # fail-fast:global 变量存储类型缺失,立即终止编译(暴露上游根因) - HandlesType.fatal_error( - node, f"变量 '{nm_id}' 存储类型缺失", "TypeError") - # 全局数组(如 pyzlib.pyzlib_error_msg: CArray[t.CChar, 512]): - # 按 C 语义衰减为基址返回(对齐下方局部数组分支 L3383-3388)。 - # 否则 load [512 x i8] 数组值当 i8* 传 → set_error 的 strncpy - # dest 是数组值(栈拷贝)而非数组基址 → 写入丢失 → get_error - # 为空(test_pyzlib "error message is empty" 根因)。 - match load_ty: - case llvmlite.LLVMType.Array(_, _): - return mod_alloca - case _: - pass - return llvmlite.build_load(builder, load_ty, mod_alloca) - - # nonlocal 变量:通过闭包 env 访问 - if HT.is_nonlocal_name(trans, nm_id) != 0: - return HandlesNonlocal.load_nonlocal_var(trans, nm_id) - - # *args va_list:变量名直接解析为指向 24 字节 va_list 缓冲区的 i8* 地址 - # (对齐 TPC _direct_values[vararg_name] = va_list_ptr;不 load 缓冲区内容, - # 转发时按值传该地址即可,如 sprintf → vsnprintf(..., args)) - if trans is not None and trans._vararg_name is not None: - if nm_id is not None and string.strcmp(nm_id, trans._vararg_name) == 0: - if trans._va_list_ptr is not None: - return trans._va_list_ptr - - # 局部变量查找(必须先于模块别名检查) - # 否则与模块同名的局部变量(如 `import t, c` 后的局部变量 c)会被误判为模块别名, - # 导致 SymTab 已注册的局部变量查找不到(rhs_val is None bug 根因) - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm_id) - if alloca is not None: - load_ty: llvmlite.LLVMType | t.CPtr = None - if alloca.Ty is not None: - load_ty = alloca.Ty.Pointee - if load_ty is None: - # fail-fast:局部变量存储类型缺失,立即终止编译(暴露上游根因) - HandlesType.fatal_error( - node, f"变量 '{nm_id}' 存储类型缺失", "TypeError") - # 结构体值变量(alloca 类型为 Struct,如 `x: Cls | t.CPtr`): - # 按"对象即指针"语义返回其地址(alloca 指针),而非加载结构体值。 - # 结构体值无法参与 ptrtoint/方法调用等地址相关操作,加载值会导致 - # `ptrtoint %Struct ... to i64` 无效指令(llc invalid cast opcode)。 - match load_ty: - case llvmlite.LLVMType.Struct(_, _, _): - return alloca - case llvmlite.LLVMType.Array(_, _): - # 数组变量按 C 语义退化为指针(返回数组基址),而非整体 - # load 数组值——如 printf("%s", str_arr) 应传数组首地址, - # load [N x i8] 值传给 %s 会读到错误数据崩溃 - # (ClassArrayTest TestCharArray 运行时崩溃根因)。 - return alloca - return llvmlite.build_load(builder, load_ty, alloca) - - # 模块别名检查:SymTab 查找失败后才检查 - # 如果 nm_id 是已导入模块名(如 win32file, fileio)且未被声明为局部变量, - # 返回 None 让上层处理(用于属性访问 win32file.CreateFileA) - if trans is not None and trans._imported_modules is not None: - if HandlesImports.is_module_imported(trans._imported_modules, nm_id) != 0: - return None - - # 模块级函数引用:函数名作为值传递(如 CreateThread(..., _thread_alloc_free, ...))。 - # 之前缺失此查找导致函数名参数翻译返回 None 被跳过,后续参数整体前移 - # (lpStartAddress 变成对象地址,线程从数据区执行直接崩溃)。 - # 注意:不能直接返回 Function 对象,也不能直接 build_bitcast(Function)—— - # Function 布局是 {Next, Name, RetTy, Params, ...},value_get_ty 会错位读到 - # Name 字段,TypePrint 输出 "void",生成 `bitcast void ... to i8*` 非法 IR; - # 且 Function.Next 是模块函数链表指针,参数链表构建对其赋值会截断函数链表, - # 最终打印出 `declare void @()` 空名函数。正确做法:按 Function 的 - # RetTy/Params 构造真实函数类型,用 new_value 包装成普通 Value 再 bitcast。 - if trans is not None and trans.Module is not None: - fn_ref: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module( - trans.Module, nm_id) - if fn_ref is not None: - fn_name: str = llvmlite.function_get_name(fn_ref) - if fn_name is None: - return None - # 构造函数类型:ret_ty + 参数 ParamNode 链表 - fn_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(fn_ref) - if fn_ret_ty is None: - # fail-fast:函数返回类型缺失,无法构造函数指针(暴露上游根因) - HandlesType.fatal_error( - node, f"函数 '{nm_id}' 返回类型缺失,无法构造函数指针", "TypeError") - fn_pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(fn_ref) - fn_first_node: llvmlite.ParamNode | t.CPtr = None - fn_prev_node: llvmlite.ParamNode | t.CPtr = None - fn_pcount: int = 0 - while fn_pp is not None: - fn_pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(fn_pp) - fn_pn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, fn_pty) - if fn_pn is not None: - if fn_first_node is None: - fn_first_node = fn_pn - if fn_prev_node is not None: - llvmlite.paramnode_set_next(fn_prev_node, fn_pn) - fn_prev_node = fn_pn - fn_pcount += 1 - fn_pp = llvmlite.param_get_next(fn_pp) - fn_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func( - pool, fn_ret_ty, fn_first_node, fn_pcount) - if fn_ty is None: - return None - # 构造函数指针 Value(new_value 包装,避免触碰 Function.Next) - fn_ref_v: llvmlite.Value | t.CPtr = llvmlite.new_value(pool) - if fn_ref_v is None: - return None - llvmlite.value_set_ty(fn_ref_v, llvmlite.Ptr(pool, fn_ty)) - llvmlite.value_set_isconst(fn_ref_v, 1) - fn_ref_name: str = pool.alloc(256) - if fn_ref_name is not None: - fn_ref_name[0] = '\0' - if HandlesClassDef._vtable_name_needs_quote(fn_name) != 0: - viperlib.snprintf(fn_ref_name, 256, "@\"%s\"", fn_name) - else: - viperlib.snprintf(fn_ref_name, 256, "@%s", fn_name) - llvmlite.value_set_name(fn_ref_v, fn_ref_name) - fn_i8ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - return llvmlite.build_bitcast(builder, fn_ref_v, fn_i8ptr_ty) - - # ============================================================ - # 跨模块 from-import 全局变量读取(如 from .tokens import _op_head) - # 根因:模块级全局(非 CDefine/非函数)from-import 后无本模块 SymTab - # 条目,所有查找路径未命中 → translate_name_value 返回 None → 赋值被 - # 静默跳过 → 变量未初始化 → 垃圾指针解引用崩溃(AstTest 的 - # _read_operator 里 `cur = _op_head` 丢失导致 while 循环读未初始化 %6)。 - # 语义对齐模块属性全局(sys._mbuddy):external @{全局名} 引用 + load, - # 定义由源模块提供(COFF 按名链接)。别名导入用源模块内真实名。 - # ============================================================ - if trans is not None and trans._from_imports is not None: - if trans.Module is not None: - # 是 from-import 名称(禁用 star 回退,避免误归 star 模块) - fi_mod: str = HandlesImports.lookup_from_import( - trans._from_imports, nm_id, 0) - if fi_mod is not None: - # 排除已注册类名/枚举名:这些是类型,不作为全局变量值读取 - fi_is_class: int = 0 - if HandlesStruct.get_struct_type(nm_id) is not None: - fi_is_class = 1 - # 排除 ALL_CAPS CDefine(上方已处理本地+跨模块查找) - if self._is_cdefine_name_pattern(nm_id) != 0: - fi_is_class = 1 - if fi_is_class == 0: - fi_gname: str = nm_id - fi_orig: str = HandlesImports.lookup_from_import_original( - trans._from_imports, nm_id) - if fi_orig is not None: - og_len_fi: t.CSizeT = 0 - while fi_orig[og_len_fi] != ' ' and fi_orig[og_len_fi] != '\0': - og_len_fi += 1 - if og_len_fi > 0: - og_buf_fi: str = pool.alloc(og_len_fi + 1) - if og_buf_fi is not None: - string.strncpy(og_buf_fi, fi_orig, og_len_fi) - og_buf_fi[og_len_fi] = '\0' - fi_gname = og_buf_fi - # stub 已注入全局(精确类型)→ 直接引用;未注入 → fail-fast - # (不再创建 external i8* 声明,否则 llc 报 "use of undefined value", - # 静默回退掩盖 stub 未注入的上游根因) - gv_fi: llvmlite.GlobalVariable | t.CPtr = self.find_global_in_module( - trans.Module, fi_gname) - ref_fi: llvmlite.Value | t.CPtr = None - if gv_fi is not None and gv_fi.Ty is not None: - ref_fi = self.make_global_ref(pool, fi_gname, gv_fi.Ty) - else: - HandlesType.fatal_error( - node, - f"跨模块全局变量 '{fi_gname}' 类型未知(stub 未注入)", - "TypeError") - if ref_fi is not None and ref_fi.Ty is not None: - lty_fi: llvmlite.LLVMType | t.CPtr = ref_fi.Ty.Pointee - if lty_fi is not None: - return llvmlite.build_load(builder, lty_fi, ref_fi) - return ref_fi - - # 所有查找路径均失败 - # fail-fast:未定义名称立即终止编译(NameError,暴露上游根因), - # 不再静默返回 None(否则下游 store/call 到 None 崩溃,掩盖名称查找失败)。 - # 豁免:关键字/内建名(self/pool/true/false/None/match 上下文关键字、_、 - # CIf 系等特殊名字)——这些名字不注册 SymTab 属正常,调用方有合法语义 - # 处理路径(如 CIf 未定义名特判走 else),保持返回 None 不报错。 - if nm_id is None: - return None - if string.strcmp(nm_id, "self") == 0 or string.strcmp(nm_id, "pool") == 0 \ - or string.strcmp(nm_id, "true") == 0 or string.strcmp(nm_id, "false") == 0 \ - or string.strcmp(nm_id, "None") == 0 or string.strcmp(nm_id, "match") == 0 \ - or string.strcmp(nm_id, "_") == 0 \ - or string.strcmp(nm_id, "CIf") == 0 or string.strcmp(nm_id, "CIfdef") == 0 \ - or string.strcmp(nm_id, "CIfndef") == 0: - return None - HandlesType.fatal_error(node, f"未定义名称 '{nm_id}'", "NameError") - return None - - # ============================================================ - # list_getitem_inline — 内联生成 list[T] __getitem__ 逻辑 - # - # list 结构布局 (6 字段 × 8 字节): - # __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40) - # 返回元素地址 (i8*),调用方根据元素类型 load 正确的值 - # ============================================================ - def list_getitem_inline(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - lm_obj: llvmlite.Value | t.CPtr, - idx_val: llvmlite.Value | t.CPtr, - node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """内联生成 list __getitem__ 逻辑,返回元素地址 (i8*)""" - if builder is None or pool is None or lm_obj is None or idx_val is None: - return None - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - # 加载 __data__ (偏移 0, index 0) - g_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) - g_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0) - if g_dpp is None: - return None - g_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, g_dpp) - # 加载 __elem_size__ (偏移 32, index 4) - g_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) - g_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4) - if g_epp is None: - return None - g_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, g_epp) - if g_data is None or g_esize is None: - return None - g_idx_i64: llvmlite.Value | t.CPtr = self.coerce_to_type(builder, idx_val, i64_ty, node) - if g_idx_i64 is None: - return None - g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize) - if g_offset is None: - return None - # 返回元素地址 (i8*),不 load - return llvmlite.build_gep(builder, i8_ty, g_data, g_offset) - - # ============================================================ - # _list_elem_type_from_name — 从 list 类型名提取元素 LLVM 类型 - # - # 类型名格式: .list[] - # 用 strstr 检查完整模式,避免子串提取 - # 支持: list[int]→i32, list[str]/list[bytes]→i8*, list[CInt]→i32 等 - # 默认: i32 - # ============================================================ - def _list_elem_type_from_name(self, pool: memhub.MemBuddy | t.CPtr, - struct_name: str) -> llvmlite.LLVMType | t.CPtr: - """从 list 类型名提取元素 LLVM 类型""" - if pool is None or struct_name is None: - return None - # 用 strstr 检查完整模式 - if string.strstr(struct_name, "list[int]") is not None: - return llvmlite.Int32(pool) - if string.strstr(struct_name, "list[CInt]") is not None: - return llvmlite.Int32(pool) - if string.strstr(struct_name, "list[CInt8T]") is not None: - return llvmlite.Int8(pool) - if string.strstr(struct_name, "list[CInt16T]") is not None: - return llvmlite.Int16(pool) - if string.strstr(struct_name, "list[CInt32T]") is not None: - return llvmlite.Int32(pool) - if string.strstr(struct_name, "list[CInt64T]") is not None: - return llvmlite.Int64(pool) - if string.strstr(struct_name, "list[CSizeT]") is not None: - return llvmlite.Int64(pool) - if string.strstr(struct_name, "list[CDouble]") is not None: - return llvmlite.Double(pool) - if string.strstr(struct_name, "list[CFloat]") is not None: - return llvmlite.Float(pool) - if string.strstr(struct_name, "list[CChar]") is not None: - return llvmlite.Int8(pool) - # str/bytes/CPtr 等已知指针元素类型 → i8*(元素存储为 8 字节地址) - i8_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - if string.strstr(struct_name, "list[str]") is not None: - return llvmlite.Ptr(pool, i8_ty_d) - if string.strstr(struct_name, "list[bytes]") is not None: - return llvmlite.Ptr(pool, i8_ty_d) - if string.strstr(struct_name, "list[CPtr]") is not None: - return llvmlite.Ptr(pool, i8_ty_d) - # 未知 list[T] 元素类型(如 list[Foo]、list[AST|t.CPtr]):元素存储为 - # 8 字节槽(指针或 8 字节整数),回退 Ptr(i8) 位宽一致(load 8 字节), - # 由 AnnotClassName/特化恢复机制保证语义。禁止 fail-fast(误杀合法 - # 自定义类元素列表的下标访问)。 - return llvmlite.Ptr(pool, i8_ty_d) - - # ============================================================ - # list_setitem_inline — 内联生成 list[T] __setitem__ 逻辑 - # - # 直接存储 rhs_val 到元素地址 (coerce 为 i8* 后 store) - # ============================================================ - def list_setitem_inline(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - lm_obj: llvmlite.Value | t.CPtr, - idx_val: llvmlite.Value | t.CPtr, - rhs_val: llvmlite.Value | t.CPtr, - node: ast.AST | t.CPtr = None) -> int: - """内联生成 list __setitem__ 逻辑,返回 0""" - if builder is None or pool is None or lm_obj is None or idx_val is None or rhs_val is None: - return 0 - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - # 加载 __data__ (偏移 0, index 0) - s_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) - s_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0) - if s_dpp is None: - return 0 - s_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, s_dpp) - # 加载 __elem_size__ (偏移 32, index 4) - s_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) - s_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4) - if s_epp is None: - return 0 - s_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, s_epp) - if s_data is None or s_esize is None: - return 0 - s_idx_i64: llvmlite.Value | t.CPtr = self.coerce_to_type(builder, idx_val, i64_ty, node) - if s_idx_i64 is None: - return 0 - s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize) - if s_offset is None: - return 0 - s_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s_data, s_offset) - if s_addr is None: - return 0 - # 元素类型 T:从 list 特化类型名解析(list[int]→i32、list[str]→i8*)。 - # 此前固定 i8*(8 字节)store(inttoptr 值)覆盖相邻元素——与 - # CallGenMixin list 内置分支同根因(ListTest pop FAILED expect 30)。 - s_sty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(lm_obj) - s_name: str = None - if s_sty is not None: - s_name = llvmlite.get_struct_name(s_sty) - s_elem_ty: llvmlite.LLVMType | t.CPtr = None - if s_name is not None: - s_elem_ty = self._list_elem_type_from_name(pool, s_name) - if s_elem_ty is None: - s_elem_ty = i8_ptr_ty - s_val_ptr: llvmlite.Value | t.CPtr = self.coerce_to_type(builder, rhs_val, s_elem_ty, node) - if s_val_ptr is None: - return 0 - s_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, s_addr, llvmlite.Ptr(pool, s_elem_ty)) - if s_ep is not None: - llvmlite.build_store(builder, s_val_ptr, s_ep) - return 0 - - # ============================================================ - # is_list_subscript — 检查 Subscript 节点是否是 list[T] 类型 - # - # 返回 list 对象指针 (Ptr(list[T])) 或 None - # ============================================================ - def is_list_subscript(self, node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """检查 Subscript 节点是否是 list[T] 类型,返回 list 对象指针或 None""" - if node is None or trans is None: - return None - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - if sub is None or sub.value is None: - return None - if sub.value.kind() != ast.ASTKind.Name: - return None - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) - if nm is None or nm.id is None: - return None - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is None or alloca.Ty is None: - return None - if self.is_ptr_type(alloca.Ty) == 0: - return None - pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee - if pointee is None: - return None - # 检查 pointee 是否是 Ptr(Struct) - inner_ty: llvmlite.LLVMType | t.CPtr = None - match pointee: - case llvmlite.LLVMType.Ptr(it): - inner_ty = it - case _: - return None - if inner_ty is None: - return None - # 检查 inner_ty 是否是 Struct 且名称包含 "list[" - struct_name: str = None - match inner_ty: - case llvmlite.LLVMType.Struct(_, _, sname): - struct_name = sname - case _: - return None - if struct_name is None: - return None - if string.strstr(struct_name, "list[") is None: - return None - # 是 list 类型: load 出 list 对象指针 - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - return llvmlite.build_load(builder, pointee, alloca) - - # ============================================================ - # _nonlocal_subscript_ptr - nonlocal 数组/指针的下标元素指针 - # - # 嵌套函数(提升函数)体内访问 nonlocal 变量时,变量的实际存储是 - # 运行时共享堆(env[ni] 存的堆地址),不能 lookup_var 找外层函数 - # alloca(其 SSA 编号属于外层函数,当前函数引用错乱崩溃—— - # ClosureTest2 Test 4 fill() 内 arr[i] 崩溃根因)。 - # 正确路径:从 env 读堆地址(_load_raw_var_ptr)→ bitcast → GEP。 - # ============================================================ - def _nonlocal_subscript_ptr(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - nm_id: str, - idx_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: - """nonlocal 数组/指针下标:从 env 读堆地址 → bitcast → GEP,返回元素指针""" - if trans is None or nm_id is None or idx_val is None: - return None - nl_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, nm_id) - if nl_ty is None: - return None - raw_nl: llvmlite.Value | t.CPtr = HandlesNonlocal._load_raw_var_ptr(trans, nm_id) - if raw_nl is None: - return None - match nl_ty: - case llvmlite.LLVMType.Array(elem_ty_nl, _cnt_nl): - arr_ptr_nl: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, raw_nl, llvmlite.Ptr(pool, nl_ty)) - if arr_ptr_nl is None: - return None - return llvmlite.build_gep_array( - builder, nl_ty, elem_ty_nl, arr_ptr_nl, - self._zext_index_to_i32(builder, idx_val)) - case llvmlite.LLVMType.Ptr(inner_nl): - arr_ptr_nl2: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, raw_nl, llvmlite.Ptr(pool, nl_ty)) - if arr_ptr_nl2 is None: - return None - return llvmlite.build_gep(builder, inner_nl, arr_ptr_nl2, idx_val) - case _: - arr_ptr_nl3: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, raw_nl, llvmlite.Ptr(pool, nl_ty)) - if arr_ptr_nl3 is None: - return None - return llvmlite.build_gep(builder, nl_ty, arr_ptr_nl3, idx_val) - return None - - # ============================================================ - # 翻译下标表达式 Subscript(value, slice, ctx) — ptr[i] / arr[i] - # - # 指针遍历: ptr 是指针变量,load 出指针值后 GEP + load - # 数组遍历: arr 是数组变量,用 alloca 指针做双索引 GEP [0, i] + load - # list[T]: 泛型类不注册 struct,subscript 走 __getitem__ 内联路径 - # ============================================================ - def translate_subscript(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译下标表达式,返回加载的元素值""" - if node is None or builder is None: - return None - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - if sub is None: - return None - - # 翻译索引 - idx_val: llvmlite.Value | t.CPtr = self.translate_value( - builder, pool, mod, sub.slice, None, 0, trans) - if idx_val is None: - return None - - # 如果 value 是 Name,尝试从 alloca 类型推断 - if sub.value is not None and sub.value.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) - if nm.id is not None and trans is not None: - # nonlocal 数组/指针:从 env 读共享堆地址(提升函数内不能 - # lookup_var 外层 alloca——SSA 编号跨函数错乱崩溃) - # 读路径:元素指针 load 出元素值 - if HT.is_nonlocal_name(trans, nm.id) != 0: - nl_ptr_r: llvmlite.Value | t.CPtr = self._nonlocal_subscript_ptr( - builder, pool, trans, nm.id, idx_val) - if nl_ptr_r is not None and nl_ptr_r.Ty is not None: - nl_elem_ty: llvmlite.LLVMType | t.CPtr = nl_ptr_r.Ty.Pointee - if nl_elem_ty is not None: - return llvmlite.build_load(builder, nl_elem_ty, nl_ptr_r) - return None - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is not None and alloca.Ty is not None: - if self.is_ptr_type(alloca.Ty) != 0: - pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee - if pointee is not None: - # 不调用 pointee.kind() 避免跨模块引用 LLVMType.kind 符号 - # 用 match 检查 pointee 类型 - match pointee: - case llvmlite.LLVMType.Array(elem_ty, count): - # 数组遍历: getelementptr [N x elem_ty], ... , i32 0, i32 %idx - elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, pointee, elem_ty, alloca, - self._zext_index_to_i32(builder, idx_val)) - if elem_ptr is not None: - return llvmlite.build_load(builder, elem_ty, elem_ptr) - return None - case llvmlite.LLVMType.Struct(_fs_v, _fc_v, lsn_v): - # list[T] 值变量(无注解赋值 rhs 返回 list 值, - # 如 parts = s1.split(','):split 的 define 返回 - # %list[str] 结构体值,alloca 直接存 list 对象)。 - # alloca 即 list*,直接走 list 内联 __getitem__ - #(对齐 Ptr(Ptr(list)) 变量路径,修复 parts[0] 崩溃) - if lsn_v is not None: - if string.strstr(lsn_v, "list[") is not None: - elem_addr_v: llvmlite.Value | t.CPtr = \ - self.list_getitem_inline( - builder, pool, alloca, idx_val, node) - if elem_addr_v is not None: - elem_ty_v: llvmlite.LLVMType | t.CPtr = \ - self._list_elem_type_from_name(pool, lsn_v) - if elem_ty_v is not None: - elem_ptr_ty_v: llvmlite.LLVMType | t.CPtr = \ - llvmlite.Ptr(pool, elem_ty_v) - casted_v: llvmlite.Value | t.CPtr = \ - llvmlite.build_bitcast( - builder, elem_addr_v, elem_ptr_ty_v) - if casted_v is not None: - return llvmlite.build_load( - builder, elem_ty_v, casted_v) - return None - case llvmlite.LLVMType.Ptr(inner_ty): - # 检查 inner_ty 是否是 list[T] 类型(泛型类不注册 struct) - # list 的 subscript 应该走 __getitem__ 内联路径,而非指针遍历 - list_struct_name: str = None - match inner_ty: - case llvmlite.LLVMType.Struct(_, _, lsn): - list_struct_name = lsn - case _: - pass - if list_struct_name is not None: - if string.strstr(list_struct_name, "list[") is not None: - # list[T] 类型: 内联生成 __getitem__ 逻辑 - ptr_val_list: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val_list is not None: - elem_addr_list: llvmlite.Value | t.CPtr = self.list_getitem_inline( - builder, pool, ptr_val_list, idx_val, node) - if elem_addr_list is not None: - # 根据类型名提取元素类型,bitcast 后 load - elem_ty_list: llvmlite.LLVMType | t.CPtr = self._list_elem_type_from_name( - pool, list_struct_name) - if elem_ty_list is not None: - elem_ptr_ty_list: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, elem_ty_list) - casted_addr_list: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, elem_addr_list, elem_ptr_ty_list) - if casted_addr_list is not None: - return llvmlite.build_load( - builder, elem_ty_list, casted_addr_list) - return None - # inner_ty 是 Ptr 说明 alloca.Ty 是三重指针 Ptr(Ptr(Ptr(...))), - # 即 X|t.CPtr 当 X 本身是指针类型 (如 T=AST|t.CPtr, T|t.CPtr=AST**)。 - # 此时 [i] 应该是指针解引用 (步长 sizeof(ptr)=8), 而非调用 - # 结构体的 __getitem__ 方法 (会错误生成 AST.__getitem__ 调用)。 - # 对比 HashTable|t.CPtr: alloca.Ty=HashTable**, inner_ty=Struct(HashTable) - # (非 Ptr), 仍走下面的方法调用转发路径。 - if self.is_ptr_type(inner_ty) != 0: - ptr_val_pp: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val_pp is not None: - elem_ptr_pp: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, inner_ty, ptr_val_pp, idx_val) - if elem_ptr_pp is not None: - return llvmlite.build_load(builder, inner_ty, elem_ptr_pp) - return None - # 自定义结构体 (如 HashTable|t.CPtr, JsonValue|t.CPtr): - # 仅当类定义了 __getitem__(当前模块定义或跨模块 stub declare 注入) - # 才转发方法调用;否则普通结构体指针按下标做 GEP 数组访问 - # (对齐 TPC _HandleSubscriptLlvm: if ClassName and has_function(__getitem__)) - cls_nm_rd_ptr: str = self._get_custom_struct_cls_nm(pool, inner_ty) - if not (cls_nm_rd_ptr is None): - gi_lookup_rd: str = pool.alloc(128) - if gi_lookup_rd is not None: - viperlib.snprintf(gi_lookup_rd, 128, "%s.__getitem__", cls_nm_rd_ptr) - if HandlesExprCall.find_func_in_module(mod, gi_lookup_rd) is not None: - obj_ptr_rd: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if not (obj_ptr_rd is None): - arg_vals_rd_p: t.CSizeT | t.CPtr = pool.alloc(8) - if not (arg_vals_rd_p is None): - arg_vals_rd_p[0] = t.CSizeT(idx_val) - ret_rd_p: llvmlite.Value | t.CPtr = HandlesExprCall._call_method_on_ptr( - pool, builder, mod, cls_nm_rd_ptr, "__getitem__", - obj_ptr_rd, arg_vals_rd_p, 1, trans, sub) - if not (ret_rd_p is None): - return ret_rd_p - # 无 __getitem__:结构体指针数组访问(GEP + load) - ptr_val_rd_g: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val_rd_g is not None: - elem_rd_g: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, inner_ty, ptr_val_rd_g, idx_val) - if elem_rd_g is not None: - return llvmlite.build_load(builder, inner_ty, elem_rd_g) - return None - # bytes|t.CPtr / str|t.CPtr: alloca 是 i8**, - # 直接 GEP 按 i8* 步长(8 字节),load i8* - # 仅当 inner_ty 不是自定义结构体时才走指针遍历 - if trans is not None: - ve_pe_ts: HandlesVar.VarEntry | t.CPtr = \ - HandlesVar.lookup_var_entry(trans.SymTab, nm.id) - if ve_pe_ts is not None and ve_pe_ts.IsPtrElement == 1: - # bytes|t.CPtr / str|t.CPtr / T|t.CPtr:变量存指针值(i8*), - # elem[i] 语义 = load [指针值 + i*8](8 字节指针元素)。 - # 必须先 load alloca 得指针值,再 GEP i8*(步长 8)—— - # 否则 GEP base 用 alloca(&elem_ptr)读到栈变量而非数据区, - # list.get 返回"元素地址"而非"元素值"(dump 虚调用读错 vtable)。 - ptr_val_pe_ts: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val_pe_ts is not None: - elem_ptr_ts: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, pointee, ptr_val_pe_ts, idx_val) - if elem_ptr_ts is not None: - return llvmlite.build_load(builder, pointee, elem_ptr_ts) - return None - # 普通指针遍历: 先 load 指针值,再 GEP - ptr_val: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val is not None: - elem_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, inner_ty, ptr_val, idx_val) - if elem_ptr2 is not None: - return llvmlite.build_load(builder, inner_ty, elem_ptr2) - return None - case _: - # 联合类型变量(IsPtrElement=1,如 _list.vp 的 - # elem_ptr: T | t.CPtr 退化为 i8*):pointee=i8 但 - # 元素是 8 字节指针,须按 i8* 步长 GEP + load i8*—— - # 否则 list.get 只读 1 字节,指针截断 inttoptr 崩溃。 - if trans is not None: - ve_pe_rd: HandlesVar.VarEntry | t.CPtr = \ - HandlesVar.lookup_var_entry(trans.SymTab, nm.id) - if ve_pe_rd is not None and ve_pe_rd.IsPtrElement == 1: - match pointee: - case llvmlite.LLVMType.Int8(): - i8_ptr_rd: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - elem_ptr_rd: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i8_ptr_rd, alloca, idx_val) - if elem_ptr_rd is not None: - return llvmlite.build_load( - builder, i8_ptr_rd, elem_ptr_rd) - case _: - pass - # 自定义类(结构体类型): 仅当类定义了 __getitem__ - # (当前模块定义或跨模块 stub declare 注入)才转发方法调用; - # 否则普通结构体指针按下标做 GEP 数组访问 - cls_nm_sub: str = HandlesStruct.get_class_name_by_type(pool, pointee) - if not (cls_nm_sub is None): - gi_lookup_sub: str = pool.alloc(128) - if gi_lookup_sub is not None: - viperlib.snprintf(gi_lookup_sub, 128, "%s.__getitem__", cls_nm_sub) - if HandlesExprCall.find_func_in_module(mod, gi_lookup_sub) is not None: - obj_val_sub: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if not (obj_val_sub is None): - arg_vals_sub: t.CSizeT | t.CPtr = pool.alloc(8) - if not (arg_vals_sub is None): - arg_vals_sub[0] = t.CSizeT(idx_val) - ret_sub: llvmlite.Value | t.CPtr = HandlesExprCall._call_method_on_ptr( - pool, builder, mod, cls_nm_sub, "__getitem__", - obj_val_sub, arg_vals_sub, 1, trans, sub) - if not (ret_sub is None): - return ret_sub - # 无 __getitem__:结构体指针数组访问(GEP + load) - ptr_val_sub_g: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val_sub_g is not None: - elem_sub_g: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, pointee, ptr_val_sub_g, idx_val) - if elem_sub_g is not None: - return llvmlite.build_load(builder, pointee, elem_sub_g) - return None - pass - - # 通用路径:翻译 value 获取指针 - ptr_val: llvmlite.Value | t.CPtr = self.translate_value( - builder, pool, mod, sub.value, None, 0, trans) - if ptr_val is None or ptr_val.Ty is None: - return None - - # 检查是否是指针类型 - if self.is_ptr_type(ptr_val.Ty) != 0: - elem_ty2: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee - if elem_ty2 is not None: - # 数组类型: 双索引 GEP + load 元素 - match elem_ty2: - case llvmlite.LLVMType.Array(arr_elem_ty2, arr_count2): - elem_ptr3: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, elem_ty2, arr_elem_ty2, ptr_val, - self._zext_index_to_i32(builder, idx_val)) - if elem_ptr3 is not None: - return llvmlite.build_load(builder, arr_elem_ty2, elem_ptr3) - return None - case _: - pass - # 自定义结构体 (如 self._ht[key]): 仅当类定义了 __getitem__ 才转发方法调用; - # 否则普通结构体指针按下标做 GEP 数组访问 - cls_nm_rd_gen: str = self._get_custom_struct_cls_nm(pool, elem_ty2) - if not (cls_nm_rd_gen is None): - gi_lookup_gen: str = pool.alloc(128) - if gi_lookup_gen is not None: - viperlib.snprintf(gi_lookup_gen, 128, "%s.__getitem__", cls_nm_rd_gen) - if HandlesExprCall.find_func_in_module(mod, gi_lookup_gen) is not None: - arg_vals_rd_g: t.CSizeT | t.CPtr = pool.alloc(8) - if not (arg_vals_rd_g is None): - arg_vals_rd_g[0] = t.CSizeT(idx_val) - ret_rd_g: llvmlite.Value | t.CPtr = HandlesExprCall._call_method_on_ptr( - pool, builder, mod, cls_nm_rd_gen, "__getitem__", - ptr_val, arg_vals_rd_g, 1, trans, sub) - if not (ret_rd_g is None): - return ret_rd_g - # 无 __getitem__:结构体指针数组访问(GEP + load) - elem_ptr_gen: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, elem_ty2, ptr_val, idx_val) - if elem_ptr_gen is not None: - return llvmlite.build_load(builder, elem_ty2, elem_ptr_gen) - return None - # 指针类型: 单索引 GEP + load - elem_ptr4: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, elem_ty2, ptr_val, idx_val) - if elem_ptr4 is not None: - return llvmlite.build_load(builder, elem_ty2, elem_ptr4) - return None - - # ============================================================ - # find_global_in_module - 在模块全局变量链表中按名称查找 - # - # 查找策略: - # 1. 精确匹配 (如 "_mbuddy" 匹配 @_mbuddy) - # 2. 后缀匹配 (如 "_mbuddy" 匹配 @"sha1._mbuddy") - # ============================================================ - def find_global_in_module(self, mod: llvmlite.LLVMModule | t.CPtr, - name: str) -> llvmlite.GlobalVariable | t.CPtr: - """在模块全局变量链表中按名称查找全局变量""" - if mod is None or name is None: - return None - name_len: t.CSizeT = string.strlen(name) - cur: llvmlite.GlobalVariable | t.CPtr = mod.GlobalHead - # 第一遍: 精确匹配 - while cur is not None: - if cur.Name is not None: - if string.strcmp(cur.Name, name) == 0: - return cur - cur = cur.Next - # 第二遍: 后缀匹配 (.name) - cur = mod.GlobalHead - while cur is not None: - if cur.Name is not None: - cur_len: t.CSizeT = string.strlen(cur.Name) - if cur_len > name_len + 1: - suffix_start: t.CSizeT = cur_len - name_len - if cur.Name[suffix_start - 1] == '.': - match: int = 1 - for i in range(name_len): - if cur.Name[suffix_start + i] != name[i]: - match = 0 - break - if match == 1: - return cur - cur = cur.Next - return None - - # ============================================================ - # make_global_ref - 创建全局变量引用 (@name,类型为 ty*) - # - # 用于跨模块全局变量访问: stub 未注入时,翻译阶段生成 @name 引用, - # 链接时由 stub 提供 external global 声明。 - # ============================================================ - def make_global_ref(self, pool: memhub.MemBuddy | t.CPtr, - name: str, - ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: - """创建全局变量引用 (类型为 ty*,名称为 @name)""" - if name is None or ty is None: - return None - ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, ty) - ref_name: str = pool.alloc(64) - if ref_name is None: - return None - viperlib.snprintf(ref_name, 64, "@%s", name) - return llvmlite.SSAValue(pool, ptr_ty, ref_name) - - # ============================================================ - # _resolve_module_attribute_global - 解析模块属性访问的全局变量引用 - # - # 当 obj 是已导入模块名 (如 sys._mbuddy) 时: - # 1. 在当前模块全局变量链表中查找 (stub 已注入的情况) - # 2. 未找到则创建前向引用 (@attr_name, 类型为 ty 参数) - # - # 参数: - # ty_hint: 类型提示 (写路径用 rhs 类型, 读路径用 i8* 回退) - # 返回: Value 指针 (类型为 ty*),未识别为模块属性返回 None - # ============================================================ - def _is_t_type_object_name(self, name: str) -> int: - """检查 name 是否是 t.py 中的类型对象名(CPtr/CInt/CDouble 等) - - 这些类型对象在运行时作为全局变量 @CPtr/@CInt 等被引用, - 但 t.py 不被编译,需要在使用处生成带 null 初值的定义。 - """ - if name is None: - return 0 - # t.py 中的类型对象名(PascalCase,首字母大写) - if string.strcmp(name, "CPtr") == 0: - return 1 - if string.strcmp(name, "CInt") == 0: - return 1 - if string.strcmp(name, "CChar") == 0: - return 1 - if string.strcmp(name, "CShort") == 0: - return 1 - if string.strcmp(name, "CLong") == 0: - return 1 - if string.strcmp(name, "CLongLong") == 0: - return 1 - if string.strcmp(name, "CDouble") == 0: - return 1 - if string.strcmp(name, "CFloat") == 0: - return 1 - if string.strcmp(name, "CBool") == 0: - return 1 - if string.strcmp(name, "CVoid") == 0: - return 1 - if string.strcmp(name, "CInt8T") == 0: - return 1 - if string.strcmp(name, "CInt16T") == 0: - return 1 - if string.strcmp(name, "CInt32T") == 0: - return 1 - if string.strcmp(name, "CInt64T") == 0: - return 1 - if string.strcmp(name, "CUInt8T") == 0: - return 1 - if string.strcmp(name, "CUInt16T") == 0: - return 1 - if string.strcmp(name, "CUInt32T") == 0: - return 1 - if string.strcmp(name, "CUInt64T") == 0: - return 1 - if string.strcmp(name, "CUnsigned") == 0: - return 1 - if string.strcmp(name, "CUnsignedInt") == 0: - return 1 - if string.strcmp(name, "CUnsignedChar") == 0: - return 1 - if string.strcmp(name, "CUnsignedShort") == 0: - return 1 - if string.strcmp(name, "CUnsignedLong") == 0: - return 1 - if string.strcmp(name, "CUnsignedLongLong") == 0: - return 1 - if string.strcmp(name, "CSizeT") == 0: - return 1 - if string.strcmp(name, "CIntPtrT") == 0: - return 1 - if string.strcmp(name, "CUIntPtrT") == 0: - return 1 - if string.strcmp(name, "CPtrDiffT") == 0: - return 1 - if string.strcmp(name, "CType") == 0: - return 1 - if string.strcmp(name, "CDefine") == 0: - return 1 - if string.strcmp(name, "CStatic") == 0: - return 1 - if string.strcmp(name, "CExport") == 0: - return 1 - if string.strcmp(name, "CArray") == 0: - return 1 - if string.strcmp(name, "CTypedef") == 0: - return 1 - if string.strcmp(name, "CNoVTable") == 0: - return 1 - if string.strcmp(name, "CNeedPtr") == 0: - return 1 - if string.strcmp(name, "CAutoPtr") == 0: - return 1 - return 0 - - def _attr_module_path_str(self, pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr) -> str: - """把模块引用 AST 转成模块路径字符串(递归拼接 Attribute 链): - Name('sys') → "sys";Attribute(Attribute(Name('os'),'_win32')) → "os._win32"。 - 非模块引用形态(Call/Subscript 等)返回 None。""" - if node is None: - return None - k: int = node.kind() - if k == ast.ASTKind.Name: - nm_m: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm_m.id is not None: - return nm_m.id - return None - if k == ast.ASTKind.Attribute: - at_m: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at_m.attr is None: - return None - base_m: str = self._attr_module_path_str(pool, at_m.value) - if base_m is None: - return None - blen: t.CSizeT = string.strlen(base_m) - alen: t.CSizeT = string.strlen(at_m.attr) - buf_m: str = pool.alloc(blen + alen + 2) - if buf_m is None: - return None - viperlib.snprintf(buf_m, blen + alen + 2, "%s.%s", base_m, at_m.attr) - return buf_m - return None - - def _resolve_module_attribute_global(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - trans: HT.Translator | t.CPtr, - at: ast.Attribute | t.CPtr, - ty_hint: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: - """解析模块属性访问,返回全局变量引用 (用于跨模块 global 访问)""" - if at is None or at.value is None or at.attr is None: - return None - if trans is None or trans._imported_modules is None: - return None - # 提取模块路径名:Name → "sys";嵌套 Attribute → "os._win32" - # (此前只支持 Name 模块;SysLibTest main.vp L32 `os._win32._mbuddy = v` - # 的 at.value 是 Attribute → 被跳过 → "属性写入失败" 根因) - mod_path_w: str = self._attr_module_path_str(pool, at.value) - if mod_path_w is None: - return None - # 检查是否是已导入模块 - if HandlesImports.is_module_imported(trans._imported_modules, mod_path_w) == 0: - return None - # 在当前模块查找全局变量 (stub 可能已注入) - gv: llvmlite.GlobalVariable | t.CPtr = self.find_global_in_module(mod, at.attr) - if gv is not None and gv.Ty is not None: - return self.make_global_ref(pool, at.attr, gv.Ty) - # 未找到: 创建 external global 声明并添加到模块 - # 否则只生成 @_argc 引用而无声明,LLVM 报 "use of undefined value '@_argc'" - use_ty: llvmlite.LLVMType | t.CPtr = ty_hint - if use_ty is None: - use_ty = llvmlite.Int8(pool) - # 确保 use_ty 中的跨模块结构体类型有 opaque 声明 - llvmlite.module_ensure_opaque_for_type(mod, pool, use_ty) - # 特殊处理: t.py 中的类型对象(CPtr/CInt/CDouble 等) - # t.py 不被编译,但这些类型对象在运行时被引用(如 va_arg(ap, t.CPtr))。 - # 创建带 null 初值的 linkonce_odr 全局变量定义,避免链接时 undefined reference。 - # LLVM 22+ 不允许 external linkage 全局变量带初值,使用 linkonce_odr 替代。 - is_t_type_obj: int = 0 - if string.strcmp(mod_path_w, "t") == 0: - is_t_type_obj = self._is_t_type_object_name(at.attr) - ext_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, at.attr, use_ty) - if ext_gv is not None: - if is_t_type_obj != 0: - # t.CPtr 等类型对象: 创建带 null 初值的定义(linkonce_odr) - ext_gv.Linkage = "linkonce_odr" - # i8* null 的初值文本 - null_init: bytes = pool.alloc(8) - if null_init is not None: - null_init[0] = 'n' - null_init[1] = 'u' - null_init[2] = 'l' - null_init[3] = 'l' - null_init[4] = '\0' - ext_gv.Initializer = null_init - else: - ext_gv.Initializer = None - else: - # 普通模块属性: external 声明(由其他模块提供定义) - ext_gv.Linkage = "external" - ext_gv.Initializer = None - llvmlite.module_add_global(mod, ext_gv) - return self.make_global_ref(pool, at.attr, use_ty) - - # ============================================================ - # 翻译属性访问 Attribute(value, attr, ctx) — obj.field - # - # 优先级: - # 1. 枚举成员访问 (State.Idle → 常量值) - # 2. 模块属性访问 (sys._mbuddy → 加载全局变量) - # 3. 结构体字段访问 (obj.field → GEP + load) - # - # 对于 Name 类型的 obj,直接使用 alloca 指针(不 load 结构体) - # ============================================================ - - - # ============================================================ - # _get_cderef_attr_base - c.Deref(ptr).attr 属性访问的 base 指针 - # - # c.Deref(ptr) 作为属性访问 base 时(如 c.Deref(p).a),需要 ptr - # 指针本身而非 load 后的结构体值(*p.a → p->a),与 TPC - # _handle_attr_call_result 语义一致。否则 c.Deref 返回结构体值, - # 后续 GEP 在非指针上做属性访问会误报"base=非指针类型"。 - # - # 返回: - # ptr 指针值(Ptr(Struct) 或 Ptr(Ptr(Struct)),交由 _deref_if_ptr_ptr 解层级) - # 非 c.Deref 模式返回 None - # ============================================================ - def _get_cderef_attr_base(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - at_value: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """检测 at.value 是否为 c.Deref(ptr) 调用,返回 ptr 指针(不做 load)""" - if at_value is None or at_value.kind() != ast.ASTKind.Call: - return None - cl_cd: ast.Call | t.CPtr = (ast.Call | t.CPtr)(at_value) - if cl_cd.func is None or cl_cd.func.kind() != ast.ASTKind.Attribute: - return None - f_cd: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl_cd.func) - if f_cd.attr is None or string.strcmp(f_cd.attr, "Deref") != 0: - return None - if f_cd.value is None or f_cd.value.kind() != ast.ASTKind.Name: - return None - nm_cd: ast.Name | t.CPtr = (ast.Name | t.CPtr)(f_cd.value) - if nm_cd.id is None or string.strcmp(nm_cd.id, "c") != 0: - return None - if cl_cd.args is None or len(cl_cd.args) < 1: - return None - inner_cd: llvmlite.Value | t.CPtr = self.translate_value( - builder, pool, mod, cl_cd.args.get(0), None, 0, trans) - if inner_cd is not None and self.is_ptr_type(inner_cd.Ty) != 0: - return inner_cd - return None - - # ============================================================ - # docstring 提取/登记/查找(__doc__ 魔法属性支持) - # - # 预注册阶段(BuildPipeline.TranslateFileGetTrans)扫描所有 - # App/includes 文件的 AST,提取函数/类/方法的 docstring 内容 - # 登记到全局表(key = "{module_sha1}.{symbol}");__doc__ 属性 - # 访问时查表,命中则当前模块内联生成字符串常量(无跨模块 IR - # 符号依赖),未命中返回 null。幂等查重,多遍翻译安全。 - # ============================================================ - - def _extract_docstring_from_body(self, body: list[ast.AST | t.CPtr] | t.CPtr) -> str: - """从函数/类体提取 docstring:body[0] 为 Expr(Constant str) 时返回内容""" - if body is None or len(body) == 0: - return None - first: ast.AST | t.CPtr = body.get(0) - if first is None or first.kind() != ast.ASTKind.Expr: - return None - ex: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(first) - if ex is None or ex.value is None or ex.value.kind() != ast.ASTKind.Constant: - return None - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(ex.value) - if cn is None or cn.const_kind != ast.CONST_STR: - return None - return cn.str_val - - def register_docstring(self, module_sha1: str, symbol: str, doc: str) -> None: - """登记 docstring(key="{module_sha1}.{symbol}"),查重幂等""" - if module_sha1 is None or symbol is None or doc is None: - return - if string.strlen(doc) == 0: - return - if self.DocKeys is None: - self.DocKeys = CompilerFactory.get_perm_pool().alloc(DOC_MAX * DOC_KEY_SZ) - self.DocValues = CompilerFactory.get_perm_pool().alloc(DOC_MAX * DOC_VAL_SZ) - if self.DocKeys is None or self.DocValues is None: - return - string.memset(self.DocKeys, 0, DOC_MAX * DOC_KEY_SZ) - string.memset(self.DocValues, 0, DOC_MAX * DOC_VAL_SZ) - if self.DocCount >= DOC_MAX: - return - ml: t.CSizeT = string.strlen(module_sha1) - sl: t.CSizeT = string.strlen(symbol) - key_buf: bytes = stdlib.malloc(ml + sl + 2) - if key_buf is None: - return - viperlib.snprintf(key_buf, ml + sl + 2, "%s.%s", module_sha1, symbol) - i: int - for i in range(self.DocCount): - if string.strcmp(self.DocKeys + i * DOC_KEY_SZ, key_buf) == 0: - stdlib.free(key_buf) - return - string.strcpy(self.DocKeys + self.DocCount * DOC_KEY_SZ, key_buf) - string.strcpy(self.DocValues + self.DocCount * DOC_VAL_SZ, doc) - self.DocCount += 1 - stdlib.free(key_buf) - - def lookup_docstring(self, module_sha1: str, symbol: str) -> str: - """查找 docstring 内容(key="{module_sha1}.{symbol}"),未找到返回 None""" - if self.DocKeys is None or module_sha1 is None or symbol is None: - return None - ml: t.CSizeT = string.strlen(module_sha1) - sl: t.CSizeT = string.strlen(symbol) - key_buf: bytes = stdlib.malloc(ml + sl + 2) - if key_buf is None: - return None - viperlib.snprintf(key_buf, ml + sl + 2, "%s.%s", module_sha1, symbol) - i: int - for i in range(self.DocCount): - if string.strcmp(self.DocKeys + i * DOC_KEY_SZ, key_buf) == 0: - stdlib.free(key_buf) - return self.DocValues + i * DOC_VAL_SZ - stdlib.free(key_buf) - return None - - def extract_module_docstrings(self, tree: ast.AST | t.CPtr, module_sha1: str) -> None: - """扫描模块 AST:登记模块级函数/类/方法的 docstring(幂等)""" - if tree is None or module_sha1 is None: - return - ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children - if ch is None: - return - cn: t.CSizeT = len(ch) - for ci in range(cn): - child: ast.AST | t.CPtr = ch.get(ci) - if child is None: - continue - kd: int = child.kind() - if kd == ast.ASTKind.FunctionDef: - fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child) - if fd is not None and fd.name is not None: - fd_body: list[ast.AST | t.CPtr] | t.CPtr = fd.children - fdoc: str = self._extract_docstring_from_body(fd_body) - if fdoc is not None: - self.register_docstring(module_sha1, fd.name, fdoc) - elif kd == ast.ASTKind.ClassDef: - cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child) - if cd is None or cd.name is None: - continue - cd_body0: list[ast.AST | t.CPtr] | t.CPtr = cd.children - cdoc: str = self._extract_docstring_from_body(cd_body0) - if cdoc is not None: - self.register_docstring(module_sha1, cd.name, cdoc) - # 类方法 docstring(key="{ClassName}.{method}") - cd_body: list[ast.AST | t.CPtr] | t.CPtr = cd.children - if cd_body is not None: - cbn: t.CSizeT = len(cd_body) - for mi in range(cbn): - m: ast.AST | t.CPtr = cd_body.get(mi) - if m is None or m.kind() != ast.ASTKind.FunctionDef: - continue - mfd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(m) - if mfd is None or mfd.name is None: - continue - mdoc: str = self._extract_docstring_from_body(mfd.children) - if mdoc is not None: - cl_nl: t.CSizeT = string.strlen(cd.name) - mt_nl: t.CSizeT = string.strlen(mfd.name) - sym_buf: bytes = stdlib.malloc(cl_nl + mt_nl + 2) - if sym_buf is not None: - viperlib.snprintf(sym_buf, cl_nl + mt_nl + 2, "%s.%s", cd.name, mfd.name) - self.register_docstring(module_sha1, sym_buf, mdoc) - stdlib.free(sym_buf) - - def _resolve_doc_symbol_name(self, trans: HT.Translator | t.CPtr, name_id: str, - out_mod: str | t.CPtr, out_sym: str | t.CPtr) -> int: - """解析 Name 符号的 docstring 归属,写入 out_mod/out_sym,成功返回 1 - - 判定顺序:本地变量(函数变量)→ 结构体类(含跨模块预注册)→ 模块名。 - """ - if trans is None or name_id is None or out_mod is None or out_sym is None: - return 0 - if trans.ModuleSha1 is None: - return 0 - # 1. 本地变量(函数变量/全局变量) - if HandlesVar.lookup_var(trans.SymTab, name_id) is not None: - string.strcpy(out_mod, trans.ModuleSha1) - string.strcpy(out_sym, name_id) - return 1 - # 2. 结构体类(entry.ModuleSha1 区分跨模块预注册的类) - se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(name_id) - if se is not None: - if se.ModuleSha1 is not None: - string.strcpy(out_mod, se.ModuleSha1) - else: - string.strcpy(out_mod, trans.ModuleSha1) - string.strcpy(out_sym, name_id) - return 1 - # 3. 模块名(模块本身,少见);用 StubMerger 模块级函数(避免 - # 跨 Mixin self 调用生成不存在符号) - mod_sha1: str = StubMerger.LookupSha1ByModName(name_id) - if mod_sha1 is None: - mod_sha1 = StubMerger.LookupSha1ByModNameSuffix(name_id) - if mod_sha1 is not None: - string.strcpy(out_mod, mod_sha1) - string.strcpy(out_sym, name_id) - return 1 - # 4. 兜底当前模块 - string.strcpy(out_mod, trans.ModuleSha1) - string.strcpy(out_sym, name_id) - return 1 - - def _resolve_doc_symbol_attr(self, trans: HT.Translator | t.CPtr, - at: ast.Attribute | t.CPtr, - out_mod: str | t.CPtr, out_sym: str | t.CPtr) -> int: - """解析嵌套 Attribute 链的 docstring 归属,写入 out_mod/out_sym - - 支持形态:remote.remote_func / remote.RemoteClass / - remote.RemoteClass.remote_method / LocalClass.local_method 等。 - 最左 Name 判定:模块名 → 该模块 sha1;变量/类 → 类所属模块 sha1。 - """ - if trans is None or at is None or out_mod is None or out_sym is None: - return 0 - if trans.ModuleSha1 is None: - return 0 - # 收集 Attribute 链(最外层 attr 在前) - DOC_CHAIN_MAX: t.CInt = 8 - items: bytes = stdlib.malloc(DOC_CHAIN_MAX * 128) - if items is None: - return 0 - n_items: int = 0 - cur: ast.AST | t.CPtr = (ast.AST | t.CPtr)(at) - while cur is not None and cur.kind() == ast.ASTKind.Attribute and n_items < DOC_CHAIN_MAX: - cat: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cur) - if cat.attr is None: - break - string.strcpy(items + n_items * 128, cat.attr) - n_items += 1 - cur = cat.value - # 最左应为 Name - head_id: str = None - if cur is not None and cur.kind() == ast.ASTKind.Name: - hnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cur) - head_id = hnm.id - if head_id is None: - stdlib.free(items) - return 0 - # head 判定:模块名 or 变量/类 - is_mod: int = 0 - mod_sha1: str = None - if HandlesVar.lookup_var(trans.SymTab, head_id) is None: - mod_sha1 = StubMerger.LookupSha1ByModName(head_id) - if mod_sha1 is None: - mod_sha1 = StubMerger.LookupSha1ByModNameSuffix(head_id) - if mod_sha1 is not None: - is_mod = 1 - if is_mod != 0: - # 模块限定:symbol = items 反转(不含 head_id) - if n_items == 0: - string.strcpy(out_mod, mod_sha1) - string.strcpy(out_sym, head_id) - stdlib.free(items) - return 1 - total: t.CSizeT = 0 - j: int - for j in range(n_items): - total += string.strlen(items + j * 128) + 1 - sym_buf: bytes = stdlib.malloc(total + 1) - if sym_buf is None: - stdlib.free(items) - return 0 - sym_buf[0] = '\0' - for j in range(n_items): - if j > 0: - string.strcat(sym_buf, ".") - string.strcat(sym_buf, items + (n_items - 1 - j) * 128) - string.strcpy(out_mod, mod_sha1) - string.strcpy(out_sym, sym_buf) - stdlib.free(sym_buf) - stdlib.free(items) - return 1 - # 变量/类:symbol = head_id + '.' + items 反转 - total2: t.CSizeT = string.strlen(head_id) - for j in range(n_items): - total2 += string.strlen(items + j * 128) + 1 - sym2: bytes = stdlib.malloc(total2 + 1) - if sym2 is None: - stdlib.free(items) - return 0 - sym2[0] = '\0' - string.strcat(sym2, head_id) - for j in range(n_items): - string.strcat(sym2, ".") - string.strcat(sym2, items + (n_items - 1 - j) * 128) - se2: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(head_id) - if se2 is not None and se2.ModuleSha1 is not None: - string.strcpy(out_mod, se2.ModuleSha1) - else: - string.strcpy(out_mod, trans.ModuleSha1) - string.strcpy(out_sym, sym2) - stdlib.free(sym2) - stdlib.free(items) - return 1 - - def translate_attribute(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译属性访问,返回加载的字段值""" - if node is None or builder is None: - return None - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at is None or at.value is None or at.attr is None: - # fast-fail: AST 节点字段缺失属解析器 bug,应报告具体缺失字段 - diag_buf_an: bytes = stdlib.malloc(256) - if diag_buf_an is not None: - missing_an: str = "?" - if at is not None: - if at.value is None: - missing_an = "value" - elif at.attr is None: - missing_an = "attr" - viperlib.snprintf(diag_buf_an, 256, - "属性访问失败: AST 节点字段缺失 (%s sha1=%s:%d)", - missing_an, - trans.ModuleSha1 if trans is not None and trans.ModuleSha1 is not None else "?", - at.lineno if at is not None and at.lineno is not None else 0) - VLogger.error(diag_buf_an, "ATTR") - return None - - # 魔法属性 __doc__:查询 docstring 登记表(预注册阶段从 AST 提取), - # 命中则当前模块内联生成字符串常量返回;未命中(无 docstring 的 - # 函数/类/方法)返回 null 指针(i8*)。支持本模块与跨模块符号: - # local_func / LocalClass / LocalClass.method / remote.remote_func / - # remote.RemoteClass / remote.RemoteClass.remote_method - if string.strcmp(at.attr, "__doc__") == 0: - doc_mod_buf: bytes = pool.alloc(64) - doc_sym_buf: bytes = pool.alloc(256) - if doc_mod_buf is None or doc_sym_buf is None: - return None - doc_mod_buf[0] = '\0' - doc_sym_buf[0] = '\0' - if at.value is not None and at.value.kind() == ast.ASTKind.Name: - nm_doc: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm_doc.id is not None: - self._resolve_doc_symbol_name(trans, nm_doc.id, doc_mod_buf, doc_sym_buf) - elif at.value is not None and at.value.kind() == ast.ASTKind.Attribute: - self._resolve_doc_symbol_attr(trans, (ast.Attribute | t.CPtr)(at.value), doc_mod_buf, doc_sym_buf) - doc_val: str = None - if doc_mod_buf[0] != '\0' and doc_sym_buf[0] != '\0': - doc_val = self.lookup_docstring(doc_mod_buf, doc_sym_buf) - if doc_val is None: - i8_ty_doc: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - if i8_ty_doc is None: - return None - i8_ptr_ty_doc: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_doc) - if i8_ptr_ty_doc is None: - return None - return llvmlite.ConstNull(pool, i8_ptr_ty_doc, "null") - return self.create_global_string(builder, pool, mod, doc_val, trans) - - # 枚举成员访问: EnumName.MemberName → 常量值 - # 当 value 是 Name 且 Name.id 是已注册枚举时,查找成员并返回常量 - if at.value.kind() == ast.ASTKind.Name: - enum_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if enum_nm.id is not None: - if HandlesEnum.is_enum_class(enum_nm.id) == 1: - member: HandlesEnum.EnumMember | t.CPtr = HandlesEnum.lookup_enum_member( - enum_nm.id, at.attr) - if member is not None: - base_ty: llvmlite.LLVMType | t.CPtr = HandlesEnum.get_enum_base_type( - enum_nm.id) - if base_ty is not None: - # 生成数字字符串作为常量名(LLVM IR 要求常量输出数字值) - name_buf: str = pool.alloc(32) - if name_buf is not None: - viperlib.snprintf(name_buf, 32, "%lld", member.Value) - return llvmlite.ConstInt(pool, base_ty, member.Value, name_buf) - return llvmlite.const_int32(pool, member.Value) - # fast-fail: 枚举成员未找到 - VLogger.error( - f"枚举成员未找到: {enum_nm.id}.{at.attr}", - "ATTR") - return None - - # 嵌套枚举成员访问: Module.EnumName.MemberName → 常量值 - # 当 value 是 Attribute(如 fileio.MODE / w32.fileio.MODE,含三级以上 - # 模块路径)且 attr 部分是已注册枚举时。此前限制 inner_at_e.value 必须是 - # Name(仅支持两层 Module.EnumName),w32.fileio.MODE.W(三层,value 是 - # Attribute)被跳过 → "属性访问失败: .W"(SysLibTest L190 根因)。 - # 枚举类名只取最内层 attr(MODE),模块路径形态不影响。 - if at.value.kind() == ast.ASTKind.Attribute: - inner_at_e: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(at.value) - if inner_at_e.attr is not None: - if HandlesEnum.is_enum_class(inner_at_e.attr) == 1: - member_e: HandlesEnum.EnumMember | t.CPtr = HandlesEnum.lookup_enum_member( - inner_at_e.attr, at.attr) - if member_e is not None: - base_ty_e: llvmlite.LLVMType | t.CPtr = HandlesEnum.get_enum_base_type( - inner_at_e.attr) - if base_ty_e is not None: - name_buf_e: str = pool.alloc(32) - if name_buf_e is not None: - viperlib.snprintf(name_buf_e, 32, "%lld", member_e.Value) - return llvmlite.ConstInt(pool, base_ty_e, member_e.Value, name_buf_e) - return llvmlite.const_int32(pool, member_e.Value) - # fast-fail: 嵌套枚举成员未找到 - dbg_ee: HandlesEnum.EnumEntry | t.CPtr = HandlesEnum.find_enum( - inner_at_e.attr) - dbg_mc: int = -1 - if dbg_ee is not None: - dbg_mc = dbg_ee.MemberCount - VLogger.error( - f"嵌套枚举成员未找到: {inner_at_e.attr}.{at.attr} " - f"(enum_members={dbg_mc})", "ATTR") - return None - - # FakeDuck: 影子结构体属性读取 (str 变量的 per-instance 字段) - # a.__data__ / a.__mbuddy__ → GEP {a}__meta__[field] 并加载 - # 对齐 TPC HandlesExprAttr.py L433-442:对象是 Name 变量且存在 - # {var}__meta__ 影子(fd2 创建)时,属性访问改走影子结构体。 - if at.value.kind() == ast.ASTKind.Name and trans is not None: - fd_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if fd_nm.id is not None: - # pool 持久缓冲(f-string 栈缓冲在函数返回后失效) - fd_meta_buf: str = pool.alloc(256) - if fd_meta_buf is not None: - viperlib.snprintf(fd_meta_buf, 256, "%s__meta__", fd_nm.id) - fd_meta_v: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( - trans.SymTab, fd_meta_buf) - if fd_meta_v is not None: - fd_sty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type( - "_str") - if fd_sty is not None: - fd_fe: HandlesStruct.FieldEntry | t.CPtr = \ - HandlesStruct.lookup_field(fd_sty, at.attr) - if fd_fe is not None and fd_fe.Ty is not None: - fd_fp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, fd_sty, fd_fe.Ty, fd_meta_v, fd_fe.Index) - if fd_fp is not None: - return llvmlite.build_load(builder, fd_fe.Ty, fd_fp) - - # 模块属性访问 (读路径): sys._mbuddy → 加载全局变量 @_mbuddy - # 当 obj 是已导入模块名且不是普通变量时,查找/创建全局变量引用并加载 - if at.value.kind() == ast.ASTKind.Name and trans is not None: - nm_ma: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm_ma.id is not None: - # 先检查是否是普通变量 (优先级高于模块属性) - ma_is_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, nm_ma.id) - if ma_is_var is None: - # 先检查是否是 CDefine 编译期常量 (如 ast.CONST_INT / win32base.INVALID_HANDLE_VALUE) - # 模块属性访问的 CDefine 常量需要跨模块查找源 .vp / .vpi 文件 - cdef_ma_val: t.CInt64T = HandlesType.lookup_cdefine_constant(at.attr) - cd_local: int = HandlesType.is_cdefine_found() - if cd_local == 0: - # 确定真实模块名:优先从 _from_imports 解析别名 - # from_imports 中条目格式 "local_name:real_module" - # 如 win32base:w32.win32base → 别名 win32base 真实模块 w32.win32base - real_mod_name: str = nm_ma.id - if trans._from_imports is not None: - resolved_mod: str = HandlesImports.lookup_from_import( - trans._from_imports, nm_ma.id, 0) - if resolved_mod is not None: - # 复制模块名到新缓冲区(截断于空格、null、或 ':') - rm_len: t.CSizeT = 0 - while resolved_mod[rm_len] != ' ' and resolved_mod[rm_len] != '\0' and resolved_mod[rm_len] != ':': - rm_len += 1 - rm_buf: str = pool.alloc(rm_len + 1) - if rm_buf is not None: - for rm_i in range(rm_len): - rm_buf[rm_i] = resolved_mod[rm_i] - rm_buf[rm_len] = '\0' - real_mod_name = rm_buf - # 即使 _from_imports 为 None(如纯 `import ast` 无 from-import), - # 也必须尝试跨模块 CDefine 查找,否则 ast.CONST_INT 会被 - # 误解析为全局变量引用 @CONST_INT(未定义符号)。 - # 构建临时 from_imports "{attr}:{real_module}" 用于跨模块查找 - if real_mod_name is not None: - ma_fi_len: t.CSizeT = string.strlen(at.attr) + string.strlen(real_mod_name) + 2 - ma_fi: str = pool.alloc(ma_fi_len) - if ma_fi is not None: - viperlib.snprintf(ma_fi, ma_fi_len, "%s:%s", at.attr, real_mod_name) - cdef_ma_val = self._lookup_cross_module_cdefine(pool, at.attr, ma_fi) - if HandlesType.is_cdefine_found() != 0: - # 跨模块字符串 CDefine(如 pyzlib.ZLIB_VERSION = "1.3.2")→ - # 字符串全局常量(test_pyzlib.vp L49 ver = pyzlib.ZLIB_VERSION) - if HandlesType.is_cdefine_str() != 0: - cdef_str_v: str = HandlesType.lookup_cdefine_string(at.attr) - if cdef_str_v is not None: - return self.create_global_string( - builder, pool, mod, cdef_str_v, trans) - # 跨模块浮点 CDefine(如 vipermath.U_M_PI)→ 浮点常量 - dchk_ma: double = HandlesType.lookup_cdefine_double(at.attr) - if HandlesType.is_cdefine_double() != 0: - return llvmlite.ConstFloat(pool, llvmlite.Double(pool), dchk_ma) - return self._const_int_for_cdefine(pool, cdef_ma_val) - # 检查 nm_ma.id.at.attr 是否是已导入子模块 (如 w32.win32file) - # 如果是子模块,不应创建全局变量,让嵌套属性访问路径处理 - is_submod: int = 0 - if trans._imported_modules is not None: - submod_len: t.CSizeT = string.strlen(nm_ma.id) + string.strlen(at.attr) + 2 - submod_buf: str = pool.alloc(submod_len) - if submod_buf is not None: - viperlib.snprintf(submod_buf, submod_len, "%s.%s", nm_ma.id, at.attr) - if HandlesImports.is_module_imported(trans._imported_modules, submod_buf) == 1: - is_submod = 1 - # also check from_imports: at.attr 别名对应真实模块 w32.win32file - if is_submod == 0 and trans._from_imports is not None: - fi_mod_raw: str = HandlesImports.lookup_from_import( - trans._from_imports, at.attr, 0) - if fi_mod_raw is not None: - # 复制模块名到新缓冲区(截断于空格、null、或 ':') - fm_len: t.CSizeT = 0 - while fi_mod_raw[fm_len] != ' ' and fi_mod_raw[fm_len] != '\0' and fi_mod_raw[fm_len] != ':': - fm_len += 1 - fi_mod: str = pool.alloc(fm_len + 1) - if fi_mod is not None: - for fm_i in range(fm_len): - fi_mod[fm_i] = fi_mod_raw[fm_i] - fi_mod[fm_len] = '\0' - # 检查 fi_mod 是否以 "nm_ma.id." 开头 (如 w32.win32file 以 w32. 开头) - prefix_len: t.CSizeT = string.strlen(nm_ma.id) - fi_mod_len: t.CSizeT = string.strlen(fi_mod) - if fi_mod_len > prefix_len + 1: - match_prefix: int = 1 - for pi in range(prefix_len): - if fi_mod[pi] != nm_ma.id[pi]: - match_prefix = 0 - break - if match_prefix == 1 and fi_mod[prefix_len] == '.': - is_submod = 1 - if is_submod != 0: - return None # 是子模块,交给嵌套属性访问路径 - # 特殊处理: t.ASM_DESCR 不是 CDefine,是内联汇编约束命名空间 - # t.ASM_DESCR.XXX 由 HandlesExprCall 的 _asm_resolve_constraint 处理 - # 此处返回 None,让上层嵌套属性访问路径处理 - if string.strcmp(nm_ma.id, "t") == 0 and string.strcmp(at.attr, "ASM_DESCR") == 0: - return None - # CDefine 未找到且属性名符合 ALL_CAPS 约定: fail-fast 终止编译 - # 不再创建未定义的外部全局变量引用(否则 llc 报 "use of undefined value") - if self._is_cdefine_name_pattern(at.attr) != 0: - HandlesType.fatal_error( - at, - f"跨模块 CDefine 未找到: '{nm_ma.id}.{at.attr}'(CDefine cross-module lookup failed)", - "TypeError") - # 非 CDefine: 使用 i8* 作为类型提示 (模块级变量通常存储指针) - i8_ptr_hint: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - mod_gv_ref: llvmlite.Value | t.CPtr = self._resolve_module_attribute_global( - pool, mod, trans, at, i8_ptr_hint) - if mod_gv_ref is not None and mod_gv_ref.Ty is not None: - load_ty_mod: llvmlite.LLVMType | t.CPtr = mod_gv_ref.Ty.Pointee - if load_ty_mod is not None: - # 模块级全局数组(如 zdef.zdeflate_len_base: CArray[T, N]): - # 按 C 语义衰减为基址返回(对齐 translate_name_value 局部 - # 数组分支 L3383-3388),load [N x T] 数组值无法作 GEP 基址。 - match load_ty_mod: - case llvmlite.LLVMType.Array(_, _): - return mod_gv_ref - case _: - pass - return llvmlite.build_load(builder, load_ty_mod, mod_gv_ref) - - # 嵌套模块属性访问 (w32.win32file.GENERIC_READ → 查找全局 @GENERIC_READ) - # 当 at.value 是 Attribute 且解析为已导入子模块时,查找 at.attr 作为全局常量 - if at.value.kind() == ast.ASTKind.Attribute and trans is not None: - inner_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(at.value) - if inner_at.value is not None and inner_at.value.kind() == ast.ASTKind.Name: - inner_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner_at.value) - if inner_nm.id is not None and inner_at.attr is not None: - if HandlesVar.lookup_var(trans.SymTab, inner_nm.id) is None: - # 构建限定模块名: "w32.win32file" - qual_len: t.CSizeT = string.strlen(inner_nm.id) + string.strlen(inner_at.attr) + 2 - qual_buf: str = pool.alloc(qual_len) - if qual_buf is not None: - viperlib.snprintf(qual_buf, qual_len, "%s.%s", inner_nm.id, inner_at.attr) - if HandlesImports.is_module_imported(trans._imported_modules, qual_buf) == 1: - # 查找全局变量 at.attr (stub 已注入的情况) - gv_nested: llvmlite.GlobalVariable | t.CPtr = self.find_global_in_module(mod, at.attr) - if gv_nested is not None and gv_nested.Ty is not None: - gv_ref_nested: llvmlite.Value | t.CPtr = self.make_global_ref( - pool, at.attr, gv_nested.Ty) - if gv_ref_nested is not None and gv_ref_nested.Ty is not None: - load_ty_nested: llvmlite.LLVMType | t.CPtr = gv_ref_nested.Ty.Pointee - if load_ty_nested is not None: - return llvmlite.build_load(builder, load_ty_nested, gv_ref_nested) - # 未找到全局: 尝试 CDefine 常量查找 - # 对于 w32.win32base.INVALID_HANDLE_VALUE 等嵌套模块属性访问, - # 先从限定模块的 .vpi 文件中查找 CDefine 常量值并内联 - cdef_val_nested: t.CInt64T = HandlesType.lookup_cdefine_constant(at.attr) - if HandlesType.is_cdefine_found() == 0: - # 构建临时 from_imports "attr:module" 用于跨模块查找 - tmp_fi_len: t.CSizeT = string.strlen(at.attr) + string.strlen(qual_buf) + 2 - tmp_fi: str = pool.alloc(tmp_fi_len) - if tmp_fi is not None: - viperlib.snprintf(tmp_fi, tmp_fi_len, "%s:%s", at.attr, qual_buf) - cdef_val_nested = self._lookup_cross_module_cdefine(pool, at.attr, tmp_fi) - if HandlesType.is_cdefine_found() != 0: - # 跨模块浮点 CDefine → 浮点常量 - dchk_nst: double = HandlesType.lookup_cdefine_double(at.attr) - if HandlesType.is_cdefine_double() != 0: - return llvmlite.ConstFloat(pool, llvmlite.Double(pool), dchk_nst) - return self._const_int_for_cdefine(pool, cdef_val_nested) - # CDefine 未找到: fail-fast 终止编译(不再创建未定义的全局变量引用) - # 之前此处创建 @INVALID_HANDLE_VALUE 等前向引用,但全局未定义, - # 导致 llc 报 "use of undefined value" 错误。 - # 正确做法是报错终止,让开发者修复跨模块 CDefine 查找失败的根本原因。 - if self._is_cdefine_name_pattern(at.attr) != 0: - HandlesType.fatal_error( - at, - f"嵌套属性跨模块 CDefine 未找到: '{qual_buf}.{at.attr}'(CDefine cross-module lookup failed)", - "TypeError") - return None - - # 对于 Name 类型的 obj,直接查找 alloca(不 load 结构体); - # nonlocal 变量(提升函数内)从 env 读共享堆值,避免 lookup_var - # 跨函数引用外层 alloca(SSA 编号跨函数错乱崩溃) - obj_ptr: llvmlite.Value | t.CPtr = None - if at.value.kind() == ast.ASTKind.Name and trans is not None: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm.id is not None: - if HT.is_nonlocal_name(trans, nm.id) != 0: - raw_nl_a: llvmlite.Value | t.CPtr = HandlesNonlocal._load_raw_var_ptr( - trans, nm.id) - if raw_nl_a is not None: - nl_ty_a: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type( - trans, nm.id) - if nl_ty_a is not None: - # 对象即指针:Struct/Array 类型直接用堆地址(bitcast 后 - # 作为对象指针,不 load);指针类型(如 Ptr(Point))堆里 - # 存对象指针,需 load 出对象指针 - match nl_ty_a: - case llvmlite.LLVMType.Struct(_, _, _): - obj_ptr = llvmlite.build_bitcast( - builder, raw_nl_a, llvmlite.Ptr(pool, nl_ty_a)) - case llvmlite.LLVMType.Array(_, _): - obj_ptr = llvmlite.build_bitcast( - builder, raw_nl_a, llvmlite.Ptr(pool, nl_ty_a)) - case _: - nl_val_ptr_a: llvmlite.Value | t.CPtr = \ - llvmlite.build_bitcast( - builder, raw_nl_a, llvmlite.Ptr(pool, nl_ty_a)) - if nl_val_ptr_a is not None: - obj_ptr = llvmlite.build_load( - builder, nl_ty_a, nl_val_ptr_a) - else: - obj_ptr = HandlesVar.lookup_var(trans.SymTab, nm.id) - - # 非 Name 路径:翻译对象值(会 load) - if obj_ptr is None: - # c.Deref(ptr).attr: 属性访问 base 取指针本身而非 load 后的结构体值 - # (如 c.Deref(p).a 语义是 (*p).a,直接对 p 做 GEP) - cd_base_rd: llvmlite.Value | t.CPtr = self._get_cderef_attr_base( - builder, pool, mod, at.value, trans) - if cd_base_rd is not None: - obj_ptr = cd_base_rd - elif at.value.kind() == ast.ASTKind.Subscript: - # 下标基座属性访问(如 pts[0].x):list[T]/OOP __getitem__ 类走 - # translate_value(返回元素值/地址);普通结构体指针数组走 - # get_subscript_ptr(GEP 元素地址,避免结构体值 base=非指针 报错) - if self._sub_base_uses_getitem(pool, mod, trans, at.value) != 0: - obj_ptr = self.translate_value(builder, pool, mod, at.value, None, 0, trans) - else: - obj_ptr = self.get_subscript_ptr(builder, pool, mod, at.value, trans) - elif at.value.kind() == ast.ASTKind.Attribute: - # 嵌套属性基座(如 r.origin.x):取内层字段地址(get_attribute_ptr 递归, - # 地址语义),指针字段(X|t.CPtr)由 _deref_if_ptr_ptr load 解引用 - obj_ptr = self.get_attribute_ptr(builder, pool, mod, at.value, trans) - if obj_ptr is None: - obj_ptr = self.translate_value(builder, pool, mod, at.value, None, 0, trans) - else: - obj_ptr = self.translate_value(builder, pool, mod, at.value, None, 0, trans) - - if obj_ptr is None or obj_ptr.Ty is None: - return None - - # 如果 obj_ptr 是 Ptr(Ptr(Struct))(X|t.CPtr 变量的 alloca), - # load 解引用获取 Ptr(Struct) - obj_ptr = self._deref_if_ptr_ptr(builder, obj_ptr) - - # 查找结构体类型信息 - # obj_ptr 类型应该是 Ptr(Struct(...)) - match obj_ptr.Ty: - case llvmlite.LLVMType.Ptr(struct_ty): - # 确保跨模块结构体的完整定义在当前模块中可用(供 getelementptr 访问字段) - HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) - # 查找字段索引和类型 - field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( - struct_ty, at.attr) - # REnum 变体字段查找: lookup_field 失败时,尝试 REnum 别名 - # REnum 结构体字段名是 _p1/_p2/...,但源码用变体字段名访问(如 ty.Pointee) - if field_info is None: - renum_se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type( - struct_ty) - if renum_se is not None and renum_se.Name is not None: - is_rn: int = HandlesClassDef._is_renum_class_name(renum_se.Name) - if is_rn == 1: - alias_idx: int = HandlesClassDef._lookup_renum_field_alias( - renum_se.Name, at.attr) - if alias_idx >= 1: - alias_fe: HandlesStruct.FieldEntry | t.CPtr = \ - HandlesStruct._get_field_entry(renum_se, alias_idx) - if alias_fe is not None and alias_fe.Ty is not None: - alias_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, struct_ty, alias_fe.Ty, obj_ptr, alias_idx) - if alias_ptr is not None: - return llvmlite.build_load(builder, alias_fe.Ty, alias_ptr) - # property getter 回退: obj.attr 是 @property/@x.getter 方法时生成调用 - # (字段未找到时先尝试,避免报误导性的"字段未找到"错误) - if field_info is None and at.value is not None and trans is not None: - prop_cls_fb: str = HandlesStruct.get_class_name_by_type(pool, struct_ty) - prop_val: llvmlite.Value | t.CPtr = HandlesExprCall._try_property_getter_attr( - pool, builder, mod, at, obj_ptr, trans, prop_cls_fb) - if prop_val is not None: - return prop_val - # 按需过滤: struct_ty 为 i8(简化联合类型)时,通过 AnnotClassName 按类名查找 - # 传递 SHA1 以区分跨模块同名类 - # base 注解类名提取:Name → 变量注解类名;Attribute → 属性链递归字段注解类名 - if field_info is None: - base_class: str = None - if at.value.kind() == ast.ASTKind.Name and trans is not None: - nm_fb: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm_fb.id is not None: - var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm_fb.id) - if var_entry is not None: - base_class = var_entry.AnnotClassName - elif at.value.kind() == ast.ASTKind.Attribute: - base_class = self._resolve_attr_field_class(pool, trans, at.value) - if base_class is not None: - cur_sha1: str = trans.ModuleSha1 - field_info = HandlesStruct.lookup_field_by_class( - base_class, at.attr, cur_sha1) - # REnum 变体字段别名回退:base_class 是 REnum 类时,变体 - # 字段名(如 LLVMType.Pointee → _p2 槽位)不是普通字段, - # lookup_field_by_class 查不到(LLVMType"字段 Pointee 未找到" - # 根因;主路径 L4989-5004 的 REnum 别名查找因 struct_ty 简化 - # 为 i8、find_struct_by_type 失败被跳过) - if field_info is None \ - and HandlesClassDef._is_renum_class_name(base_class) != 0: - rn_alias: int = HandlesClassDef._lookup_renum_field_alias( - base_class, at.attr) - if rn_alias >= 1: - rn_se: HandlesStruct.StructEntry | t.CPtr = \ - HandlesStruct.find_struct(base_class) - if rn_se is not None: - rn_fe: HandlesStruct.FieldEntry | t.CPtr = \ - HandlesStruct._get_field_entry(rn_se, rn_alias) - if rn_fe is not None and rn_fe.Ty is not None: - field_info = rn_fe - # 按需过滤成功:bitcast obj_ptr 到 AnnotClassName 对应的结构体类型 - # 原始 struct_ty 可能是 i8(X|t.CPtr 简化为 Ptr(i8)), - # 需用实际结构体类型做 GEP,否则 GEP i8 失败 - if field_info is not None: - annot_se: HandlesStruct.StructEntry | t.CPtr = \ - HandlesStruct.find_struct(base_class) - if annot_se is not None and annot_se.Ty is not None: - annot_ptr_ty: llvmlite.LLVMType | t.CPtr = \ - llvmlite.Ptr(pool, annot_se.Ty) - casted_ptr: llvmlite.Value | t.CPtr = \ - llvmlite.build_bitcast(builder, obj_ptr, annot_ptr_ty) - if casted_ptr is not None: - obj_ptr = casted_ptr - struct_ty = annot_se.Ty - # 按需过滤更新 struct_ty 后,需重新确保 - # 注解类型结构体定义在当前模块可用 - # (原始 struct_ty 可能是 i8,ensure 无效) - HandlesStruct.ensure_struct_def_in_module( - pool, mod, annot_se.Ty) - if field_info is not None: - field_ty: llvmlite.LLVMType | t.CPtr = field_info.Ty - # 联合体:bitcast obj_ptr 到 field_ty* 后 load - if HandlesStruct.is_union_by_type(struct_ty) == 1: - field_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, field_ty) - casted: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, obj_ptr, field_ptr_ty) - if casted is not None: - return llvmlite.build_load(builder, field_ty, casted) - return None - # 普通结构体:GEP + load - field_idx: int = field_info.Index - field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, struct_ty, field_ty, obj_ptr, field_idx) - if field_ptr is not None: - # 数组类型字段不能 load 为 SSA value,直接返回字段指针 - # 用于后续下标访问: self.state[0] → GEP state 字段 → GEP 数组元素 - if self.is_array_type(field_ty) != 0: - return field_ptr - loaded_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, field_ty, field_ptr) - # 联合类型字段(如 Token | t.CPtr)被编译为 i8*, - # 若 AnnotClassName 指示了具体结构体类型,bitcast 为正确的结构体指针。 - # 注意:仅当字段类型本身是指针时才 bitcast(指针→指针); - # 内嵌结构体字段(field_ty=Struct)load 出的是结构体值, - # bitcast 值→指针是非法 IR(llc: invalid cast opcode)。 - if loaded_val is not None and field_info.AnnotClassName is not None \ - and self.is_ptr_type(field_ty) != 0: - annot_struct: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct( - field_info.AnnotClassName) - if annot_struct is not None and annot_struct.Ty is not None: - annot_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, annot_struct.Ty) - return llvmlite.build_bitcast(builder, loaded_val, annot_ptr_ty) - return loaded_val - # fast-fail: 字段未找到,立即终止编译(不再打印诊断后返回 None) - # Phase A 依赖未就绪(_deps_pending,父类/依赖类未注册致字段缺失): - # 跳过本属性访问交给下遍重译(对齐 get_attribute_ptr L5541-5547), - # 避免 fail-fast 中断多遍收敛;依赖就绪后仍缺失则走下方真实报错。 - if trans is not None and trans._deps_pending != 0: - return None - if trans is not None: - diag_annot: str = None - diag_var_nm: str = None - if at.value is not None and at.value.kind() == ast.ASTKind.Name: - dnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - diag_var_nm = dnm.id - if dnm.id is not None: - dve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, dnm.id) - if dve is not None: - diag_annot = dve.AnnotClassName - diag_var_txt: str = "?" - if diag_var_nm is not None: - diag_var_txt = diag_var_nm - diag_annot_txt: str = "None" - if diag_annot is not None: - diag_annot_txt = diag_annot - sha1_attr: str = "?" - if trans.ModuleSha1 is not None: - sha1_attr = trans.ModuleSha1 - HandlesType.fatal_error( - at, - f"属性访问失败: .{at.attr} (var={diag_var_txt} annot={diag_annot_txt} sha1={sha1_attr})", - "TypeError") - return None - case _: - # fast-fail: 对非指针类型做属性访问(如 i32.x), - # Python traceback 立即终止,不静默返回 None(否则下游 "store to None" 崩溃,丢失错误现场) - attr_nm_ap: str = "?" - if at is not None and at.attr is not None: - attr_nm_ap = at.attr - sha1_ap: str = "?" - if trans is not None and trans.ModuleSha1 is not None: - sha1_ap = trans.ModuleSha1 - ln_ap: int = 0 - if at is not None and at.lineno is not None: - ln_ap = at.lineno - HandlesType.fatal_error( - at, - f"属性访问失败: .{attr_nm_ap} (base=非指针类型,无法做属性访问 sha1={sha1_ap}:{ln_ap})", - "TypeError") - - # ============================================================ - # 获取下标表达式的元素指针(不加载值,用于赋值) - # ============================================================ - def get_subscript_ptr(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """获取下标表达式的元素指针(用于赋值 lhs)""" - if node is None or builder is None: - return None - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - if sub is None: - return None - - # 翻译索引 - idx_val: llvmlite.Value | t.CPtr = self.translate_value( - builder, pool, mod, sub.slice, None, 0, trans) - if idx_val is None: - return None - - # 如果 value 是 Name,尝试从 alloca 类型推断 - if sub.value is not None and sub.value.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) - if nm.id is not None and trans is not None: - # nonlocal 数组/指针:从 env 读共享堆地址(提升函数内不能 - # lookup_var 外层 alloca——SSA 编号跨函数错乱崩溃) - if HT.is_nonlocal_name(trans, nm.id) != 0: - return self._nonlocal_subscript_ptr( - builder, pool, trans, nm.id, idx_val) - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is not None and alloca.Ty is not None: - if self.is_ptr_type(alloca.Ty) != 0: - pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee - if pointee is not None: - # 用 match 检查 pointee 类型 - match pointee: - case llvmlite.LLVMType.Array(elem_ty, count): - # 数组遍历 - return llvmlite.build_gep_array( - builder, pointee, elem_ty, alloca, - self._zext_index_to_i32(builder, idx_val)) - case llvmlite.LLVMType.Ptr(inner_ty): - # inner_ty 是 Ptr 说明 alloca.Ty 是三重指针, - # 即 X|t.CPtr 当 X 本身是指针类型 (如 T=AST|t.CPtr, T|t.CPtr=AST**)。 - # 此时 [i]=val 应该是指针解引用赋值, 而非调用 __setitem__。 - if self.is_ptr_type(inner_ty) != 0: - ptr_val_gsp: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val_gsp is not None: - return llvmlite.build_gep( - builder, inner_ty, ptr_val_gsp, idx_val) - return None - # 自定义结构体 (如 HashTable|t.CPtr, JsonValue|t.CPtr): - # 仅当类定义了 __setitem__(当前模块定义或跨模块 stub declare 注入) - # 才返回 None 触发 __setitem__ 重载;否则普通结构体指针按下标 - # 做 GEP 数组访问(走下方指针遍历路径) - cls_nm_ptr_chk: str = self._get_custom_struct_cls_nm(pool, inner_ty) - if not (cls_nm_ptr_chk is None): - si_lookup_gsp: str = pool.alloc(128) - if si_lookup_gsp is not None: - viperlib.snprintf(si_lookup_gsp, 128, "%s.__setitem__", cls_nm_ptr_chk) - if HandlesExprCall.find_func_in_module(mod, si_lookup_gsp) is not None: - return None - # bytes|t.CPtr / str|t.CPtr: alloca 是 i8**, - # 直接 GEP 按 i8* 步长(8 字节),不 load - # 仅当 inner_ty 不是自定义结构体时才走指针遍历 - if trans is not None: - ve_pe: HandlesVar.VarEntry | t.CPtr = \ - HandlesVar.lookup_var_entry(trans.SymTab, nm.id) - if ve_pe is not None and ve_pe.IsPtrElement == 1: - # bytes|t.CPtr / str|t.CPtr / T|t.CPtr:变量存指针值, - # 下标语义 = [指针值 + i*8](8 字节指针元素)。必须先 load - # alloca 得指针值,再 GEP——否则 GEP base 用 alloca(&elem_ptr) - # 读到栈变量而非数据区,赋值写不进 list 数据 - # (data 全 0xbaadf00d,dump 虚调用读错 vtable 崩溃)。 - ptr_val_pe: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val_pe is not None: - match pointee: - case llvmlite.LLVMType.Int8(): - i8_ptr_pe: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - return llvmlite.build_gep( - builder, i8_ptr_pe, ptr_val_pe, idx_val) - case _: - pass - return llvmlite.build_gep( - builder, pointee, ptr_val_pe, idx_val) - return None - # 普通指针遍历: 先 load 指针值,再 GEP - ptr_val: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val is None: - return None - gep_r: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, inner_ty, ptr_val, idx_val) - return gep_r - case _: - # pointee 是普通标量类型 (如 i64, i32, i8): - # alloca 是 Ptr(标量), 直接 GEP 获取第 idx 个元素指针 - # 支持 arg_vals[i] = val 这类参数数组下标赋值 - # 联合类型变量(IsPtrElement=1,如 _list.vp 的 - # elem_ptr: T | t.CPtr 退化为 i8*):pointee=i8 但 - # 元素是 8 字节指针,须按 i8* 步长 GEP(防只写 1 字节截断) - if trans is not None: - ve_pe_cs: HandlesVar.VarEntry | t.CPtr = \ - HandlesVar.lookup_var_entry(trans.SymTab, nm.id) - if ve_pe_cs is not None and ve_pe_cs.IsPtrElement == 1: - # T|t.CPtr(退化为 i8*,如 _list.vp 的 elem_ptr)变量 - # 存数据区指针,元素为 8 字节指针:必须先 load alloca - # 得指针值,再按 i8* 步长 GEP——否则 GEP base 用 alloca - # (&elem_ptr)算到栈地址,赋值写不进 list 数据区 - # (append 只增 count、data 全 0xbaadf00d)。 - ptr_val_cs: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val_cs is not None: - match pointee: - case llvmlite.LLVMType.Int8(): - i8_ptr_cs: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - return llvmlite.build_gep( - builder, i8_ptr_cs, ptr_val_cs, idx_val) - case _: - pass - return llvmlite.build_gep( - builder, pointee, ptr_val_cs, idx_val) - return None - return llvmlite.build_gep(builder, pointee, alloca, idx_val) - - # 通用路径 - ptr_val: llvmlite.Value | t.CPtr = self.translate_value( - builder, pool, mod, sub.value, None, 0, trans) - if ptr_val is None or ptr_val.Ty is None: - return None - if self.is_ptr_type(ptr_val.Ty) != 0: - elem_ty2: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee - if elem_ty2 is not None: - # 数组类型: 双索引 GEP (getelementptr [N x ty], ptr, i32 0, i32 idx) - match elem_ty2: - case llvmlite.LLVMType.Array(arr_elem_ty, arr_count): - return llvmlite.build_gep_array( - builder, elem_ty2, arr_elem_ty, ptr_val, - self._zext_index_to_i32(builder, idx_val)) - case _: - pass - # 自定义结构体 (如 self._ht[key]): 仅当类定义了 __setitem__ - # 才返回 None 触发 HandlesAssign 的 __setitem__ 重载; - # 否则普通结构体指针按下标做 GEP 数组访问 - cls_nm_gen: str = self._get_custom_struct_cls_nm(pool, elem_ty2) - if not (cls_nm_gen is None): - si_lookup_gen: str = pool.alloc(128) - if si_lookup_gen is not None: - viperlib.snprintf(si_lookup_gen, 128, "%s.__setitem__", cls_nm_gen) - if find_func_in_module(mod, si_lookup_gen) is not None: - return None - # 指针类型: 单索引 GEP (getelementptr ty, ptr, idx) - return llvmlite.build_gep(builder, elem_ty2, ptr_val, idx_val) - return None - - # ============================================================ - # 获取属性访问的字段指针(不加载值,用于赋值) - # 对于 Name 类型的 obj,直接使用 alloca 指针(不 load 结构体) - # ============================================================ - def _resolve_attr_field_class(self, pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - attr_node: ast.AST | t.CPtr) -> str: - """解析属性链(a.b.c)中 c 字段的注解类名。 - - 联合类型字段(X | t.CPtr)被简化为 Ptr(i8),属性链写入时 - (如 lx.tokens_tail.next = tok)obj_ptr.Ty 是 Ptr(i8), - lookup_field(i8, ...) 必然失败。此函数沿属性链递归解析 - 最终字段的 AnnotClassName(如 tokens_tail → 'Token'), - 供按需过滤分支 bitcast 回真实结构体类型后 GEP。 - """ - if attr_node is None or trans is None: - return None - k: int = attr_node.kind() - if k != ast.ASTKind.Attribute: - return None - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(attr_node) - if at is None or at.attr is None or at.value is None: - return None - # 递归解析基座的注解类名(Name → 变量注解;Attribute → 字段注解) - parent_class: str = None - if at.value.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm.id is None: - return None - var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm.id) - if var_entry is None: - return None - parent_class = var_entry.AnnotClassName - elif at.value.kind() == ast.ASTKind.Attribute: - parent_class = self._resolve_attr_field_class(pool, trans, at.value) - else: - return None - if parent_class is None: - return None - # 在父类中查 at.attr 字段,返回其注解类名 - cur_sha1: str = None - if trans is not None: - cur_sha1 = trans.ModuleSha1 - fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field_by_class( - parent_class, at.attr, cur_sha1) - if fe is None: - return None - return HandlesStruct.get_field_annot_class_name(fe) - - def get_attribute_ptr(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """获取属性访问的字段指针(用于赋值 lhs)""" - if node is None or builder is None: - return None - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at is None or at.value is None or at.attr is None: - return None - - # 对于 Name 类型的 obj,直接查找 alloca(不 load 结构体); - # nonlocal 变量(提升函数内)从 env 读共享堆值,避免 lookup_var - # 跨函数引用外层 alloca(SSA 编号跨函数错乱崩溃) - obj_ptr: llvmlite.Value | t.CPtr = None - if at.value.kind() == ast.ASTKind.Name and trans is not None: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm.id is not None: - if HT.is_nonlocal_name(trans, nm.id) != 0: - raw_nl_a: llvmlite.Value | t.CPtr = HandlesNonlocal._load_raw_var_ptr( - trans, nm.id) - if raw_nl_a is not None: - nl_ty_a: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type( - trans, nm.id) - if nl_ty_a is not None: - # 对象即指针:Struct/Array 类型直接用堆地址(bitcast 后 - # 作为对象指针,不 load);指针类型(如 Ptr(Point))堆里 - # 存对象指针,需 load 出对象指针 - match nl_ty_a: - case llvmlite.LLVMType.Struct(_, _, _): - obj_ptr = llvmlite.build_bitcast( - builder, raw_nl_a, llvmlite.Ptr(pool, nl_ty_a)) - case llvmlite.LLVMType.Array(_, _): - obj_ptr = llvmlite.build_bitcast( - builder, raw_nl_a, llvmlite.Ptr(pool, nl_ty_a)) - case _: - nl_val_ptr_a: llvmlite.Value | t.CPtr = \ - llvmlite.build_bitcast( - builder, raw_nl_a, llvmlite.Ptr(pool, nl_ty_a)) - if nl_val_ptr_a is not None: - obj_ptr = llvmlite.build_load( - builder, nl_ty_a, nl_val_ptr_a) - else: - obj_ptr = HandlesVar.lookup_var(trans.SymTab, nm.id) - - # 模块属性访问 (写路径): sys._mbuddy = mb / os._win32._mbuddy = v - # → store 到模块全局变量。当 obj 是已导入模块名(Name 或嵌套 Attribute - # 模块路径)且不是普通变量时,查找/创建全局变量引用。 - if obj_ptr is None and trans is not None: - mod_path_c: str = self._attr_module_path_str(pool, at.value) - if mod_path_c is not None: - # CDefine 常量不可写: 报 FATAL 错误,不创建未定义全局 - # (仅单层 Name 模块可精确判 CDefine) - if at.value.kind() == ast.ASTKind.Name: - nm_wma: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm_wma.id is not None: - if self._is_cdefine_name_pattern(at.attr) != 0: - err_buf_wma: str = pool.alloc(256) - if err_buf_wma is not None: - viperlib.snprintf(err_buf_wma, 256, - "[CD] FATAL: Cannot assign to CDefine constant '%s.%s'\n", - nm_wma.id, at.attr) - VLogger.error(err_buf_wma, "CD") - return None - # 使用 i8* 作为类型提示 (模块级变量通常存储指针) - i8_ptr_w: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - wma_ref: llvmlite.Value | t.CPtr = self._resolve_module_attribute_global( - pool, mod, trans, at, i8_ptr_w) - if wma_ref is not None: - return wma_ref - - # 非 Name 路径:翻译对象值(会 load) - if obj_ptr is None: - # c.Deref(ptr).attr: 属性写入 base 取指针本身而非 load 后的结构体值 - # (如 c.Deref(p).a = val 语义是 (*p).a = val,直接对 p 做 GEP) - cd_base_wr: llvmlite.Value | t.CPtr = self._get_cderef_attr_base( - builder, pool, mod, at.value, trans) - if cd_base_wr is not None: - obj_ptr = cd_base_wr - elif at.value.kind() == ast.ASTKind.Subscript: - # 下标基座属性写入(如 pts[0].x = val):list[T]/OOP __getitem__ 类走 - # translate_value(返回元素值/地址);普通结构体指针数组走 - # get_subscript_ptr(GEP 元素地址,避免结构体值 base=非指针 报错) - if self._sub_base_uses_getitem(pool, mod, trans, at.value) != 0: - obj_ptr = self.translate_value(builder, pool, mod, at.value, None, 0, trans) - else: - obj_ptr = self.get_subscript_ptr(builder, pool, mod, at.value, trans) - elif at.value.kind() == ast.ASTKind.Attribute: - # 嵌套属性基座写入(如 r.origin.x = val):取内层字段地址 - # (get_attribute_ptr 递归,地址语义),指针字段由 _deref_if_ptr_ptr 解引用 - obj_ptr = self.get_attribute_ptr(builder, pool, mod, at.value, trans) - if obj_ptr is None: - obj_ptr = self.translate_value(builder, pool, mod, at.value, None, 0, trans) - else: - obj_ptr = self.translate_value(builder, pool, mod, at.value, None, 0, trans) - - if obj_ptr is None or obj_ptr.Ty is None: - return None - - # 如果 obj_ptr 是 Ptr(Ptr(Struct))(X|t.CPtr 变量的 alloca), - # load 解引用获取 Ptr(Struct) - obj_ptr = self._deref_if_ptr_ptr(builder, obj_ptr) - - match obj_ptr.Ty: - case llvmlite.LLVMType.Ptr(struct_ty): - # 确保跨模块结构体的完整定义在当前模块中可用(供 getelementptr 访问字段) - # 与 translate_attribute 一致,避免 opaque 类型导致 GEP 报错 - HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) - field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( - struct_ty, at.attr) - # 按需过滤: struct_ty 为 i8(简化联合类型)时,通过 AnnotClassName 按类名查找 - # 传递 SHA1 以区分跨模块同名类 - # base 注解类名提取:Name → 变量注解类名;Attribute → 属性链递归字段注解类名 - # (如 lx.tokens_tail.next = tok:lx 的注解 Lexer → tokens_tail 字段注解 Token) - if field_info is None: - base_class: str = None - if at.value.kind() == ast.ASTKind.Name and trans is not None: - nm_fb: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm_fb.id is not None: - var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm_fb.id) - if var_entry is not None: - base_class = var_entry.AnnotClassName - elif at.value.kind() == ast.ASTKind.Attribute: - base_class = self._resolve_attr_field_class(pool, trans, at.value) - if base_class is not None: - cur_sha1: str = None - if trans is not None: - cur_sha1 = trans.ModuleSha1 - field_info = HandlesStruct.lookup_field_by_class( - base_class, at.attr, cur_sha1) - # REnum 变体字段别名回退(同 translate_attribute L5046-5062): - # get_attribute_ptr 赋值路径的按需过滤同样需要——struct_ty 简化 - # i8 时主路径 REnum 别名查找被跳过(LLVMType.Pointee 报错根因) - if field_info is None \ - and HandlesClassDef._is_renum_class_name(base_class) != 0: - rn_alias_g: int = HandlesClassDef._lookup_renum_field_alias( - base_class, at.attr) - if rn_alias_g >= 1: - rn_se_g: HandlesStruct.StructEntry | t.CPtr = \ - HandlesStruct.find_struct(base_class) - if rn_se_g is not None: - rn_fe_g: HandlesStruct.FieldEntry | t.CPtr = \ - HandlesStruct._get_field_entry(rn_se_g, rn_alias_g) - if rn_fe_g is not None and rn_fe_g.Ty is not None: - field_info = rn_fe_g - # 按需过滤成功:bitcast obj_ptr 到 AnnotClassName 对应的结构体类型 - # 原始 struct_ty 可能是 i8(X|t.CPtr 简化为 Ptr(i8)), - # 需用实际结构体类型做 GEP,否则 GEP i8 失败 - if field_info is not None: - annot_se: HandlesStruct.StructEntry | t.CPtr = \ - HandlesStruct.find_struct(base_class) - if annot_se is not None and annot_se.Ty is not None: - annot_ptr_ty: llvmlite.LLVMType | t.CPtr = \ - llvmlite.Ptr(pool, annot_se.Ty) - casted_ptr: llvmlite.Value | t.CPtr = \ - llvmlite.build_bitcast(builder, obj_ptr, annot_ptr_ty) - if casted_ptr is not None: - obj_ptr = casted_ptr - struct_ty = annot_se.Ty - # 按需过滤更新 struct_ty 后,需重新确保 - # 注解类型结构体定义在当前模块可用 - HandlesStruct.ensure_struct_def_in_module( - pool, mod, annot_se.Ty) - if field_info is not None: - # 联合体:bitcast obj_ptr 到 field_ty*(字段指针用于 store) - if HandlesStruct.is_union_by_type(struct_ty) == 1: - field_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, field_info.Ty) - return llvmlite.build_bitcast(builder, obj_ptr, field_ptr_ty) - # 普通结构体:GEP 获取字段指针 - return llvmlite.build_gep_struct( - builder, struct_ty, field_info.Ty, obj_ptr, field_info.Index) - # fast-fail: 字段未找到,立即终止编译(不再打印诊断后返回 None) - # Phase A 依赖未就绪(_deps_pending,父类/依赖类未注册致字段缺失, - # 如 Generator.vp 先于 TypeGenMixin.vp 编译时 self.TraceFrames): - # 跳过本属性写入交给下遍重译(对齐 HandlesAssign L69-78), - # 避免 fail-fast 中断多遍收敛;依赖就绪后仍缺失则走下方真实报错。 - if trans is not None and trans._deps_pending != 0: - return None - if trans is not None: - diag_annot_g: str = None - diag_var_nm_g: str = None - if at.value is not None and at.value.kind() == ast.ASTKind.Name: - dnm_g: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - diag_var_nm_g = dnm_g.id - if dnm_g.id is not None: - dve_g: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, dnm_g.id) - if dve_g is not None: - diag_annot_g = dve_g.AnnotClassName - diag_var_txt_g: str = "?" - if diag_var_nm_g is not None: - diag_var_txt_g = diag_var_nm_g - diag_annot_txt_g: str = "None" - if diag_annot_g is not None: - diag_annot_txt_g = diag_annot_g - sha1_attr_g: str = "?" - if trans.ModuleSha1 is not None: - sha1_attr_g = trans.ModuleSha1 - HandlesType.fatal_error( - at, - f"属性写入失败: .{at.attr} (var={diag_var_txt_g} annot={diag_annot_txt_g} sha1={sha1_attr_g})", - "TypeError") - return None - case _: - # fast-fail: 对非指针类型做属性写入(如 i32.x = ...), - # Python traceback 立即终止,不静默返回 None(否则下游 "store to None" 崩溃) - attr_nm_gp: str = "?" - if at is not None and at.attr is not None: - attr_nm_gp = at.attr - sha1_gp: str = "?" - if trans is not None and trans.ModuleSha1 is not None: - sha1_gp = trans.ModuleSha1 - ln_gp: int = 0 - if at is not None and at.lineno is not None: - ln_gp = at.lineno - HandlesType.fatal_error( - at, - f"属性写入失败: .{attr_nm_gp} (base=非指针类型,无法做属性写入 sha1={sha1_gp}:{ln_gp})", - "TypeError") - - # ============================================================ - # P3 迁移方法(来自 HandlesExprOps.vp:运算符重载 + 二元运算) - # ============================================================ - - # ============================================================ - # infer_expr_class - 从表达式推断结构体类名(共享推断) - # - # 无注解赋值(HandlesAssign)与方法调用分派(CallGenMixin)共用: - # 联合类型 X|t.CPtr 简化为 Ptr(i8),不含类名,需按表达式结构推断: - # Call → 类实例化(func 为已注册结构体名);func 为 Attribute - # 时是方法调用,经 vpi 返回注解缓存解析返回类名 - # Name → 源变量的 AnnotClassName - # BinOp/UnaryOp → lhs 类名 + 存在对应 dunder 方法(返回同类对象) - # Attribute → 字段注解类名(_resolve_attr_field_class) - # 仅采用已注册结构体;无法精确推断返回 None(fail-fast 由调用方暴露)。 - # ============================================================ - def infer_expr_class(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr) -> str: - """从表达式推断结构体类名,无法推断返回 None""" - if node is None or trans is None: - return None - k: int = node.kind() - # Call: 类实例化 / 方法调用 - if k == ast.ASTKind.Call: - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) - if cl is None or cl.func is None: - return None - if cl.func.kind() == ast.ASTKind.Name: - cand: str = ((ast.Name | t.CPtr)(cl.func)).id - if cand is None: - return None - if HandlesStruct.find_struct(cand) is not None: - return cand - return None - if cl.func.kind() == ast.ASTKind.Attribute: - # 方法调用 a.cross(b):vpi 返回注解缓存精确解析返回类名 - # (方法可返回非同类对象,如 Transform.world_position → 'Vec3')。 - ca: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if ca is None or ca.attr is None or ca.value is None: - return None - obj_cls: str = self.infer_expr_class(pool, mod, ca.value, trans) - if obj_cls is None: - return None - if self._cls_has_dunder(pool, mod, obj_cls, ca.attr) == 0: - return None - cls_sha1: str = HandlesStruct.get_struct_sha1(obj_cls) - if cls_sha1 is None and trans.ModuleSha1 is not None: - cls_sha1 = trans.ModuleSha1 - ret_cls: str = None - if cls_sha1 is not None: - import lib.StubGen.VpiReader as VpiReader - temp_dir: str = None - # 跨 Mixin 不能 self 访问 Generator 的 TempDir 字段(字段按 - # 声明类隔离),经全局单例获取(同 HandlesAssign 模式) - import lib.core.Gen.Generator as Generator - g2: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( - t.CVoid(HandlesExpr._g_gen, t.CPtr)) - if g2 is not None and g2.TempDir is not None: - temp_dir = g2.TempDir - if temp_dir is not None: - VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, temp_dir) - annot_ret: str = VpiReader._lookup_vpi_ret_annot( - cls_sha1, obj_cls, ca.attr) - if annot_ret is not None: - ret_cls = self._extract_annot_class_name(pool, annot_ret) - return ret_cls - return None - # Name: 源变量注解 - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm is None or nm.id is None: - return None - ve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm.id) - if ve is None: - return None - acn_n: str = ve.AnnotClassName - if acn_n is None: - return None - # 去模块前缀:json.JsonValue → JsonValue。AnnotClassName 可能带 - # 模块限定(extract_class_name_from_annotation 的 Attribute 分支返回 - # "memhub.MemBuddy" 形式),而 find_struct/_cls_has_dunder/ - # get_struct_sha1 查找都用裸类名(struct 注册名)。泛型名 - # (list[str] 含 '[')不截断(方括号内可能有点号)。 - acn_dot_n: str = string.strrchr(acn_n, 46) - if acn_dot_n is not None and string.strchr(acn_n, 91) is None: - acn_n = acn_dot_n + 1 - return acn_n - # BinOp/UnaryOp: 运算符重载返回同类对象 - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - if bop is None or bop.left is None: - return None - dunder: str = self._binop_to_dunder(bop.op) - if dunder is None: - return None - lhs_cls: str = self.infer_expr_class(pool, mod, bop.left, trans) - if lhs_cls is None or self._cls_has_dunder(pool, mod, lhs_cls, dunder) == 0: - return None - return lhs_cls - if k == ast.ASTKind.UnaryOp: - uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) - if uop is None or uop.operand is None: - return None - dunder: str = self._unaryop_to_dunder(uop.op) - if dunder is None: - return None - opr_cls: str = self.infer_expr_class(pool, mod, uop.operand, trans) - if opr_cls is None or self._cls_has_dunder(pool, mod, opr_cls, dunder) == 0: - return None - return opr_cls - # Attribute: 字段注解类名(属性链递归,如 p = r.origin) - if k == ast.ASTKind.Attribute: - return self._resolve_attr_field_class(pool, trans, node) - return None - - # ============================================================ - # _cls_has_dunder - 检查类(含继承链)是否存在 dunder/方法 - # - # 与 try_operator_overload 的查找一致:当前模块内定义或跨模块类有 - # SHA1(stub 中声明)即视为存在。仅在确实存在时采用推断类名, - # 避免把原生运算误标为类类型。 - # ============================================================ - def _cls_has_dunder(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, dunder: str) -> int: - """类及其 MRO 祖先链中是否存在 dunder 方法,存在返回 1""" - if class_name is None or dunder is None or mod is None: - return 0 - lookup_name: str = pool.alloc(128) - if lookup_name is None: - return 0 - viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder) - if HandlesExprCall.find_func_in_module(mod, lookup_name) is not None: - return 1 - # 继承链祖先查找 - mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name) - mi: int = 1 - while mro_ptr is not None and mro_ptr[mi] != 0: - anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr)) - if anc is not None: - anc_lookup: str = pool.alloc(128) - if anc_lookup is not None: - viperlib.snprintf(anc_lookup, 128, "%s.%s", anc, dunder) - if HandlesExprCall.find_func_in_module(mod, anc_lookup) is not None: - return 1 - mi += 1 - # 跨模块:类有 SHA1(stub 中声明该方法)视为存在 - if HandlesStruct.get_struct_sha1(class_name) is not None: - return 1 - return 0 - - # ============================================================ - # _extract_annot_class_name - 从返回注解文本提取结构体类名 - # - # vpi 返回注解文本(如 "'Vec3' | CPtr")按 '|' 分段,每段去除 - # 空格/引号后查结构体注册表:命中即类名(内置类型 str/int/ - # CFloat64T/t.CPtr 等均不注册 struct,天然过滤)。"A | B" 联合 - # 多候选时取首个命中段。 - # ============================================================ - def _extract_annot_class_name(self, pool: memhub.MemBuddy | t.CPtr, - annot: str) -> str: - """从返回注解文本提取已注册结构体类名,无命中返回 None""" - if pool is None or annot is None: - return None - alen: t.CSizeT = string.strlen(annot) - if alen == 0: - return None - seg: str = pool.alloc(256) - if seg is None: - return None - start: t.CSizeT = 0 - i: t.CSizeT - for i in range(alen): - if annot[i] == '|': - s: t.CSizeT = start - e: t.CSizeT = i - while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'): - s += 1 - while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'): - e -= 1 - seglen: t.CSizeT = e - s - if seglen > 0 and seglen < 256: - string.strncpy(seg, annot + s, seglen) - seg[seglen] = '\0' - if HandlesStruct.find_struct(seg) is not None: - return seg - start = i + 1 - # 最后一段(无 '|' 后缀) - s: t.CSizeT = start - e: t.CSizeT = alen - while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'): - s += 1 - while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'): - e -= 1 - seglen: t.CSizeT = e - s - if seglen > 0 and seglen < 256: - string.strncpy(seg, annot + s, seglen) - seg[seglen] = '\0' - if HandlesStruct.find_struct(seg) is not None: - return seg - return None - - # ============================================================ - # BinOp 运算符 → dunder 方法名 - # ============================================================ - def _binop_to_dunder(self, op: int) -> str: - """将 BinOp 运算符映射到 dunder 方法名,无映射时返回 None - - Python 3 语义:/ 映射 __truediv__(Python 2 的 __div__ 已废弃)。 - """ - if op == ast.OpKind.Add: return "__add__" - if op == ast.OpKind.Sub: return "__sub__" - if op == ast.OpKind.Mult: return "__mul__" - if op == ast.OpKind.Div: return "__truediv__" - if op == ast.OpKind.Mod: return "__mod__" - if op == ast.OpKind.BitAnd: return "__and__" - if op == ast.OpKind.BitOr: return "__or__" - if op == ast.OpKind.BitXor: return "__xor__" - if op == ast.OpKind.LShift: return "__lshift__" - if op == ast.OpKind.RShift: return "__rshift__" - if op == ast.OpKind.FloorDiv: return "__floordiv__" - return None - - # ============================================================ - # Compare 运算符 → dunder 方法名 - # ============================================================ - def _cmpop_to_dunder(self, op: int) -> str: - """将 Compare 运算符映射到 dunder 方法名,无映射时返回 None""" - if op == ast.OpKind.Eq: return "__eq__" - if op == ast.OpKind.Ne: return "__ne__" - if op == ast.OpKind.Lt: return "__lt__" - if op == ast.OpKind.Le: return "__le__" - if op == ast.OpKind.Gt: return "__gt__" - if op == ast.OpKind.Ge: return "__ge__" - return None - - # ============================================================ - # UnaryOp 运算符 → dunder 方法名 - # ============================================================ - def _unaryop_to_dunder(self, op: int) -> str: - """将 UnaryOp 运算符映射到 dunder 方法名,无映射时返回 None""" - if op == ast.OpKind.USub: return "__neg__" - if op == ast.OpKind.UAdd: return "__pos__" - if op == ast.OpKind.Invert: return "__invert__" - return None - - # ============================================================ - # try_operator_overload - 尝试运算符重载 - # - # 检查 lhs 是否为结构体指针,并在该类(含继承链)中查找对应的 - # dunder 方法。找到则生成方法调用 lhs.__dunder__(rhs),返回 - # 调用结果;未找到返回 None,调用方回退到原生运算。 - # ============================================================ - def try_operator_overload(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - lhs: llvmlite.Value | t.CPtr, - rhs: llvmlite.Value | t.CPtr, - op: int, - trans: HT.Translator | t.CPtr, - is_compare: int) -> llvmlite.Value | t.CPtr: - """尝试运算符重载:lhs 是结构体指针时调用 dunder 方法,否则返回 None""" - if lhs is None or rhs is None: - return None - - # 延迟导入避免循环依赖 - import lib.core.Handles.HandlesStruct as HandlesStruct - import lib.core.Handles.HandlesExprCall as HandlesExprCall - - # 映射运算符到 dunder 方法名 - dunder: str = None - if is_compare != 0: - dunder = self._cmpop_to_dunder(op) - else: - dunder = self._binop_to_dunder(op) - if dunder is None: - return None - - # 检查 lhs 是否为结构体指针 - struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(lhs) - if struct_ty is None: - return None - - # 获取类名 - class_name: str = HandlesStruct.get_class_name_by_type(pool, struct_ty) - if class_name is None: - return None - - # 在继承链中查找 dunder 方法 - lookup_name: str = pool.alloc(128) - if lookup_name is None: - return None - viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder) - found_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, lookup_name) - - search_class: str = class_name - if found_func is None: - # 多继承:沿 MRO 祖先链查找(先声明父类优先) - mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name) - mi: int = 1 - while mro_ptr is not None and mro_ptr[mi] != 0: - anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr)) - if anc is not None: - parent_lookup: str = pool.alloc(128) - if parent_lookup is not None: - viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, dunder) - parent_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, parent_lookup) - if parent_func is not None: - found_func = parent_func - search_class = anc - break - mi += 1 - - # 方法不在当前模块中时,检查类(含父类)是否有 SHA1(stub 可能未注入) - # 优先用类型指针定位 entry 获取 SHA1(规避跨模块同名 find_struct 找错) - cls_sha1: str = None - op_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) - if op_entry is not None: - cls_sha1 = op_entry.ModuleSha1 - if cls_sha1 is None: - cls_sha1 = HandlesStruct.get_struct_sha1(search_class) - if cls_sha1 is None: - mro_p: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, search_class) - mj: int = 1 - while mro_p is not None and mro_p[mj] != 0 and cls_sha1 is None: - anc_p: str = (str | t.CPtr)(t.CVoid(mro_p[mj], t.CPtr)) - if anc_p is not None: - cls_sha1 = HandlesStruct.get_struct_sha1(anc_p) - mj += 1 - - # 既无函数定义也无 SHA1 → 该类没有此 dunder 方法,返回 None 回退原生运算 - if found_func is None and cls_sha1 is None: - return None - - # 方法在"定义它的模块"中确实不存在(同模块类但模块内无此 dunder): - # 返回 None 回退原生运算,绝不发出幽灵 call——否则 IR 残留 - # `call void @...__div__`(副作用)且调用方回退原生 sdiv 双重发射, - # llc 报 invalid operand type for instruction(CPythonTest PyFloatObj 根因) - if found_func is None and trans is not None and trans.ModuleSha1 is not None: - if cls_sha1 is not None and string.strcmp(cls_sha1, trans.ModuleSha1) == 0: - return None - # 跨模块类:stub 可能未注入,方法存在性以依赖模块 vpi stub 为准。 - # vpi 未命中(依赖模块确实无此 dunder)→ 回退原生比较(icmp), - # 绝不发幽灵 call——`call @{cls_sha1}.{Class}.{dunder}` 链接 undefined - # (MemBuddy 无 __eq__ 时 os._mbuddy == sys._mbuddy,SysLibTest 根因)。 - vpi_dup: llvmlite.LLVMType | t.CPtr = HandlesExprCall._lookup_method_ret_ty_via_vpi( - pool, cls_sha1, search_class, dunder) - if vpi_dup is None: - return None - - # 构建 extra_args 数组(仅含 rhs 一个参数) - extra_args: t.CSizeT | t.CPtr = pool.alloc(8) - if extra_args is None: - return None - extra_args[0] = t.CSizeT(rhs) - - # 调用方法: lhs.__dunder__(rhs) - return HandlesExprCall._call_method_on_ptr( - pool, builder, mod, search_class, dunder, - lhs, extra_args, 1, trans) - - # ============================================================ - # try_unary_operator_overload - 尝试一元运算符重载 - # - # 检查 operand 是否为结构体指针,并在该类(含继承链)中查找对应的 - # dunder 方法(__neg__/__pos__/__invert__)。找到则生成方法调用 - # operand.__dunder__(),返回调用结果;未找到返回 None,调用方回退到原生运算。 - # ============================================================ - def try_unary_operator_overload(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - operand: llvmlite.Value | t.CPtr, - op: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """尝试一元运算符重载:operand 是结构体指针时调用 dunder 方法,否则返回 None""" - if operand is None: - return None - - # 延迟导入避免循环依赖 - import lib.core.Handles.HandlesStruct as HandlesStruct - import lib.core.Handles.HandlesExprCall as HandlesExprCall - - dunder: str = self._unaryop_to_dunder(op) - if dunder is None: - return None - - # 检查 operand 是否为结构体指针 - struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(operand) - if struct_ty is None: - return None - - # 获取类名 - class_name: str = HandlesStruct.get_class_name_by_type(pool, struct_ty) - if class_name is None: - return None - - # 在继承链中查找 dunder 方法 - lookup_name: str = pool.alloc(128) - if lookup_name is None: - return None - viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder) - found_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, lookup_name) - - search_class: str = class_name - if found_func is None: - # 多继承:沿 MRO 祖先链查找(先声明父类优先) - mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name) - mi: int = 1 - while mro_ptr is not None and mro_ptr[mi] != 0: - anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr)) - if anc is not None: - parent_lookup: str = pool.alloc(128) - if parent_lookup is not None: - viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, dunder) - parent_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, parent_lookup) - if parent_func is not None: - found_func = parent_func - search_class = anc - break - mi += 1 - - # 方法不在当前模块中时,检查类(含父类)是否有 SHA1(stub 可能未注入) - cls_sha1: str = None - uop_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) - if uop_entry is not None: - cls_sha1 = uop_entry.ModuleSha1 - if cls_sha1 is None: - cls_sha1 = HandlesStruct.get_struct_sha1(search_class) - if cls_sha1 is None: - mro_p: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, search_class) - mj: int = 1 - while mro_p is not None and mro_p[mj] != 0 and cls_sha1 is None: - anc_p: str = (str | t.CPtr)(t.CVoid(mro_p[mj], t.CPtr)) - if anc_p is not None: - cls_sha1 = HandlesStruct.get_struct_sha1(anc_p) - mj += 1 - - # 既无函数定义也无 SHA1 → 该类没有此 dunder 方法,返回 None 回退原生运算 - if found_func is None and cls_sha1 is None: - return None - - # 同模块类但模块内无此 dunder → 返回 None 回退原生运算,不发幽灵 call - # (与 try_operator_overload 一致,防 IR 残留 call void @...__neg__) - if found_func is None and trans is not None and trans.ModuleSha1 is not None: - if cls_sha1 is not None and string.strcmp(cls_sha1, trans.ModuleSha1) == 0: - return None - - # 一元方法无额外参数(extra_args 为空) - return HandlesExprCall._call_method_on_ptr( - pool, builder, mod, search_class, dunder, - operand, None, 0, trans) - - # ============================================================ - # 翻译二元运算(自动类型提升) - # ============================================================ - def translate_binop(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译二元运算(自动类型提升)""" - binop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - if binop is None: - return None - - lhs_node: ast.AST | t.CPtr = binop.left - rhs_node: ast.AST | t.CPtr = binop.right - op: int = binop.op - - # 先翻译 rhs(只翻译一次,避免副作用重复) - rhs: llvmlite.Value | t.CPtr = self.translate_value( - builder, pool, mod, rhs_node, None, 0, trans) - if rhs is None: - return None - - # === 运算符重载路径 1: lhs 是 Name 且对应结构体变量 === - # 对于值类型变量(如 cnt: Counter),translate_value 会 load 返回 Struct 值, - # 但 dunder 方法需要 Ptr(Struct) 作为 self。直接用 alloca 指针尝试重载。 - if lhs_node is not None and lhs_node.kind() == ast.ASTKind.Name and trans is not None: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(lhs_node) - if nm is not None and nm.id is not None: - lhs_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, nm.id) - if lhs_alloca is not None: - ovl_self1: llvmlite.Value | t.CPtr = lhs_alloca - # alloca 是 Ptr(Ptr(Struct))(X|t.CPtr 对象存储槽)时, - # load 出对象指针作为 self——若把槽地址当 self,dunder 内 - # load 槽内容(对象指针值)当字段读 → 垃圾(MultiInheritTest - # Vec2Both __add__ 输出 (1.0,2.0) 根因;get_struct_type_from_value - # 递归解指针后路径 1 能识别 alloca,需同步修正 self 语义) - if lhs_alloca.Ty is not None and lhs_alloca.Ty.Pointee is not None \ - and HandlesExpr.is_ptr_type(lhs_alloca.Ty.Pointee) != 0: - load_self1: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, lhs_alloca.Ty.Pointee, lhs_alloca) - if load_self1 is not None: - ovl_self1 = load_self1 - ovl_result: llvmlite.Value | t.CPtr = self.try_operator_overload( - pool, builder, mod, ovl_self1, rhs, op, trans, 0) - if ovl_result is not None: - return ovl_result - - # 正常翻译 lhs - lhs: llvmlite.Value | t.CPtr = self.translate_value( - builder, pool, mod, lhs_node, None, 0, trans) - if lhs is None: - return None - - # === 运算符重载路径 2: lhs 是 Ptr(Struct)(如 Counter|t.CPtr 变量 load 后)=== - ovl_result2: llvmlite.Value | t.CPtr = self.try_operator_overload( - pool, builder, mod, lhs, rhs, op, trans, 0) - if ovl_result2 is not None: - return ovl_result2 - - # 获取操作数类型信息 - lhs_bits: int = self.get_llvm_type_bits(lhs.Ty) - rhs_bits: int = self.get_llvm_type_bits(rhs.Ty) - lhs_fbits: int = self.get_llvm_float_bits(lhs.Ty) - rhs_fbits: int = self.get_llvm_float_bits(rhs.Ty) - - # 浮点运算: 任一操作数为浮点时,使用浮点指令(必须在指针算术之前检查, - # 因为 float 的 int bits 为 0,会被误认为指针) - if lhs_fbits != 0 or rhs_fbits != 0: - # 确定目标浮点类型(使用较大的位宽) - target_fbits: int = lhs_fbits - if rhs_fbits > target_fbits: - target_fbits = rhs_fbits - target_float_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) - if target_fbits == 32: - target_float_ty = llvmlite.Float(pool) - # 将两个操作数转换为目标浮点类型(int→float via si2fp, float→float via fpext/fptrunc) - lhs = self.coerce_to_type(builder, lhs, target_float_ty, node) - rhs = self.coerce_to_type(builder, rhs, target_float_ty, node) - if op == ast.OpKind.Add: - return llvmlite.build_fadd(builder, lhs, rhs) - if op == ast.OpKind.Sub: - return llvmlite.build_fsub(builder, lhs, rhs) - if op == ast.OpKind.Mult: - return llvmlite.build_fmul(builder, lhs, rhs) - if op == ast.OpKind.Div: - return llvmlite.build_fdiv(builder, lhs, rhs) - if op == ast.OpKind.Mod: - return llvmlite.build_frem(builder, lhs, rhs) - return None - - # 指针算术: ptr + int / ptr - int / int + ptr → getelementptr(按元素大小缩放) - # 对齐 TPC ExprGen.emit_binary_op L50-67;int - ptr 无 GEP 形式(C 语义非法) - if (lhs_bits == 0 and rhs_bits != 0) or (lhs_bits != 0 and rhs_bits == 0): - if op == ast.OpKind.Add: - if lhs_bits == 0: - return self.translate_ptr_arith(pool, builder, lhs, rhs, op) - # int + ptr(交换) - return self.translate_ptr_arith(pool, builder, rhs, lhs, op) - if op == ast.OpKind.Sub and lhs_bits == 0: - return self.translate_ptr_arith(pool, builder, lhs, rhs, op) - - if lhs_bits > rhs_bits: - if self.should_zext_widen(pool, rhs, lhs, rhs_node) != 0: - rhs = llvmlite.build_zext(builder, rhs, lhs.Ty) - else: - rhs = self.coerce_to_type(builder, rhs, lhs.Ty, node) - elif rhs_bits > lhs_bits: - if self.should_zext_widen(pool, lhs, rhs, lhs_node) != 0: - lhs = llvmlite.build_zext(builder, lhs, rhs.Ty) - else: - lhs = self.coerce_to_type(builder, lhs, rhs.Ty, node) - - # 位运算类型安全检查:两边都是指针(lhs_bits==0 and rhs_bits==0)时, - # 位运算(BitOr/BitAnd/BitXor/LShift/RShift)非法,LLVM 要求整数操作数。 - # 常见触发场景:CDefine 常量查找失败返回指针 null,与另一指针做 `|`。 - if lhs_bits == 0 and rhs_bits == 0: - if op == ast.OpKind.BitOr or op == ast.OpKind.BitAnd or op == ast.OpKind.BitXor or op == ast.OpKind.LShift or op == ast.OpKind.RShift: - # fail-fast:位运算操作数类型非法,立即终止编译(暴露上游根因) - HandlesType.fatal_error( - node, - "位运算操作数类型非法: lhs/rhs 均为非整数类型(指针或结构体),无法执行位运算", - "TypeError") - - if op == ast.OpKind.Add: - return llvmlite.build_add(builder, lhs, rhs) - elif op == ast.OpKind.Sub: - return llvmlite.build_sub(builder, lhs, rhs) - elif op == ast.OpKind.Mult: - return llvmlite.build_mul(builder, lhs, rhs) - elif op == ast.OpKind.Div: - return llvmlite.build_sdiv(builder, lhs, rhs) - elif op == ast.OpKind.FloorDiv: - return llvmlite.build_sdiv(builder, lhs, rhs) - elif op == ast.OpKind.Mod: - return llvmlite.build_srem(builder, lhs, rhs) - elif op == ast.OpKind.BitAnd: - return llvmlite.build_and(builder, lhs, rhs) - elif op == ast.OpKind.BitOr: - return llvmlite.build_or(builder, lhs, rhs) - elif op == ast.OpKind.BitXor: - return llvmlite.build_xor(builder, lhs, rhs) - elif op == ast.OpKind.LShift: - return llvmlite.build_shl(builder, lhs, rhs) - elif op == ast.OpKind.RShift: - # 无符号 >> → lshr(逻辑右移),有符号 >> → ashr(算术右移) - # 对齐 TPC ExprGen.emit_binary_op:i8/i16 默认无符号;其余查操作数无符号性 - if lhs_bits == 8 or lhs_bits == 16: - return llvmlite.build_lshr(builder, lhs, rhs) - if self._node_type_unsigned(pool, lhs_node, trans) != 0: - return llvmlite.build_lshr(builder, lhs, rhs) - return llvmlite.build_ashr(builder, lhs, rhs) - return None