From 82a86761b9828e87fcf2e88bb61ec9a082faa63d Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Sat, 22 Aug 2026 00:34:32 +0800 Subject: [PATCH] =?UTF-8?q?feat(tpv):=20=E8=AF=AD=E8=A8=80=E5=86=85?= =?UTF-8?q?=E5=8D=8F=E7=A8=8B=20M1-M7=20=E7=A7=BB=E6=A4=8D=E2=80=94?= =?UTF-8?q?=E2=80=94async/await=20=E7=8A=B6=E6=80=81=E6=9C=BA=20+=20?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E4=BC=A0=E6=92=AD=20+=20=E5=B8=A7=E6=B1=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - M1: async def -> 帧结构体 + create_/resume_ 状态机 + coro.coro_run 内联 - M2: async 参数、嵌套 await 提升 __await_N、If/While 内 await - M3: For 内 await(range->While)、coro_sleep 轮询挂起、coro_destroy 回池 - M4: raise 存码、await 子帧异常传播、coro_exception、coro_gather - M5/M6: try/except 链式匹配 + as e 绑定 + 异常类型码 - M7: try/finally、异常消息 msg 槽、自定义异常类、帧池复用 --- App/lib/core/Gen/AssignGenMixin.vp | 11 + App/lib/core/Gen/AsyncGenMixin.vp | 2836 +++++++++++++++++++ App/lib/core/Gen/CallGenDispatch.vp | 3046 +++++++++++---------- App/lib/core/Gen/CallGenMixin.vp | 2353 ++++++++-------- App/lib/core/Gen/ClassGenBase.vp | 12 +- App/lib/core/Gen/ClassGenVTable.vp | 2607 +++++++++--------- App/lib/core/Gen/ExprGenMixin.vp | 16 + App/lib/core/Gen/FuncGenDef.vp | 7 + App/lib/core/Gen/Generator.vp | 9 + App/lib/core/Handles/HandlesTranslator.vp | 1342 +++++---- Test/App/async_test.vp | 58 + 11 files changed, 7722 insertions(+), 4575 deletions(-) create mode 100644 App/lib/core/Gen/AsyncGenMixin.vp create mode 100644 Test/App/async_test.vp diff --git a/App/lib/core/Gen/AssignGenMixin.vp b/App/lib/core/Gen/AssignGenMixin.vp index 2d04f95..6c7dc32 100644 --- a/App/lib/core/Gen/AssignGenMixin.vp +++ b/App/lib/core/Gen/AssignGenMixin.vp @@ -1352,6 +1352,17 @@ class AssignGenMixin: # 如果有初始值,store if aa.value is not None: + # 协程(TPV-M1):记录 async 函数调用赋值的变量名(coro.coro_run + # 内联翻译反查帧类型用)。对齐 TPC HandlesAnnAssign.py L319-326: + # value 是 Call 且 func 是 Name 且该名字是 async 函数时, + # 登记 _coro_var_async[target] = callee。 + if aa.value.kind() == ast.ASTKind.Call: + val_cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(aa.value) + if val_cl.func is not None and val_cl.func.kind() == ast.ASTKind.Name: + val_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_cl.func) + if val_nm.id is not None: + if self.Gen.AsyncGen.is_async_func(trans, val_nm.id) != 0: + self.Gen.AsyncGen.register_coro_var(trans, nm.id, val_nm.id) # 局部数组:列表字面量 → 逐元素 GEP + store 初始化 # 修复:此前局部 CArray[...] = [x, y] 会走 translate_list_literal, # 错误触发 list[T] 泛型特化(堆对象)导致崩溃(如 this.vp 的 diff --git a/App/lib/core/Gen/AsyncGenMixin.vp b/App/lib/core/Gen/AsyncGenMixin.vp new file mode 100644 index 0000000..7eb8afa --- /dev/null +++ b/App/lib/core/Gen/AsyncGenMixin.vp @@ -0,0 +1,2836 @@ +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.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) + pool_head: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i64_ty, pool_gv) + 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_gv) + 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) + 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) + pool_head: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i64_ty, pool_gv) + i64_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i64_ty) + 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_gv) + 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) + async_name: str = self._var_to_async(trans, cl.args.get(0)) + if async_name is None: + return llvmlite.ConstNull(pool, i8_ptr_ty) + 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) + 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) + 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) + 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/CallGenDispatch.vp b/App/lib/core/Gen/CallGenDispatch.vp index 25c882f..1130f9c 100644 --- a/App/lib/core/Gen/CallGenDispatch.vp +++ b/App/lib/core/Gen/CallGenDispatch.vp @@ -1,1510 +1,1538 @@ -import lib.core.Gen.GenTypes as GenTypes -import lib.core.Gen.Generator as Generator -import lib.core.Gen.ExprGenCls as ExprGenCls -import lib.core.Gen.ExprGenName as ExprGenName -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import sys -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.CompilerFactory as CompilerFactory - - -import lib.core.Gen.CallGenBase as CallGenBase - -# ============================================================ -# CallGenDispatch - CallGenMixin 拆分(阶段 C):translate_call 检测段 -# -# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 每个 helper 返回 Value|CPtr,None = 未命中(translate_call 继续)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class CallGenDispatch(CallGenBase.CallGenBase): - """translate_call 前置检测 helper(继承 Base)""" - - def _tc_h1_super_ctraits(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr, - func_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - hit_box: t.CPtr = None) -> llvmlite.Value | t.CPtr: - """super()/ctraits 编译期检测(未命中返回 None) - - hit_box: 命中标志字节([0]=1 表示被本 helper 拦截处理)。 - super().method() 命中后 _translate_super_call 对 void 方法(如 - __init__)经 build_call 返回 None 属预期(void call 无 SSA 值), - 必须用 hit_box 与"未命中"区分,否则 translate_call 会误判继续 - 主路径 → 把内层 Call(super) 当裸名调用报"super 未定义"。 - """ - # super() 语义(2026-08-10):super().method(args) → 静态调用父类方法 - # 形态: Call(func=Attribute(value=Call(func=Name('super')), attr=method)) - # 必须在 Attribute 分派前拦截——否则 value 的 Call(super) 被 translate_value - # 当作普通函数调用报错,且走普通属性调用会命中自身/虚分派而非父类实现。 - if func_name is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - sup_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if sup_at.value is not None and sup_at.value.kind() == ast.ASTKind.Call: - sup_cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(sup_at.value) - if sup_cl.func is not None and sup_cl.func.kind() == ast.ASTKind.Name: - sup_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sup_cl.func) - if sup_nm.id is not None and string.strcmp(sup_nm.id, "super") == 0: - if hit_box is not None: - hit_box[0] = 1 - return self.Gen.CallGenCall._translate_super_call( - pool, builder, mod, cl, func_name, trans) - - # ctraits 宏库编译期谓词:ctraits.isptr(x) 不生成运行时调用, - # 直接按变量存储类型返回编译期常量(CIf 求值失败回退或非 CIf 上下文时兜底, - # 避免生成跨模块调用 ctraits.isptr 触发"模块未注册 SHA1"误导性报错) - if func_name is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - ct_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if ct_at.value is not None and ct_at.value.kind() == ast.ASTKind.Name: - ct_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ct_at.value) - if ct_nm.id is not None and string.strcmp(ct_nm.id, "ctraits") == 0 \ - and string.strcmp(func_name, "isptr") == 0: - ct_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if ct_args is not None and len(ct_args) >= 1: - ct_arg0: ast.AST | t.CPtr = ct_args.get(0) - if ct_arg0 is not None and ct_arg0.kind() == ast.ASTKind.Name: - ct_nm0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ct_arg0) - if ct_nm0.id is not None and trans is not None: - ct_r: int = self.Gen.StmtGenCif._eval_ctraits_isptr(trans.SymTab, ct_nm0.id) - if ct_r > 0: - return llvmlite.const_int32(pool, 1) - return llvmlite.const_int32(pool, 0) - return None - - def _tc_h2_c_special(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr, - func_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - hit_box: t.CPtr = None) -> llvmlite.Value | t.CPtr: - """c.Deref/Asm/LLVMIR 等特殊调用(未命中返回 None) - - hit_box: 命中标记(t.CPtr,[0]=1 表示已识别为 c.* 特殊调用)。 - 仅对 c.Asm/c.LLVMIR 等返回 None(void,无返回值)的调用置位—— - translate_c_asm/translate_c_llvmir 成功处理 void 时返回 None, - 若不加 hit_box 会被 translate_call 误判为"未命中"继续走外部函数路径。 - """ - # 检测 c.Deref / c.DerefAs / c.Addr 等特殊调用(内联 IR,不生成 call) - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - at_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if at_node.value is not None and at_node.value.kind() == ast.ASTKind.Name: - mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_node.value) - if mod_nm.id is not None and string.strcmp(mod_nm.id, "c") == 0: - if string.strcmp(func_name, "Deref") == 0: - return self.Gen.CallGenCBuiltin.translate_c_deref(pool, builder, mod, cl, trans) - elif string.strcmp(func_name, "DerefAs") == 0: - return self.Gen.CallGenCBuiltin.translate_c_derefas(pool, builder, mod, cl, trans) - elif string.strcmp(func_name, "Addr") == 0: - return self.Gen.CallGenCBuiltin.translate_c_addr(pool, builder, mod, cl, trans) - elif string.strcmp(func_name, "Set") == 0: - # c.Set(a, b) = a = b(赋值语义,非指针解引用)。 - # 若当普通函数调用会生成 @Set 引用导致链接失败(undefined reference to `Set')。 - return self.Gen.CallGenCBuiltin.translate_c_set(pool, builder, mod, cl, trans) - elif string.strcmp(func_name, "Load") == 0: - return self.Gen.CallGenCBuiltin.translate_c_load(pool, builder, mod, cl, trans) - elif string.strcmp(func_name, "Asm") == 0: - # c.Asm 无输出(void)时 translate_c_asm 返回 None: - # 置命中标记,避免 translate_call 误判未命中继续走外部函数 - if hit_box is not None: - hit_box[0] = 1 - return self.Gen.CallGenCBuiltin.translate_c_asm(pool, builder, mod, cl, trans) - elif string.strcmp(func_name, "LLVMIR") == 0: - # c.LLVMIR 总是无返回值(返回 None):置命中标记 - if hit_box is not None: - hit_box[0] = 1 - return self.Gen.CallGenCBuiltin.translate_c_llvmir(pool, builder, mod, cl, trans) - elif string.strcmp(func_name, "LInp") == 0 or string.strcmp(func_name, "LOut") == 0: - # c.LInp/c.LOut 独立调用时返回 0(仅在 c.LLVMIR 的 f-string 内有意义) - return llvmlite.ConstInt(pool, llvmlite.Int32(pool), 0, "0") - elif string.strcmp(func_name, "CIf") == 0: - # 运行时 c.CIf(expr)(编译期求值失败回退):expr 与 0 比较得到 i1 - # 对齐 TPC HandlesExprCall.py L2434-2444 - cif_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cif_args is not None and len(cif_args) >= 1: - cif_arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, cif_args.get(0), funcs_ptr, func_count, trans) - if cif_arg_val is not None: - cif_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(cif_arg_val.Ty) - if cif_bits == 1: - return cif_arg_val - if self.Gen.ExprGenBase.is_ptr_type(cif_arg_val.Ty) != 0: - cif_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull( - pool, cif_arg_val.Ty, "null") - return llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, cif_arg_val, cif_null) - cif_zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - return llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, cif_arg_val, cif_zero) - return llvmlite.ConstInt(pool, llvmlite.Int1(pool), 0, "0") - elif string.strcmp(func_name, "CIfdef") == 0 or string.strcmp(func_name, "CIfndef") == 0: - # 运行时 c.CIfdef/c.CIfndef(编译期求值失败回退):恒真 - # 对齐 TPC HandlesExprCall.py L2445-2446 - return llvmlite.ConstInt(pool, llvmlite.Int1(pool), 1, "1") - return None - - def _tc_h3_stdarg_cast(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr, - func_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT) -> llvmlite.Value | t.CPtr: - """stdarg 糖 + str/int/bool 内置强转(未命中返回 None)""" - # stdarg 糖函数处理: va_arg / arg / va_start / va_end - # 这些函数在 stdarg.vp 中声明为 pass 体,由编译器在翻译期处理: - # va_arg(ap, type) → %N = va_arg , (LLVM 指令) - # va_arg(ap) → 同上,类型从赋值上下文推断(默认 i32) - # arg(type) → 同上,使用当前函数的隐式 va_list (trans._va_list_ptr) - # va_start(ap, _) → call void @llvm.va_start(i8* %ap) (LLVM intrinsic) - # va_end(ap) → call void @llvm.va_end(i8* %ap) (LLVM intrinsic) - # ============================================================ - if func_name is not None and trans is not None: - if string.strcmp(func_name, "va_arg") == 0: - return self.Gen.CallGenVa._translate_va_arg_sugar(pool, builder, mod, cl, cargs, can, - funcs_ptr, func_count, trans) - elif string.strcmp(func_name, "arg") == 0: - return self.Gen.CallGenVa._translate_arg_sugar(pool, builder, mod, cl, cargs, can, - funcs_ptr, func_count, trans) - elif string.strcmp(func_name, "va_start") == 0: - return self.Gen.CallGenVa._translate_va_start_sugar(pool, builder, mod, cargs, can, - funcs_ptr, func_count, trans) - elif string.strcmp(func_name, "va_end") == 0: - return self.Gen.CallGenVa._translate_va_end_sugar(pool, builder, mod, cargs, can, - funcs_ptr, func_count, trans) - - # 内置强转函数: str(x)/bytes(x) → i8*, int(x) → i32 - # 等价于 (str)(x) / (t.CInt32T)(x) - # 单参数:str(val) → bitcast val to i8* - # int(val) → trunc/sext val to i32 - # 泛型类型参数: 类特化/泛型函数上下文中的 T(x) 先解析 T 为具体类型名 - # (如 "int")再按内建强转处理(Box[int].__init__ 的 self.value = T(v)、 - # combine[T1,T2] 的 T1(b) 依赖此路径) - if func_name is not None and can == 1: - cast_fn_name: str = self.Gen.TypeGenBase.resolve_generic_type_name(func_name) - if string.strcmp(cast_fn_name, "str") == 0 or string.strcmp(cast_fn_name, "bytes") == 0: - # str(x) / bytes(x) → i8* (bitcast) - cast_arg: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) - if cast_arg is not None: - i8_ptr_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, cast_arg, i8_ptr_ty_builtin) - return None - elif string.strcmp(cast_fn_name, "int") == 0: - # int(x) → i32 - cast_arg_int: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) - if cast_arg_int is not None: - i32_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, cast_arg_int, i32_ty_builtin) - return None - elif string.strcmp(cast_fn_name, "bool") == 0: - # bool(x) → i1(严格 != 0 归一化) - # 整数: icmp ne x, 0 → i1 - # 浮点: fcmp one x, 0.0 → i1 - # 指针: icmp ne x, null → i1 - cast_arg_bool: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) - if cast_arg_bool is not None: - arg_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(cast_arg_bool.Ty) - arg_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(cast_arg_bool.Ty) - # 整数: icmp ne x, 0 - if arg_bits != 0: - zero_int: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, arg_bits, 0) - if zero_int is not None: - return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cast_arg_bool, zero_int) - return None - # 浮点: fcmp one x, 0.0 - if arg_fbits != 0: - zero_ty: llvmlite.LLVMType | t.CPtr = cast_arg_bool.Ty - zero_flt: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, zero_ty, 0.0) - if zero_flt is not None: - return llvmlite.build_fcmp(builder, llvmlite.FCMP_ONE, cast_arg_bool, zero_flt) - return None - # 指针: icmp ne x, null - ptr_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cast_arg_bool.Ty, "null") - if ptr_null is not None: - return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cast_arg_bool, ptr_null) - return None - return None - return None - - def _tc_h4_type_casts(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr, - func_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT) -> llvmlite.Value | t.CPtr: - """t.XXX / typedef 类型转换(未命中返回 None)""" - # 检测 t.XXX 类型转换: t.CUInt64T(ptr), t.CPtr(val), t.CInt(val) 等 - # 当 func 是 t.XXX 形式且 XXX 是已知类型名时,当作类型转换处理(而非函数调用) - # 支持: - # 单参数: t.CInt(val) → 目标类型 = map_t_type(func_name) - # 双参数: t.CInt(val, t.CPtr) → 目标类型 = Ptr(map_t_type(func_name)) - # t 是内部库,一旦确认为类型转换,绝不跌落到跨模块调用 FATAL 路径 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - tc_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if tc_at.value is not None and tc_at.value.kind() == ast.ASTKind.Name: - tc_mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_at.value) - if tc_mod_nm.id is not None and string.strcmp(tc_mod_nm.id, "t") == 0: - target_ty: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.map_t_type(pool, func_name) - if target_ty is not None: - tc_effective_can: t.CSizeT = can - # 双参数形式: t.CInt(val, t.CPtr) → Ptr(target_ty) - # 注意: void* 在 LLVM 中非法,CVoid* 应表示为 i8* - if can == 2: - tc_arg2_node: ast.AST | t.CPtr = cargs.get(1) - tc_arg2_is_cptr: int = 0 - if tc_arg2_node is not None: - # 形式 1: t.CPtr(Attribute 形式) - if tc_arg2_node.kind() == ast.ASTKind.Attribute: - tc_arg2_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(tc_arg2_node) - if tc_arg2_at.attr is not None and string.strcmp(tc_arg2_at.attr, "CPtr") == 0: - if tc_arg2_at.value is not None and tc_arg2_at.value.kind() == ast.ASTKind.Name: - tc_arg2_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_arg2_at.value) - if tc_arg2_nm.id is not None and string.strcmp(tc_arg2_nm.id, "t") == 0: - tc_arg2_is_cptr = 1 - # 形式 2: 裸名 CPtr(from t import CPtr 后直接使用,如 t.CVoid(x, CPtr)) - elif tc_arg2_node.kind() == ast.ASTKind.Name: - tc_arg2_bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_arg2_node) - if tc_arg2_bn.id is not None and string.strcmp(tc_arg2_bn.id, "CPtr") == 0: - tc_arg2_is_cptr = 1 - if tc_arg2_is_cptr != 0: - # CVoid* → i8*(LLVM 中 void* 表示为 i8*) - match target_ty: - case llvmlite.LLVMType.Void(): - target_ty = llvmlite.Int8(pool) - case _: - pass - target_ty = llvmlite.Ptr(pool, target_ty) - tc_effective_can = 1 - if tc_effective_can == 1: - tc_arg_node: ast.AST | t.CPtr = cargs.get(0) - if tc_arg_node is not None: - tc_arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, tc_arg_node, None, 0, trans) - if tc_arg_val is not None: - return self.Gen.CallGenCtor._translate_t_type_cast( - pool, builder, tc_arg_val, target_ty, - func_name, tc_arg_node, trans) - # t.XXX 类型转换已确认但不满足参数条件:返回 None,不跌落到跨模块 FATAL - return None - - # 模块限定 typedef 转换: posix.mode_t(mode), w32.win32base.HANDLE(v) 等 - # func = Attribute(value=Name(模块), attr=typedef名),此前被误当跨模块函数调用 - # → "跨模块函数 'sha1.mode_t' 返回类型无法精确获取"(SysLibTest os/_posix.vp - # L130 posix.mode_t(mode) 根因)。typedef 名做类型转换(与裸名 BYTEPTR(x) - # 对齐);非 typedef 名继续走模块函数调用。 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - mt_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if mt_at.value is not None and mt_at.value.kind() == ast.ASTKind.Name: - mt_mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(mt_at.value) - if mt_mod_nm.id is not None and string.strcmp(mt_mod_nm.id, "t") != 0 \ - and string.strcmp(mt_mod_nm.id, "c") != 0: - mod_td_ty: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.map_t_type( - pool, func_name) - if mod_td_ty is None: - mod_td_str: str = self.Gen.TypeGenCType.lookup_ctypedef(func_name) - if mod_td_str is not None and self.Gen.TypeGenCType.is_ctypedef_found() != 0: - mod_td_ast: ast.AST | t.CPtr = self.Gen.TypeGenResolve._parse_type_string( - pool, mod_td_str, 0) - if mod_td_ast is not None: - mod_imp_td: str = None - mod_fi_td: str = None - if trans is not None: - mod_imp_td = trans._imported_modules - mod_fi_td = trans._from_imports - mod_td_ty = self.Gen.TypeGenResolve.resolve_annotation_type( - pool, mod_td_ast, mod_imp_td, mod_fi_td, trans) - if mod_td_ty is not None and can == 1: - mt_arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) - if mt_arg_val is not None: - return self.Gen.CallGenCtor._translate_t_type_cast( - pool, builder, mt_arg_val, mod_td_ty, - func_name, cargs.get(0), trans) - - # 裸名 typedef 调用: BYTEPTR(ptr1), HANDLE(val), CHARPTR(str) 等 - # 用户通过 `from stdint import *` 导入 typedef 后,可直接用裸名做类型转换 - # map_t_type 包含所有内置 typedef 名称(BYTEPTR/HANDLE/LPCSTR/size_t 等) - # 泛型类型参数转换: 泛型上下文(类特化/泛型函数)中 T(x) → 先解析 T 为具体 - # 类型名(如 "int")再走 map_t_type(Box[int].__init__ 的 self.value = T(v)、 - # combine[T1,T2] 的 T1(b) 依赖此路径) - if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: - bare_fn_name: str = self.Gen.TypeGenBase.resolve_generic_type_name(func_name) - bare_ty: llvmlite.LLVMType | t.CPtr = None - # 泛型上下文解析出的内建名(如 T→"double"/"float"):map_t_type 只认 t.CDouble, - # 且 float 必须映射 t.CFloat(f32)而非 f64(与注解语义一致) - if string.strcmp(bare_fn_name, "double") == 0: - bare_ty = llvmlite.Double(pool) - elif string.strcmp(bare_fn_name, "float") == 0: - bare_ty = llvmlite.Float(pool) - else: - bare_ty = self.Gen.TypeGenResolve.map_t_type(pool, bare_fn_name) - # 泛型上下文替换出的类型名(如 T→"t.CInt")map_t_type 不识别(只认无前缀名), - # 回退用 resolve_annotation_type 解析(支持 t.CXxx / 结构体类名 / 别名等)。 - # GenericTest4 Box[t.CInt].__init__ 的 self.value = T(v) 依赖此路径。 - if bare_ty is None and string.strcmp(bare_fn_name, func_name) != 0: - gp_ast: ast.AST | t.CPtr = self.Gen.TypeGenResolve._parse_type_string(pool, bare_fn_name, 0) - if gp_ast is not None: - imp_gp: str = None - fi_gp: str = None - if trans is not None: - imp_gp = trans._imported_modules - fi_gp = trans._from_imports - bare_ty = self.Gen.TypeGenResolve.resolve_annotation_type( - pool, gp_ast, imp_gp, fi_gp, trans) - # 泛型类型参数双参数形式: T(val, t.CPtr) → Ptr(T) - # (与 t.CInt(val, t.CPtr) → Ptr(i32) 对齐;vector.vp get() 的 - # typed_ptr = T(offset, t.CPtr) 依赖此路径,否则双参数不进 - # can==1 单参数分支 → 跌落到"裸名调用未定义"误报) - if bare_ty is not None and can == 2: - bare_arg2_node: ast.AST | t.CPtr = cargs.get(1) - bare_arg2_is_cptr: int = 0 - if bare_arg2_node is not None: - # 形式 1: t.CPtr(Attribute 形式) - if bare_arg2_node.kind() == ast.ASTKind.Attribute: - bare_arg2_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(bare_arg2_node) - if bare_arg2_at.attr is not None and string.strcmp(bare_arg2_at.attr, "CPtr") == 0: - if bare_arg2_at.value is not None and bare_arg2_at.value.kind() == ast.ASTKind.Name: - bare_arg2_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bare_arg2_at.value) - if bare_arg2_nm.id is not None and string.strcmp(bare_arg2_nm.id, "t") == 0: - bare_arg2_is_cptr = 1 - # 形式 2: 裸名 CPtr(from t import CPtr 后直接使用) - elif bare_arg2_node.kind() == ast.ASTKind.Name: - bare_arg2_bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bare_arg2_node) - if bare_arg2_bn.id is not None and string.strcmp(bare_arg2_bn.id, "CPtr") == 0: - bare_arg2_is_cptr = 1 - if bare_arg2_is_cptr != 0: - # CVoid* → i8*(LLVM 中 void* 表示为 i8*) - match bare_ty: - case llvmlite.LLVMType.Void(): - bare_ty = llvmlite.Int8(pool) - case _: - pass - bare_ty = llvmlite.Ptr(pool, bare_ty) - bare_arg_node: ast.AST | t.CPtr = cargs.get(0) - if bare_arg_node is not None: - bare_arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, bare_arg_node, None, 0, trans) - if bare_arg_val is not None: - return self.Gen.CallGenCtor._translate_t_type_cast( - pool, builder, bare_arg_val, bare_ty, - bare_fn_name, bare_arg_node, trans) - if bare_ty is not None and can == 1: - bare_arg_node: ast.AST | t.CPtr = cargs.get(0) - if bare_arg_node is not None: - bare_arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, bare_arg_node, None, 0, trans) - if bare_arg_val is not None: - return self.Gen.CallGenCtor._translate_t_type_cast( - pool, builder, bare_arg_val, bare_ty, - bare_fn_name, bare_arg_node, trans) - - return None - - def _tc_h5_sizeof_len_isinst(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr, - func_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT) -> llvmlite.Value | t.CPtr: - """__sizeof__/len/isinstance 内置(未命中返回 None)""" - # 检测 ClassName.__sizeof__() — 返回结构体大小常量(i64) - # __sizeof__ 是内置方法,不走跨模块调用路径 - # 支持: Argument.__sizeof__() 和 w32.win32file.WIN32_FIND_DATAA.__sizeof__() - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - sz_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if sz_at.attr is not None and string.strcmp(sz_at.attr, "__sizeof__") == 0: - if sz_at.value is not None and can == 0: - sz_cls_name: str = None - sz_vk: int = sz_at.value.kind() - if sz_vk == ast.ASTKind.Name: - sz_cls_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sz_at.value) - sz_cls_name = sz_cls_nm2.id - elif sz_vk == ast.ASTKind.Attribute: - sz_inner_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sz_at.value) - sz_cls_name = sz_inner_at.attr - # 最终解析出的结构体类型:类型名命中 → 泛型特化(Stack[T])→ 实例接收者类型(self/obj) - sz_resolved_ty: llvmlite.LLVMType | t.CPtr = None - sz_resolved_name: str = sz_cls_name - if sz_cls_name is not None: - # 泛型类型参数 T 替换: T.__sizeof__() → int.__sizeof__() - sz_cls_name = self.Gen.TypeGenBase.resolve_generic_type_name(sz_cls_name) - sz_resolved_name = sz_cls_name - # 去除模块前缀: Viper 解析器将 t.CInt 解析为 Name(id="t.CInt") - # 而非 Attribute(value=Name("t"), attr="CInt"),需要手动提取最后的类名分量 - # "t.CInt" → "CInt", "w32.win32file.WIN32_FIND_DATAA" → "WIN32_FIND_DATAA" - dot_pos: str = string.strrchr(sz_cls_name, '.') - if dot_pos is not None: - sz_cls_name = dot_pos + 1 - # 联合类型(如 AST|t.CPtr)按指针大小处理(8 字节) - # 联合类型在 TPV 中表示指针,可以指向多种类型 - # 对应 TPC 中对 BinOp/BitOr 联合类型的特殊处理 - if string.strstr(sz_cls_name, "|") is not None: - return llvmlite.const_int64(pool, 8) - # 内置类型 sizeof(int=4, str/bytes=8 指针, double=8 等) - sz_builtin: int = -1 - if string.strcmp(sz_cls_name, "int") == 0: - sz_builtin = 4 - elif string.strcmp(sz_cls_name, "str") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "bytes") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "CInt") == 0: - sz_builtin = 4 - elif string.strcmp(sz_cls_name, "CInt8T") == 0: - sz_builtin = 1 - elif string.strcmp(sz_cls_name, "CInt16T") == 0: - sz_builtin = 2 - elif string.strcmp(sz_cls_name, "CInt32T") == 0: - sz_builtin = 4 - elif string.strcmp(sz_cls_name, "CInt64T") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "CChar") == 0: - sz_builtin = 1 - elif string.strcmp(sz_cls_name, "CDouble") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "CFloat") == 0: - sz_builtin = 4 - elif string.strcmp(sz_cls_name, "CPtr") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "CSizeT") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "CBool") == 0: - sz_builtin = 1 - elif string.strcmp(sz_cls_name, "bool") == 0: - sz_builtin = 1 - # 泛型 T 解析出的裸内建名(resolve_generic_type_name 返回 - # _infer_generic_ctor_type_arg 的输出,如 T→"double"/"float"): - # 缺省会让 sz_builtin=-1 → 落到"回退 2"把 Name(T) 当值翻译 → - # NameError(VectorGenericTest Vector[double].__init__ 回归根因) - elif string.strcmp(sz_cls_name, "double") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "float") == 0: - sz_builtin = 4 - elif string.strcmp(sz_cls_name, "char") == 0: - sz_builtin = 1 - if sz_builtin >= 0: - # 注意: 必须用 const_int64 而非 ConstInt(...,"0") - # ConstInt 的 name 参数是 IR 文本表示,ValuePrint 输出时使用 Name 而非 IntVal - # 硬编码 "0" 会导致 IR 输出 i64 0 而非实际值 - return llvmlite.const_int64(pool, sz_builtin) - sz_resolved_ty = self.Gen.StructGen.get_struct_type(sz_cls_name) - # 回退 1: 泛型类引用接收者 Stack[T].__sizeof__() — Subscript → 特化后计算大小 - # (GenericTest2 Stack.type_size 依赖此路径) - if sz_resolved_ty is None and trans is not None and sz_vk == ast.ASTKind.Subscript: - sub_sz: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sz_at.value) - if sub_sz.value is not None and sub_sz.value.kind() == ast.ASTKind.Name: - gen_nm_sz: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_sz.value) - if gen_nm_sz.id is not None: - gen_args_sz: list[str] | t.CPtr = self.Gen.CallGenCtor._extract_type_args_from_slice(pool, sub_sz.slice) - if gen_args_sz is not None and len(gen_args_sz) > 0: - gargs_resolved: list[str] | t.CPtr = list[str](pool, 8) - if gargs_resolved is not None: - gai_sz: t.CSizeT = len(gen_args_sz) - gai2_sz: t.CSizeT = 0 - for gai2_sz in range(gai_sz): - gres_sz: str = self.Gen.TypeGenBase.resolve_generic_type_name( - gen_args_sz.get(gai2_sz)) - gargs_resolved.append(gres_sz) - spec_sz: str = self.Gen.ClassGenGeneric._specialize_generic_class( - trans, gen_nm_sz.id, gargs_resolved) - if spec_sz is not None: - sz_resolved_name = spec_sz - sz_resolved_ty = self.Gen.StructGen.get_struct_type(spec_sz) - # 回退 2: 实例接收者 self.__sizeof__() / obj.__sizeof__() — 用接收者值的实际类型 - # (GenericTest2 Stack.size_of 依赖此路径;self 在方法内是 Ptr(Stack[int])) - # 数组变量接收者 bl_count.__sizeof__()(t.CArray[T, N] 变量)→ alloca - # 指针 Ptr([N x T]),算 N*elem_size(TPC _HandleSizeofLlvm 数组分支; - # zhuff.vp memset(bl_count, 0, bl_count.__sizeof__()) 依赖) - if sz_resolved_ty is None: - inst_sz_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, sz_at.value, None, 0, trans) - if inst_sz_val is not None and inst_sz_val.Ty is not None: - match inst_sz_val.Ty: - case llvmlite.LLVMType.Ptr(inst_inner_sz): - match inst_inner_sz: - case llvmlite.LLVMType.Struct(_, _, _): - sz_resolved_ty = inst_inner_sz - case llvmlite.LLVMType.Array(_, _): - sz_resolved_ty = inst_inner_sz - case _: - pass - case llvmlite.LLVMType.Struct(_, _, _): - sz_resolved_ty = inst_sz_val.Ty - case llvmlite.LLVMType.Array(_, _): - # 全局数组变量(模块级 t.CArray[T,N])translate_value - # 返回数组值 [N x T](非指针);局部数组返回 alloca - # 指针 Ptr([N x T]) 走上方 Ptr(Array) 分支。 - # pyzlib_error_msg.__sizeof__() 依赖(全局字符缓冲)。 - sz_resolved_ty = inst_sz_val.Ty - case _: - pass - if sz_resolved_ty is not None: - sz_val: int = self.Gen.ClassGenEnum._get_type_size(sz_resolved_ty) - if sz_val > 0: - return llvmlite.const_int64(pool, sz_val) - # 类型已注册但大小为 0(opaque struct 或字段链表未填充):Python 风格报错终止 - self.Gen.TypeGenErr.fatal_error( - sz_at, f"类型 '{sz_resolved_name}' 已注册但大小为 0(字段链表未填充),无法计算大小", - "TypeError") - # 类型未注册:Python 风格报错终止,不静默返回 0(会导致 malloc(0)/alloc(0) 堆溢出) - if sz_resolved_name is None: - sz_resolved_name = "(unknown)" - self.Gen.TypeGenErr.fatal_error( - sz_at, f"类型 '{sz_resolved_name}' 未在结构体表中注册,无法计算大小", - "TypeError") - - # 检测 len(obj) — 返回 list 对象的 __count__ 字段(偏移 8,i64) - # __len__ 是 list[T] 的内置方法,list 是泛型类不注册 struct - # 注意: 必须用 translate_value 而非 translate_name_value,因为 len_at.value - # 可能是 Attribute 节点(如 md_ags.args),translate_name_value 只处理 Name 节点, - # 对 Attribute 会错误返回 i32 0,导致 GEP base 不是指针(base of getelementptr must be a pointer) - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - len_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if len_at.attr is not None and string.strcmp(len_at.attr, "__len__") == 0: - if len_at.value is not None and can == 0: - obj_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, len_at.value, funcs_ptr, func_count, trans) - if obj_val is not None and obj_val.Ty is not None: - # 防御性类型检查: obj_val 必须是指针类型才能做 GEP - # 如果 translate_value 返回 i32 (如 CDefine 常量被误解析、 - # 模块属性前向引用回退为 i32),GEP base 会是 i32 而非指针, - # 导致 llc 报错 "base of getelementptr must be a pointer" - if self.Gen.ExprGenBase.is_ptr_type(obj_val.Ty) == 0: - # 类型推断失败(非指针/结构体):fail-fast,绝不返回 0 掩盖错误 - self.Gen.TypeGenErr.fatal_error( - len_at.value, "len() 参数类型推断失败(非指针/结构体)", "TypeError") - i64_ty_len: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - # 注意: 必须用 const_int64 而非 ConstInt(...,"0") - # ConstInt 的 name 参数 "0" 会被当作 IR 文本值输出 i64 0 - # 导致 GEP 索引为 0(访问 __data__)而非 1(访问 __count__) - idx_one: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) - count_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i64_ty_len, obj_val, idx_one) - if count_ptr is not None: - return llvmlite.build_load(builder, i64_ty_len, count_ptr) - - # 检测 len() 内置函数调用 — 结构体对象走 __len__ 方法,字符串走 strlen - # len(s) 对 str 类型调用 strlen,返回 i64 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: - if func_name is not None and string.strcmp(func_name, "len") == 0: - if can == 1: - len_arg_node: ast.AST | t.CPtr = cargs.get(0) - if len_arg_node is not None: - len_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, len_arg_node, None, 0, trans) - if len_val is not None: - # len(数组):t.CArray[T, N] → 常量 N(对齐 TPC - # _HandleLenLlvm 的 ArrayType.count 分支)。数组变量 - # translate_value 可能返回 Ptr([N x T])(alloca 指针) - # 或 [N x T] 值,两种都识别;否则会误走 strlen 把 - # 数组首元素当字符串读 → 垃圾长度。 - len_is_arr: int = 0 - len_arr_n: int = 0 - if len_val.Ty is not None: - if self.Gen.ExprGenBase.is_ptr_type(len_val.Ty) != 0: - len_ap: llvmlite.LLVMType | t.CPtr = len_val.Ty.Pointee - if len_ap is not None: - match len_ap: - case llvmlite.LLVMType.Array(_, len_arr_cnt): - len_is_arr = 1 - len_arr_n = len_arr_cnt - case _: - pass - else: - match len_val.Ty: - case llvmlite.LLVMType.Array(_, len_arr_cnt): - len_is_arr = 1 - len_arr_n = len_arr_cnt - case _: - pass - if len_is_arr != 0: - return llvmlite.const_int64(pool, len_arr_n) - # len(对象):有 __len__ 就调用,没有就编译期报错 - # (用户要求 2026-08-15,不再静默 strlen 读对象首字段): - # - list 泛型内置容器:__len__ 由 list 内置分支内联 - # (读 __count__,偏移 1),不生成方法函数 - # (_is_list_builtin_method,通用判断非特判) - # - 普通类:调用 {Class}.__len__ 函数 - # - 都没有:fatal_error - # str(Ptr(Int8))保持 strlen(内建语义)。 - len_struct_ty: llvmlite.LLVMType | t.CPtr = \ - self.Gen.StructGen.get_struct_type_from_value(len_val) - if len_struct_ty is not None: - len_cls_nm: str = self.Gen.StructGen.get_class_name_by_type( - pool, len_struct_ty) - if len_cls_nm is None: - self.Gen.TypeGenErr.fatal_error( - len_arg_node, "len() 参数类型推断失败(结构体类名未知)", - "TypeError") - # list 内置 __len__:读 __count__(GEP 偏移 1,i64) - if self.Gen.CallGenProp._is_list_builtin_method(len_cls_nm, "__len__") != 0: - i64_ty_lb: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - idx_one_lb: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) - cnt_ptr_lb: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i64_ty_lb, len_val, idx_one_lb) - if cnt_ptr_lb is not None: - return llvmlite.build_load(builder, i64_ty_lb, cnt_ptr_lb) - len_lookup: str = pool.alloc(128) - if len_lookup is not None: - viperlib.snprintf(len_lookup, 128, "%s.__len__", len_cls_nm) - len_fn2: llvmlite.Function | t.CPtr = self.find_func_in_module( - mod, len_lookup) - if len_fn2 is not None: - len_ret_ty2: llvmlite.LLVMType | t.CPtr = \ - llvmlite.function_get_ret_ty(len_fn2) - len_fn_name2: str = \ - llvmlite.function_get_name(len_fn2) - if len_ret_ty2 is not None and len_fn_name2 is not None: - # self 参数类型对齐(按方法首个形参 bitcast) - len_self_arg2: llvmlite.Value | t.CPtr = len_val - len_first_param2: llvmlite.Param | t.CPtr = \ - llvmlite.function_get_param_head(len_fn2) - if len_first_param2 is not None: - len_self_ty2: llvmlite.LLVMType | t.CPtr = \ - llvmlite.param_get_ty(len_first_param2) - if len_self_ty2 is not None and len_val.Ty is not None: - len_self_arg2 = llvmlite.build_bitcast( - builder, len_val, len_self_ty2) - len_self_arg2.Next = None - return llvmlite.build_call( - builder, len_fn_name2, len_self_arg2, - 1, len_ret_ty2, 0) - # len_fn2 未命中(跨模块方法):如 ndarray[t.CDouble].__len__ - # 定义在 numpy——泛型特化方法无 stub declare,find_func_in_module - # 后缀匹配查不到。用结构体所属模块 sha1 构造 - # {sha1}.{cls}.__len__ 精确调用名(对齐 _translate_method_call - # 跨模块调用名构造),返回类型从 text.ll/vpi 精确解析, - # _ensure_method_declare 建 declare 后调用。 - len_cls_sha1_x: str = self.Gen.StructGen.get_struct_sha1(len_cls_nm) - if len_cls_sha1_x is not None: - # 缓冲区需容纳 "{sha1}.{cls}.__len__": - # 2 个点 + "__len__"(7) + NUL = 10;+8 会截断 - # 末两位 → 符号变 ".__len" 链接 undefined - # (NumpyTest test_len 链接错误根因) - len_ml_x: t.CSizeT = string.strlen(len_cls_sha1_x) \ - + string.strlen(len_cls_nm) + 10 - len_mangled_x: str = pool.alloc(len_ml_x) - if len_mangled_x is not None: - viperlib.snprintf(len_mangled_x, len_ml_x, - "%s.%s.__len__", len_cls_sha1_x, len_cls_nm) - len_ret_x: llvmlite.LLVMType | t.CPtr = \ - self._LookupMethodRetTyFromTextLL( - pool, len_cls_sha1_x, len_cls_nm, "__len__") - if len_ret_x is None: - len_ret_x = self._lookup_method_ret_ty_via_vpi( - pool, len_cls_sha1_x, len_cls_nm, "__len__") - if len_ret_x is not None: - # self 参数按对象实际类型 Ptr(len_struct_ty)(与定义侧 - # 同名类型链接匹配);len_val 已是 load 后的对象指针。 - # Value 链直接作 param_head(同跨模块调用模式)。 - len_self_x: llvmlite.Value | t.CPtr = len_val - len_self_x.Next = None - self._ensure_method_declare( - pool, mod, len_mangled_x, len_ret_x, - len_self_x, 1) - return llvmlite.build_call( - builder, len_mangled_x, len_self_x, - 1, len_ret_x, 0) - # fail-fast:类没有 __len__(用户要求编译期报错) - self.Gen.TypeGenErr.fatal_error( - len_arg_node, - f"len() 参数类型 '{len_cls_nm}' 没有 __len__ 方法", - "TypeError") - # 非结构体:str(Ptr(Int8))走 strlen;其它类型 fail-fast - len_arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(len_val) - len_is_str: int = 0 - if len_arg_ty is not None and self.Gen.ExprGenBase.is_ptr_type(len_arg_ty) != 0: - match len_arg_ty: - case llvmlite.LLVMType.Ptr(len_pt_ty): - if len_pt_ty is not None: - match len_pt_ty: - case llvmlite.LLVMType.Int(len_pt_bits): - if len_pt_bits == 8: - len_is_str = 1 - case _: - pass - case _: - pass - if len_is_str != 0: - # 确保 strlen 在模块中有声明 - strlen_fn: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, "strlen") - if strlen_fn is None: - i64_ty_ln: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i8_ptr_ty_ln: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - strlen_fn = llvmlite.create_declare(pool, mod, "strlen", i64_ty_ln) - if strlen_fn is not None: - llvmlite.add_param(pool, strlen_fn, i8_ptr_ty_ln, "s") - # 参数类型转换为 i8* - i8_ptr_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - len_coerced: llvmlite.Value | t.CPtr = len_val - if self.Gen.ExprGenBase.is_ptr_type(len_arg_ty) != 0: - len_coerced = llvmlite.build_bitcast(builder, len_val, i8_ptr_ty_ln2) - # 构建单参数链表并调用 strlen - len_coerced.Next = None - i64_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - return llvmlite.build_call(builder, "strlen", len_coerced, 1, i64_ty_ln2, 0) - # fail-fast:非字符串/数组/对象,无法求长度 - self.Gen.TypeGenErr.fatal_error( - len_arg_node, "len() 参数类型不支持(非字符串/数组/对象)", - "TypeError") - - # 检测 isinstance() 内置函数调用 — 运行时 vtable 子类集合比较 - # isinstance(obj, Cls):obj 头部 vtable 指针 ∈ {Cls 及全部子类 vtable}; - # NoVTable 目标类回退编译时静态判断(详见 _translate_isinstance)。 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: - if func_name is not None and string.strcmp(func_name, "isinstance") == 0: - if can >= 2: - is_res: llvmlite.Value | t.CPtr = self.Gen.CallGenLeafKit._translate_isinstance( - pool, builder, mod, cargs.get(0), cargs.get(1), trans) - if is_res is not None: - return is_res - - return None - - def _tc_h6_method_dispatch(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr, - func_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - hit_box: t.CPtr = None) -> llvmlite.Value | t.CPtr: - """静态类/方法调用/表达式接收者/self.field/list 内置(未命中返回 None) - - hit_box: 命中标记(t.CPtr,[0]=1 表示已识别为方法调用路径)。 - 编译器生成方法(如 __before_init__/__init__)恒返回 void, - _translate_method_call 处理后返回 None(无返回值)——若不标记, - translate_call 会误判"未命中"继续走跨模块函数路径(把对象名 - 当模块名查 SHA1 → "跨模块调用 'buf.__before_init__' 找不到模块 SHA1")。 - """ - # 检测类名静态/类方法调用: ClassName.method(args) - # 当 cl.func 是 Attribute、value 是已注册结构体类名(非普通变量)时, - # 且方法带 @staticmethod/@classmethod 元数据,走静态调用路径 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - st_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if st_at is not None and st_at.value is not None and trans is not None: - if st_at.value.kind() == ast.ASTKind.Name: - st_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(st_at.value) - if st_nm.id is not None: - # 仅当该名称不是普通变量且是已注册结构体类名时尝试静态/类方法 - # 追加"非导入模块"条件:st_nm.id 是模块名(import X as Y 把别名 - # Y 加入 _imported_modules,HandlesImports L344-347)时,X.Y(...) - # 是模块限定调用(Module.Class 构造 / Module.func 函数),不是 - # ClassName.method(obj,args)。模块名与类名同名时(CompilerFactory. - # CompilerFactory(...) 构造 / .set_factory(...) 函数,main.vp - # 追加84/84b 根因)get_struct_type(st_nm.id) 会误判为类名 → - # 把首实参当 self 传 _call_method_on_ptr → 返回类型查 "X.Y" 永远 - # 落空 → fail-fast。模块限定调用由尾部 ctor 检测(L7441 模块限定 - # 构造)与跨模块函数路径正确路由。 - st_var: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( - trans.SymTab, st_nm.id) - if st_var is None and self.Gen.StructGen.get_struct_type(st_nm.id) is not None \ - and self.Gen.ImportsGen.is_module_imported( - trans._imported_modules, st_nm.id) == 0: - # REnum 变体构造优先于静态/类方法调用: - # ClassName.VariantName(args)(如 Option.Some(42))若被当 - # "实例方法经类名调用"处理,会把首实参 42 当 self 传 - # _call_method_on_ptr → 查 "Option.Some" 方法返回类型 → - # 跨模块 stub 未命中 → fail-fast(EnumTest "方法 - # 'Option.Some' 返回类型无法确定" 根因)。REnum 变体 - # 构造检测原在 translate_call 尾部(L7493),被本分支 - # 拦截先执行不到,此处提前检测。 - if self.Gen.ClassGenEnum._is_renum_class_name(st_nm.id) != 0: - rc_tag_sc: int = self.Gen.ClassGenEnum._lookup_renum_variant_in_class( - st_nm.id, func_name) - if rc_tag_sc >= 0: - return self.Gen.CallGenCtor._translate_renum_construct( - pool, builder, mod, st_nm.id, func_name, - rc_tag_sc, cargs, can, trans) - st_res: llvmlite.Value | t.CPtr = self.Gen.CallGenProp._translate_static_class_call( - pool, builder, mod, st_nm.id, func_name, cl, trans) - if st_res is not None: - return st_res - # 实例方法经类名调用: ClassName.method(obj, args) → obj.method(args) - # (Python 语义,首参是 self 对象;zdeflate.vp - # zdeflate_stream.find_match(s, data, ...) 根因:_translate_ - # static_class_call 对非静态方法返回 None 后,ClassName 被 - # 通用路径当模块名 → "跨模块调用找不到模块 SHA1") - # st_nm.id == func_name(类名==方法名,如 CompilerFactory. - # CompilerFactory(...))不是实例方法调用而是构造调用: - # 模块名与类名同名时本分支把模块限定类构造误判为 - # ClassName.method(obj,args),首实参当 self 传 → - # _call_method_on_ptr 查 "X.X" 返回类型永远落空 → - # fail-fast(main.vp CompilerFactory 追加84 根因)。 - # 跳过本分支,落到 translate_call 尾部的 ctor 检测 - # (L7426 模块限定类构造 find_struct_by_module 正确路由)。 - if can >= 1 and cargs is not None \ - and string.strcmp(st_nm.id, func_name) != 0: - im_self: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, cargs.get(0), None, 0, trans) - if im_self is not None: - im_rem: t.CSizeT | t.CPtr = None - if can >= 2: - im_rem = pool.alloc(t.CSizeT(can - 1) * 8) - if im_rem is not None: - ri_im: t.CSizeT - for ri_im in range(can - 1): - im_rv: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, cargs.get(ri_im + 1), None, 0, trans) - if im_rv is not None: - im_rem[ri_im] = t.CSizeT(im_rv) - im_res: llvmlite.Value | t.CPtr = self.Gen.CallGenCall._call_method_on_ptr( - pool, builder, mod, st_nm.id, func_name, - im_self, im_rem, can - 1, trans) - if im_res is not None: - return im_res - elif st_at.value.kind() == ast.ASTKind.Attribute: - # 模块限定静态调用: module.ClassName.static_method(args) - # cl.func = Attribute(value=Attribute(value=Name(module), - # attr=ClassName), attr=method_name) - # 此前未检测 → 走通用路径把 method_name 当裸函数解析, - # 生成 call i32 @from_long(无类名/SHA1 前缀)→ 链接 - # undefined reference(CPythonTest PyLongObj.from_long 根因) - st_at2: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(st_at.value) - if st_at2 is not None and st_at2.attr is not None and st_at2.value is not None: - if st_at2.value.kind() == ast.ASTKind.Name: - # ClassName 是已注册结构体类名时尝试静态/类方法 - if self.Gen.StructGen.get_struct_type(st_at2.attr) is not None: - st_res2: llvmlite.Value | t.CPtr = self.Gen.CallGenProp._translate_static_class_call( - pool, builder, mod, st_at2.attr, func_name, cl, trans) - if st_res2 is not None: - return st_res2 - - # 检测方法调用: obj.method(args) - # 当 cl.func 是 Attribute 且 obj 是已注册的结构体变量时,翻译为方法调用 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if method_at is not None and method_at.value is not None: - if method_at.value.kind() == ast.ASTKind.Name and trans is not None: - method_obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(method_at.value) - if method_obj_nm.id is not None: - # 查找对象变量 - obj_var: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( - trans.SymTab, method_obj_nm.id) - if obj_var is not None and obj_var.Ty is not None: - # 检查是否为 Ptr(Struct(...))(结构体值变量) - # 或 Ptr(Ptr(Struct(...)))(指针变量,需 load) - match obj_var.Ty: - case llvmlite.LLVMType.Ptr(obj_struct_ty): - class_nm: str = self.Gen.StructGen.get_class_name_by_type( - pool, obj_struct_ty) - if class_nm is not None: - # list 泛型内置容器方法(append/get/set/pop/clear/__iter__/ - # __len__/__getitem__/__setitem__)由下方 list 内置分支 - # (L5848 起)内联 GEP 处理,不注册方法函数;若走 - # _translate_method_call 会查 append 返回类型(函数/text.ll/ - # vpi stub 均未命中)→ fail-fast。检测到 list 方法时 - # 跳过 method_call,落到内置分支(NewAstTest body.append 根因)。 - if self.Gen.CallGenProp._is_list_builtin_method(class_nm, func_name) == 0: - if hit_box is not None: - hit_box[0] = 1 - return self.Gen.CallGenCall._translate_method_call( - pool, builder, mod, class_nm, func_name, - obj_var, cl, trans) - # 指针变量: alloca 类型是 Ptr(Ptr(Struct)) - # load 获取实际指针 Ptr(Struct) 后再查找 - match obj_struct_ty: - case llvmlite.LLVMType.Ptr(inner_struct_ty): - inner_nm: str = self.Gen.StructGen.get_class_name_by_type( - pool, inner_struct_ty) - if inner_nm is not None: - # list 内置方法同样跳过(同 Ptr(Struct) 分支) - if self.Gen.CallGenProp._is_list_builtin_method(inner_nm, func_name) == 0: - obj_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, obj_struct_ty, obj_var) - if obj_ptr is not None: - if hit_box is not None: - hit_box[0] = 1 - return self.Gen.CallGenCall._translate_method_call( - pool, builder, mod, inner_nm, func_name, - obj_ptr, cl, trans) - # FakeDuck: str/bytes 变量(Ptr(i8),AnnotClassName 为空) - # 方法调用 → 扩展类 _Type/_str(a.type_id() / a.upper())。 - # 前置拦截:常规结构体方法分支全落空时,尝试扩展类方法 - # (find_func_in_module 未命中返回 None,不影响正常路径)。 - fd_name_res: llvmlite.Value | t.CPtr = self.Gen.CallGenFd._translate_fakeduck_call( - pool, builder, mod, None, func_name, cl, trans) - if fd_name_res is not None: - return fd_name_res - # AnnotClassName 回退:联合类型简化为 Ptr(i8) 时, - # 通过原始类型注解的类名查找结构体 - var_entry: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( - trans.SymTab, method_obj_nm.id) - if var_entry is not None and var_entry.AnnotClassName is not None: - annot_val: str = var_entry.AnnotClassName - # 解析模块限定名 "memhub.MemBuddy" → mod_nm="memhub", cls_nm="MemBuddy" - dot_ptr: str = string.strrchr(annot_val, '.') - cls_nm2: str = annot_val - mod_nm2: str = None - if dot_ptr is not None: - cls_nm2 = dot_ptr + 1 - total_len_av: t.CSizeT = string.strlen(annot_val) - cls_len_av: t.CSizeT = string.strlen(cls_nm2) - mod_len2: t.CSizeT = total_len_av - cls_len_av - 1 - mod_nm2 = pool.alloc(mod_len2 + 1) - if mod_nm2 is not None: - string.strncpy(mod_nm2, annot_val, mod_len2) - mod_nm2[mod_len2] = '\0' - # 检查结构体是否已注册 - if self.Gen.StructGen.get_struct_type(cls_nm2) is not None: - # list 内置方法跳过 method_call(同 Ptr(Struct) 分支), - # 落到下方 list 内置分支 - if self.Gen.CallGenProp._is_list_builtin_method(cls_nm2, func_name) == 0: - # 结构体已注册:load obj_ptr 走方法调用 - i8_ptr_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - obj_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i8_ptr_ty2, obj_var) - if obj_ptr2 is not None: - if hit_box is not None: - hit_box[0] = 1 - return self.Gen.CallGenCall._translate_method_call( - pool, builder, mod, cls_nm2, func_name, - obj_ptr2, cl, trans) - else: - # list 内置方法跳过(结构体未注册路径同样不能 - # 构造 {sha1}.{cls}.append 调用名——list 方法无此函数) - if self.Gen.CallGenProp._is_list_builtin_method(cls_nm2, func_name) == 0: - # FakeDuck: str 变量方法调用 → 扩展类 _Type/_str - # a.type_id() / a.upper() / " ".isspace() 等 - # AnnotClassName=="str" 且对象是 char* 时触发, - # self 用影子结构体 {a}__meta__(或临时影子)。 - fd_res: llvmlite.Value | t.CPtr = self.Gen.CallGenFd._translate_fakeduck_call( - pool, builder, mod, cls_nm2, func_name, cl, trans) - if fd_res is not None: - return fd_res - # 结构体未注册(跨模块依赖未翻译): - # 用模块名查 SHA1 构造方法调用名 - sha1_fc: str = None - if mod_nm2 is not None: - sha1_fc = self._lookup_module_sha1(mod_nm2) - if sha1_fc is not None: - # 构造 "{sha1}.{cls_nm2}.{func_name}" 调用名 - mlen3: t.CSizeT = string.strlen(sha1_fc) + string.strlen(cls_nm2) + string.strlen(func_name) + 3 - mangled3: str = pool.alloc(mlen3) - if mangled3 is not None: - viperlib.snprintf(mangled3, mlen3, "%s.%s.%s", sha1_fc, cls_nm2, func_name) - # load obj_ptr (self) - i8_ptr_ty3: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - obj_ptr3: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i8_ptr_ty3, obj_var) - if obj_ptr3 is not None: - # 构建参数链表: obj_ptr3 (self) → 其他参数 - llvmlite.value_set_next(obj_ptr3, None) - head3: llvmlite.Value | t.CPtr = obj_ptr3 - tail3: llvmlite.Value | t.CPtr = obj_ptr3 - for ai3 in range(can): - arg3: ast.AST | t.CPtr = cargs.get(ai3) - if arg3 is not None: - arg_val3: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, arg3, None, 0, trans) - if arg_val3 is not None: - llvmlite.value_set_next(arg_val3, None) - llvmlite.value_set_next(tail3, arg_val3) - tail3 = arg_val3 - total3: int = 1 + can - ret_ty3: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty( - pool, cls_nm2, func_name) - if ret_ty3 is None: - ret_ty3 = self._LookupMethodRetTyFromTextLL( - pool, sha1_fc, cls_nm2, func_name) - if ret_ty3 is None: - # 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单) - ret_ty3 = self._lookup_method_ret_ty_via_vpi( - pool, sha1_fc, cls_nm2, func_name) - if ret_ty3 is None: - # 本分支仅在"注解类结构体未注册"时到达(L6932 else): - # 类未注册 → 无法沿 MRO 解析 Mixin 方法定义模块。 - # 例如 g 注解 Generator.Generator,但 _register_cdefine_from_value - # 定义在 AssignGenMixin.vp——其 text.ll 的 define 名是 - # {AssignGenMixin_sha1}.AssignGenMixin.xxx,查 - # {Generator_sha1}.Generator.xxx 永远落空(追加80d 根因; - # sha1_fc 存在 + text.ll 存在仍查不到,固定 256KB 截断 - # 只是次要因素)。必须标记 pending:等 Generator 注册后 - # 下遍走 L6919 已注册分支 → _translate_method_call 沿 - # MRO 链找到 AssignGenMixin → 精确解析。真正不存在的 - # 类/方法由 Phase A 收敛检查兜底,绝不在此 fail-fast - # 中断多遍收敛(对齐追加77/77b 类 defer 原则)。 - if trans is not None: - trans._deps_pending = 1 - # 依赖未就绪:保持默认 i32(build_call(Void) - # 返回 None 破坏表达式翻译;本遍不写盘) - ret_ty3 = llvmlite.Int32(pool) - self._ensure_method_declare(pool, mod, mangled3, ret_ty3, head3, total3) - return llvmlite.build_call(builder, mangled3, head3, total3, ret_ty3, 0) - else: - # 编译器生成特殊方法放行(__before_init__/__init__ 等): - # 结构体未注册 + 模块 SHA1 均不可查(Phase A 依赖未就绪)时, - # 方法返回类型由编译器确定性定义(_special_method_ret_ty), - # 不依赖结构体注册即可精确解析。走 _translate_method_call 处理 - # (内部含 _special_method_ret_ty + mc_entry/类型名 SHA1 提取), - # 绝不掉出返回 None 让 translate_call 把对象名当模块名 - # 报"跨模块调用 'buf.__before_init__' 找不到模块 SHA1" - # (memhub.alloc_buf buf.__before_init__() 根因)。 - sp_ty4: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty( - pool, cls_nm2, func_name) - if sp_ty4 is not None: - i8_ptr_ty4: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - obj_ptr4: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i8_ptr_ty4, obj_var) - if obj_ptr4 is not None: - if trans is not None: - trans._deps_pending = 1 - if hit_box is not None: - hit_box[0] = 1 - return self.Gen.CallGenCall._translate_method_call( - pool, builder, mod, cls_nm2, func_name, - obj_ptr4, cl, trans) - - # ============================================================ - # 检测表达式接收者方法调用: (expr).method(args) - # - # 当 method_at.value 是 BinOp/Subscript/Call 等非 Name/Attribute 表达式时 - # (如 (a + b).dot(c)、(v1 + v2) * 3.0),先 translate_value 求值接收者, - # 再从值的 LLVM 类型(Ptr(Struct))解析类名,走方法调用路径。 - # ============================================================ - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - expr_method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if expr_method_at is not None and expr_method_at.value is not None and trans is not None: - evk: int = expr_method_at.value.kind() - # Attribute 接收者区分两种形态: - # 1. 模块限定路径(os._win32.exists / w32.fileio.fn)——根名是已导入 - # 模块或 t/c,留给下方跨模块限定路径处理 - # 2. 字段链表达式接收者(self.writer.write_bits / self.pool.alloc) - # ——根名是对象(self/局部变量),必须走本方法调用路径; - # 否则被模块限定路径误判 xmod_path="self.writer" → "找不到模块 - # SHA1"(zdeflate.vp write_fixed_block 根因) - is_mod_path_expr: int = 0 - if evk == ast.ASTKind.Attribute: - expr_root: ast.AST | t.CPtr = expr_method_at.value - while expr_root is not None and expr_root.kind() == ast.ASTKind.Attribute: - expr_root = (ast.Attribute | t.CPtr)(expr_root).value - if expr_root is not None and expr_root.kind() == ast.ASTKind.Name: - expr_root_nm: str = (ast.Name | t.CPtr)(expr_root).id - if expr_root_nm is not None: - if string.strcmp(expr_root_nm, "t") == 0 or \ - string.strcmp(expr_root_nm, "c") == 0: - is_mod_path_expr = 1 - elif trans._imported_modules is not None: - if self.Gen.ImportsGen.is_module_imported( - trans._imported_modules, expr_root_nm) != 0: - is_mod_path_expr = 1 - if evk != ast.ASTKind.Name and is_mod_path_expr == 0: - # 翻译接收者表达式(求值结果应为 Ptr(Struct)) - expr_obj: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, expr_method_at.value, funcs_ptr, func_count, trans) - if expr_obj is not None and expr_obj.Ty is not None: - expr_cls_nm: str = None - # 递归解 Ptr:识别 X|t.CPtr 联合简化的 Ptr(Ptr(Struct)) - # (如 (a*2.0 - b) 中 __mul__ 返回 Vec3**),否则方法 - # 调用被当裸函数 @dot 解析 → 链接 undefined symbol - expr_struct_ty: llvmlite.LLVMType | t.CPtr = \ - self.Gen.StructGen.get_struct_type_from_value(expr_obj) - if expr_struct_ty is not None: - expr_cls_nm = self.Gen.StructGen.get_class_name_by_type( - pool, expr_struct_ty) - # 回退:LLVM 类型为 Ptr(i8)(方法返回 X|t.CPtr 无类型信息)时, - # 从接收者表达式结构推断类名(链式调用 c2.scale(2.0).move(...) - # 的 scale 返回 Ptr(i8),经 infer_expr_class → vpi 返回注解) - # 跨 Mixin 不能 self 调用 ExprGenMixin 方法,经全局单例 - if expr_cls_nm is None: - expr_cls_nm = self.Gen.ExprGenCls.infer_expr_class( - pool, mod, expr_method_at.value, trans) - if expr_cls_nm is not None: - # 值类型接收者(内嵌 struct 字段,如 zdeflate s.writer 值字段): - # 方法调用 self 必须传字段地址(GEP)而非 load 出的结构体值, - # 否则结构体值(40B)塞进 zbit_writer* 参数 → ABI 错配 → - # 被调方把值当 this 指针解引用 → GEP 0x18 崩溃 - # (s.writer.write_zlib_header 运行时 access-violation 根因; - # 本路径 evk=Attribute 先于 self.field.method() 分支命中)。 - expr_is_ptr: int = 0 - match expr_obj.Ty: - case llvmlite.LLVMType.Ptr(expr_ptr_inner): - expr_is_ptr = 1 - case _: - expr_is_ptr = 0 - if expr_is_ptr == 0: - expr_addr: llvmlite.Value | t.CPtr = self.Gen.ExprGenAttr.get_attribute_ptr( - builder, pool, mod, expr_method_at.value, trans) - if expr_addr is not None: - expr_obj = expr_addr - if hit_box is not None: - hit_box[0] = 1 - return self.Gen.CallGenCall._translate_method_call( - pool, builder, mod, expr_cls_nm, func_name, - expr_obj, cl, trans) - # FakeDuck: 表达式接收者解析失败且对象是 char* 时 - # (如 " ".isspace()),尝试扩展类 _Type/_str 方法 - # (self 用临时影子,对齐 TPC L2858-2873) - fd_expr_res: llvmlite.Value | t.CPtr = self.Gen.CallGenFd._translate_fakeduck_call( - pool, builder, mod, None, func_name, cl, trans) - if fd_expr_res is not None: - return fd_expr_res - - # ============================================================ - # 检测 self.field.method() 调用 - # - # 当 method_at.value 是 Attribute(字段访问,如 self.__pool__)时, - # 翻译字段值获取对象指针,然后走方法调用路径。 - # - # 路径1: 从字段值的 LLVM 类型获取类名(字段类型为 Ptr(Struct("MemManager"))) - # 路径2: 从字段的 AnnotClassName 回退查找(字段类型被简化为 Ptr(i8) 时) - # ============================================================ - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - attr_method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if attr_method_at is not None and attr_method_at.value is not None: - if attr_method_at.value.kind() == ast.ASTKind.Attribute and trans is not None: - inner_attr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(attr_method_at.value) - if inner_attr is not None and inner_attr.attr is not None: - # 翻译 self.__pool__ 获取字段值(已 load 的对象指针) - field_obj: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, attr_method_at.value, funcs_ptr, func_count, trans) - if field_obj is not None and field_obj.Ty is not None: - field_cls_nm: str = None - # 路径1: 从字段值的 LLVM 类型获取类名 - match field_obj.Ty: - case llvmlite.LLVMType.Ptr(field_struct_ty): - field_cls_nm = self.Gen.StructGen.get_class_name_by_type( - pool, field_struct_ty) - # 路径2: 从字段注解类名回退查找 - if field_cls_nm is None: - if inner_attr.value is not None and inner_attr.value.kind() == ast.ASTKind.Name: - inner_name_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner_attr.value) - if inner_name_node is not None and inner_name_node.id is not None: - inner_var: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( - trans.SymTab, inner_name_node.id) - if inner_var is not None and inner_var.Ty is not None: - match inner_var.Ty: - case llvmlite.LLVMType.Ptr(field_owner_struct_ty): - field_info: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field( - field_owner_struct_ty, inner_attr.attr) - if field_info is not None: - field_annot: str = self.Gen.StructGen.get_field_annot_class_name(field_info) - if field_annot is not None: - dot_p: str = string.strrchr(field_annot, 46) - if dot_p is not None: - field_cls_nm = dot_p + 1 - else: - field_cls_nm = field_annot - if field_cls_nm is not None: - # 值类型字段(内嵌 struct,如 zdeflate_stream.writer: zbit_writer) - # 方法调用 self 必须传字段地址(GEP),而非 load 出的结构体值: - # 传值给 stub 声明/define 的 zbit_writer* 参数 → ABI 错配, - # 被调方把结构体值前 8 字节当 this 指针解引用 → GEP 0x18 崩溃 - # (zdeflate s.writer.write_zlib_header 运行时 access-violation 根因)。 - is_val_field: int = 0 - match field_obj.Ty: - case llvmlite.LLVMType.Ptr(field_ptr_inner): - is_val_field = 0 - case _: - is_val_field = 1 - if is_val_field != 0: - field_addr: llvmlite.Value | t.CPtr = self.Gen.ExprGenAttr.get_attribute_ptr( - builder, pool, mod, attr_method_at.value, trans) - if field_addr is not None: - field_obj = field_addr - if hit_box is not None: - hit_box[0] = 1 - return self.Gen.CallGenCall._translate_method_call( - pool, builder, mod, field_cls_nm, func_name, - field_obj, cl, trans) - - # ============================================================ - # 检测 list 内置方法调用: lst.get(i), lst.set(i,v), lst.pop(), lst.clear(), lst.__iter__() - # list[T] 是泛型类不注册 struct,方法调用处理器(上方)无法处理, - # 需要在此特殊处理。 - # list 结构布局 (6 字段 × 8 字节): - # __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40) - # ============================================================ - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - lm_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if lm_at is not None and lm_at.attr is not None and lm_at.value is not None: - lm_name: str = lm_at.attr - # 判断是否是 list 方法名 - lm_is_list: int = 0 - if string.strcmp(lm_name, "get") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "__getitem__") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "set") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "__setitem__") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "pop") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "clear") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "__iter__") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "append") == 0: lm_is_list = 1 - - if lm_is_list == 1 and trans is not None: - # 翻译 list 对象 - lm_obj: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, lm_at.value, funcs_ptr, func_count, trans) - if lm_obj is not None: - # 防御性类型检查: lm_obj 必须是指针类型才能做 GEP - # translate_value 对某些 Attribute 节点(如 ast.Arguments 的属性) - # 可能返回 i32 0 (非指针),直接 GEP 会导致 - # "base of getelementptr must be a pointer" 错误 - if lm_obj.Ty is None or self.Gen.ExprGenBase.is_ptr_type(lm_obj.Ty) == 0: - # translate_value 类型推断失败(目标对象非指针): - # fail-fast,绝不 VLogger.critical 后 return None 静默吞掉 - self.Gen.TypeGenErr.fatal_error( - lm_at.value, f"list 方法 '{lm_name}' 目标对象非指针", "TypeError") - # list 对象类型确认(额外搜索路径):list 内置分支仅按方法名 - # 判断(get/set/__getitem__ 等非 list 专有),须确认对象确实 - # 是 list——从对象结构体名匹配 "list"。明确非 list(如 dict / - # 普通类未注册场景)跳过本分支,避免按 list 布局 GEP 生成 - # 错误 IR(dict 的 get 被当 list.get 按 __data__/__elem_size__ - # 偏移读写垃圾)。 - lm_conf_ty: llvmlite.LLVMType | t.CPtr = \ - self.Gen.StructGen.get_struct_type_from_value(lm_obj) - lm_conf_nm: str = None - if lm_conf_ty is not None: - lm_conf_nm = llvmlite.get_struct_name(lm_conf_ty) - if lm_conf_nm is not None and \ - string.strstr(lm_conf_nm, "list") is None: - return None - # list 内置分支命中标记:void 方法(set/clear)成功处理后返回 - # None,必须置位 hit_box 区分"已识别为 list 方法路径",否则 - # translate_call 误判未命中继续走跨模块函数路径,把对象名当 - # 模块名查 SHA1 → "跨模块调用 'nums.set' 找不到模块 SHA1" - # (ListTest main.vp nums.set(1,99) 根因;对齐 _translate_method_call - # 调用点的 hit_box 置位模式)。 - if hit_box is not None: - hit_box[0] = 1 - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - # 元素类型 T:从 list 特化类型名解析(list[int]→i32、 - # list[str]→i8*、未知/指针元素→i8*)。此前 get/set/pop - # 固定 i8*(8 字节)读写:set 的 8 字节 store 覆盖相邻元素 - # (inttoptr 值,如 set(1,99) 把 data[8..11] 的 30 清 0), - # pop 读回 0 → ListTest "pop FAILED expect 30" 根因。 - # subscript 路径(list_getitem_inline 调用方)已用 - # _list_elem_type_from_name 修正,方法调用路径漏改。 - lm_esty: llvmlite.LLVMType | t.CPtr = \ - self.Gen.StructGen.get_struct_type_from_value(lm_obj) - lm_ename: str = None - if lm_esty is not None: - lm_ename = llvmlite.get_struct_name(lm_esty) - lm_elem_ty: llvmlite.LLVMType | t.CPtr = None - if lm_ename is not None: - lm_elem_ty = self.Gen.ExprGenName._list_elem_type_from_name( - pool, lm_ename) - if lm_elem_ty is None: - lm_elem_ty = i8_ptr_ty - - # get / __getitem__: 返回 index 处的元素 - if string.strcmp(lm_name, "get") == 0 or string.strcmp(lm_name, "__getitem__") == 0: - if can >= 1: - # 加载 __data__ (偏移 0) - g_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) - g_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0) - g_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, g_dpp) - # 加载 __elem_size__ (偏移 32, index 4) - g_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) - g_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4) - g_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, g_epp) - # 翻译 index - g_idx_node: ast.AST | t.CPtr = cargs.get(0) - g_idx_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, g_idx_node, None, 0, trans) - if g_data is not None and g_esize is not None and g_idx_val is not None: - g_idx_i64: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type( - builder, g_idx_val, i64_ty, g_idx_node) - g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize) - g_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, g_data, g_offset) - if g_addr is not None: - g_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, g_addr, llvmlite.Ptr(pool, lm_elem_ty)) - if g_ep is not None: - return llvmlite.build_load(builder, lm_elem_ty, g_ep) - - # set / __setitem__: 设置 index 处的元素 - elif string.strcmp(lm_name, "set") == 0 or string.strcmp(lm_name, "__setitem__") == 0: - if can >= 2: - s_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) - s_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0) - s_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, s_dpp) - s_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) - s_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4) - s_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, s_epp) - s_idx_node: ast.AST | t.CPtr = cargs.get(0) - s_val_node: ast.AST | t.CPtr = cargs.get(1) - s_idx_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, s_idx_node, None, 0, trans) - s_val_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, s_val_node, None, 0, trans) - if s_data is not None and s_esize is not None and s_idx_val is not None and s_val_val is not None: - s_idx_i64: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type( - builder, s_idx_val, i64_ty, s_idx_node) - s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize) - s_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s_data, s_offset) - if s_addr is not None: - s_val_elem: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type( - builder, s_val_val, lm_elem_ty, s_val_node) - s_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, s_addr, llvmlite.Ptr(pool, lm_elem_ty)) - if s_ep is not None: - llvmlite.build_store(builder, s_val_elem, s_ep) - return None - - # pop: 返回最后一个元素,count-- - elif string.strcmp(lm_name, "pop") == 0: - p_idx1: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) - p_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx1) - p_count: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_cpp) - p_nc: llvmlite.Value | t.CPtr = llvmlite.build_sub( - builder, p_count, llvmlite.const_int64(pool, 1)) - llvmlite.build_store(builder, p_nc, p_cpp) - p_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) - p_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx0) - p_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, p_dpp) - p_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) - p_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx4) - p_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_epp) - if p_data is not None and p_esize is not None and p_nc is not None: - p_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, p_nc, p_esize) - p_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, p_data, p_offset) - if p_addr is not None: - p_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, p_addr, llvmlite.Ptr(pool, lm_elem_ty)) - if p_ep is not None: - return llvmlite.build_load(builder, lm_elem_ty, p_ep) - - # clear: count = 0 - elif string.strcmp(lm_name, "clear") == 0: - c_idx1: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) - c_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, c_idx1) - llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), c_cpp) - return None - - # __iter__: iter_index = 0, return self - elif string.strcmp(lm_name, "__iter__") == 0: - it_idx5: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 5) - it_ipp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, it_idx5) - llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), it_ipp) - return lm_obj - - # append: 直接调用 list.append(self, item) - # append 需要容量检查和内存重分配,逻辑复杂,直接调用 _list.py 中的实现 - elif string.strcmp(lm_name, "append") == 0: - if can >= 1: - ap_sha1: str = self._lookup_module_sha1("_list") - if ap_sha1 is None: - # 依赖模块未编译(_list 未预加入编译链):fail-fast, - # 绝不静默跳过 append(元素永远不会被加入列表) - self.Gen.TypeGenErr.fatal_error( - cl, "list.append: 找不到 _list 模块 SHA1(依赖模块未编译)", - "InternalCompilerError") - if ap_sha1 is not None: - # 特化类名提取:list.append 的符号名是 - # {sha1}.list[AST|CPtr].append(带类型参数特化名), - # 而非 {sha1}.list.append。lm_obj 类型即特化结构体 - # Ptr(list[AST|CPtr]),从类型解析特化类名拼接调用名, - # 否则 ld.lld undefined symbol(定义端是特化名)。 - ap_spec_nm: str = None - ap_struct_ty: llvmlite.LLVMType | t.CPtr = \ - self.Gen.StructGen.get_struct_type_from_value(lm_obj) - if ap_struct_ty is not None: - ap_spec_nm = self.Gen.StructGen.get_class_name_by_type( - pool, ap_struct_ty) - if ap_spec_nm is None: - ap_spec_nm = "list" - # 触发泛型特化翻译(幂等,MethodsEmitted 防重入): - # list[AST|CPtr].append 的 define 方法体在特化类翻译时 - # 生成。仅构造调用名不触发特化会导致定义缺失 - # (ld.lld undefined symbol: list[AST|CPtr].append)。 - if trans is not None and ap_spec_nm is not None: - lbkt_ap: str = string.strchr(ap_spec_nm, '[') - if lbkt_ap is not None: - rbkt_ap: str = string.strrchr(ap_spec_nm, ']') - if rbkt_ap is not None and rbkt_ap > lbkt_ap: - base_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(lbkt_ap) - t.CUInt64T(ap_spec_nm)) - arg_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(rbkt_ap) - t.CUInt64T(lbkt_ap) - 1) - if base_len_ap > 0 and arg_len_ap > 0: - base_buf_ap: str = pool.alloc(base_len_ap + 1) - arg_buf_ap: str = pool.alloc(arg_len_ap + 1) - if base_buf_ap is not None and arg_buf_ap is not None: - string.strncpy(base_buf_ap, ap_spec_nm, base_len_ap) - base_buf_ap[base_len_ap] = '\0' - string.strncpy(arg_buf_ap, lbkt_ap + 1, arg_len_ap) - arg_buf_ap[arg_len_ap] = '\0' - args_ap: list[str] | t.CPtr = list[str](pool, 8) - if args_ap is not None: - # 逗号分隔多类型实参(list[X] / dict[K, V]) - cur_ap: str = arg_buf_ap - while cur_ap is not None: - comma_ap: str = string.strchr(cur_ap, ',') - if comma_ap is None: - args_ap.append(cur_ap) - break - seg_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(comma_ap) - t.CUInt64T(cur_ap)) - seg_buf_ap: str = pool.alloc(seg_len_ap + 1) - if seg_buf_ap is not None: - string.strncpy(seg_buf_ap, cur_ap, seg_len_ap) - seg_buf_ap[seg_len_ap] = '\0' - args_ap.append(seg_buf_ap) - cur_ap = comma_ap + 1 - self.Gen.ClassGenGeneric._specialize_generic_class( - trans, base_buf_ap, args_ap) - # 调用名 "{sha1}.{spec}.append": - # sha1(16) + '.'(1) + spec + '.append'(7) + NUL(1) = spec + 25。 - # 此前 +8 少 1 字节,snprintf 截断末尾 'd' → - # undefined symbol: ...list[AST|CPtr].appen(缺 d)。 - ap_mlen: t.CSizeT = string.strlen(ap_sha1) + \ - string.strlen(ap_spec_nm) + 26 - ap_mangled: str = pool.alloc(ap_mlen) - if ap_mangled is not None: - viperlib.snprintf(ap_mangled, ap_mlen, "%s.%s.append", - ap_sha1, ap_spec_nm) - ap_item_node: ast.AST | t.CPtr = cargs.get(0) - ap_item_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, ap_item_node, None, 0, trans) - if ap_item_val is not None: - llvmlite.value_set_next(lm_obj, None) - llvmlite.value_set_next(ap_item_val, None) - llvmlite.value_set_next(lm_obj, ap_item_val) - ap_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - self._ensure_method_declare(pool, mod, ap_mangled, ap_ret_ty, lm_obj, 2) - return llvmlite.build_call(builder, ap_mangled, lm_obj, 2, ap_ret_ty, 0) - +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.Generator as Generator +import lib.core.Gen.ExprGenCls as ExprGenCls +import lib.core.Gen.ExprGenName as ExprGenName +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import sys +import viperlib +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.CallGenBase as CallGenBase + +# ============================================================ +# CallGenDispatch - CallGenMixin 拆分(阶段 C):translate_call 检测段 +# +# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 每个 helper 返回 Value|CPtr,None = 未命中(translate_call 继续)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class CallGenDispatch(CallGenBase.CallGenBase): + """translate_call 前置检测 helper(继承 Base)""" + + def _tc_h1_super_ctraits(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + hit_box: t.CPtr = None) -> llvmlite.Value | t.CPtr: + """super()/ctraits 编译期检测(未命中返回 None) + + hit_box: 命中标志字节([0]=1 表示被本 helper 拦截处理)。 + super().method() 命中后 _translate_super_call 对 void 方法(如 + __init__)经 build_call 返回 None 属预期(void call 无 SSA 值), + 必须用 hit_box 与"未命中"区分,否则 translate_call 会误判继续 + 主路径 → 把内层 Call(super) 当裸名调用报"super 未定义"。 + """ + # super() 语义(2026-08-10):super().method(args) → 静态调用父类方法 + # 形态: Call(func=Attribute(value=Call(func=Name('super')), attr=method)) + # 必须在 Attribute 分派前拦截——否则 value 的 Call(super) 被 translate_value + # 当作普通函数调用报错,且走普通属性调用会命中自身/虚分派而非父类实现。 + if func_name is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + sup_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if sup_at.value is not None and sup_at.value.kind() == ast.ASTKind.Call: + sup_cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(sup_at.value) + if sup_cl.func is not None and sup_cl.func.kind() == ast.ASTKind.Name: + sup_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sup_cl.func) + if sup_nm.id is not None and string.strcmp(sup_nm.id, "super") == 0: + if hit_box is not None: + hit_box[0] = 1 + return self.Gen.CallGenCall._translate_super_call( + pool, builder, mod, cl, func_name, trans) + + # ctraits 宏库编译期谓词:ctraits.isptr(x) 不生成运行时调用, + # 直接按变量存储类型返回编译期常量(CIf 求值失败回退或非 CIf 上下文时兜底, + # 避免生成跨模块调用 ctraits.isptr 触发"模块未注册 SHA1"误导性报错) + if func_name is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + ct_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if ct_at.value is not None and ct_at.value.kind() == ast.ASTKind.Name: + ct_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ct_at.value) + if ct_nm.id is not None and string.strcmp(ct_nm.id, "ctraits") == 0 \ + and string.strcmp(func_name, "isptr") == 0: + ct_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if ct_args is not None and len(ct_args) >= 1: + ct_arg0: ast.AST | t.CPtr = ct_args.get(0) + if ct_arg0 is not None and ct_arg0.kind() == ast.ASTKind.Name: + ct_nm0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ct_arg0) + if ct_nm0.id is not None and trans is not None: + ct_r: int = self.Gen.StmtGenCif._eval_ctraits_isptr(trans.SymTab, ct_nm0.id) + if ct_r > 0: + return llvmlite.const_int32(pool, 1) + return llvmlite.const_int32(pool, 0) + return None + + def _tc_h2_c_special(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + hit_box: t.CPtr = None) -> llvmlite.Value | t.CPtr: + """c.Deref/Asm/LLVMIR 等特殊调用(未命中返回 None) + + hit_box: 命中标记(t.CPtr,[0]=1 表示已识别为 c.* 特殊调用)。 + 仅对 c.Asm/c.LLVMIR 等返回 None(void,无返回值)的调用置位—— + translate_c_asm/translate_c_llvmir 成功处理 void 时返回 None, + 若不加 hit_box 会被 translate_call 误判为"未命中"继续走外部函数路径。 + """ + # 检测 c.Deref / c.DerefAs / c.Addr 等特殊调用(内联 IR,不生成 call) + # 及 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: + target_ty: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.map_t_type(pool, func_name) + if target_ty is not None: + tc_effective_can: t.CSizeT = can + # 双参数形式: t.CInt(val, t.CPtr) → Ptr(target_ty) + # 注意: void* 在 LLVM 中非法,CVoid* 应表示为 i8* + if can == 2: + tc_arg2_node: ast.AST | t.CPtr = cargs.get(1) + tc_arg2_is_cptr: int = 0 + if tc_arg2_node is not None: + # 形式 1: t.CPtr(Attribute 形式) + if tc_arg2_node.kind() == ast.ASTKind.Attribute: + tc_arg2_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(tc_arg2_node) + if tc_arg2_at.attr is not None and string.strcmp(tc_arg2_at.attr, "CPtr") == 0: + if tc_arg2_at.value is not None and tc_arg2_at.value.kind() == ast.ASTKind.Name: + tc_arg2_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_arg2_at.value) + if tc_arg2_nm.id is not None and string.strcmp(tc_arg2_nm.id, "t") == 0: + tc_arg2_is_cptr = 1 + # 形式 2: 裸名 CPtr(from t import CPtr 后直接使用,如 t.CVoid(x, CPtr)) + elif tc_arg2_node.kind() == ast.ASTKind.Name: + tc_arg2_bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_arg2_node) + if tc_arg2_bn.id is not None and string.strcmp(tc_arg2_bn.id, "CPtr") == 0: + tc_arg2_is_cptr = 1 + if tc_arg2_is_cptr != 0: + # CVoid* → i8*(LLVM 中 void* 表示为 i8*) + match target_ty: + case llvmlite.LLVMType.Void(): + target_ty = llvmlite.Int8(pool) + case _: + pass + target_ty = llvmlite.Ptr(pool, target_ty) + tc_effective_can = 1 + if tc_effective_can == 1: + tc_arg_node: ast.AST | t.CPtr = cargs.get(0) + if tc_arg_node is not None: + tc_arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, tc_arg_node, None, 0, trans) + if tc_arg_val is not None: + return self.Gen.CallGenCtor._translate_t_type_cast( + pool, builder, tc_arg_val, target_ty, + func_name, tc_arg_node, trans) + # t.XXX 类型转换已确认但不满足参数条件:返回 None,不跌落到跨模块 FATAL + return None + + # 模块限定 typedef 转换: posix.mode_t(mode), w32.win32base.HANDLE(v) 等 + # func = Attribute(value=Name(模块), attr=typedef名),此前被误当跨模块函数调用 + # → "跨模块函数 'sha1.mode_t' 返回类型无法精确获取"(SysLibTest os/_posix.vp + # L130 posix.mode_t(mode) 根因)。typedef 名做类型转换(与裸名 BYTEPTR(x) + # 对齐);非 typedef 名继续走模块函数调用。 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + mt_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if mt_at.value is not None and mt_at.value.kind() == ast.ASTKind.Name: + mt_mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(mt_at.value) + if mt_mod_nm.id is not None and string.strcmp(mt_mod_nm.id, "t") != 0 \ + and string.strcmp(mt_mod_nm.id, "c") != 0: + mod_td_ty: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.map_t_type( + pool, func_name) + if mod_td_ty is None: + mod_td_str: str = self.Gen.TypeGenCType.lookup_ctypedef(func_name) + if mod_td_str is not None and self.Gen.TypeGenCType.is_ctypedef_found() != 0: + mod_td_ast: ast.AST | t.CPtr = self.Gen.TypeGenResolve._parse_type_string( + pool, mod_td_str, 0) + if mod_td_ast is not None: + mod_imp_td: str = None + mod_fi_td: str = None + if trans is not None: + mod_imp_td = trans._imported_modules + mod_fi_td = trans._from_imports + mod_td_ty = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, mod_td_ast, mod_imp_td, mod_fi_td, trans) + if mod_td_ty is not None and can == 1: + mt_arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) + if mt_arg_val is not None: + return self.Gen.CallGenCtor._translate_t_type_cast( + pool, builder, mt_arg_val, mod_td_ty, + func_name, cargs.get(0), trans) + + # 裸名 typedef 调用: BYTEPTR(ptr1), HANDLE(val), CHARPTR(str) 等 + # 用户通过 `from stdint import *` 导入 typedef 后,可直接用裸名做类型转换 + # map_t_type 包含所有内置 typedef 名称(BYTEPTR/HANDLE/LPCSTR/size_t 等) + # 泛型类型参数转换: 泛型上下文(类特化/泛型函数)中 T(x) → 先解析 T 为具体 + # 类型名(如 "int")再走 map_t_type(Box[int].__init__ 的 self.value = T(v)、 + # combine[T1,T2] 的 T1(b) 依赖此路径) + if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: + bare_fn_name: str = self.Gen.TypeGenBase.resolve_generic_type_name(func_name) + bare_ty: llvmlite.LLVMType | t.CPtr = None + # 泛型上下文解析出的内建名(如 T→"double"/"float"):map_t_type 只认 t.CDouble, + # 且 float 必须映射 t.CFloat(f32)而非 f64(与注解语义一致) + if string.strcmp(bare_fn_name, "double") == 0: + bare_ty = llvmlite.Double(pool) + elif string.strcmp(bare_fn_name, "float") == 0: + bare_ty = llvmlite.Float(pool) + else: + bare_ty = self.Gen.TypeGenResolve.map_t_type(pool, bare_fn_name) + # 泛型上下文替换出的类型名(如 T→"t.CInt")map_t_type 不识别(只认无前缀名), + # 回退用 resolve_annotation_type 解析(支持 t.CXxx / 结构体类名 / 别名等)。 + # GenericTest4 Box[t.CInt].__init__ 的 self.value = T(v) 依赖此路径。 + if bare_ty is None and string.strcmp(bare_fn_name, func_name) != 0: + gp_ast: ast.AST | t.CPtr = self.Gen.TypeGenResolve._parse_type_string(pool, bare_fn_name, 0) + if gp_ast is not None: + imp_gp: str = None + fi_gp: str = None + if trans is not None: + imp_gp = trans._imported_modules + fi_gp = trans._from_imports + bare_ty = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, gp_ast, imp_gp, fi_gp, trans) + # 泛型类型参数双参数形式: T(val, t.CPtr) → Ptr(T) + # (与 t.CInt(val, t.CPtr) → Ptr(i32) 对齐;vector.vp get() 的 + # typed_ptr = T(offset, t.CPtr) 依赖此路径,否则双参数不进 + # can==1 单参数分支 → 跌落到"裸名调用未定义"误报) + if bare_ty is not None and can == 2: + bare_arg2_node: ast.AST | t.CPtr = cargs.get(1) + bare_arg2_is_cptr: int = 0 + if bare_arg2_node is not None: + # 形式 1: t.CPtr(Attribute 形式) + if bare_arg2_node.kind() == ast.ASTKind.Attribute: + bare_arg2_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(bare_arg2_node) + if bare_arg2_at.attr is not None and string.strcmp(bare_arg2_at.attr, "CPtr") == 0: + if bare_arg2_at.value is not None and bare_arg2_at.value.kind() == ast.ASTKind.Name: + bare_arg2_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bare_arg2_at.value) + if bare_arg2_nm.id is not None and string.strcmp(bare_arg2_nm.id, "t") == 0: + bare_arg2_is_cptr = 1 + # 形式 2: 裸名 CPtr(from t import CPtr 后直接使用) + elif bare_arg2_node.kind() == ast.ASTKind.Name: + bare_arg2_bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bare_arg2_node) + if bare_arg2_bn.id is not None and string.strcmp(bare_arg2_bn.id, "CPtr") == 0: + bare_arg2_is_cptr = 1 + if bare_arg2_is_cptr != 0: + # CVoid* → i8*(LLVM 中 void* 表示为 i8*) + match bare_ty: + case llvmlite.LLVMType.Void(): + bare_ty = llvmlite.Int8(pool) + case _: + pass + bare_ty = llvmlite.Ptr(pool, bare_ty) + bare_arg_node: ast.AST | t.CPtr = cargs.get(0) + if bare_arg_node is not None: + bare_arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, bare_arg_node, None, 0, trans) + if bare_arg_val is not None: + return self.Gen.CallGenCtor._translate_t_type_cast( + pool, builder, bare_arg_val, bare_ty, + bare_fn_name, bare_arg_node, trans) + if bare_ty is not None and can == 1: + bare_arg_node: ast.AST | t.CPtr = cargs.get(0) + if bare_arg_node is not None: + bare_arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, bare_arg_node, None, 0, trans) + if bare_arg_val is not None: + return self.Gen.CallGenCtor._translate_t_type_cast( + pool, builder, bare_arg_val, bare_ty, + bare_fn_name, bare_arg_node, trans) + + return None + + def _tc_h5_sizeof_len_isinst(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT) -> llvmlite.Value | t.CPtr: + """__sizeof__/len/isinstance 内置(未命中返回 None)""" + # 检测 ClassName.__sizeof__() — 返回结构体大小常量(i64) + # __sizeof__ 是内置方法,不走跨模块调用路径 + # 支持: Argument.__sizeof__() 和 w32.win32file.WIN32_FIND_DATAA.__sizeof__() + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + sz_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if sz_at.attr is not None and string.strcmp(sz_at.attr, "__sizeof__") == 0: + if sz_at.value is not None and can == 0: + sz_cls_name: str = None + sz_vk: int = sz_at.value.kind() + if sz_vk == ast.ASTKind.Name: + sz_cls_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sz_at.value) + sz_cls_name = sz_cls_nm2.id + elif sz_vk == ast.ASTKind.Attribute: + sz_inner_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sz_at.value) + sz_cls_name = sz_inner_at.attr + # 最终解析出的结构体类型:类型名命中 → 泛型特化(Stack[T])→ 实例接收者类型(self/obj) + sz_resolved_ty: llvmlite.LLVMType | t.CPtr = None + sz_resolved_name: str = sz_cls_name + if sz_cls_name is not None: + # 泛型类型参数 T 替换: T.__sizeof__() → int.__sizeof__() + sz_cls_name = self.Gen.TypeGenBase.resolve_generic_type_name(sz_cls_name) + sz_resolved_name = sz_cls_name + # 去除模块前缀: Viper 解析器将 t.CInt 解析为 Name(id="t.CInt") + # 而非 Attribute(value=Name("t"), attr="CInt"),需要手动提取最后的类名分量 + # "t.CInt" → "CInt", "w32.win32file.WIN32_FIND_DATAA" → "WIN32_FIND_DATAA" + dot_pos: str = string.strrchr(sz_cls_name, '.') + if dot_pos is not None: + sz_cls_name = dot_pos + 1 + # 联合类型(如 AST|t.CPtr)按指针大小处理(8 字节) + # 联合类型在 TPV 中表示指针,可以指向多种类型 + # 对应 TPC 中对 BinOp/BitOr 联合类型的特殊处理 + if string.strstr(sz_cls_name, "|") is not None: + return llvmlite.const_int64(pool, 8) + # 内置类型 sizeof(int=4, str/bytes=8 指针, double=8 等) + sz_builtin: int = -1 + if string.strcmp(sz_cls_name, "int") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "str") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "bytes") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CInt") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "CInt8T") == 0: + sz_builtin = 1 + elif string.strcmp(sz_cls_name, "CInt16T") == 0: + sz_builtin = 2 + elif string.strcmp(sz_cls_name, "CInt32T") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "CInt64T") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CChar") == 0: + sz_builtin = 1 + elif string.strcmp(sz_cls_name, "CDouble") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CFloat") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "CPtr") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CSizeT") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CBool") == 0: + sz_builtin = 1 + elif string.strcmp(sz_cls_name, "bool") == 0: + sz_builtin = 1 + # 泛型 T 解析出的裸内建名(resolve_generic_type_name 返回 + # _infer_generic_ctor_type_arg 的输出,如 T→"double"/"float"): + # 缺省会让 sz_builtin=-1 → 落到"回退 2"把 Name(T) 当值翻译 → + # NameError(VectorGenericTest Vector[double].__init__ 回归根因) + elif string.strcmp(sz_cls_name, "double") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "float") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "char") == 0: + sz_builtin = 1 + if sz_builtin >= 0: + # 注意: 必须用 const_int64 而非 ConstInt(...,"0") + # ConstInt 的 name 参数是 IR 文本表示,ValuePrint 输出时使用 Name 而非 IntVal + # 硬编码 "0" 会导致 IR 输出 i64 0 而非实际值 + return llvmlite.const_int64(pool, sz_builtin) + sz_resolved_ty = self.Gen.StructGen.get_struct_type(sz_cls_name) + # 回退 1: 泛型类引用接收者 Stack[T].__sizeof__() — Subscript → 特化后计算大小 + # (GenericTest2 Stack.type_size 依赖此路径) + if sz_resolved_ty is None and trans is not None and sz_vk == ast.ASTKind.Subscript: + sub_sz: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sz_at.value) + if sub_sz.value is not None and sub_sz.value.kind() == ast.ASTKind.Name: + gen_nm_sz: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_sz.value) + if gen_nm_sz.id is not None: + gen_args_sz: list[str] | t.CPtr = self.Gen.CallGenCtor._extract_type_args_from_slice(pool, sub_sz.slice) + if gen_args_sz is not None and len(gen_args_sz) > 0: + gargs_resolved: list[str] | t.CPtr = list[str](pool, 8) + if gargs_resolved is not None: + gai_sz: t.CSizeT = len(gen_args_sz) + gai2_sz: t.CSizeT = 0 + for gai2_sz in range(gai_sz): + gres_sz: str = self.Gen.TypeGenBase.resolve_generic_type_name( + gen_args_sz.get(gai2_sz)) + gargs_resolved.append(gres_sz) + spec_sz: str = self.Gen.ClassGenGeneric._specialize_generic_class( + trans, gen_nm_sz.id, gargs_resolved) + if spec_sz is not None: + sz_resolved_name = spec_sz + sz_resolved_ty = self.Gen.StructGen.get_struct_type(spec_sz) + # 回退 2: 实例接收者 self.__sizeof__() / obj.__sizeof__() — 用接收者值的实际类型 + # (GenericTest2 Stack.size_of 依赖此路径;self 在方法内是 Ptr(Stack[int])) + # 数组变量接收者 bl_count.__sizeof__()(t.CArray[T, N] 变量)→ alloca + # 指针 Ptr([N x T]),算 N*elem_size(TPC _HandleSizeofLlvm 数组分支; + # zhuff.vp memset(bl_count, 0, bl_count.__sizeof__()) 依赖) + if sz_resolved_ty is None: + inst_sz_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, sz_at.value, None, 0, trans) + if inst_sz_val is not None and inst_sz_val.Ty is not None: + match inst_sz_val.Ty: + case llvmlite.LLVMType.Ptr(inst_inner_sz): + match inst_inner_sz: + case llvmlite.LLVMType.Struct(_, _, _): + sz_resolved_ty = inst_inner_sz + case llvmlite.LLVMType.Array(_, _): + sz_resolved_ty = inst_inner_sz + case _: + pass + case llvmlite.LLVMType.Struct(_, _, _): + sz_resolved_ty = inst_sz_val.Ty + case llvmlite.LLVMType.Array(_, _): + # 全局数组变量(模块级 t.CArray[T,N])translate_value + # 返回数组值 [N x T](非指针);局部数组返回 alloca + # 指针 Ptr([N x T]) 走上方 Ptr(Array) 分支。 + # pyzlib_error_msg.__sizeof__() 依赖(全局字符缓冲)。 + sz_resolved_ty = inst_sz_val.Ty + case _: + pass + if sz_resolved_ty is not None: + sz_val: int = self.Gen.ClassGenEnum._get_type_size(sz_resolved_ty) + if sz_val > 0: + return llvmlite.const_int64(pool, sz_val) + # 类型已注册但大小为 0(opaque struct 或字段链表未填充):Python 风格报错终止 + self.Gen.TypeGenErr.fatal_error( + sz_at, f"类型 '{sz_resolved_name}' 已注册但大小为 0(字段链表未填充),无法计算大小", + "TypeError") + # 类型未注册:Python 风格报错终止,不静默返回 0(会导致 malloc(0)/alloc(0) 堆溢出) + if sz_resolved_name is None: + sz_resolved_name = "(unknown)" + self.Gen.TypeGenErr.fatal_error( + sz_at, f"类型 '{sz_resolved_name}' 未在结构体表中注册,无法计算大小", + "TypeError") + + # 检测 len(obj) — 返回 list 对象的 __count__ 字段(偏移 8,i64) + # __len__ 是 list[T] 的内置方法,list 是泛型类不注册 struct + # 注意: 必须用 translate_value 而非 translate_name_value,因为 len_at.value + # 可能是 Attribute 节点(如 md_ags.args),translate_name_value 只处理 Name 节点, + # 对 Attribute 会错误返回 i32 0,导致 GEP base 不是指针(base of getelementptr must be a pointer) + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + len_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if len_at.attr is not None and string.strcmp(len_at.attr, "__len__") == 0: + if len_at.value is not None and can == 0: + obj_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, len_at.value, funcs_ptr, func_count, trans) + if obj_val is not None and obj_val.Ty is not None: + # 防御性类型检查: obj_val 必须是指针类型才能做 GEP + # 如果 translate_value 返回 i32 (如 CDefine 常量被误解析、 + # 模块属性前向引用回退为 i32),GEP base 会是 i32 而非指针, + # 导致 llc 报错 "base of getelementptr must be a pointer" + if self.Gen.ExprGenBase.is_ptr_type(obj_val.Ty) == 0: + # 类型推断失败(非指针/结构体):fail-fast,绝不返回 0 掩盖错误 + self.Gen.TypeGenErr.fatal_error( + len_at.value, "len() 参数类型推断失败(非指针/结构体)", "TypeError") + i64_ty_len: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + # 注意: 必须用 const_int64 而非 ConstInt(...,"0") + # ConstInt 的 name 参数 "0" 会被当作 IR 文本值输出 i64 0 + # 导致 GEP 索引为 0(访问 __data__)而非 1(访问 __count__) + idx_one: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) + count_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i64_ty_len, obj_val, idx_one) + if count_ptr is not None: + return llvmlite.build_load(builder, i64_ty_len, count_ptr) + + # 检测 len() 内置函数调用 — 结构体对象走 __len__ 方法,字符串走 strlen + # len(s) 对 str 类型调用 strlen,返回 i64 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: + if func_name is not None and string.strcmp(func_name, "len") == 0: + if can == 1: + len_arg_node: ast.AST | t.CPtr = cargs.get(0) + if len_arg_node is not None: + len_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, len_arg_node, None, 0, trans) + if len_val is not None: + # len(数组):t.CArray[T, N] → 常量 N(对齐 TPC + # _HandleLenLlvm 的 ArrayType.count 分支)。数组变量 + # translate_value 可能返回 Ptr([N x T])(alloca 指针) + # 或 [N x T] 值,两种都识别;否则会误走 strlen 把 + # 数组首元素当字符串读 → 垃圾长度。 + len_is_arr: int = 0 + len_arr_n: int = 0 + if len_val.Ty is not None: + if self.Gen.ExprGenBase.is_ptr_type(len_val.Ty) != 0: + len_ap: llvmlite.LLVMType | t.CPtr = len_val.Ty.Pointee + if len_ap is not None: + match len_ap: + case llvmlite.LLVMType.Array(_, len_arr_cnt): + len_is_arr = 1 + len_arr_n = len_arr_cnt + case _: + pass + else: + match len_val.Ty: + case llvmlite.LLVMType.Array(_, len_arr_cnt): + len_is_arr = 1 + len_arr_n = len_arr_cnt + case _: + pass + if len_is_arr != 0: + return llvmlite.const_int64(pool, len_arr_n) + # len(对象):有 __len__ 就调用,没有就编译期报错 + # (用户要求 2026-08-15,不再静默 strlen 读对象首字段): + # - list 泛型内置容器:__len__ 由 list 内置分支内联 + # (读 __count__,偏移 1),不生成方法函数 + # (_is_list_builtin_method,通用判断非特判) + # - 普通类:调用 {Class}.__len__ 函数 + # - 都没有:fatal_error + # str(Ptr(Int8))保持 strlen(内建语义)。 + len_struct_ty: llvmlite.LLVMType | t.CPtr = \ + self.Gen.StructGen.get_struct_type_from_value(len_val) + if len_struct_ty is not None: + len_cls_nm: str = self.Gen.StructGen.get_class_name_by_type( + pool, len_struct_ty) + if len_cls_nm is None: + self.Gen.TypeGenErr.fatal_error( + len_arg_node, "len() 参数类型推断失败(结构体类名未知)", + "TypeError") + # list 内置 __len__:读 __count__(GEP 偏移 1,i64) + if self.Gen.CallGenProp._is_list_builtin_method(len_cls_nm, "__len__") != 0: + i64_ty_lb: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + idx_one_lb: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) + cnt_ptr_lb: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i64_ty_lb, len_val, idx_one_lb) + if cnt_ptr_lb is not None: + return llvmlite.build_load(builder, i64_ty_lb, cnt_ptr_lb) + len_lookup: str = pool.alloc(128) + if len_lookup is not None: + viperlib.snprintf(len_lookup, 128, "%s.__len__", len_cls_nm) + len_fn2: llvmlite.Function | t.CPtr = self.find_func_in_module( + mod, len_lookup) + if len_fn2 is not None: + len_ret_ty2: llvmlite.LLVMType | t.CPtr = \ + llvmlite.function_get_ret_ty(len_fn2) + len_fn_name2: str = \ + llvmlite.function_get_name(len_fn2) + if len_ret_ty2 is not None and len_fn_name2 is not None: + # self 参数类型对齐(按方法首个形参 bitcast) + len_self_arg2: llvmlite.Value | t.CPtr = len_val + len_first_param2: llvmlite.Param | t.CPtr = \ + llvmlite.function_get_param_head(len_fn2) + if len_first_param2 is not None: + len_self_ty2: llvmlite.LLVMType | t.CPtr = \ + llvmlite.param_get_ty(len_first_param2) + if len_self_ty2 is not None and len_val.Ty is not None: + len_self_arg2 = llvmlite.build_bitcast( + builder, len_val, len_self_ty2) + len_self_arg2.Next = None + return llvmlite.build_call( + builder, len_fn_name2, len_self_arg2, + 1, len_ret_ty2, 0) + # len_fn2 未命中(跨模块方法):如 ndarray[t.CDouble].__len__ + # 定义在 numpy——泛型特化方法无 stub declare,find_func_in_module + # 后缀匹配查不到。用结构体所属模块 sha1 构造 + # {sha1}.{cls}.__len__ 精确调用名(对齐 _translate_method_call + # 跨模块调用名构造),返回类型从 text.ll/vpi 精确解析, + # _ensure_method_declare 建 declare 后调用。 + len_cls_sha1_x: str = self.Gen.StructGen.get_struct_sha1(len_cls_nm) + if len_cls_sha1_x is not None: + # 缓冲区需容纳 "{sha1}.{cls}.__len__": + # 2 个点 + "__len__"(7) + NUL = 10;+8 会截断 + # 末两位 → 符号变 ".__len" 链接 undefined + # (NumpyTest test_len 链接错误根因) + len_ml_x: t.CSizeT = string.strlen(len_cls_sha1_x) \ + + string.strlen(len_cls_nm) + 10 + len_mangled_x: str = pool.alloc(len_ml_x) + if len_mangled_x is not None: + viperlib.snprintf(len_mangled_x, len_ml_x, + "%s.%s.__len__", len_cls_sha1_x, len_cls_nm) + len_ret_x: llvmlite.LLVMType | t.CPtr = \ + self._LookupMethodRetTyFromTextLL( + pool, len_cls_sha1_x, len_cls_nm, "__len__") + if len_ret_x is None: + len_ret_x = self._lookup_method_ret_ty_via_vpi( + pool, len_cls_sha1_x, len_cls_nm, "__len__") + if len_ret_x is not None: + # self 参数按对象实际类型 Ptr(len_struct_ty)(与定义侧 + # 同名类型链接匹配);len_val 已是 load 后的对象指针。 + # Value 链直接作 param_head(同跨模块调用模式)。 + len_self_x: llvmlite.Value | t.CPtr = len_val + len_self_x.Next = None + self._ensure_method_declare( + pool, mod, len_mangled_x, len_ret_x, + len_self_x, 1) + return llvmlite.build_call( + builder, len_mangled_x, len_self_x, + 1, len_ret_x, 0) + # fail-fast:类没有 __len__(用户要求编译期报错) + self.Gen.TypeGenErr.fatal_error( + len_arg_node, + f"len() 参数类型 '{len_cls_nm}' 没有 __len__ 方法", + "TypeError") + # 非结构体:str(Ptr(Int8))走 strlen;其它类型 fail-fast + len_arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(len_val) + len_is_str: int = 0 + if len_arg_ty is not None and self.Gen.ExprGenBase.is_ptr_type(len_arg_ty) != 0: + match len_arg_ty: + case llvmlite.LLVMType.Ptr(len_pt_ty): + if len_pt_ty is not None: + match len_pt_ty: + case llvmlite.LLVMType.Int(len_pt_bits): + if len_pt_bits == 8: + len_is_str = 1 + case _: + pass + case _: + pass + if len_is_str != 0: + # 确保 strlen 在模块中有声明 + strlen_fn: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, "strlen") + if strlen_fn is None: + i64_ty_ln: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i8_ptr_ty_ln: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + strlen_fn = llvmlite.create_declare(pool, mod, "strlen", i64_ty_ln) + if strlen_fn is not None: + llvmlite.add_param(pool, strlen_fn, i8_ptr_ty_ln, "s") + # 参数类型转换为 i8* + i8_ptr_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + len_coerced: llvmlite.Value | t.CPtr = len_val + if self.Gen.ExprGenBase.is_ptr_type(len_arg_ty) != 0: + len_coerced = llvmlite.build_bitcast(builder, len_val, i8_ptr_ty_ln2) + # 构建单参数链表并调用 strlen + len_coerced.Next = None + i64_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + return llvmlite.build_call(builder, "strlen", len_coerced, 1, i64_ty_ln2, 0) + # fail-fast:非字符串/数组/对象,无法求长度 + self.Gen.TypeGenErr.fatal_error( + len_arg_node, "len() 参数类型不支持(非字符串/数组/对象)", + "TypeError") + + # 检测 isinstance() 内置函数调用 — 运行时 vtable 子类集合比较 + # isinstance(obj, Cls):obj 头部 vtable 指针 ∈ {Cls 及全部子类 vtable}; + # NoVTable 目标类回退编译时静态判断(详见 _translate_isinstance)。 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: + if func_name is not None and string.strcmp(func_name, "isinstance") == 0: + if can >= 2: + is_res: llvmlite.Value | t.CPtr = self.Gen.CallGenLeafKit._translate_isinstance( + pool, builder, mod, cargs.get(0), cargs.get(1), trans) + if is_res is not None: + return is_res + + return None + + def _tc_h6_method_dispatch(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + hit_box: t.CPtr = None) -> llvmlite.Value | t.CPtr: + """静态类/方法调用/表达式接收者/self.field/list 内置(未命中返回 None) + + hit_box: 命中标记(t.CPtr,[0]=1 表示已识别为方法调用路径)。 + 编译器生成方法(如 __before_init__/__init__)恒返回 void, + _translate_method_call 处理后返回 None(无返回值)——若不标记, + translate_call 会误判"未命中"继续走跨模块函数路径(把对象名 + 当模块名查 SHA1 → "跨模块调用 'buf.__before_init__' 找不到模块 SHA1")。 + """ + # 检测类名静态/类方法调用: ClassName.method(args) + # 当 cl.func 是 Attribute、value 是已注册结构体类名(非普通变量)时, + # 且方法带 @staticmethod/@classmethod 元数据,走静态调用路径 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + st_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if st_at is not None and st_at.value is not None and trans is not None: + if st_at.value.kind() == ast.ASTKind.Name: + st_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(st_at.value) + if st_nm.id is not None: + # 仅当该名称不是普通变量且是已注册结构体类名时尝试静态/类方法 + # 追加"非导入模块"条件:st_nm.id 是模块名(import X as Y 把别名 + # Y 加入 _imported_modules,HandlesImports L344-347)时,X.Y(...) + # 是模块限定调用(Module.Class 构造 / Module.func 函数),不是 + # ClassName.method(obj,args)。模块名与类名同名时(CompilerFactory. + # CompilerFactory(...) 构造 / .set_factory(...) 函数,main.vp + # 追加84/84b 根因)get_struct_type(st_nm.id) 会误判为类名 → + # 把首实参当 self 传 _call_method_on_ptr → 返回类型查 "X.Y" 永远 + # 落空 → fail-fast。模块限定调用由尾部 ctor 检测(L7441 模块限定 + # 构造)与跨模块函数路径正确路由。 + st_var: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, st_nm.id) + if st_var is None and self.Gen.StructGen.get_struct_type(st_nm.id) is not None \ + and self.Gen.ImportsGen.is_module_imported( + trans._imported_modules, st_nm.id) == 0: + # REnum 变体构造优先于静态/类方法调用: + # ClassName.VariantName(args)(如 Option.Some(42))若被当 + # "实例方法经类名调用"处理,会把首实参 42 当 self 传 + # _call_method_on_ptr → 查 "Option.Some" 方法返回类型 → + # 跨模块 stub 未命中 → fail-fast(EnumTest "方法 + # 'Option.Some' 返回类型无法确定" 根因)。REnum 变体 + # 构造检测原在 translate_call 尾部(L7493),被本分支 + # 拦截先执行不到,此处提前检测。 + if self.Gen.ClassGenEnum._is_renum_class_name(st_nm.id) != 0: + rc_tag_sc: int = self.Gen.ClassGenEnum._lookup_renum_variant_in_class( + st_nm.id, func_name) + if rc_tag_sc >= 0: + return self.Gen.CallGenCtor._translate_renum_construct( + pool, builder, mod, st_nm.id, func_name, + rc_tag_sc, cargs, can, trans) + st_res: llvmlite.Value | t.CPtr = self.Gen.CallGenProp._translate_static_class_call( + pool, builder, mod, st_nm.id, func_name, cl, trans) + if st_res is not None: + return st_res + # 实例方法经类名调用: ClassName.method(obj, args) → obj.method(args) + # (Python 语义,首参是 self 对象;zdeflate.vp + # zdeflate_stream.find_match(s, data, ...) 根因:_translate_ + # static_class_call 对非静态方法返回 None 后,ClassName 被 + # 通用路径当模块名 → "跨模块调用找不到模块 SHA1") + # st_nm.id == func_name(类名==方法名,如 CompilerFactory. + # CompilerFactory(...))不是实例方法调用而是构造调用: + # 模块名与类名同名时本分支把模块限定类构造误判为 + # ClassName.method(obj,args),首实参当 self 传 → + # _call_method_on_ptr 查 "X.X" 返回类型永远落空 → + # fail-fast(main.vp CompilerFactory 追加84 根因)。 + # 跳过本分支,落到 translate_call 尾部的 ctor 检测 + # (L7426 模块限定类构造 find_struct_by_module 正确路由)。 + if can >= 1 and cargs is not None \ + and string.strcmp(st_nm.id, func_name) != 0: + im_self: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cargs.get(0), None, 0, trans) + if im_self is not None: + im_rem: t.CSizeT | t.CPtr = None + if can >= 2: + im_rem = pool.alloc(t.CSizeT(can - 1) * 8) + if im_rem is not None: + ri_im: t.CSizeT + for ri_im in range(can - 1): + im_rv: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, cargs.get(ri_im + 1), None, 0, trans) + if im_rv is not None: + im_rem[ri_im] = t.CSizeT(im_rv) + im_res: llvmlite.Value | t.CPtr = self.Gen.CallGenCall._call_method_on_ptr( + pool, builder, mod, st_nm.id, func_name, + im_self, im_rem, can - 1, trans) + if im_res is not None: + return im_res + elif st_at.value.kind() == ast.ASTKind.Attribute: + # 模块限定静态调用: module.ClassName.static_method(args) + # cl.func = Attribute(value=Attribute(value=Name(module), + # attr=ClassName), attr=method_name) + # 此前未检测 → 走通用路径把 method_name 当裸函数解析, + # 生成 call i32 @from_long(无类名/SHA1 前缀)→ 链接 + # undefined reference(CPythonTest PyLongObj.from_long 根因) + st_at2: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(st_at.value) + if st_at2 is not None and st_at2.attr is not None and st_at2.value is not None: + if st_at2.value.kind() == ast.ASTKind.Name: + # ClassName 是已注册结构体类名时尝试静态/类方法 + if self.Gen.StructGen.get_struct_type(st_at2.attr) is not None: + st_res2: llvmlite.Value | t.CPtr = self.Gen.CallGenProp._translate_static_class_call( + pool, builder, mod, st_at2.attr, func_name, cl, trans) + if st_res2 is not None: + return st_res2 + + # 检测方法调用: obj.method(args) + # 当 cl.func 是 Attribute 且 obj 是已注册的结构体变量时,翻译为方法调用 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if method_at is not None and method_at.value is not None: + if method_at.value.kind() == ast.ASTKind.Name and trans is not None: + method_obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(method_at.value) + if method_obj_nm.id is not None: + # 查找对象变量 + obj_var: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, method_obj_nm.id) + if obj_var is not None and obj_var.Ty is not None: + # 检查是否为 Ptr(Struct(...))(结构体值变量) + # 或 Ptr(Ptr(Struct(...)))(指针变量,需 load) + match obj_var.Ty: + case llvmlite.LLVMType.Ptr(obj_struct_ty): + class_nm: str = self.Gen.StructGen.get_class_name_by_type( + pool, obj_struct_ty) + if class_nm is not None: + # list 泛型内置容器方法(append/get/set/pop/clear/__iter__/ + # __len__/__getitem__/__setitem__)由下方 list 内置分支 + # (L5848 起)内联 GEP 处理,不注册方法函数;若走 + # _translate_method_call 会查 append 返回类型(函数/text.ll/ + # vpi stub 均未命中)→ fail-fast。检测到 list 方法时 + # 跳过 method_call,落到内置分支(NewAstTest body.append 根因)。 + if self.Gen.CallGenProp._is_list_builtin_method(class_nm, func_name) == 0: + if hit_box is not None: + hit_box[0] = 1 + return self.Gen.CallGenCall._translate_method_call( + pool, builder, mod, class_nm, func_name, + obj_var, cl, trans) + # 指针变量: alloca 类型是 Ptr(Ptr(Struct)) + # load 获取实际指针 Ptr(Struct) 后再查找 + match obj_struct_ty: + case llvmlite.LLVMType.Ptr(inner_struct_ty): + inner_nm: str = self.Gen.StructGen.get_class_name_by_type( + pool, inner_struct_ty) + if inner_nm is not None: + # list 内置方法同样跳过(同 Ptr(Struct) 分支) + if self.Gen.CallGenProp._is_list_builtin_method(inner_nm, func_name) == 0: + obj_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, obj_struct_ty, obj_var) + if obj_ptr is not None: + if hit_box is not None: + hit_box[0] = 1 + return self.Gen.CallGenCall._translate_method_call( + pool, builder, mod, inner_nm, func_name, + obj_ptr, cl, trans) + # FakeDuck: str/bytes 变量(Ptr(i8),AnnotClassName 为空) + # 方法调用 → 扩展类 _Type/_str(a.type_id() / a.upper())。 + # 前置拦截:常规结构体方法分支全落空时,尝试扩展类方法 + # (find_func_in_module 未命中返回 None,不影响正常路径)。 + fd_name_res: llvmlite.Value | t.CPtr = self.Gen.CallGenFd._translate_fakeduck_call( + pool, builder, mod, None, func_name, cl, trans) + if fd_name_res is not None: + return fd_name_res + # AnnotClassName 回退:联合类型简化为 Ptr(i8) 时, + # 通过原始类型注解的类名查找结构体 + var_entry: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, method_obj_nm.id) + if var_entry is not None and var_entry.AnnotClassName is not None: + annot_val: str = var_entry.AnnotClassName + # 解析模块限定名 "memhub.MemBuddy" → mod_nm="memhub", cls_nm="MemBuddy" + dot_ptr: str = string.strrchr(annot_val, '.') + cls_nm2: str = annot_val + mod_nm2: str = None + if dot_ptr is not None: + cls_nm2 = dot_ptr + 1 + total_len_av: t.CSizeT = string.strlen(annot_val) + cls_len_av: t.CSizeT = string.strlen(cls_nm2) + mod_len2: t.CSizeT = total_len_av - cls_len_av - 1 + mod_nm2 = pool.alloc(mod_len2 + 1) + if mod_nm2 is not None: + string.strncpy(mod_nm2, annot_val, mod_len2) + mod_nm2[mod_len2] = '\0' + # 检查结构体是否已注册 + if self.Gen.StructGen.get_struct_type(cls_nm2) is not None: + # list 内置方法跳过 method_call(同 Ptr(Struct) 分支), + # 落到下方 list 内置分支 + if self.Gen.CallGenProp._is_list_builtin_method(cls_nm2, func_name) == 0: + # 结构体已注册:load obj_ptr 走方法调用 + i8_ptr_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + obj_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i8_ptr_ty2, obj_var) + if obj_ptr2 is not None: + if hit_box is not None: + hit_box[0] = 1 + return self.Gen.CallGenCall._translate_method_call( + pool, builder, mod, cls_nm2, func_name, + obj_ptr2, cl, trans) + else: + # list 内置方法跳过(结构体未注册路径同样不能 + # 构造 {sha1}.{cls}.append 调用名——list 方法无此函数) + if self.Gen.CallGenProp._is_list_builtin_method(cls_nm2, func_name) == 0: + # FakeDuck: str 变量方法调用 → 扩展类 _Type/_str + # a.type_id() / a.upper() / " ".isspace() 等 + # AnnotClassName=="str" 且对象是 char* 时触发, + # self 用影子结构体 {a}__meta__(或临时影子)。 + fd_res: llvmlite.Value | t.CPtr = self.Gen.CallGenFd._translate_fakeduck_call( + pool, builder, mod, cls_nm2, func_name, cl, trans) + if fd_res is not None: + return fd_res + # 结构体未注册(跨模块依赖未翻译): + # 用模块名查 SHA1 构造方法调用名 + sha1_fc: str = None + if mod_nm2 is not None: + sha1_fc = self._lookup_module_sha1(mod_nm2) + if sha1_fc is not None: + # 构造 "{sha1}.{cls_nm2}.{func_name}" 调用名 + mlen3: t.CSizeT = string.strlen(sha1_fc) + string.strlen(cls_nm2) + string.strlen(func_name) + 3 + mangled3: str = pool.alloc(mlen3) + if mangled3 is not None: + viperlib.snprintf(mangled3, mlen3, "%s.%s.%s", sha1_fc, cls_nm2, func_name) + # load obj_ptr (self) + i8_ptr_ty3: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + obj_ptr3: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i8_ptr_ty3, obj_var) + if obj_ptr3 is not None: + # 构建参数链表: obj_ptr3 (self) → 其他参数 + llvmlite.value_set_next(obj_ptr3, None) + head3: llvmlite.Value | t.CPtr = obj_ptr3 + tail3: llvmlite.Value | t.CPtr = obj_ptr3 + for ai3 in range(can): + arg3: ast.AST | t.CPtr = cargs.get(ai3) + if arg3 is not None: + arg_val3: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg3, None, 0, trans) + if arg_val3 is not None: + llvmlite.value_set_next(arg_val3, None) + llvmlite.value_set_next(tail3, arg_val3) + tail3 = arg_val3 + total3: int = 1 + can + ret_ty3: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty( + pool, cls_nm2, func_name) + if ret_ty3 is None: + ret_ty3 = self._LookupMethodRetTyFromTextLL( + pool, sha1_fc, cls_nm2, func_name) + if ret_ty3 is None: + # 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单) + ret_ty3 = self._lookup_method_ret_ty_via_vpi( + pool, sha1_fc, cls_nm2, func_name) + if ret_ty3 is None: + # 本分支仅在"注解类结构体未注册"时到达(L6932 else): + # 类未注册 → 无法沿 MRO 解析 Mixin 方法定义模块。 + # 例如 g 注解 Generator.Generator,但 _register_cdefine_from_value + # 定义在 AssignGenMixin.vp——其 text.ll 的 define 名是 + # {AssignGenMixin_sha1}.AssignGenMixin.xxx,查 + # {Generator_sha1}.Generator.xxx 永远落空(追加80d 根因; + # sha1_fc 存在 + text.ll 存在仍查不到,固定 256KB 截断 + # 只是次要因素)。必须标记 pending:等 Generator 注册后 + # 下遍走 L6919 已注册分支 → _translate_method_call 沿 + # MRO 链找到 AssignGenMixin → 精确解析。真正不存在的 + # 类/方法由 Phase A 收敛检查兜底,绝不在此 fail-fast + # 中断多遍收敛(对齐追加77/77b 类 defer 原则)。 + if trans is not None: + trans._deps_pending = 1 + # 依赖未就绪:保持默认 i32(build_call(Void) + # 返回 None 破坏表达式翻译;本遍不写盘) + ret_ty3 = llvmlite.Int32(pool) + self._ensure_method_declare(pool, mod, mangled3, ret_ty3, head3, total3) + return llvmlite.build_call(builder, mangled3, head3, total3, ret_ty3, 0) + else: + # 编译器生成特殊方法放行(__before_init__/__init__ 等): + # 结构体未注册 + 模块 SHA1 均不可查(Phase A 依赖未就绪)时, + # 方法返回类型由编译器确定性定义(_special_method_ret_ty), + # 不依赖结构体注册即可精确解析。走 _translate_method_call 处理 + # (内部含 _special_method_ret_ty + mc_entry/类型名 SHA1 提取), + # 绝不掉出返回 None 让 translate_call 把对象名当模块名 + # 报"跨模块调用 'buf.__before_init__' 找不到模块 SHA1" + # (memhub.alloc_buf buf.__before_init__() 根因)。 + sp_ty4: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty( + pool, cls_nm2, func_name) + if sp_ty4 is not None: + i8_ptr_ty4: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + obj_ptr4: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i8_ptr_ty4, obj_var) + if obj_ptr4 is not None: + if trans is not None: + trans._deps_pending = 1 + if hit_box is not None: + hit_box[0] = 1 + return self.Gen.CallGenCall._translate_method_call( + pool, builder, mod, cls_nm2, func_name, + obj_ptr4, cl, trans) + + # ============================================================ + # 检测表达式接收者方法调用: (expr).method(args) + # + # 当 method_at.value 是 BinOp/Subscript/Call 等非 Name/Attribute 表达式时 + # (如 (a + b).dot(c)、(v1 + v2) * 3.0),先 translate_value 求值接收者, + # 再从值的 LLVM 类型(Ptr(Struct))解析类名,走方法调用路径。 + # ============================================================ + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + expr_method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if expr_method_at is not None and expr_method_at.value is not None and trans is not None: + evk: int = expr_method_at.value.kind() + # Attribute 接收者区分两种形态: + # 1. 模块限定路径(os._win32.exists / w32.fileio.fn)——根名是已导入 + # 模块或 t/c,留给下方跨模块限定路径处理 + # 2. 字段链表达式接收者(self.writer.write_bits / self.pool.alloc) + # ——根名是对象(self/局部变量),必须走本方法调用路径; + # 否则被模块限定路径误判 xmod_path="self.writer" → "找不到模块 + # SHA1"(zdeflate.vp write_fixed_block 根因) + is_mod_path_expr: int = 0 + if evk == ast.ASTKind.Attribute: + expr_root: ast.AST | t.CPtr = expr_method_at.value + while expr_root is not None and expr_root.kind() == ast.ASTKind.Attribute: + expr_root = (ast.Attribute | t.CPtr)(expr_root).value + if expr_root is not None and expr_root.kind() == ast.ASTKind.Name: + expr_root_nm: str = (ast.Name | t.CPtr)(expr_root).id + if expr_root_nm is not None: + if string.strcmp(expr_root_nm, "t") == 0 or \ + string.strcmp(expr_root_nm, "c") == 0: + is_mod_path_expr = 1 + elif trans._imported_modules is not None: + if self.Gen.ImportsGen.is_module_imported( + trans._imported_modules, expr_root_nm) != 0: + is_mod_path_expr = 1 + if evk != ast.ASTKind.Name and is_mod_path_expr == 0: + # 翻译接收者表达式(求值结果应为 Ptr(Struct)) + expr_obj: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, expr_method_at.value, funcs_ptr, func_count, trans) + if expr_obj is not None and expr_obj.Ty is not None: + expr_cls_nm: str = None + # 递归解 Ptr:识别 X|t.CPtr 联合简化的 Ptr(Ptr(Struct)) + # (如 (a*2.0 - b) 中 __mul__ 返回 Vec3**),否则方法 + # 调用被当裸函数 @dot 解析 → 链接 undefined symbol + expr_struct_ty: llvmlite.LLVMType | t.CPtr = \ + self.Gen.StructGen.get_struct_type_from_value(expr_obj) + if expr_struct_ty is not None: + expr_cls_nm = self.Gen.StructGen.get_class_name_by_type( + pool, expr_struct_ty) + # 回退:LLVM 类型为 Ptr(i8)(方法返回 X|t.CPtr 无类型信息)时, + # 从接收者表达式结构推断类名(链式调用 c2.scale(2.0).move(...) + # 的 scale 返回 Ptr(i8),经 infer_expr_class → vpi 返回注解) + # 跨 Mixin 不能 self 调用 ExprGenMixin 方法,经全局单例 + if expr_cls_nm is None: + expr_cls_nm = self.Gen.ExprGenCls.infer_expr_class( + pool, mod, expr_method_at.value, trans) + if expr_cls_nm is not None: + # 值类型接收者(内嵌 struct 字段,如 zdeflate s.writer 值字段): + # 方法调用 self 必须传字段地址(GEP)而非 load 出的结构体值, + # 否则结构体值(40B)塞进 zbit_writer* 参数 → ABI 错配 → + # 被调方把值当 this 指针解引用 → GEP 0x18 崩溃 + # (s.writer.write_zlib_header 运行时 access-violation 根因; + # 本路径 evk=Attribute 先于 self.field.method() 分支命中)。 + expr_is_ptr: int = 0 + match expr_obj.Ty: + case llvmlite.LLVMType.Ptr(expr_ptr_inner): + expr_is_ptr = 1 + case _: + expr_is_ptr = 0 + if expr_is_ptr == 0: + expr_addr: llvmlite.Value | t.CPtr = self.Gen.ExprGenAttr.get_attribute_ptr( + builder, pool, mod, expr_method_at.value, trans) + if expr_addr is not None: + expr_obj = expr_addr + if hit_box is not None: + hit_box[0] = 1 + return self.Gen.CallGenCall._translate_method_call( + pool, builder, mod, expr_cls_nm, func_name, + expr_obj, cl, trans) + # FakeDuck: 表达式接收者解析失败且对象是 char* 时 + # (如 " ".isspace()),尝试扩展类 _Type/_str 方法 + # (self 用临时影子,对齐 TPC L2858-2873) + fd_expr_res: llvmlite.Value | t.CPtr = self.Gen.CallGenFd._translate_fakeduck_call( + pool, builder, mod, None, func_name, cl, trans) + if fd_expr_res is not None: + return fd_expr_res + + # ============================================================ + # 检测 self.field.method() 调用 + # + # 当 method_at.value 是 Attribute(字段访问,如 self.__pool__)时, + # 翻译字段值获取对象指针,然后走方法调用路径。 + # + # 路径1: 从字段值的 LLVM 类型获取类名(字段类型为 Ptr(Struct("MemManager"))) + # 路径2: 从字段的 AnnotClassName 回退查找(字段类型被简化为 Ptr(i8) 时) + # ============================================================ + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + attr_method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if attr_method_at is not None and attr_method_at.value is not None: + if attr_method_at.value.kind() == ast.ASTKind.Attribute and trans is not None: + inner_attr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(attr_method_at.value) + if inner_attr is not None and inner_attr.attr is not None: + # 翻译 self.__pool__ 获取字段值(已 load 的对象指针) + field_obj: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, attr_method_at.value, funcs_ptr, func_count, trans) + if field_obj is not None and field_obj.Ty is not None: + field_cls_nm: str = None + # 路径1: 从字段值的 LLVM 类型获取类名 + match field_obj.Ty: + case llvmlite.LLVMType.Ptr(field_struct_ty): + field_cls_nm = self.Gen.StructGen.get_class_name_by_type( + pool, field_struct_ty) + # 路径2: 从字段注解类名回退查找 + if field_cls_nm is None: + if inner_attr.value is not None and inner_attr.value.kind() == ast.ASTKind.Name: + inner_name_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner_attr.value) + if inner_name_node is not None and inner_name_node.id is not None: + inner_var: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var( + trans.SymTab, inner_name_node.id) + if inner_var is not None and inner_var.Ty is not None: + match inner_var.Ty: + case llvmlite.LLVMType.Ptr(field_owner_struct_ty): + field_info: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field( + field_owner_struct_ty, inner_attr.attr) + if field_info is not None: + field_annot: str = self.Gen.StructGen.get_field_annot_class_name(field_info) + if field_annot is not None: + dot_p: str = string.strrchr(field_annot, 46) + if dot_p is not None: + field_cls_nm = dot_p + 1 + else: + field_cls_nm = field_annot + if field_cls_nm is not None: + # 值类型字段(内嵌 struct,如 zdeflate_stream.writer: zbit_writer) + # 方法调用 self 必须传字段地址(GEP),而非 load 出的结构体值: + # 传值给 stub 声明/define 的 zbit_writer* 参数 → ABI 错配, + # 被调方把结构体值前 8 字节当 this 指针解引用 → GEP 0x18 崩溃 + # (zdeflate s.writer.write_zlib_header 运行时 access-violation 根因)。 + is_val_field: int = 0 + match field_obj.Ty: + case llvmlite.LLVMType.Ptr(field_ptr_inner): + is_val_field = 0 + case _: + is_val_field = 1 + if is_val_field != 0: + field_addr: llvmlite.Value | t.CPtr = self.Gen.ExprGenAttr.get_attribute_ptr( + builder, pool, mod, attr_method_at.value, trans) + if field_addr is not None: + field_obj = field_addr + if hit_box is not None: + hit_box[0] = 1 + return self.Gen.CallGenCall._translate_method_call( + pool, builder, mod, field_cls_nm, func_name, + field_obj, cl, trans) + + # ============================================================ + # 检测 list 内置方法调用: lst.get(i), lst.set(i,v), lst.pop(), lst.clear(), lst.__iter__() + # list[T] 是泛型类不注册 struct,方法调用处理器(上方)无法处理, + # 需要在此特殊处理。 + # list 结构布局 (6 字段 × 8 字节): + # __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40) + # ============================================================ + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + lm_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if lm_at is not None and lm_at.attr is not None and lm_at.value is not None: + lm_name: str = lm_at.attr + # 判断是否是 list 方法名 + lm_is_list: int = 0 + if string.strcmp(lm_name, "get") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "__getitem__") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "set") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "__setitem__") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "pop") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "clear") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "__iter__") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "append") == 0: lm_is_list = 1 + + if lm_is_list == 1 and trans is not None: + # 翻译 list 对象 + lm_obj: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, lm_at.value, funcs_ptr, func_count, trans) + if lm_obj is not None: + # 防御性类型检查: lm_obj 必须是指针类型才能做 GEP + # translate_value 对某些 Attribute 节点(如 ast.Arguments 的属性) + # 可能返回 i32 0 (非指针),直接 GEP 会导致 + # "base of getelementptr must be a pointer" 错误 + if lm_obj.Ty is None or self.Gen.ExprGenBase.is_ptr_type(lm_obj.Ty) == 0: + # translate_value 类型推断失败(目标对象非指针): + # fail-fast,绝不 VLogger.critical 后 return None 静默吞掉 + self.Gen.TypeGenErr.fatal_error( + lm_at.value, f"list 方法 '{lm_name}' 目标对象非指针", "TypeError") + # list 对象类型确认(额外搜索路径):list 内置分支仅按方法名 + # 判断(get/set/__getitem__ 等非 list 专有),须确认对象确实 + # 是 list——从对象结构体名匹配 "list"。明确非 list(如 dict / + # 普通类未注册场景)跳过本分支,避免按 list 布局 GEP 生成 + # 错误 IR(dict 的 get 被当 list.get 按 __data__/__elem_size__ + # 偏移读写垃圾)。 + lm_conf_ty: llvmlite.LLVMType | t.CPtr = \ + self.Gen.StructGen.get_struct_type_from_value(lm_obj) + lm_conf_nm: str = None + if lm_conf_ty is not None: + lm_conf_nm = llvmlite.get_struct_name(lm_conf_ty) + if lm_conf_nm is not None and \ + string.strstr(lm_conf_nm, "list") is None: + return None + # list 内置分支命中标记:void 方法(set/clear)成功处理后返回 + # None,必须置位 hit_box 区分"已识别为 list 方法路径",否则 + # translate_call 误判未命中继续走跨模块函数路径,把对象名当 + # 模块名查 SHA1 → "跨模块调用 'nums.set' 找不到模块 SHA1" + # (ListTest main.vp nums.set(1,99) 根因;对齐 _translate_method_call + # 调用点的 hit_box 置位模式)。 + if hit_box is not None: + hit_box[0] = 1 + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + # 元素类型 T:从 list 特化类型名解析(list[int]→i32、 + # list[str]→i8*、未知/指针元素→i8*)。此前 get/set/pop + # 固定 i8*(8 字节)读写:set 的 8 字节 store 覆盖相邻元素 + # (inttoptr 值,如 set(1,99) 把 data[8..11] 的 30 清 0), + # pop 读回 0 → ListTest "pop FAILED expect 30" 根因。 + # subscript 路径(list_getitem_inline 调用方)已用 + # _list_elem_type_from_name 修正,方法调用路径漏改。 + lm_esty: llvmlite.LLVMType | t.CPtr = \ + self.Gen.StructGen.get_struct_type_from_value(lm_obj) + lm_ename: str = None + if lm_esty is not None: + lm_ename = llvmlite.get_struct_name(lm_esty) + lm_elem_ty: llvmlite.LLVMType | t.CPtr = None + if lm_ename is not None: + lm_elem_ty = self.Gen.ExprGenName._list_elem_type_from_name( + pool, lm_ename) + if lm_elem_ty is None: + lm_elem_ty = i8_ptr_ty + + # get / __getitem__: 返回 index 处的元素 + if string.strcmp(lm_name, "get") == 0 or string.strcmp(lm_name, "__getitem__") == 0: + if can >= 1: + # 加载 __data__ (偏移 0) + g_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + g_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0) + g_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, g_dpp) + # 加载 __elem_size__ (偏移 32, index 4) + g_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) + g_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4) + g_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, g_epp) + # 翻译 index + g_idx_node: ast.AST | t.CPtr = cargs.get(0) + g_idx_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, g_idx_node, None, 0, trans) + if g_data is not None and g_esize is not None and g_idx_val is not None: + g_idx_i64: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type( + builder, g_idx_val, i64_ty, g_idx_node) + g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize) + g_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, g_data, g_offset) + if g_addr is not None: + g_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, g_addr, llvmlite.Ptr(pool, lm_elem_ty)) + if g_ep is not None: + return llvmlite.build_load(builder, lm_elem_ty, g_ep) + + # set / __setitem__: 设置 index 处的元素 + elif string.strcmp(lm_name, "set") == 0 or string.strcmp(lm_name, "__setitem__") == 0: + if can >= 2: + s_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + s_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0) + s_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, s_dpp) + s_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) + s_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4) + s_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, s_epp) + s_idx_node: ast.AST | t.CPtr = cargs.get(0) + s_val_node: ast.AST | t.CPtr = cargs.get(1) + s_idx_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, s_idx_node, None, 0, trans) + s_val_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, s_val_node, None, 0, trans) + if s_data is not None and s_esize is not None and s_idx_val is not None and s_val_val is not None: + s_idx_i64: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type( + builder, s_idx_val, i64_ty, s_idx_node) + s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize) + s_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s_data, s_offset) + if s_addr is not None: + s_val_elem: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type( + builder, s_val_val, lm_elem_ty, s_val_node) + s_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, s_addr, llvmlite.Ptr(pool, lm_elem_ty)) + if s_ep is not None: + llvmlite.build_store(builder, s_val_elem, s_ep) + return None + + # pop: 返回最后一个元素,count-- + elif string.strcmp(lm_name, "pop") == 0: + p_idx1: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) + p_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx1) + p_count: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_cpp) + p_nc: llvmlite.Value | t.CPtr = llvmlite.build_sub( + builder, p_count, llvmlite.const_int64(pool, 1)) + llvmlite.build_store(builder, p_nc, p_cpp) + p_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + p_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx0) + p_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, p_dpp) + p_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) + p_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx4) + p_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_epp) + if p_data is not None and p_esize is not None and p_nc is not None: + p_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, p_nc, p_esize) + p_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, p_data, p_offset) + if p_addr is not None: + p_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, p_addr, llvmlite.Ptr(pool, lm_elem_ty)) + if p_ep is not None: + return llvmlite.build_load(builder, lm_elem_ty, p_ep) + + # clear: count = 0 + elif string.strcmp(lm_name, "clear") == 0: + c_idx1: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) + c_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, c_idx1) + llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), c_cpp) + return None + + # __iter__: iter_index = 0, return self + elif string.strcmp(lm_name, "__iter__") == 0: + it_idx5: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 5) + it_ipp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, it_idx5) + llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), it_ipp) + return lm_obj + + # append: 直接调用 list.append(self, item) + # append 需要容量检查和内存重分配,逻辑复杂,直接调用 _list.py 中的实现 + elif string.strcmp(lm_name, "append") == 0: + if can >= 1: + ap_sha1: str = self._lookup_module_sha1("_list") + if ap_sha1 is None: + # 依赖模块未编译(_list 未预加入编译链):fail-fast, + # 绝不静默跳过 append(元素永远不会被加入列表) + self.Gen.TypeGenErr.fatal_error( + cl, "list.append: 找不到 _list 模块 SHA1(依赖模块未编译)", + "InternalCompilerError") + if ap_sha1 is not None: + # 特化类名提取:list.append 的符号名是 + # {sha1}.list[AST|CPtr].append(带类型参数特化名), + # 而非 {sha1}.list.append。lm_obj 类型即特化结构体 + # Ptr(list[AST|CPtr]),从类型解析特化类名拼接调用名, + # 否则 ld.lld undefined symbol(定义端是特化名)。 + ap_spec_nm: str = None + ap_struct_ty: llvmlite.LLVMType | t.CPtr = \ + self.Gen.StructGen.get_struct_type_from_value(lm_obj) + if ap_struct_ty is not None: + ap_spec_nm = self.Gen.StructGen.get_class_name_by_type( + pool, ap_struct_ty) + if ap_spec_nm is None: + ap_spec_nm = "list" + # 触发泛型特化翻译(幂等,MethodsEmitted 防重入): + # list[AST|CPtr].append 的 define 方法体在特化类翻译时 + # 生成。仅构造调用名不触发特化会导致定义缺失 + # (ld.lld undefined symbol: list[AST|CPtr].append)。 + if trans is not None and ap_spec_nm is not None: + lbkt_ap: str = string.strchr(ap_spec_nm, '[') + if lbkt_ap is not None: + rbkt_ap: str = string.strrchr(ap_spec_nm, ']') + if rbkt_ap is not None and rbkt_ap > lbkt_ap: + base_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(lbkt_ap) - t.CUInt64T(ap_spec_nm)) + arg_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(rbkt_ap) - t.CUInt64T(lbkt_ap) - 1) + if base_len_ap > 0 and arg_len_ap > 0: + base_buf_ap: str = pool.alloc(base_len_ap + 1) + arg_buf_ap: str = pool.alloc(arg_len_ap + 1) + if base_buf_ap is not None and arg_buf_ap is not None: + string.strncpy(base_buf_ap, ap_spec_nm, base_len_ap) + base_buf_ap[base_len_ap] = '\0' + string.strncpy(arg_buf_ap, lbkt_ap + 1, arg_len_ap) + arg_buf_ap[arg_len_ap] = '\0' + args_ap: list[str] | t.CPtr = list[str](pool, 8) + if args_ap is not None: + # 逗号分隔多类型实参(list[X] / dict[K, V]) + cur_ap: str = arg_buf_ap + while cur_ap is not None: + comma_ap: str = string.strchr(cur_ap, ',') + if comma_ap is None: + args_ap.append(cur_ap) + break + seg_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(comma_ap) - t.CUInt64T(cur_ap)) + seg_buf_ap: str = pool.alloc(seg_len_ap + 1) + if seg_buf_ap is not None: + string.strncpy(seg_buf_ap, cur_ap, seg_len_ap) + seg_buf_ap[seg_len_ap] = '\0' + args_ap.append(seg_buf_ap) + cur_ap = comma_ap + 1 + self.Gen.ClassGenGeneric._specialize_generic_class( + trans, base_buf_ap, args_ap) + # 调用名 "{sha1}.{spec}.append": + # sha1(16) + '.'(1) + spec + '.append'(7) + NUL(1) = spec + 25。 + # 此前 +8 少 1 字节,snprintf 截断末尾 'd' → + # undefined symbol: ...list[AST|CPtr].appen(缺 d)。 + ap_mlen: t.CSizeT = string.strlen(ap_sha1) + \ + string.strlen(ap_spec_nm) + 26 + ap_mangled: str = pool.alloc(ap_mlen) + if ap_mangled is not None: + viperlib.snprintf(ap_mangled, ap_mlen, "%s.%s.append", + ap_sha1, ap_spec_nm) + ap_item_node: ast.AST | t.CPtr = cargs.get(0) + ap_item_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, ap_item_node, None, 0, trans) + if ap_item_val is not None: + llvmlite.value_set_next(lm_obj, None) + llvmlite.value_set_next(ap_item_val, None) + llvmlite.value_set_next(lm_obj, ap_item_val) + ap_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + self._ensure_method_declare(pool, mod, ap_mangled, ap_ret_ty, lm_obj, 2) + return llvmlite.build_call(builder, ap_mangled, lm_obj, 2, ap_ret_ty, 0) + return None \ No newline at end of file diff --git a/App/lib/core/Gen/CallGenMixin.vp b/App/lib/core/Gen/CallGenMixin.vp index 5ddc48e..fb11acb 100644 --- a/App/lib/core/Gen/CallGenMixin.vp +++ b/App/lib/core/Gen/CallGenMixin.vp @@ -1,1151 +1,1202 @@ -import lib.core.Gen.GenTypes as GenTypes -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import sys -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.StubMerger as StubMerger -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.CompilerFactory as CompilerFactory - - -import lib.core.Gen.CallGenBase as CallGenBase -import lib.core.Handles.ExprCallTable as ExprCallTable - - -# ============================================================ -# CallGenMixin - 调用分派 Mixin(拆分后顶层,阶段 A:底层已拆至 -# CallGenBase/CallGenCBuiltin/CallGenLeafKit) -# -# 500~1500 行/文件架构重构阶段 A:底层自包含组(模块查找/返回类型解析/ -# c.*/asm/llvmir/EH/isinstance/闭包/print/函数表)已拆出,本文件保留 -# 调用分派中枢(translate_call 等)。继承链 CallGenMixin → LeafKit → -# CBuiltin → Base,@t.NoVTable 静态绑定沿 MRO 解析 self 调用。 -# -# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 -# ============================================================ - - -# ============================================================ -# 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug) -# ============================================================ -GLOBAL_FUNC_MAX: t.CDefine = 8192 -GLOBAL_DEFAULTS_MAX: t.CDefine = 4096 -_CEXPORT_MAX: t.CDefine = 256 -ASM_MAX_OPERANDS: t.CDefine = 16 -ASM_TEXT_BUF_SIZE: t.CDefine = 2048 -ASM_CONST_BUF_SIZE: t.CDefine = 512 -ASM_ARGS_BUF_SIZE: t.CDefine = 512 -ASM_LINE_BUF_SIZE: t.CDefine = 4096 -LLVMIR_MAX_OPS: t.CDefine = 16 -LLVMIR_TEMPLATE_BUF: t.CDefine = 512 -# 闭包名表大小(原 HandlesExprCall 模块级常量) -MAX_CLOSURE_NAMES: t.CDefine = 128 -# 函数指针签名表大小(原 HandlesExprCall 模块级常量) -MAX_FUNC_PTR_SIGS: t.CDefine = 64 -# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32) -ISINSTANCE_CLASS_MAX: t.CDefine = 64 - - -# ============================================================ -# CallGenMixin - 调用分派中枢(顶层,继承 LeafKit) -# ============================================================ -@t.NoVTable -class CallGenMixin(CallGenBase.CallGenBase): - """调用分派 Mixin(拆分后顶层,直接继承 CallGenBase——TPV self 调用仅支持 1 级父类)""" - - # ============================================================ - # 翻译函数调用 Call(func, args) — 模块级版本 - # ============================================================ - def translate_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译函数调用,返回 call 结果 Value""" - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) - if cl is None: - return None - - func_name: str = self.Gen.ExprGenBase.get_func_name(cl.func) - - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - can: t.CSizeT = 0 - if cargs is not None: - can = len(cargs) - - # super()/ctraits 检测:void 方法(如 __init__)命中后 build_call 返回 - # None 属预期(void call 无 SSA 值),必须用 hit_box 区分"命中已处理" - # 与"未命中",否则 None 被误判继续主路径 → 内层 Call(super) 当裸名 - # 调用报"super 未定义且未导入"(SuperTest 根因)。 - h1_hit: t.CPtr = stdlib.malloc(4) - if h1_hit is not None: - h1_hit[0] = 0 - _tc_h1_super_ctraits_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._tc_h1_super_ctraits( - pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can, h1_hit) - h1_hit_val: int = 0 - if h1_hit is not None: - h1_hit_val = h1_hit[0] - stdlib.free(h1_hit) - if _tc_h1_super_ctraits_res is not None: - return _tc_h1_super_ctraits_res - if h1_hit_val != 0: - # 命中 super()/ctraits 但无返回值(void 方法/宏调用):视为已处理 - return None - - # ---- func_name is None:泛型实例化 + 类型转换 ---- - if func_name is None: - # 检查是否是 list[int](pool) 形式的泛型实例化调用 - # Subscript 节点作为 Call func: 泛型类构造函数 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Subscript and trans is not None: - sub_node: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(cl.func) - if sub_node.value is not None and sub_node.value.kind() == ast.ASTKind.Name: - gen_nm_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_node.value) - gen_class_name: str = gen_nm_node.id - # 检查是否是泛型类模板 - template_cd: ast.ClassDef | t.CPtr = self.Gen.ClassGenGeneric._find_generic_template(gen_class_name) - if template_cd is not None: - # 提取类型实参 - gen_type_args: list[str] | t.CPtr = self.Gen.CallGenCtor._extract_type_args_from_slice(pool, sub_node.slice) - if gen_type_args is not None and len(gen_type_args) > 0: - # 特化泛型类,返回特化类名 - spec_name: str = self.Gen.ClassGenGeneric._specialize_generic_class( - trans, gen_class_name, gen_type_args) - if spec_name is not None: - # 泛型类构造调用: list[str](pool, 8) → __new__ + __before_init__ + __init__ - # 不能直接用 spec_name 作为 func_name(会走裸名调用路径, - # 被 star import 回退误导用错误的 SHA1,且缺少 __new__ 方法名后缀) - return self.Gen.CallGenCtor._translate_generic_ctor_call( - pool, builder, mod, spec_name, cl, trans) - else: - # 泛型类模板未找到:可能是泛型函数手动传类型参数调用 xxx[T](x) - # (对应 TPC _HandleGenericCallExplicitLlvm;TPV 无泛型函数特化, - # 泛型函数按普通函数编译,类型参数 [T] 仅在函数定义处消费)。 - # 检查当前模块是否已定义同名函数(def double[T] 编译后即普通函数 - # double),若是则丢弃 [t.CInt] 显式类型参数,退回普通函数调用。 - if self.find_func_in_module(mod, gen_class_name) is not None: - func_name = gen_class_name - else: - # 泛型类模板未找到:可能未 import 定义模块 - gt_err: str = pool.alloc(256) - if gt_err is not None: - viperlib.snprintf(gt_err, 256, "泛型类 '%s' 未找到模板,可能未 import 定义模块", gen_class_name) - self.Gen.TypeGenErr.fatal_error(gen_nm_node, gt_err) - self.Gen.TypeGenErr.fatal_error(gen_nm_node, "泛型类模板未找到") - if func_name is None: - # 检查是否是 (A | t.CPtr)(value) 形式的类型转换 - # BinOp 节点作为 Call func: 联合类型注解用作类型转换 - if cl.func is not None and cl.func.kind() == ast.ASTKind.BinOp and trans is not None: - binop_ty: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( - pool, cl.func, trans._imported_modules, trans._from_imports, trans) - if binop_ty is not None: - binop_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if binop_args is not None and len(binop_args) == 1: - binop_arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, binop_args.get(0), funcs_ptr, func_count, trans) - if binop_arg_val is not None: - return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, binop_arg_val, binop_ty) - return None - - # c.Asm/c.LLVMIR 等特殊调用:void(无输出)时 translate_c_asm/llvmir - # 返回 None 表示"已处理无返回值",需用 hit_box 区分"未命中", - # 否则会误判未命中继续走外部函数路径(外部函数返回类型未登记 Asm + - # t.ASM_DESCR 被当 CDefine 常量赋值) - h2_hit: t.CPtr = stdlib.malloc(4) - if h2_hit is not None: - h2_hit[0] = 0 - _tc_h2_c_special_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._tc_h2_c_special( - pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can, h2_hit) - h2_hit_val: int = 0 - if h2_hit is not None: - h2_hit_val = h2_hit[0] - stdlib.free(h2_hit) - if _tc_h2_c_special_res is not None: - return _tc_h2_c_special_res - if h2_hit_val != 0: - # 命中 c.Asm/c.LLVMIR 但无返回值(void):视为已处理 - return None - - _tc_h3_stdarg_cast_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._tc_h3_stdarg_cast( - pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) - if _tc_h3_stdarg_cast_res is not None: - return _tc_h3_stdarg_cast_res - - _tc_h4_type_casts_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._tc_h4_type_casts( - pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) - if _tc_h4_type_casts_res is not None: - return _tc_h4_type_casts_res - - _tc_h5_sizeof_len_isinst_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._tc_h5_sizeof_len_isinst( - pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) - if _tc_h5_sizeof_len_isinst_res is not None: - return _tc_h5_sizeof_len_isinst_res - - # c.Asm/c.LLVMIR 等方法调用分派:方法调用识别成功但返回 None - # (如编译器生成方法 __before_init__/__init__ 恒返回 void,_translate_ - # method_call 或 _emit_eh_guarded_call 处理后可能返回 None)时,须用 - # hit_box 区分"已识别为方法调用"与"未命中",否则 translate_call 误判 - # 未命中继续走跨模块函数路径,把对象名当模块名查 SHA1 → - # "跨模块调用 'buf.__before_init__' 找不到模块 SHA1"(memhub.alloc_buf 根因)。 - h6_hit: t.CPtr = stdlib.malloc(4) - if h6_hit is not None: - h6_hit[0] = 0 - _tc_h6_method_dispatch_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._tc_h6_method_dispatch( - pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can, h6_hit) - h6_hit_val: int = 0 - if h6_hit is not None: - h6_hit_val = h6_hit[0] - stdlib.free(h6_hit) - if _tc_h6_method_dispatch_res is not None: - return _tc_h6_method_dispatch_res - if h6_hit_val != 0: - # 命中方法调用路径但无返回值(编译器生成方法等 void 语义):视为已处理 - return None - - # 获取关键字参数 - keywords: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords - kw_count: t.CSizeT = 0 - if keywords is not None: - kw_count = len(keywords) - - # 检查是否是结构体构造函数: Point() / Point(10, 20) / Point(x=10, y=20) - # 命名空间隔离:严格模式下检查结构体可见性 - # - 裸名 Class(): 需要 from X import Class 或本地定义 - # - 模块限定 Module.Class(): 需要 import Module - # 用 find_struct_by_module 规避跨模块同名 find_struct 找错 - struct_ty: llvmlite.LLVMType | t.CPtr = None - gen_ctor_entry: GenTypes.StructEntry | t.CPtr = None - vis: int = self.Gen.StructGen.is_struct_visible(func_name) - if vis != 0: - if trans is not None: - gen_ctor_entry = self.Gen.StructGen.find_struct_by_module(func_name, trans.ModuleSha1) - if gen_ctor_entry is None: - gen_ctor_entry = self.Gen.StructGen.find_struct(func_name) - if gen_ctor_entry is not None: - struct_ty = gen_ctor_entry.Ty - elif trans is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - at_qc: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if at_qc.value is not None and at_qc.value.kind() == ast.ASTKind.Name: - mod_nm_qc: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_qc.value) - imp_ok: int = self.Gen.ImportsGen.is_module_imported(trans._imported_modules, mod_nm_qc.id) - if imp_ok != 0: - if trans is not None: - gen_ctor_entry = self.Gen.StructGen.find_struct_by_module(func_name, trans.ModuleSha1) - if gen_ctor_entry is None: - gen_ctor_entry = self.Gen.StructGen.find_struct(func_name) - if gen_ctor_entry is not None: - struct_ty = gen_ctor_entry.Ty - elif at_qc.value is not None and at_qc.value.kind() == ast.ASTKind.Attribute: - # 多层模块路径类构造: w32.fileio.File(...)(value 是嵌套 Attribute)。 - # 仅两层(fileio.File)支持时,三层会被跳过 → 退化走跨模块普通函数 - # 调用生成 @File 裸名 → 链接 undefined symbol: File(SysLibTest 根因)。 - # 模块路径经 attr_module_path_str 递归拼接("w32.fileio"), - # import 检查用完整路径(import w32.fileio 注册 "w32.fileio"), - # 结构体查找用该模块自身 SHA1 精确命中(find_struct_by_module)。 - # 注:经 HandlesExpr 委托调用(跨 mixin 不能 self. 直接调, - # @t.NoVTable 静态绑定会 mangle 成 CallGenMixin. 前缀 → undefined reference)。 - mod_path_qc: str = self.Gen.ExprGenAttr._attr_module_path_str(pool, at_qc.value) - if mod_path_qc is not None: - imp_ok_qc: int = self.Gen.ImportsGen.is_module_imported( - trans._imported_modules, mod_path_qc) - if imp_ok_qc != 0: - mod_sha1_qc: str = self._lookup_module_sha1(mod_path_qc) - if mod_sha1_qc is not None: - gen_ctor_entry = self.Gen.StructGen.find_struct_by_module( - func_name, mod_sha1_qc) - if gen_ctor_entry is None: - gen_ctor_entry = self.Gen.StructGen.find_struct(func_name) - if gen_ctor_entry is not None: - struct_ty = gen_ctor_entry.Ty - # 别名导入的类构造: from X import Class as Alias → Alias(args) - # 可见性列表按别名注册(HandleImportFromNames 用 local_name=asname),但结构体 - # 按原名注册(如 Keyword as KwNode → 可见 "KwNode"、注册名 "Keyword")。 - # 直接按别名 find_struct 查不到 → 误走普通函数路径生成 @sha1.Keyword 调用 - # (该函数不存在)→ 链接期 undefined reference。此处解析别名→原名再查结构体。 - if gen_ctor_entry is None and trans is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Name: - if trans._from_imports is not None: - ctor_sha1: str = self._lookup_mod_sha1(pool, trans._from_imports, func_name, 0) - if ctor_sha1 is not None: - ctor_orig: str = self.Gen.ImportsGen.lookup_from_import_original( - trans._from_imports, func_name) - if ctor_orig is not None: - # 复制到独立 null 终止缓冲区(from_imports 内部缓冲未终止) - co_len: t.CSizeT = 0 - while ctor_orig[co_len] != ' ' and ctor_orig[co_len] != '\0': - co_len += 1 - co_buf: str = pool.alloc(co_len + 1) - if co_buf is not None: - for co_i in range(co_len): - co_buf[co_i] = ctor_orig[co_i] - co_buf[co_len] = '\0' - # 原名结构体查找(可见性已由别名保证,原名无需再查) - gen_ctor_entry = self.Gen.StructGen.find_struct_by_module(co_buf, ctor_sha1) - if gen_ctor_entry is None: - gen_ctor_entry = self.Gen.StructGen.find_struct(co_buf) - if gen_ctor_entry is not None: - struct_ty = gen_ctor_entry.Ty - func_name = co_buf - if struct_ty is not None: - if can == 0 and kw_count == 0: - # OOP 结构体:即使无参数也调用 __before_init__ - # 用 gen_ctor_entry 规避跨模块同名 find_struct 找错 - ctor_is_oop: int = 0 - if gen_ctor_entry is not None: - ctor_is_oop = gen_ctor_entry.IsOOP - if ctor_is_oop != 0: - return self.Gen.CallGenCtor._translate_struct_ctor( - pool, builder, mod, struct_ty, func_name, cargs, 0, trans) - # @t.NoVTable 类(无方法、类语义/指针对象):无参构造也应分配内存 - # 返回指针。否则按值结构体返回 ConstZero(struct_ty),LHS 联合注解 - # (如 Plain|CPtr)存 0 指针 → p.v 解引用 NULL 段错误 - # (TpvIsinstanceTest Plain 场景崩溃根因)。 - ctor_is_novt: int = 0 - if gen_ctor_entry is not None: - ctor_is_novt = gen_ctor_entry.IsNoVTable - if ctor_is_novt != 0: - return self.Gen.CallGenCtor._translate_struct_ctor( - pool, builder, mod, struct_ty, func_name, cargs, 0, trans) - # 普通结构体:检查是否有默认值(用 entry 直接访问) - gen_has_defaults: int = 0 - if gen_ctor_entry is not None: - for gdi in range(gen_ctor_entry.FieldCount): - gdf: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry( - gen_ctor_entry, gdi) - if gdf is not None and gdf.DefaultVal is not None: - gen_has_defaults = 1 - break - else: - gen_has_defaults = self.Gen.StructGen.struct_has_defaults(func_name) - if gen_has_defaults == 1: - # 有默认值:走构造函数路径应用默认值 - return self.Gen.CallGenCtor._translate_struct_ctor( - pool, builder, mod, struct_ty, func_name, cargs, 0, trans) - # 无默认值:返回 zeroinitializer - ret: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) - return ret - if kw_count > 0: - # 有关键字参数:按字段名赋值 - return self.Gen.CallGenCtor._translate_struct_ctor_kw( - pool, builder, mod, struct_ty, func_name, cargs, can, - keywords, kw_count, trans) - # 仅位置参数:按字段顺序构建 - return self.Gen.CallGenCtor._translate_struct_ctor( - pool, builder, mod, struct_ty, func_name, cargs, can, trans) - - # 裸名泛型类模板构造: Box(42) → 从实参推断类型实参 → 特化 → 构造 - # (TPC 参考: _HandleGenericClassNewLlvm;GenericTest Test4 Box(42)/Test5 - # Pair(10,20)/Test10 Counter(0) 依赖此路径。显式类型实参 list[int](mb) - # 走 translate_call 上方的 Subscript 分支,此处处理裸名 + 推断。) - # 支持模块限定调用(vector.Vector(...)):func_name 是 attr("Vector"), - # 需确认模块已导入(模板查找兜底——普通函数如 stdlib.free 的 attr 找 - # 不到模板 → 回落普通调用)。 - if struct_ty is None and gen_ctor_entry is None and trans is not None: - is_gen_bare: int = 0 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: - is_gen_bare = 1 - elif cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - at_gb: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if at_gb.value is not None and at_gb.value.kind() == ast.ASTKind.Name: - am_gb: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_gb.value) - if am_gb.id is not None: - if self.Gen.ImportsGen.is_module_imported(trans._imported_modules, am_gb.id) != 0: - is_gen_bare = 1 - if is_gen_bare != 0: - template_cd_bare: ast.ClassDef | t.CPtr = self.Gen.ClassGenGeneric._find_generic_template(func_name) - if template_cd_bare is not None and template_cd_bare.type_params is not None: - tp_bare: list[str] | t.CPtr = template_cd_bare.type_params - tp_count_bare: t.CSizeT = len(tp_bare) - if tp_count_bare > 0: - inferred_args_bare: list[str] | t.CPtr = list[str](pool, 8) - if inferred_args_bare is not None: - # 对齐 TPC _HandleGenericClassNewLlvm:先收集全部实参 - # 推断类型,过滤纯 int(排除 pool 等非 T 参数), - # hint_types 优先填充(Vector(pool,8,CFloat64T(0.0)) - # → Vector[double];Vector(pool,10,CInt(0)) → Vector[int]) - hint_bare: list[str] | t.CPtr = list[str](pool, 8) - if hint_bare is not None: - hi_bare: t.CSizeT - for hi_bare in range(can): - hty_bare: str = self.Gen.CallGenCtor._infer_generic_ctor_type_arg(pool, cargs.get(hi_bare), func_name) - if string.strcmp(hty_bare, "int") != 0: - hint_bare.append(hty_bare) - tpi_bare: t.CSizeT = 0 - for tpi_bare in range(tp_count_bare): - ta_bare: str = "int" - if tpi_bare < len(hint_bare): - ta_bare = hint_bare.get(tpi_bare) - elif tpi_bare < can: - ta_bare = self.Gen.CallGenCtor._infer_generic_ctor_type_arg(pool, cargs.get(tpi_bare), func_name) - inferred_args_bare.append(ta_bare) - spec_name_bare: str = self.Gen.ClassGenGeneric._specialize_generic_class( - trans, func_name, inferred_args_bare) - if spec_name_bare is not None: - return self.Gen.CallGenCtor._translate_generic_ctor_call( - pool, builder, mod, spec_name_bare, cl, trans) - - # REnum 变体构造检测: ClassName.VariantName(args...) - # 如 LLVMType.Int(1) → 构造 LLVMType 的 Int 变体 - # 必须在跨模块调用查找之前,否则 ClassName 会被误判为模块名 - # 对应 TPC HandlesExprCall.py:585-644 的三条检测路径之一 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - rc_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if rc_at.value is not None and rc_at.value.kind() == ast.ASTKind.Name: - rc_cls_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rc_at.value) - if rc_cls_node.id is not None: - rc_cls_name: str = rc_cls_node.id - # 检查 ClassName 是否是已注册的 REnum 类 - if self.Gen.ClassGenEnum._is_renum_class_name(rc_cls_name) != 0: - # 在该 REnum 类中查找变体名 func_name - rc_tag: int = self.Gen.ClassGenEnum._lookup_renum_variant_in_class( - rc_cls_name, func_name) - if rc_tag >= 0: - return self.Gen.CallGenCtor._translate_renum_construct( - pool, builder, mod, rc_cls_name, func_name, - rc_tag, cargs, can, trans) - elif rc_at.value is not None and rc_at.value.kind() == ast.ASTKind.Attribute: - # 模块限定 REnum 变体构造: mod.Class.Variant(args...) - # 如 llvmlite.LLVMType.Struct(...) → 构造 llvmlite 模块 LLVMType 的 Struct 变体。 - # 根因:此前只支持单层 Name(ClassName.Variant),嵌套属性漏检 → 误走跨模块 - # 函数路径 → _lookup_module_sha1("llvmlite.LLVMType") 查无 → 报"跨模块调用 - # 'llvmlite.LLVMType.Struct' 找不到模块 SHA1"。跨模块任意同名可接受(REnum - # 表按类名全局注册):仅要求最左模块已导入 + 末段类名在全局 REnum 表中命中, - # 不做"类必须属于该模块"校验(未命中则按后续函数路径 fast-fail)。 - rc_mq_path: str = self.Gen.ExprGenAttr._attr_module_path_str(pool, rc_at.value) - if rc_mq_path is not None: - rc_mq_dot: str = string.strrchr(rc_mq_path, 46) # 46 = ord('.') - if rc_mq_dot is not None and rc_mq_dot[1] != '\0': - # 模块路径 = 末段之前(支持多级: w32.fileio.Class.Variant)。 - # 注意:不能用 rc_mq_dot - rc_mq_path 指针减法(TPC 直接发 - # sub i8*, i8* 非法 IR),用 strlen 整数差扣除末段与分隔点。 - rc_mq_len: t.CSizeT = string.strlen(rc_mq_path) - string.strlen(rc_mq_dot + 1) - 1 - rc_mq_mod: str = pool.alloc(rc_mq_len + 1) - if rc_mq_mod is not None: - string.memcpy(rc_mq_mod, rc_mq_path, rc_mq_len) - rc_mq_mod[rc_mq_len] = '\0' - rc_mq_imp: int = 1 - if trans is not None and trans._imported_modules is not None: - rc_mq_imp = self.Gen.ImportsGen.is_module_imported( - trans._imported_modules, rc_mq_mod) - if rc_mq_imp != 0: - rc_mq_cls: str = rc_mq_dot + 1 - # 检查类名是否是已注册的 REnum 类 - if self.Gen.ClassGenEnum._is_renum_class_name(rc_mq_cls) != 0: - rc_mq_tag: int = self.Gen.ClassGenEnum._lookup_renum_variant_in_class( - rc_mq_cls, func_name) - if rc_mq_tag >= 0: - return self.Gen.CallGenCtor._translate_renum_construct( - pool, builder, mod, rc_mq_cls, func_name, - rc_mq_tag, cargs, can, trans) - - # 查找函数:优先从函数表按裸名精确匹配(同模块函数), - # 再从模块函数链表按后缀匹配(SHA1 前缀名)。 - # 注意:模块限定/属性调用(如 stdlib.free)不能做后缀匹配—— - # "free" 会误命中 viperio.Buf.free 等方法,导致普通 malloc 指针被 - # 当作 Buf 对象释放(Buf.free 读 self 字段/写 self.data), - # 传入句柄数组等指针时把句柄值当地址写入直接崩溃。 - # 后缀匹配仅用于裸名调用(cl.func 是 Name,如 _thread_alloc_free)。 - # stubs 在翻译后才注入,翻译时跨模块函数 found_func 通常为 None, - # 此时根据函数名推断 includes 库函数的返回类型(如 strchr 返回 i8*) - # 如果调用方未传 funcs_ptr/func_count(如 AnnAssign 路径),从 trans 获取 - actual_funcs: GenTypes.FuncEntry | t.CPtr = funcs_ptr - actual_func_count: int = func_count - if actual_funcs is None and trans is not None: - actual_funcs = trans._funcs - actual_func_count = trans._func_count - found_func: llvmlite.Function | t.CPtr = None - if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: - # 裸名调用:允许精确 + 后缀匹配 - # 自定义装饰器 wrapper 重写:原函数名 → __decor_wrap_{name} - # (对齐 TPC DecoratorPass.run 的 _redirect_calls;wrapper 在函数 - # 翻译末尾生成,同 pass 内 main 调用点晚于被装饰函数定义,可达) - decor_wrap_nm: str = self.Gen.ClassGenBase.lookup_decor_wrapper(func_name) - if decor_wrap_nm is not None: - found_func = self.find_func_in_module(mod, decor_wrap_nm) - else: - found_func = self.find_func_in_module(mod, func_name) - # 治本修复(对齐 Attribute 路径 L6579-6613):后缀匹配误命中类方法 - # (SHA1.Class.method,第 2 段是已注册结构体类)必须拒绝——否则方法体内 - # 与 from-import 模块函数同名的裸名调用(如 LLVMModuleCore.SSAValue 内 - # 的 SSAValue(self.Pool, ...))绑定到本类方法 define → 无限递归 - # (栈溢出 0xC0000005)。裸名调用应优先解析为模块级函数 - # (同模块函数表 / from_imports),方法调用需显式 obj.method。 - if found_func is not None: - bn_name: str = llvmlite.function_get_name(found_func) - if bn_name is not None: - bn_dots: int = 0 - bni2: t.CSizeT = 0 - while bn_name[bni2] != '\0': - if bn_name[bni2] == '.': - bn_dots += 1 - bni2 += 1 - if bn_dots >= 2: - # 提取第 2 段(SHA1.Class.method → Class;SHA1.submod.func → submod) - bn_seg2: str = pool.alloc(64) - if bn_seg2 is not None: - bn_seg2[0] = '\0' - bsi2: t.CSizeT = 0 - while bn_name[bsi2] != '\0' and bsi2 < 17: - bsi2 += 1 - bse2: t.CSizeT = bsi2 - while bn_name[bse2] != '\0' and bn_name[bse2] != '.': - bse2 += 1 - bsl2: t.CSizeT = bse2 - bsi2 - if bsl2 > 0 and bsl2 < 63: - string.strncpy(bn_seg2, bn_name + bsi2, bsl2) - bn_seg2[bsl2] = '\0' - # 第 2 段是已注册结构体类 → 是方法,拒绝(走模块 SHA1 路径) - if self.Gen.StructGen.get_struct_type(bn_seg2) is not None: - found_func = None - else: - # 模块限定/属性调用:精确匹配优先,后缀匹配仅接受模块函数。 - # 后缀匹配命中的"方法"(SHA1.Class.method,Class 是已注册类)必须拒绝—— - # 短方法名(free/reset/close 等)会误命中其他模块的方法 - # (如 stdlib.free 命中 viperio.Buf.free,普通指针被当 Buf 释放崩溃; - # 且 atom.__atomic_test_and_set 若被误拒,返回类型从 i1 推断成 i32, - # 调用按 i32 读 i1 返回值读到垃圾高位,spinlock 恒非 0 卡死)。 - # 模块函数(SHA1.func)或子模块函数(SHA1.submod.func)的后缀匹配保留。 - found_func = self.find_func_in_module(mod, func_name) - if found_func is not None: - # 模块限定调用(mod.func,value 是已导入模块名):校验 found_func - # 的 SHA1 前缀必须等于该模块。否则 find_func_in_module 第 3 遍对 - # stub declare 的后缀匹配会误命中其他模块的同名函数(如 main 模块 - # 里 subprocess 的 declare 先注入,syslibtest_impl.run() 后缀匹配 - # 误命中 subprocess.run → call 到错误符号 → 参数错位解引用崩溃, - # SysLibTest 0xC0000005 根因)。误命中时拒绝(found_func=None), - # 落到下方跨模块模块限定解析用模块自身 SHA1 构造正确符号。 - xm_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if xm_at is not None and xm_at.value is not None and trans is not None \ - and trans._imported_modules is not None: - # 模块路径:单层 Name(syslibtest_impl.run)或嵌套 Attribute - # (os._win32.exists)。后者此前不校验 → os/__init__.vp 内部 - # 调 os._win32.exists 后缀匹配命中本模块同名 define → - # 无限递归栈溢出(SysLibTest 0xC00000FD 根因)。 - xm_mod_path: str = None - if xm_at.value.kind() == ast.ASTKind.Name: - xm_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(xm_at.value) - if xm_nm.id is not None: - xm_mod_path = xm_nm.id - elif xm_at.value.kind() == ast.ASTKind.Attribute: - xm_mod_path = self.Gen.ExprGenAttr._attr_module_path_str( - pool, xm_at.value) - if xm_mod_path is not None: - if self.Gen.ImportsGen.is_module_imported( - trans._imported_modules, xm_mod_path) != 0: - mod_sha1_chk: str = self._lookup_module_sha1(xm_mod_path) - if mod_sha1_chk is not None: - ff_nm2: str = llvmlite.function_get_name(found_func) - if ff_nm2 is not None: - if string.strncmp(ff_nm2, mod_sha1_chk, 16) != 0: - found_func = None - ff_name: str = llvmlite.function_get_name(found_func) - if ff_name is not None: - ff_dots: int = 0 - ffi2: t.CSizeT = 0 - while ff_name[ffi2] != '\0': - if ff_name[ffi2] == '.': - ff_dots += 1 - ffi2 += 1 - if ff_dots >= 2: - # 提取第 2 段(SHA1.Class.method → Class;SHA1.submod.func → submod) - seg2: str = pool.alloc(64) - if seg2 is not None: - seg2[0] = '\0' - si: t.CSizeT = 0 - while ff_name[si] != '\0' and si < 17: - si += 1 - seg_start: t.CSizeT = si - seg_end: t.CSizeT = si - while ff_name[seg_end] != '\0' and ff_name[seg_end] != '.': - seg_end += 1 - seg_len: t.CSizeT = seg_end - seg_start - if seg_len > 0 and seg_len < 63: - string.strncpy(seg2, ff_name + seg_start, seg_len) - seg2[seg_len] = '\0' - # 第 2 段是已注册结构体类 → 是方法,拒绝(走模块 SHA1 路径) - if self.Gen.StructGen.get_struct_type(seg2) is not None: - found_func = None - # C 库函数裸名调用支持:若模块中找不到且是已知 C 库函数,自动创建 declare - # 对应 TPC 的 _C_LIB_FUNCS 机制,支持 memset/memmove/memcmp/strcmp 等裸名调用 - if found_func is None and cl.func is not None and cl.func.kind() == ast.ASTKind.Name: - found_func = self.Gen.CallGenLib._ensure_c_lib_declare(pool, mod, func_name) - # builtins 自动关联:C 库未命中时,自动关联 builtins 模块的内置函数(ord/chr 等)。 - # builtins 已由编译链预加入(StubMerger 预加入列表)。PhaseA 期 builtins 尚未编译, - # 因此按约定签名创建 {builtins_sha1}.{name} 的 mangled declare(链接时解析到 - # builtins.vp 的真实定义);签名与 builtins.vp 保持一致:ord(i8)->i32, chr(i32)->i8。 - if found_func is None: - bi_sha1: str = self._lookup_module_sha1("builtins") - if bi_sha1 is not None: - bi_ret: llvmlite.LLVMType | t.CPtr = None - bi_p1: llvmlite.LLVMType | t.CPtr = None - if string.strcmp(func_name, "ord") == 0: - bi_ret = llvmlite.Int32(pool) - bi_p1 = llvmlite.Int8(pool) - elif string.strcmp(func_name, "chr") == 0: - bi_ret = llvmlite.Int8(pool) - bi_p1 = llvmlite.Int32(pool) - if bi_ret is not None: - bi_sym: str = func_name - if self.Gen.CallGenBase.is_cexport_func(bi_sha1, func_name) == 0: - bi_sym_len: t.CSizeT = string.strlen(bi_sha1) + string.strlen(func_name) + 2 - bi_sym_buf: str = pool.alloc(bi_sym_len) - if bi_sym_buf is not None: - viperlib.snprintf(bi_sym_buf, bi_sym_len, "%s.%s", bi_sha1, func_name) - bi_sym = bi_sym_buf - bi_decl: llvmlite.Function | t.CPtr = llvmlite.create_declare( - pool, mod, bi_sym, bi_ret) - if bi_decl is not None: - llvmlite.add_param(pool, bi_decl, bi_p1, "v") - found_func = bi_decl - # 使用访问器绕过 stub 类型限制 - found_ret_ty: llvmlite.LLVMType | t.CPtr = None - found_params: t.CPtr = None - if found_func is not None: - found_ret_ty = llvmlite.function_get_ret_ty(found_func) - found_params = llvmlite.function_get_params(found_func) - if found_ret_ty is not None: - call_ret_ty: llvmlite.LLVMType | t.CPtr = found_ret_ty - else: - # found_func=None(跨模块 stub 未注入):先从 vpi stub 返回注解 - # 缓存精确获取返回类型(含 tuple[T1,T2] → 匿名结构体,如 - # b2a_hqx -> tuple[str, t.CUnsignedShort] → {i8*, i16}), - # 未命中才回退 _infer_external_func_ret_ty 白名单推断。 - # 根因:_infer 白名单无 tuple 概念,未知函数默认 i32 会截断 - # 指针/i64;b2a_hqx 被推断为单值 i8*/i32 后调用侧返回值类型 - # 与定义侧 {i8*, i16} 不匹配 → HandlesAssign 的 tuple 解包 - # (依赖 rhs_val.Ty 是 Struct)静默跳过 → 目标变量从未赋值 → - # free 未初始化栈垃圾指针崩溃(HashLibTest hqx 段)。 - vpi_ret_ty: llvmlite.LLVMType | t.CPtr = None - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - at_ret: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if at_ret.value is not None and at_ret.value.kind() == ast.ASTKind.Name: - mod_ret_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_ret.value) - if mod_ret_nm.id is not None: - mod_ret_sha1: str = self._lookup_module_sha1(mod_ret_nm.id) - if mod_ret_sha1 is not None: - # 函数内懒 import:VpiReader imports HandlesExprCall, - # 顶层 import 会成环(与 _lookup_method_ret_ty_via_vpi 一致) - import lib.StubGen.VpiReader as VpiReader - VpiReader._ensure_vpi_ret_annot_loaded(mod_ret_sha1, self.Gen.CallGenBase.TempDir) - ret_annot_fc: str = VpiReader._lookup_vpi_ret_annot( - mod_ret_sha1, None, func_name) - if ret_annot_fc is not None: - vpi_ret_ty = VpiReader._resolve_vpi_ret_annot_str( - pool, ret_annot_fc, - llvmlite.Int32(pool), - llvmlite.Ptr(pool, llvmlite.Int8(pool))) - if vpi_ret_ty is not None: - call_ret_ty = vpi_ret_ty - else: - call_ret_ty = self.Gen.CallGenLib._infer_external_func_ret_ty(pool, func_name) - - # 如果模块中找不到函数,仅裸名调用(Name)才回退查局部变量(函数指针/ - # 闭包调用);模块属性调用(VLogger.fmt_buf())的目标是模块符号,绝不 - # 回退局部变量——跨模块任意同名可接受(CallGenLeafKit 局部 fmt_buf - # 曾劫持 VLogger.fmt_buf → 误走函数指针调用报 t.Callable 缺失), - # 仅 from-import 的裸名 yyy 与局部重名才可能冲突(该场景 func 是 Name)。 - if found_func is None: - fp_alloca: llvmlite.Value | t.CPtr = None - if cl.func is None or cl.func.kind() == ast.ASTKind.Name: - fp_alloca = self.Gen.VarGen.lookup_var(trans.SymTab, func_name) - if fp_alloca is not None: - # 闭包变量(嵌套函数提升,已注册到闭包名集合):提取 fn_ptr/env_ptr 间接调用 - if self.Gen.CallGenLeafKit.is_closure_name(func_name) != 0: - return self.Gen.CallGenLeafKit.translate_closure_call(pool, builder, mod, fp_alloca, - cargs, can, trans) - # 函数指针变量(t.Callable 注解 → i8** alloca):按实参构造签名间接调用 - if self.Gen.CallGenLeafKit._is_func_ptr_alloca(fp_alloca) != 0: - # 区分 t.Callable(真函数指针)vs t.CPtr(闭包指针): - # t.CPtr 变量(如 f: t.CPtr = make_counter())存的是闭包结构 - # {fn_ptr, env_ptr},调用必须提取 env 传参;若按函数指针直接 - # call,跳转到闭包结构数据地址崩溃(ClosureCallTest 运行时崩溃)。 - ve_fp: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( - trans.SymTab, func_name) - is_cptr_annot_fp: int = 0 - if ve_fp is not None and ve_fp.AnnotClassName is not None: - if string.strstr(ve_fp.AnnotClassName, "CPtr") is not None: - is_cptr_annot_fp = 1 - if is_cptr_annot_fp == 0: - return self.Gen.CallGenLeafKit._translate_func_ptr_call(pool, builder, mod, fp_alloca, - func_name, cargs, can, trans) - return self.Gen.CallGenLeafKit.translate_closure_call(pool, builder, mod, fp_alloca, - cargs, can, trans) - # 其他 i8* 变量按闭包调用路径处理 - return self.Gen.CallGenLeafKit.translate_closure_call(pool, builder, mod, fp_alloca, - cargs, can, trans) - - # 翻译参数并链接 - # 有关键字参数且找到函数定义时,按参数名匹配 - if kw_count > 0 and found_func is not None and found_params is not None: - return self.Gen.CallGenLib._translate_call_with_kwargs( - pool, builder, mod, func_name, found_func, - cargs, can, keywords, kw_count, trans) - - head: llvmlite.Value | t.CPtr = None - tail: llvmlite.Value | t.CPtr = None - # memcpy 专用: 收集前三个 Value 的独立引用(避免共享 alloca 对象的 Next 被污染) - mc_dst2: llvmlite.Value | t.CPtr = None - mc_src2: llvmlite.Value | t.CPtr = None - mc_num2: llvmlite.Value | t.CPtr = None - for ai in range(can): - arg: ast.AST | t.CPtr = cargs.get(ai) - if arg is not None: - arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, arg, None, 0, trans) - if arg_val is not None: - # 参数类型提升:当 found_func 为 None(stub 未注入)时, - # 根据外部函数签名推断期望类型,提升字面量(如 i32→i64) - # 避免 declare(i64) 与 call(i32) 类型不匹配 - if found_func is None and arg_val.Ty is not None: - # 数组实参按 C 语义衰减为元素指针(对齐 TPC - # _decay_array_to_ptr),与 _translate_method_call 一致。 - if self.Gen.ExprGenBase.is_ptr_type(arg_val.Ty) != 0: - arr_pointee_fc: llvmlite.LLVMType | t.CPtr = arg_val.Ty.Pointee - if arr_pointee_fc is not None: - match arr_pointee_fc: - case llvmlite.LLVMType.Array(arr_et_fc, _): - decayed_fc: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, arr_pointee_fc, arr_et_fc, arg_val, - llvmlite.const_int32(pool, 0)) - if decayed_fc is not None: - arg_val = decayed_fc - case _: - pass - ext_param_ty: llvmlite.LLVMType | t.CPtr = self.Gen.CallGenLib._get_external_func_param_ty( - pool, func_name, ai) - if ext_param_ty is not None: - val_bits_ap: int = self.Gen.ExprGenBase.get_llvm_type_bits(arg_val.Ty) - tgt_bits_ap: int = self.Gen.ExprGenBase.get_llvm_type_bits(ext_param_ty) - if val_bits_ap != 0 and tgt_bits_ap != 0 and val_bits_ap != tgt_bits_ap: - if val_bits_ap == 1 and val_bits_ap < tgt_bits_ap: - arg_val = llvmlite.build_zext(builder, arg_val, ext_param_ty) - else: - arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, ext_param_ty, arg) - elif found_func is not None: - # found_func 存在:按形参类型 coerce(如 stdlib.malloc(size: t.CSizeT)) - # 修复: CDefine/i32 常量传给 i64 形参未提升,导致 call(i32) 与 define(i64) 不匹配 - fp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) - fpi: int = 0 - while fp is not None and fpi < ai: - fp = llvmlite.param_get_next(fp) - fpi += 1 - if fp is not None: - fpty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(fp) - if fpty is not None: - arg_val = self.Gen.ExprGenBase.coerce_to_type( - builder, arg_val, fpty, arg) - elif found_func.IsVarArg == 1: - # Win64 变参 8 字节槽位:<64 位整数按 i64 传(sext 符号扩展), - # f32 提升为 f64。若按原窄类型传,调用点只写 4 字节进 8 字节槽, - # 高 4 字节残留旧栈数据,va_arg(i64) 读到垃圾(如 DefineTest - # PAGE=%d 读到 0x400921FB00001000,高位是 PI 残留)。 - # 对齐 TPC FuncGen/Python-llvmlite 的 ABI 自动提升。 - ab_va: int = self.Gen.ExprGenBase.get_llvm_type_bits(arg_val.Ty) - af_va: int = self.Gen.ExprGenBase.get_llvm_float_bits(arg_val.Ty) - i64_va: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - if ab_va != 0 and ab_va < 64: - arg_val = llvmlite.build_sext(builder, arg_val, i64_va) - elif af_va == 32: - arg_val = llvmlite.build_fpext( - builder, arg_val, llvmlite.Double(pool)) - arg_val.Next = None - if head is None: - head = arg_val - else: - tail.Next = arg_val - tail = arg_val - # memcpy 专用: 保存前三个参数的独立引用 - if ai == 0: - mc_dst2 = arg_val - elif ai == 1: - mc_src2 = arg_val - elif ai == 2: - mc_num2 = arg_val - - # 默认参数填充:当实参数量 < 形参数量时,用默认值填充缺失参数 - # defaults 数组右对齐到 args:defaults[0] 对应 args[offset],offset = param_count - default_count - if can > 0 or (can == 0 and cargs is not None): - df_defaults: t.CVoid | t.CPtr = None - df_default_count: int = 0 - df_param_count: int = 0 - # 先从当前模块函数表查找 FuncEntry - if trans is not None and trans._funcs is not None: - df_entry: FuncEntry | t.CPtr = ExprCallTable.find_func_entry_in_table( - trans._funcs, trans._func_count, func_name) - if df_entry is not None: - df_defaults = df_entry.Defaults - df_default_count = df_entry.DefaultCount - df_param_count = df_entry.ParamCount - # 无条件查询全局默认参数表(跨模块/同模块都要用 stdlib 常量快照 - # 重建默认值:模块表 Defaults 指向 pool 内 AST,跨 1b reset 后悬空; - # 快照才是跨文件永久存活。同模块命中时 gd_entry 也必须已赋值, - # 否则下方 _build_const_from_snapshot 读到未初始化栈垃圾指针崩溃。 - # 与 _translate_method_call 的 mdf_gd 无条件查询(L2677)保持一致。 - gd_entry: FuncDefaultsEntry | t.CPtr = self.Gen.CallGenLeafKit.find_func_defaults(func_name) - if df_defaults is None and gd_entry is not None: - df_defaults = gd_entry.Defaults - df_default_count = gd_entry.DefaultCount - df_param_count = gd_entry.ParamCount - # 填充缺失参数 - if df_defaults is not None and df_default_count > 0 and can < df_param_count: - df_offset: int = df_param_count - df_default_count - df_di: int = 0 - while df_di < df_default_count: - df_param_idx: int = df_offset + df_di - if df_param_idx >= can: - # 优先用 stdlib 常量快照重建(gd_entry.Defaults 的 pool 内 AST 可能已被 reset 回收) - df_arg_val: llvmlite.Value | t.CPtr = None - if gd_entry is not None: - df_arg_val = self.Gen.CallGenLeafKit._build_const_from_snapshot( - pool, mod, gd_entry, df_di, trans, builder) - if df_arg_val is None: - df_defaults_list: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(df_defaults), t.CPtr)) - df_default_node: ast.AST | t.CPtr = df_defaults_list.get(df_di) - if df_default_node is not None: - df_arg_val = self.Gen.ExprGen.translate_value( - builder, pool, mod, df_default_node, None, 0, trans) - if df_arg_val is not None: - df_arg_val.Next = None - if head is None: - head = df_arg_val - else: - tail.Next = df_arg_val - tail = df_arg_val - df_di += 1 - - # 使用模块中的实际函数名(可能带 SHA1 前缀,如 "83210a72e829a086.atoi") - # t.CExtern/t.State/t.CExport 函数不加 SHA1 前缀,使用裸名 - # declare 和 define 统一用 found_func.Name: - # - 普通函数的 declare/define 都带 SHA1 前缀(forward_declare_functions 和 stub 注入都用 mangled_name) - # - t.CExtern/t.State/t.CExport 函数的 declare/define 都用裸名 - # 旧逻辑(IsDeclared==1 时用 func_name 裸名)是错误的:stub 注入的 declare Name 已带 SHA1 前缀, - # 用裸名会导致 call @_PathToModuleName 而 define 是 @"sha1._PathToModuleName",链接报 undefined reference - call_name: str = func_name - # 原始函数名(别名导入时记录,如 from X import parse as json_parse → orig_func_name="parse") - # 用于在别名处理后重新推断返回类型,避免 _infer_external_func_ret_ty 用别名匹配失败 - orig_func_name: str = None - if found_func is not None: - found_name: str = llvmlite.function_get_name(found_func) - if found_name is not None: - call_name = found_name - else: - # 跨模块函数调用:found_func 为 None 时,检查是否是模块限定调用 - # 如 string.strchr(...) → @{sha1_of_string}.strchr - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - xmod_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if xmod_at.value is not None and (xmod_at.value.kind() == ast.ASTKind.Name - or xmod_at.value.kind() == ast.ASTKind.Attribute): - # 模块路径:单层 Name(string.strchr)或嵌套 Attribute - # (os._win32.exists)。嵌套路径此前不支持 → os/__init__.vp - # 内部调 os._win32.exists 只能被 find_func_in_module 后缀匹配 - # 命中本模块同名 define(无限递归),或找不到模块路径而走 - # 错误 fallback;此处用完整模块路径解析正确 SHA1(与校验段 - # L7344 对齐,SysLibTest 0xC00000FD 根因)。 - xmod_path: str = None - if xmod_at.value.kind() == ast.ASTKind.Name: - xmod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(xmod_at.value) - if xmod_nm.id is not None: - xmod_path = xmod_nm.id - else: - xmod_path = self.Gen.ExprGenAttr._attr_module_path_str(pool, xmod_at.value) - if xmod_path is not None: - mod_sha1: str = self._lookup_module_sha1(xmod_path) - if mod_sha1 is not None: - # fast-fail: 模块限定调用要求模块已被当前文件 import。 - # 全局 SHA1 存储包含所有被扫描的 includes,未导入的模块 - # (如 this.this() 但 import this 被注释)也会命中存储, - # 静默生成 @{sha1}.func 调用而非报错——违反"找不到 fast-fail"原则。 - is_xmod_imported: int = 1 - if trans is not None and trans._imported_modules is not None: - is_xmod_imported = self.Gen.ImportsGen.is_module_imported( - trans._imported_modules, xmod_path) - if is_xmod_imported == 0: - err_ni: str = pool.alloc(256) - if err_ni is not None: - viperlib.snprintf(err_ni, 256, - "跨模块调用 '%s.%s':模块 '%s' 未导入(请先 import %s)", - xmod_path, func_name, xmod_path, xmod_path) - self.Gen.TypeGenErr.fatal_error(xmod_at, err_ni) - self.Gen.TypeGenErr.fatal_error(xmod_at, "跨模块调用:模块未导入") - # 检查是否是 re-export 函数(如 ast._lexer_init 实际定义在 ast.lexer) - reexport_src: str = self.Gen.ImportsGen.lookup_reexport(mod_sha1, func_name) - if reexport_src is None: - # re-export 表未命中(includes 模块 stub/text 已存在时 - # 不被按需全量翻译,表只在 declare_only=0 时注册,可能为空): - # 按需解析该模块 .vpi 的 from-import 定位定义模块 - reexport_src = self._lookup_reexport_from_vpi(pool, mod_sha1, func_name) - if reexport_src is not None: - reexport_sha1: str = self._lookup_module_sha1(reexport_src) - if reexport_sha1 is not None: - mod_sha1 = reexport_sha1 - # CExport 函数定义用裸名(@strlen),跨模块调用需用裸名而非 @{sha1}.func - if self.Gen.CallGenBase.is_cexport_func(mod_sha1, func_name) != 0: - call_name = func_name - elif self._is_state_func_from_vpi(pool, mod_sha1, func_name) != 0: - # t.State 标记的外部 C 函数(如 CPython PyList_Size): - # 定义端用裸名 @PyList_Size(链接外部库),跨模块调用 - # 必须用裸名——带 sha1 前缀 → ld.lld undefined symbol - call_name = func_name - else: - mangled_len: t.CSizeT = string.strlen(mod_sha1) + string.strlen(func_name) + 2 - mangled: str = pool.alloc(mangled_len) - if mangled is not None: - viperlib.snprintf(mangled, mangled_len, "%s.%s", mod_sha1, func_name) - call_name = mangled - else: - # t 和 c 是内部库,豁免 SHA1 查找:使用裸名调用 - if string.strcmp(xmod_path, "t") == 0 or string.strcmp(xmod_path, "c") == 0: - call_name = func_name - else: - # Bug 修复: 先检查是否是已导入的模块名(如 BuildPipeline.run_pipeline) - # 如果是已导入模块但 SHA1 未注册,说明该模块未被编译(如 Phase2 未扫描到), - # 应该立即报错,而不是错误地走 from_imports 查找(会被 star import 回退误导) - is_imported_mod: int = 0 - if trans is not None and trans._imported_modules is not None: - is_imported_mod = self.Gen.ImportsGen.is_module_imported( - trans._imported_modules, xmod_path) - if is_imported_mod != 0: - # 别名导入(import X as Y):Y 在 _imported_modules 中, - # 但 _lookup_module_sha1("Y") 精确匹配失败(mod_arr 只存文件名)。 - # 先尝试 from_imports 查找别名→完整模块名→后缀匹配 SHA1。 - # allow_star_fallback=0 避免被 star import 回退误导。 - alias_sha1: str = None - if trans is not None and trans._from_imports is not None: - alias_sha1 = self._lookup_mod_sha1(pool, trans._from_imports, xmod_path, 0) - if alias_sha1 is not None: - if self.Gen.CallGenBase.is_cexport_func(alias_sha1, func_name) != 0: - call_name = func_name - elif self._is_state_func_from_vpi(pool, alias_sha1, func_name) != 0: - # t.State 外部 C 函数:裸名(同主路径 L7918) - call_name = func_name - else: - AliasMangledLen: t.CSizeT = string.strlen(alias_sha1) + string.strlen(func_name) + 2 - alias_mangled: str = pool.alloc(AliasMangledLen) - if alias_mangled is not None: - viperlib.snprintf(alias_mangled, AliasMangledLen, "%s.%s", alias_sha1, func_name) - call_name = alias_mangled - else: - # 已导入模块但 SHA1 未注册:该模块未被编译,立即报错 - err_msg_imp: str = pool.alloc(256) - if err_msg_imp is not None: - viperlib.snprintf(err_msg_imp, 256, "模块 '%s' 已导入但 SHA1 未注册(该模块未被编译)", xmod_path) - self.Gen.TypeGenErr.fatal_error(xmod_at, err_msg_imp) - self.Gen.TypeGenErr.fatal_error(xmod_at, "已导入模块 SHA1 未注册") - else: - # 检查是否是通过 from import 导入的名称(如 from .__types import LLVMType) - # LLVMType.Ptr(ty) 中 LLVMType 是类名不是模块名, - # 但 Ptr 是 __types 模块的模块级函数 - # 禁用 star import 回退:xmod_path 是明确名称,不应回退到 star import 模块 - from_sha1: str = None - if trans is not None and trans._from_imports is not None: - from_sha1 = self._lookup_mod_sha1(pool, trans._from_imports, xmod_path, 0) - if from_sha1 is not None: - # CExport 函数定义用裸名,跨模块调用需用裸名 - if self.Gen.CallGenBase.is_cexport_func(from_sha1, func_name) != 0: - call_name = func_name - else: - fmangled_len: t.CSizeT = string.strlen(from_sha1) + string.strlen(func_name) + 2 - fmangled: str = pool.alloc(fmangled_len) - if fmangled is not None: - viperlib.snprintf(fmangled, fmangled_len, "%s.%s", from_sha1, func_name) - call_name = fmangled - else: - err_msg2: str = pool.alloc(256) - if err_msg2 is not None: - viperlib.snprintf(err_msg2, 256, "跨模块调用 '%s.%s' 找不到模块 SHA1", xmod_path, func_name) - self.Gen.TypeGenErr.fatal_error(xmod_at, err_msg2) - self.Gen.TypeGenErr.fatal_error(xmod_at, "跨模块调用找不到模块 SHA1") - else: - # 裸名调用(非 Attribute):检查 from_imports - # 治本修复:函数调用禁用 star import 回退(allow_star_fallback=0)。 - # star import(from stdint import *)本意是导入类型/常量(如 BYTEPTR),而非函数; - # 函数应显式 from import。漏导函数若走 star 回退会被错归到 star 模块,生成错误 SHA1 符号 - # (如 block_insert_text_before_terminator 漏导后被错归 stdint,生成 - # f5522571bcce7bcb.block_insert... 而非 874bac141c97bae9.block_insert...)。 - # 禁用回退后,漏导函数编译期即报"未定义且未导入"(fast-fail),优于链接期 undefined reference。 - if trans is not None and trans._from_imports is not None: - bare_sha1: str = self._lookup_mod_sha1(pool, trans._from_imports, func_name, 0) - if bare_sha1 is not None: - # 别名处理: from X import Y as Z → 调用 Z 时需用 Y 作为源模块函数名 - # 例如 from json.__parser import parse as json_parse → 修饰为 SHA1.parse 而非 SHA1.json_parse - bare_orig: str = self.Gen.ImportsGen.lookup_from_import_original( - trans._from_imports, func_name) - bare_func_name: str = func_name - if bare_orig is not None: - # bare_orig 指向 from_imports 内部缓冲区,未 null 终止 - # 需复制到独立缓冲区(截断于空格或 null) - bo_len: t.CSizeT = 0 - while bare_orig[bo_len] != ' ' and bare_orig[bo_len] != '\0': - bo_len += 1 - bo_buf: str = pool.alloc(bo_len + 1) - if bo_buf is not None: - for bo_i in range(bo_len): - bo_buf[bo_i] = bare_orig[bo_i] - bo_buf[bo_len] = '\0' - bare_func_name = bo_buf - # 记录原始函数名,供后续重新推断返回类型 - # 例如 from json.__parser import parse as json_parse - # func_name="json_parse", bare_func_name="parse" - # _infer_external_func_ret_ty 用 "parse" 能正确匹配,用 "json_parse" 则返回默认 i32 - orig_func_name = bare_func_name - # re-export 解析(对齐模块限定路径 L6598): - # 裸名 from import 的函数可能实际定义在子模块(re-export)。 - # 例:from ast import dump → dump 定义在 ast.base(sha1=71b2), - # ast/__init__(sha1=876e)只是 re-export。若沿用包 sha1 构造 - # call_name="876e.dump",text.ll/vpi 返回类型解析均未命中, - # fail-fast 报"返回类型无法精确获取";需重定向到定义模块 SHA1。 - reexport_src2: str = self.Gen.ImportsGen.lookup_reexport(bare_sha1, bare_func_name) - if reexport_src2 is None: - # re-export 表未命中:按需解析该模块 .vpi 的 from-import - reexport_src2 = self._lookup_reexport_from_vpi(pool, bare_sha1, bare_func_name) - if reexport_src2 is not None: - reexport_sha1_2: str = self._lookup_module_sha1(reexport_src2) - if reexport_sha1_2 is not None: - bare_sha1 = reexport_sha1_2 - if self.Gen.CallGenBase.is_cexport_func(bare_sha1, bare_func_name) != 0: - call_name = bare_func_name - else: - bare_mangled_len: t.CSizeT = string.strlen(bare_sha1) + string.strlen(bare_func_name) + 2 - bare_mangled: str = pool.alloc(bare_mangled_len) - if bare_mangled is not None: - viperlib.snprintf(bare_mangled, bare_mangled_len, "%s.%s", bare_sha1, bare_func_name) - call_name = bare_mangled - else: - err_msg3: str = pool.alloc(256) - if err_msg3 is not None: - viperlib.snprintf(err_msg3, 256, "裸名调用 '%s' 未定义且未导入", func_name) - self.Gen.TypeGenErr.fatal_error(node, err_msg3) - self.Gen.TypeGenErr.fatal_error(node, "裸名调用未定义且未导入") - else: - err_msg4: str = pool.alloc(256) - if err_msg4 is not None: - viperlib.snprintf(err_msg4, 256, "裸名调用 '%s' 未定义且未导入", func_name) - self.Gen.TypeGenErr.fatal_error(node, err_msg4) - self.Gen.TypeGenErr.fatal_error(node, "裸名调用未定义且未导入") - - # 直接调用 - # memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失) - if string.strcmp(func_name, "memcpy") == 0 and can >= 3: - return self.Gen.CallGenLib._emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst2, mc_src2, mc_num2) - # 别名导入重新推断返回类型: - # from X import parse as json_parse → func_name="json_parse" 时 _infer_external_func_ret_ty 返回默认 i32 - # 用 orig_func_name="parse" 重新推断,能正确匹配返回 i8*(JsonValue*) - # 避免指针被截断为 i32 后 inttoptr 丢失高 32 位导致崩溃 - if orig_func_name is not None and orig_func_name != func_name: - re_inferred_ty: llvmlite.LLVMType | t.CPtr = self.Gen.CallGenLib._infer_external_func_ret_ty(pool, orig_func_name) - if re_inferred_ty is not None: - call_ret_ty = re_inferred_ty - # ============================================================ - # 跨模块 Viper 函数返回类型精确解析(对齐方法路径,fail-fast) - # 根因:_infer_external_func_ret_ty 白名单未覆盖返回指针的模块函数 - # (new_lexer→Lexer* / tokenize→Token* / parse_tokens→AST*),兜底 i32 - # 导致 64 位指针被截断高 32 位 → inttoptr 无效指针 → 解引用崩溃 - # (AstTest 的 _lexer_init 崩溃链)。declare 也可能是错误 i32(_ensure_method_declare - # 曾用兜底类型创建),因此不信任 found_func 的 declare 返回类型。 - # 权威来源:text.ll define;次选:vpi stub 返回注解;均未命中立即终止。 - # 仅对 mangled("{16位hex}.func")调用生效;C 库/Win32 裸名走原白名单。 - # Phase 1a(declare_only)期间依赖 text.ll 未生成,保持原白名单行为不 fail-fast。 - # ============================================================ - if self.Gen.CallGenLib._is_sha1_mangled_call(call_name) != 0: - if trans is None or trans._declare_only == 0: - cf_dot: str = string.strchr(call_name, '.') - cf_last: str = string.strrchr(call_name, '.') - if cf_dot is not None and cf_last is not None: - cf_sha1: str = stdlib.malloc(17) - cf_bare_len: t.CSizeT = string.strlen(call_name) - \ - (t.CSizeT(t.CUInt64T(cf_last) - t.CUInt64T(call_name))) - 1 - cf_bare: str = stdlib.malloc(cf_bare_len + 1) - if cf_sha1 is not None and cf_bare is not None: - string.strncpy(cf_sha1, call_name, 16) - cf_sha1[16] = '\0' - string.strcpy(cf_bare, cf_last + 1) - # 本模块自身函数(泛型特化等):从当前 IR 已声明的函数 - # 取返回类型;不走跨模块 text.ll 查找——自己的 text.ll - # 在 Phase A 翻译中尚未生成,直接查会误报"依赖未生成" - # 并保持默认类型(GenericTest 泛型 add/combine 等警告 - # 根因)。未命中(特化尚未声明)保持默认推断。 - is_local_mod: int = 0 - if trans is not None and trans.ModuleSha1 is not None: - if string.strncmp(cf_sha1, trans.ModuleSha1, 16) == 0: - is_local_mod = 1 - if is_local_mod != 0: - local_fn: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, call_name) - if local_fn is not None and local_fn.RetTy is not None: - call_ret_ty = local_fn.RetTy - else: - cf_ret: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL( - pool, cf_sha1, None, cf_bare, 1) - if cf_ret is not None: - call_ret_ty = cf_ret - else: - cf_vpi: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi( - pool, cf_sha1, None, cf_bare) - if cf_vpi is not None: - call_ret_ty = cf_vpi - else: - # 区分两种失败场景: - # 1. 依赖模块 text.ll 存在但函数未命中 → 真错误,fail-fast - # 2. 依赖模块 text.ll 不存在(模块尚未翻译)→ Phase A 按 - # 文件顺序翻译,main.vp 先于其 import 的 mbuddytest.vp - # (同项目多源文件)。此时标记 trans._deps_pending=1, - # 保持白名单类型继续,Phase A 多遍循环下遍重译—— - # 届时依赖已生成 text.ll,可精确解析(治本:依赖先翻译)。 - if self._dep_text_ll_exists(pool, cf_sha1) != 0: - cf_err: str = VLogger.fmt_buf() - if cf_err is not None: - viperlib.snprintf( - cf_err, 1024, - "跨模块函数 '%s' 返回类型无法精确获取(text.ll/vpi 均未命中)," - "默认 i32 会截断指针/i64,请检查依赖模块是否已编译/注册", call_name) - VLogger.error(cf_err, "HandlesExprCall") - self.Gen.TypeGenErr.fatal_error( - node, - f"跨模块函数返回类型无法精确获取(text.ll/vpi 均未命中),默认 i32 会截断指针: {call_name}", - "TypeError") - else: - if trans is not None: - trans._deps_pending = 1 - cf_dbg: str = VLogger.fmt_buf() - if cf_dbg is not None: - viperlib.snprintf( - cf_dbg, 1024, - "跨模块函数 '%s' 依赖模块 text.ll 尚未生成(Phase A 顺序)," - "标记重试,本遍保持默认类型", call_name) - if VLogger.nowarn_register() == 0: - VLogger.warning(cf_dbg, "HandlesExprCall") - stdlib.free(cf_sha1) - stdlib.free(cf_bare) - # 跨模块调用:创建 declare 声明,避免 llc 报 undefined value - self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, can) - # 检查被调用函数是否为变长函数(*args),若是则对变长参数进行 C ABI 提升 - # (cargs 为本函数参数 AST 链表,self_offset=0 普通函数调用) - is_variadic_call: int = self.Gen.CallGenVa._check_and_promote_variadic_call( - pool, builder, mod, call_name, head, can, cargs, 0, trans) - # try-except:被调函数带 EH 输出参数时,追加输出实参 + 调用后检测异常 - return self.Gen.CallGenLeafKit._emit_eh_guarded_call( - builder, pool, mod, trans, found_func, call_name, head, can, - call_ret_ty, is_variadic_call) - - - - - - - - - - - - - +import lib.core.Gen.GenTypes as GenTypes +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import sys +import viperlib +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.CallGenBase as CallGenBase +import lib.core.Handles.ExprCallTable as ExprCallTable + + +# ============================================================ +# CallGenMixin - 调用分派 Mixin(拆分后顶层,阶段 A:底层已拆至 +# CallGenBase/CallGenCBuiltin/CallGenLeafKit) +# +# 500~1500 行/文件架构重构阶段 A:底层自包含组(模块查找/返回类型解析/ +# c.*/asm/llvmir/EH/isinstance/闭包/print/函数表)已拆出,本文件保留 +# 调用分派中枢(translate_call 等)。继承链 CallGenMixin → LeafKit → +# CBuiltin → Base,@t.NoVTable 静态绑定沿 MRO 解析 self 调用。 +# +# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 +# ============================================================ + + +# ============================================================ +# 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug) +# ============================================================ +GLOBAL_FUNC_MAX: t.CDefine = 8192 +GLOBAL_DEFAULTS_MAX: t.CDefine = 4096 +_CEXPORT_MAX: t.CDefine = 256 +ASM_MAX_OPERANDS: t.CDefine = 16 +ASM_TEXT_BUF_SIZE: t.CDefine = 2048 +ASM_CONST_BUF_SIZE: t.CDefine = 512 +ASM_ARGS_BUF_SIZE: t.CDefine = 512 +ASM_LINE_BUF_SIZE: t.CDefine = 4096 +LLVMIR_MAX_OPS: t.CDefine = 16 +LLVMIR_TEMPLATE_BUF: t.CDefine = 512 +# 闭包名表大小(原 HandlesExprCall 模块级常量) +MAX_CLOSURE_NAMES: t.CDefine = 128 +# 函数指针签名表大小(原 HandlesExprCall 模块级常量) +MAX_FUNC_PTR_SIGS: t.CDefine = 64 +# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32) +ISINSTANCE_CLASS_MAX: t.CDefine = 64 + + +# ============================================================ +# CallGenMixin - 调用分派中枢(顶层,继承 LeafKit) +# ============================================================ +@t.NoVTable +class CallGenMixin(CallGenBase.CallGenBase): + """调用分派 Mixin(拆分后顶层,直接继承 CallGenBase——TPV self 调用仅支持 1 级父类)""" + + # ============================================================ + # 翻译函数调用 Call(func, args) — 模块级版本 + # ============================================================ + def translate_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译函数调用,返回 call 结果 Value""" + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + if cl is None: + return None + + func_name: str = self.Gen.ExprGenBase.get_func_name(cl.func) + + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + can: t.CSizeT = 0 + if cargs is not None: + can = len(cargs) + + # super()/ctraits 检测:void 方法(如 __init__)命中后 build_call 返回 + # None 属预期(void call 无 SSA 值),必须用 hit_box 区分"命中已处理" + # 与"未命中",否则 None 被误判继续主路径 → 内层 Call(super) 当裸名 + # 调用报"super 未定义且未导入"(SuperTest 根因)。 + h1_hit: t.CPtr = stdlib.malloc(4) + if h1_hit is not None: + h1_hit[0] = 0 + _tc_h1_super_ctraits_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._tc_h1_super_ctraits( + pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can, h1_hit) + h1_hit_val: int = 0 + if h1_hit is not None: + h1_hit_val = h1_hit[0] + stdlib.free(h1_hit) + if _tc_h1_super_ctraits_res is not None: + return _tc_h1_super_ctraits_res + if h1_hit_val != 0: + # 命中 super()/ctraits 但无返回值(void 方法/宏调用):视为已处理 + return None + + # ---- func_name is None:泛型实例化 + 类型转换 ---- + if func_name is None: + # 检查是否是 list[int](pool) 形式的泛型实例化调用 + # Subscript 节点作为 Call func: 泛型类构造函数 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Subscript and trans is not None: + sub_node: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(cl.func) + if sub_node.value is not None and sub_node.value.kind() == ast.ASTKind.Name: + gen_nm_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_node.value) + gen_class_name: str = gen_nm_node.id + # 检查是否是泛型类模板 + template_cd: ast.ClassDef | t.CPtr = self.Gen.ClassGenGeneric._find_generic_template(gen_class_name) + if template_cd is not None: + # 提取类型实参 + gen_type_args: list[str] | t.CPtr = self.Gen.CallGenCtor._extract_type_args_from_slice(pool, sub_node.slice) + if gen_type_args is not None and len(gen_type_args) > 0: + # 特化泛型类,返回特化类名 + spec_name: str = self.Gen.ClassGenGeneric._specialize_generic_class( + trans, gen_class_name, gen_type_args) + if spec_name is not None: + # 泛型类构造调用: list[str](pool, 8) → __new__ + __before_init__ + __init__ + # 不能直接用 spec_name 作为 func_name(会走裸名调用路径, + # 被 star import 回退误导用错误的 SHA1,且缺少 __new__ 方法名后缀) + return self.Gen.CallGenCtor._translate_generic_ctor_call( + pool, builder, mod, spec_name, cl, trans) + else: + # 泛型类模板未找到:可能是泛型函数手动传类型参数调用 xxx[T](x) + # (对应 TPC _HandleGenericCallExplicitLlvm;TPV 无泛型函数特化, + # 泛型函数按普通函数编译,类型参数 [T] 仅在函数定义处消费)。 + # 检查当前模块是否已定义同名函数(def double[T] 编译后即普通函数 + # double),若是则丢弃 [t.CInt] 显式类型参数,退回普通函数调用。 + if self.find_func_in_module(mod, gen_class_name) is not None: + func_name = gen_class_name + else: + # 泛型类模板未找到:可能未 import 定义模块 + gt_err: str = pool.alloc(256) + if gt_err is not None: + viperlib.snprintf(gt_err, 256, "泛型类 '%s' 未找到模板,可能未 import 定义模块", gen_class_name) + self.Gen.TypeGenErr.fatal_error(gen_nm_node, gt_err) + self.Gen.TypeGenErr.fatal_error(gen_nm_node, "泛型类模板未找到") + if func_name is None: + # 检查是否是 (A | t.CPtr)(value) 形式的类型转换 + # BinOp 节点作为 Call func: 联合类型注解用作类型转换 + if cl.func is not None and cl.func.kind() == ast.ASTKind.BinOp and trans is not None: + binop_ty: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, cl.func, trans._imported_modules, trans._from_imports, trans) + if binop_ty is not None: + binop_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if binop_args is not None and len(binop_args) == 1: + binop_arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, binop_args.get(0), funcs_ptr, func_count, trans) + if binop_arg_val is not None: + return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, binop_arg_val, binop_ty) + return None + + # c.Asm/c.LLVMIR 等特殊调用:void(无输出)时 translate_c_asm/llvmir + # 返回 None 表示"已处理无返回值",需用 hit_box 区分"未命中", + # 否则会误判未命中继续走外部函数路径(外部函数返回类型未登记 Asm + + # t.ASM_DESCR 被当 CDefine 常量赋值) + h2_hit: t.CPtr = stdlib.malloc(4) + if h2_hit is not None: + h2_hit[0] = 0 + _tc_h2_c_special_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._tc_h2_c_special( + pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can, h2_hit) + h2_hit_val: int = 0 + if h2_hit is not None: + h2_hit_val = h2_hit[0] + stdlib.free(h2_hit) + if _tc_h2_c_special_res is not None: + return _tc_h2_c_special_res + if h2_hit_val != 0: + # 命中 c.Asm/c.LLVMIR 但无返回值(void):视为已处理 + return None + + _tc_h3_stdarg_cast_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._tc_h3_stdarg_cast( + pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) + if _tc_h3_stdarg_cast_res is not None: + return _tc_h3_stdarg_cast_res + + _tc_h4_type_casts_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._tc_h4_type_casts( + pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) + if _tc_h4_type_casts_res is not None: + return _tc_h4_type_casts_res + + _tc_h5_sizeof_len_isinst_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._tc_h5_sizeof_len_isinst( + pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) + if _tc_h5_sizeof_len_isinst_res is not None: + return _tc_h5_sizeof_len_isinst_res + + # c.Asm/c.LLVMIR 等方法调用分派:方法调用识别成功但返回 None + # (如编译器生成方法 __before_init__/__init__ 恒返回 void,_translate_ + # method_call 或 _emit_eh_guarded_call 处理后可能返回 None)时,须用 + # hit_box 区分"已识别为方法调用"与"未命中",否则 translate_call 误判 + # 未命中继续走跨模块函数路径,把对象名当模块名查 SHA1 → + # "跨模块调用 'buf.__before_init__' 找不到模块 SHA1"(memhub.alloc_buf 根因)。 + h6_hit: t.CPtr = stdlib.malloc(4) + if h6_hit is not None: + h6_hit[0] = 0 + _tc_h6_method_dispatch_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._tc_h6_method_dispatch( + pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can, h6_hit) + h6_hit_val: int = 0 + if h6_hit is not None: + h6_hit_val = h6_hit[0] + stdlib.free(h6_hit) + if _tc_h6_method_dispatch_res is not None: + return _tc_h6_method_dispatch_res + if h6_hit_val != 0: + # 命中方法调用路径但无返回值(编译器生成方法等 void 语义):视为已处理 + return None + + # 获取关键字参数 + keywords: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords + kw_count: t.CSizeT = 0 + if keywords is not None: + kw_count = len(keywords) + + # 检查是否是结构体构造函数: Point() / Point(10, 20) / Point(x=10, y=20) + # 命名空间隔离:严格模式下检查结构体可见性 + # - 裸名 Class(): 需要 from X import Class 或本地定义 + # - 模块限定 Module.Class(): 需要 import Module + # 用 find_struct_by_module 规避跨模块同名 find_struct 找错 + struct_ty: llvmlite.LLVMType | t.CPtr = None + gen_ctor_entry: GenTypes.StructEntry | t.CPtr = None + vis: int = self.Gen.StructGen.is_struct_visible(func_name) + if vis != 0: + if trans is not None: + gen_ctor_entry = self.Gen.StructGen.find_struct_by_module(func_name, trans.ModuleSha1) + if gen_ctor_entry is None: + gen_ctor_entry = self.Gen.StructGen.find_struct(func_name) + if gen_ctor_entry is not None: + struct_ty = gen_ctor_entry.Ty + elif trans is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + at_qc: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if at_qc.value is not None and at_qc.value.kind() == ast.ASTKind.Name: + mod_nm_qc: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_qc.value) + imp_ok: int = self.Gen.ImportsGen.is_module_imported(trans._imported_modules, mod_nm_qc.id) + if imp_ok != 0: + if trans is not None: + gen_ctor_entry = self.Gen.StructGen.find_struct_by_module(func_name, trans.ModuleSha1) + if gen_ctor_entry is None: + gen_ctor_entry = self.Gen.StructGen.find_struct(func_name) + if gen_ctor_entry is not None: + struct_ty = gen_ctor_entry.Ty + elif at_qc.value is not None and at_qc.value.kind() == ast.ASTKind.Attribute: + # 多层模块路径类构造: w32.fileio.File(...)(value 是嵌套 Attribute)。 + # 仅两层(fileio.File)支持时,三层会被跳过 → 退化走跨模块普通函数 + # 调用生成 @File 裸名 → 链接 undefined symbol: File(SysLibTest 根因)。 + # 模块路径经 attr_module_path_str 递归拼接("w32.fileio"), + # import 检查用完整路径(import w32.fileio 注册 "w32.fileio"), + # 结构体查找用该模块自身 SHA1 精确命中(find_struct_by_module)。 + # 注:经 HandlesExpr 委托调用(跨 mixin 不能 self. 直接调, + # @t.NoVTable 静态绑定会 mangle 成 CallGenMixin. 前缀 → undefined reference)。 + mod_path_qc: str = self.Gen.ExprGenAttr._attr_module_path_str(pool, at_qc.value) + if mod_path_qc is not None: + imp_ok_qc: int = self.Gen.ImportsGen.is_module_imported( + trans._imported_modules, mod_path_qc) + if imp_ok_qc != 0: + mod_sha1_qc: str = self._lookup_module_sha1(mod_path_qc) + if mod_sha1_qc is not None: + gen_ctor_entry = self.Gen.StructGen.find_struct_by_module( + func_name, mod_sha1_qc) + if gen_ctor_entry is None: + gen_ctor_entry = self.Gen.StructGen.find_struct(func_name) + if gen_ctor_entry is not None: + struct_ty = gen_ctor_entry.Ty + # 别名导入的类构造: from X import Class as Alias → Alias(args) + # 可见性列表按别名注册(HandleImportFromNames 用 local_name=asname),但结构体 + # 按原名注册(如 Keyword as KwNode → 可见 "KwNode"、注册名 "Keyword")。 + # 直接按别名 find_struct 查不到 → 误走普通函数路径生成 @sha1.Keyword 调用 + # (该函数不存在)→ 链接期 undefined reference。此处解析别名→原名再查结构体。 + if gen_ctor_entry is None and trans is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Name: + if trans._from_imports is not None: + ctor_sha1: str = self._lookup_mod_sha1(pool, trans._from_imports, func_name, 0) + if ctor_sha1 is not None: + ctor_orig: str = self.Gen.ImportsGen.lookup_from_import_original( + trans._from_imports, func_name) + if ctor_orig is not None: + # 复制到独立 null 终止缓冲区(from_imports 内部缓冲未终止) + co_len: t.CSizeT = 0 + while ctor_orig[co_len] != ' ' and ctor_orig[co_len] != '\0': + co_len += 1 + co_buf: str = pool.alloc(co_len + 1) + if co_buf is not None: + for co_i in range(co_len): + co_buf[co_i] = ctor_orig[co_i] + co_buf[co_len] = '\0' + # 原名结构体查找(可见性已由别名保证,原名无需再查) + gen_ctor_entry = self.Gen.StructGen.find_struct_by_module(co_buf, ctor_sha1) + if gen_ctor_entry is None: + gen_ctor_entry = self.Gen.StructGen.find_struct(co_buf) + if gen_ctor_entry is not None: + struct_ty = gen_ctor_entry.Ty + func_name = co_buf + if struct_ty is not None: + if can == 0 and kw_count == 0: + # OOP 结构体:即使无参数也调用 __before_init__ + # 用 gen_ctor_entry 规避跨模块同名 find_struct 找错 + ctor_is_oop: int = 0 + if gen_ctor_entry is not None: + ctor_is_oop = gen_ctor_entry.IsOOP + if ctor_is_oop != 0: + return self.Gen.CallGenCtor._translate_struct_ctor( + pool, builder, mod, struct_ty, func_name, cargs, 0, trans) + # @t.NoVTable 类(无方法、类语义/指针对象):无参构造也应分配内存 + # 返回指针。否则按值结构体返回 ConstZero(struct_ty),LHS 联合注解 + # (如 Plain|CPtr)存 0 指针 → p.v 解引用 NULL 段错误 + # (TpvIsinstanceTest Plain 场景崩溃根因)。 + ctor_is_novt: int = 0 + if gen_ctor_entry is not None: + ctor_is_novt = gen_ctor_entry.IsNoVTable + if ctor_is_novt != 0: + return self.Gen.CallGenCtor._translate_struct_ctor( + pool, builder, mod, struct_ty, func_name, cargs, 0, trans) + # 普通结构体:检查是否有默认值(用 entry 直接访问) + gen_has_defaults: int = 0 + if gen_ctor_entry is not None: + for gdi in range(gen_ctor_entry.FieldCount): + gdf: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry( + gen_ctor_entry, gdi) + if gdf is not None and gdf.DefaultVal is not None: + gen_has_defaults = 1 + break + else: + gen_has_defaults = self.Gen.StructGen.struct_has_defaults(func_name) + if gen_has_defaults == 1: + # 有默认值:走构造函数路径应用默认值 + return self.Gen.CallGenCtor._translate_struct_ctor( + pool, builder, mod, struct_ty, func_name, cargs, 0, trans) + # 无默认值:返回 zeroinitializer + ret: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) + return ret + if kw_count > 0: + # 有关键字参数:按字段名赋值 + return self.Gen.CallGenCtor._translate_struct_ctor_kw( + pool, builder, mod, struct_ty, func_name, cargs, can, + keywords, kw_count, trans) + # 仅位置参数:按字段顺序构建 + return self.Gen.CallGenCtor._translate_struct_ctor( + pool, builder, mod, struct_ty, func_name, cargs, can, trans) + + # 裸名泛型类模板构造: Box(42) → 从实参推断类型实参 → 特化 → 构造 + # (TPC 参考: _HandleGenericClassNewLlvm;GenericTest Test4 Box(42)/Test5 + # Pair(10,20)/Test10 Counter(0) 依赖此路径。显式类型实参 list[int](mb) + # 走 translate_call 上方的 Subscript 分支,此处处理裸名 + 推断。) + # 支持模块限定调用(vector.Vector(...)):func_name 是 attr("Vector"), + # 需确认模块已导入(模板查找兜底——普通函数如 stdlib.free 的 attr 找 + # 不到模板 → 回落普通调用)。 + if struct_ty is None and gen_ctor_entry is None and trans is not None: + is_gen_bare: int = 0 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: + is_gen_bare = 1 + elif cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + at_gb: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if at_gb.value is not None and at_gb.value.kind() == ast.ASTKind.Name: + am_gb: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_gb.value) + if am_gb.id is not None: + if self.Gen.ImportsGen.is_module_imported(trans._imported_modules, am_gb.id) != 0: + is_gen_bare = 1 + if is_gen_bare != 0: + template_cd_bare: ast.ClassDef | t.CPtr = self.Gen.ClassGenGeneric._find_generic_template(func_name) + if template_cd_bare is not None and template_cd_bare.type_params is not None: + tp_bare: list[str] | t.CPtr = template_cd_bare.type_params + tp_count_bare: t.CSizeT = len(tp_bare) + if tp_count_bare > 0: + inferred_args_bare: list[str] | t.CPtr = list[str](pool, 8) + if inferred_args_bare is not None: + # 对齐 TPC _HandleGenericClassNewLlvm:先收集全部实参 + # 推断类型,过滤纯 int(排除 pool 等非 T 参数), + # hint_types 优先填充(Vector(pool,8,CFloat64T(0.0)) + # → Vector[double];Vector(pool,10,CInt(0)) → Vector[int]) + hint_bare: list[str] | t.CPtr = list[str](pool, 8) + if hint_bare is not None: + hi_bare: t.CSizeT + for hi_bare in range(can): + hty_bare: str = self.Gen.CallGenCtor._infer_generic_ctor_type_arg(pool, cargs.get(hi_bare), func_name) + if string.strcmp(hty_bare, "int") != 0: + hint_bare.append(hty_bare) + tpi_bare: t.CSizeT = 0 + for tpi_bare in range(tp_count_bare): + ta_bare: str = "int" + if tpi_bare < len(hint_bare): + ta_bare = hint_bare.get(tpi_bare) + elif tpi_bare < can: + ta_bare = self.Gen.CallGenCtor._infer_generic_ctor_type_arg(pool, cargs.get(tpi_bare), func_name) + inferred_args_bare.append(ta_bare) + spec_name_bare: str = self.Gen.ClassGenGeneric._specialize_generic_class( + trans, func_name, inferred_args_bare) + if spec_name_bare is not None: + return self.Gen.CallGenCtor._translate_generic_ctor_call( + pool, builder, mod, spec_name_bare, cl, trans) + + # REnum 变体构造检测: ClassName.VariantName(args...) + # 如 LLVMType.Int(1) → 构造 LLVMType 的 Int 变体 + # 必须在跨模块调用查找之前,否则 ClassName 会被误判为模块名 + # 对应 TPC HandlesExprCall.py:585-644 的三条检测路径之一 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + rc_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if rc_at.value is not None and rc_at.value.kind() == ast.ASTKind.Name: + rc_cls_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rc_at.value) + if rc_cls_node.id is not None: + rc_cls_name: str = rc_cls_node.id + # 检查 ClassName 是否是已注册的 REnum 类 + if self.Gen.ClassGenEnum._is_renum_class_name(rc_cls_name) != 0: + # 在该 REnum 类中查找变体名 func_name + rc_tag: int = self.Gen.ClassGenEnum._lookup_renum_variant_in_class( + rc_cls_name, func_name) + if rc_tag >= 0: + return self.Gen.CallGenCtor._translate_renum_construct( + pool, builder, mod, rc_cls_name, func_name, + rc_tag, cargs, can, trans) + elif rc_at.value is not None and rc_at.value.kind() == ast.ASTKind.Attribute: + # 模块限定 REnum 变体构造: mod.Class.Variant(args...) + # 如 llvmlite.LLVMType.Struct(...) → 构造 llvmlite 模块 LLVMType 的 Struct 变体。 + # 根因:此前只支持单层 Name(ClassName.Variant),嵌套属性漏检 → 误走跨模块 + # 函数路径 → _lookup_module_sha1("llvmlite.LLVMType") 查无 → 报"跨模块调用 + # 'llvmlite.LLVMType.Struct' 找不到模块 SHA1"。跨模块任意同名可接受(REnum + # 表按类名全局注册):仅要求最左模块已导入 + 末段类名在全局 REnum 表中命中, + # 不做"类必须属于该模块"校验(未命中则按后续函数路径 fast-fail)。 + rc_mq_path: str = self.Gen.ExprGenAttr._attr_module_path_str(pool, rc_at.value) + if rc_mq_path is not None: + rc_mq_dot: str = string.strrchr(rc_mq_path, 46) # 46 = ord('.') + if rc_mq_dot is not None and rc_mq_dot[1] != '\0': + # 模块路径 = 末段之前(支持多级: w32.fileio.Class.Variant)。 + # 注意:不能用 rc_mq_dot - rc_mq_path 指针减法(TPC 直接发 + # sub i8*, i8* 非法 IR),用 strlen 整数差扣除末段与分隔点。 + rc_mq_len: t.CSizeT = string.strlen(rc_mq_path) - string.strlen(rc_mq_dot + 1) - 1 + rc_mq_mod: str = pool.alloc(rc_mq_len + 1) + if rc_mq_mod is not None: + string.memcpy(rc_mq_mod, rc_mq_path, rc_mq_len) + rc_mq_mod[rc_mq_len] = '\0' + rc_mq_imp: int = 1 + if trans is not None and trans._imported_modules is not None: + rc_mq_imp = self.Gen.ImportsGen.is_module_imported( + trans._imported_modules, rc_mq_mod) + if rc_mq_imp != 0: + rc_mq_cls: str = rc_mq_dot + 1 + # 检查类名是否是已注册的 REnum 类 + if self.Gen.ClassGenEnum._is_renum_class_name(rc_mq_cls) != 0: + rc_mq_tag: int = self.Gen.ClassGenEnum._lookup_renum_variant_in_class( + rc_mq_cls, func_name) + if rc_mq_tag >= 0: + return self.Gen.CallGenCtor._translate_renum_construct( + pool, builder, mod, rc_mq_cls, func_name, + rc_mq_tag, cargs, can, trans) + + # 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( + trans._imported_modules, xm_mod_path) != 0: + mod_sha1_chk: str = self._lookup_module_sha1(xm_mod_path) + if mod_sha1_chk is not None: + ff_nm2: str = llvmlite.function_get_name(found_func) + if ff_nm2 is not None: + if string.strncmp(ff_nm2, mod_sha1_chk, 16) != 0: + found_func = None + ff_name: str = llvmlite.function_get_name(found_func) + if ff_name is not None: + ff_dots: int = 0 + ffi2: t.CSizeT = 0 + while ff_name[ffi2] != '\0': + if ff_name[ffi2] == '.': + ff_dots += 1 + ffi2 += 1 + if ff_dots >= 2: + # 提取第 2 段(SHA1.Class.method → Class;SHA1.submod.func → submod) + seg2: str = pool.alloc(64) + if seg2 is not None: + seg2[0] = '\0' + si: t.CSizeT = 0 + while ff_name[si] != '\0' and si < 17: + si += 1 + seg_start: t.CSizeT = si + seg_end: t.CSizeT = si + while ff_name[seg_end] != '\0' and ff_name[seg_end] != '.': + seg_end += 1 + seg_len: t.CSizeT = seg_end - seg_start + if seg_len > 0 and seg_len < 63: + string.strncpy(seg2, ff_name + seg_start, seg_len) + seg2[seg_len] = '\0' + # 第 2 段是已注册结构体类 → 是方法,拒绝(走模块 SHA1 路径) + if self.Gen.StructGen.get_struct_type(seg2) is not None: + found_func = None + # C 库函数裸名调用支持:若模块中找不到且是已知 C 库函数,自动创建 declare + # 对应 TPC 的 _C_LIB_FUNCS 机制,支持 memset/memmove/memcmp/strcmp 等裸名调用 + if found_func is None and cl.func is not None and cl.func.kind() == ast.ASTKind.Name: + found_func = self.Gen.CallGenLib._ensure_c_lib_declare(pool, mod, func_name) + # builtins 自动关联:C 库未命中时,自动关联 builtins 模块的内置函数(ord/chr 等)。 + # builtins 已由编译链预加入(StubMerger 预加入列表)。PhaseA 期 builtins 尚未编译, + # 因此按约定签名创建 {builtins_sha1}.{name} 的 mangled declare(链接时解析到 + # builtins.vp 的真实定义);签名与 builtins.vp 保持一致:ord(i8)->i32, chr(i32)->i8。 + if found_func is None: + bi_sha1: str = self._lookup_module_sha1("builtins") + if bi_sha1 is not None: + bi_ret: llvmlite.LLVMType | t.CPtr = None + bi_p1: llvmlite.LLVMType | t.CPtr = None + if string.strcmp(func_name, "ord") == 0: + bi_ret = llvmlite.Int32(pool) + bi_p1 = llvmlite.Int8(pool) + elif string.strcmp(func_name, "chr") == 0: + bi_ret = llvmlite.Int8(pool) + bi_p1 = llvmlite.Int32(pool) + if bi_ret is not None: + bi_sym: str = func_name + if self.Gen.CallGenBase.is_cexport_func(bi_sha1, func_name) == 0: + bi_sym_len: t.CSizeT = string.strlen(bi_sha1) + string.strlen(func_name) + 2 + bi_sym_buf: str = pool.alloc(bi_sym_len) + if bi_sym_buf is not None: + viperlib.snprintf(bi_sym_buf, bi_sym_len, "%s.%s", bi_sha1, func_name) + bi_sym = bi_sym_buf + bi_decl: llvmlite.Function | t.CPtr = llvmlite.create_declare( + pool, mod, bi_sym, bi_ret) + if bi_decl is not None: + llvmlite.add_param(pool, bi_decl, bi_p1, "v") + found_func = bi_decl + # 使用访问器绕过 stub 类型限制 + found_ret_ty: llvmlite.LLVMType | t.CPtr = None + found_params: t.CPtr = None + if found_func is not None: + found_ret_ty = llvmlite.function_get_ret_ty(found_func) + found_params = llvmlite.function_get_params(found_func) + if found_ret_ty is not None: + call_ret_ty: llvmlite.LLVMType | t.CPtr = found_ret_ty + else: + # found_func=None(跨模块 stub 未注入):先从 vpi stub 返回注解 + # 缓存精确获取返回类型(含 tuple[T1,T2] → 匿名结构体,如 + # b2a_hqx -> tuple[str, t.CUnsignedShort] → {i8*, i16}), + # 未命中才回退 _infer_external_func_ret_ty 白名单推断。 + # 根因:_infer 白名单无 tuple 概念,未知函数默认 i32 会截断 + # 指针/i64;b2a_hqx 被推断为单值 i8*/i32 后调用侧返回值类型 + # 与定义侧 {i8*, i16} 不匹配 → HandlesAssign 的 tuple 解包 + # (依赖 rhs_val.Ty 是 Struct)静默跳过 → 目标变量从未赋值 → + # free 未初始化栈垃圾指针崩溃(HashLibTest hqx 段)。 + vpi_ret_ty: llvmlite.LLVMType | t.CPtr = None + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + at_ret: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if at_ret.value is not None and at_ret.value.kind() == ast.ASTKind.Name: + mod_ret_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_ret.value) + if mod_ret_nm.id is not None: + mod_ret_sha1: str = self._lookup_module_sha1(mod_ret_nm.id) + if mod_ret_sha1 is not None: + # 函数内懒 import:VpiReader imports HandlesExprCall, + # 顶层 import 会成环(与 _lookup_method_ret_ty_via_vpi 一致) + import lib.StubGen.VpiReader as VpiReader + VpiReader._ensure_vpi_ret_annot_loaded(mod_ret_sha1, self.Gen.CallGenBase.TempDir) + ret_annot_fc: str = VpiReader._lookup_vpi_ret_annot( + mod_ret_sha1, None, func_name) + if ret_annot_fc is not None: + vpi_ret_ty = VpiReader._resolve_vpi_ret_annot_str( + pool, ret_annot_fc, + llvmlite.Int32(pool), + llvmlite.Ptr(pool, llvmlite.Int8(pool))) + if vpi_ret_ty is not None: + call_ret_ty = vpi_ret_ty + else: + call_ret_ty = self.Gen.CallGenLib._infer_external_func_ret_ty(pool, func_name) + + # 如果模块中找不到函数,仅裸名调用(Name)才回退查局部变量(函数指针/ + # 闭包调用);模块属性调用(VLogger.fmt_buf())的目标是模块符号,绝不 + # 回退局部变量——跨模块任意同名可接受(CallGenLeafKit 局部 fmt_buf + # 曾劫持 VLogger.fmt_buf → 误走函数指针调用报 t.Callable 缺失), + # 仅 from-import 的裸名 yyy 与局部重名才可能冲突(该场景 func 是 Name)。 + if found_func is None: + fp_alloca: llvmlite.Value | t.CPtr = None + if cl.func is None or cl.func.kind() == ast.ASTKind.Name: + fp_alloca = self.Gen.VarGen.lookup_var(trans.SymTab, func_name) + if fp_alloca is not None: + # 闭包变量(嵌套函数提升,已注册到闭包名集合):提取 fn_ptr/env_ptr 间接调用 + if self.Gen.CallGenLeafKit.is_closure_name(func_name) != 0: + return self.Gen.CallGenLeafKit.translate_closure_call(pool, builder, mod, fp_alloca, + cargs, can, trans) + # 函数指针变量(t.Callable 注解 → i8** alloca):按实参构造签名间接调用 + if self.Gen.CallGenLeafKit._is_func_ptr_alloca(fp_alloca) != 0: + # 区分 t.Callable(真函数指针)vs t.CPtr(闭包指针): + # t.CPtr 变量(如 f: t.CPtr = make_counter())存的是闭包结构 + # {fn_ptr, env_ptr},调用必须提取 env 传参;若按函数指针直接 + # call,跳转到闭包结构数据地址崩溃(ClosureCallTest 运行时崩溃)。 + ve_fp: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, func_name) + is_cptr_annot_fp: int = 0 + if ve_fp is not None and ve_fp.AnnotClassName is not None: + if string.strstr(ve_fp.AnnotClassName, "CPtr") is not None: + is_cptr_annot_fp = 1 + if is_cptr_annot_fp == 0: + return self.Gen.CallGenLeafKit._translate_func_ptr_call(pool, builder, mod, fp_alloca, + func_name, cargs, can, trans) + return self.Gen.CallGenLeafKit.translate_closure_call(pool, builder, mod, fp_alloca, + cargs, can, trans) + # 其他 i8* 变量按闭包调用路径处理 + return self.Gen.CallGenLeafKit.translate_closure_call(pool, builder, mod, fp_alloca, + cargs, can, trans) + + # 翻译参数并链接 + # 有关键字参数且找到函数定义时,按参数名匹配 + if kw_count > 0 and found_func is not None and found_params is not None: + return self.Gen.CallGenLib._translate_call_with_kwargs( + pool, builder, mod, func_name, found_func, + cargs, can, keywords, kw_count, trans) + + head: llvmlite.Value | t.CPtr = None + tail: llvmlite.Value | t.CPtr = None + # memcpy 专用: 收集前三个 Value 的独立引用(避免共享 alloca 对象的 Next 被污染) + mc_dst2: llvmlite.Value | t.CPtr = None + mc_src2: llvmlite.Value | t.CPtr = None + mc_num2: llvmlite.Value | t.CPtr = None + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is not None: + arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is not None: + # 参数类型提升:当 found_func 为 None(stub 未注入)时, + # 根据外部函数签名推断期望类型,提升字面量(如 i32→i64) + # 避免 declare(i64) 与 call(i32) 类型不匹配 + if found_func is None and arg_val.Ty is not None: + # 数组实参按 C 语义衰减为元素指针(对齐 TPC + # _decay_array_to_ptr),与 _translate_method_call 一致。 + if self.Gen.ExprGenBase.is_ptr_type(arg_val.Ty) != 0: + arr_pointee_fc: llvmlite.LLVMType | t.CPtr = arg_val.Ty.Pointee + if arr_pointee_fc is not None: + match arr_pointee_fc: + case llvmlite.LLVMType.Array(arr_et_fc, _): + decayed_fc: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( + builder, arr_pointee_fc, arr_et_fc, arg_val, + llvmlite.const_int32(pool, 0)) + if decayed_fc is not None: + arg_val = decayed_fc + case _: + pass + ext_param_ty: llvmlite.LLVMType | t.CPtr = self.Gen.CallGenLib._get_external_func_param_ty( + pool, func_name, ai) + if ext_param_ty is not None: + val_bits_ap: int = self.Gen.ExprGenBase.get_llvm_type_bits(arg_val.Ty) + tgt_bits_ap: int = self.Gen.ExprGenBase.get_llvm_type_bits(ext_param_ty) + if val_bits_ap != 0 and tgt_bits_ap != 0 and val_bits_ap != tgt_bits_ap: + if val_bits_ap == 1 and val_bits_ap < tgt_bits_ap: + arg_val = llvmlite.build_zext(builder, arg_val, ext_param_ty) + else: + arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, ext_param_ty, arg) + elif found_func is not None: + # found_func 存在:按形参类型 coerce(如 stdlib.malloc(size: t.CSizeT)) + # 修复: CDefine/i32 常量传给 i64 形参未提升,导致 call(i32) 与 define(i64) 不匹配 + fp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + fpi: int = 0 + while fp is not None and fpi < ai: + fp = llvmlite.param_get_next(fp) + fpi += 1 + if fp is not None: + fpty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(fp) + if fpty is not None: + arg_val = self.Gen.ExprGenBase.coerce_to_type( + builder, arg_val, fpty, arg) + elif found_func.IsVarArg == 1: + # Win64 变参 8 字节槽位:<64 位整数按 i64 传(sext 符号扩展), + # f32 提升为 f64。若按原窄类型传,调用点只写 4 字节进 8 字节槽, + # 高 4 字节残留旧栈数据,va_arg(i64) 读到垃圾(如 DefineTest + # PAGE=%d 读到 0x400921FB00001000,高位是 PI 残留)。 + # 对齐 TPC FuncGen/Python-llvmlite 的 ABI 自动提升。 + ab_va: int = self.Gen.ExprGenBase.get_llvm_type_bits(arg_val.Ty) + af_va: int = self.Gen.ExprGenBase.get_llvm_float_bits(arg_val.Ty) + i64_va: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + if ab_va != 0 and ab_va < 64: + arg_val = llvmlite.build_sext(builder, arg_val, i64_va) + elif af_va == 32: + arg_val = llvmlite.build_fpext( + builder, arg_val, llvmlite.Double(pool)) + arg_val.Next = None + if head is None: + head = arg_val + else: + tail.Next = arg_val + tail = arg_val + # memcpy 专用: 保存前三个参数的独立引用 + if ai == 0: + mc_dst2 = arg_val + elif ai == 1: + mc_src2 = arg_val + elif ai == 2: + mc_num2 = arg_val + + # 默认参数填充:当实参数量 < 形参数量时,用默认值填充缺失参数 + # defaults 数组右对齐到 args:defaults[0] 对应 args[offset],offset = param_count - default_count + if can > 0 or (can == 0 and cargs is not None): + df_defaults: t.CVoid | t.CPtr = None + df_default_count: int = 0 + df_param_count: int = 0 + # 先从当前模块函数表查找 FuncEntry + if trans is not None and trans._funcs is not None: + df_entry: FuncEntry | t.CPtr = ExprCallTable.find_func_entry_in_table( + trans._funcs, trans._func_count, func_name) + if df_entry is not None: + df_defaults = df_entry.Defaults + df_default_count = df_entry.DefaultCount + df_param_count = df_entry.ParamCount + # 无条件查询全局默认参数表(跨模块/同模块都要用 stdlib 常量快照 + # 重建默认值:模块表 Defaults 指向 pool 内 AST,跨 1b reset 后悬空; + # 快照才是跨文件永久存活。同模块命中时 gd_entry 也必须已赋值, + # 否则下方 _build_const_from_snapshot 读到未初始化栈垃圾指针崩溃。 + # 与 _translate_method_call 的 mdf_gd 无条件查询(L2677)保持一致。 + gd_entry: FuncDefaultsEntry | t.CPtr = self.Gen.CallGenLeafKit.find_func_defaults(func_name) + if df_defaults is None and gd_entry is not None: + df_defaults = gd_entry.Defaults + df_default_count = gd_entry.DefaultCount + df_param_count = gd_entry.ParamCount + # 填充缺失参数 + if df_defaults is not None and df_default_count > 0 and can < df_param_count: + df_offset: int = df_param_count - df_default_count + df_di: int = 0 + while df_di < df_default_count: + df_param_idx: int = df_offset + df_di + if df_param_idx >= can: + # 优先用 stdlib 常量快照重建(gd_entry.Defaults 的 pool 内 AST 可能已被 reset 回收) + df_arg_val: llvmlite.Value | t.CPtr = None + if gd_entry is not None: + df_arg_val = self.Gen.CallGenLeafKit._build_const_from_snapshot( + pool, mod, gd_entry, df_di, trans, builder) + if df_arg_val is None: + df_defaults_list: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(df_defaults), t.CPtr)) + df_default_node: ast.AST | t.CPtr = df_defaults_list.get(df_di) + if df_default_node is not None: + df_arg_val = self.Gen.ExprGen.translate_value( + builder, pool, mod, df_default_node, None, 0, trans) + if df_arg_val is not None: + df_arg_val.Next = None + if head is None: + head = df_arg_val + else: + tail.Next = df_arg_val + tail = df_arg_val + df_di += 1 + + # 使用模块中的实际函数名(可能带 SHA1 前缀,如 "83210a72e829a086.atoi") + # t.CExtern/t.State/t.CExport 函数不加 SHA1 前缀,使用裸名 + # declare 和 define 统一用 found_func.Name: + # - 普通函数的 declare/define 都带 SHA1 前缀(forward_declare_functions 和 stub 注入都用 mangled_name) + # - t.CExtern/t.State/t.CExport 函数的 declare/define 都用裸名 + # 旧逻辑(IsDeclared==1 时用 func_name 裸名)是错误的:stub 注入的 declare Name 已带 SHA1 前缀, + # 用裸名会导致 call @_PathToModuleName 而 define 是 @"sha1._PathToModuleName",链接报 undefined reference + call_name: str = func_name + # 原始函数名(别名导入时记录,如 from X import parse as json_parse → orig_func_name="parse") + # 用于在别名处理后重新推断返回类型,避免 _infer_external_func_ret_ty 用别名匹配失败 + orig_func_name: str = None + if found_func is not None: + found_name: str = llvmlite.function_get_name(found_func) + if found_name is not None: + call_name = found_name + else: + # 跨模块函数调用:found_func 为 None 时,检查是否是模块限定调用 + # 如 string.strchr(...) → @{sha1_of_string}.strchr + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + xmod_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if xmod_at.value is not None and (xmod_at.value.kind() == ast.ASTKind.Name + or xmod_at.value.kind() == ast.ASTKind.Attribute): + # 模块路径:单层 Name(string.strchr)或嵌套 Attribute + # (os._win32.exists)。嵌套路径此前不支持 → os/__init__.vp + # 内部调 os._win32.exists 只能被 find_func_in_module 后缀匹配 + # 命中本模块同名 define(无限递归),或找不到模块路径而走 + # 错误 fallback;此处用完整模块路径解析正确 SHA1(与校验段 + # L7344 对齐,SysLibTest 0xC00000FD 根因)。 + xmod_path: str = None + if xmod_at.value.kind() == ast.ASTKind.Name: + xmod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(xmod_at.value) + if xmod_nm.id is not None: + xmod_path = xmod_nm.id + else: + xmod_path = self.Gen.ExprGenAttr._attr_module_path_str(pool, xmod_at.value) + if xmod_path is not None: + mod_sha1: str = self._lookup_module_sha1(xmod_path) + if mod_sha1 is not None: + # fast-fail: 模块限定调用要求模块已被当前文件 import。 + # 全局 SHA1 存储包含所有被扫描的 includes,未导入的模块 + # (如 this.this() 但 import this 被注释)也会命中存储, + # 静默生成 @{sha1}.func 调用而非报错——违反"找不到 fast-fail"原则。 + is_xmod_imported: int = 1 + if trans is not None and trans._imported_modules is not None: + is_xmod_imported = self.Gen.ImportsGen.is_module_imported( + trans._imported_modules, xmod_path) + if is_xmod_imported == 0: + err_ni: str = pool.alloc(256) + if err_ni is not None: + viperlib.snprintf(err_ni, 256, + "跨模块调用 '%s.%s':模块 '%s' 未导入(请先 import %s)", + xmod_path, func_name, xmod_path, xmod_path) + self.Gen.TypeGenErr.fatal_error(xmod_at, err_ni) + self.Gen.TypeGenErr.fatal_error(xmod_at, "跨模块调用:模块未导入") + # 检查是否是 re-export 函数(如 ast._lexer_init 实际定义在 ast.lexer) + reexport_src: str = self.Gen.ImportsGen.lookup_reexport(mod_sha1, func_name) + if reexport_src is None: + # re-export 表未命中(includes 模块 stub/text 已存在时 + # 不被按需全量翻译,表只在 declare_only=0 时注册,可能为空): + # 按需解析该模块 .vpi 的 from-import 定位定义模块 + reexport_src = self._lookup_reexport_from_vpi(pool, mod_sha1, func_name) + if reexport_src is not None: + reexport_sha1: str = self._lookup_module_sha1(reexport_src) + if reexport_sha1 is not None: + mod_sha1 = reexport_sha1 + # CExport 函数定义用裸名(@strlen),跨模块调用需用裸名而非 @{sha1}.func + if self.Gen.CallGenBase.is_cexport_func(mod_sha1, func_name) != 0: + call_name = func_name + elif self._is_state_func_from_vpi(pool, mod_sha1, func_name) != 0: + # t.State 标记的外部 C 函数(如 CPython PyList_Size): + # 定义端用裸名 @PyList_Size(链接外部库),跨模块调用 + # 必须用裸名——带 sha1 前缀 → ld.lld undefined symbol + call_name = func_name + else: + mangled_len: t.CSizeT = string.strlen(mod_sha1) + string.strlen(func_name) + 2 + mangled: str = pool.alloc(mangled_len) + if mangled is not None: + viperlib.snprintf(mangled, mangled_len, "%s.%s", mod_sha1, func_name) + call_name = mangled + else: + # t 和 c 是内部库,豁免 SHA1 查找:使用裸名调用 + if string.strcmp(xmod_path, "t") == 0 or string.strcmp(xmod_path, "c") == 0: + call_name = func_name + else: + # Bug 修复: 先检查是否是已导入的模块名(如 BuildPipeline.run_pipeline) + # 如果是已导入模块但 SHA1 未注册,说明该模块未被编译(如 Phase2 未扫描到), + # 应该立即报错,而不是错误地走 from_imports 查找(会被 star import 回退误导) + is_imported_mod: int = 0 + if trans is not None and trans._imported_modules is not None: + is_imported_mod = self.Gen.ImportsGen.is_module_imported( + trans._imported_modules, xmod_path) + if is_imported_mod != 0: + # 别名导入(import X as Y):Y 在 _imported_modules 中, + # 但 _lookup_module_sha1("Y") 精确匹配失败(mod_arr 只存文件名)。 + # 先尝试 from_imports 查找别名→完整模块名→后缀匹配 SHA1。 + # allow_star_fallback=0 避免被 star import 回退误导。 + alias_sha1: str = None + if trans is not None and trans._from_imports is not None: + alias_sha1 = self._lookup_mod_sha1(pool, trans._from_imports, xmod_path, 0) + if alias_sha1 is not None: + if self.Gen.CallGenBase.is_cexport_func(alias_sha1, func_name) != 0: + call_name = func_name + elif self._is_state_func_from_vpi(pool, alias_sha1, func_name) != 0: + # t.State 外部 C 函数:裸名(同主路径 L7918) + call_name = func_name + else: + AliasMangledLen: t.CSizeT = string.strlen(alias_sha1) + string.strlen(func_name) + 2 + alias_mangled: str = pool.alloc(AliasMangledLen) + if alias_mangled is not None: + viperlib.snprintf(alias_mangled, AliasMangledLen, "%s.%s", alias_sha1, func_name) + call_name = alias_mangled + else: + # 已导入模块但 SHA1 未注册:该模块未被编译,立即报错 + err_msg_imp: str = pool.alloc(256) + if err_msg_imp is not None: + viperlib.snprintf(err_msg_imp, 256, "模块 '%s' 已导入但 SHA1 未注册(该模块未被编译)", xmod_path) + self.Gen.TypeGenErr.fatal_error(xmod_at, err_msg_imp) + self.Gen.TypeGenErr.fatal_error(xmod_at, "已导入模块 SHA1 未注册") + else: + # 检查是否是通过 from import 导入的名称(如 from .__types import LLVMType) + # LLVMType.Ptr(ty) 中 LLVMType 是类名不是模块名, + # 但 Ptr 是 __types 模块的模块级函数 + # 禁用 star import 回退:xmod_path 是明确名称,不应回退到 star import 模块 + from_sha1: str = None + if trans is not None and trans._from_imports is not None: + from_sha1 = self._lookup_mod_sha1(pool, trans._from_imports, xmod_path, 0) + if from_sha1 is not None: + # CExport 函数定义用裸名,跨模块调用需用裸名 + if self.Gen.CallGenBase.is_cexport_func(from_sha1, func_name) != 0: + call_name = func_name + else: + fmangled_len: t.CSizeT = string.strlen(from_sha1) + string.strlen(func_name) + 2 + fmangled: str = pool.alloc(fmangled_len) + if fmangled is not None: + viperlib.snprintf(fmangled, fmangled_len, "%s.%s", from_sha1, func_name) + call_name = fmangled + else: + err_msg2: str = pool.alloc(256) + if err_msg2 is not None: + viperlib.snprintf(err_msg2, 256, "跨模块调用 '%s.%s' 找不到模块 SHA1", xmod_path, func_name) + self.Gen.TypeGenErr.fatal_error(xmod_at, err_msg2) + self.Gen.TypeGenErr.fatal_error(xmod_at, "跨模块调用找不到模块 SHA1") + else: + # 裸名调用(非 Attribute):检查 from_imports + # 治本修复:函数调用禁用 star import 回退(allow_star_fallback=0)。 + # star import(from stdint import *)本意是导入类型/常量(如 BYTEPTR),而非函数; + # 函数应显式 from import。漏导函数若走 star 回退会被错归到 star 模块,生成错误 SHA1 符号 + # (如 block_insert_text_before_terminator 漏导后被错归 stdint,生成 + # f5522571bcce7bcb.block_insert... 而非 874bac141c97bae9.block_insert...)。 + # 禁用回退后,漏导函数编译期即报"未定义且未导入"(fast-fail),优于链接期 undefined reference。 + if trans is not None and trans._from_imports is not None: + bare_sha1: str = self._lookup_mod_sha1(pool, trans._from_imports, func_name, 0) + if bare_sha1 is not None: + # 别名处理: from X import Y as Z → 调用 Z 时需用 Y 作为源模块函数名 + # 例如 from json.__parser import parse as json_parse → 修饰为 SHA1.parse 而非 SHA1.json_parse + bare_orig: str = self.Gen.ImportsGen.lookup_from_import_original( + trans._from_imports, func_name) + bare_func_name: str = func_name + if bare_orig is not None: + # bare_orig 指向 from_imports 内部缓冲区,未 null 终止 + # 需复制到独立缓冲区(截断于空格或 null) + bo_len: t.CSizeT = 0 + while bare_orig[bo_len] != ' ' and bare_orig[bo_len] != '\0': + bo_len += 1 + bo_buf: str = pool.alloc(bo_len + 1) + if bo_buf is not None: + for bo_i in range(bo_len): + bo_buf[bo_i] = bare_orig[bo_i] + bo_buf[bo_len] = '\0' + bare_func_name = bo_buf + # 记录原始函数名,供后续重新推断返回类型 + # 例如 from json.__parser import parse as json_parse + # func_name="json_parse", bare_func_name="parse" + # _infer_external_func_ret_ty 用 "parse" 能正确匹配,用 "json_parse" 则返回默认 i32 + orig_func_name = bare_func_name + # re-export 解析(对齐模块限定路径 L6598): + # 裸名 from import 的函数可能实际定义在子模块(re-export)。 + # 例:from ast import dump → dump 定义在 ast.base(sha1=71b2), + # ast/__init__(sha1=876e)只是 re-export。若沿用包 sha1 构造 + # call_name="876e.dump",text.ll/vpi 返回类型解析均未命中, + # fail-fast 报"返回类型无法精确获取";需重定向到定义模块 SHA1。 + reexport_src2: str = self.Gen.ImportsGen.lookup_reexport(bare_sha1, bare_func_name) + if reexport_src2 is None: + # re-export 表未命中:按需解析该模块 .vpi 的 from-import + reexport_src2 = self._lookup_reexport_from_vpi(pool, bare_sha1, bare_func_name) + if reexport_src2 is not None: + reexport_sha1_2: str = self._lookup_module_sha1(reexport_src2) + if reexport_sha1_2 is not None: + bare_sha1 = reexport_sha1_2 + if self.Gen.CallGenBase.is_cexport_func(bare_sha1, bare_func_name) != 0: + call_name = bare_func_name + else: + bare_mangled_len: t.CSizeT = string.strlen(bare_sha1) + string.strlen(bare_func_name) + 2 + bare_mangled: str = pool.alloc(bare_mangled_len) + if bare_mangled is not None: + viperlib.snprintf(bare_mangled, bare_mangled_len, "%s.%s", bare_sha1, bare_func_name) + call_name = bare_mangled + else: + err_msg3: str = pool.alloc(256) + if err_msg3 is not None: + viperlib.snprintf(err_msg3, 256, "裸名调用 '%s' 未定义且未导入", func_name) + self.Gen.TypeGenErr.fatal_error(node, err_msg3) + self.Gen.TypeGenErr.fatal_error(node, "裸名调用未定义且未导入") + else: + err_msg4: str = pool.alloc(256) + if err_msg4 is not None: + viperlib.snprintf(err_msg4, 256, "裸名调用 '%s' 未定义且未导入", func_name) + self.Gen.TypeGenErr.fatal_error(node, err_msg4) + self.Gen.TypeGenErr.fatal_error(node, "裸名调用未定义且未导入") + + # 直接调用 + # memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失) + if string.strcmp(func_name, "memcpy") == 0 and can >= 3: + return self.Gen.CallGenLib._emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst2, mc_src2, mc_num2) + # 别名导入重新推断返回类型: + # from X import parse as json_parse → func_name="json_parse" 时 _infer_external_func_ret_ty 返回默认 i32 + # 用 orig_func_name="parse" 重新推断,能正确匹配返回 i8*(JsonValue*) + # 避免指针被截断为 i32 后 inttoptr 丢失高 32 位导致崩溃 + if orig_func_name is not None and orig_func_name != func_name: + re_inferred_ty: llvmlite.LLVMType | t.CPtr = self.Gen.CallGenLib._infer_external_func_ret_ty(pool, orig_func_name) + if re_inferred_ty is not None: + call_ret_ty = re_inferred_ty + # ============================================================ + # 跨模块 Viper 函数返回类型精确解析(对齐方法路径,fail-fast) + # 根因:_infer_external_func_ret_ty 白名单未覆盖返回指针的模块函数 + # (new_lexer→Lexer* / tokenize→Token* / parse_tokens→AST*),兜底 i32 + # 导致 64 位指针被截断高 32 位 → inttoptr 无效指针 → 解引用崩溃 + # (AstTest 的 _lexer_init 崩溃链)。declare 也可能是错误 i32(_ensure_method_declare + # 曾用兜底类型创建),因此不信任 found_func 的 declare 返回类型。 + # 权威来源:text.ll define;次选:vpi stub 返回注解;均未命中立即终止。 + # 仅对 mangled("{16位hex}.func")调用生效;C 库/Win32 裸名走原白名单。 + # Phase 1a(declare_only)期间依赖 text.ll 未生成,保持原白名单行为不 fail-fast。 + # ============================================================ + if self.Gen.CallGenLib._is_sha1_mangled_call(call_name) != 0: + if trans is None or trans._declare_only == 0: + cf_dot: str = string.strchr(call_name, '.') + cf_last: str = string.strrchr(call_name, '.') + if cf_dot is not None and cf_last is not None: + cf_sha1: str = stdlib.malloc(17) + cf_bare_len: t.CSizeT = string.strlen(call_name) - \ + (t.CSizeT(t.CUInt64T(cf_last) - t.CUInt64T(call_name))) - 1 + cf_bare: str = stdlib.malloc(cf_bare_len + 1) + if cf_sha1 is not None and cf_bare is not None: + string.strncpy(cf_sha1, call_name, 16) + cf_sha1[16] = '\0' + string.strcpy(cf_bare, cf_last + 1) + # 本模块自身函数(泛型特化等):从当前 IR 已声明的函数 + # 取返回类型;不走跨模块 text.ll 查找——自己的 text.ll + # 在 Phase A 翻译中尚未生成,直接查会误报"依赖未生成" + # 并保持默认类型(GenericTest 泛型 add/combine 等警告 + # 根因)。未命中(特化尚未声明)保持默认推断。 + is_local_mod: int = 0 + if trans is not None and trans.ModuleSha1 is not None: + if string.strncmp(cf_sha1, trans.ModuleSha1, 16) == 0: + is_local_mod = 1 + if is_local_mod != 0: + local_fn: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, call_name) + if local_fn is not None and local_fn.RetTy is not None: + call_ret_ty = local_fn.RetTy + else: + cf_ret: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL( + pool, cf_sha1, None, cf_bare, 1) + if cf_ret is not None: + call_ret_ty = cf_ret + else: + cf_vpi: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi( + pool, cf_sha1, None, cf_bare) + if cf_vpi is not None: + call_ret_ty = cf_vpi + else: + # 区分两种失败场景: + # 1. 依赖模块 text.ll 存在但函数未命中 → 真错误,fail-fast + # 2. 依赖模块 text.ll 不存在(模块尚未翻译)→ Phase A 按 + # 文件顺序翻译,main.vp 先于其 import 的 mbuddytest.vp + # (同项目多源文件)。此时标记 trans._deps_pending=1, + # 保持白名单类型继续,Phase A 多遍循环下遍重译—— + # 届时依赖已生成 text.ll,可精确解析(治本:依赖先翻译)。 + if self._dep_text_ll_exists(pool, cf_sha1) != 0: + cf_err: str = VLogger.fmt_buf() + if cf_err is not None: + viperlib.snprintf( + cf_err, 1024, + "跨模块函数 '%s' 返回类型无法精确获取(text.ll/vpi 均未命中)," + "默认 i32 会截断指针/i64,请检查依赖模块是否已编译/注册", call_name) + VLogger.error(cf_err, "HandlesExprCall") + self.Gen.TypeGenErr.fatal_error( + node, + f"跨模块函数返回类型无法精确获取(text.ll/vpi 均未命中),默认 i32 会截断指针: {call_name}", + "TypeError") + else: + if trans is not None: + trans._deps_pending = 1 + cf_dbg: str = VLogger.fmt_buf() + if cf_dbg is not None: + viperlib.snprintf( + cf_dbg, 1024, + "跨模块函数 '%s' 依赖模块 text.ll 尚未生成(Phase A 顺序)," + "标记重试,本遍保持默认类型", call_name) + if VLogger.nowarn_register() == 0: + VLogger.warning(cf_dbg, "HandlesExprCall") + stdlib.free(cf_sha1) + stdlib.free(cf_bare) + # 跨模块调用:创建 declare 声明,避免 llc 报 undefined value + self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, can) + # 检查被调用函数是否为变长函数(*args),若是则对变长参数进行 C ABI 提升 + # (cargs 为本函数参数 AST 链表,self_offset=0 普通函数调用) + is_variadic_call: int = self.Gen.CallGenVa._check_and_promote_variadic_call( + pool, builder, mod, call_name, head, can, cargs, 0, trans) + # try-except:被调函数带 EH 输出参数时,追加输出实参 + 调用后检测异常 + return self.Gen.CallGenLeafKit._emit_eh_guarded_call( + builder, pool, mod, trans, found_func, call_name, head, can, + call_ret_ty, is_variadic_call) + + + + + + + + + + + + + diff --git a/App/lib/core/Gen/ClassGenBase.vp b/App/lib/core/Gen/ClassGenBase.vp index c1b524e..8bc4bfb 100644 --- a/App/lib/core/Gen/ClassGenBase.vp +++ b/App/lib/core/Gen/ClassGenBase.vp @@ -361,11 +361,11 @@ class ClassGenBase: nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(deco) if nm.id is not None: if string.strcmp(nm.id, "staticmethod") == 0: - meta |= META_STATIC + meta |= GenTypes.META_STATIC elif string.strcmp(nm.id, "property") == 0: - meta |= META_PROP_GETTER + meta |= GenTypes.META_PROP_GETTER elif string.strcmp(nm.id, "classmethod") == 0: - meta |= META_CLASS + meta |= GenTypes.META_CLASS elif string.strcmp(nm.id, "TLS") == 0: meta |= META_TLS elif k == ast.ASTKind.Attribute: @@ -385,11 +385,11 @@ class ClassGenBase: if is_prop_name != 0 or string.strcmp(at.attr, "setter") == 0 \ or string.strcmp(at.attr, "getter") == 0 or string.strcmp(at.attr, "deleter") == 0: if string.strcmp(at.attr, "setter") == 0: - meta |= META_PROP_SETTER + meta |= GenTypes.META_PROP_SETTER elif string.strcmp(at.attr, "getter") == 0: - meta |= META_PROP_GETTER + meta |= GenTypes.META_PROP_GETTER elif string.strcmp(at.attr, "deleter") == 0: - meta |= META_PROP_DELETER + meta |= GenTypes.META_PROP_DELETER return meta def register_class_meta(self, pool: memhub.MemBuddy | t.CPtr, kind: int, cls: str, field: str) -> int: diff --git a/App/lib/core/Gen/ClassGenVTable.vp b/App/lib/core/Gen/ClassGenVTable.vp index c3f3150..9a3f1b2 100644 --- a/App/lib/core/Gen/ClassGenVTable.vp +++ b/App/lib/core/Gen/ClassGenVTable.vp @@ -1,1311 +1,1298 @@ -import lib.core.Gen.GenTypes as GenTypes -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import viperlib -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT -import lib.core.StubMerger as StubMerger -import lib.core.CompilerFactory as CompilerFactory - - -import lib.core.Gen.ClassGenBase as ClassGenBase -import lib.core.Handles.ExprCallTable as ExprCallTable - - -# 方法元数据 flag:TLS(@t.TLS 装饰器,对齐 ClassGenBase 本地常量;本地副本避免跨模块 CDefine 查找) -META_TLS: t.CDefine = 32 -# 虚表方法数上限(原 HandlesClassDef.VTBL_METHOD_MAX,阶段 D 拆分遗漏) -VTBL_METHOD_MAX: t.CDefine = 32 - -# ============================================================ -# ClassGenVTable - ClassGenMixin 拆分(阶段 D):vtable 收集/生成/方法翻译 -# -# 继承 ClassGenBase(1 级,TPV self 调用仅支持 1 级父类)。 -# 跨 Mixin 调用统一走 HandlesClassDef 委托(经 _g_gen)。 -# @t.NoVTable:静态绑定。 -# ============================================================ -@t.NoVTable -class ClassGenVTable(ClassGenBase.ClassGenBase): - """vtable 收集/生成/方法翻译""" - - # ============================================================ - # _vtable_strcat — 将 src 追加到 dst 末尾 - # ============================================================ - def _vtable_strcat(self, dst: str, dst_size: t.CSizeT, - src: str): - """将 src 追加到 dst 末尾""" - if dst is None or src is None: - return - dlen: t.CSizeT = string.strlen(dst) - slen: t.CSizeT = string.strlen(src) - remain: t.CSizeT = dst_size - dlen - if remain <= 0: - return - i: t.CSizeT = 0 - while i < slen and i + 1 < remain: - dst[dlen + i] = src[i] - i += 1 - dst[dlen + i] = '\0' - # ============================================================ - # _vtable_name_needs_quote — 检查 LLVM 标识符是否需要引号 - # ============================================================ - def _vtable_name_needs_quote(self, name: str) -> int: - """检查 LLVM 标识符是否需要引号(以数字开头或含 '.')""" - if name is None: - return 0 - if '0' <= name[0] <= '9': - return 1 - for i in name: - if i == '.': - return 1 - return 0 - # ============================================================ - # _format_func_type_str — 从 Function 对象生成函数类型字符串 - # - # 格式: ret_ty (param1_ty, param2_ty, ...) - # 例如: void ({i32, i32}*, i32) - # ============================================================ - def _format_func_type_str(self, pool: memhub.MemBuddy | t.CPtr, - buf: str, buf_size: t.CSizeT, - func: llvmlite.Function | t.CPtr) -> int: - """从 Function 对象生成函数类型字符串""" - if buf is None or func is None or buf_size == 0: - return 0 - buf[0] = '\0' - # 打印返回类型(使用访问器函数避免跨模块直接字段访问) - ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(func) - ret_buf: str = pool.alloc(128) - if ret_buf is not None and ret_ty is not None: - ret_buf[0] = '\0' - llvmlite.TypePrint(ret_buf, 128, ret_ty, pool) - self._vtable_strcat(buf, buf_size, ret_buf) - self._vtable_strcat(buf, buf_size, " (") - - # 遍历参数(使用访问器函数避免跨模块直接字段访问) - cur: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) - first: int = 1 - param_buf: str = pool.alloc(128) - _pc: int = 0 - while cur is not None: - _pc += 1 - if _pc > 100: - break - if first == 0: - self._vtable_strcat(buf, buf_size, ", ") - if param_buf is not None: - param_buf[0] = '\0' - param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur) - if param_ty is not None: - llvmlite.TypePrint(param_buf, 128, param_ty, pool) - self._vtable_strcat(buf, buf_size, param_buf) - cur = llvmlite.param_get_next(cur) - first = 0 - self._vtable_strcat(buf, buf_size, ")") - return 1 - # ============================================================ - # _collect_vtable_methods — 收集类的虚方法信息 - # - # 1. 继承父类虚方法(父类方法排在子类方法之前,保持槽位顺序一致) - # 2. 收集当前类虚方法(跳过已继承的) - # - # 结果存入 self.VtFullNames/VtMethodNames/VtParentSha1s/VtMethodCount - # (原模块级 _g_vt_*),并设置 entry.VTableMethodCount / - # VTableMethods(stdlib 分配,供虚分派跨模块查询)。 - # - # 返回 1=有虚方法 / 0=无方法或失败 - # ============================================================ - def _collect_vtable_methods(self, trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr, - class_name: str) -> int: - """收集虚方法信息,设置 entry.VTableMethods/VTableMethodCount""" - if trans is None or cd is None or class_name is None: - return 0 - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - # 懒导入(find_func_global 探测方法实际定义类用) - import lib.core.Handles.HandlesExprCall as HandlesExprCall - - children: list[ast.AST | t.CPtr] | t.CPtr = cd.children - if children is None: - return 0 - cn: t.CSizeT = len(children) - - # 1. 收集虚方法信息 - # stdlib 分配:method_names_buf 存到 StructEntry.VTableMethods(跨文件永久存活), - # 必须迁出 mb 池 reset 区间,否则 1b 每文件 reset_to(mark1) 会回收导致悬空。 - full_names_buf: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(8 * VTBL_METHOD_MAX) - method_names_buf: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(8 * VTBL_METHOD_MAX) - # 记录每个方法的父类 SHA1(非 0=继承方法用父模块 SHA1 mangling,0=当前类方法) - method_parent_sha1s: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(8 * VTBL_METHOD_MAX) - if full_names_buf is None or method_names_buf is None or method_parent_sha1s is None: - return 0 - string.memset(full_names_buf, 0, 8 * VTBL_METHOD_MAX) - string.memset(method_names_buf, 0, 8 * VTBL_METHOD_MAX) - string.memset(method_parent_sha1s, 0, 8 * VTBL_METHOD_MAX) - - method_count: int = 0 - - # ============================================================ - # 1.5 继承父类虚方法 - # - # 父类虚方法排在子类虚方法之前,保持 vtable 槽位顺序一致。 - # 如果子类覆盖了方法,full_name 用子类的;否则用父类的。 - # 用 SHA1 感知查找,规避跨模块同名 find_struct 找错 - # ============================================================ - vt_self_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module( - class_name, trans.ModuleSha1) - # 多继承:遍历所有父类(声明顺序),vtable 方法合并(短名去重,先声明父类优先) - parent_count: int = self.Gen.StructGen.get_parent_count(class_name) - if parent_count > 0: - for pi in range(parent_count): - pname: str = self.Gen.StructGen.get_parent_name_at(class_name, pi) - if pname is None: - continue - # 查找父类 entry(优先同模块 SHA1 匹配) - vt_parent_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module( - pname, trans.ModuleSha1) - if vt_parent_entry is None: - # 跨模块继承: 父类在不同模块定义(SHA1 不同),回退到按类名查找 - vt_parent_entry = self.Gen.StructGen.find_struct(pname) - parent_vt_count: int = 0 - if vt_parent_entry is not None: - parent_vt_count = vt_parent_entry.VTableMethodCount - if parent_vt_count > 0: - for pvi in range(parent_vt_count): - if method_count >= VTBL_METHOD_MAX: - break - pmethod_name: str = None - if vt_parent_entry is not None: - pmethod_name = self.Gen.StructGen.get_vtable_method_name(pname, pvi) - if pmethod_name is None: - continue - # 多继承 vtable 去重:方法短名已存在跳过(先声明父类优先) - if self.Gen.ClassGenBase._field_name_exists(method_names_buf, method_count, pmethod_name) != 0: - continue - # 检查子类是否覆盖了该方法,以及是否标记 @t.NoVTable - child_overrides: int = 0 - child_nvt: int = 0 - for ci2 in range(cn): - stmt2: ast.AST | t.CPtr = children.get(ci2) - if stmt2 is None: - continue - if stmt2.kind() != ast.ASTKind.FunctionDef: - continue - fd2: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt2) - if fd2 is not None and fd2.name is not None: - if string.strcmp(fd2.name, pmethod_name) == 0: - child_overrides = 1 - # 检查子类覆盖方法是否标记 @t.NoVTable - if fd2.decorator_list is not None: - if self.Gen.ClassGenBase._has_decorator(fd2.decorator_list, "NoVTable") == 1: - child_nvt = 1 - break - # 构造 full_name - # 子类覆盖且未标记 NoVTable → 用子类实现 - # 子类未覆盖 或 子类覆盖但标记 NoVTable → 用实际定义类实现(保持 vtable 槽位) - # - # 多层继承修复: 直接父类可能只是继承而非定义该方法 - # (如 ElectricCar 继承 Car 的 is_running 实际定义在 Vehicle), - # 沿父类链向上用 find_func_global("类名.方法名") 探测实际定义类, - # 避免生成 "Car.is_running" 这类找不到函数的 full_name → vtable 槽变 null。 - def_class: str = class_name - if child_overrides == 1 and child_nvt == 0: - def_class = class_name - else: - def_class = pname - # 多继承:沿 pname 的 MRO 祖先链探测实际定义类(跳过自身,先声明父类优先) - mro_ptr: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, pname) - mro_i: int = 1 - while mro_ptr is not None and mro_ptr[mro_i] != 0: - anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mro_i], t.CPtr)) - if anc is not None: - probe_buf: str = pool.alloc(128) - if probe_buf is not None: - viperlib.snprintf(probe_buf, 128, "%s.%s", anc, pmethod_name) - if self.Gen.CallGenLeafKit.find_func_global(probe_buf) is not None: - def_class = anc - break - mro_i += 1 - pfname_buf: str = CompilerFactory.get_perm_pool().alloc(128) - if pfname_buf is not None: - viperlib.snprintf(pfname_buf, 128, "%s.%s", def_class, pmethod_name) - full_names_buf[method_count] = t.CSizeT(pfname_buf) - # 复制方法名(短名) - pmname_len: t.CSizeT = string.strlen(pmethod_name) - pmname_buf: str = CompilerFactory.get_perm_pool().alloc(pmname_len + 1) - if pmname_buf is not None: - string.strcpy(pmname_buf, pmethod_name) - method_names_buf[method_count] = t.CSizeT(pmname_buf) - # 记录 mangling 用的 SHA1(继承未覆盖的方法用实际定义类的模块 SHA1) - if child_overrides == 1 and child_nvt == 0: - # 子类覆盖: 用当前模块 SHA1(保持 0) - method_parent_sha1s[method_count] = 0 - else: - # 继承未覆盖: 用实际定义类的模块 SHA1(跨模块继承时 mangling 正确) - def_entry2: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct( - def_class) - if def_entry2 is not None and def_entry2.ModuleSha1 is not None: - method_parent_sha1s[method_count] = t.CSizeT(def_entry2.ModuleSha1) - else: - method_parent_sha1s[method_count] = 0 - method_count += 1 - - # 2. 收集当前类的虚方法(跳过已从父类继承的) - for ci in range(cn): - stmt: ast.AST | t.CPtr = children.get(ci) - if stmt is None: - continue - if stmt.kind() != ast.ASTKind.FunctionDef: - continue - fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) - if fd is None or fd.name is None: - continue - if method_count >= VTBL_METHOD_MAX: - break - - mname: str = fd.name - # 跳过构造函数和特殊方法(不应放入虚表) - if string.strcmp(mname, "__init__") == 0: - continue - if string.strcmp(mname, "__before_init__") == 0: - continue - if string.strcmp(mname, "__new__") == 0: - continue - # 函数级装饰器过滤:判断方法是否应该进入虚表 - if self.Gen.ClassGenBase._should_method_be_virtual(cd, fd, trans) == 0: - continue - # 检查是否已从父类继承(避免重复) - already_in_vt: int = 0 - for mi in range(method_count): - exist_addr: t.CSizeT = method_names_buf[mi] - if exist_addr != 0: - exist_name: str = (str | t.CPtr)(t.CVoid(exist_addr, t.CPtr)) - if exist_name is not None and string.strcmp(exist_name, mname) == 0: - already_in_vt = 1 - break - if already_in_vt == 1: - continue - # 构造 full_name = "ClassName.method_name" - # 内容必须落在 perm_pool:1a(mark_only=1)收集的 VTableMethods 被 - # Phase 1b 依赖模块翻译跨文件读取,1a 每文件 reset 后 pool 裸字符串悬空 - fname_buf: str = CompilerFactory.get_perm_pool().alloc(128) - if fname_buf is not None: - viperlib.snprintf(fname_buf, 128, "%s.%s", class_name, mname) - full_names_buf[method_count] = t.CSizeT(fname_buf) - - # 复制方法名 - mname_len: t.CSizeT = string.strlen(mname) - mname_buf: str = CompilerFactory.get_perm_pool().alloc(mname_len + 1) - if mname_buf is not None: - string.strcpy(mname_buf, mname) - method_names_buf[method_count] = t.CSizeT(mname_buf) - - method_count += 1 - - # 暂存结果(_generate_vtable 复用) - self.VtFullNames = full_names_buf - self.VtMethodNames = method_names_buf - self.VtParentSha1s = method_parent_sha1s - self.VtMethodCount = method_count - - # 设置 entry 元数据(虚分派查询用;必须在本类方法体翻译前就绪, - # 否则方法体内 self.虚方法 调用无法虚分派) - if vt_self_entry is not None and method_count > 0: - vt_self_entry.VTableMethodCount = method_count - vt_self_entry.VTableMethods = method_names_buf - - if method_count == 0: - return 0 - return 1 - # ============================================================ - # _generate_vtable — 生成 VTable 全局变量 - # - # 1. 收集 class body 中所有 FunctionDef 作为虚方法 - # 2. 构造 VTable 类型 { i8*, i8*, ... } - # 3. 构造初始化字符串 { i8* bitcast (...), ... } - # 4. 创建全局变量 @"SHA1.ClassName.vtable" - # 5. 存储虚方法名列表到 StructEntry - # ============================================================ - def _generate_vtable(self, trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr, - class_name: str) -> int: - """生成 VTable 全局变量""" - if trans is None or cd is None or class_name is None: - return 0 - - # 懒导入 - import lib.core.Handles.HandlesFunctions as HandlesFunctions - import lib.core.Handles.HandlesExprCall as HandlesExprCall - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - - # 收集虚方法信息(继承父类 + 自身,结果存 self.VtFullNames 等暂存区) - # 同时设置 entry.VTableMethodCount/VTableMethods(虚分派查询用) - if self._collect_vtable_methods(trans, cd, class_name) == 0: - return 0 - full_names_buf: t.CSizeT | t.CPtr = self.VtFullNames - method_names_buf: t.CSizeT | t.CPtr = self.VtMethodNames - method_parent_sha1s: t.CSizeT | t.CPtr = self.VtParentSha1s - method_count: int = self.VtMethodCount - # 重新获取 entry(后续存储 VTableMethods 用) - vt_self_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module( - class_name, trans.ModuleSha1) - - # 2. 构造 VTable 类型: { i8*, i8*, ..., i8* } - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - first_node: llvmlite.ParamNode | t.CPtr = None - tail_node: llvmlite.ParamNode | t.CPtr = None - for i in range(method_count): - pnode: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) - if pnode is None: - continue - tail_node = llvmlite.param_list_append(first_node, tail_node, pnode) - if first_node is None: - first_node = tail_node - - vtable_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, first_node, method_count, None) - if vtable_ty is None: - return 0 - - # 3. 构造初始化字符串 - # 大 vtable(如 MemBuddy 28+ 方法)每个方法 bitcast 约 100+ 字节, - # 4096 可能写满导致截断/strlen 越界,用 16384 预留足够空间。 - init_buf: str = pool.alloc(16384) - if init_buf is None: - return 0 - init_buf[0] = '\0' - self._vtable_strcat(init_buf, 16384, "{ ") - - for i in range(method_count): - if i > 0: - self._vtable_strcat(init_buf, 16384, ", ") - - full_name_addr: t.CSizeT = full_names_buf[i] - if full_name_addr == 0: - self._vtable_strcat(init_buf, 16384, "i8* null") - continue - - full_name: str = (str | t.CPtr)(t.CVoid(full_name_addr, t.CPtr)) - - # 检查是否是继承方法(method_parent_sha1s 非 0 表示用父模块 SHA1 mangling) - parent_sha1_addr: t.CSizeT = method_parent_sha1s[i] - if parent_sha1_addr != 0: - # 继承方法: 用父类模块 SHA1 做 mangling - parent_sha1: str = (str | t.CPtr)(t.CVoid(parent_sha1_addr, t.CPtr)) - mangled_name: str = self.Gen.FuncGenBase._mangle_name_with_sha1(parent_sha1, full_name) - # 从全局函数表查找(跨模块函数不在当前模块表中) - func: llvmlite.Function | t.CPtr = self.Gen.CallGenLeafKit.find_func_global(full_name) - else: - # 当前类方法: 用当前模块 SHA1 - mangled_name: str = self.Gen.FuncGenBase._mangle_name(trans, full_name) - func: llvmlite.Function | t.CPtr = self.Gen.CallGenLeafKit.find_func_in_table( - trans._funcs, trans._func_count, full_name) - # 当前模块表找不到时,回退到全局表 - if func is None: - func = self.Gen.CallGenLeafKit.find_func_global(full_name) - - # func 可能已被 1b reset_to(mark1) 回收(跨模块继承方法在定义文件翻译后被 reset)。 - # 悬空指针非 NULL 但内容已被复用,_format_func_type_str 解引用会沿垃圾 Next 链 - # 指针追逐导致无限分配(TypePrint 每次 pool.alloc(512) → 单文件暴涨 900MB OOM)。 - # 因此 func 非 NULL 时也须用 _is_valid_ptr 校验,失败回退到 TypeStr。 - func_valid: int = 0 - if func is not None: - if trans.Pool is not None: - # 继承方法(parent_sha1_addr != 0):func 来自其他模块,该模块 1b 翻译 - # 后已被 reset_to(mark1) 回收,_is_valid_ptr 存在假阳性(块头复用后仍 - # 看似有效),直接判定无效走 TypeStr 回退,避免解引用悬空 func 崩溃。 - if parent_sha1_addr != 0: - func_valid = 0 - elif trans.Pool._is_valid_ptr(func) != 0: - func_valid = 1 - if func_valid == 0: - # 回退到全局表完整 entry 的 TypeStr(stdlib 深拷贝,跨文件永久存活)。 - ge: GenTypes.FuncEntry | t.CPtr = self.Gen.CallGenLeafKit.find_func_entry_global(full_name) - if ge is not None and ge.TypeStr is not None: - self._vtable_strcat(init_buf, 16384, "i8* bitcast (") - self._vtable_strcat(init_buf, 16384, ge.TypeStr) - self._vtable_strcat(init_buf, 16384, "* @") - if self._vtable_name_needs_quote(mangled_name) != 0: - self._vtable_strcat(init_buf, 16384, "\"") - self._vtable_strcat(init_buf, 16384, mangled_name) - self._vtable_strcat(init_buf, 16384, "\"") - else: - self._vtable_strcat(init_buf, 16384, mangled_name) - self._vtable_strcat(init_buf, 16384, " to i8*)") - continue - # fail-fast:func 无效且全局表 TypeStr 回退也失败, - # 不再写 "i8* null" 静默掩盖缺失实现。 - self.Gen.TypeGenErr.fatal_error( - cd, f"vtable 方法 '{full_name}' 找不到函数实现", "InternalCompilerError") - continue - - # 构造函数类型字符串 - func_ty_buf: str = pool.alloc(512) - if func_ty_buf is None: - self._vtable_strcat(init_buf, 16384, "i8* null") - continue - self._format_func_type_str(pool, func_ty_buf, 512, func) - - # 构造 bitcast 字符串: i8* bitcast (func_ty* @mangled to i8*) - self._vtable_strcat(init_buf, 16384, "i8* bitcast (") - self._vtable_strcat(init_buf, 16384, func_ty_buf) - self._vtable_strcat(init_buf, 16384, "* @") - - if self._vtable_name_needs_quote(mangled_name) != 0: - self._vtable_strcat(init_buf, 16384, "\"") - self._vtable_strcat(init_buf, 16384, mangled_name) - self._vtable_strcat(init_buf, 16384, "\"") - else: - self._vtable_strcat(init_buf, 16384, mangled_name) - self._vtable_strcat(init_buf, 16384, " to i8*)") - - self._vtable_strcat(init_buf, 16384, " }") - - # 4. 构造 VTable 全局变量名 - vtable_name_buf: str = pool.alloc(128) - if vtable_name_buf is None: - return 0 - viperlib.snprintf(vtable_name_buf, 128, "%s.vtable", class_name) - vtable_mangled: str = self.Gen.FuncGenBase._mangle_name(trans, vtable_name_buf) - - # 5. 创建全局变量 - gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable( - pool, vtable_mangled, vtable_ty) - if gv is None: - return 0 - gv.Initializer = init_buf - gv.IsConstant = 1 - # 默认 linkage(external,2026-08-10):isinstance 内建函数需要跨模块 - # 引用其他模块类的 vtable 符号({模块sha1}.Class.vtable),internal 不对外 - # 导出会导致链接失败。vtable 名含模块 sha1 前缀全局唯一,外部可见不冲突。 - # llvmlite 打印规则:Initializer 非空 + external 时不打印 external 关键字, - # 输出 @name = constant {...}(合法外部强定义)。 - - # 添加到模块 - llvmlite.module_add_global(mod, gv) - - # 6. 存储虚方法名列表到 StructEntry(直接用 entry,规避跨模块同名 find_struct 找错) - if vt_self_entry is not None: - vt_self_entry.VTableMethods = method_names_buf - vt_self_entry.VTableMethodCount = method_count - - return 0 - # ============================================================ - # _translate_oop_methods — 扫描 class body 中的方法并翻译 - # - # 遍历 ClassDef.children,对每个 FunctionDef: - # - 标记 OOP(mark_as_oop) - # - 如果是 __init__,标记 has_init - # - 翻译方法(生成 SHA1.ClassName.method_name 函数) - # 翻译完所有方法后,生成 __before_init__ 函数 - # ============================================================ - def _translate_oop_methods(self, trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr, - struct_ty: llvmlite.LLVMType | t.CPtr, - class_name: str, - mark_only: int = 0, - reemit: int = 0) -> int: - """扫描 class body 中的方法并翻译,生成 __before_init__ - - mark_only: 0=全量翻译(默认),1=只设置 IsOOP/HasNew/HasInit 标志(不翻译方法体) - reemit: 1=补译模式(_specialize_generic_class Phase B 补译分支调用)。 - 补译分支为防重入已提前置 MethodsEmitted=1,但方法体尚未发射, - 必须跳过下方 MethodsEmitted==1 的防重复检查强制发射,否则补译 - 被自身拦截 → 特化方法只有 call 无 define → 链接 undefined symbol。 - """ - if trans is None or cd is None or struct_ty is None or class_name is None: - return 0 - - children: list[ast.AST | t.CPtr] | t.CPtr = cd.children - if children is None: - return 0 - - cn: t.CSizeT = len(children) - has_method: int = 0 - has_init: int = 0 - has_new: int = 0 - - # 提前用类型指针定位 entry(规避跨模块同名类 find_struct 找错) - oop_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_type(struct_ty) - - # 第一遍:检测是否有方法,标记 OOP,并注册装饰器元数据 - for ci in range(cn): - stmt: ast.AST | t.CPtr = children.get(ci) - if stmt is None: - continue - if stmt.kind() == ast.ASTKind.FunctionDef: - has_method = 1 - fd_check: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) - if fd_check is not None and fd_check.name is not None: - if string.strcmp(fd_check.name, "__init__") == 0: - has_init = 1 - if string.strcmp(fd_check.name, "__new__") == 0: - has_new = 1 - # 注册装饰器元数据(@property/@staticmethod/@classmethod/@x.setter 等)。 - # 此处(含 mark_only=1 的 struct 预注册阶段)注册, - # 确保其他模块在 App 文件翻译时能识别属性访问。 - fd_meta: int = self.Gen.ClassGenBase._extract_func_meta(fd_check.decorator_list) - if fd_meta != 0: - self.Gen.ClassGenBase.register_method_meta(class_name, fd_check.name, fd_meta) - - if has_method == 0: - # 子类没有自己的方法,但可能继承了父类的虚方法 - # 用 oop_entry 直接获取 ParentName,规避 find_struct 按名查找找错 - parent_name: str = None - if oop_entry is not None: - parent_name = oop_entry.ParentName - if parent_name is not None: - parent_vt_count: int = self.Gen.StructGen.get_vtable_method_count(parent_name) - if parent_vt_count > 0: - has_method = 1 # 标记为有方法(继承的虚方法) - if has_method == 0: - return 0 - - # 标记为 OOP 结构体 - if oop_entry is not None: - oop_entry.IsOOP = 1 - if has_init != 0: - oop_entry.HasInit = 1 - if has_new != 0: - oop_entry.HasNew = 1 - - # mark_only 模式:只设置标志,不翻译方法体 - if mark_only != 0: - # Phase 1a 预注册也收集 vtable 元数据(VTableMethods/VTableMethodCount)。 - # 根因:Phase 1b 中依赖模块可能先于其依赖类全量翻译(如 tokens.vp 先于 - # memhub 生成 text.ll),此时调用方查到 entry 有 HasVTable=1 但 - # VTableMethods=None → _translate_method_call 虚分派条件 - # (VTableMethods is not None)不成立 → pool.alloc 被静态绑定到 - # MemManager.alloc(默认返回 None)→ KwEntry.__new__ 返回 null → - # __before_init__ 写 null 崩溃。 - # 短名顺序与 Phase 1b 全量收集一致(父类方法在前 + 本类方法,确定性), - # 多遍扫描重复收集时用新缓冲区覆盖(stdlib 泄漏可忽略,Phase 1b 重译幂等)。 - mk_has_vt: int = 0 - if oop_entry is not None: - mk_has_vt = oop_entry.HasVTable - if mk_has_vt == 1: - self._collect_vtable_methods(trans, cd, class_name) - return 0 - - # 防重复生成:MethodsEmitted==1 说明方法体/__before_init__ 已生成过。 - # 场景:_specialize_generic_class 的 Phase B 补译分支(MethodsEmitted==0 - # 时补译方法体并置 1)之后,同一特化类又经 translate_class_def 全量 - # 翻译进入本方法 → 重复生成 __before_init__ → ld.lld duplicate symbol。 - # 已生成过则直接跳过(方法+__before_init__ 都产出过,跳过安全)。 - # reemit=1(补译模式)时跳过本检查:补译分支为防重入已提前置 - # MethodsEmitted=1,但方法体尚未发射,必须强制发射。 - if oop_entry is not None and oop_entry.MethodsEmitted == 1 and reemit == 0: - return 0 - - # 防重入:方法体翻译前先标记 MethodsEmitted=1。 - # 根因:若等全部方法译完再标记,翻译 __iter__(返回 list[T]|t.CPtr)时, - # 返回类型注解会再次触发 _specialize_generic_class,此时 MethodsEmitted - # 仍为 0,走补译分支把同一特化类方法全部重发 → invalid redefinition。 - if oop_entry is not None: - oop_entry.MethodsEmitted = 1 - - # 第二遍:翻译每个方法 - # 翻译方法体前先预注册 vtable 元数据(VTableMethods/VTableMethodCount)。 - # 根因:方法体翻译先于 _generate_vtable,若不预注册,方法体内的 - # self.虚方法 调用(如 MemManager.calloc 里的 self.alloc)读不到 - # VTableMethods,虚分派失败,被静态绑定到本类实现(基类 alloc 返回 - # None),导致 calloc 永远返回 NULL。 - oop_has_vt_pre: int = 0 - if oop_entry is not None: - oop_has_vt_pre = oop_entry.HasVTable - if oop_has_vt_pre == 1: - self._collect_vtable_methods(trans, cd, class_name) - for ci in range(cn): - stmt: ast.AST | t.CPtr = children.get(ci) - if stmt is None: - continue - if stmt.kind() == ast.ASTKind.FunctionDef: - fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) - if fd is not None and fd.name is not None: - self._translate_method(trans, fd, struct_ty, class_name) - - # 如果有虚表,先生成 VTable 全局变量(设置 VTableMethodCount) - # 必须在 __before_init__ 之前,否则 __before_init__ 读不到 VTableMethodCount - # 用 oop_entry 直接检查,规避跨模块同名 find_struct 找错 - has_vt_flag: int = 0 - if oop_entry is not None: - has_vt_flag = oop_entry.HasVTable - if has_vt_flag == 1: - self._generate_vtable(trans, cd, class_name) - - # 生成 __before_init__ 函数(零值填充 + 默认值赋值 + vtable 指针设置) - self._generate_before_init(trans, struct_ty, class_name) - - return 0 - # ============================================================ - # _translate_method — 翻译单个方法 - # - # 生成: define @SHA1.ClassName.method_name(Ptr(StructTy) %self, ...) - # - # self 参数处理: - # - 类型 Ptr(struct_ty),直接注册为 SSA 值(不创建 alloca) - # - 使 self.field 能通过 GEP 直接访问原始结构体 - # ============================================================ - def _translate_method(self, trans: HT.Translator | t.CPtr, - fd: ast.FunctionDef | t.CPtr, - struct_ty: llvmlite.LLVMType | t.CPtr, - class_name: str) -> int: - """翻译单个方法,返回 0""" - if trans is None or fd is None or struct_ty is None or class_name is None: - return 0 - - # 懒导入 - import lib.core.Handles.HandlesFunctions as HandlesFunctions - import lib.core.Handles.HandlesVar as HandlesVar - import lib.core.Handles.HandlesBody as HandlesBody - import lib.core.Handles.HandlesType as HandlesType - import lib.core.Handles.HandlesExprCall as HandlesExprCall - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - imported_modules: str = trans._imported_modules - from_imports: str = trans._from_imports - funcs_ptr: GenTypes.FuncEntry | t.CPtr = trans._funcs - func_count: int = trans._func_count - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - self_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) - - method_name: str = fd.name - if method_name is None: - # fail-fast:方法名缺失(解析器不可能产出无名 def)——静默打印 - VLogger.error("方法名缺失(fd.name is None)", "OOP") - self.Gen.TypeGenErr.fatal_error(fd, "方法名缺失(fd.name is None)", "TypeError") - - # 提取装饰器元数据(@property/@staticmethod/@classmethod/@x.setter/@x.deleter) - func_meta: int = self.Gen.ClassGenBase._extract_func_meta(fd.decorator_list) - # property setter/deleter 函数名带 $set/$del 后缀,避免与 getter 冲突 - method_name_buf: str = pool.alloc(128) - if method_name_buf is None: - return 0 - viperlib.snprintf(method_name_buf, 128, "%s", fd.name) - if func_meta & META_PROP_SETTER != 0: - # 128 字节缓冲:追加 "$set" 前检查剩余容量,防 strcat 无界写穿 - mn_len2: t.CSizeT = string.strlen(method_name_buf) - if mn_len2 + 5 < 128: - string.strcat(method_name_buf, "$set") - elif func_meta & META_PROP_DELETER != 0: - mn_len2: t.CSizeT = string.strlen(method_name_buf) - if mn_len2 + 5 < 128: - string.strcat(method_name_buf, "$del") - method_name = method_name_buf - - is_static_m: int = 0 - is_class_m: int = 0 - is_tls_m: int = 0 - if func_meta & META_STATIC != 0: - is_static_m = 1 - if func_meta & META_CLASS != 0: - is_class_m = 1 - if func_meta & META_TLS != 0: - is_tls_m = 1 - - # 构建方法全名: ClassName.method_name - full_name_buf: str = pool.alloc(128) - if full_name_buf is None: - return 0 - viperlib.snprintf(full_name_buf, 128, "%s.%s", class_name, method_name) - full_name: str = full_name_buf - - # SHA1 命名空间混淆 - mangled_name: str = self.Gen.FuncGenBase._mangle_name(trans, full_name) - - # 推断返回类型 - ret_ty: llvmlite.LLVMType | t.CPtr = None - if fd.returns is not None: - ret_ty = self.Gen.TypeGenResolve.resolve_annotation_type( - pool, fd.returns, imported_modules, from_imports, trans) - if ret_ty is None and fd.returns is not None: - if self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "State") != 0: - ret_ty = llvmlite.Void(pool) - if ret_ty is None: - # __init__ 和 __before_init__ 返回 void - if string.strcmp(method_name, "__init__") == 0: - ret_ty = llvmlite.Void(pool) - # __new__ 返回 Ptr(struct_ty)(结构体指针作为存储空间) - elif string.strcmp(method_name, "__new__") == 0: - ret_ty = llvmlite.Ptr(pool, struct_ty) - else: - param_types_str: str = self.Gen.TypeGenErr.build_param_types_str(pool, fd.args) - ret_ty = self.Gen.TypeGenErr.infer_return_type( - pool, fd.children, param_types_str) - - # 创建 LLVM 函数 - func: llvmlite.Function | t.CPtr = llvmlite.create_function( - pool, mod, mangled_name, ret_ty) - if func is None: - return 0 - - # 提取默认参数信息(普通方法 args[0] 是 self,不含在 param_count 中; - # @staticmethod 无 self,param_count 为完整参数数) - # 注意: 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(), - # 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错 - md_defaults: t.CVoid | t.CPtr = None - md_default_count: int = 0 - md_param_count: int = 0 - md_args_node: ast.Arguments | t.CPtr = fd.args - if md_args_node is not None: - md_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(md_args_node) - if md_ags.args is not None: - md_alist: list[ast.AST | t.CPtr] | t.CPtr = md_ags.args - if is_static_m != 0: - md_param_count = len(md_alist) - else: - md_param_count = len(md_alist) - 1 - if md_ags.defaults is not None: - md_dlist: list[ast.AST | t.CPtr] | t.CPtr = md_ags.defaults - md_defaults = md_dlist - md_default_count = len(md_dlist) - - # 注册到函数表(用 ClassName.method_name 作为查找名,支持后缀匹配) - max_funcs: int = 1024 - if self.Gen.CallGenLeafKit.add_func_to_table(funcs_ptr, func_count, full_name, func, max_funcs, - md_defaults, md_default_count, md_param_count, - pool) == 0: - trans._func_count = func_count + 1 - - # 添加 self/cls 参数(Ptr(struct_ty));@staticmethod 无 self,跳过 - # @classmethod 的 cls 也用 Ptr(struct_ty),首参名取 args[0](如 cls) - if is_static_m == 0: - first_pname: str = "self" - if is_class_m != 0 and fd.args is not None: - fd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args) - if fd_ags.args is not None and len(fd_ags.args) > 0: - fd_first_arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(fd_ags.args.get(0)) - if fd_first_arg is not None and fd_first_arg.arg is not None: - first_pname = fd_first_arg.arg - first_pname_buf: str = pool.alloc(32) - if first_pname_buf is not None: - viperlib.snprintf(first_pname_buf, 32, "%%%s", first_pname) - llvmlite.add_param(pool, func, self_ptr_ty, first_pname_buf) - - # 添加其他参数(支持类型注解;@staticmethod 从索引 0 开始,其余跳过索引 0 的 self/cls) - args_node: ast.Arguments | t.CPtr = fd.args - if args_node is not None: - ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) - if ags.args is not None: - alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args - an: t.CSizeT = len(alist) - start_idx: int = 0 - if is_static_m == 0: - start_idx = 1 - for ai in range(start_idx, an): - arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) - if arg is not None and arg.arg is not None: - param_ty: llvmlite.LLVMType | t.CPtr = i32_ty - if arg.annotation is not None: - resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( - pool, arg.annotation, imported_modules, from_imports, trans) - if resolved is not None: - # 裸类形参 → Ptr(struct):按"对象即指针"引用传参。 - # 若按 struct 值传参,self.Head = node 会取局部拷贝地址 - # (append 返回后悬垂,G5 Test4 head.Value 读到垃圾)。 - # CArray 形参 → 元素指针 ty*(数组衰减,C 语义,与函数形参一致)。 - match resolved: - case llvmlite.LLVMType.Struct(_, _, _): - param_ty = llvmlite.Ptr(pool, resolved) - case llvmlite.LLVMType.Array(aelem_ty, _): - param_ty = llvmlite.Ptr(pool, aelem_ty) - case _: - param_ty = resolved - pname: str = pool.alloc(32) - if pname is not None: - viperlib.snprintf(pname, 32, "%%%s", arg.arg) - llvmlite.add_param(pool, func, param_ty, pname) - - # OOP iter 协议:__next__ 方法注入隐藏参数 __stop_iter_flag__(i1*)。 - # raise StopIteration 时置 1(对齐 TPC HandlesFunctions.py L703-705)。 - # 该参数不计入 md_param_count(逻辑参数),调用侧(for 循环)显式传。 - if string.strcmp(method_name, "__next__") == 0: - i1_ty_si: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - if i1_ty_si is not None: - i1_ptr_ty_si: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_si) - if i1_ptr_ty_si is not None: - llvmlite.add_param(pool, func, i1_ptr_ty_si, "%__stop_iter_flag__") - - # 参数添加完成,补全全局函数表的 TypeStr(供 vtable 在 func 被 reset 后使用) - self.Gen.CallGenLeafKit.update_global_func_typestr(pool, full_name, func) - - # 创建 entry 块 - entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") - if entry_blk is None: - return 0 - - # 创建方法专属 builder - func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) - if func_builder is None: - return 0 - llvmlite.position_at_end(func_builder, entry_blk) - - # @t.TLS 一次性初始化守卫(对齐 TPC HandlesFunctions.py L1763-1792; - # 与 FuncGenMixin.translate_function_def 同一实现,类方法同样支持) - if is_tls_m != 0: - tls_m_flag_name: str = pool.alloc(128) - if tls_m_flag_name is not None: - viperlib.snprintf(tls_m_flag_name, 128, "__tls_init_done_%s", method_name) - tls_m_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.create_global_int( - pool, mod, tls_m_flag_name, 1, 0) - if tls_m_gv is not None: - i1_ty_m: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - if i1_ty_m is not None: - # GlobalVariable 非 Value 子类:构造 Value 视图后再 load/store - tls_m_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_m) - tls_m_rn: str = pool.alloc(64) - if tls_m_rn is not None: - viperlib.snprintf(tls_m_rn, 64, "@%s", tls_m_flag_name) - tls_m_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, tls_m_ptr_ty, tls_m_rn) - if tls_m_ref is not None: - tls_m_ld: llvmlite.Value | t.CPtr = llvmlite.build_load( - func_builder, i1_ty_m, tls_m_ref) - lc_m: int = trans._label_counter - trans._label_counter = lc_m + 1 - tls_m_buf: str = pool.alloc(64) - if tls_m_buf is not None: - viperlib.snprintf(tls_m_buf, 64, "tls.skip.%d", lc_m) - tls_m_skip: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, tls_m_buf) - viperlib.snprintf(tls_m_buf, 64, "tls.cont.%d", lc_m) - tls_m_cont: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, tls_m_buf) - if tls_m_skip is not None and tls_m_cont is not None: - llvmlite.build_cond_br( - func_builder, tls_m_ld, tls_m_skip, tls_m_cont) - llvmlite.position_at_end(func_builder, tls_m_skip) - match ret_ty: - case llvmlite.LLVMType.Void(): - llvmlite.build_ret_void(func_builder) - case llvmlite.LLVMType.Int(_): - tlm0: llvmlite.Value | t.CPtr = llvmlite.ConstInt( - pool, ret_ty, 0, "0") - if tlm0 is not None: - llvmlite.build_ret(func_builder, tlm0) - case llvmlite.LLVMType.Float(_): - tlmf: llvmlite.Value | t.CPtr = llvmlite.ConstFloat( - pool, ret_ty, 0.0) - if tlmf is not None: - llvmlite.build_ret(func_builder, tlmf) - case _: - tlmn: llvmlite.Value | t.CPtr = llvmlite.ConstNull( - pool, ret_ty, "null") - if tlmn is not None: - llvmlite.build_ret(func_builder, tlmn) - llvmlite.position_at_end(func_builder, tls_m_cont) - tlmo: llvmlite.Value | t.CPtr = llvmlite.ConstInt( - pool, i1_ty_m, 1, "1") - if tlmo is not None: - llvmlite.build_store(func_builder, tlmo, tls_m_ref) - - # 进入函数作用域 - self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_FUNCTION) - - # 为 self/cls 创建 alloca 并 store(与其他参数一致);@staticmethod 无 self,跳过 - # 修复: 之前 self 注册为 SSA 值导致 translate_name_value 错误地 load 一次 - # 将 Ptr(struct_ty) 变成 struct 值,引发变参函数 ABI 不匹配崩溃 - if is_static_m == 0: - self_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, self_ptr_ty) - if self_alloca is not None: - self_var_name: str = "self" - self_ssa_name: str = "%self" - if is_class_m != 0 and args_node is not None: - cags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) - if cags.args is not None and len(cags.args) > 0: - cfirst: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(cags.args.get(0)) - if cfirst is not None and cfirst.arg is not None: - self_var_name = cfirst.arg - self_ssa_name_buf: str = pool.alloc(32) - if self_ssa_name_buf is not None: - viperlib.snprintf(self_ssa_name_buf, 32, "%%%s", cfirst.arg) - self_ssa_name = self_ssa_name_buf - self.Gen.VarGen.define_var(trans.SymTab, self_var_name, self_alloca) - # 设置 self/cls 的类型注解类名(属性访问 lookup_field 回退查找用) - self.Gen.VarGen.set_var_annot_class_name(trans.SymTab, self_var_name, class_name) - self_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, self_ptr_ty, self_ssa_name) - llvmlite.build_store(func_builder, self_val, self_alloca) - - # 为其他参数创建 alloca 并 store(与普通函数一致; - # @staticmethod 从索引 0 开始,其余跳过索引 0 的 self/cls 参数) - if args_node is not None: - ags2: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) - if ags2.args is not None: - alist2: list[ast.AST | t.CPtr] | t.CPtr = ags2.args - an2: t.CSizeT = len(alist2) - start_idx2: int = 0 - if is_static_m == 0: - start_idx2 = 1 - for ai2 in range(start_idx2, an2): - arg2: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist2.get(ai2)) - if arg2 is not None and arg2.arg is not None: - param_ty2: llvmlite.LLVMType | t.CPtr = i32_ty - if arg2.annotation is not None: - resolved2: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( - pool, arg2.annotation, imported_modules, from_imports, trans) - if resolved2 is None: - # fail-fast:参数有注解但类型解析失败,不再静默保持 i32 - self.Gen.TypeGenErr.fatal_error( - arg2, f"方法 '{class_name}.{method_name}' 参数 '{arg2.arg}' 类型解析失败", - "NameError") - resolved2 = i32_ty # 不可达(fatal_error 已退出) - if resolved2 is not None: - # 与 add_param 保持一致:裸类形参 → Ptr(struct)(对象即指针) - # CArray 形参 → 元素指针 ty*(数组衰减,与 add_param 一致) - match resolved2: - case llvmlite.LLVMType.Struct(_, _, _): - param_ty2 = llvmlite.Ptr(pool, resolved2) - case llvmlite.LLVMType.Array(aelem_ty2, _): - param_ty2 = llvmlite.Ptr(pool, aelem_ty2) - case _: - param_ty2 = resolved2 - alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, param_ty2) - if alloca is not None: - self.Gen.VarGen.define_var(trans.SymTab, arg2.arg, alloca) - # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) - # 传 pool:泛型 Subscript 返回 mangled name(对齐 HandlesAnnAssign 修复) - if arg2.annotation is not None: - cls_nm_oc: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation( - arg2.annotation, imported_modules, pool) - if cls_nm_oc is not None: - self.Gen.VarGen.set_var_annot_class_name( - trans.SymTab, arg2.arg, cls_nm_oc) - pname2: str = pool.alloc(32) - if pname2 is not None: - viperlib.snprintf(pname2, 32, "%%%s", arg2.arg) - param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, param_ty2, pname2) - llvmlite.build_store(func_builder, param_val, alloca) - - # OOP iter 协议:__next__ 的 stop-flag 参数初始化(store 0)并保存 - # 指针到 trans,供 translate_raise 的 raise StopIteration 写 1。 - # 参数名必须与上面 add_param 的 "%__stop_iter_flag__" 一致。 - if string.strcmp(method_name, "__next__") == 0: - i1_ty_sf: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - if i1_ty_sf is not None: - i1_ptr_ty_sf: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_sf) - if i1_ptr_ty_sf is not None: - flag_ref_sf: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, i1_ptr_ty_sf, "%__stop_iter_flag__") - if flag_ref_sf is not None: - trans._stop_iter_flag_ptr = flag_ref_sf - zero_i1_sf: llvmlite.Value | t.CPtr = llvmlite.ConstInt( - pool, i1_ty_sf, 0, "0") - if zero_i1_sf is not None: - llvmlite.build_store(func_builder, zero_i1_sf, flag_ref_sf) - - # 保存模块级作用域状态 - old_func: llvmlite.Function | t.CPtr = trans._cur_func - old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - old_global_count: int = trans._global_name_count - old_nonlocal_count: int = trans._nonlocal_name_count - old_env_count: int = trans._closure_env_count - old_stop_iter_flag: llvmlite.Value | t.CPtr = trans._stop_iter_flag_ptr - - trans._cur_func = func - trans._cur_builder = func_builder - HT.clear_scope_names(trans) - - # 预扫描方法体:为局部变量提前创建 alloca - body: list[ast.AST | t.CPtr] | t.CPtr = fd.children - if body is not None: - bn: t.CSizeT = len(body) - for bi in range(bn): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - self.Gen.StmtGenDecl.pre_scan_allocas(trans, stmt) - - # 翻译方法体 - if body is not None: - bn2: t.CSizeT = len(body) - for bi2 in range(bn2): - stmt2: ast.AST | t.CPtr = body.get(bi2) - if stmt2 is not None: - self.Gen.StmtGen.translate_stmt(trans, stmt2) - - # 追加89:方法末尾收尾与模块级函数(FuncGenMixin.translate_function_def) - # 同语义——编译器不替代码发明返回值,三种合法收尾: - # ① void 方法掉出末尾 → ret void(无值可发明,Python 语义) - # ② 末句是控制流语句(match/if 全分支 return)→ merge 块结构性 - # 不可达 → build_unreachable(不可能抵达,GCC/Clang fall-through - # 视为 UB 同语义) - # ③ 无返回类型注解的方法 → 视为无返回值过程,ConstZero 兜底 - # 有 -> 注解且末句普通语句掉出末尾 → fail-fast。 - # 不做 noreturn 函数名白名单:错误终止路径(fatal_error 等)也必须在 - # 源码层面保证块收尾(如显式 return 样板),每个函数都符合块设计。 - # 原实现 L4529 const_int32 硬编码 ret i32 0,对 i64 返回方法报 llc - # "value doesn't match function result type 'i64'"(追加88 只修了 - # FuncGenMixin 模块级函数路径,方法路径此处追加89 一并同步) - last_is_return: int = 0 - # 追加89:bn3 提前初始化,避免 body is None 时下方引用未定义变量 - bn3: t.CSizeT = 0 - if body is not None: - bn3 = len(body) - if bn3 > 0: - last_stmt_m: ast.AST | t.CPtr = body.get(bn3 - 1) - if last_stmt_m is not None and last_stmt_m.kind() == ast.ASTKind.Return: - last_is_return = 1 - if last_is_return == 0: - if llvmlite.builder_cur_block_is_terminated(func_builder) == 0: - last_is_ctrl: int = 0 - if bn3 > 0: - last_stmt3_m: ast.AST | t.CPtr = body.get(bn3 - 1) - if last_stmt3_m is not None: - k3m: int = last_stmt3_m.kind() - if k3m == ast.ASTKind.If or k3m == ast.ASTKind.While or \ - k3m == ast.ASTKind.For or k3m == ast.ASTKind.Try or \ - k3m == ast.ASTKind.With or k3m == ast.ASTKind.Match: - last_is_ctrl = 1 - _is_void: int = 0 - if ret_ty is not None: - match ret_ty: - case llvmlite.LLVMType.Void(): - _is_void = 1 - case _: - pass - if _is_void != 0: - llvmlite.build_ret_void(func_builder) - elif last_is_ctrl != 0 and trans._ctrl_merge_reachable == 0: - # 追加90(与 FuncGenMixin 同步):非 void 方法末句是控制流 - # 且 merge 块结构性不可达(全分支 return,无 br 到 merge) - # → LLVM 语义 unreachable。merge 可达(分支 br 到 merge)时 - # 不是结构性不可达,需正常收尾(下方 ConstZero / fail-fast)。 - # 原无条件 unreachable 使 llc O2 优化 br-to-unreachable 为 - # fall-through → 双分支执行崩溃(FuncTest check) - llvmlite.build_unreachable(func_builder) - elif fd.returns is None: - # 无返回类型注解 → 无返回值过程方法,默认零值返回 - if ret_ty is not None: - _m_zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, ret_ty) - if _m_zero_val is not None: - llvmlite.build_ret(func_builder, _m_zero_val) - else: - self.Gen.TypeGenErr.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") - else: - self.Gen.TypeGenErr.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") - else: - # fail-fast:有 -> 注解但流程真实掉出末尾(traceback 风格) - if ret_ty is not None: - rt_name_m: str = pool.alloc(64) - if rt_name_m is not None: - llvmlite.TypePrint(rt_name_m, 64, ret_ty, pool) - if rt_name_m[0] == '\0': - rt_name_m = "?" - err_fn_m: str = pool.alloc(256) - if err_fn_m is not None: - viperlib.snprintf( - err_fn_m, 256, - "方法 '%s' 流程掉出末尾但未显式 return(返回类型 %s)," - "请补显式 return(如 return 0 / return null)", method_name, rt_name_m) - self.Gen.TypeGenErr.fatal_error(fd, err_fn_m, "TypeError") - self.Gen.TypeGenErr.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") - else: - self.Gen.TypeGenErr.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") - - # 恢复模块级作用域 - self.Gen.VarGen.exit_scope(trans.SymTab) - trans._cur_func = old_func - trans._cur_builder = old_builder - trans._global_name_count = old_global_count - trans._nonlocal_name_count = old_nonlocal_count - trans._closure_env_count = old_env_count - trans._stop_iter_flag_ptr = old_stop_iter_flag - - return 0 - # ============================================================ - # _generate_before_init — 生成 __before_init__ 函数 - # - # 生成: define void @SHA1.ClassName.__before_init__(Ptr(StructTy) %self) - # - # 执行: - # 1. store zeroinitializer 到 %self(零值填充) - # 2. 逐字段 store 默认值(如有) - # 3. ret void - # ============================================================ - def _generate_before_init(self, trans: HT.Translator | t.CPtr, - struct_ty: llvmlite.LLVMType | t.CPtr, - class_name: str) -> int: - """生成 __before_init__ 函数,返回 0""" - if trans is None or struct_ty is None or class_name is None: - return 0 - - import lib.core.Handles.HandlesFunctions as HandlesFunctions - import lib.core.Handles.HandlesVar as HandlesVar - import lib.core.Handles.HandlesExpr as HandlesExpr - import lib.core.Handles.HandlesExprCall as HandlesExprCall - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - funcs_ptr: GenTypes.FuncEntry | t.CPtr = trans._funcs - func_count: int = trans._func_count - - self_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) - void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) - - # 构建函数名: ClassName.__before_init__ - full_name_buf: str = pool.alloc(128) - if full_name_buf is None: - return 0 - viperlib.snprintf(full_name_buf, 128, "%s.__before_init__", class_name) - full_name: str = full_name_buf - - mangled_name: str = self.Gen.FuncGenBase._mangle_name(trans, full_name) - - # 创建函数 - func: llvmlite.Function | t.CPtr = llvmlite.create_function( - pool, mod, mangled_name, void_ty) - if func is None: - return 0 - - # 注册到函数表 - max_funcs: int = 1024 - rc_add: int = self.Gen.CallGenLeafKit.add_func_to_table(funcs_ptr, func_count, full_name, func, max_funcs, None, 0, 0, pool) - if rc_add == 0: - trans._func_count = func_count + 1 - - # 添加 self 参数 - llvmlite.add_param(pool, func, self_ptr_ty, "%self") - - # 参数添加完成,补全全局函数表的 TypeStr - rc_ut: int = self.Gen.CallGenLeafKit.update_global_func_typestr(pool, full_name, func) - - # 创建 entry 块 + builder - entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") - if entry_blk is None: - return 0 - func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) - if func_builder is None: - return 0 - llvmlite.position_at_end(func_builder, entry_blk) - - # 注册 self 为 SSA 值 - self_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, self_ptr_ty, "%self") - - # 1. 零值填充: store zeroinitializer, Ptr(struct_ty)* %self - # 空 struct({})在 LLVM 中不允许 zeroinitializer(invalid type for null constant), - # 无字段类(接口/标记类,如多继承的 Vec2Extra)跳过零值填充; - # @t.CVTable 类必有 vtable 指针字段(非空),不受影响。 - struct_fcount_zi: int = llvmlite.get_struct_fcount(struct_ty) - if struct_fcount_zi > 0: - zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) - if zero is not None: - llvmlite.build_store(func_builder, zero, self_val) - - # 1.5 如果有虚表,store vtable 全局地址到 __vtable__ 字段(索引 0) - # 用 find_struct_by_type 定位 entry,规避跨模块同名 find_struct 找错 - bi_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_type(struct_ty) - bi_has_vt: int = 0 - if bi_entry is not None: - bi_has_vt = bi_entry.HasVTable - if bi_has_vt == 1: - vt_method_count: int = 0 - if bi_entry is not None: - vt_method_count = bi_entry.VTableMethodCount - if vt_method_count > 0: - # 构造 vtable 类型 { i8*, i8*, ..., i8* } - vt_i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - vt_i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, vt_i8_ty) - - vt_first_node: llvmlite.ParamNode | t.CPtr = None - vt_prev_node: llvmlite.ParamNode | t.CPtr = None - for vti in range(vt_method_count): - vtnode: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, vt_i8_ptr_ty) - if vtnode is None: - continue - if vt_first_node is None: - vt_first_node = vtnode - if vt_prev_node is not None: - llvmlite.paramnode_set_next(vt_prev_node, vtnode) - vt_prev_node = vtnode - - vt_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, vt_first_node, vt_method_count, None) - vt_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, vt_ty) - - # 构造 vtable 全局变量名 - vt_name_buf: str = pool.alloc(128) - if vt_name_buf is not None: - viperlib.snprintf(vt_name_buf, 128, "%s.vtable", class_name) - vt_full_name: str = vt_name_buf - vt_mangled: str = self.Gen.FuncGenBase._mangle_name(trans, vt_full_name) - - # GEP 到 __vtable__ 字段(索引 0) - vt_slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - func_builder, struct_ty, vt_i8_ptr_ty, self_val, 0) - if vt_slot is not None: - # 创建全局变量引用 Value - vt_ref: llvmlite.Value | t.CPtr = llvmlite.new_value(pool) - if vt_ref is not None: - llvmlite.value_set_ty(vt_ref, vt_ptr_ty) - llvmlite.value_set_isconst(vt_ref, 1) - # Name 格式: @"mangled" 或 @mangled - vt_ref_name: str = pool.alloc(256) - if vt_ref_name is not None: - vt_ref_name[0] = '\0' - if self._vtable_name_needs_quote(vt_mangled) != 0: - viperlib.snprintf(vt_ref_name, 256, "@\"%s\"", vt_mangled) - else: - viperlib.snprintf(vt_ref_name, 256, "@%s", vt_mangled) - llvmlite.value_set_name(vt_ref, vt_ref_name) - - # bitcast 到 i8* - vt_as_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - func_builder, vt_ref, vt_i8_ptr_ty) - if vt_as_i8 is not None: - llvmlite.build_store(func_builder, vt_as_i8, vt_slot) - - # 2. 逐字段 store 默认值(用 bi_entry 直接访问,规避跨模块同名 find_struct 找错) - if bi_entry is not None: - for fi in range(bi_entry.FieldCount): - fe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry( - bi_entry, fi) - if fe is None or fe.DefaultVal is None: - continue - # 静态数组字段 + 列表字面量默认值 → 整体置零 + 逐元素 GEP+store - # (与局部 AnnAssign 数组初始化一致;translate_value 会把列表字面量 - # 误译成动态 list 对象指针,coerce 到 [N x elem] 会失败)。 - # 单参 CArray 字段(如 t.CArray[str] = ["py", ...])经类体字段收集 - # 推断为静态数组,此处保证 __before_init__ 填充真实字符串指针。 - if fe.Ty is not None and self.Gen.ExprGenBase.is_array_type(fe.Ty) != 0 \ - and fe.DefaultVal.kind() == ast.ASTKind.List: - field_ptr_arr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - func_builder, struct_ty, fe.Ty, self_val, fe.Index) - if field_ptr_arr is not None: - zero_arr_f: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, fe.Ty) - if zero_arr_f is not None: - llvmlite.build_store(func_builder, zero_arr_f, field_ptr_arr) - # Mixin 静态绑定:self._xxx 只沿本类查找,跨 Mixin 方法 - # (AssignGenMixin._init_global_array_from_list)会生成不存在 - # 符号 → 必须走 HandlesAnnAssign 模块级委托(延迟 import Gen)。 - self.Gen.AssignGen._init_global_array_from_list( - func_builder, pool, mod, field_ptr_arr, fe.DefaultVal, trans) - continue - # 翻译默认值表达式 - default_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - func_builder, pool, mod, fe.DefaultVal, None, 0, trans) - if default_val is None: - continue - # GEP 到字段 - field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - func_builder, struct_ty, fe.Ty, self_val, fe.Index) - if field_ptr is None: - continue - # 类型转换并 store - default_val = self.Gen.ExprGenBase.coerce_to_type(func_builder, default_val, fe.Ty, fe.DefaultVal) - llvmlite.build_store(func_builder, default_val, field_ptr) - - # 3. ret void - llvmlite.build_ret_void(func_builder) - +import lib.core.Gen.GenTypes as GenTypes +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HT +import lib.core.StubMerger as StubMerger +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.ClassGenBase as ClassGenBase +import lib.core.Handles.ExprCallTable as ExprCallTable + + +# 方法元数据 flag:TLS(@t.TLS 装饰器,对齐 ClassGenBase 本地常量;本地副本避免跨模块 CDefine 查找) +META_TLS: t.CDefine = 32 +# 虚表方法数上限(原 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.get_perm_pool().alloc(8 * VTBL_METHOD_MAX) + method_names_buf: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(8 * VTBL_METHOD_MAX) + # 记录每个方法的父类 SHA1(非 0=继承方法用父模块 SHA1 mangling,0=当前类方法) + method_parent_sha1s: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(8 * VTBL_METHOD_MAX) + if full_names_buf is None or method_names_buf is None or method_parent_sha1s is None: + return 0 + string.memset(full_names_buf, 0, 8 * VTBL_METHOD_MAX) + string.memset(method_names_buf, 0, 8 * VTBL_METHOD_MAX) + string.memset(method_parent_sha1s, 0, 8 * VTBL_METHOD_MAX) + + method_count: int = 0 + + # ============================================================ + # 1.5 继承父类虚方法 + # + # 父类虚方法排在子类虚方法之前,保持 vtable 槽位顺序一致。 + # 如果子类覆盖了方法,full_name 用子类的;否则用父类的。 + # 用 SHA1 感知查找,规避跨模块同名 find_struct 找错 + # ============================================================ + vt_self_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module( + class_name, trans.ModuleSha1) + # 多继承:遍历所有父类(声明顺序),vtable 方法合并(短名去重,先声明父类优先) + parent_count: int = self.Gen.StructGen.get_parent_count(class_name) + if parent_count > 0: + for pi in range(parent_count): + pname: str = self.Gen.StructGen.get_parent_name_at(class_name, pi) + if pname is None: + continue + # 查找父类 entry(优先同模块 SHA1 匹配) + vt_parent_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module( + pname, trans.ModuleSha1) + if vt_parent_entry is None: + # 跨模块继承: 父类在不同模块定义(SHA1 不同),回退到按类名查找 + vt_parent_entry = self.Gen.StructGen.find_struct(pname) + parent_vt_count: int = 0 + if vt_parent_entry is not None: + parent_vt_count = vt_parent_entry.VTableMethodCount + if parent_vt_count > 0: + for pvi in range(parent_vt_count): + if method_count >= VTBL_METHOD_MAX: + break + pmethod_name: str = None + if vt_parent_entry is not None: + pmethod_name = self.Gen.StructGen.get_vtable_method_name(pname, pvi) + if pmethod_name is None: + continue + # 多继承 vtable 去重:方法短名已存在跳过(先声明父类优先) + if self.Gen.ClassGenBase._field_name_exists(method_names_buf, method_count, pmethod_name) != 0: + continue + # 检查子类是否覆盖了该方法,以及是否标记 @t.NoVTable + child_overrides: int = 0 + child_nvt: int = 0 + for ci2 in range(cn): + stmt2: ast.AST | t.CPtr = children.get(ci2) + if stmt2 is None: + continue + if stmt2.kind() != ast.ASTKind.FunctionDef: + continue + fd2: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt2) + if fd2 is not None and fd2.name is not None: + if string.strcmp(fd2.name, pmethod_name) == 0: + child_overrides = 1 + # 检查子类覆盖方法是否标记 @t.NoVTable + if fd2.decorator_list is not None: + if self.Gen.ClassGenBase._has_decorator(fd2.decorator_list, "NoVTable") == 1: + child_nvt = 1 + break + # 构造 full_name + # 子类覆盖且未标记 NoVTable → 用子类实现 + # 子类未覆盖 或 子类覆盖但标记 NoVTable → 用实际定义类实现(保持 vtable 槽位) + # + # 多层继承修复: 直接父类可能只是继承而非定义该方法 + # (如 ElectricCar 继承 Car 的 is_running 实际定义在 Vehicle), + # 沿父类链向上用 find_func_global("类名.方法名") 探测实际定义类, + # 避免生成 "Car.is_running" 这类找不到函数的 full_name → vtable 槽变 null。 + def_class: str = class_name + if child_overrides == 1 and child_nvt == 0: + def_class = class_name + else: + def_class = pname + # 多继承:沿 pname 的 MRO 祖先链探测实际定义类(跳过自身,先声明父类优先) + mro_ptr: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, pname) + mro_i: int = 1 + while mro_ptr is not None and mro_ptr[mro_i] != 0: + anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mro_i], t.CPtr)) + if anc is not None: + probe_buf: str = pool.alloc(128) + if probe_buf is not None: + viperlib.snprintf(probe_buf, 128, "%s.%s", anc, pmethod_name) + if self.Gen.CallGenLeafKit.find_func_global(probe_buf) is not None: + def_class = anc + break + mro_i += 1 + pfname_buf: str = CompilerFactory.get_perm_pool().alloc(128) + if pfname_buf is not None: + viperlib.snprintf(pfname_buf, 128, "%s.%s", def_class, pmethod_name) + full_names_buf[method_count] = t.CSizeT(pfname_buf) + # 复制方法名(短名) + pmname_len: t.CSizeT = string.strlen(pmethod_name) + pmname_buf: str = CompilerFactory.get_perm_pool().alloc(pmname_len + 1) + if pmname_buf is not None: + string.strcpy(pmname_buf, pmethod_name) + method_names_buf[method_count] = t.CSizeT(pmname_buf) + # 记录 mangling 用的 SHA1(继承未覆盖的方法用实际定义类的模块 SHA1) + if child_overrides == 1 and child_nvt == 0: + # 子类覆盖: 用当前模块 SHA1(保持 0) + method_parent_sha1s[method_count] = 0 + else: + # 继承未覆盖: 用实际定义类的模块 SHA1(跨模块继承时 mangling 正确) + def_entry2: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct( + def_class) + if def_entry2 is not None and def_entry2.ModuleSha1 is not None: + method_parent_sha1s[method_count] = t.CSizeT(def_entry2.ModuleSha1) + else: + method_parent_sha1s[method_count] = 0 + method_count += 1 + + # 2. 收集当前类的虚方法(跳过已从父类继承的) + for ci in range(cn): + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + if stmt.kind() != ast.ASTKind.FunctionDef: + continue + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) + if fd is None or fd.name is None: + continue + if method_count >= VTBL_METHOD_MAX: + break + + mname: str = fd.name + # 跳过构造函数和特殊方法(不应放入虚表) + if string.strcmp(mname, "__init__") == 0: + continue + if string.strcmp(mname, "__before_init__") == 0: + continue + if string.strcmp(mname, "__new__") == 0: + continue + # 函数级装饰器过滤:判断方法是否应该进入虚表 + if self.Gen.ClassGenBase._should_method_be_virtual(cd, fd, trans) == 0: + continue + # 检查是否已从父类继承(避免重复) + already_in_vt: int = 0 + for mi in range(method_count): + exist_addr: t.CSizeT = method_names_buf[mi] + if exist_addr != 0: + exist_name: str = (str | t.CPtr)(t.CVoid(exist_addr, t.CPtr)) + if exist_name is not None and string.strcmp(exist_name, mname) == 0: + already_in_vt = 1 + break + if already_in_vt == 1: + continue + # 构造 full_name = "ClassName.method_name" + # 内容必须落在 perm_pool:1a(mark_only=1)收集的 VTableMethods 被 + # Phase 1b 依赖模块翻译跨文件读取,1a 每文件 reset 后 pool 裸字符串悬空 + fname_buf: str = CompilerFactory.get_perm_pool().alloc(128) + if fname_buf is not None: + viperlib.snprintf(fname_buf, 128, "%s.%s", class_name, mname) + full_names_buf[method_count] = t.CSizeT(fname_buf) + + # 复制方法名 + mname_len: t.CSizeT = string.strlen(mname) + mname_buf: str = CompilerFactory.get_perm_pool().alloc(mname_len + 1) + if mname_buf is not None: + string.strcpy(mname_buf, mname) + method_names_buf[method_count] = t.CSizeT(mname_buf) + + method_count += 1 + + # 暂存结果(_generate_vtable 复用) + self.VtFullNames = full_names_buf + self.VtMethodNames = method_names_buf + self.VtParentSha1s = method_parent_sha1s + self.VtMethodCount = method_count + + # 设置 entry 元数据(虚分派查询用;必须在本类方法体翻译前就绪, + # 否则方法体内 self.虚方法 调用无法虚分派) + if vt_self_entry is not None and method_count > 0: + vt_self_entry.VTableMethodCount = method_count + vt_self_entry.VTableMethods = method_names_buf + + if method_count == 0: + return 0 + return 1 + # ============================================================ + # _generate_vtable — 生成 VTable 全局变量 + # + # 1. 收集 class body 中所有 FunctionDef 作为虚方法 + # 2. 构造 VTable 类型 { i8*, i8*, ... } + # 3. 构造初始化字符串 { i8* bitcast (...), ... } + # 4. 创建全局变量 @"SHA1.ClassName.vtable" + # 5. 存储虚方法名列表到 StructEntry + # ============================================================ + def _generate_vtable(self, trans: HT.Translator | t.CPtr, + cd: ast.ClassDef | t.CPtr, + class_name: str) -> int: + """生成 VTable 全局变量""" + if trans is None or cd is None or class_name is None: + return 0 + + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + + # 收集虚方法信息(继承父类 + 自身,结果存 self.VtFullNames 等暂存区) + # 同时设置 entry.VTableMethodCount/VTableMethods(虚分派查询用) + if self._collect_vtable_methods(trans, cd, class_name) == 0: + return 0 + full_names_buf: t.CSizeT | t.CPtr = self.VtFullNames + method_names_buf: t.CSizeT | t.CPtr = self.VtMethodNames + method_parent_sha1s: t.CSizeT | t.CPtr = self.VtParentSha1s + method_count: int = self.VtMethodCount + # 重新获取 entry(后续存储 VTableMethods 用) + vt_self_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module( + class_name, trans.ModuleSha1) + + # 2. 构造 VTable 类型: { i8*, i8*, ..., i8* } + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + first_node: llvmlite.ParamNode | t.CPtr = None + tail_node: llvmlite.ParamNode | t.CPtr = None + for i in range(method_count): + pnode: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) + if pnode is None: + continue + tail_node = llvmlite.param_list_append(first_node, tail_node, pnode) + if first_node is None: + first_node = tail_node + + vtable_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, first_node, method_count, None) + if vtable_ty is None: + return 0 + + # 3. 构造初始化字符串 + # 大 vtable(如 MemBuddy 28+ 方法)每个方法 bitcast 约 100+ 字节, + # 4096 可能写满导致截断/strlen 越界,用 16384 预留足够空间。 + init_buf: str = pool.alloc(16384) + if init_buf is None: + return 0 + init_buf[0] = '\0' + self._vtable_strcat(init_buf, 16384, "{ ") + + for i in range(method_count): + if i > 0: + self._vtable_strcat(init_buf, 16384, ", ") + + full_name_addr: t.CSizeT = full_names_buf[i] + if full_name_addr == 0: + self._vtable_strcat(init_buf, 16384, "i8* null") + continue + + full_name: str = (str | t.CPtr)(t.CVoid(full_name_addr, t.CPtr)) + + # 检查是否是继承方法(method_parent_sha1s 非 0 表示用父模块 SHA1 mangling) + parent_sha1_addr: t.CSizeT = method_parent_sha1s[i] + if parent_sha1_addr != 0: + # 继承方法: 用父类模块 SHA1 做 mangling + parent_sha1: str = (str | t.CPtr)(t.CVoid(parent_sha1_addr, t.CPtr)) + mangled_name: str = self.Gen.FuncGenBase._mangle_name_with_sha1(parent_sha1, full_name) + # 从全局函数表查找(跨模块函数不在当前模块表中) + func: llvmlite.Function | t.CPtr = self.Gen.CallGenLeafKit.find_func_global(full_name) + else: + # 当前类方法: 用当前模块 SHA1 + mangled_name: str = self.Gen.FuncGenBase._mangle_name(trans, full_name) + func: llvmlite.Function | t.CPtr = self.Gen.CallGenLeafKit.find_func_in_table( + trans._funcs, trans._func_count, full_name) + # 当前模块表找不到时,回退到全局表 + if func is None: + func = self.Gen.CallGenLeafKit.find_func_global(full_name) + + # func 可能已被 1b reset_to(mark1) 回收(跨模块继承方法在定义文件翻译后被 reset)。 + # 悬空指针非 NULL 但内容已被复用,_format_func_type_str 解引用会沿垃圾 Next 链 + # 指针追逐导致无限分配(TypePrint 每次 pool.alloc(512) → 单文件暴涨 900MB OOM)。 + # 因此 func 非 NULL 时也须用 _is_valid_ptr 校验,失败回退到 TypeStr。 + func_valid: int = 0 + if func is not None: + if trans.Pool is not None: + # 继承方法(parent_sha1_addr != 0):func 来自其他模块,该模块 1b 翻译 + # 后已被 reset_to(mark1) 回收,_is_valid_ptr 存在假阳性(块头复用后仍 + # 看似有效),直接判定无效走 TypeStr 回退,避免解引用悬空 func 崩溃。 + if parent_sha1_addr != 0: + func_valid = 0 + elif trans.Pool._is_valid_ptr(func) != 0: + func_valid = 1 + if func_valid == 0: + # 回退到全局表完整 entry 的 TypeStr(stdlib 深拷贝,跨文件永久存活)。 + ge: GenTypes.FuncEntry | t.CPtr = self.Gen.CallGenLeafKit.find_func_entry_global(full_name) + if ge is not None and ge.TypeStr is not None: + self._vtable_strcat(init_buf, 16384, "i8* bitcast (") + self._vtable_strcat(init_buf, 16384, ge.TypeStr) + self._vtable_strcat(init_buf, 16384, "* @") + if self._vtable_name_needs_quote(mangled_name) != 0: + self._vtable_strcat(init_buf, 16384, "\"") + self._vtable_strcat(init_buf, 16384, mangled_name) + self._vtable_strcat(init_buf, 16384, "\"") + else: + self._vtable_strcat(init_buf, 16384, mangled_name) + self._vtable_strcat(init_buf, 16384, " to i8*)") + continue + # fail-fast:func 无效且全局表 TypeStr 回退也失败, + # 不再写 "i8* null" 静默掩盖缺失实现。 + self.Gen.TypeGenErr.fatal_error( + cd, f"vtable 方法 '{full_name}' 找不到函数实现", "InternalCompilerError") + continue + + # 构造函数类型字符串 + func_ty_buf: str = pool.alloc(512) + if func_ty_buf is None: + self._vtable_strcat(init_buf, 16384, "i8* null") + continue + self._format_func_type_str(pool, func_ty_buf, 512, func) + + # 构造 bitcast 字符串: i8* bitcast (func_ty* @mangled to i8*) + self._vtable_strcat(init_buf, 16384, "i8* bitcast (") + self._vtable_strcat(init_buf, 16384, func_ty_buf) + self._vtable_strcat(init_buf, 16384, "* @") + + if self._vtable_name_needs_quote(mangled_name) != 0: + self._vtable_strcat(init_buf, 16384, "\"") + self._vtable_strcat(init_buf, 16384, mangled_name) + self._vtable_strcat(init_buf, 16384, "\"") + else: + self._vtable_strcat(init_buf, 16384, mangled_name) + self._vtable_strcat(init_buf, 16384, " to i8*)") + + self._vtable_strcat(init_buf, 16384, " }") + + # 4. 构造 VTable 全局变量名 + vtable_name_buf: str = pool.alloc(128) + if vtable_name_buf is None: + return 0 + viperlib.snprintf(vtable_name_buf, 128, "%s.vtable", class_name) + vtable_mangled: str = self.Gen.FuncGenBase._mangle_name(trans, vtable_name_buf) + + # 5. 创建全局变量 + gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable( + pool, vtable_mangled, vtable_ty) + if gv is None: + return 0 + gv.Initializer = init_buf + gv.IsConstant = 1 + # 默认 linkage(external,2026-08-10):isinstance 内建函数需要跨模块 + # 引用其他模块类的 vtable 符号({模块sha1}.Class.vtable),internal 不对外 + # 导出会导致链接失败。vtable 名含模块 sha1 前缀全局唯一,外部可见不冲突。 + # llvmlite 打印规则:Initializer 非空 + external 时不打印 external 关键字, + # 输出 @name = constant {...}(合法外部强定义)。 + + # 添加到模块 + llvmlite.module_add_global(mod, gv) + + # 6. 存储虚方法名列表到 StructEntry(直接用 entry,规避跨模块同名 find_struct 找错) + if vt_self_entry is not None: + vt_self_entry.VTableMethods = method_names_buf + vt_self_entry.VTableMethodCount = method_count + + return 0 + # ============================================================ + # _translate_oop_methods — 扫描 class body 中的方法并翻译 + # + # 遍历 ClassDef.children,对每个 FunctionDef: + # - 标记 OOP(mark_as_oop) + # - 如果是 __init__,标记 has_init + # - 翻译方法(生成 SHA1.ClassName.method_name 函数) + # 翻译完所有方法后,生成 __before_init__ 函数 + # ============================================================ + def _translate_oop_methods(self, trans: HT.Translator | t.CPtr, + cd: ast.ClassDef | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr, + class_name: str, + mark_only: int = 0, + reemit: int = 0) -> int: + """扫描 class body 中的方法并翻译,生成 __before_init__ + + mark_only: 0=全量翻译(默认),1=只设置 IsOOP/HasNew/HasInit 标志(不翻译方法体) + reemit: 1=补译模式(_specialize_generic_class Phase B 补译分支调用)。 + 补译分支为防重入已提前置 MethodsEmitted=1,但方法体尚未发射, + 必须跳过下方 MethodsEmitted==1 的防重复检查强制发射,否则补译 + 被自身拦截 → 特化方法只有 call 无 define → 链接 undefined symbol。 + """ + if trans is None or cd is None or struct_ty is None or class_name is None: + return 0 + + children: list[ast.AST | t.CPtr] | t.CPtr = cd.children + if children is None: + return 0 + + cn: t.CSizeT = len(children) + has_method: int = 0 + has_init: int = 0 + has_new: int = 0 + + # 提前用类型指针定位 entry(规避跨模块同名类 find_struct 找错) + oop_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_type(struct_ty) + + # 第一遍:检测是否有方法,标记 OOP,并注册装饰器元数据 + for ci in range(cn): + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + if stmt.kind() == ast.ASTKind.FunctionDef: + has_method = 1 + fd_check: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) + if fd_check is not None and fd_check.name is not None: + if string.strcmp(fd_check.name, "__init__") == 0: + has_init = 1 + if string.strcmp(fd_check.name, "__new__") == 0: + has_new = 1 + # 注册装饰器元数据(@property/@staticmethod/@classmethod/@x.setter 等)。 + # 此处(含 mark_only=1 的 struct 预注册阶段)注册, + # 确保其他模块在 App 文件翻译时能识别属性访问。 + fd_meta: int = self.Gen.ClassGenBase._extract_func_meta(fd_check.decorator_list) + if fd_meta != 0: + self.Gen.ClassGenBase.register_method_meta(class_name, fd_check.name, fd_meta) + + if has_method == 0: + # 子类没有自己的方法,但可能继承了父类的虚方法 + # 用 oop_entry 直接获取 ParentName,规避 find_struct 按名查找找错 + parent_name: str = None + if oop_entry is not None: + parent_name = oop_entry.ParentName + if parent_name is not None: + parent_vt_count: int = self.Gen.StructGen.get_vtable_method_count(parent_name) + if parent_vt_count > 0: + has_method = 1 # 标记为有方法(继承的虚方法) + if has_method == 0: + return 0 + + # 标记为 OOP 结构体 + if oop_entry is not None: + oop_entry.IsOOP = 1 + if has_init != 0: + oop_entry.HasInit = 1 + if has_new != 0: + oop_entry.HasNew = 1 + + # mark_only 模式:只设置标志,不翻译方法体 + if mark_only != 0: + # Phase 1a 预注册也收集 vtable 元数据(VTableMethods/VTableMethodCount)。 + # 根因:Phase 1b 中依赖模块可能先于其依赖类全量翻译(如 tokens.vp 先于 + # memhub 生成 text.ll),此时调用方查到 entry 有 HasVTable=1 但 + # VTableMethods=None → _translate_method_call 虚分派条件 + # (VTableMethods is not None)不成立 → pool.alloc 被静态绑定到 + # MemManager.alloc(默认返回 None)→ KwEntry.__new__ 返回 null → + # __before_init__ 写 null 崩溃。 + # 短名顺序与 Phase 1b 全量收集一致(父类方法在前 + 本类方法,确定性), + # 多遍扫描重复收集时用新缓冲区覆盖(stdlib 泄漏可忽略,Phase 1b 重译幂等)。 + mk_has_vt: int = 0 + if oop_entry is not None: + mk_has_vt = oop_entry.HasVTable + if mk_has_vt == 1: + self._collect_vtable_methods(trans, cd, class_name) + return 0 + + # 防重复生成:MethodsEmitted==1 说明方法体/__before_init__ 已生成过。 + # 场景:_specialize_generic_class 的 Phase B 补译分支(MethodsEmitted==0 + # 时补译方法体并置 1)之后,同一特化类又经 translate_class_def 全量 + # 翻译进入本方法 → 重复生成 __before_init__ → ld.lld duplicate symbol。 + # 已生成过则直接跳过(方法+__before_init__ 都产出过,跳过安全)。 + # reemit=1(补译模式)时跳过本检查:补译分支为防重入已提前置 + # MethodsEmitted=1,但方法体尚未发射,必须强制发射。 + if oop_entry is not None and oop_entry.MethodsEmitted == 1 and reemit == 0: + return 0 + + # 防重入:方法体翻译前先标记 MethodsEmitted=1。 + # 根因:若等全部方法译完再标记,翻译 __iter__(返回 list[T]|t.CPtr)时, + # 返回类型注解会再次触发 _specialize_generic_class,此时 MethodsEmitted + # 仍为 0,走补译分支把同一特化类方法全部重发 → invalid redefinition。 + if oop_entry is not None: + oop_entry.MethodsEmitted = 1 + + # 第二遍:翻译每个方法 + # 翻译方法体前先预注册 vtable 元数据(VTableMethods/VTableMethodCount)。 + # 根因:方法体翻译先于 _generate_vtable,若不预注册,方法体内的 + # self.虚方法 调用(如 MemManager.calloc 里的 self.alloc)读不到 + # VTableMethods,虚分派失败,被静态绑定到本类实现(基类 alloc 返回 + # None),导致 calloc 永远返回 NULL。 + oop_has_vt_pre: int = 0 + if oop_entry is not None: + oop_has_vt_pre = oop_entry.HasVTable + if oop_has_vt_pre == 1: + self._collect_vtable_methods(trans, cd, class_name) + for ci in range(cn): + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + if stmt.kind() == ast.ASTKind.FunctionDef: + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) + if fd is not None and fd.name is not None: + self._translate_method(trans, fd, struct_ty, class_name) + + # 如果有虚表,先生成 VTable 全局变量(设置 VTableMethodCount) + # 必须在 __before_init__ 之前,否则 __before_init__ 读不到 VTableMethodCount + # 用 oop_entry 直接检查,规避跨模块同名 find_struct 找错 + has_vt_flag: int = 0 + if oop_entry is not None: + has_vt_flag = oop_entry.HasVTable + if has_vt_flag == 1: + self._generate_vtable(trans, cd, class_name) + + # 生成 __before_init__ 函数(零值填充 + 默认值赋值 + vtable 指针设置) + self._generate_before_init(trans, struct_ty, class_name) + + return 0 + # ============================================================ + # _translate_method — 翻译单个方法 + # + # 生成: define @SHA1.ClassName.method_name(Ptr(StructTy) %self, ...) + # + # self 参数处理: + # - 类型 Ptr(struct_ty),直接注册为 SSA 值(不创建 alloca) + # - 使 self.field 能通过 GEP 直接访问原始结构体 + # ============================================================ + def _translate_method(self, trans: HT.Translator | t.CPtr, + fd: ast.FunctionDef | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr, + class_name: str) -> int: + """翻译单个方法,返回 0""" + if trans is None or fd is None or struct_ty is None or class_name is None: + return 0 + + + 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.Gen.FuncGenBase._mangle_name(trans, full_name) + + # 推断返回类型 + ret_ty: llvmlite.LLVMType | t.CPtr = None + if fd.returns is not None: + ret_ty = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, fd.returns, imported_modules, from_imports, trans) + if ret_ty is None and fd.returns is not None: + if self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "State") != 0: + ret_ty = llvmlite.Void(pool) + if ret_ty is None: + # __init__ 和 __before_init__ 返回 void + if string.strcmp(method_name, "__init__") == 0: + ret_ty = llvmlite.Void(pool) + # __new__ 返回 Ptr(struct_ty)(结构体指针作为存储空间) + elif string.strcmp(method_name, "__new__") == 0: + ret_ty = llvmlite.Ptr(pool, struct_ty) + else: + param_types_str: str = self.Gen.TypeGenErr.build_param_types_str(pool, fd.args) + ret_ty = self.Gen.TypeGenErr.infer_return_type( + pool, fd.children, param_types_str) + + # 创建 LLVM 函数 + func: llvmlite.Function | t.CPtr = llvmlite.create_function( + pool, mod, mangled_name, ret_ty) + if func is None: + return 0 + + # 提取默认参数信息(普通方法 args[0] 是 self,不含在 param_count 中; + # @staticmethod 无 self,param_count 为完整参数数) + # 注意: 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(), + # 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错 + md_defaults: t.CVoid | t.CPtr = None + md_default_count: int = 0 + md_param_count: int = 0 + md_args_node: ast.Arguments | t.CPtr = fd.args + if md_args_node is not None: + md_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(md_args_node) + if md_ags.args is not None: + md_alist: list[ast.AST | t.CPtr] | t.CPtr = md_ags.args + if is_static_m != 0: + md_param_count = len(md_alist) + else: + md_param_count = len(md_alist) - 1 + if md_ags.defaults is not None: + md_dlist: list[ast.AST | t.CPtr] | t.CPtr = md_ags.defaults + md_defaults = md_dlist + md_default_count = len(md_dlist) + + # 注册到函数表(用 ClassName.method_name 作为查找名,支持后缀匹配) + max_funcs: int = 1024 + if self.Gen.CallGenLeafKit.add_func_to_table(funcs_ptr, func_count, full_name, func, max_funcs, + md_defaults, md_default_count, md_param_count, + pool) == 0: + trans._func_count = func_count + 1 + + # 添加 self/cls 参数(Ptr(struct_ty));@staticmethod 无 self,跳过 + # @classmethod 的 cls 也用 Ptr(struct_ty),首参名取 args[0](如 cls) + if is_static_m == 0: + first_pname: str = "self" + if is_class_m != 0 and fd.args is not None: + fd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args) + if fd_ags.args is not None and len(fd_ags.args) > 0: + fd_first_arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(fd_ags.args.get(0)) + if fd_first_arg is not None and fd_first_arg.arg is not None: + first_pname = fd_first_arg.arg + first_pname_buf: str = pool.alloc(32) + if first_pname_buf is not None: + viperlib.snprintf(first_pname_buf, 32, "%%%s", first_pname) + llvmlite.add_param(pool, func, self_ptr_ty, first_pname_buf) + + # 添加其他参数(支持类型注解;@staticmethod 从索引 0 开始,其余跳过索引 0 的 self/cls) + args_node: ast.Arguments | t.CPtr = fd.args + if args_node is not None: + ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if ags.args is not None: + alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args + an: t.CSizeT = len(alist) + start_idx: int = 0 + if is_static_m == 0: + start_idx = 1 + for ai in range(start_idx, an): + arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) + if arg is not None and arg.arg is not None: + param_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if arg.annotation is not None: + resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, arg.annotation, imported_modules, from_imports, trans) + if resolved is not None: + # 裸类形参 → Ptr(struct):按"对象即指针"引用传参。 + # 若按 struct 值传参,self.Head = node 会取局部拷贝地址 + # (append 返回后悬垂,G5 Test4 head.Value 读到垃圾)。 + # CArray 形参 → 元素指针 ty*(数组衰减,C 语义,与函数形参一致)。 + match resolved: + case llvmlite.LLVMType.Struct(_, _, _): + param_ty = llvmlite.Ptr(pool, resolved) + case llvmlite.LLVMType.Array(aelem_ty, _): + param_ty = llvmlite.Ptr(pool, aelem_ty) + case _: + param_ty = resolved + pname: str = pool.alloc(32) + if pname is not None: + viperlib.snprintf(pname, 32, "%%%s", arg.arg) + llvmlite.add_param(pool, func, param_ty, pname) + + # OOP iter 协议:__next__ 方法注入隐藏参数 __stop_iter_flag__(i1*)。 + # raise StopIteration 时置 1(对齐 TPC HandlesFunctions.py L703-705)。 + # 该参数不计入 md_param_count(逻辑参数),调用侧(for 循环)显式传。 + if string.strcmp(method_name, "__next__") == 0: + i1_ty_si: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + if i1_ty_si is not None: + i1_ptr_ty_si: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_si) + if i1_ptr_ty_si is not None: + llvmlite.add_param(pool, func, i1_ptr_ty_si, "%__stop_iter_flag__") + + # 参数添加完成,补全全局函数表的 TypeStr(供 vtable 在 func 被 reset 后使用) + self.Gen.CallGenLeafKit.update_global_func_typestr(pool, full_name, func) + + # 创建 entry 块 + entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") + if entry_blk is None: + return 0 + + # 创建方法专属 builder + func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) + if func_builder is None: + return 0 + llvmlite.position_at_end(func_builder, entry_blk) + + # @t.TLS 一次性初始化守卫(对齐 TPC HandlesFunctions.py L1763-1792; + # 与 FuncGenMixin.translate_function_def 同一实现,类方法同样支持) + if is_tls_m != 0: + tls_m_flag_name: str = pool.alloc(128) + if tls_m_flag_name is not None: + viperlib.snprintf(tls_m_flag_name, 128, "__tls_init_done_%s", method_name) + tls_m_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.create_global_int( + pool, mod, tls_m_flag_name, 1, 0) + if tls_m_gv is not None: + i1_ty_m: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + if i1_ty_m is not None: + # GlobalVariable 非 Value 子类:构造 Value 视图后再 load/store + tls_m_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_m) + tls_m_rn: str = pool.alloc(64) + if tls_m_rn is not None: + viperlib.snprintf(tls_m_rn, 64, "@%s", tls_m_flag_name) + tls_m_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, tls_m_ptr_ty, tls_m_rn) + if tls_m_ref is not None: + tls_m_ld: llvmlite.Value | t.CPtr = llvmlite.build_load( + func_builder, i1_ty_m, tls_m_ref) + lc_m: int = trans._label_counter + trans._label_counter = lc_m + 1 + tls_m_buf: str = pool.alloc(64) + if tls_m_buf is not None: + viperlib.snprintf(tls_m_buf, 64, "tls.skip.%d", lc_m) + tls_m_skip: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, tls_m_buf) + viperlib.snprintf(tls_m_buf, 64, "tls.cont.%d", lc_m) + tls_m_cont: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, tls_m_buf) + if tls_m_skip is not None and tls_m_cont is not None: + llvmlite.build_cond_br( + func_builder, tls_m_ld, tls_m_skip, tls_m_cont) + llvmlite.position_at_end(func_builder, tls_m_skip) + match ret_ty: + case llvmlite.LLVMType.Void(): + llvmlite.build_ret_void(func_builder) + case llvmlite.LLVMType.Int(_): + tlm0: llvmlite.Value | t.CPtr = llvmlite.ConstInt( + pool, ret_ty, 0, "0") + if tlm0 is not None: + llvmlite.build_ret(func_builder, tlm0) + case llvmlite.LLVMType.Float(_): + tlmf: llvmlite.Value | t.CPtr = llvmlite.ConstFloat( + pool, ret_ty, 0.0) + if tlmf is not None: + llvmlite.build_ret(func_builder, tlmf) + case _: + tlmn: llvmlite.Value | t.CPtr = llvmlite.ConstNull( + pool, ret_ty, "null") + if tlmn is not None: + llvmlite.build_ret(func_builder, tlmn) + llvmlite.position_at_end(func_builder, tls_m_cont) + tlmo: llvmlite.Value | t.CPtr = llvmlite.ConstInt( + pool, i1_ty_m, 1, "1") + if tlmo is not None: + llvmlite.build_store(func_builder, tlmo, tls_m_ref) + + # 进入函数作用域 + self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_FUNCTION) + + # 为 self/cls 创建 alloca 并 store(与其他参数一致);@staticmethod 无 self,跳过 + # 修复: 之前 self 注册为 SSA 值导致 translate_name_value 错误地 load 一次 + # 将 Ptr(struct_ty) 变成 struct 值,引发变参函数 ABI 不匹配崩溃 + if is_static_m == 0: + self_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, self_ptr_ty) + if self_alloca is not None: + self_var_name: str = "self" + self_ssa_name: str = "%self" + if is_class_m != 0 and args_node is not None: + cags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if cags.args is not None and len(cags.args) > 0: + cfirst: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(cags.args.get(0)) + if cfirst is not None and cfirst.arg is not None: + self_var_name = cfirst.arg + self_ssa_name_buf: str = pool.alloc(32) + if self_ssa_name_buf is not None: + viperlib.snprintf(self_ssa_name_buf, 32, "%%%s", cfirst.arg) + self_ssa_name = self_ssa_name_buf + self.Gen.VarGen.define_var(trans.SymTab, self_var_name, self_alloca) + # 设置 self/cls 的类型注解类名(属性访问 lookup_field 回退查找用) + self.Gen.VarGen.set_var_annot_class_name(trans.SymTab, self_var_name, class_name) + self_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, self_ptr_ty, self_ssa_name) + llvmlite.build_store(func_builder, self_val, self_alloca) + + # 为其他参数创建 alloca 并 store(与普通函数一致; + # @staticmethod 从索引 0 开始,其余跳过索引 0 的 self/cls 参数) + if args_node is not None: + ags2: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if ags2.args is not None: + alist2: list[ast.AST | t.CPtr] | t.CPtr = ags2.args + an2: t.CSizeT = len(alist2) + start_idx2: int = 0 + if is_static_m == 0: + start_idx2 = 1 + for ai2 in range(start_idx2, an2): + arg2: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist2.get(ai2)) + if arg2 is not None and arg2.arg is not None: + param_ty2: llvmlite.LLVMType | t.CPtr = i32_ty + if arg2.annotation is not None: + resolved2: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( + pool, arg2.annotation, imported_modules, from_imports, trans) + if resolved2 is None: + # fail-fast:参数有注解但类型解析失败,不再静默保持 i32 + self.Gen.TypeGenErr.fatal_error( + arg2, f"方法 '{class_name}.{method_name}' 参数 '{arg2.arg}' 类型解析失败", + "NameError") + resolved2 = i32_ty # 不可达(fatal_error 已退出) + if resolved2 is not None: + # 与 add_param 保持一致:裸类形参 → Ptr(struct)(对象即指针) + # CArray 形参 → 元素指针 ty*(数组衰减,与 add_param 一致) + match resolved2: + case llvmlite.LLVMType.Struct(_, _, _): + param_ty2 = llvmlite.Ptr(pool, resolved2) + case llvmlite.LLVMType.Array(aelem_ty2, _): + param_ty2 = llvmlite.Ptr(pool, aelem_ty2) + case _: + param_ty2 = resolved2 + alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, param_ty2) + if alloca is not None: + self.Gen.VarGen.define_var(trans.SymTab, arg2.arg, alloca) + # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) + # 传 pool:泛型 Subscript 返回 mangled name(对齐 HandlesAnnAssign 修复) + if arg2.annotation is not None: + cls_nm_oc: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation( + arg2.annotation, imported_modules, pool) + if cls_nm_oc is not None: + self.Gen.VarGen.set_var_annot_class_name( + trans.SymTab, arg2.arg, cls_nm_oc) + pname2: str = pool.alloc(32) + if pname2 is not None: + viperlib.snprintf(pname2, 32, "%%%s", arg2.arg) + param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, param_ty2, pname2) + llvmlite.build_store(func_builder, param_val, alloca) + + # OOP iter 协议:__next__ 的 stop-flag 参数初始化(store 0)并保存 + # 指针到 trans,供 translate_raise 的 raise StopIteration 写 1。 + # 参数名必须与上面 add_param 的 "%__stop_iter_flag__" 一致。 + if string.strcmp(method_name, "__next__") == 0: + i1_ty_sf: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + if i1_ty_sf is not None: + i1_ptr_ty_sf: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_sf) + if i1_ptr_ty_sf is not None: + flag_ref_sf: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, i1_ptr_ty_sf, "%__stop_iter_flag__") + if flag_ref_sf is not None: + trans._stop_iter_flag_ptr = flag_ref_sf + zero_i1_sf: llvmlite.Value | t.CPtr = llvmlite.ConstInt( + pool, i1_ty_sf, 0, "0") + if zero_i1_sf is not None: + llvmlite.build_store(func_builder, zero_i1_sf, flag_ref_sf) + + # 保存模块级作用域状态 + old_func: llvmlite.Function | t.CPtr = trans._cur_func + old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + old_global_count: int = trans._global_name_count + old_nonlocal_count: int = trans._nonlocal_name_count + old_env_count: int = trans._closure_env_count + old_stop_iter_flag: llvmlite.Value | t.CPtr = trans._stop_iter_flag_ptr + + trans._cur_func = func + trans._cur_builder = func_builder + HT.clear_scope_names(trans) + + # 预扫描方法体:为局部变量提前创建 alloca + body: list[ast.AST | t.CPtr] | t.CPtr = fd.children + if body is not None: + bn: t.CSizeT = len(body) + for bi in range(bn): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + self.Gen.StmtGenDecl.pre_scan_allocas(trans, stmt) + + # 翻译方法体 + if body is not None: + bn2: t.CSizeT = len(body) + for bi2 in range(bn2): + stmt2: ast.AST | t.CPtr = body.get(bi2) + if stmt2 is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt2) + + # 追加89:方法末尾收尾与模块级函数(FuncGenMixin.translate_function_def) + # 同语义——编译器不替代码发明返回值,三种合法收尾: + # ① void 方法掉出末尾 → ret void(无值可发明,Python 语义) + # ② 末句是控制流语句(match/if 全分支 return)→ merge 块结构性 + # 不可达 → build_unreachable(不可能抵达,GCC/Clang fall-through + # 视为 UB 同语义) + # ③ 无返回类型注解的方法 → 视为无返回值过程,ConstZero 兜底 + # 有 -> 注解且末句普通语句掉出末尾 → fail-fast。 + # 不做 noreturn 函数名白名单:错误终止路径(fatal_error 等)也必须在 + # 源码层面保证块收尾(如显式 return 样板),每个函数都符合块设计。 + # 原实现 L4529 const_int32 硬编码 ret i32 0,对 i64 返回方法报 llc + # "value doesn't match function result type 'i64'"(追加88 只修了 + # FuncGenMixin 模块级函数路径,方法路径此处追加89 一并同步) + last_is_return: int = 0 + # 追加89:bn3 提前初始化,避免 body is None 时下方引用未定义变量 + bn3: t.CSizeT = 0 + if body is not None: + bn3 = len(body) + if bn3 > 0: + last_stmt_m: ast.AST | t.CPtr = body.get(bn3 - 1) + if last_stmt_m is not None and last_stmt_m.kind() == ast.ASTKind.Return: + last_is_return = 1 + if last_is_return == 0: + if llvmlite.builder_cur_block_is_terminated(func_builder) == 0: + last_is_ctrl: int = 0 + if bn3 > 0: + last_stmt3_m: ast.AST | t.CPtr = body.get(bn3 - 1) + if last_stmt3_m is not None: + k3m: int = last_stmt3_m.kind() + if k3m == ast.ASTKind.If or k3m == ast.ASTKind.While or \ + k3m == ast.ASTKind.For or k3m == ast.ASTKind.Try or \ + k3m == ast.ASTKind.With or k3m == ast.ASTKind.Match: + last_is_ctrl = 1 + _is_void: int = 0 + if ret_ty is not None: + match ret_ty: + case llvmlite.LLVMType.Void(): + _is_void = 1 + case _: + pass + if _is_void != 0: + llvmlite.build_ret_void(func_builder) + elif last_is_ctrl != 0 and trans._ctrl_merge_reachable == 0: + # 追加90(与 FuncGenMixin 同步):非 void 方法末句是控制流 + # 且 merge 块结构性不可达(全分支 return,无 br 到 merge) + # → LLVM 语义 unreachable。merge 可达(分支 br 到 merge)时 + # 不是结构性不可达,需正常收尾(下方 ConstZero / fail-fast)。 + # 原无条件 unreachable 使 llc O2 优化 br-to-unreachable 为 + # fall-through → 双分支执行崩溃(FuncTest check) + llvmlite.build_unreachable(func_builder) + elif fd.returns is None: + # 无返回类型注解 → 无返回值过程方法,默认零值返回 + if ret_ty is not None: + _m_zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, ret_ty) + if _m_zero_val is not None: + llvmlite.build_ret(func_builder, _m_zero_val) + else: + self.Gen.TypeGenErr.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") + else: + self.Gen.TypeGenErr.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") + else: + # fail-fast:有 -> 注解但流程真实掉出末尾(traceback 风格) + if ret_ty is not None: + rt_name_m: str = pool.alloc(64) + if rt_name_m is not None: + llvmlite.TypePrint(rt_name_m, 64, ret_ty, pool) + if rt_name_m[0] == '\0': + rt_name_m = "?" + err_fn_m: str = pool.alloc(256) + if err_fn_m is not None: + viperlib.snprintf( + err_fn_m, 256, + "方法 '%s' 流程掉出末尾但未显式 return(返回类型 %s)," + "请补显式 return(如 return 0 / return null)", method_name, rt_name_m) + self.Gen.TypeGenErr.fatal_error(fd, err_fn_m, "TypeError") + self.Gen.TypeGenErr.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") + else: + self.Gen.TypeGenErr.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") + + # 恢复模块级作用域 + self.Gen.VarGen.exit_scope(trans.SymTab) + trans._cur_func = old_func + trans._cur_builder = old_builder + trans._global_name_count = old_global_count + trans._nonlocal_name_count = old_nonlocal_count + trans._closure_env_count = old_env_count + trans._stop_iter_flag_ptr = old_stop_iter_flag + + return 0 + # ============================================================ + # _generate_before_init — 生成 __before_init__ 函数 + # + # 生成: define void @SHA1.ClassName.__before_init__(Ptr(StructTy) %self) + # + # 执行: + # 1. store zeroinitializer 到 %self(零值填充) + # 2. 逐字段 store 默认值(如有) + # 3. ret void + # ============================================================ + def _generate_before_init(self, trans: HT.Translator | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr, + class_name: str) -> int: + """生成 __before_init__ 函数,返回 0""" + if trans is None or struct_ty is None or class_name is None: + return 0 + + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + funcs_ptr: GenTypes.FuncEntry | t.CPtr = trans._funcs + func_count: int = trans._func_count + + self_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) + void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + + # 构建函数名: ClassName.__before_init__ + full_name_buf: str = pool.alloc(128) + if full_name_buf is None: + return 0 + viperlib.snprintf(full_name_buf, 128, "%s.__before_init__", class_name) + full_name: str = full_name_buf + + mangled_name: str = self.Gen.FuncGenBase._mangle_name(trans, full_name) + + # 创建函数 + func: llvmlite.Function | t.CPtr = llvmlite.create_function( + pool, mod, mangled_name, void_ty) + if func is None: + return 0 + + # 注册到函数表 + max_funcs: int = 1024 + rc_add: int = self.Gen.CallGenLeafKit.add_func_to_table(funcs_ptr, func_count, full_name, func, max_funcs, None, 0, 0, pool) + if rc_add == 0: + trans._func_count = func_count + 1 + + # 添加 self 参数 + llvmlite.add_param(pool, func, self_ptr_ty, "%self") + + # 参数添加完成,补全全局函数表的 TypeStr + rc_ut: int = self.Gen.CallGenLeafKit.update_global_func_typestr(pool, full_name, func) + + # 创建 entry 块 + builder + entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") + if entry_blk is None: + return 0 + func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) + if func_builder is None: + return 0 + llvmlite.position_at_end(func_builder, entry_blk) + + # 注册 self 为 SSA 值 + self_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, self_ptr_ty, "%self") + + # 1. 零值填充: store zeroinitializer, Ptr(struct_ty)* %self + # 空 struct({})在 LLVM 中不允许 zeroinitializer(invalid type for null constant), + # 无字段类(接口/标记类,如多继承的 Vec2Extra)跳过零值填充; + # @t.CVTable 类必有 vtable 指针字段(非空),不受影响。 + struct_fcount_zi: int = llvmlite.get_struct_fcount(struct_ty) + if struct_fcount_zi > 0: + zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) + if zero is not None: + llvmlite.build_store(func_builder, zero, self_val) + + # 1.5 如果有虚表,store vtable 全局地址到 __vtable__ 字段(索引 0) + # 用 find_struct_by_type 定位 entry,规避跨模块同名 find_struct 找错 + bi_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_type(struct_ty) + bi_has_vt: int = 0 + if bi_entry is not None: + bi_has_vt = bi_entry.HasVTable + if bi_has_vt == 1: + vt_method_count: int = 0 + if bi_entry is not None: + vt_method_count = bi_entry.VTableMethodCount + if vt_method_count > 0: + # 构造 vtable 类型 { i8*, i8*, ..., i8* } + vt_i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + vt_i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, vt_i8_ty) + + vt_first_node: llvmlite.ParamNode | t.CPtr = None + vt_prev_node: llvmlite.ParamNode | t.CPtr = None + for vti in range(vt_method_count): + vtnode: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, vt_i8_ptr_ty) + if vtnode is None: + continue + if vt_first_node is None: + vt_first_node = vtnode + if vt_prev_node is not None: + llvmlite.paramnode_set_next(vt_prev_node, vtnode) + vt_prev_node = vtnode + + vt_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, vt_first_node, vt_method_count, None) + vt_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, vt_ty) + + # 构造 vtable 全局变量名 + vt_name_buf: str = pool.alloc(128) + if vt_name_buf is not None: + viperlib.snprintf(vt_name_buf, 128, "%s.vtable", class_name) + vt_full_name: str = vt_name_buf + vt_mangled: str = self.Gen.FuncGenBase._mangle_name(trans, vt_full_name) + + # GEP 到 __vtable__ 字段(索引 0) + vt_slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + func_builder, struct_ty, vt_i8_ptr_ty, self_val, 0) + if vt_slot is not None: + # 创建全局变量引用 Value + vt_ref: llvmlite.Value | t.CPtr = llvmlite.new_value(pool) + if vt_ref is not None: + llvmlite.value_set_ty(vt_ref, vt_ptr_ty) + llvmlite.value_set_isconst(vt_ref, 1) + # Name 格式: @"mangled" 或 @mangled + vt_ref_name: str = pool.alloc(256) + if vt_ref_name is not None: + vt_ref_name[0] = '\0' + if self._vtable_name_needs_quote(vt_mangled) != 0: + viperlib.snprintf(vt_ref_name, 256, "@\"%s\"", vt_mangled) + else: + viperlib.snprintf(vt_ref_name, 256, "@%s", vt_mangled) + llvmlite.value_set_name(vt_ref, vt_ref_name) + + # bitcast 到 i8* + vt_as_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + func_builder, vt_ref, vt_i8_ptr_ty) + if vt_as_i8 is not None: + llvmlite.build_store(func_builder, vt_as_i8, vt_slot) + + # 2. 逐字段 store 默认值(用 bi_entry 直接访问,规避跨模块同名 find_struct 找错) + if bi_entry is not None: + for fi in range(bi_entry.FieldCount): + fe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry( + bi_entry, fi) + if fe is None or fe.DefaultVal is None: + continue + # 静态数组字段 + 列表字面量默认值 → 整体置零 + 逐元素 GEP+store + # (与局部 AnnAssign 数组初始化一致;translate_value 会把列表字面量 + # 误译成动态 list 对象指针,coerce 到 [N x elem] 会失败)。 + # 单参 CArray 字段(如 t.CArray[str] = ["py", ...])经类体字段收集 + # 推断为静态数组,此处保证 __before_init__ 填充真实字符串指针。 + if fe.Ty is not None and self.Gen.ExprGenBase.is_array_type(fe.Ty) != 0 \ + and fe.DefaultVal.kind() == ast.ASTKind.List: + field_ptr_arr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + func_builder, struct_ty, fe.Ty, self_val, fe.Index) + if field_ptr_arr is not None: + zero_arr_f: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, fe.Ty) + if zero_arr_f is not None: + llvmlite.build_store(func_builder, zero_arr_f, field_ptr_arr) + # Mixin 静态绑定:self._xxx 只沿本类查找,跨 Mixin 方法 + # (AssignGenMixin._init_global_array_from_list)会生成不存在 + # 符号 → 必须走 HandlesAnnAssign 模块级委托(延迟 import Gen)。 + self.Gen.AssignGen._init_global_array_from_list( + func_builder, pool, mod, field_ptr_arr, fe.DefaultVal, trans) + continue + # 翻译默认值表达式 + default_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + func_builder, pool, mod, fe.DefaultVal, None, 0, trans) + if default_val is None: + continue + # GEP 到字段 + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + func_builder, struct_ty, fe.Ty, self_val, fe.Index) + if field_ptr is None: + continue + # 类型转换并 store + default_val = self.Gen.ExprGenBase.coerce_to_type(func_builder, default_val, fe.Ty, fe.DefaultVal) + llvmlite.build_store(func_builder, default_val, field_ptr) + + # 3. ret void + llvmlite.build_ret_void(func_builder) + return 0 \ No newline at end of file diff --git a/App/lib/core/Gen/ExprGenMixin.vp b/App/lib/core/Gen/ExprGenMixin.vp index 03cf488..c6730fc 100644 --- a/App/lib/core/Gen/ExprGenMixin.vp +++ b/App/lib/core/Gen/ExprGenMixin.vp @@ -118,4 +118,20 @@ class ExprGenMixin(ExprGenBase.ExprGenBase): # 解析器对 f"{expr:spec}"(单 FormattedValue 无字面量)返回裸 FormattedValue # 而非 JoinedStr(见 ast/parser.vp _parse_fstring),需单独翻译 return self.Gen.ExprGenFstr.translate_formatted_value(builder, pool, mod, node, trans) + elif k == ast.ASTKind.Await: + # 协程 await(TPV-M1):await 目标是 async 函数调用时内联翻译 + # (子帧创建 + resume 到 DONE + 取子帧 ret 存父帧 await 槽 + 父挂起), + # 返回子协程 ret 值(i32)。顶层 await(AnnAssign/Assign 的 value 直接 + # 是 Await)由 AsyncGen 段翻译特判处理,本分支覆盖表达式上下文中的 + # await(M1 覆盖有限场景,详见 AsyncGenMixin._emit_await)。 + aw: ast.Await | t.CPtr = (ast.Await | t.CPtr)(node) + if aw is not None and aw.value is not None and aw.value.kind() == ast.ASTKind.Call: + aw_cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(aw.value) + if aw_cl.func is not None and aw_cl.func.kind() == ast.ASTKind.Name: + aw_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aw_cl.func) + if aw_nm.id is not None and trans is not None: + if self.Gen.AsyncGen.is_async_func(trans, aw_nm.id) != 0: + return self.Gen.AsyncGen._emit_await( + builder, pool, mod, trans, aw, aw_nm.id) + return None return None diff --git a/App/lib/core/Gen/FuncGenDef.vp b/App/lib/core/Gen/FuncGenDef.vp index 2099482..01b6660 100644 --- a/App/lib/core/Gen/FuncGenDef.vp +++ b/App/lib/core/Gen/FuncGenDef.vp @@ -224,6 +224,13 @@ class FuncGenDef(CallGenBase.CallGenBase): if fd is None or fd.name is None: return 0 + # async def(TPV-M1 协程):FLAG_IS_ASYNC=1(includes/ast/stmts.vp L342-345, + # 解析器把 async def 存为 FunctionDef 且 flags & 1)。 + # → 走 AsyncGenMixin 状态机翻译(create_/resume_), + # 早返回不进普通函数路径(普通路径生成 ret 型普通函数,无法挂起/恢复)。 + if fd.flags is not None and (fd.flags & 1) != 0: + return self.Gen.AsyncGen.translate_async_function(trans, node) + pool: memhub.MemBuddy | t.CPtr = trans.Pool mod: llvmlite.LLVMModule | t.CPtr = trans.Module imported_modules: str = trans._imported_modules diff --git a/App/lib/core/Gen/Generator.vp b/App/lib/core/Gen/Generator.vp index 10600d7..959b5b2 100644 --- a/App/lib/core/Gen/Generator.vp +++ b/App/lib/core/Gen/Generator.vp @@ -50,6 +50,7 @@ import lib.core.Gen.StmtGenDeclMixin as StmtGenDeclMixin import lib.core.Gen.StmtGenMixin as StmtGenMixin import lib.core.Gen.MatchGenMixin as MatchGenMixin import lib.core.Gen.AssignGenMixin as AssignGenMixin +import lib.core.Gen.AsyncGenMixin as AsyncGenMixin import lib.core.Gen.VarGenMixin as VarGenMixin import lib.core.Gen.TranslatorGenMixin as TranslatorGenMixin @@ -111,6 +112,7 @@ class Generator: StmtGen: StmtGenMixin.StmtGenMixin | t.CPtr MatchGen: MatchGenMixin.MatchGenMixin | t.CPtr AssignGen: AssignGenMixin.AssignGenMixin | t.CPtr + AsyncGen: AsyncGenMixin.AsyncGenMixin | t.CPtr VarGen: VarGenMixin.VarGenMixin | t.CPtr TranslatorGen: TranslatorGenMixin.TranslatorGenMixin | t.CPtr @@ -440,6 +442,13 @@ class Generator: string.memset(SubTranslatorGen, 0, TranslatorGenMixin.TranslatorGenMixin.__sizeof__()) SubTranslatorGen.Gen = self self.TranslatorGen = SubTranslatorGen + SubAsyncGen: AsyncGenMixin.AsyncGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(AsyncGenMixin.AsyncGenMixin.__sizeof__()) + if SubAsyncGen is None: + stdio.printf("FAIL: AsyncGenMixin alloc failed\n") + stdlib.exit(1) + string.memset(SubAsyncGen, 0, AsyncGenMixin.AsyncGenMixin.__sizeof__()) + SubAsyncGen.Gen = self + self.AsyncGen = SubAsyncGen # ---- 初始化各子对象字段(Init* 方法内联调用) ---- SubBaseGen.InitBaseGen(pool) diff --git a/App/lib/core/Handles/HandlesTranslator.vp b/App/lib/core/Handles/HandlesTranslator.vp index b8133cf..2d2e9b9 100644 --- a/App/lib/core/Handles/HandlesTranslator.vp +++ b/App/lib/core/Handles/HandlesTranslator.vp @@ -1,599 +1,743 @@ -import lib.core.Gen.GenApi as GenApi -import lib.core.Gen.GenTypes as GenTypes -import lib.core.Gen.TranslatorGenMixin as TranslatorGenMixin -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import viperlib -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.Projectrans.Config as Config -import lib.core.StubMergerBuild as StubMergerBuild -import lib.core.Handles.ExprCallTable as ExprCallTable -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Gen.Generator as Generator - - -# ============================================================ -# HandlesTranslator - 翻译器状态管理 + 主入口 -# -# 从 translator.py 拆分出来,负责: -# 1. Translator 类 - 状态管理(Module, 变量表, 函数表, 导入) -# 2. translate() - 主翻译入口 -# 3. dump_ir() - IR 输出 -# -# 语句/表达式翻译全部委托给 Handles 模块: -# HandlesMain - wrapper main 创建 + children 遍历 -# HandlesBody - 语句分派 -# HandlesExpr - 表达式翻译 -# HandlesFunctions - 函数定义处理 -# 注意:str = bytes = t.CChar | t.CPtr = i8* -# -# P6-E 对象化重构:模块级 global/nonlocal 名称管理函数已迁移为 -# lib.core.Gen.TranslatorGenMixin 的方法,本模块保留同名模块级 -# 函数作为"一行委托"(同 P2-P5 模式)。Translator 类保留在本模块。 -# ============================================================ - -# 常量 -MAX_VARS: t.CDefine = 1024 -MAX_FUNCS: t.CDefine = 1024 -MAX_GLOBAL_NAMES: t.CDefine = 32 - - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) -# ============================================================ -_g_gen: Generator.Generator | t.CPtr = None - - -@t.NoVTable -class Translator: - """翻译器:管理编译状态,委托 Handles 模块执行翻译""" - - # LLVM 上下文(共享状态) - Module: llvmlite.LLVMModule | t.CPtr - Pool: memhub.MemBuddy | t.CPtr - - # 函数表 - _funcs: GenTypes.FuncEntry | t.CPtr - _func_count: t.CInt - - # 导入模块跟踪 - _imported_modules: str - _from_imports: str - - # 当前翻译上下文 - _cur_func: llvmlite.Function | t.CPtr - _cur_builder: llvmlite.IRBuilder | t.CPtr - - # 当前赋值语句的注解节点(AnnAssign 翻译 rhs 前设置,Assign 翻译前清空)。 - # 供 c.Deref(i8*) 推断读取宽度:v: int = c.Deref(p) → bitcast i32* load, - # 对齐 TPC HandlesSpecialCall._infer_deref_target_type(DictTest 500→-12 根因: - # i8* Deref 固定读 1 字节 + sext 截断)。 - CurAssignAnnot: ast.AST | t.CPtr - - # 当前赋值语句的 RHS 节点(AnnAssign 翻译 rhs 前设置,rhs 翻译后清除)。 - # 供 c.Deref 判定"是否为赋值直接 RHS":仅 v: int = c.Deref(p) 时用 - # CurAssignAnnot 推断读取宽度;嵌套在 while 条件/比较/binop/类型转换 - # 调用中(如 while c.Deref(p) != 0、total += t.CInt(c.Deref(p)))不推断, - # 否则 i8* 会被残留 CurAssignAnnot 误判为 i32* 读 4 字节(对齐 TPC - # _infer_deref_target_type 的直接 RHS 检查)。 - CurAssignNode: ast.AST | t.CPtr - - # 循环控制流目标(break/continue) - _break_bb: llvmlite.BasicBlock | t.CPtr - _continue_bb: llvmlite.BasicBlock | t.CPtr - - # 独立标签计数器(不与 builder.Counter 共享,避免 SSA 编号非单调) - _label_counter: t.CInt - - # 追加90:控制流 merge 块可达性(1=有 br 进入可达/0=全分支 return 结构性不可达) - _ctrl_merge_reachable: t.CInt - - # global 声明的变量名集合(当前函数内) - _global_names: str - _global_name_count: t.CInt - - # nonlocal 声明的变量名集合(当前函数内) - _nonlocal_names: str - _nonlocal_name_count: t.CInt - # nonlocal 变量的类型信息(LLVMType 指针数组,与 _nonlocal_names 一一对应) - # 用于 env 指针数组方案:子函数访问 nonlocal 变量时需要知道原始类型 - _nonlocal_types: str - - # 闭包相关:当前函数名(用于嵌套函数提升命名) - _cur_func_name: str - - # *args 变长参数支持:当前函数的 va_list 指针(i8* alloca) - # 仅当函数声明了 *args 时设置,供 arg(type) 糖函数使用 - _va_list_ptr: llvmlite.Value | t.CPtr - # *args 参数名(如 "args"),用于符号表注册 - _vararg_name: str - - # OOP iter 协议:当前 __next__ 方法的隐藏 stop-flag 参数(i1*)。 - # _translate_method 注入 __stop_iter_flag__ 参数时设置;translate_raise - # 检测 raise StopIteration 时对该指针 store 1(对齐 TPC HandlesRaise.py)。 - # 非 __next__ 函数中为 None。 - _stop_iter_flag_ptr: llvmlite.Value | t.CPtr - - # try-except 机制(对齐 TPC HandlesTry.py):当前最内层 try 的 - # 分发块 + 异常编码/消息 alloca。translate_try 设置,translate_raise - # 与调用侧 EH 检测写入/跳转。try 外为 None。 - _eh_dispatch_bb: llvmlite.BasicBlock | t.CPtr - _eh_code_ptr: llvmlite.Value | t.CPtr - _eh_msg_ptr: llvmlite.Value | t.CPtr - # 当前函数的 __eh_msg_out__(i8**)/__eh_code_out__(i32*)输出参数 - # (函数签名含 raise 时由 translate_function_def/_translate_method 注入)。 - # 无 EH 参数时 _cur_func_has_eh == 0。 - _eh_msg_out_param: llvmlite.Value | t.CPtr - _eh_code_out_param: llvmlite.Value | t.CPtr - _cur_func_has_eh: int - - # 模块 SHA1 前缀(16 字符),用于函数名混淆(SHA1 命名空间) - ModuleSha1: str - # 当前文件所属包名(如 "llvmlite"),用于解析相对导入(from . import ...) - # None 表示当前文件是顶级模块(无包),相对导入无法解析 - CurrentPackage: str - # 闭包 env 中的 nonlocal 变量偏移映射(每个 nonlocal 变量在 env 中的字节偏移) - _closure_env_offsets: t.CInt - _closure_env_count: t.CInt - # lambda 表达式全局唯一 ID 计数器(生成提升函数名 __lambda_{id}) - # 独立于 _closure_env_count:后者随函数进入被 clear_scope_names 重置, - # lambda ID 需跨函数全局唯一(提升函数名避免冲突) - _lambda_count: t.CInt - # 函数链内 nonlocal 变量集合(预扫描收集,含嵌套函数声明的 nonlocal)。 - # 用于"不同层捕获不同变量"场景(如 level1→a, level2→b):b 定义在最外层 - # 但 level1 不捕获——level1 env 无 b 槽,level2 无法经 env 链获取 b 的堆。 - # 解决:在最外层函数中为链内所有 nonlocal 建堆,并把堆地址 store 到 - # 模块级映射变量 @nlheap.{sha1}.{name};内层闭包创建时从映射 load。 - _nl_chain_names: t.CVoid | t.CPtr - _nl_chain_count: t.CInt - # 链内 nonlocal 堆预建标志(每函数只建一次):translate_function_def 进入 - # 新函数时重置为 0;_prepare_chain_nonlocals 首次调用置 1。多个嵌套函数 - # 定义共享同一堆(防重复 malloc + 二次重定向 VarEntry.Alloca)。 - _nl_chain_done: t.CInt - - # 泛型特化上下文:当前正在特化的类型参数名/实参名列表 - # 由 _specialize_generic_class 设置,方法体翻译时用于将 T 替换为具体类型 - # None 表示不在泛型特化上下文中 - GenericTypeParamNames: list[str] | t.CPtr - GenericTypeArgs: list[str] | t.CPtr - - # Phase 1a 声明模式标志:1=只注册 struct/enum/union 不翻译代码体,0=全量翻译 - _declare_only: t.CInt - - # Phase A 依赖未就绪标志:1=本文件翻译时依赖模块的 text.ll 尚未生成 - # (同项目源文件按顺序翻译,main.vp 先于其 import 的 mbuddytest.vp), - # 跨模块函数返回类型无法精确解析。Phase A 多遍循环据此下遍重试。 - _deps_pending: t.CInt - - # 嵌套作用域符号表 - SymTab: GenTypes.SymbolTable | t.CPtr - - def __init__(self): - self.Module = None - self.Pool = None - self._funcs = None - self._func_count = 0 - self._cur_func = None - self._cur_builder = None - self._break_bb = None - self._continue_bb = None - self._label_counter = 0 - self._imported_modules = None - self._from_imports = None - self._global_names = None - self._global_name_count = 0 - self._nonlocal_names = None - self._nonlocal_name_count = 0 - self._nonlocal_types = None - self._cur_func_name = None - self._va_list_ptr = None - self._vararg_name = None - self._stop_iter_flag_ptr = None - self._eh_dispatch_bb = None - self._eh_code_ptr = None - self._eh_msg_ptr = None - self._eh_msg_out_param = None - self._eh_code_out_param = None - self._cur_func_has_eh = 0 - self.ModuleSha1 = None - self.CurrentPackage = None - self._closure_env_offsets = 0 - self._closure_env_count = 0 - self._lambda_count = 0 - self._nl_chain_names = None - self._nl_chain_count = 0 - self._nl_chain_done = 0 - self.GenericTypeParamNames = None - self.GenericTypeArgs = None - self._declare_only = 0 - self._deps_pending = 0 - self.SymTab = None - - # ============================================================ - # 状态初始化 - # ============================================================ - def _init_state(self, pool: memhub.MemBuddy | t.CPtr): - """初始化变量表、函数表和子 Handle""" - self.Pool = pool - if self._funcs is None: - self._funcs = GenApi.init_func_table(pool, MAX_FUNCS) - # 嵌套作用域符号表(新版) - if self.SymTab is None: - self.SymTab = GenApi.init_symbol_table(pool) - # global/nonlocal 名称集合缓冲区(32 个 char* 指针 = 256 字节) - if self._global_names is None: - self._global_names = stdlib.malloc(MAX_GLOBAL_NAMES * 8) - if self._global_names is not None: - string.memset(self._global_names, 0, MAX_GLOBAL_NAMES * 8) - self._global_name_count = 0 - if self._nonlocal_names is None: - self._nonlocal_names = stdlib.malloc(MAX_GLOBAL_NAMES * 8) - if self._nonlocal_names is not None: - string.memset(self._nonlocal_names, 0, MAX_GLOBAL_NAMES * 8) - self._nonlocal_name_count = 0 - # nonlocal 变量类型数组(LLVMType 指针数组,与 _nonlocal_names 一一对应) - if self._nonlocal_types is None: - self._nonlocal_types = stdlib.malloc(MAX_GLOBAL_NAMES * 8) - if self._nonlocal_types is not None: - string.memset(self._nonlocal_types, 0, MAX_GLOBAL_NAMES * 8) - - # ============================================================ - # 主翻译入口 - # ============================================================ - def translate(self, tree: ast.AST | t.CPtr) -> int: - """将 AST 翻译为 LLVM IR""" - if tree is None: - return 1 - if _mbuddy is None: - return 1 - - pool: memhub.MemBuddy | t.CPtr = _mbuddy - - # 初始化状态 - self._init_state(pool) - - # 创建 LLVM 模块 - mod: llvmlite.LLVMModule | t.CPtr = llvmlite.new_module(pool, "main") - if mod is None: - VLogger.error("NewModule returned NULL", "TR") - return 1 - self.Module = mod - - # 设置目标(优先使用 project.vpj 中的配置) - triple: str = Config.TargetTriple - if triple is None: - triple = "x86_64-pc-windows-msvc" - llvmlite.module_set_target(mod, triple) - - # 类型 - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - # 声明 printf - printf_func: llvmlite.Function | t.CPtr = llvmlite.create_declare( - pool, mod, "printf", i32_ty) - if printf_func is None: - VLogger.error("CreateDeclare printf returned NULL", "TR") - return 1 - llvmlite.add_param(pool, printf_func, i8_ptr_ty, "fmt") - printf_func.IsVarArg = 1 - # 声明 LLVM va_start/va_end intrinsic(供 *args 函数体内使用) - # declare void @llvm.va_start(i8*) - # declare void @llvm.va_end(i8*) - void_ty_decl: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) - va_start_func: llvmlite.Function | t.CPtr = llvmlite.create_declare( - pool, mod, "llvm.va_start", void_ty_decl) - if va_start_func is not None: - llvmlite.add_param(pool, va_start_func, i8_ptr_ty, "ap") - va_end_func: llvmlite.Function | t.CPtr = llvmlite.create_declare( - pool, mod, "llvm.va_end", void_ty_decl) - if va_end_func is not None: - llvmlite.add_param(pool, va_end_func, i8_ptr_ty, "ap") - - # 声明 malloc(闭包分配用) - malloc_func: llvmlite.Function | t.CPtr = llvmlite.create_declare( - pool, mod, "malloc", i8_ptr_ty) - if malloc_func is not None: - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - llvmlite.add_param(pool, malloc_func, i64_ty, "size") - - # 检查用户是否定义了 main 函数 - has_user_main: int = 0 - ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children - if ch is not None: - cn_count: t.CSizeT = len(ch) - for ci in range(cn_count): - child: ast.AST | t.CPtr = ch.get(ci) - if child is not None and child.kind() == ast.ASTKind.FunctionDef: - fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child) - if fd is not None and fd.name is not None: - if string.strcmp(fd.name, "main") == 0: - has_user_main = 1 - break - - if self._declare_only != 0: - # Phase 1a-pre(2=import扫描) / Phase 1a(1=struct注册): 只处理模块级,不创建 main 函数和 builder - self._translate_module_level(pool, mod, tree) - elif has_user_main == 0: - # 无用户 main → 只翻译模块级语句,不创建 wrapper main - # 修复:避免每个文件都生成 define i32 @main() 导致链接时 main 冲突 - # 只有包含 def main() 的入口文件才会有 define i32 @main() - self._translate_module_level(pool, mod, tree) - else: - # 用户已定义 main → 委托 HandlesMain 翻译模块级 - self._translate_module_level(pool, mod, tree) - - return 0 - - # ============================================================ - # 包装 main 函数(无用户 main 时)→ 委托 HandlesMain - # ============================================================ - def _translate_wrapper_main(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - tree: ast.AST | t.CPtr, - i32_ty: llvmlite.LLVMType | t.CPtr): - """委托 GenApi.create_wrapper_main() 创建包装 main(trans 单参)""" - added: int = GenApi.create_wrapper_main(self, tree, i32_ty) - - # ============================================================ - # 模块级翻译(用户已定义 main)→ 委托 HandlesMain - # ============================================================ - def _translate_module_level(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - tree: ast.AST | t.CPtr): - """委托 GenApi.translate_children() 翻译模块级语句(trans 单参)""" - # 全量翻译模式下,先处理导入语句,再创建前向声明,解决前向引用问题 - if self._declare_only == 0: - # 预处理导入语句,确保 _imported_modules 和 _from_imports 已填充 - # (前向声明需要解析类型注解,如 t.CArray[str] 依赖 t 模块已导入) - # 记录最后处理的 import 行号,供 vpi 注入错误上下文帧定位 - cur_imp_lineno: int = 0 - ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children - if ch is not None: - cn_count: t.CSizeT = len(ch) - for ci in range(cn_count): - child: ast.AST | t.CPtr = ch.get(ci) - if child is None: - continue - kd: int = child.kind() - if kd == ast.ASTKind.Import: - cur_imp_lineno = child.lineno - GenApi.translate_import(self, child) - elif kd == ast.ASTKind.ImportFrom: - cur_imp_lineno = child.lineno - GenApi.translate_import_from_module(self, child) - GenApi.translate_import_from_names(self, child) - # 对齐 TPC _inject_auto_imports:检测源文件对 list/dict 容器的使用 - # (裸名注解 d: dict / 构造 dict(...) / 下标 list[T]),自动把容器 - # 类标记为可见结构体。背景:_list.vp/_dict.vp 定义内建容器类且已由 - # Phase1 注册,但源文件不显式 import 它们(TPC 在翻译前自动注入 - # import _list/_dict);TPV 用可见性机制等效替代——否则裸名 - # `d: dict` 注解 resolve_annotation_type 时 is_struct_visible=0 - # 解析失败(DictTest 的 "变量类型注解解析失败")。 - self._inject_auto_container_visibility(pool, tree) - # 扫描当前模块的 CTypedef 声明已由 Phase1 1b 文本扫描注册 - # (RegisterCTypedefFromSource,见 Phase1Main.vp)——AST 字符串字段 - # token 零拷贝指向 src_buf,跨阶段内容不稳定,此处 AST 扫描读 attr - # 会 0xC0000005(stdint.vp 崩溃根因),故移除。 - # 跨模块 .vpi 注入:加载依赖模块的 .vpi 文件, - # 将函数 declare 声明注入到当前模块,解决跨模块函数调用找不到函数的问题 - # 严格保证 declare_only == 0 时才注入(避免 Phase A-pre-inc 死锁) - if self._imported_modules is not None: - import lib.core.StubMerger as StubMerger - # 错误上下文帧:当前模块触发依赖 stub 加载的 import 位置 - GenApi.push_trace(GenApi.get_current_file(), cur_imp_lineno) - StubMergerBuild.LoadDepVpiIntoModule( - pool, mod, self._imported_modules, self._from_imports, - GenApi.get_temp_dir(), self) - GenApi.pop_trace() - # 预注册模块级变量(AnnAssign/Assign)到 SymTab - # 解决时序问题:class Logger 的 __init__ 引用 _mbuddy 时, - # _mbuddy 的 AnnAssign 在 AST 中位于 class Logger 之后, - # 按 AST 顺序翻译时 _mbuddy 尚未注册 → lookup_var 返回 None → rhs_val is None - # 预处理先于 translate_children 注册所有模块级变量, - # 后续 translate_children 遍历到同一 AnnAssign 时 handle_module_level_var - # 通过 lookup_module_var 检测已存在并跳过(HandlesMain.py:206-209) - if ch is not None: - for ci in range(cn_count): - child: ast.AST | t.CPtr = ch.get(ci) - if child is None: - continue - kd_mv: int = child.kind() - if kd_mv == ast.ASTKind.AnnAssign or kd_mv == ast.ASTKind.Assign: - GenApi.handle_module_level_var(self, child) - # 创建前向声明 - GenApi.forward_declare_functions(self, tree) - added: int = GenApi.translate_children(self, tree) - - # ============================================================ - # 容器模块自动可见性注入(对齐 TPC _inject_auto_imports) - # - # TPC 在翻译前自动注入 `import _list / import _dict (+json)` 到源文件, - # 使 list/dict 内建容器类在符号表中可见。TPV 用可见性机制等效替代: - # _list.vp/_dict.vp 已由 Phase1 注册(可达集合含它们),这里只需在 - # 当前文件翻译时把容器类名标记为可见结构体,裸名注解/构造即可解析。 - # - # 检测模式(与 TPC Phase2Translator._inject_auto_imports 一致): - # - AnnAssign 注解裸名 Name(list/dict):d: dict - # - 构造调用 func 裸名 Name(list/dict):dict(bd) - # - Subscript 的 value 裸名 Name(list/dict):list[int] - # ============================================================ - def _inject_auto_container_visibility(self, pool: memhub.MemBuddy | t.CPtr, - tree: ast.AST | t.CPtr): - """检测 list/dict 容器使用,注入容器类可见性""" - if tree is None or tree.children is None: - return - # 用栈式缓冲区传递检测结果(跨函数参数用 4 字节 int 指针) - need_list_box: t.CPtr = stdlib.malloc(4) - need_dict_box: t.CPtr = stdlib.malloc(4) - if need_list_box is None or need_dict_box is None: - if need_list_box is not None: - stdlib.free(need_list_box) - if need_dict_box is not None: - stdlib.free(need_dict_box) - return - need_list_box[0] = 0 - need_dict_box[0] = 0 - self._scan_container_usage(tree, need_list_box, need_dict_box) - if need_dict_box[0] != 0: - # dict 类可见 + _dict 模块导入(构造/方法调用的 SHA1 解析) - GenApi.add_visible_struct(pool, "dict") - if self._imported_modules is None or \ - GenApi.is_module_imported(self._imported_modules, "_dict") == 0: - self._imported_modules = GenApi.add_imported_module( - pool, self._imported_modules, "_dict") - if need_list_box[0] != 0: - GenApi.add_visible_struct(pool, "list") - if self._imported_modules is None or \ - GenApi.is_module_imported(self._imported_modules, "_list") == 0: - self._imported_modules = GenApi.add_imported_module( - pool, self._imported_modules, "_list") - stdlib.free(need_list_box) - stdlib.free(need_dict_box) - - def _scan_container_usage(self, node: ast.AST | t.CPtr, - need_list_box: t.CPtr, - need_dict_box: t.CPtr): - """递归扫描 AST 语句结构,检测 list/dict 容器使用""" - if node is None: - return - k: int = node.kind() - if k == ast.ASTKind.AnnAssign: - aa_s: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) - if aa_s.annotation is not None: - self._check_container_type_node(aa_s.annotation, need_list_box, need_dict_box) - elif k == ast.ASTKind.Call: - cl_s: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) - if cl_s.func is not None: - self._check_container_type_node(cl_s.func, need_list_box, need_dict_box) - elif k == ast.ASTKind.Subscript: - sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - if sub_s.value is not None: - self._check_container_type_node(sub_s.value, need_list_box, need_dict_box) - elif k == ast.ASTKind.List: - # [] 字面量:容器模板仍需注册 - need_list_box[0] = 1 - elif k == ast.ASTKind.Dict: - # {} 字面量:容器模板仍需注册 - need_dict_box[0] = 1 - # 递归语句块子节点 - if node.children is not None: - ch_s: list[ast.AST | t.CPtr] | t.CPtr = node.children - n_s: t.CSizeT = len(ch_s) - for ci_s in range(n_s): - self._scan_container_usage(ch_s.get(ci_s), need_list_box, need_dict_box) - - def _check_container_type_node(self, node: ast.AST | t.CPtr, - need_list_box: t.CPtr, - need_dict_box: t.CPtr): - """检测类型位置节点是否为 list/dict(支持 Name 与 Subscript 外层)""" - if node is None: - return - k: int = node.kind() - if k == ast.ASTKind.Name: - nm_s: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm_s.id is not None: - if string.strcmp(nm_s.id, "dict") == 0: - need_dict_box[0] = 1 - elif string.strcmp(nm_s.id, "list") == 0: - need_list_box[0] = 1 - elif k == ast.ASTKind.Subscript: - sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - if sub_s.value is not None: - self._check_container_type_node(sub_s.value, need_list_box, need_dict_box) - - - # ============================================================ - # IR 输出 - # ============================================================ - def dump_ir(self, buf: bytes, size: t.CSizeT, mode: int): - """将 LLVM IR 输出到缓冲区 - - mode: 0=完整, 1=stub(仅声明), 2=text(仅代码) - """ - if self.Module is None or buf is None: - return - if _mbuddy is None: - return - buf[0] = '\0' - llvmlite.LLVMModulePrint(buf, size, self.Module, _mbuddy, mode) - - -# ============================================================ -# global/nonlocal 名称管理(模块级辅助函数,委托到 gen 方法) -# ============================================================ -def add_global_name(trans: HT.Translator | t.CPtr, name: str): - """添加一个 global 变量名(委托到 gen.add_global_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.TranslatorGen.add_global_name(trans, name) - - -def is_global_name(trans: HT.Translator | t.CPtr, name: str) -> int: - """检查 name 是否在当前函数的 global 集合中(委托到 gen.is_global_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.TranslatorGen.is_global_name(trans, name) - return 0 - - -def add_nonlocal_name(trans: HT.Translator | t.CPtr, name: str, - var_ty: llvmlite.LLVMType | t.CPtr = None): - """添加一个 nonlocal 变量名(委托到 gen.add_nonlocal_name) - - Args: - name: nonlocal 变量名 - var_ty: 变量的 LLVM 类型(用于 env 指针数组方案的类型恢复, - None 时回退为 i32) - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.TranslatorGen.add_nonlocal_name(trans, name, var_ty) - - -def get_nonlocal_type(trans: HT.Translator | t.CPtr, - name: str) -> llvmlite.LLVMType | t.CPtr: - """获取 nonlocal 变量的 LLVM 类型(委托到 gen.get_nonlocal_type) - - Returns: 找到的类型指针,找不到返回 None - """ - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.TranslatorGen.get_nonlocal_type(trans, name) - return None - - -def is_nonlocal_name(trans: HT.Translator | t.CPtr, name: str) -> int: - """检查 name 是否在当前函数的 nonlocal 集合中(委托到 gen.is_nonlocal_name)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.TranslatorGen.is_nonlocal_name(trans, name) - return 0 - - -def get_nonlocal_index(trans: HT.Translator | t.CPtr, name: str) -> int: - """获取 nonlocal 变量在 env 中的索引(0-based),找不到返回 -1(委托到 gen.get_nonlocal_index)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.TranslatorGen.get_nonlocal_index(trans, name) - return 0 - - -def clear_scope_names(trans: HT.Translator | t.CPtr): - """清空当前函数的 global/nonlocal 名称集合(进入新函数时调用)(委托到 gen.clear_scope_names)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - g.TranslatorGen.clear_scope_names(trans) - - -# 全局 mbuddy 指针 -_mbuddy: memhub.MemBuddy | t.CPtr +import lib.core.Gen.GenApi as GenApi +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.TranslatorGenMixin as TranslatorGenMixin +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.Projectrans.Config as Config +import lib.core.StubMergerBuild as StubMergerBuild +import lib.core.Handles.ExprCallTable as ExprCallTable +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Gen.Generator as Generator + + +# ============================================================ +# HandlesTranslator - 翻译器状态管理 + 主入口 +# +# 从 translator.py 拆分出来,负责: +# 1. Translator 类 - 状态管理(Module, 变量表, 函数表, 导入) +# 2. translate() - 主翻译入口 +# 3. dump_ir() - IR 输出 +# +# 语句/表达式翻译全部委托给 Handles 模块: +# HandlesMain - wrapper main 创建 + children 遍历 +# HandlesBody - 语句分派 +# HandlesExpr - 表达式翻译 +# HandlesFunctions - 函数定义处理 +# 注意:str = bytes = t.CChar | t.CPtr = i8* +# +# P6-E 对象化重构:模块级 global/nonlocal 名称管理函数已迁移为 +# lib.core.Gen.TranslatorGenMixin 的方法,本模块保留同名模块级 +# 函数作为"一行委托"(同 P2-P5 模式)。Translator 类保留在本模块。 +# ============================================================ + +# 常量 +MAX_VARS: t.CDefine = 1024 +MAX_FUNCS: t.CDefine = 1024 +MAX_GLOBAL_NAMES: t.CDefine = 32 +# 协程表容量(TPV-M1):async 函数数 / 协程变量·局部名数 +MAX_CORO_FUNCS: t.CDefine = 256 +MAX_CORO_VARS: t.CDefine = 256 +MAX_CORO_TRY: t.CDefine = 16 + + +# ============================================================ +# 全局 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 + + # 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: + import lib.core.StubMerger as StubMerger + # 错误上下文帧:当前模块触发依赖 stub 加载的 import 位置 + GenApi.push_trace(GenApi.get_current_file(), cur_imp_lineno) + StubMergerBuild.LoadDepVpiIntoModule( + pool, mod, self._imported_modules, self._from_imports, + GenApi.get_temp_dir(), self) + GenApi.pop_trace() + # 预注册模块级变量(AnnAssign/Assign)到 SymTab + # 解决时序问题:class Logger 的 __init__ 引用 _mbuddy 时, + # _mbuddy 的 AnnAssign 在 AST 中位于 class Logger 之后, + # 按 AST 顺序翻译时 _mbuddy 尚未注册 → lookup_var 返回 None → rhs_val is None + # 预处理先于 translate_children 注册所有模块级变量, + # 后续 translate_children 遍历到同一 AnnAssign 时 handle_module_level_var + # 通过 lookup_module_var 检测已存在并跳过(HandlesMain.py:206-209) + if ch is not None: + for ci in range(cn_count): + child: ast.AST | t.CPtr = ch.get(ci) + if child is None: + continue + kd_mv: int = child.kind() + if kd_mv == ast.ASTKind.AnnAssign or kd_mv == ast.ASTKind.Assign: + GenApi.handle_module_level_var(self, child) + # 创建前向声明 + GenApi.forward_declare_functions(self, tree) + added: int = GenApi.translate_children(self, tree) + + # ============================================================ + # 容器模块自动可见性注入(对齐 TPC _inject_auto_imports) + # + # TPC 在翻译前自动注入 `import _list / import _dict (+json)` 到源文件, + # 使 list/dict 内建容器类在符号表中可见。TPV 用可见性机制等效替代: + # _list.vp/_dict.vp 已由 Phase1 注册(可达集合含它们),这里只需在 + # 当前文件翻译时把容器类名标记为可见结构体,裸名注解/构造即可解析。 + # + # 检测模式(与 TPC Phase2Translator._inject_auto_imports 一致): + # - AnnAssign 注解裸名 Name(list/dict):d: dict + # - 构造调用 func 裸名 Name(list/dict):dict(bd) + # - Subscript 的 value 裸名 Name(list/dict):list[int] + # ============================================================ + def _inject_auto_container_visibility(self, pool: memhub.MemBuddy | t.CPtr, + tree: ast.AST | t.CPtr): + """检测 list/dict 容器使用,注入容器类可见性""" + if tree is None or tree.children is None: + return + # 用栈式缓冲区传递检测结果(跨函数参数用 4 字节 int 指针) + need_list_box: t.CPtr = stdlib.malloc(4) + need_dict_box: t.CPtr = stdlib.malloc(4) + if need_list_box is None or need_dict_box is None: + if need_list_box is not None: + stdlib.free(need_list_box) + if need_dict_box is not None: + stdlib.free(need_dict_box) + return + need_list_box[0] = 0 + need_dict_box[0] = 0 + self._scan_container_usage(tree, need_list_box, need_dict_box) + if need_dict_box[0] != 0: + # dict 类可见 + _dict 模块导入(构造/方法调用的 SHA1 解析) + GenApi.add_visible_struct(pool, "dict") + if self._imported_modules is None or \ + GenApi.is_module_imported(self._imported_modules, "_dict") == 0: + self._imported_modules = GenApi.add_imported_module( + pool, self._imported_modules, "_dict") + if need_list_box[0] != 0: + GenApi.add_visible_struct(pool, "list") + if self._imported_modules is None or \ + GenApi.is_module_imported(self._imported_modules, "_list") == 0: + self._imported_modules = GenApi.add_imported_module( + pool, self._imported_modules, "_list") + stdlib.free(need_list_box) + stdlib.free(need_dict_box) + + def _scan_container_usage(self, node: ast.AST | t.CPtr, + need_list_box: t.CPtr, + need_dict_box: t.CPtr): + """递归扫描 AST 语句结构,检测 list/dict 容器使用""" + if node is None: + return + k: int = node.kind() + if k == ast.ASTKind.AnnAssign: + aa_s: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) + if aa_s.annotation is not None: + self._check_container_type_node(aa_s.annotation, need_list_box, need_dict_box) + elif k == ast.ASTKind.Call: + cl_s: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + if cl_s.func is not None: + self._check_container_type_node(cl_s.func, need_list_box, need_dict_box) + elif k == ast.ASTKind.Subscript: + sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + if sub_s.value is not None: + self._check_container_type_node(sub_s.value, need_list_box, need_dict_box) + elif k == ast.ASTKind.List: + # [] 字面量:容器模板仍需注册 + need_list_box[0] = 1 + elif k == ast.ASTKind.Dict: + # {} 字面量:容器模板仍需注册 + need_dict_box[0] = 1 + # 递归语句块子节点 + if node.children is not None: + ch_s: list[ast.AST | t.CPtr] | t.CPtr = node.children + n_s: t.CSizeT = len(ch_s) + for ci_s in range(n_s): + self._scan_container_usage(ch_s.get(ci_s), need_list_box, need_dict_box) + + def _check_container_type_node(self, node: ast.AST | t.CPtr, + need_list_box: t.CPtr, + need_dict_box: t.CPtr): + """检测类型位置节点是否为 list/dict(支持 Name 与 Subscript 外层)""" + if node is None: + return + k: int = node.kind() + if k == ast.ASTKind.Name: + nm_s: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm_s.id is not None: + if string.strcmp(nm_s.id, "dict") == 0: + need_dict_box[0] = 1 + elif string.strcmp(nm_s.id, "list") == 0: + need_list_box[0] = 1 + elif k == ast.ASTKind.Subscript: + sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + if sub_s.value is not None: + self._check_container_type_node(sub_s.value, need_list_box, need_dict_box) + + + # ============================================================ + # IR 输出 + # ============================================================ + def dump_ir(self, buf: bytes, size: t.CSizeT, mode: int): + """将 LLVM IR 输出到缓冲区 + + mode: 0=完整, 1=stub(仅声明), 2=text(仅代码) + """ + if self.Module is None or buf is None: + return + if _mbuddy is None: + return + buf[0] = '\0' + llvmlite.LLVMModulePrint(buf, size, self.Module, _mbuddy, mode) + + +# ============================================================ +# global/nonlocal 名称管理(模块级辅助函数,委托到 gen 方法) +# ============================================================ +def add_global_name(trans: HT.Translator | t.CPtr, name: str): + """添加一个 global 变量名(委托到 gen.add_global_name)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + g.TranslatorGen.add_global_name(trans, name) + + +def is_global_name(trans: HT.Translator | t.CPtr, name: str) -> int: + """检查 name 是否在当前函数的 global 集合中(委托到 gen.is_global_name)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.TranslatorGen.is_global_name(trans, name) + return 0 + + +def add_nonlocal_name(trans: HT.Translator | t.CPtr, name: str, + var_ty: llvmlite.LLVMType | t.CPtr = None): + """添加一个 nonlocal 变量名(委托到 gen.add_nonlocal_name) + + Args: + name: nonlocal 变量名 + var_ty: 变量的 LLVM 类型(用于 env 指针数组方案的类型恢复, + None 时回退为 i32) + """ + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + g.TranslatorGen.add_nonlocal_name(trans, name, var_ty) + + +def get_nonlocal_type(trans: HT.Translator | t.CPtr, + name: str) -> llvmlite.LLVMType | t.CPtr: + """获取 nonlocal 变量的 LLVM 类型(委托到 gen.get_nonlocal_type) + + Returns: 找到的类型指针,找不到返回 None + """ + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.TranslatorGen.get_nonlocal_type(trans, name) + return None + + +def is_nonlocal_name(trans: HT.Translator | t.CPtr, name: str) -> int: + """检查 name 是否在当前函数的 nonlocal 集合中(委托到 gen.is_nonlocal_name)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.TranslatorGen.is_nonlocal_name(trans, name) + return 0 + + +def get_nonlocal_index(trans: HT.Translator | t.CPtr, name: str) -> int: + """获取 nonlocal 变量在 env 中的索引(0-based),找不到返回 -1(委托到 gen.get_nonlocal_index)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.TranslatorGen.get_nonlocal_index(trans, name) + return 0 + + +def clear_scope_names(trans: HT.Translator | t.CPtr): + """清空当前函数的 global/nonlocal 名称集合(进入新函数时调用)(委托到 gen.clear_scope_names)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + g.TranslatorGen.clear_scope_names(trans) + + +# 全局 mbuddy 指针 +_mbuddy: memhub.MemBuddy | t.CPtr diff --git a/Test/App/async_test.vp b/Test/App/async_test.vp new file mode 100644 index 0000000..ad84488 --- /dev/null +++ b/Test/App/async_test.vp @@ -0,0 +1,58 @@ +import t, c +from stdint import * +import stdio +import coro + + +# TPV-M3~M7 协程综合测试: +# M3: For 内 await(range→While)、coro_sleep 挂起、coro_destroy 帧回池 +# M4: raise 存码、await 子帧异常传播、coro_exception 查询 +# M5/M6: try/except(链式匹配 + as e 绑定异常码 + 类型码) +# M7: try/finally、异常消息 msg 槽、自定义异常类、帧池复用 +class MyError(Exception): + pass + + +async def leaf(x: int) -> int: + return x * 2 + + +async def task(n: int) -> int: + s: int = 0 + for i in range(3): # M3:For 内 await + s = s + await leaf(i) + if s > 4: + await coro.coro_sleep(5) # M3:coro_sleep 挂起(wake 槽 + 轮询) + try: + raise ValueError("boom") # M4/M6:raise 类型 + M7 消息 + except ValueError as e: # M5/M6:as e 绑定异常码 + s = s + e + return s + + +async def raiser() -> int: + try: + raise MyError("fin_msg") # M7:自定义异常类 + 消息 + finally: + x: int = 99 # M7:finally 正常路径执行 + return 0 + + +def main() -> int: + tt: t.CPtr = task(3) + r: int = coro.coro_run(tt) + e: int = coro.coro_exception(tt) + stdio.printf("coro result = %d exc = %d\n", r, e) + coro.coro_destroy(tt) # M3/M7:destroy 回池 + t1: t.CPtr = raiser() + r1: int = coro.coro_run(t1) + e1: int = coro.coro_exception(t1) + m1: t.CPtr = coro.coro_exception_msg(t1) + stdio.printf("coro result = %d exc = %d msg = %s\n", r1, e1, m1) + coro.coro_destroy(t1) + t2: t.CPtr = raiser() # 帧池复用 + r2: int = coro.coro_run(t2) + e2: int = coro.coro_exception(t2) + stdio.printf("coro result = %d exc = %d\n", r2, e2) + coro.coro_destroy(t2) + return 0