from __future__ import annotations import ast import os import re import llvmlite.ir as ir from lib.core.LlvmCodeGenerator import LlvmCodeGenerator from lib.core.SymbolNode import SymbolNode from lib.core.Handles.HandlesBase import CTypeInfo from lib.includes import t from lib.constants.config import mode as _config_mode from lib.core.Translator.BaseTranslator import _StrictLog class LlvmGeneratorMixin: """LLVM IR 生成 Mixin 提供 LLVM IR 直接生成、模块级 LLVM IR 处理与 C 代码生成入口能力。 """ def GenerateLlvmDirect(self, Tree): Gen = self.LlvmGen # 预扫描:为所有 -> 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): 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 = self.TypeMergeHandler.GetCTypeInfo(Node.annotation) if TypeInfo and TypeInfo.BaseType and hasattr(TypeInfo.BaseType, 'CName') and TypeInfo.BaseType.CName == '#define': val = 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 = {} Gen._define_constants[Node.target.id] = val from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo sym_info = _CTypeInfo() sym_info.IsDefine = True sym_info.DefineValue = val self.SymbolTable[Node.target.id] = sym_info elif isinstance(Node, ast.Assign): for target in Node.targets: if isinstance(target, ast.Name): TypeInfo = None if Node.type_comment: try: tc_ast = ast.parse(Node.type_comment, mode='eval') TypeInfo = self.TypeMergeHandler.GetCTypeInfo(tc_ast.body) except Exception as _e: from lib.core.VLogger import get_logger as _vlog from lib.constants.config import mode as _config_mode if _config_mode == "strict": raise _vlog().warning(f"解析类型注释失败: {_e}", "Exception") if TypeInfo and TypeInfo.BaseType and hasattr(TypeInfo.BaseType, 'CName') and TypeInfo.BaseType.CName == '#define': val = 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 = {} Gen._define_constants[target.id] = val from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo sym_info = _CTypeInfo() sym_info.IsDefine = True sym_info.DefineValue = val self.SymbolTable[target.id] = sym_info # 预扫描所有顶层函数定义,填充 FunctionDefCache(不创建 LLVM 声明) # 这样类方法编译时遇到未声明的函数可以按需前向声明 for Node in ast.iter_child_nodes(Tree): if isinstance(Node, ast.FunctionDef): FuncName = 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 = getattr(Node, 'lineno', 0) source_line = Gen._get_source_line(lineno) src_file = getattr(Gen, '_current_source_file', '') src_path = src_file if src_file else 'unknown' line_info = "源代码 (%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)) # 预创建全局变量(带初始化器),确保类方法编译时能引用全局数组等 Gen._current_tree = Tree for Node in ast.iter_child_nodes(Tree): if isinstance(Node, ast.AnnAssign): self.AssignHandler._EmitGlobalAnnAssignLlvm(Node, Gen) elif isinstance(Node, ast.Assign): self.AssignHandler._EmitGlobalAssignLlvm(Node, Gen) # 前向声明所有顶层函数,确保类方法编译时能找到这些函数 for Node in ast.iter_child_nodes(Tree): if isinstance(Node, ast.FunctionDef): self.FunctionHandler._EmitFunctionForwardDeclLlvm(Node, Gen) # 首先处理所有类定义(包括 CUnion),确保类型定义在使用前完成 for Node in ast.iter_child_nodes(Tree): if isinstance(Node, ast.ClassDef): 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 = getattr(Node, 'lineno', 0) source_line = Gen._get_source_line(lineno) src_file = getattr(Gen, '_current_source_file', '') src_path = src_file if src_file else 'unknown' line_info = "源代码 (%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 from lib.core.DecoratorPass import run as _run_decorator_pass _run_decorator_pass(Gen) ir_code = Gen.finalize() return ir_code def _HandleModuleLevelExprLlvm(self, Node, Gen): if not isinstance(Node.value, ast.Call): return 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 = call.func.attr if func_name == 'LLVMIR': self._HandleModuleLevelLLVMIR(call, Gen) def _HandleModuleLevelLLVMIR(self, Node, Gen): if not Node.args: return first_arg = Node.args[0] if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str): ir_text = first_arg.value elif isinstance(first_arg, ast.JoinedStr): parts = [] 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, ir_text): import re for line in ir_text.strip().split('\n'): line = line.strip() if not line: continue module_flags_match = re.match(r'!llvm\.module\.flags\s*=\s*!\{(!\d+)\}', line) if module_flags_match: ref = module_flags_match.group(1) if not hasattr(Gen, '_pending_module_flags'): Gen._pending_module_flags = [] Gen._pending_module_flags_refs = ref continue metadata_match = re.match(r'(!\d+)\s*=\s*!\{(.+)\}', line) if metadata_match: md_id = metadata_match.group(1) md_body = metadata_match.group(2) fields = [] for field_str in re.split(r',\s*', md_body): field_str = field_str.strip() if not field_str: continue int_m = 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(r'^"([^"]*)"$', field_str) if str_m: fields.append(ir.MetaDataString(Gen.module, str_m.group(1))) continue mdstr_m = re.match(r'^!"([^"]*)"$', field_str) if mdstr_m: fields.append(ir.MetaDataString(Gen.module, mdstr_m.group(1))) continue int_m2 = 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(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 = [] Gen._pending_metadata.append((md_id, fields)) continue self._FlushModuleMetadata(Gen) def _FlushModuleMetadata(self, Gen): if not hasattr(Gen, '_pending_metadata') or not Gen._pending_metadata: return md_map = {} for md_id, fields in Gen._pending_metadata: resolved = [] for f in fields: if isinstance(f, str) and f.startswith('!'): ref = md_map.get(f) if ref: resolved.append(ref) else: resolved.append(f) md_value = Gen.module.add_metadata(resolved) md_map[md_id] = md_value if hasattr(Gen, '_pending_module_flags_refs'): ref = Gen._pending_module_flags_refs md_node = 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, target='llvm'): """生成代码 Args: Tree: Python AST 树 target: 目标代码类型,仅支持 'llvm' Returns: 生成的代码字符串 """ self._generated_vars = set() self.VarScopes = [{}] # 全局作用域 # 预扫描 import 语句,注册别名,确保类型解析时能正确解析模块别名 if not getattr(self, '_ImportAliases', None): self._ImportAliases = {} if not getattr(self, '_ImportedModules', None): self._ImportedModules = set() for Node in ast.iter_child_nodes(Tree): if isinstance(Node, ast.Import): for alias in Node.names: name = alias.name if name in ('c', 't'): continue self._ImportedModules.add(name) if alias.asname: self._ImportAliases[alias.asname] = name elif isinstance(Node, ast.ImportFrom): module_name = 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._ImportAliases[alias.asname] = f"{module_name}.{alias.name}" for Node in ast.iter_child_nodes(Tree): if isinstance(Node, ast.ClassDef): ClassName = Node.name # 检查是否是特殊类型(枚举或联合体) IsSpecialType = 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 = {} IsTypedef = False TypedefName = None if hasattr(Node, 'annotation') and Node.annotation: try: AnnotationStr = ast.dump(Node.annotation) if 'CTypedef' in AnnotationStr: 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: from lib.core.VLogger import get_logger as _vlog from lib.constants.config import mode as _config_mode 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__': value_str = ast.dump(value) if 'CTypedef' in value_str: IsTypedef = True if isinstance(value, ast.Call): if value.args: if isinstance(value.args[0], ast.Constant): TypedefName = value.args[0].value if IsTypedef: TypedefKey = TypedefName if TypedefName else ClassName TypedefNode = SymbolNode.CreateClass( name=TypedefKey, TypeKind='typedef', lineno=0 ) TypedefNode.set('OriginalType', f'struct {ClassName}') TypedefNode.set('IsComplete', True) TypedefNode.set('file', '') self.SymbolTable[TypedefKey] = TypedefNode.attributes for item in Node.body: if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): VarName = item.target.id try: TypeInfo = self.TypeMergeHandler.GetCTypeInfo(item.annotation) if TypeInfo is None: TypeInfo = CTypeInfo() TypeInfo.BaseType = t.CInt() IsPtr = TypeInfo.IsPtr if not IsPtr: if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr): LeftStr = ast.dump(item.annotation.left) RightStr = ast.dump(item.annotation.right) if 'CPtr' in LeftStr or 'CPtr' in RightStr: IsPtr = True dims = [] if hasattr(item.annotation, 'slice') and isinstance(item.annotation.slice, ast.Constant): if isinstance(item.annotation.value, ast.Name): if item.annotation.value.id == 't': if hasattr(item.annotation, 'slice'): try: dims.append(int(item.annotation.slice.value)) except Exception as _e: if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": self.LogWarning(f"异常被忽略: {_e}") MemberInfo = TypeInfo.Copy() if dims: MemberInfo.ArrayDims = [str(d) for d in dims] members[VarName] = MemberInfo except Exception as _e: if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": self.LogWarning(f"异常被忽略: {_e}") if not IsTypedef: StructNode = SymbolNode.CreateClass( name=ClassName, TypeKind='struct', members=members, lineno=0 ) StructNode.set('file', '') if ClassName in self.SymbolTable: existing = self.SymbolTable[ClassName] if hasattr(existing, 'IsCpythonObject') and existing.IsCpythonObject: StructNode.set('IsCpythonObject', True) self.SymbolTable[ClassName] = StructNode.attributes elif isinstance(Node, ast.FunctionDef): FuncName = Node.name FuncNode = SymbolNode.CreateClass( name=FuncName, TypeKind='function', lineno=0 ) FuncNode.set('file', '') self.SymbolTable[FuncName] = FuncNode.attributes elif isinstance(Node, ast.AnnAssign): if isinstance(Node.target, ast.Name): VarName = Node.target.id VarType = 'unknown' IsPtr = False IsTypedef_assignment = False if Node.annotation: try: AnnotationStr = ast.dump(Node.annotation) if 'CTypedef' in AnnotationStr: IsTypedef_assignment = True except Exception as _e: if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": self.LogWarning(f"异常被忽略: {_e}") if IsTypedef_assignment and Node.value: if isinstance(Node.value, ast.Name): OriginalType = Node.value.id if OriginalType in self.GeneratedTypes: if OriginalType in self.SymbolTable: OriginalInfo = self.SymbolTable[OriginalType] if isinstance(OriginalInfo, dict): actual_type = 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 = SymbolNode.CreateClass( name=VarName, TypeKind='typedef', lineno=0 ) TypedefNode.set('OriginalType', f'enum {OriginalType}') TypedefNode.set('file', '') self.SymbolTable[VarName] = TypedefNode.attributes elif actual_type == 'typedef': TypedefNode = SymbolNode.CreateClass( name=VarName, TypeKind='typedef', lineno=0 ) if isinstance(OriginalInfo, dict): TypedefNode.set('OriginalType', OriginalInfo.get('OriginalType', f'struct {OriginalType}')) elif isinstance(OriginalInfo, CTypeInfo) and OriginalInfo.OriginalType: TypedefNode.set('OriginalType', OriginalInfo.OriginalType) else: TypedefNode.set('OriginalType', f'struct {OriginalType}') TypedefNode.set('PendingTypedef', True) TypedefNode.set('file', '') self.SymbolTable[VarName] = TypedefNode.attributes else: TypedefNode = SymbolNode.CreateClass( name=VarName, TypeKind='typedef', lineno=0 ) TypedefNode.set('OriginalType', f'struct {OriginalType}') TypedefNode.set('PendingTypedef', True) TypedefNode.set('file', '') self.SymbolTable[VarName] = TypedefNode.attributes self.GeneratedTypes.add(VarName) continue else: if OriginalType in self.SymbolTable: OriginalInfo = self.SymbolTable[OriginalType] if isinstance(OriginalInfo, dict): actual_type = 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 = SymbolNode.CreateClass( name=VarName, TypeKind='typedef', lineno=0 ) if isinstance(OriginalInfo, dict): TypedefNode.set('OriginalType', OriginalInfo.get('OriginalType', f'struct {OriginalType}')) elif isinstance(OriginalInfo, CTypeInfo) and OriginalInfo.OriginalType: TypedefNode.set('OriginalType', OriginalInfo.OriginalType) else: TypedefNode.set('OriginalType', f'struct {OriginalType}') TypedefNode.set('PendingTypedef', True) TypedefNode.set('file', '') self.SymbolTable[VarName] = TypedefNode.attributes self.GeneratedTypes.add(VarName) if isinstance(OriginalInfo, dict): OriginalInfo['skip_generation'] = True continue elif actual_type == 'struct': TypedefNode = SymbolNode.CreateClass( name=VarName, TypeKind='typedef', lineno=0 ) TypedefNode.set('OriginalType', f'struct {OriginalType}') TypedefNode.set('PendingTypedef', True) TypedefNode.set('file', '') self.SymbolTable[VarName] = TypedefNode.attributes self.GeneratedTypes.add(VarName) if isinstance(OriginalInfo, dict): OriginalInfo['skip_generation'] = True continue elif actual_type == 'enum': TypedefNode = SymbolNode.CreateClass( name=VarName, TypeKind='typedef', lineno=0 ) TypedefNode.set('OriginalType', f'enum {OriginalType}') TypedefNode.set('PendingTypedef', True) TypedefNode.set('file', '') self.SymbolTable[VarName] = TypedefNode.attributes self.GeneratedTypes.add(VarName) if isinstance(OriginalInfo, dict): OriginalInfo['skip_generation'] = True continue elif isinstance(Node.value, ast.Attribute): from lib.core.Handles.HandlesBase import CTypeHelper CName = CTypeHelper.GetCName(Node.value.attr) if CName: TypedefNode = SymbolNode.CreateClass( name=VarName, TypeKind='typedef', lineno=0 ) TypedefNode.set('OriginalType', CName) TypedefNode.set('file', '') self.SymbolTable[VarName] = TypedefNode.attributes self.GeneratedTypes.add(VarName) continue if Node.annotation: try: TypeInfo = self.TypeMergeHandler.GetCTypeInfo(Node.annotation) IsPtr = TypeInfo.IsPtr if TypeInfo else False except Exception as _e: if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": self.LogWarning(f"异常被忽略: {_e}") var_node = SymbolNode.CreateClass( name=VarName, TypeKind='variable', lineno=0 ) var_node.set('IsPtr', IsPtr) var_node.set('file', '') self.SymbolTable[VarName] = var_node.attributes self.LlvmGen = 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) return self.GenerateLlvmDirect(Tree)