修正了一些错误

This commit is contained in:
2026-07-26 20:32:26 +08:00
parent ca7c2120b8
commit 1837339f69
203 changed files with 374300 additions and 2638 deletions

View File

@@ -205,6 +205,15 @@ class ClassHandle(BaseHandle):
saved_block: ir.Block | None = None
if Gen.builder and Gen.builder.block and not Gen.builder.block.is_terminated:
saved_block = Gen.builder.block
# 切换 module_sha1 为泛型模板定义模块的 SHA1
# 使结构体类型名和方法定义名都用定义模块的 SHA1 前缀,
# 与调用端 _struct_sha1_map 查到的 SHA1 一致。
template_sha1: str | None = template.get('sha1')
saved_gen_sha1: str | None = getattr(Gen, 'module_sha1', None)
saved_trans_sha1: str | None = getattr(self.Trans, '_module_sha1', None)
if template_sha1:
Gen.module_sha1 = template_sha1
self.Trans._module_sha1 = template_sha1
try:
self._EmitClassLlvm(SpecNode, Gen, declare_only=declare_only)
finally:
@@ -219,6 +228,9 @@ class ClassHandle(BaseHandle):
Gen.var_signedness = saved_var_signedness
Gen.global_vars = saved_global_vars
self.Trans.VarScopes = saved_var_scopes
# 恢复原始 module_sha1
Gen.module_sha1 = saved_gen_sha1
self.Trans._module_sha1 = saved_trans_sha1
Gen._generic_class_specializations[spec_key] = (spec_name, declare_only)
# 缓存 type_args/type_names供后续 declare_only=False 完整特化补发方法体使用
# (如 _HandleMethodCallLlvm 中发现方法未定义时触发)
@@ -228,7 +240,10 @@ class ClassHandle(BaseHandle):
if not hasattr(self.Trans, '_generic_class_specializations'):
self.Trans._generic_class_specializations = {}
self.Trans._generic_class_specializations[spec_key] = spec_name
if hasattr(self.Trans, '_module_sha1') and self.Trans._module_sha1:
# 用模板定义模块的 SHA1 注册到 _struct_sha1_map与方法定义端一致
if template_sha1:
Gen._struct_sha1_map[spec_name] = template_sha1
elif hasattr(self.Trans, '_module_sha1') and self.Trans._module_sha1:
Gen._struct_sha1_map[spec_name] = self.Trans._module_sha1
return spec_name
@@ -460,9 +475,12 @@ class ClassHandle(BaseHandle):
if not hasattr(self, '_generic_class_templates'):
self._generic_class_templates = {}
type_params: list[str] = [tp.name for tp in Node.type_params]
# 记录泛型模板定义模块的 SHA1用于特化时统一命名空间
template_sha1: str | None = getattr(self.Trans, '_module_sha1', None)
self._generic_class_templates[ClassName] = {
'node': Node,
'type_params': type_params,
'sha1': template_sha1,
}
return
if self._is_exception_class(Node):

View File

