_handle_simple_match 的 MatchOr 分支此前只把 pats[0] 译成 case 值 → switch value: case 1 | 2 中 2 落 default(LogicFlowTest SwitchMultiValueTest(2) != 10)。改为按臂记录 MatchOr 节点,建 sw 链时逐备选 new_switch_case 挂同一 body(等价 C 的 case 1: case 2:);_handle_guarded_simple_match 同款:cond 改为各备选 subj==cv 的 OR 再与 guard 取与。非 MatchOr 路径逐字不变;非值备选改为 fail-fast(原为静默丢弃)。
1918 lines
103 KiB
Plaintext
1918 lines
103 KiB
Plaintext
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import viperlib
|
||
import lib.core.Gen.Translator as HT
|
||
import lib.core.Gen.GenTypes as GenTypes
|
||
import lib.core.Gen.Generator as Generator
|
||
|
||
|
||
# ============================================================
|
||
# MatchGenMixin - match 语句翻译 Mixin(P6 方法化)
|
||
# ============================================================
|
||
|
||
|
||
# match case 数量上限(原 HandlesMatch.MAX_MATCH_CASES)
|
||
define MAX_MATCH_CASES = 32
|
||
|
||
# 作用域种类常量(与 HandlesVar 的 Scope.Kind 区分,原 HandlesMatch.SCOPE_MATCH)
|
||
define SCOPE_MATCH = 6
|
||
|
||
# match 翻译最大递归深度(match → case body → translate_value → 嵌套 match)。
|
||
# 入口计数出口递减,超限即 fail-fast:AST 自引用环可致无限递归 → 栈溢出。
|
||
define MATCH_TRANSLATE_MAX_DEPTH = 64
|
||
|
||
|
||
novirtual class MatchGenMixin:
|
||
"""match 语句翻译 Mixin(P6 方法化)"""
|
||
|
||
# _case_tail_unreachable - case 体末尾结构性不可达判定
|
||
# case 体翻译后当前块未终止、且末句是控制流语句(If/While/For/Match)且其
|
||
# merge 结构性不可达(全分支 return)时,当前块即该 merge(无 terminator),
|
||
# 与 HandlesIf L309-315 / ClassGenVTable L1084 同语义补 unreachable。
|
||
# 返回 1=已补 unreachable(调用方不应 br end_bb);0=正常收尾(应 br end_bb)。
|
||
# 不含 Try/With:其处理器不维护 _ctrl_merge_reachable,避免残留值误判。
|
||
Gen: Generator.Generator*
|
||
def _case_tail_unreachable(self, trans: HT.Translator*,
|
||
builder: llvmlite.IRBuilder*,
|
||
body_list: list[ast.AST*]*) -> int:
|
||
if trans is None or builder is None:
|
||
return 0
|
||
if llvmlite.builder_cur_block_is_terminated(builder) != 0:
|
||
return 0
|
||
if body_list is None or len(body_list) == 0:
|
||
return 0
|
||
lst: ast.AST* = body_list.get(len(body_list) - 1)
|
||
if lst is None:
|
||
return 0
|
||
lk: int = lst.kind()
|
||
if lk != ast.ASTKind.If and lk != ast.ASTKind.While \
|
||
and lk != ast.ASTKind.For and lk != ast.ASTKind.Match:
|
||
return 0
|
||
if trans._ctrl_merge_reachable != 0:
|
||
return 0
|
||
llvmlite.build_unreachable(builder)
|
||
return 1
|
||
|
||
# ============================================================
|
||
# translate_match - match 语句主入口,返回 0
|
||
# (迁移自 HandlesMatch.MatchHandle.Handle)
|
||
# ============================================================
|
||
def translate_match(self, trans: HT.Translator*,
|
||
node: ast.AST*) -> int:
|
||
"""match 语句翻译主入口(深度守卫包装器,原逻辑见 _translate_match_impl)"""
|
||
if trans is not None:
|
||
if trans.MatchTranslateDepth >= MATCH_TRANSLATE_MAX_DEPTH:
|
||
self.Gen.TypeGenErr.fatal_error(node, "match 翻译嵌套过深(疑似 AST 自引用环或翻译 bug)", "RecursionError")
|
||
trans.MatchTranslateDepth += 1
|
||
mret: int = self._translate_match_impl(trans, node)
|
||
if trans is not None:
|
||
trans.MatchTranslateDepth -= 1
|
||
return mret
|
||
|
||
def _translate_match_impl(self, trans: HT.Translator*,
|
||
node: ast.AST*) -> int:
|
||
if node is None:
|
||
return 0
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
func: llvmlite.Function* = trans._cur_func
|
||
if builder is None or func is None:
|
||
return 0
|
||
|
||
# match merge 可达性重置(分派前初始化为 0)。标志必须由各处理函数
|
||
# (_handle_renum_match/_handle_sequence_match/_handle_simple_match)
|
||
# 内部声明并收尾覆盖:声明在 Handle 这里会退化为隐式全局,跨 match 污染。
|
||
trans._ctrl_merge_reachable = 0
|
||
|
||
m_node: ast.Match* = ast.Match*(node)
|
||
|
||
# 重名 case 检测(fail-fast):**match 不允许重复 case 标签**(重复标签让
|
||
# 某个臂永远不可达,且常意味着漏改的分支);**switch 允许重复标签**(按书写
|
||
# 顺序,先出现者生效),故仅对 match 做值标签去重。
|
||
# 通配臂(match 的 `case _` / switch 的 `default`):**无 guard** 的通配臂
|
||
# 两者都只允许一个(真正的 default);**带 guard** 的通配臂(`case _ if ...`)
|
||
# 允许多个(唯一性由各自的 guard 区分,见 _handle_guarded_simple_match)。
|
||
# 在任何 IR 产出之前检查,保证报错即终止。报文前缀按 is_switch 区分。
|
||
kind_label: str = "match"
|
||
default_label: str = "`case _`"
|
||
if m_node.is_switch != 0:
|
||
kind_label = "switch"
|
||
default_label = "`default`"
|
||
cases_chk: list[ast.AST*]* = m_node.cases
|
||
if cases_chk is not None:
|
||
ccn: sizet = len(cases_chk)
|
||
default_cnt: int = 0
|
||
dci: int = 0
|
||
while dci < ccn:
|
||
dcase: ast.AST* = cases_chk.get(dci)
|
||
if dcase is not None and dcase.kind() == ast.ASTKind.MatchCase:
|
||
dpat: ast.AST* = rawptr[ast.MatchCase](dcase).pattern
|
||
if dpat is not None:
|
||
if dpat.kind() == ast.ASTKind.MatchAs \
|
||
and rawptr[ast.MatchAs](dpat).pattern is None:
|
||
# 只统计**无 guard** 的通配臂:带 guard 的 `case _ if ...`
|
||
# 允许多个(各自 guard 区分),不当 default 计
|
||
if rawptr[ast.MatchCase](dcase).guard is None:
|
||
default_cnt = default_cnt + 1
|
||
elif m_node.is_switch == 0:
|
||
dcj: int = dci + 1
|
||
while dcj < ccn:
|
||
dcase2: ast.AST* = cases_chk.get(dcj)
|
||
if dcase2 is not None and dcase2.kind() == ast.ASTKind.MatchCase:
|
||
dpat2: ast.AST* = rawptr[ast.MatchCase](dcase2).pattern
|
||
if self._case_label_same(dpat, dpat2) != 0:
|
||
self.Gen.TypeGenErr.fatal_error(dcase2,
|
||
f"match 出现重名 case:第 {dci} 与第 {dcj} 个 case 的标签相同(match 不允许重复 case 标签)",
|
||
"SyntaxError")
|
||
dcj = dcj + 1
|
||
dci = dci + 1
|
||
if default_cnt > 1:
|
||
self.Gen.TypeGenErr.fatal_error(node,
|
||
f"{kind_label} 出现 {default_cnt} 个{default_label}(无 guard 的通配/default 只允许一个;带 guard 的 `case _ if ...` / `default if ...` 可有多个)", "SyntaxError")
|
||
|
||
# 1. 求值 subject
|
||
subject_node: ast.AST* = m_node.subject
|
||
if subject_node is None:
|
||
return 0
|
||
# 序列匹配(match (a, b): case (x, y): ...)走独立路径:
|
||
# Tuple/List subject 无法用 translate_value 求值(会返回 None),
|
||
# 提前分派到 _handle_sequence_match,避免 fail-fast 误报。
|
||
sk_seq: int = subject_node.kind()
|
||
if sk_seq == ast.ASTKind.Tuple or sk_seq == ast.ASTKind.List:
|
||
return self._handle_sequence_match(trans, m_node, subject_node)
|
||
subject_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, subject_node,
|
||
trans._funcs, trans._func_count, trans)
|
||
if subject_val is None:
|
||
# fail-fast: match subject 翻译失败
|
||
self.Gen.TypeGenErr.fatal_error(subject_node, "match subject 翻译失败", "TypeError")
|
||
|
||
# 2. 检测是否 REnum match
|
||
is_renum: int = 0
|
||
renum_name: str = None
|
||
subject_ptr: llvmlite.Value* = None
|
||
|
||
# 2a. 若 subject 是 Name,查变量注解类名
|
||
if subject_node.kind() == ast.ASTKind.Name:
|
||
nm: ast.Name* = ast.Name*(subject_node)
|
||
if nm.id is not None:
|
||
entry: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id)
|
||
entry_annot: str = self.Gen.VarGen.var_annot_class_name(entry)
|
||
if entry_annot is not None \
|
||
and (self.Gen.ClassGenEnum._is_renum_class_name(entry_annot) != 0
|
||
or self.Gen.ClassGenEnum._is_renum_by_entry(entry_annot) != 0):
|
||
is_renum = 1
|
||
renum_name = entry_annot
|
||
subject_ptr = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)
|
||
|
||
# 2b. 若未确定,遍历 cases 查 MatchClass 变体
|
||
if is_renum == 0:
|
||
cases_list: list[ast.AST*]* = m_node.cases
|
||
if cases_list is not None:
|
||
cn: sizet = len(cases_list)
|
||
ci: int = 0
|
||
while ci < cn and is_renum == 0:
|
||
case_node: ast.AST* = cases_list.get(ci)
|
||
if case_node is not None \
|
||
and case_node.kind() == ast.ASTKind.MatchCase:
|
||
mc: rawptr[ast.MatchCase] = (rawptr[ast.MatchCase])(case_node)
|
||
pat: ast.AST* = mc.pattern
|
||
if pat is not None \
|
||
and pat.kind() == ast.ASTKind.MatchClass:
|
||
rnm: str = self._extract_renum_name_from_cls(pat)
|
||
if rnm is not None \
|
||
and (self.Gen.ClassGenEnum._is_renum_class_name(rnm) != 0
|
||
or self.Gen.ClassGenEnum._is_renum_by_entry(rnm) != 0):
|
||
is_renum = 1
|
||
renum_name = rnm
|
||
if subject_ptr is None:
|
||
subject_ptr = subject_val
|
||
ci = ci + 1
|
||
|
||
# 3. 分派
|
||
if is_renum != 0 and subject_ptr is not None:
|
||
return self._handle_renum_match(trans, m_node, renum_name, subject_ptr)
|
||
return self._handle_simple_match(trans, m_node, subject_val)
|
||
|
||
# ============================================================
|
||
# _extract_renum_name_from_cls - 从 MatchClass.cls 提取 REnum 类名
|
||
#
|
||
# LLVMType.Ptr -> Attribute(value=Name('LLVMType'), attr='Ptr') -> 'LLVMType'
|
||
# llvmlite.LLVMType.Ptr -> Attribute(Attribute(Name('llvmlite'),'LLVMType'),'Ptr') -> 'LLVMType'
|
||
# Ptr -> Name('Ptr') -> 遍历查找
|
||
# ============================================================
|
||
def _extract_renum_name_from_cls(self,
|
||
pattern: ast.AST*) -> str:
|
||
if pattern is None:
|
||
return None
|
||
mc: rawptr[ast.MatchClass] = rawptr[ast.MatchClass](pattern)
|
||
cls_node: ast.AST* = mc.cls
|
||
if cls_node is None:
|
||
return None
|
||
# Attribute 形式
|
||
if cls_node.kind() == ast.ASTKind.Attribute:
|
||
at: ast.Attribute* = ast.Attribute*(cls_node)
|
||
if at.value is not None:
|
||
if at.value.kind() == ast.ASTKind.Name:
|
||
inner_nm: ast.Name* = ast.Name*(at.value)
|
||
return inner_nm.id
|
||
if at.value.kind() == ast.ASTKind.Attribute:
|
||
inner_at: ast.Attribute* = (ast.Attribute*)(at.value)
|
||
return inner_at.attr
|
||
# Name 形式:遍历所有 REnum 类反查
|
||
if cls_node.kind() == ast.ASTKind.Name:
|
||
nm: ast.Name* = ast.Name*(cls_node)
|
||
return self._find_renum_class_for_variant(nm.id)
|
||
return None
|
||
|
||
# ============================================================
|
||
# _extract_variant_name_from_cls - 从 MatchClass.cls 提取变体名
|
||
# ============================================================
|
||
def _extract_variant_name_from_cls(self,
|
||
pattern: ast.AST*) -> str:
|
||
if pattern is None:
|
||
return None
|
||
mc: rawptr[ast.MatchClass] = rawptr[ast.MatchClass](pattern)
|
||
cls_node: ast.AST* = mc.cls
|
||
if cls_node is None:
|
||
return None
|
||
if cls_node.kind() == ast.ASTKind.Attribute:
|
||
at: ast.Attribute* = ast.Attribute*(cls_node)
|
||
return at.attr
|
||
if cls_node.kind() == ast.ASTKind.Name:
|
||
nm: ast.Name* = ast.Name*(cls_node)
|
||
return nm.id
|
||
return None
|
||
|
||
# ============================================================
|
||
# _find_renum_class_for_variant - 从变体名反查 REnum 类名
|
||
#
|
||
# P5-2 后 REnum 变体表迁入 gen 字段(RenumClassNames/RenumClassCount),
|
||
# 模块级 _renum_class_* 已失效,统一委托到 gen._lookup_renum_variant。
|
||
# ============================================================
|
||
def _find_renum_class_for_variant(self, variant_name: str) -> str:
|
||
if variant_name is None:
|
||
return None
|
||
return self.Gen.ClassGenEnum._lookup_renum_variant(variant_name)
|
||
|
||
# ============================================================
|
||
# _value_label_same / _case_label_same - 重名 case 判定(switch 标签比较)
|
||
#
|
||
# C 的 switch 不允许重复 case 标签:重复标签会让某个臂永远不可达,且通常
|
||
# 意味着漏改的分支。只比较 switch 标签本身:
|
||
# MatchValue(常量 / 名字 / 属性链)、MatchSingleton(None)、MatchClass(变体名);
|
||
# MatchOr 逐个子模式两两比较;MatchAs / MatchSequence 无 switch 标签,恒不等。
|
||
# ============================================================
|
||
def _value_label_same(self, a: ast.AST*, b: ast.AST*) -> int:
|
||
"""两个 `case` 值节点是否等价(常量值 / 名字 / 属性链)"""
|
||
if a is None or b is None:
|
||
return 0
|
||
ka: int = a.kind()
|
||
if ka != b.kind():
|
||
return 0
|
||
if ka == ast.ASTKind.Constant:
|
||
ca: ast.Constant* = ast.Constant*(a)
|
||
cb: ast.Constant* = ast.Constant*(b)
|
||
if ca.const_kind != cb.const_kind:
|
||
return 0
|
||
if ca.const_kind == ast.CONST_STR:
|
||
if ca.str_val is not None and cb.str_val is not None \
|
||
and string.strcmp(ca.str_val, cb.str_val) == 0:
|
||
return 1
|
||
return 0
|
||
if ca.const_kind == ast.CONST_FLOAT:
|
||
if ca.float_val == cb.float_val:
|
||
return 1
|
||
return 0
|
||
# 整数 / 布尔 / 字符码
|
||
if ca.int_val == cb.int_val:
|
||
return 1
|
||
return 0
|
||
if ka == ast.ASTKind.Name:
|
||
na: ast.Name* = ast.Name*(a)
|
||
nb: ast.Name* = ast.Name*(b)
|
||
if na.id is not None and nb.id is not None and string.strcmp(na.id, nb.id) == 0:
|
||
return 1
|
||
return 0
|
||
if ka == ast.ASTKind.Attribute:
|
||
aa: ast.Attribute* = ast.Attribute*(a)
|
||
ab: ast.Attribute* = ast.Attribute*(b)
|
||
if aa.attr is None or ab.attr is None or string.strcmp(aa.attr, ab.attr) != 0:
|
||
return 0
|
||
return self._value_label_same(aa.value, ab.value)
|
||
return 0
|
||
|
||
def _case_label_same(self, a: ast.AST*, b: ast.AST*) -> int:
|
||
"""两个 case 模式是否有相同的 switch 标签"""
|
||
if a is None or b is None:
|
||
return 0
|
||
ka: int = a.kind()
|
||
if ka != b.kind():
|
||
return 0
|
||
if ka == ast.ASTKind.MatchValue:
|
||
av: ast.AST* = rawptr[ast.MatchValue](a).value
|
||
bv: ast.AST* = rawptr[ast.MatchValue](b).value
|
||
return self._value_label_same(av, bv)
|
||
if ka == ast.ASTKind.MatchSingleton:
|
||
return 1 # MatchSingleton 只可能是 None
|
||
if ka == ast.ASTKind.MatchClass:
|
||
an: str = self._extract_variant_name_from_cls(a)
|
||
bn: str = self._extract_variant_name_from_cls(b)
|
||
if an is None or bn is None:
|
||
return 0
|
||
if string.strcmp(an, bn) == 0:
|
||
return 1
|
||
return 0
|
||
if ka == ast.ASTKind.MatchOr:
|
||
ap: list[ast.AST*]* = rawptr[ast.MatchOr](a).patterns
|
||
bp: list[ast.AST*]* = rawptr[ast.MatchOr](b).patterns
|
||
if ap is None or bp is None or len(ap) != len(bp):
|
||
return 0
|
||
oi: int = 0
|
||
while oi < len(ap):
|
||
if self._case_label_same(ap.get(oi), bp.get(oi)) == 0:
|
||
return 0
|
||
oi = oi + 1
|
||
return 1
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _has_no_break - 检测 case body 是否要求 fallthrough(落到下一个 case)
|
||
#
|
||
# 只认 `fallthrough` 关键字语句(ASTKind.FallThrough)。该语句只可能在 switch
|
||
# 的 case 体内出现(translate_fallthrough 已对 match / switch 之外 fail-fast),
|
||
# 故此处无需再判上下文。
|
||
# ============================================================
|
||
def _has_no_break(self, body_list: list[ast.AST*]*) -> int:
|
||
if body_list is None:
|
||
return 0
|
||
n: sizet = len(body_list)
|
||
i: int = 0
|
||
while i < n:
|
||
stmt: ast.AST* = body_list.get(i)
|
||
if stmt is not None and stmt.kind() == ast.ASTKind.FallThrough:
|
||
return 1
|
||
i = i + 1
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _handle_renum_match - REnum 路径
|
||
#
|
||
# 1. bitcast subject 到 i32* 读 __tag
|
||
# 2. 收集 case 值 + 创建 BB + 构建 SwitchCase 链表
|
||
# 3. 发射 build_switch
|
||
# 4. 翻译每个 case body(含作用域隔离 + 变体字段绑定)
|
||
# ============================================================
|
||
def _handle_renum_match(self, trans: HT.Translator*,
|
||
node: ast.Match*,
|
||
renum_name: str,
|
||
subject_ptr: llvmlite.Value*) -> int:
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
func: llvmlite.Function* = trans._cur_func
|
||
# 局部记录本 renum match 是否有 br 进入 end_bb,收尾时覆盖
|
||
# _ctrl_merge_reachable(case 体内嵌套 If 无 else + return 会把全局
|
||
# 标志置 1,全 case return 的 match 被误判 merge 可达 → 函数收尾
|
||
# fail-fast "流程掉出末尾"。声明必须在本函数内——放 Handle 分派
|
||
# 函数里会使本函数引用退化为隐式全局,跨 match 污染)。
|
||
rm_merge_reach: int = 0
|
||
|
||
# guard 守卫(match/switch 分支条件守卫):本路径用 switch(tag) 一次性分发,
|
||
# **不评估 guard**——带 guard 的臂会被静默忽略(可能选错分支)。禁止静默兜底:
|
||
# 一旦存在带 guard 的臂,在任何 IR 产出之前 fail-fast 报错。
|
||
rn_cases: list[ast.AST*]* = node.cases
|
||
if rn_cases is not None:
|
||
rn_n: sizet = len(rn_cases)
|
||
rn_i: int = 0
|
||
while rn_i < rn_n:
|
||
rn_case: ast.AST* = rn_cases.get(rn_i)
|
||
if rn_case is not None and rn_case.kind() == ast.ASTKind.MatchCase:
|
||
if rawptr[ast.MatchCase](rn_case).guard is not None:
|
||
self.Gen.TypeGenErr.fatal_error(rn_case,
|
||
"REnum match 暂不支持 guard 守卫(该臂会被 switch(tag) 静默忽略);请改为普通 match 或去掉 guard",
|
||
"NotImplementedError")
|
||
rn_i = rn_i + 1
|
||
|
||
# 0. subject 归一化:确保 subject_ptr 是指向 REnum 结构体的指针
|
||
# (对齐 TPC HandlesMatch.py:238-259 的 _HandleRenumMatchLlvm)
|
||
# 情况1: subject_ptr 是 T**(变量 alloca)→ load 一次得 T*
|
||
# 情况2: subject_ptr 不是指针(值型,如 REnum payload 槽位 load 出的 i64)
|
||
# → alloca REnum 结构体 + store 值 + 用 alloca 指针
|
||
# 情况3: 指针但 pointee 不是结构体 → bitcast 到 REnum 结构体指针
|
||
subj_ty: llvmlite.LLVMType* = subject_ptr.Ty
|
||
if subj_ty is not None and self.Gen.ExprGenBase.is_ptr_type(subj_ty) != 0 \
|
||
and subj_ty.Pointee != 0 \
|
||
and self.Gen.ExprGenBase.is_ptr_type(subj_ty.Pointee) != 0:
|
||
# 情况1: T** → load 一次得 T*
|
||
loaded_sub: llvmlite.Value* = llvmlite.build_load(builder, subj_ty.Pointee, subject_ptr)
|
||
if loaded_sub is not None:
|
||
subject_ptr = loaded_sub
|
||
# 情况2: 值型 subject(非指针)→ inttoptr 转回指针
|
||
# 值型 subject 来自 REnum payload 槽位 load(槽位类型 i64,存的是指针),
|
||
# 所以直接 inttoptr 到 renum_sty* 即可,无需 alloca+store
|
||
if subject_ptr.Ty is None or self.Gen.ExprGenBase.is_ptr_type(subject_ptr.Ty) == 0:
|
||
renum_se: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(renum_name)
|
||
renum_sty: llvmlite.LLVMType* = None
|
||
if renum_se is not None:
|
||
renum_sty = renum_se.Ty
|
||
if renum_sty is None:
|
||
# fail-fast: REnum 结构体未注册,无法构造
|
||
self.Gen.TypeGenErr.fatal_error(node, f"REnum 结构体 '{renum_name}' 未注册", "NameError")
|
||
i64_ty0: llvmlite.LLVMType* = llvmlite.Int64(pool)
|
||
int_val: llvmlite.Value* = subject_ptr
|
||
# 非 i64 整数值先扩展/截断到 i64(inttoptr 要求同宽)
|
||
# 仅当 subj_ty 是已知整数类型时转换;类型未知时保持原值
|
||
if subj_ty is not None and self.Gen.ExprGenBase.get_llvm_type_bits(subj_ty) != 64 \
|
||
and self.Gen.ExprGenBase.is_ptr_type(subj_ty) == 0:
|
||
if self.Gen.ExprGenBase.get_llvm_type_bits(subj_ty) > 64:
|
||
int_val = llvmlite.build_trunc(builder, subject_ptr, i64_ty0)
|
||
else:
|
||
int_val = llvmlite.build_zext(builder, subject_ptr, i64_ty0)
|
||
renum_ptr_ty0: llvmlite.LLVMType* = llvmlite.Ptr(pool, renum_sty)
|
||
subj_ptr0: llvmlite.Value* = llvmlite.build_inttoptr(builder, int_val, renum_ptr_ty0)
|
||
if subj_ptr0 is not None:
|
||
subject_ptr = subj_ptr0
|
||
|
||
# 1. bitcast subject 到 __tag* 读 __tag
|
||
# tag 的**类型**取 __tag 的字段声明类型(FieldEntry.Ty),与 kind()
|
||
# (CallGenDispatch)和变体构造共用同一真源,不再各自硬编码 i32;
|
||
# 下方 case 常量(ConstInt)同用 tag_ty ⇒ 将来 __tag 换宽度时
|
||
# 读 / 写 / 比较三侧自动跟随。(默认 i32 仅当字段条目取不到时的等效值:
|
||
# __tag 全仓唯一写入点是 ClassGenEnum:1009 add_field(entry,"__tag",Int32)。)
|
||
tag_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||
tag_se: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(renum_name)
|
||
if tag_se is not None and tag_se.Ty is not None:
|
||
tag_fe: GenTypes.FieldEntry* = self.Gen.StructGen.lookup_field(tag_se.Ty, "__tag")
|
||
if tag_fe is not None and tag_fe.Ty is not None:
|
||
tag_ty = tag_fe.Ty
|
||
tag_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, tag_ty)
|
||
tag_ptr: llvmlite.Value* = llvmlite.build_bitcast(builder, subject_ptr, tag_ptr_ty)
|
||
if tag_ptr is None:
|
||
# fail-fast: REnum tag 指针转换失败
|
||
self.Gen.TypeGenErr.fatal_error(node, "REnum tag 指针转换失败", "TypeError")
|
||
tag_val: llvmlite.Value* = llvmlite.build_load(builder, tag_ty, tag_ptr)
|
||
if tag_val is None:
|
||
# fail-fast: REnum tag 读取失败
|
||
self.Gen.TypeGenErr.fatal_error(node, "REnum tag 读取失败", "TypeError")
|
||
|
||
# 2. 创建 default/end BB
|
||
cnt: int = trans._label_counter
|
||
trans._label_counter = cnt + 1
|
||
name_buf: str = pool.alloc(32)
|
||
if name_buf is None:
|
||
# fail-fast: 标签缓冲区分配失败
|
||
self.Gen.TypeGenErr.fatal_error(node, "标签缓冲区分配失败", "TypeError")
|
||
viperlib.snprintf(name_buf, 32, "match.default.%d", cnt)
|
||
default_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
viperlib.snprintf(name_buf, 32, "match.end.%d", cnt)
|
||
end_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
# 3. 准备收集数组(用 CSizeT 数组存指针)
|
||
cases_list: list[ast.AST*]* = node.cases
|
||
if cases_list is None:
|
||
# fail-fast: match cases 缺失
|
||
self.Gen.TypeGenErr.fatal_error(node, "match cases 缺失", "TypeError")
|
||
case_count: sizet = len(cases_list)
|
||
|
||
# BB 指针数组、case 值指针数组、default 标记数组、nobreak 标记数组
|
||
bb_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
|
||
cv_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
|
||
def_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
|
||
nb_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
|
||
# pass1 缓存的 mc 指针数组(pass2 复用,避免重索引)
|
||
mc_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
|
||
if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None \
|
||
or mc_arr is None:
|
||
# fail-fast: match 分派数组分配失败
|
||
self.Gen.TypeGenErr.fatal_error(node, "match 分派数组分配失败", "TypeError")
|
||
|
||
collected: int = 0
|
||
has_default: int = 0
|
||
# 穷尽臂(`case _`)节点:pass1 显式记录,default 块直接翻译
|
||
default_case_node: ast.AST* = None
|
||
|
||
# SwitchCase 链表
|
||
sw_head: rawptr[llvmlite.SwitchCase] = None
|
||
sw_tail: rawptr[llvmlite.SwitchCase] = None
|
||
sw_count: int = 0
|
||
|
||
# 应提交 case 的臂计数(非 default 且模式必须产出 case 值:MatchClass
|
||
# 必有变体 tag / MatchValue 必有常量值);与 sw_count 不等即静默丢 case,
|
||
# build_switch 前 fail-fast(见 step 5 前的硬校验)。
|
||
need_case: int = 0
|
||
# 修复: 未取到 case 值的臂诊断串(供硬校验报错打印 臂序号/变体名/tag)
|
||
# 容量 = 8 条 × 单条上限(diag_tmp 128,strcat 无边界检查 → 必须够大)
|
||
miss_buf: str = pool.alloc(1088)
|
||
diag_tmp: str = pool.alloc(128)
|
||
if miss_buf is None or diag_tmp is None:
|
||
# fail-fast: 诊断缓冲区分配失败(与上方 name_buf 同款处理)
|
||
self.Gen.TypeGenErr.fatal_error(node, "match 诊断缓冲区分配失败", "TypeError")
|
||
miss_buf[0] = '\0'
|
||
miss_cnt: int = 0
|
||
# 变体表 RenumClassNames 按裸类名注册(ClassDef.name),而 renum_name 来自
|
||
# 注解书写形态(Spec.SourceName,Attribute 会带模块限定名 "mod.LLVMType")→
|
||
# 精确 strcmp 失配恒 -1 → 该臂被静默丢弃。故先去模块前缀(复用 find_struct
|
||
# 同款「括号外取点」判定,泛型下标内的点不算)。
|
||
tag_cls_bare: str = renum_name
|
||
rn_dot: str = self.Gen.StructGen._last_dot_outside_brackets(renum_name)
|
||
if rn_dot is not None and rn_dot[1] != '\0':
|
||
tag_cls_bare = rn_dot + 1
|
||
|
||
# 4. 第一遍:收集 case 信息 + 创建 BB + 构建链表
|
||
i: int = 0
|
||
while i < case_count:
|
||
case_node: ast.AST* = cases_list.get(i)
|
||
if case_node is None:
|
||
i = i + 1
|
||
continue
|
||
if case_node.kind() != ast.ASTKind.MatchCase:
|
||
i = i + 1
|
||
continue
|
||
mc: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](case_node)
|
||
pat: ast.AST* = mc.pattern
|
||
|
||
is_def: int = 0
|
||
cv: llvmlite.Value* = None
|
||
# 修复: 提升到臂作用域(原先声明在 MatchClass 分支内),供下方
|
||
# "未取到 case 值"诊断打印变体名/tag
|
||
vnm: str = None
|
||
tag: int = -1
|
||
|
||
if pat is not None:
|
||
pk: int = pat.kind()
|
||
if pk == ast.ASTKind.MatchClass:
|
||
vnm = self._extract_variant_name_from_cls(pat)
|
||
if vnm is not None:
|
||
# 先用裸类名查表(变体表按裸类名注册,与模式侧 2b 路径同口径);
|
||
# 失败再用注解书写形态重试(泛型特化 mangled 名确需带点)。
|
||
# 两者都失败 → tag=-1 → step 5 前的硬校验 fail-fast。
|
||
tag = self.Gen.ClassGenEnum._lookup_renum_variant_in_class(tag_cls_bare, vnm)
|
||
if tag < 0 and string.strcmp(tag_cls_bare, renum_name) != 0:
|
||
tag = self.Gen.ClassGenEnum._lookup_renum_variant_in_class(renum_name, vnm)
|
||
if tag >= 0:
|
||
tag_buf: str = pool.alloc(32)
|
||
if tag_buf is not None:
|
||
viperlib.snprintf(tag_buf, 32, "%d", tag)
|
||
cv = llvmlite.ConstInt(pool, tag_ty, tag,
|
||
tag_buf if tag_buf is not None else "0")
|
||
elif pk == ast.ASTKind.MatchAs:
|
||
ma: rawptr[ast.MatchAs] = rawptr[ast.MatchAs](pat)
|
||
if ma.pattern is None:
|
||
is_def = 1
|
||
has_default = 1
|
||
default_case_node = case_node
|
||
elif pk == ast.ASTKind.MatchValue:
|
||
mv: rawptr[ast.MatchValue] = rawptr[ast.MatchValue](pat)
|
||
cv = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, mv.value, trans._funcs, trans._func_count, trans)
|
||
elif pk == ast.ASTKind.MatchOr:
|
||
# MatchOr: 多个值共享一个 BB(取第一个值做 case)
|
||
mo: rawptr[ast.MatchOr] = rawptr[ast.MatchOr](pat)
|
||
pats: list[ast.AST*]* = mo.patterns
|
||
if pats is not None and len(pats) > 0:
|
||
first_pat: ast.AST* = pats.get(0)
|
||
if first_pat is not None \
|
||
and first_pat.kind() == ast.ASTKind.MatchValue:
|
||
mv2: rawptr[ast.MatchValue] = (rawptr[ast.MatchValue])(first_pat)
|
||
cv = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, mv2.value, trans._funcs, trans._func_count, trans)
|
||
|
||
# 创建 case BB
|
||
if is_def == 0:
|
||
if collected >= MAX_MATCH_CASES:
|
||
break
|
||
viperlib.snprintf(name_buf, 32, "match.case.%d.%d", cnt, i)
|
||
bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
else:
|
||
bb = default_bb
|
||
|
||
# 检测 NoBreak
|
||
body_list: list[ast.AST*]* = mc.children
|
||
nb: int = self._has_no_break(body_list)
|
||
|
||
# 存入数组
|
||
if collected < MAX_MATCH_CASES:
|
||
bb_arr[collected] = sizet(bb)
|
||
cv_arr[collected] = sizet(cv)
|
||
def_arr[collected] = is_def
|
||
nb_arr[collected] = nb
|
||
# 缓存 mc 指针(pass2 复用,避免重索引)
|
||
mc_arr[collected] = sizet(mc)
|
||
collected = collected + 1
|
||
# 计入"必须提交 case"的臂(MatchClass 必有变体 tag、MatchValue 必有
|
||
# 常量值);必须在 MAX_MATCH_CASES 上限判定之后计数(超上限的臂已
|
||
# break,不参与校验)。
|
||
if is_def == 0 and pat is not None:
|
||
pkm: int = pat.kind()
|
||
if pkm == ast.ASTKind.MatchClass or pkm == ast.ASTKind.MatchValue:
|
||
need_case = need_case + 1
|
||
|
||
# 构建 SwitchCase 链表(非 default case 且有值)
|
||
if is_def == 0 and cv is not None:
|
||
sc: rawptr[llvmlite.SwitchCase] = llvmlite.new_switch_case(pool, cv, bb)
|
||
if sc is not None:
|
||
if sw_head is None:
|
||
sw_head = sc
|
||
sw_tail = sc
|
||
else:
|
||
sw_tail.Next = sc
|
||
sw_tail = sc
|
||
sw_count = sw_count + 1
|
||
# 记录"应产出 case 值但未产出"的臂(MatchClass 变体 tag 查表失败 /
|
||
# MatchValue 常量翻译失败)。此处只收集诊断,是否致命由 step 5 前的
|
||
# 硬校验统一判定(口径唯一)。
|
||
if is_def == 0 and cv is None and miss_cnt < 8 and pat is not None:
|
||
pkm_d: int = pat.kind()
|
||
if pkm_d == ast.ASTKind.MatchClass or pkm_d == ast.ASTKind.MatchValue:
|
||
viperlib.snprintf(diag_tmp, 128, " #%d(%s,tag=%d)",
|
||
i, vnm if vnm is not None else "?", tag)
|
||
string.strcat(miss_buf, diag_tmp)
|
||
miss_cnt = miss_cnt + 1
|
||
|
||
i = i + 1
|
||
|
||
# 5. 发射 switch 指令
|
||
# 禁止静默丢 case:必须提交 case 的臂数(MatchClass/MatchValue,非 default)
|
||
# 必须等于实际提交给 build_switch 的 sw_count。不等即该臂 case 值未算出
|
||
# (REnum 变体 tag 查表失败最常见)→ build_switch 发射空 case 列表、臂体
|
||
# 结构性不可达。故不等即 fail-fast,打印类名/查表名/应提交数/实际数/
|
||
# 各未取到值臂的 序号(变体名,tag),便于定位变体表失配。
|
||
if need_case != sw_count:
|
||
self.Gen.TypeGenErr.fatal_error(node,
|
||
f"REnum match 分派丢失 case:class='{renum_name}'(查表名='{tag_cls_bare}')应提交 {need_case} 个 case,实际提交 {sw_count} 个;未取到值的臂:{miss_buf}",
|
||
"InternalCompilerError")
|
||
llvmlite.build_switch(builder, tag_val, default_bb, sw_head, sw_count)
|
||
|
||
# 6. 查找 REnum 结构体类型(用于变体字段绑定的 GEP)
|
||
# 两条健壮性要求——否则 renum_entry/renum_ty 取不到,step 7 的变体字段绑定会被
|
||
# **整段静默跳过** ⇒ case 绑定名在 body 里未定义(NameError:__types.vp
|
||
# `_TypePrintDepth` 的 `bits` 根因,真因因此藏到下游):
|
||
# (1) 名字:变体表与 struct 注册都按**裸类名**(ClassDef.name),而 renum_name
|
||
# 来自注解书写形态(Spec.SourceName,Attribute 可带模块限定名,如
|
||
# "c93534fe43c0ee56.LLVMType")⇒ 精确查找可能失配 → 回退 tag_cls_bare。
|
||
# (2) 条目有效性:find_struct 是"首注册命中",可能命中 D30 重注册时被就地
|
||
# 中和的旧 entry(Ty=None)⇒ 扫表取 Ty 有效者。
|
||
renum_entry: GenTypes.StructEntry* = None
|
||
renum_ty: llvmlite.LLVMType* = None
|
||
se: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(renum_name)
|
||
if se is not None and se.Ty is not None:
|
||
renum_entry = se
|
||
renum_ty = se.Ty
|
||
else:
|
||
se_v: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_entry_with_ty(renum_name, tag_cls_bare)
|
||
if se_v is not None:
|
||
renum_entry = se_v
|
||
renum_ty = se_v.Ty
|
||
|
||
# 6b. 跨模块 REnum:变体字段绑定(step 7/_bind_variant_fields)会对
|
||
# renum_ty 做带字段下标的 GEP,LLVM 要求被指结构体 sized(有完整定义)。
|
||
# 签名扫描(ensure_opaque_for_type)只为 Ptr(Struct) 发 `type opaque`,
|
||
# 不透明类型作 GEP base element 时 llc 报
|
||
# "base element of getelementptr must be sized"(__values.vp 匹配
|
||
# __types.LLVMType 的根因)。此处用结构体表 entry.Ty 的完整定义**同名替换**
|
||
# opaque(module_add_named_type 原地替换,非追加,故不会 invalid redefinition);
|
||
# 本地非跨模块类型(名不含 '.')会自动跳过。
|
||
if renum_ty is not None:
|
||
self.Gen.StructGen.ensure_struct_def_in_module(pool, trans.Module, renum_ty)
|
||
|
||
# 7. 第二遍:翻译每个 case body
|
||
i = 0
|
||
while i < collected:
|
||
# pass2 用 pass1 缓存的 mc(避免重索引错位)
|
||
mc: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](mc_arr[i])
|
||
if mc is None:
|
||
i = i + 1
|
||
continue
|
||
pat: ast.AST* = mc.pattern
|
||
|
||
# 取 BB
|
||
bb_addr: sizet = bb_arr[i]
|
||
case_bb: rawptr[llvmlite.BasicBlock] = (rawptr[llvmlite.BasicBlock])(bb_addr)
|
||
is_def: int = def_arr[i]
|
||
nb: int = nb_arr[i]
|
||
|
||
# default case 的 body 在 step 8 单独翻译,这里跳过避免重复
|
||
if is_def == 1:
|
||
i = i + 1
|
||
continue
|
||
|
||
# 定位到 case BB
|
||
llvmlite.position_at_end(builder, case_bb)
|
||
|
||
# case 体内 break = 跳出 match(C switch 语义):暂存外层循环的
|
||
# break 目标并覆盖为 match 的 end_bb,出 case 时恢复。
|
||
rmb_old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||
trans._break_bb = end_bb
|
||
rmb_old_inmc: int = trans._in_switch_case
|
||
trans._in_switch_case = node.is_switch
|
||
|
||
# 进入 case 作用域(变体字段绑定隔离)
|
||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||
|
||
# 变体字段绑定(MatchClass)
|
||
if pat is not None and pat.kind() == ast.ASTKind.MatchClass:
|
||
if renum_entry is not None and renum_ty is not None:
|
||
self._bind_variant_fields(pat, renum_name, renum_entry, renum_ty, subject_ptr, trans, pool, builder)
|
||
elif (self.Gen.ClassGenEnum._is_renum_class_name(tag_cls_bare) != 0
|
||
or self.Gen.ClassGenEnum._is_renum_class_name(renum_name) != 0
|
||
or self.Gen.ClassGenEnum._is_renum_by_entry(tag_cls_bare) != 0
|
||
or self.Gen.ClassGenEnum._is_renum_by_entry(renum_name) != 0):
|
||
# 走到这里 ⇒ 分派判定为 REnum match(同一组判据至少一条为真),而
|
||
# MatchClass 却拿不到可用的 struct entry/类型:此前**静默跳过**绑定
|
||
# ⇒ 绑定名在 body 里未定义,最终报 NameError(__types.vp `bits`),
|
||
# 真因被藏到下游。此处 fail-fast 并打印现场,便于定位是"变体表缺该类"
|
||
# 还是"条目被中和/Ty 缺失"。
|
||
ent_nm: str = "None"
|
||
ent_fc: int = -1
|
||
if renum_entry is not None:
|
||
ent_nm = renum_entry.Name
|
||
ent_fc = renum_entry.FieldCount
|
||
ty_present: int = 0
|
||
if renum_ty is not None:
|
||
ty_present = 1
|
||
self.Gen.TypeGenErr.fatal_error(pat,
|
||
f"REnum match 变体字段绑定失败:class='{tag_cls_bare}'(查表名='{renum_name}')"
|
||
f" entry='{ent_nm}' FieldCount={ent_fc} ty_present={ty_present};"
|
||
f"变体表已登记该类,说明结构体条目或 Ty 缺失(已不再静默跳过绑定,"
|
||
f"否则绑定名未定义只会在下游报 NameError)",
|
||
"InternalCompilerError")
|
||
|
||
# 翻译 case body
|
||
body_list: list[ast.AST*]* = mc.children
|
||
if body_list is not None:
|
||
bc: sizet = len(body_list)
|
||
bi: int = 0
|
||
while bi < bc:
|
||
# 用 list.get() 读取元素值(已验证编译为 8 字节加载,与
|
||
# pass1 的 cases_list.get(i) 同型同码)。切勿改为
|
||
# `bl_data + bi*8` 裸地址:那会把数组槽地址当节点传入
|
||
# translate_stmt,虚调用跳进 vtable 表 → DEP 崩溃。
|
||
stmt: ast.AST* = body_list.get(bi)
|
||
if stmt is not None:
|
||
self.Gen.StmtGen.translate_stmt(trans, stmt)
|
||
bi = bi + 1
|
||
|
||
# 退出 case 作用域,并恢复 break 目标 / match-case 标记
|
||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||
trans._break_bb = rmb_old_break
|
||
trans._in_switch_case = rmb_old_inmc
|
||
|
||
# 若未终止:默认跳 end;含 fallthrough(`fallthrough` 标记或兼容的
|
||
# c.NoBreak())则落到下一个 case 的 body(跳过其模式检查)。
|
||
# 末句控制流全 return(结构性不可达)时补 unreachable,不 br end_bb
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
|
||
and self._case_tail_unreachable(trans, builder, body_list) == 0:
|
||
if nb == 0:
|
||
llvmlite.build_br(builder, end_bb)
|
||
else:
|
||
rmb_ft_nj: int = i + 1
|
||
while rmb_ft_nj < collected and def_arr[rmb_ft_nj] != 0:
|
||
rmb_ft_nj = rmb_ft_nj + 1
|
||
if rmb_ft_nj < collected:
|
||
rmb_ft_bb: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](bb_arr[rmb_ft_nj])
|
||
llvmlite.build_br(builder, rmb_ft_bb)
|
||
elif has_default != 0:
|
||
llvmlite.build_br(builder, default_bb)
|
||
else:
|
||
llvmlite.build_br(builder, end_bb)
|
||
trans._ctrl_merge_reachable = 1
|
||
rm_merge_reach = 1
|
||
|
||
i = i + 1
|
||
|
||
# 8. 处理 default 块
|
||
llvmlite.position_at_end(builder, default_bb)
|
||
if has_default == 0 or default_case_node is None:
|
||
# 无显式 default:default 直接跳 end(match 不穷尽 ⇒ merge 可达)
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||
llvmlite.build_br(builder, end_bb)
|
||
trans._ctrl_merge_reachable = 1
|
||
rm_merge_reach = 1
|
||
else:
|
||
# 有显式 default:直接翻译 pass1 记录的 `case _` 臂
|
||
# (不再经 def_arr 槽位反查 cases_list:collected 下标与原始下标
|
||
# 在"有臂被跳过"时会错位,default_bb 随之空转)
|
||
dmc_d: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](default_case_node)
|
||
# default 臂同样按 match-case 语义:break = 跳出 match
|
||
rmd_old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||
trans._break_bb = end_bb
|
||
rmd_old_inmc: int = trans._in_switch_case
|
||
trans._in_switch_case = 1
|
||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||
# dbody 预声明+重赋值会使 .get 误分派成 list[int].get
|
||
# (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃,gen1 IR 证据)。
|
||
# 用 dbody3 内联声明接收者遍历(对齐 Converter arg_defaults 规避模式)。
|
||
dbody3: list[ast.AST*]* = dmc_d.children
|
||
if dbody3 is not None:
|
||
dn3: sizet = len(dbody3)
|
||
dj3: int = 0
|
||
while dj3 < dn3:
|
||
stmt3: ast.AST* = dbody3.get(dj3)
|
||
if stmt3 is not None:
|
||
self.Gen.StmtGen.translate_stmt(trans, stmt3)
|
||
dj3 = dj3 + 1
|
||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||
trans._break_bb = rmd_old_break
|
||
trans._in_switch_case = rmd_old_inmc
|
||
# 末句控制流全 return → 补 unreachable(不 br end_bb)
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
|
||
and self._case_tail_unreachable(trans, builder, dbody3) == 0:
|
||
llvmlite.build_br(builder, end_bb)
|
||
trans._ctrl_merge_reachable = 1
|
||
rm_merge_reach = 1
|
||
|
||
# 9. 定位到 end 块
|
||
llvmlite.position_at_end(builder, end_bb)
|
||
# 用本 match 自身的 br 记录覆盖,消除 case 体内嵌套控制流对
|
||
# _ctrl_merge_reachable 的污染(全 case return 时应为不可达)
|
||
trans._ctrl_merge_reachable = rm_merge_reach
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _bind_variant_fields - 绑定 MatchClass 的变体字段
|
||
#
|
||
# case LLVMType.Ptr(pointee) 中的 pointee 绑定到 subject 的 payload 字段
|
||
# ============================================================
|
||
def _bind_variant_fields(self, pat: ast.AST*,
|
||
renum_name: str,
|
||
renum_entry: GenTypes.StructEntry*,
|
||
renum_ty: llvmlite.LLVMType*,
|
||
subject_ptr: llvmlite.Value*,
|
||
trans: HT.Translator*,
|
||
pool: memhub.MemBuddy*,
|
||
builder: llvmlite.IRBuilder*):
|
||
if pat is None or renum_entry is None or renum_ty is None:
|
||
return
|
||
mc: rawptr[ast.MatchClass] = rawptr[ast.MatchClass](pat)
|
||
pats: list[ast.AST*]* = mc.patterns
|
||
if pats is None:
|
||
return
|
||
# bitcast subject_ptr 到 renum_ptr_ty(确保 GEP 类型匹配)
|
||
renum_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, renum_ty)
|
||
casted_ptr: llvmlite.Value* = llvmlite.build_bitcast(builder, subject_ptr, renum_ptr_ty)
|
||
if casted_ptr is None:
|
||
casted_ptr = subject_ptr
|
||
pn: sizet = len(pats)
|
||
for j in range(pn):
|
||
sub_pat: ast.AST* = pats.get(j)
|
||
if sub_pat is not None and sub_pat.kind() == ast.ASTKind.MatchAs:
|
||
ma: rawptr[ast.MatchAs] = rawptr[ast.MatchAs](sub_pat)
|
||
bind_name: str = ma.name
|
||
if bind_name is not None:
|
||
# 按位置绑定:MatchClass 第 j 个参数 → payload 索引 j+1
|
||
# 对应 TPC HandlesMatch.py:305-306(不依赖字段名大小写匹配)
|
||
payload_idx: int = j + 1
|
||
# 字段名查找作为回退(若字段名与 MatchAs 名一致可直接命中)
|
||
if payload_idx >= renum_entry.FieldCount:
|
||
# class_name 用 CSizeT 指针值比较:必须传 renum_entry.Name
|
||
# (注册时 _update_renum_alias_class_ptr 统一后的 perm_pool 指针);
|
||
# renum_name(AnnotClassName 等)是不同指针,恒不匹配 → 误报 fail-fast。
|
||
alt_idx: int = self.Gen.ClassGenEnum._lookup_renum_field_alias(renum_entry.Name, bind_name)
|
||
if alt_idx >= 1:
|
||
payload_idx = alt_idx
|
||
else:
|
||
# fail-fast: payload 越界且别名查找失败
|
||
# (node 在本函数不存在——参数是 pat/sub_pat,用 sub_pat
|
||
# 定位到具体 MatchAs 模式;TPC Python 语义下未定义名只在
|
||
# 运行时求值才报错,TPV 惰性编译方法体时即 NameError)
|
||
self.Gen.TypeGenErr.fatal_error(sub_pat, f"REnum 变体字段 '{bind_name}' 在结构体 '{renum_name}' 中越界且别名查找失败", "TypeError")
|
||
# 获取字段类型
|
||
fe: GenTypes.FieldEntry* = (self.Gen.StructGen._get_field_entry(renum_entry, payload_idx))
|
||
field_ty: llvmlite.LLVMType* = None
|
||
if fe is not None:
|
||
field_ty = fe.Ty
|
||
if field_ty is None:
|
||
# fail-fast: 变体字段类型缺失,禁止兜底 i8
|
||
self.Gen.TypeGenErr.fatal_error(sub_pat, f"REnum 变体字段类型缺失: {bind_name}", "TypeError")
|
||
# GEP 取字段地址
|
||
elem_ptr: llvmlite.Value* = llvmlite.build_gep_struct(builder, renum_ty, field_ty,casted_ptr, payload_idx)
|
||
if elem_ptr is None:
|
||
# fail-fast: 变体字段地址计算失败
|
||
self.Gen.TypeGenErr.fatal_error(sub_pat, f"REnum 变体字段 '{bind_name}' 地址计算失败", "TypeError")
|
||
# 变体成员实际类型(对齐 TPC class_members):注册时别名表存了成员
|
||
# 注解解析出的类型(perm_pool 深拷贝),用它把槽位地址 bitcast 成
|
||
# Ptr(成员类型),使绑定变量按成员类型读 payload(否则按槽位 i64 读 →
|
||
# is 比较/下标/strlen 等字符串操作翻译失败)。
|
||
# 必须按 (class, 变体名, 位置) 定位:MatchAs 名是局部变量名而非字段名,
|
||
# 按字段名查恒不匹配;同一 payload 位置跨变体类型也不同。
|
||
# 自引用类型注册期解析失败 → 查不到类型时回退槽位类型。
|
||
mem_ty_m: llvmlite.LLVMType* = None
|
||
vnt_m: str = self._extract_variant_name_from_cls(pat)
|
||
if vnt_m is not None and renum_entry is not None \
|
||
and renum_entry.Name is not None:
|
||
mem_ty_m = self.Gen.ClassGenEnum._lookup_renum_member_ty(renum_entry.Name, vnt_m, payload_idx)
|
||
if mem_ty_m is not None:
|
||
mem_ptr_m: llvmlite.LLVMType* = llvmlite.Ptr(pool, mem_ty_m)
|
||
if mem_ptr_m is not None:
|
||
cast_m: llvmlite.Value* = llvmlite.build_bitcast(builder, elem_ptr, mem_ptr_m)
|
||
if cast_m is not None:
|
||
elem_ptr = cast_m
|
||
self.Gen.VarGen.define_var(trans.SymTab, bind_name, elem_ptr)
|
||
|
||
# ============================================================
|
||
# _seq_cmp_eq - 序列匹配元素相等比较
|
||
#
|
||
# 对齐 lhs/rhs(指针统一 ptrtoint i64,整数位宽统一到较宽者)后
|
||
# 生成 icmp eq,返回 i1 条件。
|
||
# ============================================================
|
||
def _seq_cmp_eq(self, trans: HT.Translator*,
|
||
builder: llvmlite.IRBuilder*,
|
||
lhs: llvmlite.Value*,
|
||
rhs: llvmlite.Value*) -> llvmlite.Value*:
|
||
"""对齐 lhs/rhs 后生成 icmp eq(指针统一 ptrtoint i64)"""
|
||
if lhs is None or rhs is None or builder is None:
|
||
return None
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
if self.Gen.ExprGenBase.is_ptr_type(lhs.Ty) != 0 \
|
||
or self.Gen.ExprGenBase.is_ptr_type(rhs.Ty) != 0:
|
||
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
|
||
if self.Gen.ExprGenBase.is_ptr_type(lhs.Ty) != 0:
|
||
lhs = llvmlite.build_ptrtoint(builder, lhs, i64_ty)
|
||
if self.Gen.ExprGenBase.is_ptr_type(rhs.Ty) != 0:
|
||
rhs = llvmlite.build_ptrtoint(builder, rhs, i64_ty)
|
||
lb: int = self.Gen.ExprGenBase.get_llvm_type_bits(lhs.Ty)
|
||
rb: int = self.Gen.ExprGenBase.get_llvm_type_bits(rhs.Ty)
|
||
if lb != rb and lb != 0 and rb != 0:
|
||
if lb < rb:
|
||
if lb == 1:
|
||
lhs = llvmlite.build_zext(builder, lhs, rhs.Ty)
|
||
else:
|
||
lhs = llvmlite.build_sext(builder, lhs, rhs.Ty)
|
||
else:
|
||
if rb == 1:
|
||
rhs = llvmlite.build_zext(builder, rhs, lhs.Ty)
|
||
else:
|
||
rhs = llvmlite.build_sext(builder, rhs, lhs.Ty)
|
||
return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, lhs, rhs)
|
||
|
||
# ============================================================
|
||
# _handle_sequence_match - 序列匹配(match (a, b): case (x, y): ...)
|
||
#
|
||
# subject 是 Tuple/List、case 是 MatchSequence 时走此路径(对齐 Python
|
||
# 语义,按声明顺序取首个全部元素匹配且 guard 为真的 case 执行):
|
||
# 元素 pattern:
|
||
# MatchValue v → subject[i] == v
|
||
# MatchAs(pattern=None) → _ 通配(恒真)
|
||
# MatchStar → 剩余元素通配(恒真)
|
||
# IR 结构(check/body 链):
|
||
# entry → check0
|
||
# check_i: 匹配条件 → body_i(不满足 → check_{i+1})
|
||
# body_i: <body> → end(c.NoBreak 时 fallthrough 到下一 case body)
|
||
# 全不匹配 → default → end
|
||
# ============================================================
|
||
def _handle_sequence_match(self, trans: HT.Translator*,
|
||
node: ast.Match*,
|
||
subject_node: ast.AST*) -> int:
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
func: llvmlite.Function* = trans._cur_func
|
||
if builder is None or func is None:
|
||
return 0
|
||
# 同主路径:局部记录本 sequence match 的 br end_bb,收尾覆盖
|
||
# _ctrl_merge_reachable,消除 case 体内嵌套控制流污染
|
||
sq_merge_reach: int = 0
|
||
|
||
# 1. 求值 subject 各元素
|
||
elts: list[ast.AST*]* = None
|
||
if subject_node.kind() == ast.ASTKind.Tuple:
|
||
st: ast.Tuple* = ast.Tuple*(subject_node)
|
||
if st is not None:
|
||
elts = st.elts
|
||
elif subject_node.kind() == ast.ASTKind.List:
|
||
sl2: ast.List* = ast.List*(subject_node)
|
||
if sl2 is not None:
|
||
elts = sl2.elts
|
||
if elts is None:
|
||
return 0
|
||
ecount: sizet = len(elts)
|
||
if ecount == 0:
|
||
return 0
|
||
subj_vals: sizet* = pool.alloc(8 * ecount)
|
||
if subj_vals is None:
|
||
return 0
|
||
for ei in range(ecount):
|
||
# elts 预声明+重赋值会把 .get 误分派成 list[int].get(i32 截断);
|
||
# 用内联别名接收者规避(对齐 Converter arg_defaults 内联模式)
|
||
elts_inl: list[ast.AST*]* = elts
|
||
elt: ast.AST* = elts_inl.get(ei)
|
||
sv: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, elt,
|
||
trans._funcs, trans._func_count, trans)
|
||
if sv is None:
|
||
self.Gen.TypeGenErr.fatal_error(elt, f"match 序列元素 {ei} 翻译失败", "TypeError")
|
||
subj_vals[ei] = sizet(sv)
|
||
|
||
# 2. 创建 default/end BB
|
||
cnt: int = trans._label_counter
|
||
trans._label_counter = cnt + 1
|
||
name_buf: str = pool.alloc(32)
|
||
if name_buf is None:
|
||
return 0
|
||
viperlib.snprintf(name_buf, 32, "match.seq.default.%d", cnt)
|
||
default_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
viperlib.snprintf(name_buf, 32, "match.seq.end.%d", cnt)
|
||
end_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
# 3. 第一遍:收集 case 信息(check/body BB、default 标记、nobreak、guard)
|
||
cases_list: list[ast.AST*]* = node.cases
|
||
if cases_list is None:
|
||
return 0
|
||
case_count: sizet = len(cases_list)
|
||
check_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
|
||
body_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
|
||
def_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
|
||
nb_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
|
||
guard_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
|
||
if check_arr is None or body_arr is None or def_arr is None \
|
||
or nb_arr is None or guard_arr is None:
|
||
return 0
|
||
collected: int = 0
|
||
has_default: int = 0
|
||
# 穷尽臂(`case _`)节点:pass1 显式记录,default 块直接翻译
|
||
default_case_node: ast.AST* = None
|
||
first_check: int = -1
|
||
i: int = 0
|
||
while i < case_count:
|
||
# 容量防线(与 _translate_match_simple / match-list 路径的
|
||
# `collected < MAX_MATCH_CASES` 守卫对齐):默认 case(case _)分支也须校验
|
||
# collected 再写 check_arr/body_arr/def_arr/nb_arr/guard_arr[collected],
|
||
# 否则 case 数超 MAX_MATCH_CASES 会越界写穿 pool 相邻块。超限直接
|
||
# fail-fast,不静默丢弃 case。
|
||
if collected >= MAX_MATCH_CASES:
|
||
self.Gen.TypeGenErr.fatal_error(node, f"match case 数量超过上限 MAX_MATCH_CASES={MAX_MATCH_CASES}", "OverflowError")
|
||
break
|
||
case_node: ast.AST* = cases_list.get(i)
|
||
if case_node is None or case_node.kind() != ast.ASTKind.MatchCase:
|
||
i = i + 1
|
||
continue
|
||
mc: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](case_node)
|
||
pat: ast.AST* = mc.pattern
|
||
is_def: int = 0
|
||
if pat is not None:
|
||
pk: int = pat.kind()
|
||
if pk == ast.ASTKind.MatchAs:
|
||
ma0: rawptr[ast.MatchAs] = rawptr[ast.MatchAs](pat)
|
||
if ma0.pattern is None:
|
||
# 顶层 _ 通配臂带 guard(`case _ if <cond>`):本序列路径把
|
||
# `_` 一律当 default(恒真)处理,会**静默忽略 guard**。禁止
|
||
# 静默兜底 → 在任何 IR 产出之前 fail-fast。
|
||
if mc.guard is not None:
|
||
self.Gen.TypeGenErr.fatal_error(pat,
|
||
"序列匹配的顶层 `case _ if <cond>` 暂不支持 guard 守卫",
|
||
"NotImplementedError")
|
||
is_def = 1
|
||
elif pk != ast.ASTKind.MatchSequence:
|
||
# fail-fast:序列匹配只接受 MatchSequence / 顶层 _ 通配
|
||
self.Gen.TypeGenErr.fatal_error(pat, "序列匹配 case 只支持 (元素) 或 _ 模式", "TypeError")
|
||
if is_def == 1:
|
||
has_default = 1
|
||
default_case_node = case_node
|
||
check_arr[collected] = 0
|
||
body_arr[collected] = sizet(default_bb)
|
||
else:
|
||
if collected >= MAX_MATCH_CASES:
|
||
break
|
||
viperlib.snprintf(name_buf, 32, "match.seq.check.%d.%d", cnt, i)
|
||
cbb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
viperlib.snprintf(name_buf, 32, "match.seq.body.%d.%d", cnt, i)
|
||
bbb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
check_arr[collected] = sizet(cbb)
|
||
body_arr[collected] = sizet(bbb)
|
||
if first_check < 0:
|
||
first_check = collected
|
||
body_list: list[ast.AST*]* = mc.children
|
||
nb: int = self._has_no_break(body_list)
|
||
def_arr[collected] = is_def
|
||
nb_arr[collected] = nb
|
||
guard_arr[collected] = sizet(mc.guard)
|
||
collected = collected + 1
|
||
i = i + 1
|
||
|
||
# 4. 入口 → 第一个 check(或 default/end)
|
||
if first_check >= 0:
|
||
head_bb: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](check_arr[first_check])
|
||
llvmlite.build_br(builder, head_bb)
|
||
elif has_default == 1:
|
||
llvmlite.build_br(builder, default_bb)
|
||
else:
|
||
llvmlite.build_br(builder, end_bb)
|
||
|
||
# 5. 发射 check 链
|
||
ci: int = 0
|
||
while ci < collected:
|
||
if def_arr[ci] == 1:
|
||
ci = ci + 1
|
||
continue
|
||
cbb2: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](check_arr[ci])
|
||
bbb2: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](body_arr[ci])
|
||
llvmlite.position_at_end(builder, cbb2)
|
||
|
||
# 计算匹配条件(元素比较 && guard)
|
||
cond: llvmlite.Value* = None
|
||
cnode: ast.AST* = cases_list.get(ci)
|
||
mc2: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](cnode)
|
||
ms: rawptr[ast.MatchSequence] = (rawptr[ast.MatchSequence])(mc2.pattern)
|
||
pats: list[ast.AST*]* = None
|
||
if ms is not None:
|
||
pats = ms.patterns
|
||
pcount: sizet = 0
|
||
if pats is not None:
|
||
pcount = len(pats)
|
||
if pcount != ecount:
|
||
# 元素数量不匹配 → 恒假(对齐 Python 语义)
|
||
cond = llvmlite.const_int(pool, 1, 0)
|
||
else:
|
||
for pi in range(ecount):
|
||
# pats 预声明+重赋值会把 .get 误分派成 list[int].get(i32 截断);
|
||
# 用内联别名接收者规避(对齐 Converter arg_defaults 内联模式)
|
||
pats_inl: list[ast.AST*]* = pats
|
||
pat1: ast.AST* = pats_inl.get(pi)
|
||
if pat1 is None:
|
||
continue
|
||
pk1: int = pat1.kind()
|
||
if pk1 == ast.ASTKind.MatchValue:
|
||
mv: rawptr[ast.MatchValue] = (rawptr[ast.MatchValue])(pat1)
|
||
pv: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, mv.value, trans._funcs, trans._func_count, trans)
|
||
if pv is None:
|
||
self.Gen.TypeGenErr.fatal_error(pat1, f"序列模式元素 {pi} 翻译失败", "TypeError")
|
||
sv1: llvmlite.Value* = llvmlite.Value*(subj_vals[pi])
|
||
c1: llvmlite.Value* = self._seq_cmp_eq(trans, builder, sv1, pv)
|
||
if c1 is None:
|
||
self.Gen.TypeGenErr.fatal_error(pat1, "序列模式元素比较失败", "TypeError")
|
||
if cond is None:
|
||
cond = c1
|
||
else:
|
||
cond = llvmlite.build_and(builder, cond, c1)
|
||
elif pk1 == ast.ASTKind.MatchAs:
|
||
ma2: rawptr[ast.MatchAs] = rawptr[ast.MatchAs](pat1)
|
||
if ma2.pattern is None:
|
||
continue # _ 通配:恒真
|
||
if ma2.name is not None:
|
||
# fail-fast:序列模式变量绑定暂不支持
|
||
self.Gen.TypeGenErr.fatal_error(pat1, "序列模式变量绑定暂不支持", "NotImplementedError")
|
||
elif pk1 == ast.ASTKind.MatchStar:
|
||
continue # 剩余元素通配:恒真
|
||
else:
|
||
self.Gen.TypeGenErr.fatal_error(pat1, "序列模式不支持的 pattern 类型", "TypeError")
|
||
# guard(若有):匹配成立且 guard 非零
|
||
g_addr: sizet = guard_arr[ci]
|
||
if g_addr != 0:
|
||
gnode: ast.AST* = (ast.AST*)(g_addr)
|
||
gv: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, gnode,
|
||
trans._funcs, trans._func_count, trans)
|
||
if gv is None:
|
||
self.Gen.TypeGenErr.fatal_error(gnode, "match guard 翻译失败", "TypeError")
|
||
gbits: int = self.Gen.ExprGenBase.get_llvm_type_bits(gv.Ty)
|
||
if gbits == 1:
|
||
g1: llvmlite.Value* = gv
|
||
else:
|
||
gzero: llvmlite.Value* = llvmlite.const_int(pool, gbits if gbits > 0 else 32, 0)
|
||
g1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, gv, gzero)
|
||
if cond is None:
|
||
cond = g1
|
||
else:
|
||
cond = llvmlite.build_and(builder, cond, g1)
|
||
if cond is None:
|
||
cond = llvmlite.const_int(pool, 1, 1)
|
||
|
||
# 下一个 check(或 default/end)
|
||
nxt: rawptr[llvmlite.BasicBlock] = None
|
||
nj: int = ci + 1
|
||
while nj < collected and def_arr[nj] == 1:
|
||
nj = nj + 1
|
||
if nj < collected:
|
||
nxt = rawptr[llvmlite.BasicBlock](check_arr[nj])
|
||
elif has_default == 1:
|
||
nxt = default_bb
|
||
else:
|
||
nxt = end_bb
|
||
llvmlite.build_cond_br(builder, cond, bbb2, nxt)
|
||
ci = ci + 1
|
||
|
||
# 6. 翻译 case body
|
||
ci = 0
|
||
while ci < collected:
|
||
if def_arr[ci] == 1:
|
||
ci = ci + 1
|
||
continue
|
||
bbb3: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](body_arr[ci])
|
||
llvmlite.position_at_end(builder, bbb3)
|
||
cnode2: ast.AST* = cases_list.get(ci)
|
||
mc3: rawptr[ast.MatchCase] = (rawptr[ast.MatchCase])(cnode2)
|
||
# case 体内 break = 跳出 match(C switch 语义):暂存/覆盖 _break_bb
|
||
sqb_old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||
trans._break_bb = end_bb
|
||
sqb_old_inmc: int = trans._in_switch_case
|
||
trans._in_switch_case = 1
|
||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||
body_list2: list[ast.AST*]* = mc3.children
|
||
if body_list2 is not None:
|
||
bc: sizet = len(body_list2)
|
||
bi: int = 0
|
||
while bi < bc:
|
||
stmt: ast.AST* = body_list2.get(bi)
|
||
if stmt is not None:
|
||
self.Gen.StmtGen.translate_stmt(trans, stmt)
|
||
bi = bi + 1
|
||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||
trans._break_bb = sqb_old_break
|
||
trans._in_switch_case = sqb_old_inmc
|
||
# 末句控制流全 return → 补 unreachable(不 br end,无 fallthrough)
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
|
||
and self._case_tail_unreachable(trans, builder, body_list2) == 0:
|
||
if nb_arr[ci] == 0:
|
||
llvmlite.build_br(builder, end_bb)
|
||
else:
|
||
# c.NoBreak:fallthrough 到下一个 case body(跳过模式检查)
|
||
nj2: int = ci + 1
|
||
while nj2 < collected and def_arr[nj2] == 1:
|
||
nj2 = nj2 + 1
|
||
if nj2 < collected:
|
||
nbb: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](body_arr[nj2])
|
||
llvmlite.build_br(builder, nbb)
|
||
elif has_default == 1:
|
||
llvmlite.build_br(builder, default_bb)
|
||
else:
|
||
llvmlite.build_br(builder, end_bb)
|
||
trans._ctrl_merge_reachable = 1
|
||
sq_merge_reach = 1
|
||
ci = ci + 1
|
||
|
||
# 7. default 块
|
||
llvmlite.position_at_end(builder, default_bb)
|
||
dbody: list[ast.AST*]* = None
|
||
if has_default == 1 and default_case_node is not None:
|
||
# 直接翻译 pass1 记录的 `case _` 臂(不再经 def_arr 槽位反查 cases_list:
|
||
# collected 下标与原始下标在"有臂被跳过"时会错位,default_bb 随之空转)
|
||
dmc_d: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](default_case_node)
|
||
# default 臂同样按 match-case 语义:break = 跳出 match
|
||
sqd_old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||
trans._break_bb = end_bb
|
||
sqd_old_inmc: int = trans._in_switch_case
|
||
trans._in_switch_case = 1
|
||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||
# dbody 预声明+重赋值会使 .get 误分派成 list[int].get
|
||
# (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃,gen1 IR 证据)。
|
||
# 用 dbody3 内联声明接收者遍历(对齐 Converter arg_defaults 规避模式)。
|
||
dbody3: list[ast.AST*]* = dmc_d.children
|
||
dbody = dbody3
|
||
if dbody3 is not None:
|
||
dn3: sizet = len(dbody3)
|
||
dj3: int = 0
|
||
while dj3 < dn3:
|
||
stmt3: ast.AST* = dbody3.get(dj3)
|
||
if stmt3 is not None:
|
||
self.Gen.StmtGen.translate_stmt(trans, stmt3)
|
||
dj3 = dj3 + 1
|
||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||
trans._break_bb = sqd_old_break
|
||
trans._in_switch_case = sqd_old_inmc
|
||
# 末句控制流全 return → 补 unreachable(不 br end_bb)
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
|
||
and self._case_tail_unreachable(trans, builder, dbody) == 0:
|
||
llvmlite.build_br(builder, end_bb)
|
||
sq_merge_reach = 1
|
||
|
||
# 8. 定位到 end
|
||
llvmlite.position_at_end(builder, end_bb)
|
||
# 覆盖嵌套控制流污染(同主路径)
|
||
trans._ctrl_merge_reachable = sq_merge_reach
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _handle_simple_match - 非 REnum 路径
|
||
#
|
||
# subject ptrtoint 到 i32 + switch 分派
|
||
# ============================================================
|
||
def _handle_simple_match(self, trans: HT.Translator*,
|
||
node: ast.Match*,
|
||
subject_val: llvmlite.Value*) -> int:
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
func: llvmlite.Function* = trans._cur_func
|
||
# 同主路径:局部记录本 simple match 的 br end_bb,收尾覆盖
|
||
# _ctrl_merge_reachable,消除 case 体内嵌套控制流污染
|
||
sm_merge_reach: int = 0
|
||
|
||
# 1. subject 转 i32(若已 i32 直接用,否则 ptrtoint)
|
||
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||
subj_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(subject_val.Ty)
|
||
subj_val: llvmlite.Value* = subject_val
|
||
if subj_bits != 32:
|
||
if self.Gen.ExprGenBase.is_ptr_type(subject_val.Ty) != 0:
|
||
subj_val = llvmlite.build_ptrtoint(builder, subject_val, i32_ty)
|
||
elif subj_bits > 32:
|
||
# trunc 到 i32
|
||
subj_val = llvmlite.build_trunc(builder, subject_val, i32_ty)
|
||
elif subj_bits == 0:
|
||
# 未知类型,尝试 ptrtoint
|
||
subj_val = llvmlite.build_ptrtoint(builder, subject_val, i32_ty)
|
||
if subj_val is None:
|
||
# fail-fast: subject 转 i32 失败
|
||
self.Gen.TypeGenErr.fatal_error(node, "match subject 转换为 i32 失败", "TypeError")
|
||
|
||
# 1b. guard 预扫描:任一臂带 guard → 改走按书写顺序的 if-else 比较链
|
||
# (Python match 语义:按序取首个"模式匹配且 guard 为真"的臂,见
|
||
# _handle_guarded_simple_match)。**无 guard 时**保持下方既有 switch 分发
|
||
# 路径逐字不变(不得有任何行为变化)。
|
||
cases_g: list[ast.AST*]* = node.cases
|
||
has_guard: int = 0
|
||
if cases_g is not None:
|
||
cg_n: sizet = len(cases_g)
|
||
cg_i: int = 0
|
||
while cg_i < cg_n:
|
||
cg_case: ast.AST* = cases_g.get(cg_i)
|
||
if cg_case is not None and cg_case.kind() == ast.ASTKind.MatchCase:
|
||
if rawptr[ast.MatchCase](cg_case).guard is not None:
|
||
has_guard = 1
|
||
cg_i = cg_i + 1
|
||
if has_guard != 0:
|
||
return self._handle_guarded_simple_match(trans, node, subj_val)
|
||
|
||
# 2. 创建 default/end BB
|
||
cnt: int = trans._label_counter
|
||
trans._label_counter = cnt + 1
|
||
name_buf: str = pool.alloc(32)
|
||
if name_buf is None:
|
||
# fail-fast: 标签缓冲区分配失败
|
||
self.Gen.TypeGenErr.fatal_error(node, "标签缓冲区分配失败", "TypeError")
|
||
viperlib.snprintf(name_buf, 32, "match.default.%d", cnt)
|
||
default_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
viperlib.snprintf(name_buf, 32, "match.end.%d", cnt)
|
||
end_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
# 3. 收集 case 信息
|
||
cases_list: list[ast.AST*]* = node.cases
|
||
if cases_list is None:
|
||
# fail-fast: match cases 缺失
|
||
self.Gen.TypeGenErr.fatal_error(node, "match cases 缺失", "TypeError")
|
||
case_count: sizet = len(cases_list)
|
||
|
||
bb_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
|
||
cv_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
|
||
def_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
|
||
nb_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
|
||
# 每个已收集臂的 MatchOr 节点指针(0 = 非 MatchOr):`case 1 | 2:` 需为
|
||
# 每个备选各产出一个 switch case 值(同一 body BB),故此处记录节点,
|
||
# 建 sw 链时逐备选展开。非 MatchOr 恒为 0,走原单 cv 路径逐字不变。
|
||
mo_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
|
||
if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None or mo_arr is None:
|
||
# fail-fast: match 分派数组分配失败
|
||
self.Gen.TypeGenErr.fatal_error(node, "match 分派数组分配失败", "TypeError")
|
||
|
||
collected: int = 0
|
||
has_default: int = 0
|
||
# 穷尽臂(`case _`)的 MatchCase 节点:pass1 显式记录,step 7 直接使用。
|
||
# 不再依赖 def_arr 槽位反查(collected → cases_list 下标在"有臂被跳过"
|
||
# 时会错位,default_bb 随之空转 → merge 误判可达 → 函数末句穷尽 match
|
||
# 被误报"流程掉出函数末尾",同时 case _ 臂不生成 IR)。
|
||
default_case_node: ast.AST* = None
|
||
sw_head: rawptr[llvmlite.SwitchCase] = None
|
||
sw_tail: rawptr[llvmlite.SwitchCase] = None
|
||
sw_count: int = 0
|
||
|
||
# 4. 第一遍:收集 + 创建 BB + 构建链表
|
||
i: int = 0
|
||
while i < case_count:
|
||
case_node: ast.AST* = cases_list.get(i)
|
||
if case_node is None:
|
||
i = i + 1
|
||
continue
|
||
if case_node.kind() != ast.ASTKind.MatchCase:
|
||
i = i + 1
|
||
continue
|
||
mc: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](case_node)
|
||
pat: ast.AST* = mc.pattern
|
||
|
||
is_def: int = 0
|
||
cv: llvmlite.Value* = None
|
||
# MatchOr 臂节点(非 MatchOr 保持 None):pass1 只记录,真正的
|
||
# 逐备选 case 值在建 sw 链时产出,保证 `case 1 | 2:` 两个值都命中同一 body。
|
||
or_node: ast.AST* = None
|
||
|
||
if pat is not None:
|
||
pk: int = pat.kind()
|
||
if pk == ast.ASTKind.MatchValue:
|
||
mv: rawptr[ast.MatchValue] = rawptr[ast.MatchValue](pat)
|
||
cv = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, mv.value,
|
||
trans._funcs, trans._func_count, trans)
|
||
elif pk == ast.ASTKind.MatchSingleton:
|
||
ms: rawptr[ast.MatchSingleton] = (rawptr[ast.MatchSingleton])(pat)
|
||
# None -> 0
|
||
cv = llvmlite.const_int32(pool, 0)
|
||
elif pk == ast.ASTKind.MatchAs:
|
||
ma: rawptr[ast.MatchAs] = rawptr[ast.MatchAs](pat)
|
||
if ma.pattern is None:
|
||
is_def = 1
|
||
has_default = 1
|
||
default_case_node = case_node
|
||
elif pk == ast.ASTKind.MatchOr:
|
||
# 记录整节点:备选在建 sw 链处逐个数展开,不再只取第 0 个。
|
||
or_node = pat
|
||
elif pk == ast.ASTKind.MatchClass:
|
||
# 本路径(非 REnum 分派)不为 class-pattern 臂产出 case 值 → 该臂被
|
||
# 静默丢弃、臂体不可达。若该 class-pattern 确实指向已注册 REnum
|
||
# (_is_renum_class_name / _is_renum_by_entry 命中),说明是 REnum
|
||
# 分派失配,必须 fail-fast 暴露,不得静默丢 case(禁止兜底掩盖)。
|
||
rnm_nr: str = self._extract_renum_name_from_cls(pat)
|
||
if rnm_nr is not None and (self.Gen.ClassGenEnum._is_renum_class_name(rnm_nr) != 0 or self.Gen.ClassGenEnum._is_renum_by_entry(rnm_nr) != 0):
|
||
self.Gen.TypeGenErr.fatal_error(pat,
|
||
f"非 REnum 路径收到 REnum 变体模式 'case {rnm_nr}.*':case 值无法产出,该臂会被静默丢弃(REnum 分派失配)",
|
||
"InternalCompilerError")
|
||
|
||
if is_def == 0:
|
||
if collected >= MAX_MATCH_CASES:
|
||
break
|
||
viperlib.snprintf(name_buf, 32, "match.case.%d.%d", cnt, i)
|
||
bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
else:
|
||
bb = default_bb
|
||
|
||
body_list: list[ast.AST*]* = mc.children
|
||
nb: int = self._has_no_break(body_list)
|
||
|
||
# 本臂占用的收集槽位:collected 随后自增;is_def==0 时上方已保证未越界
|
||
cur_slot: int = collected
|
||
if collected < MAX_MATCH_CASES:
|
||
bb_arr[cur_slot] = sizet(bb)
|
||
cv_arr[cur_slot] = sizet(cv)
|
||
def_arr[cur_slot] = is_def
|
||
nb_arr[cur_slot] = nb
|
||
mo_arr[cur_slot] = sizet(or_node)
|
||
collected = collected + 1
|
||
|
||
if is_def == 0:
|
||
mo_addr: sizet = mo_arr[cur_slot]
|
||
if mo_addr != 0:
|
||
# MatchOr 臂:为每个备选各产出一个 case 值,全部指向同一 bb
|
||
# (等价 C 的 `case 1: case 2:`,共享 body)。非 MatchValue/
|
||
# MatchSingleton 备选无法产出值,fail-fast 不得静默丢弃。
|
||
mo2: rawptr[ast.MatchOr] = (rawptr[ast.MatchOr])(mo_addr)
|
||
pats2: list[ast.AST*]* = mo2.patterns
|
||
if pats2 is None or len(pats2) == 0:
|
||
self.Gen.TypeGenErr.fatal_error(pat, "switch OR 模式无备选子模式", "TypeError")
|
||
pats2_n: sizet = len(pats2)
|
||
pats2_i: int = 0
|
||
while pats2_i < pats2_n:
|
||
alt_pat: ast.AST* = pats2.get(pats2_i)
|
||
if alt_pat is not None:
|
||
alt_cv: llvmlite.Value* = None
|
||
if alt_pat.kind() == ast.ASTKind.MatchValue:
|
||
alt_mv: rawptr[ast.MatchValue] = (rawptr[ast.MatchValue])(alt_pat)
|
||
alt_cv = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, alt_mv.value,
|
||
trans._funcs, trans._func_count, trans)
|
||
elif alt_pat.kind() == ast.ASTKind.MatchSingleton:
|
||
# None -> 0(与单值/守卫路径同口径)
|
||
alt_cv = llvmlite.const_int32(pool, 0)
|
||
else:
|
||
self.Gen.TypeGenErr.fatal_error(alt_pat, "switch OR 模式备选不是值模式", "TypeError")
|
||
if alt_cv is not None:
|
||
sc2: rawptr[llvmlite.SwitchCase] = llvmlite.new_switch_case(pool, alt_cv, bb)
|
||
if sc2 is not None:
|
||
if sw_head is None:
|
||
sw_head = sc2
|
||
sw_tail = sc2
|
||
else:
|
||
sw_tail.Next = sc2
|
||
sw_tail = sc2
|
||
sw_count = sw_count + 1
|
||
pats2_i = pats2_i + 1
|
||
elif cv is not None:
|
||
sc: rawptr[llvmlite.SwitchCase] = llvmlite.new_switch_case(pool, cv, bb)
|
||
if sc is not None:
|
||
if sw_head is None:
|
||
sw_head = sc
|
||
sw_tail = sc
|
||
else:
|
||
sw_tail.Next = sc
|
||
sw_tail = sc
|
||
sw_count = sw_count + 1
|
||
|
||
i = i + 1
|
||
|
||
# 5. 发射 switch
|
||
llvmlite.build_switch(builder, subj_val, default_bb, sw_head, sw_count)
|
||
|
||
# 6. 第二遍:翻译 case body
|
||
i = 0
|
||
while i < collected:
|
||
case_node: ast.AST* = cases_list.get(i)
|
||
if case_node is None:
|
||
i = i + 1
|
||
continue
|
||
mc: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](case_node)
|
||
|
||
bb_addr: sizet = bb_arr[i]
|
||
case_bb: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](bb_addr)
|
||
is_def: int = def_arr[i]
|
||
nb: int = nb_arr[i]
|
||
|
||
# default case 的 body 在 step 7 单独翻译,这里跳过避免重复
|
||
if is_def == 1:
|
||
i = i + 1
|
||
continue
|
||
|
||
llvmlite.position_at_end(builder, case_bb)
|
||
|
||
# case 体内 break = 跳出 match(C switch 语义):暂存/覆盖 _break_bb
|
||
smb_old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||
trans._break_bb = end_bb
|
||
smb_old_inmc: int = trans._in_switch_case
|
||
trans._in_switch_case = 1
|
||
|
||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||
|
||
body_list: list[ast.AST*]* = mc.children
|
||
if body_list is not None:
|
||
bc: sizet = len(body_list)
|
||
bi: int = 0
|
||
while bi < bc:
|
||
stmt: ast.AST* = body_list.get(bi)
|
||
if stmt is not None:
|
||
self.Gen.StmtGen.translate_stmt(trans, stmt)
|
||
bi = bi + 1
|
||
|
||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||
trans._break_bb = smb_old_break
|
||
trans._in_switch_case = smb_old_inmc
|
||
|
||
# 若未终止:默认跳 end;含 fallthrough(`fallthrough` 标记或兼容的
|
||
# c.NoBreak())则落到下一个 case 的 body(跳过其模式检查)。
|
||
# 末句控制流全 return → 补 unreachable(不 br end_bb)
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
|
||
and self._case_tail_unreachable(trans, builder, body_list) == 0:
|
||
if nb == 0:
|
||
llvmlite.build_br(builder, end_bb)
|
||
else:
|
||
sm_ft_nj: int = i + 1
|
||
while sm_ft_nj < collected and def_arr[sm_ft_nj] != 0:
|
||
sm_ft_nj = sm_ft_nj + 1
|
||
if sm_ft_nj < collected:
|
||
sm_ft_bb: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](bb_arr[sm_ft_nj])
|
||
llvmlite.build_br(builder, sm_ft_bb)
|
||
elif has_default != 0:
|
||
llvmlite.build_br(builder, default_bb)
|
||
else:
|
||
llvmlite.build_br(builder, end_bb)
|
||
trans._ctrl_merge_reachable = 1
|
||
sm_merge_reach = 1
|
||
|
||
i = i + 1
|
||
|
||
# 7. default 块(含 `case _` 穷尽臂)
|
||
llvmlite.position_at_end(builder, default_bb)
|
||
if has_default == 0 or default_case_node is None:
|
||
# 无显式 default:default 直接跳 end(match 不穷尽 ⇒ merge 可达)
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||
llvmlite.build_br(builder, end_bb)
|
||
trans._ctrl_merge_reachable = 1
|
||
sm_merge_reach = 1
|
||
else:
|
||
# 直接翻译 pass1 记录的 `case _` 臂(不再经 def_arr 槽位反查 cases_list:
|
||
# collected 下标与原始下标在"有臂被跳过"时会错位,default_bb 随之空转)
|
||
dmc_d: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](default_case_node)
|
||
# default 臂同样按 match-case 语义:break = 跳出 match
|
||
smd_old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||
trans._break_bb = end_bb
|
||
smd_old_inmc: int = trans._in_switch_case
|
||
trans._in_switch_case = node.is_switch
|
||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||
# dbody 预声明+重赋值会使 .get 误分派成 list[int].get
|
||
# (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃,gen1 IR 证据)。
|
||
# 用 dbody3 内联声明接收者遍历(对齐 Converter arg_defaults 规避模式)。
|
||
dbody3: list[ast.AST*]* = dmc_d.children
|
||
if dbody3 is not None:
|
||
dn3: sizet = len(dbody3)
|
||
dj3: int = 0
|
||
while dj3 < dn3:
|
||
stmt3: ast.AST* = dbody3.get(dj3)
|
||
if stmt3 is not None:
|
||
self.Gen.StmtGen.translate_stmt(trans, stmt3)
|
||
dj3 = dj3 + 1
|
||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||
trans._break_bb = smd_old_break
|
||
trans._in_switch_case = smd_old_inmc
|
||
# 末句控制流全 return → 补 unreachable(不 br end_bb)
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
|
||
and self._case_tail_unreachable(trans, builder, dbody3) == 0:
|
||
llvmlite.build_br(builder, end_bb)
|
||
trans._ctrl_merge_reachable = 1
|
||
sm_merge_reach = 1
|
||
|
||
# 8. 定位到 end
|
||
llvmlite.position_at_end(builder, end_bb)
|
||
# 覆盖嵌套控制流污染(同主路径)
|
||
trans._ctrl_merge_reachable = sm_merge_reach
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _handle_guarded_simple_match - _handle_simple_match 的 guard 分支
|
||
#
|
||
# 任一臂带 guard 时改走**按书写顺序**的 if-else 比较链分发(对齐 Python
|
||
# match 语义:按序取首个"模式匹配且 guard 为真"的臂):
|
||
# entry → check0
|
||
# check_i: cond_i → body_i(不满足 → check_{i+1})
|
||
# body_i : <body> → end(fallthrough 时落到下一个非通配 body)
|
||
# 全部 check 不中 → default_bb(唯一的**无 guard** 通配臂 body,若有)→ end
|
||
# cond_i = 值臂(subj_val == case值) / 通配臂(恒真),再与 guard(归一为 i1)取与。
|
||
# guard 归一化、i1 判定、const_int 参数顺序(pool, bits, val)均与
|
||
# _handle_sequence_match 同款(L1118-1135)。
|
||
# 注意:**无 guard** 的 match/switch 不会进入本函数(见 _handle_simple_match
|
||
# 的 has_guard 预扫描),既有 switch 分派路径逐字不变。
|
||
# ============================================================
|
||
def _handle_guarded_simple_match(self, trans: HT.Translator*,
|
||
node: ast.Match*,
|
||
subj_val: llvmlite.Value*) -> int:
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
func: llvmlite.Function* = trans._cur_func
|
||
# 同主路径:局部记录本 guarded match 的 br end_bb,收尾覆盖
|
||
# _ctrl_merge_reachable,消除 case 体内嵌套控制流污染
|
||
gm_merge_reach: int = 0
|
||
|
||
# 1. 创建 default/end BB
|
||
cnt: int = trans._label_counter
|
||
trans._label_counter = cnt + 1
|
||
name_buf: str = pool.alloc(32)
|
||
if name_buf is None:
|
||
self.Gen.TypeGenErr.fatal_error(node, "标签缓冲区分配失败", "TypeError")
|
||
viperlib.snprintf(name_buf, 32, "match.guard.default.%d", cnt)
|
||
default_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
viperlib.snprintf(name_buf, 32, "match.guard.end.%d", cnt)
|
||
end_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
# 2. 收集 case 信息(check/body BB、default 标记、nobreak、mc、cv)
|
||
cases_list: list[ast.AST*]* = node.cases
|
||
if cases_list is None:
|
||
self.Gen.TypeGenErr.fatal_error(node, "match cases 缺失", "TypeError")
|
||
case_count: sizet = len(cases_list)
|
||
check_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
|
||
body_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
|
||
def_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
|
||
nb_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
|
||
mc_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
|
||
cv_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
|
||
# 每个已收集臂的 MatchOr 节点指针(0 = 非 MatchOr):check 链需把
|
||
# `case 1 | 2` 变成各备选 subj_val == cv_i 的 OR,故此处记录节点,
|
||
# 发射 check 时逐备选展开取 OR。非 MatchOr 恒为 0,走原单 cv 路径不变。
|
||
or_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
|
||
if check_arr is None or body_arr is None or def_arr is None \
|
||
or nb_arr is None or mc_arr is None or cv_arr is None or or_arr is None:
|
||
self.Gen.TypeGenErr.fatal_error(node, "match 分派数组分配失败", "TypeError")
|
||
collected: int = 0
|
||
has_default: int = 0
|
||
# 唯一的**无 guard** 通配臂(default):其 body = default_bb,且 default_bb
|
||
# 是所有 check 不中时的落点。带 guard 的通配臂不算 default(各有独立
|
||
# check/body BB),避免其 guard 被静默忽略。
|
||
default_case_node: ast.AST* = None
|
||
first_check: int = -1
|
||
i: int = 0
|
||
while i < case_count:
|
||
if collected >= MAX_MATCH_CASES:
|
||
self.Gen.TypeGenErr.fatal_error(node, f"match case 数量超过上限 MAX_MATCH_CASES={MAX_MATCH_CASES}", "OverflowError")
|
||
break
|
||
case_node: ast.AST* = cases_list.get(i)
|
||
if case_node is None or case_node.kind() != ast.ASTKind.MatchCase:
|
||
i = i + 1
|
||
continue
|
||
mc: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](case_node)
|
||
pat: ast.AST* = mc.pattern
|
||
gnode0: ast.AST* = mc.guard
|
||
is_def: int = 0
|
||
cv: llvmlite.Value* = None
|
||
# MatchOr 臂节点(非 MatchOr 保持 None):pass1 只记录,check 发射时
|
||
# 逐备选展开成 subj_val == cv_i 的 OR,不再只看第 0 个备选。
|
||
or_node: ast.AST* = None
|
||
if pat is not None:
|
||
pk: int = pat.kind()
|
||
if pk == ast.ASTKind.MatchValue:
|
||
mv: rawptr[ast.MatchValue] = rawptr[ast.MatchValue](pat)
|
||
cv = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, mv.value,
|
||
trans._funcs, trans._func_count, trans)
|
||
elif pk == ast.ASTKind.MatchSingleton:
|
||
# None -> 0
|
||
cv = llvmlite.const_int32(pool, 0)
|
||
elif pk == ast.ASTKind.MatchAs:
|
||
ma: rawptr[ast.MatchAs] = rawptr[ast.MatchAs](pat)
|
||
if ma.pattern is None and gnode0 is None:
|
||
# 唯一的**无 guard** 通配臂 → default
|
||
is_def = 1
|
||
# ma.pattern is None 且 guard 非空 → 带 guard 的通配臂:条件恒真
|
||
# 再与 guard 取与(见发射阶段),不当作 default
|
||
elif pk == ast.ASTKind.MatchOr:
|
||
# 记录整节点:check 发射时逐备选展开为 OR(见 step 4)
|
||
or_node = pat
|
||
else:
|
||
# 禁止静默兜底:guard 分支只支持 值/None/通配/或 模式
|
||
self.Gen.TypeGenErr.fatal_error(pat, "guard 分支不支持的 case 模式", "TypeError")
|
||
if is_def == 1:
|
||
has_default = 1
|
||
default_case_node = case_node
|
||
check_arr[collected] = 0
|
||
body_arr[collected] = sizet(default_bb)
|
||
else:
|
||
viperlib.snprintf(name_buf, 32, "match.guard.check.%d.%d", cnt, i)
|
||
cbb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
viperlib.snprintf(name_buf, 32, "match.guard.body.%d.%d", cnt, i)
|
||
bbb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
check_arr[collected] = sizet(cbb)
|
||
body_arr[collected] = sizet(bbb)
|
||
if first_check < 0:
|
||
first_check = collected
|
||
body_list: list[ast.AST*]* = mc.children
|
||
nb: int = self._has_no_break(body_list)
|
||
def_arr[collected] = is_def
|
||
nb_arr[collected] = nb
|
||
mc_arr[collected] = sizet(mc)
|
||
cv_arr[collected] = sizet(cv)
|
||
or_arr[collected] = sizet(or_node)
|
||
collected = collected + 1
|
||
i = i + 1
|
||
|
||
# 3. 入口 → 第一个 check(或 default/end)
|
||
if first_check >= 0:
|
||
head_bb: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](check_arr[first_check])
|
||
llvmlite.build_br(builder, head_bb)
|
||
elif has_default == 1:
|
||
llvmlite.build_br(builder, default_bb)
|
||
else:
|
||
llvmlite.build_br(builder, end_bb)
|
||
|
||
# 4. 发射 check 链(按书写顺序)
|
||
ci: int = 0
|
||
while ci < collected:
|
||
if def_arr[ci] == 1:
|
||
ci = ci + 1
|
||
continue
|
||
cbb2: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](check_arr[ci])
|
||
bbb2: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](body_arr[ci])
|
||
llvmlite.position_at_end(builder, cbb2)
|
||
mc2: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](mc_arr[ci])
|
||
# 值条件:subj_val == case值(通配臂无 case 值 → cond 保持 None=恒真)
|
||
cond: llvmlite.Value* = None
|
||
or_addr: sizet = or_arr[ci]
|
||
cv_addr: sizet = cv_arr[ci]
|
||
if or_addr != 0:
|
||
# MatchOr 臂:cond = (subj_val == cv_0) OR (subj_val == cv_1) OR ...
|
||
# 各备选逐一比较后取 OR(非 MatchValue/MatchSingleton 备选无法产出
|
||
# 值 → fail-fast,不静默丢弃)。
|
||
mo4: rawptr[ast.MatchOr] = (rawptr[ast.MatchOr])(or_addr)
|
||
pats4: list[ast.AST*]* = mo4.patterns
|
||
if pats4 is None or len(pats4) == 0:
|
||
self.Gen.TypeGenErr.fatal_error(node, "guard OR 模式无备选子模式", "TypeError")
|
||
pats4_n: sizet = len(pats4)
|
||
pats4_i: int = 0
|
||
while pats4_i < pats4_n:
|
||
alt_pat2: ast.AST* = pats4.get(pats4_i)
|
||
if alt_pat2 is not None:
|
||
alt_cv2: llvmlite.Value* = None
|
||
if alt_pat2.kind() == ast.ASTKind.MatchValue:
|
||
alt_mv2: rawptr[ast.MatchValue] = (rawptr[ast.MatchValue])(alt_pat2)
|
||
alt_cv2 = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, alt_mv2.value,
|
||
trans._funcs, trans._func_count, trans)
|
||
elif alt_pat2.kind() == ast.ASTKind.MatchSingleton:
|
||
# None -> 0(与单值路径同口径)
|
||
alt_cv2 = llvmlite.const_int32(pool, 0)
|
||
else:
|
||
self.Gen.TypeGenErr.fatal_error(alt_pat2, "guard OR 模式备选不是值模式", "TypeError")
|
||
if alt_cv2 is not None:
|
||
cc: llvmlite.Value* = self._seq_cmp_eq(trans, builder, subj_val, alt_cv2)
|
||
if cc is None:
|
||
self.Gen.TypeGenErr.fatal_error(node, "match OR 备选值比较失败", "TypeError")
|
||
if cond is None:
|
||
cond = cc
|
||
else:
|
||
cond = llvmlite.build_or(builder, cond, cc)
|
||
pats4_i = pats4_i + 1
|
||
if cond is None:
|
||
self.Gen.TypeGenErr.fatal_error(node, "guard OR 模式未能产出任何比较条件", "TypeError")
|
||
elif cv_addr != 0:
|
||
cv2: llvmlite.Value* = (llvmlite.Value*)(cv_addr)
|
||
c1: llvmlite.Value* = self._seq_cmp_eq(trans, builder, subj_val, cv2)
|
||
if c1 is None:
|
||
self.Gen.TypeGenErr.fatal_error(node, "match case 值比较失败", "TypeError")
|
||
cond = c1
|
||
# guard(若有):匹配成立且 guard 非零(归一为 i1,写法同序列路径)
|
||
g_addr: sizet = sizet(mc2.guard)
|
||
if g_addr != 0:
|
||
gnode: ast.AST* = (ast.AST*)(g_addr)
|
||
gv: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, gnode,
|
||
trans._funcs, trans._func_count, trans)
|
||
if gv is None:
|
||
self.Gen.TypeGenErr.fatal_error(gnode, "match guard 翻译失败", "TypeError")
|
||
gbits: int = self.Gen.ExprGenBase.get_llvm_type_bits(gv.Ty)
|
||
if gbits == 1:
|
||
g1: llvmlite.Value* = gv
|
||
else:
|
||
gzero: llvmlite.Value* = llvmlite.const_int(pool, gbits if gbits > 0 else 32, 0)
|
||
g1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, gv, gzero)
|
||
if cond is None:
|
||
cond = g1
|
||
else:
|
||
cond = llvmlite.build_and(builder, cond, g1)
|
||
if cond is None:
|
||
cond = llvmlite.const_int(pool, 1, 1)
|
||
# 下一个 check(跳过 default)→ 否则 default/end
|
||
nxt: rawptr[llvmlite.BasicBlock] = None
|
||
nj: int = ci + 1
|
||
while nj < collected and def_arr[nj] == 1:
|
||
nj = nj + 1
|
||
if nj < collected:
|
||
nxt = rawptr[llvmlite.BasicBlock](check_arr[nj])
|
||
elif has_default == 1:
|
||
nxt = default_bb
|
||
else:
|
||
nxt = end_bb
|
||
llvmlite.build_cond_br(builder, cond, bbb2, nxt)
|
||
ci = ci + 1
|
||
|
||
# 5. 翻译 case body
|
||
ci = 0
|
||
while ci < collected:
|
||
if def_arr[ci] == 1:
|
||
ci = ci + 1
|
||
continue
|
||
bbb3: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](body_arr[ci])
|
||
llvmlite.position_at_end(builder, bbb3)
|
||
mc3: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](mc_arr[ci])
|
||
# case 体内 break = 跳出 match(C switch 语义):暂存/覆盖 _break_bb
|
||
gmb_old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||
trans._break_bb = end_bb
|
||
gmb_old_inmc: int = trans._in_switch_case
|
||
trans._in_switch_case = 1
|
||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||
body_list2: list[ast.AST*]* = mc3.children
|
||
if body_list2 is not None:
|
||
bc: sizet = len(body_list2)
|
||
bi: int = 0
|
||
while bi < bc:
|
||
stmt: ast.AST* = body_list2.get(bi)
|
||
if stmt is not None:
|
||
self.Gen.StmtGen.translate_stmt(trans, stmt)
|
||
bi = bi + 1
|
||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||
trans._break_bb = gmb_old_break
|
||
trans._in_switch_case = gmb_old_inmc
|
||
# 若未终止:默认跳 end;含 fallthrough 则落到下一个非通配 body。
|
||
# 末句控制流全 return → 补 unreachable(不 br end_bb)
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
|
||
and self._case_tail_unreachable(trans, builder, body_list2) == 0:
|
||
if nb_arr[ci] == 0:
|
||
llvmlite.build_br(builder, end_bb)
|
||
else:
|
||
nj2: int = ci + 1
|
||
while nj2 < collected and def_arr[nj2] == 1:
|
||
nj2 = nj2 + 1
|
||
if nj2 < collected:
|
||
nbb: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](body_arr[nj2])
|
||
llvmlite.build_br(builder, nbb)
|
||
elif has_default == 1:
|
||
llvmlite.build_br(builder, default_bb)
|
||
else:
|
||
llvmlite.build_br(builder, end_bb)
|
||
trans._ctrl_merge_reachable = 1
|
||
gm_merge_reach = 1
|
||
ci = ci + 1
|
||
|
||
# 6. default 块(唯一的**无 guard** 通配臂;全部 check 不中时落此)
|
||
llvmlite.position_at_end(builder, default_bb)
|
||
if has_default == 0 or default_case_node is None:
|
||
# 无无 guard 通配臂:match 非穷尽 ⇒ merge 可达,default 直接跳 end
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||
llvmlite.build_br(builder, end_bb)
|
||
trans._ctrl_merge_reachable = 1
|
||
gm_merge_reach = 1
|
||
else:
|
||
dmc_d: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](default_case_node)
|
||
# default 臂同样按 match-case 语义:break = 跳出 match
|
||
gmd_old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||
trans._break_bb = end_bb
|
||
gmd_old_inmc: int = trans._in_switch_case
|
||
trans._in_switch_case = node.is_switch
|
||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||
# dbody3 内联声明接收者遍历(规避 .get 误分派成 list[int].get 的截断)
|
||
dbody3: list[ast.AST*]* = dmc_d.children
|
||
if dbody3 is not None:
|
||
dn3: sizet = len(dbody3)
|
||
dj3: int = 0
|
||
while dj3 < dn3:
|
||
stmt3: ast.AST* = dbody3.get(dj3)
|
||
if stmt3 is not None:
|
||
self.Gen.StmtGen.translate_stmt(trans, stmt3)
|
||
dj3 = dj3 + 1
|
||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||
trans._break_bb = gmd_old_break
|
||
trans._in_switch_case = gmd_old_inmc
|
||
# 末句控制流全 return → 补 unreachable(不 br end_bb)
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
|
||
and self._case_tail_unreachable(trans, builder, dbody3) == 0:
|
||
llvmlite.build_br(builder, end_bb)
|
||
trans._ctrl_merge_reachable = 1
|
||
gm_merge_reach = 1
|
||
|
||
# 7. 定位到 end
|
||
llvmlite.position_at_end(builder, end_bb)
|
||
# 覆盖嵌套控制流污染(同主路径)
|
||
trans._ctrl_merge_reachable = gm_merge_reach
|
||
return 0
|