refactor(tpc): 删除类型联合语法并将修饰迁移为 AST 字段

类型注解不再接受任何 T1 | T2;const/volatile/static/export/extern/inline/define/typedef/__attribute__/BigEndian/LittleEndian/Bit 改为注解节点字段 Markers/Attributes/ByteOrder/BitWidth;指针与引用改为 CPtr[T]/CRef[T]/CTempRef[T]/CArrayPtr[T]/CAutoPtr[T];Python 与 vast_c 两套解析器、类型解析与声明端同步;C 扩展早于 vast_c.c 时自动回退纯 Python 解析器。
This commit is contained in:
TermiNexus committed 2026-10-18 13:35:34 +08:00
1 parent 3269775945
commit 660a15bef8
19 files changed
+1312 -1576

No files matched your search

+65 -166
View File
@@ -8,9 +8,7 @@ import copy
import traceback
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta
from lib.core.SymbolUtils import (
FindStructNameInAnnotationWithContext, AnnotationContainsName,
IsPtrSubscriptNode, DesugarPtrSubscriptToUnion, FindAutoAddrMode)
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
@@ -53,36 +51,24 @@ def _RejectRefReturnAnnotation(node: ast.AST) -> None:
def _IsVoidOrDeclAnnotation(Annot: ast.AST) -> bool:
"""判断函数返回注解是否为 void 或 extern/export 声明型辅助符号。
void:None / CVoid,含 `|` 联合形式(注解中 `|` 表示 and),
如 `-> CVoid | CExport`(sprintf 先例)→ 掉出末尾 ret void 合法。
void:None / CVoid。
声明型辅助符号:State(extern)/ CExport(export)/ CExtern——
此类函数返回注解被改写为 `<原类型> | 辅助符号` 且 body 为空(extern 声明),
掉出末尾是正常形态,必须豁免 fail-fast。
此类函数 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],修饰符请用关键字")
if isinstance(Annot, ast.Constant):
return Annot.value is None
if isinstance(Annot, ast.Attribute):
return getattr(Annot, 'attr', '') in ('CVoid', 'State', 'CExport', 'CExtern')
if isinstance(Annot, ast.BinOp) and isinstance(Annot.op, ast.BitOr):
return _IsVoidOrDeclAnnotation(Annot.left) or _IsVoidOrDeclAnnotation(Annot.right)
return False
def _IsVoidOrDeclAnnotation(Annot: ast.AST) -> bool:
"""判断函数返回注解是否为 void 或 extern/export 声明型辅助符号。
void:None / CVoid,含 `|` 联合形式(注解中 `|` 表示 and),
如 `-> CVoid | CExport`(sprintf 先例)→ 掉出末尾 ret void 合法。
声明型辅助符号:State(extern)/ CExport(export)/ CExtern——
此类函数返回注解被改写为 `<原类型> | 辅助符号` 且 body 为空(extern 声明),
掉出末尾是正常形态,必须豁免 fail-fast。
"""
if isinstance(Annot, ast.Constant):
return Annot.value is None
if isinstance(Annot, ast.Attribute):
return getattr(Annot, 'attr', '') in ('CVoid', 'State', 'CExport', 'CExtern')
if isinstance(Annot, ast.BinOp) and isinstance(Annot.op, ast.BitOr):
return _IsVoidOrDeclAnnotation(Annot.left) or _IsVoidOrDeclAnnotation(Annot.right)
if isinstance(Annot, ast.Name):
Markers: tuple[str, ...] = getattr(Annot, 'Markers', None) or ()
if 'state' in Markers or 'export' in Markers or 'extern' in Markers:
return True
return Annot.id in ('CVoid', 'State', 'CExport', 'CExtern')
return False
@@ -310,13 +296,14 @@ class FunctionHandle(BaseHandle):
def _ExtractLLVMAttrs(self, node: ast.AST) -> list[str]:
attrs: list[str] = []
if isinstance(node, ast.BinOp):
attrs.extend(self._ExtractLLVMAttrs(node.left))
attrs.extend(self._ExtractLLVMAttrs(node.right))
elif isinstance(node, ast.Attribute):
attr_name: str | None = self._GetAttrLLVMName(node)
if attr_name:
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:
@@ -535,44 +522,10 @@ class FunctionHandle(BaseHandle):
else:
try:
if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr):
ReturnTypeInfo = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Node.returns)
if not isinstance(ReturnTypeInfo, CTypeInfo):
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CVoid()
if ((ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState)
or (ReturnTypeInfo.PtrCount >= 2 and ReturnTypeInfo.BaseType is None)):
def _FindNonVoidCTypeInfo(node: ast.AST) -> Any:
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
results: list[Any] = []
for child in [node.left, node.right]:
r: Any = _FindNonVoidCTypeInfo(child)
if r and not r.IsVoid:
results.append(r)
for r in results:
if not r.IsPtr and not r.IsStruct:
return r
return results[0] if results else None
try:
SideInfo: Any = CTypeInfo.FromNode(node, self.Trans.SymbolTable)
if SideInfo:
return SideInfo
except Exception as _e:
if _config_mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
return None
found: Any = _FindNonVoidCTypeInfo(Node.returns)
if found and not found.IsVoid:
ReturnTypeInfo = found
if ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState:
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CInt()
# define 宏函数(返回注解含 CDefine,如 `int | CDefine`):
# 标记为编译期内联宏(alwaysinline),对齐裸 `-> CDefine` 路径
# (合并路径丢失 IsDefine 时仍能命中)
if AnnotationContainsName(Node.returns, 'CDefine'):
if not hasattr(self, '_cdefine_funcs'):
self._cdefine_funcs = set()
self._cdefine_funcs.add(FuncName)
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'):
@@ -648,6 +601,8 @@ class FunctionHandle(BaseHandle):
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()
@@ -834,12 +789,10 @@ class FunctionHandle(BaseHandle):
replacement: str = type_map[node.id]
return self._make_replacement_node(replacement)
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
if isinstance(node.left, ast.Name) and node.left.id in type_map:
replacement: str = type_map[node.left.id]
node.left = self._make_replacement_node(replacement)
return node
node.left = self._replace_type_in_annotation(node.left, type_map, cptr_params)
node.right = self._replace_type_in_annotation(node.right, type_map, cptr_params)
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]
@@ -884,10 +837,10 @@ class FunctionHandle(BaseHandle):
base_node = self._make_name_node(BaseName)
node: ast.AST = base_node
for _ in range(StarCount):
node = ast.BinOp(
left=node,
op=ast.BitOr(),
right=ast.Name(id='CPtr', ctx=ast.Load()),
node = ast.Subscript(
value=ast.Name(id='CPtr', ctx=ast.Load()),
slice=node,
ctx=ast.Load(),
)
return node
if replacement.endswith('ptr'):
@@ -899,10 +852,10 @@ class FunctionHandle(BaseHandle):
levels += 1
node: ast.AST = self._make_name_node(base)
for _ in range(levels):
node = ast.BinOp(
left=node,
op=ast.BitOr(),
right=ast.Name(id='CPtr', ctx=ast.Load()),
node = ast.Subscript(
value=ast.Name(id='CPtr', ctx=ast.Load()),
slice=node,
ctx=ast.Load(),
)
return node
if '[' in replacement:
@@ -914,8 +867,6 @@ class FunctionHandle(BaseHandle):
if not isinstance(SubNode, ast.Subscript):
SubNode = self._parse_subscript_manually(replacement)
if isinstance(SubNode, ast.Subscript):
if IsPtrSubscriptNode(SubNode, self.Trans.SymbolTable):
return DesugarPtrSubscriptToUnion(SubNode, self.Trans.SymbolTable)
return SubNode
return self._make_name_node(replacement)
@@ -1051,10 +1002,10 @@ class FunctionHandle(BaseHandle):
# 需替换为 BinOp(AST | CPtr),使 __sizeof__ 等处理器能正确识别
# 指针语义并直接返回 8,避免触发 struct 加载和重入编译
if cptr_params and node.func.value.id in cptr_params:
node.func.value = ast.BinOp(
left=self._make_name_node(replacement),
op=ast.BitOr(),
right=ast.Name(id='CPtr', ctx=ast.Load())
node.func.value = ast.Subscript(
value=ast.Name(id='CPtr', ctx=ast.Load()),
slice=self._make_name_node(replacement),
ctx=ast.Load()
)
else:
node.func.value = self._make_name_node(replacement)
@@ -1066,10 +1017,10 @@ class FunctionHandle(BaseHandle):
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:
node.value = ast.BinOp(
left=self._make_name_node(replacement),
op=ast.BitOr(),
right=ast.Name(id='CPtr', ctx=ast.Load())
node.value = ast.Subscript(
value=ast.Name(id='CPtr', ctx=ast.Load()),
slice=self._make_name_node(replacement),
ctx=ast.Load()
)
else:
node.value = ast.Name(id=replacement, ctx=ast.Load())
@@ -1134,11 +1085,7 @@ class FunctionHandle(BaseHandle):
has_cexport: bool = False
if Node.returns:
try:
RetTypeInfo: Any = None
if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr):
RetTypeInfo = self.Trans.TypeMergeHandler.MergeTypes(Node.returns)
else:
RetTypeInfo = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable)
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:
@@ -1495,43 +1442,10 @@ class FunctionHandle(BaseHandle):
else:
try:
if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr):
ReturnTypeInfo = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Node.returns)
if not isinstance(ReturnTypeInfo, CTypeInfo):
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CVoid()
if ((ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState)
or (ReturnTypeInfo.PtrCount >= 2 and ReturnTypeInfo.BaseType is None)):
def _FindNonVoidCTypeInfo(node):
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
results = []
for child in [node.left, node.right]:
r = _FindNonVoidCTypeInfo(child)
if r and not r.IsVoid:
results.append(r)
for r in results:
if not r.IsPtr and not r.IsStruct:
return r
return results[0] if results else None
try:
SideInfo = CTypeInfo.FromNode(node, self.Trans.SymbolTable)
if SideInfo:
return SideInfo
except Exception as _e:
if _config_mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
return None
found = _FindNonVoidCTypeInfo(Node.returns)
if found and not found.IsVoid:
ReturnTypeInfo = found
if ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState:
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CInt()
# define 宏函数(返回注解含 CDefine,如 `int | CDefine`):
# 标记为编译期内联宏(alwaysinline),对齐裸 `-> CDefine` 路径
if AnnotationContainsName(Node.returns, 'CDefine'):
if not hasattr(self, '_cdefine_funcs'):
self._cdefine_funcs = set()
self._cdefine_funcs.add(FuncName)
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'):
@@ -1602,6 +1516,8 @@ class FunctionHandle(BaseHandle):
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()
@@ -1977,31 +1893,7 @@ class FunctionHandle(BaseHandle):
var = Gen._allocaEntry(param.type, name=param_name)
Gen._store(param, var)
Gen.variables[param_name] = var
# 为联合类型注解(如 Function | CPtr)的参数设置 var_struct_class,
# 确保编译器能正确生成 GEP 访问结构体成员(如 func.Blocks、func.Params)
for i, arg in enumerate(Node.args.args):
if arg.annotation and isinstance(arg.annotation, ast.BinOp) and isinstance(arg.annotation.op, ast.BitOr):
param_name: str = ParamNames[i] if i < len(ParamNames) else arg.arg
if param_name in Gen.variables:
# 若 L1650-1657 已根据 param.type.pointee 匹配到正确的特化名
# (如 ndarray[double]),不覆盖:FindStructNameInAnnotation 对
# 泛型注解 ndarray[CDouble] 会构造 ndarray[CDouble](与实际
# ndarray[double] 不匹配),回退到裸模板类名 ndarray(opaque),
# 导致方法调用查找 ndarray.sum 而非 ndarray[double].sum。
if param_name in Gen.var_struct_class:
_existing_ps: str = Gen.var_struct_class[param_name]
# 指针占位名(rawptr / {sha1}.rawptr / rawptr[...])是模块限定
# struct 联合(llvmlite.Function | CPtr)被 resolver 退化
# 的产物,必须允许 FindStructNameInAnnotation 短名修正
# (否则 func.IsVarArg → "属性在类 'rawptr' 中找不到")。
if not (_existing_ps == 'rawptr' or '.rawptr' in _existing_ps
or _existing_ps.startswith('rawptr[')):
continue
found_struct: str | None = FindStructNameInAnnotationWithContext(
arg.annotation, self.Trans, Gen)
if found_struct:
Gen.var_struct_class[param_name] = found_struct
# 普通类注解形参(非 BinOp 联合):rawptr[X] / CPtr[X] / X / X
# 类注释形参:rawptr[X] / CPtr[X] / X
# 一律按"声明类"登记 var_struct_class。避免按 param.type.pointee 匹配
# 到泛型父特化(如 class Function(GSListNode[Function]) 的形参 func 被
# 登记成 GSListNode[Function],其 struct 仅含 Next → func.Blocks 访问
@@ -2011,7 +1903,10 @@ class FunctionHandle(BaseHandle):
if arg.annotation is None:
continue
if isinstance(arg.annotation, ast.BinOp) and isinstance(arg.annotation.op, ast.BitOr):
continue # 联合注解由上方循环处理
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
@@ -2024,8 +1919,10 @@ class FunctionHandle(BaseHandle):
elif isinstance(ann, ast.Subscript):
subv = ann.value
subname = getattr(subv, 'id', None) or getattr(subv, 'attr', '')
if subname in ('rawptr', 'CPtr', 'Ptr'):
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):
@@ -2184,9 +2081,11 @@ class FunctionHandle(BaseHandle):
_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 声明型辅助符号
# void(None / CVoid)/ extern|export 声明型辅助符号
# (State / CExport / CExtern)→ 掉出合法,不 fail-fast
if not _IsVoidOrDeclAnnotation(Node.returns):
_DeclMarkers: tuple[str, ...] = getattr(Node, 'Markers', None) or ()
_IsDecl: bool = any(m in ('state', 'export', 'extern') for m in _DeclMarkers)
if not _IsDecl and not _IsVoidOrDeclAnnotation(Node.returns):
raise Exception(
f"函数 {Node.name} 声明了返回类型但函数体可能掉出末尾(缺少 return 语句);"
f"普通语句掉出末尾 + 有返回注解属于定义缺陷,请补显式 return")