Files
TransPyC/lib/core/Handles/HandlesAssert.py
T
TermiNexus 2514cee4c9 feat(lang): 同步 cif/celif/celse、值引用注解与 assert 改译 testcheck.check
vast 双路径(Python Parser/ExprParser 与 C 扩展 vast_c.c)新增 cif-celif-celse 语句族与 &T / &temp T 参数注解解析,_parser.pyd 已同步重编。HandlesIf 改认 @CIf 标记并做编译期常量求值,含运行时变量一律 fail-fast,同时删除 c.CIf 家族(c.py)。HandlesAssert 合成 testcheck.check(cond, None, msg) 调用,非字符串字面量消息报 TypeError。FuncGen 调用点按形参模式自动取址(ref 仅接受左值,右值 fail-fast;temp 物化临时栈),SymbolUtils/TypeAnnotationResolver 提供模式识别;t.py 删除 CNeedPtr。
2026-10-07 19:03:29 +08:00

80 lines
3.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP
import vast as ast
# 无信息 assert 使用的默认 fail_msg;须与 testcheck.check 的 fail_msg: str 形参一致
_ASSERT_DEFAULT_FAIL_MSG: str = "assertion failed"
# assert 自动依赖的检查库模块名与入口函数(见 includes/testcheck.vp)
_ASSERT_CHECK_MODULE: str = "testcheck"
_ASSERT_CHECK_FUNC: str = "check"
class AssertHandle(BaseHandle):
def _HandleAssertLlvm(self, Node: ast.Assert) -> None:
"""把 `assert 条件[, 信息]` 译为一次普通函数调用 testcheck.check(条件, None, 信息)。
语义:条件为真 → ok_msg 传 None(静默,不打印 PASS);条件为假 → fail(信息)。
不再中止程序(旧实现的 printf AssertionError + exit(1) 已移除),也不再走
try/except 抛异常码的路径。
"""
FailMsgNode: ast.expr = self._ResolveAssertFailMsgNode(Node)
CallNode: ast.Call = ast.Call(
func=ast.Attribute(
value=ast.Name(id=_ASSERT_CHECK_MODULE, ctx=ast.Load()),
attr=_ASSERT_CHECK_FUNC,
ctx=ast.Load()),
args=[Node.test, ast.Constant(value=None, kind=None), FailMsgNode],
keywords=[],
)
ast.copy_location(CallNode, Node)
# 复用既有跨模块调用生成路径(含符号解析、实参按形参类型收窄/扩充与 fail-fast 校验)
self.HandleExprLlvm(CallNode)
def _ResolveAssertFailMsgNode(self, Node: ast.Assert) -> ast.expr:
"""解析 assert 的信息表达式,并强制其为 str(fail-fast,禁止静默降级)。
- 无信息 → 字符串字面量 "assertion failed"
- 有信息 → 原节点(须为 str 形态:字面量 / f-string / str 变量或属性)
"""
MsgNode: ast.expr | None = Node.msg
if MsgNode is None:
DefaultMsg: ast.Constant = ast.Constant(value=_ASSERT_DEFAULT_FAIL_MSG, kind=None)
ast.copy_location(DefaultMsg, Node)
return DefaultMsg
# 旧实现允许把异常类名当信息(映射为异常码、不打印)。check() 的 fail_msg 形参
# 是 str,这类写法已无对应语义:显式报错,不静默降级。
_ExcName: str | None = None
if isinstance(MsgNode, ast.Name):
_ExcName = MsgNode.id
elif isinstance(MsgNode, ast.Call) and isinstance(MsgNode.func, ast.Name):
_ExcName = MsgNode.func.id
if _ExcName is not None and _ExcName in EXCEPTION_CODE_MAP:
self._RaiseAssertMsgTypeError(
f"assert 的信息必须是字符串(str),不能是异常类 '{_ExcName}'")
if not self._IsStrAssertMsg(MsgNode):
self._RaiseAssertMsgTypeError(
"assert 的信息必须是字符串(str):仅支持字符串字面量、f-string 或 str 变量/属性"
"(如需拼接请先写入 str 变量)")
return MsgNode
def _IsStrAssertMsg(self, MsgNode: ast.expr) -> bool:
"""静态判定 assert 信息是否为 str 形态。
变量/属性(Name/Attribute)无法在此静态证伪为 str,放行并由调用点的
`fail_msg: str` 形参做类型收口;其余非常量、非 f-string 的形态一律拒绝。
"""
if isinstance(MsgNode, ast.Constant):
return isinstance(MsgNode.value, str)
if isinstance(MsgNode, ast.JoinedStr):
return True
if isinstance(MsgNode, (ast.Name, ast.Attribute)):
return True
return False
def _RaiseAssertMsgTypeError(self, Message: str) -> None:
from lib.core.LLVMCG.FuncGen import FailFastError
Gen = self.Trans.LlvmGen
raise FailFastError(Message + (Gen._get_node_info() if Gen else ''))