Files
TransPyC/lib/Projectrans/DeclarationGenerator.py

748 lines
37 KiB
Python

import ast
from typing import List
from lib.includes import t
class DeclarationGenerator:
"""从 .pyi AST 生成纯 LLVM IR 声明(不使用字符串操作)"""
def __init__(self, struct_names=None, enum_names=None, module_sha1=None, target_triple=None, target_datalayout=None, struct_sha1_map=None, exception_names=None, typedef_map=None):
import llvmlite.ir as ir
self.ir = ir
self.module = None
self.builder = None
self._DefineConstants = {}
self.struct_names = struct_names or set()
self.enum_names = enum_names or set()
self.module_sha1 = module_sha1
self.struct_sha1_map = struct_sha1_map or {}
self.exception_names = exception_names or set()
self.target_triple = target_triple or "x86_64-none-elf"
self.target_datalayout = target_datalayout or "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
self.typedef_map = typedef_map or {}
t.configure_platform(self.target_triple)
def generate(self, pyi_content: str, src_path: str) -> str:
import ast
tree = ast.parse(pyi_content)
self._DefineConstants = {}
self._pyi_tree = tree
global_typedef_map = self.typedef_map
self.typedef_map = {}
if global_typedef_map:
self.typedef_map.update(global_typedef_map)
for node in ast.iter_child_nodes(tree):
if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name):
var_name = node.target.id
if node.value and isinstance(node.value, ast.Constant):
self._DefineConstants[var_name] = node.value.value
elif node.value and isinstance(node.value, ast.Name):
self._DefineConstants[var_name] = node.value.id
is_typedef = False
if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef':
is_typedef = True
elif isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef':
is_typedef = True
elif isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef':
is_typedef = True
if is_typedef:
if node.value:
self.typedef_map[var_name] = node.value
elif isinstance(node.annotation, ast.BinOp) and node.annotation.right:
self.typedef_map[var_name] = node.annotation.right
lines = []
lines.append('; ModuleID = "transpyc_decl"')
lines.append(f'target triple = "{self.target_triple}"')
lines.append(f'target datalayout = "{self.target_datalayout}"')
lines.append('')
for node in ast.iter_child_nodes(tree):
if isinstance(node, ast.FunctionDef):
if hasattr(node, 'type_params') and node.type_params:
continue
decl = self._generate_func_decl(node)
if decl:
lines.append(decl)
elif isinstance(node, ast.AnnAssign):
decl = self._generate_global_decl(node)
if decl:
lines.append(decl)
elif isinstance(node, ast.Assign):
decl = self._generate_global_assign_decl(node)
if decl:
lines.append(decl)
elif isinstance(node, ast.ClassDef):
if hasattr(node, 'type_params') and node.type_params:
continue
decls = self._generate_class_decl(node)
lines.extend(decls)
return '\n'.join(lines)
def _generate_func_decl(self, node: ast.FunctionDef) -> str:
"""生成函数声明"""
func_name = node.name
is_export = self._is_export_func(node)
if self.module_sha1 and not is_export:
func_name = f"{self.module_sha1}.{func_name}"
CReturnTypes = []
if node.decorator_list:
for decorator in node.decorator_list:
if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Attribute):
if decorator.func.attr == 'CReturn':
for arg in decorator.args:
CReturnTypes.append(arg)
if node.returns:
if isinstance(node.returns, ast.Subscript) and isinstance(node.returns.value, ast.Name) and node.returns.value.id == 'tuple':
slice_node = node.returns.slice
if isinstance(slice_node, ast.Tuple):
for elt in slice_node.elts:
CReturnTypes.append(elt)
else:
CReturnTypes.append(slice_node)
if CReturnTypes:
elem_types = [self._get_type_str(rt, embedded=True) for rt in CReturnTypes]
ret_type = '{ ' + ', '.join(elem_types) + ' }'
else:
ret_type = self._get_type_str(node.returns)
if not ret_type or ret_type == 'void':
ret_type = 'void'
elif ret_type == 'i8*':
if node.returns is None:
ret_type = 'void'
params = []
for arg in node.args.args:
if arg.annotation:
arg_type = self._get_type_str(arg.annotation)
else:
arg_type = 'i8*'
if arg_type and arg_type != 'void':
params.append(arg_type)
param_str = ', '.join(params) if params else ''
if node.args.vararg:
param_str = param_str + ', ...' if param_str else '...'
if func_name[0].isdigit():
return f'declare {ret_type} @"{func_name}"({param_str})'
return f'declare {ret_type} @{func_name}({param_str})'
def _is_export_func(self, node: ast.FunctionDef) -> bool:
"""检查函数是否标记为 CExport"""
if not node.returns:
return False
return self._check_annotation_for_export(node.returns)
def _check_annotation_for_export(self, annotation) -> bool:
"""递归检查类型注解中是否包含 CExport 或 t.State"""
if isinstance(annotation, ast.Attribute):
if hasattr(annotation, 'attr') and annotation.attr in ('CExport', 'State'):
return True
elif isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
return self._check_annotation_for_export(annotation.left) or self._check_annotation_for_export(annotation.right)
elif isinstance(annotation, ast.Name):
return annotation.id in ('CExport', 'State')
return False
def _generate_global_decl(self, node: ast.AnnAssign) -> str:
"""生成全局变量声明"""
if not isinstance(node.target, ast.Name):
return None
var_name = node.target.id
if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CDefine':
return None
if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef':
return None
if isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef':
return None
if isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef':
return None
if isinstance(node.annotation, ast.List):
for elt in node.annotation.elts:
if isinstance(elt, ast.Attribute) and hasattr(elt, 'attr') and elt.attr in ('CTypedef', 'Callable'):
return None
if isinstance(elt, ast.Subscript) and isinstance(elt.value, ast.Attribute) and isinstance(elt.value.value, ast.Name) and elt.value.value.id == 't' and elt.value.attr == 'Callable':
return None
VarType = self._get_type_str(node.annotation)
if VarType.startswith('[0 x ') and node.value and isinstance(node.value, ast.List):
elem_type = VarType[5:-1]
actual_count = len(node.value.elts)
if actual_count > 0:
VarType = f'[{actual_count} x {elem_type}]'
return f'@{var_name} = external global {VarType}'
def _generate_global_assign_decl(self, node: ast.Assign) -> str:
"""从无类型标注赋值推断并生成全局变量声明"""
if not node.targets or not isinstance(node.targets[0], ast.Name):
return None
var_name = node.targets[0].id
VarType = self._infer_type(node.value)
if VarType:
return f'@{var_name} = external global {VarType}'
return None
def _generate_class_decl(self, node: ast.ClassDef) -> List[str]:
"""生成结构体/类声明"""
decls = []
class_name = node.name
is_enum = False
is_exception = False
if node.bases:
for base in node.bases:
if isinstance(base, ast.Attribute) and hasattr(base, 'attr'):
if base.attr == 'CEnum' or base.attr == 'Enum':
is_enum = True
break
elif base.attr == 'Exception' or base.attr in self.exception_names:
is_exception = True
break
elif isinstance(base, ast.Name) and hasattr(base, 'id'):
if base.id == 'CEnum' or base.id == 'Enum':
is_enum = True
break
elif base.id == 'Exception' or base.id in self.exception_names:
is_exception = True
break
if is_exception:
return decls
if is_enum:
enum_values = {}
next_value = 0
for item in node.body:
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
var_name = item.target.id
if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
enum_values[var_name] = item.value.value
else:
enum_values[var_name] = next_value
next_value += 1
elif isinstance(item, ast.Assign) and len(item.targets) == 1 and isinstance(item.targets[0], ast.Name):
var_name = item.targets[0].id
if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
enum_values[var_name] = item.value.value
next_value = item.value.value + 1
else:
enum_values[var_name] = next_value
next_value += 1
for var_name, value in enum_values.items():
decls.append(f'@__config_{class_name}_{var_name} = external global i32')
return decls
member_types = []
has_bitfield = False
total_bits = 0
has_methods = any(isinstance(item, ast.FunctionDef) for item in node.body)
is_cvtable = False
is_cpython_object = 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':
if decorator.attr == 'CVTable':
is_cvtable = True
elif decorator.attr == 'Object':
is_cpython_object = True
elif isinstance(decorator, ast.Name):
if decorator.id == 'CVTable':
is_cvtable = True
elif decorator.id == 'Object':
is_cpython_object = True
if has_methods and not is_cpython_object:
is_cpython_object = True
has_parent_class = False
for base in node.bases:
base_name = None
if isinstance(base, ast.Attribute):
base_name = base.attr
elif isinstance(base, ast.Name):
base_name = base.id
elif isinstance(base, ast.Subscript):
if isinstance(base.value, ast.Attribute):
base_name = base.value.attr
elif isinstance(base.value, ast.Name):
base_name = base.value.id
if base_name and base_name not in ('Object', 'CVTable', 'CEnum', 'Enum', 'CStruct', 'CUnion'):
has_parent_class = True
break
if has_parent_class and not is_cvtable:
is_cvtable = True
base_has_vtable = False
for base in node.bases:
base_name = None
if isinstance(base, ast.Attribute):
base_name = base.attr
elif isinstance(base, ast.Name):
base_name = base.id
elif isinstance(base, ast.Subscript):
if isinstance(base.value, ast.Attribute):
base_name = base.value.attr
elif isinstance(base.value, ast.Name):
base_name = base.value.id
if base_name and base_name not in ('Object', 'CVTable', 'CEnum', 'Enum', 'CStruct', 'CUnion'):
for n in ast.iter_child_nodes(self._pyi_tree):
if isinstance(n, ast.ClassDef) and n.name == base_name:
if hasattr(n, 'decorator_list') and n.decorator_list:
for dec in n.decorator_list:
if isinstance(dec, ast.Attribute) and getattr(dec.value, 'id', None) == 't' and dec.attr == 'CVTable':
base_has_vtable = True
elif isinstance(dec, ast.Name) and dec.id == 'CVTable':
base_has_vtable = True
break
if base_has_vtable:
break
if has_methods and is_cvtable and not base_has_vtable:
member_types.append('i8*')
seen_member_names = set()
for base in node.bases:
base_name = None
if isinstance(base, ast.Attribute):
base_name = base.attr
elif isinstance(base, ast.Name):
base_name = base.id
elif isinstance(base, ast.Subscript):
if isinstance(base.value, ast.Attribute):
base_name = base.value.attr
elif isinstance(base.value, ast.Name):
base_name = base.value.id
if base_name and base_name not in ('Object', 'CVTable', 'CEnum', 'Enum', 'CStruct', 'CUnion'):
base_member_types, base_seen = self._get_inherited_members(base_name)
for mt in base_member_types:
member_types.append(mt)
seen_member_names.update(base_seen)
for item in node.body:
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
seen_member_names.add(item.target.id)
init_members = []
for item in node.body:
if isinstance(item, ast.FunctionDef) and item.name == '__init__':
for stmt in item.body:
if (isinstance(stmt, ast.AnnAssign)
and isinstance(stmt.target, ast.Attribute)
and isinstance(stmt.target.value, ast.Name)
and stmt.target.value.id == 'self'):
init_members.append(stmt)
untyped_self_members = []
for m_name in [m.attr for m in init_members if isinstance(m.target, ast.Attribute)]:
seen_member_names.add(m_name)
for item in node.body:
if isinstance(item, ast.FunctionDef):
if hasattr(item, 'type_params') and item.type_params:
continue
for stmt in item.body:
if (isinstance(stmt, ast.Assign)
and len(stmt.targets) == 1
and isinstance(stmt.targets[0], ast.Attribute)
and isinstance(stmt.targets[0].value, ast.Name)
and stmt.targets[0].value.id == 'self'):
attr_name = stmt.targets[0].attr
if attr_name not in seen_member_names:
seen_member_names.add(attr_name)
untyped_self_members.append(stmt)
for item in list(node.body) + init_members + untyped_self_members:
if isinstance(item, ast.AnnAssign):
bit_width = self._get_bitfield_width(item.annotation)
if bit_width is not None:
has_bitfield = True
total_bits += bit_width
else:
VarType = self._get_type_str(item.annotation, embedded=True)
if (isinstance(item.annotation, ast.Subscript)
and isinstance(item.annotation.value, ast.Name)
and item.annotation.value.id == 'list'):
slice_node = item.annotation.slice
is_dynamic = False
if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2:
count_node = slice_node.elts[1]
if isinstance(count_node, ast.Constant) and count_node.value is None:
is_dynamic = True
elif not (isinstance(count_node, ast.Constant) and isinstance(count_node.value, int) and count_node.value > 0):
if not isinstance(count_node, (ast.Name, ast.BinOp)):
is_dynamic = True
elif not isinstance(slice_node, ast.Tuple):
is_dynamic = True
if is_dynamic:
elem_type = self._get_type_str(slice_node if not isinstance(slice_node, ast.Tuple) else slice_node.elts[0], embedded=True)
init_len = 0
if isinstance(item.value, ast.List):
init_len = len(item.value.elts)
elif isinstance(item.value, ast.Constant) and isinstance(item.value.value, str):
init_len = len(item.value.value) + 1
VarType = f'[{init_len} x {elem_type}]'
member_types.append(VarType)
elif isinstance(item, ast.Assign):
if (len(item.targets) == 1
and isinstance(item.targets[0], ast.Attribute)
and isinstance(item.targets[0].value, ast.Name)
and item.targets[0].value.id == 'self'):
attr_name = item.targets[0].attr
if attr_name in seen_member_names:
continue
InferredType = 'i32'
if item.value and isinstance(item.value, ast.Constant):
if isinstance(item.value.value, float):
InferredType = 'float'
elif isinstance(item.value.value, bool):
InferredType = 'i8'
elif isinstance(item.value.value, str):
InferredType = 'i8*'
member_types.append(InferredType)
else:
member_types.append('i32')
if has_bitfield:
if total_bits <= 8:
member_types.insert(0, 'i8')
elif total_bits <= 16:
member_types.insert(0, 'i16')
elif total_bits <= 32:
member_types.insert(0, 'i32')
else:
member_types.insert(0, 'i64')
struct_type_name = f'%"{self.module_sha1}.{class_name}"' if self.module_sha1 else f'%struct.{class_name}'
struct_decl = f'{struct_type_name} = type {{ {", ".join(member_types)} }}'
decls.append(struct_decl)
if is_cpython_object or is_cvtable:
new_func_name = f'{class_name}.__before_init__'
if self.module_sha1:
new_func_name = f"{self.module_sha1}.{new_func_name}"
if new_func_name[0].isdigit():
new_func_decl = f'declare void @"{new_func_name}"({struct_type_name}*)'
else:
new_func_decl = f'declare void @{new_func_name}({struct_type_name}*)'
decls.append(new_func_decl)
for item in node.body:
if isinstance(item, ast.FunctionDef):
if hasattr(item, 'type_params') and item.type_params:
continue
method_name = f'{class_name}.{item.name}'
if self.module_sha1:
method_name = f"{self.module_sha1}.{method_name}"
ret_type = self._get_type_str(item.returns) if item.returns else 'void'
if not ret_type:
ret_type = 'void'
params = []
for arg_idx, arg in enumerate(item.args.args):
if arg.annotation:
arg_type = self._get_type_str(arg.annotation)
elif arg_idx == 0 and arg.arg == 'self':
arg_type = f'{struct_type_name}*'
else:
arg_type = 'i8*'
params.append(arg_type)
param_str = ', '.join(params) if params else ''
if method_name[0].isdigit():
decls.append(f'declare {ret_type} @"{method_name}"({param_str})')
else:
decls.append(f'declare {ret_type} @{method_name}({param_str})')
return decls
def _get_inherited_members(self, base_name: str):
import ast
member_types = []
seen_names = set()
if not hasattr(self, '_pyi_tree') or self._pyi_tree is None:
return member_types, seen_names
base_node = None
for node in ast.iter_child_nodes(self._pyi_tree):
if isinstance(node, ast.ClassDef) and node.name == base_name:
base_node = node
break
if base_node is None:
return member_types, seen_names
base_decls = self._generate_class_decl(base_node)
for decl in base_decls:
if '= type {' in decl:
type_body = decl.split('= type {')[1].rstrip('}').strip()
if type_body:
for t in type_body.split(','):
t = t.strip()
if t:
member_types.append(t)
break
for item in base_node.body:
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
seen_names.add(item.target.id)
elif isinstance(item, ast.Assign) and len(item.targets) == 1:
if isinstance(item.targets[0], ast.Attribute) and isinstance(item.targets[0].value, ast.Name) and item.targets[0].value.id == 'self':
seen_names.add(item.targets[0].attr)
for item in base_node.body:
if isinstance(item, ast.FunctionDef) and item.name == '__init__':
for stmt in item.body:
if isinstance(stmt, ast.AnnAssign) and isinstance(stmt.target, ast.Attribute) and isinstance(stmt.target.value, ast.Name) and stmt.target.value.id == 'self':
seen_names.add(stmt.target.attr)
elif isinstance(stmt, ast.Assign) and len(stmt.targets) == 1 and isinstance(stmt.targets[0], ast.Attribute) and isinstance(stmt.targets[0].value, ast.Name) and stmt.targets[0].value.id == 'self':
seen_names.add(stmt.targets[0].attr)
return member_types, seen_names
@staticmethod
def _ctype_name_to_llvm(name: str) -> str:
"""根据 CType 元属性自动推导 LLVM IR 类型
通过 CTypeRegistry.NameToLLVM 查询,利用 CType 的
position/IsSigned/Size 元属性自动推导,无需手动映射表。
"""
from lib.includes.t import CTypeRegistry
result = CTypeRegistry.NameToLLVM(name)
return result
def _get_type_str(self, annotation: ast.AST, embedded: bool = False) -> str:
import ast
from lib.includes.t import CTypeRegistry
if annotation is None:
return 'i8*'
non_struct_types = {'list', 'dict', 'tuple', 'set', 'array'}
if isinstance(annotation, ast.Name):
if annotation.id == 'None':
return 'void'
if annotation.id in ('str', 'bytes'):
return 'i8*'
llvm_type = CTypeRegistry.NameToLLVM(annotation.id)
if llvm_type is not None:
return llvm_type
resolved = CTypeRegistry.ResolveName(annotation.id)
if resolved is not None:
ctype_cls, ptr_level = resolved
base = CTypeRegistry.CTypeToLLVM(ctype_cls)
if ptr_level > 0:
if base == 'void':
return 'i8*'
if '*' in base:
return base
return f'{base}*'
return base
if annotation.id in non_struct_types:
return 'i32'
if annotation.id in self.enum_names:
return 'i32'
if annotation.id in self.struct_names:
sha1 = self.struct_sha1_map.get(annotation.id, self.module_sha1)
sname = f'%"{sha1}.{annotation.id}"' if sha1 else f'%struct.{annotation.id}'
if embedded:
return sname
else:
return f'{sname}*'
if annotation.id in self.typedef_map:
resolved = self._get_type_str(self.typedef_map[annotation.id], embedded=embedded)
return resolved
sha1 = self.struct_sha1_map.get(annotation.id, self.module_sha1)
sname = f'%"{sha1}.{annotation.id}"' if sha1 else f'%struct.{annotation.id}'
return f'{sname}*'
elif isinstance(annotation, ast.Attribute):
attr_name = annotation.attr if hasattr(annotation, 'attr') else ''
module_name = ''
if hasattr(annotation, 'value'):
if isinstance(annotation.value, ast.Name):
module_name = annotation.value.id
elif isinstance(annotation.value, ast.Attribute) and hasattr(annotation.value, 'attr'):
module_name = annotation.value.attr
if (module_name == 't' and attr_name == 'State') or attr_name == 'State':
return ''
if (module_name == 't' and attr_name == 'Callable') or attr_name == 'Callable':
return 'i8*'
llvm_type = CTypeRegistry.NameToLLVM(attr_name)
if llvm_type is not None:
return llvm_type
resolved = CTypeRegistry.ResolveName(attr_name)
if resolved is not None:
ctype_cls, ptr_level = resolved
base = CTypeRegistry.CTypeToLLVM(ctype_cls)
if ptr_level > 0:
if base == 'void':
return 'i8*'
if '*' in base:
return base
return f'{base}*'
return base
if attr_name in self.typedef_map:
return self._get_type_str(self.typedef_map[attr_name], embedded=embedded)
if attr_name in self.enum_names:
return 'i32'
if attr_name in self.struct_names:
sha1 = self.struct_sha1_map.get(attr_name, self.module_sha1)
sname = f'%"{sha1}.{attr_name}"' if sha1 else f'%struct.{attr_name}'
if embedded:
return sname
else:
return f'{sname}*'
if attr_name and attr_name[0].isupper() and attr_name not in non_struct_types:
sha1 = self.struct_sha1_map.get(attr_name, self.module_sha1)
sname = f'%"{sha1}.{attr_name}"' if sha1 else f'%struct.{attr_name}'
return f'{sname}*'
if attr_name and attr_name not in non_struct_types:
sha1 = self.struct_sha1_map.get(attr_name, self.module_sha1)
sname = f'%"{sha1}.{attr_name}"' if sha1 else f'%struct.{attr_name}'
return f'{sname}*'
return 'i32'
elif isinstance(annotation, ast.BinOp):
left_type = self._get_type_str(annotation.left, embedded=embedded)
right_type = self._get_type_str(annotation.right, embedded=embedded)
if left_type in ('', 'void'):
return right_type if right_type not in ('', 'void') else (left_type or right_type)
if right_type in ('', 'void'):
return left_type
if '*' in left_type:
return left_type
if '*' in right_type:
if right_type == 'i8*':
return self._type_to_llvm_ptr(left_type)
return right_type
return left_type
elif isinstance(annotation, ast.Subscript):
base = self._get_type_str(annotation.value)
if base == 'i8*' and isinstance(annotation.slice, ast.Constant):
return f'[{self._get_const_int(annotation.slice)} x i8]'
if isinstance(annotation.slice, ast.Constant) and isinstance(annotation.slice.value, int):
return f'[{annotation.slice.value} x {base}]'
if isinstance(annotation.value, ast.Name) and annotation.value.id == 'list':
slice_node = annotation.slice
if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2:
elem_type = self._get_type_str(slice_node.elts[0], embedded=True)
count_node = slice_node.elts[1]
array_count = self._get_const_int(count_node)
if array_count > 0:
return f'[{array_count} x {elem_type}]'
else:
return f'[0 x {elem_type}]'
elem_type = self._get_type_str(slice_node, embedded=True)
return f'[0 x {elem_type}]'
if isinstance(annotation.value, ast.Name) and annotation.value.id == 'tuple':
slice_node = annotation.slice
if isinstance(slice_node, ast.Tuple):
elem_types = [self._get_type_str(e, embedded=True) for e in slice_node.elts]
else:
elem_types = [self._get_type_str(slice_node, embedded=True)]
return '{ ' + ', '.join(elem_types) + ' }'
return f'{base}'
elif isinstance(annotation, ast.Constant):
if annotation.value is None:
return 'void'
if isinstance(annotation.value, int):
return 'i32'
if isinstance(annotation.value, str):
type_name = annotation.value
if type_name in self.enum_names:
return 'i32'
if type_name in self.struct_names:
sha1 = self.struct_sha1_map.get(type_name, self.module_sha1)
sname = f'%"{sha1}.{type_name}"' if sha1 else f'%struct.{type_name}'
if embedded:
return sname
else:
return f'{sname}*'
llvm_type = CTypeRegistry.NameToLLVM(type_name)
if llvm_type is not None:
return llvm_type
resolved = CTypeRegistry.ResolveName(type_name)
if resolved is not None:
ctype_cls, ptr_level = resolved
base = CTypeRegistry.CTypeToLLVM(ctype_cls)
if ptr_level > 0:
if base == 'void':
return 'i8*'
if '*' in base:
return base
return f'{base}*'
return base
sha1 = self.struct_sha1_map.get(type_name, self.module_sha1)
sname = f'%"{sha1}.{type_name}"' if sha1 else f'%struct.{type_name}'
return f'{sname}*'
return 'i8*'
elif isinstance(annotation, ast.Call):
if isinstance(annotation.func, ast.Name) and annotation.func.id == 'callable':
return 'i8*'
if isinstance(annotation.func, ast.Attribute) and annotation.func.attr == 'Callable':
return 'i8*'
return 'i32'
def _type_to_llvm_ptr(self, type_str: str) -> str:
if type_str.startswith('%struct.') and not type_str.endswith('*'):
return type_str + '*'
if type_str.startswith('%') and not type_str.endswith('*'):
return type_str + '*'
if type_str.endswith('*'):
return type_str
from lib.includes.t import CTypeRegistry
resolved = CTypeRegistry.ResolveName(type_str)
if resolved is not None:
ctype_cls, ptr_level = resolved
llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
if llvm_str:
return f'{llvm_str}{"*" * (ptr_level + 1)}'
cnameres = CTypeRegistry.CNameToClass(type_str)
if cnameres is not None:
llvm_str = CTypeRegistry.CTypeToLLVM(cnameres)
if llvm_str:
return f'{llvm_str}*'
return f'{type_str}*'
def _infer_type(self, value: ast.AST) -> str:
"""从值推断类型"""
import ast
if isinstance(value, ast.Constant):
if isinstance(value.value, int):
return 'i32'
elif isinstance(value.value, float):
return 'double'
elif isinstance(value.value, str):
return 'i8*'
elif isinstance(value.value, bool):
return 'i8'
elif isinstance(value, ast.List):
return 'i8*'
elif isinstance(value, ast.Dict):
return 'i8*'
elif isinstance(value, ast.Name):
return 'i32'
elif isinstance(value, ast.BinOp):
return self._infer_type(value.left)
elif isinstance(value, ast.Call):
return 'i8*'
return 'i32'
def _get_bitfield_width(self, annotation: ast.AST):
import ast
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
right_width = self._get_bitfield_width(annotation.right)
if right_width is not None:
return right_width
return self._get_bitfield_width(annotation.left)
if isinstance(annotation, ast.Call):
if isinstance(annotation.func, ast.Attribute) and annotation.func.attr == 'Bit':
if annotation.args:
arg = annotation.args[0]
if isinstance(arg, ast.Constant) and isinstance(arg.value, int):
return arg.value
if isinstance(annotation, ast.Subscript):
if isinstance(annotation.value, ast.Attribute) and annotation.value.attr == 'Bit':
if isinstance(annotation.slice, ast.Constant) and isinstance(annotation.slice.value, int):
return annotation.slice.value
return None
def _get_const_int(self, node: ast.AST) -> int:
"""获取常量整数值,支持符号常量和简单表达式"""
import ast
if isinstance(node, ast.Constant) and isinstance(node.value, int):
return node.value
if isinstance(node, ast.Name):
if node.id in self._DefineConstants:
val = self._DefineConstants[node.id]
if isinstance(val, int):
return val
if isinstance(node, ast.BinOp):
left_val = self._get_const_int(node.left)
right_val = self._get_const_int(node.right)
if left_val and right_val:
if isinstance(node.op, ast.Add):
return left_val + right_val
if isinstance(node.op, ast.Sub):
return left_val - right_val
if isinstance(node.op, ast.Mult):
return left_val * right_val
if isinstance(node.op, ast.Div):
return left_val // right_val
if isinstance(node.op, ast.FloorDiv):
return left_val // right_val
return 0