- Gen 内部 1742 处 HandlesX.func() 改 self.Gen.Y.method() 链式调用 - 数据类/常量迁移 GenTypes.vp(10 类 + CLASS_META_*/META_*/SEQ_KIND_*/FIELD_MAX 等) - 管线/保留文件经 GenApi.vp 模块级入口(48 函数带类型注解,从 Gen 方法签名自动生成) - 删除 26 个纯委托 Handles 文件,仅留 5 个实体文件(Base/Translator/Expr/ExprCall/ExprCallTable) - 修复字段分裂:TypeGenErr CurrentFile/TraceCount 链式化;CallGenBase TempDir/Cexport 真源化
502 lines
24 KiB
Plaintext
502 lines
24 KiB
Plaintext
import lib.core.Gen.GenApi as GenApi
|
||
import t, c
|
||
from stdint import *
|
||
import string
|
||
import stdlib
|
||
import memhub
|
||
import viperlib
|
||
import w32.fileio as fileio
|
||
import w32.win32file
|
||
import w32.win32base
|
||
import ast
|
||
import llvmlite
|
||
import lib.core.VLogger as VLogger
|
||
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||
import lib.core.IncludesScanner as IncludesScanner
|
||
import lib.core.StubMerger as StubMerger
|
||
import lib.core.Gen.Generator as GenGenerator
|
||
import lib.core.CompilerFactory as CompilerFactory
|
||
import lib.core.BuildPipeline as BuildPipeline
|
||
import lib.Projectrans.Config as Config
|
||
import lib.StubGen.Converter as StubConverter
|
||
import lib.core.StubMergerBuild as StubMergerBuild
|
||
import lib.core.StubMergerCollect as StubMergerCollect
|
||
import lib.core.StubMergerIR as StubMergerIR
|
||
import lib.core.StubMergerStore as StubMergerStore
|
||
|
||
|
||
import lib.core.Phase1Topo as Phase1Topo
|
||
import lib.core.Phase1Main as Phase1Main
|
||
import lib.core.Phase1 as Phase1
|
||
|
||
# ============================================================
|
||
# Phase1Scan - Phase1 拆分(阶段 E):Phase1Scan
|
||
#
|
||
# 直接移动模式:函数迁至此模块,原 Phase1.vp 仅保留常量/_mbuddy;
|
||
# 调用方经本模块前缀访问。全局符号经 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: memhub.MemBuddy | t.CPtr,
|
||
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 or class_names_buf is None or parent_names_buf is None or def_sha1s_buf is None:
|
||
return -1
|
||
|
||
entry_size: t.CSizeT = 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 在调用前分配,
|
||
# 位于本 mark 之前,reset 不影响;generic_file_indices 同理)
|
||
scan_mark: t.CSizeT = mb.mark()
|
||
entry_addr: t.CUInt64T = t.CUInt64T(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: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R)
|
||
if f.closed:
|
||
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
|
||
else:
|
||
src_buf[Phase1.SRC_BUF_SIZE - 1] = 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: t.CSizeT = 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 = (t.CInt | 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: t.CUInt64T = t.CUInt64T(generic_file_indices) + gfc_scan * 4
|
||
gi_ptr_scan: t.CPtr = (t.CInt | 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: t.CSizeT = 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: t.CSizeT = 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
|
||
# (NewAstTest [52/68] pool 耗尽根因:1a-pre 已 parse 全部驻留,
|
||
# 预注册再全量 parse 等于翻倍)。
|
||
# 误报(字符串/注释里的 "class X[")无害(多 parse 一个文件);
|
||
# 漏报有害(泛型模板未预注册 → 悬空复发),模式保守匹配行内单行形式
|
||
# (TPV 源码泛型类均为单行 `class X[T]:`,grep 确认)。
|
||
# ============================================================
|
||
def _BufHasGenericClassMarker(buf: bytes, blen: t.CSizeT) -> int:
|
||
"""文本扫描:buf 中是否有 'class 标识符[' 泛型类标记,返回 1/0"""
|
||
if buf is None or blen <= 6:
|
||
return 0
|
||
pos: t.CSizeT = 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: t.CChar = 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: t.CSizeT = 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),
|
||
# mark2 > mark1)存活。现有 1a-pre-generic 只注册"可达"泛型文件;FuncTest
|
||
# 这类可达集合无泛型的项目,模板要等 Phase2 Phase A-pre-inc(mark2 之后)
|
||
# 翻译全部 includes 时才注册 → reset 回收表与节点 → _find_generic_template
|
||
# 遍历悬空内存 strcmp 崩溃。
|
||
# 本函数先文本扫描(_BufHasGenericClassMarker,不 parse、不驻留)筛选出
|
||
# 含泛型类的文件(全量 parse 会把 98 个 includes 的 AST 驻留 mark1 前 →
|
||
# NewAstTest [52/68] pool 耗尽 OOM),仅对命中的文件用**永久池(perm_pool)**
|
||
# 解析 → 模板节点与表直接进 perm_pool,跨 mark 永久存活、不占主 pool。
|
||
# 重复注册由 _register_generic_template 内部查重跳过。
|
||
# ============================================================
|
||
def _PreRegisterAllGenericTemplates(mb: memhub.MemBuddy | t.CPtr,
|
||
result: IncludesScanner.ScanResult | t.CPtr) -> int:
|
||
"""预注册全部 includes 文件的泛型类模板,返回处理到的泛型类数量"""
|
||
if result is None or mb is None:
|
||
return 0
|
||
perm: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool()
|
||
if perm is None:
|
||
return 0
|
||
p1e_size: t.CSizeT = IncludesScanner.FileEntry.__sizeof__()
|
||
handled_count: int = 0
|
||
for i in range(result.Count):
|
||
entry_addr_pg: t.CUInt64T = t.CUInt64T(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: fileio.File | t.CPtr = fileio.File(file_path_pg, fileio.MODE.R)
|
||
if f_pg.closed:
|
||
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
|
||
else:
|
||
src_buf_pg[Phase1.SRC_BUF_SIZE - 1] = 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: t.CSizeT = 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:
|
||
fb_gpre2: str = VLogger.fmt_buf()
|
||
if fb_gpre2 is not None:
|
||
viperlib.snprintf(fb_gpre2, 1024, "mark1 前永久池预注册 %d 个 includes 泛型类模板", handled_count)
|
||
VLogger.info(fb_gpre2, "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(BinOp
|
||
# 包裹)、list[...](...)(Call.func)、字段注解等一切非语句块位置。
|
||
# 因此每个节点先递归其表达式承载字段,再递归 children 语句块。
|
||
# 命中即置 need_list/need_dict;误报无害(最多多编译两个空壳模块)。
|
||
# ============================================================
|
||
def _ScanTreeForContainers(node: ast.AST | t.CPtr,
|
||
need_list_box: t.CPtr,
|
||
need_dict_box: t.CPtr):
|
||
"""递归扫描 AST(字段 + 语句块),检测 list/dict 容器使用"""
|
||
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)
|
||
_ScanTreeForContainers(sub_s.slice, need_list_box, need_dict_box)
|
||
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)
|
||
_ScanTreeForContainers(bop_s.right, need_list_box, need_dict_box)
|
||
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)
|
||
cl_args_s: list[ast.AST | t.CPtr] | t.CPtr = cl_s2.args
|
||
if cl_args_s is not None:
|
||
na_s: t.CSizeT = len(cl_args_s)
|
||
i_a2: t.CSizeT
|
||
for i_a2 in range(na_s):
|
||
_ScanTreeForContainers(cl_args_s.get(i_a2), need_list_box, need_dict_box)
|
||
cl_kws_s: list[ast.AST | t.CPtr] | t.CPtr = cl_s2.keywords
|
||
if cl_kws_s is not None:
|
||
nk_s: t.CSizeT = len(cl_kws_s)
|
||
i_k2: t.CSizeT
|
||
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)
|
||
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)
|
||
tgts_s: list[ast.AST | t.CPtr] | t.CPtr = asn_s.targets
|
||
if tgts_s is not None:
|
||
nt_s: t.CSizeT = len(tgts_s)
|
||
i_t2: t.CSizeT
|
||
for i_t2 in range(nt_s):
|
||
_ScanTreeForContainers(tgts_s.get(i_t2), need_list_box, need_dict_box)
|
||
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)
|
||
_ScanTreeForContainers(aa_s2.value, need_list_box, need_dict_box)
|
||
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)
|
||
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: t.CSizeT = len(fa_s)
|
||
i_f2: t.CSizeT
|
||
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)
|
||
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: t.CSizeT = len(bases_s)
|
||
i_b2: t.CSizeT
|
||
for i_b2 in range(nb_s):
|
||
_ScanTreeForContainers(bases_s.get(i_b2), need_list_box, need_dict_box)
|
||
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)
|
||
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: t.CSizeT = len(elts_s)
|
||
i_e2: t.CSizeT
|
||
for i_e2 in range(ne_s):
|
||
_ScanTreeForContainers(elts_s.get(i_e2), need_list_box, need_dict_box)
|
||
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)
|
||
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)
|
||
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)
|
||
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)
|
||
cps_s: list[ast.AST | t.CPtr] | t.CPtr = cp_s.comparators
|
||
if cps_s is not None:
|
||
nc_s: t.CSizeT = len(cps_s)
|
||
i_c2: t.CSizeT
|
||
for i_c2 in range(nc_s):
|
||
_ScanTreeForContainers(cps_s.get(i_c2), need_list_box, need_dict_box)
|
||
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: t.CSizeT = len(bvs_s)
|
||
i_v2: t.CSizeT
|
||
for i_v2 in range(nv_s):
|
||
_ScanTreeForContainers(bvs_s.get(i_v2), need_list_box, need_dict_box)
|
||
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: t.CSizeT = len(ch_s)
|
||
ci_s: t.CSizeT
|
||
for ci_s in range(n_s):
|
||
_ScanTreeForContainers(ch_s.get(ci_s), need_list_box, need_dict_box)
|