From 24ae2dc966e9e4ae5ba8f49b837b13b36c51738c Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Fri, 28 Aug 2026 14:29:25 +0800 Subject: [PATCH] =?UTF-8?q?refactor(tpv):=20=E5=88=A0=E9=99=A4=20Handles?= =?UTF-8?q?=20=E7=9B=AE=E5=BD=95=EF=BC=8C=E6=A0=B8=E5=BF=83=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E5=90=88=E5=B9=B6=E8=BF=9B=20Gen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新建 Gen/Translator.vp:Translator 类 + Mixin + 常量 + _mbuddy 自 HandlesTranslator 迁入(删 7 个委托壳与 _g_gen) - GenApi 下沉 7 个 global/nonlocal 管理委托(add/is_global_name、add/is_nonlocal_name、get_nonlocal_type/index、clear_scope_names)+ update_global_func_typestr - CallGenLeafKit 并入 ExprCallHandle 类,NewExprCallHandle 改本地引用 - 删除 Handles/HandlesExpr/ExprCallTable/HandlesBase(60+ 委托零消费者/纯委托壳)与 Handles 目录整体 - 全 App 56 文件 import 改指 lib.core.Gen.*,清理死 import,委托调用改 GenApi,main/BuildPipeline _g_gen 注入删除 --- App/lib/Phase/BuildPipeline.vp | 7 +- App/lib/Phase/Phase1/Phase1Main.vp | 3 +- App/lib/Phase/Phase1/Phase1Scan.vp | 3 +- App/lib/Phase/Phase1/Phase1Topo.vp | 3 +- App/lib/Phase/Phase2/__init__.vp | 3 +- App/lib/Stub/StubGen/VpiReader.vp | 8 +- App/lib/Stub/StubMerger/StubMergerBuild.vp | 2 +- App/lib/Stub/StubMerger/StubMergerCollect.vp | 2 +- App/lib/Stub/StubMerger/StubMergerIR.vp | 2 +- App/lib/Stub/StubMerger/StubMergerStore.vp | 2 +- App/lib/Stub/StubMerger/StubMergerTopo.vp | 2 +- App/lib/Stub/StubMerger/__init__.vp | 2 +- App/lib/core/Gen/AssignGenMixin.vp | 20 +- App/lib/core/Gen/AsyncGenMixin.vp | 5694 ++++++++--------- App/lib/core/Gen/BaseGenMixin.vp | 1 - App/lib/core/Gen/Call/CallGenBase.vp | 5 +- App/lib/core/Gen/Call/CallGenCBuiltin.vp | 12 +- App/lib/core/Gen/Call/CallGenCall.vp | 10 +- App/lib/core/Gen/Call/CallGenCtor.vp | 6 +- App/lib/core/Gen/Call/CallGenDispatch.vp | 3400 +++++----- App/lib/core/Gen/Call/CallGenFd.vp | 5 +- App/lib/core/Gen/Call/CallGenLeafKit.vp | 54 +- App/lib/core/Gen/Call/CallGenLib.vp | 5 +- App/lib/core/Gen/Call/CallGenMixin.vp | 2715 ++++---- App/lib/core/Gen/Call/CallGenProp.vp | 5 +- App/lib/core/Gen/Call/CallGenVa.vp | 5 +- App/lib/core/Gen/Call/CallGenVt.vp | 5 +- App/lib/core/Gen/Class/ClassGenBase.vp | 2 +- App/lib/core/Gen/Class/ClassGenDef.vp | 2 +- App/lib/core/Gen/Class/ClassGenEnum.vp | 2 +- App/lib/core/Gen/Class/ClassGenGeneric.vp | 2 +- App/lib/core/Gen/Class/ClassGenMixin.vp | 2 +- App/lib/core/Gen/Class/ClassGenVTable.vp | 2608 ++++---- App/lib/core/Gen/Expr/ExprGenAttr.vp | 14 +- App/lib/core/Gen/Expr/ExprGenBase.vp | 5 +- App/lib/core/Gen/Expr/ExprGenCdef.vp | 5 +- App/lib/core/Gen/Expr/ExprGenCls.vp | 5 +- App/lib/core/Gen/Expr/ExprGenConst.vp | 5 +- App/lib/core/Gen/Expr/ExprGenFstr.vp | 5 +- App/lib/core/Gen/Expr/ExprGenMixin.vp | 5 +- App/lib/core/Gen/Expr/ExprGenName.vp | 16 +- App/lib/core/Gen/Expr/ExprGenOps.vp | 5 +- App/lib/core/Gen/Func/FuncGenBase.vp | 4 +- App/lib/core/Gen/Func/FuncGenDef.vp | 8 +- App/lib/core/Gen/Func/FuncGenMixin.vp | 3127 +++++---- App/lib/core/Gen/GenApi.vp | 83 +- App/lib/core/Gen/ImportsGenMixin.vp | 2 +- App/lib/core/Gen/MatchGenMixin.vp | 2678 ++++---- App/lib/core/Gen/Stmt/StmtGenCifMixin.vp | 4 +- App/lib/core/Gen/Stmt/StmtGenDeclMixin.vp | 15 +- App/lib/core/Gen/Stmt/StmtGenMixin.vp | 4 +- .../Translator.vp} | 1477 +++-- App/lib/core/Gen/TranslatorGenMixin.vp | 2 +- App/lib/core/Gen/Type/TypeGenCDef.vp | 5 +- App/lib/core/Gen/Type/TypeGenCType.vp | 7 +- App/lib/core/Gen/Type/TypeGenErr.vp | 790 +-- App/lib/core/Gen/Type/TypeGenMixin.vp | 2 +- App/lib/core/Gen/Type/TypeGenResolve.vp | 5 +- App/lib/core/Handles/ExprCallTable.vp | 197 - App/lib/core/Handles/HandlesBase.vp | 262 - App/lib/core/Handles/HandlesExpr.vp | 953 --- App/lib/core/Handles/HandlesExprCall.vp | 137 - App/lib/core/Handles/__init__.vp | 9 - App/main.vp | 7 +- 64 files changed, 11434 insertions(+), 13008 deletions(-) rename App/lib/core/{Handles/HandlesTranslator.vp => Gen/Translator.vp} (91%) delete mode 100644 App/lib/core/Handles/ExprCallTable.vp delete mode 100644 App/lib/core/Handles/HandlesBase.vp delete mode 100644 App/lib/core/Handles/HandlesExpr.vp delete mode 100644 App/lib/core/Handles/HandlesExprCall.vp delete mode 100644 App/lib/core/Handles/__init__.vp diff --git a/App/lib/Phase/BuildPipeline.vp b/App/lib/Phase/BuildPipeline.vp index f7c2e1c..3e83565 100644 --- a/App/lib/Phase/BuildPipeline.vp +++ b/App/lib/Phase/BuildPipeline.vp @@ -16,9 +16,7 @@ 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.Gen.Translator as HandlesTranslator import lib.Stub.StubMerger as StubMerger import lib.Stub.StubGen.Converter as StubConverter import lib.Projectrans.Config as Config @@ -154,9 +152,6 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str, # P2-P5: 注入各 Handles 模块级单例(委托函数经本地 _g_gen 访问, # 避免函数体 import 包模块与类/模块名歧义) GenApi._g_gen = gen - HandlesTranslator._g_gen = gen - HandlesExpr._g_gen = gen - HandlesExprCall._g_gen = gen # P6: 注入语句/赋值/变量/导入/翻译驱动模块的单例 # 设置当前文件名(供报错使用) GenApi.set_current_file_type(file_path) diff --git a/App/lib/Phase/Phase1/Phase1Main.vp b/App/lib/Phase/Phase1/Phase1Main.vp index 586aa25..39edab5 100644 --- a/App/lib/Phase/Phase1/Phase1Main.vp +++ b/App/lib/Phase/Phase1/Phase1Main.vp @@ -9,8 +9,7 @@ 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.Gen.Translator as HandlesTranslator import lib.core.IncludesScanner as IncludesScanner import lib.Stub.StubMerger as StubMerger import lib.core.Gen.Generator as GenGenerator diff --git a/App/lib/Phase/Phase1/Phase1Scan.vp b/App/lib/Phase/Phase1/Phase1Scan.vp index 7c5bded..93375a2 100644 --- a/App/lib/Phase/Phase1/Phase1Scan.vp +++ b/App/lib/Phase/Phase1/Phase1Scan.vp @@ -11,8 +11,7 @@ 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.Gen.Translator as HandlesTranslator import lib.core.IncludesScanner as IncludesScanner import lib.Stub.StubMerger as StubMerger import lib.core.Gen.Generator as GenGenerator diff --git a/App/lib/Phase/Phase1/Phase1Topo.vp b/App/lib/Phase/Phase1/Phase1Topo.vp index 26ecb62..f01febe 100644 --- a/App/lib/Phase/Phase1/Phase1Topo.vp +++ b/App/lib/Phase/Phase1/Phase1Topo.vp @@ -10,8 +10,7 @@ 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.Gen.Translator as HandlesTranslator import lib.core.IncludesScanner as IncludesScanner import lib.Stub.StubMerger as StubMerger import lib.core.Gen.Generator as GenGenerator diff --git a/App/lib/Phase/Phase2/__init__.vp b/App/lib/Phase/Phase2/__init__.vp index 66b7f83..a5c1f5d 100644 --- a/App/lib/Phase/Phase2/__init__.vp +++ b/App/lib/Phase/Phase2/__init__.vp @@ -15,8 +15,7 @@ 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.Gen.Translator as HandlesTranslator import lib.Phase.BuildPipeline as BuildPipeline import lib.core.IncludesScanner as IncludesScanner import lib.core.CompilerFactory as CompilerFactory diff --git a/App/lib/Stub/StubGen/VpiReader.vp b/App/lib/Stub/StubGen/VpiReader.vp index 3ef86d1..aff875f 100644 --- a/App/lib/Stub/StubGen/VpiReader.vp +++ b/App/lib/Stub/StubGen/VpiReader.vp @@ -13,10 +13,8 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger.StubMergerStore as StubMergerStore -import lib.core.Handles.ExprCallTable as ExprCallTable # ============================================================ @@ -1959,7 +1957,7 @@ def _inject_function_declare(pool: memhub.MemBuddy | t.CPtr, # 补全全局函数表 TypeStr(参数已全部添加,对齐 FuncGenDef L211 行为): # vpi 注入路径若不补全,跨模块 vtable/调用解析 find_func_entry_global() # 时 TypeStr 为空 → "vtable 方法找不到函数实现"(依赖模块晚于本模块编译时必现) - ExprCallTable.update_global_func_typestr(pool, fd.name, func) + GenApi.update_global_func_typestr(pool, fd.name, func) # ============================================================ @@ -2152,7 +2150,7 @@ def _inject_method_declare(pool: memhub.MemBuddy | t.CPtr, # vpi 注入的方法声明若不补全 TypeStr,跨模块继承 vtable 生成时 # find_func_entry_global().TypeStr 为空 → "vtable 方法找不到函数实现" # (astaux.vp 先于 ast.base.vp 编译时必现:AST.accept 仅有 vpi 注入条目) - ExprCallTable.update_global_func_typestr(pool, lookup_name, func) + GenApi.update_global_func_typestr(pool, lookup_name, func) # ============================================================ diff --git a/App/lib/Stub/StubMerger/StubMergerBuild.vp b/App/lib/Stub/StubMerger/StubMergerBuild.vp index 4f1dc6a..2e3c2ff 100644 --- a/App/lib/Stub/StubMerger/StubMergerBuild.vp +++ b/App/lib/Stub/StubMerger/StubMergerBuild.vp @@ -13,7 +13,7 @@ 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.Gen.Translator as HandlesTranslator import lib.Phase.BuildPipeline as BuildPipeline import lib.Stub.StubGen.VpiReader as VpiReader import lib.Projectrans.Utils as Utils diff --git a/App/lib/Stub/StubMerger/StubMergerCollect.vp b/App/lib/Stub/StubMerger/StubMergerCollect.vp index 5671d00..1f222c2 100644 --- a/App/lib/Stub/StubMerger/StubMergerCollect.vp +++ b/App/lib/Stub/StubMerger/StubMergerCollect.vp @@ -12,7 +12,7 @@ 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.Gen.Translator as HandlesTranslator import lib.Phase.BuildPipeline as BuildPipeline import lib.Stub.StubGen.VpiReader as VpiReader import lib.Projectrans.Utils as Utils diff --git a/App/lib/Stub/StubMerger/StubMergerIR.vp b/App/lib/Stub/StubMerger/StubMergerIR.vp index c9deee1..8809a76 100644 --- a/App/lib/Stub/StubMerger/StubMergerIR.vp +++ b/App/lib/Stub/StubMerger/StubMergerIR.vp @@ -13,7 +13,7 @@ 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.Gen.Translator as HandlesTranslator import lib.Phase.BuildPipeline as BuildPipeline import lib.Stub.StubGen.VpiReader as VpiReader import lib.Projectrans.Utils as Utils diff --git a/App/lib/Stub/StubMerger/StubMergerStore.vp b/App/lib/Stub/StubMerger/StubMergerStore.vp index 46017c0..bd8afe7 100644 --- a/App/lib/Stub/StubMerger/StubMergerStore.vp +++ b/App/lib/Stub/StubMerger/StubMergerStore.vp @@ -12,7 +12,7 @@ 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.Gen.Translator as HandlesTranslator import lib.Phase.BuildPipeline as BuildPipeline import lib.Stub.StubGen.VpiReader as VpiReader import lib.Projectrans.Utils as Utils diff --git a/App/lib/Stub/StubMerger/StubMergerTopo.vp b/App/lib/Stub/StubMerger/StubMergerTopo.vp index 44b1aeb..4b28c8c 100644 --- a/App/lib/Stub/StubMerger/StubMergerTopo.vp +++ b/App/lib/Stub/StubMerger/StubMergerTopo.vp @@ -12,7 +12,7 @@ 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.Gen.Translator as HandlesTranslator import lib.Phase.BuildPipeline as BuildPipeline import lib.Stub.StubGen.VpiReader as VpiReader import lib.Projectrans.Utils as Utils diff --git a/App/lib/Stub/StubMerger/__init__.vp b/App/lib/Stub/StubMerger/__init__.vp index 5b228c7..56e7485 100644 --- a/App/lib/Stub/StubMerger/__init__.vp +++ b/App/lib/Stub/StubMerger/__init__.vp @@ -12,7 +12,7 @@ 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.Gen.Translator as HandlesTranslator import lib.Phase.BuildPipeline as BuildPipeline import lib.Stub.StubGen.VpiReader as VpiReader import lib.Projectrans.Utils as Utils diff --git a/App/lib/core/Gen/AssignGenMixin.vp b/App/lib/core/Gen/AssignGenMixin.vp index bbaa87b..e6eb1d9 100644 --- a/App/lib/core/Gen/AssignGenMixin.vp +++ b/App/lib/core/Gen/AssignGenMixin.vp @@ -9,12 +9,12 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger.StubMergerStore as StubMergerStore import lib.core.Gen.GenTypes as GenTypes import lib.core.Gen.Generator as Generator import lib.Stub.StubGen.VpiReader as VpiReader +import lib.core.Gen.GenApi as GenApi # ============================================================ # AssignGenMixin - 赋值翻译 Mixin(P6 方法化) @@ -789,9 +789,9 @@ class AssignGenMixin: # 1. 确定变量作用域类型: 0=local, 1=global, 2=nonlocal scope_type: int = 0 - if HT.is_global_name(trans, nm.id) != 0: + if GenApi.is_global_name(trans, nm.id) != 0: scope_type = 1 - elif HT.is_nonlocal_name(trans, nm.id) != 0: + elif GenApi.is_nonlocal_name(trans, nm.id) != 0: scope_type = 2 # 2. 加载当前值 @@ -999,9 +999,9 @@ class AssignGenMixin: return 0 # global/nonlocal 变量不需要局部 alloca - if HT.is_global_name(trans, nm.id) != 0: + if GenApi.is_global_name(trans, nm.id) != 0: return 0 - if HT.is_nonlocal_name(trans, nm.id) != 0: + if GenApi.is_nonlocal_name(trans, nm.id) != 0: return 0 # 模块级全局变量已由 handle_module_level_var 注册到模块作用域。 @@ -1161,7 +1161,7 @@ class AssignGenMixin: self.Gen.CallGenLeafKit.register_func_ptr_sig(nm.id, callable_ret) # global 变量:写入模块作用域中的全局变量 - if HT.is_global_name(trans, nm.id) != 0: + if GenApi.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: @@ -1178,7 +1178,7 @@ class AssignGenMixin: return 0 # nonlocal 变量:通过闭包 env 写入 - if HT.is_nonlocal_name(trans, nm.id) != 0: + if GenApi.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, @@ -1821,7 +1821,7 @@ class AssignGenMixin: if nm.id is None: continue # global 变量:写入模块作用域中的全局变量 - if HT.is_global_name(trans, nm.id) != 0: + if GenApi.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: @@ -1839,7 +1839,7 @@ class AssignGenMixin: continue # nonlocal 变量:通过闭包 env 写入 - if HT.is_nonlocal_name(trans, nm.id) != 0: + if GenApi.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: diff --git a/App/lib/core/Gen/AsyncGenMixin.vp b/App/lib/core/Gen/AsyncGenMixin.vp index 50350ab..f826d13 100644 --- a/App/lib/core/Gen/AsyncGenMixin.vp +++ b/App/lib/core/Gen/AsyncGenMixin.vp @@ -1,2848 +1,2846 @@ -import lib.core.Gen.GenTypes as GenTypes -import t, c -from stdint import * -import ast -import llvmlite -from llvmlite import LLVMType -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.Call.CallGenBase as CallGenBase - - -# ============================================================ -# AsyncGenMixin - TPV-M1 协程翻译(async def / await / coro.coro_run) -# -# M1 最小协程闭环(对齐 TPC lib/core/Handles/HandlesAsyncFunctions.py M1): -# - async def f(): → 帧结构体 %Coro_ = -# { i32 state, i32 done, i32 ret, } -# - create_() → malloc 帧 + 置零 state/done/ret,ret 帧指针 -# - resume_(frame) → switch(state) 状态机:case i → state_i 块 -# (静态段切分,每段以顶层 await 结尾), -# exit 块 load done 返回(0=SUSPEND 1=DONE) -# - await async_fn() → 创建子帧 + resume 到 DONE + 取子帧 ret 槽存父槽 -# + 父挂起(store state=下一恢复段号 + br exit) -# - coro.coro_run(frame) → 内联循环 resume 到 done,返回帧 ret 槽值(i32) -# -# M1 限制(与 TPC M1 一致): -# - async 函数无参数(fd.args 为空) -# - await 仅限顶层 AnnAssign/Assign(value 直接是 Await) -# - 无 coro_sleep / For 内 await / If-While 控制流(后续 M2/M3 扩展) -# -# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# @t.NoVTable:静态绑定。 -# ============================================================ - -SCOPE_FUNCTION: t.CDefine = 1 - -@t.NoVTable -class AsyncGenMixin(CallGenBase.CallGenBase): - """协程翻译 Mixin(TPV-M1 状态机)""" - - # ============================================================ - # 入口:async 函数定义 - # - # 由 FuncGenDef.translate_function_def 检测 fd.flags & FLAG_IS_ASYNC - # (=1,见 includes/ast/stmts.vp L342-345)后调用,早返回不进普通函数路径。 - # ============================================================ - def translate_async_function(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译 async 函数定义,返回 0 成功 - - 生成 create_(帧分配,M2 带参数)与 resume_(状态机), - 并把裸名注册进 trans._async_funcs(is_async_func / coro_run 反查)。 - - M2 帧布局:{ i32 state, i32 done, i32 ret, - 参数槽(3..3+nparams), 局部槽(3+nparams..), __await_N 额外槽 } - - 参数槽:create_(args) 收值入帧(M2 参数) - - 局部槽:顶层 AnnAssign/Assign 的 Name 目标 - - 额外槽:嵌套 await 提升临时变量 __await_N(预扫描分配,与翻译同序) - 恢复块状态号:state0 = 入口,每个 await(顶层或嵌套)按 DFS 顺序 - 分配 state1..,switch case 预建(TPV build_switch 一次性生成,无法动态 add_case)。 - """ - fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node) - if fd is None or fd.name is None or trans is None: - return 0 - name: str = fd.name - pool: memhub.MemBuddy | t.CPtr = trans.Pool - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - if pool is None or mod is None: - return 0 - - # 防重复生成:create_ 已存在(模块多遍编译/重复定义) - cname_buf: str = pool.alloc(64) - if cname_buf is not None: - viperlib.snprintf(cname_buf, 64, "create_%s", name) - create_mangled: str = self.Gen.FuncGenBase._mangle_func_name( - trans, cname_buf, 0) - if self.Gen.CallGenBase.find_func_in_module(mod, create_mangled) is not None: - return 0 - - # 注册 async 裸名(供 await 目标校验 / coro_run 反查) - self._register_async_func(trans, name) - - # M2:参数收集 → trans._coro_params(char* 数组,8 字节/项) - trans._coro_param_count = 0 - nparams: int = self._collect_param_names(trans, fd) - - # 局部变量收集(顶层 AnnAssign/Assign 的 Name 目标 → 帧槽) - trans._coro_local_count = 0 - nlocals: int = self._collect_local_names(trans, fd) - - # M3-M7:预扫描额外槽(wake/for/await 类型表 + 位置数组)+ 状态号 - # _coro_await_count = 恢复块数;nseg = 1 入口 + await_count - trans._coro_extra_count = 0 - trans._coro_hoist_count = 0 - trans._coro_await_count = 0 - trans._coro_uses_sleep = 0 - trans._coro_scan_for_count = 0 - trans._coro_for_counter = 0 - self._scan_sleep_usage(trans, fd) - self._pre_scan_awaits(trans, fd) - nextra: int = trans._coro_extra_count - trans._coro_nseg = 1 + trans._coro_await_count - - # 帧结构体 %Coro_ - frame_ty: llvmlite.LLVMType | t.CPtr = self._build_frame_ty( - pool, mod, trans, name, nparams, nlocals, nextra) - if frame_ty is None: - return 0 - self._register_coro_frame(trans, name, frame_ty) - # M3:wake 槽 index 注册(coro_run 轮询反查;wake 在额外槽相对 0) - if trans._coro_uses_sleep != 0: - self._register_coro_wake(trans, name, trans._coro_extra_base + 0) - - # 进入函数作用域:resume 局部槽注册隔离,翻译完退出不污染模块作用域 - self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_FUNCTION) - - self._emit_create(pool, mod, trans, name, frame_ty, nparams) - self._emit_resume(pool, mod, trans, name, fd, frame_ty, - nparams, nlocals, nextra) - - self.Gen.VarGen.exit_scope(trans.SymTab) - return 0 - - # ============================================================ - # M2:参数收集(帧参数槽 index 3+i) - # ============================================================ - def _collect_param_names(self, trans: HT.Translator | t.CPtr, - fd: ast.FunctionDef | t.CPtr) -> int: - """收集 async 函数参数名到 trans._coro_params(char* 数组,8 字节/项)。 - 参数槽 index = 3 + i,create_ 按参数顺序收值入帧。""" - if fd is None or fd.args is None or trans is None: - return 0 - if trans._coro_params is None: - return 0 - ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args) - cnt: int = 0 - if ags.args is None: - return 0 - bn: t.CSizeT = len(ags.args) - i: t.CSizeT = 0 - for i in range(bn): - a0: ast.AST | t.CPtr = ags.args.get(i) - if a0 is None: - continue - aname: str = None - if a0.kind() == ast.ASTKind.Arg: - ar: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(a0) - aname = ar.arg - elif a0.kind() == ast.ASTKind.Name: - anm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(a0) - aname = anm.id - if aname is None: - continue - if cnt >= HT.MAX_CORO_VARS: - break - addr: t.CUInt64T = t.CUInt64T(trans._coro_params) + cnt * 8 - slot: str | t.CPtr = (t.CVoid | t.CPtr)(addr) - slot[0] = aname - cnt = cnt + 1 - trans._coro_param_count = cnt - return cnt - - # ============================================================ - # M3-M7:预扫描额外槽(wake/for/await 类型表 + 位置数组)+ 状态号 - # - # 与翻译端同一 DFS 顺序。额外槽表 _coro_extra_types(i8:1=i32 2=i64): - # [0] __coro_wake_us(若用 coro_sleep,i64) - # 随后按 DFS:__f_idx_N/__f_len_N(range-For 含 await,i32)、 - # __await_N(嵌套 await,i32) - # 位置数组:_coro_await_slots[M]=__await_M 相对序号;_coro_for_slots[N]=__f_idx_N 相对序号 - # _coro_await_count = 恢复块数(顶层 + 嵌套 await) - # ============================================================ - def _pre_scan_awaits(self, trans: HT.Translator | t.CPtr, - fd: ast.FunctionDef | t.CPtr) -> int: - """DFS 预扫描协程体,填额外槽表并返回额外槽总数""" - if fd is None or fd.children is None or trans is None: - return 0 - trans._coro_extra_count = 0 - trans._coro_hoist_count = 0 - trans._coro_await_count = 0 - trans._coro_scan_for_count = 0 - if trans._coro_uses_sleep != 0: - trans._coro_extra_types[0] = 2 # __coro_wake_us(i64)相对序号 0 - trans._coro_extra_count = 1 - self._scan_stmts(trans, fd.children) - return trans._coro_extra_count - - # ---------- 第一遍:coro_sleep 检测(wake 槽决定) ---------- - def _scan_sleep_usage(self, trans: HT.Translator | t.CPtr, - fd: ast.FunctionDef | t.CPtr): - if fd is None or fd.children is None or trans is None: - return - self._scan_sleep_stmts(trans, fd.children) - - def _scan_sleep_stmts(self, trans: HT.Translator | t.CPtr, - stmts: list[ast.AST | t.CPtr] | t.CPtr): - if stmts is None or trans._coro_uses_sleep != 0: - return - bn: t.CSizeT = len(stmts) - i: t.CSizeT = 0 - for i in range(bn): - self._scan_sleep_stmt(trans, stmts.get(i)) - - def _scan_sleep_stmt(self, trans: HT.Translator | t.CPtr, - stmt: ast.AST | t.CPtr): - if stmt is None or trans._coro_uses_sleep != 0: - return - sk: int = stmt.kind() - if sk == ast.ASTKind.If: - ifn: ast.If | t.CPtr = (ast.If | t.CPtr)(stmt) - self._scan_sleep_expr(trans, ifn.test) - self._scan_sleep_stmts(trans, stmt.children) - self._scan_sleep_stmts(trans, ifn.orelse) - return - if sk == ast.ASTKind.While: - whn: ast.While | t.CPtr = (ast.While | t.CPtr)(stmt) - self._scan_sleep_expr(trans, whn.test) - self._scan_sleep_stmts(trans, stmt.children) - self._scan_sleep_stmts(trans, whn.orelse) - return - if sk == ast.ASTKind.For: - fn2: ast.For | t.CPtr = (ast.For | t.CPtr)(stmt) - self._scan_sleep_expr(trans, fn2.iter) - self._scan_sleep_stmts(trans, stmt.children) - self._scan_sleep_stmts(trans, fn2.orelse) - return - if sk == ast.ASTKind.Try: - trn: ast.Try | t.CPtr = (ast.Try | t.CPtr)(stmt) - self._scan_sleep_stmts(trans, stmt.children) - if trn.handlers is not None: - nh: t.CSizeT = len(trn.handlers) - hh: t.CSizeT = 0 - for hh in range(nh): - h0: ast.AST | t.CPtr = trn.handlers.get(hh) - if h0 is not None: - self._scan_sleep_stmts(trans, h0.children) - self._scan_sleep_stmts(trans, trn.orelse) - self._scan_sleep_stmts(trans, trn.finalbody) - return - if sk == ast.ASTKind.Return: - rv: ast.Return | t.CPtr = (ast.Return | t.CPtr)(stmt) - self._scan_sleep_expr(trans, rv.value) - return - if sk == ast.ASTKind.AnnAssign: - aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) - self._scan_sleep_expr(trans, aa.value) - return - if sk == ast.ASTKind.Assign: - as_: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) - self._scan_sleep_expr(trans, as_.value) - return - if sk == ast.ASTKind.Expr: - e: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(stmt) - self._scan_sleep_expr(trans, e.value) - return - - def _scan_sleep_expr(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr): - if node is None or trans._coro_uses_sleep != 0: - return - 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: - if cl.func.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl.func) - if nm.id is not None and string.strcmp(nm.id, "coro_sleep") == 0: - trans._coro_uses_sleep = 1 - return - elif cl.func.kind() == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if at.attr is not None and string.strcmp(at.attr, "coro_sleep") == 0: - trans._coro_uses_sleep = 1 - return - self._scan_sleep_expr(trans, cl.func) - if cl.args is not None: - nb: t.CSizeT = len(cl.args) - j: t.CSizeT = 0 - for j in range(nb): - self._scan_sleep_expr(trans, cl.args.get(j)) - return - if k == ast.ASTKind.BinOp: - b: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - self._scan_sleep_expr(trans, b.left) - self._scan_sleep_expr(trans, b.right) - return - if k == ast.ASTKind.UnaryOp: - u: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) - self._scan_sleep_expr(trans, u.operand) - return - if k == ast.ASTKind.Compare: - cm: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) - self._scan_sleep_expr(trans, cm.left) - if cm.comparators is not None: - nb2: t.CSizeT = len(cm.comparators) - j2: t.CSizeT = 0 - for j2 in range(nb2): - self._scan_sleep_expr(trans, cm.comparators.get(j2)) - return - if k == ast.ASTKind.BoolOp: - bo: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) - if bo.values is not None: - nb3: t.CSizeT = len(bo.values) - j3: t.CSizeT = 0 - for j3 in range(nb3): - self._scan_sleep_expr(trans, bo.values.get(j3)) - return - if k == ast.ASTKind.IfExp: - ie: ast.IfExp | t.CPtr = (ast.IfExp | t.CPtr)(node) - self._scan_sleep_expr(trans, ie.test) - self._scan_sleep_expr(trans, ie.body) - self._scan_sleep_expr(trans, ie.orelse) - return - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - self._scan_sleep_expr(trans, at.value) - return - if k == ast.ASTKind.Subscript: - sb: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - self._scan_sleep_expr(trans, sb.value) - self._scan_sleep_expr(trans, sb.slice) - return - if k == ast.ASTKind.Await: - aw: ast.Await | t.CPtr = (ast.Await | t.CPtr)(node) - self._scan_sleep_expr(trans, aw.value) - return - - # ---------- 第二遍:填额外槽表 + 状态号计数 ---------- - def _scan_stmts(self, trans: HT.Translator | t.CPtr, - stmts: list[ast.AST | t.CPtr] | t.CPtr): - if stmts is None: - return - bn: t.CSizeT = len(stmts) - i: t.CSizeT = 0 - for i in range(bn): - self._scan_stmt(trans, stmts.get(i)) - - def _scan_stmt(self, trans: HT.Translator | t.CPtr, - stmt: ast.AST | t.CPtr): - if stmt is None: - return - sk: int = stmt.kind() - if sk == ast.ASTKind.If: - ifn: ast.If | t.CPtr = (ast.If | t.CPtr)(stmt) - if ifn.test is not None: - self._scan_expr(trans, ifn.test) - self._scan_stmts(trans, stmt.children) - self._scan_stmts(trans, ifn.orelse) - return - if sk == ast.ASTKind.While: - whn: ast.While | t.CPtr = (ast.While | t.CPtr)(stmt) - if whn.test is not None: - self._scan_expr(trans, whn.test) - self._scan_stmts(trans, stmt.children) - self._scan_stmts(trans, whn.orelse) - return - if sk == ast.ASTKind.For: - fn_: ast.For | t.CPtr = (ast.For | t.CPtr)(stmt) - if self._for_deep_await(stmt) != 0: - # 含 await:必须是 range-For(M3) - if self._is_range_for(stmt) == 0: - err_b2: str = trans.Pool.alloc(256) - if err_b2 is not None: - viperlib.snprintf( - err_b2, 256, - "[coro-M3] 协程内 For 仅支持 range 迭代(含 await)") - self.Gen.TypeGenErr.fatal_error(stmt, err_b2, "SyntaxError") - return - # 填 __f_idx_N / __f_len_N(i32) - if trans._coro_scan_for_count < HT.MAX_CORO_VARS: - trans._coro_for_slots[trans._coro_scan_for_count] = trans._coro_extra_count - trans._coro_extra_types[trans._coro_extra_count] = 1 - trans._coro_extra_count = trans._coro_extra_count + 1 - trans._coro_extra_types[trans._coro_extra_count] = 1 - trans._coro_extra_count = trans._coro_extra_count + 1 - trans._coro_scan_for_count = trans._coro_scan_for_count + 1 - self._scan_stmts(trans, stmt.children) - self._scan_stmts(trans, fn_.orelse) - return - # 无 await:委托标准 For;递归扫描(嵌套 For/Try 可能含 await) - self._scan_stmts(trans, stmt.children) - self._scan_stmts(trans, fn_.orelse) - return - if sk == ast.ASTKind.Try: - tr2: ast.Try | t.CPtr = (ast.Try | t.CPtr)(stmt) - self._scan_stmts(trans, stmt.children) - if tr2.handlers is not None: - nh2: t.CSizeT = len(tr2.handlers) - hh2: t.CSizeT = 0 - for hh2 in range(nh2): - h2: ast.AST | t.CPtr = tr2.handlers.get(hh2) - if h2 is not None: - self._scan_stmts(trans, h2.children) - self._scan_stmts(trans, tr2.orelse) - self._scan_stmts(trans, tr2.finalbody) - return - if sk == ast.ASTKind.Raise: - rz: ast.Raise | t.CPtr = (ast.Raise | t.CPtr)(stmt) - if rz.exc is not None: - self._scan_expr(trans, rz.exc) - return - if sk == ast.ASTKind.Return: - rv: ast.Return | t.CPtr = (ast.Return | t.CPtr)(stmt) - if rv.value is not None: - self._scan_expr(trans, rv.value) - return - if sk == ast.ASTKind.Break or sk == ast.ASTKind.Continue: - return - # 顶层 await(AnnAssign/Assign/Expr value 直接 Await):计数不提升 - if sk == ast.ASTKind.AnnAssign or sk == ast.ASTKind.Assign or sk == ast.ASTKind.Expr: - if self._is_await_tail(stmt) != 0: - trans._coro_await_count = trans._coro_await_count + 1 - return - # 语句内嵌套 await:DFS 表达式(AnnAssign.value / Assign.value / Expr.value) - self._scan_stmt_exprs(trans, stmt) - - def _scan_stmt_exprs(self, trans: HT.Translator | t.CPtr, - stmt: ast.AST | t.CPtr): - """扫描语句的值表达式找嵌套 await""" - if stmt is None: - return - sk: int = stmt.kind() - if sk == ast.ASTKind.AnnAssign: - aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) - if aa.value is not None: - self._scan_expr(trans, aa.value) - return - if sk == ast.ASTKind.Assign: - as_: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) - if as_.value is not None: - self._scan_expr(trans, as_.value) - return - if sk == ast.ASTKind.Expr: - e: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(stmt) - if e.value is not None: - self._scan_expr(trans, e.value) - return - # 其它语句类型:翻译端 fail-fast - - def _scan_expr(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr): - """DFS 扫描表达式找 Await:命中分配 __await_N 槽并计数状态号""" - if node is None: - return - k: int = node.kind() - if k == ast.ASTKind.Await: - # M3:await coro_sleep 用 wake 槽挂起,不占 __await_N 槽(仅计状态号) - aw_s: ast.Await | t.CPtr = (ast.Await | t.CPtr)(node) - if self._expr_await_is_sleep(aw_s) != 0: - trans._coro_await_count = trans._coro_await_count + 1 - return - if trans._coro_hoist_count < HT.MAX_CORO_VARS: - trans._coro_await_slots[trans._coro_hoist_count] = trans._coro_extra_count - trans._coro_extra_types[trans._coro_extra_count] = 1 - trans._coro_extra_count = trans._coro_extra_count + 1 - trans._coro_hoist_count = trans._coro_hoist_count + 1 - trans._coro_await_count = trans._coro_await_count + 1 - return - if k == ast.ASTKind.BinOp: - b: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - self._scan_expr(trans, b.left) - self._scan_expr(trans, b.right) - return - if k == ast.ASTKind.Call: - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) - if cl.func is not None: - self._scan_expr(trans, cl.func) - if cl.args is not None: - nb: t.CSizeT = len(cl.args) - j: t.CSizeT = 0 - for j in range(nb): - self._scan_expr(trans, cl.args.get(j)) - return - if k == ast.ASTKind.UnaryOp: - u: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) - if u.operand is not None: - self._scan_expr(trans, u.operand) - return - if k == ast.ASTKind.Compare: - cm: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) - if cm.left is not None: - self._scan_expr(trans, cm.left) - if cm.comparators is not None: - nb2: t.CSizeT = len(cm.comparators) - j2: t.CSizeT = 0 - for j2 in range(nb2): - self._scan_expr(trans, cm.comparators.get(j2)) - return - if k == ast.ASTKind.BoolOp: - bo: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) - if bo.values is not None: - nb3: t.CSizeT = len(bo.values) - j3: t.CSizeT = 0 - for j3 in range(nb3): - self._scan_expr(trans, bo.values.get(j3)) - return - if k == ast.ASTKind.IfExp: - ie: ast.IfExp | t.CPtr = (ast.IfExp | t.CPtr)(node) - self._scan_expr(trans, ie.test) - self._scan_expr(trans, ie.body) - self._scan_expr(trans, ie.orelse) - return - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at.value is not None: - self._scan_expr(trans, at.value) - return - if k == ast.ASTKind.Subscript: - sb: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - if sb.value is not None: - self._scan_expr(trans, sb.value) - if sb.slice is not None: - self._scan_expr(trans, sb.slice) - return - # Name / Constant 等叶子:无嵌套 await - - # ---------- For 判定辅助(M3) ---------- - def _for_deep_await(self, stmt: ast.AST | t.CPtr) -> int: - """For 语句树(含嵌套 If/While/For/Try/body/orelse)是否含 await""" - if stmt is None: - return 0 - fn3: ast.For | t.CPtr = (ast.For | t.CPtr)(stmt) - if fn3.iter is not None and self._find_expr_await(fn3.iter) is not None: - return 1 - if stmt.children is not None: - bn4: t.CSizeT = len(stmt.children) - i4: t.CSizeT = 0 - for i4 in range(bn4): - if self._stmt_deep_await(stmt.children.get(i4)) != 0: - return 1 - if fn3.orelse is not None: - bn5: t.CSizeT = len(fn3.orelse) - i5: t.CSizeT = 0 - for i5 in range(bn5): - if self._stmt_deep_await(fn3.orelse.get(i5)) != 0: - return 1 - return 0 - - def _stmt_deep_await(self, stmt: ast.AST | t.CPtr) -> int: - """语句树(含嵌套 If/While/For/Try)是否含 await""" - if stmt is None: - return 0 - sk2: int = stmt.kind() - if sk2 == ast.ASTKind.If: - ifn2: ast.If | t.CPtr = (ast.If | t.CPtr)(stmt) - if ifn2.test is not None and self._find_expr_await(ifn2.test) is not None: - return 1 - if self._stmts_deep_await(stmt.children) != 0: - return 1 - return self._stmts_deep_await(ifn2.orelse) - if sk2 == ast.ASTKind.While: - whn2: ast.While | t.CPtr = (ast.While | t.CPtr)(stmt) - if whn2.test is not None and self._find_expr_await(whn2.test) is not None: - return 1 - if self._stmts_deep_await(stmt.children) != 0: - return 1 - return self._stmts_deep_await(whn2.orelse) - if sk2 == ast.ASTKind.For: - return self._for_deep_await(stmt) - if sk2 == ast.ASTKind.Try: - tr3: ast.Try | t.CPtr = (ast.Try | t.CPtr)(stmt) - if self._stmts_deep_await(stmt.children) != 0: - return 1 - if tr3.handlers is not None: - nh3: t.CSizeT = len(tr3.handlers) - hh3: t.CSizeT = 0 - for hh3 in range(nh3): - h3: ast.AST | t.CPtr = tr3.handlers.get(hh3) - if h3 is not None and self._stmts_deep_await(h3.children) != 0: - return 1 - if self._stmts_deep_await(tr3.orelse) != 0: - return 1 - return self._stmts_deep_await(tr3.finalbody) - return self._stmt_has_await(stmt) - - def _stmts_deep_await(self, stmts: list[ast.AST | t.CPtr] | t.CPtr) -> int: - if stmts is None: - return 0 - bn6: t.CSizeT = len(stmts) - i6: t.CSizeT = 0 - for i6 in range(bn6): - if self._stmt_deep_await(stmts.get(i6)) != 0: - return 1 - return 0 - - def _is_range_for(self, stmt: ast.AST | t.CPtr) -> int: - """range-For:单 Name target + iter 是 range(x) 或 range(a, b),参数无 await""" - if stmt is None: - return 0 - fn4: ast.For | t.CPtr = (ast.For | t.CPtr)(stmt) - if fn4.target is None or fn4.target.kind() != ast.ASTKind.Name: - return 0 - if fn4.iter is None or fn4.iter.kind() != ast.ASTKind.Call: - return 0 - cl4: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fn4.iter) - if cl4.func is None or cl4.func.kind() != ast.ASTKind.Name: - return 0 - nm4: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl4.func) - if nm4.id is None or string.strcmp(nm4.id, "range") != 0: - return 0 - if cl4.args is None: - return 0 - nb7: t.CSizeT = len(cl4.args) - if nb7 != 1 and nb7 != 2: - return 0 - j7: t.CSizeT = 0 - for j7 in range(nb7): - if self._find_expr_await(cl4.args.get(j7)) is not None: - return 0 - return 1 - - # ============================================================ - # 局部变量收集(顶层 AnnAssign / Assign 的 Name 目标) - # ============================================================ - def _collect_local_names(self, trans: HT.Translator | t.CPtr, - fd: ast.FunctionDef | t.CPtr) -> int: - """收集帧局部变量名(_coro_locals,8 字节/项): - - 顶层 AnnAssign/Assign 的 Name 目标(M2) - - try 的 except as e 绑定名(M5/M6,跨 handler 需要帧槽) - - 含 await 的 range-For 迭代目标(M3) - 递归扫描(If/While/For/Try 嵌套)。""" - if fd is None or fd.children is None or trans is None: - return 0 - if trans._coro_locals is None: - return 0 - trans._coro_local_count = 0 - self._collect_locals_stmts(trans, fd.children) - return trans._coro_local_count - - def _collect_locals_stmts(self, trans: HT.Translator | t.CPtr, - stmts: list[ast.AST | t.CPtr] | t.CPtr): - if stmts is None: - return - bn: t.CSizeT = len(stmts) - i: t.CSizeT = 0 - for i in range(bn): - self._collect_locals_stmt(trans, stmts.get(i)) - - def _collect_locals_stmt(self, trans: HT.Translator | t.CPtr, - stmt: ast.AST | t.CPtr): - if stmt is None: - return - sk: int = stmt.kind() - if 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) - self._add_local(trans, tn.id) - return - if sk == ast.ASTKind.Assign: - as_: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) - if as_.targets is not None and len(as_.targets) == 1: - t0: ast.AST | t.CPtr = as_.targets.get(0) - if t0 is not None and t0.kind() == ast.ASTKind.Name: - tn2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(t0) - self._add_local(trans, tn2.id) - return - if sk == ast.ASTKind.If: - self._collect_locals_stmts(trans, stmt.children) - ifn: ast.If | t.CPtr = (ast.If | t.CPtr)(stmt) - self._collect_locals_stmts(trans, ifn.orelse) - return - if sk == ast.ASTKind.While: - self._collect_locals_stmts(trans, stmt.children) - whn: ast.While | t.CPtr = (ast.While | t.CPtr)(stmt) - self._collect_locals_stmts(trans, whn.orelse) - return - if sk == ast.ASTKind.For: - fn: ast.For | t.CPtr = (ast.For | t.CPtr)(stmt) - if self._for_deep_await(stmt) != 0: - if fn.target is not None and fn.target.kind() == ast.ASTKind.Name: - tn3: ast.Name | t.CPtr = (ast.Name | t.CPtr)(fn.target) - self._add_local(trans, tn3.id) - self._collect_locals_stmts(trans, stmt.children) - self._collect_locals_stmts(trans, fn.orelse) - return - if sk == ast.ASTKind.Try: - tr: ast.Try | t.CPtr = (ast.Try | t.CPtr)(stmt) - self._collect_locals_stmts(trans, stmt.children) - if tr.handlers is not None: - nh: t.CSizeT = len(tr.handlers) - hh: t.CSizeT = 0 - for hh in range(nh): - h0: ast.AST | t.CPtr = tr.handlers.get(hh) - if h0 is None: - continue - hd: ast.ExceptHandler | t.CPtr = (ast.ExceptHandler | t.CPtr)(h0) - self._add_local(trans, hd.name) - self._collect_locals_stmts(trans, h0.children) - self._collect_locals_stmts(trans, tr.orelse) - self._collect_locals_stmts(trans, tr.finalbody) - return - - def _add_local(self, trans: HT.Translator | t.CPtr, - name: str): - if name is None: - return - cnt: int = trans._coro_local_count - if cnt >= HT.MAX_CORO_VARS: - return - addr: t.CUInt64T = t.CUInt64T(trans._coro_locals) + cnt * 8 - slot: str | t.CPtr = (t.CVoid | t.CPtr)(addr) - slot[0] = name - trans._coro_local_count = cnt + 1 - - # ============================================================ - # 帧结构体 %Coro_ = { i32 state, i32 done, i32 ret, <局部槽>* } - # 槽索引: 0=state 1=done 2=ret 3..3+nlocals-1=局部变量 - # ============================================================ - def _build_frame_ty(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - trans: HT.Translator | t.CPtr, - name: str, - nparams: int, nlocals: int, - nextra: int) -> llvmlite.LLVMType | t.CPtr: - """构造帧结构体并注册到模块与结构体表,返回 LLVMType - M7 布局:{i32 state, i32 done, i32 ret, i32 exc, i8* msg, - 参数槽(5+i), 局部槽(5+nparams+i), 额外槽(extra_base+i, 按类型表 1=i32 2=i64)}""" - 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, llvmlite.Int8(pool)) - # 槽基址(供 resume/await 计算槽 index) - trans._coro_local_base = 5 + nparams - trans._coro_extra_base = trans._coro_local_base + nlocals - total: int = 5 + nparams + nlocals + nextra - head: llvmlite.ParamNode | t.CPtr = None - prev: llvmlite.ParamNode | t.CPtr = None - fi: int = 0 - for fi in range(total): - fty: llvmlite.LLVMType | t.CPtr = i32_ty - if fi == 4: - fty = i8_ptr_ty - elif fi >= trans._coro_extra_base: - tidx: int = fi - trans._coro_extra_base - if tidx < nextra and trans._coro_extra_types is not None: - if trans._coro_extra_types[tidx] == 2: - fty = i64_ty - 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 head is None: - head = pnode - if prev is not None: - prev.Next = pnode - prev = pnode - ty_name: str = pool.alloc(128) - if ty_name is not None: - viperlib.snprintf(ty_name, 128, "Coro_%s", name) - frame_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct( - pool, head, total, ty_name) - if frame_ty is None: - return None - llvmlite.module_add_named_type(mod, pool, frame_ty) - self.Gen.StructGen.register_struct( - pool, ty_name, frame_ty, trans.ModuleSha1) - return frame_ty - - # ============================================================ - # create_() -> %Coro_* - # ============================================================ - def _emit_create(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - trans: HT.Translator | t.CPtr, - name: str, - frame_ty: llvmlite.LLVMType | t.CPtr, - nparams: int) -> int: - """生成 create_(args...):M7 帧池弹帧(i64 池头 free-list)或 malloc, - 5 头清零 + 参数存槽(帧槽 5+i)+ ret 帧指针""" - if frame_ty is None: - return 0 - 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) - i64_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i64_ty) - frame_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, frame_ty) - - cname_buf2: str = pool.alloc(64) - if cname_buf2 is not None: - viperlib.snprintf(cname_buf2, 64, "create_%s", name) - mangled: str = self.Gen.FuncGenBase._mangle_func_name( - trans, cname_buf2, 0) - if self.Gen.CallGenBase.find_func_in_module(mod, mangled) is not None: - return 0 - func: llvmlite.Function | t.CPtr = llvmlite.create_function( - pool, mod, mangled, frame_ptr_ty) - if func is None: - return 0 - # 参数(i32,帧槽 5+i)。TPV 无 Python % 格式化(% 是取模), - # 参数名用 snprintf 生成("%%arg" → "%arg",与 resume "%frame" 命名一致)。 - pi: int = 0 - argn_buf: str = pool.alloc(16) - for pi in range(nparams): - if argn_buf is not None: - viperlib.snprintf(argn_buf, 16, "%%arg%d", pi) - llvmlite.add_param(pool, func, i32_ty, argn_buf) - # 注册到函数表(裸名 create_) - funcs_ptr: GenTypes.FuncEntry | t.CPtr = trans._funcs - cur_count: int = trans._func_count - if self.Gen.CallGenLeafKit.add_func_to_table( - funcs_ptr, cur_count, cname_buf2, func, 1024, - None, 0, 0, trans.Pool) == 0: - trans._func_count = cur_count + 1 - - entry: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "entry") - if entry is None: - return 0 - builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) - if builder is None: - return 0 - llvmlite.position_at_end(builder, entry) - - frame_size: int = self.Gen.ClassGenEnum._get_type_size(frame_ty) - size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, frame_size) - if size_val is None: - return 0 - size_val.Next = None - - # M7 帧池:i64 池头(0 = 空);帧首 8 字节存 next(覆盖 state/done,弹池后统一清零) - pool_gv: llvmlite.GlobalVariable | t.CPtr = self._get_coro_pool( - pool, mod, trans, name) - # GlobalVariable 非 Value 子类:构造 Value 视图(Ty=Ptr(i64), Name="@coro_pool_") - pool_ref_name: str = pool.alloc(96) - if pool_ref_name is not None: - viperlib.snprintf(pool_ref_name, 96, "@coro_pool_%s", name) - pool_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, i64_ptr_ty, pool_ref_name) - pool_head: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i64_ty, pool_ref) - if pool_head is None: - return 0 - zero64: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) - empty_cond: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_EQ, pool_head, zero64) - if empty_cond is None: - return 0 - hit_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "pool.hit") - miss_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "pool.miss") - join_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "pool.join") - if hit_bb is None or miss_bb is None or join_bb is None: - return 0 - llvmlite.build_cond_br(builder, empty_cond, miss_bb, hit_bb) - # hit:弹池(帧首 8 字节是 next) - llvmlite.position_at_end(builder, hit_bb) - node_next_ptr: llvmlite.Value | t.CPtr = llvmlite.build_inttoptr( - builder, pool_head, i64_ptr_ty) - next_head: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i64_ty, node_next_ptr) - if next_head is None: - return 0 - llvmlite.build_store(builder, next_head, pool_ref) - hit_frame: llvmlite.Value | t.CPtr = llvmlite.build_inttoptr( - builder, pool_head, frame_ptr_ty) - if hit_frame is None: - return 0 - llvmlite.build_br(builder, join_bb) - # miss:malloc + 帧首 8 字节置 0(弹池帧的 next 残留清零) - llvmlite.position_at_end(builder, miss_bb) - raw: llvmlite.Value | t.CPtr = llvmlite.build_call( - builder, "malloc", size_val, 1, i8_ptr_ty, 0) - if raw is None: - return 0 - miss_frame: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, raw, frame_ptr_ty) - if miss_frame is None: - return 0 - miss_head_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, miss_frame, i64_ptr_ty) - if miss_head_ptr is not None: - llvmlite.build_store(builder, zero64, miss_head_ptr) - llvmlite.build_br(builder, join_bb) - # join:phi 选帧 + 5 头清零(弹池复用帧必须重置 state/done/ret/exc/msg)+ 参数存槽 - llvmlite.position_at_end(builder, join_bb) - inc1: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming( - pool, hit_frame, hit_bb) - inc2: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming( - pool, miss_frame, miss_bb) - if inc1 is None or inc2 is None: - return 0 - inc1.Next = inc2 - frame_ref: llvmlite.Value | t.CPtr = llvmlite.build_phi( - builder, frame_ptr_ty, inc1, 2) - if frame_ref is None: - return 0 - zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - null_p: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty, "null") - si: int = 0 - for si in range(5): - if si == 4: - mslot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, frame_ty, i8_ptr_ty, frame_ref, 4) - if mslot is not None: - llvmlite.build_store(builder, null_p, mslot) - else: - slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, frame_ty, i32_ty, frame_ref, si) - if slot is not None: - llvmlite.build_store(builder, zero, slot) - # 参数存帧槽(index 5+i) - pj: int = 0 - for pj in range(nparams): - pslot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, frame_ty, i32_ty, frame_ref, 5 + pj) - if pslot is not None: - arnb: str = pool.alloc(16) - if arnb is not None: - viperlib.snprintf(arnb, 16, "%%arg%d", pj) - arg_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, i32_ty, arnb) - if arg_ref is not None: - llvmlite.build_store(builder, arg_ref, pslot) - llvmlite.build_ret(builder, frame_ref) - return 0 - - # ============================================================ - # M7:每帧类型的全局 free-list 池头(i64,0 = 空) - # ============================================================ - def _get_coro_pool(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - trans: HT.Translator | t.CPtr, - name: str) -> llvmlite.GlobalVariable | t.CPtr: - """取/建 coro_pool_ 全局(i64 池头)。池节点 next 存帧首 8 字节。""" - pn_buf: str = pool.alloc(128) - if pn_buf is not None: - viperlib.snprintf(pn_buf, 128, "coro_pool_%s", name) - # 幂等:create/destroy 都会调用,须先查模块全局链表(无 find_global API) - g: llvmlite.GlobalVariable | t.CPtr = mod.GlobalHead - while g is not None: - if g.Name is not None and string.strcmp(g.Name, pn_buf) == 0: - return g - g = g.Next - return llvmlite.create_global_int(pool, mod, pn_buf, 64, 0) - - def _register_coro_wake(self, trans: HT.Translator | t.CPtr, - name: str, wake_idx: int): - """记录 async 名的 wake 槽 index(_coro_wake_names/_coro_wake_idxs 平行表)""" - if trans is None or name is None or trans._coro_wake_names is None: - return - cnt: int = trans._coro_wake_count - if cnt >= HT.MAX_CORO_FUNCS: - return - addr: t.CUInt64T = t.CUInt64T(trans._coro_wake_names) + cnt * 8 - slot: str | t.CPtr = (t.CVoid | t.CPtr)(addr) - slot[0] = name - trans._coro_wake_idxs[cnt] = wake_idx - trans._coro_wake_count = cnt + 1 - - def _lookup_coro_wake(self, trans: HT.Translator | t.CPtr, - name: str) -> int: - """查 async 名的 wake 槽 index,无 wake 槽返回 -1""" - if trans is None or name is None or trans._coro_wake_names is None: - return -1 - i: int = 0 - for i in range(trans._coro_wake_count): - addr: t.CUInt64T = t.CUInt64T(trans._coro_wake_names) + i * 8 - slot: str | t.CPtr = (t.CVoid | t.CPtr)(addr) - if slot[0] is not None and string.strcmp(slot[0], name) == 0: - return trans._coro_wake_idxs[i] - return -1 - - # ============================================================ - # resume_(%Coro_*) -> i32 状态机(静态段切分) - # ============================================================ - def _emit_resume(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - trans: HT.Translator | t.CPtr, - name: str, - fd: ast.FunctionDef | t.CPtr, - frame_ty: llvmlite.LLVMType | t.CPtr, - nparams: int, nlocals: int, - nextra: int) -> int: - """生成 resume_(frame) -> i32 状态机(M2): - entry 读 state → switch → state0 主入口递归翻译整个函数体; - 每个 await(顶层或嵌套,DFS 序)分配 state{N} 恢复块(预建 case); - exit 块 load done 返回(0=SUSPEND 1=DONE)。""" - if frame_ty is None: - return 0 - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - frame_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, frame_ty) - - rname_buf: str = pool.alloc(64) - if rname_buf is not None: - viperlib.snprintf(rname_buf, 64, "resume_%s", name) - mangled: str = self.Gen.FuncGenBase._mangle_func_name( - trans, rname_buf, 0) - func: llvmlite.Function | t.CPtr = llvmlite.create_function( - pool, mod, mangled, i32_ty) - if func is None: - return 0 - llvmlite.add_param(pool, func, frame_ptr_ty, "%frame") - funcs_ptr: GenTypes.FuncEntry | t.CPtr = trans._funcs - cur_count: int = trans._func_count - if self.Gen.CallGenLeafKit.add_func_to_table( - funcs_ptr, cur_count, rname_buf, func, 1024, - None, 0, 1, trans.Pool) == 0: - trans._func_count = cur_count + 1 - - entry: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "entry") - if entry is None: - return 0 - builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) - if builder is None: - return 0 - llvmlite.position_at_end(builder, entry) - - frame_arg: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, frame_ptr_ty, "%frame") - if frame_arg is None: - return 0 - - # GEP 5 头槽(M4 exc / M7 msg) - i8_ptr_ty_r: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - i64_ty_r: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - state_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, frame_ty, i32_ty, frame_arg, 0) - done_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, frame_ty, i32_ty, frame_arg, 1) - ret_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, frame_ty, i32_ty, frame_arg, 2) - exc_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, frame_ty, i32_ty, frame_arg, 3) - msg_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, frame_ty, i8_ptr_ty_r, frame_arg, 4) - - # 参数槽 GEP → 注册到符号表(index 5+i) - pj: int = 0 - for pj in range(nparams): - pname: str = self._read_param_name(trans, pj) - if pname is None: - continue - pslot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, frame_ty, i32_ty, frame_arg, 5 + pj) - if pslot is not None: - self.Gen.VarGen.define_var(trans.SymTab, pname, pslot) - - # 局部槽 GEP → 注册到符号表 - li: int = 0 - for li in range(nlocals): - lname: str = self._read_local_name(trans, li) - if lname is None: - continue - slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, frame_ty, i32_ty, frame_arg, - trans._coro_local_base + li) - if slot is not None: - self.Gen.VarGen.define_var(trans.SymTab, lname, slot) - - # M3-M7:额外槽注册(wake i64 / __f_idx/__f_len/__await i32)。 - # 名字反查:wake=uses_sleep 且 ei==0;for=位置数组 _coro_for_slots; - # 其余按 _coro_await_slots 反查 __await_M。 - ei: int = 0 - for ei in range(nextra): - ety: int = 1 - if trans._coro_extra_types is not None: - ety = trans._coro_extra_types[ei] - ety_llvm: llvmlite.LLVMType | t.CPtr = i32_ty - if ety == 2: - ety_llvm = i64_ty_r - eslot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, frame_ty, ety_llvm, frame_arg, - trans._coro_extra_base + ei) - if eslot is None: - continue - # wake 槽:只存指针,不注册 SymTab(coro_run 轮询用) - if trans._coro_uses_sleep != 0 and ei == 0: - trans._coro_wake_ptr = eslot - continue - ename: str = pool.alloc(16) - # for 槽:_coro_for_slots[N] 是 __f_idx_N 位置,+1 是 __f_len_N - is_for: int = 0 - is_len: int = 0 - kf: int = 0 - for kf in range(trans._coro_scan_for_count): - if trans._coro_for_slots[kf] == ei: - is_for = 1 - break - if trans._coro_for_slots[kf] + 1 == ei: - is_for = 1 - is_len = 1 - break - if is_for != 0: - if ename is not None: - if is_len != 0: - viperlib.snprintf(ename, 16, "__f_len_%d", kf) - else: - viperlib.snprintf(ename, 16, "__f_idx_%d", kf) - else: - # __await_M:反查位置数组 - found: int = 0 - km: int = 0 - for km in range(nextra): - if trans._coro_await_slots[km] == ei: - found = 1 - break - if found == 0: - continue - if ename is not None: - viperlib.snprintf(ename, 16, "__await_%d", km) - if ename is not None: - self.Gen.VarGen.define_var(trans.SymTab, ename, eslot) - - # state 值 + exit 块 - state_val: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i32_ty, state_ptr) - exit_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "coro.exit") - if exit_bb is None: - return 0 - - # 保存 resume 上下文(await 挂起 / 恢复块共享) - trans._coro_state_ptr = state_ptr - trans._coro_done_ptr = done_ptr - trans._coro_ret_ptr = ret_ptr - trans._coro_exc_ptr = exc_ptr - trans._coro_msg_ptr = msg_ptr - trans._coro_wake_ptr = None - trans._coro_exit_bb = exit_bb - trans._coro_frame = frame_arg - trans._coro_await_slot = None - # state0 是入口,await 从状态号 1 开始(与预扫描 DFS 序一致) - trans._coro_next_state = 1 - # 翻译期序号(与预扫描同序) - trans._coro_hoist_count = 0 - trans._coro_for_counter = 0 - trans._coro_try_stack_count = 0 - trans._coro_break_bb = None - trans._coro_continue_bb = None - - nseg: int = trans._coro_nseg - if nseg <= 0: - nseg = 1 - # 预建 state 块 + switch case(一次性生成,await 恢复块 position 填充) - state_bbs: t.CSizeT | t.CPtr = pool.alloc(nseg * 8) - if state_bbs is None: - return 0 - trans._coro_state_bbs = state_bbs - sw_head: llvmlite.SwitchCase | t.CPtr = None - sw_tail: llvmlite.SwitchCase | t.CPtr = None - sw_count: int = 0 - bb_name: str = pool.alloc(32) - si: int = 0 - for si in range(nseg): - if bb_name is not None: - viperlib.snprintf(bb_name, 32, "state%d", si) - sbb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, bb_name) - if sbb is None: - continue - state_bbs[si] = t.CSizeT(sbb) - sc: llvmlite.SwitchCase | t.CPtr = llvmlite.new_switch_case( - pool, llvmlite.const_int32(pool, si), sbb) - 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 - llvmlite.build_switch(builder, state_val, exit_bb, sw_head, sw_count) - - # ---- state0 主入口:递归翻译整个函数体(If/While 内 await 动态恢复)---- - # 标准语句翻译(translate_stmt → translate_assign/annassign 等)从 - # trans._cur_builder/_cur_func 取当前 IRBuilder/Function——必须在此设置, - # 后续 position_at_end 都作用于同一 builder 对象,_cur_builder 引用不变。 - trans._cur_func = func - trans._cur_builder = builder - seg_bb: llvmlite.BasicBlock | t.CPtr = (llvmlite.BasicBlock | t.CPtr)( - t.CVoid(state_bbs[0], t.CPtr)) - llvmlite.position_at_end(builder, seg_bb) - self._handle_segment(trans, builder, pool, mod, fd.children) - # 函数体自然结束 → 隐式 return(ret=0 + done=1 + br exit) - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - zret: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - done_one: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) - llvmlite.build_store(builder, zret, ret_ptr) - llvmlite.build_store(builder, done_one, done_ptr) - llvmlite.build_br(builder, exit_bb) - - # exit 块:load done 返回(0=SUSPEND 1=DONE) - llvmlite.position_at_end(builder, exit_bb) - done_val: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i32_ty, done_ptr) - llvmlite.build_ret(builder, done_val) - return 0 - - # ============================================================ - # M2:协程体递归翻译(Return/顶层 await/If/While/嵌套 await/普通) - # ============================================================ - def _handle_segment(self, trans: HT.Translator | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - stmts: list[ast.AST | t.CPtr] | t.CPtr): - """递归翻译协程体语句。builder 当前块 = 活跃执行块(state0 或某恢复块)。""" - if stmts is None: - return - bn: t.CSizeT = len(stmts) - i: t.CSizeT = 0 - for i in range(bn): - stmt: ast.AST | t.CPtr = stmts.get(i) - if stmt is None: - continue - # 当前块已终止(return/挂起后无后续)→ 停止本段 - if llvmlite.builder_cur_block_is_terminated(builder) != 0: - return - sk: int = stmt.kind() - if sk == ast.ASTKind.Return: - self._emit_coro_return(builder, pool, mod, trans, stmt) - continue - if sk == ast.ASTKind.If: - self._handle_coro_if(trans, builder, pool, mod, stmt) - continue - if sk == ast.ASTKind.While: - self._handle_coro_while(trans, builder, pool, mod, stmt) - continue - if sk == ast.ASTKind.Raise: - self._handle_coro_raise(builder, pool, mod, trans, stmt) - continue - if sk == ast.ASTKind.Try: - tr_: ast.Try | t.CPtr = (ast.Try | t.CPtr)(stmt) - has_fin: int = 0 - has_exc: int = 0 - if tr_.finalbody is not None and len(tr_.finalbody) > 0: - has_fin = 1 - if tr_.handlers is not None and len(tr_.handlers) > 0: - has_exc = 1 - if has_fin != 0 and has_exc == 0: - self._handle_coro_try_finally(trans, builder, pool, mod, stmt) - else: - self._handle_coro_try(trans, builder, pool, mod, stmt) - continue - if sk == ast.ASTKind.For: - if self._for_deep_await(stmt) != 0: - self._handle_coro_for(trans, builder, pool, mod, stmt) - else: - # 无 await:委托标准 For - self.Gen.StmtGen.translate_stmt(trans, stmt) - continue - if sk == ast.ASTKind.Break: - if trans._coro_break_bb is not None: - llvmlite.build_br(builder, trans._coro_break_bb) - continue - if sk == ast.ASTKind.Continue: - if trans._coro_continue_bb is not None: - llvmlite.build_br(builder, trans._coro_continue_bb) - continue - if sk == ast.ASTKind.Pass: - continue - # 顶层 await:AnnAssign/Assign/Expr 的 value 直接是 Await → 挂起 - if sk == ast.ASTKind.AnnAssign or sk == ast.ASTKind.Assign or sk == ast.ASTKind.Expr: - if self._is_await_tail(stmt) != 0: - target_name: str = self._get_assign_target_name(stmt) - if target_name is not None: - trans._coro_await_slot = self.Gen.VarGen.lookup_var( - trans.SymTab, target_name) - else: - # Expr(await ...):无目标槽(丢弃返回值),防残留旧槽 - trans._coro_await_slot = None - aw_node: ast.Await | t.CPtr = self._get_await_value(stmt) - call_name: str = None - if aw_node is not None: - call_name = self._extract_await_call_name(aw_node) - if call_name is not None and self.is_async_func(trans, call_name) != 0: - self._emit_await(builder, pool, mod, trans, aw_node, call_name) - else: - if call_name is None: - call_name = "(unknown)" - err_buf: str = pool.alloc(256) - if err_buf is not None: - viperlib.snprintf( - err_buf, 256, - "[coro-M2] await 目标 '%s' 不是 async 函数", call_name) - self.Gen.TypeGenErr.fatal_error(stmt, err_buf, "SyntaxError") - continue - # 语句内嵌套 await → 提升为 __await_N - if self._stmt_has_await(stmt) != 0: - self._handle_nested_await_stmt(trans, builder, pool, mod, stmt) - continue - # 其它语句 → 标准翻译 - self.Gen.StmtGen.translate_stmt(trans, stmt) - - # ============================================================ - # M2:协程版 If(分支内 await 就地挂起/恢复) - # ============================================================ - def _handle_coro_if(self, trans: HT.Translator | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - stmt: ast.AST | t.CPtr): - ifn: ast.If | t.CPtr = (ast.If | t.CPtr)(stmt) - if ifn is None or ifn.test is None: - return - if self._find_expr_await(ifn.test) is not None: - err_b: str = pool.alloc(256) - if err_b is not None: - viperlib.snprintf(err_b, 256, "[coro-M2] if 条件中不支持 await") - self.Gen.TypeGenErr.fatal_error(stmt, err_b, "SyntaxError") - return - cond: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, ifn.test, None, 0, trans) - if cond is None: - return - cond1: llvmlite.Value | t.CPtr = self._normalize_cond(builder, pool, cond) - func: llvmlite.Function | t.CPtr = trans._cur_func - then_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "coro.then") - merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "coro.end") - has_else: int = 0 - if ifn.orelse is not None and len(ifn.orelse) > 0: - has_else = 1 - else_bb: llvmlite.BasicBlock | t.CPtr = None - if has_else != 0: - else_bb = llvmlite.create_block(pool, func, "coro.else") - if cond1 is None or then_bb is None or merge_bb is None: - return - llvmlite.build_cond_br(builder, cond1, then_bb, - else_bb if else_bb is not None else merge_bb) - # then 分支 - llvmlite.position_at_end(builder, then_bb) - self._handle_segment(trans, builder, pool, mod, stmt.children) - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, merge_bb) - # else 分支 - if else_bb is not None: - llvmlite.position_at_end(builder, else_bb) - self._handle_segment(trans, builder, pool, mod, ifn.orelse) - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, merge_bb) - llvmlite.position_at_end(builder, merge_bb) - - # ============================================================ - # M2:协程版 While(条件块 + 循环体,body 内 await 就地挂起/恢复) - # ============================================================ - def _handle_coro_while(self, trans: HT.Translator | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - stmt: ast.AST | t.CPtr): - whn: ast.While | t.CPtr = (ast.While | t.CPtr)(stmt) - if whn is None: - return - if whn.test is not None and self._find_expr_await(whn.test) is not None: - err_c: str = pool.alloc(256) - if err_c is not None: - viperlib.snprintf(err_c, 256, "[coro-M2] while 条件中不支持 await") - self.Gen.TypeGenErr.fatal_error(stmt, err_c, "SyntaxError") - return - func: llvmlite.Function | t.CPtr = trans._cur_func - cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "coro.wcond") - body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "coro.wbody") - after_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "coro.wend") - if cond_bb is None or body_bb is None or after_bb is None: - return - # break/continue 目标(M2 单层) - prev_break: llvmlite.BasicBlock | t.CPtr = trans._coro_break_bb - prev_cont: llvmlite.BasicBlock | t.CPtr = trans._coro_continue_bb - trans._coro_break_bb = after_bb - trans._coro_continue_bb = cond_bb - llvmlite.build_br(builder, cond_bb) - # 条件块 - llvmlite.position_at_end(builder, cond_bb) - cond: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, whn.test, None, 0, trans) - if cond is None: - cond = llvmlite.const_int32(pool, 0) - cond1: llvmlite.Value | t.CPtr = self._normalize_cond(builder, pool, cond) - llvmlite.build_cond_br(builder, cond1, body_bb, after_bb) - # 循环体 - llvmlite.position_at_end(builder, body_bb) - self._handle_segment(trans, builder, pool, mod, stmt.children) - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, cond_bb) - trans._coro_break_bb = prev_break - trans._coro_continue_bb = prev_cont - # 循环结束块 - llvmlite.position_at_end(builder, after_bb) - - # ============================================================ - # M2:嵌套 await 提升:a = b + await f() → __await_N = await f(); a = b + __await_N - # ============================================================ - def _handle_nested_await_stmt(self, trans: HT.Translator | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - stmt: ast.AST | t.CPtr): - """把语句中所有嵌套 await 提升为顶层临时赋值(与预扫描 DFS 顺序一致)""" - guard: int = 0 - while True: - aw_node: ast.Await | t.CPtr = self._extract_first_await(stmt) - if aw_node is None: - break - if guard >= HT.MAX_CORO_VARS: - break - guard = guard + 1 - temp_name: str = pool.alloc(32) - if temp_name is not None: - viperlib.snprintf( - temp_name, 32, "__await_%d", trans._coro_hoist_count) - # 目标槽 = __await_N 帧额外槽(预扫描位置数组,wake/for 槽穿插在前) - slot_idx: int = trans._coro_extra_base + trans._coro_await_slots[trans._coro_hoist_count] - trans._coro_hoist_count = trans._coro_hoist_count + 1 - slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, self._lookup_coro_frame_by_trans(trans), - llvmlite.Int32(pool), trans._coro_frame, slot_idx) - trans._coro_await_slot = slot - call_name: str = self._extract_await_call_name(aw_node) - if call_name is None: - break - self._emit_await(builder, pool, mod, trans, aw_node, call_name) - self._replace_await_with_name(pool, stmt, temp_name) - # 提升完成 → 标准翻译(恢复块内继续执行剩余表达式) - self.Gen.StmtGen.translate_stmt(trans, stmt) - - # ============================================================ - # 嵌套 await 存在性 / 提取 / 替换(DFS 与预扫描同序) - # ============================================================ - def _stmt_has_await(self, stmt: ast.AST | t.CPtr) -> int: - aw: ast.Await | t.CPtr = self._extract_first_await(stmt) - if aw is not None: - return 1 - return 0 - - def _extract_first_await(self, stmt: ast.AST | t.CPtr) -> ast.Await | t.CPtr: - """取语句中第一个 Await 节点(DFS 字段序),未命中返回 None""" - if stmt is None: - return None - sk: int = stmt.kind() - if sk == ast.ASTKind.AnnAssign: - aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) - return self._find_expr_await(aa.value) - if sk == ast.ASTKind.Assign: - as_: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) - return self._find_expr_await(as_.value) - if sk == ast.ASTKind.Expr: - e: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(stmt) - return self._find_expr_await(e.value) - if sk == ast.ASTKind.Return: - rv: ast.Return | t.CPtr = (ast.Return | t.CPtr)(stmt) - return self._find_expr_await(rv.value) - return None - - def _find_expr_await(self, node: ast.AST | t.CPtr) -> ast.Await | t.CPtr: - """表达式树中 DFS 找第一个 Await""" - if node is None: - return None - k: int = node.kind() - if k == ast.ASTKind.Await: - return (ast.Await | t.CPtr)(node) - if k == ast.ASTKind.BinOp: - b: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - r: ast.Await | t.CPtr = self._find_expr_await(b.left) - if r is not None: - return r - return self._find_expr_await(b.right) - if k == ast.ASTKind.Call: - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) - if cl.func is not None: - r2: ast.Await | t.CPtr = self._find_expr_await(cl.func) - if r2 is not None: - return r2 - if cl.args is not None: - nb: t.CSizeT = len(cl.args) - j: t.CSizeT = 0 - for j in range(nb): - r3: ast.Await | t.CPtr = self._find_expr_await(cl.args.get(j)) - if r3 is not None: - return r3 - return None - if k == ast.ASTKind.UnaryOp: - u: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) - return self._find_expr_await(u.operand) - if k == ast.ASTKind.Compare: - cm: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) - r4: ast.Await | t.CPtr = self._find_expr_await(cm.left) - if r4 is not None: - return r4 - if cm.comparators is not None: - nb2: t.CSizeT = len(cm.comparators) - j2: t.CSizeT = 0 - for j2 in range(nb2): - r5: ast.Await | t.CPtr = self._find_expr_await(cm.comparators.get(j2)) - if r5 is not None: - return r5 - return None - if k == ast.ASTKind.BoolOp: - bo: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) - if bo.values is not None: - nb3: t.CSizeT = len(bo.values) - j3: t.CSizeT = 0 - for j3 in range(nb3): - r6: ast.Await | t.CPtr = self._find_expr_await(bo.values.get(j3)) - if r6 is not None: - return r6 - return None - if k == ast.ASTKind.IfExp: - ie: ast.IfExp | t.CPtr = (ast.IfExp | t.CPtr)(node) - r7: ast.Await | t.CPtr = self._find_expr_await(ie.test) - if r7 is not None: - return r7 - r8: ast.Await | t.CPtr = self._find_expr_await(ie.body) - if r8 is not None: - return r8 - return self._find_expr_await(ie.orelse) - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - return self._find_expr_await(at.value) - if k == ast.ASTKind.Subscript: - sb: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - r9: ast.Await | t.CPtr = self._find_expr_await(sb.value) - if r9 is not None: - return r9 - return self._find_expr_await(sb.slice) - return None - - def _replace_await_with_name(self, pool: memhub.MemBuddy | t.CPtr, - stmt: ast.AST | t.CPtr, - temp_name: str) -> int: - """把语句树中第一个 Await 替换为 Name(temp_name)(DFS 字段序)""" - if stmt is None or temp_name is None: - return 0 - sk: int = stmt.kind() - if sk == ast.ASTKind.AnnAssign: - aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) - if aa.value is not None: - return self._replace_expr_await(pool, aa.value, temp_name) - return 0 - if sk == ast.ASTKind.Assign: - as_: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) - if as_.value is not None: - return self._replace_expr_await(pool, as_.value, temp_name) - return 0 - if sk == ast.ASTKind.Expr: - e: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(stmt) - if e.value is not None: - return self._replace_expr_await(pool, e.value, temp_name) - return 0 - if sk == ast.ASTKind.Return: - rv: ast.Return | t.CPtr = (ast.Return | t.CPtr)(stmt) - if rv.value is not None: - return self._replace_expr_await(pool, rv.value, temp_name) - return 0 - return 0 - - def _replace_expr_await(self, pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr, - temp_name: str) -> int: - """在表达式树中把第一个 Await 替换为 Name(temp_name, Load)。 - node 本身是 Await 时返回 2(由父字段替换)。返回 1=已替换 0=无 2=node 即 Await。""" - if node is None: - return 0 - k: int = node.kind() - if k == ast.ASTKind.Await: - return 2 - if k == ast.ASTKind.BinOp: - b: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - r: int = self._replace_expr_await(pool, b.left, temp_name) - if r == 1: - return 1 - if r == 2: - b.left = ast.Name(pool, temp_name, 0) - return 1 - r2: int = self._replace_expr_await(pool, b.right, temp_name) - if r2 == 1: - return 1 - if r2 == 2: - b.right = ast.Name(pool, temp_name, 0) - return 1 - return 0 - if k == ast.ASTKind.Call: - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) - if cl.func is not None: - r3: int = self._replace_expr_await(pool, cl.func, temp_name) - if r3 == 1: - return 1 - if r3 == 2: - cl.func = ast.Name(pool, temp_name, 0) - return 1 - if cl.args is not None: - nb: t.CSizeT = len(cl.args) - j: t.CSizeT = 0 - for j in range(nb): - r4: int = self._replace_expr_await(pool, cl.args.get(j), temp_name) - if r4 == 1: - return 1 - if r4 == 2: - cl.args.set(j, ast.Name(pool, temp_name, 0)) - return 1 - return 0 - if k == ast.ASTKind.UnaryOp: - u: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) - r5: int = self._replace_expr_await(pool, u.operand, temp_name) - if r5 == 1: - return 1 - if r5 == 2: - u.operand = ast.Name(pool, temp_name, 0) - return 1 - return 0 - if k == ast.ASTKind.Compare: - cm: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) - r6: int = self._replace_expr_await(pool, cm.left, temp_name) - if r6 == 1: - return 1 - if r6 == 2: - cm.left = ast.Name(pool, temp_name, 0) - return 1 - if cm.comparators is not None: - nb2: t.CSizeT = len(cm.comparators) - j2: t.CSizeT = 0 - for j2 in range(nb2): - r7: int = self._replace_expr_await(pool, cm.comparators.get(j2), temp_name) - if r7 == 1: - return 1 - if r7 == 2: - cm.comparators.set(j2, ast.Name(pool, temp_name, 0)) - return 1 - return 0 - if k == ast.ASTKind.BoolOp: - bo: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) - if bo.values is not None: - nb3: t.CSizeT = len(bo.values) - j3: t.CSizeT = 0 - for j3 in range(nb3): - r8: int = self._replace_expr_await(pool, bo.values.get(j3), temp_name) - if r8 == 1: - return 1 - if r8 == 2: - bo.values.set(j3, ast.Name(pool, temp_name, 0)) - return 1 - return 0 - if k == ast.ASTKind.IfExp: - ie: ast.IfExp | t.CPtr = (ast.IfExp | t.CPtr)(node) - r9: int = self._replace_expr_await(pool, ie.test, temp_name) - if r9 == 1: - return 1 - if r9 == 2: - ie.test = ast.Name(pool, temp_name, 0) - return 1 - r10: int = self._replace_expr_await(pool, ie.body, temp_name) - if r10 == 1: - return 1 - if r10 == 2: - ie.body = ast.Name(pool, temp_name, 0) - return 1 - r11: int = self._replace_expr_await(pool, ie.orelse, temp_name) - if r11 == 1: - return 1 - if r11 == 2: - ie.orelse = ast.Name(pool, temp_name, 0) - return 1 - return 0 - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - r12: int = self._replace_expr_await(pool, at.value, temp_name) - if r12 == 1: - return 1 - if r12 == 2: - at.value = ast.Name(pool, temp_name, 0) - return 1 - return 0 - if k == ast.ASTKind.Subscript: - sb: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - r13: int = self._replace_expr_await(pool, sb.value, temp_name) - if r13 == 1: - return 1 - if r13 == 2: - sb.value = ast.Name(pool, temp_name, 0) - return 1 - r14: int = self._replace_expr_await(pool, sb.slice, temp_name) - if r14 == 1: - return 1 - if r14 == 2: - sb.slice = ast.Name(pool, temp_name, 0) - return 1 - return 0 - return 0 - - # ============================================================ - # 条件归一化(i1 直通;其余 icmp ne 0) - # ============================================================ - def _normalize_cond(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - cond: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: - if cond is None: - return None - ty: llvmlite.LLVMType | t.CPtr = cond.Ty - is_i1: int = 0 - if ty is not None: - match ty: - case LLVMType.Int(): - if ty.Bits == 1: - is_i1 = 1 - case _: - pass - if is_i1 != 0: - return cond - zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, ty) - return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond, zero) - - # ============================================================ - # 参数名读取(_coro_params 表) - # ============================================================ - def _read_param_name(self, trans: HT.Translator | t.CPtr, - idx: int) -> str: - if trans is None or trans._coro_params is None: - return None - addr: t.CUInt64T = t.CUInt64T(trans._coro_params) + idx * 8 - slot: str | t.CPtr = (t.CVoid | t.CPtr)(addr) - return slot[0] - - # ============================================================ - # 恢复块定位(state{N},预建数组) - # ============================================================ - def _get_state_bb(self, trans: HT.Translator | t.CPtr, - state_no: int) -> llvmlite.BasicBlock | t.CPtr: - if trans is None or trans._coro_state_bbs is None: - return None - if state_no < 0 or state_no >= trans._coro_nseg: - return None - # 注意:state_bbs 数组存的是块指针(t.CSizeT),必须下标取值, - # 不能取元素地址(t.CUInt64T(数组)+idx*8 是地址,会导致 position - # 到非法块 → IR 指令链损坏 → RenumberSSA/FunctionPrint 崩溃)。 - return (llvmlite.BasicBlock | t.CPtr)( - t.CVoid(trans._coro_state_bbs[state_no], t.CPtr)) - - def _lookup_coro_frame_by_trans(self, trans: HT.Translator | t.CPtr) -> llvmlite.LLVMType | t.CPtr: - """取当前 resume 的帧类型:从 _coro_frames 反查(当前 async 名未知时用帧指针类型不可行, - 直接返回当前协程注册的帧类型——_handle_nested_await_stmt 需要帧类型做 GEP。""" - # 简化:恢复块 GEP 需要帧类型;从 _coro_frame 的 Ty(Ptr(帧))取 Pointee - if trans is None or trans._coro_frame is None: - return None - ft: llvmlite.LLVMType | t.CPtr = trans._coro_frame.Ty - if ft is None: - return None - match ft: - case LLVMType.Ptr(): - return ft.Pointee - case _: - return None - - # ============================================================ - # M3:await coro_sleep(ms) —— wake 槽挂起(coro_run 轮询续跑) - # ============================================================ - def _emit_await_sleep(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> llvmlite.Value | t.CPtr: - """await coro_sleep(ms):wake = GetTickCount64() + ms 存帧 wake 槽, - 父挂起(state 分配 + br exit + position 恢复块);coro_run 轮询续跑。""" - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if node is None or trans is None or trans._coro_wake_ptr is None: - return llvmlite.const_int32(pool, 0) - ms_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) - aw_s: ast.Await | t.CPtr = (ast.Await | t.CPtr)(node) - if aw_s.value is not None and aw_s.value.kind() == ast.ASTKind.Call: - cl_s: ast.Call | t.CPtr = (ast.Call | t.CPtr)(aw_s.value) - if cl_s.args is not None and len(cl_s.args) > 0: - ms_v: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, cl_s.args.get(0), None, 0, trans) - if ms_v is not None: - ms_val = ms_v - # GetTickCount64() + ms(i64) - now_fn: llvmlite.Function | t.CPtr = self.Gen.CallGenBase.find_func_in_module( - mod, "GetTickCount64") - if now_fn is None: - now_fn = llvmlite.create_declare(pool, mod, "GetTickCount64", i64_ty) - if now_fn is None: - return llvmlite.const_int32(pool, 0) - now_val: llvmlite.Value | t.CPtr = llvmlite.build_call( - builder, "GetTickCount64", None, 0, i64_ty, 0) - if now_val is None: - return llvmlite.const_int32(pool, 0) - wake_val: llvmlite.Value | t.CPtr = llvmlite.build_add( - builder, now_val, ms_val) - if wake_val is None: - return llvmlite.const_int32(pool, 0) - llvmlite.build_store(builder, wake_val, trans._coro_wake_ptr) - # 父挂起:新状态号 + br exit + position 恢复块 - new_state_s: int = trans._coro_next_state - trans._coro_next_state = new_state_s + 1 - st_v_s: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, new_state_s) - llvmlite.build_store(builder, st_v_s, trans._coro_state_ptr) - llvmlite.build_br(builder, trans._coro_exit_bb) - resume_bb_s: llvmlite.BasicBlock | t.CPtr = self._get_state_bb( - trans, new_state_s) - if resume_bb_s is not None: - llvmlite.position_at_end(builder, resume_bb_s) - return llvmlite.const_int32(pool, 0) - - # ============================================================ - # M4-M6:协程内 raise(异常类型/值 → 帧 exc 槽) - # ============================================================ - def _handle_coro_raise(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - trans: HT.Translator | t.CPtr, - stmt: ast.AST | t.CPtr): - """协程内 raise:解析异常类型/值 → 帧 exc 槽(+msg); - try 栈非空跳 except 处理器,否则 done=1 + br exit 终止。""" - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - exc_code: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) - rz: ast.Raise | t.CPtr = (ast.Raise | t.CPtr)(stmt) - if rz is not None and rz.exc is not None: - code: int = self._resolve_raise_code(pool, rz.exc) - if code != 0: - exc_code = llvmlite.const_int32(pool, code) - # M7:异常消息(Exception("msg") 首参) - msg_v: llvmlite.Value | t.CPtr = self._resolve_raise_msg( - builder, pool, mod, trans, rz.exc) - if msg_v is not None and trans._coro_msg_ptr is not None: - llvmlite.build_store(builder, msg_v, trans._coro_msg_ptr) - else: - v: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, rz.exc, None, 0, trans) - if v is not None: - exc_code = v - if trans._coro_exc_ptr is not None: - llvmlite.build_store(builder, exc_code, trans._coro_exc_ptr) - # 跳 try except / 终止 - if trans._coro_try_stack_count > 0: - tbb_r: llvmlite.BasicBlock | t.CPtr = ( - llvmlite.BasicBlock | t.CPtr)(t.CVoid( - trans._coro_try_stack[trans._coro_try_stack_count - 1], - t.CPtr)) - llvmlite.build_br(builder, tbb_r) - else: - done_r: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) - llvmlite.build_store(builder, done_r, trans._coro_done_ptr) - llvmlite.build_br(builder, trans._coro_exit_bb) - - def _resolve_raise_code(self, pool: memhub.MemBuddy | t.CPtr, - exc_node: ast.AST | t.CPtr) -> int: - """解析 raise 目标的异常码(内置/用户异常类名);非异常类返回 0""" - if exc_node is None: - return 0 - name: str = None - if exc_node.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(exc_node) - name = nm.id - elif exc_node.kind() == ast.ASTKind.Call: - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(exc_node) - if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: - nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl.func) - name = nm2.id - elif exc_node.kind() == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(exc_node) - name = at.attr - if name is None: - return 0 - return self.Gen.ClassGenBase.lookup_exception_code(name) - - def _resolve_raise_msg(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - trans: HT.Translator | t.CPtr, - exc_node: ast.AST | t.CPtr) -> llvmlite.Value | t.CPtr: - """取异常消息表达式(Exception("msg") 首参),无则返回 None""" - if exc_node is None or exc_node.kind() != ast.ASTKind.Call: - return None - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(exc_node) - if cl.args is None or len(cl.args) < 1: - return None - return self.Gen.ExprGen.translate_value( - builder, pool, mod, cl.args.get(0), None, 0, trans) - - # ============================================================ - # M5-M6:协程内 try/except(多 except 链式匹配 + 类型码 + as e 绑定) - # ============================================================ - def _handle_coro_try(self, trans: HT.Translator | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - stmt: ast.AST | t.CPtr): - """协程内 try/except:raise/await 传播异常在 try 栈内改跳 except 处理器; - 多 except 按声明序匹配(含子类码集合),Exception/裸 except 捕获所有; - 全不匹配重新传播(done=1 + br exit)。""" - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - tr: ast.Try | t.CPtr = (ast.Try | t.CPtr)(stmt) - if tr is None: - return - nhandlers: int = 0 - if tr.handlers is not None: - nhandlers = len(tr.handlers) - if nhandlers == 0: - err_t: str = pool.alloc(256) - if err_t is not None: - viperlib.snprintf(err_t, 256, "[coro-M6] 协程内 try 需要 except 子句") - self.Gen.TypeGenErr.fatal_error(stmt, err_t, "SyntaxError") - return - func: llvmlite.Function | t.CPtr = trans._cur_func - except_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "coro.try_except") - merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "coro.try_merge") - if except_bb is None or merge_bb is None: - return - # try 栈 push - if trans._coro_try_stack_count < HT.MAX_CORO_TRY: - trans._coro_try_stack[trans._coro_try_stack_count] = t.CSizeT(except_bb) - trans._coro_try_stack_count = trans._coro_try_stack_count + 1 - # try body - self._handle_segment(trans, builder, pool, mod, stmt.children) - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, merge_bb) - if trans._coro_try_stack_count > 0: - trans._coro_try_stack_count = trans._coro_try_stack_count - 1 - # ---- 异常分发:exc 码依次匹配各 except ---- - llvmlite.position_at_end(builder, except_bb) - exc_val: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i32_ty, trans._coro_exc_ptr) - # 预建 check/handler/unmatched 块 - check_bbs: t.CSizeT | t.CPtr = pool.alloc((nhandlers + 1) * 8) - handler_bbs: t.CSizeT | t.CPtr = pool.alloc(nhandlers * 8) - if check_bbs is None or handler_bbs is None: - return - check_bbs[0] = t.CSizeT(except_bb) - hi: int = 0 - for hi in range(nhandlers): - check_bbs[hi + 1] = t.CSizeT(llvmlite.create_block( - pool, func, "coro.exc_check_%d" % hi)) - handler_bbs[hi] = t.CSizeT(llvmlite.create_block( - pool, func, "coro.except_%d" % hi)) - unmatched_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "coro.try_reraise") - codes_buf: t.CInt | t.CPtr = pool.alloc(256) - # 每个 handler:check 链 - for hi in range(nhandlers): - h_node: ast.AST | t.CPtr = tr.handlers.get(hi) - check_bb: llvmlite.BasicBlock | t.CPtr = ( - llvmlite.BasicBlock | t.CPtr)(t.CVoid(check_bbs[hi], t.CPtr)) - llvmlite.position_at_end(builder, check_bb) - catch_all: int = 0 - ncodes: int = 0 - if h_node is not None: - hd: ast.ExceptHandler | t.CPtr = (ast.ExceptHandler | t.CPtr)(h_node) - if hd.type is None: - catch_all = 1 - else: - ename: str = self._exception_type_name(pool, hd.type) - if ename is not None and string.strcmp(ename, "Exception") == 0: - catch_all = 1 - else: - ncodes = self.Gen.ClassGenBase.collect_descendant_codes( - ename, codes_buf, 64) - next_check: llvmlite.BasicBlock | t.CPtr = None - if hi + 1 < nhandlers: - next_check = (llvmlite.BasicBlock | t.CPtr)( - t.CVoid(check_bbs[hi + 1], t.CPtr)) - else: - next_check = unmatched_bb - handler_bb: llvmlite.BasicBlock | t.CPtr = ( - llvmlite.BasicBlock | t.CPtr)(t.CVoid(handler_bbs[hi], t.CPtr)) - if catch_all != 0: - llvmlite.build_br(builder, handler_bb) - else: - match_cond: llvmlite.Value | t.CPtr = None - ci: int = 0 - for ci in range(ncodes): - eq_v: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_EQ, exc_val, - llvmlite.const_int32(pool, codes_buf[ci])) - if match_cond is None: - match_cond = eq_v - else: - match_cond = llvmlite.build_or(builder, match_cond, eq_v) - if match_cond is None: - llvmlite.build_br(builder, next_check) - else: - llvmlite.build_cond_br(builder, match_cond, handler_bb, next_check) - # 未匹配:异常继续传播(重新终止协程) - llvmlite.position_at_end(builder, unmatched_bb) - done_u: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) - llvmlite.build_store(builder, done_u, trans._coro_done_ptr) - llvmlite.build_br(builder, trans._coro_exit_bb) - # ---- 各 except handler ---- - for hi in range(nhandlers): - h_node2: ast.AST | t.CPtr = tr.handlers.get(hi) - handler_bb2: llvmlite.BasicBlock | t.CPtr = ( - llvmlite.BasicBlock | t.CPtr)(t.CVoid(handler_bbs[hi], t.CPtr)) - llvmlite.position_at_end(builder, handler_bb2) - if h_node2 is not None: - hd2: ast.ExceptHandler | t.CPtr = (ast.ExceptHandler | t.CPtr)(h_node2) - # as e:异常码绑定 e 槽(e 是局部槽,_collect_local_names 收集) - if hd2.name is not None and trans._coro_exc_ptr is not None: - e_slot: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( - trans.SymTab, hd2.name) - if e_slot is not None: - hv: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i32_ty, trans._coro_exc_ptr) - llvmlite.build_store(builder, hv, e_slot) - # 捕获后清帧 exc - z_clr: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - llvmlite.build_store(builder, z_clr, trans._coro_exc_ptr) - self._handle_segment(trans, builder, pool, mod, h_node2.children) - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, merge_bb) - llvmlite.position_at_end(builder, merge_bb) - - def _exception_type_name(self, pool: memhub.MemBuddy | t.CPtr, - type_node: ast.AST | t.CPtr) -> str: - """取 except 类型名(Name/Attribute),未命中返回 None""" - if type_node is None: - return None - if type_node.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(type_node) - return nm.id - if type_node.kind() == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(type_node) - return at.attr - return None - - # ============================================================ - # M7:协程内 try/finally(无 except) - # ============================================================ - def _handle_coro_try_finally(self, trans: HT.Translator | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - stmt: ast.AST | t.CPtr): - """协程内 try/finally:正常/异常路径都执行 fbody; - 异常时 finally 后重新传播(done=1 + br exit);finally 内不支持 await。""" - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - tr: ast.Try | t.CPtr = (ast.Try | t.CPtr)(stmt) - if tr is None: - return - if tr.finalbody is not None and self._stmts_deep_await(tr.finalbody) != 0: - err_f: str = pool.alloc(256) - if err_f is not None: - viperlib.snprintf(err_f, 256, "[coro-M7] finally 内暂不支持 await") - self.Gen.TypeGenErr.fatal_error(stmt, err_f, "SyntaxError") - return - func: llvmlite.Function | t.CPtr = trans._cur_func - fin_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "coro.fin") - fin_exc_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "coro.fin_exc") - merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "coro.fin_merge") - if fin_bb is None or fin_exc_bb is None or merge_bb is None: - return - # try 栈 push(异常跳 finally) - if trans._coro_try_stack_count < HT.MAX_CORO_TRY: - trans._coro_try_stack[trans._coro_try_stack_count] = t.CSizeT(fin_bb) - trans._coro_try_stack_count = trans._coro_try_stack_count + 1 - self._handle_segment(trans, builder, pool, mod, stmt.children) - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, fin_bb) - if trans._coro_try_stack_count > 0: - trans._coro_try_stack_count = trans._coro_try_stack_count - 1 - # fin_bb:记录异常标志 + 执行 fbody - llvmlite.position_at_end(builder, fin_bb) - was_exc: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, - llvmlite.build_load(builder, i32_ty, trans._coro_exc_ptr), - llvmlite.const_int32(pool, 0)) - self._handle_segment(trans, builder, pool, mod, tr.finalbody) - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_cond_br(builder, was_exc, fin_exc_bb, merge_bb) - # fin_exc:finally 后异常继续传播 - llvmlite.position_at_end(builder, fin_exc_bb) - done_f: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) - llvmlite.build_store(builder, done_f, trans._coro_done_ptr) - llvmlite.build_br(builder, trans._coro_exit_bb) - llvmlite.position_at_end(builder, merge_bb) - - # ============================================================ - # M3:协程内 range-For(含 await)变换为 While(__f_idx/__f_len 帧槽) - # ============================================================ - def _handle_coro_for(self, trans: HT.Translator | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - stmt: ast.AST | t.CPtr): - """range-For(含 await):__f_idx_N = start; __f_len_N = end; - while __f_idx_N < __f_len_N: target = __f_idx_N; ; __f_idx_N += 1""" - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if self._is_range_for(stmt) == 0: - err_g: str = pool.alloc(256) - if err_g is not None: - viperlib.snprintf(err_g, 256, "[coro-M3] 协程内 For 仅支持 range 迭代(含 await)") - self.Gen.TypeGenErr.fatal_error(stmt, err_g, "SyntaxError") - return - fn: ast.For | t.CPtr = (ast.For | t.CPtr)(stmt) - k: int = trans._coro_for_counter - trans._coro_for_counter = k + 1 - idx_idx: int = trans._coro_extra_base + trans._coro_for_slots[k] - len_idx: int = idx_idx + 1 - idx_slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, self._lookup_coro_frame_by_trans(trans), - i32_ty, trans._coro_frame, idx_idx) - len_slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, self._lookup_coro_frame_by_trans(trans), - i32_ty, trans._coro_frame, len_idx) - if idx_slot is None or len_slot is None: - return - # start/end(range 1/2 参数) - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fn.iter) - start_val: llvmlite.Value | t.CPtr = None - end_val: llvmlite.Value | t.CPtr = None - nargs: int = len(cl.args) - if nargs == 1: - start_val = llvmlite.const_int32(pool, 0) - end_val = self.Gen.ExprGen.translate_value( - builder, pool, mod, cl.args.get(0), None, 0, trans) - else: - start_val = self.Gen.ExprGen.translate_value( - builder, pool, mod, cl.args.get(0), None, 0, trans) - end_val = self.Gen.ExprGen.translate_value( - builder, pool, mod, cl.args.get(1), None, 0, trans) - if start_val is None: - start_val = llvmlite.const_int32(pool, 0) - if end_val is None: - end_val = llvmlite.const_int32(pool, 0) - llvmlite.build_store(builder, start_val, idx_slot) - llvmlite.build_store(builder, end_val, len_slot) - # 循环结构 - func: llvmlite.Function | t.CPtr = trans._cur_func - cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "coro.fcond") - body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "coro.fbody") - after_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "coro.fend") - if cond_bb is None or body_bb is None or after_bb is None: - return - prev_break: llvmlite.BasicBlock | t.CPtr = trans._coro_break_bb - prev_cont: llvmlite.BasicBlock | t.CPtr = trans._coro_continue_bb - trans._coro_break_bb = after_bb - trans._coro_continue_bb = cond_bb - llvmlite.build_br(builder, cond_bb) - # 条件块 - llvmlite.position_at_end(builder, cond_bb) - idx_v: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i32_ty, idx_slot) - len_v: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i32_ty, len_slot) - cmp_v: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_SLT, idx_v, len_v) - llvmlite.build_cond_br(builder, cmp_v, body_bb, after_bb) - # 循环体:target = idx; ; idx += 1 - llvmlite.position_at_end(builder, body_bb) - if fn.target is not None and fn.target.kind() == ast.ASTKind.Name: - tn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(fn.target) - tgt_slot: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( - trans.SymTab, tn.id) - if tgt_slot is not None: - idx_v2: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i32_ty, idx_slot) - llvmlite.build_store(builder, idx_v2, tgt_slot) - self._handle_segment(trans, builder, pool, mod, stmt.children) - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - idx_v3: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i32_ty, idx_slot) - one_v: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) - nxt_v: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, idx_v3, one_v) - llvmlite.build_store(builder, nxt_v, idx_slot) - llvmlite.build_br(builder, cond_bb) - trans._coro_break_bb = prev_break - trans._coro_continue_bb = prev_cont - llvmlite.position_at_end(builder, after_bb) - - # ============================================================ - # M3/M4/M7:coro.coro_destroy / coro_exception / coro_exception_msg / coro_gather - # ============================================================ - def translate_coro_destroy(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """coro.coro_destroy(帧):帧回池(free-list,帧首 8 字节存 next)""" - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - if cl is None or trans is None or cl.args is None or len(cl.args) < 1: - return llvmlite.const_int32(pool, 0) - async_name: str = self._var_to_async(trans, cl.args.get(0)) - if async_name is None: - return llvmlite.const_int32(pool, 0) - frame_ty: llvmlite.LLVMType | t.CPtr = self._lookup_coro_frame( - trans, async_name) - if frame_ty is None: - return llvmlite.const_int32(pool, 0) - frame_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, frame_ty) - frame_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, cl.args.get(0), None, 0, trans) - if frame_val is None: - return llvmlite.const_int32(pool, 0) - frame_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, frame_val, frame_ptr_ty) - if frame_ptr is None: - return llvmlite.const_int32(pool, 0) - # 回池:帧首 8 字节存旧池头;池头 = 本帧(i64) - pool_gv: llvmlite.GlobalVariable | t.CPtr = self._get_coro_pool( - pool, mod, trans, async_name) - # GlobalVariable 非 Value 子类:构造 Value 视图(Ty=Ptr(i64), Name="@coro_pool_") - i64_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i64_ty) - pool_ref_name: str = pool.alloc(96) - if pool_ref_name is not None: - viperlib.snprintf(pool_ref_name, 96, "@coro_pool_%s", async_name) - pool_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, i64_ptr_ty, pool_ref_name) - pool_head: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i64_ty, pool_ref) - node_next: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, frame_ptr, i64_ptr_ty) - llvmlite.build_store(builder, pool_head, node_next) - frame_i64: llvmlite.Value | t.CPtr = llvmlite.build_ptrtoint( - builder, frame_ptr, i64_ty) - llvmlite.build_store(builder, frame_i64, pool_ref) - return llvmlite.const_int32(pool, 0) - - def translate_coro_exception(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """coro.coro_exception(帧):返回帧 exc 槽(异常码,0=无异常)""" - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if cl is None or trans is None or cl.args is None or len(cl.args) < 1: - return llvmlite.const_int32(pool, 0) - async_name: str = self._var_to_async(trans, cl.args.get(0)) - if async_name is None: - return llvmlite.const_int32(pool, 0) - frame_ty: llvmlite.LLVMType | t.CPtr = self._lookup_coro_frame( - trans, async_name) - if frame_ty is None: - return llvmlite.const_int32(pool, 0) - frame_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, frame_ty) - frame_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, cl.args.get(0), None, 0, trans) - if frame_val is None: - return llvmlite.const_int32(pool, 0) - frame_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, frame_val, frame_ptr_ty) - if frame_ptr is None: - return llvmlite.const_int32(pool, 0) - exc_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, frame_ty, i32_ty, frame_ptr, 3) - return llvmlite.build_load(builder, i32_ty, exc_ptr) - - def translate_coro_exception_msg(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """coro.coro_exception_msg(帧):返回帧 msg 槽(异常消息指针,null=无)""" - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - if cl is None or trans is None or cl.args is None or len(cl.args) < 1: - return llvmlite.ConstNull(pool, i8_ptr_ty, "null") - async_name: str = self._var_to_async(trans, cl.args.get(0)) - if async_name is None: - return llvmlite.ConstNull(pool, i8_ptr_ty, "null") - frame_ty: llvmlite.LLVMType | t.CPtr = self._lookup_coro_frame( - trans, async_name) - if frame_ty is None: - return llvmlite.ConstNull(pool, i8_ptr_ty, "null") - frame_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, frame_ty) - frame_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, cl.args.get(0), None, 0, trans) - if frame_val is None: - return llvmlite.ConstNull(pool, i8_ptr_ty, "null") - frame_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, frame_val, frame_ptr_ty) - if frame_ptr is None: - return llvmlite.ConstNull(pool, i8_ptr_ty, "null") - msg_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, frame_ty, i8_ptr_ty, frame_ptr, 4) - return llvmlite.build_load(builder, i8_ptr_ty, msg_ptr) - - def translate_coro_gather(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """coro.coro_gather(帧...):并发推进全部协程到完成,返回完成数(M4 纯 resume 循环)""" - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if cl is None or trans is None or cl.args is None: - return llvmlite.const_int32(pool, 0) - nb: t.CSizeT = len(cl.args) - j: t.CSizeT = 0 - for j in range(nb): - arg0: ast.AST | t.CPtr = cl.args.get(j) - async_name: str = self._var_to_async(trans, arg0) - if async_name is None: - continue - frame_ty: llvmlite.LLVMType | t.CPtr = self._lookup_coro_frame( - trans, async_name) - if frame_ty is None: - continue - frame_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, frame_ty) - frame_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, arg0, None, 0, trans) - if frame_val is None: - continue - frame_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, frame_val, frame_ptr_ty) - if frame_ptr is None: - continue - rn_buf: str = pool.alloc(64) - if rn_buf is not None: - viperlib.snprintf(rn_buf, 64, "resume_%s", async_name) - resume_mangled: str = self.Gen.FuncGenBase._mangle_func_name( - trans, rn_buf, 0) - if self.Gen.CallGenBase.find_func_in_module(mod, resume_mangled) is None: - continue - func: llvmlite.Function | t.CPtr = trans._cur_func - loop_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "gather.loop") - after_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "gather.after") - if loop_bb is None or after_bb is None: - continue - llvmlite.build_br(builder, loop_bb) - llvmlite.position_at_end(builder, loop_bb) - frame_ptr.Next = None - status: llvmlite.Value | t.CPtr = llvmlite.build_call( - builder, resume_mangled, frame_ptr, 1, i32_ty, 0) - done_cond: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, status, llvmlite.const_int32(pool, 0)) - llvmlite.build_cond_br(builder, done_cond, after_bb, loop_bb) - llvmlite.position_at_end(builder, after_bb) - return llvmlite.const_int32(pool, 0) - - def _var_to_async(self, trans: HT.Translator | t.CPtr, - arg0: ast.AST | t.CPtr) -> str: - """变量节点 → async 函数名(_coro_var_async 反查),未命中返回 None""" - if trans is None or arg0 is None or arg0.kind() != ast.ASTKind.Name: - return None - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0) - if nm.id is None: - return None - return self._lookup_coro_var(trans, nm.id) - - # ============================================================ - # await 表达式翻译(顶层段尾 / translate_value Await 分支共用) - # ============================================================ - def _emit_await(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr, - call_name: str) -> llvmlite.Value | t.CPtr: - """await async_fn(args...) 内联翻译(M2 带参数): - 1. 求值调用参数(表达式逐个翻译,i32) - 2. create_(args...) 创建子帧 - 3. resume_(child) 推进到 DONE - 4. 子帧 ret 槽 GEP [0,2] load → store 到父帧 await 槽(若非 None) - 5. 父挂起:store state=新状态号 + br exit;恢复块 state{new_state} - 立即 position(预建 case 块),后续语句在恢复块继续翻译 - 返回子协程 ret 值(i32)。注意 node 是 Await,须先转 ast.Await 再取 value。""" - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i8_ptr_ty_a: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - if node is None or call_name is None or trans is None: - return llvmlite.const_int32(pool, 0) - # M3:await coro_sleep(ms) —— 挂起到 wake 时刻(帧 wake 槽) - if string.strcmp(call_name, "coro_sleep") == 0: - return self._emit_await_sleep(builder, pool, mod, trans, node) - child_frame_ty: llvmlite.LLVMType | t.CPtr = self._lookup_coro_frame( - trans, call_name) - if child_frame_ty is None: - return llvmlite.const_int32(pool, 0) - child_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, child_frame_ty) - - cc_buf: str = pool.alloc(64) - if cc_buf is not None: - viperlib.snprintf(cc_buf, 64, "create_%s", call_name) - create_mangled: str = self.Gen.FuncGenBase._mangle_func_name( - trans, cc_buf, 0) - rc_buf: str = pool.alloc(64) - if rc_buf is not None: - viperlib.snprintf(rc_buf, 64, "resume_%s", call_name) - resume_mangled: str = self.Gen.FuncGenBase._mangle_func_name( - trans, rc_buf, 0) - if self.Gen.CallGenBase.find_func_in_module(mod, create_mangled) is None \ - or self.Gen.CallGenBase.find_func_in_module(mod, resume_mangled) is None: - # async 函数必须定义在前(前向引用未支持),静默返回 0 - return llvmlite.const_int32(pool, 0) - - # M2:子协程调用参数(await fn(a, b) → create_fn(a, b)) - args_head: llvmlite.Value | t.CPtr = None - args_tail: llvmlite.Value | t.CPtr = None - args_count: int = 0 - aw_n: ast.Await | t.CPtr = (ast.Await | t.CPtr)(node) - if aw_n.value is not None and aw_n.value.kind() == ast.ASTKind.Call: - cl_a: ast.Call | t.CPtr = (ast.Call | t.CPtr)(aw_n.value) - if cl_a.args is not None: - nb: t.CSizeT = len(cl_a.args) - j: t.CSizeT = 0 - for j in range(nb): - av: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, cl_a.args.get(j), None, 0, trans) - if av is None: - av = llvmlite.const_int32(pool, 0) - av.Next = None - if args_head is None: - args_head = av - args_tail = av - else: - args_tail.Next = av - args_tail = av - args_count = args_count + 1 - - # 子协程 create(M2 带参数)+ resume - child: llvmlite.Value | t.CPtr = llvmlite.build_call( - builder, create_mangled, args_head, args_count, child_ptr_ty, 0) - if child is None: - return llvmlite.const_int32(pool, 0) - child.Next = None - llvmlite.build_call(builder, resume_mangled, child, 1, i32_ty, 0) - # 子帧 ret 槽 GEP [0,2] load - child_ret_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, child_frame_ty, i32_ty, child, 2) - child_ret: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i32_ty, child_ret_ptr) - # M4:子帧异常传播——子帧 exc != 0 → 父 exc/msg 槽 + 跳 try except 或终止 - child_exc_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, child_frame_ty, i32_ty, child, 3) - child_exc: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i32_ty, child_exc_ptr) - zero32_x: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - exc_ok_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, trans._cur_func, "coro.ok") - exc_bad_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, trans._cur_func, "coro.exc") - if exc_ok_bb is None or exc_bad_bb is None: - return llvmlite.const_int32(pool, 0) - exc_cond: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_EQ, child_exc, zero32_x) - llvmlite.build_cond_br(builder, exc_cond, exc_ok_bb, exc_bad_bb) - # exc 路径:父帧 exc/msg 槽 + 跳 try 或终止 - llvmlite.position_at_end(builder, exc_bad_bb) - if trans._coro_exc_ptr is not None: - llvmlite.build_store(builder, child_exc, trans._coro_exc_ptr) - if trans._coro_msg_ptr is not None: - child_msg_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, child_frame_ty, i8_ptr_ty_a, child, 4) - child_msg: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i8_ptr_ty_a, child_msg_ptr) - llvmlite.build_store(builder, child_msg, trans._coro_msg_ptr) - if trans._coro_try_stack_count > 0: - tbb: llvmlite.BasicBlock | t.CPtr = ( - llvmlite.BasicBlock | t.CPtr)(t.CVoid( - trans._coro_try_stack[trans._coro_try_stack_count - 1], - t.CPtr)) - llvmlite.build_br(builder, tbb) - else: - done_x: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) - llvmlite.build_store(builder, done_x, trans._coro_done_ptr) - llvmlite.build_br(builder, trans._coro_exit_bb) - # 正常路径:存父帧 await 槽(若非 None)+ 挂起 - llvmlite.position_at_end(builder, exc_ok_bb) - slot: llvmlite.Value | t.CPtr = trans._coro_await_slot - if slot is not None: - llvmlite.build_store(builder, child_ret, slot) - # 父挂起:新状态号(与预扫描 DFS 序一致) - new_state: int = trans._coro_next_state - trans._coro_next_state = new_state + 1 - st_v: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, new_state) - llvmlite.build_store(builder, st_v, trans._coro_state_ptr) - llvmlite.build_br(builder, trans._coro_exit_bb) - # 恢复块 state{new_state}:立即 position(预建 case 块,后续翻译在此继续) - resume_bb: llvmlite.BasicBlock | t.CPtr = self._get_state_bb( - trans, new_state) - if resume_bb is not None: - llvmlite.position_at_end(builder, resume_bb) - return child_ret - - # ============================================================ - # coro.coro_run(帧) 内联翻译 - # ============================================================ - def translate_coro_run(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """coro.coro_run(frame) 内联翻译: - 参数是 Name 变量 → 经 _coro_var_async 反查 async 名 → _coro_frames - 取帧类型 → bitcast 变量值到 Ptr(帧) → 循环 resume_(frame) 直到 - done != 0 → GEP [0,2] load ret 返回。 - M1 无 coro_sleep 轮询(无 wake 槽),纯忙等直到协程完成。 - """ - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if cl is None or trans is None: - return llvmlite.const_int32(pool, 0) - if cl.args is None or len(cl.args) < 1: - return llvmlite.const_int32(pool, 0) - arg0: ast.AST | t.CPtr = cl.args.get(0) - if arg0 is None or arg0.kind() != ast.ASTKind.Name: - return llvmlite.const_int32(pool, 0) - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0) - if nm.id is None: - return llvmlite.const_int32(pool, 0) - async_name: str = self._lookup_coro_var(trans, nm.id) - if async_name is None: - return llvmlite.const_int32(pool, 0) - frame_ty: llvmlite.LLVMType | t.CPtr = self._lookup_coro_frame( - trans, async_name) - if frame_ty is None: - return llvmlite.const_int32(pool, 0) - frame_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, frame_ty) - - # 帧变量值(i8* / Ptr(帧))→ bitcast 到 Ptr(帧) - frame_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, arg0, None, 0, trans) - if frame_val is None: - return llvmlite.const_int32(pool, 0) - frame_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, frame_val, frame_ptr_ty) - if frame_ptr is None: - return llvmlite.const_int32(pool, 0) - - func: llvmlite.Function | t.CPtr = trans._cur_func - if func is None: - return llvmlite.const_int32(pool, 0) - rn_buf: str = pool.alloc(64) - if rn_buf is not None: - viperlib.snprintf(rn_buf, 64, "resume_%s", async_name) - resume_mangled: str = self.Gen.FuncGenBase._mangle_func_name( - trans, rn_buf, 0) - if self.Gen.CallGenBase.find_func_in_module(mod, resume_mangled) is None: - return llvmlite.const_int32(pool, 0) - - loop_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "coro.loop") - check_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "coro.check") - after_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "coro.after") - if loop_bb is None or check_bb is None or after_bb is None: - return llvmlite.const_int32(pool, 0) - llvmlite.build_br(builder, loop_bb) - llvmlite.position_at_end(builder, loop_bb) - frame_ptr.Next = None - status: llvmlite.Value | t.CPtr = llvmlite.build_call( - builder, resume_mangled, frame_ptr, 1, i32_ty, 0) - zero_cmp: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - done_cond: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, status, zero_cmp) - llvmlite.build_cond_br(builder, done_cond, after_bb, check_bb) - # M3:SUSPEND → wake 轮询(GetTickCount64 >= wake 或 wake==0 继续,否则 Sleep(1)) - llvmlite.position_at_end(builder, check_bb) - wake_idx_r: int = self._lookup_coro_wake(trans, async_name) - if wake_idx_r < 0: - llvmlite.build_br(builder, loop_bb) - else: - i64_ty_r2: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - wake_ptr_r: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, frame_ty, i64_ty_r2, frame_ptr, wake_idx_r) - wake_v_r: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i64_ty_r2, wake_ptr_r) - now_v_r: llvmlite.Value | t.CPtr = llvmlite.build_call( - builder, "GetTickCount64", None, 0, i64_ty_r2, 0) - not_wake_r: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_EQ, wake_v_r, - llvmlite.const_int64(pool, 0)) - due_r: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_UGE, now_v_r, wake_v_r) - cont_r: llvmlite.Value | t.CPtr = llvmlite.build_or( - builder, not_wake_r, due_r) - wsleep_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "coro.wsleep") - wdue_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, "coro.wdue") - llvmlite.build_cond_br(builder, cont_r, wdue_bb, wsleep_bb) - llvmlite.position_at_end(builder, wsleep_bb) - sleep_one: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) - llvmlite.build_call(builder, "Sleep", sleep_one, 1, - llvmlite.Void(pool), 0) - llvmlite.build_br(builder, loop_bb) - llvmlite.position_at_end(builder, wdue_bb) - llvmlite.build_br(builder, loop_bb) - llvmlite.position_at_end(builder, after_bb) - ret_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, frame_ty, i32_ty, frame_ptr, 2) - ret_val: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i32_ty, ret_ptr) - return ret_val - - # ============================================================ - # 公共查询 / 登记 - # ============================================================ - def is_async_func(self, trans: HT.Translator | t.CPtr, - name: str) -> int: - """查询 name 是否已注册为 async 函数(_async_funcs 表),1=是 0=否""" - if trans is None or name is None or trans._async_funcs is None: - return 0 - cnt: int = trans._async_func_count - i: int = 0 - for i in range(cnt): - addr: t.CUInt64T = t.CUInt64T(trans._async_funcs) + i * 8 - slot: str | t.CPtr = (t.CVoid | t.CPtr)(addr) - if slot[0] is not None and string.strcmp(slot[0], name) == 0: - return 1 - return 0 - - def register_coro_var(self, trans: HT.Translator | t.CPtr, - var_name: str, func_name: str) -> int: - """记录 变量名→async 函数名 映射(coro.coro_run 反查帧类型用)。 - 对齐 TPC HandlesAnnAssign.py L319-326。返回 0 成功。""" - if trans is None or var_name is None or func_name is None: - return 1 - if trans._coro_var_async is None: - return 1 - cnt: int = trans._coro_var_async_count - i: int = 0 - for i in range(cnt): - addr: t.CUInt64T = t.CUInt64T(trans._coro_var_async) + i * 16 - pair: str | t.CPtr = (t.CVoid | t.CPtr)(addr) - if pair[0] is not None and string.strcmp(pair[0], var_name) == 0: - return 0 - if cnt >= HT.MAX_CORO_VARS: - return 1 - pair2_addr: t.CUInt64T = t.CUInt64T(trans._coro_var_async) + cnt * 16 - pair2: str | t.CPtr = (t.CVoid | t.CPtr)(pair2_addr) - pair2[0] = var_name - pair2[1] = func_name - trans._coro_var_async_count = cnt + 1 - return 0 - - def _register_async_func(self, trans: HT.Translator | t.CPtr, - name: str) -> int: - """注册 async 函数裸名到 _async_funcs 表""" - if trans is None or name is None or trans._async_funcs is None: - return 1 - cnt: int = trans._async_func_count - i: int = 0 - for i in range(cnt): - addr: t.CUInt64T = t.CUInt64T(trans._async_funcs) + i * 8 - slot: str | t.CPtr = (t.CVoid | t.CPtr)(addr) - if slot[0] is not None and string.strcmp(slot[0], name) == 0: - return 0 - if cnt >= HT.MAX_CORO_FUNCS: - return 1 - addr2: t.CUInt64T = t.CUInt64T(trans._async_funcs) + cnt * 8 - slot2: str | t.CPtr = (t.CVoid | t.CPtr)(addr2) - slot2[0] = name - trans._async_func_count = cnt + 1 - return 0 - - def _register_coro_frame(self, trans: HT.Translator | t.CPtr, - name: str, - frame_ty: llvmlite.LLVMType | t.CPtr) -> int: - """注册 async 名→帧类型 到 _coro_frames 表(16 字节/项 = char* + LLVMType*)""" - if trans is None or name is None or frame_ty is None: - return 1 - if trans._coro_frames is None: - return 1 - cnt: int = trans._coro_frame_count - i: int = 0 - for i in range(cnt): - addr: t.CUInt64T = t.CUInt64T(trans._coro_frames) + i * 16 - pair: str | t.CPtr = (t.CVoid | t.CPtr)(addr) - if pair[0] is not None and string.strcmp(pair[0], name) == 0: - pair[1] = (str)(t.CVoid(t.CSizeT(frame_ty), t.CPtr)) - return 0 - if cnt >= HT.MAX_CORO_FUNCS: - return 1 - pair2_addr: t.CUInt64T = t.CUInt64T(trans._coro_frames) + cnt * 16 - pair2: str | t.CPtr = (t.CVoid | t.CPtr)(pair2_addr) - pair2[0] = name - pair2[1] = (str)(t.CVoid(t.CSizeT(frame_ty), t.CPtr)) - trans._coro_frame_count = cnt + 1 - return 0 - - def _lookup_coro_frame(self, trans: HT.Translator | t.CPtr, - name: str) -> llvmlite.LLVMType | t.CPtr: - """按 async 名查帧类型,未命中返回 None""" - if trans is None or name is None or trans._coro_frames is None: - return None - cnt: int = trans._coro_frame_count - i: int = 0 - for i in range(cnt): - addr: t.CUInt64T = t.CUInt64T(trans._coro_frames) + i * 16 - pair: str | t.CPtr = (t.CVoid | t.CPtr)(addr) - if pair[0] is not None and string.strcmp(pair[0], name) == 0: - if pair[1] is not None: - ty_addr: t.CSizeT = t.CSizeT(pair[1]) - return (llvmlite.LLVMType | t.CPtr)(t.CVoid(ty_addr, t.CPtr)) - return None - return None - - def _lookup_coro_var(self, trans: HT.Translator | t.CPtr, - var_name: str) -> str: - """按变量名反查 async 函数名(_coro_var_async 表),未命中返回 None""" - if trans is None or var_name is None or trans._coro_var_async is None: - return None - cnt: int = trans._coro_var_async_count - i: int = 0 - for i in range(cnt): - addr: t.CUInt64T = t.CUInt64T(trans._coro_var_async) + i * 16 - pair: str | t.CPtr = (t.CVoid | t.CPtr)(addr) - if pair[0] is not None and string.strcmp(pair[0], var_name) == 0: - return pair[1] - return None - - # ============================================================ - # 段翻译辅助 - # ============================================================ - def _emit_coro_return(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - trans: HT.Translator | t.CPtr, - stmt: ast.AST | t.CPtr) -> None: - """协程内 Return 特判:store ret 槽 + done=1 + br exit。 - M1 不支持 return await(顶层 await 仅限 AnnAssign/Assign)。 - - 注意:stmt 以 ast.AST 基类型传入,AST 基类没有 value 字段 - (base.vp 仅 parent/pool/lineno/col/children),直接 stmt.value - 读到的是非法偏移(0/垃圾)→ ret 恒 0。必须转回 ast.Return 再取。""" - rv_node: ast.Return | t.CPtr = (ast.Return | t.CPtr)(stmt) - ret_val: llvmlite.Value | t.CPtr = None - if rv_node is not None and rv_node.value is not None: - if rv_node.value.kind() != ast.ASTKind.Await: - ret_val = self.Gen.ExprGen.translate_value( - builder, pool, mod, rv_node.value, None, 0, trans) - if ret_val is None: - ret_val = llvmlite.const_int32(pool, 0) - llvmlite.build_store(builder, ret_val, trans._coro_ret_ptr) - done_one: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) - llvmlite.build_store(builder, done_one, trans._coro_done_ptr) - llvmlite.build_br(builder, trans._coro_exit_bb) - - def _expr_await_is_sleep(self, aw: ast.Await | t.CPtr) -> int: - """Await 目标是否为 coro_sleep(Name 或 coro.coro_sleep)""" - if aw is None or aw.value is None: - return 0 - if aw.value.kind() != ast.ASTKind.Call: - return 0 - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(aw.value) - if cl.func is None: - return 0 - if cl.func.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl.func) - if nm.id is not None and string.strcmp(nm.id, "coro_sleep") == 0: - return 1 - elif cl.func.kind() == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if at.attr is not None and string.strcmp(at.attr, "coro_sleep") == 0: - return 1 - return 0 - - def _is_await_tail(self, stmt: ast.AST | t.CPtr) -> int: - """判断语句是否为段尾:AnnAssign/Assign/Expr 且 value 直接是 Await""" - if stmt is None: - return 0 - sk: int = stmt.kind() - if sk == ast.ASTKind.AnnAssign: - aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) - if aa.value is not None and aa.value.kind() == ast.ASTKind.Await: - return 1 - elif sk == ast.ASTKind.Assign: - as_: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) - if as_.value is not None and as_.value.kind() == ast.ASTKind.Await: - if as_.targets is not None and len(as_.targets) == 1: - return 1 - elif sk == ast.ASTKind.Expr: - e: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(stmt) - if e.value is not None and e.value.kind() == ast.ASTKind.Await: - return 1 - return 0 - - def _get_assign_target_name(self, stmt: ast.AST | t.CPtr) -> str: - """取 AnnAssign(target=Name)/Assign(单 target=Name) 的目标名,未命中返回 None""" - if stmt is None: - return None - sk: int = stmt.kind() - if 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) - return tn.id - elif sk == ast.ASTKind.Assign: - as_: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) - if as_.targets is not None and len(as_.targets) == 1: - t0: ast.AST | t.CPtr = as_.targets.get(0) - if t0 is not None and t0.kind() == ast.ASTKind.Name: - tn2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(t0) - return tn2.id - return None - - def _get_await_value(self, stmt: ast.AST | t.CPtr) -> ast.Await | t.CPtr: - """取段尾语句的 Await value 节点,未命中返回 None""" - if stmt is None: - return None - sk: int = stmt.kind() - if sk == ast.ASTKind.AnnAssign: - aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) - if aa.value is not None and aa.value.kind() == ast.ASTKind.Await: - return (ast.Await | t.CPtr)(aa.value) - elif sk == ast.ASTKind.Assign: - as_: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) - if as_.value is not None and as_.value.kind() == ast.ASTKind.Await: - return (ast.Await | t.CPtr)(as_.value) - elif sk == ast.ASTKind.Expr: - ex: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(stmt) - if ex.value is not None and ex.value.kind() == ast.ASTKind.Await: - return (ast.Await | t.CPtr)(ex.value) - return None - - def _extract_await_call_name(self, aw_node: ast.Await | t.CPtr) -> str: - """从 Await(value=Call(func)) 提取 async 函数名或 coro_sleep,未命中返回 None""" - if aw_node is None or aw_node.value is None: - return None - if aw_node.value.kind() == ast.ASTKind.Call: - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(aw_node.value) - if cl.func is not None: - if cl.func.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl.func) - return nm.id - if cl.func.kind() == ast.ASTKind.Attribute: - # coro.coro_sleep(ms):M3 sleep 挂起 - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if at.attr is not None and string.strcmp(at.attr, "coro_sleep") == 0: - return "coro_sleep" - return None - - def _read_local_name(self, trans: HT.Translator | t.CPtr, - idx: int) -> str: - """读 trans._coro_locals 第 idx 个局部变量名,越界返回 None""" - if trans is None or trans._coro_locals is None: - return None - addr: t.CUInt64T = t.CUInt64T(trans._coro_locals) + idx * 8 - slot: str | t.CPtr = (t.CVoid | t.CPtr)(addr) - return slot[0] +import lib.core.Gen.GenTypes as GenTypes +import t, c +from stdint import * +import ast +import llvmlite +from llvmlite import LLVMType +import memhub +import string +import viperlib +import stdio +import stdlib +import lib.core.VLogger as VLogger +import lib.core.Gen.Translator as HT +import lib.core.Gen.Call.CallGenBase as CallGenBase + + +# ============================================================ +# AsyncGenMixin - TPV-M1 协程翻译(async def / await / coro.coro_run) +# +# M1 最小协程闭环(对齐 TPC lib/core/Handles/HandlesAsyncFunctions.py M1): +# - async def f(): → 帧结构体 %Coro_ = +# { i32 state, i32 done, i32 ret, } +# - create_() → malloc 帧 + 置零 state/done/ret,ret 帧指针 +# - resume_(frame) → switch(state) 状态机:case i → state_i 块 +# (静态段切分,每段以顶层 await 结尾), +# exit 块 load done 返回(0=SUSPEND 1=DONE) +# - await async_fn() → 创建子帧 + resume 到 DONE + 取子帧 ret 槽存父槽 +# + 父挂起(store state=下一恢复段号 + br exit) +# - coro.coro_run(frame) → 内联循环 resume 到 done,返回帧 ret 槽值(i32) +# +# M1 限制(与 TPC M1 一致): +# - async 函数无参数(fd.args 为空) +# - await 仅限顶层 AnnAssign/Assign(value 直接是 Await) +# - 无 coro_sleep / For 内 await / If-While 控制流(后续 M2/M3 扩展) +# +# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# @t.NoVTable:静态绑定。 +# ============================================================ + +SCOPE_FUNCTION: t.CDefine = 1 + +@t.NoVTable +class AsyncGenMixin(CallGenBase.CallGenBase): + """协程翻译 Mixin(TPV-M1 状态机)""" + + # ============================================================ + # 入口:async 函数定义 + # + # 由 FuncGenDef.translate_function_def 检测 fd.flags & FLAG_IS_ASYNC + # (=1,见 includes/ast/stmts.vp L342-345)后调用,早返回不进普通函数路径。 + # ============================================================ + def translate_async_function(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 async 函数定义,返回 0 成功 + + 生成 create_(帧分配,M2 带参数)与 resume_(状态机), + 并把裸名注册进 trans._async_funcs(is_async_func / coro_run 反查)。 + + M2 帧布局:{ i32 state, i32 done, i32 ret, + 参数槽(3..3+nparams), 局部槽(3+nparams..), __await_N 额外槽 } + - 参数槽:create_(args) 收值入帧(M2 参数) + - 局部槽:顶层 AnnAssign/Assign 的 Name 目标 + - 额外槽:嵌套 await 提升临时变量 __await_N(预扫描分配,与翻译同序) + 恢复块状态号:state0 = 入口,每个 await(顶层或嵌套)按 DFS 顺序 + 分配 state1..,switch case 预建(TPV build_switch 一次性生成,无法动态 add_case)。 + """ + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node) + if fd is None or fd.name is None or trans is None: + return 0 + name: str = fd.name + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + if pool is None or mod is None: + return 0 + + # 防重复生成:create_ 已存在(模块多遍编译/重复定义) + cname_buf: str = pool.alloc(64) + if cname_buf is not None: + viperlib.snprintf(cname_buf, 64, "create_%s", name) + create_mangled: str = self.Gen.FuncGenBase._mangle_func_name( + trans, cname_buf, 0) + if self.Gen.CallGenBase.find_func_in_module(mod, create_mangled) is not None: + return 0 + + # 注册 async 裸名(供 await 目标校验 / coro_run 反查) + self._register_async_func(trans, name) + + # M2:参数收集 → trans._coro_params(char* 数组,8 字节/项) + trans._coro_param_count = 0 + nparams: int = self._collect_param_names(trans, fd) + + # 局部变量收集(顶层 AnnAssign/Assign 的 Name 目标 → 帧槽) + trans._coro_local_count = 0 + nlocals: int = self._collect_local_names(trans, fd) + + # M3-M7:预扫描额外槽(wake/for/await 类型表 + 位置数组)+ 状态号 + # _coro_await_count = 恢复块数;nseg = 1 入口 + await_count + trans._coro_extra_count = 0 + trans._coro_hoist_count = 0 + trans._coro_await_count = 0 + trans._coro_uses_sleep = 0 + trans._coro_scan_for_count = 0 + trans._coro_for_counter = 0 + self._scan_sleep_usage(trans, fd) + self._pre_scan_awaits(trans, fd) + nextra: int = trans._coro_extra_count + trans._coro_nseg = 1 + trans._coro_await_count + + # 帧结构体 %Coro_ + frame_ty: llvmlite.LLVMType | t.CPtr = self._build_frame_ty( + pool, mod, trans, name, nparams, nlocals, nextra) + if frame_ty is None: + return 0 + self._register_coro_frame(trans, name, frame_ty) + # M3:wake 槽 index 注册(coro_run 轮询反查;wake 在额外槽相对 0) + if trans._coro_uses_sleep != 0: + self._register_coro_wake(trans, name, trans._coro_extra_base + 0) + + # 进入函数作用域:resume 局部槽注册隔离,翻译完退出不污染模块作用域 + self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_FUNCTION) + + self._emit_create(pool, mod, trans, name, frame_ty, nparams) + self._emit_resume(pool, mod, trans, name, fd, frame_ty, + nparams, nlocals, nextra) + + self.Gen.VarGen.exit_scope(trans.SymTab) + return 0 + + # ============================================================ + # M2:参数收集(帧参数槽 index 3+i) + # ============================================================ + def _collect_param_names(self, trans: HT.Translator | t.CPtr, + fd: ast.FunctionDef | t.CPtr) -> int: + """收集 async 函数参数名到 trans._coro_params(char* 数组,8 字节/项)。 + 参数槽 index = 3 + i,create_ 按参数顺序收值入帧。""" + if fd is None or fd.args is None or trans is None: + return 0 + if trans._coro_params is None: + return 0 + ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args) + cnt: int = 0 + if ags.args is None: + return 0 + bn: t.CSizeT = len(ags.args) + i: t.CSizeT = 0 + for i in range(bn): + a0: ast.AST | t.CPtr = ags.args.get(i) + if a0 is None: + continue + aname: str = None + if a0.kind() == ast.ASTKind.Arg: + ar: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(a0) + aname = ar.arg + elif a0.kind() == ast.ASTKind.Name: + anm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(a0) + aname = anm.id + if aname is None: + continue + if cnt >= HT.MAX_CORO_VARS: + break + addr: t.CUInt64T = t.CUInt64T(trans._coro_params) + cnt * 8 + slot: str | t.CPtr = (t.CVoid | t.CPtr)(addr) + slot[0] = aname + cnt = cnt + 1 + trans._coro_param_count = cnt + return cnt + + # ============================================================ + # M3-M7:预扫描额外槽(wake/for/await 类型表 + 位置数组)+ 状态号 + # + # 与翻译端同一 DFS 顺序。额外槽表 _coro_extra_types(i8:1=i32 2=i64): + # [0] __coro_wake_us(若用 coro_sleep,i64) + # 随后按 DFS:__f_idx_N/__f_len_N(range-For 含 await,i32)、 + # __await_N(嵌套 await,i32) + # 位置数组:_coro_await_slots[M]=__await_M 相对序号;_coro_for_slots[N]=__f_idx_N 相对序号 + # _coro_await_count = 恢复块数(顶层 + 嵌套 await) + # ============================================================ + def _pre_scan_awaits(self, trans: HT.Translator | t.CPtr, + fd: ast.FunctionDef | t.CPtr) -> int: + """DFS 预扫描协程体,填额外槽表并返回额外槽总数""" + if fd is None or fd.children is None or trans is None: + return 0 + trans._coro_extra_count = 0 + trans._coro_hoist_count = 0 + trans._coro_await_count = 0 + trans._coro_scan_for_count = 0 + if trans._coro_uses_sleep != 0: + trans._coro_extra_types[0] = 2 # __coro_wake_us(i64)相对序号 0 + trans._coro_extra_count = 1 + self._scan_stmts(trans, fd.children) + return trans._coro_extra_count + + # ---------- 第一遍:coro_sleep 检测(wake 槽决定) ---------- + def _scan_sleep_usage(self, trans: HT.Translator | t.CPtr, + fd: ast.FunctionDef | t.CPtr): + if fd is None or fd.children is None or trans is None: + return + self._scan_sleep_stmts(trans, fd.children) + + def _scan_sleep_stmts(self, trans: HT.Translator | t.CPtr, + stmts: list[ast.AST | t.CPtr] | t.CPtr): + if stmts is None or trans._coro_uses_sleep != 0: + return + bn: t.CSizeT = len(stmts) + i: t.CSizeT = 0 + for i in range(bn): + self._scan_sleep_stmt(trans, stmts.get(i)) + + def _scan_sleep_stmt(self, trans: HT.Translator | t.CPtr, + stmt: ast.AST | t.CPtr): + if stmt is None or trans._coro_uses_sleep != 0: + return + sk: int = stmt.kind() + if sk == ast.ASTKind.If: + ifn: ast.If | t.CPtr = (ast.If | t.CPtr)(stmt) + self._scan_sleep_expr(trans, ifn.test) + self._scan_sleep_stmts(trans, stmt.children) + self._scan_sleep_stmts(trans, ifn.orelse) + return + if sk == ast.ASTKind.While: + whn: ast.While | t.CPtr = (ast.While | t.CPtr)(stmt) + self._scan_sleep_expr(trans, whn.test) + self._scan_sleep_stmts(trans, stmt.children) + self._scan_sleep_stmts(trans, whn.orelse) + return + if sk == ast.ASTKind.For: + fn2: ast.For | t.CPtr = (ast.For | t.CPtr)(stmt) + self._scan_sleep_expr(trans, fn2.iter) + self._scan_sleep_stmts(trans, stmt.children) + self._scan_sleep_stmts(trans, fn2.orelse) + return + if sk == ast.ASTKind.Try: + trn: ast.Try | t.CPtr = (ast.Try | t.CPtr)(stmt) + self._scan_sleep_stmts(trans, stmt.children) + if trn.handlers is not None: + nh: t.CSizeT = len(trn.handlers) + hh: t.CSizeT = 0 + for hh in range(nh): + h0: ast.AST | t.CPtr = trn.handlers.get(hh) + if h0 is not None: + self._scan_sleep_stmts(trans, h0.children) + self._scan_sleep_stmts(trans, trn.orelse) + self._scan_sleep_stmts(trans, trn.finalbody) + return + if sk == ast.ASTKind.Return: + rv: ast.Return | t.CPtr = (ast.Return | t.CPtr)(stmt) + self._scan_sleep_expr(trans, rv.value) + return + if sk == ast.ASTKind.AnnAssign: + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) + self._scan_sleep_expr(trans, aa.value) + return + if sk == ast.ASTKind.Assign: + as_: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) + self._scan_sleep_expr(trans, as_.value) + return + if sk == ast.ASTKind.Expr: + e: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(stmt) + self._scan_sleep_expr(trans, e.value) + return + + def _scan_sleep_expr(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr): + if node is None or trans._coro_uses_sleep != 0: + return + 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: + if cl.func.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl.func) + if nm.id is not None and string.strcmp(nm.id, "coro_sleep") == 0: + trans._coro_uses_sleep = 1 + return + elif cl.func.kind() == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if at.attr is not None and string.strcmp(at.attr, "coro_sleep") == 0: + trans._coro_uses_sleep = 1 + return + self._scan_sleep_expr(trans, cl.func) + if cl.args is not None: + nb: t.CSizeT = len(cl.args) + j: t.CSizeT = 0 + for j in range(nb): + self._scan_sleep_expr(trans, cl.args.get(j)) + return + if k == ast.ASTKind.BinOp: + b: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + self._scan_sleep_expr(trans, b.left) + self._scan_sleep_expr(trans, b.right) + return + if k == ast.ASTKind.UnaryOp: + u: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + self._scan_sleep_expr(trans, u.operand) + return + if k == ast.ASTKind.Compare: + cm: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) + self._scan_sleep_expr(trans, cm.left) + if cm.comparators is not None: + nb2: t.CSizeT = len(cm.comparators) + j2: t.CSizeT = 0 + for j2 in range(nb2): + self._scan_sleep_expr(trans, cm.comparators.get(j2)) + return + if k == ast.ASTKind.BoolOp: + bo: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) + if bo.values is not None: + nb3: t.CSizeT = len(bo.values) + j3: t.CSizeT = 0 + for j3 in range(nb3): + self._scan_sleep_expr(trans, bo.values.get(j3)) + return + if k == ast.ASTKind.IfExp: + ie: ast.IfExp | t.CPtr = (ast.IfExp | t.CPtr)(node) + self._scan_sleep_expr(trans, ie.test) + self._scan_sleep_expr(trans, ie.body) + self._scan_sleep_expr(trans, ie.orelse) + return + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + self._scan_sleep_expr(trans, at.value) + return + if k == ast.ASTKind.Subscript: + sb: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + self._scan_sleep_expr(trans, sb.value) + self._scan_sleep_expr(trans, sb.slice) + return + if k == ast.ASTKind.Await: + aw: ast.Await | t.CPtr = (ast.Await | t.CPtr)(node) + self._scan_sleep_expr(trans, aw.value) + return + + # ---------- 第二遍:填额外槽表 + 状态号计数 ---------- + def _scan_stmts(self, trans: HT.Translator | t.CPtr, + stmts: list[ast.AST | t.CPtr] | t.CPtr): + if stmts is None: + return + bn: t.CSizeT = len(stmts) + i: t.CSizeT = 0 + for i in range(bn): + self._scan_stmt(trans, stmts.get(i)) + + def _scan_stmt(self, trans: HT.Translator | t.CPtr, + stmt: ast.AST | t.CPtr): + if stmt is None: + return + sk: int = stmt.kind() + if sk == ast.ASTKind.If: + ifn: ast.If | t.CPtr = (ast.If | t.CPtr)(stmt) + if ifn.test is not None: + self._scan_expr(trans, ifn.test) + self._scan_stmts(trans, stmt.children) + self._scan_stmts(trans, ifn.orelse) + return + if sk == ast.ASTKind.While: + whn: ast.While | t.CPtr = (ast.While | t.CPtr)(stmt) + if whn.test is not None: + self._scan_expr(trans, whn.test) + self._scan_stmts(trans, stmt.children) + self._scan_stmts(trans, whn.orelse) + return + if sk == ast.ASTKind.For: + fn_: ast.For | t.CPtr = (ast.For | t.CPtr)(stmt) + if self._for_deep_await(stmt) != 0: + # 含 await:必须是 range-For(M3) + if self._is_range_for(stmt) == 0: + err_b2: str = trans.Pool.alloc(256) + if err_b2 is not None: + viperlib.snprintf( + err_b2, 256, + "[coro-M3] 协程内 For 仅支持 range 迭代(含 await)") + self.Gen.TypeGenErr.fatal_error(stmt, err_b2, "SyntaxError") + return + # 填 __f_idx_N / __f_len_N(i32) + if trans._coro_scan_for_count < HT.MAX_CORO_VARS: + trans._coro_for_slots[trans._coro_scan_for_count] = trans._coro_extra_count + trans._coro_extra_types[trans._coro_extra_count] = 1 + trans._coro_extra_count = trans._coro_extra_count + 1 + trans._coro_extra_types[trans._coro_extra_count] = 1 + trans._coro_extra_count = trans._coro_extra_count + 1 + trans._coro_scan_for_count = trans._coro_scan_for_count + 1 + self._scan_stmts(trans, stmt.children) + self._scan_stmts(trans, fn_.orelse) + return + # 无 await:委托标准 For;递归扫描(嵌套 For/Try 可能含 await) + self._scan_stmts(trans, stmt.children) + self._scan_stmts(trans, fn_.orelse) + return + if sk == ast.ASTKind.Try: + tr2: ast.Try | t.CPtr = (ast.Try | t.CPtr)(stmt) + self._scan_stmts(trans, stmt.children) + if tr2.handlers is not None: + nh2: t.CSizeT = len(tr2.handlers) + hh2: t.CSizeT = 0 + for hh2 in range(nh2): + h2: ast.AST | t.CPtr = tr2.handlers.get(hh2) + if h2 is not None: + self._scan_stmts(trans, h2.children) + self._scan_stmts(trans, tr2.orelse) + self._scan_stmts(trans, tr2.finalbody) + return + if sk == ast.ASTKind.Raise: + rz: ast.Raise | t.CPtr = (ast.Raise | t.CPtr)(stmt) + if rz.exc is not None: + self._scan_expr(trans, rz.exc) + return + if sk == ast.ASTKind.Return: + rv: ast.Return | t.CPtr = (ast.Return | t.CPtr)(stmt) + if rv.value is not None: + self._scan_expr(trans, rv.value) + return + if sk == ast.ASTKind.Break or sk == ast.ASTKind.Continue: + return + # 顶层 await(AnnAssign/Assign/Expr value 直接 Await):计数不提升 + if sk == ast.ASTKind.AnnAssign or sk == ast.ASTKind.Assign or sk == ast.ASTKind.Expr: + if self._is_await_tail(stmt) != 0: + trans._coro_await_count = trans._coro_await_count + 1 + return + # 语句内嵌套 await:DFS 表达式(AnnAssign.value / Assign.value / Expr.value) + self._scan_stmt_exprs(trans, stmt) + + def _scan_stmt_exprs(self, trans: HT.Translator | t.CPtr, + stmt: ast.AST | t.CPtr): + """扫描语句的值表达式找嵌套 await""" + if stmt is None: + return + sk: int = stmt.kind() + if sk == ast.ASTKind.AnnAssign: + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) + if aa.value is not None: + self._scan_expr(trans, aa.value) + return + if sk == ast.ASTKind.Assign: + as_: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) + if as_.value is not None: + self._scan_expr(trans, as_.value) + return + if sk == ast.ASTKind.Expr: + e: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(stmt) + if e.value is not None: + self._scan_expr(trans, e.value) + return + # 其它语句类型:翻译端 fail-fast + + def _scan_expr(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr): + """DFS 扫描表达式找 Await:命中分配 __await_N 槽并计数状态号""" + if node is None: + return + k: int = node.kind() + if k == ast.ASTKind.Await: + # M3:await coro_sleep 用 wake 槽挂起,不占 __await_N 槽(仅计状态号) + aw_s: ast.Await | t.CPtr = (ast.Await | t.CPtr)(node) + if self._expr_await_is_sleep(aw_s) != 0: + trans._coro_await_count = trans._coro_await_count + 1 + return + if trans._coro_hoist_count < HT.MAX_CORO_VARS: + trans._coro_await_slots[trans._coro_hoist_count] = trans._coro_extra_count + trans._coro_extra_types[trans._coro_extra_count] = 1 + trans._coro_extra_count = trans._coro_extra_count + 1 + trans._coro_hoist_count = trans._coro_hoist_count + 1 + trans._coro_await_count = trans._coro_await_count + 1 + return + if k == ast.ASTKind.BinOp: + b: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + self._scan_expr(trans, b.left) + self._scan_expr(trans, b.right) + return + if k == ast.ASTKind.Call: + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + if cl.func is not None: + self._scan_expr(trans, cl.func) + if cl.args is not None: + nb: t.CSizeT = len(cl.args) + j: t.CSizeT = 0 + for j in range(nb): + self._scan_expr(trans, cl.args.get(j)) + return + if k == ast.ASTKind.UnaryOp: + u: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + if u.operand is not None: + self._scan_expr(trans, u.operand) + return + if k == ast.ASTKind.Compare: + cm: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) + if cm.left is not None: + self._scan_expr(trans, cm.left) + if cm.comparators is not None: + nb2: t.CSizeT = len(cm.comparators) + j2: t.CSizeT = 0 + for j2 in range(nb2): + self._scan_expr(trans, cm.comparators.get(j2)) + return + if k == ast.ASTKind.BoolOp: + bo: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) + if bo.values is not None: + nb3: t.CSizeT = len(bo.values) + j3: t.CSizeT = 0 + for j3 in range(nb3): + self._scan_expr(trans, bo.values.get(j3)) + return + if k == ast.ASTKind.IfExp: + ie: ast.IfExp | t.CPtr = (ast.IfExp | t.CPtr)(node) + self._scan_expr(trans, ie.test) + self._scan_expr(trans, ie.body) + self._scan_expr(trans, ie.orelse) + return + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at.value is not None: + self._scan_expr(trans, at.value) + return + if k == ast.ASTKind.Subscript: + sb: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + if sb.value is not None: + self._scan_expr(trans, sb.value) + if sb.slice is not None: + self._scan_expr(trans, sb.slice) + return + # Name / Constant 等叶子:无嵌套 await + + # ---------- For 判定辅助(M3) ---------- + def _for_deep_await(self, stmt: ast.AST | t.CPtr) -> int: + """For 语句树(含嵌套 If/While/For/Try/body/orelse)是否含 await""" + if stmt is None: + return 0 + fn3: ast.For | t.CPtr = (ast.For | t.CPtr)(stmt) + if fn3.iter is not None and self._find_expr_await(fn3.iter) is not None: + return 1 + if stmt.children is not None: + bn4: t.CSizeT = len(stmt.children) + i4: t.CSizeT = 0 + for i4 in range(bn4): + if self._stmt_deep_await(stmt.children.get(i4)) != 0: + return 1 + if fn3.orelse is not None: + bn5: t.CSizeT = len(fn3.orelse) + i5: t.CSizeT = 0 + for i5 in range(bn5): + if self._stmt_deep_await(fn3.orelse.get(i5)) != 0: + return 1 + return 0 + + def _stmt_deep_await(self, stmt: ast.AST | t.CPtr) -> int: + """语句树(含嵌套 If/While/For/Try)是否含 await""" + if stmt is None: + return 0 + sk2: int = stmt.kind() + if sk2 == ast.ASTKind.If: + ifn2: ast.If | t.CPtr = (ast.If | t.CPtr)(stmt) + if ifn2.test is not None and self._find_expr_await(ifn2.test) is not None: + return 1 + if self._stmts_deep_await(stmt.children) != 0: + return 1 + return self._stmts_deep_await(ifn2.orelse) + if sk2 == ast.ASTKind.While: + whn2: ast.While | t.CPtr = (ast.While | t.CPtr)(stmt) + if whn2.test is not None and self._find_expr_await(whn2.test) is not None: + return 1 + if self._stmts_deep_await(stmt.children) != 0: + return 1 + return self._stmts_deep_await(whn2.orelse) + if sk2 == ast.ASTKind.For: + return self._for_deep_await(stmt) + if sk2 == ast.ASTKind.Try: + tr3: ast.Try | t.CPtr = (ast.Try | t.CPtr)(stmt) + if self._stmts_deep_await(stmt.children) != 0: + return 1 + if tr3.handlers is not None: + nh3: t.CSizeT = len(tr3.handlers) + hh3: t.CSizeT = 0 + for hh3 in range(nh3): + h3: ast.AST | t.CPtr = tr3.handlers.get(hh3) + if h3 is not None and self._stmts_deep_await(h3.children) != 0: + return 1 + if self._stmts_deep_await(tr3.orelse) != 0: + return 1 + return self._stmts_deep_await(tr3.finalbody) + return self._stmt_has_await(stmt) + + def _stmts_deep_await(self, stmts: list[ast.AST | t.CPtr] | t.CPtr) -> int: + if stmts is None: + return 0 + bn6: t.CSizeT = len(stmts) + i6: t.CSizeT = 0 + for i6 in range(bn6): + if self._stmt_deep_await(stmts.get(i6)) != 0: + return 1 + return 0 + + def _is_range_for(self, stmt: ast.AST | t.CPtr) -> int: + """range-For:单 Name target + iter 是 range(x) 或 range(a, b),参数无 await""" + if stmt is None: + return 0 + fn4: ast.For | t.CPtr = (ast.For | t.CPtr)(stmt) + if fn4.target is None or fn4.target.kind() != ast.ASTKind.Name: + return 0 + if fn4.iter is None or fn4.iter.kind() != ast.ASTKind.Call: + return 0 + cl4: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fn4.iter) + if cl4.func is None or cl4.func.kind() != ast.ASTKind.Name: + return 0 + nm4: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl4.func) + if nm4.id is None or string.strcmp(nm4.id, "range") != 0: + return 0 + if cl4.args is None: + return 0 + nb7: t.CSizeT = len(cl4.args) + if nb7 != 1 and nb7 != 2: + return 0 + j7: t.CSizeT = 0 + for j7 in range(nb7): + if self._find_expr_await(cl4.args.get(j7)) is not None: + return 0 + return 1 + + # ============================================================ + # 局部变量收集(顶层 AnnAssign / Assign 的 Name 目标) + # ============================================================ + def _collect_local_names(self, trans: HT.Translator | t.CPtr, + fd: ast.FunctionDef | t.CPtr) -> int: + """收集帧局部变量名(_coro_locals,8 字节/项): + - 顶层 AnnAssign/Assign 的 Name 目标(M2) + - try 的 except as e 绑定名(M5/M6,跨 handler 需要帧槽) + - 含 await 的 range-For 迭代目标(M3) + 递归扫描(If/While/For/Try 嵌套)。""" + if fd is None or fd.children is None or trans is None: + return 0 + if trans._coro_locals is None: + return 0 + trans._coro_local_count = 0 + self._collect_locals_stmts(trans, fd.children) + return trans._coro_local_count + + def _collect_locals_stmts(self, trans: HT.Translator | t.CPtr, + stmts: list[ast.AST | t.CPtr] | t.CPtr): + if stmts is None: + return + bn: t.CSizeT = len(stmts) + i: t.CSizeT = 0 + for i in range(bn): + self._collect_locals_stmt(trans, stmts.get(i)) + + def _collect_locals_stmt(self, trans: HT.Translator | t.CPtr, + stmt: ast.AST | t.CPtr): + if stmt is None: + return + sk: int = stmt.kind() + if 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) + self._add_local(trans, tn.id) + return + if sk == ast.ASTKind.Assign: + as_: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) + if as_.targets is not None and len(as_.targets) == 1: + t0: ast.AST | t.CPtr = as_.targets.get(0) + if t0 is not None and t0.kind() == ast.ASTKind.Name: + tn2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(t0) + self._add_local(trans, tn2.id) + return + if sk == ast.ASTKind.If: + self._collect_locals_stmts(trans, stmt.children) + ifn: ast.If | t.CPtr = (ast.If | t.CPtr)(stmt) + self._collect_locals_stmts(trans, ifn.orelse) + return + if sk == ast.ASTKind.While: + self._collect_locals_stmts(trans, stmt.children) + whn: ast.While | t.CPtr = (ast.While | t.CPtr)(stmt) + self._collect_locals_stmts(trans, whn.orelse) + return + if sk == ast.ASTKind.For: + fn: ast.For | t.CPtr = (ast.For | t.CPtr)(stmt) + if self._for_deep_await(stmt) != 0: + if fn.target is not None and fn.target.kind() == ast.ASTKind.Name: + tn3: ast.Name | t.CPtr = (ast.Name | t.CPtr)(fn.target) + self._add_local(trans, tn3.id) + self._collect_locals_stmts(trans, stmt.children) + self._collect_locals_stmts(trans, fn.orelse) + return + if sk == ast.ASTKind.Try: + tr: ast.Try | t.CPtr = (ast.Try | t.CPtr)(stmt) + self._collect_locals_stmts(trans, stmt.children) + if tr.handlers is not None: + nh: t.CSizeT = len(tr.handlers) + hh: t.CSizeT = 0 + for hh in range(nh): + h0: ast.AST | t.CPtr = tr.handlers.get(hh) + if h0 is None: + continue + hd: ast.ExceptHandler | t.CPtr = (ast.ExceptHandler | t.CPtr)(h0) + self._add_local(trans, hd.name) + self._collect_locals_stmts(trans, h0.children) + self._collect_locals_stmts(trans, tr.orelse) + self._collect_locals_stmts(trans, tr.finalbody) + return + + def _add_local(self, trans: HT.Translator | t.CPtr, + name: str): + if name is None: + return + cnt: int = trans._coro_local_count + if cnt >= HT.MAX_CORO_VARS: + return + addr: t.CUInt64T = t.CUInt64T(trans._coro_locals) + cnt * 8 + slot: str | t.CPtr = (t.CVoid | t.CPtr)(addr) + slot[0] = name + trans._coro_local_count = cnt + 1 + + # ============================================================ + # 帧结构体 %Coro_ = { i32 state, i32 done, i32 ret, <局部槽>* } + # 槽索引: 0=state 1=done 2=ret 3..3+nlocals-1=局部变量 + # ============================================================ + def _build_frame_ty(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + trans: HT.Translator | t.CPtr, + name: str, + nparams: int, nlocals: int, + nextra: int) -> llvmlite.LLVMType | t.CPtr: + """构造帧结构体并注册到模块与结构体表,返回 LLVMType + M7 布局:{i32 state, i32 done, i32 ret, i32 exc, i8* msg, + 参数槽(5+i), 局部槽(5+nparams+i), 额外槽(extra_base+i, 按类型表 1=i32 2=i64)}""" + 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, llvmlite.Int8(pool)) + # 槽基址(供 resume/await 计算槽 index) + trans._coro_local_base = 5 + nparams + trans._coro_extra_base = trans._coro_local_base + nlocals + total: int = 5 + nparams + nlocals + nextra + head: llvmlite.ParamNode | t.CPtr = None + prev: llvmlite.ParamNode | t.CPtr = None + fi: int = 0 + for fi in range(total): + fty: llvmlite.LLVMType | t.CPtr = i32_ty + if fi == 4: + fty = i8_ptr_ty + elif fi >= trans._coro_extra_base: + tidx: int = fi - trans._coro_extra_base + if tidx < nextra and trans._coro_extra_types is not None: + if trans._coro_extra_types[tidx] == 2: + fty = i64_ty + 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 head is None: + head = pnode + if prev is not None: + prev.Next = pnode + prev = pnode + ty_name: str = pool.alloc(128) + if ty_name is not None: + viperlib.snprintf(ty_name, 128, "Coro_%s", name) + frame_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct( + pool, head, total, ty_name) + if frame_ty is None: + return None + llvmlite.module_add_named_type(mod, pool, frame_ty) + self.Gen.StructGen.register_struct( + pool, ty_name, frame_ty, trans.ModuleSha1) + return frame_ty + + # ============================================================ + # create_() -> %Coro_* + # ============================================================ + def _emit_create(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + trans: HT.Translator | t.CPtr, + name: str, + frame_ty: llvmlite.LLVMType | t.CPtr, + nparams: int) -> int: + """生成 create_(args...):M7 帧池弹帧(i64 池头 free-list)或 malloc, + 5 头清零 + 参数存槽(帧槽 5+i)+ ret 帧指针""" + if frame_ty is None: + return 0 + 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) + i64_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i64_ty) + frame_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, frame_ty) + + cname_buf2: str = pool.alloc(64) + if cname_buf2 is not None: + viperlib.snprintf(cname_buf2, 64, "create_%s", name) + mangled: str = self.Gen.FuncGenBase._mangle_func_name( + trans, cname_buf2, 0) + if self.Gen.CallGenBase.find_func_in_module(mod, mangled) is not None: + return 0 + func: llvmlite.Function | t.CPtr = llvmlite.create_function( + pool, mod, mangled, frame_ptr_ty) + if func is None: + return 0 + # 参数(i32,帧槽 5+i)。TPV 无 Python % 格式化(% 是取模), + # 参数名用 snprintf 生成("%%arg" → "%arg",与 resume "%frame" 命名一致)。 + pi: int = 0 + argn_buf: str = pool.alloc(16) + for pi in range(nparams): + if argn_buf is not None: + viperlib.snprintf(argn_buf, 16, "%%arg%d", pi) + llvmlite.add_param(pool, func, i32_ty, argn_buf) + # 注册到函数表(裸名 create_) + funcs_ptr: GenTypes.FuncEntry | t.CPtr = trans._funcs + cur_count: int = trans._func_count + if self.Gen.CallGenLeafKit.add_func_to_table( + funcs_ptr, cur_count, cname_buf2, func, 1024, + None, 0, 0, trans.Pool) == 0: + trans._func_count = cur_count + 1 + + entry: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "entry") + if entry is None: + return 0 + builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) + if builder is None: + return 0 + llvmlite.position_at_end(builder, entry) + + frame_size: int = self.Gen.ClassGenEnum._get_type_size(frame_ty) + size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, frame_size) + if size_val is None: + return 0 + size_val.Next = None + + # M7 帧池:i64 池头(0 = 空);帧首 8 字节存 next(覆盖 state/done,弹池后统一清零) + pool_gv: llvmlite.GlobalVariable | t.CPtr = self._get_coro_pool( + pool, mod, trans, name) + # GlobalVariable 非 Value 子类:构造 Value 视图(Ty=Ptr(i64), Name="@coro_pool_") + pool_ref_name: str = pool.alloc(96) + if pool_ref_name is not None: + viperlib.snprintf(pool_ref_name, 96, "@coro_pool_%s", name) + pool_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, i64_ptr_ty, pool_ref_name) + pool_head: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i64_ty, pool_ref) + if pool_head is None: + return 0 + zero64: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + empty_cond: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_EQ, pool_head, zero64) + if empty_cond is None: + return 0 + hit_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "pool.hit") + miss_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "pool.miss") + join_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "pool.join") + if hit_bb is None or miss_bb is None or join_bb is None: + return 0 + llvmlite.build_cond_br(builder, empty_cond, miss_bb, hit_bb) + # hit:弹池(帧首 8 字节是 next) + llvmlite.position_at_end(builder, hit_bb) + node_next_ptr: llvmlite.Value | t.CPtr = llvmlite.build_inttoptr( + builder, pool_head, i64_ptr_ty) + next_head: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i64_ty, node_next_ptr) + if next_head is None: + return 0 + llvmlite.build_store(builder, next_head, pool_ref) + hit_frame: llvmlite.Value | t.CPtr = llvmlite.build_inttoptr( + builder, pool_head, frame_ptr_ty) + if hit_frame is None: + return 0 + llvmlite.build_br(builder, join_bb) + # miss:malloc + 帧首 8 字节置 0(弹池帧的 next 残留清零) + llvmlite.position_at_end(builder, miss_bb) + raw: llvmlite.Value | t.CPtr = llvmlite.build_call( + builder, "malloc", size_val, 1, i8_ptr_ty, 0) + if raw is None: + return 0 + miss_frame: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, raw, frame_ptr_ty) + if miss_frame is None: + return 0 + miss_head_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, miss_frame, i64_ptr_ty) + if miss_head_ptr is not None: + llvmlite.build_store(builder, zero64, miss_head_ptr) + llvmlite.build_br(builder, join_bb) + # join:phi 选帧 + 5 头清零(弹池复用帧必须重置 state/done/ret/exc/msg)+ 参数存槽 + llvmlite.position_at_end(builder, join_bb) + inc1: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming( + pool, hit_frame, hit_bb) + inc2: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming( + pool, miss_frame, miss_bb) + if inc1 is None or inc2 is None: + return 0 + inc1.Next = inc2 + frame_ref: llvmlite.Value | t.CPtr = llvmlite.build_phi( + builder, frame_ptr_ty, inc1, 2) + if frame_ref is None: + return 0 + zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + null_p: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty, "null") + si: int = 0 + for si in range(5): + if si == 4: + mslot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, frame_ty, i8_ptr_ty, frame_ref, 4) + if mslot is not None: + llvmlite.build_store(builder, null_p, mslot) + else: + slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, frame_ty, i32_ty, frame_ref, si) + if slot is not None: + llvmlite.build_store(builder, zero, slot) + # 参数存帧槽(index 5+i) + pj: int = 0 + for pj in range(nparams): + pslot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, frame_ty, i32_ty, frame_ref, 5 + pj) + if pslot is not None: + arnb: str = pool.alloc(16) + if arnb is not None: + viperlib.snprintf(arnb, 16, "%%arg%d", pj) + arg_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, i32_ty, arnb) + if arg_ref is not None: + llvmlite.build_store(builder, arg_ref, pslot) + llvmlite.build_ret(builder, frame_ref) + return 0 + + # ============================================================ + # M7:每帧类型的全局 free-list 池头(i64,0 = 空) + # ============================================================ + def _get_coro_pool(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + trans: HT.Translator | t.CPtr, + name: str) -> llvmlite.GlobalVariable | t.CPtr: + """取/建 coro_pool_ 全局(i64 池头)。池节点 next 存帧首 8 字节。""" + pn_buf: str = pool.alloc(128) + if pn_buf is not None: + viperlib.snprintf(pn_buf, 128, "coro_pool_%s", name) + # 幂等:create/destroy 都会调用,须先查模块全局链表(无 find_global API) + g: llvmlite.GlobalVariable | t.CPtr = mod.GlobalHead + while g is not None: + if g.Name is not None and string.strcmp(g.Name, pn_buf) == 0: + return g + g = g.Next + return llvmlite.create_global_int(pool, mod, pn_buf, 64, 0) + + def _register_coro_wake(self, trans: HT.Translator | t.CPtr, + name: str, wake_idx: int): + """记录 async 名的 wake 槽 index(_coro_wake_names/_coro_wake_idxs 平行表)""" + if trans is None or name is None or trans._coro_wake_names is None: + return + cnt: int = trans._coro_wake_count + if cnt >= HT.MAX_CORO_FUNCS: + return + addr: t.CUInt64T = t.CUInt64T(trans._coro_wake_names) + cnt * 8 + slot: str | t.CPtr = (t.CVoid | t.CPtr)(addr) + slot[0] = name + trans._coro_wake_idxs[cnt] = wake_idx + trans._coro_wake_count = cnt + 1 + + def _lookup_coro_wake(self, trans: HT.Translator | t.CPtr, + name: str) -> int: + """查 async 名的 wake 槽 index,无 wake 槽返回 -1""" + if trans is None or name is None or trans._coro_wake_names is None: + return -1 + i: int = 0 + for i in range(trans._coro_wake_count): + addr: t.CUInt64T = t.CUInt64T(trans._coro_wake_names) + i * 8 + slot: str | t.CPtr = (t.CVoid | t.CPtr)(addr) + if slot[0] is not None and string.strcmp(slot[0], name) == 0: + return trans._coro_wake_idxs[i] + return -1 + + # ============================================================ + # resume_(%Coro_*) -> i32 状态机(静态段切分) + # ============================================================ + def _emit_resume(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + trans: HT.Translator | t.CPtr, + name: str, + fd: ast.FunctionDef | t.CPtr, + frame_ty: llvmlite.LLVMType | t.CPtr, + nparams: int, nlocals: int, + nextra: int) -> int: + """生成 resume_(frame) -> i32 状态机(M2): + entry 读 state → switch → state0 主入口递归翻译整个函数体; + 每个 await(顶层或嵌套,DFS 序)分配 state{N} 恢复块(预建 case); + exit 块 load done 返回(0=SUSPEND 1=DONE)。""" + if frame_ty is None: + return 0 + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + frame_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, frame_ty) + + rname_buf: str = pool.alloc(64) + if rname_buf is not None: + viperlib.snprintf(rname_buf, 64, "resume_%s", name) + mangled: str = self.Gen.FuncGenBase._mangle_func_name( + trans, rname_buf, 0) + func: llvmlite.Function | t.CPtr = llvmlite.create_function( + pool, mod, mangled, i32_ty) + if func is None: + return 0 + llvmlite.add_param(pool, func, frame_ptr_ty, "%frame") + funcs_ptr: GenTypes.FuncEntry | t.CPtr = trans._funcs + cur_count: int = trans._func_count + if self.Gen.CallGenLeafKit.add_func_to_table( + funcs_ptr, cur_count, rname_buf, func, 1024, + None, 0, 1, trans.Pool) == 0: + trans._func_count = cur_count + 1 + + entry: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "entry") + if entry is None: + return 0 + builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) + if builder is None: + return 0 + llvmlite.position_at_end(builder, entry) + + frame_arg: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, frame_ptr_ty, "%frame") + if frame_arg is None: + return 0 + + # GEP 5 头槽(M4 exc / M7 msg) + i8_ptr_ty_r: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + i64_ty_r: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + state_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, frame_ty, i32_ty, frame_arg, 0) + done_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, frame_ty, i32_ty, frame_arg, 1) + ret_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, frame_ty, i32_ty, frame_arg, 2) + exc_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, frame_ty, i32_ty, frame_arg, 3) + msg_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, frame_ty, i8_ptr_ty_r, frame_arg, 4) + + # 参数槽 GEP → 注册到符号表(index 5+i) + pj: int = 0 + for pj in range(nparams): + pname: str = self._read_param_name(trans, pj) + if pname is None: + continue + pslot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, frame_ty, i32_ty, frame_arg, 5 + pj) + if pslot is not None: + self.Gen.VarGen.define_var(trans.SymTab, pname, pslot) + + # 局部槽 GEP → 注册到符号表 + li: int = 0 + for li in range(nlocals): + lname: str = self._read_local_name(trans, li) + if lname is None: + continue + slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, frame_ty, i32_ty, frame_arg, + trans._coro_local_base + li) + if slot is not None: + self.Gen.VarGen.define_var(trans.SymTab, lname, slot) + + # M3-M7:额外槽注册(wake i64 / __f_idx/__f_len/__await i32)。 + # 名字反查:wake=uses_sleep 且 ei==0;for=位置数组 _coro_for_slots; + # 其余按 _coro_await_slots 反查 __await_M。 + ei: int = 0 + for ei in range(nextra): + ety: int = 1 + if trans._coro_extra_types is not None: + ety = trans._coro_extra_types[ei] + ety_llvm: llvmlite.LLVMType | t.CPtr = i32_ty + if ety == 2: + ety_llvm = i64_ty_r + eslot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, frame_ty, ety_llvm, frame_arg, + trans._coro_extra_base + ei) + if eslot is None: + continue + # wake 槽:只存指针,不注册 SymTab(coro_run 轮询用) + if trans._coro_uses_sleep != 0 and ei == 0: + trans._coro_wake_ptr = eslot + continue + ename: str = pool.alloc(16) + # for 槽:_coro_for_slots[N] 是 __f_idx_N 位置,+1 是 __f_len_N + is_for: int = 0 + is_len: int = 0 + kf: int = 0 + for kf in range(trans._coro_scan_for_count): + if trans._coro_for_slots[kf] == ei: + is_for = 1 + break + if trans._coro_for_slots[kf] + 1 == ei: + is_for = 1 + is_len = 1 + break + if is_for != 0: + if ename is not None: + if is_len != 0: + viperlib.snprintf(ename, 16, "__f_len_%d", kf) + else: + viperlib.snprintf(ename, 16, "__f_idx_%d", kf) + else: + # __await_M:反查位置数组 + found: int = 0 + km: int = 0 + for km in range(nextra): + if trans._coro_await_slots[km] == ei: + found = 1 + break + if found == 0: + continue + if ename is not None: + viperlib.snprintf(ename, 16, "__await_%d", km) + if ename is not None: + self.Gen.VarGen.define_var(trans.SymTab, ename, eslot) + + # state 值 + exit 块 + state_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i32_ty, state_ptr) + exit_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "coro.exit") + if exit_bb is None: + return 0 + + # 保存 resume 上下文(await 挂起 / 恢复块共享) + trans._coro_state_ptr = state_ptr + trans._coro_done_ptr = done_ptr + trans._coro_ret_ptr = ret_ptr + trans._coro_exc_ptr = exc_ptr + trans._coro_msg_ptr = msg_ptr + trans._coro_wake_ptr = None + trans._coro_exit_bb = exit_bb + trans._coro_frame = frame_arg + trans._coro_await_slot = None + # state0 是入口,await 从状态号 1 开始(与预扫描 DFS 序一致) + trans._coro_next_state = 1 + # 翻译期序号(与预扫描同序) + trans._coro_hoist_count = 0 + trans._coro_for_counter = 0 + trans._coro_try_stack_count = 0 + trans._coro_break_bb = None + trans._coro_continue_bb = None + + nseg: int = trans._coro_nseg + if nseg <= 0: + nseg = 1 + # 预建 state 块 + switch case(一次性生成,await 恢复块 position 填充) + state_bbs: t.CSizeT | t.CPtr = pool.alloc(nseg * 8) + if state_bbs is None: + return 0 + trans._coro_state_bbs = state_bbs + sw_head: llvmlite.SwitchCase | t.CPtr = None + sw_tail: llvmlite.SwitchCase | t.CPtr = None + sw_count: int = 0 + bb_name: str = pool.alloc(32) + si: int = 0 + for si in range(nseg): + if bb_name is not None: + viperlib.snprintf(bb_name, 32, "state%d", si) + sbb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, bb_name) + if sbb is None: + continue + state_bbs[si] = t.CSizeT(sbb) + sc: llvmlite.SwitchCase | t.CPtr = llvmlite.new_switch_case( + pool, llvmlite.const_int32(pool, si), sbb) + 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 + llvmlite.build_switch(builder, state_val, exit_bb, sw_head, sw_count) + + # ---- state0 主入口:递归翻译整个函数体(If/While 内 await 动态恢复)---- + # 标准语句翻译(translate_stmt → translate_assign/annassign 等)从 + # trans._cur_builder/_cur_func 取当前 IRBuilder/Function——必须在此设置, + # 后续 position_at_end 都作用于同一 builder 对象,_cur_builder 引用不变。 + trans._cur_func = func + trans._cur_builder = builder + seg_bb: llvmlite.BasicBlock | t.CPtr = (llvmlite.BasicBlock | t.CPtr)( + t.CVoid(state_bbs[0], t.CPtr)) + llvmlite.position_at_end(builder, seg_bb) + self._handle_segment(trans, builder, pool, mod, fd.children) + # 函数体自然结束 → 隐式 return(ret=0 + done=1 + br exit) + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + zret: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + done_one: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) + llvmlite.build_store(builder, zret, ret_ptr) + llvmlite.build_store(builder, done_one, done_ptr) + llvmlite.build_br(builder, exit_bb) + + # exit 块:load done 返回(0=SUSPEND 1=DONE) + llvmlite.position_at_end(builder, exit_bb) + done_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i32_ty, done_ptr) + llvmlite.build_ret(builder, done_val) + return 0 + + # ============================================================ + # M2:协程体递归翻译(Return/顶层 await/If/While/嵌套 await/普通) + # ============================================================ + def _handle_segment(self, trans: HT.Translator | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + stmts: list[ast.AST | t.CPtr] | t.CPtr): + """递归翻译协程体语句。builder 当前块 = 活跃执行块(state0 或某恢复块)。""" + if stmts is None: + return + bn: t.CSizeT = len(stmts) + i: t.CSizeT = 0 + for i in range(bn): + stmt: ast.AST | t.CPtr = stmts.get(i) + if stmt is None: + continue + # 当前块已终止(return/挂起后无后续)→ 停止本段 + if llvmlite.builder_cur_block_is_terminated(builder) != 0: + return + sk: int = stmt.kind() + if sk == ast.ASTKind.Return: + self._emit_coro_return(builder, pool, mod, trans, stmt) + continue + if sk == ast.ASTKind.If: + self._handle_coro_if(trans, builder, pool, mod, stmt) + continue + if sk == ast.ASTKind.While: + self._handle_coro_while(trans, builder, pool, mod, stmt) + continue + if sk == ast.ASTKind.Raise: + self._handle_coro_raise(builder, pool, mod, trans, stmt) + continue + if sk == ast.ASTKind.Try: + tr_: ast.Try | t.CPtr = (ast.Try | t.CPtr)(stmt) + has_fin: int = 0 + has_exc: int = 0 + if tr_.finalbody is not None and len(tr_.finalbody) > 0: + has_fin = 1 + if tr_.handlers is not None and len(tr_.handlers) > 0: + has_exc = 1 + if has_fin != 0 and has_exc == 0: + self._handle_coro_try_finally(trans, builder, pool, mod, stmt) + else: + self._handle_coro_try(trans, builder, pool, mod, stmt) + continue + if sk == ast.ASTKind.For: + if self._for_deep_await(stmt) != 0: + self._handle_coro_for(trans, builder, pool, mod, stmt) + else: + # 无 await:委托标准 For + self.Gen.StmtGen.translate_stmt(trans, stmt) + continue + if sk == ast.ASTKind.Break: + if trans._coro_break_bb is not None: + llvmlite.build_br(builder, trans._coro_break_bb) + continue + if sk == ast.ASTKind.Continue: + if trans._coro_continue_bb is not None: + llvmlite.build_br(builder, trans._coro_continue_bb) + continue + if sk == ast.ASTKind.Pass: + continue + # 顶层 await:AnnAssign/Assign/Expr 的 value 直接是 Await → 挂起 + if sk == ast.ASTKind.AnnAssign or sk == ast.ASTKind.Assign or sk == ast.ASTKind.Expr: + if self._is_await_tail(stmt) != 0: + target_name: str = self._get_assign_target_name(stmt) + if target_name is not None: + trans._coro_await_slot = self.Gen.VarGen.lookup_var( + trans.SymTab, target_name) + else: + # Expr(await ...):无目标槽(丢弃返回值),防残留旧槽 + trans._coro_await_slot = None + aw_node: ast.Await | t.CPtr = self._get_await_value(stmt) + call_name: str = None + if aw_node is not None: + call_name = self._extract_await_call_name(aw_node) + if call_name is not None and self.is_async_func(trans, call_name) != 0: + self._emit_await(builder, pool, mod, trans, aw_node, call_name) + else: + if call_name is None: + call_name = "(unknown)" + err_buf: str = pool.alloc(256) + if err_buf is not None: + viperlib.snprintf( + err_buf, 256, + "[coro-M2] await 目标 '%s' 不是 async 函数", call_name) + self.Gen.TypeGenErr.fatal_error(stmt, err_buf, "SyntaxError") + continue + # 语句内嵌套 await → 提升为 __await_N + if self._stmt_has_await(stmt) != 0: + self._handle_nested_await_stmt(trans, builder, pool, mod, stmt) + continue + # 其它语句 → 标准翻译 + self.Gen.StmtGen.translate_stmt(trans, stmt) + + # ============================================================ + # M2:协程版 If(分支内 await 就地挂起/恢复) + # ============================================================ + def _handle_coro_if(self, trans: HT.Translator | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + stmt: ast.AST | t.CPtr): + ifn: ast.If | t.CPtr = (ast.If | t.CPtr)(stmt) + if ifn is None or ifn.test is None: + return + if self._find_expr_await(ifn.test) is not None: + err_b: str = pool.alloc(256) + if err_b is not None: + viperlib.snprintf(err_b, 256, "[coro-M2] if 条件中不支持 await") + self.Gen.TypeGenErr.fatal_error(stmt, err_b, "SyntaxError") + return + cond: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, ifn.test, None, 0, trans) + if cond is None: + return + cond1: llvmlite.Value | t.CPtr = self._normalize_cond(builder, pool, cond) + func: llvmlite.Function | t.CPtr = trans._cur_func + then_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "coro.then") + merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "coro.end") + has_else: int = 0 + if ifn.orelse is not None and len(ifn.orelse) > 0: + has_else = 1 + else_bb: llvmlite.BasicBlock | t.CPtr = None + if has_else != 0: + else_bb = llvmlite.create_block(pool, func, "coro.else") + if cond1 is None or then_bb is None or merge_bb is None: + return + llvmlite.build_cond_br(builder, cond1, then_bb, + else_bb if else_bb is not None else merge_bb) + # then 分支 + llvmlite.position_at_end(builder, then_bb) + self._handle_segment(trans, builder, pool, mod, stmt.children) + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, merge_bb) + # else 分支 + if else_bb is not None: + llvmlite.position_at_end(builder, else_bb) + self._handle_segment(trans, builder, pool, mod, ifn.orelse) + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, merge_bb) + llvmlite.position_at_end(builder, merge_bb) + + # ============================================================ + # M2:协程版 While(条件块 + 循环体,body 内 await 就地挂起/恢复) + # ============================================================ + def _handle_coro_while(self, trans: HT.Translator | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + stmt: ast.AST | t.CPtr): + whn: ast.While | t.CPtr = (ast.While | t.CPtr)(stmt) + if whn is None: + return + if whn.test is not None and self._find_expr_await(whn.test) is not None: + err_c: str = pool.alloc(256) + if err_c is not None: + viperlib.snprintf(err_c, 256, "[coro-M2] while 条件中不支持 await") + self.Gen.TypeGenErr.fatal_error(stmt, err_c, "SyntaxError") + return + func: llvmlite.Function | t.CPtr = trans._cur_func + cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "coro.wcond") + body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "coro.wbody") + after_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "coro.wend") + if cond_bb is None or body_bb is None or after_bb is None: + return + # break/continue 目标(M2 单层) + prev_break: llvmlite.BasicBlock | t.CPtr = trans._coro_break_bb + prev_cont: llvmlite.BasicBlock | t.CPtr = trans._coro_continue_bb + trans._coro_break_bb = after_bb + trans._coro_continue_bb = cond_bb + llvmlite.build_br(builder, cond_bb) + # 条件块 + llvmlite.position_at_end(builder, cond_bb) + cond: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, whn.test, None, 0, trans) + if cond is None: + cond = llvmlite.const_int32(pool, 0) + cond1: llvmlite.Value | t.CPtr = self._normalize_cond(builder, pool, cond) + llvmlite.build_cond_br(builder, cond1, body_bb, after_bb) + # 循环体 + llvmlite.position_at_end(builder, body_bb) + self._handle_segment(trans, builder, pool, mod, stmt.children) + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, cond_bb) + trans._coro_break_bb = prev_break + trans._coro_continue_bb = prev_cont + # 循环结束块 + llvmlite.position_at_end(builder, after_bb) + + # ============================================================ + # M2:嵌套 await 提升:a = b + await f() → __await_N = await f(); a = b + __await_N + # ============================================================ + def _handle_nested_await_stmt(self, trans: HT.Translator | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + stmt: ast.AST | t.CPtr): + """把语句中所有嵌套 await 提升为顶层临时赋值(与预扫描 DFS 顺序一致)""" + guard: int = 0 + while True: + aw_node: ast.Await | t.CPtr = self._extract_first_await(stmt) + if aw_node is None: + break + if guard >= HT.MAX_CORO_VARS: + break + guard = guard + 1 + temp_name: str = pool.alloc(32) + if temp_name is not None: + viperlib.snprintf( + temp_name, 32, "__await_%d", trans._coro_hoist_count) + # 目标槽 = __await_N 帧额外槽(预扫描位置数组,wake/for 槽穿插在前) + slot_idx: int = trans._coro_extra_base + trans._coro_await_slots[trans._coro_hoist_count] + trans._coro_hoist_count = trans._coro_hoist_count + 1 + slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, self._lookup_coro_frame_by_trans(trans), + llvmlite.Int32(pool), trans._coro_frame, slot_idx) + trans._coro_await_slot = slot + call_name: str = self._extract_await_call_name(aw_node) + if call_name is None: + break + self._emit_await(builder, pool, mod, trans, aw_node, call_name) + self._replace_await_with_name(pool, stmt, temp_name) + # 提升完成 → 标准翻译(恢复块内继续执行剩余表达式) + self.Gen.StmtGen.translate_stmt(trans, stmt) + + # ============================================================ + # 嵌套 await 存在性 / 提取 / 替换(DFS 与预扫描同序) + # ============================================================ + def _stmt_has_await(self, stmt: ast.AST | t.CPtr) -> int: + aw: ast.Await | t.CPtr = self._extract_first_await(stmt) + if aw is not None: + return 1 + return 0 + + def _extract_first_await(self, stmt: ast.AST | t.CPtr) -> ast.Await | t.CPtr: + """取语句中第一个 Await 节点(DFS 字段序),未命中返回 None""" + if stmt is None: + return None + sk: int = stmt.kind() + if sk == ast.ASTKind.AnnAssign: + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) + return self._find_expr_await(aa.value) + if sk == ast.ASTKind.Assign: + as_: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) + return self._find_expr_await(as_.value) + if sk == ast.ASTKind.Expr: + e: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(stmt) + return self._find_expr_await(e.value) + if sk == ast.ASTKind.Return: + rv: ast.Return | t.CPtr = (ast.Return | t.CPtr)(stmt) + return self._find_expr_await(rv.value) + return None + + def _find_expr_await(self, node: ast.AST | t.CPtr) -> ast.Await | t.CPtr: + """表达式树中 DFS 找第一个 Await""" + if node is None: + return None + k: int = node.kind() + if k == ast.ASTKind.Await: + return (ast.Await | t.CPtr)(node) + if k == ast.ASTKind.BinOp: + b: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + r: ast.Await | t.CPtr = self._find_expr_await(b.left) + if r is not None: + return r + return self._find_expr_await(b.right) + if k == ast.ASTKind.Call: + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + if cl.func is not None: + r2: ast.Await | t.CPtr = self._find_expr_await(cl.func) + if r2 is not None: + return r2 + if cl.args is not None: + nb: t.CSizeT = len(cl.args) + j: t.CSizeT = 0 + for j in range(nb): + r3: ast.Await | t.CPtr = self._find_expr_await(cl.args.get(j)) + if r3 is not None: + return r3 + return None + if k == ast.ASTKind.UnaryOp: + u: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + return self._find_expr_await(u.operand) + if k == ast.ASTKind.Compare: + cm: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) + r4: ast.Await | t.CPtr = self._find_expr_await(cm.left) + if r4 is not None: + return r4 + if cm.comparators is not None: + nb2: t.CSizeT = len(cm.comparators) + j2: t.CSizeT = 0 + for j2 in range(nb2): + r5: ast.Await | t.CPtr = self._find_expr_await(cm.comparators.get(j2)) + if r5 is not None: + return r5 + return None + if k == ast.ASTKind.BoolOp: + bo: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) + if bo.values is not None: + nb3: t.CSizeT = len(bo.values) + j3: t.CSizeT = 0 + for j3 in range(nb3): + r6: ast.Await | t.CPtr = self._find_expr_await(bo.values.get(j3)) + if r6 is not None: + return r6 + return None + if k == ast.ASTKind.IfExp: + ie: ast.IfExp | t.CPtr = (ast.IfExp | t.CPtr)(node) + r7: ast.Await | t.CPtr = self._find_expr_await(ie.test) + if r7 is not None: + return r7 + r8: ast.Await | t.CPtr = self._find_expr_await(ie.body) + if r8 is not None: + return r8 + return self._find_expr_await(ie.orelse) + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + return self._find_expr_await(at.value) + if k == ast.ASTKind.Subscript: + sb: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + r9: ast.Await | t.CPtr = self._find_expr_await(sb.value) + if r9 is not None: + return r9 + return self._find_expr_await(sb.slice) + return None + + def _replace_await_with_name(self, pool: memhub.MemBuddy | t.CPtr, + stmt: ast.AST | t.CPtr, + temp_name: str) -> int: + """把语句树中第一个 Await 替换为 Name(temp_name)(DFS 字段序)""" + if stmt is None or temp_name is None: + return 0 + sk: int = stmt.kind() + if sk == ast.ASTKind.AnnAssign: + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) + if aa.value is not None: + return self._replace_expr_await(pool, aa.value, temp_name) + return 0 + if sk == ast.ASTKind.Assign: + as_: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) + if as_.value is not None: + return self._replace_expr_await(pool, as_.value, temp_name) + return 0 + if sk == ast.ASTKind.Expr: + e: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(stmt) + if e.value is not None: + return self._replace_expr_await(pool, e.value, temp_name) + return 0 + if sk == ast.ASTKind.Return: + rv: ast.Return | t.CPtr = (ast.Return | t.CPtr)(stmt) + if rv.value is not None: + return self._replace_expr_await(pool, rv.value, temp_name) + return 0 + return 0 + + def _replace_expr_await(self, pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr, + temp_name: str) -> int: + """在表达式树中把第一个 Await 替换为 Name(temp_name, Load)。 + node 本身是 Await 时返回 2(由父字段替换)。返回 1=已替换 0=无 2=node 即 Await。""" + if node is None: + return 0 + k: int = node.kind() + if k == ast.ASTKind.Await: + return 2 + if k == ast.ASTKind.BinOp: + b: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + r: int = self._replace_expr_await(pool, b.left, temp_name) + if r == 1: + return 1 + if r == 2: + b.left = ast.Name(pool, temp_name, 0) + return 1 + r2: int = self._replace_expr_await(pool, b.right, temp_name) + if r2 == 1: + return 1 + if r2 == 2: + b.right = ast.Name(pool, temp_name, 0) + return 1 + return 0 + if k == ast.ASTKind.Call: + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + if cl.func is not None: + r3: int = self._replace_expr_await(pool, cl.func, temp_name) + if r3 == 1: + return 1 + if r3 == 2: + cl.func = ast.Name(pool, temp_name, 0) + return 1 + if cl.args is not None: + nb: t.CSizeT = len(cl.args) + j: t.CSizeT = 0 + for j in range(nb): + r4: int = self._replace_expr_await(pool, cl.args.get(j), temp_name) + if r4 == 1: + return 1 + if r4 == 2: + cl.args.set(j, ast.Name(pool, temp_name, 0)) + return 1 + return 0 + if k == ast.ASTKind.UnaryOp: + u: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + r5: int = self._replace_expr_await(pool, u.operand, temp_name) + if r5 == 1: + return 1 + if r5 == 2: + u.operand = ast.Name(pool, temp_name, 0) + return 1 + return 0 + if k == ast.ASTKind.Compare: + cm: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) + r6: int = self._replace_expr_await(pool, cm.left, temp_name) + if r6 == 1: + return 1 + if r6 == 2: + cm.left = ast.Name(pool, temp_name, 0) + return 1 + if cm.comparators is not None: + nb2: t.CSizeT = len(cm.comparators) + j2: t.CSizeT = 0 + for j2 in range(nb2): + r7: int = self._replace_expr_await(pool, cm.comparators.get(j2), temp_name) + if r7 == 1: + return 1 + if r7 == 2: + cm.comparators.set(j2, ast.Name(pool, temp_name, 0)) + return 1 + return 0 + if k == ast.ASTKind.BoolOp: + bo: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) + if bo.values is not None: + nb3: t.CSizeT = len(bo.values) + j3: t.CSizeT = 0 + for j3 in range(nb3): + r8: int = self._replace_expr_await(pool, bo.values.get(j3), temp_name) + if r8 == 1: + return 1 + if r8 == 2: + bo.values.set(j3, ast.Name(pool, temp_name, 0)) + return 1 + return 0 + if k == ast.ASTKind.IfExp: + ie: ast.IfExp | t.CPtr = (ast.IfExp | t.CPtr)(node) + r9: int = self._replace_expr_await(pool, ie.test, temp_name) + if r9 == 1: + return 1 + if r9 == 2: + ie.test = ast.Name(pool, temp_name, 0) + return 1 + r10: int = self._replace_expr_await(pool, ie.body, temp_name) + if r10 == 1: + return 1 + if r10 == 2: + ie.body = ast.Name(pool, temp_name, 0) + return 1 + r11: int = self._replace_expr_await(pool, ie.orelse, temp_name) + if r11 == 1: + return 1 + if r11 == 2: + ie.orelse = ast.Name(pool, temp_name, 0) + return 1 + return 0 + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + r12: int = self._replace_expr_await(pool, at.value, temp_name) + if r12 == 1: + return 1 + if r12 == 2: + at.value = ast.Name(pool, temp_name, 0) + return 1 + return 0 + if k == ast.ASTKind.Subscript: + sb: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + r13: int = self._replace_expr_await(pool, sb.value, temp_name) + if r13 == 1: + return 1 + if r13 == 2: + sb.value = ast.Name(pool, temp_name, 0) + return 1 + r14: int = self._replace_expr_await(pool, sb.slice, temp_name) + if r14 == 1: + return 1 + if r14 == 2: + sb.slice = ast.Name(pool, temp_name, 0) + return 1 + return 0 + return 0 + + # ============================================================ + # 条件归一化(i1 直通;其余 icmp ne 0) + # ============================================================ + def _normalize_cond(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + cond: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: + if cond is None: + return None + ty: llvmlite.LLVMType | t.CPtr = cond.Ty + is_i1: int = 0 + if ty is not None: + match ty: + case LLVMType.Int(): + if ty.Bits == 1: + is_i1 = 1 + case _: + pass + if is_i1 != 0: + return cond + zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, ty) + return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond, zero) + + # ============================================================ + # 参数名读取(_coro_params 表) + # ============================================================ + def _read_param_name(self, trans: HT.Translator | t.CPtr, + idx: int) -> str: + if trans is None or trans._coro_params is None: + return None + addr: t.CUInt64T = t.CUInt64T(trans._coro_params) + idx * 8 + slot: str | t.CPtr = (t.CVoid | t.CPtr)(addr) + return slot[0] + + # ============================================================ + # 恢复块定位(state{N},预建数组) + # ============================================================ + def _get_state_bb(self, trans: HT.Translator | t.CPtr, + state_no: int) -> llvmlite.BasicBlock | t.CPtr: + if trans is None or trans._coro_state_bbs is None: + return None + if state_no < 0 or state_no >= trans._coro_nseg: + return None + # 注意:state_bbs 数组存的是块指针(t.CSizeT),必须下标取值, + # 不能取元素地址(t.CUInt64T(数组)+idx*8 是地址,会导致 position + # 到非法块 → IR 指令链损坏 → RenumberSSA/FunctionPrint 崩溃)。 + return (llvmlite.BasicBlock | t.CPtr)( + t.CVoid(trans._coro_state_bbs[state_no], t.CPtr)) + + def _lookup_coro_frame_by_trans(self, trans: HT.Translator | t.CPtr) -> llvmlite.LLVMType | t.CPtr: + """取当前 resume 的帧类型:从 _coro_frames 反查(当前 async 名未知时用帧指针类型不可行, + 直接返回当前协程注册的帧类型——_handle_nested_await_stmt 需要帧类型做 GEP。""" + # 简化:恢复块 GEP 需要帧类型;从 _coro_frame 的 Ty(Ptr(帧))取 Pointee + if trans is None or trans._coro_frame is None: + return None + ft: llvmlite.LLVMType | t.CPtr = trans._coro_frame.Ty + if ft is None: + return None + match ft: + case LLVMType.Ptr(): + return ft.Pointee + case _: + return None + + # ============================================================ + # M3:await coro_sleep(ms) —— wake 槽挂起(coro_run 轮询续跑) + # ============================================================ + def _emit_await_sleep(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> llvmlite.Value | t.CPtr: + """await coro_sleep(ms):wake = GetTickCount64() + ms 存帧 wake 槽, + 父挂起(state 分配 + br exit + position 恢复块);coro_run 轮询续跑。""" + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if node is None or trans is None or trans._coro_wake_ptr is None: + return llvmlite.const_int32(pool, 0) + ms_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + aw_s: ast.Await | t.CPtr = (ast.Await | t.CPtr)(node) + if aw_s.value is not None and aw_s.value.kind() == ast.ASTKind.Call: + cl_s: ast.Call | t.CPtr = (ast.Call | t.CPtr)(aw_s.value) + if cl_s.args is not None and len(cl_s.args) > 0: + ms_v: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cl_s.args.get(0), None, 0, trans) + if ms_v is not None: + ms_val = ms_v + # GetTickCount64() + ms(i64) + now_fn: llvmlite.Function | t.CPtr = self.Gen.CallGenBase.find_func_in_module( + mod, "GetTickCount64") + if now_fn is None: + now_fn = llvmlite.create_declare(pool, mod, "GetTickCount64", i64_ty) + if now_fn is None: + return llvmlite.const_int32(pool, 0) + now_val: llvmlite.Value | t.CPtr = llvmlite.build_call( + builder, "GetTickCount64", None, 0, i64_ty, 0) + if now_val is None: + return llvmlite.const_int32(pool, 0) + wake_val: llvmlite.Value | t.CPtr = llvmlite.build_add( + builder, now_val, ms_val) + if wake_val is None: + return llvmlite.const_int32(pool, 0) + llvmlite.build_store(builder, wake_val, trans._coro_wake_ptr) + # 父挂起:新状态号 + br exit + position 恢复块 + new_state_s: int = trans._coro_next_state + trans._coro_next_state = new_state_s + 1 + st_v_s: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, new_state_s) + llvmlite.build_store(builder, st_v_s, trans._coro_state_ptr) + llvmlite.build_br(builder, trans._coro_exit_bb) + resume_bb_s: llvmlite.BasicBlock | t.CPtr = self._get_state_bb( + trans, new_state_s) + if resume_bb_s is not None: + llvmlite.position_at_end(builder, resume_bb_s) + return llvmlite.const_int32(pool, 0) + + # ============================================================ + # M4-M6:协程内 raise(异常类型/值 → 帧 exc 槽) + # ============================================================ + def _handle_coro_raise(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + trans: HT.Translator | t.CPtr, + stmt: ast.AST | t.CPtr): + """协程内 raise:解析异常类型/值 → 帧 exc 槽(+msg); + try 栈非空跳 except 处理器,否则 done=1 + br exit 终止。""" + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + exc_code: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) + rz: ast.Raise | t.CPtr = (ast.Raise | t.CPtr)(stmt) + if rz is not None and rz.exc is not None: + code: int = self._resolve_raise_code(pool, rz.exc) + if code != 0: + exc_code = llvmlite.const_int32(pool, code) + # M7:异常消息(Exception("msg") 首参) + msg_v: llvmlite.Value | t.CPtr = self._resolve_raise_msg( + builder, pool, mod, trans, rz.exc) + if msg_v is not None and trans._coro_msg_ptr is not None: + llvmlite.build_store(builder, msg_v, trans._coro_msg_ptr) + else: + v: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, rz.exc, None, 0, trans) + if v is not None: + exc_code = v + if trans._coro_exc_ptr is not None: + llvmlite.build_store(builder, exc_code, trans._coro_exc_ptr) + # 跳 try except / 终止 + if trans._coro_try_stack_count > 0: + tbb_r: llvmlite.BasicBlock | t.CPtr = ( + llvmlite.BasicBlock | t.CPtr)(t.CVoid( + trans._coro_try_stack[trans._coro_try_stack_count - 1], + t.CPtr)) + llvmlite.build_br(builder, tbb_r) + else: + done_r: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) + llvmlite.build_store(builder, done_r, trans._coro_done_ptr) + llvmlite.build_br(builder, trans._coro_exit_bb) + + def _resolve_raise_code(self, pool: memhub.MemBuddy | t.CPtr, + exc_node: ast.AST | t.CPtr) -> int: + """解析 raise 目标的异常码(内置/用户异常类名);非异常类返回 0""" + if exc_node is None: + return 0 + name: str = None + if exc_node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(exc_node) + name = nm.id + elif exc_node.kind() == ast.ASTKind.Call: + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(exc_node) + if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: + nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl.func) + name = nm2.id + elif exc_node.kind() == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(exc_node) + name = at.attr + if name is None: + return 0 + return self.Gen.ClassGenBase.lookup_exception_code(name) + + def _resolve_raise_msg(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + trans: HT.Translator | t.CPtr, + exc_node: ast.AST | t.CPtr) -> llvmlite.Value | t.CPtr: + """取异常消息表达式(Exception("msg") 首参),无则返回 None""" + if exc_node is None or exc_node.kind() != ast.ASTKind.Call: + return None + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(exc_node) + if cl.args is None or len(cl.args) < 1: + return None + return self.Gen.ExprGen.translate_value( + builder, pool, mod, cl.args.get(0), None, 0, trans) + + # ============================================================ + # M5-M6:协程内 try/except(多 except 链式匹配 + 类型码 + as e 绑定) + # ============================================================ + def _handle_coro_try(self, trans: HT.Translator | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + stmt: ast.AST | t.CPtr): + """协程内 try/except:raise/await 传播异常在 try 栈内改跳 except 处理器; + 多 except 按声明序匹配(含子类码集合),Exception/裸 except 捕获所有; + 全不匹配重新传播(done=1 + br exit)。""" + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + tr: ast.Try | t.CPtr = (ast.Try | t.CPtr)(stmt) + if tr is None: + return + nhandlers: int = 0 + if tr.handlers is not None: + nhandlers = len(tr.handlers) + if nhandlers == 0: + err_t: str = pool.alloc(256) + if err_t is not None: + viperlib.snprintf(err_t, 256, "[coro-M6] 协程内 try 需要 except 子句") + self.Gen.TypeGenErr.fatal_error(stmt, err_t, "SyntaxError") + return + func: llvmlite.Function | t.CPtr = trans._cur_func + except_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "coro.try_except") + merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "coro.try_merge") + if except_bb is None or merge_bb is None: + return + # try 栈 push + if trans._coro_try_stack_count < HT.MAX_CORO_TRY: + trans._coro_try_stack[trans._coro_try_stack_count] = t.CSizeT(except_bb) + trans._coro_try_stack_count = trans._coro_try_stack_count + 1 + # try body + self._handle_segment(trans, builder, pool, mod, stmt.children) + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, merge_bb) + if trans._coro_try_stack_count > 0: + trans._coro_try_stack_count = trans._coro_try_stack_count - 1 + # ---- 异常分发:exc 码依次匹配各 except ---- + llvmlite.position_at_end(builder, except_bb) + exc_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i32_ty, trans._coro_exc_ptr) + # 预建 check/handler/unmatched 块 + check_bbs: t.CSizeT | t.CPtr = pool.alloc((nhandlers + 1) * 8) + handler_bbs: t.CSizeT | t.CPtr = pool.alloc(nhandlers * 8) + if check_bbs is None or handler_bbs is None: + return + check_bbs[0] = t.CSizeT(except_bb) + hi: int = 0 + for hi in range(nhandlers): + check_bbs[hi + 1] = t.CSizeT(llvmlite.create_block( + pool, func, "coro.exc_check_%d" % hi)) + handler_bbs[hi] = t.CSizeT(llvmlite.create_block( + pool, func, "coro.except_%d" % hi)) + unmatched_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "coro.try_reraise") + codes_buf: t.CInt | t.CPtr = pool.alloc(256) + # 每个 handler:check 链 + for hi in range(nhandlers): + h_node: ast.AST | t.CPtr = tr.handlers.get(hi) + check_bb: llvmlite.BasicBlock | t.CPtr = ( + llvmlite.BasicBlock | t.CPtr)(t.CVoid(check_bbs[hi], t.CPtr)) + llvmlite.position_at_end(builder, check_bb) + catch_all: int = 0 + ncodes: int = 0 + if h_node is not None: + hd: ast.ExceptHandler | t.CPtr = (ast.ExceptHandler | t.CPtr)(h_node) + if hd.type is None: + catch_all = 1 + else: + ename: str = self._exception_type_name(pool, hd.type) + if ename is not None and string.strcmp(ename, "Exception") == 0: + catch_all = 1 + else: + ncodes = self.Gen.ClassGenBase.collect_descendant_codes( + ename, codes_buf, 64) + next_check: llvmlite.BasicBlock | t.CPtr = None + if hi + 1 < nhandlers: + next_check = (llvmlite.BasicBlock | t.CPtr)( + t.CVoid(check_bbs[hi + 1], t.CPtr)) + else: + next_check = unmatched_bb + handler_bb: llvmlite.BasicBlock | t.CPtr = ( + llvmlite.BasicBlock | t.CPtr)(t.CVoid(handler_bbs[hi], t.CPtr)) + if catch_all != 0: + llvmlite.build_br(builder, handler_bb) + else: + match_cond: llvmlite.Value | t.CPtr = None + ci: int = 0 + for ci in range(ncodes): + eq_v: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_EQ, exc_val, + llvmlite.const_int32(pool, codes_buf[ci])) + if match_cond is None: + match_cond = eq_v + else: + match_cond = llvmlite.build_or(builder, match_cond, eq_v) + if match_cond is None: + llvmlite.build_br(builder, next_check) + else: + llvmlite.build_cond_br(builder, match_cond, handler_bb, next_check) + # 未匹配:异常继续传播(重新终止协程) + llvmlite.position_at_end(builder, unmatched_bb) + done_u: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) + llvmlite.build_store(builder, done_u, trans._coro_done_ptr) + llvmlite.build_br(builder, trans._coro_exit_bb) + # ---- 各 except handler ---- + for hi in range(nhandlers): + h_node2: ast.AST | t.CPtr = tr.handlers.get(hi) + handler_bb2: llvmlite.BasicBlock | t.CPtr = ( + llvmlite.BasicBlock | t.CPtr)(t.CVoid(handler_bbs[hi], t.CPtr)) + llvmlite.position_at_end(builder, handler_bb2) + if h_node2 is not None: + hd2: ast.ExceptHandler | t.CPtr = (ast.ExceptHandler | t.CPtr)(h_node2) + # as e:异常码绑定 e 槽(e 是局部槽,_collect_local_names 收集) + if hd2.name is not None and trans._coro_exc_ptr is not None: + e_slot: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, hd2.name) + if e_slot is not None: + hv: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i32_ty, trans._coro_exc_ptr) + llvmlite.build_store(builder, hv, e_slot) + # 捕获后清帧 exc + z_clr: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + llvmlite.build_store(builder, z_clr, trans._coro_exc_ptr) + self._handle_segment(trans, builder, pool, mod, h_node2.children) + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, merge_bb) + llvmlite.position_at_end(builder, merge_bb) + + def _exception_type_name(self, pool: memhub.MemBuddy | t.CPtr, + type_node: ast.AST | t.CPtr) -> str: + """取 except 类型名(Name/Attribute),未命中返回 None""" + if type_node is None: + return None + if type_node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(type_node) + return nm.id + if type_node.kind() == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(type_node) + return at.attr + return None + + # ============================================================ + # M7:协程内 try/finally(无 except) + # ============================================================ + def _handle_coro_try_finally(self, trans: HT.Translator | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + stmt: ast.AST | t.CPtr): + """协程内 try/finally:正常/异常路径都执行 fbody; + 异常时 finally 后重新传播(done=1 + br exit);finally 内不支持 await。""" + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + tr: ast.Try | t.CPtr = (ast.Try | t.CPtr)(stmt) + if tr is None: + return + if tr.finalbody is not None and self._stmts_deep_await(tr.finalbody) != 0: + err_f: str = pool.alloc(256) + if err_f is not None: + viperlib.snprintf(err_f, 256, "[coro-M7] finally 内暂不支持 await") + self.Gen.TypeGenErr.fatal_error(stmt, err_f, "SyntaxError") + return + func: llvmlite.Function | t.CPtr = trans._cur_func + fin_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "coro.fin") + fin_exc_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "coro.fin_exc") + merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "coro.fin_merge") + if fin_bb is None or fin_exc_bb is None or merge_bb is None: + return + # try 栈 push(异常跳 finally) + if trans._coro_try_stack_count < HT.MAX_CORO_TRY: + trans._coro_try_stack[trans._coro_try_stack_count] = t.CSizeT(fin_bb) + trans._coro_try_stack_count = trans._coro_try_stack_count + 1 + self._handle_segment(trans, builder, pool, mod, stmt.children) + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, fin_bb) + if trans._coro_try_stack_count > 0: + trans._coro_try_stack_count = trans._coro_try_stack_count - 1 + # fin_bb:记录异常标志 + 执行 fbody + llvmlite.position_at_end(builder, fin_bb) + was_exc: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, + llvmlite.build_load(builder, i32_ty, trans._coro_exc_ptr), + llvmlite.const_int32(pool, 0)) + self._handle_segment(trans, builder, pool, mod, tr.finalbody) + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_cond_br(builder, was_exc, fin_exc_bb, merge_bb) + # fin_exc:finally 后异常继续传播 + llvmlite.position_at_end(builder, fin_exc_bb) + done_f: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) + llvmlite.build_store(builder, done_f, trans._coro_done_ptr) + llvmlite.build_br(builder, trans._coro_exit_bb) + llvmlite.position_at_end(builder, merge_bb) + + # ============================================================ + # M3:协程内 range-For(含 await)变换为 While(__f_idx/__f_len 帧槽) + # ============================================================ + def _handle_coro_for(self, trans: HT.Translator | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + stmt: ast.AST | t.CPtr): + """range-For(含 await):__f_idx_N = start; __f_len_N = end; + while __f_idx_N < __f_len_N: target = __f_idx_N; ; __f_idx_N += 1""" + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if self._is_range_for(stmt) == 0: + err_g: str = pool.alloc(256) + if err_g is not None: + viperlib.snprintf(err_g, 256, "[coro-M3] 协程内 For 仅支持 range 迭代(含 await)") + self.Gen.TypeGenErr.fatal_error(stmt, err_g, "SyntaxError") + return + fn: ast.For | t.CPtr = (ast.For | t.CPtr)(stmt) + k: int = trans._coro_for_counter + trans._coro_for_counter = k + 1 + idx_idx: int = trans._coro_extra_base + trans._coro_for_slots[k] + len_idx: int = idx_idx + 1 + idx_slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, self._lookup_coro_frame_by_trans(trans), + i32_ty, trans._coro_frame, idx_idx) + len_slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, self._lookup_coro_frame_by_trans(trans), + i32_ty, trans._coro_frame, len_idx) + if idx_slot is None or len_slot is None: + return + # start/end(range 1/2 参数) + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fn.iter) + start_val: llvmlite.Value | t.CPtr = None + end_val: llvmlite.Value | t.CPtr = None + nargs: int = len(cl.args) + if nargs == 1: + start_val = llvmlite.const_int32(pool, 0) + end_val = self.Gen.ExprGen.translate_value( + builder, pool, mod, cl.args.get(0), None, 0, trans) + else: + start_val = self.Gen.ExprGen.translate_value( + builder, pool, mod, cl.args.get(0), None, 0, trans) + end_val = self.Gen.ExprGen.translate_value( + builder, pool, mod, cl.args.get(1), None, 0, trans) + if start_val is None: + start_val = llvmlite.const_int32(pool, 0) + if end_val is None: + end_val = llvmlite.const_int32(pool, 0) + llvmlite.build_store(builder, start_val, idx_slot) + llvmlite.build_store(builder, end_val, len_slot) + # 循环结构 + func: llvmlite.Function | t.CPtr = trans._cur_func + cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "coro.fcond") + body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "coro.fbody") + after_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "coro.fend") + if cond_bb is None or body_bb is None or after_bb is None: + return + prev_break: llvmlite.BasicBlock | t.CPtr = trans._coro_break_bb + prev_cont: llvmlite.BasicBlock | t.CPtr = trans._coro_continue_bb + trans._coro_break_bb = after_bb + trans._coro_continue_bb = cond_bb + llvmlite.build_br(builder, cond_bb) + # 条件块 + llvmlite.position_at_end(builder, cond_bb) + idx_v: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i32_ty, idx_slot) + len_v: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i32_ty, len_slot) + cmp_v: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_SLT, idx_v, len_v) + llvmlite.build_cond_br(builder, cmp_v, body_bb, after_bb) + # 循环体:target = idx; ; idx += 1 + llvmlite.position_at_end(builder, body_bb) + if fn.target is not None and fn.target.kind() == ast.ASTKind.Name: + tn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(fn.target) + tgt_slot: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, tn.id) + if tgt_slot is not None: + idx_v2: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i32_ty, idx_slot) + llvmlite.build_store(builder, idx_v2, tgt_slot) + self._handle_segment(trans, builder, pool, mod, stmt.children) + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + idx_v3: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i32_ty, idx_slot) + one_v: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) + nxt_v: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, idx_v3, one_v) + llvmlite.build_store(builder, nxt_v, idx_slot) + llvmlite.build_br(builder, cond_bb) + trans._coro_break_bb = prev_break + trans._coro_continue_bb = prev_cont + llvmlite.position_at_end(builder, after_bb) + + # ============================================================ + # M3/M4/M7:coro.coro_destroy / coro_exception / coro_exception_msg / coro_gather + # ============================================================ + def translate_coro_destroy(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """coro.coro_destroy(帧):帧回池(free-list,帧首 8 字节存 next)""" + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + if cl is None or trans is None or cl.args is None or len(cl.args) < 1: + return llvmlite.const_int32(pool, 0) + async_name: str = self._var_to_async(trans, cl.args.get(0)) + if async_name is None: + return llvmlite.const_int32(pool, 0) + frame_ty: llvmlite.LLVMType | t.CPtr = self._lookup_coro_frame( + trans, async_name) + if frame_ty is None: + return llvmlite.const_int32(pool, 0) + frame_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, frame_ty) + frame_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cl.args.get(0), None, 0, trans) + if frame_val is None: + return llvmlite.const_int32(pool, 0) + frame_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, frame_val, frame_ptr_ty) + if frame_ptr is None: + return llvmlite.const_int32(pool, 0) + # 回池:帧首 8 字节存旧池头;池头 = 本帧(i64) + pool_gv: llvmlite.GlobalVariable | t.CPtr = self._get_coro_pool( + pool, mod, trans, async_name) + # GlobalVariable 非 Value 子类:构造 Value 视图(Ty=Ptr(i64), Name="@coro_pool_") + i64_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i64_ty) + pool_ref_name: str = pool.alloc(96) + if pool_ref_name is not None: + viperlib.snprintf(pool_ref_name, 96, "@coro_pool_%s", async_name) + pool_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, i64_ptr_ty, pool_ref_name) + pool_head: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i64_ty, pool_ref) + node_next: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, frame_ptr, i64_ptr_ty) + llvmlite.build_store(builder, pool_head, node_next) + frame_i64: llvmlite.Value | t.CPtr = llvmlite.build_ptrtoint( + builder, frame_ptr, i64_ty) + llvmlite.build_store(builder, frame_i64, pool_ref) + return llvmlite.const_int32(pool, 0) + + def translate_coro_exception(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """coro.coro_exception(帧):返回帧 exc 槽(异常码,0=无异常)""" + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if cl is None or trans is None or cl.args is None or len(cl.args) < 1: + return llvmlite.const_int32(pool, 0) + async_name: str = self._var_to_async(trans, cl.args.get(0)) + if async_name is None: + return llvmlite.const_int32(pool, 0) + frame_ty: llvmlite.LLVMType | t.CPtr = self._lookup_coro_frame( + trans, async_name) + if frame_ty is None: + return llvmlite.const_int32(pool, 0) + frame_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, frame_ty) + frame_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cl.args.get(0), None, 0, trans) + if frame_val is None: + return llvmlite.const_int32(pool, 0) + frame_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, frame_val, frame_ptr_ty) + if frame_ptr is None: + return llvmlite.const_int32(pool, 0) + exc_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, frame_ty, i32_ty, frame_ptr, 3) + return llvmlite.build_load(builder, i32_ty, exc_ptr) + + def translate_coro_exception_msg(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """coro.coro_exception_msg(帧):返回帧 msg 槽(异常消息指针,null=无)""" + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + if cl is None or trans is None or cl.args is None or len(cl.args) < 1: + return llvmlite.ConstNull(pool, i8_ptr_ty, "null") + async_name: str = self._var_to_async(trans, cl.args.get(0)) + if async_name is None: + return llvmlite.ConstNull(pool, i8_ptr_ty, "null") + frame_ty: llvmlite.LLVMType | t.CPtr = self._lookup_coro_frame( + trans, async_name) + if frame_ty is None: + return llvmlite.ConstNull(pool, i8_ptr_ty, "null") + frame_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, frame_ty) + frame_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cl.args.get(0), None, 0, trans) + if frame_val is None: + return llvmlite.ConstNull(pool, i8_ptr_ty, "null") + frame_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, frame_val, frame_ptr_ty) + if frame_ptr is None: + return llvmlite.ConstNull(pool, i8_ptr_ty, "null") + msg_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, frame_ty, i8_ptr_ty, frame_ptr, 4) + return llvmlite.build_load(builder, i8_ptr_ty, msg_ptr) + + def translate_coro_gather(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """coro.coro_gather(帧...):并发推进全部协程到完成,返回完成数(M4 纯 resume 循环)""" + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if cl is None or trans is None or cl.args is None: + return llvmlite.const_int32(pool, 0) + nb: t.CSizeT = len(cl.args) + j: t.CSizeT = 0 + for j in range(nb): + arg0: ast.AST | t.CPtr = cl.args.get(j) + async_name: str = self._var_to_async(trans, arg0) + if async_name is None: + continue + frame_ty: llvmlite.LLVMType | t.CPtr = self._lookup_coro_frame( + trans, async_name) + if frame_ty is None: + continue + frame_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, frame_ty) + frame_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg0, None, 0, trans) + if frame_val is None: + continue + frame_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, frame_val, frame_ptr_ty) + if frame_ptr is None: + continue + rn_buf: str = pool.alloc(64) + if rn_buf is not None: + viperlib.snprintf(rn_buf, 64, "resume_%s", async_name) + resume_mangled: str = self.Gen.FuncGenBase._mangle_func_name( + trans, rn_buf, 0) + if self.Gen.CallGenBase.find_func_in_module(mod, resume_mangled) is None: + continue + func: llvmlite.Function | t.CPtr = trans._cur_func + loop_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "gather.loop") + after_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "gather.after") + if loop_bb is None or after_bb is None: + continue + llvmlite.build_br(builder, loop_bb) + llvmlite.position_at_end(builder, loop_bb) + frame_ptr.Next = None + status: llvmlite.Value | t.CPtr = llvmlite.build_call( + builder, resume_mangled, frame_ptr, 1, i32_ty, 0) + done_cond: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, status, llvmlite.const_int32(pool, 0)) + llvmlite.build_cond_br(builder, done_cond, after_bb, loop_bb) + llvmlite.position_at_end(builder, after_bb) + return llvmlite.const_int32(pool, 0) + + def _var_to_async(self, trans: HT.Translator | t.CPtr, + arg0: ast.AST | t.CPtr) -> str: + """变量节点 → async 函数名(_coro_var_async 反查),未命中返回 None""" + if trans is None or arg0 is None or arg0.kind() != ast.ASTKind.Name: + return None + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0) + if nm.id is None: + return None + return self._lookup_coro_var(trans, nm.id) + + # ============================================================ + # await 表达式翻译(顶层段尾 / translate_value Await 分支共用) + # ============================================================ + def _emit_await(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr, + call_name: str) -> llvmlite.Value | t.CPtr: + """await async_fn(args...) 内联翻译(M2 带参数): + 1. 求值调用参数(表达式逐个翻译,i32) + 2. create_(args...) 创建子帧 + 3. resume_(child) 推进到 DONE + 4. 子帧 ret 槽 GEP [0,2] load → store 到父帧 await 槽(若非 None) + 5. 父挂起:store state=新状态号 + br exit;恢复块 state{new_state} + 立即 position(预建 case 块),后续语句在恢复块继续翻译 + 返回子协程 ret 值(i32)。注意 node 是 Await,须先转 ast.Await 再取 value。""" + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i8_ptr_ty_a: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + if node is None or call_name is None or trans is None: + return llvmlite.const_int32(pool, 0) + # M3:await coro_sleep(ms) —— 挂起到 wake 时刻(帧 wake 槽) + if string.strcmp(call_name, "coro_sleep") == 0: + return self._emit_await_sleep(builder, pool, mod, trans, node) + child_frame_ty: llvmlite.LLVMType | t.CPtr = self._lookup_coro_frame( + trans, call_name) + if child_frame_ty is None: + return llvmlite.const_int32(pool, 0) + child_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, child_frame_ty) + + cc_buf: str = pool.alloc(64) + if cc_buf is not None: + viperlib.snprintf(cc_buf, 64, "create_%s", call_name) + create_mangled: str = self.Gen.FuncGenBase._mangle_func_name( + trans, cc_buf, 0) + rc_buf: str = pool.alloc(64) + if rc_buf is not None: + viperlib.snprintf(rc_buf, 64, "resume_%s", call_name) + resume_mangled: str = self.Gen.FuncGenBase._mangle_func_name( + trans, rc_buf, 0) + if self.Gen.CallGenBase.find_func_in_module(mod, create_mangled) is None \ + or self.Gen.CallGenBase.find_func_in_module(mod, resume_mangled) is None: + # async 函数必须定义在前(前向引用未支持),静默返回 0 + return llvmlite.const_int32(pool, 0) + + # M2:子协程调用参数(await fn(a, b) → create_fn(a, b)) + args_head: llvmlite.Value | t.CPtr = None + args_tail: llvmlite.Value | t.CPtr = None + args_count: int = 0 + aw_n: ast.Await | t.CPtr = (ast.Await | t.CPtr)(node) + if aw_n.value is not None and aw_n.value.kind() == ast.ASTKind.Call: + cl_a: ast.Call | t.CPtr = (ast.Call | t.CPtr)(aw_n.value) + if cl_a.args is not None: + nb: t.CSizeT = len(cl_a.args) + j: t.CSizeT = 0 + for j in range(nb): + av: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cl_a.args.get(j), None, 0, trans) + if av is None: + av = llvmlite.const_int32(pool, 0) + av.Next = None + if args_head is None: + args_head = av + args_tail = av + else: + args_tail.Next = av + args_tail = av + args_count = args_count + 1 + + # 子协程 create(M2 带参数)+ resume + child: llvmlite.Value | t.CPtr = llvmlite.build_call( + builder, create_mangled, args_head, args_count, child_ptr_ty, 0) + if child is None: + return llvmlite.const_int32(pool, 0) + child.Next = None + llvmlite.build_call(builder, resume_mangled, child, 1, i32_ty, 0) + # 子帧 ret 槽 GEP [0,2] load + child_ret_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, child_frame_ty, i32_ty, child, 2) + child_ret: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i32_ty, child_ret_ptr) + # M4:子帧异常传播——子帧 exc != 0 → 父 exc/msg 槽 + 跳 try except 或终止 + child_exc_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, child_frame_ty, i32_ty, child, 3) + child_exc: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i32_ty, child_exc_ptr) + zero32_x: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + exc_ok_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, trans._cur_func, "coro.ok") + exc_bad_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, trans._cur_func, "coro.exc") + if exc_ok_bb is None or exc_bad_bb is None: + return llvmlite.const_int32(pool, 0) + exc_cond: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_EQ, child_exc, zero32_x) + llvmlite.build_cond_br(builder, exc_cond, exc_ok_bb, exc_bad_bb) + # exc 路径:父帧 exc/msg 槽 + 跳 try 或终止 + llvmlite.position_at_end(builder, exc_bad_bb) + if trans._coro_exc_ptr is not None: + llvmlite.build_store(builder, child_exc, trans._coro_exc_ptr) + if trans._coro_msg_ptr is not None: + child_msg_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, child_frame_ty, i8_ptr_ty_a, child, 4) + child_msg: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i8_ptr_ty_a, child_msg_ptr) + llvmlite.build_store(builder, child_msg, trans._coro_msg_ptr) + if trans._coro_try_stack_count > 0: + tbb: llvmlite.BasicBlock | t.CPtr = ( + llvmlite.BasicBlock | t.CPtr)(t.CVoid( + trans._coro_try_stack[trans._coro_try_stack_count - 1], + t.CPtr)) + llvmlite.build_br(builder, tbb) + else: + done_x: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) + llvmlite.build_store(builder, done_x, trans._coro_done_ptr) + llvmlite.build_br(builder, trans._coro_exit_bb) + # 正常路径:存父帧 await 槽(若非 None)+ 挂起 + llvmlite.position_at_end(builder, exc_ok_bb) + slot: llvmlite.Value | t.CPtr = trans._coro_await_slot + if slot is not None: + llvmlite.build_store(builder, child_ret, slot) + # 父挂起:新状态号(与预扫描 DFS 序一致) + new_state: int = trans._coro_next_state + trans._coro_next_state = new_state + 1 + st_v: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, new_state) + llvmlite.build_store(builder, st_v, trans._coro_state_ptr) + llvmlite.build_br(builder, trans._coro_exit_bb) + # 恢复块 state{new_state}:立即 position(预建 case 块,后续翻译在此继续) + resume_bb: llvmlite.BasicBlock | t.CPtr = self._get_state_bb( + trans, new_state) + if resume_bb is not None: + llvmlite.position_at_end(builder, resume_bb) + return child_ret + + # ============================================================ + # coro.coro_run(帧) 内联翻译 + # ============================================================ + def translate_coro_run(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """coro.coro_run(frame) 内联翻译: + 参数是 Name 变量 → 经 _coro_var_async 反查 async 名 → _coro_frames + 取帧类型 → bitcast 变量值到 Ptr(帧) → 循环 resume_(frame) 直到 + done != 0 → GEP [0,2] load ret 返回。 + M1 无 coro_sleep 轮询(无 wake 槽),纯忙等直到协程完成。 + """ + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if cl is None or trans is None: + return llvmlite.const_int32(pool, 0) + if cl.args is None or len(cl.args) < 1: + return llvmlite.const_int32(pool, 0) + arg0: ast.AST | t.CPtr = cl.args.get(0) + if arg0 is None or arg0.kind() != ast.ASTKind.Name: + return llvmlite.const_int32(pool, 0) + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0) + if nm.id is None: + return llvmlite.const_int32(pool, 0) + async_name: str = self._lookup_coro_var(trans, nm.id) + if async_name is None: + return llvmlite.const_int32(pool, 0) + frame_ty: llvmlite.LLVMType | t.CPtr = self._lookup_coro_frame( + trans, async_name) + if frame_ty is None: + return llvmlite.const_int32(pool, 0) + frame_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, frame_ty) + + # 帧变量值(i8* / Ptr(帧))→ bitcast 到 Ptr(帧) + frame_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg0, None, 0, trans) + if frame_val is None: + return llvmlite.const_int32(pool, 0) + frame_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, frame_val, frame_ptr_ty) + if frame_ptr is None: + return llvmlite.const_int32(pool, 0) + + func: llvmlite.Function | t.CPtr = trans._cur_func + if func is None: + return llvmlite.const_int32(pool, 0) + rn_buf: str = pool.alloc(64) + if rn_buf is not None: + viperlib.snprintf(rn_buf, 64, "resume_%s", async_name) + resume_mangled: str = self.Gen.FuncGenBase._mangle_func_name( + trans, rn_buf, 0) + if self.Gen.CallGenBase.find_func_in_module(mod, resume_mangled) is None: + return llvmlite.const_int32(pool, 0) + + loop_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "coro.loop") + check_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "coro.check") + after_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "coro.after") + if loop_bb is None or check_bb is None or after_bb is None: + return llvmlite.const_int32(pool, 0) + llvmlite.build_br(builder, loop_bb) + llvmlite.position_at_end(builder, loop_bb) + frame_ptr.Next = None + status: llvmlite.Value | t.CPtr = llvmlite.build_call( + builder, resume_mangled, frame_ptr, 1, i32_ty, 0) + zero_cmp: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + done_cond: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, status, zero_cmp) + llvmlite.build_cond_br(builder, done_cond, after_bb, check_bb) + # M3:SUSPEND → wake 轮询(GetTickCount64 >= wake 或 wake==0 继续,否则 Sleep(1)) + llvmlite.position_at_end(builder, check_bb) + wake_idx_r: int = self._lookup_coro_wake(trans, async_name) + if wake_idx_r < 0: + llvmlite.build_br(builder, loop_bb) + else: + i64_ty_r2: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + wake_ptr_r: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, frame_ty, i64_ty_r2, frame_ptr, wake_idx_r) + wake_v_r: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i64_ty_r2, wake_ptr_r) + now_v_r: llvmlite.Value | t.CPtr = llvmlite.build_call( + builder, "GetTickCount64", None, 0, i64_ty_r2, 0) + not_wake_r: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_EQ, wake_v_r, + llvmlite.const_int64(pool, 0)) + due_r: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_UGE, now_v_r, wake_v_r) + cont_r: llvmlite.Value | t.CPtr = llvmlite.build_or( + builder, not_wake_r, due_r) + wsleep_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "coro.wsleep") + wdue_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, "coro.wdue") + llvmlite.build_cond_br(builder, cont_r, wdue_bb, wsleep_bb) + llvmlite.position_at_end(builder, wsleep_bb) + sleep_one: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) + llvmlite.build_call(builder, "Sleep", sleep_one, 1, + llvmlite.Void(pool), 0) + llvmlite.build_br(builder, loop_bb) + llvmlite.position_at_end(builder, wdue_bb) + llvmlite.build_br(builder, loop_bb) + llvmlite.position_at_end(builder, after_bb) + ret_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, frame_ty, i32_ty, frame_ptr, 2) + ret_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i32_ty, ret_ptr) + return ret_val + + # ============================================================ + # 公共查询 / 登记 + # ============================================================ + def is_async_func(self, trans: HT.Translator | t.CPtr, + name: str) -> int: + """查询 name 是否已注册为 async 函数(_async_funcs 表),1=是 0=否""" + if trans is None or name is None or trans._async_funcs is None: + return 0 + cnt: int = trans._async_func_count + i: int = 0 + for i in range(cnt): + addr: t.CUInt64T = t.CUInt64T(trans._async_funcs) + i * 8 + slot: str | t.CPtr = (t.CVoid | t.CPtr)(addr) + if slot[0] is not None and string.strcmp(slot[0], name) == 0: + return 1 + return 0 + + def register_coro_var(self, trans: HT.Translator | t.CPtr, + var_name: str, func_name: str) -> int: + """记录 变量名→async 函数名 映射(coro.coro_run 反查帧类型用)。 + 对齐 TPC HandlesAnnAssign.py L319-326。返回 0 成功。""" + if trans is None or var_name is None or func_name is None: + return 1 + if trans._coro_var_async is None: + return 1 + cnt: int = trans._coro_var_async_count + i: int = 0 + for i in range(cnt): + addr: t.CUInt64T = t.CUInt64T(trans._coro_var_async) + i * 16 + pair: str | t.CPtr = (t.CVoid | t.CPtr)(addr) + if pair[0] is not None and string.strcmp(pair[0], var_name) == 0: + return 0 + if cnt >= HT.MAX_CORO_VARS: + return 1 + pair2_addr: t.CUInt64T = t.CUInt64T(trans._coro_var_async) + cnt * 16 + pair2: str | t.CPtr = (t.CVoid | t.CPtr)(pair2_addr) + pair2[0] = var_name + pair2[1] = func_name + trans._coro_var_async_count = cnt + 1 + return 0 + + def _register_async_func(self, trans: HT.Translator | t.CPtr, + name: str) -> int: + """注册 async 函数裸名到 _async_funcs 表""" + if trans is None or name is None or trans._async_funcs is None: + return 1 + cnt: int = trans._async_func_count + i: int = 0 + for i in range(cnt): + addr: t.CUInt64T = t.CUInt64T(trans._async_funcs) + i * 8 + slot: str | t.CPtr = (t.CVoid | t.CPtr)(addr) + if slot[0] is not None and string.strcmp(slot[0], name) == 0: + return 0 + if cnt >= HT.MAX_CORO_FUNCS: + return 1 + addr2: t.CUInt64T = t.CUInt64T(trans._async_funcs) + cnt * 8 + slot2: str | t.CPtr = (t.CVoid | t.CPtr)(addr2) + slot2[0] = name + trans._async_func_count = cnt + 1 + return 0 + + def _register_coro_frame(self, trans: HT.Translator | t.CPtr, + name: str, + frame_ty: llvmlite.LLVMType | t.CPtr) -> int: + """注册 async 名→帧类型 到 _coro_frames 表(16 字节/项 = char* + LLVMType*)""" + if trans is None or name is None or frame_ty is None: + return 1 + if trans._coro_frames is None: + return 1 + cnt: int = trans._coro_frame_count + i: int = 0 + for i in range(cnt): + addr: t.CUInt64T = t.CUInt64T(trans._coro_frames) + i * 16 + pair: str | t.CPtr = (t.CVoid | t.CPtr)(addr) + if pair[0] is not None and string.strcmp(pair[0], name) == 0: + pair[1] = (str)(t.CVoid(t.CSizeT(frame_ty), t.CPtr)) + return 0 + if cnt >= HT.MAX_CORO_FUNCS: + return 1 + pair2_addr: t.CUInt64T = t.CUInt64T(trans._coro_frames) + cnt * 16 + pair2: str | t.CPtr = (t.CVoid | t.CPtr)(pair2_addr) + pair2[0] = name + pair2[1] = (str)(t.CVoid(t.CSizeT(frame_ty), t.CPtr)) + trans._coro_frame_count = cnt + 1 + return 0 + + def _lookup_coro_frame(self, trans: HT.Translator | t.CPtr, + name: str) -> llvmlite.LLVMType | t.CPtr: + """按 async 名查帧类型,未命中返回 None""" + if trans is None or name is None or trans._coro_frames is None: + return None + cnt: int = trans._coro_frame_count + i: int = 0 + for i in range(cnt): + addr: t.CUInt64T = t.CUInt64T(trans._coro_frames) + i * 16 + pair: str | t.CPtr = (t.CVoid | t.CPtr)(addr) + if pair[0] is not None and string.strcmp(pair[0], name) == 0: + if pair[1] is not None: + ty_addr: t.CSizeT = t.CSizeT(pair[1]) + return (llvmlite.LLVMType | t.CPtr)(t.CVoid(ty_addr, t.CPtr)) + return None + return None + + def _lookup_coro_var(self, trans: HT.Translator | t.CPtr, + var_name: str) -> str: + """按变量名反查 async 函数名(_coro_var_async 表),未命中返回 None""" + if trans is None or var_name is None or trans._coro_var_async is None: + return None + cnt: int = trans._coro_var_async_count + i: int = 0 + for i in range(cnt): + addr: t.CUInt64T = t.CUInt64T(trans._coro_var_async) + i * 16 + pair: str | t.CPtr = (t.CVoid | t.CPtr)(addr) + if pair[0] is not None and string.strcmp(pair[0], var_name) == 0: + return pair[1] + return None + + # ============================================================ + # 段翻译辅助 + # ============================================================ + def _emit_coro_return(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + trans: HT.Translator | t.CPtr, + stmt: ast.AST | t.CPtr) -> None: + """协程内 Return 特判:store ret 槽 + done=1 + br exit。 + M1 不支持 return await(顶层 await 仅限 AnnAssign/Assign)。 + + 注意:stmt 以 ast.AST 基类型传入,AST 基类没有 value 字段 + (base.vp 仅 parent/pool/lineno/col/children),直接 stmt.value + 读到的是非法偏移(0/垃圾)→ ret 恒 0。必须转回 ast.Return 再取。""" + rv_node: ast.Return | t.CPtr = (ast.Return | t.CPtr)(stmt) + ret_val: llvmlite.Value | t.CPtr = None + if rv_node is not None and rv_node.value is not None: + if rv_node.value.kind() != ast.ASTKind.Await: + ret_val = self.Gen.ExprGen.translate_value( + builder, pool, mod, rv_node.value, None, 0, trans) + if ret_val is None: + ret_val = llvmlite.const_int32(pool, 0) + llvmlite.build_store(builder, ret_val, trans._coro_ret_ptr) + done_one: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) + llvmlite.build_store(builder, done_one, trans._coro_done_ptr) + llvmlite.build_br(builder, trans._coro_exit_bb) + + def _expr_await_is_sleep(self, aw: ast.Await | t.CPtr) -> int: + """Await 目标是否为 coro_sleep(Name 或 coro.coro_sleep)""" + if aw is None or aw.value is None: + return 0 + if aw.value.kind() != ast.ASTKind.Call: + return 0 + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(aw.value) + if cl.func is None: + return 0 + if cl.func.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl.func) + if nm.id is not None and string.strcmp(nm.id, "coro_sleep") == 0: + return 1 + elif cl.func.kind() == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if at.attr is not None and string.strcmp(at.attr, "coro_sleep") == 0: + return 1 + return 0 + + def _is_await_tail(self, stmt: ast.AST | t.CPtr) -> int: + """判断语句是否为段尾:AnnAssign/Assign/Expr 且 value 直接是 Await""" + if stmt is None: + return 0 + sk: int = stmt.kind() + if sk == ast.ASTKind.AnnAssign: + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) + if aa.value is not None and aa.value.kind() == ast.ASTKind.Await: + return 1 + elif sk == ast.ASTKind.Assign: + as_: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) + if as_.value is not None and as_.value.kind() == ast.ASTKind.Await: + if as_.targets is not None and len(as_.targets) == 1: + return 1 + elif sk == ast.ASTKind.Expr: + e: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(stmt) + if e.value is not None and e.value.kind() == ast.ASTKind.Await: + return 1 + return 0 + + def _get_assign_target_name(self, stmt: ast.AST | t.CPtr) -> str: + """取 AnnAssign(target=Name)/Assign(单 target=Name) 的目标名,未命中返回 None""" + if stmt is None: + return None + sk: int = stmt.kind() + if 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) + return tn.id + elif sk == ast.ASTKind.Assign: + as_: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) + if as_.targets is not None and len(as_.targets) == 1: + t0: ast.AST | t.CPtr = as_.targets.get(0) + if t0 is not None and t0.kind() == ast.ASTKind.Name: + tn2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(t0) + return tn2.id + return None + + def _get_await_value(self, stmt: ast.AST | t.CPtr) -> ast.Await | t.CPtr: + """取段尾语句的 Await value 节点,未命中返回 None""" + if stmt is None: + return None + sk: int = stmt.kind() + if sk == ast.ASTKind.AnnAssign: + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) + if aa.value is not None and aa.value.kind() == ast.ASTKind.Await: + return (ast.Await | t.CPtr)(aa.value) + elif sk == ast.ASTKind.Assign: + as_: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) + if as_.value is not None and as_.value.kind() == ast.ASTKind.Await: + return (ast.Await | t.CPtr)(as_.value) + elif sk == ast.ASTKind.Expr: + ex: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(stmt) + if ex.value is not None and ex.value.kind() == ast.ASTKind.Await: + return (ast.Await | t.CPtr)(ex.value) + return None + + def _extract_await_call_name(self, aw_node: ast.Await | t.CPtr) -> str: + """从 Await(value=Call(func)) 提取 async 函数名或 coro_sleep,未命中返回 None""" + if aw_node is None or aw_node.value is None: + return None + if aw_node.value.kind() == ast.ASTKind.Call: + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(aw_node.value) + if cl.func is not None: + if cl.func.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl.func) + return nm.id + if cl.func.kind() == ast.ASTKind.Attribute: + # coro.coro_sleep(ms):M3 sleep 挂起 + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if at.attr is not None and string.strcmp(at.attr, "coro_sleep") == 0: + return "coro_sleep" + return None + + def _read_local_name(self, trans: HT.Translator | t.CPtr, + idx: int) -> str: + """读 trans._coro_locals 第 idx 个局部变量名,越界返回 None""" + if trans is None or trans._coro_locals is None: + return None + addr: t.CUInt64T = t.CUInt64T(trans._coro_locals) + idx * 8 + slot: str | t.CPtr = (t.CVoid | t.CPtr)(addr) + return slot[0] diff --git a/App/lib/core/Gen/BaseGenMixin.vp b/App/lib/core/Gen/BaseGenMixin.vp index 409b1a9..79e002d 100644 --- a/App/lib/core/Gen/BaseGenMixin.vp +++ b/App/lib/core/Gen/BaseGenMixin.vp @@ -4,7 +4,6 @@ import t, c from stdint import * import memhub import llvmlite -import lib.core.Handles.HandlesExprCall as HandlesExprCall # ============================================================ diff --git a/App/lib/core/Gen/Call/CallGenBase.vp b/App/lib/core/Gen/Call/CallGenBase.vp index 151fec1..ac2e2c9 100644 --- a/App/lib/core/Gen/Call/CallGenBase.vp +++ b/App/lib/core/Gen/Call/CallGenBase.vp @@ -12,11 +12,8 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall import lib.core.CompilerFactory as CompilerFactory import lib.Stub.StubMerger.StubMergerCollect as StubMergerCollect import lib.Stub.StubMerger.StubMergerStore as StubMergerStore diff --git a/App/lib/core/Gen/Call/CallGenCBuiltin.vp b/App/lib/core/Gen/Call/CallGenCBuiltin.vp index 1be4494..ee463af 100644 --- a/App/lib/core/Gen/Call/CallGenCBuiltin.vp +++ b/App/lib/core/Gen/Call/CallGenCBuiltin.vp @@ -11,14 +11,12 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall import lib.core.CompilerFactory as CompilerFactory import lib.core.Gen.Call.CallGenBase as CallGenBase +import lib.core.Gen.GenApi as GenApi # ============================================================ @@ -259,7 +257,7 @@ class CallGenCBuiltin(CallGenBase.CallGenBase): 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: + if GenApi.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: @@ -271,7 +269,7 @@ class CallGenCBuiltin(CallGenBase.CallGenBase): 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: + if GenApi.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: @@ -357,7 +355,7 @@ class CallGenCBuiltin(CallGenBase.CallGenBase): # 不能 lookup_var 跨函数命中父函数 alloca(SSA 编号错乱崩溃)。 # 与普通局部 c.Addr(obj) 返回对象指针(load 一次)语义一致。 if trans is not None: - if HT.is_nonlocal_name(trans, nm.id) != 0: + if GenApi.is_nonlocal_name(trans, nm.id) != 0: nl_addr: llvmlite.Value | t.CPtr = self.Gen.StmtGenDecl.load_nonlocal_var( trans, nm.id) if nl_addr is not None: diff --git a/App/lib/core/Gen/Call/CallGenCall.vp b/App/lib/core/Gen/Call/CallGenCall.vp index 0177519..73774fd 100644 --- a/App/lib/core/Gen/Call/CallGenCall.vp +++ b/App/lib/core/Gen/Call/CallGenCall.vp @@ -11,15 +11,11 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall import lib.core.CompilerFactory as CompilerFactory import lib.core.Gen.Call.CallGenBase as CallGenBase -import lib.core.Handles.ExprCallTable as ExprCallTable # ============================================================ @@ -417,7 +413,7 @@ class CallGenCall(CallGenBase.CallGenBase): mdf_default_count: int = 0 mdf_param_count: int = 0 if trans is not None and trans._funcs is not None: - mdf_entry: GenTypes.FuncEntry | t.CPtr = ExprCallTable.find_func_entry_in_table( + mdf_entry: GenTypes.FuncEntry | t.CPtr = self.Gen.CallGenLeafKit.find_func_entry_in_table( trans._funcs, trans._func_count, lookup_name) if mdf_entry is not None: mdf_defaults = mdf_entry.Defaults @@ -1370,7 +1366,7 @@ class CallGenCall(CallGenBase.CallGenBase): mdf_default_count: int = 0 mdf_param_count: int = 0 if trans is not None and trans._funcs is not None: - mdf_entry: GenTypes.FuncEntry | t.CPtr = ExprCallTable.find_func_entry_in_table( + mdf_entry: GenTypes.FuncEntry | t.CPtr = self.Gen.CallGenLeafKit.find_func_entry_in_table( trans._funcs, trans._func_count, lookup_name) if mdf_entry is not None: mdf_defaults = mdf_entry.Defaults diff --git a/App/lib/core/Gen/Call/CallGenCtor.vp b/App/lib/core/Gen/Call/CallGenCtor.vp index c0a6947..023f1b7 100644 --- a/App/lib/core/Gen/Call/CallGenCtor.vp +++ b/App/lib/core/Gen/Call/CallGenCtor.vp @@ -11,15 +11,11 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall import lib.core.CompilerFactory as CompilerFactory import lib.core.Gen.Call.CallGenBase as CallGenBase -import lib.core.Handles.ExprCallTable as ExprCallTable # ============================================================ diff --git a/App/lib/core/Gen/Call/CallGenDispatch.vp b/App/lib/core/Gen/Call/CallGenDispatch.vp index 911b99a..8439514 100644 --- a/App/lib/core/Gen/Call/CallGenDispatch.vp +++ b/App/lib/core/Gen/Call/CallGenDispatch.vp @@ -1,1702 +1,1700 @@ -import lib.core.Gen.GenTypes as GenTypes -import lib.core.Gen.Generator as Generator -import lib.core.Gen.Expr.ExprGenCls as ExprGenCls -import lib.core.Gen.Expr.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.Stub.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.CompilerFactory as CompilerFactory - -import lib.core.Gen.Call.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) - # 及 coro.* 协程库拦截(coro.coro_run 内联翻译,TPV-M1) - 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) - is_coro_mod: int = 0 - if mod_nm.id is not None and string.strcmp(mod_nm.id, "coro") == 0: - is_coro_mod = 1 - if mod_nm.id is not None and (string.strcmp(mod_nm.id, "c") == 0 or is_coro_mod != 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") - elif is_coro_mod != 0 and string.strcmp(func_name, "coro_run") == 0: - # coro.coro_run(帧):内联翻译(resume 循环到 done,返回帧 ret 槽) - # 对齐 TPC HandlesAsyncFunctions._HandleCoroRunLlvm - # 注意:coro.* 系列 translate_coro_* 签名统一是 - # (builder, pool, mod, cl, trans),与本文件其它 c.* 分支的 - # (pool, builder, ...) 顺序不同,勿混用。 - return self.Gen.AsyncGen.translate_coro_run( - builder, pool, mod, cl, trans) - elif is_coro_mod != 0 and string.strcmp(func_name, "coro_destroy") == 0: - # coro.coro_destroy(帧):帧回池(M7 free-list) - return self.Gen.AsyncGen.translate_coro_destroy( - builder, pool, mod, cl, trans) - elif is_coro_mod != 0 and string.strcmp(func_name, "coro_exception") == 0: - # coro.coro_exception(帧):返回帧 exc 槽(M4) - return self.Gen.AsyncGen.translate_coro_exception( - builder, pool, mod, cl, trans) - elif is_coro_mod != 0 and string.strcmp(func_name, "coro_exception_msg") == 0: - # coro.coro_exception_msg(帧):返回帧 msg 槽(M7) - return self.Gen.AsyncGen.translate_coro_exception_msg( - builder, pool, mod, cl, trans) - elif is_coro_mod != 0 and string.strcmp(func_name, "coro_gather") == 0: - # coro.coro_gather(帧...):并发推进全部协程(M4) - return self.Gen.AsyncGen.translate_coro_gather( - builder, pool, mod, cl, trans) - 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: - # t.CType 特殊形式:t.CType(value, TypeName, t.CPtr) → - # 把 value 转为 TypeName|t.CPtr(TypeName* 指针)。TypeName - # 是类型名(Name/Attribute),不是值表达式——此前被当普通 - # 参数翻译 → NameError: 未定义名称 'memory_block' - # (VKernel mm.vp merge_blocks 根因)。CType 不是 map_t_type - # 的具名类型,须在此显式处理,否则跌落到跨模块 FATAL。 - if string.strcmp(func_name, "CType") == 0 and can >= 2: - cty_node: ast.AST | t.CPtr = cargs.get(1) - ctype_target: llvmlite.LLVMType | t.CPtr = None - if cty_node is not None: - cti_imp: str = None - cti_fi: str = None - if trans is not None: - cti_imp = trans._imported_modules - cti_fi = trans._from_imports - ctype_target = self.Gen.TypeGenResolve.resolve_annotation_type( - pool, cty_node, cti_imp, cti_fi, trans, 0) - if ctype_target is not None: - if can == 3: - cty_arg3: ast.AST | t.CPtr = cargs.get(2) - cty_is_cptr: int = 0 - if cty_arg3 is not None: - # 形式 1: t.CPtr(Attribute) - if cty_arg3.kind() == ast.ASTKind.Attribute: - cty_at3: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cty_arg3) - if cty_at3.attr is not None and string.strcmp(cty_at3.attr, "CPtr") == 0: - if cty_at3.value is not None and cty_at3.value.kind() == ast.ASTKind.Name: - cty_nm3: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cty_at3.value) - if cty_nm3.id is not None and string.strcmp(cty_nm3.id, "t") == 0: - cty_is_cptr = 1 - # 形式 2: 裸名 CPtr - elif cty_arg3.kind() == ast.ASTKind.Name: - cty_bn3: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cty_arg3) - if cty_bn3.id is not None and string.strcmp(cty_bn3.id, "CPtr") == 0: - cty_is_cptr = 1 - if cty_is_cptr != 0: - # CVoid* → i8*(LLVM 中 void* 表示为 i8*) - match ctype_target: - case llvmlite.LLVMType.Void(): - ctype_target = llvmlite.Int8(pool) - case _: - pass - ctype_target = llvmlite.Ptr(pool, ctype_target) - cty_arg0: ast.AST | t.CPtr = cargs.get(0) - if cty_arg0 is not None: - cty_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, cty_arg0, funcs_ptr, func_count, trans) - if cty_val is not None: - return self.Gen.CallGenCtor._translate_t_type_cast( - pool, builder, cty_val, ctype_target, - func_name, cty_arg0, trans) - # t.CType 语法已确认:即使类型解析失败也不跌落到跨模块 FATAL - return None - # CConst const 标记:CConst(val, t.CPtr) → Ptr(i8)(const void*)。 - # CConst 不是 map_t_type 具名类型——t.CConst|t.CChar|t.CPtr 注解 = - # const char*(i8*),显式调用 t.CConst(addr, t.CPtr) 把整数地址转 - # const 指针。此前 map_t_type 失败 → 跌落跨模块函数调用 → 生成 - # call @CConst(裸名,无 obj 定义)→ ld.lld undefined symbol: - # CConst(elf.vp L650 t.CConst(t.CUInt64T(strtab_ptr)+sym.st_name, - # t.CPtr) 根因)。单参 CConst(x) 仅 const 限定,LLVM 类型不变, - # 直接返回原值。 - if string.strcmp(func_name, "CConst") == 0: - if can >= 2: - cconst_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - cconst_arg: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) - if cconst_arg is not None: - return self.Gen.CallGenCtor._translate_t_type_cast( - pool, builder, cconst_arg, cconst_ptr_ty, - func_name, cargs.get(0), trans) - elif can == 1: - return self.Gen.ExprGen.translate_value( - builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) - return None - 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, 0) - 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, 0) - # 泛型类型参数双参数形式: 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, trans._from_imports) - 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")。 - """ - # REnum.kind() 编译期转 __tag 读取(位置 0 i32): - # REnum 无 kind 方法(源码无、编译器不生成),此前 .kind() 被方法查找 - # 兜底误绑到 ast.AST.kind(this 偏移,语义错误)。此处直接翻译为 - # bitcast obj 到 i32* + load —— 零函数调用,返回变体 tag。 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - rk_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if rk_at is not None and rk_at.attr is not None \ - and string.strcmp(rk_at.attr, "kind") == 0: - rk_obj: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, rk_at.value, None, 0, trans) - if rk_obj is not None and rk_obj.Ty is not None: - rk_ty: llvmlite.LLVMType | t.CPtr = rk_obj.Ty - rk_load: int = 0 - if self.Gen.ExprGenBase.is_ptr_type(rk_ty) != 0: - rk_pointee: llvmlite.LLVMType | t.CPtr = rk_ty.Pointee - # 联合简化双指针(Ptr(Ptr(Struct)))→ 解一层 + load - if rk_pointee is not None \ - and self.Gen.ExprGenBase.is_ptr_type(rk_pointee) != 0: - rk_pointee = rk_pointee.Pointee - rk_load = 1 - rk_cls: str = self.Gen.StructGen.get_class_name_by_type(pool, rk_pointee) - if rk_cls is not None \ - and self.Gen.ClassGenEnum._is_renum_class_name(rk_cls) != 0: - rk_val: llvmlite.Value | t.CPtr = rk_obj - if rk_load != 0: - rk_val = llvmlite.build_load(builder, rk_ty, rk_obj) - if rk_val is not None: - if hit_box is not None: - hit_box[0] = 1 - rk_i32p: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int32(pool)) - rk_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, rk_val, rk_i32p) - return llvmlite.build_load(builder, rk_i32p, rk_cast) - # 检测类名静态/类方法调用: 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_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 变体构造优先于静态/类方法调用: - 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: - # 链式方法调用: a.b().c() —— value 是内层 Call(如 gfx.vp 的 - # eye.Sub(target).Norm())。此前未处理 → 外层 .Norm() 的 value - # 非 Name 跳过方法分支 → 通用路径把 eye.Sub 当属性解析 → - # "属性写入失败: .Sub"。先翻译内层调用得接收者,再方法调用。 - if method_at.value.kind() == ast.ASTKind.Call and trans is not None: - recv_val_c: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, method_at.value, None, 0, trans) - if recv_val_c is not None and recv_val_c.Ty is not None: - recv_ty_c: llvmlite.LLVMType | t.CPtr = recv_val_c.Ty - if self.Gen.ExprGenBase.is_ptr_type(recv_ty_c) != 0: - recv_ty_c = recv_ty_c.Pointee - # 堆对象(@t.Object)双指针 → 再解一层取 struct - if self.Gen.ExprGenBase.is_ptr_type(recv_ty_c) != 0: - recv_ty_c = recv_ty_c.Pointee - recv_cls_c: str = self.Gen.StructGen.get_class_name_by_type( - pool, recv_ty_c) - if recv_cls_c is not None: - if self.Gen.CallGenProp._is_list_builtin_method( - recv_cls_c, method_at.attr) == 0: - obj_ptr_c: llvmlite.Value | t.CPtr = recv_val_c - if self.Gen.ExprGenBase.is_ptr_type(recv_val_c.Ty) != 0 \ - and recv_val_c.Ty.Pointee is not None \ - and self.Gen.ExprGenBase.is_ptr_type(recv_val_c.Ty.Pointee) != 0: - obj_ptr_c = llvmlite.build_load( - builder, recv_val_c.Ty, recv_val_c) - if obj_ptr_c is not None: - if hit_box is not None: - hit_box[0] = 1 - return self.Gen.CallGenCall._translate_method_call( - pool, builder, mod, recv_cls_c, method_at.attr, - obj_ptr_c, cl, trans) - 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: - # nonlocal 对象:提升函数内从 env 读对象指针(load_nonlocal_var), - # 不能 lookup_var 跨函数命中父函数 alloca(SSA 编号错乱 → - # llc "use of undefined value")。entry.get() 等方法调用的 - # 基座对象经此路径解析(closure 隐式捕获场景)。 - # 用 get_struct_type_from_value 递归解 Ptr,兼容 - # Ptr(Struct)(load_nonlocal_var 已 load)与 - # Ptr(Ptr(Struct))(联合简化未解引用)两种形态。 - if HT.is_nonlocal_name(trans, method_obj_nm.id) != 0: - nl_obj: llvmlite.Value | t.CPtr = self.Gen.StmtGenDecl.load_nonlocal_var( - trans, method_obj_nm.id) - if nl_obj is not None and nl_obj.Ty is not None: - nl_deref: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase._deref_if_ptr_ptr( - builder, nl_obj) - if nl_deref is None: - nl_deref = nl_obj - nl_struct: llvmlite.LLVMType | t.CPtr = \ - self.Gen.StructGen.get_struct_type_from_value(nl_deref) - if nl_struct is not None: - nl_cls: str = self.Gen.StructGen.get_class_name_by_type( - pool, nl_struct) - if nl_cls is not None: - if self.Gen.CallGenProp._is_list_builtin_method( - nl_cls, func_name) == 0: - if hit_box is not None: - hit_box[0] = 1 - return self.Gen.CallGenCall._translate_method_call( - pool, builder, mod, nl_cls, func_name, - nl_deref, cl, trans) - # 非 local 对象但分派未成功:绝不回退 lookup_var - # (其 Alloca 是父函数存储,跨函数引用 → SSA 错乱), - # 返回 None 让上层 fast-fail 暴露类型解析问题。 - return 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 - # [DEPDBG] 临时诊断:方法返回类型解析依赖未就绪即 pending 的根因(用后移除) - dbg_ms6: str = trans.ModuleSha1 if (trans is not None and trans.ModuleSha1 is not None) else "?" - stdio.printf("[DEPDBG] pending(dispatch_ret): mod=%s cls=%s method=%s sha1=%s\n", - dbg_ms6, cls_nm2, func_name, - sha1_fc if sha1_fc is not None else "none") - # 依赖未就绪:保持默认 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 - # [DEPDBG] 临时诊断:特殊方法依赖未就绪即 pending 的根因(用后移除) - dbg_ms7: str = trans.ModuleSha1 if (trans is not None and trans.ModuleSha1 is not None) else "?" - stdio.printf("[DEPDBG] pending(dispatch_sp): mod=%s cls=%s method=%s\n", - dbg_ms7, cls_nm2, func_name) - 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) - +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.Generator as Generator +import lib.core.Gen.Expr.ExprGenCls as ExprGenCls +import lib.core.Gen.Expr.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.Gen.Translator as HT +import lib.Stub.StubMerger as StubMerger +import lib.core.CompilerFactory as CompilerFactory + +import lib.core.Gen.Call.CallGenBase as CallGenBase +import lib.core.Gen.GenApi as GenApi + + +# ============================================================ +# 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) + # 及 coro.* 协程库拦截(coro.coro_run 内联翻译,TPV-M1) + 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) + is_coro_mod: int = 0 + if mod_nm.id is not None and string.strcmp(mod_nm.id, "coro") == 0: + is_coro_mod = 1 + if mod_nm.id is not None and (string.strcmp(mod_nm.id, "c") == 0 or is_coro_mod != 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") + elif is_coro_mod != 0 and string.strcmp(func_name, "coro_run") == 0: + # coro.coro_run(帧):内联翻译(resume 循环到 done,返回帧 ret 槽) + # 对齐 TPC HandlesAsyncFunctions._HandleCoroRunLlvm + # 注意:coro.* 系列 translate_coro_* 签名统一是 + # (builder, pool, mod, cl, trans),与本文件其它 c.* 分支的 + # (pool, builder, ...) 顺序不同,勿混用。 + return self.Gen.AsyncGen.translate_coro_run( + builder, pool, mod, cl, trans) + elif is_coro_mod != 0 and string.strcmp(func_name, "coro_destroy") == 0: + # coro.coro_destroy(帧):帧回池(M7 free-list) + return self.Gen.AsyncGen.translate_coro_destroy( + builder, pool, mod, cl, trans) + elif is_coro_mod != 0 and string.strcmp(func_name, "coro_exception") == 0: + # coro.coro_exception(帧):返回帧 exc 槽(M4) + return self.Gen.AsyncGen.translate_coro_exception( + builder, pool, mod, cl, trans) + elif is_coro_mod != 0 and string.strcmp(func_name, "coro_exception_msg") == 0: + # coro.coro_exception_msg(帧):返回帧 msg 槽(M7) + return self.Gen.AsyncGen.translate_coro_exception_msg( + builder, pool, mod, cl, trans) + elif is_coro_mod != 0 and string.strcmp(func_name, "coro_gather") == 0: + # coro.coro_gather(帧...):并发推进全部协程(M4) + return self.Gen.AsyncGen.translate_coro_gather( + builder, pool, mod, cl, trans) + 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: + # t.CType 特殊形式:t.CType(value, TypeName, t.CPtr) → + # 把 value 转为 TypeName|t.CPtr(TypeName* 指针)。TypeName + # 是类型名(Name/Attribute),不是值表达式——此前被当普通 + # 参数翻译 → NameError: 未定义名称 'memory_block' + # (VKernel mm.vp merge_blocks 根因)。CType 不是 map_t_type + # 的具名类型,须在此显式处理,否则跌落到跨模块 FATAL。 + if string.strcmp(func_name, "CType") == 0 and can >= 2: + cty_node: ast.AST | t.CPtr = cargs.get(1) + ctype_target: llvmlite.LLVMType | t.CPtr = None + if cty_node is not None: + cti_imp: str = None + cti_fi: str = None + if trans is not None: + cti_imp = trans._imported_modules + cti_fi = trans._from_imports + ctype_target = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, cty_node, cti_imp, cti_fi, trans, 0) + if ctype_target is not None: + if can == 3: + cty_arg3: ast.AST | t.CPtr = cargs.get(2) + cty_is_cptr: int = 0 + if cty_arg3 is not None: + # 形式 1: t.CPtr(Attribute) + if cty_arg3.kind() == ast.ASTKind.Attribute: + cty_at3: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cty_arg3) + if cty_at3.attr is not None and string.strcmp(cty_at3.attr, "CPtr") == 0: + if cty_at3.value is not None and cty_at3.value.kind() == ast.ASTKind.Name: + cty_nm3: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cty_at3.value) + if cty_nm3.id is not None and string.strcmp(cty_nm3.id, "t") == 0: + cty_is_cptr = 1 + # 形式 2: 裸名 CPtr + elif cty_arg3.kind() == ast.ASTKind.Name: + cty_bn3: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cty_arg3) + if cty_bn3.id is not None and string.strcmp(cty_bn3.id, "CPtr") == 0: + cty_is_cptr = 1 + if cty_is_cptr != 0: + # CVoid* → i8*(LLVM 中 void* 表示为 i8*) + match ctype_target: + case llvmlite.LLVMType.Void(): + ctype_target = llvmlite.Int8(pool) + case _: + pass + ctype_target = llvmlite.Ptr(pool, ctype_target) + cty_arg0: ast.AST | t.CPtr = cargs.get(0) + if cty_arg0 is not None: + cty_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cty_arg0, funcs_ptr, func_count, trans) + if cty_val is not None: + return self.Gen.CallGenCtor._translate_t_type_cast( + pool, builder, cty_val, ctype_target, + func_name, cty_arg0, trans) + # t.CType 语法已确认:即使类型解析失败也不跌落到跨模块 FATAL + return None + # CConst const 标记:CConst(val, t.CPtr) → Ptr(i8)(const void*)。 + # CConst 不是 map_t_type 具名类型——t.CConst|t.CChar|t.CPtr 注解 = + # const char*(i8*),显式调用 t.CConst(addr, t.CPtr) 把整数地址转 + # const 指针。此前 map_t_type 失败 → 跌落跨模块函数调用 → 生成 + # call @CConst(裸名,无 obj 定义)→ ld.lld undefined symbol: + # CConst(elf.vp L650 t.CConst(t.CUInt64T(strtab_ptr)+sym.st_name, + # t.CPtr) 根因)。单参 CConst(x) 仅 const 限定,LLVM 类型不变, + # 直接返回原值。 + if string.strcmp(func_name, "CConst") == 0: + if can >= 2: + cconst_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + cconst_arg: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) + if cconst_arg is not None: + return self.Gen.CallGenCtor._translate_t_type_cast( + pool, builder, cconst_arg, cconst_ptr_ty, + func_name, cargs.get(0), trans) + elif can == 1: + return self.Gen.ExprGen.translate_value( + builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) + return None + 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, 0) + 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, 0) + # 泛型类型参数双参数形式: 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, trans._from_imports) + 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")。 + """ + # REnum.kind() 编译期转 __tag 读取(位置 0 i32): + # REnum 无 kind 方法(源码无、编译器不生成),此前 .kind() 被方法查找 + # 兜底误绑到 ast.AST.kind(this 偏移,语义错误)。此处直接翻译为 + # bitcast obj 到 i32* + load —— 零函数调用,返回变体 tag。 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + rk_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if rk_at is not None and rk_at.attr is not None \ + and string.strcmp(rk_at.attr, "kind") == 0: + rk_obj: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, rk_at.value, None, 0, trans) + if rk_obj is not None and rk_obj.Ty is not None: + rk_ty: llvmlite.LLVMType | t.CPtr = rk_obj.Ty + rk_load: int = 0 + if self.Gen.ExprGenBase.is_ptr_type(rk_ty) != 0: + rk_pointee: llvmlite.LLVMType | t.CPtr = rk_ty.Pointee + # 联合简化双指针(Ptr(Ptr(Struct)))→ 解一层 + load + if rk_pointee is not None \ + and self.Gen.ExprGenBase.is_ptr_type(rk_pointee) != 0: + rk_pointee = rk_pointee.Pointee + rk_load = 1 + rk_cls: str = self.Gen.StructGen.get_class_name_by_type(pool, rk_pointee) + if rk_cls is not None \ + and self.Gen.ClassGenEnum._is_renum_class_name(rk_cls) != 0: + rk_val: llvmlite.Value | t.CPtr = rk_obj + if rk_load != 0: + rk_val = llvmlite.build_load(builder, rk_ty, rk_obj) + if rk_val is not None: + if hit_box is not None: + hit_box[0] = 1 + rk_i32p: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int32(pool)) + rk_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, rk_val, rk_i32p) + return llvmlite.build_load(builder, rk_i32p, rk_cast) + # 检测类名静态/类方法调用: 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_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 变体构造优先于静态/类方法调用: + 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: + # 链式方法调用: a.b().c() —— value 是内层 Call(如 gfx.vp 的 + # eye.Sub(target).Norm())。此前未处理 → 外层 .Norm() 的 value + # 非 Name 跳过方法分支 → 通用路径把 eye.Sub 当属性解析 → + # "属性写入失败: .Sub"。先翻译内层调用得接收者,再方法调用。 + if method_at.value.kind() == ast.ASTKind.Call and trans is not None: + recv_val_c: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, method_at.value, None, 0, trans) + if recv_val_c is not None and recv_val_c.Ty is not None: + recv_ty_c: llvmlite.LLVMType | t.CPtr = recv_val_c.Ty + if self.Gen.ExprGenBase.is_ptr_type(recv_ty_c) != 0: + recv_ty_c = recv_ty_c.Pointee + # 堆对象(@t.Object)双指针 → 再解一层取 struct + if self.Gen.ExprGenBase.is_ptr_type(recv_ty_c) != 0: + recv_ty_c = recv_ty_c.Pointee + recv_cls_c: str = self.Gen.StructGen.get_class_name_by_type( + pool, recv_ty_c) + if recv_cls_c is not None: + if self.Gen.CallGenProp._is_list_builtin_method( + recv_cls_c, method_at.attr) == 0: + obj_ptr_c: llvmlite.Value | t.CPtr = recv_val_c + if self.Gen.ExprGenBase.is_ptr_type(recv_val_c.Ty) != 0 \ + and recv_val_c.Ty.Pointee is not None \ + and self.Gen.ExprGenBase.is_ptr_type(recv_val_c.Ty.Pointee) != 0: + obj_ptr_c = llvmlite.build_load( + builder, recv_val_c.Ty, recv_val_c) + if obj_ptr_c is not None: + if hit_box is not None: + hit_box[0] = 1 + return self.Gen.CallGenCall._translate_method_call( + pool, builder, mod, recv_cls_c, method_at.attr, + obj_ptr_c, cl, trans) + 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: + # nonlocal 对象:提升函数内从 env 读对象指针(load_nonlocal_var), + # 不能 lookup_var 跨函数命中父函数 alloca(SSA 编号错乱 → + # llc "use of undefined value")。entry.get() 等方法调用的 + # 基座对象经此路径解析(closure 隐式捕获场景)。 + # 用 get_struct_type_from_value 递归解 Ptr,兼容 + # Ptr(Struct)(load_nonlocal_var 已 load)与 + # Ptr(Ptr(Struct))(联合简化未解引用)两种形态。 + if GenApi.is_nonlocal_name(trans, method_obj_nm.id) != 0: + nl_obj: llvmlite.Value | t.CPtr = self.Gen.StmtGenDecl.load_nonlocal_var( + trans, method_obj_nm.id) + if nl_obj is not None and nl_obj.Ty is not None: + nl_deref: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase._deref_if_ptr_ptr( + builder, nl_obj) + if nl_deref is None: + nl_deref = nl_obj + nl_struct: llvmlite.LLVMType | t.CPtr = \ + self.Gen.StructGen.get_struct_type_from_value(nl_deref) + if nl_struct is not None: + nl_cls: str = self.Gen.StructGen.get_class_name_by_type( + pool, nl_struct) + if nl_cls is not None: + if self.Gen.CallGenProp._is_list_builtin_method( + nl_cls, func_name) == 0: + if hit_box is not None: + hit_box[0] = 1 + return self.Gen.CallGenCall._translate_method_call( + pool, builder, mod, nl_cls, func_name, + nl_deref, cl, trans) + # 非 local 对象但分派未成功:绝不回退 lookup_var + # (其 Alloca 是父函数存储,跨函数引用 → SSA 错乱), + # 返回 None 让上层 fast-fail 暴露类型解析问题。 + return 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 + # [DEPDBG] 临时诊断:方法返回类型解析依赖未就绪即 pending 的根因(用后移除) + dbg_ms6: str = trans.ModuleSha1 if (trans is not None and trans.ModuleSha1 is not None) else "?" + stdio.printf("[DEPDBG] pending(dispatch_ret): mod=%s cls=%s method=%s sha1=%s\n", + dbg_ms6, cls_nm2, func_name, + sha1_fc if sha1_fc is not None else "none") + # 依赖未就绪:保持默认 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 + # [DEPDBG] 临时诊断:特殊方法依赖未就绪即 pending 的根因(用后移除) + dbg_ms7: str = trans.ModuleSha1 if (trans is not None and trans.ModuleSha1 is not None) else "?" + stdio.printf("[DEPDBG] pending(dispatch_sp): mod=%s cls=%s method=%s\n", + dbg_ms7, cls_nm2, func_name) + 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/Call/CallGenFd.vp b/App/lib/core/Gen/Call/CallGenFd.vp index b1f90ef..2e273bd 100644 --- a/App/lib/core/Gen/Call/CallGenFd.vp +++ b/App/lib/core/Gen/Call/CallGenFd.vp @@ -11,11 +11,8 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall import lib.core.CompilerFactory as CompilerFactory import lib.core.Gen.Call.CallGenBase as CallGenBase diff --git a/App/lib/core/Gen/Call/CallGenLeafKit.vp b/App/lib/core/Gen/Call/CallGenLeafKit.vp index 4701306..b4eb98d 100644 --- a/App/lib/core/Gen/Call/CallGenLeafKit.vp +++ b/App/lib/core/Gen/Call/CallGenLeafKit.vp @@ -11,11 +11,9 @@ 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.Gen.GenApi as GenApi +import lib.core.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall import lib.core.CompilerFactory as CompilerFactory import lib.core.Gen.Call.CallGenCBuiltin as CallGenCBuiltin @@ -1293,11 +1291,53 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin): 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__()) + trans: HT.Translator | t.CPtr) -> ExprCallHandle | t.CPtr: + h: ExprCallHandle | t.CPtr = pool.alloc(ExprCallHandle.__sizeof__()) if h is None: return None - string.memset(h, 0, HandlesExprCall.ExprCallHandle.__sizeof__()) + string.memset(h, 0, ExprCallHandle.__sizeof__()) h.Trans = trans return h + +# ============================================================ +# ExprCallHandle - 函数调用处理器(自 HandlesExprCall 迁入) +# +# HandleCall / HandlePrintfCall / HandlePrintCall 提供 trans 接口, +# 内部委托 GenApi.translate_call 等。 +# ============================================================ +@t.NoVTable +class ExprCallHandle(HT.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/Gen/Call/CallGenLib.vp b/App/lib/core/Gen/Call/CallGenLib.vp index 97242ec..346aa17 100644 --- a/App/lib/core/Gen/Call/CallGenLib.vp +++ b/App/lib/core/Gen/Call/CallGenLib.vp @@ -10,11 +10,8 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall import lib.core.CompilerFactory as CompilerFactory import lib.core.Gen.Call.CallGenBase as CallGenBase diff --git a/App/lib/core/Gen/Call/CallGenMixin.vp b/App/lib/core/Gen/Call/CallGenMixin.vp index 7d0367f..0d7d260 100644 --- a/App/lib/core/Gen/Call/CallGenMixin.vp +++ b/App/lib/core/Gen/Call/CallGenMixin.vp @@ -1,1359 +1,1356 @@ -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.Stub.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.CompilerFactory as CompilerFactory -import lib.Stub.StubGen.VpiReader as VpiReader - -import lib.core.Gen.Call.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, trans._from_imports) - 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, 0) - 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 - # 模块限定构造 Module.Class(...) 优先:按模块名解析 SHA1 精确命中类。 - # 必须在裸名可见性分支之前——跨模块同名类(VKernel gfx 与 App gfx 都 - # 定义 Scene3D)存在时,裸名 find_struct 返回先注册的错误 entry - # (0ae → ctor 生成 @0ae.Scene3D.__before_init__ → 链接 undefined - # symbol,Scene3D 根因)。模块解析成功即锁定,跳过下方裸名回退。 - mod_qual_done: int = 0 - if trans is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - at_qc0: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - mod_path0: str = None - if at_qc0.value is not None and at_qc0.value.kind() == ast.ASTKind.Name: - mod_nm0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_qc0.value) - if mod_nm0.id is not None: - mod_path0 = mod_nm0.id - elif at_qc0.value is not None and at_qc0.value.kind() == ast.ASTKind.Attribute: - mod_path0 = self.Gen.ExprGenAttr._attr_module_path_str(pool, at_qc0.value) - if mod_path0 is not None: - if self.Gen.ImportsGen.is_module_imported_or_known(trans._imported_modules, mod_path0) != 0: - mod_sha1_0: str = self._lookup_module_sha1(mod_path0) - if mod_sha1_0 is not None: - gen_ctor_entry = self.Gen.StructGen.find_struct_by_module( - func_name, mod_sha1_0) - mod_qual_done = 1 - vis: int = self.Gen.StructGen.is_struct_visible(func_name) - if mod_qual_done == 0 and 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_or_known(trans._imported_modules, mod_nm_qc.id) - if imp_ok != 0: - # 模块限定构造 Module.Class(...):按模块名解析 SHA1 精确命中类。 - # 不能用 trans.ModuleSha1(那是当前文件 sha1,类在 gfx 模块)—— - # find_struct_by_module 落空后裸名回退 find_struct 会命中跨模块 - # 同名类中先注册的 entry(VKernel gfx 与 App gfx 都定义 Scene3D, - # 0ae 先注册 → ctor 生成 @0ae.Scene3D.__before_init__ → 链接 - # undefined symbol,Scene3D 根因)。 - mod_sha1_qc2: str = None - if mod_nm_qc.id is not None: - mod_sha1_qc2 = self._lookup_module_sha1(mod_nm_qc.id) - if mod_sha1_qc2 is not None: - gen_ctor_entry = self.Gen.StructGen.find_struct_by_module( - func_name, mod_sha1_qc2) - 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, t.CSizeT(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, t.CSizeT(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, t.CSizeT(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) - - # async 裸名调用(TPV-M1/M2):普通函数调用 async 函数(如 task(5, 6))→ - # 生成 create_(args...) 调用(返回 Ptr(帧),bitcast 成 i8* 供变量存储)。 - # 对齐 TPC HandlesAsyncFunctions._HandleAsyncCreateCallLlvm。必须在裸名 - # 函数查找之前拦截——async 函数只注册了 create_/resume_,裸名 task 不在 - # 函数表,走普通路径会报"裸名调用未定义且未导入"。 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: - if func_name is not None and trans is not None: - if self.Gen.AsyncGen.is_async_func(trans, func_name) != 0: - can_buf: str = pool.alloc(64) - if can_buf is not None: - viperlib.snprintf(can_buf, 64, "create_%s", func_name) - create_an: str = self.Gen.FuncGenBase._mangle_func_name( - trans, can_buf, 0) - create_fn_an: llvmlite.Function | t.CPtr = self.find_func_in_module( - mod, create_an) - if create_fn_an is not None: - frame_ty_an: llvmlite.LLVMType | t.CPtr = self.Gen.AsyncGen._lookup_coro_frame( - trans, func_name) - if frame_ty_an is not None: - ret_ptr_ty_an: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, frame_ty_an) - i8_ptr_ty_an: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - # M2:async 调用参数(task(5, 6) → create_task(5, 6)) - arg_head_an: llvmlite.Value | t.CPtr = None - arg_tail_an: llvmlite.Value | t.CPtr = None - arg_cnt_an: int = 0 - if cl.args is not None: - nb_an: t.CSizeT = len(cl.args) - j_an: t.CSizeT = 0 - for j_an in range(nb_an): - av_an: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, cl.args.get(j_an), - None, 0, trans) - if av_an is None: - av_an = llvmlite.const_int32(pool, 0) - av_an.Next = None - if arg_head_an is None: - arg_head_an = av_an - arg_tail_an = av_an - else: - arg_tail_an.Next = av_an - arg_tail_an = av_an - arg_cnt_an = arg_cnt_an + 1 - child_an: llvmlite.Value | t.CPtr = llvmlite.build_call( - builder, create_an, arg_head_an, arg_cnt_an, - ret_ptr_ty_an, 0) - if child_an is not None: - return llvmlite.build_bitcast(builder, child_an, i8_ptr_ty_an) - return llvmlite.const_int32(pool, 0) - - # 查找函数:优先从函数表按裸名精确匹配(同模块函数), - # 再从模块函数链表按后缀匹配(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_or_known( - trans._imported_modules, xm_mod_path) != 0: - mod_sha1_chk: str = self._lookup_module_sha1(xm_mod_path) - if mod_sha1_chk is None and trans._from_imports is not None: - # import X as Y(如 import fat32_diskio as diskio): - # 精确查不到别名,必须按别名还原后再查(精确→后缀→ - # LookupModNameByAlias 三级)。否则本校验被跳过 → - # find_func_in_module 后缀匹配误命中本模块同名函数 - # (diskio.read 命中 fat32 自身 read)→ call 到错误 - # 符号 + 参数错位 + define 被 4 参调用污染(VKernel - # llc "instruction expected to be numbered" 根因)。 - mod_sha1_chk = self.Gen.StructGen._resolve_module_sha1( - xm_mod_path, trans._from_imports) - 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 - bi_p2: 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) - elif string.strcmp(func_name, "min") == 0 or string.strcmp(func_name, "max") == 0: - # min/max 数值比较(builtins.vp 定义 double 参数/返回, - # int/float 实参经 coerce 提升;两参数) - bi_ret = llvmlite.Double(pool) - bi_p1 = llvmlite.Double(pool) - bi_p2 = llvmlite.Double(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") - if bi_p2 is not None: - llvmlite.add_param(pool, bi_decl, bi_p2, "w") - 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 - # 跨模块返回类型解析的来源模块 SHA1:仅在下方 cl.func 是 - # Attribute(模块.函数) 分支赋值。必须显式初始化 None——此前声明在 - # if 块内、elif mod_ret_sha1 is not None 在外层读取,裸名调用 - # (cl.func 是 Name,如 LLVMModuleCore 方法内裸名 create_global_int) - # 时该 alloca 从未 store,读到栈残留垃圾(0x1)→ - # _LookupMethodRetTyFromTextLL 的 strlen(0x1) 零页崩溃 - # (llvmlite/__init__.vp CreateGlobalInt 翻译时 0xC0000005 根因)。 - mod_ret_sha1: str = 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 = 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 一致) - 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 - elif mod_ret_sha1 is not None: - # 跨模块裸名 CExport 函数(如 mm.malloc → @malloc):found_func=None - # 且 vpi 返回注解缓存未命中时,仍从依赖模块 text.ll/vpi 精确解析 - # 返回类型(对齐 mangled 路径),避免静默默认 i32 截断指针/i64 - # (uhci.vp mm.malloc 根因:call i32 @malloc 截断 0xbb69000 → null)。 - # 依赖模块尚未编译(text.ll/vpi 均未生成)→ 标记 _deps_pending=1 - # 下遍重试,本遍保持默认类型(Phase A 多遍收敛)。 - cross_ret: llvmlite.LLVMType | t.CPtr = None - if trans is not None and trans._declare_only == 0: - cross_ret = self._LookupMethodRetTyFromTextLL( - pool, mod_ret_sha1, None, func_name, 1) - if cross_ret is None: - cross_ret = self._lookup_method_ret_ty_via_vpi( - pool, mod_ret_sha1, None, func_name) - if cross_ret is not None: - call_ret_ty = cross_ret - else: - if trans is not None and trans._declare_only == 0: - if self._dep_text_ll_exists(pool, mod_ret_sha1) == 0: - trans._deps_pending = 1 - call_ret_ty = self.Gen.CallGenLib._infer_external_func_ret_ty(pool, func_name) - else: - call_ret_ty = self.Gen.CallGenLib._infer_external_func_ret_ty(pool, 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: - # 闭包内调用捕获的闭包变量(如 _cmd_cd 调 _build_path): - # 从 env 读闭包对象指针,不能 lookup_var 跨函数命中父函数 - # 闭包 alloca(SSA 错乱 → llc "instruction expected to be - # numbered",Terminal _cmd_cd 根因)。 - if trans is not None and HT.is_nonlocal_name(trans, func_name) != 0: - fp_alloca = self.Gen.StmtGenDecl.load_nonlocal_var(trans, func_name) - if fp_alloca is not None: - # translate_closure_call 期望 i8** 存储(load 一次得闭包 - # 对象指针);load_nonlocal_var 已返回对象指针 → 临时 - # alloca 暂存 - i8_ty_nl: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty_nl: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_nl) - tmp_alloca_nl: llvmlite.Value | t.CPtr = llvmlite.build_alloca( - builder, i8_ptr_ty_nl) - if tmp_alloca_nl is not None: - llvmlite.build_store(builder, fp_alloca, tmp_alloca_nl) - fp_alloca = tmp_alloca_nl - else: - 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: - # 先取形参类型:单引号单字符字面量(CONST_CHAR)传给 str/指针 - # 形参时需物化 1 字符字符串(translate_constant 依据 target_ty - # 判定),否则 coerce inttoptr 把字符值当指针(如 '"'=0x22)→ - # strlen 访问低地址 ASan 崩溃(二代编 StringTest PyI 生成根因)。 - fp: llvmlite.Param | t.CPtr = None - fpty: llvmlite.LLVMType | t.CPtr = None - if found_func is not None: - fp = 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.param_get_ty(fp) - arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, arg, None, 0, trans, fpty) - 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 - # 已知变参 C 库函数(snprintf/sprintf/vsprintf)固定参数 - # 按签名 coerce:stub 未注入时跨模块签名不可见,但固定 - # 参数类型是 C ABI 硬约束(snprintf size 为 i64),不提升 - # 则 call(i32 1024) 与 declare(i64 size) 不匹配,且 Win64 - # 变参槽高 4 字节残留栈垃圾(clean 日志 0x7ff700000052 根因)。 - kvc_ty: llvmlite.LLVMType | t.CPtr = self.Gen.CallGenVa._get_known_vararg_cfunc_param_ty( - pool, func_name, ai) - if kvc_ty is not None: - arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, kvc_ty, arg) - 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) 不匹配 - if fp is not None: - 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: GenTypes.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: GenTypes.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 - for df_di in range(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 - elif found_func is not None: - # 默认参数缺失/表信息不全时的零值兜底: - # 1) df_param_count>0 但 df_defaults 为空(函数表有参数数、无默认值记录) - # → 现有 if 不满足(要求 df_defaults 非 None 且 default_count>0), - # 缺参调用按 x64 约定读 [rsp+0x28] 栈参数区垃圾 → ASan 崩溃。 - # 2) 调用方文件先于定义文件编译(编译顺序问题,如 Phase1Main 调 - # StubMergerBuild._BuildReachableSha1Set 缺 app_deps), - # find_func_entry_in_table/find_func_defaults 均查不到(df_param_count=0) - # → 同样缺参崩溃。 - # 两种情况都用 found_func 实际参数数兜底,缺参填零值 - # (对齐 TPC _fill_default_args 的零值兜底语义;found_func 是 stub - # declare,参数数与 define 一致,按它填充安全)。 - # 注意排除 EH 输出参数(%__eh_msg_out__/%__eh_code_out__): - # 含 raise 的函数定义尾部注入 2 个 EH 形参,若计入 fc_cnt 会为 - # raise_disk() 这类无参调用补 2 个 zeroinitializer 占位,随后 - # _emit_eh_guarded_call 又追加真实 EH 实参 → call 4 参 vs define - # 2 参 → x64 ABI 错位 → 函数写 null 输出指针 → 0xC0000005 - # (TestFBProject raise_disk 崩溃根因)。 - fc_cnt: int = 0 - fc_p: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) - while fc_p is not None: - fp_nm_z: str = llvmlite.param_get_name(fc_p) - if fp_nm_z is None or (string.strcmp(fp_nm_z, "%__eh_msg_out__") != 0 - and string.strcmp(fp_nm_z, "%__eh_code_out__") != 0): - fc_cnt += 1 - fc_p = llvmlite.param_get_next(fc_p) - if fc_cnt == 0: - fc_cnt = df_param_count if df_param_count > 0 else 0 - if can < fc_cnt: - fp_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) - fpi_z: int = 0 - while fp_z is not None and fpi_z < can: - fp_z = llvmlite.param_get_next(fp_z) - fpi_z += 1 - while fp_z is not None and fpi_z < fc_cnt: - zero_ty_z: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(fp_z) - zero_val_z: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, zero_ty_z) - if zero_val_z is not None: - zero_val_z.Next = None - if head is None: - head = zero_val_z - else: - tail.Next = zero_val_z - tail = zero_val_z - fp_z = llvmlite.param_get_next(fp_z) - fpi_z += 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 - # CExport 裸名兜底:跨模块 stub declare 可能带 SHA1 前缀 - # (@"1fdad1c76fb116bc.malloc"),但定义端 CExport 函数 - # (mm.vp malloc/free/malloc_direct,返回注解含 t.CExport) - # 用裸名 @malloc → 链接 undefined symbol: 1fdad1c76fb116bc.malloc。 - # found_func 非 None 时下方 is_cexport_func 裸名分支不执行 - # (该分支仅 found_func None 的模块限定路径),这里对带前缀 - # 的 declare 提取 sha1 再查 CExport 注册表,命中则改用裸名。 - if found_func.IsDeclared != 0: - dot_pos_cx: str = string.strchr(found_name, 46) - if dot_pos_cx is not None: - cx_pre_len: t.CSizeT = string.strlen(found_name) - string.strlen(dot_pos_cx) - if cx_pre_len == 16: - cx_sha1_buf: str = pool.alloc(17) - if cx_sha1_buf is not None: - string.memcpy(cx_sha1_buf, found_name, 16) - cx_sha1_buf[16] = '\0' - if self.Gen.CallGenBase.is_cexport_func(cx_sha1_buf, func_name) != 0: - call_name = func_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_or_known( - 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: - self.Gen.TypeGenErr.fatal_error( - node, - f"跨模块函数返回类型无法精确获取(text.ll/vpi 均未命中),默认 i32 会截断指针: {call_name}", - "TypeError") - else: - if trans is not None: - trans._deps_pending = 1 - if VLogger._nowarn_register == 0: - VLogger.warning(f"跨模块函数 '{call_name}' 依赖模块 text.ll 尚未生成(Phase A 顺序)," - "标记重试,本遍保持默认类型", "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, t.CSizeT(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) - - - - - - - - - - - - - +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.Gen.Translator as HT +import lib.Stub.StubMerger as StubMerger +import lib.core.CompilerFactory as CompilerFactory +import lib.Stub.StubGen.VpiReader as VpiReader + +import lib.core.Gen.Call.CallGenBase as CallGenBase +import lib.core.Gen.GenApi as GenApi + + +# ============================================================ +# 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, trans._from_imports) + 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, 0) + 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 + # 模块限定构造 Module.Class(...) 优先:按模块名解析 SHA1 精确命中类。 + # 必须在裸名可见性分支之前——跨模块同名类(VKernel gfx 与 App gfx 都 + # 定义 Scene3D)存在时,裸名 find_struct 返回先注册的错误 entry + # (0ae → ctor 生成 @0ae.Scene3D.__before_init__ → 链接 undefined + # symbol,Scene3D 根因)。模块解析成功即锁定,跳过下方裸名回退。 + mod_qual_done: int = 0 + if trans is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + at_qc0: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + mod_path0: str = None + if at_qc0.value is not None and at_qc0.value.kind() == ast.ASTKind.Name: + mod_nm0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_qc0.value) + if mod_nm0.id is not None: + mod_path0 = mod_nm0.id + elif at_qc0.value is not None and at_qc0.value.kind() == ast.ASTKind.Attribute: + mod_path0 = self.Gen.ExprGenAttr._attr_module_path_str(pool, at_qc0.value) + if mod_path0 is not None: + if self.Gen.ImportsGen.is_module_imported_or_known(trans._imported_modules, mod_path0) != 0: + mod_sha1_0: str = self._lookup_module_sha1(mod_path0) + if mod_sha1_0 is not None: + gen_ctor_entry = self.Gen.StructGen.find_struct_by_module( + func_name, mod_sha1_0) + mod_qual_done = 1 + vis: int = self.Gen.StructGen.is_struct_visible(func_name) + if mod_qual_done == 0 and 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_or_known(trans._imported_modules, mod_nm_qc.id) + if imp_ok != 0: + # 模块限定构造 Module.Class(...):按模块名解析 SHA1 精确命中类。 + # 不能用 trans.ModuleSha1(那是当前文件 sha1,类在 gfx 模块)—— + # find_struct_by_module 落空后裸名回退 find_struct 会命中跨模块 + # 同名类中先注册的 entry(VKernel gfx 与 App gfx 都定义 Scene3D, + # 0ae 先注册 → ctor 生成 @0ae.Scene3D.__before_init__ → 链接 + # undefined symbol,Scene3D 根因)。 + mod_sha1_qc2: str = None + if mod_nm_qc.id is not None: + mod_sha1_qc2 = self._lookup_module_sha1(mod_nm_qc.id) + if mod_sha1_qc2 is not None: + gen_ctor_entry = self.Gen.StructGen.find_struct_by_module( + func_name, mod_sha1_qc2) + 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, t.CSizeT(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, t.CSizeT(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, t.CSizeT(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) + + # async 裸名调用(TPV-M1/M2):普通函数调用 async 函数(如 task(5, 6))→ + # 生成 create_(args...) 调用(返回 Ptr(帧),bitcast 成 i8* 供变量存储)。 + # 对齐 TPC HandlesAsyncFunctions._HandleAsyncCreateCallLlvm。必须在裸名 + # 函数查找之前拦截——async 函数只注册了 create_/resume_,裸名 task 不在 + # 函数表,走普通路径会报"裸名调用未定义且未导入"。 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: + if func_name is not None and trans is not None: + if self.Gen.AsyncGen.is_async_func(trans, func_name) != 0: + can_buf: str = pool.alloc(64) + if can_buf is not None: + viperlib.snprintf(can_buf, 64, "create_%s", func_name) + create_an: str = self.Gen.FuncGenBase._mangle_func_name( + trans, can_buf, 0) + create_fn_an: llvmlite.Function | t.CPtr = self.find_func_in_module( + mod, create_an) + if create_fn_an is not None: + frame_ty_an: llvmlite.LLVMType | t.CPtr = self.Gen.AsyncGen._lookup_coro_frame( + trans, func_name) + if frame_ty_an is not None: + ret_ptr_ty_an: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, frame_ty_an) + i8_ptr_ty_an: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + # M2:async 调用参数(task(5, 6) → create_task(5, 6)) + arg_head_an: llvmlite.Value | t.CPtr = None + arg_tail_an: llvmlite.Value | t.CPtr = None + arg_cnt_an: int = 0 + if cl.args is not None: + nb_an: t.CSizeT = len(cl.args) + j_an: t.CSizeT = 0 + for j_an in range(nb_an): + av_an: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cl.args.get(j_an), + None, 0, trans) + if av_an is None: + av_an = llvmlite.const_int32(pool, 0) + av_an.Next = None + if arg_head_an is None: + arg_head_an = av_an + arg_tail_an = av_an + else: + arg_tail_an.Next = av_an + arg_tail_an = av_an + arg_cnt_an = arg_cnt_an + 1 + child_an: llvmlite.Value | t.CPtr = llvmlite.build_call( + builder, create_an, arg_head_an, arg_cnt_an, + ret_ptr_ty_an, 0) + if child_an is not None: + return llvmlite.build_bitcast(builder, child_an, i8_ptr_ty_an) + return llvmlite.const_int32(pool, 0) + + # 查找函数:优先从函数表按裸名精确匹配(同模块函数), + # 再从模块函数链表按后缀匹配(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_or_known( + trans._imported_modules, xm_mod_path) != 0: + mod_sha1_chk: str = self._lookup_module_sha1(xm_mod_path) + if mod_sha1_chk is None and trans._from_imports is not None: + # import X as Y(如 import fat32_diskio as diskio): + # 精确查不到别名,必须按别名还原后再查(精确→后缀→ + # LookupModNameByAlias 三级)。否则本校验被跳过 → + # find_func_in_module 后缀匹配误命中本模块同名函数 + # (diskio.read 命中 fat32 自身 read)→ call 到错误 + # 符号 + 参数错位 + define 被 4 参调用污染(VKernel + # llc "instruction expected to be numbered" 根因)。 + mod_sha1_chk = self.Gen.StructGen._resolve_module_sha1( + xm_mod_path, trans._from_imports) + 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 + bi_p2: 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) + elif string.strcmp(func_name, "min") == 0 or string.strcmp(func_name, "max") == 0: + # min/max 数值比较(builtins.vp 定义 double 参数/返回, + # int/float 实参经 coerce 提升;两参数) + bi_ret = llvmlite.Double(pool) + bi_p1 = llvmlite.Double(pool) + bi_p2 = llvmlite.Double(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") + if bi_p2 is not None: + llvmlite.add_param(pool, bi_decl, bi_p2, "w") + 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 + # 跨模块返回类型解析的来源模块 SHA1:仅在下方 cl.func 是 + # Attribute(模块.函数) 分支赋值。必须显式初始化 None——此前声明在 + # if 块内、elif mod_ret_sha1 is not None 在外层读取,裸名调用 + # (cl.func 是 Name,如 LLVMModuleCore 方法内裸名 create_global_int) + # 时该 alloca 从未 store,读到栈残留垃圾(0x1)→ + # _LookupMethodRetTyFromTextLL 的 strlen(0x1) 零页崩溃 + # (llvmlite/__init__.vp CreateGlobalInt 翻译时 0xC0000005 根因)。 + mod_ret_sha1: str = 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 = 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 一致) + 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 + elif mod_ret_sha1 is not None: + # 跨模块裸名 CExport 函数(如 mm.malloc → @malloc):found_func=None + # 且 vpi 返回注解缓存未命中时,仍从依赖模块 text.ll/vpi 精确解析 + # 返回类型(对齐 mangled 路径),避免静默默认 i32 截断指针/i64 + # (uhci.vp mm.malloc 根因:call i32 @malloc 截断 0xbb69000 → null)。 + # 依赖模块尚未编译(text.ll/vpi 均未生成)→ 标记 _deps_pending=1 + # 下遍重试,本遍保持默认类型(Phase A 多遍收敛)。 + cross_ret: llvmlite.LLVMType | t.CPtr = None + if trans is not None and trans._declare_only == 0: + cross_ret = self._LookupMethodRetTyFromTextLL( + pool, mod_ret_sha1, None, func_name, 1) + if cross_ret is None: + cross_ret = self._lookup_method_ret_ty_via_vpi( + pool, mod_ret_sha1, None, func_name) + if cross_ret is not None: + call_ret_ty = cross_ret + else: + if trans is not None and trans._declare_only == 0: + if self._dep_text_ll_exists(pool, mod_ret_sha1) == 0: + trans._deps_pending = 1 + call_ret_ty = self.Gen.CallGenLib._infer_external_func_ret_ty(pool, func_name) + else: + call_ret_ty = self.Gen.CallGenLib._infer_external_func_ret_ty(pool, 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: + # 闭包内调用捕获的闭包变量(如 _cmd_cd 调 _build_path): + # 从 env 读闭包对象指针,不能 lookup_var 跨函数命中父函数 + # 闭包 alloca(SSA 错乱 → llc "instruction expected to be + # numbered",Terminal _cmd_cd 根因)。 + if trans is not None and GenApi.is_nonlocal_name(trans, func_name) != 0: + fp_alloca = self.Gen.StmtGenDecl.load_nonlocal_var(trans, func_name) + if fp_alloca is not None: + # translate_closure_call 期望 i8** 存储(load 一次得闭包 + # 对象指针);load_nonlocal_var 已返回对象指针 → 临时 + # alloca 暂存 + i8_ty_nl: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty_nl: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_nl) + tmp_alloca_nl: llvmlite.Value | t.CPtr = llvmlite.build_alloca( + builder, i8_ptr_ty_nl) + if tmp_alloca_nl is not None: + llvmlite.build_store(builder, fp_alloca, tmp_alloca_nl) + fp_alloca = tmp_alloca_nl + else: + 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: + # 先取形参类型:单引号单字符字面量(CONST_CHAR)传给 str/指针 + # 形参时需物化 1 字符字符串(translate_constant 依据 target_ty + # 判定),否则 coerce inttoptr 把字符值当指针(如 '"'=0x22)→ + # strlen 访问低地址 ASan 崩溃(二代编 StringTest PyI 生成根因)。 + fp: llvmlite.Param | t.CPtr = None + fpty: llvmlite.LLVMType | t.CPtr = None + if found_func is not None: + fp = 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.param_get_ty(fp) + arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg, None, 0, trans, fpty) + 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 + # 已知变参 C 库函数(snprintf/sprintf/vsprintf)固定参数 + # 按签名 coerce:stub 未注入时跨模块签名不可见,但固定 + # 参数类型是 C ABI 硬约束(snprintf size 为 i64),不提升 + # 则 call(i32 1024) 与 declare(i64 size) 不匹配,且 Win64 + # 变参槽高 4 字节残留栈垃圾(clean 日志 0x7ff700000052 根因)。 + kvc_ty: llvmlite.LLVMType | t.CPtr = self.Gen.CallGenVa._get_known_vararg_cfunc_param_ty( + pool, func_name, ai) + if kvc_ty is not None: + arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, kvc_ty, arg) + 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) 不匹配 + if fp is not None: + 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: GenTypes.FuncEntry | t.CPtr = self.Gen.CallGenLeafKit.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: GenTypes.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 + for df_di in range(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 + elif found_func is not None: + # 默认参数缺失/表信息不全时的零值兜底: + # 1) df_param_count>0 但 df_defaults 为空(函数表有参数数、无默认值记录) + # → 现有 if 不满足(要求 df_defaults 非 None 且 default_count>0), + # 缺参调用按 x64 约定读 [rsp+0x28] 栈参数区垃圾 → ASan 崩溃。 + # 2) 调用方文件先于定义文件编译(编译顺序问题,如 Phase1Main 调 + # StubMergerBuild._BuildReachableSha1Set 缺 app_deps), + # find_func_entry_in_table/find_func_defaults 均查不到(df_param_count=0) + # → 同样缺参崩溃。 + # 两种情况都用 found_func 实际参数数兜底,缺参填零值 + # (对齐 TPC _fill_default_args 的零值兜底语义;found_func 是 stub + # declare,参数数与 define 一致,按它填充安全)。 + # 注意排除 EH 输出参数(%__eh_msg_out__/%__eh_code_out__): + # 含 raise 的函数定义尾部注入 2 个 EH 形参,若计入 fc_cnt 会为 + # raise_disk() 这类无参调用补 2 个 zeroinitializer 占位,随后 + # _emit_eh_guarded_call 又追加真实 EH 实参 → call 4 参 vs define + # 2 参 → x64 ABI 错位 → 函数写 null 输出指针 → 0xC0000005 + # (TestFBProject raise_disk 崩溃根因)。 + fc_cnt: int = 0 + fc_p: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + while fc_p is not None: + fp_nm_z: str = llvmlite.param_get_name(fc_p) + if fp_nm_z is None or (string.strcmp(fp_nm_z, "%__eh_msg_out__") != 0 + and string.strcmp(fp_nm_z, "%__eh_code_out__") != 0): + fc_cnt += 1 + fc_p = llvmlite.param_get_next(fc_p) + if fc_cnt == 0: + fc_cnt = df_param_count if df_param_count > 0 else 0 + if can < fc_cnt: + fp_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + fpi_z: int = 0 + while fp_z is not None and fpi_z < can: + fp_z = llvmlite.param_get_next(fp_z) + fpi_z += 1 + while fp_z is not None and fpi_z < fc_cnt: + zero_ty_z: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(fp_z) + zero_val_z: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, zero_ty_z) + if zero_val_z is not None: + zero_val_z.Next = None + if head is None: + head = zero_val_z + else: + tail.Next = zero_val_z + tail = zero_val_z + fp_z = llvmlite.param_get_next(fp_z) + fpi_z += 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 + # CExport 裸名兜底:跨模块 stub declare 可能带 SHA1 前缀 + # (@"1fdad1c76fb116bc.malloc"),但定义端 CExport 函数 + # (mm.vp malloc/free/malloc_direct,返回注解含 t.CExport) + # 用裸名 @malloc → 链接 undefined symbol: 1fdad1c76fb116bc.malloc。 + # found_func 非 None 时下方 is_cexport_func 裸名分支不执行 + # (该分支仅 found_func None 的模块限定路径),这里对带前缀 + # 的 declare 提取 sha1 再查 CExport 注册表,命中则改用裸名。 + if found_func.IsDeclared != 0: + dot_pos_cx: str = string.strchr(found_name, 46) + if dot_pos_cx is not None: + cx_pre_len: t.CSizeT = string.strlen(found_name) - string.strlen(dot_pos_cx) + if cx_pre_len == 16: + cx_sha1_buf: str = pool.alloc(17) + if cx_sha1_buf is not None: + string.memcpy(cx_sha1_buf, found_name, 16) + cx_sha1_buf[16] = '\0' + if self.Gen.CallGenBase.is_cexport_func(cx_sha1_buf, func_name) != 0: + call_name = func_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_or_known( + 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: + self.Gen.TypeGenErr.fatal_error( + node, + f"跨模块函数返回类型无法精确获取(text.ll/vpi 均未命中),默认 i32 会截断指针: {call_name}", + "TypeError") + else: + if trans is not None: + trans._deps_pending = 1 + if VLogger._nowarn_register == 0: + VLogger.warning(f"跨模块函数 '{call_name}' 依赖模块 text.ll 尚未生成(Phase A 顺序)," + "标记重试,本遍保持默认类型", "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, t.CSizeT(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/Call/CallGenProp.vp b/App/lib/core/Gen/Call/CallGenProp.vp index 0b2553f..f7dab50 100644 --- a/App/lib/core/Gen/Call/CallGenProp.vp +++ b/App/lib/core/Gen/Call/CallGenProp.vp @@ -11,11 +11,8 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall import lib.core.CompilerFactory as CompilerFactory import lib.core.Gen.Call.CallGenBase as CallGenBase diff --git a/App/lib/core/Gen/Call/CallGenVa.vp b/App/lib/core/Gen/Call/CallGenVa.vp index d90e9c0..6c9b56c 100644 --- a/App/lib/core/Gen/Call/CallGenVa.vp +++ b/App/lib/core/Gen/Call/CallGenVa.vp @@ -10,11 +10,8 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall import lib.core.CompilerFactory as CompilerFactory import lib.core.Gen.Call.CallGenBase as CallGenBase diff --git a/App/lib/core/Gen/Call/CallGenVt.vp b/App/lib/core/Gen/Call/CallGenVt.vp index 1932be0..9707951 100644 --- a/App/lib/core/Gen/Call/CallGenVt.vp +++ b/App/lib/core/Gen/Call/CallGenVt.vp @@ -13,11 +13,8 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall import lib.core.CompilerFactory as CompilerFactory import lib.core.Gen.Call.CallGenBase as CallGenBase diff --git a/App/lib/core/Gen/Class/ClassGenBase.vp b/App/lib/core/Gen/Class/ClassGenBase.vp index e660b53..a66bfcb 100644 --- a/App/lib/core/Gen/Class/ClassGenBase.vp +++ b/App/lib/core/Gen/Class/ClassGenBase.vp @@ -10,7 +10,7 @@ import stdio import stdlib import viperlib import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT +import lib.core.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger import lib.core.CompilerFactory as CompilerFactory diff --git a/App/lib/core/Gen/Class/ClassGenDef.vp b/App/lib/core/Gen/Class/ClassGenDef.vp index fb8ab52..f33480e 100644 --- a/App/lib/core/Gen/Class/ClassGenDef.vp +++ b/App/lib/core/Gen/Class/ClassGenDef.vp @@ -9,7 +9,7 @@ import stdio import stdlib import viperlib import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT +import lib.core.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger import lib.core.CompilerFactory as CompilerFactory diff --git a/App/lib/core/Gen/Class/ClassGenEnum.vp b/App/lib/core/Gen/Class/ClassGenEnum.vp index bec3572..ce42e35 100644 --- a/App/lib/core/Gen/Class/ClassGenEnum.vp +++ b/App/lib/core/Gen/Class/ClassGenEnum.vp @@ -9,7 +9,7 @@ import stdio import stdlib import viperlib import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT +import lib.core.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger import lib.core.CompilerFactory as CompilerFactory diff --git a/App/lib/core/Gen/Class/ClassGenGeneric.vp b/App/lib/core/Gen/Class/ClassGenGeneric.vp index 85d94e0..df2b40b 100644 --- a/App/lib/core/Gen/Class/ClassGenGeneric.vp +++ b/App/lib/core/Gen/Class/ClassGenGeneric.vp @@ -9,7 +9,7 @@ import stdio import stdlib import viperlib import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT +import lib.core.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger import lib.core.CompilerFactory as CompilerFactory diff --git a/App/lib/core/Gen/Class/ClassGenMixin.vp b/App/lib/core/Gen/Class/ClassGenMixin.vp index e5ec2e3..8b5a97a 100644 --- a/App/lib/core/Gen/Class/ClassGenMixin.vp +++ b/App/lib/core/Gen/Class/ClassGenMixin.vp @@ -8,7 +8,7 @@ import stdio import stdlib import viperlib import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT +import lib.core.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger import lib.core.CompilerFactory as CompilerFactory import lib.core.Gen.Class.ClassGenBase as ClassGenBase diff --git a/App/lib/core/Gen/Class/ClassGenVTable.vp b/App/lib/core/Gen/Class/ClassGenVTable.vp index 4f0746c..f152d5c 100644 --- a/App/lib/core/Gen/Class/ClassGenVTable.vp +++ b/App/lib/core/Gen/Class/ClassGenVTable.vp @@ -1,1305 +1,1305 @@ -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.Stub.StubMerger as StubMerger -import lib.core.CompilerFactory as CompilerFactory - -import lib.core.Gen.Class.ClassGenBase as ClassGenBase -import lib.core.Handles.ExprCallTable as ExprCallTable - - -# 方法元数据 flag:TLS(@t.TLS 装饰器,对齐 ClassGenBase 本地常量;本地副本避免跨模块 CDefine 查找) -META_TLS: t.CDefine = 32 -# 虚表方法数上限(原 HandlesClassDef.VTBL_METHOD_MAX,阶段 D 拆分遗漏) -VTBL_METHOD_MAX: t.CDefine = 32 - -SCOPE_FUNCTION: t.CDefine = 1 - -# ============================================================ -# 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 - - 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.factory.PermPool.alloc(8 * VTBL_METHOD_MAX) - method_names_buf: t.CSizeT | t.CPtr = CompilerFactory.factory.PermPool.alloc(8 * VTBL_METHOD_MAX) - # 记录每个方法的父类 SHA1(非 0=继承方法用父模块 SHA1 mangling,0=当前类方法) - method_parent_sha1s: t.CSizeT | t.CPtr = CompilerFactory.factory.PermPool.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.factory.PermPool.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.factory.PermPool.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.factory.PermPool.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.factory.PermPool.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 - - - 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._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._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 - - - 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 & GenTypes.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 & GenTypes.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 & GenTypes.META_STATIC != 0: - is_static_m = 1 - if func_meta & GenTypes.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._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, 0) - if ret_ty is None and fd.returns is not None: - if self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "State", 0) != 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, 0) - 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, 0) - 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, trans._from_imports) - 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 - # 必须先预扫描 Global/Nonlocal 声明(对齐 FuncGenDef 模块级函数路径), - # 否则 `global BootInfo` 未注册时 prescan 把 BootInfo 当局部创建 alloca, - # 后续翻译 is_global_name 为真又写全局 → 局部 alloca 永不写入 → 读全 0 - # (main.vp __init__ BootInfo memmap 全 0 根因)。 - 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: - 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 - - - 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._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._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] = [...])经类体字段收集 - # 推断为静态数组,此处保证 __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) - +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.Gen.Translator as HT +import lib.Stub.StubMerger as StubMerger +import lib.core.CompilerFactory as CompilerFactory + +import lib.core.Gen.Class.ClassGenBase as ClassGenBase +import lib.core.Gen.GenApi as GenApi + + +# 方法元数据 flag:TLS(@t.TLS 装饰器,对齐 ClassGenBase 本地常量;本地副本避免跨模块 CDefine 查找) +META_TLS: t.CDefine = 32 +# 虚表方法数上限(原 HandlesClassDef.VTBL_METHOD_MAX,阶段 D 拆分遗漏) +VTBL_METHOD_MAX: t.CDefine = 32 + +SCOPE_FUNCTION: t.CDefine = 1 + +# ============================================================ +# 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 + + 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.factory.PermPool.alloc(8 * VTBL_METHOD_MAX) + method_names_buf: t.CSizeT | t.CPtr = CompilerFactory.factory.PermPool.alloc(8 * VTBL_METHOD_MAX) + # 记录每个方法的父类 SHA1(非 0=继承方法用父模块 SHA1 mangling,0=当前类方法) + method_parent_sha1s: t.CSizeT | t.CPtr = CompilerFactory.factory.PermPool.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.factory.PermPool.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.factory.PermPool.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.factory.PermPool.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.factory.PermPool.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 + + + 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._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._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 + + + 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 & GenTypes.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 & GenTypes.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 & GenTypes.META_STATIC != 0: + is_static_m = 1 + if func_meta & GenTypes.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._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, 0) + if ret_ty is None and fd.returns is not None: + if self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "State", 0) != 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, 0) + 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, 0) + 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, trans._from_imports) + 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 + GenApi.clear_scope_names(trans) + + # 预扫描方法体:为局部变量提前创建 alloca + # 必须先预扫描 Global/Nonlocal 声明(对齐 FuncGenDef 模块级函数路径), + # 否则 `global BootInfo` 未注册时 prescan 把 BootInfo 当局部创建 alloca, + # 后续翻译 is_global_name 为真又写全局 → 局部 alloca 永不写入 → 读全 0 + # (main.vp __init__ BootInfo memmap 全 0 根因)。 + 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: + 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 + + + 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._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._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] = [...])经类体字段收集 + # 推断为静态数组,此处保证 __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/Expr/ExprGenAttr.vp b/App/lib/core/Gen/Expr/ExprGenAttr.vp index bb978c4..45a24b3 100644 --- a/App/lib/core/Gen/Expr/ExprGenAttr.vp +++ b/App/lib/core/Gen/Expr/ExprGenAttr.vp @@ -10,10 +10,7 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger import lib.Stub.StubMerger.StubMergerStore as StubMergerStore import lib.Stub.StubMerger.StubMergerBuild as StubMergerBuild @@ -23,6 +20,7 @@ import lib.Projectrans.Utils as Utils import lib.core.Gen.Expr.ExprGenBase as ExprGenBase +import lib.core.Gen.GenApi as GenApi # ============================================================ # ExprGenAttr - ExprGenMixin 拆分(阶段 D):Attribute/属性访问/全局引用 @@ -721,11 +719,11 @@ class ExprGenAttr(ExprGenBase.ExprGenBase): 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: + if GenApi.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( + nl_ty_a: llvmlite.LLVMType | t.CPtr = GenApi.get_nonlocal_type( trans, nm.id) if nl_ty_a is not None: # 对象即指针:Struct/Array 类型直接用堆地址(bitcast 后 @@ -1044,11 +1042,11 @@ class ExprGenAttr(ExprGenBase.ExprGenBase): 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: + if GenApi.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( + nl_ty_a: llvmlite.LLVMType | t.CPtr = GenApi.get_nonlocal_type( trans, nm.id) if nl_ty_a is not None: # 对象即指针:Struct/Array 类型直接用堆地址(bitcast 后 diff --git a/App/lib/core/Gen/Expr/ExprGenBase.vp b/App/lib/core/Gen/Expr/ExprGenBase.vp index 5572ae1..752f97c 100644 --- a/App/lib/core/Gen/Expr/ExprGenBase.vp +++ b/App/lib/core/Gen/Expr/ExprGenBase.vp @@ -10,10 +10,7 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger import lib.core.VLogger as VLogger import lib.Projectrans.Config as Config diff --git a/App/lib/core/Gen/Expr/ExprGenCdef.vp b/App/lib/core/Gen/Expr/ExprGenCdef.vp index c98a1e4..40216f7 100644 --- a/App/lib/core/Gen/Expr/ExprGenCdef.vp +++ b/App/lib/core/Gen/Expr/ExprGenCdef.vp @@ -9,10 +9,7 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger import lib.core.VLogger as VLogger import lib.Projectrans.Config as Config diff --git a/App/lib/core/Gen/Expr/ExprGenCls.vp b/App/lib/core/Gen/Expr/ExprGenCls.vp index fba389f..50a3f3b 100644 --- a/App/lib/core/Gen/Expr/ExprGenCls.vp +++ b/App/lib/core/Gen/Expr/ExprGenCls.vp @@ -12,10 +12,7 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger import lib.core.VLogger as VLogger import lib.Projectrans.Config as Config diff --git a/App/lib/core/Gen/Expr/ExprGenConst.vp b/App/lib/core/Gen/Expr/ExprGenConst.vp index 98be476..addeecb 100644 --- a/App/lib/core/Gen/Expr/ExprGenConst.vp +++ b/App/lib/core/Gen/Expr/ExprGenConst.vp @@ -10,10 +10,7 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger import lib.core.VLogger as VLogger import lib.Projectrans.Config as Config diff --git a/App/lib/core/Gen/Expr/ExprGenFstr.vp b/App/lib/core/Gen/Expr/ExprGenFstr.vp index c273a96..22dbea2 100644 --- a/App/lib/core/Gen/Expr/ExprGenFstr.vp +++ b/App/lib/core/Gen/Expr/ExprGenFstr.vp @@ -9,10 +9,7 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger import lib.core.VLogger as VLogger import lib.Projectrans.Config as Config diff --git a/App/lib/core/Gen/Expr/ExprGenMixin.vp b/App/lib/core/Gen/Expr/ExprGenMixin.vp index ac221d6..895008d 100644 --- a/App/lib/core/Gen/Expr/ExprGenMixin.vp +++ b/App/lib/core/Gen/Expr/ExprGenMixin.vp @@ -9,10 +9,7 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger import lib.core.VLogger as VLogger import lib.Projectrans.Config as Config diff --git a/App/lib/core/Gen/Expr/ExprGenName.vp b/App/lib/core/Gen/Expr/ExprGenName.vp index f0f7e20..dc6de8f 100644 --- a/App/lib/core/Gen/Expr/ExprGenName.vp +++ b/App/lib/core/Gen/Expr/ExprGenName.vp @@ -10,10 +10,7 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger import lib.Stub.StubMerger.StubMergerStore as StubMergerStore import lib.core.VLogger as VLogger @@ -22,6 +19,7 @@ import lib.Projectrans.Utils as Utils import lib.core.Gen.Expr.ExprGenBase as ExprGenBase +import lib.core.Gen.GenApi as GenApi # ============================================================ # ExprGenName - ExprGenMixin 拆分(阶段 D):Name/Subscript/下标访问 @@ -157,7 +155,7 @@ class ExprGenName(ExprGenBase.ExprGenBase): # global 变量:从模块作用域查找(global 声明优先级最高) if trans is not None: - if HT.is_global_name(trans, nm_id) != 0: + if GenApi.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: @@ -181,7 +179,7 @@ class ExprGenName(ExprGenBase.ExprGenBase): return llvmlite.build_load(builder, load_ty, mod_alloca) # nonlocal 变量:通过闭包 env 访问 - if HT.is_nonlocal_name(trans, nm_id) != 0: + if GenApi.is_nonlocal_name(trans, nm_id) != 0: return self.Gen.StmtGenDecl.load_nonlocal_var(trans, nm_id) # *args va_list:变量名直接解析为指向 24 字节 va_list 缓冲区的 i8* 地址 @@ -587,7 +585,7 @@ class ExprGenName(ExprGenBase.ExprGenBase): """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) + nl_ty: llvmlite.LLVMType | t.CPtr = GenApi.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) @@ -702,7 +700,7 @@ class ExprGenName(ExprGenBase.ExprGenBase): # nonlocal 数组/指针:从 env 读共享堆地址(提升函数内不能 # lookup_var 外层 alloca——SSA 编号跨函数错乱崩溃) # 读路径:元素指针 load 出元素值 - if HT.is_nonlocal_name(trans, nm.id) != 0: + if GenApi.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: @@ -1002,7 +1000,7 @@ class ExprGenName(ExprGenBase.ExprGenBase): 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: + if GenApi.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) diff --git a/App/lib/core/Gen/Expr/ExprGenOps.vp b/App/lib/core/Gen/Expr/ExprGenOps.vp index e805a03..2e85901 100644 --- a/App/lib/core/Gen/Expr/ExprGenOps.vp +++ b/App/lib/core/Gen/Expr/ExprGenOps.vp @@ -10,10 +10,7 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger import lib.core.VLogger as VLogger import lib.Projectrans.Config as Config diff --git a/App/lib/core/Gen/Func/FuncGenBase.vp b/App/lib/core/Gen/Func/FuncGenBase.vp index e58b6e9..30fe991 100644 --- a/App/lib/core/Gen/Func/FuncGenBase.vp +++ b/App/lib/core/Gen/Func/FuncGenBase.vp @@ -8,9 +8,7 @@ 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.Translator as HT import lib.core.Gen.Call.CallGenBase as CallGenBase # ============================================================ diff --git a/App/lib/core/Gen/Func/FuncGenDef.vp b/App/lib/core/Gen/Func/FuncGenDef.vp index 78d3bbe..f3c9229 100644 --- a/App/lib/core/Gen/Func/FuncGenDef.vp +++ b/App/lib/core/Gen/Func/FuncGenDef.vp @@ -10,11 +10,9 @@ 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 +import lib.core.Gen.Translator as HT import lib.core.Gen.Call.CallGenBase as CallGenBase +import lib.core.Gen.GenApi as GenApi # ============================================================ @@ -800,7 +798,7 @@ class FuncGenDef(CallGenBase.CallGenBase): trans._cur_func = func trans._cur_builder = func_builder # 清空 global/nonlocal 名称集合(新函数作用域) - HT.clear_scope_names(trans) + GenApi.clear_scope_names(trans) # 重置链内 nonlocal 堆预建标志(每函数只建一次;多嵌套函数定义 # 共享同一堆,防重复 malloc + 二次重定向 VarEntry) trans._nl_chain_done = 0 diff --git a/App/lib/core/Gen/Func/FuncGenMixin.vp b/App/lib/core/Gen/Func/FuncGenMixin.vp index af42d14..8ff4327 100644 --- a/App/lib/core/Gen/Func/FuncGenMixin.vp +++ b/App/lib/core/Gen/Func/FuncGenMixin.vp @@ -1,1564 +1,1563 @@ -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.Call.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, 0) - 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, trans._from_imports) - 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) - - # 8c. 隐式捕获扫描:嵌套函数读取的外层函数局部变量注册为 nonlocal - # (Python 语义,无需显式 nonlocal;否则 read 经 lookup_var - # 跨函数命中父函数 alloca → SSA 编号错乱 → llc undefined value)。 - # 分支内 AnnAssign 局部已由 pre_scan_allocas 递归预注册 - # (StmtGenDeclMixin),本扫描经 lookup_current 自然排除。 - if body is not None: - bnc: t.CSizeT = len(body) - for bic in range(bnc): - stmtc: ast.AST | t.CPtr = body.get(bic) - if stmtc is not None: - self._closure_scan_captures(trans, stmtc) - - # 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 - - # ============================================================ - # _closure_scan_captures - 递归扫描嵌套函数体中的隐式捕获变量 - # - # Python 语义:嵌套函数读取外层函数局部变量无需显式 nonlocal。 - # 此前嵌套 def 闭包仅在显式 `nonlocal` 语句时注册捕获;无 nonlocal - # 的 read 在翻译时会经 lookup_var 跨函数命中父函数 alloca(SSA 编号 - # 属于父函数,提升函数内引用 → llc "use of undefined value '%X'")。 - # lambda 已有 _lambda_scan_body 预扫描,这里对嵌套 def 做等价预扫描: - # 把"读取的外层函数局部变量"注册为 nonlocal(复用 env 共享堆机制), - # 使 read 走 _load_raw_var_ptr 从 env 读堆值。 - # 注意:与 lambda 快照方案不同,嵌套 def 复用显式 nonlocal 的 - # env 共享堆路径,因此注册顺序必须与 step 13 的 env 构建一致 - # (本扫描在 body 翻译前执行,注册顺序稳定)。 - # ============================================================ - def _closure_scan_captures(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """递归扫描节点中的隐式捕获并注册为 nonlocal""" - if node is None or trans is None: - return 1 - 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 1 - # 当前作用域已定义(参数 / AnnAssign 局部,含分支内)→ 非捕获 - if self.Gen.VarGen.lookup_current(trans.SymTab, nm.id) is not None: - return 1 - # 已注册 nonlocal(显式 nonlocal 语句 / 已捕获)→ 跳过 - if HT.is_nonlocal_name(trans, nm.id) != 0: - return 1 - ve: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( - trans.SymTab, nm.id) - if ve is None or ve.Alloca is None or ve.Alloca.Ty is None: - return 1 - nl_ty: llvmlite.LLVMType | t.CPtr = ve.Alloca.Ty.Pointee - if nl_ty is None: - return 1 - # 模块级全局直接解析,无需 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(ve.Alloca): - return 1 - # 外层函数局部变量 → 隐式捕获(注册为 nonlocal) - HT.add_nonlocal_name(trans, nm.id, nl_ty) - return 1 - # ---- 语句 ---- - if k == ast.ASTKind.Assign: - asn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node) - if asn.value is not None: - self._closure_scan_captures(trans, asn.value) - return 1 - if k == ast.ASTKind.AnnAssign: - aan: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) - if aan.value is not None: - self._closure_scan_captures(trans, aan.value) - return 1 - if k == ast.ASTKind.AugAssign: - aun: ast.AugAssign | t.CPtr = (ast.AugAssign | t.CPtr)(node) - # 目标同时是读(先读旧值),参与捕获 - if aun.target is not None: - self._closure_scan_captures(trans, aun.target) - if aun.value is not None: - self._closure_scan_captures(trans, aun.value) - return 1 - if k == ast.ASTKind.If: - ifn: ast.If | t.CPtr = (ast.If | t.CPtr)(node) - if ifn.test is not None: - self._closure_scan_captures(trans, ifn.test) - if ifn.children is not None: - bn_if: t.CSizeT = len(ifn.children) - for bi_if in range(bn_if): - self._closure_scan_captures(trans, ifn.children.get(bi_if)) - if ifn.orelse is not None: - bn_el: t.CSizeT = len(ifn.orelse) - for bi_el in range(bn_el): - self._closure_scan_captures(trans, ifn.orelse.get(bi_el)) - return 1 - if k == ast.ASTKind.For: - for_n: ast.For | t.CPtr = (ast.For | t.CPtr)(node) - # 循环目标是新局部变量,不参与捕获 - if for_n.iter is not None: - self._closure_scan_captures(trans, for_n.iter) - if for_n.children is not None: - bn_f: t.CSizeT = len(for_n.children) - for bi_f in range(bn_f): - self._closure_scan_captures(trans, for_n.children.get(bi_f)) - if for_n.orelse is not None: - bn_fe: t.CSizeT = len(for_n.orelse) - for bi_fe in range(bn_fe): - self._closure_scan_captures(trans, for_n.orelse.get(bi_fe)) - return 1 - if k == ast.ASTKind.While: - wh_n: ast.While | t.CPtr = (ast.While | t.CPtr)(node) - if wh_n.test is not None: - self._closure_scan_captures(trans, wh_n.test) - if wh_n.children is not None: - bn_w: t.CSizeT = len(wh_n.children) - for bi_w in range(bn_w): - self._closure_scan_captures(trans, wh_n.children.get(bi_w)) - if wh_n.orelse is not None: - bn_we: t.CSizeT = len(wh_n.orelse) - for bi_we in range(bn_we): - self._closure_scan_captures(trans, wh_n.orelse.get(bi_we)) - return 1 - if k == ast.ASTKind.Return: - rt_n: ast.Return | t.CPtr = (ast.Return | t.CPtr)(node) - if rt_n.value is not None: - self._closure_scan_captures(trans, rt_n.value) - return 1 - if k == ast.ASTKind.Expr: - ex_n: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(node) - if ex_n.value is not None: - self._closure_scan_captures(trans, ex_n.value) - return 1 - if k == ast.ASTKind.With: - wth: ast.With | t.CPtr = (ast.With | t.CPtr)(node) - if wth.items is not None: - bn_wi: t.CSizeT = len(wth.items) - for bi_wi in range(bn_wi): - wi_n: ast.AST | t.CPtr = wth.items.get(bi_wi) - if wi_n is not None and wi_n.kind() == ast.ASTKind.WithItem: - wi_c: ast.WithItem | t.CPtr = (ast.WithItem | t.CPtr)(wi_n) - if wi_c.context_expr is not None: - self._closure_scan_captures(trans, wi_c.context_expr) - if wth.children is not None: - bn_wb: t.CSizeT = len(wth.children) - for bi_wb in range(bn_wb): - self._closure_scan_captures(trans, wth.children.get(bi_wb)) - return 1 - if k == ast.ASTKind.Raise: - rs_n: ast.Raise | t.CPtr = (ast.Raise | t.CPtr)(node) - if rs_n.exc is not None: - self._closure_scan_captures(trans, rs_n.exc) - if rs_n.cause is not None: - self._closure_scan_captures(trans, rs_n.cause) - return 1 - if k == ast.ASTKind.Assert: - as_n: ast.Assert | t.CPtr = (ast.Assert | t.CPtr)(node) - if as_n.test is not None: - self._closure_scan_captures(trans, as_n.test) - if as_n.msg is not None: - self._closure_scan_captures(trans, as_n.msg) - return 1 - if k == ast.ASTKind.Try: - tr_n: ast.Try | t.CPtr = (ast.Try | t.CPtr)(node) - if tr_n.children is not None: - bn_t: t.CSizeT = len(tr_n.children) - for bi_t in range(bn_t): - self._closure_scan_captures(trans, tr_n.children.get(bi_t)) - if tr_n.handlers is not None: - bn_th: t.CSizeT = len(tr_n.handlers) - for bi_th in range(bn_th): - eh_n: ast.AST | t.CPtr = tr_n.handlers.get(bi_th) - if eh_n is not None and eh_n.kind() == ast.ASTKind.ExceptHandler: - eh_c: ast.ExceptHandler | t.CPtr = (ast.ExceptHandler | t.CPtr)(eh_n) - if eh_c.children is not None: - bn_ehb: t.CSizeT = len(eh_c.children) - for bi_ehb in range(bn_ehb): - self._closure_scan_captures(trans, eh_c.children.get(bi_ehb)) - if tr_n.orelse is not None: - bn_to: t.CSizeT = len(tr_n.orelse) - for bi_to in range(bn_to): - self._closure_scan_captures(trans, tr_n.orelse.get(bi_to)) - if tr_n.finalbody is not None: - bn_tf: t.CSizeT = len(tr_n.finalbody) - for bi_tf in range(bn_tf): - self._closure_scan_captures(trans, tr_n.finalbody.get(bi_tf)) - return 1 - if k == ast.ASTKind.Match: - mt_n: ast.Match | t.CPtr = (ast.Match | t.CPtr)(node) - if mt_n.subject is not None: - self._closure_scan_captures(trans, mt_n.subject) - if mt_n.cases is not None: - bn_mc: t.CSizeT = len(mt_n.cases) - for bi_mc in range(bn_mc): - mc_n: ast.AST | t.CPtr = mt_n.cases.get(bi_mc) - if mc_n is not None and mc_n.kind() == ast.ASTKind.MatchCase: - mc_c: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(mc_n) - if mc_c.guard is not None: - self._closure_scan_captures(trans, mc_c.guard) - if mc_c.children is not None: - bn_mcb: t.CSizeT = len(mc_c.children) - for bi_mcb in range(bn_mcb): - self._closure_scan_captures(trans, mc_c.children.get(bi_mcb)) - return 1 - # ---- 表达式 ---- - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - if bop.left is not None: - self._closure_scan_captures(trans, bop.left) - if bop.right is not None: - self._closure_scan_captures(trans, bop.right) - return 1 - if k == ast.ASTKind.UnaryOp: - uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) - if uop.operand is not None: - self._closure_scan_captures(trans, uop.operand) - return 1 - if k == ast.ASTKind.BoolOp: - bop2: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) - if bop2.values is not None: - bn_bo: t.CSizeT = len(bop2.values) - for bi_bo in range(bn_bo): - self._closure_scan_captures(trans, bop2.values.get(bi_bo)) - return 1 - if k == ast.ASTKind.Compare: - cmp: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) - if cmp.left is not None: - self._closure_scan_captures(trans, cmp.left) - if cmp.comparators is not None: - bn_cmp: t.CSizeT = len(cmp.comparators) - for bi_cmp in range(bn_cmp): - self._closure_scan_captures(trans, cmp.comparators.get(bi_cmp)) - return 1 - if k == ast.ASTKind.Call: - cal: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) - if cal.func is not None: - self._closure_scan_captures(trans, cal.func) - if cal.args is not None: - bn_ca: t.CSizeT = len(cal.args) - for bi_ca in range(bn_ca): - self._closure_scan_captures(trans, cal.args.get(bi_ca)) - if cal.keywords is not None: - bn_ck: t.CSizeT = len(cal.keywords) - for bi_ck in range(bn_ck): - kw_n: ast.AST | t.CPtr = cal.keywords.get(bi_ck) - if kw_n is not None and kw_n.kind() == ast.ASTKind.Keyword: - kw_c: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(kw_n) - if kw_c.value is not None: - self._closure_scan_captures(trans, kw_c.value) - return 1 - if k == ast.ASTKind.Subscript: - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - if sub.value is not None: - self._closure_scan_captures(trans, sub.value) - if sub.slice is not None: - self._closure_scan_captures(trans, sub.slice) - return 1 - if k == ast.ASTKind.Attribute: - at_n: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at_n.value is not None: - self._closure_scan_captures(trans, at_n.value) - return 1 - if k == ast.ASTKind.IfExp: - ie: ast.IfExp | t.CPtr = (ast.IfExp | t.CPtr)(node) - if ie.test is not None: - self._closure_scan_captures(trans, ie.test) - if ie.body is not None: - self._closure_scan_captures(trans, ie.body) - if ie.orelse is not None: - self._closure_scan_captures(trans, ie.orelse) - return 1 - if k == ast.ASTKind.Dict: - dc: ast.Dict | t.CPtr = (ast.Dict | t.CPtr)(node) - if dc.keys is not None: - bn_dk: t.CSizeT = len(dc.keys) - for bi_dk in range(bn_dk): - self._closure_scan_captures(trans, dc.keys.get(bi_dk)) - if dc.values is not None: - bn_dv: t.CSizeT = len(dc.values) - for bi_dv in range(bn_dv): - self._closure_scan_captures(trans, dc.values.get(bi_dv)) - return 1 - if k == ast.ASTKind.Set: - st_n: ast.Set | t.CPtr = (ast.Set | t.CPtr)(node) - if st_n.elts is not None: - bn_set: t.CSizeT = len(st_n.elts) - for bi_set in range(bn_set): - self._closure_scan_captures(trans, st_n.elts.get(bi_set)) - return 1 - if k == ast.ASTKind.List: - ls_n: ast.List | t.CPtr = (ast.List | t.CPtr)(node) - if ls_n.elts is not None: - bn_ls: t.CSizeT = len(ls_n.elts) - for bi_ls in range(bn_ls): - self._closure_scan_captures(trans, ls_n.elts.get(bi_ls)) - return 1 - if k == ast.ASTKind.Tuple: - tp_n: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(node) - if tp_n.elts is not None: - bn_tp: t.CSizeT = len(tp_n.elts) - for bi_tp in range(bn_tp): - self._closure_scan_captures(trans, tp_n.elts.get(bi_tp)) - return 1 - if k == ast.ASTKind.Starred: - sr_n: ast.Starred | t.CPtr = (ast.Starred | t.CPtr)(node) - if sr_n.value is not None: - self._closure_scan_captures(trans, sr_n.value) - return 1 - if k == ast.ASTKind.NamedExpr: - ne_n: ast.NamedExpr | t.CPtr = (ast.NamedExpr | t.CPtr)(node) - if ne_n.value is not None: - self._closure_scan_captures(trans, ne_n.value) - return 1 - if k == ast.ASTKind.Slice: - sl_n: ast.Slice | t.CPtr = (ast.Slice | t.CPtr)(node) - if sl_n.lower is not None: - self._closure_scan_captures(trans, sl_n.lower) - if sl_n.upper is not None: - self._closure_scan_captures(trans, sl_n.upper) - if sl_n.step is not None: - self._closure_scan_captures(trans, sl_n.step) - return 1 - if k == ast.ASTKind.JoinedStr: - js_n: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(node) - if js_n.values is not None: - bn_js: t.CSizeT = len(js_n.values) - for bi_js in range(bn_js): - self._closure_scan_captures(trans, js_n.values.get(bi_js)) - return 1 - if k == ast.ASTKind.FormattedValue: - fv_n: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(node) - if fv_n.value is not None: - self._closure_scan_captures(trans, fv_n.value) - if fv_n.format_spec is not None: - self._closure_scan_captures(trans, fv_n.format_spec) - return 1 - if k == ast.ASTKind.Await: - aw_n: ast.Await | t.CPtr = (ast.Await | t.CPtr)(node) - if aw_n.value is not None: - self._closure_scan_captures(trans, aw_n.value) - return 1 - if k == ast.ASTKind.Yield: - yd_n: ast.Yield | t.CPtr = (ast.Yield | t.CPtr)(node) - if yd_n.value is not None: - self._closure_scan_captures(trans, yd_n.value) - return 1 - if k == ast.ASTKind.YieldFrom: - yf_n: ast.YieldFrom | t.CPtr = (ast.YieldFrom | t.CPtr)(node) - if yf_n.value is not None: - self._closure_scan_captures(trans, yf_n.value) - return 1 - is_comp: int = 0 - if k == ast.ASTKind.ListComp: - is_comp = 1 - elif k == ast.ASTKind.SetComp: - is_comp = 1 - elif k == ast.ASTKind.GeneratorExp: - is_comp = 1 - if is_comp != 0: - lc_n: ast.ListComp | t.CPtr = (ast.ListComp | t.CPtr)(node) - if lc_n.elt is not None: - self._closure_scan_captures(trans, lc_n.elt) - if lc_n.generators is not None: - bn_gen: t.CSizeT = len(lc_n.generators) - for bi_gen in range(bn_gen): - cp_n: ast.AST | t.CPtr = lc_n.generators.get(bi_gen) - if cp_n is not None and cp_n.kind() == ast.ASTKind.Comprehension: - cp_c: ast.Comprehension | t.CPtr = (ast.Comprehension | t.CPtr)(cp_n) - if cp_c.iter is not None: - self._closure_scan_captures(trans, cp_c.iter) - if cp_c.ifs is not None: - bn_cpi: t.CSizeT = len(cp_c.ifs) - for bi_cpi in range(bn_cpi): - self._closure_scan_captures(trans, cp_c.ifs.get(bi_cpi)) - return 1 - if k == ast.ASTKind.DictComp: - dcn: ast.DictComp | t.CPtr = (ast.DictComp | t.CPtr)(node) - if dcn.key is not None: - self._closure_scan_captures(trans, dcn.key) - if dcn.value is not None: - self._closure_scan_captures(trans, dcn.value) - if dcn.generators is not None: - bn_dgen: t.CSizeT = len(dcn.generators) - for bi_dgen in range(bn_dgen): - cp_dn: ast.AST | t.CPtr = dcn.generators.get(bi_dgen) - if cp_dn is not None and cp_dn.kind() == ast.ASTKind.Comprehension: - cp_dc: ast.Comprehension | t.CPtr = (ast.Comprehension | t.CPtr)(cp_dn) - if cp_dc.iter is not None: - self._closure_scan_captures(trans, cp_dc.iter) - if cp_dc.ifs is not None: - bn_dcpi: t.CSizeT = len(cp_dc.ifs) - for bi_dcpi in range(bn_dcpi): - self._closure_scan_captures(trans, cp_dc.ifs.get(bi_dcpi)) - return 1 - 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, 0) - 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 +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.Gen.Translator as HT +import lib.core.Gen.Call.CallGenBase as CallGenBase +import lib.core.Gen.GenApi as GenApi + + +# ============================================================ +# 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, 0) + 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, trans._from_imports) + 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 + GenApi.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) + + # 8c. 隐式捕获扫描:嵌套函数读取的外层函数局部变量注册为 nonlocal + # (Python 语义,无需显式 nonlocal;否则 read 经 lookup_var + # 跨函数命中父函数 alloca → SSA 编号错乱 → llc undefined value)。 + # 分支内 AnnAssign 局部已由 pre_scan_allocas 递归预注册 + # (StmtGenDeclMixin),本扫描经 lookup_current 自然排除。 + if body is not None: + bnc: t.CSizeT = len(body) + for bic in range(bnc): + stmtc: ast.AST | t.CPtr = body.get(bic) + if stmtc is not None: + self._closure_scan_captures(trans, stmtc) + + # 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 + + # ============================================================ + # _closure_scan_captures - 递归扫描嵌套函数体中的隐式捕获变量 + # + # Python 语义:嵌套函数读取外层函数局部变量无需显式 nonlocal。 + # 此前嵌套 def 闭包仅在显式 `nonlocal` 语句时注册捕获;无 nonlocal + # 的 read 在翻译时会经 lookup_var 跨函数命中父函数 alloca(SSA 编号 + # 属于父函数,提升函数内引用 → llc "use of undefined value '%X'")。 + # lambda 已有 _lambda_scan_body 预扫描,这里对嵌套 def 做等价预扫描: + # 把"读取的外层函数局部变量"注册为 nonlocal(复用 env 共享堆机制), + # 使 read 走 _load_raw_var_ptr 从 env 读堆值。 + # 注意:与 lambda 快照方案不同,嵌套 def 复用显式 nonlocal 的 + # env 共享堆路径,因此注册顺序必须与 step 13 的 env 构建一致 + # (本扫描在 body 翻译前执行,注册顺序稳定)。 + # ============================================================ + def _closure_scan_captures(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """递归扫描节点中的隐式捕获并注册为 nonlocal""" + if node is None or trans is None: + return 1 + 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 1 + # 当前作用域已定义(参数 / AnnAssign 局部,含分支内)→ 非捕获 + if self.Gen.VarGen.lookup_current(trans.SymTab, nm.id) is not None: + return 1 + # 已注册 nonlocal(显式 nonlocal 语句 / 已捕获)→ 跳过 + if GenApi.is_nonlocal_name(trans, nm.id) != 0: + return 1 + ve: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, nm.id) + if ve is None or ve.Alloca is None or ve.Alloca.Ty is None: + return 1 + nl_ty: llvmlite.LLVMType | t.CPtr = ve.Alloca.Ty.Pointee + if nl_ty is None: + return 1 + # 模块级全局直接解析,无需 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(ve.Alloca): + return 1 + # 外层函数局部变量 → 隐式捕获(注册为 nonlocal) + GenApi.add_nonlocal_name(trans, nm.id, nl_ty) + return 1 + # ---- 语句 ---- + if k == ast.ASTKind.Assign: + asn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node) + if asn.value is not None: + self._closure_scan_captures(trans, asn.value) + return 1 + if k == ast.ASTKind.AnnAssign: + aan: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) + if aan.value is not None: + self._closure_scan_captures(trans, aan.value) + return 1 + if k == ast.ASTKind.AugAssign: + aun: ast.AugAssign | t.CPtr = (ast.AugAssign | t.CPtr)(node) + # 目标同时是读(先读旧值),参与捕获 + if aun.target is not None: + self._closure_scan_captures(trans, aun.target) + if aun.value is not None: + self._closure_scan_captures(trans, aun.value) + return 1 + if k == ast.ASTKind.If: + ifn: ast.If | t.CPtr = (ast.If | t.CPtr)(node) + if ifn.test is not None: + self._closure_scan_captures(trans, ifn.test) + if ifn.children is not None: + bn_if: t.CSizeT = len(ifn.children) + for bi_if in range(bn_if): + self._closure_scan_captures(trans, ifn.children.get(bi_if)) + if ifn.orelse is not None: + bn_el: t.CSizeT = len(ifn.orelse) + for bi_el in range(bn_el): + self._closure_scan_captures(trans, ifn.orelse.get(bi_el)) + return 1 + if k == ast.ASTKind.For: + for_n: ast.For | t.CPtr = (ast.For | t.CPtr)(node) + # 循环目标是新局部变量,不参与捕获 + if for_n.iter is not None: + self._closure_scan_captures(trans, for_n.iter) + if for_n.children is not None: + bn_f: t.CSizeT = len(for_n.children) + for bi_f in range(bn_f): + self._closure_scan_captures(trans, for_n.children.get(bi_f)) + if for_n.orelse is not None: + bn_fe: t.CSizeT = len(for_n.orelse) + for bi_fe in range(bn_fe): + self._closure_scan_captures(trans, for_n.orelse.get(bi_fe)) + return 1 + if k == ast.ASTKind.While: + wh_n: ast.While | t.CPtr = (ast.While | t.CPtr)(node) + if wh_n.test is not None: + self._closure_scan_captures(trans, wh_n.test) + if wh_n.children is not None: + bn_w: t.CSizeT = len(wh_n.children) + for bi_w in range(bn_w): + self._closure_scan_captures(trans, wh_n.children.get(bi_w)) + if wh_n.orelse is not None: + bn_we: t.CSizeT = len(wh_n.orelse) + for bi_we in range(bn_we): + self._closure_scan_captures(trans, wh_n.orelse.get(bi_we)) + return 1 + if k == ast.ASTKind.Return: + rt_n: ast.Return | t.CPtr = (ast.Return | t.CPtr)(node) + if rt_n.value is not None: + self._closure_scan_captures(trans, rt_n.value) + return 1 + if k == ast.ASTKind.Expr: + ex_n: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(node) + if ex_n.value is not None: + self._closure_scan_captures(trans, ex_n.value) + return 1 + if k == ast.ASTKind.With: + wth: ast.With | t.CPtr = (ast.With | t.CPtr)(node) + if wth.items is not None: + bn_wi: t.CSizeT = len(wth.items) + for bi_wi in range(bn_wi): + wi_n: ast.AST | t.CPtr = wth.items.get(bi_wi) + if wi_n is not None and wi_n.kind() == ast.ASTKind.WithItem: + wi_c: ast.WithItem | t.CPtr = (ast.WithItem | t.CPtr)(wi_n) + if wi_c.context_expr is not None: + self._closure_scan_captures(trans, wi_c.context_expr) + if wth.children is not None: + bn_wb: t.CSizeT = len(wth.children) + for bi_wb in range(bn_wb): + self._closure_scan_captures(trans, wth.children.get(bi_wb)) + return 1 + if k == ast.ASTKind.Raise: + rs_n: ast.Raise | t.CPtr = (ast.Raise | t.CPtr)(node) + if rs_n.exc is not None: + self._closure_scan_captures(trans, rs_n.exc) + if rs_n.cause is not None: + self._closure_scan_captures(trans, rs_n.cause) + return 1 + if k == ast.ASTKind.Assert: + as_n: ast.Assert | t.CPtr = (ast.Assert | t.CPtr)(node) + if as_n.test is not None: + self._closure_scan_captures(trans, as_n.test) + if as_n.msg is not None: + self._closure_scan_captures(trans, as_n.msg) + return 1 + if k == ast.ASTKind.Try: + tr_n: ast.Try | t.CPtr = (ast.Try | t.CPtr)(node) + if tr_n.children is not None: + bn_t: t.CSizeT = len(tr_n.children) + for bi_t in range(bn_t): + self._closure_scan_captures(trans, tr_n.children.get(bi_t)) + if tr_n.handlers is not None: + bn_th: t.CSizeT = len(tr_n.handlers) + for bi_th in range(bn_th): + eh_n: ast.AST | t.CPtr = tr_n.handlers.get(bi_th) + if eh_n is not None and eh_n.kind() == ast.ASTKind.ExceptHandler: + eh_c: ast.ExceptHandler | t.CPtr = (ast.ExceptHandler | t.CPtr)(eh_n) + if eh_c.children is not None: + bn_ehb: t.CSizeT = len(eh_c.children) + for bi_ehb in range(bn_ehb): + self._closure_scan_captures(trans, eh_c.children.get(bi_ehb)) + if tr_n.orelse is not None: + bn_to: t.CSizeT = len(tr_n.orelse) + for bi_to in range(bn_to): + self._closure_scan_captures(trans, tr_n.orelse.get(bi_to)) + if tr_n.finalbody is not None: + bn_tf: t.CSizeT = len(tr_n.finalbody) + for bi_tf in range(bn_tf): + self._closure_scan_captures(trans, tr_n.finalbody.get(bi_tf)) + return 1 + if k == ast.ASTKind.Match: + mt_n: ast.Match | t.CPtr = (ast.Match | t.CPtr)(node) + if mt_n.subject is not None: + self._closure_scan_captures(trans, mt_n.subject) + if mt_n.cases is not None: + bn_mc: t.CSizeT = len(mt_n.cases) + for bi_mc in range(bn_mc): + mc_n: ast.AST | t.CPtr = mt_n.cases.get(bi_mc) + if mc_n is not None and mc_n.kind() == ast.ASTKind.MatchCase: + mc_c: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(mc_n) + if mc_c.guard is not None: + self._closure_scan_captures(trans, mc_c.guard) + if mc_c.children is not None: + bn_mcb: t.CSizeT = len(mc_c.children) + for bi_mcb in range(bn_mcb): + self._closure_scan_captures(trans, mc_c.children.get(bi_mcb)) + return 1 + # ---- 表达式 ---- + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if bop.left is not None: + self._closure_scan_captures(trans, bop.left) + if bop.right is not None: + self._closure_scan_captures(trans, bop.right) + return 1 + if k == ast.ASTKind.UnaryOp: + uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + if uop.operand is not None: + self._closure_scan_captures(trans, uop.operand) + return 1 + if k == ast.ASTKind.BoolOp: + bop2: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) + if bop2.values is not None: + bn_bo: t.CSizeT = len(bop2.values) + for bi_bo in range(bn_bo): + self._closure_scan_captures(trans, bop2.values.get(bi_bo)) + return 1 + if k == ast.ASTKind.Compare: + cmp: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) + if cmp.left is not None: + self._closure_scan_captures(trans, cmp.left) + if cmp.comparators is not None: + bn_cmp: t.CSizeT = len(cmp.comparators) + for bi_cmp in range(bn_cmp): + self._closure_scan_captures(trans, cmp.comparators.get(bi_cmp)) + return 1 + if k == ast.ASTKind.Call: + cal: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + if cal.func is not None: + self._closure_scan_captures(trans, cal.func) + if cal.args is not None: + bn_ca: t.CSizeT = len(cal.args) + for bi_ca in range(bn_ca): + self._closure_scan_captures(trans, cal.args.get(bi_ca)) + if cal.keywords is not None: + bn_ck: t.CSizeT = len(cal.keywords) + for bi_ck in range(bn_ck): + kw_n: ast.AST | t.CPtr = cal.keywords.get(bi_ck) + if kw_n is not None and kw_n.kind() == ast.ASTKind.Keyword: + kw_c: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(kw_n) + if kw_c.value is not None: + self._closure_scan_captures(trans, kw_c.value) + return 1 + if k == ast.ASTKind.Subscript: + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + if sub.value is not None: + self._closure_scan_captures(trans, sub.value) + if sub.slice is not None: + self._closure_scan_captures(trans, sub.slice) + return 1 + if k == ast.ASTKind.Attribute: + at_n: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at_n.value is not None: + self._closure_scan_captures(trans, at_n.value) + return 1 + if k == ast.ASTKind.IfExp: + ie: ast.IfExp | t.CPtr = (ast.IfExp | t.CPtr)(node) + if ie.test is not None: + self._closure_scan_captures(trans, ie.test) + if ie.body is not None: + self._closure_scan_captures(trans, ie.body) + if ie.orelse is not None: + self._closure_scan_captures(trans, ie.orelse) + return 1 + if k == ast.ASTKind.Dict: + dc: ast.Dict | t.CPtr = (ast.Dict | t.CPtr)(node) + if dc.keys is not None: + bn_dk: t.CSizeT = len(dc.keys) + for bi_dk in range(bn_dk): + self._closure_scan_captures(trans, dc.keys.get(bi_dk)) + if dc.values is not None: + bn_dv: t.CSizeT = len(dc.values) + for bi_dv in range(bn_dv): + self._closure_scan_captures(trans, dc.values.get(bi_dv)) + return 1 + if k == ast.ASTKind.Set: + st_n: ast.Set | t.CPtr = (ast.Set | t.CPtr)(node) + if st_n.elts is not None: + bn_set: t.CSizeT = len(st_n.elts) + for bi_set in range(bn_set): + self._closure_scan_captures(trans, st_n.elts.get(bi_set)) + return 1 + if k == ast.ASTKind.List: + ls_n: ast.List | t.CPtr = (ast.List | t.CPtr)(node) + if ls_n.elts is not None: + bn_ls: t.CSizeT = len(ls_n.elts) + for bi_ls in range(bn_ls): + self._closure_scan_captures(trans, ls_n.elts.get(bi_ls)) + return 1 + if k == ast.ASTKind.Tuple: + tp_n: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(node) + if tp_n.elts is not None: + bn_tp: t.CSizeT = len(tp_n.elts) + for bi_tp in range(bn_tp): + self._closure_scan_captures(trans, tp_n.elts.get(bi_tp)) + return 1 + if k == ast.ASTKind.Starred: + sr_n: ast.Starred | t.CPtr = (ast.Starred | t.CPtr)(node) + if sr_n.value is not None: + self._closure_scan_captures(trans, sr_n.value) + return 1 + if k == ast.ASTKind.NamedExpr: + ne_n: ast.NamedExpr | t.CPtr = (ast.NamedExpr | t.CPtr)(node) + if ne_n.value is not None: + self._closure_scan_captures(trans, ne_n.value) + return 1 + if k == ast.ASTKind.Slice: + sl_n: ast.Slice | t.CPtr = (ast.Slice | t.CPtr)(node) + if sl_n.lower is not None: + self._closure_scan_captures(trans, sl_n.lower) + if sl_n.upper is not None: + self._closure_scan_captures(trans, sl_n.upper) + if sl_n.step is not None: + self._closure_scan_captures(trans, sl_n.step) + return 1 + if k == ast.ASTKind.JoinedStr: + js_n: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(node) + if js_n.values is not None: + bn_js: t.CSizeT = len(js_n.values) + for bi_js in range(bn_js): + self._closure_scan_captures(trans, js_n.values.get(bi_js)) + return 1 + if k == ast.ASTKind.FormattedValue: + fv_n: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(node) + if fv_n.value is not None: + self._closure_scan_captures(trans, fv_n.value) + if fv_n.format_spec is not None: + self._closure_scan_captures(trans, fv_n.format_spec) + return 1 + if k == ast.ASTKind.Await: + aw_n: ast.Await | t.CPtr = (ast.Await | t.CPtr)(node) + if aw_n.value is not None: + self._closure_scan_captures(trans, aw_n.value) + return 1 + if k == ast.ASTKind.Yield: + yd_n: ast.Yield | t.CPtr = (ast.Yield | t.CPtr)(node) + if yd_n.value is not None: + self._closure_scan_captures(trans, yd_n.value) + return 1 + if k == ast.ASTKind.YieldFrom: + yf_n: ast.YieldFrom | t.CPtr = (ast.YieldFrom | t.CPtr)(node) + if yf_n.value is not None: + self._closure_scan_captures(trans, yf_n.value) + return 1 + is_comp: int = 0 + if k == ast.ASTKind.ListComp: + is_comp = 1 + elif k == ast.ASTKind.SetComp: + is_comp = 1 + elif k == ast.ASTKind.GeneratorExp: + is_comp = 1 + if is_comp != 0: + lc_n: ast.ListComp | t.CPtr = (ast.ListComp | t.CPtr)(node) + if lc_n.elt is not None: + self._closure_scan_captures(trans, lc_n.elt) + if lc_n.generators is not None: + bn_gen: t.CSizeT = len(lc_n.generators) + for bi_gen in range(bn_gen): + cp_n: ast.AST | t.CPtr = lc_n.generators.get(bi_gen) + if cp_n is not None and cp_n.kind() == ast.ASTKind.Comprehension: + cp_c: ast.Comprehension | t.CPtr = (ast.Comprehension | t.CPtr)(cp_n) + if cp_c.iter is not None: + self._closure_scan_captures(trans, cp_c.iter) + if cp_c.ifs is not None: + bn_cpi: t.CSizeT = len(cp_c.ifs) + for bi_cpi in range(bn_cpi): + self._closure_scan_captures(trans, cp_c.ifs.get(bi_cpi)) + return 1 + if k == ast.ASTKind.DictComp: + dcn: ast.DictComp | t.CPtr = (ast.DictComp | t.CPtr)(node) + if dcn.key is not None: + self._closure_scan_captures(trans, dcn.key) + if dcn.value is not None: + self._closure_scan_captures(trans, dcn.value) + if dcn.generators is not None: + bn_dgen: t.CSizeT = len(dcn.generators) + for bi_dgen in range(bn_dgen): + cp_dn: ast.AST | t.CPtr = dcn.generators.get(bi_dgen) + if cp_dn is not None and cp_dn.kind() == ast.ASTKind.Comprehension: + cp_dc: ast.Comprehension | t.CPtr = (ast.Comprehension | t.CPtr)(cp_dn) + if cp_dc.iter is not None: + self._closure_scan_captures(trans, cp_dc.iter) + if cp_dc.ifs is not None: + bn_dcpi: t.CSizeT = len(cp_dc.ifs) + for bi_dcpi in range(bn_dcpi): + self._closure_scan_captures(trans, cp_dc.ifs.get(bi_dcpi)) + return 1 + 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, 0) + 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 + GenApi.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 index ed693ba..4fc8a9f 100644 --- a/App/lib/core/Gen/GenApi.vp +++ b/App/lib/core/Gen/GenApi.vp @@ -14,7 +14,7 @@ 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 +import lib.core.Gen.Translator as HT # ============================================================ @@ -603,3 +603,84 @@ def translate_print_call(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBui 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) + + +# ---------------- add_global_name(委托 TranslatorGenMixin.add_global_name) ---------------- +def add_global_name(trans: HT.Translator | t.CPtr, name: str) -> None: + """委托到 gen.TranslatorGen.add_global_name(原 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.add_global_name(trans, name) + + +# ---------------- is_global_name(委托 TranslatorGenMixin.is_global_name) ---------------- +def is_global_name(trans: HT.Translator | t.CPtr, name: str) -> int: + """委托到 gen.TranslatorGen.is_global_name(原 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.is_global_name(trans, name) + return 0 + + +# ---------------- add_nonlocal_name(委托 TranslatorGenMixin.add_nonlocal_name) ---------------- +def add_nonlocal_name(trans: HT.Translator | t.CPtr, name: str, + var_ty: llvmlite.LLVMType | t.CPtr = None) -> None: + """委托到 gen.TranslatorGen.add_nonlocal_name(原 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.add_nonlocal_name(trans, name, var_ty) + + +# ---------------- get_nonlocal_type(委托 TranslatorGenMixin.get_nonlocal_type) ---------------- +def get_nonlocal_type(trans: HT.Translator | t.CPtr, + name: str) -> llvmlite.LLVMType | t.CPtr: + """委托到 gen.TranslatorGen.get_nonlocal_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.TranslatorGen.get_nonlocal_type(trans, name) + return None + + +# ---------------- is_nonlocal_name(委托 TranslatorGenMixin.is_nonlocal_name) ---------------- +def is_nonlocal_name(trans: HT.Translator | t.CPtr, name: str) -> int: + """委托到 gen.TranslatorGen.is_nonlocal_name(原 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.is_nonlocal_name(trans, name) + return 0 + + +# ---------------- get_nonlocal_index(委托 TranslatorGenMixin.get_nonlocal_index) ---------------- +def get_nonlocal_index(trans: HT.Translator | t.CPtr, name: str) -> int: + """委托到 gen.TranslatorGen.get_nonlocal_index(原 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.get_nonlocal_index(trans, name) + return 0 + + +# ---------------- clear_scope_names(委托 TranslatorGenMixin.clear_scope_names) ---------------- +def clear_scope_names(trans: HT.Translator | t.CPtr) -> None: + """委托到 gen.TranslatorGen.clear_scope_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.TranslatorGen.clear_scope_names(trans) + + +# ---------------- update_global_func_typestr(委托 CallGenLeafKit.update_global_func_typestr) ---------------- +def update_global_func_typestr(pool: memhub.MemBuddy | t.CPtr, + name: str, + func: llvmlite.Function | t.CPtr) -> int: + """委托到 gen.CallGenLeafKit.update_global_func_typestr(原 ExprCallTable 壳)""" + 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.update_global_func_typestr(pool, name, func) + return 0 diff --git a/App/lib/core/Gen/ImportsGenMixin.vp b/App/lib/core/Gen/ImportsGenMixin.vp index 0fc4d01..33ad36d 100644 --- a/App/lib/core/Gen/ImportsGenMixin.vp +++ b/App/lib/core/Gen/ImportsGenMixin.vp @@ -11,7 +11,7 @@ import sys import w32.fileio as fileio import lib.Stub.StubMerger as StubMerger import lib.core.CompilerFactory as CompilerFactory -import lib.core.Handles.HandlesTranslator as HT +import lib.core.Gen.Translator as HT import lib.Stub.StubMerger.StubMergerStore as StubMergerStore diff --git a/App/lib/core/Gen/MatchGenMixin.vp b/App/lib/core/Gen/MatchGenMixin.vp index 9209440..cb7cced 100644 --- a/App/lib/core/Gen/MatchGenMixin.vp +++ b/App/lib/core/Gen/MatchGenMixin.vp @@ -1,1339 +1,1339 @@ -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.Gen.GenTypes as GenTypes -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# MatchGenMixin - match 语句翻译 Mixin(P6 方法化) -# ============================================================ - - -# match case 数量上限(原 HandlesMatch.MAX_MATCH_CASES) -MAX_MATCH_CASES: t.CDefine = 32 - -# 作用域种类常量(与 HandlesVar 的 Scope.Kind 区分,原 HandlesMatch.SCOPE_MATCH) -SCOPE_MATCH: t.CDefine = 6 - -# match 翻译最大递归深度(match → case body → translate_value → 嵌套 match)。 -# AST 自引用环/翻译 bug 可致无限递归 → ASan stack-overflow(崩溃点实测为 -# translate_match 内 subject kind() 虚调用,栈 2MB 耗尽)。入口计数出口递减, -# 超限即 fail-fast(对齐 TypeGenResolve 深度守卫,防栈溢出)。 -MATCH_TRANSLATE_MAX_DEPTH: t.CDefine = 64 - - -@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: - """match 语句翻译主入口(深度守卫包装器,原逻辑见 _translate_match_impl)""" - if trans is not None: - if trans.MatchTranslateDepth >= MATCH_TRANSLATE_MAX_DEPTH: - self.Gen.TypeGenErr.fatal_error( - node, "match 翻译嵌套过深(疑似 AST 自引用环或翻译 bug)", "RecursionError") - trans.MatchTranslateDepth += 1 - mret: int = self._translate_match_impl(trans, node) - if trans is not None: - trans.MatchTranslateDepth -= 1 - return mret - - def _translate_match_impl(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) - # pass1 缓存的 mc 指针数组(pass2 复用,避免重索引) - mc_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) - if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None \ - or mc_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 - # 缓存 mc 指针(pass2 复用,避免重索引) - mc_arr[collected] = t.CSizeT(mc) - 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: - # pass2 用 pass1 缓存的 mc(避免重索引错位) - mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)( - t.CVoid(mc_arr[i], t.CPtr)) - if mc is None: - i = i + 1 - continue - 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: - # 用 list.get() 读取元素值(已验证编译为 8 字节加载,与 - # pass1 的 cases_list.get(i) 同型同码)。切勿改为 - # `bl_data + bi*8` 裸地址:那会把数组槽地址当节点传入 - # translate_stmt,虚调用跳进 vtable 表 → DEP 崩溃。 - 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 预声明+重赋值会使 .get 误分派成 list[int].get - # (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃, - # gen1 IR 证据)。用 dbody2 内联声明接收者遍历(对齐 - # Converter arg_defaults 内联声明规避模式)。 - dbody2: list[ast.AST | t.CPtr] | t.CPtr = dmc.children - dbody = dbody2 - if dbody2 is not None: - dn: t.CSizeT = len(dbody2) - dj: int = 0 - while dj < dn: - stmt: ast.AST | t.CPtr = dbody2.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): - # elts 预声明+重赋值会把 .get 误分派成 list[int].get(i32 截断); - # 用内联别名接收者规避(对齐 Converter arg_defaults 内联模式) - elts_inl: list[ast.AST | t.CPtr] | t.CPtr = elts - elt: ast.AST | t.CPtr = elts_inl.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): - # pats 预声明+重赋值会把 .get 误分派成 list[int].get(i32 截断); - # 用内联别名接收者规避(对齐 Converter arg_defaults 内联模式) - pats_inl: list[ast.AST | t.CPtr] | t.CPtr = pats - pat1: ast.AST | t.CPtr = pats_inl.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 预声明+重赋值会使 .get 误分派成 list[int].get - # (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃, - # gen1 IR 证据)。用 dbody2 内联声明接收者遍历(对齐 - # Converter arg_defaults 内联声明规避模式)。 - dbody2: list[ast.AST | t.CPtr] | t.CPtr = dmc.children - dbody = dbody2 - if dbody2 is not None: - dn: t.CSizeT = len(dbody2) - dj: int = 0 - while dj < dn: - stmt: ast.AST | t.CPtr = dbody2.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 预声明+重赋值会使 .get 误分派成 list[int].get - # (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃, - # gen1 IR 证据)。用 dbody2 内联声明接收者遍历(对齐 - # Converter arg_defaults 内联声明规避模式)。 - dbody2: list[ast.AST | t.CPtr] | t.CPtr = dmc.children - dbody = dbody2 - if dbody2 is not None: - dn: t.CSizeT = len(dbody2) - dj: int = 0 - while dj < dn: - stmt: ast.AST | t.CPtr = dbody2.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 +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import viperlib +import lib.core.Gen.Translator as HT +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.Generator as Generator + + +# ============================================================ +# MatchGenMixin - match 语句翻译 Mixin(P6 方法化) +# ============================================================ + + +# match case 数量上限(原 HandlesMatch.MAX_MATCH_CASES) +MAX_MATCH_CASES: t.CDefine = 32 + +# 作用域种类常量(与 HandlesVar 的 Scope.Kind 区分,原 HandlesMatch.SCOPE_MATCH) +SCOPE_MATCH: t.CDefine = 6 + +# match 翻译最大递归深度(match → case body → translate_value → 嵌套 match)。 +# AST 自引用环/翻译 bug 可致无限递归 → ASan stack-overflow(崩溃点实测为 +# translate_match 内 subject kind() 虚调用,栈 2MB 耗尽)。入口计数出口递减, +# 超限即 fail-fast(对齐 TypeGenResolve 深度守卫,防栈溢出)。 +MATCH_TRANSLATE_MAX_DEPTH: t.CDefine = 64 + + +@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: + """match 语句翻译主入口(深度守卫包装器,原逻辑见 _translate_match_impl)""" + if trans is not None: + if trans.MatchTranslateDepth >= MATCH_TRANSLATE_MAX_DEPTH: + self.Gen.TypeGenErr.fatal_error( + node, "match 翻译嵌套过深(疑似 AST 自引用环或翻译 bug)", "RecursionError") + trans.MatchTranslateDepth += 1 + mret: int = self._translate_match_impl(trans, node) + if trans is not None: + trans.MatchTranslateDepth -= 1 + return mret + + def _translate_match_impl(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) + # pass1 缓存的 mc 指针数组(pass2 复用,避免重索引) + mc_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) + if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None \ + or mc_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 + # 缓存 mc 指针(pass2 复用,避免重索引) + mc_arr[collected] = t.CSizeT(mc) + 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: + # pass2 用 pass1 缓存的 mc(避免重索引错位) + mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)( + t.CVoid(mc_arr[i], t.CPtr)) + if mc is None: + i = i + 1 + continue + 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: + # 用 list.get() 读取元素值(已验证编译为 8 字节加载,与 + # pass1 的 cases_list.get(i) 同型同码)。切勿改为 + # `bl_data + bi*8` 裸地址:那会把数组槽地址当节点传入 + # translate_stmt,虚调用跳进 vtable 表 → DEP 崩溃。 + 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 预声明+重赋值会使 .get 误分派成 list[int].get + # (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃, + # gen1 IR 证据)。用 dbody2 内联声明接收者遍历(对齐 + # Converter arg_defaults 内联声明规避模式)。 + dbody2: list[ast.AST | t.CPtr] | t.CPtr = dmc.children + dbody = dbody2 + if dbody2 is not None: + dn: t.CSizeT = len(dbody2) + dj: int = 0 + while dj < dn: + stmt: ast.AST | t.CPtr = dbody2.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): + # elts 预声明+重赋值会把 .get 误分派成 list[int].get(i32 截断); + # 用内联别名接收者规避(对齐 Converter arg_defaults 内联模式) + elts_inl: list[ast.AST | t.CPtr] | t.CPtr = elts + elt: ast.AST | t.CPtr = elts_inl.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): + # pats 预声明+重赋值会把 .get 误分派成 list[int].get(i32 截断); + # 用内联别名接收者规避(对齐 Converter arg_defaults 内联模式) + pats_inl: list[ast.AST | t.CPtr] | t.CPtr = pats + pat1: ast.AST | t.CPtr = pats_inl.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 预声明+重赋值会使 .get 误分派成 list[int].get + # (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃, + # gen1 IR 证据)。用 dbody2 内联声明接收者遍历(对齐 + # Converter arg_defaults 内联声明规避模式)。 + dbody2: list[ast.AST | t.CPtr] | t.CPtr = dmc.children + dbody = dbody2 + if dbody2 is not None: + dn: t.CSizeT = len(dbody2) + dj: int = 0 + while dj < dn: + stmt: ast.AST | t.CPtr = dbody2.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 预声明+重赋值会使 .get 误分派成 list[int].get + # (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃, + # gen1 IR 证据)。用 dbody2 内联声明接收者遍历(对齐 + # Converter arg_defaults 内联声明规避模式)。 + dbody2: list[ast.AST | t.CPtr] | t.CPtr = dmc.children + dbody = dbody2 + if dbody2 is not None: + dn: t.CSizeT = len(dbody2) + dj: int = 0 + while dj < dn: + stmt: ast.AST | t.CPtr = dbody2.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/Stmt/StmtGenCifMixin.vp b/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp index 41e073a..c7714c9 100644 --- a/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp +++ b/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp @@ -10,9 +10,7 @@ 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.Gen.Translator as HT import lib.core.CompilerFactory as CompilerFactory import lib.Projectrans.Config as Config # ============================================================ diff --git a/App/lib/core/Gen/Stmt/StmtGenDeclMixin.vp b/App/lib/core/Gen/Stmt/StmtGenDeclMixin.vp index c6ca96a..edbfb50 100644 --- a/App/lib/core/Gen/Stmt/StmtGenDeclMixin.vp +++ b/App/lib/core/Gen/Stmt/StmtGenDeclMixin.vp @@ -9,12 +9,11 @@ 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.Gen.Translator as HT import lib.core.CompilerFactory as CompilerFactory import lib.Projectrans.Config as Config import lib.core.Gen.Stmt.StmtGenCifMixin as StmtGenCifMixin +import lib.core.Gen.GenApi as GenApi # ============================================================ @@ -56,7 +55,7 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin): 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) + GenApi.add_global_name(trans, nm.id) return 0 def translate_nonlocal(self, trans: HT.Translator | t.CPtr, @@ -92,7 +91,7 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin): self.Gen.TypeGenErr.fatal_error(nm_node, f"nonlocal 变量 '{nm.id}' 类型无效(Void/无法解析)", "TypeError") case _: pass - HT.add_nonlocal_name(trans, nm.id, var_ty) + GenApi.add_nonlocal_name(trans, nm.id, var_ty) return 0 def translate_expr_stmt(self, trans: HT.Translator | t.CPtr, @@ -330,7 +329,7 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin): 返回 i8* 类型的 Value,调用方需 bitcast 为具体类型指针后 load/store。 """ - idx: int = HT.get_nonlocal_index(trans, name) + idx: int = GenApi.get_nonlocal_index(trans, name) if idx < 0: return None @@ -374,7 +373,7 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin): builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder # 获取变量类型(从注册时存储的类型信息) - var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name) + var_ty: llvmlite.LLVMType | t.CPtr = GenApi.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") @@ -400,7 +399,7 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin): builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder # 获取变量类型 - var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name) + var_ty: llvmlite.LLVMType | t.CPtr = GenApi.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") diff --git a/App/lib/core/Gen/Stmt/StmtGenMixin.vp b/App/lib/core/Gen/Stmt/StmtGenMixin.vp index 8d8c643..8f20a25 100644 --- a/App/lib/core/Gen/Stmt/StmtGenMixin.vp +++ b/App/lib/core/Gen/Stmt/StmtGenMixin.vp @@ -11,9 +11,7 @@ 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.Gen.Translator as HT import lib.core.CompilerFactory as CompilerFactory import lib.Projectrans.Config as Config import lib.core.Gen.Stmt.StmtGenDeclMixin as StmtGenDeclMixin diff --git a/App/lib/core/Handles/HandlesTranslator.vp b/App/lib/core/Gen/Translator.vp similarity index 91% rename from App/lib/core/Handles/HandlesTranslator.vp rename to App/lib/core/Gen/Translator.vp index baadeec..2941751 100644 --- a/App/lib/core/Handles/HandlesTranslator.vp +++ b/App/lib/core/Gen/Translator.vp @@ -1,758 +1,719 @@ -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.Stub.StubMerger.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 -# 协程表容量(TPV-M1):async 函数数 / 协程变量·局部名数 -MAX_CORO_FUNCS: t.CDefine = 256 -MAX_CORO_VARS: t.CDefine = 256 -MAX_CORO_TRY: t.CDefine = 16 - -# 翻译主环最大递归深度(translate_stmt/translate_value 嵌套)。AST 自引用环 -# 或翻译 bug 可致翻译主环(语句/表达式/调用)无限递归 → ASan stack-overflow。 -# match 守卫(MatchTranslateDepth)只保护 match 递归,本常量保护语句/表达式 -# 翻译环(fail-fast,对齐 TypeGenResolve 深度守卫模式)。 -TRANSLATE_MAX_DEPTH: t.CDefine = 256 - - -# ============================================================ -# 全局 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 - - # 协程(TPV-M1 async def / await / coro.coro_run) - # _async_funcs: 已注册 async 函数裸名表(char* 数组,8 字节/项) - # _coro_var_async: 变量名→async 函数名 成对表(char* 数组,16 字节/项) - # _coro_locals: 当前 async 函数局部变量名表(char* 数组,8 字节/项) - # _coro_frames: async 名→帧类型 成对表(16 字节/项 = char* + LLVMType*) - _async_funcs: str - _async_func_count: t.CInt - _coro_var_async: str - _coro_var_async_count: t.CInt - _coro_locals: str - _coro_local_count: t.CInt - _coro_frames: str - _coro_frame_count: t.CInt - # resume_ 翻译上下文(AsyncGenMixin 段翻译共享) - _coro_state_ptr: llvmlite.Value | t.CPtr - _coro_done_ptr: llvmlite.Value | t.CPtr - _coro_ret_ptr: llvmlite.Value | t.CPtr - _coro_exit_bb: llvmlite.BasicBlock | t.CPtr - _coro_await_slot: llvmlite.Value | t.CPtr - _coro_frame: llvmlite.Value | t.CPtr - _coro_next_state: t.CInt - _coro_nseg: t.CInt - # M2:async 参数表(char* 数组,8 字节/项)+ 预扫描计数 - _coro_params: str - _coro_param_count: t.CInt - _coro_hoist_count: t.CInt # __await_N 槽计数(预扫描与翻译共用,序一致) - _coro_await_count: t.CInt # 总 await 数(= 恢复块数 = switch case 数) - _coro_local_base: t.CInt # 局部槽起始 index(= 3 + nparams) - _coro_extra_base: t.CInt # 额外槽(__await_N)起始 index - _coro_break_bb: llvmlite.BasicBlock | t.CPtr # While break 目标(M2 单层) - _coro_continue_bb: llvmlite.BasicBlock | t.CPtr # While continue 目标 - _coro_state_bbs: t.CSizeT | t.CPtr # 预建 state 块数组(await 恢复块定位) - # M3-M7 协程扩展 - _coro_exc_ptr: llvmlite.Value | t.CPtr # 帧 exc 槽(i32,M4) - _coro_msg_ptr: llvmlite.Value | t.CPtr # 帧 msg 槽(i8*,M7) - _coro_wake_ptr: llvmlite.Value | t.CPtr # 帧 wake 槽(i64,M3 coro_sleep) - _coro_try_stack: t.CSizeT | t.CPtr # try 栈:except/finally 块指针数组(8B/项) - _coro_try_stack_count: t.CInt - _coro_for_counter: t.CInt # range-For 编号(M3,翻译期递增) - _coro_scan_for_count: t.CInt # 预扫描期 For 计数 - _coro_uses_sleep: t.CInt # 函数体是否用 coro_sleep(预扫描置位) - _coro_extra_types: str # 额外槽类型表(i8 数组:1=i32 2=i64) - _coro_extra_count: t.CInt # 额外槽总数 - _coro_await_slots: t.CInt | t.CPtr # __await_N 的帧相对槽 index(预扫描填) - _coro_for_slots: t.CInt | t.CPtr # range-For N 的 __f_idx 帧相对槽 index(预扫描填) - # per-async wake 槽 index 表(coro_run/gather 轮询反查用) - _coro_wake_names: str # char* 数组(8B/项) - _coro_wake_idxs: t.CInt | t.CPtr # i32 数组(4B/项,-1=无 wake 槽) - _coro_wake_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 - - # match 翻译递归深度(match → case body → translate_value → 嵌套 match)。 - # 守卫:AST 自引用环(子节点回指祖先)或翻译 bug 导致的无限递归在此 - # fail-fast(对齐 TypeGenResolve 深度守卫,防 ASan stack-overflow)。 - MatchTranslateDepth: t.CInt - - # 翻译主环递归深度(translate_stmt/translate_value 入口计数)。match 守卫 - # 只覆盖 match 递归;语句/表达式/调用环(如 translate_value ↔ translate_call) - # 由本字段守卫,超 TRANSLATE_MAX_DEPTH 即 fail-fast(防 ASan stack-overflow)。 - TranslateDepth: 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 - self._async_funcs = None - self._async_func_count = 0 - self._coro_var_async = None - self._coro_var_async_count = 0 - self._coro_locals = None - self._coro_local_count = 0 - self._coro_frames = None - self._coro_frame_count = 0 - self._coro_state_ptr = None - self._coro_done_ptr = None - self._coro_ret_ptr = None - self._coro_exit_bb = None - self._coro_await_slot = None - self._coro_frame = None - self._coro_next_state = 1 - self._coro_nseg = 0 - self._coro_params = None - self._coro_param_count = 0 - self._coro_hoist_count = 0 - self._coro_await_count = 0 - self._coro_local_base = 3 - self._coro_extra_base = 3 - self._coro_break_bb = None - self._coro_continue_bb = None - self._coro_state_bbs = None - self._coro_exc_ptr = None - self._coro_msg_ptr = None - self._coro_wake_ptr = None - self._coro_try_stack = None - self._coro_try_stack_count = 0 - self._coro_for_counter = 0 - self._coro_scan_for_count = 0 - self._coro_uses_sleep = 0 - self._coro_extra_types = None - self._coro_extra_count = 0 - self._coro_await_slots = None - self._coro_for_slots = None - self._coro_wake_names = None - self._coro_wake_idxs = None - self._coro_wake_count = 0 - - # ============================================================ - # 状态初始化 - # ============================================================ - 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) - - # 协程表(TPV-M1):async 函数名 / 变量→async 映射 / 局部名 / 帧类型 - if self._async_funcs is None: - self._async_funcs = stdlib.malloc(MAX_CORO_FUNCS * 8) - if self._async_funcs is not None: - string.memset(self._async_funcs, 0, MAX_CORO_FUNCS * 8) - self._async_func_count = 0 - if self._coro_var_async is None: - self._coro_var_async = stdlib.malloc(MAX_CORO_VARS * 16) - if self._coro_var_async is not None: - string.memset(self._coro_var_async, 0, MAX_CORO_VARS * 16) - self._coro_var_async_count = 0 - if self._coro_locals is None: - self._coro_locals = stdlib.malloc(MAX_CORO_VARS * 8) - if self._coro_locals is not None: - string.memset(self._coro_locals, 0, MAX_CORO_VARS * 8) - if self._coro_params is None: - self._coro_params = stdlib.malloc(MAX_CORO_VARS * 8) - if self._coro_params is not None: - string.memset(self._coro_params, 0, MAX_CORO_VARS * 8) - if self._coro_try_stack is None: - self._coro_try_stack = stdlib.malloc(MAX_CORO_TRY * 8) - if self._coro_try_stack is not None: - string.memset(self._coro_try_stack, 0, MAX_CORO_TRY * 8) - if self._coro_extra_types is None: - self._coro_extra_types = stdlib.malloc(MAX_CORO_VARS) - if self._coro_extra_types is not None: - string.memset(self._coro_extra_types, 0, MAX_CORO_VARS) - if self._coro_await_slots is None: - self._coro_await_slots = stdlib.malloc(MAX_CORO_VARS * 4) - if self._coro_await_slots is not None: - string.memset(self._coro_await_slots, 0, MAX_CORO_VARS * 4) - if self._coro_for_slots is None: - self._coro_for_slots = stdlib.malloc(MAX_CORO_VARS * 4) - if self._coro_for_slots is not None: - string.memset(self._coro_for_slots, 0, MAX_CORO_VARS * 4) - if self._coro_wake_names is None: - self._coro_wake_names = stdlib.malloc(MAX_CORO_FUNCS * 8) - if self._coro_wake_names is not None: - string.memset(self._coro_wake_names, 0, MAX_CORO_FUNCS * 8) - if self._coro_wake_idxs is None: - self._coro_wake_idxs = stdlib.malloc(MAX_CORO_FUNCS * 4) - if self._coro_wake_idxs is not None: - string.memset(self._coro_wake_idxs, 0, MAX_CORO_FUNCS * 4) - self._coro_local_count = 0 - if self._coro_frames is None: - self._coro_frames = stdlib.malloc(MAX_CORO_FUNCS * 16) - if self._coro_frames is not None: - string.memset(self._coro_frames, 0, MAX_CORO_FUNCS * 16) - self._coro_frame_count = 0 - - # ============================================================ - # 主翻译入口 - # ============================================================ - 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: - # 错误上下文帧:当前模块触发依赖 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 +import lib.core.Gen.GenApi as GenApi +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.Projectrans.Config as Config +import lib.Stub.StubMerger.StubMergerBuild as StubMergerBuild +import lib.core.Gen.Generator as Generator + +# ============================================================ +# Gen/Translator.vp - 翻译器状态管理 + 主入口(自 HandlesTranslator 迁入) +# +# 负责: +# 1. Translator 类 - 状态管理(Module, 变量表, 函数表, 导入) +# 2. translate() - 主翻译入口 +# 3. dump_ir() - IR 输出 +# +# global/nonlocal 名称管理委托函数已下沉 lib.core.Gen.GenApi +# (add_global_name/is_global_name/add_nonlocal_name/get_nonlocal_type/ +# is_nonlocal_name/get_nonlocal_index/clear_scope_names),本模块不再保留 +# _g_gen 单例;Handles 目录迁移完成后整体删除。 +# ============================================================ + + + +# ============================================================ +# 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 +# 协程表容量(TPV-M1):async 函数数 / 协程变量·局部名数 +MAX_CORO_FUNCS: t.CDefine = 256 +MAX_CORO_VARS: t.CDefine = 256 +MAX_CORO_TRY: t.CDefine = 16 + +# 翻译主环最大递归深度(translate_stmt/translate_value 嵌套)。AST 自引用环 +# 或翻译 bug 可致翻译主环(语句/表达式/调用)无限递归 → ASan stack-overflow。 +# match 守卫(MatchTranslateDepth)只保护 match 递归,本常量保护语句/表达式 +# 翻译环(fail-fast,对齐 TypeGenResolve 深度守卫模式)。 +TRANSLATE_MAX_DEPTH: t.CDefine = 256 + + +# ============================================================ +# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) +# ============================================================ + +@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 + + # 协程(TPV-M1 async def / await / coro.coro_run) + # _async_funcs: 已注册 async 函数裸名表(char* 数组,8 字节/项) + # _coro_var_async: 变量名→async 函数名 成对表(char* 数组,16 字节/项) + # _coro_locals: 当前 async 函数局部变量名表(char* 数组,8 字节/项) + # _coro_frames: async 名→帧类型 成对表(16 字节/项 = char* + LLVMType*) + _async_funcs: str + _async_func_count: t.CInt + _coro_var_async: str + _coro_var_async_count: t.CInt + _coro_locals: str + _coro_local_count: t.CInt + _coro_frames: str + _coro_frame_count: t.CInt + # resume_ 翻译上下文(AsyncGenMixin 段翻译共享) + _coro_state_ptr: llvmlite.Value | t.CPtr + _coro_done_ptr: llvmlite.Value | t.CPtr + _coro_ret_ptr: llvmlite.Value | t.CPtr + _coro_exit_bb: llvmlite.BasicBlock | t.CPtr + _coro_await_slot: llvmlite.Value | t.CPtr + _coro_frame: llvmlite.Value | t.CPtr + _coro_next_state: t.CInt + _coro_nseg: t.CInt + # M2:async 参数表(char* 数组,8 字节/项)+ 预扫描计数 + _coro_params: str + _coro_param_count: t.CInt + _coro_hoist_count: t.CInt # __await_N 槽计数(预扫描与翻译共用,序一致) + _coro_await_count: t.CInt # 总 await 数(= 恢复块数 = switch case 数) + _coro_local_base: t.CInt # 局部槽起始 index(= 3 + nparams) + _coro_extra_base: t.CInt # 额外槽(__await_N)起始 index + _coro_break_bb: llvmlite.BasicBlock | t.CPtr # While break 目标(M2 单层) + _coro_continue_bb: llvmlite.BasicBlock | t.CPtr # While continue 目标 + _coro_state_bbs: t.CSizeT | t.CPtr # 预建 state 块数组(await 恢复块定位) + # M3-M7 协程扩展 + _coro_exc_ptr: llvmlite.Value | t.CPtr # 帧 exc 槽(i32,M4) + _coro_msg_ptr: llvmlite.Value | t.CPtr # 帧 msg 槽(i8*,M7) + _coro_wake_ptr: llvmlite.Value | t.CPtr # 帧 wake 槽(i64,M3 coro_sleep) + _coro_try_stack: t.CSizeT | t.CPtr # try 栈:except/finally 块指针数组(8B/项) + _coro_try_stack_count: t.CInt + _coro_for_counter: t.CInt # range-For 编号(M3,翻译期递增) + _coro_scan_for_count: t.CInt # 预扫描期 For 计数 + _coro_uses_sleep: t.CInt # 函数体是否用 coro_sleep(预扫描置位) + _coro_extra_types: str # 额外槽类型表(i8 数组:1=i32 2=i64) + _coro_extra_count: t.CInt # 额外槽总数 + _coro_await_slots: t.CInt | t.CPtr # __await_N 的帧相对槽 index(预扫描填) + _coro_for_slots: t.CInt | t.CPtr # range-For N 的 __f_idx 帧相对槽 index(预扫描填) + # per-async wake 槽 index 表(coro_run/gather 轮询反查用) + _coro_wake_names: str # char* 数组(8B/项) + _coro_wake_idxs: t.CInt | t.CPtr # i32 数组(4B/项,-1=无 wake 槽) + _coro_wake_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 + + # match 翻译递归深度(match → case body → translate_value → 嵌套 match)。 + # 守卫:AST 自引用环(子节点回指祖先)或翻译 bug 导致的无限递归在此 + # fail-fast(对齐 TypeGenResolve 深度守卫,防 ASan stack-overflow)。 + MatchTranslateDepth: t.CInt + + # 翻译主环递归深度(translate_stmt/translate_value 入口计数)。match 守卫 + # 只覆盖 match 递归;语句/表达式/调用环(如 translate_value ↔ translate_call) + # 由本字段守卫,超 TRANSLATE_MAX_DEPTH 即 fail-fast(防 ASan stack-overflow)。 + TranslateDepth: 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 + self._async_funcs = None + self._async_func_count = 0 + self._coro_var_async = None + self._coro_var_async_count = 0 + self._coro_locals = None + self._coro_local_count = 0 + self._coro_frames = None + self._coro_frame_count = 0 + self._coro_state_ptr = None + self._coro_done_ptr = None + self._coro_ret_ptr = None + self._coro_exit_bb = None + self._coro_await_slot = None + self._coro_frame = None + self._coro_next_state = 1 + self._coro_nseg = 0 + self._coro_params = None + self._coro_param_count = 0 + self._coro_hoist_count = 0 + self._coro_await_count = 0 + self._coro_local_base = 3 + self._coro_extra_base = 3 + self._coro_break_bb = None + self._coro_continue_bb = None + self._coro_state_bbs = None + self._coro_exc_ptr = None + self._coro_msg_ptr = None + self._coro_wake_ptr = None + self._coro_try_stack = None + self._coro_try_stack_count = 0 + self._coro_for_counter = 0 + self._coro_scan_for_count = 0 + self._coro_uses_sleep = 0 + self._coro_extra_types = None + self._coro_extra_count = 0 + self._coro_await_slots = None + self._coro_for_slots = None + self._coro_wake_names = None + self._coro_wake_idxs = None + self._coro_wake_count = 0 + + # ============================================================ + # 状态初始化 + # ============================================================ + 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) + + # 协程表(TPV-M1):async 函数名 / 变量→async 映射 / 局部名 / 帧类型 + if self._async_funcs is None: + self._async_funcs = stdlib.malloc(MAX_CORO_FUNCS * 8) + if self._async_funcs is not None: + string.memset(self._async_funcs, 0, MAX_CORO_FUNCS * 8) + self._async_func_count = 0 + if self._coro_var_async is None: + self._coro_var_async = stdlib.malloc(MAX_CORO_VARS * 16) + if self._coro_var_async is not None: + string.memset(self._coro_var_async, 0, MAX_CORO_VARS * 16) + self._coro_var_async_count = 0 + if self._coro_locals is None: + self._coro_locals = stdlib.malloc(MAX_CORO_VARS * 8) + if self._coro_locals is not None: + string.memset(self._coro_locals, 0, MAX_CORO_VARS * 8) + if self._coro_params is None: + self._coro_params = stdlib.malloc(MAX_CORO_VARS * 8) + if self._coro_params is not None: + string.memset(self._coro_params, 0, MAX_CORO_VARS * 8) + if self._coro_try_stack is None: + self._coro_try_stack = stdlib.malloc(MAX_CORO_TRY * 8) + if self._coro_try_stack is not None: + string.memset(self._coro_try_stack, 0, MAX_CORO_TRY * 8) + if self._coro_extra_types is None: + self._coro_extra_types = stdlib.malloc(MAX_CORO_VARS) + if self._coro_extra_types is not None: + string.memset(self._coro_extra_types, 0, MAX_CORO_VARS) + if self._coro_await_slots is None: + self._coro_await_slots = stdlib.malloc(MAX_CORO_VARS * 4) + if self._coro_await_slots is not None: + string.memset(self._coro_await_slots, 0, MAX_CORO_VARS * 4) + if self._coro_for_slots is None: + self._coro_for_slots = stdlib.malloc(MAX_CORO_VARS * 4) + if self._coro_for_slots is not None: + string.memset(self._coro_for_slots, 0, MAX_CORO_VARS * 4) + if self._coro_wake_names is None: + self._coro_wake_names = stdlib.malloc(MAX_CORO_FUNCS * 8) + if self._coro_wake_names is not None: + string.memset(self._coro_wake_names, 0, MAX_CORO_FUNCS * 8) + if self._coro_wake_idxs is None: + self._coro_wake_idxs = stdlib.malloc(MAX_CORO_FUNCS * 4) + if self._coro_wake_idxs is not None: + string.memset(self._coro_wake_idxs, 0, MAX_CORO_FUNCS * 4) + self._coro_local_count = 0 + if self._coro_frames is None: + self._coro_frames = stdlib.malloc(MAX_CORO_FUNCS * 16) + if self._coro_frames is not None: + string.memset(self._coro_frames, 0, MAX_CORO_FUNCS * 16) + self._coro_frame_count = 0 + + # ============================================================ + # 主翻译入口 + # ============================================================ + 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: + # 错误上下文帧:当前模块触发依赖 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) + + +# ============================================================ +# Mixin - Handler 非多态基类(自 HandlesBase 迁入) +# +# 持有 Translator 回指针。ExprCallHandle 等跨模块 handler 类经 +# `class X(Translator.Mixin)` 继承(TPV 支持模块限定基类继承)。 +# ============================================================ +@t.NoVTable +class Mixin: + """所有 Handle 的非多态基类:持有 Translator 回指针 + 共享委托方法""" + Trans: Translator | t.CPtr + + def InitMixin(self, trans: Translator | t.CPtr) -> int: + """初始化 Mixin 字段(子类 __init__ 中调用)""" + self.Trans = trans + return 0 + + +# ============================================================ + +# 全局 mbuddy 指针 +_mbuddy: memhub.MemBuddy | t.CPtr + diff --git a/App/lib/core/Gen/TranslatorGenMixin.vp b/App/lib/core/Gen/TranslatorGenMixin.vp index 558ddfd..113272c 100644 --- a/App/lib/core/Gen/TranslatorGenMixin.vp +++ b/App/lib/core/Gen/TranslatorGenMixin.vp @@ -7,7 +7,7 @@ import memhub import string import viperlib import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT +import lib.core.Gen.Translator as HT import lib.core.Gen.GenTypes as GenTypes diff --git a/App/lib/core/Gen/Type/TypeGenCDef.vp b/App/lib/core/Gen/Type/TypeGenCDef.vp index 8ed6816..1bf4bc8 100644 --- a/App/lib/core/Gen/Type/TypeGenCDef.vp +++ b/App/lib/core/Gen/Type/TypeGenCDef.vp @@ -8,10 +8,7 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger import lib.core.CompilerFactory as CompilerFactory diff --git a/App/lib/core/Gen/Type/TypeGenCType.vp b/App/lib/core/Gen/Type/TypeGenCType.vp index f6e1e5f..4f1950b 100644 --- a/App/lib/core/Gen/Type/TypeGenCType.vp +++ b/App/lib/core/Gen/Type/TypeGenCType.vp @@ -8,10 +8,7 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger import lib.core.CompilerFactory as CompilerFactory @@ -322,7 +319,6 @@ class TypeGenCType(TypeGenBase.TypeGenBase): # 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: @@ -355,7 +351,6 @@ class TypeGenCType(TypeGenBase.TypeGenBase): 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: diff --git a/App/lib/core/Gen/Type/TypeGenErr.vp b/App/lib/core/Gen/Type/TypeGenErr.vp index 0b9acf5..09b2bef 100644 --- a/App/lib/core/Gen/Type/TypeGenErr.vp +++ b/App/lib/core/Gen/Type/TypeGenErr.vp @@ -1,396 +1,396 @@ -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 stdio -import stdlib -import sys -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.Stub.StubMerger as StubMerger -import lib.core.CompilerFactory as CompilerFactory -import lib.core.Handles.HandlesTranslator as HT - -import lib.core.Gen.Type.TypeGenBase as TypeGenBase - - -# ============================================================ -# TypeGenErr - TypeGenMixin 拆分(阶段 D):错误上报/源行读取/类型推断(fatal_error/infer_* 等) -# -# 继承 TypeGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesType 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class TypeGenErr(TypeGenBase.TypeGenBase): - """错误上报/源行读取/类型推断(fatal_error/infer_* 等)""" - - def _read_source_line(self, file_path: str, lineno: int) -> str: - """从源文件读取第 lineno 行内容""" - if file_path is None or lineno <= 0: - return None - f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R) - if f.closed: - return None - # 按文件实际大小分配缓冲区:固定 256KB 会截断大源文件,末尾行号读不到 → - # 误报"文件不存在或行号超出范围"(如 CallGenMixin.vp 555KB/9236 行的第 - # 8390 行)。64MB 上限防御异常超大文件整体读取。 - fsize: LONGLONG = f.size() - if fsize <= 0 or fsize > 67108864: - f.close() - return None - src_size: t.CSizeT = t.CSizeT(fsize) - buf: bytes = stdlib.malloc(src_size + 1) - if buf is None: - f.close() - return None - bytes_read: LONG = f.read_all(buf, ULONG(src_size + 1)) - f.close() - if bytes_read <= 0: - stdlib.free(buf) - return None - # 逐行查找第 lineno 行 - cur_line: int = 1 - line_start: t.CSizeT = 0 - for i in range(bytes_read): - if buf[i] == '\n': - if cur_line == lineno: - line_len: t.CSizeT = i - line_start - if line_len > 0 and buf[line_start + line_len - 1] == '\r': - line_len -= 1 - line_buf: bytes = stdlib.malloc(line_len + 1) - if line_buf is not None: - string.strncpy(line_buf, buf + line_start, line_len) - line_buf[line_len] = '\0' - stdlib.free(buf) - return line_buf - stdlib.free(buf) - return None - cur_line += 1 - line_start = i + 1 - stdlib.free(buf) - return None - def read_source_line(self, file_path: str, lineno: int) -> str: - """公开包装:从源文件读取第 lineno 行内容(供 traceback 展示)""" - return self._read_source_line(file_path, lineno) - def dump_parse_traceback(self, file_path: str) -> None: - """解析失败时以 Python 风格输出 traceback(仿 fatal_error)""" - err_line: int = ast.get_parse_err_line() - err_col: int = ast.get_parse_err_col() - err_msg: str = ast.get_parse_err_msg() - stdio.printf("Traceback (most recent call last):\n") - if file_path is None or file_path[0] == 0: - file_path = "" - if err_line > 0: - stdio.printf(' File "%s", line %d\n', file_path, err_line) - src: str = self._read_source_line(file_path, err_line) - if src is not None: - stdio.printf(" %s\n", src) - # 列标记:在出错 token 起始列下方标 ^(parser 的 col_offset 是 0-based, - # 前缀 4 空格 + err_col 个空格后落点恰好是该 token 首字符) - if err_col > 0: - stdio.printf(" ") - c: int - for c in range(err_col): - stdio.printf(" ") - stdio.printf("^\n") - stdlib.free(src) - else: - stdio.printf(' File "%s"\n', file_path) - if err_msg is None or err_msg[0] == 0: - err_msg = "语法错误" - stdio.printf("SyntaxError: %s\n", err_msg) - def fatal_error(self, node: ast.AST | t.CPtr, msg: str, - err_type: str = "SyntaxError", - col_start: int = 0, col_end: int = 0): - """以 Python 风格报错并退出(支持多帧、错误类型、列范围) - - 向后兼容:err_type/col_start/col_end 有默认值,旧调用 fatal_error(node, msg) 仍可用。 - """ - stdio.printf("Traceback (most recent call last):\n") - # 输出调用栈帧(从底到顶) - i: int - for i in range(self.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) - src: str = self._read_source_line(frame.file_name, frame.lineno) - if src is not None: - stdio.printf(" %s\n", src) - stdlib.free(src) - else: - stdio.printf(' File "%s"\n', frame.file_name) - # 输出当前帧(node 对应的位置) - lineno: int = 0 - if node is not None: - lineno = node.lineno - file_name: str = self.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.Gen.TypeGenBase.TraceCount > 0: - ti_b: int = self.Gen.TypeGenBase.TraceCount - 1 - while ti_b >= 0: - 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 - break - ti_b -= 1 - # 行号合理性防御:先读取该行源码,验证 node.lineno 是否落在当前文件内。 - # 若读不到(文件不存在或行号超出范围),说明文件/行号归属不可信 - # (如 AST 树被内存复用/串扰后跨文件报错),打印警告而非误导性行号。 - src_line: str = None - line_ok: int = 1 - if lineno > 0 and string.strcmp(file_name, "") != 0: - src_line = self._read_source_line(file_name, lineno) - if src_line is None: - line_ok = 0 - if line_ok == 0: - stdio.printf(' File "%s", line %d (!! 无法读取该行源码:文件不存在或行号超出范围,错误可能来自被复用的 AST 树,请以错误消息为准)\n', - file_name, lineno) - else: - stdio.printf(' File "%s", line %d\n', file_name, lineno) - if src_line is not None: - stdio.printf(" %s\n", src_line) - # 列范围标记:在源代码行下方用 ^ 标记出错范围 - if col_start > 0 and col_end >= col_start: - stdio.printf(" ") - j: int - for j in range(col_end): - if j >= col_start - 1 and j < col_end: - stdio.printf("^") - else: - stdio.printf(" ") - stdio.printf("\n") - stdlib.free(src_line) - # 输出错误类型 + 消息 - if err_type is None or err_type[0] == 0: - err_type = "SyntaxError" - stdio.printf("%s: %s\n", err_type, msg) - sys.exit(1) - - def fatal_type_error(self, node: ast.AST | t.CPtr, msg: str, - col_start: int = 0, col_end: int = 0): - """以 Python 风格报错并退出(TypeError 版本)""" - self.fatal_error(node, msg, "TypeError", col_start, col_end) - def try_extract_callable_ret(self, pool: memhub.MemBuddy | t.CPtr, - annot: ast.AST | t.CPtr, - imported_modules: str, - from_imports: str, - trans: HT.Translator | t.CPtr) -> llvmlite.LLVMType | t.CPtr: - """提取 t.Callable 注解的返回类型 LLVMType;非 Callable 注解返回 None""" - if annot is None or annot.kind() != ast.ASTKind.Subscript: - return None - sub_cr: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot) - if sub_cr.value is None or sub_cr.value.kind() != ast.ASTKind.Attribute: - return None - at_cr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sub_cr.value) - if at_cr.attr is None or string.strcmp(at_cr.attr, "Callable") != 0: - return None - # slice 必须是 Tuple(elts=[args_list, ret_node]) - if sub_cr.slice is None or sub_cr.slice.kind() != ast.ASTKind.Tuple: - return None - tp_cr: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub_cr.slice) - if tp_cr.elts is None or len(tp_cr.elts) != 2: - return None - ret_node_cr: ast.AST | t.CPtr = tp_cr.elts.get(1) - if ret_node_cr is None: - return None - return self.Gen.TypeGenResolve.resolve_annotation_type(pool, ret_node_cr, imported_modules, from_imports, trans, 0) - def has_decorator_marker(self, node: ast.AST | t.CPtr, - marker_name: str, - depth: int = 0) -> int: - """检测类型注解中是否包含指定的装饰器标记""" - if node is None or marker_name is None: - return 0 - # 递归深度守卫:vpi stub 注入时对每个函数 returns 调用本函数, - # vpi tree 深层节点可能被覆盖损坏成回指环(VpiReader L810-813), - # BinOp 递归无守卫会无限递归直至栈耗尽。fail-fast 终止。 - if depth > 128: - self.fatal_type_error(node, "装饰器标记检测递归过深(AST 环或嵌套超过 128 层)") - - k: int = node.kind() - - # Attribute 节点: t.CExtern, t.State, t.CExport, t.CInline - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at.attr is not None: - if string.strcmp(at.attr, marker_name) == 0: - return 1 - return 0 - - # BinOp 节点: int | t.CExtern(递归检测左右子节点) - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - if self.has_decorator_marker(bop.left, marker_name, depth + 1) != 0: - return 1 - if self.has_decorator_marker(bop.right, marker_name, depth + 1) != 0: - return 1 - return 0 - - return 0 - def is_pass_body(self, body: list[ast.AST | t.CPtr] | t.CPtr) -> int: - """检测函数体是否为 pass(空体或仅含 pass 语句)""" - if body is None: - return 1 - bn: t.CSizeT = len(body) - if bn == 0: - return 1 - if bn == 1: - stmt: ast.AST | t.CPtr = body.get(0) - if stmt is not None and stmt.kind() == ast.ASTKind.Pass: - return 1 - return 0 - def get_llvm_type_bits(self, ty: llvmlite.LLVMType | t.CPtr) -> int: - """获取 LLVM 整数类型的位宽,非整数类型返回 0""" - if ty is None: - return 0 - match ty: - case llvmlite.LLVMType.Int(bits): - return bits - case _: - return 0 - def infer_expr_type(self, pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr, - param_types: str) -> llvmlite.LLVMType | t.CPtr: - """推断表达式的 LLVM 类型 - - param_types 格式: "name:bits,name:bits,..." - """ - if node is None: - return llvmlite.Int32(pool) - - k: int = node.kind() - - if k == ast.ASTKind.Constant: - return llvmlite.Int32(pool) - - elif k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm.id is not None and param_types is not None: - # 在 param_types 中查找: "name:bits" 格式 - search_key: str = pool.alloc(64) - if search_key is not None: - viperlib.snprintf(search_key, 64, "%s:", nm.id) - found: str = string.strstr(param_types, search_key) - if found is not None: - colon_pos: t.CSizeT = string.strlen(nm.id) + 1 - bits_str: str = found + colon_pos - bits: int = 0 - for bi in range(4): - ch: t.CChar = bits_str[bi] - if ch >= '0' and ch <= '9': - bits = bits * 10 + (ch - '0') - else: - break - if bits == 64: - return llvmlite.Int64(pool) - elif bits == 16: - return llvmlite.Int16(pool) - elif bits == 8: - return llvmlite.Int8(pool) - return llvmlite.Int32(pool) - - elif k == ast.ASTKind.BinOp: - binop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - lhs_ty: llvmlite.LLVMType | t.CPtr = self.infer_expr_type( - pool, binop.left, param_types) - rhs_ty: llvmlite.LLVMType | t.CPtr = self.infer_expr_type( - pool, binop.right, param_types) - lhs_bits: int = self.get_llvm_type_bits(lhs_ty) - rhs_bits: int = self.get_llvm_type_bits(rhs_ty) - if lhs_bits >= rhs_bits: - return lhs_ty - return rhs_ty - - return llvmlite.Int32(pool) - def infer_return_type(self, pool: memhub.MemBuddy | t.CPtr, - body: list[ast.AST | t.CPtr] | t.CPtr, - param_types: str) -> llvmlite.LLVMType | t.CPtr: - """扫描函数体中的 return 语句,推断返回类型""" - if body is None: - return llvmlite.Int32(pool) - - ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - bn: t.CSizeT = len(body) - for bi in range(bn): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None and stmt.kind() == ast.ASTKind.Return: - rt: ast.Return | t.CPtr = (ast.Return | t.CPtr)(stmt) - if rt.value is not None: - expr_ty: llvmlite.LLVMType | t.CPtr = self.infer_expr_type( - pool, rt.value, param_types) - if expr_ty is not None: - cur_bits: int = self.get_llvm_type_bits(ret_ty) - new_bits: int = self.get_llvm_type_bits(expr_ty) - if new_bits > cur_bits: - ret_ty = expr_ty - return ret_ty - def build_param_types_str(self, pool: memhub.MemBuddy | t.CPtr, - args_node: ast.AST | t.CPtr) -> str: - """构建参数类型编码字符串 "name:bits,name:bits,..." """ - if args_node is None: - return None - ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) - if ags.args is None: - return None - alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args - an: t.CSizeT = len(alist) - if an == 0: - return None - - buf_size: t.CSizeT = an * 32 + 1 - buf: str = pool.alloc(buf_size) - if buf is None: - return None - buf[0] = '\0' - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - for ai in range(an): - arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) - if arg is not None and arg.arg is not None: - param_ty: llvmlite.LLVMType | t.CPtr = i32_ty - if arg.annotation is not None: - # 直接调用 map_t_type 解析 Attribute 注解 - if arg.annotation.kind() == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg.annotation) - if at.attr is not None: - resolved: llvmlite.LLVMType | t.CPtr = self.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) - if bits == 0: - bits = 32 - tmp: str = pool.alloc(32) - if tmp is not None: - viperlib.snprintf(tmp, 32, "%s:%d", arg.arg, bits) - if ai > 0: - self._strappend(buf, buf_size, ",") - self._strappend(buf, buf_size, tmp) - return buf - def _strappend(self, dst: str, dst_size: t.CSizeT, src: str): - """将 src 追加到 dst 末尾""" - if dst is None or src is None: - return - dlen: t.CSizeT = string.strlen(dst) - slen: t.CSizeT = string.strlen(src) - remain: t.CSizeT = dst_size - dlen - if remain <= 0: - return - # 内联 min(slen, remain - 1) 避免 builtin min 未定义(TransPyV 无 builtin min) - limit: t.CSizeT = slen - cap: t.CSizeT = remain - 1 - if cap < limit: - limit = cap - for i in range(limit): - dst[dlen + i] = src[i] +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 stdio +import stdlib +import sys +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.Stub.StubMerger as StubMerger +import lib.core.CompilerFactory as CompilerFactory +import lib.core.Gen.Translator as HT + +import lib.core.Gen.Type.TypeGenBase as TypeGenBase + + +# ============================================================ +# TypeGenErr - TypeGenMixin 拆分(阶段 D):错误上报/源行读取/类型推断(fatal_error/infer_* 等) +# +# 继承 TypeGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesType 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class TypeGenErr(TypeGenBase.TypeGenBase): + """错误上报/源行读取/类型推断(fatal_error/infer_* 等)""" + + def _read_source_line(self, file_path: str, lineno: int) -> str: + """从源文件读取第 lineno 行内容""" + if file_path is None or lineno <= 0: + return None + f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R) + if f.closed: + return None + # 按文件实际大小分配缓冲区:固定 256KB 会截断大源文件,末尾行号读不到 → + # 误报"文件不存在或行号超出范围"(如 CallGenMixin.vp 555KB/9236 行的第 + # 8390 行)。64MB 上限防御异常超大文件整体读取。 + fsize: LONGLONG = f.size() + if fsize <= 0 or fsize > 67108864: + f.close() + return None + src_size: t.CSizeT = t.CSizeT(fsize) + buf: bytes = stdlib.malloc(src_size + 1) + if buf is None: + f.close() + return None + bytes_read: LONG = f.read_all(buf, ULONG(src_size + 1)) + f.close() + if bytes_read <= 0: + stdlib.free(buf) + return None + # 逐行查找第 lineno 行 + cur_line: int = 1 + line_start: t.CSizeT = 0 + for i in range(bytes_read): + if buf[i] == '\n': + if cur_line == lineno: + line_len: t.CSizeT = i - line_start + if line_len > 0 and buf[line_start + line_len - 1] == '\r': + line_len -= 1 + line_buf: bytes = stdlib.malloc(line_len + 1) + if line_buf is not None: + string.strncpy(line_buf, buf + line_start, line_len) + line_buf[line_len] = '\0' + stdlib.free(buf) + return line_buf + stdlib.free(buf) + return None + cur_line += 1 + line_start = i + 1 + stdlib.free(buf) + return None + def read_source_line(self, file_path: str, lineno: int) -> str: + """公开包装:从源文件读取第 lineno 行内容(供 traceback 展示)""" + return self._read_source_line(file_path, lineno) + def dump_parse_traceback(self, file_path: str) -> None: + """解析失败时以 Python 风格输出 traceback(仿 fatal_error)""" + err_line: int = ast.get_parse_err_line() + err_col: int = ast.get_parse_err_col() + err_msg: str = ast.get_parse_err_msg() + stdio.printf("Traceback (most recent call last):\n") + if file_path is None or file_path[0] == 0: + file_path = "" + if err_line > 0: + stdio.printf(' File "%s", line %d\n', file_path, err_line) + src: str = self._read_source_line(file_path, err_line) + if src is not None: + stdio.printf(" %s\n", src) + # 列标记:在出错 token 起始列下方标 ^(parser 的 col_offset 是 0-based, + # 前缀 4 空格 + err_col 个空格后落点恰好是该 token 首字符) + if err_col > 0: + stdio.printf(" ") + c: int + for c in range(err_col): + stdio.printf(" ") + stdio.printf("^\n") + stdlib.free(src) + else: + stdio.printf(' File "%s"\n', file_path) + if err_msg is None or err_msg[0] == 0: + err_msg = "语法错误" + stdio.printf("SyntaxError: %s\n", err_msg) + def fatal_error(self, node: ast.AST | t.CPtr, msg: str, + err_type: str = "SyntaxError", + col_start: int = 0, col_end: int = 0): + """以 Python 风格报错并退出(支持多帧、错误类型、列范围) + + 向后兼容:err_type/col_start/col_end 有默认值,旧调用 fatal_error(node, msg) 仍可用。 + """ + stdio.printf("Traceback (most recent call last):\n") + # 输出调用栈帧(从底到顶) + i: int + for i in range(self.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) + src: str = self._read_source_line(frame.file_name, frame.lineno) + if src is not None: + stdio.printf(" %s\n", src) + stdlib.free(src) + else: + stdio.printf(' File "%s"\n', frame.file_name) + # 输出当前帧(node 对应的位置) + lineno: int = 0 + if node is not None: + lineno = node.lineno + file_name: str = self.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.Gen.TypeGenBase.TraceCount > 0: + ti_b: int = self.Gen.TypeGenBase.TraceCount - 1 + while ti_b >= 0: + 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 + break + ti_b -= 1 + # 行号合理性防御:先读取该行源码,验证 node.lineno 是否落在当前文件内。 + # 若读不到(文件不存在或行号超出范围),说明文件/行号归属不可信 + # (如 AST 树被内存复用/串扰后跨文件报错),打印警告而非误导性行号。 + src_line: str = None + line_ok: int = 1 + if lineno > 0 and string.strcmp(file_name, "") != 0: + src_line = self._read_source_line(file_name, lineno) + if src_line is None: + line_ok = 0 + if line_ok == 0: + stdio.printf(' File "%s", line %d (!! 无法读取该行源码:文件不存在或行号超出范围,错误可能来自被复用的 AST 树,请以错误消息为准)\n', + file_name, lineno) + else: + stdio.printf(' File "%s", line %d\n', file_name, lineno) + if src_line is not None: + stdio.printf(" %s\n", src_line) + # 列范围标记:在源代码行下方用 ^ 标记出错范围 + if col_start > 0 and col_end >= col_start: + stdio.printf(" ") + j: int + for j in range(col_end): + if j >= col_start - 1 and j < col_end: + stdio.printf("^") + else: + stdio.printf(" ") + stdio.printf("\n") + stdlib.free(src_line) + # 输出错误类型 + 消息 + if err_type is None or err_type[0] == 0: + err_type = "SyntaxError" + stdio.printf("%s: %s\n", err_type, msg) + sys.exit(1) + + def fatal_type_error(self, node: ast.AST | t.CPtr, msg: str, + col_start: int = 0, col_end: int = 0): + """以 Python 风格报错并退出(TypeError 版本)""" + self.fatal_error(node, msg, "TypeError", col_start, col_end) + def try_extract_callable_ret(self, pool: memhub.MemBuddy | t.CPtr, + annot: ast.AST | t.CPtr, + imported_modules: str, + from_imports: str, + trans: HT.Translator | t.CPtr) -> llvmlite.LLVMType | t.CPtr: + """提取 t.Callable 注解的返回类型 LLVMType;非 Callable 注解返回 None""" + if annot is None or annot.kind() != ast.ASTKind.Subscript: + return None + sub_cr: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot) + if sub_cr.value is None or sub_cr.value.kind() != ast.ASTKind.Attribute: + return None + at_cr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sub_cr.value) + if at_cr.attr is None or string.strcmp(at_cr.attr, "Callable") != 0: + return None + # slice 必须是 Tuple(elts=[args_list, ret_node]) + if sub_cr.slice is None or sub_cr.slice.kind() != ast.ASTKind.Tuple: + return None + tp_cr: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub_cr.slice) + if tp_cr.elts is None or len(tp_cr.elts) != 2: + return None + ret_node_cr: ast.AST | t.CPtr = tp_cr.elts.get(1) + if ret_node_cr is None: + return None + return self.Gen.TypeGenResolve.resolve_annotation_type(pool, ret_node_cr, imported_modules, from_imports, trans, 0) + def has_decorator_marker(self, node: ast.AST | t.CPtr, + marker_name: str, + depth: int = 0) -> int: + """检测类型注解中是否包含指定的装饰器标记""" + if node is None or marker_name is None: + return 0 + # 递归深度守卫:vpi stub 注入时对每个函数 returns 调用本函数, + # vpi tree 深层节点可能被覆盖损坏成回指环(VpiReader L810-813), + # BinOp 递归无守卫会无限递归直至栈耗尽。fail-fast 终止。 + if depth > 128: + self.fatal_type_error(node, "装饰器标记检测递归过深(AST 环或嵌套超过 128 层)") + + k: int = node.kind() + + # Attribute 节点: t.CExtern, t.State, t.CExport, t.CInline + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at.attr is not None: + if string.strcmp(at.attr, marker_name) == 0: + return 1 + return 0 + + # BinOp 节点: int | t.CExtern(递归检测左右子节点) + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if self.has_decorator_marker(bop.left, marker_name, depth + 1) != 0: + return 1 + if self.has_decorator_marker(bop.right, marker_name, depth + 1) != 0: + return 1 + return 0 + + return 0 + def is_pass_body(self, body: list[ast.AST | t.CPtr] | t.CPtr) -> int: + """检测函数体是否为 pass(空体或仅含 pass 语句)""" + if body is None: + return 1 + bn: t.CSizeT = len(body) + if bn == 0: + return 1 + if bn == 1: + stmt: ast.AST | t.CPtr = body.get(0) + if stmt is not None and stmt.kind() == ast.ASTKind.Pass: + return 1 + return 0 + def get_llvm_type_bits(self, ty: llvmlite.LLVMType | t.CPtr) -> int: + """获取 LLVM 整数类型的位宽,非整数类型返回 0""" + if ty is None: + return 0 + match ty: + case llvmlite.LLVMType.Int(bits): + return bits + case _: + return 0 + def infer_expr_type(self, pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr, + param_types: str) -> llvmlite.LLVMType | t.CPtr: + """推断表达式的 LLVM 类型 + + param_types 格式: "name:bits,name:bits,..." + """ + if node is None: + return llvmlite.Int32(pool) + + k: int = node.kind() + + if k == ast.ASTKind.Constant: + return llvmlite.Int32(pool) + + elif k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is not None and param_types is not None: + # 在 param_types 中查找: "name:bits" 格式 + search_key: str = pool.alloc(64) + if search_key is not None: + viperlib.snprintf(search_key, 64, "%s:", nm.id) + found: str = string.strstr(param_types, search_key) + if found is not None: + colon_pos: t.CSizeT = string.strlen(nm.id) + 1 + bits_str: str = found + colon_pos + bits: int = 0 + for bi in range(4): + ch: t.CChar = bits_str[bi] + if ch >= '0' and ch <= '9': + bits = bits * 10 + (ch - '0') + else: + break + if bits == 64: + return llvmlite.Int64(pool) + elif bits == 16: + return llvmlite.Int16(pool) + elif bits == 8: + return llvmlite.Int8(pool) + return llvmlite.Int32(pool) + + elif k == ast.ASTKind.BinOp: + binop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + lhs_ty: llvmlite.LLVMType | t.CPtr = self.infer_expr_type( + pool, binop.left, param_types) + rhs_ty: llvmlite.LLVMType | t.CPtr = self.infer_expr_type( + pool, binop.right, param_types) + lhs_bits: int = self.get_llvm_type_bits(lhs_ty) + rhs_bits: int = self.get_llvm_type_bits(rhs_ty) + if lhs_bits >= rhs_bits: + return lhs_ty + return rhs_ty + + return llvmlite.Int32(pool) + def infer_return_type(self, pool: memhub.MemBuddy | t.CPtr, + body: list[ast.AST | t.CPtr] | t.CPtr, + param_types: str) -> llvmlite.LLVMType | t.CPtr: + """扫描函数体中的 return 语句,推断返回类型""" + if body is None: + return llvmlite.Int32(pool) + + ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + bn: t.CSizeT = len(body) + for bi in range(bn): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None and stmt.kind() == ast.ASTKind.Return: + rt: ast.Return | t.CPtr = (ast.Return | t.CPtr)(stmt) + if rt.value is not None: + expr_ty: llvmlite.LLVMType | t.CPtr = self.infer_expr_type( + pool, rt.value, param_types) + if expr_ty is not None: + cur_bits: int = self.get_llvm_type_bits(ret_ty) + new_bits: int = self.get_llvm_type_bits(expr_ty) + if new_bits > cur_bits: + ret_ty = expr_ty + return ret_ty + def build_param_types_str(self, pool: memhub.MemBuddy | t.CPtr, + args_node: ast.AST | t.CPtr) -> str: + """构建参数类型编码字符串 "name:bits,name:bits,..." """ + if args_node is None: + return None + ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if ags.args is None: + return None + alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args + an: t.CSizeT = len(alist) + if an == 0: + return None + + buf_size: t.CSizeT = an * 32 + 1 + buf: str = pool.alloc(buf_size) + if buf is None: + return None + buf[0] = '\0' + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + for ai in range(an): + arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) + if arg is not None and arg.arg is not None: + param_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if arg.annotation is not None: + # 直接调用 map_t_type 解析 Attribute 注解 + if arg.annotation.kind() == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg.annotation) + if at.attr is not None: + resolved: llvmlite.LLVMType | t.CPtr = self.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) + if bits == 0: + bits = 32 + tmp: str = pool.alloc(32) + if tmp is not None: + viperlib.snprintf(tmp, 32, "%s:%d", arg.arg, bits) + if ai > 0: + self._strappend(buf, buf_size, ",") + self._strappend(buf, buf_size, tmp) + return buf + def _strappend(self, dst: str, dst_size: t.CSizeT, src: str): + """将 src 追加到 dst 末尾""" + if dst is None or src is None: + return + dlen: t.CSizeT = string.strlen(dst) + slen: t.CSizeT = string.strlen(src) + remain: t.CSizeT = dst_size - dlen + if remain <= 0: + return + # 内联 min(slen, remain - 1) 避免 builtin min 未定义(TransPyV 无 builtin min) + limit: t.CSizeT = slen + cap: t.CSizeT = remain - 1 + if cap < limit: + limit = cap + for i in range(limit): + dst[dlen + i] = src[i] dst[dlen + i] = '\0' # i 退出值存疑 \ No newline at end of file diff --git a/App/lib/core/Gen/Type/TypeGenMixin.vp b/App/lib/core/Gen/Type/TypeGenMixin.vp index d6f0e32..ef1e635 100644 --- a/App/lib/core/Gen/Type/TypeGenMixin.vp +++ b/App/lib/core/Gen/Type/TypeGenMixin.vp @@ -11,7 +11,7 @@ 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.Translator as HT import lib.core.Gen.Type.TypeGenBase as TypeGenBase diff --git a/App/lib/core/Gen/Type/TypeGenResolve.vp b/App/lib/core/Gen/Type/TypeGenResolve.vp index 0d6585d..c9eb041 100644 --- a/App/lib/core/Gen/Type/TypeGenResolve.vp +++ b/App/lib/core/Gen/Type/TypeGenResolve.vp @@ -11,10 +11,7 @@ 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.Gen.Translator as HT import lib.Stub.StubMerger as StubMerger import lib.Stub.StubMerger.StubMergerStore as StubMergerStore import lib.core.CompilerFactory as CompilerFactory diff --git a/App/lib/core/Handles/ExprCallTable.vp b/App/lib/core/Handles/ExprCallTable.vp deleted file mode 100644 index db33e81..0000000 --- a/App/lib/core/Handles/ExprCallTable.vp +++ /dev/null @@ -1,197 +0,0 @@ -import lib.core.Gen.GenTypes as GenTypes -import lib.core.Gen.Call.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.Stub.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/HandlesBase.vp b/App/lib/core/Handles/HandlesBase.vp deleted file mode 100644 index 1625ba4..0000000 --- a/App/lib/core/Handles/HandlesBase.vp +++ /dev/null @@ -1,262 +0,0 @@ -import t, c -from stdint import * -import string -import viperlib -import memhub -import hashtable -import lib.core.Handles.HandlesTranslator as HT - - -# ============================================================ -# TypeKind - 类型种类枚举 -# -# 替代 TransPyC 中 CType.position frozenset 的元属性系统。 -# 每个 TypeInfo 通过 Kind 字段标记其种类,避免 Python ClassVar 反射。 -# ============================================================ -class TypeKind(t.CEnum): - Basic: t.State # 基本类型(int/char/float/double/bool 等) - Pointer: t.State # 指针(T*)— 指针层数由 TypeInfo.PtrCount 表达 - Struct: t.State # 结构体/类 - Union: t.State # 联合体 - Enum: t.State # 枚举 - Typedef: t.State # 类型别名 - Function: t.State # 函数指针 - Array: t.State # 数组 T[N] - Void: t.State # void - - -# ============================================================ -# TypeInfo - 类型信息结构 -# -# 设计原则(相对 TransPyC CTypeInfo 的简化): -# - POD 数据结构,无虚函数,无 Python 元特性(ClassVar/Generic/frozenset) -# - 通过 mbuddy 分配,调用方管理生命周期(参考 llvmlite Module 模式) -# - 通过 Kind 枚举代替 position frozenset -# - PtrCount 表达指针层数(0=非指针, 1=T*, 2=T**) -# - IsSigned 三态:-1=不适用(void/float), 0=unsigned, 1=signed -# -# 字段布局(8 字段): -# Kind : i32 类型种类(TypeKind 枚举值) -# Name : i8* 类型名(如 'int', 'CInt', 'MyStruct'),可能为 None -# Size : i32 位宽(0=void/未知;int=32, char=8, double=64, long long=64) -# Align : i32 对齐字节数(0=默认) -# IsSigned : i32 -1=N/A, 0=unsigned, 1=signed -# PtrCount : i32 指针层数 -# IsConst : i32 const 限定符(0/1) -# IsVolatile : i32 volatile 限定符(0/1) -# -# 注意:Size 使用位宽(bit width)而非字节数,与 LLVM IR 的 i{N} 和 -# TransPyC CType.Size 约定一致(CInt.Size=32, CChar.Size=8)。 -# ============================================================ -@t.NoVTable -class TypeInfo: - Kind: int - Name: str - Size: int - Align: int - IsSigned: int - PtrCount: int - IsConst: int - IsVolatile: int - - -# ============================================================ -# TypeRegistry - 类型注册表 -# -# 维护 name(str) → TypeInfo* 映射,基于 HashTable 实现 O(1) 查找。 -# 替代 TransPyC CTypeRegistry 的 _name_to_class dict。 -# 内置基本类型(int/char/void/...)由 InitBasicTypes 注册。 -# ============================================================ -class TypeRegistry: - _ht: hashtable.HashTable | t.CPtr - __mbuddy__: memhub.MemBuddy | t.CPtr - - def Register(self, ti: TypeInfo | t.CPtr) -> int: - """注册一个 TypeInfo。ti.Name 字段必须已设置。 - - Returns: - 1 表示成功,0 表示失败(ti 为 None 或 Name 为 None) - """ - if ti is None: - return 0 - if ti.Name is None: - return 0 - self._ht[ti.Name] = ti - return 1 - - def Lookup(self, name: str) -> TypeInfo | t.CPtr: - """按名称查找 TypeInfo。 - - Returns: - 找到返回 TypeInfo*,找不到返回 None - """ - if name is None: - return None - return self._ht[name] - - def Has(self, name: str) -> int: - """检查类型是否已注册。""" - if name is None: - return 0 - return name in self._ht - - -# ============================================================ -# NewTypeInfo - 工厂函数:分配并初始化一个 TypeInfo -# -# 默认值:Kind=Basic, IsSigned=-1, 其余=0/None -# ============================================================ -def NewTypeInfo(pool: memhub.MemBuddy | t.CPtr) -> TypeInfo | t.CPtr: - ptr: TypeInfo | t.CPtr = pool.alloc(TypeInfo.__sizeof__()) - if ptr is None: - return None - string.memset(ptr, 0, TypeInfo.__sizeof__()) - ptr.Kind = TypeKind.Basic - ptr.IsSigned = -1 - return ptr - - -# ============================================================ -# NewTypeRegistry - 工厂函数:创建类型注册表 -# ============================================================ -def NewTypeRegistry(pool: memhub.MemBuddy | t.CPtr) -> TypeRegistry | t.CPtr: - ptr: TypeRegistry | t.CPtr = pool.alloc(TypeRegistry.__sizeof__()) - if ptr is None: - return None - string.memset(ptr, 0, TypeRegistry.__sizeof__()) - ptr.__mbuddy__ = pool - ptr._ht = hashtable.HashTable(pool) - return ptr - - -# ============================================================ -# TypeToLLVM - 将 TypeInfo 转换为 LLVM IR 类型字符串 -# -# 规则: -# - Kind == Void 或 (Size==0 且 IsSigned==-1 且 PtrCount==0) → "void" -# - void 有 PtrCount > 0 → "i8" + PtrCount 个 "*" -# - IsSigned == -1 且 Size > 0 → 浮点: half/float/double/fp128 -# - IsSigned != -1 且 Size > 0 → 整数: i{Size} -# - 未知 → "i8*" -# -# Args: -# buf: 输出缓冲区(i8*) -# buf_size: 缓冲区容量 -# ti: TypeInfo 指针 -# -# Returns: -# 写入的字符数(不含 NUL),失败返回 -1 -# ============================================================ -def TypeToLLVM(buf: str, buf_size: t.CSizeT, - ti: TypeInfo | t.CPtr) -> int: - if buf is None: - return -1 - if ti is None: - return -1 - if buf_size == 0: - return -1 - - # 判定 void - is_void: int = 0 - if ti.Kind == TypeKind.Void: - is_void = 1 - elif ti.Size == 0 and ti.IsSigned == -1 and ti.PtrCount == 0: - is_void = 1 - - # 写入 base 类型字符串到 buf - base_len: int = 0 - if is_void == 1: - if ti.PtrCount == 0: - # "void" - if buf_size < 5: - return -1 - string.strcpy(buf, "void") - base_len = 4 - else: - # void* → i8*(LLVM 中 void* 表示为 i8*) - if buf_size < 4: - return -1 - string.strcpy(buf, "i8") - base_len = 2 - elif ti.IsSigned == -1: - # 浮点 - if ti.Size == 16: - if buf_size < 5: - return -1 - string.strcpy(buf, "half") - base_len = 4 - elif ti.Size == 32: - if buf_size < 6: - return -1 - string.strcpy(buf, "float") - base_len = 5 - elif ti.Size == 64: - if buf_size < 7: - return -1 - string.strcpy(buf, "double") - base_len = 6 - elif ti.Size == 128: - if buf_size < 6: - return -1 - string.strcpy(buf, "fp128") - base_len = 5 - else: - # 未知浮点尺寸 → double 兜底 - if buf_size < 7: - return -1 - string.strcpy(buf, "double") - base_len = 6 - else: - # 整数: i{Size},用 snprintf 安全写入 - if ti.Size <= 0: - # 无效尺寸 → i8 兜底 - if buf_size < 4: - return -1 - string.strcpy(buf, "i8") - base_len = 2 - else: - viperlib.snprintf(buf, buf_size, "i%d", ti.Size) - base_len = string.strlen(buf) - - # 追加 PtrCount 个 "*" - if base_len + ti.PtrCount + 1 > buf_size: - return -1 - pos: int = base_len - for i in range(ti.PtrCount): - buf[pos] = '*' - pos += 1 - buf[pos] = 0 - return pos - - -# ============================================================ -# Mixin - 所有 Handle 的非多态基类(对应 TransPyC 的 BaseHandle) -# -# @t.NoVTable 继承:字段展平嵌入子类,无 vtable 开销(对应 C++ 非多态继承)。 -# 子类继承 Trans 字段 + 共享工具方法,编译器自动生成子类方法包装 -# (self bitcast 为父类指针后调用),子类可直接调用继承的方法。 -# -# 用法: -# @t.NoVTable -# class AssignHandle(Mixin): -# _CurrentClass: str -# def __init__(self, trans): -# self.InitMixin(trans) -# self._CurrentClass = None -# def Handle(self, node) -> int: -# rhs = self.Trans.ExprH.HandleValue(node.value) -# ... -# ============================================================ -@t.NoVTable -class Mixin: - """所有 Handle 的非多态基类:持有 Translator 回指针 + 共享委托方法""" - Trans: HT.Translator | t.CPtr - - def InitMixin(self, trans: HT.Translator | t.CPtr) -> int: - """初始化 Mixin 字段(子类 __init__ 中调用)""" - self.Trans = trans - return 0 - - -# 全局 mbuddy 指针 -_mbuddy: t.CVoid | t.CPtr diff --git a/App/lib/core/Handles/HandlesExpr.vp b/App/lib/core/Handles/HandlesExpr.vp deleted file mode 100644 index 41dfb79..0000000 --- a/App/lib/core/Handles/HandlesExpr.vp +++ /dev/null @@ -1,953 +0,0 @@ -import lib.core.Gen.Expr.ExprGenAttr as ExprGenAttr -import lib.core.Gen.Expr.ExprGenBase as ExprGenBase -import lib.core.Gen.Expr.ExprGenCdef as ExprGenCdef -import lib.core.Gen.Expr.ExprGenCls as ExprGenCls -import lib.core.Gen.Expr.ExprGenConst as ExprGenConst -import lib.core.Gen.Expr.ExprGenFstr as ExprGenFstr -import lib.core.Gen.Expr.ExprGenMixin as ExprGenMixin -import lib.core.Gen.Expr.ExprGenName as ExprGenName -import lib.core.Gen.Expr.ExprGenOps as ExprGenOps -import lib.core.Gen.Func.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.Stub.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, out_sym: str) -> 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, out_sym: str) -> 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 deleted file mode 100644 index 1e53575..0000000 --- a/App/lib/core/Handles/HandlesExprCall.vp +++ /dev/null @@ -1,137 +0,0 @@ -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.Stub.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/__init__.vp b/App/lib/core/Handles/__init__.vp deleted file mode 100644 index a6f57df..0000000 --- a/App/lib/core/Handles/__init__.vp +++ /dev/null @@ -1,9 +0,0 @@ -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/main.vp b/App/main.vp index 3537b41..e782bf2 100644 --- a/App/main.vp +++ b/App/main.vp @@ -1,8 +1,6 @@ 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.Gen.Translator as HandlesTranslator import lib.Phase.BuildPipeline as BuildPipeline import lib.core.IncludesScanner as IncludesScanner import lib.Stub.StubMerger as StubMerger @@ -118,9 +116,6 @@ def main() -> int: # 种子 TPC 时代用裸名 @_g_gen(全局共享),遗漏三个 Handles 模块无感, # 自举后 HT/HE/HEC 委托读各自 _g_gen=None 恒失效(is_global_name 恒 0 误报) GenApi._g_gen = gen - HandlesTranslator._g_gen = gen - HandlesExpr._g_gen = gen - HandlesExprCall._g_gen = gen # P6: 注入语句/赋值/变量/导入/翻译驱动模块的单例 # 初始化 VLogger 并打印启动日志