refactor: StubMerger 复用公共工具(LookupSha1ByModName 委托、_sliced_path 复用 slice_subdir、_PathToModuleName 下沉)
This commit is contained in:
1 parent
96e045889e
commit
0665ee1164
1 file changed
+13
-135
+13
-135
@@ -17,6 +17,7 @@ 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
|
||||
|
||||
|
||||
@@ -94,26 +95,11 @@ def _sliced_path(temp_dir: str, td_len: t.CSizeT, sha1: str, ext: str) -> str:
|
||||
sha1_len: t.CSizeT = string.strlen(sha1)
|
||||
ext_len: t.CSizeT = string.strlen(ext)
|
||||
|
||||
# 子目录前缀缓冲区(最多 3 层 = 8 字节 + null = 16 足够)
|
||||
SUBDIR_BUF_SIZE: t.CSizeT = 16
|
||||
subdir_buf: bytes = stdlib.malloc(SUBDIR_BUF_SIZE)
|
||||
if subdir_buf is None:
|
||||
return None
|
||||
subdir_buf[0] = '\0'
|
||||
# 子目录前缀:复用 Config.slice_subdir(SHA1 切片唯一权威实现,mbuddy 分配无需 free)
|
||||
subdir_buf: str = Config.slice_subdir(sha1, Config.Sha1SliceLevel)
|
||||
sub_len: t.CSizeT = 0
|
||||
level: int = Config.Sha1SliceLevel
|
||||
if level > 0:
|
||||
li: int = 0
|
||||
while li < level:
|
||||
if li > 0:
|
||||
subdir_buf[sub_len] = '/'
|
||||
sub_len += 1
|
||||
idx: int = li * 2
|
||||
subdir_buf[sub_len] = sha1[idx]
|
||||
subdir_buf[sub_len + 1] = sha1[idx + 1]
|
||||
sub_len += 2
|
||||
li += 1
|
||||
subdir_buf[sub_len] = '\0'
|
||||
if subdir_buf is not None:
|
||||
sub_len = string.strlen(subdir_buf)
|
||||
|
||||
# 确保子目录存在: {temp_dir}/{subdir}
|
||||
# 不创建目录会导致 fileio.File(MODE.W) 静默失败(file.closed==True),
|
||||
@@ -139,7 +125,6 @@ def _sliced_path(temp_dir: str, td_len: t.CSizeT, sha1: str, ext: str) -> str:
|
||||
if path is not None:
|
||||
viperlib.snprintf(path, path_len, "%s/%s.%s", temp_dir, sha1, ext)
|
||||
|
||||
stdlib.free(subdir_buf)
|
||||
return path
|
||||
|
||||
|
||||
@@ -222,10 +207,8 @@ def _collect_stub_sha1s(base_dir: str, bd_len: t.CSizeT, level: int,
|
||||
is_dot = 1
|
||||
if is_dot == 0:
|
||||
# 构建子目录路径并递归扫描
|
||||
fname_len: t.CSizeT = string.strlen(fname)
|
||||
sub_dir: str = stdlib.malloc(bd_len + fname_len + 2)
|
||||
sub_dir: str = Utils.JoinPath(base_dir, fname)
|
||||
if sub_dir is not None:
|
||||
viperlib.snprintf(sub_dir, bd_len + fname_len + 2, "%s/%s", base_dir, fname)
|
||||
sub_dir_len: t.CSizeT = string.strlen(sub_dir)
|
||||
out_count = _collect_stub_sha1s(sub_dir, sub_dir_len, level - 1, out_arr, out_count, max_count)
|
||||
stdlib.free(sub_dir)
|
||||
@@ -395,7 +378,7 @@ def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> in
|
||||
if full_path_buf is None:
|
||||
continue
|
||||
viperlib.snprintf(full_path_buf, rp_len + 10, "includes/%s", ent.RelPath)
|
||||
mod_name: str = _PathToModuleName(full_path_buf)
|
||||
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(_sha1_store_count) * 17
|
||||
@@ -467,7 +450,7 @@ def AppendToSha1MapStore(sha1: str, rel_path: str) -> int:
|
||||
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 = _PathToModuleName(full_path_buf)
|
||||
mod_name: str = Utils.PathToModuleName(full_path_buf, 1)
|
||||
stdlib.free(full_path_buf)
|
||||
if mod_name is None:
|
||||
return 1
|
||||
@@ -513,34 +496,8 @@ def GetSha1StoreCount() -> int:
|
||||
# SHA1 字符串指针(指向全局存储器内部,无需释放),None 未找到
|
||||
# ============================================================
|
||||
def LookupSha1ByModName(mod_name: str) -> str:
|
||||
"""从模块名查找 SHA1(精确匹配 + 包名回退)"""
|
||||
if mod_name is None:
|
||||
return None
|
||||
if _sha1_store_arr is None or _sha1_store_mod is None:
|
||||
return None
|
||||
if _sha1_store_count <= 0:
|
||||
return None
|
||||
# 第一遍:精确匹配
|
||||
i_em: int
|
||||
for i_em in range(_sha1_store_count):
|
||||
idx_em: t.CSizeT = t.CSizeT(i_em) * 64
|
||||
if string.strcmp(_sha1_store_mod + idx_em, mod_name) == 0:
|
||||
sidx_em: t.CSizeT = t.CSizeT(i_em) * 17
|
||||
return _sha1_store_arr + sidx_em
|
||||
# 第二遍:包名回退("ast" → "ast.__init__")
|
||||
nm_len_em: t.CSizeT = string.strlen(mod_name)
|
||||
init_buf_em: bytes = stdlib.malloc(nm_len_em + 12)
|
||||
if init_buf_em is not None:
|
||||
viperlib.snprintf(init_buf_em, nm_len_em + 12, "%s.__init__", mod_name)
|
||||
i_im: int
|
||||
for i_im in range(_sha1_store_count):
|
||||
idx2_im: t.CSizeT = t.CSizeT(i_im) * 64
|
||||
if string.strcmp(_sha1_store_mod + idx2_im, init_buf_em) == 0:
|
||||
sidx2_im: t.CSizeT = t.CSizeT(i_im) * 17
|
||||
stdlib.free(init_buf_em)
|
||||
return _sha1_store_arr + sidx2_im
|
||||
stdlib.free(init_buf_em)
|
||||
return None
|
||||
"""从模块名查找 SHA1(精确匹配 + 包名回退),委托通用实现 _FindSha1ByModName"""
|
||||
return _FindSha1ByModName(_sha1_store_arr, _sha1_store_mod, _sha1_store_count, mod_name)
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -1277,66 +1234,6 @@ def _LoadAndAppendTextDeclares(temp_dir: str, td_len: t.CSizeT, dep_sha1: str,
|
||||
return out_pos
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _PathToModuleName - 将文件路径转换为模块名
|
||||
#
|
||||
# 输入: "includes/stdio.vp" 或 "includes/lib/core/Handles/HandlesType.vp"
|
||||
# 输出: "stdio" 或 "lib.core.Handles.HandlesType"
|
||||
# 去除 includes/ 前缀和 .vp/.py 后缀,/ 替换为 .
|
||||
# 返回 stdlib.malloc 分配的字符串,调用者负责释放
|
||||
# ============================================================
|
||||
def _PathToModuleName(path: str) -> str:
|
||||
"""将文件路径转换为模块名
|
||||
|
||||
特殊处理 __init__.vp:includes/ast/__init__.vp → ast(而非 ast.__init__)
|
||||
"""
|
||||
if path is None:
|
||||
return None
|
||||
plen: t.CSizeT = string.strlen(path)
|
||||
# 跳过 includes/ 或 includes\ 前缀(Windows 反斜杠兼容)
|
||||
prefix_len: t.CSizeT = 9
|
||||
path_start: t.CSizeT = 0
|
||||
if plen > prefix_len and string.strncmp(path, "includes", 8) == 0:
|
||||
psep_ch: t.CChar = path[8]
|
||||
if psep_ch == '/' or psep_ch == '\\':
|
||||
path_start = prefix_len
|
||||
plen = plen - prefix_len
|
||||
# 去掉 .vp 或 .py 后缀(.vp 为 Viper 源,.py 向后兼容)
|
||||
if plen > 3:
|
||||
if (path[path_start + plen - 3] == '.' and path[path_start + plen - 2] == 'v' and path[path_start + plen - 1] == 'p') or (path[path_start + plen - 3] == '.' and path[path_start + plen - 2] == 'p' and path[path_start + plen - 1] == 'y'):
|
||||
plen -= 3
|
||||
if plen == 0:
|
||||
return None
|
||||
# 检查是否以 /__init__ 或 \__init__ 结尾(包的 __init__.vp)
|
||||
# /__init__ 是 9 个字符:/ _ _ i n i t _ _
|
||||
# 如果是,去掉分隔符+__init__ 后缀,模块名就是包名(如 ast/__init__ → ast)
|
||||
# 注意:顶级 __init__.vp(plen=8)不会进入此分支,因为 plen > 9 才检查
|
||||
# 同时支持 / 和 \ 两种分隔符(TPC 写入的路径可能混合使用)
|
||||
if plen > 9:
|
||||
tail_off: t.CSizeT = path_start + plen - 9
|
||||
sep_char: t.CChar = path[tail_off]
|
||||
if (sep_char == '/' or sep_char == '\\') \
|
||||
and path[tail_off + 1] == '_' and path[tail_off + 2] == '_' \
|
||||
and path[tail_off + 3] == 'i' and path[tail_off + 4] == 'n' and path[tail_off + 5] == 'i' \
|
||||
and path[tail_off + 6] == 't' and path[tail_off + 7] == '_' and path[tail_off + 8] == '_':
|
||||
# 去掉 分隔符+__init__ 后缀,plen 就是包名部分长度
|
||||
plen = tail_off - path_start
|
||||
if plen == 0:
|
||||
return None
|
||||
# 复制并替换 / 为 .
|
||||
result: str = stdlib.malloc(plen + 1)
|
||||
if result is None:
|
||||
return None
|
||||
for ri in range(plen):
|
||||
ch: t.CChar = path[path_start + ri]
|
||||
if ch == '/' or ch == '\\':
|
||||
result[ri] = '.'
|
||||
else:
|
||||
result[ri] = ch
|
||||
result[plen] = '\0'
|
||||
return result
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _BuildIncludesSha1Map - 从全局内存存储器构建 sha1 → module_name 映射
|
||||
#
|
||||
@@ -1554,26 +1451,11 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
||||
fname: str = find_data.cFileName
|
||||
if fname is not None:
|
||||
fname_len: t.CSizeT = string.strlen(fname)
|
||||
if fname_len > 3:
|
||||
is_py: int = 0
|
||||
# 检查 .vp 或 .py 扩展名(.vp 为 Viper 源,.py 向后兼容)
|
||||
if (fname[fname_len - 3] == '.' and fname[fname_len - 2] == 'v' and fname[fname_len - 1] == 'p') or (fname[fname_len - 3] == '.' and fname[fname_len - 2] == 'p' and fname[fname_len - 1] == 'y'):
|
||||
is_py = 1
|
||||
if is_py != 0:
|
||||
full_path: bytes = stdlib.malloc(dir_len + fname_len + 2)
|
||||
if Utils.is_vp_or_py_at(fname, 0, fname_len) != 0:
|
||||
full_path: bytes = Utils.JoinPath(source_dir, fname)
|
||||
if full_path is not None:
|
||||
viperlib.snprintf(full_path, dir_len + fname_len + 2, "%s/%s", source_dir, fname)
|
||||
sf: fileio.File | t.CPtr = fileio.File(full_path, fileio.MODE.R)
|
||||
if not sf.closed:
|
||||
sbuf: bytes = stdlib.malloc(SRC_BUF_SIZE_R)
|
||||
sbuf: bytes = Utils.read_file_to_buf(full_path, SRC_BUF_SIZE_R)
|
||||
if sbuf is not None:
|
||||
br: LONG = sf.read_all(sbuf, SRC_BUF_SIZE_R)
|
||||
sf.close()
|
||||
if br > 0:
|
||||
if br < SRC_BUF_SIZE_R:
|
||||
sbuf[br] = 0
|
||||
else:
|
||||
sbuf[SRC_BUF_SIZE_R - 1] = 0
|
||||
# 解析 AST 获取 _imported_modules
|
||||
lx: ast.Lexer | t.CPtr = ast.new_lexer(mb)
|
||||
if lx is not None:
|
||||
@@ -1609,10 +1491,6 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
||||
if tr._nonlocal_names is not None:
|
||||
stdlib.free(tr._nonlocal_names)
|
||||
stdlib.free(sbuf)
|
||||
else:
|
||||
stdlib.free(sbuf)
|
||||
else:
|
||||
sf.close()
|
||||
stdlib.free(full_path)
|
||||
|
||||
if win32file.FindNextFileA(handle, find_data) == 0:
|
||||
|
||||
Reference in new issue
Block a user