@@ -7,6 +7,13 @@ from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta
import ast
import llvmlite.ir as ir
# [CDF-LOAD] 模块加载标记:用于确认修复后的代码被实际加载
try:
with open('d:/Users/TermiNexus/Desktop/TransPyC/_attr_debug.log', 'a', encoding='utf-8') as _f:
_f.write('[CDF-LOAD] HandlesExprAttr.py loaded (with CDefine fix)\n')
except Exception:
pass
class ExprAttrHandle(BaseHandle):
@@ -174,25 +181,44 @@ class ExprAttrHandle(BaseHandle):
return None
def _lookup_cdefine(self, Gen: LlvmCodeGenerator, VarName: str, AttrName: str) -> ir.Value | None:
"""在符号表和模块中查找 CDefine 常量值"""
imported_modules: Any = getattr(self.Trans, '_ImportedModules', None)
if not imported_modules:
return None
"""在符号表和模块中查找 CDefine 常量值
注意:不再强制依赖 _ImportedModules。即使该集合为空(例如自举编译
阶段尚未填充),也始终检查符号表与 Gen._define_constants确保
ast.CONST_INT 这类 CDefine 常量能够被解析为立即数而非全局变量引用。
"""
PossibleKeys: list[str] = [f"{VarName}.{AttrName}", AttrName]
for mod_name in imported_modules:
if mod_name.endswith(f".{VarName}") or mod_name == VarName:
key: str = f"{mod_name}.{AttrName}"
if key not in PossibleKeys:
PossibleKeys.append(key)
imported_modules: Any = getattr(self.Trans, '_ImportedModules', None)
if imported_modules:
for mod_name in imported_modules:
if mod_name.endswith(f".{VarName}") or mod_name == VarName:
key: str = f"{mod_name}.{AttrName}"
if key not in PossibleKeys:
PossibleKeys.append(key)
# 始终遍历符号表(不依赖 imported_modules 是否为空)
for lookup_key in PossibleKeys:
SymInfo: Any = self.Trans.SymbolTable.lookup(lookup_key)
if SymInfo and SymInfo.IsDefine and SymInfo.DefineValue is not None:
return self._make_define_constant(Gen, SymInfo.DefineValue)
# 也检查 _define_constants
# 也检查 _define_constantsLlvmGenerator 预扫描阶段填充)
define_constants: Any = getattr(Gen, '_define_constants', {})
for key in (f"{VarName}.{AttrName}", AttrName):
if key in define_constants:
return self._make_define_constant(Gen, define_constants[key])
# [CDF-DBG] CDefine 查找失败时的诊断输出
if AttrName in ('CONST_INT', 'CONST_FLOAT', 'CONST_STR', 'CONST_BOOL', 'CONST_NONE'):
_dbg_keys: list[str] = []
for _k in PossibleKeys:
_si: Any = self.Trans.SymbolTable.lookup(_k)
_dbg_keys.append(f"{_k}=>si={_si is not None},isdef={getattr(_si, 'IsDefine', None)},dv={getattr(_si, 'DefineValue', None)}")
_dc_keys: list[str] = [f"{k}=>{define_constants.get(k, '<miss>')}" for k in (f"{VarName}.{AttrName}", AttrName)]
try:
with open('d:/Users/TermiNexus/Desktop/TransPyC/_attr_debug.log', 'a', encoding='utf-8') as _f:
_f.write(f"[CDF-DBG] miss VarName={VarName} AttrName={AttrName} imported_modules={imported_modules}\n")
_f.write(f"[CDF-DBG] sym_keys={_dbg_keys}\n")
_f.write(f"[CDF-DBG] dc_keys={_dc_keys}\n")
except Exception:
pass
return None
def _lookup_module_global(self, Gen: LlvmCodeGenerator, VarName: str, AttrName: str) -> ir.Value | None:
@@ -394,6 +420,18 @@ class ExprAttrHandle(BaseHandle):
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
AttrName: str = Node.attr
# [HAN-DBG] 入口诊断:标记 CONST_* 属性访问
if AttrName in ('CONST_INT', 'CONST_FLOAT', 'CONST_STR', 'CONST_BOOL', 'CONST_NONE'):
_in_globals: bool = AttrName in Gen.module.globals
_gv_type: Any = None
if _in_globals:
_gv_type = str(Gen.module.globals[AttrName].type)
try:
with open('d:/Users/TermiNexus/Desktop/TransPyC/_attr_debug.log', 'a', encoding='utf-8') as _f:
_f.write(f"[HAN-DBG] enter VarName={VarName} AttrName={AttrName} in_globals={_in_globals} gv_type={_gv_type}\n")
except Exception:
pass
# __doc__ 魔法字符串:函数/结构体的 docstring
if AttrName == '__doc__':
doc_ptr: ir.Value | None = Gen._get_doc_ptr(VarName)
@@ -410,9 +448,26 @@ class ExprAttrHandle(BaseHandle):
if result is not None:
return result
# 冗余回退:直接以短名/全名查符号表的 CDefine 条目
# 覆盖 _ImportedModules 未填充但符号表已注册 CDefine 的场景
# (例如自举编译期 ast.CONST_INT 在 LlvmGenerator 预扫描阶段
# 已注册到 SymbolTable但 _ImportedModules 仍为空)。
for _cdefine_key in (AttrName, f"{VarName}.{AttrName}"):
_sym: Any = self.Trans.SymbolTable.lookup(_cdefine_key)
if _sym and _sym.IsDefine and _sym.DefineValue is not None:
_const_val: Any = self._make_define_constant(Gen, _sym.DefineValue)
if _const_val is not None:
return _const_val
# 尝试 import 模块全局变量
result = self._lookup_module_global(Gen, VarName, AttrName)
if result is not None:
if AttrName in ('CONST_INT', 'CONST_FLOAT', 'CONST_STR', 'CONST_BOOL', 'CONST_NONE'):
try:
with open('d:/Users/TermiNexus/Desktop/TransPyC/_attr_debug.log', 'a', encoding='utf-8') as _f:
_f.write(f"[HAN-DBG] module_global HIT VarName={VarName} AttrName={AttrName} result_type={result.type}\n")
except Exception:
pass
return result
# FakeDuck: 检查是否有影子结构体 a__meta__ (str 变量的 per-instance 字段存储)
@@ -433,6 +488,12 @@ class ExprAttrHandle(BaseHandle):
# 尝试 attr 直接作为全局变量(仅当 VarName 不是结构体变量时)
if not ClassName and AttrName in Gen.module.globals:
gv: Any = Gen.module.globals[AttrName]
if AttrName in ('CONST_INT', 'CONST_FLOAT', 'CONST_STR', 'CONST_BOOL', 'CONST_NONE'):
try:
with open('d:/Users/TermiNexus/Desktop/TransPyC/_attr_debug.log', 'a', encoding='utf-8') as _f:
_f.write(f"[HAN-DBG] FALLBACK_TO_GLOBAL VarName={VarName} AttrName={AttrName} gv_type={gv.type}\n")
except Exception:
pass
if AttrName in Gen.variables and Gen.variables[AttrName] is None:
str_gv_name: str = AttrName + '_str'
if str_gv_name in Gen.module.globals:
@@ -838,6 +899,20 @@ class ExprAttrHandle(BaseHandle):
def _HandleAttributeLlvm(self, Node: ast.Attribute) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
# [ATTR-DBG] 入口诊断:标记 CONST_* 属性访问的派发路径
if Node.attr in ('CONST_INT', 'CONST_FLOAT', 'CONST_STR', 'CONST_BOOL', 'CONST_NONE'):
_val_kind: str = type(Node.value).__name__
_val_id: str = ''
if isinstance(Node.value, ast.Name):
_val_id = Node.value.id
elif isinstance(Node.value, ast.Attribute):
_val_id = f"<Attribute attr={Node.value.attr}>"
try:
with open('d:/Users/TermiNexus/Desktop/TransPyC/_attr_debug.log', 'a', encoding='utf-8') as _f:
_f.write(f"[ATTR-DBG] dispatch Node.attr={Node.attr} value_kind={_val_kind} value_id={_val_id}\n")
except Exception:
pass
if isinstance(Node.value, ast.Name):
VarName: str = Node.value.id
# 处理 t/c import 的别名重定向
@@ -846,6 +921,12 @@ class ExprAttrHandle(BaseHandle):
src_module: str
src_name: str
src_module, src_name = t_c_imported[VarName]
if Node.attr in ('CONST_INT', 'CONST_FLOAT', 'CONST_STR', 'CONST_BOOL', 'CONST_NONE'):
try:
with open('d:/Users/TermiNexus/Desktop/TransPyC/_attr_debug.log', 'a', encoding='utf-8') as _f:
_f.write(f"[ATTR-DBG] REDIRECT VarName={VarName} -> src_module={src_module} src_name={src_name}\n")
except Exception:
pass
virtual_attr: ast.Attribute = ast.Attribute(
value=ast.Name(id=src_module, ctx=ast.Load()),
attr=src_name, ctx=ast.Load()
@@ -1388,10 +1469,13 @@ class ExprAttrHandle(BaseHandle):
return parts
def _try_resolve_nested_cdefine(self, Node: ast.Attribute) -> ir.Value | None:
"""尝试解析嵌套属性路径上的 CDefine 常量
注意:不再强制依赖 _ImportedModules。即使该集合为空如自举编译
早期阶段),也始终构建属性路径并检查符号表,确保 ast.CONST_INT
这类跨模块 CDefine 常量可被解析为立即数。
"""
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
imported_modules: Any = getattr(self.Trans, '_ImportedModules', None)
if not imported_modules:
return None
parts: list[str] = self._build_attr_path(Node)
if len(parts) < 2:
return None
@@ -1400,6 +1484,7 @@ class ExprAttrHandle(BaseHandle):
possible_keys: list[str] = [attr_name]
full_path: str = '.'.join(parts)
possible_keys.append(full_path)
imported_modules: Any = getattr(self.Trans, '_ImportedModules', None)
if module_parts:
ModulePath: str = '.'.join(module_parts)
resolved_first: str = self.Trans.SymbolTable.resolve_alias(module_parts[0])
@@ -1407,15 +1492,16 @@ class ExprAttrHandle(BaseHandle):
resolved_parts: list[str] = [resolved_first] + module_parts[1:]
resolved_path: str = '.'.join(resolved_parts)
possible_keys.append(f"{resolved_path}.{attr_name}")
for mod_name in imported_modules:
if mod_name.endswith('.' + ModulePath) or mod_name == ModulePath:
key: str = f"{mod_name}.{attr_name}"
if key not in possible_keys:
possible_keys.append(key)
if module_parts and (mod_name.endswith('.' + module_parts[-1]) or mod_name == module_parts[-1]):
key = f"{mod_name}.{attr_name}"
if key not in possible_keys:
possible_keys.append(key)
if imported_modules:
for mod_name in imported_modules:
if mod_name.endswith('.' + ModulePath) or mod_name == ModulePath:
key: str = f"{mod_name}.{attr_name}"
if key not in possible_keys:
possible_keys.append(key)
if module_parts and (mod_name.endswith('.' + module_parts[-1]) or mod_name == module_parts[-1]):
key = f"{mod_name}.{attr_name}"
if key not in possible_keys:
possible_keys.append(key)
for lookup_key in possible_keys:
SymInfo: Any = self.Trans.SymbolTable.lookup(lookup_key)
if SymInfo and SymInfo.IsDefine and SymInfo.DefineValue is not None:
@@ -1426,6 +1512,17 @@ class ExprAttrHandle(BaseHandle):
return ir.Constant(ir.IntType(32), val)
elif isinstance(val, float):
return ir.Constant(ir.FloatType(), val)
# 回退:检查 Gen._define_constantsLlvmGenerator 预扫描阶段填充)
define_constants: Any = getattr(Gen, '_define_constants', {})
for key in (attr_name, full_path):
if key in define_constants:
val: Any = define_constants[key]
if isinstance(val, int):
if val > 0x7FFFFFFF or val < -0x80000000:
return ir.Constant(ir.IntType(64), val & 0xFFFFFFFFFFFFFFFF)
return ir.Constant(ir.IntType(32), val)
elif isinstance(val, float):
return ir.Constant(ir.FloatType(), val)
return None
def _try_resolve_cross_module_enum(self, module_alias: str, enum_class_name: str, member_name: str) -> ir.Value | None:

View File

@@ -1562,30 +1562,127 @@ class ExprCallHandle(BaseHandle):
if not Node.args:
return None
type_info = None
MergeException = None
try:
type_info = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Node.func)
except Exception as _e:
MergeException = _e
if _config_mode == "strict":
raise
_vlog().warning(f"解析类型失败: {_e}", "Exception")
if not isinstance(type_info, CTypeInfo):
return None
target_type_str = type_info.ToString()
IsPtr = type_info.IsPtr
if IsPtr and target_type_str and '*' not in target_type_str:
target_type_str += ' *'
if not target_type_str:
return None
if type_info.IsPtr and not IsPtr:
IsPtr = True
if '*' not in target_type_str:
if isinstance(type_info, CTypeInfo):
# 主路径MergeTypes 成功返回 CTypeInfo沿用原有逻辑生成类型字符串
target_type_str = type_info.ToString()
IsPtr = type_info.IsPtr
if IsPtr and target_type_str and '*' not in target_type_str:
target_type_str += ' *'
if isinstance(type_info.Storage, t.CExport) or isinstance(type_info.Storage, t.CExtern):
pass
if type_info.IsState:
Gen._export_funcs.add('_type_union_cast')
if not target_type_str:
# FallbackToString 返回空字符串时,尝试手动从 BinOp 提取类型字符串
_vlog().warning(
f"_HandleTypeUnionCastLlvm: ToString 返回空字符串,启用 fallback 手动解析 "
f"(type_info={type_info!r})"
)
target_type_str = self._ExtractTypeStrFromUnionBinOp(Node.func)
if target_type_str and type_info.IsPtr and not IsPtr:
if '*' not in target_type_str:
target_type_str += ' *'
if isinstance(type_info.Storage, t.CExport) or isinstance(type_info.Storage, t.CExtern):
pass
if type_info.IsState:
Gen._export_funcs.add('_type_union_cast')
else:
# Fallback 路径MergeTypes 失败(返回 None 或抛异常)时,手动从 BinOp 提取类型信息
# 处理 (BaseType | t.CPtr) 这种模式,手动解析为 "{BaseType} *"
_vlog().warning(
f"_HandleTypeUnionCastLlvm: MergeTypes 未返回 CTypeInfo "
f"(type_info={type_info!r}, exception={MergeException!r}),启用 fallback 手动解析"
)
target_type_str = self._ExtractTypeStrFromUnionBinOp(Node.func)
if not target_type_str:
# Fallback 也无法解析:记录详细诊断信息后返回 None
_vlog().warning(
f"_HandleTypeUnionCastLlvm: fallback 解析失败,无法确定目标类型 "
f"(Node.func={ast.dump(Node.func)})"
)
return None
return self._HandleTypeCastLlvm(Node.args[0], target_type_str)
def _ExtractTypeStrFromUnionBinOp(self, NodeFunc: ast.AST) -> str | None:
"""Fallback从类型联合 BinOp 手动提取类型字符串。
处理 (BaseType | t.CPtr) 这种模式,手动解析为 "{BaseType} *"
支持嵌套的 | 操作(如 (t.CInt | t.CPtr) | t.CStatic
策略:
- 递归展平所有 | 操作数
- t.CPtr 视为指针修饰符(生成 "{BaseType} *" 格式)
- 其他 CType 子类作为基础类型(取第一个)
- 跳过存储类/限定符修饰符CExport/CExtern/CStatic/CConst/CVolatile/CInline 等)
"""
if not isinstance(NodeFunc, ast.BinOp) or not isinstance(NodeFunc.op, ast.BitOr):
return None
# 存储类/限定符/修饰符类型名集合:这些类型在类型联合中只起修饰作用,
# 不是基础类型,应跳过(参考 HandlesTypeMerge._GetCTypeInfoInternal 的分类逻辑)
StorageQualifierNames = {
'CArrayPtr', 'CConst', 'CVolatile', 'CInline',
'CStatic', 'CExtern', 'CExport', 'CAuto', 'CRegister',
'CDefine', 'CPass', 'CTypeDefault', 'State',
'BigEndian', 'LittleEndian',
}
# 递归展平所有 | 操作数
Operands = []
def CollectOperands(node: ast.AST) -> None:
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
CollectOperands(node.left)
CollectOperands(node.right)
else:
Operands.append(node)
CollectOperands(NodeFunc)
HasCPtr = False # 是否包含 t.CPtr指针修饰符
BaseTypeName = None # 基础类型名(如 "CInt"、"CChar"
for Operand in Operands:
AttrName = None
if isinstance(Operand, ast.Attribute):
AttrName = Operand.attr
elif isinstance(Operand, ast.Name):
AttrName = Operand.id
else:
continue
# t.CPtr 是指针修饰符,单独处理(增加一层 *
if AttrName == 'CPtr':
HasCPtr = True
continue
# 跳过存储类/限定符/修饰符类型,它们不是基础类型
if AttrName in StorageQualifierNames:
continue
# 通过 t 模块获取类型类,验证是否为 CType 子类
TypeClass = getattr(t, AttrName, None)
if not (isinstance(TypeClass, type) and issubclass(TypeClass, t.CType)):
# 非 CType 类,跳过
continue
# 记录第一个非 CPtr 基础类型
if BaseTypeName is None:
BaseTypeName = AttrName
if not BaseTypeName:
return None
# 包含 t.CPtr 时,生成 "{BaseType} *" 格式
# _CType2LLVM 已验证能解析 "CInt *" → i32*ir.PointerType(ir.IntType(32))
if HasCPtr:
return f"{BaseTypeName} *"
return BaseTypeName
def _HandleTypeCastLlvm(self, expr_node: ast.AST, target_type_str: str) -> ir.Value | None:
Gen = self.Trans.LlvmGen
val = self.HandleExprLlvm(expr_node)

