812 lines
36 KiB
Plaintext
812 lines
36 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
|
||
|
||
|
||
# ============================================================
|
||
# 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
|