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

612 lines
27 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
# ============================================================
# HandlesFor - for 循环语句处理(Mixin 继承模式)
#
# 支持 for i in range(start, stop, step) 模式:
# %i = alloca i32
# store i32 start, i32* %i
# br label %cond
# cond:
# %cur = load i32, i32* %i
# %cmp = icmp slt i32 %cur, stop
# br i1 %cmp, label %body, label %end
# body:
# ... body ...
# br label %incr
# incr:
# %cur2 = load i32, i32* %i
# %next = add i32 %cur2, step
# store i32 %next, i32* %i
# br label %cond
# end:
# ============================================================
@t.NoVTable
class ForHandle(HandlesBase.Mixin):
"""for 循环语句处理器:继承 Mixin 获得 Trans 回指针"""
def __init__(self, trans: HT.Translator | t.CPtr):
self.Trans = trans
# ============================================================
# Handle - 处理 for 语句,返回新增变量数
# ============================================================
def Handle(self, node: ast.AST | t.CPtr) -> int:
"""翻译 for i in range(...) 循环语句"""
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
for_node: ast.For | t.CPtr = (ast.For | t.CPtr)(node)
# 1. 获取循环变量名(仅支持 for i in range(...))
target: ast.AST | t.CPtr = for_node.target
if target is None:
return 0
if target.kind() != ast.ASTKind.Name:
return 0
target_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
var_name: str = target_nm.id
if var_name is None:
return 0
# 2. 解析迭代器:支持 range() 和指针迭代
iter_node: ast.AST | t.CPtr = for_node.iter
if iter_node is None:
return 0
# 检查是否是 range() 调用
is_range_iter: int = 0
if iter_node.kind() == ast.ASTKind.Call:
call_pre: ast.Call | t.CPtr = (ast.Call | t.CPtr)(iter_node)
fn_pre: str = HandlesExpr.get_func_name(call_pre.func)
if fn_pre is not None:
if string.strcmp(fn_pre, "range") == 0:
is_range_iter = 1
else:
err_msg: t.CChar | t.CPtr = pool.alloc(256)
if err_msg is not None:
viperlib.snprintf(err_msg, 256, "仅支持 range() 或指针迭代,got call '%s'", fn_pre)
HandlesType.fatal_error(iter_node, err_msg)
HandlesType.fatal_error(iter_node, "仅支持 range() 或指针迭代")
# 非范围迭代:走指针/数组/列表字面量迭代路径
if is_range_iter == 0:
# 列表字面量:按元素顺序迭代(for x in [1, 2, 3])
if iter_node.kind() == ast.ASTKind.List:
return self._handle_list_literal_iter(for_node, var_name, iter_node)
# 其它不支持的字面量:fast-fail 显式报错,
# 避免 translate_value 触发 list[T] 特化崩溃或语义歧义。
ik: int = iter_node.kind()
if ik == ast.ASTKind.Constant:
cn_ik: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(iter_node)
if cn_ik.const_kind != ast.CONST_STR:
HandlesType.fatal_error(
iter_node,
"for 迭代不支持该常量(仅支持字符串、数组、列表字面量、range())")
elif ik == ast.ASTKind.Dict or ik == ast.ASTKind.Set or ik == ast.ASTKind.Tuple \
or ik == ast.ASTKind.SetComp or ik == ast.ASTKind.DictComp:
HandlesType.fatal_error(
iter_node,
"for 迭代不支持字典/集合/元组字面量,请使用 range()、t.CArray 数组或列表字面量")
return self._handle_ptr_iter(for_node, var_name)
call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(iter_node)
# 3. 解析 range 参数: range(stop) / range(start, stop) / range(start, stop, step)
args: list[ast.AST | t.CPtr] | t.CPtr = call.args
if args is None:
return 0
arg_count: t.CSizeT = args.__len__()
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
start_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
stop_val: llvmlite.Value | t.CPtr = None
step_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1)
if arg_count == 1:
stop_val = HandlesExpr.translate_value(
builder, pool, trans.Module, args.get(0),
trans._funcs, trans._func_count, trans)
elif arg_count >= 2:
start_val = HandlesExpr.translate_value(
builder, pool, trans.Module, args.get(0),
trans._funcs, trans._func_count, trans)
stop_val = HandlesExpr.translate_value(
builder, pool, trans.Module, args.get(1),
trans._funcs, trans._func_count, trans)
if arg_count >= 3:
step_val = HandlesExpr.translate_value(
builder, pool, trans.Module, args.get(2),
trans._funcs, trans._func_count, trans)
if stop_val is None:
stop_val = llvmlite.const_int32(pool, 0)
if start_val is None:
start_val = llvmlite.const_int32(pool, 0)
if step_val is None:
step_val = llvmlite.const_int32(pool, 1)
# 4. 创建/查找循环变量 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, i32_ty)
if HandlesVar.define_var(
trans.SymTab, var_name, var_alloca) == 0:
new_vars = 1
# 获取循环变量的实际元素类型(alloca 是指针类型,需解引用 Pointee)
# 当循环变量已声明为 i64(如 t.CSizeT),使用 i64 而非硬编码 i32
# 避免 load i32, i64* / store i32, i64* 类型不匹配
loop_var_ty: llvmlite.LLVMType | t.CPtr = i32_ty
if var_alloca is not None and var_alloca.Ty is not None:
match var_alloca.Ty:
case llvmlite.LLVMType.Ptr(pointee_ty):
if pointee_ty is not None:
loop_var_ty = pointee_ty
loop_var_bits: int = HandlesExpr.get_llvm_type_bits(loop_var_ty)
# 5. 存储初始值 (类型对齐: start_val 可能是 i32/i64,需对齐到 loop_var_ty)
init_val: llvmlite.Value | t.CPtr = start_val
if start_val is not None and start_val.Ty is not None:
start_bits: int = HandlesExpr.get_llvm_type_bits(start_val.Ty)
if start_bits != 0 and start_bits != loop_var_bits:
if start_bits < loop_var_bits:
init_val = llvmlite.build_sext(builder, start_val, loop_var_ty)
else:
init_val = llvmlite.build_trunc(builder, start_val, loop_var_ty)
llvmlite.build_store(builder, init_val, var_alloca)
# 6. 创建基本块: cond / body / incr / end(使用 trans._label_counter,不与 SSA 名共享)
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "for.cond.%d", cnt)
cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "for.body.%d", cnt)
body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "for.incr.%d", cnt)
incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "for.end.%d", cnt)
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
# 7. 跳转到 cond 块
llvmlite.build_br(builder, cond_bb)
# 8. cond 块: load i, icmp slt i, stop, cond_br body/end
llvmlite.position_at_end(builder, cond_bb)
cur_i: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, loop_var_ty, var_alloca)
# 类型对齐: stop_val 可能是 i64 (如 range(strlen(s))),需将 cur_i 提升到 stop_val 类型
cmp_lhs: llvmlite.Value | t.CPtr = cur_i
cmp_rhs: llvmlite.Value | t.CPtr = stop_val
if stop_val is not None and stop_val.Ty is not None:
stop_bits: int = HandlesExpr.get_llvm_type_bits(stop_val.Ty)
cur_bits: int = HandlesExpr.get_llvm_type_bits(cur_i.Ty)
if stop_bits != 0 and cur_bits != 0 and stop_bits != cur_bits:
if cur_bits < stop_bits:
cmp_lhs = llvmlite.build_sext(builder, cur_i, stop_val.Ty)
else:
cmp_rhs = llvmlite.build_trunc(builder, stop_val, loop_var_ty)
cond_i1: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
builder, llvmlite.ICMP_SLT, cmp_lhs, cmp_rhs)
llvmlite.build_cond_br(builder, cond_i1, body_bb, end_bb)
# 9. body 块: 翻译循环体,跳到 incr
llvmlite.position_at_end(builder, body_bb)
# 保存旧循环上下文,设置 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 = body.__len__()
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)
# 10. incr 块: i = i + step, 跳回 cond
llvmlite.position_at_end(builder, incr_bb)
cur_i2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, loop_var_ty, var_alloca)
# 类型对齐: step_val 可能是 i32/i64,需对齐到 loop_var_ty 与 cur_i2 类型一致
incr_step: llvmlite.Value | t.CPtr = step_val
if step_val is not None and step_val.Ty is not None:
step_bits: int = HandlesExpr.get_llvm_type_bits(step_val.Ty)
cur2_bits: int = HandlesExpr.get_llvm_type_bits(cur_i2.Ty)
if step_bits != 0 and cur2_bits != 0 and step_bits != cur2_bits:
if step_bits > cur2_bits:
incr_step = llvmlite.build_trunc(builder, step_val, loop_var_ty)
else:
incr_step = llvmlite.build_sext(builder, step_val, loop_var_ty)
next_i: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_i2, incr_step)
llvmlite.build_store(builder, next_i, var_alloca)
llvmlite.build_br(builder, cond_bb)
# 11. 定位到 end 块
llvmlite.position_at_end(builder, end_bb)
return new_vars
# ============================================================
# _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, "指针迭代: 无法获取元素类型")
# 元素类型必须是整数(用于 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: t.CChar | t.CPtr = 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 = body.__len__()
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)
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: t.CChar | t.CPtr = 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 = body.__len__()
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)
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 = elts.__len__()
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)
# ============================================================
# NewForHandle - 工厂函数
# ============================================================
def NewForHandle(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> ForHandle | t.CPtr:
h: ForHandle | t.CPtr = pool.alloc(ForHandle.__sizeof__())
if h is None:
return None
string.memset(h, 0, ForHandle.__sizeof__())
h.Trans = trans
return h