View File

@@ -336,6 +336,19 @@ class ExprOpsHandle(BaseHandle):
}
result: bool = cmp_map.get(ComparatorSymbol, False)
return ir.Constant(ir.IntType(1), 1 if result else 0)
# is / is not: 值类型IntType与 None空指针常量比较
# 值类型(如 i8/i32永远不可能为 None因此
# - 值类型 is None → 恒为 false (i1 0)
# - 值类型 is not None → 恒为 true (i1 1)
# 此检查必须在类型对齐之前,否则类型对齐会对 i8* null 执行 load空指针解引用导致崩溃
if ComparatorSymbol in ('is', 'is not'):
LeftIsNullPtr: bool = isinstance(LeftVal, ir.Constant) and LeftVal.constant is None and isinstance(LeftVal.type, ir.PointerType)
RightIsNullPtr: bool = isinstance(RightVal, ir.Constant) and RightVal.constant is None and isinstance(RightVal.type, ir.PointerType)
LeftIsValueType: bool = isinstance(LeftVal.type, ir.IntType)
RightIsValueType: bool = isinstance(RightVal.type, ir.IntType)
if (LeftIsValueType and RightIsNullPtr) or (RightIsValueType and LeftIsNullPtr):
IsNotResult: int = 1 if ComparatorSymbol == 'is not' else 0
return ir.Constant(ir.IntType(1), IsNotResult)
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
if LeftVal.type.width < RightVal.type.width:
# 如果宽类型常量值超出窄类型有符号范围则必须用zext

