diff --git a/App/lib/core/Phase1.vp b/App/lib/core/Phase1.vp index c26291a..575f9a7 100644 --- a/App/lib/core/Phase1.vp +++ b/App/lib/core/Phase1.vp @@ -229,14 +229,17 @@ def _FindClassDefSha1(class_names_buf: bytes, def_sha1s_buf: bytes, # ============================================================ # _ScanTreeForContainers - 递归扫描 AST 检测 list/dict 容器使用 # -# 覆盖:裸名(list/dict)、泛型下标(list[T] 的 Subscript.value)、 -# 字面量([]/{})。命中即置 need_list/need_dict 标志。 -# 误报无害(最多多编译 _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 容器使用""" + """递归扫描 AST(字段 + 语句块),检测 list/dict 容器使用""" if node is None: return k_s: int = node.kind() @@ -249,15 +252,107 @@ def _ScanTreeForContainers(node: ast.AST | t.CPtr, need_dict_box[0] = 1 elif k_s == ast.ASTKind.Subscript: sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - if sub_s.value is not None: - _ScanTreeForContainers(sub_s.value, need_list_box, need_dict_box) + _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)