Files
TransPyC/lib/core/Handles/HandlesBody.py
T
TermiNexus 34c4eeff02 fix(flow): 循环/match 外的 break/continue 改为 fail-fast
HandlesBody:loop_break_targets / loop_continue_targets 为空时不再静默不生成跳转,
直接 FailFastError 暴露——原实现会让 break/continue 无声无效果(不兜底原则)。
2026-10-02 22:35:26 +08:00

108 lines
6.1 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
import vast as ast
import llvmlite.ir as ir
class BodyHandle(BaseHandle):
def __init__(self, translator: "Translator") -> None:
super().__init__(translator)
def HandleBodyLlvm(self, Body: list[ast.stmt]) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
for Node in Body:
if Gen.builder and Gen.builder.block.is_terminated:
break
Gen._set_node_info(Node)
try:
if isinstance(Node, ast.Expr):
# `fallthrough`(vast 软关键字已脱糖为 c.NoBreak())是 match 的
# 标记语句,本身不产出 IR,语义由 HandlesMatch 消费;后续步骤
# (含 _EmitTempFrees)保持原样执行。
if self._IsNoBreakMarkerStmt(Node):
pass
else:
self.HandleExprLlvm(Node.value)
elif isinstance(Node, ast.Return):
self.Trans.ReturnHandler._HandleReturnLlvm(Node)
elif isinstance(Node, ast.Assign):
self.Trans.AssignHandler._HandleAssignLlvm(Node)
elif isinstance(Node, ast.AugAssign):
self.Trans.AugAssignHandler._HandleAugAssignLlvm(Node)
elif isinstance(Node, ast.AnnAssign):
self.Trans.AnnAssignHandler._HandleAnnAssignLlvm(Node)
elif isinstance(Node, ast.If):
self.Trans.IfHandler._HandleIfLlvm(Node)
elif isinstance(Node, ast.For):
self.Trans.ForHandler._HandleForLlvm(Node)
elif isinstance(Node, ast.While):
self.Trans.WhileHandler._HandleWhileLlvm(Node)
elif isinstance(Node, ast.Break):
if not Gen.loop_break_targets:
# fail-fast:循环 / match-case 之外的 break 无处可跳,
# 静默忽略只会让"提前退出"变成无声无效果(不兜底)
from lib.core.LLVMCG.FuncGen import FailFastError
raise FailFastError(
"break 只能用在循环或 match-case 体内(当前没有可跳出的目标)")
Gen.builder.branch(Gen.loop_break_targets[-1])
elif isinstance(Node, ast.Continue):
if not Gen.loop_continue_targets:
# fail-fast:循环之外的 continue 无处可跳(同上)
from lib.core.LLVMCG.FuncGen import FailFastError
raise FailFastError(
"continue 只能用在循环体内(当前没有可继续的循环)")
Gen.builder.branch(Gen.loop_continue_targets[-1])
elif isinstance(Node, ast.With):
self.Trans.WithHandler._HandleWithLlvm(Node)
elif isinstance(Node, ast.ClassDef):
pass
elif getattr(ast, 'Match', None) and isinstance(Node, ast.Match):
self.Trans.MatchHandler._HandleMatchLlvm(Node)
elif isinstance(Node, ast.Try):
self.Trans.TryHandler._HandleTryLlvm(Node)
elif isinstance(Node, ast.Raise):
self.Trans.RaiseHandler._HandleRaiseLlvm(Node)
elif isinstance(Node, ast.Assert):
self.Trans.AssertHandler._HandleAssertLlvm(Node)
elif isinstance(Node, ast.Global):
self.Trans.ForHandler._HandleGlobalLlvm(Node)
elif isinstance(Node, ast.FunctionDef):
self.Trans.ForHandler._HandleNestedFunctionLlvm(Node)
elif isinstance(Node, ast.Nonlocal):
self.Trans.ForHandler._HandleNonlocalLlvm(Node)
elif isinstance(Node, ast.Delete):
self.Trans.DeleteHandler._HandleDeleteLlvm(Node)
except Exception as e:
lineno: int = getattr(Node, 'lineno', 0)
# 注入行偏移还原:AST 行号含 _inject_auto_imports 在文件头注入的 N 行,
# 先按精确偏移减回磁盘真实行号(N 由 Phase2Translator 计算并挂到 translator);
# 报文行号与源码行必须同用还原后的 lineno,二者一致(否则会显示下一行源码)。
_line_offset: int = int(getattr(self.Trans, '_line_offset', 0) or 0)
if _line_offset > 0 and lineno > _line_offset:
lineno -= _line_offset
source_line: str | None = Gen._get_source_line(lineno)
src_file: str = Gen._current_source_file or ''
src_path: str = src_file if src_file else 'unknown'
line_info: str = "源代码 (%s, line %d)" % (src_path, lineno)
if source_line:
line_info += ":\n %d | %s" % (lineno, source_line)
self.Trans._ErrorStack.append((type(e).__name__, str(e), line_info))
raise
if Gen.builder and not Gen.builder.block.is_terminated:
Gen._EmitTempFrees()
@staticmethod
def _IsNoBreakMarkerStmt(Node: ast.stmt) -> bool:
"""是否 `c.NoBreak()` 标记语句(`fallthrough` 软关键字的脱糖形态)"""
if not isinstance(Node, ast.Expr) or not isinstance(Node.value, ast.Call):
return False
Fn: ast.expr = Node.value.func
return (isinstance(Fn, ast.Attribute) and isinstance(Fn.value, ast.Name)
and Fn.value.id == 'c' and Fn.attr == 'NoBreak')
def HandleExprLlvm(self, Node: ast.expr, VarType: ir.Type | None = None,
ConstWidthHint: int | None = None) -> ir.Value | None:
return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType, ConstWidthHint)