diff --git a/App/lib/core/Handles/HandlesFor.vp b/App/lib/core/Handles/HandlesFor.vp index 214b98e..02c2f53 100644 --- a/App/lib/core/Handles/HandlesFor.vp +++ b/App/lib/core/Handles/HandlesFor.vp @@ -93,8 +93,25 @@ class ForHandle(HandlesBase.Mixin): 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) @@ -287,8 +304,11 @@ class ForHandle(HandlesBase.Mixin): 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, "指针迭代: 迭代器不是指针类型") # 获取元素类型 @@ -384,6 +404,199 @@ class ForHandle(HandlesBase.Mixin): 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 - 工厂函数