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

449 lines
22 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.ForHandleBase as ForHandleBase
import lib.core.Handles.ForHandleIter as ForHandleIter
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
# ============================================================
# HandlesFor - for 循环语句处理(P6 对象化后的委托层)
#
# NewForHandle 工厂已迁移为 lib.core.Gen.StmtGenMixin 的方法
# (ForHandle 类保留:trans.ForH 的类型,由 HandlesTranslator.
# _init_state 经 NewForHandle 委托创建)。
#
# 支持 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:
# ============================================================
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式)
#
# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。
# 委托函数用本地 _g_gen(cast 成 Generator 类型)调
# StmtGenMixin 方法,避免函数体 import 包模块与类/模块名歧义。
# ============================================================
_g_gen: t.CVoid | t.CPtr = None
# ============================================================
# 序列迭代源类型码(for x in ... / enumerate / zip 迭代源分类)
# RANGE: range(start, stop, step)
# STR: 字符串(常量或 str 变量)
# LIST: list[T] 容器(按 __count__ + __data__ 迭代)
# ============================================================
SEQ_KIND_RANGE: t.CDefine = 1
SEQ_KIND_STR: t.CDefine = 2
SEQ_KIND_LIST: t.CDefine = 3
def set_global_gen(gen: t.CVoid | t.CPtr) -> None:
"""注入全局 gen 单例(BuildPipeline/main 调用)"""
global _g_gen
_g_gen = gen
@t.NoVTable
class ForHandle(ForHandleBase.ForHandleBase, ForHandleIter.ForHandleIter):
"""for 循环语句处理器:继承 Mixin 获得 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. 获取循环变量(Name 单变量 / Tuple 多变量)
target: ast.AST | t.CPtr = for_node.target
if target is None:
return 0
tk: int = target.kind()
if tk != ast.ASTKind.Name and tk != ast.ASTKind.Tuple:
return 0
var_name: str = None
if tk == ast.ASTKind.Name:
target_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
var_name = 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
elif string.strcmp(fn_pre, "enumerate") == 0 or string.strcmp(fn_pre, "zip") == 0:
pass # 多变量迭代,在下方非 range 分支处理
else:
err_msg: str = pool.alloc(256)
if err_msg is not None:
viperlib.snprintf(err_msg, 256, "仅支持 range()/enumerate()/zip() 或指针迭代,got call '%s'", fn_pre)
HandlesType.fatal_error(iter_node, err_msg)
HandlesType.fatal_error(iter_node, "仅支持 range()/enumerate()/zip() 或指针迭代")
# 非范围迭代:走指针/数组/列表字面量/容器/多变量迭代路径
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)
# enumerate(x):for i, v in enumerate(x)(多变量迭代)
if iter_node.kind() == ast.ASTKind.Call:
call_mi: ast.Call | t.CPtr = (ast.Call | t.CPtr)(iter_node)
fn_mi: str = HandlesExpr.get_func_name(call_mi.func)
if fn_mi is not None and string.strcmp(fn_mi, "enumerate") == 0:
if tk != ast.ASTKind.Tuple:
HandlesType.fatal_error(iter_node, "enumerate 迭代需要两个循环变量 (for i, v in enumerate(x))")
tup_ie: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(target)
t1_buf_ie: bytes = pool.alloc(128)
t2_buf_ie: bytes = pool.alloc(128)
if t1_buf_ie is None or t2_buf_ie is None:
return 0
t1_buf_ie[0] = '\0'
t2_buf_ie[0] = '\0'
if self._extract_tuple_names(tup_ie, t1_buf_ie, t2_buf_ie) == 0:
HandlesType.fatal_error(iter_node, "enumerate 迭代变量必须是简单名称")
return self._handle_enumerate_iter(for_node, t1_buf_ie, t2_buf_ie, call_mi)
if fn_mi is not None and string.strcmp(fn_mi, "zip") == 0:
if tk != ast.ASTKind.Tuple:
HandlesType.fatal_error(iter_node, "zip 迭代需要两个循环变量 (for a, b in zip(...))")
tup_iz: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(target)
t1_buf_iz: bytes = pool.alloc(128)
t2_buf_iz: bytes = pool.alloc(128)
if t1_buf_iz is None or t2_buf_iz is None:
return 0
t1_buf_iz[0] = '\0'
t2_buf_iz[0] = '\0'
if self._extract_tuple_names(tup_iz, t1_buf_iz, t2_buf_iz) == 0:
HandlesType.fatal_error(iter_node, "zip 迭代变量必须是简单名称")
return self._handle_zip_iter(for_node, t1_buf_iz, t2_buf_iz, call_mi)
# list[T] 容器变量:按 __count__ 动态长度迭代
if iter_node.kind() == ast.ASTKind.Name and trans is not None:
nm_lst: ast.Name | t.CPtr = (ast.Name | t.CPtr)(iter_node)
if nm_lst.id is not None:
ve_lst: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
trans.SymTab, nm_lst.id)
if ve_lst is not None and ve_lst.AnnotClassName is not None:
# dict 容器变量:按 __count__/__keys__ 布局迭代(__iter__ 协议内联)
if string.strstr(ve_lst.AnnotClassName, "dict") is not None:
lst_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, iter_node,
trans._funcs, trans._func_count, trans)
if lst_val is not None and lst_val.Ty is not None \
and HandlesExpr.is_ptr_type(lst_val.Ty) != 0:
return self._handle_dict_iter(for_node, var_name, lst_val)
if string.strstr(ve_lst.AnnotClassName, "list") is not None:
lst_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, iter_node,
trans._funcs, trans._func_count, trans)
if lst_val is not None and lst_val.Ty is not None \
and HandlesExpr.is_ptr_type(lst_val.Ty) != 0:
return self._handle_list_iter(for_node, var_name, lst_val)
# OOP iter 协议:迭代源是类对象且类有 __iter__/__next__ 方法 →
# 走 __iter__/__next__ 调用迭代(对齐 TPC HandlesFor.py L142-166
# _HandleForIterLlvm)。dict/list 是内置泛型容器已在上方内联处理。
ov_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, iter_node,
trans._funcs, trans._func_count, trans)
if ov_val is not None and ov_val.Ty is not None \
and HandlesExpr.is_ptr_type(ov_val.Ty) != 0:
ov_st: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(
ov_val)
if ov_st is not None:
ov_cn: str = HandlesStruct.get_class_name_by_type(pool, ov_st)
if ov_cn is not None:
oi_lookup: str = pool.alloc(128)
if oi_lookup is not None:
viperlib.snprintf(oi_lookup, 128, "%s.__iter__", ov_cn)
oi_fn: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module(
trans.Module, oi_lookup)
if oi_fn is not None:
on_lookup: str = pool.alloc(128)
if on_lookup is not None:
viperlib.snprintf(on_lookup, 128, "%s.__next__", ov_cn)
on_fn: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module(
trans.Module, on_lookup)
if on_fn is not None:
return self._handle_oop_iter(
for_node, var_name, ov_cn, ov_val)
# 其它不支持的字面量: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 = len(args)
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 == 0:
# fail-fast: range 无参数,立即终止
HandlesType.fatal_error(call, "range 需要至少一个参数", "SyntaxError")
elif arg_count == 1:
stop_val = HandlesExpr.translate_value(
builder, pool, trans.Module, args.get(0),
trans._funcs, trans._func_count, trans)
if stop_val is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(args.get(0), "range 参数翻译失败", "TypeError")
elif arg_count >= 2:
start_val = HandlesExpr.translate_value(
builder, pool, trans.Module, args.get(0),
trans._funcs, trans._func_count, trans)
if start_val is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(args.get(0), "range 参数翻译失败", "TypeError")
stop_val = HandlesExpr.translate_value(
builder, pool, trans.Module, args.get(1),
trans._funcs, trans._func_count, trans)
if stop_val is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(args.get(1), "range 参数翻译失败", "TypeError")
if arg_count >= 3:
step_val = HandlesExpr.translate_value(
builder, pool, trans.Module, args.get(2),
trans._funcs, trans._func_count, trans)
if step_val is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(args.get(2), "range 参数翻译失败", "TypeError")
# step 为负数字面量时循环条件反转(对齐 TPC HandlesFor.py L86-94):
# range(a, b, -1) → i > stop;range(a, b, +1) → i < stop。
# TPC 仅识别负数字面量(UnaryOp USub 常量 / 负常量);变量 step 保守按正。
# 修复 _find_provider 的 range(top-1, -1, -1) 循环体不执行(i < -1 恒假)。
step_neg_const: int = 0
if arg_count >= 3:
step_arg_node: ast.AST | t.CPtr = args.get(2)
if step_arg_node is not None:
skn: int = step_arg_node.kind()
if skn == ast.ASTKind.UnaryOp:
uop_r: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(step_arg_node)
if uop_r.op == ast.OpKind.USub and uop_r.operand is not None:
if uop_r.operand.kind() == ast.ASTKind.Constant:
uoc_r: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(uop_r.operand)
if uoc_r.int_val > 0:
step_neg_const = 1
elif skn == ast.ASTKind.Constant:
skc_r: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(step_arg_node)
if skc_r.int_val < 0:
step_neg_const = 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: str = 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:
# 循环变量位宽 > stop 位宽(如 t.CSizeT 循环变量 + range(i32)):
# 应把 cur_i 截断到 stop_val 类型(低向高才 sext/zext,高向低用
# trunc)。原实现反了——把小的 stop_val trunc 到大的 loop_var_ty,
# 生成 `trunc i32 to i64` 扩宽非法 IR,llc 报
# "invalid cast opcode for cast from 'i32' to 'i64'"
# (VpiReader.vp range(arg_count) 追加86 根因)。
cmp_lhs = llvmlite.build_trunc(builder, cur_i, stop_val.Ty)
# step 为负时条件反转:i > stop(ICMP_SGT);正/缺省 step 保持 i < stop
range_cmp_op: int = llvmlite.ICMP_SLT
if step_neg_const != 0:
range_cmp_op = llvmlite.ICMP_SGT
cond_i1: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
builder, range_cmp_op, 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 = 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)
# 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)
# 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾)
trans._ctrl_merge_reachable = 1
return new_vars
# ============================================================
# NewForHandle - 工厂函数(委托到 gen.NewForHandle)
# ============================================================
def NewForHandle(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> ForHandle | t.CPtr:
"""创建 ForHandle 实例(委托到 gen.NewForHandle)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.NewForHandle(pool, trans)
return None