2207 lines
131 KiB
Python
2207 lines
131 KiB
Python
from __future__ import annotations
|
||
from typing import TYPE_CHECKING, Any
|
||
if TYPE_CHECKING:
|
||
from lib.core.translator import Translator
|
||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||
import vast as ast
|
||
import copy
|
||
import traceback
|
||
import llvmlite.ir as ir
|
||
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta
|
||
from lib.core.SymbolUtils import FindAutoAddrMode
|
||
from lib.core.VLogger import get_logger as _vlog
|
||
from lib.constants.config import mode as _config_mode
|
||
from lib.core import TypeSystem
|
||
from lib.core.TypeSystem import CTypeRegistry
|
||
|
||
|
||
# 内建存储类标记装饰器名称集合
|
||
_T_STORAGE_DECORATORS = frozenset({'CExport', 'CExtern', 'CStatic', 'State', 'CInline', 'TLS'})
|
||
|
||
# `@CReturn` 装饰器已移除;任何地方遇到都必须 fail-fast,不得静默忽略或改写。
|
||
_CRETURN_REMOVED_HINT: str = (
|
||
"`@CReturn` 已移除:请改用返回注解 `-> tuple[ty1, ty2, ...]`(多返回值打包为 struct)"
|
||
)
|
||
|
||
|
||
def _RejectCReturnDecorator(node: ast.AST, decorators: list[ast.AST]) -> None:
|
||
"""扫到 `@CReturn` 装饰器即 fail-fast 报错(该装饰器已移除)。"""
|
||
for decorator in decorators:
|
||
if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Attribute):
|
||
if decorator.func.attr == 'CReturn':
|
||
func_name: str = getattr(node, 'name', '<unknown>')
|
||
raise SyntaxError(f"函数 '{func_name}':{_CRETURN_REMOVED_HINT}")
|
||
|
||
|
||
def _RejectRefReturnAnnotation(node: ast.AST) -> None:
|
||
"""返回注解出现值引用标记(`&T` / `&temp T`)即 fail-fast。
|
||
|
||
值引用仅用于函数参数位;返回位一律拒绝,禁止静默按指针降级。
|
||
"""
|
||
if getattr(node, 'returns', None) is None:
|
||
return
|
||
if FindAutoAddrMode(node.returns) is not None:
|
||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||
func_name: str = getattr(node, 'name', '<unknown>')
|
||
raise FailFastError(
|
||
f"返回注解不支持值引用 `&T` / `&temp T`(函数 '{func_name}'):"
|
||
f"值引用仅用于函数参数位;返回位请改用显式指针类型(如 `T*`)。")
|
||
|
||
|
||
def _IsVoidOrDeclAnnotation(Annot: ast.AST) -> bool:
|
||
"""判断函数返回注解是否为 void 或 extern/export 声明型辅助符号。
|
||
|
||
void:None / CVoid。
|
||
声明型辅助符号:State(extern)/ CExport(export)/ CExtern——
|
||
此类函数 body 为空(extern 声明),掉出末尾是正常形态,必须豁免 fail-fast。
|
||
"""
|
||
if isinstance(Annot, ast.BinOp) and isinstance(Annot.op, ast.BitOr):
|
||
Line: int = getattr(Annot, 'lineno', 0) or 0
|
||
raise TypeError(
|
||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||
# 新表示:修饰词写入注解节点的 Markers(State/CExport/CExtern -> state/export/extern)。
|
||
Markers: tuple[str, ...] = getattr(Annot, 'Markers', None) or ()
|
||
if 'state' in Markers or 'export' in Markers or 'extern' in Markers:
|
||
return True
|
||
if isinstance(Annot, ast.Constant):
|
||
return Annot.value is None
|
||
if isinstance(Annot, ast.Subscript):
|
||
return _IsVoidOrDeclAnnotation(Annot.value)
|
||
return False
|
||
|
||
|
||
class FunctionHandle(BaseHandle):
|
||
@staticmethod
|
||
def _ExtractFuncMeta(decorator_list: list[ast.AST]) -> FuncMeta:
|
||
meta: FuncMeta = FuncMeta.NONE
|
||
if not decorator_list:
|
||
return meta
|
||
for d in decorator_list:
|
||
if isinstance(d, ast.Name):
|
||
if d.id == 'staticmethod':
|
||
meta |= FuncMeta.STATIC_METHOD
|
||
elif d.id == 'property':
|
||
meta |= FuncMeta.PROPERTY_GETTER
|
||
elif d.id == 'classmethod':
|
||
meta |= FuncMeta.CLASS_METHOD
|
||
elif isinstance(d, ast.Attribute):
|
||
if isinstance(d.value, ast.Name):
|
||
# 支持 @property.setter 和 @propname.setter 两种形式
|
||
# @propname.setter 中 propname 是之前用 @property 定义的同名属性
|
||
if d.value.id == 'property' or d.attr in ('setter', 'getter', 'deleter'):
|
||
if d.attr == 'setter':
|
||
meta |= FuncMeta.PROPERTY_SETTER
|
||
elif d.attr == 'getter':
|
||
meta |= FuncMeta.PROPERTY_GETTER
|
||
elif d.attr == 'deleter':
|
||
meta |= FuncMeta.PROPERTY_DELETER
|
||
return meta
|
||
|
||
def _extract_decorator_storage_flags(self, Node: ast.FunctionDef) -> dict[str, bool]:
|
||
"""从装饰器列表中提取内建存储类标记
|
||
|
||
支持 @CExport, @CExtern, @CStatic, @State, @CInline
|
||
内建标记按裸名书写,如 @CExport。
|
||
|
||
Returns:
|
||
dict with keys: 'is_export', 'is_extern', 'is_static', 'is_state', 'is_inline'
|
||
"""
|
||
flags: dict[str, bool] = {
|
||
'is_export': False, 'is_extern': False,
|
||
'is_static': False, 'is_state': False, 'is_inline': False,
|
||
}
|
||
if not Node.decorator_list:
|
||
return flags
|
||
symtab: object = self.Trans.SymbolTable
|
||
for decorator in Node.decorator_list:
|
||
attr_name: str | None = None
|
||
# 内建标记按裸名书写(@CExport / @CStatic / ...)
|
||
if isinstance(decorator, ast.Name):
|
||
cls: type | None = getattr(TypeSystem, decorator.id, None)
|
||
if cls is None and hasattr(symtab, '_builtin_type_symbols'):
|
||
cls = symtab._builtin_type_symbols.get(decorator.id)
|
||
if cls is not None and isinstance(cls, type) and issubclass(cls, TypeSystem.CType):
|
||
attr_name = cls.__name__
|
||
if attr_name and attr_name in _T_STORAGE_DECORATORS:
|
||
if attr_name == 'CExport':
|
||
flags['is_export'] = True
|
||
elif attr_name == 'CExtern':
|
||
flags['is_extern'] = True
|
||
elif attr_name == 'CStatic':
|
||
flags['is_static'] = True
|
||
elif attr_name == 'State':
|
||
flags['is_state'] = True
|
||
elif attr_name == 'CInline':
|
||
flags['is_inline'] = True
|
||
return flags
|
||
|
||
@staticmethod
|
||
def _is_t_storage_decorator(decorator: ast.AST, symtab: object) -> bool:
|
||
"""检查装饰器是否是内建存储类标记(用于排除 behavior_decorators)"""
|
||
attr_name: str | None = None
|
||
if isinstance(decorator, ast.Name):
|
||
cls: type | None = getattr(TypeSystem, decorator.id, None)
|
||
if cls is None and hasattr(symtab, '_builtin_type_symbols'):
|
||
cls = symtab._builtin_type_symbols.get(decorator.id)
|
||
if cls is not None and isinstance(cls, type) and issubclass(cls, TypeSystem.CType):
|
||
attr_name = cls.__name__
|
||
elif decorator.id in _T_STORAGE_DECORATORS and hasattr(TypeSystem, decorator.id):
|
||
# TLS 是普通函数标记,不是 CType 子类
|
||
attr_name = decorator.id
|
||
return attr_name in _T_STORAGE_DECORATORS if attr_name else False
|
||
|
||
# ------------------------------------------------------------------
|
||
# 函数签名公共辅助:以下三个方法供 _GetFunctionSignatureLlvm 与
|
||
# _EmitFunctionLlvm 共享,避免 ~80 行重复代码。
|
||
# ------------------------------------------------------------------
|
||
|
||
def _compute_func_name_meta(self, Node: ast.FunctionDef, ClassName: str | None) -> tuple[str, str, FuncMeta]:
|
||
"""计算函数全名(含 setter/deleter 后缀)和 func_meta
|
||
|
||
Returns:
|
||
(FuncName, RawFuncName, func_meta)
|
||
"""
|
||
RawFuncName: str = Node.name
|
||
FuncName: str = f"{ClassName}.{RawFuncName}" if ClassName else RawFuncName
|
||
func_meta: FuncMeta = self._ExtractFuncMeta(Node.decorator_list)
|
||
# property setter/deleter 使用不同的函数名后缀,避免与 getter 冲突
|
||
if FuncMeta.PROPERTY_SETTER in func_meta:
|
||
FuncName = FuncName + '$set'
|
||
elif FuncMeta.PROPERTY_DELETER in func_meta:
|
||
FuncName = FuncName + '$del'
|
||
return FuncName, RawFuncName, func_meta
|
||
|
||
def _resolve_method_class(self, Node: ast.FunctionDef, ClassName: str | None, func_meta: FuncMeta, FuncName: str, Gen: LlvmCodeGenerator) -> tuple[bool, bool, str | None]:
|
||
"""判定函数是否是实例方法 / 类方法,并解析所属类名
|
||
|
||
Returns:
|
||
(IsMethod, IsClassMethod, ResolvedClassName)
|
||
"""
|
||
RawFuncName: str = Node.name
|
||
IsMethod: bool = False
|
||
IsClassMethod: bool = False
|
||
ResolvedClassName: str | None = ClassName
|
||
if not ResolvedClassName:
|
||
for potential_class in Gen.class_methods:
|
||
if FuncName.startswith(f"{potential_class}."):
|
||
IsMethod = True
|
||
ResolvedClassName = potential_class
|
||
break
|
||
else:
|
||
IsMethod = FuncMeta.STATIC_METHOD not in func_meta and FuncMeta.CLASS_METHOD not in func_meta
|
||
IsClassMethod = FuncMeta.CLASS_METHOD in func_meta
|
||
if RawFuncName == '__init__':
|
||
IsMethod = False
|
||
return IsMethod, IsClassMethod, ResolvedClassName
|
||
|
||
def _apply_struct_self_cls_types(self, ParamTypes: list[ir.Type], ParamNames: list[str], IsMethod: bool, IsClassMethod: bool, ResolvedClassName: str | None, Gen: LlvmCodeGenerator) -> bool:
|
||
"""根据 IsMethod / IsClassMethod 调整 self/cls 参数的 LLVM 类型
|
||
|
||
- 若是实例方法且无 self 参数,自动插入一个 struct 指针类型;
|
||
此时调用方需要同步插入对应的 ParamTypeStrs(本方法不维护)。
|
||
- 若是 @classmethod,将 cls 参数覆盖为 struct 指针类型。
|
||
|
||
Returns:
|
||
True 表示为实例方法自动插入了 self 参数;False 表示未插入。
|
||
"""
|
||
if not ResolvedClassName or ResolvedClassName not in Gen.structs:
|
||
return False
|
||
# 治本修复:同名类 sha1 冲突检测。
|
||
# 当多个模块定义同名类(如 stmts.py:Module 和 __module.py:Module)时,
|
||
# Gen.structs[short_name] 可能指向错误模块的 struct(set_body 已锁定错误布局)。
|
||
# 通过 class_sha1_map 获取当前类的源模块 sha1,查找以 sha1 为前缀的完整 struct。
|
||
TargetStruct: ir.IdentifiedStructType = Gen.structs[ResolvedClassName]
|
||
ClassSha1Map: dict[str, str] = getattr(Gen, 'class_sha1_map', {})
|
||
ExpectedSha1: str | None = ClassSha1Map.get(ResolvedClassName)
|
||
if ExpectedSha1 and isinstance(TargetStruct, ir.IdentifiedStructType):
|
||
ExistingSha1: str = Gen._extract_struct_sha1(TargetStruct)
|
||
if ExistingSha1 and ExistingSha1 != ExpectedSha1:
|
||
# sha1 冲突:查找或创建正确的 struct
|
||
FullKey: str = f"{ExpectedSha1}.{ResolvedClassName}"
|
||
if FullKey in Gen.structs:
|
||
TargetStruct = Gen.structs[FullKey]
|
||
else:
|
||
# 创建新 struct 并从 stub 加载 body
|
||
TargetStruct = Gen._get_or_create_struct(ResolvedClassName, source_sha1=ExpectedSha1)
|
||
if hasattr(self.Trans, 'ImportHandler'):
|
||
self.Trans.ImportHandler._TryLoadStructFromStub(ResolvedClassName, Gen, source_sha1=ExpectedSha1)
|
||
if FullKey in Gen.structs:
|
||
TargetStruct = Gen.structs[FullKey]
|
||
# 安全回退:如果新 struct 仍为 opaque(body 未加载),回退到原始短名 struct,
|
||
# 避免方法编译生成无效 GEP(访问 opaque struct 元素)导致运行时崩溃。
|
||
if isinstance(TargetStruct, ir.IdentifiedStructType):
|
||
try:
|
||
_is_opaque: bool = TargetStruct.is_opaque
|
||
except (AssertionError, AttributeError):
|
||
_is_opaque = False
|
||
if _is_opaque:
|
||
TargetStruct = Gen.structs[ResolvedClassName]
|
||
if IsMethod:
|
||
StructPtrType: ir.PointerType = ir.PointerType(TargetStruct)
|
||
SelfIdx: int = next((i for i, n in enumerate(ParamNames) if n == "self"), -1)
|
||
if SelfIdx >= 0:
|
||
ParamTypes[SelfIdx] = StructPtrType
|
||
return False
|
||
ParamTypes.insert(0, StructPtrType)
|
||
ParamNames.insert(0, "self")
|
||
return True
|
||
# 非方法但属于类(如 staticmethod / 顶层函数位于类下)
|
||
SelfIdx = next((i for i, n in enumerate(ParamNames) if n == "self"), -1)
|
||
if SelfIdx >= 0:
|
||
StructPtrType = ir.PointerType(TargetStruct)
|
||
ParamTypes[SelfIdx] = StructPtrType
|
||
if IsClassMethod:
|
||
ClsIdx: int = next((i for i, n in enumerate(ParamNames) if n == "cls"), -1)
|
||
if ClsIdx >= 0:
|
||
StructPtrType = ir.PointerType(TargetStruct)
|
||
ParamTypes[ClsIdx] = StructPtrType
|
||
return False
|
||
|
||
def _body_contains_raise(self, body: list[ast.AST]) -> bool:
|
||
for node in ast.walk(ast.Module(body=body, type_ignores=[])):
|
||
if isinstance(node, ast.Raise):
|
||
if node.exc:
|
||
if isinstance(node.exc, ast.Name) and node.exc.id == 'StopIteration':
|
||
continue
|
||
if isinstance(node.exc, ast.Call) and isinstance(node.exc.func, ast.Name) and node.exc.func.id == 'StopIteration':
|
||
continue
|
||
return True
|
||
if isinstance(node, ast.Call):
|
||
called_name: str | None = None
|
||
if isinstance(node.func, ast.Name):
|
||
called_name = node.func.id
|
||
elif isinstance(node.func, ast.Attribute):
|
||
called_name = node.func.attr
|
||
if called_name:
|
||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||
for prefix in ['', f'{called_name}.', f'__']:
|
||
for suffix in ['', f'.{called_name}']:
|
||
fname: str = f'{prefix}{called_name}{suffix}'
|
||
if fname in Gen.functions:
|
||
func: Any = Gen.functions[fname]
|
||
if len(func.args) > 0:
|
||
for arg in func.args:
|
||
if hasattr(arg, 'name') and arg.name in ('__eh_msg_out__', '__eh_code_out__'):
|
||
return True
|
||
break
|
||
return False
|
||
|
||
_LLVM_ATTR_NAMES = frozenset({
|
||
'nobuiltin', 'nounwind', 'noredzone', 'willreturn', 'mustprogress',
|
||
'optnone', 'noinline', 'alwaysinline', 'readnone', 'readonly',
|
||
'writeonly', 'inaccessiblememonly', 'inaccessiblemem_or_argmemonly',
|
||
})
|
||
|
||
def _ExtractLLVMAttrs(self, node: ast.AST) -> list[str]:
|
||
attrs: list[str] = []
|
||
for raw_attr in getattr(node, 'Attributes', None) or ():
|
||
attr_name: str = str(raw_attr).split('(', 1)[0].strip()
|
||
if attr_name in self._LLVM_ATTR_NAMES:
|
||
attrs.append(attr_name)
|
||
if isinstance(node, ast.Attribute):
|
||
resolved: str | None = self._GetAttrLLVMName(node)
|
||
if resolved:
|
||
attrs.append(resolved)
|
||
return attrs
|
||
|
||
def _GetAttrLLVMName(self, node: ast.AST) -> str | None:
|
||
if not isinstance(node, ast.Attribute):
|
||
return None
|
||
if node.attr not in self._LLVM_ATTR_NAMES:
|
||
return None
|
||
value: ast.AST = node.value
|
||
if not isinstance(value, ast.Attribute) or value.attr != 'llvm':
|
||
return None
|
||
inner: ast.AST = value.value
|
||
if not isinstance(inner, ast.Name) or inner.id != 'attr':
|
||
return None
|
||
return node.attr
|
||
|
||
def _infer_return_type_from_body(self, Node: ast.AST, Gen: LlvmCodeGenerator | None = None, ClassName: str | None = None) -> tuple[str, bool] | None:
|
||
local_var_types: dict[str, tuple[str, bool]] = {}
|
||
for child in ast.walk(Node):
|
||
if isinstance(child, ast.Assign) and len(child.targets) == 1:
|
||
target: ast.AST = child.targets[0]
|
||
if isinstance(target, ast.Name) and isinstance(child.value, ast.Subscript):
|
||
sub: ast.Subscript = child.value
|
||
if (isinstance(sub.value, ast.Attribute)
|
||
and isinstance(sub.value.value, ast.Name)
|
||
and sub.value.value.id == 'self'
|
||
and ClassName and ClassName in Gen.class_members):
|
||
member_name: str = sub.value.attr
|
||
for m_name, m_type in Gen.class_members[ClassName]:
|
||
if m_name == member_name:
|
||
if isinstance(m_type, ir.ArrayType):
|
||
elem_type: ir.Type = m_type.element
|
||
if isinstance(elem_type, ir.FloatType):
|
||
local_var_types[target.id] = ('float', False)
|
||
elif isinstance(elem_type, ir.DoubleType):
|
||
local_var_types[target.id] = ('double', False)
|
||
elif isinstance(elem_type, ir.IntType):
|
||
if elem_type.width == 8:
|
||
local_var_types[target.id] = ('char', False)
|
||
else:
|
||
local_var_types[target.id] = ('int', False)
|
||
elif isinstance(elem_type, ir.PointerType):
|
||
if isinstance(elem_type.pointee, ir.IntType) and elem_type.pointee.width == 8:
|
||
local_var_types[target.id] = ('char', True)
|
||
else:
|
||
local_var_types[target.id] = ('void', True)
|
||
elif isinstance(elem_type, ir.IdentifiedStructType):
|
||
struct_name: str = elem_type.name
|
||
if struct_name:
|
||
for sn, st in Gen.structs.items():
|
||
if st.name == struct_name or sn == struct_name:
|
||
local_var_types[target.id] = (sn, False)
|
||
break
|
||
else:
|
||
local_var_types[target.id] = (elem_type.name, False)
|
||
elif isinstance(m_type, ir.PointerType):
|
||
pointee: ir.Type = m_type.pointee
|
||
if isinstance(pointee, ir.FloatType):
|
||
local_var_types[target.id] = ('float', False)
|
||
elif isinstance(pointee, ir.DoubleType):
|
||
local_var_types[target.id] = ('double', False)
|
||
elif isinstance(pointee, ir.IntType):
|
||
if pointee.width == 8:
|
||
local_var_types[target.id] = ('char', False)
|
||
else:
|
||
local_var_types[target.id] = ('int', False)
|
||
elif isinstance(pointee, ir.PointerType):
|
||
local_var_types[target.id] = ('void', True)
|
||
elif isinstance(pointee, ir.IdentifiedStructType):
|
||
for sn, st in Gen.structs.items():
|
||
if st == pointee or st.name == pointee.name:
|
||
local_var_types[target.id] = (sn, True)
|
||
break
|
||
break
|
||
for child in ast.walk(Node):
|
||
if isinstance(child, ast.Return) and child.value:
|
||
val: ast.AST = child.value
|
||
if isinstance(val, ast.Name) and val.id == 'self' and ClassName:
|
||
return (ClassName, True)
|
||
if isinstance(val, ast.Call):
|
||
if isinstance(val.func, ast.Name):
|
||
callee: str = val.func.id
|
||
if callee == 'malloc':
|
||
return ('char', True)
|
||
if callee == 'chr':
|
||
return ('char', False)
|
||
if Gen and callee in Gen.functions:
|
||
func: Any = Gen.functions[callee]
|
||
if hasattr(func, 'ftype'):
|
||
ret_type: ir.Type = func.ftype.return_type
|
||
if isinstance(ret_type, ir.PointerType):
|
||
if isinstance(ret_type.pointee, ir.IntType) and ret_type.pointee.width == 8:
|
||
return ('char', True)
|
||
return ('void', True)
|
||
elif isinstance(ret_type, ir.IntType):
|
||
if ret_type.width == 8:
|
||
return ('char', False)
|
||
return ('int', False)
|
||
elif isinstance(ret_type, ir.VoidType):
|
||
return ('void', False)
|
||
elif isinstance(val.func, ast.Attribute):
|
||
pass
|
||
callee_name: str | None = None
|
||
if isinstance(val.func, ast.Name):
|
||
callee_name = val.func.id
|
||
elif isinstance(val.func, ast.Attribute):
|
||
callee_name = getattr(val.func, 'attr', None)
|
||
if callee_name:
|
||
sym: Any = self.Trans.SymbolTable.lookup(callee_name)
|
||
if sym and isinstance(sym, dict):
|
||
ret_type_str: str = sym.get('return_type', '')
|
||
if ret_type_str and ret_type_str != 'int':
|
||
IsPtr: bool = sym.get('IsPtr', False)
|
||
return (ret_type_str, IsPtr)
|
||
elif isinstance(val, ast.Constant):
|
||
if val.value is None:
|
||
return ('char', True)
|
||
elif isinstance(val.value, str) and len(val.value) <= 1:
|
||
return ('char', True)
|
||
elif isinstance(val, ast.Name):
|
||
var_name: str = val.id
|
||
if var_name in local_var_types:
|
||
return local_var_types[var_name]
|
||
var_info: Any = self.Trans.SymbolTable.lookup(var_name)
|
||
if var_info and isinstance(var_info, dict):
|
||
var_type: str = var_info.get('type', '')
|
||
if var_type and var_type != 'int':
|
||
IsPtr: bool = var_info.get('IsPtr', False)
|
||
return (var_type, IsPtr)
|
||
elif isinstance(val, ast.Subscript):
|
||
if (isinstance(val.value, ast.Attribute)
|
||
and isinstance(val.value.value, ast.Name)
|
||
and val.value.value.id == 'self'
|
||
and ClassName):
|
||
member_name: str = val.value.attr
|
||
if ClassName in Gen.class_members:
|
||
for m_name, m_type in Gen.class_members[ClassName]:
|
||
if m_name == member_name:
|
||
if isinstance(m_type, ir.ArrayType):
|
||
elem_type: ir.Type = m_type.element
|
||
if isinstance(elem_type, ir.FloatType):
|
||
return ('float', False)
|
||
elif isinstance(elem_type, ir.DoubleType):
|
||
return ('double', False)
|
||
elif isinstance(elem_type, ir.IntType):
|
||
if elem_type.width == 8:
|
||
return ('char', False)
|
||
return ('int', False)
|
||
elif isinstance(elem_type, ir.PointerType):
|
||
if isinstance(elem_type.pointee, ir.IntType) and elem_type.pointee.width == 8:
|
||
return ('char', True)
|
||
return ('void', True)
|
||
elif isinstance(elem_type, ir.IdentifiedStructType):
|
||
struct_name: str = elem_type.name
|
||
if struct_name:
|
||
for sn, st in Gen.structs.items():
|
||
if st.name == struct_name or sn == struct_name:
|
||
return (sn, False)
|
||
return (elem_type.name, False)
|
||
elif isinstance(m_type, ir.PointerType):
|
||
pointee: ir.Type = m_type.pointee
|
||
if isinstance(pointee, ir.FloatType):
|
||
return ('float', False)
|
||
elif isinstance(pointee, ir.DoubleType):
|
||
return ('double', False)
|
||
elif isinstance(pointee, ir.IntType):
|
||
if pointee.width == 8:
|
||
return ('char', False)
|
||
return ('int', False)
|
||
elif isinstance(pointee, ir.PointerType):
|
||
return ('void', True)
|
||
elif isinstance(pointee, ir.IdentifiedStructType):
|
||
for sn, st in Gen.structs.items():
|
||
if st == pointee or st.name == pointee.name:
|
||
return (sn, True)
|
||
return (pointee.name, True)
|
||
break
|
||
if isinstance(val.value, ast.Name):
|
||
var_name: str = val.value.id
|
||
var_info: Any = self.Trans.SymbolTable.lookup(var_name)
|
||
if var_info and isinstance(var_info, dict):
|
||
var_type: str = var_info.get('type', '')
|
||
if var_type.startswith('list[') or var_type.startswith('List[') or var_type.startswith('CArray['):
|
||
inner: str = var_type[var_type.index('[') + 1:var_type.rindex(']')]
|
||
parts: list[str] = inner.split(',')
|
||
elem_type_str: str = parts[0].strip()
|
||
if elem_type_str and elem_type_str != 'int':
|
||
IsPtr: bool = var_info.get('IsPtr', False)
|
||
return (elem_type_str, IsPtr)
|
||
return None
|
||
|
||
def _GetFunctionSignatureLlvm(self, Node: ast.FunctionDef, Gen: LlvmCodeGenerator, ClassName: str | None = None, extra_params: list[tuple[str, Any]] | None = None) -> tuple[str, ir.FunctionType, Any, list[Any], list[ast.AST], bool, str | None, bool]:
|
||
FuncName, RawFuncName, func_meta = self._compute_func_name_meta(Node, ClassName)
|
||
if Node.decorator_list:
|
||
_RejectCReturnDecorator(Node, Node.decorator_list)
|
||
_RejectRefReturnAnnotation(Node)
|
||
MultiRetTypes: list[ast.AST] = []
|
||
if Node.returns:
|
||
llvm_attrs: list[str] = self._ExtractLLVMAttrs(Node.returns)
|
||
if llvm_attrs:
|
||
if not hasattr(self, '_pending_llvm_attrs'):
|
||
self._pending_llvm_attrs = {}
|
||
self._pending_llvm_attrs[FuncName] = llvm_attrs
|
||
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)
|
||
IsPtr: bool = False
|
||
ReturnTypeInfo: Any = None
|
||
if Node.returns:
|
||
if MultiRetTypes:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = TypeSystem.CVoid()
|
||
else:
|
||
try:
|
||
if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr):
|
||
Line: int = getattr(Node.returns, 'lineno', 0) or 0
|
||
raise TypeError(
|
||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||
else:
|
||
is_str_type: bool = False
|
||
if isinstance(Node.returns, ast.Name) and Node.returns.id in ('str', 'bytes'):
|
||
is_str_type = True
|
||
# 走 ResolveAnnotationType 而非 CTypeInfo.FromNode:指针下标
|
||
# 返回注解(rawptr[T] / CPtr[T])需走 TypeMerge 通用解析,
|
||
# 否则内层跨模块类解析不出 → CVoid/1(i8*)。
|
||
ReturnTypeInfo = self.ResolveAnnotationType(Node.returns)
|
||
if ReturnTypeInfo and ReturnTypeInfo.IsDefine:
|
||
inferred: Any = self._infer_return_type_from_body(Node, Gen, ClassName)
|
||
if inferred:
|
||
ReturnTypeInfo = CTypeInfo.FromTypeName(inferred[0])
|
||
ReturnTypeInfo.PtrCount = 1 if inferred[1] else 0
|
||
else:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = TypeSystem.CInt()
|
||
if not hasattr(self, '_cdefine_funcs'):
|
||
self._cdefine_funcs = set()
|
||
self._cdefine_funcs.add(FuncName)
|
||
elif ReturnTypeInfo and ReturnTypeInfo.IsState:
|
||
if ReturnTypeInfo.PtrCount > 0 or (ReturnTypeInfo.BaseType and not isinstance(ReturnTypeInfo.BaseType, TypeSystem.CVoid)):
|
||
pass
|
||
else:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = TypeSystem.CVoid()
|
||
if ReturnTypeInfo is None:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = TypeSystem.CVoid()
|
||
# 仅指针层数 <=1 才算裸 str/bytes(i8*)。
|
||
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,不能压平。
|
||
if is_str_type or (ReturnTypeInfo.IsStr and ReturnTypeInfo.PtrCount <= 1):
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = TypeSystem.CChar()
|
||
ReturnTypeInfo.PtrCount = 1
|
||
# 检查泛型类返回类型 (如 list[str])
|
||
# 注意:_from_node_subscript 对未识别的泛型下标(如 list[str])返回空 CTypeInfo(BaseType=None),
|
||
# 此时 IsVoid 为 False(因为 IsVoid 仅检查 CVoid 实例),需额外检测 BaseType is None
|
||
if (isinstance(Node.returns, ast.Subscript)
|
||
and isinstance(Node.returns.value, ast.Name)
|
||
and hasattr(self.Trans.ClassHandler, '_generic_class_templates')
|
||
and Node.returns.value.id in self.Trans.ClassHandler._generic_class_templates
|
||
and (ReturnTypeInfo.IsVoid or ReturnTypeInfo.BaseType is None) and ReturnTypeInfo.PtrCount == 0):
|
||
ret_class: str = Node.returns.value.id
|
||
ret_slice: ast.AST = Node.returns.slice
|
||
ret_type_args: list[str] = []
|
||
ret_type_names: list[str] = []
|
||
if isinstance(ret_slice, ast.Tuple):
|
||
for elt in ret_slice.elts:
|
||
if isinstance(elt, ast.Name):
|
||
tn2: str = elt.id
|
||
ts2: str = tn2
|
||
if tn2 == 'int':
|
||
ts2, tn2 = 'int', 'CInt'
|
||
ret_type_args.append(ts2)
|
||
ret_type_names.append(tn2)
|
||
elif isinstance(ret_slice, ast.Name):
|
||
tn2: str = ret_slice.id
|
||
ts2: str = tn2
|
||
if tn2 == 'int':
|
||
ts2, tn2 = 'int', 'CInt'
|
||
ret_type_args.append(ts2)
|
||
ret_type_names.append(tn2)
|
||
# 返回类型解析只需 struct 定义,不需方法体;使用 declare_only=True
|
||
# 避免过早触发完整特化(此时 MemManager.alloc 可能尚未注册,
|
||
# 导致 __new__ 的 pool.alloc(48) 解析失败,IR 块未终止)。
|
||
# 完整特化由后续类实例化(L3688/L3753)触发 declare_only=False。
|
||
try:
|
||
spec_name2: str | None = self.Trans.ClassHandler._specialize_generic_class(
|
||
ret_class, ret_type_args, Gen, type_names=ret_type_names, declare_only=True)
|
||
except Exception as _spec_err:
|
||
# 不静默吞特化异常:记录到 Gen._generic_spec_error 后再
|
||
# 交给外层返回类型回退(否则只剩一个错误的 CInt 返回类型)。
|
||
Gen._generic_spec_error = f'{type(_spec_err).__name__}: {_spec_err}'
|
||
raise
|
||
if spec_name2 and spec_name2 in Gen.structs:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = TypeSystem.CStruct(name=spec_name2)
|
||
ReturnTypeInfo.PtrCount = 1
|
||
if (ReturnTypeInfo.IsVoid or ReturnTypeInfo.BaseType is None) and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = TypeSystem.CInt()
|
||
except TypeError:
|
||
raise
|
||
except Exception: # 回退:设置默认返回类型为 CInt
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = TypeSystem.CInt()
|
||
else:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = TypeSystem.CInt()
|
||
inferred: Any = self._infer_return_type_from_body(Node, Gen, ClassName)
|
||
if inferred:
|
||
ReturnTypeInfo = CTypeInfo.FromTypeName(inferred[0])
|
||
ReturnTypeInfo.PtrCount = 1 if inferred[1] else 0
|
||
IsPtr = ReturnTypeInfo.IsPtr if ReturnTypeInfo else False
|
||
ReturnType: ir.Type = Gen._ctype_to_llvm(ReturnTypeInfo)
|
||
# 此处原有 "Ptr(Ptr(Struct)) → Ptr(Struct)" 的压层(历史遗留):会把已解析的
|
||
# 多层指针返回类型(`-> rawptr[rawptr[X]]` / `-> CPtr[CPtr[X]]`)
|
||
# 与泛型特化方法返回(`list[X**]` 的 get/pop/__getitem__/__next__)少算一层,
|
||
# 与同函数的形参(`append(item: T)` 保留 `X**`)、声明端
|
||
# DeclarationGenerator._get_type_str 的指针下标分支(同样不压层,见
|
||
# '_is_bare_class_ref_annotation' 为假时逐层外包)以及 _EmitFunctionLlvm
|
||
# 的定义体路径全部不一致。违反"多层指针已解析时照原样保留层数"。
|
||
# 实测(36 用例 A/B)删除后仅 `list[X**]` 的 4 个方法 declare 由 `X*` 变
|
||
# `X**`,与 append/set 的形参一致;stub 逐字节不变。
|
||
if isinstance(ReturnType, ir.IntType) and ReturnType.width == 8:
|
||
if RawFuncName == '__str__':
|
||
ReturnType = ir.PointerType(ir.IntType(8))
|
||
if isinstance(ReturnType, ir.VoidType) and FuncName == 'main':
|
||
ReturnType = ir.IntType(32)
|
||
IsMethod, IsClassMethod, ResolvedClassName = self._resolve_method_class(Node, ClassName, func_meta, FuncName, Gen)
|
||
# __new__ methods should return a pointer to the struct (for heap allocation replacement)
|
||
# 修复:前向声明也必须使用正确的返回类型,否则 _replace_function_decl 可能失败,
|
||
# 导致 vtable 引用错误的函数类型(i32 而非 ClassName*)
|
||
if RawFuncName == '__new__' and ResolvedClassName:
|
||
StructType = Gen.structs.get(ResolvedClassName)
|
||
if StructType:
|
||
if isinstance(StructType, ir.PointerType):
|
||
ReturnType = StructType
|
||
else:
|
||
ReturnType = ir.PointerType(StructType)
|
||
ParamTypes: list[ir.Type] = []
|
||
ParamNames: list[str] = []
|
||
ParamTypeStrs: list[Any] = []
|
||
auto_addr_modes: list[str | None] = []
|
||
MultiRetLlvmTypes: list[ir.Type] = []
|
||
if MultiRetTypes:
|
||
for i, ReturnTypeNode in enumerate(MultiRetTypes):
|
||
ReturnTypeInfo = CTypeInfo.FromNode(ReturnTypeNode, self.Trans.SymbolTable)
|
||
# 仅指针层数 <=1 才算裸 str/bytes(i8*)。
|
||
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,不能压平。
|
||
if ReturnTypeInfo and ReturnTypeInfo.IsStr and ReturnTypeInfo.PtrCount <= 1:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = TypeSystem.CChar()
|
||
ReturnTypeInfo.PtrCount = 1
|
||
if ReturnTypeInfo is None:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = TypeSystem.CInt()
|
||
RetType: ir.Type = Gen._ctype_to_llvm(ReturnTypeInfo)
|
||
MultiRetLlvmTypes.append(RetType)
|
||
ReturnType = ir.LiteralStructType(MultiRetLlvmTypes)
|
||
for Arg in Node.args.args:
|
||
ParamIsUnsigned: bool = False
|
||
if Arg.annotation:
|
||
try:
|
||
ParamTypeInfo: Any
|
||
# 走 ResolveParamAnnotation(= ResolveAnnotationType + 泛型模板
|
||
# 识别):参数注解中的泛型容器(list[X] / rawptr[list[X]])与
|
||
# 指针下标(rawptr[X])需走 TypeMerge 通用解析,否则
|
||
# TypeAnnotationResolver 解析不出 → VoidType → 报
|
||
# "无法识别的参数类型注解"。
|
||
ParamTypeInfo = self.ResolveParamAnnotation(Arg.annotation)
|
||
if ParamTypeInfo is None:
|
||
ParamTypeInfo = CTypeInfo()
|
||
ParamTypeInfo.BaseType = TypeSystem.CInt()
|
||
IsPtr = ParamTypeInfo.IsPtr
|
||
if ParamTypeInfo and getattr(ParamTypeInfo, 'IsCpythonObject', False) and not IsPtr:
|
||
IsPtr = True
|
||
ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1)
|
||
# 仅当指针层数 <=1 时才压平为 i8*(裸 str/bytes)。
|
||
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,
|
||
# 不能压平,否则形参类型错误导致 _adjust_args 多 load 一层崩溃。
|
||
if (ParamTypeInfo.IsStr and ParamTypeInfo.PtrCount <= 1) or (isinstance(Arg.annotation, ast.Name) and Arg.annotation.id in ('str', 'bytes')):
|
||
ParamTypeInfo = CTypeInfo()
|
||
ParamTypeInfo.BaseType = TypeSystem.CChar()
|
||
ParamTypeInfo.PtrCount = 1
|
||
IsPtr = True
|
||
# C 语言中数组参数退化为指针:CArray[type, N] → type*
|
||
if ParamTypeInfo.ArrayDims:
|
||
ParamTypeInfo.ArrayDims = []
|
||
ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1)
|
||
ParamType: ir.Type = Gen._ctype_to_llvm(ParamTypeInfo)
|
||
# 参数类型不能是 VoidType:C 语言不允许 void 参数,
|
||
# VoidType 说明类型注解无法识别(如跨模块 ast.expr),直接报错终止
|
||
if isinstance(ParamType, ir.VoidType):
|
||
AnnStr: str = ast.unparse(Arg.annotation) if hasattr(ast, 'unparse') else str(Arg.annotation)
|
||
raise SyntaxError(
|
||
f"无法识别的参数类型注解: '{AnnStr}'(在函数 '{Node.name}' 的参数 '{Arg.arg}' 上)。"
|
||
f"请使用有效的 VPC 类型(如 CPtr、ast.AST 或已注册的结构体)。"
|
||
)
|
||
ParamTypeStr: Any = ParamTypeInfo
|
||
except SyntaxError:
|
||
raise
|
||
except Exception as e:
|
||
ParamType = ir.IntType(32)
|
||
ParamTypeStr = CTypeInfo()
|
||
ParamTypeStr.BaseType = TypeSystem.CInt()
|
||
else:
|
||
if ClassName and Arg.arg != 'self':
|
||
op_method_names: list[str] = ['__add__', '__sub__', '__mul__', '__truediv__', '__floordiv__', '__mod__', '__pow__',
|
||
'__radd__', '__rsub__', '__rmul__', '__rtruediv__', '__rfloordiv__', '__rmod__', '__rpow__',
|
||
'__iadd__', '__isub__', '__imul__', '__itruediv__', '__ifloordiv__', '__imod__', '__ipow__',
|
||
'__eq__', '__ne__', '__lt__', '__le__', '__gt__', '__ge__',
|
||
'__neg__', '__pos__', '__abs__', '__call__']
|
||
if RawFuncName in op_method_names and ClassName in Gen.structs:
|
||
ParamType = ir.PointerType(Gen.structs[ClassName])
|
||
else:
|
||
ParamType = ir.IntType(32)
|
||
else:
|
||
ParamType = ir.IntType(32)
|
||
ParamTypeStr = CTypeInfo()
|
||
ParamTypeStr.BaseType = TypeSystem.CInt()
|
||
ParamTypes.append(ParamType)
|
||
ParamNames.append(Arg.arg)
|
||
ParamTypeStrs.append(ParamTypeStr)
|
||
# 自动取址模式(由注解读出,不依赖 BaseType 类型):
|
||
# 'ref' = &T、'temp' = &temp T(合成下标 CRef[T] / CTempRef[T]),
|
||
# 'always' = CAutoPtr。经 Gen._auto_addr_params 供调用点分流。
|
||
auto_mode: str | None = FindAutoAddrMode(Arg.annotation)
|
||
auto_addr_modes.append(auto_mode)
|
||
if self._apply_struct_self_cls_types(ParamTypes, ParamNames, IsMethod, IsClassMethod, ResolvedClassName, Gen):
|
||
ParamTypeStrs.insert(0, f"struct {ResolvedClassName}")
|
||
auto_addr_modes.insert(0, None)
|
||
IsVariadic: bool = Node.args.vararg is not None
|
||
if extra_params:
|
||
for var_name, ptr_type in extra_params:
|
||
ParamTypes.append(ptr_type)
|
||
ParamNames.append(f'__nonlocal_{var_name}__')
|
||
if IsMethod and RawFuncName == '__next__':
|
||
ParamTypes.append(ir.PointerType(ir.IntType(1)))
|
||
ParamNames.append('__stop_iter_flag__')
|
||
HasRaise: bool = self._body_contains_raise(Node.body)
|
||
if HasRaise and RawFuncName != 'main':
|
||
ParamTypes.append(ir.PointerType(ir.PointerType(ir.IntType(8))))
|
||
ParamNames.append('__eh_msg_out__')
|
||
ParamTypes.append(ir.PointerType(ir.IntType(32)))
|
||
ParamNames.append('__eh_code_out__')
|
||
FuncType: ir.FunctionType = ir.FunctionType(ReturnType, ParamTypes, var_arg=IsVariadic)
|
||
# 存储 auto_addr_modes(为额外参数补 None)
|
||
total_params: int = len(ParamTypes)
|
||
while len(auto_addr_modes) < total_params:
|
||
auto_addr_modes.append(None)
|
||
Gen._auto_addr_params[FuncName] = auto_addr_modes
|
||
return FuncName, FuncType, ReturnTypeInfo, ParamTypeStrs, MultiRetTypes, IsMethod, ResolvedClassName, IsVariadic
|
||
|
||
def _is_generic_function(self, Node: ast.FunctionDef) -> bool:
|
||
if hasattr(Node, 'type_params') and Node.type_params:
|
||
return True
|
||
return False
|
||
|
||
def _mangle_generic_name(self, func_name: str, type_args: list[str], has_cexport: bool = False) -> str:
|
||
mangled_args: list[str] = []
|
||
for ta in type_args:
|
||
llvm_str: str | None = CTypeRegistry.NameToLLVM(ta)
|
||
if llvm_str:
|
||
if llvm_str in ('float', 'double', 'half', 'fp128'):
|
||
mangled: str = 'f' + str(CTypeRegistry.GetClassByName(ta)().Size)
|
||
else:
|
||
mangled = llvm_str
|
||
else:
|
||
mangled = ta
|
||
mangled_args.append(mangled)
|
||
if has_cexport:
|
||
return func_name + '_T_' + '_'.join(mangled_args)
|
||
return func_name + '[' + ']['.join(mangled_args) + ']'
|
||
|
||
def _apply_type_map_to_node(self, Node: ast.FunctionDef, type_map: dict[str, str], cptr_params: set[str] | None = None) -> None:
|
||
for arg in Node.args.args:
|
||
if arg.annotation:
|
||
arg.annotation = self._replace_type_in_annotation(arg.annotation, type_map, cptr_params)
|
||
if Node.returns:
|
||
Node.returns = self._replace_type_in_annotation(Node.returns, type_map, cptr_params)
|
||
self._apply_type_map_to_body(Node.body, type_map, cptr_params)
|
||
|
||
def _replace_type_in_annotation(self, node: ast.AST, type_map: dict[str, str], cptr_params: set[str] | None = None) -> ast.AST:
|
||
if isinstance(node, ast.Name):
|
||
if node.id in type_map:
|
||
replacement: str = type_map[node.id]
|
||
return self._make_replacement_node(replacement)
|
||
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||
Line: int = getattr(node, 'lineno', 0) or 0
|
||
raise TypeError(
|
||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||
elif isinstance(node, ast.Attribute):
|
||
if hasattr(node, 'attr') and node.attr in type_map:
|
||
replacement: str = type_map[node.attr]
|
||
return self._make_replacement_node(replacement)
|
||
elif isinstance(node, ast.Subscript):
|
||
# 嵌套泛型(如 list[T]):递归替换 value 和 slice 中的类型参数
|
||
node.value = self._replace_type_in_annotation(node.value, type_map, cptr_params)
|
||
node.slice = self._replace_type_in_annotation(node.slice, type_map, cptr_params)
|
||
return node
|
||
|
||
def _make_replacement_node(self, replacement: str) -> ast.AST:
|
||
"""将 type_map 中的替换字符串转换为 AST 节点。
|
||
mangled 名称如 '<sha1>.AST*' 需要还原为 `CPtr[<sha1>.AST]` 下标结构,
|
||
否则类型解析会丢失 PtrCount 信息。
|
||
含点号的名称(如 '<sha1>.AST')需解析为 ast.Attribute 链。
|
||
下标形态('rawptr[ast.AST]' / 'list[AST]' 等)必须整体解析为 Subscript:
|
||
_make_name_node 只按 '.' 切分会把 'rawptr[ast.AST]' 拆成
|
||
Name('rawptr[ast') + Attribute('AST]'),两段都不是有效类型名 →
|
||
参数/返回注解解析为空 → VoidType → "无法识别的参数类型注解"。
|
||
指针下标统一保持 Subscript 形态(rawptr[T] / CPtr[T] / CRef[T] / ...)。
|
||
内层为已混淆名(数字开头,如 'rawptr[7565e081d88517ac.AST]')时
|
||
ast.parse 无法解析(数字开头的令牌),改用手工拆 base/slice(同 VPC
|
||
TypeGenResolve._parse_type_string 的数字开头手工拆分分支)。
|
||
尾部 '*'(泛型实参 '<sha1>.Node*' / '<sha1>.Node**',来自 rawptr[T] /
|
||
CPtr 的逐层 mangling)逐层还原为嵌套 `CPtr[...]` → 对应
|
||
层数指针;只剥一层会把 'Node*' 当结构体名建出 phantom opaque
|
||
(item 类型与特化名 '<sha1>.Node**' 的语义不一致)。
|
||
尾部 'ptr'(旧规则 mangling,如 'Nodeptr' / 'ast.ASTptr')保留兼容:
|
||
.vpi/stub 缓存里仍是旧名时按同样方式还原。
|
||
"""
|
||
StarCount: int = len(replacement) - len(replacement.rstrip('*'))
|
||
if StarCount > 0:
|
||
BaseName: str = replacement[:len(replacement) - StarCount]
|
||
base_node: ast.AST
|
||
if BaseName in ('i8', 'void', 'void*'):
|
||
# i8*(void*)在源码侧写作 CPtr;再叠加 StarCount-1 层
|
||
base_node = ast.Name(id='CPtr', ctx=ast.Load())
|
||
StarCount -= 1
|
||
else:
|
||
base_node = self._make_name_node(BaseName)
|
||
node: ast.AST = base_node
|
||
for _ in range(StarCount):
|
||
node = ast.Subscript(
|
||
value=ast.Name(id='CPtr', ctx=ast.Load()),
|
||
slice=node,
|
||
ctx=ast.Load(),
|
||
)
|
||
return node
|
||
if replacement.endswith('ptr'):
|
||
# 提取基础名称:'sha1.ASTptr' → 'sha1.AST';'Nodeptrptr' → 'Node'(2 层)
|
||
base: str = replacement
|
||
levels: int = 0
|
||
while base.endswith('ptr') and len(base) > 3:
|
||
base = base[:-3]
|
||
levels += 1
|
||
node: ast.AST = self._make_name_node(base)
|
||
for _ in range(levels):
|
||
node = ast.Subscript(
|
||
value=ast.Name(id='CPtr', ctx=ast.Load()),
|
||
slice=node,
|
||
ctx=ast.Load(),
|
||
)
|
||
return node
|
||
if '[' in replacement:
|
||
SubNode: ast.AST | None = None
|
||
try:
|
||
SubNode = ast.parse(replacement, '<stub:type_expr>', mode='eval').body
|
||
except Exception:
|
||
SubNode = None
|
||
if not isinstance(SubNode, ast.Subscript):
|
||
SubNode = self._parse_subscript_manually(replacement)
|
||
if isinstance(SubNode, ast.Subscript):
|
||
return SubNode
|
||
return self._make_name_node(replacement)
|
||
|
||
def _parse_subscript_manually(self, replacement: str) -> ast.AST | None:
|
||
"""手工拆分单实参下标字符串(ast.parse 因数字开头标识符失败时使用)。
|
||
|
||
处理 `<base>[<inner>]`(整体以 ']' 结尾、单实参、无逗号;内层可为嵌套
|
||
单实参下标):'rawptr[7565e081d88517ac.AST]' → Subscript(Name('rawptr'),
|
||
Attribute(Name('7565e081d88517ac'), 'AST'));
|
||
'rawptr[rawptr[7565e081d88517ac.AST]]' → 外层 Subscript 的 slice 递归
|
||
拆出内层 Subscript(嵌套 rawptr 需两层指针)。带逗号等复杂形态返回
|
||
None(交调用方按普通名称处理),不做字符串猜测。
|
||
"""
|
||
open_idx: int = replacement.find('[')
|
||
if open_idx <= 0 or not replacement.endswith(']'):
|
||
return None
|
||
inner: str = replacement[open_idx + 1:-1]
|
||
if not inner or ',' in inner:
|
||
return None
|
||
base_name: str = replacement[:open_idx].strip()
|
||
inner_name: str = inner.strip()
|
||
if not base_name or not inner_name:
|
||
return None
|
||
slice_node: ast.AST | None
|
||
if '[' in inner_name or inner_name.endswith('*'):
|
||
# 嵌套单实参下标 / 指针层数内层(如 rawptr[rawptr[<sha1>.CLS]]、
|
||
# <sha1>.list[<sha1>.X*]):递归按同一还原规则拆解
|
||
slice_node = self._make_replacement_node(inner_name)
|
||
else:
|
||
try:
|
||
slice_node = ast.parse(inner_name, '<stub:type_expr>', mode='eval').body
|
||
except Exception:
|
||
slice_node = self._make_name_node(inner_name)
|
||
if slice_node is None:
|
||
return None
|
||
return ast.Subscript(
|
||
value=self._make_name_node(base_name), slice=slice_node, ctx=ast.Load())
|
||
|
||
@staticmethod
|
||
def _make_name_node(name: str) -> ast.AST:
|
||
"""将可能含点号的名称转换为 ast.Name 或 ast.Attribute 链。
|
||
'AST' -> ast.Name(id='AST')
|
||
'sha1.AST' -> ast.Attribute(value=ast.Name(id='sha1'), attr='AST')
|
||
"""
|
||
if '.' not in name:
|
||
return ast.Name(id=name, ctx=ast.Load())
|
||
parts: list[str] = name.split('.')
|
||
node: ast.AST = ast.Name(id=parts[0], ctx=ast.Load())
|
||
for part in parts[1:]:
|
||
node = ast.Attribute(value=node, attr=part, ctx=ast.Load())
|
||
return node
|
||
|
||
def _apply_type_map_to_body(self, body: list[ast.AST], type_map: dict[str, str], cptr_params: set[str] | None = None) -> None:
|
||
for stmt in body:
|
||
self._apply_type_map_to_stmt(stmt, type_map, cptr_params)
|
||
|
||
def _apply_type_map_to_stmt(self, node: ast.AST, type_map: dict[str, str], cptr_params: set[str] | None = None) -> None:
|
||
if isinstance(node, ast.Return) and node.value:
|
||
self._apply_type_map_to_expr(node.value, type_map, cptr_params)
|
||
elif isinstance(node, ast.Assign):
|
||
for t in node.targets:
|
||
self._apply_type_map_to_expr(t, type_map, cptr_params)
|
||
self._apply_type_map_to_expr(node.value, type_map, cptr_params)
|
||
elif isinstance(node, ast.AnnAssign):
|
||
if node.annotation:
|
||
node.annotation = self._replace_type_in_annotation(node.annotation, type_map, cptr_params)
|
||
if node.value:
|
||
self._apply_type_map_to_expr(node.value, type_map, cptr_params)
|
||
elif isinstance(node, ast.AugAssign):
|
||
self._apply_type_map_to_expr(node.target, type_map, cptr_params)
|
||
self._apply_type_map_to_expr(node.value, type_map, cptr_params)
|
||
elif isinstance(node, ast.Expr):
|
||
self._apply_type_map_to_expr(node.value, type_map, cptr_params)
|
||
elif isinstance(node, ast.If):
|
||
self._apply_type_map_to_expr(node.test, type_map, cptr_params)
|
||
for s in node.body:
|
||
self._apply_type_map_to_stmt(s, type_map, cptr_params)
|
||
for s in node.orelse:
|
||
self._apply_type_map_to_stmt(s, type_map, cptr_params)
|
||
elif isinstance(node, ast.For):
|
||
self._apply_type_map_to_expr(node.iter, type_map, cptr_params)
|
||
for s in node.body:
|
||
self._apply_type_map_to_stmt(s, type_map, cptr_params)
|
||
for s in node.orelse:
|
||
self._apply_type_map_to_stmt(s, type_map, cptr_params)
|
||
elif isinstance(node, ast.While):
|
||
self._apply_type_map_to_expr(node.test, type_map, cptr_params)
|
||
for s in node.body:
|
||
self._apply_type_map_to_stmt(s, type_map, cptr_params)
|
||
for s in node.orelse:
|
||
self._apply_type_map_to_stmt(s, type_map, cptr_params)
|
||
elif isinstance(node, ast.Try):
|
||
for s in node.body:
|
||
self._apply_type_map_to_stmt(s, type_map, cptr_params)
|
||
for handler in node.handlers:
|
||
for s in handler.body:
|
||
self._apply_type_map_to_stmt(s, type_map, cptr_params)
|
||
for s in node.orelse:
|
||
self._apply_type_map_to_stmt(s, type_map, cptr_params)
|
||
for s in node.finalbody:
|
||
self._apply_type_map_to_stmt(s, type_map, cptr_params)
|
||
elif isinstance(node, ast.With):
|
||
for item in node.items:
|
||
self._apply_type_map_to_expr(item.context_expr, type_map, cptr_params)
|
||
if item.optional_vars:
|
||
self._apply_type_map_to_expr(item.optional_vars, type_map, cptr_params)
|
||
for s in node.body:
|
||
self._apply_type_map_to_stmt(s, type_map, cptr_params)
|
||
elif isinstance(node, ast.Raise):
|
||
if node.exc:
|
||
self._apply_type_map_to_expr(node.exc, type_map, cptr_params)
|
||
if node.cause:
|
||
self._apply_type_map_to_expr(node.cause, type_map, cptr_params)
|
||
elif isinstance(node, ast.Assert):
|
||
self._apply_type_map_to_expr(node.test, type_map, cptr_params)
|
||
if node.msg:
|
||
self._apply_type_map_to_expr(node.msg, type_map, cptr_params)
|
||
|
||
def _apply_type_map_to_expr(self, node: ast.AST | None, type_map: dict[str, str], cptr_params: set[str] | None = None) -> None:
|
||
if node is None:
|
||
return
|
||
if isinstance(node, ast.Call):
|
||
if isinstance(node.func, ast.Name) and node.func.id in type_map:
|
||
replacement: str = type_map[node.func.id]
|
||
# 使用 _make_replacement_node 处理含点号的类型名(如 'CUnsignedChar'),
|
||
# 避免 T(0) 替换为 CUnsignedChar(0) 后因 CUnsignedChar 不在顶层作用域
|
||
# 而报 "Undefined function: 'CUnsignedChar'"
|
||
node.func = self._make_replacement_node(replacement)
|
||
elif isinstance(node.func, ast.Attribute):
|
||
if isinstance(node.func.value, ast.Name) and node.func.value.id in type_map:
|
||
replacement: str = type_map[node.func.value.id]
|
||
# 指针类型参数(如 list[CPtr[AST]] 中的 T):表达式里 T 的唯一
|
||
# 用法是 `T.__sizeof__()`,指针大小恒为 8。替换成**裸 CPtr**
|
||
# (而不是 CPtr[<mangled 串>]):mangled 串含 '.'/'*',既不是
|
||
# 合法 Name,也会让 __sizeof__ 的 Subscript 分支(只认泛型切片)
|
||
# 落空后把 CPtr 当变量求值 → "未定义名称: 'CPtr'"。
|
||
if cptr_params and node.func.value.id in cptr_params:
|
||
node.func.value = ast.Name(id='CPtr', ctx=ast.Load())
|
||
else:
|
||
node.func.value = self._make_name_node(replacement)
|
||
else:
|
||
self._apply_type_map_to_expr(node.func.value, type_map, cptr_params)
|
||
elif isinstance(node.func, ast.Subscript):
|
||
# `T*(expr)` / `list[T](...)`:被调者/转换目标的切片也要替换。
|
||
self._apply_type_map_to_expr(node.func, type_map, cptr_params)
|
||
for arg in node.args:
|
||
self._apply_type_map_to_expr(arg, type_map, cptr_params)
|
||
elif isinstance(node, ast.Attribute):
|
||
if isinstance(node.value, ast.Name) and node.value.id in type_map:
|
||
replacement: str = type_map[node.value.id]
|
||
if cptr_params and node.value.id in cptr_params:
|
||
# 同上:指针类型参数的表达式用法(T.__sizeof__ 等)只需
|
||
# "指针语义",裸 CPtr 即指针大小 8;不要拼 mangled 串。
|
||
node.value = ast.Name(id='CPtr', ctx=ast.Load())
|
||
else:
|
||
node.value = ast.Name(id=replacement, ctx=ast.Load())
|
||
else:
|
||
self._apply_type_map_to_expr(node.value, type_map, cptr_params)
|
||
elif isinstance(node, ast.BinOp):
|
||
self._apply_type_map_to_expr(node.left, type_map, cptr_params)
|
||
self._apply_type_map_to_expr(node.right, type_map, cptr_params)
|
||
elif isinstance(node, ast.UnaryOp):
|
||
self._apply_type_map_to_expr(node.operand, type_map, cptr_params)
|
||
elif isinstance(node, ast.Compare):
|
||
self._apply_type_map_to_expr(node.left, type_map, cptr_params)
|
||
for comp in node.comparators:
|
||
self._apply_type_map_to_expr(comp, type_map, cptr_params)
|
||
elif isinstance(node, ast.BoolOp):
|
||
for val in node.values:
|
||
self._apply_type_map_to_expr(val, type_map, cptr_params)
|
||
elif isinstance(node, ast.IfExp):
|
||
self._apply_type_map_to_expr(node.test, type_map, cptr_params)
|
||
self._apply_type_map_to_expr(node.body, type_map, cptr_params)
|
||
self._apply_type_map_to_expr(node.orelse, type_map, cptr_params)
|
||
elif isinstance(node, ast.Subscript):
|
||
self._apply_type_map_to_expr(node.value, type_map, cptr_params)
|
||
# `T*(expr)` 的指针转换在 AST 里是 Call(func=Subscript(CPtr, T)):
|
||
# 切片上的 T 必须整体替换成 `_make_replacement_node` 的产物(如
|
||
# CPtr[<sha1>.AST]),不能走 Name 分支直接改 id(mangled 串含 '.'/'*'
|
||
# 不是合法标识符),否则会留下裸 T → 生成幻影结构体 %"<sha1>.T"。
|
||
if isinstance(node.slice, ast.Name) and node.slice.id in type_map:
|
||
node.slice = self._make_replacement_node(type_map[node.slice.id])
|
||
else:
|
||
self._apply_type_map_to_expr(node.slice, type_map, cptr_params)
|
||
elif isinstance(node, ast.Name):
|
||
if node.id in type_map:
|
||
node.id = type_map[node.id]
|
||
|
||
def _infer_type_arg_from_value(self, val: ir.Value, Gen: LlvmCodeGenerator) -> str:
|
||
if val is None:
|
||
return 'int'
|
||
if isinstance(val.type, ir.IntType):
|
||
if val.type.width == 64:
|
||
return 'i64'
|
||
elif val.type.width == 16:
|
||
return 'i16'
|
||
elif val.type.width == 8:
|
||
return 'i8'
|
||
return 'int'
|
||
elif isinstance(val.type, ir.DoubleType):
|
||
return 'double'
|
||
elif isinstance(val.type, ir.FloatType):
|
||
return 'float'
|
||
elif isinstance(val.type, ir.PointerType):
|
||
return 'void*'
|
||
return 'int'
|
||
|
||
def _specialize_generic_function(self, FuncName: str, type_args: list[str], Gen: LlvmCodeGenerator) -> str | None:
|
||
if not hasattr(self, '_generic_templates') or FuncName not in self._generic_templates:
|
||
return None
|
||
template: dict[str, Any] = self._generic_templates[FuncName]
|
||
Node: ast.FunctionDef = template['node']
|
||
type_param_names: list[str] = template['type_params']
|
||
ClassName: str | None = template['class_name']
|
||
if len(type_args) != len(type_param_names):
|
||
return None
|
||
spec_key: str = FuncName + '<' + ','.join(type_args) + '>'
|
||
if not hasattr(self, '_generic_specializations'):
|
||
self._generic_specializations = {}
|
||
if spec_key in self._generic_specializations:
|
||
return self._generic_specializations[spec_key]
|
||
has_cexport: bool = False
|
||
if Node.returns:
|
||
try:
|
||
RetTypeInfo: Any = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable)
|
||
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, TypeSystem.CExport):
|
||
has_cexport = True
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
spec_name: str = self._mangle_generic_name(FuncName, type_args, has_cexport)
|
||
type_map: dict[str, str] = {}
|
||
for i, tp_name in enumerate(type_param_names):
|
||
type_map[tp_name] = type_args[i]
|
||
SpecNode: ast.FunctionDef = copy.deepcopy(Node)
|
||
SpecNode.type_params = []
|
||
SpecNode.name = spec_name
|
||
self._apply_type_map_to_node(SpecNode, type_map)
|
||
if has_cexport:
|
||
if not hasattr(Gen, '_export_funcs'):
|
||
Gen._export_funcs = set()
|
||
Gen._export_funcs.add(spec_name)
|
||
saved_builder: Any = Gen.builder
|
||
saved_variables: dict[str, Any] = dict(Gen.variables) if Gen.variables else {}
|
||
saved_direct_values: dict[str, Any] = dict(Gen._direct_values) if Gen._direct_values else {}
|
||
saved_var_type_info: dict[str, Any] = dict(Gen.var_type_info) if Gen.var_type_info else {}
|
||
saved_var_signedness: dict[str, Any] = dict(Gen.var_signedness) if Gen.var_signedness else {}
|
||
saved_global_vars: set[str] = set(Gen.global_vars) if Gen.global_vars else set()
|
||
saved_var_scopes: list[dict[str, Any]] = [dict(s) for s in self.Trans.VarScopes] if self.Trans.VarScopes else []
|
||
saved_func: Any = Gen.func
|
||
saved_current_func_name: str | None = getattr(Gen, '_current_func_name', None)
|
||
saved_block: Any = None
|
||
if Gen.builder and Gen.builder.block and not Gen.builder.block.is_terminated:
|
||
saved_block = Gen.builder.block
|
||
self._EmitFunctionForwardDeclLlvm(SpecNode, Gen, ClassName=ClassName)
|
||
self._EmitFunctionLlvm(SpecNode, Gen, ClassName=ClassName)
|
||
Gen.builder = saved_builder
|
||
if saved_block is not None and Gen.builder is not None:
|
||
Gen.builder.position_at_end(saved_block)
|
||
Gen.variables = saved_variables
|
||
Gen._direct_values = saved_direct_values
|
||
Gen.var_type_info = saved_var_type_info
|
||
Gen.var_signedness = saved_var_signedness
|
||
Gen.global_vars = saved_global_vars
|
||
Gen.func = saved_func
|
||
if saved_current_func_name is not None:
|
||
Gen._current_func_name = saved_current_func_name
|
||
self.Trans.VarScopes = saved_var_scopes
|
||
self._generic_specializations[spec_key] = spec_name
|
||
if not hasattr(self.Trans, '_generic_specializations'):
|
||
self.Trans._generic_specializations = {}
|
||
self.Trans._generic_specializations[spec_key] = spec_name
|
||
return spec_name
|
||
|
||
def _EmitFunctionForwardDeclLlvm(self, Node: ast.FunctionDef, Gen: LlvmCodeGenerator, ClassName: str | None = None) -> None:
|
||
if self._is_generic_function(Node):
|
||
if not hasattr(self, '_generic_templates'):
|
||
self._generic_templates = {}
|
||
RawFuncName: str = Node.name
|
||
if ClassName:
|
||
FuncName: str = f"{ClassName}.{RawFuncName}"
|
||
else:
|
||
FuncName = RawFuncName
|
||
type_params: list[str] = [tp.name for tp in Node.type_params]
|
||
self._generic_templates[FuncName] = {
|
||
'node': Node,
|
||
'type_params': type_params,
|
||
'class_name': ClassName,
|
||
}
|
||
return
|
||
result: Any = self._GetFunctionSignatureLlvm(Node, Gen, ClassName)
|
||
if result is None:
|
||
return
|
||
FuncName: str
|
||
FuncType: ir.FunctionType
|
||
ReturnTypeInfo: Any
|
||
ParamTypeStrs: list[Any]
|
||
MultiRetTypes: list[ast.AST]
|
||
IsMethod: bool
|
||
ResolvedClassName: str | None
|
||
IsVariadic: bool
|
||
FuncName, FuncType, ReturnTypeInfo, ParamTypeStrs, MultiRetTypes, IsMethod, ResolvedClassName, IsVariadic = result
|
||
IsUserMarkedExport: bool = False
|
||
if Node.returns:
|
||
try:
|
||
RetTypeInfo: Any = None
|
||
RetTypeInfo = self.ResolveAnnotationType(Node.returns)
|
||
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, TypeSystem.CExport) and not RetTypeInfo.IsState:
|
||
Gen._export_funcs.add(FuncName)
|
||
IsUserMarkedExport = True
|
||
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, TypeSystem.CExtern):
|
||
Gen._export_funcs.add(FuncName)
|
||
IsUserMarkedExport = True
|
||
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.IsState:
|
||
Gen._export_funcs.add(FuncName) # State 标记的函数必须保持原始名称,以便链接器解析
|
||
IsUserMarkedExport = True
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
# 装饰器形式的存储类标记(@CExport / @CExtern / @State 等)
|
||
deco_flags: dict[str, bool] = self._extract_decorator_storage_flags(Node)
|
||
if deco_flags['is_export'] or deco_flags['is_extern'] or deco_flags['is_state']:
|
||
Gen._export_funcs.add(FuncName)
|
||
IsUserMarkedExport = True
|
||
# 注册当前模块定义的函数名,使 _mangle_func_name 跳过 _export_extern_funcs 检查
|
||
# (_export_extern_funcs 是跨模块共享集合,包含所有 CExtern 函数名;当前模块定义的
|
||
# 同名用户函数应使用 SHA1 前缀,而非被误判为外部 C 函数返回裸名)
|
||
Gen._current_module_func_names.add(FuncName)
|
||
# 移除导入污染:用户函数未显式标记导出,但名称在 _export_funcs 中(来自导入的同名 C 库函数)
|
||
if not IsUserMarkedExport and FuncName in Gen._export_funcs:
|
||
Gen._export_funcs.discard(FuncName)
|
||
MangledName: str = Gen._mangle_func_name(FuncName)
|
||
# 自动取址模式:查表侧统一按**真实发射名**(func.name,即 MangledName)查
|
||
# (FuncGen._adjust_args)。签名阶段(_GetFunctionSignatureLlvm)只能按逻辑名
|
||
# (FuncName)登记,故在此把该逻辑名下的模式复制到真实名下——否则同模块
|
||
# "先调用、后定义"的 &T / &temp T 会在前向声明路径上静默丢失取址。
|
||
_aam_fwd: list[str | None] | None = Gen._auto_addr_params.get(FuncName)
|
||
if _aam_fwd:
|
||
Gen._auto_addr_params[MangledName] = _aam_fwd
|
||
need_new: bool = MangledName not in Gen.functions
|
||
if not need_new:
|
||
existing: Any = Gen.functions[MangledName]
|
||
if getattr(existing, 'name', MangledName) != MangledName:
|
||
need_new = True
|
||
if need_new:
|
||
try:
|
||
# 统一走幂等入口:module.globals 已有同名函数时复用(并补登记
|
||
# Gen.functions),签名冲突则 fail-fast —— 绝不直接新建同名
|
||
# ir.Function(llvmlite NameScope 按名去重,必抛 DuplicatedNameError;
|
||
# 现场:5d84ea579d83ef73.CallGenFd._translate_fakeduck_call 被此路径新建,
|
||
# 而 BaseGen._get_or_declare_function 已建过同名声明却未登记
|
||
# Gen.functions ⇒ need_new 误判为真)。
|
||
func: ir.Function = Gen._CreateOrReuseFuncDecl(MangledName, FuncType)
|
||
func.attributes.add('noredzone')
|
||
if hasattr(self, '_cdefine_funcs') and FuncName in self._cdefine_funcs:
|
||
func.linkage = 'linkonce_odr'
|
||
func.attributes.add('alwaysinline')
|
||
if hasattr(self, '_pending_llvm_attrs') and FuncName in self._pending_llvm_attrs:
|
||
for attr_name in self._pending_llvm_attrs[FuncName]:
|
||
try:
|
||
func.attributes.add(attr_name)
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
raise
|
||
_vlog().warning(f"添加函数属性失败: {_e}", "Exception")
|
||
Gen.functions[MangledName] = func
|
||
if MangledName == FuncName or FuncName not in Gen._export_extern_funcs:
|
||
Gen.functions[FuncName] = func
|
||
except Exception as _e:
|
||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||
if isinstance(_e, FailFastError):
|
||
# 签名冲突 = declare/define 分裂,必须终止(不吞)
|
||
raise
|
||
# 其余异常同样必须终止:本 try 块内只有「创建/复用声明 + 挂属性」,
|
||
# 失败即该声明不可用(调用点会按错签名传参)。原实现非严格模式静默
|
||
# `pass`、严格模式仅 LogWarning —— 正是它把 llvmlite 的 AssertionError
|
||
# (形参类型不是 types.Type 时 `Argument(...)` 断言失败,见
|
||
# BaseGen._CreateOrReuseFuncDecl 的创建前自检注释)吞成"名字半注册":
|
||
# 名字已进 module.scope、未进 module.globals,直到定义阶段才以
|
||
# DuplicatedNameError(报文只有名字)暴露,真因与现场彻底脱节。
|
||
raise FailFastError(
|
||
f"函数前置声明创建失败:'{MangledName}'"
|
||
f"\n · 本次签名: {FuncType}"
|
||
f"\n · 原始异常: {type(_e).__name__}: {_e}"
|
||
+ Gen._get_node_info())
|
||
else:
|
||
existing = Gen.functions[MangledName]
|
||
existing_type: ir.FunctionType | None = getattr(existing, 'ftype', None)
|
||
if existing_type and existing_type != FuncType:
|
||
Gen.functions[MangledName] = self._replace_function_decl(Gen, FuncName, FuncType)
|
||
if MangledName == FuncName or FuncName not in Gen._export_extern_funcs:
|
||
Gen.functions[FuncName] = Gen.functions[MangledName]
|
||
elif not existing_type:
|
||
try:
|
||
Gen.functions[MangledName] = self._replace_function_decl(Gen, FuncName, FuncType)
|
||
if MangledName == FuncName or FuncName not in Gen._export_extern_funcs:
|
||
Gen.functions[FuncName] = Gen.functions[MangledName]
|
||
except Exception as _e:
|
||
# fail-fast 一律上抛(本仓既定口径):吞掉它 = 声明静默缺失 +
|
||
# 半注册名字留给下一轮,真因与现场脱节。
|
||
from lib.core.LLVMCG.FuncGen import FailFastError as _FFE
|
||
if isinstance(_e, _FFE):
|
||
raise
|
||
if _config_mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
self.Trans.FunctionDefCache[FuncName] = Node
|
||
|
||
def _replace_function_decl(self, Gen: LlvmCodeGenerator, FuncName: str, NewFuncType: ir.FunctionType) -> ir.Function:
|
||
MangledName: str = Gen._mangle_func_name(FuncName)
|
||
old_func: Any = Gen.functions.get(MangledName)
|
||
if old_func is None:
|
||
try:
|
||
# 走唯一幂等入口:名字可能已存在于 module.globals 但未登记进 Gen.functions
|
||
# (别的路径先建过声明)——直接 ir.Function 必抛裸 DuplicatedNameError,
|
||
# 入口则同名同类型复用、异类型带两侧签名 fail-fast。
|
||
return Gen._CreateOrReuseFuncDecl(MangledName, NewFuncType)
|
||
except Exception as _e: # 回退:函数已存在时返回旧函数
|
||
from lib.core.LLVMCG.FuncGen import FailFastError as _FFE
|
||
if isinstance(_e, _FFE):
|
||
# 创建中途失败(如形参/返回类型不是 llvmlite Type)由 BaseGen 的
|
||
# Function 守卫转成 fail-fast:必须上抛,原实现会 `return old_func`
|
||
# (此处 old_func 必为 None)⇒ 调用点把 None 当声明用。
|
||
raise
|
||
return old_func
|
||
try:
|
||
old_name: str = old_func.name
|
||
# 必须同时清 old_name(对象真名)与 MangledName(字典键 / 目标名):
|
||
# 别名场景下二者不同,只清真名会让 MangledName 仍占住 module.scope
|
||
# (llvmlite 按名字去重)→ 重建抛 DuplicatedNameError。
|
||
module_scope: Any = getattr(Gen.module, 'scope', None)
|
||
for _stale_name in {old_name, MangledName}:
|
||
_stale: Any = Gen.module.globals.get(_stale_name)
|
||
if isinstance(_stale, ir.Function):
|
||
del Gen.module.globals[_stale_name]
|
||
if getattr(module_scope, '_useset', None):
|
||
module_scope._useset.discard(_stale_name)
|
||
if getattr(Gen.module, '_guessed_names', None):
|
||
Gen.module._guessed_names.discard(FuncName)
|
||
new_func: ir.Function = Gen._CreateOrReuseFuncDecl(MangledName, NewFuncType)
|
||
Gen.functions[MangledName] = new_func
|
||
if MangledName == FuncName or FuncName not in Gen._export_extern_funcs:
|
||
Gen.functions[FuncName] = new_func
|
||
return new_func
|
||
except Exception as ex:
|
||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||
if isinstance(ex, FailFastError):
|
||
# 同名符号冲突(函数签名分裂 / 名字被非函数 global 占住):必须终止,
|
||
# 不能回退成"复用旧声明"——那正是 declare/define 分裂的现场。
|
||
raise
|
||
traceback.print_exc()
|
||
Gen.functions[MangledName] = old_func
|
||
if MangledName == FuncName or FuncName not in Gen._export_extern_funcs:
|
||
Gen.functions[FuncName] = old_func
|
||
return old_func
|
||
|
||
def _EmitFunctionLlvm(self, Node: ast.FunctionDef, Gen: LlvmCodeGenerator, ClassName: str | None = None, extra_params: list[tuple[str, ir.Type]] | None = None) -> ir.Function | None:
|
||
if self._is_generic_function(Node):
|
||
return
|
||
FuncName, RawFuncName, func_meta = self._compute_func_name_meta(Node, ClassName)
|
||
_RejectRefReturnAnnotation(Node)
|
||
# 保存父级 _CurrentCpythonObjectClass,防止嵌套函数发射污染父方法类上下文
|
||
# (例如 HandleImport body 内触发 list[ast.ASTptr] 方法发射,结束后会清空 _CurrentCpythonObjectClass)
|
||
saved_cpython_class: str | None = self.Trans._CurrentCpythonObjectClass
|
||
MultiRetTypes = []
|
||
IsPtr = False
|
||
fn_attrs = {}
|
||
# 自定义行为装饰器列表,用于生成 wrapper 函数
|
||
# 任何 @name 或 @name(args) 只要不是内置装饰器,都视为自定义行为装饰器
|
||
behavior_decorators = []
|
||
# 内置装饰器名称,这些由编译器特殊处理,不作为行为装饰器
|
||
# 另含**编译期生命期标注**(P2):@life(willFree(...)) 与 @willFree(...) 是纯标注,
|
||
# 没有运行时装饰器函数;不排除会生成 wrapper 去调用不存在的 @life/@willFree,
|
||
# 并把被装饰的 extern def(如 stdlib.free)变成本模块 internal 声明(llc 报 linkage 错)。
|
||
_BUILTIN_DECORATORS = {'staticmethod', 'property', 'classmethod', 'life', 'willFree', 'Attribute'}
|
||
_symtab: object = self.Trans.SymbolTable
|
||
if Node.decorator_list:
|
||
for decorator in Node.decorator_list:
|
||
# 跳过内建存储类标记装饰器(@CExport / @CStatic 等)
|
||
if self._is_t_storage_decorator(decorator, _symtab):
|
||
continue
|
||
# 识别自定义行为装饰器:@name(ast.Name 形式)
|
||
if isinstance(decorator, ast.Name):
|
||
if decorator.id not in _BUILTIN_DECORATORS:
|
||
behavior_decorators.append({'name': decorator.id, 'args': [], 'kwargs': {}})
|
||
continue
|
||
# 识别带参数的自定义行为装饰器:@name(arg1, key=val)(ast.Call + ast.Name 形式)
|
||
if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Name):
|
||
deco_name = decorator.func.id
|
||
if deco_name not in _BUILTIN_DECORATORS:
|
||
deco_info = {'name': deco_name, 'args': [], 'kwargs': {}}
|
||
for arg in decorator.args:
|
||
if isinstance(arg, ast.Constant):
|
||
deco_info['args'].append(arg.value)
|
||
for kw in decorator.keywords:
|
||
if isinstance(kw.value, ast.Constant):
|
||
deco_info['kwargs'][kw.arg] = kw.value.value
|
||
behavior_decorators.append(deco_info)
|
||
continue
|
||
if isinstance(decorator, ast.Call):
|
||
if isinstance(decorator.func, ast.Attribute) and decorator.func.attr == 'CReturn':
|
||
_RejectCReturnDecorator(Node, [decorator])
|
||
elif isinstance(decorator.func, ast.Name) and decorator.func.id == 'Attribute':
|
||
for arg in decorator.args:
|
||
if isinstance(arg, ast.Call) and isinstance(arg.func, ast.Attribute):
|
||
if isinstance(arg.func.value, ast.Name) and arg.func.value.id == 'attr':
|
||
attr_name = arg.func.attr
|
||
str_args = [a.value for a in arg.args if isinstance(a, ast.Constant) and isinstance(a.value, str)]
|
||
int_args = [a.value for a in arg.args if isinstance(a, ast.Constant) and isinstance(a.value, int)]
|
||
if attr_name == 'section' and str_args:
|
||
fn_attrs['section'] = str_args[0]
|
||
elif attr_name == 'aligned' and int_args:
|
||
fn_attrs['aligned'] = int_args[0]
|
||
elif attr_name == 'visibility' and str_args:
|
||
fn_attrs['visibility'] = str_args[0]
|
||
elif attr_name in ('noreturn', 'always_inline', 'noinline', 'cold', 'hot', 'constructor', 'destructor', 'pure', 'const', 'malloc', 'returns_nonnull', 'used', 'naked', 'no_instrument_function', 'warn_unused_result', 'weak', 'fallthrough'):
|
||
if not arg.args:
|
||
fn_attrs[attr_name] = True
|
||
elif (isinstance(arg.func.value, ast.Attribute) and arg.func.value.attr == 'llvm'
|
||
and isinstance(arg.func.value.value, ast.Name) and arg.func.value.value.id == 'attr'):
|
||
llvm_attr_name = arg.func.attr
|
||
if llvm_attr_name in self._LLVM_ATTR_NAMES:
|
||
fn_attrs[f'llvm.{llvm_attr_name}'] = True
|
||
elif isinstance(arg, ast.Attribute):
|
||
if isinstance(arg.value, ast.Name) and arg.value.id == 'attr':
|
||
attr_name = arg.attr
|
||
if attr_name in ('noreturn', 'always_inline', 'noinline', 'cold', 'hot', 'constructor', 'destructor', 'pure', 'const', 'malloc', 'returns_nonnull', 'used', 'naked', 'no_instrument_function', 'warn_unused_result', 'weak', 'fallthrough', 'packed'):
|
||
fn_attrs[attr_name] = True
|
||
elif (isinstance(arg.value, ast.Attribute) and arg.value.attr == 'llvm'
|
||
and isinstance(arg.value.value, ast.Name) and arg.value.value.id == 'attr'):
|
||
llvm_attr_name = arg.attr
|
||
if llvm_attr_name in self._LLVM_ATTR_NAMES:
|
||
fn_attrs[f'llvm.{llvm_attr_name}'] = True
|
||
# 检查 @TLS 装饰器(一次性初始化标记)
|
||
is_tls_func: bool = False
|
||
if Node.decorator_list:
|
||
for decorator in Node.decorator_list:
|
||
if isinstance(decorator, ast.Attribute) and isinstance(decorator.value, ast.Name):
|
||
if decorator.attr == 'TLS':
|
||
is_tls_func = True
|
||
break
|
||
elif isinstance(decorator, ast.Name) and decorator.id == 'TLS' and hasattr(TypeSystem, 'TLS'):
|
||
is_tls_func = True
|
||
break
|
||
if Node.returns:
|
||
if isinstance(Node.returns, ast.Subscript) and isinstance(Node.returns.value, ast.Name) and Node.returns.value.id == 'tuple':
|
||
slice_node = Node.returns.slice
|
||
if isinstance(slice_node, ast.Tuple):
|
||
for elt in slice_node.elts:
|
||
MultiRetTypes.append(elt)
|
||
else:
|
||
MultiRetTypes.append(slice_node)
|
||
|
||
# 先强制检查 str 类型注解
|
||
is_str_return = False
|
||
ReturnTypeInfo = None
|
||
if Node.returns:
|
||
if isinstance(Node.returns, ast.Name) and Node.returns.id in ('str', 'bytes'):
|
||
is_str_return = True
|
||
else:
|
||
try:
|
||
rt_info = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable)
|
||
# 仅指针层数 <=1 才算裸 str/bytes(i8*)。
|
||
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,
|
||
# 不能压平,否则返回类型错误。
|
||
if rt_info and rt_info.IsStr and rt_info.PtrCount <= 1:
|
||
is_str_return = True
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
|
||
if is_str_return:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = TypeSystem.CChar()
|
||
ReturnTypeInfo.PtrCount = 1
|
||
elif Node.returns:
|
||
if MultiRetTypes:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = TypeSystem.CVoid()
|
||
else:
|
||
try:
|
||
if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr):
|
||
Line: int = getattr(Node.returns, 'lineno', 0) or 0
|
||
raise TypeError(
|
||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||
else:
|
||
is_str_type = False
|
||
if isinstance(Node.returns, ast.Name) and Node.returns.id in ('str', 'bytes'):
|
||
is_str_type = True
|
||
# 与 _GetFunctionSignatureLlvm 同口径:指针下标返回注解
|
||
# (rawptr[T] / CPtr[T])走 ResolveAnnotationType 的
|
||
# TypeMerge 通用解析,避免内层跨模块类退化为 i8*。
|
||
ReturnTypeInfo = self.ResolveAnnotationType(Node.returns)
|
||
if ReturnTypeInfo and ReturnTypeInfo.IsDefine:
|
||
inferred = self._infer_return_type_from_body(Node, Gen, ClassName)
|
||
if inferred:
|
||
ReturnTypeInfo = CTypeInfo.FromTypeName(inferred[0])
|
||
ReturnTypeInfo.PtrCount = 1 if inferred[1] else 0
|
||
else:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = TypeSystem.CInt()
|
||
if not hasattr(self, '_cdefine_funcs'):
|
||
self._cdefine_funcs = set()
|
||
self._cdefine_funcs.add(FuncName)
|
||
elif ReturnTypeInfo and ReturnTypeInfo.IsState:
|
||
pass # State is a modifier, preserve the actual return type
|
||
if ReturnTypeInfo is None:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = TypeSystem.CVoid()
|
||
# 仅指针层数 <=1 才算裸 str/bytes(i8*)。
|
||
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,不能压平。
|
||
if is_str_type or (ReturnTypeInfo.IsStr and ReturnTypeInfo.PtrCount <= 1):
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = TypeSystem.CChar()
|
||
ReturnTypeInfo.PtrCount = 1
|
||
# 检查泛型类返回类型 (如 list[str])
|
||
# 注意:_from_node_subscript 对未识别的泛型下标(如 list[str])返回空 CTypeInfo(BaseType=None),
|
||
# 此时 IsVoid 为 False(因为 IsVoid 仅检查 CVoid 实例),需额外检测 BaseType is None
|
||
if (isinstance(Node.returns, ast.Subscript)
|
||
and isinstance(Node.returns.value, ast.Name)
|
||
and hasattr(self.Trans.ClassHandler, '_generic_class_templates')
|
||
and Node.returns.value.id in self.Trans.ClassHandler._generic_class_templates
|
||
and (ReturnTypeInfo.IsVoid or ReturnTypeInfo.BaseType is None) and ReturnTypeInfo.PtrCount == 0):
|
||
ret_class: str = Node.returns.value.id
|
||
ret_slice: ast.AST = Node.returns.slice
|
||
ret_type_args: list[str] = []
|
||
ret_type_names: list[str] = []
|
||
if isinstance(ret_slice, ast.Tuple):
|
||
for elt in ret_slice.elts:
|
||
if isinstance(elt, ast.Name):
|
||
tn2: str = elt.id
|
||
ts2: str = tn2
|
||
if tn2 == 'int':
|
||
ts2, tn2 = 'int', 'CInt'
|
||
ret_type_args.append(ts2)
|
||
ret_type_names.append(tn2)
|
||
elif isinstance(ret_slice, ast.Name):
|
||
tn2: str = ret_slice.id
|
||
ts2: str = tn2
|
||
if tn2 == 'int':
|
||
ts2, tn2 = 'int', 'CInt'
|
||
ret_type_args.append(ts2)
|
||
ret_type_names.append(tn2)
|
||
# 返回类型解析只需 struct 定义,不需方法体;使用 declare_only=True
|
||
# 避免过早触发完整特化(此时 MemManager.alloc 可能尚未注册,
|
||
# 导致 __new__ 的 pool.alloc(48) 解析失败,IR 块未终止)。
|
||
try:
|
||
spec_name2: str | None = self.Trans.ClassHandler._specialize_generic_class(
|
||
ret_class, ret_type_args, Gen, type_names=ret_type_names, declare_only=True)
|
||
except Exception as _spec_err:
|
||
# 不静默吞特化异常:记录到 Gen._generic_spec_error 后再
|
||
# 交给外层返回类型回退(否则只剩一个错误的 CInt 返回类型)。
|
||
Gen._generic_spec_error = f'{type(_spec_err).__name__}: {_spec_err}'
|
||
raise
|
||
if spec_name2 and spec_name2 in Gen.structs:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = TypeSystem.CStruct(name=spec_name2)
|
||
ReturnTypeInfo.PtrCount = 1
|
||
if (ReturnTypeInfo.IsVoid or ReturnTypeInfo.BaseType is None) and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = TypeSystem.CInt()
|
||
except TypeError:
|
||
raise
|
||
except Exception: # 回退:设置默认返回类型为 CInt
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = TypeSystem.CInt()
|
||
else:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = TypeSystem.CInt()
|
||
inferred = self._infer_return_type_from_body(Node, Gen, ClassName)
|
||
if inferred:
|
||
ReturnTypeInfo = CTypeInfo.FromTypeName(inferred[0])
|
||
ReturnTypeInfo.PtrCount = 1 if inferred[1] else 0
|
||
|
||
ReturnType = Gen._ctype_to_llvm(ReturnTypeInfo)
|
||
|
||
if isinstance(ReturnType, ir.VoidType) and FuncName == 'main':
|
||
ReturnType = ir.IntType(32)
|
||
IsMethod, IsClassMethod, ResolvedClassName = self._resolve_method_class(Node, ClassName, func_meta, FuncName, Gen)
|
||
# __new__ methods should return a pointer to the struct (for heap allocation replacement)
|
||
if RawFuncName == '__new__' and ResolvedClassName:
|
||
StructType = Gen.structs.get(ResolvedClassName)
|
||
if StructType:
|
||
if isinstance(StructType, ir.PointerType):
|
||
ReturnType = StructType
|
||
else:
|
||
ReturnType = ir.PointerType(StructType)
|
||
ParamTypes = []
|
||
ParamNames = []
|
||
ParamTypeStrs = []
|
||
auto_addr_modes_emit: list[str | None] = []
|
||
self.Trans.VarScopes.append({})
|
||
for Arg in Node.args.args:
|
||
ParamIsUnsigned = False
|
||
if Arg.annotation:
|
||
try:
|
||
ParamTypeInfo = self.ResolveParamAnnotation(Arg.annotation)
|
||
if ParamTypeInfo is None:
|
||
ParamTypeInfo = CTypeInfo()
|
||
ParamTypeInfo.BaseType = TypeSystem.CInt()
|
||
IsPtr = ParamTypeInfo.IsPtr
|
||
if ParamTypeInfo and getattr(ParamTypeInfo, 'IsCpythonObject', False) and not IsPtr:
|
||
IsPtr = True
|
||
ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1)
|
||
# 仅当指针层数 <=1 时才压平为 i8*(裸 str/bytes)。
|
||
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,
|
||
# 不能压平,否则形参类型错误导致 _adjust_args 多 load 一层崩溃。
|
||
if (ParamTypeInfo.IsStr and ParamTypeInfo.PtrCount <= 1) or (isinstance(Arg.annotation, ast.Name) and Arg.annotation.id in ('str', 'bytes')):
|
||
ParamTypeInfo = CTypeInfo()
|
||
ParamTypeInfo.BaseType = TypeSystem.CChar()
|
||
ParamTypeInfo.PtrCount = 1
|
||
IsPtr = True
|
||
# C 语言中数组参数退化为指针:CArray[type, N] → type*
|
||
if ParamTypeInfo.ArrayDims:
|
||
ParamTypeInfo.ArrayDims = []
|
||
ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1)
|
||
ParamType = Gen._ctype_to_llvm(ParamTypeInfo)
|
||
# 参数类型不能是 VoidType:C 语言不允许 void 参数,
|
||
# VoidType 说明类型注解无法识别(如跨模块 ast.expr),直接报错终止
|
||
if isinstance(ParamType, ir.VoidType):
|
||
AnnStr: str = ast.unparse(Arg.annotation) if hasattr(ast, 'unparse') else str(Arg.annotation)
|
||
raise SyntaxError(
|
||
f"无法识别的参数类型注解: '{AnnStr}'(在函数 '{Node.name}' 的参数 '{Arg.arg}' 上)。"
|
||
f"请使用有效的 VPC 类型(如 CPtr、ast.AST 或已注册的结构体)。"
|
||
)
|
||
if ParamTypeInfo and ParamTypeInfo.IsFuncPtr:
|
||
ParamType = ir.IntType(8).as_pointer()
|
||
ParamIsUnsigned = ParamTypeInfo.IsUInt
|
||
except SyntaxError:
|
||
raise
|
||
except Exception: # 回退:参数类型解析失败时使用默认 i32
|
||
ParamType = ir.IntType(32)
|
||
ParamTypeInfo = CTypeInfo()
|
||
ParamTypeInfo.BaseType = TypeSystem.CInt()
|
||
else:
|
||
ParamType = ir.IntType(32)
|
||
ParamTypeInfo = CTypeInfo()
|
||
ParamTypeInfo.BaseType = TypeSystem.CInt()
|
||
ParamTypes.append(ParamType)
|
||
ParamNames.append(Arg.arg)
|
||
ParamTypeStrs.append(ParamTypeInfo)
|
||
# 自动取址模式(由注解读出):'ref' = &T、'temp' = &temp T、'always' = CAutoPtr
|
||
auto_mode_emit: str | None = FindAutoAddrMode(Arg.annotation)
|
||
auto_addr_modes_emit.append(auto_mode_emit)
|
||
Gen._record_var_signedness(Arg.arg, ParamIsUnsigned)
|
||
self.Trans.VarScopes[-1][Arg.arg] = ParamTypeInfo
|
||
if Arg.annotation:
|
||
try:
|
||
PInfo = self.ResolveAnnotationType(Arg.annotation)
|
||
# const/volatile 形参登记(统一登记入口)。const 判据沿用形参历史
|
||
# 条件(IsParam=True,见 BaseGen.RegisterVarQualifiers 说明);
|
||
# volatile / pointee-volatile 与 ViperC 侧同口径。
|
||
Gen.RegisterVarQualifiers(Arg.arg, PInfo, Arg.annotation, IsParam=True)
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
if MultiRetTypes:
|
||
MultiRetLlvmTypes = []
|
||
for i, ReturnTypeNode in enumerate(MultiRetTypes):
|
||
ReturnTypeInfo = CTypeInfo.FromNode(ReturnTypeNode, self.Trans.SymbolTable)
|
||
# 仅指针层数 <=1 才算裸 str/bytes(i8*)。
|
||
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,不能压平。
|
||
if ReturnTypeInfo and ReturnTypeInfo.IsStr and ReturnTypeInfo.PtrCount <= 1:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = TypeSystem.CChar()
|
||
ReturnTypeInfo.PtrCount = 1
|
||
if ReturnTypeInfo is None:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = TypeSystem.CInt()
|
||
RetType = Gen._ctype_to_llvm(ReturnTypeInfo)
|
||
MultiRetLlvmTypes.append(RetType)
|
||
ReturnType = ir.LiteralStructType(MultiRetLlvmTypes)
|
||
self.Trans.CurrentMultiRetTypes = MultiRetTypes
|
||
else:
|
||
self.Trans.CurrentMultiRetTypes = None
|
||
if self._apply_struct_self_cls_types(ParamTypes, ParamNames, IsMethod, IsClassMethod, ResolvedClassName, Gen):
|
||
auto_addr_modes_emit.insert(0, None)
|
||
IsVariadic = Node.args.vararg is not None
|
||
if extra_params:
|
||
for var_name, ptr_type in extra_params:
|
||
ParamTypes.append(ptr_type)
|
||
ParamNames.append(f'__nonlocal_{var_name}__')
|
||
HasStopIterFlag = False
|
||
if IsMethod and RawFuncName == '__next__':
|
||
ParamTypes.append(ir.PointerType(ir.IntType(1)))
|
||
ParamNames.append('__stop_iter_flag__')
|
||
HasStopIterFlag = True
|
||
HasRaise = self._body_contains_raise(Node.body)
|
||
if HasRaise and RawFuncName != 'main':
|
||
ParamTypes.append(ir.PointerType(ir.PointerType(ir.IntType(8))))
|
||
ParamNames.append('__eh_msg_out__')
|
||
ParamTypes.append(ir.PointerType(ir.IntType(32)))
|
||
ParamNames.append('__eh_code_out__')
|
||
FuncType = ir.FunctionType(ReturnType, ParamTypes, var_arg=IsVariadic)
|
||
# 存储 auto_addr_modes(为额外参数补 None)
|
||
total_params_emit: int = len(ParamTypes)
|
||
while len(auto_addr_modes_emit) < total_params_emit:
|
||
auto_addr_modes_emit.append(None)
|
||
# 逻辑名(FuncName = 裸名 / "类名.方法")登记:真身定义路径下它是真实发射名的
|
||
# 别名,保留以便按逻辑名查表;真实发射名(func.name)的登记在下方 func 就绪后
|
||
# 进行(查表侧 FuncGen._adjust_args 统一按 func.name 查)。
|
||
Gen._auto_addr_params[FuncName] = auto_addr_modes_emit
|
||
self.Trans.FunctionDefCache[FuncName] = Node
|
||
IsInlineFunc = False
|
||
IsExternFunc = False
|
||
IsStateFunc = False
|
||
IsUserMarkedExport: bool = False
|
||
if Node.returns:
|
||
try:
|
||
RetTypeInfo = None
|
||
RetTypeInfo = self.ResolveAnnotationType(Node.returns)
|
||
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, TypeSystem.CInline):
|
||
IsInlineFunc = True
|
||
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, TypeSystem.CExport) and not RetTypeInfo.IsState:
|
||
Gen._export_funcs.add(FuncName)
|
||
IsUserMarkedExport = True
|
||
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, TypeSystem.CExtern):
|
||
IsExternFunc = True
|
||
Gen._export_funcs.add(FuncName)
|
||
IsUserMarkedExport = True
|
||
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.IsState:
|
||
IsStateFunc = True
|
||
Gen._export_funcs.add(FuncName) # 外部 C 函数声明必须保持原始名称
|
||
IsUserMarkedExport = True
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
# 装饰器形式的存储类标记(@CExport / @CExtern / @CStatic / @State / @CInline)
|
||
deco_flags: dict[str, bool] = self._extract_decorator_storage_flags(Node)
|
||
if deco_flags['is_inline']:
|
||
IsInlineFunc = True
|
||
if deco_flags['is_extern']:
|
||
IsExternFunc = True
|
||
if deco_flags['is_state']:
|
||
IsStateFunc = True
|
||
if deco_flags['is_export'] or deco_flags['is_extern'] or deco_flags['is_state']:
|
||
Gen._export_funcs.add(FuncName)
|
||
IsUserMarkedExport = True
|
||
# 注册当前模块定义的函数名,使 _mangle_func_name 跳过 _export_extern_funcs 检查
|
||
Gen._current_module_func_names.add(FuncName)
|
||
# 移除导入污染:用户函数未显式标记导出,但名称在 _export_funcs 中(来自导入的同名 C 库函数)
|
||
if not IsUserMarkedExport and FuncName in Gen._export_funcs:
|
||
Gen._export_funcs.discard(FuncName)
|
||
MangledName = Gen._mangle_func_name(FuncName)
|
||
# 补登记:module.globals 已有同名函数(stub 声明 / 调用点先建)但未登记到
|
||
# Gen.functions 时,先登记再走下方判定 —— 否则 1750 分支裸建 ir.Function
|
||
# 会抛 llvmlite DuplicatedNameError(报文只有名字,不含冲突双方)。
|
||
_g_existing_fn: Any = Gen.module.globals.get(MangledName)
|
||
if MangledName not in Gen.functions and isinstance(_g_existing_fn, ir.Function):
|
||
Gen.functions[MangledName] = _g_existing_fn
|
||
if MangledName in Gen.functions:
|
||
func = Gen.functions[MangledName]
|
||
if getattr(func, 'name', MangledName) != MangledName:
|
||
func = Gen._CreateOrReuseFuncDecl(MangledName, FuncType)
|
||
else:
|
||
existing_type = getattr(func, 'ftype', None)
|
||
if existing_type and existing_type != FuncType:
|
||
func = self._replace_function_decl(Gen, FuncName, FuncType)
|
||
else:
|
||
func = Gen._CreateOrReuseFuncDecl(MangledName, FuncType)
|
||
if MangledName == FuncName or FuncName not in Gen._export_extern_funcs:
|
||
Gen.functions[FuncName] = func
|
||
# 自动取址模式(ref/temp/always)的**主键**必须是真实发射出的函数名 func.name,
|
||
# 与查表侧 FuncGen._adjust_args 的 func.name 逐字一致;FuncName(上方已登记)作别名。
|
||
_auto_addr_real_name: str | None = getattr(func, 'name', None)
|
||
if _auto_addr_real_name:
|
||
Gen._auto_addr_params[_auto_addr_real_name] = auto_addr_modes_emit
|
||
func.attributes.add('noredzone')
|
||
# 泛型特化类方法(如 GSList[NameEntry].__before_init__):多个模块各自
|
||
# 特化会生成同名定义(external linkage)→ ld.lld duplicate symbol warning。
|
||
# 特化方法代码由相同模板+类型参数生成,定义相同,设 linkonce_odr 让
|
||
# 链接器合并重复定义(linkonce_odr 的 alwaysinline 不适用,仅改 linkage)。
|
||
is_spec_generic_method: bool = '[' in FuncName
|
||
if IsInlineFunc:
|
||
func.linkage = 'linkonce_odr'
|
||
func.attributes.add('alwaysinline')
|
||
if is_spec_generic_method:
|
||
func.linkage = 'linkonce_odr'
|
||
if hasattr(self, '_cdefine_funcs') and FuncName in self._cdefine_funcs:
|
||
func.linkage = 'linkonce_odr'
|
||
func.attributes.add('alwaysinline')
|
||
if fn_attrs:
|
||
_LLVM_FN_ATTR_MAP = {
|
||
'noreturn': 'noreturn',
|
||
'always_inline': 'alwaysinline',
|
||
'noinline': 'noinline',
|
||
'cold': 'cold',
|
||
'hot': 'hot',
|
||
'constructor': 'constructor',
|
||
'destructor': 'destructor',
|
||
'malloc': 'malloc',
|
||
'returns_nonnull': 'returns_nonnull',
|
||
'used': 'used',
|
||
'naked': 'naked',
|
||
'no_instrument_function': 'no_instrument_function',
|
||
'warn_unused_result': 'warn_unused_result',
|
||
'fallthrough': 'fallthrough',
|
||
'pure': 'readonly',
|
||
'const': 'readnone',
|
||
}
|
||
if 'section' in fn_attrs:
|
||
func.section = fn_attrs['section']
|
||
if 'visibility' in fn_attrs:
|
||
func.linkage = 'internal'
|
||
func.attributes.add('visibility')
|
||
if fn_attrs.get('weak'):
|
||
func.linkage = 'weak'
|
||
for attr_name, llvm_name in _LLVM_FN_ATTR_MAP.items():
|
||
if fn_attrs.get(attr_name):
|
||
try:
|
||
func.attributes.add(llvm_name)
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
raise
|
||
_vlog().warning(f"添加函数属性失败: {_e}", "Exception")
|
||
for key in fn_attrs:
|
||
if key.startswith('llvm.'):
|
||
llvm_attr_name = key[5:]
|
||
try:
|
||
func.attributes.add(llvm_attr_name)
|
||
except Exception as _e:
|
||
# llvmlite 不支持某些较新的 LLVM 属性(如 willreturn, mustprogress)
|
||
# 记录下来,后续通过 IR 后处理添加
|
||
if not hasattr(Gen, '_pending_str_attrs'):
|
||
Gen._pending_str_attrs = {}
|
||
Gen._pending_str_attrs.setdefault(MangledName, []).append(llvm_attr_name)
|
||
if hasattr(self, '_pending_llvm_attrs') and FuncName in self._pending_llvm_attrs:
|
||
for attr_name in self._pending_llvm_attrs.pop(FuncName):
|
||
try:
|
||
func.attributes.add(attr_name)
|
||
except Exception as _e:
|
||
# llvmlite 不支持的属性,记录下来后续通过 IR 后处理添加
|
||
if not hasattr(Gen, '_pending_str_attrs'):
|
||
Gen._pending_str_attrs = {}
|
||
Gen._pending_str_attrs.setdefault(MangledName, []).append(attr_name)
|
||
# 记录自定义行为装饰器信息,供 DecoratorPass 使用
|
||
if behavior_decorators:
|
||
Gen._decorated_funcs[MangledName] = {
|
||
'decorators': behavior_decorators,
|
||
'func_name': FuncName,
|
||
'func_type': FuncType,
|
||
'return_type': FuncType.return_type,
|
||
'param_types': [p.type for p in func.args],
|
||
'param_names': ParamNames,
|
||
'is_export': FuncName in Gen._export_funcs,
|
||
}
|
||
if IsExternFunc or IsStateFunc:
|
||
return
|
||
# 治本修复:如果函数已经有 body(blocks 不为空),跳过重复编译。
|
||
# 否则会导致同一函数被追加第二个 entry block(llvmlite 自动重命名为 entry.1),
|
||
# 产生非法 IR:两个 entry block + 第二个 block 无前驱成为死代码。
|
||
# 触发场景:泛型特化路径 _EmitGenericSpecialization 先调用 _EmitFunctionForwardDeclLlvm
|
||
# 再调用 _EmitFunctionLlvm,若特化在多个调用点被重复触发(如 list[str] 在 split/upper 等多处使用),
|
||
# 同一 MangledName 会进入此函数两次,第二次会重复追加 entry block。
|
||
existing_blocks: list = getattr(func, 'blocks', [])
|
||
if existing_blocks:
|
||
return func
|
||
EntryBlock = func.append_basic_block(name="entry")
|
||
Gen.builder = Gen._NewIrBuilder(EntryBlock)
|
||
Gen.func = func
|
||
# 函数级 + 语句级 DWARF 调试元数据(--dwarf / --asan 自动开启):建
|
||
# DISubprogram 挂 func.metadata["dbg"],并把本 builder 的默认调试位置设为
|
||
# 入口 DILocation(line/column = 该 def 语句的位置)—— 之后本函数体内每条
|
||
# 新建指令自动带 !dbg,逐语句位置由 Gen._set_node_info 覆盖。这样函数体内
|
||
# 所有 call(对同模块有定义的被调函数)都有合法 !dbg,llc 不再报
|
||
# "inlinable function call in a function with debug info must have a !dbg
|
||
# location" 而丢弃整份 DI。declare/extern 在此之前已 return,不会被挂
|
||
# !dbg;未启用时 _GetDebugInfo() 返回 None,不产生任何 IR 差异(零影响)。
|
||
_DbgInfo = Gen._GetDebugInfo()
|
||
if _DbgInfo is not None:
|
||
try:
|
||
_DbgInfo.PushFunction(
|
||
Gen.builder, func, getattr(Node, 'lineno', 0) or 0,
|
||
getattr(Node, 'col_offset', 0) + 1)
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
raise
|
||
_vlog().warning(f"发射调试元数据失败: {_e}", "Exception")
|
||
Gen.variables = {}
|
||
Gen._reg_values = {}
|
||
Gen.global_vars = set()
|
||
if 'aligned' in fn_attrs:
|
||
Gen._emit_stack_align(fn_attrs['aligned'])
|
||
# 保存当前的 var_type_info,以便函数结束时恢复
|
||
saved_var_type_info = Gen.var_type_info.copy()
|
||
saved_var_type_assignments = Gen.var_type_assignments.copy()
|
||
# 治本修复:保存并清空 _local_heap_ptrs / _var_to_heap_ptr。
|
||
# 当 with 上下文中的代码(如 s1.split(','))触发内联编译 list[str].__new__ 时,
|
||
# 若不清空,__new__ 方法会继承外层 with 的 _local_heap_ptrs(含 %call_enter 条目),
|
||
# 方法结束时 _emit_local_heap_frees 会尝试 bitcast/free %call_enter,
|
||
# 但该值在 __new__ 作用域中不存在 → llc 报错 'use of undefined value'。
|
||
saved_local_heap_ptrs = list(Gen._local_heap_ptrs)
|
||
saved_var_to_heap_ptr = dict(Gen._var_to_heap_ptr)
|
||
Gen._local_heap_ptrs = []
|
||
Gen._var_to_heap_ptr = {}
|
||
# 治本修复:保存 var_struct_class / global_struct_class。
|
||
# 当方法调用(如 a.delete())触发 _try_complete_generic_specialization 时,
|
||
# 该路径走 _EmitFunctionLlvm 编译方法体,函数结尾会清空 var_struct_class。
|
||
# 若不保存/恢复,外层函数中已设置的 var_struct_class(如 b='ndarray[double]')
|
||
# 会被清空,导致后续方法调用 fallback 匹配 opaque 基础类型(如 ndarray),
|
||
# 生成对 stub declare(无方法体)的调用 → 链接报 undefined reference。
|
||
saved_var_struct_class = dict(Gen.var_struct_class) if Gen.var_struct_class else {}
|
||
saved_global_struct_class = dict(Gen.global_struct_class) if getattr(Gen, 'global_struct_class', None) else {}
|
||
# 函数内部定义的变量会在赋值时添加到 var_type_info 中
|
||
# 这样函数内部定义的元类型变量(如 a = CInt32T)就能被正确处理
|
||
for stmt in Node.body:
|
||
if isinstance(stmt, ast.Global):
|
||
self.Trans.ForHandler._RegisterGlobalNames(stmt.names, Gen)
|
||
for param, param_name in zip(func.args, ParamNames):
|
||
param.name = param_name
|
||
if param_name == '__stop_iter_flag__':
|
||
Gen._stop_iter_flag_param = param
|
||
Gen.builder.store(ir.Constant(ir.IntType(1), 0), param)
|
||
elif param_name.startswith('__nonlocal_') and param_name.endswith('__'):
|
||
var_name = param_name[len('__nonlocal_'):-2]
|
||
Gen.variables[var_name] = param
|
||
else:
|
||
if isinstance(param.type, ir.PointerType) and isinstance(param.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||
var = Gen.builder.alloca(param.type, name=param_name)
|
||
Gen._store(param, var)
|
||
Gen.variables[param_name] = var
|
||
for CN, ST in Gen.structs.items():
|
||
if param.type.pointee == ST or (isinstance(param.type.pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and param.type.pointee.name == ST.name):
|
||
Gen.var_struct_class[param_name] = CN
|
||
break
|
||
elif isinstance(param.type, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||
var = Gen.builder.alloca(param.type, name=param_name)
|
||
Gen._store(param, var)
|
||
Gen.variables[param_name] = var
|
||
for CN, ST in Gen.structs.items():
|
||
if param.type == ST or (isinstance(param.type, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and param.type.name == ST.name):
|
||
Gen.var_struct_class[param_name] = CN
|
||
break
|
||
else:
|
||
# 所有参数都存入 alloca,确保循环体中对参数的修改能正确反映
|
||
var = Gen._allocaEntry(param.type, name=param_name)
|
||
Gen._store(param, var)
|
||
Gen.variables[param_name] = var
|
||
# 类注释形参:rawptr[X] / CPtr[X] / X
|
||
# 一律按"声明类"登记 var_struct_class。避免按 param.type.pointee 匹配
|
||
# 到泛型父特化(如 class Function(GSListNode[Function]) 的形参 func 被
|
||
# 登记成 GSListNode[Function],其 struct 仅含 Next → func.Blocks 访问
|
||
# fast-fail "属性 'Blocks' 在类 'GSListNode[Function]' 中找不到")。
|
||
# 泛型占位(rawptr[T])的 T 不在 Gen.structs,自动跳过、保留 pointee 匹配。
|
||
for i, arg in enumerate(Node.args.args):
|
||
if arg.annotation is None:
|
||
continue
|
||
if isinstance(arg.annotation, ast.BinOp) and isinstance(arg.annotation.op, ast.BitOr):
|
||
Line: int = getattr(arg.annotation, 'lineno', 0) or 0
|
||
raise TypeError(
|
||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||
param_name = ParamNames[i] if i < len(ParamNames) else arg.arg
|
||
if param_name not in Gen.variables:
|
||
continue
|
||
ann = arg.annotation
|
||
target: str | None = None
|
||
if isinstance(ann, ast.Name):
|
||
target = ann.id
|
||
elif isinstance(ann, ast.Attribute):
|
||
target = ann.attr
|
||
elif isinstance(ann, ast.Subscript):
|
||
subv = ann.value
|
||
subname = getattr(subv, 'id', None) or getattr(subv, 'attr', '')
|
||
if subname in ('rawptr', 'CPtr', 'Ptr', 'CRef', 'CTempRef', 'CArrayPtr', 'CAutoPtr'):
|
||
slc = ann.slice
|
||
while isinstance(slc, ast.Subscript):
|
||
slc = slc.value
|
||
if isinstance(slc, ast.Name):
|
||
target = slc.id
|
||
elif isinstance(slc, ast.Attribute):
|
||
target = slc.attr
|
||
if not target:
|
||
continue
|
||
key: str | None = target if target in Gen.structs else None
|
||
if key is None:
|
||
_sha_t: str | None = (getattr(Gen, 'class_sha1_map', {}) or {}).get(target)
|
||
if _sha_t and f'{_sha_t}.{target}' in Gen.structs:
|
||
key = f'{_sha_t}.{target}'
|
||
if key:
|
||
Gen.var_struct_class[param_name] = key
|
||
if ResolvedClassName and (IsMethod or RawFuncName == '__init__'):
|
||
self.Trans._CurrentCpythonObjectClass = ResolvedClassName
|
||
Gen._variadic_info = None
|
||
if IsVariadic and Node.args.vararg:
|
||
vararg_name = getattr(Node.args.vararg, 'arg', 'args')
|
||
last_param_name = ParamNames[-1] if ParamNames else None
|
||
last_param_ptr = None
|
||
for param, pn in zip(func.args, ParamNames):
|
||
if pn == last_param_name:
|
||
last_param_ptr = param
|
||
break
|
||
triple = getattr(Gen, 'module_triple', '') or getattr(Gen.module, 'triple', '')
|
||
is_windows = 'windows' in triple if triple else False
|
||
ptr_size = getattr(Gen, 'ptr_size', 8)
|
||
# va_list 大小取决于 ABI:Windows x64 = __va_list_tag(24字节),Linux x64 = __va_list_tag[1](24字节)
|
||
# 注意:x86_64-pc-windows-gnu 的 llvm.va_start 写的是 24 字节的 struct __va_list_tag
|
||
# ({i32 gp_offset, i32 fp_offset, i8* overflow_arg_area, i8* reg_save_area}),
|
||
# 若只分配 8 字节会向调用者栈帧越界写 16 字节,导致随机栈破坏(历史崩溃根因)。
|
||
if ptr_size == 4:
|
||
va_list_size = 4 if is_windows else 12
|
||
va_list_align = 4
|
||
else:
|
||
va_list_size = 24
|
||
va_list_align = 16
|
||
va_list_type = ir.ArrayType(ir.IntType(8), va_list_size)
|
||
va_list_alloc = Gen._allocaEntry(va_list_type, name=f"{vararg_name}_va_list", align=va_list_align)
|
||
va_list_ptr = Gen.builder.bitcast(va_list_alloc, ir.IntType(8).as_pointer(), name=f"{vararg_name}_va_list_i8ptr")
|
||
Gen._variadic_info = {
|
||
'vararg_name': vararg_name,
|
||
'va_list_ptr': va_list_ptr,
|
||
'last_param_ptr': last_param_ptr,
|
||
'va_start_called': False,
|
||
}
|
||
if last_param_ptr:
|
||
last_param_alloc = Gen._allocaEntry(last_param_ptr.type, name="last_param_copy")
|
||
Gen.builder.store(last_param_ptr, last_param_alloc)
|
||
Gen.emit_va_start(va_list_ptr)
|
||
Gen._variadic_info['va_start_called'] = True
|
||
# 用 _direct_values 注册,Name 解析时直接返回 va_list 指针(i8*),
|
||
# 不走 variables 的 load 路径(否则会把 i8* 当 char* 加载一个字节)
|
||
Gen._direct_values[vararg_name] = va_list_ptr
|
||
# @TLS 一次性初始化检查:首次调用执行函数体,后续调用直接返回
|
||
if is_tls_func:
|
||
flag_name: str = f"__tls_init_done_{FuncName}"
|
||
flag_global = None
|
||
for gv in Gen.module.global_values:
|
||
if gv.name == flag_name:
|
||
flag_global = gv
|
||
break
|
||
if flag_global is None:
|
||
flag_global = ir.GlobalVariable(Gen.module, ir.IntType(1), name=flag_name)
|
||
flag_global.initializer = ir.Constant(ir.IntType(1), 0)
|
||
flag_global.linkage = 'internal'
|
||
flag_val = Gen.builder.load(flag_global, name="tls_flag_check")
|
||
skip_bb = func.append_basic_block("tls_skip")
|
||
cont_bb = func.append_basic_block("tls_continue")
|
||
Gen.builder.cbranch(flag_val, skip_bb, cont_bb)
|
||
Gen.builder.position_at_end(skip_bb)
|
||
ActualReturnType = func.function_type.return_type
|
||
if isinstance(ActualReturnType, ir.VoidType):
|
||
Gen.builder.ret_void()
|
||
elif isinstance(ActualReturnType, ir.IntType):
|
||
Gen.builder.ret(ir.Constant(ActualReturnType, 0))
|
||
elif isinstance(ActualReturnType, (ir.FloatType, ir.DoubleType)):
|
||
Gen.builder.ret(ir.Constant(ActualReturnType, 0.0))
|
||
elif isinstance(ActualReturnType, ir.PointerType):
|
||
Gen.builder.ret(ir.Constant(ActualReturnType, None))
|
||
else:
|
||
Gen.builder.ret(ir.Constant(ActualReturnType, None))
|
||
Gen.builder.position_at_end(cont_bb)
|
||
Gen.builder.store(ir.Constant(ir.IntType(1), 1), flag_global)
|
||
_saved_class_name = getattr(Gen, '_current_class_name', None)
|
||
Gen._current_class_name = ClassName
|
||
# 提取首个裸字符串字面量作为 __doc__ docstring,并跳过该节点避免生成死代码
|
||
func_body: list[ast.stmt] = Node.body
|
||
doc_symbol: str = f"{ClassName}.{Node.name}" if ClassName else Node.name
|
||
if (func_body and isinstance(func_body[0], ast.Expr)
|
||
and isinstance(func_body[0].value, ast.Constant)
|
||
and isinstance(func_body[0].value.value, str)):
|
||
Gen._create_doc_global(doc_symbol, func_body[0].value.value)
|
||
func_body = func_body[1:]
|
||
else:
|
||
Gen._create_doc_global(doc_symbol, None)
|
||
try:
|
||
self.Trans.BodyHandler.HandleBodyLlvm(func_body)
|
||
except Exception as _body_exc:
|
||
# 方法体编译失败:确保 block 终止(防止 expected instruction opcode 错误),
|
||
# 然后重新抛出异常让编译立即终止(不吞掉错误)
|
||
_fn_name: str = Node.name
|
||
_cls_name: str = ClassName if ClassName else ''
|
||
import sys as _sys
|
||
import traceback as _tb
|
||
print(f"[FATAL] 方法体编译失败 ({_cls_name}.{_fn_name}): {type(_body_exc).__name__}: {_body_exc}", file=_sys.stderr)
|
||
_tb.print_exc(file=_sys.stderr)
|
||
if Gen.builder is not None:
|
||
try:
|
||
if not Gen.builder.block.is_terminated:
|
||
_ret_ty = func.function_type.return_type
|
||
if isinstance(_ret_ty, ir.VoidType):
|
||
Gen.builder.ret_void()
|
||
elif isinstance(_ret_ty, ir.PointerType):
|
||
Gen.builder.ret(ir.Constant(_ret_ty, None))
|
||
elif isinstance(_ret_ty, ir.IntType):
|
||
Gen.builder.ret(ir.Constant(_ret_ty, 0))
|
||
else:
|
||
Gen.builder.ret(ir.Constant(_ret_ty, None))
|
||
except Exception:
|
||
try:
|
||
if Gen.builder and not Gen.builder.block.is_terminated:
|
||
Gen.builder.ret_void()
|
||
except Exception:
|
||
pass
|
||
# 失败路径也要复位「当前方法」上下文(成功路径的复位在函数末尾,异常
|
||
# 直接 re-raise 会跳过它)。上层有吞掉异常的调用点(如泛型特化按需补全
|
||
# _try_complete_generic_specialization、类按需实例化),它们让外层方法
|
||
# 继续编译;若此时 _CurrentCpythonObjectClass / var_struct_class 仍指向
|
||
# 内层特化类,外层方法的 `self.X` 会被按内层类解析(典型现象:
|
||
# ExprGenFstr.translate_joined_str 的 `self.Gen` 被按
|
||
# `list[cfc4ca8da95a30e1.AST*]` 解析 → "属性 'Gen' 在类中找不到")。
|
||
Gen._current_class_name = _saved_class_name
|
||
self.Trans._CurrentCpythonObjectClass = saved_cpython_class
|
||
Gen.var_struct_class = saved_var_struct_class
|
||
if hasattr(Gen, 'global_struct_class'):
|
||
Gen.global_struct_class = saved_global_struct_class
|
||
raise
|
||
if not Gen.builder.block.is_terminated:
|
||
if 'naked' in fn_attrs:
|
||
Gen.builder.unreachable()
|
||
self.Trans._CurrentCpythonObjectClass = saved_cpython_class
|
||
return
|
||
# fail-fast:有非 void 返回类型注解但函数体掉出末尾(无显式 return 覆盖)
|
||
# → 立即报错,不静默 ret 0(用户隐式返回规则)。
|
||
# 判据按**源码层面**函数体末句判断(不依赖 builder 状态——翻译后未
|
||
# terminated 可能由其它翻译问题导致,如 HandleExprLlvm 返回 None 静默
|
||
# 跳过 ret,不该归类为"掉出末尾"缺陷):
|
||
# - 末句是显式 return → 有覆盖,正常
|
||
# - 末句是控制流(If/Match/While/For/Try/With)→ 掉出合法(隐式返回
|
||
# 规则:末句控制流 → unreachable;match/if 合成 after 块机械掉出,
|
||
# 所有 arm 已 terminated 属正常)
|
||
# - 末句是普通语句 → 真掉出末尾;-> None / -> CVoid 视为 Void 合法,
|
||
# 无注解 → C 风格过程(ConstZero,保持现状);其余注解报错
|
||
_last_stmt = Node.body[-1] if Node.body else None
|
||
_is_ret_or_ctrl_tail: bool = isinstance(_last_stmt, (
|
||
ast.Return, ast.If, ast.Match, ast.While, ast.For, ast.Try, ast.With))
|
||
if Node.returns is not None and not _is_ret_or_ctrl_tail:
|
||
# void(None / CVoid)/ extern|export 声明型辅助符号
|
||
# (State / CExport / CExtern)→ 掉出合法,不 fail-fast
|
||
_DeclMarkers: tuple[str, ...] = (
|
||
tuple(getattr(Node, 'Markers', None) or ())
|
||
+ tuple(getattr(Node.returns, 'Markers', None) or ()))
|
||
_IsDecl: bool = (any(m in ('state', 'export', 'extern') for m in _DeclMarkers)
|
||
or bool(getattr(Node, 'Extern', False))
|
||
or bool(getattr(Node, 'Export', False)))
|
||
if not _IsDecl and not _IsVoidOrDeclAnnotation(Node.returns):
|
||
raise Exception(
|
||
f"函数 {Node.name} 声明了返回类型但函数体可能掉出末尾(缺少 return 语句);"
|
||
f"普通语句掉出末尾 + 有返回注解属于定义缺陷,请补显式 return")
|
||
Gen._emit_local_heap_frees()
|
||
if Gen._variadic_info and Gen._variadic_info.get('va_start_called'):
|
||
va_list_ptr = Gen._variadic_info.get('va_list_ptr')
|
||
if va_list_ptr:
|
||
Gen.emit_va_end(va_list_ptr)
|
||
ActualReturnType = func.function_type.return_type
|
||
if isinstance(ActualReturnType, ir.VoidType):
|
||
Gen.builder.ret_void()
|
||
elif isinstance(ActualReturnType, ir.IntType):
|
||
Gen.builder.ret(ir.Constant(ActualReturnType, 0))
|
||
elif isinstance(ActualReturnType, (ir.FloatType, ir.DoubleType)):
|
||
Gen.builder.ret(ir.Constant(ActualReturnType, 0.0))
|
||
elif isinstance(ActualReturnType, ir.PointerType):
|
||
Gen.builder.ret(ir.Constant(ActualReturnType, None))
|
||
elif isinstance(ActualReturnType, ir.IdentifiedStructType):
|
||
if ActualReturnType.elements:
|
||
zero_val = ir.Constant(ActualReturnType, [ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) else ir.Constant(et, ir.Undefined) for et in ActualReturnType.elements])
|
||
else:
|
||
zero_val = ir.Constant(ActualReturnType, None)
|
||
Gen.builder.ret(zero_val)
|
||
elif isinstance(ActualReturnType, ir.ArrayType):
|
||
Gen.builder.ret(ir.Constant(ActualReturnType, None))
|
||
else:
|
||
Gen.builder.ret_void()
|
||
# 离开函数体:停用本 builder 的默认调试位置(含 SP 绑定),防止遗留状态
|
||
# 被后续模块级指令误用(未启用 --dwarf 时 _DbgInfo 为 None,不做任何事)。
|
||
if _DbgInfo is not None:
|
||
_DbgInfo.PopFunction(Gen.builder)
|
||
Gen.builder = None
|
||
Gen.func = None
|
||
Gen._current_class_name = _saved_class_name
|
||
Gen.variables = {}
|
||
Gen.var_signedness = {}
|
||
Gen._reg_values = {}
|
||
Gen._direct_values = {}
|
||
Gen.var_struct_class = {}
|
||
# 注解声明类台账是**函数作用域**的(局部变量的声明随函数出栈失效),
|
||
# 与 var_struct_class 同处清空 —— 否则同名变量会在别的函数里被误判为
|
||
# "已由注解声明",从而挡住右值推出类的正常登记。
|
||
Gen.var_annotated_class = {}
|
||
Gen.var_ptr_element = {}
|
||
Gen.var_const_flags = {}
|
||
# const/volatile 的**函数作用域层**随函数出栈清空(模块级层 global_* 与
|
||
# 类字段层 field_* 是持久的,不在此清;见 BaseGen 的登记说明)。
|
||
Gen.var_volatile_flags = {}
|
||
Gen.var_pointee_volatile_flags = {}
|
||
# 恢复保存的 var_type_info
|
||
Gen.var_type_info = saved_var_type_info
|
||
Gen.var_type_assignments = saved_var_type_assignments
|
||
Gen._stop_iter_flag_param = None
|
||
# 恢复外层作用域的 _local_heap_ptrs / _var_to_heap_ptr
|
||
Gen._local_heap_ptrs = saved_local_heap_ptrs
|
||
Gen._var_to_heap_ptr = saved_var_to_heap_ptr
|
||
# 恢复外层作用域的 var_struct_class / global_struct_class
|
||
# (内层方法体编译不应污染外层函数的变量-类型映射)
|
||
Gen.var_struct_class = saved_var_struct_class
|
||
if hasattr(Gen, 'global_struct_class'):
|
||
Gen.global_struct_class = saved_global_struct_class
|
||
Gen._variadic_info = None
|
||
self.Trans._CurrentCpythonObjectClass = saved_cpython_class
|
||
self.Trans.CurrentMultiRetTypes = None
|
||
if self.Trans.VarScopes:
|
||
self.Trans.VarScopes.pop()
|
||
self.Trans.FunctionReturnTypes[FuncName] = ReturnTypeInfo
|
||
if not self.Trans.SymbolTable.has(FuncName):
|
||
FuncInfo = CTypeInfo()
|
||
FuncInfo.Name = FuncName
|
||
FuncInfo.IsFunction = True
|
||
FuncInfo.MetaList = func_meta
|
||
if IsInlineFunc:
|
||
FuncInfo.IsInline = True
|
||
FuncInfo.InlineBody = Node.body
|
||
FuncInfo.InlineParams = [arg.arg for arg in Node.args.args]
|
||
self.Trans.SymbolTable.insert(FuncName, FuncInfo)
|
||
else:
|
||
existing = self.Trans.SymbolTable[FuncName]
|
||
if existing.MetaList == FuncMeta.NONE and func_meta != FuncMeta.NONE:
|
||
existing.MetaList = func_meta
|
||
if IsInlineFunc:
|
||
existing.IsInline = True
|
||
existing.InlineBody = Node.body
|
||
existing.InlineParams = [arg.arg for arg in Node.args.args]
|
||
# property setter/deleter: 在原始 PropKey(不带后缀)下注册 MetaList
|
||
if FuncMeta.PROPERTY_SETTER in func_meta or FuncMeta.PROPERTY_DELETER in func_meta:
|
||
BasePropKey = f"{ClassName}.{RawFuncName}" if ClassName else RawFuncName
|
||
base_existing = self.Trans.SymbolTable.lookup(BasePropKey)
|
||
if base_existing:
|
||
if func_meta != FuncMeta.NONE:
|
||
base_existing.MetaList = base_existing.MetaList | func_meta
|
||
else:
|
||
PropInfo = CTypeInfo()
|
||
PropInfo.Name = BasePropKey
|
||
PropInfo.IsFunction = True
|
||
PropInfo.MetaList = func_meta
|
||
self.Trans.SymbolTable.insert(BasePropKey, PropInfo)
|
||
return func
|