- Gen 内部 1742 处 HandlesX.func() 改 self.Gen.Y.method() 链式调用 - 数据类/常量迁移 GenTypes.vp(10 类 + CLASS_META_*/META_*/SEQ_KIND_*/FIELD_MAX 等) - 管线/保留文件经 GenApi.vp 模块级入口(48 函数带类型注解,从 Gen 方法签名自动生成) - 删除 26 个纯委托 Handles 文件,仅留 5 个实体文件(Base/Translator/Expr/ExprCall/ExprCallTable) - 修复字段分裂:TypeGenErr CurrentFile/TraceCount 链式化;CallGenBase TempDir/Cexport 真源化
493 lines
24 KiB
Plaintext
493 lines
24 KiB
Plaintext
import lib.core.Gen.GenTypes as GenTypes
|
||
import lib.core.Gen.Generator as Generator
|
||
import lib.core.Gen.CallGenBase as CallGenBase
|
||
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdio
|
||
import stdlib
|
||
import viperlib
|
||
import w32.fileio as fileio
|
||
import lib.core.CompilerFactory as CompilerFactory
|
||
import lib.core.Handles.HandlesBase as HandlesBase
|
||
import lib.core.Handles.HandlesTranslator as HT
|
||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||
import lib.core.StubMerger as StubMerger
|
||
import lib.core.VLogger as VLogger
|
||
import lib.Projectrans.Config as Config
|
||
import lib.Projectrans.Utils as Utils
|
||
|
||
|
||
import lib.core.Gen.ExprGenBase as ExprGenBase
|
||
import lib.core.StubMergerStore as StubMergerStore
|
||
|
||
# ============================================================
|
||
# docstring 登记表容量常量(与 ExprGenMixin 保持一致,本地副本避免
|
||
# 跨模块 CDefine 查找 bug:ExprGenCls(C) 在 ExprGenMixin(M) 之前按
|
||
# 文件序编译时,跨模块 CDefine 全局表未注册 → NameError 未定义)
|
||
# ============================================================
|
||
DOC_MAX: t.CDefine = 512
|
||
DOC_KEY_SZ: t.CDefine = 192
|
||
DOC_VAL_SZ: t.CDefine = 4096
|
||
|
||
|
||
# ============================================================
|
||
# ExprGenCls - ExprGenMixin 拆分(阶段 D):类名推断/docstring 登记
|
||
#
|
||
# 继承 ExprGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||
# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。
|
||
# @t.NoVTable:静态绑定。
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class ExprGenCls(ExprGenBase.ExprGenBase):
|
||
"""类名推断/docstring 登记"""
|
||
|
||
# ============================================================
|
||
# docstring 提取/登记/查找(__doc__ 魔法属性支持)
|
||
#
|
||
# 预注册阶段(BuildPipeline.TranslateFileGetTrans)扫描所有
|
||
# App/includes 文件的 AST,提取函数/类/方法的 docstring 内容
|
||
# 登记到全局表(key = "{module_sha1}.{symbol}");__doc__ 属性
|
||
# 访问时查表,命中则当前模块内联生成字符串常量(无跨模块 IR
|
||
# 符号依赖),未命中返回 null。幂等查重,多遍翻译安全。
|
||
# ============================================================
|
||
|
||
def _extract_docstring_from_body(self, body: list[ast.AST | t.CPtr] | t.CPtr) -> str:
|
||
"""从函数/类体提取 docstring:body[0] 为 Expr(Constant str) 时返回内容"""
|
||
if body is None or len(body) == 0:
|
||
return None
|
||
first: ast.AST | t.CPtr = body.get(0)
|
||
if first is None or first.kind() != ast.ASTKind.Expr:
|
||
return None
|
||
ex: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(first)
|
||
if ex is None or ex.value is None or ex.value.kind() != ast.ASTKind.Constant:
|
||
return None
|
||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(ex.value)
|
||
if cn is None or cn.const_kind != ast.CONST_STR:
|
||
return None
|
||
return cn.str_val
|
||
def register_docstring(self, module_sha1: str, symbol: str, doc: str) -> None:
|
||
"""登记 docstring(key="{module_sha1}.{symbol}"),查重幂等"""
|
||
if module_sha1 is None or symbol is None or doc is None:
|
||
return
|
||
if string.strlen(doc) == 0:
|
||
return
|
||
if self.DocKeys is None:
|
||
self.DocKeys = CompilerFactory.get_perm_pool().alloc(DOC_MAX * DOC_KEY_SZ)
|
||
self.DocValues = CompilerFactory.get_perm_pool().alloc(DOC_MAX * DOC_VAL_SZ)
|
||
if self.DocKeys is None or self.DocValues is None:
|
||
return
|
||
string.memset(self.DocKeys, 0, DOC_MAX * DOC_KEY_SZ)
|
||
string.memset(self.DocValues, 0, DOC_MAX * DOC_VAL_SZ)
|
||
if self.DocCount >= DOC_MAX:
|
||
return
|
||
ml: t.CSizeT = string.strlen(module_sha1)
|
||
sl: t.CSizeT = string.strlen(symbol)
|
||
key_buf: bytes = stdlib.malloc(ml + sl + 2)
|
||
if key_buf is None:
|
||
return
|
||
viperlib.snprintf(key_buf, ml + sl + 2, "%s.%s", module_sha1, symbol)
|
||
i: int
|
||
for i in range(self.DocCount):
|
||
if string.strcmp(self.DocKeys + i * DOC_KEY_SZ, key_buf) == 0:
|
||
stdlib.free(key_buf)
|
||
return
|
||
string.strcpy(self.DocKeys + self.DocCount * DOC_KEY_SZ, key_buf)
|
||
string.strcpy(self.DocValues + self.DocCount * DOC_VAL_SZ, doc)
|
||
self.DocCount += 1
|
||
stdlib.free(key_buf)
|
||
def lookup_docstring(self, module_sha1: str, symbol: str) -> str:
|
||
"""查找 docstring 内容(key="{module_sha1}.{symbol}"),未找到返回 None"""
|
||
if self.DocKeys is None or module_sha1 is None or symbol is None:
|
||
return None
|
||
ml: t.CSizeT = string.strlen(module_sha1)
|
||
sl: t.CSizeT = string.strlen(symbol)
|
||
key_buf: bytes = stdlib.malloc(ml + sl + 2)
|
||
if key_buf is None:
|
||
return None
|
||
viperlib.snprintf(key_buf, ml + sl + 2, "%s.%s", module_sha1, symbol)
|
||
i: int
|
||
for i in range(self.DocCount):
|
||
if string.strcmp(self.DocKeys + i * DOC_KEY_SZ, key_buf) == 0:
|
||
stdlib.free(key_buf)
|
||
return self.DocValues + i * DOC_VAL_SZ
|
||
stdlib.free(key_buf)
|
||
return None
|
||
def extract_module_docstrings(self, tree: ast.AST | t.CPtr, module_sha1: str) -> None:
|
||
"""扫描模块 AST:登记模块级函数/类/方法的 docstring(幂等)"""
|
||
if tree is None or module_sha1 is None:
|
||
return
|
||
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||
if ch is None:
|
||
return
|
||
cn: t.CSizeT = len(ch)
|
||
for ci in range(cn):
|
||
child: ast.AST | t.CPtr = ch.get(ci)
|
||
if child is None:
|
||
continue
|
||
kd: int = child.kind()
|
||
if kd == ast.ASTKind.FunctionDef:
|
||
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child)
|
||
if fd is not None and fd.name is not None:
|
||
fd_body: list[ast.AST | t.CPtr] | t.CPtr = fd.children
|
||
fdoc: str = self._extract_docstring_from_body(fd_body)
|
||
if fdoc is not None:
|
||
self.register_docstring(module_sha1, fd.name, fdoc)
|
||
elif kd == ast.ASTKind.ClassDef:
|
||
cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child)
|
||
if cd is None or cd.name is None:
|
||
continue
|
||
cd_body0: list[ast.AST | t.CPtr] | t.CPtr = cd.children
|
||
cdoc: str = self._extract_docstring_from_body(cd_body0)
|
||
if cdoc is not None:
|
||
self.register_docstring(module_sha1, cd.name, cdoc)
|
||
# 类方法 docstring(key="{ClassName}.{method}")
|
||
cd_body: list[ast.AST | t.CPtr] | t.CPtr = cd.children
|
||
if cd_body is not None:
|
||
cbn: t.CSizeT = len(cd_body)
|
||
for mi in range(cbn):
|
||
m: ast.AST | t.CPtr = cd_body.get(mi)
|
||
if m is None or m.kind() != ast.ASTKind.FunctionDef:
|
||
continue
|
||
mfd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(m)
|
||
if mfd is None or mfd.name is None:
|
||
continue
|
||
mdoc: str = self._extract_docstring_from_body(mfd.children)
|
||
if mdoc is not None:
|
||
cl_nl: t.CSizeT = string.strlen(cd.name)
|
||
mt_nl: t.CSizeT = string.strlen(mfd.name)
|
||
sym_buf: bytes = stdlib.malloc(cl_nl + mt_nl + 2)
|
||
if sym_buf is not None:
|
||
viperlib.snprintf(sym_buf, cl_nl + mt_nl + 2, "%s.%s", cd.name, mfd.name)
|
||
self.register_docstring(module_sha1, sym_buf, mdoc)
|
||
stdlib.free(sym_buf)
|
||
def _resolve_doc_symbol_name(self, trans: HT.Translator | t.CPtr, name_id: str,
|
||
out_mod: str | t.CPtr, out_sym: str | t.CPtr) -> int:
|
||
"""解析 Name 符号的 docstring 归属,写入 out_mod/out_sym,成功返回 1
|
||
|
||
判定顺序:本地变量(函数变量)→ 结构体类(含跨模块预注册)→ 模块名。
|
||
"""
|
||
if trans is None or name_id is None or out_mod is None or out_sym is None:
|
||
return 0
|
||
if trans.ModuleSha1 is None:
|
||
return 0
|
||
# 1. 本地变量(函数变量/全局变量)
|
||
if self.Gen.VarGen.lookup_var(trans.SymTab, name_id) is not None:
|
||
string.strcpy(out_mod, trans.ModuleSha1)
|
||
string.strcpy(out_sym, name_id)
|
||
return 1
|
||
# 2. 结构体类(entry.ModuleSha1 区分跨模块预注册的类)
|
||
se: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(name_id)
|
||
if se is not None:
|
||
if se.ModuleSha1 is not None:
|
||
string.strcpy(out_mod, se.ModuleSha1)
|
||
else:
|
||
string.strcpy(out_mod, trans.ModuleSha1)
|
||
string.strcpy(out_sym, name_id)
|
||
return 1
|
||
# 3. 模块名(模块本身,少见);用 StubMerger 模块级函数(避免
|
||
# 跨 Mixin self 调用生成不存在符号)
|
||
mod_sha1: str = StubMergerStore.LookupSha1ByModName(name_id)
|
||
if mod_sha1 is None:
|
||
mod_sha1 = StubMergerStore.LookupSha1ByModNameSuffix(name_id)
|
||
if mod_sha1 is not None:
|
||
string.strcpy(out_mod, mod_sha1)
|
||
string.strcpy(out_sym, name_id)
|
||
return 1
|
||
# 4. 兜底当前模块
|
||
string.strcpy(out_mod, trans.ModuleSha1)
|
||
string.strcpy(out_sym, name_id)
|
||
return 1
|
||
def _resolve_doc_symbol_attr(self, trans: HT.Translator | t.CPtr,
|
||
at: ast.Attribute | t.CPtr,
|
||
out_mod: str | t.CPtr, out_sym: str | t.CPtr) -> int:
|
||
"""解析嵌套 Attribute 链的 docstring 归属,写入 out_mod/out_sym
|
||
|
||
支持形态:remote.remote_func / remote.RemoteClass /
|
||
remote.RemoteClass.remote_method / LocalClass.local_method 等。
|
||
最左 Name 判定:模块名 → 该模块 sha1;变量/类 → 类所属模块 sha1。
|
||
"""
|
||
if trans is None or at is None or out_mod is None or out_sym is None:
|
||
return 0
|
||
if trans.ModuleSha1 is None:
|
||
return 0
|
||
# 收集 Attribute 链(最外层 attr 在前)
|
||
DOC_CHAIN_MAX: t.CInt = 8
|
||
items: bytes = stdlib.malloc(DOC_CHAIN_MAX * 128)
|
||
if items is None:
|
||
return 0
|
||
n_items: int = 0
|
||
cur: ast.AST | t.CPtr = (ast.AST | t.CPtr)(at)
|
||
while cur is not None and cur.kind() == ast.ASTKind.Attribute and n_items < DOC_CHAIN_MAX:
|
||
cat: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cur)
|
||
if cat.attr is None:
|
||
break
|
||
string.strcpy(items + n_items * 128, cat.attr)
|
||
n_items += 1
|
||
cur = cat.value
|
||
# 最左应为 Name
|
||
head_id: str = None
|
||
if cur is not None and cur.kind() == ast.ASTKind.Name:
|
||
hnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cur)
|
||
head_id = hnm.id
|
||
if head_id is None:
|
||
stdlib.free(items)
|
||
return 0
|
||
# head 判定:模块名 or 变量/类
|
||
is_mod: int = 0
|
||
mod_sha1: str = None
|
||
if self.Gen.VarGen.lookup_var(trans.SymTab, head_id) is None:
|
||
mod_sha1 = StubMergerStore.LookupSha1ByModName(head_id)
|
||
if mod_sha1 is None:
|
||
mod_sha1 = StubMergerStore.LookupSha1ByModNameSuffix(head_id)
|
||
if mod_sha1 is not None:
|
||
is_mod = 1
|
||
if is_mod != 0:
|
||
# 模块限定:symbol = items 反转(不含 head_id)
|
||
if n_items == 0:
|
||
string.strcpy(out_mod, mod_sha1)
|
||
string.strcpy(out_sym, head_id)
|
||
stdlib.free(items)
|
||
return 1
|
||
total: t.CSizeT = 0
|
||
j: int
|
||
for j in range(n_items):
|
||
total += string.strlen(items + j * 128) + 1
|
||
sym_buf: bytes = stdlib.malloc(total + 1)
|
||
if sym_buf is None:
|
||
stdlib.free(items)
|
||
return 0
|
||
sym_buf[0] = '\0'
|
||
for j in range(n_items):
|
||
if j > 0:
|
||
string.strcat(sym_buf, ".")
|
||
string.strcat(sym_buf, items + (n_items - 1 - j) * 128)
|
||
string.strcpy(out_mod, mod_sha1)
|
||
string.strcpy(out_sym, sym_buf)
|
||
stdlib.free(sym_buf)
|
||
stdlib.free(items)
|
||
return 1
|
||
# 变量/类:symbol = head_id + '.' + items 反转
|
||
total2: t.CSizeT = string.strlen(head_id)
|
||
for j in range(n_items):
|
||
total2 += string.strlen(items + j * 128) + 1
|
||
sym2: bytes = stdlib.malloc(total2 + 1)
|
||
if sym2 is None:
|
||
stdlib.free(items)
|
||
return 0
|
||
sym2[0] = '\0'
|
||
string.strcat(sym2, head_id)
|
||
for j in range(n_items):
|
||
string.strcat(sym2, ".")
|
||
string.strcat(sym2, items + (n_items - 1 - j) * 128)
|
||
se2: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(head_id)
|
||
if se2 is not None and se2.ModuleSha1 is not None:
|
||
string.strcpy(out_mod, se2.ModuleSha1)
|
||
else:
|
||
string.strcpy(out_mod, trans.ModuleSha1)
|
||
string.strcpy(out_sym, sym2)
|
||
stdlib.free(sym2)
|
||
stdlib.free(items)
|
||
return 1
|
||
# ============================================================
|
||
# P3 迁移方法(来自 HandlesExprOps.vp:运算符重载 + 二元运算)
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
# infer_expr_class - 从表达式推断结构体类名(共享推断)
|
||
#
|
||
# 无注解赋值(HandlesAssign)与方法调用分派(CallGenMixin)共用:
|
||
# 联合类型 X|t.CPtr 简化为 Ptr(i8),不含类名,需按表达式结构推断:
|
||
# Call → 类实例化(func 为已注册结构体名);func 为 Attribute
|
||
# 时是方法调用,经 vpi 返回注解缓存解析返回类名
|
||
# Name → 源变量的 AnnotClassName
|
||
# BinOp/UnaryOp → lhs 类名 + 存在对应 dunder 方法(返回同类对象)
|
||
# Attribute → 字段注解类名(_resolve_attr_field_class)
|
||
# 仅采用已注册结构体;无法精确推断返回 None(fail-fast 由调用方暴露)。
|
||
# ============================================================
|
||
def infer_expr_class(self, pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
node: ast.AST | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> str:
|
||
"""从表达式推断结构体类名,无法推断返回 None"""
|
||
if node is None or trans is None:
|
||
return None
|
||
k: int = node.kind()
|
||
# Call: 类实例化 / 方法调用
|
||
if k == ast.ASTKind.Call:
|
||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
|
||
if cl is None or cl.func is None:
|
||
return None
|
||
if cl.func.kind() == ast.ASTKind.Name:
|
||
cand: str = ((ast.Name | t.CPtr)(cl.func)).id
|
||
if cand is None:
|
||
return None
|
||
if self.Gen.StructGen.find_struct(cand) is not None:
|
||
return cand
|
||
return None
|
||
if cl.func.kind() == ast.ASTKind.Attribute:
|
||
# 方法调用 a.cross(b):vpi 返回注解缓存精确解析返回类名
|
||
# (方法可返回非同类对象,如 Transform.world_position → 'Vec3')。
|
||
ca: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||
if ca is None or ca.attr is None or ca.value is None:
|
||
return None
|
||
obj_cls: str = self.infer_expr_class(pool, mod, ca.value, trans)
|
||
if obj_cls is None:
|
||
return None
|
||
if self._cls_has_dunder(pool, mod, obj_cls, ca.attr) == 0:
|
||
return None
|
||
cls_sha1: str = self.Gen.StructGen.get_struct_sha1(obj_cls)
|
||
if cls_sha1 is None and trans.ModuleSha1 is not None:
|
||
cls_sha1 = trans.ModuleSha1
|
||
ret_cls: str = None
|
||
if cls_sha1 is not None:
|
||
import lib.StubGen.VpiReader as VpiReader
|
||
temp_dir: str = None
|
||
# 跨子对象访问经 self.Gen 取 CallGenBase.TempDir(双向引用)
|
||
if self.Gen.CallGenBase.TempDir is not None:
|
||
temp_dir = self.Gen.CallGenBase.TempDir
|
||
if temp_dir is not None:
|
||
VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, temp_dir)
|
||
annot_ret: str = VpiReader._lookup_vpi_ret_annot(
|
||
cls_sha1, obj_cls, ca.attr)
|
||
if annot_ret is not None:
|
||
ret_cls = self._extract_annot_class_name(pool, annot_ret)
|
||
return ret_cls
|
||
return None
|
||
# Name: 源变量注解
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||
if nm is None or nm.id is None:
|
||
return None
|
||
ve: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry(
|
||
trans.SymTab, nm.id)
|
||
if ve is None:
|
||
return None
|
||
acn_n: str = ve.AnnotClassName
|
||
if acn_n is None:
|
||
return None
|
||
# 去模块前缀:json.JsonValue → JsonValue。AnnotClassName 可能带
|
||
# 模块限定(extract_class_name_from_annotation 的 Attribute 分支返回
|
||
# "memhub.MemBuddy" 形式),而 find_struct/_cls_has_dunder/
|
||
# get_struct_sha1 查找都用裸类名(struct 注册名)。泛型名
|
||
# (list[str] 含 '[')不截断(方括号内可能有点号)。
|
||
acn_dot_n: str = string.strrchr(acn_n, 46)
|
||
if acn_dot_n is not None and string.strchr(acn_n, 91) is None:
|
||
acn_n = acn_dot_n + 1
|
||
return acn_n
|
||
# BinOp/UnaryOp: 运算符重载返回同类对象
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||
if bop is None or bop.left is None:
|
||
return None
|
||
dunder: str = self.Gen.ExprGenOps._binop_to_dunder(bop.op)
|
||
if dunder is None:
|
||
return None
|
||
lhs_cls: str = self.infer_expr_class(pool, mod, bop.left, trans)
|
||
if lhs_cls is None or self._cls_has_dunder(pool, mod, lhs_cls, dunder) == 0:
|
||
return None
|
||
return lhs_cls
|
||
if k == ast.ASTKind.UnaryOp:
|
||
uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node)
|
||
if uop is None or uop.operand is None:
|
||
return None
|
||
dunder: str = self.Gen.ExprGenOps._unaryop_to_dunder(uop.op)
|
||
if dunder is None:
|
||
return None
|
||
opr_cls: str = self.infer_expr_class(pool, mod, uop.operand, trans)
|
||
if opr_cls is None or self._cls_has_dunder(pool, mod, opr_cls, dunder) == 0:
|
||
return None
|
||
return opr_cls
|
||
# Attribute: 字段注解类名(属性链递归,如 p = r.origin)
|
||
if k == ast.ASTKind.Attribute:
|
||
return self.Gen.ExprGenAttr._resolve_attr_field_class(pool, trans, node)
|
||
return None
|
||
# ============================================================
|
||
# _cls_has_dunder - 检查类(含继承链)是否存在 dunder/方法
|
||
#
|
||
# 与 try_operator_overload 的查找一致:当前模块内定义或跨模块类有
|
||
# SHA1(stub 中声明)即视为存在。仅在确实存在时采用推断类名,
|
||
# 避免把原生运算误标为类类型。
|
||
# ============================================================
|
||
def _cls_has_dunder(self, pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
class_name: str, dunder: str) -> int:
|
||
"""类及其 MRO 祖先链中是否存在 dunder 方法,存在返回 1"""
|
||
if class_name is None or dunder is None or mod is None:
|
||
return 0
|
||
lookup_name: str = pool.alloc(128)
|
||
if lookup_name is None:
|
||
return 0
|
||
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder)
|
||
if self.Gen.CallGenBase.find_func_in_module(mod, lookup_name) is not None:
|
||
return 1
|
||
# 继承链祖先查找
|
||
mro_ptr: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, class_name)
|
||
mi: int = 1
|
||
while mro_ptr is not None and mro_ptr[mi] != 0:
|
||
anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr))
|
||
if anc is not None:
|
||
anc_lookup: str = pool.alloc(128)
|
||
if anc_lookup is not None:
|
||
viperlib.snprintf(anc_lookup, 128, "%s.%s", anc, dunder)
|
||
if self.Gen.CallGenBase.find_func_in_module(mod, anc_lookup) is not None:
|
||
return 1
|
||
mi += 1
|
||
# 跨模块:类有 SHA1(stub 中声明该方法)视为存在
|
||
if self.Gen.StructGen.get_struct_sha1(class_name) is not None:
|
||
return 1
|
||
return 0
|
||
# ============================================================
|
||
# _extract_annot_class_name - 从返回注解文本提取结构体类名
|
||
#
|
||
# vpi 返回注解文本(如 "'Vec3' | CPtr")按 '|' 分段,每段去除
|
||
# 空格/引号后查结构体注册表:命中即类名(内置类型 str/int/
|
||
# CFloat64T/t.CPtr 等均不注册 struct,天然过滤)。"A | B" 联合
|
||
# 多候选时取首个命中段。
|
||
# ============================================================
|
||
def _extract_annot_class_name(self, pool: memhub.MemBuddy | t.CPtr,
|
||
annot: str) -> str:
|
||
"""从返回注解文本提取已注册结构体类名,无命中返回 None"""
|
||
if pool is None or annot is None:
|
||
return None
|
||
alen: t.CSizeT = string.strlen(annot)
|
||
if alen == 0:
|
||
return None
|
||
seg: str = pool.alloc(256)
|
||
if seg is None:
|
||
return None
|
||
start: t.CSizeT = 0
|
||
i: t.CSizeT
|
||
for i in range(alen):
|
||
if annot[i] == '|':
|
||
s: t.CSizeT = start
|
||
e: t.CSizeT = i
|
||
while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'):
|
||
s += 1
|
||
while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'):
|
||
e -= 1
|
||
seglen: t.CSizeT = e - s
|
||
if seglen > 0 and seglen < 256:
|
||
string.strncpy(seg, annot + s, seglen)
|
||
seg[seglen] = '\0'
|
||
if self.Gen.StructGen.find_struct(seg) is not None:
|
||
return seg
|
||
start = i + 1
|
||
# 最后一段(无 '|' 后缀)
|
||
s: t.CSizeT = start
|
||
e: t.CSizeT = alen
|
||
while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'):
|
||
s += 1
|
||
while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'):
|
||
e -= 1
|
||
seglen: t.CSizeT = e - s
|
||
if seglen > 0 and seglen < 256:
|
||
string.strncpy(seg, annot + s, seglen)
|
||
seg[seglen] = '\0'
|
||
if self.Gen.StructGen.find_struct(seg) is not None:
|
||
return seg
|
||
return None |