Files
ViperC/App/lib/core/Gen/MatchGenMixin.vp
T
TermiNexus 7cba4cbc95 chore: 清理超长历史注释,并一并提交并行会话的代码改动
注释清理(65 文件 / 约 -2578 行 / 约 516 处):删除/压缩叙述式历史注释——多行根因叙事、工作代号段(D25/D30/N11/B5/S4/阶段E 等)、改前改后与先例叙述、逐条推导块,压成一行讲清作用信息;契约类注释(用途、参数与返回、关键约束与不变量、IR 结构说明)与被注释掉的代码一律保留

存疑 标记 6 处一字未动:StubMergerStore.vp、VpiReader.vp、VLogger.vp、AssignGenMixin.vp、CallGenLib.vp、CallGenLeafKit.vp

本次一并带入并行会话的代码改动(同批文件,按文件粒度无法拆分):fileio.File -> rowptr[fileio.File] 等

已知副作用/残留:① CallGenDispatch.vp 有 2 行非注释行的行尾被 LF->CRLF 规范化(纯字节变化,无文本改动);② core/Gen 区约 24 处压缩因并行会话整文件覆写被写回原样,尚未生效(StmtGenCifMixin/ClassGenVTable/FuncGenDef/ClassGenEnum/StructGenMixin/TypeSpec 等)

清单与复跑判据见 Debugger/comment_cleanup_summary.md(该目录不受版本控制)
2026-09-16 11:27:05 +08:00

