fix(type): 统一注入期类归属与导入上下文记账,修占位表爆与属性标记误解析
- 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 属性访问失败)。
This commit is contained in:
1 parent
2c33effee1
commit
15b416b527
9 files changed
+460
-410
No files matched your search
@@ -1723,76 +1723,15 @@ def _extract_sha1_from_path(vpi_path: str) -> str:
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _stub_add_imported - 追加模块名到空格分隔列表(stub 上下文收集用)
|
||||
# stub 导入上下文记账:一律走 StubMergerStore(单一真源)
|
||||
#
|
||||
# 与 HandlesImports.add_imported_module 逻辑一致,但内联在本模块,
|
||||
# 避免 VpiReader → HandlesImports → StubMerger → VpiReader 循环依赖。
|
||||
# 原 _stub_add_imported / _stub_add_from 是本模块内的两份私有副本,与翻译期
|
||||
# ImportsGenMixin.add_imported_module / add_from_import 重复;其中 Import 分支
|
||||
# 只抄了 imported_modules 的追加,漏掉 from_imports 的别名映射,导致 vpi 注解
|
||||
# 前向声明解析不到模块 SHA1(GenTypes.VarEntry.Spec.PtrLevel 失败根因)。
|
||||
# 记账已统一到 StubMergerStore.AppendImportedModule / AppendFromImport /
|
||||
# NotePlainImport(纯记账、无索引副作用,正合 stub 上下文所需)。
|
||||
# ============================================================
|
||||
def _stub_add_imported(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
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _stub_add_from - 追加 from-import 映射("local:mod[:orig]" 空格分隔)
|
||||
# ============================================================
|
||||
def _stub_add_from(pool: memhub.MemBuddy*,
|
||||
cur: str, local: str, mod: str, orig: str) -> str:
|
||||
"""追加 from-import 映射(pool 分配),返回新列表
|
||||
|
||||
[D7·截断纪律] 旧实现固定 256 缓冲 + `snprintf("%s:%s[:%s]")`:三者合计超长即被
|
||||
**静默截断**,该条目在 ImportsGen 侧仍被当作合法条目解析出**错误的
|
||||
local/mod/orig** ⇒ 跨模块类名/别名还原取到错名字(D16 之后即污染
|
||||
Spec.SourceName 的来源名)。改为按精确长度分配,不存在上限。
|
||||
"""
|
||||
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
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -2137,6 +2076,10 @@ def _ParseVpiIntoModuleImpl(pool: memhub.MemBuddy*,
|
||||
# 解析注解——根治跨上下文误报(如 t.CArray[str] 需要 't' 已导入)。
|
||||
stub_imported_modules: str = None
|
||||
stub_from_imports: str = None
|
||||
# 记账统一走 StubMergerStore(单一真源,与翻译期 ImportsGenMixin.translate_import
|
||||
# 同口径):含 `import X as Y → from_imports "Y:X"`(别名反查模块真名)与
|
||||
# `import a.b.c → imported_modules "a"`(顶层包名)。
|
||||
stub_ctx: StubMergerStore.ImportCtx* = StubMergerStore.AllocImportCtx(pool, None, None)
|
||||
for si in range(n):
|
||||
schild: ast.AST* = ch.get(si)
|
||||
if schild is None:
|
||||
@@ -2149,9 +2092,7 @@ def _ParseVpiIntoModuleImpl(pool: memhub.MemBuddy*,
|
||||
for sni in range(sn_n):
|
||||
sal: ast.Alias* = ast.Alias*(simp.names.get(sni))
|
||||
if sal is not None and sal.name is not None:
|
||||
stub_imported_modules = _stub_add_imported(pool, stub_imported_modules, sal.name)
|
||||
if sal.asname is not None:
|
||||
stub_imported_modules = _stub_add_imported(pool, stub_imported_modules, sal.asname)
|
||||
StubMergerStore.NotePlainImport(pool, stub_ctx, sal.name, sal.asname)
|
||||
elif sk == ast.ASTKind.ImportFrom:
|
||||
sifr: ast.ImportFrom* = ast.ImportFrom*(schild)
|
||||
sifr_mod: str = sifr.module
|
||||
@@ -2219,7 +2160,9 @@ def _ParseVpiIntoModuleImpl(pool: memhub.MemBuddy*,
|
||||
string.strcpy(qbuf_r + pkg_len_r + 1, sifr_mod)
|
||||
sifr_mod_q = qbuf_r
|
||||
if sifr_mod is not None:
|
||||
stub_imported_modules = _stub_add_imported(pool, stub_imported_modules, sifr_mod_q)
|
||||
if stub_ctx is not None:
|
||||
stub_ctx.ImportedModules = StubMergerStore.AppendImportedModule(
|
||||
pool, stub_ctx.ImportedModules, sifr_mod_q)
|
||||
# 方案A:包 __init__.vpi 的重导出类以包 sha1 注册别名 entry
|
||||
# (ast.Attribute 定义在 ast.exprs 但归属 ast 包;查找端按包
|
||||
# sha1 匹配,注册端按定义文件 sha1 → name+sha1 错位 fail-fast。
|
||||
@@ -2283,22 +2226,31 @@ def _ParseVpiIntoModuleImpl(pool: memhub.MemBuddy*,
|
||||
for sifri in range(sifr_nn):
|
||||
sial: ast.Alias* = ast.Alias*(sifr.names.get(sifri))
|
||||
if sial is not None and sial.name is not None:
|
||||
# '*' star import 不建 from 映射(lookup 有 star 回退)
|
||||
slocal: str = sial.name
|
||||
sorig: str = None
|
||||
if sial.asname is not None:
|
||||
slocal = sial.asname
|
||||
sorig = sial.name
|
||||
# `from X import *` 亦写 "*:mod"(与翻译期
|
||||
# ImportsGenMixin.translate_from_import_names 同口径):
|
||||
# lookup_from_import 的 star 回退正是靠这条 entry,旧实现
|
||||
# 在此跳过 ⇒ stub 上下文里 star 回退恒失效(同一份约定
|
||||
# 的两处 loop 又一处不一致)。
|
||||
if stub_ctx is not None:
|
||||
stub_ctx.FromImports = StubMergerStore.AppendFromImport(
|
||||
pool, stub_ctx.FromImports, slocal, sifr_mod_q, sorig)
|
||||
# 重导出类以包 sha1 注册(asname 时按别名注册);star 无
|
||||
# 具体类名,不参与重导出(仅记账,见上)。
|
||||
if string.strcmp(sial.name, "*") != 0:
|
||||
slocal: str = sial.name
|
||||
sorig: str = None
|
||||
if sial.asname is not None:
|
||||
slocal = sial.asname
|
||||
sorig = sial.name
|
||||
stub_from_imports = _stub_add_from(
|
||||
pool, stub_from_imports, slocal, sifr_mod_q, sorig)
|
||||
# 重导出类以包 sha1 注册(asname 时按别名注册)
|
||||
if is_pkg_init_rt != 0 and sub_sha1_rt is not None:
|
||||
_inject_reexport_class_declare(
|
||||
pool, mod, sial.name, slocal,
|
||||
sub_sha1_rt, src_sha1, trans)
|
||||
|
||||
# 用 stub 自己的 imports 替代当前模块的(stub 注解解析上下文正确性)
|
||||
if stub_ctx is not None:
|
||||
stub_imported_modules = stub_ctx.ImportedModules
|
||||
stub_from_imports = stub_ctx.FromImports
|
||||
imported_modules: str = trans._imported_modules
|
||||
from_imports: str = trans._from_imports
|
||||
if stub_imported_modules is not None:
|
||||
@@ -2328,7 +2280,8 @@ def _ParseVpiIntoModuleImpl(pool: memhub.MemBuddy*,
|
||||
else:
|
||||
src_mod_buf[sri_src] = ch_src
|
||||
src_mod_buf[sr_len_src] = '\0'
|
||||
imported_modules = _stub_add_imported(pool, imported_modules, src_mod_buf)
|
||||
imported_modules = StubMergerStore.AppendImportedModule(
|
||||
pool, imported_modules, src_mod_buf)
|
||||
stdlib.free(src_mod_buf)
|
||||
|
||||
# 递归预注册 stub import 闭包的 CTypedef/CDefine:注解(如 codepage:
|
||||
@@ -2780,14 +2733,6 @@ def _inject_class_struct_declare(pool: memhub.MemBuddy*,
|
||||
flat_buf_c[p_len] = '_'
|
||||
string.strcpy(flat_buf_c + p_len + 1, cls_name)
|
||||
real_name = flat_buf_c
|
||||
# [DBG-GEN] 一次性取证(用完删除)
|
||||
_dg_v_isgen: int = 0
|
||||
if string.strcmp(real_name, "Generator") == 0:
|
||||
_dg_v_isgen = 1
|
||||
_dg_v_s: str = "<null>"
|
||||
if src_sha1 is not None:
|
||||
_dg_v_s = src_sha1
|
||||
stdio.printf("[DBG-GEN] vpi inject_class IN name=Generator src_sha1=%s\n", _dg_v_s)
|
||||
# REPL(ReplStubLayoutMode,见文件末"REPL:includes 类完整布局与虚表恢复"):
|
||||
# 本类若已由 .stub.ll 驱动的路径接管 ⇒ 这里整类让位——已登记(或本遍就地
|
||||
# 登记成功)只标可见;父类未就绪 ⇒ 本遍不登记(收尾遍补齐);布局不可信 ⇒
|
||||
@@ -2802,23 +2747,26 @@ def _inject_class_struct_declare(pool: memhub.MemBuddy*,
|
||||
if se.State == _REPL_SS_OK:
|
||||
GenApi.add_visible_struct(pool, real_name)
|
||||
return 1
|
||||
# 1. 已注册检查(含源模块编译时注册的 entry):仅标记可见,避免重复注册
|
||||
# 1. 已注册检查(含源模块编译时注册的 entry):仅标记可见,避免重复注册。
|
||||
# 例外:**前向声明占位**(IsForwardDecl != 0)不早退——必须走下方注册路径,
|
||||
# 并用「占位 Ty 原地写入」把字段体填进**同一个 Ty 对象**(见下方 fill_fwd_c 段)。
|
||||
# existing_c/fill_fwd_c 声明在 if 外:下方填充段要跨块读取。
|
||||
existing_c: GenTypes.StructEntry* = None
|
||||
fill_fwd_c: int = 0
|
||||
if src_sha1 is not None and src_sha1[0] != '\0':
|
||||
existing_c: GenTypes.StructEntry* = GenApi.find_struct_by_module(real_name, src_sha1)
|
||||
existing_c = GenApi.find_struct_by_module(real_name, src_sha1)
|
||||
if existing_c is not None and existing_c.Ty is not None:
|
||||
GenApi.add_visible_struct(pool, real_name)
|
||||
if _dg_v_isgen != 0:
|
||||
stdio.printf("[DBG-GEN] vpi inject_class EXISTING name=Generator fcount=%d\n",
|
||||
existing_c.FieldCount)
|
||||
return 1
|
||||
if existing_c.IsForwardDecl != 0:
|
||||
fill_fwd_c = 1
|
||||
else:
|
||||
GenApi.add_visible_struct(pool, real_name)
|
||||
return 1
|
||||
# REnum 类(class X(t.REnum))跳过:布局 {i32 __tag, <payload>} 由
|
||||
# ClassGenEnum._translate_renum_def 按变体计算;vpi 侧按普通 struct 注册
|
||||
# 会得到错误布局(变体字段都在嵌套类里,直接 AnnAssign 扫描得 0 字段)。
|
||||
# 留给源模块正式翻译注册。LLVMType 本就因 field_count==0 早退,此守卫把
|
||||
# 该行为显式化,避免将来 REnum 带直接字段时被误注册为普通 struct。
|
||||
if _vpi_class_is_renum(class_cd) != 0:
|
||||
if _dg_v_isgen != 0:
|
||||
stdio.printf("[DBG-GEN] vpi inject_class RENUM-SKIP name=Generator\n")
|
||||
return 0
|
||||
# 规则 5.5 的证据前置(**必须早于**下方字段注解解析):
|
||||
# 本函数在**注入期**解析字段注解(GenApi.resolve_annotation_type →
|
||||
@@ -2875,12 +2823,6 @@ def _inject_class_struct_declare(pool: memhub.MemBuddy*,
|
||||
pool, m_aa_c.annotation, imported_modules, from_imports, trans, 0)
|
||||
if field_ty_c is None:
|
||||
# 字段类型解析失败:不注册该类(留给源模块编译注册),不 fatal
|
||||
if _dg_v_isgen != 0:
|
||||
_dg_v_fn: str = "<null>"
|
||||
if m_tgt_c.id is not None:
|
||||
_dg_v_fn = m_tgt_c.id
|
||||
stdio.printf("[DBG-GEN] vpi inject_class FIELD-FAIL name=Generator field=%s\n",
|
||||
_dg_v_fn)
|
||||
return 0
|
||||
if field_count < GenTypes.FIELD_MAX:
|
||||
field_names_buf[field_count] = sizet(m_tgt_c.id)
|
||||
@@ -2889,8 +2831,6 @@ def _inject_class_struct_declare(pool: memhub.MemBuddy*,
|
||||
# 3. vpi 存根不含类字段(只序列化 class 名 + def 签名)→ field_count 恒为 0;注册空类会让源模块编译时 find_struct_by_module 命中空类
|
||||
# → "结构体已注册但字段数为0" InternalCompilerError。故改为不注册:依赖模块已编译时命中真实类(上方已处理),未编译时由 _deps_pending 多遍收敛。
|
||||
if field_count == 0:
|
||||
if _dg_v_isgen != 0:
|
||||
stdio.printf("[DBG-GEN] vpi inject_class EMPTY name=Generator\n")
|
||||
return 0
|
||||
# 4. 构建 ParamNode 链表
|
||||
first_node_c: rawptr[llvmlite.ParamNode] = None
|
||||
@@ -2935,6 +2875,22 @@ def _inject_class_struct_declare(pool: memhub.MemBuddy*,
|
||||
CompilerFactory.factory.PermPool, struct_ty_c)
|
||||
if st_copy_c is not None:
|
||||
struct_ty_c = st_copy_c
|
||||
# 5.5 前向声明占位命中 ⇒ **占位 Ty 原地写入**(与 ClassGenDef.translate_class_def
|
||||
# 的 fill_fwd 段逐句同款):给已存在的类型对象 `*existing.Ty` 赋入刚构建的
|
||||
# 字段体,并让 struct_ty_c 指向**同一个 Ty**。
|
||||
# 这是"不新建条目"的唯一正确做法:若此处让 struct_ty_c 保持新对象,下方
|
||||
# register_struct 按 **Ty 指针**去重就会 miss ⇒ 每一遍注入都追加一个新条目
|
||||
# ⇒ StructTable 爆表(现场:table full, cannot register Translator)。
|
||||
# 必须早于 module_add_named_type:避免同一名字先以占位名注册、又以新对象重复注册。
|
||||
if fill_fwd_c != 0 and existing_c is not None and existing_c.Ty is not None:
|
||||
fwd_name_c: str = llvmlite.get_struct_name(existing_c.Ty)
|
||||
fwd_fields_c: rawptr[llvmlite.ParamNode] = llvmlite.get_struct_fields(struct_ty_c)
|
||||
fwd_fc_c: int = llvmlite.get_struct_fcount(struct_ty_c)
|
||||
*existing_c.Ty = llvmlite.LLVMType.Struct(fwd_fields_c, fwd_fc_c, fwd_name_c)
|
||||
struct_ty_c = existing_c.Ty
|
||||
type_name_c = fwd_name_c
|
||||
existing_c.IsForwardDecl = 0
|
||||
existing_c.FieldCount = 0
|
||||
# 6. 注册到当前模块(输出类型定义行)+ 全局 StructTable + 可见性
|
||||
llvmlite.module_add_named_type(mod, pool, struct_ty_c)
|
||||
# B5:vpi 保留 @c.Attribute(t.attr.packed) 装饰器,stub 注入的跨模块
|
||||
@@ -2962,9 +2918,6 @@ def _inject_class_struct_declare(pool: memhub.MemBuddy*,
|
||||
af_ty_c: llvmlite.LLVMType* = (llvmlite.LLVMType*)(field_types_buf[afi_c])
|
||||
GenApi.add_field(pool, entry_c, af_name_c, af_ty_c)
|
||||
GenApi.add_visible_struct(pool, real_name)
|
||||
if _dg_v_isgen != 0:
|
||||
stdio.printf("[DBG-GEN] vpi inject_class REGISTERED name=Generator fcount=%d ty=%s\n",
|
||||
field_count, type_name_c)
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
@@ -29,6 +29,141 @@ 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 映射,填充全局存储器
|
||||
#
|
||||
|
||||
Reference in new issue
Block a user