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 关键字已脱糖为 NoBreak())是 switch 的 # 标记语句,本身不产出 IR,语义由 HandlesMatch 消费(case 体因此 # 不自动跳出 switch);合法位置**只有 switch 的 case 体内**, # match(完全禁止 fallthrough)或 switch 之外一律 fail-fast。 if self._IsNoBreakMarkerStmt(Node): if not Gen.in_switch_case: from lib.core.LLVMCG.FuncGen import FailFastError raise FailFastError( "fallthrough 只能用在 switch 的 case 体内" "(match 完全禁止 fallthrough)") 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:循环 / switch / match-case 之外的 break 无处可跳, # 静默忽略只会让"提前退出"变成无声无效果(不兜底) from lib.core.LLVMCG.FuncGen import FailFastError raise FailFastError( "break 只能用在循环或 switch/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: """是否 `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.Name) and Fn.id == '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)