可用的回归测试通过的标准版本

This commit is contained in:
2026-06-18 00:39:43 +08:00
parent bffb0cb6b7
commit e02c867edf
365 changed files with 22562 additions and 24532 deletions

View File

@@ -0,0 +1,622 @@
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', '<stdin>')
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', '<stdin>')
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', '<stdin>')
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', '<stdin>')
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', '<stdin>')
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', '<stdin>')
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', '<stdin>')
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', '<stdin>')
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', '<stdin>')
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', '<stdin>')
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', '<stdin>')
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)