- StubMergerStore 新增共享导入上下文记账(AppendImportedModule / AppendFromImport / ImportCtx / AllocImportCtx / NotePlainImport),ImportsGenMixin 与 VpiReader 共用同一份 口径;顺带移除 add_from_import 的 256 缓冲静默截断,VpiReader 删除两份私有副本 - 注入窗口按「名字归属」判据解析(is_module_class + CurDefModuleSha1): _forward_declare_ptr_from_node 的 Name 分支、resolve_annotation_type 的 Name/Attribute 分支均补齐,使同一 stub 内先声明/先引用的类产出**具名占位**而不是 Ptr(i8),并新增 _is_tattr_marker 让 t.attr.* 属性标记不参与类型联合竞争 - VpiReader._inject_class_struct_declare:命中前向声明占位时不再早退,改为「占位 Ty 原地写入」(对齐 ClassGenDef.fill_fwd),修 StructTable 爆表(table full, cannot register Translator) - 清除全部一次性探针:[DBG-GEN](VpiReader / StructGenMixin / ClassGenDef)、 [DBG-ATTR](ExprGenAttr)、[MODSHA1](CallGenMixin) 根因记录:vpi 注入期漏记 `import X as Y -> from_imports "Y:X"`,使 GenTypes.VarEntry.Spec (TSpec.TypeSpec | t.CPtr)取不到模块 SHA1、退化为 i8* 并被永久冻结 (CallGenCtor.vp:897 .PtrLevel 属性访问失败)。
789 lines
41 KiB
Plaintext
789 lines
41 KiB
Plaintext
import t, c
|
||
from stdint import *
|
||
import memhub
|
||
import string
|
||
import stdlib
|
||
import llvmlite
|
||
import w32.win32file as win32file
|
||
import w32.win32base as win32base
|
||
import w32.fileio as fileio
|
||
import viperlib
|
||
import sys
|
||
import ast
|
||
import lib.core.VLogger as VLogger
|
||
import lib.core.IncludesScanner as IncludesScanner
|
||
import lib.core.Gen.Translator as HandlesTranslator
|
||
import lib.Phase.BuildPipeline as BuildPipeline
|
||
import lib.Stub.StubGen.VpiReader as VpiReader
|
||
import lib.Projectrans.Utils as Utils
|
||
import lib.Projectrans.Config as Config
|
||
|
||
import lib.Stub.StubMerger.StubMergerCollect as StubMergerCollect
|
||
import lib.Stub.StubMerger.StubMergerTopo as StubMergerTopo
|
||
import lib.Stub.StubMerger.StubMergerIR as StubMergerIR
|
||
import lib.Stub.StubMerger.StubMergerBuild as StubMergerBuild
|
||
import lib.Stub.StubMerger as StubMerger
|
||
|
||
|
||
# ============================================================
|
||
# StubMergerStore - 全局 SHA1 映射存储器(sha1→模块名/相对路径)读写
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
# 导入上下文记账(单一真源)
|
||
#
|
||
# 「AST 导入语句 → imported_modules / from_imports」的记账口径必须唯一。
|
||
# 翻译期(ImportsGenMixin.translate_import)与 vpi 注入期(VpiReader 顶层
|
||
# 遍历)此前各写一份:注入期漏掉 `import X as Y → from_imports "Y:X"`(别名
|
||
# 反查模块真名的唯一入口,见 LookupModNameByAlias)以及 `import a.b.c →
|
||
# imported_modules "a"`(顶层包名放行 is_module_imported)。前者使注解里的
|
||
# `TSpec.TypeSpec*` 在 _forward_declare_ptr_from_node 4a'/4b 全落空 → 退化
|
||
# 为 Ptr(i8)(现场:GenTypes.VarEntry.Spec.PtrLevel 属性访问失败);后者使
|
||
# 包限定解析在 stub 上下文里被误判"未导入"。
|
||
#
|
||
# 现统一到本模块,两侧只保留各自的特有副作用(SHA1 校验 / reexport 注册 /
|
||
# add_visible_struct),字符串记账一律走下面这组函数。ImportCtx 只承载两个
|
||
# 上下文串(Viper 无多返回值,用 pool 分配的小 struct 传出)。
|
||
# ============================================================
|
||
|
||
class ImportCtx:
|
||
"""导入上下文容器:两个空格分隔串(ImportedModules / FromImports)"""
|
||
ImportedModules: str
|
||
FromImports: str
|
||
|
||
|
||
# ============================================================
|
||
# AppendImportedModule - 追加模块名到空格分隔列表(纯记账,无索引副作用)
|
||
# ============================================================
|
||
def AppendImportedModule(pool: memhub.MemBuddy*, cur: str, name: str) -> str:
|
||
"""追加模块名到空格分隔列表(pool 分配),返回新列表"""
|
||
if name is None:
|
||
return cur
|
||
if cur is None:
|
||
nlen: sizet = string.strlen(name)
|
||
buf: str = pool.alloc(nlen + 1)
|
||
if buf is not None:
|
||
string.strcpy(buf, name)
|
||
return buf
|
||
old_len: sizet = string.strlen(cur)
|
||
name_len: sizet = string.strlen(name)
|
||
buf2: str = pool.alloc(old_len + 1 + name_len + 1)
|
||
if buf2 is not None:
|
||
string.strcpy(buf2, cur)
|
||
buf2[old_len] = ' '
|
||
string.strcpy(buf2 + old_len + 1, name)
|
||
return buf2
|
||
|
||
|
||
# ============================================================
|
||
# AppendFromImport - 追加 from-import 映射("local:mod[:orig]" 空格分隔)
|
||
#
|
||
# [D7·截断纪律] 旧实现固定 256 缓冲 + snprintf:三者合计超长即被静默截断,
|
||
# 该条目在查找侧仍被当作合法条目解析出错误的 local/mod/orig ⇒ 跨模块类名/
|
||
# 别名还原取到错名字(污染 Spec.SourceName)。此处按精确长度分配,无上限。
|
||
# ============================================================
|
||
def AppendFromImport(pool: memhub.MemBuddy*, cur: str,
|
||
local: str, mod: str, orig: str) -> str:
|
||
"""追加 from-import 映射(pool 分配),返回新列表"""
|
||
if local is None or mod is None:
|
||
return cur
|
||
llen: sizet = string.strlen(local)
|
||
mlen: sizet = string.strlen(mod)
|
||
use_orig: int = 0
|
||
olen: sizet = 0
|
||
if orig is not None and string.strcmp(orig, local) != 0:
|
||
use_orig = 1
|
||
olen = string.strlen(orig)
|
||
# local ':' mod [':' orig] '\0'
|
||
need: sizet = llen + 1 + mlen + 1
|
||
if use_orig != 0:
|
||
need += 1 + olen
|
||
entry: str = pool.alloc(need)
|
||
if entry is None:
|
||
return cur
|
||
string.strcpy(entry, local)
|
||
entry[llen] = ':'
|
||
string.strcpy(entry + llen + 1, mod)
|
||
if use_orig != 0:
|
||
entry[llen + 1 + mlen] = ':'
|
||
string.strcpy(entry + llen + 1 + mlen + 1, orig)
|
||
if cur is None:
|
||
return entry
|
||
old_len: sizet = string.strlen(cur)
|
||
entry_len: sizet = string.strlen(entry)
|
||
buf: str = pool.alloc(old_len + 1 + entry_len + 1)
|
||
if buf is not None:
|
||
string.strcpy(buf, cur)
|
||
buf[old_len] = ' '
|
||
string.strcpy(buf + old_len + 1, entry)
|
||
return buf
|
||
|
||
|
||
# ============================================================
|
||
# AllocImportCtx - 用两个既有上下文串构造记账容器
|
||
# ============================================================
|
||
def AllocImportCtx(pool: memhub.MemBuddy*,
|
||
imported_modules: str, from_imports: str) -> ImportCtx*:
|
||
"""构造导入上下文容器(pool 分配);两串可为 None"""
|
||
ctx: ImportCtx* = pool.alloc(ImportCtx.__sizeof__())
|
||
if ctx is None:
|
||
return None
|
||
ctx.ImportedModules = imported_modules
|
||
ctx.FromImports = from_imports
|
||
return ctx
|
||
|
||
|
||
# ============================================================
|
||
# NotePlainImport - 记账 `import X` / `import X as Y`(就地更新 ctx)
|
||
#
|
||
# 有别名:追加别名 `Y`,并写 from-import 映射 "Y:X"——这就是 `LookupModNameByAlias`
|
||
# 与 `_forward_declare_ptr_from_node` 4a' 反查模块真名的唯一来源,绝不可省。
|
||
# 无别名:`import a.b.c` 时把顶层包名 `a` 也追加(使 a.b.c 作为属性访问 base
|
||
# 时 is_module_imported("a") 放行)。
|
||
# ============================================================
|
||
def NotePlainImport(pool: memhub.MemBuddy*, ctx: ImportCtx*,
|
||
name: str, asname: str) -> int:
|
||
"""记账单条 import(就地更新 ctx),返回 0"""
|
||
if ctx is None or name is None:
|
||
return 1
|
||
ctx.ImportedModules = AppendImportedModule(pool, ctx.ImportedModules, name)
|
||
if asname is not None:
|
||
ctx.ImportedModules = AppendImportedModule(pool, ctx.ImportedModules, asname)
|
||
ctx.FromImports = AppendFromImport(pool, ctx.FromImports, asname, name, None)
|
||
else:
|
||
dot_ptr: str = string.strstr(name, ".")
|
||
if dot_ptr is not None:
|
||
pkg_len: sizet = sizet(uint64(dot_ptr) - uint64(name))
|
||
if pkg_len > 0 and pkg_len < 256:
|
||
pkg_buf: str = pool.alloc(pkg_len + 1)
|
||
if pkg_buf is not None:
|
||
string.strncpy(pkg_buf, name, pkg_len)
|
||
pkg_buf[pkg_len] = '\0'
|
||
ctx.ImportedModules = AppendImportedModule(
|
||
pool, ctx.ImportedModules, pkg_buf)
|
||
return 0
|
||
|
||
|
||
# ============================================================
|
||
# PopulateSha1MapStore - 遍历 ScanResult.Entries 构建 sha1→module_name 映射,填充全局存储器
|
||
#
|
||
# 模块名通过 _PathToModuleName(includes/rel_path) 计算;内存用 stdlib.malloc 分配(全局存储器,不随 mbuddy 释放)。
|
||
# Args: scan_result IncludesScanner 扫描结果
|
||
# Returns: 填充的条目数,-1 表示失败
|
||
# ============================================================
|
||
def PopulateSha1MapStore(scan_result: rawptr[IncludesScanner.ScanResult]) -> int:
|
||
"""从扫描结果填充全局 SHA1 映射存储器
|
||
|
||
遍历 ScanResult.Entries,为每个条目构建 sha1→module_name 映射。
|
||
模块名通过 _PathToModuleName(includes/rel_path) 计算。
|
||
内存用 stdlib.malloc 分配(全局存储器,不随 mbuddy 释放)。
|
||
"""
|
||
if scan_result is None:
|
||
return -1
|
||
# 释放旧存储器
|
||
if StubMerger._sha1_store_arr is not None:
|
||
stdlib.free(StubMerger._sha1_store_arr)
|
||
if StubMerger._sha1_store_mod is not None:
|
||
stdlib.free(StubMerger._sha1_store_mod)
|
||
if StubMerger._sha1_store_rel is not None:
|
||
stdlib.free(StubMerger._sha1_store_rel)
|
||
if StubMerger._sha1_store_incdir is not None:
|
||
stdlib.free(StubMerger._sha1_store_incdir)
|
||
StubMerger._sha1_store_arr = stdlib.malloc(StubMerger.MAX_INCLUDES * 17)
|
||
StubMerger._sha1_store_mod = stdlib.malloc(StubMerger.MAX_INCLUDES * 64)
|
||
StubMerger._sha1_store_rel = stdlib.malloc(StubMerger.MAX_INCLUDES * StubMerger.MAX_REL_PATH_LEN)
|
||
StubMerger._sha1_store_incdir = stdlib.malloc(StubMerger.MAX_INCLUDES * StubMerger.MAX_INC_DIR_LEN)
|
||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None or StubMerger._sha1_store_rel is None or StubMerger._sha1_store_incdir is None:
|
||
return -1
|
||
string.memset(StubMerger._sha1_store_arr, 0, StubMerger.MAX_INCLUDES * 17)
|
||
string.memset(StubMerger._sha1_store_mod, 0, StubMerger.MAX_INCLUDES * 64)
|
||
string.memset(StubMerger._sha1_store_rel, 0, StubMerger.MAX_INCLUDES * StubMerger.MAX_REL_PATH_LEN)
|
||
string.memset(StubMerger._sha1_store_incdir, 0, StubMerger.MAX_INCLUDES * StubMerger.MAX_INC_DIR_LEN)
|
||
StubMerger._sha1_store_count = 0
|
||
p_bad: int = 0
|
||
entry_size_p: sizet = IncludesScanner.FileEntry.__sizeof__()
|
||
for i in range(scan_result.Count):
|
||
if StubMerger._sha1_store_count >= StubMerger.MAX_INCLUDES:
|
||
VLogger.error("includes SHA1 存储超上限,终止", "StubMerger")
|
||
ea: uint64 = uint64(scan_result.Entries) + i * entry_size_p
|
||
ent: rawptr[IncludesScanner.FileEntry] = rawptr[IncludesScanner.FileEntry](ea)
|
||
if ent is None or ent.Sha1 is None or ent.RelPath is None:
|
||
p_bad += 1
|
||
continue
|
||
# 构建完整路径 includes/{RelPath}(_PathToModuleName 需要)
|
||
rp_len: sizet = string.strlen(ent.RelPath)
|
||
full_path_buf: bytes = stdlib.malloc(rp_len + 10)
|
||
if full_path_buf is None:
|
||
p_bad += 1
|
||
continue
|
||
viperlib.snprintf(full_path_buf, rp_len + 10, "includes/%s", ent.RelPath)
|
||
mod_name: str = Utils.PathToModuleName(full_path_buf, 1)
|
||
stdlib.free(full_path_buf)
|
||
if mod_name is not None:
|
||
idx: sizet = sizet(StubMerger._sha1_store_count) * 17
|
||
string.strcpy(StubMerger._sha1_store_arr + idx, ent.Sha1)
|
||
idx2: sizet = sizet(StubMerger._sha1_store_count) * 64
|
||
mn_len: sizet = string.strlen(mod_name)
|
||
if mn_len < 64:
|
||
string.strcpy(StubMerger._sha1_store_mod + idx2, mod_name)
|
||
else:
|
||
string.strncpy(StubMerger._sha1_store_mod + idx2, mod_name, 63)
|
||
StubMerger._sha1_store_mod[idx2 + 63] = '\0'
|
||
stdlib.free(mod_name)
|
||
# 保存 rel_path(供 Phase2 3.5 编译缺失 includes 使用)
|
||
idx3: sizet = sizet(StubMerger._sha1_store_count) * StubMerger.MAX_REL_PATH_LEN
|
||
if rp_len < StubMerger.MAX_REL_PATH_LEN:
|
||
string.strcpy(StubMerger._sha1_store_rel + idx3, ent.RelPath)
|
||
else:
|
||
string.strncpy(StubMerger._sha1_store_rel + idx3, ent.RelPath, StubMerger.MAX_REL_PATH_LEN - 1)
|
||
StubMerger._sha1_store_rel[idx3 + StubMerger.MAX_REL_PATH_LEN - 1] = '\0'
|
||
# 保存所属 includes 根目录(Phase2 预注册/按需编译拼路径用)
|
||
idx_inc: sizet = sizet(StubMerger._sha1_store_count) * StubMerger.MAX_INC_DIR_LEN
|
||
if ent.IncDir is not None:
|
||
icd_len: sizet = string.strlen(ent.IncDir)
|
||
if icd_len < StubMerger.MAX_INC_DIR_LEN:
|
||
string.strcpy(StubMerger._sha1_store_incdir + idx_inc, ent.IncDir)
|
||
else:
|
||
string.strncpy(StubMerger._sha1_store_incdir + idx_inc, ent.IncDir, StubMerger.MAX_INC_DIR_LEN - 1)
|
||
StubMerger._sha1_store_incdir[idx_inc + StubMerger.MAX_INC_DIR_LEN - 1] = '\0'
|
||
StubMerger._sha1_store_count += 1
|
||
if p_bad > 0:
|
||
VLogger.error(f"includes SHA1 存储有 {p_bad} 个条目失败", "StubMerger")
|
||
return StubMerger._sha1_store_count
|
||
# ============================================================
|
||
# AppendToSha1MapStore - 追加 App 模块条目到全局 SHA1 映射存储器(Phase1 先用 PopulateSha1MapStore 填 includes,
|
||
# Phase2 扫描 App 源文件后调用本函数追加,否则编译 App 自身时跨模块 CDefine 查找命中不到 App 模块)
|
||
#
|
||
# 存储器未初始化时自动初始化;SHA1 已存在(去重)则跳过。
|
||
# Args: sha1 SHA1 字符串(16 字符 + null);rel_path 相对路径(如 "lib/core/StubMerger.vp",不含 includes/ 前缀,与 _sha1_map.txt 格式一致)
|
||
# Returns: 0 成功(含去重跳过),1 失败
|
||
# ============================================================
|
||
def AppendToSha1MapStore(sha1: str, rel_path: str) -> int:
|
||
"""追加条目到全局 SHA1 映射存储器(Phase2 用)"""
|
||
if sha1 is None or rel_path is None:
|
||
return 1
|
||
# 存储器未初始化:自动初始化(Phase2 可能先于 Phase1 调用)
|
||
if StubMerger._sha1_store_arr is None:
|
||
StubMerger._sha1_store_arr = stdlib.malloc(StubMerger.MAX_INCLUDES * 17)
|
||
StubMerger._sha1_store_mod = stdlib.malloc(StubMerger.MAX_INCLUDES * 64)
|
||
StubMerger._sha1_store_rel = stdlib.malloc(StubMerger.MAX_INCLUDES * StubMerger.MAX_REL_PATH_LEN)
|
||
StubMerger._sha1_store_incdir = stdlib.malloc(StubMerger.MAX_INCLUDES * StubMerger.MAX_INC_DIR_LEN)
|
||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None or StubMerger._sha1_store_rel is None or StubMerger._sha1_store_incdir is None:
|
||
return 1
|
||
string.memset(StubMerger._sha1_store_arr, 0, StubMerger.MAX_INCLUDES * 17)
|
||
string.memset(StubMerger._sha1_store_mod, 0, StubMerger.MAX_INCLUDES * 64)
|
||
string.memset(StubMerger._sha1_store_rel, 0, StubMerger.MAX_INCLUDES * StubMerger.MAX_REL_PATH_LEN)
|
||
string.memset(StubMerger._sha1_store_incdir, 0, StubMerger.MAX_INCLUDES * StubMerger.MAX_INC_DIR_LEN)
|
||
StubMerger._sha1_store_count = 0
|
||
if StubMerger._sha1_store_count >= StubMerger.MAX_INCLUDES:
|
||
return 1
|
||
# 模块名:rel_path "lib/core/StubMerger.vp" → "lib.core.StubMerger"
|
||
full_path_buf: bytes = stdlib.malloc(string.strlen(rel_path) + 10)
|
||
if full_path_buf is None:
|
||
return 1
|
||
viperlib.snprintf(full_path_buf, string.strlen(rel_path) + 10, "includes/%s", rel_path)
|
||
mod_name: str = Utils.PathToModuleName(full_path_buf, 1)
|
||
stdlib.free(full_path_buf)
|
||
if mod_name is None:
|
||
return 1
|
||
# 去重:SHA1 与模块名都相同才跳过——同一 SHA1 可能先以全路径模块名注册(App 源文件在 includes 目录下),
|
||
# App 追加的短模块名必须保留,否则 import 该模块的精确查找失败、后缀匹配会劫持到其它同名模块。
|
||
for i in range(StubMerger._sha1_store_count):
|
||
sidx_d: sizet = sizet(i) * 17
|
||
if string.strcmp(StubMerger._sha1_store_arr + sidx_d, sha1) == 0:
|
||
midx_d: sizet = sizet(i) * 64
|
||
if string.strcmp(StubMerger._sha1_store_mod + midx_d, mod_name) == 0:
|
||
stdlib.free(mod_name)
|
||
return 0
|
||
# 写入 SHA1
|
||
idx_a: sizet = sizet(StubMerger._sha1_store_count) * 17
|
||
string.strcpy(StubMerger._sha1_store_arr + idx_a, sha1)
|
||
# 写入模块名
|
||
idx_m: sizet = sizet(StubMerger._sha1_store_count) * 64
|
||
mn_len: sizet = string.strlen(mod_name)
|
||
if mn_len < 64:
|
||
string.strcpy(StubMerger._sha1_store_mod + idx_m, mod_name)
|
||
else:
|
||
string.strncpy(StubMerger._sha1_store_mod + idx_m, mod_name, 63)
|
||
StubMerger._sha1_store_mod[idx_m + 63] = '\0'
|
||
stdlib.free(mod_name)
|
||
# 写入相对路径
|
||
idx_r: sizet = sizet(StubMerger._sha1_store_count) * StubMerger.MAX_REL_PATH_LEN
|
||
rp_len: sizet = string.strlen(rel_path)
|
||
if rp_len < StubMerger.MAX_REL_PATH_LEN:
|
||
string.strcpy(StubMerger._sha1_store_rel + idx_r, rel_path)
|
||
else:
|
||
string.strncpy(StubMerger._sha1_store_rel + idx_r, rel_path, StubMerger.MAX_REL_PATH_LEN - 1)
|
||
StubMerger._sha1_store_rel[idx_r + StubMerger.MAX_REL_PATH_LEN - 1] = '\0'
|
||
# App 源文件不属于任何 includes 目录:IncDir 留空(Phase2 回退 includes_dir 参数)
|
||
idx_inc_a: sizet = sizet(StubMerger._sha1_store_count) * StubMerger.MAX_INC_DIR_LEN
|
||
StubMerger._sha1_store_incdir[idx_inc_a] = '\0'
|
||
StubMerger._sha1_store_count += 1
|
||
return 0
|
||
# ============================================================
|
||
# AddIncludeToSha1MapStore - 单条登记 includes 条目到全局 SHA1 映射存储器
|
||
#
|
||
# 依赖图按需扫描(_BuildReachableSha1Set)解析到可达 includes 文件后逐条登记,未引用的 includes 不进 store;
|
||
# App 源文件仍用 AppendToSha1MapStore(inc_dir 留空)。
|
||
# Args: sha1 SHA1 字符串(16 字符 + null);rel_path 相对 includes 根目录的路径(如 "ast/parser.vp");inc_dir 所属 includes 根目录;mod_name 模块名(如 "ast.parser")
|
||
# Returns: 0 成功(含去重跳过),1 失败
|
||
# ============================================================
|
||
def AddIncludeToSha1MapStore(sha1: str, rel_path: str, inc_dir: str, mod_name: str) -> int:
|
||
"""单条登记 includes 条目到全局 SHA1 映射存储器(依赖图按需扫描用)"""
|
||
if sha1 is None or rel_path is None or mod_name is None:
|
||
return 1
|
||
# 存储器未初始化:自动初始化
|
||
if StubMerger._sha1_store_arr is None:
|
||
StubMerger._sha1_store_arr = stdlib.malloc(StubMerger.MAX_INCLUDES * 17)
|
||
StubMerger._sha1_store_mod = stdlib.malloc(StubMerger.MAX_INCLUDES * 64)
|
||
StubMerger._sha1_store_rel = stdlib.malloc(StubMerger.MAX_INCLUDES * StubMerger.MAX_REL_PATH_LEN)
|
||
StubMerger._sha1_store_incdir = stdlib.malloc(StubMerger.MAX_INCLUDES * StubMerger.MAX_INC_DIR_LEN)
|
||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None or StubMerger._sha1_store_rel is None or StubMerger._sha1_store_incdir is None:
|
||
return 1
|
||
string.memset(StubMerger._sha1_store_arr, 0, StubMerger.MAX_INCLUDES * 17)
|
||
string.memset(StubMerger._sha1_store_mod, 0, StubMerger.MAX_INCLUDES * 64)
|
||
string.memset(StubMerger._sha1_store_rel, 0, StubMerger.MAX_INCLUDES * StubMerger.MAX_REL_PATH_LEN)
|
||
string.memset(StubMerger._sha1_store_incdir, 0, StubMerger.MAX_INCLUDES * StubMerger.MAX_INC_DIR_LEN)
|
||
StubMerger._sha1_store_count = 0
|
||
if StubMerger._sha1_store_count >= StubMerger.MAX_INCLUDES:
|
||
return 1
|
||
# 去重:SHA1 与模块名都相同才跳过(对齐 AppendToSha1MapStore)
|
||
for i in range(StubMerger._sha1_store_count):
|
||
sidx_d: sizet = sizet(i) * 17
|
||
if string.strcmp(StubMerger._sha1_store_arr + sidx_d, sha1) == 0:
|
||
midx_d: sizet = sizet(i) * 64
|
||
if string.strcmp(StubMerger._sha1_store_mod + midx_d, mod_name) == 0:
|
||
return 0
|
||
# 写 SHA1
|
||
idx_a: sizet = sizet(StubMerger._sha1_store_count) * 17
|
||
string.strcpy(StubMerger._sha1_store_arr + idx_a, sha1)
|
||
# 写模块名
|
||
idx_m: sizet = sizet(StubMerger._sha1_store_count) * 64
|
||
mn_len: sizet = string.strlen(mod_name)
|
||
if mn_len < 64:
|
||
string.strcpy(StubMerger._sha1_store_mod + idx_m, mod_name)
|
||
else:
|
||
string.strncpy(StubMerger._sha1_store_mod + idx_m, mod_name, 63)
|
||
StubMerger._sha1_store_mod[idx_m + 63] = '\0'
|
||
# 写相对路径
|
||
idx_r: sizet = sizet(StubMerger._sha1_store_count) * StubMerger.MAX_REL_PATH_LEN
|
||
rp_len: sizet = string.strlen(rel_path)
|
||
if rp_len < StubMerger.MAX_REL_PATH_LEN:
|
||
string.strcpy(StubMerger._sha1_store_rel + idx_r, rel_path)
|
||
else:
|
||
string.strncpy(StubMerger._sha1_store_rel + idx_r, rel_path, StubMerger.MAX_REL_PATH_LEN - 1)
|
||
StubMerger._sha1_store_rel[idx_r + StubMerger.MAX_REL_PATH_LEN - 1] = '\0'
|
||
# 写所属 includes 根目录(非空 = includes 条目;App 条目留空)
|
||
idx_inc: sizet = sizet(StubMerger._sha1_store_count) * StubMerger.MAX_INC_DIR_LEN
|
||
if inc_dir is not None:
|
||
icd_len: sizet = string.strlen(inc_dir)
|
||
if icd_len < StubMerger.MAX_INC_DIR_LEN:
|
||
string.strcpy(StubMerger._sha1_store_incdir + idx_inc, inc_dir)
|
||
else:
|
||
string.strncpy(StubMerger._sha1_store_incdir + idx_inc, inc_dir, StubMerger.MAX_INC_DIR_LEN - 1)
|
||
StubMerger._sha1_store_incdir[idx_inc + StubMerger.MAX_INC_DIR_LEN - 1] = '\0'
|
||
else:
|
||
StubMerger._sha1_store_incdir[idx_inc] = '\0'
|
||
StubMerger._sha1_store_count += 1
|
||
return 0
|
||
# ============================================================
|
||
# GetSha1StoreCount - 获取全局存储器条目数
|
||
# ============================================================
|
||
def GetSha1StoreCount() -> int:
|
||
"""返回全局 SHA1 存储器的条目数"""
|
||
return StubMerger._sha1_store_count
|
||
# ============================================================
|
||
# LookupSha1ByModName - 从模块名查找 SHA1(直接查全局存储器)
|
||
#
|
||
# 精确匹配失败时,尝试 "{mod_name}.__init__" 回退,
|
||
# 支持 import ast(包)→ ast.__init__ 的 SHA1 查找。
|
||
#
|
||
# Returns:
|
||
# SHA1 字符串指针(指向全局存储器内部,无需释放),None 未找到
|
||
# ============================================================
|
||
def LookupSha1ByModName(mod_name: str) -> str:
|
||
"""从模块名查找 SHA1(精确匹配 + 包名回退),委托通用实现 _FindSha1ByModName"""
|
||
return StubMergerIR._FindSha1ByModName(StubMerger._sha1_store_arr, StubMerger._sha1_store_mod, StubMerger._sha1_store_count, mod_name)
|
||
|
||
|
||
# ============================================================
|
||
# 泛型类归属表(泛型类名 → 定义模块 SHA1)——仅 REPL 会话登记/查询
|
||
#
|
||
# 为什么需要:REPL 的 includes 会话初始化只注入 `.vpi` 的类(泛型类被跳过),
|
||
# 不跑批处理的 _PreRegister*GenericTemplates ⇒ 会话内泛型模板表为空 ⇒ 注解里的
|
||
# `list[rawptr[AST]]` 等泛型下标解析(`TypeGenResolve._resolve_generic_subscript_ty`)
|
||
# 恒 miss。会话侧的最后兜底要按**定义侧特化命名** "%{模板模块 sha1}.{mangled}"
|
||
# 造 opaque 具名类型(实证:`%"b56d2f995104690d.list[rawptr[AST]]"`),因此需要
|
||
# "泛型类定义在哪个模块"这一事实——由注入期扫 `.vpi` 的 ClassDef 登记(见
|
||
# VpiReader._repl_stub_collect_module)。
|
||
#
|
||
# 归属模块 sha1 无法从类名反推(模块名取自文件路径,class list ← _list.vp;用户
|
||
# 泛型类更是名字与模块名无关),故必须显式登记,不做"按名字猜"。
|
||
# 批处理不登记(表恒空 ⇒ 查询恒 None ⇒ 批处理路径一字不改)。
|
||
# 容量:includes 现有 6 个泛型类定义(list/dict 系 + Vector/GSList/ndarray),取 32 槽。
|
||
# ============================================================
|
||
GENERIC_OWNER_MAX: t.CDefine = 32
|
||
_generic_owner_names: bytes = None
|
||
_generic_owner_sha1s: bytes = None
|
||
_generic_owner_count: int = 0
|
||
|
||
|
||
def ResetGenericOwners() -> None:
|
||
"""清空泛型类归属表(REPL 会话初始化开始时调用一次)"""
|
||
global _generic_owner_names, _generic_owner_sha1s, _generic_owner_count
|
||
if _generic_owner_names is not None:
|
||
stdlib.free(_generic_owner_names)
|
||
_generic_owner_names = None
|
||
if _generic_owner_sha1s is not None:
|
||
stdlib.free(_generic_owner_sha1s)
|
||
_generic_owner_sha1s = None
|
||
_generic_owner_count = 0
|
||
|
||
|
||
def RegisterGenericOwner(cls_name: str, mod_sha1: str) -> int:
|
||
"""登记"泛型类名 → 定义模块 SHA1";1=已登记(含重复)/ 0=失败(参数/满/同名异 sha1)
|
||
|
||
同名异 sha1(跨模块同名泛型类)保留首个,与泛型模板表按类名去重的口径一致。
|
||
"""
|
||
global _generic_owner_names, _generic_owner_sha1s, _generic_owner_count
|
||
if cls_name is None or mod_sha1 is None:
|
||
return 0
|
||
if cls_name[0] == '\0' or mod_sha1[0] == '\0':
|
||
return 0
|
||
if _generic_owner_names is None:
|
||
_generic_owner_names = stdlib.malloc(GENERIC_OWNER_MAX * 64)
|
||
_generic_owner_sha1s = stdlib.malloc(GENERIC_OWNER_MAX * 17)
|
||
if _generic_owner_names is None or _generic_owner_sha1s is None:
|
||
return 0
|
||
string.memset(_generic_owner_names, 0, GENERIC_OWNER_MAX * 64)
|
||
string.memset(_generic_owner_sha1s, 0, GENERIC_OWNER_MAX * 17)
|
||
_generic_owner_count = 0
|
||
i_go: int
|
||
for i_go in range(_generic_owner_count):
|
||
if string.strcmp(_generic_owner_names + sizet(i_go) * 64, cls_name) == 0:
|
||
if string.strcmp(_generic_owner_sha1s + sizet(i_go) * 17, mod_sha1) == 0:
|
||
return 1
|
||
return 0
|
||
if _generic_owner_count >= GENERIC_OWNER_MAX:
|
||
return 0
|
||
string.strncpy(_generic_owner_names + sizet(_generic_owner_count) * 64, cls_name, 63)
|
||
string.strncpy(_generic_owner_sha1s + sizet(_generic_owner_count) * 17, mod_sha1, 16)
|
||
_generic_owner_count += 1
|
||
return 1
|
||
|
||
|
||
def LookupGenericOwnerSha1(cls_name: str) -> str:
|
||
"""按泛型类名取定义模块 SHA1(返回内部指针,无需释放;未登记 None)"""
|
||
if cls_name is None or _generic_owner_names is None:
|
||
return None
|
||
i_lg: int
|
||
for i_lg in range(_generic_owner_count):
|
||
if string.strcmp(_generic_owner_names + sizet(i_lg) * 64, cls_name) == 0:
|
||
return _generic_owner_sha1s + sizet(i_lg) * 17
|
||
return None
|
||
# ============================================================
|
||
# LookupSha1ByModNameSuffix - 后缀匹配查找模块 SHA1(用于 from .X import Y:impf.module 是 ".X",而映射表键是 "pkg.X")
|
||
#
|
||
# 包含三种匹配方式:精确、后缀、反向后缀。
|
||
# Returns: SHA1 字符串指针(指向全局存储器内部,无需释放),None 未找到
|
||
# ============================================================
|
||
def LookupSha1ByModNameSuffix(mod_suffix: str) -> str:
|
||
"""后缀匹配查找模块 SHA1"""
|
||
if mod_suffix is None:
|
||
return None
|
||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None:
|
||
return None
|
||
if StubMerger._sha1_store_count <= 0:
|
||
return None
|
||
suffix_len_sf: sizet = string.strlen(mod_suffix)
|
||
if suffix_len_sf == 0:
|
||
return None
|
||
i_sf: int
|
||
for i_sf in range(StubMerger._sha1_store_count):
|
||
idx_sf: sizet = sizet(i_sf) * 64
|
||
mod_name_sf: str = StubMerger._sha1_store_mod + idx_sf
|
||
mod_len_sf: sizet = string.strlen(mod_name_sf)
|
||
if mod_len_sf == 0:
|
||
continue
|
||
# 精确匹配
|
||
if mod_len_sf == suffix_len_sf:
|
||
if string.strcmp(mod_name_sf, mod_suffix) == 0:
|
||
sidx_sf: sizet = sizet(i_sf) * 17
|
||
return StubMerger._sha1_store_arr + sidx_sf
|
||
# 后缀匹配:mod_name 以 "." + mod_suffix 结尾
|
||
if mod_len_sf > suffix_len_sf:
|
||
if mod_name_sf[mod_len_sf - suffix_len_sf - 1] == '.':
|
||
cmp_start_sf: str = mod_name_sf + mod_len_sf - suffix_len_sf
|
||
if string.strcmp(cmp_start_sf, mod_suffix) == 0:
|
||
sidx2_sf: sizet = sizet(i_sf) * 17
|
||
return StubMerger._sha1_store_arr + sidx2_sf
|
||
# 反向后缀匹配:mod_suffix 以 "." + mod_name 结尾
|
||
if suffix_len_sf > mod_len_sf:
|
||
if mod_suffix[suffix_len_sf - mod_len_sf - 1] == '.':
|
||
cmp_start_rev_sf: str = mod_suffix + suffix_len_sf - mod_len_sf
|
||
if string.strcmp(cmp_start_rev_sf, mod_name_sf) == 0:
|
||
sidx_rev_sf: sizet = sizet(i_sf) * 17
|
||
return StubMerger._sha1_store_arr + sidx_rev_sf
|
||
return None
|
||
# ============================================================
|
||
# LookupSha1ByAlias - 从 from_imports 别名映射解析模块 SHA1
|
||
#
|
||
# from_imports 条目格式 "local:module" 或 "local:module:orig"(空格分隔,由 ImportsGenMixin.add_from_import 写入);
|
||
# 命中 local==alias 时对 module 执行 LookupSha1ByModName。
|
||
# Returns: SHA1 字符串指针(指向全局存储器内部),None 未找到
|
||
# ============================================================
|
||
def LookupSha1ByAlias(from_imports: str, alias: str) -> str:
|
||
"""从 from_imports 别名映射解析模块 SHA1(改名别名 import X as Y 场景)"""
|
||
if from_imports is None or alias is None:
|
||
return None
|
||
alias_len: sizet = string.strlen(alias)
|
||
if alias_len == 0:
|
||
return None
|
||
total_len: sizet = string.strlen(from_imports)
|
||
ci: sizet = 0
|
||
while ci < total_len:
|
||
# 跳过前导空格
|
||
while ci < total_len and from_imports[ci] == ' ':
|
||
ci += 1
|
||
if ci >= total_len:
|
||
break
|
||
# 条目起点 ci,找 ':'(local_name 结束)
|
||
colon: sizet = ci
|
||
while colon < total_len and from_imports[colon] != ':' and from_imports[colon] != ' ':
|
||
colon += 1
|
||
local_len: sizet = colon - ci
|
||
if colon < total_len and from_imports[colon] == ':' and local_len == alias_len:
|
||
# 比较 local_name == alias
|
||
match: int = 1
|
||
li: sizet = 0
|
||
while li < alias_len:
|
||
if from_imports[ci + li] != alias[li]:
|
||
match = 0
|
||
break
|
||
li += 1
|
||
if match == 1:
|
||
# 提取 module(colon+1 到下一个 ':' 或空格)
|
||
m_start: sizet = colon + 1
|
||
m_end: sizet = m_start
|
||
while m_end < total_len and from_imports[m_end] != ':' and from_imports[m_end] != ' ':
|
||
m_end += 1
|
||
if m_end > m_start:
|
||
mbuf: str = stdlib.malloc(m_end - m_start + 1)
|
||
if mbuf is not None:
|
||
string.strncpy(mbuf, from_imports + m_start, m_end - m_start)
|
||
mbuf[m_end - m_start] = '\0'
|
||
res: str = LookupSha1ByModName(mbuf)
|
||
stdlib.free(mbuf)
|
||
return res
|
||
return None
|
||
# 跳到下一条目
|
||
while ci < total_len and from_imports[ci] != ' ':
|
||
ci += 1
|
||
return None
|
||
# ============================================================
|
||
# LookupModNameByAlias - 从 from_imports 别名映射解析模块真名
|
||
#
|
||
# import X as Y 时 ImportsGenMixin.add_from_import 写入 "Y:X"(Y=别名,X=模块真名);
|
||
# 本函数返回别名 Y 对应的模块真名 X(供限定名解析 "Y.Class" → 按 X 模块归属匹配)。
|
||
# Returns: 模块名字符串(stdlib 分配,调用方负责 free),None 未找到
|
||
# ============================================================
|
||
def LookupModNameByAlias(from_imports: str, alias: str) -> str:
|
||
"""从 from_imports 别名映射解析模块真名(import X as Y → Y:X)"""
|
||
if from_imports is None or alias is None:
|
||
return None
|
||
alias_len: sizet = string.strlen(alias)
|
||
if alias_len == 0:
|
||
return None
|
||
total_len: sizet = string.strlen(from_imports)
|
||
ci: sizet = 0
|
||
while ci < total_len:
|
||
# 跳过前导空格
|
||
while ci < total_len and from_imports[ci] == ' ':
|
||
ci += 1
|
||
if ci >= total_len:
|
||
break
|
||
# 条目起点 ci,找 ':'(local_name 结束)
|
||
colon: sizet = ci
|
||
while colon < total_len and from_imports[colon] != ':' and from_imports[colon] != ' ':
|
||
colon += 1
|
||
local_len: sizet = colon - ci
|
||
if colon < total_len and from_imports[colon] == ':' and local_len == alias_len:
|
||
# 比较 local_name == alias
|
||
match: int = 1
|
||
li: sizet = 0
|
||
while li < alias_len:
|
||
if from_imports[ci + li] != alias[li]:
|
||
match = 0
|
||
break
|
||
li += 1
|
||
if match == 1:
|
||
# 提取 module(colon+1 到下一个 ':' 或空格)
|
||
m_start: sizet = colon + 1
|
||
m_end: sizet = m_start
|
||
while m_end < total_len and from_imports[m_end] != ':' and from_imports[m_end] != ' ':
|
||
m_end += 1
|
||
if m_end > m_start:
|
||
mbuf: str = stdlib.malloc(m_end - m_start + 1)
|
||
if mbuf is not None:
|
||
string.strncpy(mbuf, from_imports + m_start, m_end - m_start)
|
||
mbuf[m_end - m_start] = '\0'
|
||
return mbuf
|
||
return None
|
||
# 跳到下一条目
|
||
while ci < total_len and from_imports[ci] != ' ':
|
||
ci += 1
|
||
return None
|
||
# ============================================================
|
||
# PopulateIncludesDeps - 将 includes 文件的依赖存入内存
|
||
#
|
||
# Phase B+ 前用 declare_only 翻译 includes 文件、提取 _imported_modules 后调用本函数存入内存;_BuildReachableSha1Set 从内存读取,不读 deps.txt。
|
||
# Args: sha1 includes 文件的 SHA1(16字符);deps_str 依赖模块名字符串(空格分隔,如 "t c stdint string")
|
||
# Returns: 0 成功,非 0 失败
|
||
# ============================================================
|
||
def PopulateIncludesDeps(sha1: str, deps_str: str) -> int:
|
||
"""将 includes 文件的依赖存入内存"""
|
||
if sha1 is None:
|
||
return 1
|
||
# 延迟初始化
|
||
if StubMerger._includes_deps_sha1 is None:
|
||
StubMerger._includes_deps_sha1 = stdlib.malloc(StubMerger.MAX_INCLUDES * 17)
|
||
StubMerger._includes_deps_str = stdlib.malloc(StubMerger.MAX_INCLUDES * StubMerger.MAX_DEPS_STR_LEN)
|
||
if StubMerger._includes_deps_sha1 is None or StubMerger._includes_deps_str is None:
|
||
return 1
|
||
string.memset(StubMerger._includes_deps_sha1, 0, StubMerger.MAX_INCLUDES * 17)
|
||
string.memset(StubMerger._includes_deps_str, 0, StubMerger.MAX_INCLUDES * StubMerger.MAX_DEPS_STR_LEN)
|
||
StubMerger._includes_deps_count = 0
|
||
if StubMerger._includes_deps_count >= StubMerger.MAX_INCLUDES:
|
||
return 1
|
||
# 去重:若 SHA1 已存在则跳过
|
||
for i in range(StubMerger._includes_deps_count):
|
||
sidx: sizet = sizet(i) * 17
|
||
if string.strcmp(StubMerger._includes_deps_sha1 + sidx, sha1) == 0:
|
||
return 0
|
||
# 写入 SHA1
|
||
idx: sizet = sizet(StubMerger._includes_deps_count) * 17
|
||
string.strcpy(StubMerger._includes_deps_sha1 + idx, sha1)
|
||
# 写入依赖字符串
|
||
idx2: sizet = sizet(StubMerger._includes_deps_count) * StubMerger.MAX_DEPS_STR_LEN
|
||
if deps_str is not None:
|
||
dl: sizet = string.strlen(deps_str)
|
||
if dl < StubMerger.MAX_DEPS_STR_LEN:
|
||
string.strcpy(StubMerger._includes_deps_str + idx2, deps_str)
|
||
else:
|
||
string.strncpy(StubMerger._includes_deps_str + idx2, deps_str, StubMerger.MAX_DEPS_STR_LEN - 1)
|
||
else:
|
||
StubMerger._includes_deps_str[idx2] = '\0'
|
||
StubMerger._includes_deps_count = StubMerger._includes_deps_count + 1
|
||
return 0
|
||
# ============================================================
|
||
# LookupIncludesDeps - 从内存查找 includes 文件的依赖
|
||
#
|
||
# Args:
|
||
# sha1: includes 文件的 SHA1(16字符)
|
||
#
|
||
# Returns:
|
||
# 依赖模块名字符串指针(空格分隔),None 表示未找到
|
||
# ============================================================
|
||
def LookupIncludesDeps(sha1: str) -> str:
|
||
"""从内存查找 includes 文件的依赖"""
|
||
if sha1 is None or StubMerger._includes_deps_sha1 is None:
|
||
return None
|
||
if StubMerger._includes_deps_count <= 0:
|
||
return None
|
||
for i in range(StubMerger._includes_deps_count):
|
||
sidx: sizet = sizet(i) * 17
|
||
if string.strcmp(StubMerger._includes_deps_sha1 + sidx, sha1) == 0:
|
||
idx2: sizet = sizet(i) * StubMerger.MAX_DEPS_STR_LEN
|
||
return StubMerger._includes_deps_str + idx2
|
||
return None
|
||
def GetSha1StoreArrPtr() -> bytes:
|
||
"""返回 SHA1 数组指针(每个条目 17 字节)"""
|
||
return StubMerger._sha1_store_arr
|
||
def GetSha1StoreModArrPtr() -> bytes:
|
||
"""返回模块名数组指针(每个条目 64 字节)"""
|
||
return StubMerger._sha1_store_mod
|
||
def GetSha1StoreRelArrPtr() -> bytes:
|
||
"""返回相对路径数组指针(每个条目 StubMerger.MAX_REL_PATH_LEN 字节)"""
|
||
return StubMerger._sha1_store_rel
|
||
def GetSha1StoreIncdirArrPtr() -> bytes:
|
||
"""返回所属 includes 根目录数组指针(每个条目 StubMerger.MAX_INC_DIR_LEN 字节,空串表示不属于任何 includes 目录)"""
|
||
return StubMerger._sha1_store_incdir
|
||
# ============================================================
|
||
# GetSha1StoreArr - 获取全局存储器数组指针(直接遍历用)
|
||
#
|
||
# 返回 sha1_arr、mod_arr、rel_arr 三个数组的指针和条目数。
|
||
# 调用者直接遍历数组:sha1_arr[i*17]、mod_arr[i*64]、rel_arr[i*StubMerger.MAX_REL_PATH_LEN]
|
||
# 内存归全局存储器所有,调用者不要 free
|
||
# ============================================================
|
||
def GetSha1StoreArr(out_sha1_arr: rawptr[t.CPtr], out_mod_arr: rawptr[t.CPtr], out_rel_arr: rawptr[t.CPtr]) -> int:
|
||
"""获取全局存储器数组指针
|
||
|
||
out_sha1_arr/out_mod_arr/out_rel_arr 是调用者提供的 t.CPtr 槽的地址(t.CPtr*),
|
||
函数把存储器数组指针写入这些槽。返回条目数,-1 失败
|
||
"""
|
||
if out_sha1_arr is None or out_mod_arr is None or out_rel_arr is None:
|
||
return -1
|
||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None or StubMerger._sha1_store_rel is None:
|
||
return -1
|
||
sp: rawptr[t.CPtr] = out_sha1_arr
|
||
if sp is not None:
|
||
sp[0] = StubMerger._sha1_store_arr
|
||
mp: rawptr[t.CPtr] = out_mod_arr
|
||
if mp is not None:
|
||
mp[0] = StubMerger._sha1_store_mod
|
||
rp: rawptr[t.CPtr] = out_rel_arr
|
||
if rp is not None:
|
||
rp[0] = StubMerger._sha1_store_rel
|
||
return StubMerger._sha1_store_count
|
||
|
||
# ============================================================
|
||
# LookupSha1RelPath - 通过 SHA1 查找相对路径
|
||
#
|
||
# 遍历全局存储器,返回 sha1 对应的相对路径指针(只读,不要 free),用于把 sha1 转成人类可读的文件路径。
|
||
# Args: sha1 SHA1 字符串(16 字符)
|
||
# Returns: 相对路径字符串指针(只读),None=未找到
|
||
# ============================================================
|
||
def LookupSha1RelPath(sha1: str) -> str:
|
||
"""通过 SHA1 查找相对路径,返回只读指针,None=未找到"""
|
||
if sha1 is None:
|
||
return None
|
||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_rel is None:
|
||
return None
|
||
for i in range(StubMerger._sha1_store_count):
|
||
sidx: sizet = sizet(i) * 17
|
||
if string.strcmp(StubMerger._sha1_store_arr + sidx, sha1) == 0:
|
||
ridx: sizet = sizet(i) * StubMerger.MAX_REL_PATH_LEN
|
||
return StubMerger._sha1_store_rel + ridx
|
||
return None
|
||
|
||
|
||
# ============================================================
|
||
# LookupModNameBySha1 - 通过 SHA1 反查模块名
|
||
#
|
||
# 用途:判定"本 stub 是否某包的 __init__"(模块名以 ".__init__" 结尾)——该事实
|
||
# **不依赖 sha1→rel_path 字段**:rel_path 反查在部分运行形态下拿不到条目 ⇒
|
||
# VpiReader 原来的 `strstr(rel_path, "__init__.vp")` 判定恒 false ⇒ 包重导出类的
|
||
# 别名 entry 静默不登记 ⇒ `ast.ClassDef` 这类**限定名在泛型实参里保留包前缀**,
|
||
# 与构造函数侧(真定义模块前缀)分裂成两个类型(现场 ClassGenGeneric.vp:92 的
|
||
# CastError;幽灵名 `list[1abcd5277fa442de.ClassDef*]` 全产物 opaque)。
|
||
# 模块名与 rel_path 是同一次登记写入的(PopulateSha1MapStore /
|
||
# AppendToSha1MapStore),但模块名可用即足以作出判定与取包前缀。
|
||
#
|
||
# 同一 SHA1 可能有多条(App 源文件按全路径模块名与短模块名各登记一次):返回
|
||
# **第一条命中**;各条的包前缀一致,调用方只取"去 .__init__ 后的前缀"。
|
||
# Args: sha1 SHA1 字符串(16 字符)
|
||
# Returns: 模块名字符串指针(只读,不要 free),None=未找到
|
||
# ============================================================
|
||
def LookupModNameBySha1(sha1: str) -> str:
|
||
"""通过 SHA1 查找模块名,返回只读指针,None=未找到"""
|
||
if sha1 is None or sha1[0] == '\0':
|
||
return None
|
||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None:
|
||
return None
|
||
for i in range(StubMerger._sha1_store_count):
|
||
sidx_mb: sizet = sizet(i) * 17
|
||
if string.strcmp(StubMerger._sha1_store_arr + sidx_mb, sha1) == 0:
|
||
midx_mb: sizet = sizet(i) * 64
|
||
return StubMerger._sha1_store_mod + midx_mb
|
||
return None
|