1406 lines
71 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.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)
MAX_MATCH_CASES: t.CDefine = 32
# 作用域种类常量(与 HandlesVar 的 Scope.Kind 区分,原 HandlesMatch.SCOPE_MATCH)
SCOPE_MATCH: t.CDefine = 6
# match 翻译最大递归深度(match → case body → translate_value → 嵌套 match)。
# 入口计数出口递减,超限即 fail-fast:AST 自引用环可致无限递归 → 栈溢出。
MATCH_TRANSLATE_MAX_DEPTH: t.CDefine = 64
@t.NoVTable
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 | t.CPtr
def _case_tail_unreachable(self, trans: HT.Translator | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
body_list: list[ast.AST | t.CPtr] | t.CPtr) -> 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 | t.CPtr = 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 | t.CPtr,
node: ast.AST | t.CPtr) -> 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 | t.CPtr,
node: ast.AST | t.CPtr) -> int:
if node is None:
return 0
pool: rowptr[memhub.MemBuddy] = 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
# match merge 可达性重置(分派前初始化为 0)。标志必须由各处理函数
# (_handle_renum_match/_handle_sequence_match/_handle_simple_match)
# 内部声明并收尾覆盖:声明在 Handle 这里会退化为隐式全局,跨 match 污染。
trans._ctrl_merge_reachable = 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(trans, m_node, subject_node)
subject_val: llvmlite.Value | t.CPtr = 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 | 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: GenTypes.VarEntry | t.CPtr = 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 | t.CPtr] | t.CPtr = 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 | 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 (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 | 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 self.Gen.ClassGenEnum._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: sizet = 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, trans: HT.Translator | t.CPtr,
node: ast.Match | t.CPtr,
renum_name: str,
subject_ptr: llvmlite.Value | t.CPtr) -> int:
pool: rowptr[memhub.MemBuddy] = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = 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
# 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 self.Gen.ExprGenBase.is_ptr_type(subj_ty) != 0 \
and subj_ty.Pointee is not None \
and self.Gen.ExprGenBase.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 self.Gen.ExprGenBase.is_ptr_type(subject_ptr.Ty) == 0:
renum_se: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.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 结构体未注册,无法构造
self.Gen.TypeGenErr.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 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 | 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 指针转换失败
self.Gen.TypeGenErr.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 读取失败
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: 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 缺失
self.Gen.TypeGenErr.fatal_error(node, "match cases 缺失", "TypeError")
case_count: sizet = len(cases_list)
# BB 指针数组、case 值指针数组、default 标记数组、nobreak 标记数组
bb_arr: sizet | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES)
cv_arr: sizet | t.CPtr = 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 | t.CPtr = 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
# SwitchCase 链表
sw_head: llvmlite.SwitchCase | t.CPtr = None
sw_tail: llvmlite.SwitchCase | t.CPtr = 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 | 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
# 修复: 提升到臂作用域(原先声明在 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, 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 = 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: 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 = 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: 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] = 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: 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
# 记录"应产出 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: GenTypes.StructEntry | t.CPtr = None
renum_ty: llvmlite.LLVMType | t.CPtr = None
se: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(renum_name)
if se is not None:
renum_entry = se
renum_ty = se.Ty
# 7. 第二遍:翻译每个 case body
i = 0
while i < collected:
# pass2 用 pass1 缓存的 mc(避免重索引错位)
mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(
t.CVoid(mc_arr[i], t.CPtr))
if mc is None:
i = i + 1
continue
pat: ast.AST | t.CPtr = mc.pattern
# 取 BB
bb_addr: sizet = 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 作用域(变体字段绑定隔离)
self.Gen.VarGen.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: 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 | t.CPtr = body_list.get(bi)
if stmt is not None:
self.Gen.StmtGen.translate_stmt(trans, stmt)
bi = bi + 1
# 退出 case 作用域
self.Gen.VarGen.exit_scope(trans.SymTab)
# 若未终止且无 NoBreak,跳到 end
# 末句控制流全 return(结构性不可达)时补 unreachable,不 br end_bb
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
and nb == 0 \
and self._case_tail_unreachable(trans, builder, body_list) == 0:
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:
# 无显式 default:default 直接跳 end
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:翻译 default case body(找到 is_def==1 的 case)
dbody: list[ast.AST | t.CPtr] | t.CPtr = None
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)
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
# dbody 预声明+重赋值会使 .get 误分派成 list[int].get
# (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃,
# gen1 IR 证据)。用 dbody2 内联声明接收者遍历(对齐
# Converter arg_defaults 内联声明规避模式)。
dbody2: list[ast.AST | t.CPtr] | t.CPtr = dmc.children
dbody = dbody2
if dbody2 is not None:
dn: sizet = len(dbody2)
dj: int = 0
while dj < dn:
stmt: ast.AST | t.CPtr = dbody2.get(dj)
if stmt is not None:
self.Gen.StmtGen.translate_stmt(trans, stmt)
dj = dj + 1
self.Gen.VarGen.exit_scope(trans.SymTab)
break
di = di + 1
# 末句控制流全 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)
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 | t.CPtr,
renum_name: str,
renum_entry: GenTypes.StructEntry | t.CPtr,
renum_ty: llvmlite.LLVMType | t.CPtr,
subject_ptr: llvmlite.Value | t.CPtr,
trans: HT.Translator | t.CPtr,
pool: rowptr[memhub.MemBuddy],
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: sizet = 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 等)是不同指针,恒不匹配 → 误报 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 | t.CPtr = (
self.Gen.StructGen._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
self.Gen.TypeGenErr.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: 变体字段地址计算失败
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 | 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 = 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 | 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
self.Gen.VarGen.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, trans: HT.Translator | t.CPtr,
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: rowptr[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 | t.CPtr = 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 | t.CPtr,
node: ast.Match | t.CPtr,
subject_node: ast.AST | t.CPtr) -> int:
pool: rowptr[memhub.MemBuddy] = 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: sizet = len(elts)
if ecount == 0:
return 0
subj_vals: sizet | t.CPtr = 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 | t.CPtr] | t.CPtr = elts
elt: ast.AST | t.CPtr = elts_inl.get(ei)
sv: llvmlite.Value | t.CPtr = 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: 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: sizet = len(cases_list)
check_arr: sizet | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES)
body_arr: sizet | t.CPtr = 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 | 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:
# 容量防线(与 _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 | 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 / 顶层 _ 通配
self.Gen.TypeGenErr.fatal_error(
pat, "序列匹配 case 只支持 (元素) 或 _ 模式", "TypeError")
if is_def == 1:
has_default = 1
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: 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] = sizet(cbb)
body_arr[collected] = sizet(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] = sizet(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: 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 | t.CPtr] | t.CPtr = pats
pat1: ast.AST | t.CPtr = pats_inl.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 = 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 | t.CPtr = (
llvmlite.Value | t.CPtr)(
t.CVoid(subj_vals[pi], t.CPtr))
c1: llvmlite.Value | t.CPtr = 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: ast.MatchAs | t.CPtr = (
ast.MatchAs | t.CPtr)(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 | t.CPtr = (
ast.AST | t.CPtr)(t.CVoid(g_addr, t.CPtr))
gv: llvmlite.Value | t.CPtr = 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 | 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)
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
body_list2: list[ast.AST | t.CPtr] | t.CPtr = mc3.children
if body_list2 is not None:
bc: sizet = len(body_list2)
bi: int = 0
while bi < bc:
stmt: ast.AST | t.CPtr = 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)
# 末句控制流全 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: 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)
dbody: list[ast.AST | t.CPtr] | t.CPtr = None
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)
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
# dbody 预声明+重赋值会使 .get 误分派成 list[int].get
# (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃,
# gen1 IR 证据)。用 dbody2 内联声明接收者遍历(对齐
# Converter arg_defaults 内联声明规避模式)。
dbody2: list[ast.AST | t.CPtr] | t.CPtr = dmc.children
dbody = dbody2
if dbody2 is not None:
dn: sizet = len(dbody2)
dj: int = 0
while dj < dn:
stmt: ast.AST | t.CPtr = dbody2.get(dj)
if stmt is not None:
self.Gen.StmtGen.translate_stmt(trans, stmt)
dj = dj + 1
self.Gen.VarGen.exit_scope(trans.SymTab)
break
di = di + 1
# 末句控制流全 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 | t.CPtr,
node: ast.Match | t.CPtr,
subject_val: llvmlite.Value | t.CPtr) -> int:
pool: rowptr[memhub.MemBuddy] = 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 = self.Gen.ExprGenBase.get_llvm_type_bits(subject_val.Ty)
subj_val: llvmlite.Value | t.CPtr = 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")
# 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: 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 缺失
self.Gen.TypeGenErr.fatal_error(node, "match cases 缺失", "TypeError")
case_count: sizet = len(cases_list)
bb_arr: sizet | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES)
cv_arr: sizet | t.CPtr = 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)
if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None:
# fail-fast: match 分派数组分配失败
self.Gen.TypeGenErr.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 = self.Gen.ExprGen.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 = self.Gen.ExprGen.translate_value(
builder, pool, trans.Module, mv2.value,
trans._funcs, trans._func_count, trans)
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: 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] = sizet(bb)
cv_arr[collected] = sizet(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: sizet = 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)
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children
if body_list is not None:
bc: sizet = len(body_list)
bi: int = 0
while bi < bc:
stmt: ast.AST | t.CPtr = 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)
# 末句控制流全 return → 补 unreachable(不 br end_bb)
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
and nb == 0 \
and self._case_tail_unreachable(trans, builder, body_list) == 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:
dbody: list[ast.AST | t.CPtr] | t.CPtr = None
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)
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
# dbody 预声明+重赋值会使 .get 误分派成 list[int].get
# (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃,
# gen1 IR 证据)。用 dbody2 内联声明接收者遍历(对齐
# Converter arg_defaults 内联声明规避模式)。
dbody2: list[ast.AST | t.CPtr] | t.CPtr = dmc.children
dbody = dbody2
if dbody2 is not None:
dn: sizet = len(dbody2)
dj: int = 0
while dj < dn:
stmt: ast.AST | t.CPtr = dbody2.get(dj)
if stmt is not None:
self.Gen.StmtGen.translate_stmt(trans, stmt)
dj = dj + 1
self.Gen.VarGen.exit_scope(trans.SymTab)
break
di = di + 1
# 末句控制流全 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)
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