Files
ViperC/App/lib/core/StubMergerStore.vp
T
TermiNexus 278893d203 refactor(core): StubMerger 拆 5 组(Collect/Store/Topo/IR/Build,2391→72 行)
直接移动+改调用方模式:35 个函数按功能移至 5 个子模块,主文件
仅保留常量与全局变量(main.vp 仍直接赋值 StubMerger._mbuddy)。
- 子模块函数体内裸调用映射为子模块前缀,全局变量经 StubMerger._xxx 跨模块访问
- 12 个调用方文件 StubMerger.func( → 对应子模块前缀并补 import
- 全 App 语法/引用/import 验证通过
2026-08-17 08:03:40 +08:00

410 lines
20 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.HandlesImports as HandlesImports
import lib.core.Handles.HandlesTranslator as HandlesTranslator
import lib.core.BuildPipeline as BuildPipeline
import lib.StubGen.VpiReader as VpiReader
import lib.Projectrans.Utils as Utils
import lib.Projectrans.Config as Config
import lib.core.StubMergerCollect as StubMergerCollect
import lib.core.StubMergerTopo as StubMergerTopo
import lib.core.StubMergerIR as StubMergerIR
import lib.core.StubMergerBuild as StubMergerBuild
import lib.core.StubMerger as StubMerger
# ============================================================
# StubMergerStore - StubMerger 拆分(阶段 E):StubMergerStore
#
# 直接移动模式:函数实现迁至此模块,原 StubMerger.vp 仅保留
# 常量/全局变量;调用方经本模块前缀访问。全局变量跨模块经
# StubMerger._xxx 访问(main.vp 先例)。
# ============================================================
# ============================================================
# PopulateSha1MapStore - 从扫描结果填充全局 SHA1 映射存储器
#
# 遍历 ScanResult.Entries,为每个条目构建 sha1→module_name 映射。
# 模块名通过 _PathToModuleName(includes/rel_path) 计算。
# 内存用 stdlib.malloc 分配(全局存储器,不随 mbuddy 释放)。
#
# Args:
# scan_result: IncludesScanner 扫描结果
#
# Returns:
# 填充的条目数,-1 表示失败
# ============================================================
def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> 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(MAX_INCLUDES * 17)
StubMerger._sha1_store_mod = stdlib.malloc(MAX_INCLUDES * 64)
StubMerger._sha1_store_rel = stdlib.malloc(MAX_INCLUDES * MAX_REL_PATH_LEN)
StubMerger._sha1_store_incdir = stdlib.malloc(MAX_INCLUDES * 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, MAX_INCLUDES * 17)
string.memset(StubMerger._sha1_store_mod, 0, MAX_INCLUDES * 64)
string.memset(StubMerger._sha1_store_rel, 0, MAX_INCLUDES * MAX_REL_PATH_LEN)
string.memset(StubMerger._sha1_store_incdir, 0, MAX_INCLUDES * MAX_INC_DIR_LEN)
StubMerger._sha1_store_count = 0
p_bad: int = 0
entry_size_p: t.CSizeT = IncludesScanner.FileEntry.__sizeof__()
for i in range(scan_result.Count):
if StubMerger._sha1_store_count >= MAX_INCLUDES:
VLogger.error("includes SHA1 存储超上限,终止", "StubMerger")
ea: t.CUInt64T = t.CUInt64T(scan_result.Entries) + i * entry_size_p
ent: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea, t.CPtr))
if ent is None or ent.Sha1 is None or ent.RelPath is None:
p_bad += 1
continue
# 构建完整路径 includes/{RelPath}(_PathToModuleName 需要)
rp_len: t.CSizeT = 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: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * 17
string.strcpy(StubMerger._sha1_store_arr + idx, ent.Sha1)
idx2: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * 64
mn_len: t.CSizeT = 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: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * MAX_REL_PATH_LEN
if rp_len < MAX_REL_PATH_LEN:
string.strcpy(StubMerger._sha1_store_rel + idx3, ent.RelPath)
else:
string.strncpy(StubMerger._sha1_store_rel + idx3, ent.RelPath, MAX_REL_PATH_LEN - 1)
StubMerger._sha1_store_rel[idx3 + MAX_REL_PATH_LEN - 1] = '\0'
# 保存所属 includes 根目录(Phase2 预注册/按需编译拼路径用)
idx_inc: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * MAX_INC_DIR_LEN
if ent.IncDir is not None:
icd_len: t.CSizeT = string.strlen(ent.IncDir)
if icd_len < 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, MAX_INC_DIR_LEN - 1)
StubMerger._sha1_store_incdir[idx_inc + MAX_INC_DIR_LEN - 1] = '\0'
StubMerger._sha1_store_count += 1
if p_bad > 0:
fb_pbad: str = VLogger.fmt_buf()
if fb_pbad is not None:
viperlib.snprintf(fb_pbad, 1024, "includes SHA1 存储有 %d 个条目失败", p_bad)
VLogger.error(fb_pbad, "StubMerger")
return StubMerger._sha1_store_count
# ============================================================
# AppendToSha1MapStore - 追加条目到全局 SHA1 映射存储器
#
# Phase1 调用 PopulateSha1MapStore 填充 includes 文件,
# Phase2 扫描 App 源文件后调用此函数追加 App 模块条目,
# 确保编译 App 自身时跨模块 CDefine 查找能命中 App 模块
# (如 StubMerger.MAX_INCLUDES 在编译 Phase2 时通过
# _build_source_path_from_sha1 查找 StubMerger 的源路径)。
#
# 若存储器未初始化(PopulateSha1MapStore 未调用),自动初始化。
# 若 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(MAX_INCLUDES * 17)
StubMerger._sha1_store_mod = stdlib.malloc(MAX_INCLUDES * 64)
StubMerger._sha1_store_rel = stdlib.malloc(MAX_INCLUDES * MAX_REL_PATH_LEN)
StubMerger._sha1_store_incdir = stdlib.malloc(MAX_INCLUDES * 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, MAX_INCLUDES * 17)
string.memset(StubMerger._sha1_store_mod, 0, MAX_INCLUDES * 64)
string.memset(StubMerger._sha1_store_rel, 0, MAX_INCLUDES * MAX_REL_PATH_LEN)
string.memset(StubMerger._sha1_store_incdir, 0, MAX_INCLUDES * MAX_INC_DIR_LEN)
StubMerger._sha1_store_count = 0
if StubMerger._sha1_store_count >= MAX_INCLUDES:
return 1
# 去重:若 SHA1 已存在则跳过
for i in range(StubMerger._sha1_store_count):
sidx_d: t.CSizeT = t.CSizeT(i) * 17
if string.strcmp(StubMerger._sha1_store_arr + sidx_d, sha1) == 0:
return 0
# 模块名: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
idx_a: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * 17
string.strcpy(StubMerger._sha1_store_arr + idx_a, sha1)
# 写入模块名
idx_m: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * 64
mn_len: t.CSizeT = 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: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * MAX_REL_PATH_LEN
rp_len: t.CSizeT = string.strlen(rel_path)
if rp_len < 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, MAX_REL_PATH_LEN - 1)
StubMerger._sha1_store_rel[idx_r + MAX_REL_PATH_LEN - 1] = '\0'
# App 源文件不属于任何 includes 目录:IncDir 留空(Phase2 回退 includes_dir 参数)
idx_inc_a: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * MAX_INC_DIR_LEN
StubMerger._sha1_store_incdir[idx_inc_a] = '\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)
# ============================================================
# LookupSha1ByModNameSuffix - 后缀匹配查找模块 SHA1
#
# 用于 from .X import Y 的相对导入:impf.module 是 ".X"(带前导点),
# 去掉前导点后为 "X",SHA1 映射表中键是 "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: t.CSizeT = 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: t.CSizeT = t.CSizeT(i_sf) * 64
mod_name_sf: str = StubMerger._sha1_store_mod + idx_sf
mod_len_sf: t.CSizeT = 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: t.CSizeT = t.CSizeT(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: t.CSizeT = t.CSizeT(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: t.CSizeT = t.CSizeT(i_sf) * 17
return StubMerger._sha1_store_arr + sidx_rev_sf
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(MAX_INCLUDES * 17)
StubMerger._includes_deps_str = stdlib.malloc(MAX_INCLUDES * 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, MAX_INCLUDES * 17)
string.memset(StubMerger._includes_deps_str, 0, MAX_INCLUDES * MAX_DEPS_STR_LEN)
StubMerger._includes_deps_count = 0
if StubMerger._includes_deps_count >= MAX_INCLUDES:
return 1
# 去重:若 SHA1 已存在则跳过
for i in range(StubMerger._includes_deps_count):
sidx: t.CSizeT = t.CSizeT(i) * 17
if string.strcmp(StubMerger._includes_deps_sha1 + sidx, sha1) == 0:
return 0
# 写入 SHA1
idx: t.CSizeT = t.CSizeT(StubMerger._includes_deps_count) * 17
string.strcpy(StubMerger._includes_deps_sha1 + idx, sha1)
# 写入依赖字符串
idx2: t.CSizeT = t.CSizeT(StubMerger._includes_deps_count) * MAX_DEPS_STR_LEN
if deps_str is not None:
dl: t.CSizeT = string.strlen(deps_str)
if dl < MAX_DEPS_STR_LEN:
string.strcpy(StubMerger._includes_deps_str + idx2, deps_str)
else:
string.strncpy(StubMerger._includes_deps_str + idx2, deps_str, 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: t.CSizeT = t.CSizeT(i) * 17
if string.strcmp(StubMerger._includes_deps_sha1 + sidx, sha1) == 0:
idx2: t.CSizeT = t.CSizeT(i) * MAX_DEPS_STR_LEN
return StubMerger._includes_deps_str + idx2
return None
def GetSha1StoreArrPtr() -> bytes | t.CPtr:
"""返回 SHA1 数组指针(每个条目 17 字节)"""
return StubMerger._sha1_store_arr
def GetSha1StoreModArrPtr() -> bytes | t.CPtr:
"""返回模块名数组指针(每个条目 64 字节)"""
return StubMerger._sha1_store_mod
def GetSha1StoreRelArrPtr() -> bytes | t.CPtr:
"""返回相对路径数组指针(每个条目 MAX_REL_PATH_LEN 字节)"""
return StubMerger._sha1_store_rel
def GetSha1StoreIncdirArrPtr() -> bytes | t.CPtr:
"""返回所属 includes 根目录数组指针(每个条目 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*MAX_REL_PATH_LEN]
# 内存归全局存储器所有,调用者不要 free
# ============================================================
def GetSha1StoreArr(out_sha1_arr: t.CPtr, out_mod_arr: t.CPtr, out_rel_arr: t.CPtr) -> int:
"""获取全局存储器数组指针
out_sha1_arr/out_mod_arr/out_rel_arr 是调用者提供的 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: t.CPtr = (t.CPtr | t.CPtr)(t.CVoid(out_sha1_arr, t.CPtr))
if sp is not None:
sp[0] = StubMerger._sha1_store_arr
mp: t.CPtr = (t.CPtr | t.CPtr)(t.CVoid(out_mod_arr, t.CPtr))
if mp is not None:
mp[0] = StubMerger._sha1_store_mod
rp: t.CPtr = (t.CPtr | t.CPtr)(t.CVoid(out_rel_arr, t.CPtr))
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: t.CSizeT = t.CSizeT(i) * 17
if string.strcmp(StubMerger._sha1_store_arr + sidx, sha1) == 0:
ridx: t.CSizeT = t.CSizeT(i) * MAX_REL_PATH_LEN
return StubMerger._sha1_store_rel + ridx
return None