Files
TransPyC/lib/Projectrans/DeclarationGenerator.py

1185 lines
61 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
import ast
import re
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, class_def_map: dict[str, ast.ClassDef] | 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] = {}
# 跨模块类定义映射:{class_name: ClassDef_node},供 _get_inherited_members
# 查找其他模块定义的父类(如 exprs.py 的 Name(AST) 查找 base.py 的 AST
self._cross_module_class_defs: dict[str, ast.ClassDef] = class_def_map or {}
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)
# 后处理:扫描引用但未定义的结构体类型,自动添加 opaque 声明
# 这解决了泛型类(如 list[T])在 stub 中被跳过导致的 "undefined type" 错误
opaque_decls: list[str] = self._collect_undefined_type_decls(lines)
if opaque_decls:
# 在 header 之后插入 opaque 声明ModuleID, triple, datalayout, 空行 = 4 行)
insert_idx: int = 4
for i, od in enumerate(opaque_decls):
lines.insert(insert_idx + i, od)
return '\n'.join(lines)
def _collect_undefined_type_decls(self, lines: list[str]) -> list[str]:
"""扫描所有引用的 %"sha1.TypeName" 类型,返回未定义类型的 opaque 声明列表"""
# 收集已定义的类型名
defined_types: set[str] = set()
type_def_re: re.Pattern = re.compile(r'^(%".+?")\s*=\s*type\s')
for line in lines:
m = type_def_re.match(line.strip())
if m:
defined_types.add(m.group(1))
# 扫描所有引用的类型名
referenced_types: set[str] = set()
type_ref_re: re.Pattern = re.compile(r'%"[a-f0-9]+\.[^"]+"')
for line in lines:
for m in type_ref_re.finditer(line):
ref: str = m.group(0)
if ref not in defined_types:
referenced_types.add(ref)
# 生成 opaque 声明(排序确保确定性)
result: list[str] = []
for type_name in sorted(referenced_types):
result.append(f'{type_name} = type opaque')
return result
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
if is_renum:
# REnum 布局: { i32 __tag, <max_variant_payload> }
# 对齐 _EmitREnumLlvm (HandlesClassDef.py) 的 Phase 2 逻辑
# Bug 修复:按每个位置的 max 字段尺寸构建布局,而非选总尺寸最大的变体。
# 不同变体在同一位置可能有不同尺寸的字段(如 Concrete 位置3是 i32
# 但 Var 位置3是 MetaType*),用最大变体的布局会导致指针截断。
variant_fields_list: list[list[str]] = []
for item in node.body:
if isinstance(item, ast.ClassDef):
variant_fields: list[str] = []
for nested_item in item.body:
if isinstance(nested_item, ast.AnnAssign) and isinstance(nested_item.target, ast.Name):
ft: str = self._get_type_str(nested_item.annotation, embedded=True)
if ft:
variant_fields.append(ft)
variant_fields_list.append(variant_fields)
elif isinstance(item, ast.Assign):
# 显式值变体(无 payload
variant_fields_list.append([])
# 计算每个位置的最大尺寸
max_field_count: int = 0
for vf in variant_fields_list:
if len(vf) > max_field_count:
max_field_count = len(vf)
renum_member_types: list[str] = ['i32'] # __tag
for pos in range(max_field_count):
pos_max_size: int = 0
for vf in variant_fields_list:
if pos < len(vf):
sz: int = self._llvm_type_size_str(vf[pos])
if sz > pos_max_size:
pos_max_size = sz
# <=4 用 i32>4 用 i648字节可容纳指针
if pos_max_size <= 4:
renum_member_types.append('i32')
else:
renum_member_types.append('i64')
if len(renum_member_types) < 2:
# 无类变体或所有变体无字段时,使用 i32 作为占位(对齐 _EmitREnumLlvm 默认行为)
renum_member_types = ['i32', 'i32']
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(renum_member_types)} }}'
decls.append(struct_decl)
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
is_novtable: bool = False
if hasattr(node, 'decorator_list') and node.decorator_list:
for decorator in node.decorator_list:
if isinstance(decorator, ast.Attribute):
if getattr(decorator.value, 'id', None) == 't':
if decorator.attr == 'CVTable':
is_cvtable = True
elif decorator.attr == 'Object':
is_cpython_object = True
elif decorator.attr == 'NoVTable':
is_novtable = True
elif isinstance(decorator, ast.Name):
if decorator.id == 'CVTable':
is_cvtable = True
elif decorator.id == 'Object':
is_cpython_object = True
elif decorator.id == 'NoVTable':
is_novtable = True
if has_methods and not is_cpython_object:
is_cpython_object = True
has_parent_class: bool = False
parent_is_novtable: 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
# 检查父类是否为 @t.NoVTable非多态继承
_p_node: ast.ClassDef | None = None
for n in ast.iter_child_nodes(self._pyi_tree):
if isinstance(n, ast.ClassDef) and n.name == base_name:
_p_node = n
break
if _p_node is None:
_p_node = self._cross_module_class_defs.get(base_name)
if _p_node is not None and hasattr(_p_node, 'decorator_list') and _p_node.decorator_list:
for dec in _p_node.decorator_list:
if isinstance(dec, ast.Attribute) and getattr(dec.value, 'id', None) == 't' and dec.attr == 'NoVTable':
parent_is_novtable = True
elif isinstance(dec, ast.Name) and dec.id == 'NoVTable':
parent_is_novtable = True
break
# 仅当非 NoVTable 且父类非 NoVTable 时才因继承启用 CVTable
# @t.NoVTable 标记的类及其子类不使用 vtable字段展平嵌入
if has_parent_class and not is_cvtable and not is_novtable and not parent_is_novtable:
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):
# 先在当前 .pyi 中查找父类,找不到则查跨模块类定义映射
_base_node: ast.ClassDef | None = None
for n in ast.iter_child_nodes(self._pyi_tree):
if isinstance(n, ast.ClassDef) and n.name == base_name:
_base_node = n
break
if _base_node is None:
_base_node = self._cross_module_class_defs.get(base_name)
if _base_node is not None and hasattr(_base_node, 'decorator_list') and _base_node.decorator_list:
for dec in _base_node.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
if base_has_vtable:
break
# NoVTable 类不添加 vtable 指针(即使有方法和父类)
if has_methods and is_cvtable and not base_has_vtable and not is_novtable:
member_types.append('i8*')
seen_member_names: set[str] = set()
for base in node.bases:
base_name: str | None = None
type_args: list[str] = []
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
slice_node: ast.AST = base.slice
if isinstance(slice_node, ast.Name):
type_args.append(slice_node.id)
elif isinstance(slice_node, ast.Tuple):
for elt in slice_node.elts:
if isinstance(elt, ast.Name):
type_args.append(elt.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)
if type_args:
base_member_types = self._specialize_member_types(base_member_types, type_args)
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})')
# 为继承但未覆写的方法生成包装声明
# 这些声明让跨模块调用能正确解析子类包装函数的签名,
# 避免 stub 缺失导致默认 i32 返回类型 → 64 位指针截断
decls.extend(self._generate_inherited_method_decls(node, class_name, struct_type_name))
return decls
def _generate_inherited_method_decls(self, node: ast.ClassDef, child_class_name: str, child_struct_type: str) -> list[str]:
"""为继承但未覆写的方法生成包装声明
在 Phase 1 stub 中声明子类继承方法的签名(与父类相同,但 self 参数为子类类型)。
这样测试模块翻译时能从 temp stub 中获取正确的返回类型,
避免 Phase 2 includes 翻译滞后导致跨模块调用使用默认 i32 返回类型。
"""
decls: list[str] = []
# 收集子类自身定义的方法名(这些不需要生成包装,子类有自己的实现)
seen_method_names: set[str] = set()
for item in node.body:
if isinstance(item, ast.FunctionDef):
seen_method_names.add(item.name)
# 沿继承链收集父类方法,近祖先优先
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 not base_name or self._is_marker_base(base_name):
continue
self._CollectInheritedWrapperDecls(
base_name, child_class_name, child_struct_type,
seen_method_names, decls)
return decls
def _CollectInheritedWrapperDecls(
self, parent_name: str, child_class_name: str, child_struct_type: str,
seen_method_names: set[str], decls: list[str]) -> None:
"""递归收集父类及其祖先的方法,为未覆写的方法生成包装声明"""
# 查找父类节点:先在当前 .pyi 中查找,找不到则查跨模块类定义映射
parent_node: ast.ClassDef | None = None
for n in ast.iter_child_nodes(self._pyi_tree):
if isinstance(n, ast.ClassDef) and n.name == parent_name:
parent_node = n
break
if parent_node is None:
parent_node = self._cross_module_class_defs.get(parent_name)
if parent_node is None:
return
# 为父类的每个方法生成包装声明
for item in parent_node.body:
if isinstance(item, ast.FunctionDef):
if hasattr(item, 'type_params') and item.type_params:
continue
method_name: str = item.name
# __before_init__ 只在自身类生成,不生成继承包装
if method_name == '__before_init__':
continue
# 跳过子类已覆写的方法,以及已处理的祖先方法
if method_name in seen_method_names:
continue
seen_method_names.add(method_name)
# 构建包装方法名:{module_sha1}.{child_class}.{method_name}
wrapper_name: str = f'{child_class_name}.{method_name}'
if self.module_sha1:
wrapper_name = f"{self.module_sha1}.{wrapper_name}"
# 解析返回类型(与父类方法相同)
ret_type: str = self._get_type_str(item.returns) if item.returns else 'void'
if not ret_type:
ret_type = 'void'
elif ret_type == 'i8*':
if item.returns is None:
ret_type = 'void'
# 构建参数列表第一个参数self替换为子类类型其余与父类相同
params: list[str] = []
for arg_idx, arg in enumerate(item.args.args):
arg_type: str
if arg_idx == 0 and arg.arg == 'self':
arg_type = f'{child_struct_type}*'
else:
if arg.annotation:
arg_type = self._get_type_str(arg.annotation)
else:
arg_type = 'i8*'
arg_type = self._decay_array_to_ptr(arg_type)
params.append(arg_type)
param_str: str = ', '.join(params) if params else ''
if wrapper_name[0].isdigit():
decls.append(f'declare {ret_type} @"{wrapper_name}"({param_str})')
else:
decls.append(f'declare {ret_type} @{wrapper_name}({param_str})')
# 递归处理祖先类
for base in parent_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):
self._CollectInheritedWrapperDecls(
base_name, child_class_name, child_struct_type,
seen_method_names, 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:
# 跨模块父类查找:当前 .pyi 中没有父类定义时,从跨模块类定义映射中查找
# (如 exprs.py 的 Name(AST)AST 定义在 base.py
base_node = self._cross_module_class_defs.get(base_name)
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
def _specialize_member_types(self, member_types: list[str], type_args: list[str]) -> list[str]:
"""将基类成员类型中的泛型参数 T 替换为具体类型参数
处理泛型基类继承(如 GSListNode[BasicBlock])时,基类 _get_inherited_members
返回的成员类型中会包含未特化的 T 引用(形式为 %"SHA1.T"*)。
替换策略:使用 i8*(不透明指针)代替 T*,而非具体类型指针。
原因:跨模块场景中,具体类型指针的 SHA1 前缀可能与导入模块不一致,
导致 TransPyC 类型转换失败。i8* 作为通用指针类型,可安全赋值给
任何 Class | t.CPtr 注解的变量,运行时行为与 T* 相同(都是指针)。
Args:
member_types: 基类成员类型字符串列表
type_args: 类型参数名列表(如 ['BasicBlock']
Returns:
特化后的成员类型字符串列表
"""
if not type_args:
return member_types
result: list[str] = []
for mt in member_types:
new_mt: str = mt
# 将 %"SHA1.T"* 替换为 i8*(不透明指针)
new_mt = re.sub(r'%"[a-f0-9]+\.T"\*', 'i8*', new_mt)
# 将 %"SHA1.T"(非指针,如 embedded struct替换为 i8*
new_mt = re.sub(r'%"[a-f0-9]+\.T"', 'i8*', new_mt)
result.append(new_mt)
return result
def _llvm_type_size_str(self, type_str: str) -> int:
"""估算 LLVM 类型字符串的大小(字节),用于 REnum 变体大小比较
对齐 _EmitREnumLlvm 中的大小计算逻辑:
- i1=1, i8=1, i16=2, i32=4, i64=8, float=4, double=8, ptr=8
- [N x T] = N * size(T)
- 其他结构体类型按指针大小 8 估算(保守值)
"""
s: str = type_str.strip()
if not s:
return 0
# 指针类型
if s.endswith('*'):
return 8
# 数组类型 [N x T]
m = self._ARR_TYPE_RE.match(s) if hasattr(self, '_ARR_TYPE_RE') else None
if m:
try:
n: int = int(m.group(1))
return n * self._llvm_type_size_str(m.group(2))
except ValueError:
return 8
# 基本整数/浮点类型
size_map: dict[str, int] = {
'i1': 1, 'i8': 1, 'i16': 2, 'i32': 4, 'i64': 8,
'float': 4, 'double': 8, 'half': 2, 'fp128': 16,
'void': 0,
}
if s in size_map:
return size_map[s]
# %{...} 结构体类型 - 保守估算为指针大小
if s.startswith('%') or s.startswith('{'):
return 8
# 其他未知类型保守估算
return 8
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
# t.CPtr (i8*) 与 left 合并:对齐 Phase 2 _MergeAllComponentTypes 的
# "first CPtr absorption" 语义struct | t.CPtr → struct*吸收struct 变量默认是指针)。
# 但对于本身已是指针的类型(如 bytes=str=i8*bytes | t.CPtr → i8**(不吸收)。
# 例外:泛型特化类型(含 '[')回退为 i8*,避免引用未定义的特化结构体。
if right_type == 'i8*':
if '[' in left_type:
return 'i8*'
if left_type in ('', 'void'):
return 'i8*'
if left_type.startswith('%"') and left_type.endswith('*'):
return left_type
if '*' in left_type:
return f'{left_type}*'
return f'{left_type}*'
if '*' in left_type:
return left_type
if '*' in right_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]'
# 处理 t.CPtr[Type] 语法(指向 Type 的指针)
# 例如: t.CPtr[t.CPtr] -> i8** (void**), t.CPtr[t.CInt] -> i32* (int*)
# t.CPtr[t.CPtr[t.CInt]] -> i32** (int**)
ValueIsCPtr: bool = (
(isinstance(annotation.value, ast.Attribute) and annotation.value.attr == 'CPtr')
or (isinstance(annotation.value, ast.Name) and annotation.value.id == 'CPtr')
)
if ValueIsCPtr and isinstance(annotation.slice, (ast.Attribute, ast.Name, ast.Subscript)):
slice_type: str = self._get_type_str(annotation.slice, embedded=True)
if slice_type and slice_type != 'void':
return f'{slice_type}*'
return 'i8*'
if isinstance(annotation.slice, ast.Constant) and isinstance(annotation.slice.value, int):
return f'[{annotation.slice.value} x {base}]'
# 处理 t.CArray[elem_type, count] 注解 → [count x elem_type]
# 支持 t.CArray (ast.Attribute) 和 CArray (ast.Name) 两种写法
ValueIsCArray: bool = (
(isinstance(annotation.value, ast.Attribute) and annotation.value.attr == 'CArray')
or (isinstance(annotation.value, ast.Name) and annotation.value.id == 'CArray')
)
if ValueIsCArray:
SliceNode: ast.AST = annotation.slice
if isinstance(SliceNode, ast.Tuple) and len(SliceNode.elts) == 2:
ElemType: str = self._get_type_str(SliceNode.elts[0], embedded=True)
CountVal: int = self._get_const_int(SliceNode.elts[1])
if CountVal > 0:
return f'[{CountVal} x {ElemType}]'
# count 为 None 或 0 → 零长度数组(外部符号)
return f'[0 x {ElemType}]'
elif isinstance(SliceNode, (ast.Attribute, ast.Name, ast.Subscript)):
# 单参数 t.CArray[elem_type] → 指针模式
ElemType: str = self._get_type_str(SliceNode, embedded=True)
return f'{ElemType}*'
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 _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