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
+358
-308
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 回退)
|
||||
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 时按别名注册)
|
||||
# `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:
|
||||
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,14 +2747,19 @@ 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:
|
||||
if existing_c.IsForwardDecl != 0:
|
||||
fill_fwd_c = 1
|
||||
else:
|
||||
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
|
||||
# REnum 类(class X(t.REnum))跳过:布局 {i32 __tag, <payload>} 由
|
||||
# ClassGenEnum._translate_renum_def 按变体计算;vpi 侧按普通 struct 注册
|
||||
@@ -2817,8 +2767,6 @@ def _inject_class_struct_declare(pool: memhub.MemBuddy*,
|
||||
# 留给源模块正式翻译注册。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 映射,填充全局存储器
|
||||
#
|
||||
|
||||
@@ -811,8 +811,8 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# _LookupMethodRetTyFromTextLL 的 strlen(0x1) 零页崩溃
|
||||
# (llvmlite/__init__.vp CreateGlobalInt 翻译时 0xC0000005 根因)。
|
||||
mod_ret_sha1: str = None
|
||||
# [MODSHA1] 诊断用:模块名(cl.func 为 Attribute 时赋值,否则保持 None)。
|
||||
# 声明在 if 外,使下方裸名兜底分支也能安全读取(读未声明的局部 = 栈垃圾)。
|
||||
# 模块路径(cl.func 为 Attribute 时赋值,否则保持 None)。声明在 if 外,
|
||||
# 使下方裸名兜底分支也能安全读取(读未声明的局部 = 栈垃圾)。
|
||||
mod_path_ret: str = None
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
at_ret: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
@@ -836,20 +836,6 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if trans is not None:
|
||||
fi_from_rt = trans._from_imports
|
||||
mod_ret_sha1 = self.Gen.StructGen._resolve_module_sha1(mod_path_ret, fi_from_rt)
|
||||
# [MODSHA1] 临时诊断(定位后删除):模块限定调用的模块名 → SHA1
|
||||
# 解析失败时,打印本模块名与对照模块名(stdint,必在 includes)
|
||||
# 的精确/后缀查询结果,区分「store 整体为空」与「store 有内容但
|
||||
# 缺该模块」。devfs.vp 的 string.split 报错即经此分支。
|
||||
if mod_ret_sha1 is None:
|
||||
dg_ex: str = self.Gen.CallGenBase._lookup_module_sha1(mod_path_ret)
|
||||
dg_sf: str = self.Gen.CallGenBase._lookup_module_sha1_suffix(mod_path_ret)
|
||||
dg_ctrl: str = self.Gen.CallGenBase._lookup_module_sha1("stdint")
|
||||
if dg_ex is None: dg_ex = "-"
|
||||
if dg_sf is None: dg_sf = "-"
|
||||
if dg_ctrl is None: dg_ctrl = "-"
|
||||
stdio.printf("[MODSHA1] mod='%s' fn='%s' exact=%s suffix=%s ctrl_stdint=%s line=%d\n",
|
||||
mod_path_ret, func_name, dg_ex, dg_sf, dg_ctrl, cl.lineno)
|
||||
stdio.fflush(None)
|
||||
if mod_ret_sha1 is not None:
|
||||
# 函数内懒 import:VpiReader imports HandlesExprCall,
|
||||
# 顶层 import 会成环(与 _lookup_method_ret_ty_via_vpi 一致)
|
||||
@@ -904,14 +890,6 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# 本遍仅临时占位。
|
||||
call_ret_ty = self.Gen.CallGenLib._infer_external_func_ret_ty(pool, func_name, node, 0)
|
||||
else:
|
||||
# [MODSHA1] 临时诊断(定位后删除):走到裸名兜底 ⇒ mod_ret_sha1 为
|
||||
# None。仅当 cl.func 仍是模块限定形态(Attribute)时打印——这正是
|
||||
# "模块限定却解析不出模块"的异常组合(此时 mod_path_ret 为 None
|
||||
# 说明 value 段不是 Name/Attribute;非 None 说明模块名查不到 SHA1)。
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
stdio.printf("[MODSHA1-D] mod='%s' fn='%s' line=%d\n",
|
||||
mod_path_ret, func_name, cl.lineno)
|
||||
stdio.fflush(None)
|
||||
# 裸名调用(cl.func 是 Name,mod_ret_sha1=None)两类来源:from-import 的函数(后续解析模块归属构造 mangled call_name 并经 text.ll/vpi 精确解析返回类型,可收敛)→ fatal_if_unknown=0 仅临时占位,不 fail-fast;纯外部 C 函数(无登记、无模块归属,白名单未命中)→ fail-fast(fatal_if_unknown=1)。闭包变量与持有函数指针/闭包的局部变量同样按可解析占位——返回类型由 translate_closure_call/lookup_var 路径固定处理,不依赖外部返回类型推断,否则被 fail-fast 误杀
|
||||
bare_resolvable: int = 0
|
||||
if self.Gen.CallGenLeafKit.is_closure_name(func_name) != 0:
|
||||
|
||||
@@ -94,16 +94,6 @@ novirtual class ClassGenDef(ClassGenBase.ClassGenBase):
|
||||
|
||||
# 检查是否已注册(用 SHA1 区分跨模块同名类)
|
||||
existing: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_module(class_name, trans.ModuleSha1)
|
||||
# [DBG-GEN] 一次性取证(用完删除)
|
||||
_dg_cd_isgen: int = 0
|
||||
if class_name is not None and string.strcmp(class_name, "Generator") == 0:
|
||||
_dg_cd_isgen = 1
|
||||
if existing is not None:
|
||||
stdio.printf("[DBG-GEN] classdef Generator EXISTING fcount=%d declare_only=%d\n",
|
||||
existing.FieldCount, trans._declare_only)
|
||||
else:
|
||||
stdio.printf("[DBG-GEN] classdef Generator EXISTING none declare_only=%d\n",
|
||||
trans._declare_only)
|
||||
# 空类注册不完整检测:existing FieldCount==0 但源类体声明了字段(vpi 注入/注册缺陷)。
|
||||
# 标记 _deps_pending 延迟会让空 entry 持久存在、多遍死锁不收敛 ⇒ 改为中和旧 entry
|
||||
# (置空 Name + Ty=None,使 find_struct_by_module 不再命中),走下方完整注册路径重建。
|
||||
@@ -609,9 +599,6 @@ novirtual class ClassGenDef(ClassGenBase.ClassGenBase):
|
||||
if entry is None:
|
||||
VLogger.error(f"failed to register {class_name}", "CLASS")
|
||||
return 0
|
||||
if _dg_cd_isgen != 0:
|
||||
stdio.printf("[DBG-GEN] classdef Generator REGISTER field_count=%d declare_only=%d\n",
|
||||
field_count, trans._declare_only)
|
||||
|
||||
# B5:记录 packed 标记到 StructEntry(供 __sizeof__/字段布局等派生查询)
|
||||
if is_packed_cd != 0:
|
||||
@@ -690,9 +677,6 @@ novirtual class ClassGenDef(ClassGenBase.ClassGenBase):
|
||||
if fe_c is not None:
|
||||
fe_c.IsConst = 1
|
||||
|
||||
if _dg_cd_isgen != 0:
|
||||
stdio.printf("[DBG-GEN] classdef Generator DONE fcount=%d\n", entry.FieldCount)
|
||||
|
||||
# Phase 1a 声明模式:只注册 struct + 设置 OOP 标志,不翻译方法体
|
||||
if trans._declare_only == 1:
|
||||
self.Gen.ClassGenVTable._translate_oop_methods(trans, cd, struct_ty, class_name, 1)
|
||||
|
||||
@@ -933,29 +933,6 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
# stub 空类 FieldCount=0,如 LARGE_INTEGER)→ 走下方真实报错
|
||||
# (lookup_field_by_class 已对空 stub 返回 None 而非 fatal)。
|
||||
if trans is not None:
|
||||
# [DBG-ATTR] 一次性取证(用完删除):任何属性访问失败都打印
|
||||
_db_pt: str = "<null>"
|
||||
if obj_ptr is not None and obj_ptr.Ty is not None:
|
||||
_db_b: str = pool.alloc(256)
|
||||
if _db_b is not None:
|
||||
_db_b[0] = '\0'
|
||||
llvmlite.TypePrint(_db_b, 256, obj_ptr.Ty, pool)
|
||||
_db_pt = _db_b
|
||||
_db_sn: str = "<non-struct>"
|
||||
_db_snm: str = llvmlite.get_struct_name(struct_ty)
|
||||
if _db_snm is not None:
|
||||
_db_sn = _db_snm
|
||||
_db_sc: int = -1
|
||||
_db_se: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_type(struct_ty)
|
||||
if _db_se is not None:
|
||||
_db_sc = _db_se.FieldCount
|
||||
stdio.printf("[DBG-ATTR] attr=%s obj_ptr.Ty=%s struct=%s fcount=%d\n",
|
||||
at.attr, _db_pt, _db_sn, _db_sc)
|
||||
_db_bc: str = "<null>"
|
||||
_db_bcv: str = self._resolve_attr_field_class(pool, trans, at.value, 1)
|
||||
if _db_bcv is not None:
|
||||
_db_bc = _db_bcv
|
||||
stdio.printf("[DBG-ATTR] base_class=%s\n", _db_bc)
|
||||
diag_annot: str = None
|
||||
diag_var_nm: str = None
|
||||
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||||
|
||||
@@ -544,6 +544,7 @@ def forward_declare_functions(trans: HT.Translator*, tree: ast.AST*) -> int:
|
||||
"""委托到 gen.forward_declare_functions(原 Handles 壳)"""
|
||||
if _g_gen is not None:
|
||||
return _g_gen.FuncGenDef.forward_declare_functions(trans, tree)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
|
||||
@@ -170,31 +170,26 @@ novirtual class ImportsGenMixin:
|
||||
def add_imported_module(self, pool: memhub.MemBuddy*,
|
||||
imported_modules: str,
|
||||
name: str) -> str:
|
||||
"""记录已导入的模块名,返回新的 imported_modules 字符串指针"""
|
||||
"""记录已导入的模块名,返回新的 imported_modules 字符串指针
|
||||
|
||||
字符串记账走 StubMergerStore.AppendImportedModule(单一真源,与 vpi
|
||||
注入期同源);本方法只额外维护查询索引。
|
||||
"""
|
||||
if name is None:
|
||||
return imported_modules
|
||||
old_len: sizet = 0
|
||||
if imported_modules is not None:
|
||||
old_len = string.strlen(imported_modules)
|
||||
buf: str = StubMergerStore.AppendImportedModule(pool, imported_modules, name)
|
||||
if buf is None:
|
||||
return imported_modules
|
||||
if imported_modules is None:
|
||||
nlen: sizet = string.strlen(name)
|
||||
buf: str = pool.alloc(nlen + 1)
|
||||
if buf is not None:
|
||||
string.strcpy(buf, name)
|
||||
# 索引:首个模块名(key 指向 buf 内部)
|
||||
self._index_imported_module(None, buf, buf)
|
||||
return buf
|
||||
return None
|
||||
else:
|
||||
old_len: sizet = string.strlen(imported_modules)
|
||||
name_len: sizet = string.strlen(name)
|
||||
new_len: sizet = old_len + 1 + name_len
|
||||
buf2: str = pool.alloc(new_len + 1)
|
||||
if buf2 is not None:
|
||||
string.strcpy(buf2, imported_modules)
|
||||
buf2[old_len] = ' '
|
||||
string.strcpy(buf2 + old_len + 1, name)
|
||||
# 索引:复用旧串索引并追加新名字(key 指向 buf2 内的 name 段)
|
||||
self._index_imported_module(imported_modules, buf2, buf2 + old_len + 1)
|
||||
return buf2
|
||||
return imported_modules
|
||||
# 索引:复用旧串索引并追加新名字(key 指向 buf 内的 name 段)
|
||||
self._index_imported_module(imported_modules, buf, buf + old_len + 1)
|
||||
return buf
|
||||
|
||||
# ============================================================
|
||||
# 检查模块是否已导入
|
||||
@@ -287,34 +282,26 @@ novirtual class ImportsGenMixin:
|
||||
无别名: "local_name:module_name"
|
||||
有别名: "local_name:module_name:original_name"
|
||||
(original_name 为源模块中的真实函数名,用于跨模块 SHA1 修饰)
|
||||
|
||||
字符串记账走 StubMergerStore.AppendFromImport(单一真源,与 vpi 注入期
|
||||
同源;按精确长度分配,无旧的 256 缓冲静默截断);本方法只额外维护索引。
|
||||
"""
|
||||
if local_name is None or module_name is None:
|
||||
return from_imports
|
||||
entry: str = pool.alloc(256)
|
||||
if entry is None:
|
||||
old_len: sizet = 0
|
||||
if from_imports is not None:
|
||||
old_len = string.strlen(from_imports)
|
||||
buf: str = StubMergerStore.AppendFromImport(
|
||||
pool, from_imports, local_name, module_name, original_name)
|
||||
if buf is None:
|
||||
return from_imports
|
||||
if original_name is not None and string.strcmp(original_name, local_name) != 0:
|
||||
viperlib.snprintf(entry, 256, "%s:%s:%s", local_name, module_name, original_name)
|
||||
else:
|
||||
viperlib.snprintf(entry, 256, "%s:%s", local_name, module_name)
|
||||
if from_imports is None:
|
||||
# 索引:首条 entry(local 从 entry 首字节开始,entry_off=0)
|
||||
self._index_from_import(None, entry, 0, local_name, module_name, original_name)
|
||||
return entry
|
||||
else:
|
||||
old_len: sizet = string.strlen(from_imports)
|
||||
entry_len: sizet = string.strlen(entry)
|
||||
new_len: sizet = old_len + 1 + entry_len
|
||||
buf: str = pool.alloc(new_len + 1)
|
||||
if buf is not None:
|
||||
string.strcpy(buf, from_imports)
|
||||
buf[old_len] = ' '
|
||||
string.strcpy(buf + old_len + 1, entry)
|
||||
# 索引:复用旧串索引并追加(entry 从 buf[old_len+1] 开始)
|
||||
self._index_from_import(from_imports, buf, old_len + 1,
|
||||
# 索引:首条 entry_off=0;追加时 entry 从 buf[old_len+1] 开始
|
||||
entry_off: sizet = 0
|
||||
if from_imports is not None:
|
||||
entry_off = old_len + 1
|
||||
self._index_from_import(from_imports, buf, entry_off,
|
||||
local_name, module_name, original_name)
|
||||
return buf
|
||||
return from_imports
|
||||
|
||||
# ============================================================
|
||||
# 查找 from-import 名称 → 返回原始函数名(别名场景)
|
||||
@@ -816,7 +803,18 @@ novirtual class ImportsGenMixin:
|
||||
# ============================================================
|
||||
def translate_import(self, trans: HT.Translator*,
|
||||
node: ast.AST*) -> int:
|
||||
"""处理 import 语句,返回 0"""
|
||||
"""处理 import 语句,返回 0
|
||||
|
||||
记账走 StubMergerStore.NotePlainImport(**该约定的唯一实现**):与 vpi
|
||||
注入期(VpiReader 顶层遍历)同口径,包含
|
||||
· `import X as Y` → from_imports 追加 "Y:X"(别名反查模块真名的唯一
|
||||
入口,见 StubMergerStore.LookupModNameByAlias);
|
||||
· `import a.b.c` → imported_modules 追加顶层包名 "a"。
|
||||
两侧各自只保留特有副作用(此处:导入 SHA1 校验)。
|
||||
注:NotePlainImport 为纯记账,不再续接 imported/from 两个查询索引 ⇒ 这两
|
||||
个串上的查找走 is_module_imported / lookup_from_import 的逐字符扫描回退
|
||||
(与 vpi 注入期上下文同款,正确性不受影响)。
|
||||
"""
|
||||
imp: ast.Import* = ast.Import*(node)
|
||||
if imp is None:
|
||||
return 0
|
||||
@@ -824,6 +822,11 @@ novirtual class ImportsGenMixin:
|
||||
if names is None:
|
||||
return 0
|
||||
nn: sizet = len(names)
|
||||
pool_val: memhub.MemBuddy* = trans.Pool
|
||||
ctx: StubMergerStore.ImportCtx* = StubMergerStore.AllocImportCtx(
|
||||
pool_val, trans._imported_modules, trans._from_imports)
|
||||
if ctx is None:
|
||||
return 0
|
||||
for ni in range(nn):
|
||||
alias: ast.Alias* = ast.Alias*(names.get(ni))
|
||||
if alias is not None and alias.name is not None:
|
||||
@@ -832,28 +835,9 @@ novirtual class ImportsGenMixin:
|
||||
# 尚未包含后续才追加的模块(如 App 源文件),检查会造成误报。
|
||||
if trans._declare_only == 0:
|
||||
self._check_import_sha1(node, alias.name)
|
||||
pool_val: memhub.MemBuddy* = trans.Pool
|
||||
im_val: str = trans._imported_modules
|
||||
trans._imported_modules = self.add_imported_module(pool_val, im_val, alias.name)
|
||||
# 别名也加入导入模块列表(用于模块限定构造器检查 Module.Class())
|
||||
if alias.asname is not None:
|
||||
trans._imported_modules = self.add_imported_module(pool_val, trans._imported_modules, alias.asname)
|
||||
# 别名也加入 from_imports(asname:fullname),
|
||||
# 使 HT.func() 跨模块调用能通过 from_imports 查找别名→完整模块名→SHA1
|
||||
# 否则 _lookup_module_sha1("HT") 找不到(mod_arr 只存文件名 HandlesTranslator)
|
||||
trans._from_imports = self.add_from_import(pool_val, trans._from_imports, alias.asname, alias.name)
|
||||
else:
|
||||
# 无别名时(import a.b.c),将顶层包名 "a" 也加入 _imported_modules,
|
||||
# 使 a.b.c 作为属性访问的 base 被翻译时能通过 is_module_imported("a") 检查
|
||||
dot_ptr: str = string.strstr(alias.name, ".")
|
||||
if dot_ptr is not None:
|
||||
pkg_len: sizet = sizet(uint64(dot_ptr) - uint64(alias.name))
|
||||
if pkg_len > 0 and pkg_len < 256:
|
||||
pkg_buf: bytes = pool_val.alloc(pkg_len + 1)
|
||||
if pkg_buf is not None:
|
||||
string.strncpy(pkg_buf, alias.name, pkg_len)
|
||||
pkg_buf[pkg_len] = '\0'
|
||||
trans._imported_modules = self.add_imported_module(pool_val, trans._imported_modules, pkg_buf)
|
||||
StubMergerStore.NotePlainImport(pool_val, ctx, alias.name, alias.asname)
|
||||
trans._imported_modules = ctx.ImportedModules
|
||||
trans._from_imports = ctx.FromImports
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
|
||||
@@ -594,34 +594,12 @@ novirtual class StructGenMixin:
|
||||
sha1 参数在注册时直接设置 ModuleSha1(避免 set_struct_sha1 找错 entry)。
|
||||
"""
|
||||
if self.init_struct_table(pool) == 0: return None
|
||||
# [DBG-GEN] 一次性取证(用完删除)
|
||||
_dg_isgen: int = 0
|
||||
if name is not None and string.strcmp(name, "Generator") == 0:
|
||||
_dg_isgen = 1
|
||||
_dg_sh0: str = "<null>"
|
||||
if sha1 is not None:
|
||||
_dg_sh0 = sha1
|
||||
_dg_tn0: str = "<null>"
|
||||
_dg_g0: str = llvmlite.get_struct_name(struct_ty)
|
||||
if _dg_g0 is not None:
|
||||
_dg_tn0 = _dg_g0
|
||||
stdio.printf("[DBG-GEN] register_struct IN name=Generator sha1=%s ty=%s count_before=%d\n",
|
||||
_dg_sh0, _dg_tn0, self.StructCount)
|
||||
# 用类型指针去重(同一类型不重复注册,支持跨模块同名类)
|
||||
# 用 uint64 指针值比较(is 比较会触发类型安全检查解引用悬空 Ty)
|
||||
# 走 find_struct_by_type(其 Ty 索引判定已整体停用、恢复原线性扫描),
|
||||
# 去重语义 = 原去重扫描"首个 Ty 指针相等条目"(首注册优先),逐字节一致。
|
||||
existing: GenTypes.StructEntry* = self.find_struct_by_type(struct_ty)
|
||||
if existing is not None:
|
||||
if _dg_isgen != 0:
|
||||
_dg_en: str = "<null>"
|
||||
if existing.Name is not None:
|
||||
_dg_en = existing.Name
|
||||
_dg_es: str = "<null>"
|
||||
if existing.ModuleSha1 is not None:
|
||||
_dg_es = existing.ModuleSha1
|
||||
stdio.printf("[DBG-GEN] register_struct DEDUP name=Generator -> existing name=%s sha1=%s fcount=%d\n",
|
||||
_dg_en, _dg_es, existing.FieldCount)
|
||||
return existing
|
||||
if self.StructCount >= STRUCT_MAX:
|
||||
VLogger.error(f"table full, cannot register {name}", "STRUCT")
|
||||
@@ -823,10 +801,6 @@ novirtual class StructGenMixin:
|
||||
if struct_entry.FieldCount >= FIELD_MAX:
|
||||
VLogger.error(f"field table full for {struct_entry.Name}", "STRUCT")
|
||||
return -1
|
||||
# [DBG-GEN] 一次性取证(用完删除)
|
||||
if struct_entry.Name is not None and string.strcmp(struct_entry.Name, "Generator") == 0:
|
||||
stdio.printf("[DBG-GEN] add_field Generator[%d] name=%s\n",
|
||||
struct_entry.FieldCount, field_name)
|
||||
idx: int = struct_entry.FieldCount
|
||||
fe: GenTypes.FieldEntry* = self._get_field_entry(struct_entry, idx)
|
||||
if fe is None: return -1
|
||||
@@ -1197,14 +1171,6 @@ novirtual class StructGenMixin:
|
||||
if self.StructCount < 0 or self.StructCount > 200000:
|
||||
VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct_by_module)", "STRUCT")
|
||||
stdlib.exit(1)
|
||||
# [DBG-GEN] 一次性取证(用完删除)
|
||||
_dg_fbm_isgen: int = 0
|
||||
if string.strcmp(name, "Generator") == 0:
|
||||
_dg_fbm_isgen = 1
|
||||
_dg_fbm_s: str = "<null>"
|
||||
if sha1 is not None:
|
||||
_dg_fbm_s = sha1
|
||||
stdio.printf("[DBG-GEN] find_struct_by_module IN name=Generator sha1=%s\n", _dg_fbm_s)
|
||||
if sha1 is not None:
|
||||
# 名索引快速路径:同名条目都位于 >= 首个同名下标处,故可从该下标起扫描
|
||||
# name+sha1(等价原全表扫描"首个 name 且 sha1 命中")。
|
||||
@@ -1221,14 +1187,9 @@ novirtual class StructGenMixin:
|
||||
if entry.ModuleSha1 is not None:
|
||||
# 同上:sha1 判等蕴含首字符相等,先比首字符再 strcmp。
|
||||
if entry.ModuleSha1[0] == sha1[0] and string.strcmp(entry.ModuleSha1, sha1) == 0:
|
||||
if _dg_fbm_isgen != 0:
|
||||
stdio.printf("[DBG-GEN] find_struct_by_module HIT name=Generator sha1=%s fcount=%d\n",
|
||||
entry.ModuleSha1, entry.FieldCount)
|
||||
return entry
|
||||
# SHA1 查找失败:不回退到 find_struct(会返回跨模块同名错误 entry)
|
||||
# 返回 None 让调用方创建新类型,避免 Phase B 用错误类型短路
|
||||
if _dg_fbm_isgen != 0:
|
||||
stdio.printf("[DBG-GEN] find_struct_by_module MISS name=Generator\n")
|
||||
return None
|
||||
# 无 SHA1:按类名查找第一个
|
||||
return self.find_struct(name)
|
||||
@@ -1396,43 +1357,6 @@ novirtual class StructGenMixin:
|
||||
if struct_ty is None or field_name is None or self.StructTable is None:
|
||||
return None
|
||||
|
||||
# [DBG-GEN] 一次性取证(用完删除)
|
||||
if string.strcmp(field_name, "FuncGenBase") == 0:
|
||||
_dg_ty: str = self._extract_struct_name(struct_ty)
|
||||
_dg_ty_t: str = "<non-struct>"
|
||||
if _dg_ty is not None:
|
||||
_dg_ty_t = _dg_ty
|
||||
stdio.printf("[DBG-GEN] lookup_field 'FuncGenBase' struct_ty=%s\n", _dg_ty_t)
|
||||
_dg_pm: GenTypes.StructEntry* = self.find_struct_by_type(struct_ty)
|
||||
if _dg_pm is not None:
|
||||
_dg_pn: str = "<null>"
|
||||
if _dg_pm.Name is not None:
|
||||
_dg_pn = _dg_pm.Name
|
||||
_dg_ps: str = "<null>"
|
||||
if _dg_pm.ModuleSha1 is not None:
|
||||
_dg_ps = _dg_pm.ModuleSha1
|
||||
stdio.printf("[DBG-GEN] ptr-match name=%s sha1=%s fcount=%d\n",
|
||||
_dg_pn, _dg_ps, _dg_pm.FieldCount)
|
||||
_dg_fi: int = 0
|
||||
while _dg_fi < _dg_pm.FieldCount:
|
||||
_dg_fe: GenTypes.FieldEntry* = self._get_field_entry(_dg_pm, _dg_fi)
|
||||
if _dg_fe is not None and _dg_fe.Name is not None:
|
||||
stdio.printf("[DBG-GEN] field[%d]=%s\n", _dg_fi, _dg_fe.Name)
|
||||
_dg_fi += 1
|
||||
else:
|
||||
stdio.printf("[DBG-GEN] ptr-match NONE\n")
|
||||
_dg_i: int = 0
|
||||
while _dg_i < self.StructCount:
|
||||
_dg_e: GenTypes.StructEntry* = self._get_struct_entry(_dg_i)
|
||||
if _dg_e is not None and _dg_e.Name is not None:
|
||||
if string.strstr(_dg_e.Name, "Generator") is not None:
|
||||
_dg_sh: str = "<null>"
|
||||
if _dg_e.ModuleSha1 is not None:
|
||||
_dg_sh = _dg_e.ModuleSha1
|
||||
stdio.printf("[DBG-GEN] tbl[%d] name=%s fcount=%d sha1=%s\n",
|
||||
_dg_i, _dg_e.Name, _dg_e.FieldCount, _dg_sh)
|
||||
_dg_i += 1
|
||||
|
||||
# ============================================================
|
||||
# 两遍查找策略(跨模块同名类冲突的根本修复):
|
||||
#
|
||||
|
||||
@@ -1997,6 +1997,23 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# 4b. mod 本身是完整模块路径(无别名 import)
|
||||
if sha1 is None:
|
||||
sha1 = self.Gen.CallGenBase._lookup_sha1_from_modname_raw(pool, mod_buf)
|
||||
# 4c. vpi 注入期:模块段 = 本 stub 自己的模块名(或其末段)⇒ 归属即
|
||||
# CurDefModuleSha1(inject_class 入口 mark_module_class 建立),
|
||||
# 与 Name 分支的注入窗口证据同口径:同一 stub 内写成
|
||||
# `自身模块名.类名`(无需 self-import)的指针注解据此前向声明为具名占位。
|
||||
if sha1 is None:
|
||||
inj_mod_a2: str = self.Gen.StructGen.CurDefModuleSha1
|
||||
if inj_mod_a2 is not None:
|
||||
inj_nm_a2: str = StubMergerStore.LookupModNameBySha1(inj_mod_a2)
|
||||
if inj_nm_a2 is not None:
|
||||
inj_seg_a2: str = inj_nm_a2
|
||||
dot_a2: str = string.strrchr(inj_nm_a2, '.')
|
||||
if dot_a2 is not None:
|
||||
inj_seg_a2 = dot_a2 + 1
|
||||
nm_eq_a2: int = string.strcmp(inj_nm_a2, mod_buf)
|
||||
seg_eq_a2: int = string.strcmp(inj_seg_a2, mod_buf)
|
||||
if nm_eq_a2 == 0 or seg_eq_a2 == 0:
|
||||
sha1 = inj_mod_a2
|
||||
elif k == ast.ASTKind.Name:
|
||||
nm: ast.Name* = ast.Name*(node)
|
||||
if nm.id is None:
|
||||
@@ -2010,6 +2027,23 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if sha1 is None:
|
||||
if self.Gen.StructGen.is_file_class(pool, cls_nm) != 0:
|
||||
sha1 = self.Gen.StructGen.get_file_module_sha1()
|
||||
# vpi 注入期的"本模块"归属:inject_class 入口已 mark_module_class(src_sha1,
|
||||
# real_name) 登记"{src_sha1}.{类名}"(**名字归属**,与 struct 是否已登记
|
||||
# 无关),并把 CurDefModuleSha1 指向本次注入的 stub 源模块。注入期
|
||||
# trans.ModuleSha1 是"正在翻译的文件"(≠ 被注入 stub 的模块),故上面
|
||||
# is_file_class 必然落空;而同一 stub 里**先声明**的类若本遍字段尚未解析
|
||||
# 成功(还没 register_struct),它的归属同样可判——据此前向声明为具名占位
|
||||
# "{src_sha1}.{类名}",而不是退化成 Ptr(i8)。
|
||||
# 现场:Translator.vp 的 `class Translator`(:84) 与 `class Mixin`(:1011),
|
||||
# 字段 `Mixin.Trans: Translator | t.CPtr` 在 Translator.vpi 注入到
|
||||
# CallGenLeafKit.vp 时解析(self.Trans.Pool 属性访问失败根因):若本遍
|
||||
# Translator 尚未登记就退化成 i8*,随后 Mixin 因 field_count>0 被判"注册
|
||||
# 成功"、i8* 被永久冻结(inject_class 的已注册检查直接早退)。
|
||||
if sha1 is None:
|
||||
inj_mod_n: str = self.Gen.StructGen.CurDefModuleSha1
|
||||
if inj_mod_n is not None:
|
||||
if self.Gen.StructGen.is_module_class(pool, inj_mod_n, cls_nm) != 0:
|
||||
sha1 = inj_mod_n
|
||||
else:
|
||||
return None
|
||||
if cls_nm is None or sha1 is None or sha1[0] == '\0':
|
||||
@@ -2229,6 +2263,43 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if nm.id is None or string.strcmp(nm.id, "t") != 0:
|
||||
return 0
|
||||
return 1
|
||||
def _is_tattr_marker(self, node: ast.AST*) -> int:
|
||||
"""检测节点是否为 `t.attr.<名>` 属性标记(含调用形 `t.attr.<名>(...)`)。
|
||||
|
||||
解析层把**类型位置**的前置 `__attribute__(...)` 经 `_MakeTAttrMarker` 脱糖为
|
||||
`t.attr.<名>` / `t.attr.<名>(...)`,再由 `_PrependDescriptorMarkers` 贴到类型
|
||||
联合的**最左操作数**位置。它**不是类型**:联合分支若把它当类型解析,会把
|
||||
`[]char`(= `t.CArray[char, None]` = i8*)的数组外壳吞掉退化成 i8——现场
|
||||
main.vp:44 `V_TPV_VERSION: __attribute__(section(".PRVERSN")) []char`
|
||||
生成 `@g = global i8 <getelementptr>` 非法 IR(opt: constant expression
|
||||
type mismatch: got type 'ptr' but expected 'i8')。
|
||||
"""
|
||||
if node is None:
|
||||
return 0
|
||||
inner: ast.AST* = node
|
||||
if inner.kind() == ast.ASTKind.Call:
|
||||
cl: ast.Call* = ast.Call*(inner)
|
||||
if cl.func is None:
|
||||
return 0
|
||||
inner = cl.func
|
||||
if inner.kind() != ast.ASTKind.Attribute:
|
||||
return 0
|
||||
at: ast.Attribute* = ast.Attribute*(inner)
|
||||
if at.attr is None or at.value is None:
|
||||
return 0
|
||||
if at.value.kind() != ast.ASTKind.Attribute:
|
||||
return 0
|
||||
root: ast.Attribute* = ast.Attribute*(at.value)
|
||||
if root.attr is None or root.value is None:
|
||||
return 0
|
||||
if root.value.kind() != ast.ASTKind.Name:
|
||||
return 0
|
||||
rn: ast.Name* = ast.Name*(root.value)
|
||||
if rn.id is None or string.strcmp(rn.id, "t") != 0:
|
||||
return 0
|
||||
if string.strcmp(root.attr, "attr") != 0:
|
||||
return 0
|
||||
return 1
|
||||
def _is_cvoid_marker(self, node: ast.AST*,
|
||||
imported_modules: str) -> int:
|
||||
"""检测节点是否为 CVoid 指针标记,返回 1=是 / 0=否"""
|
||||
@@ -2922,6 +2993,21 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# 代价是同一类型出现"裸名=指针 / 联合=再加一层"的分裂
|
||||
# (现场 includes/json/__init__.vp:90 CastError)。
|
||||
return own_entry.Ty
|
||||
# vpi 注入期:CurDefModuleSha1 = **本次注入的 stub 源模块**(inject_class 入口
|
||||
# 的 mark_module_class 建立)。注入期 trans.ModuleSha1 是"正在翻译的文件",
|
||||
# 故上面的本模块查找必然落空。此处按同一口径认"被注入 stub 自己声明的类":
|
||||
# 已登记条目、或先前由指针前向声明建立的具名占位,都返回原型(裸类名恒为原型,
|
||||
# 见上),使同一 stub 内"先声明/先被引用"的类在后继字段注解里口径一致,不再
|
||||
# 绕经"联合回退 → 前向声明 → 退化为 Ptr(i8)"那条链。
|
||||
# 注:此处**不新建**占位——值语义位置凭空建不透明原型会得到不可用布局;
|
||||
# 占位创建仍归 _forward_declare_ptr_from_node(指针语境)。
|
||||
if trans is not None and trans.ModuleSha1 is not None:
|
||||
inj_mod_rn: str = self.Gen.StructGen.CurDefModuleSha1
|
||||
if inj_mod_rn is not None:
|
||||
if string.strcmp(inj_mod_rn, trans.ModuleSha1) != 0:
|
||||
inj_e_rn: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_module(nm.id, inj_mod_rn)
|
||||
if inj_e_rn is not None and inj_e_rn.Ty is not None:
|
||||
return inj_e_rn.Ty
|
||||
# from-import 归属查找:注解里的裸名(或 import 别名)经 from_imports 定位到
|
||||
# 定义模块,再按 (name, sha1) 精确取类——这是 stub 注入场景的正解:此刻
|
||||
# trans.ModuleSha1 是"正在翻译的文件",而注解里的类归属 stub 源模块
|
||||
@@ -3143,6 +3229,24 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# 模块名 → sha1(精确/后缀/import 别名还原,统一经
|
||||
# StructGenMixin._resolve_module_sha1 逐级尝试)
|
||||
mod_sha1_v: str = self.Gen.StructGen._resolve_module_sha1(val_name.id, from_imports)
|
||||
# [vpi 注入窗口] 模块段恰为**本 stub 自己的模块名**(或其末段)时,
|
||||
# 归属即 CurDefModuleSha1(inject_class 入口 mark_module_class 建立)
|
||||
# ——与 Name 分支的注入窗口证据同口径:同一 stub 内写成
|
||||
# `自身模块名.类名`(无需 self-import)的注解不因"模块名未在
|
||||
# Sha1Store 登记"被判不可解析。
|
||||
if mod_sha1_v is None:
|
||||
inj_mod_a: str = self.Gen.StructGen.CurDefModuleSha1
|
||||
if inj_mod_a is not None:
|
||||
inj_nm_a: str = StubMergerStore.LookupModNameBySha1(inj_mod_a)
|
||||
if inj_nm_a is not None:
|
||||
inj_seg_a: str = inj_nm_a
|
||||
dot_a: str = string.strrchr(inj_nm_a, '.')
|
||||
if dot_a is not None:
|
||||
inj_seg_a = dot_a + 1
|
||||
nm_eq_a: int = string.strcmp(inj_nm_a, val_name.id)
|
||||
seg_eq_a: int = string.strcmp(inj_seg_a, val_name.id)
|
||||
if nm_eq_a == 0 or seg_eq_a == 0:
|
||||
mod_sha1_v = inj_mod_a
|
||||
mod_sha1_rv = mod_sha1_v
|
||||
if mod_sha1_v is not None:
|
||||
full_q_v: str = self._concat_sha1_class(pool, mod_sha1_v, at.attr)
|
||||
@@ -3458,10 +3562,20 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
li2 += 1
|
||||
return res_ty
|
||||
|
||||
# 无 CPtr 标记:返回第一个非 None(装饰器标记如 CExport/CExtern 被忽略)
|
||||
# 无 CPtr 标记:返回第一个**非属性标记**的类型侧。
|
||||
# 属性标记(t.attr.<名> / t.attr.<名>(...))不是类型,且解析层会把
|
||||
# 它们贴在联合的**最左操作数**位置(_PrependDescriptorMarkers)⇒ 若
|
||||
# 照旧先解析左边,会把这个标记当类型硬解,把真正的类型侧吞掉:
|
||||
# 现场 main.vp:44 `V_TPV_VERSION: __attribute__(section(".PRVERSN")) []char`
|
||||
# ⇒ 左边是 Call(t.attr.section),右边是 t.CArray[char, None](= i8*),
|
||||
# 结果丢掉数组外壳得到 i8,而初始化器按"指针模式"生成 getelementptr
|
||||
# → `@g = global i8 <ptr>` 非法 IR(opt: got 'ptr' but expected 'i8')。
|
||||
# 故标记侧**跳过**(既不参与竞争,也不进入解析)。
|
||||
if self._is_tattr_marker(bop.left) == 0:
|
||||
left_ty: llvmlite.LLVMType* = self.resolve_annotation_type(pool, bop.left, imported_modules, from_imports, trans, depth + 1)
|
||||
if left_ty is not None:
|
||||
return left_ty
|
||||
if self._is_tattr_marker(bop.right) == 0:
|
||||
right_ty: llvmlite.LLVMType* = self.resolve_annotation_type(pool, bop.right, imported_modules, from_imports, trans, depth + 1)
|
||||
if right_ty is not None:
|
||||
return right_ty
|
||||
|
||||
Reference in new issue
Block a user