Files
ViperC/App/lib/core/Handles/ForHandleBase.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

395 lines
21 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
# ============================================================
# ForHandleBase - HandlesFor 拆分(阶段 E):ForHandleBase
#
# 类方法拆 Mixin:self 调用按 1 级父类解析(TPV 限制)。
# @t.NoVTable:静态绑定。
# ============================================================
@t.NoVTable
class ForHandleBase(HandlesBase.Mixin):
"""ForHandleBase"""
def __init__(self, trans: HT.Translator | t.CPtr):
self.Trans = trans
# ============================================================
# 多变量迭代(enumerate / zip)
#
# 支持迭代源: range(start, stop, step) / 字符串(常量|变量) / list[T]
# enumerate(x) → for i, v in enumerate(x):i 为序号,v 为元素
# zip(a, b) → for x, y in zip(a, b):任一源耗尽即终止
# ============================================================
def _extract_tuple_names(self, tup: ast.Tuple | t.CPtr,
out1: str | t.CPtr, out2: str | t.CPtr) -> int:
"""从 Tuple target 提取前两个 Name 变量名,写入 out1/out2,成功返回 1"""
if tup is None or tup.elts is None or out1 is None or out2 is None:
return 0
elts: list[ast.AST | t.CPtr] | t.CPtr = tup.elts
n: t.CSizeT = len(elts)
if n < 2:
return 0
e0: ast.AST | t.CPtr = elts.get(0)
e1: ast.AST | t.CPtr = elts.get(1)
if e0 is None or e1 is None:
return 0
if e0.kind() != ast.ASTKind.Name or e1.kind() != ast.ASTKind.Name:
return 0
n0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(e0)
n1: ast.Name | t.CPtr = (ast.Name | t.CPtr)(e1)
if n0.id is None or n1.id is None:
return 0
string.strcpy(out1, n0.id)
string.strcpy(out2, n1.id)
return 1
def _seq_kind(self, src: ast.AST | t.CPtr) -> int:
"""判断迭代源类型: SEQ_KIND_RANGE / STR / LIST,不支持返回 0"""
if src is None:
return 0
k: int = src.kind()
if k == ast.ASTKind.Call:
cl_s: ast.Call | t.CPtr = (ast.Call | t.CPtr)(src)
fn_s: str = HandlesExpr.get_func_name(cl_s.func)
if fn_s is not None and string.strcmp(fn_s, "range") == 0:
return SEQ_KIND_RANGE
return 0
if k == ast.ASTKind.Constant:
cn_s: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(src)
if cn_s is not None and cn_s.const_kind == ast.CONST_STR:
return SEQ_KIND_STR
return 0
if k == ast.ASTKind.Name:
nm_s: ast.Name | t.CPtr = (ast.Name | t.CPtr)(src)
if nm_s.id is not None and self.Trans is not None:
ve_s: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
self.Trans.SymTab, nm_s.id)
if ve_s is not None and ve_s.AnnotClassName is not None:
if string.strstr(ve_s.AnnotClassName, "list") is not None:
return SEQ_KIND_LIST
return SEQ_KIND_STR
return 0
def _build_seq_loop(self, for_node: ast.For | t.CPtr,
t1: str, t2: str,
src1: ast.AST | t.CPtr,
src2: ast.AST | t.CPtr,
n_srcs: int) -> int:
"""生成序列迭代循环(enumerate: n_srcs=1 / zip: n_srcs=2)
循环变量 alloca 自动创建或复用;元素类型由源类型决定
(RANGE→i32, STR→i8, LIST→i8*)。索引内部统一 i64。
"""
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
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
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)
# ---- 源 1 准备 ----
kind1: int = self._seq_kind(src1)
if kind1 == 0:
HandlesType.fatal_error(for_node, "序列迭代: 源 1 类型不支持")
r1_start: llvmlite.Value | t.CPtr = None
r1_stop: llvmlite.Value | t.CPtr = None
r1_step: llvmlite.Value | t.CPtr = None
s1_ptr: llvmlite.Value | t.CPtr = None
l1_count: llvmlite.Value | t.CPtr = None
l1_data: llvmlite.Value | t.CPtr = None
l1_esize: llvmlite.Value | t.CPtr = None
elem1_ty: llvmlite.LLVMType | t.CPtr = i8_ptr_ty
if kind1 == SEQ_KIND_RANGE:
elem1_ty = i32_ty
r1_start = llvmlite.const_int64(pool, 0)
r1_step = llvmlite.const_int64(pool, 1)
r1_stop = llvmlite.const_int64(pool, 0)
# 先赋中间变量再取 args(cast 链式属性访问会推断错字段偏移)
call_src1: ast.Call | t.CPtr = (ast.Call | t.CPtr)(src1)
cargs1: list[ast.AST | t.CPtr] | t.CPtr = call_src1.args
if cargs1 is not None:
n1: t.CSizeT = len(cargs1)
if n1 >= 1:
sv: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, cargs1.get(0),
trans._funcs, trans._func_count, trans)
if sv is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(cargs1.get(0), "range 参数翻译失败", "TypeError")
r1_stop = HandlesExpr.coerce_to_type(builder, sv, i64_ty, cargs1.get(0))
if n1 >= 2:
sv2: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, cargs1.get(1),
trans._funcs, trans._func_count, trans)
if sv2 is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(cargs1.get(1), "range 参数翻译失败", "TypeError")
r1_start = HandlesExpr.coerce_to_type(builder, sv2, i64_ty, cargs1.get(1))
if n1 >= 3:
sv3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, cargs1.get(2),
trans._funcs, trans._func_count, trans)
if sv3 is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(cargs1.get(2), "range 参数翻译失败", "TypeError")
r1_step = HandlesExpr.coerce_to_type(builder, sv3, i64_ty, cargs1.get(2))
elif kind1 == SEQ_KIND_STR:
elem1_ty = i8_ty
s1_ptr = HandlesExpr.translate_value(
builder, pool, trans.Module, src1,
trans._funcs, trans._func_count, trans)
if s1_ptr is None:
HandlesType.fatal_error(for_node, "序列迭代: 字符串源翻译失败")
elif kind1 == SEQ_KIND_LIST:
elem1_ty = i8_ptr_ty
l1_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, src1,
trans._funcs, trans._func_count, trans)
if l1_obj is None or l1_obj.Ty is None \
or HandlesExpr.is_ptr_type(l1_obj.Ty) == 0:
HandlesType.fatal_error(for_node, "序列迭代: list 源不是指针类型")
l1_count = llvmlite.build_load(builder, i64_ty,
llvmlite.build_gep(builder, i64_ty, l1_obj, llvmlite.const_int64(pool, 1)))
l1_data = llvmlite.build_load(builder, i8_ptr_ty,
llvmlite.build_gep(builder, i64_ty, l1_obj, llvmlite.const_int64(pool, 0)))
l1_esize = llvmlite.build_load(builder, i64_ty,
llvmlite.build_gep(builder, i64_ty, l1_obj, llvmlite.const_int64(pool, 4)))
# ---- 源 2 准备(zip)----
kind2: int = 0
elem2_ty: llvmlite.LLVMType | t.CPtr = elem1_ty
s2_ptr: llvmlite.Value | t.CPtr = None
l2_count: llvmlite.Value | t.CPtr = None
l2_data: llvmlite.Value | t.CPtr = None
l2_esize: llvmlite.Value | t.CPtr = None
r2_start: llvmlite.Value | t.CPtr = None
r2_stop: llvmlite.Value | t.CPtr = None
r2_step: llvmlite.Value | t.CPtr = None
if n_srcs >= 2:
kind2 = self._seq_kind(src2)
if kind2 == 0:
HandlesType.fatal_error(for_node, "序列迭代: 源 2 类型不支持")
if kind2 == SEQ_KIND_RANGE:
elem2_ty = i32_ty
r2_start = llvmlite.const_int64(pool, 0)
r2_step = llvmlite.const_int64(pool, 1)
r2_stop = llvmlite.const_int64(pool, 0)
# 先赋中间变量再取 args(cast 链式属性访问会推断错字段偏移)
call_src2: ast.Call | t.CPtr = (ast.Call | t.CPtr)(src2)
cargs2: list[ast.AST | t.CPtr] | t.CPtr = call_src2.args
if cargs2 is not None:
n2: t.CSizeT = len(cargs2)
if n2 >= 1:
svz: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, cargs2.get(0),
trans._funcs, trans._func_count, trans)
if svz is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(cargs2.get(0), "range 参数翻译失败", "TypeError")
r2_stop = HandlesExpr.coerce_to_type(builder, svz, i64_ty, cargs2.get(0))
if n2 >= 2:
svz2: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, cargs2.get(1),
trans._funcs, trans._func_count, trans)
if svz2 is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(cargs2.get(1), "range 参数翻译失败", "TypeError")
r2_start = HandlesExpr.coerce_to_type(builder, svz2, i64_ty, cargs2.get(1))
if n2 >= 3:
svz3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, cargs2.get(2),
trans._funcs, trans._func_count, trans)
if svz3 is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(cargs2.get(2), "range 参数翻译失败", "TypeError")
r2_step = HandlesExpr.coerce_to_type(builder, svz3, i64_ty, cargs2.get(2))
elif kind2 == SEQ_KIND_STR:
elem2_ty = i8_ty
s2_ptr = HandlesExpr.translate_value(
builder, pool, trans.Module, src2,
trans._funcs, trans._func_count, trans)
if s2_ptr is None:
HandlesType.fatal_error(for_node, "序列迭代: 字符串源 2 翻译失败")
elif kind2 == SEQ_KIND_LIST:
elem2_ty = i8_ptr_ty
l2_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, src2,
trans._funcs, trans._func_count, trans)
if l2_obj is None or l2_obj.Ty is None \
or HandlesExpr.is_ptr_type(l2_obj.Ty) == 0:
HandlesType.fatal_error(for_node, "序列迭代: list 源 2 不是指针类型")
l2_count = llvmlite.build_load(builder, i64_ty,
llvmlite.build_gep(builder, i64_ty, l2_obj, llvmlite.const_int64(pool, 1)))
l2_data = llvmlite.build_load(builder, i8_ptr_ty,
llvmlite.build_gep(builder, i64_ty, l2_obj, llvmlite.const_int64(pool, 0)))
l2_esize = llvmlite.build_load(builder, i64_ty,
llvmlite.build_gep(builder, i64_ty, l2_obj, llvmlite.const_int64(pool, 4)))
# ---- 循环变量 alloca ----
# t1: enumerate → 序号 (i32);zip → 源 1 元素
t1_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, t1)
new_vars: int = 0
if t1_alloca is None:
if n_srcs == 1:
t1_alloca = HandlesVar._alloca_at_entry(builder, i32_ty)
else:
t1_alloca = HandlesVar._alloca_at_entry(builder, elem1_ty)
if t1_alloca is not None:
if HandlesVar.define_var(trans.SymTab, t1, t1_alloca) == 0:
new_vars += 1
# t2: 源 2 元素(enumerate 时 = 源 1 元素)
t2_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, t2)
if t2_alloca is None:
t2_alloca = HandlesVar._alloca_at_entry(builder, elem2_ty)
if t2_alloca is not None:
if HandlesVar.define_var(trans.SymTab, t2, t2_alloca) == 0:
new_vars += 1
# 隐式 index 变量 (i64)
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, "seq.cond.%d", cnt)
cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "seq.body.%d", cnt)
body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "seq.incr.%d", cnt)
incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "seq.end.%d", cnt)
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
llvmlite.build_br(builder, cond_bb)
# cond 块: 源 1 done 检查(zip 需源 2 也 done)
llvmlite.position_at_end(builder, cond_bb)
cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, idx_alloca)
done1: llvmlite.Value | t.CPtr = None
if kind1 == SEQ_KIND_RANGE:
done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, r1_stop)
elif kind1 == SEQ_KIND_STR:
ch_ptr1: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s1_ptr, cur_idx)
ch1: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ty, ch_ptr1)
zero1: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, 8, 0)
done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, ch1, zero1)
elif kind1 == SEQ_KIND_LIST:
done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, l1_count)
cont: llvmlite.Value | t.CPtr = done1
if n_srcs >= 2:
done2: llvmlite.Value | t.CPtr = None
if kind2 == SEQ_KIND_RANGE:
done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, r2_stop)
elif kind2 == SEQ_KIND_STR:
ch_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s2_ptr, cur_idx)
ch2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ty, ch_ptr2)
zero2: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, 8, 0)
done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, ch2, zero2)
elif kind2 == SEQ_KIND_LIST:
done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, l2_count)
cont = llvmlite.build_and(builder, done1, done2)
llvmlite.build_cond_br(builder, cont, body_bb, end_bb)
# body 块: 获取元素 → store → 循环体
llvmlite.position_at_end(builder, body_bb)
# 源 1 元素
v1: llvmlite.Value | t.CPtr = None
if kind1 == SEQ_KIND_RANGE:
step1: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, r1_step)
v1 = llvmlite.build_add(builder, r1_start, step1)
elif kind1 == SEQ_KIND_STR:
ch_ptr1b: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s1_ptr, cur_idx)
v1 = llvmlite.build_load(builder, i8_ty, ch_ptr1b)
elif kind1 == SEQ_KIND_LIST:
off1: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, l1_esize)
addr1: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, l1_data, off1)
v1 = llvmlite.build_load(builder, i8_ptr_ty, addr1)
# store t1 / t2
if t1_alloca is not None and t1_alloca.Ty is not None:
t1_ty: llvmlite.LLVMType | t.CPtr = t1_alloca.Ty.Pointee
if n_srcs == 1:
# enumerate: t1 = 序号(trunc i64 → i32)
idx32: llvmlite.Value | t.CPtr = llvmlite.build_trunc(builder, cur_idx, i32_ty)
llvmlite.build_store(builder, idx32, t1_alloca)
if t2_alloca is not None and t2_alloca.Ty is not None and v1 is not None:
t2_ty: llvmlite.LLVMType | t.CPtr = t2_alloca.Ty.Pointee
v1c: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, v1, t2_ty, src1)
llvmlite.build_store(builder, v1c, t2_alloca)
else:
if v1 is not None:
v1c: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, v1, t1_ty, src1)
llvmlite.build_store(builder, v1c, t1_alloca)
# 源 2 元素 → t2
v2: llvmlite.Value | t.CPtr = None
if kind2 == SEQ_KIND_RANGE:
step2: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, r2_step)
v2 = llvmlite.build_add(builder, r2_start, step2)
elif kind2 == SEQ_KIND_STR:
ch_ptr2b: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s2_ptr, cur_idx)
v2 = llvmlite.build_load(builder, i8_ty, ch_ptr2b)
elif kind2 == SEQ_KIND_LIST:
off2: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, l2_esize)
addr2: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, l2_data, off2)
v2 = llvmlite.build_load(builder, i8_ptr_ty, addr2)
if t2_alloca is not None and t2_alloca.Ty is not None and v2 is not None:
t2_ty2: llvmlite.LLVMType | t.CPtr = t2_alloca.Ty.Pointee
v2c: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, v2, t2_ty2, src2)
llvmlite.build_store(builder, v2c, t2_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