注释清理(65 文件 / 约 -2578 行 / 约 516 处):删除/压缩叙述式历史注释——多行根因叙事、工作代号段(D25/D30/N11/B5/S4/阶段E 等)、改前改后与先例叙述、逐条推导块,压成一行讲清作用信息;契约类注释(用途、参数与返回、关键约束与不变量、IR 结构说明)与被注释掉的代码一律保留 存疑 标记 6 处一字未动:StubMergerStore.vp、VpiReader.vp、VLogger.vp、AssignGenMixin.vp、CallGenLib.vp、CallGenLeafKit.vp 本次一并带入并行会话的代码改动(同批文件,按文件粒度无法拆分):fileio.File -> rowptr[fileio.File] 等 已知副作用/残留:① CallGenDispatch.vp 有 2 行非注释行的行尾被 LF->CRLF 规范化(纯字节变化,无文本改动);② core/Gen 区约 24 处压缩因并行会话整文件覆写被写回原样,尚未生效(StmtGenCifMixin/ClassGenVTable/FuncGenDef/ClassGenEnum/StructGenMixin/TypeSpec 等) 清单与复跑判据见 Debugger/comment_cleanup_summary.md(该目录不受版本控制)
506 lines
26 KiB
Plaintext
506 lines
26 KiB
Plaintext
import t, c
|
||
from stdint import *
|
||
import string
|
||
import stdlib
|
||
import memhub
|
||
import viperlib
|
||
import sys
|
||
import w32.fileio as fileio
|
||
import w32.win32file
|
||
import w32.win32base
|
||
import ast
|
||
import llvmlite
|
||
import lib.core.VLogger as VLogger
|
||
import lib.core.Gen.Translator as HandlesTranslator
|
||
import lib.core.IncludesScanner as IncludesScanner
|
||
import lib.Stub.StubMerger as StubMerger
|
||
import lib.core.Gen.Generator as GenGenerator
|
||
import lib.core.CompilerFactory as CompilerFactory
|
||
import lib.Phase.BuildPipeline as BuildPipeline
|
||
import lib.Projectrans.Config as Config
|
||
import lib.Stub.StubGen.Converter as StubConverter
|
||
import lib.Stub.StubMerger.StubMergerBuild as StubMergerBuild
|
||
import lib.Stub.StubMerger.StubMergerCollect as StubMergerCollect
|
||
import lib.Stub.StubMerger.StubMergerIR as StubMergerIR
|
||
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
|
||
|
||
import lib.Phase.Phase1.Phase1Scan as Phase1Scan
|
||
import lib.Phase.Phase1.Phase1Topo as Phase1Topo
|
||
import lib.Phase.Phase1 as Phase1
|
||
|
||
import lib.core.Gen.GenApi as GenApi
|
||
|
||
|
||
# ============================================================
|
||
# Phase1Scan - 扫描类继承关系、泛型类标记与容器使用
|
||
#
|
||
# 函数实现直接位于本模块,调用方经本模块前缀访问;全局符号经 Phase1._xxx 跨模块访问。
|
||
# ============================================================
|
||
|
||
# 拓扑排序使用扁平字节数组存储类信息和文件依赖,
|
||
# 避免结构体中的 str 指针字段在 mb.alloc 零填充时为 NULL 导致崩溃。
|
||
# 类名/父类名存储在 class_names_buf/parent_names_buf(每个 Phase1.CLASS_NAME_LEN 字节),
|
||
# 定义 SHA1 存储在 def_sha1s_buf(每个 Phase1.SHA1_LEN 字节)。
|
||
|
||
|
||
# ============================================================
|
||
# _ScanClassInheritance - 预扫描 includes 文件,收集类继承关系
|
||
#
|
||
# 遍历所有可达 includes 文件解析 AST,收集 ClassDef 的类名与父类名存入扁平字节数组,返回收集到的类数量。
|
||
#
|
||
# Args: mb 内存池;result IncludesScanner 扫描结果;reachable_set 可达 SHA1 集合;reachable_count 可达 SHA1 数量;use_reachable 是否使用可达集合过滤;
|
||
# sha1_set SHA1 集合(use_reachable=0 时使用);set_count SHA1 集合数量;class_names_buf 类名扁平数组(每个 Phase1.CLASS_NAME_LEN 字节);
|
||
# parent_names_buf 父类名扁平数组(每个 Phase1.CLASS_NAME_LEN 字节,无父类填 '\0');def_sha1s_buf 定义 SHA1 扁平数组(每个 Phase1.SHA1_LEN 字节)
|
||
# Returns: 收集到的类数量,-1 失败
|
||
# ============================================================
|
||
def _ScanClassInheritance(mb: rowptr[memhub.MemBuddy],
|
||
result: IncludesScanner.ScanResult | t.CPtr,
|
||
reachable_set: str, reachable_count: int,
|
||
use_reachable: int,
|
||
sha1_set: str, set_count: int,
|
||
class_names_buf: bytes,
|
||
parent_names_buf: bytes,
|
||
def_sha1s_buf: bytes,
|
||
generic_file_indices: t.CPtr,
|
||
generic_file_count_box: t.CPtr) -> int:
|
||
"""预扫描 includes 文件,收集类继承关系"""
|
||
if result is None:
|
||
return -1
|
||
# class_names_buf/parent_names_buf/def_sha1s_buf 由调用方 mb.alloc 分配(Phase1Main 预扫描前),本函数把其地址直接作为 strcpy 目的缓冲;
|
||
# 分配失败返回 NULL 时目的指针为近零地址 → strcpy 写零页(ASan access-violation),故按 fail-fast 显式报错终止(VLogger.error 内部 sys.exit(1)),不静默返回 -1。
|
||
if class_names_buf is None or parent_names_buf is None or def_sha1s_buf is None:
|
||
VLogger.error("类继承预扫描扁平缓冲分配失败(class_names_buf/parent_names_buf/def_sha1s_buf 为 NULL)", "Phase1")
|
||
|
||
entry_size: sizet = IncludesScanner.FileEntry.__sizeof__()
|
||
class_count: int = 0
|
||
|
||
for i in range(result.Count):
|
||
# 文件级 mark:收集完类继承信息后立即回收本文件 AST(可达 includes 全量 parse 的 AST 若驻留到 mark1 会耗尽 1GB 主池 OOM);
|
||
# class_names_buf/parent_names_buf/def_sha1s_buf 与 generic_file_indices 在调用前分配、位于本 mark 之前,reset 不影响。
|
||
scan_mark: sizet = mb.mark()
|
||
entry_addr: uint64 = uint64(result.Entries) + i * entry_size
|
||
entry: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
if entry is None or entry.Sha1 is None:
|
||
continue
|
||
|
||
sha1_e: str = entry.Sha1
|
||
file_has_generic: int = 0
|
||
|
||
# 按需翻译过滤
|
||
in_set: int = 0
|
||
if use_reachable != 0:
|
||
in_set = StubMergerCollect._is_in_sha1_set(sha1_e, reachable_set, reachable_count)
|
||
else:
|
||
in_set = StubMergerCollect._is_in_sha1_set(sha1_e, sha1_set, set_count)
|
||
if in_set == 0:
|
||
continue
|
||
|
||
# 读取文件
|
||
file_path: str = entry.Path
|
||
f: rowptr[fileio.File] = fileio.File(file_path, fileio.MODE.R)
|
||
if f.closed:
|
||
continue
|
||
|
||
# read_all 的容量参数含终止符(最多读 cap-1 字节), 文件更长会被静默截断
|
||
if f.size() >= Phase1.SRC_BUF_SIZE:
|
||
VLogger.error(f"源文件超过 {Phase1.SRC_BUF_SIZE} 字节上限, 拒绝读取: {file_path}", "Phase1")
|
||
f.close()
|
||
continue
|
||
|
||
src_buf: bytes = stdlib.malloc(Phase1.SRC_BUF_SIZE)
|
||
if src_buf is None:
|
||
f.close()
|
||
continue
|
||
|
||
bytes_read: LONG = f.read_all(src_buf, Phase1.SRC_BUF_SIZE)
|
||
f.close()
|
||
if bytes_read <= 0:
|
||
stdlib.free(src_buf)
|
||
continue
|
||
if bytes_read < Phase1.SRC_BUF_SIZE:
|
||
src_buf[bytes_read] = 0
|
||
|
||
# 解析 AST
|
||
lx: ast.Lexer | t.CPtr = ast.new_lexer(mb)
|
||
if lx is None:
|
||
stdlib.free(src_buf)
|
||
continue
|
||
ast._lexer_init(lx, src_buf, mb)
|
||
tokens: ast.Token | t.CPtr = ast.tokenize(lx)
|
||
tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens)
|
||
if tree is None:
|
||
stdlib.free(src_buf)
|
||
continue
|
||
|
||
# 遍历 AST 顶层节点,收集 ClassDef
|
||
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||
if ch is not None:
|
||
cn: sizet = len(ch)
|
||
for ci in range(cn):
|
||
child: ast.AST | t.CPtr = ch.get(ci)
|
||
if child is None:
|
||
continue
|
||
kd: int = child.kind()
|
||
if kd != ast.ASTKind.ClassDef:
|
||
continue
|
||
|
||
cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child)
|
||
if cd is None or cd.name is None:
|
||
continue
|
||
|
||
# 检测泛型类(有 type_params),记录文件索引以供 Phase 1a 预注册
|
||
if file_has_generic == 0:
|
||
tp_scan: list[str] | t.CPtr = cd.type_params
|
||
if tp_scan is not None:
|
||
file_has_generic = 1
|
||
if generic_file_count_box is not None:
|
||
gfc_ptr_scan: t.CPtr = (int | t.CPtr)(t.CVoid(generic_file_count_box, t.CPtr))
|
||
if gfc_ptr_scan is not None:
|
||
gfc_scan: int = gfc_ptr_scan[0]
|
||
if gfc_scan < Phase1.MAX_FILE_DEPS and generic_file_indices is not None:
|
||
gi_addr_scan: uint64 = uint64(generic_file_indices) + gfc_scan * 4
|
||
gi_ptr_scan: t.CPtr = (int | t.CPtr)(t.CVoid(gi_addr_scan, t.CPtr))
|
||
if gi_ptr_scan is not None:
|
||
gi_ptr_scan[0] = i
|
||
gfc_ptr_scan[0] = gfc_scan + 1
|
||
|
||
if class_count >= Phase1.MAX_CLASSES:
|
||
break
|
||
|
||
# 填充扁平数组:类名(偏移 = class_count * Phase1.CLASS_NAME_LEN)
|
||
name_dst: str = class_names_buf + class_count * Phase1.CLASS_NAME_LEN
|
||
nm_len: sizet = string.strlen(cd.name)
|
||
if nm_len >= Phase1.CLASS_NAME_LEN:
|
||
string.strncpy(name_dst, cd.name, Phase1.CLASS_NAME_LEN - 1)
|
||
name_dst[Phase1.CLASS_NAME_LEN - 1] = '\0'
|
||
else:
|
||
string.strcpy(name_dst, cd.name)
|
||
|
||
# 填充扁平数组:父类名(无父类填 '\0')
|
||
parent_dst: str = parent_names_buf + class_count * Phase1.CLASS_NAME_LEN
|
||
parent_dst[0] = '\0'
|
||
parent_nm: str = GenApi._get_parent_class(cd, None)
|
||
# parent_nm 是 AST 节点内部指针,不需要释放
|
||
if parent_nm is not None:
|
||
pnm_len: sizet = string.strlen(parent_nm)
|
||
if pnm_len >= Phase1.CLASS_NAME_LEN:
|
||
string.strncpy(parent_dst, parent_nm, Phase1.CLASS_NAME_LEN - 1)
|
||
parent_dst[Phase1.CLASS_NAME_LEN - 1] = '\0'
|
||
else:
|
||
string.strcpy(parent_dst, parent_nm)
|
||
|
||
# 填充扁平数组:定义 SHA1(偏移 = class_count * Phase1.SHA1_LEN)
|
||
sha1_dst: str = def_sha1s_buf + class_count * Phase1.SHA1_LEN
|
||
string.strcpy(sha1_dst, sha1_e)
|
||
|
||
class_count += 1
|
||
|
||
stdlib.free(src_buf)
|
||
# 回收本文件 AST/lexer/token(类名/父类/SHA1 已拷入扁平数组)
|
||
mb.reset_to(scan_mark)
|
||
|
||
return class_count
|
||
# ============================================================
|
||
# _BufHasGenericClassMarker - 文本扫描检测文件是否含泛型类标记
|
||
#
|
||
# 泛型类(PEP 695)语法: class Name[T]:(类名后紧跟 '[')。逐字节扫描找词边界 'class' 关键字,其后标识符后非空白是 '[' → 命中。
|
||
# 用于 _PreRegisterAllGenericTemplates 预注册前筛选,避免 parse 全部 98 个 includes 致 AST 驻留 mark1 前把 pool 推到 OOM。
|
||
# 误报(字符串/注释里的 "class X[")无害(多 parse 一个文件);漏报有害(泛型模板未预注册 → 悬空复发),故保守只匹配单行形式。
|
||
# ============================================================
|
||
def _BufHasGenericClassMarker(buf: bytes, blen: sizet) -> int:
|
||
"""文本扫描:buf 中是否有 'class 标识符[' 泛型类标记,返回 1/0"""
|
||
if buf is None or blen <= 6:
|
||
return 0
|
||
pos: sizet = 0
|
||
while pos + 5 < blen:
|
||
if buf[pos] == 'c' and buf[pos + 1] == 'l' and buf[pos + 2] == 'a' \
|
||
and buf[pos + 3] == 's' and buf[pos + 4] == 's':
|
||
# class 前是词边界(行首或非标识符字符)
|
||
prev_ok: int = 1
|
||
if pos > 0:
|
||
pc: char = buf[pos - 1]
|
||
if(pc >= 'a' and pc <= 'z') or(pc >= 'A' and pc <= 'Z') \
|
||
or(pc >= '0' and pc <= '9') or pc == '_':
|
||
prev_ok = 0
|
||
if prev_ok != 0:
|
||
p: sizet = pos + 5
|
||
# 跳过空白
|
||
while p < blen and(buf[p] == ' ' or buf[p] == '\t'):
|
||
p += 1
|
||
# 读类名标识符
|
||
if p < blen and((buf[p] >= 'a' and buf[p] <= 'z')
|
||
or(buf[p] >= 'A' and buf[p] <= 'Z') or buf[p] == '_'):
|
||
while p < blen and((buf[p] >= 'a' and buf[p] <= 'z')
|
||
or(buf[p] >= 'A' and buf[p] <= 'Z')
|
||
or(buf[p] >= '0' and buf[p] <= '9')
|
||
or buf[p] == '_'):
|
||
p += 1
|
||
# 类名后非空白是 '[' → 泛型类
|
||
while p < blen and(buf[p] == ' ' or buf[p] == '\t'):
|
||
p += 1
|
||
if p < blen and buf[p] == '[':
|
||
return 1
|
||
pos += 1
|
||
else:
|
||
pos += 1
|
||
return 0
|
||
# ============================================================
|
||
# _PreRegisterAllGenericTemplates - 预注册 includes 泛型类模板(mark1 前)
|
||
#
|
||
# 泛型模板表(GenericClassNames/GenericClassNodes/GenericClassSha1s/GenericClassFiles + 模板节点)是懒分配的跨文件持久表,
|
||
# 首次注册必须落在 mark1 之前才能跨 Phase1 1b(reset_to(mark1))与 Phase2(reset_to(mark2))存活;否则表与节点被 reset 回收,
|
||
# _find_generic_template 遍历悬空内存 strcmp 崩溃。本函数先文本扫描(_BufHasGenericClassMarker,不 parse)筛选出含泛型类的文件,
|
||
# 仅对命中文件用**永久池(perm_pool)**解析(模板节点与表直接进 perm_pool,跨 mark 永久存活、不占主 pool);重复注册由 _register_generic_template 内部查重跳过。
|
||
# ============================================================
|
||
def _PreRegisterAllGenericTemplates(mb: rowptr[memhub.MemBuddy],
|
||
result: IncludesScanner.ScanResult | t.CPtr) -> int:
|
||
"""预注册全部 includes 文件的泛型类模板,返回处理到的泛型类数量"""
|
||
if result is None or mb is None:
|
||
return 0
|
||
perm: rowptr[memhub.MemBuddy] = CompilerFactory.factory.PermPool
|
||
if perm is None:
|
||
return 0
|
||
p1e_size: sizet = IncludesScanner.FileEntry.__sizeof__()
|
||
handled_count: int = 0
|
||
for i in range(result.Count):
|
||
entry_addr_pg: uint64 = uint64(result.Entries) + i * p1e_size
|
||
entry_pg: IncludesScanner.FileEntry | t.CPtr = (
|
||
IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_pg, t.CPtr))
|
||
if entry_pg is None or entry_pg.Sha1 is None:
|
||
continue
|
||
# 读取文件
|
||
file_path_pg: str = entry_pg.Path
|
||
f_pg: rowptr[fileio.File] = fileio.File(file_path_pg, fileio.MODE.R)
|
||
if f_pg.closed:
|
||
continue
|
||
# read_all 的容量参数含终止符(最多读 cap-1 字节), 文件更长会被静默截断
|
||
if f_pg.size() >= Phase1.SRC_BUF_SIZE:
|
||
VLogger.error(f"源文件超过 {Phase1.SRC_BUF_SIZE} 字节上限, 拒绝读取: {file_path_pg}", "Phase1")
|
||
f_pg.close()
|
||
continue
|
||
src_buf_pg: bytes = stdlib.malloc(Phase1.SRC_BUF_SIZE)
|
||
if src_buf_pg is None:
|
||
f_pg.close()
|
||
continue
|
||
bytes_read_pg: LONG = f_pg.read_all(src_buf_pg, Phase1.SRC_BUF_SIZE)
|
||
f_pg.close()
|
||
if bytes_read_pg <= 0:
|
||
stdlib.free(src_buf_pg)
|
||
continue
|
||
if bytes_read_pg < Phase1.SRC_BUF_SIZE:
|
||
src_buf_pg[bytes_read_pg] = 0
|
||
# 文本扫描筛选:非泛型文件跳过(不 parse、不驻留,防 OOM)
|
||
if _BufHasGenericClassMarker(src_buf_pg, bytes_read_pg) == 0:
|
||
stdlib.free(src_buf_pg)
|
||
continue
|
||
# 泛型文件:永久池解析 → 注册模板(节点/表进 perm_pool,跨 reset 存活)
|
||
lx_pg: ast.Lexer | t.CPtr = ast.new_lexer(perm)
|
||
if lx_pg is None:
|
||
stdlib.free(src_buf_pg)
|
||
continue
|
||
ast._lexer_init(lx_pg, src_buf_pg, perm)
|
||
tokens_pg: ast.Token | t.CPtr = ast.tokenize(lx_pg)
|
||
tree_pg: ast.AST | t.CPtr = ast.parse_tokens(perm, tokens_pg)
|
||
if tree_pg is None:
|
||
stdlib.free(src_buf_pg)
|
||
continue
|
||
# 遍历顶层 ClassDef,注册泛型模板(type_params 非 None)
|
||
ch_pg: list[ast.AST | t.CPtr] | t.CPtr = tree_pg.children
|
||
if ch_pg is not None:
|
||
cn_pg: sizet = len(ch_pg)
|
||
for ci_pg in range(cn_pg):
|
||
child_pg: ast.AST | t.CPtr = ch_pg.get(ci_pg)
|
||
if child_pg is None or child_pg.kind() != ast.ASTKind.ClassDef:
|
||
continue
|
||
cd_pg: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child_pg)
|
||
if cd_pg is None or cd_pg.name is None:
|
||
continue
|
||
tp_pg: list[str] | t.CPtr = cd_pg.type_params
|
||
if tp_pg is None:
|
||
continue
|
||
GenApi.set_current_file_type(file_path_pg)
|
||
GenApi._register_generic_template(perm, cd_pg, entry_pg.Sha1)
|
||
handled_count += 1
|
||
stdlib.free(src_buf_pg)
|
||
if handled_count > 0:
|
||
VLogger.info(f"mark1 前永久池预注册 {handled_count} 个 includes 泛型类模板", "Phase1")
|
||
else:
|
||
VLogger.info(f"mark1 前永久池预注册 0 个泛型模板(扫描 {result.Count} 个文件,可能 marker 未命中或全量扫描失败)", "Phase1")
|
||
return handled_count
|
||
# ============================================================
|
||
# _FindClassDefSha1 - 在扁平数组中查找类名对应的定义文件 SHA1
|
||
#
|
||
# Args: class_names_buf 类名扁平数组;def_sha1s_buf 定义 SHA1 扁平数组;class_count 类数量;class_name 要查找的类名
|
||
# Returns: SHA1 字符串指针(指向 def_sha1s_buf 内部偏移),None 未找到
|
||
# ============================================================
|
||
def _FindClassDefSha1(class_names_buf: bytes, def_sha1s_buf: bytes,
|
||
class_count: int, class_name: str) -> str:
|
||
"""查找类名对应的定义文件 SHA1"""
|
||
if class_names_buf is None or def_sha1s_buf is None or class_name is None:
|
||
return None
|
||
for i in range(class_count):
|
||
name_ptr: str = class_names_buf + i * Phase1.CLASS_NAME_LEN
|
||
if string.strcmp(name_ptr, class_name) == 0:
|
||
return def_sha1s_buf + i * Phase1.SHA1_LEN
|
||
return None
|
||
# ============================================================
|
||
# _ScanTreeForContainers - 递归扫描 AST 检测 list/dict 容器使用
|
||
#
|
||
# TPV 的 AST 中语句块挂在 children,而表达式/注解树全部以结构体字段挂载(value/slice/func/args/annotation/targets/returns/bases/left/right 等);
|
||
# 只递归 children 会漏掉 list[...] | t.CPtr、list[...](...)、字段注解等非语句块位置,故每个节点先递归表达式承载字段、再递归 children。
|
||
# 命中即置 need_list/need_dict;误报无害(最多多编译两个空壳模块)。
|
||
# ============================================================
|
||
|
||
def _AnnIsContainer(ann: ast.AST | t.CPtr) -> int:
|
||
"""注解是否为 list/dict 容器(Name 裸名或 Subscript list[...]/dict[...])
|
||
|
||
数组初始化(t.CArray[...] / 裸数组注解)返回 0,避免 _ScanTreeForContainers
|
||
把数组字面量误判为 list 容器使用(FIX 2026-08-30,联动 Translator.vp 同修)。
|
||
"""
|
||
while ann is not None:
|
||
ak_c: int = ann.kind()
|
||
if ak_c == ast.ASTKind.Name:
|
||
nm_c: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ann)
|
||
if nm_c.id is not None:
|
||
if string.strcmp(nm_c.id, "list") == 0:
|
||
return 1
|
||
if string.strcmp(nm_c.id, "dict") == 0:
|
||
return 1
|
||
return 0
|
||
elif ak_c == ast.ASTKind.Subscript:
|
||
sub_c: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(ann)
|
||
ann = sub_c.value
|
||
else:
|
||
return 0
|
||
return 0
|
||
|
||
|
||
def _ScanTreeForContainers(node: ast.AST | t.CPtr,
|
||
need_list_box: t.CPtr,
|
||
need_dict_box: t.CPtr,
|
||
depth: int = 0):
|
||
"""递归扫描 AST(字段 + 语句块),检测 list/dict 容器使用"""
|
||
# 递归深度守卫:AST 损坏成自引用环(字段/children 回指祖先)时无限
|
||
# 递归直至栈耗尽(每个 includes 文件 parse 后必执行)。fail-fast 终止。
|
||
if depth > 128:
|
||
VLogger.error("容器扫描递归过深(AST 环或嵌套超过 128 层)", "Phase1")
|
||
if node is None:
|
||
return
|
||
k_s: int = node.kind()
|
||
if k_s == ast.ASTKind.Name:
|
||
nm_s: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||
if nm_s.id is not None:
|
||
if string.strcmp(nm_s.id, "list") == 0:
|
||
need_list_box[0] = 1
|
||
elif string.strcmp(nm_s.id, "dict") == 0:
|
||
need_dict_box[0] = 1
|
||
elif k_s == ast.ASTKind.Subscript:
|
||
sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
|
||
_ScanTreeForContainers(sub_s.value, need_list_box, need_dict_box, depth + 1)
|
||
_ScanTreeForContainers(sub_s.slice, need_list_box, need_dict_box, depth + 1)
|
||
elif k_s == ast.ASTKind.BinOp:
|
||
bop_s: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||
_ScanTreeForContainers(bop_s.left, need_list_box, need_dict_box, depth + 1)
|
||
_ScanTreeForContainers(bop_s.right, need_list_box, need_dict_box, depth + 1)
|
||
elif k_s == ast.ASTKind.Call:
|
||
cl_s2: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
|
||
_ScanTreeForContainers(cl_s2.func, need_list_box, need_dict_box, depth + 1)
|
||
cl_args_s: list[ast.AST | t.CPtr] | t.CPtr = cl_s2.args
|
||
if cl_args_s is not None:
|
||
na_s: sizet = len(cl_args_s)
|
||
i_a2: sizet
|
||
for i_a2 in range(na_s):
|
||
_ScanTreeForContainers(cl_args_s.get(i_a2), need_list_box, need_dict_box, depth + 1)
|
||
cl_kws_s: list[ast.AST | t.CPtr] | t.CPtr = cl_s2.keywords
|
||
if cl_kws_s is not None:
|
||
nk_s: sizet = len(cl_kws_s)
|
||
i_k2: sizet
|
||
for i_k2 in range(nk_s):
|
||
kw_s: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(cl_kws_s.get(i_k2))
|
||
if kw_s is not None:
|
||
_ScanTreeForContainers(kw_s.value, need_list_box, need_dict_box, depth + 1)
|
||
elif k_s == ast.ASTKind.Assign:
|
||
asn_s: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node)
|
||
_ScanTreeForContainers(asn_s.value, need_list_box, need_dict_box, depth + 1)
|
||
tgts_s: list[ast.AST | t.CPtr] | t.CPtr = asn_s.targets
|
||
if tgts_s is not None:
|
||
nt_s: sizet = len(tgts_s)
|
||
i_t2: sizet
|
||
for i_t2 in range(nt_s):
|
||
_ScanTreeForContainers(tgts_s.get(i_t2), need_list_box, need_dict_box, depth + 1)
|
||
elif k_s == ast.ASTKind.AnnAssign:
|
||
aa_s2: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||
_ScanTreeForContainers(aa_s2.annotation, need_list_box, need_dict_box, depth + 1)
|
||
_ScanTreeForContainers(aa_s2.value, need_list_box, need_dict_box, depth + 1)
|
||
elif k_s == ast.ASTKind.FunctionDef:
|
||
fn_s: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node)
|
||
_ScanTreeForContainers(fn_s.returns, need_list_box, need_dict_box, depth + 1)
|
||
fn_args_s: ast.Arguments | t.CPtr = fn_s.args
|
||
if fn_args_s is not None:
|
||
fa_s: list[ast.AST | t.CPtr] | t.CPtr = fn_args_s.args
|
||
if fa_s is not None:
|
||
nf_s: sizet = len(fa_s)
|
||
i_f2: sizet
|
||
for i_f2 in range(nf_s):
|
||
arg_s: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(fa_s.get(i_f2))
|
||
if arg_s is not None:
|
||
_ScanTreeForContainers(arg_s.annotation, need_list_box, need_dict_box, depth + 1)
|
||
elif k_s == ast.ASTKind.ClassDef:
|
||
cd_s: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(node)
|
||
bases_s: list[ast.AST | t.CPtr] | t.CPtr = cd_s.bases
|
||
if bases_s is not None:
|
||
nb_s: sizet = len(bases_s)
|
||
i_b2: sizet
|
||
for i_b2 in range(nb_s):
|
||
_ScanTreeForContainers(bases_s.get(i_b2), need_list_box, need_dict_box, depth + 1)
|
||
elif k_s == ast.ASTKind.Attribute:
|
||
at_s: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
|
||
_ScanTreeForContainers(at_s.value, need_list_box, need_dict_box, depth + 1)
|
||
elif k_s == ast.ASTKind.Tuple:
|
||
tu_s: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(node)
|
||
elts_s: list[ast.AST | t.CPtr] | t.CPtr = tu_s.elts
|
||
if elts_s is not None:
|
||
ne_s: sizet = len(elts_s)
|
||
i_e2: sizet
|
||
for i_e2 in range(ne_s):
|
||
_ScanTreeForContainers(elts_s.get(i_e2), need_list_box, need_dict_box, depth + 1)
|
||
elif k_s == ast.ASTKind.UnaryOp:
|
||
uop_s: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node)
|
||
_ScanTreeForContainers(uop_s.operand, need_list_box, need_dict_box, depth + 1)
|
||
elif k_s == ast.ASTKind.Expr:
|
||
ex_s: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(node)
|
||
_ScanTreeForContainers(ex_s.value, need_list_box, need_dict_box, depth + 1)
|
||
elif k_s == ast.ASTKind.Return:
|
||
rt_s: ast.Return | t.CPtr = (ast.Return | t.CPtr)(node)
|
||
_ScanTreeForContainers(rt_s.value, need_list_box, need_dict_box, depth + 1)
|
||
elif k_s == ast.ASTKind.Compare:
|
||
cp_s: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node)
|
||
_ScanTreeForContainers(cp_s.left, need_list_box, need_dict_box, depth + 1)
|
||
cps_s: list[ast.AST | t.CPtr] | t.CPtr = cp_s.comparators
|
||
if cps_s is not None:
|
||
nc_s: sizet = len(cps_s)
|
||
i_c2: sizet
|
||
for i_c2 in range(nc_s):
|
||
_ScanTreeForContainers(cps_s.get(i_c2), need_list_box, need_dict_box, depth + 1)
|
||
elif k_s == ast.ASTKind.BoolOp:
|
||
bo_s: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node)
|
||
bvs_s: list[ast.AST | t.CPtr] | t.CPtr = bo_s.values
|
||
if bvs_s is not None:
|
||
nv_s: sizet = len(bvs_s)
|
||
i_v2: sizet
|
||
for i_v2 in range(nv_s):
|
||
_ScanTreeForContainers(bvs_s.get(i_v2), need_list_box, need_dict_box, depth + 1)
|
||
# `[...]`/`{}` 字面量不触发 _list/_dict 导入:字面量广泛用于编译期常量列表(c.Asm 的 op/inp/out CLOBBER 参数)与数组数据初始化,并非容器使用;
|
||
# 容器的真实使用由类型位置检测覆盖(Name/Subscript 注解、Call.func 构造名)。
|
||
# elif k_s == ast.ASTKind.List:
|
||
# need_list_box[0] = 1
|
||
# elif k_s == ast.ASTKind.Dict:
|
||
# need_dict_box[0] = 1
|
||
# 递归语句块子节点
|
||
if node.children is not None:
|
||
ch_s: list[ast.AST | t.CPtr] | t.CPtr = node.children
|
||
n_s: sizet = len(ch_s)
|
||
ci_s: sizet
|
||
for ci_s in range(n_s):
|
||
_ScanTreeForContainers(ch_s.get(ci_s), need_list_box, need_dict_box, depth + 1)
|