From 244c8efc96c334b66e451bce004daa8c9f7133cc Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 11 Aug 2026 22:10:01 +0800 Subject: [PATCH] =?UTF-8?q?feat(for):=20list=20=E5=AE=B9=E5=99=A8=E8=BF=AD?= =?UTF-8?q?=E4=BB=A3=E4=B8=8E=20enumerate/zip=20=E5=A4=9A=E5=8F=98?= =?UTF-8?q?=E9=87=8F=E8=BF=AD=E4=BB=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - HandlesFor: for v in lst 按 __count__+__data__ 动态长度迭代; 统一序列循环(RANGE/STR/LIST); cast 链属性访问改中间变量(避免字段偏移推断错误) - ExprGenMixin: 跨模块 CDefine 完整修复——vpi 仅声明无值回退源文件、includes 双前缀路径、浮点值 atof 解析+double 缓存+ConstFloat 返回 --- App/lib/core/Gen/ExprGenMixin.vp | 76 +++- App/lib/core/Handles/HandlesFor.vp | 586 ++++++++++++++++++++++++++++- 2 files changed, 650 insertions(+), 12 deletions(-) diff --git a/App/lib/core/Gen/ExprGenMixin.vp b/App/lib/core/Gen/ExprGenMixin.vp index e9e2f9e..c4520de 100644 --- a/App/lib/core/Gen/ExprGenMixin.vp +++ b/App/lib/core/Gen/ExprGenMixin.vp @@ -1663,7 +1663,9 @@ class ExprGenMixin: rel_path: str = rel_arr_ptr + ridx if rel_path[0] == '\0': return None - # 选择基础目录:rel_path 以 "lib/" 开头 → App 源文件(SourceDir),否则 includes 文件 + # 选择基础目录:rel_path 以 "lib/" 开头 → App 源文件(SourceDir); + # 以 "includes/" 开头 → includes 文件(去掉 "includes/" 前缀, + # 因 IncludesDir 已包含 includes 目录本身,避免双前缀导致文件不存在) base_dir: str = Config.IncludesDir is_app: int = 0 if string.strlen(rel_path) >= 4: @@ -1672,6 +1674,11 @@ class ExprGenMixin: is_app = 1 if is_app != 0 and Config.SourceDir is not None: base_dir = Config.SourceDir + elif string.strlen(rel_path) >= 9: + if (rel_path[0] == 'i' and rel_path[1] == 'n' and rel_path[2] == 'c' and + rel_path[3] == 'l' and rel_path[4] == 'u' and rel_path[5] == 'd' and + rel_path[6] == 'e' and rel_path[7] == 's' and rel_path[8] == '/'): + rel_path = rel_path + 9 # 构建完整路径: {base_dir}/{rel_path} base_len: t.CSizeT = string.strlen(base_dir) rel_len: t.CSizeT = string.strlen(rel_path) @@ -1803,6 +1810,33 @@ class ExprGenMixin: pyi_buf[bytes_read] = 0 else: pyi_buf[PYI_READ_BUF_SIZE - 1] = 0 + # vpi(存根签名文件)中的 CDefine 只声明名字不带值 + # (如 "U_M_PI: t.CDefine",无 '='),真正的值定义在源 + # .vp/.py 文件中。若 vpi 中所有 "t.CDefine" 声明后均无 + # '='(即 vpi 不含 CDefine 值),必须回退读源文件才能找到。 + cd_sig: int = 0 + cs_total: t.CSizeT = string.strlen(pyi_buf) + cs_i: t.CSizeT = 0 + while cs_i + 9 < cs_total: + if (pyi_buf[cs_i] == 't' and pyi_buf[cs_i + 1] == '.' and + pyi_buf[cs_i + 2] == 'C' and pyi_buf[cs_i + 3] == 'D' and + pyi_buf[cs_i + 4] == 'e' and pyi_buf[cs_i + 5] == 'f' and + pyi_buf[cs_i + 6] == 'i' and pyi_buf[cs_i + 7] == 'n' and + pyi_buf[cs_i + 8] == 'e'): + # 检查该行剩余部分是否有 '='(带值声明才在 vpi 中匹配) + cd_eq: int = 0 + cs_j: t.CSizeT = cs_i + 9 + while cs_j < cs_total and pyi_buf[cs_j] != '\n': + if pyi_buf[cs_j] == '=': + cd_eq = 1 + break + cs_j += 1 + if cd_eq != 0: + cd_sig = 1 + break + cs_i += 1 + if cd_sig == 0: + need_py_fallback = 1 stdlib.free(pyi_path) if need_py_fallback != 0: @@ -1842,6 +1876,7 @@ class ExprGenMixin: pos: t.CSizeT = 0 result_val: int = 0 result_found: int = 0 + res_is_double: int = 0 while pos < total_len: # 找到行首 line_start: t.CSizeT = pos @@ -1910,7 +1945,7 @@ class ExprGenMixin: while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': eq_pos += 1 - # 解析整数值(支持十六进制 0x 前缀和负号) + # 解析整数值(支持十六进制 0x 前缀、负号、浮点小数点) # 负号标记 is_neg: int = 0 if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '-': @@ -1919,6 +1954,7 @@ class ExprGenMixin: val_str_start: t.CSizeT = eq_pos val_str_len: t.CSizeT = 0 is_hex: int = 0 + is_float_val: int = 0 if eq_pos + 1 < line_start + line_len: if pyi_buf[eq_pos] == '0' and (pyi_buf[eq_pos + 1] == 'x' or pyi_buf[eq_pos + 1] == 'X'): is_hex = 1 @@ -1938,6 +1974,11 @@ class ExprGenMixin: if ch >= '0' and ch <= '9': val_str_len += 1 eq_pos += 1 + elif ch == '.' and is_float_val == 0: + # 浮点值:'3.14159'('.' 只允许一次) + is_float_val = 1 + val_str_len += 1 + eq_pos += 1 else: break @@ -1971,6 +2012,19 @@ class ExprGenMixin: result_val = hex_result # 十六进制负值(如 0xFFFFFFFF)保持原样,由 32 位截断处理 result_found = 1 + elif is_float_val != 0: + # 浮点 CDefine(如 U_M_PI = 3.14159...): + # 值缓存为 double(register_cdefine_double),供调用处生成 + # double 常量;整数部分供 int 路径使用(is_cdefine_double 标志)。 + dval_f: double = string.atof(val_buf) + if is_neg != 0: + dval_f = -dval_f + HandlesType.register_cdefine_double(pool, name, dval_f) + result_val = string.atoi(val_buf) + if is_neg != 0: + result_val = -result_val + result_found = 1 + res_is_double = 1 else: result_val = string.atoi(val_buf) # 应用负号(如 t.CUnsignedLong(-11) → -11) @@ -2173,8 +2227,11 @@ class ExprGenMixin: result_found = 1 # 10. 缓存到当前模块的 CDefine 表中 + # 浮点 CDefine 已在匹配循环中 register_cdefine_double 缓存 + # (res_is_double=1),此处只缓存整数 CDefine,避免覆盖 double。 if result_found != 0: - HandlesType.register_cdefine_constant(pool, name, result_val) + if res_is_double == 0: + HandlesType.register_cdefine_constant(pool, name, result_val) HandlesType.set_cdefine_found(1) else: HandlesType.set_cdefine_found(0) @@ -2252,6 +2309,11 @@ class ExprGenMixin: cdef_val = self._lookup_cross_module_cdefine( pool, nm_id, trans._from_imports, trans._imported_modules) if HandlesType.is_cdefine_found() != 0: + # 跨模块浮点 CDefine 已缓存为 double(is_cdefine_double), + # 需返回浮点常量而非截断的整数 + dchk_nm: double = HandlesType.lookup_cdefine_double(nm_id) + if HandlesType.is_cdefine_double() != 0: + return llvmlite.ConstFloat(pool, llvmlite.Double(pool), dchk_nm) return llvmlite.const_int32(pool, cdef_val) # global 变量:从模块作用域查找(global 声明优先级最高) @@ -3590,6 +3652,10 @@ class ExprGenMixin: viperlib.snprintf(ma_fi, ma_fi_len, "%s:%s", at.attr, real_mod_name) cdef_ma_val = self._lookup_cross_module_cdefine(pool, at.attr, ma_fi) if HandlesType.is_cdefine_found() != 0: + # 跨模块浮点 CDefine(如 vipermath.U_M_PI)→ 浮点常量 + dchk_ma: double = HandlesType.lookup_cdefine_double(at.attr) + if HandlesType.is_cdefine_double() != 0: + return llvmlite.ConstFloat(pool, llvmlite.Double(pool), dchk_ma) return llvmlite.const_int32(pool, cdef_ma_val) # 检查 nm_ma.id.at.attr 是否是已导入子模块 (如 w32.win32file) # 如果是子模块,不应创建全局变量,让嵌套属性访问路径处理 @@ -3690,6 +3756,10 @@ class ExprGenMixin: viperlib.snprintf(tmp_fi, tmp_fi_len, "%s:%s", at.attr, qual_buf) cdef_val_nested = self._lookup_cross_module_cdefine(pool, at.attr, tmp_fi) if HandlesType.is_cdefine_found() != 0: + # 跨模块浮点 CDefine → 浮点常量 + dchk_nst: double = HandlesType.lookup_cdefine_double(at.attr) + if HandlesType.is_cdefine_double() != 0: + return llvmlite.ConstFloat(pool, llvmlite.Double(pool), dchk_nst) return llvmlite.const_int32(pool, cdef_val_nested) # CDefine 未找到: 报 FATAL 错误(不再创建未定义的全局变量引用) # 之前此处创建 @INVALID_HANDLE_VALUE 等前向引用,但全局未定义, diff --git a/App/lib/core/Handles/HandlesFor.vp b/App/lib/core/Handles/HandlesFor.vp index 4ae1762..c31ecff 100644 --- a/App/lib/core/Handles/HandlesFor.vp +++ b/App/lib/core/Handles/HandlesFor.vp @@ -51,6 +51,17 @@ import lib.core.Handles.HandlesType as HandlesType _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 @@ -82,16 +93,19 @@ class ForHandle(HandlesBase.Mixin): for_node: ast.For | t.CPtr = (ast.For | t.CPtr)(node) - # 1. 获取循环变量名(仅支持 for i in range(...)) + # 1. 获取循环变量(Name 单变量 / Tuple 多变量) 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: + 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 @@ -106,18 +120,64 @@ class ForHandle(HandlesBase.Mixin): 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: t.CChar | t.CPtr = pool.alloc(256) if err_msg is not None: - viperlib.snprintf(err_msg, 256, "仅支持 range() 或指针迭代,got call '%s'", fn_pre) + 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() 或指针迭代") + 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: + 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) # 其它不支持的字面量:fast-fail 显式报错, # 避免 translate_value 触发 list[T] 特化崩溃或语义歧义。 ik: int = iter_node.kind() @@ -617,6 +677,514 @@ class ForHandle(HandlesBase.Mixin): 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: t.CChar | t.CPtr = 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 = 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_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) + return new_vars + + # ============================================================ + # 多变量迭代(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 = elts.__len__() + 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 _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 cargs.__len__() < 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: + return 0 + cargs: list[ast.AST | t.CPtr] | t.CPtr = call.args + if cargs.__len__() < 2: + HandlesType.fatal_error(for_node, "zip 需要至少两个参数") + return self._build_seq_loop(for_node, t1, t2, cargs.get(0), cargs.get(1), 2) + + 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 = cargs1.__len__() + 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 not None: + 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 not None: + 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 not None: + 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 = cargs2.__len__() + 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 not None: + 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 not None: + 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 not None: + 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: t.CChar | t.CPtr = 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 = 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_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) + return new_vars + # ============================================================ # NewForHandle - 工厂函数(委托到 gen.NewForHandle)