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