唯一规范形 T*(rawptr[T] ≡ t.CPtr[T] ≡ T|t.CPtr,见 83baf5a/2b2b70e)落地后,
所有"读**已归一实参文本**或**结构体名**并做文本解析/嗅探"的点都必须接受 T* 形,
否则会**静默**走错分支(不是报错,更难发现):
- VpiReader._resolve_single_vpi_type_str:尾随 * 段按层重写回 rawptr[...] 文本形
再走原分支(与既有 rawptr[ 分支逐字等价)。必须补的原因:_subst_template_arg
用特化类名 [...] 内的**已归一实参**替换模板注解里的 T,喂进来的就是 {sha}.AST*;
旧代码只认 rawptr[ / t.CPtr[ / 裸 t.CPtr ⇒ 落到 strrchr('.') 取末段 "AST*"、
查 struct miss ⇒ 返回 None/i8*,跨模块参数/返回宽度被悄悄收窄。
- ExprGenCls / AssignGenMixin 的 _extract_annot_class_name(各 2 处):段尾剔除集
补 '*',剥后再 find_struct(旧形态 {sha}.AST|t.CPtr 按 '|' 分段能命中,新形态
不剥则 miss ⇒ 返回 None ⇒ 链式 .get(0).kind() 分派退化)。
- CallGenCtor._infer_generic_ctor_type_arg:新增 _ptr_layer_type_arg —— 先经
_norm_type_arg_name 归一(保证类名带定义模块 SHA1,否则裸 "AST*" 无法再归一、
反而新分裂),再按 VarEntry/FieldEntry 的 Spec.PtrLevel 补 '*',使构造侧推出的
类型实参与注解侧同票名(否则 Box(x) 这类隐式特化分裂成两个结构体)。
- CallGenDispatch.__sizeof__:'*' 判据由 strrchr 改为**尾随**判定 —— 原写法会把
list[{sha}.AST*](元素为指针的容器)误判成指针并返回 8。
现场:Test/AstTest/App/main.vp:21 的 list[ast.AST | t.CPtr] | t.CPtr 特化链
(→ includes/_list.vp:36 T.__sizeof__())。
461 lines
25 KiB
Plaintext
461 lines
25 KiB
Plaintext
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdlib
|
||
import viperlib
|
||
import lib.core.CompilerFactory as CompilerFactory
|
||
import lib.core.Gen.Translator as HT
|
||
import lib.Stub.StubGen.VpiReader as VpiReader
|
||
|
||
import lib.core.Gen.GenTypes as GenTypes
|
||
import lib.core.Gen.Expr.ExprGenBase as ExprGenBase
|
||
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
|
||
|
||
|
||
# ============================================================
|
||
# docstring 登记表容量常量(与 ExprGenMixin 保持一致,存疑
|
||
# ============================================================
|
||
define DOC_MAX = 512
|
||
define DOC_KEY_SZ = 192
|
||
define DOC_VAL_SZ = 4096
|
||
|
||
|
||
# ============================================================
|
||
# ExprGenCls - ExprGenMixin 拆分(阶段 D):类名推断/docstring 登记
|
||
# ============================================================
|
||
novirtual 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*]*) -> str:
|
||
"""从函数/类体提取 docstring:body[0] 为 Expr(Constant str) 时返回内容"""
|
||
if body is None or len(body) == 0: return None
|
||
first: ast.AST* = body.get(0)
|
||
if first is None or first.kind() != ast.ASTKind.Expr: return None
|
||
ex: rawptr[ast.Expr] = rawptr[ast.Expr](first)
|
||
if ex is None or ex.value is None or ex.value.kind() != ast.ASTKind.Constant: return None
|
||
cn: ast.Constant* = ast.Constant*(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.factory.PermPool.alloc(DOC_MAX * DOC_KEY_SZ)
|
||
self.DocValues = CompilerFactory.factory.PermPool.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: sizet = string.strlen(module_sha1)
|
||
sl: sizet = 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)
|
||
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: sizet = string.strlen(module_sha1)
|
||
sl: sizet = 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)
|
||
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*, module_sha1: str) -> None:
|
||
"""扫描模块 AST:登记模块级函数/类/方法的 docstring(幂等)"""
|
||
if tree is None or module_sha1 is None: return
|
||
ch: list[ast.AST*]* = tree.children
|
||
if ch is None: return
|
||
cn: sizet = len(ch)
|
||
for ci in range(cn):
|
||
child: ast.AST* = ch.get(ci)
|
||
if child is None: continue
|
||
kd: int = child.kind()
|
||
if kd == ast.ASTKind.FunctionDef:
|
||
fd: ast.FunctionDef* = ast.FunctionDef*(child)
|
||
if fd is not None and fd.name is not None:
|
||
fd_body: list[ast.AST*]* = 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* = ast.ClassDef*(child)
|
||
if cd is None or cd.name is None: continue
|
||
cd_body0: list[ast.AST*]* = 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*]* = cd.children
|
||
if cd_body is not None:
|
||
cbn: sizet = len(cd_body)
|
||
for mi in range(cbn):
|
||
m: ast.AST* = cd_body.get(mi)
|
||
if m is None or m.kind() != ast.ASTKind.FunctionDef: continue
|
||
mfd: ast.FunctionDef* = ast.FunctionDef*(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: sizet = string.strlen(cd.name)
|
||
mt_nl: sizet = 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*, name_id: str,
|
||
out_mod: str, out_sym: str) -> 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* = 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*,
|
||
at: ast.Attribute*,
|
||
out_mod: str, out_sym: str) -> 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: int = 8
|
||
items: bytes = stdlib.malloc(DOC_CHAIN_MAX * 128)
|
||
if items is None: return 0
|
||
n_items: int = 0
|
||
cur: ast.AST* = (ast.AST*)(at)
|
||
while cur is not None and cur.kind() == ast.ASTKind.Attribute and n_items < DOC_CHAIN_MAX:
|
||
cat: ast.Attribute* = ast.Attribute*(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* = ast.Name*(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: sizet = 0
|
||
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: sizet = 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* = 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*,
|
||
mod: llvmlite.LLVMModule*,
|
||
node: ast.AST*,
|
||
trans: HT.Translator*) -> 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* = ast.Call*(node)
|
||
if cl is None or cl.func is None: return None
|
||
if cl.func.kind() == ast.ASTKind.Name:
|
||
cand: str = (ast.Name*(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* = ast.Attribute*(cl.func)
|
||
if ca is None or ca.attr is None or ca.value is None: return None
|
||
# 模块级函数调用(Module.func()):接收者是已导入模块名而非类对象
|
||
if ca.value.kind() == ast.ASTKind.Name:
|
||
mod_nm2: str = (ast.Name*(ca.value)).id
|
||
if mod_nm2 is not None and trans._from_imports is not None:
|
||
mod_sha1_2: str = self.Gen.CallGenBase._lookup_mod_sha1(
|
||
pool, trans._from_imports, mod_nm2)
|
||
if mod_sha1_2 is not None:
|
||
temp_dir2: str = None
|
||
if self.Gen.CallGenBase.TempDir is not None:
|
||
temp_dir2 = self.Gen.CallGenBase.TempDir
|
||
if temp_dir2 is not None:
|
||
VpiReader._ensure_vpi_ret_annot_loaded(mod_sha1_2, temp_dir2)
|
||
annot_ret2: str = VpiReader._lookup_vpi_ret_annot(
|
||
mod_sha1_2, None, ca.attr)
|
||
if annot_ret2 is not None:
|
||
ret_cls2: str = self._extract_annot_class_name(pool, annot_ret2)
|
||
if ret_cls2 is not None:
|
||
return ret_cls2
|
||
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:
|
||
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* = ast.Name*(node)
|
||
if nm is None or nm.id is None: return None
|
||
ve: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id)
|
||
if ve is None: return None
|
||
acn_n: str = self.Gen.VarGen.var_annot_class_name(ve)
|
||
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* = ast.BinOp*(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* = ast.UnaryOp*(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*, mod: llvmlite.LLVMModule*, 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: sizet* = 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 = rawptr(mro_ptr[mi])
|
||
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*, annot: str) -> str:
|
||
"""从返回注解文本提取已注册结构体类名,无命中返回 None"""
|
||
if pool is None or annot is None: return None
|
||
alen: sizet = string.strlen(annot)
|
||
if alen == 0: return None
|
||
seg: str = pool.alloc(256)
|
||
if seg is None: return None
|
||
start: sizet = 0
|
||
i: sizet
|
||
for i in range(alen):
|
||
if annot[i] == '|':
|
||
s: sizet = start
|
||
e: sizet = i
|
||
while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'):
|
||
s += 1
|
||
# 段尾另需剥 '*':实参归一后段文本是 `{sha}.AST*`(旧形态
|
||
# `{sha}.AST | t.CPtr` 按 '|' 分段能落到 `{sha}.AST` 命中),与
|
||
# ExprGenName._list_elem_obj_ty_from_struct_name 的尾剔除同口径;
|
||
# 不剥则 find_struct 落空 → 返回 None → 链式 .get(0).kind() 分派退化。
|
||
while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"' or annot[e - 1] == '*'):
|
||
e -= 1
|
||
seglen: sizet = 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
|
||
# 模块前缀(memhub.MemBuddy → MemBuddy):find_struct 未命中
|
||
# 时去最后一个 '.' 前的模块名再试(vpi 返回注解常带模块限定)
|
||
seg_dot2: str = string.strrchr(seg, 46)
|
||
if seg_dot2 is not None and seg_dot2 != seg:
|
||
seg_bare2: str = seg_dot2 + 1
|
||
if self.Gen.StructGen.find_struct(seg_bare2) is not None:
|
||
return seg_bare2
|
||
start = i + 1
|
||
# 最后一段(无 '|' 后缀)
|
||
s: sizet = start
|
||
e: sizet = alen
|
||
while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'):
|
||
s += 1
|
||
# 段尾另需剥 '*':实参归一后段文本是 `{sha}.AST*`(旧形态
|
||
# `{sha}.AST | t.CPtr` 按 '|' 分段能落到 `{sha}.AST` 命中),与
|
||
# ExprGenName._list_elem_obj_ty_from_struct_name 的尾剔除同口径;
|
||
# 不剥则 find_struct 落空 → 返回 None → 链式 .get(0).kind() 分派退化。
|
||
while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"' or annot[e - 1] == '*'):
|
||
e -= 1
|
||
seglen: sizet = 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
|
||
# 模块前缀(memhub.MemBuddy → MemBuddy):find_struct 未命中时
|
||
# 去最后一个 '.' 前的模块名再试(vpi 返回注解常带模块限定)
|
||
seg_dot3: str = string.strrchr(seg, 46)
|
||
if seg_dot3 is not None and seg_dot3 != seg:
|
||
seg_bare3: str = seg_dot3 + 1
|
||
if self.Gen.StructGen.find_struct(seg_bare3) is not None:
|
||
return seg_bare3
|
||
return None |