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