Files
ViperC/App/lib/core/Handles/ForHandleIter.vp
T
TermiNexus c62ce0797d refactor(handles): HandlesFor 拆 ForHandleBase/ForHandleIter(1600→448 行)
类方法拆 Mixin:
- ForHandleBase(HandlesBase.Mixin):__init__ + 公共工具
  (_extract_tuple_names/_seq_kind/_build_seq_loop)
- ForHandleIter(ForHandleBase):8 个 _handle_* 迭代 helper
- ForHandle(ForHandleBase, ForHandleIter):保留 Handle 主分派 + 常量/
  _g_gen/NewForHandle 委托;self 调用按 1 级父类解析(Handle→Iter、
  Iter→Base 均直接父类)
StmtGenCifMixin 仍以 HandlesFor.ForHandle 实例化/引用,类名不变
2026-08-17 08:14:04 +08:00

821 lines
38 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 stdio
import viperlib
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesBody as HandlesBody
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.ExprCallBase as ExprCallBase
import lib.core.Handles.ForHandleBase as ForHandleBase
# ============================================================
# ForHandleIter - HandlesFor 拆分(阶段 E):ForHandleIter
#
# 类方法拆 Mixin:self 调用按 1 级父类解析(TPV 限制)。
# @t.NoVTable:静态绑定。
# ============================================================
@t.NoVTable
class ForHandleIter(ForHandleBase.ForHandleBase):
"""ForHandleIter"""
# ============================================================
# _handle_ptr_iter - 指针迭代: for x in ptr:
# 遍历指针,依赖隐式 index,直到解引用为空(null 终止符)
#
# 生成 IR 结构:
# %idx = alloca i32
# store i32 0, i32* %idx
# br label %cond
# cond:
# %i = load i32, i32* %idx
# %ep = getelementptr elem_ty, ptr_ty %ptr, i32 %i
# %ev = load elem_ty, elem_ty* %ep
# %null = icmp eq elem_ty %ev, 0
# br i1 %null, label %end, label %body
# body:
# store elem_ty %ev, elem_ty* %var
# ... 循环体 ...
# br label %incr
# incr:
# %next = add i32 %i, 1
# store i32 %next, i32* %idx
# br label %cond
# end:
# ============================================================
def _handle_ptr_iter(self, for_node: ast.For | t.CPtr,
var_name: str) -> int:
"""指针迭代: for x in ptr: 直到解引用为空"""
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
# 翻译迭代器表达式,获取指针值
ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, for_node.iter,
trans._funcs, trans._func_count, trans)
if ptr_val is None:
HandlesType.fatal_error(for_node, "指针迭代: 无法翻译迭代器表达式")
# 检查迭代器类型
if HandlesExpr.is_ptr_type(ptr_val.Ty) == 0:
# 数组迭代:for k in arr(定长数组按长度迭代,元素可为任意类型)
if HandlesExpr.is_array_type(ptr_val.Ty) != 0:
return self._handle_array_iter(for_node, var_name, ptr_val)
HandlesType.fatal_error(for_node, "指针迭代: 迭代器不是指针类型")
# 获取元素类型
elem_ty: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee
if elem_ty is None:
HandlesType.fatal_error(for_node, "指针迭代: 无法获取元素类型")
# 元素类型是数组(Ptr([N x T]),如 t.CArray 变量退化指针):
# load 出数组值后走数组迭代(按长度,非 null 终止)
if HandlesExpr.is_array_type(elem_ty) != 0:
arr_v2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, ptr_val)
if arr_v2 is not None:
return self._handle_array_iter(for_node, var_name, arr_v2)
# 元素类型必须是整数(用于 icmp eq 0 检查 null 终止符)
elem_bits: int = HandlesExpr.get_llvm_type_bits(elem_ty)
if elem_bits == 0:
HandlesType.fatal_error(for_node, "指针迭代: 元素类型不是整数,无法检查 null 终止符")
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
# 创建循环变量 alloca(存储元素值)
var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, var_name)
new_vars: int = 0
if var_alloca is None:
var_alloca = HandlesVar._alloca_at_entry(builder, elem_ty)
if HandlesVar.define_var(
trans.SymTab, var_name, var_alloca) == 0:
new_vars = 1
# 创建隐式 index 变量,初始为 0
idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i32_ty)
llvmlite.build_store(builder, llvmlite.const_int32(pool, 0), idx_alloca)
# 创建基本块: cond / body / incr / end
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: str = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "ptr.cond.%d", cnt)
cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "ptr.body.%d", cnt)
body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "ptr.incr.%d", cnt)
incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "ptr.end.%d", cnt)
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
# 跳转到 cond
llvmlite.build_br(builder, cond_bb)
# cond 块: load index, GEP, load elem, icmp eq 0
llvmlite.position_at_end(builder, cond_bb)
cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i32_ty, idx_alloca)
elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, elem_ty, ptr_val, cur_idx)
cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, elem_ptr)
null_val: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, elem_bits, 0)
is_null: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
builder, llvmlite.ICMP_EQ, cur_elem, null_val)
llvmlite.build_cond_br(builder, is_null, end_bb, body_bb)
# body 块: store elem to var, 翻译循环体
llvmlite.position_at_end(builder, body_bb)
llvmlite.build_store(builder, cur_elem, var_alloca)
# 保存旧循环上下文,设置 break/continue 目标
old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb
old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb
trans._break_bb = end_bb
trans._continue_bb = incr_bb
body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children
if body is not None:
body_count: t.CSizeT = len(body)
for bi in range(body_count):
stmt: ast.AST | t.CPtr = body.get(bi)
if stmt is not None:
HandlesBody.translate_stmt(trans, stmt)
# 恢复旧循环上下文
trans._break_bb = old_break
trans._continue_bb = old_continue
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, incr_bb)
# incr 块: index++, br cond
llvmlite.position_at_end(builder, incr_bb)
one_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1)
next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val)
llvmlite.build_store(builder, next_idx, idx_alloca)
llvmlite.build_br(builder, cond_bb)
# 定位到 end 块
llvmlite.position_at_end(builder, end_bb)
# 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾)
trans._ctrl_merge_reachable = 1
return new_vars
# ============================================================
# _handle_array_iter - 数组迭代: for x in arr:
# 定长数组按长度迭代(元素可为任意类型,不做 null 终止符检查)
#
# 数组值是数组类型而非指针(如局部 t.CArray 修复后),
# 先拷到临时 alloca 获得地址,再按 [0, N) 迭代。
#
# 生成 IR 结构:
# %tmp = alloca [N x elem_ty]
# store [N x elem_ty] %arr_val, [N x elem_ty]* %tmp
# %idx = alloca i32 ; store 0
# br %cond
# cond:
# %i = load i32, i32* %idx
# %c = icmp slt i32 %i, N
# br i1 %c, %body, %end
# body:
# %ep = getelementptr [N x elem_ty], [N x elem_ty]* %tmp, i32 0, i32 %i
# %ev = load elem_ty, elem_ty* %ep
# store elem_ty %ev, elem_ty* %var
# ... 循环体 ...
# br %incr
# incr:
# %n = add i32 %i, 1 ; store %n ; br %cond
# end:
# ============================================================
def _handle_array_iter(self, for_node: ast.For | t.CPtr,
var_name: str,
array_val: llvmlite.Value | t.CPtr) -> int:
"""数组迭代: for x in arr: 按数组长度迭代"""
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
# 解析数组类型 [N x elem_ty]
arr_ty: llvmlite.LLVMType | t.CPtr = array_val.Ty
elem_ty: llvmlite.LLVMType | t.CPtr = None
elem_count: int = 0
match arr_ty:
case llvmlite.LLVMType.Array(et, n):
elem_ty = et
elem_count = n
if elem_ty is None or elem_count <= 0:
HandlesType.fatal_error(for_node, "数组迭代: 无法解析数组类型")
# 数组值 → 临时 alloca(数组值不是指针,需拷贝后 GEP 迭代)
arr_tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, arr_ty)
if arr_tmp is None:
HandlesType.fatal_error(for_node, "数组迭代: 临时存储分配失败")
llvmlite.build_store(builder, array_val, arr_tmp)
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
# 循环变量 alloca(存储元素值)
var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, var_name)
new_vars: int = 0
if var_alloca is None:
var_alloca = HandlesVar._alloca_at_entry(builder, elem_ty)
if HandlesVar.define_var(
trans.SymTab, var_name, var_alloca) == 0:
new_vars = 1
# 隐式 index 变量,初始为 0
idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i32_ty)
llvmlite.build_store(builder, llvmlite.const_int32(pool, 0), idx_alloca)
# 基本块: cond / body / incr / end
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: str = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "arr.cond.%d", cnt)
cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "arr.body.%d", cnt)
body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "arr.incr.%d", cnt)
incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "arr.end.%d", cnt)
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
llvmlite.build_br(builder, cond_bb)
# cond 块: load index, icmp slt idx, elem_count
llvmlite.position_at_end(builder, cond_bb)
cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i32_ty, idx_alloca)
count_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, elem_count)
in_bounds: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
builder, llvmlite.ICMP_SLT, cur_idx, count_val)
llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb)
# body 块: GEP(0, idx) → load elem → store to var → 循环体
llvmlite.position_at_end(builder, body_bb)
elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
builder, arr_ty, elem_ty, arr_tmp, cur_idx)
cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, elem_ptr)
llvmlite.build_store(builder, cur_elem, var_alloca)
old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb
old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb
trans._break_bb = end_bb
trans._continue_bb = incr_bb
body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children
if body is not None:
body_count: t.CSizeT = len(body)
for bi in range(body_count):
stmt: ast.AST | t.CPtr = body.get(bi)
if stmt is not None:
HandlesBody.translate_stmt(trans, stmt)
trans._break_bb = old_break
trans._continue_bb = old_continue
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, incr_bb)
# incr 块: index++
llvmlite.position_at_end(builder, incr_bb)
one_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1)
next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val)
llvmlite.build_store(builder, next_idx, idx_alloca)
llvmlite.build_br(builder, cond_bb)
# 定位到 end 块
llvmlite.position_at_end(builder, end_bb)
# 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾)
trans._ctrl_merge_reachable = 1
return new_vars
# ============================================================
# _handle_list_literal_iter - 列表字面量迭代: for x in [a, b, c]:
# 把列表字面量转成定长数组值,再复用数组迭代(按长度迭代)。
#
# 元素类型取第一个元素的值类型,其余元素 coerce 到该类型。
# ============================================================
def _handle_list_literal_iter(self, for_node: ast.For | t.CPtr,
var_name: str,
list_node: ast.AST | t.CPtr) -> int:
"""列表字面量迭代: for x in [a, b, c]: 按元素顺序迭代"""
trans: HT.Translator | t.CPtr = self.Trans
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
lst: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node)
if lst is None or lst.elts is None:
HandlesType.fatal_error(for_node, "列表字面量迭代: 空列表")
elts: list[ast.AST | t.CPtr] | t.CPtr = lst.elts
elts_count: t.CSizeT = len(elts)
if elts_count <= 0:
HandlesType.fatal_error(for_node, "列表字面量迭代: 空列表")
# 翻译第一个元素,确定元素类型
first_el: ast.AST | t.CPtr = elts.get(0)
first_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, first_el,
trans._funcs, trans._func_count, trans)
if first_val is None or first_val.Ty is None:
HandlesType.fatal_error(first_el, "列表字面量迭代: 无法确定元素类型")
elem_ty: llvmlite.LLVMType | t.CPtr = first_val.Ty
# 构建 [N x elem_ty] 数组值:临时 alloca 逐元素写入后 load
arr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, elem_ty, elts_count)
tmp_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, arr_ty)
if tmp_alloca is None:
HandlesType.fatal_error(for_node, "列表字面量迭代: 临时数组分配失败")
first_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
builder, arr_ty, elem_ty, tmp_alloca, llvmlite.const_int32(pool, 0))
if first_ptr is not None:
llvmlite.build_store(builder, first_val, first_ptr)
# 写其余元素(coerce 到 elem_ty)
i: t.CSizeT = 1
while i < elts_count:
el_node: ast.AST | t.CPtr = elts.get(i)
el_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, el_node,
trans._funcs, trans._func_count, trans)
if el_val is not None:
el_val = HandlesExpr.coerce_to_type(builder, el_val, elem_ty, el_node)
el_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
builder, arr_ty, elem_ty, tmp_alloca,
llvmlite.const_int32(pool, i))
if el_ptr is not None:
llvmlite.build_store(builder, el_val, el_ptr)
i += 1
# load 回数组值,复用数组迭代
arr_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, arr_ty, tmp_alloca)
if arr_val is None:
HandlesType.fatal_error(for_node, "列表字面量迭代: 数组加载失败")
return self._handle_array_iter(for_node, var_name, arr_val)
# ============================================================
# _handle_list_iter - list[T] 容器迭代: for v in lst:
# 按 __count__ 动态长度迭代(元素任意类型,不做 null 终止符检查)
#
# list 结构布局 (6 字段 × 8 字节):
# __data__(0) __count__(8) __capacity__(16) __pool__(24)
# __elem_size__(32) __iter_index__(40)
#
# 生成 IR 结构:
# %count = load __count__
# %idx = alloca i64 ; store 0
# br %cond
# cond:
# %i = load i64, %idx
# %c = icmp slt i64 %i, %count
# br i1 %c, %body, %end
# body:
# %data = load __data__ (i8*)
# %es = load __elem_size__ (i64)
# %off = mul i64 %i, %es
# %addr = getelementptr i8, i8* %data, i64 %off
# %el = load i8*, i8** %addr
# store i8* %el, i8** %var
# ... 循环体 ...
# br %incr
# incr:
# %n = add i64 %i, 1 ; store ; br %cond
# end:
# ============================================================
def _handle_list_iter(self, for_node: ast.For | t.CPtr,
var_name: str,
list_val: llvmlite.Value | t.CPtr) -> int:
"""list[T] 容器迭代: for v in lst: 按 __count__ 动态长度迭代"""
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
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
# 读取 __count__ (偏移 8, GEP index 1)
cnt_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, i64_ty, list_val, llvmlite.const_int64(pool, 1))
if cnt_ptr is None:
HandlesType.fatal_error(for_node, "list 迭代: 无法定位 __count__")
count_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, cnt_ptr)
# 循环变量 alloca(元素类型 i8*,与 list.get 内联一致)
var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, var_name)
new_vars: int = 0
if var_alloca is None:
var_alloca = HandlesVar._alloca_at_entry(builder, i8_ptr_ty)
if HandlesVar.define_var(
trans.SymTab, var_name, var_alloca) == 0:
new_vars = 1
# 隐式 index 变量 (i64,与 __count__ 类型对齐)
idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i64_ty)
llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), idx_alloca)
# 基本块: cond / body / incr / end
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: str = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "lst.cond.%d", cnt)
cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "lst.body.%d", cnt)
body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "lst.incr.%d", cnt)
incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "lst.end.%d", cnt)
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
llvmlite.build_br(builder, cond_bb)
# cond 块: load index, icmp slt idx, count
llvmlite.position_at_end(builder, cond_bb)
cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, idx_alloca)
in_bounds: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
builder, llvmlite.ICMP_SLT, cur_idx, count_val)
llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb)
# body 块: __data__ + idx*__elem_size__ → load 元素 → store to var
llvmlite.position_at_end(builder, body_bb)
dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, i64_ty, list_val, llvmlite.const_int64(pool, 0))
data_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, dpp)
epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, i64_ty, list_val, llvmlite.const_int64(pool, 4))
esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, epp)
offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, esize)
elem_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, i8_ty, data_ptr, offset)
cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, elem_addr)
llvmlite.build_store(builder, cur_elem, var_alloca)
# 保存旧循环上下文,设置 break/continue 目标
old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb
old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb
trans._break_bb = end_bb
trans._continue_bb = incr_bb
body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children
if body is not None:
body_count: t.CSizeT = len(body)
for bi in range(body_count):
stmt: ast.AST | t.CPtr = body.get(bi)
if stmt is not None:
HandlesBody.translate_stmt(trans, stmt)
trans._break_bb = old_break
trans._continue_bb = old_continue
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, incr_bb)
# incr 块: index++
llvmlite.position_at_end(builder, incr_bb)
one_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1)
next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val)
llvmlite.build_store(builder, next_idx, idx_alloca)
llvmlite.build_br(builder, cond_bb)
# 定位到 end 块
llvmlite.position_at_end(builder, end_bb)
# 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾)
trans._ctrl_merge_reachable = 1
return new_vars
def _handle_dict_iter(self, for_node: ast.For | t.CPtr,
var_name: str,
dict_val: llvmlite.Value | t.CPtr) -> int:
"""dict 容器迭代: for key in d: 按 __count__/__keys__ 布局迭代
_dict.vp 布局(8 字节槽):__keys__@0, __values__@1, __count__@2,
__capacity__@3, __mbuddy__@4, __iter_index__@5。
__iter__ 协议(__iter__ 重置 iter_index + __next__ 取 key)内联为
循环:iter_idx < __count__ → key = __keys__[iter_idx]。
"""
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
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
# 读取 __count__(槽 2,字节偏移 16)
cnt_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, i64_ty, dict_val, llvmlite.const_int64(pool, 2))
if cnt_ptr is None:
HandlesType.fatal_error(for_node, "dict 迭代: 无法定位 __count__")
count_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, cnt_ptr)
# 循环变量 alloca(元素类型 i8*,与 dict.__next__ 返回 str 一致)
var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, var_name)
new_vars: int = 0
if var_alloca is None:
var_alloca = HandlesVar._alloca_at_entry(builder, i8_ptr_ty)
if HandlesVar.define_var(
trans.SymTab, var_name, var_alloca) == 0:
new_vars = 1
# 隐式 index 变量 (i64,与 __count__ 类型对齐)
idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i64_ty)
llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), idx_alloca)
# 基本块: cond / body / incr / end
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: str = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "dict.cond.%d", cnt)
cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "dict.body.%d", cnt)
body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "dict.incr.%d", cnt)
incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "dict.end.%d", cnt)
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
llvmlite.build_br(builder, cond_bb)
# cond 块: load index, icmp slt idx, count
llvmlite.position_at_end(builder, cond_bb)
cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, idx_alloca)
in_bounds: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
builder, llvmlite.ICMP_SLT, cur_idx, count_val)
llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb)
# body 块: __keys__ + idx*8 → load key (i8*) → store to var
llvmlite.position_at_end(builder, body_bb)
kpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, i64_ty, dict_val, llvmlite.const_int64(pool, 0))
keys_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, kpp)
eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 8)
key_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, eight_val)
key_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, i8_ty, keys_ptr, key_offset)
cur_key: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, key_addr)
llvmlite.build_store(builder, cur_key, var_alloca)
# 保存旧循环上下文,设置 break/continue 目标
old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb
old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb
trans._break_bb = end_bb
trans._continue_bb = incr_bb
body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children
if body is not None:
body_count: t.CSizeT = len(body)
for bi in range(body_count):
stmt: ast.AST | t.CPtr = body.get(bi)
if stmt is not None:
HandlesBody.translate_stmt(trans, stmt)
trans._break_bb = old_break
trans._continue_bb = old_continue
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, incr_bb)
# incr 块: index++
llvmlite.position_at_end(builder, incr_bb)
one_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1)
next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val)
llvmlite.build_store(builder, next_idx, idx_alloca)
llvmlite.build_br(builder, cond_bb)
# 定位到 end 块
llvmlite.position_at_end(builder, end_bb)
# 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾)
trans._ctrl_merge_reachable = 1
return new_vars
# ============================================================
# _handle_oop_iter - OOP 迭代协议: for x in obj:
# obj 的类有 __iter__/__next__ 方法时调用协议迭代
# (对齐 TPC HandlesFor.py _HandleForIterLlvm L599-663)
#
# 生成 IR 结构:
# %it = call {Class}.__iter__(obj)
# %flag = alloca i1 ; store 0
# br %cond
# cond:
# store 0, %flag
# %v = call {Class}.__next__(%it, %flag)
# %stop = load i1, %flag
# br i1 %stop==0, %body, %end
# body:
# store %v, %var
# ... 循环体 ...
# br %step
# step:
# br %cond
# end:
#
# __next__ 的隐藏参数 __stop_iter_flag__(i1*)由 ClassGenMixin
# _translate_method 注入,raise StopIteration 时置 1(translate_raise);
# VpiReader stub 声明同步该参数(_inject_method_declare)。
# ============================================================
def _handle_oop_iter(self, for_node: ast.For | t.CPtr,
var_name: str,
class_name: str,
obj_val: llvmlite.Value | t.CPtr) -> int:
"""OOP iter 协议: for x in obj: 调用 __iter__/__next__ 迭代"""
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
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
if builder is None or func is None or mod is None:
return 0
if obj_val is None or obj_val.Ty is None:
HandlesType.fatal_error(for_node, "OOP 迭代: 迭代源对象类型未知")
if HandlesExpr.is_ptr_type(obj_val.Ty) == 0:
HandlesType.fatal_error(for_node, "OOP 迭代: 迭代源对象不是指针类型")
# 1. 查找 {Class}.__iter__ 并调用,得到迭代器
iter_lookup: str = pool.alloc(128)
if iter_lookup is None:
return 0
viperlib.snprintf(iter_lookup, 128, "%s.__iter__", class_name)
iter_fn: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module(
mod, iter_lookup)
if iter_fn is None:
HandlesType.fatal_error(
for_node, f"OOP 迭代: 类 '{class_name}' 没有 __iter__ 方法")
iter_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(iter_fn)
iter_fn_name: str = llvmlite.function_get_name(iter_fn)
if iter_ret_ty is None or iter_fn_name is None:
return 0
# self 参数按 __iter__ 首参类型对齐(stub 声明 self 可能是 i8*)
iter_self: llvmlite.Value | t.CPtr = obj_val
iter_first: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(iter_fn)
if iter_first is not None:
iter_self_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(iter_first)
if iter_self_ty is not None:
iter_self = llvmlite.build_bitcast(builder, obj_val, iter_self_ty)
if iter_self is None:
return 0
iter_self.Next = None
iter_result: llvmlite.Value | t.CPtr = llvmlite.build_call(
builder, iter_fn_name, iter_self, 1, iter_ret_ty, 0)
if iter_result is None:
return 0
# 2. 查找 {Class}.__next__(带隐藏 __stop_iter_flag__ i1* 参数)
next_lookup: str = pool.alloc(128)
if next_lookup is None:
return 0
viperlib.snprintf(next_lookup, 128, "%s.__next__", class_name)
next_fn: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module(
mod, next_lookup)
if next_fn is None:
HandlesType.fatal_error(
for_node, f"OOP 迭代: 类 '{class_name}' 没有 __next__ 方法")
next_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(next_fn)
next_fn_name: str = llvmlite.function_get_name(next_fn)
if next_ret_ty is None or next_fn_name is None:
return 0
# 3. 循环变量 alloca(元素类型 = __next__ 返回类型)
var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, var_name)
new_vars: int = 0
if var_alloca is None:
var_alloca = HandlesVar._alloca_at_entry(builder, next_ret_ty)
if var_alloca is not None:
if HandlesVar.define_var(
trans.SymTab, var_name, var_alloca) == 0:
new_vars = 1
# 4. stop flag alloca(i1,初始 0)
i1_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool)
flag_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i1_ty)
if flag_alloca is None:
return 0
flag_zero: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i1_ty, 0, "0")
if flag_zero is not None:
llvmlite.build_store(builder, flag_zero, flag_alloca)
# 5. 创建基本块: cond / body / step / end
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: str = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "oop.cond.%d", cnt)
cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "oop.body.%d", cnt)
body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "oop.step.%d", cnt)
step_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "oop.end.%d", cnt)
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
if cond_bb is None or body_bb is None or step_bb is None or end_bb is None:
return 0
llvmlite.build_br(builder, cond_bb)
# 6. cond 块: 重置 flag → 调 __next__(iter, flag) → 检查 flag 判结束
llvmlite.position_at_end(builder, cond_bb)
if flag_zero is not None:
llvmlite.build_store(builder, flag_zero, flag_alloca)
# __next__ 参数 1:迭代器(按首参类型 bitcast)
next_self: llvmlite.Value | t.CPtr = iter_result
next_first: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(next_fn)
if next_first is not None:
next_self_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(next_first)
if next_self_ty is not None and iter_result.Ty is not None:
next_self = llvmlite.build_bitcast(builder, iter_result, next_self_ty)
if next_self is None:
return 0
# 参数链表: arg1(iter).Next = arg2(flag);flag 独立 null 结尾防自链接
next_self.Next = flag_alloca
flag_alloca.Next = None
next_val: llvmlite.Value | t.CPtr = llvmlite.build_call(
builder, next_fn_name, next_self, 2, next_ret_ty, 0)
if next_val is None:
return 0
stop_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i1_ty, flag_alloca)
if stop_val is None:
return 0
flag_zero2: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i1_ty, 0, "0")
continue_i1: llvmlite.Value | t.CPtr = None
if flag_zero2 is not None:
continue_i1 = llvmlite.build_icmp(
builder, llvmlite.ICMP_EQ, stop_val, flag_zero2)
if continue_i1 is None:
return 0
llvmlite.build_cond_br(builder, continue_i1, body_bb, end_bb)
# 7. body 块: store 元素 → 翻译循环体 → br step
llvmlite.position_at_end(builder, body_bb)
if var_alloca is not None:
llvmlite.build_store(builder, next_val, var_alloca)
old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb
old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb
trans._break_bb = end_bb
trans._continue_bb = step_bb
body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children
if body is not None:
body_count: t.CSizeT = len(body)
for bi in range(body_count):
stmt: ast.AST | t.CPtr = body.get(bi)
if stmt is not None:
HandlesBody.translate_stmt(trans, stmt)
trans._break_bb = old_break
trans._continue_bb = old_continue
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, step_bb)
# 8. step 块 → cond;定位到 end 块
llvmlite.position_at_end(builder, step_bb)
llvmlite.build_br(builder, cond_bb)
llvmlite.position_at_end(builder, end_bb)
# 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾)
trans._ctrl_merge_reachable = 1
return new_vars
def _handle_enumerate_iter(self, for_node: ast.For | t.CPtr,
t1: str, t2: str,
call: ast.Call | t.CPtr) -> int:
"""enumerate 迭代: for i, v in enumerate(x)"""
if call is None or call.args is None:
return 0
cargs: list[ast.AST | t.CPtr] | t.CPtr = call.args
if len(cargs) < 1:
HandlesType.fatal_error(for_node, "enumerate 需要至少一个参数")
return self._build_seq_loop(for_node, t1, t2, cargs.get(0), None, 1)
def _handle_zip_iter(self, for_node: ast.For | t.CPtr,
t1: str, t2: str,
call: ast.Call | t.CPtr) -> int:
"""zip 迭代: for a, b in zip(x, y)"""
if call is None or call.args is None:
# fail-fast: zip 参数缺失
HandlesType.fatal_error(call, "zip 参数缺失", "SyntaxError")
cargs: list[ast.AST | t.CPtr] | t.CPtr = call.args
if len(cargs) < 2:
HandlesType.fatal_error(for_node, "zip 需要至少两个参数")
return self._build_seq_loop(for_node, t1, t2, cargs.get(0), cargs.get(1), 2)