from __future__ import annotations import ast import re from typing import List import llvmlite.ir as ir from lib.includes import t from lib.includes.t import CTypeRegistry from lib.core.SymbolUtils import IsListAnnotation, AnnotationContainsName class DeclarationGenerator: """从 .pyi AST 生成纯 LLVM IR 声明(不使用字符串操作)""" # 匹配 LLVM 数组类型:[N x elem_type] _ARRAY_TYPE_RE: re.Pattern = re.compile(r'^\[(\d+)\s+x\s+(.+)\]$') @staticmethod def _decay_array_to_ptr(type_str: str) -> str: """C 语言中数组参数退化为指针:[N x elem_type] → elem_type*""" m = DeclarationGenerator._ARRAY_TYPE_RE.match(type_str) if m: return f'{m.group(2)}*' return type_str def __init__(self, struct_names: set[str] | None = None, enum_names: set[str] | None = None, module_sha1: str | None = None, target_triple: str | None = None, target_datalayout: str | None = None, struct_sha1_map: dict[str, str] | None = None, exception_names: set[str] | None = None, typedef_map: dict[str, ast.AST] | None = None) -> None: self.ir: ir.Module = ir self.module: ir.Module | None = None self.builder: ir.IRBuilder | None = None self._DefineConstants: dict[str, int | str] = {} self.struct_names: set[str] = struct_names or set() self.enum_names: set[str] = enum_names or set() self.module_sha1: str | None = module_sha1 self.struct_sha1_map: dict[str, str] = struct_sha1_map or {} self.exception_names: set[str] = exception_names or set() self.target_triple: str = target_triple or "x86_64-none-elf" self.target_datalayout: str = 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: dict[str, ast.AST] = typedef_map or {} self._pyi_tree: ast.Module | None = None self._t_alias_map: dict[str, type] = {} t.configure_platform(self.target_triple) def generate(self, pyi_content: str, src_path: str) -> str: tree: ast.Module = ast.parse(pyi_content) self._DefineConstants: dict[str, int | str] = {} self._pyi_tree = tree global_typedef_map: dict[str, ast.AST] = self.typedef_map self.typedef_map: dict[str, ast.AST] = {} if global_typedef_map: self.typedef_map.update(global_typedef_map) # 构建 t/c 类型别名映射(from t import CInt as myint) self._t_alias_map: dict[str, type] = {} for node in ast.iter_child_nodes(tree): if isinstance(node, ast.ImportFrom): if node.module in ('t', 'c'): for alias in node.names: name: str = alias.name asname: str = alias.asname or name if node.module == 't': t_cls: type | None = getattr(t, name, None) if isinstance(t_cls, type) and issubclass(t_cls, t.CType): self._t_alias_map[asname] = t_cls for node in ast.iter_child_nodes(tree): if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name): var_name: str = 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: bool = 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: list[str] = [] 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: str | None = self._generate_func_decl(node) if decl: lines.append(decl) elif isinstance(node, ast.AnnAssign): decl: str | None = self._generate_global_decl(node) if decl: lines.append(decl) elif isinstance(node, ast.Assign): decl: str | None = 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: list[str] = self._generate_class_decl(node) lines.extend(decls) return '\n'.join(lines) def _generate_func_decl(self, node: ast.FunctionDef) -> str | None: """生成函数声明""" func_name: str = node.name is_export: bool = self._is_export_func(node) if self.module_sha1 and not is_export: func_name = f"{self.module_sha1}.{func_name}" CReturnTypes: list[ast.AST] = [] 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: ast.AST = node.returns.slice if isinstance(slice_node, ast.Tuple): for elt in slice_node.elts: CReturnTypes.append(elt) else: CReturnTypes.append(slice_node) ret_type: str if CReturnTypes: elem_types: list[str] = [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: list[str] = [] for arg in node.args.args: arg_type: str if arg.annotation: arg_type = self._get_type_str(arg.annotation) else: arg_type = 'i8*' # C 语言中数组参数退化为指针:[N x elem_type] → elem_type* arg_type = self._decay_array_to_ptr(arg_type) if arg_type and arg_type != 'void': params.append(arg_type) param_str: 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: ast.AST | None) -> bool: """递归检查类型注解中是否包含 CExport 或 t.State""" return bool(annotation) and (AnnotationContainsName(annotation, 'CExport') or AnnotationContainsName(annotation, 'State')) def _generate_global_decl(self, node: ast.AnnAssign) -> str | None: """生成全局变量声明""" if not isinstance(node.target, ast.Name): return None var_name: str = 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: str = self._get_type_str(node.annotation) if VarType.startswith('[0 x ') and node.value and isinstance(node.value, ast.List): elem_type: str = VarType[5:-1] actual_count: int = 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 | None: """从无类型标注赋值推断并生成全局变量声明""" if not node.targets or not isinstance(node.targets[0], ast.Name): return None var_name: str = node.targets[0].id VarType: str | None = self._infer_type(node.value) if VarType: return f'@{var_name} = external global {VarType}' return None def _resolve_base_kind(self, base_name: str) -> str | None: """解析基类名称的类型种类(支持别名) Returns: 'enum' | 'union' | 'renum' | 'struct' | None """ # 1) 查 t 别名映射(from t import CEnum as en) if base_name in self._t_alias_map: t_cls: type = self._t_alias_map[base_name] if issubclass(t_cls, (t.CEnum, t.REnum)): return 'renum' if issubclass(t_cls, t.REnum) else 'enum' if issubclass(t_cls, t.CUnion): return 'union' if issubclass(t_cls, t.CStruct): return 'struct' # 2) 直接查 t 模块属性 t_cls: type | None = getattr(t, base_name, None) if isinstance(t_cls, type) and issubclass(t_cls, t.CType): if issubclass(t_cls, (t.CEnum, t.REnum)): return 'renum' if issubclass(t_cls, t.REnum) else 'enum' if issubclass(t_cls, t.CUnion): return 'union' if issubclass(t_cls, t.CStruct): return 'struct' return None def _is_marker_base(self, base_name: str) -> bool: """检查是否为标记基类(Object/CVTable/Exception/CEnum/CUnion/CStruct/REnum 及其别名)""" if base_name in ('Object', 'CVTable', 'Exception', 'CEnum', 'Enum', 'CStruct', 'CUnion', 'REnum'): return True if self._resolve_base_kind(base_name) is not None: return True return False def _generate_class_decl(self, node: ast.ClassDef) -> List[str]: """生成结构体/类声明""" decls: list[str] = [] class_name: str = node.name is_enum: bool = False is_renum: bool = False is_union: bool = False is_exception: bool = False if node.bases: for base in node.bases: base_name: str | None = None if isinstance(base, ast.Attribute) and hasattr(base, 'attr'): base_name = base.attr elif isinstance(base, ast.Name) and hasattr(base, 'id'): base_name = base.id if base_name: if base_name in self.exception_names or base_name == 'Exception': is_exception = True break kind: str | None = self._resolve_base_kind(base_name) if kind == 'enum': is_enum = True break elif kind == 'union': is_union = True elif kind == 'renum': is_renum = True if is_exception: return decls if is_enum: enum_values: dict[str, int] = {} next_value: int = 0 for item in node.body: if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): var_name: str = 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: str = 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: list[str] = [] has_bitfield: bool = False total_bits: int = 0 has_methods: bool = any(isinstance(item, ast.FunctionDef) for item in node.body) is_cvtable: bool = False is_cpython_object: 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': 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: bool = False for base in node.bases: base_name: str | None = 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 not self._is_marker_base(base_name): has_parent_class = True break if has_parent_class and not is_cvtable: is_cvtable = True base_has_vtable: bool = False for base in node.bases: base_name: str | None = 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 not self._is_marker_base(base_name): 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[str] = set() for base in node.bases: base_name: str | None = 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 not self._is_marker_base(base_name): base_member_types: list[str] base_seen: set[str] 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: list[ast.AnnAssign] = [] 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: list[ast.Assign] = [] 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: str = 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): # 跳过编译期元数据字段(__provides__/__requires__/__require_must__) if isinstance(item.target, ast.Name) and item.target.id in ('__provides__', '__requires__', '__require_must__'): continue bit_width: int | None = self._get_bitfield_width(item.annotation) if bit_width is not None: has_bitfield = True total_bits += bit_width else: VarType: str = self._get_type_str(item.annotation, embedded=True) if IsListAnnotation(item.annotation): slice_node: ast.AST = item.annotation.slice is_dynamic: bool = False if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: count_node: ast.AST = 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: str = self._get_type_str(slice_node if not isinstance(slice_node, ast.Tuple) else slice_node.elts[0], embedded=True) init_len: int = 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}]' else: # 固定大小数组: t.CArray[elem_type, count] → [count x elem_type] if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: elem_type: str = self._get_type_str(slice_node.elts[0], embedded=True) count_val: int = self._get_const_int(slice_node.elts[1]) if count_val > 0: VarType = f'[{count_val} x {elem_type}]' elif isinstance(slice_node, (ast.Attribute, ast.Name, ast.Subscript)): # 单参数 t.CArray[elem_type] → 指针模式 elem_type: str = self._get_type_str(slice_node, embedded=True) VarType = f'{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: str = item.targets[0].attr if attr_name in seen_member_names: continue InferredType: str = '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: str = f'%"{self.module_sha1}.{class_name}"' if self.module_sha1 else f'%struct.{class_name}' struct_decl: str = f'{struct_type_name} = type {{ {", ".join(member_types)} }}' decls.append(struct_decl) if is_cpython_object or is_cvtable: new_func_name: str = f'{class_name}.__before_init__' if self.module_sha1: new_func_name = f"{self.module_sha1}.{new_func_name}" new_func_decl: str 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: str = f'{class_name}.{item.name}' if self.module_sha1: method_name = f"{self.module_sha1}.{method_name}" ret_type: str = self._get_type_str(item.returns) if item.returns else 'void' if not ret_type: ret_type = 'void' params: list[str] = [] for arg_idx, arg in enumerate(item.args.args): arg_type: str 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*' # C 语言中数组参数退化为指针:[N x elem_type] → elem_type* arg_type = self._decay_array_to_ptr(arg_type) params.append(arg_type) param_str: 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) -> tuple[list[str], set[str]]: member_types: list[str] = [] seen_names: set[str] = set() if not hasattr(self, '_pyi_tree') or self._pyi_tree is None: return member_types, seen_names base_node: ast.ClassDef | None = 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: list[str] = self._generate_class_decl(base_node) for decl in base_decls: if '= type {' in decl: type_body: str = 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 元属性自动推导,无需手动映射表。 """ result: str = CTypeRegistry.NameToLLVM(name) return result def _get_type_str(self, annotation: ast.AST | None, embedded: bool = False) -> str: if annotation is None: return 'i8*' non_struct_types: set[str] = {'list', 'dict', 'tuple', 'set', 'array', 'CArray'} if isinstance(annotation, ast.Name): if annotation.id == 'None': return 'void' if annotation.id in ('str', 'bytes'): return 'i8*' llvm_type: str | None = CTypeRegistry.NameToLLVM(annotation.id) if llvm_type is not None: return llvm_type resolved: tuple[type, int] | None = CTypeRegistry.ResolveName(annotation.id) if resolved is not None: ctype_cls: type ptr_level: int ctype_cls, ptr_level = resolved base: str = 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 self.struct_names: sha1: str | None = self.struct_sha1_map.get(annotation.id, self.module_sha1) sname: str = f'%"{sha1}.{annotation.id}"' if sha1 else f'%struct.{annotation.id}' if embedded: return sname else: return f'{sname}*' if annotation.id in non_struct_types: return 'i32' if annotation.id in self.enum_names: return 'i32' if annotation.id in self.typedef_map: resolved_str: str = self._get_type_str(self.typedef_map[annotation.id], embedded=embedded) return resolved_str # 检查 t 类型别名(from t import CInt as myint) if annotation.id in self._t_alias_map: t_cls: type = self._t_alias_map[annotation.id] llvm: str | None = CTypeRegistry.CTypeToLLVM(t_cls) if llvm: return llvm sha1: str | None = self.struct_sha1_map.get(annotation.id, self.module_sha1) sname: str = f'%"{sha1}.{annotation.id}"' if sha1 else f'%struct.{annotation.id}' return f'{sname}*' elif isinstance(annotation, ast.Attribute): attr_name: str = annotation.attr if hasattr(annotation, 'attr') else '' module_name: str = '' 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: str | None = CTypeRegistry.NameToLLVM(attr_name) if llvm_type is not None: return llvm_type resolved: tuple[type, int] | None = CTypeRegistry.ResolveName(attr_name) if resolved is not None: ctype_cls: type ptr_level: int ctype_cls, ptr_level = resolved base: str = 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: str | None = self.struct_sha1_map.get(attr_name, self.module_sha1) sname: str = 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: str | None = self.struct_sha1_map.get(attr_name, self.module_sha1) sname: str = 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: str | None = self.struct_sha1_map.get(attr_name, self.module_sha1) sname: str = f'%"{sha1}.{attr_name}"' if sha1 else f'%struct.{attr_name}' return f'{sname}*' return 'i32' elif isinstance(annotation, ast.BinOp): left_type: str = self._get_type_str(annotation.left, embedded=embedded) right_type: str = 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: str = 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 == 'tuple': slice_node: ast.AST = annotation.slice elem_types: list[str] 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) + ' }' # 处理泛型类类型注解(如 list[str]) if isinstance(annotation.value, ast.Name): gc_name: str = annotation.value.id if gc_name in non_struct_types and gc_name != 'tuple': gc_slice: ast.AST = annotation.slice gc_args: list[str] = [] if isinstance(gc_slice, ast.Name): gc_args.append(gc_slice.id) elif isinstance(gc_slice, ast.Tuple): gc_valid: bool = True for gc_elt in gc_slice.elts: if isinstance(gc_elt, ast.Name): gc_args.append(gc_elt.id) else: gc_valid = False break if not gc_valid: gc_args = [] if gc_args: gc_mangled: list[str] = [] for gc_ta in gc_args: gc_llvm: str | None = CTypeRegistry.NameToLLVM(gc_ta) if gc_llvm: if gc_llvm in ('float', 'double', 'half', 'fp128'): gc_cls: type | None = CTypeRegistry.GetClassByName(gc_ta) gc_sz: int = gc_cls().Size if gc_cls else 0 gc_mangled.append('f' + str(gc_sz)) else: gc_mangled.append(gc_llvm) else: gc_mangled.append(gc_ta) gc_spec: str = gc_name + '[' + ']['.join(gc_mangled) + ']' gc_sha1: str | None = self.module_sha1 gc_sname: str = f'%"{gc_sha1}.{gc_spec}"' if gc_sha1 else f'%struct.{gc_spec}' if embedded: return gc_sname return f'{gc_sname}*' 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: str = annotation.value if type_name in self.enum_names: return 'i32' if type_name in self.struct_names: sha1: str | None = self.struct_sha1_map.get(type_name, self.module_sha1) sname: str = f'%"{sha1}.{type_name}"' if sha1 else f'%struct.{type_name}' if embedded: return sname else: return f'{sname}*' llvm_type: str | None = CTypeRegistry.NameToLLVM(type_name) if llvm_type is not None: return llvm_type resolved: tuple[type, int] | None = CTypeRegistry.ResolveName(type_name) if resolved is not None: ctype_cls: type ptr_level: int ctype_cls, ptr_level = resolved base: str = CTypeRegistry.CTypeToLLVM(ctype_cls) if ptr_level > 0: if base == 'void': return 'i8*' if '*' in base: return base return f'{base}*' return base sha1: str | None = self.struct_sha1_map.get(type_name, self.module_sha1) sname: str = 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 resolved: tuple[type, int] | None = CTypeRegistry.ResolveName(type_str) if resolved is not None: ctype_cls: type ptr_level: int ctype_cls, ptr_level = resolved llvm_str: str = CTypeRegistry.CTypeToLLVM(ctype_cls) if llvm_str: return f'{llvm_str}{"*" * (ptr_level + 1)}' return f'{type_str}*' def _infer_type(self, value: ast.AST) -> str: """从值推断类型""" 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) -> int | None: if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): right_width: int | None = 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: ast.AST = 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: """获取常量整数值,支持符号常量和简单表达式""" 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: int | str = self._DefineConstants[node.id] if isinstance(val, int): return val if isinstance(node, ast.BinOp): left_val: int = self._get_const_int(node.left) right_val: int = 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