Files
TransPyC/lib/core/Translator/LlvmGenerator.py
2026-07-18 19:25:40 +08:00

643 lines
36 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
import ast
import re
import llvmlite.ir as ir
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
from lib.core.Handles.HandlesBase import CTypeInfo
from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo, CTypeHelper
from lib.includes import t
from lib.constants.config import mode as _config_mode
from lib.core.VLogger import get_logger as _vlog
from lib.core.DecoratorPass import run as _run_decorator_pass
from lib.core.SymbolUtils import IsTModule, AnnotationContainsName
class LlvmGeneratorMixin:
"""LLVM IR 生成 Mixin
提供 LLVM IR 直接生成、模块级 LLVM IR 处理与 C 代码生成入口能力。
"""
def GenerateLlvmDirect(self, Tree: ast.Module) -> str:
Gen: LlvmCodeGenerator = self.LlvmGen
# === 新增:轻量 AST 遍历,收集类图信息,解决前向引用 ===
Gen._class_graph: dict[str, dict[str, bool | list[str]]] = {}
for Node in ast.iter_child_nodes(Tree):
if isinstance(Node, ast.ClassDef):
bases: list[str] = []
for base in Node.bases:
if hasattr(base, 'id'):
bases.append(base.id)
elif hasattr(base, 'attr'):
bases.append(base.attr)
has_methods: bool = any(isinstance(item, ast.FunctionDef) for item in Node.body)
# 检测 @t.NoVTable 装饰器(非多态继承基类标记)
has_novtable: bool = False
if hasattr(Node, 'decorator_list') and Node.decorator_list:
for decorator in Node.decorator_list:
if isinstance(decorator, ast.Attribute):
if getattr(decorator.value, 'id', None) == 't' and decorator.attr == 'NoVTable':
has_novtable = True
elif isinstance(decorator, ast.Name):
if decorator.id == 'NoVTable':
has_novtable = True
Gen._class_graph[Node.name] = {
'bases': bases,
'has_methods': has_methods,
'has_novtable': has_novtable,
}
# === 结束新增 ===
# 预扫描:为所有 -> str 注解的函数注册正确的返回类型 i8*
# 这样在类方法中调用这些函数时,前向声明会使用正确的类型
for Node in ast.iter_child_nodes(Tree):
if isinstance(Node, ast.FunctionDef):
if Node.returns and isinstance(Node.returns, ast.Name) and Node.returns.id == 'str':
Gen.known_return_types[Node.name] = ir.PointerType(ir.IntType(8))
# 首先收集所有 CDefine 常量,确保类定义中可以引用
def _extract_call_const_val(node: ast.AST) -> int | str | float | None:
if isinstance(node, ast.Call):
if isinstance(node.func, ast.Attribute):
if getattr(node.func.value, 'id', None) == 't':
if node.args and isinstance(node.args[0], ast.Constant):
return node.args[0].value
elif isinstance(node.func, ast.Name):
if node.args and isinstance(node.args[0], ast.Constant):
return node.args[0].value
return None
for Node in ast.iter_child_nodes(Tree):
if isinstance(Node, ast.AnnAssign) and isinstance(Node.target, ast.Name) and Node.value:
TypeInfo: CTypeInfo | None = self.TypeMergeHandler.GetCTypeInfo(Node.annotation)
if TypeInfo and TypeInfo.BaseType and ((isinstance(TypeInfo.BaseType, type) and issubclass(TypeInfo.BaseType, t.CDefine)) or isinstance(TypeInfo.BaseType, t.CDefine)):
val: int | str | float | None = None
if isinstance(Node.value, ast.Constant):
val = Node.value.value
else:
val = _extract_call_const_val(Node.value)
if val is not None:
if not hasattr(Gen, '_define_constants'):
Gen._define_constants: dict[str, int | str | float | bool] = {}
Gen._define_constants[Node.target.id] = val
existing = self.SymbolTable.lookup(Node.target.id)
if not (existing and existing.IsTypedef and existing.OriginalType):
sym_info: _CTypeInfo = _CTypeInfo()
sym_info.IsDefine = True
sym_info.DefineValue = val
self.SymbolTable.insert(Node.target.id, sym_info)
elif isinstance(Node, ast.Assign):
for target in Node.targets:
if isinstance(target, ast.Name):
TypeInfo: CTypeInfo | None = None
if Node.type_comment:
try:
tc_ast: ast.Expression = ast.parse(Node.type_comment, mode='eval')
TypeInfo = self.TypeMergeHandler.GetCTypeInfo(tc_ast.body)
except Exception as _e:
if _config_mode == "strict":
raise
_vlog().warning(f"解析类型注释失败: {_e}", "Exception")
if TypeInfo and TypeInfo.BaseType and ((isinstance(TypeInfo.BaseType, type) and issubclass(TypeInfo.BaseType, t.CDefine)) or isinstance(TypeInfo.BaseType, t.CDefine)):
val: int | str | float | None = None
if isinstance(Node.value, ast.Constant):
val = Node.value.value
else:
val = _extract_call_const_val(Node.value)
if val is not None:
if not hasattr(Gen, '_define_constants'):
Gen._define_constants: dict[str, int | str | float | bool] = {}
Gen._define_constants[target.id] = val
sym_info: _CTypeInfo = _CTypeInfo()
sym_info.IsDefine = True
sym_info.DefineValue = val
self.SymbolTable.insert(target.id, sym_info)
# 预扫描所有顶层函数定义,填充 FunctionDefCache不创建 LLVM 声明)
# 这样类方法编译时遇到未声明的函数可以按需前向声明
for Node in ast.iter_child_nodes(Tree):
if isinstance(Node, ast.FunctionDef):
FuncName: str = Node.name
if FuncName not in self.FunctionDefCache:
self.FunctionDefCache[FuncName] = Node
# 首先处理所有导入语句,确保模块在类型解析前被加载
for Node in ast.iter_child_nodes(Tree):
Gen._set_node_info(Node)
try:
if isinstance(Node, ast.Import):
self.ImportHandler._EmitImportDeclarationsLlvm(Node, Gen)
elif isinstance(Node, ast.ImportFrom):
self.ImportHandler._EmitImportFromDeclarationsLlvm(Node, Gen)
except Exception as e:
lineno: int = getattr(Node, 'lineno', 0)
source_line: str | None = Gen._get_source_line(lineno)
src_file: str = getattr(Gen, '_current_source_file', '')
src_path: str = src_file if src_file else 'unknown'
line_info: str = "源代码 (%s, line %d)" % (src_path, lineno)
if source_line:
line_info += ":\n %d | %s" % (lineno, source_line)
self._ErrorStack.append((type(e).__name__, str(e), line_info))
# 前向声明所有顶层函数,确保全局变量初始化时能引用函数指针
for Node in ast.iter_child_nodes(Tree):
if isinstance(Node, ast.FunctionDef):
Gen._set_node_info(Node)
self.FunctionHandler._EmitFunctionForwardDeclLlvm(Node, Gen)
# 预创建全局变量(带初始化器),确保类方法编译时能引用全局数组等
Gen._current_tree: ast.Module = Tree
for Node in ast.iter_child_nodes(Tree):
Gen._set_node_info(Node)
if isinstance(Node, ast.AnnAssign):
self.AssignHandler._EmitGlobalAnnAssignLlvm(Node, Gen)
elif isinstance(Node, ast.Assign):
self.AssignHandler._EmitGlobalAssignLlvm(Node, Gen)
# 首先处理所有类定义(包括 CUnion确保类型定义在使用前完成
for Node in ast.iter_child_nodes(Tree):
if isinstance(Node, ast.ClassDef):
Gen._set_node_info(Node)
self.ClassHandler._EmitClassLlvm(Node, Gen)
Gen._generate_structs()
Gen._create_Vtable_globals()
for Node in ast.iter_child_nodes(Tree):
Gen._set_node_info(Node)
try:
if isinstance(Node, ast.Import):
continue
elif isinstance(Node, ast.ImportFrom):
continue
elif isinstance(Node, ast.ClassDef):
continue
elif isinstance(Node, ast.FunctionDef):
self.FunctionHandler._EmitFunctionLlvm(Node, Gen)
elif isinstance(Node, ast.AnnAssign):
self.AssignHandler._EmitGlobalAnnAssignLlvm(Node, Gen)
elif isinstance(Node, ast.Assign):
self.AssignHandler._EmitGlobalAssignLlvm(Node, Gen)
elif isinstance(Node, ast.If):
pass
elif isinstance(Node, ast.Expr):
self._HandleModuleLevelExprLlvm(Node, Gen)
except Exception as e:
lineno: int = getattr(Node, 'lineno', 0)
source_line: str | None = Gen._get_source_line(lineno)
src_file: str = getattr(Gen, '_current_source_file', '')
src_path: str = src_file if src_file else 'unknown'
line_info: str = "源代码 (%s, line %d)" % (src_path, lineno)
if source_line:
line_info += ":\n %d | %s" % (lineno, source_line)
self._ErrorStack.append((type(e).__name__, str(e), line_info))
raise
Gen._set_Vtable_initializers()
# 执行 DecoratorPass为带自定义装饰器的函数生成 wrapper
_run_decorator_pass(Gen)
ir_code: str = Gen.finalize()
return ir_code
def _HandleModuleLevelExprLlvm(self, Node: ast.Expr, Gen: LlvmCodeGenerator) -> None:
if not isinstance(Node.value, ast.Call):
return
call: ast.Call = Node.value
if not isinstance(call.func, ast.Attribute):
return
if not isinstance(call.func.value, ast.Name) or call.func.value.id != 'c':
return
func_name: str = call.func.attr
if func_name == 'LLVMIR':
self._HandleModuleLevelLLVMIR(call, Gen)
def _HandleModuleLevelLLVMIR(self, Node: ast.Call, Gen: LlvmCodeGenerator) -> None:
if not Node.args:
return
first_arg: ast.expr = Node.args[0]
if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str):
ir_text: str = first_arg.value
elif isinstance(first_arg, ast.JoinedStr):
parts: list[str] = []
for value in first_arg.values:
if isinstance(value, ast.Constant) and isinstance(value.value, str):
parts.append(value.value)
elif isinstance(value, ast.FormattedValue):
parts.append('')
ir_text = ''.join(parts)
else:
return
self._InsertModuleLevelLLVMIR(Gen, ir_text)
def _InsertModuleLevelLLVMIR(self, Gen: LlvmCodeGenerator, ir_text: str) -> None:
for line in ir_text.strip().split('\n'):
line = line.strip()
if not line:
continue
module_flags_match: re.Match[str] | None = re.match(r'!llvm\.module\.flags\s*=\s*!\{(!\d+)\}', line)
if module_flags_match:
ref: str = module_flags_match.group(1)
if not hasattr(Gen, '_pending_module_flags'):
Gen._pending_module_flags: list = []
Gen._pending_module_flags_refs: str = ref
continue
metadata_match: re.Match[str] | None = re.match(r'(!\d+)\s*=\s*!\{(.+)\}', line)
if metadata_match:
md_id: str = metadata_match.group(1)
md_body: str = metadata_match.group(2)
fields: list[ir.Constant | ir.MetaDataString | str] = []
for field_str in re.split(r',\s*', md_body):
field_str = field_str.strip()
if not field_str:
continue
int_m: re.Match[str] | None = re.match(r'^i32\s+(\d+)$', field_str)
if int_m:
fields.append(ir.Constant(ir.IntType(32), int(int_m.group(1))))
continue
str_m: re.Match[str] | None = re.match(r'^"([^"]*)"$', field_str)
if str_m:
fields.append(ir.MetaDataString(Gen.module, str_m.group(1)))
continue
mdstr_m: re.Match[str] | None = re.match(r'^!"([^"]*)"$', field_str)
if mdstr_m:
fields.append(ir.MetaDataString(Gen.module, mdstr_m.group(1)))
continue
int_m2: re.Match[str] | None = re.match(r'^(\d+)$', field_str)
if int_m2:
fields.append(ir.Constant(ir.IntType(32), int(int_m2.group(1))))
continue
ref_m: re.Match[str] | None = re.match(r'^(!\d+)$', field_str)
if ref_m:
fields.append(ref_m.group(1))
continue
if fields:
if not hasattr(Gen, '_pending_metadata'):
Gen._pending_metadata: list[tuple[str, list]] = []
Gen._pending_metadata.append((md_id, fields))
continue
self._FlushModuleMetadata(Gen)
def _FlushModuleMetadata(self, Gen: LlvmCodeGenerator) -> None:
if not hasattr(Gen, '_pending_metadata') or not Gen._pending_metadata:
return
md_map: dict[str, ir.MetaDataString] = {}
for md_id, fields in Gen._pending_metadata:
resolved: list[ir.Constant | ir.MetaDataString] = []
for f in fields:
if isinstance(f, str) and f.startswith('!'):
ref: ir.MetaDataString | None = md_map.get(f)
if ref:
resolved.append(ref)
else:
resolved.append(f)
md_value: ir.MetaDataString = Gen.module.add_metadata(resolved)
md_map[md_id] = md_value
if hasattr(Gen, '_pending_module_flags_refs'):
ref: str = Gen._pending_module_flags_refs
md_node: ir.MetaDataString | None = md_map.get(ref)
if md_node:
Gen.module.add_named_metadata('llvm.module.flags', md_node)
Gen._pending_metadata = []
Gen._pending_module_flags_refs = None
def GenerateCCode(self, Tree: ast.Module, target: str = 'llvm') -> str:
"""生成代码
Args:
Tree: Python AST 树
target: 目标代码类型,仅支持 'llvm'
Returns:
生成的代码字符串
"""
self._generated_vars: set[str] = set()
self.VarScopes = [{}] # 全局作用域
# 预扫描 import 语句,注册别名,确保类型解析时能正确解析模块别名
if not getattr(self, '_ImportedModules', None):
self._ImportedModules: set[str] = set()
for Node in ast.iter_child_nodes(Tree):
if isinstance(Node, ast.Import):
for alias in Node.names:
name: str = alias.name
if name in ('c', 't'):
continue
self._ImportedModules.add(name)
if alias.asname:
self.SymbolTable.import_aliases[alias.asname] = name
elif isinstance(Node, ast.ImportFrom):
module_name: str | None = Node.module
if module_name and module_name not in ('c', 't'):
self._ImportedModules.add(module_name)
for alias in Node.names:
if alias.asname:
self.SymbolTable.import_aliases[alias.asname] = f"{module_name}.{alias.name}"
for Node in ast.iter_child_nodes(Tree):
if isinstance(Node, ast.ClassDef):
ClassName: str = Node.name
# 检查是否是特殊类型(枚举或联合体)
IsSpecialType: bool = False
if Node.bases:
for base in Node.bases:
if hasattr(base, 'attr'):
if base.attr in ['CEnum', 'Enum', 'CUnion', 'REnum']:
IsSpecialType = True
break
elif hasattr(base, 'id'):
if base.id in ['CEnum', 'Enum', 'CUnion', 'REnum']:
IsSpecialType = True
break
# 如果是特殊类型,跳过这里的处理(由 HandleClassDef 处理)
if IsSpecialType:
continue
members: dict[str, CTypeInfo] = {}
IsTypedef: bool = False
TypedefName: str | None = None
if hasattr(Node, 'annotation') and Node.annotation:
try:
if AnnotationContainsName(Node.annotation, 'CTypedef'):
IsTypedef = True
if isinstance(Node.annotation, ast.Call):
if Node.annotation.args:
if isinstance(Node.annotation.args[0], ast.Constant):
TypedefName = Node.annotation.args[0].value
except Exception as _e:
if _config_mode == "strict":
raise
_vlog().warning(f"解析 typedef 注解失败: {_e}", "Exception")
if not IsTypedef:
for item in Node.body:
if isinstance(item, ast.Assign):
for target in item.targets:
if isinstance(target, ast.Name) and target.id == '__annotations__':
if isinstance(item.value, ast.Dict):
for key, value in zip(item.value.keys, item.value.values):
if isinstance(key, ast.Constant) and key.value == '__type__':
if AnnotationContainsName(value, 'CTypedef'):
IsTypedef = True
if IsTypedef:
TypedefKey: str = TypedefName if TypedefName else ClassName
TypedefNode: CTypeInfo = CTypeInfo()
TypedefNode.Name = TypedefKey
TypedefNode.IsTypedef = True
TypedefNode.OriginalType = f'struct {ClassName}'
TypedefNode.set('IsComplete', True)
TypedefNode.file = '<stdin>'
self.SymbolTable.insert(TypedefKey, TypedefNode)
for item in Node.body:
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
VarName: str = item.target.id
try:
TypeInfo: CTypeInfo | None = self.TypeMergeHandler.GetCTypeInfo(item.annotation)
if TypeInfo is None:
TypeInfo = CTypeInfo()
TypeInfo.BaseType = t.CInt()
IsPtr: bool = TypeInfo.IsPtr
if not IsPtr:
if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr):
if AnnotationContainsName(item.annotation, 'CPtr'):
IsPtr = True
dims: list[int] = []
if hasattr(item.annotation, 'slice') and isinstance(item.annotation.slice, ast.Constant):
if isinstance(item.annotation.value, ast.Name):
if IsTModule(item.annotation.value.id, self.SymbolTable):
if hasattr(item.annotation, 'slice'):
try:
dims.append(int(item.annotation.slice.value))
except Exception as _e:
if _config_mode == "strict":
self.LogWarning(f"异常被忽略: {_e}")
MemberInfo: CTypeInfo = TypeInfo.Copy()
if dims:
MemberInfo.ArrayDims = [str(d) for d in dims]
members[VarName] = MemberInfo
except Exception as _e:
if _config_mode == "strict":
self.LogWarning(f"异常被忽略: {_e}")
if not IsTypedef:
StructNode: CTypeInfo = CTypeInfo()
StructNode.Name = ClassName
StructNode.IsStruct = True
StructNode.Members = members or {}
StructNode.file = '<stdin>'
existing: CTypeInfo | None = self.SymbolTable.lookup(ClassName)
if existing:
if hasattr(existing, 'IsCpythonObject') and existing.IsCpythonObject:
StructNode.IsCpythonObject = True
self.SymbolTable.insert(ClassName, StructNode)
elif isinstance(Node, ast.FunctionDef):
FuncName: str = Node.name
if not self.SymbolTable.has(FuncName):
FuncNode: CTypeInfo = CTypeInfo()
FuncNode.Name = FuncName
FuncNode.IsFunction = True
FuncNode.file = '<stdin>'
self.SymbolTable.insert(FuncName, FuncNode)
elif isinstance(Node, ast.AnnAssign):
if isinstance(Node.target, ast.Name):
VarName: str = Node.target.id
VarType: str = 'unknown'
IsPtr: bool = False
IsTypedef_assignment: bool = False
if Node.annotation:
try:
if AnnotationContainsName(Node.annotation, 'CTypedef'):
IsTypedef_assignment = True
except Exception as _e:
if _config_mode == "strict":
self.LogWarning(f"异常被忽略: {_e}")
if IsTypedef_assignment and Node.value:
if isinstance(Node.value, ast.Name):
OriginalType: str = Node.value.id
if OriginalType in self.GeneratedTypes:
OriginalInfo: CTypeInfo | None = self.SymbolTable.lookup(OriginalType)
if OriginalInfo:
if isinstance(OriginalInfo, dict):
actual_type: str = OriginalInfo.get('type', 'struct')
elif isinstance(OriginalInfo, CTypeInfo):
if OriginalInfo.IsEnum:
actual_type = 'enum'
elif OriginalInfo.IsTypedef:
actual_type = 'typedef'
elif OriginalInfo.IsStruct:
actual_type = 'struct'
else:
actual_type = 'struct'
else:
actual_type = 'struct'
if actual_type == 'enum':
TypedefNode: CTypeInfo = CTypeInfo()
TypedefNode.Name = VarName
TypedefNode.IsTypedef = True
TypedefNode.OriginalType = f'enum {OriginalType}'
TypedefNode.file = '<stdin>'
self.SymbolTable.insert(VarName, TypedefNode)
elif actual_type == 'typedef':
TypedefNode = CTypeInfo()
TypedefNode.Name = VarName
TypedefNode.IsTypedef = True
if isinstance(OriginalInfo, dict):
TypedefNode.OriginalType = OriginalInfo.get('OriginalType', f'struct {OriginalType}')
elif isinstance(OriginalInfo, CTypeInfo) and OriginalInfo.OriginalType:
TypedefNode.OriginalType = OriginalInfo.OriginalType
else:
TypedefNode.OriginalType = f'struct {OriginalType}'
TypedefNode.file = '<stdin>'
self.SymbolTable.insert(VarName, TypedefNode)
else:
TypedefNode = CTypeInfo()
TypedefNode.Name = VarName
TypedefNode.IsTypedef = True
TypedefNode.OriginalType = f'struct {OriginalType}'
TypedefNode.file = '<stdin>'
self.SymbolTable.insert(VarName, TypedefNode)
self.GeneratedTypes.add(VarName)
continue
else:
OriginalInfo: CTypeInfo | None = self.SymbolTable.lookup(OriginalType)
if OriginalInfo:
if isinstance(OriginalInfo, dict):
actual_type: str = OriginalInfo.get('type', 'struct')
elif isinstance(OriginalInfo, CTypeInfo):
if OriginalInfo.IsEnum:
actual_type = 'enum'
elif OriginalInfo.IsTypedef:
actual_type = 'typedef'
elif OriginalInfo.IsStruct:
actual_type = 'struct'
else:
actual_type = 'struct'
else:
actual_type = 'struct'
if actual_type == 'typedef':
TypedefNode: CTypeInfo = CTypeInfo()
TypedefNode.Name = VarName
TypedefNode.IsTypedef = True
if isinstance(OriginalInfo, dict):
TypedefNode.OriginalType = OriginalInfo.get('OriginalType', f'struct {OriginalType}')
elif isinstance(OriginalInfo, CTypeInfo) and OriginalInfo.OriginalType:
TypedefNode.OriginalType = OriginalInfo.OriginalType
else:
TypedefNode.OriginalType = f'struct {OriginalType}'
TypedefNode.file = '<stdin>'
self.SymbolTable.insert(VarName, TypedefNode)
self.GeneratedTypes.add(VarName)
if isinstance(OriginalInfo, dict):
OriginalInfo['skip_generation'] = True
continue
elif actual_type == 'struct':
TypedefNode = CTypeInfo()
TypedefNode.Name = VarName
TypedefNode.IsTypedef = True
TypedefNode.OriginalType = f'struct {OriginalType}'
TypedefNode.file = '<stdin>'
self.SymbolTable.insert(VarName, TypedefNode)
self.GeneratedTypes.add(VarName)
if isinstance(OriginalInfo, dict):
OriginalInfo['skip_generation'] = True
continue
elif actual_type == 'enum':
TypedefNode = CTypeInfo()
TypedefNode.Name = VarName
TypedefNode.IsTypedef = True
TypedefNode.OriginalType = f'enum {OriginalType}'
TypedefNode.file = '<stdin>'
self.SymbolTable.insert(VarName, TypedefNode)
self.GeneratedTypes.add(VarName)
if isinstance(OriginalInfo, dict):
OriginalInfo['skip_generation'] = True
continue
elif isinstance(Node.value, ast.Attribute):
CName: str | None = CTypeHelper.GetCName(Node.value.attr)
if CName:
TypedefNode: CTypeInfo = CTypeInfo()
TypedefNode.Name = VarName
TypedefNode.IsTypedef = True
TypedefNode.OriginalType = CName
TypedefNode.file = '<stdin>'
self.SymbolTable.insert(VarName, TypedefNode)
self.GeneratedTypes.add(VarName)
continue
if Node.annotation:
try:
TypeInfo: CTypeInfo | None = self.TypeMergeHandler.GetCTypeInfo(Node.annotation)
IsPtr = TypeInfo.IsPtr if TypeInfo else False
except Exception as _e:
if _config_mode == "strict":
self.LogWarning(f"异常被忽略: {_e}")
# 如果符号已经存在且是 typedef不要覆盖它
existing = self.SymbolTable.lookup(VarName)
if existing and existing.IsTypedef and existing.OriginalType:
# typedef 已正确插入,保持现有条目不覆盖
pass
else:
var_node: CTypeInfo = CTypeInfo()
var_node.Name = VarName
var_node.IsVariable = True
var_node.PtrCount = 1 if IsPtr else 0
var_node.file = '<stdin>'
self.SymbolTable.insert(VarName, var_node)
self.LlvmGen: LlvmCodeGenerator = LlvmCodeGenerator(
triple=getattr(self, 'triple', None),
datalayout=getattr(self, 'datalayout', None),
)
self.LlvmGen._Trans = self
self.LlvmGen._import_handler_ref = self.ImportHandler
if hasattr(self, '_module_sha1'):
self.LlvmGen.module_sha1 = self._module_sha1
if hasattr(self, '_ModuleSha1Map'):
self.LlvmGen.ModuleSha1Map = self._ModuleSha1Map
if hasattr(self, '_struct_sha1_map'):
self.LlvmGen._struct_sha1_map = self._struct_sha1_map
if hasattr(self, '_temp_dir'):
self.LlvmGen._temp_dir = self._temp_dir
if hasattr(self, '_export_extern_funcs'):
self.LlvmGen._export_extern_funcs = self._export_extern_funcs
self.LlvmGen.setup_from_symbol_table(self.SymbolTable)
if hasattr(self, 'CurrentFile') and self.CurrentFile:
self.LlvmGen._set_source_info(self.CurrentFile)
# --- 修复:共享 vtable 状态跨模块 ---
# 根因LlvmGen 每模块重新创建class_vtable/class_methods 等是实例级属性,
# 不跨模块共享。导致模块 B 编译时 _specialize_generic_class 触发的
# pool.alloc(48) 找不到 MemManager 的虚表状态,直接调用 stub 返回 NULL → 段错误。
# 修复:将 vtable 状态存储在 Translator 对象上并赋值给每个新 Gen。
if not hasattr(self, '_shared_class_vtable'):
self._shared_class_vtable: set[str] = set()
self._shared_cross_module_vtable: set[str] = set()
self._shared_class_methods: dict[str, list[str]] = {}
self._shared_cross_module_novtable: set[str] = set()
# 合并 setup_from_symbol_table 创建的实例级 class_methods 到共享 dict
# (仅添加新类,不覆盖已有方法列表)
for _cls_name, _methods in self.LlvmGen.class_methods.items():
if _cls_name not in self._shared_class_methods:
self._shared_class_methods[_cls_name] = _methods
else:
for _m in _methods:
if _m not in self._shared_class_methods[_cls_name]:
self._shared_class_methods[_cls_name].append(_m)
# 替换为共享状态
self.LlvmGen.class_vtable = self._shared_class_vtable
self.LlvmGen._cross_module_vtable_classes = self._shared_cross_module_vtable
self.LlvmGen.class_methods = self._shared_class_methods
self.LlvmGen._cross_module_novtable = self._shared_cross_module_novtable
# --- 修复结束 ---
return self.GenerateLlvmDirect(Tree)