Files
ViperC/App/lib/core/Handles/HandlesMatch.vp
T

812 lines
36 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import viperlib
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesBody as HandlesBody
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesClassDef as HandlesClassDef
import lib.core.Handles.HandlesStruct as HandlesStruct
# ============================================================
# HandlesMatch - match 语句处理(Mixin 继承模式)
#
# 逻辑移植自 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
@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
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
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:
return 0
# 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:
rn_chk: int = HandlesClassDef._is_renum_class_name(
entry.AnnotClassName)
if rn_chk != 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 = cases_list.__len__()
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:
if 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:
if pat.kind() == ast.ASTKind.MatchClass:
rnm: str = self._extract_renum_name_from_cls(pat)
if rnm is not None:
if 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 = body_list.__len__()
i: int = 0
while i < n:
stmt: ast.AST | t.CPtr = body_list.get(i)
if stmt is not None:
if 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:
if 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:
if string.strcmp(base_nm.id, "c") == 0:
if at.attr is not None:
if 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:
pointee_ty: llvmlite.LLVMType | t.CPtr = subj_ty.Pointee
if pointee_ty is not None:
if HandlesExpr.is_ptr_type(pointee_ty) != 0:
# 情况1: T** → load 一次得 T*
load_sub_ty: llvmlite.LLVMType | t.CPtr = pointee_ty
loaded_sub: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, load_sub_ty, 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:
# 找不到结构体类型时无法构造,直接放弃 REnum 路径
return 0
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:
if 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:
return 0
tag_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, i32_ty, tag_ptr)
if tag_val is None:
return 0
# 2. 创建 default/end BB
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
if name_buf is None:
return 0
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:
return 0
case_count: t.CSizeT = cases_list.__len__()
# 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:
return 0
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: t.CChar | t.CPtr = 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 pats.__len__() > 0:
first_pat: ast.AST | t.CPtr = pats.get(0)
if first_pat is not None:
if 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:
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)
# 翻译 case body
body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children
if body_list is not None:
bc: t.CSizeT = body_list.__len__()
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:
if nb == 0:
llvmlite.build_br(builder, end_bb)
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)
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 = dbody.__len__()
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)
# 9. 定位到 end 块
llvmlite.position_at_end(builder, end_bb)
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 = pats.__len__()
j: int = 0
while j < pn:
sub_pat: ast.AST | t.CPtr = pats.get(j)
if sub_pat is not None:
if 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:
alt_idx: int = HandlesClassDef._lookup_renum_field_alias(
renum_name, bind_name)
if alt_idx >= 1:
payload_idx = alt_idx
else:
j = j + 1
continue
# 获取字段类型
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:
field_ty = llvmlite.Int8(pool)
# GEP 取字段地址
elem_ptr: llvmlite.Value | t.CPtr = (
llvmlite.build_gep_struct(
builder, renum_ty, field_ty,
casted_ptr, payload_idx))
if elem_ptr is not None:
HandlesVar.define_var(
trans.SymTab, bind_name, elem_ptr)
j = j + 1
# ============================================================
# _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
# 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:
return 0
# 2. 创建 default/end BB
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
if name_buf is None:
return 0
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:
return 0
case_count: t.CSizeT = cases_list.__len__()
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:
return 0
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 pats.__len__() > 0:
first_pat: ast.AST | t.CPtr = pats.get(0)
if first_pat is not None:
if 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 = body_list.__len__()
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:
if nb == 0:
llvmlite.build_br(builder, end_bb)
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)
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 = dbody.__len__()
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)
# 8. 定位到 end
llvmlite.position_at_end(builder, end_bb)
return 0
# ============================================================
# NewMatchHandle - 工厂函数
# ============================================================
def NewMatchHandle(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> MatchHandle | t.CPtr:
h: MatchHandle | t.CPtr = pool.alloc(MatchHandle.__sizeof__())
if h is None:
return None
string.memset(h, 0, MatchHandle.__sizeof__())
h.Trans = trans
return h