删除 lib/includes/t.py、c.py,类型模型迁入 lib/core/TypeSystem.py;移除 IsTModule/_T_MODULE_NAMES 等名称判据,语法糖与内部标记统一为裸名;builtins 的 sizet/intN/uintN/fast/least/uchar/short/long 等改为编译器内建短名。
606 lines
37 KiB
Python
606 lines
37 KiB
Python
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) |