Files
TransPyC/lib/core/Handles/HandlesMatch.py
T
TermiNexus f19d25782f refactor(tpc): 退役 t/c 模块并将定宽类型升级为内建
删除 lib/includes/t.py、c.py,类型模型迁入 lib/core/TypeSystem.py;移除 IsTModule/_T_MODULE_NAMES 等名称判据,语法糖与内部标记统一为裸名;builtins 的 sizet/intN/uintN/fast/least/uchar/short/long 等改为编译器内建短名。
2026-10-18 13:00:58 +08:00

606 lines
37 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, Any
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 MatchHandle(BaseHandle):
@staticmethod
def _PatternCaptureNames(Pattern: ast.AST) -> list[str]:
"""模式中所有**捕获名**(递归 MatchOr/MatchClass/MatchSequence/MatchMapping)。
用于判定"该 case 是否必须登记绑定":有捕获却登记不上,case body 里的名字
就会变成"未定义名称",必须在**生成 body 之前**响亮失败,而不是留到取名时。
"""
Names: list[str] = []
if isinstance(Pattern, ast.MatchAs):
if Pattern.name:
Names.append(Pattern.name)
if Pattern.pattern is not None:
Names.extend(MatchHandle._PatternCaptureNames(Pattern.pattern))
elif isinstance(Pattern, ast.MatchStar):
if Pattern.name:
Names.append(Pattern.name)
elif isinstance(Pattern, (ast.MatchOr, ast.MatchSequence, ast.MatchClass, ast.MatchMapping)):
for p in (getattr(Pattern, 'patterns', None) or []):
Names.extend(MatchHandle._PatternCaptureNames(p))
for p in (getattr(Pattern, 'kwd_patterns', None) or []):
Names.extend(MatchHandle._PatternCaptureNames(p))
_rest: str | None = getattr(Pattern, 'rest', None)
if _rest:
Names.append(_rest)
return Names
@staticmethod
def _ValueLabelKey(Value: ast.expr) -> str:
"""MatchValue.value 的标签键:Constant / Name / Attribute 链"""
if isinstance(Value, ast.Constant):
Kind: str = Value.kind if Value.kind is not None else type(Value.value).__name__
return f"{Kind}:{Value.value!r}"
if isinstance(Value, ast.Name):
return f"Name:{Value.id}"
if isinstance(Value, ast.Attribute):
return f"Attr:{MatchHandle._ValueLabelKey(Value.value)}.{Value.attr}"
return f"{type(Value).__name__}"
@staticmethod
def _CaseLabelKey(Pattern: ast.pattern) -> str | None:
"""case 的 switch 标签键(None = 不参与重名判定)
- MatchValue → 'V:<值键>'(Constant 值 / Name / Attribute 链)
- MatchSingleton → 'S:<值>'(None/True/False)
- MatchClass → 'K:<变体名>'(cls 为 Name 用 id,Attribute 用链)
- MatchOr → 'O:<子模式键>'(子键任一不可比则整条不可比)
- MatchAs / MatchSequence 等 → None(通配/序列,不产出 switch 常量标签)
"""
if isinstance(Pattern, ast.MatchValue):
return f"V:{MatchHandle._ValueLabelKey(Pattern.value)}"
if isinstance(Pattern, ast.MatchSingleton):
return f"S:{Pattern.value!r}"
if isinstance(Pattern, ast.MatchClass):
Cls: ast.expr = Pattern.cls
if isinstance(Cls, ast.Name):
return f"K:{Cls.id}"
if isinstance(Cls, ast.Attribute):
return f"K:{MatchHandle._ValueLabelKey(Cls)}"
return None
if isinstance(Pattern, ast.MatchOr):
Parts: list[str | None] = [MatchHandle._CaseLabelKey(p) for p in Pattern.patterns]
if any(p is None for p in Parts):
return None
return "O:" + "|".join(Parts)
return None
def _HandleMatchLlvm(self, Node: ast.Match) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
# 重名 case 检测(fail-fast):**match 不允许重复 case 标签**——重复标签会让
# 某个臂永远不可达,且通常意味着漏改的分支。**switch 允许重复标签**(按书写
# 顺序,先出现者生效),故仅对 match 做值标签去重。
# 通配臂(match 的 `case _` / switch 的 `default`)两者都只允许一个。
# 在产出任何 IR 之前检查,保证报错即终止。报文前缀按 is_switch 区分。
KindLabel: str = 'switch' if Node.is_switch else 'match'
DefaultLabel: str = '`default`' if Node.is_switch else '`case _`'
SeenLabels: dict[str, int] = {}
DefaultCount: int = 0
for ci, case in enumerate(Node.cases):
Key: str | None = MatchHandle._CaseLabelKey(case.pattern)
if Key is None:
if isinstance(case.pattern, ast.MatchAs) and case.pattern.pattern is None:
DefaultCount += 1
continue
if not Node.is_switch and Key in SeenLabels:
from lib.core.LLVMCG.FuncGen import FailFastError
raise FailFastError(
f"match 出现重名 case:标签 '{Key}' 已在第 {SeenLabels[Key]} 个 case 使用,"
f"第 {ci} 个 case 重复(match 不允许重复 case 标签)")
SeenLabels[Key] = ci
if DefaultCount > 1:
from lib.core.LLVMCG.FuncGen import FailFastError
raise FailFastError(
f"{KindLabel} 出现 {DefaultCount} 个 {DefaultLabel}(通配/default 只允许一个)")
SubjectVal: ir.Value | None = self.HandleExprLlvm(Node.subject)
if not SubjectVal:
return
IsRenumMatch: bool = False
RenumName: str | None = None
SubjectPtr: ir.Value | None = None
if isinstance(Node.subject, ast.Name):
VarName: str = Node.subject.id
TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(VarName)
if TypeInfo and TypeInfo.IsRenum:
IsRenumMatch = True
RenumName = TypeInfo.Name
SubjectPtr = Gen._Load_var(VarName)
if not IsRenumMatch:
for case in Node.cases:
if isinstance(case.pattern, ast.MatchClass):
cls_node: ast.expr = case.pattern.cls
VariantName: str | None = None
QualifiedName: str | None = None
if isinstance(cls_node, ast.Name):
VariantName = cls_node.id
elif isinstance(cls_node, ast.Attribute):
VariantName = cls_node.attr
# Extract enum name for qualified lookup to avoid collision
# with same-name factory functions (e.g. def Ptr vs LLVMType.Ptr)
if isinstance(cls_node.value, ast.Attribute):
QualifiedName = f"{cls_node.value.attr}.{VariantName}"
elif isinstance(cls_node.value, ast.Name):
QualifiedName = f"{cls_node.value.id}.{VariantName}"
if VariantName:
# Try qualified name first (e.g., "LLVMType.Ptr") to avoid
# collision with same-name functions (e.g., def Ptr(...))
SymInfo: "SymbolTable.SymbolInfo" = None
if QualifiedName:
SymInfo = self.Trans.SymbolTable.lookup(QualifiedName)
if not (SymInfo and SymInfo.IsEnumMember):
SymInfo = self.Trans.SymbolTable.lookup(VariantName)
if SymInfo and SymInfo.IsEnumMember and SymInfo.EnumName:
EnumName: str = SymInfo.EnumName
EnumInfo: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(EnumName)
if EnumInfo and EnumInfo.IsRenum:
IsRenumMatch = True
RenumName = EnumName
if SubjectPtr is None:
SubjectPtr = self.HandleExprLlvm(Node.subject)
break
if IsRenumMatch and SubjectPtr:
self._HandleRenumMatchLlvm(Node, RenumName, SubjectPtr)
return
if not isinstance(SubjectVal.type, ir.IntType):
try:
SubjectVal = Gen.builder.ptrtoint(SubjectVal, ir.IntType(64), name="match_subj")
SubjectVal = Gen.builder.trunc(SubjectVal, ir.IntType(32), name="match_subj_i32")
except Exception: # 回退:ptrtoint 失败时直接返回
return
SwitchIntType: ir.IntType = SubjectVal.type
DefaultBB: ir.Block = Gen.func.append_basic_block(name="match.default")
AfterBB: ir.Block = Gen.func.append_basic_block(name="match.end")
CaseBBs: list[ir.Block] = []
CaseValues: list[ir.Value] = []
HasDefault: bool = False
HasNoBreak: list[bool] = []
for i, case in enumerate(Node.cases):
pattern: ast.pattern = case.pattern
if isinstance(pattern, ast.MatchValue):
Val: ir.Value | None = self.HandleExprLlvm(pattern.value)
if Val:
if not isinstance(Val, ir.Constant):
from lib.core.LLVMCG.FuncGen import FailFastError
raise FailFastError(
"switch/match 的 case 标签必须是编译期常量"
"(当前标签求值成运行期值,无法作为 switch 的 case 常量)")
CaseVal: ir.Value
if isinstance(Val.type, ir.IntType):
if Val.type != SwitchIntType:
if Val.type.width > SwitchIntType.width:
CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1))
else:
CaseVal = ir.Constant(SwitchIntType, Val.constant)
else:
CaseVal = Val
else:
try:
CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}")
except Exception: # 回退:ptrtoint 失败时设默认值 0
CaseVal = ir.Constant(SwitchIntType, 0)
CaseValues.append(CaseVal)
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
elif isinstance(pattern, ast.MatchOr):
for j, SubPattern in enumerate(pattern.patterns):
if isinstance(SubPattern, ast.MatchValue):
Val: ir.Value | None = self.HandleExprLlvm(SubPattern.value)
if Val:
if not isinstance(Val, ir.Constant):
from lib.core.LLVMCG.FuncGen import FailFastError
raise FailFastError(
"switch/match 的 case 标签必须是编译期常量"
"(当前标签求值成运行期值,无法作为 switch 的 case 常量)")
CaseVal: ir.Value
if isinstance(Val.type, ir.IntType):
if Val.type != SwitchIntType:
if Val.type.width > SwitchIntType.width:
CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1))
else:
CaseVal = ir.Constant(SwitchIntType, Val.constant)
else:
CaseVal = Val
else:
try:
CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}_{j}")
except Exception: # 回退:ptrtoint 失败时设默认值 0
CaseVal = ir.Constant(SwitchIntType, 0)
CaseValues.append(CaseVal)
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}_{j}"))
elif isinstance(pattern, ast.MatchSingleton):
if pattern.value is None:
CaseValues.append(ir.Constant(SwitchIntType, 0))
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
elif isinstance(pattern, ast.MatchAs):
if pattern.pattern is None:
HasDefault = True
CaseBBs.append(DefaultBB)
elif isinstance(pattern, ast.MatchSequence):
HasDefault = True
CaseBBs.append(DefaultBB)
elif isinstance(pattern, ast.MatchClass):
# 兜底处理:REnum 检测失败但 case 是 MatchClass(REnum 变体模式)
# 尝试从变体名查找 tag 值,按整数值处理
cls_node_mc: ast.expr = pattern.cls
VariantName_mc: str | None = None
QualifiedName_mc: str | None = None
if isinstance(cls_node_mc, ast.Name):
VariantName_mc = cls_node_mc.id
elif isinstance(cls_node_mc, ast.Attribute):
VariantName_mc = cls_node_mc.attr
if isinstance(cls_node_mc.value, ast.Attribute):
QualifiedName_mc = f"{cls_node_mc.value.attr}.{VariantName_mc}"
elif isinstance(cls_node_mc.value, ast.Name):
QualifiedName_mc = f"{cls_node_mc.value.id}.{VariantName_mc}"
TagValue_mc: int | None = None
SymInfo_mc: "SymbolTable.SymbolInfo" = None
if QualifiedName_mc:
SymInfo_mc = self.Trans.SymbolTable.lookup(QualifiedName_mc)
if not (SymInfo_mc and SymInfo_mc.IsEnumMember):
SymInfo_mc = self.Trans.SymbolTable.lookup(VariantName_mc)
if SymInfo_mc and SymInfo_mc.IsEnumMember:
TagValue_mc = SymInfo_mc.value
if TagValue_mc is not None:
# 兜底分支**不登记捕获绑定**(它按整数 tag 处理,无变体载荷可 GEP)。
# 因此只要该 case 有捕获,就必须在此 fail-fast —— 否则 case body 里的
# 绑定名随后变成"未定义名称"(现场 VpiReader.vp:1521 pointee_cs),
# 真因(外层 REnum 判定未成立)被掩盖。报文直接列出判据供定位。
_caps_mc: list[str] = self._PatternCaptureNames(pattern)
if _caps_mc:
from lib.core.LLVMCG.FuncGen import FailFastError
_en_mc: str | None = getattr(SymInfo_mc, 'EnumName', None)
_sym_en: "SymbolTable.SymbolInfo" = (
self.Trans.SymbolTable.lookup(_en_mc) if _en_mc else None)
_sym_v: "SymbolTable.SymbolInfo" = (
self.Trans.SymbolTable.lookup(VariantName_mc) if VariantName_mc else None)
raise FailFastError(
f"REnum 变体模式 '{QualifiedName_mc or VariantName_mc}' 含捕获 {_caps_mc},"
f"但外层 REnum 匹配判定未成立(IsRenumMatch=False)⇒ 兜底分支不登记捕获绑定,"
f"case body 里这些名字必然成为'未定义名称'。判据:"
f"符号表['{QualifiedName_mc}'] => "
f"IsEnumMember={getattr(SymInfo_mc, 'IsEnumMember', None)} "
f"value={getattr(SymInfo_mc, 'value', None)} EnumName={_en_mc!r};"
f"符号表['{_en_mc}'] => IsRenum={getattr(_sym_en, 'IsRenum', None)} "
f"IsStruct={getattr(_sym_en, 'IsStruct', None)} "
f"IsEnum={getattr(_sym_en, 'IsEnum', None)};"
f"符号表['{VariantName_mc}'] => "
f"IsEnumMember={getattr(_sym_v, 'IsEnumMember', None)} "
f"EnumName={getattr(_sym_v, 'EnumName', None)!r}"
)
CaseValues.append(ir.Constant(SwitchIntType, TagValue_mc))
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{VariantName_mc}"))
else:
# 变体名未找到,跳过此 case(fast-fail 已在外层处理)
pass
HasNoBreak.append(MatchHandle._HasNoBreakMarker(case.body) if case.body else False)
if not HasDefault:
CaseBBs.append(DefaultBB)
SwitchCases: list[tuple[ir.Value, ir.Block]] = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB]
switch_instr: ir.SwitchInstr = Gen.builder.switch(SubjectVal, DefaultBB)
for val, bb in SwitchCases:
switch_instr.add_case(val, bb)
CaseIdx: int = 0
for i, case in enumerate(Node.cases):
pattern: ast.pattern = case.pattern
if isinstance(pattern, ast.MatchOr):
NumSubCases: int = len(pattern.patterns)
for j in range(NumSubCases):
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
self._HandleMatchCaseBody(Gen, case.body, AfterBB, Node.is_switch)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
else:
Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB))
CaseIdx += 1
elif isinstance(pattern, (ast.MatchValue, ast.MatchSingleton)):
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
self._HandleMatchCaseBody(Gen, case.body, AfterBB, Node.is_switch)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
else:
Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB))
CaseIdx += 1
elif isinstance(pattern, ast.MatchAs):
if pattern.pattern is None:
Gen.builder.position_at_start(DefaultBB)
self._HandleMatchCaseBody(Gen, case.body, AfterBB, Node.is_switch)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
else:
Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB))
CaseIdx += 1
elif isinstance(pattern, ast.MatchSequence):
Gen.builder.position_at_start(DefaultBB)
self._HandleMatchCaseBody(Gen, case.body, AfterBB, Node.is_switch)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
else:
Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB))
CaseIdx += 1
elif isinstance(pattern, ast.MatchClass):
# 兜底处理:MatchClass 在非 REnum 路径的 case body 生成
# case 收集阶段已创建 CaseBB,此处生成 body
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
self._HandleMatchCaseBody(Gen, case.body, AfterBB, Node.is_switch)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
else:
Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB))
CaseIdx += 1
if not HasDefault:
Gen.builder.position_at_start(DefaultBB)
Gen.builder.branch(AfterBB)
elif not any(isinstance(pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(pattern, ast.MatchSequence) for c in Node.cases):
Gen.builder.position_at_start(DefaultBB)
Gen.builder.branch(AfterBB)
Gen.builder.position_at_start(AfterBB)
@staticmethod
def _HasNoBreakMarker(Stmts: list[ast.stmt]) -> bool:
"""case 体(含其嵌套 body/orelse)是否含 `fallthrough` 标记(NoBreak())"""
for stmt in Stmts:
if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call):
if isinstance(stmt.value.func, ast.Name) and stmt.value.func.id == 'NoBreak':
return True
NestedBody: Any = getattr(stmt, 'body', None)
if NestedBody and isinstance(NestedBody, list) and MatchHandle._HasNoBreakMarker(NestedBody):
return True
NestedElse: Any = getattr(stmt, 'orelse', None)
if NestedElse and isinstance(NestedElse, list) and MatchHandle._HasNoBreakMarker(NestedElse):
return True
return False
def _HandleMatchCaseBody(self, Gen: "Translator.LlvmGen",
Body: list[ast.stmt], AfterBB: ir.Block,
IsSwitch: bool) -> None:
"""翻译一个 case 体:case 体内的 break 目标是 AfterBB(C switch 语义)
- case 内 break 跳出 **match/switch**(而非外层循环):翻译前把 AfterBB
压入 loop_break_targets,翻译完弹出(外层循环目标不受影响)。
- 同时把 Gen.in_switch_case 置为 IsSwitch(进出恢复):供 `fallthrough`
标记语句判定合法性 —— 只有 switch 的 case 体内才允许,写进 match
(完全禁止 fallthrough)或 switch 之外由 HandlesBody fail-fast。
"""
Targets: list = Gen.loop_break_targets
Targets.append(AfterBB)
PrevInSwitch: bool = Gen.in_switch_case
Gen.in_switch_case = IsSwitch
try:
self.HandleBodyLlvm(Body)
finally:
Gen.in_switch_case = PrevInSwitch
Targets.pop()
@staticmethod
def _FallThroughTarget(CaseBBs: list[ir.Block], CaseIdx: int, AfterBB: ir.Block) -> ir.Block:
"""fallthrough 的落点:下一个 case 的 body(无后继槽位时落到 AfterBB)
`fallthrough`(vast 关键字,脱糖为 NoBreak())表示"本 case 不自动
跳出 switch",直接落到下一个 case 的 body(对齐 C 的 [[fallthrough]])。
"""
NextIdx: int = CaseIdx + 1
if 0 <= NextIdx < len(CaseBBs):
return CaseBBs[NextIdx]
return AfterBB
def _HandleRenumMatchLlvm(self, Node: ast.Match, RenumName: str, SubjectPtr: ir.Value) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if isinstance(SubjectPtr.type, ir.PointerType) and isinstance(SubjectPtr.type.pointee, ir.PointerType):
SubjectPtr = Gen._load(SubjectPtr, name="Load_match_subj")
# Bug fix: HandleExprLlvm 可能对 REnum 字段执行了 load,返回值而非指针。
# 情况1: SubjectPtr 不是指针类型(如 IntType)→ alloca REnum 结构体 + store
# 情况2: SubjectPtr 是指针但 pointee 不是结构体(如 i32* 指向 __tag)→ bitcast
NeedAlloca: bool = not isinstance(SubjectPtr.type, ir.PointerType)
NeedBitcast: bool = (isinstance(SubjectPtr.type, ir.PointerType) and
not isinstance(SubjectPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)))
if NeedAlloca or NeedBitcast:
RenumStructType: Any = Gen.structs.get(RenumName)
if RenumStructType is None:
# 跨模块编译时 REnum 结构体可能尚未在 Gen.structs 中注册
# (如 import llvmlite 后 LLVMType 仅在符号表,Gen.structs 无条目)。
# 使用 _get_or_create_struct 按需创建(可能为 opaque)。
RenumStructType = Gen._get_or_create_struct(RenumName)
if NeedAlloca:
AllocaPtr: ir.Value = Gen._allocaEntry(RenumStructType, name="match_subj_alloca")
CastedPtr: ir.Value = Gen.builder.bitcast(AllocaPtr, ir.PointerType(SubjectPtr.type), name="match_subj_cast")
Gen._store(SubjectPtr, CastedPtr)
SubjectPtr = AllocaPtr
else:
SubjectPtr = Gen.builder.bitcast(SubjectPtr, ir.PointerType(RenumStructType), name="match_subj_recast")
# REnum 布局为 { i32 __tag, <payload> },tag 在偏移 0。
# 使用 bitcast 到 i32* 替代 gep [0,0],兼容 opaque 结构体
# (跨模块编译时 REnum 结构体可能未 set_body,gep 会失败)。
tag_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, ir.PointerType(ir.IntType(32)), name="match_tag_ptr")
TagVal: ir.Value = Gen._load(tag_ptr, name="match_tag_val")
DefaultBB: ir.Block = Gen.func.append_basic_block(name="match.default")
AfterBB: ir.Block = Gen.func.append_basic_block(name="match.end")
CaseBBs: list[ir.Block] = []
CaseValues: list[ir.Value] = []
CaseBindings: list[list[tuple[str, str, ir.Type, int]]] = []
HasDefault: bool = False
HasNoBreak: list[bool] = []
for i, case in enumerate(Node.cases):
pattern: ast.pattern = case.pattern
bindings: list[tuple[str, str, ir.Type, int]] = []
if isinstance(pattern, ast.MatchClass):
cls_node: ast.expr = pattern.cls
VariantName: str | None = None
QualifiedName: str | None = None
if isinstance(cls_node, ast.Name):
VariantName = cls_node.id
elif isinstance(cls_node, ast.Attribute):
VariantName = cls_node.attr
if isinstance(cls_node.value, ast.Attribute):
QualifiedName = f"{cls_node.value.attr}.{VariantName}"
elif isinstance(cls_node.value, ast.Name):
QualifiedName = f"{cls_node.value.id}.{VariantName}"
if VariantName:
TagValue: int | None = None
SymInfo: "SymbolTable.SymbolInfo" = None
if QualifiedName:
SymInfo = self.Trans.SymbolTable.lookup(QualifiedName)
if not (SymInfo and SymInfo.IsEnumMember):
SymInfo = self.Trans.SymbolTable.lookup(VariantName)
if SymInfo and SymInfo.IsEnumMember:
TagValue = SymInfo.value
if TagValue is not None:
CaseValues.append(ir.Constant(ir.IntType(32), TagValue))
CaseBB: ir.Block = Gen.func.append_basic_block(name=f"match.case_{VariantName}")
CaseBBs.append(CaseBB)
# 变体嵌套结构体按需补发:导入模块侧 stub 只声明主 REnum,
# 不含 `<REnum>_<Variant>` 声明(见 _EnsureRenumVariantStruct)。
NestedStructName: str = self._EnsureRenumVariantStruct(Gen, RenumName, VariantName)
members: list[tuple[str, ir.Type]] = Gen.class_members.get(NestedStructName, [])
payLoad_members: list[tuple[str, ir.Type]] = [(n, t) for n, t in members if n != '__tag']
# 模式捕获必须能全部绑定:绑不上就在此 fail-fast,绝不让 case body
# 里的绑定名留到后面变成"未定义名称"(现场 VpiReader.vp:1521 pointee_cs)。
_captures: list[str] = [p.name for p in pattern.patterns
if isinstance(p, ast.MatchAs) and p.name]
if _captures and len(payLoad_members) < len(_captures):
from lib.core.LLVMCG.FuncGen import FailFastError
raise FailFastError(
f"REnum 变体模式 '{RenumName}.{VariantName}' 的载荷成员不足,"
f"无法绑定模式捕获 {_captures}:"
f"class_members['{NestedStructName}']={len(members)} 项"
f"(去 __tag 后载荷 {len(payLoad_members)} 项);"
f"structs 命中={'有' if NestedStructName in Gen.structs else '无'};"
f"同前缀 structs 键="
f"{[k for k in Gen.structs if k.startswith(RenumName + '_')][:8]}"
)
for j, sub_pat in enumerate(pattern.patterns):
if isinstance(sub_pat, ast.MatchAs) and sub_pat.name and j < len(payLoad_members):
bindings.append((sub_pat.name, payLoad_members[j][0], payLoad_members[j][1], j))
CaseBindings.append(bindings)
else:
CaseValues.append(ir.Constant(ir.IntType(32), 0))
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
CaseBindings.append([])
elif isinstance(pattern, ast.MatchValue):
Val: ir.Value | None = self.HandleExprLlvm(pattern.value)
if Val:
CaseVal: ir.Value
if isinstance(Val.type, ir.IntType):
CaseVal = Val
else:
try:
CaseVal = Gen.builder.ptrtoint(Val, ir.IntType(32), name=f"case_val_{i}")
except Exception: # 回退:ptrtoint 失败时设默认值 0
CaseVal = ir.Constant(ir.IntType(32), 0)
CaseValues.append(CaseVal)
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
CaseBindings.append([])
elif isinstance(pattern, ast.MatchAs):
if pattern.pattern is None:
HasDefault = True
CaseBBs.append(DefaultBB)
CaseBindings.append([])
elif isinstance(pattern, ast.MatchSequence):
HasDefault = True
CaseBBs.append(DefaultBB)
CaseBindings.append([])
HasNoBreak.append(MatchHandle._HasNoBreakMarker(case.body) if case.body else False)
if not HasDefault:
CaseBBs.append(DefaultBB)
SwitchCases: list[tuple[ir.Value, ir.Block]] = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB]
switch_instr: ir.SwitchInstr = Gen.builder.switch(TagVal, DefaultBB)
for val, bb in SwitchCases:
switch_instr.add_case(val, bb)
CaseIdx: int = 0
for i, case in enumerate(Node.cases):
pattern: ast.pattern = case.pattern
if isinstance(pattern, ast.MatchClass):
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
bindings: list[tuple[str, str, ir.Type, int]] = CaseBindings[CaseIdx] if CaseIdx < len(CaseBindings) else []
cls_node: ast.expr = pattern.cls
VariantName: str | None = None
if isinstance(cls_node, ast.Name):
VariantName = cls_node.id
elif isinstance(cls_node, ast.Attribute):
VariantName = cls_node.attr
if VariantName:
NestedStructName: str = f"{RenumName}_{VariantName}"
if NestedStructName in Gen.structs:
NestedStructType: ir.Type = Gen.structs[NestedStructName]
# 变体 struct 可能仍是 opaque(body 未 set_body / 同名两份实例)
# ⇒ 先取已具化实例,否则 GEP 在编译期算不出元素类型(判据见
# ExprAttrHandle._ConcretePointeeFor)。
_TwV: Any = self.Trans.ExprAttrHandle._ConcretePointeeFor(
Gen, NestedStructName, NestedStructType)
if isinstance(_TwV, ir.IdentifiedStructType):
NestedStructType = _TwV
NestedStructPtrType: ir.PointerType = ir.PointerType(NestedStructType)
variant_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, NestedStructPtrType, name=f"match_cast_{VariantName}")
for bind_name, member_name, member_type, member_idx in bindings:
elem_ptr: ir.Value = Gen.builder.gep(variant_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), member_idx + 1)], name=f"match_{bind_name}")
# REnum 嵌套结构体共享 max_variant_struct 布局,成员类型可能与
# 结构体字段类型不一致。bitcast 到成员类型以确保后续 load 得到正确类型。
if isinstance(elem_ptr.type, ir.PointerType) and elem_ptr.type.pointee != member_type:
elem_ptr = Gen.builder.bitcast(elem_ptr, ir.PointerType(member_type), name=f"match_{bind_name}_cast")
Gen.variables[bind_name] = elem_ptr
self._HandleMatchCaseBody(Gen, case.body, AfterBB, Node.is_switch)
for bind_name, _, _, _ in bindings:
if bind_name in Gen.variables:
del Gen.variables[bind_name]
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
else:
Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB))
CaseIdx += 1
elif isinstance(pattern, ast.MatchValue):
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
self._HandleMatchCaseBody(Gen, case.body, AfterBB, Node.is_switch)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
else:
Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB))
CaseIdx += 1
elif isinstance(pattern, ast.MatchAs):
if pattern.pattern is None:
Gen.builder.position_at_start(DefaultBB)
self._HandleMatchCaseBody(Gen, case.body, AfterBB, Node.is_switch)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
else:
Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB))
CaseIdx += 1
elif isinstance(pattern, ast.MatchSequence):
Gen.builder.position_at_start(DefaultBB)
self._HandleMatchCaseBody(Gen, case.body, AfterBB, Node.is_switch)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
else:
Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB))
CaseIdx += 1
if not HasDefault:
Gen.builder.position_at_start(DefaultBB)
Gen.builder.branch(AfterBB)
elif not any(isinstance(pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(pattern, ast.MatchSequence) for c in Node.cases):
Gen.builder.position_at_start(DefaultBB)
Gen.builder.branch(AfterBB)
Gen.builder.position_at_start(AfterBB)