回滚 13080f6 的 110 处访问器调用,恢复裸字段访问 `x.Next`。
理由:该批访问器是把访问移到定义模块内执行,**绕开**了"继承字段名解析",
属于规避而非修复;缺陷本体在 TPC 侧(导入侧继承展平把泛型基类的继承字段
记成 __inherited_N 占位名,名字丢失)。TPC 已按语义修正:
· e6451a07 继承展平沿继承链取真实字段名(泛型特化回退模板名),
展平表直接落 `[("Next", <槽位类型>), ...]`,属性访问是普通表命中;
· 3ca46c01 顺带修掉 _get_or_create_struct 里"同名枚举成员遮蔽类定义"的 i32 出口。
因此源码侧恢复为唯一写法(裸字段访问),由编译器负责解析。
注:本 commit 只回滚访问器;13080f6 里夹带的 CallGenProp.vp 续行合并(非访问器改动)
已在工作区保留(未提交)。
1332 lines
71 KiB
Plaintext
1332 lines
71 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)
|
||
|
||
# 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)
|
||
|
||
# ============================================================
|
||
# _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*]*) -> 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.Expr:
|
||
expr_node: rawptr[ast.Expr] = rawptr[ast.Expr](stmt)
|
||
val: ast.AST* = expr_node.value
|
||
if val is not None and val.kind() == ast.ASTKind.Call:
|
||
call_node: ast.Call* = ast.Call*(val)
|
||
fn: ast.AST* = call_node.func
|
||
if fn is not None and fn.kind() == ast.ASTKind.Attribute:
|
||
at: ast.Attribute* = (ast.Attribute*)(fn)
|
||
if at.value is not None \
|
||
and at.value.kind() == ast.ASTKind.Name:
|
||
base_nm: ast.Name* = (ast.Name*)(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*,
|
||
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
|
||
|
||
# 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
|
||
|
||
# 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 作用域(变体字段绑定隔离)
|
||
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 作用域
|
||
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 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)
|
||
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)
|
||
# 末句控制流全 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:
|
||
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)
|
||
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)
|
||
# 末句控制流全 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)
|
||
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)
|
||
# 末句控制流全 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")
|
||
|
||
# 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)
|
||
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
|
||
# 穷尽臂(`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
|
||
|
||
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:
|
||
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)
|
||
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)
|
||
|
||
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: 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)
|
||
|
||
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)
|
||
|
||
# 末句控制流全 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 块(含 `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)
|
||
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)
|
||
# 末句控制流全 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
|