View File

@@ -356,9 +356,21 @@ class ImportHandle(BaseHandle):
if not hasattr(self.Trans.ClassHandler, '_generic_class_templates'):
self.Trans.ClassHandler._generic_class_templates = {}
type_params = [tp.name for tp in node.type_params]
# 保留 prescan 阶段已注册的 sha1若无则从 _ModuleSha1Map 查找,
# 避免覆盖带 sha1 的注册导致特化时 SHA1 前缀丢失
existing = self.Trans.ClassHandler._generic_class_templates.get(node.name)
template_sha1 = existing.get('sha1') if existing else None
if template_sha1 is None:
msm = getattr(self.Trans, '_ModuleSha1Map', None)
if msm:
for lookup_name in (file_module_name, module_name, actual_module_name):
if lookup_name and lookup_name in msm:
template_sha1 = msm[lookup_name]
break
self.Trans.ClassHandler._generic_class_templates[node.name] = {
'node': node,
'type_params': type_params,
'sha1': template_sha1,
}
# 治本修复:使用 file_module_name源模块名而非 module_name可能是别名/类名)。
# 这样 _EmitExternalClassDeclLlvm 内的 ModuleSha1Map 查找才能命中,
@@ -647,9 +659,18 @@ class ImportHandle(BaseHandle):
if not hasattr(self.Trans.ClassHandler, '_generic_class_templates'):
self.Trans.ClassHandler._generic_class_templates = {}
type_params = [tp.name for tp in node.type_params]
# 保留 prescan 阶段已注册的 sha1若无则从 _ModuleSha1Map 查找,
# 避免覆盖带 sha1 的注册导致特化时 SHA1 前缀丢失
existing = self.Trans.ClassHandler._generic_class_templates.get(node.name)
template_sha1 = existing.get('sha1') if existing else None
if template_sha1 is None:
msm = getattr(self.Trans, '_ModuleSha1Map', None)
if msm and module_name in msm:
template_sha1 = msm[module_name]
self.Trans.ClassHandler._generic_class_templates[node.name] = {
'node': node,
'type_params': type_params,
'sha1': template_sha1,
}
self._EmitExternalClassDeclLlvm(node, Gen, module_name=module_name)
has_functions_or_classes = True