Files
ViperC/App/lib/core/Handles/HandlesMatch.vp
T
TermiNexus a45b806afa fix(match): merge 可达性用局部标志记录,消除 case 体内嵌套 if 污染
主 match/sequence/simple 三条路径:case 体内嵌套 If(无 else + return)翻译时把 _ctrl_merge_reachable 置 1,全 case return 的 match 被误判 merge 可达 → 函数收尾 fail-fast '流程掉出末尾'(LLvmLiteTest includes/llvmlite/__module.vp _is_opaque_struct)。改用局部变量记录本 match 自身的 br end_bb,收尾覆盖全局标志
2026-08-19 01:04:42 +08:00

1285 lines
60 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import viperlib
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesBody as HandlesBody
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesClassDef as HandlesClassDef
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.HandlesType as HandlesType
# ============================================================
# HandlesMatch - match 语句处理(P6 对象化后的委托层)
#
# NewMatchHandle 工厂已迁移为 lib.core.Gen.StmtGenMixin 的方法
# (MatchHandle 类保留:trans.MatchH 的类型,由 HandlesTranslator.
# _init_state 经 NewMatchHandle 委托创建)。
#
# 逻辑移植自 TPC 的 HandlesMatch.py,用 Viper 语法重写。
# 两条路径:
# 1. REnum 路径:bitcast subject 到 i32* 读 __tag + switch 分派
# 2. 非 REnum 路径:subject ptrtoint 到 i32 + switch 分派
#
# IR 模式(REnum):
# %tag_ptr = bitcast <struct>* %subj to i32*
# %tag = load i32, i32* %tag_ptr
# switch i32 %tag, label %default [ i32 <tag1>, label %case1 ... ]
# case1:
# ... body ...
# br label %end (若无 c.NoBreak)
# end:
# ============================================================
# match case 数量上限
MAX_MATCH_CASES: t.CDefine = 32
# 作用域种类常量(与 HandlesVar 的 Scope.Kind 区分)
SCOPE_MATCH: t.CDefine = 6
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式)
#
# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。
# 委托函数用本地 _g_gen(cast 成 Generator 类型)调
# StmtGenMixin 方法,避免函数体 import 包模块与类/模块名歧义。
# ============================================================
_g_gen: t.CVoid | t.CPtr = None
def set_global_gen(gen: t.CVoid | t.CPtr) -> None:
"""注入全局 gen 单例(BuildPipeline/main 调用)"""
global _g_gen
_g_gen = gen
@t.NoVTable
class MatchHandle(HandlesBase.Mixin):
"""match 语句处理器:REnum + 非 REnum 两条路径"""
def __init__(self, trans: HT.Translator | t.CPtr):
self.Trans = trans
# ============================================================
# Handle - match 语句主入口,返回 0
# ============================================================
def Handle(self, node: ast.AST | t.CPtr) -> int:
if node is None:
return 0
trans: HT.Translator | t.CPtr = self.Trans
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
if builder is None or func is None:
return 0
# 追加90:match merge 可达性重置(下方 br end_bb 处置 1)。
# 嵌套语句(case 体内的 If/While 等)翻译时会改写 _ctrl_merge_reachable,
# 用局部变量单独记录"本 match 是否有 br 进入 end_bb",收尾时覆盖,
# 消除嵌套控制流污染(_is_opaque_struct 的 case 内 if 无 else + return
# 把标志置 1,全 case return 的 match 被误判 merge 可达 → 函数收尾
# fail-fast "流程掉出末尾",见 LLvmLiteTest/__module.vp)。
trans._ctrl_merge_reachable = 0
m_merge_reach: int = 0
m_node: ast.Match | t.CPtr = (ast.Match | t.CPtr)(node)
# 1. 求值 subject
subject_node: ast.AST | t.CPtr = 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(m_node, subject_node)
subject_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, subject_node,
trans._funcs, trans._func_count, trans)
if subject_val is None:
# fail-fast: match subject 翻译失败
HandlesType.fatal_error(subject_node, "match subject 翻译失败", "TypeError")
# 2. 检测是否 REnum match
is_renum: int = 0
renum_name: str = None
subject_ptr: llvmlite.Value | t.CPtr = None
# 2a. 若 subject 是 Name,查变量注解类名
if subject_node.kind() == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(subject_node)
if nm.id is not None:
entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
trans.SymTab, nm.id)
if entry is not None and entry.AnnotClassName is not None \
and HandlesClassDef._is_renum_class_name(
entry.AnnotClassName) != 0:
is_renum = 1
renum_name = entry.AnnotClassName
subject_ptr = HandlesVar.lookup_var(trans.SymTab, nm.id)
# 2b. 若未确定,遍历 cases 查 MatchClass 变体
if is_renum == 0:
cases_list: list[ast.AST | t.CPtr] | t.CPtr = m_node.cases
if cases_list is not None:
cn: t.CSizeT = len(cases_list)
ci: int = 0
while ci < cn and is_renum == 0:
case_node: ast.AST | t.CPtr = cases_list.get(ci)
if case_node is not None \
and case_node.kind() == ast.ASTKind.MatchCase:
mc: ast.MatchCase | t.CPtr = (
ast.MatchCase | t.CPtr)(case_node)
pat: ast.AST | t.CPtr = 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 HandlesClassDef._is_renum_class_name(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(m_node, renum_name, subject_ptr)
return self._handle_simple_match(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 | t.CPtr) -> str:
if pattern is None:
return None
mc: ast.MatchClass | t.CPtr = (ast.MatchClass | t.CPtr)(pattern)
cls_node: ast.AST | t.CPtr = mc.cls
if cls_node is None:
return None
# Attribute 形式
if cls_node.kind() == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cls_node)
if at.value is not None:
if at.value.kind() == ast.ASTKind.Name:
inner_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
return inner_nm.id
if at.value.kind() == ast.ASTKind.Attribute:
inner_at: ast.Attribute | t.CPtr = (
ast.Attribute | t.CPtr)(at.value)
return inner_at.attr
# Name 形式:遍历所有 REnum 类反查
if cls_node.kind() == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(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 | t.CPtr) -> str:
if pattern is None:
return None
mc: ast.MatchClass | t.CPtr = (ast.MatchClass | t.CPtr)(pattern)
cls_node: ast.AST | t.CPtr = mc.cls
if cls_node is None:
return None
if cls_node.kind() == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cls_node)
return at.attr
if cls_node.kind() == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(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 HandlesClassDef._lookup_renum_variant(variant_name)
# ============================================================
# _has_no_break - 检测 case body 是否含 c.NoBreak() 调用
#
# 遍历 case body 顶层语句,查找 Expr(Call(Attribute(Name('c'), 'NoBreak')))
# ============================================================
def _has_no_break(self, body_list: list[ast.AST | t.CPtr] | t.CPtr) -> int:
if body_list is None:
return 0
n: t.CSizeT = len(body_list)
i: int = 0
while i < n:
stmt: ast.AST | t.CPtr = body_list.get(i)
if stmt is not None and stmt.kind() == ast.ASTKind.Expr:
expr_node: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(stmt)
val: ast.AST | t.CPtr = expr_node.value
if val is not None and val.kind() == ast.ASTKind.Call:
call_node: ast.Call | t.CPtr = (ast.Call | t.CPtr)(val)
fn: ast.AST | t.CPtr = call_node.func
if fn is not None and fn.kind() == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (
ast.Attribute | t.CPtr)(fn)
if at.value is not None \
and at.value.kind() == ast.ASTKind.Name:
base_nm: ast.Name | t.CPtr = (
ast.Name | t.CPtr)(at.value)
if base_nm.id is not None \
and string.strcmp(base_nm.id, "c") == 0 \
and at.attr is not None \
and string.strcmp(at.attr, "NoBreak") == 0:
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, node: ast.Match | t.CPtr,
renum_name: str,
subject_ptr: llvmlite.Value | t.CPtr) -> int:
trans: HT.Translator | t.CPtr = self.Trans
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
# 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 | t.CPtr = subject_ptr.Ty
if subj_ty is not None and HandlesExpr.is_ptr_type(subj_ty) != 0 \
and subj_ty.Pointee is not None \
and HandlesExpr.is_ptr_type(subj_ty.Pointee) != 0:
# 情况1: T** → load 一次得 T*
loaded_sub: llvmlite.Value | t.CPtr = 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 HandlesExpr.is_ptr_type(subject_ptr.Ty) == 0:
renum_se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(
renum_name)
renum_sty: llvmlite.LLVMType | t.CPtr = None
if renum_se is not None:
renum_sty = renum_se.Ty
if renum_sty is None:
# fail-fast: REnum 结构体未注册,无法构造
HandlesType.fatal_error(
node,
f"REnum 结构体 '{renum_name}' 未注册",
"NameError")
i64_ty0: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
int_val: llvmlite.Value | t.CPtr = subject_ptr
# 非 i64 整数值先扩展/截断到 i64(inttoptr 要求同宽)
# 仅当 subj_ty 是已知整数类型时转换;类型未知时保持原值
if subj_ty is not None and HandlesExpr.get_llvm_type_bits(subj_ty) != 64 \
and HandlesExpr.is_ptr_type(subj_ty) == 0:
if HandlesExpr.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 | t.CPtr = llvmlite.Ptr(pool, renum_sty)
subj_ptr0: llvmlite.Value | t.CPtr = llvmlite.build_inttoptr(
builder, int_val, renum_ptr_ty0)
if subj_ptr0 is not None:
subject_ptr = subj_ptr0
# 1. bitcast subject 到 i32* 读 __tag
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
i32_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty)
tag_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, subject_ptr, i32_ptr_ty)
if tag_ptr is None:
# fail-fast: REnum tag 指针转换失败
HandlesType.fatal_error(node, "REnum tag 指针转换失败", "TypeError")
tag_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, i32_ty, tag_ptr)
if tag_val is None:
# fail-fast: REnum tag 读取失败
HandlesType.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: 标签缓冲区分配失败
HandlesType.fatal_error(node, "标签缓冲区分配失败", "TypeError")
viperlib.snprintf(name_buf, 32, "match.default.%d", cnt)
default_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "match.end.%d", cnt)
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, func, name_buf)
# 3. 准备收集数组(用 CSizeT 数组存指针)
cases_list: list[ast.AST | t.CPtr] | t.CPtr = node.cases
if cases_list is None:
# fail-fast: match cases 缺失
HandlesType.fatal_error(node, "match cases 缺失", "TypeError")
case_count: t.CSizeT = len(cases_list)
# BB 指针数组、case 值指针数组、default 标记数组、nobreak 标记数组
bb_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES)
cv_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES)
def_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
nb_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None:
# fail-fast: match 分派数组分配失败
HandlesType.fatal_error(node, "match 分派数组分配失败", "TypeError")
collected: int = 0
has_default: int = 0
# SwitchCase 链表
sw_head: llvmlite.SwitchCase | t.CPtr = None
sw_tail: llvmlite.SwitchCase | t.CPtr = None
sw_count: int = 0
# 4. 第一遍:收集 case 信息 + 创建 BB + 构建链表
i: int = 0
while i < case_count:
case_node: ast.AST | t.CPtr = 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: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node)
pat: ast.AST | t.CPtr = mc.pattern
is_def: int = 0
cv: llvmlite.Value | t.CPtr = None
if pat is not None:
pk: int = pat.kind()
if pk == ast.ASTKind.MatchClass:
vnm: str = self._extract_variant_name_from_cls(pat)
if vnm is not None:
tag: int = HandlesClassDef._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, i32_ty, tag,
tag_buf if tag_buf is not None else "0")
elif pk == ast.ASTKind.MatchAs:
ma: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(pat)
if ma.pattern is None:
is_def = 1
has_default = 1
elif pk == ast.ASTKind.MatchValue:
mv: ast.MatchValue | t.CPtr = (ast.MatchValue | t.CPtr)(pat)
cv = HandlesExpr.translate_value(
builder, pool, trans.Module, mv.value,
trans._funcs, trans._func_count, trans)
elif pk == ast.ASTKind.MatchOr:
# MatchOr: 多个值共享一个 BB(取第一个值做 case)
mo: ast.MatchOr | t.CPtr = (ast.MatchOr | t.CPtr)(pat)
pats: list[ast.AST | t.CPtr] | t.CPtr = mo.patterns
if pats is not None and len(pats) > 0:
first_pat: ast.AST | t.CPtr = pats.get(0)
if first_pat is not None \
and first_pat.kind() == ast.ASTKind.MatchValue:
mv2: ast.MatchValue | t.CPtr = (
ast.MatchValue | t.CPtr)(first_pat)
cv = HandlesExpr.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: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, func, name_buf)
else:
bb = default_bb
# 检测 NoBreak
body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children
nb: int = self._has_no_break(body_list)
# 存入数组
if collected < MAX_MATCH_CASES:
bb_arr[collected] = t.CSizeT(bb)
cv_arr[collected] = t.CSizeT(cv)
def_arr[collected] = is_def
nb_arr[collected] = nb
collected = collected + 1
# 构建 SwitchCase 链表(非 default case 且有值)
if is_def == 0 and cv is not None:
sc: llvmlite.SwitchCase | t.CPtr = 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, tag_val, default_bb, sw_head, sw_count)
# 6. 查找 REnum 结构体类型(用于变体字段绑定的 GEP)
renum_entry: HandlesStruct.StructEntry | t.CPtr = None
renum_ty: llvmlite.LLVMType | t.CPtr = None
se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(renum_name)
if se is not None:
renum_entry = se
renum_ty = se.Ty
# 7. 第二遍:翻译每个 case body
i = 0
while i < collected:
case_node: ast.AST | t.CPtr = cases_list.get(i)
if case_node is None:
i = i + 1
continue
mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node)
pat: ast.AST | t.CPtr = mc.pattern
# 取 BB
bb_addr: t.CSizeT = bb_arr[i]
case_bb: llvmlite.BasicBlock | t.CPtr = (
llvmlite.BasicBlock | t.CPtr)(t.CVoid(bb_addr, t.CPtr))
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 作用域(变体字段绑定隔离)
HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH)
# 变体字段绑定(MatchClass)
if pat is not None and pat.kind() == ast.ASTKind.MatchClass \
and 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)
# 翻译 case body
body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children
if body_list is not None:
bc: t.CSizeT = len(body_list)
bi: int = 0
while bi < bc:
stmt: ast.AST | t.CPtr = body_list.get(bi)
if stmt is not None:
HandlesBody.translate_stmt(trans, stmt)
bi = bi + 1
# 退出 case 作用域
HandlesVar.exit_scope(trans.SymTab)
# 若未终止且无 NoBreak,跳到 end
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
and nb == 0:
llvmlite.build_br(builder, end_bb)
trans._ctrl_merge_reachable = 1
m_merge_reach = 1
i = i + 1
# 8. 处理 default 块
llvmlite.position_at_end(builder, default_bb)
if has_default == 0:
# 无显式 default:default 直接跳 end
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, end_bb)
trans._ctrl_merge_reachable = 1
m_merge_reach = 1
else:
# 有显式 default:翻译 default case body(找到 is_def==1 的 case)
di: int = 0
while di < collected:
if def_arr[di] == 1:
dcase: ast.AST | t.CPtr = cases_list.get(di)
if dcase is not None:
dmc: ast.MatchCase | t.CPtr = (
ast.MatchCase | t.CPtr)(dcase)
HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH)
dbody: list[ast.AST | t.CPtr] | t.CPtr = dmc.children
if dbody is not None:
dn: t.CSizeT = len(dbody)
dj: int = 0
while dj < dn:
stmt: ast.AST | t.CPtr = dbody.get(dj)
if stmt is not None:
HandlesBody.translate_stmt(trans, stmt)
dj = dj + 1
HandlesVar.exit_scope(trans.SymTab)
break
di = di + 1
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, end_bb)
trans._ctrl_merge_reachable = 1
m_merge_reach = 1
# 9. 定位到 end 块
llvmlite.position_at_end(builder, end_bb)
# 用本 match 自身的 br 记录覆盖,消除 case 体内嵌套控制流对
# _ctrl_merge_reachable 的污染(全 case return 时应为不可达)
trans._ctrl_merge_reachable = m_merge_reach
return 0
# ============================================================
# _bind_variant_fields - 绑定 MatchClass 的变体字段
#
# case LLVMType.Ptr(pointee) 中的 pointee 绑定到 subject 的 payload 字段
# ============================================================
def _bind_variant_fields(self, pat: ast.AST | t.CPtr,
renum_name: str,
renum_entry: HandlesStruct.StructEntry | t.CPtr,
renum_ty: llvmlite.LLVMType | t.CPtr,
subject_ptr: llvmlite.Value | t.CPtr,
trans: HT.Translator | t.CPtr,
pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr):
if pat is None or renum_entry is None or renum_ty is None:
return
mc: ast.MatchClass | t.CPtr = (ast.MatchClass | t.CPtr)(pat)
pats: list[ast.AST | t.CPtr] | t.CPtr = mc.patterns
if pats is None:
return
# bitcast subject_ptr 到 renum_ptr_ty(确保 GEP 类型匹配)
renum_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, renum_ty)
casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, subject_ptr, renum_ptr_ty)
if casted_ptr is None:
casted_ptr = subject_ptr
pn: t.CSizeT = len(pats)
j: int = 0
while j < pn:
sub_pat: ast.AST | t.CPtr = pats.get(j)
if sub_pat is not None and sub_pat.kind() == ast.ASTKind.MatchAs:
ma: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(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 等)是不同指针恒不匹配
# → 恒 -1 → fail-fast 误报(追加73d 同款指针陷阱)
alt_idx: int = HandlesClassDef._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)
HandlesType.fatal_error(
sub_pat,
f"REnum 变体字段 '{bind_name}' 在结构体 '{renum_name}' 中越界且别名查找失败",
"TypeError")
# 获取字段类型
fe: HandlesStruct.FieldEntry | t.CPtr = (
HandlesStruct._get_field_entry(
renum_entry, payload_idx))
field_ty: llvmlite.LLVMType | t.CPtr = None
if fe is not None:
field_ty = fe.Ty
if field_ty is None:
# fail-fast: 变体字段类型缺失,禁止兜底 i8
HandlesType.fatal_error(
sub_pat,
f"REnum 变体字段类型缺失: {bind_name}",
"TypeError")
# GEP 取字段地址
elem_ptr: llvmlite.Value | t.CPtr = (
llvmlite.build_gep_struct(
builder, renum_ty, field_ty,
casted_ptr, payload_idx))
if elem_ptr is None:
# fail-fast: 变体字段地址计算失败
HandlesType.fatal_error(
sub_pat,
f"REnum 变体字段 '{bind_name}' 地址计算失败",
"TypeError")
# 变体成员实际类型(对齐 TPC class_members L300-307/L376-382):
# 注册时别名表存了成员注解解析出的类型(perm_pool 深拷贝)。
# 用它把槽位地址 bitcast 成 Ptr(成员类型),使绑定变量按成员
# 类型读 payload——Struct.Name: t.CChar|t.CPtr = i8*,否则按
# 槽位 i64 读 → is 比较/下标/strlen 等字符串操作翻译失败
# (CallGenMixin L4631 type_name_sp is not None 根因)。
# 注意:必须按 (class, 变体名, 位置) 定位——MatchAs 名是局部
# 变量名(type_name_sp),不是变体字段名(Name),按字段名
# 查恒不匹配(追加76 第一次修复失效根因);同一 payload 位置
# 跨变体类型也不同(Int.Bits=i32 vs Struct.Fields=Ptr)。
# 自引用类型(如 Pointee: LLVMType|t.CPtr)注册期解析失败 →
# 查不到类型 → 回退槽位类型(原始位宽在嵌套 match 中经
# subject bitcast 仍可用)。
mem_ty_m: llvmlite.LLVMType | t.CPtr = 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 = HandlesClassDef._lookup_renum_member_ty(
renum_entry.Name, vnt_m, payload_idx)
if mem_ty_m is not None:
mem_ptr_m: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
pool, mem_ty_m)
if mem_ptr_m is not None:
cast_m: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, elem_ptr, mem_ptr_m)
if cast_m is not None:
elem_ptr = cast_m
HandlesVar.define_var(
trans.SymTab, bind_name, elem_ptr)
j = j + 1
# ============================================================
# _seq_cmp_eq - 序列匹配元素相等比较
#
# 对齐 lhs/rhs(指针统一 ptrtoint i64,整数位宽统一到较宽者)后
# 生成 icmp eq,返回 i1 条件。
# ============================================================
def _seq_cmp_eq(self, builder: llvmlite.IRBuilder | t.CPtr,
lhs: llvmlite.Value | t.CPtr,
rhs: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr:
"""对齐 lhs/rhs 后生成 icmp eq(指针统一 ptrtoint i64)"""
if lhs is None or rhs is None or builder is None:
return None
pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool
if HandlesExpr.is_ptr_type(lhs.Ty) != 0 \
or HandlesExpr.is_ptr_type(rhs.Ty) != 0:
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
if HandlesExpr.is_ptr_type(lhs.Ty) != 0:
lhs = llvmlite.build_ptrtoint(builder, lhs, i64_ty)
if HandlesExpr.is_ptr_type(rhs.Ty) != 0:
rhs = llvmlite.build_ptrtoint(builder, rhs, i64_ty)
lb: int = HandlesExpr.get_llvm_type_bits(lhs.Ty)
rb: int = HandlesExpr.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, node: ast.Match | t.CPtr,
subject_node: ast.AST | t.CPtr) -> int:
trans: HT.Translator | t.CPtr = self.Trans
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = 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 | t.CPtr] | t.CPtr = None
if subject_node.kind() == ast.ASTKind.Tuple:
st: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(subject_node)
if st is not None:
elts = st.elts
elif subject_node.kind() == ast.ASTKind.List:
sl2: ast.List | t.CPtr = (ast.List | t.CPtr)(subject_node)
if sl2 is not None:
elts = sl2.elts
if elts is None:
return 0
ecount: t.CSizeT = len(elts)
if ecount == 0:
return 0
subj_vals: t.CSizeT | t.CPtr = pool.alloc(8 * ecount)
if subj_vals is None:
return 0
for ei in range(ecount):
elt: ast.AST | t.CPtr = elts.get(ei)
sv: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, elt,
trans._funcs, trans._func_count, trans)
if sv is None:
HandlesType.fatal_error(
elt, f"match 序列元素 {ei} 翻译失败", "TypeError")
subj_vals[ei] = t.CSizeT(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: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "match.seq.end.%d", cnt)
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, func, name_buf)
# 3. 第一遍:收集 case 信息(check/body BB、default 标记、nobreak、guard)
cases_list: list[ast.AST | t.CPtr] | t.CPtr = node.cases
if cases_list is None:
return 0
case_count: t.CSizeT = len(cases_list)
check_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES)
body_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES)
def_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
nb_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
guard_arr: t.CSizeT | t.CPtr = 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
first_check: int = -1
i: int = 0
while i < case_count:
case_node: ast.AST | t.CPtr = cases_list.get(i)
if case_node is None or case_node.kind() != ast.ASTKind.MatchCase:
i = i + 1
continue
mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node)
pat: ast.AST | t.CPtr = mc.pattern
is_def: int = 0
if pat is not None:
pk: int = pat.kind()
if pk == ast.ASTKind.MatchAs:
ma0: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(pat)
if ma0.pattern is None:
is_def = 1
elif pk != ast.ASTKind.MatchSequence:
# fail-fast:序列匹配只接受 MatchSequence / 顶层 _ 通配
HandlesType.fatal_error(
pat, "序列匹配 case 只支持 (元素) 或 _ 模式", "TypeError")
if is_def == 1:
has_default = 1
check_arr[collected] = 0
body_arr[collected] = t.CSizeT(default_bb)
else:
if collected >= MAX_MATCH_CASES:
break
viperlib.snprintf(name_buf, 32, "match.seq.check.%d.%d", cnt, i)
cbb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "match.seq.body.%d.%d", cnt, i)
bbb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, func, name_buf)
check_arr[collected] = t.CSizeT(cbb)
body_arr[collected] = t.CSizeT(bbb)
if first_check < 0:
first_check = collected
body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children
nb: int = self._has_no_break(body_list)
def_arr[collected] = is_def
nb_arr[collected] = nb
guard_arr[collected] = t.CSizeT(mc.guard)
collected = collected + 1
i = i + 1
# 4. 入口 → 第一个 check(或 default/end)
if first_check >= 0:
head_bb: llvmlite.BasicBlock | t.CPtr = (
llvmlite.BasicBlock | t.CPtr)(
t.CVoid(check_arr[first_check], t.CPtr))
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: llvmlite.BasicBlock | t.CPtr = (
llvmlite.BasicBlock | t.CPtr)(
t.CVoid(check_arr[ci], t.CPtr))
bbb2: llvmlite.BasicBlock | t.CPtr = (
llvmlite.BasicBlock | t.CPtr)(
t.CVoid(body_arr[ci], t.CPtr))
llvmlite.position_at_end(builder, cbb2)
# 计算匹配条件(元素比较 && guard)
cond: llvmlite.Value | t.CPtr = None
cnode: ast.AST | t.CPtr = cases_list.get(ci)
mc2: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(cnode)
ms: ast.MatchSequence | t.CPtr = (
ast.MatchSequence | t.CPtr)(mc2.pattern)
pats: list[ast.AST | t.CPtr] | t.CPtr = None
if ms is not None:
pats = ms.patterns
pcount: t.CSizeT = 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):
pat1: ast.AST | t.CPtr = pats.get(pi)
if pat1 is None:
continue
pk1: int = pat1.kind()
if pk1 == ast.ASTKind.MatchValue:
mv: ast.MatchValue | t.CPtr = (
ast.MatchValue | t.CPtr)(pat1)
pv: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, mv.value,
trans._funcs, trans._func_count, trans)
if pv is None:
HandlesType.fatal_error(
pat1, f"序列模式元素 {pi} 翻译失败", "TypeError")
sv1: llvmlite.Value | t.CPtr = (
llvmlite.Value | t.CPtr)(
t.CVoid(subj_vals[pi], t.CPtr))
c1: llvmlite.Value | t.CPtr = self._seq_cmp_eq(
builder, sv1, pv)
if c1 is None:
HandlesType.fatal_error(
pat1, "序列模式元素比较失败", "TypeError")
if cond is None:
cond = c1
else:
cond = llvmlite.build_and(builder, cond, c1)
elif pk1 == ast.ASTKind.MatchAs:
ma2: ast.MatchAs | t.CPtr = (
ast.MatchAs | t.CPtr)(pat1)
if ma2.pattern is None:
continue # _ 通配:恒真
if ma2.name is not None:
# fail-fast:序列模式变量绑定暂不支持
HandlesType.fatal_error(
pat1, "序列模式变量绑定暂不支持", "NotImplementedError")
elif pk1 == ast.ASTKind.MatchStar:
continue # 剩余元素通配:恒真
else:
HandlesType.fatal_error(
pat1, "序列模式不支持的 pattern 类型", "TypeError")
# guard(若有):匹配成立且 guard 非零
g_addr: t.CSizeT = guard_arr[ci]
if g_addr != 0:
gnode: ast.AST | t.CPtr = (
ast.AST | t.CPtr)(t.CVoid(g_addr, t.CPtr))
gv: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, gnode,
trans._funcs, trans._func_count, trans)
if gv is None:
HandlesType.fatal_error(
gnode, "match guard 翻译失败", "TypeError")
gbits: int = HandlesExpr.get_llvm_type_bits(gv.Ty)
if gbits == 1:
g1: llvmlite.Value | t.CPtr = gv
else:
gzero: llvmlite.Value | t.CPtr = 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: llvmlite.BasicBlock | t.CPtr = None
nj: int = ci + 1
while nj < collected and def_arr[nj] == 1:
nj = nj + 1
if nj < collected:
nxt = (llvmlite.BasicBlock | t.CPtr)(
t.CVoid(check_arr[nj], t.CPtr))
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: llvmlite.BasicBlock | t.CPtr = (
llvmlite.BasicBlock | t.CPtr)(
t.CVoid(body_arr[ci], t.CPtr))
llvmlite.position_at_end(builder, bbb3)
cnode2: ast.AST | t.CPtr = cases_list.get(ci)
mc3: ast.MatchCase | t.CPtr = (
ast.MatchCase | t.CPtr)(cnode2)
HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH)
body_list2: list[ast.AST | t.CPtr] | t.CPtr = mc3.children
if body_list2 is not None:
bc: t.CSizeT = len(body_list2)
bi: int = 0
while bi < bc:
stmt: ast.AST | t.CPtr = body_list2.get(bi)
if stmt is not None:
HandlesBody.translate_stmt(trans, stmt)
bi = bi + 1
HandlesVar.exit_scope(trans.SymTab)
if llvmlite.builder_cur_block_is_terminated(builder) == 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: llvmlite.BasicBlock | t.CPtr = (
llvmlite.BasicBlock | t.CPtr)(
t.CVoid(body_arr[nj2], t.CPtr))
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)
if has_default == 1:
di: int = 0
while di < collected:
if def_arr[di] == 1:
dnode: ast.AST | t.CPtr = cases_list.get(di)
if dnode is not None:
dmc: ast.MatchCase | t.CPtr = (
ast.MatchCase | t.CPtr)(dnode)
HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH)
dbody: list[ast.AST | t.CPtr] | t.CPtr = dmc.children
if dbody is not None:
dn: t.CSizeT = len(dbody)
dj: int = 0
while dj < dn:
stmt: ast.AST | t.CPtr = dbody.get(dj)
if stmt is not None:
HandlesBody.translate_stmt(trans, stmt)
dj = dj + 1
HandlesVar.exit_scope(trans.SymTab)
break
di = di + 1
if llvmlite.builder_cur_block_is_terminated(builder) == 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, node: ast.Match | t.CPtr,
subject_val: llvmlite.Value | t.CPtr) -> int:
trans: HT.Translator | t.CPtr = self.Trans
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = 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 | t.CPtr = llvmlite.Int32(pool)
subj_bits: int = HandlesExpr.get_llvm_type_bits(subject_val.Ty)
subj_val: llvmlite.Value | t.CPtr = subject_val
if subj_bits != 32:
if HandlesExpr.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 失败
HandlesType.fatal_error(node, "match subject 转换为 i32 失败", "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: 标签缓冲区分配失败
HandlesType.fatal_error(node, "标签缓冲区分配失败", "TypeError")
viperlib.snprintf(name_buf, 32, "match.default.%d", cnt)
default_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "match.end.%d", cnt)
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, func, name_buf)
# 3. 收集 case 信息
cases_list: list[ast.AST | t.CPtr] | t.CPtr = node.cases
if cases_list is None:
# fail-fast: match cases 缺失
HandlesType.fatal_error(node, "match cases 缺失", "TypeError")
case_count: t.CSizeT = len(cases_list)
bb_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES)
cv_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES)
def_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
nb_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None:
# fail-fast: match 分派数组分配失败
HandlesType.fatal_error(node, "match 分派数组分配失败", "TypeError")
collected: int = 0
has_default: int = 0
sw_head: llvmlite.SwitchCase | t.CPtr = None
sw_tail: llvmlite.SwitchCase | t.CPtr = None
sw_count: int = 0
# 4. 第一遍:收集 + 创建 BB + 构建链表
i: int = 0
while i < case_count:
case_node: ast.AST | t.CPtr = 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: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node)
pat: ast.AST | t.CPtr = mc.pattern
is_def: int = 0
cv: llvmlite.Value | t.CPtr = None
if pat is not None:
pk: int = pat.kind()
if pk == ast.ASTKind.MatchValue:
mv: ast.MatchValue | t.CPtr = (ast.MatchValue | t.CPtr)(pat)
cv = HandlesExpr.translate_value(
builder, pool, trans.Module, mv.value,
trans._funcs, trans._func_count, trans)
elif pk == ast.ASTKind.MatchSingleton:
ms: ast.MatchSingleton | t.CPtr = (
ast.MatchSingleton | t.CPtr)(pat)
# None -> 0
cv = llvmlite.const_int32(pool, 0)
elif pk == ast.ASTKind.MatchAs:
ma: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(pat)
if ma.pattern is None:
is_def = 1
has_default = 1
elif pk == ast.ASTKind.MatchOr:
mo: ast.MatchOr | t.CPtr = (ast.MatchOr | t.CPtr)(pat)
pats: list[ast.AST | t.CPtr] | t.CPtr = mo.patterns
if pats is not None and len(pats) > 0:
first_pat: ast.AST | t.CPtr = pats.get(0)
if first_pat is not None \
and first_pat.kind() == ast.ASTKind.MatchValue:
mv2: ast.MatchValue | t.CPtr = (
ast.MatchValue | t.CPtr)(first_pat)
cv = HandlesExpr.translate_value(
builder, pool, trans.Module, mv2.value,
trans._funcs, trans._func_count, trans)
if is_def == 0:
if collected >= MAX_MATCH_CASES:
break
viperlib.snprintf(name_buf, 32, "match.case.%d.%d", cnt, i)
bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, func, name_buf)
else:
bb = default_bb
body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children
nb: int = self._has_no_break(body_list)
if collected < MAX_MATCH_CASES:
bb_arr[collected] = t.CSizeT(bb)
cv_arr[collected] = t.CSizeT(cv)
def_arr[collected] = is_def
nb_arr[collected] = nb
collected = collected + 1
if is_def == 0 and cv is not None:
sc: llvmlite.SwitchCase | t.CPtr = 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 | t.CPtr = cases_list.get(i)
if case_node is None:
i = i + 1
continue
mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node)
bb_addr: t.CSizeT = bb_arr[i]
case_bb: llvmlite.BasicBlock | t.CPtr = (
llvmlite.BasicBlock | t.CPtr)(t.CVoid(bb_addr, t.CPtr))
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)
HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH)
body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children
if body_list is not None:
bc: t.CSizeT = len(body_list)
bi: int = 0
while bi < bc:
stmt: ast.AST | t.CPtr = body_list.get(bi)
if stmt is not None:
HandlesBody.translate_stmt(trans, stmt)
bi = bi + 1
HandlesVar.exit_scope(trans.SymTab)
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
and nb == 0:
llvmlite.build_br(builder, end_bb)
trans._ctrl_merge_reachable = 1
sm_merge_reach = 1
i = i + 1
# 7. default 块
llvmlite.position_at_end(builder, default_bb)
if has_default == 0:
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:
di: int = 0
while di < collected:
if def_arr[di] == 1:
dcase: ast.AST | t.CPtr = cases_list.get(di)
if dcase is not None:
dmc: ast.MatchCase | t.CPtr = (
ast.MatchCase | t.CPtr)(dcase)
HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH)
dbody: list[ast.AST | t.CPtr] | t.CPtr = dmc.children
if dbody is not None:
dn: t.CSizeT = len(dbody)
dj: int = 0
while dj < dn:
stmt: ast.AST | t.CPtr = dbody.get(dj)
if stmt is not None:
HandlesBody.translate_stmt(trans, stmt)
dj = dj + 1
HandlesVar.exit_scope(trans.SymTab)
break
di = di + 1
if llvmlite.builder_cur_block_is_terminated(builder) == 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
# ============================================================
# NewMatchHandle - 工厂函数(委托到 gen.NewMatchHandle)
# ============================================================
def NewMatchHandle(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> MatchHandle | t.CPtr:
"""创建 MatchHandle 实例(委托到 gen.NewMatchHandle)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.NewMatchHandle(pool, trans)
return None