修正了一些错误

This commit is contained in:
TermiNexus committed 2026-07-26 20:32:26 +08:00
1 parent ca7c2120b8
commit 1837339f69
203 files changed
+374300 -2638

No files matched your search

+41 -23
View File
@@ -14,8 +14,38 @@ from lib.Projectrans.Phase1Generator import Phase1Generator
from lib.Projectrans.Phase2Translator import Phase2Translator
# ============================================================
# 全局 SHA1 映射内存存储器
#
# Phase1 生成 sha1_map 后写入此处(save_sha1_map),
# Phase2 从此处读取(Load_sha1_map / Phase2Translator._LoadSha1Map)。
# _sha1_map.txt 文件仅作为人类可读输出,不再作为机器分析数据源。
# ============================================================
_g_sha1_map_store: dict[str, str] = {}
def get_sha1_map_store() -> dict[str, str]:
"""返回全局 SHA1 映射内存存储器(供 Phase2Translator 直接访问)"""
return _g_sha1_map_store
def clear_sha1_map_store() -> None:
"""清空全局 SHA1 映射内存存储器"""
_g_sha1_map_store.clear()
def save_sha1_map(temp_dir: str, sha1_map: dict[str, str]) -> None:
"""将 SHA1 映射表保存到文件"""
"""将 SHA1 映射表保存到内存存储器,并输出人类可读的 _sha1_map.txt
机器分析使用内存存储器(_g_sha1_map_store),
_sha1_map.txt 仅作为人类可读输出,不再被机器读取。
"""
# 写入内存存储器(机器分析数据源)
_g_sha1_map_store.clear()
for sha1, rel in sha1_map.items():
_g_sha1_map_store[sha1] = rel
# 写入文件(仅人类可读输出)
map_path: str = os.path.join(temp_dir, '_sha1_map.txt')
with open(map_path, 'w', encoding='utf-8') as f:
for sha1, rel in sorted(sha1_map.items()):
@@ -23,18 +53,14 @@ def save_sha1_map(temp_dir: str, sha1_map: dict[str, str]) -> None:
def Load_sha1_map(temp_dir: str) -> dict[str, str]:
"""从文件加载 SHA1 映射表"""
map_path: str = os.path.join(temp_dir, '_sha1_map.txt')
"""从内存存储器加载 SHA1 映射表
temp_dir 参数保留用于签名兼容性,但不再读取文件。
机器分析使用内存存储器(_g_sha1_map_store)。
"""
result: dict[str, str] = {}
if os.path.exists(map_path):
with open(map_path, 'r', encoding='utf-8') as f:
for line in f:
line: str = line.strip()
if ':' in line:
sha1: str
rel: str
sha1, rel = line.split(':', 1)
result[sha1] = rel
for sha1, rel in _g_sha1_map_store.items():
result[sha1] = rel
return result
@@ -69,17 +95,9 @@ def resolve_paths(config: dict[str, Any], project_file: str) -> dict[str, Any]:
resolved_sources.append(resolve(src))
result['sources'] = [s for s in resolved_sources if os.path.isfile(s)]
# build_dir: 统一构建目录(默认 ./.tpv_build),temp 和 output 作为其子目录
# 不再单独读取 temp_dir/output_dir,由 build_dir 自动计算
build_dir: str = config.get('build_dir', './.tpv_build')
build_dir = resolve(build_dir)
result['build_dir'] = build_dir
if build_dir is not None:
result['temp_dir'] = os.path.join(build_dir, 'temp')
result['output_dir'] = os.path.join(build_dir, 'output')
else:
result['temp_dir'] = None
result['output_dir'] = None
# 直接使用 output_dir / temp_dir(与新版本 TPV 一致,不再支持 build_dir)
result['temp_dir'] = resolve(config.get('temp_dir', './temp'))
result['output_dir'] = resolve(config.get('output_dir', './output'))
if 'includes' in result:
result['includes'] = [resolve(inc) for inc in result['includes']]
+1 -1
View File
@@ -528,7 +528,7 @@ class Phase1Generator:
sha1: str = self._get_sha1(src_path)
if not sha1:
return
self.sha1_map[sha1] = rel_path
self.sha1_map[sha1] = rel_path.replace(os.sep, '/').replace(chr(92), '/')
sig_path: str = os.path.join(self.temp_dir, f"{sha1}.pyi")
if os.path.isfile(sig_path):
+19 -16
View File
@@ -218,18 +218,18 @@ class Phase2Translator:
if sha1 not in self.stub_files:
self.stub_files[sha1] = os.path.join(_GLOBAL_CACHE_DIR, fname)
sha1_file_path = os.path.join(self.temp_dir, '_sha1_map.txt')
if os.path.exists(sha1_file_path):
with open(sha1_file_path, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if ':' in line:
sha1, rel = line.split(':', 1)
self.sha1_map[sha1] = rel
if rel.startswith('includes/'):
module_name = os.path.splitext(os.path.basename(rel))[0]
self.include_py_map[module_name] = sha1
# 从内存存储器读取 SHA1 映射(_sha1_map.txt 仅人类可读,不再作为机器数据源)
# 延迟导入避免循环依赖(Config 导入 Phase2Translator)
from lib.Projectrans.Config import get_sha1_map_store
mem_store: dict[str, str] = get_sha1_map_store()
if mem_store:
for sha1, rel in mem_store.items():
self.sha1_map[sha1] = rel
if rel.startswith('includes/'):
module_name = os.path.splitext(os.path.basename(rel))[0]
self.include_py_map[module_name] = sha1
else:
# 内存存储器为空(独立运行 Phase2 的回退):从 stub 文件名推断
for sha1, stub_path in self.stub_files.items():
self.sha1_map[sha1] = sha1
@@ -2534,7 +2534,7 @@ class Phase2Translator:
# 注册到 sig_files 和 _source_module_sig_files
if os.path.isfile(sig_path):
self.sig_files[sha1] = sig_path
self.sha1_map[sha1] = f"includes/{mod_full.replace('.', os.sep)}.py"
self.sha1_map[sha1] = f"includes/{mod_full.replace('.', '/')}.py"
if self._shared_source_module_sig_files is not None:
self._shared_source_module_sig_files[mod_full] = sig_path
self._shared_source_module_sig_files[module_name] = sig_path
@@ -2759,15 +2759,18 @@ class Phase2Translator:
py_path = os.path.join(abs_includes, py_file)
try:
# 复用 parse_python_file 的 AST 缓存
_, py_tree = parse_python_file(py_path)
py_content, py_tree = parse_python_file(py_path)
if py_tree is None:
continue
# 计算 include 文件的 SHA1,供特化时统一命名空间
py_sha1: str = compute_sha1(py_content)
for node in py_tree.body:
if isinstance(node, ast.ClassDef) and hasattr(node, 'type_params') and node.type_params:
type_params = [tp.name for tp in node.type_params]
generic_class_templates[node.name] = {
'node': node,
'type_params': type_params,
'sha1': py_sha1,
}
except Exception as _e:
if _config_mode == "strict":
@@ -2817,9 +2820,9 @@ class Phase2Translator:
scan_dirs = []
if self.src_root and os.path.isdir(self.src_root):
scan_dirs.append(self.src_root)
project_dir = os.path.dirname(self.output_dir)
if project_dir and os.path.isdir(project_dir) and project_dir not in scan_dirs:
scan_dirs.append(project_dir)
# 不再扫描 output_dir 的父目录:当 output_dir 位于顶层时,
# 父目录是整个仓库根,会误扫到 ViperOS/includes/vqt6 等无关 C/C++ 源文件。
# 项目特定的 C/汇编文件应放在 src_root 下,或通过 extra_compile_files 指定。
for scan_dir in scan_dirs:
for root, dirs, files in os.walk(scan_dir):
dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__']
+3 -2
View File
@@ -20,12 +20,13 @@ from lib.Projectrans.Utils import (
from lib.Projectrans.Phase1Generator import Phase1Generator
from lib.Projectrans.DeclarationGenerator import DeclarationGenerator
from lib.Projectrans.Phase2Translator import Phase2Translator, _parallel_translate_worker
from lib.Projectrans.Config import save_sha1_map, Load_sha1_map, Load_project_config, resolve_paths, main
from lib.Projectrans.Config import save_sha1_map, Load_sha1_map, get_sha1_map_store, clear_sha1_map_store, Load_project_config, resolve_paths, main
__all__ = [
'compute_sha1', '_check_annotation_for_export', 'sha1_file',
'get_file_dependencies', 'find_reachable_files_from_entries',
'topological_sort_files', 'Phase1Generator', 'DeclarationGenerator',
'Phase2Translator', '_parallel_translate_worker',
'save_sha1_map', 'Load_sha1_map', 'Load_project_config', 'resolve_paths', 'main'
'save_sha1_map', 'Load_sha1_map', 'get_sha1_map_store', 'clear_sha1_map_store',
'Load_project_config', 'resolve_paths', 'main'
]
+19 -1
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):
+119 -22
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_constants(LlvmGenerator 预扫描阶段填充)
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_constants(LlvmGenerator 预扫描阶段填充)
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:
+112 -15
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:
# Fallback:ToString 返回空字符串时,尝试手动从 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)
+13
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
+21
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