Files
TransPyC/lib/Projectrans/DeclarationGenerator.py
T
TermiNexus f19d25782f refactor(tpc): 退役 t/c 模块并将定宽类型升级为内建
删除 lib/includes/t.py、c.py,类型模型迁入 lib/core/TypeSystem.py;移除 IsTModule/_T_MODULE_NAMES 等名称判据,语法糖与内部标记统一为裸名;builtins 的 sizet/intN/uintN/fast/least/uchar/short/long 等改为编译器内建短名。
2026-10-18 13:00:58 +08:00

1586 lines
88 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 vast as ast
import copy
import re
from typing import List
import llvmlite.ir as ir
from lib.core import TypeSystem
from lib.core.TypeSystem import CTypeRegistry
from lib.core.SymbolUtils import (
IsListAnnotation, AnnotationContainsName, IsCPtrSubscriptNode, IsCPtrNode,
IsRawPtrSubscriptNode, IsPtrSubscriptNode, ResolveGenericTypeArgStr,
EnumClassIntWidth, ClassHasFuncLevelCVTable)
# 泛型特化(`_SubstituteTypeArgs`)把 `%"SHA1.T"` / `%"SHA1.T"*` 替换为 i8* 用的
# **预编译**正则(性能:字面量正则预编译避免 re 缓存查找与编译开销)。
_RE_T_TYPE_PTR: re.Pattern[str] = re.compile(r'%"[a-f0-9]+\.T"\*')
_RE_T_TYPE: re.Pattern[str] = re.compile(r'%"[a-f0-9]+\.T"')
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] = {}
# 泛型模板类名(PEP 695 `class Box[T]`):声明端特化判定用,与定义端
# HandlesClassDef._generic_class_templates 同源(ClassDef 的 type_params
# 标记),generate() 里从本模块 pyi 与 class_def_map 收集
self._generic_class_names: set[str] = set()
# 内建类型导入名表(CInt as myint → 'myint' → CInt),
# 与定义端 Trans._from_import_aliases 同口径,供泛型实参串解析使用
self._from_import_aliases: dict[str, tuple[str, str]] = {}
# 跨模块类定义映射:{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 {}
TypeSystem.configure_platform(self.target_triple)
def generate(self, pyi_content: str, src_path: str) -> str:
# 传 src_path:解析失败时报错/回退诊断才带得上来源(否则 vast 记为 <unknown>,
# 既无法定位文件,也无法知道是哪份 .pyi 出问题)
tree: ast.Module = ast.parse(pyi_content, src_path)
self._DefineConstants: dict[str, int | str] = {}
self._pyi_tree = tree
# 泛型模板类名(PEP 695 `class Box[T]`):class_def_map 覆盖所有已生成
# .vpi 的模块(含本模块),本模块 pyi 直接解析的 ClassDef 优先,
# 与定义端 HandlesClassDef 注册 _generic_class_templates 的判据一致
# (都只看 ClassDef.type_params 是否非空,不看类名白名单)。
self._generic_class_names = {
node.name for node in ast.iter_child_nodes(tree)
if isinstance(node, ast.ClassDef) and getattr(node, 'type_params', None)}
for _gc_name, _gc_node in self._cross_module_class_defs.items():
if getattr(_gc_node, 'type_params', None):
self._generic_class_names.add(_gc_name)
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)
# 类型标记按裸名直接识别、不依赖导入:别名映射表保持为空。
self._t_alias_map: dict[str, type] = {}
self._from_import_aliases: dict[str, tuple[str, str]] = {}
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
elif isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Name) and node.annotation.left.id == '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):
# PEP 695 泛型类不再完全跳过:子类(如 Value(GSListNode[Value]))的
# 继承字段展平需要从泛型基类的 stub 中读取字段(如 GSListNode.Next)。
# _generate_class_decl 内部会跳过泛型类的方法声明(T 参数 → opaque struct)。
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}"
MultiRetTypes: list[ast.AST] = []
if node.decorator_list:
for decorator in node.decorator_list:
# fail-fast:`CReturn` 不是内建标记;多返回值请改用 `-> tuple[ty1, ty2, ...]`。
_DecName: str = ''
if isinstance(decorator, ast.Call):
if isinstance(decorator.func, ast.Name):
_DecName = decorator.func.id
elif isinstance(decorator.func, ast.Attribute):
_DecName = decorator.func.attr
if _DecName == 'CReturn':
raise SyntaxError(
f"函数 '{node.name}':`CReturn` 不是内建标记;请改用返回注解 "
f"`-> tuple[ty1, ty2, ...]`(多返回值打包为 struct)"
)
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:
MultiRetTypes.append(elt)
else:
MultiRetTypes.append(slice_node)
ret_type: str
if MultiRetTypes:
elem_types: list[str] = [self._get_type_str(rt, embedded=True) for rt in MultiRetTypes]
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 或 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
# CDefine 是编译期常量,不是变量:stub 里**不得**生成 external global。
# `define X: T = V` 会展开为注解 `T | CDefine`,故判据必须能识别**联合形态**——
# 原判据只认裸 `CDefine`(注解为单个 Attribute),联合注解会漏判 →
# stub 出现 `@X = external global i32` → 其他模块引用它时变成未定义符号(链接失败),
# 且会遮住跨模块 CDefine 常量回退(同名全局优先于常量)。与 _check_annotation_for_export
# 一样用递归判据。
if AnnotationContainsName(node.annotation, '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.BinOp) and isinstance(node.annotation.left, ast.Name) and node.annotation.left.id == '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.Name) and elt.value.id == 'Callable':
return None
VarType: str = self._get_type_str(node.annotation)
if VarType.startswith('[0 x ') and node.value:
elem_type: str = VarType[5:-1]
actual_count: int = 0
if isinstance(node.value, ast.List):
actual_count = len(node.value.elts)
elif isinstance(node.value, ast.Constant) and isinstance(node.value.value, str):
# 字符串字面量:与 HandlesBase.ParseArrayCount(:731-732) / HandlesAssign
# 全局路径同口径(len(str)+1,含结尾 NUL)。此前只修 List 值 → CArray
# 字符串全局的 stub 声明停留在 [0 x i8],与定义端 [N x i8] 长度不一致
# (跨模块 type mismatch / llc 拒绝)。
actual_count = len(node.value.value) + 1
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' | 'ctype_marker' | None
"""
# 1) 查内建类型别名映射
if base_name in self._t_alias_map:
t_cls: type = self._t_alias_map[base_name]
if issubclass(t_cls, (TypeSystem.CEnum, TypeSystem.REnum)):
return 'renum' if issubclass(t_cls, TypeSystem.REnum) else 'enum'
if issubclass(t_cls, TypeSystem.CUnion):
return 'union'
if issubclass(t_cls, TypeSystem.CStruct):
return 'struct'
# CType 及其子类(CChar/CInt/CVoid/CPtr 等)是"类型强转"标记,
# 不应被编译为真实结构体,也不应被生成 stub 声明。
if issubclass(t_cls, TypeSystem.CType):
return 'ctype_marker'
# 2) 直接查内建类型类
t_cls: type | None = getattr(TypeSystem, base_name, None)
if isinstance(t_cls, type) and issubclass(t_cls, TypeSystem.CType):
if issubclass(t_cls, (TypeSystem.CEnum, TypeSystem.REnum)):
return 'renum' if issubclass(t_cls, TypeSystem.REnum) else 'enum'
if issubclass(t_cls, TypeSystem.CUnion):
return 'union'
if issubclass(t_cls, TypeSystem.CStruct):
return 'struct'
# CType 及其子类是"类型强转"标记,不编译为结构体。
return 'ctype_marker'
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
elif kind == 'ctype_marker':
# CType 及其子类(CChar/CInt/CVoid/CPtr/CTypeDefault 等)是
# "类型强转"标记,不应被编译为真实结构体,也不生成 stub 声明。
return decls
if is_exception:
return decls
if is_enum:
enum_values: dict[str, int] = {}
next_value: int = 0
# 枚举存储宽度 = 最宽成员类型(与定义端 HandlesClassDef / 跨模块读取端
# 同一规则源 EnumClassIntWidth;此处无 SymbolTable,走 t 类名 / builtins /
# 库 typedef 的表)。声明端的全局类型必须与定义端运行时常量同宽(ABI)。
enum_width: int = EnumClassIntWidth(node.body)
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 i{enum_width}')
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 用 i64(8字节,可容纳指针)
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.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
# 检查父类是否为 @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.Name) and dec.id == 'NoVTable':
parent_is_novtable = True
break
# 仅当非 NoVTable 且父类非 NoVTable 时才因继承启用 CVTable
# (@NoVTable 标记的类及其子类不使用 vtable,字段展平嵌入)
if has_parent_class and not is_cvtable and not is_novtable and not parent_is_novtable:
is_cvtable = True
# 方法级 virtual(`virtual def m(...)` ⇒ 方法装饰器 @CVTable)触发类级 vtable:
# 与 HandlesClassDef._resolve_class_flags / VPC _detect_vtable_status 的
# `_has_any_func_cvtable` 分支逐条对齐(类级 NoVTable / 无真实父类)。
# 必须在此同步:定义模块按 IsCVTable 在 struct 首部放 vptr,若 stub 不同步,
# 跨模块使用该类的 struct 布局会比定义模块少一个字段 ⇒ 字段整体错位。
if not is_cvtable and ClassHasFuncLevelCVTable(node):
if is_novtable or not has_parent_class:
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.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*')
# 多继承字段展平:按继承源去重(2026-08-18)——菱形继承不再重复展平
# 祖先字段(Generator 同时继承 ClassGenMixin/ClassGenEnum/.../ClassGenBase,
# 而它们都继承 ClassGenBase → ClassGenBase 字段被展平 6 次,struct 膨胀
# 且 this_adjust/字段 GEP 错位)。每类只展平一次,只取自有字段。
# 与 HandlesClassDef._FlattenInherited 保持同一算法。
_seen_cls: 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):
self._FlattenInheritedDecl(base_name, _seen_cls, member_types,
type_args or None)
# 自身字段收集(复用 _CollectOwnMemberTypes,与 _FlattenInheritedDecl 一致)
_own_types: list[str]
_own_types, has_bitfield, total_bits = self._CollectOwnMemberTypes(node)
member_types.extend(_own_types)
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)
# 嵌套类 / 嵌套 struct:定义端以扁平名 `{外类}_{内类}` 发射(见 HandlesClassDef.
# _EmitNestedClassDefs),此处同步产出同名完整类型声明 —— 否则跨模块引用
# `外类.内类` 只会得到一个 opaque 前向声明(指针可用、字段偏移全失效)。
# deepcopy 后改名再递归:本函数所有名字都派生自 node.name,改名即全链路一致;
# 判断/枚举/联合等分支在递归时会各自按内层类自身的基类重新分派。
for _nested_item in getattr(node, 'body', None) or []:
if not isinstance(_nested_item, ast.ClassDef):
continue
_nested_inner: str | None = getattr(_nested_item, 'name', None)
if not _nested_inner:
continue
_nested_node: ast.ClassDef = copy.deepcopy(_nested_item)
_nested_node.name = f'{class_name}_{_nested_inner}'
decls.extend(self._generate_class_decl(_nested_node))
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)
# PEP 695 泛型类跳过方法声明生成:方法参数类型 T 会被解析为 opaque struct,
# LLVM 报 "invalid type for function argument"。字段(AnnAssign)仍正常生成,
# 确保子类(如 Value(GSListNode[Value]))能从 stub 中读取继承字段(如 Next)。
IsGenericClass: bool = hasattr(node, 'type_params') and bool(node.type_params)
if not IsGenericClass:
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 _CollectOwnMemberTypes(self, node: ast.ClassDef) -> tuple[list[str], bool, int]:
"""收集类自身声明的字段类型(不含继承字段)。
与 _generate_class_decl 的字段收集逻辑一致(AnnAssign + __init__/方法内
self.attr 赋值)。返回 (types, has_bitfield, total_bits)。
供 _FlattenInheritedDecl 按"每类只展平一次 + 只取自有字段"使用,
消除菱形继承的重复展平(如 ClassGenBase 41 字段被 ClassGenMixin/
ClassGenEnum/.../ClassGenBase 6 个来源重复展平)。
"""
member_types: list[str] = []
has_bitfield: bool = False
total_bits: int = 0
seen_member_names: set[str] = set()
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:
# 固定大小数组: CArray[elem_type, count] → [count x elem_type]
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_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)):
# 单参数 CArray[elem_type] → 指针模式
elem_type = 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
# 不再兜底 i32:只认**能唯一确定**的取值形态,推不出即响亮失败。
# 规则表必须与定义端 HandlesClassDef._scan_node_for_self_assign 的
# Assign 分支**逐条一致**(stub 与定义端 struct 布局必须同源,
# 少/多一个槽 ⇒ 跨模块字段偏移整体错位):
# 整型/布尔字面量 → 'i32'(定义端 bool 走 int 分支);
# 浮点字面量 → 'double'(定义端 DoubleType;此前这里写 'float'
# = f32,与定义端 8 字节不一致);字符串字面量 → 'i8*'。
# 注:`self.X = <带注解形参>` / 白名单调用(float()/double()/char()/
# int()…/len())在定义端可定型,本函数**拿不到**符号表故不在此推
# (这些形态一旦出现会被定义端接受,而 stub 这里判不了);
# 另外方法体内的裸 `self.X = ...` 已被上方 seen_member_names 过滤
# (只对**本类自有声明**判重,不含继承字段)——若贸然放行,
# 继承字段(如 G4Node.Next)会被当成自有字段重复加一个槽,
# 反而制造布局分叉。要放行必须先在此补"祖先字段名"判定。
InferredType: str | None = None
if item.value is not None and isinstance(item.value, ast.Constant):
_v: object = item.value.value
if isinstance(_v, bool):
InferredType = 'i32'
elif isinstance(_v, int):
InferredType = 'i32'
elif isinstance(_v, float):
InferredType = 'double'
elif isinstance(_v, str):
InferredType = 'i8*'
if InferredType is None:
_vt: str = ''
try:
_vt = ast.unparse(item.value) if item.value is not None else '<无值>'
except Exception:
_vt = '<无法反解析>'
raise ValueError(
f"[FATAL] 类 '{node.name}' 的字段 '{attr_name}' 在 stub 声明里"
f"推不出类型(`self.{attr_name} = {_vt}`,行 "
f"{getattr(item, 'lineno', 0)})——拒绝静默写成 i32。"
f"请在类体声明该字段并给注解。")
member_types.append(InferredType)
else:
member_types.append('i32')
return member_types, has_bitfield, total_bits
def _ShouldEmitOwnVtablePtr(self, node: ast.ClassDef) -> bool:
"""类自身是否需要 vtable 指针(复刻 _generate_class_decl 的判定)。
仅"有方法 + CVTable 且父类无 vtable + 非 NoVTable"的类在 struct 最前
放 vtable 指针。继承 vtable 父类的子类不重复添加。_FlattenInheritedDecl
递归时用此判定补齐各祖先类的 vtable 指针(原 _get_inherited_members
走 _generate_class_decl 完整 struct 天然包含;改按自有字段后必须补上)。
"""
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.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
base_has_vtable: bool = False
has_real_parent: 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_real_parent = True
_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.Name) and dec.id == 'CVTable':
base_has_vtable = True
if base_has_vtable:
break
# 方法级 virtual 触发类级 vtable(与上方 _generate_class_decl 同一判据,
# 保持在同一个类里两处口径一致;详见该处注释)
if not is_cvtable and not base_has_vtable and ClassHasFuncLevelCVTable(node):
if is_novtable or not has_real_parent:
is_cvtable = True
return has_methods and is_cvtable and not base_has_vtable and not is_novtable
def _FlattenInheritedDecl(self, cls_name: str, seen_cls: set, member_types: list[str],
type_args: list[str] | None = None) -> None:
"""按继承源去重递归展平:继承树每个类只处理一次,每类只贡献自有字段。
菱形继承(Generator 同时继承 ClassGenMixin/ClassGenEnum/.../ClassGenBase,
而它们都继承 ClassGenBase)会让 ClassGenBase 字段被重复展平,导致 stub
struct 与运行时 class_members 布局错位(this_adjust 失效崩溃)。本方法与
HandlesClassDef 的 _FlattenInherited 保持同一算法。
"""
if cls_name in seen_cls:
return
seen_cls.add(cls_name)
cls_node: ast.ClassDef | None = None
for n in ast.iter_child_nodes(self._pyi_tree):
if isinstance(n, ast.ClassDef) and n.name == cls_name:
cls_node = n
break
if cls_node is None:
cls_node = self._cross_module_class_defs.get(cls_name)
if cls_node is None:
# 跨模块未知类:回退到完整展平(_get_inherited_members 递归)
mts, _ = self._get_inherited_members(cls_name)
if type_args:
mts = self._specialize_member_types(mts, type_args)
member_types.extend(mts)
return
for base in cls_node.bases:
base_name: str | None = None
base_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):
base_type_args.append(slice_node.id)
elif isinstance(slice_node, ast.Tuple):
for elt in slice_node.elts:
if isinstance(elt, ast.Name):
base_type_args.append(elt.id)
if base_name and not self._is_marker_base(base_name):
self._FlattenInheritedDecl(base_name, seen_cls, member_types,
base_type_args or None)
own, _hbf, _tbits = self._CollectOwnMemberTypes(cls_node)
if type_args:
own = self._specialize_member_types(own, type_args)
# 该类的 vtable 指针(若有)放在自有字段最前(与 _generate_class_decl
# L485 一致;递归时各祖先类的 vtable 也按此补齐)
if self._ShouldEmitOwnVtablePtr(cls_node):
member_types.append('i8*')
member_types.extend(own)
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 | 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_T_TYPE_PTR.sub('i8*', new_mt)
# 将 %"SHA1.T"(非指针,如 embedded struct)替换为 i8*
new_mt = _RE_T_TYPE.sub('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]
# 注:此处原写作 `self._ARR_TYPE_RE`(少一个 A)并用 `hasattr` 守卫 —— 该属性
# **全仓从未定义** ⇒ 守卫恒假 ⇒ 本分支恒不执行:数组字段一律落到下方"未知类型 → 8"
# 的保守值,与 docstring 声明的"_EmitREnumLlvm 尺寸口径对齐"不符(静默降级)。
# 现改用本类已定义的 `_ARRAY_TYPE_RE`(见文件顶部),并去掉守卫:
# 属性若再丢失应当响亮失败,而不是静默退回 8。
m = self._ARRAY_TYPE_RE.match(s)
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
@staticmethod
def _ptr_level_of(type_str: str) -> int:
"""统计类型字符串尾部的指针层数('i8***' → 3,'i32' → 0)"""
return len(type_str) - len(type_str.rstrip('*'))
def _merge_cptr_subscript(self, base_type: str, cptr_sub_type: str) -> str:
"""base | CPtr[T] → Ptr^N(base_type),N = CPtr[T] 段自身指针层数。
与定义侧 VPC TypeGenResolve.vp:2610-2639 同口径:数 CPtr 侧已解析类型的
外层 Ptr 嵌套层 N(TypeGenResolve.vp:2616-2632),再给另一侧**纯外包**
N 层 Ptr(TypeGenResolve.vp:2633-2639,对 struct 基类型亦不吸收)。
与 LLVMTypeMapper._resolve_bitor 的 IsCPtrSubscriptNode 分支(_add_pointer_levels
逐层追加)同口径,对同一批形态两处结果一致。
注:裸 | CPtr(非下标标记)仍走上方的 %"..."* 吸收分支,与本节无关。
"""
return base_type + '*' * self._ptr_level_of(cptr_sub_type)
def _ptr_subscript_type_str(self, annotation: ast.Subscript) -> str:
"""指针下标(rawptr[T] / CPtr[T] / 裸名 CPtr[T],判据见
SymbolUtils.IsPtrSubscriptNode)→ LLVM 类型串。
与定义端同源:SymbolUtils.DesugarPtrSubscriptToUnion 把三者折叠为等价
联合写法 `T | CPtr` 后交 HandlesTypeMerge.MergeTypes,指针层数由
_MergeAllComponentTypes 的"struct 基类型吸收一层 CPtr"决定 —— 裸类引用
的非 embedded 形式本身即指针('%"sha1.X"*'),再包一层会被吸收 → 结果
就是该指针本身;其余类型(标量 / 已是指针的 typedef / 泛型容器特化 /
联合写法 / 嵌套指针下标)逐层外包。rawptr[...] 与 CPtr[...] 共用本条
规则(此前 CPtr[list[X]] 在此得 list[X]**、rawptr[list[X]] 得
list[X]*,同一指针语义两种结果)。
"""
inner: ast.AST = annotation.slice
inner_type: str = self._get_type_str(inner)
if self._is_bare_class_ref_annotation(inner, inner_type):
return inner_type
if inner_type in ('', 'void', 'void*'):
return 'i8*'
return f'{inner_type}*'
def _is_bare_class_ref_annotation(self, inner: ast.AST, inner_type: str) -> bool:
"""节点是否为"裸类引用"(本身即指针 → 吸收一层 CPtr)。
与 _get_type_str 的既有约定一致:类引用的**非** embedded 形式本身就是
指针('%"sha1.X"*'),所以 `AST | CPtr` 合并后仍是该指针(定义端
_MergeAllComponentTypes 的 struct 吸收)。联合写法(ast.BinOp)与指针
下标(rawptr[...] / CPtr[...])不是裸类引用——它们已自带指针层数,
须逐层外包(rawptr[Node] | CPtr → Node**、ast.AST | CPtr | CPtr
→ AST**,与定义端整体拉平后只吸收一次 CPtr 一致)。
**例外:纯装饰器标记联合**。`CExtern | X` / `CExport | X` / `State | X`
(vpi 记录的模块级全局就是这种写法,见 lib.Phase.Phase1.__init__.vpi 的
`_mbuddy: CExtern | memhub.MemBuddy | CPtr`)里标记侧展开为**空串**
(CTypeRegistry.NameToLLVM('CExtern') == ''),该联合语义上仍是 X 这一个
裸类引用,故 `CExtern | X | CPtr` 必须与 `X | CPtr` 同判(吸收)——
对齐 VPC TypeGenResolve 的第 3 条语义「ActualType | DecoratorMarker →
ActualType」。漏此判据时联合被当成"已自带指针层数的左值"而多外包一层:
声明端 `%"sha1.X"**` 与定义端 `%"sha1.X"*` 差一层,消费模块里
`self.__mbuddy__ = _mbuddy` 之类的赋值即报"层数不同"fail-fast。
"""
if not inner_type:
return False
if isinstance(inner, ast.BinOp):
if not isinstance(inner.op, ast.BitOr):
return False
LeftType: str = self._get_type_str(inner.left)
RightType: str = self._get_type_str(inner.right)
# 恰一侧是纯装饰器标记(展开为空/void)⇒ 类型全部来自另一侧,按另一侧判
if LeftType in ('', 'void') and RightType not in ('', 'void'):
return self._is_bare_class_ref_annotation(inner.right, RightType)
if RightType in ('', 'void') and LeftType not in ('', 'void'):
return self._is_bare_class_ref_annotation(inner.left, LeftType)
return False
if isinstance(inner, ast.Subscript):
return not (IsRawPtrSubscriptNode(inner) or IsCPtrSubscriptNode(inner))
return inner_type.startswith('%') and inner_type.endswith('*')
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', 'rawarray'}
if isinstance(annotation, ast.Name):
if annotation.id == 'None':
return 'void'
if annotation.id in ('str', 'bytes'):
return 'i8*'
# 值引用参数标记(CRef = `&T`、CTempRef = `&temp T`,非真实类):按
# CPtr 同形的一层指针(i8*)参与联合合并(`T | CRef` → T*)。
if annotation.id in ('CRef', 'CTempRef'):
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
# 检查内建类型别名
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
# builtins 隐式 CTypedef(int64/uint64/size_t 等:builtins.vp 声明、
# 用户文件无需 import 即用):常规路径 miss 后若落下方 fallback 会按
# "本模块结构体"建 %"{mod}.int64" opaque(ClassGenGeneric._clone_annotation
# 的 "i64 != %int64*" 根因)。按 builtins.vp 权威定义展开。
from lib.core.TypeAnnotationResolver import TypeAnnotationResolver as _DG_TAR
_dg_bv: str | None = _DG_TAR.builtins_typedef_value(annotation.id)
if _dg_bv:
_dg_node: ast.AST | None = None
try:
_dg_node = ast.parse(_dg_bv, '<DeclarationGenerator:type_expr>', mode='eval').body
except Exception:
_dg_node = None
if _dg_node is not None:
_dg_ret: str = self._get_type_str(_dg_node, embedded=embedded)
if _dg_ret and _dg_ret != 'i32':
return _dg_ret
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 ''
# 值引用参数标记(CRef = `&T`、CTempRef = `&temp T`,非真实类):按 CPtr
# 同形的「一层指针 = i8*」参与联合合并(`T | CRef` → T*),保证跨模块
# .vpi 声明端类型与定义端 _ctype_to_llvm 一致。
if attr_name in ('CRef', 'CTempRef'):
return 'i8*'
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
# 嵌套类 / 嵌套 struct:限定名 `外类.内类`(module_name 是**类名**而非模块名)。
# 定义端以扁平名 `{外类}_{内类}` 发射(见 HandlesClassDef._EmitNestedClassDefs),
# 故此处按扁平名拼类型;命中与否由 struct_names 里是否存在该扁平名裁决
# (不存在即维持下方既有路径,不改变任何既有类型名)。
if module_name:
NestedName: str = f'{module_name}_{attr_name}'
if NestedName in self.struct_names:
NestedSha1: str | None = self.struct_sha1_map.get(NestedName, self.module_sha1)
NestedStr: str = f'%"{NestedSha1}.{NestedName}"' if NestedSha1 else f'%struct.{NestedName}'
return NestedStr if embedded else f'{NestedStr}*'
if attr_name == 'State':
return ''
if 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
# CPtr (i8*) 与 left 合并:对齐 Phase 2 _MergeAllComponentTypes 的
# "first CPtr absorption" 语义:struct | CPtr → struct*(吸收,struct 变量默认是指针)。
# 但对于本身已是指针的类型(如 bytes=str=i8*),bytes | CPtr → i8**(不吸收)。
# 例外:LLVM 聚合数组([N x T],字符串以 '[' 开头)不可再外包指针层 → i8*。
# 注:具名泛型特化(%"mod.list[X]"*)**不**走此回退——stub 已由
# _collect_undefined_type_decls 为其补 opaque 声明,保留名字才能与 define 端
# 的 %"mod.list[ast.ASTptr]"* 逐字一致(原 `'[' in left_type` 会把
# list[X] | CPtr 一并退化成 i8*,与定义端 %"mod.list[X]"* 不一致)。
if right_type == 'i8*':
if left_type[:1] == '[':
return 'i8*'
if left_type in ('', 'void'):
return 'i8*'
# 吸收仅对"裸类引用"成立(其非 embedded 形式本身即指针):
# ast.AST | CPtr → %"sha1.AST"*。已自带指针层数的左值
# (rawptr[...] / CPtr[...] 下标 / 联合写法)须逐层外包:
# rawptr[Node] | CPtr → Node**、ast.AST | CPtr | CPtr → AST**
# ——与定义端 _CollectAllOperandTypes 整体拉平、只吸收一次 CPtr
# (_MergeAllComponentTypes 的 base_ptr_count>0 分支)一致。
if self._is_bare_class_ref_annotation(annotation.left, left_type):
return left_type
if '*' in left_type:
return f'{left_type}*'
return f'{left_type}*'
# X | CPtr[T](T 为下标段,非裸标记):CPtr 侧贡献自身指针层数 N,
# 另一侧外包 N 层(Ptr^N(X));左右两侧写法对称(定义侧 VPC
# TypeGenResolve.vp:2604-2609 亦两侧皆判)。必须先于下方
# "'*' in left_type → 直接返回左值":否则左值本身已是指针
# (BYTEPTR⇒i8*)时会吞掉右段层数(BYTEPTR | CPtr[CPtr] 改前得 i8*)。
# LLVM 聚合([N x T] / { ... })不可再外包指针层,保持既有行为(只报不改)。
if IsCPtrSubscriptNode(annotation.right) and left_type[:1] not in ('[', '{'):
return self._merge_cptr_subscript(left_type, right_type)
if IsCPtrSubscriptNode(annotation.left) and right_type[:1] not in ('[', '{'):
return self._merge_cptr_subscript(right_type, left_type)
# CPtr 裸标记在左侧(CPtr | X):与右侧写法(X | CPtr,见上)
# 完全对称。缺此分支时左值 i8* 会吞掉右侧的指针层数:
# CPtr | rawptr[Node] 声明端曾得 i8*,而定义端为 %"sha1.Node"**(差一层)。
# 仅对裸标记 CPtr 生效(left 为 CPtr[T] 下标走上一条分支;
# str/bytes 等其它 i8* 左值不受影响)。
if IsCPtrNode(annotation.left) and right_type[:1] not in ('[', '{'):
if self._is_bare_class_ref_annotation(annotation.right, right_type):
return right_type
return f'{right_type}*'
if '*' in left_type:
return left_type
if '*' in right_type:
return right_type
return left_type
elif isinstance(annotation, ast.Subscript):
# 指针下标(rawptr[T] / CPtr[T] / 裸名 CPtr[T] / 导入别名 X[T],以及带
# 模块前缀书写的 X.CPtr[T])≡ 源码联合写法 `T | CPtr`:与定义端
# **同一判据**(SymbolUtils.IsPtrSubscriptNode,别名经本模块的
# _from_import_aliases 表解析 X→CPtr)+ 同一层数规则
# (_ptr_subscript_type_str:裸类引用吸收一层、其余逐层外包),内层 T
# 照常解析(跨模块类由 struct_sha1_map 补 SHA1 前缀)。此前 rawptr[T]
# 在此退化成 i8*,CPtr[T] 走的是"embedded + 追加一层"的独立分支:
# 非同一规则,且对泛型容器特化多出一层(CPtr[list[X]] 得 list[X]**,
# 而 rawptr[list[X]] 得 list[X]*)。
ValueIsCPtr: bool = (
(isinstance(annotation.value, ast.Attribute) and annotation.value.attr == 'CPtr')
or (isinstance(annotation.value, ast.Name) and annotation.value.id == 'CPtr')
)
if (IsPtrSubscriptNode(annotation, TCAliasMap=self._from_import_aliases)
or (ValueIsCPtr and isinstance(annotation.slice, (ast.Attribute, ast.Name, ast.Subscript)))):
return self._ptr_subscript_type_str(annotation)
# 内建裸名函数指针构造子 callable[...] / Callable[...]:与 Attribute 分支的
# Callable[...] 逐点等价(同为 i8*)。缺此分支时落到下方 Name 泛型特化 /
# 兜底返回 'i32'(现场 Repl.vp:307 `ReplFragFn: callable[[rawptr], int]`
# 声明成 i32 全局 ⇒ 赋 i8* 触发「指针隐式转整数」)。
if isinstance(annotation.value, ast.Name) and (annotation.value.id == 'callable' or annotation.value.id == 'Callable'):
return 'i8*'
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}]'
# 处理 CArray[elem_type, count] / rawarray[elem_type, count] / array[elem_type, count]
# 注解 → [count x elem_type]
# 支持 CArray (ast.Attribute)、CArray/rawarray/array (ast.Name) 三种写法
# (array 为本轮新增的内建软关键字,与 CArray 逐点等价)
ValueIsCArray: bool = (
(isinstance(annotation.value, ast.Attribute) and annotation.value.attr == 'CArray')
or (isinstance(annotation.value, ast.Name) and annotation.value.id in ('CArray', 'rawarray', 'array'))
)
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)):
# 单参数 CArray[elem_type]:与 CArray[elem_type, None] 语义统一为
# "长度自动推导数组"。此处无初始化字面量可推导 → 与 ,None 分支同用
# [0 x elem] 占位,真实长度由 _generate_global_decl 按初始化字面量
# (List 长度 / str 长度+1) 修正。
# 参数位置经 _decay_array_to_ptr(:23-28) 退化为 elem*,与旧指针行为一致。
ElemType: str = self._get_type_str(SliceNode, embedded=True)
return f'[0 x {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] / list[rawptr[ast.AST]] /
# 用户泛型类 Box[Node])
# 实参串走 SymbolUtils.ResolveGenericTypeArgStr(与定义端
# _mangle_generic_class_name 同一规则源):此前只认 Name / Name-Tuple
# 实参,Attribute(ast.AST)/ Subscript(rawptr[...])/ BinOp
# (X | CPtr)/ 混合 Tuple 一律退回未特化的 %"...list"*,
# 与 define 端发射的 %"<mod>.list[ast.ASTptr]" 不一致
# (Undefined method / 签名错位)。
# 内建容器(non_struct_types)之外,**用户泛型类**同样特化:判据
# _generic_class_names(ClassDef.type_params,与定义端
# HandlesClassDef._generic_class_templates 同源),此前只有内建容器名
# 会特化 → Box[Node] 字段在 stub 端是 %"<mod>.Box"*、定义端是
# %"<mod>.Box[<已解析实参>]"*(Holder 字段布局两侧不一致)。
if isinstance(annotation.value, ast.Name):
gc_name: str = annotation.value.id
if (gc_name in non_struct_types or gc_name in self._generic_class_names) \
and gc_name != 'tuple':
gc_slice: ast.AST = annotation.slice
# 多参数泛型(dict[K, V]):'][' 分隔,与
# _mangle_generic_class_name 一致
gc_nodes: list[ast.AST] = (
list(gc_slice.elts) if isinstance(gc_slice, ast.Tuple) else [gc_slice])
gc_mangled: list[str] = [
ResolveGenericTypeArgStr(
gc_node,
TCAliasMap=self._from_import_aliases,
StructSha1Map=self.struct_sha1_map)
for gc_node in gc_nodes]
gc_spec: str = gc_name + '[' + ']['.join(gc_mangled) + ']'
# 特化名前缀取**泛型模板类定义模块**的 SHA1(list → includes/_list.vp、
# Box → 定义 Box 的模块,查 struct_sha1_map 即"类名 → 定义模块"表),
# 与定义端 HandlesClassDef._specialize_generic_class 的
# Gen.module_sha1 = template['sha1']、调用点
# Gen._struct_sha1_map[spec_name] 同一条规则源。
# 此前用 self.module_sha1(使用方模块):同一特化在 declare(使用方前缀)
# 与 define/call(模板模块前缀)两侧不一致 → 跨模块 undefined symbol。
gc_sha1: str | None = self.struct_sha1_map.get(gc_name, self.module_sha1)
gc_sname: str = f'%"{gc_sha1}.{gc_spec}"' if gc_sha1 else f'%struct.{gc_spec}'
# 一律以指针引用(不区分 embedded):定义端对嵌入式泛型容器
# (字段 / CArray 元素)用不透明指针(实测字段 i8*,见
# FieldForms/FieldBox/FieldOrder),嵌入 unsized opaque
# 结构体值会让字段/元素偏移错位;非 embedded(参数/返回)
# 亦与定义端同为指针
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 in ('callable', '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